Copy riched20
[reactos.git] / reactos / subsys / system / explorer / taskbar / startmenu.cpp
1 /*
2 * Copyright 2003, 2004 Martin Fuchs
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19
20 //
21 // Explorer clone
22 //
23 // startmenu.cpp
24 //
25 // Explorer start menu
26 //
27 // Martin Fuchs, 19.08.2003
28 //
29 // Credits: Thanks to Everaldo (http://www.everaldo.com) for his nice looking icons.
30 //
31
32
33 #include "precomp.h"
34
35 #include "../explorer_intres.h"
36
37 #include "desktopbar.h"
38 #include "startmenu.h"
39
40 #include "../dialogs/searchprogram.h"
41 #include "../dialogs/settings.h"
42
43
44 StartMenu::StartMenu(HWND hwnd)
45 : super(hwnd)
46 {
47 _next_id = IDC_FIRST_MENU;
48 _submenu_id = 0;
49
50 _border_left = 0;
51 _border_top = 0;
52 _bottom_max = INT_MAX;
53
54 _floating_btn = false;
55 _arrow_btns = false;
56 _scroll_mode = SCROLL_NOT;
57 _scroll_pos = 0;
58 _invisible_lines = 0;
59
60 _last_pos = WindowRect(hwnd).pos();
61 #ifdef _LIGHT_STARTMENU
62 _selected_id = -1;
63 _last_mouse_pos = 0;
64 #endif
65 }
66
67 StartMenu::StartMenu(HWND hwnd, const StartMenuCreateInfo& create_info)
68 : super(hwnd),
69 _create_info(create_info)
70 {
71 for(StartMenuFolders::const_iterator it=create_info._folders.begin(); it!=create_info._folders.end(); ++it)
72 if (*it)
73 _dirs.push_back(ShellDirectory(GetDesktopFolder(), *it, _hwnd));
74
75 _next_id = IDC_FIRST_MENU;
76 _submenu_id = 0;
77
78 _border_left = 0;
79 _border_top = create_info._border_top;
80 _bottom_max = INT_MAX;
81
82 _floating_btn = create_info._border_top? true: false;
83 _arrow_btns = false;
84 _scroll_mode = SCROLL_NOT;
85 _scroll_pos = 0;
86 _invisible_lines = 0;
87
88 _last_pos = WindowRect(hwnd).pos();
89 #ifdef _LIGHT_STARTMENU
90 _selected_id = -1;
91 _last_mouse_pos = 0;
92 #endif
93 }
94
95 StartMenu::~StartMenu()
96 {
97 SendParent(PM_STARTMENU_CLOSED);
98 }
99
100
101 // We need this wrapper function for s_wcStartMenu, it calls the WIN32 API,
102 // though static C++ initializers are not allowed for Winelib applications.
103 BtnWindowClass& StartMenu::GetWndClasss()
104 {
105 static BtnWindowClass s_wcStartMenu(CLASSNAME_STARTMENU);
106
107 return s_wcStartMenu;
108 }
109
110
111 Window::CREATORFUNC_INFO StartMenu::s_def_creator = STARTMENU_CREATOR(StartMenu);
112
113 HWND StartMenu::Create(int x, int y, const StartMenuFolders& folders, HWND hwndParent, LPCTSTR title, CREATORFUNC_INFO creator, void* info)
114 {
115 UINT style, ex_style;
116 int top_height;
117
118 if (hwndParent) {
119 style = WS_POPUP|WS_THICKFRAME|WS_CLIPCHILDREN|WS_VISIBLE;
120 ex_style = 0;
121 top_height = STARTMENU_TOP_BTN_SPACE;
122 } else {
123 style = WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_CLIPCHILDREN|WS_VISIBLE;
124 ex_style = WS_EX_TOOLWINDOW;
125 top_height = 0;
126 }
127
128 RECT rect = {x, y-STARTMENU_LINE_HEIGHT-top_height, x+STARTMENU_WIDTH_MIN, y};
129
130 #ifndef _LIGHT_STARTMENU
131 rect.top += STARTMENU_LINE_HEIGHT;
132 #endif
133
134 AdjustWindowRectEx(&rect, style, FALSE, ex_style);
135
136 StartMenuCreateInfo create_info;
137
138 create_info._folders = folders;
139 create_info._border_top = top_height;
140 create_info._creator = creator;
141 create_info._info = info;
142
143 if (title)
144 create_info._title = title;
145
146 HWND hwnd = Window::Create(creator, &create_info, ex_style, GetWndClasss(), title,
147 style, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, hwndParent);
148
149 // make sure the window is not off the screen
150 MoveVisible(hwnd);
151
152 return hwnd;
153 }
154
155
156 LRESULT StartMenu::Init(LPCREATESTRUCT pcs)
157 {
158 try {
159 AddEntries();
160
161 if (super::Init(pcs))
162 return 1;
163
164 // create buttons for registered entries in _entries
165 for(ShellEntryMap::const_iterator it=_entries.begin(); it!=_entries.end(); ++it) {
166 const StartMenuEntry& sme = it->second;
167 bool hasSubmenu = false;
168
169 for(ShellEntrySet::const_iterator it=sme._entries.begin(); it!=sme._entries.end(); ++it)
170 if ((*it)->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
171 hasSubmenu = true;
172
173 #ifdef _LIGHT_STARTMENU
174 _buttons.push_back(SMBtnInfo(sme, it->first, hasSubmenu));
175 #else
176 AddButton(sme._title, sme._hIcon, hasSubmenu, it->first);
177 #endif
178 }
179
180 #ifdef _LIGHT_STARTMENU
181 if (_buttons.empty())
182 #else
183 if (!GetWindow(_hwnd, GW_CHILD))
184 #endif
185 AddButton(ResString(IDS_EMPTY), ICID_NONE, false, 0, false);
186
187 #ifdef _LIGHT_STARTMENU
188 ResizeToButtons();
189 #endif
190
191 #ifdef _LAZY_ICONEXTRACT
192 PostMessage(_hwnd, PM_UPDATE_ICONS, 0, 0);
193 #endif
194 } catch(COMException& e) {
195 HandleException(e, pcs->hwndParent); // destroys the start menu window while switching focus
196 }
197
198 return 0;
199 }
200
201 void StartMenu::AddEntries()
202 {
203 for(StartMenuShellDirs::iterator it=_dirs.begin(); it!=_dirs.end(); ++it) {
204 StartMenuDirectory& smd = *it;
205 ShellDirectory& dir = smd._dir;
206
207 if (!dir._scanned) {
208 WaitCursor wait;
209
210 #ifdef _LAZY_ICONEXTRACT
211 dir.smart_scan(SORT_NAME, SCAN_FILESYSTEM); // lazy icon extraction, try to read directly from filesystem
212 #else
213 dir.smart_scan(SORT_NAME, SCAN_EXTRACT_ICONS|SCAN_FILESYSTEM);
214 #endif
215 }
216
217 AddShellEntries(dir, -1, smd._subfolders);
218 }
219 }
220
221
222 void StartMenu::AddShellEntries(const ShellDirectory& dir, int max, bool subfolders)
223 {
224 int cnt = 0;
225
226 for(Entry*entry=dir._down; entry; entry=entry->_next) {
227 // hide files like "desktop.ini"
228 if (entry->_shell_attribs & SFGAO_HIDDEN)
229 //not appropriate for drive roots: if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
230 continue;
231
232 // hide subfolders if requested
233 if (!subfolders)
234 if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
235 continue;
236
237 // only 'max' entries shall be added.
238 if (++cnt == max)
239 break;
240
241 if (entry->_etype == ET_SHELL)
242 AddEntry(dir._folder, static_cast<ShellEntry*>(entry));
243 else
244 AddEntry(dir._folder, entry);
245 }
246 }
247
248
249 LRESULT StartMenu::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
250 {
251 switch(nmsg) {
252 case WM_PAINT: {
253 PaintCanvas canvas(_hwnd);
254 Paint(canvas);
255 break;}
256
257 case WM_SIZE:
258 ResizeButtons(LOWORD(lparam)-_border_left);
259 break;
260
261 case WM_MOVE: {
262 POINTS& pos = MAKEPOINTS(lparam);
263
264 // move open submenus of floating menus
265 if (_submenu) {
266 int dx = pos.x - _last_pos.x;
267 int dy = pos.y - _last_pos.y;
268
269 if (dx || dy) {
270 WindowRect rt(_submenu);
271 SetWindowPos(_submenu, 0, rt.left+dx, rt.top+dy, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE);
272 //MoveVisible(_submenu);
273 }
274 }
275
276 _last_pos.x = pos.x;
277 _last_pos.y = pos.y;
278 goto def;}
279
280 case WM_NCHITTEST: {
281 LRESULT res = super::WndProc(nmsg, wparam, lparam);
282
283 if (res>=HTSIZEFIRST && res<=HTSIZELAST)
284 return HTCLIENT; // disable window resizing
285
286 return res;}
287
288 case WM_LBUTTONDOWN: {
289 RECT rect;
290
291 // check mouse cursor for coordinates of floating button
292 GetFloatingButtonRect(&rect);
293
294 if (PtInRect(&rect, Point(lparam))) {
295 // create a floating copy of the current start menu
296 WindowRect pos(_hwnd);
297
298 ///@todo do something similar to StartMenuRoot::TrackStartmenu() in order to automatically close submenus when clicking on the desktop background
299 StartMenu::Create(pos.left+3, pos.bottom-3, _create_info._folders, 0, _create_info._title, _create_info._creator, _create_info._info);
300 CloseStartMenu();
301 }
302
303 #ifdef _LIGHT_STARTMENU
304 int id = ButtonHitTest(Point(lparam));
305
306 if (id)
307 Command(id, BN_CLICKED);
308 #endif
309 break;}
310
311 case WM_SYSCOMMAND:
312 if ((wparam&0xFFF0) == SC_SIZE)
313 return 0; // disable window resizing
314 goto def;
315
316 case WM_ACTIVATEAPP:
317 // close start menu when activating another application
318 if (!wparam)
319 CloseStartMenu();
320 break; // don't call super::WndProc in case "this" has been deleted
321
322 case WM_CANCELMODE:
323 CloseStartMenu();
324
325 #ifdef _LIGHT_STARTMENU
326 if (_scroll_mode != SCROLL_NOT) {
327 ReleaseCapture();
328 KillTimer(_hwnd, 0);
329 }
330 #endif
331 break;
332
333 #ifdef _LIGHT_STARTMENU
334 case WM_MOUSEMOVE: {
335 // automatically set the focus to startmenu entries when moving the mouse over them
336 if (lparam != _last_mouse_pos) { // don't process WM_MOUSEMOVE when opening submenus using keyboard navigation
337 Point pt(lparam);
338
339 if (_arrow_btns) {
340 RECT rect_up, rect_down;
341
342 GetArrowButtonRects(&rect_up, &rect_down);
343
344 SCROLL_MODE scroll_mode = SCROLL_NOT;
345
346 if (PtInRect(&rect_up, pt))
347 scroll_mode = SCROLL_UP;
348 else if (PtInRect(&rect_down, pt))
349 scroll_mode = SCROLL_DOWN;
350
351 if (scroll_mode != _scroll_mode) {
352 if (scroll_mode == SCROLL_NOT) {
353 ReleaseCapture();
354 KillTimer(_hwnd, 0);
355 } else {
356 CloseSubmenus();
357 SetTimer(_hwnd, 0, 150, NULL); // 150 ms scroll interval
358 SetCapture(_hwnd);
359 }
360
361 _scroll_mode = scroll_mode;
362 }
363 }
364
365 int new_id = ButtonHitTest(pt);
366
367 if (new_id > 0 && new_id != _selected_id)
368 SelectButton(new_id);
369
370 _last_mouse_pos = lparam;
371 }
372 break;}
373
374 case WM_TIMER:
375 if (_scroll_mode == SCROLL_UP) {
376 if (_scroll_pos > 0) {
377 --_scroll_pos;
378 InvalidateRect(_hwnd, NULL, TRUE);
379 }
380 } else {
381 if (_scroll_pos <= _invisible_lines) {
382 ++_scroll_pos;
383 InvalidateRect(_hwnd, NULL, TRUE);
384 }
385 }
386 break;
387
388 case WM_KEYDOWN:
389 ProcessKey(wparam);
390 break;
391 #else
392 case PM_STARTENTRY_FOCUSED: { ///@todo use TrackMouseEvent() and WM_MOUSEHOVER to wait a bit before opening submenus
393 BOOL hasSubmenu = wparam;
394 HWND hctrl = (HWND)lparam;
395
396 // automatically open submenus
397 if (hasSubmenu) {
398 UpdateWindow(_hwnd); // draw focused button before waiting on submenu creation
399 //SendMessage(_hwnd, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hctrl),BN_CLICKED), (LPARAM)hctrl);
400 Command(GetDlgCtrlID(hctrl), BN_CLICKED);
401 } else {
402 // close any open submenu
403 CloseOtherSubmenus();
404 }
405 break;}
406 #endif
407
408 #ifdef _LAZY_ICONEXTRACT
409 case PM_UPDATE_ICONS:
410 UpdateIcons(/*wparam*/);
411 break;
412 #endif
413
414 case PM_STARTENTRY_LAUNCHED:
415 if (GetWindowStyle(_hwnd) & WS_CAPTION) // don't automatically close floating menus
416 return 0;
417
418 // route message to the parent menu and close menus after launching an entry
419 if (!SendParent(nmsg, wparam, lparam))
420 CloseStartMenu();
421 return 1; // signal that we have received and processed the message
422
423 case PM_STARTMENU_CLOSED:
424 _submenu = 0;
425 break;
426
427 case PM_SELECT_ENTRY:
428 SelectButtonIndex(0, wparam?true:false);
429 break;
430
431 #ifdef _LIGHT_STARTMENU
432 case WM_CONTEXTMENU: {
433 Point screen_pt(lparam), clnt_pt=screen_pt;
434 ScreenToClient(_hwnd, &clnt_pt);
435
436 int id = ButtonHitTest(clnt_pt);
437
438 if (id) {
439 StartMenuEntry& sme = _entries[id];
440
441 for(ShellEntrySet::iterator it=sme._entries.begin(); it!=sme._entries.end(); ++it) {
442 Entry* entry = *it;
443
444 if (entry) {
445 CHECKERROR(entry->do_context_menu(_hwnd, screen_pt, _cm_ifs)); // may close start menu because of focus loss
446 break; ///@todo handle context menu for more than one entry
447 }
448 }
449 }
450 break;}
451 #endif
452
453 default: def:
454 return super::WndProc(nmsg, wparam, lparam);
455 }
456
457 return 0;
458 }
459
460
461 #ifdef _LIGHT_STARTMENU
462
463 int StartMenu::ButtonHitTest(POINT pt)
464 {
465 ClientRect clnt(_hwnd);
466 RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT};
467
468 if (pt.x<rect.left || pt.x>rect.right)
469 return 0;
470
471 for(SMBtnVector::const_iterator it=_buttons.begin()+_scroll_pos; it!=_buttons.end(); ++it) {
472 const SMBtnInfo& info = *it;
473
474 if (rect.top > pt.y)
475 break;
476
477 rect.bottom = rect.top + (info._id==-1? STARTMENU_SEP_HEIGHT: STARTMENU_LINE_HEIGHT);
478
479 if (rect.bottom > _bottom_max)
480 break;
481
482 if (pt.y < rect.bottom) // PtInRect(&rect, pt)
483 return info._id;
484
485 rect.top = rect.bottom;
486 }
487
488 return 0;
489 }
490
491 void StartMenu::InvalidateSelection()
492 {
493 if (_selected_id <= 0)
494 return;
495
496 ClientRect clnt(_hwnd);
497 RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT};
498
499 for(SMBtnVector::const_iterator it=_buttons.begin()+_scroll_pos; it!=_buttons.end(); ++it) {
500 const SMBtnInfo& info = *it;
501
502 rect.bottom = rect.top + (info._id==-1? STARTMENU_SEP_HEIGHT: STARTMENU_LINE_HEIGHT);
503
504 if (info._id == _selected_id) {
505 InvalidateRect(_hwnd, &rect, TRUE);
506 break;
507 }
508
509 rect.top = rect.bottom;
510 }
511 }
512
513 const SMBtnInfo* StartMenu::GetButtonInfo(int id) const
514 {
515 for(SMBtnVector::const_iterator it=_buttons.begin(); it!=_buttons.end(); ++it)
516 if (it->_id == id)
517 return &*it;
518
519 return NULL;
520 }
521
522 bool StartMenu::SelectButton(int id, bool open_sub)
523 {
524 if (id == -1)
525 return false;
526
527 if (id == _selected_id)
528 return true;
529
530 InvalidateSelection();
531
532 const SMBtnInfo* btn = GetButtonInfo(id);
533
534 if (btn && btn->_enabled) {
535 _selected_id = id;
536
537 InvalidateSelection();
538
539 // automatically open submenus
540 if (btn->_hasSubmenu) {
541 if (open_sub)
542 OpenSubmenu();
543 } else
544 CloseOtherSubmenus(); // close any open submenu
545
546 return true;
547 } else {
548 _selected_id = -1;
549 return false;
550 }
551 }
552
553 bool StartMenu::OpenSubmenu(bool select_first)
554 {
555 if (_selected_id == -1)
556 return false;
557
558 InvalidateSelection();
559
560 const SMBtnInfo* btn = GetButtonInfo(_selected_id);
561
562 // automatically open submenus
563 if (btn->_hasSubmenu) {
564 //@@ allows destroying of startmenu when processing PM_UPDATE_ICONS -> GPF
565 UpdateWindow(_hwnd); // draw focused button before waiting on submenu creation
566 Command(_selected_id, BN_CLICKED);
567
568 if (select_first && _submenu)
569 SendMessage(_submenu, PM_SELECT_ENTRY, (WPARAM)false, 0);
570
571 return true;
572 } else
573 return false;
574 }
575
576
577 int StartMenu::GetSelectionIndex()
578 {
579 if (_selected_id == -1)
580 return -1;
581
582 for(int i=0; i<(int)_buttons.size(); ++i)
583 if (_buttons[i]._id == _selected_id)
584 return i;
585
586 return -1;
587 }
588
589 bool StartMenu::SelectButtonIndex(int idx, bool open_sub)
590 {
591 if (idx>=0 && idx<(int)_buttons.size())
592 return SelectButton(_buttons[idx]._id, open_sub);
593 else
594 return false;
595 }
596
597 void StartMenu::ProcessKey(int vk)
598 {
599 switch(vk) {
600 case VK_RETURN:
601 if (_selected_id)
602 Command(_selected_id, BN_CLICKED);
603 break;
604
605 case VK_UP:
606 Navigate(-1);
607 break;
608
609 case VK_DOWN:
610 Navigate(+1);
611 break;
612
613 case VK_HOME:
614 SelectButtonIndex(0, false);
615 break;
616
617 case VK_END:
618 SelectButtonIndex(_buttons.size()-1, false);
619 break;
620
621 case VK_LEFT:
622 if (_submenu)
623 CloseOtherSubmenus();
624 else if (!(GetWindowStyle(_hwnd) & WS_CAPTION)) // don't automatically close floating menus
625 DestroyWindow(_hwnd);
626 break;
627
628 case VK_RIGHT:
629 OpenSubmenu(true);
630 break;
631
632 case VK_ESCAPE:
633 CloseStartMenu();
634 break;
635
636 default:
637 if (vk>='0' && vk<='Z')
638 JumpToNextShortcut(vk);
639 }
640 }
641
642 bool StartMenu::Navigate(int step)
643 {
644 int idx = GetSelectionIndex();
645
646 if (idx == -1)
647 if (step > 0)
648 idx = 0 - step;
649 else
650 idx = _buttons.size() - step;
651
652 for(;;) {
653 idx += step;
654
655 if (idx<0 || idx>(int)_buttons.size())
656 break;
657
658 if (SelectButtonIndex(idx, false))
659 return true;
660 }
661
662 return false;
663 }
664
665 bool StartMenu::JumpToNextShortcut(char c)
666 {
667 int cur_idx = GetSelectionIndex();
668
669 if (cur_idx == -1)
670 cur_idx = 0;
671
672 int first_found = 0;
673 int found_more = 0;
674
675 SMBtnVector::const_iterator cur_it = _buttons.begin();
676 cur_it += cur_idx + 1;
677
678 // first search down from current item...
679 SMBtnVector::const_iterator it = cur_it;
680 for(; it!=_buttons.end(); ++it) {
681 const SMBtnInfo& btn = *it;
682
683 if (!btn._title.empty() && toupper((TBYTE)btn._title.at(0)) == c) {
684 if (!first_found)
685 first_found = btn._id;
686 else
687 ++found_more;
688 }
689 }
690
691 // ...now search from top to the current item
692 it = _buttons.begin();
693 for(; it!=_buttons.end() && it!=cur_it; ++it) {
694 const SMBtnInfo& btn = *it;
695
696 if (!btn._title.empty() && toupper((TBYTE)btn._title.at(0)) == c) {
697 if (!first_found)
698 first_found = btn._id;
699 else
700 ++found_more;
701 }
702 }
703
704 if (first_found) {
705 SelectButton(first_found);
706
707 if (!found_more)
708 Command(first_found, BN_CLICKED);
709
710 return true;
711 } else
712 return false;
713 }
714
715 #endif // _LIGHT_STARTMENU
716
717
718 bool StartMenu::GetButtonRect(int id, PRECT prect) const
719 {
720 #ifdef _LIGHT_STARTMENU
721 ClientRect clnt(_hwnd);
722 RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT};
723
724 for(SMBtnVector::const_iterator it=_buttons.begin()+_scroll_pos; it!=_buttons.end(); ++it) {
725 const SMBtnInfo& info = *it;
726
727 rect.bottom = rect.top + (info._id==-1? STARTMENU_SEP_HEIGHT: STARTMENU_LINE_HEIGHT);
728
729 if (info._id == id) {
730 *prect = rect;
731 return true;
732 }
733
734 rect.top = rect.bottom;
735 }
736
737 return false;
738 #else
739 HWND btn = GetDlgItem(_hwnd, id);
740
741 if (btn) {
742 GetWindowRect(btn, prect);
743 ScreenToClient(_hwnd, prect);
744
745 return true;
746 } else
747 return false;
748 #endif
749 }
750
751
752 void StartMenu::DrawFloatingButton(HDC hdc)
753 {
754 static ResIconEx floatingIcon(IDI_FLOATING, 8, 4);
755
756 ClientRect clnt(_hwnd);
757
758 DrawIconEx(hdc, clnt.right-12, 0, floatingIcon, 8, 4, 0, 0, DI_NORMAL);
759 }
760
761 void StartMenu::GetFloatingButtonRect(LPRECT prect)
762 {
763 GetClientRect(_hwnd, prect);
764
765 prect->right -= 4;
766 prect->left = prect->right - 8;
767 prect->bottom = 4;
768 }
769
770
771 void StartMenu::DrawArrows(HDC hdc)
772 {
773 static ResIconEx arrowUpIcon(IDI_ARROW_UP, 8, 4);
774 static ResIconEx arrowDownIcon(IDI_ARROW_DOWN, 8, 4);
775
776 ClientRect clnt(_hwnd);
777
778 DrawIconEx(hdc, clnt.right/2-4, _floating_btn?3:1, arrowUpIcon, 8, 4, 0, 0, DI_NORMAL);
779 DrawIconEx(hdc, clnt.right/2-4, clnt.bottom-5, arrowDownIcon, 8, 4, 0, 0, DI_NORMAL);
780 }
781
782 void StartMenu::GetArrowButtonRects(LPRECT prect_up, LPRECT prect_down)
783 {
784 GetClientRect(_hwnd, prect_up);
785 *prect_down = *prect_up;
786
787 // prect_up->left = prect_up->right/2 - 4;
788 // prect_up->right = prect_up->left + 8;
789 prect_up->right -= 8;
790 prect_up->top = _floating_btn? 3: 1;
791 prect_up->bottom = prect_up->top + 4;
792
793 // prect_down->left = prect_down->right/2 - 4;
794 // prect_down->right = prect_down->left + 8;
795 prect_down->right -= 8;
796 prect_down->top = prect_down->bottom - 5;
797 }
798
799
800 void StartMenu::Paint(PaintCanvas& canvas)
801 {
802 if (_floating_btn)
803 DrawFloatingButton(canvas);
804
805 #ifdef _LIGHT_STARTMENU
806 if (_arrow_btns)
807 DrawArrows(canvas);
808
809 ClientRect clnt(_hwnd);
810 RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT};
811
812 int sep_width = rect.right-rect.left - 4;
813
814 FontSelection font(canvas, GetStockFont(DEFAULT_GUI_FONT));
815 BkMode bk_mode(canvas, TRANSPARENT);
816
817 for(SMBtnVector::const_iterator it=_buttons.begin()+_scroll_pos; it!=_buttons.end(); ++it) {
818 const SMBtnInfo& btn = *it;
819
820 if (rect.top > canvas.rcPaint.bottom)
821 break;
822
823 if (btn._id == -1) { // a separator?
824 rect.bottom = rect.top + STARTMENU_SEP_HEIGHT;
825
826 if (rect.bottom > _bottom_max)
827 break;
828
829 BrushSelection brush_sel(canvas, GetSysColorBrush(COLOR_BTNSHADOW));
830 PatBlt(canvas, rect.left+2, rect.top+STARTMENU_SEP_HEIGHT/2-1, sep_width, 1, PATCOPY);
831
832 SelectBrush(canvas, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
833 PatBlt(canvas, rect.left+2, rect.top+STARTMENU_SEP_HEIGHT/2, sep_width, 1, PATCOPY);
834 } else {
835 rect.bottom = rect.top + STARTMENU_LINE_HEIGHT;
836
837 if (rect.bottom > _bottom_max)
838 break;
839
840 if (rect.top >= canvas.rcPaint.top)
841 DrawStartMenuButton(canvas, rect, btn._title, btn, btn._id==_selected_id, false);
842 }
843
844 rect.top = rect.bottom;
845 }
846 #endif
847 }
848
849 #ifdef _LAZY_ICONEXTRACT
850 void StartMenu::UpdateIcons(/*int idx*/)
851 {
852 UpdateWindow(_hwnd);
853
854 #ifdef _SINGLE_ICONEXTRACT
855
856 //if (idx >= 0)
857 int idx = _scroll_pos;
858
859 for(; idx<(int)_buttons.size(); ++idx) {
860 SMBtnInfo& btn = _buttons[idx];
861
862 if (btn._icon_id==ICID_UNKNOWN && btn._id>0) {
863 StartMenuEntry& sme = _entries[btn._id];
864
865 btn._icon_id = ICID_NONE;
866
867 for(ShellEntrySet::iterator it=sme._entries.begin(); it!=sme._entries.end(); ++it) {
868 Entry* entry = *it;
869
870 if (entry->_icon_id == ICID_UNKNOWN)
871 try {
872 entry->extract_icon();
873 } catch(COMException&) {
874 // ignore unexpected exceptions while extracting icons
875 }
876
877 if (entry->_icon_id > ICID_NONE) {
878 btn._icon_id = (ICON_ID)/*@@*/ entry->_icon_id;
879
880 RECT rect;
881
882 GetButtonRect(btn._id, &rect);
883
884 if (rect.bottom > _bottom_max)
885 break;
886
887 WindowCanvas canvas(_hwnd);
888 DrawStartMenuButton(canvas, rect, NULL, btn, btn._id==_selected_id, false);
889
890 //InvalidateRect(_hwnd, &rect, FALSE);
891 //UpdateWindow(_hwnd);
892 //break;
893
894 break;
895 }
896 }
897 }
898 }
899
900 // if (++idx < (int)_buttons.size())
901 // PostMessage(_hwnd, PM_UPDATE_ICONS, idx, 0);
902
903 #else
904
905 int icons_extracted = 0;
906 int icons_updated = 0;
907
908 for(StartMenuShellDirs::iterator it=_dirs.begin(); it!=_dirs.end(); ++it) {
909 ShellDirectory& dir = it->_dir;
910
911 icons_extracted += dir.extract_icons();
912 }
913
914 if (icons_extracted) {
915 for(ShellEntryMap::iterator it1=_entries.begin(); it1!=_entries.end(); ++it1) {
916 StartMenuEntry& sme = it1->second;
917
918 if (!sme._hIcon) {
919 sme._hIcon = (HICON)-1;
920
921 for(ShellEntrySet::const_iterator it2=sme._entries.begin(); it2!=sme._entries.end(); ++it2) {
922 const Entry* sm_entry = *it2;
923
924 if (sm_entry->_hIcon) {
925 sme._hIcon = sm_entry->_hIcon;
926 break;
927 }
928 }
929 }
930 }
931
932 for(SMBtnVector::iterator it=_buttons.begin(); it!=_buttons.end(); ++it) {
933 SMBtnInfo& info = *it;
934
935 if (info._id>0 && !info._hIcon) {
936 info._hIcon = _entries[info._id]._hIcon;
937 ++icons_updated;
938 }
939 }
940 }
941
942 if (icons_updated) {
943 InvalidateRect(_hwnd, NULL, FALSE);
944 UpdateWindow(_hwnd);
945 }
946 #endif
947 }
948 #endif
949
950
951 // resize child button controls to accomodate for new window size
952 void StartMenu::ResizeButtons(int cx)
953 {
954 HDWP hdwp = BeginDeferWindowPos(10);
955
956 for(HWND ctrl=GetWindow(_hwnd,GW_CHILD); ctrl; ctrl=GetNextWindow(ctrl,GW_HWNDNEXT)) {
957 ClientRect rt(ctrl);
958
959 if (rt.right != cx) {
960 int height = rt.bottom - rt.top;
961
962 // special handling for separator controls
963 if (!height && (GetWindowStyle(ctrl)&SS_TYPEMASK)==SS_ETCHEDHORZ)
964 height = 2;
965
966 hdwp = DeferWindowPos(hdwp, ctrl, 0, 0, 0, cx, height, SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
967 }
968 }
969
970 EndDeferWindowPos(hdwp);
971 }
972
973
974 int StartMenu::Command(int id, int code)
975 {
976 #ifndef _LIGHT_STARTMENU
977 switch(id) {
978 case IDCANCEL:
979 CloseStartMenu(id);
980 break;
981
982 default: {
983 #endif
984 ShellEntryMap::iterator found = _entries.find(id);
985
986 if (found != _entries.end()) {
987 ActivateEntry(id, found->second._entries);
988 return 0;
989 }
990
991 return super::Command(id, code);
992 #ifndef _LIGHT_STARTMENU
993 }
994 }
995
996 return 0;
997 #endif
998 }
999
1000
1001 ShellEntryMap::iterator StartMenu::AddEntry(const String& title, ICON_ID icon_id, Entry* entry)
1002 {
1003 // search for an already existing subdirectory entry with the same name
1004 if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1005 for(ShellEntryMap::iterator it=_entries.begin(); it!=_entries.end(); ++it) {
1006 StartMenuEntry& sme = it->second;
1007
1008 if (sme._title == title) ///@todo speed up by using a map indexed by name
1009 for(ShellEntrySet::iterator it2=sme._entries.begin(); it2!=sme._entries.end(); ++it2) {
1010 if ((*it2)->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1011 // merge the new shell entry with the existing of the same name
1012 sme._entries.insert(entry);
1013
1014 return it;
1015 }
1016 }
1017 }
1018
1019 ShellEntryMap::iterator sme = AddEntry(title, icon_id);
1020
1021 sme->second._entries.insert(entry);
1022
1023 return sme;
1024 }
1025
1026 ShellEntryMap::iterator StartMenu::AddEntry(const String& title, ICON_ID icon_id, int id)
1027 {
1028 if (id == -1)
1029 id = ++_next_id;
1030
1031 StartMenuEntry sme;
1032
1033 sme._title = title;
1034 sme._icon_id = icon_id;
1035
1036 ShellEntryMap::iterator it = _entries.insert(make_pair(id, sme)).first;
1037
1038 return it;
1039 }
1040
1041 ShellEntryMap::iterator StartMenu::AddEntry(const ShellFolder folder, ShellEntry* entry)
1042 {
1043 ICON_ID icon_id;
1044
1045 if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1046 icon_id = ICID_FOLDER;
1047 else
1048 icon_id = (ICON_ID)/*@@*/ entry->_icon_id;
1049
1050 return AddEntry(folder.get_name(entry->_pidl), icon_id, entry);
1051 }
1052
1053 ShellEntryMap::iterator StartMenu::AddEntry(const ShellFolder folder, Entry* entry)
1054 {
1055 ICON_ID icon_id;
1056
1057 if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1058 icon_id = ICID_FOLDER;
1059 else
1060 icon_id = (ICON_ID)/*@@*/ entry->_icon_id;
1061
1062 return AddEntry(entry->_display_name, icon_id, entry);
1063 }
1064
1065
1066 void StartMenu::AddButton(LPCTSTR title, ICON_ID icon_id, bool hasSubmenu, int id, bool enabled)
1067 {
1068 #ifdef _LIGHT_STARTMENU
1069 _buttons.push_back(SMBtnInfo(title, icon_id, id, hasSubmenu, enabled));
1070 #else
1071 DWORD style = enabled? WS_VISIBLE|WS_CHILD|BS_OWNERDRAW: WS_VISIBLE|WS_CHILD|BS_OWNERDRAW|WS_DISABLED;
1072
1073 WindowRect rect(_hwnd);
1074 ClientRect clnt(_hwnd);
1075
1076 // increase window height to make room for the new button
1077 rect.top -= STARTMENU_LINE_HEIGHT;
1078
1079 // move down if we are too high now
1080 if (rect.top < 0) {
1081 rect.top += STARTMENU_LINE_HEIGHT;
1082 rect.bottom += STARTMENU_LINE_HEIGHT;
1083 }
1084
1085 WindowCanvas canvas(_hwnd);
1086 FontSelection font(canvas, GetStockFont(DEFAULT_GUI_FONT));
1087
1088 // widen window, if it is too small
1089 int text_width = GetStartMenuBtnTextWidth(canvas, title, _hwnd) + 16/*icon*/ + 10/*placeholder*/ + 16/*arrow*/;
1090
1091 int cx = clnt.right - _border_left;
1092 if (text_width > cx)
1093 rect.right += text_width-cx;
1094
1095 MoveWindow(_hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE);
1096
1097 StartMenuCtrl(_hwnd, _border_left, clnt.bottom, rect.right-rect.left-_border_left,
1098 title, id, g_Globals._icon_cache.get_icon(icon_id)._hIcon, hasSubmenu, style);
1099 #endif
1100 }
1101
1102 void StartMenu::AddSeparator()
1103 {
1104 #ifdef _LIGHT_STARTMENU
1105 _buttons.push_back(SMBtnInfo(NULL, ICID_NONE, -1, false));
1106 #else
1107 WindowRect rect(_hwnd);
1108 ClientRect clnt(_hwnd);
1109
1110 // increase window height to make room for the new separator
1111 rect.top -= STARTMENU_SEP_HEIGHT;
1112
1113 // move down if we are too high now
1114 if (rect.top < 0) {
1115 rect.top += STARTMENU_LINE_HEIGHT;
1116 rect.bottom += STARTMENU_LINE_HEIGHT;
1117 }
1118
1119 MoveWindow(_hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE);
1120
1121 StartMenuSeparator(_hwnd, _border_left, clnt.bottom, rect.right-rect.left-_border_left);
1122 #endif
1123 }
1124
1125
1126 bool StartMenu::CloseOtherSubmenus(int id)
1127 {
1128 if (_submenu) {
1129 if (IsWindow(_submenu)) {
1130 if (_submenu_id == id)
1131 return false;
1132 else {
1133 _submenu_id = 0;
1134 DestroyWindow(_submenu);
1135 // _submenu should be reset automatically by PM_STARTMENU_CLOSED, but safety first...
1136 }
1137 }
1138
1139 _submenu = 0;
1140 }
1141
1142 return true;
1143 }
1144
1145
1146 void StartMenu::CreateSubmenu(int id, LPCTSTR title, CREATORFUNC_INFO creator, void* info)
1147 {
1148 CreateSubmenu(id, StartMenuFolders(), title, creator, info);
1149 }
1150
1151 bool StartMenu::CreateSubmenu(int id, int folder_id, LPCTSTR title, CREATORFUNC_INFO creator, void* info)
1152 {
1153 try {
1154 SpecialFolderPath folder(folder_id, _hwnd);
1155
1156 StartMenuFolders new_folders;
1157 new_folders.push_back(folder);
1158
1159 CreateSubmenu(id, new_folders, title, creator, info);
1160
1161 return true;
1162 } catch(COMException&) {
1163 // ignore Exception and don't display anything
1164 CloseOtherSubmenus(id);
1165 _buttons[GetSelectionIndex()]._enabled = false; // disable entries for non-existing folders
1166 return false;
1167 }
1168 }
1169
1170 bool StartMenu::CreateSubmenu(int id, int folder_id1, int folder_id2, LPCTSTR title, CREATORFUNC_INFO creator, void* info)
1171 {
1172 StartMenuFolders new_folders;
1173
1174 try {
1175 new_folders.push_back(SpecialFolderPath(folder_id1, _hwnd));
1176 } catch(COMException&) {
1177 }
1178
1179 try {
1180 new_folders.push_back(SpecialFolderPath(folder_id2, _hwnd));
1181 } catch(COMException&) {
1182 }
1183
1184 if (!new_folders.empty()) {
1185 CreateSubmenu(id, new_folders, title, creator, info);
1186 return true;
1187 } else {
1188 CloseOtherSubmenus(id);
1189 _buttons[GetSelectionIndex()]._enabled = false; // disable entries for non-existing folders
1190 return false;
1191 }
1192 }
1193
1194 void StartMenu::CreateSubmenu(int id, const StartMenuFolders& new_folders, LPCTSTR title, CREATORFUNC_INFO creator, void* info)
1195 {
1196 // Only open one submenu at a time.
1197 if (!CloseOtherSubmenus(id))
1198 return;
1199
1200 RECT rect;
1201 int x, y;
1202
1203 if (GetButtonRect(id, &rect)) {
1204 ClientToScreen(_hwnd, &rect);
1205
1206 x = rect.right; // Submenus should overlap their parent a bit.
1207 y = rect.top+STARTMENU_LINE_HEIGHT +_border_top/*own border*/ -STARTMENU_TOP_BTN_SPACE/*border of new submenu*/;
1208 } else {
1209 WindowRect pos(_hwnd);
1210
1211 x = pos.right;
1212 y = pos.top;
1213 }
1214
1215 _submenu_id = id;
1216 _submenu = StartMenu::Create(x, y, new_folders, _hwnd, title, creator, info);
1217 }
1218
1219
1220 void StartMenu::ActivateEntry(int id, const ShellEntrySet& entries)
1221 {
1222 StartMenuFolders new_folders;
1223 String title;
1224
1225 for(ShellEntrySet::const_iterator it=entries.begin(); it!=entries.end(); ++it) {
1226 Entry* entry = const_cast<Entry*>(*it);
1227
1228 if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1229
1230 ///@todo If the user explicitly clicked on a submenu, display this folder as floating start menu.
1231
1232 if (entry->_etype == ET_SHELL)
1233 new_folders.push_back(entry->create_absolute_pidl());
1234 else {
1235 TCHAR path[MAX_PATH];
1236
1237 if (entry->get_path(path))
1238 new_folders.push_back(path);
1239 }
1240
1241 if (title.empty())
1242 title = entry->_display_name;
1243 } else {
1244 // The entry is no subdirectory, so there can only be one shell entry.
1245 assert(entries.size()==1);
1246
1247 HWND hparent = GetParent(_hwnd);
1248 ShellPath shell_path = entry->create_absolute_pidl();
1249
1250 // close start menus when launching the selected entry
1251 CloseStartMenu(id);
1252
1253 ///@todo launch in the background; specify correct HWND for error message box titles
1254 SHELLEXECUTEINFO shexinfo;
1255
1256 shexinfo.cbSize = sizeof(SHELLEXECUTEINFO);
1257 shexinfo.fMask = SEE_MASK_IDLIST; // SEE_MASK_INVOKEIDLIST is also possible.
1258 shexinfo.hwnd = hparent;
1259 shexinfo.lpVerb = NULL;
1260 shexinfo.lpFile = NULL;
1261 shexinfo.lpParameters = NULL;
1262 shexinfo.lpDirectory = NULL;
1263 shexinfo.nShow = SW_SHOWNORMAL;
1264
1265 shexinfo.lpIDList = &*shell_path;
1266
1267 // add PIDL to the recent file list
1268 SHAddToRecentDocs(SHARD_PIDL, shexinfo.lpIDList);
1269
1270 if (!ShellExecuteEx(&shexinfo))
1271 display_error(hparent, GetLastError());
1272
1273 // we may have deleted 'this' - ensure we leave the loop and function
1274 return;
1275 }
1276 }
1277
1278 if (!new_folders.empty()) {
1279 // Only open one submenu at a time.
1280 if (!CloseOtherSubmenus(id))
1281 return;
1282
1283 CreateSubmenu(id, new_folders, title);
1284 }
1285 }
1286
1287
1288 /// close all windows of the start menu popup
1289 void StartMenu::CloseStartMenu(int id)
1290 {
1291 if (!(GetWindowStyle(_hwnd) & WS_CAPTION)) { // don't automatically close floating menus
1292 if (!SendParent(PM_STARTENTRY_LAUNCHED, id, (LPARAM)_hwnd))
1293 DestroyWindow(_hwnd);
1294 } else if (_submenu) // instead close submenus of floating parent menus
1295 CloseSubmenus();
1296 }
1297
1298
1299 int GetStartMenuBtnTextWidth(HDC hdc, LPCTSTR title, HWND hwnd)
1300 {
1301 RECT rect = {0, 0, 0, 0};
1302 DrawText(hdc, title, -1, &rect, DT_SINGLELINE|DT_NOPREFIX|DT_CALCRECT);
1303
1304 return rect.right-rect.left;
1305 }
1306
1307 #ifdef _LIGHT_STARTMENU
1308 void DrawStartMenuButton(HDC hdc, const RECT& rect, LPCTSTR title, const SMBtnInfo& btn, bool has_focus, bool pushed)
1309 #else
1310 void DrawStartMenuButton(HDC hdc, const RECT& rect, LPCTSTR title, HICON hIcon,
1311 bool hasSubmenu, bool enabled, bool has_focus, bool pushed);
1312 #endif
1313 {
1314 UINT style = DFCS_BUTTONPUSH;
1315
1316 if (!btn._enabled)
1317 style |= DFCS_INACTIVE;
1318
1319 POINT iconPos = {rect.left+2, (rect.top+rect.bottom-16)/2};
1320 RECT textRect = {rect.left+16+4, rect.top+2, rect.right-4, rect.bottom-4};
1321
1322 if (pushed) {
1323 style |= DFCS_PUSHED;
1324 ++iconPos.x; ++iconPos.y;
1325 ++textRect.left; ++textRect.top;
1326 ++textRect.right; ++textRect.bottom;
1327 }
1328
1329 int bk_color_idx = COLOR_BTNFACE;
1330 int text_color_idx = COLOR_BTNTEXT;
1331
1332 if (has_focus) {
1333 bk_color_idx = COLOR_HIGHLIGHT;
1334 text_color_idx = COLOR_HIGHLIGHTTEXT;
1335 }
1336
1337 COLORREF bk_color = GetSysColor(bk_color_idx);
1338 HBRUSH bk_brush = GetSysColorBrush(bk_color_idx);
1339
1340 if (title)
1341 FillRect(hdc, &rect, bk_brush);
1342
1343 if (btn._icon_id > ICID_NONE)
1344 g_Globals._icon_cache.get_icon(btn._icon_id).draw(hdc, iconPos.x, iconPos.y, 16, 16, bk_color, bk_brush);
1345
1346 // draw submenu arrow at the right
1347 if (btn._hasSubmenu) {
1348 static SmallIcon arrowIcon(IDI_ARROW);
1349 static SmallIcon selArrowIcon(IDI_ARROW_SELECTED);
1350
1351 DrawIconEx(hdc, rect.right-16, iconPos.y,
1352 has_focus? selArrowIcon: arrowIcon,
1353 16, 16, 0, bk_brush, DI_NORMAL);
1354 }
1355
1356 if (title) {
1357 BkMode bk_mode(hdc, TRANSPARENT);
1358
1359 if (!btn._enabled) // dis->itemState & (ODS_DISABLED|ODS_GRAYED)
1360 DrawGrayText(hdc, &textRect, title, DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER);
1361 else {
1362 TextColor lcColor(hdc, GetSysColor(text_color_idx));
1363 DrawText(hdc, title, -1, &textRect, DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER);
1364 }
1365 }
1366 }
1367
1368
1369 #ifdef _LIGHT_STARTMENU
1370
1371 void StartMenu::ResizeToButtons()
1372 {
1373 WindowRect rect(_hwnd);
1374
1375 WindowCanvas canvas(_hwnd);
1376 FontSelection font(canvas, GetStockFont(DEFAULT_GUI_FONT));
1377
1378 int max_width = STARTMENU_WIDTH_MIN;
1379 int height = 0;
1380
1381 for(SMBtnVector::const_iterator it=_buttons.begin(); it!=_buttons.end(); ++it) {
1382 int w = GetStartMenuBtnTextWidth(canvas, it->_title, _hwnd);
1383
1384 if (w > max_width)
1385 max_width = w;
1386
1387 if (it->_id == -1)
1388 height += STARTMENU_SEP_HEIGHT;
1389 else
1390 height += STARTMENU_LINE_HEIGHT;
1391 }
1392
1393 // calculate new window size
1394 int text_width = max_width + 16/*icon*/ + 10/*placeholder*/ + 16/*arrow*/;
1395
1396 RECT rt_hgt = {rect.left, rect.bottom-_border_top-height, rect.left+_border_left+text_width, rect.bottom};
1397 AdjustWindowRectEx(&rt_hgt, GetWindowStyle(_hwnd), FALSE, GetWindowExStyle(_hwnd));
1398
1399 // ignore movement, only look at the size change
1400 rect.right = rect.left + (rt_hgt.right-rt_hgt.left);
1401 rect.top = rect.bottom - (rt_hgt.bottom-rt_hgt.top);
1402
1403 // move down if we are too high
1404 if (rect.top < 0) {
1405 int dy = -rect.top;
1406 rect.top += dy;
1407 rect.bottom += dy;
1408 }
1409
1410 // enable scroll mode for long start menus, which span more than the whole screen height
1411 int cyscreen = GetSystemMetrics(SM_CYSCREEN);
1412 int bottom_max = 0;
1413
1414 if (rect.bottom > cyscreen) {
1415 _arrow_btns = true;
1416
1417 _invisible_lines = (rect.bottom-cyscreen+(STARTMENU_LINE_HEIGHT-1))/STARTMENU_LINE_HEIGHT + 1;
1418 rect.bottom -= _invisible_lines * STARTMENU_LINE_HEIGHT;
1419
1420 bottom_max = rect.bottom;
1421
1422 if (_floating_btn)
1423 rect.bottom += 6; // lower scroll arrow
1424 else {
1425 _border_top += 6; // upper scroll arrow
1426 rect.bottom += 2*6; // upper+lower scroll arrow
1427 }
1428 }
1429
1430 MoveWindow(_hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE);
1431
1432 if (bottom_max) {
1433 POINT pt = {0, bottom_max};
1434
1435 ScreenToClient(_hwnd, &pt);
1436
1437 _bottom_max = pt.y;
1438 }
1439 }
1440
1441 #else // _LIGHT_STARTMENU
1442
1443 LRESULT StartMenuButton::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
1444 {
1445 switch(nmsg) {
1446 case WM_MOUSEMOVE:
1447 // automatically set the focus to startmenu entries when moving the mouse over them
1448 if (GetFocus()!=_hwnd && !(GetWindowStyle(_hwnd)&WS_DISABLED))
1449 SetFocus(_hwnd);
1450 break;
1451
1452 case WM_SETFOCUS:
1453 PostParent(PM_STARTENTRY_FOCUSED, _hasSubmenu, (LPARAM)_hwnd);
1454 goto def;
1455
1456 case WM_CANCELMODE:
1457 // route WM_CANCELMODE to the startmenu window
1458 return SendParent(nmsg, wparam, lparam);
1459
1460 default: def:
1461 return super::WndProc(nmsg, wparam, lparam);
1462 }
1463
1464 return 0;
1465 }
1466
1467 void StartMenuButton::DrawItem(LPDRAWITEMSTRUCT dis)
1468 {
1469 TCHAR title[BUFFER_LEN];
1470
1471 GetWindowText(_hwnd, title, BUFFER_LEN);
1472
1473 DrawStartMenuButton(dis->hDC, dis->rcItem, title, _hIcon,
1474 _hasSubmenu,
1475 !(dis->itemState & ODS_DISABLED),
1476 dis->itemState&ODS_FOCUS? true: false,
1477 dis->itemState&ODS_SELECTED? true: false);
1478 }
1479
1480 #endif
1481
1482
1483 StartMenuRoot::StartMenuRoot(HWND hwnd)
1484 : super(hwnd)
1485 {
1486 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
1487 if (!g_Globals._SHRestricted || !SHRestricted(REST_NOCOMMONGROUPS))
1488 #endif
1489 try {
1490 // insert directory "All Users\Start Menu"
1491 ShellDirectory cmn_startmenu(GetDesktopFolder(), SpecialFolderPath(CSIDL_COMMON_STARTMENU, _hwnd), _hwnd);
1492 _dirs.push_back(StartMenuDirectory(cmn_startmenu, false)); // don't add subfolders
1493 } catch(COMException&) {
1494 // ignore exception and don't show additional shortcuts
1495 }
1496
1497 try {
1498 // insert directory "<user name>\Start Menu"
1499
1500 ShellDirectory usr_startmenu(GetDesktopFolder(), SpecialFolderPath(CSIDL_STARTMENU, _hwnd), _hwnd);
1501 _dirs.push_back(StartMenuDirectory(usr_startmenu, false)); // don't add subfolders
1502 } catch(COMException&) {
1503 // ignore exception and don't show additional shortcuts
1504 }
1505
1506 // read size of logo bitmap
1507 BITMAP bmp_hdr;
1508 GetObject(ResBitmap(IDB_LOGOV), sizeof(BITMAP), &bmp_hdr);
1509 _logo_size.cx = bmp_hdr.bmWidth;
1510 _logo_size.cy = bmp_hdr.bmHeight;
1511
1512 _border_left = _logo_size.cx + 1;
1513 }
1514
1515
1516 static void CalculateStartPos(HWND hwndOwner, RECT& rect)
1517 {
1518 WindowRect pos(hwndOwner);
1519
1520 rect.left = pos.left;
1521 rect.top = pos.top-STARTMENU_LINE_HEIGHT-4;
1522 rect.right = pos.left+STARTMENU_WIDTH_MIN;
1523 rect.bottom = pos.top;
1524
1525 #ifndef _LIGHT_STARTMENU
1526 rect.top += STARTMENU_LINE_HEIGHT;
1527 #endif
1528
1529 AdjustWindowRectEx(&rect, WS_POPUP|WS_THICKFRAME|WS_CLIPCHILDREN|WS_VISIBLE, FALSE, 0);
1530 }
1531
1532 HWND StartMenuRoot::Create(HWND hwndOwner)
1533 {
1534 RECT rect;
1535
1536 CalculateStartPos(hwndOwner, rect);
1537
1538 return Window::Create(WINDOW_CREATOR(StartMenuRoot), 0, GetWndClasss(), TITLE_STARTMENU,
1539 WS_POPUP|WS_THICKFRAME|WS_CLIPCHILDREN,
1540 rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, hwndOwner);
1541 }
1542
1543
1544 void StartMenuRoot::TrackStartmenu()
1545 {
1546 MSG msg;
1547 HWND hwnd = _hwnd;
1548
1549 #ifdef _LIGHT_STARTMENU
1550 _selected_id = -1;
1551 #endif
1552
1553 #ifdef _LIGHT_STARTMENU
1554 // recalculate start menu root position
1555 RECT rect;
1556
1557 CalculateStartPos(GetParent(hwnd), rect);
1558
1559 SetWindowPos(hwnd, 0, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, 0);
1560
1561 ResizeToButtons();
1562 #endif
1563
1564 // show previously hidden start menu
1565 ShowWindow(hwnd, SW_SHOW);
1566 SetForegroundWindow(hwnd);
1567
1568 while(IsWindow(hwnd)) {
1569 if (!GetMessage(&msg, 0, 0, 0)) {
1570 PostQuitMessage(msg.wParam);
1571 break;
1572 }
1573
1574 // Check for a mouse click on any window, which is not part of the start menu
1575 if (msg.message==WM_LBUTTONDOWN || msg.message==WM_MBUTTONDOWN || msg.message==WM_RBUTTONDOWN) {
1576 StartMenu* menu_wnd = NULL;
1577
1578 for(HWND hwnd=msg.hwnd; hwnd; hwnd=GetParent(hwnd)) {
1579 menu_wnd = WINDOW_DYNAMIC_CAST(StartMenu, hwnd);
1580
1581 if (menu_wnd)
1582 break;
1583 }
1584
1585 if (!menu_wnd) {
1586 CloseStartMenu();
1587 break;
1588 }
1589 }
1590
1591 try {
1592 if (pretranslate_msg(&msg))
1593 continue;
1594
1595 if (dispatch_dialog_msg(&msg))
1596 continue;
1597
1598 TranslateMessage(&msg);
1599
1600 try {
1601 DispatchMessage(&msg);
1602 } catch(COMException& e) {
1603 HandleException(e, _hwnd);
1604 }
1605 } catch(COMException& e) {
1606 HandleException(e, _hwnd);
1607 }
1608 }
1609 }
1610
1611
1612 LRESULT StartMenuRoot::Init(LPCREATESTRUCT pcs)
1613 {
1614 // add buttons for entries in _entries
1615 if (super::Init(pcs))
1616 return 1;
1617
1618 AddSeparator();
1619
1620
1621 #ifdef __MINGW32__
1622 HKEY hkey, hkeyAdv;
1623 DWORD value, len;
1624
1625 if (RegOpenKey(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer"), &hkey))
1626 hkey = 0;
1627
1628 if (RegOpenKey(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"), &hkeyAdv))
1629 hkeyAdv = 0;
1630
1631 #define IS_VALUE_ZERO(hk, name) \
1632 (!hk || (len=sizeof(value),RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE)&value, &len) || !value))
1633
1634 #define IS_VALUE_NOT_ZERO(hk, name) \
1635 (!hk || (len=sizeof(value),RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE)&value, &len) || value>0))
1636 #endif
1637
1638
1639 // insert hard coded start entries
1640 AddButton(ResString(IDS_PROGRAMS), ICID_APPS, true, IDC_PROGRAMS);
1641
1642 AddButton(ResString(IDS_DOCUMENTS), ICID_DOCUMENTS, true, IDC_DOCUMENTS);
1643
1644 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
1645 if (!g_Globals._SHRestricted || !SHRestricted(REST_NORECENTDOCSMENU))
1646 #else
1647 if (IS_VALUE_ZERO(hkey, _T("NoRecentDocsMenu")))
1648 #endif
1649 AddButton(ResString(IDS_RECENT), ICID_DOCUMENTS, true, IDC_RECENT);
1650
1651 AddButton(ResString(IDS_FAVORITES), ICID_FAVORITES, true, IDC_FAVORITES);
1652
1653 AddButton(ResString(IDS_SETTINGS), ICID_CONFIG, true, IDC_SETTINGS);
1654
1655 AddButton(ResString(IDS_BROWSE), ICID_FOLDER, true, IDC_BROWSE);
1656
1657 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
1658 if (!g_Globals._SHRestricted || !SHRestricted(REST_NOFIND))
1659 #else
1660 if (IS_VALUE_ZERO(hkey, _T("NoFind")))
1661 #endif
1662 AddButton(ResString(IDS_SEARCH), ICID_SEARCH, true, IDC_SEARCH);
1663
1664 AddButton(ResString(IDS_START_HELP), ICID_INFO, false, IDC_START_HELP);
1665
1666 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
1667 if (!g_Globals._SHRestricted || !SHRestricted(REST_NORUN))
1668 #else
1669 if (IS_VALUE_ZERO(hkey, _T("NoRun")))
1670 #endif
1671 AddButton(ResString(IDS_LAUNCH), ICID_ACTION, false, IDC_LAUNCH);
1672
1673
1674 AddSeparator();
1675
1676
1677 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
1678 if (!g_Globals._SHRestricted || !SHRestricted(REST_NOCLOSE))
1679 #else
1680 if (IS_VALUE_NOT_ZERO(hkeyAdv, _T("StartMenuLogoff")))
1681 #endif
1682 AddButton(ResString(IDS_LOGOFF), ICID_LOGOFF, false, IDC_LOGOFF);
1683
1684
1685 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
1686 if (!g_Globals._SHRestricted || SHRestricted(REST_STARTMENULOGOFF) != 1)
1687 #else
1688 if (IS_VALUE_ZERO(hkey, _T("NoClose")))
1689 #endif
1690 AddButton(ResString(IDS_SHUTDOWN), ICID_LOGOFF, false, IDC_SHUTDOWN);
1691
1692
1693 #ifdef __MINGW32__
1694 RegCloseKey(hkeyAdv);
1695 RegCloseKey(hkey);
1696 #endif
1697
1698
1699 #ifdef _LIGHT_STARTMENU
1700 // set the window size to fit all buttons
1701 ResizeToButtons();
1702 #endif
1703
1704 return 0;
1705 }
1706
1707
1708 void StartMenuRoot::AddEntries()
1709 {
1710 super::AddEntries();
1711
1712 AddButton(ResString(IDS_EXPLORE), ICID_EXPLORER, false, IDC_EXPLORE);
1713 }
1714
1715
1716 LRESULT StartMenuRoot::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
1717 {
1718 switch(nmsg) {
1719 case WM_PAINT: {
1720 PaintCanvas canvas(_hwnd);
1721 Paint(canvas);
1722 break;}
1723
1724 default:
1725 return super::WndProc(nmsg, wparam, lparam);
1726 }
1727
1728 return 0;
1729 }
1730
1731 void StartMenuRoot::Paint(PaintCanvas& canvas)
1732 {
1733 int clr_bits;
1734 {WindowCanvas dc(_hwnd); clr_bits=GetDeviceCaps(dc, BITSPIXEL);}
1735
1736 MemCanvas mem_dc;
1737 ResBitmap bmp(clr_bits<=8? clr_bits<=4? IDB_LOGOV16: IDB_LOGOV256: IDB_LOGOV);
1738 BitmapSelection sel(mem_dc, bmp);
1739
1740 ClientRect clnt(_hwnd);
1741 int h = min(_logo_size.cy, clnt.bottom);
1742
1743 RECT rect = {0, 0, _logo_size.cx, clnt.bottom-h};
1744 HBRUSH hbr = CreateSolidBrush(GetPixel(mem_dc, 0, 0));
1745 FillRect(canvas, &rect, hbr);
1746 DeleteObject(hbr);
1747
1748 PatBlt(canvas, _logo_size.cx, 0, 1, clnt.bottom, WHITENESS);
1749
1750 BitBlt(canvas, 0, clnt.bottom-h, _logo_size.cx, h, mem_dc, 0, 0, SRCCOPY);
1751
1752 super::Paint(canvas);
1753 }
1754
1755
1756 void StartMenuRoot::CloseStartMenu(int id)
1757 {
1758 if (_submenu)
1759 CloseSubmenus();
1760
1761 ShowWindow(_hwnd, SW_HIDE);
1762 }
1763
1764 void StartMenuRoot::ProcessKey(int vk)
1765 {
1766 switch(vk) {
1767 case VK_LEFT:
1768 if (_submenu)
1769 CloseOtherSubmenus();
1770 // don't close start menu root
1771 break;
1772
1773 default:
1774 super::ProcessKey(vk);
1775 }
1776 }
1777
1778
1779 int StartMenuHandler::Command(int id, int code)
1780 {
1781 switch(id) {
1782
1783 // start menu root
1784
1785 case IDC_PROGRAMS:
1786 CreateSubmenu(id, CSIDL_COMMON_PROGRAMS, CSIDL_PROGRAMS, ResString(IDS_PROGRAMS));
1787 break;
1788
1789 case IDC_EXPLORE:
1790 CloseStartMenu(id);
1791 explorer_show_frame(SW_SHOWNORMAL);
1792 break;
1793
1794 case IDC_LAUNCH:
1795 CloseStartMenu(id);
1796 ShowLaunchDialog(g_Globals._hwndDesktopBar);
1797 break;
1798
1799 case IDC_DOCUMENTS:
1800 CreateSubmenu(id, CSIDL_PERSONAL, ResString(IDS_DOCUMENTS));
1801 break;
1802
1803 case IDC_RECENT:
1804 CreateSubmenu(id, CSIDL_RECENT, ResString(IDS_RECENT), STARTMENU_CREATOR(RecentStartMenu));
1805 break;
1806
1807 case IDC_FAVORITES:
1808 #ifndef _SHELL32_FAVORITES
1809 CreateSubmenu(id, ResString(IDS_FAVORITES), STARTMENU_CREATOR(FavoritesMenu), &static_cast<BookmarkList&>(g_Globals._favorites));
1810 #else
1811 CreateSubmenu(id, CSIDL_COMMON_FAVORITES, CSIDL_FAVORITES, ResString(IDS_FAVORITES));
1812 #endif
1813 break;
1814
1815 case IDC_BROWSE:
1816 CreateSubmenu(id, ResString(IDS_BROWSE), STARTMENU_CREATOR(BrowseMenu));
1817 break;
1818
1819 case IDC_SETTINGS:
1820 CreateSubmenu(id, ResString(IDS_SETTINGS), STARTMENU_CREATOR(SettingsMenu));
1821 break;
1822
1823 case IDC_SEARCH:
1824 CreateSubmenu(id, ResString(IDS_SEARCH), STARTMENU_CREATOR(SearchMenu));
1825 break;
1826
1827 case IDC_START_HELP:
1828 CloseStartMenu(id);
1829 MessageBox(g_Globals._hwndDesktopBar, TEXT("Help not yet implemented"), ResString(IDS_TITLE), MB_OK);
1830 break;
1831
1832 case IDC_LOGOFF:
1833 /* The shell32 Dialog prompts about some system setting change. This is not what we want to display here.
1834 CloseStartMenu(id);
1835 ShowRestartDialog(g_Globals._hwndDesktopBar, EWX_LOGOFF);*/
1836 DestroyWindow(GetParent(_hwnd));
1837 break;
1838
1839 case IDC_SHUTDOWN:
1840 CloseStartMenu(id);
1841 ShowExitWindowsDialog(g_Globals._hwndDesktopBar);
1842 break;
1843
1844
1845 // settings menu
1846
1847 case ID_DESKTOPBAR_SETTINGS:
1848 CloseStartMenu(id);
1849 ExplorerPropertySheet(g_Globals._hwndDesktopBar);
1850 break;
1851
1852 case IDC_SETTINGS_MENU:
1853 CreateSubmenu(id, CSIDL_CONTROLS, ResString(IDS_SETTINGS_MENU));
1854 break;
1855
1856 case IDC_PRINTERS:
1857 #ifdef _ROS_ // to be removed when printer folder will be implemented
1858 MessageBox(0, TEXT("printer folder not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
1859 #else
1860 CreateSubmenu(id, CSIDL_PRINTERS, CSIDL_PRINTHOOD, ResString(IDS_PRINTERS));
1861 #endif
1862 break;
1863
1864 case IDC_CONTROL_PANEL:
1865 CloseStartMenu(id);
1866 //@@SDIMainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}"), 0);
1867 break;
1868
1869 case IDC_ADMIN:
1870 CreateSubmenu(id, CSIDL_COMMON_ADMINTOOLS, CSIDL_ADMINTOOLS, ResString(IDS_ADMIN));
1871 break;
1872
1873 case IDC_CONNECTIONS:
1874 #ifdef _ROS_ // to be removed when RAS will be implemented
1875 MessageBox(0, TEXT("RAS folder not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
1876 #else
1877 CreateSubmenu(id, CSIDL_CONNECTIONS, ResString(IDS_CONNECTIONS));
1878 #endif
1879 break;
1880
1881
1882 // browse menu
1883
1884 case IDC_NETWORK:
1885 #ifdef _ROS_ // to be removed when network will be implemented
1886 MessageBox(0, TEXT("network not yet implemented"), ResString(IDS_TITLE), MB_OK);
1887 #else
1888 CreateSubmenu(id, CSIDL_NETWORK, ResString(IDS_NETWORK));
1889 #endif
1890 break;
1891
1892 case IDC_DRIVES:
1893 ///@todo exclude removeable drives
1894 CreateSubmenu(id, CSIDL_DRIVES, ResString(IDS_DRIVES));
1895 break;
1896
1897
1898 // search menu
1899
1900 case IDC_SEARCH_PROGRAM:
1901 CloseStartMenu(id);
1902 Dialog::DoModal(IDD_SEARCH_PROGRAM, WINDOW_CREATOR(FindProgramDlg));
1903 break;
1904
1905 case IDC_SEARCH_FILES:
1906 CloseStartMenu(id);
1907 ShowSearchDialog();
1908 break;
1909
1910 case IDC_SEARCH_COMPUTER:
1911 CloseStartMenu(id);
1912 ShowSearchComputer();
1913 break;
1914
1915
1916 default:
1917 return super::Command(id, code);
1918 }
1919
1920 return 0;
1921 }
1922
1923
1924 void StartMenuHandler::ShowSearchDialog()
1925 {
1926 static DynamicFct<SHFINDFILES> SHFindFiles(TEXT("SHELL32"), 90);
1927
1928 if (SHFindFiles)
1929 (*SHFindFiles)(NULL, NULL);
1930 else
1931 MessageBox(0, TEXT("SHFindFiles() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
1932 }
1933
1934 void StartMenuHandler::ShowSearchComputer()
1935 {
1936 static DynamicFct<SHFINDCOMPUTER> SHFindComputer(TEXT("SHELL32"), 91);
1937
1938 if (SHFindComputer)
1939 (*SHFindComputer)(NULL, NULL);
1940 else
1941 MessageBox(0, TEXT("SHFindComputer() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
1942 }
1943
1944 void StartMenuHandler::ShowLaunchDialog(HWND hwndOwner)
1945 {
1946 ///@todo All text phrases should be put into the resources.
1947 static LPCSTR szTitle = "Run";
1948 static LPCSTR szText = "Type the name of a program, folder, document, or Internet resource, and Explorer will open it for you.";
1949
1950 static DynamicFct<RUNFILEDLG> RunFileDlg(TEXT("SHELL32"), 61);
1951
1952 // Show "Run..." dialog
1953 if (RunFileDlg) {
1954 #ifndef _ROS_ /* FIXME: our shell32 always expects Ansi strings */
1955 #define W_VER_NT 0
1956 if ((HIWORD(GetVersion())>>14) == W_VER_NT) {
1957 WCHAR wTitle[40], wText[256];
1958
1959 MultiByteToWideChar(CP_ACP, 0, szTitle, -1, wTitle, 40);
1960 MultiByteToWideChar(CP_ACP, 0, szText, -1, wText, 256);
1961
1962 (*RunFileDlg)(hwndOwner, 0, NULL, (LPCSTR)wTitle, (LPCSTR)wText, RFF_CALCDIRECTORY);
1963 }
1964 else
1965 #endif
1966 (*RunFileDlg)(hwndOwner, 0, NULL, szTitle, szText, RFF_CALCDIRECTORY);
1967 }
1968 }
1969
1970 void StartMenuHandler::ShowRestartDialog(HWND hwndOwner, UINT flags)
1971 {
1972 static DynamicFct<RESTARTWINDOWSDLG> RestartDlg(TEXT("SHELL32"), 59);
1973
1974 if (RestartDlg)
1975 (*RestartDlg)(hwndOwner, (LPWSTR)L"You selected <Log Off>.\n\n", flags); ///@todo ANSI string conversion if needed
1976 else
1977 MessageBox(hwndOwner, TEXT("RestartDlg() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
1978 }
1979
1980 void ShowExitWindowsDialog(HWND hwndOwner)
1981 {
1982 static DynamicFct<EXITWINDOWSDLG> ExitWindowsDlg(TEXT("SHELL32"), 60);
1983
1984 if (ExitWindowsDlg)
1985 (*ExitWindowsDlg)(hwndOwner);
1986 else
1987 MessageBox(hwndOwner, TEXT("ExitWindowsDlg() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
1988 }
1989
1990
1991 void SettingsMenu::AddEntries()
1992 {
1993 super::AddEntries();
1994
1995 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
1996 if (!g_Globals._SHRestricted || !SHRestricted(REST_NOCONTROLPANEL))
1997 #endif
1998 AddButton(ResString(IDS_CONTROL_PANEL), ICID_CONFIG, false, IDC_CONTROL_PANEL);
1999
2000 #ifdef _ROS_ // to be removed when printer/network will be implemented
2001 AddButton(ResString(IDS_PRINTERS), ICID_PRINTER, false, IDC_PRINTERS);
2002 AddButton(ResString(IDS_CONNECTIONS), ICID_NETWORK, false, IDC_CONNECTIONS);
2003 #else
2004 AddButton(ResString(IDS_PRINTERS), ICID_PRINTER, true, IDC_PRINTERS);
2005 AddButton(ResString(IDS_CONNECTIONS), ICID_NETWORK, true, IDC_CONNECTIONS);
2006 #endif
2007 AddButton(ResString(IDS_ADMIN), ICID_CONFIG, true, IDC_ADMIN);
2008
2009 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
2010 if (!g_Globals._SHRestricted || !SHRestricted(REST_NOCONTROLPANEL))
2011 #endif
2012 AddButton(ResString(IDS_SETTINGS_MENU), ICID_CONFIG, true, IDC_SETTINGS_MENU);
2013
2014 AddButton(ResString(IDS_DESKTOPBAR_SETTINGS), ICID_CONFIG, false, ID_DESKTOPBAR_SETTINGS);
2015 }
2016
2017 void BrowseMenu::AddEntries()
2018 {
2019 super::AddEntries();
2020
2021 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
2022 if (!g_Globals._SHRestricted || !SHRestricted(REST_NONETHOOD)) // or REST_NOENTIRENETWORK ?
2023 #endif
2024 #ifdef _ROS_ // to be removed when printer/network will be implemented
2025 AddButton(ResString(IDS_NETWORK), ICID_NETWORK, false, IDC_NETWORK);
2026 #else
2027 AddButton(ResString(IDS_NETWORK), ICID_NETWORK, true, IDC_NETWORK);
2028 #endif
2029
2030 AddButton(ResString(IDS_DRIVES), ICID_FOLDER, true, IDC_DRIVES);
2031 }
2032
2033 void SearchMenu::AddEntries()
2034 {
2035 super::AddEntries();
2036
2037 AddButton(ResString(IDS_SEARCH_FILES), ICID_SEARCH_DOC, false, IDC_SEARCH_FILES);
2038
2039 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
2040 if (!g_Globals._SHRestricted || !SHRestricted(REST_HASFINDCOMPUTERS))
2041 #endif
2042 AddButton(ResString(IDS_SEARCH_COMPUTER),ICID_COMPUTER, false, IDC_SEARCH_COMPUTER);
2043
2044 AddButton(ResString(IDS_SEARCH_PRG), ICID_APPS, false, IDC_SEARCH_PROGRAM);
2045 }
2046
2047
2048 void RecentStartMenu::AddEntries()
2049 {
2050 for(StartMenuShellDirs::iterator it=_dirs.begin(); it!=_dirs.end(); ++it) {
2051 StartMenuDirectory& smd = *it;
2052 ShellDirectory& dir = smd._dir;
2053
2054 if (!dir._scanned) {
2055 WaitCursor wait;
2056
2057 #ifdef _LAZY_ICONEXTRACT
2058 dir.smart_scan(SORT_NAME, SCAN_FILESYSTEM);
2059 #else
2060 dir.smart_scan(SORT_NAME, SCAN_EXTRACT_ICONS|SCAN_FILESYSTEM);
2061 #endif
2062 }
2063
2064 dir.sort_directory(SORT_DATE);
2065 AddShellEntries(dir, RECENT_DOCS_COUNT, smd._subfolders);
2066 }
2067 }
2068
2069
2070 #ifndef _SHELL32_FAVORITES
2071
2072 void FavoritesMenu::AddEntries()
2073 {
2074 super::AddEntries();
2075
2076 for(BookmarkList::iterator it=_bookmarks.begin(); it!=_bookmarks.end(); ++it) {
2077 BookmarkNode& node = *it;
2078
2079 int id = ++_next_id;
2080
2081 _entries[id] = node;
2082
2083 if (node._type == BookmarkNode::BMNT_FOLDER) {
2084 BookmarkFolder& folder = *node._pfolder;
2085
2086 AddButton(folder._name, ICID_FOLDER, true, id);
2087 } else if (node._type == BookmarkNode::BMNT_BOOKMARK) {
2088 Bookmark& bookmark = *node._pbookmark;
2089
2090 ICON_ID icon = ICID_NONE;
2091
2092 if (!bookmark._icon_path.empty())
2093 icon = g_Globals._icon_cache.extract(bookmark._icon_path, bookmark._icon_idx);
2094
2095 AddButton(bookmark._name, icon!=ICID_NONE?icon:ICID_BOOKMARK, false, id);
2096 }
2097 }
2098 }
2099
2100 int FavoritesMenu::Command(int id, int code)
2101 {
2102 BookmarkMap::iterator found = _entries.find(id);
2103
2104 if (found != _entries.end()) {
2105 BookmarkNode& node = found->second;
2106
2107 if (node._type == BookmarkNode::BMNT_FOLDER) {
2108 BookmarkFolder& folder = *node._pfolder;
2109
2110 if (CloseOtherSubmenus(id))
2111 CreateSubmenu(id, folder._name, STARTMENU_CREATOR(FavoritesMenu), &static_cast<BookmarkList&>(folder._bookmarks));
2112 } else if (node._type == BookmarkNode::BMNT_BOOKMARK) {
2113 Bookmark& bookmark = *node._pbookmark;
2114
2115 String url = bookmark._url;
2116 HWND hparent = GetParent(_hwnd);
2117
2118 CloseStartMenu(id);
2119
2120 launch_file(hparent, url, SW_SHOWNORMAL);
2121 }
2122
2123 return 0;
2124 }
2125
2126 return super::Command(id, code);
2127 }
2128
2129 #endif