Mercurial > projects > dynamin
view dynamin/gui/scrollable.d @ 104:5c8c1c2e12c0
Change from real to double.
double is not dependant on the platform, and it uses less space.
author | Jordan Miner <jminer7@gmail.com> |
---|---|
date | Fri, 06 Jul 2012 18:39:45 -0500 |
parents | 73060bc3f004 |
children | acdbb30fee7e |
line wrap: on
line source
/* * Copyright Jordan Miner * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * */ module dynamin.gui.scrollable; import dynamin.all_core; import dynamin.all_painting; import dynamin.all_gui; import tango.io.Stdout; /// enum VisibleScrollBars { /** * Shows a vertical scroll bar when it is needed. A horizontal scroll bar * is never shown. A text box with line wrap turned on could use this * option. */ Vertical, /** * Shows a horizontal scroll bar when it is needed. A vertical scroll bar * is never shown. The list view in Windows Explorer could use this option. */ Horizontal, /** * Shows either scroll bar when it is needed. * A control, such as the detail view in Windows Explorer, that changes its * width when not being scrolled should use this option. */ Each, /** * Shows both scroll bars when both are needed. * A control, such as a text box, that changes its width based upon * where it is scrolled to should use this option. */ Both, /** * Does not show any scroll bars, even if they are needed. * A single-line text box uses this option. */ None } class ScrollableClipper : Control { protected: override void whenPainting(PaintingEventArgs e) { auto par = cast(Scrollable)_parent; e.graphics.fillRule = GraphicsFillRule.EvenOdd; e.graphics.rectangle(Rect(0, 0, width, height)); e.graphics.rectangle(par.contentVisibleRect); e.graphics.clip(); e.graphics.source = par.foreColor; Theme.current.Scrollable_paint(par, e.graphics); } public: override bool contains(Point pt) { auto par = cast(Scrollable)_parent; if(par is null) return false; return !par.contentVisibleRect.contains(pt); } } class ScrollableContent : Panel { private: Scrollable sc; package this(Scrollable s) { sc = s; } protected: public override Size bestSize() { return sc.contentBestSize; } override void whenMoved(EventArgs e) { sc.whenContentMoved(e); } override void whenResized(EventArgs e) { sc.whenContentResized(e); } override void whenMouseEntered(EventArgs e) { sc.whenContentMouseEntered(e); } override void whenMouseLeft(EventArgs e) { sc.whenContentMouseLeft(e); } override void whenMouseDown(MouseEventArgs e) { sc.whenContentMouseDown(e); } override void whenMouseUp(MouseEventArgs e) { sc.whenContentMouseUp(e); } override void whenMouseMoved(MouseEventArgs e) { sc.whenContentMouseMoved(e); } override void whenMouseDragged(MouseEventArgs e) { sc.whenContentMouseDragged(e); } override void whenPainting(PaintingEventArgs e) { sc.whenContentPainting(e); } } /** * Here is a skeleton implementation of a scrollable control: * ----- * class YourControl : Scrollable { * protected override void whenContentPainting(PaintingEventArgs e) { * with(e.graphics) { * drawText("Hello World", 5, 5); * } * } * } * ----- */ abstract class Scrollable : Container { private: Panel _content; protected: VisibleScrollBars _scrollBars; ScrollBar _hScrollBar, _vScrollBar; ScrollableClipper _clipper; double _sbSize; double _leftControlsWidth, _topControlsHeight; // the area the content could be shown if no scroll bars Rect _availableRect; // the area the content is actually visible, after scroll bars are // taken into account Rect _visibleRect; bool _hVisible, _vVisible; override void whenMouseTurned(MouseTurnedEventArgs e) { _vScrollBar.value = _vScrollBar.value + cast(int)(10*e.scrollAmount); } Size contentBestSize() { return Size(0, 0); } /// void whenContentMoved(EventArgs e) { } /// void whenContentResized(EventArgs e) { } /// void whenContentMouseEntered(EventArgs e) { } /// void whenContentMouseLeft(EventArgs e) { } /// void whenContentMouseDown(MouseEventArgs e) { } /// void whenContentMouseUp(MouseEventArgs e) { } /// void whenContentMouseMoved(MouseEventArgs e) { } /// void whenContentMouseDragged(MouseEventArgs e) { } /// void whenContentPainting(PaintingEventArgs e) { } /// this() { _elasticX = true; _elasticY = true; _scrollBars = VisibleScrollBars.Each; //content = c; _content = new ScrollableContent(this); _content.location = [borderSize.left, borderSize.top]; add(_content); _clipper = new ScrollableClipper; add(_clipper); _vScrollBar = new VScrollBar; _vScrollBar.valueChanged += &whenValueChanged; _hScrollBar = new HScrollBar; _hScrollBar.valueChanged += &whenValueChanged; layout(); } void whenValueChanged(EventArgs e) { _content.location = [_visibleRect.x-_hScrollBar.value, _visibleRect.y-_vScrollBar.value]; } public: override void layout() { _sbSize = Theme.current.ScrollBar_size; _leftControlsWidth = 0; //foreach(c; leftControls) // total += c.bestSize.width; _topControlsHeight = 0; //foreach(c; topControls) // total += c.bestSize.height; _availableRect = Rect(0, 0, width, height) - borderSize - BorderSize(_leftControlsWidth, _topControlsHeight, 0, 0); _hVisible = HScrollBarVisible; _vVisible = VScrollBarVisible; _visibleRect = _availableRect; if(_hVisible) _visibleRect.height = _visibleRect.height - _sbSize; if(_vVisible) _visibleRect.width = _visibleRect.width - _sbSize; remove(_hScrollBar); remove(_vScrollBar); if(_hVisible) add(_hScrollBar); if(_vVisible) add(_vScrollBar); _content.size = _content.bestSize; if(_content.width < _visibleRect.width) _content.size = Size(_visibleRect.width, _content.height); if(_content.height < _visibleRect.height) _content.size = Size(_content.width, _visibleRect.height); _clipper.size = size; _vScrollBar.maxValue = cast(int)(_content.height-_visibleRect.height); _vScrollBar.visibleValue = _visibleRect.height/_content.height; _hScrollBar.maxValue = cast(int)(_content.width-_visibleRect.width); _hScrollBar.visibleValue = _visibleRect.width/_content.width; _vScrollBar.location = [_visibleRect.right, _visibleRect.y]; _vScrollBar.size = [_sbSize, _visibleRect.height]; _hScrollBar.location = [_visibleRect.x, _visibleRect.bottom]; _hScrollBar.size = [_visibleRect.width, _sbSize]; whenValueChanged(null); } /** * Gets or sets which scroll bars are shown. The default is Each. */ VisibleScrollBars visibleScrollBars() { return _scrollBars; } /// ditto void visibleScrollBars(VisibleScrollBars bars) { // TODO: rename? SBPolicy? _scrollBars = bars; } /** * Gets whether the horizontal scroll bar is currently shown. */ bool HScrollBarVisible() { switch(_scrollBars) { case VisibleScrollBars.None: case VisibleScrollBars.Vertical: return false; case VisibleScrollBars.Horizontal: return _content.bestSize.width > _availableRect.width; case VisibleScrollBars.Each: // if vertical scroll bar shown if(_content.bestSize.height > _availableRect.height) return _content.bestSize.width > _availableRect.width-_sbSize; else return _content.bestSize.width > _availableRect.width; case VisibleScrollBars.Both: return _content.bestSize.width > _availableRect.width || _content.bestSize.height > _availableRect.height; } } /** * Gets whether the vertical scroll bar is currently shown. */ bool VScrollBarVisible() { switch(_scrollBars) { case VisibleScrollBars.None: case VisibleScrollBars.Horizontal: return false; case VisibleScrollBars.Vertical: return _content.bestSize.height > _availableRect.height; case VisibleScrollBars.Each: // if horizontal scroll bar shown if(_content.bestSize.width > _availableRect.width) return _content.bestSize.height > _availableRect.height-_sbSize; else return _content.bestSize.height > _availableRect.height; case VisibleScrollBars.Both: return _content.bestSize.height > _availableRect.height || _content.bestSize.width > _availableRect.width; } } /** * Gets the combined width of all the controls docked on the left side of * this scrollable. */ double leftControlsWidth() { return _leftControlsWidth; } /** * Gets the combined height of all the controls docked on the top side of * this scrollable. */ double topControlsHeight() { return _topControlsHeight; } /// Returns the area inside the border, scroll bars, and any controls on the side. Rect contentVisibleRect() { return _visibleRect; } Panel content() { return _content; } BorderSize borderSize() { return Theme.current.Scrollable_borderSize(this); } }