2018-05-17 13:50:03 +00:00
# pragma once
# include <cgv/type/info/type_name.h>
# include <cgv/signal/rebind.h>
# include <cgv/utils/convert.h>
# include "gui_group.h"
# include "shortcut.h"
# include "gui_creator.h"
# include "lib_begin.h"
namespace cgv {
namespace gui {
/// helper struct to support value references as well as value references with index
template < typename T >
struct with_index_struct
{
const T & value ;
int index ;
with_index_struct ( const T & _value , int _index ) : value ( _value ) , index ( _index ) { }
} ;
/// helper function to support value references as well as value references with index for the tree_node functions of cgv::gui::provider
template < typename T >
with_index_struct < T > with_index ( const T & _value , int _index )
{
return with_index_struct < T > ( _value , _index ) ;
}
template < typename T >
struct with_index_traits
{
typedef const T * pointer_type ;
static pointer_type get_value_ptr ( const T & value ) { return & value ; }
static int get_index ( const T & value ) { return - 1 ; }
} ;
template < typename T >
struct with_index_traits < with_index_struct < T > >
{
typedef const T * pointer_type ;
static pointer_type get_value_ptr ( const with_index_struct < T > & value ) { return & value . value ; }
static int get_index ( const with_index_struct < T > & value ) { return value . index ; }
} ;
template < typename T >
typename with_index_traits < T > : : pointer_type wi_get_value_ptr ( const T & value )
{
return with_index_traits < T > : : get_value_ptr ( value ) ;
}
template < typename T >
int wi_get_index ( const T & value )
{
return with_index_traits < T > : : get_index ( value ) ;
}
/// derive from this class to provide a gui to the current viewer
class CGV_API provider : public cgv : : signal : : tacker
{
protected :
/**@name interface used by the parent gui*/
//@{
/// driver specific handle for the group gui element managing the gui built in the provider
gui_group_ptr parent_group ;
///
provider * parent_provider ;
/// the gui window sets the parent group through this method
void set_parent ( gui_group_ptr ) ;
/// update the parent group
void update_parent ( ) ;
/// make the gui group a friend class
friend class gui_group ;
//@}
public :
/// use the parent group to append to be managed elements that should be destroyed in a post_recreate_gui event
gui_group_ptr get_parent_group ( ) const { return parent_group ; }
/// add a newly created view to the group
view_ptr add_view_void ( const std : : string & label , const void * value_ptr , const std : : string & value_type , const std : : string & gui_type , const std : : string & options , const std : : string & align ) ;
/// add a newly created control to the group
control_ptr add_control_void ( const std : : string & label , void * value_ptr , abst_control_provider * acp , const std : : string & value_type , const std : : string & gui_type , const std : : string & options , const std : : string & align , void * user_data ) ;
/**@name creation of gui*/
//@{
/// send pure alignment information
void align ( const std : : string & _align ) ;
/// add a new group to the given parent group, not supported yet
// gui_group_ptr add_group(const std::string& label, const std::string& group_type, const std::string& options, const std::string& align);
//! Add group with the gui of another object inside.
/*! Add a new group, where the group elements are defined by another object that
must be derived from provider . You can use the same group types as in the add_group
method . */
gui_group_ptr add_object_gui ( base_ptr object , const std : : string & label , const std : : string & group_type , const std : : string & options , const std : : string & align ) ;
/// inline the gui of another object that must be derived from provider.
void inline_object_gui ( base_ptr object ) ;
/// add a newly created subgroup to the group
gui_group_ptr add_group ( const std : : string & label , const std : : string & group_type , const std : : string & options = " " , const std : : string & align = " \n " ) ;
/// add a newly created decorator to the group
base_ptr add_decorator ( const std : : string & label , const std : : string & decorator_type , const std : : string & options = " " , const std : : string & align = " \n " ) ;
/// use the current gui driver to append a new button with the given label
button_ptr add_button ( const std : : string & label , const std : : string & options = " " , const std : : string & align = " \n " ) ;
/// use this to add a new view to the gui with a given value type, gui type and init options
template < typename T >
data : : ref_ptr < view < T > > add_view ( const std : : string & label , const T & value , const std : : string & gui_type = " " , const std : : string & options = " " , const std : : string & align = " \n " ) {
if ( parent_group . empty ( ) )
return data : : ref_ptr < view < T > > ( ) ;
return parent_group - > add_view ( label , value , gui_type , options , align ) ;
}
/// use this to add a new control to the gui with a given value type, gui type and init options
template < typename T >
data : : ref_ptr < control < T > > add_control ( const std : : string & label , T & value , const std : : string & gui_type = " " , const std : : string & options = " " , const std : : string & align = " \n " ) {
if ( parent_group . empty ( ) )
return data : : ref_ptr < control < T > > ( ) ;
return parent_group - > add_control ( label , value , gui_type , options , align ) ;
}
/// use this to add a new control to the %gui, where the %control is implemented with a %control provider class
template < typename T >
data : : ref_ptr < control < T > > add_control ( const std : : string & label ,
control_provider < T > * provider , const std : : string & gui_type = " " ,
const std : : string & options = " " , const std : : string & align = " \n " , void * user_data = 0 ) {
if ( parent_group . empty ( ) )
return data : : ref_ptr < control < T > > ( ) ;
return parent_group - > add_control ( label , provider , gui_type , options , align , user_data ) ;
}
//! add control with callback to cgv::base::on_set method on cgv::gui::control::value_change
/*! use this method to add a control of a member and a callback to the on_set
method of the cgv : : base : : base class . */
template < typename T >
void add_member_control ( cgv : : base : : base * base_ptr , const std : : string & label , T & value , const std : : string & gui_type = " " , const std : : string & options = " " , const std : : string & align = " \n " ) {
connect_copy ( add_control ( label , value , gui_type , options , align ) - > value_change ,
cgv : : signal : : rebind ( base_ptr , & cgv : : base : : base : : on_set , & value ) ) ;
}
//! add a collapsable node to the gui (deprecated)
/*! This method is one possibility to support tree like guis with nodes that can be opened or closed.
The other prefarable possibitly builds on the functions begin_tree_node ( ) and end_tree_node ( ) .
Each node is represented by a heading with the text provided in the first parameter and of heading
level specified in the first parameter . The state of the node is stored in a boolean variable
" toggle " that must be supplied by the implementation of the provider . The toggle needs to be
initialized in the constructor and is used in the create_gui method to only provide the gui of
the subtree if toggle is true . Every time the status of the node is changed , the whole gui is
rebuild with the post_recreate_gui method . The value of the toggle is also the return parameter
of add_tree_node such the typical code inside the create_gui method looks
like
\ code
if ( add_tree_node ( " Node " , toggle , 2 ) ) {
align ( " \a " ) ; // indent gui elements of tree node
// create gui of subtree
align ( " \b " ) ; // undo indentation
}
\ endcode
*/
bool add_tree_node ( const std : : string & label , bool & toggle , int level , const std : : string & a = " \n " , gui_group_ptr ggp = gui_group_ptr ( ) ) ;
//! Begin a sub tree of a tree structured gui.
/*! This function addes a toggle button and a heading for the tree node.
The toggle button can be used to show or hide the subtree below the tree node . The heading shows simply the label
parameter . The function returns the visibility state of the subtree below the tree node . Therefore its contents
should only be specified if the function returns true . In that case one needs to terminate the gui elements added
for the tree node with the end_tree_node function . A typical example would be
\ code
if ( begin_tree_node ( " Node " , composed_value ) ) {
align ( " \a " ) ; // indent gui elements of tree node
// create gui of composed_value
align ( " \b " ) ; // undo indentation
end_tree_node ( composed_value ) ;
}
\ endcode
The state of the toggle button is attached to a boolean variable that is globally managed by the provider .
For this the reference to a value controlled by the tree node is specified . The pointer to the controlled value is
used as key for a map that manages the toggle states of all tree node buttons . If there is no superior structure
whose value is controlled by the tree node , one can specify any of the values controled by the tree node . It is just
important that no two tree nodes use the same value and that the pointer to the value cannot change . The latter is
for example the case , when one uses an entry in a std : : vector that can change size and reallocate its values . Then
one should use the std : : vector itself as value . In order to be able to distinguish the different elements of a vector
one can extend the key from a value reference to a pair of a value reference plus an index . The index is then the index
of the vector element . This is done by specifying with_index ( value , idx ) in the value argument . An example could look as follows :
\ code
if ( begin_tree_node ( " Node " , vec ) ) {
align ( " \a " ) ; // indent gui elements of tree node
for ( unsigned i = 0 ; i < vec . size ; + + i ) {
if ( begin_tree_node ( std : : string ( " element " ) + cgv : : utils : : to_string ( i ) , with_index ( vec , i ) ) ) {
align ( " \a " ) ; // indent gui elements of tree node for vector element
// create gui of vector element
align ( " \b " ) ; // undo indentation
end_tree_node ( with_index ( vec , i ) ) ;
}
}
align ( " \b " ) ; // undo indentation
end_tree_node ( vec ) ;
}
\ endcode
*/
template < typename T >
bool begin_tree_node ( const std : : string & label , const T & value , bool initial_visibility = false , const std : : string & options = " " , gui_group_ptr ggp = gui_group_ptr ( ) ) { return begin_tree_node_void ( label , wi_get_value_ptr ( value ) , wi_get_index ( value ) , initial_visibility , options , ggp ) ; }
/// template specialization that allows to specify value reference plus node_instance by using the result of the function with_instance(value,idx) for the value argument
//! finish a sub tree begun with begin_tree_node
/*! This functions should be called only if the corresponding call to begin_tree_node returned true. */
template < typename T >
void end_tree_node ( const T & value ) { end_tree_node_void ( wi_get_value_ptr ( value ) , wi_get_index ( value ) ) ; }
/// return whether the sub tree attached to a value is visible
template < typename T >
bool is_tree_node_visible ( const T & value ) const { return is_tree_node_visible_void ( wi_get_value_ptr ( value ) , wi_get_index ( value ) ) ; }
/// set the visibility status of sub tree attached to a value. This calls the post_recreate method if needed.
template < typename T >
void set_tree_node_visibility ( const T & value , bool is_visible ) { set_tree_node_visibility_void ( wi_get_value_ptr ( value ) , wi_get_index ( value ) , is_visible ) ; }
/// void version of the templated functions
2018-05-17 14:01:02 +00:00
bool begin_tree_node_void ( const std : : string & label , const void * value_ptr , int index = - 1 , bool initial_visibility = false , const std : : string & options = " " , gui_group_ptr ggp = gui_group_ptr ( ) ) ;
2018-05-17 13:50:03 +00:00
///
2018-05-17 14:01:02 +00:00
void end_tree_node_void ( const void * value_ptr , int index = - 1 ) ;
2018-05-17 13:50:03 +00:00
///
bool is_tree_node_visible_void ( const void * value_ptr , int index ) const ;
///
void set_tree_node_visibility_void ( const void * value_ptr , int index , bool is_visible ) ;
//! Add a composed gui of the given gui_type for the given value.
/*! This function returns false if no cgv::base::gui_creator has been registered for the given gui_type.
The plugin cg_ext contains registers gui_creators for the most important types of the framework .
The supported values for the options parameter are specific for the gui_type . Currently these are not
documented and can only be found in the source code of the cg_ext plugin .
*/
template < typename T >
bool add_gui ( const std : : string & label , T & value , const std : : string & gui_type = " " , const std : : string & options = " " )
{
return cgv : : gui : : create_gui ( this , label , & value , cgv : : type : : info : : type_name < T > : : get_name ( ) , gui_type , options , 0 ) ;
}
//@}
protected :
/**@name callbacks*/
//@{
/// called by selection_change_cb whenever the gui of this provider is selected
virtual void on_select ( ) ;
/// called by selection_change_cb whenever the gui of this provider is deselected
virtual void on_deselect ( ) ;
/// this is called by the gui group when the selection changes
virtual void selection_change_cb ( cgv : : base : : base_ptr new_child , bool selected ) ;
//@}
public :
/// default construction
provider ( ) ;
/// ensure to remove posted recreation callbacks
~ provider ( ) ;
//! Derive a name for this instance that can be used in the gui as heading.
/*! This method uses the following strategy to automatically determine
the name shown in guis for a provider instance :
- try to cast the object into cgv : : base : : named , if successful ,
use get_name ( ) method
- check whether get_menu_path ( ) results in a path or name . In
case of a path , use the last entry of the path as name .
- try to cast to cgv : : base : : base and use get_type_name ( ) .
- return " unnamed " otherwise
*/
virtual std : : string get_gui_name ( ) const ;
//! Returns the group type that should be used by the class embedding the gui of the provider.
/*! The default is to use a group of type "align_group". Overload this virtual method to use a
different group type , such as layout group . */
virtual std : : string get_parent_type ( ) const ;
/// call this to update all views and controls of a member
virtual void update_member ( void * member_ptr ) ;
/// call this to update all views and controls of all member
virtual void update_all_members ( ) ;
/// return a path in the main menu to select the gui
virtual std : : string get_menu_path ( ) const ;
/// return a shortcut to activate the gui without menu navigation
virtual shortcut get_shortcut ( ) const ;
/// you must overload this for gui creation
virtual void create_gui ( ) = 0 ;
//! Recreate the gui of this instance right now.
/*! Use this method to recreate the gui, dont call create gui directly.
Be careful when calling the method from a functor that is attached to
a gui element generated by this provider . This can cause the gui element
to be destroyed before the callback triggering the recreate_gui method
has been completely finished , what might make the program crash . Use the
post_recreate_gui method instead . */
void recreate_gui ( ) ;
//! delayed recreation of gui
/*! schedule the recreation of the gui for the next time the program is idle.
This mechanism is implemented in a thread save way . */
virtual void post_recreate_gui ( ) ;
/**@name update of gui*/
//@{
/// remove a single element from the gui
void remove_element ( base_ptr ) ;
/// this method removes all elements from the gui and can be used in a method that rebuilds the complete gui
void remove_all_elements ( ) ;
//! find a gui element by name in the current group, return empty pointer if not found
base_ptr find_element ( const std : : string & name ) ;
//! find a view of a given class member
/*! find the next view of the given value in the current group. If the index
pointer is given , start at the index to which the pointer points and set
this index to the index of the child index of the found view */
template < typename T >
data : : ref_ptr < view < T > > find_view ( const T & value , int * idx_ptr = 0 ) {
if ( parent_group . empty ( ) )
return data : : ref_ptr < view < T > > ( ) ;
return parent_group - > find_view ( value , idx_ptr ) ;
}
//! find a control of a given class member
/** find the next control of the given value in the current group. If the index
pointer is given , start at the index to which the pointer points and set
this index to the index of the child index of the found control */
template < typename T >
data : : ref_ptr < control < T > > find_control ( T & value , int * idx_ptr = 0 ) {
if ( parent_group . empty ( ) )
return data : : ref_ptr < control < T > > ( ) ;
return parent_group - > find_control ( value , idx_ptr ) ;
}
/// access to control of untyped member pointer
control_ptr find_control_void ( void * value_ptr , int * idx_ptr ) ;
/// access to view of untyped member pointer
view_ptr find_view_void ( void * value_ptr , int * idx_ptr ) ;
//@}
} ;
}
}
# include <cgv/config/lib_end.h>