1 // This file is part of VSTGUI. It is subject to the license terms
2 // in the LICENSE file found in the top-level directory of this
3 // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
4
5 #include "cscrollview.h"
6 #include "cvstguitimer.h"
7 #include "cdrawcontext.h"
8 #include "cframe.h"
9 #include "dragging.h"
10 #include "controls/cscrollbar.h"
11 #include <cmath>
12
13 /// @cond ignore
14 namespace VSTGUI {
15
16 // CScrollContainer is private
17 //-----------------------------------------------------------------------------
18 class CScrollContainer : public CViewContainer
19 //-----------------------------------------------------------------------------
20 {
21 public:
22 CScrollContainer (const CRect &size, const CRect &containerSize);
23 CScrollContainer (const CScrollContainer& v);
24 ~CScrollContainer () override = default;
25
26 void setScrollOffset (CPoint offset, bool withRedraw = false);
getScrollOffset(CPoint & off) const27 void getScrollOffset (CPoint& off) const { off = offset; }
getScrollOffset() const28 const CPoint& getScrollOffset () const { return offset; }
29
getContainerSize() const30 CRect getContainerSize () const { return containerSize; }
31 void setContainerSize (const CRect& cs);
32
33 bool isDirty () const override;
34
setAutoDragScroll(bool state)35 void setAutoDragScroll (bool state) { autoDragScroll = state; }
36
37 bool attached (CView* parent) override;
38 CMessageResult notify (CBaseObject* sender, IdStringPtr message) override;
39
40 SharedPointer<IDropTarget> getDropTarget () override;
41 void onDragMove (CPoint where);
42
43 CLASS_METHODS(CScrollContainer, CViewContainer)
44 //-----------------------------------------------------------------------------
45 protected:
46 struct DropTarget : public IDropTarget, public NonAtomicReferenceCounted
47 {
DropTargetVSTGUI::CScrollContainer::DropTarget48 DropTarget (CScrollContainer* scrollContainer, SharedPointer<IDropTarget>&& parent)
49 : scrollContainer (scrollContainer), parent (std::move (parent))
50 {
51 }
52
onDragEnterVSTGUI::CScrollContainer::DropTarget53 DragOperation onDragEnter (DragEventData data) override
54 {
55 return parent->onDragEnter (data);
56 }
onDragMoveVSTGUI::CScrollContainer::DropTarget57 DragOperation onDragMove (DragEventData data) override
58 {
59 scrollContainer->onDragMove (data.pos);
60 return parent->onDragMove (data);
61 }
onDragLeaveVSTGUI::CScrollContainer::DropTarget62 void onDragLeave (DragEventData data) override
63 {
64 return parent->onDragLeave (data);
65 }
onDropVSTGUI::CScrollContainer::DropTarget66 bool onDrop (DragEventData data) override
67 {
68 return parent->onDrop (data);
69 }
70
71 CScrollContainer* scrollContainer;
72 SharedPointer<IDropTarget> parent;
73 };
74
75 bool getScrollValue (const CPoint& where, float& x, float& y);
76
77 CRect containerSize;
78 CPoint offset;
79 bool autoDragScroll;
80 bool inScrolling;
81 };
82
83 //-----------------------------------------------------------------------------
84 //-----------------------------------------------------------------------------
85 //-----------------------------------------------------------------------------
CScrollContainer(const CRect & size,const CRect & containerSize)86 CScrollContainer::CScrollContainer (const CRect &size, const CRect &containerSize)
87 : CViewContainer (size)
88 , containerSize (containerSize)
89 , offset (CPoint (0, 0))
90 , autoDragScroll (false)
91 , inScrolling (false)
92 {
93 setTransparency (true);
94 }
95
96 //-----------------------------------------------------------------------------
CScrollContainer(const CScrollContainer & v)97 CScrollContainer::CScrollContainer (const CScrollContainer& v)
98 : CViewContainer (v)
99 , containerSize (v.containerSize)
100 , offset (v.offset)
101 , autoDragScroll (v.autoDragScroll)
102 , inScrolling (false)
103 {
104 }
105
106 //-----------------------------------------------------------------------------
setContainerSize(const CRect & cs)107 void CScrollContainer::setContainerSize (const CRect& cs)
108 {
109 containerSize = cs;
110 setScrollOffset (offset, false);
111 }
112
113 //-----------------------------------------------------------------------------
setScrollOffset(CPoint newOffset,bool redraw)114 void CScrollContainer::setScrollOffset (CPoint newOffset, bool redraw)
115 {
116 newOffset.x = floor (newOffset.x + 0.5);
117 newOffset.y = floor (newOffset.y + 0.5);
118 if (containerSize.getWidth () >= getViewSize ().getWidth ())
119 {
120 if (newOffset.x < containerSize.left - (containerSize.getWidth () - getViewSize ().getWidth ()))
121 newOffset.x = containerSize.left - (containerSize.getWidth () - getViewSize ().getWidth ());
122 }
123 else
124 {
125 if (newOffset.x < containerSize.left - containerSize.getWidth ())
126 newOffset.x = containerSize.left - containerSize.getWidth ();
127 }
128 if (newOffset.x > containerSize.right)
129 newOffset.x = containerSize.right;
130 if (newOffset.y < containerSize.top)
131 newOffset.y = containerSize.top;
132 if (newOffset.y > containerSize.bottom)
133 newOffset.y = containerSize.bottom;
134 CPoint diff ((int32_t)(newOffset.x - offset.x), (int32_t)(offset.y - newOffset.y));
135 if (diff.x == 0 && diff.y == 0)
136 return;
137 offset = newOffset;
138 inScrolling = true;
139 for (const auto& pV : getChildren ())
140 {
141 CRect r = pV->getViewSize ();
142 CRect mr = pV->getMouseableArea ();
143 r.offset (diff.x , diff.y);
144 pV->setViewSize (r, false);
145 mr.offset (diff.x , diff.y);
146 pV->setMouseableArea (mr);
147 }
148 inScrolling = false;
149 if (!isAttached ())
150 return;
151
152 if (getTransparency ())
153 {
154 invalid ();
155 }
156 else
157 {
158 CRect scrollRect (0, 0, getViewSize ().getWidth (), getViewSize ().getHeight ());
159 CPoint p;
160 localToFrame (p);
161 scrollRect.offset (p.x, p.y);
162 CRect visibleRect = getVisibleSize (CRect (0, 0, getViewSize ().getWidth (), getViewSize ().getHeight ()));
163 visibleRect.offset (p.x, p.y);
164 scrollRect.bound (visibleRect);
165
166 CPoint distance (diff.x, diff.y);
167 if (distance.x > 0)
168 scrollRect.right -= distance.x;
169 else if (distance.x < 0)
170 scrollRect.left -= distance.x;
171 if (distance.y > 0)
172 scrollRect.bottom -= distance.y;
173 else if (distance.y < 0)
174 scrollRect.top -= distance.y;
175 getFrame ()->scrollRect (scrollRect, distance);
176 }
177 }
178
179 //-----------------------------------------------------------------------------
isDirty() const180 bool CScrollContainer::isDirty () const
181 {
182 if (CView::isDirty ())
183 return true;
184
185 for (const auto& pV : getChildren ())
186 {
187 if (pV->isDirty () && pV->isVisible ())
188 {
189 CRect r = pV->getVisibleViewSize ();
190 if (r.getWidth () > 0 && r.getHeight () > 0)
191 return true;
192 else
193 pV->setDirty (false);
194 }
195 }
196 return false;
197 }
198
199 //-----------------------------------------------------------------------------
getScrollValue(const CPoint & where,float & x,float & y)200 bool CScrollContainer::getScrollValue (const CPoint& where, float& x, float& y)
201 {
202 const CCoord kWidth = 10;
203 x = 0.f;
204 y = 0.f;
205 if (where.x <= getViewSize ().left + kWidth)
206 {
207 x = (float)(where.x - (getViewSize ().left + kWidth));
208 }
209 else if (where.x >= getViewSize ().right - kWidth)
210 {
211 x = (float)(where.x - (getViewSize ().right - kWidth));
212 }
213 if (where.y <= getViewSize ().top + kWidth)
214 {
215 y = (float)(where.y - (getViewSize ().top + kWidth));
216 }
217 else if (where.y >= getViewSize ().bottom - kWidth)
218 {
219 y = (float)(where.y - (getViewSize ().bottom - kWidth));
220 }
221 return (x != 0.f || y != 0.f);
222 }
223
224 //-----------------------------------------------------------------------------
getDropTarget()225 SharedPointer<IDropTarget> CScrollContainer::getDropTarget ()
226 {
227 auto dropTarget = CViewContainer::getDropTarget ();
228 if (autoDragScroll)
229 {
230 return makeOwned<DropTarget> (this, std::move (dropTarget));
231 }
232 return dropTarget;
233 }
234
235 //-----------------------------------------------------------------------------
onDragMove(CPoint where)236 void CScrollContainer::onDragMove (CPoint where)
237 {
238 float x, y;
239 if (getScrollValue (where, x, y))
240 {
241 if (auto* scrollView = static_cast<CScrollView*> (getParentView ()))
242 {
243 CRect r (getViewSize ());
244 r.originize ();
245 r.offset (x, y);
246 scrollView->makeRectVisible (r);
247 }
248 }
249 }
250
251 //-----------------------------------------------------------------------------
attached(CView * parent)252 bool CScrollContainer::attached (CView* parent)
253 {
254 bool result = CViewContainer::attached (parent);
255 if (getNbViews () == 1)
256 {
257 if (CView* view = getView (0))
258 {
259 const CRect& r (view->getViewSize ());
260 CRect newContainerSize (containerSize);
261 newContainerSize.setWidth (r.getWidth ());
262 newContainerSize.setHeight (r.getHeight ());
263 if (newContainerSize != containerSize)
264 {
265 auto* scrollView = static_cast<CScrollView*> (getParentView ());
266 if (scrollView)
267 scrollView->setContainerSize (newContainerSize);
268 }
269 }
270 }
271 return result;
272 }
273
274 //-----------------------------------------------------------------------------
notify(CBaseObject * sender,IdStringPtr message)275 CMessageResult CScrollContainer::notify (CBaseObject* sender, IdStringPtr message)
276 {
277 if (message == kMsgViewSizeChanged && !inScrolling)
278 {
279 uint32_t numSubViews = getNbViews ();
280 auto* view = static_cast<CView*> (sender);
281 if (numSubViews == 1 && view && isChild (view))
282 {
283 const CRect& r (view->getViewSize ());
284 CRect newContainerSize (containerSize);
285 newContainerSize.setWidth (r.getWidth ());
286 newContainerSize.setHeight (r.getHeight ());
287 if (newContainerSize != containerSize)
288 {
289 auto* scrollView = static_cast<CScrollView*> (getParentView ());
290 if (scrollView)
291 scrollView->setContainerSize (newContainerSize);
292 }
293 }
294 }
295 return getParentView () ? getParentView ()->notify (sender, message) : kMessageUnknown;
296 }
297
298 /// @endcond
299
300 //-----------------------------------------------------------------------------
301 //-----------------------------------------------------------------------------
302 //-----------------------------------------------------------------------------
CScrollView(const CRect & size,const CRect & containerSize,int32_t style,CCoord scrollbarWidth,CBitmap * pBackground)303 CScrollView::CScrollView (const CRect &size, const CRect &containerSize, int32_t style, CCoord scrollbarWidth, CBitmap* pBackground)
304 : CViewContainer (size)
305 , sc (nullptr)
306 , vsb (nullptr)
307 , hsb (nullptr)
308 , containerSize (containerSize)
309 , scrollbarWidth (scrollbarWidth)
310 , style (style)
311 , activeScrollbarStyle (0)
312 {
313 if (pBackground)
314 setBackground(pBackground);
315 recalculateSubViews ();
316 }
317
318 //-----------------------------------------------------------------------------
CScrollView(const CScrollView & v)319 CScrollView::CScrollView (const CScrollView& v)
320 : CViewContainer (v)
321 , containerSize (v.containerSize)
322 , scrollbarWidth (v.scrollbarWidth)
323 , style (v.style)
324 , activeScrollbarStyle (v.activeScrollbarStyle)
325 {
326 CViewContainer::removeAll ();
327 if (activeScrollbarStyle & kHorizontalScrollbar && v.hsb)
328 {
329 hsb = static_cast<CScrollbar*> (v.hsb->newCopy ());
330 hsb->setListener (this);
331 CViewContainer::addView (hsb, nullptr);
332 }
333 if (activeScrollbarStyle & kVerticalScrollbar && v.vsb)
334 {
335 vsb = static_cast<CScrollbar*> (v.vsb->newCopy ());
336 vsb->setListener (this);
337 CViewContainer::addView (vsb, nullptr);
338 }
339 sc = static_cast<CScrollContainer*> (v.sc->newCopy ());
340 CViewContainer::addView (sc, nullptr);
341 }
342
343 //-----------------------------------------------------------------------------
recalculateSubViews()344 void CScrollView::recalculateSubViews ()
345 {
346 if (recalculateSubViewsRecursionGard)
347 return;
348 recalculateSubViewsRecursionGard = true;
349 CRect scsize (containerSize.left, containerSize.top, getViewSize ().getWidth (), getViewSize ().getHeight ());
350 if (!(style & kDontDrawFrame))
351 {
352 scsize.left++; scsize.top++;
353 scsize.right-=1; scsize.bottom--;
354 }
355 if (style & kAutoHideScrollbars)
356 {
357 activeScrollbarStyle = 0;
358 CRect r (scsize);
359 if (style & kHorizontalScrollbar)
360 {
361 if (style & kVerticalScrollbar && r.getHeight () < containerSize.getHeight ())
362 {
363 activeScrollbarStyle |= kVerticalScrollbar;
364 if (!(style & kOverlayScrollbars))
365 r.right -= scrollbarWidth;
366 }
367 activeScrollbarStyle |= containerSize.getWidth () <= r.getWidth () ? 0 : kHorizontalScrollbar;
368 if (!(style & kOverlayScrollbars))
369 r.bottom -= scrollbarWidth;
370 if (activeScrollbarStyle == kHorizontalScrollbar && style & kVerticalScrollbar && r.getHeight () < containerSize.getHeight ())
371 {
372 activeScrollbarStyle |= kVerticalScrollbar;
373 }
374 }
375 else if (style & kVerticalScrollbar)
376 {
377 activeScrollbarStyle |= containerSize.getHeight () <= r.getHeight () ? 0 : kVerticalScrollbar;
378 }
379 }
380 else
381 {
382 activeScrollbarStyle = (style & kHorizontalScrollbar) | (style & kVerticalScrollbar);
383 }
384
385 if (activeScrollbarStyle & kHorizontalScrollbar)
386 {
387 CRect sbr (getViewSize ());
388 sbr.originize ();
389 sbr.top = sbr.bottom - scrollbarWidth;
390 if (activeScrollbarStyle & kVerticalScrollbar)
391 {
392 if (hsb && (vsb && vsb->isVisible () == false))
393 hsb->invalid ();
394 sbr.right -= (scrollbarWidth - 1);
395 }
396 if (hsb)
397 {
398 hsb->setViewSize (sbr, true);
399 hsb->setMouseableArea (sbr);
400 hsb->setVisible (true);
401 }
402 else
403 {
404 hsb = new CScrollbar (sbr, this, kHSBTag, CScrollbar::kHorizontal, containerSize);
405 hsb->setAutosizeFlags (kAutosizeLeft | kAutosizeRight | kAutosizeBottom);
406 CViewContainer::addView (hsb, nullptr);
407 hsb->registerViewListener (this);
408 }
409 if (!(style & kOverlayScrollbars))
410 scsize.bottom = sbr.top;
411 hsb->setOverlayStyle ((style & kOverlayScrollbars) ? true : false);
412 }
413 else if (hsb)
414 {
415 hsb->setVisible (false);
416 }
417 if (activeScrollbarStyle & kVerticalScrollbar)
418 {
419 CRect sbr (getViewSize ());
420 sbr.originize ();
421 sbr.left = sbr.right - scrollbarWidth;
422 if (activeScrollbarStyle & kHorizontalScrollbar)
423 {
424 if (vsb && (hsb && hsb->isVisible () == false))
425 vsb->invalid ();
426 sbr.bottom -= (scrollbarWidth - 1);
427 }
428 if (vsb)
429 {
430 vsb->setViewSize (sbr, true);
431 vsb->setMouseableArea (sbr);
432 vsb->setVisible (true);
433 }
434 else
435 {
436 vsb = new CScrollbar (sbr, this, kVSBTag, CScrollbar::kVertical, containerSize);
437 vsb->setAutosizeFlags (kAutosizeTop | kAutosizeRight | kAutosizeBottom);
438 CViewContainer::addView (vsb, nullptr);
439 vsb->registerViewListener (this);
440 }
441 if (!(style & kOverlayScrollbars))
442 scsize.right = sbr.left;
443 vsb->setOverlayStyle ((style & kOverlayScrollbars) ? true : false);
444 }
445 else if (vsb)
446 {
447 vsb->setVisible (false);
448 }
449
450 if (!sc)
451 {
452 sc = new CScrollContainer (scsize, containerSize);
453 sc->setAutosizeFlags (kAutosizeAll);
454 CViewContainer::addView (sc, CViewContainer::getView (0));
455 }
456 else
457 {
458 sc->setViewSize (scsize, true);
459 sc->setMouseableArea (scsize);
460 }
461 sc->setAutoDragScroll ((style & kAutoDragScrolling) ? true : false);
462 recalculateSubViewsRecursionGard = false;
463 }
464
465 //-----------------------------------------------------------------------------
setViewSize(const CRect & rect,bool invalid)466 void CScrollView::setViewSize (const CRect &rect, bool invalid)
467 {
468 bool autoHideScrollbars = (style & kAutoHideScrollbars) != 0;
469 style &= ~ kAutoHideScrollbars;
470 CViewContainer::setViewSize (rect, invalid);
471 if (autoHideScrollbars)
472 style |= kAutoHideScrollbars;
473 setContainerSize (containerSize, true);
474 }
475
476 //-----------------------------------------------------------------------------
setAutosizeFlags(int32_t flags)477 void CScrollView::setAutosizeFlags (int32_t flags)
478 {
479 CViewContainer::setAutosizeFlags (flags);
480 if (sc)
481 sc->setAutosizeFlags (flags);
482 }
483
484 //-----------------------------------------------------------------------------
setStyle(int32_t newStyle)485 void CScrollView::setStyle (int32_t newStyle)
486 {
487 if (style != newStyle)
488 {
489 if ((style & kDontDrawFrame) != (newStyle & kDontDrawFrame))
490 setBackgroundColorDrawStyle ((style & kDontDrawFrame) ? kDrawFilled : kDrawFilledAndStroked);
491 style = newStyle;
492 recalculateSubViews ();
493 }
494 }
495
496 //-----------------------------------------------------------------------------
setScrollbarWidth(CCoord width)497 void CScrollView::setScrollbarWidth (CCoord width)
498 {
499 if (scrollbarWidth != width)
500 {
501 scrollbarWidth = width;
502 recalculateSubViews ();
503 }
504 }
505
506 //-----------------------------------------------------------------------------
setContainerSize(const CRect & cs,bool keepVisibleArea)507 void CScrollView::setContainerSize (const CRect& cs, bool keepVisibleArea)
508 {
509 CRect oldSize (containerSize);
510 containerSize = cs;
511 if (sc)
512 {
513 sc->setContainerSize (cs);
514 }
515 if (style & kAutoHideScrollbars)
516 recalculateSubViews ();
517 if (vsb)
518 {
519 CRect oldScrollSize = vsb->getScrollSize (oldScrollSize);
520 float oldValue = vsb->getValue ();
521 vsb->setScrollSize (cs);
522 if (cs.getHeight () <= getViewSize ().getHeight ())
523 vsb->setValue (0);
524 else if (sc && keepVisibleArea && oldScrollSize.getHeight () != cs.getHeight ())
525 {
526 CRect vSize = sc->getViewSize ();
527 float newValue = (float)(oldValue * ((float)(oldScrollSize.getHeight () - vSize.getHeight ()) / ((float)cs.getHeight () - vSize.getHeight ())));
528 if (newValue > 1.f)
529 newValue = 1.f;
530 else if (newValue < 0.f)
531 newValue = 0.f;
532 vsb->setValue (newValue);
533 }
534 if (oldSize != containerSize)
535 vsb->onVisualChange ();
536 valueChanged (vsb);
537 }
538 if (hsb)
539 {
540 CRect oldScrollSize = hsb->getScrollSize (oldScrollSize);
541 float oldValue = hsb->getValue ();
542 hsb->setScrollSize (cs);
543 if (cs.getWidth () <= getViewSize ().getWidth ())
544 hsb->setValue (0);
545 else if (sc && keepVisibleArea && oldScrollSize.getWidth () != cs.getWidth ())
546 {
547 CRect vSize = sc->getViewSize ();
548 float newValue = (float)(oldValue * ((float)(oldScrollSize.getWidth () - vSize.getWidth ()) / ((float)cs.getWidth () - vSize.getWidth ())));
549 if (newValue > 1.f)
550 newValue = 1.f;
551 else if (newValue < 0.f)
552 newValue = 0.f;
553 hsb->setValue (newValue);
554 }
555 if (oldSize != containerSize)
556 hsb->onVisualChange ();
557 valueChanged (hsb);
558 }
559 }
560
561 //-----------------------------------------------------------------------------
makeRectVisible(const CRect & rect)562 void CScrollView::makeRectVisible (const CRect& rect)
563 {
564 CRect r (rect);
565 const CPoint& scrollOffset = sc->getScrollOffset ();
566 CPoint newOffset (scrollOffset);
567 CRect vs = sc->getViewSize ();
568 if (!(style & kDontDrawFrame))
569 {
570 vs.left--; //vs.top--;
571 vs.right++; //vs.bottom++;
572 }
573 CRect cs (containerSize);
574 cs.offset (-cs.left, -cs.top);
575 cs.setWidth (vs.getWidth ());
576 cs.setHeight (vs.getHeight ());
577 if (r.top >= cs.top && r.bottom <= cs.bottom && r.left >= cs.left && r.right <= cs.right)
578 return;
579 if (r.top < cs.top)
580 {
581 newOffset.y -= (cs.top - r.top);
582 }
583 else if (r.bottom > cs.bottom)
584 {
585 newOffset.y += (r.bottom - cs.bottom);
586 }
587 if (r.left < cs.left)
588 {
589 newOffset.x -= (cs.left + r.left);
590 }
591 else if (r.right > cs.right && r.left != cs.left)
592 {
593 newOffset.x += (cs.right - r.right);
594 }
595 if (vsb && newOffset.y != scrollOffset.y)
596 {
597 if (containerSize.getHeight () == vs.getHeight ())
598 vsb->setValue (0.f);
599 else
600 vsb->setValue ((float)(newOffset.y - vs.top) / (float)(containerSize.getHeight () - vs.getHeight ()));
601 vsb->bounceValue ();
602 vsb->onVisualChange ();
603 vsb->invalid ();
604 valueChanged (vsb);
605 }
606 if (hsb && newOffset.x != scrollOffset.x)
607 {
608 if (containerSize.getWidth () == vs.getWidth ())
609 hsb->setValue (0.f);
610 else
611 hsb->setValue (-(float)(newOffset.x - vs.left) / (float)(containerSize.getWidth () - vs.getWidth ()));
612 hsb->bounceValue ();
613 hsb->onVisualChange ();
614 hsb->invalid ();
615 valueChanged (hsb);
616 }
617 }
618
619 //-----------------------------------------------------------------------------
resetScrollOffset()620 void CScrollView::resetScrollOffset ()
621 {
622 if (vsb)
623 {
624 vsb->setValue (0);
625 vsb->bounceValue ();
626 vsb->onVisualChange ();
627 vsb->invalid ();
628 valueChanged (vsb);
629 }
630 if (hsb)
631 {
632 hsb->setValue (0);
633 hsb->bounceValue ();
634 hsb->onVisualChange ();
635 hsb->invalid ();
636 valueChanged (hsb);
637 }
638 }
639
640 //-----------------------------------------------------------------------------
getScrollOffset() const641 const CPoint& CScrollView::getScrollOffset () const
642 {
643 return sc->getScrollOffset ();
644 }
645
646 //-----------------------------------------------------------------------------
addView(CView * pView,CView * pBefore)647 bool CScrollView::addView (CView* pView, CView* pBefore)
648 {
649 return sc->addView (pView, pBefore);
650 }
651
652 //-----------------------------------------------------------------------------
removeView(CView * pView,bool withForget)653 bool CScrollView::removeView (CView *pView, bool withForget)
654 {
655 return sc->removeView (pView, withForget);
656 }
657
658 //-----------------------------------------------------------------------------
removeAll(bool withForget)659 bool CScrollView::removeAll (bool withForget)
660 {
661 return sc->removeAll (withForget);
662 }
663
664 //-----------------------------------------------------------------------------
getNbViews() const665 uint32_t CScrollView::getNbViews () const
666 {
667 return sc->getNbViews ();
668 }
669
670 //-----------------------------------------------------------------------------
getView(uint32_t index) const671 CView* CScrollView::getView (uint32_t index) const
672 {
673 return sc->getView (index);
674 }
675
676 //-----------------------------------------------------------------------------
changeViewZOrder(CView * view,uint32_t newIndex)677 bool CScrollView::changeViewZOrder (CView* view, uint32_t newIndex)
678 {
679 return sc->changeViewZOrder (view, newIndex);
680 }
681
682 //-----------------------------------------------------------------------------
setTransparency(bool val)683 void CScrollView::setTransparency (bool val)
684 {
685 CViewContainer::setTransparency (val);
686 }
687
688 //-----------------------------------------------------------------------------
setBackgroundColor(const CColor & color)689 void CScrollView::setBackgroundColor (const CColor& color)
690 {
691 CViewContainer::setBackgroundColor (color);
692 }
693
694 //-----------------------------------------------------------------------------
valueChanged(CControl * pControl)695 void CScrollView::valueChanged (CControl *pControl)
696 {
697 if (sc)
698 {
699 float value = pControl->getValue ();
700 int32_t tag = pControl->getTag ();
701 CPoint offset;
702 CRect vsize = sc->getViewSize ();
703 CRect csize = sc->getContainerSize ();
704 sc->getScrollOffset (offset);
705
706 switch (tag)
707 {
708 case kHSBTag:
709 {
710 if (csize.getWidth () > vsize.getWidth ())
711 {
712 offset.x = (int32_t) (csize.left - (csize.getWidth () - vsize.getWidth ()) * value);
713 sc->setScrollOffset (offset, false);
714 }
715 else if (offset.x < 0)
716 {
717 offset.x = 0;
718 sc->setScrollOffset (offset, false);
719 }
720 break;
721 }
722 case kVSBTag:
723 {
724 if (csize.getHeight () > vsize.getHeight ())
725 {
726 offset.y = (int32_t) (csize.top + (csize.getHeight () - vsize.getHeight ()) * value);
727 sc->setScrollOffset (offset, false);
728 }
729 else if (offset.y > 0)
730 {
731 offset.y = 0;
732 sc->setScrollOffset (offset, false);
733 }
734 break;
735 }
736 }
737 }
738 }
739
740 //-----------------------------------------------------------------------------
drawBackgroundRect(CDrawContext * pContext,const CRect & _updateRect)741 void CScrollView::drawBackgroundRect (CDrawContext *pContext, const CRect& _updateRect)
742 {
743 CRect r (getViewSize ());
744 r.originize ();
745 CViewContainer::drawBackgroundRect (pContext, r);
746 }
747
748 //-----------------------------------------------------------------------------
onWheel(const CPoint & where,const CMouseWheelAxis & axis,const float & distance,const CButtonState & buttons)749 bool CScrollView::onWheel (const CPoint &where, const CMouseWheelAxis &axis, const float &distance, const CButtonState &buttons)
750 {
751 bool result = CViewContainer::onWheel (where, axis, distance, buttons);
752 if (!result)
753 {
754 if (vsb && axis == kMouseWheelAxisY)
755 result = vsb->onWheel (where, axis, distance, buttons);
756 else if (hsb && axis == kMouseWheelAxisX)
757 result = hsb->onWheel (where, axis, distance, buttons);
758 }
759 return result;
760 }
761
762 //-----------------------------------------------------------------------------
notify(CBaseObject * sender,IdStringPtr message)763 CMessageResult CScrollView::notify (CBaseObject* sender, IdStringPtr message)
764 {
765 if (message == kMsgNewFocusView && getStyle () & kFollowFocusView)
766 {
767 auto* focusView = static_cast<CView*> (sender);
768 if (sc->isChild (focusView, true))
769 {
770 CRect r = focusView->getViewSize ();
771 CPoint p;
772 focusView->localToFrame (p);
773 frameToLocal (p);
774 r.offset (p.x, p.y);
775 makeRectVisible (r);
776 }
777 }
778 return CViewContainer::notify (sender, message);
779 }
780
781 //-----------------------------------------------------------------------------
viewSizeChanged(CView * view,const CRect & oldSize)782 void CScrollView::viewSizeChanged (CView* view, const CRect& oldSize)
783 {
784 if (view == hsb)
785 {
786 hsb->setScrollSize (containerSize);
787 hsb->onVisualChange ();
788 }
789 else if (view == vsb)
790 {
791 vsb->setScrollSize (containerSize);
792 vsb->onVisualChange ();
793 }
794 }
795
796 //-----------------------------------------------------------------------------
viewWillDelete(CView * view)797 void CScrollView::viewWillDelete (CView* view)
798 {
799 if (view == hsb || view == vsb)
800 view->unregisterViewListener (this);
801 }
802
803 } // VSTGUI
804
805