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, pos;
1023  int height;
1024  const int h2 = mShowButtons
1025  ? mScrollbarWidth : mMarkerSize / 2;
1026  const Widget *content;
1027  if (!mWidgets.empty())
1028  content = *mWidgets.begin();
1029  else
1030  content = nullptr;
1031 
1032  if (mHBarVisible)
1033  height = mDimension.height - 2 * h2 - mScrollbarWidth;
1034  else
1035  height = mDimension.height - 2 * h2;
1036 
1037  const int maxV = getVerticalMaxScroll();
1038  if ((mMarkerSize != 0) && (maxV != 0))
1039  {
1040  pos = (mVScroll * height / maxV - mMarkerSize / 2);
1041  length = mMarkerSize;
1042  }
1043  else
1044  {
1045  if (content != nullptr)
1046  {
1047  const int h3 = content->getHeight();
1048  if (h3 != 0)
1049  length = (height * getChildrenArea().height) / h3;
1050  else
1051  length = height;
1052  }
1053  else
1054  {
1055  length = height;
1056  }
1057 
1058  if (length < mScrollbarWidth)
1059  length = mScrollbarWidth;
1060 
1061  if (length > height)
1062  length = height;
1063 
1064  if (maxV != 0)
1065  pos = ((height - length) * mVScroll) / maxV;
1066  else
1067  pos = 0;
1068  }
1069 
1070  return Rect(mDimension.width - mScrollbarWidth, h2 + pos,
1071  mScrollbarWidth, length);
1072 }
1073 
1075 {
1076  if (!mHBarVisible)
1077  return Rect(0, 0, 0, 0);
1078 
1079  int length, 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 }
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:151
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:1160
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()