FlightGear next
Highlight.cxx
Go to the documentation of this file.
1#include "Highlight.hxx"
2#include "simgear/misc/strutils.hxx"
3
4#include <Model/acmodel.hxx>
5#include <Main/globals.hxx>
6#include <FDM/fdm_shell.hxx>
7#include <FDM/flight.hxx>
8
9#include <simgear/scene/util/StateAttributeFactory.hxx>
10
11#include <osg/Material>
12#include <osg/PolygonMode>
13#include <osg/PolygonOffset>
14#include <osg/Texture2D>
15
16#include <algorithm>
17#include <map>
18#include <string>
19#include <iterator>
20
21
22/* Returns translated string for specified menu/menuitem name. */
23static std::string s_getMenuName(SGPropertyNode* node)
24{
25 /* We use 'label' if available, otherwise we translate 'name' using
26 sim/intl/locale/... */
27 std::string name = node->getStringValue("label", "");
28 if (name != "") return name;
29 name = node->getStringValue("name");
30 return globals->get_props()->getStringValue("sim/intl/locale/strings/menu/" + name, name.c_str());
31}
32
33std::string HighlightMenu::description() const
34{
35 std::string ret = std::to_string(this->menu) + "/" + std::to_string(this->item) + ": ";
36 SGPropertyNode* menubar = globals->get_props()->getNode("sim/menubar/default");
37 if (menubar)
38 {
39 SGPropertyNode* menu = menubar->getChild("menu", this->menu);
40 if (menu)
41 {
42 SGPropertyNode* item = menu->getChild("item", this->item);
43 if (item)
44 {
45 ret += s_getMenuName(menu) + '/' + s_getMenuName(item);
46 }
47 }
48 }
49 return ret;
50}
51
52static bool operator< (const HighlightMenu& a, const HighlightMenu& b)
53{
54 if (a.menu != b.menu) return a.menu < b.menu;
55 return a.item < b.item;
56}
57
59{
60 NameValue(const std::string& name, const std::string& value)
61 : name(name), value(value)
62 {}
63 std::string name;
64 std::string value;
65 bool operator< (const NameValue& rhs) const
66 {
67 if (name != rhs.name) return name < rhs.name;
68 return value < rhs.value;
69 }
70};
71
72static std::map<std::string, HighlightInfo> s_property_to_info;
73
74static std::map<osg::ref_ptr<osg::Node>, std::set<std::string>> s_node_to_properties;
75static std::map<std::string, std::set<std::string>> s_dialog_to_properties;
76static std::map<std::string, std::set<std::string>> s_keypress_to_properties;
77static std::map<HighlightMenu, std::set<std::string>> s_menu_to_properties;
78
79static std::map<HighlightMenu, std::string> s_menu_to_dialog;
80static std::map<std::string, std::set<HighlightMenu>> s_dialog_to_menus;
81
82static std::map<std::string, std::set<std::string>> s_property_to_properties;
83static std::map<std::string, std::set<std::string>> s_property_from_properties;
84
85static std::set<NameValue> s_property_tree_items;
86
87static SGPropertyNode_ptr s_prop_enabled = nullptr;
88static bool s_output_stats = false;
89
90static std::unique_ptr<struct NodeHighlighting> s_node_highlighting;
91
92std::unique_ptr<struct FdmInitialisedListener> s_fdm_initialised_listener;
93
94
95/* Handles highlighting of individual nodes by changing their StateSet to
96our internal StateSet. Also changes our StateSet's material in response to
97sim/highlighting/material/. */
98struct NodeHighlighting : SGPropertyChangeListener
99{
101 :
102 m_node(globals->get_props()->getNode("sim/highlighting/material", true /*create*/))
103 {
104 /* Create highlight StateSet. Based on
105 simgear/simgear/scene/model/SGPickAnimation.cxx:sharedHighlightStateSet().
106 */
107 m_state_set = new osg::StateSet;
108
109 osg::Texture2D* white = simgear::StateAttributeFactory::instance()->getWhiteTexture();
110 m_state_set->setTextureAttributeAndModes(
111 0,
112 white,
113 osg::StateAttribute::ON
114 | osg::StateAttribute::OVERRIDE
115 | osg::StateAttribute::PROTECTED
116 );
117
118 osg::PolygonOffset* polygonOffset = new osg::PolygonOffset;
119 polygonOffset->setFactor(-1);
120 polygonOffset->setUnits(-1);
121 m_state_set->setAttribute(polygonOffset, osg::StateAttribute::OVERRIDE);
122 m_state_set->setMode(
123 GL_POLYGON_OFFSET_LINE,
124 osg::StateAttribute::ON
125 | osg::StateAttribute::OVERRIDE
126 );
127
128 osg::PolygonMode* polygonMode = new osg::PolygonMode;
129 polygonMode->setMode(
130 osg::PolygonMode::FRONT_AND_BACK,
131 osg::PolygonMode::FILL
132 );
133 m_state_set->setAttribute(polygonMode, osg::StateAttribute::OVERRIDE);
134
135 osg::Material* material = new osg::Material;
136 material->setColorMode(osg::Material::OFF);
137 material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0, 0, 0, 0));
138 material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0, 0, 0, 0));
139 material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(0, 0, 0, 0));
140 material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0, 0, 0, 0));
141 m_state_set->setAttribute(
142 material,
143 osg::StateAttribute::OVERRIDE
144 | osg::StateAttribute::PROTECTED
145 );
146 // The default shader has a colorMode uniform that mimics the
147 // behavior of Material color mode.
148
149 osg::Uniform* colorModeUniform = new osg::Uniform(osg::Uniform::INT, "colorMode");
150 colorModeUniform->set(0); // MODE_OFF
151 colorModeUniform->setDataVariance(osg::Object::STATIC);
152 m_state_set->addUniform(
153 colorModeUniform,
154 osg::StateAttribute::OVERRIDE
155 | osg::StateAttribute::ON
156 );
157
158 /* Initialise highlight material properties to defaults if not already
159 set. */
160 // XXX Alpha < 1.0 in the diffuse material value is a signal to the
161 // default shader to take the alpha value from the material value
162 // and not the glColor. In many cases the pick animation geometry is
163 // transparent, so the outline would not be visible without this hack.
164 setRgbaDefault(m_node, "ambient", 0, 0, 0, 1);
165 setRgbaDefault(m_node, "diffuse", 0.5, 0.5, 0.5, .95);
166 setRgbaDefault(m_node, "emission", 0.75, 0.375, 0, 1);
167 setRgbaDefault(m_node, "specular", 0.0, 0.0, 0.0, 0);
168
169 /* Listen for changes to highlight material properties. */
170 m_node->addChangeListener(this, true /*initial*/);
171 }
172
173 static void setRgbaDefault(SGPropertyNode* root, const std::string& path,
174 double red, double green, double blue, double alpha)
175 {
176 setPropertyDefault(root, path + "/red", red);
177 setPropertyDefault(root, path + "/green", green);
178 setPropertyDefault(root, path + "/blue", blue);
179 setPropertyDefault(root, path + "/alpha", alpha);
180 }
181
182 // Sets property value if property does not exist.
183 static void setPropertyDefault(SGPropertyNode* root, const std::string& path, double default_value)
184 {
185 SGPropertyNode* property = root->getNode(path, false /*create*/);
186 if (!property) root->setDoubleValue(path, default_value);
187 }
188
189 virtual void valueChanged(SGPropertyNode* node)
190 {
191 assert(m_state_set);
192 osg::StateAttribute* material0 = m_state_set->getAttribute(osg::StateAttribute::MATERIAL);
193 osg::Material* material = dynamic_cast<osg::Material*>(material0);
194 assert(material);
195
196 double red;
197 double green;
198 double blue;
199 double alpha;
200
201 red = m_node->getDoubleValue("ambient/red");
202 green = m_node->getDoubleValue("ambient/green");
203 blue = m_node->getDoubleValue("ambient/blue");
204 alpha = m_node->getDoubleValue("ambient/alpha");
205 material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(red, green, blue, alpha));
206
207 red = m_node->getDoubleValue("diffuse/red");
208 green = m_node->getDoubleValue("diffuse/green");
209 blue = m_node->getDoubleValue("diffuse/blue");
210 alpha = m_node->getDoubleValue("diffuse/alpha");
211 material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(red, green, blue, alpha));
212
213 red = m_node->getDoubleValue("emission/red");
214 green = m_node->getDoubleValue("emission/green");
215 blue = m_node->getDoubleValue("emission/blue");
216 alpha = m_node->getDoubleValue("emission/alpha");
217 material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(red, green, blue, alpha));
218
219 red = m_node->getDoubleValue("ambient/red");
220 green = m_node->getDoubleValue("ambient/green");
221 blue = m_node->getDoubleValue("ambient/blue");
222 alpha = m_node->getDoubleValue("ambient/alpha");
223 material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(red, green, blue, alpha));
224
225 red = m_node->getDoubleValue("specular/red");
226 green = m_node->getDoubleValue("specular/green");
227 blue = m_node->getDoubleValue("specular/blue");
228 alpha = m_node->getDoubleValue("specular/alpha");
229 material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(red, green, blue, alpha));
230 }
231
232 /* Highlight/un-highlight the specified node. */
233 int highlight(osg::Node* node, bool highlight)
234 {
235 int ret = 0;
236 osg::Group* group = node->asGroup();
237 if (!group) return 0;
238 auto it_group_stateset = m_group_to_old_state_set.find(group);
239 if (it_group_stateset == m_group_to_old_state_set.end() && highlight)
240 {
241 m_group_to_old_state_set[group] = group->getStateSet();
242 group->setStateSet(m_state_set.get());
243 ret += 1;
244 }
245 if (it_group_stateset != m_group_to_old_state_set.end() && !highlight)
246 {
247 group->setStateSet(it_group_stateset->second);
248 m_group_to_old_state_set.erase(it_group_stateset);
249 ret += 1;
250 }
251 return ret;
252 }
253
254 /* Un-highlight all nodes. */
256 {
257 int ret = 0;
258 for(;;)
259 {
260 if (m_group_to_old_state_set.empty()) break;
261 auto& group_stateset = *m_group_to_old_state_set.begin();
262 highlight(group_stateset.first, false);
263 ret += 1;
264 }
265 return ret;
266 }
267
269 {
270 m_node->removeChangeListener(this);
271 }
272
273 SGPropertyNode_ptr m_node;
274
275 /* We keep track of osg::StateSet's for groups that we have highlighted so
276 that we can turn highlighting off by swapping the original stateset back
277 in. */
278 std::map<osg::ref_ptr<osg::Group>, osg::ref_ptr<osg::StateSet>> m_group_to_old_state_set;
279
280 /* The stateset that we use to highlight nodes. */
281 osg::ref_ptr<osg::StateSet> m_state_set;
282};
283
284
288
292
294{
295 s_property_to_info.clear();
296
297 s_node_to_properties.clear();
300 s_menu_to_properties.clear();
301
302 s_menu_to_dialog.clear();
303 s_dialog_to_menus.clear();
304
306
307 s_property_tree_items.clear();
308 s_prop_enabled.reset();
309}
310
312{
314}
315
316/* Waits until sim/fdm-initialized is true and then gets property associations
317from the FDM using FGInterface::property_associations(). */
318struct FdmInitialisedListener : SGPropertyChangeListener
319{
321 :
322 m_fdm_initialised(globals->get_props()->getNode("sim/fdm-initialized", true /*create*/))
323 {
324 m_fdm_initialised->addChangeListener(this, true /*initial*/);
325 }
326 void valueChanged(SGPropertyNode* node) override
327 {
328 if (m_fdm_initialised->getBoolValue())
329 {
330 SG_LOG(SG_GENERAL, SG_DEBUG, "Getting property associations from FDM");
331 auto highlight = globals->get_subsystem<Highlight>();
332 if (highlight)
333 {
334 auto fdmshell = globals->get_subsystem<FDMShell>();
335 FGInterface* fginterface = fdmshell->getInterface();
336 assert(fginterface);
337 fginterface->property_associations(
338 [highlight](const std::string& from, const std::string& to)
339 {
340 SG_LOG(SG_GENERAL, SG_DEBUG, "fdm property association: " << from << " => " << to);
341 highlight->addPropertyProperty(from, to);
342 }
343 );
344 }
346 }
347 }
349 {
350 m_fdm_initialised->removeChangeListener(this);
351 }
352 SGPropertyNode_ptr m_fdm_initialised;
353};
354
356{
357 s_prop_enabled = globals->get_props()->getNode("sim/highlighting/enabled", true);
358 globals->get_props()->setStringValue("sim/highlighting/current", "");
359 globals->get_props()->setStringValue("sim/highlighting/current-ptr", "/sim/highlighting/current");
360
361 /* Get property associations from FDM when sim/fdm-initialized becomes true. */
363}
364
366{
367}
368
370{
371}
372
373void Highlight::update(double dt)
374{
375}
376
377/* Avoid ambiguities caused by possible use of "[0]" within property paths. */
378static std::string canonical(const std::string property)
379{
380 return simgear::strutils::replace(property, "[0]", "");
381}
382
383
384int Highlight::highlightNodes(osg::Node* node)
385{
386 if (!s_output_stats)
387 {
388 s_output_stats = true;
389 SG_LOG(SG_GENERAL, SG_DEBUG, "Sizes of internal maps:"
390 << " s_property_to_info=" << s_property_to_info.size()
391 << " s_node_to_properties=" << s_node_to_properties.size()
392 << " s_dialog_to_properties=" << s_dialog_to_properties.size()
393 << " s_keypress_to_properties=" << s_keypress_to_properties.size()
394 << " s_menu_to_properties=" << s_menu_to_properties.size()
395 << " s_menu_to_dialog=" << s_menu_to_dialog.size()
396 << " s_dialog_to_menus=" << s_dialog_to_menus.size()
397 << " s_property_to_properties=" << s_property_to_properties.size()
398 << " s_property_from_properties=" << s_property_from_properties.size()
399 << " s_property_tree_items=" << s_property_tree_items.size()
400 );
401 }
402 if (!s_node_highlighting) return 0;
403
404 s_node_highlighting->clearAll();
405
406 int num_props = 0;
407
408 /* We build up a list of name:value items such as:
409
410 'dialog': joystick-config
411 'menu': 0/6: File/Joystick Configuration
412 'property': /controls/flight/rudder
413 'property': /surface-positions/rudder-pos-norm
414
415 These items are written into /sim/highlighting/current/. For items with
416 name='property', we highlight nodes which are animated by the specified
417 property. */
418 std::set<NameValue> items;
419
420 if (s_prop_enabled->getBoolValue())
421 {
422 /* As well as <node> itself, we also highlight other nodes by following
423 a limited part of the tree of property dependencies:
424
425 property3
426 -> property1
427 -> <node>
428 -> other nodes
429 -> property2
430 -> other nodes
431 -> other nodes
432 -> property4
433 -> other nodes
434 */
435 for (auto& property1: Highlight::findNodeProperties(node))
436 {
437 /* <property1> animates <node>. */
438 items.insert(NameValue("property", property1));
439
440 for (auto& property2: Highlight::findPropertyToProperties(property1))
441 {
442 /* <property2> is set by <property1> (which animates <node>). */
443 items.insert(NameValue("property", property2));
444 }
445
446 for (auto& property3: Highlight::findPropertyFromProperties(property1))
447 {
448 /* <property3> sets <property1> (which animates <node>). */
449 items.insert(NameValue("property", property3));
450
451 for (auto& property4: Highlight::findPropertyToProperties(property3))
452 {
453 /* <property4> is set by <property3> (which also
454 sets <property1>, which animates <node>). */
455 items.insert(NameValue("property", property4));
456 }
457 }
458 }
459
460 /* Highlight all nodes animated by properties in <items>, and add
461 nodes, dialogs, menus and keypress info to <items>. */
462 for (auto& nv: items)
463 {
464 const std::string& property = nv.value;
465 SG_LOG(SG_GENERAL, SG_DEBUG, "Looking at property=" << property);
466 const HighlightInfo& info = Highlight::findPropertyInfo(property);
467 for (auto& node: info.nodes)
468 {
469 num_props += s_node_highlighting->highlight(node, true);
470 }
471 for (auto& dialog: info.dialogs)
472 {
473 items.insert(NameValue("dialog", dialog));
474 for (auto& menu: Highlight::findMenuFromDialog(dialog))
475 {
476 items.insert(NameValue("menu", menu.description()));
477 }
478 }
479 for (auto& keypress: info.keypresses)
480 {
481 items.insert(NameValue("keypress", keypress));
482 }
483 for (auto& menu: info.menus)
484 {
485 items.insert(NameValue("menu", menu.description()));
486 }
487 }
488 }
489 else
490 {
491 num_props = -1;
492 }
493
494 if (items.empty())
495 {
496 /* Create dummy item to allow property viewer to be opened on
497 sim/highlighting/current even if it would otherwise be currently empty.
498 */
499 items.insert(NameValue("dummy", ""));
500 }
501
502 /* Update property tree representation of currently-highlighted properties
503 and associated dialogs, keypresses and menus, so that it matches
504 <items>. We do this by calculating what items need adding or removing from
505 the property tree representation */
506 std::set<NameValue> properties_new;
507 std::set<NameValue> properties_removed;
508 std::set_difference(
509 items.begin(), items.end(),
511 std::inserter(properties_new, properties_new.begin())
512 );
513 std::set_difference(
515 items.begin(), items.end(),
516 std::inserter(properties_removed, properties_removed.begin())
517 );
518 SGPropertyNode* current = globals->get_props()->getNode("sim/highlighting/current", true /*create*/);
519 for (int pos=0; pos<current->nChildren(); ++pos)
520 {
521 SGPropertyNode* child = current->getChild(pos);
522 auto nv = NameValue(child->getNameString(), child->getStringValue());
523 if (properties_removed.find(nv) != properties_removed.end())
524 {
525 current->removeChild(pos);
526 pos -= 1;
527 }
528 }
529 for (auto& name_value: properties_new)
530 {
531 current->addChild(name_value.name)->setStringValue(name_value.value);
532 }
533
534 /* Remember the current items for next time. */
535 std::swap(items, s_property_tree_items);
536
537 return num_props;
538}
539
540/* Functions that interrogate our internal data.
541
542
543We use these to avoid adding multiple empty items to our std::maps.
544*/
546static const std::set<std::string> set_string_empty;
547static const std::set<HighlightMenu> set_menu_empty;
548
549const HighlightInfo& Highlight::findPropertyInfo(const std::string& property)
550{
551 std::string property2 = canonical(property);
552 auto it = s_property_to_info.find(property2);
553 if (it == s_property_to_info.end()) return info_empty;
554 return it->second;
555}
556
557const std::set<std::string>& Highlight::findNodeProperties(osg::Node* node)
558{
559 auto it = s_node_to_properties.find(node);
560 if (it == s_node_to_properties.end()) return set_string_empty;
561 return it->second;
562}
563
564const std::set<std::string>& Highlight::findDialogProperties(const std::string& dialog)
565{
566 auto it = s_dialog_to_properties.find(dialog);
567 if (it == s_dialog_to_properties.end()) return set_string_empty;
568 return it->second;
569}
570
571const std::set<std::string>& Highlight::findKeypressProperties(const std::string& keypress)
572{
573 auto it = s_keypress_to_properties.find(keypress);
574 if (it == s_keypress_to_properties.end()) return set_string_empty;
575 return it->second;
576}
577
578const std::set<std::string>& Highlight::findMenuProperties(const HighlightMenu& menu)
579{
580 auto it = s_menu_to_properties.find(menu);
581 if (it == s_menu_to_properties.end()) return set_string_empty;
582 return it->second;
583}
584
585const std::set<std::string>& Highlight::findPropertyToProperties(const std::string& property)
586{
587 std::string property2 = canonical(property);
588 auto it = s_property_to_properties.find(property2);
589 if (it == s_property_to_properties.end()) return set_string_empty;
590 return it->second;
591}
592
593const std::set<std::string>& Highlight::findPropertyFromProperties(const std::string& property)
594{
595 std::string property2 = canonical(property);
596 auto it = s_property_from_properties.find(property2);
597 if (it == s_property_from_properties.end()) return set_string_empty;
598 return it->second;
599}
600
601const std::set<HighlightMenu>& Highlight::findMenuFromDialog(const std::string& dialog)
602{
603 auto it = s_dialog_to_menus.find(dialog);
604 if (it == s_dialog_to_menus.end()) return set_menu_empty;
605 return it->second;
606}
607
608
609/* Functions that populate our internal data. */
610
611void Highlight::addPropertyNode(const std::string& property, osg::ref_ptr<osg::Node> node)
612{
613 std::string property2 = canonical(property);
614 s_property_to_info[property2].nodes.insert(node);
615 if (s_node_to_properties[node].insert(property2).second)
616 SG_LOG(SG_GENERAL, SG_DEBUG, "node=" << node.get() << " property=" << property2);
617}
618
619void Highlight::addPropertyDialog(const std::string& property, const std::string& dialog)
620{
621 std::string property2 = canonical(property);
622 s_property_to_info[property2].dialogs.insert(dialog);
623 if (s_dialog_to_properties[dialog].insert(property2).second)
624 SG_LOG(SG_GENERAL, SG_DEBUG, "dialog=" << dialog << " property=" << property2);
625}
626
627void Highlight::addPropertyKeypress(const std::string& property, const std::string& keypress)
628{
629 std::string property2 = canonical(property);
630 s_property_to_info[property2].keypresses.insert(keypress);
631 if (s_keypress_to_properties[keypress].insert(property2).second)
632 SG_LOG(SG_GENERAL, SG_DEBUG, "keypress=" << keypress << " property=" << property2);
633}
634
635void Highlight::addPropertyMenu(HighlightMenu menu, const std::string& property)
636{
637 std::string property2 = canonical(property);
638 s_property_to_info[property2].menus.insert(menu);
639 if (s_menu_to_properties[menu].insert(property2).second)
640 SG_LOG(SG_GENERAL, SG_DEBUG, "menu=(" << menu.menu << " " << menu.item << ") property=" << property2);
641}
642
643void Highlight::addMenuDialog(HighlightMenu menu, const std::string& dialog)
644{
645 s_menu_to_dialog[menu] = dialog;
646 if (s_dialog_to_menus[dialog].insert(menu).second)
647 SG_LOG(SG_GENERAL, SG_DEBUG, "menu (" << menu.menu << " " << menu.item << ") dialog=" << dialog);
648}
649
650void Highlight::addPropertyProperty(const std::string& from0, const std::string& to0)
651{
652 std::string from = canonical(from0);
653 std::string to = canonical(to0);
654 if (from == to) return;
655 bool is_new = false;
656 if (s_property_to_properties[from].insert(to).second) is_new = true;
657 if (s_property_from_properties[to].insert(from).second) is_new = true;
658 if (is_new)
659 {
660 // Add transitive associations.
661 for (auto& toto: s_property_to_properties[to])
662 {
664 }
665 for (auto& fromfrom: s_property_from_properties[from])
666 {
667 Highlight::addPropertyProperty(fromfrom, to);
668 }
669 }
670}
671
672// Register the subsystem.
673SGSubsystemMgr::Registrant<Highlight> registrantHighlight(
674 SGSubsystemMgr::INIT);
static std::string canonical(const std::string property)
static bool s_output_stats
Definition Highlight.cxx:88
static SGPropertyNode_ptr s_prop_enabled
Definition Highlight.cxx:87
static std::unique_ptr< struct NodeHighlighting > s_node_highlighting
Definition Highlight.cxx:90
static bool operator<(const HighlightMenu &a, const HighlightMenu &b)
Definition Highlight.cxx:52
static std::map< std::string, std::set< std::string > > s_property_to_properties
Definition Highlight.cxx:82
static std::map< HighlightMenu, std::string > s_menu_to_dialog
Definition Highlight.cxx:79
static std::map< std::string, std::set< HighlightMenu > > s_dialog_to_menus
Definition Highlight.cxx:80
static std::map< std::string, std::set< std::string > > s_property_from_properties
Definition Highlight.cxx:83
static std::string s_getMenuName(SGPropertyNode *node)
Definition Highlight.cxx:23
static std::map< std::string, std::set< std::string > > s_dialog_to_properties
Definition Highlight.cxx:75
static std::map< osg::ref_ptr< osg::Node >, std::set< std::string > > s_node_to_properties
Definition Highlight.cxx:74
static const std::set< std::string > set_string_empty
static std::map< std::string, HighlightInfo > s_property_to_info
Definition Highlight.cxx:72
static std::set< NameValue > s_property_tree_items
Definition Highlight.cxx:85
SGSubsystemMgr::Registrant< Highlight > registrantHighlight(SGSubsystemMgr::INIT)
static const std::set< HighlightMenu > set_menu_empty
static std::map< HighlightMenu, std::set< std::string > > s_menu_to_properties
Definition Highlight.cxx:77
static std::map< std::string, std::set< std::string > > s_keypress_to_properties
Definition Highlight.cxx:76
std::unique_ptr< struct FdmInitialisedListener > s_fdm_initialised_listener
Definition Highlight.cxx:92
static const HighlightInfo info_empty
Wrap an FDM implementation in a subsystem with standard semantics Notably, deal with the various case...
Definition fdm_shell.hxx:44
const char * name
FGGlobals * globals
Definition globals.cxx:142
void valueChanged(SGPropertyNode *node) override
SGPropertyNode_ptr m_fdm_initialised
std::set< std::string > keypresses
Definition Highlight.hxx:30
std::set< HighlightMenu > menus
Definition Highlight.hxx:33
std::set< std::string > dialogs
Definition Highlight.hxx:27
std::set< osg::ref_ptr< osg::Node > > nodes
Definition Highlight.hxx:24
std::string description() const
Definition Highlight.cxx:33
void bind() override
void unbind() override
void addPropertyProperty(const std::string &property1, const std::string &property2)
const std::set< std::string > & findDialogProperties(const std::string &dialog)
void addPropertyDialog(const std::string &property, const std::string &dialog)
int highlightNodes(osg::Node *node)
void addPropertyMenu(HighlightMenu menu, const std::string &property)
void addMenuDialog(HighlightMenu menu, const std::string &dialog)
const std::set< std::string > & findNodeProperties(osg::Node *node)
const HighlightInfo & findPropertyInfo(const std::string &property)
const std::set< HighlightMenu > & findMenuFromDialog(const std::string &dialog)
const std::set< std::string > & findKeypressProperties(const std::string &keypress)
void reinit() override
const std::set< std::string > & findMenuProperties(const HighlightMenu &menu)
const std::set< std::string > & findPropertyFromProperties(const std::string &property)
const std::set< std::string > & findPropertyToProperties(const std::string &property)
void init() override
void update(double dt) override
void shutdown() override
void addPropertyNode(const std::string &property, osg::ref_ptr< osg::Node > node)
void addPropertyKeypress(const std::string &property, const std::string &keypress)
bool operator<(const NameValue &rhs) const
Definition Highlight.cxx:65
NameValue(const std::string &name, const std::string &value)
Definition Highlight.cxx:60
std::string name
Definition Highlight.cxx:63
std::string value
Definition Highlight.cxx:64
std::map< osg::ref_ptr< osg::Group >, osg::ref_ptr< osg::StateSet > > m_group_to_old_state_set
int highlight(osg::Node *node, bool highlight)
static void setRgbaDefault(SGPropertyNode *root, const std::string &path, double red, double green, double blue, double alpha)
virtual void valueChanged(SGPropertyNode *node)
static void setPropertyDefault(SGPropertyNode *root, const std::string &path, double default_value)
osg::ref_ptr< osg::StateSet > m_state_set
SGPropertyNode_ptr m_node