]> git.mxchange.org Git - flightgear.git/blob - src/GUI/new_gui.cxx
GUI windows are now draggable. This missing feature has annoyed me
[flightgear.git] / src / GUI / new_gui.cxx
1 // new_gui.cxx: implementation of XML-configurable GUI support.
2
3 #include "new_gui.hxx"
4
5 #include <plib/pu.h>
6 #include <plib/ul.h>
7
8 #include <simgear/compiler.h>
9 #include <simgear/structure/exception.hxx>
10
11 #include <Main/fg_props.hxx>
12
13 #include "menubar.hxx"
14 #include "dialog.hxx"
15
16 SG_USING_STD(map);
17
18 \f
19 ////////////////////////////////////////////////////////////////////////
20 // Implementation of NewGUI.
21 ////////////////////////////////////////////////////////////////////////
22
23
24 NewGUI::NewGUI ()
25     : _menubar(new FGMenuBar),
26       _active_dialog(0)
27 {
28 }
29
30 NewGUI::~NewGUI ()
31 {
32     clear();
33 }
34
35 void
36 NewGUI::init ()
37 {
38     char path1[1024];
39     char path2[1024];
40     ulMakePath(path1, globals->get_fg_root().c_str(), "gui");
41     ulMakePath(path2, path1, "dialogs");
42     readDir(path2);
43     _menubar->init();
44 }
45
46 void
47 NewGUI::reinit ()
48 {
49     unbind();
50     clear();
51     _menubar = new FGMenuBar;
52     init();
53     bind();
54 }
55
56 void
57 NewGUI::bind ()
58 {
59     fgTie("/sim/menubar/visibility", this,
60           &NewGUI::getMenuBarVisible, &NewGUI::setMenuBarVisible);
61 }
62
63 void
64 NewGUI::unbind ()
65 {
66     fgUntie("/sim/menubar/visibility");
67 }
68
69 void
70 NewGUI::update (double delta_time_sec)
71 {
72     // NO OP
73 }
74
75 bool
76 NewGUI::showDialog (const string &name)
77 {
78     if (_dialog_props.find(name) == _dialog_props.end()) {
79         SG_LOG(SG_GENERAL, SG_ALERT, "Dialog " << name << " not defined");
80         return false;
81     } else {
82         if(!_active_dialogs[name])
83             _active_dialogs[name] = new FGDialog(_dialog_props[name]);
84         return true;
85     }
86 }
87
88 bool
89 NewGUI::closeActiveDialog ()
90 {
91     if (_active_dialog == 0)
92         return false;
93
94     // Kill any entries in _active_dialogs...  Is there an STL
95     // algorithm to do (delete map entries by value, not key)?  I hate
96     // the STL :) -Andy
97     map<string,FGDialog *>::iterator iter = _active_dialogs.begin();
98     for(/**/; iter != _active_dialogs.end(); iter++) {
99         if(iter->second == _active_dialog) {
100             _active_dialogs.erase(iter);
101             // iter is no longer valid
102             break;
103         }
104     }
105
106     delete _active_dialog;
107     _active_dialog = 0;
108     return true;
109 }
110
111 bool
112 NewGUI::closeDialog (const string& name)
113 {
114     if(_active_dialogs.find(name) != _active_dialogs.end()) {
115         if(_active_dialog == _active_dialogs[name])
116             _active_dialog = 0;
117         delete _active_dialogs[name];
118         _active_dialogs.erase(name);
119         return true;
120     }
121     return false; // dialog wasn't open...
122 }
123
124 void
125 NewGUI::setActiveDialog (FGDialog * dialog)
126 {
127     _active_dialog = dialog;
128 }
129
130 FGDialog *
131 NewGUI::getActiveDialog ()
132 {
133     return _active_dialog;
134 }
135
136 FGMenuBar *
137 NewGUI::getMenuBar ()
138 {
139     return _menubar;
140 }
141
142 bool
143 NewGUI::getMenuBarVisible () const
144 {
145     return _menubar->isVisible();
146 }
147
148 void
149 NewGUI::setMenuBarVisible (bool visible)
150 {
151     if (visible)
152         _menubar->show();
153     else
154         _menubar->hide();
155 }
156
157 void
158 NewGUI::clear ()
159 {
160     delete _menubar;
161     _menubar = 0;
162     _dialog_props.clear();
163 }
164
165 static bool
166 test_extension (const char * path, const char * ext)
167 {
168     int pathlen = strlen(path);
169     int extlen = strlen(ext);
170     
171     for (int i = 1; i <= pathlen && i <= extlen; i++) {
172         if (path[pathlen-i] != ext[extlen-i])
173             return false;
174     }
175     return true;
176 }
177
178 void
179 NewGUI::newDialog (SGPropertyNode* props)
180 {
181     const char* cname = props->getStringValue("name");
182     if(!cname) {
183         SG_LOG(SG_GENERAL, SG_ALERT, "New dialog has no <name> property");
184         return;
185     }
186     string name = props->getStringValue("name");
187     _dialog_props[name] = props;
188 }
189
190 void
191 NewGUI::readDir (const char * path)
192 {
193     ulDir * dir = ulOpenDir(path);
194
195     if (dir == 0) {
196         SG_LOG(SG_GENERAL, SG_ALERT, "Failed to read GUI files from "
197                << path);
198         return;
199     }
200
201     for (ulDirEnt * dirEnt = ulReadDir(dir);
202          dirEnt != 0;
203          dirEnt = ulReadDir(dir)) {
204
205         char subpath[1024];
206
207         ulMakePath(subpath, path, dirEnt->d_name);
208
209         if (!dirEnt->d_isdir && test_extension(subpath, ".xml")) {
210             SGPropertyNode * props = new SGPropertyNode;
211             try {
212                 readProperties(subpath, props);
213             } catch (const sg_exception &) {
214                 SG_LOG(SG_INPUT, SG_ALERT, "Error parsing dialog "
215                        << subpath);
216                 delete props;
217                 continue;
218             }
219             if (!props->hasValue("name")) {
220                 SG_LOG(SG_INPUT, SG_WARN, "dialog " << subpath
221                    << " has no name; skipping.");
222                 delete props;
223                 continue;
224             }
225             newDialog(props);
226         }
227     }
228     ulCloseDir(dir);
229 }
230
231 // end of new_gui.cxx