cgv
Loading...
Searching...
No Matches
base_provider.cxx
1#include "base_provider.h"
2#include <cgv/utils/file.h>
3#include <cgv/gui/application.h>
5#include <cgv/utils/tokenizer.h>
6#include <stack>
7#include <stdlib.h>
8
9using namespace cgv::base;
10using namespace cgv::signal;
11using namespace cgv::utils;
12
13namespace cgv {
14 namespace gui {
15
18{
19 instance = _instance;
20 textual_gui_definition = gui_def;
21 toggles = 0;
22 nr_toggles = -1;
23 is_named_gui_assignment_m = _is_named_gui_assignment;
24 parent_type = "align_group";
25}
26
29{
30 toggles = 0;
31 nr_toggles = -1;
32 instance = _instance;
33 parent_type = "align_group";
34 is_named_gui_assignment_m = true;
35 read_gui_definition(file_name);
36}
39{
40 if (toggles)
41 delete [] toggles;
42 toggles = 0;
43}
44
47{
48 return parent_type;
49}
50
53{
54 return
55 rh.reflect_member("parent_type", parent_type) &&
56 rh.reflect_member("parent_options", parent_options);
57}
58
59std::string base_provider::error_start(const char* ptr) const
60{
61 std::string error("error (");
62 const char* end = ptr;
63 if (&textual_gui_definition[textual_gui_definition.size()-1] < ptr)
64 end = &textual_gui_definition[textual_gui_definition.size()-1];
65
66 unsigned line_nr = 1;
67 for (const char* p = &textual_gui_definition[0]; p<end;++p)
68 if (*p == '\n')
69 ++line_nr;
70
71 error += to_string(line_nr);
72 error += ") : ";
73 return error;
74}
75
78{
79 if (instance)
80 return instance->get_type_name();
81 return "base_provider";
82}
83
86{
87 if (instance)
88 return instance->get_named();
89 return named_ptr();
90}
91
93void base_provider::read_gui_definition(const std::string& file_name)
94{
95 std::string content;
96 if (cgv::utils::file::read(file_name, content, true))
97 set_gui_definition(content);
98 else
99 std::cerr << "could not read gui definition from " << file_name.c_str() << std::endl;
100}
101
103void base_provider::set_gui_definition(const std::string& new_def)
104{
105 textual_gui_definition = new_def;
106
107 if (toggles)
108 delete [] toggles;
109 toggles = 0;
110 nr_toggles = -1;
111
113}
114
116const std::string& base_provider::get_gui_definition() const
117{
118 return textual_gui_definition;
119}
120
122void base_provider::set_instance(cgv::base::base_ptr _instance)
123{
124 instance = _instance;
126}
127
129cgv::base::base_ptr base_provider::get_instance() const
130{
131 return instance;
132}
133
134enum CommandId {
135 CMD_WINDOW, CMD_GROUP, CMD_ALIGN, CMD_DECORATOR, CMD_BUTTON, CMD_VIEW,
136 CMD_CONTROL, CMD_TREE_NODE, CMD_LAST };
137
139{
141 CommandId cmd_id;
143 const char* command;
145
151 const char* arguments;
153 unsigned nr_arguments;
156};
157
158const command_info* get_command_infos()
159{
160 static command_info infos[] = {
161 { CMD_WINDOW, "window", "iisSS", 5, true },
162 { CMD_GROUP, "group", "ssSS", 4, true },
163 { CMD_ALIGN, "align", "s", 1, false },
164 { CMD_DECORATOR, "decorator", "ssSS", 4, false },
165 { CMD_BUTTON, "button", "sSS", 3, false },
166 { CMD_VIEW, "view", "srSSS", 5, false },
167 { CMD_CONTROL, "control", "srSSS", 5, false },
168 { CMD_TREE_NODE, "tree_node", "sbiS", 4, true },
169 { CMD_LAST, "", "", 0, false }
170 };
171 return infos;
172}
173
174bool base_provider::find_member(const std::string& name, void*& member_ptr, std::string& member_type)
175{
176 member_ptr = instance->find_member_ptr(name, &member_type);
177 return member_ptr != 0;
178}
179
180
181void base_provider::parse_definition(ParsingTasks pt)
182{
183 std::vector<token> T;
184 std::stack<bool> visible;
185 std::stack<CommandId> block_cmd;
186 std::stack<gui_group_ptr> gui_group_stack;
187 visible.push(true);
188 bool expect_block_begin = false;
189
190 tokenizer(textual_gui_definition).set_sep(";,(){}").set_skip("'\"","'\"").bite_all(T);
191 const command_info* cis = get_command_infos();
192
193 unsigned i = 0;
194 do {
195 if (T[i] == ";") {
196 ++i;
197 continue;
198 }
199 if (expect_block_begin) {
200 if (T[i] == "{") {
201 expect_block_begin = false;
202 ++i;
203 continue;
204 }
205 else
206 std::cerr << error_start(T[i].begin) << "expected { after "
207 << get_command_infos()[block_cmd.top()].command
208 << " command to enclose child elements" << std::endl;
209 }
210 if (T[i] == "{") {
211 block_cmd.push(CMD_LAST);
212 std::cerr << error_start(T[i].begin) << "{ only allowed after window / group or tree_node command" << std::endl;
213 ++i;
214 continue;
215 }
216 expect_block_begin = false;
217 if (T[i] == "}") {
218 if (block_cmd.empty())
219 std::cerr << error_start(T[i].begin) << "found unmatched }" << std::endl;
220 else {
221 if (pt == PT_CREATE_GUI) {
222 switch (block_cmd.top()) {
223 case CMD_TREE_NODE : visible.pop(); break;
224 case CMD_GROUP :
225 case CMD_WINDOW : gui_group_stack.pop(); break;
226 default: break;
227 }
228 }
229 }
230 ++i;
231 continue;
232 }
233
234 // determine command
235 unsigned j = 0;
236 while (cis[j].cmd_id != CMD_LAST) {
237 if (T[i] == cis[j].command)
238 break;
239 ++j;
240 }
241 // continue if no command found
242 if (cis[j].cmd_id == CMD_LAST) {
243 std::cerr << error_start(T[i].begin) << "command " << to_string(T[i]).c_str() << " not known" << std::endl;
244 ++i;
245 continue;
246 }
247 const command_info& ci = cis[j];
248
249 // parse arguments
250 if (++i >= T.size()) {
251 std::cerr << error_start(T[i-1].begin) << "command " << ci.command << " incomplete" << std::endl;
252 break;
253 }
254 if (T[i] != "(") {
255 std::cerr << error_start(T[i].begin) << "expected ( after command " << ci.command << " but found " << to_string(T[i]).c_str() << " instead" << std::endl;
256 continue;
257 }
258 bool terminate = false;
259 std::vector<std::string> args;
260 bool last_was_argument = false;
261 while (!terminate) {
262 if (++i >= T.size())
263 break;
264 std::string arg_str;
265 if (T[i] == ",") {
266 if (!last_was_argument && args.size() < ci.nr_arguments)
267 args.push_back("");
268 last_was_argument = false;
269 }
270 else if (T[i] == ")") {
271 if (!last_was_argument && args.size() < ci.nr_arguments)
272 args.push_back("");
273 last_was_argument = false;
274 terminate = true;
275 }
276 else {
277 if (last_was_argument) {
278 args.back() += " ";
279 args.back() += to_string(T[i]);
280 }
281 else if (args.size() < ci.nr_arguments) {
282 if (to_lower(ci.arguments[args.size()]) == 's') {
283 if (*T[i].begin == '"' && T[i].size() > 1 && T[i].end[-1] == '"') {
284 ++T[i].begin;
285 --T[i].end;
286 }
287 if (*T[i].begin == '\'' && T[i].size() > 1 && T[i].end[-1] == '\'') {
288 ++T[i].begin;
289 --T[i].end;
290 }
291 }
292 args.push_back(to_string(T[i]));
293 }
294 last_was_argument = true;
295 }
296 }
297 if (!terminate) {
298 std::cerr << error_start(T[i-1].begin) << "did not find enclosing )" << std::endl;
299 break;
300 }
301
302 // check if necessary arguments are provided
303 if (args.size() < ci.nr_arguments) {
304 char c = ci.arguments[args.size()];
305 if (to_lower(c) == c) {
306 std::cerr << error_start(T[i-1].begin) << "not all necessary arguments provided for command " << ci.command << std::endl;
307 ++i;
308 continue;
309 }
310 }
311 expect_block_begin = get_command_infos()[ci.cmd_id].block_follows;
313 block_cmd.push(ci.cmd_id);
314 //
315 switch (pt) {
316 case PT_NR_TOGGLES:
317 if (ci.cmd_id == CMD_TREE_NODE)
318 ++nr_toggles;
319 break;
320 case PT_INIT_TOGGLES:
321 if (ci.cmd_id == CMD_TREE_NODE) {
322 if (args[1] == "true")
323 toggles[nr_toggles] = true;
324 else if (args[1] == "false")
325 toggles[nr_toggles] = false;
326 else {
327 toggles[nr_toggles] = true;
328 std::cerr << error_start(T[i-1].begin) << "error parsing initial toggle value which must be true or false" << std::endl;
329 }
330 ++nr_toggles;
331 }
332 break;
333 case PT_CREATE_GUI :
334 if (!visible.top()) {
335 if (ci.cmd_id == CMD_TREE_NODE)
336 ++nr_toggles;
337 }
338 else {
339 void* member_ptr;
340 std::string member_type;
342 if (!gui_group_stack.empty())
343 ggp = gui_group_stack.top();
344/*
345 std::cout << ggp->get_name() << ":" << get_command_infos()[ci.cmd_id].command << "(";
346 for (unsigned ai=0; ai<args.size(); ++ai) {
347 std::cout << args[ai];
348 if (ai < args.size()-1)
349 std::cout << ", ";
350 }
351 std::cout << ")" << std::endl;
352*/
353 switch (ci.cmd_id) {
354 case CMD_WINDOW :
355 {
357 atoi(args[1].c_str()), args[2],
358 args.size()>3 ? args[3] : std::string("viewer"));
359 if (args.size()>4)
360 wp->multi_set(args[4], true);
361 gui_group_stack.push(wp);
362 break;
363 }
364 break;
365 case CMD_GROUP :
366 gui_group_stack.push(ggp->add_group(args[0], args[1],
367 args.size()>2 ? args[2] : std::string(""),
368 args.size()>3 ? args[3] : std::string("\n")));
369 break;
370 case CMD_ALIGN :
371 ggp->align(args[0]);
372 break;
373 case CMD_DECORATOR :
374 ggp->add_decorator(args[0], args[1],
375 args.size()>2 ? args[2] : std::string(""),
376 args.size()>3 ? args[3] : std::string("\n"));
377 break;
378 case CMD_BUTTON :
379 ggp->add_button(args[0],
380 args.size()>1 ? args[1] : std::string(""),
381 args.size()>2 ? args[2] : std::string("\n"));
382 break;
383 case CMD_VIEW :
384 if (find_member(args[1],member_ptr, member_type))
385 ggp->add_view_void(args[0],member_ptr,member_type,
386 args.size()>2 ? args[2] : std::string(""),
387 args.size()>3 ? args[3] : std::string(""),
388 args.size()>4 ? args[4] : std::string("\n"));
389 break;
390 case CMD_CONTROL :
391 if (find_member(args[1],member_ptr, member_type)) {
392
394 1,
395 rebind1<
397 void,
398 1,
399 base,
400 void*
401 >,
402 void,
404 void*
405 >
406 >,
408 > of(
409 rebind1<
411 void,
412 1,
413 base,
414 void*
415 >,
416 void,
418 void*
419 >
420 >(mtd_functor<
421 void,
422 1,
423 base,
424 void*
425 >(instance.operator->(),
426 &base::on_set),
427 member_ptr)
428 );
429
430 ggp->add_control_void(args[0],member_ptr,0,member_type,
431 args.size()>2 ? args[2] : std::string(""),
432 args.size()>3 ? args[3] : std::string(""),
433 args.size()>4 ? args[4] : std::string("\n"), 0)
434 ->attach_to_value_change(of.clone());
435 }
436 break;
437 case CMD_TREE_NODE :
438 add_tree_node(args[0], toggles[nr_toggles], atoi(args[2].c_str()),
439 args.size() > 3 ? args[3] : std::string("\n"), ggp);
440 visible.push(toggles[nr_toggles]);
441 ++nr_toggles;
442 break;
443 }
444/*
445 std::cout << "[\n";
446 for (unsigned ci=0; ci<ggp->get_nr_children(); ++ci)
447 std::cout << " " << ggp->get_child(ci)->get_named()->get_name() << ":" << ggp->get_child(ci)->get_type_name() << "\n";
448 std::cout << "]" << std::endl;
449*/
450 }
451 }
452 ++i;
453 } while (i < T.size());
454}
455
458{
459 if (!parent_options.empty())
460 parent_group->multi_set(parent_options, true);
461 if (nr_toggles == -1) {
462 nr_toggles = 0;
463 parse_definition(PT_NR_TOGGLES);
464 if (nr_toggles > 0) {
465 if (toggles)
466 delete[] toggles;
467 toggles = new bool[nr_toggles];
468 nr_toggles = 0;
469 parse_definition(PT_INIT_TOGGLES);
470 }
471 }
472 nr_toggles = 0;
473 parse_definition(PT_CREATE_GUI);
474}
475
476 }
477}
More advanced text processing for splitting text into lines or tokens.
virtual bool end()
perform the leave part of the action on the current object
Definition action.cxx:48
base class for all classes that can be registered with support for dynamic properties (see also secti...
Definition base.h:75
virtual data::ref_ptr< named, true > get_named()
perform downcast to named
Definition base.cxx:37
virtual void on_set(void *member_ptr)
this callback is called when the set_void method has changed a member and can be overloaded in derive...
Definition base.cxx:210
virtual std::string get_type_name() const
overload to return the type name of this object. By default the type interface is queried over get_ty...
Definition base.cxx:241
void * find_member_ptr(const std::string &property_name, std::string *type_name=0)
find a member pointer by name.
Definition base.cxx:360
complete implementation of method actions that only call one method when entering a node
Definition action.h:113
bool begin()
uses call_method of base class method_action to call the method refered to by the stored method point...
Definition action.h:122
static window_ptr create_window(int w, int h, const std::string &title, const std::string &window_type="viewer")
create a window of the given type, where all gui implementations must support the type "viewer"
data::ref_ptr< cgv::base::named, true > get_named()
perform downcast to named
std::string get_parent_type() const
Returns the group type that should be used by the class embedding the gui of the provider.
~base_provider()
destruct base provider
base_provider(cgv::base::base_ptr _instance=cgv::base::base_ptr(), const std::string &gui_def="", bool _is_named_gui_assignment=false)
construct from instance and gui definition
void create_gui()
you must overload this for gui creation
bool self_reflect(cgv::reflect::reflection_handler &rh)
used for simple self reflection
std::string get_type_name() const
overload to return the type name of this object. By default the type interface is queried over get_ty...
bool add_tree_node(const std::string &label, bool &toggle, int level, const std::string &a="\n", gui_group_ptr ggp=gui_group_ptr())
add a collapsable node to the gui (deprecated)
Definition provider.cxx:183
virtual void post_recreate_gui()
delayed recreation of gui
Definition provider.cxx:509
gui_group_ptr parent_group
driver specific handle for the group gui element managing the gui built in the provider
Definition provider.h:69
the self reflection handler is passed to the virtual self_reflect() method of cgv::base::base.
bool reflect_member(const std::string &member_name, T &member_ref, bool hard_cast=false)
call this to reflect a member by member name and reference to the member.
the tokenizer allows to split text into tokens in a convenient way.
Definition tokenizer.h:68
tokenizer & set_sep(const std::string &sep, bool merge)
set the list of separators and specify whether succeeding separators are merged into single tokens
Definition tokenizer.cxx:59
tokenizer & set_skip(const std::string &open, const std::string &close)
set several character pairs that enclose tokens that are not split
Definition tokenizer.cxx:44
the base namespace holds the base hierarchy, support for plugin registration and signals
Definition action.cxx:4
data::ref_ptr< named, true > named_ptr
ref counted pointer to a node
Definition named.h:13
data::ref_ptr< window > window_ptr
ref counted pointer to &window
Definition window.h:31
data::ref_ptr< gui_group, true > gui_group_ptr
ref counted pointer to a gui group
Definition gui_group.h:31
data::ref_ptr< abst_control > control_ptr
ref counted pointer to abst control
Definition control.h:29
namespace that holds tools that dont fit any other namespace
std::string to_string(const std::string &v, unsigned int w, unsigned int p, bool)
specialization of conversion from string to strings
char to_lower(char c)
convert char to lower case
Definition scan.cxx:39
the cgv namespace
Definition print.h:11
a structure to store an analized command
Definition register.h:486
const char * arguments
lower case letters for necessary arguments and upper case for optional
bool block_follows
whether command is followed by a {}-block
CommandId cmd_id
id of command
unsigned nr_arguments
length of arguments string
const char * command
command name