mirror of https://github.com/buggins/dlangui.git
Hover, scrollbars
This commit is contained in:
parent
4187da1a2d
commit
03a0844a9f
|
|
@ -63,10 +63,17 @@ extern (C) int UIAppMain(string[] args) {
|
|||
hlayout.backgroundColor = 0x8080C0;
|
||||
layout.addChild(hlayout);
|
||||
|
||||
LinearLayout vlayoutgroup = new HorizontalLayout();
|
||||
LinearLayout vlayout = new VerticalLayout();
|
||||
vlayout.addChild((new TextWidget()).text("VLayout line 1").textColor(0x40FF4000)); //
|
||||
vlayout.addChild((new TextWidget()).text("VLayout line 2").textColor(0x40FFFF00));
|
||||
layout.addChild(vlayout);
|
||||
vlayout.addChild((new TextWidget()).text("VLayout line 2").textColor(0x40FF8000));
|
||||
vlayout.addChild((new TextWidget()).text("VLayout line 2").textColor(0x40008000));
|
||||
vlayout.layoutWidth(FILL_PARENT);
|
||||
vlayoutgroup.addChild(vlayout);
|
||||
vlayoutgroup.layoutWidth(FILL_PARENT);
|
||||
ScrollBar vsb = new ScrollBar("vscroll", Orientation.Vertical);
|
||||
vlayoutgroup.addChild(vsb);
|
||||
layout.addChild(vlayoutgroup);
|
||||
|
||||
ScrollBar sb = new ScrollBar("hscroll", Orientation.Horizontal);
|
||||
layout.addChild(sb.layoutHeight(WRAP_CONTENT).layoutWidth(FILL_PARENT));
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 670 B After Width: | Height: | Size: 716 B |
|
|
@ -7,9 +7,10 @@ enum MouseAction : ubyte {
|
|||
ButtonDown, // button is down
|
||||
ButtonUp, // button is up
|
||||
Move, // mouse pointer is moving
|
||||
FocusIn, // pointer moved outside of widget while button was down
|
||||
FocusOut, // pointer is back inside widget while button is down after FocusIn
|
||||
FocusIn, // pointer is back inside widget while button is down after FocusOut
|
||||
FocusOut, // pointer moved outside of widget while button was down (if handler returns true, Move events will be sent even while pointer is outside widget)
|
||||
Wheel, // scroll wheel movement
|
||||
//Hover, // pointer entered widget which while button was not down (return true to track Hover state)
|
||||
Leave // pointer left widget which has before processed Move message, while button was not down
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ class Window {
|
|||
protected Widget _mouseCaptureWidget;
|
||||
protected ushort _mouseCaptureButtons;
|
||||
protected bool _mouseCaptureFocusedOut;
|
||||
protected bool _mouseCaptureFocusedOutTrackMovements;
|
||||
|
||||
protected bool dispatchCancel(MouseEvent event) {
|
||||
event.changeAction(MouseAction.Cancel);
|
||||
|
|
@ -157,6 +158,9 @@ class Window {
|
|||
event.changeAction(MouseAction.FocusOut);
|
||||
_mouseCaptureFocusedOut = true;
|
||||
_mouseCaptureButtons = event.flags & (MouseFlag.LButton|MouseFlag.RButton|MouseFlag.MButton);
|
||||
_mouseCaptureFocusedOutTrackMovements = _mouseCaptureWidget.onMouseEvent(event);
|
||||
return true;
|
||||
} else if (_mouseCaptureFocusedOutTrackMovements) {
|
||||
return _mouseCaptureWidget.onMouseEvent(event);
|
||||
}
|
||||
return true;
|
||||
|
|
@ -189,27 +193,35 @@ class Window {
|
|||
}
|
||||
return res;
|
||||
}
|
||||
bool processed = false;
|
||||
if (event.action == MouseAction.Move && _mouseTrackingWidget !is null) {
|
||||
if (!_mouseTrackingWidget.isPointInside(event.x, event.y)) {
|
||||
// send Leave message
|
||||
MouseEvent leaveEvent = new MouseEvent(event);
|
||||
leaveEvent.changeAction(MouseAction.Leave);
|
||||
_mouseCaptureWidget.onMouseEvent(event);
|
||||
_mouseTrackingWidget.onMouseEvent(leaveEvent);
|
||||
// stop tracking
|
||||
_mouseTrackingWidget = null;
|
||||
processed = true;
|
||||
}
|
||||
}
|
||||
if (!res) {
|
||||
res = dispatchMouseEvent(_mainWidget, event);
|
||||
}
|
||||
return res;
|
||||
return res || processed;
|
||||
}
|
||||
|
||||
/// checks content widgets for necessary redraw and/or layout
|
||||
protected void checkUpdateNeeded(Widget root, ref bool needDraw, ref bool needLayout, ref bool animationActive) {
|
||||
if (!root.visibility == Visibility.Visible)
|
||||
return;
|
||||
needDraw = root.needDraw || needDraw;
|
||||
needLayout = root.needLayout || needLayout;
|
||||
if (!needLayout) {
|
||||
needLayout = root.needLayout || needLayout;
|
||||
if (needLayout) {
|
||||
Log.d("need layout: ", root.id);
|
||||
}
|
||||
}
|
||||
animationActive = root.animating || animationActive;
|
||||
for (int i = 0; i < root.childCount; i++)
|
||||
checkUpdateNeeded(root.child(i), needDraw, needLayout, animationActive);
|
||||
|
|
|
|||
|
|
@ -201,7 +201,6 @@ class Win32Window : Window {
|
|||
|
||||
version (USE_OPENGL) {
|
||||
private void paintUsingOpenGL() {
|
||||
Log.d("paintUsingOpenGL()");
|
||||
// hack to stop infinite WM_PAINT loop
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc2 = BeginPaint(_hwnd, &ps);
|
||||
|
|
@ -223,11 +222,9 @@ class Win32Window : Window {
|
|||
float r = ((_backgroundColor >> 16) & 255) / 255.0f;
|
||||
float g = ((_backgroundColor >> 8) & 255) / 255.0f;
|
||||
float b = ((_backgroundColor >> 0) & 255) / 255.0f;
|
||||
Log.d("paintUsingOpenGL() - clearing buffer");
|
||||
glClearColor(r, g, b, a);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
Log.d("paintUsingOpenGL() - creating drawbuf");
|
||||
GLDrawBuf buf = new GLDrawBuf(_dx, _dy, false);
|
||||
buf.beforeDrawing();
|
||||
static if (false) {
|
||||
|
|
@ -244,9 +241,7 @@ class Win32Window : Window {
|
|||
} else {
|
||||
onDraw(buf);
|
||||
}
|
||||
Log.d("paintUsingOpenGL() - calling buf.afterDrawing");
|
||||
buf.afterDrawing();
|
||||
Log.d("onPaint() end drawing opengl");
|
||||
SwapBuffers(hdc);
|
||||
wglMakeCurrent(hdc, null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ class ImageButton : ImageWidget {
|
|||
super(ID);
|
||||
styleId = "BUTTON";
|
||||
_drawableId = drawableId;
|
||||
trackHover = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -127,6 +128,7 @@ class Button : Widget {
|
|||
this(string ID = null) {
|
||||
super(ID);
|
||||
styleId = "BUTTON";
|
||||
trackHover = true;
|
||||
}
|
||||
|
||||
override void measure(int parentWidth, int parentHeight) {
|
||||
|
|
@ -169,6 +171,7 @@ class ScrollBar : WidgetGroup, OnClickHandler {
|
|||
this(string ID) {
|
||||
super(ID);
|
||||
styleId = "PAGE_SCROLL";
|
||||
trackHover = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -177,8 +180,10 @@ class ScrollBar : WidgetGroup, OnClickHandler {
|
|||
int _dragStartPosition;
|
||||
bool _dragging;
|
||||
Rect _dragStartRect;
|
||||
|
||||
this(string resourceId) {
|
||||
super("SLIDER", resourceId);
|
||||
trackHover = true;
|
||||
}
|
||||
|
||||
/// process mouse event; return true if event is processed by widget.
|
||||
|
|
@ -193,6 +198,9 @@ class ScrollBar : WidgetGroup, OnClickHandler {
|
|||
_dragStartRect = _pos;
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.FocusOut && _dragging) {
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.Move && _dragging) {
|
||||
int delta = _orientation == Orientation.Vertical ? event.y - _dragStart.y : event.x - _dragStart.x;
|
||||
Rect rc = _dragStartRect;
|
||||
|
|
@ -205,7 +213,7 @@ class ScrollBar : WidgetGroup, OnClickHandler {
|
|||
rc.top = _scrollArea.top;
|
||||
rc.bottom = _scrollArea.top + _dragStartRect.height;
|
||||
} else if (rc.bottom > _scrollArea.bottom) {
|
||||
rc.top = _scrollArea.top - _dragStartRect.height;
|
||||
rc.top = _scrollArea.bottom - _dragStartRect.height;
|
||||
rc.bottom = _scrollArea.bottom;
|
||||
}
|
||||
offset = rc.top - _scrollArea.top;
|
||||
|
|
@ -223,7 +231,8 @@ class ScrollBar : WidgetGroup, OnClickHandler {
|
|||
offset = rc.left - _scrollArea.left;
|
||||
space = _scrollArea.width - rc.width;
|
||||
}
|
||||
_pos = rc;
|
||||
layoutButtons(rc);
|
||||
//_pos = rc;
|
||||
int position = space > 0 ? _minValue + offset * (_maxValue - _minValue - _pageSize) / space : 0;
|
||||
invalidate();
|
||||
onIndicatorDragging(_dragStartPosition, position);
|
||||
|
|
@ -237,6 +246,18 @@ class ScrollBar : WidgetGroup, OnClickHandler {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.Move && trackHover) {
|
||||
if (!(state & State.Hover)) {
|
||||
Log.d("Hover ", id);
|
||||
setState(State.Hover);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if ((event.action == MouseAction.Leave || event.action == MouseAction.Cancel) && trackHover) {
|
||||
Log.d("Leave ", id);
|
||||
resetState(State.Hover);
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.Cancel) {
|
||||
Log.d("SliderButton.onMouseEvent event.action == MouseAction.Cancel");
|
||||
resetState(State.Pressed);
|
||||
|
|
@ -347,6 +368,47 @@ class ScrollBar : WidgetGroup, OnClickHandler {
|
|||
measuredContent(parentWidth, parentHeight, sz.x, sz.y);
|
||||
}
|
||||
|
||||
protected void layoutButtons(Rect irc) {
|
||||
Rect r;
|
||||
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) {
|
||||
applyMargins(rc);
|
||||
applyPadding(rc);
|
||||
|
|
@ -372,23 +434,7 @@ class ScrollBar : WidgetGroup, OnClickHandler {
|
|||
Rect irc = r;
|
||||
irc.top += spaceBackSize;
|
||||
irc.bottom -= spaceForwardSize;
|
||||
_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;
|
||||
}
|
||||
layoutButtons(irc);
|
||||
} else {
|
||||
// horizontal
|
||||
int backbtnpos = rc.left + _btnSize;
|
||||
|
|
@ -409,23 +455,7 @@ class ScrollBar : WidgetGroup, OnClickHandler {
|
|||
Rect irc = r;
|
||||
irc.left += spaceBackSize;
|
||||
irc.right -= spaceForwardSize;
|
||||
_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;
|
||||
}
|
||||
layoutButtons(irc);
|
||||
}
|
||||
_pos = rc;
|
||||
_needLayout = false;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ enum State : uint {
|
|||
Pressed = 1,
|
||||
Focused = 2,
|
||||
Disabled = 4,
|
||||
Hover = 8, // mouse pointer is over control, buttons not pressed
|
||||
}
|
||||
|
||||
enum Align : ubyte {
|
||||
|
|
@ -77,7 +78,7 @@ class Style {
|
|||
protected FontFamily _fontFamily = FontFamily.Unspecified;
|
||||
protected ushort _fontSize = FONT_SIZE_UNSPECIFIED;
|
||||
protected ushort _fontWeight = FONT_WEIGHT_UNSPECIFIED;
|
||||
protected uint _backgroundColor = COLOR_TRANSPARENT;
|
||||
protected uint _backgroundColor = COLOR_UNSPECIFIED;
|
||||
protected uint _textColor = COLOR_UNSPECIFIED;
|
||||
protected string _fontFace;
|
||||
protected string _backgroundImageId;
|
||||
|
|
@ -621,6 +622,7 @@ Theme createDefaultTheme() {
|
|||
button.createState(State.Disabled, State.Disabled).backgroundImageId("btn_default_small_normal_disable");
|
||||
button.createState(State.Pressed, State.Pressed).backgroundImageId("btn_default_small_pressed");
|
||||
button.createState(State.Focused, State.Focused).backgroundImageId("btn_default_small_selected");
|
||||
button.createState(State.Hover, State.Hover).backgroundImageId("btn_default_small_normal_hover");
|
||||
res.setCustomDrawable(ATTR_SCROLLBAR_BUTTON_UP, "scrollbar_btn_up");
|
||||
res.setCustomDrawable(ATTR_SCROLLBAR_BUTTON_DOWN, "scrollbar_btn_down");
|
||||
res.setCustomDrawable(ATTR_SCROLLBAR_BUTTON_LEFT, "scrollbar_btn_left");
|
||||
|
|
@ -629,11 +631,12 @@ Theme createDefaultTheme() {
|
|||
res.setCustomDrawable(ATTR_SCROLLBAR_INDICATOR_HORIZONTAL, "scrollbar_indicator_horizontal");
|
||||
|
||||
Style scrollbar = res.createSubstyle("SCROLLBAR");
|
||||
scrollbar.backgroundColor(0xC0808080);
|
||||
Style scrollbarButton = button.createSubstyle("SCROLLBAR_BUTTON");
|
||||
scrollbar.backgroundColor(0xC0C0C0C0);
|
||||
Style scrollbarSlider = res.createSubstyle("SLIDER");
|
||||
Style scrollbarPage = res.createSubstyle("PAGE_SCROLL").backgroundColor(0xFFFFFFFF); // transparent
|
||||
scrollbarPage.createState(State.Pressed, State.Pressed).backgroundColor(0xC0404040);
|
||||
Style scrollbarPage = res.createSubstyle("PAGE_SCROLL").backgroundColor(0xFFFFFFFF);
|
||||
scrollbarPage.createState(State.Pressed, State.Pressed).backgroundColor(0xC0404080);
|
||||
scrollbarPage.createState(State.Hover, State.Hover).backgroundColor(0xF0404080);
|
||||
|
||||
//res.dumpStats();
|
||||
return res;
|
||||
|
|
|
|||
|
|
@ -67,6 +67,14 @@ class Widget {
|
|||
/// window (to be used for top level widgets only!)
|
||||
protected Window _window;
|
||||
|
||||
/// does widget need to track mouse Hover
|
||||
protected bool _trackHover;
|
||||
|
||||
/// mouse movement processing flag (when true, widget will change Hover state while mouse is moving)
|
||||
@property bool trackHover() const { return _trackHover; }
|
||||
/// set new trackHover flag value (when true, widget will change Hover state while mouse is moving)
|
||||
@property Widget trackHover(bool v) { _trackHover = v; return this; }
|
||||
|
||||
//private static int _instanceCount = 0;
|
||||
/// create widget, with optional id
|
||||
this(string ID = null) {
|
||||
|
|
@ -277,8 +285,11 @@ class Widget {
|
|||
@property Visibility visibility() { return _visibility; }
|
||||
/// sets widget visibility (Visible, Invisible, Gone)
|
||||
@property Widget visibility(Visibility visible) {
|
||||
_visibility = visible;
|
||||
requestLayout();
|
||||
if (_visibility != visible) {
|
||||
if ((_visibility == Visibility.Gone) || (visible == Visibility.Gone))
|
||||
_visibility = visible;
|
||||
requestLayout();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -305,12 +316,25 @@ class Widget {
|
|||
}
|
||||
if (event.action == MouseAction.FocusOut || event.action == MouseAction.Cancel) {
|
||||
resetState(State.Pressed);
|
||||
resetState(State.Hover);
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.FocusIn) {
|
||||
setState(State.Pressed);
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.Move && trackHover) {
|
||||
if (!(state & State.Hover)) {
|
||||
Log.d("Hover ", id);
|
||||
setState(State.Hover);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.Leave && trackHover) {
|
||||
Log.d("Leave ", id);
|
||||
resetState(State.Hover);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue