1 // Copyright (c) 2010, Amar Takhar <verm@aegisub.org>
2 //
3 // Permission to use, copy, modify, and distribute this software for any
4 // purpose with or without fee is hereby granted, provided that the above
5 // copyright notice and this permission notice appear in all copies.
6 //
7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 
15 /// @file command.h
16 /// @brief Command base class and main header.
17 /// @ingroup command
18 
19 #include <map>
20 #include <memory>
21 #include <string>
22 #include <vector>
23 
24 #include <wx/bitmap.h>
25 #include <wx/intl.h>
26 #include <wx/string.h>
27 
28 #include <libaegisub/exception.h>
29 
30 namespace agi { struct Context; }
31 
32 #define CMD_NAME(a) const char* name() const { return a; }
33 #define STR_MENU(a) wxString StrMenu(const agi::Context *) const { return _(a); }
34 #define STR_DISP(a) wxString StrDisplay(const agi::Context *) const { return _(a); }
35 #define STR_HELP(a) wxString StrHelp() const { return _(a); }
36 #define CMD_TYPE(a) int Type() const { using namespace cmd; return a; }
37 
38 #define CMD_ICON(icon) wxBitmap Icon(int size, wxLayoutDirection dir = wxLayout_LeftToRight) const override { \
39 	if (size == 64) return GETIMAGEDIR(icon##_64, dir); \
40 	if (size == 48) return GETIMAGEDIR(icon##_48, dir); \
41 	if (size == 32) return GETIMAGEDIR(icon##_32, dir); \
42 	if (size == 24) return GETIMAGEDIR(icon##_24, dir); \
43 	return GETIMAGEDIR(icon##_16, dir); \
44 }
45 
46 #define COMMAND_GROUP(cname, cmdname, menu, disp, help) \
47 struct cname final : public Command {                         \
48 	CMD_NAME(cmdname)                                   \
49 	STR_MENU(menu)                                      \
50 	STR_DISP(disp)                                      \
51 	STR_HELP(help)                                      \
52 	void operator()(agi::Context *) { }                 \
53 }
54 
55 /// Commands
56 namespace cmd {
57 DEFINE_EXCEPTION(CommandError, agi::Exception);
58 DEFINE_EXCEPTION(CommandNotFound, CommandError);
59 
60 	enum CommandFlags {
61 		/// Default command type
62 		COMMAND_NORMAL       = 0,
63 
64 		/// Invoking this command toggles a setting of some sort. Any command
65 		/// of this type should have IsActive implemented to signal the
66 		/// current state of the thing being toggled, and invoking the command
67 		/// twice should be a no-op
68 		///
69 		/// This is mutually exclusive with COMMAND_RADIO
70 		COMMAND_TOGGLE       = 1,
71 
72 		/// Invoking this command sets a setting to a specific value. Any
73 		/// command of this type should have IsActive implemented, and if
74 		/// IsActive returns true, invoking the command should have no effect
75 		///
76 		/// This is mutually exclusive with COMMAND_TOGGLE
77 		COMMAND_RADIO        = 2,
78 
79 		/// This command has an overridden Validate method
80 		COMMAND_VALIDATE     = 4,
81 
82 		/// This command's name may change based on the state of the project
83 		COMMAND_DYNAMIC_NAME = 8,
84 
85 		/// This command's help string may change
86 		COMMAND_DYNAMIC_HELP = 16,
87 
88 		/// This command's icon may change based on the state of the project
89 		COMMAND_DYNAMIC_ICON = 32
90 	};
91 
92 	/// Holds an individual Command
93 	class Command {
94 	public:
95 		/// Command name
96 		virtual const char* name() const=0;
97 		/// String for menu purposes including accelerators, but not hotkeys
98 		virtual wxString StrMenu(const agi::Context *) const=0;
99 		/// Plain string for display purposes; should normally be the same as StrMenu
100 		/// but without accelerators
101 		virtual wxString StrDisplay(const agi::Context *) const=0;
102 		/// Short help string describing what the command does
103 		virtual wxString StrHelp() const=0;
104 
105 		/// Get this command's type flags
106 		/// @return Bitmask of CommandFlags
Type()107 		virtual int Type() const { return COMMAND_NORMAL; }
108 
109 		/// Request icon.
110 		/// @param size Icon size.
111 		virtual wxBitmap Icon(int size, wxLayoutDirection = wxLayout_LeftToRight) const { return wxBitmap{}; }
112 
113 		/// Command function
114 		virtual void operator()(agi::Context *c)=0;
115 
116 		/// Check whether or not it makes sense to call this command at this time
117 		/// @param c Project context
118 		///
119 		/// This function should be very fast, as it is called whenever a menu
120 		/// containing this command is opened and is called periodically for
121 		/// any commands used in a toolbar
122 		///
123 		/// Note that it is still legal to call commands when this returns
124 		/// false. In this situation, commands should do nothing.
125 		///
126 		/// This function should be overridden iff the command's type flags
127 		/// include COMMAND_VALIDATE
Validate(const agi::Context * c)128 		virtual bool Validate(const agi::Context *c) { return true; }
129 
130 		/// Is the selectable value represented by this command currently selected?
131 		/// @param c Project context
132 		///
133 		/// As with Validate, this function should be very fast.
134 		///
135 		/// This function should be overridden iff the command's type flags
136 		/// include COMMAND_TOGGLE or COMMAND_RADIO
IsActive(const agi::Context * c)137 		virtual bool IsActive(const agi::Context *c) { return false; }
138 
139 		/// Destructor
140 		virtual ~Command() = default;
141 	};
142 
143 	/// Init all builtin commands.
144 	void init_builtin_commands();
145 
146 	/// Register a command.
147 	/// @param cmd Command object to register.
148 	void reg(std::unique_ptr<Command> cmd);
149 
150 	/// Unregister a command.
151 	/// @param cmd Command name to unregister. The associated command object is deleted.
152 	void unreg(std::string const& name);
153 
154 	/// Call a command.
155 	/// @param name Name of the command to call.
156 	/// @param c  Current Context.
157 	void call(std::string const& name, agi::Context *c);
158 
159 	/// Retrieve a Command object.
160 	/// @param Command object.
161 	Command* get(std::string const& name);
162 
163 	/// Get a list of registered command names
164 	std::vector<std::string> get_registered_commands();
165 
166 	/// Unregister and deletes all commands
167 	void clear();
168 } // namespace cmd
169