From 502ea57e42e99b77409ad31cb97bc6bccd7f022a Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Mon, 24 Mar 2014 13:53:49 +0400 Subject: [PATCH] scrollbar, part 3 --- src/dlangui/platforms/common/platform.d | 1 + src/dlangui/widgets/controls.d | 157 +++++++++++++++++++++++- src/dlangui/widgets/widget.d | 4 + 3 files changed, 161 insertions(+), 1 deletion(-) diff --git a/src/dlangui/platforms/common/platform.d b/src/dlangui/platforms/common/platform.d index f1779db5..9bb977b8 100644 --- a/src/dlangui/platforms/common/platform.d +++ b/src/dlangui/platforms/common/platform.d @@ -106,6 +106,7 @@ class Window { if (event.action == MouseAction.ButtonDown && _mouseCaptureWidget is null) { Log.d("Setting active widget"); _mouseCaptureWidget = root; + _mouseCaptureButtons = event.flags & (MouseFlag.LButton|MouseFlag.RButton|MouseFlag.MButton); } else if (event.action == MouseAction.Move && _mouseTrackingWidget is null) { Log.d("Setting tracking widget"); _mouseTrackingWidget = root; diff --git a/src/dlangui/widgets/controls.d b/src/dlangui/widgets/controls.d index 67fabb90..ab4c28d1 100644 --- a/src/dlangui/widgets/controls.d +++ b/src/dlangui/widgets/controls.d @@ -151,10 +151,130 @@ class Button : Widget { } /// scroll bar - either vertical or horizontal -class ScrollBar : WidgetGroup { +class ScrollBar : WidgetGroup, OnClickHandler { protected ImageButton _btnBack; protected ImageButton _btnForward; + protected ImageButton _indicator; + protected Rect _scrollArea; protected int _btnSize; + protected int _minIndicatorSize; + protected int _minValue = 0; + protected int _maxValue = 100; + protected int _pageSize = 30; + protected int _position = 20; + + class IndicatorButton : ImageButton { + Point _dragStart; + int _dragStartPosition; + bool _dragging; + Rect _dragStartRect; + this(string resourceId) { + super("INDICATOR", resourceId); + } + + /// process mouse event; return true if event is processed by widget. + override bool onMouseEvent(MouseEvent event) { + // support onClick + if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) { + setState(State.Pressed); + _dragging = true; + _dragStart.x = event.x; + _dragStart.y = event.y; + _dragStartPosition = _position; + _dragStartRect = _pos; + return true; + } + if (event.action == MouseAction.Move && _dragging) { + int delta = _orientation == Orientation.Vertical ? event.y - _dragStart.y : event.x - _dragStart.x; + Rect rc = _dragStartRect; + int offset; + int space; + if (_orientation == Orientation.Vertical) { + rc.top += delta; + rc.bottom += delta; + if (rc.top < _scrollArea.top) { + rc.top = _scrollArea.top; + rc.bottom = _scrollArea.top + _dragStartRect.height; + } else if (rc.bottom > _scrollArea.bottom) { + rc.top = _scrollArea.top - _dragStartRect.height; + rc.bottom = _scrollArea.bottom; + } + offset = rc.top - _scrollArea.top; + space = _scrollArea.height - rc.height; + } else { + rc.left += delta; + rc.right += delta; + if (rc.left < _scrollArea.left) { + rc.left = _scrollArea.left; + rc.right = _scrollArea.left + _dragStartRect.width; + } else if (rc.right > _scrollArea.right) { + rc.left = _scrollArea.right - _dragStartRect.width; + rc.right = _scrollArea.right; + } + offset = rc.left - _scrollArea.left; + space = _scrollArea.width - rc.width; + } + _pos = rc; + int position = space > 0 ? _minValue + offset * (_maxValue - _minValue - _pageSize) / space : 0; + invalidate(); + onIndicatorDragging(_dragStartPosition, position); + return true; + } + if (event.action == MouseAction.ButtonUp && event.button == MouseButton.Left) { + resetState(State.Pressed); + if (_dragging) { + + _dragging = false; + } + return true; + } + if (event.action == MouseAction.Cancel) { + Log.d("IndicatorButton.onMouseEvent event.action == MouseAction.Cancel"); + resetState(State.Pressed); + _dragging = false; + return true; + } + return false; + } + + } + + protected bool onIndicatorDragging(int initialPosition, int currentPosition) { + _position = currentPosition; + return true; + } + + private bool calcButtonSizes(int availableSize, ref int spaceBackSize, ref int spaceForwardSize, ref int indicatorSize) { + int dv = _maxValue - _minValue; + if (_pageSize >= dv) { + // full size + spaceBackSize = spaceForwardSize = 0; + indicatorSize = availableSize; + return false; + } + if (dv < 0) + dv = 0; + indicatorSize = _pageSize * availableSize / dv; + if (indicatorSize < _minIndicatorSize) + indicatorSize = _minIndicatorSize; + if (indicatorSize >= availableSize) { + // full size + spaceBackSize = spaceForwardSize = 0; + indicatorSize = availableSize; + return false; + } + int spaceLeft = availableSize - indicatorSize; + int topv = _position - _minValue; + int bottomv = _position + _pageSize - _minValue; + if (topv < 0) + topv = 0; + if (bottomv > dv) + bottomv = dv; + bottomv = dv - bottomv; + spaceBackSize = spaceLeft * topv / (topv + bottomv); + spaceForwardSize = spaceLeft - spaceBackSize; + return true; + } protected Orientation _orientation = Orientation.Vertical; /// returns scrollbar orientation (Vertical, Horizontal) @@ -165,6 +285,7 @@ class ScrollBar : WidgetGroup { _orientation = value; _btnBack.drawableId = _orientation == Orientation.Vertical ? "scrollbar_btn_up" : "scrollbar_btn_left"; _btnForward.drawableId = _orientation == Orientation.Vertical ? "scrollbar_btn_down" : "scrollbar_btn_right"; + _indicator.drawableId = _orientation == Orientation.Vertical ? "scrollbar_indicator_vertical" : "scrollbar_indicator_horizontal"; requestLayout(); } return this; @@ -176,15 +297,21 @@ class ScrollBar : WidgetGroup { _orientation = orient; _btnBack = new ImageButton("BACK", _orientation == Orientation.Vertical ? "scrollbar_btn_up" : "scrollbar_btn_left"); _btnForward = new ImageButton("FORWARD", _orientation == Orientation.Vertical ? "scrollbar_btn_down" : "scrollbar_btn_right"); + _indicator = new IndicatorButton(_orientation == Orientation.Vertical ? "scrollbar_indicator_vertical" : "scrollbar_indicator_horizontal"); addChild(_btnBack); addChild(_btnForward); + addChild(_indicator); + _btnBack.onClickListener = &onClick; + _btnForward.onClickListener = &onClick; } override void measure(int parentWidth, int parentHeight) { Point sz; _btnBack.measure(parentWidth, parentHeight); _btnForward.measure(parentWidth, parentHeight); + _indicator.measure(parentWidth, parentHeight); _btnSize = _btnBack.measuredWidth; + _minIndicatorSize = _orientation == Orientation.Vertical ? _indicator.measuredHeight : _indicator.measuredWidth; if (_btnSize < _btnBack.measuredHeight) _btnSize = _btnBack.measuredHeight; if (_btnSize < 16) @@ -207,6 +334,7 @@ class ScrollBar : WidgetGroup { Rect r; if (_orientation == Orientation.Vertical) { // vertical + // buttons int backbtnpos = rc.top + _btnSize; int fwdbtnpos = rc.bottom - _btnSize; r = rc; @@ -215,6 +343,17 @@ class ScrollBar : WidgetGroup { r = rc; r.top = fwdbtnpos; _btnForward.layout(r); + // indicator + r = rc; + r.top = backbtnpos; + r.bottom = fwdbtnpos; + _scrollArea = r; + int spaceBackSize, spaceForwardSize, indicatorSize; + bool indicatorVisible = calcButtonSizes(r.height, spaceBackSize, spaceForwardSize, indicatorSize); + Rect irc = r; + irc.top += spaceBackSize; + irc.bottom -= spaceForwardSize; + _indicator.layout(irc); } else { // horizontal int backbtnpos = rc.left + _btnSize; @@ -225,11 +364,26 @@ class ScrollBar : WidgetGroup { r = rc; r.left = fwdbtnpos; _btnForward.layout(r); + // indicator + r = rc; + r.left = backbtnpos; + r.right = fwdbtnpos; + _scrollArea = r; + int spaceBackSize, spaceForwardSize, indicatorSize; + bool indicatorVisible = calcButtonSizes(r.width, spaceBackSize, spaceForwardSize, indicatorSize); + Rect irc = r; + irc.left += spaceBackSize; + irc.right -= spaceForwardSize; + _indicator.layout(irc); } _pos = rc; _needLayout = false; } + override bool onClick(Widget source) { + return true; + } + /// Draw widget at its position to buffer override void onDraw(DrawBuf buf) { if (visibility != Visibility.Visible) @@ -241,5 +395,6 @@ class ScrollBar : WidgetGroup { ClipRectSaver(buf, rc); _btnForward.onDraw(buf); _btnBack.onDraw(buf); + _indicator.onDraw(buf); } } diff --git a/src/dlangui/widgets/widget.d b/src/dlangui/widgets/widget.d index 0fb89841..05a29dda 100644 --- a/src/dlangui/widgets/widget.d +++ b/src/dlangui/widgets/widget.d @@ -31,6 +31,10 @@ enum Orientation : ubyte { Horizontal } +interface OnClickHandler { + bool onClick(Widget source); +} + class Widget { /// widget id protected string _id;