GCC Code Coverage Report


Directory: ./
File: lib/geogram_gfx/gui/command.h
Date: 2026-09-07 02:37:58
Exec Total Coverage
Lines: 0 167 0.0%
Functions: 0 124 0.0%
Branches: 0 226 0.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40 #ifndef GEOGRAM_GFX_GUI_COMMAND
41 #define GEOGRAM_GFX_GUI_COMMAND
42
43 #include <geogram_gfx/basic/common.h>
44 #include <geogram/basic/logger.h>
45 #include <geogram/basic/string.h>
46
47 /**
48 * \file geogram_gfx/gui/command.h
49 * \brief A simple system to interface C++ functions
50 * with a ImGui interface. Used mainly by geobox.
51 */
52
53 namespace GEO {
54
55 /**
56 * \brief Abstract class for calling functions or
57 * calling member functions.
58 * \details Used internally by Command.
59 */
60 class GEOGRAM_GFX_API CommandInvoker : public Counted {
61 public:
62 /**
63 * \brief CommandInvoker constructor.
64 */
65 CommandInvoker();
66
67 /**
68 * \brief CommandInvoker destructor.
69 */
70 ~CommandInvoker() override;
71
72 /**
73 * \brief Invokes the target function.
74 */
75 virtual void invoke() = 0;
76
77 /**
78 * \brief Creates the arguments in the target
79 * command.
80 * \details This function is used when client code
81 * did not provide a function prototype to the
82 * constructor of Command.
83 */
84 virtual void auto_create_args() = 0;
85 };
86
87 /**
88 * \brief Automatic reference-counted pointer to a CommandInvoker.
89 * \details Used internally by Command.
90 */
91 typedef SmartPointer<CommandInvoker> CommandInvoker_var;
92
93 /*****************************************************************/
94
95 /**
96 * \brief Manages the GUI of a command with ImGUI.
97 * \details Client code will only need to use set_current()
98 */
99 class GEOGRAM_GFX_API Command : public Counted {
100 public:
101
102 /**
103 * \brief Binds the current command to a function.
104 * \details This makes the command dialog box display
105 * parameters that correspond to the arguments of the function,
106 * and whenever the 'apply' button is pushed, the function is
107 * invoked with the arguments.
108 * Example:
109 * \code
110 * void my_command_impl(float x, float y, bool normalize) {
111 * ... do something
112 * }
113 * ...
114 * ...
115 * if(ImGui::MenuItem("my command")) {
116 * GEO::Command::set_current(
117 * "void my_command_impl(float x, float y, bool normalize)",
118 * &my_command_impl
119 * )
120 * }
121 * \endcode
122 * The first argument (the string with the function prototype) is
123 * necessary to retrieve the names of the parameters. In addition,
124 * default values and tooltips may be specified, as follows:
125 * \code
126 * GEO::Command::set_current(
127 * "void my_command_impl( "
128 * " float x=0 [this is the x coordinate], "
129 * " float y=0 [this is the y coordinate], "
130 * " bool normalize=true [normalize the vector]"
131 * ") [does something with a vector] ",
132 * &my_command_impl
133 * )
134 * \endcode
135 * Each text in the square brackets corresponds to a tooltip attached
136 * to an argument. There can be also one for the function. The default
137 * values are those that are obtained at initialization, or those that
138 * are set when the 'default' button is pushed.
139 * \tparam FPTR function pointer type
140 * \param[in] prototype a string with the prototype of the function,
141 * as written in C++. In addition, the function and each parameter
142 * can be documented in square brackets.
143 * \param[in] tfun the function pointer.
144 */
145 template<class FPTR> static void set_current(
146 const std::string& prototype, FPTR tfun
147 );
148
149 /**
150 * \brief Binds the current command to a member function
151 * of an object.
152 * \details This makes the command dialog box display
153 * parameters that correspond to the arguments of the function,
154 * and whenever the 'apply' button is pushed, the function is
155 * invoked with the arguments.
156 * Example:
157 * \code
158 * class MyCommands {
159 * void my_command_impl(float x, float y, bool normalize) {
160 * ... do something
161 * }
162 * };
163 * MyCommands my_commands;
164 * ...
165 * ...
166 * if(ImGui::MenuItem("my command")) {
167 * GEO::Command::set_current(
168 * "void my_command_impl(float x, float y, bool normalize)",
169 * &my_commands, &MyCommands::my_command_impl
170 * )
171 * }
172 * \endcode
173 * The first argument (the string with the function prototype) is
174 * necessary to retrieve the names of the parameters. In addition,
175 * default values and tooltips may be specified, as follows:
176 * \code
177 * GEO::Command::set_current(
178 * "void my_command_impl( "
179 * " float x=0 [this is the x coordinate], "
180 * " float y=0 [this is the y coordinate], "
181 * " bool normalize=true [normalize the vector]"
182 * ") [does something with a vector] ",
183 * &my_commands, &MyCommands::my_command_impl
184 * )
185 * \endcode
186 * Each text in the square brackets corresponds to a tooltip attached
187 * to an argument. There can be also one for the function. The default
188 * values are those that are obtained at initialization, or those that
189 * are set when the 'default' button is pushed.
190 * \tparam T object class
191 * \tparam TFPTR function pointer type, should be a member function
192 * of class T
193 * \param[in] prototype a string with the prototype of the function,
194 * as written in C++. In addition, the function and each parameter
195 * can be documented in square brackets.
196 * \param[in] target a pointer to the object, of class T
197 * \param[in] tfun the pointer to the member function
198 */
199 template<class T, class TFPTR> static void set_current(
200 const std::string& prototype, T* target, TFPTR tfun
201 );
202
203 /**
204 * \brief Flushes the potentially queued command invokation.
205 * \details When the user pushes the 'apply' button, the command
206 * is not invoked immediatly, because we are still in the ImGUI
207 * handling function. This function is called by the framework
208 * at the end of the frame, when the ImGUI handler is already
209 * finished. It can potentially re-trigger frame rendering operations,
210 * through the Logger and ProgressLogger. Without this mechanism,
211 * it would nest two ImGUI handlers, which is not allowed.
212 */
213 static void flush_queue();
214
215
216 /**
217 * \brief Replays the latest invoked command
218 */
219 static void replay_latest();
220
221 /**
222 * \brief Command constructor.
223 * \param[in] prototype a const reference to a string with
224 * the prototype of the function that implements the callback,
225 * as declared in the C++ sources.
226 * \note Regular client code should not need to use this function.
227 */
228 Command(const std::string& prototype);
229
230
231 /**
232 * \brief Gets the name of this command.
233 * \return a const reference to the name of this command.
234 */
235 const std::string& name() const {
236 return name_;
237 }
238
239 /**
240 * \brief Sets the invoker.
241 * \details The invoker is used internally to transmit the stored
242 * arguments to the parameters of a function.
243 * \param[in] invoker a pointer to the CommandInvoker. Ownership
244 * is transferred to this Command.
245 * \note Regular client code should not need to use this function.
246 */
247 void set_invoker(CommandInvoker* invoker) {
248 invoker_ = invoker;
249 if(auto_create_args_) {
250 invoker_->auto_create_args();
251 auto_create_args_ = false;
252 }
253 }
254
255 /**
256 * \brief Command destructor.
257 */
258 ~Command() override;
259
260 /**
261 * \brief Tests whether this Command is visible.
262 * \retval true if this Command is visible
263 * \retval false otherwise
264 */
265 bool is_visible() const {
266 return visible_;
267 }
268
269 /**
270 * \brief Gets a pointer to the visibility flag of
271 * this command.
272 * \return a pointer to the visibility flag
273 */
274 bool* is_visible_ptr() {
275 return &visible_;
276 }
277
278 /**
279 * \brief Displays and manages the GUI of this
280 * Command.
281 * \note Regular client code should not need to use this function.
282 */
283 virtual void draw();
284
285 /**
286 * \brief Restores default parameter values for
287 * all parameters.
288 * \details This is the function that is called when the user pushes
289 * the 'default' button.
290 * \note Regular client code should not need to use this function.
291 */
292 virtual void reset_factory_settings();
293
294 /**
295 * \brief Gets the value of the parameters and
296 * does the task.
297 * \details This is the function that is called when the user pushes
298 * the 'apply' button. It does not invoke the command immediatly,
299 * the command invocation is queued, and executed later by
300 * Command::flush_queue(), once we are no longer in the ImGui
301 * handler (else we would have two nested ImGui handlers, which is
302 * not correct).
303 * \note Regular client code should not need to use this function.
304 */
305 virtual void apply() ;
306
307 /**
308 * \brief Gets the current command.
309 * \return a pointer to the current command
310 * \note Regular client code should not need to use this function.
311 */
312 static Command* current() {
313 return current_;
314 }
315
316
317 /**
318 * \brief Gets the latest command.
319 * \return a pointer to the command that was last executed.
320 * \details Used by playback mechanism ('F5' in applications).
321 */
322 static Command* latest() {
323 return latest_;
324 }
325
326 /**
327 * \brief Gets the queued command.
328 * \return a pointer to the command that is about to be executed
329 */
330 static Command* queued() {
331 return queued_;
332 }
333
334
335 /**
336 * \brief Resets the current command.
337 */
338 static void reset_current() {
339 current_.reset();
340 }
341
342 /**
343 * \brief Sets the current command.
344 * \param[in] command a pointer to the command
345 * to be set as current
346 * \note Regular client code should not need to use this function.
347 */
348 static void set_current(Command* command) {
349 current_ = command;
350 command->visible_ = true;
351 }
352
353 /**
354 * \brief Gets the value of a boolean argument by index.
355 * \details If the index is out of range, or if the
356 * argument is not of the correct type, then an assertion
357 * failure is triggered.
358 * \param[in] i the index of the argument
359 * \return the value of the argument
360 * \note Regular client code should not need to use this function.
361 */
362 bool bool_arg_by_index(index_t i) const {
363 const Arg& arg = find_arg_by_index(i);
364 geo_assert(arg.type == Arg::ARG_BOOL);
365 return arg.val.bool_val;
366 }
367
368 /**
369 * \brief Gets the value of an integer argument by index.
370 * \details If the index is out of range, or if the
371 * argument is not of the correct type, then an assertion
372 * failure is triggered.
373 * \param[in] i the index of the argument
374 * \return the value of the argument
375 * \note Regular client code should not need to use this function.
376 */
377 int int_arg_by_index(index_t i) const;
378
379 /**
380 * \brief Gets the value of an unsigned integer argument by index.
381 * \details If the index is out of range, or if the
382 * argument is not of the correct type, then an assertion
383 * failure is triggered. If the stored value is negative, then
384 * it is clamped to 0, and a warning message is displayed on
385 * the console.
386 * \param[in] i the index of the argument
387 * \return the value of the argument
388 * \note Regular client code should not need to use this function.
389 */
390 unsigned int uint_arg_by_index(index_t i) const;
391
392 /**
393 * \brief Gets the value of a floating-point argument by index.
394 * \details If the index is out of range, or if the
395 * argument is not of the correct type, then an assertion
396 * failure is triggered.
397 * \param[in] i the index of the argument
398 * \return the value of the argument
399 * \note Regular client code should not need to use this function.
400 */
401 float float_arg_by_index(index_t i) const {
402 const Arg& arg = find_arg_by_index(i);
403 geo_assert(arg.type == Arg::ARG_FLOAT);
404 return arg.val.float_val;
405 }
406
407 /**
408 * \brief Gets the value of a floating-point argument by index
409 * and converts it to a double.
410 * \details If the index is out of range, or if the
411 * argument is not of the correct type, then an assertion
412 * failure is triggered.
413 * \param[in] i the index of the argument
414 * \return the value of the argument
415 * \note Regular client code should not need to use this function.
416 */
417 double double_arg_by_index(index_t i) const {
418 return double(float_arg_by_index(i));
419 }
420
421 /**
422 * \brief Gets the value of a string argument by index.
423 * \details If the index is out of range, or if the
424 * argument is not of the correct type, then an assertion
425 * failure is triggered.
426 * \param[in] i the index of the argument
427 * \return the value of the argument
428 * \note Regular client code should not need to use this function.
429 */
430 std::string string_arg_by_index(index_t i) const {
431 const Arg& arg = find_arg_by_index(i);
432 geo_assert(arg.type == Arg::ARG_STRING);
433 return std::string(arg.val.string_val);
434 }
435
436 /**
437 * \brief Gets the value of an argument by index.
438 * \details This function is generic, and has several
439 * specializations for bool, int, unsigned int, float, double and
440 * std::string. For all other types, an assertion failure is
441 * triggered.
442 * \tparam T type of the argument
443 * \param[in] i the index of the argument
444 * \param[out] val a reference to the argument
445 * \note Regular client code should not need to use this function.
446 */
447 template<class T> void get_arg_by_index(index_t i, T& val) {
448 geo_argused(val);
449 Logger::err("Cmd") << "Attempted to read argument #"
450 << i
451 << " to variable of unknown type"
452 << std::endl;
453 geo_assert_not_reached;
454 }
455
456 /***************************************************************/
457
458 /**
459 * \brief Invokes a member function with the stored arguments.
460 * \details If the type or number of stored arguments do not match
461 * the function pointer, then an assertion failure is triggered.
462 * \tparam T class of the target object
463 * \param[in] target the target object
464 * \param[in] fptr the pointer to the member function to be called.
465 * \note Used by internal CommandInvoker mechanism.
466 */
467 template <class T> void invoke(
468 T* target, void (T::*fptr)(void)
469 ) {
470 this->assert_nb_args_matches(0);
471 if(target != nullptr && fptr != nullptr) {
472 (*target.*fptr)();
473 }
474 }
475
476 /**
477 * \brief Invokes a member function with the stored arguments.
478 * \details If the type or number of stored arguments do not match
479 * the function pointer, then an assertion failure is triggered.
480 * \tparam T class of the target object
481 * \tparam ARG0 type of the argument
482 * \param[in] target the target object
483 * \param[in] fptr the pointer to the member function to be called.
484 * \note Used by internal CommandInvoker mechanism.
485 */
486 template <
487 class T,
488 class ARG0
489 > void invoke(
490 T* target,
491 void (T::*fptr)(ARG0)
492 ) {
493 this->assert_nb_args_matches(1);
494 ARG0 a0;
495 this->get_arg_by_index(0,a0);
496 if(target != nullptr && fptr != nullptr) {
497 (*target.*fptr)(a0);
498 }
499 }
500
501 /**
502 * \brief Invokes a member function with the stored arguments.
503 * \details If the type or number of stored arguments do not match
504 * the function pointer, then an assertion failure is triggered.
505 * \tparam T class of the target object
506 * \tparam ARG0 , ARG1 types of the arguments
507 * \param[in] target the target object
508 * \param[in] fptr the pointer to the member function to be called.
509 * \note Used by internal CommandInvoker mechanism.
510 */
511 template <
512 class T,
513 class ARG0, class ARG1
514 > void invoke(
515 T* target,
516 void (T::*fptr)(ARG0,ARG1)
517 ) {
518 this->assert_nb_args_matches(2);
519 ARG0 a0;
520 this->get_arg_by_index(0,a0);
521 ARG1 a1;
522 this->get_arg_by_index(1,a1);
523 if(target != nullptr && fptr != nullptr) {
524 (*target.*fptr)(a0,a1);
525 }
526 }
527
528 /**
529 * \brief Invokes a member function with the stored arguments.
530 * \details If the type or number of stored arguments do not match
531 * the function pointer, then an assertion failure is triggered.
532 * \tparam T class of the target object
533 * \tparam ARG0 , ARG1 , ARG2 types of the arguments
534 * \param[in] target the target object
535 * \param[in] fptr the pointer to the member function to be called.
536 * \note Used by internal CommandInvoker mechanism.
537 */
538
539 template <
540 class T,
541 class ARG0, class ARG1, class ARG2
542 > void invoke(
543 T* target,
544 void (T::*fptr)(ARG0,ARG1,ARG2)
545 ) {
546 this->assert_nb_args_matches(3);
547 ARG0 a0;
548 this->get_arg_by_index(0,a0);
549 ARG1 a1;
550 this->get_arg_by_index(1,a1);
551 ARG2 a2;
552 this->get_arg_by_index(2,a2);
553 if(target != nullptr && fptr != nullptr) {
554 (*target.*fptr)(a0,a1,a2);
555 }
556 }
557
558 /**
559 * \brief Invokes a member function with the stored arguments.
560 * \details If the type or number of stored arguments do not match
561 * the function pointer, then an assertion failure is triggered.
562 * \tparam T class of the target object
563 * \tparam ARG0 , ARG1 , ARG2 , ARG3 types of the arguments
564 * \param[in] target the target object
565 * \param[in] fptr the pointer to the member function to be called.
566 * \note Used by internal CommandInvoker mechanism.
567 */
568
569 template <
570 class T,
571 class ARG0, class ARG1, class ARG2, class ARG3
572 > void invoke(
573 T* target,
574 void (T::*fptr)(ARG0,ARG1,ARG2,ARG3)
575 ) {
576 this->assert_nb_args_matches(4);
577 ARG0 a0;
578 this->get_arg_by_index(0,a0);
579 ARG1 a1;
580 this->get_arg_by_index(1,a1);
581 ARG2 a2;
582 this->get_arg_by_index(2,a2);
583 ARG3 a3;
584 this->get_arg_by_index(3,a3);
585 if(target != nullptr && fptr != nullptr) {
586 (*target.*fptr)(a0,a1,a2,a3);
587 }
588 }
589
590 /**
591 * \brief Invokes a member function with the stored arguments.
592 * \details If the type or number of stored arguments do not match
593 * the function pointer, then an assertion failure is triggered.
594 * \tparam T class of the target object
595 * \tparam ARG0 , ARG4 types of the arguments
596 * \param[in] target the target object
597 * \param[in] fptr the pointer to the member function to be called.
598 * \note Used by internal CommandInvoker mechanism.
599 */
600
601 template <
602 class T,
603 class ARG0, class ARG1, class ARG2, class ARG3,
604 class ARG4
605 > void invoke(
606 T* target,
607 void (T::*fptr)(ARG0,ARG1,ARG2,ARG3,ARG4)
608 ) {
609 this->assert_nb_args_matches(5);
610 ARG0 a0;
611 this->get_arg_by_index(0,a0);
612 ARG1 a1;
613 this->get_arg_by_index(1,a1);
614 ARG2 a2;
615 this->get_arg_by_index(2,a2);
616 ARG3 a3;
617 this->get_arg_by_index(3,a3);
618 ARG4 a4;
619 this->get_arg_by_index(4,a4);
620 if(target != nullptr && fptr != nullptr) {
621 (*target.*fptr)(a0,a1,a2,a3,a4);
622 }
623 }
624
625 /**
626 * \brief Invokes a member function with the stored arguments.
627 * \details If the type or number of stored arguments do not match
628 * the function pointer, then an assertion failure is triggered.
629 * \tparam T class of the target object
630 * \tparam ARG0 , ARG5 types of the arguments
631 * \param[in] target the target object
632 * \param[in] fptr the pointer to the member function to be called.
633 * \note Used by internal CommandInvoker mechanism.
634 */
635
636 template <
637 class T,
638 class ARG0, class ARG1, class ARG2, class ARG3,
639 class ARG4, class ARG5
640 > void invoke(
641 T* target,
642 void (T::*fptr)(ARG0,ARG1,ARG2,ARG3,ARG4,ARG5)
643 ) {
644 this->assert_nb_args_matches(6);
645 ARG0 a0;
646 this->get_arg_by_index(0,a0);
647 ARG1 a1;
648 this->get_arg_by_index(1,a1);
649 ARG2 a2;
650 this->get_arg_by_index(2,a2);
651 ARG3 a3;
652 this->get_arg_by_index(3,a3);
653 ARG4 a4;
654 this->get_arg_by_index(4,a4);
655 ARG5 a5;
656 this->get_arg_by_index(5,a5);
657 if(target != nullptr && fptr != nullptr) {
658 (*target.*fptr)(a0,a1,a2,a3,a4,a5);
659 }
660 }
661
662 /**
663 * \brief Invokes a member function with the stored arguments.
664 * \details If the type or number of stored arguments do not match
665 * the function pointer, then an assertion failure is triggered.
666 * \tparam T class of the target object
667 * \tparam ARG0 , ARG6 types of the arguments
668 * \param[in] target the target object
669 * \param[in] fptr the pointer to the member function to be called.
670 * \note Used by internal CommandInvoker mechanism.
671 */
672
673 template <
674 class T,
675 class ARG0, class ARG1, class ARG2, class ARG3,
676 class ARG4, class ARG5, class ARG6
677 > void invoke(
678 T* target,
679 void (T::*fptr)(ARG0,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6)
680 ) {
681 this->assert_nb_args_matches(7);
682 ARG0 a0;
683 this->get_arg_by_index(0,a0);
684 ARG1 a1;
685 this->get_arg_by_index(1,a1);
686 ARG2 a2;
687 this->get_arg_by_index(2,a2);
688 ARG3 a3;
689 this->get_arg_by_index(3,a3);
690 ARG4 a4;
691 this->get_arg_by_index(4,a4);
692 ARG5 a5;
693 this->get_arg_by_index(5,a5);
694 ARG6 a6;
695 this->get_arg_by_index(6,a6);
696 if(target != nullptr && fptr != nullptr) {
697 (*target.*fptr)(a0,a1,a2,a3,a4,a5,a6);
698 }
699 }
700
701 /**
702 * \brief Invokes a member function with the stored arguments.
703 * \details If the type or number of stored arguments do not match
704 * the function pointer, then an assertion failure is triggered.
705 * \tparam T class of the target object
706 * \tparam ARG0 , ARG7 types of the arguments
707 * \param[in] target the target object
708 * \param[in] fptr the pointer to the member function to be called.
709 * \note Used by internal CommandInvoker mechanism.
710 */
711
712 template <
713 class T,
714 class ARG0, class ARG1, class ARG2, class ARG3,
715 class ARG4, class ARG5, class ARG6, class ARG7
716 > void invoke(
717 T* target,
718 void (T::*fptr)(ARG0,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7)
719 ) {
720 this->assert_nb_args_matches(8);
721 ARG0 a0;
722 this->get_arg_by_index(0,a0);
723 ARG1 a1;
724 this->get_arg_by_index(1,a1);
725 ARG2 a2;
726 this->get_arg_by_index(2,a2);
727 ARG3 a3;
728 this->get_arg_by_index(3,a3);
729 ARG4 a4;
730 this->get_arg_by_index(4,a4);
731 ARG5 a5;
732 this->get_arg_by_index(5,a5);
733 ARG6 a6;
734 this->get_arg_by_index(6,a6);
735 ARG7 a7;
736 this->get_arg_by_index(7,a7);
737 if(target != nullptr && fptr != nullptr) {
738 (*target.*fptr)(a0,a1,a2,a3,a4,a5,a6,a7);
739 }
740 }
741
742 /**************************************************************/
743
744 /**
745 * \brief Invokes a function with the stored arguments.
746 * \details If the type or number of stored arguments do not match
747 * the function pointer, then an assertion failure is triggered.
748 * \param[in] fptr the pointer to the member function to be called.
749 * \note Used by internal CommandInvoker mechanism.
750 */
751
752 void invoke(
753 void (*fptr)(void)
754 ) {
755 this->assert_nb_args_matches(0);
756 if(fptr != nullptr) {
757 (*fptr)();
758 }
759 }
760
761 /**
762 * \brief Invokes a function with the stored arguments.
763 * \details If the type or number of stored arguments do not match
764 * the function pointer, then an assertion failure is triggered.
765 * \tparam ARG0 type of the argument
766 * \param[in] fptr the pointer to the member function to be called.
767 * \note Used by internal CommandInvoker mechanism.
768 */
769
770 template <
771 class ARG0
772 > void invoke(
773 void (*fptr)(ARG0)
774 ) {
775 this->assert_nb_args_matches(1);
776 ARG0 a0;
777 this->get_arg_by_index(0,a0);
778 if(fptr != nullptr) {
779 (*fptr)(a0);
780 }
781 }
782
783 /**
784 * \brief Invokes a function with the stored arguments.
785 * \details If the type or number of stored arguments do not match
786 * the function pointer, then an assertion failure is triggered.
787 * \tparam ARG0 , ARG1 types of the arguments
788 * \param[in] fptr the pointer to the member function to be called.
789 * \note Used by internal CommandInvoker mechanism.
790 */
791
792 template <
793 class ARG0, class ARG1
794 > void invoke(
795 void (*fptr)(ARG0,ARG1)
796 ) {
797 this->assert_nb_args_matches(2);
798 ARG0 a0;
799 this->get_arg_by_index(0,a0);
800 ARG1 a1;
801 this->get_arg_by_index(1,a1);
802 if(fptr != nullptr) {
803 (*fptr)(a0,a1);
804 }
805 }
806
807 /**
808 * \brief Invokes a function with the stored arguments.
809 * \details If the type or number of stored arguments do not match
810 * the function pointer, then an assertion failure is triggered.
811 * \tparam ARG0 , ARG1 , ARG2 types of the arguments
812 * \param[in] fptr the pointer to the member function to be called.
813 * \note Used by internal CommandInvoker mechanism.
814 */
815
816 template <
817 class ARG0, class ARG1, class ARG2
818 > void invoke(
819 void (*fptr)(ARG0,ARG1,ARG2)
820 ) {
821 this->assert_nb_args_matches(3);
822 ARG0 a0;
823 this->get_arg_by_index(0,a0);
824 ARG1 a1;
825 this->get_arg_by_index(1,a1);
826 ARG2 a2;
827 this->get_arg_by_index(2,a2);
828 if(fptr != nullptr) {
829 (*fptr)(a0,a1,a2);
830 }
831 }
832
833 /**
834 * \brief Invokes a function with the stored arguments.
835 * \details If the type or number of stored arguments do not match
836 * the function pointer, then an assertion failure is triggered.
837 * \tparam ARG0 , ARG1 , ARG2 , ARG3 types of the arguments
838 * \param[in] fptr the pointer to the member function to be called.
839 * \note Used by internal CommandInvoker mechanism.
840 */
841
842 template <
843 class ARG0, class ARG1, class ARG2, class ARG3
844 > void invoke(
845 void (*fptr)(ARG0,ARG1,ARG2,ARG3)
846 ) {
847 this->assert_nb_args_matches(4);
848 ARG0 a0;
849 this->get_arg_by_index(0,a0);
850 ARG1 a1;
851 this->get_arg_by_index(1,a1);
852 ARG2 a2;
853 this->get_arg_by_index(2,a2);
854 ARG3 a3;
855 this->get_arg_by_index(3,a3);
856 if(fptr != nullptr) {
857 (*fptr)(a0,a1,a2,a3);
858 }
859 }
860
861 /**
862 * \brief Invokes a function with the stored arguments.
863 * \details If the type or number of stored arguments do not match
864 * the function pointer, then an assertion failure is triggered.
865 * \tparam ARG0 , ARG1 , ARG2 , ARG3 , ARG4 types of the arguments
866 * \param[in] fptr the pointer to the member function to be called.
867 * \note Used by internal CommandInvoker mechanism.
868 */
869
870 template <
871 class ARG0, class ARG1, class ARG2, class ARG3,
872 class ARG4
873 > void invoke(
874 void (*fptr)(ARG0,ARG1,ARG2,ARG3,ARG4)
875 ) {
876 this->assert_nb_args_matches(5);
877 ARG0 a0;
878 this->get_arg_by_index(0,a0);
879 ARG1 a1;
880 this->get_arg_by_index(1,a1);
881 ARG2 a2;
882 this->get_arg_by_index(2,a2);
883 ARG3 a3;
884 this->get_arg_by_index(3,a3);
885 ARG4 a4;
886 this->get_arg_by_index(4,a4);
887 if(fptr != nullptr) {
888 (*fptr)(a0,a1,a2,a3,a4);
889 }
890 }
891
892 /**
893 * \brief Invokes a function with the stored arguments.
894 * \details If the type or number of stored arguments do not match
895 * the function pointer, then an assertion failure is triggered.
896 * \tparam ARG0 , ARG5 types of the arguments
897 * \param[in] fptr the pointer to the member function to be called.
898 * \note Used by internal CommandInvoker mechanism.
899 */
900
901 template <
902 class ARG0, class ARG1, class ARG2, class ARG3,
903 class ARG4, class ARG5
904 > void invoke(
905 void (*fptr)(ARG0,ARG1,ARG2,ARG3,ARG4,ARG5)
906 ) {
907 this->assert_nb_args_matches(6);
908 ARG0 a0;
909 this->get_arg_by_index(0,a0);
910 ARG1 a1;
911 this->get_arg_by_index(1,a1);
912 ARG2 a2;
913 this->get_arg_by_index(2,a2);
914 ARG3 a3;
915 this->get_arg_by_index(3,a3);
916 ARG4 a4;
917 this->get_arg_by_index(4,a4);
918 ARG5 a5;
919 this->get_arg_by_index(5,a5);
920 if(fptr != nullptr) {
921 (*fptr)(a0,a1,a2,a3,a4,a5);
922 }
923 }
924
925 /**
926 * \brief Invokes a function with the stored arguments.
927 * \details If the type or number of stored arguments do not match
928 * the function pointer, then an assertion failure is triggered.
929 * \tparam ARG0 , ARG6 types of the arguments
930 * \param[in] fptr the pointer to the member function to be called.
931 * \note Used by internal CommandInvoker mechanism.
932 */
933
934 template <
935 class ARG0, class ARG1, class ARG2, class ARG3,
936 class ARG4, class ARG5, class ARG6
937 > void invoke(
938 void (*fptr)(ARG0,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6)
939 ) {
940 this->assert_nb_args_matches(7);
941 ARG0 a0;
942 this->get_arg_by_index(0,a0);
943 ARG1 a1;
944 this->get_arg_by_index(1,a1);
945 ARG2 a2;
946 this->get_arg_by_index(2,a2);
947 ARG3 a3;
948 this->get_arg_by_index(3,a3);
949 ARG4 a4;
950 this->get_arg_by_index(4,a4);
951 ARG5 a5;
952 this->get_arg_by_index(5,a5);
953 ARG6 a6;
954 this->get_arg_by_index(6,a6);
955 if(fptr != nullptr) {
956 (*fptr)(a0,a1,a2,a3,a4,a5,a6);
957 }
958 }
959
960 /**
961 * \brief Invokes a function with the stored arguments.
962 * \details If the type or number of stored arguments do not match
963 * the function pointer, then an assertion failure is triggered.
964 * \tparam ARG0 , ARG7 types of the arguments
965 * \param[in] fptr the pointer to the member function to be called.
966 * \note Used by internal CommandInvoker mechanism.
967 */
968
969 template <
970 class ARG0, class ARG1, class ARG2, class ARG3,
971 class ARG4, class ARG5, class ARG6, class ARG7
972 > void invoke(
973 void (*fptr)(ARG0,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7)
974 ) {
975 this->assert_nb_args_matches(8);
976 ARG0 a0;
977 this->get_arg_by_index(0,a0);
978 ARG1 a1;
979 this->get_arg_by_index(1,a1);
980 ARG2 a2;
981 this->get_arg_by_index(2,a2);
982 ARG3 a3;
983 this->get_arg_by_index(3,a3);
984 ARG4 a4;
985 this->get_arg_by_index(4,a4);
986 ARG5 a5;
987 this->get_arg_by_index(5,a5);
988 ARG6 a6;
989 this->get_arg_by_index(6,a6);
990 ARG7 a7;
991 this->get_arg_by_index(7,a7);
992 if(fptr != nullptr) {
993 (*fptr)(a0,a1,a2,a3,a4,a5,a6,a7);
994 }
995 }
996
997 /**************************************************************/
998
999 protected:
1000
1001 /**
1002 * \brief Tests whether the number of declared arguments
1003 * matches a specified number.
1004 * \details If the number of arguments differs from the expected
1005 * number, then an assertion failure is triggered.
1006 * When auto_create_args_ is set, number of stored arguments should
1007 * be 0.
1008 * \param[in] nb expected number of arguments.
1009 */
1010 void assert_nb_args_matches(index_t nb) {
1011 geo_assert(
1012 (auto_create_args_ && args_.size() == 0) ||
1013 (args_.size() == nb)
1014 );
1015 }
1016
1017
1018 /**
1019 * \brief Adds a parameter to this command
1020 * \tparam T type of the parameter, deduced from
1021 * \p default_val
1022 * \param[in] name name of the parameter
1023 * \param[in] default_val default value of the parameter
1024 * \param[in] help optionnal text, displayed in
1025 * a tooltip
1026 */
1027 template<class T> void add_arg(
1028 const std::string& name, const T& default_val,
1029 const std::string& help = ""
1030 ) {
1031 args_.push_back(Arg(name, default_val, help));
1032 }
1033
1034 /**
1035 * \brief Creates an argument at a given index
1036 * \details Used by the auto_create_args mechanism, used
1037 * when client code did not provide any function prototype
1038 * \tparam T type of the parameter, deduced from
1039 * \p default_val
1040 * \param[in] default_val default value of the parameter
1041 */
1042 template<class T> void create_arg(
1043 index_t i, const T& default_val
1044 ) {
1045 if(i >= args_.size()) {
1046 args_.resize(i+1);
1047 }
1048 args_[i] = Arg("arg " + String::to_string(i), default_val);
1049 }
1050
1051 private:
1052
1053 /**
1054 * \brief Internal representation of an argument
1055 * value.
1056 */
1057 struct GEOGRAM_GFX_API ArgVal {
1058 /**
1059 * \brief Resets all values stored to zero.
1060 */
1061 void clear();
1062
1063 /**
1064 * \brief Argval constructor.
1065 */
1066 ArgVal() {
1067 clear();
1068 }
1069
1070 /**
1071 * \brief Argval copy constructor.
1072 * \param[in] rhs a const reference to the ArgVal
1073 * to be copied
1074 */
1075 ArgVal(const ArgVal& rhs);
1076
1077 /**
1078 * \brief Argval assignment operator.
1079 * \param[in] rhs a const reference to the ArgVal
1080 * to be copied
1081 * \return a reference to this ArgVal after assignment
1082 */
1083 ArgVal& operator=(const ArgVal& rhs);
1084
1085 bool bool_val;
1086 int int_val;
1087 float float_val;
1088 char string_val[64];
1089 };
1090
1091 /**
1092 * \brief Internal representation of an argument.
1093 * \details An argument has a type, a name, a
1094 * default value, and an optionnal tooltip.
1095 */
1096 struct GEOGRAM_GFX_API Arg {
1097
1098 /**
1099 * \brief Arg default constructor.
1100 */
1101 Arg();
1102
1103 /**
1104 * \brief Arg constructor from bool.
1105 * \param[in] name_in the name of the argument
1106 * \param[in] x the default value
1107 * \param[in] help_in an optional text, displayed
1108 * as a tooltip
1109 */
1110 Arg(
1111 const std::string& name_in, bool x,
1112 const std::string& help_in=""
1113 );
1114
1115 /**
1116 * \brief Arg constructor from int.
1117 * \param[in] name_in the name of the argument
1118 * \param[in] x the default value
1119 * \param[in] help_in an optional text, displayed
1120 * as a tooltip
1121 */
1122 Arg(
1123 const std::string& name_in, int x,
1124 const std::string& help_in=""
1125 );
1126
1127 /**
1128 * \brief Arg constructor from unsigned int.
1129 * \details Stored internally as (signed) int
1130 * \param[in] name_in the name of the argument
1131 * \param[in] x the default value
1132 * \param[in] help_in an optional text, displayed
1133 * as a tooltip
1134 */
1135 Arg(
1136 const std::string& name_in, unsigned int x,
1137 const std::string& help_in=""
1138 );
1139
1140 /**
1141 * \brief Arg constructor from float.
1142 * \param[in] name_in the name of the argument
1143 * \param[in] x the default value
1144 * \param[in] help_in an optional text, displayed
1145 * as a tooltip
1146 */
1147 Arg(
1148 const std::string& name_in, float x,
1149 const std::string& help_in=""
1150 );
1151
1152 /**
1153 * \brief Arg constructor from double.
1154 * \details Stored internally as a float
1155 * \param[in] name_in the name of the argument
1156 * \param[in] x the default value
1157 * \param[in] help_in an optional text, displayed
1158 * as a tooltip
1159 */
1160 Arg(
1161 const std::string& name_in, double x,
1162 const std::string& help_in=""
1163 );
1164
1165 /**
1166 * \brief Arg constructor from string.
1167 * \details String length is limited to 64 characters.
1168 * \param[in] name_in the name of the argument
1169 * \param[in] x the default value
1170 * \param[in] help_in an optional text, displayed
1171 * as a tooltip
1172 */
1173 Arg(
1174 const std::string& name_in, const std::string& x,
1175 const std::string& help_in=""
1176 );
1177
1178 /**
1179 * \brief Displays and manages the GUI for this Arg.
1180 */
1181 void draw();
1182
1183 enum { ARG_BOOL, ARG_INT, ARG_UINT, ARG_FLOAT, ARG_STRING } type;
1184 std::string name;
1185 std::string help;
1186 ArgVal val;
1187 ArgVal default_val;
1188 };
1189
1190 /**
1191 * \brief Finds an argument value by name.
1192 * \details Triggers an assertion failure if no such
1193 * argument exists.
1194 * \param[in] name name of the argument
1195 * \return a const reference to the Arg
1196 */
1197 const Arg& find_arg(const std::string& name) const {
1198 for(index_t i=0; i<args_.size(); ++i) {
1199 if(args_[i].name == name) {
1200 return args_[i];
1201 }
1202 }
1203 geo_assert_not_reached;
1204 }
1205
1206 /**
1207 * \brief Gets an Arg by its index.
1208 * \param[in] i the index of the Arg
1209 * \return a const reference to the Arg
1210 */
1211 const Arg& find_arg_by_index(index_t i) const {
1212 geo_assert(i < args_.size());
1213 return args_[i];
1214 }
1215
1216
1217 private:
1218 std::string name_;
1219 std::string help_;
1220 vector<Arg> args_;
1221 CommandInvoker_var invoker_;
1222 bool visible_;
1223 /**
1224 * \brief If no prototype was specified, then
1225 * arguments are automatically created.
1226 */
1227 bool auto_create_args_;
1228 static SmartPointer<Command> current_;
1229 static SmartPointer<Command> queued_;
1230 static SmartPointer<Command> latest_;
1231 };
1232
1233 /***********************************************************************/
1234
1235 /**
1236 * \copydoc Command::get_arg_by_index()
1237 */
1238 template<> inline void Command::get_arg_by_index(
1239 index_t i, bool& val
1240 ) {
1241 if(auto_create_args_) {
1242 val = false;
1243 this->create_arg(i, val);
1244 } else {
1245 val = this->bool_arg_by_index(i);
1246 }
1247 }
1248
1249 /**
1250 * \copydoc Command::get_arg_by_index()
1251 */
1252 template<> inline void Command::get_arg_by_index(
1253 index_t i, int& val
1254 ) {
1255 if(auto_create_args_) {
1256 val = 0;
1257 this->create_arg(i, val);
1258 } else {
1259 val = this->int_arg_by_index(i);
1260 }
1261 }
1262
1263 /**
1264 * \copydoc Command::get_arg_by_index()
1265 */
1266 template<> inline void Command::get_arg_by_index(
1267 index_t i, unsigned int& val
1268 ) {
1269 if(auto_create_args_) {
1270 val = 0;
1271 this->create_arg(i, val);
1272 } else {
1273 val = this->uint_arg_by_index(i);
1274 }
1275 }
1276
1277 /**
1278 * \copydoc Command::get_arg_by_index()
1279 */
1280 template<> inline void Command::get_arg_by_index(
1281 index_t i, float& val
1282 ) {
1283 if(auto_create_args_) {
1284 val = 0.0f;
1285 this->create_arg(i, val);
1286 } else {
1287 val = this->float_arg_by_index(i);
1288 }
1289 }
1290
1291 /**
1292 * \copydoc Command::get_arg_by_index()
1293 */
1294 template<> inline void Command::get_arg_by_index(
1295 index_t i, double& val
1296 ) {
1297 if(auto_create_args_) {
1298 val = 0.0;
1299 this->create_arg(i, val);
1300 } else {
1301 val = this->double_arg_by_index(i);
1302 }
1303 }
1304
1305 /**
1306 * \copydoc Command::get_arg_by_index()
1307 */
1308 template<> inline void Command::get_arg_by_index(
1309 index_t i, std::string& val
1310 ) {
1311 if(auto_create_args_) {
1312 val = "";
1313 this->create_arg(i, val);
1314 } else {
1315 val = this->string_arg_by_index(i);
1316 }
1317 }
1318
1319 /*****************************************************************/
1320
1321 /**
1322 * \brief An implementation of CommandInvoker that calls
1323 * a function.
1324 * \tparam FPTR function pointer type for the function to be called
1325 */
1326 template <class FPTR>
1327 class FunctionCommandInvoker : public CommandInvoker {
1328 public:
1329
1330 /**
1331 * \brief FunctionCommandInvoker constructor.
1332 * \param[in] command a pointer to the Command object
1333 * \param[in] fun the function pointer
1334 */
1335 FunctionCommandInvoker(
1336 Command* command,
1337 FPTR fun
1338 ) :
1339 command_(command),
1340 fun_(fun) {
1341 }
1342
1343 /**
1344 * \copydoc CommandInvoker::invoke()
1345 */
1346 void invoke() override {
1347 command_->invoke(fun_);
1348 }
1349
1350 /**
1351 * \copydoc CommandInvoker::auto_create_args()
1352 */
1353 void auto_create_args() override {
1354 command_->invoke(FPTR(nullptr));
1355 }
1356
1357 private:
1358 Command* command_;
1359 FPTR fun_;
1360 };
1361
1362 /*****************************************************************/
1363
1364 /**
1365 * \brief An implementation of CommandInvoker that calls
1366 * a member function of an object.
1367 * \tparam T class of the object
1368 * \tparam TFPTR function pointer type for the function to be called
1369 */
1370
1371 template <class T, class TFPTR>
1372 class MemberFunctionCommandInvoker : public CommandInvoker {
1373 public:
1374
1375 /**
1376 * \brief MemberFunctionCommandInvoker constructor.
1377 * \param[in] command a pointer to the Command object
1378 * \param[in] target a pointer to the object
1379 * \param[in] target_fun the member function pointer
1380 */
1381
1382 MemberFunctionCommandInvoker(
1383 Command* command,
1384 T* target,
1385 TFPTR target_fun
1386 ) :
1387 command_(command),
1388 target_(target),
1389 target_fun_(target_fun) {
1390 }
1391
1392 /**
1393 * \copydoc CommandInvoker::invoke()
1394 */
1395
1396 void invoke() override {
1397 command_->invoke(target_, target_fun_);
1398 }
1399
1400 /**
1401 * \copydoc CommandInvoker::auto_create_args()
1402 */
1403
1404 void auto_create_args() override {
1405 command_->invoke((T*)(nullptr), (TFPTR)(nullptr));
1406 }
1407
1408
1409 private:
1410 Command* command_;
1411 T* target_;
1412 TFPTR target_fun_;
1413 };
1414
1415 /*****************************************************************/
1416
1417 template<class FPTR> inline void Command::set_current(
1418 const std::string& prototype,
1419 FPTR fun
1420 ) {
1421 set_current(new Command(prototype));
1422 current()->set_invoker(
1423 new FunctionCommandInvoker<FPTR>(current(), fun)
1424 );
1425 }
1426
1427 /*****************************************************************/
1428
1429 template<class T, class TFPTR> inline void Command::set_current(
1430 const std::string& prototype,
1431 T* target,
1432 TFPTR tfun
1433 ) {
1434 set_current(new Command(prototype));
1435 current()->set_invoker(
1436 new MemberFunctionCommandInvoker<T, TFPTR>(current(), target, tfun)
1437 );
1438 }
1439
1440 /*****************************************************************/
1441
1442 }
1443
1444 #endif
1445