1
0
Fork 0

Windows native file-dialog, menu-bar

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.
This commit is contained in:
James Turner 2014-01-20 18:43:02 +00:00
parent b9353144a5
commit 1b585fa415
7 changed files with 477 additions and 6 deletions

View 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)

View file

@ -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

View file

@ -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

View file

@ -35,10 +35,14 @@
#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

View file

@ -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));
}

View file

@ -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

View file

@ -33,6 +33,10 @@
#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);