_last_pos = WindowRect(hwnd).pos();
#ifdef _LIGHT_STARTMENU
_selected_id = -1;
+ _last_mouse_pos = 0;
#endif
}
_last_pos = WindowRect(hwnd).pos();
#ifdef _LIGHT_STARTMENU
_selected_id = -1;
+ _last_mouse_pos = 0;
#endif
}
#ifdef _LIGHT_STARTMENU
case WM_MOUSEMOVE: {
// automatically set the focus to startmenu entries when moving the mouse over them
- int new_id = ButtonHitTest(Point(lparam));
+ if (lparam != _last_mouse_pos) { // don't process WM_MOUSEMOVE when opening submenus using keyboard navigation
+ int new_id = ButtonHitTest(Point(lparam));
- if (new_id != _selected_id)
- SelectButton(new_id);
+ if (new_id != _selected_id)
+ SelectButton(new_id);
+
+ _last_mouse_pos = lparam;
+ }
break;}
case WM_KEYDOWN:
- if (wparam==VK_RETURN && _selected_id)
- Command(_selected_id, BN_CLICKED);
+ ProcessKey(wparam);
break;
#else
case PM_STARTENTRY_FOCUSED: { ///@todo use TrackMouseEvent() and WM_MOUSEHOVER to wait a bit before opening submenus
Command(GetDlgCtrlID(hctrl), BN_CLICKED);
} else {
// close any open submenu
- CloseOtherSubmenus(0);
+ CloseOtherSubmenus();
}
break;}
#endif
_submenu = 0;
break;
+ case PM_SELECT_ENTRY:
+ SelectButtonIndex(0, wparam?true:false);
+ break;
+
default: def:
return super::WndProc(nmsg, wparam, lparam);
}
return NULL;
}
-void StartMenu::SelectButton(int id)
+bool StartMenu::SelectButton(int id, bool open_sub)
{
+ if (id == -1)
+ return false;
+
InvalidateSelection();
const SMBtnInfo* btn = GetButtonInfo(id);
// 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);
+ if (open_sub)
+ OpenSubmenu();
} else
- CloseOtherSubmenus(0); // close any open submenu
- } else
+ CloseOtherSubmenus(); // close any open submenu
+
+ return true;
+ } else {
_selected_id = -1;
+ return false;
+ }
+}
+
+bool StartMenu::OpenSubmenu(bool select_first)
+{
+ if (_selected_id == -1)
+ return false;
+
+ InvalidateSelection();
+
+ const SMBtnInfo* btn = GetButtonInfo(_selected_id);
+
+ // 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);
+
+ if (select_first && _submenu)
+ SendMessage(_submenu, PM_SELECT_ENTRY, (WPARAM)false, 0);
+
+ return true;
+ } else
+ return false;
+}
+
+
+int StartMenu::GetSelectionIndex()
+{
+ if (_selected_id == -1)
+ return -1;
+
+ for(int i=0; i<(int)_buttons.size(); ++i)
+ if (_buttons[i]._id == _selected_id)
+ return i;
+
+ 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;
+}
+
+void StartMenu::ProcessKey(int vk)
+{
+ switch(vk) {
+ case VK_RETURN:
+ if (_selected_id)
+ Command(_selected_id, BN_CLICKED);
+ break;
+
+ case VK_UP:
+ Navigate(-1);
+ break;
+
+ case VK_DOWN:
+ Navigate(+1);
+ break;
+
+ case VK_LEFT:
+ if (_submenu)
+ CloseOtherSubmenus();
+ else
+ DestroyWindow(_hwnd);
+ break;
+
+ case VK_RIGHT:
+ OpenSubmenu(true);
+ break;
+ }
+}
+
+bool StartMenu::Navigate(int step)
+{
+ int idx = GetSelectionIndex();
+
+ if (idx == -1)
+ if (step > 0)
+ idx = 0 - step;
+ else
+ idx = _buttons.size() - step;
+
+ for(;;) {
+ idx += step;
+
+ if (idx<0 || idx>(int)_buttons.size())
+ break;
+
+ if (SelectButtonIndex(idx, false))
+ return true;
+ }
+
+ return false;
}
#endif
if (entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- ///@todo If the user explicitely clicked on a submenu, display this folder as floating start menu.
+ ///@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());
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:
+ super::ProcessKey(vk);
+ }
+}
+
int StartMenuHandler::Command(int id, int code)
{
#endif
#define PM_UPDATE_ICONS (WM_APP+0x15)
+#define PM_SELECT_ENTRY (WM_APP+0x16)
/// StartMenuDirectory is used to store the base directory of start menus.
#ifdef _LIGHT_STARTMENU
SMBtnVector _buttons;
int _selected_id;
+ LPARAM _last_mouse_pos;
void ResizeToButtons();
int ButtonHitTest(POINT pt);
void InvalidateSelection();
const SMBtnInfo* GetButtonInfo(int id) const;
- void SelectButton(int id);
+ bool SelectButton(int id, bool open_sub=true);
+ bool SelectButtonIndex(int idx, bool open_sub=true);
+ int GetSelectionIndex();
+ virtual void ProcessKey(int vk);
+ bool Navigate(int step);
+ bool OpenSubmenu(bool select_first=false);
#endif
// member functions
void AddButton(LPCTSTR title, ICON_ID icon_id=ICID_NONE, bool hasSubmenu=false, int id=-1, bool enabled=true);
void AddSeparator();
- bool CloseSubmenus() {return CloseOtherSubmenus(0);}
- bool CloseOtherSubmenus(int id);
+ bool CloseSubmenus() {return CloseOtherSubmenus();}
+ bool CloseOtherSubmenus(int id=0);
void CreateSubmenu(int id, LPCTSTR title, CREATORFUNC creator=s_def_creator);
void CreateSubmenu(int id, int folder, LPCTSTR title, CREATORFUNC creator=s_def_creator);
void CreateSubmenu(int id, int folder1, int folder2, LPCTSTR title, CREATORFUNC creator=s_def_creator);
void AddEntries();
void Paint(PaintCanvas& canvas);
void CloseStartMenu(int id=0);
+ virtual void ProcessKey(int vk);
};