topic "Supporting UHD displays and Dark theme";
[l288;i1120;a17;O9;~~~.1408;2 $$1,0#10431211400427159095818037425705:param]
[a83;*R6 $$2,5#31310162474203024125188417583966:caption]
[H4;b83;m`.;N1;*4 $$3,5#07864147445237544204411237157677:title]
[i288;O9;C2 $$4,6#40027414424643823182269349404212:item]
[b42;a42;ph2 $$5,5#45413000475342174754091244180557:text]
[l288;b17;a17;2 $$6,6#27521748481378242620020725143825:desc]
[l321;C@5;1 $$7,7#20902679421464641399138805415013:code]
[b2503;2 $$8,0#65142375456100023862071332075487:separator]
[*@(0.0.255)2 $$9,0#83433469410354161042741608181528:base]
[C2 $$10,0#37138531426314131251341829483380:class]
[l288;a17;*1 $$11,11#70004532496200323422659154056402:requirement]
[i417;b42;a42;O9;~~~.416;2 $$12,12#10566046415157235020018451313112:tparam]
[b167;C2 $$13,13#92430459443460461911108080531343:item1]
[i288;a42;O9;C2 $$14,14#77422149456609303542238260500223:item2]
[*@2$(0.128.128)2 $$15,15#34511555403152284025741354420178:NewsDate]
[l321;*C$7;2 $$16,16#03451589433145915344929335295360:result]
[l321;b83;a83;*C$7;2 $$17,17#07531550463529505371228428965313:result`-line]
[l160;*C+117 $$18,5#88603949442205825958800053222425:package`-title]
[2 $$19,0#53580023442335529039900623488521:gap]
[C2 $$20,20#70211524482531209251820423858195:class`-nested]
[b50;2 $$21,21#03324558446220344731010354752573:Par]
[2 $$0,0#00000000000000000000000000000000:Default]
[{_}%EN-US 
[s2; Supporting UHD displays and Dark theme&]
[s3; Table of contents&]
[s0; &]
[s0; [^topic`:`/`/Draw`/srcdoc`/UhdAndDarkTheme`_en`-us`#1^ 1. GUI 
mode detection]&]
[s0; [^topic`:`/`/Draw`/srcdoc`/UhdAndDarkTheme`_en`-us`#2^ 2. Scaling 
GUI for actual GUI font and UHD resolution]&]
[s0; [^topic`:`/`/Draw`/srcdoc`/UhdAndDarkTheme`_en`-us`#3^ 3. Color 
adjustment]&]
[s0; [^topic`:`/`/Draw`/srcdoc`/UhdAndDarkTheme`_en`-us`#4^ 4. Iml 
files]&]
[s0; &]
[s3;:1: GUI mode detection&]
[s5; UHD mode is activated when standard GUI font is larger than 
24 pixels. Dark theme mode is activated if [* IsDark]([* SColorPaper]()), 
which means that grayscale value of default background is less 
than 80. Note that both modes create 4 combinations in total 
`- standard resolution with light theme, standard resolution 
with dark theme, UHD resolution with light theme, UHD resolution 
with dark theme.&]
[s5; [* IsUHDMode() ]and [* IsDarkTheme() ]functions return respective 
current GUI status.&]
[s3;:2: Scaling GUI for actual GUI font and UHD resolution&]
[s5; U`+`+ coordinates in drawing operations are always in real pixels 
for screen targets. U`+`+ provides various functions to adjust 
GUI elements metrics to host platform font size and UHD mode. 
Some of these function use `'font`-ratio`', which is the ratio 
of metrics of current default GUI font to `'design`-font`' (which 
is more or less defined as font where text `"OK Cancel Exit Retry`" 
has Size(99, 13), font ratio is then current GUI font Size vs 
this predefined size).&]
[ {{4916:5084^ [s0;b42;a42; int [* Zx](int cx);&]
[s0;b42;a42; double [* Zxf](double cx);]
::= [s5; Scales the value horizontally based on font ratio.]
::^ [s5; int [* Zy](int cy);]
::= [s5; Scales the value vertically based on font ratio.]
:: [s5; Size [* Zsz](int cx, int cy);&]
[s0;b42;a42; Size [* Zsz](Size sz);]
:: [s5; Scales size based on font ratio.]
:: [s5; Font [* FontZ](int face, int height `= 0);&]
[s5; Font [* StdFontZ](int height `= 0);&]
[s5; Font [* SansSerifZ](int height `= 0);&]
[s5; Font [* SerifZ](int height `= 0);&]
[s5; Font [* MonospaceZ](int height `= 0);&]
[s5; Font [* RomanZ](int height `= 0);&]
[s5; Font [* ArialZ](int height `= 0);&]
[s0;b42;a42; Font [* CourierZ](int height `= 0);]
:: [s5; Creates the font while scaling its height based on current font 
ratio. If height is 0, the height is set to current GUI font 
height.]
:: [s0;b42;a42; int [* DPI](int a);&]
[s0;b42;a42; double [* DPI](double a);&]
[s0;b42;a42; Size [* DPI](Size sz);&]
[s0;b42;a42; Size [* DPI](int cx, int cy);]
:: [s5; If UHD mode is active, returns the input argument multiplied 
by 2, otherwise returns it unchanged.]
:: [s0;b42;a42; Image [* DPI](const Image`& a, const Image`& b);]
:: [s5; Returns [* b] if UHD is active, [* a] otherwise.]}}&]
[s5; Usually [* DPI ]functions are used if the value is Image related, 
`'Z`' functions if it is text size related.&]
[s3;:3: Color adjustment&]
[s5; If application is specifying any colors, these colors need to 
be adjusted for dark theme. This can be often done by using [^topic`:`/`/Draw`/src`/Colors`_en`-us^ p
redefined colors]. Sometimes only the light theme color is available 
that needs to be converted to the dark theme `- this can be done 
using [* DarkTheme ]function. Alternatively [* AdjustIfDark] converts 
the color with [* DarkTheme] only if dark theme mode is currently 
active.&]
[s3;:4: Iml files&]
[s5; Iml files most often contain images that are used in GUI interface. 
Obviously, these images must be usually different for any of 
4 GUI modes.&]
[s5; .iml should always contain images for either standard or UHD 
resolution and the light theme. These images are used to define 
the set of icons.&]
[s5; U`+`+ then uses smart algorithms to convert such images for 
the current GUI mode. These work acceptably well in most cases.&]
[s5; Developer might decide to provide dedicated variants for any 
image for any target mode which will be used instead of converted 
basic icon. Such variant can be either placed into the same .iml 
file or into separate .iml file.&]
[s0; The complete control of the process is available in image details 
in the icon designer:&]
[s0; &]
[s0;= &]
[s0;= 
@@image:924&1482
([encoded data, 15040 characters])
&]
[s0; &]
[ {{2001:7999^ [s5; Fixed]
:: [s5; Image is never scaled or darkened to match current mode.]
:: [s5; Fixed colors]
:: [s5; Image is never darkened to match current mode. Set this if the 
image looks better in the dark mode without actually converting 
it.]
:: [s5; Fixed size]
:: [s5; Image is never scaled to match current mode.]
:: [s5; UHD variant]
:: [s5; Image is variant for UHD mode.]
:: [s5; Dark variant]
:: [s5; Image is variant for Dark theme.]
:: [s5; Supersampled 3x]
:: [s5; Image is downsampled 3x before use `- this simplifies design 
of antialiased images as images are drawn and stored as unaliased.]
:: [s5; Export...]
:: [s5; [/ This is unrelated to UHD / Dark theme mode, but if this is 
checked, the Image is exported as .ico and .png files. This is 
intended for application icon (e.g. shown in host shell).]]}}&]
[s0; &]
[s5; Finally, it is also possible to disable automatic conversion 
for the whole .iml file by #defining FIXED`_COLORS and/or FIXED`_SIZE 
macros:&]
[s0; &]
[s7; #define IMAGECLASS MyImg&]
[s7; #define IMAGEFILE <MyApp/MyImg.iml>&]
[s7; #define [* FIXED`_COLORS]&]
[s7; #define [* FIXED`_SIZE]&]
[s7; &]
[s7; #include <Draw/iml`_source.h>&]
[s0; &]
[s3;:4: Reacting to theme changes&]
[s5; Before 2025.1 U`+`+ release, the application skin was loaded 
from host platform just once at the start of execution and any 
if user changed host platform theme, this was not reflected in 
the application. Also changing to user defined or some predefined 
skin required restart of application to work properly.&]
[s5; Since 2025.1, application can be made to react to host platform 
changes and can change skins without restart with a call to Ctrl`::SkinChangeSensi
tive() (e.g. in GUI`_APP`_MAIN). However, this poses development 
challenges with switching between light theme and dark theme.&]
[s5; While application can easily react in Paint to current mode, 
situation is much more complicated when colors or images are 
used as attributes of widgets or widget contents. For example 
ArrayCtrl`::EvenRowColor can be called by developer to define 
some color that is appropriate for light theme, theme but when 
the theme is switched can be no longer viable.&]
[s5; U`+`+ provides several tools to handle this problem:&]
[s5;i150;O0; All .iml images are now considered `"special logical 
constants`" whose appearance changes according to current theme 
(dark / light) `- this applies to all copies as well.&]
[s5;i150;O0; [^topic`:`/`/Draw`/src`/Colors`_en`-us^ Predefined colors] 
constants are also `"special logical constants`" that are interpreted 
differently after theme switch.&]
[s5;i150;O0; Special logical type of Color `- SColor `- that is defined 
by function that is reevaluated after theme switch, e.g.&]
[s7; static SColor light`_highlight(`[`] `{ return Blend(SColorHighlight(), 
SColorPaper()) `});&]
[s0; &]
[s5;i150;O0; Another special logical type of Color `- AColor `- which 
should be defined as light theme color value, but when in dark 
theme, adjusts its value to the dark theme (with DarkThemeCached 
function)&]
[s5;i150;O0; RichText / QTF can use DarkThemeCached to adjust colors, 
which is automatically done e.g. in Labels or RichTextCtrl when 
rendered on dark backgrounds&]
[s5;i150;O0; If everything else fails, Ctrl`::Skin virtual function 
is always called on widget opening and on theme changes giving 
developer chance to alter colors are required&]
[s5; To simplify testing, in debug mode Ctrl `+ Num`[`*`] toggles 
quickly between light and dark theme `- that way developer can 
check whether colors adjust correctly to the situation.&]
[s5; Demonstration of these features is in reference/ThemeChangeSensitive 
example.]]