From 467611ad53070565fbf1c08192004e365ef8a094 Mon Sep 17 00:00:00 2001 From: cxl Date: Mon, 19 Sep 2011 21:20:54 +0000 Subject: [PATCH] CtrlLib, Draw: Improved support for dark visual themes (corrected text color, icon inversion for toolbar / menubar) git-svn-id: svn://ultimatepp.org/upp/trunk@3887 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/Core/Color.cpp | 5 + uppsrc/CtrlLib/Bar.h | 6 + uppsrc/CtrlLib/Button.cpp | 2 +- uppsrc/CtrlLib/LabelBase.cpp | 45 +- uppsrc/CtrlLib/LabelBase.h | 7 + uppsrc/CtrlLib/MenuBar.cpp | 1 + uppsrc/CtrlLib/MenuImp.h | 2 + uppsrc/CtrlLib/MenuItem.cpp | 8 +- uppsrc/CtrlLib/Static.cpp | 4 +- uppsrc/CtrlLib/Switch.cpp | 2 +- uppsrc/CtrlLib/ToolBar.cpp | 2 + uppsrc/CtrlLib/ToolButton.cpp | 638 +++++++-------- uppsrc/CtrlLib/init | 2 +- uppsrc/Draw/Cham.cpp | 1204 ++++++++++++++-------------- uppsrc/Draw/Cham.h | 242 +++--- uppsrc/Draw/ImageOp.cpp | 1413 +++++++++++++++++---------------- uppsrc/Draw/ImageOp.h | 319 ++++---- 17 files changed, 2013 insertions(+), 1889 deletions(-) diff --git a/uppsrc/Core/Color.cpp b/uppsrc/Core/Color.cpp index b25d5a404..f44793d2b 100644 --- a/uppsrc/Core/Color.cpp +++ b/uppsrc/Core/Color.cpp @@ -133,4 +133,9 @@ bool IsDark(Color c) return Grayscale(c) < 80; } +bool IsLight(Color c) +{ + return Grayscale(c) > 255 - 80; +} + END_UPP_NAMESPACE diff --git a/uppsrc/CtrlLib/Bar.h b/uppsrc/CtrlLib/Bar.h index bcde736b8..38983df48 100644 --- a/uppsrc/CtrlLib/Bar.h +++ b/uppsrc/CtrlLib/Bar.h @@ -292,6 +292,7 @@ private: int arealook; Size maxiconsize; LookFrame frame; + bool nodarkadjust; friend class MenuItemBase; friend class SubMenuBase; @@ -354,6 +355,7 @@ public: MenuBar& AreaLook(int q = 1) { arealook = q; Refresh(); return *this; } MenuBar& MaxIconSize(Size sz) { maxiconsize = sz; return *this; } Size GetMaxIconSize() const { return maxiconsize; } + MenuBar& NoDarkAdjust(bool b = true) { nodarkadjust = b; return *this; } typedef MenuBar CLASSNAME; @@ -407,6 +409,7 @@ protected: byte kind; Size minsize; Size maxiconsize; + bool nodarkadjust; const Style *style; @@ -434,6 +437,7 @@ public: ToolButton& Kind(int _kind) { kind = _kind; Refresh(); return *this; } ToolButton& Label(const char *text, int kind); ToolButton& Label(const char *text); + ToolButton& NoDarkAdjust(bool b = true) { nodarkadjust = b; return *this; } ToolButton(); virtual ~ToolButton(); @@ -472,6 +476,7 @@ private: Size buttonminsize; Size maxiconsize; int kind; + bool nodarkadjust; protected: enum { @@ -496,6 +501,7 @@ public: ToolBar& MaxIconSize(Size sz) { maxiconsize = sz; return *this; } ToolBar& ButtonKind(int _kind) { kind = _kind; return *this; } ToolBar& AreaLook(int q = 1) { arealook = q; Refresh(); return *this; } + ToolBar& NoDarkAdjust(bool b = true) { nodarkadjust = b; return *this; } typedef ToolBar CLASSNAME; diff --git a/uppsrc/CtrlLib/Button.cpp b/uppsrc/CtrlLib/Button.cpp index 787065705..0ec529bdf 100644 --- a/uppsrc/CtrlLib/Button.cpp +++ b/uppsrc/CtrlLib/Button.cpp @@ -579,7 +579,7 @@ void Option::Paint(Draw& w) { if(showlabel) { bool ds = !IsShowEnabled(); DrawSmartText(w, isz.cx + 4, ty, tsz.cx, label, font, - ds || IsReadOnly() ? SColorDisabled : SColorLabel, //////// + ds || IsReadOnly() ? SColorDisabled : GetLabelTextColor(this), VisibleAccessKeys() ? accesskey : 0); if(HasFocus()) DrawFocus(w, RectC(isz.cx + 2, ty - 1, tsz.cx + 3, tsz.cy + 2) & sz); diff --git a/uppsrc/CtrlLib/LabelBase.cpp b/uppsrc/CtrlLib/LabelBase.cpp index 11376fb12..6d3cef452 100644 --- a/uppsrc/CtrlLib/LabelBase.cpp +++ b/uppsrc/CtrlLib/LabelBase.cpp @@ -171,7 +171,24 @@ Image DisabledImage(const Image& img, bool dis) : img; } -Size DrawLabel::Paint(Draw& w, const Rect& r, bool visibleaccesskey) const +Color GetLabelTextColor(const Ctrl *ctrl) +{ + if(!IsLabelTextColorMismatch()) + return SColorLabel(); + while(ctrl) { + if(!ctrl->IsTransparent()) { + if(dynamic_cast(ctrl) || dynamic_cast(ctrl) || + dynamic_cast(ctrl) || dynamic_cast(ctrl) || + dynamic_cast(ctrl) || dynamic_cast(ctrl)) + break; + return SColorText(); + } + ctrl = ctrl->GetParent(); + } + return SColorLabel(); +} + +Size DrawLabel::Paint(Ctrl *ctrl, Draw& w, const Rect& r, bool visibleaccesskey) const { int lspc = this->lspc; int rspc = this->rspc; @@ -209,7 +226,7 @@ Size DrawLabel::Paint(Draw& w, const Rect& r, bool visibleaccesskey) const p.y = (r.bottom + r.top - txtsz.cy) / 2; Color color = disabled && !IsNull(disabledink) ? disabledink : ink; if(IsNull(color)) - color = disabled ? SColorDisabled : SColorLabel; ///////// + color = disabled ? SColorDisabled : GetLabelTextColor(ctrl); int ix; if(IsNull(lspc)) ix = r.left + push; @@ -247,6 +264,16 @@ Size DrawLabel::Paint(Draw& w, const Rect& r, bool visibleaccesskey) const return isz; } +Size DrawLabel::Paint(Ctrl *ctrl, Draw& w, int x, int y, int cx, int cy, bool visibleaccesskey) const +{ + return Paint(ctrl, w, RectC(x, y, cx, cy), visibleaccesskey); +} + +Size DrawLabel::Paint(Draw& w, const Rect& r, bool visibleaccesskey) const +{ + return Paint(NULL, w, r, visibleaccesskey); +} + Size DrawLabel::Paint(Draw& w, int x, int y, int cx, int cy, bool vak) const { return Paint(w, RectC(x, y, cx, cy), vak); @@ -316,13 +343,23 @@ LabelBase& LabelBase::SetVAlign(int valign) { return *this; } -Size LabelBase::PaintLabel(Draw& w, const Rect& r, bool disabled, bool push, bool focus, bool vak) +Size LabelBase::PaintLabel(Ctrl *ctrl, Draw& w, const Rect& r, bool disabled, bool push, bool focus, bool vak) { DrawLabel lbl1 = lbl; lbl1.disabled = disabled; lbl1.push = push; lbl1.focus = focus; - return lbl1.Paint(w, r, vak); + return lbl1.Paint(ctrl, w, r, vak); +} + +Size LabelBase::PaintLabel(Ctrl *ctrl, Draw& w, int x, int y, int cx, int cy, bool disabled, bool push, bool focus, bool vak) +{ + return PaintLabel(ctrl, w, RectC(x, y, cx, cy), disabled, push, focus, vak); +} + +Size LabelBase::PaintLabel(Draw& w, const Rect& r, bool disabled, bool push, bool focus, bool vak) +{ + return PaintLabel(NULL, w, r, disabled, push, focus, vak); } diff --git a/uppsrc/CtrlLib/LabelBase.h b/uppsrc/CtrlLib/LabelBase.h index 300c951b6..284e2fa09 100644 --- a/uppsrc/CtrlLib/LabelBase.h +++ b/uppsrc/CtrlLib/LabelBase.h @@ -52,6 +52,8 @@ struct DrawLabel { Size GetSize(int txtcx, Size sz1, int lspc, Size sz2, int rspc) const; Size GetSize(int txtcx = INT_MAX) const; + Size Paint(Ctrl *ctrl, Draw& w, const Rect& r, bool visibleaccesskey = true) const; + Size Paint(Ctrl *ctrl, Draw& w, int x, int y, int cx, int cy, bool visibleaccesskey = true) const; Size Paint(Draw& w, const Rect& r, bool visibleaccesskey = true) const; Size Paint(Draw& w, int x, int y, int cx, int cy, bool visibleaccesskey = true) const; @@ -59,6 +61,7 @@ struct DrawLabel { }; Image DisabledImage(const Image& img, bool disabled = true); +Color GetLabelTextColor(const Ctrl *ctrl); class LabelBase { protected: @@ -86,6 +89,10 @@ public: Font GetFont() const { return lbl.font; } Color GetInk() const { return lbl.ink; } + Size PaintLabel(Ctrl *ctrl, Draw& w, const Rect& r, + bool disabled = false, bool push = false, bool focus = false, bool vak = true); + Size PaintLabel(Ctrl *ctrl, Draw& w, int x, int y, int cx, int cy, + bool disabled = false, bool push = false, bool focus = false, bool vak = true); Size PaintLabel(Draw& w, const Rect& r, bool disabled = false, bool push = false, bool focus = false, bool vak = true); Size PaintLabel(Draw& w, int x, int y, int cx, int cy, diff --git a/uppsrc/CtrlLib/MenuBar.cpp b/uppsrc/CtrlLib/MenuBar.cpp index 22ad2f19c..2f8a75567 100644 --- a/uppsrc/CtrlLib/MenuBar.cpp +++ b/uppsrc/CtrlLib/MenuBar.cpp @@ -62,6 +62,7 @@ MenuBar::MenuBar() SetStyle(StyleDefault()); arealook = -1; maxiconsize = Null; + nodarkadjust = false; } MenuBar& MenuBar::SetStyle(const Style& s) diff --git a/uppsrc/CtrlLib/MenuImp.h b/uppsrc/CtrlLib/MenuImp.h index 0cb794c9e..e097e43fa 100644 --- a/uppsrc/CtrlLib/MenuImp.h +++ b/uppsrc/CtrlLib/MenuImp.h @@ -42,6 +42,7 @@ protected: int accesskey; Size maxiconsize; const MenuBar::Style *style; + bool nodarkadjust; public: virtual void SyncState() = 0; @@ -59,6 +60,7 @@ public: Font GetFont() const { return font; } MenuItemBase& MaxIconSize(Size sz) { maxiconsize = sz; return *this; } bool InOpaqueBar() const; + MenuItemBase& NoDarkAdjust(bool b = true) { nodarkadjust = b; return *this; } MenuItemBase(); }; diff --git a/uppsrc/CtrlLib/MenuItem.cpp b/uppsrc/CtrlLib/MenuItem.cpp index e44b6ba84..53164f445 100644 --- a/uppsrc/CtrlLib/MenuItem.cpp +++ b/uppsrc/CtrlLib/MenuItem.cpp @@ -173,8 +173,8 @@ void MenuItemBase::PaintTopItem(Draw& w, int state) { String text = GetText(); Size isz = GetTextSize(text, StdFont()); DrawMenuText(w, 6, (sz.cy - isz.cy) / 2, text, GetFont(), IsItemEnabled(), state, - opaque ? style->topitemtext[0] : SColorLabel(), - opaque2 ? style->topitemtext[state] : SColorLabel()); + opaque ? style->topitemtext[0] : GetLabelTextColor(this), + opaque2 ? style->topitemtext[state] : GetLabelTextColor(this)); } else { w.DrawRect(sz, SColorFace); @@ -194,6 +194,8 @@ void MenuItemBase::PaintTopItem(Draw& w, int state) { Bar::Item& MenuItem::Image(const UPP::Image& img) { licon = img; + if(IsDarkColorFace() && !nodarkadjust) + licon = MakeImage(licon, AdjustForDarkBk); Refresh(); return *this; } @@ -201,6 +203,8 @@ Bar::Item& MenuItem::Image(const UPP::Image& img) MenuItem& MenuItem::RightImage(const UPP::Image& img) { ricon = img; + if(IsDarkColorFace() && !nodarkadjust) + ricon = MakeImage(ricon, AdjustForDarkBk); Refresh(); return *this; } diff --git a/uppsrc/CtrlLib/Static.cpp b/uppsrc/CtrlLib/Static.cpp index dc3154b82..8a6d74ef3 100644 --- a/uppsrc/CtrlLib/Static.cpp +++ b/uppsrc/CtrlLib/Static.cpp @@ -7,7 +7,7 @@ void StaticText::Paint(Draw& w) Size sz = GetSize(); if(!IsTransparent()) w.DrawRect(0, 0, sz.cx, sz.cy, SColorFace); - PaintLabel(w, 0, 0, sz.cx, sz.cy, !IsShowEnabled(), false, false, VisibleAccessKeys()); + PaintLabel(this, w, 0, 0, sz.cx, sz.cy, !IsShowEnabled(), false, false, VisibleAccessKeys()); } Size StaticText::GetMinSize() const @@ -79,7 +79,7 @@ Label::Label() { Label::~Label() {} -CH_COLOR(LabelBoxTextColor, LtBlue()); +CH_COLOR(LabelBoxTextColor, IsDark(SColorFace()) ? Blend(LtBlue(), White) : LtBlue()); CH_COLOR(LabelBoxDisabledTextColor, SColorDisabled()); CH_COLOR(LabelBoxColor, SColorShadow()); diff --git a/uppsrc/CtrlLib/Switch.cpp b/uppsrc/CtrlLib/Switch.cpp index 852496cc3..15d7fd68d 100644 --- a/uppsrc/CtrlLib/Switch.cpp +++ b/uppsrc/CtrlLib/Switch.cpp @@ -187,7 +187,7 @@ void Switch::Paint(Draw& w) { img = CtrlsImg::Get((v.value == value ? CtrlsImg::I_S1 : CtrlsImg::I_S0) + q); w.DrawImage(x, y + iy, img); DrawSmartText(w, x + isz.cx + 4, y + ty, sz.cx, v.label, font, - dv || IsReadOnly() ? SColorDisabled : SColorLabel, /////// + dv || IsReadOnly() ? SColorDisabled : GetLabelTextColor(this), /////// VisibleAccessKeys() ? v.accesskey : 0); if(HasFocus() && (pushindex == i || v.value == value && pushindex < 0)) DrawFocus(w, RectC(x + isz.cx + 2, y + ty - 1, tsz.cx + 3, tsz.cy + 2) & sz); diff --git a/uppsrc/CtrlLib/ToolBar.cpp b/uppsrc/CtrlLib/ToolBar.cpp index de81e1af8..4f6bd7b3e 100644 --- a/uppsrc/CtrlLib/ToolBar.cpp +++ b/uppsrc/CtrlLib/ToolBar.cpp @@ -26,6 +26,7 @@ ToolBar::ToolBar() maxiconsize = Null; kind = ToolButton::NOLABEL; arealook = -1; + nodarkadjust = false; } ToolBar::~ToolBar() {} @@ -60,6 +61,7 @@ Bar::Item& ToolBar::AddItem(Callback cb) m.MaxIconSize(IsNull(maxiconsize) ? style->maxiconsize : maxiconsize); m.Kind(kind); m.SetStyle(style->buttonstyle); + m.NoDarkAdjust(nodarkadjust); pane.Add(&m, Null); return m; } diff --git a/uppsrc/CtrlLib/ToolButton.cpp b/uppsrc/CtrlLib/ToolButton.cpp index 35d4edb78..dd5fee09e 100644 --- a/uppsrc/CtrlLib/ToolButton.cpp +++ b/uppsrc/CtrlLib/ToolButton.cpp @@ -1,317 +1,321 @@ -#include "CtrlLib.h" - -NAMESPACE_UPP - -#define LTIMING(x) // TIMING(x) - -CH_STYLE(ToolButton, Style, StyleDefault) -{ - CtrlsImageLook(look, CtrlsImg::I_TB, 6); - font = StdFont(); - for(int i = 0; i < 4; i++) - textcolor[i] = Button::StyleNormal().textcolor[i]; - textcolor[CTRL_CHECKED] = textcolor[CTRL_NORMAL]; - textcolor[CTRL_HOTCHECKED] = textcolor[CTRL_HOT]; - for(int i = 0; i < 6; i++) { - light[i] = false; - contrast[i] = 0; - } - light[CTRL_PRESSED] = light[CTRL_HOT] = light[CTRL_HOTCHECKED] = true; -} - -CH_STYLE(ToolButton, Style, StyleSolid) -{ - const Button::Style& bs = Button::StyleNormal(); - look[0] = bs.look[0]; - look[1] = bs.look[1]; - look[2] = bs.look[2]; - look[3] = bs.look[3]; - look[4] = bs.look[2]; - look[5] = bs.look[1]; - font = StdFont(); - for(int i = 0; i < 4; i++) - textcolor[i] = Button::StyleNormal().textcolor[i]; - textcolor[CTRL_CHECKED] = textcolor[CTRL_NORMAL]; - textcolor[CTRL_HOTCHECKED] = textcolor[CTRL_HOT]; - for(int i = 0; i < 6; i++) { - light[i] = false; - contrast[i] = 0; - } - light[CTRL_PRESSED] = light[CTRL_HOT] = light[CTRL_HOTCHECKED] = true; -} - -ToolButton::ToolButton() -{ - Reset(); - checked = false; - paint_checked = false; - Transparent(); - kind = NOLABEL; -} - -ToolButton::~ToolButton() {} - -void ToolButton::Reset() -{ - Tip(""); - Help(""); - Topic(""); - Description(""); - repeat = false; - accel = 0; - checked = false; - NoWantFocus(); - minsize = Size(0, 0); - maxiconsize = Size(INT_MAX, INT_MAX); - style = &StyleDefault(); -} - -void ToolButton::UpdateTip() -{ - LTIMING("UpdateTip"); - String s = tiptext; - if(IsNull(s) && kind == NOLABEL) - s = text; - if(accel) { - if(s.GetCount()) - s << ' '; - s << '(' << GetKeyDesc(accel) << ')'; - } - Ctrl::Tip(s); -} - -Bar::Item& ToolButton::Text(const char *txt) -{ - ExtractAccessKey(txt, text); - UpdateTip(); - Refresh(); - return *this; -} - -Bar::Item& ToolButton::Check(bool check) -{ - checked = check; - Refresh(); - return *this; -} - -Bar::Item& ToolButton::Radio(bool check) -{ - return Check(check); -} - -Bar::Item& ToolButton::Key(dword key) -{ - if(key) { - accel = key; - UpdateTip(); - } - return *this; -} - -Bar::Item& ToolButton::Repeat(bool r) -{ - repeat = r; - return *this; -} - -ToolButton& ToolButton::Label(const char *text, int _kind) -{ - if(kind != _kind) { - kind = _kind; - Refresh(); - } - Text(text); - return *this; -} - -ToolButton& ToolButton::Label(const char *text) -{ - Label(text, kind == NOLABEL ? RIGHTLABEL : kind); - return *this; -} - -Image ToolButton::GetImage() const -{ - return CachedRescale(img, min(img.GetSize(), maxiconsize)); -} - -Bar::Item& ToolButton::Image(const UPP::Image& img_) -{ - if(!img_.IsSame(img)) { - img = img_; - Refresh(); - } - return *this; -} - -Bar::Item& ToolButton::Enable(bool enable) -{ - Ctrl::Enable(enable); - return *this; -} - -Bar::Item& ToolButton::Tip(const char *tip) -{ - tiptext = tip; - UpdateTip(); - return *this; -} - -Bar::Item& ToolButton::Help(const char *help) -{ - HelpLine(help); - return *this; -} - -Bar::Item& ToolButton::Topic(const char *help) -{ - HelpTopic(help); - return *this; -} - -Bar::Item& ToolButton::Description(const char *desc) -{ - Ctrl::Description(desc); - return *this; -} - -struct sCachedContrast : public ImageMaker -{ - int d; - Image img; - - virtual String Key() const { - String s; - RawCat(s, d); - RawCat(s, img.GetSerialId()); - return s; - } - - virtual Image Make() const { - return Contrast(img, 256 + d); - } -}; - -Image CachedContrast(const Image& m, int d) -{ - if(d == 0) - return m; - sCachedContrast cr; - cr.d = d; - cr.img = m; - return MakeImage(cr); -} - -void ToolButton::Paint(Draw& w) -{ - LTIMING("ToolButton::Paint"); - paint_checked = checked; - Size sz = GetSize(); - UPP::Image image = GetImage(); - Size isz = image.GetSize(); -// Ctrl *q = GetParent()->GetParent(); -// if(!q || !q->IsTransparent()) -// w.DrawRect(sz, checked && !HasMouse() ? Blend(SColorFace, SColorLight) : SColorFace); - int li = IsEnabled() ? HasMouse() ? GetMouseLeft() ? CTRL_PRESSED - : checked ? CTRL_HOTCHECKED : CTRL_HOT - : checked ? CTRL_CHECKED : CTRL_NORMAL - : CTRL_DISABLED; - ChPaint(w, sz, style->look[li]); - Point off = style->offset[li]; - Point ip = (sz - isz) / 2 + off; - Size tsz; - if(kind != NOLABEL) - tsz = GetTextSize(text, style->font); - if(kind == BOTTOMLABEL) { - ip.y -= tsz.cy / 2 + 1; - w.DrawText((sz.cx - tsz.cx) / 2 + off.x, ip.y + isz.cy + 2 + off.y, text, style->font, style->textcolor[li]); - } - if(kind == RIGHTLABEL) { - ip.x -= tsz.cx / 2 + 2; - w.DrawText(ip.x + isz.cx + 3 + off.x, (sz.cy - tsz.cy) / 2 + off.y, text, style->font, style->textcolor[li]); - } - UPP::Image img = CachedContrast(image, style->contrast[li]); - if(!IsEnabled()) - img = DisabledImage(img); - if(IsEnabled() && style->light[li]) - DrawHighlightImage(w, ip.x, ip.y, img, true); - else - w.DrawImage(ip.x, ip.y, img); -} - -void ToolButton::MouseEnter(Point, dword) -{ - BarCtrl::SendHelpLine(this); - Refresh(); -} - -void ToolButton::MouseLeave() -{ - BarCtrl::ClearHelpLine(this); - Refresh(); -} - -Size ToolButton::GetMinSize() const -{ - UPP::Image image = GetImage(); - Size sz = image.GetSize(); - if(sz.IsEmpty()) - sz = Size(16, 16); - sz += 6; - if(text.GetCount()) { - Size tsz = GetTextSize(text, style->font); - if(kind == BOTTOMLABEL) { - sz.cy += tsz.cy + 3; - sz.cx = max(sz.cx, tsz.cx + 9); - } - if(kind == RIGHTLABEL) { - sz.cx += tsz.cx + 6; - sz.cy = max(sz.cy, tsz.cy + 6); - } - } - return max(sz, minsize); -} - -void ToolButton::LeftDown(Point, dword) -{ - Refresh(); - if(repeat) - WhenAction(); -} - -void ToolButton::LeftRepeat(Point, dword) -{ - Refresh(); - if(repeat) - WhenAction(); -} - -void ToolButton::LeftUp(Point, dword) -{ - Refresh(); - if(!repeat) - WhenAction(); -} - -bool ToolButton::HotKey(dword key) -{ - if(key == accel) { - WhenAction(); - return true; - } - return false; -} - -void ToolButton::FinalSync() -{ - if(checked != paint_checked) - Refresh(); -} - -String ToolButton::GetDesc() const -{ - return tiptext; -} - -END_UPP_NAMESPACE +#include "CtrlLib.h" + +NAMESPACE_UPP + +#define LTIMING(x) // TIMING(x) + +CH_STYLE(ToolButton, Style, StyleDefault) +{ + CtrlsImageLook(look, CtrlsImg::I_TB, 6); + font = StdFont(); + for(int i = 0; i < 4; i++) + textcolor[i] = Button::StyleNormal().textcolor[i]; + textcolor[CTRL_CHECKED] = textcolor[CTRL_NORMAL]; + textcolor[CTRL_HOTCHECKED] = textcolor[CTRL_HOT]; + for(int i = 0; i < 6; i++) { + light[i] = false; + contrast[i] = 0; + } + light[CTRL_PRESSED] = light[CTRL_HOT] = light[CTRL_HOTCHECKED] = true; +} + +CH_STYLE(ToolButton, Style, StyleSolid) +{ + const Button::Style& bs = Button::StyleNormal(); + look[0] = bs.look[0]; + look[1] = bs.look[1]; + look[2] = bs.look[2]; + look[3] = bs.look[3]; + look[4] = bs.look[2]; + look[5] = bs.look[1]; + font = StdFont(); + for(int i = 0; i < 4; i++) + textcolor[i] = Button::StyleNormal().textcolor[i]; + textcolor[CTRL_CHECKED] = textcolor[CTRL_NORMAL]; + textcolor[CTRL_HOTCHECKED] = textcolor[CTRL_HOT]; + for(int i = 0; i < 6; i++) { + light[i] = false; + contrast[i] = 0; + } + light[CTRL_PRESSED] = light[CTRL_HOT] = light[CTRL_HOTCHECKED] = true; +} + +ToolButton::ToolButton() +{ + Reset(); + checked = false; + paint_checked = false; + nodarkadjust = false; + Transparent(); + kind = NOLABEL; +} + +ToolButton::~ToolButton() {} + +void ToolButton::Reset() +{ + Tip(""); + Help(""); + Topic(""); + Description(""); + repeat = false; + accel = 0; + checked = false; + NoWantFocus(); + minsize = Size(0, 0); + maxiconsize = Size(INT_MAX, INT_MAX); + style = &StyleDefault(); +} + +void ToolButton::UpdateTip() +{ + LTIMING("UpdateTip"); + String s = tiptext; + if(IsNull(s) && kind == NOLABEL) + s = text; + if(accel) { + if(s.GetCount()) + s << ' '; + s << '(' << GetKeyDesc(accel) << ')'; + } + Ctrl::Tip(s); +} + +Bar::Item& ToolButton::Text(const char *txt) +{ + ExtractAccessKey(txt, text); + UpdateTip(); + Refresh(); + return *this; +} + +Bar::Item& ToolButton::Check(bool check) +{ + checked = check; + Refresh(); + return *this; +} + +Bar::Item& ToolButton::Radio(bool check) +{ + return Check(check); +} + +Bar::Item& ToolButton::Key(dword key) +{ + if(key) { + accel = key; + UpdateTip(); + } + return *this; +} + +Bar::Item& ToolButton::Repeat(bool r) +{ + repeat = r; + return *this; +} + +ToolButton& ToolButton::Label(const char *text, int _kind) +{ + if(kind != _kind) { + kind = _kind; + Refresh(); + } + Text(text); + return *this; +} + +ToolButton& ToolButton::Label(const char *text) +{ + Label(text, kind == NOLABEL ? RIGHTLABEL : kind); + return *this; +} + +Image ToolButton::GetImage() const +{ + UPP::Image m = img; + if(IsDarkColorFace() && !nodarkadjust) + m = MakeImage(m, AdjustForDarkBk); + return CachedRescale(m, min(m.GetSize(), maxiconsize)); +} + +Bar::Item& ToolButton::Image(const UPP::Image& img_) +{ + if(!img_.IsSame(img)) { + img = img_; + Refresh(); + } + return *this; +} + +Bar::Item& ToolButton::Enable(bool enable) +{ + Ctrl::Enable(enable); + return *this; +} + +Bar::Item& ToolButton::Tip(const char *tip) +{ + tiptext = tip; + UpdateTip(); + return *this; +} + +Bar::Item& ToolButton::Help(const char *help) +{ + HelpLine(help); + return *this; +} + +Bar::Item& ToolButton::Topic(const char *help) +{ + HelpTopic(help); + return *this; +} + +Bar::Item& ToolButton::Description(const char *desc) +{ + Ctrl::Description(desc); + return *this; +} + +struct sCachedContrast : public ImageMaker +{ + int d; + Image img; + + virtual String Key() const { + String s; + RawCat(s, d); + RawCat(s, img.GetSerialId()); + return s; + } + + virtual Image Make() const { + return Contrast(img, 256 + d); + } +}; + +Image CachedContrast(const Image& m, int d) +{ + if(d == 0) + return m; + sCachedContrast cr; + cr.d = d; + cr.img = m; + return MakeImage(cr); +} + +void ToolButton::Paint(Draw& w) +{ + LTIMING("ToolButton::Paint"); + paint_checked = checked; + Size sz = GetSize(); + UPP::Image image = GetImage(); + Size isz = image.GetSize(); +// Ctrl *q = GetParent()->GetParent(); +// if(!q || !q->IsTransparent()) +// w.DrawRect(sz, checked && !HasMouse() ? Blend(SColorFace, SColorLight) : SColorFace); + int li = IsEnabled() ? HasMouse() ? GetMouseLeft() ? CTRL_PRESSED + : checked ? CTRL_HOTCHECKED : CTRL_HOT + : checked ? CTRL_CHECKED : CTRL_NORMAL + : CTRL_DISABLED; + ChPaint(w, sz, style->look[li]); + Point off = style->offset[li]; + Point ip = (sz - isz) / 2 + off; + Size tsz; + if(kind != NOLABEL) + tsz = GetTextSize(text, style->font); + if(kind == BOTTOMLABEL) { + ip.y -= tsz.cy / 2 + 1; + w.DrawText((sz.cx - tsz.cx) / 2 + off.x, ip.y + isz.cy + 2 + off.y, text, style->font, style->textcolor[li]); + } + if(kind == RIGHTLABEL) { + ip.x -= tsz.cx / 2 + 2; + w.DrawText(ip.x + isz.cx + 3 + off.x, (sz.cy - tsz.cy) / 2 + off.y, text, style->font, style->textcolor[li]); + } + UPP::Image img = CachedContrast(image, style->contrast[li]); + if(!IsEnabled()) + img = DisabledImage(img); + if(IsEnabled() && style->light[li]) + DrawHighlightImage(w, ip.x, ip.y, img, true); + else + w.DrawImage(ip.x, ip.y, img); +} + +void ToolButton::MouseEnter(Point, dword) +{ + BarCtrl::SendHelpLine(this); + Refresh(); +} + +void ToolButton::MouseLeave() +{ + BarCtrl::ClearHelpLine(this); + Refresh(); +} + +Size ToolButton::GetMinSize() const +{ + UPP::Image image = GetImage(); + Size sz = image.GetSize(); + if(sz.IsEmpty()) + sz = Size(16, 16); + sz += 6; + if(text.GetCount()) { + Size tsz = GetTextSize(text, style->font); + if(kind == BOTTOMLABEL) { + sz.cy += tsz.cy + 3; + sz.cx = max(sz.cx, tsz.cx + 9); + } + if(kind == RIGHTLABEL) { + sz.cx += tsz.cx + 6; + sz.cy = max(sz.cy, tsz.cy + 6); + } + } + return max(sz, minsize); +} + +void ToolButton::LeftDown(Point, dword) +{ + Refresh(); + if(repeat) + WhenAction(); +} + +void ToolButton::LeftRepeat(Point, dword) +{ + Refresh(); + if(repeat) + WhenAction(); +} + +void ToolButton::LeftUp(Point, dword) +{ + Refresh(); + if(!repeat) + WhenAction(); +} + +bool ToolButton::HotKey(dword key) +{ + if(key == accel) { + WhenAction(); + return true; + } + return false; +} + +void ToolButton::FinalSync() +{ + if(checked != paint_checked) + Refresh(); +} + +String ToolButton::GetDesc() const +{ + return tiptext; +} + +END_UPP_NAMESPACE diff --git a/uppsrc/CtrlLib/init b/uppsrc/CtrlLib/init index 288221d17..cc28a5bb6 100644 --- a/uppsrc/CtrlLib/init +++ b/uppsrc/CtrlLib/init @@ -2,7 +2,7 @@ #define _CtrlLib_icpp_init_stub #include "CtrlCore/init" #include "PdfDraw/init" -#define BLITZ_INDEX__ F682CA52260E08DE87F9D30ACEC11FC17 +#define BLITZ_INDEX__ F81538F57228D18567476124EF6E8A601 #include "CtrlLib.icpp" #undef BLITZ_INDEX__ #endif diff --git a/uppsrc/Draw/Cham.cpp b/uppsrc/Draw/Cham.cpp index 67bb870d3..e810c9f7e 100644 --- a/uppsrc/Draw/Cham.cpp +++ b/uppsrc/Draw/Cham.cpp @@ -1,594 +1,610 @@ -#include "Draw.h" - -NAMESPACE_UPP - -#define LTIMING(x) // RTIMING(x) - -#if defined(_DEBUG) && 0 -#include - -inline void LOGPNG(const char *name, const Image& m) -{ - PNGEncoder png; - png.SaveFile(ConfigFile(name) + ".png", m); -} - -#else - -#define LOGPNG(a, b) - -#endif - -struct ChImageMaker : ImageMaker { - Size sz; - Rect sr; - Image img; - - virtual String Key() const; - virtual Image Make() const; -}; - -String ChImageMaker::Key() const -{ - LTIMING("ChImageMaker::Key"); - StringBuffer b; - int64 id = img.GetSerialId(); - b.Cat((const char *)&id, sizeof(id)); - b.Cat((const char *)&sz.cx, sizeof(sz.cx)); - b.Cat((const char *)&sz.cy, sizeof(sz.cy)); - b.Cat((const char *)&sr.left, sizeof(sr.left)); - b.Cat((const char *)&sr.right, sizeof(sr.right)); - b.Cat((const char *)&sr.top, sizeof(sr.top)); - b.Cat((const char *)&sr.bottom, sizeof(sr.bottom)); - return b; -} - -Image ChImageMaker::Make() const -{ - LTIMING("ChImageMaker::Make"); - return Rescale(img, sz, sr); -} - -void ChDraw(Draw& w, int x, int y, int cx, int cy, const Image& img, const Rect& src) -{ - LTIMING("ChDraw"); - if(cx > 0 && cy > 0) { - #ifdef flagWINGL - w.DrawImage(x, y, cx, cy, img, src); - #else - ChImageMaker m; - m.sz = Size(cx, cy); - m.sr = src; - m.img = img; - w.DrawImage(x, y, MakeImage(m)); - #endif - } -} - -void ChDraw(Draw& w, const Rect& r, const Image& img, const Rect& src) -{ - ChDraw(w, r.left, r.top, r.GetWidth(), r.GetHeight(), img, src); -} - -struct sChLookWith { - Value look; - Image img; - Color (*colorfn)(int i); - int ii; - Color color; - Point offset; -}; - -Value ChLookWith(const Value& look, const Image& img, Point offset) -{ - sChLookWith x; - x.look = look; - x.img = img; - x.colorfn = NULL; - x.color = Null; - x.offset = offset; - return RawToValue(x); -} - -Value ChLookWith(const Value& look, const Image& img, Color color, Point offset) -{ - sChLookWith x; - x.look = look; - x.img = img; - x.colorfn = NULL; - x.color = color; - x.offset = offset; - return RawToValue(x); -} - -Value ChLookWith(const Value& look, const Image& img, Color (*color)(int i), int i, Point offset) -{ - sChLookWith x; - x.look = look; - x.img = img; - x.colorfn = color; - x.ii = i; - x.offset = offset; - return RawToValue(x); -} - -Value sChOp(Draw& w, const Rect& r, const Value& v, int op); - -struct sChBorder { - const ColorF *border; - Value face; -}; - -Value ChBorder(const ColorF *colors, const Value& face) -{ - sChBorder b; - b.border = colors; - b.face = face; - return RawToValue(b); -} - -Value StdChLookFn(Draw& w, const Rect& r, const Value& v, int op) -{ - if(IsType(v)) { - const sChLookWith& x = ValueTo(v); - if(op == LOOK_PAINT) { - LOGPNG(AsString(x.img.GetSerialId()), x.img); - ChPaint(w, r, x.look); - Point p = r.CenterPos(x.img.GetSize()) + x.offset; - if(x.colorfn) - w.DrawImage(p.x, p.y, x.img, (*x.colorfn)(x.ii)); - else - if(!IsNull(x.color)) - w.DrawImage(p.x, p.y, x.img, x.color); - else - w.DrawImage(p.x, p.y, x.img); - return 1; - } - return sChOp(w, r, x.look, op); - } - if(IsType(v)) { - sChBorder b = ValueTo(v); - int n = (int)(intptr_t)*b.border; - switch(op) { - case LOOK_PAINT: - ChPaint(w, r.Deflated(n), b.face); - case LOOK_PAINTEDGE: - DrawBorder(w, r, b.border); - return 0; - case LOOK_MARGINS: - return Rect(n, n, n, n); - case LOOK_ISBODYOPAQUE: - case LOOK_ISOPAQUE: - return false; - } - } - if(IsType(v)) { - Color c = v; - switch(op) { - case LOOK_PAINT: - w.DrawRect(r, c); - return 0; - case LOOK_PAINTEDGE: - DrawFrame(w, r, c); - return 0; - case LOOK_MARGINS: - return Rect(1, 1, 1, 1); - case LOOK_ISBODYOPAQUE: - case LOOK_ISOPAQUE: - return !IsNull(c); - } - } - if(IsType(v)) { - Image img = v; - Size isz = img.GetSize(); - Size sz = r.GetSize(); - Point p = img.GetHotSpot(); - Point p2 = img.Get2ndSpot(); - int tile = 0; - if(p2.x || p2.y) { - if(p2.x < p.x) { - Swap(p2.x, p.x); - tile = 1; - } - if(p2.y < p.y) { - Swap(p2.y, p.y); - tile += 2; - } - p2.x++; - p2.y++; - } - else { - p2.x = isz.cx - p.x; - p2.y = isz.cy - p.y; - if(p.x > isz.cx / 2) { - tile = 1; - p2.x = p.x; - p.x = isz.cx - p.x - 1; - } - if(p.y > isz.cy / 2) { - tile += 2; - p2.y = p.y; - p.y = isz.cy - p.y - 1; - } - } - if(op == LOOK_MARGINS) - return Rect(p.x, p.y, isz.cx - p2.x, isz.cy - p2.y); - if(op == LOOK_ISOPAQUE) - return img.GetKind() == IMAGE_OPAQUE; - if(IsNull(img)) - return 1; - if(op == LOOK_ISBODYOPAQUE) { - static VectorMap btc; - int64 key = img.GetSerialId(); - int q = btc.Find(key); - if(q < 0) { - bool opaque = true; - Rect m = ChMargins(img); - Rect r = img.GetSize(); - r.left += max(m.left, 0); - r.right -= max(m.right, 0); - r.top += m.top; - r.bottom -= m.bottom; - int cx = r.right - r.left; - if(cx >= 0) - for(int y = r.top; y < r.bottom && opaque; y++) { - const RGBA *s = img[y] + r.left; - const RGBA *e = s + cx; - while(s < e) { - if(s->a != 255) { - opaque = false; - break; - } - } - } - if(btc.GetCount() > 100) - btc.Clear(); - btc.Add(key, q); - return opaque; - } - return btc[q]; - } - if(op == LOOK_PAINT || op == LOOK_PAINTEDGE) { - LTIMING("ChPaint Image"); - w.Clipoff(r); - Rect sr(p, p2); - Size sz2(isz.cx - sr.right, isz.cy - sr.bottom); - Rect r = RectC(p.x, p.y, sz.cx - sr.left - sz2.cx, sz.cy - sr.top - sz2.cy); - int top = minmax(sz.cy / 2, 0, isz.cy); - int bottom = minmax(sz.cy - top, 0, isz.cy); - int yy = isz.cy - bottom; - int left = minmax(sz.cx / 2, 0, isz.cx); - int right = minmax(sz.cx - left, 0, isz.cx); - int xx = isz.cx - right; - if(!r.IsEmpty()) { - w.DrawImage(0, 0, img, RectC(0, 0, p.x, p.y)); - w.DrawImage(0, r.bottom, img, RectC(0, sr.bottom, p.x, sz2.cy)); - w.DrawImage(r.right, 0, img, RectC(sr.right, 0, sz2.cx, p.y)); - w.DrawImage(r.right, r.bottom, img, RectC(sr.right, sr.bottom, sz2.cx, sz2.cy)); - ChDraw(w, p.x, 0, r.Width(), p.y, img, RectC(p.x, 0, sr.Width(), p.y)); - ChDraw(w, p.x, r.bottom, r.Width(), sz2.cy, img, RectC(p.x, sr.bottom, sr.Width(), sz2.cy)); - ChDraw(w, 0, p.y, p.x, r.Height(), img, RectC(0, p.y, p.x, sr.Height())); - ChDraw(w, r.right, p.y, sz2.cx, r.Height(), img, - RectC(sr.right, p.y, sz2.cx, sr.Height())); - if(op == LOOK_PAINT) { - if(IsNull(r) || IsNull(sr)) - return 1; - if(tile) { - LTIMING("Ch-Tiles"); - LTIMING("Ch-Tiles"); - Size sz; - sz.cx = (tile & 1 ? sr : r).GetWidth(); - sz.cy = (tile & 2 ? sr : r).GetHeight(); - #ifdef flagWINGL - DrawTiles(w, r, img, sz, sr); - #else - img = Rescale(img, sz, sr); - DrawTiles(w, r, img); - #endif - } - else { - static VectorMap btc; - int64 key = img.GetSerialId(); - int q; - { - LTIMING("Find"); - q = btc.Find(key); - } - if(q < 0) { - LTIMING("ClassifyContent"); - q = ClassifyContent(img, sr); - if(btc.GetCount() > 100) - btc.Clear(); - btc.Add(key, q); - } - else - q = btc[q]; - switch(q) { - case IMAGECONTENT_VERTDUP|IMAGECONTENT_HORZDUP: - { - LTIMING("Ch-singlecolor"); - RGBA c = img[sr.top][sr.left]; - if(c.a == 255) { - w.DrawRect(r, c); - break; - } - } - case 0: - default: - ChDraw(w, r, img, sr); - break; - LTIMING("Ch-linedup"); - img = CachedRescalePaintOnly( - img, - Size((q & IMAGECONTENT_HORZDUP) ? max(min(40, r.GetWidth()), sr.GetWidth()) - : r.GetWidth(), - (q & IMAGECONTENT_VERTDUP) ? max(min(40, r.GetHeight()), sr.GetHeight()) - : r.GetHeight()), - sr - ); - LTIMING("Ch-linedup-drawtiles"); - DrawTiles(w, r, img); - break; - } - } - } - } - else - if(r.left < r.right) { - w.DrawImage(0, 0, img, RectC(0, 0, p.x, top)); - w.DrawImage(0, sz.cy - bottom, img, RectC(0, yy, p.x, bottom)); - w.DrawImage(r.right, 0, img, RectC(sr.right, 0, sz2.cx, top)); - w.DrawImage(r.right, sz.cy - bottom, img, RectC(sr.right, yy, sz2.cx, bottom)); - ChDraw(w, p.x, 0, r.Width(), top, img, RectC(p.x, 0, sr.Width(), top)); - ChDraw(w, p.x, sz.cy - bottom, r.Width(), bottom, img, RectC(p.x, yy, sr.Width(), bottom)); - } - else - if(r.top < r.bottom) { - w.DrawImage(0, 0, img, RectC(0, 0, left, p.y)); - w.DrawImage(0, r.bottom, img, RectC(0, sr.bottom, left, sz2.cy)); - w.DrawImage(sz.cx - right, 0, img, RectC(xx, 0, right, p.y)); - w.DrawImage(sz.cx - right, r.bottom, img, RectC(xx, sr.bottom, right, sz2.cy)); - ChDraw(w, 0, p.y, left, r.Height(), img, RectC(0, p.y, left, sr.Height())); - ChDraw(w, sz.cx - right, p.y, right, r.Height(), img, RectC(xx, p.y, right, sr.Height())); - } - else { - w.DrawImage(0, 0, img, RectC(0, 0, left, top)); - w.DrawImage(0, sz.cy - bottom, img, RectC(0, yy, left, top)); - w.DrawImage(sz.cx - right, 0, img, RectC(xx, 0, right, top)); - w.DrawImage(sz.cx - right, sz.cy - bottom, img, RectC(xx, yy, right, bottom)); - } - w.End(); - return 1; - } - } - return Null; -} - -typedef Value (*ChPainterFn)(Draw& w, const Rect& r, const Value& v, int op); - -Vector& sChps() -{ - static Vector x; - return x; -} - -void ChLookFn(Value (*fn)(Draw& w, const Rect& r, const Value& v, int op)) -{ - if(FindIndex(sChps(), fn) < 0) - sChps().Add(fn); -} - -struct sStyleCh : Moveable { - byte *status; - void (*init)(); -}; - -Vector& sChStyle() -{ - static Vector x; - return x; -} - -void ChRegisterStyle__(byte& state, byte& registered, void (*init)()) -{ - if(!registered) { - sStyleCh& s = sChStyle().Add(); - s.status = &state; - s.init = init; - registered = true; - } -} - -static bool sChInvalid = true; - -void ChInvalidate() -{ - sChInvalid = true; -} - -bool ChIsInvalidated() -{ - return sChInvalid; -} - -void ChReset() -{ - for(int i = 0; i < sChStyle().GetCount(); i++) - *sChStyle()[i].status = 0; - ChLookFn(StdChLookFn); -} - -void ChFinish() -{ - sChInvalid = false; - 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& simg) { - Image h = simg; - ImageBuffer img(h); - Unmultiply(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()); - Premultiply(w); - 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 +#include "Draw.h" + +NAMESPACE_UPP + +#define LTIMING(x) // RTIMING(x) + +#if defined(_DEBUG) && 0 +#include + +inline void LOGPNG(const char *name, const Image& m) +{ + PNGEncoder png; + png.SaveFile(ConfigFile(name) + ".png", m); +} + +#else + +#define LOGPNG(a, b) + +#endif + +struct ChImageMaker : ImageMaker { + Size sz; + Rect sr; + Image img; + + virtual String Key() const; + virtual Image Make() const; +}; + +String ChImageMaker::Key() const +{ + LTIMING("ChImageMaker::Key"); + StringBuffer b; + int64 id = img.GetSerialId(); + b.Cat((const char *)&id, sizeof(id)); + b.Cat((const char *)&sz.cx, sizeof(sz.cx)); + b.Cat((const char *)&sz.cy, sizeof(sz.cy)); + b.Cat((const char *)&sr.left, sizeof(sr.left)); + b.Cat((const char *)&sr.right, sizeof(sr.right)); + b.Cat((const char *)&sr.top, sizeof(sr.top)); + b.Cat((const char *)&sr.bottom, sizeof(sr.bottom)); + return b; +} + +Image ChImageMaker::Make() const +{ + LTIMING("ChImageMaker::Make"); + return Rescale(img, sz, sr); +} + +void ChDraw(Draw& w, int x, int y, int cx, int cy, const Image& img, const Rect& src) +{ + LTIMING("ChDraw"); + if(cx > 0 && cy > 0) { + #ifdef flagWINGL + w.DrawImage(x, y, cx, cy, img, src); + #else + ChImageMaker m; + m.sz = Size(cx, cy); + m.sr = src; + m.img = img; + w.DrawImage(x, y, MakeImage(m)); + #endif + } +} + +void ChDraw(Draw& w, const Rect& r, const Image& img, const Rect& src) +{ + ChDraw(w, r.left, r.top, r.GetWidth(), r.GetHeight(), img, src); +} + +struct sChLookWith { + Value look; + Image img; + Color (*colorfn)(int i); + int ii; + Color color; + Point offset; +}; + +Value ChLookWith(const Value& look, const Image& img, Point offset) +{ + sChLookWith x; + x.look = look; + x.img = img; + x.colorfn = NULL; + x.color = Null; + x.offset = offset; + return RawToValue(x); +} + +Value ChLookWith(const Value& look, const Image& img, Color color, Point offset) +{ + sChLookWith x; + x.look = look; + x.img = img; + x.colorfn = NULL; + x.color = color; + x.offset = offset; + return RawToValue(x); +} + +Value ChLookWith(const Value& look, const Image& img, Color (*color)(int i), int i, Point offset) +{ + sChLookWith x; + x.look = look; + x.img = img; + x.colorfn = color; + x.ii = i; + x.offset = offset; + return RawToValue(x); +} + +Value sChOp(Draw& w, const Rect& r, const Value& v, int op); + +struct sChBorder { + const ColorF *border; + Value face; +}; + +Value ChBorder(const ColorF *colors, const Value& face) +{ + sChBorder b; + b.border = colors; + b.face = face; + return RawToValue(b); +} + +Value StdChLookFn(Draw& w, const Rect& r, const Value& v, int op) +{ + if(IsType(v)) { + const sChLookWith& x = ValueTo(v); + if(op == LOOK_PAINT) { + LOGPNG(AsString(x.img.GetSerialId()), x.img); + ChPaint(w, r, x.look); + Point p = r.CenterPos(x.img.GetSize()) + x.offset; + if(x.colorfn) + w.DrawImage(p.x, p.y, x.img, (*x.colorfn)(x.ii)); + else + if(!IsNull(x.color)) + w.DrawImage(p.x, p.y, x.img, x.color); + else + w.DrawImage(p.x, p.y, x.img); + return 1; + } + return sChOp(w, r, x.look, op); + } + if(IsType(v)) { + sChBorder b = ValueTo(v); + int n = (int)(intptr_t)*b.border; + switch(op) { + case LOOK_PAINT: + ChPaint(w, r.Deflated(n), b.face); + case LOOK_PAINTEDGE: + DrawBorder(w, r, b.border); + return 0; + case LOOK_MARGINS: + return Rect(n, n, n, n); + case LOOK_ISBODYOPAQUE: + case LOOK_ISOPAQUE: + return false; + } + } + if(IsType(v)) { + Color c = v; + switch(op) { + case LOOK_PAINT: + w.DrawRect(r, c); + return 0; + case LOOK_PAINTEDGE: + DrawFrame(w, r, c); + return 0; + case LOOK_MARGINS: + return Rect(1, 1, 1, 1); + case LOOK_ISBODYOPAQUE: + case LOOK_ISOPAQUE: + return !IsNull(c); + } + } + if(IsType(v)) { + Image img = v; + Size isz = img.GetSize(); + Size sz = r.GetSize(); + Point p = img.GetHotSpot(); + Point p2 = img.Get2ndSpot(); + int tile = 0; + if(p2.x || p2.y) { + if(p2.x < p.x) { + Swap(p2.x, p.x); + tile = 1; + } + if(p2.y < p.y) { + Swap(p2.y, p.y); + tile += 2; + } + p2.x++; + p2.y++; + } + else { + p2.x = isz.cx - p.x; + p2.y = isz.cy - p.y; + if(p.x > isz.cx / 2) { + tile = 1; + p2.x = p.x; + p.x = isz.cx - p.x - 1; + } + if(p.y > isz.cy / 2) { + tile += 2; + p2.y = p.y; + p.y = isz.cy - p.y - 1; + } + } + if(op == LOOK_MARGINS) + return Rect(p.x, p.y, isz.cx - p2.x, isz.cy - p2.y); + if(op == LOOK_ISOPAQUE) + return img.GetKind() == IMAGE_OPAQUE; + if(IsNull(img)) + return 1; + if(op == LOOK_ISBODYOPAQUE) { + static VectorMap btc; + int64 key = img.GetSerialId(); + int q = btc.Find(key); + if(q < 0) { + bool opaque = true; + Rect m = ChMargins(img); + Rect r = img.GetSize(); + r.left += max(m.left, 0); + r.right -= max(m.right, 0); + r.top += m.top; + r.bottom -= m.bottom; + int cx = r.right - r.left; + if(cx >= 0) + for(int y = r.top; y < r.bottom && opaque; y++) { + const RGBA *s = img[y] + r.left; + const RGBA *e = s + cx; + while(s < e) { + if(s->a != 255) { + opaque = false; + break; + } + } + } + if(btc.GetCount() > 100) + btc.Clear(); + btc.Add(key, q); + return opaque; + } + return btc[q]; + } + if(op == LOOK_PAINT || op == LOOK_PAINTEDGE) { + LTIMING("ChPaint Image"); + w.Clipoff(r); + Rect sr(p, p2); + Size sz2(isz.cx - sr.right, isz.cy - sr.bottom); + Rect r = RectC(p.x, p.y, sz.cx - sr.left - sz2.cx, sz.cy - sr.top - sz2.cy); + int top = minmax(sz.cy / 2, 0, isz.cy); + int bottom = minmax(sz.cy - top, 0, isz.cy); + int yy = isz.cy - bottom; + int left = minmax(sz.cx / 2, 0, isz.cx); + int right = minmax(sz.cx - left, 0, isz.cx); + int xx = isz.cx - right; + if(!r.IsEmpty()) { + w.DrawImage(0, 0, img, RectC(0, 0, p.x, p.y)); + w.DrawImage(0, r.bottom, img, RectC(0, sr.bottom, p.x, sz2.cy)); + w.DrawImage(r.right, 0, img, RectC(sr.right, 0, sz2.cx, p.y)); + w.DrawImage(r.right, r.bottom, img, RectC(sr.right, sr.bottom, sz2.cx, sz2.cy)); + ChDraw(w, p.x, 0, r.Width(), p.y, img, RectC(p.x, 0, sr.Width(), p.y)); + ChDraw(w, p.x, r.bottom, r.Width(), sz2.cy, img, RectC(p.x, sr.bottom, sr.Width(), sz2.cy)); + ChDraw(w, 0, p.y, p.x, r.Height(), img, RectC(0, p.y, p.x, sr.Height())); + ChDraw(w, r.right, p.y, sz2.cx, r.Height(), img, + RectC(sr.right, p.y, sz2.cx, sr.Height())); + if(op == LOOK_PAINT) { + if(IsNull(r) || IsNull(sr)) + return 1; + if(tile) { + LTIMING("Ch-Tiles"); + LTIMING("Ch-Tiles"); + Size sz; + sz.cx = (tile & 1 ? sr : r).GetWidth(); + sz.cy = (tile & 2 ? sr : r).GetHeight(); + #ifdef flagWINGL + DrawTiles(w, r, img, sz, sr); + #else + img = Rescale(img, sz, sr); + DrawTiles(w, r, img); + #endif + } + else { + static VectorMap btc; + int64 key = img.GetSerialId(); + int q; + { + LTIMING("Find"); + q = btc.Find(key); + } + if(q < 0) { + LTIMING("ClassifyContent"); + q = ClassifyContent(img, sr); + if(btc.GetCount() > 100) + btc.Clear(); + btc.Add(key, q); + } + else + q = btc[q]; + switch(q) { + case IMAGECONTENT_VERTDUP|IMAGECONTENT_HORZDUP: + { + LTIMING("Ch-singlecolor"); + RGBA c = img[sr.top][sr.left]; + if(c.a == 255) { + w.DrawRect(r, c); + break; + } + } + case 0: + default: + ChDraw(w, r, img, sr); + break; + LTIMING("Ch-linedup"); + img = CachedRescalePaintOnly( + img, + Size((q & IMAGECONTENT_HORZDUP) ? max(min(40, r.GetWidth()), sr.GetWidth()) + : r.GetWidth(), + (q & IMAGECONTENT_VERTDUP) ? max(min(40, r.GetHeight()), sr.GetHeight()) + : r.GetHeight()), + sr + ); + LTIMING("Ch-linedup-drawtiles"); + DrawTiles(w, r, img); + break; + } + } + } + } + else + if(r.left < r.right) { + w.DrawImage(0, 0, img, RectC(0, 0, p.x, top)); + w.DrawImage(0, sz.cy - bottom, img, RectC(0, yy, p.x, bottom)); + w.DrawImage(r.right, 0, img, RectC(sr.right, 0, sz2.cx, top)); + w.DrawImage(r.right, sz.cy - bottom, img, RectC(sr.right, yy, sz2.cx, bottom)); + ChDraw(w, p.x, 0, r.Width(), top, img, RectC(p.x, 0, sr.Width(), top)); + ChDraw(w, p.x, sz.cy - bottom, r.Width(), bottom, img, RectC(p.x, yy, sr.Width(), bottom)); + } + else + if(r.top < r.bottom) { + w.DrawImage(0, 0, img, RectC(0, 0, left, p.y)); + w.DrawImage(0, r.bottom, img, RectC(0, sr.bottom, left, sz2.cy)); + w.DrawImage(sz.cx - right, 0, img, RectC(xx, 0, right, p.y)); + w.DrawImage(sz.cx - right, r.bottom, img, RectC(xx, sr.bottom, right, sz2.cy)); + ChDraw(w, 0, p.y, left, r.Height(), img, RectC(0, p.y, left, sr.Height())); + ChDraw(w, sz.cx - right, p.y, right, r.Height(), img, RectC(xx, p.y, right, sr.Height())); + } + else { + w.DrawImage(0, 0, img, RectC(0, 0, left, top)); + w.DrawImage(0, sz.cy - bottom, img, RectC(0, yy, left, top)); + w.DrawImage(sz.cx - right, 0, img, RectC(xx, 0, right, top)); + w.DrawImage(sz.cx - right, sz.cy - bottom, img, RectC(xx, yy, right, bottom)); + } + w.End(); + return 1; + } + } + return Null; +} + +typedef Value (*ChPainterFn)(Draw& w, const Rect& r, const Value& v, int op); + +Vector& sChps() +{ + static Vector x; + return x; +} + +void ChLookFn(Value (*fn)(Draw& w, const Rect& r, const Value& v, int op)) +{ + if(FindIndex(sChps(), fn) < 0) + sChps().Add(fn); +} + +struct sStyleCh : Moveable { + byte *status; + void (*init)(); +}; + +Vector& sChStyle() +{ + static Vector x; + return x; +} + +void ChRegisterStyle__(byte& state, byte& registered, void (*init)()) +{ + if(!registered) { + sStyleCh& s = sChStyle().Add(); + s.status = &state; + s.init = init; + registered = true; + } +} + +static bool sChInvalid = true; + +void ChInvalidate() +{ + sChInvalid = true; +} + +bool ChIsInvalidated() +{ + return sChInvalid; +} + +static bool sLabelTextColorMismatch; + +bool IsLabelTextColorMismatch() +{ + return sLabelTextColorMismatch; +} + +static bool sIsDarkColorFace; + +bool IsDarkColorFace() +{ + return sIsDarkColorFace; +} + +void ChReset() +{ + for(int i = 0; i < sChStyle().GetCount(); i++) + *sChStyle()[i].status = 0; + ChLookFn(StdChLookFn); +} + +void ChFinish() +{ + sChInvalid = false; + for(int i = 0; i < sChStyle().GetCount(); i++) + sChStyle()[i].init(); + sIsDarkColorFace = IsDark(SColorFace()); + sLabelTextColorMismatch = IsDark(SColorText()) != IsDark(SColorLabel()); +} + +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& simg) { + Image h = simg; + ImageBuffer img(h); + Unmultiply(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()); + Premultiply(w); + return w; +} + +void Override(Iml& target, Iml& source, bool colored) +{ + for(int i = 0; i < target.GetCount(); i++) { + int q = source.Find(target.GetId(i)); + if(q >= 0) { + Image m = source.Get(q); + if(colored) + m = AdjustColors(m); + target.Set(i, m); + } + } +} + +void ColoredOverride(Iml& target, Iml& source) +{ + Override(target, source, true); +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Draw/Cham.h b/uppsrc/Draw/Cham.h index 7c10cfbb3..1a1b5e6f8 100644 --- a/uppsrc/Draw/Cham.h +++ b/uppsrc/Draw/Cham.h @@ -1,120 +1,122 @@ -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); - -void ChInvalidate(); -bool ChIsInvalidated(); - -template -struct ChStyle { - byte status; - byte registered; - T *standard; - - const T& Standard() const { return *standard; } - T& Write() const { T& x = *(T *)this; x.status = 2; ChInvalidate(); 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::type& klass::style() \ -{ \ - static COMBINE5(klass, __, type, __, style) b, standard; \ - if(b.status == 0) { \ - ChRegisterStyle__(b.status, b.registered, COMBINE5(klass, __, type, __, style)::InitIt); \ - b.Init(); \ - b.status = 1; \ - standard = b; \ - standard.standard = b.standard = &standard; \ - } \ - return b; \ -} \ -\ -void COMBINE5(klass, __, type, __, style)::Init() - -#define CH_VAR(chtype, type, name, init) \ -chtype& COMBINE(ch_var__, name)(); \ -void COMBINE(ch_init__, name)() { \ - COMBINE(ch_var__, name)(); \ -} \ -\ -chtype& COMBINE(ch_var__, name)() { \ - static chtype b; \ - if(b.status == 0) { \ - ChRegisterStyle__(b.status, b.registered, COMBINE(ch_init__, name)); \ - b.value = init; \ - b.status = 1; \ - } \ - return b; \ -} \ -\ -type name() { return COMBINE(ch_var__, name)().value; } \ -void COMBINE(name, _Write)(type v) { COMBINE(ch_var__, name)().Write().value = v; } - -struct ChColor : ChStyle { Color value; }; -#define CH_COLOR(name, init) CH_VAR(ChColor, Color, name, init) - -struct ChInt : ChStyle { int value; }; -#define CH_INT(name, init) CH_VAR(ChInt, int, name, init) - -struct ChValue : ChStyle { Value value; }; -#define CH_VALUE(name, init) CH_VAR(ChValue, Value, name, init) - -struct ChImage : ChStyle { Image value; }; -#define CH_IMAGE(name, init) CH_VAR(ChImage, Image, name, init) - -void ChPaint(Draw& w, const Rect& r, const Value& element); -void ChPaint(Draw& w, int x, int y, int cx, int cy, const Value& element); - -Value ChLookWith(const Value& look, const Image& img, Point offset = Point(0, 0)); -Value ChLookWith(const Value& look, const Image& img, Color color, Point offset = Point(0, 0)); -Value ChLookWith(const Value& look, const Image& img, Color (*color)(int i), int i, Point offset = Point(0, 0)); - -//private: -void ChRegisterStyle__(byte& state, byte& registered, void (*init)()); - -Value ChBorder(const ColorF *colors, const Value& face = SColorFace()); +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); + +void ChInvalidate(); +bool ChIsInvalidated(); +bool IsLabelTextColorMismatch(); +bool IsDarkColorFace(); + +template +struct ChStyle { + byte status; + byte registered; + T *standard; + + const T& Standard() const { return *standard; } + T& Write() const { T& x = *(T *)this; x.status = 2; ChInvalidate(); 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::type& klass::style() \ +{ \ + static COMBINE5(klass, __, type, __, style) b, standard; \ + if(b.status == 0) { \ + ChRegisterStyle__(b.status, b.registered, COMBINE5(klass, __, type, __, style)::InitIt); \ + b.Init(); \ + b.status = 1; \ + standard = b; \ + standard.standard = b.standard = &standard; \ + } \ + return b; \ +} \ +\ +void COMBINE5(klass, __, type, __, style)::Init() + +#define CH_VAR(chtype, type, name, init) \ +chtype& COMBINE(ch_var__, name)(); \ +void COMBINE(ch_init__, name)() { \ + COMBINE(ch_var__, name)(); \ +} \ +\ +chtype& COMBINE(ch_var__, name)() { \ + static chtype b; \ + if(b.status == 0) { \ + ChRegisterStyle__(b.status, b.registered, COMBINE(ch_init__, name)); \ + b.value = init; \ + b.status = 1; \ + } \ + return b; \ +} \ +\ +type name() { return COMBINE(ch_var__, name)().value; } \ +void COMBINE(name, _Write)(type v) { COMBINE(ch_var__, name)().Write().value = v; } + +struct ChColor : ChStyle { Color value; }; +#define CH_COLOR(name, init) CH_VAR(ChColor, Color, name, init) + +struct ChInt : ChStyle { int value; }; +#define CH_INT(name, init) CH_VAR(ChInt, int, name, init) + +struct ChValue : ChStyle { Value value; }; +#define CH_VALUE(name, init) CH_VAR(ChValue, Value, name, init) + +struct ChImage : ChStyle { Image value; }; +#define CH_IMAGE(name, init) CH_VAR(ChImage, Image, name, init) + +void ChPaint(Draw& w, const Rect& r, const Value& element); +void ChPaint(Draw& w, int x, int y, int cx, int cy, const Value& element); + +Value ChLookWith(const Value& look, const Image& img, Point offset = Point(0, 0)); +Value ChLookWith(const Value& look, const Image& img, Color color, Point offset = Point(0, 0)); +Value ChLookWith(const Value& look, const Image& img, Color (*color)(int i), int i, Point offset = Point(0, 0)); + +//private: +void ChRegisterStyle__(byte& state, byte& registered, void (*init)()); + +Value ChBorder(const ColorF *colors, const Value& face = SColorFace()); diff --git a/uppsrc/Draw/ImageOp.cpp b/uppsrc/Draw/ImageOp.cpp index 27175a19f..3cde5c29e 100644 --- a/uppsrc/Draw/ImageOp.cpp +++ b/uppsrc/Draw/ImageOp.cpp @@ -1,687 +1,726 @@ -#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, const RGBA& rgba) -{ - ImageBuffer ib(sz); - Fill(~ib, rgba, ib.GetLength()); - return ib; -} - -Image CreateImage(Size sz, Color color) -{ - return CreateImage(sz, (RGBA)color); -} - -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++; - } - ib.SetHotSpots(src); - 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; - } - } - ib.SetHotSpots(img); - 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++; - } - w.SetHotSpots(img); - 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++; - } - w.SetHotSpots(img); - 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++; - } - w.SetHotSpots(img); - 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); - w.SetHotSpots(img); - 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); - w.SetHotSpots(img); - 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 > 0x80 && s.r + s.g + s.b < 500) { - t.r = t.g = t.b = 128; - t.a = s.a; - return t; - } - s = mx[0][0]; - if(s.a > 0x80 && s.r + s.g + s.b < 500) { - t.r = t.g = t.b = 255; - t.a = s.a; - return t; - } - Zero(t); - return t; -} - -Image Etched(const Image& img) -{ - sEtchFilter ef; - return Premultiply(Filter(Unmultiply(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; - } - Premultiply(w); - w.SetHotSpots(img); - 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 Rotate180(const Image& orig) -{ - Size sz = orig.GetSize(); - ImageBuffer dest(sz); - for(int rw = 0; rw < sz.cy; rw++) - for(int cl = 0; cl < sz.cx; cl++) - dest[rw][cl] = orig[sz.cy - rw - 1][sz.cx - cl - 1]; - return dest; -} - -Image MirrorHorz(const Image& img) -{ - Size sz = img.GetSize(); - Image h = img; - ImageBuffer ib(h); - for(int y = 0; y < sz.cy; y++) { - RGBA *b = ib[y] + 0; - RGBA *e = b + sz.cx - 1; - while(b < e) { - Swap(*b, *e); - b++; - e--; - } - } - return ib; -} - -Image MirrorVert(const Image& img) -{ - Size sz = img.GetSize(); - Image h = img; - ImageBuffer ib(h); - - for(int y = 0; y < sz.cy / 2; y++) { - RGBA *b = ib[y]; - RGBA *e = ib[sz.cy - y - 1]; - for(int x = 0; x < sz.cx; x++) { - Swap(*b, *e); - b++; - e++; - } - } - return ib; -} - -Image Magnify(const Image& img, int nx, int ny) -{ - if(nx == 1 && ny == 1) - return img; - if(nx == 0 || ny == 0) - return Image(); - Size sz = img.GetSize(); - bool xdown = nx < 0; - nx = abs(nx); - int ncx = xdown ? sz.cx / nx : sz.cx * nx; - ImageBuffer b(ncx, sz.cy * ny); - const RGBA *s = ~img; - const RGBA *e = s + img.GetLength(); - RGBA *t = ~b; - while(s < e) { - RGBA *q = t; - const RGBA *le = s + sz.cx; - while(s < le) { - Fill(q, *s, nx); - q += nx; - s++; - } - for(int n = ny - 1; n--;) { - memcpy(q, t, ncx * sizeof(RGBA)); - q += ncx; - } - t = q; - } - return b; -} - -static Pointf Cvp(double x, double y, double sina, double cosa) -{ - return Pointf(x * cosa + y * sina, -x * sina + y * cosa); -} - -Image Rotate(const Image& m, int angle) -{ - Size isz = m.GetSize(); - Point center = isz / 2; - Pointf centerf = Pointf(Point(isz)) / 2.0; - double sina, cosa; - Draw::SinCos(-angle, sina, cosa); - Pointf p1 = Cvp(-centerf.x, -centerf.y, sina, cosa); - Pointf p2 = Cvp(centerf.x, -centerf.y, sina, cosa); - Size sz2 = Size(2 * (int)max(tabs(p1.x), tabs(p2.x)), - 2 * (int)max(tabs(p1.y), tabs(p2.y))); - Pointf dcenterf = Sizef(sz2) / 2.0; - Point dcenter = sz2 / 2; - - ImageBuffer ib(sz2); - Fill(~ib, RGBAZero(), ib.GetLength()); - RGBA *t = ~ib; - Draw::SinCos(angle, sina, cosa); - int sini = int(sina * 128); - int cosi = int(cosa * 128); - Buffer xmx(sz2.cx); - Buffer xmy(sz2.cx); - for(int x = 0; x < sz2.cx; x++) { - int xx = x + x - sz2.cx; - xmx[x] = int(xx * cosi); - xmy[x] = -int(xx * sini); - } - for(int y = 0; y < sz2.cy; y++) { - int yy = y + y - sz2.cy; - int ymx = int(yy * sini) + (isz.cx << 7); - int ymy = int(yy * cosi) + (isz.cy << 7); - for(int x = 0; x < sz2.cx; x++) { - int xs = (xmx[x] + ymx) >> 8; - int ys = (xmy[x] + ymy) >> 8; - *t++ = xs >= 0 && xs < isz.cx && ys >= 0 && ys < isz.cy ? m[ys][xs] : RGBAZero(); - } - } - return ib; -} - -END_UPP_NAMESPACE +#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, const RGBA& rgba) +{ + ImageBuffer ib(sz); + Fill(~ib, rgba, ib.GetLength()); + return ib; +} + +Image CreateImage(Size sz, Color color) +{ + return CreateImage(sz, (RGBA)color); +} + +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++; + } + ib.SetHotSpots(src); + 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; + } + } + ib.SetHotSpots(img); + 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++; + } + w.SetHotSpots(img); + 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++; + } + w.SetHotSpots(img); + 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++; + } + w.SetHotSpots(img); + 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); + w.SetHotSpots(img); + return w; +} + +Image AdjustForDarkBk(const Image& img) +{ + const RGBA *s = ~img; + const RGBA *e = s + img.GetLength(); + ImageBuffer w(img.GetSize()); + RGBA *t = w; + while(s < e) { + RGBA h = *s; + Unmultiply(&h, &h, 1); + int q = Grayscale(*s); + if(q < 40) { + int lvl0 = max(s->r, max(s->g, s->b)); + int l = 255 - lvl0; + t->r = Saturate255(l + s->r); + t->g = Saturate255(l + s->g); + t->b = Saturate255(l + s->b); + } + else + if(q > 216) { + int lvl0 = min(s->r, min(s->g, s->b)); + int l = 255 - lvl0; + t->r = Saturate255(l + s->r - lvl0); + t->g = Saturate255(l + s->g - lvl0); + t->b = Saturate255(l + s->b - lvl0); + } + else { + t->r = s->r; + t->g = s->g; + t->b = s->b; + } + t->a = s->a; + t++; + s++; + } + Premultiply(w); + w.SetHotSpots(img); + 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); + w.SetHotSpots(img); + 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 > 0x80 && s.r + s.g + s.b < 500) { + t.r = t.g = t.b = 128; + t.a = s.a; + return t; + } + s = mx[0][0]; + if(s.a > 0x80 && s.r + s.g + s.b < 500) { + t.r = t.g = t.b = 255; + t.a = s.a; + return t; + } + Zero(t); + return t; +} + +Image Etched(const Image& img) +{ + sEtchFilter ef; + return Premultiply(Filter(Unmultiply(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; + } + Premultiply(w); + w.SetHotSpots(img); + 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 Rotate180(const Image& orig) +{ + Size sz = orig.GetSize(); + ImageBuffer dest(sz); + for(int rw = 0; rw < sz.cy; rw++) + for(int cl = 0; cl < sz.cx; cl++) + dest[rw][cl] = orig[sz.cy - rw - 1][sz.cx - cl - 1]; + return dest; +} + +Image MirrorHorz(const Image& img) +{ + Size sz = img.GetSize(); + Image h = img; + ImageBuffer ib(h); + for(int y = 0; y < sz.cy; y++) { + RGBA *b = ib[y] + 0; + RGBA *e = b + sz.cx - 1; + while(b < e) { + Swap(*b, *e); + b++; + e--; + } + } + return ib; +} + +Image MirrorVert(const Image& img) +{ + Size sz = img.GetSize(); + Image h = img; + ImageBuffer ib(h); + + for(int y = 0; y < sz.cy / 2; y++) { + RGBA *b = ib[y]; + RGBA *e = ib[sz.cy - y - 1]; + for(int x = 0; x < sz.cx; x++) { + Swap(*b, *e); + b++; + e++; + } + } + return ib; +} + +Image Magnify(const Image& img, int nx, int ny) +{ + if(nx == 1 && ny == 1) + return img; + if(nx == 0 || ny == 0) + return Image(); + Size sz = img.GetSize(); + bool xdown = nx < 0; + nx = abs(nx); + int ncx = xdown ? sz.cx / nx : sz.cx * nx; + ImageBuffer b(ncx, sz.cy * ny); + const RGBA *s = ~img; + const RGBA *e = s + img.GetLength(); + RGBA *t = ~b; + while(s < e) { + RGBA *q = t; + const RGBA *le = s + sz.cx; + while(s < le) { + Fill(q, *s, nx); + q += nx; + s++; + } + for(int n = ny - 1; n--;) { + memcpy(q, t, ncx * sizeof(RGBA)); + q += ncx; + } + t = q; + } + return b; +} + +static Pointf Cvp(double x, double y, double sina, double cosa) +{ + return Pointf(x * cosa + y * sina, -x * sina + y * cosa); +} + +Image Rotate(const Image& m, int angle) +{ + Size isz = m.GetSize(); + Point center = isz / 2; + Pointf centerf = Pointf(Point(isz)) / 2.0; + double sina, cosa; + Draw::SinCos(-angle, sina, cosa); + Pointf p1 = Cvp(-centerf.x, -centerf.y, sina, cosa); + Pointf p2 = Cvp(centerf.x, -centerf.y, sina, cosa); + Size sz2 = Size(2 * (int)max(tabs(p1.x), tabs(p2.x)), + 2 * (int)max(tabs(p1.y), tabs(p2.y))); + Pointf dcenterf = Sizef(sz2) / 2.0; + Point dcenter = sz2 / 2; + + ImageBuffer ib(sz2); + Fill(~ib, RGBAZero(), ib.GetLength()); + RGBA *t = ~ib; + Draw::SinCos(angle, sina, cosa); + int sini = int(sina * 128); + int cosi = int(cosa * 128); + Buffer xmx(sz2.cx); + Buffer xmy(sz2.cx); + for(int x = 0; x < sz2.cx; x++) { + int xx = x + x - sz2.cx; + xmx[x] = int(xx * cosi); + xmy[x] = -int(xx * sini); + } + for(int y = 0; y < sz2.cy; y++) { + int yy = y + y - sz2.cy; + int ymx = int(yy * sini) + (isz.cx << 7); + int ymy = int(yy * cosi) + (isz.cy << 7); + for(int x = 0; x < sz2.cx; x++) { + int xs = (xmx[x] + ymx) >> 8; + int ys = (xmy[x] + ymy) >> 8; + *t++ = xs >= 0 && xs < isz.cx && ys >= 0 && ys < isz.cy ? m[ys][xs] : RGBAZero(); + } + } + return ib; +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Draw/ImageOp.h b/uppsrc/Draw/ImageOp.h index c409b214b..f55996d6e 100644 --- a/uppsrc/Draw/ImageOp.h +++ b/uppsrc/Draw/ImageOp.h @@ -1,160 +1,159 @@ -Image CreateImage(Size sz, const RGBA& rgba); -Image CreateImage(Size sz, Color color); -Image SetColorKeepAlpha(const Image& img, Color c); - -Image WithHotSpots(const Image& m, int x1, int y1, int x2, int y2); -Image WithHotSpot(const Image& m, int x1, int y1); - -void Over(ImageBuffer& dest, Point p, const Image& src, const Rect& srect); -void Copy(ImageBuffer& dest, Point p, const Image& src, const Rect& srect); - -void Copy(Image& dest, Point p, const Image& src, const Rect& srect); -void Over(Image& dest, Point p, const Image& src, const Rect& srect); - -void OverStraightOpaque(ImageBuffer& dest, Point p, const Image& src, const Rect& srect); -void OverStraightOpaque(Image& dest, Point p, const Image& _src, const Rect& srect); - -void Crop(RasterEncoder& tgt, Raster& img, const Rect& rc); -Image Crop(const Image& img, const Rect& rc); -Image Crop(const Image& img, int x, int y, int cx, int cy); - -Image ColorMask(const Image& src, Color transparent); - -void CanvasSize(RasterEncoder& tgt, Raster& img, int cx, int cy); -Image CanvasSize(const Image& img, int cx, int cy); - -Image AssignAlpha(const Image& img, const Image& new_alpha); - -Image Grayscale(const Image& img); -Image Grayscale(const Image& img, int amount); -Image Contrast(const Image& img, int amount = 256); - -Image HorzFadeOut(int cx, int cy, Color color); -Image HorzFadeOut(Size sz, Color color); - -class RescaleImage { - Raster *src; - Size tsz; - Vector horz; - Vector vert; - void (*row_proc)(dword *dest, const RGBA *src, const dword *map); - Size size; - int cx4; - int count; - int segment; - int entry; - int step; - int segspan; - bool bigseg; - Buffer row_buffers; - int first; - int full; - const dword *offsets; - int offset; - int y; - - struct Ln { - RasterLine line; - int ii; - }; - - Ln cache[4]; - int cii; - const RGBA *GetLine(int i); - -public: - void Create(Size sz, Raster& src, const Rect& src_rc); - void Get(RGBA *line); -}; - -void DrawRasterData(Draw& w, int x, int y, int cx, int cy, const String& data); - -bool Rescale(RasterEncoder& tgt, Size sz, Raster& src, const Rect& src_rc, - Gate2 progress = false); -Image Rescale(const Image& src, Size sz, const Rect& src_rc, Gate2 progress = false); -Image Rescale(const Image& src, Size sz, Gate2 progress = false); -Image Rescale(const Image& src, int cx, int cy, Gate2 progress = false); - -struct ImageFilter9 { - virtual RGBA operator()(const RGBA **mx) = 0; - virtual ~ImageFilter9() {} -}; - -Image Filter(const Image& img, ImageFilter9& filter); -void Filter(RasterEncoder& target, Raster& src, ImageFilter9& filter); - -Image Etched(const Image& img); -Image Sharpen(const Image& img, int amount = 100); - -Image RotateClockwise(const Image& img); -Image RotateAntiClockwise(const Image& img); -Image Rotate180(const Image& orig); -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 SweepMkImageCache(); - -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); +Image CreateImage(Size sz, const RGBA& rgba); +Image CreateImage(Size sz, Color color); +Image SetColorKeepAlpha(const Image& img, Color c); + +Image WithHotSpots(const Image& m, int x1, int y1, int x2, int y2); +Image WithHotSpot(const Image& m, int x1, int y1); + +void Over(ImageBuffer& dest, Point p, const Image& src, const Rect& srect); +void Copy(ImageBuffer& dest, Point p, const Image& src, const Rect& srect); + +void Copy(Image& dest, Point p, const Image& src, const Rect& srect); +void Over(Image& dest, Point p, const Image& src, const Rect& srect); + +void OverStraightOpaque(ImageBuffer& dest, Point p, const Image& src, const Rect& srect); +void OverStraightOpaque(Image& dest, Point p, const Image& _src, const Rect& srect); + +void Crop(RasterEncoder& tgt, Raster& img, const Rect& rc); +Image Crop(const Image& img, const Rect& rc); +Image Crop(const Image& img, int x, int y, int cx, int cy); + +Image ColorMask(const Image& src, Color transparent); + +void CanvasSize(RasterEncoder& tgt, Raster& img, int cx, int cy); +Image CanvasSize(const Image& img, int cx, int cy); + +Image AssignAlpha(const Image& img, const Image& new_alpha); + +Image Grayscale(const Image& img); +Image Grayscale(const Image& img, int amount); +Image Contrast(const Image& img, int amount = 256); + +Image HorzFadeOut(int cx, int cy, Color color); +Image HorzFadeOut(Size sz, Color color); + +class RescaleImage { + Raster *src; + Size tsz; + Vector horz; + Vector vert; + void (*row_proc)(dword *dest, const RGBA *src, const dword *map); + Size size; + int cx4; + int count; + int segment; + int entry; + int step; + int segspan; + bool bigseg; + Buffer row_buffers; + int first; + int full; + const dword *offsets; + int offset; + int y; + + struct Ln { + RasterLine line; + int ii; + }; + + Ln cache[4]; + int cii; + const RGBA *GetLine(int i); + +public: + void Create(Size sz, Raster& src, const Rect& src_rc); + void Get(RGBA *line); +}; + +void DrawRasterData(Draw& w, int x, int y, int cx, int cy, const String& data); + +bool Rescale(RasterEncoder& tgt, Size sz, Raster& src, const Rect& src_rc, + Gate2 progress = false); +Image Rescale(const Image& src, Size sz, const Rect& src_rc, Gate2 progress = false); +Image Rescale(const Image& src, Size sz, Gate2 progress = false); +Image Rescale(const Image& src, int cx, int cy, Gate2 progress = false); + +struct ImageFilter9 { + virtual RGBA operator()(const RGBA **mx) = 0; + virtual ~ImageFilter9() {} +}; + +Image Filter(const Image& img, ImageFilter9& filter); +void Filter(RasterEncoder& target, Raster& src, ImageFilter9& filter); + +Image Etched(const Image& img); +Image Sharpen(const Image& img, int amount = 100); + +Image RotateClockwise(const Image& img); +Image RotateAntiClockwise(const Image& img); +Image Rotate180(const Image& orig); +Image MirrorHorz(const Image& img); +Image MirrorVert(const Image& img); +Image Rotate(const Image& m, int angle); + +Image Colorize(const Image& img, Color color, int alpha = 100); +Image Equalight(const Image& img, int thold = 10); +Image AdjustForDarkBk(const Image& img); + +//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 SweepMkImageCache(); + +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);