window color settings

This commit is contained in:
nakst 2021-09-13 09:09:44 +01:00
parent f82e5d9a30
commit 9923c28ad9
10 changed files with 128 additions and 52 deletions

View File

@ -11,7 +11,6 @@ To support development, you can donate to my Patreon: https://www.patreon.com/na
## Features
Kernel
* Audio mixer.
* Filesystem independent cache manager.
* Memory manager with shared memory, memory-mapped files and multithreaded paging zeroing and working set balancing.
* Networking stack for TCP/IP.
@ -19,6 +18,7 @@ Kernel
* On-demand module loading.
* Virtual filesystem.
* Window manager.
* Audio mixer. (being rewritten)
* Optional POSIX subsystem, capable of running GCC and some Busybox tools.
Applications
@ -52,7 +52,9 @@ Desktop
## Discussion
Visit https://essence.handmade.network/forums.
Join our Discord server: https://discord.gg/skeP9ZGDK8
Alternatively, visit the forums (not very active): https://essence.handmade.network/forums.
## Building

View File

@ -1275,6 +1275,7 @@ extern "C" void _start(EsProcessStartupInformation *_startupInformation) {
EsHeapFree(path);
SettingsUpdateGlobalAndWindowManager();
SettingsWindowColorUpdated();
} else {
EsHandle initialMountPointsBuffer = api.startupInformation->data.initialMountPoints;
size_t initialMountPointCount = EsConstantBufferGetSize(initialMountPointsBuffer) / sizeof(EsMountPoint);

View File

@ -1953,7 +1953,7 @@ void ConfigurationWriteToFile() {
if (ES_SUCCESS == EsPathDelete(EsLiteral(K_SYSTEM_CONFIGURATION))) {
if (ES_SUCCESS == EsPathMove(EsLiteral(K_SYSTEM_CONFIGURATION "_"), EsLiteral(K_SYSTEM_CONFIGURATION))) {
EsPrint("ConfigurationWriteToFile - New configuration successfully written.\n");
desktop.configurationModified = true;
desktop.configurationModified = false;
} else {
EsPrint("ConfigurationWriteToFile - Error while moving to final path.\n");
}
@ -1986,44 +1986,6 @@ void WallpaperLoad(EsGeneric) {
EsRectangle region = ES_RECT_2S(desktop.wallpaperWindow->windowWidth, desktop.wallpaperWindow->windowHeight);
EsSyscall(ES_SYSCALL_WINDOW_SET_BITS, desktop.wallpaperWindow->handle, (uintptr_t) &region, (uintptr_t) buffer, 0);
EsSyscall(ES_SYSCALL_SCREEN_FORCE_UPDATE, true, 0, 0, 0);
// Work out the most common hue on the wallpaper, and set the system hue.
uint32_t hueBuckets[36] = {};
uint32_t hueSelected = 0;
for (uintptr_t i = 0; i < desktop.wallpaperWindow->windowWidth * desktop.wallpaperWindow->windowHeight; i += 7) {
float h, s, v;
EsColorConvertToHSV(((uint32_t *) buffer)[i], &h, &s, &v);
uintptr_t bucket = (uintptr_t) (h * 6);
hueBuckets[bucket] += 2;
hueBuckets[bucket == 35 ? 0 : (bucket + 1)] += 1;
hueBuckets[bucket == 0 ? 35 : (bucket - 1)] += 1;
}
for (uintptr_t i = 1; i < 36; i++) {
if (hueBuckets[i] > hueBuckets[hueSelected]) {
hueSelected = i;
}
}
theming.systemHue = hueSelected / 6.0f;
if (theming.systemHue < 0) theming.systemHue += 6.0f;
EsHeapFree(buffer);
// Tell all container windows to redraw with the new system hue.
EsMessageMutexAcquire();
for (uintptr_t i = 0; i < gui.allWindows.Length(); i++) {
if (gui.allWindows[i]->windowStyle == ES_WINDOW_CONTAINER) {
gui.allWindows[i]->Repaint(true);
UIWindowNeedsUpdate(gui.allWindows[i]);
}
}
EsMessageMutexRelease();
}
// TODO Fade wallpaper in.

View File

@ -2067,6 +2067,7 @@ function double EsTimeStampMs();
// Graphics.
function uint32_t EsColorBlend(uint32_t under, uint32_t over, bool fullAlpha);
function bool EsColorIsLight(uint32_t color); // Returns true if you should black to draw atop the color.
function uint32_t EsColorConvertToRGB(float h, float s, float v); // 0 <= hue < 6; 0 <= saturation <= 1; 0 <= value <= 1.
function bool EsColorConvertToHSV(uint32_t color, float *h, float *s, float *v);
function uint32_t EsColorParse(STRING string);

View File

@ -51,6 +51,16 @@ const EsStyle styleSettingsGroupContainer2 = {
},
};
const uint32_t windowColors[] = {
0xFF0032, // Strawberry.
0xFF7F24, // Bronze.
0x77FFD4, // Grass.
0x448CF5, // Ocean.
0xAC00FF, // Violet.
0xE8ECF9, // Polar.
0xB7BBC5, // Space. TODO Looks bad deactivated.
};
const EsStyle styleSettingsGroupContainer3 = {
.inherit = ES_STYLE_BUTTON_GROUP_CONTAINER,
@ -74,8 +84,8 @@ const EsStyle styleSettingsNumberTextbox = {
const EsStyle styleSettingsTable = {
.metrics = {
.mask = ES_THEME_METRICS_GAP_MAJOR | ES_THEME_METRICS_GAP_MINOR,
.gapMajor = 5,
.gapMinor = 5,
.gapMajor = 7,
.gapMinor = 7,
},
};
@ -556,11 +566,83 @@ void SettingsPageDisplay(EsElement *element, SettingsPage *page) {
100, 400, INTERFACE_STRING(CommonUnitPercent), 0.05, 5);
}
int SettingsColorButtonMessage(EsElement *element, EsMessage *message) {
if (message->type == ES_MSG_PAINT_BACKGROUND) {
// HACK This assumes a lot about the workings of the radiobox style...
EsRectangle bounds = EsPainterBoundsClient(message->painter);
bounds.r = bounds.l + 14 * EsElementGetScaleFactor(element);
bounds = EsRectangleFit(bounds, ES_RECT_2S(1, 1), true);
uint32_t cornerRadius = Width(bounds);
uint32_t cornerRadii[4] = { cornerRadius, cornerRadius, cornerRadius, cornerRadius };
int32_t borderSize = 1 * EsElementGetScaleFactor(element);
uint32_t color = EsColorBlend(windowColors[element->userData.u] | 0xFF000000, 0x20FFFFFF, false);
if (element->window->pressed == element) color = EsColorBlend(color, 0x40000000, false);
EsDrawRoundedRectangle(message->painter, bounds, color, EsColorBlend(color, 0x40000000, false), ES_RECT_1(borderSize), cornerRadii);
if (EsButtonGetCheck((EsButton *) element) == ES_CHECK_CHECKED) {
int32_t inset = 4 * EsElementGetScaleFactor(element);
uint32_t bulletColor = EsColorIsLight(color) ? 0xFF000000 : 0xFFFFFFFF;
EsDrawRoundedRectangle(message->painter, EsRectangleAdd(bounds, ES_RECT_1I(inset)), bulletColor, 0, ES_RECT_1(0), cornerRadii);
}
return ES_HANDLED;
}
return 0;
}
void SettingsWindowColorUpdated() {
uint8_t index = EsSystemConfigurationReadInteger(EsLiteral("general"), EsLiteral("window_color"));
if (index > sizeof(windowColors) / sizeof(windowColors[0])) {
index = 0;
}
EsColorConvertToHSV(windowColors[index], &theming.systemHue, &theming.systemSaturation, &theming.systemValue);
if (theming.systemHue > 0.3f && theming.systemHue < 3.3f) {
theming.systemHueShift = -1.5f;
} else {
theming.systemHueShift = 1.0f;
}
for (uintptr_t i = 0; i < gui.allWindows.Length(); i++) {
if (gui.allWindows[i]->windowStyle == ES_WINDOW_CONTAINER) {
gui.allWindows[i]->Repaint(true);
UIWindowNeedsUpdate(gui.allWindows[i]);
}
}
}
void SettingsColorButtonCommand(EsInstance *, EsElement *element, EsCommand *) {
if (EsButtonGetCheck((EsButton *) element) != ES_CHECK_CHECKED) {
return;
}
EsMutexAcquire(&api.systemConfigurationMutex);
EsSystemConfigurationGroup *group = SystemConfigurationGetGroup("general", -1, true);
if (group) {
EsSystemConfigurationItem *item = SystemConfigurationGetItem(group, "window_color", -1, true);
if (item) {
EsHeapFree(item->value);
item->value = (char *) EsHeapAllocate(65, true);
item->valueBytes = EsStringFormat(item->value, 64, "%fd", ES_STRING_FORMAT_SIMPLE, element->userData.u);
}
}
EsMutexRelease(&api.systemConfigurationMutex);
SettingsWindowColorUpdated();
desktop.configurationModified = true;
ConfigurationWriteToFile();
}
void SettingsPageTheme(EsElement *element, SettingsPage *page) {
// TODO Fonts, theme file, etc.
EsElementSetHidden(((SettingsInstance *) element->instance)->undoButton, false);
EsPanel *content = EsPanelCreate(element, ES_CELL_FILL | ES_PANEL_V_SCROLL_AUTO, &styleNewTabContent);
EsPanel *container = EsPanelCreate(content, ES_PANEL_VERTICAL | ES_CELL_H_SHRINK, &styleSettingsGroupContainer2);
SettingsAddTitle(container, page);
@ -569,10 +651,15 @@ void SettingsPageTheme(EsElement *element, SettingsPage *page) {
EsIconDisplayCreate(warningRow, ES_FLAGS_DEFAULT, 0, ES_ICON_DIALOG_WARNING);
EsTextDisplayCreate(warningRow, ES_FLAGS_DEFAULT, 0, "Work in progress" ELLIPSIS);
EsPanel *table = EsPanelCreate(container, ES_CELL_H_FILL | ES_PANEL_TABLE | ES_PANEL_HORIZONTAL, &styleSettingsTable);
EsPanel *table = EsPanelCreate(container, ES_CELL_H_CENTER | ES_PANEL_TABLE | ES_PANEL_HORIZONTAL, &styleSettingsTable);
EsPanelSetBands(table, 2);
EsTextDisplayCreate(table, ES_CELL_H_RIGHT, 0, "Wallpaper:", -1);
EsTextbox *textbox = EsTextboxCreate(table, ES_CELL_H_LEFT | ES_CELL_H_PUSH | ES_TEXTBOX_EDIT_BASED | ES_ELEMENT_FREE_USER_DATA, ES_STYLE_TEXTBOX_BORDERED_SINGLE);
size_t currentWallpaperBytes;
char *currentWallpaper = EsSystemConfigurationReadString(EsLiteral("general"), EsLiteral("wallpaper"), &currentWallpaperBytes);
EsTextboxInsert(textbox, currentWallpaper, currentWallpaperBytes);
EsHeapFree(currentWallpaper);
textbox->messageUser = [] (EsElement *element, EsMessage *message) {
if (message->type == ES_MSG_TEXTBOX_EDIT_END) {
@ -597,6 +684,18 @@ void SettingsPageTheme(EsElement *element, SettingsPage *page) {
return 0;
};
EsTextDisplayCreate(table, ES_CELL_H_RIGHT, 0, "Window color:", -1);
EsPanel *panel = EsPanelCreate(table, ES_CELL_H_LEFT | ES_PANEL_HORIZONTAL);
uint8_t windowColor = EsSystemConfigurationReadInteger(EsLiteral("general"), EsLiteral("window_color"));
for (uintptr_t i = 0; i < sizeof(windowColors) / sizeof(windowColors[0]); i++) {
EsButton *button = EsButtonCreate(panel, ES_CELL_H_LEFT | ES_BUTTON_RADIOBOX | ES_ELEMENT_NO_FOCUS_ON_CLICK);
if (windowColor == i) EsButtonSetCheck(button, ES_CHECK_CHECKED);
button->userData.u = i;
button->messageUser = SettingsColorButtonMessage;
EsButtonOnCommand(button, SettingsColorButtonCommand);
}
}
SettingsPage settingsPages[] = {

View File

@ -110,7 +110,7 @@ typedef struct ThemeGradientStop {
typedef struct ThemePaintLinearGradient {
float transform[3];
uint8_t stopCount;
int8_t useGammaInterpolation : 1, useDithering : 1, useSystemHue : 1;
int8_t useGammaInterpolation : 1, useDithering : 1, useSystemColor : 1;
uint8_t repeatMode;
uint8_t _unused0;
// Followed by gradient stops.
@ -368,7 +368,7 @@ struct {
EsPaintTarget cursors;
float scale;
HashStore<UIStyleKey, struct UIStyle *> loadedStyles;
float systemHue;
float systemHue, systemSaturation, systemValue, systemHueShift;
} theming;
#endif
@ -630,12 +630,13 @@ void GradientCacheSetup(GradientCache *cache, const ThemePaintLinearGradient *gr
uint32_t color1 = stop1->color;
#ifndef IN_DESIGNER
if (gradient->useSystemHue) {
if (gradient->useSystemColor) {
float h, h2, s, v;
EsColorConvertToHSV(color0, &h, &s, &v);
color0 = (color0 & 0xFF000000) | EsColorConvertToRGB(theming.systemHue, s, v);
color0 = (color0 & 0xFF000000) | EsColorConvertToRGB(theming.systemHue, s * theming.systemSaturation, v * theming.systemValue);
EsColorConvertToHSV(color1, &h2, &s, &v);
color1 = (color1 & 0xFF000000) | EsColorConvertToRGB(theming.systemHue + (h2 - h), s, v);
color1 = (color1 & 0xFF000000) | EsColorConvertToRGB(theming.systemHue + (h2 - h) * theming.systemHueShift,
s * theming.systemSaturation, v * theming.systemValue);
}
#endif

View File

@ -7,6 +7,7 @@ click_chain_timeout_ms=500
show_cursor_shadow=1
scroll_lines_per_notch=3
ui_scale=100
window_color=3
[ui]
font_fallback=Inter

View File

@ -196,6 +196,14 @@ bool EsColorConvertToHSV(uint32_t color, float *h, float *s, float *v) {
}
}
bool EsColorIsLight(uint32_t color) {
float r = (color & 0xFF0000) >> 16;
float g = (color & 0x00FF00) >> 8;
float b = (color & 0x0000FF) >> 0;
float brightness = EsCRTsqrt(r * r * 0.241f + g * g * 0.691f + b * b * 0.068f);
return brightness >= 180.0f;
}
/////////////////////////////////
// Standard mathematical functions.
/////////////////////////////////

View File

@ -446,6 +446,7 @@ EsBufferReadInt32Endian=444
EsBufferWriteInt32Endian=445
EsSystemGetOptimalWorkQueueThreadCount=446
EsDeviceControl=447
EsColorIsLight=448
EsListViewFixedItemRemove=449
EsIconIDFromDriveType=450
EsIconDisplaySetIcon=451

View File

@ -707,7 +707,7 @@ void PaintLinearGradientOp(RfState *state, RfItem *item, void *pointer) {
EXPORT_FIELD(PaintLinearGradient, gradient, ThemePaintLinearGradient, themeGradient, transformStart, transform[2]);
themeGradient.useGammaInterpolation = gradient->useGammaInterpolation;
themeGradient.useDithering = gradient->useDithering;
themeGradient.useSystemHue = gradient->useSystemHue;
themeGradient.useSystemColor = gradient->useSystemHue;
themeGradient.stopCount = arrlenu(gradient->stops);
themeGradient.repeatMode = gradient->repeat == GRADIENT_REPEAT_CLAMP ? RAST_REPEAT_CLAMP
: gradient->repeat == GRADIENT_REPEAT_NORMAL ? RAST_REPEAT_NORMAL