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