ultimatepp/uppsrc/CtrlLib/ChCoco.cpp
2026-04-29 11:48:46 +02:00

278 lines
No EOL
7.6 KiB
C++

#include "CtrlLib.h"
#include "ChCocoMM.h"
#ifdef GUI_COCOA
namespace Upp {
bool IsCocoTransparent(const RGBA *s, int add, int n)
{
while(n-- > 0) {
if(s->a > 10)
return false;
s += add;
}
return true;
}
Rect FindCocoBounds(const Image& m)
{
Size isz = m.GetSize();
Rect r = isz;
for(r.top = 0; r.top < isz.cy && IsCocoTransparent(m[r.top], 1, isz.cx); r.top++)
;
for(r.bottom = isz.cy; r.bottom > r.top && IsCocoTransparent(m[r.bottom - 1], 1, isz.cx); r.bottom--)
;
if(r.bottom <= r.top)
return Null;
int h = r.GetHeight();
const RGBA *p = m[r.top];
for(r.left = 0; r.left < isz.cy && IsCocoTransparent(p + r.left, isz.cx, h); r.left++)
;
for(r.right = isz.cx; r.right > r.left && IsCocoTransparent(p + r.right - 1, isz.cx, h); r.right--)
;
return r;
}
Image CocoCrop(const Image& m)
{
return Crop(m, FindCocoBounds(m));
}
Image CocoImg(Color bg, int type, int value, int state)
{
Size isz(140, 140);
ImageDraw iw(DPI(isz));
iw.DrawRect(0, 0, DPI(isz.cx), DPI(isz.cy), bg);
Coco_PaintCh(iw.GetCGHandle(), type, value, state);
return iw;
}
Image CocoImg0(int type, int value = 0, int state = 0)
{
Image m[2];
for(int i = 0; i < 2; i++)
m[i] = CocoImg(i ? Black() : White(), type, value, state);
return RecreateAlpha(m[0], m[1]);
}
Image CocoImg(int type, int value = 0, int state = 0)
{
Image h = CocoCrop(CocoImg0(type, value, state));
int q = h.GetSize().cy / 4;
SetHotSpots(h, Point(q, q));
return h;
}
Color CocoColor(int k, Color bg = SColorFace())
{
#if 0
static int ii = 0; _DBG_
String p = GetHomeDirFile("Color" + AsString(ii++) + ".png"); _DBG_
DDUMP(p); PNGEncoder().SaveFile(p, CocoImg(bg, COCO_NSCOLOR, k, 0));
#endif
return AvgColor(CocoImg(bg, COCO_NSCOLOR, k, 0));
}
static Vector<int> s_so_ids;
static Vector<Image> s_so_images;
void SOImages(int imli, int type, int value)
{
Image h[4];
h[0] = CocoImg0(type, value, CTRL_NORMAL);
h[1] = CocoImg0(type, value, CTRL_HOT); // same as Normal
h[2] = CocoImg0(type, value, CTRL_PRESSED);
h[3] = CocoImg0(type, value, CTRL_DISABLED);
for(int i = 0; i < 4; i++) {
s_so_ids << imli++;
s_so_images << h[i];
}
}
void FinishSOImages()
{ // make sure we are using the same bounds everywhere
Rect bounds = FindCocoBounds(s_so_images[0]);
for(int i = 1; i < s_so_images.GetCount(); i++)
bounds.Union(FindCocoBounds(s_so_images[0]));
for(int i = 0; i < s_so_images.GetCount(); i++)
CtrlsImg::Set(s_so_ids[i], Hot3(Crop(s_so_images[i], bounds)));
s_so_ids.Clear();
s_so_images.Clear();
}
void CocoButton(Image *h, int type, int value)
{
h[0] = CocoImg(type, value, CTRL_NORMAL);
h[1] = CocoImg(type, value, CTRL_HOT); // same as Normal
h[2] = CocoImg(type, value, CTRL_PRESSED);
h[3] = CocoImg(type, value, CTRL_DISABLED);
}
void CocoButton(Button::Style& s, int type, int value)
{
Image h[4];
CocoButton(h, type, value);
for(int i = 0; i < 4; i++) {
s.look[i] = h[i];
Image gg = CreateImage(h[i].GetSize(), SColorFace());
Over(gg, h[i]);
s.monocolor[i] = s.textcolor[i] = i == CTRL_DISABLED ? SColorDisabled()
: Grayscale(AvgColor(gg, h[i].GetSize().cy / 3)) > 160 ? Black()
: White();
}
s.overpaint = 5;
s.pressoffset = Point(0, 0);
}
void ChHostSkin()
{
CtrlImg::Reset();
CtrlsImg::Reset();
ChReset();
GUI_GlobalStyle_Write(GUISTYLE_XP);
GUI_PopUpEffect_Write(GUIEFFECT_NONE);
SwapOKCancel_Write(true);
SColorPaper_Write(CocoColor(COCO_PAPER));
if(Atoi(GetEnv("UPP_SCALE__"))) {
if(IsDarkTheme())
ChDarkSkin();
else
ChStdSkin();
return;
}
SColorFace_Write(CocoColor(COCO_WINDOW, White()));
SColorHighlight_Write(CocoColor(COCO_SELECTEDPAPER));
SColorHighlightText_Write(CocoColor(COCO_SELECTEDTEXT));
SColorText_Write(CocoColor(COCO_TEXT));
SColorDisabled_Write(CocoColor(COCO_DISABLED));
ChBaseSkin();
RoundStyleArrows();
SOImages(CtrlsImg::I_S0, COCO_RADIOBUTTON, 0);
SOImages(CtrlsImg::I_S1, COCO_RADIOBUTTON, 1);
FinishSOImages();
SOImages(CtrlsImg::I_O0, COCO_CHECKBOX, 0);
SOImages(CtrlsImg::I_O1, COCO_CHECKBOX, 1);
SOImages(CtrlsImg::I_O2, COCO_CHECKBOX, 2);
FinishSOImages();
CocoButton(Button::StyleNormal().Write(), COCO_BUTTON, 0);
CocoButton(Button::StyleOk().Write(), COCO_BUTTON, 1);
CocoButton(Button::StyleEdge().Write(), COCO_BEVELBUTTON, 0);
CocoButton(Button::StyleScroll().Write(), COCO_BEVELBUTTON, 0);
{
auto& s = ToolButton::StyleDefault().Write();
Image h[4];
CocoButton(h, COCO_BEVELBUTTON, 0);
s.look[CTRL_NORMAL] = Image();
s.look[CTRL_HOT] = h[CTRL_HOT];
s.look[CTRL_PRESSED] = h[CTRL_PRESSED];
s.look[CTRL_DISABLED] = Image();
CocoButton(h, COCO_BEVELBUTTON, 1);
s.look[CTRL_CHECKED] = h[CTRL_NORMAL];
s.look[CTRL_HOTCHECKED] = h[CTRL_HOT];
}
{
ScrollBar::Style& s = ScrollBar::StyleDefault().Write();
s.arrowsize = 0;
Image track = CocoImg(COCO_SCROLLTRACK);
Image thumb = CocoImg(COCO_SCROLLTHUMB);
s.barsize = track.GetHeight();
s.thumbwidth = thumb.GetHeight();
s.thumbmin = 2 * s.barsize;
for(int status = CTRL_NORMAL; status <= CTRL_DISABLED; status++) {
s.hupper[status] = s.hlower[status] = WithHotSpot(track, CH_SCROLLBAR_IMAGE, 0);;
s.vupper[status] = s.vlower[status] = WithHotSpot(RotateAntiClockwise(track), CH_SCROLLBAR_IMAGE, 0);
Image m = thumb;
if(status == CTRL_HOT)
Over(m, m);
if(status == CTRL_PRESSED) {
Over(m, m);
Over(m, m);
}
s.hthumb[status] = WithHotSpot(m, CH_SCROLLBAR_IMAGE, 0);
s.vthumb[status] = WithHotSpot(RotateClockwise(m), CH_SCROLLBAR_IMAGE, 0);
}
}
auto field = [](int type) {
Image m = CocoImg(SColorFace(), type, 0, 0);
Rect r = m.GetSize();
r.left = r.top = DPI(5);
r.right = min(r.left + DPI(10), r.right);
r.bottom = min(r.top + DPI(5), r.bottom);
return AvgColor(m, r);
};
{
EditString::Style& s = EditString::StyleDefault().Write();
s.focus = s.paper = field(COCO_TEXTFIELD);
}
{
MultiButton::Style& s = MultiButton::StyleDefault().Write();
s.paper = field(COCO_POPUPBUTTON);
}
{ // U++ menu should not be used MacOS apps, but adjust some values anyway
MenuBar::Style& s = MenuBar::StyleDefault().Write();
s.pullshift.y = 0;
s.popupbody = SColorFace();
SColorMenu_Write(SColorFace());
s.menutext = SColorText();
SColorMenuText_Write(s.menutext);
s.itemtext = SColorText();
s.item = SColorHighlight();
s.look = SColorFace();
Color dk = SColorText();
Color wh = SColorPaper();
if(IsDark(wh))
Swap(dk, wh);
s.topitemtext[0] = SColorText();
s.topitem[1] = s.topitem[0] = Null;
s.topitemtext[1] = SColorText();
s.topitem[0] = Null;
s.topitem[2] = SColorHighlight();
s.topitemtext[2] = SColorText();
CtrlImg::Set(CtrlImg::I_MenuCheck0, CtrlsImg::O0());
CtrlImg::Set(CtrlImg::I_MenuCheck1, CtrlsImg::O1());
CtrlImg::Set(CtrlImg::I_MenuRadio0, CtrlsImg::S0());
CtrlImg::Set(CtrlImg::I_MenuRadio1, CtrlsImg::S1());
}
auto nsimg = [](int ii) { return CocoImg(COCO_NSIMAGE, ii); };
CtrlImg::Set(CtrlImg::I_information, nsimg(1));
CtrlImg::Set(CtrlImg::I_question, nsimg(0));
CtrlImg::Set(CtrlImg::I_exclamation, nsimg(0));
CtrlImg::Set(CtrlImg::I_error, nsimg(0));
Image button100x100[8];
Color text[8];
for(int i = 0; i < 8; i++) {
ImageDraw iw(100, 100);
const Button::Style& s = i < 4 ? Button::StyleNormal() : Button::StyleEdge();
ChPaint(iw, 0, 0, 100, 100, s.look[i & 3]);
button100x100[i] = iw;
text[i] = s.monocolor[i & 3];
}
ChSynthetic(button100x100, text, true);
}
};
#endif