/* If the selected entry is a submenu, show that menu */ static WMenu *show_selected_submenu(WMenu *menu) { WMenuEnt *entry; if(menu->selected<0 || MENU_SUBMENU(menu)!=NULL) return MENU_SUBMENU(menu); entry=&(menu->data->entries[menu->selected]); if(!(entry->flags&WMENUENT_SUBMENU)) return NULL; return do_show_selected_submenu(menu, entry); }
/* Select given entry */ static void menu_set_selected(WMenu *menu, int selected) { WMenuEnt *entry; if(menu->data->nentries<=selected) selected=NO_ENTRY; if(MENU_SUBMENU(menu)!=NULL) do_destroy_menu_tree(MENU_SUBMENU(menu), FALSE, FALSE); if(menu->selected==selected) return; erase_menu_selection(menu); menu->selected=selected; draw_menu_selection(menu); return; }
/* Execute selected entry; either show submenu or * call given function. */ static bool menu_execute_selected(WMenu *menu) { WMenuEnt *entry; WMenuData *data; WThing *context; if(menu->selected<0) return TRUE; /* Submenu already visible? -> return */ if(MENU_SUBMENU(menu)!=NULL) return TRUE; data=menu->data; context=menu->context; entry=&(data->entries[menu->selected]); if(entry->flags&WMENUENT_SUBMENU){ do_show_selected_submenu(menu, entry); return TRUE; } data->nref++; if(menu->flags&WMENU_KEEP){ menu_set_selected(menu, NO_ENTRY); }else{ finish_menu(menu, FALSE); } finish_contextual_menus(); if(data->exec_func!=NULL) data->exec_func(entry, context); if(--data->nref==0 && data->deinit_func!=NULL) data->deinit_func(data); return FALSE; }
bool menu_select_at(WMenu *menu, int rx, int ry) { int x, y; int entry; x=rx-menu->x; y=ry-menu->y; entry=entry_at(menu, x, y); if(entry==NO_ENTRY){ if(MENU_SUBMENU(menu)==NULL) menu_set_selected(menu, NO_ENTRY); return FALSE; } if(entry!=menu->selected){ menu_set_selected(menu, entry); show_selected_submenu(menu); } return TRUE; }
/* ** Opens the context menu in given coordinates. */ void ContextMenu::ShowMenu(POINT pos, Skin* skin) { static const MenuTemplate s_Menu[] = { MENU_ITEM(IDM_MANAGE, ID_STR_MANAGE), MENU_ITEM(IDM_ABOUT, ID_STR_ABOUT), MENU_ITEM(IDM_SHOW_HELP, ID_STR_HELP), MENU_SEPARATOR(), MENU_SUBMENU(ID_STR_SKINS, MENU_ITEM(IDM_OPENSKINSFOLDER, ID_STR_OPENFOLDER), MENU_ITEM(IDM_DISABLEDRAG, ID_STR_DISABLEDRAGGING), MENU_SEPARATOR(), MENU_ITEM_GRAYED(0, ID_STR_NOSKINS)), MENU_SUBMENU(ID_STR_FAVORITES, MENU_ITEM_GRAYED(0, ID_STR_NOFAVORITES)), MENU_SUBMENU(ID_STR_THEMES, MENU_ITEM_GRAYED(0, ID_STR_NOTHEMES)), MENU_SEPARATOR(), MENU_ITEM(IDM_EDITCONFIG, ID_STR_EDITSETTINGS), MENU_ITEM(IDM_REFRESH, ID_STR_REFRESHALL), MENU_SEPARATOR(), MENU_SUBMENU(ID_STR_LOGGING, MENU_ITEM(IDM_SHOWLOGFILE, ID_STR_SHOWLOGFILE), MENU_SEPARATOR(), MENU_ITEM(IDM_STARTLOG, ID_STR_STARTLOGGING), MENU_ITEM(IDM_STOPLOG, ID_STR_STOPLOGGING), MENU_SEPARATOR(), MENU_ITEM(IDM_DELETELOGFILE, ID_STR_DELETELOGFILE), MENU_ITEM(IDM_DEBUGLOG, ID_STR_DEBUGMODE)), MENU_SEPARATOR(), MENU_ITEM(IDM_QUIT, ID_STR_EXIT) }; if (m_MenuActive || (skin && skin->IsClosing())) return; // Show context menu, if no actions were executed HMENU menu = MenuTemplate::CreateMenu(s_Menu, _countof(s_Menu), GetString); if (!menu) return; m_MenuActive = true; Rainmeter& rainmeter = GetRainmeter(); SetMenuDefaultItem(menu, IDM_MANAGE, MF_BYCOMMAND); if (_waccess(GetLogger().GetLogFilePath().c_str(), 0) == -1) { EnableMenuItem(menu, IDM_SHOWLOGFILE, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(menu, IDM_DELETELOGFILE, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(menu, IDM_STOPLOG, MF_BYCOMMAND | MF_GRAYED); } else { EnableMenuItem( menu, (GetLogger().IsLogToFile()) ? IDM_STARTLOG : IDM_STOPLOG, MF_BYCOMMAND | MF_GRAYED); } if (rainmeter.m_Debug) { CheckMenuItem(menu, IDM_DEBUGLOG, MF_BYCOMMAND | MF_CHECKED); } HMENU allSkinsMenu = GetSubMenu(menu, 4); if (allSkinsMenu) { if (!rainmeter.m_SkinRegistry.IsEmpty()) { // "Open folder" = 0, "Disable dragging" = 1, separator = 2 DeleteMenu(allSkinsMenu, 3, MF_BYPOSITION); // "No skins available" menuitem CreateAllSkinsMenu(allSkinsMenu); } if (rainmeter.m_DisableDragging) { CheckMenuItem(allSkinsMenu, IDM_DISABLEDRAG, MF_BYCOMMAND | MF_CHECKED); } } HMENU favoritesMenu = GetSubMenu(menu, 5); if (favoritesMenu) { if (!rainmeter.m_Favorites.empty()) { DeleteMenu(favoritesMenu, 0, MF_BYPOSITION); // "No skins available" menuitem CreateFavoritesMenu(favoritesMenu); } } HMENU layoutMenu = GetSubMenu(menu, 6); if (layoutMenu) { if (!rainmeter.m_Layouts.empty()) { DeleteMenu(layoutMenu, 0, MF_BYPOSITION); // "No layouts available" menuitem CreateLayoutMenu(layoutMenu); } } if (skin) { HMENU rainmeterMenu = menu; menu = CreateSkinMenu(skin, 0, allSkinsMenu); InsertMenu(menu, IDM_CLOSESKIN, MF_BYCOMMAND | MF_POPUP, (UINT_PTR)rainmeterMenu, L"Rainmeter"); InsertMenu(menu, IDM_CLOSESKIN, MF_BYCOMMAND | MF_SEPARATOR, 0, nullptr); } else { InsertMenu(menu, 13, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); // Create a menu for all active skins int index = 0; std::map<std::wstring, Skin*>::const_iterator iter = rainmeter.m_Skins.begin(); for (; iter != rainmeter.m_Skins.end(); ++iter) { Skin* skin = ((*iter).second); HMENU skinMenu = CreateSkinMenu(skin, index, allSkinsMenu); InsertMenu(menu, 13, MF_BYPOSITION | MF_POPUP, (UINT_PTR)skinMenu, skin->GetFolderPath().c_str()); ++index; } // Add update notification item if (rainmeter.m_NewVersion) { InsertMenu(menu, 0, MF_BYPOSITION, IDM_NEW_VERSION, GetString(ID_STR_UPDATEAVAILABLE)); HiliteMenuItem(rainmeter.GetTrayIcon()->GetWindow(), menu, 0, MF_BYPOSITION | MF_HILITE); InsertMenu(menu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); } } HWND hWnd = WindowFromPoint(pos); if (hWnd != nullptr) { Skin* skin = rainmeter.GetSkin(hWnd); if (skin) { // Cancel the mouse event beforehand skin->SetMouseLeaveEvent(true); } } DisplayMenu(pos, menu, skin ? skin->GetWindow() : rainmeter.m_TrayIcon->GetWindow()); DestroyMenu(menu); m_MenuActive = false; }
HMENU ContextMenu::CreateSkinMenu(Skin* skin, int index, HMENU menu) { static const MenuTemplate s_Menu[] = { MENU_ITEM(IDM_SKIN_OPENSKINSFOLDER, 0), MENU_SEPARATOR(), MENU_SUBMENU(ID_STR_VARIANTS, MENU_SEPARATOR()), MENU_SEPARATOR(), MENU_SUBMENU(ID_STR_SETTINGS, MENU_SUBMENU(ID_STR_POSITION, MENU_SUBMENU(ID_STR_DISPLAYMONITOR, MENU_ITEM(IDM_SKIN_MONITOR_PRIMARY, ID_STR_USEDEFAULTMONITOR), MENU_ITEM(ID_MONITOR_FIRST, ID_STR_VIRTUALSCREEN), MENU_SEPARATOR(), MENU_SEPARATOR(), MENU_ITEM(IDM_SKIN_MONITOR_AUTOSELECT, ID_STR_AUTOSELECTMONITOR)), MENU_SEPARATOR(), MENU_ITEM(IDM_SKIN_VERYTOPMOST, ID_STR_STAYTOPMOST), MENU_ITEM(IDM_SKIN_TOPMOST, ID_STR_TOPMOST), MENU_ITEM(IDM_SKIN_NORMAL, ID_STR_NORMAL), MENU_ITEM(IDM_SKIN_BOTTOM, ID_STR_BOTTOM), MENU_ITEM(IDM_SKIN_ONDESKTOP, ID_STR_ONDESKTOP), MENU_SEPARATOR(), MENU_ITEM(IDM_SKIN_FROMRIGHT, ID_STR_FROMRIGHT), MENU_ITEM(IDM_SKIN_FROMBOTTOM, ID_STR_FROMBOTTOM), MENU_ITEM(IDM_SKIN_XPERCENTAGE, ID_STR_XASPERCENTAGE), MENU_ITEM(IDM_SKIN_YPERCENTAGE, ID_STR_YASPERCENTAGE)), MENU_SUBMENU(ID_STR_TRANSPARENCY, MENU_ITEM(IDM_SKIN_TRANSPARENCY_0, ID_STR_0PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_10, ID_STR_10PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_20, ID_STR_20PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_30, ID_STR_30PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_40, ID_STR_40PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_50, ID_STR_50PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_60, ID_STR_60PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_70, ID_STR_70PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_80, ID_STR_80PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_90, ID_STR_90PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_100, ID_STR_100PERCENT), MENU_SEPARATOR(), MENU_ITEM(IDM_SKIN_TRANSPARENCY_FADEIN, ID_STR_FADEIN), MENU_ITEM(IDM_SKIN_TRANSPARENCY_FADEOUT, ID_STR_FADEOUT)), MENU_SEPARATOR(), MENU_ITEM(IDM_SKIN_HIDEONMOUSE, ID_STR_HIDEONMOUSEOVER), MENU_ITEM(IDM_SKIN_DRAGGABLE, ID_STR_DRAGGABLE), MENU_ITEM(IDM_SKIN_REMEMBERPOSITION, ID_STR_SAVEPOSITION), MENU_ITEM(IDM_SKIN_SNAPTOEDGES, ID_STR_SNAPTOEDGES), MENU_ITEM(IDM_SKIN_CLICKTHROUGH, ID_STR_CLICKTHROUGH), MENU_ITEM(IDM_SKIN_KEEPONSCREEN, ID_STR_KEEPONSCREEN), MENU_ITEM(IDM_SKIN_USED2D, ID_STR_USED2D), MENU_ITEM(IDM_SKIN_FAVORITE, ID_STR_FAVORITE)), MENU_SEPARATOR(), MENU_ITEM(IDM_SKIN_MANAGESKIN, ID_STR_MANAGESKIN), MENU_ITEM(IDM_SKIN_EDITSKIN, ID_STR_EDITSKIN), MENU_ITEM(IDM_SKIN_REFRESH, ID_STR_REFRESHSKIN), MENU_SEPARATOR(), MENU_ITEM(IDM_CLOSESKIN, ID_STR_UNLOADSKIN) }; HMENU skinMenu = MenuTemplate::CreateMenu(s_Menu, _countof(s_Menu), GetString); if (!skinMenu) return nullptr; // Tick the position HMENU settingsMenu = GetSubMenu(skinMenu, 4); if (settingsMenu) { HMENU posMenu = GetSubMenu(settingsMenu, 0); if (posMenu) { const UINT checkPos = IDM_SKIN_NORMAL - (UINT)skin->GetWindowZPosition(); CheckMenuRadioItem(posMenu, checkPos, checkPos, checkPos, MF_BYCOMMAND); if (skin->GetXFromRight()) CheckMenuItem(posMenu, IDM_SKIN_FROMRIGHT, MF_BYCOMMAND | MF_CHECKED); if (skin->GetYFromBottom()) CheckMenuItem(posMenu, IDM_SKIN_FROMBOTTOM, MF_BYCOMMAND | MF_CHECKED); if (skin->GetXPercentage()) CheckMenuItem(posMenu, IDM_SKIN_XPERCENTAGE, MF_BYCOMMAND | MF_CHECKED); if (skin->GetYPercentage()) CheckMenuItem(posMenu, IDM_SKIN_YPERCENTAGE, MF_BYCOMMAND | MF_CHECKED); HMENU monitorMenu = GetSubMenu(posMenu, 0); if (monitorMenu) { CreateMonitorMenu(monitorMenu, skin); } } // Tick the transparency HMENU alphaMenu = GetSubMenu(settingsMenu, 1); if (alphaMenu) { int alpha = skin->GetAlphaValue(); if (alpha <= 1) // ~100% { CheckMenuRadioItem(alphaMenu, 10, 10, 10, MF_BYPOSITION); } else { UINT checkPos = (UINT)(10 - alpha / 25.5); checkPos = min(9, checkPos); checkPos = max(0, checkPos); CheckMenuRadioItem(alphaMenu, checkPos, checkPos, checkPos, MF_BYPOSITION); } switch (skin->GetWindowHide()) { case HIDEMODE_FADEIN: CheckMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEIN, MF_BYCOMMAND | MF_CHECKED); EnableMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEOUT, MF_BYCOMMAND | MF_GRAYED); break; case HIDEMODE_FADEOUT: CheckMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEOUT, MF_BYCOMMAND | MF_CHECKED); EnableMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEIN, MF_BYCOMMAND | MF_GRAYED); break; case HIDEMODE_HIDE: EnableMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEIN, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEOUT, MF_BYCOMMAND | MF_GRAYED); break; } } // Tick the settings switch (skin->GetWindowHide()) { case HIDEMODE_HIDE: CheckMenuItem(settingsMenu, IDM_SKIN_HIDEONMOUSE, MF_BYCOMMAND | MF_CHECKED); break; case HIDEMODE_FADEIN: case HIDEMODE_FADEOUT: EnableMenuItem(settingsMenu, IDM_SKIN_HIDEONMOUSE, MF_BYCOMMAND | MF_GRAYED); break; } if (skin->GetSnapEdges()) { CheckMenuItem(settingsMenu, IDM_SKIN_SNAPTOEDGES, MF_BYCOMMAND | MF_CHECKED); } if (skin->GetSavePosition()) { CheckMenuItem(settingsMenu, IDM_SKIN_REMEMBERPOSITION, MF_BYCOMMAND | MF_CHECKED); } if (GetRainmeter().m_DisableDragging) { EnableMenuItem(settingsMenu, IDM_SKIN_DRAGGABLE, MF_BYCOMMAND | MF_GRAYED); } else if (skin->GetWindowDraggable()) { CheckMenuItem(settingsMenu, IDM_SKIN_DRAGGABLE, MF_BYCOMMAND | MF_CHECKED); } if (skin->GetClickThrough()) { CheckMenuItem(settingsMenu, IDM_SKIN_CLICKTHROUGH, MF_BYCOMMAND | MF_CHECKED); } if (skin->GetKeepOnScreen()) { CheckMenuItem(settingsMenu, IDM_SKIN_KEEPONSCREEN, MF_BYCOMMAND | MF_CHECKED); } if (Gfx::CanvasD2D::Initialize()) { if (!Rainmeter::GetInstance().GetUseD2D()) { EnableMenuItem(settingsMenu, IDM_SKIN_USED2D, MF_BYCOMMAND | MF_GRAYED); } else if (skin->GetUseD2D()) { CheckMenuItem(settingsMenu, IDM_SKIN_USED2D, MF_BYCOMMAND | MF_CHECKED); } } else { DeleteMenu(settingsMenu, IDM_SKIN_USED2D, MF_BYCOMMAND); } Gfx::CanvasD2D::Finalize(); if (skin->GetFavorite()) { CheckMenuItem(settingsMenu, IDM_SKIN_FAVORITE, MF_BYCOMMAND | MF_CHECKED); } } // Add the name of the Skin to the menu const std::wstring& skinName = skin->GetFolderPath(); ModifyMenu(skinMenu, IDM_SKIN_OPENSKINSFOLDER, MF_BYCOMMAND, IDM_SKIN_OPENSKINSFOLDER, skinName.c_str()); SetMenuDefaultItem(skinMenu, IDM_SKIN_OPENSKINSFOLDER, FALSE); // Remove dummy menuitem from the variants menu HMENU variantsMenu = GetSubMenu(skinMenu, 2); if (variantsMenu) { DeleteMenu(variantsMenu, 0, MF_BYPOSITION); } // Give the menuitem the unique id that depends on the skin ChangeSkinIndex(skinMenu, index); // Add the variants menu if (variantsMenu) { const SkinRegistry::Folder& skinFolder = *GetRainmeter().m_SkinRegistry.FindFolder(skinName); for (int i = 0, isize = (int)skinFolder.files.size(); i < isize; ++i) { InsertMenu(variantsMenu, i, MF_BYPOSITION, skinFolder.baseID + i, skinFolder.files[i].filename.c_str()); } if (skinFolder.active) { UINT checkPos = skinFolder.active - 1; CheckMenuRadioItem(variantsMenu, checkPos, checkPos, checkPos, MF_BYPOSITION); } } // Add skin root menu int itemCount = GetMenuItemCount(menu); if (itemCount > 0) { std::wstring root = skin->GetFolderPath(); std::wstring::size_type pos = root.find_first_of(L'\\'); if (pos != std::wstring::npos) { root.erase(pos); } // Skip "Open folder", "Disable dragging" and a separator for (int i = 3; i < itemCount; ++i) { const UINT state = GetMenuState(menu, i, MF_BYPOSITION); if (state == 0xFFFFFFFF || (state & MF_POPUP) == 0) break; WCHAR buffer[MAX_PATH]; if (GetMenuString(menu, i, buffer, MAX_PATH, MF_BYPOSITION)) { if (_wcsicmp(root.c_str(), buffer) == 0) { HMENU skinRootMenu = GetSubMenu(menu, i); if (skinRootMenu) { InsertMenu(skinMenu, 3, MF_BYPOSITION | MF_POPUP, (UINT_PTR)skinRootMenu, root.c_str()); } break; } } } } AppendSkinCustomMenu(skin, index, skinMenu, false); return skinMenu; }
void menu_command(WMenu *menu, int cmd) { WMenu *other; switch(cmd){ case MENU_CMD_PREV: if(menu->selected>0) menu_set_selected(menu, menu->selected-1); else menu_set_selected(menu, menu->data->nentries-1); vis_entry(menu, menu->selected); break; case MENU_CMD_NEXT: if(menu->selected<menu->data->nentries-1) menu_set_selected(menu, menu->selected+1); else menu_set_selected(menu, 0); vis_entry(menu, menu->selected); break; case MENU_CMD_ENTERSUB: case MENU_CMD_EXECUTE: if(menu->selected<0) break; if(MENU_SUBMENU(menu)==NULL){ if(menu->data->entries[menu->selected].flags&WMENUENT_SUBMENU) show_selected_submenu(menu); } other=MENU_SUBMENU(menu); if(other!=NULL){ set_active_menu(other); if(other->selected==NO_ENTRY) other->selected=0; vis_entry(other, other->selected); break; } if(cmd!=MENU_CMD_EXECUTE) break; menu_execute_selected(menu); break; case MENU_CMD_LEAVESUB: other=MENU_PARENT(menu); if(other!=NULL){ do_destroy_menu_tree(menu, FALSE, FALSE); /* set_active_menu is not used because unlink_winobj_d gives the * parent a focus if the destroyed menu is current. This should * not bee true in INPUT_CTXMENU mode. */ if(wglobal.input_mode==INPUT_CTXMENU) wglobal.grab_holder=(WThing*)other; vis_entry(other, other->selected); } break; case MENU_CMD_CLOSE: finish_menu(menu, TRUE); finish_contextual_menus(); break; case MENU_CMD_RAISEKEEP: raise_winobj((WWinObj*)menu); case MENU_CMD_KEEP: keep(menu); break; } }
/* ** Opens the context menu in given coordinates. */ void ContextMenu::ShowMenu(POINT pos, MeterWindow* meterWindow) { static const MenuTemplate s_Menu[] = { MENU_ITEM(IDM_MANAGE, ID_STR_MANAGE), MENU_ITEM(IDM_ABOUT, ID_STR_ABOUT), MENU_ITEM(IDM_SHOW_HELP, ID_STR_HELP), MENU_SEPARATOR(), MENU_SUBMENU(ID_STR_SKINS, MENU_ITEM_GRAYED(0, ID_STR_NOSKINS), MENU_SEPARATOR(), MENU_ITEM(IDM_OPENSKINSFOLDER, ID_STR_OPENFOLDER), MENU_ITEM(IDM_DISABLEDRAG, ID_STR_DISABLEDRAGGING)), MENU_SUBMENU(ID_STR_THEMES, MENU_ITEM_GRAYED(0, ID_STR_NOTHEMES)), MENU_SEPARATOR(), MENU_ITEM(IDM_EDITCONFIG, ID_STR_EDITSETTINGS), MENU_ITEM(IDM_REFRESH, ID_STR_REFRESHALL), MENU_SEPARATOR(), MENU_SUBMENU(ID_STR_LOGGING, MENU_ITEM(IDM_SHOWLOGFILE, ID_STR_SHOWLOGFILE), MENU_SEPARATOR(), MENU_ITEM(IDM_STARTLOG, ID_STR_STARTLOGGING), MENU_ITEM(IDM_STOPLOG, ID_STR_STOPLOGGING), MENU_SEPARATOR(), MENU_ITEM(IDM_DELETELOGFILE, ID_STR_DELETELOGFILE), MENU_ITEM(IDM_DEBUGLOG, ID_STR_DEBUGMODE)), MENU_SEPARATOR(), MENU_ITEM(IDM_QUIT, ID_STR_EXIT) }; if (m_MenuActive || (meterWindow && meterWindow->IsClosing())) return; // Show context menu, if no actions were executed HMENU menu = MenuTemplate::CreateMenu(s_Menu, _countof(s_Menu), GetString); if (!menu) return; m_MenuActive = true; Rainmeter& rainmeter = GetRainmeter(); SetMenuDefaultItem(menu, IDM_MANAGE, MF_BYCOMMAND); if (_waccess(GetLogger().GetLogFilePath().c_str(), 0) == -1) { EnableMenuItem(menu, IDM_SHOWLOGFILE, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(menu, IDM_DELETELOGFILE, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(menu, IDM_STOPLOG, MF_BYCOMMAND | MF_GRAYED); } else { EnableMenuItem( menu, (GetLogger().IsLogToFile()) ? IDM_STARTLOG : IDM_STOPLOG, MF_BYCOMMAND | MF_GRAYED); } if (rainmeter.m_Debug) { CheckMenuItem(menu, IDM_DEBUGLOG, MF_BYCOMMAND | MF_CHECKED); } HMENU allSkinsMenu = GetSubMenu(menu, 4); if (allSkinsMenu) { if (!rainmeter.m_SkinRegistry.IsEmpty()) { DeleteMenu(allSkinsMenu, 0, MF_BYPOSITION); // "No skins available" menuitem CreateAllSkinsMenu(allSkinsMenu); } if (rainmeter.m_DisableDragging) { CheckMenuItem(allSkinsMenu, IDM_DISABLEDRAG, MF_BYCOMMAND | MF_CHECKED); } } HMENU layoutMenu = GetSubMenu(menu, 5); if (layoutMenu) { if (!rainmeter.m_Layouts.empty()) { DeleteMenu(layoutMenu, 0, MF_BYPOSITION); // "No layouts available" menuitem CreateLayoutMenu(layoutMenu); } } if (meterWindow) { HMENU rainmeterMenu = menu; menu = CreateSkinMenu(meterWindow, 0, allSkinsMenu); InsertMenu(menu, IDM_CLOSESKIN, MF_BYCOMMAND | MF_POPUP, (UINT_PTR)rainmeterMenu, L"Rainmeter"); InsertMenu(menu, IDM_CLOSESKIN, MF_BYCOMMAND | MF_SEPARATOR, 0, nullptr); } else { InsertMenu(menu, 12, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); // Create a menu for all active skins int index = 0; std::map<std::wstring, MeterWindow*>::const_iterator iter = rainmeter.m_MeterWindows.begin(); for (; iter != rainmeter.m_MeterWindows.end(); ++iter) { MeterWindow* mw = ((*iter).second); HMENU skinMenu = CreateSkinMenu(mw, index, allSkinsMenu); InsertMenu(menu, 12, MF_BYPOSITION | MF_POPUP, (UINT_PTR)skinMenu, mw->GetFolderPath().c_str()); ++index; } // Add update notification item if (rainmeter.m_NewVersion) { InsertMenu(menu, 0, MF_BYPOSITION, IDM_NEW_VERSION, GetString(ID_STR_UPDATEAVAILABLE)); HiliteMenuItem(rainmeter.GetTrayWindow()->GetWindow(), menu, 0, MF_BYPOSITION | MF_HILITE); InsertMenu(menu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); } } HWND hWnd = WindowFromPoint(pos); if (hWnd != nullptr) { MeterWindow* mw = rainmeter.GetMeterWindow(hWnd); if (mw) { // Cancel the mouse event beforehand mw->SetMouseLeaveEvent(true); } } // Set the window to foreground hWnd = meterWindow ? meterWindow->GetWindow() : rainmeter.m_TrayWindow->GetWindow(); HWND hWndForeground = GetForegroundWindow(); if (hWndForeground != hWnd) { const DWORD foregroundThreadID = GetWindowThreadProcessId(hWndForeground, nullptr); const DWORD currentThreadID = GetCurrentThreadId(); AttachThreadInput(currentThreadID, foregroundThreadID, TRUE); SetForegroundWindow(hWnd); AttachThreadInput(currentThreadID, foregroundThreadID, FALSE); } // Show context menu TrackPopupMenu( menu, TPM_RIGHTBUTTON | TPM_LEFTALIGN | (*GetString(ID_STR_ISRTL) == L'1' ? TPM_LAYOUTRTL : 0), pos.x, pos.y, 0, hWnd, nullptr); DestroyMenu(menu); m_MenuActive = false; }
HMENU ContextMenu::CreateSkinMenu(MeterWindow* meterWindow, int index, HMENU menu) { static const MenuTemplate s_Menu[] = { MENU_ITEM(IDM_SKIN_OPENSKINSFOLDER, 0), MENU_SEPARATOR(), MENU_SUBMENU(ID_STR_VARIANTS, MENU_SEPARATOR()), MENU_SEPARATOR(), MENU_SUBMENU(ID_STR_SETTINGS, MENU_SUBMENU(ID_STR_POSITION, MENU_SUBMENU(ID_STR_DISPLAYMONITOR, MENU_ITEM(IDM_SKIN_MONITOR_PRIMARY, ID_STR_USEDEFAULTMONITOR), MENU_ITEM(ID_MONITOR_FIRST, ID_STR_VIRTUALSCREEN), MENU_SEPARATOR(), MENU_SEPARATOR(), MENU_ITEM(IDM_SKIN_MONITOR_AUTOSELECT, ID_STR_AUTOSELECTMONITOR)), MENU_SEPARATOR(), MENU_ITEM(IDM_SKIN_VERYTOPMOST, ID_STR_STAYTOPMOST), MENU_ITEM(IDM_SKIN_TOPMOST, ID_STR_TOPMOST), MENU_ITEM(IDM_SKIN_NORMAL, ID_STR_NORMAL), MENU_ITEM(IDM_SKIN_BOTTOM, ID_STR_BOTTOM), MENU_ITEM(IDM_SKIN_ONDESKTOP, ID_STR_ONDESKTOP), MENU_SEPARATOR(), MENU_ITEM(IDM_SKIN_FROMRIGHT, ID_STR_FROMRIGHT), MENU_ITEM(IDM_SKIN_FROMBOTTOM, ID_STR_FROMBOTTOM), MENU_ITEM(IDM_SKIN_XPERCENTAGE, ID_STR_XASPERCENTAGE), MENU_ITEM(IDM_SKIN_YPERCENTAGE, ID_STR_YASPERCENTAGE)), MENU_SUBMENU(ID_STR_TRANSPARENCY, MENU_ITEM(IDM_SKIN_TRANSPARENCY_0, ID_STR_0PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_10, ID_STR_10PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_20, ID_STR_20PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_30, ID_STR_30PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_40, ID_STR_40PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_50, ID_STR_50PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_60, ID_STR_60PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_70, ID_STR_70PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_80, ID_STR_80PERCENT), MENU_ITEM(IDM_SKIN_TRANSPARENCY_90, ID_STR_90PERCENT), MENU_SEPARATOR(), MENU_ITEM(IDM_SKIN_TRANSPARENCY_FADEIN, ID_STR_FADEIN), MENU_ITEM(IDM_SKIN_TRANSPARENCY_FADEOUT, ID_STR_FADEOUT)), MENU_SEPARATOR(), MENU_ITEM(IDM_SKIN_HIDEONMOUSE, ID_STR_HIDEONMOUSEOVER), MENU_ITEM(IDM_SKIN_DRAGGABLE, ID_STR_DRAGGABLE), MENU_ITEM(IDM_SKIN_REMEMBERPOSITION, ID_STR_SAVEPOSITION), MENU_ITEM(IDM_SKIN_SNAPTOEDGES, ID_STR_SNAPTOEDGES), MENU_ITEM(IDM_SKIN_CLICKTHROUGH, ID_STR_CLICKTHROUGH), MENU_ITEM(IDM_SKIN_KEEPONSCREEN, ID_STR_KEEPONSCREEN), MENU_ITEM(IDM_SKIN_USED2D, ID_STR_USED2D)), MENU_SEPARATOR(), MENU_ITEM(IDM_SKIN_MANAGESKIN, ID_STR_MANAGESKIN), MENU_ITEM(IDM_SKIN_EDITSKIN, ID_STR_EDITSKIN), MENU_ITEM(IDM_SKIN_REFRESH, ID_STR_REFRESHSKIN), MENU_SEPARATOR(), MENU_ITEM(IDM_CLOSESKIN, ID_STR_UNLOADSKIN) }; HMENU skinMenu = MenuTemplate::CreateMenu(s_Menu, _countof(s_Menu), GetString); if (!skinMenu) return nullptr; // Tick the position HMENU settingsMenu = GetSubMenu(skinMenu, 4); if (settingsMenu) { HMENU posMenu = GetSubMenu(settingsMenu, 0); if (posMenu) { const UINT checkPos = IDM_SKIN_NORMAL - (UINT)meterWindow->GetWindowZPosition(); CheckMenuRadioItem(posMenu, checkPos, checkPos, checkPos, MF_BYCOMMAND); if (meterWindow->GetXFromRight()) CheckMenuItem(posMenu, IDM_SKIN_FROMRIGHT, MF_BYCOMMAND | MF_CHECKED); if (meterWindow->GetYFromBottom()) CheckMenuItem(posMenu, IDM_SKIN_FROMBOTTOM, MF_BYCOMMAND | MF_CHECKED); if (meterWindow->GetXPercentage()) CheckMenuItem(posMenu, IDM_SKIN_XPERCENTAGE, MF_BYCOMMAND | MF_CHECKED); if (meterWindow->GetYPercentage()) CheckMenuItem(posMenu, IDM_SKIN_YPERCENTAGE, MF_BYCOMMAND | MF_CHECKED); HMENU monitorMenu = GetSubMenu(posMenu, 0); if (monitorMenu) { CreateMonitorMenu(monitorMenu, meterWindow); } } // Tick the transparency HMENU alphaMenu = GetSubMenu(settingsMenu, 1); if (alphaMenu) { UINT checkPos = (UINT)(10 - meterWindow->GetAlphaValue() / 25.5); checkPos = min(9, checkPos); checkPos = max(0, checkPos); CheckMenuRadioItem(alphaMenu, checkPos, checkPos, checkPos, MF_BYPOSITION); switch (meterWindow->GetWindowHide()) { case HIDEMODE_FADEIN: CheckMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEIN, MF_BYCOMMAND | MF_CHECKED); EnableMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEOUT, MF_BYCOMMAND | MF_GRAYED); break; case HIDEMODE_FADEOUT: CheckMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEOUT, MF_BYCOMMAND | MF_CHECKED); EnableMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEIN, MF_BYCOMMAND | MF_GRAYED); break; case HIDEMODE_HIDE: EnableMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEIN, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(alphaMenu, IDM_SKIN_TRANSPARENCY_FADEOUT, MF_BYCOMMAND | MF_GRAYED); break; } } // Tick the settings switch (meterWindow->GetWindowHide()) { case HIDEMODE_HIDE: CheckMenuItem(settingsMenu, IDM_SKIN_HIDEONMOUSE, MF_BYCOMMAND | MF_CHECKED); break; case HIDEMODE_FADEIN: case HIDEMODE_FADEOUT: EnableMenuItem(settingsMenu, IDM_SKIN_HIDEONMOUSE, MF_BYCOMMAND | MF_GRAYED); break; } if (meterWindow->GetSnapEdges()) { CheckMenuItem(settingsMenu, IDM_SKIN_SNAPTOEDGES, MF_BYCOMMAND | MF_CHECKED); } if (meterWindow->GetSavePosition()) { CheckMenuItem(settingsMenu, IDM_SKIN_REMEMBERPOSITION, MF_BYCOMMAND | MF_CHECKED); } if (GetRainmeter().m_DisableDragging) { EnableMenuItem(settingsMenu, IDM_SKIN_DRAGGABLE, MF_BYCOMMAND | MF_GRAYED); } else if (meterWindow->GetWindowDraggable()) { CheckMenuItem(settingsMenu, IDM_SKIN_DRAGGABLE, MF_BYCOMMAND | MF_CHECKED); } if (meterWindow->GetClickThrough()) { CheckMenuItem(settingsMenu, IDM_SKIN_CLICKTHROUGH, MF_BYCOMMAND | MF_CHECKED); } if (meterWindow->GetKeepOnScreen()) { CheckMenuItem(settingsMenu, IDM_SKIN_KEEPONSCREEN, MF_BYCOMMAND | MF_CHECKED); } if (Gfx::CanvasD2D::Initialize()) { if (!Rainmeter::GetInstance().GetUseD2D()) { EnableMenuItem(settingsMenu, IDM_SKIN_USED2D, MF_BYCOMMAND | MF_GRAYED); } else if (meterWindow->GetUseD2D()) { CheckMenuItem(settingsMenu, IDM_SKIN_USED2D, MF_BYCOMMAND | MF_CHECKED); } } else { DeleteMenu(settingsMenu, IDM_SKIN_USED2D, MF_BYCOMMAND); } Gfx::CanvasD2D::Finalize(); } // Add the name of the Skin to the menu const std::wstring& skinName = meterWindow->GetFolderPath(); ModifyMenu(skinMenu, IDM_SKIN_OPENSKINSFOLDER, MF_BYCOMMAND, IDM_SKIN_OPENSKINSFOLDER, skinName.c_str()); SetMenuDefaultItem(skinMenu, IDM_SKIN_OPENSKINSFOLDER, FALSE); // Remove dummy menuitem from the variants menu HMENU variantsMenu = GetSubMenu(skinMenu, 2); if (variantsMenu) { DeleteMenu(variantsMenu, 0, MF_BYPOSITION); } // Give the menuitem the unique id that depends on the skin ChangeSkinIndex(skinMenu, index); // Add the variants menu if (variantsMenu) { const SkinRegistry::Folder& skinFolder = *GetRainmeter().m_SkinRegistry.FindFolder(skinName); for (int i = 0, isize = (int)skinFolder.files.size(); i < isize; ++i) { InsertMenu(variantsMenu, i, MF_BYPOSITION, skinFolder.baseID + i, skinFolder.files[i].c_str()); } if (skinFolder.active) { UINT checkPos = skinFolder.active - 1; CheckMenuRadioItem(variantsMenu, checkPos, checkPos, checkPos, MF_BYPOSITION); } } // Add skin root menu int itemCount = GetMenuItemCount(menu); if (itemCount > 0) { std::wstring root = meterWindow->GetFolderPath(); std::wstring::size_type pos = root.find_first_of(L'\\'); if (pos != std::wstring::npos) { root.erase(pos); } for (int i = 0; i < itemCount; ++i) { const UINT state = GetMenuState(menu, i, MF_BYPOSITION); if (state == 0xFFFFFFFF || (state & MF_POPUP) == 0) break; WCHAR buffer[MAX_PATH]; if (GetMenuString(menu, i, buffer, MAX_PATH, MF_BYPOSITION)) { if (_wcsicmp(root.c_str(), buffer) == 0) { HMENU skinRootMenu = GetSubMenu(menu, i); if (skinRootMenu) { InsertMenu(skinMenu, 3, MF_BYPOSITION | MF_POPUP, (UINT_PTR)skinRootMenu, root.c_str()); } break; } } } } // Add custom actions to the context menu std::wstring contextTitle = meterWindow->GetParser().ReadString(L"Rainmeter", L"ContextTitle", L""); if (!contextTitle.empty()) { auto isTitleSeparator = [](const std::wstring& title) { return title.find_first_not_of(L'-') == std::wstring::npos; }; std::wstring contextAction = meterWindow->GetParser().ReadString(L"Rainmeter", L"ContextAction", L""); if (!contextAction.empty() || isTitleSeparator(contextTitle)) { std::vector<std::wstring> cTitles; WCHAR buffer[128]; int i = 1; while (!contextTitle.empty() && (!contextAction.empty() || isTitleSeparator(contextTitle)) && (IDM_SKIN_CUSTOMCONTEXTMENU_FIRST + i - 1) <= IDM_SKIN_CUSTOMCONTEXTMENU_LAST) // Set maximum context items in resource.h { // Trim long titles if (contextTitle.size() > 30) { contextTitle.replace(27, contextTitle.size() - 27, L"..."); } cTitles.push_back(contextTitle); _snwprintf_s(buffer, _TRUNCATE, L"ContextTitle%i", ++i); contextTitle = meterWindow->GetParser().ReadString(L"Rainmeter", buffer, L""); _snwprintf_s(buffer, _TRUNCATE, L"ContextAction%i", i); contextAction = meterWindow->GetParser().ReadString(L"Rainmeter", buffer, L""); } // Build a sub-menu if more than three items const size_t titleSize = cTitles.size(); if (titleSize <= 3) { size_t position = 0; for (size_t i = 0; i < titleSize; ++i) { if (isTitleSeparator(cTitles[i])) { // Separators not allowed in main top-level menu --position; } else { const UINT_PTR id = (index << 16) | (IDM_SKIN_CUSTOMCONTEXTMENU_FIRST + i); InsertMenu(skinMenu, position + 1, MF_BYPOSITION | MF_STRING, id, cTitles[i].c_str()); } ++position; } if (position != 0) { InsertMenu(skinMenu, 1, MF_BYPOSITION | MF_STRING | MF_GRAYED, 0, L"Custom skin actions"); InsertMenu(skinMenu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); } } else { HMENU customMenu = CreatePopupMenu(); InsertMenu(skinMenu, 1, MF_BYPOSITION | MF_POPUP, (UINT_PTR)customMenu, L"Custom skin actions"); for (size_t i = 0; i < titleSize; ++i) { if (isTitleSeparator(cTitles[i])) { AppendMenu(customMenu, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); } else { const UINT_PTR id = (index << 16) | (IDM_SKIN_CUSTOMCONTEXTMENU_FIRST + i); AppendMenu(customMenu, MF_BYPOSITION | MF_STRING, id, cTitles[i].c_str()); } } InsertMenu(skinMenu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); } } } return skinMenu; }