refactoring: ScrollBar and SliderWidget moved to scrollbar.d

This commit is contained in:
Vadim Lopatin 2016-10-11 09:02:06 +03:00
parent ab05bf5340
commit f3a03a7378
9 changed files with 15 additions and 964 deletions

View File

@ -351,6 +351,8 @@
<Compile Include="src\dlangui\widgets\docks.d" />
<Compile Include="src\dlangui\widgets\editors.d" />
<Compile Include="src\dlangui\widgets\grid.d" />
<Compile Include="src\dlangui\widgets\groupbox.d" />
<Compile Include="src\dlangui\widgets\scrollbar.d" />
<Compile Include="src\dlangui\widgets\layouts.d" />
<Compile Include="src\dlangui\widgets\lists.d" />
<Compile Include="src\dlangui\widgets\menu.d" />

View File

@ -162,6 +162,8 @@
<Compile Include="src\dlangui\widgets\docks.d" />
<Compile Include="src\dlangui\widgets\editors.d" />
<Compile Include="src\dlangui\widgets\grid.d" />
<Compile Include="src\dlangui\widgets\groupbox.d" />
<Compile Include="src\dlangui\widgets\scrollbar.d" />
<Compile Include="src\dlangui\widgets\layouts.d" />
<Compile Include="src\dlangui\widgets\lists.d" />
<Compile Include="src\dlangui\widgets\menu.d" />

View File

@ -153,6 +153,8 @@
<Compile Include="src\dlangui\widgets\docks.d" />
<Compile Include="src\dlangui\widgets\editors.d" />
<Compile Include="src\dlangui\widgets\grid.d" />
<Compile Include="src\dlangui\widgets\groupbox.d" />
<Compile Include="src\dlangui\widgets\scrollbar.d" />
<Compile Include="src\dlangui\widgets\layouts.d" />
<Compile Include="src\dlangui\widgets\lists.d" />
<Compile Include="src\dlangui\widgets\menu.d" />

View File

@ -983,6 +983,7 @@
<File path="src\dlangui\widgets\metadata.d" />
<File path="src\dlangui\widgets\popup.d" />
<File path="src\dlangui\widgets\scroll.d" />
<File path="src\dlangui\widgets\scrollbar.d" />
<File path="src\dlangui\widgets\srcedit.d" />
<File path="src\dlangui\widgets\statusline.d" />
<File path="src\dlangui\widgets\styles.d" />

View File

@ -59,6 +59,7 @@ public {
import dlangui.graphics.drawbuf;
import dlangui.widgets.widget;
import dlangui.widgets.controls;
import dlangui.widgets.scrollbar;
import dlangui.widgets.layouts;
import dlangui.widgets.groupbox;
import dlangui.widgets.lists;

View File

@ -321,6 +321,7 @@ void registerStandardWidgets() {
import dlangui.widgets.widget;
import dlangui.widgets.layouts;
import dlangui.widgets.controls;
import dlangui.widgets.scrollbar;
import dlangui.widgets.lists;
import dlangui.widgets.combobox;
import dlangui.widgets.editors;

View File

@ -1,8 +1,11 @@
// Written in the D programming language.
/**
This module contains simple controls widgets implementation.
TextWidget - static text
ImageWidget - image
@ -19,15 +22,12 @@ RadioButton - radio button
CheckBox - button with check mark
ScrollBar - scrollbar control
SliderWidget - slider control
UrlImageTextButton - URL link button
CanvasWidget - for drawing arbitrary graphics
Note: ScrollBar and SliderWidget are moved to dlangui.widgets.scrollbar
Synopsis:
@ -576,966 +576,6 @@ class Button : Widget {
}
/// scroll event handler interface
interface OnScrollHandler {
/// handle scroll event
bool onScrollEvent(AbstractSlider source, ScrollEvent event);
}
/// base class for widgets like scrollbars and sliders
class AbstractSlider : WidgetGroup {
protected int _minValue = 0;
protected int _maxValue = 100;
protected int _pageSize = 30;
protected int _position = 20;
/// create with ID parameter
this(string ID) {
super(ID);
}
/// scroll event listeners
Signal!OnScrollHandler scrollEvent;
/// returns slider position
@property int position() const { return _position; }
/// sets new slider position
@property AbstractSlider position(int newPosition) {
if (_position != newPosition) {
_position = newPosition;
onPositionChanged();
}
return this;
}
protected void onPositionChanged() {
requestLayout();
}
/// returns slider range min value
@property int minValue() const { return _minValue; }
/// sets slider range min value
@property AbstractSlider minValue(int v) { _minValue = v; return this; }
/// returns slider range max value
@property int maxValue() const { return _maxValue; }
/// sets slider range max value
@property AbstractSlider maxValue(int v) { _maxValue = v; return this; }
/// page size (visible area size)
@property int pageSize() const { return _pageSize; }
/// set page size (visible area size)
@property AbstractSlider pageSize(int size) {
if (_pageSize != size) {
_pageSize = size;
//requestLayout();
}
return this;
}
/// set int property value, for ML loaders
//mixin(generatePropertySettersMethodOverride("setIntProperty", "int",
// "minValue", "maxValue", "pageSize", "position"));
/// set int property value, for ML loaders
override bool setIntProperty(string name, int value) {
if (name.equal("orientation")) { // use same value for all sides
orientation = cast(Orientation)value;
return true;
}
mixin(generatePropertySetters("minValue", "maxValue", "pageSize", "position"));
return super.setIntProperty(name, value);
}
/// set new range (min and max values for slider)
AbstractSlider setRange(int min, int max) {
if (_minValue != min || _maxValue != max) {
_minValue = min;
_maxValue = max;
//requestLayout();
}
return this;
}
bool sendScrollEvent(ScrollAction action) {
return sendScrollEvent(action, _position);
}
bool sendScrollEvent(ScrollAction action, int position) {
if (!scrollEvent.assigned)
return false;
ScrollEvent event = new ScrollEvent(action, _minValue, _maxValue, _pageSize, position);
bool res = scrollEvent(this, event);
if (event.positionChanged) {
_position = event.position;
if (_position > _maxValue)
_position = _maxValue;
if (_position < _minValue)
_position = _minValue;
onPositionChanged();
}
return true;
}
protected Orientation _orientation = Orientation.Vertical;
/// returns scrollbar orientation (Vertical, Horizontal)
@property Orientation orientation() { return _orientation; }
/// sets scrollbar orientation
@property AbstractSlider orientation(Orientation value) {
if (_orientation != value) {
_orientation = value;
requestLayout();
}
return this;
}
}
/// scroll bar - either vertical or horizontal
class ScrollBar : AbstractSlider, OnClickHandler {
protected ImageButton _btnBack;
protected ImageButton _btnForward;
protected SliderButton _indicator;
protected PageScrollButton _pageUp;
protected PageScrollButton _pageDown;
protected Rect _scrollArea;
protected int _btnSize;
protected int _minIndicatorSize;
class PageScrollButton : Widget {
this(string ID) {
super(ID);
styleId = STYLE_PAGE_SCROLL;
trackHover = true;
clickable = true;
}
}
class SliderButton : ImageButton {
Point _dragStart;
int _dragStartPosition;
bool _dragging;
Rect _dragStartRect;
this(string resourceId) {
super("SLIDER", resourceId);
styleId = STYLE_SCROLLBAR_BUTTON;
trackHover = true;
}
/// 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;
sendScrollEvent(ScrollAction.SliderPressed, _position);
return true;
}
if (event.action == MouseAction.FocusOut && _dragging) {
debug(scrollbar) Log.d("ScrollBar slider dragging - FocusOut");
return true;
}
if (event.action == MouseAction.FocusIn && _dragging) {
debug(scrollbar) Log.d("ScrollBar slider dragging - FocusIn");
return true;
}
if (event.action == MouseAction.Move && _dragging) {
int delta = _orientation == Orientation.Vertical ? event.y - _dragStart.y : event.x - _dragStart.x;
debug(scrollbar) Log.d("ScrollBar slider dragging - Move delta=", delta);
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.bottom - _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;
}
layoutButtons(rc);
//_pos = rc;
int position = cast(int)(space > 0 ? _minValue + cast(long)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) {
sendScrollEvent(ScrollAction.SliderReleased, _position);
_dragging = false;
}
return true;
}
if (event.action == MouseAction.Move && trackHover) {
if (!(state & State.Hovered)) {
debug(scrollbar) Log.d("Hover ", id);
setState(State.Hovered);
}
return true;
}
if (event.action == MouseAction.Leave && trackHover) {
debug(scrollbar) Log.d("Leave ", id);
resetState(State.Hovered);
return true;
}
if (event.action == MouseAction.Cancel && trackHover) {
debug(scrollbar) Log.d("Cancel ? trackHover", id);
resetState(State.Hovered);
resetState(State.Pressed);
_dragging = false;
return true;
}
if (event.action == MouseAction.Cancel) {
debug(scrollbar) Log.d("SliderButton.onMouseEvent event.action == MouseAction.Cancel");
resetState(State.Pressed);
_dragging = false;
return true;
}
return false;
}
}
protected bool onIndicatorDragging(int initialPosition, int currentPosition) {
_position = currentPosition;
return sendScrollEvent(ScrollAction.SliderMoved, currentPosition);
}
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 = dv ? _pageSize * availableSize / dv : _minIndicatorSize;
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 = cast(int)(cast(long)spaceLeft * topv / (topv + bottomv));
spaceForwardSize = spaceLeft - spaceBackSize;
return true;
}
/// returns scrollbar orientation (Vertical, Horizontal)
override @property Orientation orientation() { return _orientation; }
/// sets scrollbar orientation
override @property AbstractSlider orientation(Orientation value) {
if (_orientation != value) {
_orientation = value;
_btnBack.drawableId = style.customDrawableId(_orientation == Orientation.Vertical ? ATTR_SCROLLBAR_BUTTON_UP : ATTR_SCROLLBAR_BUTTON_LEFT);
_btnForward.drawableId = style.customDrawableId(_orientation == Orientation.Vertical ? ATTR_SCROLLBAR_BUTTON_DOWN : ATTR_SCROLLBAR_BUTTON_RIGHT);
_indicator.drawableId = style.customDrawableId(_orientation == Orientation.Vertical ? ATTR_SCROLLBAR_INDICATOR_VERTICAL : ATTR_SCROLLBAR_INDICATOR_HORIZONTAL);
requestLayout();
}
return this;
}
/// set string property value, for ML loaders
override bool setStringProperty(string name, string value) {
if (name.equal("orientation")) {
if (value.equal("Vertical") || value.equal("vertical"))
orientation = Orientation.Vertical;
else
orientation = Orientation.Horizontal;
return true;
}
return super.setStringProperty(name, value);
}
/// empty parameter list constructor - for usage by factory
this() {
this(null, Orientation.Vertical);
}
/// create with ID parameter
this(string ID, Orientation orient = Orientation.Vertical) {
super(ID);
styleId = STYLE_SCROLLBAR;
_orientation = orient;
_btnBack = new ImageButton("BACK", style.customDrawableId(_orientation == Orientation.Vertical ? ATTR_SCROLLBAR_BUTTON_UP : ATTR_SCROLLBAR_BUTTON_LEFT));
_btnForward = new ImageButton("FORWARD", style.customDrawableId(_orientation == Orientation.Vertical ? ATTR_SCROLLBAR_BUTTON_DOWN : ATTR_SCROLLBAR_BUTTON_RIGHT));
_pageUp = new PageScrollButton("PAGE_UP");
_pageDown = new PageScrollButton("PAGE_DOWN");
_btnBack.styleId = STYLE_SCROLLBAR_BUTTON_TRANSPARENT;
_btnForward.styleId = STYLE_SCROLLBAR_BUTTON_TRANSPARENT;
_indicator = new SliderButton(style.customDrawableId(_orientation == Orientation.Vertical ? ATTR_SCROLLBAR_INDICATOR_VERTICAL : ATTR_SCROLLBAR_INDICATOR_HORIZONTAL));
addChild(_btnBack);
addChild(_btnForward);
addChild(_indicator);
addChild(_pageUp);
addChild(_pageDown);
_btnBack.focusable = false;
_btnForward.focusable = false;
_indicator.focusable = false;
_pageUp.focusable = false;
_pageDown.focusable = false;
_btnBack.click = &onClick;
_btnForward.click = &onClick;
_pageUp.click = &onClick;
_pageDown.click = &onClick;
}
override void measure(int parentWidth, int parentHeight) {
Point sz;
_btnBack.measure(parentWidth, parentHeight);
_btnForward.measure(parentWidth, parentHeight);
_indicator.measure(parentWidth, parentHeight);
_pageUp.measure(parentWidth, parentHeight);
_pageDown.measure(parentWidth, parentHeight);
_btnSize = _btnBack.measuredWidth;
_minIndicatorSize = _orientation == Orientation.Vertical ? _indicator.measuredHeight : _indicator.measuredWidth;
if (_btnSize < _minIndicatorSize)
_btnSize = _minIndicatorSize;
if (_btnSize < _btnForward.measuredWidth)
_btnSize = _btnForward.measuredWidth;
if (_btnSize < _btnForward.measuredHeight)
_btnSize = _btnForward.measuredHeight;
if (_btnSize < _btnBack.measuredHeight)
_btnSize = _btnBack.measuredHeight;
static if (BACKEND_GUI) {
if (_btnSize < 16)
_btnSize = 16;
}
if (_orientation == Orientation.Vertical) {
// vertical
sz.x = _btnSize;
sz.y = _btnSize * 5; // min height
} else {
// horizontal
sz.y = _btnSize;
sz.x = _btnSize * 5; // min height
}
measuredContent(parentWidth, parentHeight, sz.x, sz.y);
}
override protected void onPositionChanged() {
if (!needLayout)
layoutButtons();
}
/// hide controls when scroll is not possible
protected void updateState() {
bool canScroll = _maxValue - _minValue > _pageSize;
if (canScroll) {
_btnBack.setState(State.Enabled);
_btnForward.setState(State.Enabled);
_indicator.visibility = Visibility.Visible;
_pageUp.visibility = Visibility.Visible;
_pageDown.visibility = Visibility.Visible;
} else {
_btnBack.resetState(State.Enabled);
_btnForward.resetState(State.Enabled);
_indicator.visibility = Visibility.Gone;
_pageUp.visibility = Visibility.Gone;
_pageDown.visibility = Visibility.Gone;
}
cancelLayout();
}
override void cancelLayout() {
_btnBack.cancelLayout();
_btnForward.cancelLayout();
_indicator.cancelLayout();
_pageUp.cancelLayout();
_pageDown.cancelLayout();
super.cancelLayout();
}
protected void layoutButtons() {
Rect irc = _scrollArea;
if (_orientation == Orientation.Vertical) {
// vertical
int spaceBackSize, spaceForwardSize, indicatorSize;
bool indicatorVisible = calcButtonSizes(_scrollArea.height, spaceBackSize, spaceForwardSize, indicatorSize);
irc.top += spaceBackSize;
irc.bottom -= spaceForwardSize;
layoutButtons(irc);
} else {
// horizontal
int spaceBackSize, spaceForwardSize, indicatorSize;
bool indicatorVisible = calcButtonSizes(_scrollArea.width, spaceBackSize, spaceForwardSize, indicatorSize);
irc.left += spaceBackSize;
irc.right -= spaceForwardSize;
layoutButtons(irc);
}
updateState();
cancelLayout();
}
protected void layoutButtons(Rect irc) {
Rect r;
_indicator.visibility = Visibility.Visible;
if (_orientation == Orientation.Vertical) {
_indicator.layout(irc);
if (_scrollArea.top < irc.top) {
r = _scrollArea;
r.bottom = irc.top;
_pageUp.layout(r);
_pageUp.visibility = Visibility.Visible;
} else {
_pageUp.visibility = Visibility.Invisible;
}
if (_scrollArea.bottom > irc.bottom) {
r = _scrollArea;
r.top = irc.bottom;
_pageDown.layout(r);
_pageDown.visibility = Visibility.Visible;
} else {
_pageDown.visibility = Visibility.Invisible;
}
} else {
_indicator.layout(irc);
if (_scrollArea.left < irc.left) {
r = _scrollArea;
r.right = irc.left;
_pageUp.layout(r);
_pageUp.visibility = Visibility.Visible;
} else {
_pageUp.visibility = Visibility.Invisible;
}
if (_scrollArea.right > irc.right) {
r = _scrollArea;
r.left = irc.right;
_pageDown.layout(r);
_pageDown.visibility = Visibility.Visible;
} else {
_pageDown.visibility = Visibility.Invisible;
}
}
}
override void layout(Rect rc) {
_needLayout = false;
applyMargins(rc);
applyPadding(rc);
Rect r;
if (_orientation == Orientation.Vertical) {
// vertical
// buttons
int backbtnpos = rc.top + _btnSize;
int fwdbtnpos = rc.bottom - _btnSize;
r = rc;
r.bottom = backbtnpos;
_btnBack.layout(r);
r = rc;
r.top = fwdbtnpos;
_btnForward.layout(r);
// indicator
r = rc;
r.top = backbtnpos;
r.bottom = fwdbtnpos;
_scrollArea = r;
} else {
// horizontal
int backbtnpos = rc.left + _btnSize;
int fwdbtnpos = rc.right - _btnSize;
r = rc;
r.right = backbtnpos;
_btnBack.layout(r);
r = rc;
r.left = fwdbtnpos;
_btnForward.layout(r);
// indicator
r = rc;
r.left = backbtnpos;
r.right = fwdbtnpos;
_scrollArea = r;
}
layoutButtons();
_pos = rc;
}
override bool onClick(Widget source) {
Log.d("Scrollbar.onClick ", source.id);
if (source.compareId("BACK"))
return sendScrollEvent(ScrollAction.LineUp, position);
if (source.compareId("FORWARD"))
return sendScrollEvent(ScrollAction.LineDown, position);
if (source.compareId("PAGE_UP"))
return sendScrollEvent(ScrollAction.PageUp, position);
if (source.compareId("PAGE_DOWN"))
return sendScrollEvent(ScrollAction.PageDown, position);
return true;
}
/// handle mouse wheel events
override bool onMouseEvent(MouseEvent event) {
if (visibility != Visibility.Visible)
return false;
if (event.action == MouseAction.Wheel) {
int delta = event.wheelDelta;
if (delta > 0)
sendScrollEvent(ScrollAction.LineUp, position);
else if (delta < 0)
sendScrollEvent(ScrollAction.LineDown, position);
return true;
}
return super.onMouseEvent(event);
}
/// Draw widget at its position to buffer
override void onDraw(DrawBuf buf) {
if (visibility != Visibility.Visible && !buf.isClippedOut(_pos))
return;
super.onDraw(buf);
Rect rc = _pos;
applyMargins(rc);
applyPadding(rc);
auto saver = ClipRectSaver(buf, rc, alpha);
_btnForward.onDraw(buf);
_btnBack.onDraw(buf);
_pageUp.onDraw(buf);
_pageDown.onDraw(buf);
_indicator.onDraw(buf);
}
}
/// scroll bar - either vertical or horizontal
class SliderWidget : AbstractSlider, OnClickHandler {
protected SliderButton _indicator;
protected PageScrollButton _pageUp;
protected PageScrollButton _pageDown;
protected Rect _scrollArea;
protected int _btnSize;
protected int _minIndicatorSize;
class PageScrollButton : Widget {
this(string ID) {
super(ID);
styleId = STYLE_PAGE_SCROLL;
trackHover = true;
clickable = true;
}
}
class SliderButton : ImageButton {
Point _dragStart;
int _dragStartPosition;
bool _dragging;
Rect _dragStartRect;
this(string resourceId) {
super("SLIDER", resourceId);
styleId = STYLE_SCROLLBAR_BUTTON;
trackHover = true;
}
/// 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;
sendScrollEvent(ScrollAction.SliderPressed, _position);
return true;
}
if (event.action == MouseAction.FocusOut && _dragging) {
debug(scrollbar) Log.d("ScrollBar slider dragging - FocusOut");
return true;
}
if (event.action == MouseAction.FocusIn && _dragging) {
debug(scrollbar) Log.d("ScrollBar slider dragging - FocusIn");
return true;
}
if (event.action == MouseAction.Move && _dragging) {
int delta = _orientation == Orientation.Vertical ? event.y - _dragStart.y : event.x - _dragStart.x;
debug(scrollbar) Log.d("ScrollBar slider dragging - Move delta=", delta);
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.bottom - _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;
}
layoutButtons(rc);
//_pos = rc;
int position = cast(int)(space > 0 ? _minValue + cast(long)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) {
sendScrollEvent(ScrollAction.SliderReleased, _position);
_dragging = false;
}
return true;
}
if (event.action == MouseAction.Move && trackHover) {
if (!(state & State.Hovered)) {
debug(scrollbar) Log.d("Hover ", id);
setState(State.Hovered);
}
return true;
}
if (event.action == MouseAction.Leave && trackHover) {
debug(scrollbar) Log.d("Leave ", id);
resetState(State.Hovered);
return true;
}
if (event.action == MouseAction.Cancel && trackHover) {
debug(scrollbar) Log.d("Cancel ? trackHover", id);
resetState(State.Hovered);
resetState(State.Pressed);
_dragging = false;
return true;
}
if (event.action == MouseAction.Cancel) {
debug(scrollbar) Log.d("SliderButton.onMouseEvent event.action == MouseAction.Cancel");
resetState(State.Pressed);
_dragging = false;
return true;
}
return false;
}
}
protected bool onIndicatorDragging(int initialPosition, int currentPosition) {
_position = currentPosition;
return sendScrollEvent(ScrollAction.SliderMoved, currentPosition);
}
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 = dv ? _pageSize * availableSize / dv : _minIndicatorSize;
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 = cast(int)(cast(long)spaceLeft * topv / (topv + bottomv));
spaceForwardSize = spaceLeft - spaceBackSize;
return true;
}
/// returns scrollbar orientation (Vertical, Horizontal)
override @property Orientation orientation() { return _orientation; }
/// sets scrollbar orientation
override @property AbstractSlider orientation(Orientation value) {
if (_orientation != value) {
_orientation = value;
_indicator.drawableId = style.customDrawableId(_orientation == Orientation.Vertical ? ATTR_SCROLLBAR_INDICATOR_VERTICAL : ATTR_SCROLLBAR_INDICATOR_HORIZONTAL);
requestLayout();
}
return this;
}
/// set string property value, for ML loaders
override bool setStringProperty(string name, string value) {
if (name.equal("orientation")) {
if (value.equal("Vertical") || value.equal("vertical"))
orientation = Orientation.Vertical;
else
orientation = Orientation.Horizontal;
return true;
}
return super.setStringProperty(name, value);
}
/// empty parameter list constructor - for usage by factory
this() {
this(null, Orientation.Horizontal);
}
/// create with ID parameter
this(string ID, Orientation orient = Orientation.Horizontal) {
super(ID);
styleId = STYLE_SLIDER;
_orientation = orient;
_pageSize = 1;
_pageUp = new PageScrollButton("PAGE_UP");
_pageDown = new PageScrollButton("PAGE_DOWN");
_indicator = new SliderButton(style.customDrawableId(_orientation == Orientation.Vertical ? ATTR_SCROLLBAR_INDICATOR_VERTICAL : ATTR_SCROLLBAR_INDICATOR_HORIZONTAL));
addChild(_indicator);
addChild(_pageUp);
addChild(_pageDown);
_indicator.focusable = false;
_pageUp.focusable = false;
_pageDown.focusable = false;
_pageUp.click = &onClick;
_pageDown.click = &onClick;
}
override void measure(int parentWidth, int parentHeight) {
Point sz;
_indicator.measure(parentWidth, parentHeight);
_pageUp.measure(parentWidth, parentHeight);
_pageDown.measure(parentWidth, parentHeight);
_minIndicatorSize = _orientation == Orientation.Vertical ? _indicator.measuredHeight : _indicator.measuredWidth;
_btnSize = _minIndicatorSize;
if (_btnSize < _minIndicatorSize)
_btnSize = _minIndicatorSize;
static if (BACKEND_GUI) {
if (_btnSize < 16)
_btnSize = 16;
}
if (_orientation == Orientation.Vertical) {
// vertical
sz.x = _btnSize;
sz.y = _btnSize * 5; // min height
} else {
// horizontal
sz.y = _btnSize;
sz.x = _btnSize * 5; // min height
}
measuredContent(parentWidth, parentHeight, sz.x, sz.y);
}
override protected void onPositionChanged() {
if (!needLayout)
layoutButtons();
}
/// hide controls when scroll is not possible
protected void updateState() {
bool canScroll = _maxValue - _minValue > _pageSize;
if (canScroll) {
_indicator.visibility = Visibility.Visible;
_pageUp.visibility = Visibility.Visible;
_pageDown.visibility = Visibility.Visible;
} else {
_indicator.visibility = Visibility.Gone;
_pageUp.visibility = Visibility.Gone;
_pageDown.visibility = Visibility.Gone;
}
cancelLayout();
}
override void cancelLayout() {
_indicator.cancelLayout();
_pageUp.cancelLayout();
_pageDown.cancelLayout();
super.cancelLayout();
}
protected void layoutButtons() {
Rect irc = _scrollArea;
if (_orientation == Orientation.Vertical) {
// vertical
int spaceBackSize, spaceForwardSize, indicatorSize;
bool indicatorVisible = calcButtonSizes(_scrollArea.height, spaceBackSize, spaceForwardSize, indicatorSize);
irc.top += spaceBackSize;
irc.bottom -= spaceForwardSize;
layoutButtons(irc);
} else {
// horizontal
int spaceBackSize, spaceForwardSize, indicatorSize;
bool indicatorVisible = calcButtonSizes(_scrollArea.width, spaceBackSize, spaceForwardSize, indicatorSize);
irc.left += spaceBackSize;
irc.right -= spaceForwardSize;
layoutButtons(irc);
}
updateState();
cancelLayout();
}
protected void layoutButtons(Rect irc) {
Rect r;
_indicator.visibility = Visibility.Visible;
if (_orientation == Orientation.Vertical) {
_indicator.layout(irc);
if (_scrollArea.top < irc.top) {
r = _scrollArea;
r.bottom = irc.top;
_pageUp.layout(r);
_pageUp.visibility = Visibility.Visible;
} else {
_pageUp.visibility = Visibility.Invisible;
}
if (_scrollArea.bottom > irc.bottom) {
r = _scrollArea;
r.top = irc.bottom;
_pageDown.layout(r);
_pageDown.visibility = Visibility.Visible;
} else {
_pageDown.visibility = Visibility.Invisible;
}
} else {
_indicator.layout(irc);
if (_scrollArea.left < irc.left) {
r = _scrollArea;
r.right = irc.left;
_pageUp.layout(r);
_pageUp.visibility = Visibility.Visible;
} else {
_pageUp.visibility = Visibility.Invisible;
}
if (_scrollArea.right > irc.right) {
r = _scrollArea;
r.left = irc.right;
_pageDown.layout(r);
_pageDown.visibility = Visibility.Visible;
} else {
_pageDown.visibility = Visibility.Invisible;
}
}
}
override void layout(Rect rc) {
_needLayout = false;
applyMargins(rc);
applyPadding(rc);
Rect r;
if (_orientation == Orientation.Vertical) {
// vertical
// buttons
// indicator
r = rc;
_scrollArea = r;
} else {
// horizontal
// indicator
r = rc;
_scrollArea = r;
}
layoutButtons();
_pos = rc;
}
override bool onClick(Widget source) {
Log.d("Scrollbar.onClick ", source.id);
if (source.compareId("PAGE_UP"))
return sendScrollEvent(ScrollAction.PageUp, position);
if (source.compareId("PAGE_DOWN"))
return sendScrollEvent(ScrollAction.PageDown, position);
return true;
}
/// handle mouse wheel events
override bool onMouseEvent(MouseEvent event) {
if (visibility != Visibility.Visible)
return false;
if (event.action == MouseAction.Wheel) {
int delta = event.wheelDelta;
if (delta > 0)
sendScrollEvent(ScrollAction.LineUp, position);
else if (delta < 0)
sendScrollEvent(ScrollAction.LineDown, position);
return true;
}
return super.onMouseEvent(event);
}
/// Draw widget at its position to buffer
override void onDraw(DrawBuf buf) {
if (visibility != Visibility.Visible && !buf.isClippedOut(_pos))
return;
Rect rc = _pos;
applyMargins(rc);
auto saver = ClipRectSaver(buf, rc, alpha);
DrawableRef bg = backgroundDrawable;
if (!bg.isNull) {
Rect r = rc;
if (_orientation == Orientation.Vertical) {
int dw = bg.width;
r.left += (rc.width - dw)/2;
r.right = r.left + dw;
} else {
int dw = bg.height;
r.top += (rc.height - dw)/2;
r.bottom = r.top + dw;
}
bg.drawTo(buf, r, state);
}
applyPadding(rc);
if (state & State.Focused) {
rc.expand(FOCUS_RECT_PADDING, FOCUS_RECT_PADDING);
drawFocusRect(buf, rc);
}
_needDraw = false;
_pageUp.onDraw(buf);
_pageDown.onDraw(buf);
_indicator.onDraw(buf);
}
}
/// interface - slot for onClick
interface OnDrawHandler {

View File

@ -20,6 +20,7 @@ module dlangui.widgets.lists;
import dlangui.widgets.widget;
import dlangui.widgets.controls;
import dlangui.widgets.scrollbar;
import dlangui.widgets.layouts;
import dlangui.core.signals;

View File

@ -72,6 +72,7 @@ module dlangui.widgets.scroll;
import dlangui.widgets.widget;
import dlangui.widgets.controls;
import dlangui.widgets.scrollbar;
import std.conv;
/** Scroll bar visibility mode. */