21#include <simgear/compiler.h>
22#include <simgear/debug/ErrorReportingCallback.hxx>
23#include <simgear/misc/sg_dir.hxx>
24#include <simgear/props/props_io.hxx>
25#include <simgear/structure/exception.hxx>
36#if defined(SG_WINDOWS)
53NewGUI::DialogMetadata::DialogMetadata(
const SGPath& xmlFilePath,
54 const std::string& translationDomain)
55 : xmlFilePath(xmlFilePath),
56 translationDomain(translationDomain)
70 for (_itt_t it = _colors.begin(); it != _colors.end(); ++it)
77static void findAllLeafValues(SGPropertyNode* node,
const std::string& leaf, std::vector<std::string>& out)
79 string name = node->getNameString();
81 out.push_back(node->getStringValue());
83 for (
int i=0;
i<node->nChildren(); ++
i) {
94 SGPropertyNode* menubar =
globals->get_props()->getNode(
"sim/menubar/default");
100 for (
int menu_p=0; menu_p<menubar->nChildren(); ++menu_p) {
101 SGPropertyNode* menu = menubar->getChild(menu_p);
102 if (menu->getNameString() !=
"menu")
continue;
103 for (
int item_p=0; item_p<menu->nChildren(); ++item_p) {
104 SGPropertyNode* item = menu->getChild(item_p);
105 if (item->getNameString() !=
"item")
continue;
106 std::vector<std::string> dialog_names;
108 for (
auto dialog_name: dialog_names) {
109 highlight->addMenuDialog(
HighlightMenu(menu->getIndex(), item->getIndex()), dialog_name);
118 createMenuBarImplementation();
119 fgTie(
"/sim/menubar/visibility",
this,
122 fgTie(
"/sim/menubar/overlap-hide",
this,
126 SGPath
p(
globals->get_fg_root(),
"gui/dialogs");
129 if (
fgGetBool(
"/sim/gui/startup") ==
false) {
130 SGPath aircraftDialogDir(
fgGetString(
"/sim/aircraft-dir"),
"gui/dialogs");
131 if (aircraftDialogDir.exists()) {
132 readDir(aircraftDialogDir,
"current-aircraft");
138 for (
const auto& addon : addonManager->registeredAddons()) {
139 SGPath addonDialogDir = addon->getBasePath() /
"gui/dialogs";
141 if (addonDialogDir.exists()) {
142 readDir(addonDialogDir,
"addons/" + addon->getId());
150 fgGetNode(
"sim/menubar")->setAttribute(SGPropertyNode::PRESERVE,
true);
159 _active_dialogs.clear();
160 _active_dialog.clear();
162 fgUntie(
"/sim/menubar/visibility");
163 fgUntie(
"/sim/menubar/overlap-hide");
165 _dialog_props.clear();
172 fgSetBool(
"/sim/signals/reinit-gui",
true);
182NewGUI::createMenuBarImplementation()
184 if (!
fgGetBool(
"/sim/menubar/enable",
true)) {
185 SG_LOG(SG_GUI, SG_INFO,
"Menubar is disabled");
190 if (
fgGetBool(
"/sim/menubar/native",
true)) {
191 _menubar.reset(
new FGCocoaMenuBar);
194#if defined(SG_WINDOWS)
195 if (
fgGetBool(
"/sim/menubar/native",
false)) {
196 _menubar.reset(
new FGWindowsMenuBar);
199 if (!_menubar.get()) {
200 _menubar.reset(
new FGNasalMenuBar);
204void NewGUI::setDialogMetadata(
const string&
name,
const SGPath& xmlFilepath,
205 const string& domain)
207 _dialog_metadata.erase(
name);
208 _dialog_metadata.emplace(
name, DialogMetadata(xmlFilepath, domain));
214 DialogDict::iterator iter;
217 for (iter = _active_dialogs.begin(); iter != _active_dialogs.end(); ++iter)
218 openDialogs.push_back(iter->first);
220 for (
auto d : openDialogs)
228 _dialog_props.clear();
229 _dialog_metadata.clear();
232 createMenuBarImplementation();
241 for (
auto d : openDialogs)
259 nasal::Hash guiModule{nas->getModule(
"gui"), ctx};
260 nasal::Hash compatModule = guiModule.createHash(
"xml");
267 _menubar->postinit();
274 SG_UNUSED(delta_time_sec);
275 auto iter = _active_dialogs.begin();
276 for(; iter != _active_dialogs.end(); iter++)
277 iter->second->update();
284 SG_LOG(SG_GENERAL, SG_ALERT,
"showDialog: no dialog name provided");
289 if (_active_dialogs.find(
name) != _active_dialogs.end()){
290 _active_dialogs[
name]->bringToFront();
295 const auto metadataIt = _dialog_metadata.find(
name);
296 if (metadataIt == _dialog_metadata.end()) {
297 simgear::reportFailure(simgear::LoadFailure::NotFound,
298 simgear::ErrorCode::GUIDialog,
299 "Metadata not found for dialog '" +
name +
"'");
308 _active_dialogs[
name] = pcd;
317 }
catch (sg_exception& e) {
318 simgear::reportFailure(simgear::LoadFailure::Misconfigured, simgear::ErrorCode::GUIDialog,
"Dialog failed to show:" +
name +
":" + e.getFormattedMessage(), e.getLocation());
326 if (_active_dialogs.find(
name) == _active_dialogs.end()) {
339 if (_active_dialog == 0)
350 auto iter = _active_dialogs.begin();
351 for(; iter != _active_dialogs.end(); iter++) {
352 if(iter->second == _active_dialog) {
353 _active_dialog->close();
355 _active_dialogs.erase(iter);
362 if (!_active_dialogs.empty()) {
363 fgSetString(
"/sim/gui/dialogs/current-dialog", _active_dialogs.begin()->second->getName());
371 if(_active_dialogs.find(
name) != _active_dialogs.end()) {
374 if(_active_dialog == _active_dialogs[
name])
375 _active_dialog.clear();
377 _active_dialogs.erase(
name);
386 const auto metadataIt = _dialog_metadata.find(
name);
388 if (metadataIt == _dialog_metadata.end()) {
389 SG_LOG(SG_GENERAL, SG_ALERT,
"Dialog '" <<
name <<
"' not defined");
393 NameDialogDict::iterator it = _dialog_props.find(
name);
394 if (it == _dialog_props.end()) {
396 const SGPath path = metadataIt->second.xmlFilePath;
397 SGPropertyNode_ptr props =
new SGPropertyNode;
400 readProperties(path, props);
401 }
catch (
const sg_exception &) {
402 SG_LOG(SG_INPUT, SG_ALERT,
"Error parsing dialog from " << path);
406 it = _dialog_props.insert(it, std::make_pair(
name, props));
415 if(_active_dialogs.find(
name) != _active_dialogs.end())
416 return _active_dialogs[
name];
418 SG_LOG(SG_GENERAL, SG_DEBUG,
"dialog '" <<
name <<
"' missing");
428 _active_dialog = dialog;
434 return _active_dialog;
440 return _menubar.get();
447 return _menubar->isVisible();
474 _menubar->setHideIfOverlapsWindow(hide);
481 string name = props->getStringValue(
"name",
"");
483 SG_LOG(SG_GENERAL, SG_ALERT,
"New dialog has no <name> property");
487 if(_active_dialogs.find(
name) == _active_dialogs.end()) {
488 _dialog_props[
name] = props;
491 setDialogMetadata(
name, SGPath());
497NewGUI::readDir (
const SGPath& path,
const std::string& translationDomain)
499 simgear::Dir dir(path);
502 SG_LOG(SG_INPUT, SG_INFO,
"directory does not exist: " << path);
508 auto highlight =
globals->get_subsystem<Highlight>();
509 for (SGPath xmlPath : dir.children(simgear::Dir::TYPE_FILE,
".xml")) {
511 SGPropertyNode_ptr props =
new SGPropertyNode;
512 SGPropertyNode *nameprop =
nullptr;
519 readProperties(xmlPath, props);
520 }
catch (
const sg_exception &) {
521 SG_LOG(SG_INPUT, SG_ALERT,
"Error parsing dialog " << xmlPath);
525 nameprop = props->getNode(
"name");
527 name = nameprop->getStringValue();
531 std::vector<std::string> property_paths;
533 for (
auto property_path: property_paths) {
538 highlight->addPropertyDialog(property_path,
name);
548 setDialogMetadata(
name, xmlPath, translationDomain);
554 SG_LOG(SG_INPUT, SG_ALERT,
"Error parsing dialog " << xmlPath);
559 SG_LOG(SG_INPUT, SG_WARN,
"dialog " << xmlPath <<
" has no name; skipping.");
563 setDialogMetadata(
name, xmlPath, translationDomain);
582 for (it = _colors.begin(); it != _colors.end(); ++it)
587 _colors[
"background"] =
new FGColor(0.8f, 0.8f, 0.9f, 0.85f);
588 _colors[
"foreground"] =
new FGColor(0.0f, 0.0f, 0.0f, 1.0f);
589 _colors[
"highlight"] =
new FGColor(0.7f, 0.7f, 0.7f, 1.0f);
590 _colors[
"label"] =
new FGColor(0.0f, 0.0f, 0.0f, 1.0f);
591 _colors[
"legend"] =
new FGColor(0.0f, 0.0f, 0.0f, 1.0f);
592 _colors[
"misc"] =
new FGColor(0.0f, 0.0f, 0.0f, 1.0f);
593 _colors[
"inputfield"] =
new FGColor(0.8f, 0.7f, 0.7f, 1.0f);
601 SGPath
p(
globals->get_fg_root(),
"gui/styles");
602 SGPropertyNode* sim_gui =
globals->get_props()->getNode(
"sim/gui/",
true);
605 for (SGPath xml: dir.children(simgear::Dir::TYPE_FILE,
".xml")) {
606 SGPropertyNode_ptr node = sim_gui->getChild(
"style",
i,
true);
607 node->removeAllChildren();
608 SG_LOG(SG_GENERAL, SG_WARN,
"reading from " << xml <<
" into " << node->getPath());
609 readProperties(xml, node);
614 int which =
fgGetInt(
"/sim/gui/current-style", 0);
615 SGPropertyNode *sim =
globals->get_props()->getNode(
"sim/gui",
true);
616 SGPropertyNode *n = sim->getChild(
"style", which);
618 n = sim->getChild(
"style", 0,
true);
620 SGPropertyNode *selected_style =
globals->get_props()->getNode(
"sim/gui/selected-style",
true);
624 selected_style->removeAllChildren();
625 copyProperties(n, selected_style);
631 n = n->getNode(
"colors",
true);
633 for (
int i = 0;
i < n->nChildren();
i++) {
634 SGPropertyNode *child = n->getChild(
i);
635 _colors[child->getNameString()] =
new FGColor(child);
642 SGSubsystemMgr::INIT);
An XML-configured dialog box.
virtual const char * getName()
An XML-configured dialog box.
static void setupGhost(nasal::Hash &compatModule)
virtual SGPropertyNode_ptr getDialogProperties(const std::string &name)
Get dialog property tree's root node.
virtual bool closeDialog(const std::string &name)
Close a named dialog, if it is open.
SGSharedPtr< FGDialog > FGDialogRef
virtual void setMenuBarVisible(bool visible)
Show or hide the menubar.
void setMenuBarOverlapHide(bool hide)
virtual FGDialogRef getActiveDialog()
Get the dialog currently active, if any.
virtual void reset(bool reload)
Used by reinit() and redraw() to close all dialogs and to apply current GUI colors.
void update(double delta_time_sec) override
virtual bool showDialog(const std::string &name)
Display a dialog box.
virtual bool toggleDialog(const std::string &name)
Toggle display of a dialog box.
virtual void redraw()
Redraw the GUI picking up new GUI colors.
virtual FGMenuBar * getMenuBar()
Return a pointer to the current menubar.
virtual bool getMenuBarVisible() const
Test if the menubar is visible.
virtual ~NewGUI()
Destructor.
virtual void setActiveDialog(FGDialog *dialog)
Ignore this method.
virtual bool closeActiveDialog()
Close the currenty active dialog.
bool getMenuBarOverlapHide() const
virtual void newDialog(SGPropertyNode *node)
Creates a new dialog box, using the same property format as the gui/dialogs configuration files.
virtual FGDialogRef getDialog(const std::string &name)
Get the named dialog if active.
static void setupGhost(nasal::Hash &guiModule)
void stampCacheFile(const SGPath &path, const std::string &sha={})
void writeStringProperty(const std::string &key, const std::string &value)
std::string readStringProperty(const std::string &key)
static NavDataCache * instance()
bool isCachedFileModified(const SGPath &path) const
static const std::unique_ptr< AddonManager > & instance()
void fgUntie(const char *name)
Untie a property from an external data source.
int fgGetInt(const char *name, int defaultValue)
Get an int value for a property.
std::string fgGetString(const char *name, const char *defaultValue)
Get a string value for a property.
void fgTie(const char *name, V(*getter)(), void(*setter)(V)=0, bool useDefault=true)
Tie a property to a pair of simple functions.
std::vector< std::string > string_list
void addSentryBreadcrumb(const std::string &, const std::string &)
static void findAllLeafValues(SGPropertyNode *node, const std::string &leaf, std::vector< std::string > &out)
SGSubsystemMgr::Registrant< NewGUI > registrantNewGUI(SGSubsystemMgr::INIT)
bool fgGetBool(char const *name, bool def)
Get a bool value for a property.
bool fgSetBool(char const *name, bool val)
Set a bool value for a property.
bool fgSetString(char const *name, char const *str)
Set a string value for a property.
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.