diff --git a/uppsrc/CtrlCore/CocoDrawText.mm b/uppsrc/CtrlCore/CocoDrawText.mm index 3e3a063c4..139861bf0 100644 --- a/uppsrc/CtrlCore/CocoDrawText.mm +++ b/uppsrc/CtrlCore/CocoDrawText.mm @@ -63,7 +63,7 @@ CGGlyph GetCharGlyph(CTFontRef ctfont, int chr) return glyph_index; } -GlyphInfo GetGlyphInfoSys(CTFontRef ctfont, int chr, bool bold_synth) +GlyphInfo GetGlyphInfoSys(CTFontRef ctfont, int chr, bool bold_synth, CGRect *bounds = NULL) { GlyphInfo gi; gi.lspc = gi.rspc = 0; @@ -79,6 +79,10 @@ GlyphInfo GetGlyphInfoSys(CTFontRef ctfont, int chr, bool bold_synth) gi.glyphi = glyph_index; if(bold_synth) gi.width++; + if(bounds) + CTFontGetBoundingRectsForGlyphs(ctfont, kCTFontOrientationHorizontal, + &glyph_index, bounds, 1); + } } return gi; @@ -101,10 +105,33 @@ CommonFontInfo GetFontInfoSys(Font font) DDUMP(CTFontGetUnderlinePosition(ctfont)); DDUMP(MakeRect(CTFontGetBoundingBox(ctfont))); DDUMPHEX(CTFontGetSymbolicTraits(ctfont)); + DDUMP(font); + CGRect cr = CTFontGetBoundingBox(ctfont); + DDUMP(cr.origin.y); + DDUMP(cr.size.height); + DDUMP(cr.origin.y + cr.size.height); #endif fi.descent = ceil(CTFontGetDescent(ctfont)); fi.ascent = ceil(CTFontGetAscent(ctfont)); fi.external = ceil(CTFontGetLeading(ctfont)); + + // Some MacOS fonts have really weird ascent/descents (namely stadard GUI font...) + // let us fix it by testing typical charactes bounding boxes + + static WString descent_test = "yjgp"; + CGRect bb; + for(int i = 0; i < descent_test.GetCount(); i++) + if(GetGlyphInfoSys(ctfont, descent_test[i], synth && font.IsBold(), &bb).IsNormal()) + fi.descent = max(fi.descent, (int)ceil(-bb.origin.y)); + + int ascent = fi.ascent; + static WString ascent_test = "ÀÁÂÃÄË"; + for(int i = 0; i < ascent_test.GetCount(); i++) + if(GetGlyphInfoSys(ctfont, ascent_test[i], synth && font.IsBold(), &bb).IsNormal()) + ascent = max(ascent, (int)ceil(bb.origin.y + bb.size.height)); + + fi.ascent = ascent; + fi.internal = 0; fi.overhang = 0; fi.maxwidth = GetGlyphInfoSys(ctfont, 'W', synth && font.IsBold()).width; // TODO? @@ -138,7 +165,7 @@ Vector GetAllFacesSys() { Index facename; - facename.Add("Arial"); // TODO: This should be default GUI font + facename.Add("Arial"); // This is default GUI font, changed afterward facename.Add("Times New Roman"); facename.Add("Arial"); facename.Add("Courier New"); diff --git a/uppsrc/CtrlCore/cocotodo.txt b/uppsrc/CtrlCore/cocotodo.txt index 30a2732c7..793fad9b0 100644 --- a/uppsrc/CtrlCore/cocotodo.txt +++ b/uppsrc/CtrlCore/cocotodo.txt @@ -1,5 +1,8 @@ sooner: +- Assist popup has vertically missaligned text +- initial focus in uword +- clang install - Information etc.. Images - Ctrl gets stuck - fix package organiser link options (joining link options missing space) diff --git a/uppsrc/CtrlLib/ChCoco.cpp b/uppsrc/CtrlLib/ChCoco.cpp index 86c712e1e..2e8e34269 100644 --- a/uppsrc/CtrlLib/ChCoco.cpp +++ b/uppsrc/CtrlLib/ChCoco.cpp @@ -85,7 +85,7 @@ void CocoButton(Button::Style& s, int type, int value) s.look[i] = h[i]; Image gg = CreateImage(h[i].GetSize(), SColorFace()); Over(gg, h[i]); - s.textcolor[i] = i == CTRL_DISABLED ? SColorDisabled() + s.monocolor[i] = s.textcolor[i] = i == CTRL_DISABLED ? SColorDisabled() : Grayscale(AvgColor(gg, h[i].GetSize().cy / 3)) > 160 ? SColorText() : White(); } @@ -103,6 +103,25 @@ Color CocoColor(int k, Color bg = SColorFace()) return AvgColor(Coco_ThemeImage(bg, 16, 16, 0, COCO_NSCOLOR, k)); } +Color GetInkColor(const Image& m) +{ + int x = m.GetSize().cx / 2; + bool dark = !IsDark(SColorText()); + int best = 1000; + Color bestc = SColorText(); + for(int y = 0; y < m.GetHeight(); y++) { + Color c = m[y][x]; + int g = Grayscale(c); + if(dark) + g = 255 - g; + if(g < best) { + best = g; + bestc = c; + } + } + return bestc; +} + void ChHostSkin() { CtrlImg::Reset(); @@ -115,6 +134,8 @@ void ChHostSkin() DUMP(Coco_Metric(0)); // kThemeMetricScrollBarWidth DUMP(Coco_Metric(7)); // kThemeMetricFocusRectOutset DUMP(Coco_Metric(19)); // kThemeMetricPushButtonHeight + + int button_height = Coco_Metric(19); // kThemeMetricPushButtonHeight SwapOKCancel_Write(true); @@ -185,6 +206,7 @@ void ChHostSkin() Image thumb = Coco_ThemeImage(s.barsize, 50, 0, COCO_SCROLLTHUMB, 0, status); Rect bounds = FindBounds(thumb); thumb = Crop(thumb, Rect(0, bounds.top, thumb.GetWidth(), bounds.bottom)); + thumb = AddMargins(thumb, 0, 1, 0, 1, RGBAZero()); s.vthumb[status] = Hot3(thumb); s.hupper[status] = s.hlower[status] = @@ -192,9 +214,45 @@ void ChHostSkin() thumb = Coco_ThemeImage(50, s.barsize, 0, COCO_SCROLLTHUMB, 1, status); bounds = FindBounds(thumb); thumb = Crop(thumb, Rect(bounds.left, 0, bounds.right, thumb.GetHeight())); + thumb = AddMargins(thumb, 1, 0, 1, 0 , RGBAZero()); s.hthumb[status] = Hot3(thumb); } } + + ColoredOverride(CtrlsImg::Iml(), CtrlsImg::Iml()); + + { + + Color e = GetInkColor(Coco_ThemeImage(SColorFace(), 100, 50, 10, COCO_COMBOBOX)); + CtrlsImg::Set(CtrlsImg::I_EFE, + WithHotSpots(AddMargins(CreateImage(Size(1, 1), SColorPaper()), 1, 1, 1, 1, e), + 1, 1, 0, 0)); + + CtrlsImg::Set(CtrlsImg::I_VE, + WithHotSpots(AddMargins(CreateImage(Size(3, 3), SColorPaper()), 1, 1, 1, 1, e), + 2, 2, 0, 0)); + + MultiButton::Style& s = MultiButton::StyleDefault().Write(); +// s.trivialsep = true; +// s.edge[0] = Null; + s.clipedge = true; + s.border = s.trivialborder = 0; + + for(int i = CTRL_NORMAL; i <= CTRL_DISABLED; i++) { + Image m = Coco_ThemeImage(150, button_height + 1, 0, COCO_BUTTON, 1, i); // TODO: ChWithOffset... + Size isz = m.GetSize(); + int x3 = isz.cx / 3; + s.left[i] = Hot3(Crop(m, 0, 0, x3, isz.cy)); + s.trivial[i] = s.look[i] = s.right[i] = Hot3(Crop(m, 2 * x3, 0, isz.cx - 2 * x3, isz.cy)); + m = Crop(m, x3, 0, x3, isz.cy); + s.lmiddle[i] = Hot3(AddMargins(m, 1, 0, 0, 0, SColorPaper())); + s.rmiddle[i] = Hot3(AddMargins(m, 0, 0, 1, 0, SColorPaper())); + + s.monocolor[i] = s.fmonocolor[i] = Button::StyleOk().monocolor[i]; + // Win32Look(s.look[i], XP_COMBOBOX, 4, i + 1); + } + } + // DDUMP(Coco_ThemeColor(1)); diff --git a/uppsrc/CtrlLib/ChCocoMM.h b/uppsrc/CtrlLib/ChCocoMM.h index b20c40bc9..8ca447fe6 100644 --- a/uppsrc/CtrlLib/ChCocoMM.h +++ b/uppsrc/CtrlLib/ChCocoMM.h @@ -7,6 +7,7 @@ enum ChCocoControlTypes { COCO_RADIOBUTTON, COCO_BEVELBUTTON, COCO_ROUNDEDBUTTON, + COCO_COMBOBOX, COCO_SCROLLTHUMB, COCO_SCROLLTRACK, COCO_BRUSH, diff --git a/uppsrc/CtrlLib/ChCocoMM.mm b/uppsrc/CtrlLib/ChCocoMM.mm index 7cad221e8..e531795a5 100644 --- a/uppsrc/CtrlLib/ChCocoMM.mm +++ b/uppsrc/CtrlLib/ChCocoMM.mm @@ -94,6 +94,7 @@ void Coco_ThemePaint(void *cgcontext, const Upp::Rect& r, int type, int value, i COCO_RADIOBUTTON, (int)kThemeRadioButton, COCO_BEVELBUTTON, (int)kThemeBevelButtonMedium, COCO_ROUNDEDBUTTON, (int)kThemeRoundedBevelButton, + COCO_COMBOBOX, (int)kThemeComboBox, (int)kThemePushButtonNormal); #ifdef _DEBUG if(type < 0) diff --git a/uppsrc/CtrlLib/MultiButton.cpp b/uppsrc/CtrlLib/MultiButton.cpp index e9aa32712..c33d5f240 100644 --- a/uppsrc/CtrlLib/MultiButton.cpp +++ b/uppsrc/CtrlLib/MultiButton.cpp @@ -234,7 +234,7 @@ bool MultiButton::GetPos(SubButton& b, int& lx, int& rx, int& x, int& cx, int px if(b.visible) { cx = Nvl(b.cx, style->stdwidth + tsz.cx); if(IsNull(b.cx) && tsz.cx > 0 && !IsNull(b.img)) - cx += LB_IMAGE + LB_MARGIN; + cx += DPI(LB_IMAGE + LB_MARGIN); } else cx = 0; @@ -263,6 +263,18 @@ void MultiButton::GetPos(int ii, int& x, int& cx) } } +void MultiButton::GetLR(int& lx, int& rx) +{ + int border; + Metrics(border, lx, rx); + int x = 0; + int cx = 0; + for(int i = 0; i < button.GetCount(); i++) { + SubButton& b = button[i]; + GetPos(b, lx, rx, x, cx); + } +} + int MultiButton::ChState(int i) { bool frm = Frame(); @@ -343,8 +355,16 @@ Rect MultiButton::Paint0(Draw& w, bool getcr) int border, lx, rx; bool frm = Metrics(border, lx, rx); int mst = ChState(MAIN); - if(frm && !nobg && !getcr) + if(frm && !nobg && !getcr) { + if(style->clipedge) { + int l, r; + GetLR(l, r); + w.Clip(l, 0, r - l, sz.cy); + } ChPaint(w, sz, style->edge[style->activeedge ? mst : 0]); + if(style->clipedge) + w.End(); + } bool left = false; bool right = false; for(int i = 0; i < button.GetCount(); i++) { @@ -394,22 +414,24 @@ Rect MultiButton::Paint0(Draw& w, bool getcr) Image m = tsz.cx > 0 ? b.img : (Image)Nvl(b.img, CtrlsImg::DA()); Size isz = m.GetSize(); Point p = (st == CTRL_PRESSED) * style->pressoffset; - p.x += x + (cx - isz.cx - tsz.cx - (tsz.cx > 0 && isz.cx > 0 ? LB_IMAGE : 0)) / 2; + p.x += x + (cx - isz.cx - tsz.cx - (tsz.cx > 0 && isz.cx > 0 ? DPI(LB_IMAGE) : 0)) / 2; p.y += (sz.cy - isz.cy) / 2; if(b.left) { if(!left) p.x += style->loff; } else if(!right) p.x += style->roff; + + Color ink = frm ? style->fmonocolor[st] : style->monocolor[st]; if(b.monoimg || IsNull(b.img)) - w.DrawImage(p.x, p.y, m, frm ? style->fmonocolor[st] : style->monocolor[st]); + w.DrawImage(p.x, p.y, m, ink); else w.DrawImage(p.x, p.y, m); if(tsz.cx > 0) { if(isz.cx > 0) - p.x += isz.cx + LB_IMAGE; - w.DrawText(p.x, (sz.cy - tsz.cy) / 2, b.label); + p.x += isz.cx + DPI(LB_IMAGE); + w.DrawText(p.x, (sz.cy - tsz.cy) / 2, b.label, StdFont(), ink); } } (b.left ? left : right) = true; diff --git a/uppsrc/CtrlLib/MultiButton.h b/uppsrc/CtrlLib/MultiButton.h index 96618f182..03ec36e12 100644 --- a/uppsrc/CtrlLib/MultiButton.h +++ b/uppsrc/CtrlLib/MultiButton.h @@ -21,26 +21,27 @@ public: Value edge[4]; bool activeedge; Value look[4]; - Value left[4]; - Value lmiddle[4]; - Value right[4]; - Value rmiddle[4]; + Value left[4]; // leftmost button on the left side + Value lmiddle[4]; // other buttons on the left size + Value right[4]; // rightmost button on the right side + Value rmiddle[4]; // other buttons on the right size Value simple[4]; int border; Value trivial[4]; int trivialborder; - Color monocolor[4]; - Color fmonocolor[4]; - Point pressoffset; + Color monocolor[4]; // color of mono images and text in nonframe situation + Color fmonocolor[4]; // color of mono images and text in frame situation + Point pressoffset; // offset of images and text if button is pressed Value sep1, sep2; int sepm; - int stdwidth; + int stdwidth; // standard width of button bool trivialsep; bool usetrivial; Rect margin; int overpaint; int loff, roff; Color error; + bool clipedge; // Clip border edge so that it does not paint area where are buttons }; class SubButton { @@ -109,6 +110,7 @@ private: int FindButton(int px); void Margins(int& l, int& r); Rect ContentRect(); + void GetLR(int& lx, int& rx); bool GetPos(SubButton& b, int& lx, int& rx, int& x, int& cx, int px = -1); void GetPos(int ii, int& x, int& cx); int ChState(int i); diff --git a/uppsrc/Draw/FontInt.h b/uppsrc/Draw/FontInt.h index 90a882148..e76a57bb5 100644 --- a/uppsrc/Draw/FontInt.h +++ b/uppsrc/Draw/FontInt.h @@ -24,6 +24,7 @@ struct CommonFontInfo { bool fixedpitch; bool scaleable; bool ttf; + int aux; char path[256]; // optional }; diff --git a/uppsrc/Draw/ImageOp.cpp b/uppsrc/Draw/ImageOp.cpp index f50621469..6e7b04441 100644 --- a/uppsrc/Draw/ImageOp.cpp +++ b/uppsrc/Draw/ImageOp.cpp @@ -166,6 +166,15 @@ Image Crop(const Image& img, const Rect& rc) return WithResolution(tgt, img); } +Image AddMargins(const Image& img, int left, int top, int right, int bottom, RGBA color) +{ + Size sz = img.GetSize(); + ImageBuffer ib(sz.cx + left + right, sz.cy + top + bottom); + Fill(ib, color, ib.GetLength()); + Copy(ib, Point(left, top), img, img.GetSize()); + return ib; +} + Image Crop(const Image& img, int x, int y, int cx, int cy) { return Crop(img, RectC(x, y, cx, cy)); diff --git a/uppsrc/Draw/ImageOp.h b/uppsrc/Draw/ImageOp.h index 01887786c..0c8d1f34a 100644 --- a/uppsrc/Draw/ImageOp.h +++ b/uppsrc/Draw/ImageOp.h @@ -24,6 +24,8 @@ 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 AddMargins(const Image& img, int left, int top, int right, int bottom, RGBA color); + Rect FindBounds(const Image& m, RGBA bg = RGBAZero()); Image AutoCrop(const Image& m, RGBA bg = RGBAZero()); void AutoCrop(Image *m, int count, RGBA bg = RGBAZero());