2 * @file GenericPluginUI.cpp
3 * Implements the GenericPluginUI class.
8 * Copyright 2012 Joel Baxter
10 * This file is part of MeshTex.
12 * MeshTex is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, either version 2 of the License, or
15 * (at your option) any later version.
17 * MeshTex is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with MeshTex. If not, see <http://www.gnu.org/licenses/>.
28 #include "GenericPluginUI.h"
32 * Default constructor. Initialize object state; the initial callback ID to
33 * use is 1 because 0 is reserved for "invalid". Note that as this is a
34 * protected method, GenericPluginUI objects cannot be created directly; only
35 * subclasses of GenericPluginUI can be created.
37 GenericPluginUI::GenericPluginUI() :
41 _widgetControlCallback(*this)
46 * Virtual destructor. Remove references to UI elements (which should
47 * trigger garbage collection).
49 GenericPluginUI::~GenericPluginUI()
51 // Remove any reference to the menu object.
52 if (_mainMenu != NULL)
56 // The _dialogMap will also be deleted by the normal destructor operation,
57 // which will clear any references we hold on dialog windows.
61 * Register the command menu.
63 * @param mainMenu The command menu.
66 GenericPluginUI::RegisterMainMenu(SmartPointer<GenericMainMenu>& mainMenu)
68 // Remember the menu object, and hold a reference on it so it won't be
69 // garbage-collected while this object exists.
70 _mainMenu = new SmartPointer<GenericMainMenu>(mainMenu);
74 * Register a dialog window.
76 * @param dialog The dialog.
79 GenericPluginUI::RegisterDialog(SmartPointer<GenericDialog>& dialog)
81 // Remember the association between key and dialog, and hold a reference
82 // on it so it won't be garbage-collected while this object exists.
83 _dialogMap.insert(std::make_pair(dialog->GetKey(), dialog));
87 * Specify the main application window.
89 * @param window The main window.
92 GenericPluginUI::SetWindow(GtkWidget *window)
96 // Set it as the parent for every dialog window.
97 DialogMap::const_iterator dialogMapIter = _dialogMap.begin();
98 for (; dialogMapIter != _dialogMap.end(); ++dialogMapIter)
100 if (dialogMapIter->second.get() != NULL)
102 dialogMapIter->second->SetWindow(window);
108 * Get the command menu.
110 * @return The command menu, or NULL if none has been registered.
113 GenericPluginUI::MainMenu()
115 if (_mainMenu == NULL)
119 return _mainMenu->get();
123 * Get the dialog identified by the specified key.
125 * @param key The key.
127 * @return The dialog, or NULL if none found for that key.
130 GenericPluginUI::Dialog(const std::string& key)
132 DialogMap::const_iterator dialogMapIter = _dialogMap.find(key);
133 if (dialogMapIter == _dialogMap.end())
137 return dialogMapIter->second;
141 * Generic event callback used to invoke the specific callback functions
142 * registered with this manager. Those specific callbacks are not themselves
143 * registered directly with GTK+ because they may be methods that must be
144 * invoked on objects. (Unlike this function, which is a static method.)
146 * @param widget The widget generating the event.
147 * @param event The event.
148 * @param data ID of the specific callback registered with this manager.
150 * @return The return value from the specific callback.
153 GenericPluginUI::DialogEventCallbackDispatch(GtkWidget *widget,
157 // Look up the callback ID in our registration map.
158 DialogEventCallbackMap::iterator dialogEventCallbackMapIter =
159 UIInstance()._dialogEventCallbackMap.find(data);
160 if (dialogEventCallbackMapIter == UIInstance()._dialogEventCallbackMap.end())
162 // If we didn't find it, nothing to do.
165 // Otherwise invoke that callback.
166 return dialogEventCallbackMapIter->second(widget, event, data);
170 * Generic signal callback used to invoke the specific callback functions
171 * registered with this manager. Those specific callbacks are not themselves
172 * registered directly with GTK+ because they may be methods that must be
173 * invoked on objects. (Unlike this function, which is a static method.)
175 * @param widget The widget generating the signal.
176 * @param data ID of the specific callback registered with this manager.
179 GenericPluginUI::DialogSignalCallbackDispatch(GtkWidget *widget,
182 // Look up the callback ID in our registration map.
183 DialogSignalCallbackMap::iterator dialogSignalCallbackMapIter =
184 UIInstance()._dialogSignalCallbackMap.find(data);
185 if (dialogSignalCallbackMapIter == UIInstance()._dialogSignalCallbackMap.end())
187 // If we didn't find it, nothing to do.
190 // Otherwise invoke that callback.
191 dialogSignalCallbackMapIter->second(widget, data);
195 * Register a function to be invoked when a widget generates an event.
197 * @param widget The widget generating the event.
198 * @param name The name of the event.
199 * @param callback The callback function.
201 * @return The unique ID for the registered callback function.
204 GenericPluginUI::RegisterDialogEventCallback(GtkWidget *widget,
206 const DialogEventCallback& callback)
208 // Get the next callback ID to use.
209 gpointer callbackID = GUINT_TO_POINTER(_callbackID++);
210 // Make that event on that dialog widget trigger our event dispatch.
211 g_signal_connect(G_OBJECT(widget), name,
212 G_CALLBACK(DialogEventCallbackDispatch), callbackID);
213 // Save the association between callback ID and function.
214 _dialogEventCallbackMap.insert(std::make_pair(callbackID, callback));
215 // Return the generated unique callback ID.
220 * Register a function to be invoked when a widget generates a signal.
222 * @param widget The widget generating the signal.
223 * @param name The name of the signal.
224 * @param callback The callback function.
226 * @return The unique ID for the registered callback function.
229 GenericPluginUI::RegisterDialogSignalCallback(GtkWidget *widget,
231 const DialogSignalCallback& callback)
233 // Get the next callback ID to use.
234 gpointer callbackID = GUINT_TO_POINTER(_callbackID++);
235 // Make that signal on that dialog widget trigger our signal dispatch.
236 g_signal_connect(G_OBJECT(widget), name,
237 G_CALLBACK(DialogSignalCallbackDispatch), callbackID);
238 // Save the association between callback ID and function.
239 _dialogSignalCallbackMap.insert(std::make_pair(callbackID, callback));
240 // Return the generated unique callback ID.
245 * Declare that the controllee widget should be inactive when the
246 * controller widget is inactive. The controllee will be active only
247 * when all of its controllers allow it to be so.
249 * @param controller The controller widget.
250 * @param controllee The controllee widget.
253 GenericPluginUI::RegisterWidgetDependence(GtkWidget *controller,
254 GtkWidget *controllee)
256 // Make sure we get a callback when the controller is toggled.
257 if (_widgetControlMap.find(controller) == _widgetControlMap.end())
259 RegisterDialogSignalCallback(controller, "clicked", _widgetControlCallback);
261 // Save the association.
262 _widgetControlMap[controller].push_back(controllee);
263 _widgetControlledByMap[controllee].push_back(controller);
267 * Declare that the controllee widget should be inactive when the
268 * controller widget is active. The controllee will be active only
269 * when all of its controllers allow it to be so.
271 * @param controller The controller widget.
272 * @param controllee The controllee widget.
275 GenericPluginUI::RegisterWidgetAntiDependence(GtkWidget *controller,
276 GtkWidget *controllee)
278 // Make sure we get a callback when the controller is toggled.
279 if (_widgetControlMap.find(controller) == _widgetControlMap.end())
281 RegisterDialogSignalCallback(controller, "clicked", _widgetControlCallback);
283 // Save the association.
284 _widgetControlMap[controller].push_back(controllee);
285 _widgetAntiControlledByMap[controllee].push_back(controller);
289 * Manage the state of controllee widgets when a controller widget is clicked.
291 * @param widget The controller widget.
292 * @param callbackID Unique numerical ID for the callback.
295 GenericPluginUI::WidgetControlCallback(GtkWidget *widget,
298 // Iterate over all controllees registered for this widget.
299 std::vector<GtkWidget *>::iterator controlleeIter =
300 _widgetControlMap[widget].begin();
301 for (; controlleeIter != _widgetControlMap[widget].end(); ++controlleeIter)
303 GtkWidget *controllee = *controlleeIter;
304 std::vector<GtkWidget *>::iterator controllerIter;
305 // Start with an assumption that the controllee widget will be active.
306 bool sensitive = true;
307 // Look for a dependence on any widget.
308 controllerIter = _widgetControlledByMap[controllee].begin();
309 for (; controllerIter != _widgetControlledByMap[controllee].end(); ++controllerIter)
311 // Dependence found; honor it.
312 if (!(GTK_TOGGLE_BUTTON(*controllerIter)->active))
318 // Look for an anti-dependence on any widget.
319 controllerIter = _widgetAntiControlledByMap[controllee].begin();
320 for (; controllerIter != _widgetAntiControlledByMap[controllee].end(); ++controllerIter)
322 // Anti-dependence found; honor it.
323 if (GTK_TOGGLE_BUTTON(*controllerIter)->active)
329 // Set the active state of the controllee appropriately.
330 gtk_widget_set_sensitive(controllee, sensitive);
335 * Generate an error dialog.
337 * @param title The dialog title.
338 * @param message The error message.
341 GenericPluginUI::ErrorReportDialog(const char *title,
344 // Pass this operation to Radiant.
345 GlobalRadiant().m_pfnMessageBox(UIInstance()._window, message, title, eMB_OK, eMB_ICONERROR);
349 * Generate a warning dialog.
351 * @param title The dialog title.
352 * @param message The warning message.
355 GenericPluginUI::WarningReportDialog(const char *title,
358 // Pass this operation to Radiant.
359 GlobalRadiant().m_pfnMessageBox(UIInstance()._window, message, title, eMB_OK, eMB_ICONWARNING);
363 * Generate an info dialog.
365 * @param title The dialog title.
366 * @param message The info message.
369 GenericPluginUI::InfoReportDialog(const char *title,
372 // Pass this operation to Radiant.
373 GlobalRadiant().m_pfnMessageBox(UIInstance()._window, message, title, eMB_OK, eMB_ICONDEFAULT);