From bc369fae0344f36ec4bf79a8da4a300bf057a3e7 Mon Sep 17 00:00:00 2001 From: cxl Date: Thu, 7 May 2009 16:38:32 +0000 Subject: [PATCH] Developing new Draw (in uppdev) git-svn-id: svn://ultimatepp.org/upp/trunk@1128 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppdev/ArrayCtrl/ArrayCtrl.upp | 2 + uppdev/ArrayCtrl/main.cpp | 2 +- uppdev/DateFmtCtrl/DateFmtCtrl.h | 4 +- uppdev/DateFmtCtrl/DateFmtCtrl.lay | 4 - uppdev/DateFmtCtrl/main.cpp | 4 +- uppdev/DbgTest/main.cpp | 1 + uppdev/DbgTest/test.lay | 1 + uppdev/Draw/BackDraw.cpp | 42 + uppdev/Draw/BackDraw.h | 32 + uppdev/Draw/Cham.cpp | 567 +++++ uppdev/Draw/Cham.h | 117 + uppdev/Draw/ComposeText.cpp | 275 +++ uppdev/Draw/Copying | 21 + uppdev/Draw/Debug.cpp | 564 +++++ uppdev/Draw/Debug.h | 46 + uppdev/Draw/Display.cpp | 321 +++ uppdev/Draw/Display.h | 100 + uppdev/Draw/Draw.cpp | 420 ++++ uppdev/Draw/Draw.h | 975 +++++++++ uppdev/Draw/Draw.upp | 91 + uppdev/Draw/DrawData.cpp | 127 ++ uppdev/Draw/DrawImg.iml | 7 + uppdev/Draw/DrawOpWin32.cpp | 321 +++ uppdev/Draw/DrawOpX11.cpp | 320 +++ uppdev/Draw/DrawRasterData.cpp | 40 + uppdev/Draw/DrawText.cpp | 141 ++ uppdev/Draw/DrawTextUtil.cpp | 128 ++ uppdev/Draw/DrawTextXft.cpp | 372 ++++ uppdev/Draw/DrawUtil.cpp | 632 ++++++ uppdev/Draw/DrawWin32.cpp | 476 ++++ uppdev/Draw/DrawWin32.h | 234 ++ uppdev/Draw/DrawX11.cpp | 445 ++++ uppdev/Draw/DrawX11.h | 754 +++++++ uppdev/Draw/Drawing.cpp | 691 ++++++ uppdev/Draw/Font.cpp | 303 +++ uppdev/Draw/FontWin32.cpp | 412 ++++ uppdev/Draw/Image.cpp | 702 ++++++ uppdev/Draw/Image.h | 342 +++ uppdev/Draw/ImageBlit.cpp | 399 ++++ uppdev/Draw/ImageChOp.cpp | 380 ++++ uppdev/Draw/ImageDraw.h | 38 + uppdev/Draw/ImageOp.cpp | 665 ++++++ uppdev/Draw/ImageOp.h | 156 ++ uppdev/Draw/ImageScale.cpp | 511 +++++ uppdev/Draw/ImageWin32.cpp | 614 ++++++ uppdev/Draw/ImageX11.cpp | 406 ++++ uppdev/Draw/MakeCache.cpp | 176 ++ uppdev/Draw/MetaFile.cpp | 253 +++ uppdev/Draw/Palette.cpp | 281 +++ uppdev/Draw/Raster.cpp | 255 +++ uppdev/Draw/Raster.h | 297 +++ uppdev/Draw/RasterEncoder.cpp | 178 ++ uppdev/Draw/RasterFormat.cpp | 368 ++++ uppdev/Draw/RasterWrite.cpp | 344 +++ uppdev/Draw/SSettings.cpp | 42 + uppdev/Draw/gdk.dli | 22 + uppdev/Draw/gnome.dli | 1 + uppdev/Draw/gobj.dli | 2 + uppdev/Draw/gpixbuf.dli | 6 + uppdev/Draw/gtk.dli | 185 ++ uppdev/Draw/iml.h | 9 + uppdev/Draw/iml_header.h | 63 + uppdev/Draw/iml_source.h | 140 ++ uppdev/Draw/init | 4 + uppdev/Draw/src.tpp/Display$en-us.tpp | 15 + uppdev/Draw/src.tpp/Draw$en-us.tpp | 1852 ++++++++++++++++ uppdev/Draw/src.tpp/Font$en-us.tpp | 13 + uppdev/Draw/src.tpp/FontInfo$en-us.tpp | 8 + uppdev/Draw/src.tpp/Image$en-us.tpp | 317 +++ uppdev/Draw/src.tpp/Iml$en-us.tpp | 7 + uppdev/Draw/srcdoc.tpp/DrawOutput$en-us.tpp | 160 ++ uppdev/Draw/srcdoc.tpp/DrawTutorial$en-us.tpp | 965 +++++++++ uppdev/Draw/srcdoc.tpp/ImgTutorial$en-us.tpp | 1924 +++++++++++++++++ uppdev/I18nFormat/I18nFormat.cpp | 3 + uppdev/LanPath/LanPath.cpp | 10 + uppdev/LanPath/LanPath.upp | 9 + uppdev/NewDraw/Draw.h | 191 ++ uppdev/NewDraw/NewDraw.upp | 10 + uppdev/NewDraw/init | 4 + uppdev/NewDraw/main.cpp | 6 + uppdev/aaa/a.h | 2 + uppdev/aaa/aaa.upp | 3 +- uppdev/aaa/init | 1 + uppdev/aaa/main3.cpp | 1 + 84 files changed, 21322 insertions(+), 10 deletions(-) create mode 100644 uppdev/Draw/BackDraw.cpp create mode 100644 uppdev/Draw/BackDraw.h create mode 100644 uppdev/Draw/Cham.cpp create mode 100644 uppdev/Draw/Cham.h create mode 100644 uppdev/Draw/ComposeText.cpp create mode 100644 uppdev/Draw/Copying create mode 100644 uppdev/Draw/Debug.cpp create mode 100644 uppdev/Draw/Debug.h create mode 100644 uppdev/Draw/Display.cpp create mode 100644 uppdev/Draw/Display.h create mode 100644 uppdev/Draw/Draw.cpp create mode 100644 uppdev/Draw/Draw.h create mode 100644 uppdev/Draw/Draw.upp create mode 100644 uppdev/Draw/DrawData.cpp create mode 100644 uppdev/Draw/DrawImg.iml create mode 100644 uppdev/Draw/DrawOpWin32.cpp create mode 100644 uppdev/Draw/DrawOpX11.cpp create mode 100644 uppdev/Draw/DrawRasterData.cpp create mode 100644 uppdev/Draw/DrawText.cpp create mode 100644 uppdev/Draw/DrawTextUtil.cpp create mode 100644 uppdev/Draw/DrawTextXft.cpp create mode 100644 uppdev/Draw/DrawUtil.cpp create mode 100644 uppdev/Draw/DrawWin32.cpp create mode 100644 uppdev/Draw/DrawWin32.h create mode 100644 uppdev/Draw/DrawX11.cpp create mode 100644 uppdev/Draw/DrawX11.h create mode 100644 uppdev/Draw/Drawing.cpp create mode 100644 uppdev/Draw/Font.cpp create mode 100644 uppdev/Draw/FontWin32.cpp create mode 100644 uppdev/Draw/Image.cpp create mode 100644 uppdev/Draw/Image.h create mode 100644 uppdev/Draw/ImageBlit.cpp create mode 100644 uppdev/Draw/ImageChOp.cpp create mode 100644 uppdev/Draw/ImageDraw.h create mode 100644 uppdev/Draw/ImageOp.cpp create mode 100644 uppdev/Draw/ImageOp.h create mode 100644 uppdev/Draw/ImageScale.cpp create mode 100644 uppdev/Draw/ImageWin32.cpp create mode 100644 uppdev/Draw/ImageX11.cpp create mode 100644 uppdev/Draw/MakeCache.cpp create mode 100644 uppdev/Draw/MetaFile.cpp create mode 100644 uppdev/Draw/Palette.cpp create mode 100644 uppdev/Draw/Raster.cpp create mode 100644 uppdev/Draw/Raster.h create mode 100644 uppdev/Draw/RasterEncoder.cpp create mode 100644 uppdev/Draw/RasterFormat.cpp create mode 100644 uppdev/Draw/RasterWrite.cpp create mode 100644 uppdev/Draw/SSettings.cpp create mode 100644 uppdev/Draw/gdk.dli create mode 100644 uppdev/Draw/gnome.dli create mode 100644 uppdev/Draw/gobj.dli create mode 100644 uppdev/Draw/gpixbuf.dli create mode 100644 uppdev/Draw/gtk.dli create mode 100644 uppdev/Draw/iml.h create mode 100644 uppdev/Draw/iml_header.h create mode 100644 uppdev/Draw/iml_source.h create mode 100644 uppdev/Draw/init create mode 100644 uppdev/Draw/src.tpp/Display$en-us.tpp create mode 100644 uppdev/Draw/src.tpp/Draw$en-us.tpp create mode 100644 uppdev/Draw/src.tpp/Font$en-us.tpp create mode 100644 uppdev/Draw/src.tpp/FontInfo$en-us.tpp create mode 100644 uppdev/Draw/src.tpp/Image$en-us.tpp create mode 100644 uppdev/Draw/src.tpp/Iml$en-us.tpp create mode 100644 uppdev/Draw/srcdoc.tpp/DrawOutput$en-us.tpp create mode 100644 uppdev/Draw/srcdoc.tpp/DrawTutorial$en-us.tpp create mode 100644 uppdev/Draw/srcdoc.tpp/ImgTutorial$en-us.tpp create mode 100644 uppdev/LanPath/LanPath.cpp create mode 100644 uppdev/LanPath/LanPath.upp create mode 100644 uppdev/NewDraw/Draw.h create mode 100644 uppdev/NewDraw/NewDraw.upp create mode 100644 uppdev/NewDraw/init create mode 100644 uppdev/NewDraw/main.cpp diff --git a/uppdev/ArrayCtrl/ArrayCtrl.upp b/uppdev/ArrayCtrl/ArrayCtrl.upp index 353c9af22..53fbc3ca6 100644 --- a/uppdev/ArrayCtrl/ArrayCtrl.upp +++ b/uppdev/ArrayCtrl/ArrayCtrl.upp @@ -1,3 +1,5 @@ +description "\377B0,0,255"; + uses CtrlLib, Crypto; diff --git a/uppdev/ArrayCtrl/main.cpp b/uppdev/ArrayCtrl/main.cpp index 1b44b5f1f..4e5685e94 100644 --- a/uppdev/ArrayCtrl/main.cpp +++ b/uppdev/ArrayCtrl/main.cpp @@ -25,7 +25,7 @@ struct App : TopWindow { void DnDInsertB(int line, PasteClip& d) { - if(AcceptInternal(d, "array")) + if(AcceptInternal()(d, "array")) b.InsertDrop(line, d); } diff --git a/uppdev/DateFmtCtrl/DateFmtCtrl.h b/uppdev/DateFmtCtrl/DateFmtCtrl.h index 3fe08d460..5b9394e46 100644 --- a/uppdev/DateFmtCtrl/DateFmtCtrl.h +++ b/uppdev/DateFmtCtrl/DateFmtCtrl.h @@ -3,11 +3,11 @@ #include +using namespace Upp; + #define LAYOUTFILE #include - - class DateFmtCtrl : public WithDateFmtCtrlLayout { public: void Print(); diff --git a/uppdev/DateFmtCtrl/DateFmtCtrl.lay b/uppdev/DateFmtCtrl/DateFmtCtrl.lay index 99603e15b..bf6f4f2ad 100644 --- a/uppdev/DateFmtCtrl/DateFmtCtrl.lay +++ b/uppdev/DateFmtCtrl/DateFmtCtrl.lay @@ -1,9 +1,5 @@ -#ifdef LAYOUTFILE - LAYOUT(DateFmtCtrlLayout, 236, 76) ITEM(DropList, lang, LeftPosZ(8, 104).TopPosZ(8, 19)) ITEM(EditDate, date, LeftPosZ(120, 104).TopPosZ(8, 19)) ITEM(Label, text, LeftPosZ(8, 216).TopPosZ(36, 24)) END_LAYOUT - -#endif diff --git a/uppdev/DateFmtCtrl/main.cpp b/uppdev/DateFmtCtrl/main.cpp index 6aa905f17..1dfe190e1 100644 --- a/uppdev/DateFmtCtrl/main.cpp +++ b/uppdev/DateFmtCtrl/main.cpp @@ -13,7 +13,7 @@ void DateFmtCtrl::Language() DateFmtCtrl::DateFmtCtrl() { - CtrlLayout(*this, "Window title %d"); + CtrlLayout(*this, "Window title"); lang.Add(LNG_('E','N','U','S'), "ENUS"); lang.Add(LNG_('C','S','C','Z'), "CSCZ"); date <<= THISBACK(Print); @@ -25,6 +25,6 @@ DateFmtCtrl::DateFmtCtrl() GUI_APP_MAIN { SetDateFormat("%4:DAY %3:02d.%2:month.%1:02.2d"); - DUMP(GetSysDate()); + SetDateFilter("A.\r,;:\r/\r:\\|"); DateFmtCtrl().Run(); } diff --git a/uppdev/DbgTest/main.cpp b/uppdev/DbgTest/main.cpp index e98042d53..7354569cc 100644 --- a/uppdev/DbgTest/main.cpp +++ b/uppdev/DbgTest/main.cpp @@ -12,6 +12,7 @@ void SecondThread() GUI_APP_MAIN { + String x = "asdfasdfkjasdfkl alsjd fl hdasflk hdasfkl;jahs dlfkjh alsfhj la flf"; Thread d; d.Run(callback(SecondThread)); PromptOK("test"); diff --git a/uppdev/DbgTest/test.lay b/uppdev/DbgTest/test.lay index 5ee1a2219..71f50d522 100644 --- a/uppdev/DbgTest/test.lay +++ b/uppdev/DbgTest/test.lay @@ -8,3 +8,4 @@ END_LAYOUT LAYOUT(sdgf, 384, 252) ITEM(ArrayCtrl, dv___0, LeftPosZ(32, 150).TopPosZ(32, 100)) END_LAYOUT + diff --git a/uppdev/Draw/BackDraw.cpp b/uppdev/Draw/BackDraw.cpp new file mode 100644 index 000000000..b7c0eca7e --- /dev/null +++ b/uppdev/Draw/BackDraw.cpp @@ -0,0 +1,42 @@ +#include "Draw.h" + +// --------------------------- + +Draw& ScreenInfo(); + +void BackDraw::Create(int cx, int cy) +{ + DrawLock __; + Create(ScreenInfo(), cx, cy); +} + +bool BackDraw::IsPaintingOp(const Rect& r) const +{ + Rect rr = r + GetOffset(); + if(!rr.Intersects(size)) + return false; + return painting ? painting->IsPainting(rr + painting_offset) : true; +} + +BackDraw::BackDraw() +{ + painting = NULL; + painting_offset = Point(0, 0); +} + +BackDraw::~BackDraw() +{ + Destroy(); +} + +Draw& ScreenInfo(); + +bool ScreenInPaletteMode() +{ + return ScreenInfo().PaletteMode(); +} + +Size GetScreenSize() +{ + return ScreenInfo().GetPagePixels(); +} diff --git a/uppdev/Draw/BackDraw.h b/uppdev/Draw/BackDraw.h new file mode 100644 index 000000000..775bfc95c --- /dev/null +++ b/uppdev/Draw/BackDraw.h @@ -0,0 +1,32 @@ +class BackDraw : public Draw { +public: + virtual bool IsPaintingOp(const Rect& r) const; + +protected: +#ifdef PLATFORM_WIN32 + HBITMAP hbmpold; + HBITMAP hbmp; +#endif +#ifdef PLATFORM_X11 + Pixmap pixmap; +#endif + Size size; + Draw *painting; + Point painting_offset; + + +public: + void Put(Draw& w, int x, int y); + void Put(Draw& w, Point p) { Put(w, p.x, p.y); } + + void Create(Draw& draw, int cx, int cy); + void Create(Draw& draw, Size sz) { Create(draw, sz.cx, sz.cy); } + void Create(int cx, int cy); + void Create(Size sz) { Create(sz.cx, sz.cy); } + void Destroy(); + + void SetPaintingDraw(Draw& w, Point off) { painting = &w; painting_offset = off; } + + BackDraw(); + ~BackDraw(); +}; diff --git a/uppdev/Draw/Cham.cpp b/uppdev/Draw/Cham.cpp new file mode 100644 index 000000000..e94c99ba2 --- /dev/null +++ b/uppdev/Draw/Cham.cpp @@ -0,0 +1,567 @@ +#include "Draw.h" + +NAMESPACE_UPP + +#define LTIMING(x) // RTIMING(x) + +#if defined(_DEBUG) && 0 +#include + +inline void LOGPNG(const char *name, const Image& m) +{ + PNGEncoder png; + png.SaveFile(ConfigFile(name) + ".png", m); +} + +#else + +#define LOGPNG(a, b) + +#endif + +struct ChImageMaker : ImageMaker { + Size sz; + Rect sr; + Image img; + + virtual String Key() const; + virtual Image Make() const; +}; + +String ChImageMaker::Key() const +{ + LTIMING("ChImageMaker::Key"); + StringBuffer b; + int64 id = img.GetSerialId(); + b.Cat((const char *)&id, sizeof(id)); + b.Cat((const char *)&sz.cx, sizeof(sz.cx)); + b.Cat((const char *)&sz.cy, sizeof(sz.cy)); + b.Cat((const char *)&sr.left, sizeof(sr.left)); + b.Cat((const char *)&sr.right, sizeof(sr.right)); + b.Cat((const char *)&sr.top, sizeof(sr.top)); + b.Cat((const char *)&sr.bottom, sizeof(sr.bottom)); + return b; +} + +Image ChImageMaker::Make() const +{ + LTIMING("ChImageMaker::Make"); + return Rescale(img, sz, sr); +} + +void ChDraw(Draw& w, int x, int y, int cx, int cy, const Image& img, const Rect& src) +{ + LTIMING("ChDraw"); + if(cx > 0 && cy > 0) { + ChImageMaker m; + m.sz = Size(cx, cy); + m.sr = src; + m.img = img; + w.DrawImage(x, y, MakeImage(m)); + } +} + +void ChDraw(Draw& w, const Rect& r, const Image& img, const Rect& src) +{ + ChDraw(w, r.left, r.top, r.GetWidth(), r.GetHeight(), img, src); +} + +struct sChLookWith { + Value look; + Image img; + Color (*colorfn)(int i); + int ii; + Color color; + Point offset; +}; + +Value ChLookWith(const Value& look, const Image& img, Point offset) +{ + sChLookWith x; + x.look = look; + x.img = img; + x.colorfn = NULL; + x.color = Null; + x.offset = offset; + return RawToValue(x); +} + +Value ChLookWith(const Value& look, const Image& img, Color color, Point offset) +{ + sChLookWith x; + x.look = look; + x.img = img; + x.colorfn = NULL; + x.color = color; + x.offset = offset; + return RawToValue(x); +} + +Value ChLookWith(const Value& look, const Image& img, Color (*color)(int i), int i, Point offset) +{ + sChLookWith x; + x.look = look; + x.img = img; + x.colorfn = color; + x.ii = i; + x.offset = offset; + return RawToValue(x); +} + +Value sChOp(Draw& w, const Rect& r, const Value& v, int op); + +struct sChBorder { + const ColorF *border; + Value face; +}; + +Value ChBorder(const ColorF *colors, const Value& face) +{ + sChBorder b; + b.border = colors; + b.face = face; + return RawToValue(b); +} + +Value StdChLookFn(Draw& w, const Rect& r, const Value& v, int op) +{ + if(IsType(v)) { + const sChLookWith& x = ValueTo(v); + if(op == LOOK_PAINT) { + LOGPNG(AsString(x.img.GetSerialId()), x.img); + ChPaint(w, r, x.look); + Point p = r.CenterPos(x.img.GetSize()) + x.offset; + if(x.colorfn) + w.DrawImage(p.x, p.y, x.img, (*x.colorfn)(x.ii)); + else + if(!IsNull(x.color)) + w.DrawImage(p.x, p.y, x.img, x.color); + else + w.DrawImage(p.x, p.y, x.img); + return 1; + } + return sChOp(w, r, x.look, op); + } + if(IsType(v)) { + sChBorder b = ValueTo(v); + int n = (int)(intptr_t)*b.border; + switch(op) { + case LOOK_PAINT: + ChPaint(w, r.Deflated(n), b.face); + case LOOK_PAINTEDGE: + DrawBorder(w, r, b.border); + return 0; + case LOOK_MARGINS: + return Rect(n, n, n, n); + case LOOK_ISBODYOPAQUE: + case LOOK_ISOPAQUE: + return false; + } + } + if(IsType(v)) { + Color c = v; + switch(op) { + case LOOK_PAINT: + w.DrawRect(r, c); + return 0; + case LOOK_PAINTEDGE: + DrawFrame(w, r, c); + return 0; + case LOOK_MARGINS: + return Rect(1, 1, 1, 1); + case LOOK_ISBODYOPAQUE: + case LOOK_ISOPAQUE: + return !IsNull(c); + } + } + if(IsType(v)) { + Image img = v; + Size isz = img.GetSize(); + Size sz = r.GetSize(); + Point p = img.GetHotSpot(); + Point p2 = img.Get2ndSpot(); + int tile = 0; + if(p2.x || p2.y) { + if(p2.x < p.x) { + Swap(p2.x, p.x); + tile = 1; + } + if(p2.y < p.y) { + Swap(p2.y, p.y); + tile += 2; + } + p2.x++; + p2.y++; + } + else { + p2.x = isz.cx - p.x; + p2.y = isz.cy - p.y; + if(p.x > isz.cx / 2) { + tile = 1; + p2.x = p.x; + p.x = isz.cx - p.x - 1; + } + if(p.y > isz.cy / 2) { + tile += 2; + p2.y = p.y; + p.y = isz.cy - p.y - 1; + } + } + if(op == LOOK_MARGINS) + return Rect(p.x, p.y, isz.cx - p2.x, isz.cy - p2.y); + if(op == LOOK_ISOPAQUE) + return img.GetKind() == IMAGE_OPAQUE; + if(IsNull(img)) + return 1; + if(op == LOOK_ISBODYOPAQUE) { + static VectorMap btc; + int64 key = img.GetSerialId(); + int q = btc.Find(key); + if(q < 0) { + bool opaque = true; + Rect m = ChMargins(img); + Rect r = img.GetSize(); + r.left += max(m.left, 0); + r.right -= max(m.right, 0); + r.top += m.top; + r.bottom -= m.bottom; + int cx = r.right - r.left; + if(cx >= 0) + for(int y = r.top; y < r.bottom && opaque; y++) { + const RGBA *s = img[y] + r.left; + const RGBA *e = s + cx; + while(s < e) { + if(s->a != 255) { + opaque = false; + break; + } + } + } + if(btc.GetCount() > 100) + btc.Clear(); + btc.Add(key, q); + return opaque; + } + return btc[q]; + } + if(op == LOOK_PAINT || op == LOOK_PAINTEDGE) { + LTIMING("ChPaint Image"); + w.Clipoff(r); + Rect sr(p, p2); + Size sz2(isz.cx - sr.right, isz.cy - sr.bottom); + Rect r = RectC(p.x, p.y, sz.cx - sr.left - sz2.cx, sz.cy - sr.top - sz2.cy); + int top = minmax(sz.cy / 2, 0, isz.cy); + int bottom = minmax(sz.cy - top, 0, isz.cy); + int yy = isz.cy - bottom; + int left = minmax(sz.cx / 2, 0, isz.cx); + int right = minmax(sz.cx - left, 0, isz.cx); + int xx = isz.cx - right; + if(!r.IsEmpty()) { + w.DrawImage(0, 0, img, RectC(0, 0, p.x, p.y)); + w.DrawImage(0, r.bottom, img, RectC(0, sr.bottom, p.x, sz2.cy)); + w.DrawImage(r.right, 0, img, RectC(sr.right, 0, sz2.cx, p.y)); + w.DrawImage(r.right, r.bottom, img, RectC(sr.right, sr.bottom, sz2.cx, sz2.cy)); + ChDraw(w, p.x, 0, r.Width(), p.y, img, RectC(p.x, 0, sr.Width(), p.y)); + ChDraw(w, p.x, r.bottom, r.Width(), sz2.cy, img, RectC(p.x, sr.bottom, sr.Width(), sz2.cy)); + ChDraw(w, 0, p.y, p.x, r.Height(), img, RectC(0, p.y, p.x, sr.Height())); + ChDraw(w, r.right, p.y, sz2.cx, r.Height(), img, + RectC(sr.right, p.y, sz2.cx, sr.Height())); + if(op == LOOK_PAINT) { + if(IsNull(r) || IsNull(sr)) + return 1; + if(tile) { + LTIMING("Ch-Tiles"); + LTIMING("Ch-Tiles"); + img = Rescale(img, Size((tile & 1 ? sr : r).GetWidth(), + (tile & 2 ? sr : r).GetHeight()), sr); + DrawTiles(w, r, img); + } + else { + static VectorMap btc; + int64 key = img.GetSerialId(); + int q; + { + LTIMING("Find"); + q = btc.Find(key); + } + if(q < 0) { + LTIMING("ClassifyContent"); + q = ClassifyContent(img, sr); + if(btc.GetCount() > 100) + btc.Clear(); + btc.Add(key, q); + } + else + q = btc[q]; + switch(q) { + case IMAGECONTENT_VERTDUP|IMAGECONTENT_HORZDUP: + { + LTIMING("Ch-singlecolor"); + RGBA c = img[sr.top][sr.left]; + if(c.a == 255) { + w.DrawRect(r, c); + break; + } + } + case 0: + default: + ChDraw(w, r, img, sr); + break; + LTIMING("Ch-linedup"); + img = CachedRescalePaintOnly( + img, + Size((q & IMAGECONTENT_HORZDUP) ? max(min(40, r.GetWidth()), sr.GetWidth()) + : r.GetWidth(), + (q & IMAGECONTENT_VERTDUP) ? max(min(40, r.GetHeight()), sr.GetHeight()) + : r.GetHeight()), + sr + ); + LTIMING("Ch-linedup-drawtiles"); + DrawTiles(w, r, img); + break; + } + } + } + } + else + if(r.left < r.right) { + w.DrawImage(0, 0, img, RectC(0, 0, p.x, top)); + w.DrawImage(0, sz.cy - bottom, img, RectC(0, yy, p.x, bottom)); + w.DrawImage(r.right, 0, img, RectC(sr.right, 0, sz2.cx, top)); + w.DrawImage(r.right, sz.cy - bottom, img, RectC(sr.right, yy, sz2.cx, bottom)); + ChDraw(w, p.x, 0, r.Width(), top, img, RectC(p.x, 0, sr.Width(), top)); + ChDraw(w, p.x, sz.cy - bottom, r.Width(), bottom, img, RectC(p.x, yy, sr.Width(), bottom)); + } + else + if(r.top < r.bottom) { + w.DrawImage(0, 0, img, RectC(0, 0, left, p.y)); + w.DrawImage(0, r.bottom, img, RectC(0, sr.bottom, left, sz2.cy)); + w.DrawImage(sz.cx - right, 0, img, RectC(xx, 0, right, p.y)); + w.DrawImage(sz.cx - right, r.bottom, img, RectC(xx, sr.bottom, right, sz2.cy)); + ChDraw(w, 0, p.y, left, r.Height(), img, RectC(0, p.y, left, sr.Height())); + ChDraw(w, sz.cx - right, p.y, right, r.Height(), img, RectC(xx, p.y, right, sr.Height())); + } + else { + w.DrawImage(0, 0, img, RectC(0, 0, left, top)); + w.DrawImage(0, sz.cy - bottom, img, RectC(0, yy, left, top)); + w.DrawImage(sz.cx - right, 0, img, RectC(xx, 0, right, top)); + w.DrawImage(sz.cx - right, sz.cy - bottom, img, RectC(xx, yy, right, bottom)); + } + w.End(); + return 1; + } + } + return Null; +} + +typedef Value (*ChPainterFn)(Draw& w, const Rect& r, const Value& v, int op); + +Vector& sChps() +{ + static Vector x; + return x; +} + +void ChLookFn(Value (*fn)(Draw& w, const Rect& r, const Value& v, int op)) +{ + if(FindIndex(sChps(), fn) < 0) + sChps().Add(fn); +} + +struct sStyleCh : Moveable { + byte *status; + void (*init)(); +}; + +Vector& sChStyle() +{ + static Vector x; + return x; +} + +void ChRegisterStyle__(byte& state, byte& registered, void (*init)()) +{ + if(!registered) { + sStyleCh& s = sChStyle().Add(); + s.status = &state; + s.init = init; + registered = true; + } +} + +void ChReset() +{ + for(int i = 0; i < sChStyle().GetCount(); i++) + *sChStyle()[i].status = 0; + ChLookFn(StdChLookFn); +} + +void ChFinish() +{ + for(int i = 0; i < sChStyle().GetCount(); i++) + sChStyle()[i].init(); +} + +Value sChOp(Draw& w, const Rect& r, const Value& v, int op) +{ + Value q; + if(!IsNull(v)) + for(int i = sChps().GetCount() - 1; i >= 0; i--) { + q = (*sChps()[i])(w, r, v, op); + if(!IsNull(q)) + break; + } + return q; +} + +void ChPaint(Draw& w, const Rect& r, const Value& look) +{ + sChOp(w, r, look, LOOK_PAINT); +} + +void ChPaint(Draw& w, int x, int y, int cx, int cy, const Value& look) +{ + sChOp(w, RectC(x, y, cx, cy), look, LOOK_PAINT); +} + +void ChPaintEdge(Draw& w, const Rect& r, const Value& look) +{ + sChOp(w, r, look, LOOK_PAINTEDGE); +} + +void ChPaintEdge(Draw& w, int x, int y, int cx, int cy, const Value& look) +{ + sChOp(w, RectC(x, y, cx, cy), look, LOOK_PAINTEDGE); +} + +void ChPaintBody(Draw& w, const Rect& r, const Value& look) +{ + Rect m = ChMargins(look); + w.Clip(r); + ChPaint(w, Rect(r.left - m.left, r.top - m.top, r.right + m.right, r.bottom + m.bottom), + look); + w.End(); +} + +void ChPaintBody(Draw& w, int x, int y, int cx, int cy, const Value& look) +{ + ChPaintBody(w, RectC(x, y, cx, cy), look); +} + +Rect ChMargins(const Value& look) +{ + NilDraw w; + return sChOp(w, Null, look, LOOK_MARGINS); +} + +bool ChIsOpaque(const Value& look) +{ + NilDraw w; + return sChOp(w, Null, look, LOOK_ISOPAQUE); +} + +bool ChIsBodyOpaque(const Value& look) +{ + NilDraw w; + return sChOp(w, Null, look, LOOK_ISBODYOPAQUE); +} + +void DeflateMargins(Rect& r, const Rect& m) +{ + r = Rect(r.left + m.left, r.top + m.top, r.right - m.right, r.bottom - m.bottom); +} + +void ChDeflateMargins(Rect& r, const Value& look) +{ + return DeflateMargins(r, ChMargins(look)); +} + +void DeflateMargins(Size& sz, const Rect& m) +{ + sz = Size(sz.cx + m.left + m.right, sz.cy + m.top + m.bottom); +} + +void ChDeflateMargins(Size& sz, const Value& look) +{ + DeflateMargins(sz, ChMargins(look)); +} + +void InflateMargins(Rect& r, const Rect& m) +{ + r = Rect(r.left - m.left, r.top - m.top, r.right + m.right, r.bottom + m.bottom); +} + +void ChInflateMargins(Rect& r, const Value& look) +{ + return InflateMargins(r, ChMargins(look)); +} + +void InflateMargins(Size& sz, const Rect& m) +{ + sz = Size(sz.cx + m.left + m.right, sz.cy + m.top + m.bottom); +} + +void ChInflateMargins(Size& sz, const Value& look) +{ + InflateMargins(sz, ChMargins(look)); +} + +Image AdjustColors(const Image& img) { + const RGBA *s = ~img; + const RGBA *e = s + img.GetLength(); + ImageBuffer w(img.GetSize()); + RGBA *t = w; + Color black = SColorText(); + Color shadow = SColorShadow(); + Color face = SColorFace(); + Color light = SColorLight(); + Color highlight = SColorHighlight(); + Color hot = highlight; + Color paper = SColorPaper(); + while(s < e) { + *t = *s; + if(s->r == s->g && s->g == s->b) + if(s->r < 128) + *t = Blend(black, shadow, 2 * s->r); + else + if(s->r >= 128 && s->r < 192) + *t = Blend(shadow, face, 4 * (s->r - 128)); + else + *t = Blend(face, light, 4 * (s->r - 192)); + else + if(s->r == 0 && s->g == 0) + *t = Blend(black, highlight, 2 * (s->b - 128)); + else + if(s->b == 0 && s->g == 0) + *t = Blend(black, hot, 2 * (s->r - 128)); + else + if(s->r == s->g && s->b == 0) + *t = Blend(black, paper, s->r); + t->a = s->a; + t++; + s++; + } + w.SetHotSpot(img.GetHotSpot()); + w.Set2ndSpot(img.Get2ndSpot()); + return w; +} + +void Override(Iml& target, Iml& source, bool colored) +{ + for(int i = 0; i < target.GetCount(); i++) { + int q = source.Find(target.GetId(i)); + if(q >= 0) { + Image m = source.Get(q); + if(colored) + m = AdjustColors(m); + target.Set(i, m); + } + } +} + +void ColoredOverride(Iml& target, Iml& source) +{ + Override(target, source, true); +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/Cham.h b/uppdev/Draw/Cham.h new file mode 100644 index 000000000..ab7f6437f --- /dev/null +++ b/uppdev/Draw/Cham.h @@ -0,0 +1,117 @@ +enum LookOp { + LOOK_PAINT, + LOOK_MARGINS, + LOOK_PAINTEDGE, + LOOK_ISOPAQUE, + LOOK_ISBODYOPAQUE, +}; + +void ChLookFn(Value (*fn)(Draw& w, const Rect& r, const Value& look, int lookop)); + +Image AdjustColors(const Image& img); + +void Override(Iml& target, Iml& source, bool colored = false); +void ColoredOverride(Iml& target, Iml& source); + +void ChReset(); +void ChFinish(); + +void ChPaint(Draw& w, const Rect& r, const Value& look); +void ChPaint(Draw& w, int x, int y, int cx, int cy, const Value& look); +void ChPaintEdge(Draw& w, const Rect& r, const Value& look); +void ChPaintEdge(Draw& w, int x, int y, int cx, int cy, const Value& look); +void ChPaintBody(Draw& w, const Rect& r, const Value& look); +void ChPaintBody(Draw& w, int x, int y, int cx, int cy, const Value& look); +Rect ChMargins(const Value& look); +bool ChIsOpaque(const Value& look); +bool ChIsBodyOpaque(const Value& look); + +void DeflateMargins(Rect& r, const Rect& margin); +void ChDeflateMargins(Rect& r, const Value& look); +void DeflateMargins(Size& sz, const Rect& m); +void ChDeflateMargins(Size& sz, const Value& look); +void InflateMargins(Rect& r, const Rect& m); +void ChInflateMargins(Rect& r, const Value& look); +void InflateMargins(Size& sz, const Rect& m); +void ChInflateMargins(Size& sz, const Value& look); + +template +struct ChStyle { + byte status; + byte registered; + T *standard; + + const T& Standard() const { return *standard; } + T& Write() const { T& x = *(T *)this; x.status = 2; return x; } + void Assign(const T& src) { *(T *)this = src; } + + ChStyle() { status = 0; registered = 0; standard = NULL; } +}; + +#define CH_STYLE(klass, type, style) \ +struct COMBINE5(klass, __, type, __, style) : klass::type { \ + void Init(); \ + static void InitIt(); \ +}; \ +\ +void COMBINE5(klass, __, type, __, style)::InitIt() { \ + klass::style(); \ +} \ +\ +const klass::Style& klass::style() \ +{ \ + static COMBINE5(klass, __, type, __, style) b, standard; \ + if(b.status == 0) { \ + ChRegisterStyle__(b.status, b.registered, COMBINE5(klass, __, type, __, style)::InitIt); \ + b.Init(); \ + b.status = 1; \ + standard = b; \ + standard.standard = b.standard = &standard; \ + } \ + return b; \ +} \ +\ +void COMBINE5(klass, __, type, __, style)::Init() + +#define CH_VAR(chtype, type, name, init) \ +chtype& COMBINE(ch_var__, name)(); \ +void COMBINE(ch_init__, name)() { \ + COMBINE(ch_var__, name)(); \ +} \ +\ +chtype& COMBINE(ch_var__, name)() { \ + static chtype b; \ + if(b.status == 0) { \ + ChRegisterStyle__(b.status, b.registered, COMBINE(ch_init__, name)); \ + b.value = init; \ + b.status = 1; \ + } \ + return b; \ +} \ +\ +type name() { return COMBINE(ch_var__, name)().value; } \ +void COMBINE(name, _Write)(type v) { COMBINE(ch_var__, name)().Write().value = v; } + +struct ChColor : ChStyle { Color value; }; +#define CH_COLOR(name, init) CH_VAR(ChColor, Color, name, init) + +struct ChInt : ChStyle { int value; }; +#define CH_INT(name, init) CH_VAR(ChInt, int, name, init) + +struct ChValue : ChStyle { Value value; }; +#define CH_VALUE(name, init) CH_VAR(ChValue, Value, name, init) + +struct ChImage : ChStyle { Image value; }; +#define CH_IMAGE(name, init) CH_VAR(ChImage, Image, name, init) + +void ChPaint(Draw& w, const Rect& r, const Value& element); +void ChPaint(Draw& w, int x, int y, int cx, int cy, const Value& element); + +Value ChLookWith(const Value& look, const Image& img, Point offset = Point(0, 0)); +Value ChLookWith(const Value& look, const Image& img, Color color, Point offset = Point(0, 0)); +Value ChLookWith(const Value& look, const Image& img, Color (*color)(int i), int i, Point offset = Point(0, 0)); + +//private: +void ChRegisterStyle__(byte& state, byte& registered, void (*init)()); + +Value ChBorder(const ColorF *colors, const Value& face = SColorFace()); diff --git a/uppdev/Draw/ComposeText.cpp b/uppdev/Draw/ComposeText.cpp new file mode 100644 index 000000000..9576ee61b --- /dev/null +++ b/uppdev/Draw/ComposeText.cpp @@ -0,0 +1,275 @@ +#include "Draw.h" + +NAMESPACE_UPP + +enum { + CG_NONE, + CG_CAPITAL, + CG_SMALL +}; + +enum { + CG_GRAVE = 0x60, + CG_ACUTE = 0xb4, + CG_CEDILLA = 0xb8, + CG_MACRON = 175, + CG_CIRCUMFLEX = 0x2c6, + CG_TILDE = 0x2dc, + CG_DOT_ABOVE = 0x2d9, + CG_OGONEK = 0x2db, + CG_STROKE = '-', + CG_BREVE = 0x2d8, + CG_CARON = 0x2c7, + CG_MIDDLE_DOT = 0xb7, + CG_DOUBLE_ACUTE = 0x2dd, + CG_DIAERESIS = 0xa8, + CG_RING_ABOVE = 0x2da, + CG_COMMA_T = ',', + CG_COMMA_UR = 1, + CG_COMMA_URI, +}; + +struct CGInfo { + byte type; + char ascii; + wchar mark; +} +gc_info[128] = { + { CG_CAPITAL, 'A', CG_MACRON }, + { CG_SMALL, 'a', CG_MACRON }, + { CG_CAPITAL, 'A', CG_BREVE }, + { CG_SMALL, 'a', CG_BREVE }, + { CG_CAPITAL, 'A', CG_OGONEK }, + { CG_SMALL, 'a', CG_OGONEK }, + { CG_CAPITAL, 'C', CG_ACUTE }, + { CG_SMALL, 'c', CG_ACUTE }, + { CG_CAPITAL, 'C', CG_CIRCUMFLEX }, + { CG_SMALL, 'c', CG_CIRCUMFLEX }, + { CG_CAPITAL, 'C', CG_DOT_ABOVE }, + { CG_SMALL, 'c', CG_DOT_ABOVE }, + { CG_CAPITAL, 'C', CG_CARON }, + { CG_SMALL, 'c', CG_CARON }, + { CG_CAPITAL, 'D', CG_CARON }, + { CG_SMALL, 'd', CG_COMMA_UR }, + { CG_CAPITAL, 'D', CG_STROKE }, + { CG_SMALL, 'd', CG_STROKE }, + { CG_CAPITAL, 'E', CG_MACRON }, + { CG_SMALL, 'e', CG_MACRON }, + { CG_CAPITAL, 'E', CG_BREVE }, + { CG_SMALL, 'e', CG_BREVE }, + { CG_CAPITAL, 'E', CG_DOT_ABOVE }, + { CG_SMALL, 'e', CG_DOT_ABOVE }, + { CG_CAPITAL, 'E', CG_OGONEK }, + { CG_SMALL, 'e', CG_OGONEK }, + { CG_CAPITAL, 'E', CG_CARON }, + { CG_SMALL, 'e', CG_CARON }, + { CG_CAPITAL, 'G', CG_CIRCUMFLEX }, + { CG_SMALL, 'g', CG_CIRCUMFLEX }, + { CG_CAPITAL, 'G', CG_BREVE }, + { CG_SMALL, 'g', CG_BREVE }, + { CG_CAPITAL, 'G', CG_DOT_ABOVE }, + { CG_SMALL, 'g', CG_DOT_ABOVE }, + { CG_CAPITAL, 'G', CG_CEDILLA }, + { CG_SMALL, 'g', CG_CEDILLA }, + { CG_CAPITAL, 'H', CG_CIRCUMFLEX }, + { CG_SMALL, 'h', CG_CIRCUMFLEX }, + { CG_CAPITAL, 'H', CG_STROKE }, + { CG_SMALL, 'h', CG_STROKE }, + { CG_CAPITAL, 'I', CG_TILDE }, + { CG_SMALL, 'i', CG_TILDE }, + { CG_CAPITAL, 'I', CG_MACRON }, + { CG_SMALL, 'i', CG_MACRON }, + { CG_CAPITAL, 'I', CG_BREVE }, + { CG_SMALL, 'i', CG_BREVE }, + { CG_CAPITAL, 'I', CG_OGONEK }, + { CG_SMALL, 'i', CG_OGONEK }, + { CG_CAPITAL, 'I', CG_DOT_ABOVE }, + { CG_NONE, 0, 0 }, // , CG_SMALL, 'DOTLESS I + { CG_NONE, 0, 0 }, // LATIN CAPITAL LIGATURE IJ + { CG_NONE, 0, 0 }, // LATIN SMALL LIGATURE IJ + { CG_CAPITAL, 'J', CG_CIRCUMFLEX }, + { CG_SMALL, 'j', CG_CIRCUMFLEX }, + { CG_CAPITAL, 'K', CG_CEDILLA }, + { CG_SMALL, 'k', CG_CEDILLA }, + { CG_NONE, 0, 0 }, // CG_SMALL, 'KRA + { CG_CAPITAL, 'L', CG_ACUTE }, + { CG_SMALL, 'l', CG_ACUTE }, + { CG_CAPITAL, 'L', CG_CEDILLA }, + { CG_SMALL, 'l', CG_CEDILLA }, + { CG_CAPITAL, 'L', CG_COMMA_URI }, + { CG_SMALL, 'l', CG_COMMA_UR }, + { CG_CAPITAL, 'L', CG_MIDDLE_DOT }, + { CG_SMALL, 'l', CG_MIDDLE_DOT }, + { CG_CAPITAL, 'L', CG_STROKE }, + { CG_SMALL, 'l', CG_STROKE }, + { CG_CAPITAL, 'N', CG_ACUTE }, + { CG_SMALL, 'n', CG_ACUTE }, + { CG_CAPITAL, 'N', CG_CEDILLA }, + { CG_SMALL, 'n', CG_CEDILLA }, + { CG_CAPITAL, 'N', CG_CARON }, + { CG_SMALL, 'n', CG_CARON }, + { CG_NONE, 0, 0 }, // CG_SMALL, 'N PRECEDED BY APOSTROPHE + { CG_NONE, 0, 0 }, //CG_CAPITAL, 'ENG + { CG_NONE, 0, 0 }, //CG_SMALL, 'ENG + { CG_CAPITAL, 'O', CG_MACRON }, + { CG_SMALL, 'o', CG_MACRON }, + { CG_CAPITAL, 'O', CG_BREVE }, + { CG_SMALL, 'o', CG_BREVE }, + { CG_CAPITAL, 'O', CG_DOUBLE_ACUTE }, + { CG_SMALL, 'o', CG_DOUBLE_ACUTE }, + { CG_NONE, 0, 0 }, // LATIN CAPITAL LIGATURE OE + { CG_NONE, 0, 0 }, // LATIN SMALL LIGATURE OE + { CG_CAPITAL, 'R', CG_ACUTE }, + { CG_SMALL, 'r', CG_ACUTE }, + { CG_CAPITAL, 'R', CG_CEDILLA }, + { CG_SMALL, 'r', CG_CEDILLA }, + { CG_CAPITAL, 'R', CG_CARON }, + { CG_SMALL, 'r', CG_CARON }, + { CG_CAPITAL, 'S', CG_ACUTE }, + { CG_SMALL, 's', CG_ACUTE }, + { CG_CAPITAL, 'S', CG_CIRCUMFLEX }, + { CG_SMALL, 's', CG_CIRCUMFLEX }, + { CG_CAPITAL, 'S', CG_CEDILLA }, + { CG_SMALL, 's', CG_CEDILLA }, + { CG_CAPITAL, 'S', CG_CARON }, + { CG_SMALL, 's', CG_CARON }, + { CG_CAPITAL, 'T', CG_CEDILLA }, + { CG_SMALL, 't', CG_CEDILLA }, + { CG_CAPITAL, 'T', CG_CARON }, + { CG_SMALL, 't', CG_COMMA_T }, + { CG_CAPITAL, 'T', CG_STROKE }, + { CG_SMALL, 't', CG_STROKE }, + { CG_CAPITAL, 'U', CG_TILDE }, + { CG_SMALL, 'u', CG_TILDE }, + { CG_CAPITAL, 'U', CG_MACRON }, + { CG_SMALL, 'u', CG_MACRON }, + { CG_CAPITAL, 'U', CG_BREVE }, + { CG_SMALL, 'u', CG_BREVE }, + { CG_CAPITAL, 'U', CG_RING_ABOVE }, + { CG_SMALL, 'u', CG_RING_ABOVE }, + { CG_CAPITAL, 'U', CG_DOUBLE_ACUTE }, + { CG_SMALL, 'u', CG_DOUBLE_ACUTE }, + { CG_CAPITAL, 'U', CG_OGONEK }, + { CG_SMALL, 'u', CG_OGONEK }, + { CG_CAPITAL, 'W', CG_CIRCUMFLEX }, + { CG_SMALL, 'w', CG_CIRCUMFLEX }, + { CG_CAPITAL, 'Y', CG_CIRCUMFLEX }, + { CG_SMALL, 'y', CG_CIRCUMFLEX }, + { CG_CAPITAL, 'Y', CG_DIAERESIS }, + { CG_CAPITAL, 'Z', CG_ACUTE }, + { CG_SMALL, 'z', CG_ACUTE }, + { CG_CAPITAL, 'Z', CG_DOT_ABOVE }, + { CG_SMALL, 'z', CG_DOT_ABOVE }, + { CG_CAPITAL, 'Z', CG_CARON }, + { CG_SMALL, 'z', CG_CARON }, + { CG_NONE, 0, 0 } // CG_SMALL, 'LONG S +}; + +SystemDraw& ScreenInfo(); + +void FontInfo::ComposeMetrics(Font fnt, CharMetrics *m, int page) const +{ + if(fnt.GetFaceInfo() & Font::COMPOSED) { + FontInfo fi = fnt.Info(); + for(int i = 0; i < 32; i++) { + int c = gc_info[i + (page - 8) * 32].ascii; + m[i].lspc = fi.GetLeftSpace(c); + m[i].width = fi[c]; + m[i].rspc = fi.GetRightSpace(c); + if(gc_info[i].type == CG_COMMA_UR && !fi.IsFixedPitch()) + m[i].rspc += m[i].width / 2; + } + } +} + +void Draw::ComposeText(int x, int y, int angle, const wchar *text, Font font, Color ink, + int n, const int *dx) { + if(font.GetFaceInfo() & Font::COMPOSED) { + for(int i = 0; i < n; i++) + if(text[i] >= 256 && text[i] < 256 + 128) { + FontInfo fi = font.Info(); + Clip(x, y, 9999, fi.GetHeight()); + Buffer ntext(n); + double sina; + double cosa; + Size offset; + if(angle) + SinCos(angle, sina, cosa); //TODO global sin tables! + int xp = 0; + for(int i = 0; i < n; i++) { + wchar chr = text[i]; + ntext[i] = chr; + if(chr >= 256 && chr < 256 + 128) { + CGInfo f = gc_info[chr - 256]; + if(f.type != CG_NONE) { + ntext[i] = chr = f.ascii; + Font mfnt = font; + FontInfo mfi = fi; + int my = 0; + int mx = 0; + int cw = fi[f.ascii]; + int mw = mfi[f.mark]; + wchar mark = f.mark; + if(mark == CG_COMMA_UR && fi.IsFixedPitch()) + mark = CG_CARON; + if(mark == CG_COMMA_T) { + my -= 3 * font.GetHeight() / 4; + mx += 4 * cw / 10; + if(font.IsItalic()) + mx += mw / 2; + } + else + if(mark == CG_COMMA_UR) { + my -= 2 * font.GetHeight() / 3; + mx += cw - mw / 4; + mark = ','; + if(font.IsItalic()) + mx += mw / 3; + } + else + if(mark == CG_COMMA_URI) { + my -= 2 * font.GetHeight() / 3; + mx += cw - mw / 2; + mark = ','; + if(font.IsItalic()) + mx += mw / 3; + } + else + if(mark != CG_STROKE) { + if(f.mark != CG_OGONEK && f.mark != CG_CEDILLA && f.type == CG_CAPITAL) { + mfnt = font(9 * font.GetHeight() / 10); + mfi = mfnt.Info(); + my -= mark == CG_RING_ABOVE ? font.GetHeight() / 19 + : font.GetHeight() / 13; + } + mw = mfi[f.mark]; + mx += (cw - mw) / 2; + if(font.IsItalic()) + mx += mw / 5; + } + if(angle) + DrawText(int(x + cosa * (xp + mx) + sina * my), + int(y - sina * (xp + mx) + cosa * my), + angle, &mark, mfnt, ink, 1); + else + DrawText(x + xp + mx, y + my, &mark, mfnt, ink, 1); + } + } + if(angle) + DrawTextOp(int(x + cosa * xp), int(y - sina * xp), + angle, &chr, font, ink, 1, dx); + if(dx) + xp += dx[i]; + else + xp += fi[chr]; + } + if(!angle) + DrawTextOp(x, y, angle, ntext, font, ink, n, dx); + End(); + return; + } + } + DrawTextOp(x, y, angle, text, font, ink, n, dx); +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/Copying b/uppdev/Draw/Copying new file mode 100644 index 000000000..f135f3633 --- /dev/null +++ b/uppdev/Draw/Copying @@ -0,0 +1,21 @@ +Copyright 1998-2008 The U++ Project. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted +provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE U++ PROJECT ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/uppdev/Draw/Debug.cpp b/uppdev/Draw/Debug.cpp new file mode 100644 index 000000000..c58deec8b --- /dev/null +++ b/uppdev/Draw/Debug.cpp @@ -0,0 +1,564 @@ +#include "Draw.h" + +NAMESPACE_UPP + +String DumpLanguage(int language) +{ + if(IsNull(language)) + return "Null"; + char out[5]; + out[0] = (char)(language >> 24); + out[1] = (char)(language >> 16); + out[2] = '-'; + out[3] = (char)(language >> 8); + out[4] = (char)(language >> 0); + return String(out, 5); +} + +String DumpAlign(int align) +{ + String ss; + switch(align) + { + case ALIGN_NULL: return "ALIGN_NULL"; + case ALIGN_LEFT: return "ALIGN_LEFT"; + case ALIGN_CENTER: return "ALIGN_CENTER"; + case ALIGN_RIGHT: return "ALIGN_RIGHT"; + case ALIGN_JUSTIFY: return "ALIGN_JUSTIFY"; + default: return ss << "ALIGNMENT(" << (int)align << ")"; + } +} + +String DumpColor(Color color) +{ + if(IsNull(color)) + return "Null"; + int r = color.GetR(), g = color.GetG(), b = color.GetB(); + byte xr = -r, xg = -g, xb = -b; + static const char *stdc[] = { "Black", "LtBlue", "LtGreen", "LtCyan", "LtRed", "LtMagenta", "Yellow", "White" }; + if((xr | xg | xb) <= 1) + return stdc[4 * xr + 2 * xg + xb]; + String ss; + return ss << "Color(" << r << ", " << g << ", " << b << ")"; +} + +String DumpFont(Font font) +{ + String out; + if(IsNull(font)) + out << "Font(Null)"; + else + { + out << "Font()"; + out << ".Face(" << font.GetFace() << ")"; + out << ".FaceName(\"" << font.GetFaceName() << "\")"; + out << ".Height(" << font.GetHeight() << ")"; + out << ".Width(" << font.GetWidth() << ")"; + + if(font.IsItalic()) out << ".Italic()"; + if(font.IsBold()) out << ".Bold()"; + if(font.IsUnderline()) out << ".Underline()"; + if(font.IsStrikeout()) out << ".Strikeout()"; + } + return out; +} + +String DumpFontInfo(FontInfo fi) +{ + String out; + out << "FontInfo(font = " << fi.GetFont() << "\n" + "\tempty = " << fi.IsEmpty() << "\n" + "\tascent = " << fi.GetAscent() << "\n" + "\tdescent = " << fi.GetDescent() << "\n" + "\texternal leading = " << fi.GetExternal() << "\n" + "\tinternal leading = " << fi.GetInternal() << "\n" + "\theight = " << fi.GetHeight() << "\n" + "\tline height = " << fi.GetLineHeight() << "\n" + "\toverhang = " << fi.GetOverhang() << "\n" + "\taverage width = " << fi.GetAveWidth() << "\n" + "\tmaximum width = " << fi.GetMaxWidth() << "\n" + "\tfixed pitch = " << fi.IsFixedPitch() << "\n" + "\tscaleable = " << fi.IsScaleable() << "\n" + "\tfont height = " << fi.GetFontHeight() << "\n"; + + out << "\n\twidth:\n"; + int i; + for(i = 0; i < 256; i++) + out << NFormat(i & 15 ? " " : "\n\t%02x\t", i) << NFormat("%2>d", fi[i]); + out << "\n\n\tleft space:\n"; + for(i = 0; i < 256; i++) + out << NFormat(i & 15 ? " " : "\n\t%02x\t", i) << NFormat("%2>d", fi.GetLeftSpace(i)); + out << "\n\n\tright space:\n"; + for(i = 0; i < 256; i++) + out << NFormat(i & 15 ? " " : "\n\t%02x\t", i) << NFormat("%2>d", fi.GetRightSpace(i)); + out << "\n\n\tkerning:\n"; + int kp = 0; + for(i = 0; i < 256; i++) + for(int j = 0; j < 256; j++) + if(int k = fi.GetKerning(i, j)) + out << (kp++ & 7 ? " " : "\n\t") << NFormat("(%02x,%02x)=%2>d", i, j, k); + out << (kp ? "\n" : "\tnone\n"); + return out; +} + +#ifdef PLATFORM_X11 +enum +{ + GCAllMask = GCFunction + | GCPlaneMask + | GCForeground + | GCBackground + | GCLineWidth + | GCLineStyle + | GCCapStyle + | GCJoinStyle + | GCFillStyle + | GCFillRule + | GCArcMode + | GCTile + | GCStipple + | GCTileStipXOrigin + | GCTileStipYOrigin + | GCFont + | GCSubwindowMode + | GCGraphicsExposures + | GCClipXOrigin + | GCClipYOrigin +// | GCClipMask + | GCDashOffset +// | GCDashList +}; +#endif + +#ifdef PLATFORM_X11 +String DumpPixmap(Pixmap pixmap) +{ + String out; + if(pixmap == Pixmap(-1)) + out << "NULL"; + else + { + Window root; + int x, y; + unsigned width, height, border_width, depth; + XGetGeometry(Xdisplay, pixmap, &root, &x, &y, &width, &height, &border_width, &depth); + out << (int)width << " x " << (int)height << ", depth = " << (int)depth; + } + return out; +} +#endif + +#ifdef PLATFORM_X11 +String DumpXFont(XFont font) +{ + XFontStruct *fs = XQueryFont(Xdisplay, font); + String out = DumpXFontStruct(fs); + if(fs) + XFreeFontInfo(NULL, fs, 0); + return out; +} +#endif + +#ifdef PLATFORM_X11 +String DumpXFontStruct(XFontStruct *fs) +{ + String out; + if(!fs) + out << "NULL\n"; + else + { + out << + "direction=" << (int)fs -> direction << "\n" + "min_char_or_byte2=" << (int)fs -> min_char_or_byte2 << "\n" + "max_char_or_byte2=" << (int)fs -> max_char_or_byte2 << "\n" + "min_byte1=" << (int)fs -> min_byte1 << "\n" + "max_byte1=" << (int)fs -> max_byte1 << "\n" + "all_chars_exist=" << (int)fs -> all_chars_exist << "\n" + "default_char=" << (int)fs -> default_char << "\n" + "n_properties=" << (int)fs -> n_properties << "\n"; + for(int i = 0; i < fs -> n_properties; i++) + { + char *name = XGetAtomName(Xdisplay, fs -> properties[i].name); + out << "properties[" << i << "]=" << name << ", card32 = " << (int)fs -> properties[i].card32 << "\n"; + XFree(name); + } + out << + "min_bounds=" << (int)fs -> min_bounds.width << " x " + << (int)fs -> min_bounds.ascent << " + " << (int)fs -> min_bounds.descent << "\n" + "max_bounds=" << (int)fs -> max_bounds.width << " x " + << (int)fs -> max_bounds.ascent << " + " << (int)fs -> max_bounds.descent << "\n"; + out << + "ascent=" << (int)fs -> ascent << "\n" + "descent=" << (int)fs -> descent << "\n"; + } + return out; +} +#endif + +#ifdef PLATFORM_X11 +String DumpGC(GC gc) +{ + XGCValues values; + Zero(values); + XGetGCValues(Xdisplay, gc, GCAllMask & ~GCFont, &values); + String out = DumpGCValues(values); + XFontStruct *gc_font = XQueryFont(Xdisplay, (XID)gc); + out << "GCFont=" << DumpXFontStruct(gc_font) << "\n"; + if(gc_font) + XFreeFontInfo(NULL, gc_font, 0); + return out; +} +#endif + +#ifdef PLATFORM_X11 +String DumpGCValues(const XGCValues& gc_values, int mask) +{ + String out; + if(mask & GCFunction) + { + static const char *names[] = + { + "X11_ROP2_ZERO", + "X11_ROP2_AND", + "X11_ROP2_AND_NOT", + "X11_ROP2_COPY", + "X11_ROP2_NOT_AND", + "X11_ROP2_NOP", + "X11_ROP2_XOR", + "X11_ROP2_OR", + "X11_ROP2_NOT_AND_NOT", + "X11_ROP2_NOT_XOR", + "X11_ROP2_INVERT", + "X11_ROP2_OR_NOT", + "X11_ROP2_NOT_COPY", + "X11_ROP2_NOT_OR", + "X11_ROP2_NOT_OR_NOT", + "X11_ROP2_ONE", + }; + ASSERT(__countof(names) == 16); + out << "GCFunction=" << (int)gc_values.function << ", " << names[gc_values.function & 15] << "\n"; + } + if(mask & GCPlaneMask) + out << "GCPlaneMask=" << Format("%08x", (int)gc_values.plane_mask) << "\n"; + if(mask & GCForeground) + out << "GCForeground=" << Format("%08x", (int)gc_values.foreground) << "\n"; + if(mask & GCBackground) + out << "GCBackground=" << Format("%08x", (int)gc_values.background) << "\n"; + if(mask & GCLineWidth) + out << "GCLineWidth=" << (int)gc_values.line_width << "\n"; + if(mask & GCLineStyle) + { + out << "GCLineStyle=" << (int)gc_values.line_style << ", "; + switch(gc_values.line_style) + { + case LineSolid: out << "LineSolid"; break; + case LineOnOffDash: out << "LineOnOffDash"; break; + case LineDoubleDash: out << "LineDoubleDash"; break; + default: out << "unknown"; break; + } + out << "\n"; + } + if(mask & GCCapStyle) + { + out << "GCCapStyle=" << (int)gc_values.cap_style << ", "; + switch(gc_values.cap_style) + { + case CapNotLast: out << "CapNotLast"; break; + case CapButt: out << "CapButt"; break; + case CapRound: out << "CapRound"; break; + case CapProjecting: out << "CapProjecting"; break; + default: out << "unknown"; break; + } + out << "\n"; + } + if(mask & GCJoinStyle) + { + out << "GCJoinStyle=" << (int)gc_values.join_style << ", "; + switch(gc_values.join_style) + { + case JoinMiter: out << "JoinMiter"; break; + case JoinRound: out << "JoinRound"; break; + case JoinBevel: out << "JoinBevel"; break; + default: out << "unknown"; break; + } + out << "\n"; + } + if(mask & GCFillStyle) + { + out << "GCFillStyle=" << (int)gc_values.fill_style << ", "; + switch(gc_values.fill_style) + { + case FillSolid: out << "FillSolid"; break; + case FillTiled: out << "FillTiled"; break; + case FillStippled: out << "FillStippled"; break; + case FillOpaqueStippled: out << "FillOpaqueStippled"; break; + default: out << "unknown"; break; + } + out << "\n"; + } + if(mask & GCFillRule) + { + out << "GCFillRule=" << (int)gc_values.fill_rule << ", "; + switch(gc_values.fill_rule) + { + case EvenOddRule: out << "EvenOddRule"; break; + case WindingRule: out << "WindingRule"; break; + default: out << "unknown"; break; + } + out << "\n"; + } + if(mask & GCArcMode) + { + out << "GCArcMode=" << (int)gc_values.arc_mode << ", "; + switch(gc_values.arc_mode) + { + case ArcChord: out << "ArcChord"; break; + case ArcPieSlice: out << "ArcPieSlice"; break; + default: out << "unknown"; break; + } + out << "\n"; + } + if(mask & GCTile) + out << "GCTile=" << DumpPixmap(gc_values.tile) << "\n"; + if(mask & GCStipple) + out << "GCStipple=" << DumpPixmap(gc_values.stipple) << "\n"; + if(mask & GCTileStipXOrigin) + out << "GCTileStipXOrigin=" << (int)gc_values.ts_x_origin << "\n"; + if(mask & GCTileStipYOrigin) + out << "GCTileStipYOrigin=" << (int)gc_values.ts_y_origin << "\n"; + if(mask & GCFont) + out << "GCFont=" << DumpXFont(gc_values.font) << "\n"; + if(mask & GCSubwindowMode) + { + out << "GCSubwindowMode=" << (int)gc_values.subwindow_mode << ", "; + switch(gc_values.subwindow_mode) + { + case ClipByChildren: out << "ClipByChildren"; break; + case IncludeInferiors: out << "IncludeInferiors"; break; + default: out << "unknown"; break; + } + } + if(mask & GCGraphicsExposures) + out << "GCGraphicsExposures=" << (gc_values.graphics_exposures ? "true" : "false") << "\n"; + if(mask & GCClipXOrigin) + out << "GCClipXOrigin=" << (int)gc_values.clip_x_origin; + if(mask & GCClipYOrigin) + out << "GCClipYOrigin=" << (int)gc_values.clip_y_origin; +// if(mask & GCClipMask) +// out << "GCClipMask=" << DumpPixmap(gc_values.clip_mask); + if(mask & GCDashOffset) + out << "GCDashOffset=" << (int)gc_values.dash_offset; +// if(mask & GCDashList) +// out << "GCDashList=" << Format("%02x\n", gc_values.dashes); + return out; +} +#endif + +#ifdef PLATFORM_X11 +String DumpEvent(XEvent *event) +{ + String out; + if(!event) + out << "NULL"; + else + { + out << "event_type=" << (int)event -> type << ", "; + switch(event -> type) + { + case KeyPress: + out << "KeyPress, state=" << (int)event -> xkey.state << ", keycode=" << (int)event -> xkey.keycode; + break; + + case KeyRelease: + out << "KeyRelease, state=" << (int)event -> xkey.state << ", keycode=" << (int)event -> xkey.keycode; + break; + + case ButtonPress: + out << "ButtonPress, x=" << (int)event -> xbutton.x << ", y=" << (int)event -> xbutton.y << ", state=" << (int)event -> xbutton.state << ", button=" << (int)event -> xbutton.button; + break; + + case ButtonRelease: + out << "ButtonRelease, x=" << (int)event -> xbutton.x << ", y=" << (int)event -> xbutton.y << ", state=" << (int)event -> xbutton.state << ", button=" << (int)event -> xbutton.button; + break; + + case MotionNotify: + out << "MotionNotify, x=" << (int)event -> xmotion.x << ", y=" << (int)event -> xmotion.y << ", state=" << (int)event -> xmotion.state; + break; + + case EnterNotify: + case LeaveNotify: + out << (event -> type == EnterNotify ? "EnterNotify" : "LeaveNotify") << ", mode="; + switch(event -> xcrossing.mode) + { + case NotifyNormal: out << "NotifyNormal"; break; + case NotifyGrab: out << "NotifyGrab"; break; + case NotifyUngrab: out << "NotifyUngrab"; break; + default: out << "unknown"; break; + } + out << ", detail="; + switch(event -> xcrossing.detail) + { + case NotifyAncestor: out << "NotifyAncestor"; break; + case NotifyVirtual: out << "NotifyVirtual"; break; + case NotifyInferior: out << "NotifyInferior"; break; + case NotifyNonlinear: out << "NotifyNonlinear"; break; + case NotifyNonlinearVirtual: out << "NotifyNonlinearVirtual"; break; + default: out << "unknown (" << (int)event -> xcrossing.detail << ")"; break; + } + out << ", same_screen=" << (event -> xcrossing.same_screen ? "true" : "false") + << ", focus=" << (event -> xcrossing.focus ? "true" : "false") + << ", state=" << (int)event -> xcrossing.state; + break; + + case FocusIn: + case FocusOut: + out << (event -> type == FocusIn ? "FocusIn" : "FocusOut") << ", mode="; + switch(event -> xfocus.mode) + { + case NotifyNormal: out << "NotifyNormal"; break; + case NotifyGrab: out << "NotifyGrab"; break; + case NotifyUngrab: out << "NotifyUngrab"; break; + default: out << "unknown"; break; + } + out << ", detail="; + switch(event -> xfocus.detail) + { + case NotifyAncestor: out << "NotifyAncestor"; break; + case NotifyVirtual: out << "NotifyVirtual"; break; + case NotifyInferior: out << "NotifyInferior"; break; + case NotifyNonlinear: out << "NotifyNonlinear"; break; + case NotifyNonlinearVirtual: out << "NotifyNonlinearVirtual"; break; + case NotifyPointer: out << "NotifyPointer"; break; + case NotifyPointerRoot: out << "NotifyPointerRoot"; break; + case NotifyDetailNone: out << "NotifyDetailNone"; break; + default: out << "unknown (" << (int)event -> xfocus.detail << ")"; break; + } + break; + + case KeymapNotify: + out << "KeymapNotify"; + break; + + case Expose: + out << "Expose [" << event -> xexpose.x << ", " << event -> xexpose.y + << " - " << (event -> xexpose.x + event -> xexpose.width) + << ", " << (event -> xexpose.y + event -> xexpose.height) << "], count=" << event -> xexpose.count; + break; + + case GraphicsExpose: + out << "GraphicsExpose [" << event -> xgraphicsexpose.x << ", " << event -> xgraphicsexpose.y + << " - " << (event -> xgraphicsexpose.x + event -> xgraphicsexpose.width) + << ", " << (event -> xgraphicsexpose.y + event -> xgraphicsexpose.height) << "], " + "count=" << event -> xgraphicsexpose.count + << ", major_code=" << (int)event -> xgraphicsexpose.major_code + << ", minor_code=" << (int)event -> xgraphicsexpose.minor_code; + break; + + case NoExpose: + out << "NoExpose" + << ", major_code=" << (int)event -> xnoexpose.major_code + << ", minor_code=" << (int)event -> xnoexpose.minor_code; + break; + + case VisibilityNotify: + out << "VisibilityNotify, state=" << (int)event -> xvisibility.state; + break; + + case CreateNotify: + out << "CreateNotify [" << event -> xcreatewindow.x << ", " << event -> xcreatewindow.y + << " - " << (event -> xcreatewindow.x + event -> xcreatewindow.width) + << ", " << (event -> xcreatewindow.y + event -> xcreatewindow.height) << "], " + "border_width=" << event -> xcreatewindow.border_width << ", " + "override_redirect=" << (event -> xcreatewindow.override_redirect ? "true" : "false"); + break; + + case DestroyNotify: + out << "DestroyNotify"; + break; + + case UnmapNotify: + out << "UnmapNotify"; + break; + + case MapNotify: + out << "MapNotify"; + break; + + case MapRequest: + out << "MapRequest"; + break; + + case ReparentNotify: + out << "ReparentNotify"; + break; + + case ConfigureNotify: + out << "ConfigureNotify"; + break; + + case ConfigureRequest: + out << "ConfigureRequest"; + break; + + case GravityNotify: + out << "GravityNotify"; + break; + + case ResizeRequest: + out << "ResizeRequest"; + break; + + case CirculateNotify: + out << "CirculateNotify"; + break; + + case CirculateRequest: + out << "CirculateRequest"; + break; + + case PropertyNotify: + out << "PropertyNotify"; + break; + + case SelectionClear: + out << "SelectionClear"; + break; + + case SelectionRequest: + out << "SelectionRequest"; + break; + + case SelectionNotify: + out << "SelectionNotify"; + break; + + case ColormapNotify: + out << "ColormapNotify"; + break; + + case ClientMessage: + out << "ClientMessage"; + break; + + case MappingNotify: + out << "MappingNotify"; + break; + } + } + return out; +} +#endif + +#ifdef PLATFORM_WIN32 +int GdiGetFreeSpace() +{ + Vector objects; + for(HPEN pen; pen = CreatePen(PS_SOLID, 0, LtGray()); objects.Add(pen)) + ; + for(int i = 0; i < objects.GetCount(); DeleteObject(objects[i++])) + ; + return objects.GetCount(); +} +#endif + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/Debug.h b/uppdev/Draw/Debug.h new file mode 100644 index 000000000..0f3f51105 --- /dev/null +++ b/uppdev/Draw/Debug.h @@ -0,0 +1,46 @@ +String DumpLanguage(int language); +String DumpColor(Color color); +String DumpFont(Font font); +String DumpFontInfo(FontInfo fi); +String DumpAlign(int align); +#ifdef PLATFORM_X11 +String DumpPixmap(Pixmap pixmap); +String DumpXFont(XFont font); +String DumpXFontStruct(XFontStruct *fs); +String DumpGC(GC gc); +String DumpGCValues(const XGCValues& gc_values, int mask = -1); +String DumpEvent(XEvent *event); +#endif//PLATFORM_X11 + +class SimpleTiming +{ +public: + SimpleTiming(const char *name) : name(name) + { + last_ticks = start_ticks = GetTickCount(); + RLOG(name << " (open) & " << start_ticks); + } + + void Show(const char *part) + { + int ticks = GetTickCount(); + RLOG(name << " in " << (ticks - start_ticks) << + ", " << part << " in " << (ticks - last_ticks)); + last_ticks = ticks; + } + + ~SimpleTiming() + { + int ticks = GetTickCount(); + String out; + RLOG(name << " done in " << (ticks - start_ticks) + << ", last part in " << (ticks - last_ticks)); + } + +private: + String name; + int start_ticks; + int last_ticks; +}; + +int GdiGetFreeSpace(); diff --git a/uppdev/Draw/Display.cpp b/uppdev/Draw/Display.cpp new file mode 100644 index 000000000..accf11296 --- /dev/null +++ b/uppdev/Draw/Display.cpp @@ -0,0 +1,321 @@ +#include "Draw.h" + +NAMESPACE_UPP + +#define IMAGECLASS DrawImg +#define IMAGEFILE +#include + +#define LLOG(x) // RLOG(x) + +AttrText::operator Value() const +{ + return RawToValue(*this); +} + +void AttrText::Init() +{ + ink = Null; + paper = Null; + font = Null; + align = Null; +} + +AttrText::AttrText(const char *_text) +{ + text = _text; + Init(); +} + +AttrText::AttrText(const wchar *_text) +{ + text = _text; + Init(); +} + +AttrText::AttrText(const WString& _text) +{ + text = _text; + Init(); +} + +class StdDisplayClass : public Display +{ +public: + StdDisplayClass(int align = ALIGN_LEFT) : align(align) {} + + virtual void Paint0(Draw& draw, const Rect& rc, const Value& v, Color ink, Color paper, dword style) const; + virtual void Paint(Draw& draw, const Rect& rc, const Value& v, Color ink, Color paper, dword style) const; + virtual Size GetStdSize(const Value& q) const; + +private: + int align; +}; + +void Display::PaintBackground(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const +{ + if(IsType(q)) { + const AttrText& t = ValueTo(q); + if(!IsNull(t.paper)) + paper = t.paper; + } + w.DrawRect(r, paper); +} + +void Display::Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const +{ + StdDisplay().Paint(w, r, q, ink, paper, style); +} + +Size Display::RatioSize(const Value& q, int cx, int cy) const { + return Size(cx, cy); +} + +Size Display::GetStdSize(const Value& q) const +{ + return Size(8, 8); +} + +void StdDisplayClass::Paint0(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword s) const { + LLOG("Display::Paint0: " << q << " ink:" << ink << " paper:" << paper); + WString txt; + Font font = StdFont(); + int a = align; + if(IsType(q)) { + const AttrText& t = ValueTo(q); + txt = t.text; + if(!IsNull(t.paper)) + paper = t.paper; + if(!IsNull(t.ink)) + ink = t.ink; + if(!IsNull(t.font)) + font = t.font; + if(!IsNull(t.align)) + a = t.align; + } + else + txt = IsString(q) ? q : StdConvert().Format(q); + int x = r.left; + Size tsz = GetTLTextSize(txt, font); + if(a == ALIGN_RIGHT) + x = r.right - tsz.cx; + if(a == ALIGN_CENTER) + x += (r.Width() - tsz.cx) / 2; + int tcy = GetTLTextHeight(txt, font); + int tt = r.top + max((r.Height() - tcy) / 2, 0); + if(tsz.cx > r.GetWidth()) { + Size isz = DrawImg::threedots().GetSize(); + int wd = r.GetWidth() - isz.cx; + w.Clip(r.left, r.top, wd, r.GetHeight()); + DrawTLText(w, x, tt, r.Width(), txt, font, ink); + w.End(); + w.DrawImage(r.left + wd, tt + font.Info().GetAscent() - isz.cy, DrawImg::threedots(), ink); + } + else + DrawTLText(w, x, tt, r.Width(), txt, font, ink); +} + +void StdDisplayClass::Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword s) const { + LLOG("Display::Paint: " << q << " ink:" << ink << " paper:" << paper); + PaintBackground(w, r, q, ink, paper, s); + Paint0(w, r, q, ink, paper, s); +} + +Size StdDisplayClass::GetStdSize(const Value& q) const +{ + Font font = StdFont(); + WString txt; + if(IsType(q)) { + const AttrText& t = ValueTo(q); + txt = t.text; + if(!IsNull(t.font)) + font = t.font; + } + else + txt = IsString(q) ? q : StdConvert().Format(q); + return GetTLTextSize(txt, font); +} + +#ifdef flagSO +Display::Display() {} +#endif + +Display::~Display() {} + +const Display& GLOBAL_V_INIT(StdDisplayClass, StdDisplay) +const Display& GLOBAL_VP_INIT(StdDisplayClass, StdCenterDisplay, (ALIGN_CENTER)) +const Display& GLOBAL_VP_INIT(StdDisplayClass, StdRightDisplay, (ALIGN_RIGHT)) + +#ifdef flagSO +ColorDisplayNull::ColorDisplayNull(String nulltext) : nulltext(nulltext) {} +ColorDisplayNull::~ColorDisplayNull() {} +#endif + +void ColorDisplayNull::Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const +{ + if(IsNull(q)) + StdDisplay().Paint(w, r, nulltext, ink, paper, style); + else + w.DrawRect(r, Color(q)); +} + +const Display& ColorDisplay() { return Single(); } + +class SizeTextDisplayCls : public Display { +public: + virtual void Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const; +}; + +void SizeTextDisplayCls::Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color, dword) const { + w.DrawText(r.left, r.top, r.Width(), (String)q, Arial(-r.Height()), ink); +} + +const Display& SizeTextDisplay() { return Single(); } + +static inline int NScale(int sz, int r) { + return sz ? sz < r ? r / sz * sz : r : 0; +} + +class CenteredImageDisplayCls : public Display { +public: + virtual void Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const + { + w.DrawRect(r, paper); + Image m = q; + Size sz = m.GetSize(); + if(!IsNull(m)) + w.DrawImage(r.left + (r.Width() - sz.cx) / 2, r.top + (r.Height() - sz.cy) / 2, m); + } + virtual Size GetStdSize(const Value& q) const + { + return Image(q).GetSize(); + } +}; + +const Display& CenteredImageDisplay() { return Single(); } + +class CenteredHighlightImageDisplayCls : public Display { +public: + virtual void Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const + { + w.DrawRect(r, paper); + Image m = q; + Size sz = m.GetSize(); + if(!IsNull(m)) + DrawHighlightImage(w, r.left + (r.Width() - sz.cx) / 2, + r.top + (r.Height() - sz.cy) / 2, m); + } + virtual Size GetStdSize(const Value& q) const + { + return Image(q).GetSize(); + } +}; + +const Display& CenteredHighlightImageDisplay() +{ + return Single(); +} + +class ImageDisplayCls : public Display { +public: + virtual void Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const + { + w.DrawRect(r, paper); + Image m = q; + if(!IsNull(m)) + w.DrawImage(r.left, r.top, Rescale(m, r.GetSize())); + } + virtual Size GetStdSize(const Value& q) const + { + return Image(q).GetSize(); + } +}; + +const Display& ImageDisplay() { return Single(); } + +class FittedImageDisplayCls : public Display { +public: + virtual void Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const + { + w.DrawRect(r, paper); + Image m = q; + if(!IsNull(m)) { + Size sz = GetFitSize(m.GetSize(), r.Size()); + Point p = r.CenterPos(sz); + w.DrawImage(p.x, p.y, m); + } + } + virtual Size GetStdSize(const Value& q) const + { + return Image(q).GetSize(); + } +}; + +const Display& FittedImageDisplay() { return Single(); } + +class DrawingDisplayCls : public Display { +public: + virtual void Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const; + virtual Size GetStdSize(const Value& q) const; + virtual Size RatioSize(const Value& q, int cx, int cy) const; +}; + +void DrawingDisplayCls::Paint(Draw& w, const Rect& r, const Value& q, + Color, Color, dword) const { + w.DrawDrawing(r, q); +} + +Size DrawingDisplayCls::GetStdSize(const Value& q) const { + return ((const Drawing&) q).GetSize(); +} + +Size DrawingDisplayCls::RatioSize(const Value& q, int cx, int cy) const { + return ((const Drawing&) q).RatioSize(cx, cy); +} + +const Display& DrawingDisplay() { return Single(); } + +Size PaintRect::GetStdSize() const { + return display ? display->GetStdSize(value) : Size(0, 0); +} + +Size PaintRect::RatioSize(int cx, int cy) const { + return display ? display->RatioSize(value, cx, cy) : Size(0, 0); +} + +void PaintRect::Paint(Draw& w, const Rect& r, + Color ink, Color paper, dword style) const { + if(display) + display->Paint(w, r, value, ink, paper, style); +} + +void PaintRect::Paint(Draw& w, int x, int y, int cx, int cy, + Color ink, Color paper, dword style) const { + Paint(w, RectC(x, y, cx, cy), ink, paper, style); +} + +PaintRect::PaintRect() { + display = NULL; +} + +PaintRect::PaintRect(const Display& _display) { + display = &_display; +} + +PaintRect::PaintRect(const Display& _display, const Value& _val) { + display = &_display; + value = _val; +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/Display.h b/uppdev/Draw/Display.h new file mode 100644 index 000000000..27727edf4 --- /dev/null +++ b/uppdev/Draw/Display.h @@ -0,0 +1,100 @@ +class Display { +public: + enum { + CURSOR = 0x01, + FOCUS = 0x02, + SELECT = 0x04, + READONLY = 0x08, + }; + + virtual void PaintBackground(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const; + virtual void Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const; + virtual Size GetStdSize(const Value& q) const; + virtual Size RatioSize(const Value& q, int cx, int cy) const; +#ifdef flagSO + Display(); +#endif + virtual ~Display(); +}; + +struct AttrText { + WString text; + Font font; + Color ink; + Color paper; + int align; + + AttrText& Ink(Color c) { ink = c; return *this; } + AttrText& Paper(Color c) { paper = c; return *this; } + AttrText& SetFont(Font f) { font = f; return *this; } + AttrText& Align(int a) { align = a; return *this; } + AttrText& Left() { return Align(ALIGN_LEFT); } + AttrText& Center() { return Align(ALIGN_CENTER); } + AttrText& Right() { return Align(ALIGN_RIGHT); } + + operator Value() const; + + AttrText(const char *text); + AttrText(const wchar *text); + AttrText(const WString& text); + +private: + void Init(); +}; + +const Display& StdDisplay(); +const Display& StdCenterDisplay(); +const Display& StdRightDisplay(); + +const Display& ColorDisplay(); +const Display& SizeTextDisplay(); +const Display& ImageDisplay(); +const Display& FittedImageDisplay(); +const Display& CenteredImageDisplay(); +const Display& CenteredHighlightImageDisplay(); +const Display& DrawingDisplay(); + +class ColorDisplayNull : public Display { +public: +#ifdef flagSO + ColorDisplayNull(String nulltext = Null); + virtual ~ColorDisplayNull(); +#else + ColorDisplayNull(String nulltext = Null) : nulltext(nulltext) {} +#endif + virtual void Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const; +private: + String nulltext; +}; + +class PaintRect : Moveable { +protected: + Value value; + const Display *display; + +public: + void Paint(Draw& w, const Rect& r, + Color ink = SColorText, Color paper = SColorPaper, dword style = 0) const; + void Paint(Draw& w, int x, int y, int cx, int cy, + Color ink = SColorText, Color paper = SColorPaper, dword style = 0) const; + Size GetStdSize() const; + Size RatioSize(int cx, int cy) const; + Size RatioSize(Size sz) const { return RatioSize(sz.cx, sz.cy); } + + void SetDisplay(const Display& d) { display = &d; } + void SetValue(const Value& v) { value = v; } + void Set(const Display& d, const Value& v) { display = &d; value = v; } + void Clear() { display = NULL; } + + const Value& GetValue() const { return value; } + const Display& GetDisplay() const { return *display; } + + operator bool() const { return display; } + + PaintRect(); + PaintRect(const Display& display); + PaintRect(const Display& display, const Value& val); +}; diff --git a/uppdev/Draw/Draw.cpp b/uppdev/Draw/Draw.cpp new file mode 100644 index 000000000..279fe7db4 --- /dev/null +++ b/uppdev/Draw/Draw.cpp @@ -0,0 +1,420 @@ +#include "Draw.h" + +NAMESPACE_UPP + +#define LLOG(x) // RLOG(x) +#define LTIMING(x) // RTIMING(x) +//#define BENCH + +static StaticMutex sDrawLock; + +INITBLOCK { + RichValue::Register(); + RichValue::Register(); +} + +void Draw::SinCos(int angle, double& sina, double& cosa) +{ + angle = angle % 3600; + switch(angle) { + case 0: sina = 0; cosa = 1; break; + case 900: sina = 1; cosa = 0; break; + case 1800: sina = 0; cosa = -1; break; + case 2700: sina = -1; cosa = 0; break; + default: + double a = angle * M_PI / 1800.0; + sina = sin(a); + cosa = cos(a); + break; + } +} + +int Draw::GetNativeX(int x) const +{ + Size inchPixels = GetPixelsPerInch(); + Size nativeDpi = GetNativeDpi(); + return inchPixels != nativeDpi ? iscale(x, nativeDpi.cx, 600) : x; +} + +int Draw::GetNativeY(int y) const +{ + Size inchPixels = GetPixelsPerInch(); + Size nativeDpi = GetNativeDpi(); + return inchPixels != nativeDpi ? iscale(y, nativeDpi.cy, 600) : y; +} + +void Draw::Native(int& x, int& y) const +{ + x = GetNativeX(x); + y = GetNativeY(y); +} + +void Draw::Native(Point& p) const +{ + Native(p.x, p.y); +} + +void Draw::Native(Size& sz) const +{ + Native(sz.cx, sz.cy); +} + +void Draw::Native(Rect& r) const +{ + Native(r.left, r.top); + Native(r.right, r.bottom); +} + +#ifdef BENCH +static TimingInspector sDrawTiming("DRAW"); +#endif + +void EnterDraw() { + sDrawLock.Enter(); +#ifdef BENCH + sDrawTiming.Start(); +#endif +} + +void LeaveDraw() { +#ifdef BENCH + sDrawTiming.End(); +#endif + sDrawLock.Leave(); +} + +void Draw::StartPage() {} +void Draw::EndPage() {} + +// ------------------------------- + +void Draw::DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color) +{ + DrawLock __; + LTIMING("DrawImageOp"); + bool tonative = !IsNative(); + if(tonative) { + BeginNative(); + Native(x, y); + Native(cx, cy); + } + Size sz = Size(cx, cy); + if((cx > 2000 || cy > 1500) && IsNull(color) && IsPrinter()) { + int yy = 0; + ImageRaster ir(img); + RescaleImage rm; + rm.Create(Size(cx, cy), ir, src); + while(yy < cy) { + int ccy = min(cy - yy, 16); + ImageBuffer ib(cx, ccy); + for(int q = 0; q < ccy; q++) + rm.Get(ib[q]); + DrawImageBandRLE(*this, x, y + yy, ib, 16); + yy += ccy; + } + } + else + if(src.GetSize() == sz) + img.PaintImage(*this, x, y, src, color); + else { + Image h = Rescale(img, Size(cx, cy), src); + h.PaintImage(*this, x, y, h.GetSize(), color); + } + if(tonative) + EndNative(); +} + +// ------------------------------- + +void Draw::DrawRect(const Rect& rect, Color color) +{ + DrawRect(rect.left, rect.top, rect.GetWidth(), rect.GetHeight(), color); +} + +void Draw::DrawImage(int x, int y, int cx, int cy, const Image& img, const Rect& src) +{ + DrawImageOp(x, y, cx, cy, img, src, Null); +} + +void Draw::DrawImage(int x, int y, int cx, int cy, const Image& img) +{ + DrawImage(x, y, cx, cy, img, img.GetSize()); +} + +void Draw::DrawImage(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color) +{ + if(IsNull(color)) return; + DrawImageOp(x, y, cx, cy, img, src, color); +} + +void Draw::DrawImage(int x, int y, int cx, int cy, const Image& img, Color color) +{ + if(IsNull(color)) return; + DrawImage(x, y, cx, cy, img, img.GetSize(), color); +} + +void Draw::DrawImage(const Rect& r, const Image& img, const Rect& src) +{ + DrawImage(r.left, r.top, r.Width(), r.Height(), img, src); +} + +void Draw::DrawImage(const Rect& r, const Image& img) +{ + DrawImage(r.left, r.top, r.Width(), r.Height(), img); +} + +void Draw::DrawImage(const Rect& r, const Image& img, const Rect& src, Color color) +{ + if(IsNull(color)) return; + DrawImage(r.left, r.top, r.Width(), r.Height(), img, src, color); +} + +void Draw::DrawImage(const Rect& r, const Image& img, Color color) +{ + if(IsNull(color)) return; + DrawImage(r.left, r.top, r.Width(), r.Height(), img, color); +} + +void Draw::DrawImage(int x, int y, const Image& img, const Rect& src) +{ + Size sz = src.GetSize(); + DrawImageOp(x, y, sz.cx, sz.cy, img, src, Null); +} + +void Draw::DrawImage(int x, int y, const Image& img) +{ + Size sz = img.GetSize(); + DrawImageOp(x, y, sz.cx, sz.cy, img, img.GetSize(), Null); +} + +void Draw::DrawImage(int x, int y, const Image& img, const Rect& src, Color color) +{ + if(IsNull(color)) return; + Size sz = img.GetSize(); + DrawImageOp(x, y, sz.cx, sz.cy, img, src, color); +} + +void Draw::DrawImage(int x, int y, const Image& img, Color color) +{ + if(IsNull(color)) return; + Size sz = img.GetSize(); + DrawImageOp(x, y, sz.cx, sz.cy, img, img.GetSize(), color); +} + +void Draw::DrawData(int x, int y, int cx, int cy, const String& data, const char *type) +{ + DrawDataOp(x, y, cx, cy, data, type); +} + +void Draw::DrawData(const Rect& r, const String& data, const char *type) +{ + DrawDataOp(r.left, r.top, r.GetWidth(), r.GetHeight(), data, type); +} + +void Draw::DrawLine(Point p1, Point p2, int width, Color color) +{ + DrawLine(p1.x, p1.y, p2.x, p2.y, width, color); +} + +#ifndef PLATFORM_WINCE +void Draw::DrawPolyPolyline(const Vector& vertices, const Vector& counts, + int width, Color color, Color doxor) +{ + DrawPolyPolyline(vertices.Begin(), vertices.GetCount(), + counts.Begin(), counts.GetCount(), + width, color, doxor); +} + +void Draw::DrawPolyline(const Point *vertices, int count, + int width, Color color, Color doxor) +{ + DrawPolyPolyline(vertices, count, &count, 1, width, color, doxor); +} + +void Draw::DrawPolyline(const Vector& vertices, + int width, Color color, Color doxor) +{ + DrawPolyline(vertices.Begin(), vertices.GetCount(), width, color, doxor); +} + +void Draw::DrawPolyPolyPolygon(const Vector& vertices, + const Vector& subpolygon_counts, + const Vector& disjunct_polygon_counts, + Color color, int width, Color outline, + uint64 pattern, Color doxor) +{ + DrawPolyPolyPolygon(vertices.Begin(), vertices.GetCount(), + subpolygon_counts.Begin(), subpolygon_counts.GetCount(), + disjunct_polygon_counts.Begin(), disjunct_polygon_counts.GetCount(), + color, width, outline, pattern, doxor); +} + +void Draw::DrawPolyPolygon(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int subpolygon_count_count, + Color color, int width, Color outline, uint64 pattern, Color doxor) +{ + DrawPolyPolyPolygon(vertices, vertex_count, + subpolygon_counts, subpolygon_count_count, &vertex_count, 1, + color, width, outline, pattern, doxor); +} + +void Draw::DrawPolyPolygon(const Vector& vertices, const Vector& subpolygon_counts, + Color color, int width, Color outline, uint64 pattern, Color doxor) +{ + DrawPolyPolygon(vertices.Begin(), vertices.GetCount(), + subpolygon_counts.Begin(), subpolygon_counts.GetCount(), + color, width, outline, pattern, doxor); +} + +void Draw::DrawPolygons(const Point *vertices, int vertex_count, + const int *polygon_counts, int polygon_count_count, + Color color, int width, Color outline, uint64 pattern, Color doxor) +{ + DrawPolyPolyPolygon(vertices, vertex_count, + polygon_counts, polygon_count_count, + polygon_counts, polygon_count_count, + color, width, outline, pattern, doxor); +} + +void Draw::DrawPolygons(const Vector& vertices, const Vector& polygon_counts, + Color color, int width, Color outline, uint64 pattern, Color doxor) +{ + DrawPolygons(vertices.Begin(), vertices.GetCount(), + polygon_counts.Begin(), polygon_counts.GetCount(), + color, width, outline, pattern, doxor); +} + +void Draw::DrawPolygon(const Point *vertices, int vertex_count, + Color color, int width, Color outline, uint64 pattern, Color doxor) +{ + DrawPolyPolyPolygon(vertices, vertex_count, &vertex_count, 1, &vertex_count, 1, + color, width, outline, pattern, doxor); +} + +void Draw::DrawPolygon(const Vector& vertices, + Color color, int width, Color outline, uint64 pattern, Color doxor) +{ + DrawPolygon(vertices.Begin(), vertices.GetCount(), color, width, outline, pattern, doxor); +} +#endif +void Draw::DrawEllipse(int x, int y, int cx, int cy, Color color, int pen, Color pencolor) +{ + DrawEllipse(RectC(x, y, cx, cy), color, pen, pencolor); +} + +void Draw::Offset(int x, int y) +{ + Offset(Point(x, y)); +} + +bool Draw::Clip(int x, int y, int cx, int cy) +{ + return Clip(RectC(x, y, cx, cy)); +} + +bool Draw::Clipoff(int x, int y, int cx, int cy) +{ + return Clipoff(RectC(x, y, cx, cy)); +} + +bool Draw::ExcludeClip(int x, int y, int cx, int cy) +{ + return ExcludeClip(RectC(x, y, cx, cy)); +} + +bool Draw::IntersectClip(int x, int y, int cx, int cy) +{ + return IntersectClip(RectC(x, y, cx, cy)); +} + +bool Draw::IsPainting(int x, int y, int cx, int cy) const +{ + return IsPainting(RectC(x, y, cx, cy)); +} + +static void (*sIgfn)(ImageBuffer& ib, const Painting& pw, Size sz, Point pos, int mode); +static void (*sIwfn)(ImageBuffer& ib, const Drawing& p, int mode); + +void RegisterPaintingFns__(void (*ig)(ImageBuffer& ib, const Painting& pw, Size sz, Point pos, int mode), + void (*iw)(ImageBuffer& ib, const Drawing& p, int mode)) +{ + sIgfn = ig; + sIwfn = iw; +} + +bool HasPainter() +{ + return sIgfn && sIwfn; +} + +void PaintImageBuffer(ImageBuffer& ib, const Painting& p, Size sz, Point pos, int mode) +{ + if(sIgfn) + (*sIgfn)(ib, p, sz, pos, mode); +} + +void PaintImageBuffer(ImageBuffer& ib, const Painting& p, int mode) +{ + PaintImageBuffer(ib, p, ib.GetSize(), Point(0, 0), mode); +} + +void PaintImageBuffer(ImageBuffer& ib, const Drawing& iw, int mode) +{ + if(sIwfn) + (*sIwfn)(ib, iw, mode); +} + +void Draw::DrawPaintingOp(const Rect& target, const Painting& pw) +{ + if(!HasPainter()) + return; + Size sz = target.GetSize(); + if((sz.cx > 2000 || sz.cy > 1500) && IsPrinter()) { + int yy = 0; + while(yy < sz.cy) { + int ccy = min(sz.cy - yy, 100); + ImageBuffer ib(sz.cx, ccy); + Fill(~ib, White(), ib.GetLength()); + PaintImageBuffer(ib, pw, sz, Point(0, yy), true); + DrawImageBandRLE(*this, target.left, target.top + yy, ib, 16); + yy += ccy; + } + } + else { + ImageBuffer ib(sz); + Fill(~ib, IsPrinter() ? White() : SColorPaper(), ib.GetLength()); + PaintImageBuffer(ib, pw, sz, Point(0, 0), IsPrinter()); + DrawImage(target.left, target.top, ib); + } +} + +void Draw::DrawPainting(int x, int y, int cx, int cy, const Painting& ig) +{ + DrawPainting(RectC(x, y, cx, cy), ig); +} + +// --------------------------- + +void NilDraw::BeginOp() {} +bool NilDraw::ClipOp(const Rect& r) { return false; } +bool NilDraw::ClipoffOp(const Rect& r) { return false; } +void NilDraw::DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color) {} +void NilDraw::DrawDataOp(int x, int y, int cx, int cy, const String& data, const char *id) {} +void NilDraw::DrawDrawingOp(const Rect& target, const Drawing& w) {} +void NilDraw::DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor) {} +void NilDraw::DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color) {} +void NilDraw::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color) {} +void NilDraw::DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, const int *subpolygon_counts, int scc, const int *disjunct_polygon_counts, int dpcc, Color color, int width, Color outline, uint64 pattern, Color doxor) {} +void NilDraw::DrawPolyPolylineOp(const Point *vertices, int vertex_count, const int *counts, int count_count, int width, Color color, Color doxor) {} +void NilDraw::DrawRectOp(int x, int y, int cx, int cy, Color color) {} +void NilDraw::DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx) {} +void NilDraw::EndOp() {} +void NilDraw::EndPage() {} +bool NilDraw::ExcludeClipOp(const Rect& r) { return false; } +Rect NilDraw::GetClipOp() const { return Null; } +bool NilDraw::IntersectClipOp(const Rect& r) { return false; } +bool NilDraw::IsPaintingOp(const Rect& r) const { return false; } +void NilDraw::OffsetOp(Point p) {} +void NilDraw::StartPage() {} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/Draw.h b/uppdev/Draw/Draw.h new file mode 100644 index 000000000..8135a78c3 --- /dev/null +++ b/uppdev/Draw/Draw.h @@ -0,0 +1,975 @@ +#ifndef DRAW_H +#define DRAW_H + +#include + +#ifdef PLATFORM_X11 + +#define Time XTime +#define Font XFont +#define Display XDisplay +#define Picture XPicture + +#include +#include +#include + +#include +#include + +#undef Picture +#undef Time +#undef Font +#undef Display + +#undef True +#undef False + +#define XFalse 0 +#define XTrue 1 +#endif + + +NAMESPACE_UPP + +#ifdef PLATFORM_X11 + +extern XDisplay *Xdisplay; +extern Visual *Xvisual; +extern int Xscreenno; +extern Window Xroot; +extern Screen *Xscreen; +extern Colormap Xcolormap; +extern int Xheight; +extern int Xwidth; +extern int XheightMM; +extern int XwidthMM; +extern int Xdepth; +extern dword Xblack; +extern dword Xwhite; +extern int Xconnection; + +extern dword (*Xgetpixel)(int r, int g, int b); + +void InitX11Draw(const char *dispname = NULL); +void InitX11Draw(XDisplay *display); + +void XError(); +void XError(const char *s); + +inline dword GetXPixel(int r, int g, int b) { return (*Xgetpixel)(r, g, b); } +inline dword GetXPixel(Color color) { return (*Xgetpixel)(color.GetR(), color.GetG(), color.GetB()); } + +enum { + X11_ROP2_ZERO, + X11_ROP2_AND, + X11_ROP2_AND_NOT, + X11_ROP2_COPY, + X11_ROP2_NOT_AND, + X11_ROP2_NOP, + X11_ROP2_XOR, + X11_ROP2_OR, + X11_ROP2_NOT_AND_NOT, + X11_ROP2_NOT_XOR, + X11_ROP2_INVERT, + X11_ROP2_OR_NOT, + X11_ROP2_NOT_COPY, + X11_ROP2_NOT_OR, + X11_ROP2_NOT_OR_NOT, + X11_ROP2_ONE, +}; + +#endif + +class Drawing; +class Draw; +class Painting; + +#ifdef PLATFORM_WIN32 +HDC ScreenHDC(); +#endif + +bool ScreenInPaletteMode(); +Size GetScreenSize(); + +#include "Image.h" + +void EnterDraw(); +void LeaveDraw(); + +struct DrawLock { + DrawLock() { EnterDraw(); } + ~DrawLock() { LeaveDraw(); } +}; + +const int FONT_V = 40; + +class FontInfo; + +class Font : AssignValueTypeNo >{ + word face; + word flags; + int16 height; + int16 width; + +public: + enum { + FIXEDPITCH = 0x0001, + SCALEABLE = 0x0002, + SYMBOLTYPE = 0x0004, + COMPOSED = 0x0008, + LOCAL = 0x0010, + }; + + static int GetFaceCount(); + static String GetFaceName(int index); + static int FindFaceNameIndex(const char *name); + static dword GetFaceInfo(int index); + + enum { + STDFONT, + SCREEN_SERIF, + SCREEN_SANS, + SCREEN_FIXED, + ROMAN, + ARIAL, + COURIER, + SYMBOL, + #ifdef PLATFORM_WIN32 + WINGDINGS, + TAHOMA, + #endif + OTHER, + }; + + int GetFace() const { return face; } + int GetHeight() const { return height; } + int GetWidth() const { return width; } + bool IsBold() const { return flags & 0x8000; } + bool IsItalic() const { return flags & 0x4000; } + bool IsUnderline() const { return flags & 0x2000; } + bool IsStrikeout() const { return flags & 0x1000; } + bool IsNonAntiAliased() const { return flags & 0x800; } + bool IsTrueTypeOnly() const { return flags & 0x400; } + String GetFaceName() const; + dword GetFaceInfo() const; + + FontInfo Info() const; + + Font& Face(int n) { face = n; return *this; } + Font& Height(int n) { height = n; return *this; } + Font& Width(int n) { width = n; return *this; } + Font& Bold() { flags |= 0x8000; return *this; } + Font& NoBold() { flags &= ~0x8000; return *this; } + Font& Bold(bool b) { return b ? Bold() : NoBold(); } + Font& Italic() { flags |= 0x4000; return *this; } + Font& NoItalic() { flags &= ~0x4000; return *this; } + Font& Italic(bool b) { return b ? Italic() : NoItalic(); } + Font& Underline() { flags |= 0x2000; return *this; } + Font& NoUnderline() { flags &= ~0x2000; return *this; } + Font& Underline(bool b) { return b ? Underline() : NoUnderline(); } + Font& Strikeout() { flags |= 0x1000; return *this; } + Font& NoStrikeout() { flags &= ~0x1000; return *this; } + Font& Strikeout(bool b) { return b ? Strikeout() : NoStrikeout(); } + Font& NonAntiAliased() { flags |= 0x800; return *this; } + Font& NoNonAntiAliased() { flags &= ~0x800; return *this; } + Font& NonAntiAliased(bool b) { return b ? NonAntiAliased() : NoNonAntiAliased(); } + Font& TrueTypeOnly() { flags |= 0x400; return *this; } + Font& NoTrueTypeOnly() { flags &= ~0x400; return *this; } + Font& TrueTypeOnly(bool b) { return b ? TrueTypeOnly() : NoTrueTypeOnly(); } + Font& FaceName(const String& name); + + Font operator()() const { return *this; } + Font operator()(int n) const { return Font(*this).Height(n); } + + void Serialize(Stream& s); + + bool operator==(Font f) const { return face == f.face && flags == f.flags && + width == f.width && height == f.height; } + bool operator!=(Font f) const { return !operator==(f); } + + dword GetHashValue() const { return MAKELONG(flags, width) ^ MAKELONG(face, height); } + bool IsNull() const { return face == 0xffff; } + + Font() { height = width = 0; face = flags = 0; } + Font(int _face, int _height) { face = _face; height = _height; flags = 0; width = 0; } + Font(const Nuller&) { face = 0xffff; height = width = 0; flags = 0; } + + operator Value() const { return RichValue(*this); } + Font(const Value& q) { *this = RichValue::Extract(q); } +}; + +template<> +inline bool IsNull(const Font& f) { return f.IsNull(); } + +template<> +inline unsigned GetHashValue(const Font& f) { return f.GetHashValue(); } + +template<> +String AsString(const Font& f); + +class FontInfo : Moveable { + struct CharMetrics : Moveable { + int width; + int lspc; + int rspc; + + bool operator==(const CharMetrics& b) const + { return width == b.width && lspc == b.lspc && rspc == b.rspc; } + }; + + struct Kinfo : Moveable { + CharMetrics std; + byte *flags; + + Kinfo() { + flags = NULL; + } + ~Kinfo() { + if(flags) + delete[] flags; + } + }; + + struct Data : public Link { + bool HasChar(int ch) const; + void GetMetrics(CharMetrics *t, int from, int count); + #ifdef PLATFORM_X11 + void CreateFont(int i, int cs); + #endif + + int refcount; + Font font; + int angle; + #ifdef PLATFORM_WIN32 + HFONT hfont; + #endif + #ifdef PLATFORM_X11 + XftFont *xftfont; + XftFont *xftfont0; + #endif + int ascent; + int descent; + int external; + int internal; + int height; + int lineheight; + int overhang; + Size offset; + int avewidth; + int maxwidth; + int firstchar; + int charcount; + int default_char; + + CharMetrics *base[64]; + + Mutex xmutex; + Vector kinfo; + VectorMap xx; + + bool fixedpitch; + bool scaleable; + int spacebefore; + int spaceafter; + #ifdef PLATFORM_X11 + int underline_position; + int underline_thickness; + double sina; + double cosa; + bool twobyte; + String filename; + #endif + + VectorMap kerning; + + Data(); + ~Data(); + }; + + Data *ptr; + int charset; + + friend class Draw; + friend class SystemDraw; + + CharMetrics *CreateMetricsPage(int page) const; + CharMetrics *GetPage(int page) const; + void ComposeMetrics(Font fnt, CharMetrics *m, int from) const; + CharMetrics GetCM(int c) const; + + void Release(); + void Retain(const FontInfo& f); + FontInfo(Data *ptr) : ptr(ptr) { charset = CHARSET_UNICODE; } + + bool IsEqual(byte charset, Font f, int angle, int device) const; + CharMetrics GetComposedMetrics(int c); + + static void InitPlatformFonts(); + static Size StdFontSize; + static Font AStdFont; + static int FontCacheMax; + static int FontCached; + + enum { LRU, HASH, FONTHASH = 97 }; + + + static Data *GetFontHash(int i); + static Data *GetFontLru(); + static void InitFonts(); + static void SyncStdFont(); + static void FreeFonts(); + + typedef Link FontLink; + + friend class Font; + +#ifdef PLATFORM_WIN32 + static int CALLBACK AddFace(const LOGFONT *logfont, const TEXTMETRIC *, dword type, LPARAM param); + static int EnumFace(HDC hdc, const char *face); + static void ForceFace(HDC hdc, const char *face, const char *aface); + static FontInfo AcquireFontInfo0(Font font, HDC hdc, int angle); + static FontInfo AcquireFontInfo(Font font, int angle); +#endif + +public: + int GetAscent() const { return ptr->ascent; } + int GetDescent() const { return ptr->descent; } + int GetExternal() const { return ptr->external; } + int GetInternal() const { return ptr->internal; } + int GetHeight() const { return ptr->height; } + int GetLineHeight() const { return ptr->lineheight; } + int GetOverhang() const { return ptr->overhang; } + int GetAveWidth() const { return ptr->avewidth; } + int GetMaxWidth() const { return ptr->maxwidth; } + int HasChar(int ch) const { return ptr->HasChar(ch); } + int GetWidth(int c) const; + int operator[](int c) const { return GetWidth(c); } + int GetLeftSpace(int c) const; + int GetRightSpace(int c) const; + int GetKerning(int c1, int c2) const { return ptr->kerning.Get(MAKELONG(c1, c2), 0); } + bool IsFixedPitch() const { return ptr->fixedpitch; } + bool IsScaleable() const { return ptr->scaleable; } + + Font GetFont() const { return ptr->font; } + int GetFontHeight() const { return ptr->font.GetHeight(); } + +#ifdef PLATFORM_X11 + String GetFileName() const; + XftFont *GetXftFont() const { return ptr->xftfont0; } +#endif +#ifdef PLATFORM_WIN32 + HFONT GetHFONT() const { return ptr->hfont; } +#endif + + void Clear() { Release(); ptr = NULL; } + bool IsEmpty() const { return !ptr; } + operator bool() const { return ptr; } + + FontInfo(const FontInfo& f); + FontInfo& operator=(const FontInfo& f); + + FontInfo(); + ~FontInfo() { Release(); } + + static void SetStdFont(Font font); + static Font GetStdFont() { return AStdFont; } + static Size GetStdFontSize(); +}; + +inline void SetStdFont(Font font) { FontInfo::SetStdFont(font); } +inline Font GetStdFont() { return FontInfo::GetStdFont(); } +inline Size GetStdFontSize() { return FontInfo::GetStdFontSize(); } +inline int GetStdFontCy() { return GetStdFontSize().cy; } + +Font StdFont(); + +inline Font StdFont(int h) { return StdFont().Height(h); } + +struct ScreenSans : public Font { ScreenSans(int n = 0) : Font(SCREEN_SANS, n) {} }; +struct ScreenSerif : public Font { ScreenSerif(int n = 0) : Font(SCREEN_SERIF, n) {} }; +struct ScreenFixed : public Font { ScreenFixed(int n = 0) : Font(SCREEN_FIXED, n) {} }; + +struct Roman : public Font { Roman(int n) : Font(ROMAN, n) {} }; +struct Arial : public Font { Arial(int n) : Font(ARIAL, n) {} }; +struct Courier : public Font { Courier(int n) : Font(COURIER, n) {} }; +struct Symbol : public Font { Symbol(int n) : Font(SYMBOL, n) {} }; + +#ifdef PLATFORM_WIN32 +struct WingDings : public Font { WingDings(int n) : Font(WINGDINGS, n) {} }; +struct Tahoma : public Font { Tahoma(int n) : Font(TAHOMA, n) {} }; +#endif + +#ifdef PLATFORM_WIN32 +#ifndef PLATFORM_WINCE +HPALETTE GetQlibPalette(); +#endif +#endif + +Size GetTextSize(const wchar *text, Font font, int n = -1); +Size GetTextSize(const WString& text, Font font); +Size GetTextSize(const char *text, byte charset, Font font, int n = -1); +Size GetTextSize(const char *text, Font font, int n = -1); +Size GetTextSize(const String& text, Font font); + +enum { + PEN_NULL = -1, + PEN_SOLID = -2, + PEN_DASH = -3, +#ifndef PLATFORM_WINCE + PEN_DOT = -4, + PEN_DASHDOT = -5, + PEN_DASHDOTDOT = -6, +#endif +}; + +class Image; + +//DEPRECATED: TODO +Color SBlack(); +Color SGray(); +Color SLtGray(); +Color SWhiteGray(); +Color SWhite(); +Color SRed(); +Color SGreen(); +Color SBrown(); +Color SBlue(); +Color SMagenta(); +Color SCyan(); +Color SYellow(); +Color SLtRed(); +Color SLtGreen(); +Color SLtYellow(); +Color SLtBlue(); +Color SLtMagenta(); +Color SLtCyan(); +//END OF DEPRECATED + +Color SColorPaper(); +Color SColorText(); +Color SColorHighlight(); +Color SColorHighlightText();// +Color SColorMenu(); +Color SColorMenuText(); +Color SColorInfo(); +Color SColorInfoText();// +Color SColorMark(); +Color SColorDisabled(); +Color SColorLight(); +Color SColorFace(); +Color SColorLabel(); +Color SColorShadow(); + +Color SColorLtFace(); +Color SColorDkShadow(); + + +void SBlack_Write(Color c); +void SGray_Write(Color c); +void SLtGray_Write(Color c); +void SWhiteGray_Write(Color c); +void SWhite_Write(Color c); +void SRed_Write(Color c); +void SGreen_Write(Color c); +void SBrown_Write(Color c); +void SBlue_Write(Color c); +void SMagenta_Write(Color c); +void SCyan_Write(Color c); +void SYellow_Write(Color c); +void SLtRed_Write(Color c); +void SLtGreen_Write(Color c); +void SLtYellow_Write(Color c); +void SLtBlue_Write(Color c); +void SLtMagenta_Write(Color c); +void SLtCyan_Write(Color c); + +void SColorPaper_Write(Color c); +void SColorText_Write(Color c); +void SColorHighlight_Write(Color c); +void SColorHighlightText_Write(Color c);// +void SColorMenu_Write(Color c); +void SColorMenuText_Write(Color c); +void SColorInfo_Write(Color c); +void SColorInfoText_Write(Color c);// +void SColorMark_Write(Color c); +void SColorDisabled_Write(Color c); +void SColorLight_Write(Color c); +void SColorFace_Write(Color c); +void SColorLabel_Write(Color c); +void SColorShadow_Write(Color c); + +void SColorLtFace_Write(Color c); +void SColorDkShadow_Write(Color c); + + +inline Color InvertColor() { return Color(255, 0); } +inline Color DefaultInk() { return Black(); } //TODO! + +class Painting : AssignValueTypeNo > { + String cmd; + ValueArray data; + Sizef size; + + friend class PaintingPainter; + friend class Painter; + +public: + Sizef GetSize() const { return size; } + + void Clear() { size = Null; data.Clear(); cmd.Clear(); } + void Serialize(Stream& s) { s % cmd % data % size; } + bool IsNullInstance() const { return cmd.IsEmpty(); } + bool operator==(const Painting& b) const { return cmd == b.cmd && data == b.data && size == b.size; } + unsigned GetHashValue() const { return CombineHash(cmd, data); } + String ToString() const { return "painting " + AsString(size); } + + operator Value() const { return RichValue(*this); } + Painting(const Value& q) { *this = RichValue::Extract(q); } + + Painting() { size = Null; } + Painting(const Nuller&) { size = Null; } +}; + +enum { + MODE_ANTIALIASED = 0, + MODE_NOAA = 1, + MODE_SUBPIXEL = 2, +}; + +bool HasPainter(); +void PaintImageBuffer(ImageBuffer& ib, const Painting& p, Size sz, Point pos, int mode = MODE_ANTIALIASED); +void PaintImageBuffer(ImageBuffer& ib, const Painting& p, int mode = MODE_ANTIALIASED); +void PaintImageBuffer(ImageBuffer& ib, const Drawing& p, int mode = MODE_ANTIALIASED); + +class Draw : NoCopy { +private: + struct DrawingPos; + + void ComposeText(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx); + +public: + enum { + DOTS = 0x001, + SYSTEM = 0x002, + PRINTER = 0x004, + BACK = 0x008, + PALETTE = 0x020, + MONO = 0x040, + NATIVE = 0x080, + }; + + virtual dword GetInfo() const = 0; + virtual Size GetPagePixels() const = 0; + + virtual void StartPage(); + virtual void EndPage(); + + virtual void BeginOp() = 0; + virtual void EndOp() = 0; + virtual void OffsetOp(Point p) = 0; + virtual bool ClipOp(const Rect& r) = 0; + virtual bool ClipoffOp(const Rect& r) = 0; + virtual bool ExcludeClipOp(const Rect& r) = 0; + virtual bool IntersectClipOp(const Rect& r) = 0; + virtual bool IsPaintingOp(const Rect& r) const = 0; + + virtual void DrawRectOp(int x, int y, int cx, int cy, Color color) = 0; + virtual void DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color) = 0; + virtual void DrawDataOp(int x, int y, int cx, int cy, const String& data, const char *id) = 0; + virtual void DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color) = 0; + + virtual void DrawPolyPolylineOp(const Point *vertices, int vertex_count, + const int *counts, int count_count, + int width, Color color, Color doxor) = 0; + virtual void DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int scc, + const int *disjunct_polygon_counts, int dpcc, + Color color, int width, Color outline, + uint64 pattern, Color doxor) = 0; + virtual void DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color) = 0; + + virtual void DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor) = 0; + virtual void DrawTextOp(int x, int y, int angle, const wchar *text, Font font, + Color ink, int n, const int *dx) = 0; + virtual void DrawDrawingOp(const Rect& target, const Drawing& w) = 0; + virtual void DrawPaintingOp(const Rect& target, const Painting& w) = 0; + + virtual Size GetNativeDpi() const; + virtual void BeginNative(); + virtual void EndNative(); + + virtual int GetCloffLevel() const; + +// -------------- + Size GetPixelsPerInch() const; + Size GetPageMMs() const; + + bool Dots() const { return GetInfo() & DOTS; } + bool Pixels() const { return !Dots(); } + bool IsSystem() const { return GetInfo() & SYSTEM; } + bool IsPrinter() const { return GetInfo() & PRINTER; } + bool IsNative() const { return GetInfo() & NATIVE; } + bool IsBack() const { return GetInfo() & BACK; } + + bool IsPaletteMode() const { return GetInfo() & PALETTE; } + bool IsMono() const { return GetInfo() & MONO; } + + int GetNativeX(int x) const; + int GetNativeY(int x) const; + void Native(int& x, int& y) const; + void Native(Point& p) const; + void Native(Size& sz) const; + void Native(Rect& r) const; + + void Begin() { BeginOp(); } + void End() { EndOp(); } + void Offset(Point p) { OffsetOp(p); } + void Offset(int x, int y); + bool Clip(const Rect& r) { return ClipOp(r); } + bool Clip(int x, int y, int cx, int cy); + bool Clipoff(const Rect& r) { return ClipoffOp(r); } + bool Clipoff(int x, int y, int cx, int cy); + bool ExcludeClip(const Rect& r) { return ExcludeClipOp(r); } + bool ExcludeClip(int x, int y, int cx, int cy); + bool IntersectClip(const Rect& r) { return IntersectClipOp(r); } + bool IntersectClip(int x, int y, int cx, int cy); + bool IsPainting(const Rect& r) const { return IsPaintingOp(r); } + bool IsPainting(int x, int y, int cx, int cy) const; + + void DrawRect(int x, int y, int cx, int cy, Color color); + void DrawRect(const Rect& rect, Color color); + + void DrawImage(int x, int y, int cx, int cy, const Image& img, const Rect& src); + void DrawImage(int x, int y, int cx, int cy, const Image& img); + void DrawImage(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color); + void DrawImage(int x, int y, int cx, int cy, const Image& img, Color color); + + void DrawImage(const Rect& r, const Image& img, const Rect& src); + void DrawImage(const Rect& r, const Image& img); + void DrawImage(const Rect& r, const Image& img, const Rect& src, Color color); + void DrawImage(const Rect& r, const Image& img, Color color); + + void DrawImage(int x, int y, const Image& img, const Rect& src); + void DrawImage(int x, int y, const Image& img); + void DrawImage(int x, int y, const Image& img, const Rect& src, Color color); + void DrawImage(int x, int y, const Image& img, Color color); + + void DrawData(int x, int y, int cx, int cy, const String& data, const char *type); + void DrawData(const Rect& r, const String& data, const char *type); + + void DrawLine(int x1, int y1, int x2, int y2, int width = 0, Color color = DefaultInk); + void DrawLine(Point p1, Point p2, int width = 0, Color color = DefaultInk); + + void DrawEllipse(const Rect& r, Color color = DefaultInk, + int pen = Null, Color pencolor = DefaultInk); + void DrawEllipse(int x, int y, int cx, int cy, Color color = DefaultInk, + int pen = Null, Color pencolor = DefaultInk); + + void DrawArc(const Rect& rc, Point start, Point end, int width = 0, Color color = DefaultInk); + + void DrawPolyPolyline(const Point *vertices, int vertex_count, + const int *counts, int count_count, + int width = 0, Color color = DefaultInk, Color doxor = Null); + void DrawPolyPolyline(const Vector& vertices, const Vector& counts, + int width = 0, Color color = DefaultInk, Color doxor = Null); + void DrawPolyline(const Point *vertices, int count, + int width = 0, Color color = DefaultInk, Color doxor = Null); + void DrawPolyline(const Vector& vertices, + int width = 0, Color color = DefaultInk, Color doxor = Null); + + void DrawPolyPolyPolygon(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int subpolygon_count_count, + const int *disjunct_polygon_counts, int disjunct_polygon_count_count, + Color color = DefaultInk, int width = 0, Color outline = Null, + uint64 pattern = 0, Color doxor = Null); + void DrawPolyPolyPolygon(const Vector& vertices, + const Vector& subpolygon_counts, + const Vector& disjunct_polygon_counts, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolyPolygon(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int subpolygon_count_count, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolyPolygon(const Vector& vertices, const Vector& subpolygon_counts, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolygons(const Point *vertices, int vertex_count, + const int *polygon_counts, int polygon_count_count, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolygons(const Vector& vertices, const Vector& polygon_counts, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolygon(const Point *vertices, int vertex_count, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolygon(const Vector& vertices, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + + void DrawDrawing(const Rect& r, const Drawing& iw) { DrawDrawingOp(r, iw); } + void DrawDrawing(int x, int y, int cx, int cy, const Drawing& iw); + + void DrawPainting(const Rect& r, const Painting& iw) { DrawPaintingOp(r, iw); } + void DrawPainting(int x, int y, int cx, int cy, const Painting& iw); + + void DrawText(int x, int y, int angle, const wchar *text, Font font = StdFont(), + Color ink = DefaultInk, int n = -1, const int *dx = NULL); + void DrawText(int x, int y, const wchar *text, Font font = StdFont(), + Color ink = DefaultInk, int n = -1, const int *dx = NULL); + + void DrawText(int x, int y, const WString& text, Font font = StdFont(), + Color ink = DefaultInk, const int *dx = NULL); + void DrawText(int x, int y, int angle, const WString& text, Font font = StdFont(), + Color ink = DefaultInk, const int *dx = NULL); + + void DrawText(int x, int y, int angle, const char *text, byte charset, + Font font = StdFont(), Color ink = DefaultInk, int n = -1, const int *dx = NULL); + void DrawText(int x, int y, const char *text, byte charset, Font font = StdFont(), + Color ink = DefaultInk, int n = -1, const int *dx = NULL); + + void DrawText(int x, int y, int angle, const char *text, + Font font = StdFont(), Color ink = DefaultInk, int n = -1, const int *dx = NULL); + void DrawText(int x, int y, const char *text, Font font = StdFont(), + Color ink = DefaultInk, int n = -1, const int *dx = NULL); + + void DrawText(int x, int y, const String& text, Font font = StdFont(), + Color ink = DefaultInk, const int *dx = NULL); + void DrawText(int x, int y, int angle, const String& text, Font font = StdFont(), + Color ink = DefaultInk, const int *dx = NULL); + + static void SinCos(int angle, double& sina, double& cosa); +}; + +void DrawImageBandRLE(Draw& w, int x, int y, const Image& m, int minp); + +class DataDrawer { + typedef DataDrawer *(*Factory)(); + template static DataDrawer *FactoryFn() { return new T; } + static void AddFormat(const char *id, Factory f); + static VectorMap& Map(); + +public: + virtual void Open(const String& data, int cx, int cy) = 0; + virtual void Render(ImageBuffer& ib) = 0; + virtual ~DataDrawer(); + + static One Create(const String& id); + + template static void Register(const char *id) { AddFormat(id, &DataDrawer::FactoryFn); } +}; + +class Drawing : AssignValueTypeNo > { + Size size; + String data; + ValueArray val; + + friend class DrawingDraw; + friend class Draw; + +public: + operator bool() const { return !data.IsEmpty(); } + Size GetSize() const { return size; } + void SetSize(Size sz) { size = sz; } + void SetSize(int cx, int cy) { size = Size(cx, cy); } + + Size RatioSize(int cx, int cy) const; + Size RatioSize(Size sz) const { return RatioSize(sz.cx, sz.cy); } + + void Clear() { data.Clear(); size = Null; } + + void Append(Drawing& dw); + + void Serialize(Stream& s); + + bool IsNullInstance() const { return data.IsEmpty(); } + bool operator==(const Drawing& b) const { return val == b.val && data == b.data && size == b.size; } + String ToString() const { return "drawing " + AsString(size); } + unsigned GetHashValue() const { return CombineHash(data, val); } + + operator Value() const { return RichValue(*this); } + Drawing(const Value& src); + + Drawing() { size = Null; } + Drawing(const Nuller&) { size = Null; } +}; + +class DrawingDraw : public Draw { +public: + virtual void BeginOp(); + virtual void EndOp(); + virtual void OffsetOp(Point p); + virtual bool ClipOp(const Rect& r); + virtual bool ClipoffOp(const Rect& r); + virtual bool ExcludeClipOp(const Rect& r); + virtual bool IntersectClipOp(const Rect& r); + virtual Rect GetClipOp() const; + virtual bool IsPaintingOp(const Rect& r) const; + + virtual void DrawRectOp(int x, int y, int cx, int cy, Color color); + virtual void DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color); + virtual void DrawDataOp(int x, int y, int cx, int cy, const String& data, const char *id); + virtual void DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color); + virtual void DrawPolyPolylineOp(const Point *vertices, int vertex_count, + const int *counts, int count_count, + int width, Color color, Color doxor); + virtual void DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int scc, + const int *disjunct_polygon_counts, int dpcc, + Color color, int width, Color outline, + uint64 pattern, Color doxor); + virtual void DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor); + virtual void DrawArcOp(const Rect& rc, Point start, Point end, int pen, Color pencolor); + virtual void DrawTextOp(int x, int y, int angle, const wchar *text, Font font, + Color ink, int n, const int *dx); + + virtual void DrawDrawingOp(const Rect& target, const Drawing& w); + virtual void DrawPaintingOp(const Rect& target, const Painting& w); + +private: + Size size; + StringStream drawing; + ValueArray val; + + Stream& DrawingOp(int code); + +public: + void Create(int cx, int cy); + void Create(Size sz); + + Size GetSize() const { return size; } + + Drawing GetResult(); + operator Drawing() { return GetResult(); } + + DrawingDraw(); + DrawingDraw(int cx, int cy); + DrawingDraw(Size sz); + ~DrawingDraw(); +}; + +class NilDraw : public Draw { +public: + virtual void BeginOp(); + virtual bool ClipOp(const Rect& r); + virtual bool ClipoffOp(const Rect& r); + virtual void DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color); + virtual void DrawDataOp(int x, int y, int cx, int cy, const String& data, const char *id); + virtual void DrawDrawingOp(const Rect& target, const Drawing& w); + virtual void DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor); + virtual void DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color); + virtual void DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color); + virtual void DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, const int *subpolygon_counts, int scc, const int *disjunct_polygon_counts, int dpcc, Color color, int width, Color outline, uint64 pattern, Color doxor); + virtual void DrawPolyPolylineOp(const Point *vertices, int vertex_count, const int *counts, int count_count, int width, Color color, Color doxor); + virtual void DrawRectOp(int x, int y, int cx, int cy, Color color); + virtual void DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx); + virtual void EndOp(); + virtual void EndPage(); + virtual bool ExcludeClipOp(const Rect& r); + virtual Rect GetClipOp() const; + virtual bool IntersectClipOp(const Rect& r); + virtual bool IsPaintingOp(const Rect& r) const; + virtual void OffsetOp(Point p); + virtual void StartPage(); + + NilDraw(); + ~NilDraw(); +}; + +void AddNotEmpty(Vector& result, int left, int right, int top, int bottom); +bool Subtract(const Rect& r, const Rect& sub, Vector& result); +bool Subtract(const Vector& rr, const Rect& sub, Vector& result); +Vector Subtract(const Vector& rr, const Rect& sub, bool& changed); +Vector Intersect(const Vector& b, const Rect& a, bool& changed); + +void Subtract(Vector& rr, const Rect& sub); +void Union(Vector& rr, const Rect& add); + +#ifdef PLATFORM_X11 +void SetClip(GC gc, XftDraw *xftdraw, const Vector& cl); +#endif + +void DrawRect(Draw& w, const Rect& rect, const Image& img, bool ralgn = false); //??? TODO +void DrawRect(Draw& w, int x, int y, int cx, int cy, const Image& img, bool ra = false); + +void DrawTiles(Draw& w, int x, int y, int cx, int cy, const Image& img); +void DrawTiles(Draw& w, const Rect& rect, const Image& img); + +void DrawFatFrame(Draw& w, int x, int y, int cx, int cy, Color color, int n); +void DrawFatFrame(Draw& w, const Rect& r, Color color, int n); + +void DrawFrame(Draw& w, int x, int y, int cx, int cy, + Color leftcolor, Color topcolor, Color rightcolor, Color bottomcolor); +void DrawFrame(Draw& w, const Rect& r, + Color leftcolor, Color topcolor, Color rightcolor, Color bottomcolor); +void DrawFrame(Draw& w, int x, int y, int cx, int cy, + Color topleftcolor, Color bottomrightcolor); +void DrawFrame(Draw& w, const Rect& r, + Color topleftcolor, Color bottomrightcolor); +void DrawFrame(Draw& w, int x, int y, int cx, int cy, Color color); +void DrawFrame(Draw& w, const Rect& r, Color color); + +void DrawBorder(Draw& w, int x, int y, int cx, int cy, const ColorF *colors_ltrd); //TODO +void DrawBorder(Draw& w, const Rect& r, const ColorF *colors_ltrd); + +const ColorF *BlackBorder(); +const ColorF *ButtonPushBorder(); +const ColorF *EdgeButtonBorder(); +const ColorF *DefButtonBorder(); +const ColorF *ButtonBorder(); +const ColorF *InsetBorder(); +const ColorF *OutsetBorder(); +const ColorF *ThinOutsetBorder(); +const ColorF *ThinInsetBorder(); + +void DrawBorder(Draw& w, int x, int y, int cx, int cy, const ColorF *(*colors_ltrd)()); +void DrawBorder(Draw& w, const Rect& r, const ColorF *(*colors_ltrd)()); + +void DrawRectMinusRect(Draw& w, const Rect& rect, const Rect& inner, Color color); + +void DrawHighlightImage(Draw& w, int x, int y, const Image& img, bool highlight = true, + bool enabled = true, Color maskcolor = SColorPaper); + +Color GradientColor(Color fc, Color tc, int i, int n); + +void DrawDragRect(SystemDraw& w, const Rect& rect1, const Rect& rect2, const Rect& clip, int n, Color color, uint64 pattern); + +enum { + BUTTON_NORMAL, BUTTON_OK, BUTTON_HIGHLIGHT, BUTTON_PUSH, BUTTON_DISABLED, BUTTON_CHECKED, + BUTTON_VERTICAL = 0x100, + BUTTON_EDGE = 0x200, + BUTTON_TOOL = 0x400, + BUTTON_SCROLL = 0x800, +}; + +void DrawXPButton(Draw& w, Rect r, int type); + +void DrawTextEllipsis(Draw& w, int x, int y, int cx, const char *text, const char *ellipsis, + Font font = StdFont(), Color ink = SColorText(), int n = -1); +void DrawTextEllipsis(Draw& w, int x, int y, int cx, const wchar *text, const char *ellipsis, + Font font = StdFont(), Color ink = SColorText(), int n = -1); +Size GetTLTextSize(const wchar *text, Font font = StdFont()); +int GetTLTextHeight(const wchar *s, Font font = StdFont()); +void DrawTLText(Draw& draw, int x, int y, int cx, const wchar *text, Font font = StdFont(), + Color ink = SColorText(), int accesskey = 0); + + +typedef String (*DrawingToPdfFnType)(const Array& report, Size pagesize, int margin); + +void SetDrawingToPdfFn(DrawingToPdfFnType Pdf); +DrawingToPdfFnType GetDrawingToPdfFn(); + +#ifdef PLATFORM_WIN32 +#include "DrawWin32.h" +#endif + +#ifdef PLATFORM_X11 +#include "DrawX11.h" +#endif + + +#include "BackDraw.h" + +#include "Display.h" +#include "ImageDraw.h" +#include "Debug.h" +#include "Cham.h" + +END_UPP_NAMESPACE + +#endif diff --git a/uppdev/Draw/Draw.upp b/uppdev/Draw/Draw.upp new file mode 100644 index 000000000..5db2652c5 --- /dev/null +++ b/uppdev/Draw/Draw.upp @@ -0,0 +1,91 @@ +description "Fundamental graphics operations, including raster image processing\377B128,0,255"; + +acceptflags + NOGTK; + +uses + Core; + +library((LINUX | BSD) & !NOGTK) "gtk-x11-2.0 gdk-x11-2.0 atk-1.0 gdk_pixbuf-2.0 m pangocairo-1.0 fontconfig Xext Xrender Xinerama Xi Xrandr Xcursor Xfixes pango-1.0 cairo X11 gobject-2.0 gmodule-2.0 glib-2.0"; + +library(WIN32 !MSC8ARM) "user32 gdi32"; + +library(LINUX) X11; + +library(LINUX) dl; + +library(LINUX !XLFD) Xft; + +library(BSD) X11; + +library(BSD !XLFD) "Xft fontconfig Xrender freetype expat"; + +library(LINUX !XLFD !SHARED) "fontconfig Xrender freetype expat"; + +library(OSX11) "X11 Xft fontconfig Xrender freetype expat"; + +file + Draw.h, + Font.cpp, + FontWin32.cpp, + FontX11.cpp, + Draw.cpp, + DrawText.cpp, + ComposeText.cpp, + DrawData.cpp, + Drawing.cpp, + DrawUtil.cpp, + DrawTextUtil.cpp, + Display.h, + Display.cpp, + Debug.h, + Debug.cpp, + SystemDraw readonly separator, + DrawWin32.h, + DrawWin32.cpp, + DrawOpWin32.cpp, + MetaFile.cpp, + DrawX11.h, + DrawX11.cpp, + DrawOpX11.cpp, + DrawTextXft.cpp, + BackDraw.h, + BackDraw.cpp, + Image readonly separator, + Image.h, + ImageDraw.h, + Image.cpp, + ImageBlit.cpp, + ImageWin32.cpp, + ImageX11.cpp, + Raster.h, + RasterFormat.cpp, + RasterWrite.cpp, + Palette.cpp, + Raster.cpp, + RasterEncoder.cpp, + ImageOp.h, + ImageOp.cpp, + ImageChOp.cpp, + ImageScale.cpp, + MakeCache.cpp, + DrawRasterData.cpp, + iml.h, + iml_header.h, + iml_source.h, + DrawImg.iml, + Chameleon readonly separator, + Cham.h, + Cham.cpp, + SSettings.cpp, + GTK-dli readonly separator, + gobj.dli, + gdk.dli, + gpixbuf.dli, + gtk.dli, + gnome.dli, + Info readonly separator, + src.tpp, + srcdoc.tpp, + Copying; + diff --git a/uppdev/Draw/DrawData.cpp b/uppdev/Draw/DrawData.cpp new file mode 100644 index 000000000..a35434078 --- /dev/null +++ b/uppdev/Draw/DrawData.cpp @@ -0,0 +1,127 @@ +#include "Draw.h" + +NAMESPACE_UPP + +#define LTIMING(x) +// #define BENCHMARK_RLE + +VectorMap& DataDrawer::Map() +{ + static VectorMap x; + return x; +} + +static StaticCriticalSection sDataDrawer; + +void DataDrawer::AddFormat(const char *id, Factory factory) +{ + INTERLOCKED_(sDataDrawer) + Map().Add(id, (void *)factory); +} + +One DataDrawer::Create(const String& id) +{ + INTERLOCKED_(sDataDrawer) { + Factory q = (Factory) Map().Get(id, NULL); + if(q) + return (*q)(); + } + return NULL; +} + +bool IsWhiteColumn(const Image& m, int x) +{ + LTIMING("IsEqColumn"); + Size sz = m.GetSize(); + const RGBA *s = ~m + x; + while(sz.cy > 1) { + s += sz.cx; + if((s->a & s->r & s->g & s->b) != 255) + return false; + sz.cy--; + } + return true; +} + + +#ifdef BENCHMARK_RLE +static int sTotal; +static int sRle; + +EXITBLOCK +{ + DUMP(sTotal); + DUMP(sRle); +} +#endif + +void DrawImageBandRLE(Draw& w, int x, int y, const Image& m, int minp) +{ + int xi = 0; + int cx = m.GetWidth(); + int ccy = m.GetHeight(); + Buffer todo(cx, true); +#ifdef BENCHMARK_RLE + sTotal += cx; +#endif + while(xi < cx) { + int xi0 = xi; + while(w.Dots() && IsWhiteColumn(m, xi) && xi < cx) + xi++; + if(xi - xi0 >= 16) { +#ifdef BENCHMARK_RLE + sRle += xi - xi0; +#endif + w.DrawRect(x + xi0, y, xi - xi0, ccy, White); + Fill(~todo + xi0, ~todo + xi, false); + } + xi++; + } + + xi = 0; + while(xi < cx) + if(todo[xi]) { + int xi0 = xi; + while(xi < cx && todo[xi] && xi - xi0 < 2000) + xi++; + m.PaintImage(w, x + xi0, y, RectC(xi0, 0, xi - xi0, ccy), Null); + } + else + xi++; +} + +void Draw::DrawDataOp(int x, int y, int cx, int cy, const String& data, const char *id) +{ + DrawLock __; + bool tonative = !IsNative(); + if(tonative) { + BeginNative(); + Native(x, y); + Native(cx, cy); + } + One dd = DataDrawer::Create(id); + if(dd) { + dd->Open(data, cx, cy); + if(cx > 2048 || cy > 2048) { + int yy = 0; + while(yy < cy) { + int ccy = min(cy - yy, 32); + ImageBuffer ib(cx, ccy); + dd->Render(ib); + DrawImageBandRLE(*this, x, y + yy, ib, 16); + yy += ccy; + } + } + else { + ImageBuffer m(cx, cy); + dd->Render(m); + DrawImage(x, y, m); + } + } + if(tonative) + EndNative(); +} + +DataDrawer::~DataDrawer() {} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/DrawImg.iml b/uppdev/Draw/DrawImg.iml new file mode 100644 index 000000000..216bac37a --- /dev/null +++ b/uppdev/Draw/DrawImg.iml @@ -0,0 +1,7 @@ +PREMULTIPLIED +IMAGE_ID(threedots) + +IMAGE_BEGIN_DATA +IMAGE_DATA(120,156,99,96,99,96,103,192,1,54,3,177,40,22,241,255,64,188,10,136,37,176,136,195,228,176,137,167,99,17,71,23) +IMAGE_DATA(3,129,80,92,14,130,1,0,129,113,9,95,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) +IMAGE_END_DATA(64, 1) diff --git a/uppdev/Draw/DrawOpWin32.cpp b/uppdev/Draw/DrawOpWin32.cpp new file mode 100644 index 000000000..f76c50943 --- /dev/null +++ b/uppdev/Draw/DrawOpWin32.cpp @@ -0,0 +1,321 @@ +#include "Draw.h" + +NAMESPACE_UPP + +#ifdef PLATFORM_WIN32 + +#define LLOG(x) // LOG(x) +#define LTIMING(x) // RTIMING(x) + +void Draw::BeginOp() +{ + LTIMING("Begin"); + DrawLock __; + Cloff& w = cloff.Add(); + w.org = actual_offset; + w.hrgn = CreateRectRgn(0, 0, 0, 0); + ASSERT(w.hrgn); + int q = ::GetClipRgn(handle, w.hrgn); + ASSERT(q >= 0); + if(q == 0) { + DeleteObject(w.hrgn); + w.hrgn = NULL; + } +} + +void Draw::OffsetOp(Point p) +{ + DrawLock __; + Begin(); + actual_offset += p; + LTIMING("Offset"); + SetOrg(); +} + +bool Draw::ClipOp(const Rect& r) +{ + DrawLock __; + Begin(); + LTIMING("Clip"); + return IntersectClip(r); +} + +bool Draw::ClipoffOp(const Rect& r) +{ + DrawLock __; + Begin(); + LTIMING("Clipoff"); + LLOG("ClipoffOp " << r << ", GetClip() = " << GetClip() << ", actual_offset = " << actual_offset); + actual_offset += r.TopLeft(); + bool q = IntersectClip(r); + SetOrg(); + LLOG("//ClipoffOp, GetClip() = " << GetClip() << ", actual_offset = " << actual_offset); + return q; +} + +void Draw::EndOp() +{ + DrawLock __; + LTIMING("End"); + ASSERT(cloff.GetCount()); + Cloff& w = cloff.Top(); + actual_offset = w.org; + ::SelectClipRgn(handle, w.hrgn); + SetOrg(); + if(w.hrgn) + ::DeleteObject(w.hrgn); + cloff.Drop(); +} + +bool Draw::ExcludeClipOp(const Rect& r) +{ + DrawLock __; +#ifdef PLATFORM_WINCE + int q = ExcludeClipRect(handle, r.left, r.top, r.right, r.bottom); +#else + LTIMING("ExcludeClip"); + Rect rr = LPtoDP(r); + HRGN hrgn = ::CreateRectRgnIndirect(rr); + int q = ::ExtSelectClipRgn(handle, hrgn, RGN_DIFF); + ASSERT(q != ERROR); + ::DeleteObject(hrgn); +#endif + return q == SIMPLEREGION || q == COMPLEXREGION; +} + +bool Draw::IntersectClipOp(const Rect& r) +{ + DrawLock __; +#ifdef PLATFORM_WINCE + int q = IntersectClipRect(handle, r.left, r.top, r.right, r.bottom); +#else + LTIMING("Intersect"); + Rect rr = LPtoDP(r); + HRGN hrgn = ::CreateRectRgnIndirect(rr); + int q = ::ExtSelectClipRgn(handle, hrgn, RGN_AND); + ASSERT(q != ERROR); + ::DeleteObject(hrgn); +#endif + return q == SIMPLEREGION || q == COMPLEXREGION; +} + +Rect Draw::GetClipOp() const +{ + DrawLock __; + Rect r; + ::GetClipBox(handle, r); + return r; +} + +bool Draw::IsPaintingOp(const Rect& r) const +{ + DrawLock __; + LTIMING("IsPainting"); + LLOG("Draw::IsPaintingOp r: " << r); + return ::RectVisible(handle, r); +} + +void Draw::DrawRectOp(int x, int y, int cx, int cy, Color color) +{ + DrawLock __; + LTIMING("DrawRect"); + LLOG("DrawRect " << RectC(x, y, cx, cy) << ": " << color); + if(IsNull(color)) return; + if(cx <= 0 || cy <= 0) return; + if(color == InvertColor) + ::PatBlt(handle, x, y, cx, cy, DSTINVERT); + else { + SetColor(color); + ::PatBlt(handle, x, y, cx, cy, PATCOPY); + } +} + +void Draw::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color) +{ + DrawLock __; + if(IsNull(width) || IsNull(color)) return; + SetDrawPen(width, color); + ::MoveToEx(handle, x1, y1, NULL); + ::LineTo(handle, x2, y2); +} + +#ifndef PLATFORM_WINCE + +void Draw::DrawPolyPolylineOp(const Point *vertices, int vertex_count, + const int *counts, int count_count, + int width, Color color, Color doxor) +{ + DrawLock __; + ASSERT(count_count > 0 && vertex_count > 0); + if(vertex_count < 2 || IsNull(color)) + return; + bool is_xor = !IsNull(doxor); + if(is_xor) + color = Color(color.GetR() ^ doxor.GetR(), color.GetG() ^ doxor.GetG(), color.GetB() ^ doxor.GetB()); + if(is_xor) + SetROP2(GetHandle(), R2_XORPEN); + SetDrawPen(width, color); + if(count_count == 1) + ::Polyline(GetHandle(), (const POINT *)vertices, vertex_count); + else + ::PolyPolyline(GetHandle(), (const POINT *)vertices, + (const dword *)counts, count_count); + if(is_xor) + SetROP2(GetHandle(), R2_COPYPEN); +} + +static void DrawPolyPolyPolygonRaw( + Draw& draw, const Point *vertices, int vertex_count, + const int *subpolygon_counts, int subpolygon_count_count, + const int *disjunct_polygon_counts, int disjunct_polygon_count_count) +{ + DrawLock __; + for(int i = 0; i < disjunct_polygon_count_count; i++, disjunct_polygon_counts++) + { + int poly = *disjunct_polygon_counts; + int sub = 1; + if(*subpolygon_counts < poly) + if(disjunct_polygon_count_count > 1) + { + const int *se = subpolygon_counts; + int total = 0; + while(total < poly) + total += *se++; + sub = (int)(se - subpolygon_counts); + } + else + sub = subpolygon_count_count; + ASSERT(sizeof(POINT) == sizeof(Point)); // modify algorithm when not + if(sub == 1) + Polygon(draw, (const POINT *)vertices, poly); + else + PolyPolygon(draw, (const POINT *)vertices, subpolygon_counts, sub); + vertices += poly; + subpolygon_counts += sub; + } +} + +void Draw::DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int subpolygon_count_count, + const int *disjunct_polygon_counts, int disjunct_polygon_count_count, + Color color, int width, Color outline, uint64 pattern, Color doxor) +{ + DrawLock __; + if(vertex_count == 0) + return; + bool is_xor = !IsNull(doxor); + HDC hdc = GetHandle(); + if(pattern) { + int old_rop = GetROP2(hdc); + HGDIOBJ old_brush = GetCurrentObject(hdc, OBJ_BRUSH); + word wpat[8] = { + (byte)(pattern >> 56), (byte)(pattern >> 48), (byte)(pattern >> 40), (byte)(pattern >> 32), + (byte)(pattern >> 24), (byte)(pattern >> 16), (byte)(pattern >> 8), (byte)(pattern >> 0), + }; + HBITMAP bitmap = CreateBitmap(8, 8, 1, 1, wpat); + HBRUSH brush = ::CreatePatternBrush(bitmap); + COLORREF old_bk = GetBkColor(hdc); + COLORREF old_fg = GetTextColor(hdc); + if(!is_xor) { + SetROP2(hdc, R2_MASKPEN); + SelectObject(hdc, brush); + SetTextColor(hdc, Black()); + SetBkColor(hdc, White()); + SetDrawPen(PEN_NULL, Black); + DrawPolyPolyPolygonRaw(*this, vertices, vertex_count, + subpolygon_counts, subpolygon_count_count, + disjunct_polygon_counts, disjunct_polygon_count_count); + SetROP2(hdc, R2_MERGEPEN); + SetTextColor(hdc, color); + SetBkColor(hdc, Black()); + } + else { + SetROP2(hdc, R2_XORPEN); + SetTextColor(hdc, COLORREF(color) ^ COLORREF(doxor)); + SelectObject(hdc, brush); + } + DrawPolyPolyPolygonRaw(*this, vertices, vertex_count, + subpolygon_counts, subpolygon_count_count, + disjunct_polygon_counts, disjunct_polygon_count_count); + SelectObject(hdc, old_brush); + SetTextColor(hdc, old_fg); + SetBkColor(hdc, old_bk); + SetROP2(hdc, old_rop); + DeleteObject(brush); + DeleteObject(bitmap); + if(!IsNull(outline)) { + SetColor(Null); + SetDrawPen(width, outline); + ASSERT(sizeof(POINT) == sizeof(Point)); + DrawPolyPolyPolygonRaw(*this, vertices, vertex_count, + subpolygon_counts, subpolygon_count_count, + disjunct_polygon_counts, disjunct_polygon_count_count); + } + } + else { // simple fill + SetDrawPen(IsNull(outline) ? PEN_NULL : width, Nvl(outline, Black)); + int old_rop2; + if(is_xor) { + color = Color(color.GetR() ^ doxor.GetR(), color.GetG() ^ doxor.GetG(), color.GetB() ^ doxor.GetB()); + old_rop2 = SetROP2(hdc, R2_XORPEN); + } + SetColor(color); + DrawPolyPolyPolygonRaw(*this, vertices, vertex_count, + subpolygon_counts, subpolygon_count_count, + disjunct_polygon_counts, disjunct_polygon_count_count); + if(is_xor) + SetROP2(hdc, old_rop2); + } +} + +void Draw::DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color) +{ + DrawLock __; + SetDrawPen(width, color); + ::Arc(GetHandle(), rc.left, rc.top, rc.right, rc.bottom, start.x, start.y, end.x, end.y); +} + +#endif + +void Draw::DrawEllipseOp(const Rect& r, Color color, int width, Color pencolor) +{ + DrawLock __; + SetColor(color); + SetDrawPen(width, pencolor); + ::Ellipse(GetHandle(), r.left, r.top, r.right, r.bottom); +} + +void Draw::DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, + int n, const int *dx) { + while(n > 30000) { + DrawTextOp(x, y, angle, text, font, ink, 30000, dx); + if(dx) { + for(int i = 0; i < 30000; i++) + x += *dx++; + } + else + x += GetTextSize(text, font, 30000).cx; + n -= 30000; + text += 30000; + } + DrawLock __; + COLORREF cr = GetColor(ink); + if(cr != lastTextColor) { + LLOG("Setting text color: " << ink); + ::SetTextColor(handle, lastTextColor = cr); + } + if(angle) { + SetFont(font, angle); + ::ExtTextOutW(handle, x + lastFont.ptr->offset.cx, y + lastFont.ptr->offset.cy, + 0, NULL, (const WCHAR *)text, n, dx); + } + else { + SetFont(font); + ::ExtTextOutW(handle, x, y + lastFont.GetAscent(), 0, NULL, (const WCHAR *)text, + n, dx); + } +} + +#endif + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/DrawOpX11.cpp b/uppdev/Draw/DrawOpX11.cpp new file mode 100644 index 000000000..8d2e494be --- /dev/null +++ b/uppdev/Draw/DrawOpX11.cpp @@ -0,0 +1,320 @@ +#include "Draw.h" + +NAMESPACE_UPP + +#ifdef PLATFORM_X11 + +#define LLOG(x) // LOG(x) +#define LTIMING(x) // TIMING(x) + +void Draw::BeginOp() +{ + Cloff f = cloff.Top(); + Vector newclip; + newclip <<= clip.Top(); + f.clipi = clip.GetCount(); + clip.Add() = newclip; + cloff.Add(f); +} + +void Draw::OffsetOp(Point p) +{ + Cloff f = cloff.Top(); + f.offseti = offset.GetCount(); + actual_offset += p; + offset.Add(actual_offset); + cloff.Add(f); +} + +bool Draw::ClipOp(const Rect& r) +{ + LLOG("Draw::ClipOp(" << r << ")"); + Cloff f = cloff.Top(); + bool ch = false; + Vector newclip = Intersect(clip.Top(), r + actual_offset, ch); + if(ch) { + f.clipi = clip.GetCount(); + clip.Add() = newclip; + } + cloff.Add(f); + if(ch) + SetClip(); + return clip.Top().GetCount(); +} + +bool Draw::ClipoffOp(const Rect& r) +{ + LLOG("Draw::ClipOffOp(" << r << ")"); + Cloff f = cloff.Top(); + bool ch = false; + Vector newclip = Intersect(clip.Top(), r + actual_offset, ch); + if(ch) { + f.clipi = clip.GetCount(); + clip.Add() = newclip; + } + f.offseti = offset.GetCount(); + actual_offset += r.TopLeft(); + offset.Add(actual_offset); + cloff.Add(f); + if(ch) + SetClip(); + return clip.Top().GetCount(); +} + +void Draw::EndOp() +{ + ASSERT(cloff.GetCount()); + cloff.Drop(); + actual_offset = offset[cloff.Top().offseti]; + clip.SetCount(cloff.Top().clipi + 1); + SetClip(); +} + +bool Draw::ExcludeClipOp(const Rect& r) +{ + LLOG("Draw::ExcludeClipOp(" << r << ")"); + CloneClip(); + Vector& cl = clip.Top(); + bool ch = false; + Vector ncl = Subtract(cl, r + actual_offset, ch); + if(ch) { + cl = ncl; + SetClip(); + } + return clip.Top().GetCount(); +} + +bool Draw::IntersectClipOp(const Rect& r) +{ + CloneClip(); + Vector& cl = clip.Top(); + bool ch = false; + Vector ncl = Intersect(cl, r + actual_offset, ch); + if(ch) { + cl = ncl; + SetClip(); + } + return clip.Top().GetCount(); +} + +Rect Draw::GetClipOp() const +{ + LLOG("Draw::GetClipOp; #clip = " << clip.GetCount() << ", #cloff = " << cloff.GetCount() + << ", clipi = " << cloff.Top().clipi); + const Vector& cl = clip[cloff.Top().clipi]; + Rect box(0, 0, 0, 0); + if(!cl.GetCount()) return box; + box = cl[0]; + LLOG("cl[0] = " << box); + for(int i = 1; i < cl.GetCount(); i++) { + LLOG("cl[" << i << "] = " << cl[i]); + box |= cl[i]; + } + LLOG("out box = " << box << ", actual offset = " << actual_offset); + return box - actual_offset; +} + +bool Draw::IsPaintingOp(const Rect& r) const +{ + LTIMING("IsPaintingOp"); + Rect rr = r + actual_offset; + const Vector& cl = clip[cloff.Top().clipi]; + for(int i = 0; i < cl.GetCount(); i++) + if(cl[i].Intersects(rr)) + return true; + return false; +} + +void Draw::DrawRectOp(int x, int y, int cx, int cy, Color color) +{ + LTIMING("DrawRect"); + DrawLock __; + LLOG("DrawRect " << RectC(x, y, cx, cy) << ": " << color); + if(IsNull(color)) return; + if(cx <= 0 || cy <= 0) return; + if(color == InvertColor) { + XSetFunction(Xdisplay, gc, GXinvert); + XFillRectangle(Xdisplay, dw, gc, x + actual_offset.x, y + actual_offset.y, cx, cy); + XSetFunction(Xdisplay, gc, GXcopy); + } + else { + SetForeground(color); + XFillRectangle(Xdisplay, dw, gc, x + actual_offset.x, y + actual_offset.y, cx, cy); + } +} + +void Draw::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color) +{ + DrawLock __; + if(IsNull(width) || IsNull(color)) return; + SetLineStyle(width); + SetForeground(color); + XDrawLine(Xdisplay, dw, gc, + x1 + actual_offset.x, y1 + actual_offset.y, + x2 + actual_offset.x, y2 + actual_offset.y); +} + +void Draw::DrawPolyPolylineOp(const Point *vertices, int vertex_count, + const int *counts, int count_count, + int width, Color color, Color doxor) +{ + DrawLock __; + ASSERT(count_count > 0 && vertex_count > 0); + if(vertex_count < 2 || IsNull(color)) + return; + XGCValues gcv_old, gcv_new; + XGetGCValues(Xdisplay, GetGC(), GCForeground | GCLineWidth | GCFunction, &gcv_old); + gcv_new.function = IsNull(doxor) ? X11_ROP2_COPY : X11_ROP2_XOR; + gcv_new.foreground = GetXPixel(color) ^ (IsNull(doxor) ? 0 : GetXPixel(doxor)); + gcv_new.line_width = width; + XChangeGC(Xdisplay, GetGC(), GCForeground | GCLineWidth | GCFunction, &gcv_new); + enum { REQUEST_LENGTH = 256 }; // X server XDrawLines request length (heuristic) + Point offset = GetOffset(); + if(vertex_count == 2) + XDrawLine(Xdisplay, GetDrawable(), GetGC(), + vertices[0].x + offset.x, vertices[0].y + offset.y, + vertices[1].x + offset.x, vertices[1].y + offset.y); + else if(count_count == 1 || vertex_count > count_count * (REQUEST_LENGTH + 2)) { + for(; --count_count >= 0; counts++) + { + Buffer part(*counts); + for(XPoint *vo = part, *ve = vo + *counts; vo < ve; vo++, vertices++) + { + vo -> x = (short)(vertices -> x + offset.x); + vo -> y = (short)(vertices -> y + offset.y); + } + XDrawLines(Xdisplay, GetDrawable(), GetGC(), part, *counts, CoordModeOrigin); + } + } + else { + int segment_count = vertex_count - count_count; + Buffer segments(segment_count); + XSegment *so = segments; + while(--count_count >= 0) + { + const Point *end = vertices + *counts++; + so -> x1 = (short)(vertices -> x + offset.x); + so -> y1 = (short)(vertices -> y + offset.y); + vertices++; + so -> x2 = (short)(vertices -> x + offset.x); + so -> y2 = (short)(vertices -> y + offset.y); + so++; + while(++vertices < end) { + so -> x1 = so[-1].x2; + so -> y1 = so[-1].y2; + so -> x2 = (short)(vertices -> x + offset.x); + so -> y2 = (short)(vertices -> y + offset.y); + so++; + } + } + ASSERT(so == segments + segment_count); + XDrawSegments(Xdisplay, GetDrawable(), GetGC(), segments, segment_count); + } + XChangeGC(Xdisplay, GetGC(), GCForeground | GCLineWidth | GCFunction, &gcv_old); +} + +static void DrawPolyPolyPolygonRaw(Draw& draw, const Point *vertices, int vertex_count, + const int *subpolygon_counts, int subpolygon_count_count, const int *, int) +{ + DrawLock __; + Point offset = draw.GetOffset(); + const Point *in = vertices; + for(int i = 0; i < subpolygon_count_count; i++) { + int n = subpolygon_counts[i]; + Buffer out_points(n); + XPoint *t = out_points; + XPoint *e = t + n; + while(t < e) { + t->x = (short)(in->x + offset.x); + t->y = (short)(in->y + offset.y); + t++; + in++; + } + XFillPolygon(Xdisplay, draw.GetDrawable(), draw.GetGC(), out_points, n, Nonconvex, CoordModeOrigin); + } +} + +void Draw::DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int subpolygon_count_count, + const int *disjunct_polygon_counts, int disjunct_polygon_count_count, + Color color, int width, Color outline, uint64 pattern, Color doxor) +{ + DrawLock __; + if(vertex_count == 0) + return; + + bool is_xor = !IsNull(doxor); + XGCValues gcv_old, gcv_new; + XGetGCValues(Xdisplay, GetGC(), GCForeground | GCFunction | GCLineWidth, &gcv_old); + unsigned xor_pixel = (is_xor ? GetXPixel(doxor) : 0); + if(!IsNull(color)) + { + gcv_new.foreground = GetXPixel(color) ^ xor_pixel; + gcv_new.function = is_xor ? X11_ROP2_XOR : X11_ROP2_COPY; + XChangeGC(Xdisplay, GetGC(), GCForeground | GCFunction, &gcv_new); + DrawPolyPolyPolygonRaw(*this, vertices, vertex_count, + subpolygon_counts, subpolygon_count_count, + disjunct_polygon_counts, disjunct_polygon_count_count); + } + if(!IsNull(outline)) + { + gcv_new.foreground = GetXPixel(outline) ^ xor_pixel; + gcv_new.line_width = width; + XChangeGC(Xdisplay, GetGC(), GCForeground | GCLineWidth, &gcv_new); + Point offset = GetOffset(); + for(const int *sp = subpolygon_counts, *se = sp + subpolygon_count_count; sp < se; sp++) + { + Buffer segment(*sp + 1); + XPoint *out = segment; + for(const Point *end = vertices + *sp; vertices < end; vertices++, out++) + { + out -> x = (short)(vertices -> x + offset.x); + out -> y = (short)(vertices -> y + offset.y); + } + *out = segment[0]; + XDrawLines(Xdisplay, GetDrawable(), GetGC(), segment, *sp + 1, CoordModeOrigin); + } + } + XChangeGC(Xdisplay, GetGC(), GCForeground | GCFunction | GCLineWidth, &gcv_old); +} + +void Draw::DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor) +{ + DrawLock __; + SetLineStyle(pen); + if(!IsNull(color)) { + SetForeground(color); + XFillArc(Xdisplay, dw, gc, r.left + actual_offset.x, r.top + actual_offset.y, + r.Width() - 1, r.Height() - 1, 0, 360 * 64); + } + if(!IsNull(pencolor) && !IsNull(pen)) { + SetForeground(pencolor); + XDrawArc(Xdisplay, dw, gc, r.left + actual_offset.x, r.top + actual_offset.y, + r.Width() - 1, r.Height() - 1, 0, 360 * 64); + } +} + +void Draw::DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color) +{ + DrawLock __; + XGCValues gcv, gcv_old; + XGetGCValues(Xdisplay, GetGC(), GCForeground, &gcv_old); + Point offset = GetOffset(); + gcv.foreground = GetXPixel(color); + XChangeGC(Xdisplay, GetGC(), GCForeground, &gcv); + Point centre = rc.CenterPoint(); + int angle1 = fround(360 * 64 / (2 * M_PI) * + atan2(centre.y - start.y, start.x - centre.x)); + int angle2 = fround(360 * 64 / (2 * M_PI) * + atan2(centre.y - end.y, end.x - centre.x)); + if(angle2 <= angle1) + angle2 += 360 * 64; + angle2 -= angle1; + XDrawArc(Xdisplay, GetDrawable(), GetGC(), rc.left + offset.x, rc.top + offset.y, + rc.Width(), rc.Height(), angle1, angle2); + XChangeGC(Xdisplay, GetGC(), GCForeground, &gcv_old); +} + +#endif + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/DrawRasterData.cpp b/uppdev/Draw/DrawRasterData.cpp new file mode 100644 index 000000000..5c9d4ecad --- /dev/null +++ b/uppdev/Draw/DrawRasterData.cpp @@ -0,0 +1,40 @@ +#include "Draw.h" + +NAMESPACE_UPP + +struct cDrawRasterData : DataDrawer { + int cx; + StringStream ss; + One raster; + RescaleImage si; + + virtual void Open(const String& data, int cx, int cy); + virtual void Render(ImageBuffer& ib); +}; + +void cDrawRasterData::Open(const String& data, int _cx, int cy) +{ + cx = _cx; + ss.Open(data); + raster = StreamRaster::OpenAny(ss); + if(raster) + si.Create(Size(cx, cy), *raster, raster->GetSize()); +} + +void cDrawRasterData::Render(ImageBuffer& ib) +{ + for(int y = 0; y < ib.GetHeight(); y++) + si.Get(ib[y]); +} + +INITBLOCK +{ + DataDrawer::Register("image_data"); +}; + +void DrawRasterData(Draw& w, int x, int y, int cx, int cy, const String& data) +{ + w.DrawData(x, y, cx, cy, data, "image_data"); +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/DrawText.cpp b/uppdev/Draw/DrawText.cpp new file mode 100644 index 000000000..fe6950700 --- /dev/null +++ b/uppdev/Draw/DrawText.cpp @@ -0,0 +1,141 @@ +#include "Draw.h" + +NAMESPACE_UPP + + +#define LLOG(x) // LOG(x) +#define LTIMING(x) // TIMING(x) + +WString TextUnicode(const char *s, int n, byte cs, Font font) +{ + if(n < 0) + n = (int)strlen(s); + if(font.GetFace() == Font::SYMBOL) { + WStringBuffer b(n); + wchar *t = b; + while(n > 0) { + *t++ = *s++; + n--; + } + return b; + } + else + return ToUnicode(s, n, cs); +} + +void Draw::DrawText(int x, int y, int angle, const wchar *text, Font font, + Color ink, int n, const int *dx) +{ + if(IsNull(ink)) return; + if(n < 0) + n = wstrlen(text); + ComposeText(x, y, angle, text, font, ink, n, dx); +} + +// ---------------------------- + +void Draw::DrawText(int x, int y, const wchar *text, Font font, + Color ink, int n, const int *dx) +{ + DrawText(x, y, 0, text, font, ink, n, dx); +} + +// --------------------------- + +void Draw::DrawText(int x, int y, int angle, const WString& text, Font font, + Color ink, const int *dx) +{ + DrawText(x, y, angle, ~text, font, ink, text.GetLength(), dx); +} + +void Draw::DrawText(int x, int y, const WString& text, Font font, Color ink, const int *dx) +{ + DrawText(x, y, 0, text, font, ink, dx); +} + +// --------------------------- + +void Draw::DrawText(int x, int y, int angle, const char *text, byte charset, Font font, + Color ink, int n, const int *dx) +{ + DrawText(x, y, angle, TextUnicode(text, n, charset, font), font, ink, dx); +} + +void Draw::DrawText(int x, int y, const char *text, byte charset, Font font, + Color ink, int n, const int *dx) +{ + DrawText(x, y, 0, text, charset, font, ink, n, dx); +} + +// --------------------------- + +void Draw::DrawText(int x, int y, int angle, const char *text, + Font font, Color ink, int n, const int *dx) +{ + DrawText(x, y, angle, text, CHARSET_DEFAULT, font, ink, n, dx); +} + +void Draw::DrawText(int x, int y, const char *text, Font font, + Color ink, int n, const int *dx) +{ + DrawText(x, y, text, CHARSET_DEFAULT, font, ink, n, dx); +} + +// --------------------------- + +void Draw::DrawText(int x, int y, int angle, const String& text, Font font, + Color ink, const int *dx) +{ + DrawText(x, y, angle, text, font, ink, text.GetLength(), dx); +} + +void Draw::DrawText(int x, int y, const String& text, Font font, Color ink, const int *dx) +{ + WString h = TextUnicode(text, text.GetLength(), CHARSET_DEFAULT, font); + DrawText(x, y, h, font, ink, h.GetLength(), dx); +} + +// -------------------------- + +Size GetTextSize(const wchar *text, Font font, int n) +{ + FontInfo fi = font.Info(); + if(n < 0) + n = wstrlen(text); + Size sz; + sz.cx = 0; + const wchar *wtext = (const wchar *)text; + while(n > 0) { + sz.cx += fi[*wtext++]; + n--; + } + sz.cy = fi.GetHeight(); + return sz; +} + +Size GetTextSize(const WString& text, Font font) +{ + return GetTextSize(text, font, text.GetLength()); +} + +Size GetTextSize(const char *text, byte charset, Font font, int n) +{ + return GetTextSize(TextUnicode(text, n, charset, font), font); +} + +Size GetTextSize(const char *text, Font font, int n) +{ + return GetTextSize(text, CHARSET_DEFAULT, font, n); +} + +Size GetTextSize(const String& text, Font font) +{ + return GetTextSize(text, font, text.GetLength()); +} + +Font Draw::GetStdFont() +{ + return AStdFont; +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/DrawTextUtil.cpp b/uppdev/Draw/DrawTextUtil.cpp new file mode 100644 index 000000000..3d27b13d9 --- /dev/null +++ b/uppdev/Draw/DrawTextUtil.cpp @@ -0,0 +1,128 @@ +#include "Draw.h" + +NAMESPACE_UPP + +void DrawTextEllipsis(Draw& w, int x, int y, int cx, const wchar *text, const char *ellipsis, + Font font, Color ink, int n) +{ + if(n < 0) n = wstrlen(text); + FontInfo f = font.Info(); + const char *s; + int dtl = 0; + int el = 0; + for(s = ellipsis; *s; s++) { + dtl += f[(byte)*s]; + el++; + } + int l = 0; + int i; + for(i = 0; i < n; i++) { + l += f[(byte) text[i]]; + if(l > cx) { + while(l + dtl > cx && i > 0) { + l -= f[(byte) text[i]]; + i--; + } + i++; + break; + } + } + w.DrawText(x, y, text, font, ink, i); + if(i < n) + w.DrawText(x + l, y, ellipsis, font, ink, el); +} + +void DrawTextEllipsis(Draw& w, int x, int y, int cx, const char *text, const char *ellipsis, + Font font, Color ink, int n) +{ + return DrawTextEllipsis(w, x, y, cx, WString(text), ellipsis, font, ink, n); +} + +Size GetTLTextSize(const wchar *text, Font font) +{ + Size sz(0, 0); + int cy = font.Info().GetHeight(); + const wchar *s = text; + const wchar *t = s; + for(;;) { + if(*s == '\n' || *s == '\0') { + int a = 0; + const wchar *q = t; + while(q < s) { + while(q < s && *q < ' ') { + if(*q == '\t') + a = (a + 2 * cy) / (2 * cy) * (2 * cy); + q++; + } + t = q; + while(q < s && *q >= ' ') + q++; + a += GetTextSize(t, font, (int) (q - t)).cx; + } + t = s + 1; + sz.cy += cy; + sz.cx = max(sz.cx, a); + } + if(*s++ == '\0') break; + } + return sz; +} + +int GetTLTextHeight(const wchar *s, Font font) +{ + int cy = font.Info().GetHeight(); + int h = cy; + while(*s) { + if(*s == '\n') + h += cy; + s++; + } + return h; +} + +void DrawTLText(Draw& draw, int x, int y, int cx, const wchar *text, + Font font, Color ink, int accesskey) { + int cy = font.Info().GetHeight(); + const wchar *s = text; + const wchar *t = s; + int apos = HIWORD(accesskey); + int akey = LOWORD(accesskey); + for(;;) { + if(*s == '\n' || *s == '\0') { + int a = x; + const wchar *q = t; + const wchar *start = NULL; + while(q < s) { + while(q < s && *q < ' ') { + if(*q == '\t') + a = (a - x + 2 * cy) / (2 * cy) * (2 * cy) + x; + q++; + } + t = q; + bool ak = false; + start = q; + while(q < s && *q >= ' ') { + if(akey && ToUpper(ToAscii(*q)) == akey && (apos == 0 || q - start + 1 == apos)) { + ak = true; + akey = 0; + break; + } + q++; + } + start = NULL; + draw.DrawText(a, y, t, font, ink, (int)(q - t)); + a += GetTextSize(t, font, (int)(q - t)).cx; + if(ak) { + draw.DrawText(a, y, q, font().Underline(), ink, 1); + a += GetTextSize(q, font().Underline(), 1).cx; + q++; + } + } + t = s + 1; + y += cy; + } + if(*s++ == '\0') break; + } +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/DrawTextXft.cpp b/uppdev/Draw/DrawTextXft.cpp new file mode 100644 index 000000000..4eba88ee0 --- /dev/null +++ b/uppdev/Draw/DrawTextXft.cpp @@ -0,0 +1,372 @@ +#include "Draw.h" + +NAMESPACE_UPP + +#define LLOG(x) //LOG(x) +#define LTIMING(x) //RTIMING(x) + +struct XFTFontFaceInfo { + String name; + bool fixed:1; + bool scaleable:1; + bool compose:1; + + XFTFontFaceInfo() + { + fixed = scaleable = false; + } +}; + +ArrayMap& XFTFontFace() +{ + static ArrayMap x; + return x; +} + +FontInfo::Data::Data() +{ + refcount = 1; + for(int i = 0; i < 64; i++) + base[i] = NULL; + xftfont = NULL; +} + +FontInfo::Data::~Data() +{ + DrawLock __; + if(xftfont0 && xftfont0 != xftfont) + XftFontClose(Xdisplay, xftfont0); + if(xftfont) + XftFontClose(Xdisplay, xftfont); + for(int i = 0; i < 64; i++) + if(base[i]) delete[] base[i]; +} + +void FontInfo::Data::GetMetrics(CharMetrics *t, int from, int count) +{ + DrawLock __; + LTIMING("GetMetrics"); + LLOG("GetMetrics " << font << " " << from << ", " << count); + if(xftfont) { + for(int i = 0; i < count; i++) { + LTIMING("XftTextExtents16"); + wchar h = from + i; + XGlyphInfo info; + XftTextExtents16(Xdisplay, xftfont0, &h, 1, &info); + t[i].width = info.xOff; + t[i].lspc = -info.x; + t[i].rspc = info.xOff - info.width + info.x; + } + } +} + +const char *basic_fonts[] = { + "sans-serif", + "serif", + "sans-serif", + "monospace", + "serif", + "sans-serif", + "monospace", +}; + +static int sCheckComposed(const char *face) +{ + XftFont *xftfont = XftFontOpen(Xdisplay, Xscreenno, + XFT_FAMILY, XftTypeString, (char *)face, + XFT_PIXEL_SIZE, XftTypeInteger, 20, + (void *)0); + if(xftfont == NULL ) + return -1; + int n = 0; + for(int c = 0; c < 128; c++) + if(!XftCharExists(Xdisplay, xftfont, c + 256)) + n++; + XftFontClose(Xdisplay, xftfont); + return n > 10; +} + +bool FontInfo::Data::HasChar(int ch) const +{ + return XftCharExists(Xdisplay, xftfont, ch); +} + +void Draw::InitPlatformFonts() +{ + for(int i = 0; i < __countof(basic_fonts); i++) { + XFTFontFaceInfo& f = XFTFontFace().Add(basic_fonts[i]); + f.name = basic_fonts[i]; + f.scaleable = true; + f.fixed = i == 3 || i == 6; + f.compose = sCheckComposed(basic_fonts[i]); + } + FcFontSet *fs = XftListFonts(Xdisplay, Xscreenno, (void *)0, XFT_FAMILY, XFT_SPACING, + XFT_SCALABLE, (void *)0); + for(int i = 0; i < fs->nfont; i++) { + FcChar8 *family = NULL; + if(FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == 0 && family) { + int comp = sCheckComposed((char *)family); + if(comp >= 0) { + XFTFontFaceInfo& f = XFTFontFace().GetAdd((char *)family); + int spacing; + if(FcPatternGetInteger(fs->fonts[i], FC_SPACING, 0, &spacing) == 0 && spacing == XFT_MONO) + f.fixed = true; + FcBool scaleable; + if(FcPatternGetBool(fs->fonts[i], FC_SCALABLE, 0, &scaleable) == 0 && scaleable) + f.scaleable = true; + f.compose = comp; + } + } + } + FcFontSetDestroy(fs); +} + +int Font::GetFaceCount() +{ + if(!Draw::sFini) Draw::InitFonts(); + return XFTFontFace().GetCount(); +} + +String Font::GetFaceName(int index) +{ + if(!Draw::sFini) Draw::InitFonts(); + return index >= 0 && index < XFTFontFace().GetCount() ? XFTFontFace().GetKey(index) + : Null; +} + +dword Font::GetFaceInfo(int index) { + if(!Draw::sFini) Draw::InitFonts(); + dword w = 0; + if(index >= 0 && index < XFTFontFace().GetCount()) { + XFTFontFaceInfo& fi = XFTFontFace()[index]; + if(fi.fixed) + w |= FIXEDPITCH; + if(fi.scaleable) + w |= SCALEABLE; + if(fi.compose) + w |= COMPOSED; + } + return w; +} + +int gtk_antialias = -1; +int gtk_hinting = -1; +String gtk_hintstyle; +String gtk_rgba; + +XftFont *Draw::CreateXftFont(Font font, int angle) +{ + LTIMING("CreateXftFont"); + XftFont *xftfont; + double sina, cosa; + int hg = abs(font.GetHeight()); + if(hg == 0) hg = 10; + int i = font.GetFace(); + if(i < 0 || i >= XFTFontFace().GetCount()) + i = 0; + const char *face = i < 7 ? basic_fonts[i] : ~XFTFontFace().GetKey(i); + FcPattern *p = FcPatternCreate(); + FcPatternAddString(p, FC_FAMILY, (FcChar8*)face); + FcPatternAddInteger(p, FC_SLANT, font.IsItalic() ? 110 : 0); + FcPatternAddInteger(p, FC_PIXEL_SIZE, hg); + FcPatternAddInteger(p, FC_WEIGHT, font.IsBold() ? 200 : 100); + FcPatternAddBool(p, FC_MINSPACE, 1); + if(angle) { + FcMatrix mx; + SinCos(angle, sina, cosa); + mx.xx = cosa; + mx.xy = -sina; + mx.yx = sina; + mx.yy = cosa; + FcPatternAddMatrix(p, FC_MATRIX, &mx); + } + FcResult result; + FcPattern *m = XftFontMatch(Xdisplay, Xscreenno, p, &result); + if(font.IsNonAntiAliased() || gtk_antialias >= 0) { + FcPatternDel(m, FC_ANTIALIAS); + FcPatternAddBool(m, FC_ANTIALIAS, + font.IsNonAntiAliased() ? FcFalse : gtk_antialias ? FcTrue : FcFalse); + } + if(gtk_hinting >= 0) { + FcPatternDel(m, FC_HINTING); + FcPatternAddBool(m, FC_HINTING, gtk_hinting); + } + const char *hs[] = { "hintnone", "hintslight", "hintmedium", "hintfull" }; + for(int i = 0; i < 4; i++) + if(gtk_hintstyle == hs[i]) { + FcPatternDel(m, FC_HINT_STYLE); + FcPatternAddInteger(m, FC_HINT_STYLE, i); + } + const char *rgba[] = { "_", "rgb", "bgr", "vrgb", "vbgr" }; + for(int i = 0; i < __countof(rgba); i++) + if(gtk_rgba == rgba[i]) { + FcPatternDel(m, FC_RGBA); + FcPatternAddInteger(m, FC_RGBA, i); + } + xftfont = XftFontOpenPattern(Xdisplay, m); + FcPatternDestroy(p); + return xftfont; +} + +FontInfo Draw::Acquire(Font font, int angle, int device) +{ + DrawLock __; + LTIMING("Acquire"); + if(IsNull(font)) + font = StdFont(); + if(font.GetFace() == 0) + font.Face(AStdFont.GetFace()); + if(font.GetHeight() == 0) + font.Height(AStdFont.GetHeight()); + FontInfo::Data *f, *fh; + f = fh = GetFontHash((font.GetHashValue() ^ angle ^ (device << 9)) % (int)FONTHASH); + LLOG("Acquire " << font << " device: " << device); + for(;;) { + f = f->GetNext(HASH); + if(f == fh) break; + if(f->font == font && f->angle == angle && f->device == device) + { + LLOG("Reusing " << f->font); + if(f->InList(LRU)) { + f->Unlink(LRU); + FontCached--; + LLOG("Removing from cache " << f->font << " cached:" << FontCached); + } + f->refcount++; + return f; + } + } + LLOG("New " << font); + LTIMING("Acquire New"); + f = fh->InsertNext(HASH); + f->font = font; + f->angle = angle; + f->device = device; + int hg = abs(font.GetHeight()); + if(hg == 0) hg = 10; + f->xftfont0 = f->xftfont = CreateXftFont(font, angle); + if(angle) + f->xftfont0 = CreateXftFont(font, 0); + f->filename = NULL; + f->ascent = (int16)f->xftfont0->ascent; + f->descent = (int16)f->xftfont0->descent; + f->height = f->ascent + f->descent; + f->lineheight = (int16)f->xftfont0->height; + f->external = 0; + f->internal = 0; + f->overhang = 0; + f->maxwidth = (int16)f->xftfont0->max_advance_width; + f->avewidth = f->maxwidth; + f->default_char = '?'; + f->fixedpitch = font.GetFaceInfo() & Font::FIXEDPITCH; + f->underline_thickness = max(hg / 20, 1); + f->underline_position = max(hg / 15, int(f->descent > 0)); + if(angle) { + SinCos(angle, f->sina, f->cosa); + f->offset.cx = fround(f->ascent * f->sina); + f->offset.cy = fround(f->ascent * f->cosa); + } + FontInfo fi = FontInfo(f); + fi.GetPage(0); + return fi; +} + +String FontInfo::GetFileName() const +{ + if(IsNull(ptr->filename)) { + char *fn = NULL; + XftPatternGetString(ptr->xftfont->pattern, XFT_FILE, 0, &fn); + if(fn) + ptr->filename = fn; + } + return ptr->filename; +} + +void Draw::DrawTextOp(int x, int y, int angle, const wchar *text, Font font, + Color ink, int n, const int *dx) { + LTIMING("DrawText"); + LLOG("DrawText " << ToUtf8(WString(text, n)) << " color:" << ink << " font:" << font); + //TODO - X11 seems to crash when displaying too long strings (?) + int ox = x + actual_offset.x; + int oy = y + actual_offset.y; + SetForeground(ink); + SetFont(font, angle); + const FontInfo::Data *fd = lastFont.ptr; + XftColor c; + c.color.red = ink.GetR() << 8; + c.color.green = ink.GetG() << 8; + c.color.blue = ink.GetB() << 8; + c.color.alpha = 0xffff; + c.pixel = GetXPixel(ink.GetR(), ink.GetG(), ink.GetB()); + if(angle) { + int xpos = 0; + for(int i = 0; i < n; i++) { + wchar h = text[i]; + XftDrawString16(xftdraw, &c, fd->xftfont, + int(ox + xpos * fd->cosa + fd->offset.cx), + int(oy - xpos * fd->sina + fd->offset.cy), + (FcChar16 *)&h, 1); + xpos += dx ? dx[i] : lastFont[text[i]]; + } + if(font.IsUnderline() || font.IsStrikeout()) { + x += fd->offset.cx; + y += fd->offset.cy; + if(font.IsUnderline()) + DrawLine( + int(x + fd->underline_position * fd->sina), + int(y + fd->underline_position * fd->cosa), + int(x + xpos * fd->cosa + fd->underline_position * fd->sina), + int(y - xpos * fd->sina + fd->underline_position * fd->cosa), + fd->underline_thickness, + ink + ); + if(font.IsStrikeout()) { + int p = 2 * fd->ascent / 3; + DrawLine( + int(x + p * fd->sina), + int(y + p * fd->cosa), + int(x + xpos * fd->cosa + p * fd->sina), + int(y - xpos * fd->sina + p * fd->cosa), + fd->underline_thickness, + ink + ); + } + } + } + else { + if(dx) { + int xpos = ox; + Buffer ch(n); + for(int i = 0; i < n; i++) { + ch[i].ucs4 = text[i]; + ch[i].x = xpos; + ch[i].y = oy + fd->ascent; + xpos += dx[i]; + } + XftDrawCharSpec(xftdraw, &c, fd->xftfont, ch, n); + } + else + XftDrawString16(xftdraw, &c, fd->xftfont, ox, oy + fd->ascent, + (FcChar16 *)text, n); + LLOG("XftColor: r=" << c.color.red << ", g=" << c.color.green << ", b=" << c.color.blue + << ", alpha=" << c.color.alpha << ", pixel=" << FormatIntHex(c.pixel)); + if(font.IsUnderline() || font.IsStrikeout()) { + int cx; + if(dx && n > 0) { + cx = 0; + Sum(cx, dx, dx + n - 1); + cx += lastFont[text[n - 1]]; + } + else + cx = GetTextSize(text, font, n).cx; + if(font.IsUnderline()) + DrawRect(x, y + lastFont.GetAscent() + lastFont.ptr->underline_position, + cx, lastFont.ptr->underline_thickness, ink); + if(font.IsStrikeout()) + DrawRect(x, y + 2 * lastFont.GetAscent() / 3, + cx, lastFont.ptr->underline_thickness, ink); + } + } +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/DrawUtil.cpp b/uppdev/Draw/DrawUtil.cpp new file mode 100644 index 000000000..b5efd537a --- /dev/null +++ b/uppdev/Draw/DrawUtil.cpp @@ -0,0 +1,632 @@ +#include "Draw.h" + +NAMESPACE_UPP + +#define LTIMING(x) // TIMING(x) + +void AddNotEmpty(Vector& result, int left, int right, int top, int bottom) +{ + if(left < right && top < bottom) + result.Add(Rect(left, top, right, bottom)); +} + +bool Subtract(const Rect& r, const Rect& sub, Vector& result) +{ + LTIMING("SubtractRect0"); + Rect is = r & sub; + if(!is.IsEmpty()) { + AddNotEmpty(result, r.left, is.left, r.top, is.top); + AddNotEmpty(result, is.left, is.right, r.top, is.top); + AddNotEmpty(result, is.right, r.right, r.top, is.top); + AddNotEmpty(result, r.left, is.left, is.top, is.bottom); + AddNotEmpty(result, is.right, r.right, is.top, is.bottom); + AddNotEmpty(result, r.left, is.left, is.bottom, r.bottom); + AddNotEmpty(result, is.left, is.right, is.bottom, r.bottom); + AddNotEmpty(result, is.right, r.right, is.bottom, r.bottom); + return true; + } + else { + result.Add(r); + return false; + } +} + +bool Subtract(const Vector& rr, const Rect& sub, Vector& result) +{ + LTIMING("SubtractRect"); + bool changed = false; + for(int i = 0; i < rr.GetCount(); i++) { + const Rect& r = rr[i]; + if(Subtract(r, sub, result)) + changed = true; + } + return changed; +} + +Vector Subtract(const Vector& rr, const Rect& sub, bool& changed) +{ + Vector result; + if(Subtract(rr, sub, result)) + changed = true; + return result; +} + +void Subtract(Vector& rr, const Rect& sub) +{ + LTIMING("Subtract"); + if(sub.IsEmpty()) + return; + bool dummy; + rr = Subtract(rr, sub, dummy); +} + +void Union(Vector& rr, const Rect& add) +{ + LTIMING("Union"); + if(add.IsEmpty()) + return; + Vector r; + r.Add(add); + for(int i = 0; i < rr.GetCount() && r.GetCount(); i++) + Subtract(r, rr[i]); + for(int i = 0; i < r.GetCount(); i++) + rr.Add(r[i]); +} + +Vector Intersect(const Vector& b, const Rect& a, bool& changed) +{ + Vector result; + for(int i = 0; i < b.GetCount(); i++) { + Rect r = b[i] & a; + if(r.IsEmpty()) + changed = true; + else { + if(r != b[i]) changed = true; + result.Add(r); + } + } + return result; +} + +void DrawFatFrame(Draw& w, int x, int y, int cx, int cy, Color color, int n) { + if(n < 0) { + x += n; + y += n; + n = -n; + cx += 2 * n; + cy += 2 * n; + } + w.DrawRect(x, y, cx, n, color); + w.DrawRect(x, y + n, n, cy - n, color); + w.DrawRect(x + cx - n, y + n, n, cy - n, color); + w.DrawRect(x + n, y + cy - n, cx - 2 * n, n, color); +} + +void DrawFatFrame(Draw& w, const Rect& r, Color color, int n) { + DrawFatFrame(w, r.left, r.top, r.Width(), r.Height(), color, n); +} + +void DrawFrame(Draw& w, int x, int y, int cx, int cy, + Color leftcolor, Color topcolor, Color rightcolor, Color bottomcolor) +{ + w.DrawRect(x, y, cx - 1, 1, topcolor); + w.DrawRect(x, y, 1, cy - 1, leftcolor); + w.DrawRect(x + cx - 1, y, 1, cy, rightcolor); + w.DrawRect(x, y + cy - 1, cx, 1, bottomcolor); +} + +void DrawFrame(Draw& w, const Rect& r, + Color leftcolor, Color topcolor, Color rightcolor, Color bottomcolor) +{ + DrawFrame(w, r.left, r.top, r.Width(), r.Height(), + leftcolor, topcolor, rightcolor, bottomcolor); +} + +void DrawFrame(Draw& w, int x, int y, int cx, int cy, + Color topleftcolor, Color bottomrightcolor) +{ + DrawFrame(w, x, y, cx, cy, topleftcolor, topleftcolor, bottomrightcolor, bottomrightcolor); +} + +void DrawFrame(Draw& w, const Rect& r, + Color topleftcolor, Color bottomrightcolor) { + DrawFrame(w, r, topleftcolor, topleftcolor, bottomrightcolor, bottomrightcolor); +} + +void DrawFrame(Draw& w, int x, int y, int cx, int cy, Color color) { + DrawFrame(w, x, y, cx, cy, color, color); +} + +void DrawFrame(Draw& w, const Rect& r, Color color) { + DrawFrame(w, r, color, color); +} + +void DrawBorder(Draw& w, int x, int y, int cx, int cy, const ColorF *c) { + if(!c) return; + int n = (int)(uintptr_t)*c; + c++; + while(n--) { + if(cx <= 0 || cy <= 0) + break; + DrawFrame(w, x, y, cx, cy, c[0], c[1], c[2], c[3]); + x += 1; + y += 1; + cx -= 2; + cy -= 2; + c += 4; + } +} + +void DrawBorder(Draw& w, const Rect& r, const ColorF *c) { + DrawBorder(w, r.left, r.top, r.Width(), r.Height(), c); +} + +const ColorF *BlackBorder() +{ + static ColorF data[] = { + (ColorF)1, + &SColorText, &SColorText, &SColorText, &SColorText, + }; + return data; +} + +const ColorF *DefButtonBorder() +{ + static ColorF data[] = { + (ColorF)3, + &SColorText, &SColorText, &SColorText, &SColorText, + &SColorLight, &SColorLight, &SColorText, &SColorText, + &SColorLtFace, &SColorLtFace, &SColorShadow, &SColorShadow, + }; + return data; +} + +const ColorF *ButtonBorder() +{ + static ColorF data[] = { + (ColorF)2, + &SColorLight, &SColorLight, &SColorText, &SColorText, + &SColorLtFace, &SColorLtFace, &SColorShadow, &SColorShadow, + }; + return data; +} + +const ColorF *EdgeButtonBorder() +{ + static ColorF data[] = { + (ColorF)2, + &SColorLtFace, &SColorLtFace, &SColorText, &SColorText, + &SColorLight, &SColorLight, &SColorShadow, &SColorShadow, + }; + return data; +} + +const ColorF *ButtonPushBorder() +{ + static ColorF data[] = { + (ColorF)2, + &SColorText, &SColorText, &SColorText, &SColorText, + &SColorShadow, &SColorShadow, &SColorText, &SColorText + }; + return data; +} + +const ColorF *InsetBorder() +{ + static ColorF data[] = { + (ColorF)2, + &SColorShadow, &SColorShadow, &SColorLight, &SColorLight, + &SColorText, &SColorText, &SColorFace, &SColorFace + }; + return data; +} + +const ColorF *OutsetBorder() +{ + static ColorF data[] = { + (ColorF)2, + &SColorFace, &SColorFace, &SColorText, &SColorText, + &SColorLight, &SColorLight, &SColorShadow, &SColorShadow, + }; + return data; +} + +const ColorF *ThinOutsetBorder() +{ + static ColorF data[] = { + (ColorF)1, + &SColorLight, &SColorLight, &SColorShadow, &SColorShadow, + }; + return data; +} + +const ColorF *ThinInsetBorder() +{ + static ColorF data[] = { + (ColorF)1, + &SColorShadow, &SColorShadow, &SColorLight, &SColorLight, + }; + return data; +} + +void DrawBorder(Draw& w, int x, int y, int cx, int cy, const ColorF *(*colors_ltrd)()) +{ + DrawBorder(w, x, y, cx, cy, (*colors_ltrd)()); +} + +void DrawBorder(Draw& w, const Rect& r, const ColorF *(*colors_ltrd)()) +{ + DrawBorder(w, r, (*colors_ltrd)()); +} + +void DrawRectMinusRect(Draw& w, const Rect& rect, const Rect& inner, Color color) { + Rect r = rect; + r.bottom = inner.top; + w.DrawRect(r, color); + r = inner; + r.right = r.left; + r.left = rect.left; + w.DrawRect(r, color); + r.left = inner.right; + r.right = rect.right; + w.DrawRect(r, color); + r = rect; + r.top = inner.bottom; + w.DrawRect(r, color); +} + +void DrawRect(Draw& w, int x, int y, int cx, int cy, const Image& img, bool ra) { + w.Clip(x, y, cx, cy); + Size sz = img.GetSize(); + for(int a = ra ? x : x / sz.cx * sz.cx; a < x + cx; a += sz.cx) + for(int b = ra ? y : y / sz.cy * sz.cy ; b < y + cy; b += sz.cy) + w.DrawImage(a, b, img); + w.End(); +} + +void DrawRect(Draw& w, const Rect& rect, const Image& img, bool ralgn) +{ + DrawRect(w, rect.left, rect.top, rect.Width(), rect.Height(), img, ralgn); +} + +void DrawTiles(Draw& w, int x, int y, int cx, int cy, const Image& img) { + w.Clip(x, y, cx, cy); + Size sz = img.GetSize(); + for(int a = x; a < x + cx; a += sz.cx) + for(int b = y; b < y + cy; b += sz.cy) + w.DrawImage(a, b, img); + w.End(); +} + +void DrawTiles(Draw& w, const Rect& rect, const Image& img) +{ + DrawTiles(w, rect.left, rect.top, rect.GetWidth(), rect.GetHeight(), img); +} + +void DrawHighlightImage(Draw& w, int x, int y, const Image& img, bool highlight, + bool enabled, Color maskcolor) +{ + if(highlight) { + w.DrawImage(x + 1, y, img, maskcolor); + w.DrawImage(x - 1, y, img, maskcolor); + w.DrawImage(x, y + 1, img, maskcolor); + w.DrawImage(x, y - 1, img, maskcolor); + } + w.DrawImage(x, y, enabled ? img : MakeImage(img, Etched)); +} + +Color GradientColor(Color fc, Color tc, int i, int n) +{ + return Color( + fc.GetR() + i * (tc.GetR() - fc.GetR()) / n, + fc.GetG() + i * (tc.GetG() - fc.GetG()) / n, + fc.GetB() + i * (tc.GetB() - fc.GetB()) / n + ); +} + +void PaintButtonRect(Draw& w, Rect& r, + Color left, Color top, Color right, Color bottom, + Color& topleft, Color& topright, Color& bottomleft, Color& bottomright) +{ + w.DrawRect(r.left, r.top, 1, 1, topleft); + w.DrawRect(r.right - 1, r.top, 1, 1, topright); + w.DrawRect(r.left, r.bottom - 1, 1, 1, bottomleft); + w.DrawRect(r.right - 1, r.bottom - 1, 1, 1, bottomright); + + Color b1, b2; + w.DrawRect(r.left + 1, r.top, 1, 1, b1 = Blend(topleft, top, 160)); + w.DrawRect(r.left, r.top + 1, 1, 1, b2 = Blend(topleft, left, 160)); + w.DrawRect(r.left + 2, r.top, 1, 1, Blend(b1, top)); + w.DrawRect(r.left, r.top + 2, 1, 1, Blend(b2, left)); + topleft = Blend(b1, b2); + + w.DrawRect(r.right - 2, r.top, 1, 1, b1 = Blend(topright, top, 160)); + w.DrawRect(r.right - 1, r.top + 1, 1, 1, b2 = Blend(topright, right, 160)); + w.DrawRect(r.right - 3, r.top, 1, 1, Blend(b1, top)); + w.DrawRect(r.right - 1, r.top + 2, 1, 1, Blend(b2, right)); + topright = Blend(b1, b2); + + w.DrawRect(r.left + 1, r.bottom - 1, 1, 1, b1 = Blend(bottomleft, bottom, 160)); + w.DrawRect(r.left, r.bottom - 2, 1, 1, b2 = Blend(bottomleft, left, 160)); + w.DrawRect(r.left + 2, r.bottom - 1, 1, 1, Blend(b1, bottom)); + w.DrawRect(r.left, r.bottom - 3, 1, 1, Blend(b2, left)); + bottomleft = Blend(b1, b2); + + w.DrawRect(r.right - 2, r.bottom - 1, 1, 1, b1 = Blend(bottomright, bottom, 160)); + w.DrawRect(r.right - 1, r.bottom - 2, 1, 1, b2 = Blend(bottomright, right, 160)); + w.DrawRect(r.right - 3, r.bottom - 1, 1, 1, Blend(b1, bottom)); + w.DrawRect(r.right - 1, r.bottom - 3, 1, 1, Blend(b2, right)); + bottomright = Blend(b1, b2); + + w.DrawRect(r.left + 3, r.top, r.Width() - 6, 1, top); + w.DrawRect(r.left, r.top + 3, 1, r.Height() - 6, left); + w.DrawRect(r.right - 1, r.top + 3, 1, r.Height() - 6, right); + w.DrawRect(r.left + 3, r.bottom - 1, r.Width() - 6, 1, bottom); + + r.Deflate(1, 1); +} + +void DrawXPButton(Draw& w, Rect r, int type) +{ + Color outlight = SColorLight; + Color outshade = Blend(SColorShadow, SColorFace); + Color light = SColorLight; + Color shade = SColorShadow; + Color frame = Blend(SColorHighlight, SColorText); + Color mark = Null; + Color topleft = SColorFace; + int markblend = 0; + + if(type & BUTTON_EDGE) + frame = Blend(SColorHighlight, SColorLight); + + if(type & BUTTON_TOOL) { + frame = SColorDisabled; + light = Blend(SColorFace, light); + } + + if(type & BUTTON_SCROLL) { + outlight = SColorFace; + shade = outshade = SColorFace; + frame = Blend(SColorHighlight, SColorShadow); + } + + switch(type & 15) { + case BUTTON_OK: + mark = Blend(Blue, SColorLight); + markblend = 130; + break; + case BUTTON_HIGHLIGHT: + if(!(type & BUTTON_SCROLL)) { + mark = Blend(Yellow, LtRed, 100); + markblend = 130; + } + break; + case BUTTON_PUSH: + light = shade = Blend(SColorHighlight, SColorFace, 235); + break; + case BUTTON_DISABLED: + frame = SColorDisabled; + outlight = outshade = light = shade = SColorFace; + break; + case BUTTON_CHECKED: + if(type & BUTTON_TOOL) + light = shade = SColorLight; + else + light = shade = Blend(SColorHighlight, SColorFace); + break; + } + + Color topright = topleft; + Color bottomleft = topleft; + Color bottomright = topleft; + + if(type & BUTTON_EDGE) { + DrawFrame(w, r, frame); + light = Blend(frame, SColorLight); + shade = Blend(frame, SColorShadow); + w.DrawRect(r.left, r.top, 1, 1, light); + w.DrawRect(r.right - 1, r.top, 1, 1, light); + w.DrawRect(r.left, r.bottom - 1, 1, 1, light); + w.DrawRect(r.right - 1, r.bottom - 1, 1, 1, light); + r.Deflate(1, 1); + switch(type & 15) { + case BUTTON_HIGHLIGHT: + light = Blend(light, SColorLight); + shade = Blend(shade, SColorLight); + break; + case BUTTON_PUSH: + light = shade = Blend(SColorHighlight, SColorFace); + break; + } + } + else { + if(!(type & BUTTON_TOOL)) + PaintButtonRect(w, r, outshade, outshade, outlight, outlight, topleft, topright, bottomleft, bottomright); + PaintButtonRect(w, r, frame, frame, frame, frame, topleft, topright, bottomleft, bottomright); + Color hc = Blend(light, mark, markblend); + Color sc = Blend(shade, mark, markblend); + PaintButtonRect(w, r, hc, hc, sc, sc, topleft, topright, bottomleft, bottomright); + if(markblend) { + DrawFrame(w, r, Blend(hc, mark, markblend), Blend(sc, mark, markblend)); + r.Deflate(1, 1); + } + } + + if(type & BUTTON_SCROLL) + switch(type & 15) { + case BUTTON_PUSH: + light = shade = Blend(SColorFace, SColorHighlight); + break; + case BUTTON_HIGHLIGHT: + light = shade = Blend(SColorLight, SColorHighlight, 40); + break; + default: + light = Blend(SColorLight, SColorHighlight, 80); + shade = Blend(SColorFace, SColorHighlight, 80); + } + + Color b1 = Blend(light, shade, 80); + Color bs = Blend(shade, SColorFace); + if(type & BUTTON_VERTICAL) { + int wd = r.Width(); + int w1 = 4 * wd / 5; + for(int i = 0; i < wd; i++) + w.DrawRect(r.left + i, r.top, 1, r.Height(), i < w1 ? Blend(light, b1, 255 * i / w1) + : Blend(b1, bs, 255 * (i - w1) / (wd - w1))); + } + else { + int h = r.Height(); + int h1 = 4 * h / 5; + for(int i = 0; i < h; i++) + w.DrawRect(r.left, r.top + i, r.Width(), 1, i < h1 ? Blend(light, b1, 255 * i / h1) + : Blend(b1, bs, 255 * (i - h1) / (h - h1))); + } +} + +#ifdef PLATFORM_WIN32 + +HRGN GetFrameRgn(const Rect& rect, int n) { + HRGN rgn = CreateRectRgnIndirect(rect); + Rect r = rect; + r.Deflate(n); + if(r.Width() > 0 && r.Height() > 0) { + HRGN rgnin = CreateRectRgnIndirect(r); + CombineRgn(rgn, rgn, rgnin, RGN_XOR); + DeleteObject(rgnin); + } + return rgn; +} + +void DrawDragRect(SystemDraw& w, const Rect& _rect1, const Rect& _rect2, const Rect& _clip, int n, Color color, uint64 pattern) +{ + Point o = w.GetOffset(); + Rect rect1 = _rect1 + o; + Rect rect2 = _rect2 + o; + Rect clip = _clip + o; + HDC hdc = w.BeginGdi(); + word wpat[8] = { + (byte)(pattern >> 56), (byte)(pattern >> 48), (byte)(pattern >> 40), (byte)(pattern >> 32), + (byte)(pattern >> 24), (byte)(pattern >> 16), (byte)(pattern >> 8), (byte)(pattern >> 0), + }; + HBITMAP bitmap = CreateBitmap(8, 8, 1, 1, wpat); + HBRUSH brush = ::CreatePatternBrush(bitmap); + DeleteObject(bitmap); + SetTextColor(hdc, color); + SetBkColor(hdc, SColorText()); + Point offset; +#ifdef PLATFORM_WINCE + offset = Point(0, 0); +#else + ::GetViewportOrgEx(hdc, offset); +#endif + HRGN rgn = GetFrameRgn(rect1 + offset, n); + HRGN rgn2 = GetFrameRgn(rect2 + offset, n); + HRGN cliprgn = CreateRectRgnIndirect(clip + offset); + CombineRgn(rgn, rgn, rgn2, RGN_XOR); + CombineRgn(rgn, rgn, cliprgn, RGN_AND); + SelectClipRgn(hdc, rgn); + Rect r; + GetClipBox(hdc, r); + HBRUSH obrush = (HBRUSH) SelectObject(hdc, brush); + PatBlt(hdc, r.left, r.top, r.Width(), r.Height(), PATINVERT); + SelectObject(hdc, obrush); + SelectClipRgn(hdc, NULL); + DeleteObject(rgn); + DeleteObject(rgn2); + DeleteObject(cliprgn); + ReleaseDC(NULL, hdc); + DeleteObject(brush); + w.EndGdi(); +} + +#endif + +#ifdef PLATFORM_X11 + +Vector RectRgn(const Rect& r) +{ + Vector q; + q.Add(r); + return q; +} + +Vector Intersect(const Vector& r1, const Vector& r2) +{ + Vector q; + for(int i = 0; i < r1.GetCount(); i++) + for(int j = 0; j < r2.GetCount(); j++) { + Rect r = r1[i] & r2[j]; + if(!r.IsEmpty()) + q.Add(r); + } + return q; +} + +Vector Subtract(const Vector& r1, const Vector& r2) +{ + Vector q; + bool dummy; + q <<= r1; + for(int i = 0; i < r2.GetCount(); i++) + q = Subtract(q, r2[i], dummy); + return q; +} + + +Vector Xor(const Vector& r1, const Vector& r2) +{ + Vector is = Intersect(r1, r2); + Vector q = Subtract(r1, is); + q.Append(Subtract(r2, is)); + return q; +} + +Vector GetFrameRgn(const Rect& rect, int n) { + Vector q = RectRgn(rect); + q.Add(rect); + Rect r = rect; + r.Deflate(n); + if(r.Width() > 0 && r.Height() > 0) + q = Xor(q, RectRgn(r)); + return q; +} + +void DrawDragRect(SystemDraw& w, const Rect& rect1, const Rect& rect2, const Rect& clip, int n, + Color color, uint64 pattern) +{ + char bd[8]; + for(int i = 0; i < 8; i++) + bd[i] = ~(byte)(pattern >> (8 * (7 - i))); + Pixmap stipple = XCreateBitmapFromData(Xdisplay, w.GetDrawable(), bd, 8, 8); + Point offset = w.GetOffset(); + GC gc = XCreateGC(Xdisplay, w.GetDrawable(), 0, 0); + SetClip(gc, w.GetXftDraw(), + Intersect(Xor(GetFrameRgn(rect1 + offset, n), GetFrameRgn(rect2 + offset, n)), + RectRgn(clip + offset))); + + XGCValues gcv; + gcv.function = X11_ROP2_XOR; + gcv.foreground = GetXPixel(color); + gcv.fill_style = FillStippled; + gcv.stipple = stipple; + XChangeGC(Xdisplay, gc, GCForeground|GCFunction|GCStipple|GCFillStyle, &gcv); + XFillRectangle(Xdisplay, w.GetDrawable(), gc, 0, 0, Xwidth, Xheight); + XFreePixmap(Xdisplay, stipple); +} + +#endif + +static DrawingToPdfFnType sPdf; + +void SetDrawingToPdfFn(DrawingToPdfFnType Pdf) +{ + sPdf = Pdf; +} + +DrawingToPdfFnType GetDrawingToPdfFn() +{ + return sPdf; +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/DrawWin32.cpp b/uppdev/Draw/DrawWin32.cpp new file mode 100644 index 000000000..ff3186cfe --- /dev/null +++ b/uppdev/Draw/DrawWin32.cpp @@ -0,0 +1,476 @@ +#include "Draw.h" + +NAMESPACE_UPP + +#define LLOG(x) // LOG(x) +#define LTIMING(x) // RTIMING(x) + +#ifdef PLATFORM_WIN32 + +static COLORREF sLightGray; + +Size Draw::GetNativeDpi() const +{ + return nativeDpi; +} + +void StaticExitDraw_() +{ + Draw::FreeFonts(); +} + +EXITBLOCK +{ + StaticExitDraw_(); +} + +#ifndef PLATFORM_WINCE +void Add(LOGPALETTE *pal, int r, int g, int b) +{ + pal->palPalEntry[pal->palNumEntries].peRed = min(r, 255); + pal->palPalEntry[pal->palNumEntries].peGreen = min(g, 255); + pal->palPalEntry[pal->palNumEntries].peBlue = min(b, 255); + pal->palPalEntry[pal->palNumEntries++].peFlags = PC_NOCOLLAPSE; +} + +HPALETTE GetQlibPalette() +{ + static HPALETTE hQlibPalette; + if(hQlibPalette) return hQlibPalette; + Draw::InitColors(); + LOGPALETTE *pal = (LOGPALETTE *) new byte[sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)]; + pal->palNumEntries = 0; + pal->palVersion = 0x300; + for(int r = 0; r < 6; r++) + for(int g = 0; g < 6; g++) + for(int b = 0; b < 6; b++) + Add(pal, 255 * r / 5, 255 * g / 5, 255 * b / 5); + for(int q = 0; q <= 16; q++) + Add(pal, 16 * q, 16 * q, 16 * q); + Add(pal, GetRValue(sLightGray), GetGValue(sLightGray), GetBValue(sLightGray)); + hQlibPalette = CreatePalette(pal); + delete[] pal; + return hQlibPalette; +} +#endif + +Draw& GLOBAL_VP(ScreenDraw, ScreenInfo, (true)) + +HDC ScreenHDC() +{ + return ScreenInfo(); +} + +static bool _AutoPalette = true; +bool Draw::AutoPalette() { return _AutoPalette; } +void Draw::SetAutoPalette(bool ap) { _AutoPalette = ap; } + +COLORREF Draw::GetColor(Color c) const { + COLORREF color = c; +#ifdef PLATFORM_WINCE + return color; +#else + if(!palette) + return color; + static Index *SColor; + ONCELOCK { + static Index StaticColor; + StaticColor << RGB(0x00, 0x00, 0x00) << RGB(0x80, 0x00, 0x00) << RGB(0x00, 0x80, 0x00) + << RGB(0x80, 0x80, 0x00) << RGB(0x00, 0x00, 0x80) << RGB(0x80, 0x00, 0x80) + << RGB(0x00, 0x80, 0x80) << RGB(0xC0, 0xC0, 0xC0) << RGB(0xC0, 0xDC, 0xC0) + << RGB(0xA6, 0xCA, 0xF0) << RGB(0xFF, 0xFB, 0xF0) << RGB(0xA0, 0xA0, 0xA4) + << RGB(0x80, 0x80, 0x80) << RGB(0xFF, 0x00, 0x00) << RGB(0x00, 0xFF, 0x00) + << RGB(0xFF, 0xFF, 0x00) << RGB(0x00, 0x00, 0xFF) << RGB(0xFF, 0x00, 0xFF) + << RGB(0x00, 0xFF, 0xFF) << RGB(0xFF, 0xFF, 0xFF); + SColor = &StaticColor; + } + if(color16 || !AutoPalette()) + return GetNearestColor(handle, color); + if(SColor->Find(color) >= 0) + return color; + if(color == sLightGray) + return PALETTEINDEX(216 + 17); + int r = GetRValue(color); + int g = GetGValue(color); + int b = GetBValue(color); + return PALETTEINDEX(r == g && g == b ? (r + 8) / 16 + 216 + : (r + 25) / 51 * 36 + + (g + 25) / 51 * 6 + + (b + 25) / 51); +#endif +} + +void Draw::InitColors() +{ +} + +void Draw::SetColor(Color color) +{ + DrawLock __; + LLOG("SetColor " << color); + if(color != lastColor) { + LLOG("Setting, lastColor:" << FormatIntHex(lastColor.GetRaw()) + << " color:" << FormatIntHex(color.GetRaw()) << + " GetColor:" << FormatIntHex(GetColor(color)) << " palette:" << palette); + HBRUSH oldBrush = actBrush; + HBRUSH h; + if(!IsNull(color)) + h = (HBRUSH) SelectObject(handle, actBrush = CreateSolidBrush(GetColor(color))); + else { + HGDIOBJ empty = GetStockObject(HOLLOW_BRUSH); + h = (HBRUSH) SelectObject(handle, empty); + actBrush = NULL; + } + ASSERT(h); + if(!orgBrush) orgBrush = h; + if(oldBrush) DeleteObject(oldBrush); + lastColor = color; + } +} + +void Draw::SetDrawPen(int width, Color color) { + DrawLock __; + if(IsNull(width)) + width = PEN_NULL; + if(width != lastPen || color != lastPenColor) { + static int penstyle[] = { + PS_NULL, PS_SOLID, PS_DASH, + #ifndef PLATFORM_WINCE + PS_DOT, PS_DASHDOT, PS_DASHDOTDOT + #endif + }; + HPEN oldPen = actPen; + actPen = CreatePen(width < 0 ? penstyle[-width - 1] : PS_SOLID, + width < 0 ? 0 : width, GetColor(color)); + HPEN h = (HPEN) SelectObject(handle, actPen); + if(!orgPen) orgPen = h; + if(oldPen) DeleteObject(oldPen); + lastPen = width; + lastPenColor = color; + } +} + + +void Draw::SetOrg() { + DrawLock __; +#ifdef PLATFORM_WINCE + ::SetViewportOrgEx(handle, actual_offset.x, actual_offset.y, 0); +#else + LLOG("Draw::SetOrg: clip = " << GetClip() << ", offset = " << actual_offset); + ::SetWindowOrgEx(handle, -actual_offset.x, -actual_offset.y, 0); + LLOG("//Draw::SetOrg: clip = " << GetClip()); +#endif +} + +#ifndef PLATFORM_WINCE +Point Draw::LPtoDP(Point p) const { + DrawLock __; + ::LPtoDP(handle, p, 1); + return p; +} + +Point Draw::DPtoLP(Point p) const { + DrawLock __; + ::DPtoLP(handle, p, 1); + return p; +} + +Rect Draw::LPtoDP(const Rect& r) const { + DrawLock __; + Rect w = r; + ::LPtoDP(handle, reinterpret_cast(&w), 2); + return w; +} + +Rect Draw::DPtoLP(const Rect& r) const { + DrawLock __; + Rect w = r; + ::LPtoDP(handle, reinterpret_cast(&w), 2); + return w; +} +#endif + +Size Draw::GetSizeCaps(int i, int j) const { + DrawLock __; + return Size(GetDeviceCaps(handle, i), GetDeviceCaps(handle, j)); +} + +void Draw::DotsMode() +{ + ::SetMapMode(handle, MM_ANISOTROPIC); + ::SetViewportExtEx(handle, nativeDpi.cx, nativeDpi.cy, NULL); + ::SetViewportOrgEx(handle, 0, 0, NULL); + ::SetWindowExtEx(handle, 600, 600, NULL); + ::SetWindowOrgEx(handle, 0, 0, NULL); +} + +void Draw::BeginNative() +{ + if(inchPixels != nativeDpi && ++native == 1) { + ::SetMapMode(handle, MM_TEXT); + actual_offset_bak = actual_offset; + Native(actual_offset); + SetOrg(); + } +} + +void Draw::EndNative() +{ + if(inchPixels != nativeDpi && --native == 0) { + DotsMode(); + actual_offset = actual_offset_bak; + SetOrg(); + } +} + +void Draw::LoadCaps() { + DrawLock __; + color16 = false; + palette = (GetDeviceCaps(handle, RASTERCAPS) & RC_PALETTE); + if(palette) + color16 = GetDeviceCaps(handle, SIZEPALETTE) != 256; + pageDots = pagePixels = GetSizeCaps(HORZRES, VERTRES); + pageMMs = GetSizeCaps(HORZSIZE, VERTSIZE); + nativeDpi = inchPixels = GetSizeCaps(LOGPIXELSX, LOGPIXELSY); + sheetPixels = GetSizeCaps(PHYSICALWIDTH, PHYSICALHEIGHT); + pageOffset = GetSizeCaps(PHYSICALOFFSETX, PHYSICALOFFSETY); + is_mono = GetDeviceCaps(handle, BITSPIXEL) == 1 && GetDeviceCaps(handle, PLANES) == 1; +} + +void Draw::SetDevice(const char *s) { + DrawLock __; + static Index map; + device = map.FindAdd(s) + 1; + LoadCaps(); +} + +void Draw::Cinit() { + DrawLock __; + lastColor = Color::FromCR(COLORREF(-5)); + lastPenColor = Color::FromCR(COLORREF(-5)); + lastTextColor = COLORREF(-1); + lastPen = Null; + actBrush = orgBrush = NULL; + actPen = orgPen = NULL; + orgFont = NULL; + lastFont.Clear(); +} + +void Draw::Init() { + DrawLock __; + Cinit(); + SetBkMode(handle, TRANSPARENT); + ::SetTextAlign(handle, TA_BASELINE); +#ifdef PLATFORM_WINCE + actual_offset = Point(0, 0); +#else + ::GetViewportOrgEx(handle, actual_offset); +#endif + LoadCaps(); +} + +void Draw::Reset() { + DrawLock __; + device = 0; + pixels = true; + printer = aborted = backdraw = is_mono = false; +} + +Draw::Draw() { + DrawLock __; + native = 0; + InitColors(); + InitFonts(); + actual_offset = Point(0, 0); + Reset(); + handle = NULL; +} + +Draw::Draw(HDC hdc) { + DrawLock __; + native = 0; + InitColors(); + InitFonts(); + Reset(); + Attach(hdc); +} + +void Draw::Unselect0() { + DrawLock __; + if(orgPen) SelectObject(handle, orgPen); + if(orgBrush) SelectObject(handle, orgBrush); + if(orgFont) SelectObject(handle, orgFont); + if(actPen) DeleteObject(actPen); + if(actBrush) DeleteObject(actBrush); + Cinit(); +} + +void Draw::Unselect() { + DrawLock __; + while(cloff.GetCount()) + End(); + Unselect0(); +} + +Draw::~Draw() { + DrawLock __; + if(handle) + Unselect(); +} + +HDC Draw::BeginGdi() { + DrawLock __; + Begin(); + return handle; +} + +void Draw::EndGdi() { + DrawLock __; + Unselect0(); + End(); +} + +NilDraw::NilDraw() { + DrawLock __; + Attach(ScreenInfo().GetHandle()); + pixels = false; + cloff.Clear(); +} + +NilDraw::~NilDraw() { + DrawLock __; + Detach(); +} + +void BackDraw::Create(Draw& w, int cx, int cy) { + ASSERT(w.GetHandle()); + DrawLock __; + Destroy(); + size.cx = cx; + size.cy = cy; + hbmp = ::CreateCompatibleBitmap(w.GetHandle(), cx, cy); + handle = ::CreateCompatibleDC(w.GetHandle()); + ASSERT(hbmp); + ASSERT(handle); +#ifndef PLATFORM_WINCE + if(w.PaletteMode() && AutoPalette()) { + ::SelectPalette(handle, GetQlibPalette(), FALSE); + ::RealizePalette(handle); + } +#endif + hbmpold = (HBITMAP) ::SelectObject(handle, hbmp); + Init(); + backdraw = true; +} + +void BackDraw::Put(Draw& w, int x, int y) { + DrawLock __; + ASSERT(handle); + LTIMING("BackDraw::Put"); +#ifdef PLATFORM_WINCE + ::SetViewportOrgEx(handle, 0, 0, 0); +#else + ::SetWindowOrgEx(handle, 0, 0, NULL); +#endif + ::BitBlt(w, x, y, size.cx, size.cy, *this, 0, 0, SRCCOPY); +} + +void BackDraw::Destroy() { + DrawLock __; + if(handle) { + Unselect(); + ::SelectObject(handle, hbmpold); + ::DeleteDC(handle); + ::DeleteObject(hbmp); + handle = NULL; + } +} + +ScreenDraw::ScreenDraw(bool ic) { + DrawLock __; +#ifdef PLATFORM_WINCE + Attach(CreateDC(NULL, NULL, NULL, NULL)); +#else + Attach((ic ? CreateIC : CreateDC)("DISPLAY", NULL, NULL, NULL)); + if(PaletteMode() && AutoPalette()) { + SelectPalette(handle, GetQlibPalette(), TRUE); + RealizePalette(handle); + } +#endif +} + +ScreenDraw::~ScreenDraw() { + DrawLock __; + Unselect(); + DeleteDC(handle); +} + +#ifndef PLATFORM_WINCE + +void PrintDraw::InitPrinter() +{ + DrawLock __; + Init(); + printer = true; + pixels = false; + nativeDpi = inchPixels; + DotsMode(); + native = 0; + actual_offset = Point(0, 0); + pageDots.cx = 600 * pagePixels.cx / inchPixels.cx; + pageDots.cy = 600 * pagePixels.cy / inchPixels.cy; + inchPixels.cx = 600; + inchPixels.cy = 600; +} + +void PrintDraw::StartPage() +{ + DrawLock __; + if(IsAborted()) return; + Unselect(); + if(::StartPage(handle) <= 0) + Abort(); + else + InitPrinter(); +} + +void PrintDraw::EndPage() +{ + DrawLock __; + if(IsAborted()) return; + Unselect(); + ASSERT(printer); + if(::EndPage(handle) <= 0) + Abort(); +} + +PrintDraw::PrintDraw(HDC hdc, const char *docname) + : Draw(hdc) +{ + DrawLock __; + DOCINFO di; + memset(&di, 0, sizeof(di)); + di.cbSize = sizeof(di); + String sys_docname = ToSystemCharset(docname); + di.lpszDocName = ~sys_docname; + if(::StartDoc(hdc, &di) <= 0) { + Abort(); + return; + } + InitPrinter(); +} + +PrintDraw::~PrintDraw() { + DrawLock __; + if(IsAborted()) + ::AbortDoc(handle); + else + ::EndDoc(handle); + DeleteDC(handle); + handle = NULL; +} +#endif + +#endif + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/DrawWin32.h b/uppdev/Draw/DrawWin32.h new file mode 100644 index 000000000..96ce81469 --- /dev/null +++ b/uppdev/Draw/DrawWin32.h @@ -0,0 +1,234 @@ +#ifdef PLATFORM_WIN32 + +class SystemDraw : public Draw { +public: + virtual dword GetInfo() const; + virtual Size GetPagePixels() const; + + virtual void StartPage(); + virtual void EndPage(); + + virtual void BeginOp(); + virtual void EndOp(); + virtual void OffsetOp(Point p); + virtual bool ClipOp(const Rect& r); + virtual bool ClipoffOp(const Rect& r); + virtual bool ExcludeClipOp(const Rect& r); + virtual bool IntersectClipOp(const Rect& r); + virtual bool IsPaintingOp(const Rect& r) const; + + virtual void DrawRectOp(int x, int y, int cx, int cy, Color color); + virtual void DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color); + virtual void DrawDataOp(int x, int y, int cx, int cy, const String& data, const char *id); + virtual void DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color); + + virtual void DrawPolyPolylineOp(const Point *vertices, int vertex_count, + const int *counts, int count_count, + int width, Color color, Color doxor); + virtual void DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int scc, + const int *disjunct_polygon_counts, int dpcc, + Color color, int width, Color outline, + uint64 pattern, Color doxor); + virtual void DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color); + + virtual void DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor); + virtual void DrawTextOp(int x, int y, int angle, const wchar *text, Font font, + Color ink, int n, const int *dx); + virtual void DrawDrawingOp(const Rect& target, const Drawing& w); + virtual void DrawPaintingOp(const Rect& target, const Painting& w); + + virtual Size GetNativeDpi() const; + virtual void BeginNative(); + virtual void EndNative(); + + virtual int GetCloffLevel() const; + +private: + dword style; + Size pagePixels; + Size nativeDpi; + + SystemDraw(); + + friend class ImageDraw; + friend class FontInfo; + friend class Font; + + friend void StaticExitDraw_(); + + FontInfo lastFont; + + Point actual_offset; + Point actual_offset_bak; + + struct Cloff : Moveable { + Point org; + HRGN hrgn; + Rect drawingclip; + }; + + Array cloff; + Rect drawingclip; + + HDC handle; + COLORREF lastTextColor; + Color lastColor; + HBRUSH orgBrush; + HBRUSH actBrush; + HFONT orgFont; + HPEN orgPen; + HPEN actPen; + int lastPen; + Color lastPenColor; + + void Unselect0(); + void Cinit(); + void Init(); + + void LoadCaps(); + void SetDevice(const char *devicename); + void SetPrinterMode(); + void Reset(); + void SetOrg(); + friend HPALETTE GetQlibPalette(); + void DotsMode(); + +public: + static bool AutoPalette(); + + static void Flush() { GdiFlush(); } + + bool IsMetaFile() const { return device == -1; } + + COLORREF GetColor(Color color) const; + +#ifndef PLATFORM_WINCE + Point LPtoDP(Point p) const; + Point DPtoLP(Point p) const; + Rect LPtoDP(const Rect& r) const; + Rect DPtoLP(const Rect& r) const; +#endif + + void SetColor(Color color); + void SetFont(Font font, int angle = 0); + void SetDrawPen(int width, Color color); + + Size GetSizeCaps(int i, int j) const; + HDC BeginGdi(); + void EndGdi(); + HDC GetHandle() { return handle; } + operator HDC() const { return handle; } + void Unselect(); + void Attach(HDC ahandle) { handle = ahandle; Init(); } + HDC Detach() { Unselect(); HDC h = handle; handle = NULL; return h; } + + SystemDraw(HDC hdc); + virtual ~SystemDraw(); +}; + +#ifndef PLATFORM_WINCE +class WinMetaFile { + Size size; + mutable HENHMETAFILE hemf; + + void ChkP() const { ASSERT(!IsPicked()); } + void Init(); + void Pick(pick_ WinMetaFile& src); + void Copy(const WinMetaFile& src); + +public: + void Attach(HENHMETAFILE emf); + HENHMETAFILE *Detach(); + + bool IsPicked() const { return (uintptr_t) hemf == 0xffffffff; } + + operator bool() const { ChkP(); return hemf; } + Size GetSize() const { ChkP(); return hemf ? size : Size(0, 0); } + + void Clear(); + + void Paint(Draw& w, const Rect& r) const; + void Paint(Draw& w, int x, int y, int cx, int cy) const; + + void Serialize(Stream& s); + + void ReadClipboard(); + void WriteClipboard() const; + bool Load(const char *file); + + WinMetaFile() { Init(); } + WinMetaFile(HENHMETAFILE hemf); + WinMetaFile(HENHMETAFILE hemf, Size sz); + WinMetaFile(const char *file); + + WinMetaFile(pick_ WinMetaFile& src) { Pick(src); } + WinMetaFile(const WinMetaFile& src, int) { Copy(src); } + void operator=(pick_ WinMetaFile& src) { Clear(); Pick(src); } + void operator<<=(const WinMetaFile& src) { Clear(); Copy(src); } + + ~WinMetaFile() { Clear(); } + + HENHMETAFILE GetHEMF() const { ChkP(); return hemf; } +}; + +class WinMetaFileDraw : public Draw { + Size size; + +public: + bool Create(HDC hdc, int cx, int cy, const char *app = NULL, const char *name = NULL, const char *file = NULL); + bool Create(int cx, int cy, const char *app = NULL, const char *name = NULL, const char *file = NULL); + WinMetaFile Close(); + + WinMetaFileDraw() {} + WinMetaFileDraw(HDC hdc, int cx, int cy, const char *app = NULL, const char *name = NULL, const char *file = NULL); + WinMetaFileDraw(int cx, int cy, const char *app = NULL, const char *name = NULL, const char *file = NULL); + ~WinMetaFileDraw(); +}; +#endif + +class ScreenDraw : public Draw { +public: + ScreenDraw(bool ic = false); + ~ScreenDraw(); +}; + +#ifndef PLATFORM_WINCE +class PrintDraw : public Draw { +public: + virtual void StartPage(); + virtual void EndPage(); + +private: + void InitPrinter(); +public: + PrintDraw(HDC hdc, const char *jobname); + ~PrintDraw(); +}; +#endif + +inline bool BitBlt(HDC ddc, Point d, HDC sdc, const Rect& s, dword rop = SRCCOPY) +{ return BitBlt(ddc, d.x, d.y, s.Width(), s.Height(), sdc, s.left, s.top, rop); } + +inline bool StretchBlt(HDC ddc, const Rect& r, HDC sdc, const Rect& s, dword rop = SRCCOPY) +{ return StretchBlt(ddc, r.left, r.top, r.Width(), r.Height(), sdc, s.left, s.top, s.Width(), s.Height(), rop); } + +inline bool PatBlt(HDC dc, const Rect& r, dword rop = PATCOPY) +{ return PatBlt(dc, r.left, r.top, r.Width(), r.Height(), rop); } + +inline void MoveTo(HDC hdc, Point pt) { MoveToEx(hdc, pt.x, pt.y, 0); } +inline void LineTo(HDC hdc, Point pt) { LineTo(hdc, pt.x, pt.y); } + +inline void DrawLine(HDC hdc, Point p, Point q) { MoveTo(hdc, p); LineTo(hdc, q); } +inline void DrawLine(HDC hdc, int px, int py, int qx, int qy) { MoveToEx(hdc, px, py, 0); LineTo(hdc, qx, qy); } + +#ifndef PLATFORM_WINCE +inline void DrawArc(HDC hdc, const Rect& rc, Point p, Point q){ Arc(hdc, rc.left, rc.top, rc.right, rc.bottom, p.x, p.y, q.x, q.y); } +#endif +inline void DrawCircle(HDC hdc, int x, int y, int radius) { Ellipse(hdc, x - radius, y - radius, x + radius + 1, y + radius + 1); } +inline void DrawCircle(HDC hdc, Point centre, int radius) { DrawCircle(hdc, centre.x, centre.y, radius); } +inline void DrawEllipse(HDC hdc, const Rect& rc) { Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom); } + +inline void DrawRect(HDC hdc, const Rect& rc) { Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom); } + +#endif diff --git a/uppdev/Draw/DrawX11.cpp b/uppdev/Draw/DrawX11.cpp new file mode 100644 index 000000000..42ca7599d --- /dev/null +++ b/uppdev/Draw/DrawX11.cpp @@ -0,0 +1,445 @@ +#include "Draw.h" + +#ifdef PLATFORM_X11 + +#define Time XTime +#define Font XFont +#define Display XDisplay +#define Picture XPicture + +#ifndef flagNOGTK +#include +#include +#include +#endif + +#undef Picture +#undef Time +#undef Font +#undef Display + +NAMESPACE_UPP + +#define LLOG(x) //LOG(x) +#define LTIMING(x) //TIMING(x) + +XDisplay *Xdisplay; +int Xscreenno; +Visual *Xvisual; +Window Xroot; +Screen *Xscreen; +Colormap Xcolormap; +int Xheight; +int Xwidth; +int XheightMM; +int XwidthMM; +int Xdepth; +dword Xblack; +dword Xwhite; +int Xconnection; +byte *Xmapcolor; +byte *Xunmapcolor; + +dword (*Xgetpixel)(int r, int g, int b); + +void StaticExitDraw_() +{ + Draw::FreeFonts(); +} + +EXITBLOCK +{ + if(Xdisplay) { + StaticExitDraw_(); +// No CloseDisplay for now... + XCloseDisplay(Xdisplay); + LLOG("Xdisplay closed"); + Xdisplay = NULL; + } + if(Xmapcolor) + delete[] Xmapcolor; + if(Xunmapcolor) + delete[] Xunmapcolor; +} + +void XError() +{ + Panic("X11 error !"); +} + +void XError(const char *s) +{ + Panic(String("X11 error:") + s + " !"); +} + +static int sAcs; + +bool sAllocColor(int xr, int xg, int xb) +{ + XColor ce; + ce.red = xr; + ce.green = xg; + ce.blue = xb; + ce.flags = DoRed | DoGreen | DoBlue; + if(!XAllocColor(Xdisplay, Xcolormap, &ce)) return false; + sAcs++; + return sAcs < 257; +} + +void sAllocColors() +{ + int r, g, b; + for(r = 0; r < 2; r++) + for(g = 0; g < 2; g++) + for(b = 0; b < 2; b++) + if(!sAllocColor(65535 * r, 65535 * g, 65535 * b)) return; + for(r = 0; r < 3; r++) + for(g = 0; g < 3; g++) + for(b = 0; b < 3; b++) + if((r == 1 || g == 1 || b == 1) && + !sAllocColor((65535 * r) / 2, (65535 * g) / 2, (65535 * b) / 2)) return; + for(r = 5; r >= 0; r--) + for(g = 5; g >= 0; g--) + for(b = 5; b >= 0; b--) + if((r != 0 && r != 5 || g != 0 && g != 5 || b != 0 && b != 5) && + !sAllocColor((65535 * r) / 5, (65535 * g) / 5, (65535 * b) / 5)) return; + for(r = 1; r <= 11; r += 2) + if(!sAllocColor((65535 * r) / 11, (65535 * r) / 11, (65535 * r) / 11)) return; + for(int r = 255; r >= 0; r--) + if(!sAllocColor(r << 8, r << 8, r << 8)) return; +} + +dword GetPseudoColorPixel(int r, int g, int b) +{ + return Xmapcolor[r * 11 / 255 * (24 * 12) + g * 23 / 255 * 12 + b * 11 / 255]; +} + +static +struct Xshift { + dword mask; + int bits; + int shift; + dword Do(int c) { return (c >> bits << shift) & mask; } +} +Xred, Xgreen, Xblue; + +Xshift CalcXShift(dword mask) +{ + Xshift f; + f.mask = mask; + f.shift = 0; + f.bits = 0; + while((mask & 1) == 0) { + mask >>= 1; + f.shift++; + } + while((mask & 1) == 1) { + mask >>= 1; + f.bits++; + } + f.bits = 8 - f.bits; + if(f.bits < 0) { + f.shift += f.bits; + f.bits = 0; + } + LLOG("xshift(" << FormatIntHex(mask) << "): mask = " + << FormatIntHex(f.mask) << ", bits = " << f.bits << ", shift = " << f.shift); + return f; +} + +dword GetTrueColorPixel(int r, int g, int b) +{ + return Xred.Do(r) | Xgreen.Do(g) | Xblue.Do(b); +} + +inline int ssq(int x) { return x * x; } + +void InitX11Draw(XDisplay *display) +{ + Xdisplay = display; + if(!Xdisplay) { + puts(NFormat("No X11 display, errno = %d, %s", errno, strerror(errno))); + fflush(stdout); + XError(); + } + int Xscreenno = DefaultScreen(Xdisplay); + Xroot = RootWindow(Xdisplay, Xscreenno); + Xscreen = ScreenOfDisplay(Xdisplay, Xscreenno); + Xcolormap = DefaultColormap(Xdisplay, Xscreenno); +// Xcolormap = (Colormap)GDK().gdk_x11_colormap_get_xcolormap(GDK().gdk_rgb_get_colormap()); + Xheight = DisplayHeight(Xdisplay, Xscreenno); + Xwidth = DisplayWidth(Xdisplay, Xscreenno); + XheightMM = DisplayHeightMM(Xdisplay, Xscreenno); + XwidthMM = DisplayWidthMM(Xdisplay, Xscreenno); + LLOG("Xwidth = " << Xwidth << ", XwidthMM = " << XwidthMM); + LLOG("Xheight = " << Xheight << ", XheightMM = " << XheightMM); + Xdepth = DefaultDepth(Xdisplay, Xscreenno); + Xblack = BlackPixel(Xdisplay, 0); + Xwhite = WhitePixel(Xdisplay, 0); + Xconnection = XConnectionNumber(Xdisplay); + Xvisual = DefaultVisual(Xdisplay, Xscreenno); + Visual *v = Xvisual; + if(v->c_class == TrueColor) { + Xred = CalcXShift(v->red_mask); + Xgreen = CalcXShift(v->green_mask); + Xblue = CalcXShift(v->blue_mask); + Xgetpixel = GetTrueColorPixel; + } + else { + sAllocColors(); + int colorcount = max(1 << Xdepth, 256); + Buffer cs(colorcount); + int i; + for(i = 0; i < colorcount; i++) + cs[i].pixel = i; + XQueryColors(Xdisplay, Xcolormap, cs, colorcount); + Xunmapcolor = new byte[3 * colorcount]; + for(i = 0; i < colorcount; i++) + { + Xunmapcolor[3 * i + 0] = cs[i].blue; + Xunmapcolor[3 * i + 1] = cs[i].green; + Xunmapcolor[3 * i + 2] = cs[i].red; + } + byte *cm = Xmapcolor = new byte[12 * 24 * 12]; + for(int r = 0; r < 12; r++) + for(int g = 0; g < 24; g++) + for(int b = 0; b < 12; b++) { + int mind = INT_MAX; + int mini; + for(int i = 0; i < colorcount; i++) { + int d = ssq(r * 255 / 11 - (cs[i].red >> 8)) + + ssq(g * 255 / 23 - (cs[i].green >> 8)) + + ssq(b * 255 / 11 - (cs[i].blue >> 8)); + if(d < mind) { + mini = i; + mind = d; + } + } + *cm++ = mini; + } + Xgetpixel = GetPseudoColorPixel; + } +// XFree(v); + + Draw::SetStdFont(ScreenSans(12)); +} + +void InitX11Draw(const char *dispname) +{ +#ifdef flagNOGTK + if(!dispname || !*dispname) { + int f = Environment().Find("DISPLAY"); + dispname = (f >= 0 ? ~Environment()[f] : ":0.0"); + } + InitX11Draw(XOpenDisplay(dispname)); +#else + MemoryIgnoreLeaksBlock __; + const Vector& cmd = CommandLine(); + char **argv = (char**) MemoryAllocPermanent(sizeof(char *) * cmd.GetCount()); + for(int i = 0; i < cmd.GetCount(); i++) + argv[i] = PermanentCopy(cmd[i]); + int argc = cmd.GetCount(); + gtk_init (&argc, &argv); + GtkWidget *w = gtk_window_new(GTK_WINDOW_TOPLEVEL); + GdkDisplay *d = gtk_widget_get_display(w); + gdk_x11_display_get_xdisplay(d); + InitX11Draw(gdk_x11_display_get_xdisplay(d)); + gtk_widget_destroy(w); +#endif +} + +void SetClip(GC gc, XftDraw *xftdraw, const Vector& cl) +{ + DrawLock __; + LTIMING("SetClip"); + Buffer xr(cl.GetCount()); + LLOG("SetClip"); + for(int i = 0; i < cl.GetCount(); i++) { + XRectangle& r = xr[i]; + const Rect& cr = cl[i]; + LLOG("[" << i << "] = " << cr); + r.x = cr.left; + r.y = cr.top; + r.width = cr.Width(); + r.height = cr.Height(); + } + XSetClipRectangles(Xdisplay, gc, 0, 0, xr, cl.GetCount(), Unsorted); + LLOG("XftDrawSetClipRectangles, # = " << cl.GetCount() << ", xftdraw = " << FormatIntHex(xftdraw)); + XftDrawSetClipRectangles(xftdraw, 0, 0, xr, cl.GetCount()); + LLOG("//XftDrawSetClipRectangles"); +} + +void Draw::CloneClip() +{ + if(cloff.GetCount() > 1 && cloff.Top().clipi == cloff[cloff.GetCount() - 2].clipi) { + cloff.Top().clipi = clip.GetCount(); + Vector& c = clip.Add(); + c <<= clip[clip.GetCount() - 2]; + } +} + +void Draw::SetForeground(Color color) +{ + DrawLock __; + LTIMING("SetForeground"); + if(IsDrawing()) return; + int p = GetXPixel(color.GetR(), color.GetG(), color.GetB()); + if(p == foreground) return; + LTIMING("XSetForeground"); + LLOG("XSetForeground " << color); + foreground = p; + XSetForeground(Xdisplay, gc, foreground); +} + +void Draw::SetClip() { + DrawLock __; + if(IsDrawing() || dw == Xroot) return; + LTIMING("SetClip"); + UPP::SetClip(gc, xftdraw, clip.Top()); +} + +void Draw::SetLineStyle(int width) +{ + DrawLock __; + if(IsDrawing()) return; + if(width == linewidth) return; + linewidth = width; + if(IsNull(width)) + width = 1; + if(width < PEN_SOLID) { + static const char dash[] = { 18, 6 }; + static const char dot[] = { 3, 3 }; + static const char dashdot[] = { 9, 6, 3, 6 }; + static const char dashdotdot[] = { 9, 3, 3, 3, 3, 3 }; + static struct { + const char *dash; + int len; + } ds[] = { + { dash, __countof(dash) }, + { dot, __countof(dot) }, + { dashdot, __countof(dashdot) }, + { dashdotdot, __countof(dashdotdot) } + }; + int i = -(width - PEN_DASH); + ASSERT(i >= 0 && i < 4); + XSetDashes(Xdisplay, gc, 0, ds[i].dash, ds[i].len); + } + XSetLineAttributes(Xdisplay, gc, max(width, 1), + width < PEN_SOLID ? LineOnOffDash : LineSolid, CapRound, JoinRound); +} + +void Draw::Init() +{ + DrawLock __; + pageDots = pagePixels = Size(Xwidth, Xheight); + pageMMs = Size(XwidthMM, XheightMM); + nativeDpi = inchPixels = 254 * pagePixels / pageMMs / 10; + sheetPixels = pagePixels; + pageOffset = Point(0, 0); + InitFonts(); + cloff.Clear(); + clip.Clear(); + foreground = linewidth = Null; + device = 0; + device = 0; + pixels = true; + printer = aborted = backdraw = is_mono = false; + native = 0; +} + +void Draw::Init(const Vector& _clip, Point _offset) +{ + DrawLock __; + Init(); + clip.Add() <<= _clip; + offset.Add(_offset); + actual_offset = _offset; + Cloff& f = cloff.Add(); + f.offseti = 0; + f.clipi = 0; + SetClip(); +} + +Draw::Draw() +{ + DrawLock __; + dw = None; + gc = None; + actual_offset = Point(0, 0); + Init(); +} + +void Draw::BeginNative() {} + +void Draw::EndNative() {} + + +Draw::Draw(Drawable _dw, GC _gc, XftDraw *_xftdraw, const Vector& _clip) +{ + LLOG("Draw"); + dw = _dw; + gc = _gc; + xftdraw = _xftdraw; + Init(_clip); +} + +Draw::~Draw() +{ +} + +void BackDraw::Create(Draw& w, int cx, int cy) +{ + DrawLock __; + LLOG("Creating BackDraw " << cx << "x" << cy); + Destroy(); + size.cx = cx; + size.cy = cy; + dw = XCreatePixmap(Xdisplay, w.GetDrawable(), max(cx, 1), max(cy, 1), Xdepth); + gc = XCreateGC(Xdisplay, dw, 0, 0); + xftdraw = XftDrawCreate(Xdisplay, (Drawable) dw, + DefaultVisual(Xdisplay, Xscreenno), Xcolormap); + Vector clip; + clip.Add(RectC(0, 0, cx, cy)); + Init(clip, Point(0, 0)); + backdraw = true; +} + +void BackDraw::Put(Draw& w, int x, int y) +{ + DrawLock __; + LLOG("Putting BackDraw"); + ASSERT(dw != None); + XCopyArea(Xdisplay, dw, w.GetDrawable(), w.GetGC(), 0, 0, size.cx, size.cy, + x + w.GetOffset().x, y + w.GetOffset().y); +} + +void BackDraw::Destroy() +{ + DrawLock __; + if(dw != None) { + XftDrawDestroy(xftdraw); + XFreePixmap(Xdisplay, dw); + XFreeGC(Xdisplay, gc); + } +} + +NilDraw::NilDraw() +{ + DrawLock __; + dw = Xroot; + gc = XCreateGC(Xdisplay, Xroot, 0, 0); + pixels = false; + Init(Vector()); +} + +NilDraw::~NilDraw() +{ + DrawLock __; + XFreeGC(Xdisplay, gc); +} + +Draw& ScreenInfo() { return Single(); } + +END_UPP_NAMESPACE + +#endif diff --git a/uppdev/Draw/DrawX11.h b/uppdev/Draw/DrawX11.h new file mode 100644 index 000000000..3c126d8d1 --- /dev/null +++ b/uppdev/Draw/DrawX11.h @@ -0,0 +1,754 @@ +#ifdef PLATFORM_X11 + +class Draw { +protected: + bool palette:1; + bool color16:1; + bool printer:1; + bool pixels:1; + bool aborted:1; + bool backdraw:1; + bool is_mono:1; + + static bool sFini; + + enum { LRU, HASH }; + static FontInfo::Data *GetFontHash(int hash); + static FontInfo::Data *GetFontLru(); + static int FontCached; + + static bool StdFontSizeSet; + static Size StdFontSize; + static Font AStdFont; + + typedef Link FontLink; + + Size pageDots; + Size pagePixels; + Size pageMMs; + Size inchPixels; + Size nativeDpi; + Size sheetPixels; + Point pageOffset; + int native; + + Draw(); + + friend class BackRectDraw; + friend class ImageDraw; + friend class FontInfo; + friend class Font; + + friend void StaticExitDraw_(); + friend Font StdFont(); + + static void InitColors(); + static void InitFonts(); + static void FreeFonts(); + static void Release(FontInfo::Data *font); + + int device; + FontInfo lastFont; + + Point actual_offset; + Point actual_offset_bak; + struct Cloff : Moveable { + Point org; + #ifdef PLATFORM_WIN32 + HRGN hrgn; + #endif + #ifdef PLATFORM_X11 + int clipi; + int offseti; + #endif + Rect drawingclip; + }; + Array cloff; + Rect drawingclip; + + static void InitPlatformFonts(); + + enum FontHashConst { FONTHASH = 97 }; + + void ComposeText(int x, int y, int angle, const wchar *text, Font font, Color ink, + int n, const int *dx); + + +#ifdef PLATFORM_WIN32 + static int CALLBACK AddFace(const LOGFONT *logfont, const TEXTMETRIC *, dword type, + LPARAM param); + static int EnumFace(HDC hdc, const char *face); + static void ForceFace(HDC hdc, const char *face, const char *aface); + static void Win32__InitColors(); + static FontInfo Acquire(Font font, HDC hdc, int angle, int device); + + HDC handle; + COLORREF lastTextColor; + Color lastColor; + HBRUSH orgBrush; + HBRUSH actBrush; + HFONT orgFont; + HPEN orgPen; + HPEN actPen; + int lastPen; + Color lastPenColor; + + void Unselect0(); + void Cinit(); + void Init(); + + void LoadCaps(); + void SetDevice(const char *devicename); + void SetPrinterMode(); + void Reset(); + void SetOrg(); + friend HPALETTE GetQlibPalette(); + void DotsMode(); + + + static const char *FontScreenSans; + static const char *FontScreenSerif; + static const char *FontScreenFixed; + static const char *FontRoman; + static const char *FontArial; + static const char *FontCourier; + static const char *FontSymbol; + static const char *FontWingdings; + static const char *FontTahoma; + +public: + static bool AutoPalette(); + static void SetAutoPalette(bool ap); + +#endif + +#ifdef PLATFORM_X11 + static int AddFonts(const char *xlfd_pattern, int count); + static FontInfo Acquire(Font font, int angle, int device); + + Vector< Vector > clip; + Vector offset; + + Drawable dw; + GC gc; + XftDraw *xftdraw; + + int foreground; + int linewidth; + + void Init(); + void Init(const Vector& clip, Point offset = Point(0, 0)); + void CloneClip(); +#endif + + enum { + BEGIN = 1, + OFFSET = 2, + CLIP = 3, + CLIPOFF = 4, + EXCLUDECLIP = 5, + INTERSECTCLIP = 6, + END = 7, + DRAWRECT = 8, + DRAWIMAGE = 9, + DRAWMONOIMAGE = 10, + DRAWDRAWING = 11, + DRAWLINE = 12, + DRAWELLIPSE = 13, + DRAWTEXT = 14, + DRAWARC = 15, + DRAWPOLYPOLYLINE = 16, + DRAWPOLYPOLYPOLYGON = 17, + DRAWDATA = 18, + DRAWPAINTING = 19, + }; + + struct DrawingPos; + +public: + static int FontCacheMax; + + static void SinCos(int angle, double& sina, double& cosa); + + static void SetStdFont(Font font); + static Font GetStdFont(); + static Size GetStdFontSize(); + static int GetStdFontCy() { return GetStdFontSize().cy; } + +#ifdef PLATFORM_WIN32 +#ifdef PLATFORM_WINCE + static void Flush() {} +#else + static void Flush() { GdiFlush(); } +#endif +#endif +#ifdef PLATFORM_X11 + static void Flush() { XSync(Xdisplay, false); } +#endif + + bool PaletteMode() const { return palette; } + bool IsMono() const { return is_mono; } + + Size GetPagePixels() const { return native ? pagePixels : pageDots; } + Size GetPixelsPerInch() const { return native ? nativeDpi : inchPixels; } + Size GetPageMMs() const { return pageMMs; } + + bool Pixels() const { return pixels; } + bool Dots() const { return !pixels; } + bool IsNative() const { return native; } + + void BeginNative(); + void EndNative(); + Size GetNativeDpi() const; + int GetNativeX(int x) const; + int GetNativeY(int x) const; + void Native(int& x, int& y) const; + void Native(Point& p) const; + void Native(Size& sz) const; + void Native(Rect& r) const; + + bool IsPrinter() const { return printer; } + bool IsAborted() const { return aborted; } + bool IsBack() const { return backdraw; } +#ifdef PLATFORM_WIN32 + bool IsSystem() const { return handle; } +#endif +#ifdef PLATFORM_X11 + bool IsSystem() const { return gc != None; } +#endif + bool IsDrawing() const; + + virtual dword GetInfo() const; + virtual Size GetPagePixels() const; + + virtual void StartPage(); + virtual void EndPage(); + + virtual void BeginOp(); + virtual void EndOp(); + virtual void OffsetOp(Point p); + virtual bool ClipOp(const Rect& r); + virtual bool ClipoffOp(const Rect& r); + virtual bool ExcludeClipOp(const Rect& r); + virtual bool IntersectClipOp(const Rect& r); + virtual Rect GetClipOp() const; + virtual bool IsPaintingOp(const Rect& r) const; + + virtual void DrawRectOp(int x, int y, int cx, int cy, Color color); + virtual void DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color); + virtual void DrawDataOp(int x, int y, int cx, int cy, const String& data, const char *id); + virtual void DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color); + +#ifndef PLATFORM_WINCE + virtual void DrawPolyPolylineOp(const Point *vertices, int vertex_count, + const int *counts, int count_count, + int width, Color color, Color doxor); + virtual void DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int scc, + const int *disjunct_polygon_counts, int dpcc, + Color color, int width, Color outline, + uint64 pattern, Color doxor); + virtual void DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color); +#endif + virtual void DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor); + virtual void DrawTextOp(int x, int y, int angle, const wchar *text, Font font, + Color ink, int n, const int *dx); + virtual void DrawDrawingOp(const Rect& target, const Drawing& w); + virtual void DrawPaintingOp(const Rect& target, const Painting& w); + + void Begin() { BeginOp(); } + void End() { EndOp(); } + void Offset(Point p) { OffsetOp(p); } + void Offset(int x, int y); + bool Clip(const Rect& r) { return ClipOp(r); } + bool Clip(int x, int y, int cx, int cy); + bool Clipoff(const Rect& r) { return ClipoffOp(r); } + bool Clipoff(int x, int y, int cx, int cy); + bool ExcludeClip(const Rect& r) { return ExcludeClipOp(r); } + bool ExcludeClip(int x, int y, int cx, int cy); + bool IntersectClip(const Rect& r) { return IntersectClipOp(r); } + bool IntersectClip(int x, int y, int cx, int cy); + Rect GetClip() const { return GetClipOp(); } + bool IsPainting(const Rect& r) const { return IsPaintingOp(r); } + bool IsPainting(int x, int y, int cx, int cy) const; + + Point GetOffset() const { return actual_offset; } + + int GetCloffLevel() const { return cloff.GetCount(); } + + + void DrawRect(int x, int y, int cx, int cy, Color color) + { DrawRectOp(x, y, cx, cy, color); } + void DrawRect(const Rect& rect, Color color); + + void DrawImage(int x, int y, int cx, int cy, const Image& img, const Rect& src); + void DrawImage(int x, int y, int cx, int cy, const Image& img); + void DrawImage(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color); + void DrawImage(int x, int y, int cx, int cy, const Image& img, Color color); + + void DrawImage(const Rect& r, const Image& img, const Rect& src); + void DrawImage(const Rect& r, const Image& img); + void DrawImage(const Rect& r, const Image& img, const Rect& src, Color color); + void DrawImage(const Rect& r, const Image& img, Color color); + + void DrawImage(int x, int y, const Image& img, const Rect& src); + void DrawImage(int x, int y, const Image& img); + void DrawImage(int x, int y, const Image& img, const Rect& src, Color color); + void DrawImage(int x, int y, const Image& img, Color color); + + void DrawData(int x, int y, int cx, int cy, const String& data, const char *type); + void DrawData(const Rect& r, const String& data, const char *type); + + void DrawLine(int x1, int y1, int x2, int y2, int width = 0, Color color = DefaultInk) + { DrawLineOp(x1, y1, x2, y2, width, color); } + void DrawLine(Point p1, Point p2, int width = 0, Color color = DefaultInk); + + void DrawEllipse(const Rect& r, Color color = DefaultInk, + int pen = Null, Color pencolor = DefaultInk) + { DrawEllipseOp(r, color, pen, pencolor); } + void DrawEllipse(int x, int y, int cx, int cy, Color color = DefaultInk, + int pen = Null, Color pencolor = DefaultInk); + +#ifndef PLATFORM_WINCE + void DrawArc(const Rect& rc, Point start, Point end, int width = 0, Color color = DefaultInk) + { DrawArcOp(rc, start, end, width, color); } + + void DrawPolyPolyline(const Point *vertices, int vertex_count, + const int *counts, int count_count, + int width = 0, Color color = DefaultInk, Color doxor = Null) + { DrawPolyPolylineOp(vertices, vertex_count, counts, count_count, width, color, doxor); } + void DrawPolyPolyline(const Vector& vertices, const Vector& counts, + int width = 0, Color color = DefaultInk, Color doxor = Null); + void DrawPolyline(const Point *vertices, int count, + int width = 0, Color color = DefaultInk, Color doxor = Null); + void DrawPolyline(const Vector& vertices, + int width = 0, Color color = DefaultInk, Color doxor = Null); + + void DrawPolyPolyPolygon(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int subpolygon_count_count, + const int *disjunct_polygon_counts, int disjunct_polygon_count_count, + Color color = DefaultInk, int width = 0, Color outline = Null, + uint64 pattern = 0, Color doxor = Null) + { DrawPolyPolyPolygonOp(vertices, vertex_count, subpolygon_counts, subpolygon_count_count, + disjunct_polygon_counts, disjunct_polygon_count_count, + color, width, outline, pattern, doxor); } + + void DrawPolyPolyPolygon(const Vector& vertices, + const Vector& subpolygon_counts, + const Vector& disjunct_polygon_counts, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolyPolygon(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int subpolygon_count_count, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolyPolygon(const Vector& vertices, const Vector& subpolygon_counts, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolygons(const Point *vertices, int vertex_count, + const int *polygon_counts, int polygon_count_count, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolygons(const Vector& vertices, const Vector& polygon_counts, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolygon(const Point *vertices, int vertex_count, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolygon(const Vector& vertices, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); +#endif + + void DrawDrawing(const Rect& r, const Drawing& iw) { DrawDrawingOp(r, iw); } + void DrawDrawing(int x, int y, int cx, int cy, const Drawing& iw); + + void DrawPainting(const Rect& r, const Painting& iw) { DrawPaintingOp(r, iw); } + void DrawPainting(int x, int y, int cx, int cy, const Painting& iw); + + void DrawText(int x, int y, int angle, const wchar *text, Font font = StdFont(), + Color ink = DefaultInk, int n = -1, const int *dx = NULL); + void DrawText(int x, int y, const wchar *text, Font font = StdFont(), + Color ink = DefaultInk, int n = -1, const int *dx = NULL); + + void DrawText(int x, int y, const WString& text, Font font = StdFont(), + Color ink = DefaultInk, const int *dx = NULL); + void DrawText(int x, int y, int angle, const WString& text, Font font = StdFont(), + Color ink = DefaultInk, const int *dx = NULL); + + void DrawText(int x, int y, int angle, const char *text, byte charset, + Font font = StdFont(), Color ink = DefaultInk, int n = -1, const int *dx = NULL); + void DrawText(int x, int y, const char *text, byte charset, Font font = StdFont(), + Color ink = DefaultInk, int n = -1, const int *dx = NULL); + + void DrawText(int x, int y, int angle, const char *text, + Font font = StdFont(), Color ink = DefaultInk, int n = -1, const int *dx = NULL); + void DrawText(int x, int y, const char *text, Font font = StdFont(), + Color ink = DefaultInk, int n = -1, const int *dx = NULL); + + void DrawText(int x, int y, const String& text, Font font = StdFont(), + Color ink = DefaultInk, const int *dx = NULL); + void DrawText(int x, int y, int angle, const String& text, Font font = StdFont(), + Color ink = DefaultInk, const int *dx = NULL); + +#ifdef PLATFORM_WIN32 + bool IsMetaFile() const { return device == -1; } + + COLORREF GetColor(Color color) const; +#ifndef PLATFORM_WINCE + Point LPtoDP(Point p) const; + Point DPtoLP(Point p) const; + Rect LPtoDP(const Rect& r) const; + Rect DPtoLP(const Rect& r) const; +#endif + void SetColor(Color color); + void SetFont(Font font, int angle = 0); + void SetDrawPen(int width, Color color); + + Size GetSizeCaps(int i, int j) const; + HDC BeginGdi(); + void EndGdi(); + HDC GetHandle() { return handle; } + operator HDC() const { return handle; } + void Unselect(); + void Attach(HDC ahandle) { handle = ahandle; Init(); } + HDC Detach() { Unselect(); HDC h = handle; handle = NULL; return h; } + + Draw(HDC hdc); + virtual ~Draw(); +#endif + +#ifdef PLATFORM_X11 + +#ifdef PLATFORM_XFT + static XftFont *CreateXftFont(Font f, int angle); + XftDraw *GetXftDraw() const { return xftdraw; } +#endif + void SetForeground(Color color); + void SetLineStyle(int width); + void SetFont(Font font, int angle); + void SetClip(); + + Drawable GetDrawable() const { return dw; } + GC GetGC() const { return gc; } + const Vector& GetClipList() const { return clip.Top(); } +#ifdef PLATFORM_XFT + Draw(Drawable dw, GC gc, XftDraw *xftdraw, const Vector& clip); +#else + Draw(Drawable dw, GC gc, const Vector& clip); +#endif + virtual ~Draw(); +#endif + +private: //Deprecated + FontInfo GetFontInfoW(Font font = StdFont()); + +private: + Draw(const Draw&); + void operator=(const Draw&); +}; + + + +class SystemDraw : public Draw { + dword style; + Size pagePixels; + Size nativeDpi; + + SystemDraw(); + + friend class ImageDraw; + friend class FontInfo; + friend class Font; + + friend void StaticExitDraw_(); + + FontInfo lastFont; + + Point actual_offset; + Point actual_offset_bak; + + struct Cloff : Moveable { + Point org; + HRGN hrgn; + Rect drawingclip; + }; + + Array cloff; + Rect drawingclip; + + HDC handle; + COLORREF lastTextColor; + Color lastColor; + HBRUSH orgBrush; + HBRUSH actBrush; + HFONT orgFont; + HPEN orgPen; + HPEN actPen; + int lastPen; + Color lastPenColor; + + void Unselect0(); + void Cinit(); + void Init(); + + void LoadCaps(); + void SetDevice(const char *devicename); + void SetPrinterMode(); + void Reset(); + void SetOrg(); + friend HPALETTE GetQlibPalette(); + void DotsMode(); + +public: + static bool AutoPalette(); + +#ifdef PLATFORM_WIN32 +#ifdef PLATFORM_WINCE + static void Flush() {} +#else + static void Flush() { GdiFlush(); } +#endif +#endif +#ifdef PLATFORM_X11 + static void Flush() { XSync(Xdisplay, false); } +#endif + + bool PaletteMode() const { return palette; } + bool IsMono() const { return is_mono; } + + Size GetPixelsPerInch() const { return native ? nativeDpi : inchPixels; } + Size GetPageMMs() const { return pageMMs; } + + bool Pixels() const { return pixels; } + bool Dots() const { return !pixels; } + bool IsNative() const { return native; } + + void BeginNative(); + void EndNative(); + Size GetNativeDpi() const; + int GetNativeX(int x) const; + int GetNativeY(int x) const; + void Native(int& x, int& y) const; + void Native(Point& p) const; + void Native(Size& sz) const; + void Native(Rect& r) const; + + bool IsPrinter() const { return printer; } + bool IsAborted() const { return aborted; } + bool IsBack() const { return backdraw; } +#ifdef PLATFORM_WIN32 + bool IsSystem() const { return handle; } +#endif +#ifdef PLATFORM_X11 + bool IsSystem() const { return gc != None; } +#endif + bool IsDrawing() const; + + virtual dword GetInfo() const; + virtual Size GetPagePixels() const; + + virtual void StartPage(); + virtual void EndPage(); + + virtual void BeginOp(); + virtual void EndOp(); + virtual void OffsetOp(Point p); + virtual bool ClipOp(const Rect& r); + virtual bool ClipoffOp(const Rect& r); + virtual bool ExcludeClipOp(const Rect& r); + virtual bool IntersectClipOp(const Rect& r); + virtual Rect GetClipOp() const; + virtual bool IsPaintingOp(const Rect& r) const; + + virtual void DrawRectOp(int x, int y, int cx, int cy, Color color); + virtual void DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color); + virtual void DrawDataOp(int x, int y, int cx, int cy, const String& data, const char *id); + virtual void DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color); + +#ifndef PLATFORM_WINCE + virtual void DrawPolyPolylineOp(const Point *vertices, int vertex_count, + const int *counts, int count_count, + int width, Color color, Color doxor); + virtual void DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int scc, + const int *disjunct_polygon_counts, int dpcc, + Color color, int width, Color outline, + uint64 pattern, Color doxor); + virtual void DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color); +#endif + virtual void DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor); + virtual void DrawTextOp(int x, int y, int angle, const wchar *text, Font font, + Color ink, int n, const int *dx); + virtual void DrawDrawingOp(const Rect& target, const Drawing& w); + virtual void DrawPaintingOp(const Rect& target, const Painting& w); + + void Begin() { BeginOp(); } + void End() { EndOp(); } + void Offset(Point p) { OffsetOp(p); } + void Offset(int x, int y); + bool Clip(const Rect& r) { return ClipOp(r); } + bool Clip(int x, int y, int cx, int cy); + bool Clipoff(const Rect& r) { return ClipoffOp(r); } + bool Clipoff(int x, int y, int cx, int cy); + bool ExcludeClip(const Rect& r) { return ExcludeClipOp(r); } + bool ExcludeClip(int x, int y, int cx, int cy); + bool IntersectClip(const Rect& r) { return IntersectClipOp(r); } + bool IntersectClip(int x, int y, int cx, int cy); + Rect GetClip() const { return GetClipOp(); } + bool IsPainting(const Rect& r) const { return IsPaintingOp(r); } + bool IsPainting(int x, int y, int cx, int cy) const; + + Point GetOffset() const { return actual_offset; } + + int GetCloffLevel() const { return cloff.GetCount(); } + + + void DrawRect(int x, int y, int cx, int cy, Color color) + { DrawRectOp(x, y, cx, cy, color); } + void DrawRect(const Rect& rect, Color color); + + void DrawImage(int x, int y, int cx, int cy, const Image& img, const Rect& src); + void DrawImage(int x, int y, int cx, int cy, const Image& img); + void DrawImage(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color); + void DrawImage(int x, int y, int cx, int cy, const Image& img, Color color); + + void DrawImage(const Rect& r, const Image& img, const Rect& src); + void DrawImage(const Rect& r, const Image& img); + void DrawImage(const Rect& r, const Image& img, const Rect& src, Color color); + void DrawImage(const Rect& r, const Image& img, Color color); + + void DrawImage(int x, int y, const Image& img, const Rect& src); + void DrawImage(int x, int y, const Image& img); + void DrawImage(int x, int y, const Image& img, const Rect& src, Color color); + void DrawImage(int x, int y, const Image& img, Color color); + + void DrawData(int x, int y, int cx, int cy, const String& data, const char *type); + void DrawData(const Rect& r, const String& data, const char *type); + + void DrawLine(int x1, int y1, int x2, int y2, int width = 0, Color color = DefaultInk) + { DrawLineOp(x1, y1, x2, y2, width, color); } + void DrawLine(Point p1, Point p2, int width = 0, Color color = DefaultInk); + + void DrawEllipse(const Rect& r, Color color = DefaultInk, + int pen = Null, Color pencolor = DefaultInk) + { DrawEllipseOp(r, color, pen, pencolor); } + void DrawEllipse(int x, int y, int cx, int cy, Color color = DefaultInk, + int pen = Null, Color pencolor = DefaultInk); + +#ifndef PLATFORM_WINCE + void DrawArc(const Rect& rc, Point start, Point end, int width = 0, Color color = DefaultInk) + { DrawArcOp(rc, start, end, width, color); } + + void DrawPolyPolyline(const Point *vertices, int vertex_count, + const int *counts, int count_count, + int width = 0, Color color = DefaultInk, Color doxor = Null) + { DrawPolyPolylineOp(vertices, vertex_count, counts, count_count, width, color, doxor); } + void DrawPolyPolyline(const Vector& vertices, const Vector& counts, + int width = 0, Color color = DefaultInk, Color doxor = Null); + void DrawPolyline(const Point *vertices, int count, + int width = 0, Color color = DefaultInk, Color doxor = Null); + void DrawPolyline(const Vector& vertices, + int width = 0, Color color = DefaultInk, Color doxor = Null); + + void DrawPolyPolyPolygon(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int subpolygon_count_count, + const int *disjunct_polygon_counts, int disjunct_polygon_count_count, + Color color = DefaultInk, int width = 0, Color outline = Null, + uint64 pattern = 0, Color doxor = Null) + { DrawPolyPolyPolygonOp(vertices, vertex_count, subpolygon_counts, subpolygon_count_count, + disjunct_polygon_counts, disjunct_polygon_count_count, + color, width, outline, pattern, doxor); } + + void DrawPolyPolyPolygon(const Vector& vertices, + const Vector& subpolygon_counts, + const Vector& disjunct_polygon_counts, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolyPolygon(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int subpolygon_count_count, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolyPolygon(const Vector& vertices, const Vector& subpolygon_counts, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolygons(const Point *vertices, int vertex_count, + const int *polygon_counts, int polygon_count_count, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolygons(const Vector& vertices, const Vector& polygon_counts, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolygon(const Point *vertices, int vertex_count, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolygon(const Vector& vertices, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); +#endif + + void DrawDrawing(const Rect& r, const Drawing& iw) { DrawDrawingOp(r, iw); } + void DrawDrawing(int x, int y, int cx, int cy, const Drawing& iw); + + void DrawPainting(const Rect& r, const Painting& iw) { DrawPaintingOp(r, iw); } + void DrawPainting(int x, int y, int cx, int cy, const Painting& iw); + + void DrawText(int x, int y, int angle, const wchar *text, Font font = StdFont(), + Color ink = DefaultInk, int n = -1, const int *dx = NULL); + void DrawText(int x, int y, const wchar *text, Font font = StdFont(), + Color ink = DefaultInk, int n = -1, const int *dx = NULL); + + void DrawText(int x, int y, const WString& text, Font font = StdFont(), + Color ink = DefaultInk, const int *dx = NULL); + void DrawText(int x, int y, int angle, const WString& text, Font font = StdFont(), + Color ink = DefaultInk, const int *dx = NULL); + + void DrawText(int x, int y, int angle, const char *text, byte charset, + Font font = StdFont(), Color ink = DefaultInk, int n = -1, const int *dx = NULL); + void DrawText(int x, int y, const char *text, byte charset, Font font = StdFont(), + Color ink = DefaultInk, int n = -1, const int *dx = NULL); + + void DrawText(int x, int y, int angle, const char *text, + Font font = StdFont(), Color ink = DefaultInk, int n = -1, const int *dx = NULL); + void DrawText(int x, int y, const char *text, Font font = StdFont(), + Color ink = DefaultInk, int n = -1, const int *dx = NULL); + + void DrawText(int x, int y, const String& text, Font font = StdFont(), + Color ink = DefaultInk, const int *dx = NULL); + void DrawText(int x, int y, int angle, const String& text, Font font = StdFont(), + Color ink = DefaultInk, const int *dx = NULL); + +#ifdef PLATFORM_WIN32 + bool IsMetaFile() const { return device == -1; } + + COLORREF GetColor(Color color) const; +#ifndef PLATFORM_WINCE + Point LPtoDP(Point p) const; + Point DPtoLP(Point p) const; + Rect LPtoDP(const Rect& r) const; + Rect DPtoLP(const Rect& r) const; +#endif + void SetColor(Color color); + void SetFont(Font font, int angle = 0); + void SetDrawPen(int width, Color color); + + Size GetSizeCaps(int i, int j) const; + HDC BeginGdi(); + void EndGdi(); + HDC GetHandle() { return handle; } + operator HDC() const { return handle; } + void Unselect(); + void Attach(HDC ahandle) { handle = ahandle; Init(); } + HDC Detach() { Unselect(); HDC h = handle; handle = NULL; return h; } + + SystemDraw(HDC hdc); + virtual ~SystemDraw(); +#endif + +#ifdef PLATFORM_X11 + + static XftFont *CreateXftFont(Font f, int angle); + XftDraw *GetXftDraw() const { return xftdraw; } + + void SetForeground(Color color); + void SetLineStyle(int width); + void SetFont(Font font, int angle); + void SetClip(); + + Drawable GetDrawable() const { return dw; } + GC GetGC() const { return gc; } + const Vector& GetClipList() const { return clip.Top(); } + + Draw(Drawable dw, GC gc, XftDraw *xftdraw, const Vector& clip); + virtual ~Draw(); +#endif +}; + + +#endif diff --git a/uppdev/Draw/Drawing.cpp b/uppdev/Draw/Drawing.cpp new file mode 100644 index 000000000..e4628d8ea --- /dev/null +++ b/uppdev/Draw/Drawing.cpp @@ -0,0 +1,691 @@ +#include "Draw.h" + +NAMESPACE_UPP + +enum { + DRAWING_BEGIN = 1, + DRAWING_OFFSET = 2, + DRAWING_CLIP = 3, + DRAWING_CLIPOFF = 4, + DRAWING_EXCLUDECLIP = 5, + DRAWING_INTERSECTCLIP = 6, + DRAWING_END = 7, + DRAWING_DRAWRECT = 8, + DRAWING_DRAWIMAGE = 9, + DRAWING_DRAWMONOIMAGE = 10, + DRAWING_DRAWDRAWING = 11, + DRAWING_DRAWLINE = 12, + DRAWING_DRAWELLIPSE = 13, + DRAWING_DRAWTEXT = 14, + DRAWING_DRAWARC = 15, + DRAWING_DRAWPOLYPOLYLINE = 16, + DRAWING_DRAWPOLYPOLYPOLYGON = 17, + DRAWING_DRAWDATA = 18, + DRAWING_DRAWPAINTING = 19, +}; + + +#define LLOG(x) // DLOG(x) + +#ifdef COMPILER_MSC +#pragma warning(disable: 4700) +#endif + +static void StreamUnpackPoints(Stream& stream, Point *out, int count) +{ + if(count == 0) + return; +#ifdef CPU_LITTLE_ENDIAN + if(sizeof(Point) == 8) { + stream.Get(out, 8 * count); + return; + } +#endif + Point *end = out + count; + byte *top = reinterpret_cast(end) - count * 8; + stream.Get(top, count * 8); + for(; out < end; out++, top += 8) { + out -> x = (short)Peek32le(top + 0); + out -> y = (short)Peek32le(top + 4); + } +} + +static void StreamPackPoints(Stream& stream, const Point *in, int count) +{ +#ifdef CPU_LITTLE_ENDIAN + if(sizeof(Point) == 8) { + stream.Put(in, 8 * count); + return; + } +#endif + enum { PART = 1024 }; + byte part[PART * 8]; + while(count > 0) + { + int part_count = min(count, PART); + for(byte *pp = part, *pe = pp + 8 * part_count; pp < pe; pp += 8, in++) { + Poke32le(pp + 0, in -> x); + Poke32le(pp + 4, in -> y); + } + stream.Put(part, part_count * 4); + count -= part_count; + } +} + +static void StreamUnpackInts(Stream& stream, int *out, int count) +{ +#ifdef CPU_LITTLE_ENDIAN + if(sizeof(int) == 4) { + stream.Get(out, count * 4); + return; + } +#endif + while(count--) + *out++ = stream.Get32le(); +} + +static void StreamPackInts(Stream& stream, const int *in, int count) +{ +#ifdef CPU_LITTLE_ENDIAN + if(sizeof(int) == 4) { + stream.Put(in, count * 4); + return; + } +#endif + while(count--) + stream.Put32le(*in++); +} + +// ------------------------------ + +Stream& DrawingDraw::DrawingOp(int code) +{ + drawing / code; + return drawing; +} + +void DrawingDraw::BeginOp() +{ + DrawingOp(DRAWING_BEGIN); +} + +void DrawingDraw::OffsetOp(Point p) +{ + DrawingOp(DRAWING_OFFSET) % p; +} + +bool DrawingDraw::ClipOp(const Rect& r) +{ + DrawingOp(DRAWING_CLIP) % const_cast(r); + return true; +} + +bool DrawingDraw::ClipoffOp(const Rect& r) +{ + DrawingOp(DRAWING_CLIPOFF) % const_cast(r); + return true; +} + +void DrawingDraw::EndOp() +{ + DrawingOp(DRAWING_END); +} + +bool DrawingDraw::ExcludeClipOp(const Rect& r) +{ + DrawingOp(DRAWING_EXCLUDECLIP) % const_cast(r); + return true; +} + +bool DrawingDraw::IntersectClipOp(const Rect& r) +{ + DrawingOp(DRAWING_INTERSECTCLIP) % const_cast(r); + return true; +} + +bool DrawingDraw::IsPaintingOp(const Rect& r) const +{ + return true; +} + +void DrawingDraw::DrawRectOp(int x, int y, int cx, int cy, Color color) +{ + if(!IsNull(color)) + DrawingOp(DRAWING_DRAWRECT) % x % y % cx % cy % color; +} + +void DrawingDraw::DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color) +{ + Rect s = src; + DrawingOp(DRAWING_DRAWIMAGE) % x % y % cx % cy % s % color; + val.Add(img); +} + +void DrawingDraw::DrawDataOp(int x, int y, int cx, int cy, const String& data, const char *id) +{ + String h = id; + DrawingOp(DRAWING_DRAWDATA) % x % y % cx % cy % h; + val.Add(data); +} + +void DrawingDraw::DrawDrawingOp(const Rect& target, const Drawing& w) +{ + DrawingOp(DRAWING_DRAWDRAWING) % const_cast(target); + val.Add(w); +} + +void DrawingDraw::DrawPaintingOp(const Rect& target, const Painting& w) +{ + DrawingOp(DRAWING_DRAWPAINTING) % const_cast(target); + val.Add(w); +} + +void DrawingDraw::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color) +{ + DrawingOp(DRAWING_DRAWLINE) % x1 % y1 % x2 % y2 % width % color; +} + +void DrawingDraw::DrawPolyPolylineOp(const Point *vertices, int vertex_count, + const int *counts, int count_count, + int width, Color color, Color doxor) +{ + ASSERT(count_count > 0 && vertex_count > 0); + if(vertex_count < 2 || IsNull(color)) + return; + DrawingOp(DRAWING_DRAWPOLYPOLYLINE); + int version = 2; + drawing / version; + drawing % width % color % doxor; + drawing % vertex_count % count_count; + StreamPackPoints(drawing, vertices, vertex_count); + StreamPackInts(drawing, counts, count_count); +} + +void DrawingDraw::DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int subpolygon_count_count, + const int *disjunct_polygon_counts, int disjunct_polygon_count_count, + Color color, int width, Color outline, uint64 pattern, Color doxor) +{ + if(vertex_count == 0) + return; + DrawingOp(DRAWING_DRAWPOLYPOLYPOLYGON); + int version = 2; + drawing / version; + drawing % color % width % outline % pattern % doxor; + drawing % vertex_count % subpolygon_count_count % disjunct_polygon_count_count; + StreamPackPoints(drawing, vertices, vertex_count); + StreamPackInts(drawing, subpolygon_counts, subpolygon_count_count); + StreamPackInts(drawing, disjunct_polygon_counts, disjunct_polygon_count_count); +} + +void DrawingDraw::DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor) +{ + DrawingOp(DRAWING_DRAWELLIPSE) % const_cast(r) % color / pen % pencolor; +} + +void DrawingDraw::DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color) +{ + DrawingOp(DRAWING_DRAWARC) % const_cast(rc) % start % end % color % width; +} + +void DrawingDraw::DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, + int n, const int *dx) { + if(IsNull(ink)) return; + if(n < 0) + n = wstrlen((const wchar *)text); + if(n == 0) + return; + Stream& s = DrawingOp(DRAWING_DRAWTEXT); + byte cs = CHARSET_UNICODE; + s % x % y % angle % font % ink / n % cs; + s.PutW((wchar *)text, n); + bool dxb = dx; + s % dxb; + if(dx) { + int *w = const_cast(dx); + while(n--) + s / *w++; + } +} + +Drawing DrawingDraw::GetResult() +{ + Drawing out; + out.size = size; + LLOG("GetResult size: " << size); + out.data = drawing.GetResult(); + out.val = val; + return out; +} + +// ------------------------------ + +struct Draw::DrawingPos : StringStream { + Size source; + Size target; + Point srcoff; + Point trgoff; + + Vector stk; + + bool Identity() const { return source == target; } + + int GetX(int x) const; + int GetY(int y) const; + int GetCx(int cx) const; + int GetCy(int cy) const; + int GetW(int w) const; + Point Get(int x, int y) const; + Point Get(Point p) const; + Rect Get(const Rect& r) const; + Rect Get(int x, int y, int cx, int cy) const; + + Point operator()(int x, int y) const { return Get(x, y); } + Point operator()(Point p) const { return Get(p); } + Rect operator()(const Rect& r) const { return Get(r); } + Rect operator()(int x, int y, int cx, int cy) const { return Get(x, y, cx, cy); } + + void TransformX(int& x) const { x = GetX(x); } + void TransformY(int& y) const { y = GetY(y); } + void TransformW(int& w) const { w = GetW(w); } + void Transform(int& x, int& y) const { TransformX(x); TransformY(y); } + void Transform(Point& p) const { p = Get(p); } + void Transform(Rect& r) const { r = Get(r); } + + Rect GetRect(); + + void Push(); + void Pop(); + + DrawingPos(const String& src) : StringStream(src) {} +}; + +void Draw::DrawingPos::Push() +{ + stk.Add(srcoff); + stk.Add(trgoff); +} + +void Draw::DrawingPos::Pop() +{ + trgoff = stk.Pop(); + srcoff = stk.Pop(); +} + +Rect Draw::DrawingPos::GetRect() +{ + Rect r; + *this % r; + return Get(r); +} + +int Draw::DrawingPos::GetX(int x) const { + return iscale(x + srcoff.x, target.cx, source.cx) - trgoff.x; +} + +int Draw::DrawingPos::GetY(int y) const { + return iscale(y + srcoff.y, target.cy, source.cy) - trgoff.y; +} + +int Draw::DrawingPos::GetCx(int cx) const { + return iscale(cx, target.cx, source.cx); +} + +int Draw::DrawingPos::GetCy(int cy) const { + return iscale(cy, target.cy, source.cy); +} + +int Draw::DrawingPos::GetW(int w) const { + return iscale(w, target.cx + target.cy, source.cx + source.cy); +} + +Point Draw::DrawingPos::Get(int x, int y) const { + return Point(GetX(x), GetY(y)); +} + +Point Draw::DrawingPos::Get(Point p) const { + return Get(p.x, p.y); +} + +Rect Draw::DrawingPos::Get(const Rect& r) const { + return Rect(GetX(r.left), GetY(r.top), GetX(r.right), GetY(r.bottom)); +} + +Rect Draw::DrawingPos::Get(int x, int y, int cx, int cy) const { + return Get(RectC(x, y, cx, cy)); +} + +void Draw::DrawDrawingOp(const Rect& target, const Drawing& w) { +#ifdef _DEBUG + int cl = GetCloffLevel(); +#endif + DrawingPos ps(w.data); + ps.srcoff = ps.trgoff = Point(0, 0); + ps.target = target.Size(); + ps.source = w.size; + LLOG("DrawDrawingOp size: " << w.size); + if(ps.target.cx == 0 || ps.target.cy == 0 || ps.source.cx == 0 || ps.source.cy == 0) + return; + Clipoff(target); + Rect r, r1; + int x, y, cx, cy, width, vertex_count, count_count; + Color color, pencolor, doxor; + Image img; + Drawing dw; + Painting sw; + Point p, p1; + int vi = 0; + while(!ps.IsEof()) { + int code; + ps / code; + switch(code) { + case DRAWING_BEGIN: + Begin(); + ps.Push(); + break; + case DRAWING_OFFSET: + ps % p; + p1 = ps(p); + Offset(p1); + ps.Push(); + ps.srcoff += p; + ps.trgoff += p1; + break; + case DRAWING_CLIP: + Clip(ps.GetRect()); + ps.Push(); + break; + case DRAWING_CLIPOFF: + ps % r; + r1 = ps(r); + Clipoff(r1); + ps.Push(); + ps.srcoff += r.TopLeft(); + ps.trgoff += r1.TopLeft(); + break; + case DRAWING_EXCLUDECLIP: + ExcludeClip(ps.GetRect()); + break; + case DRAWING_INTERSECTCLIP: + IntersectClip(ps.GetRect()); + break; + case DRAWING_END: + End(); + ps.Pop(); + break; + case DRAWING_DRAWRECT: + ps % x % y % cx % cy % color; + DrawRect(ps(x, y, cx, cy), color); + break; + case DRAWING_DRAWIMAGE: + ps % x % y % cx % cy; + if(w.val.GetCount()) + img = w.val[vi++]; + else + ps % img; + ps % r % color; + DrawImageOp(ps.GetX(x), ps.GetY(y), ps.GetCx(cx), ps.GetCy(cy), img, r, color); + break; + case DRAWING_DRAWDATA: + { + String data, id; + ps % x % y % cx % cy % id; + if(w.val.GetCount()) + data = w.val[vi++]; + else + ps % data; + DrawData(ps(x, y, cx, cy), data, id); + } + break; + case DRAWING_DRAWDRAWING: + if(w.val.GetCount()) + dw = w.val[vi++]; + else + ps % dw; + DrawDrawing(ps.GetRect(), dw); + break; + case DRAWING_DRAWPAINTING: + if(w.val.GetCount()) + sw = w.val[vi++]; + else + ps % sw; + DrawPainting(ps.GetRect(), sw); + break; + case DRAWING_DRAWLINE: + ps % x % y % cx % cy % width % color; + DrawLine(ps(x, y), ps(cx, cy), width > 0 ? ps.GetW(width) : width, color); + break; + case DRAWING_DRAWELLIPSE: + r = ps.GetRect(); + ps % color / width % pencolor; + DrawEllipse(r, color, width > 0 ? ps.GetW(width) : width, pencolor); + break; +#ifndef PLATFORM_WINCE + case DRAWING_DRAWARC: + r = ps.GetRect(); + ps % p % p1 % color % width; + DrawArc(r, ps(p), ps(p1), width > 0 ? ps.GetW(width) : width, color); + break; + case DRAWING_DRAWPOLYPOLYLINE: + { + int version; + ps / version; + ps % width % color % doxor; + ps % vertex_count % count_count; + Buffer vertices(vertex_count); + Buffer counts(count_count); + StreamUnpackPoints(ps, vertices, vertex_count); + StreamUnpackInts(ps, counts, count_count); + if(!ps.Identity()) { + for(Point *p = vertices, *e = p + vertex_count; p < e; p++) + ps.Transform(*p); + if(width > 0) + ps.TransformW(width); + } + DrawPolyPolyline(vertices, vertex_count, counts, count_count, width, color, doxor); + } + break; + case DRAWING_DRAWPOLYPOLYPOLYGON: + { + Color outline; + uint64 pattern; + int subpolygon_count_count, disjunct_polygon_count_count; + int version = 2; + ps / version; + ps % color % width % outline % pattern % doxor; + ps % vertex_count % subpolygon_count_count % disjunct_polygon_count_count; + Buffer vertices(vertex_count); + Buffer subpolygon_counts(subpolygon_count_count); + Buffer disjunct_polygon_counts(disjunct_polygon_count_count); + StreamUnpackPoints(ps, vertices, vertex_count); + StreamUnpackInts(ps, subpolygon_counts, subpolygon_count_count); + StreamUnpackInts(ps, disjunct_polygon_counts, disjunct_polygon_count_count); + if(!ps.Identity()) { + for(Point *p = vertices, *e = p + vertex_count; p < e; p++) + ps.Transform(*p); + ps.TransformW(width); + } + DrawPolyPolyPolygon(vertices, vertex_count, + subpolygon_counts, subpolygon_count_count, + disjunct_polygon_counts, disjunct_polygon_count_count, + color, width, outline, pattern, doxor); + } + break; +#endif + case DRAWING_DRAWTEXT: + { + int n, angle; + Font font; + Color ink; + byte cs; + ps % x % y % angle % font % ink / n % cs; + if(font.GetHeight() == 0) { + FontInfo fi = font.Info(); + font.Height(fi.GetHeight() - fi.GetInternal()); + } + bool unicode = cs == CHARSET_UNICODE; + WString text; + if(unicode) { + Buffer txt(n); + ps.Stream::GetW(txt, n); + text = WString(txt, n); + } + else { + Buffer txt(n); + ps.Stream::Get(txt, n); + text = ToUnicode(txt, n, cs); + } + LLOG("wsDrawText \"" << WString(text, n) + << "\" at: (" << x << ", " << y << ", " << angle << ")"); + bool dxb; + ps % dxb; + Buffer dx(n); + int *wd = dx; + int nn = n; + angle %= 3600; + if(ps.Identity()) { + if(dxb) { + while(nn--) + ps / *wd++; + DrawText(x, y, angle, text, font, ink, dx); + } + else + DrawText(x, y, angle, text, font, ink); + } + else { + FontInfo fi = font.Info(); + const wchar *wp = ~text; + int odd = (angle / 900) & 1; + if(angle % 900 == 0) { + int error = 0; + int a, b; + if(odd) { + a = ps.target.cy; + b = ps.source.cy; + int ht = ps.GetCx(fi.GetFontHeight()); + font.Width(ps.GetCy(fi.GetAveWidth())).Height(ht ? ht : 1); + FontInfo nf = font.Info(); + x = angle == 2700 ? ps.GetX(x - fi.GetAscent()) + nf.GetAscent() + : ps.GetX(x + fi.GetAscent()) - nf.GetAscent(); + y = ps.GetY(y); + } + else { + a = ps.target.cx; + b = ps.source.cx; + int ht = ps.GetCy(fi.GetFontHeight()); + font.Width(ps.GetCx(fi.GetAveWidth())).Height(ht ? ht : 1); + FontInfo nf = font.Info(); + x = ps.GetX(x); + y = angle == 1800 ? ps.GetY(y - fi.GetAscent()) + nf.GetAscent() + : ps.GetY(y + fi.GetAscent()) - nf.GetAscent(); + } + while(nn--) { + int c; + if(dxb) + ps / c; + else + c = fi[*wp++]; + *wd++ = (c * a + error) / b; + error = (c * a + error) % b; + } + DrawText(x, y, angle, text, font, ink, dx); + } + else { + double ang = (double) (angle % 900) * M_2PI / 3600; + double sx = (double) ps.target.cx / ps.source.cx; + double sy = (double) ps.target.cy / ps.source.cy; + double ang2 = atan((odd ? sx / sy : sy / sx) * tan(ang)); + double q = (odd ? sx : sy) * sin(ang) / sin(ang2); + double error = 0; + while(nn--) { + int cx; + if(dxb) + ps / cx; + else + cx = fi[*wp++]; + double ncx = q * cx + error; + *wd++ = cx = (int) ncx; + error = ncx - cx; + } + int ht = (int)(fi.GetFontHeight() * (sx * sin(ang) * sin(ang2) + sy * cos(ang) * cos(ang2))); + font.Width(int(q * fi.GetAveWidth())).Height(ht ? ht : 1); + DrawText(ps.GetX(x), ps.GetY(y), int(ang2 * 3600 / M_2PI) + (angle / 900) * 900, + text, font, ink, dx); + } + } + } + } + } +// LOGEND(); + End(); +#ifdef _DEBUG + ASSERT(GetCloffLevel() == cl); +#endif +} + +void Draw::DrawDrawing(int x, int y, int cx, int cy, const Drawing& w) { + DrawDrawing(RectC(x, y, cx, cy), w); +} + +void DrawingDraw::Create(int cx, int cy) { + Create(Size(cx, cy)); +} + +void DrawingDraw::Create(Size sz) { + drawing.Create(); + size = sz; + LLOG("DrawingDraw::Create, sz = " << sz << " -> clip = " << GetClip()); +} + +DrawingDraw::DrawingDraw() +{ +} + +DrawingDraw::DrawingDraw(Size sz) { + Create(sz); +} + +DrawingDraw::DrawingDraw(int cx, int cy) { + Create(cx, cy); +} + +DrawingDraw::~DrawingDraw() { +#ifdef PLATFORM_X11 + XFreeGC(Xdisplay, gc); +#endif +} + +Size Drawing::RatioSize(int cx, int cy) const { + return GetRatioSize(GetSize(), cx, cy); +} + +void Drawing::Append(Drawing& dw) +{ + if(IsNull(size)) + size = dw.size; + data << dw.data; + for(int i = 0; i < dw.val.GetCount(); i++) + val.Add(dw.val[i]); +} + +Drawing::Drawing(const Value& src) +{ + if(IsNull(src)) + size = Null; + else + *this = RichValue::Extract(src); +} + +void Drawing::Serialize(Stream& s) +{ + if(val.GetCount()) + size.cy |= 0x80000000; + s % size; + s % data; + if(size.cy & 0x80000000) { + size.cy &= ~0x80000000; + s % val; + } +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/Font.cpp b/uppdev/Draw/Font.cpp new file mode 100644 index 000000000..c9e6a0292 --- /dev/null +++ b/uppdev/Draw/Font.cpp @@ -0,0 +1,303 @@ +#include "Draw.h" + +#define LLOG(x) + +NAMESPACE_UPP + +void InitPlatformFonts(); + +Size FontInfo::StdFontSize; +Font FontInfo::AStdFont; + +int FontInfo::FontCacheMax = 32; +int FontInfo::FontCached; + +void FreeFonts(); + +enum FontHashConst { FONTHASH = 97 }; + +//# Pretty ugly code.... +FontInfo::Data *FontInfo::GetFontHash(int i) { + static byte buff[FONTHASH * sizeof(FontLink)]; + static FontLink *fonthash; + if(!fonthash) { + fonthash = (FontLink *)buff; + for(int i = 0; i < FONTHASH; i++) + fonthash[i].LinkSelfAll(); + } + ASSERT(i >= 0 && i < FONTHASH); + return (FontInfo::Data *)&fonthash[i]; +} + +//# Pretty ugly code.... +FontInfo::Data *FontInfo::GetFontLru() { + static byte buff[sizeof(FontLink)]; + static FontLink *fontlru; + if(!fontlru) + fontlru = new(buff) FontLink; + return (FontInfo::Data *)fontlru; +} + +INITBLOCK { + RichValue::Register(); +} + +void FontInfo::InitFonts() +{ + ONCELOCK { + DrawLock __; + GetFontHash(0); + GetFontLru(); + InitPlatformFonts(); + } +} + +int FontFilter(int c) +{ + return c >= 'a' && c <= 'z' || c >= '0' && c <= '9' ? c : c >= 'A' && c <= 'Z' ? ToLower(c) : 0; +} + +int Font::FindFaceNameIndex(const char *name) { + FontInfo::InitFonts(); + for(int i = 1; i < GetFaceCount(); i++) + if(GetFaceName(i) == name) + return i; + String n = Filter(name, FontFilter); + for(int i = 1; i < GetFaceCount(); i++) + if(Filter(GetFaceName(i), FontFilter) == n) + return i; + return 0; +} + +FontInfo::FontInfo() +{ + ptr = NULL; + charset = CHARSET_UNICODE; + InitFonts(); +} + +SystemDraw& ScreenInfo(); + +FontInfo Font::Info() const +{ + DrawLock __; + return FontInfo::AcquireFontInfo(*this, 0); +} + +void FontInfo::SyncStdFont() +{ + FontInfo fi = AStdFont.Info(); + FontInfo bfi = AStdFont().Bold().Info(); + StdFontSize = Size(fi.GetAveWidth(), bfi.GetHeight()); +} + +void FontInfo::SetStdFont(Font font) +{ + DrawLock __; + InitFonts(); + AStdFont = font; + SyncStdFont(); +} + +Size FontInfo::GetStdFontSize() +{ + ONCELOCK { + SyncStdFont(); + } + return StdFontSize; +} + +Font StdFont() +{ + return Font(0, FontInfo::GetStdFont().GetHeight()); +} + +String Font::GetFaceName() const { + if(IsNull()) return String(); + if(GetFace() == 0) + return "STDFONT"; + return GetFaceName(GetFace()); +} + +dword Font::GetFaceInfo() const { + if(IsNull()) return 0; + return GetFaceInfo(GetFace()); +} + +Font& Font::FaceName(const String& name) { + int n = FindFaceNameIndex(name); + Face(n < 0 ? 0xffff : n); + return *this; +} + +void Font::Serialize(Stream& s) { + int version = 1; + s / version; + if(version >= 1) { + int f = GetFace(); + if(f > COURIER) + f = -1; + s / f; + String name; + if(f < 0) { + name = GetFaceName(); + s % name; + } + if(s.IsLoading()) + if(f >= 0) + Face(f); + else + FaceName(name); + } + else { + String name = GetFaceName(); + s % name; + if(s.IsLoading()) { + FaceName(name); + if(IsNull()) + Face(COURIER); + } + } + s % flags % height % width; +} + +template<> +String AsString(const Font& f) { + if(IsNull(f)) return ""; + String s = "<" + f.GetFaceName() + Format(":%d", f.GetHeight()); + if(f.IsBold()) + s += " Bold"; + if(f.IsItalic()) + s += " Italic"; + if(f.IsUnderline()) + s += " Underline"; + if(f.IsStrikeout()) + s += " Strikeout"; + return s + '>'; +} + +void FontInfo::FreeFonts() { + FontCacheMax = FontCached = 0; + for(int i = 0; i < FONTHASH; i++) + GetFontHash(i)->DeleteList(HASH); +} + +FontInfo::FontInfo(const FontInfo& f) +{ + Retain(f); +} + +FontInfo& FontInfo::operator=(const FontInfo& f) +{ + Release(); + Retain(f); + return *this; +} + +bool FontInfo::IsEqual(byte _charset, Font f, int angle, int device) const +{ + return ptr && ptr->font == f && ptr->angle == angle && ptr->device == device && + charset == _charset; +} + +FontInfo::CharMetrics FontInfo::GetCM(int c) const +{ + if(c < 0) c = (byte)c; + if(charset != CHARSET_UNICODE) + c = ToUnicode(c, charset); + ASSERT(c < 65536); + if(c >= 65536) { + CharMetrics h; + h.width = h.lspc = h.rspc = 0; + return h; + } + if(c < 2048) + return GetPage(c >> 5)[c & 31]; + Mutex::Lock __(ptr->xmutex); + Kinfo& ki = ptr->kinfo.At((c >> 10) - 2); + if(!ki.flags) { + ki.flags = new byte[128]; + memset(ki.flags, 0, 128); + ptr->GetMetrics(&ki.std, c, 1); + } + int fi = (c >> 3) & 127; + int fm = 1 << (c & 7); + if(ki.flags[fi] & fm) + return ki.std; + int q = ptr->xx.Find(c); + if(q >= 0) + return ptr->xx[q]; + CharMetrics m; + ptr->GetMetrics(&m, c, 1); + if(m == ki.std) + ki.flags[fi] |= fm; + else + ptr->xx.Add(c, m); + return m; +} + +int FontInfo::GetWidth(int c) const { + return GetCM(c).width; +} + +int FontInfo::GetLeftSpace(int c) const { + return GetCM(c).lspc; +} + +int FontInfo::GetRightSpace(int c) const { + return GetCM(c).rspc; +} + +void FontInfo::Release() +{ + DrawLock __; + if(ptr) { + ASSERT(ptr->refcount > 0); + LLOG("Release " << (void *)ptr << " count:" << ptr->count); + if(--ptr->refcount == 0) { + if(FontCacheMax == 0) { + delete ptr; + return; + } + FontInfo::Data *lru = GetFontLru(); + ptr->LinkAfter(lru, LRU); + FontCached++; + LLOG("Placed to cache " << ptr->ptr << " cached:" << FontCached); + while(FontCached > FontCacheMax) { + ASSERT(lru->GetPrev(LRU) != lru); + FontCached--; + LLOG("Deleting from cache " << lru->GetPrev(LRU)->ptr << + " cached: " << FontCached); + delete lru->GetPrev(LRU); + } + } + } +} + +void FontInfo::Retain(const FontInfo& f) +{ + DrawLock __; + ptr = f.ptr; + ptr->refcount++; + charset = f.charset; +} + +FontInfo::CharMetrics *FontInfo::CreateMetricsPage(int page) const +{ + DrawLock __; + CharMetrics *cm; + cm = new CharMetrics[32]; + ptr->GetMetrics(cm, page << 5, 32); + if(page >= 8 && page < 12) + ComposeMetrics(ptr->font, cm, page); + return cm; +} + +FontInfo::CharMetrics *FontInfo::GetPage(int page) const +{ + ASSERT(page >= 0 && page < 64); + ONCELOCK_PTR(ptr->base[page], CreateMetricsPage(page)); + return ptr->base[page]; +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/FontWin32.cpp b/uppdev/Draw/FontWin32.cpp new file mode 100644 index 000000000..5bc38ab7e --- /dev/null +++ b/uppdev/Draw/FontWin32.cpp @@ -0,0 +1,412 @@ +#include "Draw.h" + +NAMESPACE_UPP + +#ifdef PLATFORM_WIN32 + +#define LLOG(x) // LOG(x) +#define LTIMING(x) + +struct FontFaceInfo : Moveable { + String name; + dword info; + + FontFaceInfo() { info = 0; } +}; + +static VectorMap& sFontFace() +{ + static VectorMap s; + return s; +} + +int Font::GetFaceCount() +{ + ONCELOCK { + FontInfo::InitFonts(); + } + return sFontFace().GetCount(); +} + +String Font::GetFaceName(int index) { + ONCELOCK { + FontInfo::InitFonts(); + } + return index >= 0 && index < sFontFace().GetCount() ? sFontFace()[index].name + : Null; +} + +dword Font::GetFaceInfo(int index) { + ONCELOCK { + FontInfo::InitFonts(); + } + return index >= 0 && index < sFontFace().GetCount() ? sFontFace()[index].info + : 0; +} + +void Win32_GetGlyphIndices(HDC hdc, LPCWSTR s, int n, LPWORD r, DWORD flag) +{ + typedef DWORD (WINAPI *GGIW)(HDC, LPCWSTR, int, LPWORD, DWORD); + static GGIW fn; + ONCELOCK + if(HMODULE hDLL = LoadLibrary("gdi32")) + fn = (GGIW) GetProcAddress(hDLL, "GetGlyphIndicesW"); + if(fn) + fn(hdc, s, n, r, flag); + else + memset(r, 0, n * sizeof(WORD)); +} + +int CALLBACK FontInfo::AddFace(const LOGFONT *logfont, const TEXTMETRIC *, dword type, LPARAM param) +{ +#ifdef PLATFORM_WINCE + const wchar *facename = (const wchar *)param; + if(facename && _wcsicmp(logfont->lfFaceName, facename)) + return 1; +#else + const char *facename = (const char *)param; + if(facename && stricmp(logfont->lfFaceName, facename)) + return 1; +#endif + + dword typ = 0; + if((logfont->lfPitchAndFamily & 3) == FIXED_PITCH) + typ |= Font::FIXEDPITCH; + if(type & TRUETYPE_FONTTYPE) + typ |= Font::SCALEABLE; + if(logfont->lfCharSet == SYMBOL_CHARSET) + typ |= Font::SYMBOLTYPE; + else + if(logfont->lfCharSet != 0) + typ |= Font::LOCAL; +#ifndef PLATFORM_WINCE + { + HDC hdc = CreateIC("DISPLAY", NULL, NULL, NULL); + HFONT hfnt = (HFONT) CreateFontIndirect(logfont); + HFONT o = (HFONT) SelectObject(hdc, hfnt); + wchar wch[128]; + WORD pos[128]; + for(int i = 0; i < 128; i++) + wch[i] = i + 256; + Win32_GetGlyphIndices(hdc, (LPCWSTR) wch, 128, pos, 1); + SelectObject(hdc, o); + DeleteObject(hfnt); + DeleteDC(hdc); + int n = 0; + for(int i = 0; i < 128; i++) + if(pos[i] == 0xffff) + n++; + if(n > 10) + typ |= Font::COMPOSED; + } +#endif +#ifdef PLATFORM_WINCE + if(facename) { + FontFaceInfo& f = sFontFace().Add(WString(logfont->lfFaceName).ToString()); + f.name = WString(facename).ToString(); + return 0; + } + FontFaceInfo& f = sFontFace().Add(WString(logfont->lfFaceName).ToString()); + f.name = FromSystemCharset(logfont->lfFaceName); +#else + if(facename) { + FontFaceInfo& f = sFontFace().Add(logfont->lfFaceName); + f.name = facename; + f.info = typ; + return 0; + } + FontFaceInfo& f = sFontFace().Add(logfont->lfFaceName); + f.name = FromSystemCharset(logfont->lfFaceName); +#endif + f.info |= typ; + return 1; +} + +int FontInfo::EnumFace(HDC hdc, const char *face) +{ +#ifdef PLATFORM_WINCE + return EnumFontFamilies(hdc, ToSystemCharset(face), AddFace, (LPARAM)~ToSystemCharset(face)); +#else + return EnumFontFamilies(hdc, face, AddFace, (LPARAM)face); +#endif +} + +void FontInfo::ForceFace(HDC hdc, const char *face, const char *aface) +{ + if(!aface) + aface = "Arial"; + if(EnumFace(hdc, face) && (aface == NULL || EnumFace(hdc, aface))) + Panic("Missing font " + String(face)); +} + +#ifdef PLATFORM_WINCE +const char *FontScreenSans = "Tahoma"; //TODO! +const char *FontScreenSerif = "Tahoma"; +const char *FontScreenFixed = "Courier New"; +const char *FontRoman = "Tahoma" ; +const char *FontArial = "Tahoma"; +const char *FontCourier = "Tahoma"; +const char *FontSymbol = "Tahoma"; +const char *FontWingdings = "Tahoma"; +const char *FontTahoma = "Tahoma"; +#else +const char *FontScreenSans = "Arial"; +const char *FontScreenSerif = "Times New Roman"; +const char *FontScreenFixed = "Courier New"; +const char *FontRoman = "Times New Roman" ; +const char *FontArial = "Arial"; +const char *FontCourier = "Courier New"; +const char *FontSymbol = "Symbol"; +const char *FontWingdings = "WingDings"; +const char *FontTahoma = "Tahoma"; +#endif + +void FontInfo::InitPlatformFonts() { +#ifdef PLATFORM_WINCE + HDC hdc = CreateDC(NULL, NULL, NULL, NULL); +#else + HDC hdc = CreateIC("DISPLAY", NULL, NULL, NULL); +#endif + ForceFace(hdc, "Arial", NULL); + ForceFace(hdc, FontScreenSerif, FontScreenSans); + ForceFace(hdc, FontScreenSans, FontScreenSans); + ForceFace(hdc, FontScreenFixed, FontScreenSans); + ForceFace(hdc, FontRoman, FontScreenSans); + ForceFace(hdc, FontArial, FontScreenSans); + ForceFace(hdc, FontCourier, FontScreenSans); + ForceFace(hdc, FontSymbol, FontScreenSans); + ForceFace(hdc, FontWingdings, FontArial); + ForceFace(hdc, FontTahoma, FontArial); + EnumFace(hdc, NULL); + DeleteDC(hdc); +#ifdef PLATFORM_WINCE + SetStdFont(Arial(10)); +#else + NONCLIENTMETRICS ncm; + ncm.cbSize = sizeof(ncm); + ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0); + SetStdFont(Font(Font::FindFaceNameIndex(ncm.lfMenuFont.lfFaceName), + abs((int)ncm.lfMenuFont.lfHeight))); +#endif +} + +FontInfo::Data::Data() +{ + refcount = 1; + hfont = NULL; + for(int i = 0; i < 64; i++) + base[i] = NULL; +} + +FontInfo::Data::~Data() +{ + DrawLock __; + if(hfont) + DeleteObject(hfont); + for(int i = 0; i < 64; i++) + if(base[i]) delete[] base[i]; +} + +bool FontInfo::Data::HasChar(int ch) const +{ + HDC hdc = ScreenHDC(); + HFONT ohfont = (HFONT) ::SelectObject(hdc, hfont); + WCHAR c = ch; + WORD pos; + Win32_GetGlyphIndices(hdc, &c, 1, &pos, 1); + ::SelectObject(hdc, ohfont); + return pos != 0xffff; +} + +int sGetCW(HDC hdc, wchar *h, int n) +{ + SIZE sz; + return GetTextExtentPoint32W(hdc, h, n, &sz) ? sz.cx : 0; +} + +void FontInfo::Data::GetMetrics(CharMetrics *t, int from, int count) +{ + DrawLock __; + HDC hdc = ScreenHDC(); + HFONT ohfont = (HFONT) ::SelectObject(hdc, hfont); + if(from >= 8192) { + wchar h[3]; + h[0] = 'x'; + h[1] = 'x'; + h[2] = 'x'; + int w0 = sGetCW(hdc, h, 2); + for(int i = 0; i < count; i++) { + h[1] = from + i; + t[i].width = sGetCW(hdc, h, 3) - w0; + t[i].lspc = t[i].rspc = 0; + } + } + else { + bool abca = false, abcw = false; + Buffer abc(count); +#ifdef PLATFORM_WINCE + if(scaleable) + abcw = ::GetCharABCWidths(hdc, from, from + count - 1, abc); +#else + if(scaleable && !(abcw = ::GetCharABCWidthsW(hdc, from, from + count - 1, abc))) + abca = ::GetCharABCWidthsA(hdc, from, from + count - 1, abc); +#endif + if(abcw) + { + for(ABC *s = abc, *lim = abc + count; s < lim; s++, t++) + { + t->width = s->abcA + s->abcB + s->abcC; + t->lspc = s->abcA; + t->rspc = s->abcC; + } + } + else + { + Buffer wb(count); +#ifdef PLATFORM_WINCE + ::GetCharWidth32(hdc, from, from + count - 1, wb); +#else + ::GetCharWidthW(hdc, from, from + count - 1, wb); +#endif + for(int *s = wb, *lim = wb + count; s < lim; s++, t++) + { + t->width = *s - overhang; + if(abca) + { + ABC aa = abc[(byte)ToAscii(from++)]; + t->lspc = aa.abcA; + t->rspc = aa.abcC; + } + else + t->lspc = t->rspc = 0; + } + } + } + ::SelectObject(hdc, ohfont); +} + +FontInfo FontInfo::AcquireFontInfo0(Font font, HDC hdc, int angle) +{ + DrawLock __; + if(IsNull(font)) + font = StdFont(); + if(font.GetFace() == 0) + font.Face(AStdFont.GetFace()); + if(font.GetHeight() == 0) + font.Height(AStdFont.GetHeight()); +// if(font.GetFace() >= sFontFace().GetCount()) +// font.SetFace(Font::ARIAL); + FontInfo::Data *f, *fh; + f = fh = GetFontHash((font.GetHashValue() ^ angle) % FONTHASH); + LLOG("Acquire " << font); + for(;;) { + f = f->GetNext(HASH); + if(f == fh) break; + if(f->font == font && f->angle == angle) + { + LLOG("Reusing " << f->font << " count:" << f->count); + if(f->InList(LRU)) { + f->Unlink(LRU); + FontCached--; + LLOG("Removing from cache " << f->font << " count:" << f->count << + " cached:" << FontCached); + } + f->refcount++; + return f; + } + } + LLOG("New " << font); + LTIMING("Acquire New"); + f = fh->InsertNext(HASH); + f->font = font; + f->angle = angle; + + byte chrset; + if((sFontFace()[font.GetFace()].info & Font::SCALEABLE) == 0) + chrset = DEFAULT_CHARSET; + else + if(sFontFace()[font.GetFace()].info & Font::SYMBOLTYPE) + chrset = SYMBOL_CHARSET; + else + chrset = DEFAULT_CHARSET; +#ifdef PLATFORM_WINCE + LOGFONT lfnt; + Zero(lfnt); + lfnt.lfHeight = font.GetHeight() ? -abs(font.GetHeight()) : -12; + lfnt.lfWeight = font.IsBold() ? FW_BOLD : FW_NORMAL; + lfnt.lfItalic = font.IsItalic(); + lfnt.lfUnderline = font.IsUnderline(); + lfnt.lfStrikeOut = font.IsStrikeout(); + wcscpy(lfnt.lfFaceName, ToSystemCharset(font.GetFaceName())); + f->hfont = CreateFontIndirect(&lfnt); +#else + f->hfont = CreateFont(font.GetHeight() ? -abs(font.GetHeight()) : -12, + font.GetWidth(), angle, angle, font.IsBold() ? FW_BOLD : FW_NORMAL, + font.IsItalic(), font.IsUnderline(), font.IsStrikeout(), + chrset, + font.IsTrueTypeOnly() ? OUT_TT_ONLY_PRECIS : OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + font.IsNonAntiAliased() ? NONANTIALIASED_QUALITY + : DEFAULT_QUALITY, + DEFAULT_PITCH|FF_DONTCARE, + sFontFace().GetKey(font.GetFace())); +#endif + ASSERT(f->hfont); + TEXTMETRIC tm; + HFONT hfont = (HFONT) ::SelectObject(hdc, f->hfont); + ::GetTextMetrics(hdc, &tm); + f->ascent = tm.tmAscent; + f->descent = tm.tmDescent; + f->external = tm.tmExternalLeading; + f->internal = tm.tmInternalLeading; + f->height = f->ascent + f->descent; + f->lineheight = f->height + f->external; + f->overhang = tm.tmOverhang; + f->avewidth = tm.tmAveCharWidth; + f->maxwidth = tm.tmMaxCharWidth; + f->firstchar = tm.tmFirstChar; + f->charcount = tm.tmLastChar - tm.tmFirstChar + 1; + f->default_char = tm.tmDefaultChar; + f->fixedpitch = (tm.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0; + f->scaleable = tm.tmPitchAndFamily & TMPF_TRUETYPE; + f->kerning.Clear(); + if(f->scaleable) { + ABC abc; + GetCharABCWidths(hdc, 'o', 'o', &abc); + f->spacebefore = abc.abcA; + f->spaceafter = abc.abcC; + } + else + f->spacebefore = f->spaceafter = 0; +#ifndef PLATFORM_WINCE + int n = ::GetKerningPairs(hdc, 0, NULL); + if(n) { + Buffer kp(n); + ::GetKerningPairs(hdc, n, kp); + const KERNINGPAIR *p = kp; + while(n--) { + f->kerning.Add(MAKELONG(p->wFirst, p->wSecond), p->iKernAmount); + p++; + } + } +#endif + ::SelectObject(hdc, hfont); + f->offset = Size(0, f->ascent); + if(angle) { + FontInfo font0 = AcquireFontInfo0(font, hdc, 0); + double sina, cosa; + Draw::SinCos(angle, sina, cosa); + f->offset.cx = fround(font0.GetAscent() * sina); + f->offset.cy = fround(font0.GetAscent() * cosa); + } + return FontInfo(f); +} + +FontInfo FontInfo::AcquireFontInfo(Font font, int angle) +{ + return AcquireFontInfo0(font, ScreenHDC(), angle); +} + +#endif + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/Image.cpp b/uppdev/Draw/Image.cpp new file mode 100644 index 000000000..23b45a635 --- /dev/null +++ b/uppdev/Draw/Image.cpp @@ -0,0 +1,702 @@ +#include "Draw.h" + +NAMESPACE_UPP + +#define LTIMING(x) // RTIMING(x) + +int ImageBuffer::ScanKind() const +{ + bool a255 = false; + bool a0 = false; + const RGBA *s = pixels; + const RGBA *e = s + GetLength(); + while(s < e) { + if(s->a == 0) + a0 = true; + else + if(s->a == 255) + a255 = true; + else + return IMAGE_ALPHA; + s++; + } + return a255 ? a0 ? IMAGE_MASK : IMAGE_OPAQUE : IMAGE_EMPTY; +} + +void ImageBuffer::Create(int cx, int cy) +{ + ASSERT(cx >= 0 && cy >= 0); + size.cx = cx; + size.cy = cy; + pixels.Alloc(GetLength()); +#ifdef _DEBUG + RGBA *s = pixels; + RGBA *e = pixels + GetLength(); + byte a = 0; + while(s < e) { + s->a = a; + a = ~a; + s->r = 255; + s->g = s->b = 0; + s++; + } +#endif + kind = IMAGE_UNKNOWN; + spot2 = hotspot = Point(0, 0); + dots = Size(0, 0); +} + +void ImageBuffer::DeepCopy(const ImageBuffer& img) +{ + Create(img.GetSize()); + SetHotSpot(img.GetHotSpot()); + Set2ndSpot(img.Get2ndSpot()); + SetDots(img.GetDots()); + memcpy(pixels, img.pixels, GetLength() * sizeof(RGBA)); +} + +void ImageBuffer::Set(Image& img) +{ + if(img.data) + if(img.data->refcount == 1) { + size = img.GetSize(); + kind = IMAGE_UNKNOWN; + hotspot = img.GetHotSpot(); + spot2 = img.Get2ndSpot(); + dots = img.GetDots(); + pixels = img.data->buffer.pixels; + img.Clear(); + } + else { + DeepCopy(img.data->buffer); + kind = IMAGE_UNKNOWN; + img.Clear(); + } + else + Create(0, 0); +} + + +void ImageBuffer::operator=(Image& img) +{ + Clear(); + Set(img); +} + +void ImageBuffer::operator=(ImageBuffer& img) +{ + Clear(); + Image m = img; + Set(m); +} + +ImageBuffer::ImageBuffer(Image& img) +{ + Set(img); +} + +ImageBuffer::ImageBuffer(ImageDraw& w) +{ + Image img = w; + Set(img); +} + +ImageBuffer::ImageBuffer(ImageBuffer& b) +{ + kind = b.kind; + size = b.size; + dots = b.dots; + pixels = b.pixels; + hotspot = b.hotspot; + spot2 = b.spot2; +} + +void Image::Set(ImageBuffer& b) +{ + if(b.GetWidth() == 0 || b.GetHeight() == 0) + data = NULL; + else + data = new Data(b); +} + +void Image::Clear() +{ + if(data) + data->Release(); + data = NULL; +} + +Image& Image::operator=(ImageBuffer& img) +{ + if(data) + data->Release(); + Set(img); + return *this; +} + +Image& Image::operator=(const Image& img) +{ + Data *d = data; + data = img.data; + if(data) + data->Retain(); + if(d) + d->Release(); + return *this; +} + +const RGBA* Image::operator~() const +{ + return data ? ~data->buffer : NULL; +} + +Image::operator const RGBA*() const +{ + return data ? ~data->buffer : NULL; +} + +const RGBA* Image::operator[](int i) const +{ + ASSERT(data); + return data->buffer[i]; +} + +Size Image::GetSize() const +{ + return data ? data->buffer.GetSize() : Size(0, 0); +} + +int Image::GetLength() const +{ + return data ? data->buffer.GetLength() : 0; +} + +Point Image::GetHotSpot() const +{ + return data ? data->buffer.GetHotSpot() : Point(0, 0); +} + +Point Image::Get2ndSpot() const +{ + return data ? data->buffer.Get2ndSpot() : Point(0, 0); +} + +Size Image::GetDots() const +{ + return data ? data->buffer.GetDots() : Size(0, 0); +} + +int Image::GetKindNoScan() const +{ + return data ? data->buffer.GetKind() : IMAGE_EMPTY; +} + +int Image::Data::GetKind() +{ + int k = buffer.GetKind(); + if(k != IMAGE_UNKNOWN) + return k; + k = buffer.ScanKind(); + buffer.SetKind(k); + return k; +} + +int Image::GetKind() const +{ + return data ? data->GetKind() : IMAGE_EMPTY; +} + +void Image::PaintImage(Draw& w, int x, int y, const Rect& src, Color c) const +{ + if(data) + data->Paint(w, x, y, src, c); +} + +void Image::Serialize(Stream& s) +{ + int version = 0; + s / version; + Size sz = GetSize(); + Point p = GetHotSpot(); + Size dots = GetDots(); + s % sz % p % dots; + int len = sz.cx * sz.cy; + if(s.IsLoading()) + if(len) { + ImageBuffer b(sz); + if(!s.GetAll(~b, len * sizeof(RGBA))) + s.SetError(); + b.SetDots(dots); + b.SetHotSpot(p); + *this = b; + } + else + Clear(); + else + s.Put(~*this, len * sizeof(RGBA)); +} + +INITBLOCK { + RichValue::Register(); +} + +bool Image::operator==(const Image& img) const +{ + if(GetLength() != img.GetLength()) + return false; + return memcmp(~*this, ~img, GetLength() * sizeof(RGBA)) == 0; +} + +bool Image::operator!=(const Image& img) const +{ + return !operator==(img); +} + +dword Image::GetHashValue() const +{ + return memhash(~*this, GetLength() * sizeof(RGBA)); +} + +Image::Image(const Image& img) +{ + data = img.data; + if(data) + data->Retain(); +} + +Image::Image(Image (*fn)()) +{ + data = NULL; + *this = (*fn)(); +} + +Image::Image(const Value& src) +{ + data = NULL; + if(!IsNull(src)) + *this = RawValue::Extract(src); +} + +Image::Image(ImageBuffer& b) +{ + Set(b); +} + +Image::~Image() +{ + if(data) + data->Release(); +} + +Image::Image(const Init& init) +{ + ASSERT(init.info[0] >= 1); + Size sz; + sz.cx = Peek32le(init.info + 1); + sz.cy = Peek32le(init.info + 5); + ImageBuffer b(sz); + int i = 0; + while(i < init.scan_count) { + UnpackRLE(b[i], (const byte *)init.scans[i], sz.cx); + i++; + } + while(i < sz.cy) + memset(b[i++], 0, sizeof(RGBA) * sz.cx); + b.SetHotSpot(Point(Peek32le(init.info + 9), Peek32le(init.info + 13))); + Set(b); +} + +String Image::ToString() const +{ + return String("Image ").Cat() << GetSize(); +} + +Link Image::Data::ResData[1]; +int Image::Data::ResCount; + +Image::Data::Data(ImageBuffer& b) +: buffer(b) +{ + paintcount = 0; + paintonly = false; + refcount = 1; + INTERLOCKED { + static int64 gserial; + serial = ++gserial; + } + SysInit(); +} + +Image::Data::~Data() +{ + DrawLock __; + SysRelease(); + Unlink(); +} + +void Image::Data::PaintOnlyShrink() +{ + if(paintonly) { + LTIMING("PaintOnlyShrink"); + DrawLock __; + DropPixels___(buffer); + ResCount -= GetResCount(); + Unlink(); + } +} + +Draw& ImageDraw::Alpha() +{ + if(!has_alpha) { + alpha.DrawRect(size, GrayColor(0)); + has_alpha = true; + } + return alpha; +} + +static void sMultiply(ImageBuffer& b, int (*op)(RGBA *t, const RGBA *s, int len)) +{ + if(b.GetKind() != IMAGE_OPAQUE && b.GetKind() != IMAGE_EMPTY) + (*op)(~b, ~b, b.GetLength()); +} + +void Premultiply(ImageBuffer& b) +{ + sMultiply(b, Premultiply); +} + +void Unmultiply(ImageBuffer& b) +{ + sMultiply(b, Unmultiply); +} + +static Image sMultiply(const Image& img, int (*op)(RGBA *t, const RGBA *s, int len)) +{ + int k = img.GetKind(); + if(k == IMAGE_OPAQUE || k == IMAGE_EMPTY) + return img; + ImageBuffer ib(img.GetSize()); + ib.SetHotSpot(img.GetHotSpot()); + ib.Set2ndSpot(img.Get2ndSpot()); + ib.SetKind(Premultiply(~ib, ~img, ib.GetLength())); + return ib; +} + +Image Premultiply(const Image& img) +{ + return sMultiply(img, Premultiply); +} + +Image Unmultiply(const Image& img) +{ + return sMultiply(img, Unmultiply); +} + +void SetPaintOnly___(Image& m) +{ + if(m.data && m.data->refcount == 1) + m.data->paintonly = true; +} + +void Iml::Init(int n) +{ + for(int i = 0; i < n; i++) + map.Add(name[i]); +} + +void Iml::Reset() +{ + int n = map.GetCount(); + map.Clear(); + Init(n); +} + +void Iml::Set(int i, const Image& img) +{ + map[i].image = img; + map[i].loaded = true; +} + +static StaticCriticalSection sImgImlLock; + +Image Iml::Get(int i) +{ + IImage& m = map[i]; + if(!m.loaded) { + INTERLOCKED_(sImgImlLock) { + if(data.GetCount()) { + int ii = 0; + for(;;) { + const Data& d = data[ii]; + if(i < d.count) { + static const char *cached_data; + static Vector cached; + if(cached_data != d.data) { + cached_data = d.data; + cached = UnpackImlData(String(d.data, d.len)); + if(premultiply) + for(int i = 0; i < cached.GetCount(); i++) + cached[i] = Premultiply(cached[i]); + } + m.image = cached[i]; + break; + } + i -= d.count; + ii++; + } + } + else + m.image = Premultiply(Image(img_init[i])); + } + m.loaded = true; + } + return m.image; +} + +#ifdef _DEBUG +int Iml::GetBinSize() const +{ + int size = 0; + for(int i = 0; i < map.GetCount(); i++) { + const Image::Init& init = img_init[i]; + size += (int)strlen(name[i]) + 1 + 24; + for(int q = 0; q < init.scan_count; q++) + size += (int)strlen(init.scans[q]); + } + return size; +} +#endif + +Iml::Iml(const Image::Init *img_init, const char **name, int n) +: img_init(img_init), + name(name) +{ +#ifdef flagCHECKINIT + RLOG("Constructing iml " << *name); +#endif + premultiply = true; + Init(n); +} + +void Iml::AddData(const byte *_data, int len, int count) +{ + Data& d = data.Add(); + d.data = (const char *)_data; + d.len = len; + d.count = count; + data.Shrink(); +} + +static StaticCriticalSection sImgMapLock; + +static VectorMap& sImgMap() +{ + static VectorMap x; + return x; +} + +void Register(const char *imageclass, Iml& list) +{ +#ifdef flagCHECKINIT + RLOG("Registering iml " << imageclass); +#endif + INTERLOCKED_(sImgMapLock) + sImgMap().GetAdd(imageclass) = &list; +} + +int GetImlCount() +{ + int q; + INTERLOCKED_(sImgMapLock) + q = sImgMap().GetCount(); + return q; +} + +Iml& GetIml(int i) +{ + return *sImgMap()[i]; +} + +void Iml::Enter() +{ + sImgMapLock.Enter(); +} + +void Iml::Leave() +{ + sImgMapLock.Leave(); +} + +String GetImlName(int i) +{ + String x; + INTERLOCKED_(sImgMapLock) + x = sImgMap().GetKey(i); + return x; +} + +int FindIml(const char *name) +{ + int q; + INTERLOCKED_(sImgMapLock) + q = sImgMap().Find(name); + return q; +} + +Image GetImlImage(const char *name) +{ + Image m; + const char *w = strchr(name, ':'); + if(w) { + int q = FindIml(String(name, w)); + if(q >= 0) { + INTERLOCKED_(sImgMapLock) { + Iml& iml = *sImgMap()[q]; + while(*w == ':') + w++; + q = iml.Find(w); + if(q >= 0) + m = iml.Get(q); + } + } + } + return m; +} + +void SetImlImage(const char *name, const Image& m) +{ + const char *w = strchr(name, ':'); + if(w) { + int q = FindIml(String(name, w)); + if(q >= 0) { + INTERLOCKED_(sImgMapLock) { + Iml& iml = *sImgMap()[q]; + while(*w == ':') + w++; + q = iml.Find(w); + if(q >= 0) + iml.Set(q, m); + } + } + } +} + +String StoreImageAsString(const Image& img) +{ + if(img.GetKind() == IMAGE_EMPTY) + return Null; + int type = img.GetKind() == IMAGE_OPAQUE ? 3 : 4; + StringStream ss; + ss.Put(type); + Size sz = img.GetSize(); + ss.Put16le(sz.cx); + ss.Put16le(sz.cy); + Point p = img.GetHotSpot(); + ss.Put16le(p.x); + ss.Put16le(p.y); + Size dots = img.GetDots(); + ss.Put16le(dots.cx); + ss.Put16le(dots.cy); + const RGBA *s = img; + const RGBA *e = s + img.GetLength(); + Buffer b(type * img.GetLength()); + byte *t = b; + if(type == 3) + while(s < e) { + *t++ = s->r; + *t++ = s->g; + *t++ = s->b; + s++; + } + else + while(s < e) { + *t++ = s->r; + *t++ = s->g; + *t++ = s->b; + *t++ = s->a; + s++; + } + MemReadStream m(b, type * img.GetLength()); + ZCompress(ss, m); + return ss; +} + +Image LoadImageFromString(const String& src) +{ + if(src.GetLength() < 13) + return Null; + StringStream ss(src); + int type = ss.Get(); + Size sz; + sz.cx = ss.Get16le(); + sz.cy = ss.Get16le(); + if(sz.cx < 0 || sz.cy < 0) + return Null; + Point p; + p.x = ss.Get16le(); + p.y = ss.Get16le(); + if(p.x < 0 || p.y < 0) + return Null; + Size dots; + dots.cx = ss.Get16le(); + dots.cy = ss.Get16le(); + if(dots.cx < 0 || dots.cy < 0) + return Null; + StringStream out; + ZDecompress(out, ss); + String data = out; + if(data.GetLength() != type * sz.cx * sz.cy) + return Image(); + ImageBuffer ib(sz); + ib.SetHotSpot(p); + ib.SetDots(dots); + RGBA *t = ib; + const RGBA *e = t + ib.GetLength(); + const byte *s = data; + if(type == 3) + while(t < e) { + t->r = *s++; + t->g = *s++; + t->b = *s++; + t->a = 255; + t++; + } + else + if(type == 4) + while(t < e) { + t->r = *s++; + t->g = *s++; + t->b = *s++; + t->a = *s++; + t++; + } + else + return Image(); + return ib; +} + +Size GetImageStringSize(const String& src) +{ + if(src.GetLength() < 13) + return Size(0, 0); + StringStream ss(src); + ss.Get(); + Size sz; + sz.cx = ss.Get16le(); + sz.cy = ss.Get16le(); + return sz; +} + +Size GetImageStringDots(const String& src) +{ + if(src.GetLength() < 13) + return Size(0, 0); + StringStream ss(src); + ss.SeekCur(9); + Size sz; + sz.cx = ss.Get16le(); + sz.cy = ss.Get16le(); + return sz; +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/Image.h b/uppdev/Draw/Image.h new file mode 100644 index 000000000..2c0755ace --- /dev/null +++ b/uppdev/Draw/Image.h @@ -0,0 +1,342 @@ +#define NEWIMAGE + +enum ImageKind { + IMAGE_UNKNOWN, + IMAGE_EMPTY, + IMAGE_ALPHA, + IMAGE_MASK, + IMAGE_OPAQUE, +}; + +inline bool operator==(const RGBA& a, const RGBA& b) +{ + return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a; +} + +inline bool operator!=(const RGBA& a, const RGBA& b) +{ + return !(a == b); +} + +inline RGBA RGBAZero() { RGBA c; c.r = c.g = c.b = c.a = 0; return c; } + +void Fill(RGBA *t, const RGBA& src, int n); +void FillColor(RGBA *t, const RGBA& src, int n); + +void Copy(RGBA *t, const RGBA *s, int n); + +int Premultiply(RGBA *t, const RGBA *s, int len); +int Unmultiply(RGBA *t, const RGBA *s, int len); + +void AlphaBlend(RGBA *t, const RGBA *s, int len); +void AlphaBlend(RGBA *t, const RGBA *s, int len, Color color); + +void AlphaBlendOpaque(RGBA *t, const RGBA *s, int len, Color color); +void AlphaBlendOpaque(RGBA *t, const RGBA *s, int len); + +void AlphaBlendStraight(RGBA *b, const RGBA *f, int len); +void AlphaBlendStraight(RGBA *b, const RGBA *f, int len, Color color); +void AlphaBlendStraightOpaque(RGBA *t, const RGBA *s, int len); +void AlphaBlendStraightOpaque(RGBA *t, const RGBA *s, int len, int alpha); + +int GetChMaskPos32(dword mask); +void AlphaBlendOverBgST(RGBA *b, RGBA bg, int len); + +const byte *UnpackRLE(RGBA *t, const byte *src, int len); +String PackRLE(const RGBA *s, int len); + +inline int Grayscale(int r, int g, int b) { return (77 * r + 151 * g + 28 * b) >> 8; } +inline int Grayscale(const RGBA& c) { return Grayscale(c.r, c.g, c.b); } +inline byte Saturate255(int x) { return byte(~(x >> 24) & (x | (-(x >> 8) >> 24)) & 0xff); } + +class Image; +class ImageDraw; + +class ImageBuffer : NoCopy { + mutable int kind; + Size size; + Buffer pixels; + Point hotspot; + Point spot2; + Size dots; + + void Set(Image& img); + void DeepCopy(const ImageBuffer& img); + + RGBA* Line(int i) const { ASSERT(i >= 0 && i < size.cy); return (RGBA *)~pixels + i * size.cx; } + friend void DropPixels___(ImageBuffer& b) { b.pixels.Clear(); } + + friend class Image; + +public: + void SetKind(int k) { kind = k; } + int GetKind() const { return kind; } + int ScanKind() const; + int GetScanKind() const { return kind == IMAGE_UNKNOWN ? ScanKind() : kind; } + + void SetHotSpot(Point p) { hotspot = p; } + Point GetHotSpot() const { return hotspot; } + + void Set2ndSpot(Point p) { spot2 = p; } + Point Get2ndSpot() const { return spot2; } + + void SetDots(Size sz) { dots = sz; } + Size GetDots() const { return dots; } + + Size GetSize() const { return size; } + int GetWidth() const { return size.cx; } + int GetHeight() const { return size.cy; } + int GetLength() const { return size.cx * size.cy; } + + RGBA *operator[](int i) { return Line(i); } + const RGBA *operator[](int i) const { return Line(i); } + RGBA *operator~() { return pixels; } + operator RGBA*() { return pixels; } + const RGBA *operator~() const { return pixels; } + operator const RGBA*() const { return pixels; } + + void Create(int cx, int cy); + void Create(Size sz) { Create(sz.cx, sz.cy); } + bool IsEmpty() const { return (size.cx | size.cy) == 0; } + void Clear() { Create(0, 0); } + + void operator=(Image& img); + void operator=(ImageBuffer& img); + + ImageBuffer() { Create(0, 0); } + ImageBuffer(int cx, int cy) { Create(cx, cy); } + ImageBuffer(Size sz) { Create(sz.cx, sz.cy); } + ImageBuffer(Image& img); + ImageBuffer(ImageDraw& w); + ImageBuffer(ImageBuffer& b); +}; + +void Premultiply(ImageBuffer& b); +void Unmultiply(ImageBuffer& b); + +void SetSurface(Draw& w, int x, int y, int cx, int cy, const RGBA *pixels); + +class Image : public AssignValueTypeNo< Image, 150, Moveable > { +private: + struct Data : Link { + Atomic refcount; + int64 serial; + int paintcount; + + static Link ResData[1]; + static int ResCount; + + void Retain() { AtomicInc(refcount); } + void Release() { if(AtomicDec(refcount) == 0) delete this; } + +#ifdef PLATFORM_WIN32 + LPCSTR cursor_cheat; + HBITMAP hbmp; + HBITMAP hmask; + HBITMAP himg; + RGBA *section; + + void CreateHBMP(HDC dc, const RGBA *data); + int GetResCount() const { return !!hbmp + !!hmask + !!himg; } +#endif + +#ifdef PLATFORM_X11 + int cursor_cheat; + XPicture picture; + XPicture picture8; + int GetResCount() const { return !!picture; } +#endif + + ImageBuffer buffer; + bool paintonly; + + void SysInit(); + void SysRelease(); + int GetKind(); + void Paint(Draw& w, int x, int y, const Rect& src, Color c); + void PaintOnlyShrink(); + + Data(ImageBuffer& b); + ~Data(); + }; + + Data *data; + + static Link ResData[1]; + static int ResCount; + + void Set(ImageBuffer& b); + + friend class ImageBuffer; + friend struct Data; + + friend class Draw; + + void PaintImage(Draw& w, int x, int y, const Rect& src, Color c) const; + + friend void SetPaintOnly___(Image& m); + friend void DrawImageBandRLE(Draw& w, int x, int y, const Image& m, int minp); + +#ifdef PLATFORM_WIN32 +#ifndef PLATFORM_WINCE + void SetCursorCheat(LPCSTR id) { data->cursor_cheat = id; } + LPCSTR GetCursorCheat() const { return data ? data->cursor_cheat : NULL; } + friend Image Win32IconCursor(LPCSTR id, int iconsize, bool cursor); + friend HICON IconWin32(const Image& img, bool cursor); +#endif +#endif + +#ifdef PLATFORM_X11 + void SetCursorCheat(int id) { data->cursor_cheat = id; } + int GetCursorCheat() const { return data ? data->cursor_cheat : -1; } + friend Cursor X11Cursor(const Image&); + friend Image sX11Cursor__(int c); +#endif + +public: + const RGBA* operator~() const; + operator const RGBA*() const; + const RGBA* operator[](int i) const; + + Size GetSize() const; + int GetWidth() const { return GetSize().cx; } + int GetHeight() const { return GetSize().cy; } + int GetLength() const; + Point GetHotSpot() const; + Point Get2ndSpot() const; + Size GetDots() const; + int GetKindNoScan() const; + int GetKind() const; + + int64 GetSerialId() const { return data ? data->serial : 0; } + bool IsSame(const Image& img) const { return GetSerialId() == img.GetSerialId(); } + + bool operator==(const Image& img) const; + bool operator!=(const Image& img) const; + dword GetHashValue() const; + String ToString() const; + + void Serialize(Stream& s); + void Clear(); + + Image& operator=(const Image& img); + Image& operator=(ImageBuffer& img); + + bool IsNullInstance() const { Size sz = GetSize(); return (sz.cx|sz.cy) == 0; } + + bool IsEmpty() const { return IsNullInstance(); } + operator Value() const { return RichValue(*this); } + + Image() { data = NULL; } + Image(const Nuller&) { data = NULL; } + Image(const Value& src); + Image(const Image& img); + Image(Image (*fn)()); + Image(ImageBuffer& b); + ~Image(); + + + static Image Arrow(); + static Image Wait(); + static Image IBeam(); + static Image No(); + static Image SizeAll(); + static Image SizeHorz(); + static Image SizeVert(); + static Image SizeTopLeft(); + static Image SizeTop(); + static Image SizeTopRight(); + static Image SizeLeft(); + static Image SizeRight(); + static Image SizeBottomLeft(); + static Image SizeBottom(); + static Image SizeBottomRight(); + static Image Cross(); + static Image Hand(); + + // IML support ("private"), deprecated - legacy .iml + struct Init { + const char *const *scans; + int16 scan_count; + char info[24]; + }; + explicit Image(const Init& init); +}; + +Image Premultiply(const Image& img); +Image Unmultiply(const Image& img); + +Vector UnpackImlData(const void *ptr, int len); +Vector UnpackImlData(const String& d); + +class Iml { + struct IImage : Moveable { + bool loaded; + Image image; + + IImage() { loaded = false; } + }; + struct Data : Moveable { + const char *data; + int len, count; + }; + Vector data; + VectorMap map; + const Image::Init *img_init; + const char **name; + bool premultiply; + + void Init(int n); + +public: + void Enter(); + void Leave(); + void Reset(); + int GetCount() const { return map.GetCount(); } + String GetId(int i) { return map.GetKey(i); } + Image Get(int i); + int Find(const String& s) const { return map.Find(s); } + void Set(int i, const Image& img); + void Premultiplied() { premultiply = false; } + +#ifdef _DEBUG + int GetBinSize() const; +#endif + + Iml(const Image::Init *img_init, const char **name, int n);//Deprecated - legacy .iml + void AddData(const byte *data, int len, int count); +}; + +void Register(const char *imageclass, Iml& iml); + +int GetImlCount(); +String GetImlName(int i); +Iml& GetIml(int i); +int FindIml(const char *name); +Image GetImlImage(const char *name); +void SetImlImage(const char *name, const Image& m); + +String StoreImageAsString(const Image& img); +Image LoadImageFromString(const String& s); +Size GetImageStringSize(const String& src); +Size GetImageStringDots(const String& src); + +#include "Raster.h" +#include "ImageOp.h" + +#ifdef PLATFORM_WIN32 +#ifndef PLATFORM_WINCE + +Image Win32Icon(LPCSTR id, int iconsize = 0); +Image Win32Icon(int id, int iconsize = 0); +Image Win32Cursor(LPCSTR id); +Image Win32Cursor(int id); +HICON IconWin32(const Image& img, bool cursor = false); +Image Win32DllIcon(const char *dll, int ii, bool large); + +#endif +#endif + +#ifdef PLATFORM_X11 +Cursor X11Cursor(const Image& img); +#endif diff --git a/uppdev/Draw/ImageBlit.cpp b/uppdev/Draw/ImageBlit.cpp new file mode 100644 index 000000000..5ce7ddc2c --- /dev/null +++ b/uppdev/Draw/ImageBlit.cpp @@ -0,0 +1,399 @@ +#include "Draw.h" + +NAMESPACE_UPP + +void Fill(RGBA *t, const RGBA& src, int n) +{ + while(n--) + *t++ = src; +} + +void FillColor(RGBA *t, const RGBA& src, int n) +{ + while(n--) { + t->r = src.r; + t->g = src.g; + t->b = src.b; + t++; + } +} + +void Copy(RGBA *t, const RGBA *s, int n) +{ + while(n--) + *t++ = *s++; +} + +const byte *UnpackRLE(RGBA *t, const byte *s, int len) +{ + RGBA *e = t + len; + while(t < e) + if(*s & 0x80) { + if(*s == 0x80) + break; + int count = min((int)(*s & 0x3F), (int)(e - t)); + RGBA h; + if(*s++ & 0x40) + Zero(h); + else { + h.b = s[0]; + h.g = s[1]; + h.r = s[2]; + h.a = 255; + s += 3; + } + count = min(count, (int)(e - t)); + memsetex(t, &h, sizeof(RGBA), count); + t += count; + } + else { + if(*s == 0) + break; + int count = *s++; + while(count-- && t < e) { + RGBA h; + h.b = s[0]; + h.g = s[1]; + h.r = s[2]; + h.a = 255; + *t++ = h; + s += 3; + } + } + while(t < e) + Zero(*t++); + return s; +} + +String PackRLE(const RGBA *s, int len) +{ + StringBuffer r; + const RGBA *e = s + len; + while(s < e) { + const RGBA *q = s; + if(s->a == 0) { + s++; + while(s < e && s->a == 0 && s - q < 0x3f) + s++; + r.Cat((0x80|0x40) + (int)(s - q)); + } + else + if(s + 1 < e && s[0] == s[1]) { + s++; + while(s + 1 < e && s[0] == s[1] && s - q < 0x3e) + s++; + s++; + r.Cat(0x80 + (int)(s - q)); + r.Cat(q->b); + r.Cat(q->g); + r.Cat(q->r); + } + else { + s++; + while(s + 1 < e && s->a && s[0] != s[1] && s - q < 0x3f) + s++; + r.Cat((int)(s - q)); + while(q < s) { + r.Cat(q->b); + r.Cat(q->g); + r.Cat(q->r); + q++; + } + } + } + return r; +} + +int Premultiply(RGBA *t, const RGBA *s, int len) +{ + const RGBA *e = s + len; + while(s < e) { + if(s->a != 255) { + while(s < e) { + byte a = s->a; + if(s->a != 0 && s->a != 255) { + while(s < e) { + int alpha = s->a + (s->a >> 7); + t->r = alpha * (s->r) >> 8; + t->g = alpha * (s->g) >> 8; + t->b = alpha * (s->b) >> 8; + t->a = s->a; + s++; + t++; + } + return IMAGE_ALPHA; + } + t->r = a & s->r; + t->g = a & s->g; + t->b = a & s->b; + t->a = s->a; + s++; + t++; + } + return IMAGE_MASK; + } + *t++ = *s++; + } + return IMAGE_OPAQUE; +} + +int um_table__[256]; + +void sInitUmTable__() +{ + ONCELOCK { + for(int i = 1; i < 256; i++) + um_table__[i] = 65536 / i; + } +} + +int Unmultiply(RGBA *t, const RGBA *s, int len) +{ + sInitUmTable__(); + const RGBA *e = s + len; + while(s < e) { + if(s->a != 255) { + while(s < e) { + byte a = s->a; + if(s->a != 0 && s->a != 255) { + while(s < e) { + int alpha = um_table__[s->a]; + t->r = (alpha * s->r) >> 8; + t->g = (alpha * s->g) >> 8; + t->b = (alpha * s->b) >> 8; + t->a = s->a; + s++; + t++; + } + return IMAGE_ALPHA; + } + t->r = a & s->r; + t->g = a & s->g; + t->b = a & s->b; + t->a = s->a; + s++; + t++; + } + return IMAGE_MASK; + } + *t++ = *s++; + } + return IMAGE_OPAQUE; +} + +void AlphaBlend(RGBA *t, const RGBA *s, int len) +{ + const RGBA *e = s + len; + while(s < e) { + int alpha = 256 - (s->a + (s->a >> 7)); + t->r = s->r + (alpha * t->r >> 8); + t->g = s->g + (alpha * t->g >> 8); + t->b = s->b + (alpha * t->b >> 8); + t->a = s->a + (alpha * t->a >> 8); + s++; + t++; + } +} + +void AlphaBlendOpaque(RGBA *t, const RGBA *s, int len) +{ + const RGBA *e = s + len; + while(s < e) { + int alpha = 256 - (s->a + (s->a >> 7)); + t->r = s->r + (alpha * t->r >> 8); + t->g = s->g + (alpha * t->g >> 8); + t->b = s->b + (alpha * t->b >> 8); + t->a = 255; + s++; + t++; + } +} + +void AlphaBlend(RGBA *t, const RGBA *s, int len, Color color) +{ + const RGBA *e = s + len; + int r = color.GetR(); + int g = color.GetG(); + int b = color.GetB(); + while(s < e) { + int alpha = s->a + (s->a >> 7); + t->r += alpha * (r - t->r) >> 8; + t->g += alpha * (g - t->g) >> 8; + t->b += alpha * (b - t->b) >> 8; + t->a = s->a + ((256 - alpha) * t->a >> 8); + s++; + t++; + } +} + +void AlphaBlendOpaque(RGBA *t, const RGBA *s, int len, Color color) +{ + const RGBA *e = s + len; + int r = color.GetR(); + int g = color.GetG(); + int b = color.GetB(); + while(s < e) { + int alpha = s->a + (s->a >> 7); + t->r += alpha * (r - t->r) >> 8; + t->g += alpha * (g - t->g) >> 8; + t->b += alpha * (b - t->b) >> 8; + t->a = 255; + s++; + t++; + } +} + +void AlphaBlendStraightOpaque(RGBA *t, const RGBA *s, int len) +{ + const RGBA *e = s + len; + while(s < e) { + int alpha = s->a + (s->a >> 7); + t->r += alpha * (s->r - t->r) >> 8; + t->g += alpha * (s->g - t->g) >> 8; + t->b += alpha * (s->b - t->b) >> 8; + t->a = 255; + s++; + t++; + } +} + +void AlphaBlendStraightOpaque(RGBA *t, const RGBA *s, int len, int alpha) +{ + if(alpha >= 256) { + AlphaBlendStraightOpaque(t, s, len); + return; + } + const RGBA *e = s + len; + alpha *= 0x102; + while(s < e) { + int a = (s->a * alpha) >> 16; + t->r += a * (s->r - t->r) >> 8; + t->g += a * (s->g - t->g) >> 8; + t->b += a * (s->b - t->b) >> 8; + t->a = 255; + s++; + t++; + } +} + +struct sBlends { + int16 m; + byte a; +}; + +sBlends *sblends; + +void sOnceInitBlends() +{ + ONCELOCK { + sblends = (sBlends *)MemoryAllocPermanent(256 * 256 * sizeof(sBlends)); + for(int Fa = 0; Fa <= 255; Fa++) + for(int Ba = 0; Ba <= 255; Ba++) { + double A = (Fa / 255.0 + Ba / 255.0 - Fa / 255.0 * Ba / 255.0); + sblends[(Ba << 8) + Fa].a = minmax((int)(255 * A + 0.5), 0, 255); + sblends[(Ba << 8) + Fa].m = A > 0.001 ? int(256 * (Fa / 255.0) / A + 0.5) : 0; + } + } +} + +inline void sInitBlends() +{ + if(!sblends) + sOnceInitBlends(); +} + +void AlphaBlendStraight(RGBA *b, const RGBA *f, int len) +{ + sInitBlends(); + const RGBA *e = f + len; + while(f < e) { + sBlends& x = sblends[(b->a << 8) + f->a]; + int m = x.m; + b->a = x.a; + b->r += m * (f->r - b->r) >> 8; + b->g += m * (f->g - b->g) >> 8; + b->b += m * (f->b - b->b) >> 8; + b++; + f++; + } +} + +void AlphaBlendOverBgStraight(RGBA *b, RGBA bg, int len) +{ + sInitBlends(); + const RGBA *e = b + len; + while(b < e) { + sBlends& x = sblends[(bg.a << 8) + b->a]; + int m = x.m; + b->a = x.a; + b->r = bg.r + (m * (b->r - bg.r) >> 8); + b->g = bg.g + (m * (b->g - bg.g) >> 8); + b->b = bg.b + (m * (b->b - bg.b) >> 8); + b++; + } +} + +void AlphaBlendStraight(RGBA *b, const RGBA *f, int len, Color color) +{ + sInitBlends(); + const RGBA *e = f + len; + int cr = color.GetR(); + int cg = color.GetG(); + int cb = color.GetB(); + while(f < e) { + sBlends& x = sblends[(b->a << 8) + f->a]; + int m = x.m; + b->a = x.a; + b->r += m * (cr - b->r) >> 8; + b->g += m * (cg - b->g) >> 8; + b->b += m * (cb - b->b) >> 8; + b++; + f++; + } +} + +int GetChMaskPos32(dword mask) +{ + if(mask == 0xff000000) + return 3; + if(mask == 0xff0000) + return 2; + if(mask == 0xff00) + return 1; + return 0; +} + +Vector UnpackImlData(const void *ptr, int len) +{ + Vector img; + String data = ZDecompress(ptr, len); + const char *s = data; + while(s + 6 * 2 + 1 <= data.End()) { + ImageBuffer ib(Peek16le(s + 1), Peek16le(s + 3)); + ib.SetHotSpot(Point(Peek16le(s + 5), Peek16le(s + 7))); + ib.Set2ndSpot(Point(Peek16le(s + 9), Peek16le(s + 11))); + s += 13; + int len = ib.GetLength(); + RGBA *t = ib; + const RGBA *e = t + len; + if(s + 4 * len > data.End()) + break; + while(t < e) { + t->a = s[3]; + t->r = s[0]; + t->g = s[1]; + t->b = s[2]; + s += 4; + t++; + } + img.Add() = ib; + } + return img; +} + +Vector UnpackImlData(const String& d) +{ + return UnpackImlData(~d, d.GetLength()); +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/ImageChOp.cpp b/uppdev/Draw/ImageChOp.cpp new file mode 100644 index 000000000..7bdd2c91f --- /dev/null +++ b/uppdev/Draw/ImageChOp.cpp @@ -0,0 +1,380 @@ +#include "Draw.h" + +NAMESPACE_UPP + +int Diff(RGBA a, RGBA b) +{ + return max(abs(a.a - b.a), max(abs(a.r - b.r), max(abs(a.b - b.b), abs(a.g - b.g)))); +} + +struct InterPoint { + ImageBuffer &b; + Rect rc; + int sr, sg, sb; + int sn, in; + + InterPoint(ImageBuffer& b) : b(b) { + sr = sg = sb = sn = in = 0; + } + void Add(int x, int y); +}; + +void InterPoint::Add(int y, int x) { + if(rc.Contains(x, y)) { + RGBA ba = b[y][x]; + if(ba.a == 0) + return; + in++; + sn++; + sr += ba.r; + sg += ba.g; + sb += ba.b; + } + else + in++; +} + +void Interpolate(ImageBuffer& b, Vector< Vector >& map, const Rect& rc) +{ + Unmultiply(b); + int todo; + do { + todo = 0; + for(int x = rc.left; x < rc.right; x++) + for(int y = rc.top; y < rc.bottom; y++) { + RGBA& p = b[y][x]; + if(map[y][x]) { + map[y][x] = 0; + InterPoint ip(b); + ip.rc = rc; + ip.Add(y - 1, x - 1); + ip.Add(y - 1, x); + ip.Add(y - 1, x + 1); + ip.Add(y, x - 1); + ip.Add(y, x + 1); + ip.Add(y + 1, x - 1); + ip.Add(y + 1, x); + ip.Add(y + 1, x + 1); + if(ip.in >= 2) { + if(ip.sn) { + p.r = ip.sr / ip.sn; + p.g = ip.sg / ip.sn; + p.b = ip.sb / ip.sn; + } + else + p = SColorFace(); + p.a = 255; + } + else + todo++; + } + } + } + while(todo); + Premultiply(b); +} + +struct ButtonDecomposer { + Image src; + Image dst; + int aa[8]; + int maxdiff; + RGBA color; + int gdiff; + int gcount; + + RGBA GetC(int p) { + Size sz = src.GetSize(); + int xx[3]; + int yy[3]; + yy[0] = xx[0] = aa[p]; + xx[1] = sz.cx - aa[p] - 1; + xx[2] = sz.cx / 2; + yy[1] = sz.cy - aa[p] - 1; + yy[2] = sz.cy / 2; + return src[xx[p / 3]][xx[p % 3]]; + } + + void Do() { + Size sz = src.GetSize(); + int qa = min(4, min(sz.cy / 4, sz.cx / 4)); + if(qa == 0) { + dst = src; + return; + } + int a = 0; + for(int p = 0; p < 8; p++) { + aa[p] = qa; + Color c = GetC(p); + while(aa[p] > 0) { + Color c1 = GetC(p); + if(Diff(c, c1) > 30) + break; + c = c1; + aa[p]--; + } + if(aa[p] > a) + a = aa[p]; + } + if(a < min(sz.cx / 3, sz.cy / 3)) + a++; + dst = src; + ImageBuffer b(dst); + color = SColorText(); + maxdiff = gdiff = gcount = 0; + Vector< Vector > map; + for(int y = a; y < sz.cy - a; y++) { + map.At(y).SetCount(sz.cx, false); + RGBA *p = b[y]; + int x = a; + Color c = p[x]; + while(x < sz.cx - a) { + if(Diff(p[x], c) > 30) + break; + c = p[x++]; + } + int xx = sz.cx - a; + while(xx > x) { + if(Diff(p[xx - 1], c) > 30) + break; + c = p[--xx]; + } + for(int q = x; q < xx; q++) { + int d = Diff(p[q], c); + gcount++; + gdiff += d; + if(d >= maxdiff) { + maxdiff = d; + color = p[q]; + } + } + Fill(p + x, RGBAZero(), xx - x); + map[y].Set(x, true, xx - x); + } + Interpolate(b, map, Rect(a, a, sz.cx - a, sz.cy - a)); + if(a < 2) a = 2; + b.SetHotSpot(Point(a, a)); + dst = b; + } +}; + +Image Unglyph(const Image& m, Color& c, double& gfactor) +{ + ButtonDecomposer b; + b.src = Unmultiply(m); + b.Do(); + c = b.color; + gfactor = (double)b.gdiff / b.gcount; + return Premultiply(b.dst); +} + +Image Unglyph(const Image& m, Color& c) +{ + double dummy; + return Unglyph(m, c, dummy); +} + +Image Unglyph(const Image& m) +{ + Color dummy; + return Unglyph(m, dummy); +} + +Image VertBlend(Image img1, Image img2, int y0, int y1) +{ + Size sz = img1.GetSize(); + Size sz2 = img2.GetSize(); + sz.cx = min(sz.cx, sz2.cx); + sz.cy = min(sz.cy, sz2.cy); + ImageBuffer b(sz); + for(int y = 0; y < sz.cy; y++) + if(y >= y1) + memcpy(b[y], img2[y], sz.cx * sizeof(RGBA)); + else + if(y >= y0 && y1 > y0) { + int alpha = 256 * (y - y0) / (y1 - y0); + RGBA *t = b[y]; + const RGBA *s1 = img1[y]; + const RGBA *s2 = img2[y]; + const RGBA *e = s1 + sz.cx; + while(s1 < e) { + t->r = s1->r + ((alpha * (s2->r - s1->r)) >> 8); + t->g = s1->g + ((alpha * (s2->g - s1->g)) >> 8); + t->b = s1->b + ((alpha * (s2->b - s1->b)) >> 8); + t->a = s1->a + ((alpha * (s2->a - s1->a)) >> 8); + s1++; + s2++; + t++; + } + } + else + memcpy(b[y], img1[y], sz.cx * sizeof(RGBA)); + b.SetHotSpot(img1.GetHotSpot()); + b.Set2ndSpot(img1.Get2ndSpot()); + return b; +} + +Image HorzBlend(Image img1, Image img2, int x0, int x1) +{ + Image m = RotateAntiClockwise(VertBlend(RotateClockwise(img1), RotateClockwise(img2), x0, x1)); + ImageBuffer b(m); + b.SetHotSpot(img1.GetHotSpot()); + b.Set2ndSpot(img1.Get2ndSpot()); + return b; +} + +Image HorzSymm(Image src) { + ImageBuffer b(src); + Size sz = b.GetSize(); + for(int y = 0; y < sz.cy; y++) { + RGBA *l = b[y]; + for(int x = 0; x < sz.cx / 2; x++) + l[sz.cx - x - 1] = l[x]; + } + b.SetHotSpot(src.GetHotSpot()); + b.Set2ndSpot(src.Get2ndSpot()); + return b; +} + +bool EqLine(const Image& m, int l1, int l2, int x, int width) +{ + return !memcmp(m[l1] + x, m[l2] + x, width * sizeof(RGBA)); +} + +bool EqLine(const Image& m, int l1, int l2) +{ + return EqLine(m, l1, l2, 0, m.GetWidth()); +} + +bool EqColumn(const Image& m, int c1, int c2, int y, int height) +{ + int cx = m.GetWidth(); + const RGBA *a = m[y] + c1; + const RGBA *b = m[y] + c2; + for(int w = 0; w < height; w++) { + if(*a != *b) + return false; + a += cx; + b += cx; + } + return true; +} + +bool EqColumn(const Image& m, int c1, int c2) +{ + return EqColumn(m, c1, c2, 0, m.GetHeight()); +} + +int ClassifyContent(const Image& m, const Rect& rect) +{ + if(IsNull(rect)) + return 0; + bool vdup = true; + for(int q = rect.top + 1; q < rect.bottom; q++) + if(!EqLine(m, q, rect.top, rect.left, rect.GetWidth())) { + vdup = false; + break; + } + for(int q = rect.left + 1; q < rect.right; q++) + if(!EqColumn(m, rect.left, q, rect.top, rect.GetHeight())) + return vdup; + return 2 + vdup; +} + +Image RecreateAlpha(const Image& overwhite, const Image& overblack) +{ + Size sz = overwhite.GetSize(); + ASSERT(overblack.GetSize() == sz); + ImageBuffer r(sz); + const RGBA *ws = overwhite; + const RGBA *bs = overblack; + RGBA *t = r; + RGBA *e = t + r.GetLength(); + while(t < e) { + t->a = bs->r - ws->r + 255; + if(t->a) { + t->r = bs->r * 255 / t->a; + t->g = bs->g * 255 / t->a; + t->b = bs->b * 255 / t->a; + } + else + t->r = t->g = t->b = 0; + t++; + bs++; + ws++; + } + Premultiply(r); + return r; +} + +int ImageMargin(const Image& _m, int p, int dist) +{ + Image m = Unmultiply(_m); + Color c = m[p][p]; + int d; + Size sz = m.GetSize(); + for(d = p; d >= 0; d--) + if(Diff(m[d][d], c) > dist || Diff(m[sz.cx - d - 1][sz.cy - d - 1], c) > dist) + break; + return d + 1; +} + +int ImageMarginV(const Image& _m, int p, int dist) +{ + Image m = Unmultiply(_m); + Size sz = m.GetSize(); + Color c = m[sz.cx / 2][p]; + int d; + for(d = p; d >= 0; d--) + if(Diff(m[sz.cx / 2][d], c) > dist || Diff(m[sz.cx / 2][sz.cy - d - 1], c) > dist) + break; + return d + 1; +} + +ChPartMaker::ChPartMaker(const Image& m) +{ + image = m; + border = SColorShadow(); + bg = Null; + ResetShape(); +} + +void ChPartMaker::ResetShape() +{ + t = b = l = r = true; + tl = tr = bl = br = 0; +} + +Image ChPartMaker::Make() const +{ + Size sz = image.GetSize(); + ASSERT(sz.cx >= 6 && sz.cy >= 6); + Image h = image; + ImageBuffer ib(h); + for(int x = 0; x < sz.cx; x++) { + if(t) + ib[0][x] = x >= tl && x < sz.cx - tr ? border : bg; + if(b) + ib[sz.cy - 1][x] = x >= bl && x < sz.cx - br ? border : bg; + } + for(int y = 0; y < sz.cy; y++) { + if(l) + ib[y][0] = y >= tl && y < sz.cy - bl ? border : bg; + if(r) + ib[y][sz.cx - 1] = y >= tr && y < sz.cy - br ? border : bg; + } + if(tl == 2) + ib[1][1] = border; + if(tr == 2) + ib[1][sz.cx - 2] = border; + if(bl == 2) + ib[sz.cy - 2][1] = border; + if(br == 2) + ib[sz.cy - 2][sz.cx - 2] = border; + int q = max(max(tl, tr), max(br, bl)); + ib.SetHotSpot(Point(q, q)); + ib.Set2ndSpot(Point(sz.cx - q - 1, sz.cy - q - 1)); + return ib; +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/ImageDraw.h b/uppdev/Draw/ImageDraw.h new file mode 100644 index 000000000..ab84cd831 --- /dev/null +++ b/uppdev/Draw/ImageDraw.h @@ -0,0 +1,38 @@ +class ImageDraw : public Draw { + Size size; + +#ifdef PLATFORM_WIN32 + struct Section { + HDC dc; + HBITMAP hbmp, hbmpOld; + RGBA *pixels; + + void Init(int cx, int cy); + ~Section(); + }; + + Section rgb; + Section a; + SystemDraw alpha; +#endif + +#ifdef PLATFORM_X11 + Draw alpha; +#endif + + bool has_alpha; + + void Init(); + Image Get(bool pm) const; + +public: + Draw& Alpha(); + + operator Image() const; + + Image GetStraight() const; + + ImageDraw(Size sz); + ImageDraw(int cx, int cy); + ~ImageDraw(); +}; diff --git a/uppdev/Draw/ImageOp.cpp b/uppdev/Draw/ImageOp.cpp new file mode 100644 index 000000000..c15bf40da --- /dev/null +++ b/uppdev/Draw/ImageOp.cpp @@ -0,0 +1,665 @@ +#include "Draw.h" + +NAMESPACE_UPP + +Image WithHotSpots(const Image& m, int x1, int y1, int x2, int y2) +{ + Image h = m; + ImageBuffer b(h); + b.SetHotSpot(Point(x1, y1)); + b.Set2ndSpot(Point(x2, y2)); + return b; +} + +Image WithHotSpot(const Image& m, int x1, int y1) +{ + Image h = m; + ImageBuffer b(h); + b.SetHotSpot(Point(x1, y1)); + return b; +} + +Image CreateImage(Size sz, Color color) +{ + ImageBuffer ib(sz); + RGBA rgba = color; + memsetex(ib, &rgba, sizeof(RGBA), ib.GetLength()); + return ib; +} + +Size DstSrc(ImageBuffer& dest, Point& p, const Image& src, Rect& sr) +{ + if(p.x < 0) { + sr.left += -p.x; + p.x = 0; + } + if(p.y < 0) { + sr.top += -p.y; + p.y = 0; + } + sr = sr & src.GetSize(); + Size sz = dest.GetSize() - p; + sz.cx = min(sz.cx, sr.GetWidth()); + sz.cy = min(sz.cy, sr.GetHeight()); + return sz; +} + +void DstSrcOp(ImageBuffer& dest, Point p, const Image& src, const Rect& srect, + void (*op)(RGBA *t, const RGBA *s, int n)) +{ + Rect sr = srect; + Size sz = DstSrc(dest, p, src, sr); + if(sz.cx > 0) + while(--sz.cy >= 0) + (*op)(dest[p.y++] + p.x, src[sr.top++] + sr.left, sz.cx); +} + +void Copy(ImageBuffer& dest, Point p, const Image& src, const Rect& srect) +{ + DstSrcOp(dest, p, src, srect, Copy); +} + +void Over(ImageBuffer& dest, Point p, const Image& src, const Rect& srect) +{ + DstSrcOp(dest, p, src, srect, AlphaBlend); +} + +void OverStraightOpaque(ImageBuffer& dest, Point p, const Image& src, const Rect& srect) +{ + DstSrcOp(dest, p, src, srect, AlphaBlendStraightOpaque); +} + +void Copy(Image& dest, Point p, const Image& _src, const Rect& srect) +{ + Image src = _src; + ImageBuffer b(dest); + Copy(b, p, src, srect); + dest = b; +} + +void Over(Image& dest, Point p, const Image& _src, const Rect& srect) +{ + Image src = _src; + ImageBuffer b(dest); + Over(b, p, src, srect); + dest = b; +} + +void OverStraightOpaque(Image& dest, Point p, const Image& _src, const Rect& srect) +{ + Image src = _src; + ImageBuffer b(dest); + OverStraightOpaque(b, p, src, srect); + dest = b; +} + +void Crop(RasterEncoder& tgt, Raster& img, const Rect& rc) +{ + Rect r = rc & img.GetSize(); + tgt.Create(r.Size(), img); + for(int y = r.top; y < r.bottom; y++) + tgt.WriteLine(~img[y] + r.left); +} + +Image Crop(const Image& img, const Rect& rc) +{ + if(rc.left == 0 && rc.top == 0 && rc.Size() == img.GetSize()) + return img; + if((rc & img.GetSize()).IsEmpty()) + return Image(); + ImageRaster src(img); + ImageEncoder tgt; + Crop(tgt, src, rc); + return tgt; +} + +Image Crop(const Image& img, int x, int y, int cx, int cy) +{ + return Crop(img, RectC(x, y, cx, cy)); +} + +Image ColorMask(const Image& src, Color key) +{ + ImageBuffer ib(src.GetSize()); + const RGBA *s = src; + const RGBA *e = src + src.GetLength(); + RGBA *t = ~ib; + byte kr = key.GetR(); + byte kg = key.GetG(); + byte kb = key.GetB(); + while(s < e) { + if(s->r == kr && s->g == kg && s->b == kb) + *t++ = RGBAZero(); + else + *t++ = *s; + s++; + } + return ib; +} + +void CanvasSize(RasterEncoder& tgt, Raster& img, int cx, int cy) +{ + tgt.Create(cx, cy, img); + int ccx = min(img.GetWidth(), cx); + int ccy = min(img.GetHeight(), cy); + for(int y = 0; y < ccy; y++) { + memcpy(~tgt, img[y], ccx * sizeof(RGBA)); + memset(~tgt + ccx, 0, (cx - ccx) * sizeof(RGBA)); + tgt.WriteLine(); + } + for(int y = cy - ccy; --y >= 0;) { + memset(~tgt, 0, cx * sizeof(RGBA)); + tgt.WriteLine(); + } +} + +Image CanvasSize(const Image& img, int cx, int cy) +{ + ImageRaster src(img); + ImageEncoder tgt; + CanvasSize(tgt, src, cx, cy); + return tgt; +} + +Image AssignAlpha(const Image& img, const Image& alpha) +{ + Size sz = Size(min(img.GetWidth(), alpha.GetWidth()), + min(img.GetHeight(), alpha.GetHeight())); + if(sz.cx == 0 || sz.cy == 0) + return Image(); + ImageBuffer ib(sz); + for(int y = 0; y < sz.cy; y++) { + const RGBA *s = img[y]; + const RGBA *e = s + sz.cx; + const RGBA *a = alpha[y]; + RGBA *t = ib[y]; + while(s < e) { + *t = *s++; + (t++)->a = (a++)->a; + } + } + return ib; +} + +int EqualightCh(int c, int l, int h) +{ + return Saturate255((c - l) * 255 / (h - l) + l); +} + +Image Equalight(const Image& img, int thold) +{ + int histogram[256]; + ZeroArray(histogram); + const RGBA *s = ~img; + const RGBA *e = s + img.GetLength(); + while(s < e) { + histogram[Grayscale(*s)]++; + s++; + } + int n = (thold * img.GetLength()) >> 8; + int h = 255; + int l = 0; + while(l < h) { + if(n < 0) + break; + n -= histogram[l++]; + if(n < 0) + break; + n -= histogram[h--]; + } + if(l >= h) + return img; + ImageBuffer w(img.GetSize()); + RGBA *t = w; + s = ~img; + while(s < e) { + t->r = EqualightCh(s->r, l, h); + t->g = EqualightCh(s->g, l, h); + t->b = EqualightCh(s->b, l, h); + t->a = s->a; + s++; + t++; + } + return w; +} + +Image Grayscale(const Image& img) +{ + const RGBA *s = ~img; + const RGBA *e = s + img.GetLength(); + ImageBuffer w(img.GetSize()); + RGBA *t = w; + while(s < e) { + int q = Grayscale(*s); + t->r = q; + t->g = q; + t->b = q; + t->a = s->a; + t++; + s++; + } + return w; +} + +Image Grayscale(const Image& img, int amount) +{ + const RGBA *s = ~img; + const RGBA *e = s + img.GetLength(); + ImageBuffer w(img.GetSize()); + RGBA *t = w; + int na = 256 - amount; + while(s < e) { + int q = Grayscale(*s); + t->r = Saturate255((amount * q + na * s->r) >> 8); + t->g = Saturate255((amount * q + na * s->g) >> 8); + t->b = Saturate255((amount * q + na * s->b) >> 8); + t->a = s->a; + t++; + s++; + } + return w; +} + +Image Colorize(const Image& img, Color color, int alpha) +{ + const RGBA *s = ~img; + const RGBA *e = s + img.GetLength(); + ImageBuffer w(img.GetSize()); + Unmultiply(w); + RGBA *t = w; + byte r = color.GetR(); + byte g = color.GetG(); + byte b = color.GetB(); + alpha = alpha + (alpha >> 7); + while(s < e) { + int ga = Grayscale(*s); + ga = ga + (ga >> 7); + t->r = (alpha * (((ga * r) >> 8) - s->r) >> 8) + s->r; + t->g = (alpha * (((ga * g) >> 8) - s->g) >> 8) + s->g; + t->b = (alpha * (((ga * b) >> 8) - s->b) >> 8) + s->b; + t->a = s->a; + t++; + s++; + } + Premultiply(w); + return w; +} + +inline +byte ContrastCh(int amount, int ch) +{ + return Saturate255(128 + (amount * (ch - 128) >> 8)); +} + +Image Contrast(const Image& img, int amount) +{ + const RGBA *s = ~img; + const RGBA *e = s + img.GetLength(); + ImageBuffer w(img.GetSize()); + Unmultiply(w); + RGBA *t = w; + while(s < e) { + t->r = ContrastCh(amount, s->r); + t->g = ContrastCh(amount, s->g); + t->b = ContrastCh(amount, s->b); + t->a = s->a; + t++; + s++; + } + Premultiply(w); + return w; +} + +void sLine(RGBA *t, int cx, const RasterLine l[3], ImageFilter9& filter) +{ + RGBA h[3][3]; + const RGBA *x[3]; + x[0] = h[0]; + x[1] = h[1]; + x[2] = h[2]; + if(cx == 1) { + h[0][0] = l[0][0]; h[0][1] = l[0][0]; h[0][2] = l[0][0]; + h[1][0] = l[1][0]; h[1][1] = l[1][0]; h[1][2] = l[1][0]; + h[2][0] = l[2][0]; h[2][1] = l[2][0]; h[2][2] = l[2][0]; + *t = filter(x); + return; + } + h[0][0] = l[0][0]; h[0][1] = l[0][0]; h[0][2] = l[0][1]; + h[1][0] = l[1][0]; h[1][1] = l[1][0]; h[1][2] = l[1][1]; + h[2][0] = l[2][0]; h[2][1] = l[2][0]; h[2][2] = l[2][1]; + *t++ = filter(x); + for(int i = 1; i < cx - 1; i++) { + x[0] = ~l[0] + i - 1; + x[1] = ~l[1] + i - 1; + x[2] = ~l[2] + i - 1; + *t++ = filter(x); + } + h[0][0] = l[0][cx - 2]; h[0][1] = l[0][cx - 1]; h[0][2] = l[0][cx - 1]; + h[1][0] = l[1][cx - 2]; h[1][1] = l[1][cx - 1]; h[1][2] = l[1][cx - 1]; + h[2][0] = l[2][cx - 2]; h[2][1] = l[2][cx - 1]; h[2][2] = l[2][cx - 1]; + x[0] = h[0]; + x[1] = h[1]; + x[2] = h[2]; + *t++ = filter(x); +} + +void Filter(RasterEncoder& target, Raster& src, ImageFilter9& filter) +{ + Size sz = src.GetSize(); + target.Create(sz, src); + if(sz.cy < 1) + return; + RasterLine l[3]; + if(sz.cy == 1) { + l[0] = src[0]; + l[1] = src[0]; + l[2] = src[0]; + sLine(target, sz.cx, l, filter); + return; + } + l[0] = src[0]; + l[1] = src[0]; + l[2] = src[1]; + sLine(target, sz.cx, l, filter); + target.WriteLine(); + for(int y = 1; y < sz.cy - 1; y++) { + l[0] = l[1]; + l[1] = l[2]; + l[2] = src[y + 1]; + sLine(target, sz.cx, l, filter); + target.WriteLine(); + } + l[0] = l[1]; + l[1] = l[2]; + l[2] = src[sz.cy - 1]; + sLine(target, sz.cx, l, filter); + target.WriteLine(); +} + +Image Filter(const Image& img, ImageFilter9& filter) +{ + ImageEncoder tgt; + ImageRaster src(img); + Filter(tgt, src, filter); + return tgt; +} + +struct RGBAI { + int r, g, b, a; + + RGBAI() { r = g = b = a= 0; } +}; + +static void sGetS(RGBA q, RGBAI& p, int mul) +{ + p.r += mul * q.r; + p.g += mul * q.g; + p.b += mul * q.b; + p.a += mul * q.a; +} + +struct sSharpenFilter : ImageFilter9 { + int amount; + + virtual RGBA operator()(const RGBA **mx); +}; + +RGBA sSharpenFilter::operator()(const RGBA **mx) +{ + RGBAI q; + sGetS(mx[0][0], q, 7); + sGetS(mx[0][1], q, 9); + sGetS(mx[0][2], q, 7); + sGetS(mx[1][0], q, 9); + sGetS(mx[1][2], q, 9); + sGetS(mx[2][0], q, 7); + sGetS(mx[2][1], q, 9); + sGetS(mx[2][2], q, 7); + const RGBA& s = mx[1][1]; + RGBA t; + int na = 256 + amount; + t.b = Saturate255((na * (s.b << 6) - amount * q.b) >> 14); + t.g = Saturate255((na * (s.g << 6) - amount * q.g) >> 14); + t.r = Saturate255((na * (s.r << 6) - amount * q.r) >> 14); + t.a = Saturate255((na * (s.a << 6) - amount * q.a) >> 14); + return t; +} + +void Sharpen(RasterEncoder& target, Raster& src, int amount) +{ + Size sz = src.GetSize(); + target.Create(sz, src); + sSharpenFilter f; + f.amount = amount; + Filter(target, src, f); +} + +Image Sharpen(const Image& img, int amount) +{ + ImageEncoder tgt; + ImageRaster src(img); + Sharpen(tgt, src, amount); + return tgt; +} + +struct sEtchFilter : ImageFilter9 { + virtual RGBA operator()(const RGBA **mx); +}; + +RGBA sEtchFilter::operator()(const RGBA **mx) +{ + RGBA t; + RGBA s = mx[1][1]; + if(s.a == 255 && s.r + s.g + s.b < 400) { + t.r = t.g = t.b = 128; + t.a = 255; + return t; + } + s = mx[0][0]; + if(s.a == 255 && s.r + s.g + s.b < 400) { + t.r = t.g = t.b = t.a = 255; + return t; + } + Zero(t); + return t; +} + +Image Etched(const Image& img) +{ + sEtchFilter ef; + return Filter(img, ef); +} + +Image SetColorKeepAlpha(const Image& img, Color c) +{ + RGBA rgba = c; + const RGBA *s = ~img; + const RGBA *e = s + img.GetLength(); + ImageBuffer w(img.GetSize()); + RGBA *t = w; + while(s < e) { + *t = rgba; + (t++)->a = (s++)->a; + } + w.SetHotSpot(img.GetHotSpot()); + w.Set2ndSpot(img.Get2ndSpot()); + return w; +} + +Image CreateHorzFadeOut(Size sz, Color color) +{ + ImageBuffer ib(sz); + RGBA c = color; + for(int q = 0; q < sz.cx; q++) { + c.a = q * 255 / sz.cx; + RGBA *t = ~ib + q; + for(int n = sz.cy; n > 0; n--) { + *t = c; + t += sz.cx; + } + } + Premultiply(ib); + return ib; +} + +struct FadeOutMaker : ImageMaker { + Size sz; + Color color; + + virtual String Key() const { + char h[sizeof(Size) + sizeof(Color)]; + memcpy(h, &sz, sizeof(sz)); + memcpy(h + sizeof(Size), &color, sizeof(Color)); + return String(h, sizeof(h)); + } + + virtual Image Make() const { + return CreateHorzFadeOut(sz, color); + } +}; + +Image HorzFadeOut(Size sz, Color color) +{ + FadeOutMaker m; + m.sz = sz; + m.color = color; + return MakeImage(m); +} + +Image HorzFadeOut(int cx, int cy, Color color) +{ + return HorzFadeOut(Size(cx, cy), color); +} + +Image RotateClockwise(const Image& img) +{ + Size sz = img.GetSize(); + ImageBuffer ib(sz.cy, sz.cx); + for(int x = 0; x < sz.cx; x++) + for(int y = 0; y < sz.cy; y++) + ib[x][y] = img[sz.cy - y - 1][x]; + return ib; +} + +Image RotateAntiClockwise(const Image& img) +{ + Size sz = img.GetSize(); + ImageBuffer ib(sz.cy, sz.cx); + for(int x = 0; x < sz.cx; x++) + for(int y = 0; y < sz.cy; y++) + ib[x][y] = img[y][sz.cx - x - 1]; + return ib; +} + +Image MirrorHorz(const Image& img) +{ + Size sz = img.GetSize(); + Image h = img; + ImageBuffer ib(h); + for(int y = 0; y < sz.cy; y++) { + RGBA *b = ib[y] + 0; + RGBA *e = b + sz.cx - 1; + while(b < e) { + Swap(*b, *e); + b++; + e--; + } + } + return ib; +} + +Image MirrorVert(const Image& img) +{ + Size sz = img.GetSize(); + Image h = img; + ImageBuffer ib(h); + + for(int y = 0; y < sz.cy / 2; y++) { + RGBA *b = ib[y]; + RGBA *e = ib[sz.cy - y - 1]; + for(int x = 0; x < sz.cx; x++) { + Swap(*b, *e); + b++; + e++; + } + } + return ib; +} + +Image Magnify(const Image& img, int nx, int ny) +{ + if(nx == 1 && ny == 1) + return img; + if(nx == 0 || ny == 0) + return Image(); + Size sz = img.GetSize(); + bool xdown = nx < 0; + nx = abs(nx); + int ncx = xdown ? sz.cx / nx : sz.cx * nx; + ImageBuffer b(ncx, sz.cy * ny); + const RGBA *s = ~img; + const RGBA *e = s + img.GetLength(); + RGBA *t = ~b; + while(s < e) { + RGBA *q = t; + const RGBA *le = s + sz.cx; + while(s < le) { + Fill(q, *s, nx); + q += nx; + s++; + } + for(int n = ny - 1; n--;) { + memcpy(q, t, ncx * sizeof(RGBA)); + q += ncx; + } + t = q; + } + return b; +} + +static Pointf Cvp(double x, double y, double sina, double cosa) +{ + return Pointf(x * cosa + y * sina, -x * sina + y * cosa); +} + +Image Rotate(const Image& m, int angle) +{ + Size isz = m.GetSize(); + Point center = isz / 2; + Pointf centerf = Pointf(Point(isz)) / 2.0; + double sina, cosa; + Draw::SinCos(-angle, sina, cosa); + Pointf p1 = Cvp(-centerf.x, -centerf.y, sina, cosa); + Pointf p2 = Cvp(centerf.x, -centerf.y, sina, cosa); + Size sz2 = Size(2 * (int)max(tabs(p1.x), tabs(p2.x)), + 2 * (int)max(tabs(p1.y), tabs(p2.y))); + Pointf dcenterf = Sizef(sz2) / 2.0; + Point dcenter = sz2 / 2; + + ImageBuffer ib(sz2); + Fill(~ib, RGBAZero(), ib.GetLength()); + RGBA *t = ~ib; + Draw::SinCos(angle, sina, cosa); + int sini = int(sina * 128); + int cosi = int(cosa * 128); + Buffer xmx(sz2.cx); + Buffer xmy(sz2.cx); + for(int x = 0; x < sz2.cx; x++) { + int xx = x + x - sz2.cx; + xmx[x] = int(xx * cosi); + xmy[x] = -int(xx * sini); + } + for(int y = 0; y < sz2.cy; y++) { + int yy = y + y - sz2.cy; + int ymx = int(yy * sini) + (isz.cx << 7); + int ymy = int(yy * cosi) + (isz.cy << 7); + for(int x = 0; x < sz2.cx; x++) { + int xs = (xmx[x] + ymx) >> 8; + int ys = (xmy[x] + ymy) >> 8; + *t++ = xs >= 0 && xs < isz.cx && ys >= 0 && ys < isz.cy ? m[ys][xs] : RGBAZero(); + } + } + return ib; +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/ImageOp.h b/uppdev/Draw/ImageOp.h new file mode 100644 index 000000000..1b772c520 --- /dev/null +++ b/uppdev/Draw/ImageOp.h @@ -0,0 +1,156 @@ +Image CreateImage(Size sz, Color color); +Image SetColorKeepAlpha(const Image& img, Color c); + +Image WithHotSpots(const Image& m, int x1, int y1, int x2, int y2); +Image WithHotSpot(const Image& m, int x1, int y1); + +void Over(ImageBuffer& dest, Point p, const Image& src, const Rect& srect); +void Copy(ImageBuffer& dest, Point p, const Image& src, const Rect& srect); + +void Copy(Image& dest, Point p, const Image& src, const Rect& srect); +void Over(Image& dest, Point p, const Image& src, const Rect& srect); + +void OverStraightOpaque(ImageBuffer& dest, Point p, const Image& src, const Rect& srect); +void OverStraightOpaque(Image& dest, Point p, const Image& _src, const Rect& srect); + +void Crop(RasterEncoder& tgt, Raster& img, const Rect& rc); +Image Crop(const Image& img, const Rect& rc); +Image Crop(const Image& img, int x, int y, int cx, int cy); + +Image ColorMask(const Image& src, Color transparent); + +void CanvasSize(RasterEncoder& tgt, Raster& img, int cx, int cy); +Image CanvasSize(const Image& img, int cx, int cy); + +Image AssignAlpha(const Image& img, const Image& new_alpha); + +Image Grayscale(const Image& img); +Image Grayscale(const Image& img, int amount); +Image Contrast(const Image& img, int amount = 256); + +Image HorzFadeOut(int cx, int cy, Color color); +Image HorzFadeOut(Size sz, Color color); + +class RescaleImage { + Raster *src; + Size tsz; + Vector horz; + Vector vert; + void (*row_proc)(dword *dest, const RGBA *src, const dword *map); + Size size; + int cx4; + int count; + int segment; + int entry; + int step; + int segspan; + bool bigseg; + Buffer row_buffers; + int first; + int full; + const dword *offsets; + int offset; + int y; + + struct Ln { + RasterLine line; + int ii; + }; + + Ln cache[4]; + int cii; + const RGBA *GetLine(int i); + +public: + void Create(Size sz, Raster& src, const Rect& src_rc); + void Get(RGBA *line); +}; + +void DrawRasterData(Draw& w, int x, int y, int cx, int cy, const String& data); + +bool Rescale(RasterEncoder& tgt, Size sz, Raster& src, const Rect& src_rc, + Gate2 progress = false); +Image Rescale(const Image& src, Size sz, const Rect& src_rc, Gate2 progress = false); +Image Rescale(const Image& src, Size sz, Gate2 progress = false); +Image Rescale(const Image& src, int cx, int cy, Gate2 progress = false); + +struct ImageFilter9 { + virtual RGBA operator()(const RGBA **mx) = 0; + virtual ~ImageFilter9() {} +}; + +Image Filter(const Image& img, ImageFilter9& filter); +void Filter(RasterEncoder& target, Raster& src, ImageFilter9& filter); + +Image Etched(const Image& img); +Image Sharpen(const Image& img, int amount = 100); + +Image RotateClockwise(const Image& img); +Image RotateAntiClockwise(const Image& img); +Image MirrorHorz(const Image& img); +Image MirrorVert(const Image& img); +Image Rotate(const Image& m, int angle); + +// Experimental { +Image Colorize(const Image& img, Color color, int alpha = 100); +Image Equalight(const Image& img, int thold = 10); +// } + +//Chameleon support +int Diff(RGBA a, RGBA b); +Image Unglyph(const Image& m, Color& c, double& factor); +Image Unglyph(const Image& m, Color& c); +Image Unglyph(const Image& m); +Image VertBlend(Image img1, Image img2, int y0, int y1); +Image HorzBlend(Image img1, Image img2, int x0, int x1); +Image HorzSymm(Image src); + +enum { + IMAGECONTENT_VERTDUP = 1, + IMAGECONTENT_HORZDUP = 2, + IMAGECONTENT_OPAQUEBODY = 4, +}; + +int ClassifyContent(const Image& m, const Rect& rect); + +Image RecreateAlpha(const Image& overwhite, const Image& overblack); +int ImageMargin(const Image& m, int p, int dist); +int ImageMarginV(const Image& _m, int p, int dist); + +struct ChPartMaker { + Image image; + Color border; + Color bg; + + bool t, b, l, r; + byte tl, tr, bl, br; + + void ResetShape(); + Image Make() const; + + ChPartMaker(const Image& m); +}; + +// Image cache + +struct ImageMaker { + virtual String Key() const = 0; + virtual Image Make() const = 0; + virtual ~ImageMaker() {} +}; + +Image MakeImage(const ImageMaker& m); +Image MakeImage(const Image& image, Image (*make)(const Image& image)); + +void ClearMakeImageCache(); +void SetMakeImageCacheSize(int m); +void SetMakeImageCacheMax(int m); + +Image MakeImagePaintOnly(const ImageMaker& m); + +Image CachedRescale(const Image& m, Size sz, const Rect& src); +Image CachedRescale(const Image& m, Size sz); +Image CachedRescalePaintOnly(const Image& m, Size sz, const Rect& src); +Image CachedRescalePaintOnly(const Image& m, Size sz); + +Image Magnify(const Image& img, int nx, int ny); diff --git a/uppdev/Draw/ImageScale.cpp b/uppdev/Draw/ImageScale.cpp new file mode 100644 index 000000000..3c7ba6dd1 --- /dev/null +++ b/uppdev/Draw/ImageScale.cpp @@ -0,0 +1,511 @@ +#include "Draw.h" + +NAMESPACE_UPP + +enum +{ + MAXAA = 4, + + MAP_COUNT = 0, + MAP_SEGMENT = 1, + MAP_BLOCK = 2, + MAP_STEP = 3, + MAP_DATA = 4, +}; + +enum { LOG2_STRETCH_CURVE = 10, COUNT_STRETCH_CURVE = 1 << LOG2_STRETCH_CURVE }; + +static const byte *GetStretchCurve() +{ + static byte cache[COUNT_STRETCH_CURVE]; + ONCELOCK { + for(int i = 0; i < COUNT_STRETCH_CURVE; i++) + { + enum { HALF = COUNT_STRETCH_CURVE >> 1 }; + double a = (i <= HALF ? i / double(HALF) : (COUNT_STRETCH_CURVE - i) / double(HALF)); + double o = pow(a, 0.85); + cache[i] = minmax((int)((i <= HALF ? o : 2 - o) * 128), 0, 255); + } + } + return cache; +} + +Vector AAGetMap(int& dmin, int& dmax, int dclipmin, int dclipmax, + int smin, int smax, int sclipmin, int sclipmax, int times, int avail) +{ + Vector map; + if(dmax == dmin || smax == smin) + return map; + if(dmax < dmin) + { + Swap(dmin, dmax); + Swap(smin, smax); + } + int dw = dmax - dmin, sw = smax - smin, spos; + if(sw > 0) + { + int x0 = dmin; + if(smin < sclipmin) + x0 += iscalefloor(sclipmin - smin, dw, sw); + if(x0 < dclipmin) + x0 = dclipmin; + spos = smin * dw + (x0 - dmin) * sw; + dmin = x0; + if(smax > sclipmax) + dmax -= iscalefloor(smax - sclipmax, dw, sw); + if(dmax > dclipmax) + dmax = dclipmax; + } + else + { + int x0 = dmin; + if(smin > sclipmax) + x0 += iscalefloor(sclipmax - smin, dw, sw); + if(x0 < dclipmin) + x0 = dclipmin; + spos = smin * dw + (x0 - dmin) * sw; + dmin = x0; + if(smax < sclipmin) + dmax -= iscalefloor(smax - sclipmin, dw, sw); + Swap(smin, smax); + } + int count = min(dclipmax, dmax) - dmin; + if(smin < sclipmin) + smin = sclipmin; + if(smax > sclipmax) + smax = sclipmax; + if(smax <= smin || count <= 0) + return map; + int span = min(tabs(sw) % dw ? idivceil(tabs(sw), dw) + 1 : tabs(sw) / dw, smax - smin); + bool bigseg = (span >= MAXAA); + int segment = (bigseg ? MAXAA : span); + int segstep = span / segment; + map.SetCount(4 + count * (bigseg ? 1 : 1 + segment)); + map[MAP_COUNT] = dword(count); + map[MAP_SEGMENT] = dword(segment); + map[MAP_BLOCK] = 1 + (bigseg ? 0 : segment); + map[MAP_STEP] = (span / segment) * times; + dword *out = map.Begin() + MAP_DATA; + int sendoffset = (smax - (segment - 1) * segstep - 1) * times; + int last = 0; + + if(smax - smin == 1) + { + ASSERT(segment == 1); + dword dval = dword(smin * times); + *out++ = dval; + *out++ = avail; + while(--count > 0) + { + *out++ = 0; + *out++ = avail; + } + } + else if(tabs(sw) >= dw) + { // size reduction + int sbegin = smin * dw, send = smax * dw, aw = tabs(sw); + for(spos += min(sw, 0); --count >= 0; spos += sw) + { + int pb = max(spos, sbegin), pe = min(spos + aw, send); + int total = pe - pb, left = avail; + int start = idivfloor(pb, dw), end = idivceil(pe, dw) - 1, rem = pb % dw; +// DUMP(start); +// DUMP(end); + if(pb >= send) + { + last += *out++ = sendoffset - last; + if(!bigseg) + { + int i = segment - 1; + while(--i >= 0) + *out++ = 0; + *out++ = left; + } + } + else if(end <= start) + { // 1 source pixel only +// ASSERT(!bigseg); + int scomp = minmax(start + segment - smax, 0, start - smin); + last += *out++ = (start - scomp) * times - last; + if(!bigseg) + { + int i = scomp; + while(--i >= 0) + *out++ = 0; + *out++ = dword(left); + i = segment - scomp - 1; + while(--i >= 0) + *out++ = 0; + } + } + else + { + int delta = (dw - rem) * left / total; + if(!delta) + start++; + int scomp = minmax(start + span - smax, 0, start - smin); + last += *out++ = (start - scomp) * times - last; + if(!bigseg) + { + int i = scomp; + while(--i >= 0) + *out++ = 0; + i = segment - scomp; + if(delta) + { + *out++ = delta; + left -= delta; + total -= dw - rem; + i--; + } + while(++start < end) + { + ASSERT(i > 0); + delta = dw * left / total; + *out++ = delta; + left -= delta; + total -= dw; + --i; + } + if(left > 0) + { + ASSERT(i > 0); + *out++ = left; + --i; + } + while(--i >= 0) + *out++ = 0; + } + } +// LOG("-> " << map[rec] << " + " << map[rec + 1]); + } + } + else + { // size inflation + static const byte *curve = GetStretchCurve(); + ASSERT(segment == 2 && !bigseg); + int sbegin = smin * dw, send = (smax - 1) * dw; + for(spos += (sw - dw) >> 1; --count >= 0; spos += sw) + { + if(spos <= sbegin) + { + last += out[0] = smin * times - last; + out[1] = avail; + out[2] = 0; + } + else if(spos >= send) + { + last += out[0] = sendoffset - last; + out[1] = 0; + out[2] = avail; + } + else + { + int pos = spos / dw; + int rel = spos % dw; + last += out[0] = pos * times - last; + out[1] = avail - (out[2] = curve[rel * COUNT_STRETCH_CURVE / dw]); + } + out += 3; + } + } + +#ifdef _DEBUG + ASSERT(out == map.End()); + int offs = 0, step = map[MAP_BLOCK], segspan = (map[MAP_SEGMENT] - 1) * map[MAP_STEP] + 1; + for(int t = 0; t < (int)map[MAP_COUNT]; t++) + { + offs += map[MAP_DATA + t * step]; + ASSERT(offs >= times * smin && offs + segspan <= times * smax); + } +#endif + + return map; +} + +static void BltAAMapRGBA1(dword *dest, const RGBA *s, const dword *map) +{ + int count = map[MAP_COUNT]; + map += 4; + while(count--) { + s += map[0]; + dest[0] = s->b << 8; + dest[1] = s->g << 8; + dest[2] = s->r << 8; + dest[3] = s->a << 8; + map += 2; + dest += 4; + } +} + +static void BltAAMapRGBA2(dword *dest, const RGBA *s, const dword *map) +{ + int count = map[MAP_COUNT]; + map += 4; + while(count--) { + s += map[0]; + dest[0] = s[0].b * map[1] + s[1].b * map[2]; + dest[1] = s[0].g * map[1] + s[1].g * map[2]; + dest[2] = s[0].r * map[1] + s[1].r * map[2]; + dest[3] = s[0].a * map[1] + s[1].a * map[2]; + map += 3; + dest += 4; + } +} + + +static void BltAAMapRGBA3(dword *dest, const RGBA *s, const dword *map) +{ + int count = map[MAP_COUNT]; + map += 4; + while(count--) { + s += map[0]; + dest[0] = s[0].b * map[1] + s[1].b * map[2] + s[2].b * map[3]; + dest[1] = s[0].g * map[1] + s[1].g * map[2] + s[2].g * map[3]; + dest[2] = s[0].r * map[1] + s[1].r * map[2] + s[2].r * map[3]; + dest[3] = s[0].a * map[1] + s[1].a * map[2] + s[2].a * map[3]; + map += 4; + dest += 4; + } +} + +static void BltAAMapRGBA4(dword *dest, const RGBA *s, const dword *map) +{ + int step = map[MAP_STEP]; + int count = map[MAP_COUNT]; + map += 4; + while(count--) { + s += map[0]; + dest[0] = (s[0].b + s[step].b + s[2 * step].b + s[3 * step].b) << 6; + dest[1] = (s[0].g + s[step].g + s[2 * step].g + s[3 * step].g) << 6; + dest[2] = (s[0].r + s[step].r + s[2 * step].r + s[3 * step].r) << 6; + dest[3] = (s[0].a + s[step].a + s[2 * step].a + s[3 * step].a) << 6; + map += 1; + dest += 4; + } +} + +void BltAASet2Fix(RGBA *dest, const dword *src1, dword w1, const dword *src2, dword w2, int count) +{ + while(count--) { + dest->b = byte((src1[0] * w1 + src2[0] * w2) >> 16); + dest->g = byte((src1[1] * w1 + src2[1] * w2) >> 16); + dest->r = byte((src1[2] * w1 + src2[2] * w2) >> 16); + dest->a = byte((src1[3] * w1 + src2[3] * w2) >> 16); + dest++; + src1 += 4; + src2 += 4; + } +} + +void BltAASet3Fix(RGBA *dest, + const dword *src1, dword w1, const dword *src2, dword w2, const dword *src3, dword w3, + dword count) +{ + while(count--) { + dest->b = byte((src1[0] * w1 + src2[0] * w2 + src3[0] * w3) >> 16); + dest->g = byte((src1[1] * w1 + src2[1] * w2 + src3[1] * w3) >> 16); + dest->r = byte((src1[2] * w1 + src2[2] * w2 + src3[2] * w3) >> 16); + dest->a = byte((src1[3] * w1 + src2[3] * w2 + src3[3] * w3) >> 16); + dest++; + src1 += 4; + src2 += 4; + src3 += 4; + } +} + +void BltAASet4Fix(RGBA *dest, const dword *src1, const dword *src2, + const dword *src3, const dword *src4, int count) +{ + while(count--) { + dest->b = byte((src1[0] + src2[0] + src3[0] + src4[0]) >> 10); + dest->g = byte((src1[1] + src2[1] + src3[1] + src4[1]) >> 10); + dest->r = byte((src1[2] + src2[2] + src3[2] + src4[2]) >> 10); + dest->a = byte((src1[3] + src2[3] + src3[3] + src4[3]) >> 10); + dest++; + src1 += 4; + src2 += 4; + src3 += 4; + src4 += 4; + } +} + +void BltAAFix2(RGBA *dest, const dword *src, int count) +{ +#ifdef CPU_LITTLE_ENDIAN + const byte *s = (byte *)src + 1; +#else + const byte *s = (byte *)src + 2; +#endif + while(count--) { + dest->b = s[0]; + dest->g = s[4]; + dest->r = s[8]; + dest->a = s[12]; + dest++; + s += 16; + } +} + +void RescaleImage::Create(Size _tsz, Raster& _src, const Rect& src_rc) +{ + y = -1; + src = &_src; + tsz = _tsz; + if(tsz.cx == 0 || tsz.cy == 0) + return; + + size = src->GetSize(); + + Rect dr = tsz; + horz = AAGetMap(dr.left, dr.right, dr.left, dr.right, + src_rc.left, src_rc.right, 0, size.cx, 1, 0x100); + if(horz.IsEmpty()) + return; + + vert = AAGetMap(dr.top, dr.bottom, dr.top, dr.bottom, + src_rc.top, src_rc.bottom, 0, size.cy, 1, 0x100); + if(vert.IsEmpty()) + return; + + switch(horz[MAP_SEGMENT]) { + case 1: row_proc = BltAAMapRGBA1; break; + case 2: row_proc = BltAAMapRGBA2; break; + case 3: row_proc = BltAAMapRGBA3; break; + case 4: row_proc = BltAAMapRGBA4; break; + default: NEVER(); return; + } + + cx4 = 4 * tsz.cx; + count = vert[MAP_COUNT]; + segment = vert[MAP_SEGMENT]; + entry = vert[MAP_BLOCK]; + step = vert[MAP_STEP]; + segspan = (segment - 1) * step + 1; + bigseg = (segment == MAXAA); + row_buffers.Alloc(cx4 * segment); + first = vert[4]; + full = 0; + offsets = vert.GetIter(4); + offset = 0; + y = 0; + cii = 0; + cache[0].ii = cache[1].ii = cache[2].ii = cache[3].ii = -1; +} + +const RGBA *RescaleImage::GetLine(int ii) +{ + if(cache[0].ii == ii) + return cache[0].line; + if(cache[1].ii == ii) + return cache[1].line; + if(cache[2].ii == ii) + return cache[2].line; + if(cache[3].ii == ii) + return cache[3].line; + cache[cii].line = (*src)[ii]; + cache[cii].ii = ii; + const RGBA *l = cache[cii].line; + cii = (cii + 1) % 4; + return l; +} + +void RescaleImage::Get(RGBA *tgt) +{ + if(y < 0 || offsets >= vert.End()) { + memset(tgt, 0, sizeof(RGBA) * tsz.cx); + return; + } + offset += *offsets++; + ASSERT(offset >= 0 && offset + segspan <= size.cy); + if(bigseg) { + row_proc(&row_buffers[0 * cx4], GetLine(offset + 0 * step), horz); + row_proc(&row_buffers[1 * cx4], GetLine(offset + 1 * step), horz); + row_proc(&row_buffers[2 * cx4], GetLine(offset + 2 * step), horz); + row_proc(&row_buffers[3 * cx4], GetLine(offset + 3 * step), horz); + BltAASet4Fix(tgt, &row_buffers[0 * cx4], &row_buffers[1 * cx4], + &row_buffers[2 * cx4], &row_buffers[3 * cx4], tsz.cx); + } + else { + int endoff = offset + segment; + for(int next = first + full; next < endoff; next++) { + if(full >= segment) + first++; + else + full++; + row_proc(&row_buffers[next % segment * cx4], GetLine(next), horz); + } + while(first > offset) { + if(full < segment) + full++; + --first; + row_proc(&row_buffers[first % segment * cx4], GetLine(first), horz); + } + ASSERT(offset >= first && endoff <= first + full); + switch(segment) { + case 1: + BltAAFix2(tgt, &row_buffers[offset % segment * cx4], tsz.cx); + offsets++; + break; + case 2: + if(offsets[0] == 0) + BltAAFix2(tgt, &row_buffers[(offset + 1) % segment * cx4], tsz.cx); + else + if(offsets[1] == 0) + BltAAFix2(tgt, &row_buffers[offset % segment * cx4], tsz.cx); + else + BltAASet2Fix(tgt, &row_buffers[(offset + 0) % segment * cx4], offsets[0], + &row_buffers[(offset + 1) % segment * cx4], offsets[1], + tsz.cx); + offsets += 2; + break; + case 3: + BltAASet3Fix(tgt, + &row_buffers[(offset + 0) % segment * cx4], offsets[0], + &row_buffers[(offset + 1) % segment * cx4], offsets[1], + &row_buffers[(offset + 2) % segment * cx4], offsets[2], tsz.cx); + offsets += 3; + break; + default: + NEVER(); + break; + } + } +} + +bool Rescale(RasterEncoder& tgt, Size tsz, Raster& src, const Rect& src_rc, + Gate2 progress) +{ + tgt.Create(tsz, src); + RescaleImage rs; + rs.Create(tsz, src, src_rc); + for(int i = 0; i < tsz.cy; i++) { + if(progress(i, tsz.cy)) + return false; + rs.Get(tgt); + tgt.WriteLine(); + } + return true; +} + +Image Rescale(const Image& src, Size sz, const Rect& src_rc, Gate2 progress) +{ + if(src.GetSize() == sz && src_rc == sz) + return src; + ImageRaster isrc(src); + ImageEncoder tgt; + Rescale(tgt, sz, isrc, src_rc); + return tgt; +} + +Image Rescale(const Image& src, Size sz, Gate2 progress) +{ + return Rescale(src, sz, src.GetSize()); +} + +Image Rescale(const Image& src, int cx, int cy, Gate2 progress) +{ + return Rescale(src, Size(cx, cy)); +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/ImageWin32.cpp b/uppdev/Draw/ImageWin32.cpp new file mode 100644 index 000000000..c40217a74 --- /dev/null +++ b/uppdev/Draw/ImageWin32.cpp @@ -0,0 +1,614 @@ +#include "Draw.h" + +#ifdef PLATFORM_WIN32 +#include +#endif + +NAMESPACE_UPP + +#ifdef PLATFORM_WIN32 + +#define LTIMING(x) // RTIMING(x) + +bool ImageFallBack +// = true +; + +class BitmapInfo32__ { + Buffer data; + +public: + operator BITMAPINFO *() { return (BITMAPINFO *)~data; } + operator BITMAPINFOHEADER *() { return (BITMAPINFOHEADER *)~data; } + BITMAPINFOHEADER *operator->() { return (BITMAPINFOHEADER *)~data; } + + BitmapInfo32__(int cx, int cy); +}; + +BitmapInfo32__::BitmapInfo32__(int cx, int cy) +{ + data.Alloc(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256); + BITMAPINFOHEADER *hi = (BITMAPINFOHEADER *) ~data;; + memset(hi, 0, sizeof(BITMAPINFOHEADER)); + hi->biSize = sizeof(BITMAPINFOHEADER); + hi->biPlanes = 1; +#ifdef PLATFORM_WINCE + hi->biBitCount = 32; + hi->biCompression = BI_BITFIELDS; + dword *x = (dword *)(~data + sizeof(BITMAPINFOHEADER)); + x[2] = 0xff; + x[1] = 0xff00; + x[0] = 0xff0000; +#else + hi->biBitCount = 32; + hi->biCompression = BI_RGB; +#endif + hi->biSizeImage = 0; + hi->biClrUsed = 0; + hi->biClrImportant = 0; + hi->biWidth = cx; + hi->biHeight = -cy; +} + +HBITMAP CreateBitMask(const RGBA *data, Size sz, Size tsz, Size csz, RGBA *ct) +{ + DrawLock __; + memset(ct, 0, tsz.cx * tsz.cy * sizeof(RGBA)); + int linelen = (tsz.cx + 15) >> 4 << 1; + Buffer mask(tsz.cy * linelen, 0xff); + byte *m = mask; + RGBA *ty = ct; + const RGBA *sy = data; + for(int y = 0; y < csz.cy; y++) { + const RGBA *s = sy; + RGBA *t = ty; + for(int x = 0; x < csz.cx; x++) { + if(s->a > 128) { + *t = *s; + m[x >> 3] &= ~(0x80 >> (x & 7)); + } + else + t->r = t->g = t->b = 0; + t->a = 0; + t++; + s++; + } + m += linelen; + sy += sz.cx; + ty += tsz.cx; + } + return ::CreateBitmap(tsz.cx, tsz.cy, 1, 1, mask); +} + +void SetSurface(HDC dc, int x, int y, int cx, int cy, const RGBA *pixels) +{ + DrawLock __; + BitmapInfo32__ bi(cx, cy); + ::SetDIBitsToDevice(dc, x, y, cx, cy, 0, 0, 0, cy, pixels, + bi, DIB_RGB_COLORS); +} + +void SetSurface(Draw& w, int x, int y, int cx, int cy, const RGBA *pixels) +{ + SetSurface(w.GetHandle(), x, y, cx, cy, pixels); +} + +class DrawSurface : NoCopy { + int x, y; + Size size; + RGBA *pixels; + HDC dc, dcMem; + HBITMAP hbmp, hbmpOld; + + void Init(Draw& w, int x, int y, int cx, int cy); + RGBA* Line(int i) const { ASSERT(i >= 0 && i < size.cy); return (RGBA *)pixels + size.cx * (size.cy - i - 1); } + +public: + operator RGBA *() { return pixels; } + Size GetSize() const { return size; } + RGBA *operator[](int i) { return Line(i); } + const RGBA *operator[](int i) const { return Line(i); } + int GetLineDelta() const { return -size.cx; } + + DrawSurface(Draw& w, const Rect& r); + DrawSurface(Draw& w, int x, int y, int cx, int cy); + ~DrawSurface(); +}; + +void DrawSurface::Init(Draw& w, int _x, int _y, int cx, int cy) +{ + DrawLock __; + dc = w.GetHandle(); + size = Size(cx, cy); + x = _x; + y = _y; + dcMem = ::CreateCompatibleDC(dc); + BitmapInfo32__ bi(cx, cy); + hbmp = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (void **)&pixels, NULL, 0); + hbmpOld = (HBITMAP) ::SelectObject(dcMem, hbmp); + ::BitBlt(dcMem, 0, 0, cx, cy, dc, x, y, SRCCOPY); +} + +DrawSurface::DrawSurface(Draw& w, const Rect& r) +{ + Init(w, r.left, r.top, r.Width(), r.Height()); +} + +DrawSurface::DrawSurface(Draw& w, int x, int y, int cx, int cy) +{ + Init(w, x, y, cx, cy); +} + +DrawSurface::~DrawSurface() +{ + DrawLock __; + ::BitBlt(dc, x, y, size.cx, size.cy, dcMem, 0, 0, SRCCOPY); + ::DeleteObject(::SelectObject(dcMem, hbmpOld)); + ::DeleteDC(dcMem); +} + +void Image::Data::SysInit() +{ + hbmp = hmask = himg = NULL; + cursor_cheat = NULL; +} + +void Image::Data::SysRelease() +{ + if(hbmp) { + DrawLock __; + DeleteObject(hbmp); + ResCount -= !paintonly; + } + if(hmask) { + DrawLock __; + DeleteObject(hmask); + ResCount -= !paintonly; + } + if(himg) { + DrawLock __; + DeleteObject(himg); + ResCount -= !paintonly; + } + himg = hbmp = hmask = NULL; +} + +#ifndef PLATFORM_WINCE +typedef BOOL (WINAPI *tAlphaBlend)(HDC hdcDest, int nXOriginDest, int nYOriginDest, + int nWidthDest, int nHeightDest, + HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, + int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction); + +static tAlphaBlend fnAlphaBlend() +{ + DrawLock __; + static tAlphaBlend pSet; + static bool inited = false; + if(!inited) { + inited = true; + if(HMODULE hDLL = LoadLibrary("msimg32.dll")) + pSet = (tAlphaBlend) GetProcAddress(hDLL, "AlphaBlend"); + } + return pSet; +} +#endif + +void Image::Data::CreateHBMP(HDC dc, const RGBA *data) +{ + DrawLock __; + Size sz = buffer.GetSize(); + BitmapInfo32__ bi(sz.cx, sz.cy); + HDC dcMem = ::CreateCompatibleDC(dc); + RGBA *pixels; + HBITMAP hbmp32 = CreateDIBSection(dcMem, bi, DIB_RGB_COLORS, (void **)&pixels, NULL, 0); + HDC hbmpOld = (HDC) ::SelectObject(dcMem, hbmp32); + memcpy(pixels, data, buffer.GetLength() * sizeof(RGBA)); + HDC dcMem2 = ::CreateCompatibleDC(dc); + hbmp = ::CreateCompatibleBitmap(dc, sz.cx, sz.cy); + HBITMAP o2 = (HBITMAP)::SelectObject(dcMem2, hbmp); + ::BitBlt(dcMem2, 0, 0, sz.cx, sz.cy, dcMem, 0, 0, SRCCOPY); + ::SelectObject(dcMem2, o2); + ::DeleteDC(dcMem2); + ::SelectObject(dcMem, hbmpOld); + ::DeleteObject(hbmp32); + ::DeleteDC(dcMem); + ResCount++; +} + +void Image::Data::Paint(Draw& w, int x, int y, const Rect& src, Color c) +{ + DrawLock __; + ASSERT(!paintonly || IsNull(c)); + int max = IsWinNT() ? 250 : 100; + while(ResCount > max) { + Image::Data *l = ResData->GetPrev(); + l->SysRelease(); + l->Unlink(); + } + HDC dc = w.GetHandle(); + Size sz = buffer.GetSize(); + int len = sz.cx * sz.cy; + Rect sr = src & sz; + Size ssz = sr.Size(); + if(sr.IsEmpty()) + return; + if(GetKind() == IMAGE_EMPTY) + return; + if(GetKind() == IMAGE_OPAQUE && !IsNull(c)) { + w.DrawRect(x, y, sz.cx, sz.cy, c); + return; + } + if(GetKind() == IMAGE_OPAQUE && paintcount == 0 && sr == Rect(sz) && !w.IsMetaFile() + && IsWinNT() && !w.IsPrinter()) { + LTIMING("Image Opaque direct set"); + SetSurface(w, x, y, sz.cx, sz.cy, buffer); + paintcount++; + return; + } + Unlink(); + LinkAfter(ResData); + if(GetKind() == IMAGE_OPAQUE) { + if(!hbmp) { + LTIMING("Image Opaque create"); + CreateHBMP(dc, buffer); + } + LTIMING("Image Opaque blit"); + HDC dcMem = ::CreateCompatibleDC(dc); + HBITMAP o = (HBITMAP)::SelectObject(dcMem, hbmp); + ::BitBlt(dc, x, y, ssz.cx, ssz.cy, dcMem, sr.left, sr.top, SRCCOPY); + ::SelectObject(dcMem, o); + ::DeleteDC(dcMem); + PaintOnlyShrink(); + return; + } + if(GetKind() == IMAGE_MASK/* || GetKind() == IMAGE_OPAQUE*/) { + HDC dcMem = ::CreateCompatibleDC(dc); + if(!hmask) { + LTIMING("Image Mask create"); + Buffer bmp(len); + hmask = CreateBitMask(buffer, sz, sz, sz, bmp); + ResCount++; + if(!hbmp) + CreateHBMP(dc, bmp); + } + LTIMING("Image Mask blt"); + HBITMAP o = (HBITMAP)::SelectObject(dcMem, ::CreateCompatibleBitmap(dc, sz.cx, sz.cy)); + ::BitBlt(dcMem, 0, 0, ssz.cx, ssz.cy, dc, x, y, SRCCOPY); + HDC dcMem2 = ::CreateCompatibleDC(dc); + ::SelectObject(dcMem2, hmask); + ::BitBlt(dcMem, 0, 0, ssz.cx, ssz.cy, dcMem2, sr.left, sr.top, SRCAND); + if(IsNull(c)) { + ::SelectObject(dcMem2, hbmp); + ::BitBlt(dcMem, 0, 0, ssz.cx, ssz.cy, dcMem2, sr.left, sr.top, SRCPAINT); + } + else { + HBRUSH ho = (HBRUSH) SelectObject(dcMem, CreateSolidBrush(c)); + ::BitBlt(dcMem, 0, 0, ssz.cx, ssz.cy, dcMem2, sr.left, sr.top, 0xba0b09); + ::DeleteObject(::SelectObject(dcMem, ho)); + } + ::BitBlt(dc, x, y, ssz.cx, ssz.cy, dcMem, 0, 0, SRCCOPY); + ::DeleteObject(::SelectObject(dcMem, o)); + ::DeleteDC(dcMem2); + ::DeleteDC(dcMem); + PaintOnlyShrink(); + return; + } +#ifndef PLATFORM_WINCE + if(fnAlphaBlend() && IsNull(c) && !ImageFallBack) { + if(!himg) { + LTIMING("Image Alpha create"); + BitmapInfo32__ bi(sz.cx, sz.cy); + himg = CreateDIBSection(ScreenHDC(), bi, DIB_RGB_COLORS, + (void **)§ion, NULL, 0); + ResCount++; + memcpy(section, ~buffer, buffer.GetLength() * sizeof(RGBA)); + } + LTIMING("Image Alpha blit"); + BLENDFUNCTION bf; + bf.BlendOp = AC_SRC_OVER; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = 255; + bf.AlphaFormat = AC_SRC_ALPHA; + HDC dcMem = ::CreateCompatibleDC(dc); + ::SelectObject(dcMem, himg); + fnAlphaBlend()(dc, x, y, ssz.cx, ssz.cy, dcMem, sr.left, sr.top, ssz.cx, ssz.cy, bf); + ::DeleteDC(dcMem); + PaintOnlyShrink(); + } + else +#endif + { + LTIMING("Image Alpha sw"); + DrawSurface sf(w, x, y, ssz.cx, ssz.cy); + RGBA *t = sf; + for(int i = sr.top; i < sr.bottom; i++) { + if(IsNull(c)) + AlphaBlendOpaque(t, buffer[i] + sr.left, ssz.cx); + else + AlphaBlendOpaque(t, buffer[i] + sr.left, ssz.cx, c); + t += ssz.cx; + } + } +} + +void ImageDraw::Section::Init(int cx, int cy) +{ + DrawLock __; + dc = ::CreateCompatibleDC(ScreenHDC()); + BitmapInfo32__ bi(cx, cy); + hbmp = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (void **)&pixels, NULL, 0); + hbmpOld = (HBITMAP) ::SelectObject(dc, hbmp); +} + +ImageDraw::Section::~Section() +{ + DrawLock __; + ::DeleteObject(::SelectObject(dc, hbmpOld)); + ::DeleteDC(dc); +} + +void ImageDraw::Init() +{ + DrawLock __; + rgb.Init(size.cx, size.cy); + a.Init(size.cx, size.cy); + Attach(rgb.dc); + alpha.Attach(a.dc); + has_alpha = false; +} + +Image ImageDraw::Get(bool pm) const +{ + ImageBuffer b(size); + int n = size.cx * size.cy; + memcpy(~b, rgb.pixels, n * sizeof(RGBA)); + const RGBA *s = a.pixels; + const RGBA *e = a.pixels + n; + RGBA *t = b; + if(has_alpha) { + while(s < e) { + t->a = s->r; + t++; + s++; + } + if(pm) + Premultiply(b); + b.SetKind(IMAGE_ALPHA); + } + else { + while(s < e) { + t->a = 255; + t++; + s++; + } + b.SetKind(IMAGE_OPAQUE); + } + return b; +} + +ImageDraw::operator Image() const +{ + return Get(true); +} + +Image ImageDraw::GetStraight() const +{ + return Get(false); +} + +ImageDraw::ImageDraw(Size sz) +{ + size = sz; + Init(); +} + +ImageDraw::ImageDraw(int cx, int cy) +{ + size = Size(cx, cy); + Init(); +} + +ImageDraw::~ImageDraw() +{ + Detach(); + alpha.Detach(); +} + +#ifdef PLATFORM_WINCE + +Image Image::Arrow() { return Null; } +Image Image::Wait() { return Null; } +Image Image::IBeam() { return Null; } +Image Image::No() { return Null; } +Image Image::SizeAll() { return Null; } +Image Image::SizeHorz() { return Null; } +Image Image::SizeVert() { return Null; } +Image Image::SizeTopLeft() { return Null; } +Image Image::SizeTop() { return Null; } +Image Image::SizeTopRight() { return Null; } +Image Image::SizeLeft() { return Null; } +Image Image::SizeRight() { return Null; } +Image Image::SizeBottomLeft() { return Null; } +Image Image::SizeBottom() { return Null; } +Image Image::SizeBottomRight() { return Null; } + +#else + +static Image sWin32Icon(HICON icon, bool cursor) +{ + DrawLock __; + ICONINFO iconinfo; + if(!icon || !GetIconInfo(icon, &iconinfo)) + return Image(); + BITMAP bm; + ::GetObject((HGDIOBJ)iconinfo.hbmMask, sizeof(BITMAP), (LPVOID)&bm); + HDC dcMem = ::CreateCompatibleDC(NULL); + Size sz(bm.bmWidth, bm.bmHeight); + BitmapInfo32__ bi(sz.cx, sz.cy); + int len = sz.cx * sz.cy; + Buffer mask(len); + ::SelectObject(dcMem, iconinfo.hbmColor); + ::GetDIBits(dcMem, iconinfo.hbmMask, 0, sz.cy, ~mask, bi, DIB_RGB_COLORS); + ImageBuffer b(sz.cx, iconinfo.hbmColor ? sz.cy : sz.cy / 2); + b.SetHotSpot(Point(iconinfo.xHotspot, iconinfo.yHotspot)); + if(iconinfo.hbmColor) { + ::SelectObject(dcMem, iconinfo.hbmColor); + ::GetDIBits(dcMem, iconinfo.hbmColor, 0, sz.cy, ~b, bi, DIB_RGB_COLORS); + RGBA *s = ~b; + RGBA *e = s + len; + RGBA *m = mask; + while(s < e) { + if(s->a != 255 && s->a != 0) { + Premultiply(b); + goto alpha; + } + s++; + } + s = ~b; + while(s < e) { + s->a = m->r ? 0 : 255; + s++; + m++; + } + } + else { + len /= 2; + RGBA *s = ~b; + RGBA *e = s + len; + RGBA *c = mask + len; + RGBA *m = mask; + while(s < e) { + s->a = (m->r & ~c->r) ? 0 : 255; + s->r = s->g = s->b = (c->r & ~m->r) ? 255 : 0; + s++; + m++; + c++; + } + } +alpha: + ::DeleteDC(dcMem); + ::DeleteObject(iconinfo.hbmColor); + ::DeleteObject(iconinfo.hbmMask); + Image img(b); + ::DestroyIcon(icon); + return img; +} + +Image Win32IconCursor(LPCSTR id, int iconsize, bool cursor) +{ + HICON icon; + if(cursor) + icon = (HICON)LoadCursor(0, id); + else + if(iconsize) + icon = (HICON)LoadImage(GetModuleHandle(NULL), id, + IMAGE_ICON, iconsize, iconsize, LR_DEFAULTCOLOR); + else + icon = LoadIcon(0, id); + Image img = sWin32Icon(icon, cursor); + if(cursor) + img.SetCursorCheat(id); + return img; +} + +Image Win32DllIcon(const char *dll, int ii, bool large) +{ + HICON icon; + if(ExtractIconEx(dll, ii, large ? &icon : NULL, large ? NULL : &icon, 1) == 1) + return sWin32Icon(icon, false); + return Null; +} + +Image Win32Icon(LPCSTR id, int iconsize) +{ + return Win32IconCursor(id, iconsize, false); +} + +Image Win32Icon(int id, int iconsize) +{ + return Win32Icon(MAKEINTRESOURCE(id), iconsize); +} + +Image Win32Cursor(LPCSTR id) +{ + return Win32IconCursor(id, 0, true); +} + +Image Win32Cursor(int id) +{ + return Win32Cursor(MAKEINTRESOURCE(id)); +} + +HICON IconWin32(const Image& img, bool cursor) +{ + DrawLock __; + if(img.IsEmpty()) + return NULL; + if(cursor) { + LPCSTR id = img.GetCursorCheat(); + if(id) + return (HICON)LoadCursor(0, id); + } + Size sz = img.GetSize(); + ICONINFO iconinfo; + iconinfo.fIcon = !cursor; + Point p = img.GetHotSpot(); + iconinfo.xHotspot = p.x; + iconinfo.yHotspot = p.y; + static Size cursor_size(GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR)); + Size tsz = sz; + if(!IsWin2K() && cursor) + tsz = cursor_size; + Size csz = Size(min(tsz.cx, sz.cx), min(tsz.cy, sz.cy)); + if(IsWinXP() && !ImageFallBack) { + RGBA *pixels; + BitmapInfo32__ bi(tsz.cx, tsz.cy); + HDC dcMem = ::CreateCompatibleDC(NULL); + iconinfo.hbmColor = ::CreateDIBSection(dcMem, bi, DIB_RGB_COLORS, (void **)&pixels, NULL, 0); + iconinfo.hbmMask = ::CreateBitmap(tsz.cx, tsz.cy, 1, 1, NULL); + memset(pixels, 0, tsz.cx * tsz.cy * sizeof(RGBA)); + for(int y = 0; y < csz.cy; y++) + memcpy(pixels + y * tsz.cx, img[y], csz.cx * sizeof(RGBA)); + ::DeleteDC(dcMem); + } + else { + Buffer h(tsz.cx * tsz.cy); + HDC dc = ::GetDC(NULL); + BitmapInfo32__ bi(tsz.cx, tsz.cy); + iconinfo.hbmMask = CreateBitMask(~img, sz, tsz, csz, h); + iconinfo.hbmColor = ::CreateDIBitmap(dc, bi, CBM_INIT, h, bi, DIB_RGB_COLORS); + ::ReleaseDC(NULL, dc); + } + + HICON icon = ::CreateIconIndirect(&iconinfo); + ::DeleteObject(iconinfo.hbmColor); + ::DeleteObject(iconinfo.hbmMask); + return icon; +} + +#define WCURSOR_(x)\ +{ Image m; INTERLOCKED { static Image img = Win32Cursor(x); m = img; } return m; } + +Image Image::Arrow() WCURSOR_(IDC_ARROW) +Image Image::Wait() WCURSOR_(IDC_WAIT) +Image Image::IBeam() WCURSOR_(IDC_IBEAM) +Image Image::No() WCURSOR_(IDC_NO) +Image Image::SizeAll() WCURSOR_(IDC_SIZEALL) +Image Image::SizeHorz() WCURSOR_(IDC_SIZEWE) +Image Image::SizeVert() WCURSOR_(IDC_SIZENS) +Image Image::SizeTopLeft() WCURSOR_(IDC_SIZENWSE) +Image Image::SizeTop() WCURSOR_(IDC_SIZENS) +Image Image::SizeTopRight() WCURSOR_(IDC_SIZENESW) +Image Image::SizeLeft() WCURSOR_(IDC_SIZEWE) +Image Image::SizeRight() WCURSOR_(IDC_SIZEWE) +Image Image::SizeBottomLeft() WCURSOR_(IDC_SIZENESW) +Image Image::SizeBottom() WCURSOR_(IDC_SIZENS) +Image Image::SizeBottomRight() WCURSOR_(IDC_SIZENWSE) +Image Image::Cross() WCURSOR_(IDC_CROSS) +Image Image::Hand() WCURSOR_(IDC_HAND) + +#endif + +#endif + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/ImageX11.cpp b/uppdev/Draw/ImageX11.cpp new file mode 100644 index 000000000..9e9d5b3f5 --- /dev/null +++ b/uppdev/Draw/ImageX11.cpp @@ -0,0 +1,406 @@ +#include "Draw.h" + +NAMESPACE_UPP + +#ifdef PLATFORM_X11 + +static void sInitXImage(XImage& ximg, Size sz) +{ + Zero(ximg); + ximg.width = sz.cx; + ximg.height = sz.cy; + ximg.xoffset = 0; + ximg.format = ZPixmap; + ximg.bitmap_bit_order = MSBFirst; +#ifdef CPU_LITTLE_ENDIAN + ximg.byte_order = LSBFirst; +#else + ximg.byte_order = MSBFirst; +#endif +} + +void SetSurface(Draw& w, int x, int y, int cx, int cy, const RGBA *pixels) +{ + DrawLock __; + Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, cx, cy, 24); + XPicture picture = XRenderCreatePicture( + Xdisplay, pixmap, + XRenderFindStandardFormat(Xdisplay, PictStandardRGB24), + 0, 0 + ); + XImage ximg; + sInitXImage(ximg, Size(cx, cy)); + ximg.bitmap_pad = 32; + ximg.bytes_per_line = 4 * cx; + ximg.bits_per_pixel = 32; + ximg.blue_mask = 0x00ff0000; + ximg.green_mask = 0x0000ff00; + ximg.red_mask = 0x000000ff; + Buffer pma; + ximg.bitmap_unit = 32; + ximg.depth = 24; + ximg.data = (char *)pixels; + XInitImage(&ximg); + GC gc = XCreateGC(Xdisplay, pixmap, 0, 0); + XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, cx, cy); + XFreeGC(Xdisplay, gc); + XFreePixmap(Xdisplay, pixmap); + XRenderComposite(Xdisplay, PictOpOver, + picture, 0, XftDrawPicture(w.GetXftDraw()), + 0, 0, 0, 0, x, y, cx, cy); + XRenderFreePicture(Xdisplay, picture); +} + +void Image::Data::SysInit() +{ + picture = 0; + picture8 = 0; + cursor_cheat = -1; +} + +void Image::Data::SysRelease() +{ + if(picture) { + DrawLock __; + if(Xdisplay) XRenderFreePicture(Xdisplay, picture); + ResCount -= !paintonly; + picture = 0; + } + if(picture8) { + DrawLock __; + if(Xdisplay) XRenderFreePicture(Xdisplay, picture8); + ResCount -= !paintonly; + picture8 = 0; + } +} + +struct XRSolidFill { + Color color; + XPicture picture; + Pixmap pixmap; +}; + +enum { XRSolidFillCount = 67 }; + +static XRSolidFill sFill[XRSolidFillCount]; + +inline int s255d16(int x) +{ + return (x << 8)|x; +} + +static XPicture sGetSolidFill(Color c) +{ + DrawLock __; + int q = GetHashValue(c) % (int)XRSolidFillCount; + XRSolidFill& f = sFill[q]; + if(f.color == c && f.picture) + return f.picture; + if(f.picture) + XRenderFreePicture(Xdisplay, f.picture); + if(f.pixmap) + XFreePixmap(Xdisplay, f.pixmap); + f.pixmap = XCreatePixmap(Xdisplay, Xroot, 1, 1, 32); + XRenderPictureAttributes attr; + attr.repeat = XTrue; + f.picture = XRenderCreatePicture(Xdisplay, f.pixmap, + XRenderFindStandardFormat(Xdisplay, PictStandardARGB32), + CPRepeat, &attr); + f.color = c; + XRenderColor xc; + xc.red = s255d16(c.GetR()); + xc.green = s255d16(c.GetG()); + xc.blue = s255d16(c.GetB()); + xc.alpha = 65535; + XRenderFillRectangle(Xdisplay, PictOpSrc, f.picture, &xc, 0, 0, 1, 1); + return f.picture; +} + +void Image::Data::Paint(Draw& w, int x, int y, const Rect& src, Color c) +{ + DrawLock __; + while(ResCount > 512) { + Image::Data *l = ResData->GetPrev(); + l->SysRelease(); + l->Unlink(); + } + x += w.GetOffset().x; + y += w.GetOffset().y; + Size sz = buffer.GetSize(); + int len = sz.cx * sz.cy; + Rect sr = src & sz; + Size ssz = sr.Size(); + if(sr.IsEmpty()) + return; + if(GetKind() == IMAGE_EMPTY) + return; + if(GetKind() == IMAGE_OPAQUE && !IsNull(c)) { + w.DrawRect(x, y, sz.cx, sz.cy, c); + return; + } + if(GetKind() == IMAGE_OPAQUE && paintcount == 0 && sr == Rect(sz)) { + SetSurface(w, x, y, sz.cx, sz.cy, buffer); + paintcount++; + return; + } + Unlink(); + LinkAfter(ResData); + if(IsNull(c)) { + if(!picture) { + bool opaque = GetKind() == IMAGE_OPAQUE; + Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, sz.cx, sz.cy, opaque ? 24 : 32); + picture = XRenderCreatePicture( + Xdisplay, pixmap, + XRenderFindStandardFormat(Xdisplay, opaque ? PictStandardRGB24 + : PictStandardARGB32), + 0, 0 + ); + ResCount++; + XImage ximg; + sInitXImage(ximg, sz); + ximg.bitmap_pad = 32; + ximg.bytes_per_line = 4 * sz.cx; + ximg.bits_per_pixel = 32; + ximg.blue_mask = 0x00ff0000; + ximg.green_mask = 0x0000ff00; + ximg.red_mask = 0x000000ff; + ximg.bitmap_unit = 32; + ximg.data = (char *)~buffer; + ximg.depth = opaque ? 24 : 32; + XInitImage(&ximg); + GC gc = XCreateGC(Xdisplay, pixmap, 0, 0); + XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, sz.cx, sz.cy); + XFreeGC(Xdisplay, gc); + XFreePixmap(Xdisplay, pixmap); + PaintOnlyShrink(); + } + XRenderComposite(Xdisplay, PictOpOver, + picture, 0, XftDrawPicture(w.GetXftDraw()), + sr.left, sr.top, 0, 0, x, y, ssz.cx, ssz.cy); + } + else { + ASSERT(!paintonly); + if(!picture8) { + Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, sz.cx, sz.cy, 8); + picture8 = XRenderCreatePicture(Xdisplay, pixmap, + XRenderFindStandardFormat(Xdisplay, PictStandardA8), + 0, 0); + ResCount++; + Buffer ab(len); + byte *t = ab; + const RGBA *s = buffer; + const RGBA *e = s + len; + while(s < e) + *t++ = (s++)->a; + XImage ximg; + sInitXImage(ximg, sz); + ximg.data = (char *)~ab; + ximg.bitmap_unit = 8; + ximg.bitmap_pad = 8; + ximg.depth = 8; + ximg.bytes_per_line = sz.cx; + ximg.bits_per_pixel = 8; + XInitImage(&ximg); + GC gc = XCreateGC(Xdisplay, pixmap, 0, 0); + XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, sz.cx, sz.cy); + XFreeGC(Xdisplay, gc); + XFreePixmap(Xdisplay, pixmap); + } + XRenderComposite(Xdisplay, PictOpOver, + sGetSolidFill(c), picture8, XftDrawPicture(w.GetXftDraw()), + sr.left, sr.top, 0, 0, x, y, ssz.cx, ssz.cy); + } +} + +void ImageDraw::Init() +{ + DrawLock __; + dw = XCreatePixmap(Xdisplay, Xroot, max(size.cx, 1), max(size.cy, 1), Xdepth); + gc = XCreateGC(Xdisplay, dw, 0, 0); + xftdraw = XftDrawCreate(Xdisplay, (Drawable) dw, DefaultVisual(Xdisplay, Xscreenno), Xcolormap); + + alpha.dw = XCreatePixmap(Xdisplay, Xroot, max(size.cx, 1), max(size.cy, 1), Xdepth); + alpha.gc = XCreateGC(Xdisplay, alpha.dw, 0, 0); + alpha.xftdraw = XftDrawCreate(Xdisplay, (Drawable) alpha.dw, DefaultVisual(Xdisplay, Xscreenno), Xcolormap); + + Vector clip; + clip.Add(RectC(0, 0, size.cx, size.cy)); + Draw::Init(clip, Point(0, 0)); + alpha.Init(clip, Point(0, 0)); + + has_alpha = false; +} + +ImageDraw::operator Image() const +{ + DrawLock __; + XImage *xim = XGetImage(Xdisplay, dw, 0, 0, max(size.cx, 1), max(size.cy, 1), AllPlanes, ZPixmap); + Visual *v = DefaultVisual(Xdisplay, Xscreenno); + RasterFormat fmt; + + RGBA palette[256]; + + switch(xim->depth) { + case 15: + case 16: + if(xim->byte_order == LSBFirst) + fmt.Set16le(v->red_mask, v->green_mask, v->blue_mask); + else + fmt.Set16be(v->red_mask, v->green_mask, v->blue_mask); + break; + case 8: { + int n = min(v->map_entries, 256); + XColor colors[256]; + for(int i = 0; i < 256; i++) { + colors[i].pixel = i; + colors[i].flags = DoRed|DoGreen|DoBlue; + } + XQueryColors(Xdisplay, Xcolormap, colors, n); + XColor *s = colors; + XColor *e = s + n; + while(s < e) { + RGBA& t = palette[s->pixel]; + t.r = s->red >> 8; + t.g = s->green >> 8; + t.b = s->blue >> 8; + t.a = 255; + s++; + } + fmt.Set8(); + break; + } + default: + if(xim->bits_per_pixel == 32) + if(xim->byte_order == LSBFirst) + fmt.Set32le(v->red_mask, v->green_mask, v->blue_mask); + else + fmt.Set32be(v->red_mask, v->green_mask, v->blue_mask); + else + if(xim->byte_order == LSBFirst) + fmt.Set24le(v->red_mask, v->green_mask, v->blue_mask); + else + fmt.Set24be(v->red_mask, v->green_mask, v->blue_mask); + break; + } + + ImageBuffer ib(size); + const byte *s = (const byte *)xim->data; + RGBA *t = ib; + for(int y = 0; y < size.cy; y++) { + fmt.Read(t, s, size.cx, palette); + s += xim->bytes_per_line; + t += size.cx; + } + XDestroyImage(xim); + if(has_alpha) { + xim = XGetImage(Xdisplay, alpha.dw, 0, 0, size.cx, size.cy, AllPlanes, ZPixmap); + const byte *s = (const byte *)xim->data; + t = ib; + Buffer line(size.cx); + for(int y = 0; y < size.cy; y++) { + fmt.Read(line, s, size.cx, palette); + for(int x = 0; x < size.cx; x++) + (t++)->a = line[x].r; + s += xim->bytes_per_line; + } + XDestroyImage(xim); + } + Premultiply(ib); + return ib; +} + +ImageDraw::ImageDraw(Size sz) +{ + size = sz; + Init(); +} + +ImageDraw::ImageDraw(int cx, int cy) +{ + size = Size(cx, cy); + Init(); +} + +ImageDraw::~ImageDraw() +{ + DrawLock __; + XftDrawDestroy(xftdraw); + XFreePixmap(Xdisplay, dw); + XFreeGC(Xdisplay, gc); + XftDrawDestroy(alpha.xftdraw); + XFreePixmap(Xdisplay, alpha.dw); + XFreeGC(Xdisplay, alpha.gc); +} + +Image sX11Cursor__(int c) +{ + ImageBuffer b(32, 32); + Image m(b); + m.SetCursorCheat(c); + return m; +} + +#include + +#define FCURSOR_(x) { Image h; INTERLOCKED { static Image m = sX11Cursor__(x); h = m; } return h; } + +Image Image::Arrow() FCURSOR_(XC_left_ptr) +Image Image::Wait() FCURSOR_(XC_watch) +Image Image::IBeam() FCURSOR_(XC_xterm) +Image Image::No() FCURSOR_(XC_circle) +Image Image::SizeAll() FCURSOR_(XC_fleur) +Image Image::SizeHorz() FCURSOR_(XC_sb_h_double_arrow) +Image Image::SizeVert() FCURSOR_(XC_double_arrow) +Image Image::SizeTopLeft() FCURSOR_(XC_top_left_corner) +Image Image::SizeTop() FCURSOR_(XC_top_side) +Image Image::SizeTopRight() FCURSOR_(XC_top_right_corner) +Image Image::SizeLeft() FCURSOR_(XC_left_side) +Image Image::SizeRight() FCURSOR_(XC_right_side) +Image Image::SizeBottomLeft() FCURSOR_(XC_bottom_left_corner) +Image Image::SizeBottom() FCURSOR_(XC_bottom_side) +Image Image::SizeBottomRight() FCURSOR_(XC_bottom_right_corner) +Image Image::Cross() FCURSOR_(XC_crosshair) +Image Image::Hand() FCURSOR_(XC_hand1) + +Cursor X11Cursor(const Image& img) +{ + DrawLock __; + int q = img.GetCursorCheat(); + if(q >= 0) + return XCreateFontCursor(Xdisplay, q); + int len = img.GetLength(); + Size sz = img.GetSize(); + Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, sz.cx, sz.cy, 32); + XPicture picture = XRenderCreatePicture( + Xdisplay, pixmap, + XRenderFindStandardFormat(Xdisplay, PictStandardARGB32), + 0, 0 + ); + XImage ximg; + sInitXImage(ximg, sz); + ximg.bitmap_pad = 32; + ximg.bytes_per_line = 4 * sz.cx; + ximg.bits_per_pixel = 32; + ximg.blue_mask = 0x00ff0000; + ximg.green_mask = 0x0000ff00; + ximg.red_mask = 0x000000ff; + Buffer pma; + pma.Alloc(len); + memcpy(pma, ~img, len * sizeof(RGBA)); + ximg.bitmap_unit = 32; + ximg.depth = 32; + ximg.data = (char *)~pma; + XInitImage(&ximg); + GC gc = XCreateGC(Xdisplay, pixmap, 0, 0); + XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, sz.cx, sz.cy); + XFreeGC(Xdisplay, gc); + XFreePixmap(Xdisplay, pixmap); + Point p = img.GetHotSpot(); + Cursor c = XRenderCreateCursor(Xdisplay, picture, p.x, p.y); + XRenderFreePicture(Xdisplay, picture); + return c; +} + +#endif + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/MakeCache.cpp b/uppdev/Draw/MakeCache.cpp new file mode 100644 index 000000000..5f03c5280 --- /dev/null +++ b/uppdev/Draw/MakeCache.cpp @@ -0,0 +1,176 @@ +#include "Draw.h" + +NAMESPACE_UPP + +#define LLOG(x) // LOG(x) + +static StaticCriticalSection sMakeImage; + +static LRUCache& sImageCache() +{ + static LRUCache m; + return m; +} + +struct scImageMaker : LRUCache::Maker { + const ImageMaker *m; + bool paintonly; + + virtual String Key() const { +// String q = m->Key(); + return m->Key(); + } + virtual int Make(Image& object) const { + object = m->Make(); + if(paintonly) { + SetPaintOnly___(object); + return object.GetLength() + 20000; + } + return object.GetLength() + 100; + } +}; + +static int sMaxSize; +static int sMaxSizeMax = 4000000; + +void ClearMakeImageCache() +{ + sImageCache().Clear(); +} + +void SetMakeImageCacheMax(int m) +{ + sMaxSizeMax = m; +} + +void SetMakeImageCacheSize(int m) +{ + sMaxSize = m; +} + +void SweepMkImageCache() +{ + INTERLOCKED_(sMakeImage) { + LRUCache& cache = sImageCache(); + cache.ClearCounters(); + } +} + +Image MakeImage__(const ImageMaker& m, bool paintonly) +{ + Image result; + INTERLOCKED_(sMakeImage) { + LRUCache& cache = sImageCache(); + scImageMaker cm; + cm.m = &m; + cm.paintonly = paintonly; + result = cache.Get(cm); + int q = min(cache.GetFoundSize() + cache.GetNewSize(), sMaxSizeMax); + if(q > sMaxSize) { + sMaxSize = q; + LLOG("ImageCache: Increasing maxsize to " << sMaxSize); + } + cache.Shrink(sMaxSize); + } + return result; +} + +Image MakeImage(const ImageMaker& m) +{ + return MakeImage__(m, false); +} + +Image MakeImagePaintOnly(const ImageMaker& m) +{ + return MakeImage__(m, true); +} + +class SimpleImageMaker : public ImageMaker { + Image (*make)(const Image& image); + Image image; + +public: + virtual String Key() const; + virtual Image Make() const; + + SimpleImageMaker(const Image& image, Image (*make)(const Image& image)) + : make(make),image(image) {} +}; + +String SimpleImageMaker::Key() const +{ + String key; + int64 k = image.GetSerialId(); + key.Cat((const char *)&k, sizeof(int64)); + key.Cat((const char *)&make, sizeof(make)); + return key; +} + +Image SimpleImageMaker::Make() const +{ + return (*make)(image); +} + +Image MakeImage(const Image& image, Image (*make)(const Image& image)) +{ + return MakeImage(SimpleImageMaker(image, make)); +} + +struct sCachedRescale : public ImageMaker +{ + Rect src; + Size sz; + Image img; + + virtual String Key() const { + StringBuffer h; + RawCat(h, src.left); + RawCat(h, src.top); + RawCat(h, src.right); + RawCat(h, src.bottom); + RawCat(h, sz.cx); + RawCat(h, sz.cy); + RawCat(h, img.GetSerialId()); + return h; + } + + virtual Image Make() const { + return Rescale(img, sz, src); + } + +}; + +Image CachedRescale(const Image& m, Size sz, const Rect& src) +{ + if(m.GetSize() == sz) + return m; + sCachedRescale cr; + cr.sz = sz; + cr.src = src; + cr.img = m; + return MakeImage(cr); +} + +Image CachedRescale(const Image& m, Size sz) +{ + return CachedRescale(m, sz, m.GetSize()); +} + +Image CachedRescalePaintOnly(const Image& m, Size sz, const Rect& src) +{ + if(m.GetSize() == sz) + return m; + sCachedRescale cr; + cr.sz = sz; + cr.src = src; + cr.img = m; + return MakeImagePaintOnly(cr); +} + +Image CachedRescalePaintOnly(const Image& m, Size sz) +{ + return CachedRescalePaintOnly(m, sz, m.GetSize()); +} + + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/MetaFile.cpp b/uppdev/Draw/MetaFile.cpp new file mode 100644 index 000000000..474df4543 --- /dev/null +++ b/uppdev/Draw/MetaFile.cpp @@ -0,0 +1,253 @@ +#include "Draw.h" + +NAMESPACE_UPP + +#ifdef PLATFORM_WIN32 +#ifndef PLATFORM_WINCE + +void WinMetaFile::Init() { + hemf = NULL; +} + +void WinMetaFile::Paint(Draw& w, const Rect& r) const { + ChkP(); + if(hemf) + PlayEnhMetaFile(w, hemf, r); +} + +void WinMetaFile::Paint(Draw& w, int x, int y, int cx, int cy) const { + Paint(w, RectC(x, y, cx, cy)); +} + +void WinMetaFile::ReadClipboard() { + Clear(); + if(::IsClipboardFormatAvailable(CF_ENHMETAFILE) && ::OpenClipboard(NULL)) { + HENHMETAFILE hemf = (HENHMETAFILE) ::GetClipboardData(CF_ENHMETAFILE); + if(hemf) Attach(hemf); + ::CloseClipboard(); + } +} + +void WinMetaFile::WriteClipboard() const { + if(hemf && ::OpenClipboard(NULL)) { + ::EmptyClipboard(); + ::SetClipboardData(CF_ENHMETAFILE, CopyEnhMetaFile(hemf, NULL)); + ::CloseClipboard(); + } +} + +void WinMetaFile::Clear() { + if(hemf && !IsPicked()) + ::DeleteEnhMetaFile(hemf); + hemf = NULL; +} + +void WinMetaFile::Pick(pick_ WinMetaFile& src) { + hemf = src.hemf; + size = src.size; + src.hemf = (HENHMETAFILE)(intptr_t) 0xffffffff; +} + +void WinMetaFile::Copy(const WinMetaFile& src) { + hemf = ::CopyEnhMetaFile(src.hemf, NULL); + size = src.size; +} + +void WinMetaFile::Attach(HENHMETAFILE _hemf) { + Clear(); + ENHMETAHEADER info; + memset(&info, 0, sizeof(info)); + info.iType = EMR_HEADER; + info.nSize = sizeof(info); + info.dSignature = ENHMETA_SIGNATURE; + if(_hemf && ::GetEnhMetaFileHeader(_hemf, sizeof(info), &info) + && info.rclFrame.left < info.rclFrame.right + && info.rclFrame.top < info.rclFrame.bottom) { + size.cx = 600 * (info.rclFrame.right - info.rclFrame.left) / 2540; + size.cy = 600 * (info.rclFrame.bottom - info.rclFrame.top) / 2540; + hemf = _hemf; + } +} + +#pragma pack(push, 1) +struct PLACEABLE_METAFILEHEADER +{ + DWORD key; + WORD hmf; + short left, top, right, bottom; + WORD inch; + DWORD reserved; + WORD checksum; +}; +#pragma pack(pop) + +bool WinMetaFile::Load(const char* path) { + Clear(); + FileIn file(path); + if(!file.Open(path) || file.GetSize() <= sizeof(ENHMETAHEADER)) + return false; + + int first = file.Get32le(); + file.Seek(0); + + HENHMETAFILE hemf; + HMETAFILE hMF; + Size sz(1000, 1000); + + if(first == 0x9AC6CDD7) { + PLACEABLE_METAFILEHEADER mfh; + file.Get(&mfh, 22); + String bits = LoadStream(file); + if((hMF = ::SetMetaFileBitsEx(bits.GetLength(), bits)) == NULL) + return false; + sz = Size(mfh.right - mfh.left, mfh.bottom - mfh.top); + } + else + if((hemf = ::GetEnhMetaFile(path)) != NULL) { + Attach(hemf); + return true; + } + else + if((LOWORD(first) == 1 || LOWORD(first) == 2) && HIWORD(first) >= sizeof(METAHEADER) / 2) { + METAHEADER mh; + if(!file.GetAll(&mh, sizeof(mh))) + return false; + if(mh.mtVersion != 0x100 && mh.mtVersion != 0x300) + return false; + if((hMF = ::GetMetaFile(path)) == NULL) + return false; + } + else + return false; + + dword len = ::GetMetaFileBitsEx(hMF, 0, NULL); + Buffer bits(len); + ::GetMetaFileBitsEx(hMF, len, bits); + Attach(::SetWinMetaFileBits(len, bits, NULL, NULL)); + ::DeleteMetaFile(hMF); + size = sz; + return true; +} + +void WinMetaFile::Serialize(Stream& s) { + dword size = 0; + if(s.IsStoring()) { + if(hemf) { + size = ::GetEnhMetaFileBits(hemf, 0, 0); + s % size; + Buffer buffer(size); + ::GetEnhMetaFileBits(hemf, size, buffer); + s.SerializeRaw(buffer, size); + } + else + s % size; + } + else { + Clear(); + s % size; + if(size) { + Buffer buffer(size); + s.SerializeRaw(buffer, size); + HENHMETAFILE hemf = ::SetEnhMetaFileBits(size, buffer); + Attach(hemf); + } + } +} + +WinMetaFile::WinMetaFile(HENHMETAFILE hemf) { + Init(); + Attach(hemf); +} + +WinMetaFile::WinMetaFile(HENHMETAFILE hemf, Size sz) { + Init(); + Attach(hemf); + size = sz; +} + +WinMetaFile::WinMetaFile(const char *file) { + Init(); + Load(file); +} + +bool WinMetaFileDraw::Create(HDC hdc, int cx, int cy, const char *app, const char *name, const char *file) { + if(handle) Close(); + + String s; + if(app) s.Cat(app); + s.Cat('\0'); + if(name) s.Cat(name); + s.Cat('\0'); + + bool del = false; + if(!hdc) { + hdc = ::GetWindowDC((HWND) NULL); + del = true; + } + size = Size(iscale(cx, 2540, 600), iscale(cy, 2540, 600)); + + Rect r = size; + + HDC mfdc = ::CreateEnhMetaFile(hdc, file, r, name || app ? (const char *)s : NULL); + if(!mfdc) + return false; + Size px(max(1, ::GetDeviceCaps(mfdc, HORZRES)), max(1, ::GetDeviceCaps(mfdc, VERTRES))); + Size mm(max(1, ::GetDeviceCaps(mfdc, HORZSIZE)), max(1, ::GetDeviceCaps(mfdc, VERTSIZE))); + Attach(mfdc); + + Init(); + + pixels = false; + + ::SetMapMode(handle, MM_ANISOTROPIC); + ::SetWindowOrgEx(handle, 0, 0, 0); + ::SetWindowExtEx(handle, 600, 600, 0); + ::SetViewportOrgEx(handle, 0, 0, 0); + ::SetViewportExtEx(handle, px.cx * 254 / (10 * mm.cx), px.cy * 254 / (10 * mm.cy), 0); + ::SelectClipRgn(mfdc, NULL); + ::IntersectClipRect(mfdc, 0, 0, cx, cy); + + if(del) { + ::ReleaseDC((HWND) NULL, hdc); + hdc = NULL; + } + + actual_offset = Point(0, 0); + + printer = false; + pixels = false; + actual_offset = Point(0, 0); + device = -1; + aborted = false; + palette = false; + backdraw = true; + + return true; +} + +bool WinMetaFileDraw::Create(int cx, int cy, const char *app, const char *name, const char *file) { + return Create(NULL, cx, cy, app, name, file); +} + +WinMetaFile WinMetaFileDraw::Close() { + HDC hdc = Detach(); + ASSERT(hdc); + return WinMetaFile(CloseEnhMetaFile(hdc), size); +} + +WinMetaFileDraw::~WinMetaFileDraw() { + if(handle) Close(); +} + +WinMetaFileDraw::WinMetaFileDraw(HDC hdc, int cx, int cy, const char *app, const char *name, const char *file) { + Create(hdc, cx, cy, app, name, file); +} + +WinMetaFileDraw::WinMetaFileDraw(int cx, int cy, const char *app, const char *name, const char *file) { + Create(cx, cy, app, name, file); +} + +#endif +#endif + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/Palette.cpp b/uppdev/Draw/Palette.cpp new file mode 100644 index 000000000..65d0c4f7f --- /dev/null +++ b/uppdev/Draw/Palette.cpp @@ -0,0 +1,281 @@ +#include "Draw.h" + +NAMESPACE_UPP + +#define LTIMING(x) + +struct sPalCv { + PaletteCv& cv_pal; + const RGBA *palette; + int ncolors; + bool done[RASTER_MAP_G]; + struct Ginfo { + int dist; + byte g; + byte ii; + }; + + enum _n { BINS = 16, BINSHIFT = 11 }; + + Ginfo line[BINS][256]; + Ginfo *eline[BINS]; + byte *gline; + + static int Sq(int a, int b) { return (a - b) * (a - b); } + + void SetLine(int r, int b); + int Get(int g); + + sPalCv(const RGBA *palette, int ncolors, PaletteCv& cv_pal); + sPalCv(const RGBA *palette, int ncolors, PaletteCv& cv_pal, + int histogram[RASTER_MAP_R][RASTER_MAP_G][RASTER_MAP_B]); +}; + +void sPalCv::SetLine(int r, int b) +{ + gline = cv_pal.At(r, b); + r = 255 * r / (RASTER_MAP_R - 1); //IMPROVE! + b = 255 * b / (RASTER_MAP_B - 1); + for(int i = 0; i < BINS; i++) + eline[i] = line[i]; + for(int i = 0; i < ncolors; i++) { + int dist = Sq(palette[i].r, r) + Sq(palette[i].b, b); + int bini = dist >> BINSHIFT; + Ginfo *t = eline[bini >= BINS ? BINS - 1 : bini]++; + t->dist = dist; + t->g = palette[i].g; + t->ii = i; + } + ZeroArray(done); +} + +int sPalCv::Get(int g) +{ + if(done[g]) + return gline[g]; + int gg = 255 * g / (RASTER_MAP_G - 1); + int ii = 0; + int dist = INT_MAX; + for(int th = 0; th < BINS; th++) { + Ginfo *s = line[th]; + Ginfo *e = eline[th]; + while(s < e) { + int sdist = Sq(s->g, gg) + s->dist; + if(sdist < dist) { + ii = s->ii; + dist = sdist; + } + s++; + } + if(th < BINS - 1 && dist < ((th + 1) << BINSHIFT)) + break; + } + done[g] = true; + gline[g] = ii; + return ii; +} + +sPalCv::sPalCv(const RGBA *palette, int ncolors, PaletteCv& cv_pal) +: cv_pal(cv_pal), palette(palette), ncolors(ncolors) +{ + byte ender[256]; + for(int b = 0; b < RASTER_MAP_B; b++) { + ZeroArray(ender); + for(int r = 0; r < RASTER_MAP_R; r++) { + SetLine(r, b); + int g = 0; + while(g < RASTER_MAP_G) { + int ii = Get(g); + int eg = max(g, ender[ii]); + if(Get(eg) == ii) + while(eg < RASTER_MAP_G - 1 && Get(eg + 1) == ii) + eg++; + else + while(Get(eg) != ii) + eg--; + ender[ii] = eg; + g++; + while(g <= eg - 1) { + gline[g] = ii; + done[g] = true; + g++; + } + } + } + } +} + +sPalCv::sPalCv(const RGBA *palette, int ncolors, PaletteCv& cv_pal, + int histogram[RASTER_MAP_R][RASTER_MAP_G][RASTER_MAP_B]) +: cv_pal(cv_pal), palette(palette), ncolors(ncolors) +{ + for(int b = 0; b < RASTER_MAP_B; b++) { + for(int r = 0; r < RASTER_MAP_R; r++) { + SetLine(r, b); + for(int g = 0; g < RASTER_MAP_G; g++) + if(histogram[r][g][b]) + Get(g); + } + } +} + +struct sPalMaker { + int histogram[RASTER_MAP_R][RASTER_MAP_G][RASTER_MAP_B]; + int colorcount; + struct Dim { + int l, h; + + operator int() { return h - l; } + }; + enum { G = 0, R = 1, B = 2 }; + void Copy(Dim *d, Dim *s) { d[R] = s[R]; d[G] = s[G]; d[B] = s[B]; } + struct Box { + int volume; + int colorcount; + int population; + Dim dim[3]; + int avg_r, avg_g, avg_b; + + Dim& operator[](int i) { return dim[i]; } + }; + + void Update(Box& box, int ii); + + sPalMaker(Raster& raster, RGBA *palette, int ncolors); +}; + +void sPalMaker::Update(Box& x, int ii) +{ + x.colorcount = 0; + x.population = 0; + int a[3][RASTER_MAP_MAX]; + ZeroArray(a[R]); + ZeroArray(a[G]); + ZeroArray(a[B]); + x.avg_r = x.avg_g = x.avg_b = 0; + for(int r = x[R].l; r < x[R].h; r++) + for(int g = x[G].l; g < x[G].h; g++) + for(int b = x[B].l; b < x[B].h; b++) { + int q = histogram[r][g][b]; + a[R][r] += q; + a[G][g] += q; + a[B][b] += q; + x.avg_r += q * r; + x.avg_g += q * g; + x.avg_b += q * b; + #ifdef CPU_X86 + x.colorcount += q > 0; + #else + x.colorcount += (-q >> 31) & 1; + #endif + x.population += q; + } + for(int i = 0; i < 3; i++) { + Dim& d = x[i]; + while(d.l < d.h && a[i][d.l] == 0) + d.l++; + while(d.h > d.l && a[i][d.h - 1] == 0) + d.h--; + } + x.volume = x[R] * x[G] * x[B]; +} + +static byte sRc(int avg, int pop, int div) +{ + return Saturate255(255 * (avg + (pop >> 1)) / pop / (div - 1)); +} + +sPalMaker::sPalMaker(Raster& raster, RGBA *palette, int ncolors) +{ + ASSERT(ncolors <= 256); + ZeroArray(histogram); + Size sz = raster.GetSize(); + for(int y = 0; y < sz.cy; y++) { + Raster::Line line = raster[y]; + const RGBA *s = line; + const RGBA *e = s + sz.cx; + while(s < e) { + histogram[s->r >> RASTER_SHIFT_R][s->g >> RASTER_SHIFT_G][s->b >> RASTER_SHIFT_B]++; + s++; + } + } + Buffer box(256); + box[0][R].l = 0; + box[0][R].h = RASTER_MAP_R; + box[0][G].l = 0; + box[0][G].h = RASTER_MAP_G; + box[0][B].l = 0; + box[0][B].h = RASTER_MAP_B; + Update(box[0], 0); + if(box[0].population == 0) + return; + colorcount = box[0].colorcount; + int count = 1; + int method = 0; + while(count < ncolors) { + int ii = -1; + int maxv = 0; + if(2 * count > ncolors) + method = 1; + for(int i = 0; i < count; i++) { + int v = method ? box[i].volume : box[i].colorcount; + if(box[i].colorcount > 1 && v > maxv) { + ii = i; + maxv = v; + } + } + if(ii < 0) + break; + Box& b = box[ii]; + int ci = b[R] > b[G] ? b[B] > b[R] ? B : R : b[B] > b[G] ? B : G; + if(b[ci] == 1) { + if(method == 1) + break; + method = 1; + } + else { + int m = (b[ci].l + b[ci].h) >> 1; + Box& b1 = box[count]; + b1 = b; + b[ci].h = m; + b1[ci].l = m; + Update(b, ii); + Update(b1, count++); + } + } + for(int i = 0; i < count; i++) { + RGBA& c = palette[i]; + Box& x = box[i]; + c.r = sRc(x.avg_r, x.population, RASTER_MAP_R); + c.g = sRc(x.avg_g, x.population, RASTER_MAP_G); + c.b = sRc(x.avg_b, x.population, RASTER_MAP_B); + c.a = 255; + } +} + +void CreatePaletteCv(const RGBA *palette, int ncolors, PaletteCv& cv_pal) +{ + LTIMING("PaletteCv"); + ASSERT(ncolors <= 256); + delete new sPalCv(palette, ncolors, cv_pal); +} + +void CreatePalette(Raster& raster, RGBA *palette, int ncolors) +{ + LTIMING("Palette"); + ASSERT(ncolors <= 256); + delete new sPalMaker(raster, palette, ncolors); +} + +void CreatePalette(Raster& raster, RGBA *palette, int ncolors, PaletteCv& cv) +{ + LTIMING("Palette+Cv"); + ASSERT(ncolors <= 256); + One m = new sPalMaker(raster, palette, ncolors); + if(m->colorcount < 15000) // Is that right!? + delete new sPalCv(palette, ncolors, cv, m->histogram); + else + CreatePaletteCv(palette, ncolors, cv); +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/Raster.cpp b/uppdev/Draw/Raster.cpp new file mode 100644 index 000000000..af00953ca --- /dev/null +++ b/uppdev/Draw/Raster.cpp @@ -0,0 +1,255 @@ +#include "Draw.h" + +NAMESPACE_UPP + +Raster::Info::Info() +{ + bpp = 24; + colors = 1 << 24; + dots = Size(0, 0); + hotspot = Point(0, 0); + kind = IMAGE_OPAQUE; +} + +const RasterFormat *Raster::GetFormat() +{ + return NULL; +} + +void Raster::SeekPage(int page) +{ + ASSERT(page == 0); +} + +int Raster::GetPageCount() +{ + return 1; +} + +void Raster::Line::Pick(pick_ Line& b) +{ + data = b.data; + fmtdata = b.fmtdata; + raster = b.raster; + free = b.free; + fmtfree = b.fmtfree; + const_cast(&b)->free = const_cast(&b)->fmtfree = false; +#ifdef _DEBUG + const_cast(&b)->data = NULL; + const_cast(&b)->fmtdata = NULL; +#endif +} + +void Raster::Line::MakeRGBA() const +{ + ASSERT(fmtdata && raster); + int cx = raster->GetWidth(); + const RasterFormat *f = raster->GetFormat(); + if(f) { + RGBA *rgba = new RGBA[cx]; + free = true; + f->Read(rgba, fmtdata, cx, raster->GetPalette()); + data = rgba; + } + else + data = (const RGBA *)fmtdata; +} + +Raster::Info Raster::GetInfo() +{ + Info f; + f.bpp = 32; + f.colors = 256*256*256; + f.dots = Size(0, 0); + f.hotspot = Point(0, 0); + f.kind = IMAGE_ALPHA; + return f; +} + +bool Raster::Create() { return true; } + +bool Raster::IsError() { return false; } + +int Raster::GetPaletteCount() { return 0; } + +const RGBA *Raster::GetPalette() { return NULL; } + +Image Raster::GetImage(int x, int y, int cx, int cy, const Gate2 progress) +{ + Size size = GetSize(); + y = minmax(y, 0, size.cy); + int yy = minmax(y + cy, y, size.cy); + x = minmax(x, 0, size.cx); + cx = minmax(x + cx, x, size.cx) - x; + ImageBuffer b(cx, yy - y); + RGBA* t = b; + int y0 = y; + while(y < yy) { + if(progress(y - y0, yy - y0)) + return Null; + memcpy(t, ~GetLine(y) + x, cx * sizeof(RGBA)); + t += cx; + y++; + } + Info f = GetInfo(); + b.SetHotSpot(f.hotspot - Point(x, y0)); + if(size.cx && size.cy) + b.SetDots(Size(f.dots.cx * cx / size.cx, f.dots.cy * cy / size.cy)); + return IsError() ? Image() : Image(b); +} + +Image Raster::GetImage(const Gate2 progress) +{ + Size sz = GetSize(); + return GetImage(0, 0, sz.cx, sz.cy, progress); +} + +Raster::~Raster() {} + +Raster::Line ImageRaster::GetLine(int line) +{ + return Line(img[line], false); +} + +Size ImageRaster::GetSize() +{ + return img.GetSize(); +} + +Raster::Info ImageRaster::GetInfo() +{ + Raster::Info f = Raster::GetInfo(); + f.dots = img.GetDots(); + f.hotspot = img.GetHotSpot(); + f.kind = img.GetKind(); + return f; +} + +MemoryRaster::MemoryRaster() +: size(0, 0) +{ +} + +void MemoryRaster::Load(Raster& raster) +{ + info = raster.GetInfo(); + size = raster.GetSize(); + palette.SetCount(raster.GetPaletteCount()); + if(!palette.IsEmpty()) + memcpy(palette, raster.GetPalette(), palette.GetCount() * sizeof(RGBA)); + lines.SetCount(size.cy); + if(const RasterFormat *fmt = raster.GetFormat()) { + format = *fmt; + int rowbytes = format.GetByteCount(size.cx); + for(int i = 0; i < size.cy; i++) { + lines[i].Alloc(rowbytes); + memcpy(~lines[i], raster.GetLine(i).GetRawData(), rowbytes); + } + } + else { + format.SetRGBA(); + int rowbytes = sizeof(RGBA) * size.cx; + for(int i = 0; i < size.cy; i++) { + lines[i].Alloc(rowbytes); + memcpy(~lines[i], raster.GetLine(i).GetRGBA(), rowbytes); + } + } +} + +Raster::Line MemoryRaster::GetLine(int line) +{ + if(format.IsRGBA()) + return Line((const RGBA *)~lines[line], false); + else + return Line(~lines[line], this, false); +} + +int MemoryRaster::GetLength() const +{ + return size.cy * (format.IsRGBA() + ? size.cx * sizeof(RGBA) + : ((size.cx * info.bpp + 31) >> 5) * 4); +} + +bool StreamRaster::Open(Stream& _s) +{ + s = &_s; + error = !Create(); + return !error; +} + +bool StreamRaster::IsError() +{ + return error || !s || s->IsError(); +} + +Image StreamRaster::Load(Stream& s, const Gate2 progress) +{ + if(Open(s)) { + Image img = GetImage(progress); + if(!IsError()) + return img; + } + return Image(); +} + +Image StreamRaster::LoadFile(const char *fn, const Gate2 progress) +{ + FileIn in(fn); + return in ? Load(in, progress) : Image(); +} + +Image StreamRaster::LoadString(const String& s, const Gate2 progress) +{ + StringStream ss(s); + return Load(ss, progress); +} + +static StaticCriticalSection sAnyRaster; + +Vector& StreamRaster::Map() +{ + static Vector x; + return x; +} + +void StreamRaster::AddFormat(RasterFactory factory) +{ + INTERLOCKED_(sAnyRaster) + Map().Add((void *)factory); +} + +One StreamRaster::OpenAny(Stream& s) +{ + INTERLOCKED_(sAnyRaster) + for(int i = 0; i < Map().GetCount(); i++) { + int64 p = s.GetPos(); + One raster = (*RasterFactory(Map()[i]))(); + s.ClearError(); + if(raster->Open(s)) + return raster; + s.ClearError(); + s.Seek(p); + } + return NULL; +} + +Image StreamRaster::LoadAny(Stream& s, const Gate2 progress) +{ + One r = OpenAny(s); + return r ? r->GetImage(progress) : Image(); +} + +Image StreamRaster::LoadFileAny(const char *fn, const Gate2 progress) +{ + FileIn in(fn); + return LoadAny(in, progress); +} + +Image StreamRaster::LoadStringAny(const String& s, const Gate2 progress) +{ + StringStream ss(s); + return LoadAny(ss, progress); +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/Raster.h b/uppdev/Draw/Raster.h new file mode 100644 index 000000000..22e9a74a0 --- /dev/null +++ b/uppdev/Draw/Raster.h @@ -0,0 +1,297 @@ +enum { + RASTER_1, + RASTER_2, + RASTER_4, + RASTER_8, + RASTER_8ALPHA, + RASTER_16, + RASTER_24, + RASTER_32, + RASTER_32ALPHA, + RASTER_32PREMULTIPLIED, + + RASTER_MSBFIRST = 0x80, + + RASTER_MAP_R = 32, + RASTER_SHIFT_R = 3, + RASTER_MAP_G = 64, + RASTER_SHIFT_G = 2, + RASTER_MAP_B = 16, + RASTER_SHIFT_B = 4, + + RASTER_MAP_MAX = 64 +}; + +struct PaletteCv { + Buffer cv; + + byte *At(int r, int b) { return cv + (r << 10) + (b << 6); } + byte Get(const RGBA& b) const { return cv[(int(b.r >> RASTER_SHIFT_R) << 10) + + (int(b.g >> RASTER_SHIFT_G)) + + (int(b.b >> RASTER_SHIFT_B) << 6)]; } + PaletteCv() { cv.Alloc(RASTER_MAP_R * RASTER_MAP_G * RASTER_MAP_B); } +}; + +struct RasterFormat { + byte type; + dword rmask, gmask, bmask, amask; + + void Set1lf() { type = RASTER_1; } + void Set1mf() { type = RASTER_1|RASTER_MSBFIRST; } + void Set2lf() { type = RASTER_2; } + void Set2mf() { type = RASTER_2|RASTER_MSBFIRST; } + void Set4lf() { type = RASTER_4; } + void Set4mf() { type = RASTER_4|RASTER_MSBFIRST; } + void Set8() { type = RASTER_8; } + void Set8A() { type = RASTER_8ALPHA; } + void Set16le(dword rmask, dword gmask, dword bmask); + void Set16be(dword rmask, dword gmask, dword bmask); + void Set24le(dword rmask, dword gmask, dword bmask); + void Set24be(dword rmask, dword gmask, dword bmask); + void Set32le(dword rmask, dword gmask, dword bmask, dword amask = 0); + void Set32be(dword rmask, dword gmask, dword bmask, dword amask = 0); + void Set32leStraight(dword rmask, dword gmask, dword bmask, dword amask); + void Set32beStraight(dword rmask, dword gmask, dword bmask, dword amask); + void SetRGBA(); + void SetRGBAStraight(); + + int IsRGBA() const; + int GetByteCount(int cx) const; + int GetBpp() const; + bool HasAlpha() const; + int GetColorCount() const; + int GetPaletteCount() const; + + void Read(RGBA *t, const byte *s, int cx, const RGBA *palette) const; + void Write(byte *t, const RGBA *s, int cx, const PaletteCv *palcv) const; + +private: + byte rpos, gpos, bpos, apos; + static void TailBits(RGBA *t, const byte *src, int cx, byte andm, byte shift, const RGBA *palette); + static void TailBitsMSB1st(RGBA *t, const byte *src, int cx, byte shift1, byte andm, byte shift, const RGBA *palette); +}; + +class Raster { +public: + class Line { + mutable const RGBA *data; + const byte *fmtdata; + Raster *raster; + mutable bool free; + bool fmtfree; + + friend class Raster; + + void MakeRGBA() const; + + public: + const RGBA *GetRGBA() const { if(!data) MakeRGBA(); return data; } + const byte *GetRawData() const { return fmtdata; } + operator const RGBA *() const { return GetRGBA(); } + const RGBA *operator~() const { return GetRGBA(); } + + Line(const RGBA *data, bool free) + : data(data), fmtdata((byte *)data), raster(NULL), free(free), fmtfree(false) {} + Line(const byte *fmtdata, Raster *raster, bool fmtfree) + : data(NULL), fmtdata(fmtdata), raster(raster), free(false), fmtfree(fmtfree) {} + Line(pick_ Line& b) { Pick(b); } + Line() { data = NULL; fmtdata = NULL; raster = NULL; free = fmtfree = false; } + ~Line() { Free(); } + + void Free() { if(free) delete[] data; if(fmtfree) delete[] fmtdata; } + void Pick(pick_ Line& b); + + void operator=(pick_ Line& b) { Free(); Pick(b); } + }; + + struct Info { + int bpp; + int colors; + Size dots; + Point hotspot; + int kind; + + Info(); + }; + +public: + virtual void SeekPage(int page); + virtual int GetPageCount(); + + virtual bool Create(); + virtual Size GetSize() = 0; + virtual Info GetInfo(); + virtual Line GetLine(int line) = 0; + virtual bool IsError(); + virtual int GetPaletteCount(); + virtual const RGBA *GetPalette(); + virtual const RasterFormat *GetFormat(); + + int GetWidth() { return GetSize().cx; } + int GetHeight() { return GetSize().cy; } + Line operator[](int i) { return GetLine(i); } + + Image GetImage(int x, int y, int cx, int cy, const Gate2 progress = false); + Image GetImage(const Gate2 progress = false); + + virtual ~Raster(); +}; + +typedef Raster::Line RasterLine; +typedef Raster::Info RasterInfo; + +void CreatePaletteCv(const RGBA *palette, int ncolors, PaletteCv& cv_pal); +void CreatePalette(Raster& raster, RGBA *palette, int ncolors); +void CreatePalette(Raster& raster, RGBA *palette, int ncolors, PaletteCv& cv); + +class ImageRaster : public Raster { + Image img; + +public: + virtual Size GetSize(); + virtual Line GetLine(int line); + virtual Info GetInfo(); + + ImageRaster(const Image& img) : img(img) {} +}; + +class MemoryRaster : public Raster { +public: + MemoryRaster(); + MemoryRaster(Raster& raster) { Load(raster); } + + virtual Size GetSize() { return size; } + virtual Info GetInfo() { return info; } + virtual Line GetLine(int line); + virtual int GetPaletteCount() { return palette.GetCount(); } + virtual const RGBA *GetPalette() { return palette.Begin(); } + virtual const RasterFormat *GetFormat() { return &format; } + + void Load(Raster& raster); + int GetLength() const; + +private: + RasterFormat format; + Info info; + Size size; + Vector< Buffer > lines; + Vector palette; +}; + +class StreamRaster : public Raster { + Stream *s; + bool error; + + typedef StreamRaster *(*RasterFactory)(); + template static StreamRaster *FactoryFn() { return new T; } + static void AddFormat(RasterFactory f); + static Vector& Map(); + +public: + Stream& GetStream() { return *s; } + bool Open(Stream& _s); + bool IsError(); + + void SetError() { error = true; } + + Image Load(Stream& s, const Gate2 progress = false); + Image LoadFile(const char *fn, const Gate2 progress = false); + Image LoadString(const String& s, const Gate2 progress = false); + + template + static void Register() { AddFormat(&StreamRaster::FactoryFn); } + + static One OpenAny(Stream& s); + static Image LoadAny(Stream& s, const Gate2 progress = false); + static Image LoadFileAny(const char *fn, const Gate2 progress = false); + static Image LoadStringAny(const String& s, const Gate2 progress = false); + + StreamRaster() { error = true; } +}; + +class RasterEncoder { + Size size, dots; + Point hotspot; + RGBA *line; + Buffer scanline; + int line_bytes; + Buffer h; + Buffer palette; + One palette_cv; + + RGBA *Pal(); + +protected: + RasterFormat format; + void SetLine(RGBA *_line); + +public: + virtual int GetPaletteCount(); + virtual void Start(Size sz) = 0; + virtual void WriteLineRaw(const byte *data) = 0; + + void WriteLine(); + void WriteLine(const RGBA *s); + + const RasterFormat& GetFormat() const { return format; } + const RGBA *GetPalette(); + const PaletteCv *GetPaletteCv() { return ~palette_cv; } + + operator RGBA *() { return line; } + RGBA *operator~() { return line; } + Size GetSize() const { return size; } + int GetWidth() const { return GetSize().cx; } + int GetHeight() const { return GetSize().cy; } + + void SetHotSpot(Point p) { hotspot = p; } + Point GetHotSpot() const { return hotspot; } + + void SetDots(Size _dots) { dots = _dots; } + Size GetDots() const { return dots; } + + void SetPalette(const RGBA *palette); + void SetPalette(Raster& pal_raster); + + void Create(Size sz); + void Create(int cx, int cy) { Create(Size(cx, cy)); } + + void Create(Size sz, const RGBA *palette); + void Create(int cx, int cy, const RGBA *palette); + void Create(Size sz, Raster& pal_raster); + void Create(int cx, int cy, Raster& pal_raster); + + RasterEncoder(); + virtual ~RasterEncoder(); +}; + +class ImageEncoder : public RasterEncoder { + int ii; + ImageBuffer ib; + +public: + virtual void Start(Size sz); + virtual void WriteLineRaw(const byte *data); + + Size GetSize() const { return ib.GetSize(); } + int GetWidth() const { return GetSize().cx; } + int GetHeight() const { return GetSize().cy; } + + operator const RGBA *() { return Image(ib); } + operator Image() { return Image(ib); } +}; + +class StreamRasterEncoder : public RasterEncoder { + Stream *s; + +public: + Stream& GetStream() { return *s; } + void SetStream(Stream& _s) { s = &_s; } + + void Save(Stream& s, Raster& raster); + bool SaveFile(const char *fn, Raster& raster); + String SaveString(Raster& raster); + + void Save(Stream& s, const Image& img); + bool SaveFile(const char *fn, const Image& img); + String SaveString(const Image& img); +}; diff --git a/uppdev/Draw/RasterEncoder.cpp b/uppdev/Draw/RasterEncoder.cpp new file mode 100644 index 000000000..bc3190ab9 --- /dev/null +++ b/uppdev/Draw/RasterEncoder.cpp @@ -0,0 +1,178 @@ +#include "Draw.h" + +NAMESPACE_UPP + +RasterEncoder::RasterEncoder() +{ + size = Size(0, 0); + dots = Size(0, 0); + hotspot = Point(0, 0); + format.SetRGBA(); +} + +void RasterEncoder::SetLine(RGBA *_line) +{ + line = _line; + h.Clear(); +} + +void RasterEncoder::WriteLine(const RGBA *s) +{ + if(format.IsRGBA()) + WriteLineRaw((byte *)s); + else { + if(!scanline) + scanline.Alloc(format.GetByteCount(size.cx)); + format.Write(scanline, s, size.cx, GetPaletteCv()); + WriteLineRaw(scanline); + } +} + +void RasterEncoder::WriteLine() +{ + WriteLine(line); +} + +void RasterEncoder::Create(Size sz) +{ + size = sz; + h.Alloc(sz.cx); + line = h; + Start(sz); + scanline.Clear(); + line_bytes = format.GetByteCount(size.cx); +} + +RGBA *RasterEncoder::Pal() +{ + if(!palette) + palette.Alloc(256); + return palette; +} + +const RGBA *RasterEncoder::GetPalette() +{ + if(!palette) { + palette.Alloc(256); + RGBA *p = palette; + int n = GetPaletteCount(); + for(int i = 0; i < n; i++) + p[i].r = p[i].g = p[i].b = p[i].a = 255 * i * (n - 1) / (n - 1); + } + return palette; +} + +void RasterEncoder::SetPalette(const RGBA *pal) +{ + int n = GetPaletteCount(); + if(n) { + memcpy(Pal(), pal, n * sizeof(RGBA)); + palette_cv.Create(); + CreatePaletteCv(Pal(), n, *palette_cv); + } +} + +void RasterEncoder::SetPalette(Raster& raster) +{ + int n = GetPaletteCount(); + if(n) { + if(raster.GetPaletteCount() == n) + memcpy(Pal(), raster.GetPalette(), n * sizeof(RGBA)); + else + CreatePalette(raster, Pal(), n); + palette_cv.Create(); + CreatePaletteCv(Pal(), n, *palette_cv); + } +} + +void RasterEncoder::Create(Size sz, const RGBA *palette) +{ + SetPalette(palette); + Create(sz); +} + +void RasterEncoder::Create(int cx, int cy, const RGBA *palette) +{ + SetPalette(palette); + Create(cx, cy); +} + +void RasterEncoder::Create(Size sz, Raster& pal_raster) +{ + SetPalette(pal_raster); + Create(sz); +} + +void RasterEncoder::Create(int cx, int cy, Raster& pal_raster) +{ + SetPalette(pal_raster); + Create(cx, cy); +} + +int RasterEncoder::GetPaletteCount() +{ + return 0; +} + +RasterEncoder::~RasterEncoder() {} + +void ImageEncoder::Start(Size sz) +{ + ii = 0; + ib.Create(sz); + if(sz.cy) + SetLine(ib[0]); +} + +void ImageEncoder::WriteLineRaw(const byte *data) +{ + if((RGBA *)data != ~*this) + memcpy(~*this, data, GetSize().cx * sizeof(RGBA)); + if(++ii < GetHeight()) + SetLine(ib[ii]); +} + +void StreamRasterEncoder::Save(Stream& s, Raster& raster) +{ + SetStream(s); + Size sz = raster.GetSize(); + Create(sz, raster); + SetDots(raster.GetInfo().dots); + SetHotSpot(raster.GetInfo().hotspot); + for(int i = 0; i < sz.cy; i++) + WriteLine(raster[i]); +} + +bool StreamRasterEncoder::SaveFile(const char *fn, Raster& raster) +{ + FileOut out(fn); + Save(out, raster); + return !out.IsError(); +} + +String StreamRasterEncoder::SaveString(Raster& raster) +{ + StringStream ss; + Save(ss, raster); + return ss; +} + +void StreamRasterEncoder::Save(Stream& s, const Image& img) +{ + ImageRaster r(img); + Save(s, r); +} + +bool StreamRasterEncoder::SaveFile(const char *fn, const Image& img) +{ + ImageRaster r(img); + return SaveFile(fn, r); +} + +String StreamRasterEncoder::SaveString(const Image& img) +{ + ImageRaster r(img); + return SaveString(r); +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/RasterFormat.cpp b/uppdev/Draw/RasterFormat.cpp new file mode 100644 index 000000000..1dc9a2d40 --- /dev/null +++ b/uppdev/Draw/RasterFormat.cpp @@ -0,0 +1,368 @@ +#include "Draw.h" + +NAMESPACE_UPP + +static int sMaskPos16(dword mask) +{ + if(mask > 0xffff) + return 0; + int pos = 0; + while(((mask << pos) & 0x18000) != 0x8000) + pos++; + return pos; +} + +void RasterFormat::Set16le(dword _rmask, dword _gmask, dword _bmask) +{ + rpos = sMaskPos16(rmask = _rmask); + gpos = sMaskPos16(gmask = _gmask); + bpos = sMaskPos16(bmask = _bmask); + type = RASTER_16; +} + +void RasterFormat::Set16be(dword _rmask, dword _gmask, dword _bmask) +{ + Set16le(_rmask, _gmask, _bmask); + type = RASTER_16|RASTER_MSBFIRST; +} + +void RasterFormat::Set24le(dword rmask, dword gmask, dword bmask) +{ + rpos = GetChMaskPos32(rmask); + gpos = GetChMaskPos32(gmask); + bpos = GetChMaskPos32(bmask); + apos = 0; + type = RASTER_24; +} + +void RasterFormat::Set32le(dword rmask, dword gmask, dword bmask, dword amask) +{ + Set24le(rmask, gmask, bmask); + if(amask) { + apos = GetChMaskPos32(amask); + type = RASTER_32ALPHA; + } + else + type = RASTER_32; +} + +void RasterFormat::Set24be(dword rmask, dword gmask, dword bmask) +{ + rpos = 2 - GetChMaskPos32(rmask); + gpos = 2 - GetChMaskPos32(gmask); + bpos = 2 - GetChMaskPos32(bmask); + apos = 0; + type = RASTER_24; +} + +void RasterFormat::Set32be(dword rmask, dword gmask, dword bmask, dword amask) +{ + rpos = 3 - GetChMaskPos32(rmask); + gpos = 3 - GetChMaskPos32(gmask); + bpos = 3 - GetChMaskPos32(bmask); + if(amask) { + apos = 3 - GetChMaskPos32(amask); + type = RASTER_32PREMULTIPLIED; + } + else + type = RASTER_32; +} + +void RasterFormat::Set32leStraight(dword rmask, dword gmask, dword bmask, dword amask) +{ + Set32le(rmask, gmask, bmask, amask); + type = RASTER_32ALPHA; +} + +void RasterFormat::Set32beStraight(dword rmask, dword gmask, dword bmask, dword amask) +{ + Set32be(rmask, gmask, bmask, amask); + type = RASTER_32ALPHA; +} + +void RasterFormat::SetRGBA() +{ + type = RASTER_32PREMULTIPLIED; + bpos = 0; + gpos = 1; + rpos = 2; + apos = 3; +} + +void RasterFormat::SetRGBAStraight() +{ + type = RASTER_32ALPHA; + bpos = 0; + gpos = 1; + rpos = 2; + apos = 3; +} + +int RasterFormat::IsRGBA() const +{ + return (type & 31) == RASTER_32PREMULTIPLIED && bpos == 0 && gpos == 1 && rpos == 2 && apos == 3; +} + +static byte bits[16] = { 1, 2, 4, 8, 16, 16, 24, 32, 32, 32 }; + +int RasterFormat::GetByteCount(int cx) const +{ + int b = bits[type & 15]; + return (cx * b + 7) >> 3; +} + +int RasterFormat::GetBpp() const +{ + return bits[type & 15]; +} + +bool RasterFormat::HasAlpha() const +{ + return (type & 15) == RASTER_32ALPHA; +} + +int RasterFormat::GetColorCount() const +{ + static int colors[16] = { 2, 4, 16, 256, 256, 65536, 256 * 256 * 256, 256 * 256 * 256, 256 * 256 * 256 }; + return colors[type & 15]; +} + +int RasterFormat::GetPaletteCount() const +{ + static int colors[16] = { 2, 4, 16, 256 }; + return (type & 15) < 4 ? colors[type & 15] : 0; +} + +void RasterFormat::TailBits(RGBA *t, const byte *src, int cx, byte andm, byte shift, const RGBA *palette) +{ + if(cx) { + byte c = *src; + while(cx > 0) { + *t++ = palette[c & andm]; c >>= shift; + cx--; + } + } +} + +void RasterFormat::TailBitsMSB1st(RGBA *t, const byte *src, int cx, byte shift1, byte andm, byte shift, const RGBA *palette) +{ + if(cx) { + byte c = *src; + while(cx > 0) { + *t++ = palette[(c >> shift1) & andm]; c <<= shift; + cx--; + } + } +} + +void RasterFormat::Read(RGBA *t, const byte *s, int cx, const RGBA *palette) const +{ + switch(type) { + case RASTER_1: + { + const byte *e = s + (cx >> 3); + while(s < e) { + byte c = *s++; + t[0] = palette[(c >> 0) & 1]; + t[1] = palette[(c >> 1) & 1]; + t[2] = palette[(c >> 2) & 1]; + t[3] = palette[(c >> 3) & 1]; + t[4] = palette[(c >> 4) & 1]; + t[5] = palette[(c >> 5) & 1]; + t[6] = palette[(c >> 6) & 1]; + t[7] = palette[(c >> 7) & 1]; + t += 8; + } + TailBits(t, s, cx & 7, 1, 1, palette); + } + break; + case RASTER_1|RASTER_MSBFIRST: + { + const byte *e = s + (cx >> 3); + while(s < e) { + byte c = *s++; + t[7] = palette[(c >> 0) & 1]; + t[6] = palette[(c >> 1) & 1]; + t[5] = palette[(c >> 2) & 1]; + t[4] = palette[(c >> 3) & 1]; + t[3] = palette[(c >> 4) & 1]; + t[2] = palette[(c >> 5) & 1]; + t[1] = palette[(c >> 6) & 1]; + t[0] = palette[(c >> 7) & 1]; + t += 8; + } + TailBitsMSB1st(t, s, cx & 7, 7, 1, 1, palette); + } + break; + case RASTER_2: + { + const byte *e = s + (cx >> 2); + while(s < e) { + byte c = *s++; + t[0] = palette[(c >> 0) & 3]; + t[1] = palette[(c >> 2) & 3]; + t[2] = palette[(c >> 4) & 3]; + t[3] = palette[(c >> 6) & 3]; + t += 4; + } + TailBits(t, s, cx & 3, 3, 2, palette); + } + break; + case RASTER_2|RASTER_MSBFIRST: + { + const byte *e = s + (cx >> 2); + while(s < e) { + byte c = *s++; + t[3] = palette[(c >> 0) & 3]; + t[2] = palette[(c >> 2) & 3]; + t[1] = palette[(c >> 4) & 3]; + t[0] = palette[(c >> 6) & 3]; + t += 4; + } + TailBitsMSB1st(t, s, cx & 3, 6, 3, 2, palette); + } + break; + case RASTER_4: + { + const byte *e = s + (cx >> 1); + while(s < e) { + byte c = *s++; + t[0] = palette[(c >> 0) & 15]; + t[1] = palette[(c >> 4) & 15]; + t += 2; + } + TailBits(t, s, cx & 1, 15, 4, palette); + } + break; + case RASTER_4|RASTER_MSBFIRST: + { + const byte *e = s + (cx >> 1); + while(s < e) { + byte c = *s++; + t[1] = palette[(c >> 0) & 15]; + t[0] = palette[(c >> 4) & 15]; + t += 2; + } + TailBitsMSB1st(t, s, cx & 1, 4, 15, 4, palette); + } + break; + case RASTER_8: + case RASTER_8|RASTER_MSBFIRST: + { + RGBA *e = t + cx; + while(t < e) + *t++ = palette[*s++]; + } + break; + case RASTER_8ALPHA: + case RASTER_8ALPHA|RASTER_MSBFIRST: + { + RGBA *e = t + cx; + while(t < e) { + RGBA pal = palette[*s]; + pal.a = s[1]; + *t++ = pal; + s += 2; + } + break; + } + case RASTER_16: + { + RGBA *e = t + cx; + while(t < e) { + word w = Peek16le(s); + t->a = 255; + t->r = byte((w & rmask) << rpos >> 8); + t->g = byte((w & gmask) << gpos >> 8); + t->b = byte((w & bmask) << bpos >> 8); + s += 2; + t++; + } + } + break; + case RASTER_16|RASTER_MSBFIRST: + { + RGBA *e = t + cx; + while(t < e) { + word w = Peek16be(s); + t->a = 255; + t->r = byte((w & rmask) << rpos >> 8); + t->g = byte((w & gmask) << gpos >> 8); + t->b = byte((w & bmask) << bpos >> 8); + s += 2; + t++; + } + } + break; + case RASTER_24: + case RASTER_24|RASTER_MSBFIRST: + { + RGBA *e = t + cx; + while(t < e) { + t->a = 255; + t->r = s[rpos]; + t->g = s[gpos]; + t->b = s[bpos]; + s += 3; + t++; + } + } + break; + case RASTER_32: + case RASTER_32|RASTER_MSBFIRST: + if(bpos == 0 && gpos == 1 && rpos == 2) { + RGBA *e = t + cx; + while(t < e) { + *t = *(RGBA *)s; + t->a = 255; + s += 4; + t++; + } + } + else + { + RGBA *e = t + cx; + while(t < e) { + t->a = 255; + t->r = s[rpos]; + t->g = s[gpos]; + t->b = s[bpos]; + s += 4; + t++; + } + } + break; + case RASTER_32ALPHA: + case RASTER_32ALPHA|RASTER_MSBFIRST: { + RGBA *e = t + cx; + while(t < e) { + t->a = s[apos]; + int alpha = t->a + (t->a >> 7); + t->r = (alpha * s[rpos]) >> 8; + t->g = (alpha * s[gpos]) >> 8; + t->b = (alpha * s[bpos]) >> 8; + s += 4; + t++; + } + } + break; + case RASTER_32PREMULTIPLIED: + case RASTER_32PREMULTIPLIED|RASTER_MSBFIRST: + if(bpos == 0 && gpos == 1 && rpos == 2 && apos == 3) + memcpy(t, s, cx * sizeof(RGBA)); + else { + RGBA *e = t + cx; + while(t < e) { + t->a = s[apos]; + t->r = s[rpos]; + t->g = s[gpos]; + t->b = s[bpos]; + s += 4; + t++; + } + } + break; + } +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/RasterWrite.cpp b/uppdev/Draw/RasterWrite.cpp new file mode 100644 index 000000000..ba24a2450 --- /dev/null +++ b/uppdev/Draw/RasterWrite.cpp @@ -0,0 +1,344 @@ +#include "Draw.h" + +NAMESPACE_UPP + +extern int um_table__[256]; +void sInitUmTable__(); + +void RasterFormat::Write(byte *t, const RGBA *s, int cx, const PaletteCv *palcv) const +{ + const RGBA *e = s + cx; + switch(type) { + case RASTER_1: + if(palcv) { + const byte *e = t + (cx >> 3); + while(t < e) { + *t++ = + ((palcv->Get(s[0]) & 1) << 0) + | ((palcv->Get(s[1]) & 1) << 1) + | ((palcv->Get(s[2]) & 1) << 2) + | ((palcv->Get(s[3]) & 1) << 3) + | ((palcv->Get(s[4]) & 1) << 4) + | ((palcv->Get(s[5]) & 1) << 5) + | ((palcv->Get(s[6]) & 1) << 6) + | ((palcv->Get(s[7]) & 1) << 7) + ; + s += 8; + } + cx &= 7; + if(cx) { + byte c = 0; + byte sh = 0; + while(cx > 0) { + c |= (palcv->Get(*s++)) << sh; + sh++; + cx--; + } + *t = c; + } + } + else { + const byte *e = t + (cx >> 3); + while(t < e) { + *t++ = + ((s[0].g & 0x80) >> 7) + | ((s[1].g & 0x80) >> 6) + | ((s[2].g & 0x80) >> 5) + | ((s[3].g & 0x80) >> 4) + | ((s[4].g & 0x80) >> 3) + | ((s[5].g & 0x80) >> 2) + | ((s[6].g & 0x80) >> 1) + | ((s[7].g & 0x80) >> 0) + ; + s += 8; + } + cx &= 7; + if(cx) { + byte c = 0; + byte sh = 7; + while(cx > 0) { + c |= ((s++)->g & 0x80) >> sh; + sh--; + cx--; + } + *t = c; + } + } + break; + case RASTER_1|RASTER_MSBFIRST: + if(palcv) { + const byte *e = t + (cx >> 3); + while(t < e) { + *t++ = + ((palcv->Get(s[7]) & 1) << 0) + | ((palcv->Get(s[6]) & 1) << 1) + | ((palcv->Get(s[5]) & 1) << 2) + | ((palcv->Get(s[4]) & 1) << 3) + | ((palcv->Get(s[3]) & 1) << 4) + | ((palcv->Get(s[2]) & 1) << 5) + | ((palcv->Get(s[1]) & 1) << 6) + | ((palcv->Get(s[0]) & 1) << 7) + ; + s += 8; + } + cx &= 7; + if(cx) { + byte c = 0; + byte sh = 7; + while(cx > 0) { + c |= (palcv->Get(*s++)) << sh; + sh--; + cx--; + } + *t = c; + } + } + else { + const byte *e = t + (cx >> 3); + while(t < e) { + *t++ = + ((s[7].g & 0x80) >> 7) + | ((s[6].g & 0x80) >> 6) + | ((s[5].g & 0x80) >> 5) + | ((s[4].g & 0x80) >> 4) + | ((s[3].g & 0x80) >> 3) + | ((s[2].g & 0x80) >> 2) + | ((s[1].g & 0x80) >> 1) + | ((s[0].g & 0x80) >> 0) + ; + s += 8; + } + cx &= 7; + if(cx) { + byte c = 0; + byte sh = 0; + while(cx > 0) { + c |= ((s++)->g & 0x80) >> sh; + sh++; + cx--; + } + *t = c; + } + } + break; + case RASTER_2: + if(palcv) { + const byte *e = t + (cx >> 2); + while(t < e) { + *t++ = + ((palcv->Get(s[0]) & 3) << 0) + | ((palcv->Get(s[1]) & 3) << 2) + | ((palcv->Get(s[2]) & 3) << 4) + | ((palcv->Get(s[3]) & 3) << 6) + ; + s += 4; + } + cx &= 3; + if(cx) { + byte c = 0; + byte sh = 0; + while(cx > 0) { + c |= (palcv->Get(*s++)) << sh; + sh += 2; + cx--; + } + *t = c; + } + } + else { + const byte *e = t + (cx >> 2); + while(t < e) { + *t++ = + ((s[0].g & 0xc0) >> 6) + | ((s[1].g & 0xc0) >> 4) + | ((s[2].g & 0xc0) >> 2) + | ((s[3].g & 0xc0) >> 0) + ; + s += 4; + } + cx &= 3; + if(cx) { + byte c = 0; + byte sh = 6; + while(cx > 0) { + c |= ((s++)->g & 0xc0) >> sh; + sh -= 2; + cx--; + } + *t = c; + } + } + break; + case RASTER_2|RASTER_MSBFIRST: + if(palcv) { + const byte *e = t + (cx >> 2); + while(t < e) { + *t++ = + ((palcv->Get(s[3]) & 3) << 0) + | ((palcv->Get(s[2]) & 3) << 2) + | ((palcv->Get(s[1]) & 3) << 4) + | ((palcv->Get(s[0]) & 3) << 6) + ; + s += 4; + } + cx &= 3; + if(cx) { + byte c = 0; + byte sh = 6; + while(cx > 0) { + c |= (palcv->Get(*s++)) << sh; + sh -= 2; + cx--; + } + *t = c; + } + } + else { + const byte *e = t + (cx >> 2); + while(t < e) { + *t++ = + ((s[3].g & 0xc0) >> 6) + | ((s[2].g & 0xc0) >> 4) + | ((s[1].g & 0xc0) >> 2) + | ((s[0].g & 0xc0) >> 0) + ; + s += 4; + } + cx &= 3; + if(cx) { + byte c = 0; + byte sh = 0; + while(cx > 0) { + c |= ((s++)->g & 0xc0) >> sh; + sh += c; + cx--; + } + *t = c; + } + } + break; + case RASTER_4: + if(palcv) { + const byte *e = t + (cx >> 1); + while(t < e) { + *t++ = (palcv->Get(s[0]) & 15) | ((palcv->Get(s[1]) & 15) << 4); + s += 2; + } + if(cx & 1) + *t = palcv->Get(*s) & 15; + } + else { + const byte *e = t + (cx >> 1); + while(t < e) { + *t++ = ((Grayscale(s[0]) & 0xf0) >> 4) | ((Grayscale(s[1]) & 0xf0)); + s += 2; + } + if(cx & 1) + *t = (Grayscale(s[0]) & 0xf0) >> 4; + } + break; + case RASTER_4|RASTER_MSBFIRST: + if(palcv) { + const byte *e = t + (cx >> 1); + while(t < e) { + *t++ = (palcv->Get(s[1]) & 15) | ((palcv->Get(s[0]) & 15) << 4); + s += 2; + } + if(cx & 1) + *t = (palcv->Get(*s) & 15) << 4; + } + else { + const byte *e = t + (cx >> 1); + while(t < e) { + *t++ = ((Grayscale(s[1]) & 0xf0) >> 4) | ((Grayscale(s[0]) & 0xf0)); + s += 2; + } + if(cx & 1) + *t = Grayscale(s[0]) & 0xf0; + } + break; + case RASTER_8: + case RASTER_8|RASTER_MSBFIRST: + if(palcv) + while(s < e) { + *t++ = palcv->Get(*s); + s++; + } + else + while(s < e) + *t++ = Grayscale(*s++); + break; + case RASTER_16: + while(s < e) { + Poke16le(t, ((s->r << 8 >> rpos) & rmask) | + ((s->g << 8 >> gpos) & gmask) | + ((s->b << 8 >> bpos) & bmask)); + t += 2; + s++; + } + break; + case RASTER_16|RASTER_MSBFIRST: + while(s < e) { + Poke16be(t, ((s->r << 8 >> rpos) & rmask) | + ((s->g << 8 >> gpos) & gmask) | + ((s->b << 8 >> bpos) & bmask)); + t += 2; + s++; + } + break; + case RASTER_24: + case RASTER_24|RASTER_MSBFIRST: + while(s < e) { + t[rpos] = s->r; + t[gpos] = s->g; + t[bpos] = s->b; + t += 3; + s++; + } + break; + case RASTER_32: + case RASTER_32|RASTER_MSBFIRST: + while(s < e) { + t[rpos] = s->r; + t[gpos] = s->g; + t[bpos] = s->b; + t += 4; + s++; + } + break; + case RASTER_32ALPHA: + case RASTER_32ALPHA|RASTER_MSBFIRST: + sInitUmTable__(); + while(s < e) { + int alpha = um_table__[t[apos] = s->a]; + t[rpos] = (alpha * s->r) >> 8; + t[gpos] = (alpha * s->g) >> 8; + t[bpos] = (alpha * s->b) >> 8; + t += 4; + s++; + } + break; + case RASTER_32PREMULTIPLIED: + case RASTER_32PREMULTIPLIED|RASTER_MSBFIRST: + #ifdef PLATFORM_WIN32 + if(bpos == 0 && gpos == 1 && rpos == 2 && apos == 3) + memcpy(t, s, cx * sizeof(RGBA)); + else + #endif + { + while(s < e) { + t[rpos] = s->r; + t[gpos] = s->g; + t[bpos] = s->b; + t[apos] = s->a; + t += 4; + s++; + } + } + break; + default: + NEVER(); + } +} + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/SSettings.cpp b/uppdev/Draw/SSettings.cpp new file mode 100644 index 000000000..618ee5b55 --- /dev/null +++ b/uppdev/Draw/SSettings.cpp @@ -0,0 +1,42 @@ +#include "Draw.h" + +NAMESPACE_UPP + +CH_COLOR(SBlack, Black()); +CH_COLOR(SGray, Gray()); +CH_COLOR(SLtGray, LtGray()); +CH_COLOR(SWhiteGray, WhiteGray()); +CH_COLOR(SWhite, White()); +CH_COLOR(SRed, Red()); +CH_COLOR(SGreen, Green()); +CH_COLOR(SBrown, Brown()); +CH_COLOR(SBlue, Blue()); +CH_COLOR(SMagenta, Magenta()); +CH_COLOR(SCyan, Cyan()); +CH_COLOR(SYellow, Yellow()); +CH_COLOR(SLtRed, LtRed()); +CH_COLOR(SLtGreen, LtGreen()); +CH_COLOR(SLtYellow, LtYellow()); +CH_COLOR(SLtBlue, LtBlue()); +CH_COLOR(SLtMagenta, LtMagenta()); +CH_COLOR(SLtCyan, LtCyan()); + +CH_COLOR(SColorPaper, White()); +CH_COLOR(SColorFace, LtGray()); +CH_COLOR(SColorText, Black()); +CH_COLOR(SColorHighlight, Blue()); +CH_COLOR(SColorHighlightText, White()); +CH_COLOR(SColorMenu, LtGray()); +CH_COLOR(SColorMenuText, Black()); +CH_COLOR(SColorInfo, LtYellow()); +CH_COLOR(SColorInfoText, Black()); +CH_COLOR(SColorDisabled, Gray()); +CH_COLOR(SColorLight, White()); +CH_COLOR(SColorShadow, Gray()); +CH_COLOR(SColorMark, LtBlue()); + +CH_COLOR(SColorLtFace, Blend(SColorFace, SColorLight)); +CH_COLOR(SColorDkShadow, Blend(SColorShadow, SColorText)); +CH_COLOR(SColorLabel, SColorText()); + +END_UPP_NAMESPACE diff --git a/uppdev/Draw/gdk.dli b/uppdev/Draw/gdk.dli new file mode 100644 index 000000000..6e45227c0 --- /dev/null +++ b/uppdev/Draw/gdk.dli @@ -0,0 +1,22 @@ +FN(G_obj *, gdk_x11_colormap_foreign_new, (G_obj *visual, Colormap xcolormap)) +FN(G_obj *, gdkx_visual_get, (VisualID xvisualid)) +FN(G_obj *, gdk_pixmap_foreign_new, (uint32 anid)) +FN(void, gdk_drawable_set_colormap, (G_obj *drawable, G_obj *colormap)) +FN(G_obj *, gdk_x11_display_get_xdisplay, (G_obj *display)) + +FN(void, gdk_draw_pixbuf, (G_obj *drawable, + G_obj *gc, + G_obj *pixbuf, + int src_x, + int src_y, + int dest_x, + int dest_y, + int width, + int height, + int dither, + int x_dither, + int y_dither)) + +FN(G_obj *, gdk_rgb_get_colormap, (void)) +FN(G_obj *, gdk_x11_colormap_get_xcolormap, (G_obj *)) +FN(G_obj *, gdk_gc_new, (G_obj *)) diff --git a/uppdev/Draw/gnome.dli b/uppdev/Draw/gnome.dli new file mode 100644 index 000000000..9c7304ddd --- /dev/null +++ b/uppdev/Draw/gnome.dli @@ -0,0 +1 @@ +FN(void, gnome_triggers_vdo, (const char *msg, const char *level, const char *supinfo[])) diff --git a/uppdev/Draw/gobj.dli b/uppdev/Draw/gobj.dli new file mode 100644 index 000000000..45e6dda0b --- /dev/null +++ b/uppdev/Draw/gobj.dli @@ -0,0 +1,2 @@ +FN(void, g_object_unref, (G_obj *object)) +FN(void, g_object_get, (G_obj *object, const char *first_property_name, ...)) diff --git a/uppdev/Draw/gpixbuf.dli b/uppdev/Draw/gpixbuf.dli new file mode 100644 index 000000000..6b6e4c78c --- /dev/null +++ b/uppdev/Draw/gpixbuf.dli @@ -0,0 +1,6 @@ +FN(int, gdk_pixbuf_get_width, (const G_obj *pixbuf)) +FN(int, gdk_pixbuf_get_height, (const G_obj *pixbuf)) +FN(int, gdk_pixbuf_get_has_alpha, (const G_obj *pixbuf)) +FN(int, gdk_pixbuf_get_bits_per_sample, (const G_obj *pixbuf)) +FN(int, gdk_pixbuf_get_n_channels, (const G_obj *pixbuf)) +FN(byte *, gdk_pixbuf_get_pixels, (const G_obj *pixbuf)) diff --git a/uppdev/Draw/gtk.dli b/uppdev/Draw/gtk.dli new file mode 100644 index 000000000..d475a3f10 --- /dev/null +++ b/uppdev/Draw/gtk.dli @@ -0,0 +1,185 @@ +FN(void, gtk_init, (int *, char ***)) +FN(G_obj *, gtk_window_new, (int)) +FN(void, gtk_widget_realize, (G_obj *)) +FN(G_obj *, gtk_fixed_new, (void)) +FN(void, gtk_container_add, (G_obj *, G_obj *)) +FN(void, gtk_fixed_put, (G_obj *, G_obj *, int, int)) +FN(void, gtk_widget_show, (G_obj *)) +FN(G_obj *, gtk_widget_get_style, (G_obj *widget)) +FN(G_obj *, gtk_settings_get_default, (void)) + +FN(void, gtk_object_sink, (G_obj *widget)) + +FN(void, gtk_paint_box, ( + G_obj *style, + G_obj *window, + int state_type, + int shadow_type, + void *area, + G_obj *widget, + const char *detail, + int x, + int y, + int width, + int height +)) + +FN(void, gtk_paint_check, ( + G_obj *style, + G_obj *window, + int state_type, + int shadow_type, + void *area, + G_obj *widget, + const char *detail, + int x, + int y, + int width, + int height +)) + +FN(void, gtk_paint_option, ( + G_obj *style, + G_obj *window, + int state_type, + int shadow_type, + void *area, + G_obj *widget, + const char *detail, + int x, + int y, + int width, + int height +)) + +FN(void, gtk_paint_tab, ( + G_obj *style, + G_obj *window, + int state_type, + int shadow_type, + void *area, + G_obj *widget, + const char *detail, + int x, + int y, + int width, + int height +)) + +FN(void, gtk_paint_slider, ( + G_obj *style, + G_obj *window, + int state_type, + int shadow_type, + void *area, + G_obj *widget, + const char *detail, + int x, + int y, + int width, + int height, + int orientation +)) + +FN(void, gtk_paint_handle, ( + G_obj *style, + G_obj *window, + int state_type, + int shadow_type, + void *area, + G_obj *widget, + const char *detail, + int x, + int y, + int width, + int height, + int orientation +)) + +FN(void, gtk_paint_resize_grip, ( + G_obj *style, + G_obj *window, + int state_type, + void *area, + G_obj *widget, + const char *detail, + G_obj *edge, + int x, + int y, + int width, + int height +)) + +FN(void, gtk_paint_arrow, ( + G_obj *style, + G_obj *window, + int state_type, + int shadow_type, + void *area, + G_obj *widget, + const char *detail, + int arrow_type, + int fill, + int x, + int y, + int width, + int height +)) + +FN(void, gtk_paint_extension, ( + G_obj *style, + G_obj *window, + int state_type, + int shadow_type, + void *area, + G_obj *widget, + const char *detail, + int x, + int y, + int width, + int height, + int gap_side +)) + +FN(G_obj *, gtk_widget_render_icon, (G_obj *widget, const char *stock_id, int size, const char *detail)) + +FN(G_obj *, gtk_adjustment_new, ( + double value, + double lower, + double upper, + double step_increment, + double page_increment, + double page_size +)) + +FN(void, gtk_widget_set_state, (G_obj *widget, int state)) +FN(void, gtk_widget_set_sensitive, (G_obj *widget, int sensitive)) + +FN(void, gtk_toggle_button_set_active, (G_obj *toggle_button, int is_active)) +FN(void, gtk_toggle_button_set_inconsistent, (G_obj *toggle_button, int setting)) +FN(G_obj *, gtk_widget_get_display, (G_obj *widget)) +FN(void, gtk_widget_destroy, (G_obj *widget)) + +FN(void, gtk_widget_style_get, (G_obj *widget, const char *first_property_name, ...)) +FN(G_obj *, gtk_widget_get_parent, (G_obj *widget)) +FN(void, gtk_widget_set, (G_obj *widget, const char *first_property_name, ...)) +FN(void, gtk_window_set_default, (G_obj *window, G_obj *default_widget)) + +FN(G_obj *, gtk_dialog_new, (void)) +FN(G_obj *, gtk_button_new, (void)) +FN(G_obj *, gtk_radio_button_new, (void *group)) +FN(G_obj *, gtk_check_button_new, (void)) +FN(G_obj *, gtk_vscrollbar_new, (G_obj *adjustment)) +FN(G_obj *, gtk_hscrollbar_new, (G_obj *adjustment)) +FN(G_obj *, gtk_image_new, (void)) +FN(G_obj *, gtk_menu_bar_new, (void)) +FN(void, gtk_menu_shell_append, (G_obj *menu_shell, G_obj *child)) +FN(void, gtk_menu_item_set_submenu, (G_obj *item, G_obj *submenu)) + + +FN(G_obj *, gtk_menu_new, (void)) +FN(G_obj *, gtk_menu_item_new, (void)) +FN(G_obj *, gtk_notebook_new, (void)) + +FN(void, gtk_misc_get_alignment, (G_obj *misc, float *xalign, float *yalign)) +FN(void, gtk_misc_get_padding, (G_obj *misc, int *xpad, int *ypad)) diff --git a/uppdev/Draw/iml.h b/uppdev/Draw/iml.h new file mode 100644 index 000000000..4c4bbd697 --- /dev/null +++ b/uppdev/Draw/iml.h @@ -0,0 +1,9 @@ +//#BLITZ_APPROVE + +#define IMAGE_KEEP + +#include "iml_header.h" + +#undef IMAGE_KEEP + +#include "iml_source.h" diff --git a/uppdev/Draw/iml_header.h b/uppdev/Draw/iml_header.h new file mode 100644 index 000000000..1253ca825 --- /dev/null +++ b/uppdev/Draw/iml_header.h @@ -0,0 +1,63 @@ +//#BLITZ_APPROVE + +//$- + +#define IMAGE_META(k, v) +#define IMAGE_SCAN(s) +#define IMAGE_PACKED(n, d) + +#define PREMULTIPLIED +#define IMAGE_BEGIN_DATA +#define IMAGE_DATA(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac,ad,ae,af,b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,ba,bb,bc,bd,be,bf) +#define IMAGE_END_DATA(n, c) + +class IMAGECLASS { +public: +#define IMAGE_BEGIN(n) I_##n, +#define IMAGE_ID(n) I_##n, + enum { +#include IMAGEFILE + COUNT + }; +#undef IMAGE_BEGIN +#undef IMAGE_ID + +public: + static UPP::Iml& Iml(); + + static void Register__() { Register(ASSTRING(IMAGECLASS), Iml()); } + + static int Find(const UPP::String& s); + static int Find(const char *s); + static int GetCount() { return Iml().GetCount(); } + static UPP::String GetId(int i) { return Iml().GetId(i); } + + static UPP::Image Get(int i); + static UPP::Image Get(const char *s); + static UPP::Image Get(const UPP::String& s); + + static void Set(int i, const UPP::Image& m); + static void Set(const char *s, const UPP::Image& m); + + static void Reset() { Iml().Reset(); } + +#define IMAGE_BEGIN(n) static UPP::Image n() { return Get(I_##n); } +#define IMAGE_ID(n) static UPP::Image n() { return Get(I_##n); } +#include IMAGEFILE +#undef IMAGE_BEGIN +#undef IMAGE_ID + +}; + +#undef IMAGE_SCAN +#undef IMAGE_PACKED +#undef IMAGE_META + +#undef IMAGE_BEGIN_DATA +#undef IMAGE_END_DATA +#undef IMAGE_DATA + +#ifndef IMAGE_KEEP +#undef IMAGECLASS +#undef IMAGEFILE +#endif diff --git a/uppdev/Draw/iml_source.h b/uppdev/Draw/iml_source.h new file mode 100644 index 000000000..a8ff73b8e --- /dev/null +++ b/uppdev/Draw/iml_source.h @@ -0,0 +1,140 @@ +//#BLITZ_APPROVE + +//$ + +#define IMAGE_META(k, v) + +#define PREMULTIPLIED +#define IMAGE_ID(n) +#define IMAGE_BEGIN_DATA +#define IMAGE_END_DATA(n, c) +#define IMAGE_DATA(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac,ad,ae,af,b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,ba,bb,bc,bd,be,bf) + +#define IMAGE_BEGIN(n) const char *COMBINE(COMBINE(IMAGECLASS, _), n##__scans__)[] = { +#define IMAGE_SCAN(s) s, +#define IMAGE_PACKED(n, d) }; +#define IMAGE_DATA_BEGIN + + +#include IMAGEFILE + +#undef IMAGE_BEGIN +#undef IMAGE_SCAN +#undef IMAGE_PACKED + +// ----------------------- + +#define IMAGE_SCAN(s) +#define IMAGE_BEGIN(n) + +// ----------------------- + + +UPP::Iml& IMAGECLASS::Iml() { + static UPP::Image::Init init[] = { + #define IMAGE_PACKED(n, d) { COMBINE(COMBINE(IMAGECLASS, _), n##__scans__), __countof(COMBINE(COMBINE(IMAGECLASS, _), n##__scans__)), d }, + + #include IMAGEFILE + + { NULL } + #undef IMAGE_PACKED + }; + + static const char *name[IMAGECLASS::COUNT] = { + #define IMAGE_PACKED(n, d) #n, + #undef IMAGE_ID + #define IMAGE_ID(n) #n, + + #include IMAGEFILE + + #undef IMAGE_PACKED + #undef IMAGE_ID + #define IMAGE_ID(n) + #define IMAGE_PACKED(n, d) + }; + static UPP::Iml iml(init, name, COUNT); + static bool imlinit; + if(!imlinit) { + imlinit = true; + + #undef IMAGE_BEGIN_DATA + #undef IMAGE_DATA + #undef IMAGE_END_DATA + #define IMAGE_BEGIN_DATA { static const UPP::byte data[] = { + #define IMAGE_DATA(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac,ad,ae,af,b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,ba,bb,bc,bd,be,bf)\ + a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac,ad,ae,af,b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,ba,bb,bc,bd,be,bf, + + #define IMAGE_END_DATA(n, c) }; iml.AddData(data, n, c); } + + #include IMAGEFILE + + #undef IMAGE_BEGIN_DATA + #undef IMAGE_END_DATA + #undef IMAGE_DATA + #define IMAGE_BEGIN_DATA + #define IMAGE_END_DATA(n, c) + #define IMAGE_DATA(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac,ad,ae,af,b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,ba,bb,bc,bd,be,bf) + + #undef PREMULTIPLIED + #define PREMULTIPLIED iml.Premultiplied(); + #include IMAGEFILE + #undef PREMULTIPLIED + #define PREMULTIPLIED + + } + return iml; +} + +UPP::Image IMAGECLASS::Get(int i) +{ + return Iml().Get(i); +} + +UPP::Image IMAGECLASS::Get(const char *s) +{ + return Iml().Get(Find(s)); +} + +int IMAGECLASS::Find(const UPP::String& s) +{ + return Iml().Find(s); +} + +int IMAGECLASS::Find(const char *s) +{ + return Iml().Find(s); +} + +void IMAGECLASS::Set(int i, const UPP::Image& m) +{ + Iml().Set(i, m); +} + +void IMAGECLASS::Set(const char *s, const UPP::Image& m) +{ + Iml().Set(Find(s), m); +} + +struct COMBINE(IMAGECLASS, __Reg) { + COMBINE(IMAGECLASS, __Reg()) { + IMAGECLASS::Register__(); + } +}; + +static COMBINE(IMAGECLASS, __Reg) COMBINE(IMAGECLASS, ___Reg); + +#undef IMAGE_BEGIN_DATA +#undef IMAGE_DATA +#undef IMAGE_END_DATA +#undef IMAGE_PACKED +#undef IMAGE_ID + +#undef IMAGE_SCAN +#undef IMAGE_BEGIN + +#ifndef IMAGE_KEEP +#undef IMAGECLASS +#undef IMAGEFILE +#endif + +#undef IMAGE_META diff --git a/uppdev/Draw/init b/uppdev/Draw/init new file mode 100644 index 000000000..ff7037a12 --- /dev/null +++ b/uppdev/Draw/init @@ -0,0 +1,4 @@ +#ifndef _Draw_icpp_init_stub +#define _Draw_icpp_init_stub +#include "Core/init" +#endif diff --git a/uppdev/Draw/src.tpp/Display$en-us.tpp b/uppdev/Draw/src.tpp/Display$en-us.tpp new file mode 100644 index 000000000..129c971c8 --- /dev/null +++ b/uppdev/Draw/src.tpp/Display$en-us.tpp @@ -0,0 +1,15 @@ +TITLE("Display") +COMPRESSED +120,156,237,27,139,114,219,54,242,87,48,238,99,100,159,164,35,41,201,146,229,235,77,18,199,73,61,205,37,29,217,233,205,141,199,182,32,10,146,112,166,72,149,15,59,206,163,223,126,187,11,144,4,37,82,150,31,73,51,215,52,157,136,36,128,125,97,95,216,69,78,29,246,253,247,86,221,250,206,186,229,191,254,115,49,225,137,23,159,157,202,118,187,183,207,157,206,254,229,47,111,246,246,119,158,212,118,219,219,8,197,6,40,173,174,221,234,117,90,118,219,217,133,191,236,150,237,116,156,86,219,238,57,123,237,94,171,213,179,250,174,199,163,232,236,212,115,122,189,125,92,228,192,34,167,219,113,236,110,187,215,238,217,173,110,207,129,181,142,101,57,86,215,233,216,237,86,207,233,244,199,34,114,207,78,121,175,181,191,51,216,133,69,45,196,4,192,45,123,215,105,119,219,142,213,178,156,54,160,178,123,189,182,221,237,244,90,123,187,187,125,151,47,98,25,248,26,151,180,109,199,222,31,217,221,125,160,249,143,63,254,104,218,109,75,81,208,6,96,182,213,6,82,109,248,102, +181,157,174,221,217,179,246,58,61,187,103,181,0,120,167,107,117,250,11,30,242,121,53,235,157,91,89,239,90,125,25,11,0,177,243,55,219,238,194,146,221,250,238,119,118,187,11,140,246,90,237,78,175,107,1,114,199,113,90,45,199,110,57,123,123,78,103,183,211,237,207,4,31,139,240,236,244,195,197,167,31,14,95,55,222,30,179,211,200,222,255,229,137,197,78,127,176,172,134,101,61,169,89,77,171,233,116,58,219,76,75,54,253,14,148,177,139,244,149,61,151,209,194,227,55,103,63,158,157,70,206,126,250,202,184,63,78,159,135,13,192,36,175,196,88,1,18,17,11,133,15,159,216,111,220,75,4,147,126,28,176,120,38,88,180,16,174,156,72,152,23,10,55,230,254,52,241,120,200,120,40,120,147,13,196,68,192,42,23,22,195,108,13,56,194,65,150,68,176,66,250,108,206,253,27,118,45,199,83,17,195,0,252,31,199,161,28,37,49,44,225,147,9,64,148,254,148,240,40,236,248,22,76,244,2,69,74,212,100,90,21,153,156,47,60,49,23,126,204,113,167,17,71,196,142,227, +113,202,29,208,176,16,225,36,8,231,140,123,30,227,46,206,138,88,45,18,130,141,132,23,92,51,24,51,23,160,158,133,146,212,102,187,169,69,133,63,86,246,115,186,195,126,147,81,194,61,22,197,55,158,96,46,0,4,33,0,47,103,25,151,192,213,112,139,134,135,91,140,20,71,196,32,199,145,140,217,196,227,211,8,25,202,185,131,193,89,48,142,104,43,22,97,112,37,199,130,241,241,88,34,17,128,70,250,72,191,226,143,143,130,36,134,165,191,39,50,4,60,87,138,16,190,88,8,64,2,82,239,43,34,119,52,177,164,247,153,170,167,26,179,195,14,222,14,142,223,12,26,31,51,229,120,153,72,38,148,32,153,140,152,155,132,33,62,214,134,91,51,78,175,81,16,14,183,182,155,103,6,220,254,16,254,164,170,3,143,47,222,28,188,61,238,151,96,163,1,80,123,6,8,77,68,8,122,18,184,73,212,92,3,245,248,240,213,225,193,73,25,88,53,146,177,208,248,184,196,68,4,207,110,44,198,107,137,30,28,62,125,254,230,245,171,255,148,33,72,199,170,81,128,202,143, +135,141,192,247,110,82,36,36,248,14,216,103,110,149,5,123,188,146,97,140,91,150,193,188,10,228,184,194,100,193,198,127,229,96,117,197,225,90,250,122,78,172,132,252,250,92,13,224,99,113,234,240,199,28,86,139,45,13,214,115,26,72,133,43,136,32,44,3,16,164,198,130,143,235,176,132,247,199,66,182,173,209,208,243,58,60,191,87,225,33,80,7,129,23,132,26,20,61,87,137,184,5,230,117,249,88,160,22,124,33,42,249,39,96,227,235,32,28,107,96,244,92,13,140,220,71,113,120,251,98,73,152,218,65,157,204,64,23,83,205,82,222,4,181,147,92,17,122,64,84,162,212,87,43,143,21,163,2,115,215,5,10,200,219,6,134,83,39,209,55,217,235,32,22,224,134,57,40,58,233,250,155,95,200,87,22,66,4,46,76,208,141,161,7,28,179,255,38,145,246,208,44,190,89,128,39,134,149,215,96,228,224,84,229,212,135,69,8,160,134,51,221,144,71,51,22,128,151,15,175,101,36,96,115,27,26,141,235,73,164,205,13,198,24,0,162,5,240,41,71,210,147,49,57,115,96, +137,66,3,16,142,252,164,1,134,28,72,59,55,221,3,82,247,198,71,52,137,178,177,16,198,78,120,136,1,37,19,75,217,188,223,97,158,230,39,128,120,161,36,9,30,165,100,42,170,81,227,227,113,50,157,138,40,86,172,138,105,24,36,200,44,106,77,217,26,165,47,230,170,17,119,47,111,91,165,20,3,8,51,162,80,243,243,121,159,103,25,73,223,252,208,55,63,244,112,63,132,121,34,37,64,47,223,30,101,177,148,252,12,166,79,144,222,68,152,255,80,130,148,58,172,220,55,65,250,72,74,169,161,215,25,228,141,44,154,5,137,55,134,116,226,74,40,171,129,165,30,71,115,138,130,185,184,70,208,128,61,205,105,210,76,79,57,48,240,59,9,154,145,7,238,5,169,87,235,225,129,18,93,200,219,48,151,51,172,82,123,128,140,144,38,171,229,142,210,36,141,205,209,25,186,30,36,102,4,203,128,17,9,76,9,99,225,221,212,33,43,133,201,201,116,6,227,224,218,138,180,73,244,156,19,233,43,233,161,235,91,50,72,242,167,68,118,204,163,203,237,111,94,80,205,163, +241,59,122,66,178,138,99,249,62,181,123,124,172,118,140,47,69,12,103,134,213,57,181,47,227,100,170,236,239,88,25,66,40,226,36,244,25,197,100,30,130,190,1,157,164,42,83,136,220,62,187,162,173,52,206,125,77,118,216,156,54,153,156,100,250,39,35,227,120,114,52,231,176,47,117,140,207,81,1,1,170,53,202,0,141,21,159,105,34,90,198,66,190,19,30,28,210,158,153,58,173,22,105,195,74,87,137,119,180,11,161,88,64,172,207,78,113,26,158,74,68,214,41,100,54,184,243,119,8,8,68,20,113,135,218,164,81,40,197,69,238,205,92,225,238,161,242,110,10,50,64,70,254,52,253,48,130,221,202,241,193,92,230,190,187,231,186,155,205,244,113,160,183,60,83,192,212,157,41,21,188,20,98,145,158,245,57,250,120,240,67,40,183,205,182,220,24,4,62,26,31,7,233,161,248,90,142,227,89,147,29,77,216,123,17,6,166,222,142,48,62,204,23,73,172,60,42,226,47,32,134,165,241,12,184,43,197,113,99,226,152,9,57,157,197,15,65,242,238,161,186,91,252,233,84,148, +132,162,56,76,150,19,165,124,183,158,198,113,120,2,54,152,57,16,42,167,0,119,30,184,100,29,133,96,71,175,68,24,203,145,71,254,63,55,76,163,108,82,199,231,1,138,196,44,43,193,183,3,176,105,17,230,197,149,24,197,112,61,19,152,248,107,246,22,88,106,162,128,42,41,45,72,105,162,35,4,193,153,193,95,128,28,68,60,150,19,42,47,197,16,174,71,128,100,28,44,168,90,228,7,254,176,225,39,88,225,201,139,73,42,56,10,114,50,133,152,229,148,136,140,108,238,223,199,49,122,60,109,117,250,173,74,118,177,33,55,69,47,5,199,177,226,85,163,42,219,29,66,245,2,206,96,26,15,62,86,33,153,224,152,70,130,243,82,167,185,30,248,166,169,34,133,107,147,133,60,218,62,28,182,10,235,26,250,179,165,136,94,68,81,64,144,238,255,121,174,157,41,72,211,233,89,236,40,79,152,151,14,35,138,198,34,121,69,7,150,125,221,206,84,31,171,145,153,186,84,166,29,46,230,76,51,177,52,97,213,132,135,59,152,151,53,31,131,207,95,205,108,254,49,57,165, +29,250,170,88,5,210,76,107,88,98,150,108,166,96,46,5,86,39,107,88,69,59,42,227,113,162,121,44,140,111,200,98,223,100,141,158,61,57,245,135,53,112,52,195,237,254,253,4,64,32,86,217,55,28,186,172,224,158,223,166,210,179,32,148,239,129,77,172,23,35,22,60,119,53,217,211,5,86,156,211,144,172,10,245,79,95,29,189,124,61,188,120,117,248,226,164,158,190,28,28,190,62,57,28,144,59,214,95,6,71,47,127,62,185,77,36,175,196,36,30,214,238,45,14,92,158,75,35,99,140,164,100,176,230,193,180,219,40,81,145,232,1,180,40,0,27,80,163,131,164,75,243,111,35,139,130,230,3,168,162,245,27,16,21,82,190,178,89,234,27,128,91,224,113,16,94,80,128,174,149,102,119,229,118,146,197,110,56,52,195,161,211,200,224,87,61,195,19,107,149,183,50,133,47,100,202,134,202,27,51,102,220,112,126,195,29,195,42,98,19,122,38,156,3,4,137,121,81,148,145,0,39,241,8,139,148,105,62,74,66,203,146,9,210,123,108,32,81,197,210,76,50,96,179,49,1, +252,60,60,146,42,92,35,123,231,236,250,255,155,203,52,245,90,206,186,150,14,58,95,152,211,22,171,250,61,78,15,215,105,139,83,139,102,229,59,121,212,172,75,153,246,6,39,137,239,234,246,222,212,11,70,220,139,134,91,88,139,74,191,71,250,184,140,228,167,13,70,248,164,123,171,84,175,151,84,26,83,171,243,131,59,77,117,77,155,99,31,62,180,58,45,171,191,219,238,90,51,123,255,73,205,177,192,198,105,52,93,229,243,185,56,235,247,245,199,188,3,10,223,206,159,56,244,121,71,157,127,179,140,255,220,200,254,97,218,79,172,148,251,102,46,6,149,236,3,243,49,237,78,226,123,34,138,116,205,63,115,27,212,151,229,35,8,72,219,77,68,94,141,218,60,108,220,13,63,121,194,97,131,98,32,30,209,30,133,156,194,57,231,110,244,168,56,113,127,74,40,247,203,104,49,223,114,58,50,172,52,204,106,105,3,153,250,46,17,106,231,141,58,33,21,106,157,73,148,90,207,210,73,109,69,24,112,94,69,50,115,137,20,63,24,2,145,115,137,151,5,64,129,205,211,35, +85,113,99,80,121,119,38,140,160,69,117,3,152,58,145,96,170,215,179,192,203,142,87,234,182,193,18,25,84,127,202,104,48,223,74,36,161,138,85,249,225,147,235,45,169,171,236,136,118,64,71,242,56,88,12,27,152,99,96,219,201,135,152,190,132,247,133,140,193,176,139,216,87,191,85,210,16,185,220,83,181,130,9,226,164,139,15,105,53,118,121,175,181,174,20,113,149,125,173,196,150,169,155,244,55,193,53,254,25,204,197,67,147,41,199,89,58,124,119,228,170,40,98,171,202,33,86,112,224,203,76,130,163,30,5,225,120,85,226,88,209,6,221,204,168,41,190,151,160,215,19,214,203,250,211,167,162,151,103,21,225,174,226,194,205,106,235,204,236,81,177,139,126,89,238,178,8,229,21,143,69,69,84,252,23,24,60,31,121,226,156,165,79,217,196,127,172,69,246,207,139,52,54,102,99,232,79,184,50,246,165,10,15,245,46,220,96,62,146,190,200,28,19,6,200,98,196,65,105,153,247,106,244,77,149,225,150,190,133,162,219,202,16,200,204,230,77,147,29,17,234,244,212,101,240,158, +241,164,163,21,140,217,78,47,29,173,76,82,255,58,87,38,30,220,66,188,24,254,116,113,76,139,84,78,116,95,192,37,13,197,28,52,213,39,30,181,191,136,176,141,25,214,102,213,230,35,255,42,184,4,5,86,93,56,208,65,84,72,78,245,230,84,109,177,36,152,127,173,172,39,63,70,211,236,43,232,132,173,59,233,125,21,70,180,182,201,112,207,222,196,205,253,150,61,86,43,228,155,241,62,204,120,87,109,86,181,75,30,102,180,239,234,12,178,76,23,126,168,141,179,108,191,172,134,217,93,29,19,189,186,106,31,213,117,135,167,180,167,254,149,155,246,35,181,178,111,219,169,124,225,221,125,237,106,229,232,87,74,53,48,53,44,52,191,30,153,217,91,219,178,127,106,187,52,149,108,70,229,131,130,216,95,178,41,250,5,116,228,46,208,192,130,223,111,182,247,135,32,67,224,148,238,66,5,57,13,181,232,125,19,221,22,254,220,108,87,213,223,114,142,205,168,94,224,234,88,100,135,241,251,150,232,242,211,214,18,160,98,184,207,241,175,54,34,214,92,215,28,163,251,46,221, +208,59,178,89,184,44,113,103,38,213,181,139,226,141,139,37,6,175,214,48,88,105,141,87,133,251,11,247,102,238,203,109,94,238,220,190,140,228,204,139,3,107,37,185,172,40,159,65,208,7,120,107,47,23,245,118,126,159,101,14,71,214,34,189,88,64,75,70,17,248,64,186,182,204,61,143,138,200,234,16,194,221,88,213,123,253,64,119,85,100,224,15,183,234,249,60,35,138,34,231,185,235,215,119,172,200,9,88,117,102,45,27,127,73,74,255,152,119,138,40,49,40,153,83,153,22,12,140,235,93,183,5,251,205,66,251,237,252,164,74,173,207,33,69,205,174,224,169,116,214,70,92,45,43,221,42,95,27,223,48,179,242,30,219,40,8,188,77,136,41,199,24,135,248,15,179,10,23,247,34,177,220,231,51,208,174,86,138,106,101,93,20,49,95,196,55,249,228,186,10,207,126,144,91,105,164,110,244,223,9,211,103,114,89,75,163,101,252,228,69,48,98,36,191,79,188,46,32,105,184,183,134,165,63,145,215,207,226,164,185,183,137,44,223,85,201,146,252,88,181,247,46,149,234,178,15, +7,18,74,188,4,252,156,253,15,162,7,123,54, diff --git a/uppdev/Draw/src.tpp/Draw$en-us.tpp b/uppdev/Draw/src.tpp/Draw$en-us.tpp new file mode 100644 index 000000000..b01708284 --- /dev/null +++ b/uppdev/Draw/src.tpp/Draw$en-us.tpp @@ -0,0 +1,1852 @@ +topic "Draw"; +[2 $$0,0#00000000000000000000000000000000:Default] +[i448;a25;kKO9;*@(64)2 $$1,0#37138531426314131252341829483380:class] +[l288;2 $$2,0#27521748481378242620020725143825:desc] +[a83;*R6 $$3,0#31310162474203024125188417583966:caption] +[l288;i1121;b17;O9;~~~.1408;2 $$4,0#10431211400427159095818037425705:param] +[i448;a25;kKO9;*@(64)2 $$5,0#37138531426314131252341829483370:item] +[*+117 $$6,6#14700283458701402223321329925657:header] +[{_}%EN-US +[s3;:`:`:Draw`:`:class`:`:Draw: Draw&] +[s0; class_[* Draw]&] +[s2; &] +[s0; +@@image:1640&2219 +˖թՃ +𜏐㩁ﻠƏȁ₈Ɯ͈ɤœԈ̼Đ +䑭ެћ׊®ћןژ +Љő󈣷Ǔǘ̸Ϸϲ⸜Ϫ +Ĉ‹đҡªћȅ∩ﶂ柋̱́ +ނ񄠢đɐǀ¥ÏƣǪ +œđҖˠؼ񤸔²ťđ塎Ƞ˜ŷƺꍄ +맦὆đҖ۲ȏ꽷Α޷ՓַđҖާ +銜Ƴߕꁻױʷ֝NjƵ͖߭Ϗ +ёڳۑҖθŃۡ˭Ĝýշ +ܶư鏣Ԏ팣ٴԶƽүÚť +ťđ塋ċNJوœᙧđҖ∵ˠ؆񤸔ǥ +ȥ죕偐񄠢đɐǀ¥ٍƣǪ +œđҖˠؼ񤸔²ťđ塎Ƞ˜ŷ +ֺ۵ԔޙǏɑNJ¸đҖԿ۾򕺽 +ĔđҖ쑂ߔؒݡѨݫƮ +ȜđҖθŃ۽ҢӲܚ񠝉ĜȈҟ +ɉͣȢסΔķۂѰƜđҖˠ؆񤸔 +ڲťĂ喡񈩋ɊوظҲҖʈȂ񄠉 +đɐʀܒӾܾȥپ塎 +NJوģœđҖˠ؆񤸔őʨńΎȸ򮎅ݟ +ǜ冉舔Ÿ̸У +ۋ́ǿߗ䏣́܏懫񴝜œ剻Ϝ +ܬđҖηđҖݸŸኻѺЈ +ؠؼ񤸔²ťđ塎Ȑ吒NJو +ҖʈȂ񈄠đɐǀ¥죕ٲ +쪣œᙧđҖ∵ˠ؆񤸔Յ²ŕđ塎ː +뀩¸Љʒ⼎歃֣ťߘܪեɝƵؘԿ +̽śܷבվ죟ܼ曷ϬҲʲݳ찶 +׉씚ŚđҖކʒϞǻÜ +֣ªťެ跙ƾښǯĜ覍؈ρ +NJٞ煌塥NJىœđҖǪ޻೏ +ƔĊɨǀȂ񄠉͗Ʈ囙柛 +夐NJو¸đҪˠ؆񯤸²ť͉޸ +ʒχ񤸔۟ߣΤƖڵ +³ԺƎבđ򱢟Š멎߳ұϾƙԜ +١ƃÞԜ䷧ǂœ嘙ڽԴҢҡӟ +ԤԈť⨙ϿȈ︔厸﷘Ãӹۏ꫰ +ǤԜ׷؟ދűݴ႞Ü幻˃ +۱ť喡񈩋ɊوœđҖǪޣ޻೏Ɣ +đɐǀȂ脠Ʈ噽柩ʱDŽ +NJ˒وœӑҖ˚؆񤸔²ť񤸔 +ۗ˼œ鏣ˬ׆وťڎܜ魙ť⨸ +ǽҌԛϪѹ߾给疟ʲݱέť +٫ۜ؛NJٸ٣幔ͤť׆đҖ +냂ːljϣ펔ྋNJǴť󬃸œđ +Җˠ񤸔ʛȥ죕塀ƪᤂƪၤƪ +ᴨާץЅ۬ìݼтǹԀĠΖ +̖ŅŜтǹԀΖ®ءʄ܉¥̢ +ݛӝ׆Ģ򲨓ҍ󉧺֤רŸ羏͛ +عƨ毮٭ꕝҰνߗᖕߖԽ +ϜLJӨזʉǻ +룎ȸԺꙸڮ࠘ŋԏ՟ÑǸяɎǁÜ +˹󟎂ސǻđΛϵŧ۩ڙ׺ +Ͷׄҁޚߩ݌𴱣ߙ +ܿŜꭟϸԌ͇ǸׁԈƜ∧ǘđƢڎ +Ÿ۬ܒȜȂ񄠉đɐǀۅÖ +ȥؼ񤸔²ťđ塎Ȑ吒NJوʢ +Ѩԭ馜ܿᯭđҖθό׺Ů +䍻آ؜ǥߗՔҏԒ +됯Գۃի񤸔윬Ѻڼٚ˗Мسѹ +񤦺񷴟ۃѝĝӍճ㕢еċ +ړڦͿ֖휌ɜå⨚޳変Ϟ +ٻמ񤸇Ƴϒǿ +ԏќǕ񴌗ݲ䈣ƪˈ٭ѵ +׿Җϥ֪ٸ⍚ʢċNJوœ +đҖˠԙˁ;ҶށȜȂ񄠉đɸѴ +گ콃ҳﻸ߾NJىœđҖˠؼ񤸔 +²ťđǽᵁÈťшť񤸔ܜ +͟܈ބ۵đŽݑך߭ͼ +꽖݈NJَݚ۰ЏŒآ̏ +ŽɢǚٞߝīҖίđҖˠ؆񤸫²ťđ +塎NJىܡҖʓȂ񄠉⨈đ +ɐǀᒮӾȥ죕پخ塎夐NJو +¸đҪˠ؆؛ۧڼ輪ǩ +ƫەŽ莩ƍ߼ʑώﵽԍ +󢚓ףѽՈťȕ柞陥儯刣Ž +ΫĪ̗Νᥬ֐ᝣ +Чś蜅Δ߷đ噒 +ٚмѽǵڡ܏ˣɧܜ +槑ǽڜǪ繸ːöͣđҖȘ +򯰀噞ΫփʒÈťĂ喡񈩋Ɋو +ظҲҖʈЁఀҁҁ䉎Ņì +ͳƩᒞс݃ɢƢ񄱈ℨǘ݋ɢƢ +񄱈۳ȯĜсύ֠򲑨ǻю +ӼŅךּ祕ȯс巩Ԑ锌̽桅 +חҌĜܑﭺ׶̾˒Ņ⸪ +ԭʜǹԠͽ͏⨙窶ϧиӣȵƂǹ +ޠǃǽяŅԇ­ݑⅅɝտ엠׶ +ԣōڅɉ┨޷کߌɢ籓Üܔ +Ζ⨧ǘɢđƚ򲨀񟄱⨧鋊ާץЅ۬ +񾮥è𘩀Ѣַߗ얕ɏ +сǨԀΖŅŜсǨԀΖӨɰ +מΖۈ跥ޱמŜсѝзք +넺ȷգ뻇𺧎迲ǬӓגǧǨڛߴճߝ +ѕ݌ΰɉ룈ӽ⧣䳗ǿ㨘꺊ȧվڳ +֊ۣ㊅ɨ͞Πڐ +٭Ո⣜ꔲ˱ȆŜǪđΣ͏ץ +Ś¥⨈đɐǀȂ񄠉঳Ʈ噽柩 +ċNJوœᙧđҖ∵ˠ؆񤸔Յ² +ɡ˞ڮ״͙đҖۊպ⫝홳򏅒 +תđז⨸ת܏婵ǷđҖ‚眝 +ϻ޵ߔ숣ťڛ輼ݴתߜ₂󨉲檖 +彣蕪桩ۿڧԚۜѕךЩ +Ļđߛމ피ͱ֧܇⿨梣ܽǽ +Ljў뿒֗́őܬ܏ +נ򠎽܅ėѲ̍đĜʉŮőތǜđ +ˠܑ؆쀣Ԁ߃ߘ +&] +[s0; &] +[s0; The class encapsulates system`-dependent internals of graphical +output. Whenever you need to paint something in a window, you +need a Draw object for it. The standard Paint method of the Ctrl +class takes a Draw`& parameter as well. In that case the underlying +mechanism passes a Draw which is already initialized for output +into the respective control, knows about the current clipping, +resolution etc. In a similar manner you can create your own Draw +objects to draw onto Images, Drawings (vector metafiles used +for serialization of graphical operations) or to perform printer +output. You can also use a Draw to query graphics`-related properties +of various output devices, like pixel size, resolution, supported +color model, available fonts etc.&] +[s0; &] +[s0; Although the internals of graphical output are very system`-dependent, +the Draw class is designed so as to hide most of the OS`-specific +details and present a unified portable interface regardless of +the actual target device or object. The downside of this approach +is that Draw capabilities are somewhat limited to cover most +frequently used graphical objects and attributes. It is quite +possible (and in certain situations rather common) that its interface +lacks some advanced capabilities, although they are supported +in the target operating system. For these situations the Draw +object supports also methods which allow you to extend its capabilities +by utilizing low`-level, system specific code, and accessing +the output device at the native system level. Of course, heavy +use of such capabilities makes writing portable code very difficult.&] +[s0;= &] +[s0; The operations supported by the Draw class can be divided into +several categories:&] +[s0; &] +[s0;i150;O0; initialization and configuration of the output device&] +[s0;i150;O0; querying output device properties&] +[s0;i150;O0; managing colors&] +[s0;i150;O0; managing text styles&] +[s0;i150;O0; controlling current clipping region and drawing offset&] +[s0;i150;O0; drawing basic vector primitives (lines, polygons)&] +[s0;i150;O0; drawing raster primitives&] +[s0;i150;O0; drawing text&] +[s0;i150;O0; accessing [*/ Drawing]`-specific functions&] +[s0;i150;O0; accessing unified virtual output interface&] +[s0;i150;O0; accessing the underlying physical output device interface&] +[s0;i150;O0; accessing device`-secific functions&] +[s0; &] +[s0; Initialization and configuration of the output device&] +[s0;3 &] +[s0;:`:`:Draw`:`:Draw`(`): [* Draw](HDC_[*@3 hdc])&] +[s2; Win32`-specific: initializes the Draw object to output on a Window +device context (HDC). This is the usual Windows method to paint +into windows, on memory`-mapped bitmaps and on the printer.&] +[s2; [* Note:] it is seldom necessary to construct the Draw object in +this way. System`-independent U`+`+ layer hides such system`-specific +internals within upper`-level abstract objects (PrintDraw, ImageDraw, +ViewDraw). Remember that, by directly handling device contexts, +you are deprived of a multitude of U`+`+ internal housekeeping +chores and checks which ensure that the device context and potentially +its attributes are properly allocated and destroyed as necessary. +For a complete set of rules for working with device contexts, +see Microsoft Windows documentation.&] +[s4; [*C@3 hdc]-|handle to output device context&] +[s0;3 &] +[s0;:`:`:Draw`:`:Draw`(`:`:Draw able`,GC`,XftDraw`*`,const`:`:Vector`<`:`:Rect`>`&`): [* D +raw](Drawable_[*@3 dw], GC_[*@3 gc], XftDraw_`*[*@3 xftdraw], const_Vector`&_[*@3 c +lip])&] +[s2; X11`-specific: initializes the draw object to output on a X`-Windows +drawable using a given graphics context (GC). This is the usual +X`-Windows method to paint into windows and on memory`-mapped +bitmaps.&] +[s2; [* Note:] it is seldom necessary to construct the Draw object in +this way. System`-independent U`+`+ layer hides such system`-specific +internals within upper`-level abstract objects (ImageDraw, ViewDraw). +Remember that, by directly handling device contexts, you are +deprived of a multitude of U`+`+ internal housekeeping chores +and checks which ensure that the device context and potentially +its attributes are properly allocated and destroyed as necessary. +For a complete set of rules for working with device contexts, +see X Windows documentation.&] +[s4; [*C@3 dw]-|output drawable&] +[s4; [*C@3 gc]-|output graphic context&] +[s4; [*C@3 xftdraw]-|XFT interface object&] +[s4; [*C@3 clip]-|clipping region&] +[s0;3 &] +[s0;:`:`:Draw`:`:Draw`(`:`:Draw able`,GC`,const`:`:Vector`<`:`:Rect`>`&`): [* Draw](Dra +wable_[*@3 dw], GC_[*@3 gc], const_Vector`&_[*@3 clip])&] +[s2; X11`-specific: initializes the draw object to output on a X`-Windows +drawable using a given graphics context (GC). This is the usual +X`-Windows method to paint into windows and on memory`-mapped +bitmaps.&] +[s2; [* Note:] it is seldom necessary to construct the Draw object in +this way. System`-independent U`+`+ layer hides such system`-specific +internals within upper`-level abstract objects (ImageDraw, ViewDraw). +Remember that, by directly handling device contexts, you are +deprived of a multitude of U`+`+ internal housekeeping chores +and checks which ensure that the device context and potentially +its attributes are properly allocated and destroyed as necessary. +For a complete set of rules for working with device contexts, +see X Windows documentation.&] +[s4; [*C@3 dw]-|output drawable&] +[s4; [*C@3 gc]-|output graphic context&] +[s4; [*C@3 clip]-|clipping region&] +[s0;3 &] +[s0;:`:`:Draw`:`:Draw`(Drawable`,GC`,XftDraw`*`,const`:`:Vector`<`:`:Rect`>`&`): void +_[* Init]()&] +[s2; Initializes internal variables for output on a previously set +output device.&] +[s2; [* Note:] this is normally not necessary. This function is called +only from derived classes which need to set the output device +handle (HDC under Win32, GC under X Windows) manually.&] +[s0;3 &] +[s0;:`:`:Draw`:`:Init`(const`:`:Vector`<`:`:Rect`>`&`,`:`:Point: void_[* Init](const_Ve +ctor`&_[*@3 clip], Point_[*@3 offset]_`=_Point([@3 0], [@3 0]))&] +[s2; X Windows`-specific: initializes Draw internals for output on +a previously set output device. The parameters give clipping +region and output offset to initialize the clipping stack with.&] +[s4; [*C@3 clip]-|clipping region of the output device (in device coordinates)&] +[s4; [*C@3 offset]-|initial output offset (device coordinates)&] +[s0; &] +[s0; Querying output device properties&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 PaletteMode]()_[@(0.0.255) const]&] +[s2; Checks whether the current output device is palette`-based or +RGB`-based. Monochrome devices are treated as RGB`-based.&] +[s4; [*/ Return value]-|[/ true] `= device uses palette`-based color management, +[/ false] `= device pixels contain direct RGB color values.&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 IsMono]()_[@(0.0.255) const]&] +[s2; Check whether the current output device is monochrome.&] +[s4; [*/ Return value]-|[/ true] `= monochrome, [/ false] `= grayscale or +color device.&] +[s0;3 &] +[s5;K%- [^`:`:Size^ Size]_[@0 GetPagePixels]()_[@(0.0.255) const]&] +[s2; Returns pixel page size. For virtual output devices (like Drawings), +this is the same as dot page size.&] +[s4; [*/ Return value]-|Pixel width and height of the output page.&] +[s0;3 &] +[s5;K%- [^`:`:Size^ Size]_[@0 GetPageMMs]()_[@(0.0.255) const]&] +[s2; Returns physical output page size in millimeters.&] +[s4; [*/ Return value]-|Output page width and height in millimeters.&] +[s0;3 &] +[s5;K%- [^`:`:Size^ Size]_[@0 GetPixelsPerInch]()_[@(0.0.255) const]&] +[s2; Returns the resolution of the output device.&] +[s4; [*/ Return value]-|Number of pixels horizontally and vertically +across a squared inch.&] +[s0;3 &] +[s5;K%- [^`:`:Size^ Size]_[@0 GetSheetPixels]()_[@(0.0.255) const]&] +[s2; Returns pixel size of the output page including physical margins. +This is meaningful only for printers for which the printable +area is sometimes smaller than the actual paper size. For such +devices [* GetSheetPixels] returns pixel size of the original (full) +paper including the margins unsuitable for printing, whereas +[* GetPagePixels] returns the printable area size (paper size minus +physically enforced margins).&] +[s4; [*/ Return value]-|Pixel width and height of the physical output +medium (paper in printer)&] +[s0;3 &] +[s5;K%- [^`:`:Point^ Point]_[@0 GetPageOffset]()_[@(0.0.255) const]&] +[s2; Returns pixel offset of the topleft corner of the printable +output area from the topleft corner of the physical output medium +(printer paper). This is meaningful only for printers where the +printable area is sometimes smaller than the actual paper size +(see also [* GetSheetPixels]). By subtracting [* GetPageOffset()] +from a pair of coordinates it is possible to position objects +absolutely with respect to the paper edges.&] +[s4; [*/ Return value]-|Horizontal and vertical displacement from the +topleft corner of the physical output medium to the topleft corner +of the printable area. &] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 Pixels]()_[@(0.0.255) const]&] +[s2; Checks whether the output device coordinates are pixel`-based +or dot`-based. This is the negation of the [* Dots()] function. +Window and image draws are pixel`-based, whereas printer and +Drawing draws are normally dot`-based.&] +[s4; [*/ Return value]-|[/ true] `= device is pixel`-based, [/ false] `= +device is dot`-based.&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 Dots]()_[@(0.0.255) const]&] +[s2; Checks whether the output device coordinates are pixel`-based +or dot`-based. This is the negation of the [* Pixels()] function. +Window and image draws are pixel`-based, whereas printer and +Drawing draws are normally dot`-based.&] +[s4; [*/ Return value]-|[/ true] `= device is dot`-based, [/ false] `= device +is pixel`-based.&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 IsPrinter]()_[@(0.0.255) const]&] +[s2; Checks whether the output device is a printer.&] +[s4; [*/ Return value]-|[/ true] `= device is a printer.&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 IsAborted]()_[@(0.0.255) const]&] +[s2; Checks whether the output job has been aborted. This is meaningful +mainly for printers.&] +[s4; [*/ Return value]-|[/ true] `= job has been aborted.&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 IsBack]()_[@(0.0.255) const]&] +[s2; Checks whether output device supports double`-buffering. For +devices with double`-buffering it is not necessary (and is usually +counterproductive) to take measures to prevent flickering as +the whole output is composed offscreen. Output devices without +direct video output (like Drawings or Images) are return [/ true] +(as there is no direct video output, it is not necessary to prevent +flickering).&] +[s4; [*/ Return value]-|[/ true] `= device is double`-buffered, [/ false] +`= output goes directly to video&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 IsDrawing]()_[@(0.0.255) const]&] +[s2; Checks whether the output device is a Drawing.&] +[s4; [*/ Return value]-|[/ true] `= device is a Drawing.&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 IsMetaFile]()_[@(0.0.255) const]&] +[s2; Win32`-specific: Checks whether the output device is a Windows +Metafile.&] +[s4; [*/ Return value]-|[/ true `= ]device is a Windows Enhanced Metafile.&] +[s0; &] +[s0; Managing colors&] +[s0; &] +[s0; Different output devices and their technologies pose natural +limitations on producing color output. The basic classes of devices +with respect to their color management are:&] +[s0; &] +[s0;i150;O0; Monochrome devices (like monochrome laser printers or +certains specialized displays) support no color at all. Every +pixel of the output device can be black or white.&] +[s0;i150;O0; Palette`-based devices (like old 16`- or 256`-color +displays) support a fixed set of distinct color slots, called +a [/ palette]. Colors of the individual slots can be either user`-settable +or fixed (system`-set). Every pixel of the output device is an +index into the palette.&] +[s0;i150;O0; RGB`-based devices (HiColor or TrueColor displays), +in which every pixel of the output device can be set to any of +the colors displayable by the device. Typically each pixel has +at least 16 bits comprising of 5`- or 8`-bit subfields for the +red, green, and blue color component.&] +[s0; &] +[s0; Logical color model used by the Draw class communicates colors +using device`-independent color values (as represented by the +[* Color] class). Graphical output functions convert these colors +on`-the`-fly to physical colors supported by the system. Pixel`- +and line`-oriented output objects (lines, polylines, ellipses) +paint the requested objects with the nearest available physical +color to the requested logical color, whereas area`- and raster`-oriented +output objects (rectangles, polygons, and images) use dithering +to approximate logical colors not directly produceable by the +device.&] +[s0; &] +[s0; Draw supports two ways of using palette`-based output devices:&] +[s0; &] +[s0;i150;O0; [* Automatic palette]: upon initialization Draw sets up +the system palette to contain a matrix of 6x6x6 RGB triplets +for all combinations of 6 equidistant intensities of the color +components, a 16`-level gray scale plus 16 basic system colors. +This fixed color palette enables the system to closely mimic +the behaviour of RGB`-based color systems.&] +[s0;i150;O0; [* User palette]: Draw works with the current palette as +set by the system / user. Nearest match is used for logical color +mapping.&] +[s0;3 &] +[s5;K%- static [@(0.0.255) bool]_[@0 AutoPalette]()&] +[s2; Checks palette mode of the active output device.&] +[s4; [*/ Return value]-|[* true] `= automatic palette mode, [* false] `= +user palette mode&] +[s0;3 &] +[s5;K%- static [@(0.0.255) void]_[@0 SetAutoPalette]([@(0.0.255) bool]_[@3 ap])&] +[s2; Turns automatic palette mode on or off.&] +[s4; [*C@3 ap]-|[* true] `= activate automatic palette, [* false] `= activate +user palette mode&] +[s0;3 &] +[s0;:`:`:Draw`:`:Win32UpdateSColors`(`): void_[* Win32UpdateSColors]()&] +[s2; Updates logical palette of basic system`-dependent colors ([* SLtGray], +[* SWhite], [* SBlack] etc.).&] +[s0; &] +[s0; Managing text styles&] +[s0;3 &] +[s5;K%- static [@(0.0.255) int]_CALLBACK_[@0 AddFace]([@(0.0.255) const]_[^LOGFONT^ LOGFONT]_ +`*[@3 logfont], [@(0.0.255) const]_[^TEXTMETRIC^ TEXTMETRIC]_`*, [^`:`:dword^ dword]_[@3 ty +pe], [^LPARAM^ LPARAM]_[@3 param])&] +[s2; &] +[s4; [*C@3 font]-|&] +[s4; [*C@3 angle]-|&] +[s4; [*C@3 device]-|&] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s5;K%- static [@(0.0.255) void]_[@0 SetStdFont]([^`:`:Font^ Font]_[@3 font])&] +[s2; Sets the font to be used as the standard font (StdFont, Font`::STDFONT).&] +[s4; [*C@3 font]-|new standard font&] +[s0;3 &] +[s5;K%- static [^`:`:Font^ Font]_[@0 GetStdFont]()&] +[s2; Returns the current standard font.&] +[s4; [*/ Return value]-|previously set or system`-default standard font&] +[s0;3 &] +[s5;K%- static [^`:`:Size^ Size]_[@0 GetStdFontSize]()&] +[s2; Returns the letter box width and height of the current standard +font.&] +[s4; [*/ Return value]-|[/ cx `= GetWidth(), cy `= GetHeight()] of the +current standard font. When [/ cx `=`= 0], standard font has default +width.&] +[s0;3 &] +[s5;K%- static [@(0.0.255) int]_[@0 GetStdFontCy]()&] +[s2; Returns letter box width and height of the current standard +font&] +[s4; [*/ Return value]-|[/ cx `= GetWidth(), cy `= GetHeight()] of the +current standard font. When [/ cx `=`= 0], standard font has default +width.&] +[s0;3 &] +[s0;:`:`:Draw`:`:GetFontInfo`(`:`:byte`,`:`:Font: FontInfo_[* GetFontInfo](byte_[*@3 char +set], Font_[*@3 font]_`=_StdFont())&] +[s2; Returns font information object describing given font and charset.&] +[s4; [*C@3 charset]-|character set to use (from the CHARSET`_xxx enumeration)&] +[s4; [*C@3 font]-|font to retrieve information for.&] +[s4; [*/ Return value]-|FontInfo structure describing metrics of system`-allocated +font for the given font object.&] +[s0;3 &] +[s0;:`:`:Draw`:`:GetFontInfo`(`:`:Font: FontInfo_[* GetFontInfo](Font_[*@3 font]_`=_StdFo +nt())&] +[s2; Returns font information object describing given font.&] +[s4; [*C@3 font]-|font to retrieve information for.&] +[s4; [*/ Return value]-|FontInfo structure describing metrics of system`-allocated +font for the given Font object.&] +[s0;3 &] +[s0;:`:`:Draw`:`:GetFontInfoW`(`:`:Font: FontInfo_[* GetFontInfoW](Font_[*@3 font]_`=_Std +Font())&] +[s2; Returns Unicode font information for a given font.&] +[s4; [*C@3 font]-|font to retrieve information for.&] +[s4; [*/ Return value]-|FontInfo structure describing Unicode metrics +of system`-allocated font for the given Font object.&] +[s0; &] +[s0; Controlling current clipping region and drawing offset&] +[s0; Sometimes it is necessary or at least handy to move the logical +coordinate origin and limit output clipping for a part of the +drawing process. For this reason, coordinate origin displacement +together with current clipping region is kept as a stack in the +Draw object. Certain function push a new offset / clipping entry +to the stack, other functions manipulate the current top of stack. +Actual coordinate origin and clipping in effect while drawing +corresponds to the entry on top of the stack. At the beginning +the coordinate origin is usually set to topleft corner of the +output medium and the clipping box encapsulates all available +output area (or, like in case of [* Ctrl`::Paint], the current `"dirty`" +area that needs to be repainted in a window).&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 Begin]()&] +[s2; Duplicates the current entry on the top of the coordinate / +clipping stack. This effectively doesn`'t change the current +coordinate / clipping setting but creates a new entry which can +be further manipulated by other methods like [* IntersectClip] +or [* ExcludeClip].&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 End]()&] +[s2; Discards one coordinate / clipping entry from top of the stack.&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 Offset]([^`:`:Point^ Point]_[@3 p])&] +[s2; Creates a new coordinate / clipping entry on top of the stack +equal to the previous entry with coordinate origin shifted by +[* p] pixels.&] +[s4; [*C@3 p]-|number of pixels to add to coordinate origin ([/ p.x_>_0] +`= right, [/ p.x_<_0] `= left, [/ p.y_>_0] `= down, [/ p.y_<_0] `= +up).&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 Offset]([@(0.0.255) int]_[@3 x], [@(0.0.255) int]_[@3 y])&] +[s2; Creates a new coordinate / clipping entry on top of the stack +equal to the previous entry with coordinate origin shifted by +[/ (x, y)] pixels.&] +[s4; [*C@3 x]-|number of pixels to add to horizontal coordinate origin +([/ x_>_0] `= right, [/ x_<_0] `= left).&] +[s4; [*C@3 y]-|number of pixels to add to vertical coordinate origin +([/ y_>_0] `= down, [/ y_<_0] `= up).&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 Clip]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 r])&] +[s2; Creates a new coordinate / clipping entry on top of the stack +with coordinate origin equal to the previous value and clipping +equal to the intersection of the previous clipping region with +the rectangle [/ r].&] +[s4; [*C@3 r]-|rectangle to intersect with current clipping region (relative +to the current coordinate origin)&] +[s4; [*/ Return value]-|[/ true] `= the new clipping region is non`-empty, +[/ false] `= the new clipping is empty (it is not necessary to +draw anything as nothing is visible)&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 Clip]([@(0.0.255) int]_[@3 x], [@(0.0.255) int]_[@3 y], +[@(0.0.255) int]_[@3 cx], [@(0.0.255) int]_[@3 cy])&] +[s2; Creates a new coordinate / clipping entry on top of the stack +with coordinate origin equal to the previous value and clipping +equal to the intersection of the previous clipping region with +the rectangle given by its topleft origin (relative to the current +coordinate origin) [/ (x, y)], width [/ cx] and height [/ cy].&] +[s2; &] +[s4; [*C@3 x]-|left side of rectangle to intersect with current clipping +region (relative to current coordinate origin)&] +[s4; [*C@3 y]-|top side of rectangle to intersect with current clipping +region (relative to current coordinate origin)&] +[s4; [*C@3 cx]-|rectangle width&] +[s4; [*C@3 cy]-|rectangle height&] +[s4; [*/ Return value]-|[/ true] `= the new clipping region is non`-empty, +[/ false] `= the new clipping is empty (it is not necessary to +draw anything as nothing is visible)&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 Clipoff]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 r])&] +[s2; Creates a new coordinate / clipping entry on top of the stack +with clipping equal to the intersection of the previous clipping +region with the rectangle [/ r] and with the coordinate origin +shifted by [/ r.TopLeft()] pixels. For further drawing operations +the current pixel [/ r.TopLeft()] will correspond to [/ (0,_0) ]and +[/ r.BottomRight()] to [/ (r.Width(),_r.Height())].&] +[s4; [*C@3 r]-|rectangle to intersect with current clipping region (relative +to current coordinate origin); [/ r.left] is added to the horizontal +coordinate origin and [/ r.top] to the vertical coordinate origin.&] +[s4; [*/ Return value]-|[/ true] `= the new clipping region is non`-empty, +[/ false] `= the new clipping is empty (it is not necessary to +draw anything as nothing is visible)&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 Clipoff]([@(0.0.255) int]_[@3 x], [@(0.0.255) int]_[@3 y], +[@(0.0.255) int]_[@3 cx], [@(0.0.255) int]_[@3 cy])&] +[s2; Creates a new coordinate / clipping entry on top of the stack +with clipping equal to the intersection of the previous clipping +region with the rectangle [/ r] and with the coordinate origin +shifted by [/ (x,_y)] pixels. For further drawing operations the +current pixel [/ (x, y)] will correspond to [/ (0,_0)].&] +[s2; &] +[s4; [*C@3 x]-|left side of rectangle to intersect with current clipping +region (relative to current coordinate origin) and the amount +to add to horizontal coordinate origin&] +[s4; [*C@3 y]-|top side of rectangle to intersect with current clipping +region (relative to current coordinate origin) and the amount +to add to vertical coordinate origin&] +[s4; [*C@3 cx]-|rectangle width&] +[s4; [*C@3 cy]-|rectangle height&] +[s4; [*/ Return value]-|[/ true] `= the new clipping region is non`-empty, +[/ false] `= the new clipping is empty (it is not necessary to +draw anything as nothing is visible)&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 ExcludeClip]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 r])&] +[s2; Updates the current clipping region on top of the coordinate +/ clipping stack by subtracting the rectangle [/ r] from the current +clipping region.&] +[s4; [*C@3 r]-|rectangle to subtract from current clipping region (relative +to current coordinate origin)&] +[s4; [*/ Return value]-|[/ true] `= the new clipping region is non`-empty, +[/ false] `= the new clipping is empty (it is not necessary to +draw anything as nothing is visible)&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 ExcludeClip]([@(0.0.255) int]_[@3 x], [@(0.0.255) int]_[@3 y], +[@(0.0.255) int]_[@3 cx], [@(0.0.255) int]_[@3 cy])&] +[s2; Updates the current clipping region on top of the coordinate +/ clipping stack by subtracting the rectangle [/ RectC(x,_y,_cx,_cy)] +from the current clipping region.&] +[s4; [*C@3 x]-|left side of rectangle to subtract from current clipping +region (relative to current coordinate origin)&] +[s4; [*C@3 y]-|top side of rectangle to subtract from current clipping +region (relative to current coordinate origin)&] +[s4; [*C@3 cx]-|rectangle width&] +[s4; [*C@3 cy]-|rectangle height&] +[s4; [*/ Return value]-|[/ true] `= the new clipping region is non`-empty, +[/ false] `= the new clipping is empty (it is not necessary to +draw anything as nothing is visible)&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 IntersectClip]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 r])&] +[s2; Updates the current clipping region on top of the coordinate +/ clipping stack by intersecting the rectangle [/ r] with the current +clipping region.&] +[s4; [*C@3 r]-|rectangle to intersect with current clipping region (relative +to current coordinate origin)&] +[s4; [*/ Return value]-|[/ true] `= the new clipping region is non`-empty, +[/ false] `= the new clipping is empty (it is not necessary to +draw anything as nothing is visible)&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 IntersectClip]([@(0.0.255) int]_[@3 x], [@(0.0.255) int]_[@3 y], +[@(0.0.255) int]_[@3 cx], [@(0.0.255) int]_[@3 cy])&] +[s2; Updates the current clipping region on top of the coordinate +/ clipping stack by intersecting the rectangle [/ RectC(x,_y,_cx,_cy)] +with the current clipping region.&] +[s4; [*C@3 x]-|left side of rectangle to intersect with current clipping +region (relative to current coordinate origin)&] +[s4; [*C@3 y]-|top side of rectangle to intersect with current clipping +region (relative to current coordinate origin)&] +[s4; [*C@3 cx]-|rectangle width&] +[s4; [*C@3 cy]-|rectangle height&] +[s4; [*/ Return value]-|[/ true] `= the new clipping region is non`-empty, +[/ false] `= the new clipping is empty (it is not necessary to +draw anything as nothing is visible)&] +[s0;3 &] +[s5;K%- [^`:`:Rect^ Rect]_[@0 GetClip]()_[@(0.0.255) const]&] +[s2; Returns the smallest rectangle fully covering the current clipping +region. The value can be used to limit output to the visible +area. Take care not to mix the current clipping region with the +output rectangle as the clipping region can be just a subset +of this output rectangle (like in case of [* Ctrl`::Paint] when +a part of the window is obscured).&] +[s4; [*/ Return value]-|Smallest rectangle fully covering the current +clipping region (relative to current coordinate origin)&] +[s0;3 &] +[s5;K%- [^`:`:Point^ Point]_[@0 GetOffset]()_[@(0.0.255) const]&] +[s2; Returns the current coordinate origin. This is naturally in +absolute coordinates relative to the topleft corner of the output +medium.&] +[s4; [*/ Return value]-|Current coordinate origin (relative to topleft +corner of the output medium)&] +[s0;3 &] +[s5;K%- [@(0.0.255) int]_[@0 GetCloffLevel]()_[@(0.0.255) const]&] +[s2; Returns the number of entries on the coordinate / clipping stack. +This is normally used for self`-consistency check where the drawing +routine ASSERTs that after drawing something the stack depth +is the same as it was before (to check whether there is not a +stack `'leak`' when the drawing routine forgets to [* End] some +coordinate / clipping entries it has previously pushed on the +stack).&] +[s4; [*/ Return value]-|number of entries on the coordinate / clipping +stack&] +[s0;3 &] +[s5;K%- [^`:`:Point^ Point]_[@0 LPtoDP]([^`:`:Point^ Point]_[@3 p])_[@(0.0.255) const]&] +[s2; Converts a point from coordinates relative to current coordinate +origin to absolute coordinates from the topleft corner of the +output medium. This effectively adds the current coordinate origin +to the given point [/ p].&] +[s4; [*C@3 p]-|Point to convert (relative to current coordinate origin)&] +[s4; [*/ Return value]-|Absolute coordinates of point [/ p] from the topleft +corner of the output medium&] +[s0;3 &] +[s5;K%- [^`:`:Point^ Point]_[@0 DPtoLP]([^`:`:Point^ Point]_[@3 p])_[@(0.0.255) const]&] +[s2; Converts a point from the absolute coordinates (from the topleft +corner of the output medium) to coordinates relative to current +coordinate origin. This effectively subtracts the current coordinate +origin from the point [/ p].&] +[s4; [*C@3 p]-|Point to convert (absolute coordinates)&] +[s4; [*/ Return value]-|Relative coordinates of [/ p] with respect to +the current coordinate origin&] +[s0;3 &] +[s5;K%- [^`:`:Rect^ Rect]_[@0 LPtoDP]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 r])_[@(0.0.255) c +onst]&] +[s2; Converts a rectangle from coordinates relative to current coordinate +origin to absolute coordinates from the topleft corner of the +output medium. This effectively offsets the rectangle [/ r] by +the amount given by the current coordinate origin.&] +[s4; [*C@3 r]-|Rectangle to convert (relative to current coordinate +origin)&] +[s4; [*/ Return value]-|Rectangle [/ r] in absolute coordinates with respect +to the topleft corner of the output medium&] +[s0;3 &] +[s5;K%- [^`:`:Rect^ Rect]_[@0 DPtoLP]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 r])_[@(0.0.255) c +onst]&] +[s2; Converts a rectangle from the absolute coordinates (with respect +to the topleft corner of the output medium) to coordinates relative +to current coordinate origin. This effectively offsets the rectangle +[/ r] by the negative value of the current coordinate origin.&] +[s4; [*C@3 r]-|Rectangle to convert (absolute coordinates)&] +[s4; [*/ Return value]-|Rectangle [/ r] in coordinates relative to current +coordinate origin&] +[s0; &] +[s0; Drawing basic vector primitives (lines, polygons)&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawRect]([@(0.0.255) int]_[@3 x], [@(0.0.255) int]_[@3 y], +[@(0.0.255) int]_[@3 cx], [@(0.0.255) int]_[@3 cy], [^`:`:Color^ Color]_[@3 color])&] +[s2; Fills rectangle [/ RectC(x,_y,_cx,_cy)] with the color [/ color]. +On palette`-based devices dithering is sometimes used for approximation +when the given color doesn`'t closely correnspond to one of the +available colors (see [* Managing colors]).&] +[s4; [*C@3 x]-|left side to rectangle to fill (relative to coordinate +origin)&] +[s4; [*C@3 y]-|top side of rectangle to fill&] +[s4; [*C@3 cx]-|rectangle width&] +[s4; [*C@3 cy]-|rectangle height&] +[s4; [*C@3 color]-|color used for filling. When [/ color `=`= Null], nothing +is done. The special color [* InvertColor()] can be used to logically +invert all pixel bits within the given area. This has the effect +of changing white to black and vice versa and changing color +hues to their complements. Note, however, that due to [/ gamma]`-correction, +the output image is not a photometrical complement of the original +image. &] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawRect]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 rect], +[^`:`:Color^ Color]_[@3 color])&] +[s2; Fills rectangle [/ rect] with the color [/ color]. On palette`-based +devices dithering is sometimes used for approximation when the +given color doesn`'t closely correnspond to one of the available +colors (see [* Managing colors]).&] +[s4; [*C@3 rect]-|area to fill (relative to coordinate origin)&] +[s4; [*C@3 color]-|color used for filling. When [/ color `=`= Null], nothing +is done. The special color [* InvertColor()] can be used to logically +invert all pixel bits within the given area.&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawLine]([@(0.0.255) int]_[@3 x1], [@(0.0.255) int]_[@3 y1], +[@(0.0.255) int]_[@3 x2], [@(0.0.255) int]_[@3 y2], [@(0.0.255) int]_[@3 width]_`=_[@3 0], +[^`:`:Color^ Color]_[@3 color]_`=_DefaultInk)&] +[s2; Draws a line from the point [/ (x1,_y1)] to [/ (x2,_y2)] with color +[/ color]. When [/ width] is positive, solid line [/ width] pixels +wide is drawn. When [/ width] is negative, function draws a dashed +line 1 pixel wide. [/ width] is then one of the [/ PEN`_...] enumeration +constants defining the desired line pattern. The fact that the +function doesn`'t support wide dashed lines is a sad limitation +of the older Win32 GDI which under Windows 95, 98 and ME doesn`'t +support this. When wide dashed lines are needed, it is necessary +to generate the segments manually and split the line patterns +into individual line segments or into polygonal patches (depending +on the precision requirements and time issues in given context). +Under Win32 GDI the point [/ (x1,_y1)] is not drawn.&] +[s4; [*C@3 x1, y1]-|line beginning (relative to current coordinate origin)&] +[s4; [*C@3 x2, y2]-|line end&] +[s4; [*C@3 width]-|line width or one of the [/ PEN`_] constants for dashed +lines&] +[s4; [*C@3 color]-|line color. When [/ color `=`= Null], nothing is drawn. +On palette`-based devices the nearest palette color is used (no +dithering is made).&] +[s0; &] +[s0;3 &] +[s0;:`:`:Draw`:`:enum`{ BEGIN`, OFFSET`, CLIP`, CLIPOFF`, EXCLUDECLIP`, INTERSECTCLIP`, END`, DRAWRECT`, DRAWIMAGE`, DRAWMONOIMAGE`, DRAWDRAWING`, DRAWLINE`, DRAWELLIPSE`, DRAWTEXT`, DRAWARC`, DRAWPOLYPOLYLINE`}: [* e +num `{ PEN`_NULL, PEN`_SOLID, PEN`_DASH, PEN`_DOT, PEN`_DASHDOT, +PEN`_DASHDOTDOT `}]&] +[s2; &] +[s4; [%-*C@3 PEN`_NULL]-|empty pen (nothing is drawn)&] +[s4; [%-*C@3 PEN`_SOLID]-|solid pen&] +[s4; [%-*C@3 PEN`_DASH]-|dashed pen `- `- `-&] +[s4; [%-*C@3 PEN`_DOT]-|dotted pen (dashes are shorter) . . .&] +[s4; [%-*C@3 PEN`_DASHDOT]-|dash `- dot `- dash `- dot pattern&] +[s4; [%-*C@3 PEN`_DASHDOTDOT]-|dash `- dot `- dot `- dash `- dot `- +dot pattern&] +[s0; &] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawLine]([^`:`:Point^ Point]_[@3 p1], [^`:`:Point^ Point]_[@3 p2], + [@(0.0.255) int]_[@3 width]_`=_[@3 0], [^`:`:Color^ Color]_[@3 color]_`=_DefaultInk)&] +[s2; Draws a line from the point [/ p1] to [/ p2] with color [/ color]. +[/ width] gives line width (positive) or dash pattern (negative). +Under Win32 GDI the point [/ (x1,_y1)] is not drawn.&] +[s2; &] +[s4; [*C@3 p1]-|line beginning (relative to coordinate origin)&] +[s4; [*C@3 p2]-|line end&] +[s4; [*C@3 width]-|line width or dash pattern&] +[s4; [*C@3 color]-|line color&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawEllipse]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 r], +[^`:`:Color^ Color]_[@3 color]_`=_DefaultInk, [@(0.0.255) int]_[@3 pen]_`=_Null, +[^`:`:Color^ Color]_[@3 pencolor]_`=_DefaultInk)&] +[s2; Draws the largest ellipse with both axes parallel to coordinate +axes fully within rectangle [/ r], i.e. with center point at [/ r.CenterPoint()], +semi major axis and semi minor axis equal to [/ r.Width() / 2] +and [/ r.Height() / 2].&] +[s4; [*C@3 r]-|ellipse`'s bounding rectangle&] +[s4; [*C@3 color]-|color to fill the ellipse inside with ([/ Null] `= +no filling)&] +[s4; [*C@3 pen]-|pen width / dash style to used for drawing the ellipse +circumference&] +[s4; [*C@3 pencolor]-|pen color for drawing the ellipse circumference +([/ Null] `= circumference is not drawn)&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawEllipse]([@(0.0.255) int]_[@3 x], [@(0.0.255) int]_[@3 y], +[@(0.0.255) int]_[@3 cx], [@(0.0.255) int]_[@3 cy], [^`:`:Color^ Color]_[@3 color]_`=_Default +Ink, [@(0.0.255) int]_[@3 pen]_`=_Null, [^`:`:Color^ Color]_[@3 pencolor]_`=_DefaultInk)&] +[s2; Draws the largest ellipse with both axes parallel to coordinate +axes fully within rectangle [/ RectC(x, y, cx, cy)], i.e. with +center point at [/ x_`+_cx_/_2] and [/ y_`+_cy_/_2], semi major axis +and semi minor axis equal to [/ cx / 2] and [/ cy / 2].&] +[s2; &] +[s4; [*C@3 x]-|left side of ellipse`'s bounding rectangle&] +[s4; [*C@3 y]-|top side of ellipse`'s bounding rectangle&] +[s4; [*C@3 cx]-|rectangle width&] +[s4; [*C@3 cy]-|rectangle height&] +[s4; [*C@3 color]-|color to fill ellipse inside with ([/ Null] `= interior +is not filled)&] +[s4; [*C@3 pen]-|pen width / dash style for drawing ellipse circumference&] +[s4; [*C@3 pencolor]-|pen color for drawing ellipse circumference ([/ Null] +`= not drawn)&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawArc]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 rc], +[^`:`:Point^ Point]_[@3 start], [^`:`:Point^ Point]_[@3 end], [@(0.0.255) int]_[@3 width]_`=_ +[@3 0], [^`:`:Color^ Color]_[@3 color]_`=_DefaultInk)&] +[s2; Draws elliptic arc corresponding to the largest ellipse fully +within the rectangle [/ rc] and running counterclockwise from the +direction corresponding to the line connecting the centre of +the ellipse ([/ rc.CenterPoint()]) with the point [/ start] and ending +at direction of the point [/ end] from the ellipse centre. When +[/ start `=`= end], the full ellipse is drawn.&] +[s4; [*C@3 rc]-|ellipse`'s bounding rectangle&] +[s4; [*C@3 start]-|direction at which to start the arc&] +[s4; [*C@3 end]-|direction of arc end (from the ellipsec centre)&] +[s4; [*C@3 width]-|pen width or dash style&] +[s4; [*C@3 color]-|color to used for drawing. On palette`-based devices +the nearest palette color is used (no dithering).&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawPolyPolyline]([@(0.0.255) const]_[^`:`:Point^ Point]_`*[@3 ve +rtices], [@(0.0.255) int]_[@3 vertex`_count], [@(0.0.255) const]_[@(0.0.255) int]_`*[@3 cou +nts], [@(0.0.255) int]_[@3 count`_count], [@(0.0.255) int]_[@3 width]_`=_[@3 0], +[^`:`:Color^ Color]_[@3 color]_`=_DefaultInk, [^`:`:Color^ Color]_[@3 doxor]_`=_Null)&] +[s2; Draws a series of polylines. Polyline vertices are kept in the +array [/ vertices]. The parameter [/ vertext`_count] gives the total +number of vertices of all polylines in the array. The array [/ counts] +gives numbers of points defining the individual polylines and +[/ count`_count] gives number of entries in this array (i.e. the +number of connected polylines). The first polyline comprises +vertices [/ vertices`[0`], vertices`[1`]] ... [/ vertices`[counts`[0`] +`- 1`]], the second polyline [/ vertices`[counts`[0`]`], vertices`[counts`[0`] +`+ 1`] ... vertices`[counts`[0`] `+ counts`[1`] `- 1`]], etc.&] +[s4; [*C@3 vertices]-|array of polyline vertices (relative to coordinate +origin)&] +[s4; [*C@3 vertex`_count]-|total number of vertices of all polylines&] +[s4; [*C@3 counts]-|array of polyline vertex counts&] +[s4; [*C@3 count`_count]-|number of entries in the [/ counts] array, i.e. +the number of polylines&] +[s4; [*C@3 width]-|pen width or dash style.&] +[s4; [*C@3 color]-|polyline color.&] +[s4; [*C@3 doxor]-|used to draw a xor`'ed polyline set. Useful for drag +`& drop animations where it is needed to draw and undraw the +rubber rectangle or line repeatedly without having to repaint +the whole display image. When set to non`-[/ Null] value, it gives +the `'background`' color on which polyline pixels will have color +[/ color] after xoring.&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawPolyPolyline]([@(0.0.255) const]_[^`:`:Vector^ Vector]<[^`:`:Point^ P +oint]>`&_[@3 vertices], [@(0.0.255) const]_[^`:`:Vector^ Vector]<[^int^ int]>`&_[@3 counts], + [^int^ int]_[@3 width]_`=_[@3 0], [^`:`:Color^ Color]_[@3 color]_`=_DefaultInk, +[^`:`:Color^ Color]_[@3 doxor]_`=_Null)&] +[s2; Draws a series of polylines. Polyline vertices are kept in the +array [/ vertices]. The array [/ counts] gives numbers of points +defining the individual polylines (i.e. the number of connected +polylines is equal to [/ counts.GetCount()]). The first polyline +comprises vertices [/ vertices`[0`], vertices`[1`]] ... [/ vertices`[counts`[0`] +`- 1`]], the second polyline [/ vertices`[counts`[0`]`], vertices`[counts`[0`] +`+ 1`] ... vertices`[counts`[0`] `+ counts`[1`] `- 1`]], etc.&] +[s2; &] +[s4; [*C@3 vertices]-|vertices of all polylines to draw&] +[s4; [*C@3 counts]-|vertex counts in individual polyline segments&] +[s4; [*C@3 width]-|pen width / dash style&] +[s4; [*C@3 color]-|polyline color&] +[s4; [*C@3 doxor]-|background value for xor`'ed drawing ([/ Null] `= draw +normally)&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawPolyline]([@(0.0.255) const]_[^`:`:Point^ Point]_`*[@3 vertic +es], [@(0.0.255) int]_[@3 count], [@(0.0.255) int]_[@3 width]_`=_[@3 0], +[^`:`:Color^ Color]_[@3 color]_`=_DefaultInk, [^`:`:Color^ Color]_[@3 doxor]_`=_Null)&] +[s2; Draws a single polyline connecting all [/ count] [/ vertices].&] +[s4; [*C@3 vertices]-|Polyline vertices&] +[s4; [*C@3 count]-|number of vertices&] +[s4; [*C@3 width]-|pen width / dash style&] +[s4; [*C@3 color]-|polyline color&] +[s4; [*C@3 doxor]-|background value for xor`'ed drawing ([/ Null] `= draw +normally)&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawPolyline]([@(0.0.255) const]_[^`:`:Vector^ Vector]<[^`:`:Point^ P +oint]>`&_[@3 vertices], [@(0.0.255) int]_[@3 width]_`=_[@3 0], [^`:`:Color^ Color]_[@3 color]_ +`=_DefaultInk, [^`:`:Color^ Color]_[@3 doxor]_`=_Null)&] +[s2; Draws a single polyline connecting all [/ vertices].&] +[s4; [*C@3 vertices]-|polyline vertices&] +[s4; [*C@3 width]-|pen width / dash style&] +[s4; [*C@3 color]-|polyline color&] +[s4; [*C@3 doxor]-|background value for xor`'ed drawing ([/ Null] `= draw +normally)&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawPolyPolyPolygon]([@(0.0.255) const]_[^`:`:Point^ Point]_`*[@3 v +ertices], [@(0.0.255) int]_[@3 vertex`_count], [@(0.0.255) const]_[@(0.0.255) int]_`*[@3 su +bpolygon`_counts], [@(0.0.255) int]_[@3 subpolygon`_count`_count], +[@(0.0.255) const]_[@(0.0.255) int]_`*[@3 disjunct`_polygon`_counts], +[@(0.0.255) int]_[@3 disjunct`_polygon`_count`_count], [^`:`:Color^ Color]_[@3 color]_`=_ +DefaultInk, [@(0.0.255) int]_[@3 width]_`=_[@3 0], [^`:`:Color^ Color]_[@3 outline]_`=_Null +, [^`:`:Image^ Image]_[@3 image]_`=_Null, [^`:`:Color^ Color]_[@3 doxor]_`=_Null)&] +[s2; Draws a series of complex polygons (i.e. polygons which may +contain holes). The [/ vertices] array holds all polygon defining +vertices. The array is divided into sections corresponding to +the whole complex polygons (parameters [/ disjunct`_polygon`_counts] +and [/ disjunct`_polygon`_count`_count]) and these sections are +further divided into the individual polygons defining one complex +polygon (i.e. outer boundary and holes). Numbers of vertices +in the individual polygons are held in the array [/ subpolygon`_counts] +(total number of simple polygons `= [/ subpolygon`_count`_count]).&] +[s4; [*C@3 vertices]-|all polygon vertices&] +[s4; [*C@3 vertex`_count]-|number of polygon vertices&] +[s4; [*C@3 subpolygon`_counts]-|vertex counts in individual simple polygons&] +[s4; [*C@3 subpolygon`_count`_count]-|number of entries in [/ subpolygon`_counts]&] +[s4; [*C@3 disjunct`_polygon`_counts]-|vertex counts of the whole complex +polygons&] +[s4; [*C@3 disjunct`_polygon`_count`_count]-|number of [/ disjunct`_polygon`_counts]&] +[s4; [*C@3 color]-|polygon fill color ([/ Null] `= no fill)&] +[s4; [*C@3 width]-|pen width / dash style to draw polygon boundary with&] +[s4; [*C@3 outline]-|pen color for drawing polygon boundary ([/ Null] +`= no boundary)&] +[s4; [*C@3 image]-|pattern for filling polygon interior. Due to Win32 +GDI limitations [/ image] must be 8 pixels wide and high.&] +[s4; [*C@3 doxor]-|Background color for xor`'ed drawing.&] +[s0; &] +[s0; Drawing raster primitives&] +[s0; &] +[s5;K:`:`:Draw`:`:DrawImage`(int`,int`,int`,int`,const`:`:Image`&`,const`:`:Rect`&`):%- [@(0.0.255) v +oid]_[@0 DrawImage]([@(0.0.255) int]_[@3 x], [@(0.0.255) int]_[@3 y], [@(0.0.255) int]_[@3 cx], + [@(0.0.255) int]_[@3 cy], [@(0.0.255) const]_[^`:`:Image^ Image]`&_[@3 img], +[@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 src])&] +[s5;K:`:`:Draw`:`:DrawImage`(int`,int`,int`,int`,const`:`:Image`&`):%- [@(0.0.255) void +]_[@0 DrawImage]([@(0.0.255) int]_[@3 x], [@(0.0.255) int]_[@3 y], [@(0.0.255) int]_[@3 cx], +[@(0.0.255) int]_[@3 cy], [@(0.0.255) const]_[^`:`:Image^ Image]`&_[@3 img])&] +[s5;K:`:`:Draw`:`:DrawImage`(int`,int`,int`,int`,const`:`:Image`&`,const`:`:Rect`&`,`:`:Color`):%- [@(0.0.255) v +oid]_[@0 DrawImage]([@(0.0.255) int]_[@3 x], [@(0.0.255) int]_[@3 y], [@(0.0.255) int]_[@3 cx], + [@(0.0.255) int]_[@3 cy], [@(0.0.255) const]_[^`:`:Image^ Image]`&_[@3 img], +[@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 src], [^`:`:Color^ Color]_[@3 color])&] +[s5;K:`:`:Draw`:`:DrawImage`(int`,int`,int`,int`,const`:`:Image`&`,`:`:Color`):%- [@(0.0.255) v +oid]_[@0 DrawImage]([@(0.0.255) int]_[@3 x], [@(0.0.255) int]_[@3 y], [@(0.0.255) int]_[@3 cx], + [@(0.0.255) int]_[@3 cy], [@(0.0.255) const]_[^`:`:Image^ Image]`&_[@3 img], +[^`:`:Color^ Color]_[@3 color])&] +[s5;K:`:`:Draw`:`:DrawImage`(const`:`:Rect`&`,const`:`:Image`&`,const`:`:Rect`&`):%- [@(0.0.255) v +oid]_[@0 DrawImage]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 r], [@(0.0.255) const]_[^`:`:Image^ I +mage]`&_[@3 img], [@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 src])&] +[s5;K:`:`:Draw`:`:DrawImage`(const`:`:Rect`&`,const`:`:Image`&`):%- [@(0.0.255) void]_[@0 D +rawImage]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 r], [@(0.0.255) const]_[^`:`:Image^ Im +age]`&_[@3 img])&] +[s5;K:`:`:Draw`:`:DrawImage`(const`:`:Rect`&`,const`:`:Image`&`,const`:`:Rect`&`,`:`:Color`):%- [@(0.0.255) v +oid]_[@0 DrawImage]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 r], [@(0.0.255) const]_[^`:`:Image^ I +mage]`&_[@3 img], [@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 src], [^`:`:Color^ Color]_[@3 co +lor])&] +[s5;K:`:`:Draw`:`:DrawImage`(const`:`:Rect`&`,const`:`:Image`&`,`:`:Color`):%- [@(0.0.255) v +oid]_[@0 DrawImage]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 r], [@(0.0.255) const]_[^`:`:Image^ I +mage]`&_[@3 img], [^`:`:Color^ Color]_[@3 color])&] +[s5;K:`:`:Draw`:`:DrawImage`(int`,int`,const`:`:Image`&`,const`:`:Rect`&`):%- [@(0.0.255) v +oid]_[@0 DrawImage]([@(0.0.255) int]_[@3 x], [@(0.0.255) int]_[@3 y], [@(0.0.255) const]_[^`:`:Image^ I +mage]`&_[@3 img], [@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 src])&] +[s5;K:`:`:Draw`:`:DrawImage`(int`,int`,const`:`:Image`&`):%- [@(0.0.255) void]_[@0 DrawIm +age]([@(0.0.255) int]_[@3 x], [@(0.0.255) int]_[@3 y], [@(0.0.255) const]_[^`:`:Image^ Image]`& +_[@3 img])&] +[s5;K:`:`:Draw`:`:DrawImage`(int`,int`,const`:`:Image`&`,const`:`:Rect`&`,`:`:Color`):%- [@(0.0.255) v +oid]_[@0 DrawImage]([@(0.0.255) int]_[@3 x], [@(0.0.255) int]_[@3 y], [@(0.0.255) const]_[^`:`:Image^ I +mage]`&_[@3 img], [@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 src], [^`:`:Color^ Color]_[@3 co +lor])&] +[s5;K:`:`:Draw`:`:DrawImage`(int`,int`,const`:`:Image`&`,`:`:Color`):%- [@(0.0.255) voi +d]_[@0 DrawImage]([@(0.0.255) int]_[@3 x], [@(0.0.255) int]_[@3 y], [@(0.0.255) const]_[^`:`:Image^ I +mage]`&_[@3 img], [^`:`:Color^ Color]_[@3 color])&] +[s2; Draws an Image at specified position. If the position specifies +dimension ([%-*@3 cx][%-@(64) , ][%-*@3 cy] or is defined using Rect +[%-@3 r], Image is rescaled. If [%-*@3 color] is provided, only Image +alpha channel is used and painted with the specified color. [%-*@3 src] +can be used specify only a portion of the source Image to be +painted.&] +[s0;:`:`:Draw`:`:DrawImage`(const`:`:Rect`&`,const`:`:Image`&`,const`:`:Rect`&`,int`): +&] +[s0;3 &] +[s0;:`:`:Draw`:`:GetTextSize`(const`:`:wchar`*`,`:`:Font: Size_[* GetTextSize](const_wc +har_`*[*@3 text], Font_[*@3 font]_`=_StdFont(), int_[*@3 n]_`=_`-[@3 1])&] +[s2; Measures width and height of a Unicode text (as when painted +using given font).&] +[s4; [*C@3 text]-|Unicode text to measure&] +[s4; [*C@3 font]-|font to use for the metrics measurements&] +[s4; [*C@3 n]-|number of letters in the array [/ text]. When [/ n < 0], +[/ text] length is counted using [/ wcslen].&] +[s4; [*/ Return value]-|[/ cx `=] output text pixel width[/ , cy `= ]line +height of given font&] +[s0;3 &] +[s0;:`:`:Draw`:`:DrawText`(int`,int`,int`,const`:`:wchar`*`,`:`:Font: void_[* DrawText]( +int_[*@3 x], int_[*@3 y], int_[*@3 angle], const_wchar_`*[*@3 text], +Font_[*@3 font]_`=_StdFont(), Color_[*@3 ink]_`=_SBlack, int_[*@3 n]_`=_`-[@3 1], +const_int_`*[*@3 dx]_`=_NULL)&] +[s2; Draws text on the output device.&] +[s2; [* Note:] when working with rotated texts, always remember that +[/ `[x, y`]] define the topleft corner of the text box. Box size +is that returned by the function [/ GetTextSize]. In case of rotated +texts, the text box is naturally not aligned with the coordinate +axes. Also, some system fonts do not support rotation (bitmap +fonts). Unfortunately there is currently no reliable way to detect +if a font supports rotation. FontInfo`::IsScaleable should provide +a good guess as to whether a given font supports rotation.&] +[s4; [*C@3 x]-|x coordinate of the topleft corner of the text box&] +[s4; [*C@3 y]-|y coordinate of the topleft corner of the text box&] +[s4; [*C@3 angle]-|angle for the text in tenths of degrees (full circle +`= 3600). 0 `= to the right (normal text orientation), 900 `= +upwards, 1800 `= head down left, 2700 downwards. &] +[s4; [*C@3 text]-|Unicode text to draw&] +[s4; [*C@3 font]-|font to use for drawing text&] +[s4; [*C@3 ink]-|text color; the text is always drawn as transparent. +To set the background under the text to a given color, you must +first measure the text size using [/ GetTextSize] and then call +[/ DrawRect] to set the text box to a given color. When using rotated +text ([/ angle !`= 0]) the situation is naturally much more complicated +and a [/ DrawPolygon] would be needed to clear the rotated text +box.&] +[s4; [*C@3 n]-|number of letters in the array [/ text]. When [/ n < 0], +[/ text] length is counted using [/ wcslen].&] +[s4; [*C@3 dx]-|array of letter widths. This can be used to set explicit +spacings for the individual letters in the text. When NULL, default +letters widths are used. When not NULL, it must contain (at least) +as many entries as are being painted from the given [/ text].&] +[s0;3 &] +[s0;:`:`:Draw`:`:DrawText`(int`,int`,const`:`:wchar`*`,`:`:Font: void_[* DrawText](int_ +[*@3 x], int_[*@3 y], const_wchar_`*[*@3 text], Font_[*@3 font]_`=_StdFont(), +Color_[*@3 ink]_`=_SBlack, int_[*@3 n]_`=_`-[@3 1], const_int_`*[*@3 dx]_`=_NULL)&] +[s2; Draws text on the output device. This is a simplified version +of the above function for the most common case when [/ angle `=`= +0] (i.e. the text is being painted in the ordinary direction +from left to right).&] +[s4; [*C@3 x]-|x coordinate of the topleft corner of the text box&] +[s4; [*C@3 y]-|y coordinate of the topleft corner of the text box&] +[s4; [*C@3 text]-|Unicode text to draw&] +[s4; [*C@3 font]-|font to use for drawing text&] +[s4; [*C@3 ink]-|text color; the text is always drawn as transparent. +To set the background under the text to a given color, you must +first measure the text size using [/ GetTextSize] and then call +[/ DrawRect] to set the text box to a given color.&] +[s4; [*C@3 n]-|number of letters in the array [/ text]. When [/ n < 0], +[/ text] length is counted using [/ wcslen].&] +[s4; [*C@3 dx]-|array of letter widths. This can be used to set explicit +spacings for the individual letters in the text. When NULL, default +letters widths are used. When not NULL, it must contain (at least) +as many entries as are being painted from the given [/ text].&] +[s0;3 &] +[s0;:`:`:Draw`:`:GetTextSize`(const`:`:WString`&`,`:`:Font: Size_[* GetTextSize](const_ +WString`&_[*@3 text], Font_[*@3 font]_`=_StdFont())&] +[s2; Measures width and height of a Unicode text (as when painted +using given font).&] +[s4; [*C@3 text]-|text string to measure&] +[s4; [*C@3 font]-|font to use for metrics measurements&] +[s4; [*/ Return value]-|[/ cx `= ]text box width, [/ cy `= ] text box height +(font ascent `+ descent).&] +[s0;3 &] +[s0;:`:`:Draw`:`:DrawText`(int`,int`,const`:`:WString`&`,`:`:Font: void_[* DrawText](in +t_[*@3 x], int_[*@3 y], const_WString`&_[*@3 text], Font_[*@3 font]_`=_StdFont(), +Color_[*@3 ink]_`=_SBlack, const_int_`*[*@3 dx]_`=_NULL)&] +[s2; Draws text on the output device (from left to right). This is +a variation of one of the above function for the case when the +input parameter is a WString. In such situation the number of +letters is known ([/ text.GetLength()]) and doesn`'t (indeed shoudn`'t) +be measured using [/ wcslen].&] +[s4; [*C@3 x]-|x coordinate of the topleft corner of the text box&] +[s4; [*C@3 y]-|y coordinate of the topleft corner of the text box&] +[s4; [*C@3 text]-|Unicode text to draw&] +[s4; [*C@3 font]-|font to use for drawing text&] +[s4; [*C@3 ink]-|text color; the text is always drawn as transparent.&] +[s4; [*C@3 dx]-|array of letter widths. This can be used to set explicit +spacings for the individual letters in the text. When NULL, default +letters widths are used. When not NULL, it must contain (at least) +as many entries as are being painted from the given [/ text].&] +[s0;3 &] +[s0;:`:`:Draw`:`:DrawText`(int`,int`,int`,const`:`:WString`&`,`:`:Font: void_[* DrawTex +t](int_[*@3 x], int_[*@3 y], int_[*@3 angle], const_WString`&_[*@3 text], +Font_[*@3 font]_`=_StdFont(), Color_[*@3 ink]_`=_SBlack, const_int_`*[*@3 dx]_`=_NULL)&] +[s2; Draws text on the output device. A variation of the above function +allowing text rotation. See above notes concerning text rotation +issues.&] +[s4; [*C@3 x]-|x coordinate of the topleft corner of the text box&] +[s4; [*C@3 y]-|y coordinate of the topleft corner of the text box&] +[s4; [*C@3 angle]-|angle for the text in tenths of degrees (full circle +`= 3600). 0 `= to the right (normal text orientation), 900 `= +upwards, 1800 `= head down left, 2700 downwards. &] +[s4; [*C@3 text]-|Unicode text to draw&] +[s4; [*C@3 font]-|font to use for drawing text&] +[s4; [*C@3 ink]-|text color; the text is always drawn as transparent.&] +[s4; [*C@3 dx]-|array of letter widths. This can be used to set explicit +spacings for the individual letters in the text. When NULL, default +letters widths are used. When not NULL, it must contain (at least) +as many entries as are being painted from the given [/ text].&] +[s0;3 &] +[s0;:`:`:Draw`:`:GetTextSize`(const char`*`,`:`:byte`,`:`:Font: Size_[* GetTextSize](co +nst_char_`*[*@3 text], byte_[*@3 charset], Font_[*@3 font]_`=_StdFont(), +int_[*@3 n]_`=_`-[@3 1])&] +[s2; Measures text box size for text in given character set.&] +[s4; [*C@3 text]-|text to measure&] +[s4; [*C@3 charset]-|text character set&] +[s4; [*C@3 font]-|font to use for the metrics measurements&] +[s4; [*C@3 n]-|number of letters in [/ text]. When [/ n < 0], [/ text] length +is counted using [/ strlen] (or [/ utf8len], when [/ charset `=`= CHARSET`_UTF8]).&] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s0;:`:`:Draw`:`:DrawText`(int`,int`,int`,const char`*`,`:`:byte`,`:`:Font: void_[* Dra +wText](int_[*@3 x], int_[*@3 y], int_[*@3 angle], const_char_`*[*@3 text], +byte_[*@3 charset], Font_[*@3 font]_`=_StdFont(), Color_[*@3 ink]_`=_SBlack, +int_[*@3 n]_`=_`-[@3 1], const_int_`*[*@3 dx]_`=_NULL)&] +[s2; Draw given text in a given character set to the ouput device. +This variant allows text rotation.&] +[s4; [*C@3 x]-|x coordinate of the topleft corner of the text box&] +[s4; [*C@3 y]-|y coordinate of the topleft corner of the text box&] +[s4; [*C@3 angle]-|angle for the text in tenths of degrees (full circle +`= 3600). 0 `= to the right (normal text orientation), 900 `= +upwards, 1800 `= head down left, 2700 downwards. &] +[s4; [*C@3 text]-|text to draw&] +[s4; [*C@3 charset]-|output text character set (from the CHARSET`_xxx +enumeration)&] +[s4; [*C@3 font]-|font to use for drawing text&] +[s4; [*C@3 ink]-|text color; the text is always drawn as transparent.&] +[s4; [*C@3 n]-|number of letters in [/ text]. When [/ n < 0], [/ text] length +is counted using [/ strlen].&] +[s4; [*C@3 dx]-|array of letter widths. This can be used to set explicit +spacings for the individual letters in the text. When NULL, default +letters widths are used. When not NULL, it must contain (at least) +as many entries as are being painted from the given [/ text].&] +[s0;3 &] +[s0;:`:`:Draw`:`:DrawText`(int`,int`,const char`*`,`:`:byte`,`:`:Font: void_[* DrawText +](int_[*@3 x], int_[*@3 y], const_char_`*[*@3 text], byte_[*@3 charset], +Font_[*@3 font]_`=_StdFont(), Color_[*@3 ink]_`=_SBlack, int_[*@3 n]_`=_`-[@3 1], +const_int_`*[*@3 dx]_`=_NULL)&] +[s2; Draws text in given character set to the output device (from +left to right).&] +[s4; [*C@3 x]-|x coordinate of the topleft corner of the text box&] +[s4; [*C@3 y]-|y coordinate of the topleft corner of the text box&] +[s4; [*C@3 text]-|text to draw&] +[s4; [*C@3 charset]-|output text character set (from the CHARSET`_xxx +enumeration)&] +[s4; [*C@3 font]-|font to use for drawing text&] +[s4; [*C@3 ink]-|text color; the text is always drawn as transparent.&] +[s4; [*C@3 n]-|number of letters in [/ text]. When [/ n < 0], [/ text] length +is counted using [/ strlen] (or [/ utf8len], when [/ charset `=`= CHARSET`_UTF8]).&] +[s4; [*C@3 dx]-|array of letter widths. This can be used to set explicit +spacings for the individual letters in the text. When NULL, default +letters widths are used. When not NULL, it must contain (at least) +as many entries as are being painted from the given [/ text].&] +[s0;3 &] +[s0;:`:`:Draw`:`:GetTextSize`(const char`*`,`:`:Font: Size_[* GetTextSize](const_char_`* +[*@3 text], Font_[*@3 font]_`=_StdFont(), int_[*@3 n]_`=_`-[@3 1])&] +[s2; Measures text box size for a text encoded in system`-default +character set. &] +[s4; [*C@3 text]-|text to measure (in default character set, CHARSET`_DEFAULT)&] +[s4; [*C@3 font]-|font to use for the metrics measurements&] +[s4; [*C@3 n]-|number of letters in [/ text]. When [/ n < 0], [/ text] length +is counted using [/ strlen] (or [/ utf8len], when the default charset +is [/ CHARSET`_UTF8]).&] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s0;:`:`:Draw`:`:DrawText`(int`,int`,int`,const char`*`,`:`:Font: void_[* DrawText](int +_[*@3 x], int_[*@3 y], int_[*@3 angle], const_char_`*[*@3 text], Font_[*@3 font]_`=_StdFont +(), Color_[*@3 ink]_`=_SBlack, int_[*@3 n]_`=_`-[@3 1], const_int_`*[*@3 dx]_`=_NULL)&] +[s2; Draws text encoded in system`-default character set on the output +device. This variant allows text rotation.&] +[s4; [*C@3 x]-|x coordinate of the topleft corner of the text box&] +[s4; [*C@3 y]-|y coordinate of the topleft corner of the text box&] +[s4; [*C@3 angle]-|angle for the text in tenths of degrees (full circle +`= 3600). 0 `= to the right (normal text orientation), 900 `= +upwards, 1800 `= head down left, 2700 downwards. &] +[s4; [*C@3 text]-|text to draw (in default character set, CHARSET`_DEFAULT)&] +[s4; [*C@3 font]-|font to use for drawing text&] +[s4; [*C@3 ink]-|text color; the text is always drawn as transparent.&] +[s4; [*C@3 n]-|number of letters in [/ text]. When [/ n < 0], [/ text] length +is counted using [/ strlen] (or [/ utf8len], when the default character +set is [/ CHARSET`_UTF8]).&] +[s4; [*C@3 dx]-|array of letter widths. This can be used to set explicit +spacings for the individual letters in the text. When NULL, default +letters widths are used. When not NULL, it must contain (at least) +as many entries as are being painted from the given [/ text].&] +[s0;3 &] +[s0;:`:`:Draw`:`:DrawText`(int`,int`,const char`*`,`:`:Font: void_[* DrawText](int_[*@3 x +], int_[*@3 y], const_char_`*[*@3 text], Font_[*@3 font]_`=_StdFont(), +Color_[*@3 ink]_`=_SBlack, int_[*@3 n]_`=_`-[@3 1], const_int_`*[*@3 dx]_`=_NULL)&] +[s2; Draws text encoded in system`-default character set on the output +device (from left to right).&] +[s4; [*C@3 x]-|x coordinate of the topleft corner of the text box&] +[s4; [*C@3 y]-|y coordinate of the topleft corner of the text box&] +[s4; [*C@3 text]-|text to draw (in default character set, CHARSET`_DEFAULT)&] +[s4; [*C@3 font]-|font to use for drawing text&] +[s4; [*C@3 ink]-|text color; the text is always drawn as transparent.&] +[s4; [*C@3 n]-|number of letters in [/ text]. When [/ n < 0], [/ text] length +is counted using [/ strlen] (or [/ utf8len], when the default character +set is [/ CHARSET`_UTF8]).&] +[s4; [*C@3 dx]-|array of letter widths. This can be used to set explicit +spacings for the individual letters in the text. When NULL, default +letters widths are used. When not NULL, it must contain (at least) +as many entries as are being painted from the given [/ text].&] +[s0;3 &] +[s0;:`:`:Draw`:`:GetTextSize`(const`:`:String`&`,`:`:Font: Size_[* GetTextSize](const_S +tring`&_[*@3 text], Font_[*@3 font]_`=_StdFont())&] +[s2; Measures text size (default character set). This is a variant +of the above function for the case when [/ text] i a [/ String] when +the text length is known ([/ text.GetLength()]) and it needn`'t +and shouldn`'t be measured using [/ strlen]. However, when the +current system`-default character set it CHARSET`_UTF8, the text +length must still be measured using [/ utf8len] because the number +of UTF8 letters can differ from the number of bytes in the string.&] +[s4; [*C@3 text]-|text to measure (in default character set, CHARSET`_DEFAULT)&] +[s4; [*C@3 font]-|font to use for the metrics measurements&] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s0;:`:`:Draw`:`:DrawText`(int`,int`,const`:`:String`&`,`:`:Font: void_[* DrawText](int +_[*@3 x], int_[*@3 y], const_String`&_[*@3 text], Font_[*@3 font]_`=_StdFont(), +Color_[*@3 ink]_`=_SBlack, const_int_`*[*@3 dx]_`=_NULL)&] +[s2; Draws text encoded in system`-default character set on the output +device (from left to right).&] +[s4; [*C@3 x]-|x coordinate of the topleft corner of the text box&] +[s4; [*C@3 y]-|y coordinate of the topleft corner of the text box&] +[s4; [*C@3 text]-|text to draw (in default character set, CHARSET`_DEFAULT)&] +[s4; [*C@3 font]-|font to use for drawing text&] +[s4; [*C@3 ink]-|text color; the text is always drawn as transparent.&] +[s4; [*C@3 dx]-|array of letter widths. This can be used to set explicit +spacings for the individual letters in the text. When NULL, default +letters widths are used. When not NULL, it must contain (at least) +as many entries as are being painted from the given [/ text].&] +[s0;3 &] +[s0;:`:`:Draw`:`:DrawText`(int`,int`,int`,const`:`:String`&`,`:`:Font: void_[* DrawText +](int_[*@3 x], int_[*@3 y], int_[*@3 angle], const_String`&_[*@3 text], +Font_[*@3 font]_`=_StdFont(), Color_[*@3 ink]_`=_SBlack, const_int_`*[*@3 dx]_`=_NULL)&] +[s2; Draws text encoded in system`-default character set on the output +device. This variant supports text rotation. See above for notes +concerning text rotation issues.&] +[s4; [*C@3 x]-|x coordinate of the topleft corner of the text box&] +[s4; [*C@3 y]-|y coordinate of the topleft corner of the text box&] +[s4; [*C@3 angle]-|angle for the text in tenths of degrees (full circle +`= 3600). 0 `= to the right (normal text orientation), 900 `= +upwards, 1800 `= head down left, 2700 downwards. &] +[s4; [*C@3 text]-|text to draw&] +[s4; [*C@3 font]-|font to use for drawing text&] +[s4; [*C@3 ink]-|text color; the text is always drawn as transparent.&] +[s4; [*C@3 dx]-|array of letter widths. This can be used to set explicit +spacings for the individual letters in the text. When NULL, default +letters widths are used. When not NULL, it must contain (at least) +as many entries as are being painted from the given [/ text].&] +[s0;3 &] +[s5;K%- static [@(0.0.255) void]_[@0 SinCos]([@(0.0.255) int]_[@3 angle], +[@(0.0.255) double]`&_[@3 sina], [@(0.0.255) double]`&_[@3 cosa])&] +[s2; A simple utility function which calculates the sine and cosine +of given angle (in tenths of degrees). This function is used +internally to calculate metrics of rotated text. &] +[s4; [*C@3 angle]-|angle in tenths of degrees. 0 `= right, 900 `= up, +1800 `= left, 2700 `= down.&] +[s4; [*C@3 sina]-|sine of the angle, or [/ sin(angle `* 2 `* M`_PI / 3600)]&] +[s4; [*C@3 cosa]-|cosine of the angle, or [/ cos(angle `* 2 `* M`_PI / +3600)]&] +[s0; &] +[s0; Accessing [/ Drawing]`-specific functions&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawDrawing]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 r], +[@(0.0.255) const]_[^`:`:Drawing^ Drawing]`&_[@3 iw])&] +[s2; Draws drawing scaled into given rectangle. The coordinate transform +equations are&] +[s2; &] +[s2; x[, out]`=x[, dwg] `* r.Width() / iw.GetSize().cx `+ r.left&] +[s2; y[, out]`=y[, dwg] `* r.Height() / iw.GetSize().cy `+ r.top&] +[s2; &] +[s4; [*C@3 r]-|destination rectangle in logical device units&] +[s4; [*C@3 iw]-|drawing object to draw&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawDrawing]([@(0.0.255) int]_[@3 x], [@(0.0.255) int]_[@3 y], +[@(0.0.255) int]_[@3 cx], [@(0.0.255) int]_[@3 cy], [@(0.0.255) const]_[^`:`:Drawing^ Drawing +]`&_[@3 iw])&] +[s2; Draws drawing scaled into rectangle [* cx] `* [* cy] pixels starting +at `[x, y`]. The equations used to scale the drawing are&] +[s2; &] +[s2; x[, out]`=x[, dwg] `* cx / iw.GetSize().cx `+ x&] +[s2; y[, out]`=y[, dwg] `* cy / iw.GetSize().cy `+ y&] +[s2; &] +[s4; [*C@3 x]-|left edge of output rectangle&] +[s4; [*C@3 y]-|top edge of output rectangle&] +[s4; [*C@3 cx]-|rectangle width&] +[s4; [*C@3 cy]-|rectangle height&] +[s4; [*C@3 iw]-|drawing to draw at the specified location&] +[s0;3 &] +[s5;K%- [^`:`:Stream^ Stream]`&_[@0 DrawingOp]([@(0.0.255) int]_[@3 code])&] +[s2; &] +[s4; [*C@3 code]-|&] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s5;K%- [^`:`:Stream^ Stream]`&_[@0 PutRect]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 r])&] +[s2; &] +[s4; [*C@3 r]-|&] +[s4; [*/ Return value]-|&] +[s0; &] +[s0; Accessing unified virtual output interface&] +[s0;3 &] +[s5;K%- virtual [@(0.0.255) void]_[@0 BeginOp]()&] +[s2; &] +[s0;3 &] +[s5;K%- virtual [@(0.0.255) void]_[@0 EndOp]()&] +[s2; &] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 OffsetOp]([^`:`:Point^ Point]_[@3 p])&] +[s2; &] +[s4; [*C@3 p]-|&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 ClipOp]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 r])&] +[s2; &] +[s4; [*C@3 r]-|&] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 ClipoffOp]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 r])&] +[s2; &] +[s4; [*C@3 r]-|&] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 ExcludeClipOp]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 r])&] +[s2; &] +[s4; [*C@3 r]-|&] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 IntersectClipOp]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 r])&] +[s2; &] +[s4; [*C@3 r]-|&] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s5;K%- virtual [^`:`:Rect^ Rect]_[@0 GetClipOp]()_[@(0.0.255) const]&] +[s2; &] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawRectOp]([@(0.0.255) int]_[@3 x], [@(0.0.255) int]_[@3 y], +[@(0.0.255) int]_[@3 cx], [@(0.0.255) int]_[@3 cy], [^`:`:Color^ Color]_[@3 color])&] +[s2; &] +[s4; [*C@3 x]-|&] +[s4; [*C@3 y]-|&] +[s4; [*C@3 cx]-|&] +[s4; [*C@3 cy]-|&] +[s4; [*C@3 color]-|&] +[s0;3 &] +[s0;:`:`:Draw`:`:DrawImageOp`(const`:`:Rect`&`,const`:`:Image`&`,const`:`:Rect`&`,int`): v +irtual void_[* DrawImageOp](const_Rect`&_[*@3 rect], const_Image`&_[*@3 img], +const_Rect`&_[*@3 src], int_[*@3 fx])&] +[s2; &] +[s4; [*C@3 rect]-|&] +[s4; [*C@3 img]-|&] +[s4; [*C@3 src]-|&] +[s4; [*C@3 fx]-|&] +[s0;3 &] +[s0;:`:`:Draw`:`:DrawImageOp`(const`:`:Rect`&`,const`:`:Image`&`,const`:`:Rect`&`,`:`:Color`,`:`:Color`,`:`:Color`): v +irtual void_[* DrawImageOp](const_Rect`&_[*@3 rect], const_Image`&_[*@3 img], +const_Rect`&_[*@3 src], Color_[*@3 fore], Color_[*@3 back], Color_[*@3 doxor])&] +[s2; &] +[s4; [*C@3 rect]-|&] +[s4; [*C@3 img]-|&] +[s4; [*C@3 src]-|&] +[s4; [*C@3 fore]-|&] +[s4; [*C@3 back]-|&] +[s4; [*C@3 doxor]-|&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawLineOp]([@(0.0.255) int]_[@3 x1], [@(0.0.255) int]_[@3 y1], +[@(0.0.255) int]_[@3 x2], [@(0.0.255) int]_[@3 y2], [@(0.0.255) int]_[@3 width], +[^`:`:Color^ Color]_[@3 color])&] +[s2; &] +[s4; [*C@3 x1]-|&] +[s4; [*C@3 y1]-|&] +[s4; [*C@3 x2]-|&] +[s4; [*C@3 y2]-|&] +[s4; [*C@3 width]-|&] +[s4; [*C@3 color]-|&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawPolyPolylineOp]([@(0.0.255) const]_[^`:`:Point^ Point]_`*[@3 v +ertices], [@(0.0.255) int]_[@3 vertex`_count], [@(0.0.255) const]_[@(0.0.255) int]_`*[@3 co +unts], [@(0.0.255) int]_[@3 count`_count], [@(0.0.255) int]_[@3 width], +[^`:`:Color^ Color]_[@3 color], [^`:`:Color^ Color]_[@3 doxor])&] +[s2; &] +[s4; [*C@3 vertices]-|&] +[s4; [*C@3 vertex`_count]-|&] +[s4; [*C@3 counts]-|&] +[s4; [*C@3 count`_count]-|&] +[s4; [*C@3 width]-|&] +[s4; [*C@3 color]-|&] +[s4; [*C@3 doxor]-|&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawEllipseOp]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 r], +[^`:`:Color^ Color]_[@3 color], [@(0.0.255) int]_[@3 width], [^`:`:Color^ Color]_[@3 pencolor +])&] +[s2; &] +[s4; [*C@3 r]-|&] +[s4; [*C@3 color]-|&] +[s4; [*C@3 pen]-|&] +[s4; [*C@3 pencolor]-|&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 DrawArcOp]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 rc], +[^`:`:Point^ Point]_[@3 start], [^`:`:Point^ Point]_[@3 end], [@(0.0.255) int]_[@3 width], +[^`:`:Color^ Color]_[@3 color])&] +[s2; &] +[s4; [*C@3 rc]-|&] +[s4; [*C@3 start]-|&] +[s4; [*C@3 end]-|&] +[s4; [*C@3 width]-|&] +[s4; [*C@3 color]-|&] +[s0;3 &] +[s5;K%- virtual [@(0.0.255) void]_[@0 DrawTextOp]([@(0.0.255) int]_[@3 x], +[@(0.0.255) int]_[@3 y], [@(0.0.255) int]_[@3 angle], [@(0.0.255) const]_[^`:`:wchar^ wchar]_ +`*[@3 text], [^`:`:Font^ Font]_[@3 font], [^`:`:Color^ Color]_[@3 ink], +[@(0.0.255) int]_[@3 n], [@(0.0.255) const]_[@(0.0.255) int]_`*[@3 dx])&] +[s2; &] +[s4; [*C@3 x]-|&] +[s4; [*C@3 y]-|&] +[s4; [*C@3 angle]-|&] +[s4; [*C@3 text]-|&] +[s4; [*C@3 font]-|&] +[s4; [*C@3 ink]-|text color&] +[s4; [*C@3 n]-|number of letters in [/ text]. When [/ n < 0], [/ text] length +is counted using [/ wcslen].&] +[s4; [*C@3 dx]-|array of letter widths. This can be used to set explicit +spacings for the individual letters in the text. When NULL, default +letters widths are used. When not NULL, it must contain (at least) +as many entries as are being painted from the given [/ text].&] +[s0;3 &] +[s5;K%- virtual [@(0.0.255) void]_[@0 DrawDrawingOp]([@(0.0.255) const]_[^`:`:Rect^ Rect]`&_[@3 t +arget], [@(0.0.255) const]_[^`:`:Drawing^ Drawing]`&_[@3 w])&] +[s2; &] +[s4; [*C@3 target]-|&] +[s4; [*C@3 w]-|&] +[s0; &] +[s0; Accessing the underlying physical output device interface&] +[s0;3 &] +[s5;K%- [^COLORREF^ COLORREF]_[@0 GetColor]([^`:`:Color^ Color]_[@3 c])_[@(0.0.255) const]&] +[s2; &] +[s4; [*C@3 color]-|&] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 SetColor]([^`:`:Color^ Color]_[@3 color])&] +[s2; &] +[s4; [*C@3 color]-|&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 SetDrawPen]([@(0.0.255) int]_[@3 width], [^`:`:Color^ Color]_[@3 co +lor])&] +[s2; &] +[s4; [*C@3 width]-|&] +[s4; [*C@3 color]-|&] +[s0;3 &] +[s5;K%- [^HDC^ HDC]_[@0 BeginGdi]()&] +[s2; &] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 EndGdi]()&] +[s2; &] +[s0;3 &] +[s5;K%- [^HDC^ HDC]_[@0 GetHandle]()&] +[s2; &] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s5;K%- operator_HDC()_[@(0.0.255) const]&] +[s2; [* Win32`-specific:] retrieves the device context handle for the +output device (in Win32, device context handles are used to paint +into windows, images, printer and Windows metafile). When the +device doesn`'t correspond to a Windows context handle (e.g. +for DrawingDraw, PdfDraw and the like), the function returns +NULL.&] +[s4; [*/ Return value]-|handle of device context (NULL `= not available +or applicable)&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 Unselect]()&] +[s2; [* Win32`-specific:] restores all drawing objects originally selected +in the Windows device context. When drawing using different line +and filll styles, the Draw object internally modifies the state +automaton of the device context to allocate the necessary brushes +and pens. This functions unselects all objects created internally +by Draw during painting and restores the objects originally selected +into the context. This is sometimes necessary when you need to +access and manipulate the device context manually using specific +Windows API calls.&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 Attach]([^HDC^ HDC]_[@3 ahandle])&] +[s2; [* Win32`-specific:] attaches the Draw object to a given Windows +device handle. The function stores the given handle and performs +certain initializations (like determining the color model and +other characteristics of the output device). This is normally +used only internally by objects deriving from the Draw object +to perform specific drawing tasks (see ImageDraw and PrintDraw).&] +[s4; [*C@3 ahandle]-|windows device context handle to connect to the +Draw object&] +[s0;3 &] +[s5;K%- [^HDC^ HDC]_[@0 Detach]()&] +[s2; [* Win32`-specific:] detaches the Windows device context handle +from the Draw object. The function unselects all device objects +selected previously by the internal implementation of the drawing +operations. After calling this function the device context handle +is freed from the Draw and can be used to perform Win32`-specific +drawing tasks.&] +[s4; [*/ Return value]-|The Windows device context being detached&] +[s0;3 &] +[s5;K%- [^`:`:Size^ Size]_[@0 GetSizeCaps]([@(0.0.255) int]_[@3 i], [@(0.0.255) int]_[@3 j])_[@(0.0.255) c +onst]&] +[s2; [* Win32`-specific:] returns a pair of Windows device context capabilities +forming an `[x, y`] pair. It is quite common for device context +characteristics to come in pairs, like HORZRES / VERTRES, PHYSICALWIDTH +/ PHYSICALHEIGHT etc. In a few such cases it is handy to have +a funcion which reads the given two capabilities (i and j) and +returns the result in the form of a Size object.&] +[s4; [*C@3 i]-|1st capability (its value is returned in Size`::cx)&] +[s4; [*C@3 j]-|2nd capability (its value is returned in Size`::cy)&] +[s4; [*/ Return value]-|Size formed from the results of call to GetDeviceCaps +for the HDC of the Draw object and the capabilities [* i] and [* j].&] +[s0;3 &] +[s5;K%- static [@(0.0.255) void]_[@0 Flush]()&] +[s2; &] +[s0;3 &] +[s0;:`:`:Draw`:`:MakeXLFD`(`:`:byte`,`:`:Font`,int`,int`): String_[* MakeXLFD](byte_[*@3 c +s], Font_[*@3 f], int_[*@3 height]_`=_Null, int_[*@3 angle]_`=_[@3 0])&] +[s2; &] +[s4; [*C@3 cs]-|&] +[s4; [*C@3 f]-|&] +[s4; [*C@3 height]-|&] +[s4; [*C@3 angle]-|&] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s5;K%- static [^XftFont^ XftFont]_`*[@0 CreateXftFont]([^`:`:Font^ Font]_[@3 f], +[@(0.0.255) int]_[@3 angle])&] +[s2; &] +[s4; [*C@3 f]-|&] +[s4; [*C@3 angle]-|&] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s5;K%- [^XftDraw^ XftDraw]_`*[@0 GetXftDraw]()_[@(0.0.255) const]&] +[s2; &] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 SetForeground]([^`:`:Color^ Color]_[@3 color])&] +[s2; &] +[s4; [*C@3 color]-|&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 SetLineStyle]([@(0.0.255) int]_[@3 width])&] +[s2; &] +[s4; [*C@3 width]-|&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 SetFont]([^`:`:Font^ Font]_[@3 font], [@(0.0.255) int]_[@3 angle])&] +[s2; &] +[s4; [*C@3 font]-|&] +[s4; [*C@3 angle]-|&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 SetClip]()&] +[s2; &] +[s0;3 &] +[s5;K%- [^Drawable^ Drawable]_[@0 GetDrawable]()_[@(0.0.255) const]&] +[s2; &] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s5;K%- [^GC^ GC]_[@0 GetGC]()_[@(0.0.255) const]&] +[s2; &] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s5;K%- [@(0.0.255) const]_[^`:`:Vector^ Vector]<[^`:`:Rect^ Rect]>`&_[@0 GetClipList]()_[@(0.0.255) c +onst]&] +[s2; &] +[s4; [*/ Return value]-|&] +[s0;3 &] +[s5;K%- [^`:`:FontInfo^ FontInfo]_[@0 GetFontInfo]([^`:`:byte^ byte]_[@3 charset], +[^`:`:Font^ Font]_[@3 font]_`=_StdFont())&] +[s2; &] +[s4; [*C@3 `_clip]-|&] +[s4; [*C@3 `_offset]-|&] +[s0; &] +[s0; Accessing device`-secific functions&] +[s0;3 &] +[s5;K%- virtual [@(0.0.255) void]_[@0 StartPage]()&] +[s2; &] +[s0;3 &] +[s5;K%- virtual [@(0.0.255) void]_[@0 EndPage]()&] +[s2; &] +[s0;3 &] +[s5;K%- static [@(0.0.255) void]_[@0 Register]([@(0.0.255) int]_[@3 code], +[^`:`:Draw`:`:Drawer^ Drawer]_[@3 drawer])&] +[s2; &] +[s4; [*C@3 code]-|&] +[s4; [*C@3 drawer]-|&] +[s0;3 &] +[s3; [3 Important derived classes]&] +[s0;3 &] +[s0;:`:`:ScreenDraw`:`:class`:`:ScreenDraw: class_[* ScreenDraw] : public +[* Draw]&] +[s0;3 &] +[s0; Used for determining screen characteristics like pixel `& physical +resolution, supported color model, and for retrieving physical +screen data. This is needed in situation when you must access +the whole screen not depending on the logical window system (e.g. +when writing an utility showing in its window a magnified part +of the screen).&] +[s0; &] +[s0;3 &] +[s5;K%- [^`:`:Draw^ Draw]`&_[@0 ScreenInfo]()&] +[s0; &] +[s0; Used for determining screen characteristics like pixel `& physical +resolution, supported color model. Instead of [* ScreenDraw], ScreenInfo +cannot be used to read physical display data, only for retrieving +device configuration information.&] +[s0; &] +[s0;3 &] +[s0;:`:`:ViewDraw`:`:class`:`:ViewDraw: class_[* ViewDraw] : public +[* Draw]&] +[s0; &] +[s0; Used to paint into a control`'s view area. This is usually needed +only in special situations (like for `"animated`" display in +drag `& drop operations), because usually the controls are repainted +automatically upon Windows request via the event loop (see [^topic`:`/`/CtrlCore`/src`/Ctrl`$en`-us`#`:`:Ctrl`:`:Paint`(Draw`&`)^ C +trl`::Paint]).&] +[s0;3 &] +[s0;:`:`:ViewDraw`:`:ViewDraw`(`:`:Ctrl`*`): [* ViewDraw](Ctrl `*[*@3 ctrl])&] +[s2; Initializes the ViewDraw object to paint into the window area +of a given Ctrl. See [^topic`:`/`/CtrlCore`/src`/Ctrl`$en`-us^ CtrlCore] +for greater detail on controls.&] +[s0; &] +[s0;3 &] +[s0;:`:`:ImageDraw`:`:class`:`:ImageDraw: class_[* ImageDraw] : public +[* Draw]&] +[s0; &] +[s0; Used to paint into images. This is needed when you generate +an image (to be later stored as a PNG, for example) using Windows +GDI functions like DrawLine, DrawText etc. You create an image +object, construct an ImageDraw using this object (and possibly +a reference Draw to specify the image color format), then perform +a series of GDI operations on the ImageDraw object. After you +Close the ImageDraw object, you can further process the Image +which now contains the object painted using the GDI output.&] +[s0; &] +[s0;3 &] +[s0;:`:`:ImageDraw`:`:ImageDraw`(`):%- [* ImageDraw]()&] +[s2; Constructs an empty ImageDraw. You can later Open the ImageDraw +with a given Image.&] +[s0;3 &] +[s0;:`:`:ImageDraw`:`:ImageDraw`(`:`:Draw`&`,`:`:Image`&`):%- [* ImageDraw](Draw`&_[*@3 d +raw], Image`&_[*@3 image])&] +[s2; Constructs an ImageDraw and Opens it for painting into the given +[* image].&] +[s4; [%-*C@3 draw]-|reference draw defining the image`'s color format.&] +[s4; [%-*C@3 image]-|image to write into&] +[s0;3 &] +[s0;:`:`:ImageDraw`:`:ImageDraw`(`:`:Image`&`):%- [* ImageDraw](Image`&_[*@3 image])&] +[s2; Constructs and ImageDraw and Opens it for painting into the +given [* image]. The image is considered to be in the color format +defined by [* ScreenDraw].&] +[s4; [%-*C@3 image]-|image to write into&] +[s0;3 &] +[s0;:`:`:ImageDraw`:`:Open`(`:`:Image`&`):%- void_[* Open](Image`&_[*@3 image])&] +[s2; Opens the ImageDraw for painting into given [* image ](assumed +to have color format compatible with ScreenDraw). If an image +was opened in the ImageDraw before, it is automatically closed.&] +[s4; [%-*C@3 image]-|image to write into&] +[s0;3 &] +[s0;:`:`:ImageDraw`:`:Open`(`:`:Draw`&`,`:`:Image`&`):%- void_[* Open](Draw`&_[*@3 draw], + Image`&_[*@3 image])&] +[s2; Opens the ImageDraw for painting into given [* image]. The [* draw] +parameter defines the [* image]`'s color model. This is needed +because in Win32, standard GDI is not completely generic as concerns +image color models. To process a bitmap, you must create a CompatibleDC +suitable for processing the image, and this is not generally +possible to determine and create solely using the information +in the image. (E.g. when a printer has different color model +than the screen, which is quite often the case, an image created +using the PrintDraw as its compatible draw will not be processable +by another ImageDraw based on ScreenDraw).&] +[s4; [%-*C@3 draw]-|draw compatible with image color model&] +[s4; [%-*C@3 image]-|image to write into&] +[s0;3 &] +[s0;:`:`:ImageDraw`:`:Close`(`):%- void_[* Close]()&] +[s2; Shuts down writing into the (previously Open`-ed) image. Between +the Open (or the non`-empty contructor) and a Close the image +itself must not be manipulated, otherwise the results may be +inpredictable. You had best consider the image locked (although +in reality, no physical lock is currently done) and leave it +alone until the Close, after which you can process it further +(encoder it using an ImageEncoder and save it to the disk, store +it in a VectorMap`-based cache for web server throughput acceleration, +assign it to the system cursor using [^topic`:`/`/CtrlCore`/src`/Ctrl`$en`-us`#`:`:Ctrl`:`:CursorImage`(Point`,dword`)^ C +ursorImage] etc.).&] +[s0; &] +[s0;3 &] +[s0;:`:`:ImageMaskDraw`:`:class`:`:ImageMaskDraw:%- class_[* ImageMaskDraw]&] +[s2; Used to paint into image masks. Images can be either unmasked +(considered to have mask equal to opaque everywhere in the image +area), or masked. Full alpha channel is currently not supported, +but is planned (hopefully soon, written on June 29, 2005). Mask +can be either `"off`" for the pixel (then the pixel is transparent +and nothing is painted) or `"on`" (then the pixel is painted +and the original pixel is overwritten). This applies to standard +functions like the simpler form of DrawImage, other functions +manipulate the pixel `& mask data otherwise.&] +[s0;%- [%%/ Derived from][%% ]Draw&] +[s0;3 &] +[s0;:`:`:ImageMaskDraw`:`:ImageMaskDraw`(`):%- [* ImageMaskDraw]()&] +[s2; Constructs an empty ImageMaskDraw. You can later Open the ImageMaskDraw +for processing an Image.&] +[s0;3 &] +[s0;:`:`:ImageMaskDraw`:`:ImageMaskDraw`(`:`:Image`&`):%- [* ImageMaskDraw](Image`&_[*@3 i +mage])&] +[s2; Creates an ImageMaskDraw and opens it for writing into an Image.&] +[s4; [%-*C@3 image]-|image to write to&] +[s0;3 &] +[s0;:`:`:ImageMaskDraw`:`:Open`(`:`:Image`&`):%- void_[* Open](Image`&_[*@3 image])&] +[s2; Opens the ImageMaskDraw to write into given Image. When the +ImageMaskDraw was previously opened with another image, it is +automatically closed. It is an error to open the same Image in +two ImageMaskDraws at once. It is, however, legal to open an +Image simultaneously in an ImageDraw together with the ImageMaskDraw. +It is often handy to be able to paint the data and mask at once, +because they often correlate.&] +[s4; [%-*C@3 image]-|image to write to&] +[s0;3 &] +[s0;:`:`:ImageMaskDraw`:`:Close`(`):%- void_[* Close]()&] +[s2; Finishes writing into the image mask. After this operation you +can further process the newly modified image (paint it, encode +it or anything else).&] +[s0;3 &] +[s0;:`:`:DrawingDraw`:`:class`:`:DrawingDraw: &] +[s0;%- class_[* DrawingDraw]&] +[s2; Used to create an internal linearized representation of the +executed drawing operations, called a [* Drawing]. The Drawing +can later be painted using DrawDrawing or serialized into a stream +(to be later read back). Please consider the DrawingDraw an optimized +internal short`-term image storage format (like when preparing +the output for printer or for caches), not a completely `"official`" +or stable format suitable e.g. for documents or distributable +images. It tends to change from time to time. We plan to implement +a specialized `"stable`" Drawing`-like vector format which will +be suitable for long`-term data storage.&] +[s0;%- [%%/ Derived from][%% ]Draw&] +[s0;3 &] +[s0;:`:`:DrawingDraw`:`:DrawingDraw`(`):%- [* DrawingDraw]()&] +[s2; Constructs an empty DrawingDraw. The DrawingDraw can be initialized +later using [* Create].&] +[s0;3 &] +[s0;:`:`:DrawingDraw`:`:DrawingDraw`(int`,int`):%- [* DrawingDraw](int_[*@3 cx], +int_[*@3 cy])&] +[s2; Creates a DrawingDraw and initializes it with given dimensions. +Pixels are set as default Drawing units, although you can change +the units to dots using SetPixels.&] +[s4; [%-*C@3 cx]-|drawing width&] +[s4; [%-*C@3 cy]-|drawing height&] +[s0;3 &] +[s0;:`:`:DrawingDraw`:`:DrawingDraw`(`:`:Size`):%- [* DrawingDraw](Size_[*@3 sz])&] +[s2; Creates a DrawingDraw with given size (with pixels as default +units).&] +[s4; [%-*C@3 sz]-|desired drawing size&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 SetPixels]([@(0.0.255) bool]_[@3 b]_`=_true)&] +[s2; Switches to pixel units (b `= true) or to dot units (b `= false).&] +[s4; [%-*C@3 b]-|unit mode: true `= pixels, false `= dots&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 Create]([@(0.0.255) int]_[@3 cx], [@(0.0.255) int]_[@3 cy])&] +[s2; Initializes the DrawingDraw to record drawing operations into +a Drawing of given size. After performing the requested set of +operations, you can GetResult to retrieve the Drawing containing +the recording of the performed operations. Default drawing units +are pixels, use SetPixels(false) to switch them to dots.&] +[s4; [%-*C@3 cx]-|drawing width&] +[s4; [%-*C@3 cy]-|drawing height&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 Create]([^`:`:Size^ Size]_[@3 sz])&] +[s2; Initializes the DrawingDraw to create a Drawing of given size.&] +[s4; [%-*C@3 sz]-|drawing size&] +[s0;3 &] +[s0;:`:`:DrawingDraw`:`:GetResult`(`)const:%- Drawing_[* GetResult]()_const&] +[s2; Returns the Drawing containing the recorded operations. (Before +you use GetResult, you must first use the constructor with parameters +or call Create to initialize the Drawing and set its size).&] +[s4; [*/ Return value]-|a Drawing representing the recorded set of drawing +operations. You can later replay this set of operations using +[^topic`:`/`/Draw`/src`/Draw`$en`-us`#`:`:Draw`:`:DrawDrawing`(const Rect`&`,const Drawing`&`)^ D +rawDrawing] or Serialize it for storage.&] +[s0;3 &] +[s0;:`:`:DrawingDraw`:`:operator`:`:Drawing`(`)const:%- [* operator_Drawing]()_const&] +[s2; Returns the recorded Drawing (just like GetResult).&] +[s4; [*/ Return value]-|the recorded drawing operations&] +[s0; &] +[s0; &] +[s0; class_[* Report]&] +[s0; The Report can be used for generating documents for printing. +Is is currently considered slightly obsolete as it is based on +the old Document object instead on RichText. It is planned to +be removed sometimes in the future, but is currently needed for +not breaking our older projects.&] +[s0; &] +[s0; class_[* WinMetaFileDraw (Win32 only)]&] +[s0; Used to create Windows metafiles. &] +[s0;3 &] +[s0;:`:`:WinMetaFileDraw`:`:WinMetaFileDraw`(HDC`,int`,int`,const char`*`,const char`*`,const char`*`):%- [* W +inMetaFileDraw](HDC_[*@3 hdc], int_[*@3 cx], int_[*@3 cy], const_char_`*[*@3 app], +const_char_`*[*@3 name], const_char_`*[*@3 file])&] +[s2; Constructs a WinMetaFileDraw to generate a metafile in color +format compatible with given device.&] +[s4; [%-*C@3 hdc]-|reference device to use for initializing metafile +color model&] +[s4; [%-*C@3 cx]-|metafile width&] +[s4; [%-*C@3 cy]-|metafile height&] +[s4; [%-*C@3 app]-|application name (stored in the metafile header)&] +[s4; [%-*C@3 name]-|metafile name (stored in the metafile header)&] +[s4; [%-*C@3 file]-|optional file name (when not given, the metafile +is memory`-only)&] +[s0;3 &] +[s0;:`:`:WinMetaFileDraw`:`:WinMetaFileDraw`(int`,int`,const char`*`,const char`*`,const char`*`):%- [* W +inMetaFileDraw](int_[*@3 cx], int_[*@3 cy], const_char_`*[*@3 app], +const_char_`*[*@3 name], const_char_`*[*@3 file])&] +[s2; Constructs a WinMetaFileDraw to generate a metafile in color +format compatible with ScreenDraw.&] +[s4; [%-*C@3 cx]-|metafile width&] +[s4; [%-*C@3 cy]-|metafile height&] +[s4; [%-*C@3 app]-|application name&] +[s4; [%-*C@3 name]-|metafile name&] +[s4; [%-*C@3 file]-|optional file name (empty causes a memory`-only +metafile to be created)&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 Create]([^HDC^ HDC]_[@3 hdc], [@(0.0.255) int]_[@3 cx], +[@(0.0.255) int]_[@3 cy], [@(0.0.255) const]_[@(0.0.255) char]_`*[@3 app]_`=_NULL, +[@(0.0.255) const]_[@(0.0.255) char]_`*[@3 name]_`=_NULL, [@(0.0.255) const]_[@(0.0.255) ch +ar]_`*[@3 file]_`=_NULL)&] +[s2; Creates a new metafile compatible with given reference device +context.&] +[s4; [%-*C@3 hdc]-|reference device context to copy color format from&] +[s4; [%-*C@3 cx]-|metafile width&] +[s4; [%-*C@3 cy]-|metafile height&] +[s4; [%-*C@3 app]-|application name&] +[s4; [%-*C@3 name]-|metafile name&] +[s4; [%-*C@3 file]-|optional file name (when not given, is memory`-only)&] +[s4; [*/ Return value]-|[* true] on success, [* false] on failure&] +[s0;3 &] +[s5;K%- [@(0.0.255) bool]_[@0 Create]([@(0.0.255) int]_[@3 cx], [@(0.0.255) int]_[@3 cy], +[@(0.0.255) const]_[@(0.0.255) char]_`*[@3 app]_`=_NULL, [@(0.0.255) const]_[@(0.0.255) cha +r]_`*[@3 name]_`=_NULL, [@(0.0.255) const]_[@(0.0.255) char]_`*[@3 file]_`=_NULL)&] +[s2; Creates a new metafile compatible with the screen.&] +[s4; [%-*C@3 cx]-|metafile width&] +[s4; [%-*C@3 cy]-|metafile height&] +[s4; [%-*C@3 app]-|application name&] +[s4; [%-*C@3 name]-|metafile name&] +[s4; [%-*C@3 file]-|optional file name&] +[s4; [*/ Return value]-|[* true] on success, [* false] on failure&] +[s0;3 &] +[s5;K%- [^`:`:WinMetaFile^ WinMetaFile]_[@0 Close]()&] +[s2; Finishes metafile creation and returns the created [* WinMetaFile] +object.&] +[s4; [*/ Return value]-|the recorded metafile&] +[s0; &] +[s0;3 &] +[s0;:`:`:PrintDraw`:`:class`:`:PrintDraw:%- class_[* PrintDraw (Win32`-only)]&] +[s2; Used for generating printer output. This is currently Win32`-only, +we hope to make a Linux version soon (volunteers needed). Currently +we have also a Win32`-compatible PdfDraw which should be ported +to Linux. Perhaps then the PrintDraw on Linux will be more or +less derived from PdfDraw.&] +[s0;%- [%%/ Derived from][%% ]Draw&] +[s0;3 &] +[s0;:`:`:PrintDraw`:`:PrintDraw`(HDC`,const char`*`):%- [* PrintDraw](HDC_[*@3 hdc], +const_char_`*[*@3 jobname])&] +[s2; Creates a PrintDraw object. Prior to constructing a PrintDraw, +you must create the printer HDC using PrintDlg or CreateDC.&] +[s4; [%-*C@3 hdc]-|printer DC&] +[s4; [%-*C@3 jobname]-|printer job name&] +[s0;3 &] +[s5;K%- virtual [@(0.0.255) void]_[@0 StartPage]()&] +[s2; Begins a new page.&] +[s0;3 &] +[s5;K%- virtual [@(0.0.255) void]_[@0 EndPage]()&] +[s2; Ends current page.&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 InitPrinter]()&] +[s2; Sends an initialization sequence to the printer.&] +[s0;3 &] +[s5;K%- [@(0.0.255) void]_[@0 Abort]()&] +[s2; Aborts current print job.&] +[s0; &] +[s0; struct_[* PageDraw]&] +[s0; The PageDraw is an abstract interface used to draw formatted +text using the RichText objects. It is derived from Draw and +captures drawing operations on the currently selected output +page. After the painting is finished, you can access the generated +pages. The user must derive the Page and Info methods and support +their routines to manage the output pages.&] +[s0; &] +[s0;3 &] +[s0;:`:`:PageDraw`:`:struct`:`:PageDraw: struct_[* PdfDraw (Win32`-only)]&] +[s0; Used to create PDF files. Volunteers are needed to implement +a Linux version (some font hackery will perhaps be needed, current +version works only with TrueType fonts).&] +[s0; ] \ No newline at end of file diff --git a/uppdev/Draw/src.tpp/Font$en-us.tpp b/uppdev/Draw/src.tpp/Font$en-us.tpp new file mode 100644 index 000000000..dfec38ae2 --- /dev/null +++ b/uppdev/Draw/src.tpp/Font$en-us.tpp @@ -0,0 +1,13 @@ +TITLE("Font") +COMPRESSED +120,156,189,90,9,115,219,182,18,254,43,232,180,205,200,142,236,240,180,100,169,237,196,241,209,106,154,216,25,31,233,235,120,44,11,34,33,11,45,69,234,17,144,28,191,76,242,219,187,0,72,10,148,120,72,178,251,236,177,69,145,216,19,187,223,98,1,222,90,232,135,31,140,166,241,189,81,243,211,57,33,35,60,11,248,221,45,117,156,118,23,91,110,247,239,223,47,14,187,187,111,27,7,206,142,224,98,2,23,187,101,218,109,215,54,29,235,0,254,153,182,105,185,150,237,152,109,235,208,105,219,118,219,232,120,1,102,236,238,54,176,218,237,174,32,178,128,200,106,185,150,217,114,218,78,219,180,91,109,11,104,45,195,176,140,150,229,154,142,221,182,220,142,79,152,119,119,139,219,118,119,247,242,0,136,108,33,9,152,27,230,129,229,180,28,203,176,13,203,1,81,102,187,237,152,45,183,109,31,30,28,116,60,60,229,52,10,19,89,212,52,45,179,59,52,91,93,208,249,219,183,111,251,166,99,40,13,28,96,102,26,14,168,106,194,61,195,177,90,166,123,104,28,186,109,179, +109,216,192,220,109,25,110,103,138,99,60,41,55,221,173,53,189,101,116,40,39,192,98,247,181,105,182,128,228,160,121,240,189,233,180,192,208,182,237,184,237,150,1,194,45,203,178,109,203,180,173,195,67,203,61,112,91,157,49,193,62,137,239,110,191,220,127,253,241,244,124,239,230,10,221,50,179,251,123,103,0,191,103,81,200,197,167,244,104,7,221,254,104,24,123,134,241,182,97,236,27,251,150,235,238,160,196,213,234,62,186,79,175,222,26,72,144,46,30,116,22,143,22,196,211,152,206,49,39,171,228,125,33,243,136,49,250,16,126,194,193,140,92,63,77,201,121,212,71,43,183,50,210,159,202,36,55,81,198,244,236,226,252,122,112,255,169,143,146,139,162,49,66,240,135,104,78,240,48,32,125,148,94,213,139,249,229,254,151,187,87,119,183,204,234,202,251,136,50,132,145,23,133,94,76,56,81,94,66,124,140,57,18,97,22,211,33,17,95,9,194,211,41,129,89,15,61,130,162,17,226,228,51,223,71,61,73,157,138,110,162,49,102,200,131,73,154,2,191,233,19,138,166,36,198,34, +232,16,14,125,49,82,186,67,200,154,147,152,83,32,65,143,148,143,81,76,189,241,96,79,61,196,67,26,80,78,9,219,79,116,76,62,148,40,198,163,152,134,15,136,17,224,128,3,132,57,7,13,103,92,232,24,101,10,75,125,149,134,215,99,33,47,142,9,155,70,161,47,73,159,24,4,30,26,37,166,11,142,4,148,11,37,209,40,138,39,194,188,17,6,51,105,232,147,207,104,176,135,8,246,198,57,58,97,39,155,18,143,142,168,151,12,155,11,237,165,188,24,140,128,63,22,77,8,132,13,241,201,136,134,82,2,12,3,61,65,4,104,52,153,128,87,4,47,214,17,6,26,210,78,244,229,139,229,30,186,157,150,99,184,63,65,196,119,251,72,216,30,24,221,221,52,158,145,10,243,206,213,245,137,8,141,187,187,78,231,231,116,16,186,226,224,103,28,251,232,215,155,158,82,52,21,62,124,66,211,0,115,97,222,62,58,198,33,2,39,225,128,147,88,61,59,137,241,163,96,74,248,21,247,133,132,125,224,91,46,252,242,226,195,209,121,137,104,70,98,58,146,194,171,121,28, +93,246,142,222,151,241,192,33,27,236,173,203,233,248,226,230,178,119,122,89,194,11,252,28,177,41,76,167,191,6,171,171,63,63,188,187,40,213,234,105,50,140,130,132,203,215,175,249,240,188,134,104,67,19,2,209,232,169,41,86,169,21,50,46,51,198,83,46,143,134,28,167,243,209,11,71,145,160,24,71,43,209,39,104,229,99,21,84,66,132,187,132,114,201,252,119,80,209,195,95,9,63,3,139,143,163,25,124,111,12,118,50,52,132,104,135,124,244,80,1,192,81,29,2,53,232,208,121,101,3,26,59,41,130,92,18,62,139,67,133,16,225,108,50,36,113,154,62,131,189,16,79,32,222,241,28,211,64,192,195,254,34,208,203,52,62,7,138,65,3,84,169,208,89,226,222,21,23,48,208,71,234,179,74,113,193,114,161,247,218,134,219,42,95,179,39,197,6,3,239,12,45,146,145,187,25,105,149,189,103,48,36,213,174,39,70,15,26,128,138,140,3,122,226,120,176,251,188,41,91,97,94,105,191,148,91,192,71,27,1,58,45,6,12,118,53,39,133,186,119,51,31,9,5,148,135, +52,28,205,194,66,115,148,36,95,35,46,68,50,172,21,23,254,99,20,251,125,36,63,170,162,66,48,252,183,162,130,134,34,143,147,186,55,140,102,188,36,62,144,40,150,209,100,72,67,53,22,28,36,174,227,39,52,10,240,195,74,93,104,183,160,46,152,118,86,23,10,224,235,172,247,159,211,147,143,189,235,227,223,82,8,51,84,141,31,236,169,137,96,26,28,166,72,88,4,131,199,71,239,79,143,222,189,63,45,101,51,138,9,9,158,16,243,176,76,109,212,160,178,152,2,142,205,137,7,21,21,41,23,52,17,217,127,128,162,24,207,8,135,69,208,78,149,76,9,189,215,127,126,92,22,42,2,84,160,38,75,0,152,73,84,133,133,160,112,88,64,56,20,49,86,193,247,248,226,195,199,139,171,211,19,141,235,205,224,245,224,53,154,49,146,20,113,88,71,120,145,79,196,10,2,230,99,26,49,130,38,20,150,111,176,88,120,15,83,19,202,4,192,158,16,36,128,91,205,153,120,74,62,83,198,197,197,98,64,90,25,86,18,62,155,154,14,68,97,69,168,11,188,150,41,217, +209,162,49,181,73,139,74,185,214,46,10,237,252,128,198,78,54,36,201,244,52,71,115,153,41,107,126,117,30,254,70,232,195,152,63,75,61,197,98,77,5,245,148,26,75,66,9,33,245,138,254,65,125,62,126,150,158,146,195,70,106,74,45,31,5,89,170,36,130,36,48,228,74,192,87,141,162,122,188,118,17,44,87,95,47,128,74,185,124,21,44,141,12,189,20,110,224,252,69,49,151,107,106,181,128,157,193,146,90,91,224,172,141,225,53,102,41,252,86,202,229,64,188,212,40,29,201,107,140,186,18,38,0,232,106,148,141,228,186,177,179,83,101,194,90,186,167,171,182,68,253,244,107,185,5,27,168,174,207,71,52,252,11,48,22,90,139,104,78,101,71,35,64,43,16,189,91,65,229,17,145,152,44,75,43,215,35,18,121,242,5,54,51,170,159,239,31,7,175,114,139,13,13,114,54,170,164,225,106,21,133,254,99,121,217,80,165,116,138,72,219,168,157,135,162,151,83,92,118,135,10,173,64,47,52,165,159,73,192,222,248,17,103,149,1,150,96,214,54,150,228,192,234,101,13,81, +136,133,110,160,32,22,64,217,70,6,190,139,2,63,215,138,172,103,156,32,91,238,58,150,89,159,71,91,50,87,132,117,236,21,243,97,20,5,207,212,190,96,102,4,215,194,169,25,46,77,205,10,32,113,28,80,111,11,155,21,97,189,75,183,22,144,146,214,137,72,5,108,229,216,101,17,47,233,218,27,128,157,56,128,46,125,11,227,51,218,122,7,63,71,140,70,93,39,72,19,179,149,167,11,4,189,164,179,197,202,229,111,2,149,106,11,47,100,180,245,206,126,142,24,141,186,78,144,38,102,43,103,23,8,122,142,179,1,207,211,27,18,215,1,192,103,33,19,87,208,70,249,111,168,76,162,55,51,152,97,49,193,111,88,42,29,154,68,159,64,39,83,1,231,231,81,120,20,114,122,20,80,204,200,118,216,171,51,168,159,193,23,16,184,169,200,188,192,173,38,180,76,228,51,103,85,204,230,155,100,42,195,40,28,236,97,16,2,255,149,24,185,125,32,118,162,101,67,238,83,15,203,237,113,177,163,175,141,147,91,225,227,104,22,248,192,130,139,205,201,153,160,125,28,19,40, +234,208,110,203,190,54,93,9,84,174,141,89,90,126,75,251,45,221,182,130,101,48,211,235,100,213,66,120,85,244,162,76,109,45,60,95,75,54,19,159,3,241,173,53,88,193,216,205,148,200,129,219,214,74,172,96,79,77,71,146,222,188,38,12,162,16,194,6,98,37,94,1,150,120,9,89,196,89,147,199,233,156,164,232,162,105,90,108,221,106,226,111,109,98,113,54,214,216,41,246,174,16,29,45,165,178,102,200,90,118,44,250,122,201,124,209,193,15,94,109,213,113,213,238,106,151,236,234,86,109,158,235,82,202,118,118,243,29,26,143,244,93,77,181,153,139,122,35,181,47,78,153,4,150,57,196,130,175,237,33,52,179,67,71,128,47,193,225,124,22,4,85,248,162,14,17,163,88,76,253,90,61,184,214,127,151,71,67,202,21,208,127,189,56,72,59,112,156,28,109,38,123,102,162,57,26,205,2,97,8,163,208,134,211,209,147,48,91,245,224,18,76,229,49,91,110,183,80,58,64,30,237,84,246,228,121,195,101,107,248,47,219,158,89,94,177,65,166,181,141,234,209,102,14,107,170, +19,223,164,69,246,198,56,124,128,108,90,10,164,202,35,129,43,240,38,196,212,255,4,230,170,96,38,120,146,75,35,205,63,243,136,22,159,3,100,92,86,179,168,191,96,43,115,132,136,55,29,10,115,132,21,37,72,194,87,107,163,229,84,163,134,118,22,178,56,119,198,108,121,127,173,178,141,206,98,226,103,248,109,100,79,182,197,68,157,93,73,44,108,18,90,54,26,173,17,27,165,54,125,247,162,54,125,247,127,52,9,38,254,56,154,76,113,44,166,253,49,202,31,254,86,38,185,216,21,199,108,44,223,125,120,225,221,209,140,239,134,8,183,216,199,2,6,218,17,116,233,250,79,32,248,243,10,51,48,216,176,28,167,69,164,174,122,100,215,122,199,176,252,70,204,226,56,187,23,82,158,230,175,20,1,200,148,28,181,55,179,221,47,5,94,77,64,246,220,11,40,162,218,229,214,4,53,10,9,68,111,230,119,252,86,20,43,168,236,101,187,121,35,125,35,182,185,254,121,177,157,216,179,138,101,186,51,70,137,51,52,152,150,2,19,64,19,239,247,104,143,18,142,235,249,33, +91,17,137,185,36,113,30,202,215,112,72,213,82,71,177,236,35,245,169,193,120,201,142,231,218,139,17,184,174,205,89,13,140,238,55,73,196,99,245,126,148,82,43,141,66,113,253,41,41,36,73,236,139,215,166,212,189,202,154,81,224,105,165,250,75,58,90,114,236,163,156,153,75,213,242,191,171,17,150,179,84,89,151,152,170,31,72,222,253,3,118,76,35,136, + diff --git a/uppdev/Draw/src.tpp/FontInfo$en-us.tpp b/uppdev/Draw/src.tpp/FontInfo$en-us.tpp new file mode 100644 index 000000000..f5917878d --- /dev/null +++ b/uppdev/Draw/src.tpp/FontInfo$en-us.tpp @@ -0,0 +1,8 @@ +TITLE("FontInfo") +COMPRESSED +120,156,181,88,13,79,219,56,24,254,43,150,182,161,150,65,101,59,73,147,182,183,19,211,177,221,161,109,220,4,59,221,73,85,161,110,226,180,214,242,181,216,45,160,211,237,183,223,107,167,105,27,40,109,104,1,16,202,135,223,199,239,243,126,199,125,138,94,191,198,71,248,21,222,242,211,61,229,33,155,70,106,208,23,182,237,245,24,117,122,223,63,253,217,233,29,158,52,218,118,83,163,16,64,177,92,98,121,142,69,108,218,134,127,196,34,212,161,150,77,60,218,177,61,203,242,112,215,143,152,148,131,126,68,61,175,167,133,40,8,81,215,161,196,181,61,219,35,150,235,81,144,165,24,83,236,82,135,216,150,71,157,110,192,165,63,232,51,207,234,29,94,180,65,200,210,59,1,56,38,109,106,187,54,197,22,166,54,108,69,60,207,38,174,227,89,157,118,187,235,179,76,137,52,153,239,37,8,161,164,55,34,110,15,116,254,249,243,103,139,216,184,208,192,6,48,130,109,80,149,192,51,108,83,151,56,29,220,113,60,226,97,11,192,29,23,59,221,140,229,44,126,156,186,179,149, +186,139,187,66,113,128,56,124,75,136,11,34,237,163,246,43,98,187,64,212,179,108,199,115,49,108,78,41,181,44,74,44,218,233,80,167,237,184,221,9,103,1,207,7,253,127,175,255,123,243,225,252,248,175,75,212,151,164,247,169,59,132,223,143,105,162,206,146,48,213,215,198,170,93,212,127,131,241,49,198,39,13,220,194,45,234,56,77,52,55,119,241,28,93,151,87,39,24,149,226,203,151,221,229,235,37,64,150,139,25,83,252,33,196,149,222,247,75,58,227,108,20,241,43,84,94,45,22,254,178,105,175,95,175,7,7,131,190,164,61,244,53,79,103,2,252,139,20,191,85,40,230,42,23,190,68,97,154,163,177,152,241,196,136,182,208,183,137,144,8,254,114,176,199,240,56,77,162,187,130,25,186,17,106,130,124,48,83,134,2,206,51,228,167,217,29,74,51,158,51,237,123,137,26,34,81,60,79,88,4,18,83,201,53,66,200,115,158,248,28,150,78,19,37,146,49,98,73,128,126,76,193,59,240,40,206,34,225,3,223,0,201,59,9,254,66,105,136,228,132,229,229,58,159,249,19, +184,110,182,180,250,206,26,79,100,42,239,94,221,127,120,202,20,187,66,143,137,252,206,213,123,233,243,68,13,27,195,166,15,90,171,238,138,3,74,147,1,145,165,123,32,236,42,206,92,64,84,151,52,154,139,69,200,0,151,86,191,224,106,154,131,121,212,4,72,3,61,230,131,149,144,207,163,8,129,27,56,16,101,35,112,168,121,63,98,146,71,34,225,134,50,238,109,162,113,202,247,231,49,199,120,54,34,35,30,165,55,79,37,242,225,182,136,154,189,152,148,32,59,80,97,65,32,116,0,179,8,201,140,249,218,17,76,65,86,36,10,233,90,152,11,83,218,32,152,33,98,99,96,9,82,41,232,35,121,174,128,176,186,225,144,57,234,38,69,154,174,212,49,172,179,171,133,46,88,206,139,68,8,106,24,225,44,121,6,35,148,32,59,24,33,78,165,2,109,195,156,243,185,21,128,33,212,138,101,180,163,25,139,166,252,169,188,254,224,98,60,217,47,72,11,136,39,114,90,168,221,104,162,225,219,149,88,215,247,199,134,242,196,224,26,135,193,157,246,222,194,121,219,121,125,134, +229,207,192,109,9,243,116,126,133,220,130,95,153,1,141,102,13,245,223,207,248,223,34,80,147,253,170,224,28,100,151,156,155,65,215,24,115,104,41,32,175,205,190,168,39,53,148,255,194,110,247,87,190,4,217,37,87,216,173,136,161,90,236,164,252,92,115,80,111,15,229,215,105,62,168,33,108,33,191,250,170,14,93,149,42,32,203,130,25,211,157,220,12,1,171,156,75,165,15,13,58,106,64,191,79,3,232,233,34,65,211,68,232,235,173,1,89,204,16,105,62,236,15,7,123,153,102,21,232,37,205,115,201,98,136,97,185,112,69,163,98,131,58,9,248,153,135,234,82,215,217,125,67,97,1,244,146,124,79,77,31,28,241,34,32,160,254,155,137,79,135,65,4,219,35,211,40,42,49,97,134,2,61,195,233,247,186,183,32,232,26,12,101,76,143,136,129,25,57,31,9,160,22,58,231,99,128,135,129,200,52,28,24,83,153,9,68,232,201,75,145,98,222,144,247,118,60,66,89,42,197,122,89,80,60,231,122,172,101,213,254,102,134,25,173,109,146,42,211,212,138,121,56,186,203,38, +53,220,120,161,75,240,179,248,113,137,244,162,129,43,98,17,177,92,79,48,171,177,99,56,27,215,154,150,200,131,241,26,127,214,48,199,39,232,64,48,177,23,182,56,218,207,32,115,172,221,172,65,170,239,142,80,77,57,250,180,242,248,189,208,17,230,196,16,26,185,169,121,15,230,198,210,180,171,81,78,6,149,91,58,208,153,177,181,123,156,201,143,226,150,7,95,133,242,55,247,190,81,154,70,143,219,118,21,166,102,247,251,150,67,50,137,176,32,7,57,20,167,73,58,60,54,121,180,117,8,60,147,151,62,139,204,247,234,94,74,47,80,118,212,89,143,182,48,183,202,18,166,70,56,235,219,77,58,47,190,61,175,10,93,244,229,198,152,126,184,160,214,192,161,197,138,218,4,121,155,142,20,84,81,120,14,156,74,125,107,114,121,134,129,117,9,179,3,15,227,138,249,216,29,230,105,92,147,28,66,53,232,137,136,159,67,87,222,234,174,75,165,207,23,230,14,43,110,54,19,158,3,215,164,251,15,33,40,131,246,8,89,31,67,163,225,190,8,133,223,170,88,33,99,48,65, +1,215,16,144,139,113,234,126,205,216,230,206,202,125,195,236,95,121,116,48,108,46,207,167,214,156,8,53,150,100,150,135,87,134,197,131,147,167,117,226,195,131,213,154,25,46,158,55,75,35,252,166,15,134,12,96,62,245,97,28,67,13,115,106,84,127,14,124,183,141,85,229,212,231,106,179,138,43,99,225,187,93,76,240,148,189,214,154,227,189,148,98,156,196,250,27,186,212,164,174,69,170,158,222,230,214,21,7,204,109,47,17,143,51,117,247,160,80,12,254,7,99,121,167,180, diff --git a/uppdev/Draw/src.tpp/Image$en-us.tpp b/uppdev/Draw/src.tpp/Image$en-us.tpp new file mode 100644 index 000000000..41dc1ffab --- /dev/null +++ b/uppdev/Draw/src.tpp/Image$en-us.tpp @@ -0,0 +1,317 @@ +topic "Image and ImageBuffer";[2 $$0,0#00000000000000000000000000000000:Default] +[i448;a25;kKO9;*@(64)2 $$1,0#37138531426314131252341829483380:class] +[l288;2 $$2,2#27521748481378242620020725143825:desc] +[a83;*R6 $$3,0#31310162474203024125188417583966:caption] +[l288;i1121;b17;O9;~~~.1408;2 $$4,0#10431211400427159095818037425705:param] +[i448;a25;kKO9;*@(64)2 $$5,0#37138531426314131252341829483370:item] +[*+117 $$6,6#14700283458701402223321329925657:header] +[{_}%EN-US +[s3; Image and ImageBuffer&] +[s1;K:`:`:Image`:`:class:%- [@(0.0.255) class]_[@0 Image]_:_[@(0.0.255) public]_[^`:`:AssignValueTypeNo^ A +ssignValueTypeNo]<_[@0 Image], [@3 150], [^`:`:Moveable^ Moveable]<[@0 Image]>_>_&] +[s2; Image represents an immutable image value. Image can be directly +painted to Draw. To create or change Image, use [^`:`:ImageBuffer^ ImageBuffer].&] +[s2; Image has low`-cost constant time deep copy. It is moveable +and Rich`-Value compatible type.&] +[s2; U`+`+ expects pixels to be in premultiplied alpha format.&] +[s0; &] +[s5;K:`:`:Image`:`:operator`~`(`)const:%- [@(0.0.255) const]_[^`:`:RGBA^ RGBA]`*_[@0 operat +or`~]()_[@(0.0.255) const]&] +[s5;%- [@0 operator]_[@(0.0.255) const]_[^`:`:RGBA^ RGBA][@0 `*]()_[@(0.0.255) const]&] +[s2; Returns a pointer to Image pixels.&] +[s0; &] +[s5;K:`:`:Image`:`:operator`[`]`(int`)const:%- [@(0.0.255) const]_[^`:`:RGBA^ RGBA]`*_[@0 o +perator`[`]]([@(0.0.255) int]_[@3 i])_[@(0.0.255) const]&] +[s2; Returns a pointer to the first pixel in the line [%-*@3 i].&] +[s0; &] +[s5;K:`:`:Image`:`:GetSize`(`)const:%- [^`:`:Size^ Size]_[@0 GetSize]()_[@(0.0.255) const]&] +[s2; Returns the dimension of Image.&] +[s0; &] +[s5;K:`:`:Image`:`:GetWidth`(`)const:%- [@(0.0.255) int]_[@0 GetWidth]()_[@(0.0.255) const]&] +[s2; Same as GetSize().cx.&] +[s0; &] +[s5;K:`:`:Image`:`:GetHeight`(`)const:%- [@(0.0.255) int]_[@0 GetHeight]()_[@(0.0.255) cons +t]&] +[s2; Same as GetSize().cy.&] +[s0; &] +[s5;K:`:`:Image`:`:GetLength`(`)const:%- [@(0.0.255) int]_[@0 GetLength]()_[@(0.0.255) cons +t]&] +[s2; Number of pixels in Image `- GetWidth() `* GetHeight().&] +[s0; &] +[s5;K:`:`:Image`:`:GetHotSpot`(`)const:%- [^`:`:Point^ Point]_[@0 GetHotSpot]()_[@(0.0.255) c +onst]&] +[s2; Returns the reference point.&] +[s0; &] +[s5;K:`:`:Image`:`:GetDots`(`)const:%- [^`:`:Size^ Size]_[@0 GetDots]()_[@(0.0.255) const]&] +[s2; Gets the physical size of Image. If physical size is not set, +returns Size(0, 0).&] +[s0; &] +[s5;K:`:`:Image`:`:GetKind`(`)const:%- [@(0.0.255) int]_[@0 GetKind]()_[@(0.0.255) const]&] +[s2; Returns the kind of image. See [^`:`:ImageBuffer^ ImageBuffer] +for detail.&] +[s0; &] +[s5;K:`:`:Image`:`:GetSerialId`(`)const:%- [^`:`:int64^ int64]_[@0 GetSerialId]()_[@(0.0.255) c +onst]&] +[s2; Returns the unique, per application run, identifier of Image. +All Images with the same serial id can be considered equal (this +is useful for caching images).&] +[s0; &] +[s5;K:`:`:Image`:`:IsSame`(const`:`:Image`&`)const:%- [@(0.0.255) bool]_[@0 IsSame]([@(0.0.255) c +onst]_[^`:`:Image^ Image]`&_[@3 img])_[@(0.0.255) const]&] +[s2; Same as GetSerialId() `=`= img.GetSerialId().&] +[s0; &] +[s5;K:`:`:Image`:`:operator`=`=`(const`:`:Image`&`)const:%- [@(0.0.255) bool]_[@0 operato +r`=`=]([@(0.0.255) const]_[^`:`:Image^ Image]`&_[@3 img])_[@(0.0.255) const]&] +[s5;K:`:`:Image`:`:operator`=`=`(const`:`:Image`&`)const:%- [@(0.0.255) bool]_[@0 operato +r!`=]([@(0.0.255) const]_[^`:`:Image^ Image]`&_[@3 img])_[@(0.0.255) const]&] +[s2; Tests whether two Images are equal (or not equal). Dimensions, +hot`-spot, dots and all pixels are compared. Note that the comparison +can be slow.&] +[s0; &] +[s5;K:`:`:Image`:`:GetHashValue`(`)const:%- [^`:`:dword^ dword]_[@0 GetHashValue]()_[@(0.0.255) c +onst]&] +[s2; Returns the hash`-value for image. All pixels combined into +hash value (potentially slow).&] +[s0; &] +[s5;K:`:`:Image`:`:ToString`(`)const:%- [^`:`:String^ String]_[@0 ToString]()_[@(0.0.255) c +onst]&] +[s2; Returns the basic Image informations as String.&] +[s0; &] +[s5;K:`:`:Image`:`:Serialize`(`:`:Stream`&`):%- [@(0.0.255) void]_[@0 Serialize]([^`:`:Stream^ S +tream]`&_[@3 s])&] +[s2; Serializes Image.&] +[s0; &] +[s5;K:`:`:Image`:`:Clear`(`):%- [@(0.0.255) void]_[@0 Clear]()&] +[s2; Assigns an empty Image.&] +[s0; &] +[s5;K:`:`:Image`:`:operator`=`(const`:`:Image`&`):%- [^`:`:Image^ Image]`&_[@0 operator`= +]([@(0.0.255) const]_[^`:`:Image^ Image]`&_[@3 img])&] +[s2; Assigns another Image.&] +[s0; &] +[s5;K:`:`:Image`:`:operator`=`(`:`:ImageBuffer`&`):%- [^`:`:Image^ Image]`&_[@0 operator`= +]([^`:`:ImageBuffer^ ImageBuffer]`&_[@3 img])&] +[s2; Assigns Image created in ImageBuffer. ImageBuffer is emptied +by this operation.&] +[s0; &] +[s5;K:`:`:Image`:`:IsNullInstance`(`)const:%- [@(0.0.255) bool]_[@0 IsNullInstance]()_[@(0.0.255) c +onst]&] +[s2; Test whether Image has nonzero dimension.&] +[s0; &] +[s5;K:`:`:Image`:`:IsEmpty`(`)const:%- [@(0.0.255) bool]_[@0 IsEmpty]()_[@(0.0.255) const]&] +[s2; Same as IsNullInstance.&] +[s0; &] +[s5;K:`:`:Image`:`:operator`:`:Value`(`)const:%- [@0 operator_][^`:`:Value^@0 Value]()_[@(0.0.255) c +onst]&] +[s2; Converts Image to Value.&] +[s0; &] +[s5;K:`:`:Image`:`:`:`:Image`(`):%- [@0 Image]()&] +[s5;%- [@0 Image]([@(0.0.255) const]_[^`:`:Nuller^ Nuller]`&)&] +[s2; Constructs empty Image.&] +[s0; &] +[s5;K:`:`:Image`:`:`:`:Image`(const`:`:Value`&`):%- [@0 Image]([@(0.0.255) const]_[^`:`:Value^ V +alue]`&_[@3 src])&] +[s2; Converts Image from Value.&] +[s0; &] +[s5;K:`:`:Image`:`:`:`:Image`(const`:`:Image`&`):%- [@0 Image]([@(0.0.255) const]_[@0 Image +]`&_[@3 img])&] +[s2; Copy constructor.&] +[s0; &] +[s5;K:`:`:Image`:`:`:`:Image`(`:`:Image`(`*`)`(`)`):%- [@0 Image]([@0 Image]_(`*[@3 fn])()) +&] +[s2; This function allow Image to be directly constructed from pointer +to function returning the Image. This allows omitting parenthesis +when passing Iml image constants as arguments.&] +[s0; &] +[s5;K:`:`:Image`:`:`:`:Image`(`:`:ImageBuffer`&`):%- [@0 Image]([^`:`:ImageBuffer^ ImageB +uffer]`&_[@3 b])&] +[s2; Uses Image created in ImageBuffer. ImageBuffer is emptied by +this operation.&] +[s0; &] +[s5;K:`:`:Image`:`:`~`:`:Image`(`):%- `~[@0 Image]()&] +[s2; Destructor.&] +[s0; &] +[s0; &] +[s0; [3 Standard cursors]&] +[s0; &] +[s0; Image class contains several standard mouse cursor Images as +static member methods:&] +[s0;^`:`:Image^ &] +[ {{3333:3333:3334f0;g0; [ {{6850:3150>274; [s0;%- Arrow] +:: [s0; ] +:: [s0;%- Wait] +:: [s0; ] +:: [s0;%- IBeam] +:: [s0; ] +:: [s0;%- No] +:: [s0; ] +:: [s0;%- SizeAll] +:: [s0; ]}}] +:: [ {{7129:2871>274; [s0;%- SizeHorz] +:: [s0; ] +:: [s0;%- SizeVert] +:: [s0; ] +:: [s0;%- SizeTopLeft] +:: [s0; ] +:: [s0;%- SizeTop] +:: [s0; ] +:: [s0;%- SizeTopRight] +:: [s0; ]}}] +:: [ {{6956:3044>274; [s0;%- SizeLeft] +:: [s0; ] +:: [s0;%- SizeRight] +:: [s0; ] +:: [s0;%- SizeBottomLeft] +:: [s0; ] +:: [s0;%- SizeBottom] +:: [s0; ] +:: [s0;%- SizeBottomRight] +:: [s0; ]}}]}}&] +[s0;^`:`:Image^ &] +[s0;^`:`:Image^ &] +[s0; &] +[s1;K:`:`:ImageBuffer`:`:class:%- [@(0.0.255) class]_[@0 ImageBuffer]_:_[@(0.0.255) private]_ +[^`:`:NoCopy^ NoCopy]&] +[s2; ImageBuffer represents a writable Image `- an array of RGBA +pixels. ImageBuffer can be converted to Image in low`-const constant +time while loosing its content and vice versa, Image can be converted +to ImageBuffer again loosing its content.&] +[s2; &] +[s2; Content of Image / ImageBuffer can be classified to optimize +drawing. Possible classifications are&] +[s2; &] +[ {{2913:7087<288;>640; [s0; [* IMAGE`_UNKNOWN]] +:: [s0; The image kind is unknown.] +:: [s0; [* IMAGE`_EMPTY]] +:: [s0; The image is empty (all alpha values are 0).] +:: [s0; [* IMAGE`_ALPHA]] +:: [s0; The image has alpha values different from 255 and 0.] +:: [s0; [* IMAGE`_MASK]] +:: [s0; The image has alpha values 0 or 255 only.] +:: [s0; [* IMAGE`_OPAQUE]] +:: [s0; The image has all alpha values 255.]}}&] +[s2; &] +[s2; Note that is the kind of image is unknown, painting routine +determines it automatically by scanning pixels and stores the +result.&] +[s2; &] +[s2; Pixels of image are organized in simple continual POD array, +first pixel being top`-left.&] +[s2; &] +[s2; U`+`+ expects pixels to be in premultiplied alpha format.&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:SetKind`(int`):%- [@(0.0.255) void]_[@0 SetKind]([@(0.0.255) int]_ +[@3 k])&] +[s2; Sets the kind of image. You can use this to avoid automatic +detection.&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:GetKind`(`)const:%- [@(0.0.255) int]_[@0 GetKind]()_[@(0.0.255) co +nst]&] +[s2; Returns the kind of image set by SetKind.&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:ScanKind`(`)const:%- [@(0.0.255) int]_[@0 ScanKind]()_[@(0.0.255) c +onst]&] +[s2; Scans all RGBA pixels to determine Image kind.&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:GetScanKind`(`)const:%- [@(0.0.255) int]_[@0 GetScanKind]()_[@(0.0.255) c +onst]&] +[s2; If kind set by SetKind is other than IMAGE`_UNKNOWN, returns +it, otherwise calls ScanKind().&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:SetHotSpot`(`:`:Point`):%- [@(0.0.255) void]_[@0 SetHotSpot]([^`:`:Point^ P +oint]_[@3 p])&] +[s2; Sets the reference point. This point is e.g. used as hot`-spot +when Image is used as mouse pointer.&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:GetHotSpot`(`)const:%- [^`:`:Point^ Point]_[@0 GetHotSpot]()_[@(0.0.255) c +onst]&] +[s2; Returns the reference point.&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:SetDots`(`:`:Size`):%- [@(0.0.255) void]_[@0 SetDots]([^`:`:Size^ S +ize]_[@3 sz])&] +[s2; Sets the optional physical size in dots.&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:GetDots`(`)const:%- [^`:`:Size^ Size]_[@0 GetDots]()_[@(0.0.255) c +onst]&] +[s2; Returns the optional physical size. Default value is Size(0, +0).&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:GetSize`(`)const:%- [^`:`:Size^ Size]_[@0 GetSize]()_[@(0.0.255) c +onst]&] +[s2; Returns the dimensions of image.&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:GetWidth`(`)const:%- [@(0.0.255) int]_[@0 GetWidth]()_[@(0.0.255) c +onst]&] +[s2; Same as GetSize().cx.&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:GetHeight`(`)const:%- [@(0.0.255) int]_[@0 GetHeight]()_[@(0.0.255) c +onst]&] +[s2; Same as GetSize().cy.&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:GetLength`(`)const:%- [@(0.0.255) int]_[@0 GetLength]()_[@(0.0.255) c +onst]&] +[s2; Returns the number of pixels in the image. Same as GetSize().cx +`* GetSize().cy.&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:operator`[`]`(int`):%- [^`:`:RGBA^ RGBA]_`*[@0 operator`[`]]([@(0.0.255) i +nt]_[@3 i])&] +[s5;K:`:`:ImageBuffer`:`:operator`[`]`(int`)const:%- [@(0.0.255) const]_[^`:`:RGBA^ RGBA]_ +`*[@0 operator`[`]]([@(0.0.255) int]_[@3 i])_[@(0.0.255) const]&] +[s2; Returns a pointer to the first pixel in the line [%-*@3 i].&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:operator`~`(`):%- [^`:`:RGBA^ RGBA]_`*[@0 operator`~]()&] +[s5;K:`:`:ImageBuffer`:`:operator`:`:RGBA`*`(`):%- [@0 operator_RGBA]`*()&] +[s5;K:`:`:ImageBuffer`:`:operator`~`(`)const:%- [@(0.0.255) const]_[^`:`:RGBA^ RGBA]_[@0 `* +operator`~]()_[@(0.0.255) const]&] +[s5;K:`:`:ImageBuffer`:`:operator const`:`:RGBA`*`(`)const:%- [@0 operator]_[@(0.0.255) c +onst]_[@0 RGBA`*]()_[@(0.0.255) const]&] +[s2; Returns a pointer to the first pixel of the image. &] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:Create`(int`,int`):%- [@(0.0.255) void]_[@0 Create]([@(0.0.255) in +t]_[@3 cx], [@(0.0.255) int]_[@3 cy])&] +[s5;K:`:`:ImageBuffer`:`:Create`(`:`:Size`):%- [@(0.0.255) void]_[@0 Create]([^`:`:Size^ Si +ze]_[@3 sz])&] +[s2; Creates a new image of specified size. Value of pixels is undefined. +Previous content of ImageBuffer is lost.&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:IsEmpty`(`)const:%- [@(0.0.255) bool]_[@0 IsEmpty]()_[@(0.0.255) c +onst]&] +[s2; Same as GetLength() `=`= 0.&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:Clear`(`):%- [@(0.0.255) void]_[@0 Clear]()&] +[s2; Clears the content, removing all pixels and setting the size +of Image to Size(0, 0).&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:operator`=`(`:`:Image`&`):%- [@(0.0.255) void]_[@0 operator`=]([^`:`:Image^ I +mage]`&_[@3 img])&] +[s5;K:`:`:ImageBuffer`:`:operator`=`(`:`:ImageBuffer`&`):%- [@(0.0.255) void]_[@0 operato +r`=]([^`:`:ImageBuffer^ ImageBuffer]`&_[@3 img])&] +[s2; Assigns pixels of [%-*@3 img] to ImageBuffer. [%-*@3 img] is cleared +and empty after this operation, price paid for low`-cost constant +time operation.&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:`:`:ImageBuffer`(`):%- [@0 ImageBuffer]()&] +[s2; Constructs empty ImageBuffer.&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:`:`:ImageBuffer`(int`,int`):%- [@0 ImageBuffer]([@(0.0.255) int]_ +[@3 cx], [@(0.0.255) int]_[@3 cy])&] +[s5;K:`:`:ImageBuffer`:`:`:`:ImageBuffer`(`:`:Size`):%- [@0 ImageBuffer]([^`:`:Size^ Size +]_[@3 sz])&] +[s2; Constructs ImageBuffer of specified size. Value of pixels is +undefined.&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:`:`:ImageBuffer`(`:`:Image`&`):%- [@0 ImageBuffer]([^`:`:Image^ I +mage]`&_[@3 img])&] +[s5;K:`:`:ImageBuffer`:`:`:`:ImageBuffer`(`:`:ImageBuffer`&`):%- [@0 ImageBuffer]([@0 Ima +geBuffer]`&_[@3 img])&] +[s2; Assigns pixels of [%-*@3 img] to ImageBuffer. [%-*@3 img] is cleared +and empty after this operation, price paid for low`-cost constant +time operation.&] +[s0; &] +[s5;K:`:`:ImageBuffer`:`:`:`:ImageBuffer`(`:`:ImageDraw`&`):%- [@0 ImageBuffer]([^`:`:ImageDraw^ I +mageDraw]`&_[@3 w])&] +[s2; Creates ImageBuffer from ImageDraw. ImageDraw is cleared and +empty after this operation, price paid for low`-cost constant +time operation.&] +[s2; &] +[s0; &] +[s0; ] \ No newline at end of file diff --git a/uppdev/Draw/src.tpp/Iml$en-us.tpp b/uppdev/Draw/src.tpp/Iml$en-us.tpp new file mode 100644 index 000000000..4342dcbb1 --- /dev/null +++ b/uppdev/Draw/src.tpp/Iml$en-us.tpp @@ -0,0 +1,7 @@ +TITLE("Iml and image list class methods") +COMPRESSED +120,156,181,86,109,111,155,72,16,254,43,35,165,141,32,231,160,221,5,12,134,47,145,122,47,138,42,93,165,186,247,9,145,122,131,215,246,94,49,228,96,237,180,58,93,126,251,13,11,216,198,6,167,201,245,18,41,235,236,238,60,243,60,51,179,51,142,24,188,121,67,70,228,130,60,243,19,252,44,22,124,147,170,56,146,142,227,135,156,185,225,151,247,31,38,225,213,141,49,118,204,10,133,34,138,237,81,219,119,109,234,176,49,254,161,54,101,46,179,29,234,179,137,227,219,182,79,130,36,229,101,25,71,41,243,253,176,50,98,35,118,193,60,151,81,207,241,29,159,218,158,207,208,150,17,194,136,199,92,234,216,62,115,131,185,40,147,56,226,190,29,94,125,28,163,145,93,121,66,112,66,199,204,241,28,70,108,194,28,116,69,125,223,161,158,235,219,147,241,56,72,248,131,146,121,214,248,146,148,50,26,222,83,47,68,206,79,79,79,22,117,72,205,192,65,48,74,28,164,74,113,143,56,204,163,238,132,76,92,159,250,196,70,112,215,35,110,240,192,11,190,30,150,238,62,43, +221,35,129,84,2,33,174,126,162,212,67,147,241,104,124,65,29,15,133,250,182,227,250,30,65,231,140,49,219,102,212,102,147,9,115,199,174,23,172,4,159,139,34,142,254,254,252,207,219,95,126,191,254,99,10,81,105,135,112,187,78,129,103,115,144,107,190,20,144,202,82,129,142,43,172,133,90,229,243,242,50,142,74,18,66,181,208,240,125,48,195,95,52,169,22,125,45,184,33,16,189,37,228,154,144,27,131,88,196,98,174,107,66,147,153,118,31,149,193,231,246,223,202,99,92,193,177,16,166,50,91,166,2,150,105,126,207,83,144,89,169,120,150,8,200,23,154,86,205,67,150,128,75,158,72,174,196,28,30,165,90,129,224,201,234,148,240,227,74,226,118,33,30,10,81,138,76,149,144,228,153,194,15,21,156,37,17,111,33,209,23,230,95,46,51,68,186,255,214,64,52,59,133,5,239,52,206,67,145,111,37,110,2,47,10,254,109,118,157,202,47,2,120,146,8,60,83,57,168,85,227,85,179,68,128,210,130,79,57,94,248,107,35,11,161,137,239,132,44,242,2,48,221,74,38,155, +148,23,39,148,71,144,240,20,175,35,215,189,222,58,238,214,65,220,221,110,220,63,162,60,53,51,102,102,208,19,249,109,46,231,187,72,239,98,142,73,210,86,187,19,195,108,83,160,247,203,211,104,54,74,219,24,238,194,38,179,90,245,62,108,195,76,127,19,234,93,190,201,52,89,4,42,85,112,192,180,165,34,51,53,80,41,200,186,69,232,222,48,204,125,53,105,220,189,24,181,41,178,82,51,207,54,235,123,81,236,179,84,49,111,115,119,158,243,237,124,102,32,171,131,0,223,85,39,83,85,96,185,222,65,189,246,6,89,27,239,131,28,159,230,231,64,237,129,165,13,114,183,107,246,137,193,122,204,148,92,200,3,65,192,85,75,239,170,3,96,197,103,213,245,106,211,136,119,53,240,144,178,255,67,87,191,146,51,233,249,85,102,152,29,157,244,125,78,102,151,175,173,175,10,238,168,182,142,42,171,223,244,176,32,234,163,110,85,212,123,179,203,78,40,142,60,13,21,113,197,169,142,206,67,94,202,106,238,236,115,174,219,223,82,110,69,214,137,216,60,182,118,97,205,196,146, +43,188,1,91,158,110,176,114,22,144,229,10,59,209,38,59,215,84,166,109,97,140,118,177,213,30,171,208,190,168,207,76,255,115,161,140,160,199,172,147,140,163,60,244,22,239,81,236,215,203,211,66,252,176,21,197,99,129,163,244,92,45,246,190,170,102,25,135,141,209,217,177,137,203,167,21,118,217,238,5,156,46,85,15,93,200,166,169,234,153,118,140,22,116,18,6,56,85,112,148,192,44,8,162,70,120,122,167,199,233,236,18,162,155,122,178,26,102,216,121,103,56,16,23,162,16,213,52,194,150,94,141,153,252,254,79,145,40,61,155,234,74,58,238,253,86,175,215,232,40,137,218,163,126,63,70,116,146,40,136,250,90,166,166,169,203,213,124,61,54,36,43,94,196,48,187,58,132,170,190,75,240,53,102,79,79,82,195,180,42,99,35,106,30,135,249,2,69,187,137,99,244,3,183,231,198,16,104,159,240,22,249,246,72,80,227,181,170,179,65,111,183,173,142,65,25,167,143,160,245,247,114,111,63,202,215,112,170,94,11,246,125,53,213,171,169,91,12,166,117,216,76,11,161,191,183, +205,161,57,135,120,189,65,230,226,107,245,28,228,225,227,120,190,136,116,83,212,18,166,103,98,63,130,65,109,157,88,52,202,214,3,194,166,251,100,141,106,242,235,239,41,244,51,28,79,115,86,254,112,178,229,43,201,214,95,95,7,222,164,62,180,154,163,248,95,62,13,49,222, diff --git a/uppdev/Draw/srcdoc.tpp/DrawOutput$en-us.tpp b/uppdev/Draw/srcdoc.tpp/DrawOutput$en-us.tpp new file mode 100644 index 000000000..a822a3004 --- /dev/null +++ b/uppdev/Draw/srcdoc.tpp/DrawOutput$en-us.tpp @@ -0,0 +1,160 @@ +topic "Draw"; +[2 $$0,0#00000000000000000000000000000000:Default] +[l288;i704;a17;O9;~~~.992;2 $$1,0#10431211400427159095818037425705:param] +[a83;*R6 $$2,5#31310162474203024125188417583966:caption] +[b83;*2 $$3,5#07864147445237544204411237157677:title] +[b167;a42;C2 $$4,6#40027414424643823182269349404212:item] +[b42;a42;2 $$5,5#45413000475342174754091244180557:text] +[l288;a17;2 $$6,6#27521748481378242620020725143825:desc] +[l321;t246;C@5;1 $$7,7#20902679421464641399138805415013:code] +[b2503;2 $$8,0#65142375456100023862071332075487:separator] +[*@(0.0.255)2 $$9,0#83433469410354161042741608181528:base] +[t4167;C2 $$10,0#37138531426314131251341829483380:class] +[l288;a17;*1 $$11,11#70004532496200323422659154056402:requirement] +[i417;b42;a42;O9;~~~.416;2 $$12,12#10566046415157235020018451313112:tparam] +[b167;C2 $$13,13#92430459443460461911108080531343:item1] +[i288;a42;O9;C2 $$14,14#77422149456609303542238260500223:item2] +[*@2$(0.128.128)2 $$15,15#34511555403152284025741354420178:NewsDate] +[l321;*C$7;2 $$16,16#03451589433145915344929335295360:result] +[l321;b83;a83;*C$7;2 $$17,17#07531550463529505371228428965313:result`-line] +[l160;t4167;*C+117 $$18,5#88603949442205825958800053222425:package`-title] +[{_}%EN-US +[s2; Draw&] +[s0; This article tries to describe view of the Draw object`'s role +in the painting process.&] +[s0; &] +[s0; Please remember: Draw is not the raster image itself, much the +less encoded in a particular image format. I believe you would +do best to think about Draw as a channel or a toolbox interfacing +the painting routine (a part of the program which wants to paint +something; for the time being let`'s ignore the distinction between +drawing vectors and rasters) to the actual `"canvas`" being painted +onto. The main role of Draw is exactly to turn your logical drawing +commands (e.g. `"draw a line`", `"draw a bit of text`", `"draw +a raster image`" etc.) into something the output `"device`" can +understand.&] +[s0; &] +[s0; Now, this is the general story. In reality there are basically +two families of Draw`-related objects sharing many common traits. +These are:&] +[s0; &] +[s0;i150;O2; raster`-oriented Draw objects: these normally include +the Draw object in the Ctrl`::Paint override, the ViewDraw, the +BackDraw, the ImageDraw `& ImageMaskDraw and sometimes PrintDraw.&] +[s0; &] +[s0;i150;O2; vector`-oriented Draw objects: DrawingDraw, WinMetaFileDraw +and sometimes PrintDraw, and also (normally) PageDraw, PdfDraw +and Report.&] +[s0; &] +[s0; Although some might prefer to explain the characteristics of +the above objects in abstract terms (with multiple references +to `"you don`'t need to know this and that`" :`-) ), I choose +to be honest with you as to how they really work, because I believe +that`'ll move you the farthest along the way.&] +[s0; &] +[s0; Actually the Draw is something like a semi`-intelligent painter +with a plentiful palette of logical drawing objects; some of +these are by nature vector`-oriented, like lines, rectangles, +polygons etc., some are naturally rasterized, typically Images, +some are a bit of both, especially text objects.&] +[s0; &] +[s0; Now, when the Draw receives a command to draw something (in +U`+`+ terminology, a drawing operation, see the host of xxxOp +methods in the declaration of Draw), the painter for the desired +output device has to decide what to do with it. Typically, when +the object is of the same type as the output medium (both are +vector or raster), not much work has to be done. When the source +(the drawing operation) is vector`-oriented and the output device +is raster`-based, the vector object has to be rasterized.&] +[s0; &] +[s0; Typical raster`-based Draw objects are related to painting into +windows and images; the Draw passed to Ctrl`::Paint by the U`+`+ +windowing mechanism is such a case, as well as ViewDraw, BackDraw +or ImageDraw and ImageMaskDraw. All these drawing objects use +the MS Windows or X Windows mechanism called GDI to channel the +drawing objects to the built`-in rasterizer which (perhaps using +some graphic card accelerator in certain cases) ends up by modifying +the desired pixels on the target device (the Ctrl area or the +Image).&] +[s0; &] +[s0; By calling the other Draw classes `"vector`-based`" I don`'t +mean they cannot cope with raster data. I am perhaps a little +abusing the standard notion of the word to emphasize the fact +that the latter group can manipulate vector objects directly, +without rasterizing them first. So, for instance, DrawingDraw +and WinMetaFileDraw are used to generate a serialized representation +of the executed sequence of drawing operations, which can be +later `"played back`" thus reproducing the original drawing.&] +[s0; &] +[s0; Notice that in the above cases there is no actual `"canvas`" +to be painted onto. Both DrawingDraw and WinMetaFileDraw merely +maintain a data stream which is used to record the individual +drawing operations (coming into Draw via the xxxOp member functions) +without actually caring about what is being drawn very much. +This is also the reason why you cannot read rasterized data from +such types of Draw: if you call DrawToImage, for instance, for +a DrawingDraw, it is sure to fail. But then, even if you call +DrawToImage for a ViewDraw, you cannot always count on getting +the correct image, because in situations when a portion of the +window is obscured by another application, you`'ll get a snapshot +of this other application and not your window.&] +[s0; &] +[s0; The main advantage of DrawingDraw compared with ImageDraw (if +we choose to see these two classes as two different means for +creating a drawing which can be stored afterwards, perhaps to +a file or a program cache) is that it can later (upon play`-back) +reproduce the original vector operations (like lines or polygons) +exactly even when size of `"painting`" is rescaled, without blocky +artifacts inevitable in rasters.&] +[s0; &] +[s0; To sum the above into a few practical guidelines, please try +to remember the following:&] +[s0; &] +[s0;i150;O2; To create a recording of an image, use DrawingDraw or +ImageDraw (see the above distinction between these two). E.g.&] +[s0; &] +[s7; DrawingDraw ddraw(100, 100);&] +[s7; myobject.Paint(ddraw);&] +[s7; Drawing dwg `= ddraw.GetResult(); // dwg is the output recording&] +[s7; &] +[s7; Image img(100, 100);&] +[s7; ImageDraw idraw(img);&] +[s7; myobject.Paint(idraw);&] +[s7; idraw.Close();&] +[s7; // now the Image has been modified by the myobject`'s drawing&] +[s7; operations and can be e.g. saved to disk&] +[s0; &] +[s0;i150;O2; When using DrawToImage, you should take care of the +above limitations. In particular, it is not always wise to use +DrawToImage on a Draw which is not entirely under your control. +To make the long story short, you`'re all right with ImageDraw +and perhaps with BackDraw, but scarcely with anything else, becauses +in most cases you cannot be sure what you`'ll get (e.g. with +ViewDraw or PrintDraw). In certain cases you can be sure you`'ll +get nothing at all (e.g. with DrawingDraw).&] +[s0; &] +[s0;i150;O2; As concerns the difference between an Image and an AlphaArray, +logically there`'s none (both represent masked raster images). +Physically there is a lot of difference (you can view this difference +as more or less optimization`-related), because the AlphaArray +is a physical matrix of pixels maintained directly by the application, +whereas an Image is (at least sometimes) a logical bitmap object +maintained by the Windows system (this is especially important +in X Windows, because the AlphaArray is stored on the client, +whereas Images are stored in the X Server). Another difference +is that you can create an AlphaArray in any pixel format you +want, but the supported pixel formats of Images are (or can be) +limited by the properties of your windowing system.&] +[s0; &] +[s0;i150;O2; As concerns image storage in the various standard formats +(like jpg, png or gif), again these formats belong neither to +the Draw object, nor to the Image object. It`'s best to see the +ImageEncoder`'s as mere data processors which receive a raster +input (an AlphaArray or an Image) and produce an encoded linearized +image as their output (this is obviously the encoding phase corresponding +to the Save`-routines; with the Load`-routines, the situation +is vice versa). Therefore, as soon as you have an Image (or an +AlphaArray), you can Save it in any format you like. Similarly, +you can take an image file in one of the standard formats and +read it into an AlphaArray or an Image.&] +[s0; ] \ No newline at end of file diff --git a/uppdev/Draw/srcdoc.tpp/DrawTutorial$en-us.tpp b/uppdev/Draw/srcdoc.tpp/DrawTutorial$en-us.tpp new file mode 100644 index 000000000..c02bef28b --- /dev/null +++ b/uppdev/Draw/srcdoc.tpp/DrawTutorial$en-us.tpp @@ -0,0 +1,965 @@ +topic "Draw tutorial"; +[2 $$0,0#00000000000000000000000000000000:Default] +[l288;i1120;a17;O9;~~~.1408;2 $$1,0#10431211400427159095818037425705:param] +[a83;*R6 $$2,5#31310162474203024125188417583966:caption] +[b83;*4 $$3,5#07864147445237544204411237157677:title] +[i288;O9;C2 $$4,6#40027414424643823182269349404212:item] +[b42;a42;2 $$5,5#45413000475342174754091244180557:text] +[l288;b17;a17;2 $$6,6#27521748481378242620020725143825:desc] +[l321;t246;C@5;1 $$7,7#20902679421464641399138805415013:code] +[b2503;2 $$8,0#65142375456100023862071332075487:separator] +[*@(0.0.255)2 $$9,0#83433469410354161042741608181528:base] +[t4167;C2 $$10,0#37138531426314131251341829483380:class] +[l288;a17;*1 $$11,11#70004532496200323422659154056402:requirement] +[i417;b42;a42;O9;~~~.416;2 $$12,12#10566046415157235020018451313112:tparam] +[b167;C2 $$13,13#92430459443460461911108080531343:item1] +[i288;a42;O9;C2 $$14,14#77422149456609303542238260500223:item2] +[*@2$(0.128.128)2 $$15,15#34511555403152284025741354420178:NewsDate] +[l321;*C$7;2 $$16,16#03451589433145915344929335295360:result] +[l321;b83;a83;*C$7;2 $$17,17#07531550463529505371228428965313:result`-line] +[l160;t4167;*C+117 $$18,5#88603949442205825958800053222425:package`-title] +[2 $$19,0#53580023442335529039900623488521:gap] +[t4167;C2 $$20,20#70211524482531209251820423858195:class`-nested] +[b50;2 $$21,21#03324558446220344731010354752573:Par] +[i448;a25;kKO9;*@(64)2 $$22,0#37138531426314131252341829483370:item] +[{_}%EN-US +[s2; Draw tutorial&] +[s3; 1. Basic drawing operations&] +[s5; Draw class is base class representing graphical output. It is +intentionally designed with quite limited set of easy to use +drawing primitives. Unlike most of other similar classes in competing +toolkits, U`+`+ drawing operations are [*/ stateless] `- there +is no separate setup of e.g. line width, pen color etc, all necessary +painting attributes are parameters of respective methods.&] +[s7; #include &] +[s7; &] +[s7; using namespace Upp;&] +[s7; &] +[s7; struct MyApp : TopWindow `{&] +[s7; -|virtual void Paint(Draw`& w) `{&] +[s7; -|-|w.[* DrawRect](GetSize(), White());&] +[s7; &] +[s7; -|-|w.[* DrawRect](10, 10, 60, 80, Green());&] +[s7; &] +[s7; -|-|w.[* DrawLine](100, 10, 160, 80, 0, Black());&] +[s7; -|-|w.[* DrawLine](160, 10, 100, 80, 4, Red());&] +[s7; -|-|w.[* DrawLine](160, 40, 100, 50, PEN`_DOT, Red());&] +[s7; &] +[s7; -|-|w.[* DrawEllipse](210, 20, 80, 60, Blue());&] +[s7; &] +[s7; -|-|w.[* DrawEllipse](310, 20, 80, 60, LtBlue(), 5, Red());&] +[s7; &] +[s7; -|-|w.[* DrawArc](RectC(410, 20, 80, 60), Point(10, 10), Point(450, +80), 3, Cyan);&] +[s7; -|-|&] +[s7; -|-|Vector p;&] +[s7; -|-|p << Point(30, 110) << Point(60, 180) << Point(10, 150) << +Point(70, 150);&] +[s7; -|-|w.[* DrawPolyline](p, 4, Black);&] +[s7; &] +[s7; -|-|p.Clear();&] +[s7; -|-|p << Point(130, 110) << Point(160, 180) << Point(110, 150) +<< Point(170, 120)&] +[s7; -|-| << Point(130, 110);&] +[s7; -|-|w.[* DrawPolygon](p, Blue);&] +[s7; &] +[s7; -|-|p.Clear();&] +[s7; -|-|p << Point(230, 110) << Point(260, 180) << Point(210, 150) +<< Point(270, 120)&] +[s7; -|-| << Point(230, 110);&] +[s7; -|-|w.[* DrawPolygon](p, Cyan, 5, Magenta);&] +[s7; &] +[s7; -|-|p.Clear();&] +[s7; -|-|p << Point(330, 110) << Point(360, 180) << Point(310, 150) +<< Point(370, 120)&] +[s7; -|-| << Point(330, 110);&] +[s7; -|-|w.[* DrawPolygon](p, Cyan, 5, Magenta, INT64(0xaa55aa55aa55aa55));&] +[s7; -|-|&] +[s7; -|-|w.[* DrawImage](40, 240, CtrlImg`::save());&] +[s7; -|-|w.[* DrawImage](110, 210, 80, 80, CtrlImg`::save());&] +[s7; -|-|w.[* DrawImage](240, 240, CtrlImg`::save(), Blue);&] +[s7; -|-|w.[* DrawImage](310, 210, 80, 80, CtrlImg`::save(), Blue);&] +[s7; -|-|&] +[s7; -|-|w.[* DrawText](20, 330, `"Hello world!`");&] +[s7; -|-|w.[* DrawText](120, 330, `"Hello world!`", Arial(15).Bold());&] +[s7; -|-|w.[* DrawText](220, 330, `"Hello world!`", Roman(15).Italic(), +Red);&] +[s7; -|-|w.[* DrawText](320, 380, 400, `"Hello world!`", Courier(15).Underline());&] +[s7; -|`}&] +[s7; `};&] +[s7; &] +[s7; GUI`_APP`_MAIN&] +[s7; `{&] +[s7; -|MyApp().Sizeable().Run();&] +[s7; `}&] +[s7; &] +[s0; &] +[s0;= +@@image:2420&2314 +ρǜ݋͂ӶÂģⱽۑͤ㙌ȱ㙐 +段퓍țն׀֞⋄ȃӣѨߩ +ӣԒꦡ׵ےжƜ֌ϑ̚Ŧڅ +ڗǥҧåݳǂ凊ëݏ +¯ӻ񐳗֏ڧήεϾ鷌ЎϿ +쿐Ɨ͕η՗ƌݳǷՋ液̸꼢 +ȼ߆Һԋ֮͆᚜̑ݙ +׿ϫںߙϨʟᄀ˳߲ˉύߕīĽ +՛ԙܙޘ۱鷌񭼳켾Ї +½竺իўծƮƓӹϝ͍㵞ܸ럹 +Ϯ󁳟ݙϫܟ۵Ჿțˇ +Ȫ޾ӱ߁ы׺嘀㤏ұڇا +ו߹òỿ򇇾ЭӋݳ̊ߜ뿺Ԭ +Թطſôę甧Ǒҧѫɯ׿߼Ϝ +Ǿ׳ٻǾޝϬγតۿ휭ԯܝ +ܽվң׈̹֒Ϡ웳ŏӯݢ싟ܿ蟯׹ +˗գǯ꽺ˉծٌ +ϐð׌隞ǝ˷ٝ½ռϪّ +ݳغθͰ޿ǿɦՅůٶ÷ +ߪώ鯺ήڭ熄ä̦ƭի +—ǼʡǖϷρܮߍٽꮫ +۽蟮趫Ж󆟻Ϋ䇔 +պǫɟѝ޽ɵð֯ק֍㖛Їѵ·ǖ +经߂ʼԏժ֟ᘦݯˇƷ +ڽ͗伣˱󟾹ə鵎Ңʕ +劻ͤی򌻭ݣ֍ݸȽ˝߈Ĺբë +ُܿϗ֋ۧúЗގʱߘ +ܸƥϚѥĭ +κڷ܃׎ޝݯΌݙ톼ı +ˑݯݸȽݓέ͚ӟ׌˟ۧΫ +եݙ٩뷕ᘘغοÇƻ㝓 +γǗ釮纮گ֗η܌߻ߢǭ㘆Ӭ +ʱ׾ퟜʖ츢ǢѣĿڽߙǧ +щݡӽԥ׳Ͱ֩ݫ峞蚅׿ +ЯᱏѭǏ +ѓܽ檁޲뻆ڻ +ᵗܲ۽ꏇ߰җֿյ񩷺 +ǺðХſϚٹÝ环çٲ +ֻ֭뉕׌៿̏ +מ柸μ㴧ϯʤ֟ +Փ穚ՉðοՙϽ͹ߞ˷ +颷̹廗瞻οƫ࿲邇ҺȞ +˳œԧĤ՞֯ۙƉُͯ蘩 +͚̔׹ӥު߫߸צ鯜׫鵓稯ݹ +̿ڙԺһꕐᘦ队ϟџ̙ +֏߆̦߹ו‡ծ᳍ؤșԍځ +襵贙Հ蔵ǫڍꦀփմǻʳ +큐緦ūۓƫԴֺΝȵϫٙ҃ȧ +؝ڝχ䞀ܓꠃЃؓׄ׼ݡЯ؟Ƕ +ʵϟʂϗۛۏҌȱ鸇ʇ׬Տ赁 +࡚󧆱くӟ΃з礒Ùӌ衑׺ƨ侑إ +ꊲͷå҉әؿϪΈɥە䉜ϵʓ +ǣՉ񟓌ɑٲ۳힊ҼѭŶ֨ +ܝ̮ǫ͟ݔփرՖޝƩ̮ +ڦױ熎ܝݔ֋̮ūퟷǎۃ깠ۿ❄ +ϒ׷Ƽܧ҈֖ˠퟴΒ˙«Бܝ阄륥ɡ +ǯå赨ᙷĸ店Ɲ޴ښ廲ۗۿֺ +˾܍ՂɃȯݓռ뭞΍Ǒٸퟸ +ӚӸԷ赬˞ճ˯ڭ֭هُ +˔ۣف˞ցꉼɇٿЌ̳֝Սꔍ +̔ɳ堘ӯß̿媟빶熬֛̾ʗ +ܴ佧ڌڭйȵč഼䎽ڌڭĔґּ̳ʫ͠ՒĿ +좩ϩѨ겝̈́ʳթލݍ +̫ퟨߦɽ乹ѥՆ׷϶ܷ勼轪ڀ +ڛؿ֒ƭ·ѽȵ٬ϱҭ鴙 +򝪉뗥ݓϓ޴֛ҙ˵Æ뻋֧Ļ +ཱɄڗֿژŮֳիŔ鵙ɝٞ쨋ꃒ +᪩ۙ״ګܫ˛گ«Ҙؿ콽 +Қ֧̿ȵٶޅڕӓ䘾۹лÅÑ +ښϔ쉇ɭ䗽љ쬟ԖݔܪۻƑ +֓ϩԔ΋סÂ̒ɵʃðҞ +ΣХϼўċśǥ̧͊ȵۍڎåť +ïֱַŇ뻱Ĵռјܫˡƻꦥ +эթ韛ƫل«ϫԀ􋞨ڍꀐփՀ +뵀ڍꀐփȀꀓʭΥ蔵ǫڍ +փՀ贵ǫѽ␎ۭ҆ƥȡ򍸄 +ßѪȕȾʳϱťҺ՚āʩڭ +ӫ÷ߥ֓눢纷ѵϻ֗ׯہŁו쫹 +툭Šլ홬ϺҺݎ۩庖亊ڝ +ŦÀ֗ײ񗵺γڟ椠թ¥Δג +繎ʍҺ⺍ש틬ǥҺ剌ɝ䴚չ +ғܕߕ֓벨Ⱦݿ۝Ի󾲈֧ +Ӡ唧ͮӚՔӠ뾤Һʡ㑸ˋ亊Ք +ݿ¹쵹ʈŖǣ«꒐ժ +ǾʝϫϝΫ¯Пޓ򫋬ӷ֯ +Ƞչϵ螢ټޝԽ󫣮إ +Ϯ̥ö´ҺձԺӾūت +̯˲ڲ㥳뤪ե˫뤪쭭˗Ěʡ +֛̭ɷۏΪӠɯΫʧ殪 +ይ궃ևꏩĵ٬¡֗ɜݴĤߤ +ֺ׸ۍꡌП߯쌵ŮИɔŻ +Ǣڧˋ؉х詑ԉؙ̦ևȨؙ +஦ʤĪŒ亳̷ľӢ޺ݥ켬 +ʤʲҠ򝚮硿序ʦ孮לΊիݴĬ򲯄 +ŮӢעܧ̺ſͬ +֟Ήö򱙱Ӣᚑ뤌« +鵋܇ʤʊѭӥ괺ωݯ燹خܣт +ݰŦĔהӢ쫓Ķڕ얏ֵӖ԰⽹Ґ̢גȖﵫֱ +աꗉٔʵևѱӯݫ庱亄ퟢՍա +쫓񞨱՜ȂՈڍēǾʔ赀ǫڍꀐփ +䣑Հ赀ǫڍꀐփ䣑Հ赀ǫڍꀐփ +䣑Հ赀ǫڍꀐփژΌ쟳ó +ĉߎ쳯«ɧٳ馽 +ǎяאƽȣݙ۶ݻ釥ק׶镵ۣ +ٶյ齫߯󫿠̯… +臢ԁݮژرïԦܸƍ۷߻ٱ +ܟݭꖥ檵۩Ҳٳ緵뫾뽁 +֛򜥺Ԫש΁Ν֛֯֔Ҝ +ɩ٬몮ڍӦ͏ߌ鵄ԧ赱ַוҺԻ +֗ˏޞΑЦЩݩκז +۫ڋߌϔ鵄赱쵻˻ܲ傋֎ +Ŝ焭Φܹߨ꜠Ƥխ䭺ޮџڎ +ݝژܺ粄ڭΉ̺۞˕ڂڝژͶ엫鵢赱د +갍Ւ꜠꤁犄֣Ѵ赱̚ɠչ獡Ȃΐ팭ƒ +̛ëڝژڍ꜐ō쀭赭 +ͣڌֳ΄ևТچއچևچև吟ޫ +ҞڼΝزեөղߐث߬ +座ǯǧýݠڤڼڭΉҫ٠۝ڨʵĸֹ +󭗸í֬ɬᣴڦڝկеԟ޾ߩ +떖ڰ餴Ѵڢڝژմ꜠Ƈɯϋںڝ݌ +ˍݛٟۛڝ۝ɪˍڝɴ赱ˍ⢭焭 +˜ڭΉ҃ڛءմ躧赱غ׏ʣÐ +꣭dzū֛ӣ⬼Ƥيū֛ +խΜہۂ믫Ɓθޥպї͙֬ +ɫšչӢֵ޵͛ټ݇焭ȫه̏ +ɫšչ䘯ῷմ赱չȂΉڄ팭ƒ赒֛ +ӫڝژڍꟜՁ焭֣嵱ɠʹڝڍ޽۶ +ە磝׳˧ПܻԖ;޼㯯Ν٩Ւ +֯Ϝ߹دϞҹ։ټٶٛ +ŋǑꉘܳ׮띸Ǻܹ͚ +赎ԹխП誥ҳ󵙳ɝگ޿雺 +ݪڭˇ֫˫īġЫ냇ζ˖ϭ߾񢋖 +էѝܥӾچ㷊ѝ +ե՞ն̟ڭІޮՁ赭랗Æ۷޾ᄃ +ۼǟܿٻ垗Ӕпۻƪۮíšа +܇ڿۻӐƴۣ߿؊Δۯҟ򠴚Ȁ赀ǫ +ҫߣՀĆ赀ȂǫڍꀐփՀĆ赀Ȃǫڍƀ +Ć赀ȂǫڍꀐփՀĆ赀ȂǫڍҶٴ仃״ +Ϋզփת֘ëȫאڍꅔ㡮ꀟ餪ޖ赀ʮӞڍ +َͫݝŴؑЗ鵀҆ˊūꢭۛג +˵՟چۗ֏׆ן率 +ϪͪҞڿꆏЗު޿竁ߞסƳݔ +èꐫǭ鏪ǻݻ +뿺郏՟ߎê쀻ͷױޠџҔޝގ +͟ݫޑۢ⿒߻ӟϻλ +ϡ՛̢򯽓Ӝ¶揔ܹՁÿ +ʥ◿鞸㥍ڭݕܯї캫穽܎×Ҽ +шճזڷȅЇɏݨޭ +ʉȨյҹ躹ǹϭ崕Ύז݅୻ +ބ߽׋ڻݪݕ咩㕞ޚ瘃꭪ۈٌ +֡īїҬ嶪ڽ幐؞ߑʴ꾵ߩ +ע򤇮›ʵԺ +ۼߞ􈇞Ԧī‡儼űĔ잔턷ѐ揙 +Đݡ赀קѯôˤϛϫϛՀṕҭҢ곿ƫج +͓փʁĖݭć螵փ놭 +Αփǫؖ«ƫՀ̢ҍՀەɞϘփÒͫ +ߋփ∬赀߰֨٦Հ„ҔÍ˓ڍ˨ūĔđ +ЧփҜ¶փ뭄ڼڍڊڍ¨Հ赀ᯣ +ԄԘʛڶ޿փ򆞄ڔڍî꠷푭𝧽먥߈赐 +­™ȷ͆ЈڍӞЇ赐ؓ +ȉռ˭փ̕ýȼ󞡄ڸڍ䜡΅ڍ䙡΋ڍ䖡Αڍ䓡Ηڍ +赀ǫڍꀐփǴąꀐʃ䣣Հ赀 +ڍꀐʃ䣣Հ赀ٴ䣢Հ赀ǁڍꀐ +ʃ䣣Հ赀᫁ᒞӍϽÆ͹ +ԣ…䬎͊߃ގ͎Żˣƃۿ +獬ሓݝߑԔćӗ㜴ӏ̾㚁םߜֿ +ðό +&] +[s0; &] +[s5; The examples shows the full range of drawing operations in action.&] +[s3; 2. Offsets and clipping&] +[s5; You can offset the drawing position and clip the drawing operations +to specified rectangle. Offsetting and clipping in U`+`+ is stack +based operation `- [*/ End] method restores the previous state. +Particularly important is combined offset/clip operation [*/ Clipoff] +that in fact creates a new Draw for subregion of current Draw +area.&] +[s7; &] +[s7; #include &] +[s7; &] +[s7; using namespace Upp;&] +[s7; &] +[s7; struct MyApp : TopWindow `{&] +[s7; -|void DoPainting(Draw`& w) `{&] +[s7; -|-|w.DrawEllipse(0, 0, 100, 30, WhiteGray(), 1, Cyan);&] +[s7; -|-|w.DrawText(0, 0, `"Hello world`", Roman(30).Bold());&] +[s7; -|`}&] +[s7; -|virtual void Paint(Draw`& w) `{&] +[s7; -|-|w.DrawRect(GetSize(), White());&] +[s7; -|-|DoPainting(w);&] +[s7; -|-|w.[* Offset](30, 50);&] +[s7; -|-|DoPainting(w);&] +[s7; -|-|w.[* End]();&] +[s7; -|-|w.[* Offset](20, 100);&] +[s7; -|-|w.[* Clip](5, 5, 40, 20);&] +[s7; -|-|DoPainting(w);&] +[s7; -|-|w.[* End]();&] +[s7; -|-|w.[* End]();&] +[s7; -|-|w.[* Clipoff](10, 150, 60, 20);&] +[s7; -|-|DoPainting(w);&] +[s7; -|-|w.[* End]();&] +[s7; -|`}&] +[s7; `};&] +[s7; &] +[s7; GUI`_APP`_MAIN&] +[s7; `{&] +[s7; -|MyApp().Sizeable().Run();&] +[s7; `}&] +[s7; &] +[s5;= +@@image:1287&1425 +΀䀀ǜ흋ǣǢȶIJȼȂђàܮĸ +ɥªӵᘛʿԹҹ¸Ѣˏۻ +ªƏ㧯ߪ咽ިԅʊʚ揭 +Ë֒饽Ңٻ矺ԗǂijɬЌ +٫ސ܆٤ԚͲ٦Ϣұ +Å۪ڵҸɋͽҮϲݘȡ݆זȗ +ФҜ箣ͮݕ淐Ú۾޷ƫȩ鑻ݾȁ +Ĭ̫ؑͭ蚐ӿƚǡЀޙ㕃Դ˫ +ѽȇ͵Ź٘Ȱݟӎ҉씋ԅ +߹ɵۂڄ럝չ͝ΡТ +̛Әݜиʆƺ尺髇ϭΕ˼ۗ +誯ܲ՞͍ךܹƱ߶䒛̈ƺƺ +ΰ㝴֩Ǟ۽ί󻻿̖Ζ +Ƭӣũނᛖ杪Ĵ穚ý +ۿλܳ庹Ϸͬ阆Е؟ɓ +ʘƥʳӂׂ׏ϟɁ󶯦㢮 +ϕ瞜眉̚ߦǙ̟ʡުǩꊡڶٓ +ߕ͚ѹފȴꢒ҂Ż睊ԱδέÚ쩁ͺ +Ӡҝ孋ж협ڴڭʖȧ͸݆ +ڹ庫ּĴ¶ڴ줖澾ڇϴ +קծਬُŤβǻݏ獖۴Βڠ͛қϜڟŚ嚞ֲ +ħ͞Ԓ糜ܣţξ؏̣ʟ頜ڏ +䘉լ¡эІ۷ڑ۰۵ť۱ +ڱ̈́¦⤱ݚܬͤ͢袹ڬĮӟ۬ +Ԩڴ͖ܬӊҦϑٰ͆ +̦֯ٱȶᐵל‘߾ۮܳɦİ⺒ +߱ʳԧ鋃ҙڃ̃ĴƔ顀Ĺ盳í +ߞ͋ۢ篞ݮ壨ږٴ٘и½ՌΓ +ȷÂؾے̪Ł̈ȶþdz髮 +̭ٗ߂ݎ痌ܹ㽿 +͚̚Ԧɽ̙۩ᏙҘо +ԍ䃠뎰˔צϖÑិɿ넆 +⡸垚̫Ĵř銆쭍¡ߗƼ電Ծ +ѳ˽߽ɞûޕޥü݅ɶʆ޳ڤԦ +樰öΔٺل֕魝ďʧ۾ѯ痌В +ͣנᤤܹ˿ +伝ްͼڐߞ⬔י +Ľ݆͆łȏٵߢܕ +ϱı˩ήܪف省Έ殧Ű +Ãϰަɭےȿئͤӫ²ߴ +丯Ҹꔽő¤̠엱ʓސڴθ +ͪݳĐ藞ش㗞󜵨̻ׄ۰ӊۥӯۃ +֡׾ڤŸͻ֬ȷͥӨѽɑ̋ +Ҿ蕭ܩ餳ȅ샹ӴǴ̃ϴǎͥ +˰½墹ƌЗ +ͽڨڞ缶֨Ęހ𖪷۶ͫ߮ƶԿ +۵ː̬߄ÖݫҊ컚Ǭĥ +Ĥ܊ͯϭѣٕƒœ蛂傰ɉ떸̳ +ӫׂݬ̘˘緄朑¸ф´ތ̋ڱ +׍قޑ͚廓޶ͱߦҍ÷Əآ˚̔ٻ˱ +ϖ׬ʁڑˋݤ띥٤dz֞ХÐ͛Ӥؤڙ +ʏɌ߈ݺ柌ʰ쀍깫֕Т̙ӌ +ۿψ̗鎾귓ŝϺņ庄̓ݴִï͆Έ +nj젂dzꉘ݋߬ϷӀšʘڙ +ë骹ʑ鑌̏ꑶޑ俷 +٠𜛐ǹݝۥ܉ɏݫŸÔЯ‡ڨף +紭ȫЫѐӴ銺ȉϴ䜭򣶃؏ԃ +Е򏥠Քƾсˣ遷 +߅˘Ĉဓ̻҃Ỻ𴍑ĀӐń +Ӯд鈘дČ蚢̍´҄芚дČ蚢郌ǐ +Ϻݕւʮͫζ҃Ʈ߰͠ӆ㶼ķ +𿇫沿ޏʷʋɩﱟӛٜɝд՝ٮӤÚ +ͽö稍奲ʹ鱙ҟ󾌞ِݴö꛲ܟ١ +򤾹ԄʎƲߤŶٳԶ˔Ţӌ䊳䨂 +ĹҠ̳ٚ馶٢ِ⚜回ِ͚嚜 +ܛ̚öިۢϹܸ隴ȣٿŸƇߦܢ쑟貏 +ېӬ馒錪ݕ鈍̳Ȁ͎ĀӐ鈘дČ蚢Ā +ȡӐ鈘дČ蚢ĀԐ鈘ЀČ蚢贍ՋΘ +Ø祶ãьިڸ򈜳Ėʂَ̳ū蚢 +Ɉڥ鬁ɞ盖Ėмى܄޳祙򟛖Ė‚ζ +ى܄³ѴЖښˋ⋷ɞȂ祶𓐙욜⋷ɞ +鈘дČ蚢Đ풂մɩ蚢ĀܐȦӏԂ +Ӑ鈘дČ蚢д鈘дČ蚢ڙؽ猞 +ͪ̓Œȯд쁵󎩲͡¨ΓࡉɛǨם +رپӎ륣鎤䅎άӂ㚹ӐԚӐ̨ +ԠҟΥ铉ʜ䨟祶ލݤЫ޳ىԚȆ +Ԧ יىіțŨǒ떛ꚲČ򆲤ڍ̓¦ +Ӑ酈дČ訚م蚒߰ĀӐ̘ᨇ𼍑ㆈĀ +Ӑ鈘дĂּӐ鈘дČ蚢ٲजٌ͛ +Ǭ񁟴ʸ󌢖ŊƨϽȷ +ᅃǚŗԯ񨈱궾ꊽ߯ѿ򊁑 + +&] +[s0;= &] +[s3; 3. Fonts and font metrics&] +[s5; [* Font] is a simple font description value type `- it contains +an index of typeface, height of font and additional attributes +(e.g. italic flag). [* Info ]method of Font returns the more complex +[* FontInfo] object that provides metrics information about the +font and individual characters.&] +[s5; The most important information of FontInfo is the [* GetAscent] +value `- distance from the baseline to the top of character, +the [* GetDescent] value `- distance from the baseline to the bottom +of character cell (height of character cell `- [* GetHeight] `- +is simply the sum of both values) and the individual character +width that can be obtained by FontInfo`'s [* operator`[`]] (where +index is in UNICODE).&] +[s5; To get the list all available typefaces and respective use [* GetFaceCount] +and [* GetFaceName] static methods of Font.&] +[s5; Position given in [* DrawText] specifies the top`-left corner +of the first letter of text.&] +[s5; Different than default character spacing can be specified by +the C array with integer widths of characters.&] +[s7; &] +[s7; #include &] +[s7; &] +[s7; using namespace Upp;&] +[s7; &] +[s7; struct MyApp : TopWindow `{&] +[s7; -|DropList fontlist;&] +[s7; &] +[s7; -|void Paint(Draw`& w) `{&] +[s7; -|-|w.DrawRect(GetSize(), White);&] +[s7; -|-|w.Offset(50, 50);&] +[s7; -|-|const char `*text `= `"Programming is fun`";&] +[s7; -|-|Font fnt(`~fontlist, 60);&] +[s7; -|-|[* FontInfo fi `= fnt.Info()];&] +[s7; -|-|int x `= 0;&] +[s7; -|-|[* Vector dx];&] +[s7; -|-|for(const char `*s `= text; `*s; s`+`+) `{&] +[s7; -|-|-|int width `= fi`[`*s`];&] +[s7; -|-|-|w.DrawRect(x, 0, width `- 1, [* fi.GetAscent()], Color(255, +255, 200));&] +[s7; -|-|-|w.DrawRect(x, [* fi.GetAscent()], width `- 1, [* fi.GetDescent()], +Color(255, 200, 255));&] +[s7; -|-|-|w.DrawRect(x `+ width `- 1, 0, 1, [* fi.GetHeight()], Black());&] +[s7; -|-|-|[* dx.Add](width `+ 4);&] +[s7; -|-|-|x `+`= width;&] +[s7; -|-|`}&] +[s7; -|-|w.DrawRect(0, 0, 4, 4, Black());&] +[s7; -|-|w.DrawText(0, 0, text, fnt);&] +[s7; -|-|w.DrawText(0, 70, text, fnt, Blue(), [* dx.GetCount(), dx.Begin()]);&] +[s7; -|-|w.End();&] +[s7; -|`}&] +[s7; -|&] +[s7; -|void NewFont() `{&] +[s7; -|-|Refresh();&] +[s7; -|`}&] +[s7; -|&] +[s7; -|typedef MyApp CLASSNAME;&] +[s7; -|&] +[s7; -|MyApp() `{&] +[s7; -|-|for(int i `= 0; i < [* Font`::GetFaceCount()]; i`+`+)&] +[s7; -|-|-|fontlist.Add(i, [* Font`::GetFaceName(i)]);&] +[s7; -|-|Add(fontlist.TopPos(0, MINSIZE).LeftPosZ(0, 200));&] +[s7; -|-|fontlist <<`= 0;&] +[s7; -|-|fontlist <<`= THISBACK(NewFont);&] +[s7; -|`}&] +[s7; `};&] +[s7; &] +[s7; GUI`_APP`_MAIN&] +[s7; `{&] +[s7; -|MyApp().Sizeable().Run();&] +[s7; `}&] +[s7; &] +[s5; &] +[s0;= +@@image:2103&725 +耀Ӝŵȿьƨƛچޒɮٜ +׏Ĩ٘ٳⅇʷ܁Аߞ秧ߪ +ػںƮㇳנ׹ۙ弞̐藷 +ߖԎ緻ޑ쫎 +ߢ옓ǔב딚½ä˼ +ߒѿĒ̝ɦ +汒ܟңֻƑ˿Ώʄ҃×ĒǬ޳ +ܟΎœݹ샳ˠķ +˅ܱ墻ʹՒΟ겱Ǽ +ʟŽ埽㝿ߚ׀ΩȹǦɯ߮՝ +ş񞃲م邠޸ȷѸˮ񥌳 +弧٪ָݯ˧ +㖋ljϤڧ򻮾뮸ܿĻΤܓ +ӽ߉ؿƭ߻ +ܸͽ޽¯傗怰ă +̽ͪ߿߾汩ޯ˛׵ +靷ݶ믹Ȓ͠Ó۰ΧĿΪ +ܦݏ͝޻篖йΦ܉ +˦ă﻾ݲݳʺش˶ꫳ +ןյݯӗĄƙ脲ߵܽ暿 +ʎۦ;㶙枽ij⻗ +֒߬˅ެ瞷מ㗞ºύǗ +㬊ͻ򠈂ÿķכ󞛺Ӷۛ +߸綄僒ݝכϥف÷ϖ +·߭םֵijϸϨϛױ玸㯣 +裀عϻݽ݀玫񟝍 +ƫۮϣߝߖΞ +οݽݹמߵӎ߸񓷔݉ +ڤߏş펌ѠʯУɴ⠧ +޽ݳ̾۵񻘾 +ơǧɐЧ퍧߰󎫺؁ܹ +Ϟɣēɴ݉×̿ޒʕ +ǭˮœҎ獪ߜݵ窿ҏܢ +ݯ肀遢齈鴝ɴАşι댳ϿɈߋϻŗ +͓矱ީΩ≤רəǬ +ԞΏζ۾ӷήӅܺ΅ +ډݷ×ǤНȓ׿ڼǬ循 +򉂠귗ڿ鿝̺ߵǸ޵ԝ +ʓijåŌ՞ݻן޿˼Զ +Ƿͽݕ׷֕ǽћҧӾ֍ՙΣ߾ӕ޹ +ݥ댄ѹӿמщ㞛֍ +ēӆτɷͥҬώԻ +ݑ򬾠뷻ߚߑ˖ҳ +־܍߻߻î߷ε +贶ׂς̅ɾȶϋ쳴衒 +َٛӽচ䁊񘤈̌ԟ۶󿞖ЀЀ +ɿڀ搯߄Лߺڇϼ +ˋĵ⁀̰֝۟񯷺ϮܷЛ껇캘Ƹ􋷎 +񠲼و׶ïćоȀ +󈔝Ô񀀀搐˼ۿ磌ڎ郞 +񹵇ٯ餾ƂءÍ鋿̓ʓ +Ձߙۿڇ†ğۙԞ⁀̢ރŀă +ʀѼý̫ŵȁäؾݚ +ЕמŃćȼϾ᯶詶ϟă⏪ +ȚܾȒ羶ɛڱ֞𬞀Ĥˆݓ +󠑆ѓ¯ƽ岐䅽ϼׯȹߟ߳ +ăԦó像֑ޚàȼ˼ˆ +яГԕ񀀀⁀ă +҂ʉȼЀ񀀀Є⁀ă񀀀 +Ð񀀠Ā҄鎀ʁ涸 +耀ԀĀҀʉȼ䀀ǂ񀀀ЄԿߡ +ʉȼŒLJڙָə順Ѕ򡬨Ф̀ +ⓐˈ̀٢ܱןɢޕ梮Вǔާ +Ո΄ޒɚЬ˅ӫ̦򄐀ȼްܬыί׏ٙҨ +ɓòĹ㯓ŗӻĀ炒Ɂ̀țȉ„񖐠ӑȼ +񯊑ٙҨɓòč㯓ŗӂ琂ɡ܀ˎ厽Ζ +靉ȼ˔ӫİ҄ȼްίٙۀҨɓ +òĹïŗӻ炒ɡ̀ȼߚ˔ӫʪ㭭ϝѣ +䕬֐рضȼϤƝӥê +ڞδ̚ۃ€ױ⪻ϣѶ᠖ƥϨ̚Ƀ̪֯ +դˮՔܹȼ̀砘̤̝ЃNJ刳ҽ +퍡ȂʼްضɃ֯ĐݨΙ҈񎤿牎퍡 +Փ݇ĦΚҹ鲢ȚЦև֯ +ڈ׺ՕʴڬȼяȚЈ˔وޕ +ϣⵄѤٮȼ֕ׄɫ֭ +ضȼ棆׷ߐ݄ޒ堰 +ڞˉӿڞߓ˚ڒ஋􌺞å򟾕潕鞛 +ܼѽꇨڢ؜˽ςސᴄ˄Ŕ +ٓԋ޶ٷѦÀѝؕվ +랔ۢӹߢѳעŤ՚ǥȉ꘰ +Ş﹑ȔƂԻɂ䒺ҽڦﳂ +ݾ‰ȀϥΘվͭɠҸݩࡼߧ +܃ѴʟӘά쉢紒Έ񱧉ěГߍ̙ +Ϯɡ٭喃ʾ٧ɻᓝгߩЎͼ +қáת⤎ҽ؃̀驘ЏǼǻоμ +鉽Ñޥ쓹㽉לꕕ򖼽픋¦ن +ۿߐӤڦ򎀘ݨء똵ѼϚ +ȿƵαԨзеՊ˜Ҥ߁ +ΨР礉߾ǻޥ僾ӡ +ގϸ͉һׇحῘȴ +رБځ壵¿Е񂔸鴇ƸݍԦר +͸ѯۑܾƑ塓Ѧ玝׈ēʖ +洝èӡ¿ޙ웅⃔ƨ求ҧᔇ߫ +ȶ浑蒖ꈵᄖ͍᯿Ϟɏ󘁰ʽ +ҰʮéٷģބЕ鎔쵭Րꦄ‰饞䝭 +២̵ǘ퓔ꡑ򏳗ϮƇ֩ʅք碯ޗ +沭䁤̒ѣʖ޾ť̋ᠥ鬇률݀⦌ +Թ̈́筤́沭޾͂މǡߴܣ氮Ʊ؏с +԰ޓÑ®ﵓ흱ꡝ耮ʋհյ +⦔Ϯۊ󪘐ܸ㛭;ūּ؂ӧݦ +؏ھ݇ځо쩤ũꙚɺݯ̀秜וЎ +ʝ꟣ƭѳ۶ՂƤȝŻ˅ټŋ +ƒԉŜėӏߺ㙁ڥʧ헭Թӛؽó +ш̪ρ╫ݍ΢ǩз۝׈յ֍䗲Ɠ +폓ܷύϦ벁ͯǨ矀ڸҾ肫ٍƇ֍Ԯʝ +˅ލ̀򟼗ܕƗюˋ +ҷէݫ𥊛ϥŊ󨻁ʇ͘ѩכ +Ȁأچյٛ苞ˢֳ֙ +כ޾Аҟ˴ĨԱίʺѡ͘ݩ̺ܖŠޔꓯ墧 +¿Ҁ߆ƪdžնƗ􃥂 +ӣӅېβ®ʿʥꁔϭ՝ +Ԩܵ枍ϫό׻Έ鮸ީőϸ +Ե굜޽Ư١΅ۏۭ͋ᄤ +ͦșָؙ̭ӵ𭣃Ԩ +߿ϔߊȏݣō䩹߀īҁ™¿Ӗ܉ھ +ϝ򄠁ӡПԣᆿ +개ܼ⿪̿݀ޣşɺũ +ޑĒԟцĻʶܕ +Ɨũ쥍ۭջԒ̹‰ȀޭœΚ⽮Фȷē +ӟƇԮɲԔބټբdzกī +ܲڏ̛榨̇ՃʮԮɲה +ŀÍɼЍϛū̘܎ +صۜůʀ깯¶ׄŎڲз +əכ۟єﺘՍۨòÂɽ +׵ˀȂؖǏݠճޒəȝֆ͍ +ƩԊԏŗӻЅҨȓɝ +і쿯ޕ⭩←ƕ㡛ř +Ȃؖנ׵ˊ瀂Ȃ؎꧘׵ˀȂ +撻ѷ׵ˊȂ浘ڿ́ꉃ죜Ȼ +㡋Ѥ򦀤́Ƞ񀀀⁀ă +񀀀⁀ă҂ +连󜕌ʕ睷¿ĤƾոӼݬ౮Ī +կ荳­Ԭ܅⃤җ݇ƨŮΖ޿ +荳¹н倀ƨΙȣٰ巷 +ҏ划۷ߺԞ߭ի׆ʔܱԬЕʬ +ˇӈʃړ捨⊀԰† +ē뢂Ԭ˷冹ﲬ졭־ +Ά֯ߴхݞ䮹ۀؾڡ˵ظЀϝܦ⍄ +Ӛ㽄¢ЀѲ܏˅Ϟ잆ʿ͎ +єߧӬԪֈޣˉ֮͜܉ʼ욙膆䴿ɽ +ӠϩǺɜՎΪɇж񲃗͖Ð +ه݂ڙۤğܷԒ׊՚ǡȵߏɵɛ +󂅙ݙߙʣשۺк͔ +˲Ђӭޣи楾ٝ޴ΘոǢȧÀ̭ +̳ڏﰷ܎׸РŏˇΪڛڡສŌ +ӕ쒟ʼ춂ǿ֘ˆ⋛㤠魫щԀ +ՖЧҏԌ৴笐·Èηת򙊑ѳ +޹ķߨꪬӰ⌚ɽâ +͏ץٔהΉՔ靤ܓ瓉߻ƉƔЫ +ôľÜ㧟ܧԇֳ͋ʼ¡ +ϋЉñ빠紩翇ΪȖňЂһõЩß +ևȾ􉚅LJ͉ѝһõ˩᢫ +۵ƀ畆օؗԶɇͿѳ긵¥ѯ +ˤݓαҳںٞ˅䳱ٖɇ͏̄֍ +̃ɼǫױյБҥ֣֙Զ͇譶ת +氟鐐ɣ⍬̓縅ۚ؁˘樘ɖܾǣ +΍󙘔Չɼլֹ񓤴縅Щ֘硲 +Ϻ֍ӆ̃ړպϒ˟ч۾߇ڎσӔҖًת԰ +Ћ܎瑿ɮԾЭӓۯƺۡƴ❃˧ +éᾓӠ̒߈Σ͓ۋ渵 +⍛ҟ骫з֝׌Ǝۿס鶶緘ꢙ΍󙘆 +ٿóџ硲ْڐ傴ܾь̃֜ +ދ‡ٖ牽ل֦Ҡь̃聘΁ۆ❲ +Ӷ۲項ߖь̃ȼר篇Ȟ硲撎 +긵Ԛ⍛˟ߚ܌Ӷ۲Ʈ項ܵޜ +޽硕χ㺟픟⚐͙˴Ђ +Ѡժ񐎈Աч۾聬՝ўϮ㦧Ӈ +󉟁ʭ򸖪ɂƬҺ翠ȓӨ؁ˤӌԢ񣢔 +ˑԷݼՏϤڳ􃅘۫䳱 +ٖ·ЎږՎ̃ʽܑƤ +ɺʶ՝ݲݢʶ̗·ɛĺ +璿ͥ̽ྥﵙţƹ过ʶ—͠ߖҫר +ݚ縈‘콦ٖ̇ȟ󋾍յŁՙ +ͥ޻εЕŬ诫ުʫϴڠُԘ +፥΀஥ϔݝʷ +̺ۤ샲׽隠ͯҢὥ”ӿֻ×֌ +׻îЮ˘Ђ䙤݁俘ҁ +ׂ„ҁΘۀ􀁊ȼҁ𨂒ߠ愀И +ᄀǂ⾗좩زƬꄐ̻ȇƀ +׳óЗҁ넲ȇƀ֭Ή϶ +ƟюԂ遉Ң㡁񀀀Ъ⁀ă҂Ȁ +ϟ鞍֯ϮͲޢެ馸򎩔ַ㘡 +؉ұ껑֊îğˇӱƱʶťتԲ +đ䳴ΖǻƸɀ +&] +[s0; &] +[s3; 4. DrawingDraw&] +[s5; [* Drawing] object contains a set of drawing operations and in +fact represents a vector image with smooth rescaling. [* DrawingDraw] +serves as the target Draw when creating Drawing, Drawing can +be painted to any Draw target using the [* DrawDrawing] method:&] +[s7; &] +[s7; #include &] +[s7; &] +[s7; using namespace Upp;&] +[s7; &] +[s7; struct MyApp : TopWindow `{&] +[s7; -|Drawing drawing;&] +[s7; -|&] +[s7; -|void Paint(Draw`& w) `{&] +[s7; -|-|w.DrawRect(GetSize(), White());&] +[s7; -|-|w.[* DrawDrawing](10, 10, 50, 60, drawing);&] +[s7; -|-|w.[* DrawDrawing](100, 10, 150, 100, drawing);&] +[s7; -|-|w.[* DrawDrawing](10, 110, 300, 300, drawing);&] +[s7; -|`}&] +[s7; -|&] +[s7; -|MyApp() `{&] +[s7; -|-|[* DrawingDraw] iw(200, 200);&] +[s7; -|-|iw.DrawEllipse(10, 10, 180, 100, Cyan());&] +[s7; -|-|iw.DrawImage(100, 100, CtrlImg`::exclamation());&] +[s7; -|-|iw.DrawRect(20, 100, 30, 30, Blue);&] +[s7; -|-|[* drawing `= iw];&] +[s7; -|`}&] +[s7; `};&] +[s7; &] +[s7; GUI`_APP`_MAIN&] +[s7; `{&] +[s7; -|MyApp().Sizeable().Run();&] +[s7; `}&] +[s7; &] +[s5;= +@@image:1620&1869 +āǜ휇ҨɒĐ򙂅劥ʐ䏁ۑߕ +쩥ޣ˥ޯңɯ齚ŔܲӲ̲ߜŢ¥ +ގԓڲܖɼ촫ϓł빫Ϧռܒǭ␎ÛșũϦ +ٕޱѫ䰾鳈ٮϯܒܫЙơ +׹똹דɥ运¥خ†¶ܒǦ +Ɋιϐdž䱉׹ኧۨ⭙Ũбڹ +Ⲳ̷ܾݲ۲έ᜕ݡߤބՋݷܪބ +ևΧ܍ծӲ侔ÁڞՈו +۸׏ɡծՆټʵ򦯓îʽ͵‰Ȼ +޳×έºרŃȷܰӭ֯ˮߩ +Ӆޘܺ֬юпɪՋư毘ř۳薽 +羦垿򕤇͝󿡆ز߫Ь襐럼߈ሚ +کۢٿͽكεƭ +ȽЮ󝙢ޑ䚞ﴆؾ޸ݢϼٔ +񋅺恨ѽʹֿ̗̲ͽ۫ڶƟ +̼媮޻ܯۣҬޙԽ +ఎڍؖȕ˶Ӯޙڶѵϛ +ãݻѱՖՅöӨخËȶԖ +ͅ玧򬙃ݻͲˍܲȑ쾾ܫ +㑶Ʃϝ֗˧Ŀ۞ͷ𞮕Ŏ̵ +ێ˭ϲ˽ċ׬ޙỻ۞ݑӮ +칗퇽޹ܴ͇ݖnj򯔵濪Ϲ +مՖۖ꽢Ԑ緃擇׮ +ұެÝ՝񓻔ؔݵܰ㒶 +弸ߡꧬ͙ؽܻțƴ߬쩝 +ț٨Ԇϸ̵ܭۖթپΡͷčܒϺ +ުڍג̸ꮛɛ߇Ԋ囫 +Α۶ذ˖ؕ޻Ǜܫݴծ˷ݕɡ +Ž̇Նƹܨٌìϲ̟еұ +Юǻ씞Мȁڳ۽ي菾߱霊 +՜义ш…ʮǴοȶ粓񡤯٘ +ڞÿ멯ޟ᫁ήЄ봅 +ܬُީӭŎީŎٸِ݃敷͊䩥ݳ +ɠ˷ٴȵ۶㢹䞓ڌ鳇ǃι +ުӦՏҍɘٓږ뷬廮ܛ̧㔚Į +߅ѝԻѐݯ컸ïەƧ۞گۦֽ +ޮԃ펰ʖЂУ۟ꇅ +ߏˉΰܺ߄꺁º۟؆鯯Ȋ +ۈ쵵冭ؾӫ٭Ԟ׀䠾𿲋̫ +򲷂Êۗ•ӋՔ䆶Ϟʉշ +具ƥ⌫ǻ땅𗣓̤߆ɖ廣䔶 +类ܑԖʀս낖虀虀 +ؙ虀åˀ֩ê܁ڶױ +ť̜ɓ⦨ƜĐإƸĒš㸝󾞐 +󚤢젻޻ȚزցŅЄˁ鸧ڠ奶é +恙̷ŶŃُв̸ȱ̮ +ţ˾вᾙֹ㯞֖ޚ˔Ʇ泙יÓܐ +ᾋڜ۲Û邘Üв但ɭ۟܍셰佣㓝 +׿ϽׯǔӖ迹Η쯞ƙÛ׬炘깞۟ +ѣѝ󉌌υɎ҅υڹ朗߻ +҅Ľ¦蹯М̡̳ݘ䷗ӊʦߞ +فǿͪӑ̧Ń٧±ƪ߃ŗԿ +۝׿귔֣Ҁ̧ +˒̊沞嶰é싖ɑѩˤ˞ُ +҆ˑ٠ޓٵޗ뭲ޣɏ툗ٔÇ +ԒČ䖀ɍ툗ԼپĦ₯վ܈ќвȰ +ߎم˷߂󦞺눮ʮԗƵ +Ǽݑ蹽풮˓󹹏ʃدѠ弟 +ٸӰҒ务ŪۦѯӦˢҭ +žߴ葇ݐڨژꊚâ +Ԝѽе멳붬Ӧ袯јςʃ搚󦏃 +޹֩ݍ쀪Մ͞ݠүօ鞴 +ɕؘۚ岁ږ카ӊ袿玭޻ÚҬヹŷ +ʼn⯳ƕ΋ʯи̒ݫώ؋ +ݲ鏟گ몣ײғ˪ٟ +麯в˗Ͽ뫇܈ܨҎʤ󨉿 +ɻ黗ǟߵے⶛ٿѬߩۅߩ +냖虀虀虀ؙˀ֖娀ܛˀȃ +ˀȃˀȃˀȃܼв虀׆в򀐭в򀭃 +򀭃вԅꊴ˂虀虬虀虀 +΂چچ巁ٜ׍ܣı彙Љឪвޟꖁ +ُˢُ˂㻊߮㗁➴롖ྱ +փྍ˃󼙋󰟜񘁅ڶډڦ +ǠŽ悾Ш噿ґӲ鶰ܡ泅֓ԁ +泄®彺Ȧ옹佩ۀЮ +޲󡻆͸ǖ̇Ӹɇ֑ٙ +ŝҲӃŀؐޮ։ȼߗ񸬒ՖٙקٲȦ +粀⭳܈ȩ曟Ǫ§꾒櫇ЙאŤꈝ +ƆМچДӖވԹچĹ҈鬦أ֍䅖 +̷ڣĖк̝䧣ːӑղ󍆡 +¦򝖘چ̔ːֱІԙֺә +АއƷʺвЁ別ː𕚺әچ +ǵȚԆѭːֱʸߐ则ąв¦ڦș +ٗچĖ·Džܡ䤃㒷劜샖̔Ǘ˘÷שّש +虢ºƭҧࡔѧŮ劜ܗ̑چж떩ɽ劜 +̑ķʺ޲ř銚ڦșȱۑ˔òȠ̑ԣɖ򆮫 +ͳڲιЅًۻș㵑˂Lj˺虢ڦȨ̑ +뵬æ㢭ⷋ嶬ބДσƆ +ڦșܺ֓٩棏׍֓˂֔ +ـҔӲ󙃥ܭ泈ٲ֍擊ܼ偡̌в +ʼֲ뙨ٕꖱˆ꭫̊ݤߛ۰ݟƍ߲ +¼߷۠妭ʬʧʷ۶뺶ʇܤ +렘ǯݫťԚ㳳ۼ߫۴ʺ˧ˈ +ҒҲ嶵》˓Ƚۅ܃֘Ǡ乕ɱݨ +ۣƣТ繽ެɯ͙㓳鱟쎠枡圗 +ҫі򅭷ȿ̃ʧɘԤ˃ِ +ϝ藉ɝǟӑƒ͝ꪼդ玻 +لԾȟúʋ޵̦ʟ +χ¼ۖ﹉κɜҠԕг٢׈ +΃ۦػ劏Ŗ֜܃ÑٜՆځꤍ +둛ِ㶛˳ȊߋѬטˇ´ғ襡 +τٶάݮͶ⒢克銼қ۞تظ +Գ앆ؔ˴喢榼נϥՆ +𸱾˶鐪ɭ޼Ͽܙۓҟ +餲򥤢¿͞霘Ơ +ܘғɡيބ䐯Ć߶ +Ơ崯ܘˌ͡ڏՠ遗ʻؐӶ +클̞兪벁ؿƜğŕԝ̩ԥϰü䄿 +ѳ܏ɟˌƣ䖠崀޹ +箉ߏʅޓ֤ڤ񡭏 +вڶǧө߯ʜɥë奫̉ӝͷК +У䠨ѡֶŀ㪯ߺƫ +̞üҔֶ҃Қ惷ɗ˃֬ڲݖף +ϙኂդ夤镬Ɉᷯ۫Тϲϸӡ +ҋɎԦݤ̊ȏ鑩߹ijǿȤ +̨Жᶙے۷ٳ풎˶Μڝ避 +ѭӁéȦۘꖧ욻겉ß٩ +ЂÖ˵ךĘ┟ަύτɿإÆ֐ +ٶԺۣŲ߸˷زǫ٨ߢɞ +ٿӴ˧ˁƆ߾ՠҶժղ +ʙɏܠ횫ǂ‡捺ω +ֿō״ڹʉ崜ˊݟǠŋˤף +픕ڎ֣חਜ਼ٖۨۤהԐڛ˺銒޳׏ +ɣ˝ጢݻǤۃϳ⺲滍ٻᣥ뉙 +ͪܳمڙɤꢑֿ˳箰󧿪ײƗ +ߗܐѓ̚˥֕Ԑ̫坌̤Թڻɠ +ܣ只ߓՆЌϾ̔ӏϱه +ܶƔӚ޷ϞίߒΓ̵ɖ +ޔ㽢ʪÔȒĥ֛ːέߍ +⋊Ĭޖɵޚ琣ܖ安ޓꮉ +鷶ުᠲנψޛݼնΪ҈׎ +鏻߾‹הĴ焘㏆ݺ׿֥ߚۖ +֧Τي߂ϟϤڊݵ +ܦմܻ۾←ݧ󧾂紩՛ +ƫ듿ռ䞷ٯ㧫ύĘĎ +ӦƜܛǓǧΰ҂隯ݗ縟 +njߕ洪њ񅠏նвٶ +ھϟ򾦘׳ֿڶӇ뜒 +ݍϚˊϼܐٽۮ匞ҳ󬧦ыԝ۟ +ҵފޱ殜߿媛ݠƠބ֭ +ϖڕќӊˊ”Ϋ۱ꎵ +ߎБړǪܕ˖׼ϩΐʋݒۇ̚ڮǀݟ储 +㺦κşӵ՗ȡ󱻾Թ䣝˸黗 +܃柜בߙ덡вܞȕΣٜۮ +ڻʚ߇ߵꮡޔƐ +ٽΊ㝏⦏ٞ񈤞ߓ崣ݞṛ +􍟻ǯÆҫűޘ˜Ξǝנס폿כ +ל絛텹۷ݐߴ熿뭡ֲث +򗎝܎өӦΙƽ᳦ϸ԰ܽöɥ嬳 +׸ξ፸ٵɚҵ埭ѫ񋹶в +ƷܾչÏɚߩºˀ +虀虀虀ؙРȀ䠁چ傀چ +چ䁐چ倁چ؎в򀭃в򀐭в򀭃Є򀭃 +в樅洩ž泥ԦʡưқՎ +ʭ柚Æދċ߫㌏ݿ૭ϳЖΟ빧 +ږֳ۪Ξ뮙 +&] +[s5;= &] +[s3; 5. ImageDraw&] +[s5; [* ImageDraw] provides a Draw target that creates an Image object. +To define the alpha component, use Draw target returned by [* Alpha] +method and [* GrayColor] to define the value (if you never use +Alpha, it is considered to be 255 for the whole Image, otherwise +it is set to 0 when Alpha is called for the first time).&] +[s7; &] +[s7; #include &] +[s7; &] +[s7; using namespace Upp;&] +[s7; &] +[s7; struct MyApp : TopWindow `{&] +[s7; -|Image image;&] +[s7; -|&] +[s7; -|void Paint(Draw`& w) `{&] +[s7; -|-|w.DrawRect(GetSize(), Cyan());&] +[s7; -|-|w.DrawImage(10, 10, image);&] +[s7; -|`}&] +[s7; -|&] +[s7; -|MyApp() `{&] +[s7; -|-|[* ImageDraw] iw(100, 40);&] +[s7; -|-|iw.[* Alpha]().DrawRect(0, 0, 100, 40, GrayColor(0));&] +[s7; -|-|iw.[* Alpha]().DrawEllipse(0, 0, 100, 40, GrayColor(255));&] +[s7; -|-|iw.DrawEllipse(0, 0, 100, 40, Yellow());&] +[s7; -|-|iw.DrawText(26, 10, `"Image`", Arial(16).Bold()); &] +[s7; -|-|[* image `= iw];&] +[s7; -|`}&] +[s7; `};&] +[s7; &] +[s7; GUI`_APP`_MAIN&] +[s7; `{&] +[s7; -|MyApp().Sizeable().Run();&] +[s7; `}&] +[s7; &] +[s0; &] +[s0;= +@@image:806&618 + ̔LJ苵Қܰԡɽ +˥؟ؑ˲⽩‰ˌѓ靈ϳͳ +Ռϒʔ̶ຠ΅̶⠣ȡ՛ܔ֙܀ +梂¡݋㈅ߓٱǚĚֽߦЂ +ТʡբƉ샙茕ѽ +Ĕ䮘󁕽ݍ㷃܆č +صי̶܄Ѵ򂀿Æ̀¤ +ŏ䨬୲ΐԺ‚ԂΏ +ŋܥ͑·첚ߓ舄Ԣɜذƻ +Ė𞿡ꐅ樥ħߞϣƬʐׄĖыӅԒя +쑳ˈڭۻԱӣݒʏ藵ƴ篸ւ׈Ӟ +ҵň赅ճȫ̧߈ƥԝߪۿ +ûتŵ럝1±ց̦ +ґ˫˵竁ׂيӥ˴龥§ǣ +ࣰܼЀ̡݄ׄí魏겋ٚ +ݥ댅ڟɐ„٨ƅҟ޷ʲٚ٭ךℨ +Ǖּ߭²΄裲ʁnj׺ +嶞Ƽ˔뽡ꈠ佳؊τ֦붩Ԫ +Љڨг¯ٗМšŎ܊ +ӷԕϡ盳纚цٜ˂ޑەݨُڝڗܺ +يڲݳڹۢǀ̝΀ۀ´ٹĮ鑐ꁔ +؋ѐʲϣЗːڛڡڻܗǞЪВՆڈθ̚ +ǀސ̙μϡ扥ϭѐӐǾУ +헜ݾȴޫ酀캞ݹҨ +٨פصdz҃ۋڙҷ̸ʬ󖵓 +݂āՎԷޱζ۶֬ +ƢҞ证ྜྷ҉̍βҭ +͖݉֝ͼĕ␂񌛩ꗂƘ舢Ƿ…չބŔ +↛ٕջϠ߫ωNj֒۴䲐 +͠ܗȺƒߺ†ۃʮՐ۽ɯֿǛ +ۗطيۤݞɂב췄ͶԏߥÅɁ +ՋӷܰƨԎś̹֬ӘՔȈ +ӓΏ͋ΥʚݥŶɝÌڒ坿 +Ƅȝäɩ̏Խыؼ̅οߑ +Ņԓ锓ѡ薅ڈ󤐉汾Ȯ +ހĈΗ˯猪ӡ©ߒِ +ƄҞԹ䍵˔́Ҙ򻍐ݓʫƴò +Ҹݭ͹âꈧҚ«߅⋂א͡ +Ϩ훢՘ӿ„Бِ ŠǐۦŰ +脎ٯĈԠʥ϶ҹɱĄե +桞쎍ݢ¥ૂ񜾡ݍŁŠʐƷʑ蔈 +DŽĵݶݽ؈ᴕ⋞ƾῄԐȡϳƫ +̹ح􊍈쫆톢ߴЪҮёܐ׸â +ŵ߭եɓТݮբݰ̉ˬ爰 +×зͺՉƂχ説Ɓڊ簟 +񚴦Ŵ̟щ΅;ε焊ѸĢŰ +ف⩌㶿ƷߗȆ҇’٭ҧǰآά䆀 +ơ̢ư俻ԍ俪ȤꟿԢƪǶ +ґ湣恈ԄЃԱ̈գĠ縪ȞؠҝҽŊ +Ԩ󍹻䆂ɮ򼬃藽ݭǏӢ +Өϐ̸δ׆ȡԽϪ޾Фܕ쿓 +֪ϳ +&] +[s0; &] +[s3; 6. Printing&] +[s5; Printing is quite similar to painting on the screen. To acquire +Draw target for the printer, you need to use [* PrinterJob] (CtrlLib +feature). Each page printed should be started by calling [* StartPage] +method and ended with [* EndPage]. Drawing coordinates when printing +are in [*/ dots], defined as 1/600 of inch (in fact, a pixel on +600dpi printer).&] +[s7; &] +[s7; #include &] +[s7; &] +[s7; using namespace Upp;&] +[s7; &] +[s7; GUI`_APP`_MAIN&] +[s7; `{&] +[s7; -|[* PrinterJob] pd(`"My printer job`");&] +[s7; -|if(pd.[* Execute]()) `{&] +[s7; -|-|Draw`& w `= pd.[* GetDraw]();&] +[s7; -|-|w.[* StartPage]();&] +[s7; -|-|w.DrawText(200, 1200, `"Helo world!`", Arial(600));&] +[s7; -|-|w.[* EndPage]();&] +[s7; -|-|w.[* StartPage]();&] +[s7; -|-|w.DrawText(200, 1200, `"Second page`", Roman(600));&] +[s7; -|-|w.[* EndPage]();&] +[s7; -|`}&] +[s7; `}&] +[s7; &] +[s0; ] \ No newline at end of file diff --git a/uppdev/Draw/srcdoc.tpp/ImgTutorial$en-us.tpp b/uppdev/Draw/srcdoc.tpp/ImgTutorial$en-us.tpp new file mode 100644 index 000000000..260a2b4d1 --- /dev/null +++ b/uppdev/Draw/srcdoc.tpp/ImgTutorial$en-us.tpp @@ -0,0 +1,1924 @@ +topic "Image tutorial"; +[2 $$0,0#00000000000000000000000000000000:Default] +[l288;i1120;a17;O9;~~~.1408;2 $$1,0#10431211400427159095818037425705:param] +[a83;*R6 $$2,5#31310162474203024125188417583966:caption] +[b83;*4 $$3,5#07864147445237544204411237157677:title] +[i288;O9;C2 $$4,6#40027414424643823182269349404212:item] +[b42;a42;2 $$5,5#45413000475342174754091244180557:text] +[l288;b17;a17;2 $$6,6#27521748481378242620020725143825:desc] +[l321;t246;C@5;1 $$7,7#20902679421464641399138805415013:code] +[b2503;2 $$8,0#65142375456100023862071332075487:separator] +[*@(0.0.255)2 $$9,0#83433469410354161042741608181528:base] +[t4167;C2 $$10,0#37138531426314131251341829483380:class] +[l288;a17;*1 $$11,11#70004532496200323422659154056402:requirement] +[i417;b42;a42;O9;~~~.416;2 $$12,12#10566046415157235020018451313112:tparam] +[b167;C2 $$13,13#92430459443460461911108080531343:item1] +[i288;a42;O9;C2 $$14,14#77422149456609303542238260500223:item2] +[*@2$(0.128.128)2 $$15,15#34511555403152284025741354420178:NewsDate] +[l321;*C$7;2 $$16,16#03451589433145915344929335295360:result] +[l321;b83;a83;*C$7;2 $$17,17#07531550463529505371228428965313:result`-line] +[l160;t4167;*C+117 $$18,5#88603949442205825958800053222425:package`-title] +[2 $$19,0#53580023442335529039900623488521:gap] +[t4167;C2 $$20,20#70211524482531209251820423858195:class`-nested] +[b50;2 $$21,21#03324558446220344731010354752573:Par] +[{_}%EN-US +[s2; Image tutorial&] +[s3; 1. Image designer and painting the image&] +[s5; In U`+`+, predefined Images needed for application (e.g. as +toolbar icons) are usually designed using TheIDE`'s Image designer&] +[s5;= +@@image:3290&2281 +콇׻׽ה„Þāѱ +б႓„Ǯ̰󮙺ԩՓڲ +Ԍϱ˩ﰨѩӂż΋ܡ +љൽΥ—Ԃ𪘒ٓ +Ǭ҈䲪ҖӠоЄŬ振Ƞȴ‰… +śӇѼ˱ϫ֬˼גĈʩԅ +￵ꥼ睑ɒՆꬰʄյ܍ʝ㉺ۯ +жҴЏōŸۗ㞿܉ӠŁ +ŵ牗Һٖǂ򩖆멋ٍʨҦ +⸇猦Ďʶdžϙ֥Ѻ +ݏÎςټ޾ϊݗ¬ޘؗި޻ωӣ +ů󸩺ѷ륳ɗ׊Ǖ쭮ԯϻٟϺ葇 +̯ڔ؎΂򨺛ךøﶌϗٜ +ژ压ٵ׭ᐋׂΉ创駗ղ׻ڙҊΒ +騩ăȇܮϋɫϋڝ󢁯󾁒ˮ +ֽ͠NJߘԘӔӂ␭ʯڸ؞ݧ +̏˶ϋܠӈޚ轨ݷǶݗֺꇍ쐚 +Ԙעʡ֌оݧ҉ˣ乴Ϊپĉ嗗 +˺៑ڡ֊÷ͤҧنʩք뚔 +ݰԗǣОء׾ֆܗ틕ڑʚ +꜡ި랕ݜŃлχᇉ͕ +ʘ쐋´ȩ鹛ƺÕʮ߅ѣވƍ³ +ߴȱȨ오޺ꐫۮɘƻ̟ʢ‚왅ղحם +׊̿УĮݘʡذڸяܦǯ杴 +뢾ܪŅí¾ԖА؁ހ玉Ž嶿瘙ܹ +ڜҚ惦Ϭ蛾烤ٵЋ՚ħ輴Ϫ +횶Êݻ׾Ԇܹ絡ؤлԋեʗ烶ǓؤܓŎт +ǡ񯅃ٽˮǦаᐳꄶሟĹְ +䆳ϯ˃νض̯ԅıƉؠŵૈ +͒ӂljܜخ틯Ū헍Ãñ +٣툉蒇Ѯ޽͑ͩđ՗ +펲دژːĄ޼ھ멮莜ѣ +ṔNJ‹̙ћَ̓Շ񣦁ǔꐏ +Е䃽ԠШ۶ԻϸӴŖق׬šۖۛ +ʁȷ㟹輁߹ɬͭɆ˭ͦ +מʶŭޅɏо͝񇍽鼔Ԧ +؁̵ˎ҂⌑ȅҗԲٞɵ +͡Ê痶ئŹ켣ԝϸ؃㕙Ï +𣟍̠Ӈ؝ѭꇶ꩑̳ԅɭЋ +ԳƩÍڅ틷诙Ĝ칔﫮ܗ񪫎 +Ֆ۷ߎ䕬뱄Ịעڍ׮ܪȫ +搇ƌܾڎ߷Թаީ +çĘꟽÏ؜ڵ۷ݞԕ̼ߍ +ŷǏ隽Ҷיлج߉߮ڹԗؘ +Ư̂ϔͤ¶纂ߗļЈප者堩 +śӫͤ밑𾉴ྰЙ姘鼥 +ﲒƱ̗񭃬׍Ӕŭ׶싆ݰΡѻ +ڋ՗ōٙ׷œ⛃֋ߞ喇皻յ +Ҕˍី楇ʓҧʸԑɴ섅֎ϟ +ɇ՝Ӆ݊ұެћԗ׽ӣ؝ޚ +ⱴב̇ךͷмߌ +ȻӾ͎ŷϷ뒨ܫϵʼn񪈜Ծͩ +ǣܑکȃӷĝə؁ʜکËɸ訇Ԉ +̎駊ϹԚ҆ÆϾꗾ厨񲤧ҡljɎ +ϑ켁ȩՏ㧵ś蚔Ϸ娝 +싈υěꮺպ™ژŕځݗ˖≺ +ڂҵžݖ̘؂Ԇ׿ +ݞڧ޻؝Ǹصێėஉ +饴娖Ꝫק޾ߊކ͗ܿ뚼Ͻ￵ +񼟴⬊ζПсͱΥٮ𚺾ԗ +ɷȹѼųƾŝ҈ۋǜ񈧠딍껋 +ÂöÈ煬וʔԋٯ̺Ϗ +⭖ᝎܸ֫̓Ϫߔ皣Ԉϼ +󁵾ѻξžז޻‰ێƒۿޟؼϏ +֓Ⱥ޵ں +ͿꐖڠωҺèȮկ̍ѐĉ¼´ +񗨏ˎٜڙںՇ㑇䞒ɐ凡Ђ؂ؠÝ +Ȏ鱠ϗⱠޮàӬﰡҊ +͗Մؗڗޞ̻󎍊ߜׇֻӹ߾싓 +ऽ鑞ӄ⛃ĨⓋӂﹿҟՎ +ø¶ỽӔÿήٵ밴𑷽Й +դۙݩϏ􂧟זпĊɧ܎̏徑޻ +͓Ձ؝ϦߨީשߋËӐ͔ۼ +җͯœŽ™咽ǥγ˅ꮼԝ +皸醋ڜڴںӃ㊴⊕卙넳ۼ娋ʢ +ԋϼ򵮳޹ƈ߬䟕ሠ޻ +剞òݴݯŐߋث߉ǫԞ⡉οݾ +۹̯Ԙ퓷٪΅ˣ +ʤĹދݑɮ֥ҞɯؤͰƛ +Ѵٯڑ֧ˈڮԘÓӘݴߓʈ +ܩ݊ԩ»ӣ׺āтטƦܝ +䉗ϯᇺąŽ放׾ЫҼ݋̊Բ𴏯ӊ +О܎ײƉ볼򶥻ɛǵمŴөōǏ +сƉªՒלù’̂ܪǨدѣ̟뇮 +خ햖ƹĕڋע贤νÞͣӁ̺ӖŃ +ΝØ˩锉Κ婝ޠهְݏńװ¶ +ҺَէŽ̤Ӆѣӊ +٧ا좯옅ښיϖ›׮Ʃ؂Š׾ +ٞ䇍؎捌מлȣكƦܜ‰ܨ +ÂςЂ溥ǣ֣㩞ޜƧΉ⹬ֲ׸߷ +ʰïۗ͝œȮ癧ûȚ֘νʔ煸 +ˊ˸ꥮڣ۪ퟗ龄͘ +ٰć͑۱٧Ÿ޸๰߷Ŋ +͟ևǥɖ㠳ç͛ͤʲﮮȆ詪 +ꗬ޻џݸΨΗݟ䪇ϻʶ +ºdz켴ӆ슫𻾹᧸ +ػĄ̬݆لѤӝ»⤰ʈņıʰ +ߟТģާቾŃݘԞ򗁒绲񩶊ꟙӱ +ރۮ䷙⏹ݼخٛߋ诚莮΢ +ʯ״ӧ펫טŭڟˡڧ +η獄첪ľ͠ɘ٬Շҕٗ듁Ǧ +ڃȺӪݗڿ򉧆ϋ½守ܛ⍪ +ߢ׹ͰˬՕ݋Ӯԯۙ쎣̷ +ܓ͎̅œ㋟Ԫєljȗ陳 +ᴘԭ뫬ȻΘ޷㺻Ҙʰؙ +냮֨ޯ껆՘յۉלƈݪۂʵŌԒޗ +ʄⲾڃߋڤƈҽ۫ +˜뾆ˢѽ㾊 ⒮ۥԠƐ͕ +ȖǴƘʝݥ㆒؆ܱЬ螹뵥ږֳ +πŸ䛶ߠמ몾ڸјɫ٤ۊɶî +弭ֽ؞ͤ⧴ݺ􆃻̼Ǧܛ +Ǹ׃󭋷ıՄι뺄 +љЛΤޝ؛ՁθϹ۴ݚٸ핳Ŧ +əҫӆۯξޠܛɵ֕ՌÂҴ +ǃŁܥɛܐ֌Ɓ啣ѩ +΋ưܡ۪ş܃ײɛڳپ׋¯͹ԩ򅧷Чⴇز +Ԗ浬ҕ͌礢Ҡې՟̶ӗܣ᱗ +게򗋋Ͽ̖ޔ뼵·掛צޑׂݵܟ +̻깚Ь䐡לԂױӒ +֑ǑڧЧǡ甪nj񁜱 +ڷ˜뭵ܼʸ䊉١ʴĜƖ鍽 +ϩ̶͗ڴؕؐǶ†럚 +Ӿ܎IJ︖٪뛥ېݩѥ +ޕ剫қ延ӡ󽭞񲯂뺩̠šœ豹敋ͻ +쏋˨֮߫ߪɗɅᱼ޽ᕒҝɹًа +њ՝ܵݡ̷թեÌꧺ钙ͷǨ +ףۥЏ߳ʨ姝۝𕈱׏٤앥nj +Ԇ̛֗ٴ氠߾ꊜ鷟ߩǩΜӳסޯ̯ޣ +ԏ俽Ք۔ƖҔʖ߂ֺ欣鵻 +퀖潄ؐ܈ސֹ֔׆͚֌Ƌ򄣒񘓺 +옳ڤ֏؞׺ւڻʽ՗ +ɰ̎ܣŮ褋쒛ݍǘőߢވɚ١֮ސ +ҍڵܨʳίԋý̻ڹ𭉕ڂ֭Ѩ +ݧآ蹏䔮д݄̅ʊїΤ𯶈ϡǢ +ޡͤӂ˖߼ӽ냖İ +ϥ؞߱Ɯݮǽ쀃ԑߊ +Ÿ嫜𨇬ֈȖ٨ך׸抖Ĥܢݥ + ݑ񋚨Ӛļö߈莨ʃʋǁ +Ԁؐ𲠥彗ߦӪذЙک﴿Ăڕ戼 +ȓԀЭу˚̑ʻùꚞآ°̬庾ա +ؐҖ̞˭߼ߊǯкڟ߭ +˿ӏ‚ꚞآ°ʙơأƵ +ιŬܔ֦͋ۺР䙫գ藤 +Эۏǚ˲دݕҶȤ䋦΍媂̸Ӿޅ +×͞믖֙غڐґӍդ¡ +ȋ˴τ짪㙁貄ǃﱓŸ̂ +Ҡ۽ϷѺۧ׆߿ѫ䫕ڐЭт +պȰˆፄڤՔʑ򟡆ې +Õ圹ސʣҴ԰Ժ֙ +ٍџνӯغϬ鳉ϛ椋Ж隦ʗ٨ +ݎľ㶙Đӱłը +يijŕͳɆގϫ椆勾ַӢƑډѼ +؛δ걎Қ֐ڿ㕴܁ʾˢˍĠڰ +ƱݽɄǾ†܊đ񭖎僓Žދ +ʃ؈ߐԩʒèސ؞亻Ώԯ‹ىף +Ӥބڇ֊ͶՔ˟˻Җןλʪѕձ +¥ɩԑʪȬÙ󾓕нᮉ +،ݴڃ̙Ȯ˫ސߖ乴쓱ߐ䄘 +ɯƤݷ豲ݺָҠ̪֔ӂʋ +ߘγ˓݁φ싖Ț뇲 +δۦݏ̿ƙ̹օ݋ǒߐכęۗߨ +ީԡэɉՕœڿ쯭׻ϚҠ +ڕҞٕٖʈƴݿڥ҈ɱٖ؎م +￰ȗڽ°盕ڇ㎿Ï緌׍ɚ +¹廊֝ƔȵߩߘʡËĽٹèȷ +백丛닲ؠϮϛĥދ譨ɭֳձʂʪ񯂛܋ߐ +暃ٹޚϩދĬƂڋޕӮǞ؃ +߰䷧ʺ䩉ҝᆍڴҕ政ڕ򴔅ٮ +Ǭȼʂ݋ݓڂĖڨ޽λؒ隥 +ɏ疃ދډ܋߅ژՓǜܿ࿇ҽ߁˻ɞ +͍ȵǨ൩܅״˂԰񍨐쐟ֶ؂л߬׋ +ސ⯦㋖ߵސþՂȲ׌܃” +Ԥڅ쵯֌՛݂ȥ斤ʮ􁽠Ƹڥ +쫄۵«Ўܛʕ令üבɮ攨Ϙ +Ɛ߮ؐЃŒɻѮސقՍʫت۲ +仱Ż䵆۵򹾯й𖞹텃猏 +ڂ𖔃̂֕ĠН쉧ӯமưʥ +ոޚ􋊧ҹɸщԂ܃ԨФ +ʘ㪴ѦꔽڕۃՋժ넅ݪƂ̢ +¢ۯсƾڵؚÈҷڦʫΑ +ۗҨשܶԞșٱ҂쟋ɑ󽼪͑߁̆ +Ŋժ֜؋˜֐վ婈᥼ħ +…ʯջސ옚տމ嵷 +܂ދ򜍱ԼߋǃмԨӂςե݋ +܋ʴؙۘېŃܵ܋ʭڐ򕪱∄ +ͨҊ쿷˫LJᅩЂԀݸϳ׍и +…蕗ԣ•뾚NJįԅǨҩ +ںݗ“ՙ躂Ͻʾԑ׈ȁ¸ԂҬ +ݠ߻땸ߵ΄ñ둈ЦԨ˂צ +ِ;٫°˂᩾‚Ͱʟ̟ήġ̆ɀŅِ +шЈ–Ȕ¡ߗ‡Ҁ⊷⣝ʂޝա +ɺԂ斤ԑߎ钻֌Ԡ툐 +낊;ÐյۥčȤґ܃돽ײ +Κߚ؀Ų֩ۂ╫񍡤֡䇐į +ؐ؈뾢ԃ쏑Ș߾氢 +°ؐӘDZ䥔גׄؐݡ׬łЃہ +Ũ򴈅̣ʋﬢ⣩鱴⬋Ɛ +׃ܭǓͥɢġ⒛ې⎈酁Àؐ +敪ނРښ雩ȶРղؐւư +ǰХՍћꡐᄅӂឰؐ񾠯 +깎ԙЍڝӀߤзцՎ抴 +۪κؐÃʌʮ竤նلߋֵߍѴ +ɘՆܻʩ˫㷮ւŘڐ֖ѡ׵ڭ +Јѡٗ貏٢衎П +ǂ蹤겫Ɉ頟ׯڗЈԱІڨה̋Łؐ +ߤ䘢կԨޅҳԳޥ뾠䀅 +ⲁʂֹ锈Ԍ԰ţޝѡߗ̳ + ۓÅ̶֦ԨӅ뢐Ġٖ +ЃՃмԨ߂꽅Ѐ̭ӟ񯺹ЖԨш +ψݬƌ۫쉋¥맵ÚҎﴌҞͩ +Ȁꔨە콅ԭؐЍ弯╹ݑꍖ +ԍс儂ըҚķ̸֙ռʺ̬ŀ +潶ꔃݱ⵺Ӝǰꔨ +ԀöÂѠ·䄖ĀŅؐţ뀪ޑӀ +ԃրޝف⚩髃Յࠆ΄ +ⷦޣ򙵇ĀŀؐęؠӒʐ斤 +𻞿գέɒ͢ԵҩҞڤǮɎҬ +ؐؐƠ忎ܦŀр€싲ޖՊԀ +ӡ؊̎ݲ +Ԃȸ밲ᙇ؈ꁋԃր˓亹㣪Ҭֆ +ÓůсÂʡŁ؀شԀŰ +‚ԍŰ̜㣪Ў̳˵с +ÂʡǷĀŅ̌캪Đ +ŅƿʟҤꏬЎȺе㜺Ϋԃր +ԓنʔϵǺӄҰߴ +낊۽΁ޘ֑ӡԞؐ +ؔ⛃̿ӸΘĵс +ڋձрԍ愖ĀŅؐМс +ؐؐؐ‚ԍdzĕۏగဍ +髃߃ҋ皱ۿЄЅڭʹǷ +מ؃ͨՕڝヤѐȟ +ˊտɒ˟ꅬȐԔߧȆƤЌԀ +ߘԦҺېĀŅؐ߫כܵ +ƖĀŅؐƽԏ𦆇ĀŅؐڐԱӄ +ؐ҈ҧ؈ꁋԃրԓ̤ӄĩŅ݋۽ +˭÷ۓЁ֑۽γҠ❮Ӛ焮Мс +ؐؐؐЌԀdzĕۗᰠԂ +ĴӠׇ٦˥Ψꀋŵύսڔب +Ȥ퀅Ņ̭ؐȱЩǖӖ泏틭ʚ +婂ͩ݉遅с㐬Ņې +ѡ෈񩉪🵭֯͞Ё󭽵Ύф؅ʚ箓 +ߐכĪ箴ʄޕ𚁕ؐؐʀ؋߾ +ࠆԂȸ𧥎ĐхԂʛق +ւсāؐؐĀŀؐ +сԁʽͬ߄ӀӠႀĹϵǦԞ؀ؐ +⚩ʿ‚נЀէ·դ锅Ҫ˘ӒĀŅ݋ +ܓ۸؆ت؇ɂꂚ杨Γ𯈀Дۂݙ +ˊտ᪣̖ԀҢɧ󢦼 +ՁŀؐʱꝤѶ̨𠀂 +üޘ񥓭еπؐؐҨ⛃ȤձˋꧽĜۂݍԖؐ +ؐҤnjΓ骟ȦЋメ勗歇ĀŅؐ +ِڂ⤀Ϛڪۨڇ +肊흩ԓ봦ӵ̌ȃؐ +λٹʭԋ؀ؐ⚩Γ萬ⷦ״ +뢌Ւ܉Æ󒰠ؐĜꟑ +ڬ̟ڔЬٗܛڟիŗي +⬨ęӖƅԦ쎬ؐ⛁͌耂Ѷٰ +󾠉逋մΟ֯ꩉ +ēԠʓ뜞Ȉ͹߮ؗչˋĜٯސ +ꕱؐƠɑ˝ػΡԲǪˢȯӠת +メ勚ƒلĀŅȁѡؐՃڂ‬ؐ +ȃ﴿njÒÀؐ⏬ȃɈ̄Ȇ +Ѕާ奥¤㴃ԅ莠ڐŁњ꯷ +Ȗ島҄ݑΓ눯ЁֿЁ؆ç֓Ё睭箓 +ȞƸǼԪܢ츗ؐƍɒѶ显 +ڿĕѧѐȄէؐč +πƄߩ՚ޗԎؐ纓Ģ͂񎡏ޗ΢ +т≏ǻډ؏Āɂ󋲫 +Ҏؐʣذ͈ؐ¯؄ĩ叅ڋ +͉ؐ샬ърߏЍͷܪ𮵧Ё +Ԅκʚ͒ζ⌬ęؐ +Áɫ̅剏Г媨ǩ +ؠؐ𥡐͉ؐؐ +ДؐӂߐԂ⌬麗׷Őݔ +ր͑۷ŐޑþֹÙëμΜ¯ +ŀЍ邊낊ѬԚء²۽ +ؐӢ脬ꊬȄʠ +ʏꊬʏ㓕фѡőˋ눱 +¨фőĔŸ۪ÙɇֹÙֹҪ +偯ؐӂދÀШȽנÊùߋ +܋񦄅ωϔؐ䄋Źб֣ġ +ДȂ񦨅ϗ㍇т䖔̄Ԋ٢՞ +ۖݝ뽨׃Ӕ劢ÈӔ̛բ튢Ӕő΢λ +ጳՎՎڍՎؐȋ֖ɱկҥ񽫪 +Д񦜅̸բץ +̘NjǦەܝՉؠ־ܡ򉰠ȫ +̈ͬ׉򇕟ȁЀՌѡ +ՍѽŐڔۦڛŐ۔ӷߪΙοٮ +Ùɷֹٯذ񆲖Ā͌ˆęߋؐ +؀Г񆈖򅖄̭ؐޖªؐ +ᰠؐ偅Ƃ市󁋂ؐȢРėސ׊˛ +Ԧ赈đ˒Ő㗨đےŐؾđ酣ֹÙ +ëμʫÂؐڐقĿ񲞠͂ +Ú濉ېЕ͂ﳠť +դ°ޅʋӠޫղҞճӠʋӠޫդ飌 +ʿנ⃥کؐԔ蜂ށթ +ȰЁ݋݊ڊيŐŐ씎әՎֹ +ݭЪܪ倅ՠށҢؐи꽂،ޔ +蜂ށ΁ԑؐހՄʂؐ +Ǩ݋êܣۗêê܃òܳêêêù +친˗̃μŖؐ薄 +ؠؐŠ͇ؐВ +גɻŻɻ߶ݎ߼ݎʶ߾ݎ㿤ݎߖǖÙݶμ +̳ؠؐ +ʄؐؐߗ堇ۻݎ +򗷵˾ʜڱ역μ엀ێؐؐ +ؐÀؐؐ +ĵةІ۔ێ +ێێ眶̵϶倅ؐ +ؐЄ󁋂ͺҮ闃 +ݎҮد闣ؿ˖Ùێ친 +Ј͉ӂД͉ؐ +ӂؘذீѽЄ˷ڱݻۻ +ۻþۻݾӎӯۤ친͖ێئД +͉ؐӂДؐհ +ȋڐč↬Нݍ莀⌬߸ +́Ё͚͚́́ߔ͚͚͚́́ +сͯظ갠́뫜ůȁ +޷Ծ܀ؐ𥂖ɕ؃ؐĝ +ڰ́ߏꦹްċČެ٧櫑ȹ +ՐڌͬĨؐ +ڐͰؐ̂ +Ăčؐ𘅖ݰ↤胰ّčؐЈؐ +ߝ↬Ň〸ĂčؐŶ +⌄ޭ믽ϿϾ¯̙λ +Μ뭽ί⋯ԩޢɓʏ̱ذ᧜Æ̱ǜу +篽ϻλ븣٦ƛÍ +ϩ̵ؐ؀Ěؐ՞ +ؐؐĚؐ՞ߵ۶Ï +λּޗ槟ɧܰ㏽ȣ̟Ҟӧͺ +Ӽʟμƍꩧ񎙳эƍθÎÎ蠾 +ᇞ׿ū +Д͉ؐӂД +͉ؐӂ´񃖄Ť +〸⒰܀ؐ̂Ăčؐ +↬􃠷ذߔߔϧ +կݛ߳ժޟǟ痭˯ݚ +uʫο޾ŋϼ旬ڿ +􏿜睛֣Ͻ̙֬ͷ +ܑ毾矟Ϥ眓χǏΏ +ÇΟÎ뗿߾ݵ +ﹼے烋Ĝؐωݮ֮ +ͭٓ۽Ïܙܶ֬߾翟ܧܲ幥 +疬ɽu˹Ź̽單̽ϼܣ +򌏼݌ߝ͘雹Ӯ +ʫӦ黬ɥ®咉ܹξٹȹνܨѹ +ܐǹǟ𛴨䑹ǜܿտܟλ޽ +Ͷ۶ܦڨ߷Ȃ⚰́腁ߔ캝ݷ®建׬ɮ +ޝ׮ﲫֶ׭ٯϲϲٲҥՏ˖ +ٷʾ׳ᅕٻϽ쭂Ǟ˾ +ڲ﹧Κۛܐܾݵ뮱 +ߞҥ쥗䯺ʔɓ燞رɞ͇Ϟ +ÆفǞɞ볇蠱쁇ۯۧϽѽݵٞ +Ͷ۷۴߼ɦٍ뭗򗥅Ԫѕٻ͎̏ +˾櫻יϳ˗駙Ǚ +ͷ«˙ŋ̳断ʼ駳ϾǙ󳏾 +Μίޙ̬ٙޚ喣ͷښ̛殾啙Ӳ +ݖň箼ē󲓧猦ʜ̄ƌɜԨȑò +̀͜ᇠ玽ȡ̜ܳӻ扗ݲͶ +ز裣̆ؠĉсߔ޷ʥצ׬ɯޝᇯߧ׮ +ܫ֤鯿럥Ɇ鏿ίۿ􇟳Ϳル +믥̿ҋ̿ϼްǞϟ܃ +ٳܟϜɧ톛ߟפ麪ŕ +җݔ࿂ϽȤ眑駥Ǎ˟̘ѣңƓ˟ǥ +я⣏̏Ӈׯ̏ߺᇟۧϻ魶 +Նؠ飋ċ̦צ֬ɭޝߧ֮ +ӫ֤ߥŗӟԧ⸵ҫԇ3͛ +ͽ򪽽˩̽Ͼڸ̳ʽ㏧éʽ޼ +ɵϽ۪ӳԕͷÍݜޙ˗ +ũ͝Թ㦦͞񚴩晩ʳȝ껴ƥɩѣӣǦƌȝÆ +РݑǦÏ뗺ᄅۑԮӟ +曥޸ߥڶܰߦۯؐʋ׮ͮٓܽîϮߙ +׬򫯒Ͼϒ嶬ҏ׽䒥߶;ͷ1 +䫯ޞܼɗȾ瓋䗦ɧ̾ǓɇΛ +ޛɻֿ̙ݔܓ䈕פެ˒ +ݔԏ˦ɞ򬳒眑رɞ򤣓ǦϞㅓÆ +Р佀ڜɃۛګǞׯ䎻߾ڿ +㍓ÍƖڵÏߦ߱NJ +רǗ睟觝Dz˗LJǒλ曝 +ꫝ˼‹Ͻ쳠̡Ǔ㝏Ýԣ +҉ٽ€ΠĐؐҮ +ɳΨ퉉큁힞햖 +풒킂픔 +폏헗풧퇇ɻϷڶݶپ훷ݾܹ +ӧϜ׿邪;ШԔרכꥵѥ +¨岹Ѩƿƶȴ♙㛷ƺիȦ +ĢӈțĂƘňҒ眝ϛ쓓艨ظ䘜 +ƮLJ؁ȚՕƼΎ˘˳ +쬱ژ錏˃󳺐ۣ +Ƌ΄ϝ߾͗¡腡נ +כ翆 䲹ѠƆРޙ +ɁηьԪ±Ɇገ߷؀І̉ʰ +ƼƌÆЍ䚺ڍӓ鶴כƕɉǡ +Ϸ暲نښŐȰřцȈؘ䈈谷 +ښ㖖Ó꧆Ǐݲܿéӆǂؽ +ͿШԔƥժҩר޺˥ÇȤ +ֵׯԪѓ翵ο֯Џƿ +¿я뇇ﯾե緷㾮ӣ +˟᡾ϧԈ򲾱Ѽ룣Ȉ +뽽ŋ奷Л럼ћǼ巊ӧǏ +䏟֟ߵϿߋӅ腡Ш⮅ǫ굞Υ翺§䲝Ԫѧ +בȤϛ׽ѷԪёɺɷ޷Ð +ӭȷ͏ꦧӻԷҍޮ +ӵ蚽􍍺եЕźחǩமΗ +Þϫ݋ݝ +׮鮚ݼúߺﺠïƣ֥ +ʪڅ«岭ԪѫΤҊځ߿ۭˍˡ߾Ԓ +ڜ΋ښ藗څֻߵڑА +ڎۛէܬԶ괵ڪ奶֦і鋊ڜ񶶳ӛ +զ蓳ڸ̌ʛ򑡍ӆ胂ՠ띝ڻ +ٳڇ⏵ݟ޹텋ڳ絧鏟מѬлċ¡п +قŋڣʍ¡˵ƪĢᨑ޾աؚ +􍍦å޾ԐɚӚ֩׵ج󫫚Ԭ谘Ғѳ覧 +ԳęԌחޮմ蚚٩Ô˵ +ŚϓӞ͂⢦ޓõ߿ݵ +獣뫱ꞿԼ͛״묮М́ +⵻Ӆ芅ШⅩҩʵ¡ղڪ՟ŢШ +ߕճԌׯԔ˵ĢУ΍ꪚ૫ƽ +ԯԳԔĽՏԃߟݭԷԌǣק +׫ҜɉРՙښŝǫԝ +ꏏﻻŤﯣ۫ϋՏߛǾ +էϪӟޮΝﺎސ٪ސѩ¥Ǫѥ +ȾЉĪХםֽ̦ׯզսդŠոõ +ǾհՀ˪ֵΪ㪑Ճȵݪ +ۛՇܬҵյՕ֦ѕՌ񎪫˕ץՉ +ܜƕЅǾЇΪە榲 +ߙǾՅêէϪӝޮΝﺎސސ +ҦߺʩجŔ¡Ҡܮݻ߼Ѳʺի몤Д䲒 +Ғʂ㕛ʄݵꪒҮʙĹӎ +ӣەʖǓ߯۬ԨٙԤ +Ɔ͙㕱DZ䤠ܙцʟ恦ֺʛ +ɓ㢼ƍի˗ϫϕў޽ݻ +ߛސ꫾ܡ֩ԪѡЈĊֈռೕߪج +Ǎҕ˅رҐ͜РݱᅄƱԬ攳 +ԔıՌ패㊁ߟݭەǓק׫ +驢ԤيՑؤ┱DZ䤠ܑքƕ +裏ꁪָųǏ̙ܽɓ +ǔݫصݱ⛮肿ߛꇇސѾ˿جۮȩ +۷ׯɩԹ傤ΠȷÎښ吸ʊ +˗勋ƾ壣򡎡߯Ȼ䝝ۛܬ +ϔ匵凥ڪɋ˞˓ȓ剉򑄄ܜƞ +۹쳳 +߿ʏ֯߳ǾݐïЋؗľɤ +̨̠ܮݻɘڙ寢贙ޤ֖ +벑ˠȎȖ勋ζʦ㲑ж +ݲLJȪڸѡȊ充ޞז̿ +⁢ޖʢ䡡Аɼž +˞޽ٝׯˮܑݺĉѣ߯۳Ƕٷ +¡ϡꋗѪȿӐҡҁtǓ۩ׯԪ +‘Ғɺ㛛Ҽ޺Ő͊ՠ֤ٺؐ椳Ԕº +ˇߟݭۥǭҖӓô߯ﭕȫٙ +󥹹ҬƆͣΖɓҘԔš˃ҿ +ȝһᡵΝ͛פ˯ރ +٣ݵ˺ސސ䟟ĢШɸɻ +Œ§އ蒪¡䉉Τڒ͉ईߗزʊޤ˒ +޲಴㒞חޮ뷓Ț +ݭǩʽʤёɑ˲ʊْʢђؘ +Ēƥޒωﻻ숬ȃ줶ѣϩ͛ +פˌޔ﷗٣ٵͲ䛮޼ސÇȤ +ߋ拫߾ⷚČΗ󥊩˗ɼśÉ +֌ձ֩Ā‚μ͉ⱱȈؼ𨞘Ž +秸Ã֦핷čեΐŌ⢢ᱡߜɑ剳 +򲸩ɜ퐠őب؜⏏ﯶȕۋ +ϟߖ߸ӧǏ񵞽ݻĻႴ +Ћ¡пŋǓ짶ۑŌΚ蟣Ŧ̖ +Ӣڍܔ΍ۓȴڒ⮊̌ʴ +â۫ĝ뫨Ԥŵ奨֦Ņ +ƅب۔ʝȐҘɢт֔ƣĈġภߛ +ŋְнݻǢ۷ŷѮݓݾ㢣 +ڿմ׮Ν︠ϟҨԏ譔Ǔ݄͖¦ +šꕐʕҨ—ȤԷׅج͸… +ָΊчȈȸ츨称֦鑠ƍº +ð٩˟¢ߘɑԈ򲰩ۘƊˆؘ +ĘƔϡ섶«ߡ‡ﶋޕ޺ +ҥᅋ³照Ή믫ڥܹސ +͖ಅވ׹˒۰ۂㅸƄ났ְݕ +؄˂‚ްϋধĀ쌈חѡ +͂ݭèԈʽ˅ёАퟯ˓ښŐ̔ +NjℱƱ䤀ܐʀᡰ +Νۂׅׯݒܸر÷߄ꅱ +腡ꋗⳙ붾߾ɼŧ +ΐƄÐ˷‚˟ؘ䄿 +̟䏌ח緓ïα +⧤ԔɂƏ䇇߾ˋ +㻸㶶뾥䛘߹ÿϝ +һƿ֠Ͽ︠׿Ћ¡̿ŋ񸼶ޭܹ +իʣИ䞃ģȶᱼꤪȃȀĭ +śڞͼޜÃë +પɉȫكƆʹ⥦񼘘ȴ䋍兇 +ۛ繺μ۞ҒٳǼĄ͛ +ׯ❿ϻرޑ޶ÅïЋ՗ +ܷ͛ӹܴʥиȯ䮉⒈ͮ࢈ָ܈₠ +Ḙ渳܍ԔɒΝ㻎Æ܁񻺟ܶ +뫷Թ빵ܪŅƭ喜󋊸䦧ӹܤ +Ȃˇ񣲢Р𰷨𽽹ϙְ܋ +쳳ĵ͛׸׮ҿϽر܃ɫÅ +Ћ±пŋ؟޿ׯԺɜšไ񶶸 +笭ʁ򀀃㖗˜ƅ˙񦧹㛜Ȉę +㴴ȩ긌՜ιʄᔕ񊼋Ύ +礥Ҹɜ‚ÉùᜐАٙ +֜γ眧¹䬼֭΍ʛ׸׮䜻ԹرÜ +ʏÅïЋܗⳙ،ۍ̦ͥ +Ñ좑͠ؼネښ٫⃈ؘϳﳳȔ򒽱 +㏎Dzݏɱٝᶶ뫻ص奧ή +㗔م삂ޞةҒܝώǟİؑ註Ȏ +϶ՕڲُٖϞݻ۷ط +߾̾ɓNj؇ޱӧ⍽ï߼̠ +ŧ޿謪š޾ɬŢ󛛬á؈筭ﵺʂʀؘ +ϳﳳȔ򒵾θ㍎ưìՏ񱺻嵴؍ +Վͪǰ񱫨ن٬⥦񬘘 +Ίㅄ؁LJ㹱جǖޞ˲ڲ紽 +Ʋ噘ݹպˬܗαΟ杸վǎַϟ +Шԏ彠񂅘ް۝ɣԦɦɤ֖ǃ࢈ߝƄ +ꪓ̥̀ϭٙꊹɜǙ̡ơ +̎涶̺΍ɘ疕˲˙̢ᡳȳ +ꪳdz㙱̨Ąʌ憅ǘߦˋ㺸ް +̛‚α̌޻Ǽ敫˗ϝ㥞ͼ +掝︠腡Шⅱ׌ꕁШĢ +Ɔ댬ƀᆄ€󌹹Ř䌏ޘ +А𐱰݌LJƜӓ߷Ϩ԰ٙ¨ +φ礦ҘɌȂ˃ƲጐА +ϰ؍ذ،ƓǏܿϸ͏댫ט +ҽ˸ñЋ±пжŋͧ +ɩԺ΢ѷĢᘎЁЗ +ѧ铓䄾̟ឞNj裏魆ǽǯ +ӫ蕕驽̯鹹֖㞑ˣғɃⶖÏ +鏡иӽ螞ٙ۹ϞП +ᢿ׮ѯܡߺĿԩ野яÅ +ïЋܗꕍʥѨ䲍Ģш𴍼ج髫 +Ж˴ˆ盝Ӧ蓓ؘ›цιϏ +ߵ譇ӓ߭Ҫմڜ«ΎȠ +驩⢭⾞NjѢᴰȈȼ޴͍ +Ҝ웛ҷٳǴڽܠݻջٳӽǏӎ +񡝺ۿ۱ӧ⍽ï߼꿨ˉԲʢчǓ +ƆԬժ…鉺ݎؠ٩Ԕ򒺱ƨԡ +ӻۛқ͎ɟ˾˩Ԣ +ᡵͥӳԁښDž̤⨱Ԕƍ⍥Ӄ +LJӜݩԧꋗƆŵӟ̜ҟ޻ǽƍ +˗ϟн˽ȑÿ̝Ћ±пжŋ +ɡ¤҈榅А΁딘ҠɂఔҒ +Ӕ䤄ƙІ𾷰ݔڨӓ +ՔŅʩъ̤ҨҒωТ +ؘ̉྾ÃƄӜښɱ +ÊĄʭ۔ĩׯҮߦܼȹԩ㔣Ǩ˻ʯҖÅ +ïЋ²՗ŦɄ󓌓ÑȈߧȵĆ +͑ɳԔ₼Ξȝ +ܜÃˮד竪ȕ̮ٙ䜜Χ +ˆˣőРȈϲ͇ +ّϞр¾֭ɗޤǾ +ۿ绗ɻᝂȋ՗ŢɄǓƆŒ +ݥɫؠᰤґၴϚΒӤĄശƚܑА𐴰 +ݤڞȭ󳩱ՑդŅƪȅޞ +ʸɌ餔򸲩őѤȠŠߒ +߹Ɏ㎤ؤʊɓےҝߦݼɺ +ҥ҅ȧϓ΁ƺߤǎҜ՟腡Ш℅ +쐑ŎֈݥČ˶‚ǜᙡϓ߈ĉ쌸 +œ䇇ߟˋדꈏՎ +˲ʈɡȑāꪱ̤Ǔ∱Ԕƌ +LJ܈ħϴڐۓӧǏć +⏉֧޽˼ⵕ˗Ϟͼ옋ȑܿĝ +腡ꋗܤ񄜎͋ܐ˄ţ‚ +ǘƼƈÄƐ݄ϵڰۉ㣡 +ϨƐՄŅʨܡ̤ӞҒ +ƒ㢣фˆ؄ӓ󶣸΄ +ʊ̌ʰջǸ붖ƍµ둄׈ܠ˸Ä +ޏ݄קï߼ƆǶἄ +Ưᗗ싋᧾䄿⇆ϏՅ +񭇭ẺՅ𥇥㾰Ѐϟ +ƆɆ䓓ܜ񡡃Аཽ㞞 +ŅĿٳǏ߸ +Ϝ»֠ϿǎЅߝΔdžސ곫 +퍇ø՜˷˸ၷӸ܁ō񃃸 +ۋ㺺øۛ҂Ƶ⚚ƭՅ竬ʽ𥥸 +񱮰ЀٸƆΝŜ㒒ܜஶØḐ +𰮰⃼޸Օ¹✜ظΑҒၳǽ +ݏ۷ݽѻٳӱŝ矸ջϸ﹠ +Шԏج̱΢΢ +Ɠ㌎ߟ۷חى҃҂ڤ +ªʛ⤨󑼼ؤƲ̤ӑČ +ȤÑਈؑLJ¼͍Ŝŋޞ쐫Ғ +͑א˗琳ӧǑÇՃ +ۮސފސؘƮ⡈؀绸氳ؙ +ꊻDZ죣𐻰خ秶ގö⛛à +ׇ㫪؊҂ƖዋؼҰؔ򲶱 +уĄჃؿۛ݃ܰ盬 +燵㭬ϱϞҼȐꊵ޻ƍ쵲ثװн +ѣㇰكݵ˯؟˅Ћ¡пŋÐʊ +‚ĄȈߏϏՅ +ֆ­皚᪪˷Ჲ¸˃᜜Λ̄ +ɟᤤظฬོۛ෷ +ξ‚ˇᇰ޽Ν֭ƍڵҥ +С߾Ϟ׮傢腡Ш兂 +؀ṹ򒚘ǃ䄚ި +Ψƨ߇ꠚʠ⣨Ɂ +̨χҠșʂ⠨ƒШϏà +ݡƗɉ־ܤ͡ߡ۷סס +ӧǠǠÇ͠ݻݡ¡腡ꙋ +Ғܜ̟Ԕؘ̀Аุߟۋ +ƗىۛڎЀׁݍՁŅގԄޞ +ꪘ‚ƁĀ記 +纻ƫ쌺ހۃ֠󚂦ݻ +͛ŋٳɓ౶୞˿˸Ћ¡п +ŋ҆ܜ̀Ԕؘ̞򹡡𐘘 +ށۛ遚àڠʆʠʀ +ႂ͘쫋̄ӃȼɁĘじ㈌𠬌 +쟟ۛՕ񁜝؁큛ʊ́ǁǏ +ɸ񃸤߾ݻ +ݡ¡腡勗܁ၳӘ䳾ÌưÛ +ߏݘގôڼڰ͘㣦ߏફ՘Ņ +Ȍڊؔ㊊ޞɃᲳꪦĤ؀ +ñ㘠ӓø✝΁컻鉱 +㞽üɆżѹΝ̭ۘ췰Ʊ㌍ +ؘ㌍ƴ㌱犂鎼ͦדũ梩ĪԳܤ藎 +׶úגߋϜͥ +؛Ȑ󏩠俹ħƓ풿в阌 +כ߿Ϻכ鳥߽ڭɗܧͦ̚ɛݤޟ +ɫ֛蒗ɵԩ񚼹ɷ̖ʗɉ휥Ţ̊ +㥷Ɏ䳱ȁɪɦȧד⒄ɬģ˾ +ͥ𰹰绺ɶ˲А֐קܯ +Ҭʅ򍩠ȐԐܽجݿįϿĨİĠ +ډɼޥܮә޼퉭ͼؒᰤ +ӥڄ£ܤ¥ʨ䤡Ƨ؜ +秶妸ڋΰ؉Ԅҙ񉜆֒ˉń +ͥӉɇ쬄Όlj碝ښδ듟墬ܜ +ب榲ͲϞҩ߾ȐԞ܃ج׿ƣϿ +Ǹʗ㟾޽劮㎾͛ݞۭ߫񋥼 +ǯꪮ՝Ƶ߭ժҙŏÎܢ +ﯾ䗊め񞯾񵵸ӱΏΦ✎ +㳳񙇙྾ć⃃-ٙƛ㟍ё +Nj⹹Ԫʛȥ󏩠俹׿ƢدĢϿبذ +ؠۘߟ󁯷Ï㉽ݻܮӘә޼DZׯի՚ +榦Ǯױ◗ӱɟ̖ɥ +⢰۱㣟㜞Ό͎رԦ贊Ċ +ŰسʌШŦ؁訶㺻㝝ˬ +ؘՏĪ╕DZኽ˥ŧĢ訔 +Ǐџϟ۝ŝ۷ч٢߭˗ы +榪ԫ޸ƵŞԭêҙ΢珎 +ﯪ큠ǷǢўŲ̈̌ӣ‰ɀђʤƉ +ф⣘̔Ǘ᡺ǧѱю۴ +ܜ㊊鴸А͍şڐ†ٟȅͽÜӤ +㤐޾Çǃ޿ݑ錁ڑIJج +ŌħŴșģܞ䤢ǎٓ訢Ǝ +࠘Ǝ뺋ߏ숋вƋЩ„ +𑌦ގŖ榲Ƣिۣۛ푖 +ӤҜחŪʅêӸ +㸐Ͻޅݮԙ߼öի՚쿱 +݅܄ا݅ϵأ܄ρ҉Ê䤬ò訦Ò +¢ȷ᾿›ᬮŊᆣ̣԰ᢱ +LJ񸰖湼ơṹᡡ܍ۛφ +㖖ӸחՅåᢢʅۀêҷ +Ԕþ߇лÎǟ͛ݞ䳅޽٭È泰 +·ׄס—ҩŒҨ§Ṽɐǡ +‡»ㅀŒֈɌĥ +񸡬ր驅…ǾáƓ +í㨾ۛՎֆå짧Ъ奍ȐԐ܃ +ࠐ㉾ޅݮә͖赆߾ڬ +Ԣ肗ԩʆԨɂ +ȂͱׂގȨ٬Ӄڐ +ՠ򐇋ގ𮭅Ѩ€ͅу訸찐 +Ȇ㎎ܜׇՏðԔϏ߼̥㧴 +ǵ۝۵捋ۃ߇짶ׁీ +攸ఄ؂Ӆфٖ҅Є΂ +𰠑ﯠ秠ㅸÉ۬쀋ಃƀƋЩ +Ȥ܀ఁ驰Ḙ؈烳 +۠ٙ舴ڸ́ݠݶʂŁŋӧԪ¥ȐԐ +܃뼏߻ݻ͛ׯ֫˿Žⷛ +線ߧߣʮ΀῾㥿濺ץÿ +ޞߤϿ̦ϡ +ޏʊү޿Ŀ䟜 +秿ݧ񷒵Օ毩өȅÆϽ +枬󽾏ܾӃ϶ؼβƣ +簀﻾뻼鴾Ծ滽侣껼 +Ϭ΢Ϩ˷춏򱙴ǧ謴⣓ +ǤɔؘԷ웚 +חƍ͍᫒͋Ч +ÇN޻嵂ڽヲ +fކ罺˯㽿ժӯ潺ʥï +⽸ޞפΎנޭ榗٬尼ҩ޲ٻ +ۺꥑĢެ֋ּɻšޝڻ坘𻎏Ƽ +޶뫷ؿ譯꼕ފ驷߼ +ׯ轶ځⱛǮ +܀מ輘ѩ鹎ɉǮёǪΒ +ף۞߳𸞦̞ӽШâ +㽸уɌʳ韙ưǽࠧӟ +ˋ詯Ǖ秸ɃϞҪυğ +Ⱦ޹ݮ͆޽ۭ斋ߡͦݷ +ݹݵۣܸۥ򫕻۽🜸ۦۢ񟜀 +ݷЇ߽ܚ暲݌͡ꪛ +ùط񯯻܋ʽκ̽➐Ϗ +ţޞ޻۝ĝ҅񳑈σ +ڞ繝ݎ巻޿ꅯߺ뺿̮ഺƥǻݺ鵮 +ݗ㺸ծҪٙԥиإ繎ҩХصΎˠ +֖Ӈ㹶ḙ엋݌讪šꪋ򑈮ޅùؗѮ +⢋ܭܳҵ᚜󍎺î຺󳫩 +ફԸݕ驫ˈ绲ݶϞҪ⟠ۃ֙߼ +͆޽ڭΗ߃級έܸӧݹ蜗εԩ +ʥԨɑΩ𞺥ߩנ统Ξ +ϹΎǹ䱜̦Κɥ΂ɠ񸬧δڹ򮮺 +ι̌ڹ團λƜΝАǝۛ +ΪŅҁ⬪򖔸̶瓧Δߧȅ͛᳹޽ +حˇⰛƎܸ׎ŅíџԪظ +˝ǎʝቄĝäС߱ܚ𸳎 +̦鎚Ȏшڱ򬮺ШǓα똙͹ +ধĄ옚쌸㎞חϝ囨𔕹 +ʜŎˑđ΅؞٭ⱛ +ƣ￾ʮگ₨ӻΌ濺ҩЮ؏ +ؾ痉컻؅߷ɵ̦Υڈ +Ά혌ۗʾĄܠ柙ۇ샃 +ߟ쏭ӏ篭۫ɉޜ͵ٳϞ +Ӫ;ղߌȾꕡڬ +Φ۶ۛڿٮ뻼鴶勋ڍͩÝ튅 +滺ɥà؎ϱض瓉컻ж㓈ܶ߶۷ܴ߷񦸶 +̦鶚ƣڨݵȶƠĎ혌ņ͖ۖ싋 +¶曝؆폃߿ڱ󳭱૫ڪ핕 +ٙϷڲ왃Ձп˛ȅƭ񏐪؅ٿ˫ⵛ +݁뵘͍կꭗ֍եԪʖ֣Ԋ +􎏭֑څΎբ֖ٷܮ֬축ŲҲֆʧ +鴫Ьʢىī㭸֕޶Ѩ‚޺ا߬։ +Ժ❞־Ϗ谶ۭ֦㣵筩٫ +К͵ٳʳϞӪ҆Ԑߜϳٍ +ՕūѫťਬщŪ +Ȅ‰Ǣؓ˲˵۸ښͶؖҭ̶Ȥ +衐ౖΌƲޭ˖˛⢅欳ʲ陟ǭ +غۛ܈겴뭵ՕҠۊ֖ +˓ȟΊ␊㟠ȅߛͦ続ͷܘ歖 +ޚŅЫ܊ӠИج꾼ˤ惃毑ȼ‡Ύ٠ +֖㙷ܮ߷浵̦̥ݵ沢̠͘ +ٌŌƛ痗ŀųذϛ̳ԔҼវ桡࠹ +̝ۛŃ촷̵Օ殩ȱ͏朜ַ攪ڐ +ªê豾ˏԡ쏉缲ධ܀עޚҫ +̧ѱɪ޷ŦΎɠ֖き +߷ɵⱂƳѩĦ׌ͤȴބÙؓޱѦӳҒф +񙖖󦝹ƴ嚜̘ȴ蚜ͽ秩 +̍ݝƘՎԘ̥ίϔɓʕ␊ +ȅܘ鑌ހޚԫƳԨƹ +ёѪ߷Ɓ¡ٱڲּƎǸ䳍 +ɴηƪȡꪑIJƂǛ񸣖ƎڸѨ‚޸眝̘ +ƉΉ̀ꜙƍ߱ƶ뫱԰כꌵ +奱܀ꬩƜ㋗ƗύϞәڐ¦ê豫ˏԼ쏳 +׌׆ܴŅ熕ʠԂёƆ +ΰۆ߰䄼׍惖䚘͝ьԪ±ă +́㍸⁋ఆ޶ΚӆĄ᎚ƌࠡ +ڼ͍騯ʌņޞ +Óݞ␊㟠ȅޡާӈ݁Ņޭ +Ԃ酩ޡɧёު՟Ğ߇ϯ¡ы뷏 +뿱ѯ콋精ӨܲٿĢ܌ƿǣ +⢞ү̌ڿؿ䟜ԏ٩з +㣾קտ諪ƕ驣ب蟿״ϩӆԐ +ުꮯꗵܧҁħ痃㠓ҩ +ؐȤ݉ȷߥ鍍퍰ٺ +ԪǢĝьŇ㖗˺ŝʷ +Ѝ݃Азݺ秮ޮյ蚛㺆۫ +骪ЗӼнė҅ӆԐߜ +рځвӡδعȫꏏĢⰷ腂 +ۛ鷊ܮڵ局ڰӂҩڊ˦խ꒵ڬ֋ +݂֮闗ڝ»㎎ƴڡק +軻LJډѶ䛛ݝݭԖʴᡶߛ +־䉶ָۼȕ藗ꚕʣԂѨל +ƢѬئף˳񴛛լ븜ᳵ +ವ΃蚪𨚲ٳĢ񱚌Ƴɳ싋ֳ +馎̤ь놆ÚߟݚLJӓ֦Ѵ뚚ݝ +ӣ˵ǥёГ޼мʕ␊ȅ +ڥʥӟڦӟ꽽¡ы +竷ԛ쨹ܰԬֳ؀ꦓ꺜ͣԵդԠՄưꕕ +֯ňŵϫԳꙙΪ䄤Ճƃߟӣ +궶뫺ҷڸѡӗţꂂם̸Կ +ʕԖ␊ȅұНѱʪ񉄜 +ӉץԛխⳁËՌ·Ѩ֭ +㮪Ȥ𢐀جԫ𫪴ڵҭоׇͩճԔ򒌏ƽԣ +ȵ⸨Խ٩ׇխƭӓР֪ժ +Ņ֕ӿհڐªêֱˏԡ쏳 +ժةԪ޼쨅鍍 +ŕ퍰ʖ䂈ɧȤဖ€֮ʔʻ +̌ڹʱǃʁ۫ʎځѶ +䛛ݝ֜ӣԨ˕ʒёЙ䨳ϔߺ̡ʿ饭 +ۇȕ˛ɔǀ՜ऒĕĊݠ +˱Ɔ늎셕਩􅍆꣪ҐǃŪ +ˊݥؔܜƨӊĄܱ՛Ê +٩۴ڔǭبթ똕ŎՕޱՔޞ +ԼŊȘšǿك̆Ԋ咉 +ؾ廻¼ր̦Ԫ„ +ɉĹّپ܄ʾȈ +䏎ʇ۫˻䝝ޑڪ鑷ɛ卍ݝӣʫ +ɉüبϟϗᅲҖԐߜϻ +ɥȄׁۓـł̦ +ƃԪ‘ƢɈؙāٶ܄䳳ʶ +칩㻲ĶʆΫ䝝ͣڪ鑵˚䍍 +ݝӣɪ岲釩ԤٲٳҨ +Ȗ҅ԐΞ睞ʥجۓת𝠐ȷڂǀǓȹ +ܰ峥ಥӍʅҀʤǃΊŘʱŏ󺸨š +޺㝝ԔҸǥȈʇϻ۫˻Ҏ +ڪ񑶷˛҆۫ǭ˫ٙڐܬ򤹹ґ֖ +Ƨ堕Зªٟ֐㰷Ģۀϗ +͉قߗ߰ـŒœЩɒɡ艎؀֤ +ޖɖ२ؐƲ̲ຊƤûߏ +پ萴ڤ󳤩بꤵ㒚٩˥ +͕üڲªêֱˏԡ쏳臫߶Ģ +ƊΎă⾟き߇ۃŒƃԳ‘̠ތ +؀ކь¹μށ⩩䤘ģļȒ +ƫĝ⎀緶⦦ø߯֊⪪奸 +狊ąޞӜ߉ɿȅ +ޱΎ؇ۢき傉ېрЀ݅ +РńŘ兠ٴ܂쿯ƴ΂쌌㎊ +Ľԍݭ񊺺ڪ鸑ď۫㪩׋ +ĕٙԀҢ񊊊Ύӧモɥ˘ +҅ԐΞ쀁ʹ͡؀ܮ߇ۃ춐Ș̂úƃԪЀݕ +ŒȀȄҐąňƃ尴ϋ愃Ƹޓ +ȸιŽ듶ڄ¦㣰߯ǵš +ѡёИퟯ˓ȊܗϟؾŠʢ +귫˺ۿɥك +热Ɔ낶؀ɄӅҁꪂĢؚʊ +˂ް̌ڰܰА +ƣ݂LJۅӷРՉ͍ե헋ʄを +بφقٳӧモ˫֡ڷ藫Ï +Ӡ豕֡䅥둕Ȟۈ܃ +րج䂆өϢ܄ؼ؀ +̶σ₌냽 +᷷㣿ϯ奿ί㗖᡿𧳳 +Ϟ񟾥ڲҬϿ㮱ꇞЄ߉к +߸ߣ걕ˡ쀮잋ʅ +ꪠĢ𠐀ʜ⭮򱒷 +𐷰ޜϏLJֆۘސӓ䵴͍ +ūɉī䕔ތ֖ŋ润ٳޓȿ +όƳ׫𮲾҅ͥЊ⭯ڪ +㨠コ㫨墟ʯԐ߿뀱Á͆ಁ +Шܲ؊ห𬮂ٰ́Ԕ򒻼ؘ +А𐸌Ӄ纻LJ烶˾Ԅ䚛ݝ +𫫹ՆŅƭ󳲸ܳϞ񟮼ܔ +ϙ˨ڜ׬䫨ߥҼ˥ʼ +Ъ惸р +℁فކ˜ŀ̇΂񂳾䄌 +࠘ﯧӍݍߧގڽڸⴆ秮˩՜ +奧Ω㔖ʸŜᢢᡧ𲳹ٜ磜ϹϞΊ +ܟ ֆЊʅ㡯फ़ +֣ݗ…ȅ؟⠁Έʅꪠő +ǃీ鉬܂Ԇƞ +ٽՅٝֆ٭䌷԰竫ʀŅ +痕Ň좢Ν쬬ӧ← +ڗђ͵׬䫨ߥҼ˥ʼЪ +Ш̆ĂĢł +‚ԔǙܰ +ﴵ洵Ãձ뙜ՇŨ԰ٙ¨怔 +ޞ…ϟܟḲƖ¹̠ +ә߱Ҽժۏʧ֗؊Ъѷヤ +ª߃Шဖ˰퉙ξϽlj +ƺŷڂ޴ڰ狫ܑذ޲Ȭ܎ʝϿӽ +󸽅Ӹˁ̶覄ྀ׻ +íꦢҁʥ㱸ȧԦĂͬ㶉ơلÛ蓌̂շ +ިȵƒ΍ݾڷ󿆢˜쇮ӭܿܕ܏ +ٔȲ괤Șޑ¬Õ޾ꈕӬ؞ +؋͇֫޽͞À̸Ø +񮻝跡據ׯ׵ںڅ娕ň̺ӝ̮ǡǣȄׁ +ݮŵ魊߿鯠Õ +ãҐǩʓאǽʳͅѿƫ׈ҽųƎ… +ߔ煭ØخݻӸ݂䂗 +£ꕘڦ堛岁ҩȦئդ +ᇡڅϷת֮ʖגŕݾǮ +돸ԯ׵ݗѩزϲȴȘΠޑÕ +ϾꈕӬ؞͛󃳙Ո䂗 +̳驢쵠لƃՖժԪЮũŢ旝ԊȤ +蔢帼܆˿ᆬ׻եǃіҖť붴ڗߢ +շ܏ϲ괕Șޑ +ÕϾӬמ޾ా憼泸Ņ +Ȏ脧ɧھ§£ꕪԂ⑊硗ҲźȥĂ +Ŗ袒¡Űٸܮ⡊ܸ᳭ټ +ûߟع߿ўўԐᴂ +Ǩڳגλ缂ѨԐͱȊг憬ӯ˘·ƣ +νᐘ߇ޏִ£ԂꕪԂ⑊硗Жȧģ +䞎è༐ͽ޹dz犂ܖ璴ŹΝՍ +؏Ŷ􇙯ѳ֐ƾ龦 +Ր󷳂揈ө鮯ᲁ⼆λшᐆޏ݆֋͢јЫ +ԪӐډ㐋Ȭ ѽՅϔܮ +Ϥ馊ه춓Ų紮ߺџȌ֐ +綉򒦓ŅǚٙƚӘ߇ޏ݇Ӂڭ趡 +ٚڍ饭Ԃؑ硗얲ȧģϷ +نɧԐڥӫͅҵϔٚ슺бފݳ +氂堂ՐⳲŅáĥĕ +ѳ鴠އڍ֡ҁʥ؄堓̆ťǡ蔢Фχޯ +㙸ݠɠ𼸥Ϯ춉պӄշۧˑ˥ϗ +ˑ̯Πٙ洗ҜⲰՂͭ +Ԫȥ٬²êɽыÐքǃ +ؔƼᖘ컵ɴҍ㒕Ī؅ϲ؅포𸤆 +ޏѧͦЯԫĥ岩ıĮ٬ĺΉ␍¤ʊ +쐈ՅДƅŐϏ曊٭ݏ̦طՎ +ق֞§ôīͦєݭ֡Ь¡ˑ٬䲐ҩ +Ͳɤ،ơ¡׻Ł䙤頊ֈݾن♘ +޼Ǫޱⵞ衱·跉֋͢ѠՈꕅԠܦʥ؄ +䁈ҩȦĂͬѨфÐχޢ˅ +֮ҵַՐĝ򶳂붉ƃҵѭۊ֔ʚ +⑨򹢛̆ȧԤܓŋͤ≇֠׋Ł䙤đ +Ζȁö渹ѿƱ╴ڬբҡԢŢЀ +鴦ҤĢǵŒ„Ðߏǃ򁬃σӉ +쎇ುڳ䪝ߛ؅ڻƼƓ߀绫ѬҨˑ٬ +ʦ颕ҢɢģĄᰑޯД˅ŐσӉ +dzՊ쮛哓ǪȈےŪڮ홂ҩܖȐ +،Ɖ̈́Ј烯ぷДنɢĐျ춥⁳ +̓؅ѫꯀ۲Ɍ񢖕ۖ́ +أޯšܔ–̉𼸝Áƒʜߛ؅ڻƼƓ +߀绫۴Ģ؉ш’Ԉǂ +و᫕䂓ȷՐ㕲۠߿ +”牧ิ᳁ج̦恊ݸ +Րο﷯󻷩ʶ٦雈Ƈ𸈻ح +㶿ɉǪޱԊⵞ豊令ӒҎ󸛠 +ÜΧؓ涓ӣܿƱ╴Ξѐ +ǜ𸎰ڥ쳛ⳙف㾩ϗߡַՐԅ +亦ϓ݃״ѱ╴˂܀ڬά㯕ιֈǔ +ǪȈŪ짫ྗĽƪȞϘƯ +͝٩㐑𬂥ڬΞǪՐ𬂌 +䧙ڬ؅ÝؓŪȸ௸ƼƓ߀Ņ⬂ +گˡᘆᾆᘆ̰͠ؾ +&] +[s5; Image designer stores images in .iml files, which are then included +using one of iml headers into C`+`+ and compiled into the application. +Such images are in the code represented as static methods of +class representing the single .iml file ([/ image list class)].&] +[s7; &] +[s7; #include &] +[s7; &] +[s7; using namespace Upp;&] +[s7; &] +[s7; [* #define IMAGECLASS ][*@(128.0.255) MyImages]&] +[s7; [* #define IMAGEFILE <][*@(128.0.255) Image01/Image01][* .iml>]&] +[s7; [* #include ]&] +[s7; &] +[s7; class MyApp : public TopWindow `{&] +[s7; public:&] +[s7; -|virtual void Paint(Draw`& draw);&] +[s7; `};&] +[s7; &] +[s7; void MyApp`::Paint(Draw`& w)&] +[s7; `{&] +[s7; -|w.DrawRect(GetSize(), SColorFace());&] +[s7; -|w.[* DrawImage](50, 50, [*@(128.0.255) MyImages]`::[*@(128.0.255) MyImage]());&] +[s7; `}&] +[s7; &] +[s7; GUI`_APP`_MAIN&] +[s7; `{&] +[s7; -|MyApp().Sizeable().Run();&] +[s7; `}&] +[s7; &] +[s5;= +@@image:609&764 +פź֔ŨŴРۮǚ۶ +麚ִŖʰ̝㈢ثݙ̝͏ùү +Ҥ֑ݩɰÏ뉸Ҏێہ떌ꠁ +֝ӭ鱸ÎꏺƯ냊Ѿ͗Î˷ +Å⸇Р⛗ű𤇏̗țŻ㑾謡蔾м̏ +Š͒톇󬠟ɁƩݷ׃޹񫽹쿰ދ +̀ϯ슩Ķۯñ£ڪЂɧ͡犋󖪿 +ДÍØԂ䁙ǧ׸Ƃż +ɑ̞ǔɘϻ㰅ۈʓ‚ӿܐȲڼ´̎ʼnε +̵̻ћːͶз׆﷬Ė +ۺԙأיթӴĴ孿Ҍ +늫׼ԸΈ۝ٸ߱㗾Ǭٟ쭴ޣ +򖪷Աͩ԰λսߖёݪ٫ +畞ָڀļ؟䚶ŵ֡ +菜Ծ܄ʩݴ噧̏ϙꌡ +뻊鶌ΌǶӰ״߽騲ȓՆ +۴蝢牶̌ݚеĠ +򗉜棉ˢ䜥Бڂ值簆É +ݟˉՊǍۅ®楽҅׻縴ϖ릺΋ +ڵǟ˯£ڐڼЬ۵ʷꏽڜ׆䏠㥰 +DzѮ匹إչ⦻І̵غռ߷ξ +휁궗ř䘛Є쪰뜪ǘސ͒牪ϊ؊ЪޣΉݛ +ҪԶ؛ܛ鐑ڙڵټӍҷ͍֙ѕ֕ +즵哩쳴³ч행͵ǘϼ㈖ۘٻ߄ +͋Φݎ٫޷ٳ̪ׅβΊՆʿę +ۖ蔏ȩ̗ţ͖ɞΌћçڶ +݋ûߘاǰՒի؁ +ߌĵӮؼڵ̖㈧᳀ُ¯̜֙ +򄊽իڛԦ♷͕汲躎ġ޳٠׸Ȣą +ĥ鬅ޓҙںҠʕ͂٩⌥悹Ơ +І잟Αõڮԝߙķ֒홋ýװ +ܧ趫ѫّÈؗƒ֮Όَ߸ +洮̛ۘӣϧ̸Үijス⏞ގڹЁʴ +Ҳގܲͻݫ皾߿œξ񥓾ݲDž +؝ߐݣՑ֘®ǵּߩՈ޴ޛ⻊ʿޞͯ +̇쫠Ⓙұ诩Ճ㑆׌͋ЇϤè۶Óޠ +ݾлĞśٮϖ嘧շϘ⧤Ň +خǓߢޞնϜع˰ߟî͂ +áĞ飶˩ϡ꣯̂ھԞݧڨɠ˵ԞۮԖ +ܴǡ믁ߣ̂ھԵ턤㬹Մڨ +ƛ嗗ߛץۆάڲ꣝܃Ԗۧ +״ϑ𳉼񖲡ϐϻ̛ +знɜ㒤ـɕכժɮҿՆ +ى씩ҀՆưدɣᚩԠЧҳ +ƈ׃ٕƞȉ݂ŞԠ؍Ѡύϛᒆ +׃ًڦԶ߭޺ǕڰЛ嚝ԖЛԖۇ +ۣ܃ݮڲԖ뒨ꣶܣԖۇڱ +ˣھƿھ뒨ڲĉЛƚ嚖טћΒǣα +̕Ԗۇړ󅆞̥܉魓ƀҋݸ䁃楍܏ +˜⺟ܓӒȵÏ䥇纶𣏈 +Ùϵ˷ +&] +[s5; &] +[s3; 2. Image list classes as arrays&] +[s5; You can also access images of image list class as an array and +even change them:&] +[s5;= +@@image:1009&564 +ʀ񀀀՞ߕį虓Ǹ҉ѱš蟈į +뭍ʠ諠ۘڪ̻潞Ͼۙݦſ͢܌ +ͿٛǦٳɕɬʞ㘇ž٥āȤإѭ +ɕеˬٻ䎤߳ō۔ۃû߻ +񃫣—Åݛ§엉ǖᅝȜƆ֐͍՛ +Π׼ӲݿŭЫ٣񈢏ۜŮΒȳ䛩 +չ쿻ŭ↗Ń󓎽흥ꤚԸԗ +ljծݢӲ¯֩ɮѮěФќԭݚج +Ԯ뗃˖̪ȩؒۮ࡭ͦݻݧյ +́ߙ軴𱷾䗵²ԭ˱꾫ǮӇש +抝̾玼Į՗ߕ׮ۥڧ;܆̨ɕ +ڶ嫤əΩԬҪסݟ˪썼ꛁЇ +ݴʭׇĪݹ䠭Ǝݣ +͕ܵḿבձƞ򄛛쯌ሊ߅ղ͘׹ +÷ǨϨזþ˙Юޠ +԰ƼÊ̽ո֖ +𗠁Տͽؕξʁ羱Ԯ◦ݡ˸ӈƮ󗂵ʜ +򴦥ԗ驍׍ʚȸ삶 +媉偻ٿ͛בԮյó֔ǧԏ̇ϝ +ݟ®ڋڻ鯦˞؋͟ޣ嗍ݮʇ +Կ҇όŢ꫈֏Ŗ̯ϩ۶ +ޗƑՏœ⢐فەݬ͈ +٭״ʱɮ顗ҵҾ޾̵߳Ǯն +작ⷰ슖Ҍݚֽѷޭыﻍ܅ݡ +ß뗻횱ȗꮎӭ֏ڙЧ޹侒 +ȸ삠 +ʮȀ +&] +[s5; &] +[s7; #include &] +[s7; &] +[s7; using namespace Upp;&] +[s7; &] +[s7; #define IMAGECLASS MyImages&] +[s7; #define IMAGEFILE &] +[s7; #include &] +[s7; &] +[s7; class MyApp : public TopWindow `{&] +[s7; public:&] +[s7; -|virtual void Paint(Draw`& draw);&] +[s7; `};&] +[s7; &] +[s7; void MyApp`::Paint(Draw`& w)&] +[s7; `{&] +[s7; -|w.DrawRect(GetSize(), SColorPaper());&] +[s7; -|for(int i `= 0; i < MyImages`::[* GetCount](); i`+`+) `{&] +[s7; -|-|w.DrawImage(50, 80 `+ 20 `* i, MyImages`::[* Get](i));&] +[s7; -|-|w.DrawText(80, 80 `+ 20 `* i, MyImages`::[* GetId](i));&] +[s7; -|`}&] +[s7; -|w.DrawImage(20, 0, 50, 50, MyImages`::Get(MyImages`::[* I`_Circle]));&] +[s7; -|w.DrawText(80, 0, AsString(MyImages`::[* Find](`"Circle`")));&] +[s7; `}&] +[s7; &] +[s7; GUI`_APP`_MAIN&] +[s7; `{&] +[s7; -|MyApp().Sizeable().Run();&] +[s7; -|Image m `= MyImages`::Circle();&] +[s7; -|MyImages`::[* Set](MyImages`::I`_Circle, MyImages`::Triangle());&] +[s7; -|MyImages`::[* Set](MyImages`::I`_Triangle, m);&] +[s7; -|MyApp().Sizeable().Run();&] +[s7; `}&] +[s7; &] +[s5;= +@@image:784&920 +ǜ׮ż۰⠭ԂЈӅӉ +‚Җՠ܂ҶԴۼ潟ߴǣ̹ǝ٬ +Ⅸ幃ӭÛو۸οˑر㑕첝˚ҟ +ŏƀòĢޥ֌ÖѳìԎܮӶ +츧寨ܱÔ۝ʬ祶ȍ߃ث˜ȶ +ճǗɠǶޡвúŸ +ѤکڔŅޅΔ凹͋ +բɘ滏ۘȿ頟樜đ́ö֮䨲ǽ٤ٻ +̫ۘݸ•ѩٽ緿丷ګ +ԪÃٚ椮ݸíȟˎؿ鐻ģȰǷ󛖫⨚ +Ȯۃ܂󪭂ԣ̐؄ɢ֝اΊ̆ +Ďظŏؗϓ͝ܜ驑͏媕ֻۣ뿲 +⤶ŒիŁƳɶLj؁ᇅјؖ +œگȠ։ԕ뫌̥ᖳŎ֑ +٘кʈԇܘŽΧ㱹ւ +𩩹𑙰򋧛Ʊ̣٤ְĝ먭嗧°Nj +ΫѣDž֛ֈӅɩɡȋᱞ +Зޅǵ鄈ٴ׋較عڱůŎݏލꈿ +ٸ曏֑ۤѥАǸ׷߁鎾޸ȫﲰΝȝ󗜯 +ݺሿŏӻᬖح֧ƪΩ߷轘┱ع +Ɗϋϼ۟ĺΝی +スد߿ͿՓʰۛۦ΅ɥڲޕ߻ +❚ڱǜ󾲡Ģʕꚜ̌ +ٲғø蘫ϟޅаĺ +ؘÑс٘⒬۫ߴϤó骲 +խً̄ެܹ񊦆檘njսѺƀƌ܋ +Β̦Æָيٸ݇ȕ׮Ś҉߼ +;٘Õ̕꯹ɆӚ޷Ϩ⬤ɪ +ۓǻ⡰ڛ۪ϑྩյ +裂ӻ罗͡ð鄐̶⡰씖뚳 +ՑƜҌɱ֒⬤Ɋ㥩Ҍɱ֕⬤NJԘʦѮϙ +财纺򹈅׫뷩Ӫݽ҄񑥗ωȼӽՉ +󽶈ڪݵ돈ė⯔㥩ʄґڵڞ謬ݒժժ״ٳ +Քꋐÿ拐ʔ括𺶶ڵ +°ֽ݋񕚘ꪫ۰ڢݴ +̱䔁֑̆ίތ܃ۻԚ¢ +옾˫♺㮰Ƃ̽舎̃Ł舫Ƶյ⟴񑪪ިꯩ +טƪ綨ʬׯɹ™ߩΏӫиʼn췰ϡݻ +͵Ǻ۸׽ʼnվِɪ١ñ㥩ƜҌɱ֒⬤Ɋ +㥩Ҍɱ֕⬤ɇ㥩ҌЫɱ֒Ɋ㥩҇ɱ֒⬤ +˫ˮؐᵼŭ֜﭂ٱŌպ՜ؕܺ +ē㕪ǖɕⵍա̴證¥٣ǭꅖӝ +ھҜԹ״Ŏɱ֒⬤Ɋ㥩޵ƔɌՁ𣋤 +ؽ֛ϋᬑأύճ߈Γإ̕ͺϒьԃ +ΙްμͶΒćߑپᲈݒɫ͗ŠֆâǴ +묬֕⬤ኤ޻å⼭قáܨаڔʆ˓ +ڦЕӬˊ͏ձèڀǫļûŎު𰖓ܫǬ +֞϶˝˱֕ا֬љʧֲּ菫؉ +ñ㥩ƜҌɱ֒⬤Ɋ㥩Ҍɱ֕⬤ʉْ̒Ɇ + + +@@image:800&914 +ŢʁĠ•ëɂѻ +ƒЄЄċ߶ݿݳĢȤ +˜ڔ굯ݡۃٺڱÿȹ܄ڞپօ̂ +Θߧηքх誇שѶ¡񼶱Žݞ +ݞލϛ̏ӹ۞ϙڑ޺؂ٹހ彟د +ΛLJ񷐇պɜہгѮĪ +ӺѵÝӐ⼃Dz¼ڌӧ홝ӑؚ +ޝܟ񺽌ţ๚ؕœ֪쮫ҎնϪ +♪ѬԞո۰됞ٝۧ≘קԱٓ糅Ϛ٠ +؃퉏췙nj퀳ÎٌĜƣ +ä̽ūɪ͜ڞ͜ +᥼Ʈբ눱؏DzѬ潹щɅ֒ÇŝӼ +§ǝ޴霐ᮋƝ۸݉㱀ϱԇȜ +̫Ӓלƒ̣惪ƕᶋִ֢ +ꗃݵЀ씣Қᒼɫ躖 +냑ۓŇѤŒފͷː̎ӖؕƣîۡĴ +Ǖ冶âˌςԣýܳ➯󾛾؞Ƈ +֜؆ޏ㎏溚޾뗟񸴿݇́付 +ˌ֏񼖦惱ӵ£׌Ƅ쇐Nj៭ٿ󕬪Ս +泥ثӧḭ׎ճﻣӣؕ +ďًÒ޽ޝŒ⫥η̝ﯨ +󭏪ڵĉܣǏߡҕ֩˗󏙯 +Ѽհ骑рȁۖϓߔďŗ׮ +飨Ȼ߀ķ–ﯿϕȍ稻ܶ݀׀ +ߖپ͛榩ٝ๸​ߡ˷ÏϟŽ +Ԇُӊ۝ɮѣ൶Ā€རϏĖۖ +定َؗ끾Ï۷Ǯ޵뮮ۜ샥ඳ߫ׯ +֞ܖꜼؘФ횉܄ +ȓƄ箧܍נ¹şԴƶڠÇ +ޓܖɷ͚͛䗿ڰ +ܵǾ—򐀥ɾܼ䤌ʜܖ節ڣ +ڵٓž܎ලݾ¯޽ڶۦ͛׬ +رׯãУ숑ܿ톽ڮǁɀəи޾ +ݺƍǮϻ؁Ռ뻶ܨطͫ +ǀƒ߿ϟȑ£·˘ܾއܖ煀ի믫ɿ +ͿМ﷞ؐӱŷݍᛶД㑱 +Ӥϊܱ޼àҥ۷ +ù㏿Ϧ趞뮒ᯕܸՅזŏɀۀꉯ׊ +NJ˺׵ӎ՝߬涗Ѯ˗ +ߊ۟ܧ팃ϻߨվܯؾᯄс巵Ҏގ˗ +մϿώͷߜシ۾֥Ɨ +оܾݽɡΞﮌ߀ +݈ʗ࿿ꡡ󭪪𺷷²৖߫׮ +駟¯ԩӗ抶梾ʭ⫷ܢ⫷ܺʭ⫷ܢݾʭ +ޫܢʭ⫯ܢ׋ʭ⫷׈ܢʭ⫷ܢʭ⫷ܢۧ +ۯ׷ʷߕ׻Œխݻ漇ժцǗؑ +ݚ͂͠·ƍ֯վƛͨƎ͹ρ +Љۙ鹎ɫ߹Đ߹喔Ꮇٹْɶ +͏߀ַյۊ̃ͅоԍ杻߰ۿ⿀Ž +ɉ̨ʾڹܛ˔̂猹ؒӋב܈ +ߒ⫷ܢʭ󅍂ɡϝۂߋϷ +ʶۑϰ񕵌⓷еШƍ棪 +՘ŗ֯贾ѧʰȎ˴遼ߗˡ +甐ߒǑ߹߹ۡ߹Ś⫷ +̧ϴﲑ +&] +[s5; Index constants representing individual Images in .iml file +are based on the name as defined in image designer, placed in +image list class scope and prefixed with I`_ (like I`_Circle +in the above example).&] +[s5; Image list classes also provide unified interface class to its +content: [* Iml]. In fact, method used in previous example are just +wrappers that call Iml methods:&] +[s7; &] +[s7; #include &] +[s7; &] +[s7; using namespace Upp;&] +[s7; &] +[s7; #define IMAGECLASS MyImages&] +[s7; #define IMAGEFILE &] +[s7; #include &] +[s7; &] +[s7; class MyApp : public TopWindow `{&] +[s7; -|[* Iml]`& iml;&] +[s7; &] +[s7; public:&] +[s7; -|virtual void Paint(Draw`& draw);&] +[s7; -|&] +[s7; -|MyApp(Iml`& `_iml) : iml(`_iml) `{`}&] +[s7; `};&] +[s7; &] +[s7; void MyApp`::Paint(Draw`& w)&] +[s7; `{&] +[s7; -|w.DrawRect(GetSize(), SColorPaper());&] +[s7; -|for(int i `= 0; i < iml.[* GetCount](); i`+`+) `{&] +[s7; -|-|w.DrawImage(50, 80 `+ 20 `* i, iml.[* Get](i));&] +[s7; -|-|w.DrawText(80, 80 `+ 20 `* i, iml.[* GetId](i));&] +[s7; -|`}&] +[s7; `}&] +[s7; &] +[s7; GUI`_APP`_MAIN&] +[s7; `{&] +[s7; -|MyApp(MyImages`::[* Iml]()).Sizeable().Run();&] +[s7; `}&] +[s7; &] +[s0; &] +[s0;= +@@image:1000&1194 +Ȁ從ǧϭ筀良ڠچŃԳ +ϻÔѰŶé +ũ勚қуʺ땳ةܹừƩЯʁ +Ä˷𩋏㈠̇ދߌ绯璾쓪 +՛ƊРҲܪ݋ٕȮ۟ф֏Ǚ˩… +䉭ғߪşÇ͹޿ԫ鲰ϥ䒈 +ɝùƳ鍴ݩ畍ڪ˵αـ҉ɅĨ +앎±Ҩ’ۺŶЇڬ׍ĪȘӨ˩ֶϊ֕ۙ +դ̍έͮ♽̖МĿڤ䑅Րԙş +鱸聘ا赏߬Ӻķ܀ٟԦލ׎ +ƞ£ĺփԵҝÓծ˝鿯ͥ̐ܺ +̡⎓ªգԬƯҟͮ;ݦע֏Λ곿 +߼ɗߓ;߶ո񵕺׸ڪѼҪꫫ +׮ǡɿهߴއ๷ +ƵܹߘהӨí躵ȫߥܤʜҕ +Ɲ޽𾺗ݕΩƢѲ֯쯝۲٫Å׳ȓ +생ϽѲƽظ٫Ք捊խى +ǯͭڭҨ㏸ͥϔײ +դёމ׮۫ÁσŽճҭͲݪ뭹 +ڄŷʂ߭ƹ쐭Ի꣼ɔҡ쏦瘝ѭ +۾ϾԯߤޥƅܤҪѮ֑ڥڰߵ +ԌѶɱʉ䕬ޑء־դިߥԲ +׵ӻʼĄӹޘ뿭⬘謓ٲٲƾѕ߹𪯎ՙ +졺Ҳȭ琷Ϛڜ⨯Փ +ݫƺƶưݙʮȫˇГ΅ +֟źէݒ땙ꪋԐ箝Ԏ͒Žأ +ʧᕽ«Ѳޅ…겖ݻ׹ٜ +쩞݁׫ѨҼĶѴ太ҏƻ՝ά +ؼĹ׼޵跹לʨ䕝譠ި +ȑ¨ؕٴُҵ仚ޖ湷ϧ +ֹҪꕅã藿ֻ۪놩ȟƛ㚑ҋ񕎞⬗Ͷ +֙ݾї묛ڐ޿ų򌵂ٚț껓ӄŧժ˳ +敡񷅒㫈Ϥѵö֪۶شՖݣ +ǂۜԯޘɵȫَ۷ղȒ޺ +ٰ۲ǖř򙮽ϲ͔珑ޕ՝ɽǗʊ؍ҵ +ѥú䃸ꧏ΍ůϿ۹ԫ䥟 +ǫݼٴԝ𜔕י̰Ģᅤ̈́˜Ȫ +ߙ܏٨ҏˮПЄ۞ڟꌕ +ݭ܍ߗ겑׿ௐьﲕ +ٺߊѯԯךƮʊ +׀׏̧׀׀格ƽ +ʅʫʫՈ̄ށށށށ +ށށ݉ԙǕѕ +ӈޟ +ܜϐוޔސޟށށށݙ𒀯 +׀ʬȺӽ͒ъ +ʢ毢دìꢼаߒՖֆ髍߷ѫ؍ +˜ܟꀯ˫ҭᭆ栵ω +̢鼂Ɂփ󨢓˒ױ݌׫ +ﴘdžՏїͨɭ֡ޘͥԒͱ董Ֆ +åϼ߳׳ǭר̂Ǻ巤ȫĢ㺓ү +ޢԔށ˂ցؕΌ򤪴奯ᕦל +瓗ՔʎΟ蘏ԪиүĚȒț +ʰǝڼ䰸ijލǒר׎ʟⲏƱ椄 +י蕤̮Պѝ՚Ԋ썪ށ׀ +׀글׀ի +ҾԂޟ緿Ϗ +׀׀Š̄ށ•ށƎԾ̄ޔ +ޠŘŁȊȊ糔Ӂ׀׀׀ȡʵ +ˢ޿Ǯۢ򎝇×Ϭۓ㟻ӎ﮶޴ގ +սșհŀȾ̓ǭߒ㛍ӟ +Ս +&] +[s0; &] +[s3; 3. Creating and altering images in the code using ImageBuffer&] +[s5; ImageBuffer represent a write access to the immutable Image +value.&] +[s7; &] +[s7; #include &] +[s7; &] +[s7; using namespace Upp;&] +[s7; &] +[s7; struct MyApp : public TopWindow `{&] +[s7; -|Image img;&] +[s7; &] +[s7; -|virtual void Paint(Draw`& w);&] +[s7; -|virtual void LeftDown(Point p, dword keyflags);&] +[s7; -|&] +[s7; -|typedef MyApp CLASSNAME;&] +[s7; -|MyApp();&] +[s7; `};&] +[s7; &] +[s7; MyApp`::MyApp()&] +[s7; `{&] +[s7; -|[* ImageBuffer ]ib(50, 50);&] +[s7; -|for(int y `= 0; y < 50; y`+`+) `{&] +[s7; -|-|[* RGBA ]`*l `= ib`[y`];&] +[s7; -|-|for(int x `= 0; x < 50; x`+`+) `{&] +[s7; -|-|-|if(y `=`= 0 `|`| y `=`= 49 `|`| x `=`= 0 `|`| x `=`= 49)&] +[s7; -|-|-|-|`*l`+`+ `= Black();&] +[s7; -|-|-|else `{&] +[s7; -|-|-|-|l`->a `= 2 `* (x `+ y);&] +[s7; -|-|-|-|l`->r `= 4 `* x;&] +[s7; -|-|-|-|l`->g `= 4 `* y;&] +[s7; -|-|-|-|l`->b `= 200;&] +[s7; -|-|-|-|l`+`+;&] +[s7; -|-|-|`}&] +[s7; -|-|`}&] +[s7; -|`}&] +[s7; -|[* Premultiply](ib);&] +[s7; -|img `= ib;&] +[s7; `}&] +[s7; &] +[s7; void MyApp`::Paint(Draw`& w)&] +[s7; `{&] +[s7; -|w.DrawRect(GetSize(), White);&] +[s7; -|w.DrawImage(10, 5, img);&] +[s7; -|w.DrawImage(40, 25, img);&] +[s7; `}&] +[s7; &] +[s7; void MyApp`::LeftDown(Point p, dword keyflags)&] +[s7; `{&] +[s7; -|[* ImageBuffer] ib(img);&] +[s7; -|for(int y `= 15; y < 35; y`+`+) `{&] +[s7; -|-|RGBA `*l `= ib`[y`];&] +[s7; -|-|for(int x `= 15; x < 35; x`+`+)&] +[s7; -|-|-|l`[x`] `= [* 100 `* Red()];&] +[s7; -|`}&] +[s7; -|[* img `= ib];&] +[s7; -|Refresh();&] +[s7; `}&] +[s7; &] +[s7; GUI`_APP`_MAIN&] +[s7; `{&] +[s7; -|MyApp().Sizeable().Run();&] +[s7; `}&] +[s7; &] +[s0;= +@@image:584&629 +ל܉եȲˆ˄􄂁̉ā̼ٻޜ +؍˭ݭ˪ӕԒʪې»텿иӪߺ +﷩Իط߃߹גʫɑǩݽ +䀍ͺϥԵ޻׮ߐ靰 +ָ뿃۞ӊν׭ޖޖ +ӯ҅ɔȹϾߍ͑׻羱̯߽ۆ +˻ޛϟȁӜ➬ɷ +ԁ֓ңȽԯʣѓ𕜒ڽߐ +֋캍ߍ렐ŗ̠۾˿ӕ򶺆蝑 +牰՞Ҏӭ˻Ԭ +ډ톮쵁ߕʙ⭜ꩻիȧ񖞄͜οէ +ߩ¯ƐνװʛޯЌȰ +͇ݱޞ򻽡ڳԘ򟿪 +ュ߹߭ۮް怰 +˹߳珵忞Ϛǀߞ˿捾ԗ +υ޺ۦ怫嶛礗ߊ +ғﹻ؝쏿˹׮ㅚޣ˒گݗ +텟׃축ݟȳ׃޺ۃ +е𳛀ïϗ퍎칩Ԟ +‡ֲ޹܆ӒۊݟܭŲ +欢㝧˼޻Ĕ˞ऽܝ +ŝޯ݃ڂޚŽԍҏٶ힞 +Ϡぇ٤ݢ싫ٱ۲ +ܹӔ“Ȍ蜟ٯōԷ뻗ﻞ +ÜȶҬ񮡟᧫ۇʿᄋ +ƫˑܦݤ書ؙڞºߞ㑃 +ǡ؊ͼά܄酿񀭽݇ԟ۫廮𽋐 +埾ȏﲲގܼ︂߯߬݇ +ڟйϯ֞͏ސЇϖߞ״ +쀢ۗߒطˏ֍ٓ +ؗեұʾˠнה󟏡࿠喙ϻ +ڣܬח⃝߹鳖񱸸ųڑ߮ +ۃۜߜŭ߫Ϫʿ +ܹ潤܃Ǔ˼ݳȻΊ€ۮ +쏯ƫѸ❸όۓޞ +ݫҫޕ؍ȗャۯߩ헧߾˭ +Լް۫޺ؑƆڞ꾹ۮƾ򚼏 +ꮹ뮺˼ۋ녹͙ +祹܉歘ꞚΜ߯νޣꎇߎڟ؞ +⮓̖軺ȷݚ摼ɮӷ՜ +蹞˫スŻෝĺ硷ɘ튯 +Ν쁫ϴ֚˽᛹Η󟯿̗ߍ +ӼӼַ۷ۣ鋝﫯ȯ՗ +⁞߯Ծǖᓔ瓶뙃虺 +٨ʬ╵ԍ̬Ł۹۲ϳҝѡ +펊鵨ϋȥ٦ҶЦӒ荻Ĩꬢݲ͊僕 +×肋Όԡӝ٣􎌻ד󝜩˔֢ +ˎёʡұܭ߯۶ˆσ̇ +ĜԦעĮ相ؚΘѦޢڊԕٱᆫ¼ +Ʋۊ񰭝²ۖӡ򗎈ϑѶ᥾⮦ +˄ꤪʩψ̘ŎÕʧڊՕӹ +ቌƢ‚꘵Œޒẚթə +˧϶ɶ垭ϯҤ󔤲ۡв湰̋񀵑ϓ񵐈ԑ۝ +Ȩ񊽊ޒԸ諞㨅Ӡ +Ý͇ě㵑ȋ׃֨ʈ̒⬡Ӱ߅ڃĕ١ǫ虞 +åߺ͓텮󝬁ɴ +Ϲꮹʰٹ갱בݕՈĔՁӉå敀ےߔ +ҋ臃߰ÉʄڹִֺͬڤĤ +ˋԅ񁙐ؙ“Տߵ恤؈籴у˵ +ۡȋסםʐ݂͵̵먣ךՐ兝ėၚ +虷فږ̳זݠ鞅Lj臁첍Ьۙ悍 +ʸ؀ˍա㕲ٮӁ޲ŧȑ懼珽Ϡɮ̂ +ओ˭塹즍ڙ䫓Ͻҳʡ폵׳ƨ挢 +ɩʰ̗ƴɼϰۢсΎṨ̺ɵ҉ +ֺś꤃֓Ω钒ΩӦ諐չӥDžNJ +Ѐےڲнᝬځɶә݈ʥ۩ī릣ĸʸ +Ԓ͚ű̙֥婷ƥřށ˕ +枡Დ٬맠ʦ䫑Џ׊ń̚ +ĤґŐŗтͯˀ䯠獨Ζ߃ΥԮ +̶֢ʤijܞƢؤܑգԐԣݵ欯՘͌ۓĸ̘騧埔֔ +Ҋم“䬀ʼψތ򋰚ԇܒԊƒ謑 +ԏߊעՈ֚ћ኱儡З㒺ʣՐƥ× +奇ˮ硺颓ؐ܂ۊئ͵ދĚȽîҸۋ +ۍň݌Ĉ؎ʉ§ʺŌ͕򓀗楇¼ +ΆΣˀ۴ڱܫš֤݌ÚģФ˃譅Րαöʪ +ɒÎ車֤ۊ瓚꓍༞֐ԃ +ǴӊϘ潃޼߶ȥ +뎗Ҡ̧ߜՎ܊ڡ̴Ơو굁ݟɟե +ʃщ境ר޵λ՟ú팼¸߳߭❜ +ϜѢᴕ”ڡ̶гӍɗɛ +򺭧ԸΑ卵ƹʸޤݯӔ̛纱 +֐ّ֠˴ĥϤ暉׼Ыŏů埳 +Ňռۧ޶־»❕ +ˏƷϺսɝɝխ݁ݾ왭늶 +օﳙֲچޞƶұ̾ý̫̾뽰ĵˏ +ӋɮȮڛՃِ݁嫸ݮ狞 +ķ͓̓﹟̻ں웉ۄ̛ہ۾ì޴ +εٺϦ͙ٔ᯹ތΐ茊ʳ픠͛Օް +ٙƸ̌ݴіଫĕųݱѭ򒔭͗ +󙭻əɑԵǼў⑬ޒӚ槕̏ +ņư̎ʫĘĭ߽Ҝ򐭷ٴĚθɎ +ɚѵū菋צ졊ض᭹Ƽӭާݬэƿ +̳͛墛ӉÁݓɆɝ͚ +͈ݸ草š싔ƧؽΗ̫刵֭݌ьڻȬݿ +֐܅珙žϯފǬޗݚΧ붤β䥋՜Ϫ +㢹ֱǫْ„˰䍈ޢݼ境ʩǪɨꕌэѡڵ̪Ϳẝ +؂ܷЏ밊̌ާݰͻٰ޷ȪِɌ͔ӵдӢ +̱ڶɜĬ۰ޅҰӔơদŸՔ淮݉ +،ހż飚ֲ漢Ƥ醮٪Ӣ٨٘˳ +ذ䰇┫ؽއб̨򜜜ՆŠɕ̵Ǵې˨ +ˌֺᡚܚöрՌɲѶˆɔ +Ӱ芾ݽ͑౱̌Կ؃Ľې +⭘̷Ɉˆ̲鐤џ銾֧鐚DŽ԰ĊѤ̄ +ٞ̈ӣ̒بⓆ؉툐ރռ +ʷȴ񚞫Ѫ掩їˣִśݪ˖وႱđτӐϲ +ё˜늣ݰ⧢΁밊ރݟǑ͋ +čͶͺɉڤ͈ї㤅ፊޘخ +𨶦Ί瀰ݿճ뚐ƫԁŅ׆Թ +ЧФ⼂ÄЈϲ֒ޕÁდึ耢 +Ɂᩝǿɵ۱ꪦ⢒ʼnٙԙ +ޛޟҡʙ͓Įۍީ︲Ȑǥ +Ú⭘ʪ禦ʺԐʔ֙ҔܚʉʌըҼ뒭뒜 +՞ء𝴚짚ۥȞܿàϭ +ݣЖɚȯ̋䰂ǝޥӕթŋ֞ˠ +ӸޕՀ钜̻ķѐٻ󂃲註 +߸ÖԊ̔衶āաࡩ㜾ʑɶ +Ɖ㨰񂮊䊓Ҋ═ȬΕԎޛ뒬武ˌň +ȶ݅Т޻͎܅ռƈݱՅ +ϫ禔ƹꬸ☸ݙʣ锨М̘˸ɜ +Ɛզ֛߰ج۲׍÷ɭ仚ٽم͌Ƈȗ +ʂҊㅐɈ􅟸ɵ񙥟򓜲ώΈۙʣ +ɡ–̔ǐΑͫՙ̠֓ۀ +ӑݽ힀dzᑓǾ˛חԭФϩܔ +ƒߙˆҐݐš̔ǻù񋄛ɸ畹֙ƍɼ +ذس乓ռᗴ٦축ʾ㟼් +؈ξ㺾ʎ䧂⌹©Å䐩򕁮ѐ¨РŁ᪸ȕ +ɏ𷈣㘾΢ِ賖줖͠ +ѻݿОӷɽ뗺ſ负Ɲ㧅 +ے䰠Ōϗ⇻ᐂǀƊ +ʽ낟߰ö̶曚ԅԼًﮄÁ +;ΈêᅉβòɎ򠅰߄↨т +ɩ˽˟䟵埧›ř۝ڣ̞ +ůǭൖކ惦уݾͧՌ䔐;ݹޠל +ʹᯮƹӷܗ݋Ǜ΢ +؋ξбѰɩ㊓ժݳݘ +叚󱃛ٳɝֲdžΪţݥ՘ΞΊ傲ب䴓Ұ +ߏ֭ΗИع˾æ釴ԡݥΪ͟ +ΎﷲƺӍӔѽ笁ժټ݃Ά +ʄ̑ʙ社Γ垸שʻُ谕ݎ蘙ʘ̐ +εǝݛݟŭ¦͂ݥق՟ +漲ڷΩʤҕϔˠί +„βҶ볖ӍἩːٟҞӁ +٢⎢ôαժǣ늳㍱ο᷑ټ +دü㔝Ⲧ֘ю܁㧈ƢҮϺժ铥Θ +ጶ˄Ũא͸ϵߪб㜶ŌƩٰٔ +ԎސѿɟԢݥ􊶤顙Ж鋓ྐ㡐 +񠚌ƻը벴ϧ㊲󒴦ĉٸޘ⡈򰒈Щƻռ +顣ʐ粤҄ŸǐġԄ۪԰ +ᆈ낆ѥϊѐ׉ݥ¨ȝ€íܖŰ +͠⣑݋뽽밭㬚˷׵ẝӬ +쇶η׵η޷ӟ۪Ӽٵϟ껚 +ž֖ǿޭﺙŠސǾނǶȽѹ +ۛя꙽ߥòƩ +ாǼ⛣ȏޏ쐰Րڶ + +@@image:584&629 +ǜ܇Ս¸ɠЂˆ̠⁊̉ހ +ţˍћ۪玼ȖپϾ۞䩌Ή͝ +㚭ϢǮƣЊϦǮ𻑹ȹݙʛݩ祬 +͏娪˟óѷɏɷԝ摶ʷ +􅏀ࡶů䖽ѳתӗ̃ +ѹ桂ɦᬹԳڣǭڗѼ҃Ǹן尣ܖՍ +ыԇܲ퉱ʷ݉Şғ܂َܯ遵ޕ +ɀʍҨԟ۪ӗ՟ǖ֠ٓӃàشɨ +ڊٱڡཏȔʲ糩埩鬓Ӣʞ㹪ĀЅ +ͣ˙ƪԥښҗܭ̆ƨdz +ۦբǞԑ냔֫߷嵻ׅɟ +׉ە¶½鍼ٹÇɬᕿ逬 +΅שߓNjǣ؞Ñמłޕ +יƦݵӍ؉މҩӻ +뺠ӓ߽۞鯚ǪÓ꩙哱€չ +͵ݥ©קⵗߞ׏޺ϭĽݼ +ȯ֬ +콼׺ߔ钯ն޳ُٰ 񛀭 +ҽމѧԞ뤟ށ냙֙ۡ +ߔߦ󹼝‡ӄ䟧̠ԉ̤ +ܾܺ˞ঝ兿Ҫǂ׆Ƞҹ㮰 +Ȋ㿀ЯޤՅϯٓꀆ疀ۃ +тնŠۑٌᇯ +֝ԽΌރǧ髴޲ͣʵޏ瓛́ +՚荬ϲǾלޠދ޵Ŝ +۲碧޷ʕͼԘ鷻¯ +ۯ߫ώί⿺Ӽ͢‹ᝂ˫ľӐ璉犲 +ެݑѻΌæ傗ƄᲯ݇ +𗾸ǧΓݺԏȳǞ믘 +˲޻ܐٝ阚݇ыއ +ž؃᱇ͱĞձǯލп·㷗䠩 +쁗җꈍ쨽ĭ͚ݏ؟̏Ǿܻڛῗ +ūܞ烙ތ譟ᒴŊ݅ݥүۃୗޜ̌Ӓ +ѷǜ뮑񁫥ﻸŖӃߜᚉ՘ +ᬼᇡ¡ԇžџ +ř¤ް«Ձ測햬ӵ +ӵןۻծ諾ҥãĻ̻ʼ +̼嬻綄ዥʀܻԽ +ٮ沆¬ك㇚ʸՍʨ꿖釙ƫߢҮ +襞оëӯܮ̦î¨֜ȍ雎큷߂Я +שͶ幣ҬϬֺ횢紷К蚵 +ϴƩҬæܻñ􏊅߉ +ڢޠצǥ̰ߑׁΙ󜾣יڳ둆ִ +Ɣωڤؔ®⡊ʸԶԶؗ㢶㬂۳܅ +ٮۑҜ֥řҜŃ̋۶ͱߋ +£ߨ䫳ƅ𑋔ߑׁسƙߎҵ٦ôִۘӒ欖֜⍩ +ɾ؛嬸ڕΜ¶ڶމݫ㈢㼺Ɓۨ +蝞Ӄ̠ǖݙ÷αƨą׋ɕώ +Ŷڌہ牱붫ОӀǹ˒ٲ樽՚ +ʖڔƗꉶεГŔɎնղދǧʶҾث朧ܹ +ݞΑҝ䈮ёɑ֔ұкӜ盕ޮĄ +ؑǎն죡߰ή۲㼽Α㬾ŴБׅɑùⲰ񾬏ޛ +šȓ±šҘ􀸷ηǙƸ۟ěƛʜα㬵 +Ɛ㴰ŋܤ׺Ǣά֟Ŝ޴֞Ҹےɽǩ˷Ƙ +ۛĨÙǟ֎Ǎ̸Í䘉Ȣ肪͛㞼ȹ츇 +ڗюڞ؄˒˂𷥈Üǔꊁ̑ۈ +ʶ©łؑ…̛ݹ߇䐡̢ҕºۊ͢Ԛ +Ԭ̔˼ƶŨ艷፭ޛ¬򦯼˶ǙƨꌤѢ +ߨ󨷏򈫇ᬼɠք玣㍺鲡 +ӝœ›ث˶ܲƙıиȏ󰻇Ȗ¡蠓 +ćϊ뜩ƘƁĐѩܬȾ +ǩ˕񇢈Ŕ򰿏򐧇ปڿߗתЙ鴧ȞȚ +ĘÌԖŴѼ⍃޺̊ԅ؅ޕ漙З񊟧题ƖѼĘ +ͅ깿ϙߞםߝげƘ숚򑼱ԇ +ڰՓ吃ˌٲɨ֘ʕㅘ쾀ۣ䌂ؗ +ї୐ωϽ诓㤸Α㸷Ł䑦Ȑֈùр +ÈɬݳޱҼޚㄸᎋ㘷ńԑߔĘ +።Ȩޒ㘰ۄĈϔދȗ +ӈצ媤ωqŁᆊׄ‮ι˟⚵ưߟ +٫Ւ׹ϛϔ쉼ќɹ蠻Džَ +±٢ˍѤ凲͒韴ߝ׭݈ž +п퇟ٜӜӲ狾办خư܈è +Ϻֳ㫿߷ĻĶߙϯؘ͘קܫÖ +眾˽Мݨݵףݡﻜ +񅋃ޏ߀ۘ̍ŝ։熠̀ݿퟖʡй +ϻއ޴ޣߘ¨טʍIJ趟Ùϟ +ʫخŻ۵֥տ֮׹ŧާͅט +ι臭̍ۇλ漪߭ڣ뎮׾ +줻ަޤߠλ雋ޡ΍йۇؓƁ󪶿߮ +ՊʹӺȷޤޠ땃ˏȬެ +σԗد߭͒ӭ֊鶝˶־˷Ýߢ֓ق +͚砻䶇݅ԧꄶҝޮřƲ +죭閦۲˾ó𹇛륳Զˉԇвʋ +߅קÍŌɛіĶߦć٫ﯗ +݁۱Իʩݲе򺸺骙ÛƝޥ +եӮ܀ռ̯ٮ䒺̻Īϵִǒᇒז +ȵƢڷ줌ڞ֍ڀեَ􂫕ӭز +Ͷ秽덍ܔǶ͕܂ޥ̛ƫӯހ +즕鴝ʵɛ疴䦼ݓэõ +ȝ樓۰׬ެ۹ͷ雝ѩɌ񳜷ñ +;ٛ–ꊸöҸزݭιͩ܍磌Ɇٴ +苛ś΋髓Щɳቨʌȭ̈njԔ͠Ѡ +蛖ۆܺʳ܍̥﫛ꆪݒް߉ͅҖ +餓ㆬㆤ怍ʠ荋·ͮԶȶ嘈Ň珙 +銭Ոⵔ쾗ޣśϙّ͙詄밉┺â +ķٓ쒭ٺׄÅ݆颫ꪱڊ +ވυӆ𒺚ڲڜΤŢڴڸºƏ +֗վӻԤν튺몰μǥ޽ɝ򉭛 +ʹƚ҄Ś𐳈ڄ̖껉样 +ɝԙᴺΣᵯ쳄ڠդՒ²ϴ񉦶ވ +ěȃĄ𑏷⥠ԄٛٞÁ״ͭ曵ňͤΐަ +ƫ䒮؃͡ן襂гˣԭăުƶơңǛ쟬ѥ +Ԥד܀Ѓ҄ѧӋƾ롷ȭتö +ُΉ׬卻͡䵆ԧܬͲ֠٧ѵĽŨՂ +ᰒDŽ’ѐÛξݓو +ݮƽǭ䶇Ơנڙ钱Ɖ둪ᘋɉکބ⵼ȴֳ +ԥ̸ׄСڲˋʈғĵă؉Ė쓙薠ö +❱ƭɞˣ풰Ƒɮ򼴚Ċ׋᪶ +Ň൅אԏˍԻ͘،Сۦ۶nj䋎 +֌»싎؃喽넼ډ閱㏉հҩǪ؅ȸ +ɆLj؀Ќڌס׻׻ډ؉޳Ɍ +ͷ୺軤μíɛݖ햽倰ᭈȶᭈņ䷔Ѣ +ֽ詆멱ɡ紸콝㎽öؐɍ +❴íو͞ޣ䷕Ĵͼڍܱݝŕ䰒˄ +Ѕ贈んة顎멾ɮѫ߀۰ڐۭۤǂ +ی塻ˮ䶬ޓ賊ڞƹʑŽܵܫ +ιۆӿ㗮㉷͞Ԅ锈ĭљѝه빲 +ەچ直Ԫ¢ަ׬Æ󘎣ƻռڥ؜˦ +͜␂¿ޕ篎歊·ڹĢƖǙ +ѥݘꓥѻἶ͟ﲅռݜߗߩ滅ܭ +ؿᰳӕ藺Ǐ׭۸뵳Ƭ +ڜԱÃ한↻ʄ£қڇݩ +ΌܸЗɺχ맃ʣμ߂ųꊝΡ +ƻΡǛħغ􉝃򽃜㇜ +׷ݢɡƻռ왕늰߾ܷ݃Ҟ +Åɸ등ƕ쮡׆؞ֱǙ +͵븶ѮệޡɍΕ㭾 +컋Աݣψ琨č񒾁ɇٖмų͏Ȩ̃ +ѽɔȱ‘ӕπ¦ˀ۵ٻ螏ӭ颇 +½ƻռ™΄昵Œ̋؃πݾǹ俗ݮا +ǝӕχ񆌵嬈귄ĀŽ֞ǩؽ̚Ƅ +ѥȦؐʅʈۉδ +ԣɶ̖ڥ۲߽׼ڎ˛ +ۉޜȕӸ埓݀ϽϺУܐ +ޞǼԟ݇꫅̽Ӏꪏ +گݩυ֞܃瞲Ƿ韧Ϫަܞ +&] +[s0; &] +[s0; To create a new image, create ImageBuffer of required size and +simply set RGBA pixels of the image. ImageBuffer provides operator`[`] +returning the pointer to scanlines. When created, assign ImageBuffer +instance to Image. Note that this operation clears the ImageBuffer +(for performance reasons).&] +[s0; &] +[s0; Ultimate`+`+ expects pixel data to be in premultiplied alpha +format `- Premultiply can do that for the whole ImageBuffer (or +Image) in straight format.&] +[s0; &] +[s0; To alter existing Image, assign it to ImageBuffer, alter pixels +and assign back to the Image. Assigning Image to ImageBuffer +clears the Image (again, for performance reasons). In this case, +operator`* is used to combine alpha value 100 with the Red color, +resulting in correctly premultiplied RGBA pixel.&] +[s0; &] +[s3; 4. Loading Images from file&] +[s5; All of internal processing of raster image data in U`+`+ is +performed using the straightforward RGBA 4x8`-bit format. In +order to process other image format there are [* Raster] and [* RasterEncoder] +based classes. Raster represents `"input`" Image, RasterEncoder +`"output`". Images are processed in scan`-lines.&] +[s5; Individual raster formats like BMP or GIF are processed by classes +derived from [* StreamRaster]. StreamRaster provides the static +interface to register various readers; reads are able to detect +whether a given stream is in appropriate format. StreamRaster +then contains static methods like `"LoadFileAny`" which detects +the format of an image file and loads it using the appropriate +StreamRaster class.&] +[s7; &] +[s7;%- #include &] +[s7; &] +[s7; using namespace Upp;&] +[s7; &] +[s7;%- struct MyApp : public TopWindow `{&] +[s7;%- -|Image img;&] +[s7;%- -|FileSel fs;&] +[s7; &] +[s7;%- -|void Open();&] +[s7; &] +[s7;%- -|virtual void Paint(Draw`& w);&] +[s7;%- -|virtual void LeftDown(Point, dword) `{ Open(); `}&] +[s7;%- -|&] +[s7;%- -|typedef MyApp CLASSNAME;&] +[s7;%- -|MyApp();&] +[s7;%- `};&] +[s7; &] +[s7;%- MyApp`::MyApp()&] +[s7;%- `{&] +[s7;%- -|fs.Type(`"Image file`", `"`*.bmp;`*.png;`*.tif;`*.tiff;`*.jpg;`*.jpeg;`*.gif`" +);&] +[s7;%- -|Sizeable();&] +[s7;%- `}&] +[s7; &] +[s7;%- void MyApp`::Paint(Draw`& w)&] +[s7;%- `{&] +[s7;%- -|w.DrawRect(GetSize(), White);&] +[s7;%- -|if(img)&] +[s7;%- -|-|w.DrawImage(0, 0, img);&] +[s7;%- -|else&] +[s7;%- -|-|w.DrawText(0, 0, `"No image loaded!`", Arial(30).Italic());&] +[s7;%- `}&] +[s7; &] +[s7;%- void MyApp`::Open()&] +[s7;%- `{&] +[s7;%- -|if(fs.ExecuteOpen(`"Choose the image file to open`")) `{&] +[s7;%- -|-|img `= [* StreamRaster`::LoadFileAny](`~fs);&] +[s7;%- -|-|Refresh();&] +[s7;%- -|`}&] +[s7;%- `}&] +[s7; &] +[s7;%- GUI`_APP`_MAIN&] +[s7;%- `{&] +[s7;%- -|MyApp app;&] +[s7;%- -|app.Open();&] +[s7;%- -|app.Run();&] +[s7;%- `}&] +[s0; &] +[s0; Important thing to note is that while packages dealing with +specific formats self`-register for use with LoadFileAny, you +need to add specific packages dealing with format to TheIDE project +(plugin/bmp, plugin/png, plugin/jpg, plugin/tif, plugin/gif).&] +[s0; &] +[s3; 5. Processing raster images by scanlines&] +[s5; Sometimes it is important to process images without loading +all the RGBA data into the memory. In such case Raster and [* RasterEncoder] +provide interface to process them by scanlines. This example +converts an image to grayscale (by using just G channel) and +saves it as low`-quality JPG image:&] +[s7; &] +[s7;%- #include &] +[s7;%- #include &] +[s7; &] +[s7; using namespace Upp;&] +[s7; &] +[s7;%- GUI`_APP`_MAIN&] +[s7;%- `{&] +[s7;%- -|FileSel fs;&] +[s7;%- -|fs.Type(`"Image file`", `"`*.bmp;`*.png;`*.tif;`*.tiff;`*.jpg;`*.jpeg;`*.gif`" +);&] +[s7;%- -|if(!fs.ExecuteOpen(`"Choose the image file to convert`"))&] +[s7;%- -|-|return;&] +[s7;%- -|String fn `= `~fs;&] +[s7;%- -|[* JPGEncoder] jpg(20);&] +[s7;%- -|FileIn in(fn);&] +[s7;%- -|[* One raster `= StreamRaster`::OpenAny(in)];&] +[s7;%- -|if(!raster) `{&] +[s7;%- -|-|Exclamation(`"Invalid input`");&] +[s7;%- -|-|return;&] +[s7;%- -|`}&] +[s7;%- -|FileOut out(fn `+ `".out.jpg`");&] +[s7;%- -|jpg.[* SetStream](out);&] +[s7;%- -|jpg.[* Create(raster`->GetSize())];&] +[s7;%- -|for(int i `= 0; i < raster`->[* GetHeight](); i`+`+) `{&] +[s7;%- -|-|[* RasterLine] l `= raster`->[* GetLine](i);&] +[s7;%- -|-|Buffer out(raster`->[* GetWidth]());&] +[s7;%- -|-|for(int j `= 0; j < raster`->[* GetWidth](); j`+`+) `{&] +[s7;%- -|-|-|out`[j`].g `= out`[j`].b `= out`[j`].r `= l`[j`].g;&] +[s7;%- -|-|-|out`[j`].a `= 255;&] +[s7;%- -|-|`}&] +[s7;%- -|-|jpg.[* WriteLine](out);&] +[s7;%- -|`}&] +[s7;%- `}&] +[s7; &] +[s0; [* StreamRaster`::OpenAny] returns a StreamRaster derived class +capable of reading the input stream (or empty One if the format +is not recognized).&] +[s0; &] +[s0; [* RasterLine] provides the information of single line of Raster. +It also hides the differences between referencing the data in +the memory (as ImageRaster provides the Raster interface for +regular Image) and using buffer to load the scan`-line from the +input stream (file). &] +[s0;* &] +[s0; [* GetLine] returns required line from the Raster. Note that not +while GetLine provides `"random`" access to the Raster, not every +Raster provides fast seeks back. E.g. It is therefore advisable +to avoid seeking back if possible. E.g. plugin/jpg restarts the +reading of file when seek back is requested, that can be painfully +slow.&] +[s0; &] +[s0; [* WriteLine] writes a single raster line to the output RasterEncoder +`- in this case, [* JPGEncoder].&] +[s0; &] +[s3; 6. Image cache&] +[s5; Image cache can significantly speed up GUI when Images are generated +based on the set of parameters and the same set o parameters +repeats often.&] +[s7; &] +[s7; #include &] +[s7; &] +[s7; using namespace Upp;&] +[s7; &] +[s7; Image CreateBall(int r, Color color)&] +[s7; `{&] +[s7; -|int rr `= 2 `* r;&] +[s7; -|int r2 `= r `* r;&] +[s7; -|ImageBuffer b(rr, rr);&] +[s7; -|for(int y `= 0; y < rr; y`+`+)&] +[s7; -|-|for(int x `= 0; x < rr; x`+`+) `{&] +[s7; -|-|-|RGBA`& a `= b`[y`]`[x`];&] +[s7; -|-|-|a.r `= color.GetR();&] +[s7; -|-|-|a.g `= color.GetG();&] +[s7; -|-|-|a.b `= color.GetB();&] +[s7; -|-|-|int q `= ((x `- r) `* (x `- r) `+ (y `- r) `* (y `- r)) `* +256 / r2;&] +[s7; -|-|-|a.a `= q <`= 255 ? q : 0;&] +[s7; -|-|`}&] +[s7; -|Premultiply(b);&] +[s7; -|return b;&] +[s7; `}&] +[s7; &] +[s7; struct BallMaker : [* ImageMaker] `{&] +[s7; -|Color color;&] +[s7; -|int r;&] +[s7; -|&] +[s7; -|[* virtual String Key() const;]&] +[s7; [* -|virtual Image Make() const;]&] +[s7; `};&] +[s7; &] +[s7; String BallMaker`::Key() const&] +[s7; `{&] +[s7; -|char h`[sizeof(int) `+ 3`];&] +[s7; -|`*(int `*)h `= r;&] +[s7; -|h`[sizeof(int)`] `= color.GetR();&] +[s7; -|h`[sizeof(int) `+ 1`] `= color.GetG();&] +[s7; -|h`[sizeof(int) `+ 2`] `= color.GetB();&] +[s7; -|return String(h, sizeof(int) `+ 3);&] +[s7; `}&] +[s7; &] +[s7; Image BallMaker`::Make() const&] +[s7; `{&] +[s7; -|return CreateBall(r, color);&] +[s7; `}&] +[s7; &] +[s7; Image CreateBallCached(int r, Color color)&] +[s7; `{&] +[s7; -|BallMaker m;&] +[s7; -|m.r `= r;&] +[s7; -|m.color `= color;&] +[s7; -|return [* MakeImage](m);&] +[s7; `}&] +[s7; &] +[s7; struct MyApp : public TopWindow `{&] +[s7; -|bool cached;&] +[s7; &] +[s7; -|virtual void Paint(Draw`& w) `{&] +[s7; -|-|w.DrawRect(GetSize(), White);&] +[s7; -|-|for(int y `= 0; y < 300; y `+`= 30)&] +[s7; -|-|-|for(int i `= 10; i < 500; i `+`= i / 3) `{&] +[s7; -|-|-|-|Color c `= Color((200 `* i) `& 255, (150 `* i) `& 255, (300 +`* i) `& 255);&] +[s7; -|-|-|-|w.DrawImage(i, y `+ i / 5,&] +[s7; -|-|-|-| (cached ? CreateBallCached : CreateBall)(i / +2, c));&] +[s7; -|-|-|`}&] +[s7; -|`}&] +[s7; &] +[s7; -|virtual void LeftDown(Point, dword) `{&] +[s7; -|-|cached `= true;&] +[s7; -|-|Title(`"Now cached `- try to resize the window to see the +speed`");&] +[s7; -|`}&] +[s7; &] +[s7; -|MyApp() `{&] +[s7; -|-|cached `= false;&] +[s7; -|-|Title(`"Not cached `- try to resize the window to see the +speed, `"&] +[s7; -|-| `"click to activate the cache`");&] +[s7; -|-|Sizeable().Zoomable();&] +[s7; -|`}&] +[s7; `};&] +[s7; &] +[s7; GUI`_APP`_MAIN&] +[s7; `{&] +[s7; -|MyApp().Run();&] +[s7; `}&] +[s0; &] +[s0; In this example, CreateBall routine creates the Image and takes +the time to do so. Anyway, in the Paint, the same resulting Image +is needed many times.&] +[s0; &] +[s0; Therefore this situation is a good candidate for Image caching. +To cache the CreateBall results, you need to create a class derived +from [* ImageMaker]. [* Key] virtual method must generate unique +String based on required set of parameters, which should be contained +as class members. [* Make] method then creates actual Image based +on these parameters.&] +[s0; &] +[s0; [* MakeImage] function then scans the image cache for the image +based on Key result (it uses RTTI to tell apart various ImageMakers). +If the required image is not in the cache yet, it is created +using Make and cached.&] +[s0; &] +[s0; The maximum cache size adjusts dynamically with platform specific +maximum (4MB for Win32).&] +[s0; ] \ No newline at end of file diff --git a/uppdev/I18nFormat/I18nFormat.cpp b/uppdev/I18nFormat/I18nFormat.cpp index f04aa248e..9c0d8da5a 100644 --- a/uppdev/I18nFormat/I18nFormat.cpp +++ b/uppdev/I18nFormat/I18nFormat.cpp @@ -5,5 +5,8 @@ using namespace Upp; CONSOLE_APP_MAIN { SetLanguage(LNG_CZECH); + + + DUMP(Format("%2!nl", 3333.1415)); } diff --git a/uppdev/LanPath/LanPath.cpp b/uppdev/LanPath/LanPath.cpp new file mode 100644 index 000000000..fe2dbd7ee --- /dev/null +++ b/uppdev/LanPath/LanPath.cpp @@ -0,0 +1,10 @@ +#include + +using namespace Upp; + +CONSOLE_APP_MAIN +{ + DDUMP(GetSystemDirectory()); + DDUMP(GetFileLength(AppendFileName(GetSystemDirectory(), "sqlncli10.dll"))); + DDUMP(GetFileLength("\\\\office\\holly$\\sqlncli.msi")); +} diff --git a/uppdev/LanPath/LanPath.upp b/uppdev/LanPath/LanPath.upp new file mode 100644 index 000000000..2d75c62ff --- /dev/null +++ b/uppdev/LanPath/LanPath.upp @@ -0,0 +1,9 @@ +uses + Core; + +file + LanPath.cpp; + +mainconfig + "" = ""; + diff --git a/uppdev/NewDraw/Draw.h b/uppdev/NewDraw/Draw.h new file mode 100644 index 000000000..ede5f31b2 --- /dev/null +++ b/uppdev/NewDraw/Draw.h @@ -0,0 +1,191 @@ +class Draw { +public: + enum { + DOTS = 0x001, + SYSTEM = 0x002, + PRINTER = 0x004, + BACK = 0x008, + DRAWING = 0x010, + PALETTE = 0x020, + MONO = 0x040, + }; + + virtual dword GetInfo() = 0; + virtual Size GetPagePixels() const = 0; + + virtual void StartPage(); + virtual void EndPage(); + + virtual void BeginOp() = 0; + virtual void EndOp() = 0; + virtual void OffsetOp(Point p) = 0; + virtual bool ClipOp(const Rect& r) = 0; + virtual bool ClipoffOp(const Rect& r) = 0; + virtual bool ExcludeClipOp(const Rect& r) = 0; + virtual bool IntersectClipOp(const Rect& r) = 0; + virtual Rect GetClipOp() const = 0; + virtual bool IsPaintingOp(const Rect& r) const = 0; + + virtual void DrawRectOp(int x, int y, int cx, int cy, Color color) = 0; + virtual void DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color) = 0; + virtual void DrawDataOp(int x, int y, int cx, int cy, const String& data, const char *id) = 0; + virtual void DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color) = 0; + + virtual void DrawPolyPolylineOp(const Point *vertices, int vertex_count, + const int *counts, int count_count, + int width, Color color, Color doxor) = 0; + virtual void DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int scc, + const int *disjunct_polygon_counts, int dpcc, + Color color, int width, Color outline, + uint64 pattern, Color doxor) = 0; + virtual void DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color) = 0; + + virtual void DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor) = 0; + virtual void DrawTextOp(int x, int y, int angle, const wchar *text, Font font, + Color ink, int n, const int *dx) = 0; + virtual void DrawDrawingOp(const Rect& target, const Drawing& w) = 0; + virtual void DrawPaintingOp(const Rect& target, const Painting& w) = 0; + + virtual void GetNativeDpi() const; + virtual void BeginNative(); + virtual void EndNative(); + + virtual int GetCloffLevel() const = 0; + +// -------------- + Size GetPixelsPerInch() const { return native ? nativeDpi : Dots() ? Size(600, 600) : Size(96, 96); } + Size GetPageMMs() const { compute... } + + bool Dots() const { return GetInfo() & DOTS; } + bool Pixels() const { return !Dots(); } + bool IsSystem() const { return GetInfo() & SYSTEM; } + bool IsPrinter() const { return GetInfo() & PRINTER; } + bool IsDrawing() const { return GetInfo() & DRAWING; } + bool IsNative() const { return GetInfo() & NATIVE; } + bool IsBack() const { return GetInfo() & BACK; } + + bool IsPaletteMode() const { return GetInfo() & PALETTE; } + bool IsMono() const { return GetInfo() & MONO; } + + int GetNativeX(int x) const; + int GetNativeY(int x) const; + void Native(int& x, int& y) const; + void Native(Point& p) const; + void Native(Size& sz) const; + void Native(Rect& r) const; + + void Begin() { BeginOp(); } + void End() { EndOp(); } + void Offset(Point p) { OffsetOp(p); } + void Offset(int x, int y); + bool Clip(const Rect& r) { return ClipOp(r); } + bool Clip(int x, int y, int cx, int cy); + bool Clipoff(const Rect& r) { return ClipoffOp(r); } + bool Clipoff(int x, int y, int cx, int cy); + bool ExcludeClip(const Rect& r) { return ExcludeClipOp(r); } + bool ExcludeClip(int x, int y, int cx, int cy); + bool IntersectClip(const Rect& r) { return IntersectClipOp(r); } + bool IntersectClip(int x, int y, int cx, int cy); + Rect GetClip() const { return GetClipOp(); } + bool IsPainting(const Rect& r) const { return IsPaintingOp(r); } + bool IsPainting(int x, int y, int cx, int cy) const; + + Point GetOffset() const { return actual_offset; } + + void DrawRect(int x, int y, int cx, int cy, Color color); + void DrawRect(const Rect& rect, Color color); + + void DrawImage(int x, int y, int cx, int cy, const Image& img, const Rect& src); + void DrawImage(int x, int y, int cx, int cy, const Image& img); + void DrawImage(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color); + void DrawImage(int x, int y, int cx, int cy, const Image& img, Color color); + + void DrawImage(const Rect& r, const Image& img, const Rect& src); + void DrawImage(const Rect& r, const Image& img); + void DrawImage(const Rect& r, const Image& img, const Rect& src, Color color); + void DrawImage(const Rect& r, const Image& img, Color color); + + void DrawImage(int x, int y, const Image& img, const Rect& src); + void DrawImage(int x, int y, const Image& img); + void DrawImage(int x, int y, const Image& img, const Rect& src, Color color); + void DrawImage(int x, int y, const Image& img, Color color); + + void DrawData(int x, int y, int cx, int cy, const String& data, const char *type); + void DrawData(const Rect& r, const String& data, const char *type); + + void DrawLine(int x1, int y1, int x2, int y2, int width = 0, Color color = DefaultInk); + void DrawLine(Point p1, Point p2, int width = 0, Color color = DefaultInk); + + void DrawEllipse(const Rect& r, Color color = DefaultInk, + int pen = Null, Color pencolor = DefaultInk); + void DrawEllipse(int x, int y, int cx, int cy, Color color = DefaultInk, + int pen = Null, Color pencolor = DefaultInk); + + void DrawArc(const Rect& rc, Point start, Point end, int width = 0, Color color = DefaultInk); + + void DrawPolyPolyline(const Point *vertices, int vertex_count, + const int *counts, int count_count, + int width = 0, Color color = DefaultInk, Color doxor = Null); + void DrawPolyPolyline(const Vector& vertices, const Vector& counts, + int width = 0, Color color = DefaultInk, Color doxor = Null); + void DrawPolyline(const Point *vertices, int count, + int width = 0, Color color = DefaultInk, Color doxor = Null); + void DrawPolyline(const Vector& vertices, + int width = 0, Color color = DefaultInk, Color doxor = Null); + + void DrawPolyPolyPolygon(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int subpolygon_count_count, + const int *disjunct_polygon_counts, int disjunct_polygon_count_count, + Color color = DefaultInk, int width = 0, Color outline = Null, + uint64 pattern = 0, Color doxor = Null); + void DrawPolyPolyPolygon(const Vector& vertices, + const Vector& subpolygon_counts, + const Vector& disjunct_polygon_counts, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolyPolygon(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int subpolygon_count_count, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolyPolygon(const Vector& vertices, const Vector& subpolygon_counts, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolygons(const Point *vertices, int vertex_count, + const int *polygon_counts, int polygon_count_count, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolygons(const Vector& vertices, const Vector& polygon_counts, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolygon(const Point *vertices, int vertex_count, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + void DrawPolygon(const Vector& vertices, + Color color = DefaultInk, int width = 0, Color outline = Null, uint64 pattern = 0, Color doxor = Null); + + void DrawDrawing(const Rect& r, const Drawing& iw) { DrawDrawingOp(r, iw); } + void DrawDrawing(int x, int y, int cx, int cy, const Drawing& iw); + + void DrawPainting(const Rect& r, const Painting& iw) { DrawPaintingOp(r, iw); } + void DrawPainting(int x, int y, int cx, int cy, const Painting& iw); + + void DrawText(int x, int y, int angle, const wchar *text, Font font = StdFont(), + Color ink = DefaultInk, int n = -1, const int *dx = NULL); + void DrawText(int x, int y, const wchar *text, Font font = StdFont(), + Color ink = DefaultInk, int n = -1, const int *dx = NULL); + + void DrawText(int x, int y, const WString& text, Font font = StdFont(), + Color ink = DefaultInk, const int *dx = NULL); + void DrawText(int x, int y, int angle, const WString& text, Font font = StdFont(), + Color ink = DefaultInk, const int *dx = NULL); + + void DrawText(int x, int y, int angle, const char *text, byte charset, + Font font = StdFont(), Color ink = DefaultInk, int n = -1, const int *dx = NULL); + void DrawText(int x, int y, const char *text, byte charset, Font font = StdFont(), + Color ink = DefaultInk, int n = -1, const int *dx = NULL); + + void DrawText(int x, int y, int angle, const char *text, + Font font = StdFont(), Color ink = DefaultInk, int n = -1, const int *dx = NULL); + void DrawText(int x, int y, const char *text, Font font = StdFont(), + Color ink = DefaultInk, int n = -1, const int *dx = NULL); + + void DrawText(int x, int y, const String& text, Font font = StdFont(), + Color ink = DefaultInk, const int *dx = NULL); + void DrawText(int x, int y, int angle, const String& text, Font font = StdFont(), + Color ink = DefaultInk, const int *dx = NULL); +}; diff --git a/uppdev/NewDraw/NewDraw.upp b/uppdev/NewDraw/NewDraw.upp new file mode 100644 index 000000000..d38d437c0 --- /dev/null +++ b/uppdev/NewDraw/NewDraw.upp @@ -0,0 +1,10 @@ +uses + CtrlLib; + +file + Draw.h, + main.cpp; + +mainconfig + "" = "GUI"; + diff --git a/uppdev/NewDraw/init b/uppdev/NewDraw/init new file mode 100644 index 000000000..3ab315fa8 --- /dev/null +++ b/uppdev/NewDraw/init @@ -0,0 +1,4 @@ +#ifndef _NewDraw_icpp_init_stub +#define _NewDraw_icpp_init_stub +#include "CtrlLib/init" +#endif diff --git a/uppdev/NewDraw/main.cpp b/uppdev/NewDraw/main.cpp new file mode 100644 index 000000000..ded874dea --- /dev/null +++ b/uppdev/NewDraw/main.cpp @@ -0,0 +1,6 @@ +#include + +GUI_APP_MAIN +{ +} + diff --git a/uppdev/aaa/a.h b/uppdev/aaa/a.h index e69de29bb..5d9bcb28f 100644 --- a/uppdev/aaa/a.h +++ b/uppdev/aaa/a.h @@ -0,0 +1,2 @@ +#define LAYOUTFILE +#include diff --git a/uppdev/aaa/aaa.upp b/uppdev/aaa/aaa.upp index 838c0da4e..e5f128f9f 100644 --- a/uppdev/aaa/aaa.upp +++ b/uppdev/aaa/aaa.upp @@ -1,5 +1,6 @@ uses - CtrlLib; + CtrlLib, + Esc; file a.h, diff --git a/uppdev/aaa/init b/uppdev/aaa/init index 155924816..d6064394d 100644 --- a/uppdev/aaa/init +++ b/uppdev/aaa/init @@ -1,4 +1,5 @@ #ifndef _aaa_icpp_init_stub #define _aaa_icpp_init_stub #include "CtrlLib/init" +#include "Esc/init" #endif diff --git a/uppdev/aaa/main3.cpp b/uppdev/aaa/main3.cpp index 167b14608..ae264a6bc 100644 --- a/uppdev/aaa/main3.cpp +++ b/uppdev/aaa/main3.cpp @@ -51,5 +51,6 @@ GUI_APP_MAIN s.Cat(s.GetIter()) s.Cat() s.EndsWith(s.GetHashValue()) + Escape(a, <, >, )() }