diff --git a/reference/GetLayoutId/MyApp.lay b/reference/GetLayoutId/MyApp.lay index 4b90461c4..b26706470 100644 --- a/reference/GetLayoutId/MyApp.lay +++ b/reference/GetLayoutId/MyApp.lay @@ -1,13 +1,13 @@ LAYOUT(MyAppLayout, 216, 140) - ITEM(Label, dv___0, SetLabel(t_("Name")).LeftPosZ(8, 68).TopPosZ(8, 21)) - ITEM(EditString, name, LeftPosZ(80, 128).TopPosZ(8, 19)) - ITEM(Label, dv___2, SetLabel(t_("Last Name")).LeftPosZ(8, 68).TopPosZ(32, 21)) - ITEM(EditString, lastname, LeftPosZ(80, 128).TopPosZ(32, 19)) - ITEM(Label, dv___4, SetLabel(t_("City")).LeftPosZ(8, 68).TopPosZ(56, 21)) - ITEM(EditString, city, LeftPosZ(80, 128).TopPosZ(56, 19)) - ITEM(Label, dv___6, SetLabel(t_("Street")).LeftPosZ(8, 68).TopPosZ(80, 21)) - ITEM(EditString, street, LeftPosZ(80, 128).TopPosZ(80, 19)) - ITEM(Button, ok, SetLabel(t_("OK")).HCenterPosZ(64, 0).BottomPosZ(8, 24)) - ITEM(Button, cancel, SetLabel(t_("Cancel")).RightPosZ(8, 64).BottomPosZ(8, 24)) + ITEM(Upp::Label, dv___0, SetLabel(t_("Name")).LeftPosZ(8, 68).TopPosZ(8, 21)) + ITEM(Upp::EditString, name, LeftPosZ(80, 128).TopPosZ(8, 19)) + ITEM(Upp::Label, dv___2, SetLabel(t_("Last Name")).LeftPosZ(8, 68).TopPosZ(32, 21)) + ITEM(Upp::EditString, lastname, LeftPosZ(80, 128).TopPosZ(32, 19)) + ITEM(Upp::Label, dv___4, SetLabel(t_("City")).LeftPosZ(8, 68).TopPosZ(56, 21)) + ITEM(Upp::EditString, city, LeftPosZ(80, 128).TopPosZ(56, 19)) + ITEM(Upp::Label, dv___6, SetLabel(t_("Street")).LeftPosZ(8, 68).TopPosZ(80, 21)) + ITEM(Upp::EditString, street, LeftPosZ(80, 128).TopPosZ(80, 19)) + ITEM(Upp::Button, ok, SetLabel(t_("OK")).HCenterPosZ(64, 0).BottomPosZ(8, 24)) + ITEM(Upp::Button, cancel, SetLabel(t_("Cancel")).RightPosZ(8, 64).BottomPosZ(8, 24)) END_LAYOUT diff --git a/uppsrc/CtrlCore/Win32Proc.cpp b/uppsrc/CtrlCore/Win32Proc.cpp index 7d01546db..45606ff57 100644 --- a/uppsrc/CtrlCore/Win32Proc.cpp +++ b/uppsrc/CtrlCore/Win32Proc.cpp @@ -110,12 +110,12 @@ close 232,17,35 int Ctrl::GetWin32TitleBarHeight(const TopWindow *tw) { - return max(tw->custom_titlebar_cy, IsUHDMode() ? 60 : 31); + return max(tw->custom_titlebar_cy, DPI(31)); } int Ctrl::GetWin32TitleBarButtonWidth() { - return IsUHDMode() ? 94 : 47; + return DPI(47); } Rect Ctrl::GetTitleBarRect(const TopWindow *win) // TODO (image, cy) diff --git a/uppsrc/CtrlLib/CtrlUtil.cpp b/uppsrc/CtrlLib/CtrlUtil.cpp index 800be5ccb..e216a7b70 100644 --- a/uppsrc/CtrlLib/CtrlUtil.cpp +++ b/uppsrc/CtrlLib/CtrlUtil.cpp @@ -473,10 +473,11 @@ struct ZoomIconMaker : ImageMaker { ImagePainter w(sz); w.Clear(RGBAZero()); w.Move(DPI(11), DPI(11)).Line(DPI(16), DPI(16)).Stroke(DPI(2), SBlack()); - w.Circle(DPI(7), DPI(7), IsUHDMode() ? 12 : 6.5).Stroke(IsUHDMode() ? 3 : 1, SBlack()); + int scale = GetDPIScale(); + w.Circle(DPI(7), DPI(7), scale > DPI_100 ? scale * 3 : 6.5).Stroke(scale - 1, SBlack()); String txt = AsString(int(zoom * 100)); - Image numbers = IsUHDMode() ? CtrlImg::Numbers2() : CtrlImg::Numbers1(); - int gcx = IsUHDMode() ? 6 : 4; + Image numbers = scale >= DPI_200 ? CtrlImg::Numbers2() : CtrlImg::Numbers1(); + int gcx = 3 + scale / 2; Size tsz(txt.GetCount() * gcx, numbers.GetHeight()); int y = DPI(7) - tsz.cy / 2; int x = DPI(7) - tsz.cx / 2; diff --git a/uppsrc/Draw/Font.cpp b/uppsrc/Draw/Font.cpp index 5196be50c..8c93f794c 100644 --- a/uppsrc/Draw/Font.cpp +++ b/uppsrc/Draw/Font.cpp @@ -129,7 +129,7 @@ void Font::SyncStdFont() } LLOG("SyncStdFont " << StdFontSize); - SyncUHDMode(); + SyncDPIScale(); } void (*whenSetStdFont)(); diff --git a/uppsrc/Draw/Image.h b/uppsrc/Draw/Image.h index 4466be17d..c1b95326a 100644 --- a/uppsrc/Draw/Image.h +++ b/uppsrc/Draw/Image.h @@ -81,6 +81,7 @@ class ImageBuffer : NoCopy { void InitAttrs(); friend class Image; + friend void iml_ReplaceAll(Image& tgt, const Image& src); public: void SetKind(int k) { kind = k; } @@ -179,7 +180,7 @@ private: friend struct scImageMaker; void SetAuxData(uint64 data); - friend void iml_ReplaceAll(Image& tgt, Image& src); + friend void iml_ReplaceAll(Image& tgt, const Image& src); public: Size GetSize() const { return data ? data->buffer.GetSize() : Size(0, 0); } @@ -274,13 +275,6 @@ Vector UnpackImlDataUncompressed(const String& data); Vector UnpackImlData(const void *ptr, int len); Vector UnpackImlData(const String& d); -enum { - GUI_MODE_NORMAL = 0, - GUI_MODE_DARK = 1, - GUI_MODE_UHD = 2, - GUI_MODE_DARK_UHD = 3, -}; - enum { IML_IMAGE_FLAG_FIXED = 0x1, IML_IMAGE_FLAG_FIXED_COLORS = 0x2, @@ -288,28 +282,31 @@ enum { IML_IMAGE_FLAG_UHD = 0x8, IML_IMAGE_FLAG_DARK = 0x10, IML_IMAGE_FLAG_S3 = 0x20, + IML_IMAGE_FLAG_QHD = 0x40, }; -Image MakeImlImage(const String& id, Function GetRaw, dword global_flags); +Image MakeImlImage(const String& id, Event GetRaw); class Iml { struct IImage : Moveable { std::atomic loaded; Image image; - IImage() { loaded = false; } + IImage() { loaded = false; } }; struct Data : Moveable { const char *data; int len, count; }; - Vector data[4]; // 0 normal, 1 HiDPI - HD, 2 DK - Dark, 3 HDK - HiDPI + dark - VectorMap map; + Vector data; const char **name; dword global_flags = 0; bool premultiply; - Index ex_name[3]; // 0 HiDPI - HD, 1 DK - Dark, 2 HDK - HiDPI + dark + VectorMap map; + Index id; + + int version = 0; void Init(int n); @@ -322,15 +319,15 @@ public: int Find(const String& id) const { return map.Find(id); } void Set(int i, const Image& img); - ImageIml GetRaw(int mode, int i); // tries to get image for mode, can return Null - ImageIml GetRaw(int mode, const String& id); // tries to get image for mode by id, can return Null + ImageIml GetRaw(int i); // these methods serve for .iml import Iml(const char **name, int n);//Deprecated - legacy .iml - void AddData(const byte *data, int len, int count, int mode = 0); + void AddData(const byte *data, int len, int count); void AddId(int mode1, const char *name); void Premultiplied() { premultiply = false; } void GlobalFlag(dword f) { global_flags |= f; } + void Version(int v) { version = v; } static void ResetAll(); // clears all .iml caches static void SkinAll(); // reskins all .iml caches diff --git a/uppsrc/Draw/ImageOp.h b/uppsrc/Draw/ImageOp.h index 24def543a..e63aba0aa 100644 --- a/uppsrc/Draw/ImageOp.h +++ b/uppsrc/Draw/ImageOp.h @@ -7,7 +7,7 @@ Image WithHotSpots(const Image& m, Point hotspot, Point hotspot2 = Point(0, 0)); Image WithHotSpots(const Image& m, int x1, int y1, int x2, int y2); Image WithHotSpot(const Image& m, int x1, int y1); -void ScanOpaque(Image& m); +void ScanOpaque(Image& m); void DstSrcOp(ImageBuffer& dest, Point p, const Image& src, const Rect& srect, void (*op)(RGBA *t, const RGBA *s, int n), bool co = false); @@ -262,23 +262,41 @@ Image MinifyCached(const Image& img, int nx, int ny, bool co = false); Image DownSample3x(const Image& src, bool co = false); Image DownSample2x(const Image& src, bool co = false); +Image DPISmartRescale(const Image& src, Size sz); +Image DPISmartRescaleCached(const Image& src, Size sz); + Image Upscale2x(const Image& src); Image Downscale2x(const Image& src); Image Downscale6x(const Image& src); -void SetUHDMode(bool b = true); -bool IsUHDMode(); -void SyncUHDMode(); +enum { + DPI_100 = 2, // Normal resolution + DPI_150 = 3, // QHD + DPI_200 = 4, // UHD + DPI_300 = 6, + DPI_600 = 12, // Used for 'master' Image drawn without aliasing +}; -// Image DPI(const Image& m); -Image DPI(const Image& img, int expected); +void SetDPIScale(int scale); +int GetDPIScale(); +double GetDPIScaleRatio(); +void SyncDPIScale(); + +inline int DPI(int a) { extern int DPIScaleGlobal_; return (DPIScaleGlobal_ * a) >> 1; } +inline double DPI(double a) { extern double DPIScaleGlobalF_; return DPIScaleGlobalF_ * a; } -inline int DPI(int a) { return IsUHDMode() ? 2 * a : a; } -inline double DPI(double a) { return IsUHDMode() ? 2 * a : a; } -inline Size DPI(Size sz) { return IsUHDMode() ? 2 * sz : sz; } inline Size DPI(int cx, int cy) { return Size(DPI(cx), DPI(cy)); } +inline Size DPI(Size sz) { return DPI(sz.cx, sz.cy); } + +int ImlFlagsToDPIScale(int imlflags); +int DPIScaleToImlFlags(int dpiscale); + + +inline int DPI2(int dpi200val, int dpi100val) { + int scale = GetDPIScale(); + return (dpi200val - dpi100val) * (scale - DPI_100) / 2 + dpi100val; +} -inline Image DPI(const Image& a, const Image& b) { return IsUHDMode() ? b : a; } struct RGBAV { dword r, g, b, a; diff --git a/uppsrc/Draw/Iml.cpp b/uppsrc/Draw/Iml.cpp index 598b91baf..942414293 100644 --- a/uppsrc/Draw/Iml.cpp +++ b/uppsrc/Draw/Iml.cpp @@ -41,10 +41,13 @@ Vector UnpackImlData(const String& d) return UnpackImlData(~d, d.GetLength()); } -void iml_ReplaceAll(Image& tgt, Image& src) +void iml_ReplaceAll(Image& tgt, const Image& src) { // this very special function replaces all unmodified instances of Image with new content - if(tgt.GetSize() == src.GetSize() && tgt.data) { - tgt.data->buffer = src.data->buffer; + Image h = src; // make sure src has refcount 1, basically 'clone' + ImageBuffer ib = h; + h = ib; + if(tgt.GetSize() == h.GetSize() && tgt.data && src.data) { + tgt.data->buffer = h.data->buffer; tgt.data->NewSerial(); } else @@ -72,15 +75,59 @@ void Iml::Skin() } } +void Iml::AddData(const byte *s, int len, int count) +{ + Data& d = data.Add(); + d.data = (const char *)s; + d.len = len; + d.count = count; + data.Shrink(); +} + +void Iml::AddId(int mode1, const char *name) +{ + map.Add(name); +} + +ImageIml Iml::GetRaw(int i) +{ + for(const Data& d : data) { + if(i < d.count) { + ImageIml m = MakeValue( + [&] { + String key; + RawCat(key, d.data); // all is static + RawCat(key, i); + return key; + }, + [&](Value& v) { + Vector& m = CreateRawValue>(v); + m = UnpackImlData(d.data, d.len); + int sz = 0; + for(ImageIml& img : m) { + sz += img.image.GetLength(); + if(premultiply) + img.image = Premultiply(img.image); + if(version == 0) // cleanup some bits that are set for legacy reasons + img.flags &= 0x3f; + } + return sz; + } + ).To>()[i]; + m.flags |= global_flags; + return m; + } + i -= d.count; + } + return ImageIml(); +} + static StaticMutex sImlLock; void Iml::Set(int i, const Image& img) { // TODO: MT IImage& m = map[i]; - Image h = img; // make sure h has refcount 1, basically 'clone' - ImageBuffer ib = h; - h = ib; - iml_ReplaceAll(m.image, h); + iml_ReplaceAll(m.image, img); m.loaded = true; } @@ -90,7 +137,13 @@ Image Iml::Get(int i) if(!m.loaded) { Mutex::Lock __(sImlLock); if(!m.loaded) { - Image h = MakeImlImage(GetId(i), [&](int mode, const String& id) { return GetRaw(mode, id); }, global_flags); + Image h = MakeImlImage(GetId(i), [&](int i, ImageIml& m, String& id) { + id.Clear(); + if(i < GetCount()) { + id = map.GetKey(i); + m = GetRaw(i); + } + }); iml_ReplaceAll(m.image, h); m.loaded = true; } @@ -98,89 +151,94 @@ Image Iml::Get(int i) return m.image; } -ImageIml Iml::GetRaw(int mode, int i) +int ImlFlagsToDPIScale(int imlflags) { + int scale = DPI_100; + if(imlflags & IML_IMAGE_FLAG_UHD) + scale = DPI_200; + if(imlflags & IML_IMAGE_FLAG_S3) + scale *= 3; + if(imlflags & IML_IMAGE_FLAG_QHD) + scale++; + return scale; +} + +int DPIScaleToImlFlags(int dpiscale) { + return dpiscale == DPI_600 ? IML_IMAGE_FLAG_S3|IML_IMAGE_FLAG_UHD + : get_i(dpiscale, 0, 0, + 0, // DPI_100 + IML_IMAGE_FLAG_QHD, // DPI_150 + IML_IMAGE_FLAG_UHD, // DPI_200 + IML_IMAGE_FLAG_UHD|IML_IMAGE_FLAG_QHD, // 'DPI_250' - not used + IML_IMAGE_FLAG_S3 // DPI_300 + ); +} + +Image MakeImlImage(const String& id, Event GetRaw) { - Mutex::Lock __(sImlLock); - if(data[mode].GetCount()) { - int ii = 0; - while(ii < data[mode].GetCount()) { - const Data& d = data[mode][ii]; - if(i < d.count) { - static const char *cached_data[4]; - static Vector cached[4]; - if(cached_data[mode] != d.data) { // cache single .iml - cached_data[mode] = d.data; - cached[mode] = UnpackImlData(d.data, d.len); - if(premultiply) - for(int i = 0; i < cached[mode].GetCount(); i++) - cached[mode][i].image = Premultiply(cached[mode][i].image); - } - return cached[mode][i]; + int ii = 0; + ImageIml best; + ImageIml exact_scale; + int scale = GetDPIScale(); + bool dark = IsDarkTheme(); + int best_dark = 10; // minimize this + int best_scale = -1; // maximize this + for(;;) { + ImageIml im; + String iid; + GetRaw(ii++, im, iid); + if(IsNull(iid)) + break; + int q = iid.Find("__"); + if(q > 0) + iid.Trim(q); + if(iid == id) { + bool isdark = im.flags & IML_IMAGE_FLAG_DARK; + int iscale = ImlFlagsToDPIScale(im.flags); + + if(isdark == dark && iscale == scale) // found perfect match + return im.image; + + if(iscale == scale) + exact_scale = im; + + int idark = !!isdark - dark; + if(CombineCompare(best_dark, idark)(iscale, best_scale) > 0) { // prioritize color, then find highest scale + best = im; + best_dark = idark; + best_scale = iscale; } - i -= d.count; - ii++; } } - return ImageIml(); -} -ImageIml Iml::GetRaw(int mode, const String& id) -{ - ASSERT(mode >= 0 && mode < 4); - int ii = -1; - if(mode == 0) - ii = map.Find(id); - else - ii = ex_name[mode - 1].Find(id); - return ii >= 0 ? GetRaw(mode, ii) : ImageIml(); -} + auto AdjustColor0 = [&](const Image& img, dword flags) { // flip light to dark if needed + if(dark && !(flags & (IML_IMAGE_FLAG_FIXED|IML_IMAGE_FLAG_FIXED_COLORS))) + return DarkTheme(img); + return img; + }; -Image MakeImlImage(const String& id, Function GetRaw, dword global_flags) -{ - int mode = IsUHDMode() * GUI_MODE_UHD + IsDarkTheme() * GUI_MODE_DARK; - - const static int mode_candidates[4][4] = { - { GUI_MODE_NORMAL, GUI_MODE_UHD, -1 }, - { GUI_MODE_DARK, GUI_MODE_DARK_UHD, GUI_MODE_NORMAL, GUI_MODE_UHD }, - { GUI_MODE_UHD, GUI_MODE_NORMAL, -1 }, - { GUI_MODE_DARK_UHD, GUI_MODE_DARK, GUI_MODE_UHD, GUI_MODE_NORMAL } + if(best_dark && !IsNull(exact_scale.image)) { // dark color version not found, but we have exact scale + return AdjustColor0(exact_scale.image, exact_scale.flags); + } + + auto AdjustColor = [&](const Image& m) { // flip light to dark if needed + return best_dark ? AdjustColor0(m, best.flags) : m; }; - ImageIml im; - Image original; - const int *candidates = mode_candidates[mode]; + if(best.flags & (IML_IMAGE_FLAG_FIXED|IML_IMAGE_FLAG_FIXED_SIZE)) + return AdjustColor(best.image); - for(int i = 0; i < 4 && candidates[i] >= 0; i++) { - int cmode = candidates[i]; - auto Mode = [&](dword m, const char *s) { return cmode & m ? String(s) : String(); }; - im = GetRaw(GUI_MODE_NORMAL, id + Mode(GUI_MODE_UHD, "__UHD") + Mode(GUI_MODE_DARK, "__DARK")); - if(IsNull(im.image)) - im = GetRaw(cmode, id); // try alternative iml - if(!IsNull(im.image)) { - original = im.image; - if(im.flags & IML_IMAGE_FLAG_S3) - im.image = DownSample3x(im.image); - break; - } + if(best_scale == DPI_600) { + if(scale == DPI_100) + return AdjustColor(Downscale6x(best.image)); + if(scale == DPI_150) + return AdjustColor(Downscale2x(DownSample2x(best.image))); + if(scale == DPI_200) + return AdjustColor(DownSample3x(best.image)); + if(scale == DPI_300) + return AdjustColor(DownSample2x(best.image)); } - if(IsNull(im.image)) - return Null; - - if(!(mode & GUI_MODE_UHD) && (im.flags & IML_IMAGE_FLAG_UHD) && !((im.flags | global_flags) & (IML_IMAGE_FLAG_FIXED|IML_IMAGE_FLAG_FIXED_SIZE))) { - if(im.flags & IML_IMAGE_FLAG_S3) - im.image = Downscale6x(original); - else - im.image = Downscale2x(im.image); - } - if((mode & GUI_MODE_UHD) && !(im.flags & IML_IMAGE_FLAG_UHD) && !((im.flags | global_flags) & (IML_IMAGE_FLAG_FIXED|IML_IMAGE_FLAG_FIXED_SIZE))) - im.image = Upscale2x(im.image); - if((mode & GUI_MODE_DARK) && !(im.flags & IML_IMAGE_FLAG_DARK) && !((im.flags | global_flags) & (IML_IMAGE_FLAG_FIXED|IML_IMAGE_FLAG_FIXED_COLORS))) - im.image = DarkTheme(im.image); - - ScanOpaque(im.image); - - return im.image; + return DPISmartRescale(best.image, scale * best.image.GetSize() / best_scale); } Iml::Iml(const char **name, int n) @@ -190,20 +248,6 @@ Iml::Iml(const char **name, int n) Init(n); } -void Iml::AddData(const byte *s, int len, int count, int mode) -{ - Data& d = data[mode].Add(); - d.data = (const char *)s; - d.len = len; - d.count = count; - data[mode].Shrink(); -} - -void Iml::AddId(int mode1, const char *name) -{ - ex_name[mode1].Add(name); -} - void Iml::ResetAll() { for(int i = 0; i < GetImlCount(); i++) diff --git a/uppsrc/Draw/Uhd.cpp b/uppsrc/Draw/Uhd.cpp index ab8c72132..e0a41a212 100644 --- a/uppsrc/Draw/Uhd.cpp +++ b/uppsrc/Draw/Uhd.cpp @@ -102,18 +102,50 @@ Image Upscale2x(const Image& src) return Image(h); } -Image Downscale2x(const Image& src) +Image DPIRescale(const Image& src, Size sz) { if(IsNull(src)) return src; - Size s2 = src.Get2ndSpot(); // see above... - Image m = RescaleFilter(src, src.GetSize() / 2, s2.cx > 0 || s2.cy > 0 ? FILTER_BILINEAR : FILTER_LANCZOS3); + Size s2 = src.Get2ndSpot(); + Size sz0 = src.GetSize(); + if(sz0 == sz) + return src; + // When 2nd spot is defined, it is likely Chameleon rescaling item (e.g. button) + // in that case, filtering by smarter rescale methods could lead to artifacts (stay BILINEAR) + Image m = RescaleFilter(src, sz, s2.cx > 0 || s2.cy > 0 ? FILTER_BILINEAR : FILTER_LANCZOS3); ImageBuffer h(m); - h.SetHotSpot(s2 / 2); - h.Set2ndSpot(src.Get2ndSpot() / 2); + h.SetHotSpot(s2 * sz / sz0); + h.Set2ndSpot(src.Get2ndSpot() * sz / sz0); return Image(h); } +Image DPISmartRescale(const Image& src, Size sz) +{ + Image m = src; + for(;;) { + Size isz = m.GetSize(); + if(isz.cx * isz.cy == 0) + return Null; + if(isz.cx >= sz.cx && isz.cy >= sz.cy) + break; + m = Upscale2x(m); + } + return DPIRescale(m, sz); +} + +Image DPISmartRescaleCached(const Image& src, Size sz) +{ + return MakeImage( + [&] { StringBuffer s; RawCat(s, src.GetSerialId()); RawCat(s, sz); return (String)s; }, + [&] { return DPISmartRescale(src, sz); } + ); +} + +Image Downscale2x(const Image& src) +{ + return DPIRescale(src, src.GetSize() / 2); +} + Image Downscale6x(const Image& src) { if(IsNull(src)) @@ -126,31 +158,34 @@ Image Downscale6x(const Image& src) return Image(h); } -static bool sUHDMode; +int DPIScaleGlobal_; +double DPIScaleGlobalF_; -void SetUHDMode(bool b) +void SetDPIScale(int scale) { Iml::ResetAll(); - sUHDMode = b; + DPIScaleGlobal_ = scale; + DPIScaleGlobalF_ = 0.5 * scale; } -bool IsUHDMode() +int GetDPIScale() { - return sUHDMode; + return DPIScaleGlobal_; } -void SyncUHDMode() +double GetDPIScaleRatio() { - bool uhd = GetStdFontCy() > 24; - if(uhd != IsUHDMode()) - SetUHDMode(uhd); + return DPIScaleGlobalF_; } -Image DPI(const Image& img, int expected) +void SyncDPIScale() { - if(img.GetSize().cy <= expected && IsUHDMode()) - return AdjustImage(img, Upscale2x); - return img; + int fcy = GetStdFontCy(); + int scale = clamp((fcy + 3) / 8, 2, 5); + if(scale == 5) + scale = DPI_300; + if(scale != GetDPIScale()) + SetDPIScale(scale); } }; \ No newline at end of file diff --git a/uppsrc/Draw/iml_header.h b/uppsrc/Draw/iml_header.h index be14e385c..874641cb9 100644 --- a/uppsrc/Draw/iml_header.h +++ b/uppsrc/Draw/iml_header.h @@ -1,10 +1,12 @@ //#BLITZ_APPROVE #define IMAGE_META(k, v) +#define IMAGE_VERSION(v) #define IMAGE_SCAN(s) #define IMAGE_PACKED(n, d) #define PREMULTIPLIED +#define VERSION(x) #define IMAGE_BEGIN_DATA #define IMAGE_DATA(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac,ad,ae,af,b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,ba,bb,bc,bd,be,bf) #define IMAGE_END_DATA(n, c) @@ -50,6 +52,7 @@ public: #undef IMAGE_SCAN #undef IMAGE_PACKED #undef IMAGE_META +#undef IMAGE_VERSION #undef IMAGE_BEGIN_DATA #undef IMAGE_END_DATA @@ -58,4 +61,8 @@ public: #ifndef IMAGE_KEEP #undef IMAGECLASS #undef IMAGEFILE + +#undef PREMULTIPLIED +#undef VERSION + #endif diff --git a/uppsrc/Draw/iml_source.h b/uppsrc/Draw/iml_source.h index 60f81c88e..848a273f7 100644 --- a/uppsrc/Draw/iml_source.h +++ b/uppsrc/Draw/iml_source.h @@ -1,8 +1,10 @@ //#BLITZ_APPROVE +#define VERSION(v) +#define PREMULTIPLIED + #define IMAGE_META(k, v) -#define PREMULTIPLIED #define IMAGE_ID(n) #define IMAGE_BEGIN_DATA #define IMAGE_END_DATA(n, c) @@ -65,30 +67,6 @@ UPP::Iml& IMAGECLASS::Iml() { #include IMAGEFILE - #ifdef IMAGEFILE_DARK - #undef IMAGE_ID - #undef IMAGE_END_DATA - #define IMAGE_ID(n) iml.AddId(0, #n); - #define IMAGE_END_DATA(n, c) }; iml.AddData(data, n, c, 1); } - #include IMAGEFILE_DARK - #endif - - #ifdef IMAGEFILE_UHD - #undef IMAGE_ID - #undef IMAGE_END_DATA - #define IMAGE_ID(n) iml.AddId(1, #n); - #define IMAGE_END_DATA(n, c) }; iml.AddData(data, n, c, 2); } - #include IMAGEFILE_UHD - #endif - - #ifdef IMAGEFILE_DARK_UHD - #undef IMAGE_ID - #undef IMAGE_END_DATA - #define IMAGE_ID(n) iml.AddId(2, #n); - #define IMAGE_END_DATA(n, c) }; iml.AddData(data, n, c, 3); } - #include IMAGEFILE_DARK_UHD - #endif - #undef IMAGE_BEGIN_DATA #undef IMAGE_END_DATA #undef IMAGE_DATA @@ -100,10 +78,13 @@ UPP::Iml& IMAGECLASS::Iml() { #undef PREMULTIPLIED #define PREMULTIPLIED iml.Premultiplied(); + #undef VERSION + #define VERSION(v) iml.Version(v); #include IMAGEFILE #undef PREMULTIPLIED #define PREMULTIPLIED - + #undef VERSION + #define VERSION(v) } return iml; } @@ -176,6 +157,9 @@ static COMBINE(IMAGECLASS, __Reg) COMBINE(IMAGECLASS, ___Reg); #undef IMAGE_META +#undef PREMULTIPLIED +#undef VERSION + #ifdef IMAGEFILE_UHD #undef IMAGEFILE_UHD #endif diff --git a/uppsrc/Draw/src.tpp/UHD_en-us.tpp b/uppsrc/Draw/src.tpp/DPI_en-us.tpp similarity index 59% rename from uppsrc/Draw/src.tpp/UHD_en-us.tpp rename to uppsrc/Draw/src.tpp/DPI_en-us.tpp index dd0e3c891..bf3296772 100644 --- a/uppsrc/Draw/src.tpp/UHD_en-us.tpp +++ b/uppsrc/Draw/src.tpp/DPI_en-us.tpp @@ -1,52 +1,34 @@ -topic "Ultra High Definition Displays support"; -[i448;a25;kKO9;2 $$1,0#37138531426314131252341829483380:class] -[l288;2 $$2,2#27521748481378242620020725143825:desc] -[0 $$3,0#96390100711032703541132217272105:end] -[H6;0 $$4,0#05600065144404261032431302351956:begin] -[i448;a25;kKO9;2 $$5,0#37138531426314131252341829483370:item] -[l288;a4;*@5;1 $$6,6#70004532496200323422659154056402:requirement] -[l288;i1121;b17;O9;~~~.1408;2 $$7,0#10431211400427159095818037425705:param] -[i448;b42;O9;2 $$8,8#61672508125594000341940100500538:tparam] -[b42;2 $$9,9#13035079074754324216151401829390:normal] -[2 $$0,0#00000000000000000000000000000000:Default] -[{_} -[ {{10000@(113.42.0) [s0;%% [*@7;4 Ultra High Definition Displays support]]}}&] -[s0;i448;a25;kKO9;@(0.0.255) &] -[ {{10000F(128)G(128)@1 [s0;%% [* Function List]]}}&] -[s0;%% &] -[s5;:Upp`:`:SetUHDMode`(bool`): [@(0.0.255) void]_[* SetUHDMode]([@(0.0.255) bool]_[*@3 b])&] -[s2;%% Sets the UHD mode.&] -[s3;%% &] -[s4; &] -[s5;:Upp`:`:IsUHDMode`(`): [@(0.0.255) bool]_[* IsUHDMode]()&] -[s2;%% Returns true if UHD mode is active.&] -[s3; &] -[s4; &] -[s5;:Upp`:`:SyncUHDMode`(`): [@(0.0.255) void]_[* SyncUHDMode]()&] -[s2;%% Sets the UHD mode if current GUI font is bigger than 27 pixels -(in windows, that corresponds to text size bigger than approximately -160%).&] -[s3; &] -[s4; &] -[s5;:Upp`:`:DPI`(const Upp`:`:Image`&`): [_^Upp`:`:Image^ Image]_[* DPI]([@(0.0.255) const]_ -[_^Upp`:`:Image^ Image][@(0.0.255) `&]_[*@3 img])&] -[s2;%% Eventually upscales or downscales [%-*@3 img] based on its UHD -flag and current mode. Standard images are upscaled 2x in UHD -mode, UHD images are downscaled 2x in standard mode.&] -[s3;%% &] -[s4; &] -[s5;:Upp`:`:DPI`(const Upp`:`:Image`&`,int`): [_^Upp`:`:Image^ Image]_[* DPI]([@(0.0.255) c -onst]_[_^Upp`:`:Image^ Image][@(0.0.255) `&]_[*@3 img], [@(0.0.255) int]_[*@3 expected])&] -[s2;%% Upscales [%-*@3 img] 2x if its height is less than or equal -to [%-*@3 expected] and UHD mode is active.&] -[s3;%% &] -[s4; &] -[s5;:Upp`:`:DPI`(int`): [@(0.0.255) int]_[* DPI]([@(0.0.255) int]_[*@3 a])&] -[s2;%% Returns 2 `* [%-*@3 a] if UHD is active and [%-*@3 a] otherwise.&] -[s3;%% &] -[s4; &] -[s5;:Upp`:`:DPI`(Upp`:`:Size`): [_^Upp`:`:Size^ Size]_[* DPI]([_^Upp`:`:Size^ Size]_[*@3 sz]) -&] -[s2;%% Returns 2 `* [%-*@3 sz] if UHD is active and [%-*@3 sz] otherwise.&] -[s3;%% &] +topic "GUI Scaling"; +[i448;a25;kKO9;2 $$1,0#37138531426314131252341829483380:class] +[l288;2 $$2,2#27521748481378242620020725143825:desc] +[0 $$3,0#96390100711032703541132217272105:end] +[H6;0 $$4,0#05600065144404261032431302351956:begin] +[i448;a25;kKO9;2 $$5,0#37138531426314131252341829483370:item] +[l288;a4;*@5;1 $$6,6#70004532496200323422659154056402:requirement] +[l288;i1121;b17;O9;~~~.1408;2 $$7,0#10431211400427159095818037425705:param] +[i448;b42;O9;2 $$8,8#61672508125594000341940100500538:tparam] +[b42;2 $$9,9#13035079074754324216151401829390:normal] +[2 $$0,0#00000000000000000000000000000000:Default] +[{_} +[ {{10000@(113.42.0) [s0;%% [*@7;4 GUI Scaling]]}}&] +[s0;i448;a25;kKO9;@(0.0.255) &] +[ {{10000F(128)G(128)@1 [s0;%% [* Function List]]}}&] +[s0;%% &] +[s3; &] +[s4; &] +[s5;:Upp`:`:DPI`(const Upp`:`:Image`&`): [_^Upp`:`:Image^ Image]_[* DPI]([@(0.0.255) const]_ +[_^Upp`:`:Image^ Image][@(0.0.255) `&]_[*@3 img])&] +[s2;%% Eventually upscales or downscales [%-*@3 img] based on its UHD +flag and current mode. Standard images are upscaled 2x in UHD +mode, UHD images are downscaled 2x in standard mode.&] +[s3;%% &] +[s4; &] +[s5;:Upp`:`:DPI`(int`): [@(0.0.255) int]_[* DPI]([@(0.0.255) int]_[*@3 a])&] +[s2;%% Returns 2 `* [%-*@3 a] if UHD is active and [%-*@3 a] otherwise.&] +[s3;%% &] +[s4; &] +[s5;:Upp`:`:DPI`(Upp`:`:Size`): [_^Upp`:`:Size^ Size]_[* DPI]([_^Upp`:`:Size^ Size]_[*@3 sz]) +&] +[s2;%% Returns 2 `* [%-*@3 sz] if UHD is active and [%-*@3 sz] otherwise.&] +[s3;%% &] [s0;%% ]] \ No newline at end of file diff --git a/uppsrc/Draw/src.tpp/DPI_en-us.tppi b/uppsrc/Draw/src.tpp/DPI_en-us.tppi new file mode 100644 index 000000000..a4851a900 --- /dev/null +++ b/uppsrc/Draw/src.tpp/DPI_en-us.tppi @@ -0,0 +1,6 @@ +TITLE("GUI Scaling") +COMPRESSED +120,156,141,82,239,79,219,48,16,253,87,44,21,80,139,186,234,238,108,199,78,242,165,31,24,63,180,73,155,134,248,20,5,106,90,211,69,107,83,150,164,99,3,193,223,190,115,72,71,209,96,172,138,98,247,238,222,243,123,207,201,10,165,108,234,72,167,223,62,124,138,83,18,59,59,56,132,158,52,40,173,150,168,40,226,23,74,36,77,82,161,165,88,89,41,45,36,211,133,171,235,60,91,144,181,45,136,134,212,35,163,9,141,178,202,162,52,150,24,75,0,4,134,52,42,105,73,39,51,95,79,243,12,120,92,242,25,113,36,99,64,0,131,8,146,12,72,173,16,37,49,5,25,66,208,137,47,103,121,118,28,165,1,160,24,0,58,2,128,136,217,148,2,102,15,48,37,81,2,73,141,177,142,146,75,63,47,202,60,251,219,146,126,211,146,129,164,104,252,178,115,228,84,186,63,214,41,50,52,26,70,61,195,199,42,205,135,197,193,145,100,24,81,164,99,212,138,37,41,160,164,242,223,215,69,229,151,190,108,58,134,2,145,48,189,68,147,178,132,135,135,135,17,42,120,76, +202,176,22,4,214,77,200,53,246,97,80,199,16,107,139,22,164,81,164,13,91,191,118,149,91,118,78,46,21,165,157,15,59,180,189,8,35,78,20,44,235,215,49,19,0,155,224,149,131,212,252,72,155,52,29,56,224,2,40,30,198,61,14,73,106,48,49,24,101,180,98,39,132,17,114,144,16,252,243,53,36,229,170,90,186,69,158,5,0,132,172,223,248,37,7,254,202,173,23,108,247,238,226,94,100,226,238,14,67,121,220,231,43,28,41,26,193,64,100,53,164,187,187,34,219,31,155,84,137,163,179,19,113,58,117,139,162,156,231,249,253,253,94,30,218,207,111,106,220,135,17,140,216,214,64,112,123,67,121,216,71,178,131,163,246,61,198,39,86,113,184,46,167,77,177,42,197,199,162,110,158,56,185,25,54,50,109,23,245,184,232,52,57,187,190,158,36,147,228,224,243,201,164,63,93,149,117,35,186,202,201,210,205,253,100,111,50,72,68,118,113,190,93,60,23,237,146,95,240,105,140,203,251,217,150,196,150,131,91,47,67,182,39,39,123,129,97,44,69,177,156,231,131,32,135,130, +202,247,63,248,115,89,187,197,226,151,88,95,215,28,141,175,197,170,18,179,213,77,217,253,203,118,223,109,96,226,210,213,126,38,216,109,209,212,226,236,248,64,92,45,220,92,184,114,38,166,235,170,98,38,177,92,205,252,72,156,54,92,115,213,140,81,172,163,22,174,242,27,250,153,160,159,162,40,91,116,24,30,182,187,173,185,63,71,111,38,235,13,89,203,253,24,107,151,239,203,193,22,101,211,230,184,229,158,75,47,7,216,53,216,160,219,74,229,139,111,214,85,89,11,18,147,253,77,0,46,23,197,213,163,88,22,202,151,254,195,183,206,159,218,171,230,171,175,110,138,250,191,68,118,251,211,226,214,63,191,244,80,57,23,225,189,165,248,149,46,159,91,223,190,161,155,7,254,41,60,244,95,81,222,126,199,121,254,27,86,89,138,21, + diff --git a/uppsrc/Draw/src.tpp/all.i b/uppsrc/Draw/src.tpp/all.i new file mode 100644 index 000000000..ecd2c14ee --- /dev/null +++ b/uppsrc/Draw/src.tpp/all.i @@ -0,0 +1,4 @@ +TOPIC("DPI_en-us") +#include "DPI_en-us.tppi" +END_TOPIC + diff --git a/uppsrc/ide/About.cpp b/uppsrc/ide/About.cpp index cd51c5754..9b02718e5 100644 --- a/uppsrc/ide/About.cpp +++ b/uppsrc/ide/About.cpp @@ -135,8 +135,10 @@ Size SplashCtrl::MakeLogo(Ctrl& parent, Array& ctrl, bool splash) #endif if(items.GetCount()) h << classes.GetCount() << " classes, " << items.GetCount() << " items\n"; - if(IsUHDMode()) - h << "UHD "; + + int scale = GetDPIScale(); + h << decode(scale, DPI_150, "QHD ", DPI_200, "UHD ", DPI_300, "XHD ", + AsString(50 * scale) + "% "); #ifdef GUI_GTK if(Ctrl::IsXWayland()) diff --git a/uppsrc/ide/IconDes/IconDes.lay b/uppsrc/ide/IconDes/IconDes.lay index c26755da1..d66732ca0 100644 --- a/uppsrc/ide/IconDes/IconDes.lay +++ b/uppsrc/ide/IconDes/IconDes.lay @@ -1,20 +1,20 @@ -LAYOUT(ImageLayout, 168, 252) +LAYOUT(ImageLayout, 168, 328) ITEM(Upp::Label, dv___0, SetLabel(t_("Name")).LeftPosZ(8, 40).TopPosZ(8, 19)) ITEM(Upp::EditString, name, LeftPosZ(52, 108).TopPosZ(8, 19)) ITEM(Upp::Label, dv___2, SetLabel(t_("Size")).LeftPosZ(8, 40).TopPosZ(32, 19)) ITEM(Upp::EditIntSpin, cx, Min(1).Max(8192).LeftPosZ(52, 44).TopPosZ(32, 19)) ITEM(Upp::Label, dv___4, SetLabel(t_("x")).LeftPosZ(100, 12).TopPosZ(32, 16)) ITEM(Upp::EditIntSpin, cy, Min(1).Max(8192).LeftPosZ(116, 44).TopPosZ(32, 19)) - ITEM(Upp::Option, fixed, SetLabel(t_("Fixed")).LeftPosZ(8, 156).TopPosZ(56, 16)) - ITEM(Upp::Option, fixed_colors, SetLabel(t_("Fixed colors")).LeftPosZ(12, 156).TopPosZ(72, 16)) - ITEM(Upp::Option, fixed_size, SetLabel(t_("Fixed size")).LeftPosZ(12, 156).TopPosZ(88, 16)) - ITEM(Upp::Option, uhd, SetLabel(t_("UHD variant")).LeftPosZ(8, 156).TopPosZ(112, 16)) - ITEM(Upp::Option, dark, SetLabel(t_("Dark variant")).LeftPosZ(8, 156).TopPosZ(128, 16)) - ITEM(Upp::Option, s3, SetLabel(t_("Supersampled 3x")).LeftPosZ(8, 156).TopPosZ(152, 16)) - ITEM(Upp::Option, exp, SetLabel(t_("Export as icon.ico and .png")).LeftPosZ(8, 160).TopPosZ(176, 16)) - ITEM(Upp::Button, ok, SetLabel(t_("OK")).LeftPosZ(28, 64).TopPosZ(220, 24)) - ITEM(Upp::Button, cancel, SetLabel(t_("Cancel")).LeftPosZ(96, 64).TopPosZ(220, 24)) - ITEM(Upp::Label, estimated_size, SetAlign(Upp::ALIGN_RIGHT).LeftPosZ(8, 156).TopPosZ(196, 19)) + ITEM(Upp::Option, fixed, SetLabel(t_("Fixed")).LeftPosZ(8, 156).TopPosZ(60, 16)) + ITEM(Upp::Option, fixed_colors, SetLabel(t_("Fixed colors")).LeftPosZ(12, 156).TopPosZ(76, 16)) + ITEM(Upp::Option, fixed_size, SetLabel(t_("Fixed size")).LeftPosZ(12, 156).TopPosZ(92, 16)) + ITEM(Upp::Option, dark, SetLabel(t_("Dark variant")).LeftPosZ(8, 156).TopPosZ(228, 16)) + ITEM(Upp::Option, exp, SetLabel(t_("Export as icon.ico and .png")).LeftPosZ(8, 160).TopPosZ(248, 16)) + ITEM(Upp::Button, ok, SetLabel(t_("OK")).LeftPosZ(28, 64).TopPosZ(296, 24)) + ITEM(Upp::Button, cancel, SetLabel(t_("Cancel")).LeftPosZ(96, 64).TopPosZ(296, 24)) + ITEM(Upp::Label, estimated_size, SetAlign(Upp::ALIGN_RIGHT).LeftPosZ(8, 156).TopPosZ(272, 19)) + ITEM(Upp::LabelBox, dv___14, SetLabel(t_("Target resolution")).LeftPosZ(8, 152).TopPosZ(112, 108)) + ITEM(Upp::Switch, scale, SetLabel(t_("600% (master)\n100% HD\n150% QHD\n200% UHD\n300% XHD")).LeftPosZ(16, 140).TopPosZ(132, 84)) END_LAYOUT LAYOUT(ImageSizeLayout, 168, 68) diff --git a/uppsrc/ide/IconDes/ImlFile.cpp b/uppsrc/ide/IconDes/ImlFile.cpp index 3069728ac..f06a0d319 100644 --- a/uppsrc/ide/IconDes/ImlFile.cpp +++ b/uppsrc/ide/IconDes/ImlFile.cpp @@ -46,9 +46,8 @@ void AlphaImageInfo::Serialize(Stream& stream) stream % size % hotspot % encoding; } -void ScanIML(CParser& parser, Array& out_images, - VectorMap& out_settings) -{ +void ScanIML(CParser& parser, Array& out_images, VectorMap& out_settings) +{ // This is for backward compatibility with the very old iml format String name, bid; bool exp = false; while(!parser.IsEof()) @@ -189,6 +188,12 @@ bool LoadIml(const String& data, Array& img, int& format) format = 0; try { bool premultiply = !p.Id("PREMULTIPLIED"); + int version = 0; + if(p.Id("VERSION")) { + p.Char('('); + version = p.ReadNumber(); + p.Char(')'); + } Vector name; Vector exp; while(p.Id("IMAGE_ID")) { @@ -242,10 +247,19 @@ bool LoadIml(const String& data, Array& img, int& format) for(int i = 0; i < count; i++) { ImlImage& c = img.Add(); (ImageIml &)c = m[i]; + if(version == 0) + c.flags &= IML_IMAGE_FLAG_QHD; c.name = name[ii]; c.exp = exp[ii++]; c.name.TrimEnd("__DARK"); c.name.TrimEnd("__UHD"); + c.name.TrimEnd("__100"); + c.name.TrimEnd("__150"); + c.name.TrimEnd("__200"); + c.name.TrimEnd("__250"); + c.name.TrimEnd("__300"); + c.name.TrimEnd("__350"); + c.name.TrimEnd("__600"); if(premultiply) c.image = Premultiply(c.image); } @@ -272,16 +286,16 @@ bool LoadIml(const String& data, Array& img, int& format) String SaveIml(const Array& iml, int format, const String& eol) { StringStream out; out << "PREMULTIPLIED" << eol; - Index names; + out << "VERSION(20260403)" << eol; Index saved_names; for(int i = 0; i < iml.GetCount(); i++) { const ImlImage& c = iml[i]; - names.FindAdd(c.name); out << "IMAGE_ID(" << c.name; - if((c.flags & (IML_IMAGE_FLAG_UHD|IML_IMAGE_FLAG_DARK)) == 0) + int scale = ImlFlagsToDPIScale(c.flags); + if(saved_names.Find(c.name) < 0) saved_names.FindAdd(c.name); - if(c.flags & IML_IMAGE_FLAG_UHD) - out << "__UHD"; + else + out << "__" << AsString(scale * 50); if(c.flags & IML_IMAGE_FLAG_DARK) out << "__DARK"; out << ")"; @@ -290,10 +304,6 @@ String SaveIml(const Array& iml, int format, const String& eol) { out << eol; } - for(String id : names) // allow UHD versions to be downscaled - if(saved_names.Find(id) < 0) - out << "IMAGE_ID(" << id << ")" << eol; - int ii = 0; while(ii < iml.GetCount()) { int bl = 0; diff --git a/uppsrc/ide/IconDes/List.cpp b/uppsrc/ide/IconDes/List.cpp index 3825ba18d..e30c6c46c 100644 --- a/uppsrc/ide/IconDes/List.cpp +++ b/uppsrc/ide/IconDes/List.cpp @@ -13,12 +13,10 @@ String IconDes::FormatImageName(const Slot& c) if(c.flags & IML_IMAGE_FLAG_FIXED_SIZE) r << " Sz"; } - if(c.flags & IML_IMAGE_FLAG_UHD) - r << " HD"; - if(c.flags & IML_IMAGE_FLAG_DARK) - r << " Dk"; - if(c.flags & IML_IMAGE_FLAG_S3) - r << " S3"; + + int scale = ImlFlagsToDPIScale(c.flags); + r << decode(scale, DPI_100, " 100%", DPI_150, " 150%", DPI_200, " 200%", DPI_300, " 300%", ""); + if(c.exp) r << " X"; return r; @@ -84,11 +82,11 @@ void IconDes::PrepareImageDlg(WithImageLayout& dlg) dlg.fixed <<= !!(flags & IML_IMAGE_FLAG_FIXED); dlg.fixed_colors <<= !!(flags & IML_IMAGE_FLAG_FIXED_COLORS); dlg.fixed_size <<= !!(flags & IML_IMAGE_FLAG_FIXED_SIZE); - - dlg.uhd <<= !!(flags & IML_IMAGE_FLAG_UHD); + dlg.dark <<= !!(flags & IML_IMAGE_FLAG_DARK); - dlg.s3 <<= !!(flags & IML_IMAGE_FLAG_S3); + int scale = ImlFlagsToDPIScale(flags); + dlg.scale = decode(scale, DPI_100, 1, DPI_150, 2, DPI_200, 3, DPI_300, 4, 0); for(Ctrl& q : dlg) if(dynamic_cast