The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
lua_widget_attributes.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2014 - 2025
3 by Chris Beck <render787@gmail.com>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
21#include "gui/widgets/label.hpp"
37#include "log.hpp"
47
48#include <functional>
49
50#include <boost/preprocessor/cat.hpp>
51
52#include <map>
53#include <utility>
54#include <vector>
55
56static lg::log_domain log_scripting_lua("scripting/lua");
57#define ERR_LUA LOG_STREAM(err, log_scripting_lua)
58
60{
61 if(auto window = w.get_window()) {
62 window->invalidate_layout();
63 }
64}
65
67{
68 assert(i > 0);
69 if(gui2::listbox* list = dynamic_cast<gui2::listbox*>(&w)) {
70 int n = list->get_item_count();
71 if(i > n) {
72 for(; n < i; ++n) {
73 list->add_row(gui2::widget_item{});
74 }
75 }
76 return list->get_row_grid(i - 1);
77 } else if(gui2::multi_page* multi_page = dynamic_cast<gui2::multi_page*>(&w)) {
78 int n = multi_page->get_page_count();
79 if(i > n) {
80 for(; n < i; ++n) {
81 multi_page->add_page(gui2::widget_item{});
82 }
83 }
84 return &multi_page->page_grid(i - 1);
85 } else if(gui2::tree_view* tree_view = dynamic_cast<gui2::tree_view*>(&w)) {
86 gui2::tree_view_node& tvn = tree_view->get_root_node();
87 int n = tvn.count_children();
88 if(i > n) {
89 throw std::invalid_argument("out of range");
90 }
91 return &tvn.get_child_at(i - 1);
92 } else if(gui2::tree_view_node* tree_view_node = dynamic_cast<gui2::tree_view_node*>(&w)) {
93 int n = tree_view_node->count_children();
94 if(i > n) {
95 throw std::invalid_argument("out of range");
96 }
97 return &tree_view_node->get_child_at(i - 1);
98 } else if(gui2::stacked_widget* stacked_widget = dynamic_cast<gui2::stacked_widget*>(&w)) {
99 int n = stacked_widget->get_layer_count();
100 if(i > n) {
101 throw std::invalid_argument("out of range");
102 }
103 return stacked_widget->get_layer_grid(i - 1);
104 }
105 return nullptr;
106}
107
108static gui2::widget* find_child_by_name(gui2::widget& w, const std::string& m)
109{
110 return w.find(m, false);
111}
112
113using tgetters = std::map<std::string, std::vector<std::function<bool(lua_State*, gui2::widget&, bool)>>>;
115
116using tsetters = std::map<std::string, std::vector<std::function<bool(lua_State*, int, gui2::widget&, bool)>>>;
118
119template<typename widget_type, typename value_type, typename action_type, bool setter>
120void register_widget_attribute(const char* name)
121{
122 utils::split_foreach(name, ',', 0, [](std::string_view name_part) {
123 using map_type = std::conditional_t<setter, tsetters, tgetters>;
124 using list_type = typename map_type::mapped_type;
125 using callback_type = typename list_type::value_type;
126 map_type* map;
127 callback_type fcn;
128 if constexpr(setter) {
129 map = &setters;
130 fcn = [action = action_type()](lua_State* L, int idx, gui2::widget& w, bool nop) {
131 if(widget_type* pw = dynamic_cast<widget_type*>(&w)) {
132 if(!nop) action.set(L, *pw, lua_check<value_type>(L, idx));
133 return true;
134 }
135 return false;
136 };
137 } else {
138 map = &getters;
139 fcn = [action = action_type()](lua_State* L, gui2::widget& w, bool nop) {
140 if(widget_type* pw = dynamic_cast<widget_type*>(&w)) {
141 if(!nop) lua_push(L, action.get(L, *pw));
142 return true;
143 }
144 return false;
145 };
146 }
147 list_type& list = (*map)[std::string(name_part)];
148 list.push_back(fcn);
149 });
150}
151
152#define WIDGET_GETTER4(name, value_type, widgt_type, id) \
153struct BOOST_PP_CAT(getter_, id) : public lua_getter<widgt_type, value_type> { \
154 value_type get(lua_State* L, const widgt_type& w) const override; \
155}; \
156struct BOOST_PP_CAT(getter_adder_, id) { \
157 BOOST_PP_CAT(getter_adder_, id) () \
158 { \
159 register_widget_attribute<widgt_type, value_type, BOOST_PP_CAT(getter_, id), false>(name); \
160 } \
161}; \
162static BOOST_PP_CAT(getter_adder_, id) BOOST_PP_CAT(getter_adder_instance_, id) ; \
163value_type BOOST_PP_CAT(getter_, id)::get([[maybe_unused]] lua_State* L, const widgt_type& w) const
164
165
166#define WIDGET_SETTER4(name, value_type, widgt_type, id) \
167struct BOOST_PP_CAT(setter_, id) : public lua_setter<widgt_type, value_type> { \
168 void set(lua_State* L, widgt_type& w, const value_type& value) const override; \
169}; \
170struct BOOST_PP_CAT(setter_adder_, id) { \
171 BOOST_PP_CAT(setter_adder_, id) ()\
172 { \
173 register_widget_attribute<widgt_type, value_type, BOOST_PP_CAT(setter_, id), true>(name); \
174 } \
175}; \
176static BOOST_PP_CAT(setter_adder_, id) BOOST_PP_CAT(setter_adder_instance_, id); \
177void BOOST_PP_CAT(setter_, id)::set([[maybe_unused]] lua_State* L, widgt_type& w, const value_type& value) const
178
179
180/**
181 * @param name: string comma seperated list
182 * @param value_type: the type of the attribute, for example int or std::string
183 * @param widgt_type: the type of the widget, for example gui2::listbox
184 */
185#define WIDGET_GETTER(name, value_type, widgt_type) WIDGET_GETTER4(name, value_type, widgt_type, __LINE__)
186
187#define WIDGET_SETTER(name, value_type, widgt_type) WIDGET_SETTER4(name, value_type, widgt_type, __LINE__)
188
189
190/// CLASSIC
191
192WIDGET_GETTER("value_compat,selected_index", int, gui2::listbox)
193{
194 return w.get_selected_row() + 1;
195}
196
197WIDGET_SETTER("value_compat,selected_index", int, gui2::listbox)
198{
199 w.select_row(value - 1);
200}
201
202WIDGET_GETTER("value_compat,selected_index", int, gui2::multi_page)
203{
204 return w.get_selected_page() + 1;
205}
206
207WIDGET_SETTER("value_compat,selected_index", int, gui2::multi_page)
208{
209 w.select_page(value -1);
210}
211
212WIDGET_GETTER("value_compat,selected_index", int, gui2::stacked_widget)
213{
214 return w.current_layer() + 1;
215}
216
217WIDGET_SETTER("value_compat,selected_index", int, gui2::stacked_widget)
218{
219 w.select_layer(value - 1);
220}
221
223{
224 return w.get_value() + 1;
225}
226
228{
229 if(value > int(w.num_states())) {
230 throw std::invalid_argument("invalid index");
231 }
232 w.set_value(value - 1);
233}
234
235WIDGET_GETTER("value_compat,selected", bool, gui2::selectable_item)
236{
237 if(w.num_states() == 2) {
238 return w.get_value_bool();
239 }
240 throw std::invalid_argument("invalid widget");
241}
242
243WIDGET_SETTER("value_compat,selected", bool, gui2::selectable_item)
244{
245 w.set_value_bool(value);
246}
247
248WIDGET_GETTER("value_compat,text", std::string, gui2::text_box)
249{
250 return w.get_value();
251}
252
253WIDGET_SETTER("value_compat,text", std::string, gui2::text_box)
254{
255 w.set_value(value);
256}
257
258WIDGET_GETTER("value_compat,value", int, gui2::slider)
259{
260 return w.get_value();
261}
262
263WIDGET_SETTER("value_compat,value", int, gui2::slider)
264{
265 w.set_value(value);
266}
267
268WIDGET_GETTER("best_slider_length", int, gui2::slider)
269{
270 return w.get_best_slider_length();
271}
272
273WIDGET_SETTER("best_slider_length", int, gui2::slider)
274{
275 if(value < 0) {
276 throw std::invalid_argument("best_slider_length must be >= 0");
277 }
278 w.set_best_slider_length(value);
279}
280
281WIDGET_GETTER("max_value", int, gui2::slider)
282{
283 return w.get_maximum_value();
284}
285
286WIDGET_SETTER("max_value", int, gui2::slider)
287{
288 w.set_value_range(w.get_minimum_value(), value);
289}
290
291WIDGET_GETTER("maximum_value_label", t_string, gui2::slider)
292{
293 return w.get_maximum_value_label();
294}
295
296WIDGET_SETTER("maximum_value_label", t_string, gui2::slider)
297{
298 w.set_maximum_value_label(value);
300}
301
302WIDGET_GETTER("min_value", int, gui2::slider)
303{
304 return w.get_minimum_value();
305}
306
307WIDGET_SETTER("min_value", int, gui2::slider)
308{
309 w.set_value_range(value, w.get_maximum_value());
310}
311
312WIDGET_GETTER("minimum_value_label", t_string, gui2::slider)
313{
314 return w.get_minimum_value_label();
315}
316
317WIDGET_SETTER("minimum_value_label", t_string, gui2::slider)
318{
319 w.set_minimum_value_label(value);
321}
322
323WIDGET_GETTER("value_compat,percentage", int, gui2::progress_bar)
324{
325 return w.get_percentage();
326}
327
328WIDGET_SETTER("value_compat,percentage", int, gui2::progress_bar)
329{
330 w.set_percentage(value);
331}
332
333WIDGET_GETTER("value_compat,selected_item_path", std::vector<int>, gui2::tree_view)
334{
335 auto res = w.selected_item()->describe_path();
336 for(int& a : res) { ++a;}
337 return res;
338}
339
340WIDGET_GETTER("path", std::vector<int>, gui2::tree_view_node)
341{
342 auto res = w.describe_path();
343 for(int& a : res) { ++a;}
344 return res;
345}
346
348{
349 return !w.get_root_node().is_folded();
350}
351
352WIDGET_SETTER("value_compat,unfolded", bool, gui2::tree_view)
353{
354 if(value) {
355 w.get_root_node().unfold();
356 } else {
357 w.get_root_node().fold();
358 }
359}
360
362{
363 return !w.is_folded();
364}
365
366WIDGET_SETTER("value_compat,unfolded", bool, gui2::tree_view_node)
367{
368 if(value) {
369 w.unfold();
370 } else {
371 w.fold();
372 }
373}
374
376{
377 if(const unit_type* ut = luaW_tounittype(L, value.index)) {
378 w.set_display_data(*ut);
379 } else if(unit* u = luaW_tounit(L, value.index)) {
380 w.set_display_data(*u);
381 } else {
382 luaW_type_error(L, value.index, "unit or unit type");
383 }
384}
385
386WIDGET_GETTER("item_count", int, gui2::combobox)
387{
388 return w.get_item_count();
389}
390
391WIDGET_GETTER("item_count", int, gui2::listbox)
392{
393 return w.get_item_count();
394}
395
397{
398 return w.get_page_count();
399}
400
402{
403 return w.get_layer_count();
404}
405
407{
408 const gui2::tree_view_node& tvn = w.get_root_node();
409 return tvn.count_children();
410}
411
413{
414 return w.count_children();
415}
416
418{
419 return w.get_use_markup();
420}
421
423{
424 w.set_use_markup(value);
425}
426
427//TODO: while i think this shortcut is useful, i'm not that happy about
428// the name since it changes 'label' and not 'text', the first one
429// is the label that is part of most widgets (like checkboxes), the
430// later is specific to input textboxes.
432{
433 w.set_use_markup(true);
434 w.set_label(value);
435}
436
437WIDGET_GETTER("characters_per_line", int, gui2::label)
438{
439 return w.get_characters_per_line();
440}
441
442WIDGET_SETTER("characters_per_line", int, gui2::label)
443{
444 if(value < 0) {
445 throw std::invalid_argument("characters_per_line must be >= 0");
446 }
447 w.set_characters_per_line(value);
449}
450
452{
453 return w.is_editable();
454}
455
457{
458 w.set_editable(value);
459}
460
461WIDGET_GETTER("ellipsize_mode", std::string, gui2::styled_widget)
462{
463 return gui2::encode_ellipsize_mode(w.get_text_ellipse_mode());
464}
465
466WIDGET_SETTER("ellipsize_mode", std::string, gui2::styled_widget)
467{
468 w.set_text_ellipse_mode(gui2::decode_ellipsize_mode(value));
470}
471
473{
474 return w.get_active();
475}
476
478{
479 w.set_active(value);
480}
481
483{
484 return w.help_message();
485}
486
488{
489 w.set_help_message(value);
490}
491
492WIDGET_GETTER("hint_image", std::string, gui2::combobox)
493{
494 return w.get_hint_image();
495}
496
497WIDGET_SETTER("hint_image", std::string, gui2::combobox)
498{
499 w.set_hint_image(value);
501}
502
504{
505 return w.get_hint_text();
506}
507
509{
510 w.set_hint_text(value);
512}
513
514WIDGET_GETTER("hint_image", std::string, gui2::text_box)
515{
516 return w.get_hint_image();
517}
518
519WIDGET_SETTER("hint_image", std::string, gui2::text_box)
520{
521 w.set_hint_image(value);
523}
524
526{
527 return w.get_hint_text();
528}
529
531{
532 w.set_hint_text(value);
534}
535
536WIDGET_SETTER("history", std::string, gui2::text_box)
537{
538 w.set_history(value);
539}
540
541WIDGET_GETTER("indentation_step_size", int, gui2::tree_view)
542{
543 return w.get_indentation_step_size();
544}
545
546WIDGET_SETTER("indentation_step_size", int, gui2::tree_view)
547{
548 if(value < 0) {
549 throw std::invalid_argument("indentation_step_size must be >= 0");
550 }
551 w.set_indentation_step_size(value);
553}
554
555WIDGET_GETTER("link_aware", bool, gui2::label)
556{
557 return w.get_link_aware();
558}
559
560WIDGET_SETTER("link_aware", bool, gui2::label)
561{
562 w.set_link_aware(value);
564}
565
566WIDGET_GETTER("link_aware", bool, gui2::rich_label)
567{
568 return w.get_link_aware();
569}
570
571WIDGET_SETTER("link_aware", bool, gui2::rich_label)
572{
573 w.set_link_aware(value);
575}
576
578{
579 return w.get_link_aware();
580}
581
583{
584 w.set_link_aware(value);
586}
587
589{
590 return w.get_link_aware();
591}
592
594{
595 w.set_link_aware(value);
597}
598
599WIDGET_GETTER("link_color", std::string, gui2::label)
600{
601 return w.get_link_color().to_hex_string();
602}
603
604WIDGET_GETTER("link_color", std::string, gui2::rich_label)
605{
606 return w.get_link_color().to_hex_string();
607}
608
609WIDGET_GETTER("max_input_length", int, gui2::combobox)
610{
611 return w.get_max_input_length();
612}
613
614WIDGET_SETTER("max_input_length", int, gui2::combobox)
615{
616 if(value < 0) {
617 throw std::invalid_argument("max_input_length must be >= 0");
618 }
619 w.set_max_input_length(value);
621}
622
623WIDGET_GETTER("max_input_length", int, gui2::text_box)
624{
625 return w.get_max_input_length();
626}
627
628WIDGET_SETTER("max_input_length", int, gui2::text_box)
629{
630 if(value < 0) {
631 throw std::invalid_argument("max_input_length must be >= 0");
632 }
633 w.set_max_input_length(value);
635}
636
637WIDGET_GETTER("selection_start", int, gui2::text_box_base)
638{
639 return w.get_selection_start() + 1;
640}
641
642WIDGET_GETTER("selection_length", int, gui2::text_box_base)
643{
644 return w.get_selection_length();
645}
646
647WIDGET_SETTER("selection_start", int, gui2::text_box_base)
648{
649 if(value < 1) {
650 throw std::invalid_argument("selection_start must be >= 1");
651 }
652 w.set_selection_start(value - 1);
653}
654
655WIDGET_SETTER("selection_length", int, gui2::text_box_base)
656{
657 w.set_selection_length(value);
658}
659
660WIDGET_GETTER("step_size", int, gui2::slider)
661{
662 return w.get_step_size();
663}
664
665WIDGET_SETTER("step_size", int, gui2::slider)
666{
667 if(value < 0) {
668 throw std::invalid_argument("step_size must be >= 0");
669 }
670 w.set_step_size(value);
671}
672
673WIDGET_GETTER("text_alignment", std::string, gui2::styled_widget)
674{
675 return gui2::encode_text_alignment(w.get_text_alignment());
676}
677
678WIDGET_SETTER("text_alignment", std::string, gui2::styled_widget)
679{
680 w.set_text_alignment(gui2::decode_text_alignment(value));
681}
682
684{
685 return w.tooltip();
686}
687
689{
690 w.set_tooltip(value);
691}
692
693WIDGET_GETTER("overflow_to_tooltip", bool, gui2::styled_widget)
694{
695 return w.get_use_tooltip_on_label_overflow();
696}
697
698WIDGET_SETTER("overflow_to_tooltip", bool, gui2::styled_widget)
699{
700 w.set_use_tooltip_on_label_overflow(value);
702}
703
705{
706 return w.can_wrap();
707}
708
710{
711 w.set_can_wrap(value);
712}
713
715{
716 return w.can_wrap();
717}
718
720{
721 w.set_can_wrap(value);
722}
723
725{
726 if(!luaW_getglobal(L, "gui", "widget", "set_callback")) {
727 ERR_LUA << "gui.widget.set_callback didn't exist";
728 }
729 luaW_pushwidget(L, w);
730 lua_pushvalue(L, value.index);
731 lua_call(L, 2, 0);
732}
733
734WIDGET_GETTER("visible", std::string, gui2::styled_widget)
735{
736 std::string s;
737 switch(w.get_visible()) {
739 s = "visible";
740 break;
742 s = "hidden";
743 break;
745 s = "invisible";
746 }
747
748 return s;
749}
750
751
753{
754
755 typedef gui2::styled_widget::visibility visibility;
756
757 visibility flag = visibility::visible;
758
759 switch(lua_type(L, value.index)) {
760 case LUA_TBOOLEAN:
761 flag = luaW_toboolean(L, value.index)
762 ? visibility::visible
763 : visibility::invisible;
764 break;
765 case LUA_TSTRING:
766 {
767 const std::string& str = lua_tostring(L, value.index);
768 if(str == "visible") {
769 flag = visibility::visible;
770 } else if(str == "hidden") {
771 flag = visibility::hidden;
772 } else if(str == "invisible") {
773 flag = visibility::invisible;
774 } else {
775 luaL_argerror(L, value.index, "string must be one of: visible, hidden, invisible");
776 }
777 }
778 break;
779 default:
780 luaW_type_error(L, value.index, "boolean or string");
781 }
782
783 w.set_visible(flag);
784
785 if(flag == visibility::hidden) {
786 // HACK: this is needed to force the widget to be repainted immediately
787 // to get rid of its ghost image.
788 gui2::window* window = w.get_window();
789 if(window) {
790 window->invalidate_layout();
791 }
792 }
793}
794
796{
797 return w.get_label();
798}
799
800//must be last
802{
803 gui2::window* window = w.get_window();
804 if(window) {
805 window->invalidate_layout();
806 }
807 w.set_label(value);
808}
809
810WIDGET_GETTER("type", std::string, gui2::widget)
811{
812 if(const gui2::styled_widget* sw = dynamic_cast<const gui2::styled_widget*>(&w)) {
813 return sw->get_control_type();
814 }
815 else if(dynamic_cast<const gui2::tree_view_node*>(&w)) {
816 return "tree_view_node";
817 }
818 else if(dynamic_cast<const gui2::grid*>(&w)) {
819 return "grid";
820 }
821 else {
822 return "";
823 }
824}
825
826///////////////////////////////////////////////////////
827////////////////////// CALLBACKS //////////////////////
828///////////////////////////////////////////////////////
829namespace {
830
831void dialog_callback(lua_State* L, lua_ptr<gui2::widget>& wp, const std::string& id)
832{
833 gui2::widget* w = wp.get_ptr();
834 if(!w) {
835 ERR_LUA << "widget was deleted";
836 return;
837 }
838 gui2::window* wd = w->get_window();
839 if(!wd) {
840 ERR_LUA << "cannot find window in widget callback";
841 return;
842 }
843 luaW_callwidgetcallback(L, w, wd, id);
844}
845
846void link_callback(lua_State* L, lua_ptr<gui2::widget>& wp, const std::string& id, const std::string& dest)
847{
848 gui2::widget* w = wp.get_ptr();
849 if(!w) {
850 ERR_LUA << "widget was deleted";
851 return;
852 }
853 gui2::window* wd = w->get_window();
854 if(!wd) {
855 ERR_LUA << "cannot find window in widget callback";
856 return;
857 }
858 luaW_getwidgetcallback(L, w, wd, id);
859 assert(lua_isfunction(L, -1));
860 lua_pushstring(L, dest.c_str());
861 luaW_pushwidget(L, *w);
862 lua_call(L, 2, 0);
863}
864
866{
867 gui2::window* wd = w.get_window();
868 if(!wd) {
869 throw std::invalid_argument("the widget has no window assigned");
870 }
871 lua_pushvalue(L, value.index);
872 if (!luaW_setwidgetcallback(L, &w, wd, "on_modified")) {
873 connect_signal_notify_modified(w, std::bind(&dialog_callback, L, lua_ptr<gui2::widget>(w), "on_modified"));
874 }
875}
876
878{
879 gui2::window* wd = w.get_window();
880 if(!wd) {
881 throw std::invalid_argument("the widget has no window assigned");
882 }
883
884 lua_pushvalue(L, value.index);
885 if (!luaW_setwidgetcallback(L, &w, wd, "on_link_click")) {
886 w.register_link_callback(
887 std::bind(&link_callback, L, lua_ptr<gui2::widget>(w), "on_link_click", std::placeholders::_1));
888 }
889}
890
892{
893 gui2::window* wd = w.get_window();
894 if(!wd) {
895 throw std::invalid_argument("the widget has no window assigned");
896 }
897 lua_pushvalue(L, value.index);
898 if (!luaW_setwidgetcallback(L, &w, wd, "on_left_click")) {
899 connect_signal_mouse_left_click(w, std::bind(&dialog_callback, L, lua_ptr<gui2::widget>(w), "on_left_click"));
900 }
901}
902
903WIDGET_SETTER("on_double_click", lua_index_raw, gui2::widget)
904{
905 gui2::window* wd = w.get_window();
906 if(!wd) {
907 throw std::invalid_argument("the widget has no window assigned");
908 }
909 lua_pushvalue(L, value.index);
910 if (!luaW_setwidgetcallback(L, &w, wd, "on_double_click")) {
911 connect_signal_mouse_left_double_click(w, std::bind(&dialog_callback, L, lua_ptr<gui2::widget>(w), "on_double_click"));
912 }
913}
914
915WIDGET_SETTER("on_button_click", lua_index_raw, gui2::widget)
916{
917 gui2::window* wd = w.get_window();
918 gui2::clickable_item* cl = dynamic_cast<gui2::clickable_item*>(&w);
919
920 if(!wd) {
921 throw std::invalid_argument("the widget has no window assigned");
922 }
923 if(!cl) {
924 throw std::invalid_argument("unsupported widget");
925 }
926 lua_pushvalue(L, value.index);
927 if (!luaW_setwidgetcallback(L, &w, wd, "on_button_click")) {
928 cl->connect_click_handler(std::bind(&dialog_callback, L, lua_ptr<gui2::widget>(w), "on_button_click"));
929 }
930}
931
932}
933
934namespace lua_widget {
935
936int impl_widget_get(lua_State* L)
937{
939 if(lua_isinteger(L, 2)) {
940
941 if(auto pwidget = find_child_by_index(w, luaL_checkinteger(L, 2))) {
942 luaW_pushwidget(L, *pwidget);
943 return 1;
944 }
945
946 }
947 std::string_view str = lua_check<std::string_view>(L, 2);
948
949 tgetters::iterator it = getters.find(std::string(str));
950 if(it != getters.end()) {
951 for(const auto& func : it->second) {
952 if(func(L, w, false)) {
953 return 1;
954 }
955 }
956 }
957 if(luaW_getglobal(L, "gui", "widget", std::string(str).c_str())) {
958 return 1;
959 }
960 if(auto pwidget = find_child_by_name(w, std::string(str))) {
961 luaW_pushwidget(L, *pwidget);
962 return 1;
963 }
964 ERR_LUA << "invalid property of '" << typeid(w).name()<< "' widget :" << str;
965 std::string err = "invalid property of widget: ";
966 err += str;
967 return luaL_argerror(L, 2, err.c_str());
968}
969
970int impl_widget_set(lua_State* L)
971{
973 std::string_view str = lua_check<std::string_view>(L, 2);
974
975
976 tsetters::iterator it = setters.find(std::string(str));
977 if(it != setters.end()) {
978 for(const auto& func : it->second) {
979 if(func(L, 3, w, false)) {
980 return 0;
981 }
982 }
983 ERR_LUA << "none of "<< it->second.size() << " setters matched";
984 }
985 else {
986 ERR_LUA << "unknown property id : " << str << " #known properties=" << setters.size();
987
988 }
989 ERR_LUA << "invalid modifiable property of '" << typeid(w).name()<< "' widget:" << str;
990 std::string err = "invalid modifiable property of widget: ";
991 err += str;
992 return luaL_argerror(L, 2, err.c_str());
993}
994
995int impl_widget_dir(lua_State* L)
996{
998 std::vector<std::string> keys;
999 // Add any readable keys
1000 for(const auto& [key, funcs] : getters) {
1001 if(key == "value_compat") continue;
1002 for(const auto& func : funcs) {
1003 if(func(L, w, true)){
1004 keys.push_back(key);
1005 break;
1006 }
1007 }
1008 }
1009 // Add any writable keys
1010 for(const auto& [key, funcs] : setters) {
1011 if(key == "value_compat") continue;
1012 if(key == "callback") continue;
1013 for(const auto& func : funcs) {
1014 if(func(L, 0, w, true)){
1015 keys.push_back(key);
1016 break;
1017 }
1018 }
1019 }
1020 // Add any nested widget IDs
1022 for(auto child = iter_t(w); !child.at_end(); child.next()) {
1023 const auto& key = child->id();
1024 if(!key.empty() && key != w.id()) {
1025 keys.push_back(key);
1026 }
1027 }
1028 // Add the gui.widget methods
1029 luaW_getglobal(L, "gui", "widget");
1030 auto methods = luaW_get_attributes(L, -1);
1031 keys.insert(keys.end(), methods.begin(), methods.end());
1032 lua_push(L, keys);
1033 return 1;
1034}
1035}
#define ERR_LUA
Small concept class.
virtual void connect_click_handler(const event::signal &signal)=0
Connects a signal handler for a 'click' event.
Class for a combobox.
Definition combobox.hpp:37
Base container class.
Definition grid.hpp:32
The iterator class.
Definition iterator.hpp:37
The listbox class.
Definition listbox.hpp:41
A rich_label takes marked up text and shows it correctly formatted and wrapped but no scrollbars are ...
Small abstract helper class.
Abstract base class for text items.
A widget that allows the user to input text in single line.
Definition text_box.hpp:125
tree_view_node & get_child_at(int index)
std::size_t count_children() const
The number of children in this widget.
Base class for all widgets.
Definition widget.hpp:55
virtual widget * find(const std::string_view id, const bool must_be_active)
Returns a widget with the wanted id.
Definition widget.cpp:560
const std::string & id() const
Definition widget.cpp:110
window * get_window()
Get the parent window.
Definition widget.cpp:117
visibility
Visibility settings done by the user.
Definition widget.hpp:65
@ visible
The user sets the widget visible, that means:
@ invisible
The user set the widget invisible, that means:
@ hidden
The user sets the widget hidden, that means:
base class of top level items, the only item which needs to store the final canvases to draw on.
Definition window.hpp:59
void invalidate_layout()
Updates the size of the window.
Definition window.cpp:759
T must inherit enable_lua_ptr<T>
Definition lua_ptr.hpp:66
T * get_ptr()
Definition lua_ptr.hpp:69
A single unit type that the player may recruit.
Definition types.hpp:43
This class represents a single unit of a specific type.
Definition unit.hpp:39
This file contains the window object, this object is a top level container which has the event manage...
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.
Definition lua_unit.cpp:142
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 luaW_pushwidget(lua_State *L, gui2::widget &w)
gui2::widget & luaW_checkwidget(lua_State *L, int n)
bool luaW_setwidgetcallback(lua_State *L, gui2::widget *wg, gui2::window *owner, std::string_view name)
returns true if a callback already existed.
void luaW_getwidgetcallback(lua_State *L, gui2::widget *wg, gui2::window *owner, std::string_view name)
pushed ther callback function onoto the stack [-0, +1, -]
void luaW_callwidgetcallback(lua_State *L, gui2::widget *wg, gui2::window *owner, std::string_view name)
callas a widgets callback [-0, +0, e]
std::map< std::string, std::vector< std::function< bool(lua_State *, int, gui2::widget &, bool)> > > tsetters
#define WIDGET_GETTER(name, value_type, widgt_type)
#define ERR_LUA
static lg::log_domain log_scripting_lua("scripting/lua")
#define WIDGET_SETTER(name, value_type, widgt_type)
std::map< std::string, std::vector< std::function< bool(lua_State *, gui2::widget &, bool)> > > tgetters
static tsetters setters
void register_widget_attribute(const char *name)
static gui2::widget * find_child_by_index(gui2::widget &w, int i)
static gui2::widget * find_child_by_name(gui2::widget &w, const std::string &m)
static void try_invalidate_layout(gui2::widget &w)
static tgetters getters
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.
void connect_signal_mouse_left_double_click(dispatcher &dispatcher, const signal &signal)
Connects a signal handler for a left mouse button double click.
std::string encode_ellipsize_mode(const PangoEllipsizeMode ellipsize_mode)
Converts a PangoEllipsizeMode to its string representation.
Definition helper.cpp:116
std::map< std::string, t_string > widget_item
Definition widget.hpp:33
PangoAlignment decode_text_alignment(const std::string &alignment)
Converts a text alignment string to a text alignment.
Definition helper.cpp:84
std::string encode_text_alignment(const PangoAlignment alignment)
Converts a PangoAlignment to its string representation.
Definition helper.cpp:130
PangoEllipsizeMode decode_ellipsize_mode(const std::string &ellipsize_mode)
Converts a text ellipsize mode string to a PangoEllipsizeMode.
Definition helper.cpp:99
int impl_widget_set(lua_State *L)
int impl_widget_get(lua_State *L)
int impl_widget_dir(lua_State *L)
void split_foreach(std::string_view s, char sep, const int flags, const F &f)
int w
Definition pathfind.cpp:188
void lua_push(lua_State *L, const T &val)
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
static map_location::direction n
static map_location::direction sw
static map_location::direction s
#define i