)
if(WIN32)
- message(STATUS "on Windows")
-
- list(APPEND HEADERS WindowsMouseCursor.hxx)
- list(APPEND SOURCES WindowsMouseCursor.cxx)
+ list(APPEND HEADERS WindowsMouseCursor.hxx
+ FGWindowsMenuBar.hxx
+ WindowsFileDialog.hxx)
+ list(APPEND SOURCES WindowsMouseCursor.cxx
+ FGWindowsMenuBar.cxx
+ WindowsFileDialog.cxx)
endif()
if (APPLE)
--- /dev/null
+#include "FGWindowsMenuBar.hxx"
+
+#include <windows.h>
+#include <cstring>
+
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <osgViewer/Viewer>
+#include <osgViewer/GraphicsWindow>
+#include <osgViewer/api/Win32/GraphicsWindowWin32>
+
+#include <simgear/props/props.hxx>
+#include <simgear/props/props_io.hxx>
+#include <simgear/debug/logstream.hxx>
+#include <simgear/structure/SGBinding.hxx>
+#include <simgear/misc/strutils.hxx>
+
+#include <Main/fg_props.hxx>
+#include <Main/globals.hxx>
+#include <Viewer/renderer.hxx>
+
+#include <iostream>
+
+using namespace simgear;
+
+namespace {
+
+HWND getMainViewerHWND()
+{
+ osgViewer::Viewer::Windows windows;
+ if (!globals->get_renderer() || !globals->get_renderer()->getViewer()) {
+ return 0;
+ }
+
+ globals->get_renderer()->getViewer()->getWindows(windows);
+ osgViewer::Viewer::Windows::const_iterator it = windows.begin();
+ for(; it != windows.end(); ++it) {
+ if (strcmp((*it)->className(), "GraphicsWindowWin32")) {
+ continue;
+ }
+
+ osgViewer::GraphicsWindowWin32* platformWin =
+ static_cast<osgViewer::GraphicsWindowWin32*>(*it);
+ return platformWin->getHWND();
+ }
+
+ return 0;
+}
+
+bool labelIsSeparator(const std::string& s)
+{
+ std::string t = "---";
+ if (s.compare(0, t.length(), t) == 0)
+ return true;
+ else
+ return false;
+}
+
+LRESULT CALLBACK menubarWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ SG_LOG(SG_GENERAL, SG_INFO, "called window proc");
+
+
+ return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
+}
+
+} // of anonymous namespace
+
+//
+
+class FGWindowsMenuBar::WindowsMenuBarPrivate
+{
+public:
+ WindowsMenuBarPrivate();
+ ~WindowsMenuBarPrivate();
+
+ void fireBindingsForItem(UINT commandId)
+ {
+ fireBindingList(itemBindings[commandId]);
+ }
+
+ HWND mainWindow;
+ HMENU menuBar;
+ bool visible;
+ WNDPROC baseMenuProc;
+
+ typedef std::vector<SGBindingList> MenuItemBindings;
+ MenuItemBindings itemBindings;
+
+};
+
+FGWindowsMenuBar::FGWindowsMenuBar() :
+ p(new WindowsMenuBarPrivate)
+{
+
+}
+
+FGWindowsMenuBar::~FGWindowsMenuBar()
+{
+
+}
+
+FGWindowsMenuBar::WindowsMenuBarPrivate::WindowsMenuBarPrivate() :
+ visible(true)
+{
+ mainWindow = getMainViewerHWND();
+ menuBar = 0;
+}
+
+FGWindowsMenuBar::WindowsMenuBarPrivate::~WindowsMenuBarPrivate()
+{
+ if (menuBar) {
+ SetMenu(mainWindow, NULL);
+ DestroyMenu(menuBar);
+ }
+}
+
+void FGWindowsMenuBar::init()
+{
+ int menuIndex = 0;
+ SGPropertyNode_ptr props = fgGetNode("/sim/menubar/default",true);
+
+ p->menuBar = CreateMenu();
+// p->baseMenuProc = (WNDPROC) ::SetWindowLongPtr((HWND) p->mainWindow, GWL_WNDPROC, (LONG_PTR) menubarWindowProc);
+
+ BOOST_FOREACH(SGPropertyNode_ptr n, props->getChildren("menu")) {
+ // synchronise menu with properties
+ std::string l = getLocalizedLabel(n);
+ std::string label = strutils::simplify(l).c_str();
+ HMENU menuItems = CreatePopupMenu();
+
+ if (!n->hasValue("enabled")) {
+ n->setBoolValue("enabled", true);
+ }
+
+ bool enabled = n->getBoolValue("enabled");
+
+ UINT flags = MF_POPUP;
+ AppendMenu(p->menuBar, flags, (UINT) menuItems, label.c_str());
+
+ // submenu
+ int subMenuIndex = 0;
+ SGPropertyNode* menuNode = n;
+ BOOST_FOREACH(SGPropertyNode_ptr n2, menuNode->getChildren("item")) {
+
+ if (!n2->hasValue("enabled")) {
+ n2->setBoolValue("enabled", true);
+ }
+
+ std::string l2 = getLocalizedLabel(n2);
+ std::string label2 = strutils::simplify(l2).c_str();
+ std::string shortcut = n2->getStringValue("key");
+
+ SGBindingList bl = readBindingList(n->getChildren("binding"), globals->get_props());
+ UINT commandId = p->itemBindings.size();
+ p->itemBindings.push_back(bl);
+
+ if (labelIsSeparator(label2)) {
+ AppendMenu(menuItems, MF_SEPARATOR, NULL, NULL);
+ } else {
+ if (!shortcut.empty()) {
+ label2 += "\t"+shortcut;
+ }
+ BOOL enabled = n2->getBoolValue("enabled");
+
+ UINT flags = MF_STRING;
+ AppendMenu(menuItems, flags, commandId, label2.c_str());
+ }
+ subMenuIndex++;
+ }
+ menuIndex++;
+ }
+
+ show();
+}
+
+bool FGWindowsMenuBar::isVisible() const
+{
+ return p->visible;
+}
+
+void FGWindowsMenuBar::show()
+{
+ SetMenu(p->mainWindow, p->menuBar);
+ p->visible = true;
+}
+
+void FGWindowsMenuBar::hide()
+{
+ SetMenu(p->mainWindow, NULL);
+ p->visible = false;
+}
+
+#if 0
+LRESULT CALLBACK WndProcedure(HWND hwnd, UINT Msg,
+ WPARAM wParam, LPARAM lParam)
+{
+ switch(Msg)
+ {
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case MY_MENU:
+ MessageBox(hwnd, "Menu Item Selected = Large", "Message", MB_OK);
+ break;
+ }
+ return 0;
+
+ case WM_DESTROY:
+ PostQuitMessage(WM_QUIT);
+ break;
+
+ default:
+ return DefWindowProc(hwnd, Msg, wParam, lParam);
+ }
+
+ return 0;
+}
+#endif
--- /dev/null
+// menubar.hxx - XML-configured menu bar.
+
+#ifndef FG_WINDOWS_MENUBAR_HXX
+#define FG_WINDOWS_MENUBAR_HXX 1
+
+#include <GUI/menubar.hxx>
+
+#include <memory>
+
+/**
+ * XML-configured Windows menu bar.
+ *
+ * This class creates a menu bar from a tree of XML properties. These
+ * properties are not part of the main FlightGear property tree, but
+ * are read from a separate file ($FG_ROOT/gui/menubar.xml).
+ *
+ * WARNING: because PUI provides no easy way to attach user data to a
+ * menu item, all menu item strings must be unique; otherwise, this
+ * class will always use the first binding with any given name.
+ */
+class FGWindowsMenuBar : public FGMenuBar
+{
+public:
+
+ /**
+ * Constructor.
+ */
+ FGWindowsMenuBar ();
+
+
+ /**
+ * Destructor.
+ */
+ virtual ~FGWindowsMenuBar ();
+
+
+ /**
+ * Initialize the menu bar from $FG_ROOT/gui/menubar.xml
+ */
+ virtual void init ();
+
+ /**
+ * Make the menu bar visible.
+ */
+ virtual void show ();
+
+
+ /**
+ * Make the menu bar invisible.
+ */
+ virtual void hide ();
+
+
+ /**
+ * Test whether the menu bar is visible.
+ */
+ virtual bool isVisible () const;
+
+ class WindowsMenuBarPrivate;
+private:
+ std::auto_ptr<WindowsMenuBarPrivate> p;
+};
+
+#endif // __MENUBAR_HXX
#include <Scripting/NasalSys.hxx>
#include "PUIFileDialog.hxx"
-#ifdef SG_MAC
+#if defined(SG_MAC)
#include "CocoaFileDialog.hxx"
#endif
+#if defined(SG_WINDOWS)
+ #include "WindowsFileDialog.hxx"
+#endif
+
FGFileDialog::FGFileDialog(Usage use) :
_usage(use),
_showHidden(false)
nasal::CallContext ctx(c, argc, args);
FGFileDialog::Usage usage = (FGFileDialog::Usage) ctx.requireArg<int>(0);
-#ifdef SG_MAC
+#if defined(SG_MAC)
FileDialogPtr fd(new CocoaFileDialog(usage));
+#elif defined(SG_WINDOWS)
+ FileDialogPtr fd(new WindowsFileDialog(usage));
#else
FileDialogPtr fd(new PUIFileDialog(usage));
#endif
--- /dev/null
+
+
+#include "WindowsFileDialog.hxx"
+
+#include <windows.h>
+#include <Shlobj.h>
+
+#include <boost/foreach.hpp>
+
+#include <osgViewer/Viewer>
+#include <osgViewer/api/Win32/GraphicsWindowWin32>
+
+#include <simgear/debug/logstream.hxx>
+#include <simgear/misc/strutils.hxx>
+
+#include <Main/globals.hxx>
+#include <Main/fg_props.hxx>
+#include <Viewer/renderer.hxx>
+
+namespace {
+
+HWND getMainViewerHWND()
+{
+ osgViewer::Viewer::Windows windows;
+ if (!globals->get_renderer() || !globals->get_renderer()->getViewer()) {
+ return 0;
+ }
+
+ globals->get_renderer()->getViewer()->getWindows(windows);
+ osgViewer::Viewer::Windows::const_iterator it = windows.begin();
+ for(; it != windows.end(); ++it) {
+ if (strcmp((*it)->className(), "GraphicsWindowWin32")) {
+ continue;
+ }
+
+ osgViewer::GraphicsWindowWin32* platformWin =
+ static_cast<osgViewer::GraphicsWindowWin32*>(*it);
+ return platformWin->getHWND();
+ }
+
+ return 0;
+}
+
+static int CALLBACK BrowseFolderCallback(
+ HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
+{
+ if (uMsg == BFFM_INITIALIZED) {
+ // set the initial directory now
+ WindowsFileDialog* dlg = reinterpret_cast<WindowsFileDialog*>(lpData);
+ LPCTSTR path = dlg->getDirectory().c_str();
+ ::SendMessage(hwnd, BFFM_SETSELECTION, true, (LPARAM) path);
+ }
+ return 0;
+}
+
+} // of anonymous namespace
+
+WindowsFileDialog::WindowsFileDialog(FGFileDialog::Usage use) :
+ FGFileDialog(use)
+{
+
+}
+
+WindowsFileDialog::~WindowsFileDialog()
+{
+
+}
+
+void WindowsFileDialog::exec()
+{
+ char Filestring[MAX_PATH] = "\0";
+ OPENFILENAME opf={0};
+ opf.lStructSize = sizeof(OPENFILENAME);
+ opf.lpstrFile = Filestring;
+ opf.lpstrTitle = const_cast<char *>(_title.c_str());
+ opf.nMaxFile = MAX_PATH;
+
+ std::string extensions;
+ size_t extensionsLen;
+ if (!_filterPatterns.empty()) {
+ BOOST_FOREACH(std::string ext, _filterPatterns) {
+ if (!simgear::strutils::starts_with(ext, "*.")) {
+ SG_LOG(SG_GENERAL, SG_ALERT, "WindowsFileDialog: can't use pattern on Windows:" << ext);
+ continue;
+ }
+ extensions += "("+ext+")\0"+ext+"\0";
+ extensionsLen += ext.size()*2+4;
+ }
+ opf.lpstrFilter = (LPCSTR) malloc(extensionsLen);
+ memcpy((void*)opf.lpstrFilter, (void*)extensions.data(), extensionsLen);
+ }
+
+ opf.lpstrInitialDir = const_cast<char *>(_initialPath.c_str());
+
+ if (_showHidden) {
+ opf.Flags = OFN_PATHMUSTEXIST;
+ }
+
+ if (_usage == USE_SAVE_FILE) {
+ if (GetSaveFileNameA(&opf)) {
+ std::string stringPath(opf.lpstrFile);
+ _callback->onFileDialogDone(this, stringPath);
+ }
+ } else if (_usage == USE_CHOOSE_DIR) {
+ chooseDir();
+ } else {
+ if (GetOpenFileNameA(&opf)) {
+ std::string stringPath(opf.lpstrFile);
+ _callback->onFileDialogDone(this, stringPath);
+ }
+ }
+}
+
+void WindowsFileDialog::close()
+{
+
+}
+
+void WindowsFileDialog::chooseDir()
+{
+ // MSDN says this needs to be called first
+ OleInitialize(NULL);
+
+ char pathBuf[MAX_PATH] = "\0";
+
+ BROWSEINFO binfo;
+ memset(&binfo, 0, sizeof(BROWSEINFO));
+ binfo.hwndOwner = getMainViewerHWND();
+ binfo.ulFlags = BIF_USENEWUI | BIF_RETURNONLYFSDIRS | BIF_EDITBOX;
+
+ binfo.pidlRoot = NULL; // can browse anywhere
+ binfo.lpszTitle = const_cast<char *>(_title.c_str());
+ binfo.lpfn = BrowseFolderCallback;
+ binfo.lParam = reinterpret_cast<LPARAM>(this);
+
+ PIDLIST_ABSOLUTE results = SHBrowseForFolder(&binfo);
+ if (results == NULL) {
+ // user cancelled
+ return;
+ }
+
+ SHGetPathFromIDList(results, pathBuf);
+ CoTaskMemFree(results);
+
+ _callback->onFileDialogDone(this, SGPath(pathBuf));
+}
\ No newline at end of file
--- /dev/null
+// WindowsFileDialog.hxx - file dialog implemented using Windows
+
+#ifndef FG_WINDOWS_FILE_DIALOG_HXX
+#define FG_WINDOWS_FILE_DIALOG_HXX 1
+
+#include <GUI/FileDialog.hxx>
+
+class WindowsFileDialog : public FGFileDialog
+{
+public:
+ WindowsFileDialog(FGFileDialog::Usage use);
+
+ virtual ~WindowsFileDialog();
+
+ virtual void exec();
+ virtual void close();
+private:
+ void chooseDir();
+
+};
+
+#endif // FG_WINDOWS_FILE_DIALOG_HXX
#include "FGCocoaMenuBar.hxx"
#endif
+#if defined(SG_WINDOWS)
+#include "FGWindowsMenuBar.hxx"
+#endif
+
#include "FGPUIDialog.hxx"
#include "FGFontCache.hxx"
#include "FGColor.hxx"
if (fgGetBool("/sim/menubar/native", true)) {
_menubar.reset(new FGCocoaMenuBar);
}
+#endif
+#if defined(SG_WINDOWS)
+ if (fgGetBool("/sim/menubar/native", true)) {
+ // Windows-native menubar disabled for the moment, fall-through
+ // to PUI version
+ // _menubar.reset(new FGWindowsMenuBar);
+ }
#endif
if (!_menubar.get()) {
_menubar.reset(new FGPUIMenuBar);