mirror of https://github.com/adamdruppe/arsd.git
scrollbars omg
This commit is contained in:
parent
abb98b54df
commit
a45a344525
346
minigui.d
346
minigui.d
|
@ -1862,6 +1862,7 @@ enum ScrollBarShowPolicy {
|
|||
|
||||
/++
|
||||
FIXME ScrollBarShowPolicy
|
||||
FIXME: use the ScrollMessageWidget in here now that it exists
|
||||
+/
|
||||
class ScrollableWidget : Widget {
|
||||
// FIXME: make line size configurable
|
||||
|
@ -2291,13 +2292,53 @@ private class ScrollableContainerWidget : Widget {
|
|||
horizontalScrollBar.showing_ = false;
|
||||
verticalScrollBar.showing_ = false;
|
||||
|
||||
horizontalScrollBar.addEventListener(EventType.change, () {
|
||||
horizontalScrollBar.addEventListener("scrolltonextline", {
|
||||
horizontalScrollBar.setPosition(horizontalScrollBar.position + 1);
|
||||
sw.horizontalScrollTo(horizontalScrollBar.position);
|
||||
});
|
||||
verticalScrollBar.addEventListener(EventType.change, () {
|
||||
horizontalScrollBar.addEventListener("scrolltopreviousline", {
|
||||
horizontalScrollBar.setPosition(horizontalScrollBar.position - 1);
|
||||
sw.horizontalScrollTo(horizontalScrollBar.position);
|
||||
});
|
||||
verticalScrollBar.addEventListener("scrolltonextline", {
|
||||
verticalScrollBar.setPosition(verticalScrollBar.position + 1);
|
||||
sw.verticalScrollTo(verticalScrollBar.position);
|
||||
});
|
||||
|
||||
verticalScrollBar.addEventListener("scrolltopreviousline", {
|
||||
verticalScrollBar.setPosition(verticalScrollBar.position - 1);
|
||||
sw.verticalScrollTo(verticalScrollBar.position);
|
||||
});
|
||||
horizontalScrollBar.addEventListener("scrolltonextpage", {
|
||||
horizontalScrollBar.setPosition(horizontalScrollBar.position + horizontalScrollBar.step_);
|
||||
sw.horizontalScrollTo(horizontalScrollBar.position);
|
||||
});
|
||||
horizontalScrollBar.addEventListener("scrolltopreviouspage", {
|
||||
horizontalScrollBar.setPosition(horizontalScrollBar.position - horizontalScrollBar.step_);
|
||||
sw.horizontalScrollTo(horizontalScrollBar.position);
|
||||
});
|
||||
verticalScrollBar.addEventListener("scrolltonextpage", {
|
||||
verticalScrollBar.setPosition(verticalScrollBar.position + verticalScrollBar.step_);
|
||||
sw.verticalScrollTo(verticalScrollBar.position);
|
||||
});
|
||||
verticalScrollBar.addEventListener("scrolltopreviouspage", {
|
||||
verticalScrollBar.setPosition(verticalScrollBar.position - verticalScrollBar.step_);
|
||||
sw.verticalScrollTo(verticalScrollBar.position);
|
||||
});
|
||||
horizontalScrollBar.addEventListener("scrolltoposition", (Event event) {
|
||||
horizontalScrollBar.setPosition(event.intValue);
|
||||
sw.horizontalScrollTo(horizontalScrollBar.position);
|
||||
});
|
||||
verticalScrollBar.addEventListener("scrolltoposition", (Event event) {
|
||||
verticalScrollBar.setPosition(event.intValue);
|
||||
sw.verticalScrollTo(verticalScrollBar.position);
|
||||
});
|
||||
horizontalScrollBar.addEventListener("scrolltrack", (Event event) {
|
||||
horizontalScrollBar.setPosition(event.intValue);
|
||||
sw.horizontalScrollTo(horizontalScrollBar.position);
|
||||
});
|
||||
verticalScrollBar.addEventListener("scrolltrack", (Event event) {
|
||||
verticalScrollBar.setPosition(event.intValue);
|
||||
});
|
||||
|
||||
super(parent);
|
||||
}
|
||||
|
@ -2402,10 +2443,14 @@ abstract class ScrollbarBase : Widget {
|
|||
///
|
||||
void setViewableArea(int a) {
|
||||
viewableArea_ = a;
|
||||
version(custom_widgets)
|
||||
redraw();
|
||||
}
|
||||
///
|
||||
void setMax(int a) {
|
||||
max_ = a;
|
||||
version(custom_widgets)
|
||||
redraw();
|
||||
}
|
||||
///
|
||||
int max() {
|
||||
|
@ -2413,7 +2458,15 @@ abstract class ScrollbarBase : Widget {
|
|||
}
|
||||
///
|
||||
void setPosition(int a) {
|
||||
if(a == int.max)
|
||||
a = max;
|
||||
position_ = max ? a : 0;
|
||||
if(position_ + viewableArea_ > max)
|
||||
position_ = max - viewableArea_;
|
||||
if(position_ < 0)
|
||||
position_ = 0;
|
||||
version(custom_widgets)
|
||||
redraw();
|
||||
}
|
||||
///
|
||||
int position() {
|
||||
|
@ -2428,6 +2481,7 @@ abstract class ScrollbarBase : Widget {
|
|||
return step_;
|
||||
}
|
||||
|
||||
// FIXME: remove this.... maybe
|
||||
protected void informProgramThatUserChangedPosition(int n) {
|
||||
position_ = n;
|
||||
auto evt = new Event(EventType.change, this);
|
||||
|
@ -2561,6 +2615,8 @@ class MouseTrackingWidget : Widget {
|
|||
redraw();
|
||||
});
|
||||
|
||||
int lpx, lpy;
|
||||
|
||||
addEventListener(EventType.mousemove, (Event event) {
|
||||
auto oh = hovering;
|
||||
if(event.clientX >= positionX && event.clientX < positionX + thumbWidth && event.clientY >= positionY && event.clientY < positionY + thumbHeight) {
|
||||
|
@ -2589,8 +2645,13 @@ class MouseTrackingWidget : Widget {
|
|||
if(positionY < 0)
|
||||
positionY = 0;
|
||||
|
||||
auto evt = new Event(EventType.change, this);
|
||||
evt.sendDirectly();
|
||||
if(positionX != lpx || positionY != lpy) {
|
||||
auto evt = new Event(EventType.change, this);
|
||||
evt.sendDirectly();
|
||||
|
||||
lpx = positionX;
|
||||
lpy = positionY;
|
||||
}
|
||||
|
||||
redraw();
|
||||
});
|
||||
|
@ -2608,8 +2669,8 @@ class MouseTrackingWidget : Widget {
|
|||
}
|
||||
}
|
||||
|
||||
version(custom_widgets)
|
||||
private
|
||||
//version(custom_widgets)
|
||||
//private
|
||||
class HorizontalScrollbar : ScrollbarBase {
|
||||
|
||||
version(custom_widgets) {
|
||||
|
@ -2644,6 +2705,10 @@ class HorizontalScrollbar : ScrollbarBase {
|
|||
info.nMax = max;
|
||||
info.fMask = SIF_RANGE;
|
||||
SetScrollInfo(hwnd, SB_CTL, &info, true);
|
||||
} else version(custom_widgets) {
|
||||
thumb.positionX = thumbPosition;
|
||||
thumb.thumbWidth = thumbSize;
|
||||
thumb.redraw();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2676,11 +2741,19 @@ class HorizontalScrollbar : ScrollbarBase {
|
|||
auto rightButton = new ArrowButton(ArrowDirection.right, vl);
|
||||
rightButton.setClickRepeat(scrollClickRepeatInterval);
|
||||
|
||||
leftButton.tabStop = false;
|
||||
rightButton.tabStop = false;
|
||||
thumb.tabStop = false;
|
||||
|
||||
leftButton.addEventListener(EventType.triggered, () {
|
||||
informProgramThatUserChangedPosition(position - step());
|
||||
auto ev = new Event("scrolltopreviousline", this);
|
||||
ev.dispatch();
|
||||
//informProgramThatUserChangedPosition(position - step());
|
||||
});
|
||||
rightButton.addEventListener(EventType.triggered, () {
|
||||
informProgramThatUserChangedPosition(position + step());
|
||||
auto ev = new Event("scrolltonextline", this);
|
||||
ev.dispatch();
|
||||
//informProgramThatUserChangedPosition(position + step());
|
||||
});
|
||||
|
||||
thumb.thumbWidth = this.minWidth;
|
||||
|
@ -2688,7 +2761,11 @@ class HorizontalScrollbar : ScrollbarBase {
|
|||
|
||||
thumb.addEventListener(EventType.change, () {
|
||||
auto sx = thumb.positionX * max() / thumb.width;
|
||||
informProgramThatUserChangedPosition(sx);
|
||||
//informProgramThatUserChangedPosition(sx);
|
||||
|
||||
auto ev = new Event("scrolltoposition", this);
|
||||
ev.intValue = sx;
|
||||
ev.dispatch();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2698,8 +2775,8 @@ class HorizontalScrollbar : ScrollbarBase {
|
|||
override int minWidth() { return 48; }
|
||||
}
|
||||
|
||||
version(custom_widgets)
|
||||
private
|
||||
//version(custom_widgets)
|
||||
//private
|
||||
class VerticalScrollbar : ScrollbarBase {
|
||||
|
||||
version(custom_widgets) {
|
||||
|
@ -2734,6 +2811,10 @@ class VerticalScrollbar : ScrollbarBase {
|
|||
info.nMax = max;
|
||||
info.fMask = SIF_RANGE;
|
||||
SetScrollInfo(hwnd, SB_CTL, &info, true);
|
||||
} else version(custom_widgets) {
|
||||
thumb.positionY = thumbPosition;
|
||||
thumb.thumbHeight = thumbSize;
|
||||
thumb.redraw();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2767,10 +2848,14 @@ class VerticalScrollbar : ScrollbarBase {
|
|||
downButton.setClickRepeat(scrollClickRepeatInterval);
|
||||
|
||||
upButton.addEventListener(EventType.triggered, () {
|
||||
informProgramThatUserChangedPosition(position - step());
|
||||
auto ev = new Event("scrolltopreviousline", this);
|
||||
ev.dispatch();
|
||||
//informProgramThatUserChangedPosition(position - step());
|
||||
});
|
||||
downButton.addEventListener(EventType.triggered, () {
|
||||
informProgramThatUserChangedPosition(position + step());
|
||||
auto ev = new Event("scrolltonextline", this);
|
||||
ev.dispatch();
|
||||
//informProgramThatUserChangedPosition(position + step());
|
||||
});
|
||||
|
||||
thumb.thumbWidth = this.minWidth;
|
||||
|
@ -2779,8 +2864,16 @@ class VerticalScrollbar : ScrollbarBase {
|
|||
thumb.addEventListener(EventType.change, () {
|
||||
auto sy = thumb.positionY * max() / thumb.height;
|
||||
|
||||
informProgramThatUserChangedPosition(sy);
|
||||
auto ev = new Event("scrolltoposition", this);
|
||||
ev.intValue = sy;
|
||||
ev.dispatch();
|
||||
|
||||
//informProgramThatUserChangedPosition(sy);
|
||||
});
|
||||
|
||||
upButton.tabStop = false;
|
||||
downButton.tabStop = false;
|
||||
thumb.tabStop = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3302,6 +3395,138 @@ class HorizontalLayout : Layout {
|
|||
|
||||
}
|
||||
|
||||
/++
|
||||
A widget that takes your widget, puts scroll bars around it, and sends
|
||||
messages to it when the user scrolls. Unlike [ScrollableWidget], it makes
|
||||
no effort to automatically scroll or clip its child widgets - it just sends
|
||||
the messages.
|
||||
+/
|
||||
class ScrollMessageWidget : Widget {
|
||||
this(Widget parent = null) {
|
||||
super(parent);
|
||||
|
||||
container = new Widget(this);
|
||||
hsb = new HorizontalScrollbar(this);
|
||||
vsb = new VerticalScrollbar(this);
|
||||
|
||||
hsb.addEventListener("scrolltonextline", {
|
||||
hsb.setPosition(hsb.position + 1);
|
||||
notify();
|
||||
});
|
||||
hsb.addEventListener("scrolltopreviousline", {
|
||||
hsb.setPosition(hsb.position - 1);
|
||||
notify();
|
||||
});
|
||||
vsb.addEventListener("scrolltonextline", {
|
||||
vsb.setPosition(vsb.position + 1);
|
||||
notify();
|
||||
});
|
||||
vsb.addEventListener("scrolltopreviousline", {
|
||||
vsb.setPosition(vsb.position - 1);
|
||||
notify();
|
||||
});
|
||||
hsb.addEventListener("scrolltonextpage", {
|
||||
hsb.setPosition(hsb.position + hsb.step_);
|
||||
notify();
|
||||
});
|
||||
hsb.addEventListener("scrolltopreviouspage", {
|
||||
hsb.setPosition(hsb.position - hsb.step_);
|
||||
notify();
|
||||
});
|
||||
vsb.addEventListener("scrolltonextpage", {
|
||||
vsb.setPosition(vsb.position + vsb.step_);
|
||||
notify();
|
||||
});
|
||||
vsb.addEventListener("scrolltopreviouspage", {
|
||||
vsb.setPosition(vsb.position - vsb.step_);
|
||||
notify();
|
||||
});
|
||||
hsb.addEventListener("scrolltoposition", (Event event) {
|
||||
hsb.setPosition(event.intValue);
|
||||
notify();
|
||||
});
|
||||
vsb.addEventListener("scrolltoposition", (Event event) {
|
||||
vsb.setPosition(event.intValue);
|
||||
notify();
|
||||
});
|
||||
|
||||
|
||||
tabStop = false;
|
||||
container.tabStop = false;
|
||||
magic = true;
|
||||
}
|
||||
|
||||
void notify() {
|
||||
auto event = new Event("scroll", this);
|
||||
event.dispatch();
|
||||
}
|
||||
|
||||
///
|
||||
Point position() {
|
||||
return Point(hsb.position, vsb.position);
|
||||
}
|
||||
|
||||
///
|
||||
void setPosition(int x, int y) {
|
||||
hsb.setPosition(x);
|
||||
vsb.setPosition(y);
|
||||
}
|
||||
|
||||
///
|
||||
void setPageSize(int unitsX, int unitsY) {
|
||||
hsb.setStep(unitsX);
|
||||
vsb.setStep(unitsY);
|
||||
}
|
||||
|
||||
///
|
||||
void setTotalArea(int width, int height) {
|
||||
hsb.setMax(width);
|
||||
vsb.setMax(height);
|
||||
}
|
||||
|
||||
///
|
||||
void setViewableArea(int width, int height) {
|
||||
hsb.setViewableArea(width);
|
||||
vsb.setViewableArea(height);
|
||||
}
|
||||
|
||||
private bool magic;
|
||||
override void addChild(Widget w, int position = int.max) {
|
||||
if(magic)
|
||||
container.addChild(w, position);
|
||||
else
|
||||
super.addChild(w, position);
|
||||
}
|
||||
|
||||
override void recomputeChildLayout() {
|
||||
if(hsb is null || vsb is null || container is null) return;
|
||||
|
||||
registerMovement();
|
||||
|
||||
hsb.height = 16; // FIXME? are tese 16s sane?
|
||||
hsb.x = 0;
|
||||
hsb.y = this.height - hsb.height;
|
||||
hsb.width = this.width - 16;
|
||||
hsb.recomputeChildLayout();
|
||||
|
||||
vsb.width = 16; // FIXME?
|
||||
vsb.x = this.width - vsb.width;
|
||||
vsb.y = 0;
|
||||
vsb.height = this.height - 16;
|
||||
vsb.recomputeChildLayout();
|
||||
|
||||
container.x = 0;
|
||||
container.y = 0;
|
||||
container.width = this.width - vsb.width;
|
||||
container.height = this.height - hsb.height;
|
||||
container.recomputeChildLayout();
|
||||
}
|
||||
|
||||
HorizontalScrollbar hsb;
|
||||
VerticalScrollbar vsb;
|
||||
Widget container;
|
||||
}
|
||||
|
||||
/++
|
||||
Bypasses automatic layout for its children, using manual positioning and sizing only.
|
||||
While you need to manually position them, you must ensure they are inside the StaticLayout's
|
||||
|
@ -3471,6 +3696,97 @@ class Window : Widget {
|
|||
if(hwnd !is this.win.impl.hwnd)
|
||||
return 1; // we don't care...
|
||||
switch(msg) {
|
||||
|
||||
case WM_VSCROLL, WM_HSCROLL:
|
||||
auto pos = HIWORD(wParam);
|
||||
auto m = LOWORD(wParam);
|
||||
|
||||
auto scrollbarHwnd = cast(HWND) lParam;
|
||||
|
||||
|
||||
if(auto widgetp = scrollbarHwnd in Widget.nativeMapping) {
|
||||
|
||||
//auto smw = cast(ScrollMessageWidget) widgetp.parent;
|
||||
|
||||
switch(m) {
|
||||
/+
|
||||
// I don't think those messages are ever actually sent normally by the widget itself,
|
||||
// they are more used for the keyboard interface. methinks.
|
||||
case SB_BOTTOM:
|
||||
import std.stdio; writeln("end");
|
||||
auto event = new Event("scrolltoend", *widgetp);
|
||||
event.dispatch();
|
||||
//if(!event.defaultPrevented)
|
||||
break;
|
||||
case SB_TOP:
|
||||
import std.stdio; writeln("top");
|
||||
auto event = new Event("scrolltobeginning", *widgetp);
|
||||
event.dispatch();
|
||||
break;
|
||||
case SB_ENDSCROLL:
|
||||
// idk
|
||||
break;
|
||||
+/
|
||||
case SB_LINEDOWN:
|
||||
auto event = new Event("scrolltonextline", *widgetp);
|
||||
event.dispatch();
|
||||
break;
|
||||
case SB_LINEUP:
|
||||
auto event = new Event("scrolltopreviousline", *widgetp);
|
||||
event.dispatch();
|
||||
break;
|
||||
case SB_PAGEDOWN:
|
||||
auto event = new Event("scrolltonextpage", *widgetp);
|
||||
event.dispatch();
|
||||
break;
|
||||
case SB_PAGEUP:
|
||||
auto event = new Event("scrolltopreviouspage", *widgetp);
|
||||
event.dispatch();
|
||||
break;
|
||||
case SB_THUMBPOSITION:
|
||||
auto event = new Event("scrolltoposition", *widgetp);
|
||||
event.intValue = pos;
|
||||
event.dispatch();
|
||||
break;
|
||||
case SB_THUMBTRACK:
|
||||
auto event = new Event("scrolltrack", *widgetp);
|
||||
event.intValue = pos;
|
||||
event.dispatch();
|
||||
/+
|
||||
if(m == SB_THUMBTRACK) {
|
||||
// the event loop doesn't seem to carry on with a requested redraw..
|
||||
// so we request it to get our dirty bit set...
|
||||
redraw();
|
||||
// then we need to immediately actually redraw it too for instant feedback to user
|
||||
actualRedraw();
|
||||
}
|
||||
+/
|
||||
break;
|
||||
default:
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_CONTEXTMENU:
|
||||
auto hwndFrom = cast(HWND) wParam;
|
||||
|
||||
/+
|
||||
auto xPos = GET_X_LPARAM(lParam);
|
||||
auto yPos = GET_Y_LPARAM(lParam);
|
||||
|
||||
if(auto widgetp = hwndFrom in Widget.nativeMapping) {
|
||||
// FIXME: translate screen coordinates to widget coordinates
|
||||
auto menu = (*widgetp).contextMenu(xPos, yPos);
|
||||
if(menu is null)
|
||||
return 1; // pass it on
|
||||
|
||||
//TrackContextMenuEx
|
||||
}
|
||||
+/
|
||||
break;
|
||||
|
||||
case WM_NOTIFY:
|
||||
auto hdr = cast(NMHDR*) lParam;
|
||||
auto hwndFrom = hdr.hwndFrom;
|
||||
|
|
Loading…
Reference in New Issue