The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
pane.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2012 - 2016 by Mark de Wever <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
17 #include "gui/widgets/pane.hpp"
18 
20 #include "gui/core/log.hpp"
21 #include "gui/widgets/grid.hpp"
22 #include "gui/widgets/window.hpp"
23 #include "utils/const_clone.hpp"
25 #include "gettext.hpp"
26 
27 #include "utils/functional.hpp"
28 
29 #define LOG_SCOPE_HEADER "tpane [" + id() + "] " + __func__
30 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
31 
32 namespace gui2
33 {
34 
35 // ------------ WIDGET -----------{
36 
37 /**
38  * Helper to implement private functions without modifying the header.
39  *
40  * The class is a helper to avoid recompilation and only has static
41  * functions. It also facilitates to create duplicates of functions for a const
42  * and a non-const member function.
43  */
45 {
46  /**
47  * Implementation for the wrappers for
48  * [const] twidget* tpane::find_at(const tpoint&, const bool) [const].
49  *
50  * @tparam W A pointer to the pane.
51  */
52  template <class W>
54  find_at(W pane, tpoint coordinate, const bool must_be_active)
55  {
56 
57  /*
58  * First test whether the mouse is at the pane.
59  */
60  if(pane->twidget::find_at(coordinate, must_be_active) != pane) {
61  return nullptr;
62  }
63 
65  for(thack item : pane->items_)
66  {
67 
68  if(item.grid->get_visible() == twidget::tvisible::invisible) {
69  continue;
70  }
71 
72  /*
73  * If the adjusted coordinate is in the item's grid let the grid
74  * resolve the coordinate.
75  */
76  const SDL_Rect rect = item.grid->get_rectangle();
77  if(coordinate.x >= rect.x && coordinate.y >= rect.y
78  && coordinate.x < rect.x + rect.w
79  && coordinate.y < rect.y + rect.h) {
80 
81  return item.grid->find_at(coordinate, must_be_active);
82  }
83  }
84 
85  return nullptr;
86  }
87 
88  /**
89  * Implementation for the wrappers for
90  * [const] tgrid* tpane::grid(const unsigned id) [const].
91  *
92  * @tparam W A pointer to the pane.
93  */
94  template <class W>
96  grid(W pane, const unsigned id)
97  {
99  for(thack item : pane->items_)
100  {
101 
102  if(item.id == id) {
103  return item.grid;
104  }
105  }
106 
107  return nullptr;
108  }
109 };
110 
111 tpane::tpane(const tbuilder_grid_ptr item_builder)
112  : twidget()
113  , items_()
114  , item_builder_(item_builder)
115  , item_id_generator_(0)
116  , placer_(tplacer_::build(tplacer_::tgrow_direction::vertical, 1))
117 {
118  connect_signal<event::REQUEST_PLACEMENT>(
119  std::bind(
120  &tpane::signal_handler_request_placement, this, _1, _2, _3),
122 }
123 
125  : twidget(builder)
126  , items_()
127  , item_builder_(builder.item_definition)
128  , item_id_generator_(0)
129  , placer_(tplacer_::build(builder.grow_direction, builder.parallel_items))
130 {
131  connect_signal<event::REQUEST_PLACEMENT>(
132  std::bind(
133  &tpane::signal_handler_request_placement, this, _1, _2, _3),
135 }
136 
138 {
139  return new tpane(builder);
140 }
141 
142 unsigned tpane::create_item(const std::map<std::string, string_map>& item_data,
143  const std::map<std::string, std::string>& tags)
144 {
145  titem item = { item_id_generator_++, tags, item_builder_->build() };
146 
147  item.grid->set_parent(this);
148 
149  for(const auto & data : item_data)
150  {
151  tcontrol* control
152  = find_widget<tcontrol>(item.grid, data.first, false, false);
153 
154  if(control) {
155  control->set_members(data.second);
156  }
157  }
158 
159  items_.push_back(item);
160 
161  event::tmessage message;
162  fire(event::REQUEST_PLACEMENT, *this, message);
163 
164  return item.id;
165 }
166 
167 void tpane::place(const tpoint& origin, const tpoint& size)
168 {
169  DBG_GUI_L << LOG_HEADER << '\n';
170  twidget::place(origin, size);
171 
172  assert(origin.x == 0);
173  assert(origin.y == 0);
174 
175  place_children();
176 }
177 
178 void tpane::layout_initialise(const bool full_initialisation)
179 {
180  DBG_GUI_D << LOG_HEADER << '\n';
181 
182  twidget::layout_initialise(full_initialisation);
183 
184  for(auto & item : items_)
185  {
186  if(item.grid->get_visible() != twidget::tvisible::invisible) {
187  item.grid->layout_initialise(full_initialisation);
188  }
189  }
190 }
191 
192 void
193 tpane::impl_draw_children(surface& frame_buffer, int x_offset, int y_offset)
194 {
195  DBG_GUI_D << LOG_HEADER << '\n';
196 
197  for(auto & item : items_)
198  {
199  if(item.grid->get_visible() != twidget::tvisible::invisible) {
200  item.grid->draw_children(frame_buffer, x_offset, y_offset);
201  }
202  }
203 }
204 
206  const std::vector<twidget*>& call_stack)
207 {
208  for(auto & item : items_)
209  {
210  std::vector<twidget*> child_call_stack = call_stack;
211  item.grid->populate_dirty_list(caller, child_call_stack);
212  }
213 }
214 
215 void tpane::sort(const tcompare_functor& compare_functor)
216 {
217  items_.sort(compare_functor);
218 
220 }
221 
222 void tpane::filter(const tfilter_functor& filter_functor)
223 {
224  for(auto & item : items_)
225  {
226  item.grid->set_visible(filter_functor(item)
229  }
230 
232 }
233 
234 void tpane::request_reduce_width(const unsigned /*maximum_width*/)
235 {
236 }
237 
238 twidget* tpane::find_at(const tpoint& coordinate, const bool must_be_active)
239 {
240  return tpane_implementation::find_at(this, coordinate, must_be_active);
241 }
242 
243 const twidget* tpane::find_at(const tpoint& coordinate,
244  const bool must_be_active) const
245 {
246  return tpane_implementation::find_at(this, coordinate, must_be_active);
247 }
248 
250 {
252  return placer_->get_size();
253 }
254 
256 {
257  return false;
258 }
259 
261 {
262  /**
263  * @todo Implement properly.
264  */
265  return nullptr;
266 }
267 
268 tgrid* tpane::grid(const unsigned id)
269 {
270  return tpane_implementation::grid(this, id);
271 }
272 
273 const tgrid* tpane::grid(const unsigned id) const
274 {
275  return tpane_implementation::grid(this, id);
276 }
277 
279 {
281  unsigned index = 0;
282  for(auto & item : items_)
283  {
284  if(item.grid->get_visible() == twidget::tvisible::invisible) {
285  continue;
286  }
287 
288  const tpoint origin = placer_->get_origin(index);
289  item.grid->place(origin, item.grid->get_best_size());
290  ++index;
291  }
292 }
293 
295 {
297  unsigned index = 0;
298  for(auto & item : items_)
299  {
300  if(item.grid->get_visible() == twidget::tvisible::invisible) {
301  continue;
302  }
303 
304  const tpoint origin = placer_->get_origin(index);
305  item.grid->set_origin(origin);
306  ++index;
307  }
308 }
309 
311 {
313  unsigned index = 0;
314  for(auto & item : items_)
315  {
316  if(item.grid->get_visible() == twidget::tvisible::invisible) {
317  continue;
318  }
319 
320  const tpoint origin = placer_->get_origin(index);
321  if(item.grid->get_size() != item.grid->get_best_size()) {
322  item.grid->place(origin, item.grid->get_best_size());
323  } else {
324  item.grid->set_origin(origin);
325  }
326  ++index;
327  }
328 }
329 
331 {
332  assert(placer_.get());
333  placer_->initialise();
334 
335  for(const auto & item : items_)
336  {
337  if(item.grid->get_visible() == twidget::tvisible::invisible) {
338  continue;
339  }
340 
341  placer_->add_item(item.grid->get_best_size());
342  }
343 }
344 
345 void tpane::signal_handler_request_placement(tdispatcher& dispatcher,
346  const event::tevent event,
347  bool& handled)
348 {
349  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
350 
351  twidget* widget = dynamic_cast<twidget*>(&dispatcher);
352  if(widget) {
353  for(auto & item : items_)
354  {
355  if(item.grid->has_widget(*widget)) {
356  if(item.grid->get_visible() != twidget::tvisible::invisible) {
357 
358  /*
359  * This time we call init layout but also the linked widget
360  * update this makes things work properly for the
361  * addon_list. This code can use some more tuning,
362  * polishing and testing.
363  */
364  item.grid->layout_initialise(false);
366 
367  /*
368  * By not calling init layout it uses its previous size
369  * what seems to work properly when showing and hiding
370  * items. Might fail with new items (haven't tested yet).
371  */
372  item.grid->place(tpoint(0, 0), item.grid->get_best_size());
373  }
375  DBG_GUI_E << LOG_HEADER << ' ' << event << " handled.\n";
376  handled = true;
377  return;
378  }
379  }
380  }
381 
382  DBG_GUI_E << LOG_HEADER << ' ' << event << " failed to handle.\n";
383  assert(false);
384  handled = false;
385 }
386 
387 // }---------- BUILDER -----------{
388 
389 /*WIKI_MACRO
390  * @begin{macro}{pane_description}
391  *
392  * A pane is a container where new members can be added and removed
393  * during run-time.
394  * @end{macro}
395  */
396 
397 /*WIKI
398  * @page = GUIWidgetInstanceWML
399  * @order = 2_viewport
400  * @begin{parent}{name="gui/window/resolution/grid/row/column/"}
401  * @begin{tag}{name="pane"}{min=0}{max=-1}{super="generic/widget_instance"}
402  * == Label ==
403  *
404  * @macro = viewport_description
405  *
406  * List with the label specific variables:
407  * @begin{table}{config}
408  * grow_direction & grow_direction & &
409  * The direction in which new items grow. $
410  * parallel_items & unsigned & &
411  * The number of items that are growing in
412  * parallel. $
413  * item_definition & section & &
414  * The definition of a new item. $
415  * @end{table}
416  *
417  * @begin{tag}{name="item_definition"}{min=1}{max=1}{super="gui/window/resolution/grid"}
418  * @end{tag}{name="item_definition"}
419  * @end{tag}{name="pane"}
420  * @end{parent}{name="gui/window/resolution/grid/row/column/"}
421  */
422 
423 namespace implementation
424 {
425 
427  : tbuilder_widget(cfg)
428  , grow_direction(
429  lexical_cast<tplacer_::tgrow_direction>(cfg["grow_direction"]))
430  , parallel_items(cfg["parallel_items"])
431  , item_definition(new tbuilder_grid(cfg.child("item_definition", "[pane]")))
432 {
433  VALIDATE(parallel_items > 0, _("Need at least 1 parallel item."));
434 }
435 
437 {
438  return build(treplacements());
439 }
440 
441 twidget* tbuilder_pane::build(const treplacements& /*replacements*/) const
442 {
443  return tpane::build(*this);
444 }
445 
446 } // namespace implementation
447 
448 // }------------ END --------------
449 
450 } // namespace gui2
Define the common log macros for the gui toolkit.
void filter(const tfilter_functor &filter_functor)
Filters the contents of the pane.
Definition: pane.cpp:222
static tpane * build(const implementation::tbuilder_pane &builder)
Definition: pane.cpp:137
virtual void place(const tpoint &origin, const tpoint &size) override
See twidget::place.
Definition: pane.cpp:167
#define DBG_GUI_L
Definition: log.hpp:58
void set_parent(twidget *parent)
Definition: widget.cpp:150
virtual void impl_draw_children(surface &frame_buffer, int x_offset, int y_offset) override
See twidget::impl_draw_children.
Definition: pane.cpp:193
twindow * build(CVideo &video, const twindow_builder::tresolution *definition)
Builds a window.
Helper to implement private functions without modifying the header.
Definition: pane.cpp:44
Contains the info needed to instantiate a widget.
void prepare_placement() const
Updates the placement for the child items.
Definition: pane.cpp:330
Base container class.
Definition: grid.hpp:29
Base class for the placement helper.
Definition: placer.hpp:52
std::function< bool(const titem &, const titem &)> tcompare_functor
Definition: pane.hpp:54
This file contains the window object, this object is a top level container which has the event manage...
virtual iterator::twalker_ * create_walker() override
See twidget::create_walker.
Definition: pane.cpp:260
virtual tpoint calculate_best_size() const override
See twidget::calculate_best_size.
Definition: pane.cpp:249
#define LOG_HEADER
Definition: pane.cpp:30
void signal_handler_request_placement(tdispatcher &dispatcher, const event::tevent event, bool &handled)
Definition: pane.cpp:345
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
Definition: glew.h:1347
To lexical_cast(From value)
Lexical cast converts one type to another.
unsigned create_item(const std::map< std::string, string_map > &item_data, const std::map< std::string, std::string > &tags)
Creates a new item.
Definition: pane.cpp:142
virtual void layout_initialise(const bool full_initialisation)
How the layout engine works.
Definition: widget.cpp:162
tgrid * grid(const unsigned id)
Returns a grid in the pane.
Definition: pane.cpp:268
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:62
A class inherited from ttext_box that displays its input as stars.
Definition: field-fwd.hpp:23
#define DBG_GUI_D
Definition: log.hpp:29
The user set the widget invisible, that means:
Definition: widget.hpp:103
tpane(const tbuilder_grid_ptr item_builder)
Definition: pane.cpp:111
tbuilder_grid_ptr item_builder_
The builer for the items in the list.
Definition: pane.hpp:158
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
virtual twidget * find_at(const tpoint &coordinate, const bool must_be_active) override
See twidget::find_at.
Definition: pane.cpp:238
bool fire(const tevent event, twidget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:144
std::list< titem > items_
The items in the pane.
Definition: pane.hpp:155
virtual void child_populate_dirty_list(twindow &caller, const std::vector< twidget * > &call_stack) override
See twidget::child_populate_dirty_list.
Definition: pane.cpp:205
int y
y coordinate.
Definition: point.hpp:34
This file contains the defintions for the gui2::event::tmessage class.
Request for somebody to place the widget.
Definition: handler.hpp:175
virtual void place(const tpoint &origin, const tpoint &size)
Places the widget.
Definition: widget.cpp:233
tevent
The event send to the dispatcher.
Definition: handler.hpp:54
std::function< bool(const titem &)> tfilter_functor
Definition: pane.hpp:56
static utils::tconst_clone< twidget, W >::pointer find_at(W pane, tpoint coordinate, const bool must_be_active)
Implementation for the wrappers for [const] twidget* tpane::find_at(const tpoint&, const bool) [const].
Definition: pane.cpp:54
int x
x coordinate.
Definition: point.hpp:31
void set_origin_children()
Moves the children on the pane.
Definition: pane.cpp:294
The user sets the widget visible, that means:
Definition: widget.hpp:79
#define DBG_GUI_E
Definition: log.hpp:35
unsigned id
Definition: pane.hpp:48
GLuint index
Definition: glew.h:1782
D * pointer
A pointer to the destination type, possibly const qualified.
Definition: const_clone.hpp:56
Holds a 2D point.
Definition: point.hpp:24
tgrid * grid
Definition: pane.hpp:51
twidget * build() const
Definition: pane.cpp:436
std::vector< expression_ptr > items_
Definition: formula.cpp:119
tbuilder_pane(const config &cfg)
Definition: pane.cpp:426
Base class for all visible items.
Definition: control.hpp:34
GLsizeiptr size
Definition: glew.h:1649
cl_event event
Definition: glew.h:3070
virtual void set_members(const string_map &data)
Sets the members of the control.
Definition: control.cpp:99
Base class for all widgets.
Definition: widget.hpp:49
GLsizei GLenum GLuint GLuint GLsizei char * message
Definition: glew.h:2499
std::unique_ptr< tplacer_ > placer_
Helper to do the placement.
Definition: pane.hpp:164
void place_or_set_origin_children()
Places or moves the children on the pane.
Definition: pane.cpp:310
void layout_linked_widgets()
Layouts the linked widgets.
Definition: window.cpp:1194
The walker abstract base class.
Definition: walker.hpp:27
std::map< std::string, boost::intrusive_ptr< tbuilder_widget > > treplacements
The replacements type is used to define replacement types.
virtual void request_reduce_width(const unsigned maximum_width) override
See twidget::request_reduce_width.
Definition: pane.cpp:234
twindow * get_window()
Get the parent window.
Definition: widget.cpp:116
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
static utils::tconst_clone< tgrid, W >::pointer grid(W pane, const unsigned id)
Implementation for the wrappers for [const] tgrid* tpane::grid(const unsigned id) [const]...
Definition: pane.cpp:96
void place_children()
Places the children on the pane.
Definition: pane.cpp:278
bool disable_click_dismiss() const override
See twidget::disable_click_dismiss.
Definition: pane.cpp:255
Contains the implementation details for lexical_cast and shouldn't be used directly.
void sort(const tcompare_functor &compare_functor)
Sorts the contents of the pane.
Definition: pane.cpp:215
virtual void layout_initialise(const bool full_initialisation) override
See twidget::layout_initialise.
Definition: pane.cpp:178
unsigned item_id_generator_
The id generator for the items.
Definition: pane.hpp:161