diff --git a/.gitignore b/.gitignore index 602d694..97fced8 100644 --- a/.gitignore +++ b/.gitignore @@ -35,8 +35,9 @@ reports/ .*.sw? *.kate-swp gnupg/ - -# Package build artifacts +.github/copilot-instructions.md +.github/instructions/* +.github/agents/* *.deb *.rpm *.buildinfo @@ -46,9 +47,3 @@ packaging/debian/coolerdash/ packaging/debian/files packaging/debian/*.substvars packaging/debian/*.log - -# GitHub-specific ignores -# AI Copilot instructions (only relevant for developers) -.github/copilot-instructions.md -.github/instructions/copilot-instructions.md -.github/instructions/BEST_PRACTICES.instructions.md diff --git a/VERSION b/VERSION index eca07e4..ac2cdeb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.1.2 +2.1.3 diff --git a/etc/coolercontrol/plugins/coolerdash/ui/index.html b/etc/coolercontrol/plugins/coolerdash/ui/index.html index fb96215..1716af2 100644 --- a/etc/coolercontrol/plugins/coolerdash/ui/index.html +++ b/etc/coolercontrol/plugins/coolerdash/ui/index.html @@ -438,23 +438,47 @@

Layout
+ 0 = no border
+
+ + Toggle bar border on/off + +
+
+
+
+ +
+

Colors

+
+ + Main background color +
+ + +
+
+
@@ -751,10 +775,12 @@

Labels bar_width: 98, bar_gap: 12, bar_border: 2.0, + bar_border_enabled: true, label_margin_left: 1, label_margin_bar: 1 }, colors: { + display_background: { r: 0, g: 0, b: 0 }, bar_background: { r: 52, g: 52, b: 52 }, bar_border: { r: 192, g: 192, b: 192 }, font_temp: { r: 255, g: 255, b: 255 }, @@ -997,6 +1023,7 @@

Labels } // Add colors + config.colors.display_background = getColorFromPicker('color_display_background'); config.colors.bar_background = getColorFromPicker('color_bar_background'); config.colors.bar_border = getColorFromPicker('color_bar_border'); config.colors.font_temp = getColorFromPicker('color_font_temp'); @@ -1023,7 +1050,12 @@

Labels for (const [field, value] of Object.entries(fields)) { const input = document.querySelector(`[name="${section}.${field}"]`); if (input && typeof value !== 'object') { - input.value = value; + // Handle boolean values for select elements + if (typeof value === 'boolean') { + input.value = value ? "1" : "0"; + } else { + input.value = value; + } // Update UI if (field === 'brightness') { @@ -1038,6 +1070,7 @@

Labels // Color pickers if (config.colors) { + if (config.colors.display_background) setupColorPicker('color_display_background', 'rgb_display_background', config.colors.display_background); if (config.colors.bar_background) setupColorPicker('color_bar_background', 'rgb_bar_background', config.colors.bar_background); if (config.colors.bar_border) setupColorPicker('color_bar_border', 'rgb_bar_border', config.colors.bar_border); if (config.colors.font_temp) setupColorPicker('color_font_temp', 'rgb_font_temp', config.colors.font_temp); diff --git a/src/device/config.c b/src/device/config.c index 3661fa2..18dbba9 100644 --- a/src/device/config.c +++ b/src/device/config.c @@ -159,8 +159,12 @@ static void set_layout_defaults(Config *config) config->layout_bar_height = 24; if (config->layout_bar_gap == 0) config->layout_bar_gap = 12.0f; - if (config->layout_bar_border == 0.0f) + // bar_border: -1 = use default (2.0), 0 = explicitly disabled, >0 = custom value + if (config->layout_bar_border < 0.0f) config->layout_bar_border = 2.0f; + // bar_border_enabled: -1 = auto (enabled), 0 = disabled, 1 = enabled + if (config->layout_bar_border_enabled < 0) + config->layout_bar_border_enabled = 1; // Default: enabled } /** @@ -244,10 +248,11 @@ static void set_temperature_defaults(Config *config) /** * @brief Check if color is unset + * @details Uses is_set flag - all RGB values (0,0,0 to 255,255,255) are valid. */ static inline int is_color_unset(const Color *color) { - return (color->r == 0 && color->g == 0 && color->b == 0); + return (color->is_set == 0); } /** @@ -265,6 +270,7 @@ typedef struct static void set_color_defaults(Config *config) { ColorDefault color_defaults[] = { + {&config->display_background_color, 0, 0, 0}, // Main background (black) {&config->layout_bar_color_background, 52, 52, 52}, {&config->layout_bar_color_border, 192, 192, 192}, {&config->font_color_temp, 255, 255, 255}, @@ -336,6 +342,7 @@ static int read_color_from_json(json_t *color_obj, Color *color) color->r = (uint8_t)r_val; color->g = (uint8_t)g_val; color->b = (uint8_t)b_val; + color->is_set = 1; // Mark as user-defined return 1; } @@ -572,8 +579,18 @@ static void load_layout_from_json(json_t *root, Config *config) if (bar_border && json_is_number(bar_border)) { double val = json_number_value(bar_border); - if (val >= 0 && val <= 10) + if (val >= 0.0 && val <= 10.0) config->layout_bar_border = (float)val; + // Note: -1 in JSON means "use default" (handled in set_layout_defaults) + } + + json_t *bar_border_enabled = json_object_get(layout, "bar_border_enabled"); + if (bar_border_enabled) + { + if (json_is_boolean(bar_border_enabled)) + config->layout_bar_border_enabled = json_is_true(bar_border_enabled) ? 1 : 0; + else if (json_is_integer(bar_border_enabled)) + config->layout_bar_border_enabled = (int)json_integer_value(bar_border_enabled) != 0 ? 1 : 0; } json_t *label_margin_left = json_object_get(layout, "label_margin_left"); @@ -602,6 +619,7 @@ static void load_colors_from_json(json_t *root, Config *config) if (!colors || !json_is_object(colors)) return; + read_color_from_json(json_object_get(colors, "display_background"), &config->display_background_color); read_color_from_json(json_object_get(colors, "bar_background"), &config->layout_bar_color_background); read_color_from_json(json_object_get(colors, "bar_border"), &config->layout_bar_color_border); read_color_from_json(json_object_get(colors, "font_temp"), &config->font_color_temp); @@ -796,9 +814,12 @@ int load_plugin_config(Config *config, const char *config_path) return 0; } - // Initialize with defaults + // Initialize with defaults (memset sets all to 0, including color.is_set = 0) memset(config, 0, sizeof(Config)); config->display_inscribe_factor = -1.0f; // Sentinel for "auto" + config->layout_bar_border = -1.0f; // Sentinel for "use default" + config->layout_bar_border_enabled = -1; // Sentinel for "auto" (enabled) + // Note: All colors have is_set=0 after memset, so defaults will be applied // Try to find and load JSON config const char *json_path = find_config_json(config_path); diff --git a/src/device/config.h b/src/device/config.h index 69cbab8..4dd093f 100644 --- a/src/device/config.h +++ b/src/device/config.h @@ -29,15 +29,15 @@ /** * @brief Simple color structure. - * @details Represents RGB color values with 8-bit components and padding for - * memory alignment. + * @details Represents RGB color values with 8-bit components. + * The is_set flag indicates if color was explicitly configured. */ typedef struct { uint8_t r; uint8_t g; uint8_t b; - uint8_t _pad; + uint8_t is_set; // 0 = use default, 1 = user-defined (allows all RGB values) } Color; /** @@ -86,9 +86,11 @@ typedef struct Config uint16_t layout_bar_height; uint16_t layout_bar_gap; float layout_bar_border; + int layout_bar_border_enabled; // 1=enabled, 0=disabled, -1=auto (use default) uint8_t layout_bar_width; uint8_t layout_label_margin_left; uint8_t layout_label_margin_bar; + Color display_background_color; // Main display background color Color layout_bar_color_background; Color layout_bar_color_border; diff --git a/src/mods/circle.c b/src/mods/circle.c index 286ee39..0d64711 100644 --- a/src/mods/circle.c +++ b/src/mods/circle.c @@ -395,12 +395,15 @@ static void draw_single_sensor(cairo_t *cr, const struct Config *config, params->corner_radius); cairo_fill(cr); - // Bar border - set_cairo_color(cr, &config->layout_bar_color_border); - draw_rounded_rectangle_path(cr, bar_x, bar_y, effective_bar_width, bar_height, - params->corner_radius); - cairo_set_line_width(cr, config->layout_bar_border); - cairo_stroke(cr); + // Bar border (only if enabled and thickness > 0) + if (config->layout_bar_border_enabled && config->layout_bar_border > 0.0f) + { + set_cairo_color(cr, &config->layout_bar_color_border); + draw_rounded_rectangle_path(cr, bar_x, bar_y, effective_bar_width, bar_height, + params->corner_radius); + cairo_set_line_width(cr, config->layout_bar_border); + cairo_stroke(cr); + } // Bar fill (temperature-based) const float max_temp = config->temp_max_scale; @@ -432,12 +435,15 @@ static void draw_single_sensor(cairo_t *cr, const struct Config *config, bar_height, params->corner_radius); cairo_fill(cr); - // Liquid bar border - set_cairo_color(cr, &config->layout_bar_color_border); - draw_rounded_rectangle_path(cr, bar_x, liquid_bar_y, effective_bar_width, - bar_height, params->corner_radius); - cairo_set_line_width(cr, config->layout_bar_border); - cairo_stroke(cr); + // Liquid bar border (only if enabled and thickness > 0) + if (config->layout_bar_border_enabled && config->layout_bar_border > 0.0f) + { + set_cairo_color(cr, &config->layout_bar_color_border); + draw_rounded_rectangle_path(cr, bar_x, liquid_bar_y, effective_bar_width, + bar_height, params->corner_radius); + cairo_set_line_width(cr, config->layout_bar_border); + cairo_stroke(cr); + } // Liquid bar fill (0-40°C typical range for AIO coolers) const float max_liquid_temp = config->temp_liquid_max_scale; @@ -574,8 +580,8 @@ static void render_display_content(cairo_t *cr, const struct Config *config, if (!cr || !config || !data || !params) return; - // Draw background (black) - cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + // Draw main background + set_cairo_color(cr, &config->display_background_color); cairo_paint(cr); // Update sensor mode (check if configured interval elapsed) diff --git a/src/mods/dual.c b/src/mods/dual.c index dd21cb7..8eb344b 100644 --- a/src/mods/dual.c +++ b/src/mods/dual.c @@ -429,12 +429,15 @@ static void draw_single_temperature_bar(cairo_t *cr, cairo_fill(cr); } - // Border - cairo_set_line_width(cr, config->layout_bar_border); - set_cairo_color(cr, &config->layout_bar_color_border); - draw_rounded_rectangle_path(cr, bar_x, bar_y, bar_width, - config->layout_bar_height, params->corner_radius); - cairo_stroke(cr); + // Border (only if enabled and thickness > 0) + if (config->layout_bar_border_enabled && config->layout_bar_border > 0.0f) + { + cairo_set_line_width(cr, config->layout_bar_border); + set_cairo_color(cr, &config->layout_bar_color_border); + draw_rounded_rectangle_path(cr, bar_x, bar_y, bar_width, + config->layout_bar_height, params->corner_radius); + cairo_stroke(cr); + } } /** @@ -565,7 +568,8 @@ static void render_display_content(cairo_t *cr, const struct Config *config, const monitor_sensor_data_t *data, const ScalingParams *params) { - cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + // Draw main background + set_cairo_color(cr, &config->display_background_color); cairo_paint(cr); cairo_select_font_face(cr, config->font_face, CAIRO_FONT_SLANT_NORMAL, @@ -703,4 +707,4 @@ void draw_dual_image(const struct Config *config) { log_message(LOG_WARNING, "Skipping dual LCD upload - device not available"); } -} \ No newline at end of file +}