minor repository reorganization: obsolete directories moved to archive

git-svn-id: svn://ultimatepp.org/upp/trunk@1997 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2010-02-01 08:24:43 +00:00
parent bc24b89946
commit 4bee3373e7
171 changed files with 73 additions and 76 deletions

View file

@ -0,0 +1,567 @@
#include "Draw.h"
NAMESPACE_UPP
#define LTIMING(x) // RTIMING(x)
#if defined(_DEBUG) && 0
#include <plugin/png/png.h>
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<sChLookWith>(v)) {
const sChLookWith& x = ValueTo<sChLookWith>(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<sChBorder>(v)) {
sChBorder b = ValueTo<sChBorder>(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<Color>(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<Image>(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<int64, bool> 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<int64, int> 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<ChPainterFn>& sChps()
{
static Vector<ChPainterFn> 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<sStyleCh> {
byte *status;
void (*init)();
};
Vector<sStyleCh>& sChStyle()
{
static Vector<sStyleCh> 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

117
archive/olddraw/Draw/Cham.h Normal file
View file

@ -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 <class T>
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<ChColor> { Color value; };
#define CH_COLOR(name, init) CH_VAR(ChColor, Color, name, init)
struct ChInt : ChStyle<ChInt> { int value; };
#define CH_INT(name, init) CH_VAR(ChInt, int, name, init)
struct ChValue : ChStyle<ChValue> { Value value; };
#define CH_VALUE(name, init) CH_VAR(ChValue, Value, name, init)
struct ChImage : ChStyle<ChImage> { 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());

View file

@ -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
};
Draw& ScreenInfo();
void FontInfo::ComposeMetrics(Font fnt, CharMetrics *m, int page) const
{
if(fnt.GetFaceInfo() & Font::COMPOSED) {
FontInfo fi = ScreenInfo().GetFontInfoW(fnt);
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 = GetFontInfoW(font);
Clip(x, y, 9999, fi.GetHeight());
Buffer<wchar> 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 = GetFontInfoW(mfnt);
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

View file

@ -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.

View file

@ -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<HPEN> 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

View file

@ -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();

View file

@ -0,0 +1,321 @@
#include "Draw.h"
NAMESPACE_UPP
#define IMAGECLASS DrawImg
#define IMAGEFILE <Draw/DrawImg.iml>
#include <Draw/iml.h>
#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<AttrText>(q)) {
const AttrText& t = ValueTo<AttrText>(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<AttrText>(q)) {
const AttrText& t = ValueTo<AttrText>(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<AttrText>(q)) {
const AttrText& t = ValueTo<AttrText>(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<ColorDisplayNull>(); }
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<SizeTextDisplayCls>(); }
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<CenteredImageDisplayCls>(); }
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<CenteredHighlightImageDisplayCls>();
}
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<ImageDisplayCls>(); }
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<FittedImageDisplayCls>(); }
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<DrawingDisplayCls>(); }
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

View file

@ -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<PaintRect> {
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);
};

View file

@ -0,0 +1,432 @@
#include "Draw.h"
NAMESPACE_UPP
#define LLOG(x) // RLOG(x)
#define LTIMING(x) // RTIMING(x)
INITBLOCK {
RichValue<Painting>::Register();
RichValue<Drawing>::Register();
}
Size Draw::GetNativeDpi() const
{
return nativeDpi;
}
int Draw::GetNativeX(int x) const
{
return inchPixels != nativeDpi ? iscale(x, nativeDpi.cx, 600) : x;
}
int Draw::GetNativeY(int y) const
{
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);
}
void Draw::StartPage() {}
void Draw::EndPage() {}
// -------------------------------
bool Draw::IsDrawing() const
{
return dynamic_cast<const DrawingDraw *>(this);
}
// -------------------------------
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<Point>& vertices, const Vector<int>& 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<Point>& vertices,
int width, Color color, Color doxor)
{
DrawPolyline(vertices.Begin(), vertices.GetCount(), width, color, doxor);
}
void Draw::DrawPolyPolyPolygon(const Vector<Point>& vertices,
const Vector<int>& subpolygon_counts,
const Vector<int>& 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<Point>& vertices, const Vector<int>& 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<Point>& vertices, const Vector<int>& 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<Point>& 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() {}
// ---------------------------
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();
}
END_UPP_NAMESPACE

1247
archive/olddraw/Draw/Draw.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,88 @@
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 Xau Xdmcp";
library(BSD !XLFD) "Xft fontconfig Xrender freetype expat";
library(LINUX !XLFD !SHARED) "fontconfig Xrender freetype expat";
library(OSX11) "X11 Xft fontconfig Xrender freetype expat";
library(FREEBSD) xcb;
file
Draw.h,
DrawWin32.h,
Mt.cpp,
DrawWin32.cpp,
DrawX11.cpp,
ComposeText.cpp,
DrawText.cpp,
DrawTextWin32.cpp,
DrawTextXft.cpp,
Draw.cpp,
DrawOpWin32.cpp,
DrawOpX11.cpp,
DrawData.cpp,
Drawing.cpp,
MetaFile.cpp,
DrawUtil.cpp,
DrawTextUtil.cpp,
Display.h,
Display.cpp,
Debug.h,
Debug.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;

View file

@ -0,0 +1,127 @@
#include "Draw.h"
NAMESPACE_UPP
#define LTIMING(x)
// #define BENCHMARK_RLE
VectorMap<String, void *>& DataDrawer::Map()
{
static VectorMap<String, void *> x;
return x;
}
static StaticCriticalSection sDataDrawer;
void DataDrawer::AddFormat(const char *id, Factory factory)
{
INTERLOCKED_(sDataDrawer)
Map().Add(id, (void *)factory);
}
One<DataDrawer> 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<bool> 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<DataDrawer> 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

View file

@ -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)

View file

@ -0,0 +1,290 @@
#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);
}
#endif
END_UPP_NAMESPACE

View file

@ -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<Rect> 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<Rect> 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<Rect> 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<Rect>& cl = clip.Top();
bool ch = false;
Vector<Rect> ncl = Subtract(cl, r + actual_offset, ch);
if(ch) {
cl = ncl;
SetClip();
}
return clip.Top().GetCount();
}
bool Draw::IntersectClipOp(const Rect& r)
{
CloneClip();
Vector<Rect>& cl = clip.Top();
bool ch = false;
Vector<Rect> 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<Rect>& 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<Rect>& 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<XPoint> 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<XSegment> 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<XPoint> 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<XPoint> 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

View file

@ -0,0 +1,40 @@
#include "Draw.h"
NAMESPACE_UPP
struct cDrawRasterData : DataDrawer {
int cx;
StringStream ss;
One<StreamRaster> 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<cDrawRasterData>("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

View file

@ -0,0 +1,483 @@
#include "Draw.h"
NAMESPACE_UPP
#if defined(PLATFORM_WIN32) || defined(PLATFORM_X11)
#define LLOG(x) // LOG(x)
#define LTIMING(x) // TIMING(x)
bool Draw::sFini;
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;
}
}
bool Draw::StdFontSizeSet;
Size Draw::StdFontSize;
Font Draw::AStdFont;
INITBLOCK {
RichValue<Font>::Register();
}
void Draw::InitFonts()
{
DrawLock __;
if(sFini) return;
sFini = true;
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) {
if(!Draw::sFini) Draw::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;
}
Draw& ScreenInfo();
FontInfo Font::Info() const
{
DrawLock __;
return ScreenInfo().GetFontInfoW(*this);
}
void Draw::SetStdFont(Font font)
{
InitFonts();
AStdFont = font;
StdFontSizeSet = false;
}
Size Draw::GetStdFontSize()
{
DrawLock __;
if(!StdFontSizeSet) {
StdFontSizeSet = true;
FontInfo fi = AStdFont.Info();
FontInfo bfi = AStdFont().Bold().Info();
StdFontSize = Size(fi.GetAveWidth(), bfi.GetHeight());
}
return StdFontSize;
}
Font StdFont()
{
return Font(0, Draw::AStdFont.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 "<null>";
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 + '>';
}
int Draw::FontCacheMax = 32;
int Draw::FontCached;
void Draw::FreeFonts() {
FontCacheMax = FontCached = 0;
sFini = false;
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;
}
//# Pretty ugly code....
FontInfo::Data *Draw::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 *Draw::GetFontLru() {
static byte buff[sizeof(FontLink)];
static FontLink *fontlru;
if(!fontlru)
fontlru = new(buff) FontLink;
return (FontInfo::Data *)fontlru;
}
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
{
// CharMetrics mm;
// ptr->GetMetrics(&mm, c, 1);
// return mm;
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 Draw::Release(FontInfo::Data *font) {
DrawLock __;
ASSERT(font->refcount > 0);
LLOG("Release " << font->font << " count:" << font->count);
if(--font->refcount == 0) {
if(FontCacheMax == 0) {
delete font;
return;
}
FontInfo::Data *lru = GetFontLru();
font->LinkAfter(lru, LRU);
FontCached++;
LLOG("Placed to cache " << font->font << " cached:" << FontCached);
while(FontCached > FontCacheMax) {
ASSERT(lru->GetPrev(LRU) != lru);
FontCached--;
LLOG("Deleting from cache " << lru->GetPrev(LRU)->font <<
" cached: " << FontCached);
delete lru->GetPrev(LRU);
}
}
}
void FontInfo::Release()
{
if(ptr) Draw::Release(ptr);
}
void FontInfo::Retain(const FontInfo& f)
{
DrawLock __;
ptr = f.ptr;
ptr->refcount++;
charset = f.charset;
}
FontInfo Draw::GetFontInfoW(Font font) {
DrawLock __;
LTIMING("GetFontInfo");
byte charset = CHARSET_UNICODE;
if(lastFont.IsEqual(charset, font, 0, device))
return lastFont;
#ifdef PLATFORM_WIN32
HDC hdc = GetHandle();
FontInfo fi = Acquire(font, hdc ? hdc : ScreenHDC(), 0, device);
#endif
#ifdef PLATFORM_X11
FontInfo fi = Acquire(font, 0, device);
#endif
fi.charset = charset;
return fi;
}
void Draw::SetFont(Font font, int angle) {
DrawLock __;
LLOG("Set font: " << font << " face: " << font.GetFaceName());
if(lastFont && lastFont.IsEqual(CHARSET_UNICODE, font, angle, device))
return;
#ifdef PLATFORM_WIN32
lastFont = Acquire(font, GetHandle(), angle, device);
HFONT h = (HFONT) SelectObject(handle, lastFont.ptr->hfont);
if(!orgFont) orgFont = h;
#endif
#ifdef PLATFORM_X11
lastFont = Acquire(font, angle, device);
#endif
}
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);
}
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];
}
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;
}
#endif
END_UPP_NAMESPACE

View file

@ -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

View file

@ -0,0 +1,433 @@
#include "Draw.h"
NAMESPACE_UPP
#ifdef PLATFORM_WIN32
#define LLOG(x) // LOG(x)
#define LTIMING(x)
struct FontFaceInfo : Moveable<FontFaceInfo> {
String name;
dword info;
FontFaceInfo() { info = 0; }
};
static VectorMap<String, FontFaceInfo>& sFontFace()
{
static VectorMap<String, FontFaceInfo> s;
return s;
}
int Font::GetFaceCount()
{
if(!Draw::sFini) Draw::InitFonts();
return sFontFace().GetCount();
}
String Font::GetFaceName(int index) {
if(!Draw::sFini) Draw::InitFonts();
return index >= 0 && index < sFontFace().GetCount() ? sFontFace()[index].name
: Null;
}
dword Font::GetFaceInfo(int index) {
if(!Draw::sFini) Draw::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 Draw::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 Draw::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 Draw::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 *Draw::FontScreenSans = "Tahoma"; //TODO!
const char *Draw::FontScreenSerif = "Tahoma";
const char *Draw::FontScreenFixed = "Courier New";
const char *Draw::FontRoman = "Tahoma" ;
const char *Draw::FontArial = "Tahoma";
const char *Draw::FontCourier = "Tahoma";
const char *Draw::FontSymbol = "Tahoma";
const char *Draw::FontWingdings = "Tahoma";
const char *Draw::FontTahoma = "Tahoma";
#else
const char *Draw::FontScreenSans = "Arial";
const char *Draw::FontScreenSerif = "Times New Roman";
const char *Draw::FontScreenFixed = "Courier New";
const char *Draw::FontRoman = "Times New Roman" ;
const char *Draw::FontArial = "Arial";
const char *Draw::FontCourier = "Courier New";
const char *Draw::FontSymbol = "Symbol";
const char *Draw::FontWingdings = "WingDings";
const char *Draw::FontTahoma = "Tahoma";
#endif
void Draw::InitPlatformFonts() {
#ifdef PLATFORM_WINCE
HDC hdc = CreateDC(NULL, NULL, NULL, NULL);
#else
HDC hdc = CreateIC("DISPLAY", NULL, NULL, NULL);
#endif
ForceFace(hdc, FontScreenSans, 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> 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<int> 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 Draw::Acquire(Font font, HDC hdc, int angle, int device)
{
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 ^ (device << 9)) % FONTHASH);
LLOG("Acquire " << font);
for(;;) {
f = f->GetNext(HASH);
if(f == fh) break;
if(f->font == font && f->angle == angle && f->device == device)
{
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;
f->device = device;
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<KERNINGPAIR> 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 = Acquire(font, hdc, 0, device);
double sina, cosa;
SinCos(angle, sina, cosa);
f->offset.cx = fround(font0.GetAscent() * sina);
f->offset.cy = fround(font0.GetAscent() * cosa);
}
return FontInfo(f);
}
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

View file

@ -0,0 +1,376 @@
#include "Draw.h"
NAMESPACE_UPP
#ifdef PLATFORM_XFT
#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<String, XFTFontFaceInfo>& XFTFontFace()
{
static ArrayMap<String, XFTFontFaceInfo> 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<XftCharSpec> 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);
}
}
}
#endif
END_UPP_NAMESPACE

View file

@ -0,0 +1,636 @@
#include "Draw.h"
NAMESPACE_UPP
#define LTIMING(x) // TIMING(x)
void AddNotEmpty(Vector<Rect>& 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<Rect>& 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<Rect>& rr, const Rect& sub, Vector<Rect>& 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<Rect> Subtract(const Vector<Rect>& rr, const Rect& sub, bool& changed)
{
Vector<Rect> result;
if(Subtract(rr, sub, result))
changed = true;
return result;
}
void Subtract(Vector<Rect>& rr, const Rect& sub)
{
LTIMING("Subtract");
if(sub.IsEmpty())
return;
bool dummy;
rr = Subtract(rr, sub, dummy);
}
void Union(Vector<Rect>& rr, const Rect& add)
{
LTIMING("Union");
if(add.IsEmpty())
return;
Vector<Rect> 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<Rect> Intersect(const Vector<Rect>& b, const Rect& a, bool& changed)
{
Vector<Rect> 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(Draw& 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<Rect> RectRgn(const Rect& r)
{
Vector<Rect> q;
q.Add(r);
return q;
}
Vector<Rect> Intersect(const Vector<Rect>& r1, const Vector<Rect>& r2)
{
Vector<Rect> 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<Rect> Subtract(const Vector<Rect>& r1, const Vector<Rect>& r2)
{
Vector<Rect> q;
bool dummy;
q <<= r1;
for(int i = 0; i < r2.GetCount(); i++)
q = Subtract(q, r2[i], dummy);
return q;
}
Vector<Rect> Xor(const Vector<Rect>& r1, const Vector<Rect>& r2)
{
Vector<Rect> is = Intersect(r1, r2);
Vector<Rect> q = Subtract(r1, is);
q.Append(Subtract(r2, is));
return q;
}
Vector<Rect> GetFrameRgn(const Rect& rect, int n) {
Vector<Rect> 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(Draw& 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);
#ifdef PLATFORM_XFT
SetClip(gc, w.GetXftDraw(),
Intersect(Xor(GetFrameRgn(rect1 + offset, n), GetFrameRgn(rect2 + offset, n)),
RectRgn(clip + offset)));
#else
SetClip(gc, Intersect(Xor(GetFrameRgn(rect1 + offset, n), GetFrameRgn(rect2 + offset, n)),
RectRgn(clip + offset)));
#endif
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

View file

@ -0,0 +1,471 @@
#include "Draw.h"
NAMESPACE_UPP
#define LLOG(x) // LOG(x)
#define LTIMING(x) // RTIMING(x)
#ifdef PLATFORM_WIN32
static COLORREF sLightGray;
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<dword> *SColor;
ONCELOCK {
static Index<dword> 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<POINT *>(&w), 2);
return w;
}
Rect Draw::DPtoLP(const Rect& r) const {
DrawLock __;
Rect w = r;
::LPtoDP(handle, reinterpret_cast<POINT *>(&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<String> 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

View file

@ -0,0 +1,105 @@
#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:
void Abort() { aborted = true; }
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); }

View file

@ -0,0 +1,465 @@
#include "Draw.h"
#ifdef PLATFORM_X11
#define Time XTime
#define Font XFont
#define Display XDisplay
#define Picture XPicture
#ifndef flagNOGTK
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <gdk/gdkprivate.h>
#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();
}
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<XColor> 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<String>& 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
}
#ifdef PLATFORM_XFT
void SetClip(GC gc, XftDraw *xftdraw, const Vector<Rect>& cl)
#else
void SetClip(GC gc, const Vector<Rect>& cl)
#endif
{
DrawLock __;
LTIMING("SetClip");
Buffer<XRectangle> 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);
#ifdef PLATFORM_XFT
LLOG("XftDrawSetClipRectangles, # = " << cl.GetCount() << ", xftdraw = " << FormatIntHex(xftdraw));
XftDrawSetClipRectangles(xftdraw, 0, 0, xr, cl.GetCount());
LLOG("//XftDrawSetClipRectangles");
#endif
}
void Draw::CloneClip()
{
if(cloff.GetCount() > 1 && cloff.Top().clipi == cloff[cloff.GetCount() - 2].clipi) {
cloff.Top().clipi = clip.GetCount();
Vector<Rect>& 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");
#ifdef PLATFORM_XFT
UPP::SetClip(gc, xftdraw, clip.Top());
#else
UPP::SetClip(gc, clip.Top());
#endif
}
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<Rect>& _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() {}
#ifdef PLATFORM_XFT
Draw::Draw(Drawable _dw, GC _gc, XftDraw *_xftdraw, const Vector<Rect>& _clip)
#else
Draw::Draw(Drawable _dw, GC _gc, const Vector<Rect>& _clip)
#endif
{
LLOG("Draw");
dw = _dw;
gc = _gc;
#ifdef PLATFORM_XFT
xftdraw = _xftdraw;
#endif
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);
#ifdef PLATFORM_XFT
xftdraw = XftDrawCreate(Xdisplay, (Drawable) dw,
DefaultVisual(Xdisplay, Xscreenno), Xcolormap);
#endif
Vector<Rect> 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) {
#ifdef PLATFORM_XFT
XftDrawDestroy(xftdraw);
#endif
XFreePixmap(Xdisplay, dw);
XFreeGC(Xdisplay, gc);
}
}
NilDraw::NilDraw()
{
DrawLock __;
dw = Xroot;
gc = XCreateGC(Xdisplay, Xroot, 0, 0);
pixels = false;
Init(Vector<Rect>());
}
NilDraw::~NilDraw()
{
DrawLock __;
XFreeGC(Xdisplay, gc);
}
Draw& ScreenInfo() { return Single<NilDraw>(); }
END_UPP_NAMESPACE
#endif

View file

@ -0,0 +1,743 @@
#include "Draw.h"
NAMESPACE_UPP
#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<byte *>(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<int>(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)
{
ASSERT(IsDrawing());
drawing / code;
return drawing;
}
void DrawingDraw::DrawingBegin()
{
Cloff& w = cloff.Add();
w.org = actual_offset;
w.drawingclip = drawingclip;
}
void DrawingDraw::BeginOp()
{
DrawingOp(BEGIN);
DrawingBegin();
}
void DrawingDraw::OffsetOp(Point p)
{
DrawingOp(OFFSET) % p;
DrawingBegin();
actual_offset += p;
}
bool DrawingDraw::ClipOp(const Rect& r)
{
DrawingOp(CLIP) % const_cast<Rect&>(r);
DrawingBegin();
drawingclip &= r + actual_offset;
return !drawingclip.IsEmpty();
}
bool DrawingDraw::ClipoffOp(const Rect& r)
{
DrawingOp(CLIPOFF) % const_cast<Rect&>(r);
DrawingBegin();
drawingclip &= r + actual_offset;
actual_offset += r.TopLeft();
return !drawingclip.IsEmpty();
}
void DrawingDraw::EndOp()
{
DrawingOp(END);
ASSERT(cloff.GetCount());
Cloff& w = cloff.Top();
actual_offset = w.org;
drawingclip = w.drawingclip;
cloff.Drop();
}
bool DrawingDraw::ExcludeClipOp(const Rect& r)
{
DrawingOp(EXCLUDECLIP) % const_cast<Rect&>(r);
return !drawingclip.IsEmpty();
}
bool DrawingDraw::IntersectClipOp(const Rect& r)
{
DrawingOp(INTERSECTCLIP) % const_cast<Rect&>(r);
drawingclip &= r;
return !drawingclip.IsEmpty();
}
Rect DrawingDraw::GetClipOp() const
{
return drawingclip - actual_offset;
}
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(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(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(DRAWDATA) % x % y % cx % cy % h;
val.Add(data);
}
void DrawingDraw::DrawDrawingOp(const Rect& target, const Drawing& w)
{
DrawingOp(DRAWDRAWING) % const_cast<Rect&>(target);
val.Add(w);
}
void DrawingDraw::DrawPaintingOp(const Rect& target, const Painting& w)
{
DrawingOp(DRAWPAINTING) % const_cast<Rect&>(target);
val.Add(w);
}
void DrawingDraw::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color)
{
DrawingOp(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(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(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(DRAWELLIPSE) % const_cast<Rect&>(r) % color / pen % pencolor;
}
void DrawingDraw::DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color)
{
DrawingOp(DRAWARC) % const_cast<Rect&>(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(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<int *>(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;
Point trgini;
Vector<Point16> stack;
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();
DrawingPos(const String& src) : StringStream(src) {}
};
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);
ps.trgini = GetOffset();
Rect r;
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 BEGIN:
Begin();
ps.stack.Add(ps.srcoff);
break;
case OFFSET:
ps % p;
Offset(ps(p));
ps.stack.Add(ps.srcoff);
ps.srcoff += p;
ps.trgoff = GetOffset() - ps.trgini;
break;
case CLIP:
Clip(ps.GetRect());
ps.stack.Add(ps.srcoff);
break;
case CLIPOFF:
ps % r;
Clipoff(ps(r));
ps.stack.Add(ps.srcoff);
ps.srcoff += r.TopLeft();
ps.trgoff = GetOffset() - ps.trgini;
break;
case EXCLUDECLIP:
ExcludeClip(ps.GetRect());
break;
case INTERSECTCLIP:
IntersectClip(ps.GetRect());
break;
case END:
End();
ps.srcoff = ps.stack.Pop();
ps.trgoff = GetOffset() - ps.trgini;
break;
case DRAWRECT:
ps % x % y % cx % cy % color;
DrawRect(ps(x, y, cx, cy), color);
break;
case 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 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 DRAWDRAWING:
if(w.val.GetCount())
dw = w.val[vi++];
else
ps % dw;
DrawDrawing(ps.GetRect(), dw);
break;
case DRAWPAINTING:
if(w.val.GetCount())
sw = w.val[vi++];
else
ps % sw;
DrawPainting(ps.GetRect(), sw);
break;
case DRAWLINE:
ps % x % y % cx % cy % width % color;
DrawLine(ps(x, y), ps(cx, cy), width > 0 ? ps.GetW(width) : width, color);
break;
case DRAWELLIPSE:
r = ps.GetRect();
ps % color / width % pencolor;
DrawEllipse(r, color, width > 0 ? ps.GetW(width) : width, pencolor);
break;
#ifndef PLATFORM_WINCE
case DRAWARC:
r = ps.GetRect();
ps % p % p1 % color % width;
DrawArc(r, ps(p), ps(p1), width > 0 ? ps.GetW(width) : width, color);
break;
case DRAWPOLYPOLYLINE:
{
int version;
ps / version;
ps % width % color % doxor;
ps % vertex_count % count_count;
Buffer<Point> vertices(vertex_count);
Buffer<int> 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 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<Point> vertices(vertex_count);
Buffer<int> subpolygon_counts(subpolygon_count_count);
Buffer<int> 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 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<wchar> txt(n);
ps.Stream::GetW(txt, n);
text = WString(txt, n);
}
else {
Buffer<char> 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<int> 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;
#ifdef PLATFORM_WIN32
cloff.Clear();
#endif
#ifdef PLATFORM_X11
cloff.Clear();
clip.Clear();
Vector<Rect> cliplist;
cliplist.Add(RectC(0, 0, sz.cx, sz.cy));
Init(cliplist);
#endif
drawingclip = Rect(0, 0, sz.cx, sz.cy);
pixels = false;
LLOG("DrawingDraw::Create, sz = " << sz << " -> clip = " << GetClip());
}
void DrawingDraw::DInit()
{
#ifdef PLATFORM_WIN32
Attach(ScreenHDC());
#endif
#ifdef PLATFORM_X11
gc = XCreateGC(Xdisplay, RootWindow(Xdisplay, Xscreenno), 0, 0);
dw = RootWindow(Xdisplay, Xscreenno);
#endif
pixels = false;
backdraw = true;
LLOG("DrawingDraw::DInit: pixels = " << Pixels());
}
DrawingDraw::DrawingDraw()
{
DInit();
}
DrawingDraw::DrawingDraw(Size sz) {
DInit();
Create(sz);
}
DrawingDraw::DrawingDraw(int cx, int cy) {
DInit();
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<Drawing>::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;
}
}
#ifdef PLATFORM_WIN32
#ifndef PLATFORM_WINCE
Drawing Drawing::FromWMF(const WinMetaFile& wmf) {
if(!wmf) return Drawing();
Size sz = wmf.GetSize();
DrawingDraw dd(sz);
wmf.Paint(dd, 0, 0, sz.cx, sz.cy);
return dd;
}
Drawing Drawing::LoadWMF(const char *file) {
return FromWMF(WinMetaFile(file));
}
Drawing Drawing::ReadClipboardWMF() {
WinMetaFile wmf;
wmf.ReadClipboard();
return FromWMF(wmf);
}
WinMetaFile Drawing::AsWMF() const {
Size sz = GetSize();
WinMetaFileDraw wd(sz.cx, sz.cy);
wd.DrawDrawing(0, 0, sz.cx, sz.cy, *this);
return wd.Close();
}
void Drawing::WriteClipboardWMF() const {
WinMetaFile wmf = AsWMF();
wmf.WriteClipboard();
}
#endif
#endif
END_UPP_NAMESPACE

View file

@ -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<Image>::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<Image>::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> 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<Image> 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<String, Iml *>& sImgMap()
{
static VectorMap<String, Iml *> 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<byte> 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

View file

@ -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<RGBA> 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<Image> > {
private:
struct Data : Link<Data> {
Atomic refcount;
int64 serial;
int paintcount;
static Link<Data> 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<Image::Data> 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<Image>(*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<Image> UnpackImlData(const void *ptr, int len);
Vector<Image> UnpackImlData(const String& d);
class Iml {
struct IImage : Moveable<IImage> {
bool loaded;
Image image;
IImage() { loaded = false; }
};
struct Data : Moveable<Data> {
const char *data;
int len, count;
};
Vector<Data> data;
VectorMap<String, IImage> 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

View file

@ -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>((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<int>(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<Image> UnpackImlData(const void *ptr, int len)
{
Vector<Image> 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<Image> UnpackImlData(const String& d)
{
return UnpackImlData(~d, d.GetLength());
}
END_UPP_NAMESPACE

View file

@ -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<bool> >& 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<bool> > 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

View file

@ -0,0 +1,38 @@
class ImageDraw : public Draw, NoCopy {
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;
Draw 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();
};

View file

@ -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<int> xmx(sz2.cx);
Buffer<int> 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

View file

@ -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<dword> horz;
Vector<dword> 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<dword> 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<int, int> progress = false);
Image Rescale(const Image& src, Size sz, const Rect& src_rc, Gate2<int, int> progress = false);
Image Rescale(const Image& src, Size sz, Gate2<int, int> progress = false);
Image Rescale(const Image& src, int cx, int cy, Gate2<int, int> 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);

View file

@ -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>((int)((i <= HALF ? o : 2 - o) * 128), 0, 255);
}
}
return cache;
}
Vector<dword> AAGetMap(int& dmin, int& dmax, int dclipmin, int dclipmax,
int smin, int smax, int sclipmin, int sclipmax, int times, int avail)
{
Vector<dword> 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<int, int> 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<int, int> 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<int, int> progress)
{
return Rescale(src, sz, src.GetSize());
}
Image Rescale(const Image& src, int cx, int cy, Gate2<int, int> progress)
{
return Rescale(src, Size(cx, cy));
}
END_UPP_NAMESPACE

View file

@ -0,0 +1,614 @@
#include "Draw.h"
#ifdef PLATFORM_WIN32
#include <shellapi.h>
#endif
NAMESPACE_UPP
#ifdef PLATFORM_WIN32
#define LTIMING(x) // RTIMING(x)
bool ImageFallBack
// = true
;
class BitmapInfo32__ {
Buffer<byte> 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<byte> 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<RGBA> 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 **)&section, 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<RGBA> 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<RGBA> 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

View file

@ -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<RGBA> 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<byte> 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<Rect> 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<RGBA> 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 <X11/cursorfont.h>
#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<RGBA> 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

View file

@ -0,0 +1,176 @@
#include "Draw.h"
NAMESPACE_UPP
#define LLOG(x) // LOG(x)
static StaticCriticalSection sMakeImage;
static LRUCache<Image>& sImageCache()
{
static LRUCache<Image> m;
return m;
}
struct scImageMaker : LRUCache<Image>::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<Image>& cache = sImageCache();
cache.ClearCounters();
}
}
Image MakeImage__(const ImageMaker& m, bool paintonly)
{
Image result;
INTERLOCKED_(sMakeImage) {
LRUCache<Image>& 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

View file

@ -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<byte> 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<byte> buffer(size);
::GetEnhMetaFileBits(hemf, size, buffer);
s.SerializeRaw(buffer, size);
}
else
s % size;
}
else {
Clear();
s % size;
if(size) {
Buffer<byte> 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

View file

@ -0,0 +1,41 @@
#include "Draw.h"
NAMESPACE_UPP
static StaticMutex sGuiLock;
static thread__ int sGuiLockLevel = 0;
void EnterGuiMutex()
{
if(sGuiLockLevel++ == 0)
sGuiLock.Enter();
}
void EnterGuiMutex(int n)
{
if(n > 0) {
if(sGuiLockLevel == 0)
sGuiLock.Enter();
sGuiLockLevel += n;
}
}
void LeaveGuiMutex()
{
ASSERT(sGuiLockLevel > 0);
if(--sGuiLockLevel == 0)
sGuiLock.Leave();
}
int LeaveGuiMutexAll()
{
int q = sGuiLockLevel;
if(q) {
sGuiLock.Leave();
sGuiLockLevel = 0;
}
return q;
}
END_UPP_NAMESPACE

View file

@ -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<int>(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> 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<sPalMaker> 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

View file

@ -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<Line *>(&b)->free = const_cast<Line *>(&b)->fmtfree = false;
#ifdef _DEBUG
const_cast<Line *>(&b)->data = NULL;
const_cast<Line *>(&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<int, int> 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<int, int> 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<int, int> progress)
{
if(Open(s)) {
Image img = GetImage(progress);
if(!IsError())
return img;
}
return Image();
}
Image StreamRaster::LoadFile(const char *fn, const Gate2<int, int> progress)
{
FileIn in(fn);
return in ? Load(in, progress) : Image();
}
Image StreamRaster::LoadString(const String& s, const Gate2<int, int> progress)
{
StringStream ss(s);
return Load(ss, progress);
}
static StaticCriticalSection sAnyRaster;
Vector<void *>& StreamRaster::Map()
{
static Vector<void *> x;
return x;
}
void StreamRaster::AddFormat(RasterFactory factory)
{
INTERLOCKED_(sAnyRaster)
Map().Add((void *)factory);
}
One<StreamRaster> StreamRaster::OpenAny(Stream& s)
{
INTERLOCKED_(sAnyRaster)
for(int i = 0; i < Map().GetCount(); i++) {
int64 p = s.GetPos();
One<StreamRaster> 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<int, int> progress)
{
One<StreamRaster> r = OpenAny(s);
return r ? r->GetImage(progress) : Image();
}
Image StreamRaster::LoadFileAny(const char *fn, const Gate2<int, int> progress)
{
FileIn in(fn);
return LoadAny(in, progress);
}
Image StreamRaster::LoadStringAny(const String& s, const Gate2<int, int> progress)
{
StringStream ss(s);
return LoadAny(ss, progress);
}
END_UPP_NAMESPACE

View file

@ -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<byte> 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<int, int> progress = false);
Image GetImage(const Gate2<int, int> 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<byte> > lines;
Vector<RGBA> palette;
};
class StreamRaster : public Raster {
Stream *s;
bool error;
typedef StreamRaster *(*RasterFactory)();
template <class T> static StreamRaster *FactoryFn() { return new T; }
static void AddFormat(RasterFactory f);
static Vector<void *>& Map();
public:
Stream& GetStream() { return *s; }
bool Open(Stream& _s);
bool IsError();
void SetError() { error = true; }
Image Load(Stream& s, const Gate2<int, int> progress = false);
Image LoadFile(const char *fn, const Gate2<int, int> progress = false);
Image LoadString(const String& s, const Gate2<int, int> progress = false);
template <class T>
static void Register() { AddFormat(&StreamRaster::FactoryFn<T>); }
static One<StreamRaster> OpenAny(Stream& s);
static Image LoadAny(Stream& s, const Gate2<int, int> progress = false);
static Image LoadFileAny(const char *fn, const Gate2<int, int> progress = false);
static Image LoadStringAny(const String& s, const Gate2<int, int> progress = false);
StreamRaster() { error = true; }
};
class RasterEncoder {
Size size, dots;
Point hotspot;
RGBA *line;
Buffer<byte> scanline;
int line_bytes;
Buffer<RGBA> h;
Buffer<RGBA> palette;
One<PaletteCv> 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);
};

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 *))

View file

@ -0,0 +1 @@
FN(void, gnome_triggers_vdo, (const char *msg, const char *level, const char *supinfo[]))

View file

@ -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, ...))

View file

@ -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))

View file

@ -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))

View file

@ -0,0 +1,9 @@
//#BLITZ_APPROVE
#define IMAGE_KEEP
#include "iml_header.h"
#undef IMAGE_KEEP
#include "iml_source.h"

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,4 @@
#ifndef _Draw_icpp_init_stub
#define _Draw_icpp_init_stub
#include "Core/init"
#endif

View file

@ -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,

File diff suppressed because it is too large Load diff

View file

@ -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,

View file

@ -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,

View file

@ -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; ]

View file

@ -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,

View file

@ -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; ]

View file

@ -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 <CtrlLib/CtrlLib.h>&]
[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<Point> 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
<EFBFBD>澿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ы<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>Α
Ёи访<EFBFBD><EFBFBD>Φ<EFBFBD><EFBFBD><EFBFBD>
ü<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ψ<EFBFBD>
в<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>Ν<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Н
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>φ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>е<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>э<EFBFBD>М<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>嬿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>φ
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>忿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>Ь<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>轿<EFBFBD>嬿<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>η<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>椿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ё<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>И<EFBFBD><EFBFBD>А<EFBFBD>
ы<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>и
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>Ь<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>ê<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>鱿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Н<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ц
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ńǒ<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
毿<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>伿
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>ω
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>饿<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ζ
ч<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>í访<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Т<EFBFBD><EFBFBD><EFBFBD>蹿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ι<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>у<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>蹿<EFBFBD><EFBFBD>亿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
浿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>φ<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>庿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
К<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
χ<EFBFBD><EFBFBD>
巿<EFBFBD>Я<EFBFBD>
<EFBFBD><EFBFBD>嬿<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>亿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>д
<EFBFBD>Ш<EFBFBD><EFBFBD><EFBFBD>χ<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>Я<EFBFBD><EFBFBD>ˉ<EFBFBD><EFBFBD>Ш<EFBFBD>
<EFBFBD><EFBFBD>亿<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Ε<EFBFBD>尿<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Τ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>尿
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ш<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
φ<EFBFBD><EFBFBD>
¤<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>ū<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>ё<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǚ<EFBFBD>
<EFBFBD><EFBFBD>Μ<EFBFBD><EFBFBD><EFBFBD>便<EFBFBD><EFBFBD>г<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>ν<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>蹿<EFBFBD>ц丿
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>蹿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>Щ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>蹿<EFBFBD><EFBFBD>蹿<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>ц<EFBFBD><EFBFBD><EFBFBD>ξ
<EFBFBD>цΛ
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>櫿<EFBFBD><EFBFBD>
<EFBFBD>ц使<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>丿<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǐ
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
亿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>о<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>驿<EFBFBD>
φ<EFBFBD>φ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>广<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>嬿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>鷿<EFBFBD><EFBFBD>箿<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Ρ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>ň<EFBFBD>
<EFBFBD><EFBFBD>Ζ
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>縿<EFBFBD>
毿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>騿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>π<EFBFBD><EFBFBD>
<EFBFBD>毿<EFBFBD><EFBFBD><EFBFBD>   
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>Д<EFBFBD>г<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
&]
[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 <CtrlLib/CtrlLib.h>&]
[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
<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ч<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>р
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ы<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>迿<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>¤<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
э<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>诿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ε<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɡ<EFBFBD>
<EFBFBD>ì<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Φ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>退ń<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>Ψ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ρ<EFBFBD><EFBFBD><EFBFBD>
фò<EFBFBD>ε<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>竿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>窿<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>沿<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
髿<EFBFBD>
<EFBFBD><EFBFBD>屿<EFBFBD>竿ǹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>εá<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>趿<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
И<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>绿<EFBFBD>é<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>Α
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
э<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
ε
<EFBFBD><EFBFBD><EFBFBD>Ц<EFBFBD>
<EFBFBD>
<EFBFBD><EFBFBD>Α<EFBFBD>
<EFBFBD>Α<EFBFBD>檿<EFBFBD>
<EFBFBD>ń<EFBFBD><EFBFBD>绿
退<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>穿<EFBFBD>退<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>Α<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>庿<EFBFBD>
屿<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
騿<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>ΑΑ<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
&]
[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 <CtrlLib/CtrlLib.h>&]
[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<int> 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
<EFBFBD><EFBFBD>ɑ泿<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>Ё<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
嬿<EFBFBD><EFBFBD><EFBFBD>樿<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>使<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>稿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>щ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ы
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>驿<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>Δ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>竿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>鴿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>岿<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>я<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ш<EFBFBD><EFBFBD>
<EFBFBD>ь<EFBFBD><EFBFBD>帿<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǚ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>Ф_
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>线岿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>贿<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>絿<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>詿<EFBFBD><EFBFBD><EFBFBD>
ě<EFBFBD>ú<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
岿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
鴿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Α<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>я<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ё<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>岿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>
<EFBFBD><EFBFBD>ē<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>Ю
<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>
广<EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>轿
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>广<EFBFBD>·湿<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>ì<EFBFBD><EFBFBD>
·<EFBFBD><EFBFBD>诿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>ň<EFBFBD>
<EFBFBD>ф<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>Υ<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>ЯЁ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>Я
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
广<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>р<EFBFBD>ü<EFBFBD><EFBFBD><EFBFBD>
ń<EFBFBD><EFBFBD><EFBFBD>è<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ъ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>箿<EFBFBD><EFBFBD>
<EFBFBD>ψ<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ
<EFBFBD>崿ǚ<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
τ<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>簿<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>祿<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>
鴿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>_<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>Σ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ǔ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>О<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>溿<EFBFBD>ρ<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>è
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>簿<EFBFBD><EFBFBD>
詿<EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>è<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>ü¤<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>ù<EFBFBD>ü<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>退
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>¤<EFBFBD><EFBFBD>
<EFBFBD>¤<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
鹿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Δ<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ň<EFBFBD><EFBFBD>И
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>υ<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>ǒ<EFBFBD>
<EFBFBD><EFBFBD>诿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>Ξ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>樿<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
亿<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
я<EFBFBD>賿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
μ<EFBFBD><EFBFBD>ě
<EFBFBD><EFBFBD><EFBFBD>м<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ν<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Η
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>ν<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鸿耀<EFBFBD>
Й<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ё<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>Ζп<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>踿Η<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>à<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>Ω
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>у<EFBFBD><EFBFBD><EFBFBD>
&]
[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 <CtrlLib/CtrlLib.h>&]
[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
<EFBFBD>渿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
线<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>τ
<EFBFBD>泿<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ω<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>О<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>Ο<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
︿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>π<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>使<EFBFBD>ё<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>迿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>姿<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>й<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>箿<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>ü<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ΤК<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
м<EFBFBD>ё<EFBFBD>浿<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>鸿<EFBFBD>з<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>椿<EFBFBD><EFBFBD>·з<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>穿<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>羿<EFBFBD><EFBFBD>
蹿<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>×<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
趿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>渿<EFBFBD>Θ<EFBFBD>廿<EFBFBD><EFBFBD>
髿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ж<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>窿<EFBFBD><EFBFBD>洿<EFBFBD><EFBFBD>
<EFBFBD>广<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>С<EFBFBD>э<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>岿Б<EFBFBD>Ч绿
<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>ˉ<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>ì<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>ü<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>
<EFBFBD>
徿<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鸿<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>榿<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
ъ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>ω
<EFBFBD><EFBFBD>В<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>騿Σ<EFBFBD>
<EFBFBD><EFBFBD>θ<EFBFBD>
泿<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ī婿θ騿<EFBFBD>
θ<EFBFBD><EFBFBD>
Σν<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
广<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Υ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>蹿
<EFBFBD>Ф<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>ц<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD> <EFBFBD>ˇ
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>р<EFBFBD>у
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>т<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
в羿<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>Т<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Τ<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>à
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>ё<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ш<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ν<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
穿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>宿
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD>
З<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ш
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>鱿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ω<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>Ь<EFBFBD>穿<EFBFBD>
<EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>í<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
μ<EFBFBD>婿樿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>轿驿<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>Б<EFBFBD>ɑ
<EFBFBD>щ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>庿<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>怀<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>騿<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>
<EFBFBD><EFBFBD>
穿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>и<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
&]
[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 <CtrlLib/CtrlLib.h>&]
[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
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD> <EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>崿
<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
溿<EFBFBD><EFBFBD>ē<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>Н<EFBFBD><EFBFBD><EFBFBD>ъ<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>絿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ò
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>±<EFBFBD>ˉя<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>踿<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>祿<EFBFBD><EFBFBD>
榿<EFBFBD>Ψ<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>¨<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ɡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>Ю
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>縿<EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>
岿<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ш<EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ж<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD>
&]
[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 <CtrlLib/CtrlLib.h>&]
[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; ]

File diff suppressed because it is too large Load diff