From 1a849c1970739cf4c30f424130cbb510ccd194a2 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Tue, 3 Jun 2014 14:30:47 +0400 Subject: [PATCH] grids: continue development; simple grid content is shown --- src/dlangui/core/types.d | 12 +++ src/dlangui/graphics/drawbuf.d | 1 + src/dlangui/widgets/grid.d | 131 ++++++++++++++++++++++++++++----- src/dlangui/widgets/widget.d | 10 ++- 4 files changed, 131 insertions(+), 23 deletions(-) diff --git a/src/dlangui/core/types.d b/src/dlangui/core/types.d index 7a90cd6c..dbafdc6c 100644 --- a/src/dlangui/core/types.d +++ b/src/dlangui/core/types.d @@ -63,6 +63,18 @@ struct Rect { top += dy; bottom += dy; } + void expand(int dx, int dy) { + left -= dx; + right += dx; + top -= dy; + bottom += dy; + } + void shrink(int dx, int dy) { + left += dx; + right -= dx; + top += dy; + bottom -= dy; + } /// for all fields, sets this.field to rc.field if rc.field > this.field void setMax(Rect rc) { if (left < rc.left) diff --git a/src/dlangui/graphics/drawbuf.d b/src/dlangui/graphics/drawbuf.d index cc58b6a6..ae66ea23 100644 --- a/src/dlangui/graphics/drawbuf.d +++ b/src/dlangui/graphics/drawbuf.d @@ -407,6 +407,7 @@ struct ClipRectSaver { private DrawBuf _buf; private Rect _oldClipRect; private uint _oldAlpha; + /// apply (intersect) new clip rectangle and alpha to draw buf; restore this(DrawBuf buf, ref Rect newClipRect, uint newAlpha = 0) { _buf = buf; _oldClipRect = buf.clipRect; diff --git a/src/dlangui/widgets/grid.d b/src/dlangui/widgets/grid.d index 5438dd0a..314b32d6 100644 --- a/src/dlangui/widgets/grid.d +++ b/src/dlangui/widgets/grid.d @@ -134,6 +134,7 @@ class StringGridWidget : GridWidgetBase { addChild(_vscrollbar); addChild(_hscrollbar); styleId = "EDIT_BOX"; + resize(20, 30); } @property override int cols() { return _cols; @@ -174,6 +175,18 @@ class StringGridWidget : GridWidgetBase { _data[row][col] = text; return this; } + + /// zero based index generation of column header - like in Excel - for testing + dstring genColHeader(int col) { + dstring res; + int n1 = col / 26; + int n2 = col % 26; + if (n1) + res ~= n1 + 'A'; + res ~= n2 + 'A'; + return res; + } + /// set new size void resize(int cols, int rows) { if (cols == _cols && rows == _rows) @@ -186,23 +199,36 @@ class StringGridWidget : GridWidgetBase { _colTitles[i] = i > 0 ? ("col "d ~ to!dstring(i)) : ""d; _rowTitles.length = rows; _colWidths.length = cols; - for (int i = _cols; i < cols; i++) - _colWidths[i] = i == 0 ? 10 : 80; + for (int i = _cols; i < cols; i++) { + if (i >= _headerCols) + _data[0][i] = genColHeader(i - _headerCols); + _colWidths[i] = i == 0 ? 20 : 80; + } _rowHeights.length = rows; int fontHeight = font.height; - for (int i = _rows; i < rows; i++) - _rowHeights[i] = fontHeight; + for (int i = _rows; i < rows; i++) { + if (i >= _headerRows) + _data[i][0] = to!dstring(i - _headerRows + 1); + _rowHeights[i] = fontHeight + 2; + } _cols = cols; _rows = rows; } - /// returns column width (col 0 is row header) + + /// returns column width (index includes col/row headers, if any); returns 0 for columns hidden by scroll at the left int colWidth(int x) { + if (x >= _headerCols + _fixedCols && x < _headerCols + _fixedCols + _scrollCol) + return 0; return _colWidths[x]; } - /// returns row height (row 0 is column header) + + /// returns row height (index includes col/row headers, if any); returns 0 for riws hidden by scroll at the top int rowHeight(int y) { + if (y >= _headerRows + _fixedRows && y < _headerRows + _fixedRows + _scrollRow) + return 0; return _rowHeights[y]; } + /// returns cell rectangle relative to client area; row 0 is col headers row; col 0 is row headers column Rect cellRect(int x, int y) { Rect rc; @@ -248,23 +274,19 @@ class StringGridWidget : GridWidgetBase { } /// draw column header void drawColHeader(DrawBuf buf, Rect rc, int index) { - FontRef fnt = font; - buf.fillRect(rc, 0xE0E0E0); - buf.drawFrame(rc, 0x808080, Rect(1,1,1,1)); - fnt.drawText(buf, rc.left, rc.top, "col"d, 0x000000); + //FontRef fnt = font; + //buf.fillRect(rc, 0xE0E0E0); + //buf.drawFrame(rc, 0x808080, Rect(1,1,1,1)); + //fnt.drawText(buf, rc.left, rc.top, "col"d, 0x000000); } /// draw row header void drawRowHeader(DrawBuf buf, Rect rc, int index) { - FontRef fnt = font; - buf.fillRect(rc, 0xE0E0E0); - buf.drawFrame(rc, 0x808080, Rect(1,1,1,1)); - fnt.drawText(buf, rc.left, rc.top, "row"d, 0x000000); - } - /// draw cell header - void drawCell(DrawBuf buf, Rect rc, int col, int row) { - FontRef fnt = font; - fnt.drawText(buf, rc.left, rc.top, "sample"d, 0x000000); + //FontRef fnt = font; + //buf.fillRect(rc, 0xE0E0E0); + //buf.drawFrame(rc, 0x808080, Rect(1,1,1,1)); + //fnt.drawText(buf, rc.left, rc.top, "row"d, 0x000000); } + /// Measure widget according to desired width and height constraints. (Step 1 of two phase layout). override void measure(int parentWidth, int parentHeight) { Rect m = margins; @@ -306,8 +328,77 @@ class StringGridWidget : GridWidgetBase { _clientRect.right = vsbrc.left; _clientRect.bottom = hsbrc.top; } + + /// draw cell content + void drawCell(DrawBuf buf, Rect rc, int col, int row) { + rc.shrink(1, 1); + FontRef fnt = font; + dstring txt = cellText(col, row); + Point sz = fnt.textSize(txt); + Align ha = Align.Left; + if (col < _headerCols) + ha = Align.Right; + if (row < _headerRows) + ha = Align.HCenter; + applyAlign(rc, sz, ha, Align.VCenter); + fnt.drawText(buf, rc.left + 1, rc.top + 1, txt, 0x000000); + } + + /// draw cell background + void drawCellBackground(DrawBuf buf, Rect rc, int col, int row) { + Rect vborder = rc; + Rect hborder = rc; + vborder.left = vborder.right - 1; + hborder.top = hborder.bottom - 1; + hborder.right--; + if (col < _headerCols || row < _headerRows) { + // draw header cell background + buf.fillRect(rc, 0x80808080); + buf.fillRect(vborder, 0x80FFFFFF); + buf.fillRect(hborder, 0x80FFFFFF); + } else { + // normal cell background + buf.fillRect(vborder, 0x80C0C0C0); + buf.fillRect(hborder, 0x80C0C0C0); + } + } + void drawClient(DrawBuf buf) { - buf.fillRect(_clientRect, 0x80A08080); + auto saver = ClipRectSaver(buf, _clientRect, 0); + //buf.fillRect(_clientRect, 0x80A08080); + Rect rc; + for (int phase = 0; phase < 2; phase++) { + int yy = 0; + for (int y = 0; y < _rows; y++) { + int rh = rowHeight(y); + rc.top = yy; + rc.bottom = yy + rh; + if (rh == 0) + continue; + if (yy > _clientRect.height) + break; + yy += rh; + int xx = 0; + for (int x = 0; x < _cols; x++) { + int cw = colWidth(x); + rc.left = xx; + rc.right = xx + cw; + if (cw == 0) + continue; + if (xx > _clientRect.width) + break; + xx += cw; + // draw cell + Rect cellRect = rc; + cellRect.moveBy(_clientRect.left, _clientRect.top); + auto cellSaver = ClipRectSaver(buf, cellRect, 0); + if (phase == 0) + drawCellBackground(buf, cellRect, x, y); + else + drawCell(buf, cellRect, x, y); + } + } + } } /// Draw widget at its position to buffer override void onDraw(DrawBuf buf) { diff --git a/src/dlangui/widgets/widget.d b/src/dlangui/widgets/widget.d index 18742806..b1848bad 100644 --- a/src/dlangui/widgets/widget.d +++ b/src/dlangui/widgets/widget.d @@ -1086,9 +1086,7 @@ class Widget { rc.right -= m.right; } /// Applies alignment for content of size sz - set rectangle rc to aligned value of content inside of initial value of rc. - void applyAlign(ref Rect rc, Point sz) { - Align va = valign; - Align ha = halign; + static void applyAlign(ref Rect rc, Point sz, Align ha, Align va) { if (va == Align.Bottom) { rc.top = rc.bottom - sz.y; } else if (va == Align.VCenter) { @@ -1108,6 +1106,12 @@ class Widget { rc.right = rc.left + sz.x; } } + /// Applies alignment for content of size sz - set rectangle rc to aligned value of content inside of initial value of rc. + void applyAlign(ref Rect rc, Point sz) { + Align va = valign; + Align ha = halign; + applyAlign(rc, sz, ha, va); + } // =========================================================== // popup menu support