/* ============================================================================== This file is part of the JUCE library - "Jules' Utility Class Extensions" Copyright 2004-9 by Raw Material Software Ltd. ------------------------------------------------------------------------------ JUCE can be redistributed and/or modified under the terms of the GNU General Public License (Version 2), as published by the Free Software Foundation. A copy of the license is included in the JUCE distribution, or can be found online at www.gnu.org/licenses. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ------------------------------------------------------------------------------ To release a closed-source product which uses JUCE, commercial licenses are available: visit www.rawmaterialsoftware.com/juce for more information. ============================================================================== */ #include "../../../core/juce_StandardHeader.h" BEGIN_JUCE_NAMESPACE #include "juce_Viewport.h" #include "../lookandfeel/juce_LookAndFeel.h" //============================================================================== Viewport::Viewport (const String& componentName) : Component (componentName), contentComp (0), lastVX (0), lastVY (0), lastVW (0), lastVH (0), scrollBarThickness (0), singleStepX (16), singleStepY (16), showHScrollbar (true), showVScrollbar (true) { // content holder is used to clip the contents so they don't overlap the scrollbars addAndMakeVisible (contentHolder = new Component()); contentHolder->setInterceptsMouseClicks (false, true); verticalScrollBar = new ScrollBar (true); horizontalScrollBar = new ScrollBar (false); addChildComponent (verticalScrollBar); addChildComponent (horizontalScrollBar); verticalScrollBar->addListener (this); horizontalScrollBar->addListener (this); setInterceptsMouseClicks (false, true); setWantsKeyboardFocus (true); } Viewport::~Viewport() { contentHolder->deleteAllChildren(); deleteAllChildren(); } //============================================================================== void Viewport::visibleAreaChanged (int, int, int, int) { } //============================================================================== void Viewport::setViewedComponent (Component* const newViewedComponent) { if (contentComp != newViewedComponent) { if (contentComp->isValidComponent()) { Component* const oldComp = contentComp; contentComp = 0; delete oldComp; } contentComp = newViewedComponent; if (contentComp != 0) { contentComp->setTopLeftPosition (0, 0); contentHolder->addAndMakeVisible (contentComp); contentComp->addComponentListener (this); } updateVisibleRegion(); } } int Viewport::getMaximumVisibleWidth() const throw() { return jmax (0, getWidth() - (verticalScrollBar->isVisible() ? getScrollBarThickness() : 0)); } int Viewport::getMaximumVisibleHeight() const throw() { return jmax (0, getHeight() - (horizontalScrollBar->isVisible() ? getScrollBarThickness() : 0)); } void Viewport::setViewPosition (const int xPixelsOffset, const int yPixelsOffset) { if (contentComp != 0) contentComp->setTopLeftPosition (-xPixelsOffset, -yPixelsOffset); } void Viewport::setViewPositionProportionately (const double x, const double y) { if (contentComp != 0) setViewPosition (jmax (0, roundDoubleToInt (x * (contentComp->getWidth() - getWidth()))), jmax (0, roundDoubleToInt (y * (contentComp->getHeight() - getHeight())))); } void Viewport::componentMovedOrResized (Component&, bool, bool) { updateVisibleRegion(); } void Viewport::resized() { updateVisibleRegion(); } //============================================================================== void Viewport::updateVisibleRegion() { if (contentComp != 0) { const int newVX = -contentComp->getX(); const int newVY = -contentComp->getY(); if (newVX == 0 && newVY == 0 && contentComp->getWidth() <= getWidth() && contentComp->getHeight() <= getHeight()) { horizontalScrollBar->setVisible (false); verticalScrollBar->setVisible (false); } horizontalScrollBar->setRangeLimits (0.0, contentComp->getWidth()); horizontalScrollBar->setCurrentRange (newVX, getMaximumVisibleWidth()); horizontalScrollBar->setSingleStepSize (singleStepX); if (! (contentComp->getWidth() > 0 && showHScrollbar && getHeight() > getScrollBarThickness())) horizontalScrollBar->setVisible (false); verticalScrollBar->setRangeLimits (0.0, contentComp->getHeight()); verticalScrollBar->setCurrentRange (newVY, getMaximumVisibleHeight()); verticalScrollBar->setSingleStepSize (singleStepY); if (! (contentComp->getHeight() > 0 && showVScrollbar && getWidth() > getScrollBarThickness())) verticalScrollBar->setVisible (false); if (verticalScrollBar->isVisible()) { horizontalScrollBar->setCurrentRange (newVX, getMaximumVisibleWidth()); verticalScrollBar->setCurrentRange (newVY, getMaximumVisibleHeight()); verticalScrollBar ->setBounds (getMaximumVisibleWidth(), 0, getScrollBarThickness(), getMaximumVisibleHeight()); } if (horizontalScrollBar->isVisible()) { horizontalScrollBar->setCurrentRange (newVX, getMaximumVisibleWidth()); horizontalScrollBar ->setBounds (0, getMaximumVisibleHeight(), getMaximumVisibleWidth(), getScrollBarThickness()); } contentHolder->setSize (getMaximumVisibleWidth(), getMaximumVisibleHeight()); const int newVW = jmin (contentComp->getRight(), getMaximumVisibleWidth()); const int newVH = jmin (contentComp->getBottom(), getMaximumVisibleHeight()); if (newVX != lastVX || newVY != lastVY || newVW != lastVW || newVH != lastVH) { lastVX = newVX; lastVY = newVY; lastVW = newVW; lastVH = newVH; visibleAreaChanged (newVX, newVY, newVW, newVH); } horizontalScrollBar->handleUpdateNowIfNeeded(); verticalScrollBar->handleUpdateNowIfNeeded(); } else { horizontalScrollBar->setVisible (false); verticalScrollBar->setVisible (false); } } //============================================================================== void Viewport::setSingleStepSizes (const int stepX, const int stepY) { singleStepX = stepX; singleStepY = stepY; updateVisibleRegion(); } void Viewport::setScrollBarsShown (const bool showVerticalScrollbarIfNeeded, const bool showHorizontalScrollbarIfNeeded) { showVScrollbar = showVerticalScrollbarIfNeeded; showHScrollbar = showHorizontalScrollbarIfNeeded; updateVisibleRegion(); } void Viewport::setScrollBarThickness (const int thickness) { scrollBarThickness = thickness; updateVisibleRegion(); } int Viewport::getScrollBarThickness() const throw() { return (scrollBarThickness > 0) ? scrollBarThickness : getLookAndFeel().getDefaultScrollbarWidth(); } void Viewport::setScrollBarButtonVisibility (const bool buttonsVisible) { verticalScrollBar->setButtonVisibility (buttonsVisible); horizontalScrollBar->setButtonVisibility (buttonsVisible); } void Viewport::scrollBarMoved (ScrollBar* scrollBarThatHasMoved, const double newRangeStart) { if (scrollBarThatHasMoved == horizontalScrollBar) { setViewPosition (roundDoubleToInt (newRangeStart), getViewPositionY()); } else if (scrollBarThatHasMoved == verticalScrollBar) { setViewPosition (getViewPositionX(), roundDoubleToInt (newRangeStart)); } } void Viewport::mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY) { if (! useMouseWheelMoveIfNeeded (e, wheelIncrementX, wheelIncrementY)) Component::mouseWheelMove (e, wheelIncrementX, wheelIncrementY); } bool Viewport::useMouseWheelMoveIfNeeded (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY) { if (! (e.mods.isAltDown() || e.mods.isCtrlDown())) { const bool hasVertBar = verticalScrollBar->isVisible(); const bool hasHorzBar = horizontalScrollBar->isVisible(); if (hasHorzBar && (wheelIncrementX != 0 || e.mods.isShiftDown() || ! hasVertBar)) { if (wheelIncrementX == 0 && ! hasVertBar) wheelIncrementX = wheelIncrementY; horizontalScrollBar->mouseWheelMove (e.getEventRelativeTo (horizontalScrollBar), wheelIncrementX, wheelIncrementY); return true; } else if (hasVertBar && wheelIncrementY != 0) { verticalScrollBar->mouseWheelMove (e.getEventRelativeTo (verticalScrollBar), wheelIncrementX, wheelIncrementY); return true; } } return false; } bool Viewport::keyPressed (const KeyPress& key) { const bool isUpDownKey = key.isKeyCode (KeyPress::upKey) || key.isKeyCode (KeyPress::downKey) || key.isKeyCode (KeyPress::pageUpKey) || key.isKeyCode (KeyPress::pageDownKey) || key.isKeyCode (KeyPress::homeKey) || key.isKeyCode (KeyPress::endKey); if (verticalScrollBar->isVisible() && isUpDownKey) return verticalScrollBar->keyPressed (key); const bool isLeftRightKey = key.isKeyCode (KeyPress::leftKey) || key.isKeyCode (KeyPress::rightKey); if (horizontalScrollBar->isVisible() && (isUpDownKey || isLeftRightKey)) return horizontalScrollBar->keyPressed (key); return false; } END_JUCE_NAMESPACE