diff --git a/color.d b/color.d index ef3554b..b655eca 100644 --- a/color.d +++ b/color.d @@ -1274,6 +1274,49 @@ struct Rectangle { int top; /// int right; /// int bottom; /// + + /// + this(int left, int top, int right, int bottom) { + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + } + + /// + this(Point upperLeft, Point lowerRight) { + this(upperLeft.x, upperLeft.y, lowerRight.x, lowerRight.y); + } + + /// + this(Point upperLeft, Size size) { + this(upperLeft.x, upperLeft.y, upperLeft.x + size.width, upperLeft.y + size.height); + } + + /// + @property Point upperLeft() { + return Point(left, top); + } + + /// + @property Point lowerRight() { + return Point(right, bottom); + } + + /// + @property Size size() { + return Size(width, height); + } + + /// + @property int width() { + return right - left; + } + + /// + @property int height() { + return bottom - top; + } } /++ diff --git a/minigui.d b/minigui.d index e02482f..4251548 100644 --- a/minigui.d +++ b/minigui.d @@ -1170,20 +1170,12 @@ class Widget { } protected void privatePaint(ScreenPainter painter, int lox, int loy) { + painter.originX = lox + x; painter.originY = loy + y; - static if(UsingSimpledisplayX11) { - XRectangle[1] rects; - rects[0] = XRectangle(cast(short)(lox + x), cast(short)(loy + y), cast(short) width, cast(short) height); - XSetClipRectangles(XDisplayConnection.get, painter.impl.gc, 0, 0, rects.ptr, 1, 0); - } else { - version(Windows) { - auto region = CreateRectRgn(lox + x, loy + y, lox + x + width, loy + y + height); - SelectClipRgn(painter.impl.hdc, region); - DeleteObject(region); - } - } + painter.setClipRectangle(Point(0, 0), width, height); + if(paint !is null) paint(painter); foreach(child; children) @@ -1346,6 +1338,41 @@ 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) { + case WM_COMMAND: + switch(HIWORD(wParam)) { + case 0: + // case BN_CLICKED: aka 0 + case 1: + auto idm = LOWORD(wParam); + if(auto item = idm in Action.mapping) { + foreach(handler; (*item).triggered) + handler(); + /* + auto event = new Event("triggered", *item); + event.button = idm; + event.dispatch(); + */ + } else { + auto handle = cast(HWND) lParam; + if(auto widgetp = handle in Widget.nativeMapping) { + (*widgetp).handleWmCommand(HIWORD(wParam), LOWORD(wParam)); + } + } + break; + default: + return 1; + } + break; + default: return 1; // not handled, pass it on + } + return 0; + }; + defaultEventHandlers["keydown"] = delegate void(Widget ignored, Event event) { Widget _this = event.target; @@ -1605,41 +1632,6 @@ class MainWindow : Window { this.statusBar.parts[0].content = _this.statusTip; // ~ " " ~ event.target.toString(); }; - 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) { - case WM_COMMAND: - switch(HIWORD(wParam)) { - case 0: - // case BN_CLICKED: aka 0 - case 1: - auto idm = LOWORD(wParam); - if(auto item = idm in Action.mapping) { - foreach(handler; (*item).triggered) - handler(); - /* - auto event = new Event("triggered", *item); - event.button = idm; - event.dispatch(); - */ - } else { - auto handle = cast(HWND) lParam; - if(auto widgetp = handle in Widget.nativeMapping) { - (*widgetp).handleWmCommand(HIWORD(wParam), LOWORD(wParam)); - } - } - break; - default: - return 1; - } - break; - default: return 1; // not handled, pass it on - } - return 0; - }; - _clientArea = new ClientAreaWidget(); _clientArea.x = 0; _clientArea.y = 0; @@ -1811,16 +1803,23 @@ class ToolButton : Button { painter.fillColor = Color.white; painter.outlineColor = Color.white; - painter.drawRectangle(Point(6, 3) * multiplier, Point(9, 5) * multiplier); - painter.drawRectangle(Point(5, 9) * multiplier, Point(10, 12) * multiplier); + // the slider + painter.drawRectangle(Point(5, 2) * multiplier, Point(10, 5) * multiplier); + // the label + painter.drawRectangle(Point(4, 8) * multiplier, Point(11, 12) * multiplier); + + painter.fillColor = Color.black; + painter.outlineColor = Color.black; + // the disc window + painter.drawRectangle(Point(8, 3) * multiplier, Point(9, 4) * multiplier); break; case GenericIcons.Open: painter.fillColor = Color.white; painter.drawPolygon( Point(2, 4) * multiplier, Point(2, 12) * multiplier, Point(13, 12) * multiplier, Point(13, 3) * multiplier, Point(9, 3) * multiplier, Point(9, 4) * multiplier, Point(2, 4) * multiplier); - painter.drawLine(Point(3, 6) * multiplier, Point(9, 6) * multiplier); - painter.drawLine(Point(9, 7) * multiplier, Point(13, 7) * multiplier); + painter.drawLine(Point(2, 6) * multiplier, Point(13, 7) * multiplier); + //painter.drawLine(Point(9, 6) * multiplier, Point(13, 7) * multiplier); break; case GenericIcons.Copy: painter.fillColor = Color.white; @@ -1839,7 +1838,7 @@ class ToolButton : Button { painter.drawRectangle(Point(2, 3) * multiplier, Point(11, 11) * multiplier); painter.drawRectangle(Point(6, 8) * multiplier, Point(13, 13) * multiplier); painter.drawLine(Point(6, 2) * multiplier, Point(4, 5) * multiplier); - painter.drawLine(Point(7, 2) * multiplier, Point(9, 5) * multiplier); + painter.drawLine(Point(6, 2) * multiplier, Point(9, 5) * multiplier); painter.fillColor = Color.black; painter.drawRectangle(Point(4, 5) * multiplier, Point(9, 6) * multiplier); break; @@ -2025,7 +2024,9 @@ class StatusBar : Widget { int remainingLength = this.width; foreach(idx, part; this.partsArray) { auto partWidth = part.width ? part.width : ((idx + 1 == this.partsArray.length) ? remainingLength : 100); + painter.setClipRectangle(Point(cpos, 0), partWidth, height); draw3dFrame(cpos, 0, partWidth, height, painter, FrameStyle.sunk); + painter.setClipRectangle(Point(cpos + 2, 2), partWidth - 4, height - 4); painter.drawText(Point(cpos + 4, 0), part.content, Point(width, height), TextAlignment.VerticalCenter); cpos += partWidth; remainingLength -= partWidth; diff --git a/simpledisplay.d b/simpledisplay.d index 685adf3..26ab3d4 100644 --- a/simpledisplay.d +++ b/simpledisplay.d @@ -4135,8 +4135,16 @@ struct ScreenPainter { window.activeScreenPainter = impl; // writeln("constructed"); } + + originalPen = impl._activePen; + originalFillColor = impl._fillColor; + originalClipRectangle = impl._clipRectangle; } + private Pen originalPen; + private Color originalFillColor; + private arsd.color.Rectangle originalClipRectangle; + ~this() { impl.referenceCount--; //writeln("refcount -- ", impl.referenceCount); @@ -4144,6 +4152,13 @@ struct ScreenPainter { //writeln("destructed"); impl.dispose(); window.activeScreenPainter = null; + } else { + // there is still an active reference, reset stuff so the + // next user doesn't get weirdness via the reference + this.rasterOp = RasterOp.normal; + pen = originalPen; + fillColor = originalFillColor; + impl.setClipRectangle(originalClipRectangle.left, originalClipRectangle.top, originalClipRectangle.width, originalClipRectangle.height); } } @@ -4152,6 +4167,18 @@ struct ScreenPainter { //writeln("refcount ++ ", impl.referenceCount); } + /// Sets the clipping region for drawing. If width == 0 && height == 0, disabled clipping. + void setClipRectangle(Point pt, int width, int height) { + transform(pt); + + impl.setClipRectangle(pt.x, pt.y, width, height); + } + + /// ditto + void setClipRectangle(arsd.color.Rectangle rect) { + setClipRectangle(rect.upperLeft, rect.width, rect.height); + } + /// void setFont(OperatingSystemFont font) { impl.setFont(font); @@ -4162,14 +4189,23 @@ struct ScreenPainter { return impl.fontHeight(); } + private Pen activePen; + + int originX; + int originY; + /// @property void pen(Pen p) { + activePen = p; impl.pen(p); } /// @property void outlineColor(Color c) { - impl.outlineColor(c); + if(activePen.color == c) + return; + activePen.color = c; + impl.pen(activePen); } /// @@ -4187,9 +4223,6 @@ struct ScreenPainter { p.y += originY; } - int originX; - int originY; - void updateDisplay() { // FIXME this should do what the dtor does } @@ -5190,6 +5223,21 @@ version(Windows) { SelectObject(hdc, defaultGuiFont); } + arsd.color.Rectangle _clipRectangle; + + void setClipRectangle(int x, int y, int width, int height) { + _clipRectangle = arsd.color.Rectangle(Point(x, y), Size(width, height)); + + if(width == 0 || height == 0) { + SelectClipRgn(hdc, null); + } else { + auto region = CreateRectRgn(x, y, x + width, y + height); + SelectClipRgn(hdc, region); + DeleteObject(region); + } + } + + // just because we can on Windows... //void create(Image image); @@ -5255,11 +5303,6 @@ version(Windows) { } - @property void outlineColor(Color c) { - _activePen.color = c; - pen = _activePen; - } - @property void rasterOp(RasterOp op) { int mode; final switch(op) { @@ -5275,9 +5318,11 @@ version(Windows) { HBRUSH originalBrush; HBRUSH currentBrush; + Color _fillColor = Color(1, 1, 1, 1); // what are the odds that they'd set this?? @property void fillColor(Color c) { - // FIXME: we probably don't need to call all this if the brush - // is already good + if(c == _fillColor) + return; + _fillColor = c; HBRUSH brush; if(c.a == 0) { brush = GetStockObject(HOLLOW_BRUSH); @@ -5326,10 +5371,15 @@ version(Windows) { } Size textSize(string text) { + bool dummyX; + if(text.length == 0) { + text = " "; + dummyX = true; + } RECT rect; WCharzBuffer buffer = WCharzBuffer(text); DrawTextW(hdc, buffer.ptr, cast(int) buffer.length, &rect, DT_CALCRECT); - return Size(rect.right, rect.bottom); + return Size(dummyX ? 0 : rect.right, rect.bottom); } void drawText(int x, int y, int x2, int y2, scope const(char)[] text, uint alignment) { @@ -6214,6 +6264,19 @@ version(X11) { } } + arsd.color.Rectangle _clipRectangle; + void setClipRectangle(int x, int y, int width, int height) { + _clipRectangle = arsd.color.Rectangle(Point(x, y), Size(width, height)); + if(width == 0 || height == 0) + XSetClipMask(display, gc, None); + else { + XRectangle[1] rects; + rects[0] = XRectangle(cast(short)(x), cast(short)(y), cast(short) width, cast(short) height); + XSetClipRectangles(XDisplayConnection.get, gc, 0, 0, rects.ptr, 1, 0); + } + } + + void setFont(OperatingSystemFont font) { if(font && font.font) { this.font = font.font; @@ -6254,13 +6317,13 @@ version(X11) { bool backgroundIsNotTransparent = true; bool foregroundIsNotTransparent = true; - Pen _pen; + Pen _activePen; Color _outlineColor; Color _fillColor; @property void pen(Pen p) { - _pen = p; + _activePen = p; _outlineColor = p.color; int style; @@ -6289,13 +6352,6 @@ version(X11) { cast(uint) p.color.b); } - @property void outlineColor(Color c) { - if(_pen.color == c) - return; // don't double call for performance - _pen.color = c; - pen = _pen; - } - @property void rasterOp(RasterOp op) { int mode; final switch(op) { @@ -6332,7 +6388,8 @@ version(X11) { void swapColors() { auto tmp = _fillColor; fillColor = _outlineColor; - outlineColor = tmp; + _activePen.color = tmp; + pen(_activePen); } void drawImage(int x, int y, Image i, int ix, int iy, int w, int h) { @@ -10940,6 +10997,7 @@ mixin template ExperimentalTextComponent() { } void drawInto(ScreenPainter painter, bool focused = false) { + painter.setClipRectangle(boundingBox); auto pos = Point(boundingBox.left, boundingBox.top); int lastHeight; @@ -11001,6 +11059,7 @@ mixin template ExperimentalTextComponent() { int caratLastDrawnX, caratLastDrawnY1, caratLastDrawnY2; bool caratShowingOnScreen = false; void drawCarat(ScreenPainter painter) { + painter.setClipRectangle(boundingBox); int x, y1, y2; if(carat.inlineElement is null) { x = boundingBox.left; @@ -11032,6 +11091,7 @@ mixin template ExperimentalTextComponent() { } void eraseCarat(ScreenPainter painter) { + painter.setClipRectangle(boundingBox); if(!caratShowingOnScreen) return; painter.pen = Pen(Color.white, 1); painter.rasterOp = RasterOp.xor;