ManaPlus
basiccontainer.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2011-2018 The ManaPlus Developers
4  *
5  * This file is part of The ManaPlus Client.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 /* _______ __ __ __ ______ __ __ _______ __ __
22  * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\
23  * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
24  * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / /
25  * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / /
26  * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
27  * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
28  *
29  * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
30  *
31  *
32  * Per Larsson a.k.a finalman
33  * Olof Naessén a.k.a jansem/yakslem
34  *
35  * Visit: http://guichan.sourceforge.net
36  *
37  * License: (BSD)
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  * notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  * notice, this list of conditions and the following disclaimer in
45  * the documentation and/or other materials provided with the
46  * distribution.
47  * 3. Neither the name of Guichan nor the names of its contributors may
48  * be used to endorse or promote products derived from this software
49  * without specific prior written permission.
50  *
51  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
52  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
53  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
54  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
55  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
56  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
57  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
58  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
59  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
60  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
61  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62  */
63 
65 
66 #include "utils/checkutils.h"
67 #include "utils/foreach.h"
68 
69 #include "render/graphics.h"
70 
71 #include <algorithm>
72 
73 #include "debug.h"
74 
76 {
77  // +++ virtual method call
78  clear();
79 }
80 
82 {
83  if (widget == nullptr)
84  {
85  reportAlways("BasicContainer::moveToTop empty widget.");
86  return;
87  }
88 
90  {
91  if (*iter == widget)
92  {
93  mWidgets.erase(iter);
94  mWidgets.push_back(widget);
95  break;
96  }
97  }
99  {
100  if (*iter == widget)
101  {
102  mLogicWidgets.erase(iter);
103  mLogicWidgets.push_back(widget);
104  return;
105  }
106  }
107 }
108 
110 {
111  if (widget == nullptr)
112  {
113  reportAlways("BasicContainer::moveToBottom empty widget.");
114  return;
115  }
116  const WidgetListIterator iter = std::find(mWidgets.begin(),
117  mWidgets.end(), widget);
118  if (iter != mWidgets.end())
119  {
120  mWidgets.erase(iter);
121  mWidgets.insert(mWidgets.begin(), widget);
122  }
123 
124  const WidgetListIterator iter2 = std::find(mLogicWidgets.begin(),
125  mLogicWidgets.end(), widget);
126  if (iter2 != mLogicWidgets.end())
127  {
128  mLogicWidgets.erase(iter2);
129  mLogicWidgets.insert(mLogicWidgets.begin(), widget);
130  }
131 }
132 
134 {
135  const WidgetListIterator iter = std::find(mWidgets.begin(),
136  mWidgets.end(), event.getSource());
137  if (iter != mWidgets.end())
138  mWidgets.erase(iter);
139 
140  const WidgetListIterator iter2 = std::find(mLogicWidgets.begin(),
141  mLogicWidgets.end(), event.getSource());
142  if (iter2 != mLogicWidgets.end())
143  mLogicWidgets.erase(iter2);
144 }
145 
147 {
148  return Rect(0, 0, mDimension.width, mDimension.height);
149 }
150 
152 {
154 
155  for (it = mWidgets.begin(); it != mWidgets.end(); ++ it)
156  {
157  if ((*it)->isFocused())
158  break;
159  }
160 
161  const WidgetListConstIterator end = it;
162 
163  if (it == mWidgets.end())
164  it = mWidgets.begin();
165 
166  ++ it;
167 
168  for ( ; it != end; ++ it)
169  {
170  if (it == mWidgets.end())
171  it = mWidgets.begin();
172 
173  if ((*it)->isFocusable())
174  {
175  (*it)->requestFocus();
176  return;
177  }
178  }
179 }
180 
182 {
184 
185  for (it = mWidgets.rbegin(); it != mWidgets.rend(); ++ it)
186  {
187  if ((*it)->isFocused())
188  break;
189  }
190 
191  const WidgetListReverseIterator end = it;
192 
193  ++ it;
194 
195  if (it == mWidgets.rend())
196  it = mWidgets.rbegin();
197 
198  for ( ; it != end; ++ it)
199  {
200  if (it == mWidgets.rend())
201  it = mWidgets.rbegin();
202 
203  if ((*it)->isFocusable())
204  {
205  (*it)->requestFocus();
206  return;
207  }
208  }
209 }
210 
212 {
213  const Rect r = getChildrenArea();
214 
215  if (!r.isPointInRect(x, y))
216  return nullptr;
217 
218  x -= r.x;
219  y -= r.y;
220 
221  for (WidgetListReverseIterator it = mWidgets.rbegin();
222  it != mWidgets.rend(); ++ it)
223  {
224  const Widget *restrict const widget = *it;
225  if (widget->isVisible() &&
226  widget->getDimension().isPointInRect(x, y))
227  {
228  return *it;
229  }
230  }
231 
232  return nullptr;
233 }
234 
236 {
237  BLOCK_START("BasicContainer::logic")
238  if (mVisible == Visible_false)
239  {
240  BLOCK_END("BasicContainer::logic")
241  return;
242  }
243  logicChildren();
244  BLOCK_END("BasicContainer::logic")
245 }
246 
248  focusHandler) restrict2
249 {
250  Widget::setFocusHandler(focusHandler);
251 
252  if (mInternalFocusHandler != nullptr)
253  return;
254 
256  (*iter)->setFocusHandler(focusHandler);
257 }
258 
260 {
261  if (widget == nullptr)
262  return;
263  mWidgets.push_back(widget);
264  if (widget->isAllowLogic())
265  mLogicWidgets.push_back(widget);
266 
267  if (mInternalFocusHandler == nullptr)
268  widget->setFocusHandler(getFocusHandler());
269  else
270  widget->setFocusHandler(mInternalFocusHandler);
271 
272  widget->setParent(this);
273  widget->addDeathListener(this);
274 }
275 
277 {
278  if (widget == nullptr)
279  return;
281  {
282  if (*iter == widget)
283  {
284  mWidgets.erase(iter);
285  widget->setFocusHandler(nullptr);
286  widget->setWindow(nullptr);
287  widget->setParent(nullptr);
288  widget->removeDeathListener(this);
289  break;
290  }
291  }
293  {
294  if (*iter == widget)
295  {
296  mLogicWidgets.erase(iter);
297  return;
298  }
299  }
300 }
301 
303 {
305  {
306  Widget *restrict const widget = *iter;
307  widget->setFocusHandler(nullptr);
308  widget->setWindow(nullptr);
309  widget->setParent(nullptr);
310  widget->removeDeathListener(this);
311  }
312 
313  mWidgets.clear();
314  mLogicWidgets.clear();
315 }
316 
318 {
319  BLOCK_START("BasicContainer::drawChildren")
320  graphics->pushClipArea(getChildrenArea());
321 
323  {
324  Widget *restrict const widget = *iter;
325  if (widget->mVisible == Visible_true)
326  {
327  // If the widget has a frame,
328  // draw it before drawing the widget
329  if (widget->mFrameSize > 0)
330  {
331  Rect rec = widget->mDimension;
332  const int frame = CAST_S32(widget->mFrameSize);
333  const int frame2 = frame * 2;
334  rec.x -= frame;
335  rec.y -= frame;
336  rec.width += frame2;
337  rec.height += frame2;
338  graphics->pushClipArea(rec);
339  BLOCK_START("BasicContainer::drawChildren 1")
340  widget->drawFrame(graphics);
341  BLOCK_END("BasicContainer::drawChildren 1")
342  graphics->popClipArea();
343  }
344 
345  graphics->pushClipArea(widget->mDimension);
346  BLOCK_START("BasicContainer::drawChildren 2")
347  widget->draw(graphics);
348  BLOCK_END("BasicContainer::drawChildren 2")
349  graphics->popClipArea();
350  }
351  }
352 
353  graphics->popClipArea();
354  BLOCK_END("BasicContainer::drawChildren")
355 }
356 
358  restrict2
359 {
360  BLOCK_START("BasicContainer::drawChildren")
361  graphics->pushClipArea(getChildrenArea());
362 
364  {
365  Widget *restrict const widget = *iter;
366  if (widget->mVisible == Visible_true)
367  {
368  // If the widget has a frame,
369  // draw it before drawing the widget
370  if (widget->mFrameSize > 0)
371  {
372  Rect rec = widget->mDimension;
373  const int frame = CAST_S32(widget->mFrameSize);
374  const int frame2 = frame * 2;
375  rec.x -= frame;
376  rec.y -= frame;
377  rec.width += frame2;
378  rec.height += frame2;
379  graphics->pushClipArea(rec);
380  BLOCK_START("BasicContainer::drawChildren 1")
381  widget->safeDrawFrame(graphics);
382  BLOCK_END("BasicContainer::drawChildren 1")
383  graphics->popClipArea();
384  }
385 
386  graphics->pushClipArea(widget->mDimension);
387  BLOCK_START("BasicContainer::drawChildren 2")
388  widget->safeDraw(graphics);
389  BLOCK_END("BasicContainer::drawChildren 2")
390  graphics->popClipArea();
391  }
392  }
393 
394  graphics->popClipArea();
395  BLOCK_END("BasicContainer::drawChildren")
396 }
397 
399 {
400  BLOCK_START("BasicContainer::logicChildren")
402  (*iter)->logic();
403  BLOCK_END("BasicContainer::logicChildren")
404 }
405 
407  const Rect &restrict area) restrict2
408 {
409  if (widget == nullptr)
410  return;
411 
412  const Rect widgetArea = getChildrenArea();
413 
414  const int x = widget->mDimension.x;
415  const int y = widget->mDimension.y;
416  const int ax = area.x + x;
417  const int ay = area.y + y;
418 
419  if (ax < 0)
420  widget->setX(-area.x);
421  else if (ax + area.width > widgetArea.width)
422  widget->setX(widgetArea.width - area.x - area.width);
423 
424  if (ay < 0)
425  widget->setY(-area.y);
426  else if (ay + area.height > widgetArea.height)
427  widget->setY(widgetArea.height - area.y - area.height);
428 }
429 
431  focusHandler) restrict2
432 {
433  Widget::setInternalFocusHandler(focusHandler);
434 
435  FocusHandler *const restrict handler = mInternalFocusHandler != nullptr ?
438  {
439  (*iter)->setFocusHandler(handler);
440  }
441 }
442 
443 Widget *BasicContainer::findFirstWidget(const std::set<Widget*> &restrict list)
444  restrict2
445 {
447  {
448  if (list.find(*iter) != list.end())
449  return *iter;
450  }
451  return nullptr;
452 }
#define FOR_EACH(type, iter, array)
Definition: foreach.h:24
void showWidgetPart(Widget *const widget, const Rect &area)
int width
Definition: rect.h:218
void moveToBottom(Widget *const widget)
const bool Visible_true
Definition: visible.h:29
WidgetList::const_iterator WidgetListConstIterator
Widget * findFirstWidget(const std::set< Widget *> &list)
Definition: rect.h:72
#define BLOCK_START(name)
Definition: perfomance.h:78
bool isPointInRect(const int x_, const int y_) const
Definition: rect.h:196
FocusHandler * getFocusHandler()
Definition: widget.h:473
#define BLOCK_END(name)
Definition: perfomance.h:79
WidgetList mLogicWidgets
#define FOR_EACHR(type, iter, array)
Definition: foreach.h:27
virtual void clear()
bool find(const std::string &key)
Visible mVisible
Definition: widget.h:962
Widget * getWidgetAt(int x, int y)
int x
Definition: rect.h:208
#define CAST_S32
Definition: cast.h:29
const bool Visible_false
Definition: visible.h:29
WidgetList::reverse_iterator WidgetListReverseIterator
int y
Definition: rect.h:213
virtual void logicChildren()
void moveToTop(Widget *const widget)
void add(Widget *const widget)
virtual void remove(Widget *const widget)
FocusHandler * mInternalFocusHandler
Definition: widget.h:1121
void setFocusHandler(FocusHandler *const focusHandler)
int height
Definition: rect.h:223
Definition: widget.h:97
virtual void drawChildren(Graphics *const graphics)
Definition: event.h:77
void setInternalFocusHandler(FocusHandler *const focusHandler)
void death(const Event &event)
#define restrict
Definition: localconsts.h:156
WidgetList mWidgets
virtual void setFocusHandler(FocusHandler *const focusHandler)
Definition: widget.cpp:237
void setInternalFocusHandler(FocusHandler *const internalFocusHandler)
Definition: widget.cpp:460
Rect mDimension
Definition: widget.h:1100
#define reportAlways(...)
Definition: checkutils.h:252
virtual void safeDrawChildren(Graphics *const graphics)
#define restrict2
Definition: localconsts.h:157
WidgetList::iterator WidgetListIterator