pflib v3.9.0-rc3-11-g2537d8f
Pretty Fine HGCROC Interaction Library
Loading...
Searching...
No Matches
Menu.h
1#ifndef PFLIB_TOOL_MENU_H
2#define PFLIB_TOOL_MENU_H
3
4#include <stdio.h>
5#include <string.h>
6
7#include <functional>
8#include <iomanip>
9#include <iostream>
10#include <list>
11#include <string>
12#include <vector>
13
14#include "pflib/Exception.h"
15#include "pflib/logging/Logging.h"
16
17namespace pflib::menu {
18
27class BaseMenu {
28 static std::string history_filepath_;
29
30 public:
34 static void set_history_filepath(std::string fp);
35
42 static void open_history();
43
47 static void close_history();
48
65 static std::string readline(const std::string& prompt,
66 const std::string& defval,
67 bool preserve_last_blank = false);
68
77 static std::string readline_nosplit(const std::string& prompt,
78 const std::string& defval);
87 static std::string readline(const std::string& prompt);
88
98 static std::string readline(const std::string& prompt,
99 const std::vector<std::string>& opts,
100 const std::string& def = "");
101
112 static std::string default_path(const std::string& name,
113 const std::string& extension = "");
114
117
126 static std::string readline_path(const std::string& name,
127 const std::string& extension = "");
128
139
149 static int readline_int(const std::string& prompt);
150
161 static int readline_int(const std::string& prompt, int aval,
162 bool ashex = false);
163
174 static double readline_float(const std::string& prompt);
175
188 static bool readline_bool(const std::string& prompt, bool aval);
189
200 static std::string readline_cmd();
201
207 static void add_to_command_queue(const std::string& str);
208
209 protected:
217 void add_to_history(const std::string& cmd) const;
218
221
225
228
229 static ::pflib::logging::logger the_log_;
230
231 private:
246 static char* matcher(const char* text, int state);
247}; // BaseMenu
248
275template <typename T>
276class Menu : public BaseMenu {
277 public:
279 using TargetHandle = T;
285
295
307 Menu* line(const char* name, const char* desc, SingleTargetCommand ex,
308 unsigned int category = 0) {
309 lines_.emplace_back(name, desc, ex, category);
310 return this;
311 }
312
327 Menu* line(const char* name, const char* desc, MultipleTargetCommands ex,
328 unsigned int category = 0) {
329 lines_.emplace_back(name, desc, ex, category);
330 return this;
331 }
332
353 std::shared_ptr<Menu> submenu(const char* name, const char* desc,
354 RenderFuncType f = 0,
355 unsigned int category = 0) {
356 auto sb = std::make_shared<Menu>(f);
357 lines_.emplace_back(name, desc, sb, category);
358 return sb;
359 }
360
364 static Menu* root() {
365 static Menu root;
366 return &root;
367 }
368
376 void build() {
377 // go through menu options and add exit
378 for (Line& l : lines_) l.build();
379 lines_.emplace_back("EXIT", "leave this menu");
380 lines_.emplace_back("HELP", "print help for this menu",
381 [this](TargetHandle tgt) { this->render(tgt); });
382 }
383
394 static void run(TargetHandle tgt) {
396 root()->build();
397 root()->steer(tgt);
399 }
400
402 Menu(const Menu&) = delete;
404 void operator=(const Menu&) = delete;
405
409 Menu(RenderFuncType f = 0, unsigned int hidden_categories = 0)
410 : render_func_{f}, hidden_categories_{hidden_categories} {}
411
413 void hide(unsigned int categories) {
414 hidden_categories_ = categories;
415 for (auto& l : lines_) {
416 l.hide(categories);
417 }
418 }
419
423 void print(std::ostream& s, int indent = 0) const {
424 for (const auto& l : lines_) {
425 if ((l.category() & hidden_categories_) == 0) {
426 l.print(s, indent);
427 }
428 }
429 }
430
440 void render(TargetHandle tgt) const {
441 if (render_func_) {
442 render_func_(tgt);
443 }
444 std::cout << "\n";
445 for (const auto& l : lines_) {
446 if ((l.category() & hidden_categories_) == 0) {
447 std::cout << l << std::endl;
448 }
449 }
450 }
451
466 void enter(TargetHandle tgt) const {
467 if (cmdTextQueue_.empty()) {
468 // copy over command options for tab complete
469 this->cmd_options_ = this->command_options();
470 this->render(tgt);
471 }
472 }
473
494 void steer(TargetHandle p_target) const {
495 enter(p_target);
496 const Line* theMatch = 0;
497 do {
498 std::string request = readline_cmd();
499 theMatch = 0;
500 // check for a unique match...
501 int nmatch = 0;
502 for (size_t i = 0; i < lines_.size(); i++)
503 if (strcasecmp(request.c_str(), lines_[i].name()) == 0) {
504 theMatch = &(lines_[i]);
505 nmatch++;
506 }
507 if (nmatch > 1) theMatch = 0;
508 // ok
509 if (theMatch == 0)
510 printf(" Command '%s' not understood.\n\n", request.c_str());
511 else {
512 add_to_history(theMatch->name());
513 if (theMatch->execute(p_target)) {
514 // resume control when the chosen line was a submenu
515 enter(p_target);
516 }
517 }
518 } while (theMatch == 0 or not theMatch->empty());
519 }
520
560 static std::shared_ptr<Menu> menu(const char* name, const char* desc,
561 RenderFuncType render_func = 0,
562 unsigned int category = 0) {
563 return root()->submenu(name, desc, render_func, category);
564 }
565
566 private:
574 v.reserve(lines_.size());
575 for (const auto& l : lines_) {
576 if ((l.category() & hidden_categories_) == 0) {
577 v.push_back(l.name());
578 }
579 }
580 return v;
581 }
582
583 private:
599 class Line {
600 public:
602 Line(const char* n, const char* d, SingleTargetCommand f,
603 unsigned int category = 0)
604 : name_(n),
605 desc_(d),
606 sub_menu_{nullptr},
607 cmd_(f),
608 mult_cmds_{0},
611 Line(const char* n, const char* d, MultipleTargetCommands f,
612 unsigned int category = 0)
613 : name_(n),
614 desc_(d),
615 sub_menu_{nullptr},
616 mult_cmds_{f},
619 Line(const char* n, const char* d, std::shared_ptr<Menu> m,
620 unsigned int category = 0)
621 : name_(n),
622 desc_(d),
623 sub_menu_(m),
624 cmd_(0),
625 mult_cmds_{0},
633 Line(const char* n, const char* d)
634 : name_(n),
635 desc_(d),
636 sub_menu_{nullptr},
637 cmd_(0),
638 mult_cmds_{0},
639 category_{0} {}
640
654 bool execute(TargetHandle p) const {
655 if (sub_menu_) {
656 sub_menu_->steer(p);
657 return true;
658 } else if (cmd_ or mult_cmds_) {
659 try {
660 if (cmd_)
661 cmd_(p);
662 else
663 mult_cmds_(name_, p);
664 } catch (const pflib::Exception& e) {
665 pflib_log(error) << "[" << e.name() << "] : " << e.message();
666 } catch (const std::exception& e) {
667 pflib_log(error) << "Unknown Exception " << e.what();
668 }
669 }
670 // empty and command lines don't need the parent menu
671 // to reset the command options
672 return false;
673 }
674
678 bool empty() const { return !sub_menu_ and cmd_ == 0 and mult_cmds_ == 0; }
679
686 void build() {
687 if (sub_menu_) sub_menu_->build();
688 }
689
693 void hide(unsigned int categories) {
694 if (sub_menu_) sub_menu_->hide(categories);
695 }
696
698 const char* name() const { return name_; }
700 const char* desc() const { return desc_; }
702 unsigned int category() const { return category_; }
703
707 friend std::ostream& operator<<(std::ostream& s, const Line& l) {
708 return (s << " " << std::left << std::setw(12) << l.name() << " "
709 << l.desc());
710 }
711
716 void print(std::ostream& s, int indent = 0) const {
717 for (std::size_t i{0}; i < indent; i++) s << " ";
718 s << *this << "\n";
719 if (sub_menu_) {
720 sub_menu_->print(s, indent + 2);
721 }
722 }
723
724 private:
726 const char* name_;
728 const char* desc_;
736 unsigned int category_;
737 }; // Line
738
739 private:
745 unsigned int hidden_categories_;
746}; // Menu
747
748} // namespace pflib::menu
749
750#endif // PFLIB_TOOL_MENU_H
T c_str(T... args)
PFlib.
Definition Exception.h:12
const std::string & message() const
Get the message of the exception.
Definition Exception.h:52
virtual const char * what() const
The error message.
Definition Exception.h:76
const std::string & name() const
Get the name of the exception.
Definition Exception.h:46
Type-less menu base for common tasks.
Definition Menu.h:27
static std::string default_path(const std::string &name, const std::string &extension="")
Create a default path from the output directory and timestamp format parameters.
Definition Menu.cc:175
static void open_history()
open history and read from file (if it exists)
Definition Menu.cc:53
static std::list< std::string > cmdTextQueue_
the ordered list of commands to be executed from a script file
Definition Menu.h:220
void add_to_history(const std::string &cmd) const
Add a command to the history of commands that have been executed.
Definition Menu.cc:76
static std::vector< std::string > cmd_options_
the current command options (for interfacing with readline's tab completion)
Definition Menu.h:224
static std::string readline_nosplit(const std::string &prompt, const std::string &defval)
Get a raw input value without the additional splitting and modifications done in base readline.
Definition Menu.cc:138
static int readline_int(const std::string &prompt)
Read an integer parameter without a default.
Definition Menu.cc:202
static void set_history_filepath(std::string fp)
Decide where the filepath for reading/writing the history should be.
Definition Menu.cc:30
static std::string timestamp_format
format of timestamp to append to default path
Definition Menu.h:138
static double readline_float(const std::string &prompt)
Read a float parameter with a default.
Definition Menu.cc:206
static std::string readline_path(const std::string &name, const std::string &extension="")
Read a path from the user using default_path to generate a default value.
Definition Menu.cc:193
static void close_history()
close up history
Definition Menu.cc:70
static const std::vector< std::string > * rl_comp_opts_
a pointer to the list of options when attempting readline completion
Definition Menu.h:227
static std::string readline_cmd()
Read a command from the menu.
Definition Menu.cc:229
static bool readline_bool(const std::string &prompt, bool aval)
Read a bool parameter with a default.
Definition Menu.cc:219
static char * matcher(const char *text, int state)
matcher function following readline's function signature
Definition Menu.cc:231
static void add_to_command_queue(const std::string &str)
Add to the queue of commands to execute automatically.
Definition Menu.cc:80
static std::string readline(const std::string &prompt, const std::string &defval, bool preserve_last_blank=false)
Read in a parameter using the default value if nothing provided.
Definition Menu.cc:84
static std::string output_directory
output directory to include in default path
Definition Menu.h:116
A command in the menu.
Definition Menu.h:599
void build()
build this line
Definition Menu.h:686
void print(std::ostream &s, int indent=0) const
More specialized printing function to make it easier to recursively printout entire menu with descrip...
Definition Menu.h:716
const char * desc_
short description for what this line is
Definition Menu.h:728
Line(const char *n, const char *d, MultipleTargetCommands f, unsigned int category=0)
define a menu line that uses a multiple command function
Definition Menu.h:611
bool execute(TargetHandle p) const
Execute this line.
Definition Menu.h:654
Line(const char *n, const char *d, SingleTargetCommand f, unsigned int category=0)
define a menu line that uses a single target command
Definition Menu.h:602
Line(const char *n, const char *d, std::shared_ptr< Menu > m, unsigned int category=0)
define a menu line that enters a sub menu
Definition Menu.h:619
friend std::ostream & operator<<(std::ostream &s, const Line &l)
Overload output stream operator for easier printing.
Definition Menu.h:707
unsigned int category_
category integer for disabling menu lines by groups
Definition Menu.h:736
const char * desc() const
short description to print with menu
Definition Menu.h:700
void hide(unsigned int categories)
pass on configuration on which categories to hide
Definition Menu.h:693
const char * name() const
name of this line to select it
Definition Menu.h:698
bool empty() const
Check if this line is an empty one.
Definition Menu.h:678
Line(const char *n, const char *d)
define an empty menu line with only a name and description
Definition Menu.h:633
MultipleTargetCommands mult_cmds_
function handling multiple commands to execute (if exists)
Definition Menu.h:734
SingleTargetCommand cmd_
function pointer to execute (if exists)
Definition Menu.h:732
const char * name_
the name of this line
Definition Menu.h:726
std::shared_ptr< Menu > sub_menu_
pointer to sub menu (if it exists)
Definition Menu.h:730
unsigned int category() const
category int for hiding if certain categories are disabled
Definition Menu.h:702
A menu to execute commands with a specific target.
Definition Menu.h:276
void steer(TargetHandle p_target) const
give control over the target to this menu
Definition Menu.h:494
std::vector< Line > lines_
lines in this menu
Definition Menu.h:741
void operator=(const Menu &)=delete
no copying
virtual std::vector< std::string > command_options() const
Provide the list of command options.
Definition Menu.h:572
void render(TargetHandle tgt) const
render this menu to the user
Definition Menu.h:440
void hide(unsigned int categories)
set hidden categories
Definition Menu.h:413
void print(std::ostream &s, int indent=0) const
Print menu without running it.
Definition Menu.h:423
void build()
Go through and build each of the lines in this menu.
Definition Menu.h:376
RenderFuncType render_func_
function pointer to render the menu prompt
Definition Menu.h:743
Menu * line(const char *name, const char *desc, SingleTargetCommand ex, unsigned int category=0)
declare a single target command with thei nput name and desc
Definition Menu.h:307
static std::shared_ptr< Menu > menu(const char *name, const char *desc, RenderFuncType render_func=0, unsigned int category=0)
Construct a new menu with the root as parent and optional rendering.
Definition Menu.h:560
unsigned int hidden_categories_
bit-wise OR of any category integers that should not be displayed
Definition Menu.h:745
static void run(TargetHandle tgt)
Call this function when ready to run.
Definition Menu.h:394
Menu * line(const char *name, const char *desc, MultipleTargetCommands ex, unsigned int category=0)
declare a single target command with the input name and desc
Definition Menu.h:327
void enter(TargetHandle tgt) const
entered this menu
Definition Menu.h:466
static Menu * root()
Retreve a pointer to the root menu.
Definition Menu.h:364
Menu(const Menu &)=delete
no copying
std::shared_ptr< Menu > submenu(const char *name, const char *desc, RenderFuncType f=0, unsigned int category=0)
declare a sub menu of us with input name and desc
Definition Menu.h:353
Menu(RenderFuncType f=0, unsigned int hidden_categories=0)
Construct a menu with a rendering function.
Definition Menu.h:409
T TargetHandle
the type of target this menu will hold and pass around
Definition Menu.h:279
T empty(T... args)
T endl(T... args)
T left(T... args)
T make_shared(T... args)
T push_back(T... args)
T reserve(T... args)
T setw(T... args)