The Battle for Wesnoth  1.19.18+dev
tab_container.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2024 - 2025
3  by Subhraman Sarkar (babaissarkar) <suvrax@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 
16 #define GETTEXT_DOMAIN "wesnoth-lib"
17 
19 
20 #include "gui/core/log.hpp"
21 #include "gettext.hpp"
24 #include "gui/widgets/listbox.hpp"
25 #include "gui/widgets/settings.hpp"
26 #include "gui/widgets/window.hpp"
27 #include "wml_exception.hpp"
28 
29 #include <functional>
30 
31 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
32 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
33 
34 namespace gui2
35 {
36 
37 // ------------ WIDGET -----------{
38 
39 REGISTER_WIDGET(tab_container)
40 
42 {
43  template<typename W>
45  const std::string_view id,
46  const bool must_be_active)
47  {
48  for(unsigned i = 0; i < stack.get_tab_count(); ++i) {
49  auto* tab_grid = stack.get_tab_grid(i);
50  if(!tab_grid) {
51  continue;
52  }
53 
54  if(W* res = tab_grid->find(id, must_be_active)) {
55  return res;
56  }
57  }
58 
59  return stack.container_base::find(id, must_be_active);
60  }
61 };
62 
64  : container_base(builder, type())
65  , state_(ENABLED)
66  , tab_count_(0)
67  , generator_(nullptr)
68 {
69  const auto conf = cast_config_to<tab_container_definition>();
70  assert(conf);
71 
72  init_grid(*conf->grid);
73 
75 
76  generator_ = generator.get();
77  assert(generator_);
78 
79  const widget_item empty_data;
80  for(const auto& builder_entry : builder.builders) {
81  generator->create_item(-1, *builder_entry, empty_data, nullptr);
82  }
83 
84  grid* parent_grid = find_widget<grid>("_content_grid", false, true);
85  if(parent_grid) {
86  parent_grid->swap_child("_page", std::move(generator), false);
87  }
88 
89  for (const widget_data& row : builder.list_items) {
90  add_tab_entry(row);
91  }
92 
93  tab_count_ = builder.builders.size();
94 
96 }
97 
98 void tab_container::set_self_active(const bool active)
99 {
100  state_ = active ? ENABLED : DISABLED;
101 }
102 
104 {
105  return state_ != DISABLED;
106 }
107 
108 unsigned tab_container::get_state() const
109 {
110  return state_;
111 }
112 
114 {
115  return true;
116 }
117 
119 {
120  return get_grid().find_widget<listbox>("_tab_list", false);
121 }
122 
124 {
125  listbox& list = get_internal_list();
126  list.add_row(row);
127 }
128 
130 {
131  if (index < get_tab_count()) {
133  generator_->select_item(index, true);
134  }
135 }
136 
139  place(get_origin(), get_size());
140  queue_redraw();
141 
142  fire(event::NOTIFY_MODIFIED, *this, nullptr);
143 }
144 
145 widget* tab_container::find(const std::string_view id, const bool must_be_active)
146 {
147  return tab_container_implementation::find<widget>(*this, id, must_be_active);
148 }
149 
150 const widget* tab_container::find(const std::string_view id, const bool must_be_active) const
151 {
152  return tab_container_implementation::find<const widget>(*this, id, must_be_active);
153 }
154 
155 // }---------- DEFINITION ---------{
156 
159 {
160  DBG_GUI_P << "Parsing tab_container " << id;
161 
162  load_resolutions<resolution>(cfg);
163 }
164 
166  : resolution_definition(cfg), grid(nullptr)
167 {
168  // Note the order should be the same as the enum state_t is tab_container.hpp.
169  state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_enabled", missing_mandatory_wml_tag("tab_container_definition][resolution", "state_enabled")));
170  state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_disabled", missing_mandatory_wml_tag("tab_container_definition][resolution", "state_disabled")));
171 
172  auto child = VALIDATE_WML_CHILD(cfg, "grid", _("No grid defined for tab container control"));
173  grid = std::make_shared<builder_grid>(child);
174 }
175 
176 // }---------- BUILDER -----------{
177 
178 namespace implementation
179 {
180 
181 builder_tab_container::builder_tab_container(const config& cfg)
183 {
184  if(cfg.has_child("tab")) {
185  for(const config& tab : cfg.child_range("tab")) {
186  list_items.emplace_back(widget_data{
187  { "image", {{"label", tab["image"].str()}} },
188  { "name", {{"label", tab["name"].t_str()}} }
189  });
190 
191  if(tab.has_child("data")) {
192  auto builder = std::make_shared<builder_grid>(tab.mandatory_child("data"));
193  builders.push_back(builder);
194  }
195  }
196  }
197 }
198 
199 std::unique_ptr<widget> builder_tab_container::build() const
200 {
201  auto widget = std::make_unique<tab_container>(*this);
202  DBG_GUI_G << "Window builder: placed tab_container '" << id
203  << "' with definition '" << definition << "'.";
204  return widget;
205 }
206 
207 } // namespace implementation
208 
209 // }------------ END --------------
210 
211 } //
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:157
child_itors child_range(std::string_view key)
Definition: config.cpp:268
bool has_child(std::string_view key) const
Determine whether a config has a child or not.
Definition: config.cpp:312
A generic container base class.
const grid & get_grid() const
virtual void place(const point &origin, const point &size) override
See widget::place.
void init_grid(const builder_grid &grid_builder)
Initializes and builds the grid.
void connect_signal(const F &func, const queue_position position=back_child)
Adds a callback to the appropriate queue based on event type.
Definition: dispatcher.hpp:351
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:74
virtual void select_item(const unsigned index, const bool select)=0
(De)selects an item.
static std::unique_ptr< generator_base > build(const bool has_minimum, const bool has_maximum, const placement placement, const bool select)
Create a new generator.
Definition: generator.cpp:1160
Basic template class to generate new items.
grid & create_item(const int index, const builder_grid &list_builder, const widget_item &item_data, const std::function< void(widget &)> &callback) override
Inherited from generator_base.
Base container class.
Definition: grid.hpp:32
std::unique_ptr< widget > swap_child(const std::string &id, std::unique_ptr< widget > w, const bool recurse, widget *new_parent=nullptr)
Exchanges a child in the grid.
Definition: grid.cpp:101
The listbox class.
Definition: listbox.hpp:41
grid & add_row(const widget_item &item, const int index=-1)
When an item in the list is selected by the user we need to update the state.
Definition: listbox.cpp:92
bool select_row(const unsigned row, const bool select=true)
Selects a row.
Definition: listbox.cpp:267
state_t state_
Current state of the widget.
virtual unsigned get_state() const override
Returns the id of the state.
generator_base * generator_
Contains a pointer to the generator.
virtual bool get_active() const override
Gets the active state of the styled_widget.
virtual widget * find(const std::string_view id, const bool must_be_active) override
See widget::find.
void add_tab_entry(const widget_data &row)
unsigned get_tab_count() const
virtual void set_self_active(const bool active) override
Helper for set_active.
bool can_wrap() const override
See widget::can_wrap.
void select_tab(unsigned index)
listbox & get_internal_list()
Get the listbox inside which the tabs are shown.
tab_container(const implementation::builder_tab_container &builder)
unsigned get_active_tab_index()
Base class for all widgets.
Definition: widget.hpp:55
void queue_redraw()
Indicates that this widget should be redrawn.
Definition: widget.cpp:464
point get_origin() const
Returns the screen origin of the widget.
Definition: widget.cpp:311
point get_size() const
Returns the size of the widget.
Definition: widget.cpp:316
T * find_widget(const std::string_view id, const bool must_be_active, const bool must_exist)
Gets a widget with the wanted id.
Definition: widget.hpp:747
const config * cfg
std::size_t i
Definition: function.cpp:1032
static std::string _(const char *str)
Definition: gettext.hpp:97
Define the common log macros for the gui toolkit.
#define DBG_GUI_G
Definition: log.hpp:41
#define DBG_GUI_P
Definition: log.hpp:66
This file contains the window object, this object is a top level container which has the event manage...
@ NOTIFY_MODIFIED
Definition: handler.hpp:175
Generic file dialog.
std::map< std::string, widget_item > widget_data
Definition: widget.hpp:36
std::map< std::string, t_string > widget_item
Definition: widget.hpp:33
Contains the implementation details for lexical_cast and shouldn't be used directly.
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:70
typename const_clone< D, S >::reference const_clone_ref
Definition: const_clone.hpp:63
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
This file contains the settings handling of the widget library.
std::string definition
Parameters for the styled_widget.
virtual std::unique_ptr< widget > build() const override
std::vector< std::shared_ptr< builder_grid > > builders
std::vector< state_definition > state
tab_container_definition(const config &cfg)
static W * find(utils::const_clone_ref< tab_container, W > stack, const std::string_view id, const bool must_be_active)
std::string missing_mandatory_wml_tag(const std::string &section, const std::string &tag)
Returns a standard message for a missing wml child (tag).
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
#define VALIDATE_WML_CHILD(cfg, key, message)