CtrlCore,Draw, POSIX: Fixed font metrics issue, fixed editfield frame issue, fixed PdfDraw

git-svn-id: svn://ultimatepp.org/upp/trunk@1480 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2009-08-08 21:52:08 +00:00
parent d89a0903b9
commit 3ecde91bb5
13 changed files with 2081 additions and 2012 deletions

View file

@ -7,11 +7,10 @@ NAMESPACE_UPP
#define LTIMING(x)
#define LLOG(x)
int gtk_antialias = -1;
int gtk_hinting = -1;
String gtk_hintstyle;
String gtk_rgba;
extern int gtk_antialias;
extern int gtk_hinting;
extern String gtk_hintstyle;
extern String gtk_rgba;
extern int gtk_dpi;
XftFont *CreateXftFont(Font font, int angle)
@ -22,15 +21,11 @@ XftFont *CreateXftFont(Font font, int angle)
Std(font);
int hg = abs(font.GetHeight());
if(hg == 0) hg = 10;
int i = font.GetFace();
if(i < 0 || i >= Font::GetFaceCount())
i = 0;
String face = font.GetFaceName();
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_DPI, gtk_dpi);
FcPatternAddInteger(p, FC_WEIGHT, font.IsBold() ? 200 : 100);
FcPatternAddBool(p, FC_MINSPACE, 1);
if(angle) {
@ -108,6 +103,53 @@ XftFont *GetXftFont(Font fnt, int angle)
return be.xftfont;
}
CommonFontInfo XftGetFontInfoSys(Font font)
{
CommonFontInfo fi;
String path;
XftFont *xftfont = GetXftFont(font, 0);
if(xftfont) {
fi.ascent = (int16)xftfont->ascent;
fi.descent = (int16)xftfont->descent;
fi.height = fi.ascent + fi.descent;
fi.lineheight = (int16)xftfont->height;
fi.external = 0;
fi.internal = 0;
fi.overhang = 0;
fi.maxwidth = (int16)xftfont->max_advance_width;
fi.avewidth = fi.maxwidth;
fi.default_char = '?';
fi.fixedpitch = font.GetFaceInfo() & Font::FIXEDPITCH;
char *fn = NULL;
XftPatternGetString(xftfont->pattern, XFT_FILE, 0, &fn);
if(fn && strlen(fn) < 250)
strcpy(fi.path, fn);
}
return fi;
}
GlyphInfo XftGetGlyphInfoSys(Font font, int chr)
{
wchar h = chr;
XGlyphInfo info;
XftTextExtents16(Xdisplay, GetXftFont(font, 0), &h, 1, &info);
GlyphInfo gi;
gi.width = info.xOff;
gi.lspc = -info.x;
gi.rspc = info.xOff - info.width + info.x;
return gi;
}
INITBLOCK {
// extern FT_Face (*FTFaceXft)(Font fnt, String *rpath);
extern CommonFontInfo (*GetFontInfoSysXft)(Font font);
extern GlyphInfo (*GetGlyphInfoSysXft)(Font font, int chr);
// FTFaceXft = XftFTFace;
GetFontInfoSysXft = XftGetFontInfoSys;
GetGlyphInfoSysXft = XftGetGlyphInfoSys;
}
void SystemDraw::DrawTextOp(int x, int y, int angle, const wchar *text, Font font,
Color ink, int n, const int *dx) {
GuiLock __;

View file

@ -577,11 +577,12 @@ String GtkStyleString(const char *name)
return h;
}
extern int gtk_dpi;
extern int gtk_antialias;
extern int gtk_hinting;
extern String gtk_hintstyle;
extern String gtk_rgba;
int gtk_antialias = -1;
int gtk_hinting;
String gtk_hintstyle;
String gtk_rgba;
extern void ClearFtFaceCache();
void ChHostSkin()
{
@ -623,7 +624,6 @@ void ChHostSkin()
String font_name = GtkStyleString("gtk-font-name");
int xdpi = Nvl(GtkStyleInt("gtk-xft-dpi"), 72 * 1024);
gtk_dpi = xdpi / 1024;
gtk_antialias = Nvl(GtkStyleInt("gtk-xft-antialias"), -1);
gtk_hinting = Nvl(GtkStyleInt("gtk-xft-hinting"), -1);
// gtk_hintstyle = GtkStyleString("gtk-xft-hintstyle");
@ -670,6 +670,8 @@ void ChHostSkin()
Draw::SetStdFont(Font(fontname, (fontheight * xdpi + 512*72) / (1024*72))
.Bold(bold).Italic(italic));
ClearFtFaceCache();
ColoredOverride(CtrlsImg::Iml(), CtrlsImg::Iml());
Color fc = Blend(SColorHighlight, SColorShadow);
@ -1255,6 +1257,8 @@ void ChHostSkin()
GUI_DropShadows_Write(1);
GUI_AltAccessKeys_Write(1);
GUI_AKD_Conservative_Write(0);
ClearFtFaceCache();
}
END_UPP_NAMESPACE

View file

@ -91,6 +91,7 @@ public:
Color selected, selectedtext;
Value edge[4];
bool activeedge;
int vfm;
};
protected:

View file

@ -67,9 +67,18 @@ int TextArrayOps::GetPrevWord(int cursor)
return c;
}
Rect LookMargins(const Rect& r, const Value& ch)
{
Rect m = ChMargins(ch);
int fcy = GetStdFontCy();
if(m.top + m.bottom + fcy > r.GetHeight())
m.top = m.bottom = max((r.GetHeight() - fcy) / 2, 0);
return m;
}
void LookFrame::FrameLayout(Rect& r)
{
Rect m = ChMargins(Get());
Rect m = LookMargins(r, Get());
r.left += m.left;
r.right -= m.right;
r.top += m.top;
@ -90,7 +99,7 @@ void LookFrame::FrameAddSize(Size& sz)
void ActiveEdgeFrame::FrameLayout(Rect& r)
{
Rect m = ChMargins(edge[0]);
Rect m = LookMargins(r, edge[0]);
r.left += m.left;
r.right -= m.right;
r.top += m.top;
@ -135,6 +144,7 @@ CH_STYLE(EditField, Style, StyleDefault)
for(int i = 0; i < 4; i++)
edge[i] = CtrlsImg::EFE();
activeedge = false;
vfm = 2;
}
bool EditField::FrameIsEdge()

View file

@ -1,321 +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
#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

@ -1,193 +1,193 @@
#include "Draw.h"
NAMESPACE_UPP
#define LLOG(x) // LOG(x)
#define LTIMING(x) // TIMING(x)
WString TextUnicode(const char *s, int n, byte cs, Font font)
{
if(n < 0)
n = (int)strlen(s);
#ifdef PLATFORM_WIN32
if(font.GetFace() == Font::SYMBOL) {
WStringBuffer b(n);
wchar *t = b;
while(n > 0) {
*t++ = *s++;
n--;
}
return b;
}
#endif
return ToUnicode(s, n, cs);
}
void Draw::DrawText(int x, int y, int angle, const wchar *text, Font font,
Color ink, int n, const int *dx)
{
if(IsNull(ink)) return;
if(n < 0)
n = wstrlen(text);
Std(font);
double sina;
double cosa;
int d = 0;
if(angle)
Draw::SinCos(angle, sina, cosa);
for(int i = 0; i < n; i++) {
wchar chr = text[i];
GlyphInfo gi = GetGlyphInfo(font, chr);
if(gi.IsNormal())
if(angle)
DrawTextOp(int(x + cosa * d), int(y - sina * d), angle, &chr, font, ink, 1, NULL);
else {
int c = 1;
int dd = 0;
while(c < n) {
GlyphInfo gi2 = GetGlyphInfo(font, text[i + c]);
if(!gi2.IsNormal())
break;
dd += dx ? dx[c] : gi.width;
c++;
gi = gi2;
}
DrawTextOp(x + d, y, 0, text + i, font, ink, c, dx);
d += dd;
i += c - 1;
if(dx)
dx += c - 1;
}
else
if(gi.IsReplaced()) {
Font fnt = font;
fnt.Face(gi.lspc);
fnt.Height(gi.rspc);
if(angle)
DrawTextOp(int(x + cosa * d), int(y - sina * (font.GetAscent() - fnt.GetAscent() + d)),
angle, &chr, fnt, ink, 1, NULL);
else
DrawTextOp(x + d, y + font.GetAscent() - fnt.GetAscent(), 0, &chr, fnt, ink, 1, NULL);
GlyphMetrics(gi, font, chr);
}
else
if(gi.IsComposed()) {
ComposedGlyph cg;
Compose(font, chr, cg);
if(angle) {
DrawTextOp(int(x + cosa * d), int(y - sina * d), angle, &cg.basic_char, font, ink, 1, NULL);
DrawTextOp(int(x + cosa * (d + cg.mark_pos.x)), int(y - sina * (cg.mark_pos.y + d)), angle, &cg.mark_char, cg.mark_font, ink, 1, NULL);
}
else {
DrawTextOp(x + d, y, 0, &cg.basic_char, font, ink, 1, NULL);
DrawTextOp(x + cg.mark_pos.x + d, y + cg.mark_pos.y, 0, &cg.mark_char, cg.mark_font, ink, 1, NULL);
}
GlyphMetrics(gi, font, chr);
}
d += dx ? *dx++ : gi.width;
}
}
// ----------------------------
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());
}
END_UPP_NAMESPACE
#include "Draw.h"
NAMESPACE_UPP
#define LLOG(x) // LOG(x)
#define LTIMING(x) // TIMING(x)
WString TextUnicode(const char *s, int n, byte cs, Font font)
{
if(n < 0)
n = (int)strlen(s);
#ifdef PLATFORM_WIN32
if(font.GetFace() == Font::SYMBOL) {
WStringBuffer b(n);
wchar *t = b;
while(n > 0) {
*t++ = *s++;
n--;
}
return b;
}
#endif
return ToUnicode(s, n, cs);
}
void Draw::DrawText(int x, int y, int angle, const wchar *text, Font font,
Color ink, int n, const int *dx)
{
if(IsNull(ink)) return;
if(n < 0)
n = wstrlen(text);
Std(font);
double sina;
double cosa;
int d = 0;
if(angle)
Draw::SinCos(angle, sina, cosa);
for(int i = 0; i < n; i++) {
wchar chr = text[i];
GlyphInfo gi = GetGlyphInfo(font, chr);
if(gi.IsNormal())
if(angle)
DrawTextOp(int(x + cosa * d), int(y - sina * d), angle, &chr, font, ink, 1, NULL);
else {
int c = 1;
int dd = 0;
while(c < n) {
GlyphInfo gi2 = GetGlyphInfo(font, text[i + c]);
if(!gi2.IsNormal())
break;
dd += dx ? dx[c] : gi.width;
c++;
gi = gi2;
}
DrawTextOp(x + d, y, 0, text + i, font, ink, c, dx);
d += dd;
i += c - 1;
if(dx)
dx += c - 1;
}
else
if(gi.IsReplaced()) {
Font fnt = font;
fnt.Face(gi.lspc);
fnt.Height(gi.rspc);
if(angle)
DrawTextOp(int(x + cosa * d), int(y - sina * (font.GetAscent() - fnt.GetAscent() + d)),
angle, &chr, fnt, ink, 1, NULL);
else
DrawTextOp(x + d, y + font.GetAscent() - fnt.GetAscent(), 0, &chr, fnt, ink, 1, NULL);
GlyphMetrics(gi, font, chr);
}
else
if(gi.IsComposed()) {
ComposedGlyph cg;
Compose(font, chr, cg);
if(angle) {
DrawTextOp(int(x + cosa * d), int(y - sina * d), angle, &cg.basic_char, font, ink, 1, NULL);
DrawTextOp(int(x + cosa * (d + cg.mark_pos.x)), int(y - sina * (cg.mark_pos.y + d)), angle, &cg.mark_char, cg.mark_font, ink, 1, NULL);
}
else {
DrawTextOp(x + d, y, 0, &cg.basic_char, font, ink, 1, NULL);
DrawTextOp(x + cg.mark_pos.x + d, y + cg.mark_pos.y, 0, &cg.mark_char, cg.mark_font, ink, 1, NULL);
}
GlyphMetrics(gi, font, chr);
}
d += dx ? *dx++ : gi.width;
}
}
// ----------------------------
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());
}
END_UPP_NAMESPACE

View file

@ -1,379 +1,379 @@
#include "Draw.h"
#define LLOG(x)
NAMESPACE_UPP
CommonFontInfo GetFontInfoSys(Font font);
GlyphInfo GetGlyphInfoSys(Font font, int chr);
void GetStdFontSys(String& name, int& height);
Vector<FaceInfo> GetAllFacesSys();
bool Replace(Font fnt, int chr, Font& rfnt);
void Std(Font& font)
{
if(IsNull(font))
font = StdFont();
if(font.GetFace() == 0)
font.Face(GetStdFont().GetFace());
if(font.GetHeight() == 0)
font.Height(GetStdFont().GetHeight());
}
Size Font::StdFontSize;
Font Font::AStdFont;
INITBLOCK {
RichValue<Font>::Register();
}
const Vector<FaceInfo>& Font::List()
{
static Vector<FaceInfo> *q;
ONCELOCK {
static Vector<FaceInfo> x;
x = GetAllFacesSys();
q = &x;
}
return *q;
}
void sInitFonts()
{
Font::List();
GetStdFont();
}
INITBLOCK {
sInitFonts();
}
int Font::GetFaceCount()
{
return List().GetCount();
}
String Font::GetFaceName(int index)
{
if(index == 0)
return "STDFONT";
const Vector<FaceInfo>& l = List();
if(index >= 0 && index < l.GetCount())
return l[index].name;
return Null;
}
dword Font::GetFaceInfo(int index)
{
const Vector<FaceInfo>& l = List();
if(index >= 0 && index < l.GetCount())
return l[index].info;
return 0;
}
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 String& name) {
if(name == "STDFONT")
return 0;
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;
}
void Font::SyncStdFont()
{
DrawLock __;
StdFontSize = Size(AStdFont.GetAveWidth(), AStdFont().Bold().GetCy());
}
void Font::SetStdFont(Font font)
{
DrawLock __;
InitStdFont();
AStdFont = font;
SyncStdFont();
}
void Font::InitStdFont()
{
ONCELOCK {
DrawLock __;
List();
AStdFont = Arial(12);
String name;
int height = 0;
GetStdFontSys(name, height);
int q = FindFaceNameIndex(name);
if(q > 0) {
AStdFont = Font(q, max(height, 1));
SyncStdFont();
}
}
}
Font Font::GetStdFont()
{
InitStdFont();
return AStdFont;
}
Size Font::GetStdFontSize()
{
InitStdFont();
return StdFontSize;
}
Font StdFont()
{
return Font(0, 0);
}
int Font::GetHeight() const
{
return v.height || v.face ? v.height : GetStdFont().GetHeight();
}
String Font::GetFaceName() const {
if(IsNull()) return String();
if(GetFace() == 0)
return "STDFONT";
return GetFaceName(GetFace());
}
dword Font::GetFaceInfo() const {
if(IsNull()) return 0;
return GetFaceInfo(GetFace());
}
Font& Font::FaceName(const String& name) {
int n = FindFaceNameIndex(name);
Face(n < 0 ? 0xffff : n);
return *this;
}
void Font::Serialize(Stream& s) {
int version = 1;
s / version;
if(version >= 1) {
enum {
OLD_STDFONT, OLD_SCREEN_SERIF, OLD_SCREEN_SANS, OLD_SCREEN_FIXED,
OLD_ROMAN,
OLD_ARIAL,
OLD_COURIER,
};
int f = GetFace();
if(f > COURIER)
f = -1;
s / f;
String name;
if(f == OLD_ROMAN)
f = ROMAN;
if(f == OLD_ARIAL)
f = ARIAL;
if(f == OLD_COURIER)
f = COURIER;
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 % v.flags % v.height % v.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 + '>';
}
struct CharEntry {
int64 font;
GlyphInfo info;
word chr;
};
CharEntry fc_cache_global[4093];
bool IsNormal(Font font, int chr)
{
DrawLock __;
CharEntry& e = fc_cache_global[CombineHash(font.GetHashValue(), chr) % 4093];
if(e.font == font.AsInt64() || e.chr == chr)
return e.info.IsNormal();
return GetGlyphInfoSys(font, chr).IsNormal();
}
CharEntry GetGlyphEntry(Font font, int chr, unsigned hash)
{
DrawLock __;
CharEntry& e = fc_cache_global[hash % 4093];
if(e.font != font.AsInt64() || e.chr != chr) {
e.font = font.AsInt64();
e.chr = chr;
e.info = GetGlyphInfoSys(font, chr);
if(!e.info.IsNormal()) {
ComposedGlyph cg;
Font rfnt;
if(Compose(font, chr, cg)) {
e.info.lspc = -1;
e.info.rspc = cg.basic_char;
}
else
if(Replace(font, chr, rfnt)) {
e.info.lspc = rfnt.GetFace();
e.info.rspc = rfnt.GetHeight();
}
else
e.info.lspc = -2;
}
}
return e;
}
thread__ CharEntry fc_cache[512];
GlyphInfo GetGlyphInfo(Font font, int chr)
{
Std(font);
unsigned hash = CombineHash(font.GetHashValue(), chr);
CharEntry& e = fc_cache[hash & 511];
if(e.font != font.AsInt64() || e.chr != chr)
e = GetGlyphEntry(font, chr, hash);
return e.info;
}
bool Font::IsNormal(int ch) const
{
return GetGlyphInfo(*this, ch).IsNormal();
}
bool Font::IsComposed(int ch) const
{
return GetGlyphInfo(*this, ch).IsComposed();
}
bool Font::IsReplaced(int ch) const
{
return GetGlyphInfo(*this, ch).IsReplaced();
}
bool Font::IsMissing(int ch) const
{
return GetGlyphInfo(*this, ch).IsMissing();
}
int Font::HasChar(int ch) const
{
return !GetGlyphInfo(*this, ch).IsMissing();
}
void GlyphMetrics(GlyphInfo& f, Font font, int chr)
{
if(f.IsReplaced())
f = GetGlyphInfo(font().Face(f.lspc).Height(f.rspc), chr);
if(f.IsComposed()) {
f = GetGlyphInfo(font, f.rspc);
if(f.IsComposedLM())
f.rspc += f.width / 2;
}
}
GlyphInfo GetGlyphMetrics(Font font, int chr)
{
GlyphInfo f = GetGlyphInfo(font, chr);
if(f.IsMissing())
f = GetGlyphInfo(font, '?');
GlyphMetrics(f, font, chr);
return f;
}
struct FontEntry {
CommonFontInfo info;
int64 font;
};
thread__ FontEntry fi_cache[64];
const CommonFontInfo& GetFontInfo(Font font)
{
Std(font);
unsigned hash = font.GetHashValue() & 63;
FontEntry& e = fi_cache[hash];
if(e.font != font.AsInt64()) {
DrawLock __;
e.font = font.AsInt64();
e.info = GetFontInfoSys(font);
}
return e.info;
}
int Font::GetWidth(int c) const {
return GetGlyphMetrics(*this, c).width;
}
int Font::GetLeftSpace(int c) const {
return GetGlyphMetrics(*this, c).lspc;
}
int Font::GetRightSpace(int c) const {
return GetGlyphMetrics(*this, c).rspc;
}
thread__ int64 lastFiFont = INT_MIN;
thread__ CommonFontInfo lastFontInfo;
thread__ int64 lastStdFont = INT_MIN;
const CommonFontInfo& Font::Fi() const
{
if(lastStdFont != AStdFont.AsInt64()) {
lastFiFont = INT_MIN;
lastStdFont = AStdFont.AsInt64();
}
if(AsInt64() == lastFiFont)
return lastFontInfo;
lastFontInfo = GetFontInfo(*this);
lastFiFont = AsInt64();
return lastFontInfo;
}
FontInfo Font::Info() const
{
FontInfo h;
h.font = *this;
return h;
}
END_UPP_NAMESPACE
#include "Draw.h"
#define LLOG(x)
NAMESPACE_UPP
CommonFontInfo GetFontInfoSys(Font font);
GlyphInfo GetGlyphInfoSys(Font font, int chr);
void GetStdFontSys(String& name, int& height);
Vector<FaceInfo> GetAllFacesSys();
bool Replace(Font fnt, int chr, Font& rfnt);
void Std(Font& font)
{
if(IsNull(font))
font = StdFont();
if(font.GetFace() == 0)
font.Face(GetStdFont().GetFace());
if(font.GetHeight() == 0)
font.Height(GetStdFont().GetHeight());
}
Size Font::StdFontSize;
Font Font::AStdFont;
INITBLOCK {
RichValue<Font>::Register();
}
const Vector<FaceInfo>& Font::List()
{
static Vector<FaceInfo> *q;
ONCELOCK {
static Vector<FaceInfo> x;
x = GetAllFacesSys();
q = &x;
}
return *q;
}
void sInitFonts()
{
Font::List();
GetStdFont();
}
INITBLOCK {
sInitFonts();
}
int Font::GetFaceCount()
{
return List().GetCount();
}
String Font::GetFaceName(int index)
{
if(index == 0)
return "STDFONT";
const Vector<FaceInfo>& l = List();
if(index >= 0 && index < l.GetCount())
return l[index].name;
return Null;
}
dword Font::GetFaceInfo(int index)
{
const Vector<FaceInfo>& l = List();
if(index >= 0 && index < l.GetCount())
return l[index].info;
return 0;
}
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 String& name) {
if(name == "STDFONT")
return 0;
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;
}
void Font::SyncStdFont()
{
DrawLock __;
StdFontSize = Size(AStdFont.GetAveWidth(), AStdFont().Bold().GetCy());
}
void Font::SetStdFont(Font font)
{
DrawLock __;
InitStdFont();
AStdFont = font;
SyncStdFont();
}
void Font::InitStdFont()
{
ONCELOCK {
DrawLock __;
List();
AStdFont = Arial(12);
String name;
int height = 0;
GetStdFontSys(name, height);
int q = FindFaceNameIndex(name);
if(q > 0) {
AStdFont = Font(q, max(height, 1));
SyncStdFont();
}
}
}
Font Font::GetStdFont()
{
InitStdFont();
return AStdFont;
}
Size Font::GetStdFontSize()
{
InitStdFont();
return StdFontSize;
}
Font StdFont()
{
return Font(0, 0);
}
int Font::GetHeight() const
{
return v.height || v.face ? v.height : GetStdFont().GetHeight();
}
String Font::GetFaceName() const {
if(IsNull()) return String();
if(GetFace() == 0)
return "STDFONT";
return GetFaceName(GetFace());
}
dword Font::GetFaceInfo() const {
if(IsNull()) return 0;
return GetFaceInfo(GetFace());
}
Font& Font::FaceName(const String& name) {
int n = FindFaceNameIndex(name);
Face(n < 0 ? 0xffff : n);
return *this;
}
void Font::Serialize(Stream& s) {
int version = 1;
s / version;
if(version >= 1) {
enum {
OLD_STDFONT, OLD_SCREEN_SERIF, OLD_SCREEN_SANS, OLD_SCREEN_FIXED,
OLD_ROMAN,
OLD_ARIAL,
OLD_COURIER,
};
int f = GetFace();
if(f > COURIER)
f = -1;
s / f;
String name;
if(f == OLD_ROMAN)
f = ROMAN;
if(f == OLD_ARIAL)
f = ARIAL;
if(f == OLD_COURIER)
f = COURIER;
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 % v.flags % v.height % v.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 + '>';
}
struct CharEntry {
int64 font;
GlyphInfo info;
word chr;
};
CharEntry fc_cache_global[4093];
bool IsNormal(Font font, int chr)
{
DrawLock __;
CharEntry& e = fc_cache_global[CombineHash(font.GetHashValue(), chr) % 4093];
if(e.font == font.AsInt64() || e.chr == chr)
return e.info.IsNormal();
return GetGlyphInfoSys(font, chr).IsNormal();
}
CharEntry GetGlyphEntry(Font font, int chr, unsigned hash)
{
DrawLock __;
CharEntry& e = fc_cache_global[hash % 4093];
if(e.font != font.AsInt64() || e.chr != chr) {
e.font = font.AsInt64();
e.chr = chr;
e.info = GetGlyphInfoSys(font, chr);
if(!e.info.IsNormal()) {
ComposedGlyph cg;
Font rfnt;
if(Compose(font, chr, cg)) {
e.info.lspc = -1;
e.info.rspc = cg.basic_char;
}
else
if(Replace(font, chr, rfnt)) {
e.info.lspc = rfnt.GetFace();
e.info.rspc = rfnt.GetHeight();
}
else
e.info.lspc = -2;
}
}
return e;
}
thread__ CharEntry fc_cache[512];
GlyphInfo GetGlyphInfo(Font font, int chr)
{
Std(font);
unsigned hash = CombineHash(font.GetHashValue(), chr);
CharEntry& e = fc_cache[hash & 511];
if(e.font != font.AsInt64() || e.chr != chr)
e = GetGlyphEntry(font, chr, hash);
return e.info;
}
bool Font::IsNormal(int ch) const
{
return GetGlyphInfo(*this, ch).IsNormal();
}
bool Font::IsComposed(int ch) const
{
return GetGlyphInfo(*this, ch).IsComposed();
}
bool Font::IsReplaced(int ch) const
{
return GetGlyphInfo(*this, ch).IsReplaced();
}
bool Font::IsMissing(int ch) const
{
return GetGlyphInfo(*this, ch).IsMissing();
}
int Font::HasChar(int ch) const
{
return !GetGlyphInfo(*this, ch).IsMissing();
}
void GlyphMetrics(GlyphInfo& f, Font font, int chr)
{
if(f.IsReplaced())
f = GetGlyphInfo(font().Face(f.lspc).Height(f.rspc), chr);
if(f.IsComposed()) {
f = GetGlyphInfo(font, f.rspc);
if(f.IsComposedLM())
f.rspc += f.width / 2;
}
}
GlyphInfo GetGlyphMetrics(Font font, int chr)
{
GlyphInfo f = GetGlyphInfo(font, chr);
if(f.IsMissing())
f = GetGlyphInfo(font, '?');
GlyphMetrics(f, font, chr);
return f;
}
struct FontEntry {
CommonFontInfo info;
int64 font;
};
thread__ FontEntry fi_cache[64];
const CommonFontInfo& GetFontInfo(Font font)
{
Std(font);
unsigned hash = font.GetHashValue() & 63;
FontEntry& e = fi_cache[hash];
if(e.font != font.AsInt64()) {
DrawLock __;
e.font = font.AsInt64();
e.info = GetFontInfoSys(font);
}
return e.info;
}
int Font::GetWidth(int c) const {
return GetGlyphMetrics(*this, c).width;
}
int Font::GetLeftSpace(int c) const {
return GetGlyphMetrics(*this, c).lspc;
}
int Font::GetRightSpace(int c) const {
return GetGlyphMetrics(*this, c).rspc;
}
thread__ int64 lastFiFont = INT_MIN;
thread__ CommonFontInfo lastFontInfo;
thread__ int64 lastStdFont = INT_MIN;
const CommonFontInfo& Font::Fi() const
{
if(lastStdFont != AStdFont.AsInt64()) {
lastFiFont = INT_MIN;
lastStdFont = AStdFont.AsInt64();
}
if(AsInt64() == lastFiFont)
return lastFontInfo;
lastFontInfo = GetFontInfo(*this);
lastFiFont = AsInt64();
return lastFontInfo;
}
FontInfo Font::Info() const
{
FontInfo h;
h.font = *this;
return h;
}
END_UPP_NAMESPACE

View file

@ -26,8 +26,6 @@ bool sInitFt(void)
return FT_Init_FreeType(&sFTlib) == 0;
}
int gtk_dpi = 96;
FcPattern *CreateFcPattern(Font font)
{
LTIMING("CreateXftFont");
@ -39,12 +37,11 @@ FcPattern *CreateFcPattern(Font font)
FcPatternAddString(p, FC_FAMILY, (FcChar8*)~face);
FcPatternAddInteger(p, FC_SLANT, font.IsItalic() ? 110 : 0);
FcPatternAddInteger(p, FC_PIXEL_SIZE, hg);
FcPatternAddInteger(p, FC_DPI, gtk_dpi);
FcPatternAddInteger(p, FC_WEIGHT, font.IsBold() ? 200 : 100);
FcPatternAddBool(p, FC_MINSPACE, 1);
FcResult result;
FcConfigSubstitute(0, p, FcMatchPattern);
FcDefaultSubstitute(p);
FcResult result;
FcPattern *m = FcFontMatch(0, p, &result);
FcPatternDestroy(p);
return m;
@ -75,7 +72,7 @@ FT_Face CreateFTFace(const FcPattern *pattern, String *rpath) {
FT_F26Dot6 ysize = (FT_F26Dot6) (dsize * 64.0);
FT_F26Dot6 xsize = (FT_F26Dot6) (dsize * aspect * 64.0);
if(FT_New_Face (sFTlib, (const char *)filename, 0, &face))
if(FT_New_Face(sFTlib, (const char *)filename, 0, &face))
return NULL;
FT_Set_Char_Size(face, xsize, ysize, 0, 0);
@ -90,25 +87,35 @@ struct FtFaceEntry {
String path;
};
static FtFaceEntry ft_cache[FONTCACHE];
void ClearFtFaceCache()
{
for(int i = 0; i < FONTCACHE; i++)
ft_cache[i].font.Height(-30000);
}
FT_Face (*FTFaceXft)(Font fnt, String *rpath);
FT_Face FTFace(Font fnt, String *rpath = NULL)
{
LTIMING("FTFace");
static FtFaceEntry cache[FONTCACHE];
if(FTFaceXft)
return (*FTFaceXft)(fnt, rpath);
ONCELOCK {
for(int i = 0; i < FONTCACHE; i++)
cache[i].font.Height(-30000);
ClearFtFaceCache();
}
FtFaceEntry be;
be = cache[0];
be = ft_cache[0];
for(int i = 0; i < FONTCACHE; i++) {
FtFaceEntry e = cache[i];
FtFaceEntry e = ft_cache[i];
if(i)
cache[i] = be;
ft_cache[i] = be;
if(e.font == fnt) {
if(rpath)
*rpath = e.path;
if(i)
cache[0] = e;
ft_cache[0] = e;
return e.face;
}
be = e;
@ -122,16 +129,19 @@ FT_Face FTFace(Font fnt, String *rpath = NULL)
FcPattern *p = CreateFcPattern(fnt);
be.face = CreateFTFace(p, &be.path);
FcPatternDestroy(p);
cache[0] = be;
ft_cache[0] = be;
if(rpath)
*rpath = be.path;
return be.face;
}
CommonFontInfo (*GetFontInfoSysXft)(Font font);
CommonFontInfo GetFontInfoSys(Font font)
{
if(GetFontInfoSysXft)
return (*GetFontInfoSysXft)(font);
CommonFontInfo fi;
String path;
FT_Face face = FTFace(font, &path);
if(face) {
@ -159,9 +169,13 @@ CommonFontInfo GetFontInfoSys(Font font)
#define TRUNC(x) ((x) >> 6)
#define ROUND(x) (((x)+32) & -64)
GlyphInfo (*GetGlyphInfoSysXft)(Font font, int chr);
GlyphInfo GetGlyphInfoSys(Font font, int chr)
{
LTIMING("GetGlyphInfoSys");
if(GetGlyphInfoSysXft)
return (*GetGlyphInfoSysXft)(font, chr);
GlyphInfo gi;
FT_Face face = FTFace(font, NULL);
gi.lspc = gi.rspc = 0;

View file

@ -1,156 +1,155 @@
//----------------------------------------------------------------------------
// Anti-Grain Geometry - Version 2.4
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all coM_PIes.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
//----------------------------------------------------------------------------
// Contact: mcseem@antigrain.com
// mcseemagg@yahoo.com
// http://www.antigrain.com
//----------------------------------------------------------------------------
// Recycled for U++ by Miroslav Fidler 2008
#include "Painter.h"
#ifdef PLATFORM_POSIX
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
NAMESPACE_UPP
FT_Face FTFace(Font fnt, String *rpath);
static inline double ft_dbl(int p)
{
return double(p) / 64.0;
}
bool RenderOutline(const FT_Outline& outline, Painter& path, double xx, double yy)
{
FT_Vector v_last;
FT_Vector v_control;
FT_Vector v_start;
FT_Vector* point;
FT_Vector* limit;
char* tags;
int n; // index of contour in outline
char tag; // current point's state
int first = 0; // index of first point in contour
for(n = 0; n < outline.n_contours; n++) {
int last = outline.contours[n];
limit = outline.points + last;
v_start = outline.points[first];
v_last = outline.points[last];
v_control = v_start;
point = outline.points + first;
tags = outline.tags + first;
tag = FT_CURVE_TAG(tags[0]);
if(tag == FT_CURVE_TAG_CUBIC) return false;
if(tag == FT_CURVE_TAG_CONIC) {
if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON) {
// start at last point if it is on the curve
v_start = v_last;
limit--;
}
else {
// if both first and last points are conic,
// start at their middle and record its position
// for closure
v_start.x = (v_start.x + v_last.x) / 2;
v_start.y = (v_start.y + v_last.y) / 2;
v_last = v_start;
}
point--;
tags--;
}
path.Move(ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy);
while(point < limit) {
point++;
tags++;
tag = FT_CURVE_TAG(tags[0]);
switch(tag) {
case FT_CURVE_TAG_ON:
path.Line(ft_dbl(point->x) + xx, -ft_dbl(point->y) + yy);
continue;
case FT_CURVE_TAG_CONIC:
v_control.x = point->x;
v_control.y = point->y;
Do_Conic:
if(point < limit) {
FT_Vector vec;
FT_Vector v_middle;
point++;
tags++;
tag = FT_CURVE_TAG(tags[0]);
vec.x = point->x;
vec.y = point->y;
if(tag == FT_CURVE_TAG_ON) {
path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy,
ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy);
continue;
}
if(tag != FT_CURVE_TAG_CONIC) return false;
v_middle.x = (v_control.x + vec.x) / 2;
v_middle.y = (v_control.y + vec.y) / 2;
path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy,
ft_dbl(v_middle.x) + xx, -ft_dbl(v_middle.y) + yy);
v_control = vec;
goto Do_Conic;
}
path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy,
ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy);
goto Close;
default:
FT_Vector vec1, vec2;
if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC)
return false;
vec1.x = point[0].x;
vec1.y = point[0].y;
vec2.x = point[1].x;
vec2.y = point[1].y;
point += 2;
tags += 2;
if(point <= limit) {
FT_Vector vec;
vec.x = point->x;
vec.y = point->y;
path.Cubic(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy,
ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy,
ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy);
continue;
}
path.Cubic(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy,
ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy,
ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy);
goto Close;
}
}
Close:
path.Close();
first = last + 1;
}
return true;
}
void PaintCharacterSys(Painter& sw, double x, double y, int ch, Font fnt)
{
DrawLock __;
PAINTER_TIMING("CharacterOp");
FT_Face face = FTFace(fnt, NULL);
int glyph_index = FT_Get_Char_Index(face, ch);
if(glyph_index && FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) == 0)
RenderOutline(face->glyph->outline, sw, x, y + fnt.GetAscent());
sw.EvenOdd(true);
}
END_UPP_NAMESPACE
#endif
//----------------------------------------------------------------------------
// Anti-Grain Geometry - Version 2.4
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all coM_PIes.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
//----------------------------------------------------------------------------
// Contact: mcseem@antigrain.com
// mcseemagg@yahoo.com
// http://www.antigrain.com
//----------------------------------------------------------------------------
// Recycled for U++ by Miroslav Fidler 2008
#include "Painter.h"
#ifdef PLATFORM_POSIX
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
NAMESPACE_UPP
FT_Face FTFace(Font fnt, String *rpath);
static inline double ft_dbl(int p)
{
return double(p) / 64.0;
}
bool RenderOutline(const FT_Outline& outline, Painter& path, double xx, double yy)
{
FT_Vector v_last;
FT_Vector v_control;
FT_Vector v_start;
FT_Vector* point;
FT_Vector* limit;
char* tags;
int n; // index of contour in outline
char tag; // current point's state
int first = 0; // index of first point in contour
for(n = 0; n < outline.n_contours; n++) {
int last = outline.contours[n];
limit = outline.points + last;
v_start = outline.points[first];
v_last = outline.points[last];
v_control = v_start;
point = outline.points + first;
tags = outline.tags + first;
tag = FT_CURVE_TAG(tags[0]);
if(tag == FT_CURVE_TAG_CUBIC) return false;
if(tag == FT_CURVE_TAG_CONIC) {
if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON) {
// start at last point if it is on the curve
v_start = v_last;
limit--;
}
else {
// if both first and last points are conic,
// start at their middle and record its position
// for closure
v_start.x = (v_start.x + v_last.x) / 2;
v_start.y = (v_start.y + v_last.y) / 2;
v_last = v_start;
}
point--;
tags--;
}
path.Move(ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy);
while(point < limit) {
point++;
tags++;
tag = FT_CURVE_TAG(tags[0]);
switch(tag) {
case FT_CURVE_TAG_ON:
path.Line(ft_dbl(point->x) + xx, -ft_dbl(point->y) + yy);
continue;
case FT_CURVE_TAG_CONIC:
v_control.x = point->x;
v_control.y = point->y;
Do_Conic:
if(point < limit) {
FT_Vector vec;
FT_Vector v_middle;
point++;
tags++;
tag = FT_CURVE_TAG(tags[0]);
vec.x = point->x;
vec.y = point->y;
if(tag == FT_CURVE_TAG_ON) {
path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy,
ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy);
continue;
}
if(tag != FT_CURVE_TAG_CONIC) return false;
v_middle.x = (v_control.x + vec.x) / 2;
v_middle.y = (v_control.y + vec.y) / 2;
path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy,
ft_dbl(v_middle.x) + xx, -ft_dbl(v_middle.y) + yy);
v_control = vec;
goto Do_Conic;
}
path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy,
ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy);
goto Close;
default:
FT_Vector vec1, vec2;
if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC)
return false;
vec1.x = point[0].x;
vec1.y = point[0].y;
vec2.x = point[1].x;
vec2.y = point[1].y;
point += 2;
tags += 2;
if(point <= limit) {
FT_Vector vec;
vec.x = point->x;
vec.y = point->y;
path.Cubic(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy,
ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy,
ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy);
continue;
}
path.Cubic(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy,
ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy,
ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy);
goto Close;
}
}
Close:
path.Close();
first = last + 1;
}
return true;
}
void PaintCharacterSys(Painter& sw, double x, double y, int ch, Font fnt)
{
DrawLock __;
PAINTER_TIMING("CharacterOp");
FT_Face face = FTFace(fnt, NULL);
int glyph_index = FT_Get_Char_Index(face, ch);
if(glyph_index && FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) == 0)
RenderOutline(face->glyph->outline, sw, x, y + fnt.GetAscent());
sw.EvenOdd(true);
}
END_UPP_NAMESPACE
#endif

View file

@ -267,7 +267,7 @@ PdfDraw::OutlineInfo PdfDraw::GetOutlineInfo(Font fnt)
}
}
#endif
#ifdef PLATFORM_X11
#ifdef PLATFORM_POSIX
FontInfo fi = fnt.Info();
String fn = fi.GetFileName();
String ext = ToLower(GetFileExt(fn));
@ -299,7 +299,7 @@ void PdfDraw::DrawTextOp(int x, int y, int angle, const wchar *s, Font fnt,
#ifdef PLATFORM_WIN32
int fh = ff.GetHeight() - ff.GetInternal();//TODO
#endif
#ifdef PLATFORM_X11
#ifdef PLATFORM_POSIX
int fh = fnt.GetHeight();
#endif
OutlineInfo of = GetOutlineInfo(fnt);

View file

@ -1,7 +1,7 @@
#ifndef _PdfDraw_icpp_init_stub
#define _PdfDraw_icpp_init_stub
#include "Draw/init"
#define BLITZ_INDEX__ F2EB858D15FF91342F7F9648AA934C9C8
#define BLITZ_INDEX__ FA6D939FEC0881A8606B7621CDFC33471
#include "PdfReport.icpp"
#undef BLITZ_INDEX__
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,364 +1,364 @@
#include "usvn.h"
bool CheckSvn()
{
String h;
if(Sys("svn", h) >= 0)
return true;
#ifdef PLATFORM_WIN32
Exclamation("Unable to execute svn.exe!&"
"You can download svn client here: [^http://www.sliksvn.com/en/download^ http://www.sliksvn.com/en/download]");
#else
Exclamation("Unable to execute 'svn' binary!&Please install svn client.");
#endif
return false;
}
SvnSync::SvnSync()
{
CtrlLayoutOKCancel(*this, "SvnSynchronize SVN repositories");
list.AddIndex();
list.AddIndex();
list.AddColumn("Action");
list.AddColumn("Path");
list.AddColumn("Changes");
list.ColumnWidths("170 500 100");
list.NoCursor().EvenRowColor();
list.SetLineCy(max(Draw::GetStdFontCy(), 20));
list.WhenLeftClick = THISBACK(Diff);
Sizeable().Zoomable();
setup <<= THISBACK(Setup);
BackPaint();
}
void SvnSync::Setup()
{
works.Execute();
SyncList();
}
int CharFilterSvnMsg(int c)
{
return c >= 32 && c < 128 && c != '\"' ? c : 0;
}
void SvnSync::SyncList()
{
list.Clear();
for(int i = 0; i < works.GetCount(); i++) {
SvnWork w = works[i];
String path = GetFullPath(w.working);
list.Add(REPOSITORY, path,
AttrText("Working directory").SetFont(StdFont().Bold()).Ink(White).Paper(Blue),
AttrText(path).SetFont(Arial(20).Bold()).Paper(Blue).Ink(White),
AttrText("").SetFont(Arial(20).Bold()).Paper(Blue).Ink(White));
list.SetLineCy(list.GetCount() - 1, 26);
Vector<String> ln = Split(Sys("svn status " + path), CharFilterCrLf);
bool actions = false;
for(int pass = 0; pass < 2; pass++)
for(int i = 0; i < ln.GetCount(); i++) {
String h = ln[i];
if(h.GetCount() > 7) {
String file = h.Mid(7);
if(IsFullPath(file)) {
actions = true;
h.Trim(7);
bool simple = h.Mid(1, 6) == " ";
int action = simple ? String("MC?!~").Find(h[0]) : -1;
if(h == " S ")
action = REPLACE;
String an;
Color color;
if(action < 0) {
color = Black;
if(simple && h[0] == 'A')
an = "svn add";
else
if(simple && h[0] == 'D')
an = "svn delete";
else {
an = h.Mid(0, 7);
color = Gray;
}
}
else {
int q = file.ReverseFind('.');
if(action == ADD && q >= 0 && (file.Mid(q + 1) == "mine" ||
file[q + 1] == 'r' && IsDigit(file[q + 2]))
&& FileExists(file.Mid(0, q))) {
action = DELETEC;
an = "Delete";
color = Black;
}
else {
static const char *as[] = {
"Modify", "Resolved", "Add", "Remove", "Replace"
};
static Color c[] = { LtBlue, Magenta, Green, LtRed, LtMagenta };
an = as[action];
color = c[action];
}
}
if(pass == action < 0) {
int ii = list.GetCount();
list.Add(action, file,
action < 0 ? Value(AttrText(an).Ink(color)) : Value(true),
AttrText(" " + file.Mid(path.GetCount() + 1)).Ink(color));
if(action >= 0) {
list.SetCtrl(ii, 0, revert.Add().SetLabel("Revert\n" + an).NoWantFocus());
Ctrl& b = diff.Add().SetLabel("Changes..").SizePos().NoWantFocus();
b <<= THISBACK1(DoDiff, ii);
list.SetCtrl(ii, 2, b);
}
}
}
}
}
if(actions) {
list.Add(MESSAGE, Null, AttrText("Commit message:").SetFont(StdFont().Bold()));
list.SetLineCy(list.GetCount() - 1, (3 * EditField::GetStdHeight()) + 4);
list.SetCtrl(list.GetCount() - 1, 1, message.Add().SetFilter(CharFilterSvnMsg).VSizePos(2, 2).HSizePos());
int q = msgmap.Find(w.working);
if(q >= 0) {
message.Top() <<= msgmap[q];
msgmap.Unlink(q);
}
}
else
list.Add(-1, Null, "", AttrText("Nothing to do").SetFont(StdFont().Italic()));
}
}
void SvnSync::DoDiff(int ii)
{
String f = list.Get(ii, 1);
if(!IsNull(f))
RunSvnDiff(f);
}
void SvnSync::Diff()
{
int cr = list.GetClickRow();
if(cr >= 0)
DoDiff(cr);
}
#ifdef PLATFORM_WIN32
void sDeleteFolderDeep(const char *dir)
{
{
FindFile ff(AppendFileName(dir, "*.*"));
while(ff) {
String name = ff.GetName();
String p = AppendFileName(dir, name);
if(ff.IsFile()) {
SetFileAttributes(p, GetFileAttributes(p) & ~FILE_ATTRIBUTE_READONLY);
FileDelete(p);
}
else
if(ff.IsFolder())
sDeleteFolderDeep(p);
ff.Next();
}
}
DirectoryDelete(dir);
}
#else
void sDeleteFolderDeep(const char *path)
{
DeleteFolderDeep(path);
}
#endif
void SvnDel(const char *path)
{
FindFile ff(AppendFileName(path, "*.*"));
while(ff) {
if(ff.IsFolder()) {
String dir = AppendFileName(path, ff.GetName());
if(ff.GetName() == ".svn")
sDeleteFolderDeep(dir);
else
SvnDel(dir);
}
ff.Next();
}
}
void SvnSync::Dir(const char *dir)
{
setup.Hide();
works.Add(dir, Null, Null);
}
void SvnSync::Perform()
{
if(!CheckSvn())
return;
const Vector<String>& cl = CommandLine();
if(cl.GetCount())
for(int i = 0; i < cl.GetCount(); i++) {
if(cl[i] == "-") {
works.Load(LoadFile(ConfigFile("svnworks")));
DoSync();
SaveFile(ConfigFile("svnworks"), works.Save());
return;
}
String d = GetFullPath(cl[i]);
if(!DirectoryExists(cl[i])) {
Cerr() << cl[i] << " not a directory\n";
SetExitCode(1);
return;
}
works.Add(d, "", "");
}
else
works.Add(GetCurrentDirectory(), "", "");
setup.Hide();
DoSync();
}
void MoveSvn(const String& path, const String& tp)
{
FindFile ff(AppendFileName(path, "*.*"));
while(ff) {
String nm = ff.GetName();
String s = AppendFileName(path, nm);
String t = AppendFileName(tp, nm);
if(ff.IsFolder())
if(nm == ".svn")
FileMove(s, t);
else
MoveSvn(s, t);
ff.Next();
}
}
void SvnSync::DoSync()
{
SyncList();
msgmap.Sweep();
again:
if(Execute() != IDOK || list.GetCount() == 0) {
int repoi = 0;
for(int i = 0; i < list.GetCount(); i++)
if(list.Get(i, 0) == MESSAGE)
msgmap.GetAdd(works[repoi++].working) = list.Get(i, 3);
return;
}
bool changes = false;
for(int i = 0; i < list.GetCount(); i++) {
int action = list.Get(i, 0);
Value v = list.Get(i, 2);
if(action == MESSAGE) {
if(changes && IsNull(list.Get(i, 3))
&& !PromptYesNo("Commit message is empty.&Do you want to continue?"))
goto again;
changes = false;
}
else if(action != REPOSITORY && IsNumber(v) && (int)v)
changes = true;
}
SysConsole sys;
int repoi = 0;
int l = 0;
bool commit = false;
while(l < list.GetCount()) {
SvnWork w = works[repoi++];
l++;
String message;
while(l < list.GetCount()) {
int action = list.Get(l, 0);
String path = list.Get(l, 1);
if(action == MESSAGE && commit) {
String msg = list.Get(l, 3);
if(sys.CheckSystem(SvnCmd("commit", w).Cat() << w.working << " -m \"" << msg << "\""))
msgmap.GetAdd(w.working) = msg;
l++;
break;
}
if(action == REPOSITORY)
break;
Value v = list.Get(l, 2);
if(IsNumber(v) && (int)v == 0) {
if(action == REPLACE || action == ADD)
DeleteFolderDeep(path);
if(action != ADD)
sys.CheckSystem("svn revert " + path);
}
else {
commit = true;
switch(action) {
case ADD:
SvnDel(path);
sys.CheckSystem("svn add --force " + path);
break;
case REMOVE:
sys.CheckSystem("svn delete " + path);
break;
case CONFLICT:
sys.CheckSystem("svn resolved " + path);
break;
case REPLACE: {
SvnDel(path);
String tp = AppendFileName(GetFileFolder(path), Format(Uuid::Create()));
FileMove(path, tp);
sys.CheckSystem(SvnCmd("update", w).Cat() << ' ' << path);
MoveSvn(path, tp);
sDeleteFolderDeep(path);
FileMove(tp, path);
Vector<String> ln = Split(Sys("svn status " + path), CharFilterCrLf);
for(int l = 0; l < ln.GetCount(); l++) {
String h = ln[l];
if(h.GetCount() > 7) {
String file = h.Mid(7);
if(IsFullPath(file)) {
h.Trim(7);
if(h == "? ")
sys.CheckSystem("svn add --force " + file);
if(h == "! ")
sys.CheckSystem("svn delete " + file);
}
}
}
}
break;
case DELETEC:
FileDelete(path);
break;
}
}
l++;
}
sys.CheckSystem(SvnCmd("update", w).Cat() << w.working);
}
sys.Perform();
}
void SvnSync::SetMsgs(const String& s)
{
LoadFromString(msgmap, s);
}
String SvnSync::GetMsgs()
{
return StoreAsString(msgmap);
}
bool IsSvnDir(const String& p)
{
return DirectoryExists(AppendFileName(p, ".svn")) || DirectoryExists(AppendFileName(p, "_svn"));
}
#ifdef flagMAIN
GUI_APP_MAIN
{
if(!CheckSvn())
return;
SvnSync ss;
String mp = ConfigFile("usvn.msg");
ss.SetMsgs(LoadFile(mp));
ss.Perform();
SaveFile(mp, ss.GetMsgs());
}
#endif
#include "usvn.h"
bool CheckSvn()
{
String h;
if(Sys("svn", h) >= 0)
return true;
#ifdef PLATFORM_WIN32
Exclamation("Unable to execute svn.exe!&"
"You can download svn client here: [^http://www.sliksvn.com/en/download^ http://www.sliksvn.com/en/download]");
#else
Exclamation("Unable to execute 'svn' binary!&Please install svn client.");
#endif
return false;
}
SvnSync::SvnSync()
{
CtrlLayoutOKCancel(*this, "SvnSynchronize SVN repositories");
list.AddIndex();
list.AddIndex();
list.AddColumn("Action");
list.AddColumn("Path");
list.AddColumn("Changes");
list.ColumnWidths("170 500 100");
list.NoCursor().EvenRowColor();
list.SetLineCy(max(Draw::GetStdFontCy(), 20));
list.WhenLeftClick = THISBACK(Diff);
Sizeable().Zoomable();
setup <<= THISBACK(Setup);
BackPaint();
}
void SvnSync::Setup()
{
works.Execute();
SyncList();
}
int CharFilterSvnMsg(int c)
{
return c >= 32 && c < 128 && c != '\"' ? c : 0;
}
void SvnSync::SyncList()
{
list.Clear();
for(int i = 0; i < works.GetCount(); i++) {
SvnWork w = works[i];
String path = GetFullPath(w.working);
list.Add(REPOSITORY, path,
AttrText("Working directory").SetFont(StdFont().Bold()).Ink(White).Paper(Blue),
AttrText(path).SetFont(Arial(20).Bold()).Paper(Blue).Ink(White),
AttrText("").SetFont(Arial(20).Bold()).Paper(Blue).Ink(White));
list.SetLineCy(list.GetCount() - 1, 26);
Vector<String> ln = Split(Sys("svn status " + path), CharFilterCrLf);
bool actions = false;
for(int pass = 0; pass < 2; pass++)
for(int i = 0; i < ln.GetCount(); i++) {
String h = ln[i];
if(h.GetCount() > 7) {
String file = TrimLeft(h.Mid(7));
if(IsFullPath(file)) {
actions = true;
h.Trim(7);
bool simple = h.Mid(1, 6) == " ";
int action = simple ? String("MC?!~").Find(h[0]) : -1;
if(h == " S ")
action = REPLACE;
String an;
Color color;
if(action < 0) {
color = Black;
if(simple && h[0] == 'A')
an = "svn add";
else
if(simple && h[0] == 'D')
an = "svn delete";
else {
an = h.Mid(0, 7);
color = Gray;
}
}
else {
int q = file.ReverseFind('.');
if(action == ADD && q >= 0 && (file.Mid(q + 1) == "mine" ||
file[q + 1] == 'r' && IsDigit(file[q + 2]))
&& FileExists(file.Mid(0, q))) {
action = DELETEC;
an = "Delete";
color = Black;
}
else {
static const char *as[] = {
"Modify", "Resolved", "Add", "Remove", "Replace"
};
static Color c[] = { LtBlue, Magenta, Green, LtRed, LtMagenta };
an = as[action];
color = c[action];
}
}
if(pass == action < 0) {
int ii = list.GetCount();
list.Add(action, file,
action < 0 ? Value(AttrText(an).Ink(color)) : Value(true),
AttrText(" " + file.Mid(path.GetCount() + 1)).Ink(color));
if(action >= 0) {
list.SetCtrl(ii, 0, revert.Add().SetLabel("Revert\n" + an).NoWantFocus());
Ctrl& b = diff.Add().SetLabel("Changes..").SizePos().NoWantFocus();
b <<= THISBACK1(DoDiff, ii);
list.SetCtrl(ii, 2, b);
}
}
}
}
}
if(actions) {
list.Add(MESSAGE, Null, AttrText("Commit message:").SetFont(StdFont().Bold()));
list.SetLineCy(list.GetCount() - 1, (3 * EditField::GetStdHeight()) + 4);
list.SetCtrl(list.GetCount() - 1, 1, message.Add().SetFilter(CharFilterSvnMsg).VSizePos(2, 2).HSizePos());
int q = msgmap.Find(w.working);
if(q >= 0) {
message.Top() <<= msgmap[q];
msgmap.Unlink(q);
}
}
else
list.Add(-1, Null, "", AttrText("Nothing to do").SetFont(StdFont().Italic()));
}
}
void SvnSync::DoDiff(int ii)
{
String f = list.Get(ii, 1);
if(!IsNull(f))
RunSvnDiff(f);
}
void SvnSync::Diff()
{
int cr = list.GetClickRow();
if(cr >= 0)
DoDiff(cr);
}
#ifdef PLATFORM_WIN32
void sDeleteFolderDeep(const char *dir)
{
{
FindFile ff(AppendFileName(dir, "*.*"));
while(ff) {
String name = ff.GetName();
String p = AppendFileName(dir, name);
if(ff.IsFile()) {
SetFileAttributes(p, GetFileAttributes(p) & ~FILE_ATTRIBUTE_READONLY);
FileDelete(p);
}
else
if(ff.IsFolder())
sDeleteFolderDeep(p);
ff.Next();
}
}
DirectoryDelete(dir);
}
#else
void sDeleteFolderDeep(const char *path)
{
DeleteFolderDeep(path);
}
#endif
void SvnDel(const char *path)
{
FindFile ff(AppendFileName(path, "*.*"));
while(ff) {
if(ff.IsFolder()) {
String dir = AppendFileName(path, ff.GetName());
if(ff.GetName() == ".svn")
sDeleteFolderDeep(dir);
else
SvnDel(dir);
}
ff.Next();
}
}
void SvnSync::Dir(const char *dir)
{
setup.Hide();
works.Add(dir, Null, Null);
}
void SvnSync::Perform()
{
if(!CheckSvn())
return;
const Vector<String>& cl = CommandLine();
if(cl.GetCount())
for(int i = 0; i < cl.GetCount(); i++) {
if(cl[i] == "-") {
works.Load(LoadFile(ConfigFile("svnworks")));
DoSync();
SaveFile(ConfigFile("svnworks"), works.Save());
return;
}
String d = GetFullPath(cl[i]);
if(!DirectoryExists(cl[i])) {
Cerr() << cl[i] << " not a directory\n";
SetExitCode(1);
return;
}
works.Add(d, "", "");
}
else
works.Add(GetCurrentDirectory(), "", "");
setup.Hide();
DoSync();
}
void MoveSvn(const String& path, const String& tp)
{
FindFile ff(AppendFileName(path, "*.*"));
while(ff) {
String nm = ff.GetName();
String s = AppendFileName(path, nm);
String t = AppendFileName(tp, nm);
if(ff.IsFolder())
if(nm == ".svn")
FileMove(s, t);
else
MoveSvn(s, t);
ff.Next();
}
}
void SvnSync::DoSync()
{
SyncList();
msgmap.Sweep();
again:
if(Execute() != IDOK || list.GetCount() == 0) {
int repoi = 0;
for(int i = 0; i < list.GetCount(); i++)
if(list.Get(i, 0) == MESSAGE)
msgmap.GetAdd(works[repoi++].working) = list.Get(i, 3);
return;
}
bool changes = false;
for(int i = 0; i < list.GetCount(); i++) {
int action = list.Get(i, 0);
Value v = list.Get(i, 2);
if(action == MESSAGE) {
if(changes && IsNull(list.Get(i, 3))
&& !PromptYesNo("Commit message is empty.&Do you want to continue?"))
goto again;
changes = false;
}
else if(action != REPOSITORY && IsNumber(v) && (int)v)
changes = true;
}
SysConsole sys;
int repoi = 0;
int l = 0;
bool commit = false;
while(l < list.GetCount()) {
SvnWork w = works[repoi++];
l++;
String message;
while(l < list.GetCount()) {
int action = list.Get(l, 0);
String path = list.Get(l, 1);
if(action == MESSAGE && commit) {
String msg = list.Get(l, 3);
if(sys.CheckSystem(SvnCmd("commit", w).Cat() << w.working << " -m \"" << msg << "\""))
msgmap.GetAdd(w.working) = msg;
l++;
break;
}
if(action == REPOSITORY)
break;
Value v = list.Get(l, 2);
if(IsNumber(v) && (int)v == 0) {
if(action == REPLACE || action == ADD)
DeleteFolderDeep(path);
if(action != ADD)
sys.CheckSystem("svn revert " + path);
}
else {
commit = true;
switch(action) {
case ADD:
SvnDel(path);
sys.CheckSystem("svn add --force " + path);
break;
case REMOVE:
sys.CheckSystem("svn delete " + path);
break;
case CONFLICT:
sys.CheckSystem("svn resolved " + path);
break;
case REPLACE: {
SvnDel(path);
String tp = AppendFileName(GetFileFolder(path), Format(Uuid::Create()));
FileMove(path, tp);
sys.CheckSystem(SvnCmd("update", w).Cat() << ' ' << path);
MoveSvn(path, tp);
sDeleteFolderDeep(path);
FileMove(tp, path);
Vector<String> ln = Split(Sys("svn status " + path), CharFilterCrLf);
for(int l = 0; l < ln.GetCount(); l++) {
String h = ln[l];
if(h.GetCount() > 7) {
String file = h.Mid(7);
if(IsFullPath(file)) {
h.Trim(7);
if(h == "? ")
sys.CheckSystem("svn add --force " + file);
if(h == "! ")
sys.CheckSystem("svn delete " + file);
}
}
}
}
break;
case DELETEC:
FileDelete(path);
break;
}
}
l++;
}
sys.CheckSystem(SvnCmd("update", w).Cat() << w.working);
}
sys.Perform();
}
void SvnSync::SetMsgs(const String& s)
{
LoadFromString(msgmap, s);
}
String SvnSync::GetMsgs()
{
return StoreAsString(msgmap);
}
bool IsSvnDir(const String& p)
{
return DirectoryExists(AppendFileName(p, ".svn")) || DirectoryExists(AppendFileName(p, "_svn"));
}
#ifdef flagMAIN
GUI_APP_MAIN
{
if(!CheckSvn())
return;
SvnSync ss;
String mp = ConfigFile("usvn.msg");
ss.SetMsgs(LoadFile(mp));
ss.Perform();
SaveFile(mp, ss.GetMsgs());
}
#endif