OpenWalnut  1.5.0dev
WMTemplate.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
26 // How to run this module in OpenWalnut:
27 // * Download a sample Dataset (http://www.informatik.uni-leipzig.de/~wiebel/public_data/walnut/walnut_masked.nii.gz)
28 // * Load the dataset by dragging it into OpenWalnut
29 // * Click on it and add the template module
30 // * This can be done via right-click menu or the module toolbar below the menu
31 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
32 
33 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
34 // How to create your own module in OpenWalnut? Here are the steps to take:
35 // * Setup your module building framework
36 // * See https://bsvgit.informatik.uni-leipzig.de/openwalnut/openwalnut/wikis/Module_ExternalDevelopment for details
37 // * copy the template module directory
38 // * think about a name for your module
39 // * rename the files from WMTemplate.cpp and WMTemplate.h to WMYourModuleName.cpp and WMYourModuleName.h
40 // * rename the class inside these files to WMYourModuleName
41 // * rename the class inside "W_LOADABLE_MODULE" to WMYourModuleName
42 // * change WMYourModuleName::getName() to a unique name, like "Your Module Name"
43 // * read the documentation in this module and modify it to your needs
44 // * compile
45 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
46 
47 // Some rules to the inclusion of headers:
48 // * Ordering:
49 // * C Headers
50 // * C++ Standard headers
51 // * External Lib headers (like OSG or Boost headers)
52 // * headers of other classes inside OpenWalnut
53 // * your own header file
54 
55 #include <memory>
56 #include <string>
57 
58 #include <osg/Geode>
59 #include <osg/Group>
60 #include <osg/Material>
61 #include <osg/ShapeDrawable>
62 #include <osg/StateAttribute>
63 
64 #include "WMTemplate.h"
65 #include "core/common/WColor.h"
66 #include "core/common/WItemSelection.h"
67 #include "core/common/WItemSelectionItem.h"
68 #include "core/common/WItemSelector.h"
69 #include "core/common/WPathHelper.h"
70 #include "core/common/WPropertyHelper.h"
71 #include "core/common/exceptions/WFileNotFound.h"
72 #include "core/graphicsEngine/WGERequirement.h"
73 #include "core/graphicsEngine/WGEUtils.h"
74 #include "core/kernel/WKernel.h"
75 #include "icons/bier.xpm"
76 #include "icons/steak.xpm"
77 #include "icons/wurst.xpm"
78 
80  WModule()
81 {
82  // In the constructor, you can initialize your members and all this stuff. You must not initialize connectors or properties here! You also
83  // should avoid doing computationally expensive stuff, since every module has its own thread which is intended to be used for such calculations.
84  // Please keep in mind, that every member initialized here is also initialized in the prototype, which may be a problem if the member is large,
85  // and therefore, wasting a lot of memory in your module's prototype instance.
86 }
87 
89 {
90  // Cleanup!
91 }
92 
93 std::shared_ptr< WModule > WMTemplate::factory() const
94 {
95  // To properly understand what this is, we need to have a look at how module instances get created. At first, if you are not familiar with the
96  // design patterns "Prototype", "Abstract Factory" and "Factory Method" you should probably read about them first. For short: while the kernel
97  // is starting up, it also creates an instance of WModuleFactory, which creates a prototype instance of every module that can be loaded.
98  // These prototypes are then used to create new instances of modules, check compatibility of modules and identify the type of modules.
99  // If someone, in most cases the module container, wants a new instance of a module with a given prototype, it asks the factory class for it,
100  // which uses the prototype's factory() method. Since the method is virtual, it returns a module instance, created with the correct type.
101  // A prototype itself is an instance of your module, with the constructor run, as well as connectors() and properties(). What does this mean
102  // to your module? Unlike the real "Prototype"- Design pattern, the module prototypes do not get cloned to retrieve a new instance,
103  // they get constructed using "new" and this factory method.
104  //
105  // Here is a short overview of the lifetime of a module instance:
106  //
107  // * constructor
108  // * connectors()
109  // * properties()
110  // * now isInitialized() will return true
111  // * the module will be associated with a container
112  // * now isAssociated() will return true
113  // o isUsable() will return true
114  // * after it got added, moduleMain() will be called
115  // * run, run, run, run
116  // * notifyStop gets called
117  // * moduleMain() should end
118  // * destructor
119  //
120  // So you always have to write this method and always return a valid pointer to an object of your module class.
121  // Never initialize something else in here!
122  return std::shared_ptr< WModule >( new WMTemplate() );
123 }
124 
125 const char** WMTemplate::getXPMIcon() const
126 {
127  // This is deprecated! You can still use it as fallback if you do not specify a META file.
128  //
129  // This was used to provide an icon for your module. You should use the META file in your resource directory. This file is commented and
130  // explains each entry in detail.
131  return NULL;
132 }
133 
134 const std::string WMTemplate::getName() const
135 {
136  // Specify your module name here. This name must be UNIQUE!
137  return "Template";
138 }
139 
140 const std::string WMTemplate::getDescription() const
141 {
142  // Specify your module description here. Be detailed. This text is read by the user.
143  return "This module is intended to be a module template and an example for writing modules.";
144 }
145 
147 {
148  // How will your module know on which data it should work? Through its input connector(s). How will other modules get to know about your
149  // calculated output data? Through your output connector(s). Simple isn't it? You may assume your module as some kind of function, as in
150  // common programming languages, where your connectors denote its function signature. The method "connectors()" is for initializing your
151  // connectors, your function signature. Now, a short excursion on how the module container and kernel knows which connector can be connected
152  // to which. Generally, there are only two types of connectors available for your usage: WModuleInputData and WModuleOutputData and they can
153  // only be connected to each other. So, it is not possible to connect an input with an input, nor an output with an output. Both of them are
154  // template classes and therefore are associated with a type. This type determines if an input connector is compatible with an output connector.
155  // A simple example: assume you have a class hierarchy:
156  // Initialize your connectors here. Give them proper names and use the type your module will create or rely on. Do not use types unnecessarily
157  // high in class hierarchy. The list of your connectors is fixed after connectors() got called. As in common imperative programming languages
158  // the function signature can not be changed during runtime (which, in our case, means after connectors() got called).
159 
160  // Here is an example of how to create connectors. This module wants to have an input connector. This connector is defined by the type of
161  // data that should be transferred, a module-wide unique name and a proper description:
162  m_input = WModuleInputData< WDataSetSingle >::createAndAdd( shared_from_this(), "in", "The dataset to display" );
163 
164  // This creates an input connector which can receive WDataSetSingle. It will never be able to connect to output connectors providing just a
165  // WDataSet (which is the father class of WDataSetSingle), but it will be able to be connected to an output connector with a type derived
166  // from WDataSetSingle (like WDataSetScalar or WDataSetVector)
167 
168  // Now, lets add an output connector. We want to provide data calculated here to other modules. The output connector is initialized the same
169  // way as input connectors. You need the type, the module-wide unique name and the description. The type you specify here also determines
170  // which input connectors can be connected to this output connector: only connectors with a type equal or lower in class hierarchy.
171  m_output = WModuleOutputData < WDataSetSingle >::createAndAdd( shared_from_this(), "out", "The calculated dataset" );
172 
173  // call WModule's initialization
175 }
176 
178 {
179  // Every module can provide properties to the outside world. These properties can be changed by the user in the GUI or simply by other
180  // modules using yours. Properties NEED to be created and added here. Doing this outside this function will lead to severe problems.
181  //
182  // Theoretically, you can specify properties of every type possible in C++. Therefore, see WPropertyVariable. But in most cases, the
183  // predefined properties (WPropertyTypes.h) are enough, besides being the only properties shown and supported by the GUI.
184  //
185  // To create and add a new property, every module has a member m_properties. It is a set of properties this module provides to the outer
186  // world. As with connectors, a property which not has been added to m_properties is not visible for others. Now, how to add a new property?
187 
188  m_propCondition = std::shared_ptr< WCondition >( new WCondition() );
189  m_aTrigger = m_properties->addProperty( "Do it now!", "Trigger Button Text.", WPVBaseTypes::PV_TRIGGER_READY,
190  m_propCondition );
191 
192  m_enableFeature = m_properties->addProperty( "Enable feature", "Description.", true );
193  m_anInteger = m_properties->addProperty( "Number of shape rows", "Number of shape rows.", 10, m_propCondition );
194  m_anIntegerClone = m_properties->addProperty( "CLONE!Number of shape rows",
195  "A property which gets modified if \"Number of shape rows\" gets modified.", 10 );
196  m_aDouble = m_properties->addProperty( "Shape radii", "Shape radii.", 20.0, m_propCondition );
197  m_aString = m_properties->addProperty( "A string", "Something.", std::string( "hello" ), m_propCondition );
198  m_aFile = m_properties->addProperty( "A filename", "Description.", WPathHelper::getAppPath(), m_propCondition );
199  m_aColor = m_properties->addProperty( "A color", "Description.", WColor( 1.0, 0.0, 0.0, 1.0 ) );
200  m_aPosition = m_properties->addProperty( "Somewhere", "Description.", WPosition( 0.0, 0.0, 0.0 ) );
201 
202  // These lines create some new properties and add them to the property list of this module. The specific type to create is determined by the
203  // initial value specified in the third argument. The first argument is the name of the property, which needs to be unique among all
204  // properties of this group and must not contain any slashes (/). The second argument is a description. A nice feature is the possibility
205  // to specify an own condition, which gets fired when the property gets modified. This is especially useful to wake up the module's thread
206  // on property changes. So, the property m_anInteger will wake the module thread on changes. m_enableFeature and m_aColor should not wake up
207  // the module thread. They get read by the update callback of this modules OSG node, to update the color. m_aTrigger is a property which can
208  // be used to trigger costly operations. The GUI shows them as buttons with the description as button text. The user can then press them and
209  // the WPropTrigger will change its state to PV_TRIGGER_TRIGGERED. In the moduleMain documentation, you'll find a more detailed description
210  // of how to use trigger properties. Be aware, that these kind of properties should be used carefully. They somehow inhibit the update flow
211  // through the module graph.
212  //
213  // m_anIntegerClone has a special purpose in this example. It shows that you can simply update properties from within your module whilst the
214  // GUI updates itself. You can, for example, set constraints or simply modify values depending on input data, most probably useful to set
215  // nice default values or min/max constraints.
216 
217  // All these above properties are not that usable for selections. Assume the following situation. Your module allows two different kinds of
218  // algorithms to run on some data and you want the user to select which one should do the work. This might be done with integer properties but it
219  // is simply ugly. Therefore, properties of type WPropSelection are available. First you need to define a list of alternatives:
220  m_possibleSelections = std::shared_ptr< WItemSelection >( new WItemSelection() );
221  m_possibleSelections->addItem( "Beer", "Cold and fresh.", template_bier_xpm ); // NOTE: you can add XPM images here.
222  m_possibleSelections->addItem( "Steaks", "Medium please.", template_steak_xpm );
223  m_possibleSelections->addItem( "Sausages", "With Sauerkraut.", template_wurst_xpm );
224 
225  // This list of alternatives is NOT the actual property value. It is the list on which so called "WItemSelector" instances work. These
226  // selectors are the actual property. After you created the first selector instance from the list, it can't be modified anymore. This ensures
227  // that it is consistent among multiple threads and selection instances. The following two lines create two selectors as initial value and
228  // create the property:
229  m_aSingleSelection = m_properties->addProperty( "I like most", "Do you like the most?", m_possibleSelections->getSelectorFirst(),
230  m_propCondition );
231  m_aMultiSelection = m_properties->addProperty( "I like", "What do you like.", m_possibleSelections->getSelectorAll(),
232  m_propCondition );
233 
234  // The last examples showed you how to create more or less complex selections. You where able to define a name, description and some icon for
235  // each selectable item. But maybe you want to store additional information, a class implementing some function (like a strategy pattern),
236  // and similar. To achieve this, we provide a special item class called WItemSelectionItemTyped. It is a templatized class which allows you
237  // to add a value of an arbitrary type to each item. This value of an arbitrary type might be a pointer, string, int, or a custom class'
238  // instance.
241  "The value 1", // this is the value for the type we specified: std::string.
242  "Option 1",
243  "Description for the first option"
244  )
245  );
247  "The value 2", // this is the value for the type we specified: std::string.
248  "Option 2",
249  "Description for the second option"
250  )
251  );
252  // This now created the selections. We store a string inside each item. But remember again: this can by ANY type.
253  // Finally, add a property by specifying the selector of the selection:
254  m_aSingleSelectionUsingTypes = m_properties->addProperty( "Choose one", "Choose on of these and watch the console output.",
255  m_possibleSelectionsUsingTypes->getSelectorFirst(), m_propCondition );
256 
257  // There are more property types available. Check out core/common/WPropertyTypes.h. One last to mention here is the WPropInterval. This
258  // property type allows you to define intervals. You can create one in the same way you created the other properties:
259  m_anInterval = m_properties->addProperty( "Interval", "Choose some interval please", WIntervalDouble( -1.0, 100.0 ), m_propCondition );
260  // Important to know is that you can only use WIntervalDouble. You can also use make_interval, which works similar to std::make_pair.
261 
262  // Adding a lot of properties might confuse the user. Using WPropGroup, you have the possibility to group your properties together. A
263  // WPropGroup needs a name and can provide a description. As with properties, the name should not contain any "/" and must be unique.
264 
265  m_group1 = m_properties->addPropertyGroup( "First Group", "A nice group for grouping stuff." );
266  m_group1a = m_group1->addPropertyGroup( "Group 1a", "A group nested into \"Group 1\"." );
267  m_group2 = m_properties->addPropertyGroup( "Second Group", "Another nice group for grouping stuff." );
268 
269  // You can nest property groups arbitrarily deep. ( But as with a good text, a chapter number 1.23.23.5.73.1.5 is useless. Avoid nesting too
270  // deep and avoid groups with only one or two properties. )
271  WPropGroup group = m_properties->addPropertyGroup( "Group Nesting - Level 0", "Demo for intensive group nesting." );
272  for( int d = 1; d <= 20; ++d )
273  {
274  std::string depth = string_utils::toString( d );
275  group = group->addPropertyGroup( "Group Nesting - Level " + depth, "A nested group." );
276  // NOTE: the last group will be deleted as we do not keep its shared_ptr.
277  }
278 
279  // To understand how the groups can be used, you should consider that m_properties itself is a WPropGroup! This means, you can use your newly
280  // created groups exactly in the same way as you would use m_properties.
281  m_group1Bool = m_group1->addProperty( "Funny stuff", "A grouped property", true );
282 
283  // You even can add one property multiple times to different groups:
284  m_group2->addProperty( m_aColor );
285  m_group1a->addProperty( m_aDouble );
286  m_group1a->addProperty( m_enableFeature );
287 
288  // Properties can be hidden on the fly. The GUI updates automatically. This is a very useful feature. You can create properties which depend
289  // on a current selection and blend them in our out accordingly.
290  m_aHiddenInt = m_group2->addProperty( "Hide me please", "A property used to demonstrate the hidden feature.", 1, true );
291  m_aHiddenGroup = m_group2->addPropertyGroup( "Hide me please too", "A property used to demonstrate the hidden feature.", true );
292 
293  // Add another button to group2. But this time, we do not want to wake up the main thread. We handle this directly. Fortunately,
294  // WPropertyVariable offers you the possibility to specify your own change callback. This callback is used for hiding the m_aColor property
295  // on the fly.
296  m_hideButton = m_group2->addProperty( "(Un-)Hide", "Trigger Button Text.", WPVBaseTypes::PV_TRIGGER_READY,
297  boost::bind( &WMTemplate::hideButtonPressed, this ) );
298 
299  // How can the values of the properties be changed? You can take a look at moduleMain where this is shown. For short: m_anInteger->set( 2 )
300  // and m_anInteger->get().
301 
302  // The properties offer another nice feature: property constraints. You can enforce your properties to be in a special range, to not be
303  // empty, to contain a valid directory name and so on. This is done with the class WPropertyVariable< T >::WPropertyConstraint. There are
304  // several predefined you can use directly: WPropertyConstraintTypes.h. The constants defined there can be used as namespace in
305  // WPropertyHelper. As an example, we want the property m_aFile to only contain existing directories:
308 
309  // Thats it. To set minimum and maximum value for a property the convenience methods setMin and setMax are defined. setMin and setMax are
310  // allowed for all property types with defined <= and >= operator.
311  m_anInteger->setMin( 1 );
312  m_anInteger->setMax( 15 );
313  m_aDouble->setMin( 5.0 );
314  m_aDouble->setMax( 50.0 );
315 
316  // we also want to constraint the both selection properties. One should not allow selecting multiple elements. But both require at least one
317  // element to be selected:
323 
324  // The most amazing feature is: custom constraints. Similar to OSG update callbacks, you just need to write your own PropertyConstraint class
325  // to define the allowed values for your constraint. Take a look at the StringLength class in this module's code on how to do it.
326  m_aString->addConstraint( std::shared_ptr< StringLength >( new StringLength ) );
328 
329  // One last thing to mention is the active property. This property is available in all modules and represents the activation state of the
330  // module. In the GUI this is simply a checkbox beneath the module. The active property should be taken into account in ALL modules.
331  // Visualization modules should turn off their graphics. There are basically three ways to react on changes in m_active, which is the member
332  // variable for this property.
333  // 1: overwrite WModule::activate() in your module
334  // 2: register your own handler: m_active->getCondition()->subscribeSignal( boost::bind( &WMTemplate::myCustomActiveHandler, this ) );
335  // 3: react during your module main loop using the moduleState: m_moduleState.add( m_active->getCondition );
336  // Additionally, your can also use the m_active variable directly in your update callbacks to en-/disable some OSG nodes.
337  // This template module uses method number 1. This might be the easiest and most commonly used way.
338 
339  // Sometimes it is desirable to provide some values, statistics, counts, times, ... to the user. This would be possible by using a property
340  // and set the value to the value you want to show the user. Nice, but the user can change this value. PropertyConstraints can't help here,
341  // as they would forbid writing any value to the property (regardless if the module or the user wants to set it). In other words, these
342  // special properties serve another purpose. They are used for information output. Your module already provides another property list only
343  // for these kind of properties. m_infoProperties can be used in the same way as m_properties. The only difference is that each property and
344  // property group added here can't be modified from the outside world. Here is an example:
345  m_aIntegerOutput = m_infoProperties->addProperty( "Run count", "Number of run cycles the module made so far.", 0 );
346  // Later on, we will use this property to provide the number of run cycles to the user.
347  // In more detail, the purpose type of the property gets set to PV_PURPOSE_INFORMATION automatically by m_infoProperties. You can, of course,
348  // add information properties to your custom groups or m_properties too. There, you need to set the purpose flag of the property manually:
349  std::string message = std::string( "Hey you! Besides all these parameters, you also can print values, " ) +
350  std::string( "<font color=\"#00f\" size=15>html</font> formatted strings, colors and " ) +
351  std::string( "so on using <font color=\"#ff0000\">properties</font>! Isn't it <b>amazing</b>?" );
352 
353  m_aStringOutput = m_group1a->addProperty( "A message", "A message to the user.", message );
354  m_aStringOutput->setPurpose( PV_PURPOSE_INFORMATION );
355  // This adds the property m_aStringOutput to your group and sets its purpose. The default purpose for all properties is always
356  // "PV_PURPOSE_PARAMETER". It simply denotes the meaning of the property - its meant to be used as modifier for the module's behavior; a
357  // parameter.
358  //
359  // Some more examples. Please note: Although every property type can be used as information property, not everything is really useful.
360  m_infoProperties->addProperty( m_aStringOutput ); // we can also re-add properties
361  m_aTriggerOutput = m_infoProperties->addProperty( "A trigger", "Trigger As String", WPVBaseTypes::PV_TRIGGER_READY );
362  m_aDoubleOutput = m_infoProperties->addProperty( "Some double", "a Double. Nice isn't it?", 3.1415 );
363  m_aIntOutput = m_infoProperties->addProperty( "Some int", "a int. Nice isn't it?", 123456 );
364  m_aColorOutput = m_infoProperties->addProperty( "A color", "Some Color. Nice isn't it?", WColor( 0.5, 0.5, 1.0, 1.0 ) );
365  m_aFilenameOutput = m_infoProperties->addProperty( "Nice file", "a Double. Nice isn't it?", WPathHelper::getAppPath() );
366  m_aSelectionOutput = m_infoProperties->addProperty( "A selection", "Selection As String", m_possibleSelections->getSelectorFirst() );
367  // One important note regarding information properties. If a property gets added in a group which is an information property-group, then
368  // each added property does NOT contain any constraints. If a property gets an information property AFTER its creation, like m_aStringOutput,
369  // then it keeps its constraints!
370 
371  // We now add another trigger. Pressing this button will cause an exception to be thrown. This demonstrates how the GUI and OpenWalnut
372  // handles modules which throw an exception without catching it.
373  m_exceptionTrigger = m_properties->addProperty( "Press to crash Module", "Pressing this button lets the module intentionally crash.",
375 
377 }
378 
380 {
381  // This method allows modules to specify what they need to run properly. This module, for example, needs the WGE. It therefore adds the
382  // WGERequirement to the list of requirements. Modules only get started if all the requirements of it are met by the current running
383  // OpenWalnut. This is a very handy tool for NO-GUI versions or script versions of OpenWalnut where there simply is no graphics engine
384  // running. This way, the kernel can ensure that only modules are allowed to run who do not require the WGE.
385  // Another useful example are module containers. Usually, they need several other modules to work properly.
386  m_requirements.push_back( new WGERequirement() );
387 }
388 
390 {
391  // This is the modules working thread. Its the most important part of your module.
392  // When you enter this method, all connectors and properties the module provides are fixed. They get initialized in connectors() and
393  // properties(). You always can assume the kernel, the GUI, the graphics engine and the data handler to be initialized and ready. Please keep
394  // in mind, that this method is running in its own thread.
395 
396  // You can output log messages everywhere and any time in your module. The WModule base class therefore provides debugLog, infoLog, warnLog
397  // and errorLog. You can use them very similar to the common std::cout streams.
398  debugLog() << "Entering moduleMain()";
399 
400  // Your module can notify everybody that it is ready to be used. The member function ready() does this for you. The ready state is especially
401  // useful whenever your module needs to do long operations to initialize. No other module can connect to your module before it signals its
402  // ready state. You can assume the code before ready() to be some kind of initialization code.
403  debugLog() << "Doing time consuming operations";
404  sleep( 2 );
405 
406  // Your module can use a moduleState variable to wait for certain events. Most commonly, these events are new data on input connectors or
407  // changed properties. You can decide which events the moduleState should handle. Therefore, use m_moduleState.add( ... ) to insert every
408  // condition you want to wait on. As every input connector provides an changeCondition, we now add this condition to the moduleState:
409  m_moduleState.setResetable( true, true );
410  m_moduleState.add( m_input->getDataChangedCondition() );
411  // Remember the condition provided to some properties in properties()? The condition can now be used with this condition set.
413  // One note about "setResetable": It might happen, that a condition fires and your thread does not currently waits on it. This would mean,
414  // that your thread misses the event. The resettable flag for those condition sets can help here. Whenever a condition, managed by the
415  // condition set, fires, the moduleState variable remembers it. So, the next call to m_moduleState.wait() will immediately return and reset
416  // the "memory" of the moduleState. For more details, see:
417  // https://bsvgit.informatik.uni-leipzig.de/openwalnut/openwalnut/wikis/MultithreadingHowto#how-to-wait-correctly
418 
419  // Most probably, your module will be a module providing some kind of visual output. In this case, the WGEManagedGroupNode is very handy.
420  // It allows you to insert several nodes and transform them as the WGEGroupNode (from which WGEManagedGroupNode is derived from) is also
421  // an osg::MatrixTransform. The transformation feature comes in handy if you want to transform your whole geometry according to a dataset
422  // coordinate system for example. Another nice feature in WGEManagedGroupNode is that it can handle the m_active flag for you. Read the
423  // documentation of WMTemplate::activate for more details.
424  // First, create the node and add it to the main scene. If you insert something into the scene, you HAVE TO remove it after your module
425  // has finished!
427  // Set a new callback for this node which basically transforms the geometry according to m_aPosition. Update callbacks are the thread safe
428  // way to manipulate an OSG node while it is inside the scene. This module contains several of these callbacks as an example. The one used
429  // here is to translate the root node coordinate system in space according to m_aPosition:
430  m_rootNode->addUpdateCallback( new TranslateCallback( this ) );
431  // Insert to the scene:
432  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_rootNode );
433 
434  // Signal ready state. Now your module can be connected by the container, which owns the module.
435  ready();
436  debugLog() << "Module is now ready.";
437 
438  // After your module has signalled that it is ready, OpenWalnut allows the project loader to set the restored properties and connections. For
439  // you this means that your module now runs but WHILE running, the project loader might change properties and connections. Usually, this is
440  // no problem as you write interactive modules, handling these changes fast. But if you need to ensure that you do not continue your module
441  // until the project file loader has completely restored your module, you will need to call this:
442  waitRestored();
443  // This always returns if you manually add your module and no project file loader or something similar has to restore any values.
444 
445  // Before we begin, we finally create a shader object which shades the graphics we create in this module. You can use your own shaders or a
446  // global one, like WGELighting. When creating a shader, you need to specify its name and an optional search path. When developing modules,
447  // this search path should be you module's local resource path.
448  m_shader = new WGEShader( "WGELighting", m_localPath );
449 
450  // Later in the code, we show how we use a property to modify the graphics color. There, we use the OpenGL material mechanism. So we need to
451  // switch the shader to this mode by setting a compile-time switch:
452  m_shader->setDefine( "USE_MATERIAL_DIFFUSE" );
453  // There are multiple ways to set uniforms and defines automatically by binding them to properties. But this is not the topic of this module.
454 
455  // Normally, you will have a loop which runs as long as the module should not shutdown. In this loop you can react on changing data on input
456  // connectors or on changed in your properties.
457  debugLog() << "Entering main loop";
458  while( !m_shutdownFlag() )
459  {
460  // Now, the moduleState variable comes into play. The module can wait for the condition, which gets fired whenever the input receives data
461  // or an property changes. The main loop now waits until something happens.
462  debugLog() << "Waiting ...";
464 
465  // As you might remember, this property is an information property to provide the number of run cycles to the outside world. It won't be
466  // modified but the module can modify it. This is useful to provide statistics, counts, times or even a "hello world" string to the user
467  // as an information or status report. Please do not abuse these information properties as progress indicators. A short overview on how
468  // to make progress indicators is provided some lines below. Here, we simply increase the value.
469  m_aIntegerOutput->set( m_aIntegerOutput->get() + 1 );
470 
471  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
472  // After waking up, the module has to check whether the shutdownFlag fired. If yes, simply quit the module.
473 
474  // woke up since the module is requested to finish
475  if( m_shutdownFlag() )
476  {
477  break;
478  }
479 
480  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
481  // The next part is the collection part. We collect the information we need and check whether they changed.
482  // Do not recalculate everything in every loop. Always check whether the data changed or some property and handle those cases properly.
483  // After collection, the calculation work can be done.
484 
485 
486  // Now, we can check the input, whether there is an update enqueued for us. But first, we need to understand the meaning of an update on
487  // an input connector:
488  // * a module updates its output connector with some new data -> updated
489  // * a module triggers an update on its output connector without an actual data change -> updated
490  // * our own input connector got connected to an output connector -> updated
491  // * our own input connector got DISconnected from an output connector -> NO update
492  // You now might ask: "Why can modules trigger updates if they did not change the data?". The answer is simple. Some modules change the
493  // grid without actually changing the data for example. They translate the grid in space. This results in an update although the actual
494  // data stayed the same.
495 
496  // To query whether an input was updated, simply ask the input:
497  bool dataUpdated = m_input->updated();
498 
499  // Remember the above criteria. We now need to check if the data is valid. After a connect-update, it might be NULL.
500  std::shared_ptr< WDataSetSingle > dataSet = m_input->getData();
501  bool dataValid = ( dataSet != NULL );
502  // After calling getData(), the update flag is reset and false again. Please keep in mind, that the module lives in an multi-threaded
503  // world where the update flag and data can change at any time. DO NEVER use getData directly in several places of your module as the
504  // data returned may change between two consecutive calls! Always grab it into a local variable and use this variable.
505 
506  // Another important hint. For grabbing the data, use a local variable wherever possible. If you use a member variable, the data might
507  // never be freed if nobody uses the data anymore because your module holds the last reference. If you need to use a member variable for
508  // the received data, subscribe the your input's disconnect signal or overwrite WModule::notifyConnectionClosed and reset your variable
509  // there to ensure its proper deletion.
510 
511  // do something with the data
512  if( dataUpdated && dataValid )
513  {
514  // The data is valid and we received an update. The data is not NULL but may be the same as in previous loops.
515  debugLog() << "Received Data.";
516  }
517 
518  // If there is no data, this might have the following reasons: the connector never has been connected or it got disconnected. Especially
519  // in the case of a disconnect, you should always clean up your renderings and internal states. A disconnected module should not render
520  // anything anymore. Locally stored referenced to the old input data have to be reset to. Only this way, it is guaranteed that not used
521  // data gets deleted properly.
522  if( !dataValid )
523  {
524  debugLog() << "Data changed. No valid data anymore. Cleaning up.";
525  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_rootNode );
526  }
527 
528  // Here we collect our properties. You, as with input connectors, always check if a property really has changed. You most probably do not
529  // want to check properties which are used exclusively inside the update callback of your OSG node. As the properties are thread-safe, the
530  // update callback can check them and apply it correctly to your visualization.
531  //
532  // To check whether a property changed, WPropertyVariable provides a changed() method which is true whenever the property has changed.
533  // Please note: creating the property with addProperty( ... ) will set changed to true.
534  if( m_aFile->changed() )
535  {
536  // To reset the changed flag, supply a "true" to the get method. This resets the changed-flag and next loop you can again check
537  // whether it has been changed externally.
538 
539  // This is a simple example for doing an operation which is not depending on any other property.
540  debugLog() << "Doing an operation on the file \"" << m_aFile->get( true ).string() << "\".";
541 
542  // NOTE: be careful if you want to use dataSet here, as it might be unset. Verify data validity using dataUpdated && dataValid.
543  }
544 
545  // m_aFile got handled above. Now, handle two properties which together are used as parameters for an operation.
546  if( m_aString->changed() )
547  {
548  // This is a simple example for doing an operation which is depends on all, but m_aFile, properties.
549  debugLog() << "Doing an operation basing on m_aString ... ";
550  debugLog() << "m_aString: " << m_aString->get( true );
551 
552  // NOTE: be careful if you want to use dataSet here, as it might be unset. Verify data validity using dataUpdated && dataValid.
553  }
554 
555  // This example code now shows how to modify your OSG nodes basing on changes in your dataset or properties.
556  // The if statement also checks for data validity as it uses the data! You should also always do that.
557  if( ( m_anInteger->changed() || m_aDouble->changed() || dataUpdated ) && dataValid )
558  {
559  debugLog() << "Creating new OSG node";
560 
561  // You should grab your values at the beginning of such calculation blocks, since the property might change at any time!
562  int rows = m_anInteger->get( true );
563  double radii = m_aDouble->get( true );
564 
565  // You can set other properties here. This example simply sets the value of m_anIntegerClone. The set command allows an additional
566  // parameter. If it is true, the specified property condition does not fire if it is set. This is useful if your module main loop
567  // waits for the condition of the property you want to set. Setting the property without suppressing the notification would cause
568  // another loop in your module.
569  m_anIntegerClone->set( m_anInteger->get(), true );
570 
571  debugLog() << "Number of Rows: " << rows;
572  debugLog() << "Radii: " << radii;
573  debugLog() << "Current dataset: " << dataSet->getFilename() << " with name: " << dataSet->getName();
574 
575  // This block will be executed whenever we have a new dataset or the m_anInteger property has changed. This example codes produces
576  // some shapes and replaces the existing root node by a new (updated) one. Therefore, a new root node is needed:
577  osg::ref_ptr< osg::Geode > newGeode = new osg::Geode();
578  // When working with the OpenSceneGraph, always use ref_ptr to store pointers to OSG objects. This allows OpenSceneGraph to manage
579  // its resources automatically.
580  for( int32_t i = 0; i < rows; ++i )
581  {
582  newGeode->addDrawable(
583  new osg::ShapeDrawable( new osg::Box( osg::Vec3( 25, 128, i * 15 ), radii ) ) );
584  newGeode->addDrawable(
585  new osg::ShapeDrawable( new osg::Sphere( osg::Vec3( 75, 128, i * 15 ), radii ) ) );
586  newGeode->addDrawable(
587  new osg::ShapeDrawable( new osg::Cone( osg::Vec3( 125, 128, i * 15 ), radii, radii ) ) );
588  newGeode->addDrawable(
589  new osg::ShapeDrawable( new osg::Cylinder( osg::Vec3( 175, 128, i * 15 ), radii, radii ) ) );
590  newGeode->addDrawable(
591  new osg::ShapeDrawable( new osg::Capsule( osg::Vec3( 225, 128, i * 15 ), radii, radii ) ) );
592  }
593 
594  // The old root node needs to be removed safely. The OpenSceneGraph traverses the graph at every frame. This traversal is done in a
595  // separate thread. Therefore, adding a node directly may cause the OpenSceneGraph to crash. Thats why the Group node (WGEGroupNode)
596  // offers safe remove and insert methods. Use them to manipulate the scene node.
597  // First remove the old node:
598  m_rootNode->remove( m_geode );
599  m_geode = newGeode;
600 
601  // OSG allows you to add custom callbacks. These callbacks get executed on each update traversal. They can be used to modify several
602  // attributes and modes of existing nodes. You do not want to remove the node and recreate another one to simply change some color,
603  // right? Setting the color can be done in such an update callback. See in the header file, how this class is defined.
604  m_geode->addUpdateCallback( new SafeUpdateCallback( this ) );
605 
606  // The default lighting is not very pretty. We can bind a default shader provided by OpenWalnut to this geode to have nice per-pixel
607  // Phong shading. We earlier created this shader object. Now, we need to apply it:
608  m_shader->apply( m_geode );
609 
610  // And insert the new node
611  m_rootNode->insert( m_geode );
612  }
613 
614  // Now we updated the visualization after the dataset has changed. Your module might also calculate some other datasets basing on the
615  // input data.
616  // To ensure that all datasets are valid, check dataUpdated and dataValid. If both are true, you can safely use the data.
617  if( dataUpdated && dataValid )
618  {
619  debugLog() << "Data changed. Recalculating output.";
620 
621  // Calculate your new data here. This example just forwards the input to the output ;-).
622  std::shared_ptr< WDataSetSingle > newData = dataSet;
623 
624  // Doing a lot of work without notifying the user visually is not a good idea. So how is it possible to report progress? Therefore,
625  // the WModule class provides a member m_progress which is of type WPropgressCombiner. You can create own progress objects and count
626  // them individually. The m_progress combiner provides this information to the GUI and the user.
627  // Here is a simple example:
628  int steps = 10;
629  std::shared_ptr< WProgress > progress1( new WProgress( "Doing work 1", steps ) );
630  m_progress->addSubProgress( progress1 );
631  for( int i = 0; i < steps; ++i )
632  {
633  ++*progress1;
634  sleep( 1 );
635  }
636  progress1->finish();
637  // This creates a progress object with a name and a given number of steps. Your work loop can now increment the progress object. The
638  // progress combiner m_progress collects the progress and provides it to the GUI. When finished, the progress MUST be marked as
639  // finished using finish(). It is no problem to have several progress objects at the same time!
640 
641  // Sometimes, the number of steps is not known. WProgress can also handle this. Simply leave away the last parameter (the number of
642  // steps. As with the other progress, you need to add it to the modules progress combiner and you need to mark it as finished with
643  // finish() if you are done with your work.
644  std::shared_ptr< WProgress > progress2( new WProgress( "Doing work 2" ) );
645  m_progress->addSubProgress( progress2 );
646  sleep( 2 );
647  progress2->finish();
648 
649  // How to set the data to the output and how to notify other modules about it?
650  m_output->updateData( newData );
651  // This sets the new data to the output connector and automatically notifies all modules connected to your output.
652  }
653 
654  // As we provided our condition to m_aTrigger too, the main thread will wake up if it changes. The GUI can change the trigger only to the
655  // state "PV_TRIGGER_TRIGGERED" (this is the case if the user presses the button).
656  if( m_aTrigger->get( true ) == WPVBaseTypes::PV_TRIGGER_TRIGGERED )
657  {
658  // Now that the trigger has the state "triggered", a time consuming operation can be done here.
659  debugLog() << "User triggered an important and time consuming operation.";
660 
661  // We can exchange the list used for selection properties. This of course invalidates the current user selection. You should avoid
662  // changing this too often and too fast as it might confuse the user.
663  m_possibleSelections->addItem( "Beer2", "Cold and fresh.", template_bier_xpm ); // NOTE: you can add XPM images here.
664  m_possibleSelections->addItem( "Steaks2", "Medium please.", template_steak_xpm );
665  m_possibleSelections->addItem( "Sausages2", "With Sauerkraut.", template_wurst_xpm );
666  // Each of the above write operations trigger an invalidation of all currently exiting selectors. You can create a new selector
667  // basing on an old invalid one and set it as new value for the selections:
668 
669  // Now we set the new selection and selector. Calling newSelector without any argument copies the old selector and tries to resize
670  // the selection to match the new size
671  m_aSingleSelection->set( m_aSingleSelection->get().newSelector() );
672  m_aMultiSelection->set( m_aMultiSelection->get().newSelector() );
673 
674  // Update the output property
676 
677  // Do something here. As above, do not forget to inform the user about your progress.
678  int steps = 10;
679  std::shared_ptr< WProgress > progress1( new WProgress( "Doing something important", steps ) );
680  m_progress->addSubProgress( progress1 );
681  for( int i = 0; i < steps; ++i )
682  {
683  ++*progress1;
684  sleep( 1 );
685  }
686  progress1->finish();
687 
688  // As long as the module does not reset the trigger to "ready", the GUI disables the trigger button. This is very useful to avoid
689  // that a user presses the button multiple times during an operation. When setting the property back to "ready", the GUI re-enables
690  // the button and the user can press it again.
691  // To avoid the moduleMain- loop to awake every time we reset the trigger, provide a second parameter to the set() method. It denotes
692  // whether the change notification should be fired or not. In our case, we avoid this by providing false to the second parameter.
694 
695  // Also update the information property.
697  }
698 
699  // This checks the selections.
700  if( m_aMultiSelection->changed() || m_aSingleSelection->changed() )
701  {
702  // The single selector allows only one selected item and requires one item to be selected all the time. So accessing it by index
703  // is trivial:
704  WItemSelector s = m_aSingleSelection->get( true );
705  infoLog() << "The user likes " << s.at( 0 )->getName() << " the most.";
706 
707  // The multi property allows the selection of several items. So, iteration needs to be done here:
708  s = m_aMultiSelection->get( true );
709  for( size_t i = 0; i < s.size(); ++i )
710  {
711  infoLog() << "The user likes " << s.at( i )->getName();
712  }
713  }
714 
715  // This checks the selections with our additional value.
716  if( m_aSingleSelectionUsingTypes->changed() )
717  {
718  // The single selector allows only one selected item and requires one item to be selected all the time. So accessing it by index
719  // is trivial:
721  infoLog() << "The item value is: " << s.at( 0 )->getAs< MyItemType >()->getValue() <<
722  ". Length: " << s.at( 0 )->getAs< MyItemType >()->getValue().length();
723 
724  // This showed that you can add values of your arbitrary type into the selection. Assume this is an object providing a ()-operator.
725  // You can then use s.at( 0 )->getAs< MyItemType >()->getValue()() to call this operator. This< is very handy for implementing
726  // strategies. But before you get too excited about this, for strategies with automatic, complex property handling, you should have
727  // a look at WStrategyHelper!
728  }
729 
730  // Trigger an exception? We do this whenever the user pressed the exception-button
732  {
733  // Throw an exception and do not catch it. Please note that OpenWalnut provides several exceptions which usually cover the most
734  // needs. If not, derive your own exceptions from WException. Using WExceptions has one nice advantage: it provides a backtrace on
735  // systems which support this.
736  throw WFileNotFound( "This is a demonstration of an exception being thrown from within a module." );
737  // OpenWalnut then automatically catches it and transports it to the kernel and the registered callbacks. This usually is the GUI
738  // which shows a dialog or something similar. Additionally, the m_isCrashed flag is set to true. Once a module is crahsed, it cannot
739  // be "restored".
740  }
741 
742  // Check if the interval was modified.
743  if( m_anInterval->changed() )
744  {
745  // Grab the value as you have learned above:
746  WIntervalDouble i = m_anInterval->get( true );
747  // And use it somehow:
748  infoLog() << "You have selected this interval: [" << i.getLower() << ", " << i.getUpper() << "].";
749  }
750  }
751 
752  // At this point, the container managing this module signaled to shutdown. The main loop has ended and you should clean up:
753  //
754  // * remove allocated memory
755  // * remove all OSG nodes
756  // * stop any pending threads you may have started earlier
757  // * ...
758  // NOTE: as the module gets disconnected prior to shutdown, most of the cleanup should have been done already.
759 
760  // Remove the geometry from the scene. If it has never been added, this call does nothing. Always remember to remove your rendering at the
761  // end of the module loop.
762  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_rootNode );
763 
764  // Let us utilize the META file in the resources directory. This file contains several information about a module and
765  // can also contain custom values. Here, we query the "goodbye" value:
766  std::string bye = getMetaInformation()->query< std::string >(
767  "common/goodbye", // the absolute path
768  "have a nice day" // a default if the element does not exist or cannot be returned as std::string.
769  );
770  infoLog() << bye;
771 }
772 
773 void WMTemplate::SafeUpdateCallback::operator()( osg::Node* node, osg::NodeVisitor* nv )
774 {
775  // One note about m_aColor: As you might have notices, changing one of the properties, which recreate the OSG node, causes the material to be
776  // gray again. This is simply caused by m_aColor->changed() is still false! To resolve this problem, use some m_osgNeedsUpdate boolean which
777  // gets set in your thread main and checked here or, as done in this module, by checking whether the callback is called the first time.
778  if( m_module->m_aColor->changed() || m_initialUpdate )
779  {
780  // Set the diffuse color and material:
781  osg::ref_ptr< osg::Material > mat = new osg::Material();
782  mat->setDiffuse( osg::Material::FRONT, m_module->m_aColor->get( true ) );
783  node->getOrCreateStateSet()->setAttribute( mat, osg::StateAttribute::ON );
784  }
785  traverse( node, nv );
786 }
787 
788 void WMTemplate::TranslateCallback::operator()( osg::Node* node, osg::NodeVisitor* nv )
789 {
790  // Update the transformation matrix according to m_aPosition if it has changed.
791  if( m_module->m_aPosition->changed() || m_initialUpdate )
792  {
793  // The node to which this callback has been attached needs to be an osg::MatrixTransform:
794  osg::ref_ptr< osg::MatrixTransform > transform = static_cast< osg::MatrixTransform* >( node );
795 
796  // Build a translation matrix (to comfortably convert between WPosition and osg::Vec3 use the WVector3XXX methods)
797  osg::Matrixd translate = osg::Matrixd::translate( m_module->m_aPosition->get( true ).as< osg::Vec3d >() );
798 
799  // and set the translation matrix
800  transform->setMatrix( translate );
801 
802  // First update done
803  m_initialUpdate = false;
804  }
805  traverse( node, nv );
806 }
807 
809  const WPVBaseTypes::PV_STRING& value )
810 {
811  // This method gets called every time the m_aString property is going to be changed. It can decide whether the new value is valid or not. If
812  // the method returns true, the new value is set. If it returns false, the value is rejected.
813  //
814  // Note: always use WPVBaseTypes when specializing the WPropertyVariable template.
815 
816  // simple example: just accept string which are at least 5 chars long and at most 10.
817  return ( value.length() <= 10 ) && ( value.length() >= 5 );
818 }
819 
820 std::shared_ptr< WPropertyVariable< WPVBaseTypes::PV_STRING >::PropertyConstraint > WMTemplate::StringLength::clone()
821 {
822  // If you write your own constraints, you NEED to provide a clone function. It creates a new copied instance of the constraints with the
823  // correct runtime type.
824  return std::shared_ptr< WPropertyVariable< WPVBaseTypes::PV_STRING >::PropertyConstraint >( new WMTemplate::StringLength( *this ) );
825 }
826 
828 {
829  // This method gets called, whenever the m_active property changes. Your module should always handle this if you do not use the
830  // WGEManagedGroupNode for your scene. The user can (de-)activate modules in his GUI and you can handle this case here:
831  if( m_active->get() )
832  {
833  debugLog() << "Activate.";
834  }
835  else
836  {
837  debugLog() << "Deactivate.";
838  }
839 
840  // The simpler way is by using WGEManagedGroupNode which deactivates itself according to m_active. See moduleMain for details.
841 
842  // Always call WModule's activate!
844 }
845 
847 {
848  // This method is called whenever m_hideButton changes its value. You can use such callbacks to avoid waking-up or disturbing the module
849  // thread for certain operations.
850 
851  // If the button was triggered, switch the hide-state of m_aColor and m_aHiddenInt.
853  {
854  // switch the hide flag of the color prop.
855  m_aColor->setHidden( !m_aColor->isHidden() );
856  m_aHiddenInt->setHidden( !m_aHiddenInt->isHidden() );
857  m_aHiddenGroup->setHidden( !m_aHiddenGroup->isHidden() );
858 
859  // never forget to reset a trigger. If not done, the trigger is disabled in the GUI and can't be used again.
861  // NOTE: this again triggers an update, which is why we need to check the state of the trigger in this if-clause.
862  }
863 }
virtual void wait() const
Wait for the condition.
void setResetable(bool resetable=true, bool autoReset=true)
Sets the resetable flag.
virtual void add(std::shared_ptr< WCondition > condition)
Adds another condition to the set of conditions to wait for.
Class to encapsulate boost::condition_variable_any.
Definition: WCondition.h:42
Thrown whenever a file was not found.
Definition: WFileNotFound.h:37
This class adds some convenience methods to WGEGroupNode.
This requirement ensures an up and running WGE.
Class encapsulating the OSG Program class for a more convenient way of adding and modifying shader.
Definition: WGEShader.h:48
const T & getUpper() const
Return the upper value of the interval.
Definition: WInterval.h:263
const T & getLower() const
Get the lower value of the interval.
Definition: WInterval.h:257
A derivation of WItemSelection which can store a value of any type.
static SPtr create(T value, std::string name, std::string description="", const char **icon=NULL)
Create a instance of the item.
A class containing a list of named items.
std::shared_ptr< WItemSelection > SPtr
Convenience typedef for a std::shared_ptr< WItemSelection >
This class represents a subset of a WItemSelection.
Definition: WItemSelector.h:53
virtual const std::shared_ptr< WItemSelectionItem > at(size_t index) const
Gets the selected item with the given index.
virtual size_t size() const
The number of selected items.
static WKernel * getRunningKernel()
Returns pointer to the currently running kernel.
Definition: WKernel.cpp:117
std::shared_ptr< WGraphicsEngine > getGraphicsEngine() const
Returns pointer to currently running instance of graphics engine.
Definition: WKernel.cpp:122
Node callback to change the color of the shapes inside the root node.
Definition: WMTemplate.h:320
bool m_initialUpdate
Denotes whether the update callback is called the first time.
Definition: WMTemplate.h:350
WMTemplate * m_module
Pointer used to access members of the module to modify the node.
Definition: WMTemplate.h:344
virtual void operator()(osg::Node *node, osg::NodeVisitor *nv)
operator () - called during the update traversal.
Definition: WMTemplate.cpp:773
This shows how to write custom constraints for your modules.
Definition: WMTemplate.h:398
virtual bool accept(std::shared_ptr< WPropertyVariable< WPVBaseTypes::PV_STRING > > property, const WPVBaseTypes::PV_STRING &value)
You need to overwrite this method.
Definition: WMTemplate.cpp:808
virtual std::shared_ptr< WPropertyVariable< WPVBaseTypes::PV_STRING >::PropertyConstraint > clone()
Method to clone the constraint and create a new one with the correct dynamic type.
Definition: WMTemplate.cpp:820
Node callback to change the position of the shapes in the coordinate system of the scene.
Definition: WMTemplate.h:359
virtual void operator()(osg::Node *node, osg::NodeVisitor *nv)
operator () - called during the update traversal.
Definition: WMTemplate.cpp:788
WPropColor m_aColor
A color.
Definition: WMTemplate.h:196
osg::ref_ptr< WGEManagedGroupNode > m_rootNode
The root node used for this modules graphics.
Definition: WMTemplate.h:115
WPropPosition m_aPosition
A Property used to store some position.
Definition: WMTemplate.h:258
WPropDouble m_aDouble
A double value.
Definition: WMTemplate.h:181
WPropSelection m_aSingleSelection
A property allowing the user to select ONE item of some list.
Definition: WMTemplate.h:216
WPropSelection m_aSelectionOutput
A Property used to show some selection to the user.
Definition: WMTemplate.h:273
WPropTrigger m_aTriggerOutput
A Property used to show some trigger to the user.
Definition: WMTemplate.h:268
WPropColor m_aColorOutput
A Property used to show some color to the user.
Definition: WMTemplate.h:253
WPropFilename m_aFilenameOutput
A Property used to show some filename to the user.
Definition: WMTemplate.h:263
osg::ref_ptr< osg::Geode > m_geode
The geometry rendered by this module.
Definition: WMTemplate.h:120
WPropInterval m_anInterval
A property allowing you to define whole intervals.
Definition: WMTemplate.h:303
virtual const std::string getDescription() const
Gives back a description of this module.
Definition: WMTemplate.cpp:140
WPropTrigger m_exceptionTrigger
This causes an exception to be thrown on press to demonstrate how the GUI handles crashing modules.
Definition: WMTemplate.h:298
virtual void requirements()
Initialize requirements for this module.
Definition: WMTemplate.cpp:379
WPropInt m_aIntOutput
A property simply providing a int value to the outside world.
Definition: WMTemplate.h:243
std::shared_ptr< WItemSelection > m_possibleSelectionsUsingTypes
A list of items that can be selected using m_aSingleSelectionUsingTypes property.
Definition: WMTemplate.h:288
WPropInt m_anInteger
An integer value.
Definition: WMTemplate.h:171
WPropInt m_anIntegerClone
An integer value.
Definition: WMTemplate.h:176
WMTemplate()
Default constructor.
Definition: WMTemplate.cpp:79
std::shared_ptr< WModuleOutputData< WDataSetSingle > > m_output
The output connector used to provide the calculated data to other modules.
Definition: WMTemplate.h:136
virtual void properties()
Initialize the properties for this module.
Definition: WMTemplate.cpp:177
WPropTrigger m_hideButton
A Property used to show the callback mechanism avoiding the thread wake up on change.
Definition: WMTemplate.h:293
void hideButtonPressed()
The callback triggering the hide flag of m_aColor for demonstration.
Definition: WMTemplate.cpp:846
virtual const char ** getXPMIcon() const
Get the icon for this module in XPM format.
Definition: WMTemplate.cpp:125
WPropSelection m_aSingleSelectionUsingTypes
A property allowing the user to select ONE item.
Definition: WMTemplate.h:221
std::shared_ptr< WItemSelection > m_possibleSelections
A list of items that can be selected using m_aSingleSelection or m_aMultiSelection.
Definition: WMTemplate.h:278
WPropDouble m_aDoubleOutput
A property simply providing a double value to the outside world.
Definition: WMTemplate.h:238
WPropBool m_group1Bool
A nice feature trigger inside m_group1.
Definition: WMTemplate.h:166
WPropSelection m_aMultiSelection
A property allowing the user to select multiple elements of a list.
Definition: WMTemplate.h:226
virtual void moduleMain()
Entry point after loading the module.
Definition: WMTemplate.cpp:389
virtual void activate()
Callback for m_active.
Definition: WMTemplate.cpp:827
virtual std::shared_ptr< WModule > factory() const
Due to the prototype design pattern used to build modules, this method returns a new instance of this...
Definition: WMTemplate.cpp:93
WPropGroup m_group1a
To group properties, use WPropGroup.
Definition: WMTemplate.h:151
WPropInt m_aHiddenInt
A int property used to show hide/un-hide feature.
Definition: WMTemplate.h:201
virtual ~WMTemplate()
Destructor.
Definition: WMTemplate.cpp:88
WPropString m_aStringOutput
A property simply providing some text to the outside world.
Definition: WMTemplate.h:248
virtual const std::string getName() const
Gives back the name of this module.
Definition: WMTemplate.cpp:134
WPropGroup m_group1
To group properties, use WPropGroup.
Definition: WMTemplate.h:146
WGEShader::RefPtr m_shader
We want some nice shading effects, so we need a nice shader.
Definition: WMTemplate.h:313
WPropGroup m_group2
To group properties, use WPropGroup.
Definition: WMTemplate.h:156
std::shared_ptr< WModuleInputData< WDataSetSingle > > m_input
An input connector used to get datasets from other modules.
Definition: WMTemplate.h:131
WPropInt m_aIntegerOutput
A property simply providing a integer value to the outside world.
Definition: WMTemplate.h:233
WPropFilename m_aFile
A filename.
Definition: WMTemplate.h:191
WPropString m_aString
A string.
Definition: WMTemplate.h:186
WPropTrigger m_aTrigger
A trigger which can be used to trigger some kind of operation.
Definition: WMTemplate.h:211
virtual void connectors()
Initialize the connectors this module is using.
Definition: WMTemplate.cpp:146
WPropBool m_enableFeature
En/Disables an feature.
Definition: WMTemplate.h:161
std::shared_ptr< WCondition > m_propCondition
A condition used to notify about changes in several properties.
Definition: WMTemplate.h:141
WPropGroup m_aHiddenGroup
A group used to show that even hiding whole groups is possible.
Definition: WMTemplate.h:206
static PtrType createAndAdd(std::shared_ptr< WModule > module, std::string name="", std::string description="")
Convenience method to create a new instance of this in data connector with proper type and add it to ...
Class offering an instantiate-able data connection between modules.
Class representing a single module of OpenWalnut.
Definition: WModule.h:72
boost::filesystem::path m_localPath
The path where the module binary resides in.
Definition: WModule.h:734
Requirements m_requirements
The list of requirements.
Definition: WModule.h:754
virtual void properties()
Initialize properties in this function.
Definition: WModule.cpp:212
wlog::WStreamedLogger debugLog() const
Logger instance for comfortable debug logging.
Definition: WModule.cpp:575
virtual WModuleMetaInformation::ConstSPtr getMetaInformation() const
The meta information of this module.
Definition: WModule.cpp:229
std::shared_ptr< WProperties > m_properties
The property object for the module.
Definition: WModule.h:640
std::shared_ptr< WProperties > m_infoProperties
The property object for the module containing only module whose purpose is "PV_PURPOSE_INFORMNATION".
Definition: WModule.h:647
void ready()
Call this whenever your module is ready and can react on property changes.
Definition: WModule.cpp:505
WConditionSet m_moduleState
The internal state of the module.
Definition: WModule.h:703
virtual void activate()
Callback for m_active.
Definition: WModule.cpp:220
WPropBool m_active
True whenever the module should be active.
Definition: WModule.h:723
std::shared_ptr< WProgressCombiner > m_progress
Progress indicator used as parent for all progress' of this module.
Definition: WModule.h:652
wlog::WStreamedLogger infoLog() const
Logger instance for comfortable info logging.
Definition: WModule.cpp:565
virtual void connectors()
Initialize connectors in this function.
Definition: WModule.cpp:208
void waitRestored()
This method waits for the module to be restored completely.
Definition: WModule.cpp:625
static boost::filesystem::path getAppPath()
The path where the binary file resides in.
Definition: WPathHelper.cpp:93
This only is a 3d double vector.
Class managing progress inside of modules.
Definition: WProgress.h:42
A named property class with a concrete type.
void sleep(const int32_t t) const
Sets thread asleep.
WBoolFlag m_shutdownFlag
Condition getting fired whenever the thread should quit.
@ PV_TRIGGER_TRIGGERED
Trigger property: got triggered.
@ PV_TRIGGER_READY
Trigger property: is ready to be triggered (again)
std::string PV_STRING
base type used for every WPVString
void addTo(WPropFilename prop)
Add the PC_PATHEXISTS constraint to the property.
void addTo(WPropSelection prop)
Add the PC_NOTEMPTY constraint to the property.
void addTo(WPropFilename prop)
Add the PC_PATHEXISTS constraint to the property.
void addTo(WPropSelection prop)
Add the PC_SELECTONLYONE constraint to the property.
std::string toString(const T &value)
Convert a given value to a string.
Definition: WStringUtils.h:120