JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_ScrollBar.cpp
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26namespace juce
27{
28
30{
31public:
33 : Button (String()), direction (direc), owner (s)
34 {
36 }
37
38 void paintButton (Graphics& g, bool over, bool down) override
39 {
41 direction, owner.isVertical(), over, down);
42 }
43
44 void clicked() override
45 {
46 owner.moveScrollbarInSteps ((direction == 1 || direction == 2) ? 1 : -1);
47 }
48
49 using Button::clicked;
50
51 int direction;
52
53private:
54 ScrollBar& owner;
55
57};
58
59
60//==============================================================================
66
68{
69 upButton.reset();
70 downButton.reset();
71}
72
73//==============================================================================
75{
76 if (totalRange != newRangeLimit)
77 {
78 totalRange = newRangeLimit;
79 setCurrentRange (visibleRange, notification);
80 updateThumbPosition();
81 }
82}
83
89
91{
92 auto constrainedRange = totalRange.constrainRange (newRange);
93
94 if (visibleRange != constrainedRange)
95 {
96 visibleRange = constrainedRange;
97
98 updateThumbPosition();
99
102
105
106 return true;
107 }
108
109 return false;
110}
111
116
121
123{
124 singleStepSize = newSingleStepSize;
125}
126
128{
129 return setCurrentRange (visibleRange + howManySteps * singleStepSize, notification);
130}
131
136
141
146
148 int newRepeatDelay,
149 int newMinimumDelay)
150{
151 initialDelayInMillisecs = newInitialDelay;
152 repeatDelayInMillisecs = newRepeatDelay;
153 minimumDelayInMillisecs = newMinimumDelay;
154
155 if (upButton != nullptr)
156 {
157 upButton ->setRepeatSpeed (newInitialDelay, newRepeatDelay, newMinimumDelay);
158 downButton->setRepeatSpeed (newInitialDelay, newRepeatDelay, newMinimumDelay);
159 }
160}
161
162//==============================================================================
164{
165 listeners.add (listener);
166}
167
169{
170 listeners.remove (listener);
171}
172
173void ScrollBar::handleAsyncUpdate()
174{
175 auto start = visibleRange.getStart(); // (need to use a temp variable for VC7 compatibility)
176 listeners.call ([this, start] (Listener& l) { l.scrollBarMoved (this, start); });
177}
178
179//==============================================================================
180void ScrollBar::updateThumbPosition()
181{
183
184 int newThumbSize = roundToInt (totalRange.getLength() > 0 ? (visibleRange.getLength() * thumbAreaSize) / totalRange.getLength()
185 : thumbAreaSize);
186
188 newThumbSize = jmin (minimumScrollBarThumbSize, thumbAreaSize - 1);
189
190 if (newThumbSize > thumbAreaSize)
191 newThumbSize = thumbAreaSize;
192
193 int newThumbStart = thumbAreaStart;
194
195 if (totalRange.getLength() > visibleRange.getLength())
196 newThumbStart += roundToInt (((visibleRange.getStart() - totalRange.getStart()) * (thumbAreaSize - newThumbSize))
197 / (totalRange.getLength() - visibleRange.getLength()));
198
199 Component::setVisible (getVisibility());
200
201 if (thumbStart != newThumbStart || thumbSize != newThumbSize)
202 {
203 auto repaintStart = jmin (thumbStart, newThumbStart) - 4;
204 auto repaintSize = jmax (thumbStart + thumbSize, newThumbStart + newThumbSize) + 8 - repaintStart;
205
206 if (vertical)
208 else
210
211 thumbStart = newThumbStart;
212 thumbSize = newThumbSize;
213 }
214}
215
217{
218 if (vertical != shouldBeVertical)
219 {
220 vertical = shouldBeVertical;
221
222 if (upButton != nullptr)
223 {
224 upButton->direction = vertical ? 0 : 3;
225 downButton->direction = vertical ? 2 : 1;
226 }
227
228 updateThumbPosition();
229 }
230}
231
233{
234 autohides = shouldHideWhenFullRange;
235 updateThumbPosition();
236}
237
239{
240 return autohides;
241}
242
243//==============================================================================
245{
246 if (thumbAreaSize > 0)
247 {
248 auto& lf = getLookAndFeel();
249
250 auto thumb = (thumbAreaSize > lf.getMinimumScrollbarThumbSize (*this))
251 ? thumbSize : 0;
252
253 if (vertical)
254 lf.drawScrollbar (g, *this, 0, thumbAreaStart, getWidth(), thumbAreaSize,
255 vertical, thumbStart, thumb, isMouseOver(), isMouseButtonDown());
256 else
257 lf.drawScrollbar (g, *this, thumbAreaStart, 0, thumbAreaSize, getHeight(),
258 vertical, thumbStart, thumb, isMouseOver(), isMouseButtonDown());
259 }
260}
261
263{
264 setComponentEffect (getLookAndFeel().getScrollbarEffect());
265
266 if (isVisible())
267 resized();
268}
269
271{
272 auto length = vertical ? getHeight() : getWidth();
273
274 auto& lf = getLookAndFeel();
275 bool buttonsVisible = lf.areScrollbarButtonsVisible();
276 int buttonSize = 0;
277
278 if (buttonsVisible)
279 {
280 if (upButton == nullptr)
281 {
282 upButton .reset (new ScrollbarButton (vertical ? 0 : 3, *this));
283 downButton.reset (new ScrollbarButton (vertical ? 2 : 1, *this));
284
285 addAndMakeVisible (upButton.get());
286 addAndMakeVisible (downButton.get());
287
288 setButtonRepeatSpeed (initialDelayInMillisecs, repeatDelayInMillisecs, minimumDelayInMillisecs);
289 }
290
291 buttonSize = jmin (lf.getScrollbarButtonSize (*this), length / 2);
292 }
293 else
294 {
295 upButton.reset();
296 downButton.reset();
297 }
298
299 if (length < 32 + lf.getMinimumScrollbarThumbSize (*this))
300 {
301 thumbAreaStart = length / 2;
302 thumbAreaSize = 0;
303 }
304 else
305 {
306 thumbAreaStart = buttonSize;
307 thumbAreaSize = length - 2 * buttonSize;
308 }
309
310 if (upButton != nullptr)
311 {
312 auto r = getLocalBounds();
313
314 if (vertical)
315 {
316 upButton->setBounds (r.removeFromTop (buttonSize));
317 downButton->setBounds (r.removeFromBottom (buttonSize));
318 }
319 else
320 {
321 upButton->setBounds (r.removeFromLeft (buttonSize));
322 downButton->setBounds (r.removeFromRight (buttonSize));
323 }
324 }
325
326 updateThumbPosition();
327}
328
333
335{
336 isDraggingThumb = false;
337 lastMousePos = vertical ? e.y : e.x;
338 dragStartMousePos = lastMousePos;
339 dragStartRange = visibleRange.getStart();
340
341 if (dragStartMousePos < thumbStart)
342 {
344 startTimer (400);
345 }
346 else if (dragStartMousePos >= thumbStart + thumbSize)
347 {
349 startTimer (400);
350 }
351 else
352 {
353 isDraggingThumb = (thumbAreaSize > getLookAndFeel().getMinimumScrollbarThumbSize (*this))
354 && (thumbAreaSize > thumbSize);
355 }
356}
357
359{
360 auto mousePos = vertical ? e.y : e.x;
361
362 if (isDraggingThumb && lastMousePos != mousePos && thumbAreaSize > thumbSize)
363 {
364 auto deltaPixels = mousePos - dragStartMousePos;
365
366 setCurrentRangeStart (dragStartRange
367 + deltaPixels * (totalRange.getLength() - visibleRange.getLength())
368 / (thumbAreaSize - thumbSize));
369 }
370
371 lastMousePos = mousePos;
372}
373
375{
376 isDraggingThumb = false;
377 stopTimer();
378 repaint();
379}
380
382{
383 float increment = 10.0f * (vertical ? wheel.deltaY : wheel.deltaX);
384
385 if (increment < 0)
386 increment = jmin (increment, -1.0f);
387 else if (increment > 0)
388 increment = jmax (increment, 1.0f);
389
390 setCurrentRange (visibleRange - singleStepSize * increment);
391}
392
393void ScrollBar::timerCallback()
394{
395 if (isMouseButtonDown())
396 {
397 startTimer (40);
398
399 if (lastMousePos < thumbStart)
400 setCurrentRange (visibleRange - visibleRange.getLength());
401 else if (lastMousePos > thumbStart + thumbSize)
402 setCurrentRangeStart (visibleRange.getEnd());
403 }
404 else
405 {
406 stopTimer();
407 }
408}
409
411{
412 if (isVisible())
413 {
414 if (key == KeyPress::upKey || key == KeyPress::leftKey) return moveScrollbarInSteps (-1);
415 if (key == KeyPress::downKey || key == KeyPress::rightKey) return moveScrollbarInSteps (1);
416 if (key == KeyPress::pageUpKey) return moveScrollbarInPages (-1);
417 if (key == KeyPress::pageDownKey) return moveScrollbarInPages (1);
418 if (key == KeyPress::homeKey) return scrollToTop();
419 if (key == KeyPress::endKey) return scrollToBottom();
420 }
421
422 return false;
423}
424
426{
427 if (userVisibilityFlag != shouldBeVisible)
428 {
429 userVisibilityFlag = shouldBeVisible;
430 Component::setVisible (getVisibility());
431 }
432}
433
434bool ScrollBar::getVisibility() const noexcept
435{
436 if (! userVisibilityFlag)
437 return false;
438
439 return (! autohides) || (totalRange.getLength() > visibleRange.getLength()
440 && visibleRange.getLength() > 0.0);
441}
442
443//==============================================================================
445{
446 class ValueInterface final : public AccessibilityRangedNumericValueInterface
447 {
448 public:
449 explicit ValueInterface (ScrollBar& scrollBarToWrap) : scrollBar (scrollBarToWrap) {}
450
451 bool isReadOnly() const override { return false; }
452
453 double getCurrentValue() const override { return scrollBar.getCurrentRangeStart(); }
454 void setValue (double newValue) override { scrollBar.setCurrentRangeStart (newValue); }
455
456 AccessibleValueRange getRange() const override
457 {
458 if (scrollBar.getRangeLimit().isEmpty())
459 return {};
460
461 return { { scrollBar.getMinimumRangeLimit(), scrollBar.getMaximumRangeLimit() },
462 scrollBar.getSingleStepSize() };
463 }
464
465 private:
466 ScrollBar& scrollBar;
467
469 };
470
471 return std::make_unique<AccessibilityHandler> (*this,
472 AccessibilityRole::scrollBar,
474 AccessibilityHandler::Interfaces { std::make_unique<ValueInterface> (*this) });
475}
476
477} // namespace juce
A simple wrapper for building a collection of supported accessibility actions and corresponding callb...
A value interface that represents a ranged numeric value.
void handleUpdateNowIfNeeded()
If an update has been triggered and is pending, this will invoke it synchronously.
void triggerAsyncUpdate()
Causes the callback to be triggered at a later time.
A base class for buttons.
Definition juce_Button.h:43
virtual void clicked()
This method is called when the button has been clicked.
bool isMouseButtonDown(bool includeChildren=false) const
Returns true if the mouse button is currently held down in this component.
void setRepaintsOnMouseActivity(bool shouldRepaint) noexcept
Causes automatic repaints when the mouse enters or exits this component.
bool isVisible() const noexcept
Tests whether the component is visible or not.
void setFocusContainerType(FocusContainerType containerType) noexcept
Sets whether this component is a container for components that can have their focus traversed,...
int getHeight() const noexcept
Returns the component's height in pixels.
void addAndMakeVisible(Component *child, int zOrder=-1)
Adds a child component to this one, and also makes the child visible if it isn't already.
void repaint()
Marks the whole component as needing to be redrawn.
@ keyboardFocusContainer
The component will act as a top-level component within which keyboard focus is passed around.
void setWantsKeyboardFocus(bool wantsFocus) noexcept
Sets a flag to indicate whether this component wants keyboard focus or not.
bool isMouseOver(bool includeChildren=false) const
Returns true if the mouse is currently over this component.
int getWidth() const noexcept
Returns the component's width in pixels.
LookAndFeel & getLookAndFeel() const noexcept
Finds the appropriate look-and-feel to use for this component.
Rectangle< int > getLocalBounds() const noexcept
Returns the component's bounds, relative to its own origin.
void setComponentEffect(ImageEffectFilter *newEffect)
Adds an effect filter to alter the component's appearance.
virtual void setVisible(bool shouldBeVisible)
Makes the component visible or invisible.
A graphics context, used for drawing a component or image.
Represents a key press, including any modifier keys that are needed.
static const int homeKey
key-code for the home key
static const int upKey
key-code for the cursor-up key
static const int endKey
key-code for the end key
static const int rightKey
key-code for the cursor-right key
static const int downKey
key-code for the cursor-down key
static const int leftKey
key-code for the cursor-left key
static const int pageUpKey
key-code for the page-up key
static const int pageDownKey
key-code for the page-down key
Contains position and status information about a mouse event.
const int x
The x-position of the mouse when the event occurred.
const int y
The y-position of the mouse when the event occurred.
A general-purpose range object, that simply represents any linear range with a start and end point.
Definition juce_Range.h:40
Range constrainRange(Range rangeToConstrain) const noexcept
Returns a given range, after moving it forwards or backwards to fit it within this range.
Definition juce_Range.h:269
constexpr ValueType getStart() const noexcept
Returns the start of the range.
Definition juce_Range.h:80
constexpr ValueType getEnd() const noexcept
Returns the end of the range.
Definition juce_Range.h:86
constexpr Range movedToStartAt(const ValueType newStart) const noexcept
Returns a range with the same length as this one, but moved to have the given start position.
Definition juce_Range.h:113
constexpr ValueType getLength() const noexcept
Returns the length of the range.
Definition juce_Range.h:83
constexpr Range movedToEndAt(const ValueType newEnd) const noexcept
Returns a range with the same length as this one, but moved to have the given end position.
Definition juce_Range.h:139
A class for receiving events from a ScrollBar.
void clicked() override
This method is called when the button has been clicked.
void paintButton(Graphics &g, bool over, bool down) override
Subclasses should override this to actually paint the button's contents.
A scrollbar component.
void removeListener(Listener *listener)
Deregisters a previously-registered listener.
bool moveScrollbarInPages(int howManyPages, NotificationType notification=sendNotificationAsync)
Moves the scroll bar up or down in pages.
bool moveScrollbarInSteps(int howManySteps, NotificationType notification=sendNotificationAsync)
Moves the scrollbar by a number of single-steps.
bool setCurrentRange(Range< double > newRange, NotificationType notification=sendNotificationAsync)
Changes the position of the scrollbar's 'thumb'.
void parentHierarchyChanged() override
Called to indicate that the component's parents have changed.
void addListener(Listener *listener)
Registers a listener that will be called when the scrollbar is moved.
ScrollBar(bool isVertical)
Creates a Scrollbar.
void setOrientation(bool shouldBeVertical)
Changes the scrollbar's direction.
void mouseDown(const MouseEvent &) override
Called when a mouse button is pressed.
void mouseUp(const MouseEvent &) override
Called when a mouse button is released.
bool isVertical() const noexcept
Returns true if the scrollbar is vertical, false if it's horizontal.
bool keyPressed(const KeyPress &) override
Called when a key is pressed.
bool scrollToBottom(NotificationType notification=sendNotificationAsync)
Scrolls to the bottom (or right).
bool scrollToTop(NotificationType notification=sendNotificationAsync)
Scrolls to the top (or left).
std::unique_ptr< AccessibilityHandler > createAccessibilityHandler() override
Override this method to return a custom AccessibilityHandler for this component.
void setVisible(bool) override
Makes the component visible or invisible.
void lookAndFeelChanged() override
Called to let the component react to a change in the look-and-feel setting.
void resized() override
Called when this component's size has been changed.
double getMaximumRangeLimit() const noexcept
Returns the upper value that the thumb can be set to.
void mouseWheelMove(const MouseEvent &, const MouseWheelDetails &) override
Called when the mouse-wheel is moved.
void paint(Graphics &) override
Components can override this method to draw their content.
void mouseDrag(const MouseEvent &) override
Called when the mouse is moved while a button is held down.
~ScrollBar() override
Destructor.
void setCurrentRangeStart(double newStart, NotificationType notification=sendNotificationAsync)
Moves the bar's thumb position.
void setRangeLimits(Range< double > newRangeLimit, NotificationType notification=sendNotificationAsync)
Sets the minimum and maximum values that the bar will move between.
void setButtonRepeatSpeed(int initialDelayInMillisecs, int repeatDelayInMillisecs, int minimumDelayInMillisecs=-1)
Changes the delay before the up and down buttons autorepeat when they are held down.
void setAutoHide(bool shouldHideWhenFullRange)
Tells the scrollbar whether to make itself invisible when not needed.
bool autoHides() const noexcept
Returns true if this scrollbar is set to auto-hide when its thumb is as big as its maximum range.
double getMinimumRangeLimit() const noexcept
Returns the lower value that the thumb can be set to.
void setSingleStepSize(double newSingleStepSize) noexcept
Sets the amount by which the up and down buttons will move the bar.
The JUCE String class!
Definition juce_String.h:53
void stopTimer() noexcept
Stops the timer.
void startTimer(int intervalInMilliseconds) noexcept
Starts the timer and sets the length of interval required.
#define jassert(expression)
Platform-independent assertion macro.
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and JUCE_LEAK_DETECTOR macro for ...
JUCE Namespace.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
NotificationType
These enums are used in various classes to indicate whether a notification event should be sent out.
@ sendNotificationSync
Requests a synchronous notification.
@ dontSendNotification
No notification message should be sent.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
int roundToInt(const FloatType value) noexcept
Fast floating-point-to-integer conversion.
Contains status information about a mouse wheel event.
Utility struct which holds one or more accessibility interfaces.
virtual void drawScrollbarButton(Graphics &g, ScrollBar &scrollbar, int width, int height, int buttonDirection, bool isScrollbarVertical, bool isMouseOverButton, bool isButtonDown)=0
Draws one of the buttons on a scrollbar.
virtual int getMinimumScrollbarThumbSize(ScrollBar &)=0
Returns the minimum length in pixels to use for a scrollbar thumb.