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