scrollablewidget on windows

This commit is contained in:
Adam D. Ruppe 2017-04-07 00:20:00 -04:00
parent ea1f30fff4
commit 939d18fcd8
3 changed files with 542 additions and 230 deletions

20
color.d
View File

@ -1259,7 +1259,9 @@ struct Point {
int x; ///
int y; ///
Point opBinary(string op)(Point rhs) {
pure const nothrow @safe:
Point opBinary(string op)(in Point rhs) {
return Point(mixin("x" ~ op ~ "rhs.x"), mixin("y" ~ op ~ "rhs.y"));
}
@ -1281,6 +1283,8 @@ struct Rectangle {
int right; ///
int bottom; ///
pure const nothrow @safe:
///
this(int left, int top, int right, int bottom) {
this.left = left;
@ -1290,12 +1294,12 @@ struct Rectangle {
}
///
this(Point upperLeft, Point lowerRight) {
this(in Point upperLeft, in Point lowerRight) {
this(upperLeft.x, upperLeft.y, lowerRight.x, lowerRight.y);
}
///
this(Point upperLeft, Size size) {
this(in Point upperLeft, in Size size) {
this(upperLeft.x, upperLeft.y, upperLeft.x + size.width, upperLeft.y + size.height);
}
@ -1323,6 +1327,16 @@ struct Rectangle {
@property int height() {
return bottom - top;
}
///
bool contains(in Rectangle r) {
return contains(r.upperLeft) && contains(r.lowerRight);
}
///
bool contains(in Point p) {
return (p.x >= left && p.y < right && p.y >= top && p.y < bottom);
}
}
/++

711
minigui.d
View File

@ -62,6 +62,7 @@
module arsd.minigui;
public import arsd.simpledisplay;
private alias Rectangle = arsd.color.Rectangle; // I specifically want this in here, not the win32 GDI Rectangle()
version(Windows)
import core.sys.windows.windows;
@ -139,7 +140,6 @@ abstract class ComboboxBase : Widget {
version(win32_widgets)
this(uint style, Widget parent = null) {
super(parent);
parentWindow = parent.parentWindow;
createWin32Window(this, "ComboBox", null, style);
}
else version(custom_widgets)
@ -876,6 +876,9 @@ version(win32_widgets) {
//import std.stdio; try { writeln(iMessage); } catch(Exception e) {};
if(auto te = hWnd in Widget.nativeMapping) {
try {
te.hookedWndProc(iMessage, wParam, lParam);
if(iMessage == WM_SETFOCUS) {
auto lol = *te;
while(lol !is null && lol.implicitlyCreated)
@ -1048,6 +1051,10 @@ class Widget {
static Widget[HWND] nativeMapping;
HWND hwnd;
WNDPROC originalWindowProcedure;
int hookedWndProc(UINT iMessage, WPARAM wParam, LPARAM lParam) {
return 0;
}
}
bool implicitlyCreated;
@ -1281,11 +1288,94 @@ enum ScrollBarShowPolicy {
/++
+/
version(win32_widgets)
class ScrollableWidget : Widget { this(Widget parent = null) { super(parent); } } // TEMPORARY
else
class ScrollableWidget : Widget {
this(Widget parent = null) {
// FIXME: make line size configurable
// FIXME: add keyboard controls
// FIXME: SB_THUMBTRACK doesn't seem to be working
version(win32_widgets) {
override int hookedWndProc(UINT msg, WPARAM wParam, LPARAM lParam) {
if(msg == WM_VSCROLL || msg == WM_HSCROLL) {
auto pos = HIWORD(wParam);
auto m = LOWORD(wParam);
// FIXME: I can reintroduce the
// scroll bars now by using this
// in the top-level window handler
// to forward comamnds
auto scrollbarHwnd = lParam;
switch(m) {
case SB_BOTTOM:
if(msg == WM_HSCROLL)
horizontalScrollTo(contentWidth_);
else
verticalScrollTo(contentHeight_);
break;
case SB_TOP:
if(msg == WM_HSCROLL)
horizontalScrollTo(0);
else
verticalScrollTo(0);
break;
case SB_ENDSCROLL:
// idk
break;
case SB_LINEDOWN:
if(msg == WM_HSCROLL)
horizontalScroll(16);
else
verticalScroll(16);
break;
case SB_LINEUP:
if(msg == WM_HSCROLL)
horizontalScroll(-16);
else
verticalScroll(-16);
break;
case SB_PAGEDOWN:
if(msg == WM_HSCROLL)
horizontalScroll(100);
else
verticalScroll(100);
break;
case SB_PAGEUP:
if(msg == WM_HSCROLL)
horizontalScroll(-100);
else
verticalScroll(-100);
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
if(msg == WM_HSCROLL)
horizontalScrollTo(pos);
else
verticalScrollTo(pos);
break;
default:
}
}
return 0;
}
}
this(Widget parent) {
this.parentWindow = parent.parentWindow;
version(win32_widgets) {
static bool classRegistered = false;
if(!classRegistered) {
HINSTANCE hInstance = cast(HINSTANCE) GetModuleHandle(null);
WNDCLASSEX wc;
wc.cbSize = wc.sizeof;
wc.hInstance = hInstance;
wc.lpfnWndProc = &DefWindowProc;
wc.lpszClassName = "arsd_minigui_ScrollableWidget"w.ptr;
if(!RegisterClassExW(&wc))
throw new Exception("RegisterClass ");// ~ to!string(GetLastError()));
classRegistered = true;
}
createWin32Window(this, "arsd_minigui_ScrollableWidget", "",
0|WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL, 0);
} else version(custom_widgets) {
horizontalScrollbarHolder = new FixedPosition(this);
verticalScrollbarHolder = new FixedPosition(this);
horizontalScrollBar = new HorizontalScrollbar(horizontalScrollbarHolder);
@ -1294,62 +1384,92 @@ class ScrollableWidget : Widget {
horizontalScrollbarHolder.hidden_ = true;
verticalScrollbarHolder.hidden_ = true;
horizontalScrollBar.addEventListener(EventType.change, () {
horizontalScrollTo(horizontalScrollBar.position);
});
verticalScrollBar.addEventListener(EventType.change, () {
verticalScrollTo(verticalScrollBar.position);
});
} else static assert(0);
super(parent);
}
version(custom_widgets) {
FixedPosition horizontalScrollbarHolder;
FixedPosition verticalScrollbarHolder;
VerticalScrollbar verticalScrollBar;
HorizontalScrollbar horizontalScrollBar;
}
version(custom_widgets)
override void recomputeChildLayout() {
bool both = showingVerticalScroll && showingHorizontalScroll;
if(horizontalScrollbarHolder && verticalScrollbarHolder) {
horizontalScrollbarHolder.width = this.width - (both ? 16 : 0);
horizontalScrollbarHolder.height = 16;
horizontalScrollbarHolder.width = this.width - (both ? verticalScrollBar.minWidth() : 0);
horizontalScrollbarHolder.height = horizontalScrollBar.minHeight();
horizontalScrollbarHolder.x = 0;
horizontalScrollbarHolder.y = this.height - 16;
horizontalScrollbarHolder.y = this.height - horizontalScrollBar.minHeight();
verticalScrollbarHolder.width = 16;
verticalScrollbarHolder.height = this.height - (both ? 16 : 0);
verticalScrollbarHolder.x = this.width - 16;
verticalScrollbarHolder.width = verticalScrollBar.minWidth();
verticalScrollbarHolder.height = this.height - (both ? horizontalScrollBar.minHeight() : 0);
verticalScrollbarHolder.x = this.width - verticalScrollBar.minWidth();
verticalScrollbarHolder.y = 0;
{
int viewableScrollArea = viewportHeight;
int totalScrollArea = contentHeight;
int totalScrollBarArea = verticalScrollBar.thumb.height;
int thumbSize;
if(totalScrollArea)
thumbSize = viewableScrollArea * totalScrollBarArea / totalScrollArea;
else
thumbSize = 0;
if(thumbSize < 6)
thumbSize = 6;
verticalScrollBar.thumb.thumbHeight = thumbSize;
}
{
int viewableScrollArea = viewportWidth;
int totalScrollArea = contentWidth;
int totalScrollBarArea = horizontalScrollBar.thumb.width;
int thumbSize;
if(totalScrollArea)
thumbSize = viewableScrollArea * totalScrollBarArea / totalScrollArea;
else
thumbSize = 0;
if(thumbSize < 6)
thumbSize = 6;
horizontalScrollBar.thumb.thumbWidth = thumbSize;
}
if(contentWidth_ <= this.width)
scrollOrigin_.x = 0;
if(contentHeight_ <= this.height)
scrollOrigin_.y = 0;
}
super.recomputeChildLayout();
}
if(contentWidth_ <= this.width)
scrollOrigin_.x = 0;
if(contentHeight_ <= this.height)
scrollOrigin_.y = 0;
if(showingHorizontalScroll())
horizontalScrollbarHolder.hidden = false;
else
horizontalScrollbarHolder.hidden = true;
if(showingVerticalScroll())
verticalScrollbarHolder.hidden = false;
else
verticalScrollbarHolder.hidden = true;
verticalScrollBar.setViewableArea(this.viewportHeight());
verticalScrollBar.setMax(contentHeight);
verticalScrollBar.setPosition(this.scrollOrigin.y);
horizontalScrollBar.setViewableArea(this.viewportWidth());
horizontalScrollBar.setMax(contentWidth);
horizontalScrollBar.setPosition(this.scrollOrigin.x);
} else version(win32_widgets)
override void recomputeChildLayout() {
super.recomputeChildLayout();
SCROLLINFO info;
info.cbSize = info.sizeof;
info.nPage = viewportHeight;
info.fMask = SIF_PAGE | SIF_RANGE;
info.nMin = 0;
info.nMax = contentHeight_;
SetScrollInfo(hwnd, SB_VERT, &info, true);
info.cbSize = info.sizeof;
info.nPage = viewportWidth;
info.fMask = SIF_PAGE | SIF_RANGE;
info.nMin = 0;
info.nMax = contentWidth_;
SetScrollInfo(hwnd, SB_HORZ, &info, true);
} else static assert(0);
/*
Scrolling
@ -1371,42 +1491,43 @@ class ScrollableWidget : Widget {
the viewportWidth, viewportHeight, and scrollOrigin members.
*/
@property int viewportWidth() {
final @property int viewportWidth() {
return width - (showingVerticalScroll ? 16 : 0);
}
@property int viewportHeight() {
final @property int viewportHeight() {
return height - (showingHorizontalScroll ? 16 : 0);
}
// FIXME property
Point scrollOrigin;
Point scrollOrigin_;
final const(Point) scrollOrigin() {
return scrollOrigin_;
}
// the user sets these two
private int contentWidth = 0;
private int contentHeight = 0;
private int contentWidth_ = 0;
private int contentHeight_ = 0;
int contentWidth() { return contentWidth_; }
int contentHeight() { return contentHeight_; }
void setContentSize(int width, int height) {
contentWidth = width;
contentHeight = height;
contentWidth_ = width;
contentHeight_ = height;
version(custom_widgets) {
if(showingVerticalScroll || showingHorizontalScroll) {
recomputeChildLayout();
}
if(showingHorizontalScroll())
horizontalScrollbarHolder.hidden = false;
else
horizontalScrollbarHolder.hidden = true;
if(showingVerticalScroll())
verticalScrollbarHolder.hidden = false;
else
verticalScrollbarHolder.hidden = true;
if(showingVerticalScroll())
verticalScrollBar.redraw();
if(showingHorizontalScroll())
horizontalScrollBar.redraw();
} else version(win32_widgets) {
recomputeChildLayout();
} else static assert(0);
}
@ -1414,20 +1535,22 @@ class ScrollableWidget : Widget {
verticalScrollTo(scrollOrigin.y + delta);
}
void verticalScrollTo(int pos) {
scrollOrigin.y = pos;
if(scrollOrigin.y + viewportHeight > contentHeight)
scrollOrigin.y = contentHeight - viewportHeight;
scrollOrigin_.y = pos;
if(scrollOrigin_.y + viewportHeight > contentHeight)
scrollOrigin_.y = contentHeight - viewportHeight;
if(scrollOrigin.y < 0)
scrollOrigin.y = 0;
if(scrollOrigin_.y < 0)
scrollOrigin_.y = 0;
int viewableScrollArea = viewportHeight;
int totalScrollArea = contentHeight;
int totalScrollBarArea = verticalScrollBar.thumb.height;
int thumbPosition = scrollOrigin.y * totalScrollBarArea / totalScrollArea;
int thumbSize = viewableScrollArea * totalScrollBarArea / totalScrollArea;
verticalScrollBar.thumb.positionY = thumbPosition;
version(win32_widgets) {
SCROLLINFO info;
info.cbSize = info.sizeof;
info.fMask = SIF_POS;
info.nPos = scrollOrigin_.y;
SetScrollInfo(hwnd, SB_VERT, &info, true);
} else version(custom_widgets) {
verticalScrollBar.setPosition(scrollOrigin_.y);
} else static assert(0);
redraw();
}
@ -1436,20 +1559,22 @@ class ScrollableWidget : Widget {
horizontalScrollTo(scrollOrigin.x + delta);
}
void horizontalScrollTo(int pos) {
scrollOrigin.x = pos;
if(scrollOrigin.x + viewportWidth > contentWidth)
scrollOrigin.x = contentWidth - viewportWidth;
scrollOrigin_.x = pos;
if(scrollOrigin_.x + viewportWidth > contentWidth)
scrollOrigin_.x = contentWidth - viewportWidth;
if(scrollOrigin.x < 0)
scrollOrigin.x = 0;
if(scrollOrigin_.x < 0)
scrollOrigin_.x = 0;
int viewableScrollArea = viewportWidth;
int totalScrollArea = contentWidth;
int totalScrollBarArea = horizontalScrollBar.thumb.width;
int thumbPosition = scrollOrigin.x * totalScrollBarArea / totalScrollArea;
int thumbSize = viewableScrollArea * totalScrollBarArea / totalScrollArea;
horizontalScrollBar.thumb.positionX = thumbPosition;
version(win32_widgets) {
SCROLLINFO info;
info.cbSize = info.sizeof;
info.fMask = SIF_POS;
info.nPos = scrollOrigin_.x;
SetScrollInfo(hwnd, SB_HORZ, &info, true);
} else version(custom_widgets) {
horizontalScrollBar.setPosition(scrollOrigin_.x);
} else static assert(0);
redraw();
}
@ -1458,6 +1583,30 @@ class ScrollableWidget : Widget {
horizontalScrollTo(p.x);
}
void ensureVisibleInScroll(Point p) {
auto rect = viewportRectangle();
if(rect.contains(p))
return;
if(p.x < rect.left)
horizontalScroll(p.x - rect.left);
else if(p.x > rect.right)
horizontalScroll(p.x - rect.right);
if(p.y < rect.top)
verticalScroll(p.y - rect.top);
else if(p.y > rect.bottom)
verticalScroll(p.y - rect.bottom);
}
void ensureVisibleInScroll(Rectangle rect) {
ensureVisibleInScroll(rect.upperLeft);
ensureVisibleInScroll(rect.lowerRight);
}
Rectangle viewportRectangle() {
return Rectangle(scrollOrigin, Size(viewportWidth, viewportHeight));
}
bool showingHorizontalScroll() {
return contentWidth > width;
}
@ -1520,139 +1669,93 @@ class ScrollableWidget : Widget {
child.privatePaint(painter, painter.originX, painter.originY);
}
}
}
///
abstract class ScrollbarBase : Widget {
this(Widget parent = null) {
this(Widget parent) {
super(parent);
tabStop = false;
}
int viewableArea;
int totalScrollableArea;
private int viewableArea_;
private int max_;
private int step_ = 16;
private int position_;
void setViewableArea(int a) {
viewableArea_ = a;
}
void setMax(int a) {
max_ = a;
}
int max() {
return max_;
}
void setPosition(int a) {
position_ = max ? a : 0;
}
int position() {
return position_;
}
void setStep(int a) {
step_ = a;
}
int step() {
return step_;
}
protected void informProgramThatUserChangedPosition(int n) {
position_ = n;
auto evt = new Event(EventType.change, this);
evt.dispatch();
}
version(custom_widgets) {
abstract protected int getBarDim();
int thumbSize() {
int res;
if(max_) {
res = getBarDim() * viewableArea_ / max_;
}
if(res < 6)
res = 6;
return res;
}
int thumbPosition() {
if(max_) {
auto res = position_ * viewableArea_ / max_;
if(res + thumbSize() > getBarDim())
res = getBarDim() - thumbSize();
if(res < 0)
res = 0;
return res;
}
return 0;
}
}
}
///
version(custom_widgets)
class HorizontalScrollbar : ScrollbarBase {
MouseTrackingWidget thumb;
this(Widget parent = null) {
super(parent);
// FIXME win32_widgets
auto vl = new HorizontalLayout(this);
auto leftButton = new ArrowButton(ArrowDirection.left, vl);
thumb = new MouseTrackingWidget(MouseTrackingWidget.Orientation.horizontal, vl);
auto rightButton = new ArrowButton(ArrowDirection.right, vl);
ScrollableWidget scrollableParent;
Widget p = parent;
while(p !is null) {
if(auto sw = cast(ScrollableWidget) p) {
scrollableParent = sw;
break;
}
p = p.parent;
}
leftButton.addEventListener(EventType.triggered, () {
if(scrollableParent)
scrollableParent.horizontalScroll(-16);
});
rightButton.addEventListener(EventType.triggered, () {
if(scrollableParent)
scrollableParent.horizontalScroll(16);
});
thumb.thumbWidth = this.minWidth;
thumb.thumbHeight = 16;
thumb.addEventListener(EventType.change, () {
int viewableScrollArea = scrollableParent.viewportWidth;
int totalScrollArea = scrollableParent.contentWidth;
int totalScrollBarArea = thumb.width;
auto sx = thumb.positionX * totalScrollArea / totalScrollBarArea;
scrollableParent.horizontalScrollTo(sx);
});
}
override int minHeight() { return 16; }
override int maxHeight() { return 16; }
override int minWidth() { return 48; }
}
///show
version(custom_widgets)
class VerticalScrollbar : ScrollbarBase {
MouseTrackingWidget thumb;
this(Widget parent = null) {
super(parent);
// FIXME win32_widgets
auto vl = new VerticalLayout(this);
auto upButton = new ArrowButton(ArrowDirection.up, vl);
thumb = new MouseTrackingWidget(MouseTrackingWidget.Orientation.vertical, vl);
auto downButton = new ArrowButton(ArrowDirection.down, vl);
ScrollableWidget scrollableParent;
Widget p = parent;
while(p !is null) {
if(auto sw = cast(ScrollableWidget) p) {
scrollableParent = sw;
break;
}
p = p.parent;
}
upButton.addEventListener(EventType.triggered, () {
if(scrollableParent)
scrollableParent.verticalScroll(-16);
});
downButton.addEventListener(EventType.triggered, () {
if(scrollableParent)
scrollableParent.verticalScroll(16);
});
thumb.thumbWidth = this.minWidth;
thumb.thumbHeight = 16;
thumb.addEventListener(EventType.change, () {
int viewableScrollArea = scrollableParent.viewportHeight;
int totalScrollArea = scrollableParent.contentHeight;
int totalScrollBarArea = thumb.height;
auto sy = thumb.positionY * totalScrollArea / totalScrollBarArea;
scrollableParent.verticalScrollTo(sy);
});
}
override int minWidth() { return 16; }
override int maxWidth() { return 16; }
override int minHeight() { return 48; }
}
//public import mgt;
/++
A mouse tracking widget is one that follows the mouse when dragged inside it.
Concrete subclasses may include a scrollbar thumb and a volume control.
+/
version(custom_widgets)
//version(custom_widgets)
class MouseTrackingWidget : Widget {
int mouseTrackerPosition;
int positionX;
int positionY;
int positionX() { return positionX_; }
int positionY() { return positionY_; }
void positionX(int p) { positionX_ = p; }
void positionY(int p) { positionY_ = p; }
private int positionX_;
private int positionY_;
///
enum Orientation {
@ -1661,8 +1764,13 @@ class MouseTrackingWidget : Widget {
twoDimensional, ///
}
int thumbWidth;
int thumbHeight;
private int thumbWidth_;
private int thumbHeight_;
int thumbWidth() { return thumbWidth_; }
int thumbHeight() { return thumbHeight_; }
int thumbWidth(int a) { return thumbWidth_ = a; }
int thumbHeight(int a) { return thumbHeight_ = a; }
this(Orientation orientation, Widget parent = null) {
super(parent);
@ -1751,6 +1859,7 @@ class MouseTrackingWidget : Widget {
redraw();
});
version(custom_widgets)
this.paint = (ScreenPainter painter) {
auto c = lighten(windowBackgroundColor, 0.2);
painter.outlineColor = c;
@ -1764,13 +1873,190 @@ class MouseTrackingWidget : Widget {
}
}
version(custom_widgets)
private
class HorizontalScrollbar : ScrollbarBase {
version(custom_widgets) {
private MouseTrackingWidget thumb;
override int getBarDim() {
return thumb.width;
}
}
override void setViewableArea(int a) {
super.setViewableArea(a);
version(win32_widgets) {
SCROLLINFO info;
info.cbSize = info.sizeof;
info.nPage = a;
info.fMask = SIF_PAGE;
SetScrollInfo(hwnd, SB_CTL, &info, true);
} else version(custom_widgets) {
// intentionally blank
} else static assert(0);
}
override void setMax(int a) {
super.setMax(a);
version(win32_widgets) {
SCROLLINFO info;
info.cbSize = info.sizeof;
info.nMin = 0;
info.nMax = max;
info.fMask = SIF_RANGE;
SetScrollInfo(hwnd, SB_CTL, &info, true);
}
}
override void setPosition(int a) {
super.setPosition(a);
version(win32_widgets) {
SCROLLINFO info;
info.cbSize = info.sizeof;
info.fMask = SIF_POS;
info.nPos = position;
SetScrollInfo(hwnd, SB_CTL, &info, true);
} else version(custom_widgets) {
thumb.positionX = thumbPosition();
thumb.thumbWidth = thumbSize;
thumb.redraw();
} else static assert(0);
}
this(Widget parent) {
super(parent);
version(win32_widgets) {
createWin32Window(this, "Scrollbar", "",
0|WS_CHILD|WS_VISIBLE|SBS_HORZ|SBS_BOTTOMALIGN, 0);
} else version(custom_widgets) {
auto vl = new HorizontalLayout(this);
auto leftButton = new ArrowButton(ArrowDirection.left, vl);
thumb = new MouseTrackingWidget(MouseTrackingWidget.Orientation.horizontal, vl);
auto rightButton = new ArrowButton(ArrowDirection.right, vl);
leftButton.addEventListener(EventType.triggered, () {
informProgramThatUserChangedPosition(position - step());
});
rightButton.addEventListener(EventType.triggered, () {
informProgramThatUserChangedPosition(position + step());
});
thumb.thumbWidth = this.minWidth;
thumb.thumbHeight = 16;
thumb.addEventListener(EventType.change, () {
auto sx = thumb.positionX * max() / thumb.width;
informProgramThatUserChangedPosition(sx);
});
}
}
override int minHeight() { return 16; }
override int maxHeight() { return 16; }
override int minWidth() { return 48; }
}
version(custom_widgets)
private
class VerticalScrollbar : ScrollbarBase {
version(custom_widgets) {
override int getBarDim() {
return thumb.height;
}
private MouseTrackingWidget thumb;
}
override void setViewableArea(int a) {
super.setViewableArea(a);
version(win32_widgets) {
SCROLLINFO info;
info.cbSize = info.sizeof;
info.nPage = a;
info.fMask = SIF_PAGE;
SetScrollInfo(hwnd, SB_CTL, &info, true);
} else version(custom_widgets) {
// intentionally blank
} else static assert(0);
}
override void setMax(int a) {
super.setMax(a);
version(win32_widgets) {
SCROLLINFO info;
info.cbSize = info.sizeof;
info.nMin = 0;
info.nMax = max;
info.fMask = SIF_RANGE;
SetScrollInfo(hwnd, SB_CTL, &info, true);
}
}
override void setPosition(int a) {
super.setPosition(a);
version(win32_widgets) {
SCROLLINFO info;
info.cbSize = info.sizeof;
info.fMask = SIF_POS;
info.nPos = position;
SetScrollInfo(hwnd, SB_CTL, &info, true);
} else version(custom_widgets) {
thumb.positionY = thumbPosition;
thumb.thumbHeight = thumbSize;
thumb.redraw();
} else static assert(0);
}
this(Widget parent) {
super(parent);
version(win32_widgets) {
createWin32Window(this, "Scrollbar", "",
0|WS_CHILD|WS_VISIBLE|SBS_VERT|SBS_RIGHTALIGN, 0);
} else version(custom_widgets) {
auto vl = new VerticalLayout(this);
auto upButton = new ArrowButton(ArrowDirection.up, vl);
thumb = new MouseTrackingWidget(MouseTrackingWidget.Orientation.vertical, vl);
auto downButton = new ArrowButton(ArrowDirection.down, vl);
upButton.addEventListener(EventType.triggered, () {
informProgramThatUserChangedPosition(position - step());
});
downButton.addEventListener(EventType.triggered, () {
informProgramThatUserChangedPosition(position + step());
});
thumb.thumbWidth = this.minWidth;
thumb.thumbHeight = 16;
thumb.addEventListener(EventType.change, () {
auto sy = thumb.positionY * max() / thumb.height;
informProgramThatUserChangedPosition(sy);
});
}
}
override int minWidth() { return 16; }
override int maxWidth() { return 16; }
override int minHeight() { return 48; }
}
///
abstract class Layout : Widget {
this(Widget parent = null) {
tabStop = false;
super(parent);
if(parent)
this.parentWindow = parent.parentWindow;
}
}
@ -1970,7 +2256,7 @@ class StaticPosition : Layout {
the parent content.
+/
class FixedPosition : StaticPosition {
this(Widget parent = null) { super(parent); }
this(Widget parent) { super(parent); }
}
@ -2057,6 +2343,7 @@ class Window : Widget {
version(win32_widgets)
win.handleNativeEvent = delegate int(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if(hwnd !is this.win.impl.hwnd)
return 1; // we don't care...
switch(msg) {
@ -2497,7 +2784,6 @@ class ToolBar : Widget {
tabStop = false;
version(win32_widgets) {
parentWindow = parent.parentWindow;
createWin32Window(this, "ToolbarWindow32", "", 0);
imageList = ImageList_Create(
@ -2829,7 +3115,6 @@ class IndefiniteProgressBar : Widget {
version(win32_widgets)
this(Widget parent = null) {
super(parent);
parentWindow = parent.parentWindow;
createWin32Window(this, "msctls_progress32", "", 8 /* PBS_MARQUEE */);
tabStop = false;
}
@ -2841,7 +3126,6 @@ class ProgressBar : Widget {
version(win32_widgets)
this(Widget parent = null) {
super(parent);
parentWindow = parent.parentWindow;
createWin32Window(this, "msctls_progress32", "", 0);
tabStop = false;
}
@ -2936,7 +3220,6 @@ class Fieldset : Widget {
this(string legend, Widget parent = null) {
super(parent);
this.legend = legend;
parentWindow = parent.parentWindow;
createWin32Window(this, "button", legend, BS_GROUPBOX);
tabStop = false;
}
@ -2945,7 +3228,6 @@ class Fieldset : Widget {
super(parent);
tabStop = false;
this.legend = legend;
parentWindow = parent.parentWindow;
this.paint = (ScreenPainter painter) {
painter.fillColor = Color.transparent;
painter.pen = Pen(Color.black, 1);
@ -3286,7 +3568,6 @@ class Checkbox : MouseActivatedWidget {
version(win32_widgets)
this(string label, Widget parent = null) {
super(parent);
parentWindow = parent.parentWindow;
createWin32Window(this, "button", label, BS_AUTOCHECKBOX);
}
else version(custom_widgets)
@ -3363,7 +3644,6 @@ class Radiobox : MouseActivatedWidget {
version(win32_widgets)
this(string label, Widget parent = null) {
super(parent);
parentWindow = parent.parentWindow;
createWin32Window(this, "button", label, BS_AUTORADIOBUTTON);
}
else version(custom_widgets)
@ -3453,7 +3733,6 @@ class Button : MouseActivatedWidget {
version(win32_widgets)
this(string label, Widget parent = null) {
super(parent);
parentWindow = parent.parentWindow;
createWin32Window(this, "button", label, BS_PUSHBUTTON);
// FIXME: use ideal button size instead
@ -3587,7 +3866,6 @@ class TextLabel : Widget {
this.label = label;
this.tabStop = false;
super(parent);
parentWindow = parent.parentWindow;
paint = (ScreenPainter painter) {
painter.outlineColor = Color.black;
painter.drawText(Point(0, 0), this.label, Point(width,height), TextAlignment.Right);
@ -3599,8 +3877,14 @@ class TextLabel : Widget {
version(custom_widgets)
mixin ExperimentalTextComponent;
version(win32_widgets)
alias EditableTextWidgetParent = Widget; ///
else version(custom_widgets)
alias EditableTextWidgetParent = ScrollableWidget; ///
else static assert(0);
/// Contains the implementation of text editing
abstract class EditableTextWidget : ScrollableWidget {
abstract class EditableTextWidget : EditableTextWidgetParent {
this(Widget parent = null) {
super(parent);
}
@ -3767,6 +4051,7 @@ abstract class EditableTextWidget : ScrollableWidget {
redraw();
}
*/
ensureVisibleInScroll(textLayout.caretBoundingBox());
});
static if(UsingSimpledisplayX11)
@ -3787,7 +4072,6 @@ class LineEdit : EditableTextWidget {
this(Widget parent = null) {
super(parent);
version(win32_widgets) {
parentWindow = parent.parentWindow;
createWin32Window(this, "edit", "",
0, WS_EX_CLIENTEDGE);//|WS_HSCROLL|ES_AUTOHSCROLL);
} else version(custom_widgets) {
@ -3806,7 +4090,6 @@ class TextEdit : EditableTextWidget {
this(Widget parent = null) {
super(parent);
version(win32_widgets) {
parentWindow = parent.parentWindow;
createWin32Window(this, "edit", "",
0|WS_VSCROLL|WS_HSCROLL|ES_MULTILINE|ES_WANTRETURN|ES_AUTOHSCROLL|ES_AUTOVSCROLL, WS_EX_CLIENTEDGE);
} else version(custom_widgets) {

View File

@ -11157,6 +11157,21 @@ mixin template ExperimentalTextComponent() {
}
}
Rectangle caretBoundingBox() {
int x, y1, y2;
if(caret.inlineElement is null) {
x = boundingBox.left;
y1 = boundingBox.top + 2;
y2 = boundingBox.top + 16;
} else {
x = caret.inlineElement.xOfIndex(caret.offset);
y1 = caret.inlineElement.boundingBox.top + 2;
y2 = caret.inlineElement.boundingBox.bottom - 2;
}
return Rectangle(x, y1, x + 1, y2);
}
void eraseCaret(ScreenPainter painter) {
//painter.setClipRectangle(boundingBox);
if(!caretShowingOnScreen) return;