Skip to content

Commit 0f82451

Browse files
committed
Add cross-platform window background color support
Introduces a new Color abstraction and C API for color manipulation, including parsing from hex and conversion utilities. Adds SetBackgroundColor and GetBackgroundColor methods to the Window class and implements them for all supported platforms. Updates the C API to allow setting and retrieving window background color, and provides platform-specific implementations for Windows, macOS, Linux, Android, iOS, and OpenHarmony.
1 parent 930d6ba commit 0f82451

File tree

13 files changed

+570
-1
lines changed

13 files changed

+570
-1
lines changed

src/capi/color_c.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#include "color_c.h"
2+
#include "../foundation/color.h"
3+
#include <cstring>
4+
5+
using namespace nativeapi;
6+
7+
// Helper function to convert C++ Color to native_color_t
8+
static native_color_t to_native_color(const Color& color) {
9+
native_color_t result;
10+
result.r = color.r;
11+
result.g = color.g;
12+
result.b = color.b;
13+
result.a = color.a;
14+
return result;
15+
}
16+
17+
// Helper function to convert native_color_t to C++ Color
18+
static Color from_native_color(const native_color_t& color) {
19+
return Color{color.r, color.g, color.b, color.a};
20+
}
21+
22+
native_color_t native_color_from_rgba(unsigned char red,
23+
unsigned char green,
24+
unsigned char blue,
25+
unsigned char alpha) {
26+
native_color_t color;
27+
color.r = red;
28+
color.g = green;
29+
color.b = blue;
30+
color.a = alpha;
31+
return color;
32+
}
33+
34+
bool native_color_from_hex(const char* hex, native_color_t* out_color) {
35+
if (!hex || !out_color) {
36+
return false;
37+
}
38+
39+
try {
40+
Color color = Color::FromHex(hex);
41+
*out_color = to_native_color(color);
42+
return true;
43+
} catch (...) {
44+
return false;
45+
}
46+
}
47+
48+
uint32_t native_color_to_rgba(native_color_t color) {
49+
Color cpp_color = from_native_color(color);
50+
return cpp_color.ToRGBA();
51+
}
52+
53+
uint32_t native_color_to_argb(native_color_t color) {
54+
Color cpp_color = from_native_color(color);
55+
return cpp_color.ToARGB();
56+
}
57+
58+
// Predefined color constants
59+
extern "C" {
60+
const native_color_t NATIVE_COLOR_TRANSPARENT = {0, 0, 0, 0};
61+
const native_color_t NATIVE_COLOR_BLACK = {0, 0, 0, 255};
62+
const native_color_t NATIVE_COLOR_WHITE = {255, 255, 255, 255};
63+
const native_color_t NATIVE_COLOR_RED = {255, 0, 0, 255};
64+
const native_color_t NATIVE_COLOR_GREEN = {0, 255, 0, 255};
65+
const native_color_t NATIVE_COLOR_BLUE = {0, 0, 255, 255};
66+
const native_color_t NATIVE_COLOR_YELLOW = {255, 255, 0, 255};
67+
const native_color_t NATIVE_COLOR_CYAN = {0, 255, 255, 255};
68+
const native_color_t NATIVE_COLOR_MAGENTA = {255, 0, 255, 255};
69+
}

src/capi/color_c.h

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#pragma once
2+
3+
#include <stdbool.h>
4+
#include <stdint.h>
5+
6+
#if _WIN32
7+
#define FFI_PLUGIN_EXPORT __declspec(dllexport)
8+
#else
9+
#define FFI_PLUGIN_EXPORT
10+
#endif
11+
12+
#ifdef __cplusplus
13+
extern "C" {
14+
#endif
15+
16+
/**
17+
* @struct native_color_t
18+
* @brief Representation of a color with RGBA components
19+
*
20+
* Each component is represented as an unsigned byte (0-255).
21+
* Alpha value: 0 = fully transparent, 255 = fully opaque
22+
*/
23+
typedef struct {
24+
unsigned char r; /** Red component (0-255) */
25+
unsigned char g; /** Green component (0-255) */
26+
unsigned char b; /** Blue component (0-255) */
27+
unsigned char a; /** Alpha component (0-255) */
28+
} native_color_t;
29+
30+
/**
31+
* @brief Creates a color from RGBA values.
32+
*
33+
* @param red Red component (0-255)
34+
* @param green Green component (0-255)
35+
* @param blue Blue component (0-255)
36+
* @param alpha Alpha component (0-255)
37+
* @return Color instance with specified values
38+
*/
39+
FFI_PLUGIN_EXPORT
40+
native_color_t native_color_from_rgba(unsigned char red,
41+
unsigned char green,
42+
unsigned char blue,
43+
unsigned char alpha);
44+
45+
/**
46+
* @brief Creates a color from a hexadecimal string.
47+
*
48+
* Supports multiple hex color formats:
49+
* - "#RGB" - 3-digit hex (e.g., "#F00" = red)
50+
* - "#RGBA" - 4-digit hex with alpha
51+
* - "#RRGGBB" - 6-digit hex (e.g., "#FF0000" = red)
52+
* - "#RRGGBBAA" - 8-digit hex with alpha
53+
*
54+
* @param hex Hexadecimal color string (with or without '#' prefix)
55+
* @param out_color Pointer to store the resulting color
56+
* @return true if parsing succeeded, false otherwise
57+
*/
58+
FFI_PLUGIN_EXPORT
59+
bool native_color_from_hex(const char* hex, native_color_t* out_color);
60+
61+
/**
62+
* @brief Converts the color to a 32-bit integer (RGBA format).
63+
*
64+
* @param color The color to convert
65+
* @return 32-bit unsigned integer in RGBA format (0xRRGGBBAA)
66+
*/
67+
FFI_PLUGIN_EXPORT
68+
uint32_t native_color_to_rgba(native_color_t color);
69+
70+
/**
71+
* @brief Converts the color to a 32-bit integer (ARGB format).
72+
*
73+
* @param color The color to convert
74+
* @return 32-bit unsigned integer in ARGB format (0xAARRGGBB)
75+
*/
76+
FFI_PLUGIN_EXPORT
77+
uint32_t native_color_to_argb(native_color_t color);
78+
79+
// Predefined color constants
80+
FFI_PLUGIN_EXPORT
81+
extern const native_color_t NATIVE_COLOR_TRANSPARENT;
82+
83+
FFI_PLUGIN_EXPORT
84+
extern const native_color_t NATIVE_COLOR_BLACK;
85+
86+
FFI_PLUGIN_EXPORT
87+
extern const native_color_t NATIVE_COLOR_WHITE;
88+
89+
FFI_PLUGIN_EXPORT
90+
extern const native_color_t NATIVE_COLOR_RED;
91+
92+
FFI_PLUGIN_EXPORT
93+
extern const native_color_t NATIVE_COLOR_GREEN;
94+
95+
FFI_PLUGIN_EXPORT
96+
extern const native_color_t NATIVE_COLOR_BLUE;
97+
98+
FFI_PLUGIN_EXPORT
99+
extern const native_color_t NATIVE_COLOR_YELLOW;
100+
101+
FFI_PLUGIN_EXPORT
102+
extern const native_color_t NATIVE_COLOR_CYAN;
103+
104+
FFI_PLUGIN_EXPORT
105+
extern const native_color_t NATIVE_COLOR_MAGENTA;
106+
107+
#ifdef __cplusplus
108+
}
109+
#endif

src/capi/window_c.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,29 @@ native_visual_effect_t native_window_get_visual_effect(native_window_t window) {
608608
return static_cast<native_visual_effect_t>(win->GetVisualEffect());
609609
}
610610

611+
FFI_PLUGIN_EXPORT
612+
void native_window_set_background_color(native_window_t window, native_color_t color) {
613+
if (!window)
614+
return;
615+
auto* win = static_cast<nativeapi::Window*>(window);
616+
Color cpp_color = Color::FromRGBA(color.r, color.g, color.b, color.a);
617+
win->SetBackgroundColor(cpp_color);
618+
}
619+
620+
FFI_PLUGIN_EXPORT
621+
native_color_t native_window_get_background_color(native_window_t window) {
622+
native_color_t result = {255, 255, 255, 255}; // Default to white
623+
if (!window)
624+
return result;
625+
auto* win = static_cast<nativeapi::Window*>(window);
626+
Color cpp_color = win->GetBackgroundColor();
627+
result.r = cpp_color.r;
628+
result.g = cpp_color.g;
629+
result.b = cpp_color.b;
630+
result.a = cpp_color.a;
631+
return result;
632+
}
633+
611634
FFI_PLUGIN_EXPORT
612635
void native_window_set_visible_on_all_workspaces(native_window_t window, bool visible) {
613636
if (!window)

src/capi/window_c.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#define FFI_PLUGIN_EXPORT
1010
#endif
1111

12+
#include "color_c.h"
1213
#include "geometry_c.h"
1314

1415
#ifdef __cplusplus
@@ -236,6 +237,12 @@ void native_window_set_visual_effect(native_window_t window, native_visual_effec
236237
FFI_PLUGIN_EXPORT
237238
native_visual_effect_t native_window_get_visual_effect(native_window_t window);
238239

240+
FFI_PLUGIN_EXPORT
241+
void native_window_set_background_color(native_window_t window, native_color_t color);
242+
243+
FFI_PLUGIN_EXPORT
244+
native_color_t native_window_get_background_color(native_window_t window);
245+
239246
FFI_PLUGIN_EXPORT
240247
void native_window_set_visible_on_all_workspaces(native_window_t window, bool visible);
241248

src/foundation/color.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#include "color.h"
2+
#include <cstring>
3+
#include <stdexcept>
4+
5+
namespace nativeapi {
6+
7+
// Parse a single hex digit (0-9, A-F, a-f) to a value 0-15
8+
static unsigned char ParseHexDigit(char c) {
9+
if (c >= '0' && c <= '9')
10+
return c - '0';
11+
if (c >= 'A' && c <= 'F')
12+
return c - 'A' + 10;
13+
if (c >= 'a' && c <= 'f')
14+
return c - 'a' + 10;
15+
throw std::invalid_argument("Invalid hex digit");
16+
}
17+
18+
// Parse two hex digits to a byte value 0-255
19+
static unsigned char ParseHexByte(const char* hex) {
20+
return (ParseHexDigit(hex[0]) << 4) | ParseHexDigit(hex[1]);
21+
}
22+
23+
Color Color::FromHex(const char* hex) {
24+
if (!hex) {
25+
throw std::invalid_argument("Hex string cannot be null");
26+
}
27+
28+
// Skip leading '#' if present
29+
if (hex[0] == '#') {
30+
hex++;
31+
}
32+
33+
size_t len = std::strlen(hex);
34+
35+
// Parse based on format
36+
if (len == 3) {
37+
// #RGB format - expand each digit to two digits
38+
unsigned char r = ParseHexDigit(hex[0]);
39+
unsigned char g = ParseHexDigit(hex[1]);
40+
unsigned char b = ParseHexDigit(hex[2]);
41+
// Expand: F -> FF (15 -> 255)
42+
r = (r << 4) | r;
43+
g = (g << 4) | g;
44+
b = (b << 4) | b;
45+
return Color{r, g, b, 255};
46+
} else if (len == 4) {
47+
// #RGBA format - expand each digit to two digits
48+
unsigned char r = ParseHexDigit(hex[0]);
49+
unsigned char g = ParseHexDigit(hex[1]);
50+
unsigned char b = ParseHexDigit(hex[2]);
51+
unsigned char a = ParseHexDigit(hex[3]);
52+
r = (r << 4) | r;
53+
g = (g << 4) | g;
54+
b = (b << 4) | b;
55+
a = (a << 4) | a;
56+
return Color{r, g, b, a};
57+
} else if (len == 6) {
58+
// #RRGGBB format
59+
unsigned char r = ParseHexByte(hex);
60+
unsigned char g = ParseHexByte(hex + 2);
61+
unsigned char b = ParseHexByte(hex + 4);
62+
return Color{r, g, b, 255};
63+
} else if (len == 8) {
64+
// #RRGGBBAA format
65+
unsigned char r = ParseHexByte(hex);
66+
unsigned char g = ParseHexByte(hex + 2);
67+
unsigned char b = ParseHexByte(hex + 4);
68+
unsigned char a = ParseHexByte(hex + 6);
69+
return Color{r, g, b, a};
70+
} else {
71+
throw std::invalid_argument("Invalid hex color format. Expected #RGB, #RGBA, #RRGGBB, or #RRGGBBAA");
72+
}
73+
}
74+
75+
// Color constants
76+
const Color Color::Transparent = {0, 0, 0, 0};
77+
const Color Color::Black = {0, 0, 0, 255};
78+
const Color Color::White = {255, 255, 255, 255};
79+
const Color Color::Red = {255, 0, 0, 255};
80+
const Color Color::Green = {0, 255, 0, 255};
81+
const Color Color::Blue = {0, 0, 255, 255};
82+
const Color Color::Yellow = {255, 255, 0, 255};
83+
const Color Color::Cyan = {0, 255, 255, 255};
84+
const Color Color::Magenta = {255, 0, 255, 255};
85+
86+
} // namespace nativeapi

0 commit comments

Comments
 (0)