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:
parent
b9353144a5
commit
1b585fa415
7 changed files with 477 additions and 6 deletions
|
@ -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)
|
||||
|
|
220
src/GUI/FGWindowsMenuBar.cxx
Normal file
220
src/GUI/FGWindowsMenuBar.cxx
Normal 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
|
64
src/GUI/FGWindowsMenuBar.hxx
Normal file
64
src/GUI/FGWindowsMenuBar.hxx
Normal 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
|
|
@ -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
|
||||
|
|
146
src/GUI/WindowsFileDialog.cxx
Normal file
146
src/GUI/WindowsFileDialog.cxx
Normal 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));
|
||||
}
|
22
src/GUI/WindowsFileDialog.hxx
Normal file
22
src/GUI/WindowsFileDialog.hxx
Normal 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
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue