49 #include <boost/preprocessor/cat.hpp>
56 #define ERR_LUA LOG_STREAM(err, log_scripting_lua)
60 if(
auto window =
w.get_window()) {
61 window->invalidate_layout();
69 int n = list->get_item_count();
75 return list->get_row_grid(
i - 1);
77 int n = multi_page->get_page_count();
83 return &multi_page->page_grid(
i - 1);
88 throw std::invalid_argument(
"out of range");
92 int n = tree_view_node->count_children();
94 throw std::invalid_argument(
"out of range");
96 return &tree_view_node->get_child_at(
i - 1);
98 int n = stacked_widget->get_layer_count();
100 throw std::invalid_argument(
"out of range");
102 return stacked_widget->get_layer_grid(
i - 1);
109 return w.find(m,
false);
115 using tsetters = std::map<std::string, std::vector<std::function<bool(lua_State*,
int,
gui2::widget&,
bool)>>>;
118 template<
typename w
idget_type,
typename value_type,
typename action_type,
bool setter>
122 using map_type = std::conditional_t<setter, tsetters, tgetters>;
123 using list_type =
typename map_type::mapped_type;
124 using callback_type =
typename list_type::value_type;
129 fcn = [action = action_type()](lua_State* L,
int idx,
gui2::widget&
w,
bool nop) {
130 if(widget_type* pw =
dynamic_cast<widget_type*
>(&
w)) {
131 if(!nop) action.set(L, *pw, lua_check<value_type>(L, idx));
138 fcn = [action = action_type()](lua_State* L,
gui2::widget&
w,
bool nop) {
139 if(widget_type* pw =
dynamic_cast<widget_type*
>(&
w)) {
140 if(!nop)
lua_push(L, action.get(L, *pw));
146 list_type& list = (*map)[std::string(name_part)];
151 #define WIDGET_GETTER4(name, value_type, widgt_type, id) \
152 struct BOOST_PP_CAT(getter_, id) : public lua_getter<widgt_type, value_type> { \
153 value_type get(lua_State* L, const widgt_type& w) const override; \
155 struct BOOST_PP_CAT(getter_adder_, id) { \
156 BOOST_PP_CAT(getter_adder_, id) () \
158 register_widget_attribute<widgt_type, value_type, BOOST_PP_CAT(getter_, id), false>(name); \
161 static BOOST_PP_CAT(getter_adder_, id) BOOST_PP_CAT(getter_adder_instance_, id) ; \
162 value_type BOOST_PP_CAT(getter_, id)::get([[maybe_unused]] lua_State* L, const widgt_type& w) const
165 #define WIDGET_SETTER4(name, value_type, widgt_type, id) \
166 struct BOOST_PP_CAT(setter_, id) : public lua_setter<widgt_type, value_type> { \
167 void set(lua_State* L, widgt_type& w, const value_type& value) const override; \
169 struct BOOST_PP_CAT(setter_adder_, id) { \
170 BOOST_PP_CAT(setter_adder_, id) ()\
172 register_widget_attribute<widgt_type, value_type, BOOST_PP_CAT(setter_, id), true>(name); \
175 static BOOST_PP_CAT(setter_adder_, id) BOOST_PP_CAT(setter_adder_instance_, id); \
176 void BOOST_PP_CAT(setter_, id)::set([[maybe_unused]] lua_State* L, widgt_type& w, const value_type& value) const
184 #define WIDGET_GETTER(name, value_type, widgt_type) WIDGET_GETTER4(name, value_type, widgt_type, __LINE__)
186 #define WIDGET_SETTER(name, value_type, widgt_type) WIDGET_SETTER4(name, value_type, widgt_type, __LINE__)
193 return w.get_selected_row() + 1;
198 w.select_row(value - 1);
203 return w.get_selected_page() + 1;
208 w.select_page(value -1);
213 return w.current_layer() + 1;
218 w.select_layer(value - 1);
223 return w.get_value() + 1;
228 if(value >
int(
w.num_states())) {
229 throw std::invalid_argument(
"invalid index");
231 w.set_value(value - 1);
236 if(
w.num_states() == 2) {
237 return w.get_value_bool();
239 throw std::invalid_argument(
"invalid widget");
244 w.set_value_bool(value);
249 return w.get_value();
259 return w.get_value();
269 return w.get_best_slider_length();
275 throw std::invalid_argument(
"best_slider_length must be >= 0");
277 w.set_best_slider_length(value);
282 return w.get_maximum_value();
287 w.set_value_range(
w.get_minimum_value(), value);
292 return w.get_maximum_value_label();
297 w.set_maximum_value_label(value);
303 return w.get_minimum_value();
308 w.set_value_range(value,
w.get_maximum_value());
313 return w.get_minimum_value_label();
318 w.set_minimum_value_label(value);
324 return w.get_percentage();
329 w.set_percentage(value);
334 auto res =
w.selected_item()->describe_path();
335 for(
int& a : res) { ++a;}
341 auto res =
w.describe_path();
342 for(
int& a : res) { ++a;}
348 return !
w.get_root_node().is_folded();
354 w.get_root_node().unfold();
356 w.get_root_node().fold();
362 return !
w.is_folded();
377 w.set_displayed_type(*ut);
379 w.set_displayed_unit(*u);
387 return w.get_item_count();
392 return w.get_item_count();
397 return w.get_page_count();
402 return w.get_layer_count();
413 return w.count_children();
418 return w.get_use_markup();
423 w.set_use_markup(value);
432 w.set_use_markup(
true);
438 return w.get_characters_per_line();
444 throw std::invalid_argument(
"characters_per_line must be >= 0");
446 w.set_characters_per_line(value);
452 return w.is_editable();
457 w.set_editable(value);
464 switch(
w.get_text_ellipse_mode()) {
465 case(PangoEllipsizeMode::PANGO_ELLIPSIZE_NONE):
468 case(PangoEllipsizeMode::PANGO_ELLIPSIZE_START):
471 case(PangoEllipsizeMode::PANGO_ELLIPSIZE_MIDDLE):
474 case(PangoEllipsizeMode::PANGO_ELLIPSIZE_END):
483 if(value ==
"none") {
484 w.set_text_ellipse_mode(PangoEllipsizeMode::PANGO_ELLIPSIZE_NONE);
485 }
else if(value ==
"start") {
486 w.set_text_ellipse_mode(PangoEllipsizeMode::PANGO_ELLIPSIZE_START);
487 }
else if(value ==
"middle") {
488 w.set_text_ellipse_mode(PangoEllipsizeMode::PANGO_ELLIPSIZE_MIDDLE);
489 }
else if(value ==
"end") {
490 w.set_text_ellipse_mode(PangoEllipsizeMode::PANGO_ELLIPSIZE_END);
492 throw std::invalid_argument(
"ellipsize_mode must be one of <none,start,middle,end>");
499 return w.get_active();
509 return w.help_message();
514 w.set_help_message(value);
519 return w.get_hint_image();
524 w.set_hint_image(value);
530 return w.get_hint_text();
535 w.set_hint_text(value);
541 return w.get_hint_image();
546 w.set_hint_image(value);
552 return w.get_hint_text();
557 w.set_hint_text(value);
563 w.set_history(value);
568 return w.get_indentation_step_size();
574 throw std::invalid_argument(
"indentation_step_size must be >= 0");
576 w.set_indentation_step_size(value);
582 return w.get_link_aware();
587 w.set_link_aware(value);
593 return w.get_link_aware();
598 w.set_link_aware(value);
604 return w.get_link_aware();
609 w.set_link_aware(value);
615 return w.get_link_aware();
620 w.set_link_aware(value);
626 return w.get_link_color().to_hex_string();
631 return w.get_link_color().to_hex_string();
636 return w.get_max_input_length();
642 throw std::invalid_argument(
"max_input_length must be >= 0");
644 w.set_max_input_length(value);
650 return w.get_max_input_length();
656 throw std::invalid_argument(
"max_input_length must be >= 0");
658 w.set_max_input_length(value);
664 return w.get_step_size();
670 throw std::invalid_argument(
"step_size must be >= 0");
672 w.set_step_size(value);
679 switch(
w.get_text_alignment()) {
680 case(PangoAlignment::PANGO_ALIGN_LEFT):
683 case(PangoAlignment::PANGO_ALIGN_RIGHT):
686 case(PangoAlignment::PANGO_ALIGN_CENTER):
695 if(value ==
"left") {
696 w.set_text_alignment(PangoAlignment::PANGO_ALIGN_LEFT);
697 }
else if(value ==
"right") {
698 w.set_text_alignment(PangoAlignment::PANGO_ALIGN_RIGHT);
699 }
else if(value ==
"center") {
700 w.set_text_alignment(PangoAlignment::PANGO_ALIGN_CENTER);
702 throw std::invalid_argument(
"text_alignment must be one of <left,center,right>");
713 w.set_tooltip(value);
718 return w.get_use_tooltip_on_label_overflow();
723 w.set_use_tooltip_on_label_overflow(value);
734 w.set_can_wrap(value);
744 w.set_can_wrap(value);
750 ERR_LUA <<
"gui.widget.set_callback didn't exist";
753 lua_pushvalue(L, value.index);
760 switch(
w.get_visible()) {
780 visibility
flag = visibility::visible;
782 switch(lua_type(L, value.index)) {
785 ? visibility::visible
786 : visibility::invisible;
790 const std::string& str = lua_tostring(L, value.index);
791 if(str ==
"visible") {
792 flag = visibility::visible;
793 }
else if(str ==
"hidden") {
794 flag = visibility::hidden;
795 }
else if(str ==
"invisible") {
796 flag = visibility::invisible;
798 luaL_argerror(L, value.index,
"string must be one of: visible, hidden, invisible");
808 if(
flag == visibility::hidden) {
820 return w.get_label();
836 return sw->get_control_type();
839 return "tree_view_node";
858 ERR_LUA <<
"widget was deleted";
863 ERR_LUA <<
"cannot find window in widget callback";
873 throw std::invalid_argument(
"the widget has no window assigned");
875 lua_pushvalue(L, value.index);
885 throw std::invalid_argument(
"the widget has no window assigned");
887 lua_pushvalue(L, value.index);
899 throw std::invalid_argument(
"the widget has no window assigned");
902 throw std::invalid_argument(
"unsupported widget");
904 lua_pushvalue(L, value.index);
917 if(lua_isinteger(L, 2)) {
925 std::string_view str = lua_check<std::string_view>(L, 2);
929 for(
const auto& func : it->second) {
930 if(func(L,
w,
false)) {
935 if(
luaW_getglobal(L,
"gui",
"widget", std::string(str).c_str())) {
942 ERR_LUA <<
"invalid property of '" <<
typeid(
w).name()<<
"' widget :" << str;
943 std::string
err =
"invalid property of widget: ";
945 return luaL_argerror(L, 2,
err.c_str());
951 std::string_view str = lua_check<std::string_view>(L, 2);
956 for(
const auto& func : it->second) {
957 if(func(L, 3,
w,
false)) {
961 ERR_LUA <<
"none of "<< it->second.size() <<
" setters matched";
964 ERR_LUA <<
"unknown property id : " << str <<
" #known properties=" <<
setters.size();
967 ERR_LUA <<
"invalid modifiable property of '" <<
typeid(
w).name()<<
"' widget:" << str;
968 std::string
err =
"invalid modifiable property of widget: ";
970 return luaL_argerror(L, 2,
err.c_str());
976 std::vector<std::string> keys;
978 for(
const auto& [key, funcs] :
getters) {
979 if(key ==
"value_compat")
continue;
980 for(
const auto& func : funcs) {
981 if(func(L,
w,
true)){
988 for(
const auto& [key, funcs] :
setters) {
989 if(key ==
"value_compat")
continue;
990 if(key ==
"callback")
continue;
991 for(
const auto& func : funcs) {
992 if(func(L, 0,
w,
true)){
1000 for(
auto child = iter_t(
w); !child.at_end(); child.next()) {
1001 const auto& key = child->
id();
1002 if(!key.empty() && key !=
w.id()) {
1003 keys.push_back(key);
1009 keys.insert(keys.end(), methods.begin(), methods.end());
virtual void connect_click_handler(const event::signal &signal)=0
Connects a signal handler for a 'click' event.
A rich_label takes marked up text and shows it correctly formatted and wrapped but no scrollbars are ...
Small abstract helper class.
A widget that allows the user to input text in single line.
tree_view_node & get_child_at(int index)
std::size_t count_children() const
The number of children in this widget.
base class of top level items, the only item which needs to store the final canvases to draw on.
void invalidate_layout()
Updates the size of the window.
Tmust inherit enable_lua_ptr<T>
A single unit type that the player may recruit.
This class represents a single unit of a specific type.
Contains the base iterator class for the gui2 widgets.
Standard logging facilities (interface).
bool luaW_toboolean(lua_State *L, int n)
int luaW_type_error(lua_State *L, int narg, const char *tname)
bool luaW_getglobal(lua_State *L, const std::vector< std::string > &path)
Pushes the value found by following the variadic names (char *), if the value is not nil.
std::vector< std::string > luaW_get_attributes(lua_State *L, int idx)
This function does the actual work of grabbing all the attribute names.
unit * luaW_tounit(lua_State *L, int index, bool only_on_map)
Converts a Lua value to a unit pointer.
const unit_type * luaW_tounittype(lua_State *L, int idx)
Test if a stack element is a unit type, and return it if so.
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification &signal)
Connects a signal handler for getting a notification upon modification.
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal &signal)
Connects a signal handler for a left mouse button click.
std::map< std::string, t_string > widget_item
void split_foreach(std::string_view s, char sep, const int flags, const F &f)
std::string::const_iterator iterator
void lua_push(lua_State *L, const T &val)
static map_location::direction n
static map_location::direction sw
static map_location::direction s