]>
cygwin.com Git - cygwin-apps/setup.git/blob - ListView.cc
2 * Copyright (c) 2016 Jon Turney
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * A copy of the GNU General Public License can be found at
15 #include "LogSingleton.h"
19 // ---------------------------------------------------------------------------
20 // implements class ListView
22 // ListView Common Control
23 // ---------------------------------------------------------------------------
26 ListView::init(HWND parent
, int id
, HeaderList headers
)
30 // locate the listview control
31 hWndListView
= ::GetDlgItem(parent
, id
);
33 // configure the listview control
34 SendMessage(hWndListView
, CCM_SETVERSION
, 6, 0);
36 ListView_SetExtendedListViewStyle(hWndListView
,
37 LVS_EX_COLUMNSNAPPOINTS
| // use cxMin
38 LVS_EX_FULLROWSELECT
|
40 LVS_EX_HEADERDRAGDROP
); // headers can be re-ordered
42 // give the header control a border
43 HWND hWndHeader
= ListView_GetHeader(hWndListView
);
44 SetWindowLongPtr(hWndHeader
, GWL_STYLE
,
45 GetWindowLongPtr(hWndHeader
, GWL_STYLE
) | WS_BORDER
);
47 // ensure an initial item exists for width calculations...
52 lvi
.pszText
= const_cast <char *> ("Working...");
53 ListView_InsertItem(hWndListView
, &lvi
);
55 // populate with columns
60 ListView::initColumns(HeaderList headers_
)
62 // store HeaderList for later use
67 lvc
.mask
= LVCF_FMT
| LVCF_WIDTH
| LVCF_TEXT
| LVCF_SUBITEM
;
70 for (i
= 0; headers
[i
].text
!= 0; i
++)
73 lvc
.pszText
= const_cast <char *> (headers
[i
].text
);
75 lvc
.fmt
= headers
[i
].fmt
;
77 ListView_InsertColumn(hWndListView
, i
, &lvc
);
80 // now do some width calculations
81 for (i
= 0; headers
[i
].text
!= 0; i
++)
85 ListView_SetColumnWidth(hWndListView
, i
, LVSCW_AUTOSIZE_USEHEADER
);
86 headers
[i
].hdr_width
= ListView_GetColumnWidth(hWndListView
, i
);
91 ListView::noteColumnWidthStart()
93 dc
= GetDC (hWndListView
);
95 // we must set the font of the DC here, otherwise the width calculations
96 // will be off because the system will use the wrong font metrics
97 HANDLE sysfont
= GetStockObject (DEFAULT_GUI_FONT
);
98 SelectObject (dc
, sysfont
);
101 for (i
= 0; headers
[i
].text
!= 0; i
++)
103 headers
[i
].width
= 0;
108 ListView::noteColumnWidth(int col_num
, const std::string
& string
)
112 // A margin of 3*GetSystemMetrics(SM_CXEDGE) is used at each side of the
114 int addend
= 2*3*GetSystemMetrics(SM_CXEDGE
);
117 GetTextExtentPoint32 (dc
, string
.c_str(), string
.size(), &s
);
119 int width
= addend
+ s
.cx
;
121 if (width
> headers
[col_num
].width
)
122 headers
[col_num
].width
= width
;
126 ListView::noteColumnWidthEnd()
128 ReleaseDC(hWndListView
, dc
);
132 ListView::resizeColumns(void)
134 // ensure the last column stretches all the way to the right-hand side of the
138 for (i
= 0; headers
[i
].text
!= 0; i
++)
139 total
= total
+ headers
[i
].width
;
142 GetClientRect(hWndListView
, &r
);
143 int width
= r
.right
- r
.left
;
146 headers
[i
-1].width
+= width
- total
;
150 lvc
.mask
= LVCF_WIDTH
| LVCF_MINWIDTH
;
151 for (i
= 0; headers
[i
].text
!= 0; i
++)
154 lvc
.cx
= (headers
[i
].width
< headers
[i
].hdr_width
) ? headers
[i
].hdr_width
: headers
[i
].width
;
155 lvc
.cxMin
= headers
[i
].hdr_width
;
157 Log (LOG_BABBLE
) << "resizeColumns: " << i
<< " cx " << lvc
.cx
<< " cxMin " << lvc
.cxMin
<<endLog
;
160 ListView_SetColumn(hWndListView
, i
, &lvc
);
165 ListView::setContents(ListViewContents
*_contents
)
167 contents
= _contents
;
169 // disable redrawing of ListView
170 // (otherwise it will redraw every time a row is added, which makes this very slow)
171 SendMessage(hWndListView
, WM_SETREDRAW
, FALSE
, 0);
173 // preserve focus/selection
174 int iRow
= ListView_GetSelectionMark(hWndListView
);
179 for (i
= 0; i
< contents
->size(); i
++)
182 lvi
.mask
= LVIF_TEXT
;
185 lvi
.pszText
= LPSTR_TEXTCALLBACK
;
187 ListView_InsertItem(hWndListView
, &lvi
);
192 ListView_SetItemState(hWndListView
, iRow
, LVNI_SELECTED
| LVNI_FOCUSED
, LVNI_SELECTED
| LVNI_FOCUSED
);
193 ListView_EnsureVisible(hWndListView
, iRow
, false);
196 // enable redrawing of ListView and redraw
197 SendMessage(hWndListView
, WM_SETREDRAW
, TRUE
, 0);
198 RedrawWindow(hWndListView
, NULL
, NULL
, RDW_ERASE
| RDW_FRAME
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
201 // Helper class: The char * pointer we hand back needs to remain valid for some
202 // time after OnNotify returns, when the std::string we have retrieved has gone
203 // out of scope, so a static instance of this class maintains a local cache.
207 StringCache() : cache(NULL
), cache_size(0) { }
208 StringCache
& operator = (const std::string
& s
)
210 if ((s
.length() + 1) > cache_size
)
212 cache_size
= s
.length() + 1;
213 cache
= (char *)realloc(cache
, cache_size
);
215 strcpy(cache
, s
.c_str());
218 operator char *() const
228 ListView::OnNotify (NMHDR
*pNmHdr
, LRESULT
*pResult
)
231 Log (LOG_BABBLE
) << "ListView::OnNotify id:" << pNmHdr
->idFrom
<< " hwnd:" << pNmHdr
->hwndFrom
<< " code:" << (int)pNmHdr
->code
<< endLog
;
234 switch (pNmHdr
->code
)
236 case LVN_GETDISPINFO
:
238 NMLVDISPINFO
*pNmLvDispInfo
= (NMLVDISPINFO
*)pNmHdr
;
240 Log (LOG_BABBLE
) << "LVN_GETDISPINFO " << pNmLvDispInfo
->item
.iItem
<< endLog
;
244 int iRow
= pNmLvDispInfo
->item
.iItem
;
245 int iCol
= pNmLvDispInfo
->item
.iSubItem
;
247 static StringCache s
;
248 s
= (*contents
)[iRow
]->get_text(iCol
);
249 pNmLvDispInfo
->item
.pszText
= s
;
256 case LVN_GETEMPTYMARKUP
:
258 NMLVEMPTYMARKUP
*pNmMarkup
= (NMLVEMPTYMARKUP
*) pNmHdr
;
260 MultiByteToWideChar(CP_UTF8
, 0,
262 pNmMarkup
->szMarkup
, L_MAX_URL_LENGTH
);
271 NMITEMACTIVATE
*pNmItemAct
= (NMITEMACTIVATE
*) pNmHdr
;
273 Log (LOG_BABBLE
) << "NM_CLICK: pnmitem->iItem " << pNmItemAct
->iItem
<< " pNmItemAct->iSubItem " << pNmItemAct
->iSubItem
<< endLog
;
275 int iRow
= pNmItemAct
->iItem
;
276 int iCol
= pNmItemAct
->iSubItem
;
282 if (headers
[iCol
].type
== ListView::ControlType::popup
)
285 // position pop-up menu at the location of the click
288 update
= popup_menu(iRow
, iCol
, p
);
292 // Inform the item of the click
293 update
= (*contents
)[iRow
]->do_action(iCol
, 0);
296 // Update items, if needed
299 ListView_RedrawItems(hWndListView
, iRow
, iRow
+ update
-1);
308 NMLVCUSTOMDRAW
*pNmLvCustomDraw
= (NMLVCUSTOMDRAW
*)pNmHdr
;
310 switch(pNmLvCustomDraw
->nmcd
.dwDrawStage
)
313 *pResult
= CDRF_NOTIFYITEMDRAW
;
315 case CDDS_ITEMPREPAINT
:
316 *pResult
= CDRF_NOTIFYSUBITEMDRAW
;
318 case CDDS_SUBITEM
| CDDS_ITEMPREPAINT
:
320 LRESULT result
= CDRF_DODEFAULT
;
321 int iCol
= pNmLvCustomDraw
->iSubItem
;
322 int iRow
= pNmLvCustomDraw
->nmcd
.dwItemSpec
;
324 switch (headers
[iCol
].type
)
327 case ListView::ControlType::text
:
328 result
= CDRF_DODEFAULT
;
331 case ListView::ControlType::checkbox
:
333 // get the subitem text
335 ListView_GetItemText(hWndListView
, iRow
, iCol
, buf
, _countof(buf
));
337 // map the subitem text to a checkbox state
338 UINT state
= DFCS_BUTTONCHECK
| DFCS_FLAT
;
339 if (buf
[0] == '\0') // empty
341 result
= CDRF_DODEFAULT
;
344 else if (buf
[0] == 'y') // yes
345 state
|= DFCS_CHECKED
;
346 else if ((buf
[0] == 'n') && (buf
[1] == 'o')) // no
349 state
|= DFCS_INACTIVE
;
351 // erase and draw a checkbox
353 ListView_GetSubItemRect(hWndListView
, iRow
, iCol
, LVIR_BOUNDS
, &r
);
354 HBRUSH hBrush
= CreateSolidBrush(ListView_GetBkColor(hWndListView
));
355 FillRect(pNmLvCustomDraw
->nmcd
.hdc
, &r
, hBrush
);
356 DeleteObject(hBrush
);
357 DrawFrameControl(pNmLvCustomDraw
->nmcd
.hdc
, &r
, DFC_BUTTON
, state
);
359 result
= CDRF_SKIPDEFAULT
;
363 case ListView::ControlType::popup
:
365 // let the control draw the text, but notify us afterwards
366 result
= CDRF_NOTIFYPOSTPAINT
;
374 case CDDS_SUBITEM
| CDDS_ITEMPOSTPAINT
:
376 LRESULT result
= CDRF_DODEFAULT
;
377 int iCol
= pNmLvCustomDraw
->iSubItem
;
378 int iRow
= pNmLvCustomDraw
->nmcd
.dwItemSpec
;
380 switch (headers
[iCol
].type
)
383 result
= CDRF_DODEFAULT
;
386 case ListView::ControlType::popup
:
388 // draw the control at the RHS of the cell
390 ListView_GetSubItemRect(hWndListView
, iRow
, iCol
, LVIR_BOUNDS
, &r
);
391 r
.left
= r
.right
- GetSystemMetrics(SM_CXVSCROLL
);
392 DrawFrameControl(pNmLvCustomDraw
->nmcd
.hdc
, &r
, DFC_SCROLL
,DFCS_SCROLLCOMBOBOX
);
394 result
= CDRF_DODEFAULT
;
410 ListView::empty(void)
412 ListView_DeleteAllItems(hWndListView
);
416 ListView::setEmptyText(const char *text
)
418 empty_list_text
= text
;
422 ListView::popup_menu(int iRow
, int iCol
, POINT p
)
426 HMENU hMenu
= CreatePopupMenu();
429 memset(&mii
, 0, sizeof(mii
));
430 mii
.cbSize
= sizeof(mii
);
431 mii
.fMask
= MIIM_FTYPE
| MIIM_STATE
| MIIM_STRING
| MIIM_ID
;
432 mii
.fType
= MFT_STRING
;
434 ActionList
*al
= (*contents
)[iRow
]->get_actions(iCol
);
438 for (i
= al
->list
.begin (); i
!= al
->list
.end (); ++i
, ++j
)
441 mii
.dwTypeData
= (char *)i
->name
.c_str();
442 mii
.fState
= (i
->selected
? MFS_CHECKED
: MFS_UNCHECKED
|
443 i
->enabled
? MFS_ENABLED
: MFS_DISABLED
);
446 res
= InsertMenuItem(hMenu
, -1, TRUE
, &mii
);
447 if (!res
) Log (LOG_BABBLE
) << "InsertMenuItem failed " << endLog
;
450 int id
= TrackPopupMenu(hMenu
,
451 TPM_LEFTALIGN
| TPM_TOPALIGN
| TPM_RETURNCMD
| TPM_LEFTBUTTON
| TPM_NOANIMATION
,
452 p
.x
, p
.y
, 0, hWndListView
, NULL
);
454 // Inform the item of the menu choice
456 update
= (*contents
)[iRow
]->do_action(iCol
, al
->list
[id
-1].id
);
This page took 0.05703 seconds and 6 git commands to generate.