PR: Fixing settings && Adding a option for cursor scale (#11)

* Adding slider widget

* feat: Add mouse cursor scale commands and settings improvement speed

* Correct wallpaper scanning and thumbnail loading
This commit is contained in:
Lluciocc 2026-05-09 21:53:07 +02:00 committed by GitHub
parent 36ed0d4a9e
commit cfae88f9f5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 429 additions and 123 deletions

View file

@ -1476,6 +1476,11 @@ static uint64_t sys_cmd_set_mouse_speed(const syscall_args_t *args) {
return 0; return 0;
} }
static uint64_t sys_cmd_set_mouse_cursor_scale(const syscall_args_t *args) {
wm_set_cursor_scale_tenths((int)args->arg2);
return 0;
}
static uint64_t sys_cmd_network_init(const syscall_args_t *args) { static uint64_t sys_cmd_network_init(const syscall_args_t *args) {
(void)args; (void)args;
extern int network_init(void); extern int network_init(void);
@ -1501,6 +1506,11 @@ static uint64_t sys_cmd_get_mouse_speed(const syscall_args_t *args) {
return mouse_speed; return mouse_speed;
} }
static uint64_t sys_cmd_get_mouse_cursor_scale(const syscall_args_t *args) {
(void)args;
return (uint64_t)wm_get_cursor_scale_tenths();
}
static uint64_t sys_cmd_get_wallpaper_thumb(const syscall_args_t *args) { static uint64_t sys_cmd_get_wallpaper_thumb(const syscall_args_t *args) {
(void)args; (void)args;
return -1; return -1;
@ -2415,6 +2425,8 @@ static const syscall_handler_fn sys_cmd_table[SYS_CMD_TABLE_SIZE] = {
[SYSTEM_CMD_PARALLEL_RUN] = sys_cmd_parallel_run, [SYSTEM_CMD_PARALLEL_RUN] = sys_cmd_parallel_run,
[SYSTEM_CMD_SET_KEYBOARD_LAYOUT] = sys_cmd_set_keyboard_layout, [SYSTEM_CMD_SET_KEYBOARD_LAYOUT] = sys_cmd_set_keyboard_layout,
[SYSTEM_CMD_GET_KEYBOARD_LAYOUT] = sys_cmd_get_keyboard_layout, [SYSTEM_CMD_GET_KEYBOARD_LAYOUT] = sys_cmd_get_keyboard_layout,
[SYSTEM_CMD_SET_MOUSE_CURSOR_SCALE] = sys_cmd_set_mouse_cursor_scale,
[SYSTEM_CMD_GET_MOUSE_CURSOR_SCALE] = sys_cmd_get_mouse_cursor_scale,
[SYSTEM_CMD_TTY_CREATE] = sys_cmd_tty_create, [SYSTEM_CMD_TTY_CREATE] = sys_cmd_tty_create,
[SYSTEM_CMD_TTY_READ_OUT] = sys_cmd_tty_read_out, [SYSTEM_CMD_TTY_READ_OUT] = sys_cmd_tty_read_out,
[SYSTEM_CMD_TTY_WRITE_IN] = sys_cmd_tty_write_in, [SYSTEM_CMD_TTY_WRITE_IN] = sys_cmd_tty_write_in,

View file

@ -103,6 +103,8 @@ typedef struct {
#define SYSTEM_CMD_SET_KEYBOARD_LAYOUT 49 #define SYSTEM_CMD_SET_KEYBOARD_LAYOUT 49
#define SYSTEM_CMD_PARALLEL_RUN 50 #define SYSTEM_CMD_PARALLEL_RUN 50
#define SYSTEM_CMD_GET_KEYBOARD_LAYOUT 51 #define SYSTEM_CMD_GET_KEYBOARD_LAYOUT 51
#define SYSTEM_CMD_SET_MOUSE_CURSOR_SCALE 52
#define SYSTEM_CMD_GET_MOUSE_CURSOR_SCALE 53
#define SYSTEM_CMD_TTY_CREATE 60 #define SYSTEM_CMD_TTY_CREATE 60
#define SYSTEM_CMD_TTY_READ_OUT 61 #define SYSTEM_CMD_TTY_READ_OUT 61
#define SYSTEM_CMD_TTY_WRITE_IN 62 #define SYSTEM_CMD_TTY_WRITE_IN 62

View file

@ -62,6 +62,8 @@ static widget_dropdown_t drop_keyboard;
static widget_textbox_t tb_r, tb_g, tb_b; static widget_textbox_t tb_r, tb_g, tb_b;
static widget_textbox_t tb_ip, tb_dns; static widget_textbox_t tb_ip, tb_dns;
static widget_button_t btn_apply, btn_back; static widget_button_t btn_apply, btn_back;
static widget_slider_t slider_mouse;
static widget_slider_t slider_cursor_size;
#define MAX_WALLPAPERS 10 #define MAX_WALLPAPERS 10
@ -199,16 +201,20 @@ typedef struct {
char name[64]; char name[64];
uint32_t thumb[WALLPAPER_THUMB_W * WALLPAPER_THUMB_H]; uint32_t thumb[WALLPAPER_THUMB_W * WALLPAPER_THUMB_H];
_Bool valid; _Bool valid;
_Bool thumb_loaded;
} wallpaper_entry_t; } wallpaper_entry_t;
static wallpaper_entry_t wallpapers[MAX_WALLPAPERS]; static wallpaper_entry_t wallpapers[MAX_WALLPAPERS];
static int wallpaper_count = 0; static int wallpaper_count = 0;
static _Bool wallpapers_scanned = 0;
static int next_wallpaper_thumb = 0;
static _Bool desktop_snap_to_grid = 1; static _Bool desktop_snap_to_grid = 1;
static _Bool desktop_auto_align = 1; static _Bool desktop_auto_align = 1;
static int desktop_max_rows_per_col = 10; static int desktop_max_rows_per_col = 10;
static int desktop_max_cols = 10; static int desktop_max_cols = 10;
static int mouse_speed = 10; static int mouse_speed = 10;
static int mouse_cursor_scale_tenths = 10;
static int font_count = 0; static int font_count = 0;
static int selected_font = -1; static int selected_font = -1;
@ -229,6 +235,22 @@ static void cli_itoa(int num, char *str) {
} }
} }
static void format_scale_tenths(int scale_tenths, char *str) {
if (scale_tenths < 10) scale_tenths = 10;
if (scale_tenths > 40) scale_tenths = 40;
char whole[4];
cli_itoa(scale_tenths / 10, whole);
strcpy(str, whole);
int len = 0;
while (str[len]) len++;
str[len++] = '.';
str[len++] = (char)('0' + (scale_tenths % 10));
str[len++] = 'x';
str[len] = 0;
}
static void generate_lumberjack_pattern(void) { static void generate_lumberjack_pattern(void) {
uint32_t red = 0xFFDC143C; uint32_t red = 0xFFDC143C;
uint32_t dark_grey = 0xFF404040; uint32_t dark_grey = 0xFF404040;
@ -388,9 +410,15 @@ static void load_settings_icons(void) {
static void decode_wallpapers_task(void *arg) { static void decode_wallpapers_task(void *arg) {
(void)arg; (void)arg;
wallpaper_count = 0; wallpaper_count = 0;
next_wallpaper_thumb = 0;
wallpapers_scanned = 0;
FAT32_FileInfo info[MAX_WALLPAPERS]; FAT32_FileInfo info[MAX_WALLPAPERS];
int count = sys_list("/Library/images/Wallpapers", info, MAX_WALLPAPERS); int count = sys_list("/Library/images/Wallpapers", info, MAX_WALLPAPERS);
if (count < 0) return; if (count < 0) {
wallpapers_scanned = 1;
return;
}
for (int i = 0; i < count && wallpaper_count < MAX_WALLPAPERS; i++) { for (int i = 0; i < count && wallpaper_count < MAX_WALLPAPERS; i++) {
if (info[i].is_directory) continue; // Skip directories if (info[i].is_directory) continue; // Skip directories
@ -404,6 +432,9 @@ static void decode_wallpapers_task(void *arg) {
if (c1 != 'g' || c2 != 'p' || c3 != 'j') continue; if (c1 != 'g' || c2 != 'p' || c3 != 'j') continue;
wallpaper_entry_t *wp = &wallpapers[wallpaper_count]; wallpaper_entry_t *wp = &wallpapers[wallpaper_count];
wp->valid = 0;
wp->thumb_loaded = 0;
// Set path // Set path
char *pref = "/Library/images/Wallpapers/"; char *pref = "/Library/images/Wallpapers/";
int pl = 0; while (pref[pl]) { wp->path[pl] = pref[pl]; pl++; } int pl = 0; while (pref[pl]) { wp->path[pl] = pref[pl]; pl++; }
@ -414,13 +445,41 @@ static void decode_wallpapers_task(void *arg) {
for (int j = 0; j < nl - 4 && j < 63; j++) wp->name[j] = info[i].name[j]; for (int j = 0; j < nl - 4 && j < 63; j++) wp->name[j] = info[i].name[j];
wp->name[(nl-4 < 63) ? nl-4 : 63] = 0; wp->name[(nl-4 < 63) ? nl-4 : 63] = 0;
// Load and generate thumbnail int tx = (wallpaper_count % 3) * (WALLPAPER_THUMB_W + 15);
int ty = (wallpaper_count / 3) * (WALLPAPER_THUMB_H + 30);
widget_button_init(&btn_wp_thumbs[wallpaper_count], 8 + tx, 306 + ty, WALLPAPER_THUMB_W + 8, WALLPAPER_THUMB_H + 26, "");
wallpaper_count++;
}
wallpapers_scanned = 1;
}
static void load_wallpapers(void) {
void *job_args[1] = { NULL };
sys_parallel_run(decode_wallpapers_task, job_args, 1);
}
static bool load_next_wallpaper_thumb(void) {
if (!wallpapers_scanned) return false;
while (next_wallpaper_thumb < wallpaper_count) {
wallpaper_entry_t *wp = &wallpapers[next_wallpaper_thumb];
next_wallpaper_thumb++;
if (wp->thumb_loaded) continue;
wp->thumb_loaded = 1;
char cache_path[256]; char cache_path[256];
int cp = 0; int cp = 0;
char *cpref = "/Library/Caches/Thumbnails/"; char *cpref = "/Library/Caches/Thumbnails/";
while (cpref[cp]) { cache_path[cp] = cpref[cp]; cp++; } while (cpref[cp]) { cache_path[cp] = cpref[cp]; cp++; }
int prefix_len = 0;
char *pref = "/Library/images/Wallpapers/";
while (pref[prefix_len] && wp->path[prefix_len] == pref[prefix_len]) prefix_len++;
int cn = 0; int cn = 0;
while (info[i].name[cn]) { cache_path[cp+cn] = info[i].name[cn]; cn++; } while (wp->path[prefix_len + cn]) { cache_path[cp + cn] = wp->path[prefix_len + cn]; cn++; }
char *csuf = ".bin"; char *csuf = ".bin";
int cs = 0; int cs = 0;
while (csuf[cs]) { cache_path[cp + cn + cs] = csuf[cs]; cs++; } while (csuf[cs]) { cache_path[cp + cn + cs] = csuf[cs]; cs++; }
@ -431,7 +490,9 @@ static void decode_wallpapers_task(void *arg) {
sys_read(cfd, wp->thumb, WALLPAPER_THUMB_W * WALLPAPER_THUMB_H * 4); sys_read(cfd, wp->thumb, WALLPAPER_THUMB_W * WALLPAPER_THUMB_H * 4);
sys_close(cfd); sys_close(cfd);
wp->valid = 1; wp->valid = 1;
} else { return true;
}
int fd = sys_open(wp->path, "r"); int fd = sys_open(wp->path, "r");
if (fd >= 0) { if (fd >= 0) {
int size = sys_seek(fd, 0, 2); // SEEK_END int size = sys_seek(fd, 0, 2); // SEEK_END
@ -445,9 +506,7 @@ static void decode_wallpapers_task(void *arg) {
if (img && img_w > 0 && img_h > 0) { if (img && img_w > 0 && img_h > 0) {
scale_rgba_to_argb(img, img_w, img_h, wp->thumb, WALLPAPER_THUMB_W, WALLPAPER_THUMB_H); scale_rgba_to_argb(img, img_w, img_h, wp->thumb, WALLPAPER_THUMB_W, WALLPAPER_THUMB_H);
wp->valid = 1; wp->valid = 1;
stbi_image_free(img);
// Save to cache
sys_mkdir("/Library/Caches"); sys_mkdir("/Library/Caches");
sys_mkdir("/Library/Caches/Thumbnails"); sys_mkdir("/Library/Caches/Thumbnails");
int swfd = sys_open(cache_path, "w"); int swfd = sys_open(cache_path, "w");
@ -456,26 +515,17 @@ static void decode_wallpapers_task(void *arg) {
sys_close(swfd); sys_close(swfd);
} }
} }
if (img) stbi_image_free(img);
free(buf); free(buf);
} }
} }
sys_close(fd); sys_close(fd);
} }
return true;
} }
wallpaper_count++; return false;
}
}
static void load_wallpapers(void) {
void *job_args[1] = { NULL };
sys_parallel_run(decode_wallpapers_task, job_args, 1);
for (int i = 0; i < wallpaper_count; i++) {
int tx = (i % 3) * (WALLPAPER_THUMB_W + 15);
int ty = (i / 3) * (WALLPAPER_THUMB_H + 30);
widget_button_init(&btn_wp_thumbs[i], 8 + tx, 306 + ty, WALLPAPER_THUMB_W + 8, WALLPAPER_THUMB_H + 20, "");
}
} }
static uint32_t parse_rgb_separate(const char *r, const char *g, const char *b) { static uint32_t parse_rgb_separate(const char *r, const char *g, const char *b) {
@ -498,7 +548,6 @@ static uint32_t parse_rgb_separate(const char *r, const char *g, const char *b)
static void control_panel_paint_main(ui_window_t win) { static void control_panel_paint_main(ui_window_t win) {
int offset_x = 8; int offset_x = 8;
int offset_y = 6; int offset_y = 6;
int win_w = 350;
int item_y = 0; int item_y = 0;
int item_h = 60; int item_h = 60;
@ -815,15 +864,23 @@ static void control_panel_paint_mouse(ui_window_t win) {
int section_y = offset_y + 65; int section_y = offset_y + 65;
ui_draw_string(win, offset_x, section_y, "Speed:", COLOR_DARK_TEXT); ui_draw_string(win, offset_x, section_y, "Speed:", COLOR_DARK_TEXT);
ui_draw_rounded_rect_filled(win, offset_x + 60, section_y + 8, 200, 8, 4, COLOR_DARK_PANEL); slider_mouse.value = (float)mouse_speed;
widget_slider_draw(&settings_ctx, &slider_mouse);
int knob_x = offset_x + 60 + (mouse_speed - 1) * 190 / 49;
ui_draw_rounded_rect_filled(win, knob_x, section_y + 2, 10, 14, 3, 0xFF4A90E2);
ui_draw_string(win, offset_x + 270, section_y + 4, "x", COLOR_DARK_TEXT); ui_draw_string(win, offset_x + 270, section_y + 4, "x", COLOR_DARK_TEXT);
char speed_str[4]; char speed_str[4];
cli_itoa(mouse_speed, speed_str); cli_itoa(mouse_speed, speed_str);
ui_draw_string(win, offset_x + 280, section_y + 4, speed_str, COLOR_DARK_TEXT); ui_draw_string(win, offset_x + 280, section_y + 4, speed_str, COLOR_DARK_TEXT);
section_y += 40;
ui_draw_string(win, offset_x, section_y, "Size:", COLOR_DARK_TEXT);
slider_cursor_size.value = (float)mouse_cursor_scale_tenths;
widget_slider_draw(&settings_ctx, &slider_cursor_size);
char scale_str[8];
format_scale_tenths(mouse_cursor_scale_tenths, scale_str);
ui_draw_string(win, offset_x + 270, section_y + 4, scale_str, COLOR_DARK_TEXT);
} }
static void on_font_scroll(void *user_data, int new_scroll_y) { static void on_font_scroll(void *user_data, int new_scroll_y) {
@ -982,6 +1039,7 @@ static void save_desktop_config(void) {
static void save_mouse_config(void) { static void save_mouse_config(void) {
sys_system(SYSTEM_CMD_SET_MOUSE_SPEED, mouse_speed, 0, 0, 0); sys_system(SYSTEM_CMD_SET_MOUSE_SPEED, mouse_speed, 0, 0, 0);
sys_system(SYSTEM_CMD_SET_MOUSE_CURSOR_SCALE, mouse_cursor_scale_tenths, 0, 0, 0);
} }
static int parse_ip(const char* str, net_ipv4_address_t* ip) { static int parse_ip(const char* str, net_ipv4_address_t* ip) {
@ -1006,41 +1064,7 @@ static int parse_ip(const char* str, net_ipv4_address_t* ip) {
return 0; return 0;
} }
static void fetch_kernel_state(void) {
desktop_snap_to_grid = sys_system(SYSTEM_CMD_GET_DESKTOP_PROP, 1, 0, 0, 0);
desktop_auto_align = sys_system(SYSTEM_CMD_GET_DESKTOP_PROP, 2, 0, 0, 0);
desktop_max_rows_per_col = sys_system(SYSTEM_CMD_GET_DESKTOP_PROP, 3, 0, 0, 0);
desktop_max_cols = sys_system(SYSTEM_CMD_GET_DESKTOP_PROP, 4, 0, 0, 0);
mouse_speed = sys_system(SYSTEM_CMD_GET_MOUSE_SPEED, 0, 0, 0, 0);
net_ipv4_address_t kip;
if (sys_network_get_ip(&kip) == 0) {
char bp[4];
net_ip[0] = 0;
for (int i=0; i<4; i++) {
cli_itoa(kip.bytes[i], bp);
strcat(net_ip, bp);
if (i < 3) strcat(net_ip, ".");
}
}
if (sys_get_dns_server(&kip) == 0) {
char bp[4];
net_dns[0] = 0;
for (int i=0; i<4; i++) {
cli_itoa(kip.bytes[i], bp);
strcat(net_dns, bp);
if (i < 3) strcat(net_dns, ".");
}
}
init_dynamic_resolutions();
load_wallpapers();
}
static void control_panel_handle_mouse(int x, int y, bool is_down, bool is_click) { static void control_panel_handle_mouse(int x, int y, bool is_down, bool is_click) {
int win_w = 350;
if (current_view != VIEW_MAIN && widget_button_handle_mouse(&btn_back, x, y, is_down, is_click, NULL)) { if (current_view != VIEW_MAIN && widget_button_handle_mouse(&btn_back, x, y, is_down, is_click, NULL)) {
if (is_click) { if (is_click) {
current_view = VIEW_MAIN; current_view = VIEW_MAIN;
@ -1218,7 +1242,12 @@ static void control_panel_handle_mouse(int x, int y, bool is_down, bool is_click
if (current_view == VIEW_MAIN) { if (current_view == VIEW_MAIN) {
if (widget_button_handle_mouse(&btn_main_wallpaper, x, y, is_down, is_click, NULL)) { if (widget_button_handle_mouse(&btn_main_wallpaper, x, y, is_down, is_click, NULL)) {
if (is_click) { current_view = VIEW_WALLPAPER; focused_field = -1; btn_main_wallpaper.pressed = false; } if (is_click) {
current_view = VIEW_WALLPAPER;
focused_field = -1;
btn_main_wallpaper.pressed = false;
load_wallpapers();
}
return; return;
} }
if (widget_button_handle_mouse(&btn_main_network, x, y, is_down, is_click, NULL)) { if (widget_button_handle_mouse(&btn_main_network, x, y, is_down, is_click, NULL)) {
@ -1255,18 +1284,26 @@ static void control_panel_handle_mouse(int x, int y, bool is_down, bool is_click
} }
if (current_view == VIEW_MOUSE) { if (current_view == VIEW_MOUSE) {
if (is_down || is_click) { if (widget_slider_handle_mouse(&slider_mouse, x, y, is_down, is_click, NULL)) {
int offset_x = 8; int new_speed = (int)(slider_mouse.value);
int offset_y = 6; focused_field = -1; // slider doesn't use textbox, so clear focus on click
int section_y = offset_y + 65;
if (x >= offset_x + 60 && x <= offset_x + 260 && y >= section_y && y <= section_y + 20) { if (new_speed != mouse_speed) {
int new_speed = 1 + (x - (offset_x + 60)) * 49 / 200;
if (new_speed < 1) new_speed = 1;
if (new_speed > 50) new_speed = 50;
mouse_speed = new_speed; mouse_speed = new_speed;
save_mouse_config(); save_mouse_config();
}
return; return;
} }
if (widget_slider_handle_mouse(&slider_cursor_size, x, y, is_down, is_click, NULL)) {
int new_scale = (int)(slider_cursor_size.value);
focused_field = -1;
if (new_scale != mouse_cursor_scale_tenths) {
mouse_cursor_scale_tenths = new_scale;
save_mouse_config();
}
return;
} }
} }
@ -1385,6 +1422,12 @@ static void init_settings_widgets(void) {
// Display View Textboxes // Display View Textboxes
widget_textbox_init(&tb_custom_w, 8, 276, 60, 25, custom_res_w, 5); widget_textbox_init(&tb_custom_w, 8, 276, 60, 25, custom_res_w, 5);
widget_textbox_init(&tb_custom_h, 88, 276, 60, 25, custom_res_h, 5); widget_textbox_init(&tb_custom_h, 88, 276, 60, 25, custom_res_h, 5);
widget_slider_init(&slider_mouse, 68, 71, 200, 20, 1.0f, 50.0f, (float)mouse_speed);
slider_mouse.step = 1.0f;
widget_slider_init(&slider_cursor_size, 68, 111, 200, 20, 10.0f, 40.0f, (float)mouse_cursor_scale_tenths);
slider_cursor_size.step = 1.0f;
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
@ -1404,6 +1447,9 @@ int main(int argc, char **argv) {
desktop_max_rows_per_col = sys_system(SYSTEM_CMD_GET_DESKTOP_PROP, 3, 0, 0, 0); desktop_max_rows_per_col = sys_system(SYSTEM_CMD_GET_DESKTOP_PROP, 3, 0, 0, 0);
desktop_max_cols = sys_system(SYSTEM_CMD_GET_DESKTOP_PROP, 4, 0, 0, 0); desktop_max_cols = sys_system(SYSTEM_CMD_GET_DESKTOP_PROP, 4, 0, 0, 0);
mouse_speed = sys_system(SYSTEM_CMD_GET_MOUSE_SPEED, 0, 0, 0, 0); mouse_speed = sys_system(SYSTEM_CMD_GET_MOUSE_SPEED, 0, 0, 0, 0);
mouse_cursor_scale_tenths = sys_system(SYSTEM_CMD_GET_MOUSE_CURSOR_SCALE, 0, 0, 0, 0);
if (mouse_cursor_scale_tenths < 10) mouse_cursor_scale_tenths = 10;
if (mouse_cursor_scale_tenths > 40) mouse_cursor_scale_tenths = 40;
load_settings_icons(); load_settings_icons();
// Set initial widget states // Set initial widget states
@ -1418,8 +1464,6 @@ int main(int argc, char **argv) {
control_panel_paint(win); control_panel_paint(win);
ui_mark_dirty(win, 0, 0, 350, 500); ui_mark_dirty(win, 0, 0, 350, 500);
load_wallpapers(); // load after first paint to avoid startup delay
gui_event_t ev; gui_event_t ev;
while (1) { while (1) {
bool dirty = false; bool dirty = false;
@ -1429,12 +1473,11 @@ int main(int argc, char **argv) {
dirty = true; dirty = true;
} else if (ev.type == GUI_EVENT_CLICK || } else if (ev.type == GUI_EVENT_CLICK ||
ev.type == GUI_EVENT_MOUSE_DOWN ||
ev.type == GUI_EVENT_MOUSE_MOVE || ev.type == GUI_EVENT_MOUSE_MOVE ||
ev.type == GUI_EVENT_MOUSE_UP) { ev.type == GUI_EVENT_MOUSE_UP) {
bool down = false; bool down = false;
if (ev.type == GUI_EVENT_MOUSE_DOWN || ev.type == GUI_EVENT_CLICK) { if (ev.type == GUI_EVENT_CLICK) {
down = true; down = true;
} else if (ev.type == GUI_EVENT_MOUSE_MOVE) { } else if (ev.type == GUI_EVENT_MOUSE_MOVE) {
down = (ev.arg3 & 1); down = (ev.arg3 & 1);
@ -1442,6 +1485,7 @@ int main(int argc, char **argv) {
down = false; down = false;
} }
if (ev.type != GUI_EVENT_MOUSE_MOVE || down) {
control_panel_handle_mouse( control_panel_handle_mouse(
ev.arg1, ev.arg1,
ev.arg2, ev.arg2,
@ -1449,6 +1493,7 @@ int main(int argc, char **argv) {
ev.type == GUI_EVENT_CLICK ev.type == GUI_EVENT_CLICK
); );
dirty = true; dirty = true;
}
} else if (ev.type == GUI_EVENT_MOUSE_WHEEL) { } else if (ev.type == GUI_EVENT_MOUSE_WHEEL) {
if (current_view == VIEW_FONTS) { if (current_view == VIEW_FONTS) {
@ -1481,11 +1526,15 @@ int main(int argc, char **argv) {
control_panel_paint(win); control_panel_paint(win);
ui_mark_dirty(win, 0, 0, 350, 500); ui_mark_dirty(win, 0, 0, 350, 500);
} }
} else {
if (current_view == VIEW_WALLPAPER && load_next_wallpaper_thumb()) {
control_panel_paint(win);
ui_mark_dirty(win, 0, 0, 350, 500);
} else { } else {
sleep(10); sleep(10);
} }
} }
}
return 0; return 0;
} }

View file

@ -67,6 +67,8 @@
#define SYSTEM_CMD_NETWORK_GET_NIC_NAME 48 #define SYSTEM_CMD_NETWORK_GET_NIC_NAME 48
#define SYSTEM_CMD_SET_KEYBOARD_LAYOUT 49 #define SYSTEM_CMD_SET_KEYBOARD_LAYOUT 49
#define SYSTEM_CMD_GET_KEYBOARD_LAYOUT 51 #define SYSTEM_CMD_GET_KEYBOARD_LAYOUT 51
#define SYSTEM_CMD_SET_MOUSE_CURSOR_SCALE 52
#define SYSTEM_CMD_GET_MOUSE_CURSOR_SCALE 53
#define SYSTEM_CMD_SET_TEXT_COLOR 29 #define SYSTEM_CMD_SET_TEXT_COLOR 29
#define SYSTEM_CMD_SET_WALLPAPER_PATH 31 #define SYSTEM_CMD_SET_WALLPAPER_PATH 31
#define SYSTEM_CMD_RTC_SET 32 #define SYSTEM_CMD_RTC_SET 32

View file

@ -497,3 +497,149 @@ bool widget_checkbox_handle_mouse(widget_checkbox_t *cb, int mx, int my, bool mo
} }
return false; return false;
} }
// --- Slider ---
void widget_slider_init(widget_slider_t *sl, int x, int y, int w, int h, float min, float max, float value) {
sl->x = x;
sl->y = y;
sl->w = w;
sl->h = h;
sl->min = min;
sl->max = max;
sl->value = value;
sl->step = 0.0f;
sl->dragging = false;
sl->hovered = false;
sl->on_change = NULL;
}
void widget_slider_draw(widget_context_t *ctx, widget_slider_t *sl) {
uint32_t track_bg = ctx->use_light_theme ? 0xFFD0D0D0 : 0xFF404040;
uint32_t fill_color = ctx->use_light_theme ? 0xFF007AFF : 0xFF4A90E2;
uint32_t thumb_color = ctx->use_light_theme ? 0xFF606060 : 0xFFDDDDDD;
if (sl->dragging) {
thumb_color = ctx->use_light_theme ? 0xFF404040 : 0xFFFFFFFF;
} else if (sl->hovered) {
thumb_color = ctx->use_light_theme ? 0xFF505050 : 0xFFF0F0F0;
}
int track_h = 4;
int track_y = sl->y + (sl->h - track_h) / 2;
float t = (sl->value - sl->min) / (sl->max - sl->min);
if (t < 0) t = 0;
if (t > 1) t = 1;
int thumb_x = sl->x + (int)(t * sl->w);
if (ctx->draw_rounded_rect_filled) {
ctx->draw_rounded_rect_filled(ctx->user_data, sl->x, track_y, sl->w, track_h, 2, track_bg);
} else {
ctx->draw_rect(ctx->user_data, sl->x, track_y, sl->w, track_h, track_bg);
}
if (ctx->draw_rounded_rect_filled) {
ctx->draw_rounded_rect_filled(ctx->user_data, sl->x, track_y, thumb_x - sl->x, track_h, 2, fill_color);
} else {
ctx->draw_rect(ctx->user_data, sl->x, track_y, thumb_x - sl->x, track_h, fill_color);
}
int radius = sl->h / 2;
int cx = thumb_x - radius;
if (ctx->draw_rounded_rect_filled) {
ctx->draw_rounded_rect_filled(ctx->user_data, cx, sl->y, sl->h, sl->h, radius, thumb_color);
} else {
ctx->draw_rect(ctx->user_data, cx, sl->y, sl->h, sl->h, thumb_color);
}
}
static float widget_roundf(float x) {
return (x >= 0.0f) ? (float)((int)(x + 0.5f)) : (float)((int)(x - 0.5f));
}
bool widget_slider_handle_mouse(widget_slider_t *sl, int mx, int my, bool mouse_down, bool mouse_clicked, void *user_data) {
bool in_bounds = (mx >= sl->x && mx < sl->x + sl->w &&
my >= sl->y && my < sl->y + sl->h);
sl->hovered = in_bounds;
if (mouse_clicked && in_bounds) {
sl->dragging = true;
}
if (!mouse_down) {
sl->dragging = false;
}
if (sl->dragging) {
float t = (float)(mx - sl->x) / (float)sl->w;
if (t < 0) t = 0;
if (t > 1) t = 1;
float new_value = sl->min + t * (sl->max - sl->min);
if (sl->step > 0.0f) {
new_value = sl->min + widget_roundf((new_value - sl->min) / sl->step) * sl->step;
}
if (new_value != sl->value) {
sl->value = new_value;
if (sl->on_change) sl->on_change(user_data, sl->value);
}
return true;
}
return in_bounds;
}
static void widget_itoa(int value, char *buf) {
int i = 0;
int neg = 0;
if (value == 0) {
buf[0] = '0';
buf[1] = 0;
return;
}
if (value < 0) {
neg = 1;
value = -value;
}
while (value > 0) {
buf[i++] = (char)('0' + (value % 10));
value /= 10;
}
if (neg) {
buf[i++] = '-';
}
buf[i] = 0;
for (int a = 0, b = i - 1; a < b; a++, b--) {
char t = buf[a];
buf[a] = buf[b];
buf[b] = t;
}
}
void widget_slider_draw_value(widget_context_t *ctx, widget_slider_t *sl) {
if (!ctx->draw_string) return;
char buf[16];
widget_itoa((int)sl->value, buf);
ctx->draw_string(ctx->user_data,
sl->x + sl->w + 8,
sl->y + (sl->h - 8) / 2,
buf,
ctx->use_light_theme ? 0xFF000000 : 0xFFFFFFFF);
}

View file

@ -86,6 +86,29 @@ typedef struct {
void (*on_toggle)(void *user_data, bool new_state); void (*on_toggle)(void *user_data, bool new_state);
} widget_checkbox_t; } widget_checkbox_t;
// --- Slider ---
typedef struct {
int x, y, w, h;
float min;
float max;
float value;
float step; // 0 = not steps
bool dragging;
bool hovered;
void (*on_change)(void *user_data, float value);
} widget_slider_t;
void widget_slider_init(widget_slider_t *sl, int x, int y, int w, int h,
float min, float max, float value);
void widget_slider_draw(widget_context_t *ctx, widget_slider_t *sl);
bool widget_slider_handle_mouse(widget_slider_t *sl, int mx, int my,
bool mouse_down, bool mouse_clicked,
void *user_data);
void widget_checkbox_init(widget_checkbox_t *cb, int x, int y, int w, int h, const char *text, bool is_radio); void widget_checkbox_init(widget_checkbox_t *cb, int x, int y, int w, int h, const char *text, bool is_radio);
void widget_checkbox_draw(widget_context_t *ctx, widget_checkbox_t *cb); void widget_checkbox_draw(widget_context_t *ctx, widget_checkbox_t *cb);
bool widget_checkbox_handle_mouse(widget_checkbox_t *cb, int mx, int my, bool mouse_clicked, void *user_data); bool widget_checkbox_handle_mouse(widget_checkbox_t *cb, int mx, int my, bool mouse_clicked, void *user_data);

View file

@ -408,9 +408,14 @@ static uint32_t timer_ticks = 0;
static int last_cursor_x = 400; static int last_cursor_x = 400;
static int last_cursor_y = 300; static int last_cursor_y = 300;
static int last_cursor_w = 18;
static int last_cursor_h = 18;
#define CURSOR_W 18 #define CURSOR_BASE_W 18
#define CURSOR_H 18 #define CURSOR_BASE_H 18
#define CURSOR_SCALE_MIN_TENTHS 10
#define CURSOR_SCALE_MAX_TENTHS 40
#define CURSOR_SCALE_DEFAULT_TENTHS 10
static bool periodic_refresh_pending = false; static bool periodic_refresh_pending = false;
@ -433,10 +438,62 @@ int desktop_max_cols = 23;
// Mouse Settings // Mouse Settings
int mouse_speed = 10; int mouse_speed = 10;
static int mouse_cursor_scale_tenths = CURSOR_SCALE_DEFAULT_TENTHS;
static int mouse_accum_x = 0; static int mouse_accum_x = 0;
static int mouse_accum_y = 0; static int mouse_accum_y = 0;
Window *active_mouse_capture_win = NULL; Window *active_mouse_capture_win = NULL;
static int cursor_clamp_scale_tenths(int scale) {
if (scale < CURSOR_SCALE_MIN_TENTHS) return CURSOR_SCALE_MIN_TENTHS;
if (scale > CURSOR_SCALE_MAX_TENTHS) return CURSOR_SCALE_MAX_TENTHS;
return scale;
}
static int cursor_scaled_size(int base, int scale_tenths) {
scale_tenths = cursor_clamp_scale_tenths(scale_tenths);
return (base * scale_tenths + 9) / 10;
}
static int cursor_width_for_scale(int scale_tenths) {
return cursor_scaled_size(CURSOR_BASE_W, scale_tenths);
}
static int cursor_height_for_scale(int scale_tenths) {
return cursor_scaled_size(CURSOR_BASE_H, scale_tenths);
}
static int cursor_current_width(void) {
return cursor_width_for_scale(mouse_cursor_scale_tenths);
}
static int cursor_current_height(void) {
return cursor_height_for_scale(mouse_cursor_scale_tenths);
}
void wm_set_cursor_scale_tenths(int scale) {
scale = cursor_clamp_scale_tenths(scale);
uint64_t rflags = wm_lock_acquire();
if (scale != mouse_cursor_scale_tenths) {
int old_w = cursor_current_width();
int old_h = cursor_current_height();
mouse_cursor_scale_tenths = scale;
wm_mark_dirty(last_cursor_x, last_cursor_y, last_cursor_w, last_cursor_h);
wm_mark_dirty(mx, my, old_w, old_h);
wm_mark_dirty(mx, my, cursor_current_width(), cursor_current_height());
}
wm_lock_release(rflags);
}
int wm_get_cursor_scale_tenths(void) {
uint64_t rflags = wm_lock_acquire();
int scale = mouse_cursor_scale_tenths;
wm_lock_release(rflags);
return scale;
}
// Helper to check if string ends with suffix // Helper to check if string ends with suffix
static bool str_ends_with(const char *str, const char *suffix) { static bool str_ends_with(const char *str, const char *suffix) {
int str_len = 0; while(str[str_len]) str_len++; int str_len = 0; while(str[str_len]) str_len++;
@ -2198,7 +2255,7 @@ void draw_window(Window *win) {
void draw_cursor(int x, int y) { void draw_cursor(int x, int y) {
// '.' transparent, 'w' white outline, 'b' black fill // '.' transparent, 'w' white outline, 'b' black fill
static const char cursor_bitmap[CURSOR_H][CURSOR_W + 1] = { static const char cursor_bitmap[CURSOR_BASE_H][CURSOR_BASE_W + 1] = {
"w.................", "w.................",
"ww................", "ww................",
"wbw...............", "wbw...............",
@ -2216,16 +2273,21 @@ void draw_cursor(int x, int y) {
"wwwwbbbw..........", "wwwwbbbw..........",
"....wbbw..........", "....wbbw..........",
".....wbw..........", ".....wbw..........",
"......ww..........." "......ww.........."
}; };
for (int r = 0; r < CURSOR_H; r++) { int draw_w = cursor_current_width();
for (int c = 0; c < CURSOR_W; c++) { int draw_h = cursor_current_height();
for (int y_off = 0; y_off < draw_h; y_off++) {
int r = (y_off * CURSOR_BASE_H) / draw_h;
for (int x_off = 0; x_off < draw_w; x_off++) {
int c = (x_off * CURSOR_BASE_W) / draw_w;
char p = cursor_bitmap[r][c]; char p = cursor_bitmap[r][c];
if (p == 'w') { if (p == 'w') {
put_pixel(x + c, y + r, COLOR_WHITE); put_pixel(x + x_off, y + y_off, COLOR_WHITE);
} else if (p == 'b') { } else if (p == 'b') {
put_pixel(x + c, y + r, COLOR_BLACK); put_pixel(x + x_off, y + y_off, COLOR_BLACK);
} }
} }
} }
@ -2239,8 +2301,8 @@ static void erase_cursor(int x, int y) {
// Clamp to screen // Clamp to screen
int x1 = x < 0 ? 0 : x; int x1 = x < 0 ? 0 : x;
int y1 = y < 0 ? 0 : y; int y1 = y < 0 ? 0 : y;
int x2 = x + CURSOR_W > sw ? sw : x + CURSOR_W; int x2 = x + cursor_current_width() > sw ? sw : x + cursor_current_width();
int y2 = y + CURSOR_H > sh ? sh : y + CURSOR_H; int y2 = y + cursor_current_height() > sh ? sh : y + cursor_current_height();
int w = x2 - x1; int w = x2 - x1;
int h = y2 - y1; int h = y2 - y1;
@ -2644,8 +2706,10 @@ void wm_paint(void) {
int sh = get_screen_height(); int sh = get_screen_height();
uint64_t rflags; uint64_t rflags;
rflags = wm_lock_acquire(); rflags = wm_lock_acquire();
wm_mark_dirty(last_cursor_x, last_cursor_y, CURSOR_W, CURSOR_H); int cursor_w = cursor_current_width();
wm_mark_dirty(mx, my, CURSOR_W, CURSOR_H); int cursor_h = cursor_current_height();
wm_mark_dirty(last_cursor_x, last_cursor_y, last_cursor_w, last_cursor_h);
wm_mark_dirty(mx, my, cursor_w, cursor_h);
DirtyRect dirty = graphics_get_dirty_rect(); DirtyRect dirty = graphics_get_dirty_rect();
if (menubar_dirty_pending) { if (menubar_dirty_pending) {
@ -2719,6 +2783,8 @@ void wm_paint(void) {
draw_cursor(mx, my); draw_cursor(mx, my);
last_cursor_x = mx; last_cursor_x = mx;
last_cursor_y = my; last_cursor_y = my;
last_cursor_w = cursor_w;
last_cursor_h = cursor_h;
graphics_flip_buffer(); graphics_flip_buffer();
graphics_clear_dirty_no_lock(); graphics_clear_dirty_no_lock();
wm_lock_release(rflags); wm_lock_release(rflags);
@ -3230,8 +3296,10 @@ static void wm_handle_mouse_internal(int dx, int dy, uint8_t buttons, int dz) {
if (my >= sh) my = sh - 1; if (my >= sh) my = sh - 1;
if (move_x != 0 || move_y != 0) { if (move_x != 0 || move_y != 0) {
wm_mark_dirty(prev_mx, prev_my, CURSOR_W, CURSOR_H); int cursor_w = cursor_current_width();
wm_mark_dirty(mx, my, CURSOR_W, CURSOR_H); int cursor_h = cursor_current_height();
wm_mark_dirty(prev_mx, prev_my, cursor_w, cursor_h);
wm_mark_dirty(mx, my, cursor_w, cursor_h);
} }
if (dz != 0) { if (dz != 0) {
@ -3792,8 +3860,10 @@ static void wm_handle_mouse_internal(int dx, int dy, uint8_t buttons, int dz) {
if (prev_mx != mx || prev_my != my) { if (prev_mx != mx || prev_my != my) {
// Cursor moved - just mark dirty cursor areas // Cursor moved - just mark dirty cursor areas
wm_mark_dirty(prev_mx, prev_my, CURSOR_W, CURSOR_H); int cursor_w = cursor_current_width();
wm_mark_dirty(mx, my, CURSOR_W, CURSOR_H); int cursor_h = cursor_current_height();
wm_mark_dirty(prev_mx, prev_my, cursor_w, cursor_h);
wm_mark_dirty(mx, my, cursor_w, cursor_h);
} }
} }

View file

@ -152,5 +152,7 @@ extern int desktop_max_cols;
// Mouse Settings // Mouse Settings
extern int mouse_speed; extern int mouse_speed;
void wm_set_cursor_scale_tenths(int scale);
int wm_get_cursor_scale_tenths(void);
#endif #endif