/*
- * Copyright 2003 Martin Fuchs
+ * Copyright 2003, 2004 Martin Fuchs
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
//
-#include "../utility/utility.h"
+#include "precomp.h"
-#include "../explorer.h"
-#include "../globals.h"
-#include "../externals.h"
#include "../explorer_intres.h"
#include "desktopbar.h"
#include "startmenu.h"
+
#include "../dialogs/searchprogram.h"
+#include "../dialogs/settings.h"
+
+
+#define SHELLPATH_CONTROL_PANEL TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}")
+#define SHELLPATH_PRINTERS TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}")
+#define SHELLPATH_NET_CONNECTIONS TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}")
StartMenu::StartMenu(HWND hwnd)
{
_next_id = IDC_FIRST_MENU;
_submenu_id = 0;
+
_border_left = 0;
_border_top = 0;
+ _bottom_max = INT_MAX;
+
+ _floating_btn = false;
+ _arrow_btns = false;
+ _scroll_mode = SCROLL_NOT;
+ _scroll_pos = 0;
+ _invisible_lines = 0;
+
_last_pos = WindowRect(hwnd).pos();
+#ifdef _LIGHT_STARTMENU
+ _selected_id = -1;
+ _last_mouse_pos = 0;
+#endif
}
StartMenu::StartMenu(HWND hwnd, const StartMenuCreateInfo& create_info)
{
for(StartMenuFolders::const_iterator it=create_info._folders.begin(); it!=create_info._folders.end(); ++it)
if (*it)
- _dirs.push_back(ShellDirectory(Desktop(), *it, _hwnd));
+ _dirs.push_back(ShellDirectory(GetDesktopFolder(), *it, _hwnd));
_next_id = IDC_FIRST_MENU;
_submenu_id = 0;
+
_border_left = 0;
_border_top = create_info._border_top;
+ _bottom_max = INT_MAX;
+
+ _floating_btn = create_info._border_top? true: false;
+ _arrow_btns = false;
+ _scroll_mode = SCROLL_NOT;
+ _scroll_pos = 0;
+ _invisible_lines = 0;
+
_last_pos = WindowRect(hwnd).pos();
+#ifdef _LIGHT_STARTMENU
+ _selected_id = -1;
+ _last_mouse_pos = 0;
+#endif
}
StartMenu::~StartMenu()
}
-Window::CREATORFUNC StartMenu::s_def_creator = STARTMENU_CREATOR(StartMenu);
+Window::CREATORFUNC_INFO StartMenu::s_def_creator = STARTMENU_CREATOR(StartMenu);
-HWND StartMenu::Create(int x, int y, const StartMenuFolders& folders, HWND hwndParent, LPCTSTR title, CREATORFUNC creator)
+HWND StartMenu::Create(int x, int y, const StartMenuFolders& folders, HWND hwndParent, LPCTSTR title, CREATORFUNC_INFO creator, void* info)
{
UINT style, ex_style;
int top_height;
top_height = 0;
}
- RECT rect = {x, y, x+STARTMENU_WIDTH_MIN, y+top_height}; // start height before adding an menu button
+ RECT rect = {x, y-STARTMENU_LINE_HEIGHT-top_height, x+STARTMENU_WIDTH_MIN, y};
+
+#ifndef _LIGHT_STARTMENU
+ rect.top += STARTMENU_LINE_HEIGHT;
+#endif
AdjustWindowRectEx(&rect, style, FALSE, ex_style);
create_info._folders = folders;
create_info._border_top = top_height;
create_info._creator = creator;
+ create_info._info = info;
if (title)
create_info._title = title;
}
-LRESULT StartMenu::Init(LPCREATESTRUCT pcs)
+LRESULT StartMenu::Init(LPCREATESTRUCT pcs)
{
try {
AddEntries();
if ((*it)->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
hasSubmenu = true;
+#ifdef _LIGHT_STARTMENU
+ _buttons.push_back(SMBtnInfo(sme, it->first, hasSubmenu));
+#else
AddButton(sme._title, sme._hIcon, hasSubmenu, it->first);
+#endif
}
+#ifdef _LIGHT_STARTMENU
+ if (_buttons.empty())
+#else
if (!GetWindow(_hwnd, GW_CHILD))
- AddButton(ResString(IDS_EMPTY), 0, false, (UINT)-1, WS_VISIBLE|WS_CHILD|BS_OWNERDRAW|WS_DISABLED);
+#endif
+ AddButton(ResString(IDS_EMPTY), ICID_NONE, false, 0, false);
+
+#ifdef _LIGHT_STARTMENU
+ ResizeToButtons();
+#endif
+
+#ifdef _LAZY_ICONEXTRACT
+ PostMessage(_hwnd, PM_UPDATE_ICONS, 0, 0);
+#endif
} catch(COMException& e) {
HandleException(e, pcs->hwndParent); // destroys the start menu window while switching focus
}
if (!dir._scanned) {
WaitCursor wait;
- dir.smart_scan();
+#ifdef _LAZY_ICONEXTRACT
+ dir.smart_scan(SORT_NAME, SCAN_FILESYSTEM); // lazy icon extraction, try to read directly from filesystem
+#else
+ dir.smart_scan(SORT_NAME, SCAN_EXTRACT_ICONS|SCAN_FILESYSTEM);
+#endif
}
AddShellEntries(dir, -1, smd._subfolders);
{
int cnt = 0;
- for(const Entry*entry=dir._down; entry; entry=entry->_next) {
+ for(Entry*entry=dir._down; entry; entry=entry->_next) {
// hide files like "desktop.ini"
if (entry->_shell_attribs & SFGAO_HIDDEN)
//not appropriate for drive roots: if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
if (++cnt == max)
break;
- const ShellEntry* shell_entry = static_cast<const ShellEntry*>(entry);
-
- AddEntry(dir._folder, shell_entry);
+ if (entry->_etype == ET_SHELL)
+ AddEntry(dir._folder, static_cast<ShellEntry*>(entry));
+ else
+ AddEntry(dir._folder, entry);
}
}
LRESULT StartMenu::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
{
switch(nmsg) {
- case WM_PAINT:
- DrawFloatingButton(PaintCanvas(_hwnd));
- break;
+ case WM_PAINT: {
+ PaintCanvas canvas(_hwnd);
+ Paint(canvas);
+ break;}
case WM_SIZE:
ResizeButtons(LOWORD(lparam)-_border_left);
RECT rect;
// check mouse cursor for coordinates of floating button
- GetFloatingButonRect(&rect);
+ GetFloatingButtonRect(&rect);
if (PtInRect(&rect, Point(lparam))) {
// create a floating copy of the current start menu
WindowRect pos(_hwnd);
///@todo do something similar to StartMenuRoot::TrackStartmenu() in order to automatically close submenus when clicking on the desktop background
- StartMenu::Create(pos.left+3, pos.bottom-3, _create_info._folders, 0, _create_info._title, _create_info._creator);
+ StartMenu::Create(pos.left+3, pos.bottom-3, _create_info._folders, 0, _create_info._title, _create_info._creator, _create_info._info);
CloseStartMenu();
}
+
+#ifdef _LIGHT_STARTMENU
+ int id = ButtonHitTest(Point(lparam));
+
+ if (id)
+ Command(id, BN_CLICKED);
+#endif
break;}
case WM_SYSCOMMAND:
case WM_CANCELMODE:
CloseStartMenu();
+
+#ifdef _LIGHT_STARTMENU
+ if (_scroll_mode != SCROLL_NOT) {
+ ReleaseCapture();
+ KillTimer(_hwnd, 0);
+ }
+#endif
+ break;
+
+#ifdef _LIGHT_STARTMENU
+ case WM_MOUSEMOVE: {
+ // automatically set the focus to startmenu entries when moving the mouse over them
+ if (lparam != _last_mouse_pos) { // don't process WM_MOUSEMOVE when opening submenus using keyboard navigation
+ Point pt(lparam);
+
+ if (_arrow_btns) {
+ RECT rect_up, rect_down;
+
+ GetArrowButtonRects(&rect_up, &rect_down);
+
+ SCROLL_MODE scroll_mode = SCROLL_NOT;
+
+ if (PtInRect(&rect_up, pt))
+ scroll_mode = SCROLL_UP;
+ else if (PtInRect(&rect_down, pt))
+ scroll_mode = SCROLL_DOWN;
+
+ if (scroll_mode != _scroll_mode) {
+ if (scroll_mode == SCROLL_NOT) {
+ ReleaseCapture();
+ KillTimer(_hwnd, 0);
+ } else {
+ CloseSubmenus();
+ SetTimer(_hwnd, 0, 150, NULL); // 150 ms scroll interval
+ SetCapture(_hwnd);
+ }
+
+ _scroll_mode = scroll_mode;
+ }
+ }
+
+ int new_id = ButtonHitTest(pt);
+
+ if (new_id > 0 && new_id != _selected_id)
+ SelectButton(new_id);
+
+ _last_mouse_pos = lparam;
+ }
+ break;}
+
+ case WM_TIMER:
+ if (_scroll_mode == SCROLL_UP) {
+ if (_scroll_pos > 0) {
+ --_scroll_pos;
+ InvalidateRect(_hwnd, NULL, TRUE);
+ }
+ } else {
+ if (_scroll_pos <= _invisible_lines) {
+ ++_scroll_pos;
+ InvalidateRect(_hwnd, NULL, TRUE);
+ }
+ }
break;
+ case WM_KEYDOWN:
+ ProcessKey(wparam);
+ break;
+#else
case PM_STARTENTRY_FOCUSED: { ///@todo use TrackMouseEvent() and WM_MOUSEHOVER to wait a bit before opening submenus
BOOL hasSubmenu = wparam;
HWND hctrl = (HWND)lparam;
Command(GetDlgCtrlID(hctrl), BN_CLICKED);
} else {
// close any open submenu
- CloseOtherSubmenus(0);
+ CloseOtherSubmenus();
}
break;}
+#endif
+
+#ifdef _LAZY_ICONEXTRACT
+ case PM_UPDATE_ICONS:
+ UpdateIcons(/*wparam*/);
+ break;
+#endif
case PM_STARTENTRY_LAUNCHED:
if (GetWindowStyle(_hwnd) & WS_CAPTION) // don't automatically close floating menus
// route message to the parent menu and close menus after launching an entry
if (!SendParent(nmsg, wparam, lparam))
- DestroyWindow(_hwnd);
+ CloseStartMenu();
return 1; // signal that we have received and processed the message
case PM_STARTMENU_CLOSED:
_submenu = 0;
break;
+ case PM_SELECT_ENTRY:
+ SelectButtonIndex(0, wparam!=0);
+ break;
+
+#ifdef _LIGHT_STARTMENU
+ case WM_CONTEXTMENU: {
+ Point screen_pt(lparam), clnt_pt=screen_pt;
+ ScreenToClient(_hwnd, &clnt_pt);
+
+ int id = ButtonHitTest(clnt_pt);
+
+ if (id) {
+ StartMenuEntry& sme = _entries[id];
+
+ for(ShellEntrySet::iterator it=sme._entries.begin(); it!=sme._entries.end(); ++it) {
+ Entry* entry = *it;
+
+ if (entry) {
+ CHECKERROR(entry->do_context_menu(_hwnd, screen_pt, _cm_ifs)); // may close start menu because of focus loss
+ break; ///@todo handle context menu for more than one entry
+ }
+ }
+ }
+ break;}
+#endif
+
default: def:
return super::WndProc(nmsg, wparam, lparam);
}
}
-void StartMenu::DrawFloatingButton(HDC hdc)
-{
- static ResIconEx floatingIcon(IDI_FLOATING, 8, 4);
-
- ClientRect clnt(_hwnd);
-
- DrawIconEx(hdc, clnt.right-12, 0, floatingIcon, 8, 4, 0, 0, DI_NORMAL);
-}
+#ifdef _LIGHT_STARTMENU
-void StartMenu::GetFloatingButonRect(LPRECT prect)
+int StartMenu::ButtonHitTest(POINT pt)
{
- GetClientRect(_hwnd, prect);
+ ClientRect clnt(_hwnd);
+ RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT};
- prect->right -= 4;
- prect->left = prect->right - 8;
- prect->bottom = 4;
-}
+ if (pt.x<rect.left || pt.x>rect.right)
+ return 0;
+ for(SMBtnVector::const_iterator it=_buttons.begin()+_scroll_pos; it!=_buttons.end(); ++it) {
+ const SMBtnInfo& info = *it;
- // resize child button controls to accomodate for new window size
-void StartMenu::ResizeButtons(int cx)
-{
- HDWP hdwp = BeginDeferWindowPos(10);
+ if (rect.top > pt.y)
+ break;
- for(HWND ctrl=GetWindow(_hwnd,GW_CHILD); ctrl; ctrl=GetNextWindow(ctrl,GW_HWNDNEXT)) {
- ClientRect rt(ctrl);
+ rect.bottom = rect.top + (info._id==-1? STARTMENU_SEP_HEIGHT: STARTMENU_LINE_HEIGHT);
- if (rt.right != cx) {
- int height = rt.bottom - rt.top;
+ if (rect.bottom > _bottom_max)
+ break;
- // special handling for separator controls
- if (!height && (GetWindowStyle(ctrl)&SS_TYPEMASK)==SS_ETCHEDHORZ)
- height = 2;
+ if (pt.y < rect.bottom) // PtInRect(&rect, pt)
+ return info._id;
- hdwp = DeferWindowPos(hdwp, ctrl, 0, 0, 0, cx, height, SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
- }
+ rect.top = rect.bottom;
}
- EndDeferWindowPos(hdwp);
+ return 0;
}
-
-int StartMenu::Command(int id, int code)
+void StartMenu::InvalidateSelection()
{
- switch(id) {
- case IDCANCEL:
- DestroyWindow(_hwnd);
- break;
+ if (_selected_id <= 0)
+ return;
- default: {
- ShellEntryMap::iterator found = _entries.find(id);
+ ClientRect clnt(_hwnd);
+ RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT};
- if (found != _entries.end()) {
- ActivateEntry(id, found->second._entries);
+ for(SMBtnVector::const_iterator it=_buttons.begin()+_scroll_pos; it!=_buttons.end(); ++it) {
+ const SMBtnInfo& info = *it;
+
+ rect.bottom = rect.top + (info._id==-1? STARTMENU_SEP_HEIGHT: STARTMENU_LINE_HEIGHT);
+
+ if (info._id == _selected_id) {
+ InvalidateRect(_hwnd, &rect, TRUE);
break;
}
- return super::Command(id, code);}
+ rect.top = rect.bottom;
}
-
- return 0;
}
-
-StartMenuEntry& StartMenu::AddEntry(LPCTSTR title, HICON hIcon, UINT id)
+const SMBtnInfo* StartMenu::GetButtonInfo(int id) const
{
- if (id == (UINT)-1)
- id = ++_next_id;
+ for(SMBtnVector::const_iterator it=_buttons.begin(); it!=_buttons.end(); ++it)
+ if (it->_id == id)
+ return &*it;
- StartMenuEntry& sme = _entries[id];
-
- sme._title = title;
- sme._hIcon = hIcon;
-
- return sme;
+ return NULL;
}
-StartMenuEntry& StartMenu::AddEntry(const ShellFolder folder, const ShellEntry* entry)
+bool StartMenu::SelectButton(int id, bool open_sub)
{
- HICON hIcon = entry->_hIcon;
+ if (id == -1)
+ return false;
- if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- hIcon = SmallIcon(IDI_EXPLORER);
+ if (id == _selected_id)
+ return true;
- const String& entry_name = folder.get_name(entry->_pidl);
+ InvalidateSelection();
- // search for an already existing subdirectory entry with the same name
- if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- for(ShellEntryMap::iterator it=_entries.begin(); it!=_entries.end(); ++it) {
- StartMenuEntry& sme = it->second;
+ const SMBtnInfo* btn = GetButtonInfo(id);
- if (sme._title == entry_name) ///@todo speed up by using a map indexed by name
- for(ShellEntrySet::iterator it2=sme._entries.begin(); it2!=sme._entries.end(); ++it2) {
- if ((*it2)->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- // merge the new shell entry with the existing of the same name
- sme._entries.insert(entry);
- return sme;
- }
- }
- }
+ if (btn && btn->_enabled) {
+ _selected_id = id;
- StartMenuEntry& sme = AddEntry(entry_name, hIcon);
+ InvalidateSelection();
- sme._entries.insert(entry);
+ // automatically open submenus
+ if (btn->_hasSubmenu) {
+ if (open_sub)
+ OpenSubmenu();
+ } else
+ CloseOtherSubmenus(); // close any open submenu
- return sme;
+ return true;
+ } else {
+ _selected_id = -1;
+ return false;
+ }
}
-
-void StartMenu::AddButton(LPCTSTR title, HICON hIcon, bool hasSubmenu, UINT id, DWORD style)
+bool StartMenu::OpenSubmenu(bool select_first)
{
- WindowRect rect(_hwnd);
- ClientRect clnt(_hwnd);
-
- // increase window height to make room for the new button
- rect.top -= STARTMENU_LINE_HEIGHT;
+ if (_selected_id == -1)
+ return false;
- // move down if we are too high now
- if (rect.top < 0) {
- rect.top += STARTMENU_LINE_HEIGHT;
- rect.bottom += STARTMENU_LINE_HEIGHT;
- }
+ InvalidateSelection();
- // widen window, if it is too small
- int text_width = StartMenuButton::GetTextWidth(title,_hwnd) + 16/*icon*/ + 10/*placeholder*/ + 16/*arrow*/;
+ const SMBtnInfo* btn = GetButtonInfo(_selected_id);
- int cx = clnt.right - _border_left;
- if (text_width > cx)
- rect.right += text_width-cx;
+ // automatically open submenus
+ if (btn->_hasSubmenu) {
+ //@@ allows destroying of startmenu when processing PM_UPDATE_ICONS -> GPF
+ UpdateWindow(_hwnd); // draw focused button before waiting on submenu creation
+ Command(_selected_id, BN_CLICKED);
- MoveWindow(_hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE);
+ if (select_first && _submenu)
+ SendMessage(_submenu, PM_SELECT_ENTRY, (WPARAM)false, 0);
- StartMenuCtrl(_hwnd, _border_left, clnt.bottom, rect.right-rect.left-_border_left,
- title, id, hIcon, hasSubmenu, style);
+ return true;
+ } else
+ return false;
}
-void StartMenu::AddSeparator()
-{
- WindowRect rect(_hwnd);
- ClientRect clnt(_hwnd);
-
- // increase window height to make room for the new separator
- rect.top -= STARTMENU_SEP_HEIGHT;
- // move down if we are too high now
- if (rect.top < 0) {
- rect.top += STARTMENU_LINE_HEIGHT;
- rect.bottom += STARTMENU_LINE_HEIGHT;
- }
+int StartMenu::GetSelectionIndex()
+{
+ if (_selected_id == -1)
+ return -1;
- MoveWindow(_hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE);
+ for(int i=0; i<(int)_buttons.size(); ++i)
+ if (_buttons[i]._id == _selected_id)
+ return i;
- StartMenuSeparator(_hwnd, _border_left, clnt.bottom, rect.right-rect.left-_border_left);
+ return -1;
}
+bool StartMenu::SelectButtonIndex(int idx, bool open_sub)
+{
+ if (idx>=0 && idx<(int)_buttons.size())
+ return SelectButton(_buttons[idx]._id, open_sub);
+ else
+ return false;
+}
-bool StartMenu::CloseOtherSubmenus(int id)
+void StartMenu::ProcessKey(int vk)
{
- if (_submenu) {
- if (IsWindow(_submenu)) {
- if (_submenu_id == id)
- return false;
- else {
- DestroyWindow(_submenu);
- _submenu_id = 0;
- // _submenu should be reset automatically by PM_STARTMENU_CLOSED, but safety first...
- }
- }
+ switch(vk) {
+ case VK_RETURN:
+ if (_selected_id)
+ Command(_selected_id, BN_CLICKED);
+ break;
- _submenu = 0;
- }
+ case VK_UP:
+ Navigate(-1);
+ break;
- return true;
-}
+ case VK_DOWN:
+ Navigate(+1);
+ break;
+ case VK_HOME:
+ SelectButtonIndex(0, false);
+ break;
-void StartMenu::CreateSubmenu(int id, LPCTSTR title, CREATORFUNC creator)
-{
- CreateSubmenu(id, StartMenuFolders(), title, creator);
-}
+ case VK_END:
+ SelectButtonIndex(_buttons.size()-1, false);
+ break;
-void StartMenu::CreateSubmenu(int id, int folder_id, LPCTSTR title, CREATORFUNC creator)
-{
- try {
- SpecialFolderPath folder(folder_id, _hwnd);
+ case VK_LEFT:
+ if (_submenu)
+ CloseOtherSubmenus();
+ else if (!(GetWindowStyle(_hwnd) & WS_CAPTION)) // don't automatically close floating menus
+ DestroyWindow(_hwnd);
+ break;
- StartMenuFolders new_folders;
- new_folders.push_back(folder);
+ case VK_RIGHT:
+ OpenSubmenu(true);
+ break;
- CreateSubmenu(id, new_folders, title, creator);
- } catch(COMException&) {
- // ignore Exception and don't display anything
+ case VK_ESCAPE:
+ CloseStartMenu();
+ break;
+
+ default:
+ if (vk>='0' && vk<='Z')
+ JumpToNextShortcut(vk);
}
}
-void StartMenu::CreateSubmenu(int id, int folder_id1, int folder_id2, LPCTSTR title, CREATORFUNC creator)
+bool StartMenu::Navigate(int step)
{
- StartMenuFolders new_folders;
+ int idx = GetSelectionIndex();
- try {
- new_folders.push_back(SpecialFolderPath(folder_id1, _hwnd));
- } catch(COMException&) {
- }
+ if (idx == -1)
+ if (step > 0)
+ idx = 0 - step;
+ else
+ idx = _buttons.size() - step;
- try {
- new_folders.push_back(SpecialFolderPath(folder_id2, _hwnd));
- } catch(COMException&) {
+ for(;;) {
+ idx += step;
+
+ if (idx<0 || idx>(int)_buttons.size())
+ break;
+
+ if (SelectButtonIndex(idx, false))
+ return true;
}
- if (!new_folders.empty())
- CreateSubmenu(id, new_folders, title, creator);
+ return false;
}
-void StartMenu::CreateSubmenu(int id, const StartMenuFolders& new_folders, LPCTSTR title, CREATORFUNC creator)
+bool StartMenu::JumpToNextShortcut(char c)
{
- // Only open one submenu at a time.
- if (!CloseOtherSubmenus(id))
- return;
+ int cur_idx = GetSelectionIndex();
- HWND btn = GetDlgItem(_hwnd, id);
- int x, y;
+ if (cur_idx == -1)
+ cur_idx = 0;
- if (btn) {
- WindowRect pos(btn);
+ int first_found = 0;
+ int found_more = 0;
- x = pos.right; // Submenus should overlap their parent a bit.
- y = pos.top+STARTMENU_LINE_HEIGHT-_border_top;
- } else {
- WindowRect pos(_hwnd);
+ SMBtnVector::const_iterator cur_it = _buttons.begin();
+ cur_it += cur_idx + 1;
- x = pos.right;
- y = pos.top;
+ // first search down from current item...
+ SMBtnVector::const_iterator it = cur_it;
+ for(; it!=_buttons.end(); ++it) {
+ const SMBtnInfo& btn = *it;
+
+ if (!btn._title.empty() && toupper((TBYTE)btn._title.at(0)) == c) {
+ if (!first_found)
+ first_found = btn._id;
+ else
+ ++found_more;
+ }
}
- _submenu_id = id;
- _submenu = StartMenu::Create(x, y, new_folders, _hwnd, title, creator);
-}
+ // ...now search from top to the current item
+ it = _buttons.begin();
+ for(; it!=_buttons.end() && it!=cur_it; ++it) {
+ const SMBtnInfo& btn = *it;
+ if (!btn._title.empty() && toupper((TBYTE)btn._title.at(0)) == c) {
+ if (!first_found)
+ first_found = btn._id;
+ else
+ ++found_more;
+ }
+ }
-void StartMenu::ActivateEntry(int id, const ShellEntrySet& entries)
-{
- StartMenuFolders new_folders;
- String title;
+ if (first_found) {
+ SelectButton(first_found);
- for(ShellEntrySet::const_iterator it=entries.begin(); it!=entries.end(); ++it) {
- ShellEntry* entry = const_cast<ShellEntry*>(*it);
+ if (!found_more)
+ Command(first_found, BN_CLICKED);
- if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- new_folders.push_back(entry->create_absolute_pidl());
+ return true;
+ } else
+ return false;
+}
- if (title.empty())
- title = entry->_display_name;
- } else {
- // If the entry is no subdirectory, there can only be one shell entry.
- assert(entries.size()==1);
+#endif // _LIGHT_STARTMENU
- entry->launch_entry(_hwnd); ///@todo launch in the background; specify correct HWND for error message box titles
- // close start menus after launching the selected entry
- CloseStartMenu(id);
+bool StartMenu::GetButtonRect(int id, PRECT prect) const
+{
+#ifdef _LIGHT_STARTMENU
+ ClientRect clnt(_hwnd);
+ RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT};
- // we deleted 'this' - ensure we leave loop and function
+ for(SMBtnVector::const_iterator it=_buttons.begin()+_scroll_pos; it!=_buttons.end(); ++it) {
+ const SMBtnInfo& info = *it;
+
+ rect.bottom = rect.top + (info._id==-1? STARTMENU_SEP_HEIGHT: STARTMENU_LINE_HEIGHT);
+
+ if (info._id == id) {
+ *prect = rect;
+ return true;
+ }
+
+ rect.top = rect.bottom;
+ }
+
+ return false;
+#else
+ HWND btn = GetDlgItem(_hwnd, id);
+
+ if (btn) {
+ GetWindowRect(btn, prect);
+ ScreenToClient(_hwnd, prect);
+
+ return true;
+ } else
+ return false;
+#endif
+}
+
+
+void StartMenu::DrawFloatingButton(HDC hdc)
+{
+ static ResIconEx floatingIcon(IDI_FLOATING, 8, 4);
+
+ ClientRect clnt(_hwnd);
+
+ DrawIconEx(hdc, clnt.right-12, 0, floatingIcon, 8, 4, 0, 0, DI_NORMAL);
+}
+
+void StartMenu::GetFloatingButtonRect(LPRECT prect)
+{
+ GetClientRect(_hwnd, prect);
+
+ prect->right -= 4;
+ prect->left = prect->right - 8;
+ prect->bottom = 4;
+}
+
+
+void StartMenu::DrawArrows(HDC hdc)
+{
+ static ResIconEx arrowUpIcon(IDI_ARROW_UP, 8, 4);
+ static ResIconEx arrowDownIcon(IDI_ARROW_DOWN, 8, 4);
+
+ ClientRect clnt(_hwnd);
+
+ DrawIconEx(hdc, clnt.right/2-4, _floating_btn?3:1, arrowUpIcon, 8, 4, 0, 0, DI_NORMAL);
+ DrawIconEx(hdc, clnt.right/2-4, clnt.bottom-5, arrowDownIcon, 8, 4, 0, 0, DI_NORMAL);
+}
+
+void StartMenu::GetArrowButtonRects(LPRECT prect_up, LPRECT prect_down)
+{
+ GetClientRect(_hwnd, prect_up);
+ *prect_down = *prect_up;
+
+// prect_up->left = prect_up->right/2 - 4;
+// prect_up->right = prect_up->left + 8;
+ prect_up->right -= 8;
+ prect_up->top = _floating_btn? 3: 1;
+ prect_up->bottom = prect_up->top + 4;
+
+// prect_down->left = prect_down->right/2 - 4;
+// prect_down->right = prect_down->left + 8;
+ prect_down->right -= 8;
+ prect_down->top = prect_down->bottom - 5;
+}
+
+
+void StartMenu::Paint(PaintCanvas& canvas)
+{
+ if (_floating_btn)
+ DrawFloatingButton(canvas);
+
+#ifdef _LIGHT_STARTMENU
+ if (_arrow_btns)
+ DrawArrows(canvas);
+
+ ClientRect clnt(_hwnd);
+ RECT rect = {_border_left, _border_top, clnt.right, STARTMENU_LINE_HEIGHT};
+
+ int sep_width = rect.right-rect.left - 4;
+
+ FontSelection font(canvas, GetStockFont(DEFAULT_GUI_FONT));
+ BkMode bk_mode(canvas, TRANSPARENT);
+
+ for(SMBtnVector::const_iterator it=_buttons.begin()+_scroll_pos; it!=_buttons.end(); ++it) {
+ const SMBtnInfo& btn = *it;
+
+ if (rect.top > canvas.rcPaint.bottom)
+ break;
+
+ if (btn._id == -1) { // a separator?
+ rect.bottom = rect.top + STARTMENU_SEP_HEIGHT;
+
+ if (rect.bottom > _bottom_max)
+ break;
+
+ BrushSelection brush_sel(canvas, GetSysColorBrush(COLOR_BTNSHADOW));
+ PatBlt(canvas, rect.left+2, rect.top+STARTMENU_SEP_HEIGHT/2-1, sep_width, 1, PATCOPY);
+
+ SelectBrush(canvas, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
+ PatBlt(canvas, rect.left+2, rect.top+STARTMENU_SEP_HEIGHT/2, sep_width, 1, PATCOPY);
+ } else {
+ rect.bottom = rect.top + STARTMENU_LINE_HEIGHT;
+
+ if (rect.bottom > _bottom_max)
+ break;
+
+ if (rect.top >= canvas.rcPaint.top)
+ DrawStartMenuButton(canvas, rect, btn._title, btn, btn._id==_selected_id, false);
+ }
+
+ rect.top = rect.bottom;
+ }
+#endif
+}
+
+#ifdef _LAZY_ICONEXTRACT
+void StartMenu::UpdateIcons(/*int idx*/)
+{
+ UpdateWindow(_hwnd);
+
+#ifdef _SINGLE_ICONEXTRACT
+
+ //if (idx >= 0)
+ int idx = _scroll_pos;
+
+ for(; idx<(int)_buttons.size(); ++idx) {
+ SMBtnInfo& btn = _buttons[idx];
+
+ if (btn._icon_id==ICID_UNKNOWN && btn._id>0) {
+ StartMenuEntry& sme = _entries[btn._id];
+
+ btn._icon_id = ICID_NONE;
+
+ for(ShellEntrySet::iterator it=sme._entries.begin(); it!=sme._entries.end(); ++it) {
+ Entry* entry = *it;
+
+ if (entry->_icon_id == ICID_UNKNOWN)
+ try {
+ entry->extract_icon();
+ } catch(COMException&) {
+ // ignore unexpected exceptions while extracting icons
+ }
+
+ if (entry->_icon_id > ICID_NONE) {
+ btn._icon_id = (ICON_ID)/*@@*/ entry->_icon_id;
+
+ RECT rect;
+
+ GetButtonRect(btn._id, &rect);
+
+ if (rect.bottom > _bottom_max)
+ break;
+
+ WindowCanvas canvas(_hwnd);
+ DrawStartMenuButton(canvas, rect, NULL, btn, btn._id==_selected_id, false);
+
+ //InvalidateRect(_hwnd, &rect, FALSE);
+ //UpdateWindow(_hwnd);
+ //break;
+
+ break;
+ }
+ }
+ }
+ }
+
+// if (++idx < (int)_buttons.size())
+// PostMessage(_hwnd, PM_UPDATE_ICONS, idx, 0);
+
+#else
+
+ int icons_extracted = 0;
+ int icons_updated = 0;
+
+ for(StartMenuShellDirs::iterator it=_dirs.begin(); it!=_dirs.end(); ++it) {
+ ShellDirectory& dir = it->_dir;
+
+ icons_extracted += dir.extract_icons();
+ }
+
+ if (icons_extracted) {
+ for(ShellEntryMap::iterator it1=_entries.begin(); it1!=_entries.end(); ++it1) {
+ StartMenuEntry& sme = it1->second;
+
+ if (!sme._hIcon) {
+ sme._hIcon = (HICON)-1;
+
+ for(ShellEntrySet::const_iterator it2=sme._entries.begin(); it2!=sme._entries.end(); ++it2) {
+ const Entry* sm_entry = *it2;
+
+ if (sm_entry->_hIcon) {
+ sme._hIcon = sm_entry->_hIcon;
+ break;
+ }
+ }
+ }
+ }
+
+ for(SMBtnVector::iterator it=_buttons.begin(); it!=_buttons.end(); ++it) {
+ SMBtnInfo& info = *it;
+
+ if (info._id>0 && !info._hIcon) {
+ info._hIcon = _entries[info._id]._hIcon;
+ ++icons_updated;
+ }
+ }
+ }
+
+ if (icons_updated) {
+ InvalidateRect(_hwnd, NULL, FALSE);
+ UpdateWindow(_hwnd);
+ }
+#endif
+}
+#endif
+
+
+ // resize child button controls to accomodate for new window size
+void StartMenu::ResizeButtons(int cx)
+{
+ HDWP hdwp = BeginDeferWindowPos(10);
+
+ for(HWND ctrl=GetWindow(_hwnd,GW_CHILD); ctrl; ctrl=GetNextWindow(ctrl,GW_HWNDNEXT)) {
+ ClientRect rt(ctrl);
+
+ if (rt.right != cx) {
+ int height = rt.bottom - rt.top;
+
+ // special handling for separator controls
+ if (!height && (GetWindowStyle(ctrl)&SS_TYPEMASK)==SS_ETCHEDHORZ)
+ height = 2;
+
+ hdwp = DeferWindowPos(hdwp, ctrl, 0, 0, 0, cx, height, SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
+ }
+ }
+
+ EndDeferWindowPos(hdwp);
+}
+
+
+int StartMenu::Command(int id, int code)
+{
+#ifndef _LIGHT_STARTMENU
+ switch(id) {
+ case IDCANCEL:
+ CloseStartMenu(id);
+ break;
+
+ default: {
+#endif
+ ShellEntryMap::iterator found = _entries.find(id);
+
+ if (found != _entries.end()) {
+ ActivateEntry(id, found->second._entries);
+ return 0;
+ }
+
+ return super::Command(id, code);
+#ifndef _LIGHT_STARTMENU
+ }
+ }
+
+ return 0;
+#endif
+}
+
+
+ShellEntryMap::iterator StartMenu::AddEntry(const String& title, ICON_ID icon_id, Entry* entry)
+{
+ // search for an already existing subdirectory entry with the same name
+ if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ for(ShellEntryMap::iterator it=_entries.begin(); it!=_entries.end(); ++it) {
+ StartMenuEntry& sme = it->second;
+
+ if (!_tcsicmp(sme._title, title)) ///@todo speed up by using a map indexed by name
+ for(ShellEntrySet::iterator it2=sme._entries.begin(); it2!=sme._entries.end(); ++it2) {
+ if ((*it2)->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ // merge the new shell entry with the existing of the same name
+ sme._entries.insert(entry);
+
+ return it;
+ }
+ }
+ }
+
+ ShellEntryMap::iterator sme = AddEntry(title, icon_id);
+
+ sme->second._entries.insert(entry);
+
+ return sme;
+}
+
+ShellEntryMap::iterator StartMenu::AddEntry(const String& title, ICON_ID icon_id, int id)
+{
+ if (id == -1)
+ id = ++_next_id;
+
+ StartMenuEntry sme;
+
+ sme._title = title;
+ sme._icon_id = icon_id;
+
+ ShellEntryMap::iterator it = _entries.insert(make_pair(id, sme)).first;
+
+ return it;
+}
+
+ShellEntryMap::iterator StartMenu::AddEntry(const ShellFolder folder, ShellEntry* entry)
+{
+ ICON_ID icon_id;
+
+ if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ icon_id = ICID_FOLDER;
+ else
+ icon_id = (ICON_ID)/*@@*/ entry->_icon_id;
+
+ return AddEntry(folder.get_name(entry->_pidl), icon_id, entry);
+}
+
+ShellEntryMap::iterator StartMenu::AddEntry(const ShellFolder folder, Entry* entry)
+{
+ ICON_ID icon_id;
+
+ if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ icon_id = ICID_FOLDER;
+ else
+ icon_id = (ICON_ID)/*@@*/ entry->_icon_id;
+
+ return AddEntry(entry->_display_name, icon_id, entry);
+}
+
+
+void StartMenu::AddButton(LPCTSTR title, ICON_ID icon_id, bool hasSubmenu, int id, bool enabled)
+{
+#ifdef _LIGHT_STARTMENU
+ _buttons.push_back(SMBtnInfo(title, icon_id, id, hasSubmenu, enabled));
+#else
+ DWORD style = enabled? WS_VISIBLE|WS_CHILD|BS_OWNERDRAW: WS_VISIBLE|WS_CHILD|BS_OWNERDRAW|WS_DISABLED;
+
+ WindowRect rect(_hwnd);
+ ClientRect clnt(_hwnd);
+
+ // increase window height to make room for the new button
+ rect.top -= STARTMENU_LINE_HEIGHT;
+
+ // move down if we are too high now
+ if (rect.top < 0) {
+ rect.top += STARTMENU_LINE_HEIGHT;
+ rect.bottom += STARTMENU_LINE_HEIGHT;
+ }
+
+ WindowCanvas canvas(_hwnd);
+ FontSelection font(canvas, GetStockFont(DEFAULT_GUI_FONT));
+
+ // widen window, if it is too small
+ int text_width = GetStartMenuBtnTextWidth(canvas, title, _hwnd) + 16/*icon*/ + 10/*placeholder*/ + 16/*arrow*/;
+
+ int cx = clnt.right - _border_left;
+ if (text_width > cx)
+ rect.right += text_width-cx;
+
+ MoveWindow(_hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE);
+
+ StartMenuCtrl(_hwnd, _border_left, clnt.bottom, rect.right-rect.left-_border_left,
+ title, id, g_Globals._icon_cache.get_icon(icon_id)._hIcon, hasSubmenu, style);
+#endif
+}
+
+void StartMenu::AddSeparator()
+{
+#ifdef _LIGHT_STARTMENU
+ _buttons.push_back(SMBtnInfo(NULL, ICID_NONE, -1, false));
+#else
+ WindowRect rect(_hwnd);
+ ClientRect clnt(_hwnd);
+
+ // increase window height to make room for the new separator
+ rect.top -= STARTMENU_SEP_HEIGHT;
+
+ // move down if we are too high now
+ if (rect.top < 0) {
+ rect.top += STARTMENU_LINE_HEIGHT;
+ rect.bottom += STARTMENU_LINE_HEIGHT;
+ }
+
+ MoveWindow(_hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE);
+
+ StartMenuSeparator(_hwnd, _border_left, clnt.bottom, rect.right-rect.left-_border_left);
+#endif
+}
+
+
+bool StartMenu::CloseOtherSubmenus(int id)
+{
+ if (_submenu) {
+ if (IsWindow(_submenu)) {
+ if (_submenu_id == id)
+ return false;
+ else {
+ _submenu_id = 0;
+ DestroyWindow(_submenu);
+ // _submenu should be reset automatically by PM_STARTMENU_CLOSED, but safety first...
+ }
+ }
+
+ _submenu = 0;
+ }
+
+ return true;
+}
+
+
+void StartMenu::CreateSubmenu(int id, LPCTSTR title, CREATORFUNC_INFO creator, void* info)
+{
+ CreateSubmenu(id, StartMenuFolders(), title, creator, info);
+}
+
+bool StartMenu::CreateSubmenu(int id, int folder_id, LPCTSTR title, CREATORFUNC_INFO creator, void* info)
+{
+ try {
+ SpecialFolderPath folder(folder_id, _hwnd);
+
+ StartMenuFolders new_folders;
+ new_folders.push_back(folder);
+
+ CreateSubmenu(id, new_folders, title, creator, info);
+
+ return true;
+ } catch(COMException&) {
+ // ignore Exception and don't display anything
+ CloseOtherSubmenus(id);
+ _buttons[GetSelectionIndex()]._enabled = false; // disable entries for non-existing folders
+ return false;
+ }
+}
+
+bool StartMenu::CreateSubmenu(int id, int folder_id1, int folder_id2, LPCTSTR title, CREATORFUNC_INFO creator, void* info)
+{
+ StartMenuFolders new_folders;
+
+ try {
+ new_folders.push_back(SpecialFolderPath(folder_id1, _hwnd));
+ } catch(COMException&) {
+ }
+
+ try {
+ new_folders.push_back(SpecialFolderPath(folder_id2, _hwnd));
+ } catch(COMException&) {
+ }
+
+ if (!new_folders.empty()) {
+ CreateSubmenu(id, new_folders, title, creator, info);
+ return true;
+ } else {
+ CloseOtherSubmenus(id);
+ _buttons[GetSelectionIndex()]._enabled = false; // disable entries for non-existing folders
+ return false;
+ }
+}
+
+void StartMenu::CreateSubmenu(int id, const StartMenuFolders& new_folders, LPCTSTR title, CREATORFUNC_INFO creator, void* info)
+{
+ // Only open one submenu at a time.
+ if (!CloseOtherSubmenus(id))
+ return;
+
+ RECT rect;
+ int x, y;
+
+ if (GetButtonRect(id, &rect)) {
+ ClientToScreen(_hwnd, &rect);
+
+ x = rect.right; // Submenus should overlap their parent a bit.
+ y = rect.top+STARTMENU_LINE_HEIGHT +_border_top/*own border*/ -STARTMENU_TOP_BTN_SPACE/*border of new submenu*/;
+ } else {
+ WindowRect pos(_hwnd);
+
+ x = pos.right;
+ y = pos.top;
+ }
+
+ _submenu_id = id;
+ _submenu = StartMenu::Create(x, y, new_folders, _hwnd, title, creator, info);
+}
+
+
+void StartMenu::ActivateEntry(int id, const ShellEntrySet& entries)
+{
+ StartMenuFolders new_folders;
+ String title;
+
+ for(ShellEntrySet::const_iterator it=entries.begin(); it!=entries.end(); ++it) {
+ Entry* entry = const_cast<Entry*>(*it);
+
+ if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+
+ ///@todo If the user explicitly clicked on a submenu, display this folder as floating start menu.
+
+ if (entry->_etype == ET_SHELL)
+ new_folders.push_back(entry->create_absolute_pidl());
+ else {
+ TCHAR path[MAX_PATH];
+
+ if (entry->get_path(path))
+ new_folders.push_back(path);
+ }
+
+ if (title.empty())
+ title = entry->_display_name;
+ } else {
+ // The entry is no subdirectory, so there can only be one shell entry.
+ assert(entries.size()==1);
+
+ HWND hparent = GetParent(_hwnd);
+ ShellPath shell_path = entry->create_absolute_pidl();
+
+ // close start menus when launching the selected entry
+ CloseStartMenu(id);
+
+ ///@todo launch in the background; specify correct HWND for error message box titles
+ SHELLEXECUTEINFO shexinfo;
+
+ shexinfo.cbSize = sizeof(SHELLEXECUTEINFO);
+ shexinfo.fMask = SEE_MASK_IDLIST; // SEE_MASK_INVOKEIDLIST is also possible.
+ shexinfo.hwnd = hparent;
+ shexinfo.lpVerb = NULL;
+ shexinfo.lpFile = NULL;
+ shexinfo.lpParameters = NULL;
+ shexinfo.lpDirectory = NULL;
+ shexinfo.nShow = SW_SHOWNORMAL;
+
+ shexinfo.lpIDList = &*shell_path;
+
+ // add PIDL to the recent file list
+ SHAddToRecentDocs(SHARD_PIDL, shexinfo.lpIDList);
+
+ if (!ShellExecuteEx(&shexinfo))
+ display_error(hparent, GetLastError());
+
+ // we may have deleted 'this' - ensure we leave the loop and function
return;
}
}
}
-int StartMenuButton::GetTextWidth(LPCTSTR title, HWND hwnd)
+int GetStartMenuBtnTextWidth(HDC hdc, LPCTSTR title, HWND hwnd)
{
- WindowCanvas canvas(hwnd);
- FontSelection font(canvas, GetStockFont(DEFAULT_GUI_FONT));
-
RECT rect = {0, 0, 0, 0};
- DrawText(canvas, title, -1, &rect, DT_SINGLELINE|DT_NOPREFIX|DT_CALCRECT);
+ DrawText(hdc, title, -1, &rect, DT_SINGLELINE|DT_NOPREFIX|DT_CALCRECT);
return rect.right-rect.left;
}
+#ifdef _LIGHT_STARTMENU
+void DrawStartMenuButton(HDC hdc, const RECT& rect, LPCTSTR title, const SMBtnInfo& btn, bool has_focus, bool pushed)
+#else
+void DrawStartMenuButton(HDC hdc, const RECT& rect, LPCTSTR title, HICON hIcon,
+ bool hasSubmenu, bool enabled, bool has_focus, bool pushed);
+#endif
+{
+ UINT style = DFCS_BUTTONPUSH;
+
+ if (!btn._enabled)
+ style |= DFCS_INACTIVE;
+
+ POINT iconPos = {rect.left+2, (rect.top+rect.bottom-16)/2};
+ RECT textRect = {rect.left+16+4, rect.top+2, rect.right-4, rect.bottom-4};
+
+ if (pushed) {
+ style |= DFCS_PUSHED;
+ ++iconPos.x; ++iconPos.y;
+ ++textRect.left; ++textRect.top;
+ ++textRect.right; ++textRect.bottom;
+ }
+
+ int bk_color_idx = COLOR_BTNFACE;
+ int text_color_idx = COLOR_BTNTEXT;
+
+ if (has_focus) {
+ bk_color_idx = COLOR_HIGHLIGHT;
+ text_color_idx = COLOR_HIGHLIGHTTEXT;
+ }
+
+ COLORREF bk_color = GetSysColor(bk_color_idx);
+ HBRUSH bk_brush = GetSysColorBrush(bk_color_idx);
+
+ if (title)
+ FillRect(hdc, &rect, bk_brush);
+
+ if (btn._icon_id > ICID_NONE)
+ g_Globals._icon_cache.get_icon(btn._icon_id).draw(hdc, iconPos.x, iconPos.y, 16, 16, bk_color, bk_brush);
+
+ // draw submenu arrow at the right
+ if (btn._hasSubmenu) {
+ static SmallIcon arrowIcon(IDI_ARROW);
+ static SmallIcon selArrowIcon(IDI_ARROW_SELECTED);
+
+ DrawIconEx(hdc, rect.right-16, iconPos.y,
+ has_focus? selArrowIcon: arrowIcon,
+ 16, 16, 0, bk_brush, DI_NORMAL);
+ }
+
+ if (title) {
+ BkMode bk_mode(hdc, TRANSPARENT);
+
+ if (!btn._enabled) // dis->itemState & (ODS_DISABLED|ODS_GRAYED)
+ DrawGrayText(hdc, &textRect, title, DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER);
+ else {
+ TextColor lcColor(hdc, GetSysColor(text_color_idx));
+ DrawText(hdc, title, -1, &textRect, DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER);
+ }
+ }
+}
+
+
+#ifdef _LIGHT_STARTMENU
+
+void StartMenu::ResizeToButtons()
+{
+ WindowRect rect(_hwnd);
+
+ WindowCanvas canvas(_hwnd);
+ FontSelection font(canvas, GetStockFont(DEFAULT_GUI_FONT));
+
+ int max_width = STARTMENU_WIDTH_MIN;
+ int height = 0;
+
+ for(SMBtnVector::const_iterator it=_buttons.begin(); it!=_buttons.end(); ++it) {
+ int w = GetStartMenuBtnTextWidth(canvas, it->_title, _hwnd);
+
+ if (w > max_width)
+ max_width = w;
+
+ if (it->_id == -1)
+ height += STARTMENU_SEP_HEIGHT;
+ else
+ height += STARTMENU_LINE_HEIGHT;
+ }
+
+ // calculate new window size
+ int text_width = max_width + 16/*icon*/ + 10/*placeholder*/ + 16/*arrow*/;
+
+ RECT rt_hgt = {rect.left, rect.bottom-_border_top-height, rect.left+_border_left+text_width, rect.bottom};
+ AdjustWindowRectEx(&rt_hgt, GetWindowStyle(_hwnd), FALSE, GetWindowExStyle(_hwnd));
+
+ // ignore movement, only look at the size change
+ rect.right = rect.left + (rt_hgt.right-rt_hgt.left);
+ rect.top = rect.bottom - (rt_hgt.bottom-rt_hgt.top);
+
+ // move down if we are too high
+ if (rect.top < 0) {
+ int dy = -rect.top;
+ rect.top += dy;
+ rect.bottom += dy;
+ }
+
+ // enable scroll mode for long start menus, which span more than the whole screen height
+ int cyscreen = GetSystemMetrics(SM_CYSCREEN);
+ int bottom_max = 0;
+
+ if (rect.bottom > cyscreen) {
+ _arrow_btns = true;
+
+ _invisible_lines = (rect.bottom-cyscreen+(STARTMENU_LINE_HEIGHT-1))/STARTMENU_LINE_HEIGHT + 1;
+ rect.bottom -= _invisible_lines * STARTMENU_LINE_HEIGHT;
+
+ bottom_max = rect.bottom;
+
+ if (_floating_btn)
+ rect.bottom += 6; // lower scroll arrow
+ else {
+ _border_top += 6; // upper scroll arrow
+ rect.bottom += 2*6; // upper+lower scroll arrow
+ }
+ }
+
+ MoveWindow(_hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE);
+
+ if (bottom_max) {
+ POINT pt = {0, bottom_max};
+
+ ScreenToClient(_hwnd, &pt);
+
+ _bottom_max = pt.y;
+ }
+}
+
+#else // _LIGHT_STARTMENU
LRESULT StartMenuButton::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
{
switch(nmsg) {
case WM_MOUSEMOVE:
- // automatically set the focus to startmenu entries when moving the mouse over them
+ // automatically set the focus to startmenu entries when moving the mouse over them
if (GetFocus()!=_hwnd && !(GetWindowStyle(_hwnd)&WS_DISABLED))
SetFocus(_hwnd);
break;
void StartMenuButton::DrawItem(LPDRAWITEMSTRUCT dis)
{
- UINT style = DFCS_BUTTONPUSH;
-
- if (dis->itemState & ODS_DISABLED)
- style |= DFCS_INACTIVE;
-
- POINT iconPos = {dis->rcItem.left+2, (dis->rcItem.top+dis->rcItem.bottom-16)/2};
- RECT textRect = {dis->rcItem.left+16+4, dis->rcItem.top+2, dis->rcItem.right-4, dis->rcItem.bottom-4};
-
- if (dis->itemState & ODS_SELECTED) {
- style |= DFCS_PUSHED;
- ++iconPos.x; ++iconPos.y;
- ++textRect.left; ++textRect.top;
- ++textRect.right; ++textRect.bottom;
- }
-
- int bk_color = COLOR_BTNFACE;
- int text_color = COLOR_BTNTEXT;
-
- if (dis->itemState & ODS_FOCUS) {
- bk_color = COLOR_HIGHLIGHT;
- text_color = COLOR_HIGHLIGHTTEXT;
- }
-
- HBRUSH bk_brush = GetSysColorBrush(bk_color);
-
- FillRect(dis->hDC, &dis->rcItem, bk_brush);
- DrawIconEx(dis->hDC, iconPos.x, iconPos.y, _hIcon, 16, 16, 0, bk_brush, DI_NORMAL);
-
- // draw submenu arrow at the right
- if (_hasSubmenu) {
- static SmallIcon arrowIcon(IDI_ARROW);
- static SmallIcon selArrowIcon(IDI_ARROW_SELECTED);
-
- DrawIconEx(dis->hDC, dis->rcItem.right-16, iconPos.y,
- dis->itemState&ODS_FOCUS?selArrowIcon:arrowIcon, 16, 16, 0, bk_brush, DI_NORMAL);
- }
-
TCHAR title[BUFFER_LEN];
- GetWindowText(_hwnd, title, BUFFER_LEN);
- BkMode bk_mode(dis->hDC, TRANSPARENT);
+ GetWindowText(_hwnd, title, BUFFER_LEN);
- if (dis->itemState & (ODS_DISABLED|ODS_GRAYED))
- DrawGrayText(dis, &textRect, title, DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER);
- else {
- TextColor lcColor(dis->hDC, GetSysColor(text_color));
- DrawText(dis->hDC, title, -1, &textRect, DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER);
- }
+ DrawStartMenuButton(dis->hDC, dis->rcItem, title, _hIcon,
+ _hasSubmenu,
+ !(dis->itemState & ODS_DISABLED),
+ dis->itemState&ODS_FOCUS? true: false,
+ dis->itemState&ODS_SELECTED? true: false);
}
+#endif
+
StartMenuRoot::StartMenuRoot(HWND hwnd)
: super(hwnd)
#endif
try {
// insert directory "All Users\Start Menu"
- ShellDirectory cmn_startmenu(Desktop(), SpecialFolderPath(CSIDL_COMMON_STARTMENU, _hwnd), _hwnd);
+ ShellDirectory cmn_startmenu(GetDesktopFolder(), SpecialFolderPath(CSIDL_COMMON_STARTMENU, _hwnd), _hwnd);
_dirs.push_back(StartMenuDirectory(cmn_startmenu, false)); // don't add subfolders
} catch(COMException&) {
// ignore exception and don't show additional shortcuts
try {
// insert directory "<user name>\Start Menu"
- ShellDirectory usr_startmenu(Desktop(), SpecialFolderPath(CSIDL_STARTMENU, _hwnd), _hwnd);
+
+ ShellDirectory usr_startmenu(GetDesktopFolder(), SpecialFolderPath(CSIDL_STARTMENU, _hwnd), _hwnd);
_dirs.push_back(StartMenuDirectory(usr_startmenu, false)); // don't add subfolders
} catch(COMException&) {
// ignore exception and don't show additional shortcuts
_logo_size.cx = bmp_hdr.bmWidth;
_logo_size.cy = bmp_hdr.bmHeight;
- _border_left = _logo_size.cx;
+ _border_left = _logo_size.cx + 1;
}
-HWND StartMenuRoot::Create(HWND hwndDesktopBar)
+static void CalculateStartPos(HWND hwndOwner, RECT& rect)
+{
+ WindowRect pos(hwndOwner);
+
+ rect.left = pos.left;
+ rect.top = pos.top-STARTMENU_LINE_HEIGHT-4;
+ rect.right = pos.left+STARTMENU_WIDTH_MIN;
+ rect.bottom = pos.top;
+
+#ifndef _LIGHT_STARTMENU
+ rect.top += STARTMENU_LINE_HEIGHT;
+#endif
+
+ AdjustWindowRectEx(&rect, WS_POPUP|WS_THICKFRAME|WS_CLIPCHILDREN|WS_VISIBLE, FALSE, 0);
+}
+
+HWND StartMenuRoot::Create(HWND hwndOwner)
{
- WindowRect pos(hwndDesktopBar);
+ RECT rect;
+
+ CalculateStartPos(hwndOwner, rect);
return Window::Create(WINDOW_CREATOR(StartMenuRoot), 0, GetWndClasss(), TITLE_STARTMENU,
- WS_POPUP|WS_THICKFRAME|WS_CLIPCHILDREN|WS_VISIBLE, pos.left, pos.top-4, STARTMENU_WIDTH_MIN, 4, hwndDesktopBar);
+ WS_POPUP|WS_THICKFRAME|WS_CLIPCHILDREN,
+ rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, hwndOwner);
}
MSG msg;
HWND hwnd = _hwnd;
+#ifdef _LIGHT_STARTMENU
+ _selected_id = -1;
+#endif
+
+#ifdef _LIGHT_STARTMENU
+ // recalculate start menu root position
+ RECT rect;
+
+ CalculateStartPos(GetParent(hwnd), rect);
+
+ SetWindowPos(hwnd, 0, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, 0);
+
+ ResizeToButtons();
+#endif
+
+ // show previously hidden start menu
+ ShowWindow(hwnd, SW_SHOW);
+ SetForegroundWindow(hwnd);
+
while(IsWindow(hwnd)) {
if (!GetMessage(&msg, 0, 0, 0)) {
PostQuitMessage(msg.wParam);
}
if (!menu_wnd) {
- DestroyWindow(_hwnd);
+ CloseStartMenu();
break;
}
}
// insert hard coded start entries
- AddButton(ResString(IDS_PROGRAMS), SmallIcon(IDI_APPS), true, IDC_PROGRAMS);
+ AddButton(ResString(IDS_PROGRAMS), ICID_APPS, true, IDC_PROGRAMS);
- AddButton(ResString(IDS_DOCUMENTS), SmallIcon(IDI_DOCUMENTS), true, IDC_DOCUMENTS);
+ AddButton(ResString(IDS_DOCUMENTS), ICID_DOCUMENTS, true, IDC_DOCUMENTS);
#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
if (!g_Globals._SHRestricted || !SHRestricted(REST_NORECENTDOCSMENU))
#else
if (IS_VALUE_ZERO(hkey, _T("NoRecentDocsMenu")))
#endif
- AddButton(ResString(IDS_RECENT), SmallIcon(IDI_DOCUMENTS), true, IDC_RECENT);
+ AddButton(ResString(IDS_RECENT), ICID_DOCUMENTS, true, IDC_RECENT);
- AddButton(ResString(IDS_FAVORITES), SmallIcon(IDI_FAVORITES), true, IDC_FAVORITES);
+ AddButton(ResString(IDS_FAVORITES), ICID_FAVORITES, true, IDC_FAVORITES);
- AddButton(ResString(IDS_SETTINGS), SmallIcon(IDI_CONFIG), true, IDC_SETTINGS);
+ AddButton(ResString(IDS_SETTINGS), ICID_CONFIG, true, IDC_SETTINGS);
- AddButton(ResString(IDS_BROWSE), SmallIcon(IDI_FOLDER), true, IDC_BROWSE);
+ AddButton(ResString(IDS_BROWSE), ICID_FOLDER, true, IDC_BROWSE);
#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
if (!g_Globals._SHRestricted || !SHRestricted(REST_NOFIND))
#else
if (IS_VALUE_ZERO(hkey, _T("NoFind")))
#endif
- AddButton(ResString(IDS_SEARCH), SmallIcon(IDI_SEARCH), true, IDC_SEARCH);
+ AddButton(ResString(IDS_SEARCH), ICID_SEARCH, true, IDC_SEARCH);
- AddButton(ResString(IDS_START_HELP), SmallIcon(IDI_INFO), false, IDC_START_HELP);
+ AddButton(ResString(IDS_START_HELP), ICID_INFO, false, IDC_START_HELP);
#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
if (!g_Globals._SHRestricted || !SHRestricted(REST_NORUN))
#else
if (IS_VALUE_ZERO(hkey, _T("NoRun")))
#endif
- AddButton(ResString(IDS_LAUNCH), SmallIcon(IDI_ACTION), false, IDC_LAUNCH);
+ AddButton(ResString(IDS_LAUNCH), ICID_ACTION, false, IDC_LAUNCH);
AddSeparator();
#else
if (IS_VALUE_NOT_ZERO(hkeyAdv, _T("StartMenuLogoff")))
#endif
- AddButton(ResString(IDS_LOGOFF), SmallIcon(IDI_LOGOFF), false, IDC_LOGOFF);
+ AddButton(ResString(IDS_LOGOFF), ICID_LOGOFF, false, IDC_LOGOFF);
#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
#else
if (IS_VALUE_ZERO(hkey, _T("NoClose")))
#endif
- AddButton(ResString(IDS_SHUTDOWN), SmallIcon(IDI_LOGOFF), false, IDC_SHUTDOWN);
+ AddButton(ResString(IDS_SHUTDOWN), ICID_LOGOFF, false, IDC_SHUTDOWN);
+
+
+ AddButton(ResString(IDS_TERMINATE), ICID_LOGOFF, false, IDC_TERMINATE);
#ifdef __MINGW32__
RegCloseKey(hkey);
#endif
+
+#ifdef _LIGHT_STARTMENU
+ // set the window size to fit all buttons
+ ResizeToButtons();
+#endif
+
return 0;
}
{
super::AddEntries();
- AddButton(ResString(IDS_EXPLORE), SmallIcon(IDI_EXPLORER), false, IDC_EXPLORE);
+ AddButton(ResString(IDS_EXPLORE), ICID_EXPLORER, false, IDC_EXPLORE);
}
{
switch(nmsg) {
case WM_PAINT: {
- int clr_bits;
- {WindowCanvas dc(_hwnd); clr_bits=GetDeviceCaps(dc, BITSPIXEL);}
- bool logo256 = clr_bits<=8;
-
PaintCanvas canvas(_hwnd);
+ Paint(canvas);
+ break;}
+
+ default:
+ return super::WndProc(nmsg, wparam, lparam);
+ }
+
+ return 0;
+}
- MemCanvas mem_dc;
- ResBitmap bmp(logo256? IDB_LOGOV256: IDB_LOGOV);
- BitmapSelection sel(mem_dc, bmp);
+void StartMenuRoot::Paint(PaintCanvas& canvas)
+{
+ int clr_bits;
+ {WindowCanvas dc(_hwnd); clr_bits=GetDeviceCaps(dc, BITSPIXEL);}
- ClientRect clnt(_hwnd);
- int h = min(_logo_size.cy, clnt.bottom);
+ MemCanvas mem_dc;
+ ResBitmap bmp(clr_bits<=8? clr_bits<=4? IDB_LOGOV16: IDB_LOGOV256: IDB_LOGOV);
+ BitmapSelection sel(mem_dc, bmp);
- RECT rect = {0, 0, _logo_size.cx-1, clnt.bottom-h};
- HBRUSH hbr = CreateSolidBrush(logo256? RGB(166,202,240): RGB(255,255,255)); // same color as the background color in the logo bitmap
- FillRect(canvas, &rect, hbr);
- DeleteObject(hbr);
- //PatBlt(canvas, _logo_size.cx-1, 0, 1, clnt.bottom-h, WHITENESS);
- PatBlt(canvas, _logo_size.cx-1, 0, 1, clnt.bottom-h, WHITENESS);
+ ClientRect clnt(_hwnd);
+ int h = min(_logo_size.cy, clnt.bottom);
- BitBlt(canvas, 0, clnt.bottom-h, _logo_size.cx, h, mem_dc, 0, 0, SRCCOPY);
+ RECT rect = {0, 0, _logo_size.cx, clnt.bottom-h};
+ HBRUSH hbr = CreateSolidBrush(GetPixel(mem_dc, 0, 0));
+ FillRect(canvas, &rect, hbr);
+ DeleteObject(hbr);
- if (!logo256) {
- rect.left = rect.right++;
- rect.bottom = clnt.bottom;
- HBRUSH hbr_border = GetStockBrush(GRAY_BRUSH); //CreateSolidBrush(RGB(71,88,85));
- FillRect(canvas, &rect, hbr_border);
- //DeleteObject(hbr_border);
- }
- break;}
+ PatBlt(canvas, _logo_size.cx, 0, 1, clnt.bottom, WHITENESS);
+
+ BitBlt(canvas, 0, clnt.bottom-h, _logo_size.cx, h, mem_dc, 0, 0, SRCCOPY);
+
+ super::Paint(canvas);
+}
+
+
+void StartMenuRoot::CloseStartMenu(int id)
+{
+ if (_submenu)
+ CloseSubmenus();
+
+ ShowWindow(_hwnd, SW_HIDE);
+}
+
+void StartMenuRoot::ProcessKey(int vk)
+{
+ switch(vk) {
+ case VK_LEFT:
+ if (_submenu)
+ CloseOtherSubmenus();
+ // don't close start menu root
+ break;
default:
- return super::WndProc(nmsg, wparam, lparam);
+ super::ProcessKey(vk);
}
-
- return 0;
}
-int StartMenuRoot::Command(int id, int code)
+int StartMenuHandler::Command(int id, int code)
{
switch(id) {
+
+ // start menu root
+
case IDC_PROGRAMS:
CreateSubmenu(id, CSIDL_COMMON_PROGRAMS, CSIDL_PROGRAMS, ResString(IDS_PROGRAMS));
break;
case IDC_EXPLORE:
CloseStartMenu(id);
- explorer_show_frame(_hwnd, SW_SHOWNORMAL);
+ explorer_show_frame(SW_SHOWNORMAL);
break;
- case IDC_LAUNCH: {
- HWND hwndDesktopBar = GetWindow(_hwnd, GW_OWNER);
+ case IDC_LAUNCH:
CloseStartMenu(id);
- ShowLaunchDialog(hwndDesktopBar);
- break;}
+ ShowLaunchDialog(g_Globals._hwndDesktopBar);
+ break;
case IDC_DOCUMENTS:
CreateSubmenu(id, CSIDL_PERSONAL, ResString(IDS_DOCUMENTS));
break;
case IDC_FAVORITES:
- CreateSubmenu(id, CSIDL_FAVORITES, ResString(IDS_FAVORITES));
+#ifndef _SHELL32_FAVORITES
+ CreateSubmenu(id, ResString(IDS_FAVORITES), STARTMENU_CREATOR(FavoritesMenu), &static_cast<BookmarkList&>(g_Globals._favorites));
+#else
+ CreateSubmenu(id, CSIDL_COMMON_FAVORITES, CSIDL_FAVORITES, ResString(IDS_FAVORITES));
+#endif
break;
case IDC_BROWSE:
CreateSubmenu(id, ResString(IDS_SEARCH), STARTMENU_CREATOR(SearchMenu));
break;
+ case IDC_START_HELP:
+ CloseStartMenu(id);
+ MessageBox(g_Globals._hwndDesktopBar, TEXT("Help not yet implemented"), ResString(IDS_TITLE), MB_OK);
+ break;
+
case IDC_LOGOFF:
- /* The shell32 Dialog prompts about some system setting change. This is not what we want to display here.
- HWND hwndDesktopBar = GetWindow(_hwnd, GW_OWNER);
CloseStartMenu(id);
- ShowRestartDialog(hwndDesktopBar, EWX_LOGOFF);*/
+ ShowLogoffDialog(g_Globals._hwndDesktopBar);
+ break;
+
+ case IDC_TERMINATE:
DestroyWindow(GetParent(_hwnd));
break;
- case IDC_SHUTDOWN: {
- HWND hwndDesktopBar = GetWindow(_hwnd, GW_OWNER);
+ case IDC_SHUTDOWN:
+ CloseStartMenu(id);
+ ShowExitWindowsDialog(g_Globals._hwndDesktopBar);
+ break;
+
+
+ // settings menu
+
+ case ID_DESKTOPBAR_SETTINGS:
+ CloseStartMenu(id);
+ ExplorerPropertySheet(g_Globals._hwndDesktopBar);
+ break;
+
+ case IDC_CONTROL_PANEL: {
+ CloseStartMenu(id);
+#ifndef ROSSHELL
+#ifndef _NO_MDI
+ XMLPos explorer_options = g_Globals.get_cfg("general/explorer");
+ bool mdi = XMLBool(explorer_options, "mdi", true);
+
+ if (mdi)
+ MDIMainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}"), 0);
+ else
+#endif
+ SDIMainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}"), 0);
+#else
+ launch_file(_hwnd, SHELLPATH_CONTROL_PANEL);
+#endif
+ break;}
+
+ case IDC_SETTINGS_MENU:
+ CreateSubmenu(id, CSIDL_CONTROLS, ResString(IDS_SETTINGS_MENU));
+ break;
+
+ case IDC_PRINTERS: {
CloseStartMenu(id);
- ShowExitWindowsDialog(hwndDesktopBar);
+
+#ifndef ROSSHELL
+#ifdef _ROS_ // to be removed when printer folder will be implemented
+ MessageBox(0, TEXT("printer folder not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
+#else
+#ifndef _NO_MDI
+ XMLPos explorer_options = g_Globals.get_cfg("general/explorer");
+ bool mdi = XMLBool(explorer_options, "mdi", true);
+
+ if (mdi)
+ MDIMainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}"), 0);
+ else
+#endif
+ SDIMainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}"), 0);
+#endif
+#else
+ launch_file(_hwnd, SHELLPATH_PRINTERS);
+#endif
break;}
+ case IDC_PRINTERS_MENU:
+ CreateSubmenu(id, CSIDL_PRINTERS, CSIDL_PRINTHOOD, ResString(IDS_PRINTERS));
+/* StartMenuFolders new_folders;
+
+ try {
+ new_folders.push_back(ShellPath(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}")));
+ } catch(COMException&) {
+ }
+
+ CreateSubmenu(id, new_folders, ResString(IDS_PRINTERS));*/
+ break;
+
+ case IDC_ADMIN:
+#ifndef ROSSHELL
+ CreateSubmenu(id, CSIDL_COMMON_ADMINTOOLS, CSIDL_ADMINTOOLS, ResString(IDS_ADMIN));
+ //CloseStartMenu(id);
+ //MainFrame::Create(SpecialFolderPath(CSIDL_COMMON_ADMINTOOLS, _hwnd), OWM_PIDL);
+#else
+ launch_file(_hwnd, SpecialFolderFSPath(CSIDL_COMMON_ADMINTOOLS, _hwnd));
+#endif
+ break;
+
+ case IDC_CONNECTIONS:
+#ifndef ROSSHELL
+#ifdef _ROS_ // to be removed when RAS will be implemented
+ MessageBox(0, TEXT("RAS folder not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
+#else
+ CreateSubmenu(id, CSIDL_CONNECTIONS, ResString(IDS_CONNECTIONS));
+ //CloseStartMenu(id);
+ //MainFrame::Create(SpecialFolderPath(CSIDL_CONNECTIONS, _hwnd), OWM_PIDL);
+#endif
+#else
+ launch_file(_hwnd, SHELLPATH_NET_CONNECTIONS);
+#endif
+ break;
+
+
+ // browse menu
+
+ case IDC_NETWORK:
+#ifdef _ROS_ // to be removed when network will be implemented
+ MessageBox(0, TEXT("network not yet implemented"), ResString(IDS_TITLE), MB_OK);
+#else
+ CreateSubmenu(id, CSIDL_NETWORK, ResString(IDS_NETWORK));
+#endif
+ break;
+
+ case IDC_DRIVES:
+ ///@todo exclude removable drives
+ CreateSubmenu(id, CSIDL_DRIVES, ResString(IDS_DRIVES));
+ break;
+
+
+ // search menu
+
+ case IDC_SEARCH_PROGRAM:
+ CloseStartMenu(id);
+ Dialog::DoModal(IDD_SEARCH_PROGRAM, WINDOW_CREATOR(FindProgramDlg));
+ break;
+
+ case IDC_SEARCH_FILES:
+ CloseStartMenu(id);
+ ShowSearchDialog();
+ break;
+
+ case IDC_SEARCH_COMPUTER:
+ CloseStartMenu(id);
+ ShowSearchComputer();
+ break;
+
+
default:
return super::Command(id, code);
}
}
-void StartMenuRoot::ShowLaunchDialog(HWND hwndDesktopBar)
+void StartMenuHandler::ShowSearchDialog()
+{
+ static DynamicFct<SHFINDFILES> SHFindFiles(TEXT("SHELL32"), 90);
+
+ if (SHFindFiles)
+ (*SHFindFiles)(NULL, NULL);
+ else
+ MessageBox(0, TEXT("SHFindFiles() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
+}
+
+void StartMenuHandler::ShowSearchComputer()
+{
+ static DynamicFct<SHFINDCOMPUTER> SHFindComputer(TEXT("SHELL32"), 91);
+
+ if (SHFindComputer)
+ (*SHFindComputer)(NULL, NULL);
+ else
+ MessageBox(0, TEXT("SHFindComputer() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
+}
+
+void StartMenuHandler::ShowLaunchDialog(HWND hwndOwner)
{
///@todo All text phrases should be put into the resources.
- static LPCSTR szTitle = "Create New Task";
- static LPCSTR szText = "Type the name of a program, folder, document, or Internet resource, and Task Manager will open it for you.";
+ static LPCSTR szTitle = "Run";
+ static LPCSTR szText = "Type the name of a program, folder, document, or Internet resource, and Explorer will open it for you.";
static DynamicFct<RUNFILEDLG> RunFileDlg(TEXT("SHELL32"), 61);
// Show "Run..." dialog
if (RunFileDlg) {
-#define W_VER_NT 0
+#ifndef _ROS_ /* FIXME: our shell32 always expects Ansi strings */
if ((HIWORD(GetVersion())>>14) == W_VER_NT) {
WCHAR wTitle[40], wText[256];
MultiByteToWideChar(CP_ACP, 0, szTitle, -1, wTitle, 40);
MultiByteToWideChar(CP_ACP, 0, szText, -1, wText, 256);
- (*RunFileDlg)(hwndDesktopBar, 0, NULL, (LPCSTR)wTitle, (LPCSTR)wText, RFF_CALCDIRECTORY);
+ (*RunFileDlg)(hwndOwner, 0, NULL, (LPCSTR)wTitle, (LPCSTR)wText, RFF_CALCDIRECTORY);
}
else
- (*RunFileDlg)(hwndDesktopBar, 0, NULL, szTitle, szText, RFF_CALCDIRECTORY);
+#endif
+ (*RunFileDlg)(hwndOwner, 0, NULL, szTitle, szText, RFF_CALCDIRECTORY);
}
}
-void StartMenuRoot::ShowExitWindowsDialog(HWND hwndOwner)
+void StartMenuHandler::ShowLogoffDialog(HWND hwndOwner)
{
- static DynamicFct<EXITWINDOWSDLG> ExitWindowsDlg(TEXT("SHELL32"), 60);
-
- if (ExitWindowsDlg)
- (*ExitWindowsDlg)(hwndOwner);
+ static DynamicFct<LOGOFFWINDOWSDIALOG> LogoffWindowsDialog(TEXT("SHELL32"), 54);
+// static DynamicFct<RESTARTWINDOWSDLG> RestartDialog(TEXT("SHELL32"), 59);
+
+ if (LogoffWindowsDialog)
+ (*LogoffWindowsDialog)(0);
+/* The RestartDialog function prompts about some system setting change. This is not what we want to display here.
+ else if (RestartDialog)
+ return (*RestartDialog)(hwndOwner, (LPWSTR)L"You selected <Log Off>.\n\n", EWX_LOGOFF) == 1; ///@todo ANSI string conversion if needed
+*/
+ else
+ MessageBox(hwndOwner, TEXT("LogoffWindowsDialog() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
}
-void StartMenuRoot::ShowRestartDialog(HWND hwndOwner, UINT flags)
+void ShowExitWindowsDialog(HWND hwndOwner)
{
- static DynamicFct<RESTARTWINDOWSDLG> RestartDlg(TEXT("SHELL32"), 59);
+ static DynamicFct<EXITWINDOWSDLG> ExitWindowsDialog(TEXT("SHELL32"), 60);
- if (RestartDlg)
- (*RestartDlg)(hwndOwner, (LPWSTR)L"You selected <Log Off>.\n\n", flags); ///@todo ANSI string conversion if needed
+ if (ExitWindowsDialog)
+ (*ExitWindowsDialog)(hwndOwner);
+ else
+ MessageBox(hwndOwner, TEXT("ExitWindowsDialog() not yet implemented in SHELL32"), ResString(IDS_TITLE), MB_OK);
}
{
super::AddEntries();
-#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
- if (!g_Globals._SHRestricted || !SHRestricted(REST_NOCONTROLPANEL))
+#ifdef _ROS_ // to be removed when printer/network will be implemented
+ AddButton(ResString(IDS_PRINTERS), ICID_PRINTER, false, IDC_PRINTERS_MENU);
+ AddButton(ResString(IDS_CONNECTIONS), ICID_NETWORK, false, IDC_CONNECTIONS);
+#else
+ AddButton(ResString(IDS_PRINTERS), ICID_PRINTER, true, IDC_PRINTERS_MENU);
+ AddButton(ResString(IDS_CONNECTIONS), ICID_NETWORK, true, IDC_CONNECTIONS);
#endif
- AddButton(ResString(IDS_CONTROL_PANEL), SmallIcon(IDI_CONFIG), false, IDC_CONTROL_PANEL);
-
- AddButton(ResString(IDS_PRINTERS), SmallIcon(IDI_PRINTER), true, IDC_PRINTERS);
- AddButton(ResString(IDS_CONNECTIONS), SmallIcon(IDI_NETWORK), true, IDC_CONNECTIONS);
- AddButton(ResString(IDS_ADMIN), SmallIcon(IDI_CONFIG), true, IDC_ADMIN);
+ AddButton(ResString(IDS_ADMIN), ICID_CONFIG, true, IDC_ADMIN);
#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
if (!g_Globals._SHRestricted || !SHRestricted(REST_NOCONTROLPANEL))
#endif
- AddButton(ResString(IDS_SETTINGS_MENU), SmallIcon(IDI_CONFIG), true, IDC_SETTINGS_MENU);
-}
-
-int SettingsMenu::Command(int id, int code)
-{
- switch(id) {
- case IDC_SETTINGS_MENU:
- CreateSubmenu(id, CSIDL_CONTROLS, ResString(IDS_SETTINGS_MENU));
- break;
-
- case IDC_PRINTERS:
- CreateSubmenu(id, CSIDL_PRINTERS, CSIDL_PRINTHOOD, ResString(IDS_PRINTERS));
- break;
-
- case IDC_CONTROL_PANEL:
- CloseStartMenu(id);
- MainFrame::Create(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}"), FALSE);
- break;
+ AddButton(ResString(IDS_SETTINGS_MENU), ICID_CONFIG, true, IDC_SETTINGS_MENU);
- case IDC_ADMIN:
- CreateSubmenu(id, CSIDL_COMMON_ADMINTOOLS, CSIDL_ADMINTOOLS, ResString(IDS_ADMIN));
- break;
-
- case IDC_CONNECTIONS:
- CreateSubmenu(id, CSIDL_CONNECTIONS, ResString(IDS_CONNECTIONS));
- break;
+ AddButton(ResString(IDS_DESKTOPBAR_SETTINGS), ICID_CONFIG, false, ID_DESKTOPBAR_SETTINGS);
- default:
- return super::Command(id, code);
- }
+ AddButton(ResString(IDS_PRINTERS), ICID_PRINTER, false, IDC_PRINTERS);
- return 0;
+#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
+ if (!g_Globals._SHRestricted || !SHRestricted(REST_NOCONTROLPANEL))
+#endif
+ AddButton(ResString(IDS_CONTROL_PANEL), ICID_CONFIG, false, IDC_CONTROL_PANEL);
}
-
void BrowseMenu::AddEntries()
{
super::AddEntries();
#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
if (!g_Globals._SHRestricted || !SHRestricted(REST_NONETHOOD)) // or REST_NOENTIRENETWORK ?
#endif
- AddButton(ResString(IDS_NETWORK), SmallIcon(IDI_NETWORK), true, IDC_NETWORK);
+#ifdef _ROS_ // to be removed when printer/network will be implemented
+ AddButton(ResString(IDS_NETWORK), ICID_NETWORK, false, IDC_NETWORK);
+#else
+ AddButton(ResString(IDS_NETWORK), ICID_NETWORK, true, IDC_NETWORK);
+#endif
- AddButton(ResString(IDS_DRIVES), SmallIcon(IDI_FOLDER), true, IDC_DRIVES);
+ AddButton(ResString(IDS_DRIVES), ICID_FOLDER, true, IDC_DRIVES);
}
-int BrowseMenu::Command(int id, int code)
+void SearchMenu::AddEntries()
{
- switch(id) {
- case IDC_NETWORK:
- CreateSubmenu(id, CSIDL_NETWORK, ResString(IDS_NETWORK));
- break;
+ super::AddEntries();
- case IDC_DRIVES:
- ///@todo exclude removeable drives
- CreateSubmenu(id, CSIDL_DRIVES, ResString(IDS_DRIVES));
- break;
+ AddButton(ResString(IDS_SEARCH_FILES), ICID_SEARCH_DOC, false, IDC_SEARCH_FILES);
- default:
- return super::Command(id, code);
- }
+#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
+ if (!g_Globals._SHRestricted || !SHRestricted(REST_HASFINDCOMPUTERS))
+#endif
+ AddButton(ResString(IDS_SEARCH_COMPUTER),ICID_COMPUTER, false, IDC_SEARCH_COMPUTER);
- return 0;
+ AddButton(ResString(IDS_SEARCH_PRG), ICID_APPS, false, IDC_SEARCH_PROGRAM);
}
-void SearchMenu::AddEntries()
+void RecentStartMenu::AddEntries()
{
- super::AddEntries();
-
- AddButton(ResString(IDS_SEARCH_PRG), SmallIcon(IDI_APPS), false, IDC_SEARCH_PROGRAM);
+ for(StartMenuShellDirs::iterator it=_dirs.begin(); it!=_dirs.end(); ++it) {
+ StartMenuDirectory& smd = *it;
+ ShellDirectory& dir = smd._dir;
- AddButton(ResString(IDS_SEARCH_FILES), SmallIcon(IDI_SEARCH_DOC), false, IDC_SEARCH_FILES);
+ if (!dir._scanned) {
+ WaitCursor wait;
-#ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
- if (!g_Globals._SHRestricted || !SHRestricted(REST_HASFINDCOMPUTERS))
+#ifdef _LAZY_ICONEXTRACT
+ dir.smart_scan(SORT_NAME, SCAN_FILESYSTEM);
+#else
+ dir.smart_scan(SORT_NAME, SCAN_EXTRACT_ICONS|SCAN_FILESYSTEM);
#endif
- AddButton(ResString(IDS_SEARCH_COMPUTER), SmallIcon(IDI_COMPUTER), false, IDC_SEARCH_COMPUTER);
+ }
+
+ dir.sort_directory(SORT_DATE);
+ AddShellEntries(dir, RECENT_DOCS_COUNT, smd._subfolders);
+ }
}
-int SearchMenu::Command(int id, int code)
+
+#ifndef _SHELL32_FAVORITES
+
+void FavoritesMenu::AddEntries()
{
- switch(id) {
- case IDC_SEARCH_PROGRAM:
- CloseStartMenu(id);
- Dialog::DoModal(IDD_SEARCH_PROGRAM, WINDOW_CREATOR(FindProgramDlg));
- break;
+ super::AddEntries();
- case IDC_SEARCH_FILES:
- CloseStartMenu(id);
- ShowSearchDialog();
- break;
+ for(BookmarkList::iterator it=_bookmarks.begin(); it!=_bookmarks.end(); ++it) {
+ BookmarkNode& node = *it;
- case IDC_SEARCH_COMPUTER:
- CloseStartMenu(id);
- ShowSearchComputer();
- break;
+ int id = ++_next_id;
- default:
- return super::Command(id, code);
- }
+ _entries[id] = node;
- return 0;
-}
+ if (node._type == BookmarkNode::BMNT_FOLDER) {
+ BookmarkFolder& folder = *node._pfolder;
-void SearchMenu::ShowSearchDialog()
-{
- static DynamicFct<SHFINDFILES> SHFindFiles(TEXT("SHELL32"), 90);
+ AddButton(folder._name, ICID_FOLDER, true, id);
+ } else if (node._type == BookmarkNode::BMNT_BOOKMARK) {
+ Bookmark& bookmark = *node._pbookmark;
- if (SHFindFiles)
- (*SHFindFiles)(NULL, NULL);
+ ICON_ID icon = ICID_NONE;
+
+ if (!bookmark._icon_path.empty())
+ icon = g_Globals._icon_cache.extract(bookmark._icon_path, bookmark._icon_idx);
+
+ AddButton(bookmark._name, icon!=ICID_NONE?icon:ICID_BOOKMARK, false, id);
+ }
+ }
}
-void SearchMenu::ShowSearchComputer()
+int FavoritesMenu::Command(int id, int code)
{
- static DynamicFct<SHFINDCOMPUTER> SHFindComputer(TEXT("SHELL32"), 91);
+ BookmarkMap::iterator found = _entries.find(id);
- if (SHFindComputer)
- (*SHFindComputer)(NULL, NULL);
-}
+ if (found != _entries.end()) {
+ BookmarkNode& node = found->second;
+ if (node._type == BookmarkNode::BMNT_FOLDER) {
+ BookmarkFolder& folder = *node._pfolder;
-RecentStartMenu::RecentStartMenu(HWND hwnd, const StartMenuCreateInfo& create_info)
- : super(hwnd, create_info)
-{
-}
+ if (CloseOtherSubmenus(id))
+ CreateSubmenu(id, folder._name, STARTMENU_CREATOR(FavoritesMenu), &static_cast<BookmarkList&>(folder._bookmarks));
+ } else if (node._type == BookmarkNode::BMNT_BOOKMARK) {
+ Bookmark& bookmark = *node._pbookmark;
-void RecentStartMenu::AddEntries()
-{
- for(StartMenuShellDirs::iterator it=_dirs.begin(); it!=_dirs.end(); ++it) {
- StartMenuDirectory& smd = *it;
- ShellDirectory& dir = smd._dir;
+ String url = bookmark._url;
+ HWND hparent = GetParent(_hwnd);
- if (!dir._scanned) {
- WaitCursor wait;
+ CloseStartMenu(id);
- dir.smart_scan();
+ launch_file(hparent, url, SW_SHOWNORMAL);
}
- dir.sort_directory(SORT_DATE);
- AddShellEntries(dir, 16, smd._subfolders); ///@todo read max. count of entries from registry
+ return 0;
}
+
+ return super::Command(id, code);
}
+
+#endif