From 9923c28ad9bd7ae35ba03586ae4a202ff3de0faf Mon Sep 17 00:00:00 2001 From: nakst <> Date: Mon, 13 Sep 2021 09:09:44 +0100 Subject: [PATCH] window color settings --- README.md | 6 +- desktop/api.cpp | 1 + desktop/desktop.cpp | 40 +--------- desktop/os.header | 1 + desktop/settings.cpp | 109 ++++++++++++++++++++++++-- desktop/theme.cpp | 11 +-- res/System Configuration Template.ini | 1 + shared/math.cpp | 8 ++ util/api_table.ini | 1 + util/designer/designer.c | 2 +- 10 files changed, 128 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index a89cb34..27e21fa 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/desktop/api.cpp b/desktop/api.cpp index 8f19b61..9e61cf8 100644 --- a/desktop/api.cpp +++ b/desktop/api.cpp @@ -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); diff --git a/desktop/desktop.cpp b/desktop/desktop.cpp index 550bcc0..d613baf 100644 --- a/desktop/desktop.cpp +++ b/desktop/desktop.cpp @@ -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) ®ion, (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. diff --git a/desktop/os.header b/desktop/os.header index 8c451f5..e550a0d 100644 --- a/desktop/os.header +++ b/desktop/os.header @@ -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); diff --git a/desktop/settings.cpp b/desktop/settings.cpp index bc6ba9f..3bb32f5 100644 --- a/desktop/settings.cpp +++ b/desktop/settings.cpp @@ -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"), ¤tWallpaperBytes); + 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[] = { diff --git a/desktop/theme.cpp b/desktop/theme.cpp index a69f5a3..aca543b 100644 --- a/desktop/theme.cpp +++ b/desktop/theme.cpp @@ -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 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 diff --git a/res/System Configuration Template.ini b/res/System Configuration Template.ini index 25f0ce8..96d895b 100644 --- a/res/System Configuration Template.ini +++ b/res/System Configuration Template.ini @@ -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 diff --git a/shared/math.cpp b/shared/math.cpp index 911eea9..5ddc321 100644 --- a/shared/math.cpp +++ b/shared/math.cpp @@ -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. ///////////////////////////////// diff --git a/util/api_table.ini b/util/api_table.ini index 7df435e..b945ee7 100644 --- a/util/api_table.ini +++ b/util/api_table.ini @@ -446,6 +446,7 @@ EsBufferReadInt32Endian=444 EsBufferWriteInt32Endian=445 EsSystemGetOptimalWorkQueueThreadCount=446 EsDeviceControl=447 +EsColorIsLight=448 EsListViewFixedItemRemove=449 EsIconIDFromDriveType=450 EsIconDisplaySetIcon=451 diff --git a/util/designer/designer.c b/util/designer/designer.c index 8c2d698..ace3e25 100644 --- a/util/designer/designer.c +++ b/util/designer/designer.c @@ -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