325 lines
No EOL
16 KiB
C++
325 lines
No EOL
16 KiB
C++
#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
|
|
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());
|
|
///
|
|
void end_tree_node_void(const void* value_ptr, int index = -1);
|
|
///
|
|
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> |