]> git.mxchange.org Git - flightgear.git/commitdiff
Windows native file-dialog, menu-bar
authorJames Turner <zakalawe@mac.com>
Mon, 20 Jan 2014 18:43:02 +0000 (18:43 +0000)
committerJames Turner <zakalawe@mac.com>
Mon, 20 Jan 2014 18:43:02 +0000 (18:43 +0000)
By Gijs with additions by James. Menubar is disabled at present
since it's not usable and potentially inferior to other solutions,
but committing the code so it doesn't rot.

src/GUI/CMakeLists.txt
src/GUI/FGWindowsMenuBar.cxx [new file with mode: 0644]
src/GUI/FGWindowsMenuBar.hxx [new file with mode: 0644]
src/GUI/FileDialog.cxx
src/GUI/WindowsFileDialog.cxx [new file with mode: 0644]
src/GUI/WindowsFileDialog.hxx [new file with mode: 0644]
src/GUI/new_gui.cxx

index 239faf28477e247d27e895e86127bea9256e2ae9..e51a32679bf7f7fc0861271c2f0efcf2ad42d29c 100644 (file)
@@ -46,10 +46,12 @@ set(HEADERS
        )
 
 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)
diff --git a/src/GUI/FGWindowsMenuBar.cxx b/src/GUI/FGWindowsMenuBar.cxx
new file mode 100644 (file)
index 0000000..212e26b
--- /dev/null
@@ -0,0 +1,220 @@
+#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
diff --git a/src/GUI/FGWindowsMenuBar.hxx b/src/GUI/FGWindowsMenuBar.hxx
new file mode 100644 (file)
index 0000000..de9deb9
--- /dev/null
@@ -0,0 +1,64 @@
+// 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
index 200b156902a83e095a76bc7df29fddf6f672ce8d..f7dfcc116cef8c1691407087bee87847ac8c2d68 100644 (file)
 #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)
@@ -142,8 +146,10 @@ static naRef f_createFileDialog(naContext c, naRef me, int argc, naRef* args)
     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
diff --git a/src/GUI/WindowsFileDialog.cxx b/src/GUI/WindowsFileDialog.cxx
new file mode 100644 (file)
index 0000000..b082efa
--- /dev/null
@@ -0,0 +1,146 @@
+
+
+#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
diff --git a/src/GUI/WindowsFileDialog.hxx b/src/GUI/WindowsFileDialog.hxx
new file mode 100644 (file)
index 0000000..0af0d4b
--- /dev/null
@@ -0,0 +1,22 @@
+// 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
index d679c44c94e5037912c86afa7b12851f7a374cf3..66f4a115a10c244fb68856736b68230fa6f1fffb 100644 (file)
 #include "FGCocoaMenuBar.hxx"
 #endif
 
+#if defined(SG_WINDOWS)
+#include "FGWindowsMenuBar.hxx"
+#endif
+
 #include "FGPUIDialog.hxx"
 #include "FGFontCache.hxx"
 #include "FGColor.hxx"
@@ -109,6 +113,13 @@ NewGUI::createMenuBarImplementation()
     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);