All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opencms.gwt.client.ui.CmsScrollBar Maven / Gradle / Ivy

Go to download

OpenCms is an enterprise-ready, easy to use website content management system based on Java and XML technology. Offering a complete set of features, OpenCms helps content managers worldwide to create and maintain beautiful websites fast and efficiently.

There is a newer version: 18.0
Show newest version
/*
 * This library is part of OpenCms -
 * the Open Source Content Management System
 *
 * Copyright (c) Alkacon Software GmbH (http://www.alkacon.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * For further information about Alkacon Software, please see the
 * company website: http://www.alkacon.com
 *
 * For further information about OpenCms, please see the
 * project website: http://www.opencms.org
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.opencms.gwt.client.ui;

import com.alkacon.geranium.client.I_DescendantResizeHandler;

import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle;
import org.opencms.gwt.client.util.CmsDebugLog;
import org.opencms.gwt.client.util.CmsPositionBean;

import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.VerticalScrollbar;

/**
 * A custom scroll bar to be used with {@link org.opencms.gwt.client.ui.CmsScrollPanel}.

*/ public class CmsScrollBar extends FocusPanel implements I_DescendantResizeHandler, HasValue, VerticalScrollbar { /** * The timer used to continue to shift the knob as the user holds down one of * the left/right arrow keys. Only IE auto-repeats, so we just keep catching * the events. */ private class KeyTimer extends Timer { /** A bit indicating that this is the first run. */ private boolean m_firstRun = true; /** The number of steps to shift with each press. */ private int m_multiplier = 1; /** The delay between shifts, which shortens as the user holds down the button. */ private final int m_repeatDelay = 30; /** A bit indicating whether we are shifting to a higher or lower value. */ private boolean m_shiftUp; /** * Constructor.

*/ public KeyTimer() { // nothing to do } /** * This method will be called when a timer fires. Override it to implement * the timer's logic. */ @Override public void run() { int newPos = 0; boolean stop = false; // Slide the slider bar if (m_shiftUp) { newPos = getVerticalScrollPosition() - (m_multiplier * m_stepSize); } else { newPos = getVerticalScrollPosition() + (m_multiplier * m_stepSize); } // Check if we are paging while holding mouse down // and make sure will not overshoot original mouse down position. if (m_pagingMouse && m_shiftUp && (m_mouseDownPos > newPos)) { stop = true; setValue(Integer.valueOf(m_mouseDownPos)); } else if (m_pagingMouse && !m_shiftUp && (m_mouseDownPos < newPos)) { stop = true; setValue(Integer.valueOf(m_mouseDownPos)); } if (!stop) { if (m_firstRun) { m_firstRun = false; } // Slide the slider bar setValue(Integer.valueOf(newPos)); // Repeat this timer until cancelled by keyup event schedule(m_repeatDelay); } } /** * Schedules a timer to elapse in the future. * * @param delayMillis how long to wait before the timer elapses, in * milliseconds * @param shiftUp2 whether to shift up or not * @param multiplier2 the number of steps to shift */ public void schedule(final int delayMillis, final boolean shiftUp2, final int multiplier2) { m_firstRun = true; this.m_shiftUp = shiftUp2; this.m_multiplier = multiplier2; super.schedule(delayMillis); } } /** The initial delay. */ private static final int INITIALDELAY = 400; /** The scroll knob minimum height. */ private static final int SCROLL_KNOB_MIN_HEIGHT = 10; /** The scroll knob top and bottom offset. */ private static final int SCROLL_KNOB_OFFSET = 2; /** The size of the increments between knob positions. */ protected int m_stepSize = 5; /** The position of the first mouse down. Used for paging. */ int m_mouseDownPos; /** A flag for the when the mouse button is held down when away from the slider. */ boolean m_pagingMouse; /** The scroll content element. */ private Element m_containerElement; /** The current scroll position. */ private int m_currentValue; /** * The timer used to continue to shift the knob if the user holds down a key. */ private final KeyTimer m_keyTimer = new KeyTimer(); /** The scroll knob. */ private Element m_knob; /** The current scroll knob height. */ private int m_knobHeight; /** Last mouse Y position. */ private int m_lastMouseY; /** Mous sliding start value. */ private int m_mouseSlidingStartValue; /** Mouse sliding start Y position. */ private int m_mouseSlidingStartY; /** The page size value. */ private int m_pageSize = 20; /** The value knob position ratio. */ private double m_positionValueRatio; /** The scrollable element. */ private Element m_scrollableElement; /** A bit indicating whether or not we are currently sliding the slider bar due to keyboard events. */ private boolean m_slidingKeyboard; /** * A bit indicating whether or not we are currently sliding the slider bar due * to mouse events. */ private boolean m_slidingMouse; /** * Constructor.

* * @param scrollableElement the scrollable element * @param containerElement the scroll content */ public CmsScrollBar(Element scrollableElement, Element containerElement) { I_CmsLayoutBundle.INSTANCE.scrollBarCss().ensureInjected(); setStyleName(I_CmsLayoutBundle.INSTANCE.scrollBarCss().scrollBar()); m_scrollableElement = scrollableElement; m_containerElement = containerElement; m_knob = DOM.createDiv(); m_knob.addClassName(I_CmsLayoutBundle.INSTANCE.scrollBarCss().scrollKnob()); getElement().appendChild(m_knob); sinkEvents(Event.MOUSEEVENTS | Event.ONMOUSEWHEEL | Event.KEYEVENTS | Event.FOCUSEVENTS); } /** * @see com.google.gwt.event.dom.client.HasScrollHandlers#addScrollHandler(com.google.gwt.event.dom.client.ScrollHandler) */ public HandlerRegistration addScrollHandler(ScrollHandler handler) { // Sink the event on the scrollable element, not the root element. Event.sinkEvents(getScrollableElement(), Event.ONSCROLL); return addHandler(handler, ScrollEvent.getType()); } /** * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler) */ public HandlerRegistration addValueChangeHandler(ValueChangeHandler handler) { return addHandler(handler, ValueChangeEvent.getType()); } /** * @see com.google.gwt.user.client.ui.HasVerticalScrolling#getMaximumVerticalScrollPosition() */ public int getMaximumVerticalScrollPosition() { return m_containerElement.getOffsetHeight() - getScrollableElement().getOffsetHeight(); } /** * @see com.google.gwt.user.client.ui.HasVerticalScrolling#getMinimumVerticalScrollPosition() */ public int getMinimumVerticalScrollPosition() { return 0; } /** * @see com.google.gwt.user.client.ui.VerticalScrollbar#getScrollHeight() */ public int getScrollHeight() { return m_containerElement.getOffsetHeight(); } /** * @see com.google.gwt.user.client.ui.HasValue#getValue() */ public Integer getValue() { return Integer.valueOf(m_currentValue); } /** * @see com.google.gwt.user.client.ui.HasVerticalScrolling#getVerticalScrollPosition() */ public int getVerticalScrollPosition() { return getValue().intValue(); } /** * @param reziseable true if the panel is resizeable * */ public void isResizeable(boolean reziseable) { if (reziseable) { this.getElement().getStyle().setMarginBottom(7, Unit.PX); } else { this.getElement().getStyle().setMarginBottom(0, Unit.PX); } } /** * Listen for events that will move the knob. * * @param event the event that occurred */ @Override public final void onBrowserEvent(final Event event) { super.onBrowserEvent(event); switch (DOM.eventGetType(event)) { // Unhighlight and cancel keyboard events case Event.ONBLUR: m_keyTimer.cancel(); if (m_slidingMouse) { stopMouseSliding(event); } else if (m_slidingKeyboard) { m_slidingKeyboard = false; } break; // Mousewheel events case Event.ONMOUSEWHEEL: int velocityY = event.getMouseWheelVelocityY() * m_stepSize; event.preventDefault(); CmsDebugLog.getInstance().printLine("Whell velocity: " + velocityY); if (velocityY > 0) { shiftDown(velocityY); } else { shiftUp(-velocityY); } break; // Shift left or right on key press case Event.ONKEYDOWN: if (!m_slidingKeyboard) { int multiplier = 1; if (event.getCtrlKey()) { multiplier = m_stepSize; } switch (event.getKeyCode()) { case KeyCodes.KEY_HOME: event.preventDefault(); setValue(Integer.valueOf(0)); break; case KeyCodes.KEY_END: event.preventDefault(); setValue(Integer.valueOf(getMaximumVerticalScrollPosition())); break; case KeyCodes.KEY_PAGEUP: event.preventDefault(); m_slidingKeyboard = true; shiftUp(m_pageSize); m_keyTimer.schedule(INITIALDELAY, true, m_pageSize); break; case KeyCodes.KEY_PAGEDOWN: event.preventDefault(); m_slidingKeyboard = true; shiftDown(m_pageSize); m_keyTimer.schedule(INITIALDELAY, false, m_pageSize); break; case KeyCodes.KEY_UP: event.preventDefault(); m_slidingKeyboard = true; shiftUp(multiplier); m_keyTimer.schedule(INITIALDELAY, true, multiplier); break; case KeyCodes.KEY_DOWN: event.preventDefault(); m_slidingKeyboard = true; shiftDown(multiplier); m_keyTimer.schedule(INITIALDELAY, false, multiplier); break; default: } } break; // Stop shifting on key up case Event.ONKEYUP: m_keyTimer.cancel(); if (m_slidingKeyboard) { m_slidingKeyboard = false; } break; // Mouse Events case Event.ONMOUSEDOWN: if (sliderClicked(event)) { startMouseSliding(event); event.preventDefault(); } break; case Event.ONMOUSEUP: stopMouseSliding(event); break; case Event.ONMOUSEMOVE: slideKnob(event); break; default: } } /** * @see com.alkacon.geranium.client.I_DescendantResizeHandler#onResizeDescendant() */ public void onResizeDescendant() { redraw(); } /** * @see com.google.gwt.user.client.ui.VerticalScrollbar#setScrollHeight(int) */ public void setScrollHeight(int height) { redraw(); } /** * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object) */ public void setValue(Integer value) { setValue(value, true); } /** * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object, boolean) */ public void setValue(Integer value, boolean fireEvents) { if (value != null) { m_currentValue = value.intValue(); } else { m_currentValue = 0; } setKnobPosition(m_currentValue); // Fire the ValueChangeEvent if (fireEvents) { ValueChangeEvent.fire(this, Integer.valueOf(m_currentValue)); } } /** * @see com.google.gwt.user.client.ui.HasVerticalScrolling#setVerticalScrollPosition(int) */ public void setVerticalScrollPosition(int position) { setValue(Integer.valueOf(position)); } /** * Returns the associated scrollable element.

* * @return the associated scrollable element */ protected Element getScrollableElement() { return m_scrollableElement; } /** * @see com.google.gwt.user.client.ui.Widget#onAttach() */ @Override protected void onAttach() { super.onAttach(); /* * Attach the event listener in onAttach instead of onLoad so users cannot * accidentally override it. */ Event.setEventListener(getScrollableElement(), this); redraw(); } /** * @see com.google.gwt.user.client.ui.Widget#onDetach() */ @Override protected void onDetach() { /* * Detach the event listener in onDetach instead of onUnload so users cannot * accidentally override it. */ Event.setEventListener(getScrollableElement(), null); super.onDetach(); } /** * Redraws the scroll bar.

*/ protected void redraw() { if (isAttached()) { int outerHeight = getElement().getOffsetHeight(); int innerHeight = m_containerElement.getOffsetHeight(); if (outerHeight >= innerHeight) { setScrollbarVisible(false); } else { setScrollbarVisible(true); adjustKnobHeight(outerHeight, innerHeight); setKnobPosition(m_currentValue); } } if (m_slidingMouse) { m_mouseSlidingStartY = m_lastMouseY; m_mouseSlidingStartValue = m_currentValue; } } /** * Shifts the scroll position down.

* * @param shift the shift size */ protected void shiftDown(int shift) { int max = getMaximumVerticalScrollPosition(); if ((m_currentValue + shift) < max) { setVerticalScrollPosition(m_currentValue + shift); } else { setVerticalScrollPosition(max); } } /** * Shifts the scroll position up.

* * @param shift the shift size */ protected void shiftUp(int shift) { int min = getMinimumVerticalScrollPosition(); if ((m_currentValue - shift) > min) { setVerticalScrollPosition(m_currentValue - shift); } else { setVerticalScrollPosition(min); } } /** * Calculates the scroll knob height.

* * @param outerHeight the height of the scrollable element * @param innerHeight the height of the scroll content */ private void adjustKnobHeight(int outerHeight, int innerHeight) { int result = (int)((1.0 * outerHeight * outerHeight) / innerHeight); result = result > (outerHeight - 5) ? 5 : (result < 8 ? 8 : result); m_positionValueRatio = (1.0 * (outerHeight - result)) / (innerHeight - outerHeight); m_knobHeight = result - (2 * SCROLL_KNOB_OFFSET); m_knobHeight = m_knobHeight < SCROLL_KNOB_MIN_HEIGHT ? SCROLL_KNOB_MIN_HEIGHT : m_knobHeight; m_knob.getStyle().setHeight(m_knobHeight, Unit.PX); } /** * Sets the scroll knob position according to the given value.

* * @param value the value */ private void setKnobPosition(int value) { int top = (int)(SCROLL_KNOB_OFFSET + (m_positionValueRatio * value)); int maxPosition = getElement().getOffsetHeight() - m_knobHeight - SCROLL_KNOB_OFFSET; top = top < SCROLL_KNOB_OFFSET ? SCROLL_KNOB_OFFSET : (top > maxPosition ? maxPosition : top); m_knob.getStyle().setTop(top, Unit.PX); } /** * Sets the scroll bar visibility.

* * @param visible true to set the scroll bar visible */ private void setScrollbarVisible(boolean visible) { if (visible) { getElement().getStyle().clearWidth(); m_knob.getStyle().clearDisplay(); } else { getElement().getStyle().setWidth(0, Unit.PX); m_knob.getStyle().setDisplay(Display.NONE); } } /** * Sides the scroll knob according to the mouse event.

* * @param event the mouse event */ private void slideKnob(Event event) { if (m_slidingMouse) { m_lastMouseY = event.getClientY(); int shift = (int)((m_lastMouseY - m_mouseSlidingStartY) / m_positionValueRatio); int nextValue = m_mouseSlidingStartValue + shift; CmsDebugLog.getInstance().printLine("Mouse sliding should set value to: " + nextValue); int max = getMaximumVerticalScrollPosition(); int min = getMinimumVerticalScrollPosition(); if (nextValue < min) { nextValue = min; } else if (nextValue > max) { nextValue = max; } setValue(Integer.valueOf(nextValue)); } } /** * Returns true if the events mouse position is above the scroll bar knob.

* * @param event the mouse event * * @return true if the events mouse position is above the scroll bar knob */ private boolean sliderClicked(Event event) { boolean result = CmsPositionBean.generatePositionInfo(m_knob).isOverElement( event.getClientX() + Window.getScrollLeft(), event.getClientY() + Window.getScrollTop()); CmsDebugLog.getInstance().printLine("Slider was clicked: " + result); return result; } /** * Starts the mouse sliding.

* * @param event the mouse event */ private void startMouseSliding(Event event) { if (!m_slidingMouse) { m_slidingMouse = true; DOM.setCapture(getElement()); m_mouseSlidingStartY = event.getClientY(); m_mouseSlidingStartValue = m_currentValue; CmsDebugLog.getInstance().printLine( "Mouse sliding started with clientY: " + m_mouseSlidingStartY + " and start value: " + m_mouseSlidingStartValue + " and a max value of " + getMaximumVerticalScrollPosition()); } } /** * Stops the mouse sliding.

* * @param event the mouse event */ private void stopMouseSliding(Event event) { slideKnob(event); m_slidingMouse = false; DOM.releaseCapture(getElement()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy