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-2018 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  {
161  Theme::unloadRect(vMarker, 0, 8);
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  {
207  skinName,
208  "scroll_background.xml",
209  0,
210  8);
212  "scroll.xml",
213  "",
214  0,
215  8);
217  "scroll_highlighted.xml",
218  "scroll.xml",
219  0,
220  8);
222  "scroll_vbackground.xml",
223  "",
224  0,
225  8);
227  "scroll_hbackground.xml",
228  "",
229  0,
230  8);
231  }
232 
233  for (int i = 0; i < 2; i ++)
234  {
235  Skin *skin = nullptr;
236  if (theme != nullptr)
237  {
238  skin = theme->load(buttonFiles[i],
239  "scrollbuttons.xml",
240  true,
242  }
243  if (skin != nullptr)
244  {
245  const ImageRect &rect = skin->getBorder();
246  for (int f = UP; f < BUTTONS_DIR; f ++)
247  {
248  if (rect.grid[f] != nullptr)
249  rect.grid[f]->incRef();
250  buttons[f][i] = rect.grid[f];
251  }
252  if (i == 0)
253  {
254  mShowButtons = (skin->getOption("showbuttons", 1) == 1);
255  mMarkerSize = skin->getOption("markersize", 0);
256  mScrollbarSize = skin->getOption("scrollbarsize", 12);
257  }
258  }
259  else
260  {
261  for (int f = UP; f < BUTTONS_DIR; f ++)
262  buttons[f][i] = nullptr;
263  }
264  if (theme != nullptr)
265  theme->unload(skin);
266  }
267  }
269  instances++;
270 }
271 
273 {
274  BLOCK_START("ScrollArea::logic")
275  if (!isVisible())
276  {
277  BLOCK_END("ScrollArea::logic")
278  return;
279  }
280 
281  checkPolicies();
282 
285 
286  Widget *const content = getContent();
287  if (content != nullptr)
288  {
289  unsigned int frameSize = content->getFrameSize();
290  content->setPosition(-mHScroll + frameSize, -mVScroll + frameSize);
291  content->logic();
292 
293  // When no scrollbar in a certain direction,
294  // adapt content size to match the content dimension exactly.
295  frameSize = 2 * content->getFrameSize();
297  {
299  - mScrollbarWidth) : mDimension.width) - frameSize);
300  }
302  {
304  - mScrollbarWidth) : mDimension.height) - frameSize);
305  }
306  }
307 
308  if (mUpButtonPressed)
310  else if (mDownButtonPressed)
312  else if (mLeftButtonPressed)
314  else if (mRightButtonPressed)
316  BLOCK_END("ScrollArea::logic")
317 }
318 
320 {
321  const float alpha = std::max(settings.guiAlpha,
323 
324  if (alpha != mAlpha)
325  {
326  mAlpha = alpha;
327  for (int a = 0; a < 9; a++)
328  {
329  if (background.grid[a] != nullptr)
331  if (hBackground.grid[a] != nullptr)
333  if (vBackground.grid[a] != nullptr)
335  if (vMarker.grid[a] != nullptr)
337  if (vMarkerHi.grid[a] != nullptr)
339  }
340  }
341 }
342 
343 void ScrollArea::draw(Graphics *const graphics)
344 {
345  BLOCK_START("ScrollArea::draw")
346  if (mVBarVisible || mHBarVisible)
347  {
348  if (mOpaque == Opaque_false)
349  updateCalcFlag(graphics);
350  // need add caching or remove calc calls.
351 // if (mRedraw)
352  {
353  mVertexes->clear();
354  if (mVBarVisible)
355  {
356  if (mShowButtons)
357  {
358  calcButton(graphics, UP);
359  calcButton(graphics, DOWN);
360  }
361  calcVBar(graphics);
362  calcVMarker(graphics);
363  }
364 
365  if (mHBarVisible)
366  {
367  if (mShowButtons)
368  {
369  calcButton(graphics, LEFT);
370  calcButton(graphics, RIGHT);
371  }
372  calcHBar(graphics);
373  calcHMarker(graphics);
374  }
375  graphics->finalize(mVertexes);
376  }
377  graphics->drawTileCollection(mVertexes);
378  }
379 
380  updateAlpha();
381 
382  if (mRedraw)
383  {
384  const bool redraw = graphics->getRedraw();
385  graphics->setRedraw(true);
386  drawChildren(graphics);
387  graphics->setRedraw(redraw);
388  }
389  else
390  {
391  drawChildren(graphics);
392  }
393  mRedraw = false;
394  BLOCK_END("ScrollArea::draw")
395 }
396 
397 void ScrollArea::safeDraw(Graphics *const graphics)
398 {
399  BLOCK_START("ScrollArea::draw")
400  if (mVBarVisible)
401  {
402  if (mShowButtons)
403  {
404  drawButton(graphics, UP);
405  drawButton(graphics, DOWN);
406  }
407  drawVBar(graphics);
408  drawVMarker(graphics);
409  }
410 
411  if (mHBarVisible)
412  {
413  if (mShowButtons)
414  {
415  drawButton(graphics, LEFT);
416  drawButton(graphics, RIGHT);
417  }
418  drawHBar(graphics);
419  drawHMarker(graphics);
420  }
421 
422  updateAlpha();
423 
424  safeDrawChildren(graphics);
425  mRedraw = false;
426  BLOCK_END("ScrollArea::draw")
427 }
428 
429 void ScrollArea::updateCalcFlag(const Graphics *const graphics)
430 {
431  if (!mRedraw)
432  {
433  // because we don't know where parent windows was moved,
434  // need recalc vertexes
435  const ClipRect &rect = graphics->getTopClip();
436  if (rect.xOffset != mXOffset || rect.yOffset != mYOffset)
437  {
438  mRedraw = true;
439  mXOffset = rect.xOffset;
440  mYOffset = rect.yOffset;
441  }
442  else if (rect.width != mDrawWidth || rect.height != mDrawHeight)
443  {
444  mRedraw = true;
445  mDrawWidth = rect.width;
446  mDrawHeight = rect.height;
447  }
448  else if (graphics->getRedraw())
449  {
450  mRedraw = true;
451  }
452  }
453 }
454 
455 void ScrollArea::drawFrame(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 
466  if (mRedraw)
467  {
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  const unsigned int frameSize = 2 * mFrameSize;
763  Widget *const content = getContent();
764  if (content != nullptr)
765  {
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  {
819  if (y < getVerticalMarkerDimension().y)
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  {
840  if (x < getHorizontalMarkerDimension().x)
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 
939  const int pos = event.getY() - barDim.y
941  const int length = getVerticalMarkerDimension().height;
942 
943  if ((barDim.height - length) > 0)
944  {
946  / (barDim.height - length));
947  }
948  else
949  {
951  }
952  }
953 
955  {
956  const Rect barDim = getHorizontalBarDimension();
957 
958  const int pos = event.getX() - barDim.x
960  const int length = getHorizontalMarkerDimension().width;
961 
962  if ((barDim.width - length) > 0)
963  {
965  / (barDim.width - length));
966  }
967  else
968  {
970  }
971  }
972 
973  event.consume();
974  mRedraw = true;
975 }
976 
978 {
979  if (!mVBarVisible)
980  return Rect(0, 0, 0, 0);
981 
982  const int height = mShowButtons ? mScrollbarWidth : 0;
983  if (mHBarVisible)
984  {
986  height,
988  mDimension.height - 2 * height - mScrollbarWidth);
989  }
990 
992  height,
994  mDimension.height - 2 * height);
995 }
996 
998 {
999  if (!mHBarVisible)
1000  return Rect(0, 0, 0, 0);
1001 
1002  const int width = mShowButtons ? mScrollbarWidth : 0;
1003  if (mVBarVisible)
1004  {
1005  return Rect(width,
1007  mDimension.width - 2 * width - mScrollbarWidth,
1008  mScrollbarWidth);
1009  }
1010 
1011  return Rect(width,
1013  mDimension.width - 2 * width,
1014  mScrollbarWidth);
1015 }
1016 
1018 {
1019  if (!mVBarVisible)
1020  return Rect(0, 0, 0, 0);
1021 
1022  int length;
1023  int pos;
1024  int height;
1025  const int h2 = mShowButtons
1026  ? mScrollbarWidth : mMarkerSize / 2;
1027  const Widget *content;
1028  if (!mWidgets.empty())
1029  content = *mWidgets.begin();
1030  else
1031  content = nullptr;
1032 
1033  if (mHBarVisible)
1034  height = mDimension.height - 2 * h2 - mScrollbarWidth;
1035  else
1036  height = mDimension.height - 2 * h2;
1037 
1038  const int maxV = getVerticalMaxScroll();
1039  if ((mMarkerSize != 0) && (maxV != 0))
1040  {
1041  pos = (mVScroll * height / maxV - mMarkerSize / 2);
1042  length = mMarkerSize;
1043  }
1044  else
1045  {
1046  if (content != nullptr)
1047  {
1048  const int h3 = content->getHeight();
1049  if (h3 != 0)
1050  length = (height * getChildrenArea().height) / h3;
1051  else
1052  length = height;
1053  }
1054  else
1055  {
1056  length = height;
1057  }
1058 
1059  if (length < mScrollbarWidth)
1060  length = mScrollbarWidth;
1061 
1062  if (length > height)
1063  length = height;
1064 
1065  if (maxV != 0)
1066  pos = ((height - length) * mVScroll) / maxV;
1067  else
1068  pos = 0;
1069  }
1070 
1071  return Rect(mDimension.width - mScrollbarWidth, h2 + pos,
1072  mScrollbarWidth, length);
1073 }
1074 
1076 {
1077  if (!mHBarVisible)
1078  return Rect(0, 0, 0, 0);
1079 
1080  int length;
1081  int pos;
1082  int width;
1083  const int w2 = mShowButtons
1084  ? mScrollbarWidth : mMarkerSize / 2;
1085  const Widget *content;
1086  if (!mWidgets.empty())
1087  content = *mWidgets.begin();
1088  else
1089  content = nullptr;
1090 
1091  if (mVBarVisible)
1092  width = mDimension.width - 2 * w2 - mScrollbarWidth;
1093  else
1094  width = mDimension.width - w2 - mScrollbarWidth;
1095 
1096  const int maxH = getHorizontalMaxScroll();
1097  if (mMarkerSize != 0 && maxH != 0)
1098  {
1099  pos = (mHScroll * width / maxH - mMarkerSize / 2);
1100  length = mMarkerSize;
1101  }
1102  else
1103  {
1104  if (content != nullptr)
1105  {
1106  const int w3 = content->getWidth();
1107  if (w3 != 0)
1108  length = (width * getChildrenArea().width) / w3;
1109  else
1110  length = width;
1111  }
1112  else
1113  {
1114  length = width;
1115  }
1116 
1117  if (length < mScrollbarWidth)
1118  length = mScrollbarWidth;
1119 
1120  if (length > width)
1121  length = width;
1122 
1123  if (maxH != 0)
1124  {
1125  pos = ((width - length) * mHScroll) / maxH;
1126  }
1127  else
1128  {
1129  pos = 0;
1130  }
1131  }
1132 
1133  return Rect(w2 + pos, mDimension.height - mScrollbarWidth,
1134  length, mScrollbarWidth);
1135 }
1136 
1138 {
1139  if (!mVBarVisible || !mShowButtons)
1140  return Rect(0, 0, 0, 0);
1141 
1142  return Rect(mDimension.width - mScrollbarWidth, 0,
1144 }
1145 
1147 {
1148  if (!mVBarVisible || !mShowButtons)
1149  return Rect(0, 0, 0, 0);
1150 
1151  if (mHBarVisible)
1152  {
1156  mScrollbarWidth);
1157  }
1158 
1162  mScrollbarWidth);
1163 }
1164 
1166 {
1167  if (!mHBarVisible || !mShowButtons)
1168  return Rect(0, 0, 0, 0);
1169 
1170  return Rect(0, mDimension.height - mScrollbarWidth,
1172 }
1173 
1175 {
1176  if (!mHBarVisible || !mShowButtons)
1177  return Rect(0, 0, 0, 0);
1178 
1179  if (mVBarVisible)
1180  {
1181  return Rect(mDimension.width - mScrollbarWidth*2,
1184  mScrollbarWidth);
1185  }
1186 
1190  mScrollbarWidth);
1191 }
1192 
1194 {
1195  if (widget != nullptr)
1196  {
1197  clear();
1198  add(widget);
1199  widget->setPosition(0, 0);
1200  }
1201  else
1202  {
1203  clear();
1204  }
1205 
1206  checkPolicies();
1207 }
1208 
1210 {
1211  if (!mWidgets.empty())
1212  return *mWidgets.begin();
1213 
1214  return nullptr;
1215 }
1216 
1218 {
1219  mHPolicy = hPolicy;
1220  checkPolicies();
1221 }
1222 
1224 {
1225  mVPolicy = vPolicy;
1226  checkPolicies();
1227 }
1228 
1230  const ScrollPolicy vPolicy)
1231 {
1232  mHPolicy = hPolicy;
1233  mVPolicy = vPolicy;
1234  checkPolicies();
1235 }
1236 
1238 {
1239  const int max = getVerticalMaxScroll();
1240 
1241  mVScroll = vScroll;
1242 
1243  if (vScroll > max)
1244  mVScroll = max;
1245 
1246  if (vScroll < 0)
1247  mVScroll = 0;
1248 }
1249 
1251 {
1252  const int max = getHorizontalMaxScroll();
1253 
1254  mHScroll = hScroll;
1255 
1256  if (hScroll > max)
1257  mHScroll = max;
1258  else if (hScroll < 0)
1259  mHScroll = 0;
1260 }
1261 
1262 void ScrollArea::setScrollAmount(const int hScroll, const int vScroll)
1263 {
1264  setHorizontalScrollAmount(hScroll);
1265  setVerticalScrollAmount(vScroll);
1266 }
1267 
1269 {
1270  checkPolicies();
1271 
1272  const Widget *const content = getContent();
1273  if (content == nullptr)
1274  return 0;
1275 
1276  const int value = content->getWidth() - getChildrenArea().width +
1277  2 * content->getFrameSize();
1278 
1279  if (value < 0)
1280  return 0;
1281 
1282  return value;
1283 }
1284 
1286 {
1287  checkPolicies();
1288 
1289  const Widget *const content = getContent();
1290  if (content == nullptr)
1291  return 0;
1292 
1293  int value;
1294 
1295  value = content->getHeight() - getChildrenArea().height +
1296  2 * content->getFrameSize();
1297 
1298  if (value < 0)
1299  return 0;
1300 
1301  return value;
1302 }
1303 
1304 void ScrollArea::setScrollbarWidth(const int width)
1305 {
1306  if (width > 0)
1307  mScrollbarWidth = width;
1308 }
1309 
1310 void ScrollArea::showWidgetPart(Widget *const widget, const Rect &area)
1311 {
1312  const Widget *const content = getContent();
1313  if (widget != content || (content == nullptr))
1314  return;
1315 
1316  BasicContainer::showWidgetPart(widget, area);
1317 
1319  - content->getX());
1321  - content->getY());
1322 }
1323 
1325 {
1326  const Rect area = Rect(0, 0,
1329 
1330  if (area.width < 0 || area.height < 0)
1331  return Rect();
1332 
1333  return area;
1334 }
1335 
1337 {
1338  if (getChildrenArea().isPointInRect(x, y))
1339  return getContent();
1340 
1341  return nullptr;
1342 }
1343 
1344 void ScrollArea::setWidth(int width)
1345 {
1346  Widget::setWidth(width);
1347  checkPolicies();
1348 }
1349 
1350 void ScrollArea::setHeight(int height)
1351 {
1352  Widget::setHeight(height);
1353  checkPolicies();
1354 }
1355 
1356 void ScrollArea::setDimension(const Rect& dimension)
1357 {
1358  Widget::setDimension(dimension);
1359  checkPolicies();
1360 }
1361 
1363 {
1364  if (event.isConsumed())
1365  return;
1366 
1368  - getChildrenArea().height / 8);
1369 
1370  event.consume();
1371 }
1372 
1374 {
1375  if (event.isConsumed())
1376  return;
1377 
1379  + getChildrenArea().height / 8);
1380 
1381  event.consume();
1382 }
1383 
1385 {
1386  const int w = getWidth();
1387  const int h = getHeight();
1388 
1389  mHBarVisible = false;
1390  mVBarVisible = false;
1391 
1392  const Widget *const content = getContent();
1393  if (content == nullptr)
1394  {
1397  return;
1398  }
1399 
1400  if (mHPolicy == SHOW_AUTO &&
1401  mVPolicy == SHOW_AUTO)
1402  {
1403  if (content->getWidth() <= w
1404  && content->getHeight() <= h)
1405  {
1406  mHBarVisible = false;
1407  mVBarVisible = false;
1408  }
1409 
1410  if (content->getWidth() > w)
1411  {
1412  mHBarVisible = true;
1413  }
1414 
1415  if ((content->getHeight() > h)
1416  || (mHBarVisible && content->getHeight()
1417  > h - mScrollbarWidth))
1418  {
1419  mVBarVisible = true;
1420  }
1421 
1422  if (mVBarVisible && content->getWidth() > w - mScrollbarWidth)
1423  mHBarVisible = true;
1424 
1425  return;
1426  }
1427 
1428  switch (mHPolicy)
1429  {
1430  case SHOW_NEVER:
1431  mHBarVisible = false;
1432  break;
1433 
1434  case SHOW_ALWAYS:
1435  mHBarVisible = true;
1436  break;
1437 
1438  case SHOW_AUTO:
1439  if (mVPolicy == SHOW_NEVER)
1440  {
1441  mHBarVisible = (content->getWidth() > w);
1442  }
1443  else // (mVPolicy == SHOW_ALWAYS)
1444  {
1445  mHBarVisible = (content->getWidth()
1446  > w - mScrollbarWidth);
1447  }
1448  break;
1449 
1450  default:
1451  break;
1452  }
1453 
1454  switch (mVPolicy)
1455  {
1456  case SHOW_NEVER:
1457  mVBarVisible = false;
1458  break;
1459 
1460  case SHOW_ALWAYS:
1461  mVBarVisible = true;
1462  break;
1463 
1464  case SHOW_AUTO:
1465  if (mHPolicy == SHOW_NEVER)
1466  {
1467  mVBarVisible = (content->getHeight() > h);
1468  }
1469  else // (mHPolicy == SHOW_ALWAYS)
1470  {
1471  mVBarVisible = (content->getHeight()
1472  > h - mScrollbarWidth);
1473  }
1474  break;
1475  default:
1476  break;
1477  }
1478 }
1479 
1481 {
1482  if (mVBarVisible || mHBarVisible)
1483  return true;
1484  return Widget::isSelectable();
1485 }
void setSize(const int width, const int height)
Definition: widget.cpp:366
void drawVMarker(Graphics *const graphics)
Definition: scrollarea.cpp:666
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
void loadRect(ImageRect &image, const std::string &name, const std::string &name2, const int start, const int end)
Definition: theme.cpp:882
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:580
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
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:997
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:534
void widgetMoved(const Event &event)
Definition: scrollarea.cpp:771
Rect getVerticalBarDimension() const
Definition: scrollarea.cpp:977
MouseButtonT getButton() const
Definition: mouseevent.h:115
void setScrollPolicy(const ScrollPolicy hPolicy, const ScrollPolicy vPolicy)
float getMinimumOpacity() const
Definition: theme.h:123
int mDrawHeight
Definition: scrollarea.h:547
Definition: rect.h:72
void mouseMoved(MouseEvent &event)
Definition: scrollarea.cpp:743
void showWidgetPart(Widget *const widget, const Rect &area)
Rect getVerticalMarkerDimension()
virtual bool isSelectable() const
Definition: widget.h:944
#define BLOCK_START(name)
Definition: perfomance.h:78
static std::string getThemePath()
Definition: theme.h:66
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
Skin * load(const std::string &filename, const std::string &filename2, const bool full, const std::string &defaultPath)
Definition: theme.cpp:178
#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:544
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:503
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:497
unsigned int getFrameSize() const
Definition: widget.h:183
int getVerticalMaxScroll()
Logger * logger
Definition: logger.cpp:88
void drawVBar(Graphics *const graphics) const
Definition: scrollarea.cpp:557
void calcVMarker(Graphics *const graphics)
Definition: scrollarea.cpp:684
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:286
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:933
void calcHBar(const Graphics *const graphics)
Definition: scrollarea.cpp:635
void mouseReleased(MouseEvent &event)
Definition: scrollarea.cpp:861
ScrollArea(Widget2 *const widget2, Widget *const widget, const Opaque opaque, const std::string &skin)
Definition: scrollarea.cpp:104
static ImageRect vMarkerHi
Definition: scrollarea.h:477
int xOffset
Definition: cliprect.h:121
void drawHMarker(Graphics *const graphics)
Definition: scrollarea.cpp:704
void safeDraw(Graphics *const graphics)
Definition: scrollarea.cpp:397
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:723
void add(Widget *const widget)
static ImageRect vMarker
Definition: scrollarea.h:476
void drawHBar(Graphics *const graphics) const
Definition: scrollarea.cpp:607
void mouseWheelMovedUp(MouseEvent &event)
bool mMouseConsume
Definition: widget.h:1161
Rect getRightButtonDimension() const
void widgetResized(const Event &event)
Definition: scrollarea.cpp:759
static int mScrollbarSize
Definition: scrollarea.h:474
void safeDrawFrame(Graphics *const graphics)
Definition: scrollarea.cpp:480
void addMouseListener(MouseListener *const mouseListener)
Definition: widget.cpp:291
const bool Opaque_false
Definition: opaque.h:29
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:455
static int mMarkerSize
Definition: scrollarea.h:473
Rect getUpButtonDimension() const
void mouseEntered(MouseEvent &event)
Definition: scrollarea.cpp:749
void setHeight(const int height)
Definition: widget.cpp:139
void checkPolicies()
virtual void incRef()
Definition: resource.cpp:37
void mousePressed(MouseEvent &event)
Definition: scrollarea.cpp:776
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:159
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:1161
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:343
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:754
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:264
void init(std::string skinName)
Definition: scrollarea.cpp:181
int mDownButtonScrollAmount
Definition: scrollarea.h:518
static void unloadRect(const ImageRect &rect, const int start, const int end)
Definition: theme.cpp:914
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:522
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:429
void updateAlpha()
Definition: scrollarea.cpp:319
int getHeight() const A_INLINE
Definition: image.h:122
void logic()
Definition: scrollarea.cpp:272
void setHorizontalScrollPolicy(const ScrollPolicy hPolicy)
Widget * getContent()
void setUpButtonScrollAmount(const int amount)
Definition: scrollarea.h:360
int getHorizontalMaxScroll()