FlightGear next
FGWindowsMenuBar.cxx
Go to the documentation of this file.
1/*
2 * SPDX-FileName: FGWindowsMenuBar.cxx
3 * SPDX-FileComment: XML-configured menu bar.
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <cstring>
10#include <windows.h>
11
12#include <osgViewer/GraphicsWindow>
13#include <osgViewer/Viewer>
14#include <osgViewer/api/Win32/GraphicsWindowWin32>
15
16#include <simgear/debug/logstream.hxx>
17#include <simgear/misc/strutils.hxx>
18#include <simgear/props/props.hxx>
19#include <simgear/props/props_io.hxx>
20#include <simgear/structure/SGBinding.hxx>
21
22#include <Main/fg_props.hxx>
23#include <Main/globals.hxx>
24#include <Viewer/renderer.hxx>
25
26#include "new_gui.hxx"
27
28#include <iostream>
29
31
32static HWND getMainViewerHWND()
33{
34 osgViewer::Viewer::Windows windows;
35 if (!globals->get_renderer() || !globals->get_renderer()->getViewerBase()) {
36 return nullptr;
37 }
38
39 globals->get_renderer()->getViewerBase()->getWindows(windows);
40 for (auto win : windows) {
41 if (strcmp(win->className(), "GraphicsWindowWin32")) {
42 continue;
43 }
44
45 osgViewer::GraphicsWindowWin32* platformWin =
46 static_cast<osgViewer::GraphicsWindowWin32*>(win);
47 return platformWin->getHWND();
48 }
49
50 return nullptr;
51}
52
53static bool nameIsSeparator(const std::string& n)
54{
55 return simgear::strutils::starts_with(n, "----");
56}
57
58static LRESULT CALLBACK menubarWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
59{
60 switch (Msg) {
61 case WM_COMMAND:
62 if (HIWORD(wParam) == 0) {
63 auto gui = globals->get_subsystem<NewGUI>();
64 auto menubar = (FGWindowsMenuBar*)gui->getMenuBar();
65 int commandId = (int)LOWORD(wParam);
66 if (commandId < menubar->getItemBindings().size()) {
67 fireBindingList(menubar->getItemBindings()[commandId]);
68 }
69 }
70 break;
71 }
72
73 return CallWindowProc((WNDPROC)g_prevWindowProc, hWnd, Msg, wParam, lParam);
74}
75
77{
78public:
81
83 HMENU menuBar;
84 bool visible = true;
86
87 typedef std::vector<SGBindingList> MenuItemBindings;
89};
90
96
98{
99 if (menuBar) {
100 SetMenu(mainWindow, NULL);
101 DestroyMenu(menuBar);
102 }
103}
104
108
110{
111 _p->menuBar = CreateMenu();
112 LONG_PTR tempWindowProc = GetWindowLongPtr(_p->mainWindow, GWLP_WNDPROC);
113 if (tempWindowProc != (LONG_PTR)menubarWindowProc) {
114 g_prevWindowProc = tempWindowProc;
115 SetWindowLongPtr(_p->mainWindow, GWLP_WNDPROC, (LONG_PTR)menubarWindowProc);
116 }
117
118 // menus in menu bar
119 SGPropertyNode_ptr props = fgGetNode("/sim/menubar/default", true);
120 for (auto menu : props->getChildren("menu")) {
121 // synchronise menu with properties
122 std::string label = simgear::strutils::simplify(getLocalizedLabel(menu));
123 HMENU menuItems = CreatePopupMenu();
124
125 if (!menu->hasValue("enabled")) {
126 menu->setBoolValue("enabled", true);
127 }
128
129 bool enabled = menu->getBoolValue("enabled");
130
131 UINT flags = enabled ? MF_POPUP : MF_POPUP | MF_GRAYED;
132 const auto wlabel = simgear::strutils::convertUtf8ToWString(label);
133 AppendMenuW(_p->menuBar, flags, (UINT_PTR)menuItems, wlabel.c_str());
134
135 // menu items in menu
136 for (auto menuItem : menu->getChildren("item")) {
137 if (!menuItem->hasValue("enabled")) {
138 menuItem->setBoolValue("enabled", true);
139 }
140
141 std::string label2 = simgear::strutils::simplify(getLocalizedLabel(menuItem));
142 std::string shortcut = menuItem->getStringValue("key");
143
144 SGBindingList bl = readBindingList(menuItem->getChildren("binding"), globals->get_props());
145 UINT commandId = _p->itemBindings.size();
146 _p->itemBindings.push_back(bl);
147
148 if (nameIsSeparator(label2)) {
149 AppendMenu(menuItems, MF_SEPARATOR, NULL, NULL);
150 } else {
151 if (!shortcut.empty()) {
152 label2 += "\t" + shortcut;
153 }
154 bool enabled = menuItem->getBoolValue("enabled");
155
156 UINT flags = enabled ? MF_STRING : MF_STRING | MF_GRAYED;
157 const auto wl2 = simgear::strutils::convertUtf8ToWString(label2);
158 AppendMenuW(menuItems, flags, commandId, wl2.c_str());
159 }
160 }
161 }
162
163 show();
164}
165
167{
168 SetMenu(_p->mainWindow, _p->menuBar);
169 _p->visible = true;
170}
171
173{
174 SetMenu(_p->mainWindow, NULL);
175 _p->visible = false;
176}
177
179{
180 return _p->visible;
181}
182
184{
185 _p->hideIfOverlapsWindow = hideOverlapping;
186 if (_p->menuBar) {
187 const bool actualVis = _p->visible && (!_p->hideIfOverlapsWindow);
188 if (actualVis) {
189 show();
190 } else {
191 hide();
192 }
193 }
194}
195
197{
198 return _p->hideIfOverlapsWindow;
199}
200
201std::vector<SGBindingList> FGWindowsMenuBar::getItemBindings() const
202{
203 return _p->itemBindings;
204}
static bool nameIsSeparator(const std::string &n)
static LRESULT CALLBACK menubarWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
static HWND getMainViewerHWND()
static bool nameIsSeparator(const std::string &n)
LONG_PTR g_prevWindowProc
static std::string getLocalizedLabel(SGPropertyNode *node)
Read a menu label from the menu's property tree.
Definition menubar.cxx:19
std::vector< SGBindingList > MenuItemBindings
XML-configured Windows menu bar.
void setHideIfOverlapsWindow(bool hide) override
Request the menubar to be hidden if its display overlays the main window content.
void hide() override
Make the menu bar invisible.
bool getHideIfOverlapsWindow() const override
void show() override
Make the menu bar visible.
FGWindowsMenuBar()
Constructor.
void init() override
Initialize the menu bar from $FG_ROOT/gui/menubar.xml.
bool isVisible() const override
Test whether the menu bar is visible.
std::vector< SGBindingList > getItemBindings() const
XML-configured GUI subsystem.
Definition new_gui.hxx:31
virtual FGMenuBar * getMenuBar()
Return a pointer to the current menubar.
Definition new_gui.cxx:438
FGGlobals * globals
Definition globals.cxx:142
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
Definition proptest.cpp:27