]> cygwin.com Git - cygwin-apps/setup.git/blame - ListView.cc
Simplify uninstall-only warning
[cygwin-apps/setup.git] / ListView.cc
CommitLineData
ce9f6dd0
JT
1/*
2 * Copyright (c) 2016 Jon Turney
3 *
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.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 */
13
14#include "ListView.h"
15#include "LogSingleton.h"
db1c5abc 16#include "resource.h"
f34a20e7 17#include "String++.h"
ce9f6dd0
JT
18
19#include <commctrl.h>
20
21// ---------------------------------------------------------------------------
22// implements class ListView
23//
24// ListView Common Control
25// ---------------------------------------------------------------------------
26
27void
28ListView::init(HWND parent, int id, HeaderList headers)
29{
30 hWndParent = parent;
31
32 // locate the listview control
33 hWndListView = ::GetDlgItem(parent, id);
34
35 // configure the listview control
36 SendMessage(hWndListView, CCM_SETVERSION, 6, 0);
37
38 ListView_SetExtendedListViewStyle(hWndListView,
39 LVS_EX_COLUMNSNAPPOINTS | // use cxMin
40 LVS_EX_FULLROWSELECT |
41 LVS_EX_GRIDLINES |
42 LVS_EX_HEADERDRAGDROP); // headers can be re-ordered
43
44 // give the header control a border
45 HWND hWndHeader = ListView_GetHeader(hWndListView);
46 SetWindowLongPtr(hWndHeader, GWL_STYLE,
47 GetWindowLongPtr(hWndHeader, GWL_STYLE) | WS_BORDER);
48
49 // ensure an initial item exists for width calculations...
50 LVITEM lvi;
51 lvi.mask = LVIF_TEXT;
52 lvi.iItem = 0;
53 lvi.iSubItem = 0;
54 lvi.pszText = const_cast <char *> ("Working...");
55 ListView_InsertItem(hWndListView, &lvi);
56
57 // populate with columns
58 initColumns(headers);
db1c5abc 59
68487c7c 60 // create a small icon imagelist
db1c5abc 61 // (the order of images matches ListViewLine::State enum)
68487c7c
JT
62 hImgList = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
63 GetSystemMetrics(SM_CYSMICON),
64 ILC_COLOR32, 2, 0);
db1c5abc
JT
65 ImageList_AddIcon(hImgList, LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_TREE_PLUS)));
66 ImageList_AddIcon(hImgList, LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_TREE_MINUS)));
68487c7c
JT
67
68 // create an empty imagelist, used to reset the indent
69 hEmptyImgList = ImageList_Create(1, 1,
70 ILC_COLOR32, 2, 0);
800274fd
JT
71
72 // LVS_EX_INFOTIP/LVN_GETINFOTIP doesn't work for subitems, so we have to do
73 // our own tooltip handling
74 hWndTip = CreateWindowEx (0,
75 (LPCTSTR) TOOLTIPS_CLASS,
76 NULL,
77 WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
78 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
79 hWndParent,
80 (HMENU) 0,
81 GetModuleHandle(NULL),
82 NULL);
83 // must be topmost so that tooltips will display on top
84 SetWindowPos(hWndTip, HWND_TOPMOST,0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
85
86 TOOLINFO ti;
87 memset ((void *)&ti, 0, sizeof(ti));
88 ti.cbSize = sizeof(ti);
89 ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
90 ti.hwnd = hWndParent;
91 ti.uId = (UINT_PTR)hWndListView;
92 ti.lpszText = LPSTR_TEXTCALLBACK; // use TTN_GETDISPINFO
93 SendMessage(hWndTip, TTM_ADDTOOL, 0, (LPARAM)&ti);
94
95 // match long delay for tooltip to disappear used elsewhere (30s)
96 SendMessage(hWndTip, TTM_SETDELAYTIME, TTDT_AUTOPOP, (LPARAM) MAKELONG (30000, 0));
97 // match tip width used elsewhere
98 SendMessage(hWndTip, TTM_SETMAXTIPWIDTH, 0, 450);
f34a20e7
JT
99
100 // switch to using wide-char WM_NOTIFY messages
101 ListView_SetUnicodeFormat(hWndListView, TRUE);
ce9f6dd0
JT
102}
103
104void
105ListView::initColumns(HeaderList headers_)
106{
107 // store HeaderList for later use
108 headers = headers_;
109
110 // create the columns
111 LVCOLUMN lvc;
112 lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
113
114 int i;
115 for (i = 0; headers[i].text != 0; i++)
116 {
117 lvc.iSubItem = i;
118 lvc.pszText = const_cast <char *> (headers[i].text);
119 lvc.cx = 100;
120 lvc.fmt = headers[i].fmt;
121
122 ListView_InsertColumn(hWndListView, i, &lvc);
123 }
124
125 // now do some width calculations
126 for (i = 0; headers[i].text != 0; i++)
127 {
128 headers[i].width = 0;
129
130 ListView_SetColumnWidth(hWndListView, i, LVSCW_AUTOSIZE_USEHEADER);
131 headers[i].hdr_width = ListView_GetColumnWidth(hWndListView, i);
132 }
133}
134
135void
136ListView::noteColumnWidthStart()
137{
138 dc = GetDC (hWndListView);
139
140 // we must set the font of the DC here, otherwise the width calculations
141 // will be off because the system will use the wrong font metrics
142 HANDLE sysfont = GetStockObject (DEFAULT_GUI_FONT);
143 SelectObject (dc, sysfont);
144
145 int i;
146 for (i = 0; headers[i].text != 0; i++)
147 {
148 headers[i].width = 0;
149 }
150}
151
152void
153ListView::noteColumnWidth(int col_num, const std::string& string)
154{
155 SIZE s = { 0, 0 };
156
157 // A margin of 3*GetSystemMetrics(SM_CXEDGE) is used at each side of the
158 // header text.
159 int addend = 2*3*GetSystemMetrics(SM_CXEDGE);
160
161 if (string.size())
162 GetTextExtentPoint32 (dc, string.c_str(), string.size(), &s);
163
164 int width = addend + s.cx;
165
d5a81cbe
JT
166 // allow for width of dropdown button in popup columns
167 if (headers[col_num].type == ListView::ControlType::popup)
168 {
169 width += GetSystemMetrics(SM_CXVSCROLL);
170 }
171
ce9f6dd0
JT
172 if (width > headers[col_num].width)
173 headers[col_num].width = width;
174}
175
176void
177ListView::noteColumnWidthEnd()
178{
179 ReleaseDC(hWndListView, dc);
180}
181
182void
183ListView::resizeColumns(void)
184{
185 // ensure the last column stretches all the way to the right-hand side of the
186 // listview control
187 int i;
188 int total = 0;
189 for (i = 0; headers[i].text != 0; i++)
190 total = total + headers[i].width;
191
192 RECT r;
193 GetClientRect(hWndListView, &r);
194 int width = r.right - r.left;
195
196 if (total < width)
197 headers[i-1].width += width - total;
198
199 // size each column
200 LVCOLUMN lvc;
201 lvc.mask = LVCF_WIDTH | LVCF_MINWIDTH;
202 for (i = 0; headers[i].text != 0; i++)
203 {
204 lvc.iSubItem = i;
205 lvc.cx = (headers[i].width < headers[i].hdr_width) ? headers[i].hdr_width : headers[i].width;
206 lvc.cxMin = headers[i].hdr_width;
207#if DEBUG
208 Log (LOG_BABBLE) << "resizeColumns: " << i << " cx " << lvc.cx << " cxMin " << lvc.cxMin <<endLog;
209#endif
210
211 ListView_SetColumn(hWndListView, i, &lvc);
212 }
213}
214
215void
68487c7c 216ListView::setContents(ListViewContents *_contents, bool tree)
ce9f6dd0
JT
217{
218 contents = _contents;
219
220 // disable redrawing of ListView
221 // (otherwise it will redraw every time a row is added, which makes this very slow)
222 SendMessage(hWndListView, WM_SETREDRAW, FALSE, 0);
223
224 // preserve focus/selection
225 int iRow = ListView_GetSelectionMark(hWndListView);
226
227 empty();
228
68487c7c
JT
229 // assign imagelist to listview control (this also sets the size for indents)
230 if (tree)
231 ListView_SetImageList(hWndListView, hImgList, LVSIL_SMALL);
232 else
233 ListView_SetImageList(hWndListView, hEmptyImgList, LVSIL_SMALL);
234
ce9f6dd0
JT
235 size_t i;
236 for (i = 0; i < contents->size(); i++)
237 {
238 LVITEM lvi;
68487c7c 239 lvi.mask = LVIF_TEXT | (tree ? LVIF_IMAGE | LVIF_INDENT : 0);
ce9f6dd0
JT
240 lvi.iItem = i;
241 lvi.iSubItem = 0;
242 lvi.pszText = LPSTR_TEXTCALLBACK;
68487c7c
JT
243 if (tree)
244 {
245 lvi.iImage = I_IMAGECALLBACK;
246 lvi.iIndent = (*contents)[i]->get_indent();
247 }
ce9f6dd0
JT
248
249 ListView_InsertItem(hWndListView, &lvi);
250 }
251
252 if (iRow >= 0)
253 {
254 ListView_SetItemState(hWndListView, iRow, LVNI_SELECTED | LVNI_FOCUSED, LVNI_SELECTED | LVNI_FOCUSED);
255 ListView_EnsureVisible(hWndListView, iRow, false);
256 }
257
258 // enable redrawing of ListView and redraw
259 SendMessage(hWndListView, WM_SETREDRAW, TRUE, 0);
260 RedrawWindow(hWndListView, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
261}
262
f34a20e7
JT
263// Helper class: The pointer we hand back needs to remain valid for some time
264// after OnNotify returns, when the string object we have retrieved has gone out
265// of scope, so a static instance of this class maintains a local cache.
266template <class T> class StringCache
ce9f6dd0 267{
f34a20e7 268 typedef typename T::traits_type::char_type char_type;
ce9f6dd0
JT
269public:
270 StringCache() : cache(NULL), cache_size(0) { }
f34a20e7 271 StringCache & operator = (const T & s)
ce9f6dd0
JT
272 {
273 if ((s.length() + 1) > cache_size)
274 {
275 cache_size = s.length() + 1;
f34a20e7 276 cache = (char_type *)realloc(cache, cache_size * sizeof(char_type));
ce9f6dd0 277 }
f34a20e7 278 memcpy(cache, s.c_str(), cache_size * sizeof(char_type));
ce9f6dd0
JT
279 return *this;
280 }
f34a20e7 281 operator char_type *() const
ce9f6dd0
JT
282 {
283 return cache;
284 }
285private:
f34a20e7 286 char_type *cache;
ce9f6dd0
JT
287 size_t cache_size;
288};
289
290bool
291ListView::OnNotify (NMHDR *pNmHdr, LRESULT *pResult)
292{
293#if DEBUG
294 Log (LOG_BABBLE) << "ListView::OnNotify id:" << pNmHdr->idFrom << " hwnd:" << pNmHdr->hwndFrom << " code:" << (int)pNmHdr->code << endLog;
295#endif
296
297 switch (pNmHdr->code)
298 {
f34a20e7 299 case LVN_GETDISPINFOW:
ce9f6dd0 300 {
f34a20e7 301 NMLVDISPINFOW *pNmLvDispInfo = (NMLVDISPINFOW *)pNmHdr;
ce9f6dd0
JT
302#if DEBUG
303 Log (LOG_BABBLE) << "LVN_GETDISPINFO " << pNmLvDispInfo->item.iItem << endLog;
304#endif
305 if (contents)
306 {
307 int iRow = pNmLvDispInfo->item.iItem;
308 int iCol = pNmLvDispInfo->item.iSubItem;
309
f34a20e7 310 static StringCache<std::wstring> s;
ce9f6dd0
JT
311 s = (*contents)[iRow]->get_text(iCol);
312 pNmLvDispInfo->item.pszText = s;
db1c5abc
JT
313
314 if (pNmLvDispInfo->item.iSubItem == 0)
315 {
316 pNmLvDispInfo->item.iImage = (int)((*contents)[pNmLvDispInfo->item.iItem]->get_state());
317 }
ce9f6dd0
JT
318 }
319
320 return true;
321 }
322 break;
323
324 case LVN_GETEMPTYMARKUP:
325 {
326 NMLVEMPTYMARKUP *pNmMarkup = (NMLVEMPTYMARKUP*) pNmHdr;
327
328 MultiByteToWideChar(CP_UTF8, 0,
329 empty_list_text, -1,
330 pNmMarkup->szMarkup, L_MAX_URL_LENGTH);
331
332 *pResult = true;
333 return true;
334 }
335 break;
336
337 case NM_CLICK:
338 {
339 NMITEMACTIVATE *pNmItemAct = (NMITEMACTIVATE *) pNmHdr;
340#if DEBUG
341 Log (LOG_BABBLE) << "NM_CLICK: pnmitem->iItem " << pNmItemAct->iItem << " pNmItemAct->iSubItem " << pNmItemAct->iSubItem << endLog;
342#endif
343 int iRow = pNmItemAct->iItem;
344 int iCol = pNmItemAct->iSubItem;
4018914c
JT
345 if (iRow < 0)
346 return false;
ce9f6dd0 347
4018914c
JT
348 int update = 0;
349
350 if (headers[iCol].type == ListView::ControlType::popup)
351 {
352 POINT p;
4018914c
JT
353 GetCursorPos(&p);
354
76dc99c1
JT
355 RECT r;
356 ListView_GetSubItemRect(hWndListView, iRow, iCol, LVIR_BOUNDS, &r);
357 POINT cp = p;
358 ::ScreenToClient(hWndListView, &cp);
359
360 // if the click isn't over the pop-up button, do nothing yet (but this
361 // might be followed by a NM_DBLCLK)
362 if (cp.x < r.right - GetSystemMetrics(SM_CXVSCROLL))
363 return true;
364
365 // position pop-up menu at the location of the click
4018914c
JT
366 update = popup_menu(iRow, iCol, p);
367 }
368 else
ce9f6dd0
JT
369 {
370 // Inform the item of the click
4018914c
JT
371 update = (*contents)[iRow]->do_action(iCol, 0);
372 }
ce9f6dd0 373
4018914c
JT
374 // Update items, if needed
375 if (update > 0)
376 {
377 ListView_RedrawItems(hWndListView, iRow, iRow + update -1);
ce9f6dd0 378 }
4018914c 379
ce9f6dd0
JT
380 return true;
381 }
382 break;
61183f15 383
76dc99c1
JT
384 case NM_DBLCLK:
385 {
386 NMITEMACTIVATE *pNmItemAct = (NMITEMACTIVATE *) pNmHdr;
387#if DEBUG
388 Log (LOG_BABBLE) << "NM_DBLCLICK: pnmitem->iItem " << pNmItemAct->iItem << " pNmItemAct->iSubItem " << pNmItemAct->iSubItem << endLog;
389#endif
390 int iRow = pNmItemAct->iItem;
391 int iCol = pNmItemAct->iSubItem;
392 if (iRow < 0)
393 return false;
394
395 int update = 0;
396
397 // Inform the item of the double-click
398 update = (*contents)[iRow]->do_default_action(iCol );
399
400 // Update items, if needed
401 if (update > 0)
402 {
403 ListView_RedrawItems(hWndListView, iRow, iRow + update -1);
404 }
405
406 return true;
407 }
408 break;
409
61183f15
JT
410 case NM_CUSTOMDRAW:
411 {
412 NMLVCUSTOMDRAW *pNmLvCustomDraw = (NMLVCUSTOMDRAW *)pNmHdr;
413
414 switch(pNmLvCustomDraw->nmcd.dwDrawStage)
415 {
416 case CDDS_PREPAINT:
417 *pResult = CDRF_NOTIFYITEMDRAW;
418 return true;
419 case CDDS_ITEMPREPAINT:
420 *pResult = CDRF_NOTIFYSUBITEMDRAW;
421 return true;
422 case CDDS_SUBITEM | CDDS_ITEMPREPAINT:
423 {
424 LRESULT result = CDRF_DODEFAULT;
425 int iCol = pNmLvCustomDraw->iSubItem;
426 int iRow = pNmLvCustomDraw->nmcd.dwItemSpec;
427
428 switch (headers[iCol].type)
429 {
430 default:
431 case ListView::ControlType::text:
432 result = CDRF_DODEFAULT;
433 break;
434
435 case ListView::ControlType::checkbox:
436 {
f34a20e7 437 // get the subitem text (as ASCII)
61183f15
JT
438 char buf[3];
439 ListView_GetItemText(hWndListView, iRow, iCol, buf, _countof(buf));
440
441 // map the subitem text to a checkbox state
442 UINT state = DFCS_BUTTONCHECK | DFCS_FLAT;
443 if (buf[0] == '\0') // empty
444 {
445 result = CDRF_DODEFAULT;
446 break;
447 }
448 else if (buf[0] == 'y') // yes
449 state |= DFCS_CHECKED;
450 else if ((buf[0] == 'n') && (buf[1] == 'o')) // no
451 state |= 0;
452 else // n/a
453 state |= DFCS_INACTIVE;
454
455 // erase and draw a checkbox
456 RECT r;
457 ListView_GetSubItemRect(hWndListView, iRow, iCol, LVIR_BOUNDS, &r);
05edbf21
JT
458 DWORD bkg_color;
459 if (pNmLvCustomDraw->nmcd.uItemState & CDIS_SELECTED)
460 bkg_color = GetSysColor(COLOR_HIGHLIGHT);
461 else
462 bkg_color = ListView_GetBkColor(hWndListView);
463 HBRUSH hBrush = CreateSolidBrush(bkg_color);
61183f15
JT
464 FillRect(pNmLvCustomDraw->nmcd.hdc, &r, hBrush);
465 DeleteObject(hBrush);
466 DrawFrameControl(pNmLvCustomDraw->nmcd.hdc, &r, DFC_BUTTON, state);
467
468 result = CDRF_SKIPDEFAULT;
469 }
470 break;
4018914c
JT
471
472 case ListView::ControlType::popup:
473 {
474 // let the control draw the text, but notify us afterwards
475 result = CDRF_NOTIFYPOSTPAINT;
476 }
477 break;
478 }
479
480 *pResult = result;
481 return true;
482 }
483 case CDDS_SUBITEM | CDDS_ITEMPOSTPAINT:
484 {
485 LRESULT result = CDRF_DODEFAULT;
486 int iCol = pNmLvCustomDraw->iSubItem;
487 int iRow = pNmLvCustomDraw->nmcd.dwItemSpec;
488
489 switch (headers[iCol].type)
490 {
491 default:
492 result = CDRF_DODEFAULT;
493 break;
494
495 case ListView::ControlType::popup:
496 {
497 // draw the control at the RHS of the cell
498 RECT r;
499 ListView_GetSubItemRect(hWndListView, iRow, iCol, LVIR_BOUNDS, &r);
500 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL);
501 DrawFrameControl(pNmLvCustomDraw->nmcd.hdc, &r, DFC_SCROLL,DFCS_SCROLLCOMBOBOX);
502
503 result = CDRF_DODEFAULT;
504 }
505 break;
61183f15
JT
506 }
507 *pResult = result;
508 return true;
509 }
510 }
511 }
800274fd
JT
512 break;
513
514 case LVN_HOTTRACK:
515 {
516 NMLISTVIEW *pNmListView = (NMLISTVIEW *)pNmHdr;
517 int iRow = pNmListView->iItem;
518 int iCol = pNmListView->iSubItem;
519#if DEBUG
520 Log (LOG_BABBLE) << "LVN_HOTTRACK " << iRow << " " << iCol << endLog;
521#endif
522 if (iRow < 0)
523 return true;
524
525 // if we've tracked off to a different cell
526 if ((iRow != iRow_track) || (iCol != iCol_track))
527 {
528#if DEBUG
529 Log (LOG_BABBLE) << "LVN_HOTTRACK changed cell" << endLog;
530#endif
531
532 // if the tooltip for previous cell is displayed, remove it
533 // restart the tooltip AUTOPOP timer for this cell
534 SendMessage(hWndTip, TTM_ACTIVATE, FALSE, 0);
535 SendMessage(hWndTip, TTM_ACTIVATE, TRUE, 0);
536
537 iRow_track = iRow;
538 iCol_track = iCol;
539 }
540
541 return true;
542 }
543 break;
544
22e01f51
JT
545 case LVN_KEYDOWN:
546 {
547 NMLVKEYDOWN *pNmLvKeyDown = (NMLVKEYDOWN *)pNmHdr;
548 int iRow = ListView_GetSelectionMark(hWndListView);
549#if DEBUG
550 Log (LOG_PLAIN) << "LVN_KEYDOWN vkey " << pNmLvKeyDown->wVKey << " on row " << iRow << endLog;
551#endif
552
553 if (contents && iRow >= 0)
554 {
555 int col_num;
556 int action_id;
557 if ((*contents)[iRow]->map_key_to_action(pNmLvKeyDown->wVKey, &col_num, &action_id))
558 {
559 int update;
560 if (action_id >= 0)
561 update = (*contents)[iRow]->do_action(col_num, action_id);
562 else
563 {
564 POINT p;
565 RECT r;
566 ListView_GetSubItemRect(hWndListView, iRow, col_num, LVIR_BOUNDS, &r);
567 p.x = r.left;
568 p.y = r.top;
569 ClientToScreen(hWndListView, &p);
570
571 update = popup_menu(iRow, col_num, p);
572 }
573
574 if (update > 0)
575 ListView_RedrawItems(hWndListView, iRow, iRow + update -1);
576 }
577 }
578 }
579 break;
580
800274fd
JT
581 case TTN_GETDISPINFO:
582 {
583 // convert mouse position to item/subitem
584 LVHITTESTINFO lvHitTestInfo;
585 lvHitTestInfo.flags = LVHT_ONITEM;
586 GetCursorPos(&lvHitTestInfo.pt);
587 ::ScreenToClient(hWndListView, &lvHitTestInfo.pt);
588 ListView_SubItemHitTest(hWndListView, &lvHitTestInfo);
589
590 int iRow = lvHitTestInfo.iItem;
591 int iCol = lvHitTestInfo.iSubItem;
592 if (iRow < 0)
593 return false;
594
595#if DEBUG
596 Log (LOG_BABBLE) << "TTN_GETDISPINFO " << iRow << " " << iCol << endLog;
597#endif
598
599 // get the tooltip text for that item/subitem
f34a20e7 600 static StringCache<std::string> tooltip;
800274fd
JT
601 tooltip = "";
602 if (contents)
603 tooltip = (*contents)[iRow]->get_tooltip(iCol);
604
605 // set the tooltip text
606 NMTTDISPINFO *pNmTTDispInfo = (NMTTDISPINFO *)pNmHdr;
607 pNmTTDispInfo->lpszText = tooltip;
608 pNmTTDispInfo->hinst = NULL;
609 pNmTTDispInfo->uFlags = 0;
610
611 return true;
612 }
613 break;
ce9f6dd0
JT
614 }
615
616 // We don't care.
617 return false;
618}
619
620void
621ListView::empty(void)
622{
623 ListView_DeleteAllItems(hWndListView);
624}
625
626void
627ListView::setEmptyText(const char *text)
628{
629 empty_list_text = text;
630}
4018914c
JT
631
632int
633ListView::popup_menu(int iRow, int iCol, POINT p)
634{
635 int update = 0;
636 // construct menu
637 HMENU hMenu = CreatePopupMenu();
638
f34a20e7 639 MENUITEMINFOW mii;
4018914c
JT
640 memset(&mii, 0, sizeof(mii));
641 mii.cbSize = sizeof(mii);
642 mii.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_STRING | MIIM_ID;
643 mii.fType = MFT_STRING;
644
645 ActionList *al = (*contents)[iRow]->get_actions(iCol);
646
647 Actions::iterator i;
648 int j = 1;
649 for (i = al->list.begin (); i != al->list.end (); ++i, ++j)
650 {
651 BOOL res;
f34a20e7 652 mii.dwTypeData = const_cast <wchar_t *> (i->name.c_str());
4018914c
JT
653 mii.fState = (i->selected ? MFS_CHECKED : MFS_UNCHECKED |
654 i->enabled ? MFS_ENABLED : MFS_DISABLED);
655 mii.wID = j;
656
f34a20e7 657 res = InsertMenuItemW(hMenu, -1, TRUE, &mii);
4018914c
JT
658 if (!res) Log (LOG_BABBLE) << "InsertMenuItem failed " << endLog;
659 }
660
661 int id = TrackPopupMenu(hMenu,
662 TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_NOANIMATION,
663 p.x, p.y, 0, hWndListView, NULL);
664
665 // Inform the item of the menu choice
666 if (id)
667 update = (*contents)[iRow]->do_action(iCol, al->list[id-1].id);
668
669 DestroyMenu(hMenu);
670 delete al;
671
672 return update;
673}
This page took 0.14993 seconds and 5 git commands to generate.