mirror of https://github.com/buggins/dlangui.git
progress bar initial implementatino
This commit is contained in:
parent
f3a03a7378
commit
b4974cb177
|
@ -982,6 +982,7 @@
|
|||
<File path="src\dlangui\widgets\menu.d" />
|
||||
<File path="src\dlangui\widgets\metadata.d" />
|
||||
<File path="src\dlangui\widgets\popup.d" />
|
||||
<File path="src\dlangui\widgets\progressbar.d" />
|
||||
<File path="src\dlangui\widgets\scroll.d" />
|
||||
<File path="src\dlangui\widgets\scrollbar.d" />
|
||||
<File path="src\dlangui\widgets\srcedit.d" />
|
||||
|
|
|
@ -569,8 +569,11 @@ extern (C) int UIAppMain(string[] args) {
|
|||
|
||||
LinearLayout layout = new LinearLayout("tab1");
|
||||
|
||||
|
||||
layout.addChild((new TextWidget()).textColor(0x00802000).text("Text widget 0"));
|
||||
layout.addChild((new TextWidget()).textColor(0x40FF4000).text("Text widget"));
|
||||
layout.addChild(new ProgressBarWidget().progress(300).animationInterval(50));
|
||||
layout.addChild(new ProgressBarWidget().progress(-1).animationInterval(50));
|
||||
layout.addChild((new Button("BTN1")).textResource("EXIT")); //.textColor(0x40FF4000)
|
||||
layout.addChild(new TimerTest());
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ public {
|
|||
import dlangui.widgets.widget;
|
||||
import dlangui.widgets.controls;
|
||||
import dlangui.widgets.scrollbar;
|
||||
import dlangui.widgets.progressbar;
|
||||
import dlangui.widgets.layouts;
|
||||
import dlangui.widgets.groupbox;
|
||||
import dlangui.widgets.lists;
|
||||
|
|
|
@ -327,14 +327,17 @@ void registerStandardWidgets() {
|
|||
import dlangui.widgets.editors;
|
||||
import dlangui.widgets.grid;
|
||||
import dlangui.widgets.groupbox;
|
||||
import dlangui.widgets.progressbar;
|
||||
import dlangui.dialogs.filedlg;
|
||||
import dlangui.widgets.menu;
|
||||
mixin(registerWidgets!(FileNameEditLine, DirEditLine, //dlangui.dialogs.filedlg
|
||||
ComboBox, ComboEdit, //dlangui.widgets.combobox
|
||||
Widget, TextWidget, MultilineTextWidget, Button, ImageWidget, ImageButton, ImageCheckButton, ImageTextButton,
|
||||
SwitchButton, RadioButton, CheckBox, ScrollBar, SliderWidget, HSpacer, VSpacer, CanvasWidget, // dlangui.widgets.controls
|
||||
SwitchButton, RadioButton, CheckBox, HSpacer, VSpacer, CanvasWidget, // dlangui.widgets.controls
|
||||
ScrollBar, SliderWidget, // dlangui.widgets.scrollbar
|
||||
EditLine, EditBox, LogWidget,//dlangui.widgets.editors
|
||||
GroupBox, // dlangui.widgets.groupbox
|
||||
ProgressBarWidget, // dlangui.widgets.progressbar
|
||||
StringGridWidget, //dlangui.widgets.grid
|
||||
VerticalLayout, HorizontalLayout, TableLayout, FrameLayout, // dlangui.widgets.layouts
|
||||
ListWidget, StringListWidget,//dlangui.widgets.lists
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
// Written in the D programming language.
|
||||
|
||||
/**
|
||||
This module contains progress bar controls implementation.
|
||||
|
||||
ProgressBarWidget - progeress bar control
|
||||
|
||||
|
||||
Synopsis:
|
||||
|
||||
----
|
||||
import dlangui.widgets.progressbar;
|
||||
|
||||
----
|
||||
|
||||
Copyright: Vadim Lopatin, 2016
|
||||
License: Boost License 1.0
|
||||
Authors: Vadim Lopatin, coolreader.org@gmail.com
|
||||
*/
|
||||
module dlangui.widgets.progressbar;
|
||||
|
||||
import dlangui.widgets.widget;
|
||||
|
||||
enum PROGRESS_INDETERMINATE = -1;
|
||||
enum PROGRESS_HIDDEN = -2;
|
||||
enum PROGRESS_ANIMATION_OFF = 0;
|
||||
enum PROGRESS_MAX = 1000;
|
||||
|
||||
/// Base for different progress bar controls
|
||||
class AbstractProgressBar : Widget {
|
||||
this(string ID = null, int progress = PROGRESS_INDETERMINATE) {
|
||||
super(ID);
|
||||
_progress = progress;
|
||||
}
|
||||
|
||||
protected int _progress = PROGRESS_INDETERMINATE;
|
||||
|
||||
/// Set current progress value, 0 .. 1000; -1 == indeterminate, -2 == hidden
|
||||
@property AbstractProgressBar progress(int progress) {
|
||||
if (progress < -2)
|
||||
progress = -2;
|
||||
if (progress > 1000)
|
||||
progress = 1000;
|
||||
if (_progress != progress) {
|
||||
_progress = progress;
|
||||
invalidate();
|
||||
}
|
||||
requestLayout();
|
||||
return this;
|
||||
}
|
||||
/// Get current progress value, 0 .. 1000; -1 == indeterminate
|
||||
@property int progress() {
|
||||
return _progress;
|
||||
}
|
||||
/// returns true if progress bar is in indeterminate state
|
||||
@property bool indeterminate() { return _progress == PROGRESS_INDETERMINATE; }
|
||||
|
||||
protected int _animationInterval = 0; // no animation by default
|
||||
/// get animation interval in milliseconds, if 0 - no animation
|
||||
@property int animationInterval() { return _animationInterval; }
|
||||
/// set animation interval in milliseconds, if 0 - no animation
|
||||
@property AbstractProgressBar animationInterval(int animationIntervalMillis) {
|
||||
if (animationIntervalMillis < 0)
|
||||
animationIntervalMillis = 0;
|
||||
if (animationIntervalMillis > 5000)
|
||||
animationIntervalMillis = 5000;
|
||||
if (_animationInterval != animationIntervalMillis) {
|
||||
_animationInterval = animationIntervalMillis;
|
||||
if (!animationIntervalMillis)
|
||||
stopAnimation();
|
||||
else
|
||||
scheduleAnimation();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
protected ulong _animationTimerId;
|
||||
protected void scheduleAnimation() {
|
||||
if (!visible || !_animationInterval) {
|
||||
if (_animationTimerId)
|
||||
stopAnimation();
|
||||
return;
|
||||
}
|
||||
stopAnimation();
|
||||
_animationTimerId = setTimer(_animationInterval);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
protected void stopAnimation() {
|
||||
if (_animationTimerId) {
|
||||
cancelTimer(_animationTimerId);
|
||||
_animationTimerId = 0;
|
||||
}
|
||||
_lastAnimationTs = 0;
|
||||
}
|
||||
|
||||
protected int _animationSpeedPixelsPerSecond = 20;
|
||||
protected long _animationPhase;
|
||||
protected long _lastAnimationTs;
|
||||
/// called on animation timer
|
||||
protected void onAnimationTimer(long millisElapsed) {
|
||||
_animationPhase += millisElapsed;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/// handle timer; return true to repeat timer event after next interval, false cancel timer
|
||||
override bool onTimer(ulong id) {
|
||||
if (id == _animationTimerId) {
|
||||
if (!visible || _progress == PROGRESS_HIDDEN) {
|
||||
stopAnimation();
|
||||
return false;
|
||||
}
|
||||
long elapsed = 0;
|
||||
long ts = currentTimeMillis;
|
||||
if (_lastAnimationTs) {
|
||||
elapsed = ts - _lastAnimationTs;
|
||||
if (elapsed < 0)
|
||||
elapsed = 0;
|
||||
else if (elapsed > 5000)
|
||||
elapsed = 5000;
|
||||
}
|
||||
_lastAnimationTs = ts;
|
||||
onAnimationTimer(elapsed);
|
||||
return _animationInterval != 0;
|
||||
}
|
||||
// return true to repeat after the same interval, false to stop timer
|
||||
return super.onTimer(id);
|
||||
}
|
||||
}
|
||||
|
||||
/// Progress bar widget
|
||||
class ProgressBarWidget : AbstractProgressBar {
|
||||
this(string ID = null, int progress = PROGRESS_INDETERMINATE) {
|
||||
super(ID, progress);
|
||||
styleId = STYLE_PROGRESS_BAR;
|
||||
}
|
||||
|
||||
/**
|
||||
Measure widget according to desired width and height constraints. (Step 1 of two phase layout).
|
||||
|
||||
*/
|
||||
override void measure(int parentWidth, int parentHeight) {
|
||||
int h = 0;
|
||||
int w = 0;
|
||||
DrawableRef gaugeDrawable = style.customDrawable("progress_bar_gauge");
|
||||
DrawableRef indeterminateDrawable = style.customDrawable("progress_bar_indeterminate");
|
||||
if (!gaugeDrawable.isNull) {
|
||||
if (h < gaugeDrawable.height)
|
||||
h = gaugeDrawable.height;
|
||||
}
|
||||
if (!indeterminateDrawable.isNull) {
|
||||
if (h < indeterminateDrawable.height)
|
||||
h = indeterminateDrawable.height;
|
||||
}
|
||||
measuredContent(parentWidth, parentHeight, w, h);
|
||||
}
|
||||
|
||||
|
||||
/// Draw widget at its position to buffer
|
||||
override void onDraw(DrawBuf buf) {
|
||||
if (visibility != Visibility.Visible)
|
||||
return;
|
||||
super.onDraw(buf);
|
||||
Rect rc = _pos;
|
||||
applyMargins(rc);
|
||||
applyPadding(rc);
|
||||
DrawableRef animDrawable;
|
||||
if (_progress >= 0) {
|
||||
DrawableRef gaugeDrawable = style.customDrawable("progress_bar_gauge");
|
||||
animDrawable = style.customDrawable("progress_bar_gauge_animation");
|
||||
int x = rc.left + _progress * rc.width / PROGRESS_MAX;
|
||||
if (!gaugeDrawable.isNull) {
|
||||
gaugeDrawable.drawTo(buf, Rect(rc.left, rc.top, x, rc.bottom));
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
DrawableRef indeterminateDrawable = style.customDrawable("progress_bar_indeterminate");
|
||||
if (!indeterminateDrawable.isNull) {
|
||||
indeterminateDrawable.drawTo(buf, rc);
|
||||
}
|
||||
animDrawable = style.customDrawable("progress_bar_indeterminate_animation");
|
||||
}
|
||||
if (!animDrawable.isNull && _animationInterval) {
|
||||
if (!_animationTimerId)
|
||||
scheduleAnimation();
|
||||
int w = animDrawable.width;
|
||||
_animationPhase %= w * 1000;
|
||||
animDrawable.drawTo(buf, rc, 0, cast(int)(_animationPhase * _animationSpeedPixelsPerSecond / 1000), 0);
|
||||
Log.d("progress animation draw ", _animationPhase, " rc=", rc);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,995 @@
|
|||
// Written in the D programming language.
|
||||
|
||||
/**
|
||||
This module contains simple scrollbar-like controls implementation.
|
||||
|
||||
ScrollBar - scrollbar control
|
||||
|
||||
SliderWidget - slider control
|
||||
|
||||
|
||||
|
||||
Synopsis:
|
||||
|
||||
----
|
||||
import dlangui.widgets.scrollbar;
|
||||
|
||||
----
|
||||
|
||||
Copyright: Vadim Lopatin, 2014
|
||||
License: Boost License 1.0
|
||||
Authors: Vadim Lopatin, coolreader.org@gmail.com
|
||||
*/
|
||||
module dlangui.widgets.scrollbar;
|
||||
|
||||
|
||||
import dlangui.widgets.widget;
|
||||
import dlangui.widgets.layouts;
|
||||
import dlangui.widgets.controls;
|
||||
import dlangui.core.events;
|
||||
import dlangui.core.stdaction;
|
||||
|
||||
private import std.algorithm;
|
||||
private import std.conv : to;
|
||||
private import std.utf : toUTF32;
|
||||
|
||||
/// 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -119,6 +119,8 @@ immutable string STYLE_TRANSPARENT_BUTTON_BACKGROUND = "TRANSPARENT_BUTTON_BACKG
|
|||
immutable string STYLE_GROUP_BOX = "GROUP_BOX";
|
||||
/// standard style id for GroupBox caption
|
||||
immutable string STYLE_GROUP_BOX_CAPTION = "GROUP_BOX_CAPTION";
|
||||
/// standard style id for ProgressBarWidget caption
|
||||
immutable string STYLE_PROGRESS_BAR = "PROGRESS_BAR";
|
||||
|
||||
/// standard style id for tree item
|
||||
immutable string STYLE_TREE_ITEM = "TREE_ITEM";
|
||||
|
|
|
@ -1143,12 +1143,15 @@ public:
|
|||
|
||||
/// set new timer to call onTimer() after specified interval (for recurred notifications, return true from onTimer)
|
||||
ulong setTimer(long intervalMillis) {
|
||||
return window.setTimer(this, intervalMillis);
|
||||
if (auto w = window)
|
||||
return w.setTimer(this, intervalMillis);
|
||||
return 0; // no window - no timer
|
||||
}
|
||||
|
||||
/// cancel timer - pass value returned from setTimer() as timerId parameter
|
||||
void cancelTimer(ulong timerId) {
|
||||
window.cancelTimer(timerId);
|
||||
if (auto w = window)
|
||||
w.cancelTimer(timerId);
|
||||
}
|
||||
|
||||
/// handle timer; return true to repeat timer event after next interval, false cancel timer
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
|
@ -505,5 +505,17 @@
|
|||
padding="1pt,1pt,1pt,1pt">
|
||||
</style>
|
||||
|
||||
<style id="PROGRESS_BAR"
|
||||
padding="2pt,2pt,2pt,2pt"
|
||||
minWidth="50pt"
|
||||
minHeight="10pt"
|
||||
backgroundColor="#D0D0D0"
|
||||
padding="1pt,1pt,1pt,1pt">
|
||||
<drawable id="progress_bar_gauge" value="#0000FF"/>
|
||||
<drawable id="progress_bar_gauge_animation" value="progress_bar_gauge_animation.tiled"/>
|
||||
<drawable id="progress_bar_indeterminate" value="#8080C0"/>
|
||||
<drawable id="progress_bar_indeterminate_animation" value="progress_bar_gauge_animation.tiled"/>
|
||||
</style>
|
||||
|
||||
</theme>
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ res/group_box_frame_bottom_dark.9.png
|
|||
res/group_box_frame_up_left_dark.9.png
|
||||
res/group_box_frame_up_right_dark.9.png
|
||||
res/slider_background_dark.9.png
|
||||
res/progress_bar_gauge_animation.png
|
||||
res/i18n/std_en.ini
|
||||
res/i18n/std_ru.ini
|
||||
res/list_item_background.xml
|
||||
|
|
Loading…
Reference in New Issue