ManaPlus
scrollarea.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2004-2009 The Mana World Development Team
4  * Copyright (C) 2009-2010 The Mana Developers
5  * Copyright (C) 2011-2017 The ManaPlus Developers
6  *
7  * This file is part of The ManaPlus Client.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 /* _______ __ __ __ ______ __ __ _______ __ __
24  * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\
25  * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
26  * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / /
27  * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / /
28  * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
29  * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
30  *
31  * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
32  *
33  *
34  * Per Larsson a.k.a finalman
35  * Olof Naessén a.k.a jansem/yakslem
36  *
37  * Visit: http://guichan.sourceforge.net
38  *
39  * License: (BSD)
40  * Redistribution and use in source and binary forms, with or without
41  * modification, are permitted provided that the following conditions
42  * are met:
43  * 1. Redistributions of source code must retain the above copyright
44  * notice, this list of conditions and the following disclaimer.
45  * 2. Redistributions in binary form must reproduce the above copyright
46  * notice, this list of conditions and the following disclaimer in
47  * the documentation and/or other materials provided with the
48  * distribution.
49  * 3. Neither the name of Guichan nor the names of its contributors may
50  * be used to endorse or promote products derived from this software
51  * without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
54  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
55  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
56  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
57  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
58  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
59  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
60  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
61  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
62  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64  */
65 
66 #include "gui/widgets/scrollarea.h"
67 
68 #include "settings.h"
69 
70 #include "gui/gui.h"
71 #include "gui/skin.h"
72 
73 #include "utils/delete2.h"
74 #include "utils/stringutils.h"
75 
76 #include "render/graphics.h"
77 
79 
80 #include "resources/imagerect.h"
81 
82 #include "resources/image/image.h"
83 
84 #include "debug.h"
85 
86 int ScrollArea::instances = 0;
87 float ScrollArea::mAlpha = 1.0;
88 bool ScrollArea::mShowButtons = true;
97 
98 static std::string const buttonFiles[2] =
99 {
100  "scrollbuttons.xml",
101  "scrollbuttons_pressed.xml"
102 };
103 
105  Widget *const widget,
106  const Opaque opaque,
107  const std::string &skin) :
108  BasicContainer(widget2),
109  MouseListener(),
110  WidgetListener(),
111  mVertexes(new ImageCollection),
112  mVertexes2(new ImageCollection),
113  mHPolicy(SHOW_AUTO),
114  mVPolicy(SHOW_AUTO),
115  mVScroll(0),
116  mHScroll(0),
117  mScrollbarWidth(12),
118  mUpButtonScrollAmount(10),
119  mDownButtonScrollAmount(10),
120  mLeftButtonScrollAmount(10),
121  mRightButtonScrollAmount(10),
122  mHorizontalMarkerDragOffset(0),
123  mVerticalMarkerDragOffset(0),
124  mX(0),
125  mY(0),
126  mClickX(0),
127  mClickY(0),
128  mXOffset(0),
129  mYOffset(0),
130  mDrawWidth(0),
131  mDrawHeight(0),
132  mVBarVisible(false),
133  mHBarVisible(false),
134  mUpButtonPressed(false),
135  mDownButtonPressed(false),
136  mLeftButtonPressed(false),
137  mRightButtonPressed(false),
138  mIsVerticalMarkerDragged(false),
139  mIsHorizontalMarkerDragged(false),
140  mOpaque(Opaque_true),
141  mHasMouse(false)
142 {
143  setContent(widget);
144  addMouseListener(this);
145  mOpaque = opaque;
146  init(skin);
147 }
148 
150 {
151  if (gui != nullptr)
152  gui->removeDragged(this);
153 
154  // Garbage collection
155  delete getContent();
156 
157  instances--;
158  if (instances == 0)
159  {
165  for (int i = 0; i < 2; i ++)
166  {
167  for (int f = UP; f < BUTTONS_DIR; f ++)
168  {
169  if (buttons[f][i] != nullptr)
170  buttons[f][i]->decRef();
171  }
172  }
173  }
174 
177 
178  setContent(nullptr);
179 }
180 
181 void ScrollArea::init(std::string skinName)
182 {
184 
189 
190  if (instances == 0)
191  {
192  for (int f = 0; f < 9; f ++)
193  {
194  background.grid[f] = nullptr;
195  vMarker.grid[f] = nullptr;
196  vMarkerHi.grid[f] = nullptr;
197  vBackground.grid[f] = nullptr;
198  hBackground.grid[f] = nullptr;
199  }
200 
201  // +++ here probably need move background from static
202  if (skinName.empty())
203  skinName = "scroll_background.xml";
204  if (theme != nullptr)
205  {
206  theme->loadRect(background, skinName, "scroll_background.xml");
207  theme->loadRect(vMarker, "scroll.xml", "");
208  theme->loadRect(vMarkerHi, "scroll_highlighted.xml", "scroll.xml");
209  theme->loadRect(vBackground, "scroll_vbackground.xml", "");
210  theme->loadRect(hBackground, "scroll_hbackground.xml", "");
211  }
212 
213  for (int i = 0; i < 2; i ++)
214  {
215  Skin *skin = nullptr;
216  if (theme != nullptr)
217  skin = theme->load(buttonFiles[i], "scrollbuttons.xml");
218  if (skin != nullptr)
219  {
220  const ImageRect &rect = skin->getBorder();
221  for (int f = UP; f < BUTTONS_DIR; f ++)
222  {
223  if (rect.grid[f] != nullptr)
224  rect.grid[f]->incRef();
225  buttons[f][i] = rect.grid[f];
226  }
227  if (i == 0)
228  {
229  mShowButtons = (skin->getOption("showbuttons", 1) == 1);
230  mMarkerSize = skin->getOption("markersize", 0);
231  mScrollbarSize = skin->getOption("scrollbarsize", 12);
232  }
233  }
234  else
235  {
236  for (int f = UP; f < BUTTONS_DIR; f ++)
237  buttons[f][i] = nullptr;
238  }
239  if (theme != nullptr)
240  theme->unload(skin);
241  }
242  }
244  instances++;
245 }
246 
248 {
249  BLOCK_START("ScrollArea::logic")
250  if (!isVisible())
251  {
252  BLOCK_END("ScrollArea::logic")
253  return;
254  }
255 
256  checkPolicies();
257 
260 
261  Widget *const content = getContent();
262  if (content != nullptr)
263  {
264  unsigned int frameSize = content->getFrameSize();
265  content->setPosition(-mHScroll + frameSize, -mVScroll + frameSize);
266  content->logic();
267 
268  // When no scrollbar in a certain direction,
269  // adapt content size to match the content dimension exactly.
270  frameSize = 2 * content->getFrameSize();
272  {
274  - mScrollbarWidth) : mDimension.width) - frameSize);
275  }
277  {
279  - mScrollbarWidth) : mDimension.height) - frameSize);
280  }
281  }
282 
283  if (mUpButtonPressed)
285  else if (mDownButtonPressed)
287  else if (mLeftButtonPressed)
289  else if (mRightButtonPressed)
291  BLOCK_END("ScrollArea::logic")
292 }
293 
295 {
296  const float alpha = std::max(settings.guiAlpha,
298 
299  if (alpha != mAlpha)
300  {
301  mAlpha = alpha;
302  for (int a = 0; a < 9; a++)
303  {
304  if (background.grid[a] != nullptr)
306  if (hBackground.grid[a] != nullptr)
308  if (vBackground.grid[a] != nullptr)
310  if (vMarker.grid[a] != nullptr)
312  if (vMarkerHi.grid[a] != nullptr)
314  }
315  }
316 }
317 
318 void ScrollArea::draw(Graphics *const graphics)
319 {
320  BLOCK_START("ScrollArea::draw")
321  if (mVBarVisible || mHBarVisible)
322  {
323  if (mOpaque == Opaque_false)
324  updateCalcFlag(graphics);
325  // need add caching or remove calc calls.
326 // if (mRedraw)
327  {
328  mVertexes->clear();
329  if (mVBarVisible)
330  {
331  if (mShowButtons)
332  {
333  calcButton(graphics, UP);
334  calcButton(graphics, DOWN);
335  }
336  calcVBar(graphics);
337  calcVMarker(graphics);
338  }
339 
340  if (mHBarVisible)
341  {
342  if (mShowButtons)
343  {
344  calcButton(graphics, LEFT);
345  calcButton(graphics, RIGHT);
346  }
347  calcHBar(graphics);
348  calcHMarker(graphics);
349  }
350  graphics->finalize(mVertexes);
351  }
352  graphics->drawTileCollection(mVertexes);
353  }
354 
355  updateAlpha();
356 
357  if (mRedraw)
358  {
359  const bool redraw = graphics->getRedraw();
360  graphics->setRedraw(true);
361  drawChildren(graphics);
362  graphics->setRedraw(redraw);
363  }
364  else
365  {
366  drawChildren(graphics);
367  }
368  mRedraw = false;
369  BLOCK_END("ScrollArea::draw")
370 }
371 
372 void ScrollArea::safeDraw(Graphics *const graphics)
373 {
374  BLOCK_START("ScrollArea::draw")
375  if (mVBarVisible)
376  {
377  if (mShowButtons)
378  {
379  drawButton(graphics, UP);
380  drawButton(graphics, DOWN);
381  }
382  drawVBar(graphics);
383  drawVMarker(graphics);
384  }
385 
386  if (mHBarVisible)
387  {
388  if (mShowButtons)
389  {
390  drawButton(graphics, LEFT);
391  drawButton(graphics, RIGHT);
392  }
393  drawHBar(graphics);
394  drawHMarker(graphics);
395  }
396 
397  updateAlpha();
398 
399  safeDrawChildren(graphics);
400  mRedraw = false;
401  BLOCK_END("ScrollArea::draw")
402 }
403 
404 void ScrollArea::updateCalcFlag(const Graphics *const graphics)
405 {
406  if (!mRedraw)
407  {
408  // because we don't know where parent windows was moved,
409  // need recalc vertexes
410  const ClipRect &rect = graphics->getTopClip();
411  if (rect.xOffset != mXOffset || rect.yOffset != mYOffset)
412  {
413  mRedraw = true;
414  mXOffset = rect.xOffset;
415  mYOffset = rect.yOffset;
416  }
417  else if (rect.width != mDrawWidth || rect.height != mDrawHeight)
418  {
419  mRedraw = true;
420  mDrawWidth = rect.width;
421  mDrawHeight = rect.height;
422  }
423  else if (graphics->getRedraw())
424  {
425  mRedraw = true;
426  }
427  }
428 }
429 
430 void ScrollArea::drawFrame(Graphics *const graphics)
431 {
432  BLOCK_START("ScrollArea::drawFrame")
433  if (mOpaque == Opaque_true)
434  {
435  const int bs = mFrameSize * 2;
436  const int w = mDimension.width + bs;
437  const int h = mDimension.height + bs;
438 
439  updateCalcFlag(graphics);
440 
441  if (mRedraw)
442  {
443  mVertexes2->clear();
444  graphics->calcWindow(mVertexes2,
445  0, 0,
446  w, h,
447  background);
448  graphics->finalize(mVertexes2);
449  }
450  graphics->drawTileCollection(mVertexes2);
451  }
452  BLOCK_END("ScrollArea::drawFrame")
453 }
454 
455 void ScrollArea::safeDrawFrame(Graphics *const graphics)
456 {
457  BLOCK_START("ScrollArea::drawFrame")
458  if (mOpaque == Opaque_true)
459  {
460  const int bs = mFrameSize * 2;
461  const int w = mDimension.width + bs;
462  const int h = mDimension.height + bs;
463 
464  updateCalcFlag(graphics);
465  graphics->drawImageRect(0, 0,
466  w, h,
467  background);
468  }
469  BLOCK_END("ScrollArea::drawFrame")
470 }
471 
473 {
474  mOpaque = opaque;
475  setFrameSize(mOpaque == Opaque_true ? 2 : 0);
476 }
477 
479 {
480  int state = 0;
481 
482  switch (dir)
483  {
484  case UP:
485  state = mUpButtonPressed ? 1 : 0;
486  dim = getUpButtonDimension();
487  break;
488  case DOWN:
489  state = mDownButtonPressed ? 1 : 0;
490  dim = getDownButtonDimension();
491  break;
492  case LEFT:
493  state = mLeftButtonPressed ? 1 : 0;
494  dim = getLeftButtonDimension();
495  break;
496  case RIGHT:
497  state = mRightButtonPressed ? 1 : 0;
498  dim = getRightButtonDimension();
499  break;
500  case BUTTONS_DIR:
501  default:
502  logger->log("ScrollArea::drawButton unknown dir: "
503  + toString(CAST_U32(dir)));
504  return nullptr;
505  }
506  return buttons[CAST_SIZE(dir)][state];
507 }
508 
509 void ScrollArea::drawButton(Graphics *const graphics,
510  const BUTTON_DIR dir)
511 {
512  Rect dim;
513  const Image *const image = getImageByState(dim, dir);
514 
515  if (image != nullptr)
516  graphics->drawImage(image, dim.x, dim.y);
517 }
518 
519 void ScrollArea::calcButton(Graphics *const graphics,
520  const BUTTON_DIR dir)
521 {
522  Rect dim;
523  const Image *const image = getImageByState(dim, dir);
524 
525  if (image != nullptr)
526  {
527  static_cast<Graphics*>(graphics)->calcTileCollection(
528  mVertexes, image, dim.x, dim.y);
529  }
530 }
531 
532 void ScrollArea::drawVBar(Graphics *const graphics) const
533 {
534  const Rect &dim = getVerticalBarDimension();
535 
536  if (vBackground.grid[4] != nullptr)
537  {
538  graphics->drawPattern(vBackground.grid[4],
539  dim.x, dim.y, dim.width, dim.height);
540  }
541  if (vBackground.grid[1] != nullptr)
542  {
543  graphics->drawPattern(vBackground.grid[1],
544  dim.x, dim.y,
545  dim.width, vBackground.grid[1]->getHeight());
546  }
547  if (vBackground.grid[7] != nullptr)
548  {
549  graphics->drawPattern(vBackground.grid[7],
550  dim.x, dim.height - vBackground.grid[7]->getHeight() + dim.y,
551  dim.width, vBackground.grid[7]->getHeight());
552  }
553 }
554 
555 void ScrollArea::calcVBar(const Graphics *const graphics)
556 {
557  const Rect &dim = getVerticalBarDimension();
558 
559  if (vBackground.grid[4] != nullptr)
560  {
561  graphics->calcPattern(mVertexes,
562  vBackground.grid[4],
563  dim.x, dim.y,
564  dim.width, dim.height);
565  }
566  if (vBackground.grid[1] != nullptr)
567  {
568  graphics->calcPattern(mVertexes,
569  vBackground.grid[1],
570  dim.x, dim.y,
571  dim.width, vBackground.grid[1]->getHeight());
572  }
573  if (vBackground.grid[7] != nullptr)
574  {
575  graphics->calcPattern(mVertexes,
576  vBackground.grid[7],
577  dim.x, dim.height - vBackground.grid[7]->getHeight() + dim.y,
578  dim.width, vBackground.grid[7]->getHeight());
579  }
580 }
581 
582 void ScrollArea::drawHBar(Graphics *const graphics) const
583 {
584  const Rect &dim = getHorizontalBarDimension();
585 
586  if (hBackground.grid[4] != nullptr)
587  {
588  graphics->drawPattern(hBackground.grid[4],
589  dim.x, dim.y,
590  dim.width, dim.height);
591  }
592 
593  if (hBackground.grid[3] != nullptr)
594  {
595  graphics->drawPattern(hBackground.grid[3],
596  dim.x, dim.y,
597  hBackground.grid[3]->getWidth(), dim.height);
598  }
599 
600  if (hBackground.grid[5] != nullptr)
601  {
602  graphics->drawPattern(hBackground.grid[5],
603  dim.x + dim.width - hBackground.grid[5]->getWidth(),
604  dim.y,
605  hBackground.grid[5]->getWidth(),
606  dim.height);
607  }
608 }
609 
610 void ScrollArea::calcHBar(const Graphics *const graphics)
611 {
612  const Rect &dim = getHorizontalBarDimension();
613 
614  if (hBackground.grid[4] != nullptr)
615  {
616  graphics->calcPattern(mVertexes,
617  hBackground.grid[4],
618  dim.x, dim.y,
619  dim.width, dim.height);
620  }
621 
622  if (hBackground.grid[3] != nullptr)
623  {
624  graphics->calcPattern(mVertexes,
625  hBackground.grid[3],
626  dim.x, dim.y,
627  hBackground.grid[3]->getWidth(), dim.height);
628  }
629 
630  if (hBackground.grid[5] != nullptr)
631  {
632  graphics->calcPattern(mVertexes,
633  hBackground.grid[5],
634  dim.x + dim.width - hBackground.grid[5]->getWidth(),
635  dim.y,
636  hBackground.grid[5]->getWidth(),
637  dim.height);
638  }
639 }
640 
641 void ScrollArea::drawVMarker(Graphics *const graphics)
642 {
643  const Rect &dim = getVerticalMarkerDimension();
644 
645  if ((mHasMouse) && (mX > (mDimension.width - mScrollbarWidth)))
646  {
647  graphics->drawImageRect(dim.x, dim.y,
648  dim.width, dim.height,
649  vMarkerHi);
650  }
651  else
652  {
653  graphics->drawImageRect(dim.x, dim.y,
654  dim.width, dim.height,
655  vMarker);
656  }
657 }
658 
659 void ScrollArea::calcVMarker(Graphics *const graphics)
660 {
661  const Rect &dim = getVerticalMarkerDimension();
662 
663  if ((mHasMouse) && (mX > (mDimension.width - mScrollbarWidth)))
664  {
665  graphics->calcWindow(mVertexes,
666  dim.x, dim.y,
667  dim.width, dim.height,
668  vMarkerHi);
669  }
670  else
671  {
672  graphics->calcWindow(mVertexes,
673  dim.x, dim.y,
674  dim.width, dim.height,
675  vMarker);
676  }
677 }
678 
679 void ScrollArea::drawHMarker(Graphics *const graphics)
680 {
681  const Rect dim = getHorizontalMarkerDimension();
682 
683  if ((mHasMouse) && (mY > (mDimension.height - mScrollbarWidth)))
684  {
685  graphics->drawImageRect(dim.x, dim.y,
686  dim.width, dim.height,
687  vMarkerHi);
688  }
689  else
690  {
691  graphics->drawImageRect(
692  dim.x, dim.y,
693  dim.width, dim.height,
694  vMarker);
695  }
696 }
697 
698 void ScrollArea::calcHMarker(Graphics *const graphics)
699 {
700  const Rect dim = getHorizontalMarkerDimension();
701 
702  if ((mHasMouse) && (mY > (mDimension.height - mScrollbarWidth)))
703  {
704  graphics->calcWindow(mVertexes,
705  dim.x, dim.y,
706  dim.width, dim.height,
707  vMarkerHi);
708  }
709  else
710  {
711  graphics->calcWindow(mVertexes,
712  dim.x, dim.y,
713  dim.width, dim.height,
714  vMarker);
715  }
716 }
717 
719 {
720  mX = event.getX();
721  mY = event.getY();
722 }
723 
725 {
726  mHasMouse = true;
727 }
728 
730 {
731  mHasMouse = false;
732 }
733 
735 {
736  mRedraw = true;
737  const unsigned int frameSize = 2 * mFrameSize;
738  Widget *const content = getContent();
739  if (content != nullptr)
740  {
741  content->setSize(mDimension.width - frameSize,
742  mDimension.height - frameSize);
743  }
744 }
745 
747 {
748  mRedraw = true;
749 }
750 
752 {
753  const int x = event.getX();
754  const int y = event.getY();
755 
756  if (getUpButtonDimension().isPointInRect(x, y))
757  {
760  mUpButtonPressed = true;
761  event.consume();
762  }
763  else if (getDownButtonDimension().isPointInRect(x, y))
764  {
767  mDownButtonPressed = true;
768  event.consume();
769  }
770  else if (getLeftButtonDimension().isPointInRect(x, y))
771  {
774  mLeftButtonPressed = true;
775  event.consume();
776  }
777  else if (getRightButtonDimension().isPointInRect(x, y))
778  {
781  mRightButtonPressed = true;
782  event.consume();
783  }
784  else if (getVerticalMarkerDimension().isPointInRect(x, y))
785  {
788 
790  event.consume();
791  }
792  else if (getVerticalBarDimension().isPointInRect(x, y))
793  {
794  if (y < getVerticalMarkerDimension().y)
795  {
797  - CAST_S32(getChildrenArea().height * 0.1));
798  }
799  else
800  {
802  + CAST_S32(getChildrenArea().height * 0.1));
803  }
804  event.consume();
805  }
806  else if (getHorizontalMarkerDimension().isPointInRect(x, y))
807  {
809  mIsVerticalMarkerDragged = false;
811  event.consume();
812  }
813  else if (getHorizontalBarDimension().isPointInRect(x, y))
814  {
815  if (x < getHorizontalMarkerDimension().x)
816  {
818  - CAST_S32(getChildrenArea().width * 0.1));
819  }
820  else
821  {
823  + CAST_S32(getChildrenArea().width * 0.1));
824  }
825  event.consume();
826  }
827 
828  if (event.getButton() == MouseButton::LEFT &&
829  !event.isConsumed())
830  {
831  mClickX = event.getX();
832  mClickY = event.getY();
833  }
834 }
835 
837 {
838  if (event.getButton() == MouseButton::LEFT &&
839  mClickX != 0 &&
840  mClickY != 0)
841  {
842  if (!event.isConsumed())
843  {
844 #ifdef ANDROID
845  int dx = mClickX - event.getX();
846  int dy = mClickY - event.getY();
847 #else // ANDROID
848 
849  int dx = event.getX() - mClickX;
850  int dy = event.getY() - mClickY;
851 #endif // ANDROID
852 
853  if ((dx < 20 && dx > 0) || (dx > -20 && dx < 0))
854  dx = 0;
855 
856  if ((dy < 20 && dy > 0) || (dy > -20 && dy < 0))
857  dy = 0;
858 
859  if (abs(dx) > abs(dy))
860  {
861  int s = mHScroll + dx;
862  if (s < 0)
863  {
864  s = 0;
865  }
866  else
867  {
868  const int maxH = getHorizontalMaxScroll();
869  if (s > maxH)
870  s = maxH;
871  }
872 
874  }
875  else if (dy != 0)
876  {
877  int s = mVScroll + dy;
878  if (s < 0)
879  {
880  s = 0;
881  }
882  else
883  {
884  const int maxV = getVerticalMaxScroll();
885  if (s > maxV)
886  s = maxV;
887  }
888 
890  }
891  mClickX = 0;
892  mClickY = 0;
893  if (mMouseConsume && ((dx != 0) || (dy != 0)))
894  event.consume();
895  }
896  }
897  mUpButtonPressed = false;
898  mDownButtonPressed = false;
899  mLeftButtonPressed = false;
900  mRightButtonPressed = false;
902  mIsVerticalMarkerDragged = false;
903  if (mMouseConsume)
904  event.consume();
905  mRedraw = true;
906 }
907 
909 {
911  {
912  const Rect barDim = getVerticalBarDimension();
913 
914  const int pos = event.getY() - barDim.y
916  const int length = getVerticalMarkerDimension().height;
917 
918  if ((barDim.height - length) > 0)
919  {
921  / (barDim.height - length));
922  }
923  else
924  {
926  }
927  }
928 
930  {
931  const Rect barDim = getHorizontalBarDimension();
932 
933  const int pos = event.getX() - barDim.x
935  const int length = getHorizontalMarkerDimension().width;
936 
937  if ((barDim.width - length) > 0)
938  {
940  / (barDim.width - length));
941  }
942  else
943  {
945  }
946  }
947 
948  event.consume();
949  mRedraw = true;
950 }
951 
953 {
954  if (!mVBarVisible)
955  return Rect(0, 0, 0, 0);
956 
957  const int height = mShowButtons ? mScrollbarWidth : 0;
958  if (mHBarVisible)
959  {
961  height,
963  mDimension.height - 2 * height - mScrollbarWidth);
964  }
965 
967  height,
969  mDimension.height - 2 * height);
970 }
971 
973 {
974  if (!mHBarVisible)
975  return Rect(0, 0, 0, 0);
976 
977  const int width = mShowButtons ? mScrollbarWidth : 0;
978  if (mVBarVisible)
979  {
980  return Rect(width,
982  mDimension.width - 2 * width - mScrollbarWidth,
984  }
985 
986  return Rect(width,
988  mDimension.width - 2 * width,
990 }
991 
993 {
994  if (!mVBarVisible)
995  return Rect(0, 0, 0, 0);
996 
997  int length, pos;
998  int height;
999  const int h2 = mShowButtons
1000  ? mScrollbarWidth : mMarkerSize / 2;
1001  const Widget *content;
1002  if (!mWidgets.empty())
1003  content = *mWidgets.begin();
1004  else
1005  content = nullptr;
1006 
1007  if (mHBarVisible)
1008  height = mDimension.height - 2 * h2 - mScrollbarWidth;
1009  else
1010  height = mDimension.height - 2 * h2;
1011 
1012  const int maxV = getVerticalMaxScroll();
1013  if ((mMarkerSize != 0) && (maxV != 0))
1014  {
1015  pos = (mVScroll * height / maxV - mMarkerSize / 2);
1016  length = mMarkerSize;
1017  }
1018  else
1019  {
1020  if (content != nullptr)
1021  {
1022  const int h3 = content->getHeight();
1023  if (h3 != 0)
1024  length = (height * getChildrenArea().height) / h3;
1025  else
1026  length = height;
1027  }
1028  else
1029  {
1030  length = height;
1031  }
1032 
1033  if (length < mScrollbarWidth)
1034  length = mScrollbarWidth;
1035 
1036  if (length > height)
1037  length = height;
1038 
1039  const int maxScroll = getVerticalMaxScroll();
1040  if (maxScroll != 0)
1041  pos = ((height - length) * mVScroll) / maxScroll;
1042  else
1043  pos = 0;
1044  }
1045 
1046  return Rect(mDimension.width - mScrollbarWidth, h2 + pos,
1047  mScrollbarWidth, length);
1048 }
1049 
1051 {
1052  if (!mHBarVisible)
1053  return Rect(0, 0, 0, 0);
1054 
1055  int length, pos;
1056  int width;
1057  const int w2 = mShowButtons
1058  ? mScrollbarWidth : mMarkerSize / 2;
1059  const Widget *content;
1060  if (!mWidgets.empty())
1061  content = *mWidgets.begin();
1062  else
1063  content = nullptr;
1064 
1065  if (mVBarVisible)
1066  width = mDimension.width - 2 * w2 - mScrollbarWidth;
1067  else
1068  width = mDimension.width - w2 - mScrollbarWidth;
1069 
1070  const int maxH = getHorizontalMaxScroll();
1071  if ((mMarkerSize != 0) && (maxH != 0))
1072  {
1073  pos = (mHScroll * width / maxH - mMarkerSize / 2);
1074  length = mMarkerSize;
1075  }
1076  else
1077  {
1078  if (content != nullptr)
1079  {
1080  const int w3 = content->getWidth();
1081  if (w3 != 0)
1082  length = (width * getChildrenArea().width) / w3;
1083  else
1084  length = width;
1085  }
1086  else
1087  {
1088  length = width;
1089  }
1090 
1091  if (length < mScrollbarWidth)
1092  length = mScrollbarWidth;
1093 
1094  if (length > width)
1095  length = width;
1096 
1097  if (getHorizontalMaxScroll() != 0)
1098  {
1099  pos = ((width - length) * mHScroll)
1101  }
1102  else
1103  {
1104  pos = 0;
1105  }
1106  }
1107 
1108  return Rect(w2 + pos, mDimension.height - mScrollbarWidth,
1109  length, mScrollbarWidth);
1110 }
1111 
1113 {
1114  if (!mVBarVisible || !mShowButtons)
1115  return Rect(0, 0, 0, 0);
1116 
1117  return Rect(mDimension.width - mScrollbarWidth, 0,
1119 }
1120 
1122 {
1123  if (!mVBarVisible || !mShowButtons)
1124  return Rect(0, 0, 0, 0);
1125 
1126  if (mHBarVisible)
1127  {
1131  mScrollbarWidth);
1132  }
1133 
1137  mScrollbarWidth);
1138 }
1139 
1141 {
1142  if (!mHBarVisible || !mShowButtons)
1143  return Rect(0, 0, 0, 0);
1144 
1145  return Rect(0, mDimension.height - mScrollbarWidth,
1147 }
1148 
1150 {
1151  if (!mHBarVisible || !mShowButtons)
1152  return Rect(0, 0, 0, 0);
1153 
1154  if (mVBarVisible)
1155  {
1156  return Rect(mDimension.width - mScrollbarWidth*2,
1159  mScrollbarWidth);
1160  }
1161 
1165  mScrollbarWidth);
1166 }
1167 
1169 {
1170  if (widget != nullptr)
1171  {
1172  clear();
1173  add(widget);
1174  widget->setPosition(0, 0);
1175  }
1176  else
1177  {
1178  clear();
1179  }
1180 
1181  checkPolicies();
1182 }
1183 
1185 {
1186  if (!mWidgets.empty())
1187  return *mWidgets.begin();
1188 
1189  return nullptr;
1190 }
1191 
1193 {
1194  mHPolicy = hPolicy;
1195  checkPolicies();
1196 }
1197 
1199 {
1200  mVPolicy = vPolicy;
1201  checkPolicies();
1202 }
1203 
1205  const ScrollPolicy vPolicy)
1206 {
1207  mHPolicy = hPolicy;
1208  mVPolicy = vPolicy;
1209  checkPolicies();
1210 }
1211 
1213 {
1214  const int max = getVerticalMaxScroll();
1215 
1216  mVScroll = vScroll;
1217 
1218  if (vScroll > max)
1219  mVScroll = max;
1220 
1221  if (vScroll < 0)
1222  mVScroll = 0;
1223 }
1224 
1226 {
1227  const int max = getHorizontalMaxScroll();
1228 
1229  mHScroll = hScroll;
1230 
1231  if (hScroll > max)
1232  mHScroll = max;
1233  else if (hScroll < 0)
1234  mHScroll = 0;
1235 }
1236 
1237 void ScrollArea::setScrollAmount(const int hScroll, const int vScroll)
1238 {
1239  setHorizontalScrollAmount(hScroll);
1240  setVerticalScrollAmount(vScroll);
1241 }
1242 
1244 {
1245  checkPolicies();
1246 
1247  const Widget *const content = getContent();
1248  if (content == nullptr)
1249  return 0;
1250 
1251  const int value = content->getWidth() - getChildrenArea().width +
1252  2 * content->getFrameSize();
1253 
1254  if (value < 0)
1255  return 0;
1256 
1257  return value;
1258 }
1259 
1261 {
1262  checkPolicies();
1263 
1264  const Widget *const content = getContent();
1265  if (content == nullptr)
1266  return 0;
1267 
1268  int value;
1269 
1270  value = content->getHeight() - getChildrenArea().height +
1271  2 * content->getFrameSize();
1272 
1273  if (value < 0)
1274  return 0;
1275 
1276  return value;
1277 }
1278 
1279 void ScrollArea::setScrollbarWidth(const int width)
1280 {
1281  if (width > 0)
1282  mScrollbarWidth = width;
1283 }
1284 
1285 void ScrollArea::showWidgetPart(Widget *const widget, const Rect &area)
1286 {
1287  const Widget *const content = getContent();
1288  if (widget != content || (content == nullptr))
1289  return;
1290 
1291  BasicContainer::showWidgetPart(widget, area);
1292 
1294  - content->getX());
1296  - content->getY());
1297 }
1298 
1300 {
1301  const Rect area = Rect(0, 0,
1304 
1305  if (area.width < 0 || area.height < 0)
1306  return Rect();
1307 
1308  return area;
1309 }
1310 
1312 {
1313  if (getChildrenArea().isPointInRect(x, y))
1314  return getContent();
1315 
1316  return nullptr;
1317 }
1318 
1319 void ScrollArea::setWidth(int width)
1320 {
1321  Widget::setWidth(width);
1322  checkPolicies();
1323 }
1324 
1325 void ScrollArea::setHeight(int height)
1326 {
1327  Widget::setHeight(height);
1328  checkPolicies();
1329 }
1330 
1331 void ScrollArea::setDimension(const Rect& dimension)
1332 {
1333  Widget::setDimension(dimension);
1334  checkPolicies();
1335 }
1336 
1338 {
1339  if (event.isConsumed())
1340  return;
1341 
1343  - getChildrenArea().height / 8);
1344 
1345  event.consume();
1346 }
1347 
1349 {
1350  if (event.isConsumed())
1351  return;
1352 
1354  + getChildrenArea().height / 8);
1355 
1356  event.consume();
1357 }
1358 
1360 {
1361  const int w = getWidth();
1362  const int h = getHeight();
1363 
1364  mHBarVisible = false;
1365  mVBarVisible = false;
1366 
1367  const Widget *const content = getContent();
1368  if (content == nullptr)
1369  {
1372  return;
1373  }
1374 
1375  if (mHPolicy == SHOW_AUTO &&
1376  mVPolicy == SHOW_AUTO)
1377  {
1378  if (content->getWidth() <= w
1379  && content->getHeight() <= h)
1380  {
1381  mHBarVisible = false;
1382  mVBarVisible = false;
1383  }
1384 
1385  if (content->getWidth() > w)
1386  {
1387  mHBarVisible = true;
1388  }
1389 
1390  if ((content->getHeight() > h)
1391  || (mHBarVisible && content->getHeight()
1392  > h - mScrollbarWidth))
1393  {
1394  mVBarVisible = true;
1395  }
1396 
1397  if (mVBarVisible && content->getWidth() > w - mScrollbarWidth)
1398  mHBarVisible = true;
1399 
1400  return;
1401  }
1402 
1403  switch (mHPolicy)
1404  {
1405  case SHOW_NEVER:
1406  mHBarVisible = false;
1407  break;
1408 
1409  case SHOW_ALWAYS:
1410  mHBarVisible = true;
1411  break;
1412 
1413  case SHOW_AUTO:
1414  if (mVPolicy == SHOW_NEVER)
1415  {
1416  mHBarVisible = (content->getWidth() > w);
1417  }
1418  else // (mVPolicy == SHOW_ALWAYS)
1419  {
1420  mHBarVisible = (content->getWidth()
1421  > w - mScrollbarWidth);
1422  }
1423  break;
1424 
1425  default:
1426  break;
1427  }
1428 
1429  switch (mVPolicy)
1430  {
1431  case SHOW_NEVER:
1432  mVBarVisible = false;
1433  break;
1434 
1435  case SHOW_ALWAYS:
1436  mVBarVisible = true;
1437  break;
1438 
1439  case SHOW_AUTO:
1440  if (mHPolicy == SHOW_NEVER)
1441  {
1442  mVBarVisible = (content->getHeight() > h);
1443  }
1444  else // (mHPolicy == SHOW_ALWAYS)
1445  {
1446  mVBarVisible = (content->getHeight()
1447  > h - mScrollbarWidth);
1448  }
1449  break;
1450  default:
1451  break;
1452  }
1453 }
1454 
1456 {
1457  if (mVBarVisible || mHBarVisible)
1458  return true;
1459  return Widget::isSelectable();
1460 }
void setSize(const int width, const int height)
Definition: widget.cpp:366
void drawVMarker(Graphics *const graphics)
Definition: scrollarea.cpp:641
Rect getDownButtonDimension() const
#define CAST_U32
Definition: cast.h:30
void showWidgetPart(Widget *const widget, const Rect &area)
void void calcTileCollection(ImageCollection *restrict const vertCol, const Image *restrict const image, int x, int y) restrict2 override final
ImageCollection * mVertexes2
Definition: scrollarea.h:483
void setLeftButtonScrollAmount(const int amount)
Definition: scrollarea.h:340
int width
Definition: rect.h:218
Rect getHorizontalMarkerDimension()
bool mRightButtonPressed
Definition: scrollarea.h:577
int getWidth() const
Definition: widget.h:220
int mHScroll
Definition: scrollarea.h:503
void calcVBar(const Graphics *const graphics)
Definition: scrollarea.cpp:555
int mScrollbarWidth
Definition: scrollarea.h:508
Definition: skin.h:35
virtual void drawTileCollection(const ImageCollection *const vertCol)=0
void setWidth(const int width)
Definition: widget.cpp:132
void unload(Skin *const skin)
Definition: theme.cpp:249
static void unloadRect(const ImageRect &rect, const int start=0, const int end=8)
Definition: theme.cpp:1118
ClipRect & getTopClip() const
Definition: graphics.h:280
Gui * gui
Definition: gui.cpp:110
int mXOffset
Definition: scrollarea.h:544
int mUpButtonScrollAmount
Definition: scrollarea.h:513
virtual void drawImageRect(const int x, const int y, const int w, const int h, const ImageRect &imgRect)=0
Rect getHorizontalBarDimension() const
Definition: scrollarea.cpp:972
Opaque mOpaque
Definition: scrollarea.h:593
int getY() const
Definition: widget.h:287
bool mIsHorizontalMarkerDragged
Definition: scrollarea.h:587
ScrollPolicy mVPolicy
Definition: scrollarea.h:493
void drawButton(Graphics *const graphics, const BUTTON_DIR dir)
Definition: scrollarea.cpp:509
ScrollArea(Widget2 *const widget2, Widget *const widget, const Opaque opaque=Opaque_true, const std::string &skin="")
Definition: scrollarea.cpp:104
void widgetMoved(const Event &event)
Definition: scrollarea.cpp:746
Rect getVerticalBarDimension() const
Definition: scrollarea.cpp:952
MouseButtonT getButton() const
Definition: mouseevent.h:113
void setScrollPolicy(const ScrollPolicy hPolicy, const ScrollPolicy vPolicy)
float getMinimumOpacity() const
Definition: theme.h:124
int mDrawHeight
Definition: scrollarea.h:547
Definition: rect.h:72
void mouseMoved(MouseEvent &event)
Definition: scrollarea.cpp:718
void showWidgetPart(Widget *const widget, const Rect &area)
Rect getVerticalMarkerDimension()
Definition: scrollarea.cpp:992
virtual bool isSelectable() const
Definition: widget.h:944
#define BLOCK_START(name)
Definition: perfomance.h:78
void setDimension(const Rect &dimension)
Definition: widget.cpp:168
void setDimension(const Rect &dimension)
void setWidth(int width)
static std::string const buttonFiles[2]
Definition: scrollarea.cpp:98
bool mLeftButtonPressed
Definition: scrollarea.h:572
#define BLOCK_END(name)
Definition: perfomance.h:79
int yOffset
Definition: cliprect.h:126
void calcButton(Graphics *const graphics, const BUTTON_DIR dir)
Definition: scrollarea.cpp:519
void setVerticalScrollAmount(const int vScroll)
#define delete2(var)
Definition: delete2.h:24
Widget * getWidgetAt(int x, int y)
void setHeight(int height)
void setScrollbarWidth(const int width)
static ImageRect vBackground
Definition: scrollarea.h:478
bool mIsVerticalMarkerDragged
Definition: scrollarea.h:582
void setVerticalScrollPolicy(const ScrollPolicy vPolicy)
Image * getImageByState(Rect &dim, const BUTTON_DIR dir)
Definition: scrollarea.cpp:478
bool mHasMouse
Definition: scrollarea.h:595
int getOption(const std::string &name) const
Definition: skin.h:105
virtual void clear()
void setOpaque(Opaque opaque)
Definition: scrollarea.cpp:472
unsigned int getFrameSize() const
Definition: widget.h:183
int getVerticalMaxScroll()
Logger * logger
Definition: logger.cpp:95
void drawVBar(Graphics *const graphics) const
Definition: scrollarea.cpp:532
void calcVMarker(Graphics *const graphics)
Definition: scrollarea.cpp:659
virtual void finalize(ImageCollection *const col)
Definition: graphics.h:464
#define new
Definition: debug_new.h:147
Settings settings
Definition: settings.cpp:31
virtual void setAlpha(const float alpha)
Definition: image.cpp:285
int x
Definition: rect.h:208
bool mVBarVisible
Definition: scrollarea.h:552
void setRightButtonScrollAmount(const int amount)
Definition: scrollarea.h:350
#define CAST_S32
Definition: cast.h:29
const ImageRect & getBorder() const
Definition: skin.h:67
Image * grid[9]
Definition: imagerect.h:41
void mouseDragged(MouseEvent &event)
Definition: scrollarea.cpp:908
void calcHBar(const Graphics *const graphics)
Definition: scrollarea.cpp:610
void mouseReleased(MouseEvent &event)
Definition: scrollarea.cpp:836
static ImageRect vMarkerHi
Definition: scrollarea.h:477
int xOffset
Definition: cliprect.h:121
void drawHMarker(Graphics *const graphics)
Definition: scrollarea.cpp:679
void safeDraw(Graphics *const graphics)
Definition: scrollarea.cpp:372
int y
Definition: rect.h:213
virtual void logic()
Definition: widget.h:192
unsigned int mFrameSize
Definition: widget.h:1137
static float mAlpha
Definition: scrollarea.h:471
void setFrameSize(const unsigned int frameSize)
Definition: widget.h:167
void calcHMarker(Graphics *const graphics)
Definition: scrollarea.cpp:698
void add(Widget *const widget)
static ImageRect vMarker
Definition: scrollarea.h:476
void drawHBar(Graphics *const graphics) const
Definition: scrollarea.cpp:582
void mouseWheelMovedUp(MouseEvent &event)
bool mMouseConsume
Definition: widget.h:1161
Rect getRightButtonDimension() const
void widgetResized(const Event &event)
Definition: scrollarea.cpp:734
static int mScrollbarSize
Definition: scrollarea.h:474
void safeDrawFrame(Graphics *const graphics)
Definition: scrollarea.cpp:455
void addMouseListener(MouseListener *const mouseListener)
Definition: widget.cpp:291
const bool Opaque_false
Definition: opaque.h:29
void loadRect(ImageRect &image, const std::string &name, const std::string &name2, const int start=0, const int end=8)
Definition: theme.cpp:1092
void setPosition(const int x, const int y)
Definition: widget.cpp:160
int height
Definition: rect.h:223
static Image * buttons[4][2]
Definition: scrollarea.h:480
static ImageRect hBackground
Definition: scrollarea.h:479
Rect getChildrenArea()
static int instances
Definition: scrollarea.h:470
bool getRedraw() const
Definition: graphics.h:286
void mouseWheelMovedDown(MouseEvent &event)
static ImageRect background
Definition: scrollarea.h:475
int mHorizontalMarkerDragOffset
Definition: scrollarea.h:533
int mRightButtonScrollAmount
Definition: scrollarea.h:528
bool isConsumed() const
void setContent(Widget *widget)
void drawFrame(Graphics *const graphics)
Definition: scrollarea.cpp:430
static int mMarkerSize
Definition: scrollarea.h:473
Rect getUpButtonDimension() const
void mouseEntered(MouseEvent &event)
Definition: scrollarea.cpp:724
void setHeight(const int height)
Definition: widget.cpp:139
void checkPolicies()
virtual void incRef()
Definition: resource.cpp:37
Skin * load(const std::string &filename, const std::string &filename2, const bool full=true, const std::string &defaultPath=getThemePath())
Definition: theme.cpp:178
void mousePressed(MouseEvent &event)
Definition: scrollarea.cpp:751
int getX() const
Definition: widget.h:268
virtual void calcPattern(ImageVertexes *const vert, const Image *const image, const int x, const int y, const int w, const int h) const =0
ImageCollection * mVertexes
Definition: scrollarea.h:482
std::string toString(T const &value)
converts any type to a string
Definition: catch.hpp:1774
Theme * theme
Definition: theme.cpp:61
#define A_UNUSED
Definition: localconsts.h:171
bool isVisible() const
Definition: widget.h:377
bool mDownButtonPressed
Definition: scrollarea.h:567
virtual void drawImage(const Image *const image, int dstX, int dstY)=0
void removeDragged(const Widget *const widget)
Definition: gui.cpp:1144
Definition: widget.h:97
virtual void drawChildren(Graphics *const graphics)
const bool Opaque_true
Definition: opaque.h:29
int mLeftButtonScrollAmount
Definition: scrollarea.h:523
int mVScroll
Definition: scrollarea.h:498
bool mUpButtonPressed
Definition: scrollarea.h:562
Definition: event.h:77
bool mRedraw
Definition: widget.h:1163
void setScrollAmount(const int hScroll, const int vScroll)
void draw(Graphics *const graphics)
Definition: scrollarea.cpp:318
Definition: image.h:61
int getHeight() const
Definition: widget.h:239
void setDownButtonScrollAmount(const int amount)
Definition: scrollarea.h:370
int getWidth() const A_INLINE
Definition: image.h:116
void setHorizontalScrollAmount(int hScroll)
static bool mShowButtons
Definition: scrollarea.h:472
WidgetList mWidgets
virtual void drawPattern(const Image *const image, const int x, const int y, const int w, const int h)=0
void mouseExited(MouseEvent &event)
Definition: scrollarea.cpp:729
void setRedraw(const bool n)
Definition: graphics.h:283
bool isSelectable() const
#define CAST_SIZE
Definition: cast.h:33
void log(const char *const log_text,...)
Definition: logger.cpp:243
void init(std::string skinName)
Definition: scrollarea.cpp:181
int mDownButtonScrollAmount
Definition: scrollarea.h:518
float guiAlpha
Definition: settings.h:129
Rect mDimension
Definition: widget.h:1100
ScrollPolicy mHPolicy
Definition: scrollarea.h:488
bool mHBarVisible
Definition: scrollarea.h:557
virtual void safeDrawChildren(Graphics *const graphics)
int mYOffset
Definition: scrollarea.h:545
void decRef()
Definition: image.cpp:521
int mDrawWidth
Definition: scrollarea.h:546
#define noexcept2
Definition: localconsts.h:49
int mVerticalMarkerDragOffset
Definition: scrollarea.h:538
Rect getLeftButtonDimension() const
virtual void calcWindow(ImageCollection *const vertCol, const int x, const int y, const int w, const int h, const ImageRect &imgRect)=0
void updateCalcFlag(const Graphics *const graphics)
Definition: scrollarea.cpp:404
void updateAlpha()
Definition: scrollarea.cpp:294
int getHeight() const A_INLINE
Definition: image.h:122
void logic()
Definition: scrollarea.cpp:247
void setHorizontalScrollPolicy(const ScrollPolicy hPolicy)
Widget * getContent()
void setUpButtonScrollAmount(const int amount)
Definition: scrollarea.h:360
int getHorizontalMaxScroll()