ultimatepp/uppsrc/CtrlLib/CtrlLib.usc
2022-05-08 08:48:22 +02:00

1665 lines
36 KiB
Text

namespace Upp;
enum_property Frame {
"NullFrame()",
"FieldFrame()",
"InsetFrame()",
"OutsetFrame()",
"ButtonFrame()",
"ThinInsetFrame()",
"ThinOutsetFrame()",
"BlackFrame()",
"TopSeparatorFrame()",
"BottomSeparatorFrame()",
"LeftSeparatorFrame()",
"RightSeparatorFrame()",
"default"
};
enum_property Align {
"ALIGN_LEFT",
"ALIGN_CENTER",
"ALIGN_RIGHT"
};
fn IsUHD()
{
return GetTextSize("X", StdFont()).cy > 24;
}
fn DeflateRect(&r)
{
r.top++;
r.left++;
r.right--;
r.bottom--;
}
fn DrawFrame(w, &r, c1, c2) {
w.DrawRect(r.left, r.top, r.right - r.left, 1, c1);
w.DrawRect(r.left, r.top, 1, r.bottom - r.top, c1);
w.DrawRect(r.right - 1, r.top, 1, r.bottom - r.top, c2);
w.DrawRect(r.left, r.bottom - 1, r.right - r.left, 1, c2);
DeflateRect(r);
}
fn DrawBorder(w, &r, ...)
{
for(i = 0; i < count(argv); i += 2)
DrawFrame(w, r, argv[i], argv[i + 1]);
}
fn DrawButtonFrame(w, &r)
{
if(IsUHD())
DrawBorder(w, r, :Gray, :Gray, :Gray, :Gray);
else
DrawBorder(w, r, :Gray, :Gray);
}
fn DrawEdgeButtonFrame(w, &r)
{
DrawBorder(w, r, :SWhite, :SWhite, :Gray, :Gray);
}
fn DrawButton(w, r)
{
w.DrawRect(r, :SWhiteGray);
DrawButtonFrame(w, r);
}
fn DrawEdgeButton(w, &r)
{
DrawEdgeButtonFrame(w, r);
w.DrawRect(r, :SLtGray);
}
fn DrawInsetFrame(w, &r)
{
DrawButtonFrame(w, r);
}
fn DrawCtrlFrame(w, &r, frame)
{
width = r.right - r.left;
height = r.bottom - r.top;
switch(frame) {
case "FieldFrame()":
case "default": IsUHD() ? DrawBorder(w, r, :SGray, :SGray, :SGray, :SGray) : DrawBorder(w, r, :SGray, :SGray); break;
case "InsetFrame()": DrawBorder(w, r, :Gray, :White, :Black, :LtGray); break;
case "OutsetFrame()": DrawBorder(w, r, :LtGray, :Black, :White, :Gray); break;
case "ButtonFrame()": DrawButtonFrame(w, r); break;
case "ThinInsetFrame()": DrawBorder(w, r, :Gray, :White); break;
case "ThinOutsetFrame()": DrawBorder(w, r, :White, :Gray); break;
case "BlackFrame()": DrawBorder(w, r, :SBlack, :SBlack); break;
case "TopSeparatorFrame()":
w.DrawRect(r.left, r.top, width, 1, :Gray);
w.DrawRect(r.left, r.top + 1, width, 1, :White);
r.top += 2;
break;
case "BottomSeparatorFrame()":
w.DrawRect(r.left, r.bottom - 2, width, 1, :Gray);
w.DrawRect(r.left, r.bottom - 1, width, 1, :White);
r.bottom -= 2;
break;
case "LeftSeparatorFrame()":
w.DrawRect(r.left, r.top, 1, height, :Gray);
w.DrawRect(r.left + 1, r.top, 1, height, :White);
r.left += 2;
break;
case "RightSeparatorFrame()":
w.DrawRect(r.right - 2, r.top, 1, height, :Gray);
w.DrawRect(r.right - 1, r.top, 1, height, :White);
r.right -= 2;
break;
}
}
fn GradientColor(fc, tc, i, n)
{
return Color(
fc.r + i * (tc.r - fc.r) / n,
fc.g + i * (tc.g - fc.g) / n,
fc.b + i * (tc.b - fc.b) / n
);
}
fn max(a, b)
{
return a > b ? a : b;
}
fn min(a, b)
{
return a < b ? a : b;
}
fn abs(a)
{
return a < 0 ? -a : a;
}
fn atoi(a)
{
n = 0;
for(i = 0; i < count(a); i++)
n = 10 * n + a[i] - '0';
return n;
}
fn DrawVertArrowFromTip(w, tipx, tipy, dir, l, color)
{
for(i = 0; i < l; i++) {
w.DrawRect(tipx - i, tipy, 2 * i + 1, 1, color);
tipy += dir;
}
}
fn DrawVertArrow(ww, r, size, dir)
{
w = r.right - r.left;
h = r.bottom - r.top;
y = r.top + (h - size) / 2;
DrawVertArrowFromTip(ww, r.left + w / 2, dir > 0 ? y : y + size, dir, size, :SBlack);
}
fn DrawSpinButtons(w, r)
{
h = r.bottom - r.top;
h2 = int(h / 2);
h7 = int(7 * h / 10);
x = r.right - h7;
ah = int(h / 6);
ax = x + h7 / 2;
rr = RectC(x, r.top, h7, h2);
DrawEdgeButton(w, rr);
DrawVertArrow(w, rr, h / 6, 1);
rr = RectC(x, r.top + h2, h7, h - h2);
DrawEdgeButton(w, rr);
DrawVertArrow(w, rr, h / 6, -1);
}
fn XMinSize()
{
return Size(8, 13);
}
subctrl NormalSize {
GetMinSize() { sz = XMinSize(); sz.cy += 2; return sz; }
GetStdSize() { sz = GetMinSize(); sz.cx *= 7; return sz; }
};
subctrl Base {
>NormalSize;
Font SetFont = StdFont();
Color SetInk = :SBlack;
Frame SetFrame @1;
// Qtf SetInfo @1 ? "Info of control" ;
ViewRect(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
return r;
}
ViewSize(w) {
r = ViewRect(w);
return Size(r.right - r.left, r.bottom - r.top);
}
};
subctrl Unknown {
> Base;
};
subctrl TextCtrl {
GetMinSize() { sz = XMinSize(); sz.cy += 2; return sz; }
GetStdSize() { sz = GetMinSize(); sz.cx *= 8; return sz; }
Text SetLabel @1 ? "Label of control" ;
ViewRect(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
return r;
}
ViewSize(w) {
r = ViewRect(w);
return Size(r.right - r.left, r.bottom - r.top);
}
Paint(w) {
sz = ViewSize(w);
textsize = GetSmartTextSize(.SetLabel, .SetFont);
px = 0;
if(.SetAlign == "ALIGN_CENTER")
px = (sz.cx - textsize.cx) / 2;
if(.SetAlign == "ALIGN_RIGHT")
px = sz.cx - textsize.cx;
w.DrawSmartText(px, (sz.cy - textsize.cy) / 2, .SetLabel, .SetFont, .SetInk, sz.cx);
}
};
ctrl Label {
group "Static";
GetMinSize() { return XMinSize(); }
GetStdSize() { sz = GetMinSize(); sz.cy += 6; sz.cx *= 5; return sz; }
>TextCtrl;
Doc SetLabel @0 ? "Label of control";
Align SetAlign = ALIGN_LEFT @2;
Font SetFont = StdFont() @2;
Color SetInk = :SBlack @2;
Frame SetFrame @3;
// Qtf SetInfo @1 ? "Info of control" ;
Paint(w) {
sz = ViewSize(w);
textsize = GetSmartTextSize(.SetLabel, .SetFont);
px = 0;
if(.SetAlign == "ALIGN_CENTER")
px = (sz.cx - textsize.cx) / 2;
if(.SetAlign == "ALIGN_RIGHT")
px = sz.cx - textsize.cx;
w.DrawSmartText(px, (sz.cy - textsize.cy) / 2, .SetLabel, .SetFont, .SetInk, sz.cx);
}
Sample() {
.SetLabel = "Label";
.SetFont = Arial(10).Bold().Italic();
}
};
ctrl StaticText {
group "Static";
GetMinSize() { return XMinSize(); }
GetStdSize() { sz = XMinSize(); sz.cy += 6; sz.cx *= 5; return sz; }
Doc SetText ? "Label of control" ;
Align SetAlign = ALIGN_LEFT;
Font SetFont = StdFont();
Color SetInk = :SBlack;
Frame SetFrame @1;
// Qtf SetInfo @1 ? "Info of control" ;
ViewRect(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
return r;
}
ViewSize(w) {
r = ViewRect(w);
return Size(r.right - r.left, r.bottom - r.top);
}
Paint(w) {
sz = ViewSize(w);
textsize = GetSmartTextSize(.SetText, .SetFont);
px = 0;
if(.SetAlign == "ALIGN_CENTER")
px = (sz.cx - textsize.cx) / 2;
if(.SetAlign == "ALIGN_RIGHT")
px = sz.cx - textsize.cx;
w.DrawSmartText(px, (sz.cy - textsize.cy) / 2, .SetText, .SetFont, .SetInk);
}
Sample() {
.SetText = "Text";
.SetFont = Arial(10).Bold().Italic();
}
};
ctrl LabelBox {
group "Static";
GetMinSize() { return Size(0, 0); }
GetStdSize() { return Size(64, 24); }
>Base;
Text SetLabel ? "Box label" ;
Paint(w) {
sz = GetSize();
ts = GetSmartTextSize(.SetLabel, .SetFont);
d = ts.cy / 2;
if(2 * GetSmartTextSize("X").cy > sz.cy) {
d = sz.cy / 2;
w.DrawSmartText(d, (sz.cy - ts.cy) / 2, .SetLabel, .SetFont, .SetInk, sz.cx);
w.DrawRect(1, d, d - 1, 1, :Gray);
w.DrawRect(1, d + 1, d - 1, 1, :Gray);
w.DrawRect(d + ts.cx, d, sz.cx - ts.cx - d - 2, 1, :Gray);
w.DrawRect(d + ts.cx, d + 1, sz.cx - ts.cx - d - 2, 1, :Gray);
}
else {
d = ts.cy / 2;
DrawButtonFrame(w, RectC(0, d, sz.cx, sz.cy - d));
w.DrawRect(8, 0, ts.cx + 4, ts.cy, :SLtGray);
w.DrawSmartText(10, 0, .SetLabel, .SetFont);
}
}
}
fn DrawClassName(w, r, text)
{
font = Arial(10);
sz = GetTextSize(text, font);
w.DrawRect(r.right - sz.cx - sz.cy, r.bottom - sz.cy, sz.cx + 2 * sz.cy, sz.cy, :SGray);
w.DrawText(r.right - sz.cx - sz.cy / 2, r.bottom - sz.cy, text, font, :SYellow);
}
ctrl ParentCtrl {
group "Special";
GetMinSize() { return Size(0, 0); }
GetStdSize() { return Size(64, 24); }
Frame SetFrame @3;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
DrawBorder(w, r, :SGray, :SGray);
DrawClassName(w, r, "ParentCtrl");
}
Sample() {}
};
ctrl ImageCtrl {
group "Static";
GetMinSize() { return Size(0, 0); }
GetStdSize() { return Size(64, 24); }
Frame SetFrame @3;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
DrawBorder(w, r, :SGray, :SGray);
DrawClassName(w, r, "ImageCtrl");
}
Sample() {}
};
ctrl DrawingCtrl {
group "Static";
GetMinSize() { return Size(0, 0); }
GetStdSize() { return Size(64, 24); }
Frame SetFrame @3;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
DrawBorder(w, r, :SGray, :SGray);
DrawClassName(w, r, "DrawingCtrl");
}
Sample() {}
};
ctrl StaticRect {
group "Static";
GetMinSize() { return Size(0, 0); }
GetStdSize() { return Size(64, 24); }
Color SetPaper = :SLtBlue @2;
Frame SetFrame @3;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
w.DrawRect(r, .SetPaper);
DrawBorder(w, r, :SGray, :SGray);
DrawClassName(w, r, "StaticRect");
}
Sample() {}
};
ctrl DataPusher {
group "Push";
GetStdSize() { return Size(64, 24); }
>Base;
Frame SetFrame = default;
bool SetEditable = true @1;
Text Tip @1;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
w.DrawRect(r, :SWhite);
}
};
ctrl ColorPusher {
group "Push";
GetStdSize() { return Size(64, 24); }
>Base;
Frame SetFrame = default;
bool SetEditable = true @1;
Text Tip @1;
bool NotNull = false;
bool WithVoid = false;
bool SColors = false;
bool WithText = false;
bool WithHex = false;
bool Track = false;
bool NoRampWheel = false;
Text NullText;
Text VoidText;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
w.DrawRect(r, :SWhite);
DeflateRect(r);
w.DrawRect(r, :LtBlue);
DrawFrame(w, r, :SBlack, :SBlack);
if(.WithText || .WithHex) {
text = .WithText ? "LtBlue" : "#0000FF";
w.DrawText(r.left + 6, (r.top + r.bottom - GetSmartTextSize(text, StdFont()).cy) / 2,
text, StdFont(), :White);
}
}
};
ctrl Button {
group "Push";
GetMinSize() { sz = XMinSize(); sz.cy += 2; return sz; }
GetStdSize() { sz = GetMinSize(); sz.cx *= 7; return sz; }
Text SetLabel ? "Button label";
Font SetFont = StdFont();
Frame SetFrame @1;
Text Tip @1;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
DrawButtonFrame(w, r);
sz = Size(r.right - r.left, r.bottom - r.top);
n = int(sz.cy / 8);
w.DrawRect(r.left, r.top, sz.cx, sz.cy, :SWhiteGray);
textsize = GetSmartTextSize(.SetLabel, .SetFont);
py = (sz.cy - textsize.cy) / 2;
if(count(.SetLabel) && (.SetLabel)[0] == 1)
w.DrawSmartText(r.left, r.top + py, .SetLabel, .SetFont, :SBlack, sz.cx);
else {
px = (sz.cx - textsize.cx) / 2;
w.DrawSmartText(px + r.left, py + r.top, .SetLabel, .SetFont, :SBlack, sz.cx);
}
}
}
fn DrawCircle(w, xx, yy, c, color)
{
if(c > 15) {
w.DrawRect(xx + 5, yy, c - 10, c, color);
w.DrawRect(xx, yy + 5, c, c - 10, color);
w.DrawRect(xx + 3, yy + 1, c - 6, c - 2, color);
w.DrawRect(xx + 1, yy + 3, c - 2, c - 6, color);
w.DrawRect(xx + 2, yy + 2, c - 4, c - 4, color);
}
else {
w.DrawRect(xx + 2, yy, c - 4, c, color);
w.DrawRect(xx, yy + 2, c, c - 4, color);
w.DrawRect(xx + 1, yy + 1, c - 2, c - 2, color);
}
}
fn OptionSize()
{
return IsUHD() ? 24 : 11;
}
fn DrawOption(w, x, y, kind)
{
osz = OptionSize();
if(kind == 2) {
DrawCircle(w, x, y, osz, :Gray);
if(osz > 15)
DrawCircle(w, x + 2, y + 2, osz - 4, :SWhite);
else
DrawCircle(w, x + 1, y + 1, osz - 2, :SWhite);
}
else {
r = RectC(x, y, osz, osz);
w.DrawRect(r, :SWhite);
if(osz > 15) {
DrawButtonFrame(w, r);
if(kind == 1)
w.DrawRect(x + 4, y + osz / 2 - 1, osz - 8, 2, :SBlack);
}
else {
DrawBorder(w, r, :Gray, :Gray);
if(kind == 1)
w.DrawRect(x + 3, y + osz / 2 - 1, osz - 6, 2, :SBlack);
}
}
}
ctrl Option {
group "Push";
Text SetLabel @1 ? "Option text";
Font SetFont = StdFont() @1;
Frame SetFrame @2;
bool Box;
bool AutoBox;
bool BlackEdge;
bool SwitchImage;
bool SetEditable = true @1 ? "Editable";
bool ThreeState;
bool NotNull;
Text Tip @2;
GetMinSize() { sz = XMinSize(); sz.cy += 2; return sz; }
GetStdSize() { sz = GetMinSize(); sz.cx *= 7; sz.cy = max(16, sz.cy); return sz; }
ViewRect(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
return r;
}
ViewSize(w) {
r = ViewRect(w);
return Size(r.right - r.left, r.bottom - r.top);
}
Paint(w) {
sz = ViewSize(w);
kind = .SwitchImage ? 2 : .ThreeState ? 1 : 0;
osz = OptionSize();
textsize = GetSmartTextSize(.SetLabel, .SetFont);
if(.Box || .AutoBox) {
d = textsize.cy / 2;
DrawButtonFrame(w, RectC(0, d, sz.cx, sz.cy - d));
d = (textsize.cy - osz) / 2;
w.DrawRect(8, 0, osz + textsize.cx + 8, textsize.cy, :SLtGray);
DrawOption(w, 10, d, kind);
w.DrawSmartText(osz + 14, 0, .SetLabel, .SetFont);
}
else {
DrawOption(w, 0, (sz.cy - osz) / 2, kind);
w.DrawSmartText(osz + 4, (sz.cy - textsize.cy) / 2, .SetLabel, .SetFont);
}
}
}
ctrl OptionBox {
> Option;
bool Box = true;
}
ctrl Switch {
group "Push";
GetMinSize() { sz = XMinSize(); sz.cy += 2; return sz; }
GetStdSize() { sz = GetMinSize(); sz.cx *= 7; sz.cy = max(16, sz.cy); return sz; }
Doc SetLabel;
Font SetFont = StdFont();
bool SetEditable = true @1 ? "Editable";
// Qtf SetInfo @1 ? "Info of control" ;
Paint(w)
{
sz = GetSize();
ln = [];
cs = [];
gap = [];
sep = [];
g = 0;
sp = 0;
n = count(.SetLabel);
for(i = 0; i < n; i++) {
ch = .SetLabel[i];
if(ch == '^') {
if(i + 1 < n && .SetLabel[i + 1] == '^') {
ln[] = '^';
ln[] = '^';
i++;
}
else {
g = atoi(ln);
ln = "";
}
}
else
if(ch == '|') {
if(i + 1 < n && .SetLabel[i + 1] == '|') {
ln[] = '|';
ln[] = '|';
i++;
}
else {
g = atoi(ln);
ln = "";
sp = 1;
}
}
else
if(ch >= 32 && ch < 65536) {
ln[] = ch;
}
else
if(ch == '\n') {
cs[] = ln;
gap[] = g;
sep[] = sp;
ln = "";
g = 0;
}
}
cs[] = ln;
gap[] = g;
sep[] = sp;
tcy = GetTextSize("W", .SetFont).cy;
linecy = max(16, tcy + 2);
osz = OptionSize();
setlabel = .SetLabel;
horz = 0;
for(pass = 0; pass < 2; pass++) {
y = 0;
x = 0;
for(i = 0; i < count(cs); i++) {
textsize = GetSmartTextSize(cs[i], .SetFont);
if(gap[i]) {
gsz = gap[i] * tcy / 4;
if(sep[i] && pass) {
if(horz)
w.DrawRect(x + y + gsz / 2, y, 1 + IsUHD(), linecy, :SGray);
else
w.DrawRect(x, y + gsz / 2, sz.cx, 1 + IsUHD(), :SGray);
}
if(horz)
x += gsz;
else
y += gsz;
}
if(horz) {
if(pass) {
DrawOption(w, x, (sz.cy - osz) / 2, 2);
w.DrawSmartText(x + osz + 4, (sz.cy - tcy) / 2, cs[i], .SetFont);
}
x += osz + 4 + textsize.cx + tcy / 2;
}
else {
if(pass) {
DrawOption(w, x, y, 2);
w.DrawSmartText(x + osz + 4, y + (osz - tcy) / 2, cs[i], .SetFont);
}
y += linecy;
}
}
if(y > sz.cy)
horz = 1;
}
}
};
ctrl EditField {
group "Input fields";
GetMinSize() { sz = XMinSize(); sz.cy += 6; return sz; }
GetStdSize() { sz = GetMinSize(); sz.cx *= 8; return sz; }
Font SetFont = StdFont() @3;
int MaxChars @2;
bool AlignRight @1;
bool SetEditable = true @4 ? "Editable";
Frame SetFrame = default @5;
Text Tip @5;
bool WantFocus = true @7;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
w.DrawRect(r, :SWhite);
PaintData(w);
}
PaintText(w, text) {
w.DrawText(3, (GetSize().cy - GetTextSize(text, Arial(10)).cy) / 2,
(.SetEditable ? "" : "R/O ") + text, Arial(10), :SMagenta);
}
PaintData(w) {
PaintText(w, "EditField");
}
}
ctrl DocEdit {
group "Editors";
GetMinSize() { sz = XMinSize(); sz.cy += 6; return sz; }
GetStdSize() { sz = GetMinSize(); sz.cx *= 8; return sz; }
Font SetFont = StdFont();
Frame SetFrame = default @1;
bool SetEditable = true @1 ? "Editable";
bool WantFocus = true;
Text Tip @1;
// Qtf SetInfo @1 ? "Info of control" ;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
w.DrawRect(r, :SWhite);
PaintData(w);
}
PaintText(w, text) {
w.DrawText(3, (GetSize().cy - GetTextSize(text, Arial(10)).cy) / 2,
(.SetEditable ? "" : "R/O ") + text, Arial(10), :SMagenta);
}
PaintData(w) {
PaintText(w, "DocEdit");
}
}
ctrl LineEdit {
group "Editors";
GetMinSize() { sz = XMinSize(); sz.cy += 6; return sz; }
GetStdSize() { sz = GetMinSize(); sz.cx *= 8; return sz; }
Font SetFont = StdFont() @3;
// int MaxChars @2;
// bool AlignRight @1;
bool SetEditable = true @4 ? "Editable";
Frame SetFrame = default @5;
Text Tip @5;
bool WantFocus = true @7;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
w.DrawRect(r, :SWhite);
PaintData(w);
}
PaintText(w, text) {
w.DrawText(3, (GetSize().cy - GetTextSize(text, Arial(10)).cy) / 2,
(.SetEditable ? "" : "R/O ") + text, Arial(10), :SMagenta);
}
PaintData(w) {
PaintText(w, "LineEdit");
}
}
subctrl EditNotNull {
>EditField;
bool NotNull = false;
PaintMinMax(w, type, minval, maxval) {
PaintMinMaxText(w, type, minval, maxval, addtext);
}
PaintMinMaxText(w, type, minval, maxval, addtext) {
text = (.NotNull ? "!" : "") + type;
if(minval != "" && maxval != "")
text << " " << minval << "..." << maxval;
else
if(minval != "")
text << " >= " << minval;
else
if(maxval != "")
text << " <= " << maxval;
text << addtext;
PaintText(w, text);
}
}
ctrl EditString {
>EditNotNull;
raw MaxLen;
bool TrimLeft = false;
bool TrimRight = false;
PaintData(w) {
text = (.NotNull ? "!" : "") + "Str";
if(.MaxLen != "")
text << "(" << .MaxLen << ")";
PaintText(w, text);
}
}
ctrl SuggestCtrl {
>EditString;
PaintData(w) {
text = (.NotNull ? "!" : "") + "SuggestCtrl";
if(.MaxLen != "")
text << "(" << .MaxLen << ")";
PaintText(w, text);
}
}
fn IntStr(x)
{
return x == :IntNull || x < :DblNullLim ? "" : to_string(x);
}
fn DblStr(x)
{
return x < :DblNullLim ? "" : to_string(x);
}
ctrl EditInt {
>EditNotNull;
int Min;
int Max;
PaintData(w) { PaintMinMax(w, "int", IntStr(.Min), IntStr(.Max)); }
}
ctrl EditInt64 {
>EditNotNull;
int Min;
int Max;
PaintData(w) { PaintMinMax(w, "int64", IntStr(.Min), IntStr(.Max)); }
}
ctrl EditIntNotNull {
>EditInt;
bool NotNull = true;
};
ctrl EditDouble {
>EditNotNull;
double Min;
double Max;
PaintData(w) { PaintMinMax(w, "dbl", DblStr(.Min), DblStr(.Max)); }
}
ctrl EditDoubleNotNull {
>EditDouble;
bool NotNull = true;
}
ctrl EditFloat {
>EditNotNull;
double Min;
double Max;
PaintData(w) { PaintMinMax(w, "flt", DblStr(.Min), DblStr(.Max)); }
}
ctrl EditFloatNotNull {
>EditFloat;
bool NotNull = true;
}
ctrl EditDate {
>EditNotNull;
PaintData(w) { PaintMinMax(w, "Date", "", ""); }
}
ctrl EditDateNotNull {
>EditDate;
bool NotNull = true;
}
ctrl EditTime {
>EditNotNull;
PaintData(w) { PaintMinMax(w, "Time", "", ""); }
}
ctrl EditTimeNotNull {
>EditTime;
bool NotNull = true;
}
ctrl EditIntSpin {
>EditInt;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
w.DrawRect(r, :SWhite);
DrawSpinButtons(w, r);
PaintMinMax(w, "int", IntStr(.Min), IntStr(.Max));
}
}
ctrl EditInt64Spin {
>EditInt64;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
w.DrawRect(r, :SWhite);
DrawSpinButtons(w, r);
PaintMinMax(w, "int64", IntStr(.Min), IntStr(.Max));
}
}
ctrl EditDoubleSpin {
>EditDouble;
double SetInc = 0.1;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
w.DrawRect(r, :SWhite);
DrawSpinButtons(w, r);
PaintMinMaxText(w, "dbl", DblStr(.Min), DblStr(.Max), "+-" + DblStr(.SetInc));
}
}
ctrl EditFloatSpin {
>EditDoubleSpin;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
w.DrawRect(r, :SWhite);
DrawSpinButtons(w, r);
PaintMinMaxText(w, "flt", DblStr(.Min), DblStr(.Max), "+-" + DblStr(.SetInc));
}
}
ctrl EditDateSpin {
>EditDate;
double SetInc = 1;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
w.DrawRect(r, :SWhite);
DrawSpinButtons(w, r);
PaintMinMaxText(w, "date", DblStr(.Min), DblStr(.Max), "+-" + DblStr(.SetInc));
}
}
ctrl EditTimeSpin {
>EditTime;
double SetInc = 1;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
w.DrawRect(r, :SWhite);
DrawSpinButtons(w, r);
PaintMinMaxText(w, "time", DblStr(.Min), DblStr(.Max), "+-" + DblStr(.SetInc));
}
}
fn DrawArrowButton(w, rr, dir)
{
DrawEdgeButton(w, rr);
DrawVertArrow(w, rr, OptionSize() / 3, dir);
}
fn DrawHArrowButton(w, rr, dir)
{
DrawEdgeButton(w, rr);
DrawHorzArrow(w, rr, dir);
}
fn DrawDropButton(w, rr)
{
DrawArrowButton(w, rr, -1);
}
fn PaintVScrollBar(w, r)
{
wd = r.right - r.left;
up = r;
r.top = (up.bottom = up.top + wd);
down = r;
r.bottom = (down.top = down.bottom - wd);
DrawArrowButton(w, up, 1);
DrawArrowButton(w, down, -1);
w.DrawRect(r, :SWhiteGray);
}
fn PaintHScrollBar(w, r)
{
hg = r.bottom - r.top;
left = r;
r.left = (left.right = left.left + hg);
right = r;
r.right = (right.left = right.right - hg);
DrawHArrowButton(w, left, 1);
DrawHArrowButton(w, right, -1);
w.DrawRect(r, :SWhiteGray);
}
ctrl DropList {
group "Input fields";
GetMinSize() { sz = XMinSize(); sz.cy += 6; return sz; }
GetStdSize() { sz = GetMinSize(); sz.cx *= 8; return sz; }
Frame SetFrame = default;
bool SetEditable = true @2 ? "Editable";
bool WantFocus = true;
bool DisplayAll = false;
bool AlwaysDrop = false @1;
bool NotNull = false;
Text Tip @2;
// Qtf SetInfo @1 ? "Info of control" ;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
w.DrawRect(r, :SWhite);
n = r.bottom - r.top;
DrawDropButton(w, RectC(r.right - n, r.top, n, n));
w.DrawText(3, (GetSize().cy - GetTextSize("", Arial(10)).cy) / 2,
(.SetEditable ? "" : "R/O ") + "DropList", Arial(10), :SMagenta);
}
}
ctrl DropTree {
group "Input fields";
GetMinSize() { sz = XMinSize(); sz.cy += 6; return sz; }
GetStdSize() { sz = GetMinSize(); sz.cx *= 8; return sz; }
Frame SetFrame = default;
bool SetEditable = true @2 ? "Editable";
bool WantFocus = true;
bool DisplayAll = false;
bool AutoResize = false;
bool DropFocus = false;
bool AlwaysDrop = false @1;
Text Tip @2;
// Qtf SetInfo @1 ? "Info of control" ;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
w.DrawRect(r, :SWhite);
n = r.bottom - r.top;
DrawDropButton(w, RectC(r.right - n, r.top, n, n));
w.DrawText(3, (GetSize().cy - GetTextSize("", Arial(10)).cy) / 2,
(.SetEditable ? "" : "R/O ") + "DropTree", Arial(10), :SMagenta);
}
}
template WithDropChoice {
bool Dropping = true;
String Appending = ", ";
raw SetDropLines = 16;
Text Tip @1;
Paint(w) {
CtrlPaint(w);
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
n = r.bottom - r.top;
DrawDropButton(w, RectC(r.right - n, r.top, n, n));
}
};
fn PaintTab(w, x, y, text, color)
{
tsz = GetSmartTextSize(text, StdFont());
h = 4 * tsz.cy / 3;
sz = Size(tsz.cx + tsz.cy, h);
r = RectC(x, y, sz.cx, sz.cy);
w.DrawRect(r, color);
DrawButtonFrame(w, r);
w.DrawSmartText(x + tsz.cy / 2, y + 4, text, StdFont(), :SBlack, sz.cx);
sz.cx -= 4;
return sz;
}
ctrl TabCtrl {
group "Complex";
GetStdSize() { return Size(150, 100); }
// Font SetFont = StdFont();
bool AcceptCurrent = false;
// Qtf SetInfo @1 ? "Info of control" ;
Paint(w) {
r = GetRect();
x0 = x = r.left;
y = r.top;
tsz = PaintTab(w, x, y, "Tab 1", :SWhiteGray);
x += tsz.cx;
x += PaintTab(w, x, y + 3, "Tab 2", :SLtGray).cx;
x += PaintTab(w, x, y + 3, "Tab 3", :SLtGray).cx;
r.top += tsz.cy;
DrawButton(w, r);
PaintTab(w, x0, y, "Tab 1", :SWhiteGray);
if(IsUHD())
w.DrawRect(2, r.top - 2, tsz.cx, 4, :SWhiteGray);
else
w.DrawRect(1, r.top - 1, tsz.cx + 2, 2, :SWhiteGray);
}
};
fn PaintHeaderTab(w, r, text)
{
DrawEdgeButtonFrame(w, r);
w.DrawText(r.left + 2, (r.top + r.bottom - GetTextSize(text).cy) >> 1, text, StdFont());
}
fn PaintHeaderTabs(w, ...)
{
for(i = 0; i < count(argv); i += 2)
PaintHeaderTab(w, argv[i], argv[i + 1]);
}
fn PaintCenterText(w, x, y, text, fnt, color)
{
sz = GetTextSize(text, fnt);
w.DrawText(x - sz.cx / 2, y - sz.cy / 2, text, fnt, color);
}
ctrl ArrayCtrl {
group "Complex";
GetStdSize() { return Size(150, 100); }
Frame SetFrame = default @1;
bool AutoHideSb = false;
bool Header = true;
bool Inserting = false;
bool Appending = false;
bool AppendLine = false;
bool Removing = false;
bool AskRemove = true;
bool Duplicating = false;
bool Moving = false;
bool Track = false;
bool VertGrid = true;
bool HorzGrid = true;
bool NoCursor = false;
bool MouseMoveCursor = false;
bool MultiSelect = false;
int SetLineCy;
// Qtf SetInfo @1 ? "Info of control" ;
Paint(w) {
PaintArray(w, GetRect());
}
PaintArray(w, r) {
col1 = "A";
col2 = "B";
col3 = "C";
fontcy = GetTextSize(col1).cy;
DrawCtrlFrame(w, r, .SetFrame);
if(!.AutoHideSb) {
rsb = r;
r.right = rsb.left = rsb.right - fontcy - 4;
PaintVScrollBar(w, rsb);
}
wd = r.right - r.left;
hdrcy = .Header ? fontcy + 4 : 0;
third = wd / 3;
r1 = r;
r1.bottom = r1.top + hdrcy;
r1.right = r.left + third;
r2 = r1;
r2.right = (r2.left = r1.right) + third;
r3 = r2;
r3.left = r2.right;
r3.right = r.right;
if(hdrcy)
PaintHeaderTabs(w, r1, col1, r2, col2, r3, col3);
linecy = .SetLineCy;
if(is_void(linecy) || linecy <= 0)
linecy = fontcy + 1;
celltop = r1.bottom;
cellht = 3 * linecy;
cellbot = celltop + cellht + 1;
w.DrawRect(r.left, celltop, wd, cellht, :SWhite);
if(.NoCursor == "false")
w.DrawRect(r.left, celltop + linecy, wd, linecy, :SBlue);
for(i = 1; i <= 3; i++)
{
if(.HorzGrid)
w.DrawRect(r.left, celltop + linecy * i, wd, 1, :SLtGray);
if(.VertGrid)
w.DrawRect(r.left + i * third - 1, celltop, 1, cellht, :SLtGray);
}
w.DrawRect(r.left, cellbot, wd, r.bottom - cellbot, :SWhite.r < 50 ? Color(90, 90, 90) : Color(160, 160, 160));
w.DrawText(3, r.bottom - fontcy, "ArrayCtrl", Arial(10), :SMagenta);
}
};
fn DrawTreeItem(w, x, y, text, kind)
{
osz = OptionSize();
textsize = GetTextSize(text);
if(kind)
DrawOption(w, x, y + (textsize.cy - osz) / 2, 1);
w.DrawText(x + osz + 2, y, text, StdFont(), :SBlack);
}
ctrl TreeCtrl {
group "Complex";
GetStdSize() { return Size(150, 100); }
Frame SetFrame = default @1;
// Qtf SetInfo @1 ? "Info of control" ;
Paint(w) {
r = GetRect();
w.DrawRect(r, :SWhite);
fontcy = GetTextSize("X").cy;
DrawCtrlFrame(w, r, .SetFrame);
rsb = r;
r.right = rsb.left = rsb.right - fontcy - 4;
PaintVScrollBar(w, rsb);
w.DrawText(3, r.bottom - fontcy, "TreeCtrl", Arial(10), :SMagenta);
DeflateRect(r);
DeflateRect(r);
DrawTreeItem(w, r.left + 2 + 0 * fontcy, r.top + 2 + 0 * fontcy, "Root", 1);
DrawTreeItem(w, r.left + 2 + 1 * fontcy, r.top + 2 + 1 * fontcy, "Node 1", 0);
DrawTreeItem(w, r.left + 2 + 1 * fontcy, r.top + 2 + 2 * fontcy, "Node 2", 1);
DrawTreeItem(w, r.left + 2 + 2 * fontcy, r.top + 2 + 3 * fontcy, "Node 3", 0);
}
};
ctrl ColumnList {
group "Complex";
GetStdSize() { return Size(150, 100); }
Frame SetFrame = default @1;
// Qtf SetInfo @1 ? "Info of control" ;
Paint(w) {
r = GetRect();
w.DrawRect(r, :SWhite);
fontcy = GetTextSize("X").cy;
DrawCtrlFrame(w, r, .SetFrame);
rsb = r;
r.right = rsb.left = rsb.right - fontcy - 4;
PaintVScrollBar(w, rsb);
w.DrawText(3, 3, "ColumnList", Arial(10), :SMagenta);
}
};
ctrl RichTextView {
group "Complex";
GetMinSize() { sz = XMinSize(); sz.cy += 6; return sz; }
GetStdSize() { sz = GetMinSize(); sz.cx *= 8; return sz; }
Frame SetFrame = default @1;
Color Background = :SWhite;
bool VCenter = false;
bool NoSb = false @0;
bool AutoHideSb = false;
int HMargins = 0;
int VMargins = 0;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
w.DrawRect(r, .Background);
w.DrawText(3, 3, "RichTextView", Arial(10), :SMagenta);
}
}
ctrl RichTextCtrl {
group "Static";
>RichTextView;
GetMinSize() { sz = XMinSize(); sz.cy += 6; return sz; }
GetStdSize() { sz = GetMinSize(); sz.cx *= 8; return sz; }
Frame SetFrame = NullFrame() @1;
Color Background = Null @0;
bool NoSb = false @0;
bool AutoHideSb = true @0;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
if(!is_void(.Background))
w.DrawRect(r, .Background);
w.DrawText(3, 3, "RichTextCtrl", Arial(10), :SMagenta);
}
}
ctrl DropDate {
group "Input fields";
GetMinSize() { sz = XMinSize(); sz.cy += 6; return sz; }
GetStdSize() { sz = GetMinSize(); sz.cx *= 13; return sz; }
bool SelectAll = true;
bool SwapMonthYear = false;
bool OneButton = false;
bool NotNull = false;
Frame SetFrame = default;
bool SetEditable = true @2 ? "Editable";
bool WantFocus = true;
Text Tip @2;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
w.DrawRect(r, :SWhite);
n = r.bottom - r.top;
DrawDropButton(w, RectC(r.right - n, r.top, n, n));
w.DrawText(3, (GetSize().cy - GetTextSize("", Arial(10)).cy) / 2,
(.SetEditable ? "" : "R/O ") + (.NotNull ? "!" : "") + "01/05/2007", Arial(10), :SMagenta);
}
}
ctrl DropTime {
group "Input fields";
GetMinSize() { sz = XMinSize(); sz.cy += 6; return sz; }
GetStdSize() { sz = GetMinSize(); sz.cx *= 15; return sz; }
bool SelectAll = true;
bool SwapMonthYear = false;
bool Seconds = true;
bool DayEnd = false;
bool TimeAlways = false;
bool NotNull = false;
Frame SetFrame = default;
bool SetEditable = true @2 ? "Editable";
bool WantFocus = true @2;
Text Tip @2;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
w.DrawRect(r, :SWhite);
n = r.bottom - r.top;
DrawDropButton(w, RectC(r.right - n, r.top, n, n));
w.DrawText(3, (GetSize().cy - GetTextSize("", Arial(10)).cy) / 2,
(.SetEditable ? "" : "R/O ") + (.NotNull ? "!" : "") + "01/05/2007 10:34:58", Arial(10), :SMagenta);
}
}
fn DrawHorzArrowFromTip(w, tipx, tipy, dir, l, color)
{
for(i = 0; i < l; i++) {
w.DrawRect(tipx, tipy - i, 1, 2 * i + 1, color);
tipx += dir;
}
}
fn DrawHorzArrow(ww, r, dir)
{
size = OptionSize() / 3;
w = r.right - r.left;
h = r.bottom - r.top;
x = r.left + (h - size) / 2;
DrawHorzArrowFromTip(ww, dir > 0 ? x : x + size, r.top + h / 2, dir, size, :SBlack);
}
ctrl Clock {
group "Input fields";
GetMinSize() { return Size(150, 156); }
GetStdSize() { return Size(150, 156); }
Frame SetFrame = BlackFrame() @2;
bool SetEditable = true @2 ? "Editable";
bool WantFocus = true @2;
bool Seconds = true;
Text Tip @2;
PaintPtr(w, cmx, cmy, pos, m, d, color, cf) {
dx = m * sin(pos * 2 * 3.1415);
dy = m * cos(pos * 2 * 3.1415);
sx = cmx - dx * 35 / 2.0;
sy = cmy + dy * 35 / 2.0;
ex = cmx + dx * cf;
ey = cmy - dy * cf;
w.DrawLine(sx, sy, ex, ey, d, color);
}
Paint(w) {
ts = GetTextSize("X");
r = GetRect();
ro = GetRect();
b = r.bottom;
hs = 20;
r.bottom = hs;
w.DrawRect(r, :SLtBlue);
r.top = r.bottom;
r.bottom = b;
w.DrawRect(r, :SWhite);
width = r.right - r.left;
height = r.bottom - r.top;
w.DrawRect(0, hs, 5, ro.bottom - hs, Color(200, 200, 200));
w.DrawRect(ro.right - 5, hs, 5, ro.bottom - hs, Color(200, 200, 200));
cmx = width / 2;
cmy = height / 2 + hs;
cf = min(cmy - 15, cmx) - 5;
for(i = 1; i <= 60; i++)
{
x = cmx + (0.95 * sin(i * 3.1415 / 30.0) * cf);
y = cmy - (0.95 * cos(i * 3.1415 / 30.0) * cf);
if(i % 5 == 0)
w.DrawRect(x, y, 2, 2, :SBlack);
else
w.DrawRect(x, y, 1, 1, :SBlack);
}
fnt = Arial(10);
for(i = 1; i <= 12; i++)
{
x = cmx + (0.8 * sin(i * 3.1415 / 6.0) * cf);
y = cmy - (0.8 * cos(i * 3.1415 / 6.0) * cf);
PaintCenterText(w, x, y, to_string(i), .fnt, :SBlack);
}
hour = 10;
minute = 34;
second = 15;
tm = hour * 3600 + minute * 60 + second;
PaintPtr(w, cmx, cmy, tm / 3600 / 12, 0.5, 5, :SRed, cf);
PaintPtr(w, cmx, cmy, tm / 3600, 0.6, 3, :SBlue, cf);
PaintPtr(w, cmx, cmy, tm / 60, 0.75, 2, :SBlack, cf);
r = Rect(ro.left + 3, ro.top + 2, ro.left + 3 + 16, ro.top + 18);
left = r.left;
r.left += 15 + 25;
r.right += 15 + 25;
PaintCenterText(w, (r.right + left) / 2, (r.top + r.bottom) / 2, to_string(hour), .fnt, :SWhite);
r = Rect(ro.right - 3 - 16, ro.top + 2, ro.right - 3, ro.top + 18);
right = r.right;
r.left -= 15 + 25;
r.right -= 15 + 25;
PaintCenterText(w, (right + r.left) / 2, (r.top + r.bottom) / 2, to_string(minute), .fnt, :SWhite);
DrawCtrlFrame(w, ro, .SetFrame);
}
}
ctrl Calendar {
group "Input fields";
GetMinSize() { return Size(180, 120); }
GetStdSize() { return Size(236, 156); }
Frame SetFrame = BlackFrame();
bool SetEditable = true @2 ? "Editable";
bool WantFocus = true @2;
bool SelectAll = true;
bool SwapMonthYear = false;
bool OneButton = false;
Text Tip @2;
Paint(w) {
ts = GetTextSize("X");
r = GetRect();
ro = GetRect();
f = StdFont();
b = r.bottom;
hs = 20;
r.bottom = hs;
w.DrawRect(r, :SLtBlue);
r.top = r.bottom;
r.bottom = b;
w.DrawRect(r, :SWhite);
width = r.right - r.left;
height = r.bottom - r.top - 15;
sw = width / 8;
sh = height / 7;
w.DrawRect(r.left + 4, r.top + sh, width - 8, 1, :SBlack);
w.DrawRect(r.left + sw, r.top + 4, 1, height - 8, :SBlack);
ts = GetTextSize("Wk");
ty = r.top + (sh - ts.cy) / 2;
w.DrawText(r.left + (sw - ts.cx) / 2 , ty, "Wk", f, :SBlack);
days = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"];
for(i = 0; i < 7; i++)
w.DrawText(r.left + sw + i * sw + (sw - ts.cx) / 2, ty, days[i], f, :SBlack);
d = 1;
tn = GetTextSize("0");
gray = 0;
fnt = f;
for(j = 0; j < 6; j++)
{
ty = r.top + sh + j * sh + (sh - ts.cy) / 2;
w.DrawText(r.left + (sw - tn.cx) / 2, ty, to_string(j + 1), f, :SBlack);
for(i = 0; i < 7; i++)
{
if(d == 19)
{
w.DrawRect(r.left + sw + i * sw + 0, r.top + sh + j * sh + 0, sw, sh, :SBlack);
w.DrawRect(r.left + sw + i * sw + 1, r.top + sh + j * sh + 1, sw - 2, sh - 2, :SYellow);
fnt = f.Bold(1);
}
day = to_string(d);
ts = GetTextSize(day, fnt);
w.DrawText(r.left + sw + i * sw + (sw - ts.cx) / 2, ty, day, fnt, gray ? :SGray : (i == 6 ? :SRed : :SBlack));
fnt = f.Bold(false);
if(++d > 31)
{
d = 1;
gray = 1;
}
}
}
today = "Today: 01/19/2007";
ts = GetTextSize(today, StdFont().Bold());
w.DrawText((r.right - ts.cx) / 2, r.bottom - 3 - ts.cy, today, f.Bold(), :SBlue);
r = Rect(ro.left + 3, ro.top + 2, ro.left + 3 + 16, ro.top + 18);
left = r.left;
r.left += 15 + 65;
r.right += 15 + 65;
PaintCenterText(w, (left + r.right) / 2, (r.top + r.bottom) / 2, "January", f.Bold(), :SWhite);
r = Rect(ro.right - 3 - 16, ro.top + 2, ro.right - 3, ro.top + 18);
right = r.right;
r.left -= 15 + 40;
r.right -= 15 + 40;
PaintCenterText(w, (r.left + right) / 2, (r.top + r.bottom) / 2, "2007", f.Bold(), :SWhite);
DrawCtrlFrame(w, ro, .SetFrame);
}
}
ctrl SliderCtrl {
group "Progress";
GetMinSize() { return Size(0, 0); }
GetStdSize() { return Size(64, 24); }
Frame SetFrame @1;
bool Jump = false;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
sz = Size(r.right - r.left, r.bottom - r.top);
halfX = int(r.left + r.right) >> 1;
halfY = int(r.top + r.bottom) >> 1;
osz = 3 * OptionSize() / 2;
osz2 = int(osz / 2);
osz4 = int(osz / 4);
if (sz.cx < sz.cy) {
DrawInsetFrame(w, Rect(halfX - 2, r.top + 2, halfX + 2, r.bottom - 2));
DrawButton(w, RectC(halfX - osz2, halfY - osz4, osz, osz2));
} else {
DrawInsetFrame(w, Rect(r.left + 2, halfY - 2, r.right - 2, halfY + 2));
DrawButton(w, RectC(halfX - osz4, halfY - osz2, osz2, osz));
}
}
}
ctrl ProgressIndicator {
group "Progress";
GetMinSize() { return Size(0, 0); }
GetStdSize() { return Size(64, 24); }
Frame SetFrame @1;
Paint(w) {
r = GetRect();
DrawCtrlFrame(w, r, .SetFrame);
DrawInsetFrame(w, r);
sz = Size(r.right - r.left, r.bottom - r.top);
w.DrawRect(r.left, r.top, sz.cx, sz.cy, :SBlack);
DeflateRect(r);
sz = Size(r.right - r.left, r.bottom - r.top);
w.DrawRect(r.left, r.top, sz.cx, sz.cy, :SWhite);
if(sz.cx > sz.cy) {
w.DrawRect(r.left, r.top, sz.cx >> 2, sz.cy, :SLtGreen);
}
else {
w.DrawRect(r.left, r.bottom - (sz.cy >> 2), sz.cx, sz.cy >> 2, :SLtGreen);
}
}
}