From 19cb29a9b760d290e4284b4d3600e168e1d5bcc2 Mon Sep 17 00:00:00 2001 From: Liu Date: Wed, 20 May 2026 23:44:17 +0800 Subject: [PATCH 01/66] feat(app): add lcui_request_frame and animation timer driver --- include/LCUI/app.h | 5 +++ lib/ptk/include/ptk/steptimer.h | 13 +++++++ lib/ptk/src/steptimer.c | 35 +++++++++++++++-- src/lcui_app.c | 69 ++++++++++++++++++++++++++++++++- tests/cases/test_steptimer.c | 53 +++++++++++++++++++++++++ 5 files changed, 170 insertions(+), 5 deletions(-) diff --git a/include/LCUI/app.h b/include/LCUI/app.h index ffbbae988..34dd02818 100644 --- a/include/LCUI/app.h +++ b/include/LCUI/app.h @@ -23,6 +23,11 @@ LCUI_API int lcui_app_process_events(ptk_process_events_option_t option); LCUI_API void lcui_app_init(void); LCUI_API void lcui_app_destroy(void); +typedef void (*lcui_frame_cb_t)(uint64_t timestamp, void *data); + +LCUI_API int lcui_request_frame(lcui_frame_cb_t callback, void *data); +LCUI_API void lcui_cancel_frame(int request_id); + LCUI_END_HEADER #endif diff --git a/lib/ptk/include/ptk/steptimer.h b/lib/ptk/include/ptk/steptimer.h index c8884e582..f0496db3e 100644 --- a/lib/ptk/include/ptk/steptimer.h +++ b/lib/ptk/include/ptk/steptimer.h @@ -29,6 +29,13 @@ PTK_BEGIN_DECLS * driving stable physics simulation or animation timelines, NOT for * throttling render frame rate. Render throttling should be implemented as * a separate minimum-interval gate by the caller. + * + * When enable_catch_up is false (the default), fixed-step mode invokes the + * handler at most once per tick, treating target_elapsed_time as a cadence + * gate. This is appropriate for visual callbacks like requestAnimationFrame + * where replaying missed frames would cause a burst of renders. When true, + * the original DirectXTK catch-up behavior is preserved, suitable for + * physics or simulation where accumulated time must be fully consumed. */ typedef struct ptk_steptimer { @@ -49,6 +56,7 @@ typedef struct ptk_steptimer { // Members for configuring fixed timestep mode. bool is_fixed_time_step; + bool enable_catch_up; uint64_t target_elapsed_time; } ptk_steptimer_t; @@ -61,6 +69,11 @@ PTK_PUBLIC void ptk_steptimer_init(ptk_steptimer_t *timer); PTK_PUBLIC void ptk_steptimer_tick(ptk_steptimer_t *timer, ptk_steptimer_handler_t handler, void *data); +// After an intentional timing discontinuity (for instance a blocking IO +// operation or a long pause), call this to avoid having the fixed timestep +// logic attempt a set of catch-up Update calls. +PTK_PUBLIC void ptk_steptimer_reset_elapsed_time(ptk_steptimer_t *timer); + PTK_END_DECLS #endif diff --git a/lib/ptk/src/steptimer.c b/lib/ptk/src/steptimer.c index dd1f0e8bf..36a6d4ff5 100644 --- a/lib/ptk/src/steptimer.c +++ b/lib/ptk/src/steptimer.c @@ -28,6 +28,7 @@ void ptk_steptimer_init(ptk_steptimer_t *timer) timer->frames_this_second = 0; timer->second_counter = 0; timer->is_fixed_time_step = false; + timer->enable_catch_up = false; timer->target_elapsed_time = 1000 / 60; timer->max_delta = 1000; } @@ -69,10 +70,27 @@ void ptk_steptimer_tick(ptk_steptimer_t *timer, ptk_steptimer_handler_t handler, timer->left_over_time += time_delta; - while (timer->left_over_time >= timer->target_elapsed_time) { - timer->elapsed_time = timer->target_elapsed_time; - timer->total_time += timer->target_elapsed_time; - timer->left_over_time -= timer->target_elapsed_time; + if (timer->enable_catch_up) { + // DirectXTK behavior: catch up by invoking the handler + // multiple times to fully consume accumulated time. + while (timer->left_over_time >= timer->target_elapsed_time) { + timer->elapsed_time = timer->target_elapsed_time; + timer->total_time += timer->target_elapsed_time; + timer->left_over_time -= timer->target_elapsed_time; + timer->frame_count++; + + handler(timer, data); + } + } else if (timer->left_over_time >= timer->target_elapsed_time) { + // No catch-up: invoke the handler at most once per tick. + // elapsed_time reflects the actual accumulated delta so + // the handler can respond to real-time passage (useful + // for visual callbacks like requestAnimationFrame). The + // remainder is preserved via modulo to prevent long-term + // drift without causing a burst of calls. + timer->elapsed_time = timer->left_over_time; + timer->total_time += timer->left_over_time; + timer->left_over_time %= timer->target_elapsed_time; timer->frame_count++; handler(timer, data); @@ -98,3 +116,12 @@ void ptk_steptimer_tick(ptk_steptimer_t *timer, ptk_steptimer_handler_t handler, timer->second_counter %= 1000; } } + +void ptk_steptimer_reset_elapsed_time(ptk_steptimer_t *timer) +{ + timer->last_time = get_time_ms(); + timer->left_over_time = 0; + timer->frames_per_second = 0; + timer->frames_this_second = 0; + timer->second_counter = 0; +} diff --git a/src/lcui_app.c b/src/lcui_app.c index 44b1b91ed..8239625e3 100644 --- a/src/lcui_app.c +++ b/src/lcui_app.c @@ -10,15 +10,31 @@ */ #include +#include #include #include +#include #include #include #include #include #include +typedef struct lcui_frame_request { + list_node_t node; + int id; + lcui_frame_cb_t callback; + void *data; +} lcui_frame_request_t; + static struct lcui_app { + // Animation frame driver. Fixed-step, no catch-up: the handler + // fires at most once per tick when enough time has accumulated, + // flushing all registered lcui_request_frame callbacks. + ptk_steptimer_t anim_timer; + list_t frame_cbs; + int next_frame_id; + // Render throttling. Two consecutive renders are at least // min_render_interval milliseconds apart. 0 disables throttling. uint64_t last_render_time; @@ -146,6 +162,47 @@ static void lcui_dispatch_ui_event(ptk_event_t *app_event) } } +static void lcui_app_on_anim_frame(ptk_steptimer_t *timer, void *data) +{ + uint64_t timestamp = (uint64_t)get_time_ms(); + list_node_t *node; + + list_for_each(node, &lcui_app.frame_cbs) { + lcui_frame_request_t *req = node->data; + req->callback(timestamp, req->data); + } + list_destroy(&lcui_app.frame_cbs, NULL); +} + +int lcui_request_frame(lcui_frame_cb_t callback, void *data) +{ + lcui_frame_request_t *req = malloc(sizeof(lcui_frame_request_t)); + + if (!req) { + return -1; + } + req->id = ++lcui_app.next_frame_id; + req->callback = callback; + req->data = data; + list_append(&lcui_app.frame_cbs, req); + return req->id; +} + +void lcui_cancel_frame(int request_id) +{ + list_node_t *node; + + list_for_each(node, &lcui_app.frame_cbs) { + lcui_frame_request_t *req = node->data; + if (req->id == request_id) { + list_unlink(&lcui_app.frame_cbs, node); + free(req); + list_node_free(node); + return; + } + } +} + static void lcui_app_render_frame(void) { uint64_t now = (uint64_t)get_time_ms(); @@ -175,8 +232,9 @@ static int lcui_app_dispatch(ptk_event_t *e) return 0; } lcui_dispatch_ui_event(e); - lcui_ui_update(); lcui_worker_run(); + ptk_steptimer_tick(&lcui_app.anim_timer, lcui_app_on_anim_frame, NULL); + lcui_ui_update(); lcui_app_render_frame(); return 0; } @@ -189,6 +247,8 @@ uint32_t lcui_app_get_fps(void) void lcui_app_set_frame_rate_cap(unsigned rate_cap) { lcui_app.min_render_interval = (rate_cap > 0) ? (1000 / rate_cap) : 0; + lcui_app.anim_timer.target_elapsed_time = + (rate_cap > 0) ? (1000 / rate_cap) : (1000 / 60); } int lcui_app_process_events(ptk_process_events_option_t option) @@ -201,6 +261,12 @@ void lcui_app_init(void) uint64_t now = (uint64_t)get_time_ms(); lcui_worker_init(); + ptk_steptimer_init(&lcui_app.anim_timer); + lcui_app.anim_timer.is_fixed_time_step = true; + lcui_app.anim_timer.enable_catch_up = false; + lcui_app.anim_timer.target_elapsed_time = 1000 / 60; + list_create(&lcui_app.frame_cbs); + lcui_app.next_frame_id = 0; lcui_app.last_render_time = now; lcui_app.min_render_interval = 0; lcui_app.fps_window_start = now; @@ -217,5 +283,6 @@ void lcui_app_destroy(void) { lcui_ui_destroy(); lcui_worker_destroy(); + list_destroy_without_node(&lcui_app.frame_cbs, NULL); ptk_destroy(); } diff --git a/tests/cases/test_steptimer.c b/tests/cases/test_steptimer.c index 6e9b8bb90..2037aeabf 100644 --- a/tests/cases/test_steptimer.c +++ b/tests/cases/test_steptimer.c @@ -66,6 +66,7 @@ static void test_steptimer_fixed_step_catch_up(void) ptk_steptimer_init(&timer); timer.is_fixed_time_step = true; + timer.enable_catch_up = true; timer.target_elapsed_time = 8; // max_delta defaults to 1000; a 500ms delta will not be clamped. timer.last_time = (uint64_t)get_time_ms() - 500; @@ -80,6 +81,54 @@ static void test_steptimer_fixed_step_catch_up(void) count_in_range, true); } +static void test_steptimer_fixed_step_no_catch_up(void) +{ + ptk_steptimer_t timer; + steptimer_probe_t probe = { 0 }; + + ptk_steptimer_init(&timer); + timer.is_fixed_time_step = true; + timer.enable_catch_up = false; + timer.target_elapsed_time = 8; + timer.last_time = (uint64_t)get_time_ms() - 500; + + ptk_steptimer_tick(&timer, on_steptimer_tick, &probe); + + ctest_equal_uint("no-catch-up should invoke handler exactly once", + probe.call_count, 1); + ctest_equal_bool( + "no-catch-up elapsed_time should reflect real delta (~500ms)", + probe.last_elapsed_time >= 400 && probe.last_elapsed_time <= 600, + true); +} + +static void test_steptimer_reset_elapsed_time(void) +{ + ptk_steptimer_t timer; + steptimer_probe_t probe = { 0 }; + + ptk_steptimer_init(&timer); + timer.is_fixed_time_step = true; + timer.enable_catch_up = false; + timer.target_elapsed_time = 16; + + // Accumulate some left-over time by ticking twice with a gap. + ptk_steptimer_tick(&timer, on_steptimer_tick, &probe); + sleep_ms(20); + ptk_steptimer_tick(&timer, on_steptimer_tick, &probe); + + // Before reset, left_over_time should be non-zero. + ctest_equal_bool("left_over_time is non-zero before reset", + timer.left_over_time > 0, true); + + ptk_steptimer_reset_elapsed_time(&timer); + + ctest_equal_bool("left_over_time is zero after reset", + timer.left_over_time == 0, true); + ctest_equal_uint("frames_per_second is zero after reset", + timer.frames_per_second, 0); +} + static void test_steptimer_max_delta_clamp(void) { ptk_steptimer_t timer; @@ -108,6 +157,10 @@ void test_steptimer(void) test_steptimer_variable_step); ctest_describe("fixed-step catch-up replays missed updates", test_steptimer_fixed_step_catch_up); + ctest_describe("fixed-step no-catch-up fires handler once", + test_steptimer_fixed_step_no_catch_up); + ctest_describe("reset_elapsed_time clears leftovers", + test_steptimer_reset_elapsed_time); ctest_describe("max_delta clamps excessive deltas", test_steptimer_max_delta_clamp); } From c844045b30bfaefd485da1e3ff2bba3a8a6946bb Mon Sep 17 00:00:00 2001 From: Liu Date: Wed, 20 May 2026 23:44:43 +0800 Subject: [PATCH 02/66] docs: add AGENTS.md --- AGENTS.md | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..5efbc0879 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,109 @@ +## 代码格式 + +### 缩进 + +使用八个空格缩进。 + +### 代码结构 + +源文件中的代码结构应该为: + +1. 预处理指令 +2. 类型 +3. 全局变量 +4. 函数声明 +5. 函数定义 + +其中“函数定义”应该按照功能类别分组、按依赖关系从基础到高级的顺序排列,例如: + +```c +static int var1; +static int var1; + +static void func1(); +static void func2(); + +// object 1 + +void object1_func1() +{ + // .. +} + +void object1_func2() { + // ... + object1_func1(); +} + + +// object 2 + +void object2_func1() +{ + // .. +} + +void object2_func2() { + // ... + object2_func1(); +} +``` + +注意!优先通过调整函数定义代码块的顺序来解决声明问题,而不是前置声明函数。 + +## 测试用例 + +在 tests/cases 中新建测试代码,源文件名称以 `test_` 开头,内部添加头文件包含: + +```c +#include +`` + +然后使用 lib/ctest/include/ctest.h 中的函数输出测试信息、检测测试结果,例如: + + +```c +#include + +int add(int a, int b) +{ + return a + b; +} + +void test_my_case(void) +{ + ctest_equat_init("check add(1, 1)", 2, add(1, 1)); +} +``` + +最后,在 tests/run_tests.c 中添加这个测试的调用代码。 + +## 重构约定 + +### 合并重复分支 + +当存在两个分支仅输入不同但后续处理相同(如选择 obs->root 或 ui_root),用局部变量合并公共逻辑,避免重复代码。 + +```c +/* before */ +if (ctx->logger) { + write_log(ctx->logger, msg); +} else { + logger_t *logger = get_default_logger(); + write_log(logger, msg); +} + +/* after */ +logger_t *logger = ctx->logger ? ctx->logger : get_default_logger(); +write_log(logger, msg); +``` + +### 提取公共逻辑 + +若公共逻辑较长,可提取为独立函数,并保持调用路径一致,减少分叉实现。 + +## 指令 + +### gen-commit + +用于生成符合 Angular 规范的提交信息,scope 应为 lib 目录下的任意目录名(例如:ui、css),标题长度限制在 80 字符以内,应结合本次会话内容生成,无需读取实际改动文件内容。 From abb97dcdf562d879a8b789703fef0a96e2e32f4d Mon Sep 17 00:00:00 2001 From: Liu Date: Wed, 20 May 2026 23:53:53 +0800 Subject: [PATCH 03/66] refactor(app): drop app_ prefix from public API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BREAKING CHANGE: lcui_app_get_fps -> lcui_get_fps, lcui_app_set_frame_rate_cap -> lcui_set_fps_cap, settings.frame_rate_cap -> settings.fps_cap. lcui_app_init, lcui_app_destroy, lcui_app_process_events removed from public header — use lcui_init, lcui_destroy, lcui_run instead. --- include/LCUI/app.h | 7 ++---- include/LCUI/settings.h | 2 +- src/lcui.c | 1 + src/lcui_app.c | 9 ++++---- src/lcui_app.h | 21 ++++++++++++++++++ src/lcui_settings.c | 6 ++--- tests/cases/test_mainloop.c | 2 +- tests/cases/test_settings.c | 44 ++++++++++++++++++------------------- 8 files changed, 56 insertions(+), 36 deletions(-) create mode 100644 src/lcui_app.h diff --git a/include/LCUI/app.h b/include/LCUI/app.h index 34dd02818..20bff2ea9 100644 --- a/include/LCUI/app.h +++ b/include/LCUI/app.h @@ -17,11 +17,8 @@ LCUI_BEGIN_HEADER -LCUI_API uint32_t lcui_app_get_fps(void); -LCUI_API void lcui_app_set_frame_rate_cap(unsigned rate_cap); -LCUI_API int lcui_app_process_events(ptk_process_events_option_t option); -LCUI_API void lcui_app_init(void); -LCUI_API void lcui_app_destroy(void); +LCUI_API uint32_t lcui_get_fps(void); +LCUI_API void lcui_set_fps_cap(unsigned fps_cap); typedef void (*lcui_frame_cb_t)(uint64_t timestamp, void *data); diff --git a/include/LCUI/settings.h b/include/LCUI/settings.h index da9078639..8c5b3f2d5 100644 --- a/include/LCUI/settings.h +++ b/include/LCUI/settings.h @@ -20,7 +20,7 @@ LCUI_BEGIN_HEADER typedef struct lcui_settings { - int frame_rate_cap; + int fps_cap; int parallel_rendering_threads; bool paint_flashing; } lcui_settings_t; diff --git a/src/lcui.c b/src/lcui.c index 6304e22a3..a8210404d 100644 --- a/src/lcui.c +++ b/src/lcui.c @@ -13,6 +13,7 @@ #include #include #include +#include "lcui_app.h" #include #include diff --git a/src/lcui_app.c b/src/lcui_app.c index 8239625e3..ac98972d5 100644 --- a/src/lcui_app.c +++ b/src/lcui_app.c @@ -19,6 +19,7 @@ #include #include #include +#include "lcui_app.h" typedef struct lcui_frame_request { list_node_t node; @@ -239,16 +240,16 @@ static int lcui_app_dispatch(ptk_event_t *e) return 0; } -uint32_t lcui_app_get_fps(void) +uint32_t lcui_get_fps(void) { return lcui_app.frames_per_second; } -void lcui_app_set_frame_rate_cap(unsigned rate_cap) +void lcui_set_fps_cap(unsigned fps_cap) { - lcui_app.min_render_interval = (rate_cap > 0) ? (1000 / rate_cap) : 0; + lcui_app.min_render_interval = (fps_cap > 0) ? (1000 / fps_cap) : 0; lcui_app.anim_timer.target_elapsed_time = - (rate_cap > 0) ? (1000 / rate_cap) : (1000 / 60); + (fps_cap > 0) ? (1000 / fps_cap) : (1000 / 60); } int lcui_app_process_events(ptk_process_events_option_t option) diff --git a/src/lcui_app.h b/src/lcui_app.h new file mode 100644 index 000000000..d78c82c0f --- /dev/null +++ b/src/lcui_app.h @@ -0,0 +1,21 @@ +/* + * src/lcui_app.h + * + * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#ifndef LCUI_SRC_LCUI_APP_H +#define LCUI_SRC_LCUI_APP_H + +#include + +void lcui_app_init(void); +void lcui_app_destroy(void); +int lcui_app_process_events(ptk_process_events_option_t option); + +#endif \ No newline at end of file diff --git a/src/lcui_settings.c b/src/lcui_settings.c index f51076f35..78f26deda 100644 --- a/src/lcui_settings.c +++ b/src/lcui_settings.c @@ -28,19 +28,19 @@ void lcui_get_settings(lcui_settings_t *settings) void lcui_apply_settings(lcui_settings_t *settings) { lcui_settings = *settings; - lcui_settings.frame_rate_cap = y_max(lcui_settings.frame_rate_cap, 1); + lcui_settings.fps_cap = y_max(lcui_settings.fps_cap, 1); lcui_settings.parallel_rendering_threads = y_max(lcui_settings.parallel_rendering_threads, 1); ui_server_set_threads(lcui_settings.parallel_rendering_threads); ui_server_set_paint_flashing_enabled(lcui_settings.paint_flashing); - lcui_app_set_frame_rate_cap(lcui_settings.frame_rate_cap); + lcui_set_fps_cap(lcui_settings.fps_cap); } /* Reset global settings to their defaults. */ void lcui_reset_settings(void) { lcui_settings_t settings = { - .frame_rate_cap = LCUI_MAX_FRAMES_PER_SEC, + .fps_cap = LCUI_MAX_FRAMES_PER_SEC, .parallel_rendering_threads = 4, .paint_flashing = false }; diff --git a/tests/cases/test_mainloop.c b/tests/cases/test_mainloop.c index 9e79f0fc0..d11656f66 100644 --- a/tests/cases/test_mainloop.c +++ b/tests/cases/test_mainloop.c @@ -27,7 +27,7 @@ static void handle_btn_click(ui_widget_t *w, ui_event_t *ui_event, void *arg) { ptk_set_timeout(0, handle_refresh, NULL); ptk_set_timeout(1, handle_quit, NULL); - lcui_app_process_events(PTK_PROCESS_EVENTS_UNTIL_QUIT); + ptk_process_native_events(PTK_PROCESS_EVENTS_UNTIL_QUIT); lcui_quit(); } diff --git a/tests/cases/test_settings.c b/tests/cases/test_settings.c index 60ccdbb24..0adb3bee3 100644 --- a/tests/cases/test_settings.c +++ b/tests/cases/test_settings.c @@ -13,11 +13,11 @@ #include #include -static void check_settings_frame_rate_cap(void *arg) +static void check_settings_fps_cap(void *arg) { char str[256]; int fps_limit = *((int *)arg); - int fps = (int)lcui_app_get_fps(); + int fps = (int)lcui_get_fps(); sprintf(str, "should work when frame cap is %u (actual %u)", fps_limit, fps); @@ -33,7 +33,7 @@ static void test_default_settings(void) lcui_reset_settings(); lcui_get_settings(&settings); - ctest_equal_int("check default frame rate cap", settings.frame_rate_cap, 120); + ctest_equal_int("check default frame rate cap", settings.fps_cap, 120); ctest_equal_int("check default parallel rendering threads", settings.parallel_rendering_threads, 4); ctest_equal_bool("check default paint flashing", settings.paint_flashing, false); @@ -45,68 +45,68 @@ static void test_apply_settings(void) { lcui_settings_t settings; - settings.frame_rate_cap = 60; + settings.fps_cap = 60; settings.parallel_rendering_threads = 2; settings.paint_flashing = true; lcui_init(); lcui_apply_settings(&settings); lcui_get_settings(&settings); - ctest_equal_int("check frame rate cap", settings.frame_rate_cap, 60); + ctest_equal_int("check frame rate cap", settings.fps_cap, 60); ctest_equal_int("check parallel rendering threads", settings.parallel_rendering_threads, 2); ctest_equal_bool("check paint flashing", settings.paint_flashing, true); - settings.frame_rate_cap = -1; + settings.fps_cap = -1; settings.parallel_rendering_threads = -1; lcui_apply_settings(&settings); lcui_get_settings(&settings); - ctest_equal_int("check frame rate cap minimum", settings.frame_rate_cap, 1); + ctest_equal_int("check frame rate cap minimum", settings.fps_cap, 1); ctest_equal_int("check parallel rendering threads minimum", settings.parallel_rendering_threads, 1); lcui_reset_settings(); lcui_get_settings(&settings); - ctest_equal_int("check frame rate cap", settings.frame_rate_cap, LCUI_MAX_FRAMES_PER_SEC); + ctest_equal_int("check frame rate cap", settings.fps_cap, LCUI_MAX_FRAMES_PER_SEC); lcui_quit(); lcui_main(); } -void test_settings_frame_rate_cap(void) +void test_settings_fps_cap(void) { lcui_settings_t settings; lcui_init(); lcui_get_settings(&settings); - settings.frame_rate_cap = 30; + settings.fps_cap = 30; lcui_apply_settings(&settings); - ptk_set_timeout(2000, check_settings_frame_rate_cap, - &settings.frame_rate_cap); + ptk_set_timeout(2000, check_settings_fps_cap, + &settings.fps_cap); lcui_main(); lcui_init(); - settings.frame_rate_cap = 5; + settings.fps_cap = 5; lcui_apply_settings(&settings); - ptk_set_timeout(2000, check_settings_frame_rate_cap, - &settings.frame_rate_cap); + ptk_set_timeout(2000, check_settings_fps_cap, + &settings.fps_cap); lcui_main(); lcui_init(); - settings.frame_rate_cap = 90; + settings.fps_cap = 90; lcui_apply_settings(&settings); - ptk_set_timeout(2000, check_settings_frame_rate_cap, - &settings.frame_rate_cap); + ptk_set_timeout(2000, check_settings_fps_cap, + &settings.fps_cap); lcui_main(); lcui_init(); - settings.frame_rate_cap = 25; + settings.fps_cap = 25; lcui_apply_settings(&settings); - ptk_set_timeout(2000, check_settings_frame_rate_cap, - &settings.frame_rate_cap); + ptk_set_timeout(2000, check_settings_fps_cap, + &settings.fps_cap); lcui_main(); } @@ -114,5 +114,5 @@ void test_settings(void) { ctest_describe("test default settings", test_default_settings); ctest_describe("test apply settings", test_apply_settings); - ctest_describe("test settings.frame_rate_cap", test_settings_frame_rate_cap); + ctest_describe("test settings.fps_cap", test_settings_fps_cap); } From 554cbedbd0b0e55220d86f5c84f473e00148ed9f Mon Sep 17 00:00:00 2001 From: OrbisAI Security Date: Thu, 21 May 2026 08:07:34 +0530 Subject: [PATCH 04/66] fix(css): stack buffer overflow in selector fullname construction Multiple unbounded strcpy() calls in lib/css/src/selector --- lib/css/src/selector.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/css/src/selector.c b/lib/css/src/selector.c index 0b9588941..1447418ff 100644 --- a/lib/css/src/selector.c +++ b/lib/css/src/selector.c @@ -9,6 +9,7 @@ * LICENSE.TXT file in the root directory of this source tree. */ +#include #include #include @@ -72,6 +73,7 @@ static int css_selector_collect_name(css_selector_name_collector_t *sfinder, size_t len, old_len; int i, old_level, count = 0; char *fullname = sfinder->name + sfinder->name_i; + size_t avail = MAX_NAME_LEN - sfinder->name_i; old_len = len = strlen(fullname); old_level = sfinder->level; @@ -81,7 +83,7 @@ static int css_selector_collect_name(css_selector_name_collector_t *sfinder, if (!sfinder->node->type) { return 0; } - strcpy(fullname, sfinder->node->type); + snprintf(fullname, avail, "%s", sfinder->node->type); list_append(list, strdup2(fullname)); break; case LEVEL_ID: @@ -91,7 +93,7 @@ static int css_selector_collect_name(css_selector_name_collector_t *sfinder, } fullname[len++] = '#'; fullname[len] = 0; - strcpy(fullname + len, sfinder->node->id); + snprintf(fullname + len, avail - len, "%s", sfinder->node->id); list_append(list, strdup2(fullname)); break; case LEVEL_CLASS: @@ -109,7 +111,7 @@ static int css_selector_collect_name(css_selector_name_collector_t *sfinder, for (i = 0; sfinder->node->classes[i]; ++i) { sfinder->level += 1; sfinder->class_i = i; - strcpy(fullname + len, sfinder->node->classes[i]); + snprintf(fullname + len, avail - len, "%s", sfinder->node->classes[i]); list_append(list, strdup2(fullname)); /* 将当前选择器名与其它层级的选择器名组合 */ while (sfinder->level < LEVEL_TOTAL_NUM) { From ddce82dc8869ecb95f8f86058d53b0ce6b151d72 Mon Sep 17 00:00:00 2001 From: Liu Date: Sat, 23 May 2026 18:38:41 +0800 Subject: [PATCH 05/66] build(yutil): update submodule to renamed tests/ layout --- lib/yutil | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/yutil b/lib/yutil index c2c215c5a..e75df7841 160000 --- a/lib/yutil +++ b/lib/yutil @@ -1 +1 @@ -Subproject commit c2c215c5a45b94c60f1847296e954c8c68e45881 +Subproject commit e75df78415a7087020d2aab85356a25e72b8b014 From 27fd503d68f686c59db7529382a479d0a2aae2d0 Mon Sep 17 00:00:00 2001 From: Liu Date: Sat, 23 May 2026 18:39:34 +0800 Subject: [PATCH 06/66] feat(ctest): add suite filter, list and CTEST_MAIN macro Introduce ctest_suite_t, ctest_parse_args, ctest_run_suites and CTEST_MAIN macro to standardize test binary entry points. Support --grep / --grep= / --list / --interactive / --help. Add lib/ctest/tests/ for self-tests covering str converters and grep filter logic. --- lib/ctest/include/ctest.h | 23 +++- lib/ctest/src/ctest.c | 202 ++++++++++++++++++++++++++---------- lib/ctest/tests/main.c | 23 ++++ lib/ctest/tests/test_grep.c | 57 ++++++++++ lib/ctest/tests/test_str.c | 59 +++++++++++ lib/ctest/tests/xmake.lua | 9 ++ lib/ctest/xmake.lua | 4 + 7 files changed, 319 insertions(+), 58 deletions(-) create mode 100644 lib/ctest/tests/main.c create mode 100644 lib/ctest/tests/test_grep.c create mode 100644 lib/ctest/tests/test_str.c create mode 100644 lib/ctest/tests/xmake.lua diff --git a/lib/ctest/include/ctest.h b/lib/ctest/include/ctest.h index 48f41a0f7..c3682d5ab 100644 --- a/lib/ctest/include/ctest.h +++ b/lib/ctest/include/ctest.h @@ -36,7 +36,28 @@ bool ctest_equal_uint(const char *name, unsigned actual, unsigned expected); bool ctest_equal_float(const char *name, float actual, float expected); bool ctest_equal_str(const char *name, const char *actual, const char *expected); -bool ctest_equal_wcs(const char *name, const wchar_t *actual, const wchar_t *expected); +bool ctest_equal_wcs(const char *name, const wchar_t *actual, + const wchar_t *expected); int ctest_finish(void); +typedef struct { + const char *name; + void (*run)(void); +} ctest_suite_t; + +void ctest_set_grep(const char *pattern); +bool ctest_should_run(const char *name); +bool ctest_is_interactive(void); +void ctest_set_interactive(bool interactive); +int ctest_parse_args(int argc, char **argv); +int ctest_run_suites(const ctest_suite_t *suites); + +#define CTEST_MAIN(SUITES) \ + int main(int argc, char **argv) \ + { \ + if (ctest_parse_args(argc, argv) != 0) \ + return 1; \ + return ctest_run_suites(SUITES); \ + } + #endif diff --git a/lib/ctest/src/ctest.c b/lib/ctest/src/ctest.c index 9b60c88b6..f5786a319 100644 --- a/lib/ctest/src/ctest.c +++ b/lib/ctest/src/ctest.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -42,128 +43,215 @@ static int64_t test_start_time = 0; int ctest_printf(const char *fmt, ...) { - int ret; - char str[1024]; - va_list args; + int ret; + char str[1024]; + va_list args; - va_start(args, fmt); - ret = vsnprintf(str, 1023, fmt, args); - va_end(args); - printf("%*s%s", test_msg_indent * 2, "", str); - return ret; + va_start(args, fmt); + ret = vsnprintf(str, 1023, fmt, args); + va_end(args); + printf("%*s%s", test_msg_indent * 2, "", str); + return ret; } void ctest_group_begin(void) { - if (test_start_time == 0) { - test_start_time = get_time_ms(); - } - test_msg_indent++; + if (test_start_time == 0) { + test_start_time = get_time_ms(); + } + test_msg_indent++; } void ctest_group_end(void) { - test_msg_indent--; + test_msg_indent--; } void ctest_describe(const char *name, void (*func)()) { - ctest_printf("%s\n", name); - ctest_group_begin(); - func(); - ctest_group_end(); - ctest_printf("\n"); + if (!ctest_should_run(name)) + return; + ctest_printf("%s\n", name); + ctest_group_begin(); + func(); + ctest_group_end(); + ctest_printf("\n"); } bool ctest_equal(const char *name, int (*to_str)(void *, char *, unsigned), - void *actual, void *expected) -{ - char actual_str[256] = { 0 }; - char expected_str[256] = { 0 }; - - tests_total++; - to_str(actual, actual_str, 255); - to_str(expected, expected_str, 255); - if (strncmp(actual_str, expected_str, 255) == 0) { - ctest_printf(CHECK_MARK "%s\n", name); - tests_passed++; - return true; - } - ctest_printf(RED(ERROR_MARK "%s\n"), name); - ctest_printf(GREEN(" + expected ") RED("- actual\n\n")); - ctest_printf(RED(" - %s\n"), actual_str); - ctest_printf(GREEN(" + %s\n\n"), expected_str); - return false; + void *actual, void *expected) +{ + char actual_str[256] = { 0 }; + char expected_str[256] = { 0 }; + + tests_total++; + to_str(actual, actual_str, 255); + to_str(expected, expected_str, 255); + if (strncmp(actual_str, expected_str, 255) == 0) { + ctest_printf(CHECK_MARK "%s\n", name); + tests_passed++; + return true; + } + ctest_printf(RED(ERROR_MARK "%s\n"), name); + ctest_printf(GREEN(" + expected ") RED("- actual\n\n")); + ctest_printf(RED(" - %s\n"), actual_str); + ctest_printf(GREEN(" + %s\n\n"), expected_str); + return false; } int ctest_int_to_str(void *data, char *str, unsigned max_len) { - return snprintf(str, max_len, "%d", *(int *)data); + return snprintf(str, max_len, "%d", *(int *)data); } int ctest_uint_to_str(void *data, char *str, unsigned max_len) { - return snprintf(str, max_len, "%u", *(unsigned *)data); + return snprintf(str, max_len, "%u", *(unsigned *)data); } int ctest_float_to_str(void *data, char *str, unsigned max_len) { - return snprintf(str, max_len, "%f", *(float *)data); + return snprintf(str, max_len, "%f", *(float *)data); } int ctest_str_to_str(void *data, char *str, unsigned max_len) { - return snprintf(str, max_len, "\"%s\"", (char *)data); + return snprintf(str, max_len, "\"%s\"", (char *)data); } int ctest_wcs_to_str(void *data, char *str, unsigned max_len) { - return snprintf(str, max_len, "\"%S\"", (wchar_t *)data); + return snprintf(str, max_len, "\"%S\"", (wchar_t *)data); } int ctest_bool_to_str(void *data, char *str, unsigned max_len) { - return snprintf(str, max_len, "%s", *(bool*)data ? "true" : "false"); + return snprintf(str, max_len, "%s", *(bool *)data ? "true" : "false"); } bool ctest_equal_int(const char *name, int actual, int expected) { - return ctest_equal(name, ctest_int_to_str, &actual, &expected); + return ctest_equal(name, ctest_int_to_str, &actual, &expected); } bool ctest_equal_bool(const char *name, bool actual, bool expected) { - return ctest_equal(name, ctest_bool_to_str, &actual, &expected); + return ctest_equal(name, ctest_bool_to_str, &actual, &expected); } bool ctest_equal_uint(const char *name, unsigned actual, unsigned expected) { - return ctest_equal(name, ctest_uint_to_str, &actual, &expected); + return ctest_equal(name, ctest_uint_to_str, &actual, &expected); } bool ctest_equal_float(const char *name, float actual, float expected) { - return ctest_equal(name, ctest_float_to_str, &actual, &expected); + return ctest_equal(name, ctest_float_to_str, &actual, &expected); } bool ctest_equal_str(const char *name, const char *actual, const char *expected) { - return ctest_equal(name, ctest_str_to_str, (void *)actual, (void *)expected); + return ctest_equal(name, ctest_str_to_str, (void *)actual, + (void *)expected); } -bool ctest_equal_wcs(const char *name, const wchar_t *actual, const wchar_t *expected) +bool ctest_equal_wcs(const char *name, const wchar_t *actual, + const wchar_t *expected) { - return ctest_equal(name, ctest_wcs_to_str, (void *)actual, (void *)expected); + return ctest_equal(name, ctest_wcs_to_str, (void *)actual, + (void *)expected); } int ctest_finish(void) { - printf(GREEN(" %zu passing") " (%ums)\n", tests_passed, - (unsigned)get_time_delta(test_start_time)); - if (tests_total > tests_passed) { - printf(RED(" %zu faling\n\n"), tests_total - tests_passed); - return (int)(tests_total - tests_passed); - } - printf("\n"); - return 0; + printf(GREEN(" %zu passing") " (%ums)\n", tests_passed, + (unsigned)get_time_delta(test_start_time)); + if (tests_total > tests_passed) { + printf(RED(" %zu faling\n\n"), tests_total - tests_passed); + return (int)(tests_total - tests_passed); + } + printf("\n"); + return 0; +} + +static const char *grep_pattern = NULL; +static bool interactive = false; +static bool list_only = false; +static int suite_running_depth = 0; + +void ctest_set_grep(const char *pattern) +{ + grep_pattern = pattern; +} + +bool ctest_should_run(const char *name) +{ + if (!grep_pattern) + return true; + if (suite_running_depth > 0) + return true; + return strstr(name, grep_pattern) != NULL; +} + +bool ctest_is_interactive(void) +{ + return interactive; +} + +void ctest_set_interactive(bool value) +{ + interactive = value; +} + +int ctest_parse_args(int argc, char **argv) +{ + int i; + for (i = 1; i < argc; ++i) { + if (strcmp(argv[i], "--grep") == 0 && i + 1 < argc) { + grep_pattern = argv[++i]; + } else if (strncmp(argv[i], "--grep=", 7) == 0) { + grep_pattern = argv[i] + 7; + } else if (strcmp(argv[i], "--list") == 0) { + list_only = true; + } else if (strcmp(argv[i], "--interactive") == 0 || + strcmp(argv[i], "-i") == 0) { + interactive = true; + } else if (strcmp(argv[i], "--help") == 0 || + strcmp(argv[i], "-h") == 0) { + printf("usage: %s [options]\n", argv[0]); + printf(" --grep " + "run suites matching pattern\n"); + printf(" --list " + "list all suite names\n"); + printf(" --interactive,-i " + "enable interactive mode\n"); + printf(" --help,-h " + "show this help message\n"); + return -1; + } + } + return 0; +} + +int ctest_run_suites(const ctest_suite_t *suites) +{ + const ctest_suite_t *s; + if (list_only) { + for (s = suites; s->name; ++s) { + printf("%s\n", s->name); + } + return 0; + } + for (s = suites; s->name; ++s) { + if (!ctest_should_run(s->name)) + continue; + ctest_printf("%s\n", s->name); + ctest_group_begin(); + suite_running_depth++; + s->run(); + suite_running_depth--; + ctest_group_end(); + ctest_printf("\n"); + } + return ctest_finish(); } diff --git a/lib/ctest/tests/main.c b/lib/ctest/tests/main.c new file mode 100644 index 000000000..1fbf27786 --- /dev/null +++ b/lib/ctest/tests/main.c @@ -0,0 +1,23 @@ +/* + * lib/ctest/tests/main.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include + +extern void test_str_funcs(void); +extern void test_grep_funcs(void); + +int main(void) +{ + test_str_funcs(); + test_grep_funcs(); + printf("ctest-tests: all assertions passed\n"); + return 0; +} diff --git a/lib/ctest/tests/test_grep.c b/lib/ctest/tests/test_grep.c new file mode 100644 index 000000000..2b0e8256b --- /dev/null +++ b/lib/ctest/tests/test_grep.c @@ -0,0 +1,57 @@ +#include +#include +#include + +static void test_should_run_no_pattern(void) +{ + ctest_set_grep(NULL); + assert(ctest_should_run("anything") == true); + assert(ctest_should_run("") == true); +} + +static void test_should_run_with_pattern(void) +{ + ctest_set_grep("widget"); + assert(ctest_should_run("widget event") == true); + assert(ctest_should_run("widget opacity") == true); + assert(ctest_should_run("settings") == false); + assert(ctest_should_run("thread") == false); +} + +static void test_should_run_exact_match(void) +{ + ctest_set_grep("steptimer"); + assert(ctest_should_run("steptimer") == true); + assert(ctest_should_run("ptk/steptimer") == true); + assert(ctest_should_run("widget event") == false); +} + +static void test_should_run_empty_pattern(void) +{ + ctest_set_grep(""); + assert(ctest_should_run("anything") == true); +} + +static void test_is_interactive_default(void) +{ + ctest_set_interactive(false); + assert(ctest_is_interactive() == false); +} + +static void test_is_interactive_set(void) +{ + ctest_set_interactive(true); + assert(ctest_is_interactive() == true); + ctest_set_interactive(false); + assert(ctest_is_interactive() == false); +} + +void test_grep_funcs(void) +{ + test_should_run_no_pattern(); + test_should_run_with_pattern(); + test_should_run_exact_match(); + test_should_run_empty_pattern(); + test_is_interactive_default(); + test_is_interactive_set(); +} diff --git a/lib/ctest/tests/test_str.c b/lib/ctest/tests/test_str.c new file mode 100644 index 000000000..97f50e29b --- /dev/null +++ b/lib/ctest/tests/test_str.c @@ -0,0 +1,59 @@ +#include +#include +#include + +static void test_int_to_str(void) +{ + char buf[256]; + int val = 42; + ctest_int_to_str(&val, buf, 255); + assert(strcmp(buf, "42") == 0); + + val = -1; + ctest_int_to_str(&val, buf, 255); + assert(strcmp(buf, "-1") == 0); +} + +static void test_uint_to_str(void) +{ + char buf[256]; + unsigned val = 123u; + ctest_uint_to_str(&val, buf, 255); + assert(strcmp(buf, "123") == 0); +} + +static void test_float_to_str(void) +{ + char buf[256]; + float val = 3.14f; + ctest_float_to_str(&val, buf, 255); + assert(strncmp(buf, "3.14", 4) == 0); +} + +static void test_str_to_str(void) +{ + char buf[256]; + const char *val = "hello"; + ctest_str_to_str((void *)val, buf, 255); + assert(strcmp(buf, "\"hello\"") == 0); +} + +static void test_bool_to_str(void) +{ + char buf[256]; + bool val_true = true; + bool val_false = false; + ctest_bool_to_str(&val_true, buf, 255); + assert(strcmp(buf, "true") == 0); + ctest_bool_to_str(&val_false, buf, 255); + assert(strcmp(buf, "false") == 0); +} + +void test_str_funcs(void) +{ + test_int_to_str(); + test_uint_to_str(); + test_float_to_str(); + test_str_to_str(); + test_bool_to_str(); +} diff --git a/lib/ctest/tests/xmake.lua b/lib/ctest/tests/xmake.lua new file mode 100644 index 000000000..7b9c3ca7a --- /dev/null +++ b/lib/ctest/tests/xmake.lua @@ -0,0 +1,9 @@ +target("ctest-tests") + set_default(false) + set_kind("binary") + set_group("tests") + set_rundir(".") + add_files("test_str.c", "test_grep.c", "main.c") + add_deps("ctest", "yutil") + add_rules("tests.runnable") + add_tests("default", {group = "tests"}) diff --git a/lib/ctest/xmake.lua b/lib/ctest/xmake.lua index a2ec594b4..20e4dd5a3 100644 --- a/lib/ctest/xmake.lua +++ b/lib/ctest/xmake.lua @@ -6,3 +6,7 @@ target("ctest") add_files("src/*.c") add_deps("yutil") add_headerfiles("include/ctest.h") + +if os.isdir("tests") then + includes("tests/xmake.lua") +end From faa705883765c95fb9ddf449f66c4645fdb667b1 Mon Sep 17 00:00:00 2001 From: Liu Date: Sat, 23 May 2026 18:46:07 +0800 Subject: [PATCH 07/66] test: reorganize test suite with xmake test integration Restructure the test infrastructure with these changes: * Extend libctest with ctest_suite_t, ctest_parse_args, ctest_run_suites and CTEST_MAIN macro to standardize test entry points; support --grep / --grep= / --list / --interactive flags; add ctest-tests for self-tests. * Regroup tests by lib boundary: sink unit tests into lib//tests/ with _ entry function names, move fixtures into lib//tests/fixtures/, rename top-level tests/cases/ to tests/integration/ for cross-lib integration tests. * Add tests/scenes/ for reusable widget tree builders shared by integration cases and visual preview binaries; add tests/previews/ with 4 diagnostic binaries (flex_layout, block_layout, widget_opacity, scrollbar). * Rewrite all describe/equal description strings using 'should ...' style or noun topic names; drop redundant lcui_quit/lcui_main calls from integration cases. * Integrate xmake test via add_tests(\default\) and a shared tests.runnable rule defined in the root xmake.lua; the rule wraps the test binary with drmemory (Windows) or valgrind (Linux) when option memcheck=y. * Drop the lcui-tests aggregation: lcui-tests now contains only integration cases and scenes, not the union of lib tests. Use xmake test to run everything across libs. * Fix .clang-format: InsertNewlineAtEndOfFile -> InsertNewlineAtEOF (correct key for clang-format 16+). * Update AGENTS.md with the new test layout, naming rules, description style and run commands. * Update CI to use xmake test and xmake f --memcheck=y instead of per-lib runs. --- .clang-format | 1 + .github/workflows/ccpp.yml | 36 +- AGENTS.md | 77 +- lib/css/xmake.lua | 26 +- lib/i18n/xmake.lua | 30 +- lib/pandagl/examples/char-render/src/main.c | 48 ++ lib/pandagl/examples/char-render/xmake.lua | 7 + .../examples/fill-rect-with-rgba/src/main.c | 53 ++ .../examples/fill-rect-with-rgba/xmake.lua | 7 + lib/pandagl/examples/fill-rect/src/main.c | 38 + lib/pandagl/examples/fill-rect/xmake.lua | 7 + .../examples/image-scaling-bench/src/main.c | 55 ++ .../examples/image-scaling-bench/xmake.lua | 7 + .../examples/mix-rect-with-opacity/src/main.c | 49 ++ .../examples/mix-rect-with-opacity/xmake.lua | 7 + .../app}/test_image_reader.png | Bin .../examples/paint-background/src/main.c | 135 +++ .../examples/paint-background/xmake.lua | 7 + .../paint-border/app/test_image_reader.png | Bin 0 -> 8695 bytes lib/pandagl/examples/paint-border/src/main.c | 91 ++ lib/pandagl/examples/paint-border/xmake.lua | 7 + .../paint-boxshadow/app/test_image_reader.png | Bin 0 -> 8695 bytes .../examples/paint-boxshadow/src/main.c | 121 +++ .../examples/paint-boxshadow/xmake.lua | 7 + .../examples/pixel-manipulation/app}/dog.jpg | Bin .../examples/pixel-manipulation/src/main.c | 85 ++ .../examples/pixel-manipulation/xmake.lua | 7 + lib/pandagl/examples/string-render/src/main.c | 45 + lib/pandagl/examples/string-render/xmake.lua | 7 + lib/pandagl/test/test.c | 19 - lib/pandagl/test/test.h | 12 - lib/pandagl/test/test_canvas_mix.c | 71 -- .../tests/fixtures}/test_font_load.ttf | Bin .../tests/fixtures}/test_image_reader.bmp | Bin .../tests/fixtures}/test_image_reader.jpg | Bin .../tests/fixtures/test_image_reader.png | Bin 0 -> 8695 bytes lib/pandagl/tests/main.c | 25 + lib/pandagl/tests/test_canvas_mix.c | 73 ++ .../pandagl/tests}/test_font_load.c | 129 ++- .../pandagl/tests}/test_image_reader.c | 19 +- lib/pandagl/xmake.lua | 10 +- lib/ptk/tests/main.c | 19 + .../cases => lib/ptk/tests}/test_steptimer.c | 10 +- lib/ptk/xmake.lua | 11 + lib/router/xmake.lua | 29 +- lib/thread/tests/main.c | 19 + lib/thread/tests/test_thread.c | 95 +++ lib/thread/xmake.lua | 11 + .../fixtures}/test_xml_parser.nested.xml | 0 .../tests/fixtures}/test_xml_parser.xml | 0 lib/ui-xml/tests/main.c | 19 + lib/ui-xml/tests/test_xml_parser.c | 64 ++ lib/ui-xml/xmake.lua | 10 + tests/cases/test_flex_layout.c | 752 ----------------- tests/cases/test_scrollbar.c | 202 ----- tests/cases/test_settings.c | 118 --- tests/cases/test_textinput.c | 67 -- tests/cases/test_thread.c | 94 --- tests/cases/test_widget_event.c | 122 --- tests/cases/test_widget_rect.c | 173 ---- tests/cases/test_xml_parser.c | 62 -- tests/{ => fixtures}/test_block_layout.css | 0 tests/{ => fixtures}/test_block_layout.xml | 0 tests/{ => fixtures}/test_flex_layout.css | 0 tests/{ => fixtures}/test_flex_layout.xml | 0 .../test_font_face.css} | 2 +- tests/fixtures/test_font_face.ttf | Bin 0 -> 4496 bytes tests/{ => fixtures}/test_scrollbar.xml | 0 tests/{ => fixtures}/test_widget_opacity.css | 0 tests/{ => fixtures}/test_widget_opacity.xml | 0 tests/{include => helpers}/ctest-custom.h | 10 +- .../test_block_layout.c | 47 +- tests/{cases => integration}/test_clipboard.c | 3 +- tests/integration/test_flex_layout.c | 789 ++++++++++++++++++ tests/integration/test_font_face.c | 24 + tests/{cases => integration}/test_mainloop.c | 2 +- tests/{cases => integration}/test_router.c | 19 +- tests/integration/test_scrollbar.c | 120 +++ tests/integration/test_settings.c | 120 +++ .../{cases => integration}/test_text_resize.c | 47 +- tests/integration/test_textinput.c | 76 ++ tests/integration/test_widget_event.c | 130 +++ .../test_widget_opacity.c | 53 +- tests/integration/test_widget_rect.c | 180 ++++ tests/main.c | 53 ++ tests/previews/preview_block_layout.c | 24 + tests/previews/preview_flex_layout.c | 24 + tests/previews/preview_scrollbar.c | 24 + tests/previews/preview_widget_opacity.c | 26 + tests/previews/xmake.lua | 18 + tests/run_tests.c | 40 - tests/run_tests.h | 28 - tests/scenes/block_layout_scene.c | 25 + tests/scenes/block_layout_scene.h | 19 + tests/scenes/flex_layout_scene.c | 25 + tests/scenes/flex_layout_scene.h | 19 + tests/scenes/scrollbar_scene.c | 81 ++ tests/scenes/scrollbar_scene.h | 19 + tests/scenes/widget_opacity_scene.c | 26 + tests/scenes/widget_opacity_scene.h | 25 + tests/test_block_layout.c | 21 - tests/test_block_layout.html | 157 ---- tests/test_border.c | 32 - tests/test_border.css | 47 -- tests/test_border.html | 40 - tests/test_border.xml | 150 ---- tests/test_box_shadow.c | 30 - tests/test_box_shadow.css | 46 - tests/test_box_shadow.html | 34 - tests/test_box_shadow.xml | 32 - tests/test_char_render.c | 57 -- tests/test_css_parser.css | 58 -- tests/test_css_parser.xml | 21 - tests/test_fill_rect.c | 39 - tests/test_fill_rect_with_rgba.c | 56 -- tests/test_flex_layout.c | 21 - tests/test_flex_layout.html | 359 -------- tests/test_image_scaling_bench.c | 57 -- tests/test_mix_rect_with_opacity.c | 56 -- tests/test_paint_background.c | 156 ---- tests/test_paint_border.c | 98 --- tests/test_paint_boxshadow.c | 134 --- tests/test_pixel_manipulation.c | 84 -- tests/test_render.c | 171 ---- tests/test_scaling_support.c | 81 -- tests/test_scaling_support.css | 49 -- tests/test_scaling_support.xml | 40 - tests/test_scrollbar.c | 25 - tests/test_string_render.c | 52 -- tests/test_text_resize.c | 26 - tests/test_touch.c | 110 --- tests/test_widget.c | 65 -- tests/test_widget_opacity.c | 55 -- tests/test_widget_render.c | 60 -- tests/xmake.lua | 87 +- xmake.lua | 74 +- 136 files changed, 3295 insertions(+), 4678 deletions(-) create mode 100644 lib/pandagl/examples/char-render/src/main.c create mode 100644 lib/pandagl/examples/char-render/xmake.lua create mode 100644 lib/pandagl/examples/fill-rect-with-rgba/src/main.c create mode 100644 lib/pandagl/examples/fill-rect-with-rgba/xmake.lua create mode 100644 lib/pandagl/examples/fill-rect/src/main.c create mode 100644 lib/pandagl/examples/fill-rect/xmake.lua create mode 100644 lib/pandagl/examples/image-scaling-bench/src/main.c create mode 100644 lib/pandagl/examples/image-scaling-bench/xmake.lua create mode 100644 lib/pandagl/examples/mix-rect-with-opacity/src/main.c create mode 100644 lib/pandagl/examples/mix-rect-with-opacity/xmake.lua rename {tests => lib/pandagl/examples/paint-background/app}/test_image_reader.png (100%) create mode 100644 lib/pandagl/examples/paint-background/src/main.c create mode 100644 lib/pandagl/examples/paint-background/xmake.lua create mode 100644 lib/pandagl/examples/paint-border/app/test_image_reader.png create mode 100644 lib/pandagl/examples/paint-border/src/main.c create mode 100644 lib/pandagl/examples/paint-border/xmake.lua create mode 100644 lib/pandagl/examples/paint-boxshadow/app/test_image_reader.png create mode 100644 lib/pandagl/examples/paint-boxshadow/src/main.c create mode 100644 lib/pandagl/examples/paint-boxshadow/xmake.lua rename {tests => lib/pandagl/examples/pixel-manipulation/app}/dog.jpg (100%) create mode 100644 lib/pandagl/examples/pixel-manipulation/src/main.c create mode 100644 lib/pandagl/examples/pixel-manipulation/xmake.lua create mode 100644 lib/pandagl/examples/string-render/src/main.c create mode 100644 lib/pandagl/examples/string-render/xmake.lua delete mode 100644 lib/pandagl/test/test.c delete mode 100644 lib/pandagl/test/test.h delete mode 100644 lib/pandagl/test/test_canvas_mix.c rename {tests => lib/pandagl/tests/fixtures}/test_font_load.ttf (100%) rename {tests => lib/pandagl/tests/fixtures}/test_image_reader.bmp (100%) rename {tests => lib/pandagl/tests/fixtures}/test_image_reader.jpg (100%) create mode 100644 lib/pandagl/tests/fixtures/test_image_reader.png create mode 100644 lib/pandagl/tests/main.c create mode 100644 lib/pandagl/tests/test_canvas_mix.c rename {tests/cases => lib/pandagl/tests}/test_font_load.c (58%) rename {tests/cases => lib/pandagl/tests}/test_image_reader.c (61%) create mode 100644 lib/ptk/tests/main.c rename {tests/cases => lib/ptk/tests}/test_steptimer.c (96%) create mode 100644 lib/thread/tests/main.c create mode 100644 lib/thread/tests/test_thread.c rename {tests => lib/ui-xml/tests/fixtures}/test_xml_parser.nested.xml (100%) rename {tests => lib/ui-xml/tests/fixtures}/test_xml_parser.xml (100%) create mode 100644 lib/ui-xml/tests/main.c create mode 100644 lib/ui-xml/tests/test_xml_parser.c delete mode 100644 tests/cases/test_flex_layout.c delete mode 100644 tests/cases/test_scrollbar.c delete mode 100644 tests/cases/test_settings.c delete mode 100644 tests/cases/test_textinput.c delete mode 100644 tests/cases/test_thread.c delete mode 100644 tests/cases/test_widget_event.c delete mode 100644 tests/cases/test_widget_rect.c delete mode 100644 tests/cases/test_xml_parser.c rename tests/{ => fixtures}/test_block_layout.css (100%) rename tests/{ => fixtures}/test_block_layout.xml (100%) rename tests/{ => fixtures}/test_flex_layout.css (100%) rename tests/{ => fixtures}/test_flex_layout.xml (100%) rename tests/{test_font_load.css => fixtures/test_font_face.css} (71%) create mode 100644 tests/fixtures/test_font_face.ttf rename tests/{ => fixtures}/test_scrollbar.xml (100%) rename tests/{ => fixtures}/test_widget_opacity.css (100%) rename tests/{ => fixtures}/test_widget_opacity.xml (100%) rename tests/{include => helpers}/ctest-custom.h (60%) rename tests/{cases => integration}/test_block_layout.c (96%) rename tests/{cases => integration}/test_clipboard.c (94%) create mode 100644 tests/integration/test_flex_layout.c create mode 100644 tests/integration/test_font_face.c rename tests/{cases => integration}/test_mainloop.c (96%) rename tests/{cases => integration}/test_router.c (84%) create mode 100644 tests/integration/test_scrollbar.c create mode 100644 tests/integration/test_settings.c rename tests/{cases => integration}/test_text_resize.c (70%) create mode 100644 tests/integration/test_textinput.c create mode 100644 tests/integration/test_widget_event.c rename tests/{cases => integration}/test_widget_opacity.c (70%) create mode 100644 tests/integration/test_widget_rect.c create mode 100644 tests/main.c create mode 100644 tests/previews/preview_block_layout.c create mode 100644 tests/previews/preview_flex_layout.c create mode 100644 tests/previews/preview_scrollbar.c create mode 100644 tests/previews/preview_widget_opacity.c create mode 100644 tests/previews/xmake.lua delete mode 100644 tests/run_tests.c delete mode 100644 tests/run_tests.h create mode 100644 tests/scenes/block_layout_scene.c create mode 100644 tests/scenes/block_layout_scene.h create mode 100644 tests/scenes/flex_layout_scene.c create mode 100644 tests/scenes/flex_layout_scene.h create mode 100644 tests/scenes/scrollbar_scene.c create mode 100644 tests/scenes/scrollbar_scene.h create mode 100644 tests/scenes/widget_opacity_scene.c create mode 100644 tests/scenes/widget_opacity_scene.h delete mode 100644 tests/test_block_layout.c delete mode 100644 tests/test_block_layout.html delete mode 100644 tests/test_border.c delete mode 100644 tests/test_border.css delete mode 100644 tests/test_border.html delete mode 100644 tests/test_border.xml delete mode 100644 tests/test_box_shadow.c delete mode 100644 tests/test_box_shadow.css delete mode 100644 tests/test_box_shadow.html delete mode 100644 tests/test_box_shadow.xml delete mode 100644 tests/test_char_render.c delete mode 100644 tests/test_css_parser.css delete mode 100644 tests/test_css_parser.xml delete mode 100644 tests/test_fill_rect.c delete mode 100644 tests/test_fill_rect_with_rgba.c delete mode 100644 tests/test_flex_layout.c delete mode 100644 tests/test_flex_layout.html delete mode 100644 tests/test_image_scaling_bench.c delete mode 100644 tests/test_mix_rect_with_opacity.c delete mode 100644 tests/test_paint_background.c delete mode 100644 tests/test_paint_border.c delete mode 100644 tests/test_paint_boxshadow.c delete mode 100644 tests/test_pixel_manipulation.c delete mode 100644 tests/test_render.c delete mode 100644 tests/test_scaling_support.c delete mode 100644 tests/test_scaling_support.css delete mode 100644 tests/test_scaling_support.xml delete mode 100644 tests/test_scrollbar.c delete mode 100644 tests/test_string_render.c delete mode 100644 tests/test_text_resize.c delete mode 100644 tests/test_touch.c delete mode 100644 tests/test_widget.c delete mode 100644 tests/test_widget_opacity.c delete mode 100644 tests/test_widget_render.c diff --git a/.clang-format b/.clang-format index 526b64afa..6d12e8efd 100644 --- a/.clang-format +++ b/.clang-format @@ -33,3 +33,4 @@ SpacesInParentheses: false SpacesInSquareBrackets: false SortIncludes: false UseTab: Never +InsertNewlineAtEOF: true diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 5368827d2..7ff01bcf3 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -42,36 +42,20 @@ jobs: - name: Build run: | xmake - xmake build yutil_test - xmake build pandagl_tests - xmake build libcss_tests - xmake build librouter_tests - xmake build libi18n_tests - xmake build lcui_tests - - - name: Run tests for libraries with memcheck - if: runner.os == 'Linux' - run: | - xmake run pandagl_tests - xmake run yutil_test --memcheck - xmake run libcss_tests --memcheck - xmake run librouter_tests --memcheck - xmake run libi18n_tests --memcheck + xmake build yutil-tests - - name: Run tests for lcui with memcheck - if: runner.os == 'Linux' - run: | - xmake run lcui_tests --memcheck + - name: Run yutil tests + run: xmake run yutil-tests - - name: Run tests + - name: Run all tests if: runner.os == 'Windows' + run: xmake test + + - name: Run all tests with memcheck + if: runner.os == 'Linux' run: | - xmake run pandagl_tests - xmake run yutil_test - xmake run libcss_tests - xmake run librouter_tests - xmake run libi18n_tests - xmake run lcui_tests + xmake f -m debug --memcheck=y + xmake test - name: Upload reports to Codecov if: runner.os == 'Linux' diff --git a/AGENTS.md b/AGENTS.md index 5efbc0879..3113d8ed8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,5 +1,7 @@ ## 代码格式 +遵循 .clang-format 文件中定义的规则,修改文件后需格式化。 + ### 缩进 使用八个空格缩进。 @@ -53,30 +55,81 @@ void object2_func2() { ## 测试用例 -在 tests/cases 中新建测试代码,源文件名称以 `test_` 开头,内部添加头文件包含: +### 归属规则 -```c -#include -`` +按下面优先级判定一个测试归属: + +1. case 实际 `#include` 的库头文件集合(含传递依赖)。 +2. 调用的运行时入口(`lcui_init` / `ui_init` / `pd_*_init` 等)。 +3. xmake target 上需要的 `add_deps`。 + +仅触达单 lib(外加 yutil/ctest/标准库)的测试放 `lib//tests/`;触达两个及以上同级 lib,或依赖 `src/widgets/` 注册的 widget 类型的测试放 `tests/integration/`。 + +### 文件与函数命名 + +- 文件名:`test_.c` +- 套件入口(lib 内):`void test__(void)`,如 `test_ui_xml_parser`、`test_pandagl_image_reader` +- 套件入口(顶层集成):`void test_(void)`,无前缀,如 `test_settings` +- 套件入口必须在两个位置都注册:所属 lib 的 `tests/main.c` 与顶层 `tests/main.c` 中的 `suites[]` 表 +- 内部分组用 `static void <动词>_(void)`,由 `ctest_describe` 注册 + +### 描述文本风格 + +- `ctest_describe(name, fn)` 的 `name` 是名词性主题,全小写空格分词,无 `test` 前缀。例:`"widget opacity"`、`"flex layout"`、`"settings.fps_cap"` +- `ctest_equal_*(name, ...)` 的 `name` 用 `should ...` 行为陈述。例:`"should default fps_cap to 120"`、`"should match parent border color"` +- 当上下文清晰(例如 layout case 中描述某 selector 对应的 box)时,可保留 jQuery 选择器风格的描述,无需强行加 should + +### 资源文件 + +- 跨 lib 共享的 fixture 放 `tests/fixtures/` +- 仅本 lib 用的 fixture 也建议复制到 `tests/fixtures/`(顶层 lcui-tests 与单 lib binary 共用同一 rundir) +- xmake target 的 `set_rundir` 指向 `tests/fixtures/` +- 测试代码加载资源时直接用文件名,不带目录前缀 + +### 三种文件职责 -然后使用 lib/ctest/include/ctest.h 中的函数输出测试信息、检测测试结果,例如: +- `tests/integration/test_.c`:跨 lib 集成测试,自动断言。不调用 `lcui_main`,必要时由 `tests/previews/preview_.c` 提供可视诊断 +- `tests/scenes/_scene.{c,h}`:可视化场景搭建模块,签名 `void _scene_build(...)`。只构造 widget 树和应用样式,不做断言、不调用 `ctest_*`、不调用 `lcui_main`/`lcui_quit`。给 cases 与未来的 examples demo 共用 +- `lib//tests/test_.c`:纯 lib 测试,仅断言 +### 编写示例 ```c #include -int add(int a, int b) -{ - return a + b; -} - void test_my_case(void) { - ctest_equat_init("check add(1, 1)", 2, add(1, 1)); + ctest_equal_int("should add two numbers", 1 + 1, 2); } ``` -最后,在 tests/run_tests.c 中添加这个测试的调用代码。 +注册: + +```c +/* lib//tests/main.c 或 tests/main.c */ +extern void test_my_case(void); + +static const ctest_suite_t suites[] = { + { "my case", test_my_case }, + { NULL, NULL } +}; + +CTEST_MAIN(suites) +``` + +### 运行 + +- 全量:`xmake test` +- 按 pattern 过滤:`xmake test "*/widget*"`(匹配 target/test 名) +- 按 group 过滤:`xmake test -g tests` +- 单 binary 跑全部 suite:`xmake run -tests`,例如 `xmake run lcui-tests` +- 单 binary 内细粒度过滤:`xmake run lcui-tests --grep=""`,子串匹配 suite 名 +- 单 binary 列出 suite:`xmake run lcui-tests --list` +- 内存检查:`xmake f --memcheck=y && xmake test`,调用 drmemory(Windows)或 valgrind(Linux);恢复正常运行:`xmake f --memcheck=n` + +### 不要触碰 + +- `lib/yutil/tests/`:使用旧 libtest 框架自管理,不并入 ctest 体系,不被 lcui-tests 收集 ## 重构约定 diff --git a/lib/css/xmake.lua b/lib/css/xmake.lua index de8b1f14b..0aacb35e8 100644 --- a/lib/css/xmake.lua +++ b/lib/css/xmake.lua @@ -14,29 +14,13 @@ target("libcss") add_defines("LIBCSS_DLL_EXPORT") end -target("libcss_tests") +target("libcss-tests") set_default(false) set_kind("binary") + set_group("tests") set_rundir("tests") + add_includedirs("tests") add_files("tests/*.c") add_deps("ctest", "libcss") - on_run(function (target) - import("core.base.option") - local argv = {} - local options = {{nil, "memcheck", "k", nil, "enable memory check."}} - local args = option.raw_parse(option.get("arguments") or {}, options) - os.cd("$(scriptdir)/tests") - if args.memcheck then - if is_plat("windows") then - table.insert(argv, target:targetfile()) - os.execv("drmemory", argv) - else - table.insert(argv, "--leak-check=full") - table.insert(argv, "--error-exitcode=42") - table.insert(argv, target:targetfile()) - os.execv("valgrind", argv) - end - else - os.execv(target:targetfile()) - end - end) + add_rules("tests.runnable") + add_tests("default", {group = "tests"}) diff --git a/lib/i18n/xmake.lua b/lib/i18n/xmake.lua index 047882c3d..8724e2621 100644 --- a/lib/i18n/xmake.lua +++ b/lib/i18n/xmake.lua @@ -20,30 +20,12 @@ target("libi18n") add_defines("LIBI18N_DLL_EXPORT") end -target("libi18n_tests") +target("libi18n-tests") set_default(false) set_kind("binary") - add_files("tests/test.c") - add_deps("libi18n", "ctest") + set_group("tests") set_rundir("tests") - on_run(function (target) - import("core.base.option") - local argv = {} - local options = {{nil, "memcheck", "k", nil, "enable memory check."}} - local args = option.raw_parse(option.get("arguments") or {}, options) - os.cd("$(scriptdir)/tests") - if args.memcheck then - if is_plat("windows") then - table.insert(argv, target:targetfile()) - os.execv("drmemory", argv) - else - table.insert(argv, "valgrind") - table.insert(argv, "--leak-check=full") - table.insert(argv, "--error-exitcode=42") - table.insert(argv, target:targetfile()) - os.execv("sudo", argv) - end - else - os.execv(target:targetfile()) - end - end) + add_files("tests/test.c") + add_deps("ctest", "libi18n") + add_rules("tests.runnable") + add_tests("default", {group = "tests"}) diff --git a/lib/pandagl/examples/char-render/src/main.c b/lib/pandagl/examples/char-render/src/main.c new file mode 100644 index 000000000..79c3c75d6 --- /dev/null +++ b/lib/pandagl/examples/char-render/src/main.c @@ -0,0 +1,48 @@ +/* + * lib/pandagl/examples/char-render/src/main.c + * + * Copyright (c) 2023, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include + +int main(void) +{ + int ret, fid; + pd_canvas_t img; + pd_font_bitmap_t bmp; + pd_pos_t pos = { 25, 25 }; + pd_color_t bg = pd_rgb(240, 240, 240); + pd_color_t color = pd_rgb(255, 0, 0); + + pd_font_library_init(); + + pd_canvas_init(&img); + pd_canvas_create(&img, 100, 100); + pd_canvas_fill(&img, bg); + + ret = pd_font_library_load_file("C:/Windows/fonts/simsun.ttc"); + while (ret == 0) { + fid = pd_font_library_get_font_id("SimSun", 0, 0); + if (fid < 0) { + break; + } + ret = pd_font_library_render_bitmap(&bmp, L'字', fid, 48); + if (ret != 0) { + break; + } + pd_canvas_mix_font_bitmap(&img, pos, &bmp, color); + pd_write_png_file("test_char_render.png", &img); + pd_font_bitmap_destroy(&bmp); + pd_canvas_destroy(&img); + break; + } + + pd_font_library_destroy(); + return ret; +} \ No newline at end of file diff --git a/lib/pandagl/examples/char-render/xmake.lua b/lib/pandagl/examples/char-render/xmake.lua new file mode 100644 index 000000000..15cb4c29e --- /dev/null +++ b/lib/pandagl/examples/char-render/xmake.lua @@ -0,0 +1,7 @@ +target("char-render") + set_default(false) + set_kind("binary") + set_rundir("app") + add_deps("pandagl") + add_files("src/*.c") + add_installfiles("app/*") \ No newline at end of file diff --git a/lib/pandagl/examples/fill-rect-with-rgba/src/main.c b/lib/pandagl/examples/fill-rect-with-rgba/src/main.c new file mode 100644 index 000000000..036f0702d --- /dev/null +++ b/lib/pandagl/examples/fill-rect-with-rgba/src/main.c @@ -0,0 +1,53 @@ +/* + * lib/pandagl/examples/fill-rect-with-rgba/src/main.c + * + * Copyright (c) 2023, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include + +int main(void) +{ + int i, j; + pd_canvas_t canvas; + pd_canvas_t fore_canvas; + pd_color_t color; + pd_rect_t rect; + + pd_canvas_init(&canvas); + pd_canvas_init(&fore_canvas); + pd_canvas_create(&canvas, 160, 160); + rect.x = 0; + rect.y = 0; + rect.width = 160; + rect.height = 40; + pd_canvas_fill_rect(&canvas, pd_rgb(255, 221, 0), rect); + rect.y += 40; + pd_canvas_fill_rect(&canvas, pd_rgb(102, 204, 0), rect); + rect.y += 40; + pd_canvas_fill_rect(&canvas, pd_rgb(0, 153, 255), rect); + rect.y += 40; + pd_canvas_fill_rect(&canvas, pd_rgb(255, 51, 0), rect); + color.red = 255; + color.green = 255; + color.blue = 255; + fore_canvas.color_type = PD_COLOR_TYPE_ARGB; + pd_canvas_create(&fore_canvas, 15, 30); + for (i = 0; i < 10; ++i) { + color.alpha = (unsigned char)(255 * (i + 1) / 10.0); + pd_canvas_fill(&fore_canvas, color); + for (j = 0; j < 4; ++j) { + pd_canvas_mix(&canvas, &fore_canvas, 5 + i * 15, 5 + j * 40, true); + } + } + pd_write_png_file("test_fill_rect_with_rgba.png", &canvas); + pd_canvas_destroy(&fore_canvas); + pd_canvas_destroy(&canvas); + return 0; +} \ No newline at end of file diff --git a/lib/pandagl/examples/fill-rect-with-rgba/xmake.lua b/lib/pandagl/examples/fill-rect-with-rgba/xmake.lua new file mode 100644 index 000000000..d5e4a6995 --- /dev/null +++ b/lib/pandagl/examples/fill-rect-with-rgba/xmake.lua @@ -0,0 +1,7 @@ +target("fill-rect-with-rgba") + set_default(false) + set_kind("binary") + set_rundir("app") + add_deps("pandagl") + add_files("src/*.c") + add_installfiles("app/*") \ No newline at end of file diff --git a/lib/pandagl/examples/fill-rect/src/main.c b/lib/pandagl/examples/fill-rect/src/main.c new file mode 100644 index 000000000..efe5ecfbf --- /dev/null +++ b/lib/pandagl/examples/fill-rect/src/main.c @@ -0,0 +1,38 @@ +/* + * lib/pandagl/examples/fill-rect/src/main.c + * + * Copyright (c) 2023, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include + +int main(void) +{ + int i, j; + pd_canvas_t canvas; + pd_color_t color; + pd_rect_t rect; + + pd_canvas_init(&canvas); + pd_canvas_create(&canvas, 150, 150); + for (i = 0; i < 6; ++i) { + for (j = 0; j < 6; ++j) { + color.red = (unsigned char)(255 - 42.5 * i); + color.green = (unsigned char)(255 - 42.5 * j); + color.blue = 0; + rect.x = j * 25; + rect.y = i * 25; + rect.width = 25; + rect.height = 25; + pd_canvas_fill_rect(&canvas, color, rect); + } + } + pd_write_png_file("test_fill_rect.png", &canvas); + pd_canvas_destroy(&canvas); + return 0; +} \ No newline at end of file diff --git a/lib/pandagl/examples/fill-rect/xmake.lua b/lib/pandagl/examples/fill-rect/xmake.lua new file mode 100644 index 000000000..e6a5ee561 --- /dev/null +++ b/lib/pandagl/examples/fill-rect/xmake.lua @@ -0,0 +1,7 @@ +target("fill-rect") + set_default(false) + set_kind("binary") + set_rundir("app") + add_deps("pandagl") + add_files("src/*.c") + add_installfiles("app/*") \ No newline at end of file diff --git a/lib/pandagl/examples/image-scaling-bench/src/main.c b/lib/pandagl/examples/image-scaling-bench/src/main.c new file mode 100644 index 000000000..a56614f7e --- /dev/null +++ b/lib/pandagl/examples/image-scaling-bench/src/main.c @@ -0,0 +1,55 @@ +/* + * lib/pandagl/examples/image-scaling-bench/src/main.c + * + * Copyright (c) 2023, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + int i; + int64_t t0, t1, t2; + int resx[] = { 480, 960, 1280, 1366, 1920, 2560, 3840 }, resy; + char s_res[32], s_t0[32], s_t1[32]; + + pd_canvas_t g_src, g_dst; + pd_color_t t_color; + + pd_canvas_init(&g_src); + g_src.color_type = PD_COLOR_TYPE_ARGB; + if (pd_canvas_create(&g_src, 960, 540) < 0) { + return -2; + } + t_color.value = 0xffaa5500; + pd_canvas_fill(&g_src, t_color); + logger_info("%-20s%-20s%s\n", "image size\\method", "Graph_Zoom()", + "Graph_ZoomBilinear()"); + for (i = 0; i < sizeof(resx) / sizeof(int); i++) { + resy = resx[i] * 9 / 16; + t0 = get_time_ms(); + pd_canvas_init(&g_dst); + pd_canvas_zoom(&g_src, &g_dst, false, resx[i], resy); + pd_canvas_destroy(&g_dst); + t1 = get_time_ms(); + pd_canvas_init(&g_dst); + pd_canvas_zoom_bilinear(&g_src, &g_dst, false, resx[i], resy); + pd_canvas_destroy(&g_dst); + t2 = get_time_ms(); + sprintf(s_res, "%dx%d", resx[i], resy); + sprintf(s_t0, "%ldms", (int)(t1 - t0)); + sprintf(s_t1, "%ldms", (int)(t2 - t1)); + logger_info("%-20s%-20s%-20s\n", s_res, s_t0, s_t1); + } + pd_canvas_destroy(&g_src); + return 0; +} \ No newline at end of file diff --git a/lib/pandagl/examples/image-scaling-bench/xmake.lua b/lib/pandagl/examples/image-scaling-bench/xmake.lua new file mode 100644 index 000000000..167da6d90 --- /dev/null +++ b/lib/pandagl/examples/image-scaling-bench/xmake.lua @@ -0,0 +1,7 @@ +target("image-scaling-bench") + set_default(false) + set_kind("binary") + set_rundir("app") + add_deps("pandagl", "yutil") + add_files("src/*.c") + add_installfiles("app/*") \ No newline at end of file diff --git a/lib/pandagl/examples/mix-rect-with-opacity/src/main.c b/lib/pandagl/examples/mix-rect-with-opacity/src/main.c new file mode 100644 index 000000000..2b65d4049 --- /dev/null +++ b/lib/pandagl/examples/mix-rect-with-opacity/src/main.c @@ -0,0 +1,49 @@ +/* + * lib/pandagl/examples/mix-rect-with-opacity/src/main.c + * + * Copyright (c) 2023, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include + +int main(void) +{ + int i, size; + pd_canvas_t canvas; + pd_canvas_t fore_canvas; + pd_rect_t rect; + + pd_canvas_init(&canvas); + pd_canvas_init(&fore_canvas); + pd_canvas_create(&canvas, 150, 150); + rect.x = 0; + rect.y = 0; + rect.width = 75; + rect.height = 75; + pd_canvas_fill_rect(&canvas, pd_rgb(255, 221, 0), rect); + rect.x = 75; + pd_canvas_fill_rect(&canvas, pd_rgb(102, 204, 0), rect); + rect.x = 0; + rect.y = 75; + pd_canvas_fill_rect(&canvas, pd_rgb(0, 153, 255), rect); + rect.x = 75; + pd_canvas_fill_rect(&canvas, pd_rgb(255, 51, 0), rect); + fore_canvas.opacity = 0.2f; + fore_canvas.color_type = PD_COLOR_TYPE_ARGB; + for (i = 0; i < 7; ++i) { + size = 2 * (10 + 10 * i); + pd_canvas_create(&fore_canvas, size, size); + pd_canvas_fill(&fore_canvas, pd_rgb(255, 255, 255)); + pd_canvas_mix(&canvas, &fore_canvas, 75 - size / 2, 75 - size / 2, + false); + } + pd_write_png_file("test_mix_rect_with_opacity.png", &canvas); + pd_canvas_destroy(&fore_canvas); + pd_canvas_destroy(&canvas); + return 0; +} \ No newline at end of file diff --git a/lib/pandagl/examples/mix-rect-with-opacity/xmake.lua b/lib/pandagl/examples/mix-rect-with-opacity/xmake.lua new file mode 100644 index 000000000..5caea4a8c --- /dev/null +++ b/lib/pandagl/examples/mix-rect-with-opacity/xmake.lua @@ -0,0 +1,7 @@ +target("mix-rect-with-opacity") + set_default(false) + set_kind("binary") + set_rundir("app") + add_deps("pandagl") + add_files("src/*.c") + add_installfiles("app/*") \ No newline at end of file diff --git a/tests/test_image_reader.png b/lib/pandagl/examples/paint-background/app/test_image_reader.png similarity index 100% rename from tests/test_image_reader.png rename to lib/pandagl/examples/paint-background/app/test_image_reader.png diff --git a/lib/pandagl/examples/paint-background/src/main.c b/lib/pandagl/examples/paint-background/src/main.c new file mode 100644 index 000000000..88951d1c2 --- /dev/null +++ b/lib/pandagl/examples/paint-background/src/main.c @@ -0,0 +1,135 @@ +/* + * lib/pandagl/examples/paint-background/src/main.c + * + * Copyright (c) 2023, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include + +int test_paint_background_color(void) +{ + pd_canvas_t canvas; + pd_color_t gray = pd_rgb(240, 240, 240); + pd_color_t green = pd_rgb(102, 204, 0); + pd_rect_t rect = { 200, 100, 400, 300 }; + pd_background_t bg = { 0 }; + pd_context_t* ctx; + + pd_canvas_init(&canvas); + pd_canvas_create(&canvas, 800, 600); + pd_canvas_fill(&canvas, gray); + bg.color = green; + ctx = pd_context_create(&canvas, &rect); + pd_paint_background(ctx, &bg, &rect); + pd_write_png_file("test_paint_background_color.png", &canvas); + pd_context_destroy(ctx); + pd_canvas_destroy(&canvas); + return 0; +} + +int test_paint_background_image(void) +{ + pd_canvas_t canvas; + pd_canvas_t image; + pd_color_t gray = pd_rgb(240, 240, 240); + pd_color_t green = pd_rgb(102, 204, 0); + pd_rect_t rect = { 200, 100, 400, 300 }; + pd_background_t bg = { 0 }; + pd_context_t* ctx; + + pd_canvas_init(&canvas); + pd_canvas_init(&image); + pd_canvas_create(&canvas, 800, 600); + pd_canvas_fill(&canvas, gray); + if (pd_read_image_from_file("test_image_reader.png", &image) != 0) { + return -1; + } + bg.color = green; + bg.image = ℑ + bg.width = image.width; + bg.height = image.height; + ctx = pd_context_create(&canvas, &rect); + pd_paint_background(ctx, &bg, &rect); + pd_write_png_file("test_paint_background_image.png", &canvas); + pd_context_destroy(ctx); + pd_canvas_destroy(&image); + pd_canvas_destroy(&canvas); + return 0; +} + +int test_paint_background_image_with_size(void) +{ + pd_canvas_t canvas; + pd_canvas_t image; + pd_color_t gray = pd_rgb(240, 240, 240); + pd_color_t green = pd_rgb(102, 204, 0); + pd_rect_t rect = { 200, 100, 400, 300 }; + pd_background_t bg = { 0 }; + pd_context_t* ctx; + + pd_canvas_init(&canvas); + pd_canvas_init(&image); + pd_canvas_create(&canvas, 800, 600); + pd_canvas_fill(&canvas, gray); + if (pd_read_image_from_file("test_image_reader.png", &image) != 0) { + return -1; + } + bg.color = green; + bg.image = ℑ + bg.width = rect.width; + bg.height = rect.height; + ctx = pd_context_create(&canvas, &rect); + pd_paint_background(ctx, &bg, &rect); + pd_write_png_file("test_paint_background_image_with_size.png", &canvas); + pd_context_destroy(ctx); + pd_canvas_destroy(&image); + pd_canvas_destroy(&canvas); + return 0; +} + +int test_paint_background_image_with_position(void) +{ + pd_canvas_t canvas; + pd_canvas_t image; + pd_color_t gray = pd_rgb(240, 240, 240); + pd_color_t green = pd_rgb(102, 204, 0); + pd_rect_t rect = { 200, 100, 400, 300 }; + pd_background_t bg = { 0 }; + pd_context_t* ctx; + + pd_canvas_init(&canvas); + pd_canvas_init(&image); + pd_canvas_create(&canvas, 800, 600); + pd_canvas_fill(&canvas, gray); + if (pd_read_image_from_file("test_image_reader.png", &image) != 0) { + return -1; + } + bg.color = green; + bg.image = ℑ + bg.width = image.width; + bg.height = image.height; + bg.x = (rect.width - image.width) / 2; + bg.y = (rect.height - image.height) / 2; + ctx = pd_context_create(&canvas, &rect); + pd_paint_background(ctx, &bg, &rect); + pd_write_png_file("test_paint_background_image_with_position.png", + &canvas); + pd_context_destroy(ctx); + pd_canvas_destroy(&image); + pd_canvas_destroy(&canvas); + return 0; +} + +int main(void) +{ + test_paint_background_color(); + test_paint_background_image(); + test_paint_background_image_with_size(); + test_paint_background_image_with_position(); + return 0; +} \ No newline at end of file diff --git a/lib/pandagl/examples/paint-background/xmake.lua b/lib/pandagl/examples/paint-background/xmake.lua new file mode 100644 index 000000000..c5619837e --- /dev/null +++ b/lib/pandagl/examples/paint-background/xmake.lua @@ -0,0 +1,7 @@ +target("paint-background") + set_default(false) + set_kind("binary") + set_rundir("app") + add_deps("pandagl") + add_files("src/*.c") + add_installfiles("app/*") \ No newline at end of file diff --git a/lib/pandagl/examples/paint-border/app/test_image_reader.png b/lib/pandagl/examples/paint-border/app/test_image_reader.png new file mode 100644 index 0000000000000000000000000000000000000000..cb3fef4cf844324953cc45f21b479a338cb9c288 GIT binary patch literal 8695 zcmVy!Wh04#7r zK}=$AXLWNRb#7^Na{vGU00000|Nj62W^ZpVVqtOsF)lD=FaS0+E;TbXWiwYmdmI1& z01|UUK}-QMGc-0gMJ+ip05dT(F*ZduSlHFikA^FNzj*b{^&1C0y8`&+Xt>IiFrGR9x&RM` z#d+oH(XeM2U%ICvqn#2u*g>ce|htbC!_xPr2O(10B6Ss zt9kjw&gU;*43^7`d`CX(+??~wd5YZd`1zzWJvmyPPcE61ZZ>ye0IeFU`dWp)cKqK@ zPgb+Z6k`PAb>H;#YFOmgItMUXxbihWdwM!<8b+aApr(PIHEEOOI-^}M_KfCqQXUTX z3>S0P=@*7bWbVTC9go@_cz%5FMxFl!Kx}^w;PB~1=i93JokfJam#fi1&-(TMb>H@d zyX2Fj;VJ@;+f90O&|5j@QIa7d#2cIS)+s$dK3IKnG+doLxZaB=NBz~=4LzMrudqr1 z=}`8KMkFJ|hAKqHGuOFu@Tv1muRLYt`Q&K0>KFOS`^a?e`1GSu`hiG=2sT$MYZaLY zlesehO2MOp-s)f5&)yo`wCnHdhyWQdcY#Y^b2gcCc05|mUDcb;OZrw*RRJZ!LBH@y zG(_+|+^rUXfi)N{TwFS=(O4rGm62t_(bKUxKR)or2+wD((=-r?6h_bjh0QTqD68=L z;DymlT(W@D-o@#p>0VN-+|$l0`feej-DqbH;O>R&$^t&R_R=K$mR)r{tP7bz`+WSpoT z^ox~bg7bkY)I`A7_4s0bhiy3;7Ux$!a5^a&_U!1a)yNp($x(l;2J3y`LBCj4 zp=RGIO6QrBRp(;vI%O3O*Xp}9xNp+GSq82OhzO&8;Y(km$T%AIPUbEghS)H#JWWhC z$c5M`a&^9rKF*I1R#R6^Zw+p;bfoJ#;(U#6SG|dmi%ZAxXmFhVhGAjZvzizq!y;c< zqc^dH00Wy3ZVj%lcMw_$m#(4;5oMXF!R!F;;0ZBLftSZk|kXKKodcUyfSzdru#PMqk{oY zCnYY_tkqz&aCFe~AD>MJ_xCMEU{Y3{^O>VC8s9{$5p)Jf#46ptHTe0|oe1#Z^9i{K z)@ZaAs-~%$CV6}p!pzt8#!Jpz)rk=v4hldJ5eC-q;qzp2Z-$kXkYSbHEKJi-os8!_ zqXl2b8NlP`vySuiW_=z$yXZ_yKhu)2Z*_J5MyPSi`$xcPX=f%ppUurd&z>VNnY+!7 zD625O`MswX^8t6rt>dqGo8vKX*DQ5APc6t#W>Ruv*8#zgJNr z|2aKTk*n9Ti9dXR`W|wAe6T7*4GmbW5rNXx^a{iMpN((L^}S=vW)LVBacYjIWLN2i174q`z;?bXZu77EUK+H7Qd# z3@NuA?pp+yTsk5RN|Nn~L}E-iaADNuM6cyrYy6;R{lkIHecfP<=E-<^ICr=0jnT=b zmz76p%X-pEWOO*N=c9f>h>_FDB|?T0O^9j203zvfKA?m=#B1}jnRvUD=XHowb%O}h zF;cp~zRl?uhPm_j7#UC9;lpe&~B?4W0 zQ3@X-qn@P-fjSBwo?g3(evz*-;G?5Mo}FC~VuO;5L6Ot5h8QFF-;l-jZ9cl+x6gzu zFRU;x>)FTS*=^6fmJq1~*f;vtq|?hts2dLUaxQ&MjNq$)QNq)UIU<5qaQ@NJDp$#N zhdQ=+O-&$qdPwfhRS_2=!y-jeqn=%@Umx`BN~`SrvaIsLDnf{?Cw=F{0i=z(xN(}V ze2uFcB!kdEN(;HUAStI#K-KYEC%zWnM9Mni>PQBtEW;?xrK{){mO){#xhD8#lj_f1 z#o+O2C)OT=@1Gry&Qoj_u}X+B5{X>83g>I85XqI^!~-IN*6EV=@2YMnaz$a(+coZd zJ%eP13ZpnEa*jv)#0Ji$C9Y}+u|`PPL}4{Xbc!A$SS6!}PcJ%GuEK}F!@(ZDj`$Fn zI)CV^hPkhCA?4S@J%iR@P15mt!a8dM`49*(V$^jEedoj{m+mCSNG3@`ld|ID=TpvR zS4bvUl}wk`f=2K@(rX<>VHN$toCEyb>7)~5tVCeApJQ{O3UNGhRmWAKQ@VQA#E4Ns zVGJN-S+Ztz9T5?%QuM9Chuco*jSeWGKn-UTN0Dd5m^6`PDGk&a)D46fXLW2&?icpl z$ABQMZ7w%s7r7c84foI6$oaM36v&@E=zGH?KRak7W$ln>EeHRfSKj_)xpC7%B ztUns|rYe*CY;r}eGD1ulj@H7bmmUH3t-giQ{6V+J*`tFMl0woD;q>D2mS?m|j)y(d z7m*ZAhKN!vK-m^JW>=oxo*BR$pzj|-KD{jYbXwvAd^&YZ%F5h$JOAk6-~`~Tg$<3l z_MGd4*oBCB#e#e*P1{`cKf1p^u9_zATf={Q1=G0xVUX5^zX~CYde(zbhe#D_v}Bua zg~+XhxODZc?|v&y`zpB7*SXaha~IxP0u3>e2~3^e?8{NluCz`eZqMKRq6; zLJZWg!Pk*}YnaR(bpsCv79Uc=HMw%tcyzc)zWV1c)KOJ`-KAUtRV2$RYop6Ye@!YXz6|sTA zUYAp985Rp}>d8CwH(D1n@DEi3n z^=v*J7Wrz_FIIcTOhaG;D`YqFh}R}vhcub}J%!dOQ%)-o$W4axH4WFfNT?gKOn5q; z5@W-j(OiD=XtPb$yoowSBop?n!Ke(ak}-TZDEzRnt3hGTjmr9v5o1JJr*v6*VgtE) zOD)vZ;S9k0lu9+N#zSn#ZhTHjdQY;9rinD9Bo!L!0R6)D0j_*H+*$;iXQ@~vf(v!B z$HWcQ1i1A&0NWK7G7D<8-N zE>0dz0kkA?fDjQ9IVMR)9a2Vr6Los^iZQu%=if5vwPSL1q;A?6Ac7AKJ*#oPL1nOK z6k0US*N8xj4N42M(m|}boR^#&9Zap!uXQ4QS;42I3WXaW0_yG z9?pkpCT)ftujw5|Wt2XWn+)r8o4Kbc=u8Nqq4G7k(oCTWDlsVIq;uA9rawM5-nxYhl`AUj&BMqBP9Q8f#SIy1b$wB^i;(ilgiC7=8wENP(uEm(lL3yJ2t6y zuXS?8Rftp}kSoFDY6JfJ7~LBuZF5EGYD^|vI!}y=u9q|$Tdk%gj4`&L`L#WDzTSAn z()qD5k_ZUaY{JtB)$>`|nLA&tfqtvhX4~Z|jn$;6f{VF(8e2^8&PmT*pl6er5)q0# zx!}Smbe3pv=>Q6+ld@y-WNno|-9&td)Ad--Cgq`!Ox8`uasB?>#HOigz?zJGt0{7Y z)f%f58E`teI=or8d_#$YS?MD^Yc?5$)oJPLmLVa)vx~WbWWIEkB0{SbA>Iyv9-mDI zv4MSS?j*22em*nL#Rwqr{dhdWY7?jrdnp;%Gdgh?oqr?r`|mD(=a}Kdh!0$n%_b0oV3yUkQfQ=?$DWVe(4Txa)1ElE{tC-{C^kn+NAqM ze)8y`IF1pV_p|Y(J9(7>^+zXn(RcnVf0jSXx0PJU=s~~mkA}thH+}Yxrtx(XY?XpL4vbdig>8@!5dtfgnwd6ApZuxDHDY9urbr4PiI zP{v&J2G(5z?U6{Vuc6=@_rlb9BujR`e1j?ZPL=&=*qaUu(^oANR>w%?8?+Wq9t_VX zb2t0h8~R0F6S-N^7OD`iEh%{F{L{M>twct{!kmi;hXafAkv*gFA#zzJzqYO_ua#Uk zEjK(uD&AxpT<0c|7Gk9IH9cz%f3M2UmGrfU=~+Fvzi%J5Kb>DWUxmnYa^+6$`oU+D z`QUUi&xbubS0edv&yeekx=tA6uxI;PiGMPl^zH==MlytJ1WnonaCJTQA)JKB?BdN91bBn8 zl}K)s40={S+%sx)a|x|Z^#C6tv1xEVbs6L;*##HksL1t*7DF9R-FPy0kJjKsgzBR0 z7_LHnJ{sfIFkShE++?YvB2`#t-p5-&%Y(i>AMDwYT^AGEMXF-M z*{9{de`rN8~Mi2ugKMCG%U__wl2$obM=OY)ZEwzRY)}a;l4#F!B>IM zeqibEj3<1H9lPG3!#(rR3I`I zWoVLT-?!#ODM4wdV-rCZ z)(~Q94nb0lHMC5T!ltIi<_7P*YU1&mA{R)GRRn8|dYnO?E6x4=#Cobj#I$L=kZN&N zhZ{8J2FZmA>v6*BR6+-(^hZR(zD>}RD8B3qi0j+O^k3AlG0_} zE7LX%W?AHPGH1A#THt($m|UT9$xn|*{@KOsa58tdZXndrsZ8>9D{~?-wd)m|c1l93 zBxDdFGl?0vXB1a1pfVX0xq2*_478BTjq3NBR!G*LD+vI9f z3tY=PrRyKu(?8uoikBfG*%n^|aS_ROge+So$CD*95|&@FSVnfYxB0+mmYojOi&U5X z&5H#hu)`K+H#w|s7q+@xUPf5P2+Jk^_PJ+C#O&@6BmBTCyqZbi1%vEcu%F zljU+*nC)zv?$)h)?{;s#-eL)KmupsK+O09d2X>dZh=h8{?oO9~{#E%8uj=ug7?ZB5 z&kCz4tlq5hHIWPInhjGX5d<`KNZm+UNL;C=!G{`G)ws}bS*FH{HHFja6mFGOIxeNF znO^$jBYcf%2?zK4y<`9BCz~fQtey7y^_nPYl-_i*Cl*A@`Dqg&eIvDBe|K{(Tbk)6 zzP|CA8=qVMm#YIIv`tYo_;_~{_B$y%HtFU|SEr+tWoQkFMG`m3g-D`5RV}Gk0Oy-T z=&b^=S@XH#hUKF^;?I**ZvbB@}({Oac)t%^MFhY-)KNz4o_ z8JAZM?`!h*`9n7^NakasteBWgxl&~9lC5zNB`M|>mFO#K&Eet3CD(m+zK-NdP?;vw zk;8$##d?KzG$T9PqKTb69m?QXH4p;^L~WbAHl@#7D2_U~!jiyFS}z}6Q2MPyq#>}sJ) z7roPkWtZg=7I9hK+uqrJxmZw#$W|9(T&4v9eqeU)olQO)mQ_8w|6j~czgjGaOMoT! zc6WZVv)$$MFJI7=EtV}4XIF&(_1Whv=@6H#?QO5^?JiqO&^qIbu)u70S<Te zTkW-6zOIWbgRLcOW!Im}wqP5fyVXH&3tGhO%F{}Jh5|EjgOvPm`ns8 z0;Zi`|_r_tZ9acbC8YVd_EdF1OG-!ad#P zSD$(QrTmgFLj;!iMZ<4nhwW|x-?z4siJ-fL<#O@Y_jb2+wnga|$v*A~FY6SYd|(t> zwscvAU&JMg@vlGs$DUPxlWk@9%yyTTbwp)b{OE&wIKN<5!%jEj?BB}6|5Js3SS;c{ z{pbVpKkn^j+sogA&?UsLu|{)G2_Y`YvM$RmxN1RMF4@hxhzQ#P(uEM0tT(yLvgCbN5ei$>P10ZFYC={q5l1PdeQtFJCmgSVVsFa=~X`yyP=q z@vE}p#Uk>VtGFn?z%LdomrHiKTXehd1HFTEyDXMVmMqab+mK8M(v|J33p?2sFBg%m ztuBi?vMs{y?l#*3i%9Xoy`8@=zf44?UzOEqTrPKhWOoNI7b#49v55TWgIyMN2cx%{ zfBwa+TEub*i_fd@wEQys<03A9`NMnqeplEozX<%$?()?FcDErcIut(;mUO9?OBTxo z9l*U4d2_z_`c3?FBf#_@-lwKS8+)d0wKb^?PR;ZuXk9oBnFb=ce?CkUG&yA zaT(d#f?d5$r;~QWqIFS&37t+d{$Y_Ig%^uR=j$ck+Z6`IJ(gcD>2AS}bouAWzd!!fAVlJU6-C*T{9_t`#6FG0u}k1+a8JGx@!(@V<>CeSCh=&^vXXjjOO96I9d1T zWbGr4gcQf>OgNw3T@VlO@qlYV$;kXKc9UgJ}!`-91Xn|p^g#XH0d1x!oRL7bhQw7bOd=xNmLB`*r5it=-Tm05cgC|_2s4BYGPiFHF2v2_HeyVr zBxyOfqNU~G%BGBzo~xA}_olT#9jeo|(J4az2ofQ<3Y%Crk&%VEiPf9%ix^WM{>g*> zRLJ`4N24j7*>}0O$huV?Mm>8n*w2qs%&&>SzDZAKuqGjs2fc(cmc9l7=fdpCcsBYb z4F0_ezDNDy{9s^5B7$>)dFAmwZgy~LkGQVY(UR`7_L%`8#`V9|`P7YGRo>4ZrKYTT z=}Fa`l%-lDT+IE`xvO4F6ke5so;?}v=f^ZqSi{4oWAjZ)c#|k09~SnpP6?9Tx5`Y* zYC8Az`M052zE`D2G8{1_3&sd!1|en6>jr_FiY7}(EoE0AQJ6bFzDa)Fj4kA$ecX|> z3scvLKH36?`BHA3wf`dUDwfBl~_Pl33--r)m(RwSfh~E&Q>9j<*N{xT)M-% z9xDP#(f9Z5)VA#fbxcLrOJ8pat5^QbRPVRRho=+s&7b=2#|m| zZ>u#C!PVhbr|+whE9oB%i)lvk>HyPAKh_ycuKZby(cjf?`ll-I@=E zrH?3`5Wx^5zKNJNjek>^_MchaIjQMcb#nYS`=>7#5hId-_pg@;{0DY-1(wU%=U>#n z82|b=|1~a`U;Y8-{U<5kxU)xndp@xF$mk4LH?vDuP3NvY_aV5qQ4Rhqugm`fNI@&~ z^&rlb0002SdQ@0+L}hbha%pgMX>V=-00@~)%Rx%SKoAAceNOS03Nv9q@C4#c9pVtz zJ>5S^K~mLpRYr1qx4!)wsD+IM_XAfp7Y}MCY{Domrg)0&8ACd7YbmpJBb$pUUi!-k zyNk|B4iuw9El{K}uW`WlTCD{{ zgKbTj1-3`sj!9NxNsc?I$fggrU_ls?{$H}CnRrM->Z*C1YqLyu(HS1B{U2@! VS0jWSKIQ-b002ovPDHLkV1k2400;m8 literal 0 HcmV?d00001 diff --git a/lib/pandagl/examples/paint-border/src/main.c b/lib/pandagl/examples/paint-border/src/main.c new file mode 100644 index 000000000..261dd5e01 --- /dev/null +++ b/lib/pandagl/examples/paint-border/src/main.c @@ -0,0 +1,91 @@ +/* + * lib/pandagl/examples/paint-border/src/main.c + * + * Copyright (c) 2023, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include + +int paint_background(pd_context_t* ctx, pd_rect_t* box) +{ + pd_canvas_t image; + pd_color_t green = pd_rgb(102, 204, 0); + pd_background_t bg = { 0 }; + + pd_canvas_init(&image); + if (pd_read_image_from_file("test_image_reader.png", &image) != 0) { + return -1; + } + bg.color = green; + bg.image = ℑ + bg.width = image.width; + bg.height = image.height; + bg.x = (box->width - image.width) / 2; + bg.y = (box->height - image.height) / 2; + pd_paint_background(ctx, &bg, box); + pd_canvas_destroy(&image); + return 0; +} + +void paint_border(pd_context_t* ctx, pd_rect_t* box) +{ + pd_border_t border = { 0 }; + pd_color_t black = pd_rgb(0, 0, 0); + + border.top.color = black; + border.top.style = CSS_KEYWORD_SOLID; + border.top.width = 4; + border.right.color = black; + border.right.style = CSS_KEYWORD_SOLID; + border.right.width = 4; + border.bottom.color = black; + border.bottom.style = CSS_KEYWORD_SOLID; + border.bottom.width = 4; + border.left.color = black; + border.left.style = CSS_KEYWORD_SOLID; + border.left.width = 4; + border.top_left_radius = 32; + border.top_right_radius = 32; + border.bottom_left_radius = 32; + border.bottom_right_radius = 32; + pd_paint_border(ctx, &border, box); +} + +int main(void) +{ + int border_size = 4; + + pd_canvas_t canvas; + pd_canvas_t layer; + pd_color_t gray = pd_rgb(240, 240, 240); + pd_rect_t border_box = { 0, 0, 400, 300 }; + pd_rect_t bg_box = { border_box.x + border_size, + border_box.y + border_size, + border_box.width - border_size * 2, + border_box.height - border_size * 2 }; + pd_rect_t layer_rect = { 0, 0, border_box.width, border_box.height }; + pd_context_t* paint; + + pd_canvas_init(&canvas); + pd_canvas_create(&canvas, 800, 600); + pd_canvas_fill(&canvas, gray); + + pd_canvas_init(&layer); + layer.color_type = PD_COLOR_TYPE_ARGB; + pd_canvas_create(&layer, layer_rect.width, layer_rect.height); + + paint = pd_context_create(&layer, &layer_rect); + paint->with_alpha = true; + paint_background(paint, &bg_box); + paint_border(paint, &border_box); + pd_canvas_mix(&canvas, &layer, (canvas.width - layer_rect.width) / 2, + (canvas.height - layer_rect.height) / 2, false); + pd_write_png_file("test_paint_border.png", &canvas); + pd_canvas_destroy(&canvas); + return 0; +} \ No newline at end of file diff --git a/lib/pandagl/examples/paint-border/xmake.lua b/lib/pandagl/examples/paint-border/xmake.lua new file mode 100644 index 000000000..919f6003d --- /dev/null +++ b/lib/pandagl/examples/paint-border/xmake.lua @@ -0,0 +1,7 @@ +target("paint-border") + set_default(false) + set_kind("binary") + set_rundir("app") + add_deps("pandagl") + add_files("src/*.c") + add_installfiles("app/*") \ No newline at end of file diff --git a/lib/pandagl/examples/paint-boxshadow/app/test_image_reader.png b/lib/pandagl/examples/paint-boxshadow/app/test_image_reader.png new file mode 100644 index 0000000000000000000000000000000000000000..cb3fef4cf844324953cc45f21b479a338cb9c288 GIT binary patch literal 8695 zcmVy!Wh04#7r zK}=$AXLWNRb#7^Na{vGU00000|Nj62W^ZpVVqtOsF)lD=FaS0+E;TbXWiwYmdmI1& z01|UUK}-QMGc-0gMJ+ip05dT(F*ZduSlHFikA^FNzj*b{^&1C0y8`&+Xt>IiFrGR9x&RM` z#d+oH(XeM2U%ICvqn#2u*g>ce|htbC!_xPr2O(10B6Ss zt9kjw&gU;*43^7`d`CX(+??~wd5YZd`1zzWJvmyPPcE61ZZ>ye0IeFU`dWp)cKqK@ zPgb+Z6k`PAb>H;#YFOmgItMUXxbihWdwM!<8b+aApr(PIHEEOOI-^}M_KfCqQXUTX z3>S0P=@*7bWbVTC9go@_cz%5FMxFl!Kx}^w;PB~1=i93JokfJam#fi1&-(TMb>H@d zyX2Fj;VJ@;+f90O&|5j@QIa7d#2cIS)+s$dK3IKnG+doLxZaB=NBz~=4LzMrudqr1 z=}`8KMkFJ|hAKqHGuOFu@Tv1muRLYt`Q&K0>KFOS`^a?e`1GSu`hiG=2sT$MYZaLY zlesehO2MOp-s)f5&)yo`wCnHdhyWQdcY#Y^b2gcCc05|mUDcb;OZrw*RRJZ!LBH@y zG(_+|+^rUXfi)N{TwFS=(O4rGm62t_(bKUxKR)or2+wD((=-r?6h_bjh0QTqD68=L z;DymlT(W@D-o@#p>0VN-+|$l0`feej-DqbH;O>R&$^t&R_R=K$mR)r{tP7bz`+WSpoT z^ox~bg7bkY)I`A7_4s0bhiy3;7Ux$!a5^a&_U!1a)yNp($x(l;2J3y`LBCj4 zp=RGIO6QrBRp(;vI%O3O*Xp}9xNp+GSq82OhzO&8;Y(km$T%AIPUbEghS)H#JWWhC z$c5M`a&^9rKF*I1R#R6^Zw+p;bfoJ#;(U#6SG|dmi%ZAxXmFhVhGAjZvzizq!y;c< zqc^dH00Wy3ZVj%lcMw_$m#(4;5oMXF!R!F;;0ZBLftSZk|kXKKodcUyfSzdru#PMqk{oY zCnYY_tkqz&aCFe~AD>MJ_xCMEU{Y3{^O>VC8s9{$5p)Jf#46ptHTe0|oe1#Z^9i{K z)@ZaAs-~%$CV6}p!pzt8#!Jpz)rk=v4hldJ5eC-q;qzp2Z-$kXkYSbHEKJi-os8!_ zqXl2b8NlP`vySuiW_=z$yXZ_yKhu)2Z*_J5MyPSi`$xcPX=f%ppUurd&z>VNnY+!7 zD625O`MswX^8t6rt>dqGo8vKX*DQ5APc6t#W>Ruv*8#zgJNr z|2aKTk*n9Ti9dXR`W|wAe6T7*4GmbW5rNXx^a{iMpN((L^}S=vW)LVBacYjIWLN2i174q`z;?bXZu77EUK+H7Qd# z3@NuA?pp+yTsk5RN|Nn~L}E-iaADNuM6cyrYy6;R{lkIHecfP<=E-<^ICr=0jnT=b zmz76p%X-pEWOO*N=c9f>h>_FDB|?T0O^9j203zvfKA?m=#B1}jnRvUD=XHowb%O}h zF;cp~zRl?uhPm_j7#UC9;lpe&~B?4W0 zQ3@X-qn@P-fjSBwo?g3(evz*-;G?5Mo}FC~VuO;5L6Ot5h8QFF-;l-jZ9cl+x6gzu zFRU;x>)FTS*=^6fmJq1~*f;vtq|?hts2dLUaxQ&MjNq$)QNq)UIU<5qaQ@NJDp$#N zhdQ=+O-&$qdPwfhRS_2=!y-jeqn=%@Umx`BN~`SrvaIsLDnf{?Cw=F{0i=z(xN(}V ze2uFcB!kdEN(;HUAStI#K-KYEC%zWnM9Mni>PQBtEW;?xrK{){mO){#xhD8#lj_f1 z#o+O2C)OT=@1Gry&Qoj_u}X+B5{X>83g>I85XqI^!~-IN*6EV=@2YMnaz$a(+coZd zJ%eP13ZpnEa*jv)#0Ji$C9Y}+u|`PPL}4{Xbc!A$SS6!}PcJ%GuEK}F!@(ZDj`$Fn zI)CV^hPkhCA?4S@J%iR@P15mt!a8dM`49*(V$^jEedoj{m+mCSNG3@`ld|ID=TpvR zS4bvUl}wk`f=2K@(rX<>VHN$toCEyb>7)~5tVCeApJQ{O3UNGhRmWAKQ@VQA#E4Ns zVGJN-S+Ztz9T5?%QuM9Chuco*jSeWGKn-UTN0Dd5m^6`PDGk&a)D46fXLW2&?icpl z$ABQMZ7w%s7r7c84foI6$oaM36v&@E=zGH?KRak7W$ln>EeHRfSKj_)xpC7%B ztUns|rYe*CY;r}eGD1ulj@H7bmmUH3t-giQ{6V+J*`tFMl0woD;q>D2mS?m|j)y(d z7m*ZAhKN!vK-m^JW>=oxo*BR$pzj|-KD{jYbXwvAd^&YZ%F5h$JOAk6-~`~Tg$<3l z_MGd4*oBCB#e#e*P1{`cKf1p^u9_zATf={Q1=G0xVUX5^zX~CYde(zbhe#D_v}Bua zg~+XhxODZc?|v&y`zpB7*SXaha~IxP0u3>e2~3^e?8{NluCz`eZqMKRq6; zLJZWg!Pk*}YnaR(bpsCv79Uc=HMw%tcyzc)zWV1c)KOJ`-KAUtRV2$RYop6Ye@!YXz6|sTA zUYAp985Rp}>d8CwH(D1n@DEi3n z^=v*J7Wrz_FIIcTOhaG;D`YqFh}R}vhcub}J%!dOQ%)-o$W4axH4WFfNT?gKOn5q; z5@W-j(OiD=XtPb$yoowSBop?n!Ke(ak}-TZDEzRnt3hGTjmr9v5o1JJr*v6*VgtE) zOD)vZ;S9k0lu9+N#zSn#ZhTHjdQY;9rinD9Bo!L!0R6)D0j_*H+*$;iXQ@~vf(v!B z$HWcQ1i1A&0NWK7G7D<8-N zE>0dz0kkA?fDjQ9IVMR)9a2Vr6Los^iZQu%=if5vwPSL1q;A?6Ac7AKJ*#oPL1nOK z6k0US*N8xj4N42M(m|}boR^#&9Zap!uXQ4QS;42I3WXaW0_yG z9?pkpCT)ftujw5|Wt2XWn+)r8o4Kbc=u8Nqq4G7k(oCTWDlsVIq;uA9rawM5-nxYhl`AUj&BMqBP9Q8f#SIy1b$wB^i;(ilgiC7=8wENP(uEm(lL3yJ2t6y zuXS?8Rftp}kSoFDY6JfJ7~LBuZF5EGYD^|vI!}y=u9q|$Tdk%gj4`&L`L#WDzTSAn z()qD5k_ZUaY{JtB)$>`|nLA&tfqtvhX4~Z|jn$;6f{VF(8e2^8&PmT*pl6er5)q0# zx!}Smbe3pv=>Q6+ld@y-WNno|-9&td)Ad--Cgq`!Ox8`uasB?>#HOigz?zJGt0{7Y z)f%f58E`teI=or8d_#$YS?MD^Yc?5$)oJPLmLVa)vx~WbWWIEkB0{SbA>Iyv9-mDI zv4MSS?j*22em*nL#Rwqr{dhdWY7?jrdnp;%Gdgh?oqr?r`|mD(=a}Kdh!0$n%_b0oV3yUkQfQ=?$DWVe(4Txa)1ElE{tC-{C^kn+NAqM ze)8y`IF1pV_p|Y(J9(7>^+zXn(RcnVf0jSXx0PJU=s~~mkA}thH+}Yxrtx(XY?XpL4vbdig>8@!5dtfgnwd6ApZuxDHDY9urbr4PiI zP{v&J2G(5z?U6{Vuc6=@_rlb9BujR`e1j?ZPL=&=*qaUu(^oANR>w%?8?+Wq9t_VX zb2t0h8~R0F6S-N^7OD`iEh%{F{L{M>twct{!kmi;hXafAkv*gFA#zzJzqYO_ua#Uk zEjK(uD&AxpT<0c|7Gk9IH9cz%f3M2UmGrfU=~+Fvzi%J5Kb>DWUxmnYa^+6$`oU+D z`QUUi&xbubS0edv&yeekx=tA6uxI;PiGMPl^zH==MlytJ1WnonaCJTQA)JKB?BdN91bBn8 zl}K)s40={S+%sx)a|x|Z^#C6tv1xEVbs6L;*##HksL1t*7DF9R-FPy0kJjKsgzBR0 z7_LHnJ{sfIFkShE++?YvB2`#t-p5-&%Y(i>AMDwYT^AGEMXF-M z*{9{de`rN8~Mi2ugKMCG%U__wl2$obM=OY)ZEwzRY)}a;l4#F!B>IM zeqibEj3<1H9lPG3!#(rR3I`I zWoVLT-?!#ODM4wdV-rCZ z)(~Q94nb0lHMC5T!ltIi<_7P*YU1&mA{R)GRRn8|dYnO?E6x4=#Cobj#I$L=kZN&N zhZ{8J2FZmA>v6*BR6+-(^hZR(zD>}RD8B3qi0j+O^k3AlG0_} zE7LX%W?AHPGH1A#THt($m|UT9$xn|*{@KOsa58tdZXndrsZ8>9D{~?-wd)m|c1l93 zBxDdFGl?0vXB1a1pfVX0xq2*_478BTjq3NBR!G*LD+vI9f z3tY=PrRyKu(?8uoikBfG*%n^|aS_ROge+So$CD*95|&@FSVnfYxB0+mmYojOi&U5X z&5H#hu)`K+H#w|s7q+@xUPf5P2+Jk^_PJ+C#O&@6BmBTCyqZbi1%vEcu%F zljU+*nC)zv?$)h)?{;s#-eL)KmupsK+O09d2X>dZh=h8{?oO9~{#E%8uj=ug7?ZB5 z&kCz4tlq5hHIWPInhjGX5d<`KNZm+UNL;C=!G{`G)ws}bS*FH{HHFja6mFGOIxeNF znO^$jBYcf%2?zK4y<`9BCz~fQtey7y^_nPYl-_i*Cl*A@`Dqg&eIvDBe|K{(Tbk)6 zzP|CA8=qVMm#YIIv`tYo_;_~{_B$y%HtFU|SEr+tWoQkFMG`m3g-D`5RV}Gk0Oy-T z=&b^=S@XH#hUKF^;?I**ZvbB@}({Oac)t%^MFhY-)KNz4o_ z8JAZM?`!h*`9n7^NakasteBWgxl&~9lC5zNB`M|>mFO#K&Eet3CD(m+zK-NdP?;vw zk;8$##d?KzG$T9PqKTb69m?QXH4p;^L~WbAHl@#7D2_U~!jiyFS}z}6Q2MPyq#>}sJ) z7roPkWtZg=7I9hK+uqrJxmZw#$W|9(T&4v9eqeU)olQO)mQ_8w|6j~czgjGaOMoT! zc6WZVv)$$MFJI7=EtV}4XIF&(_1Whv=@6H#?QO5^?JiqO&^qIbu)u70S<Te zTkW-6zOIWbgRLcOW!Im}wqP5fyVXH&3tGhO%F{}Jh5|EjgOvPm`ns8 z0;Zi`|_r_tZ9acbC8YVd_EdF1OG-!ad#P zSD$(QrTmgFLj;!iMZ<4nhwW|x-?z4siJ-fL<#O@Y_jb2+wnga|$v*A~FY6SYd|(t> zwscvAU&JMg@vlGs$DUPxlWk@9%yyTTbwp)b{OE&wIKN<5!%jEj?BB}6|5Js3SS;c{ z{pbVpKkn^j+sogA&?UsLu|{)G2_Y`YvM$RmxN1RMF4@hxhzQ#P(uEM0tT(yLvgCbN5ei$>P10ZFYC={q5l1PdeQtFJCmgSVVsFa=~X`yyP=q z@vE}p#Uk>VtGFn?z%LdomrHiKTXehd1HFTEyDXMVmMqab+mK8M(v|J33p?2sFBg%m ztuBi?vMs{y?l#*3i%9Xoy`8@=zf44?UzOEqTrPKhWOoNI7b#49v55TWgIyMN2cx%{ zfBwa+TEub*i_fd@wEQys<03A9`NMnqeplEozX<%$?()?FcDErcIut(;mUO9?OBTxo z9l*U4d2_z_`c3?FBf#_@-lwKS8+)d0wKb^?PR;ZuXk9oBnFb=ce?CkUG&yA zaT(d#f?d5$r;~QWqIFS&37t+d{$Y_Ig%^uR=j$ck+Z6`IJ(gcD>2AS}bouAWzd!!fAVlJU6-C*T{9_t`#6FG0u}k1+a8JGx@!(@V<>CeSCh=&^vXXjjOO96I9d1T zWbGr4gcQf>OgNw3T@VlO@qlYV$;kXKc9UgJ}!`-91Xn|p^g#XH0d1x!oRL7bhQw7bOd=xNmLB`*r5it=-Tm05cgC|_2s4BYGPiFHF2v2_HeyVr zBxyOfqNU~G%BGBzo~xA}_olT#9jeo|(J4az2ofQ<3Y%Crk&%VEiPf9%ix^WM{>g*> zRLJ`4N24j7*>}0O$huV?Mm>8n*w2qs%&&>SzDZAKuqGjs2fc(cmc9l7=fdpCcsBYb z4F0_ezDNDy{9s^5B7$>)dFAmwZgy~LkGQVY(UR`7_L%`8#`V9|`P7YGRo>4ZrKYTT z=}Fa`l%-lDT+IE`xvO4F6ke5so;?}v=f^ZqSi{4oWAjZ)c#|k09~SnpP6?9Tx5`Y* zYC8Az`M052zE`D2G8{1_3&sd!1|en6>jr_FiY7}(EoE0AQJ6bFzDa)Fj4kA$ecX|> z3scvLKH36?`BHA3wf`dUDwfBl~_Pl33--r)m(RwSfh~E&Q>9j<*N{xT)M-% z9xDP#(f9Z5)VA#fbxcLrOJ8pat5^QbRPVRRho=+s&7b=2#|m| zZ>u#C!PVhbr|+whE9oB%i)lvk>HyPAKh_ycuKZby(cjf?`ll-I@=E zrH?3`5Wx^5zKNJNjek>^_MchaIjQMcb#nYS`=>7#5hId-_pg@;{0DY-1(wU%=U>#n z82|b=|1~a`U;Y8-{U<5kxU)xndp@xF$mk4LH?vDuP3NvY_aV5qQ4Rhqugm`fNI@&~ z^&rlb0002SdQ@0+L}hbha%pgMX>V=-00@~)%Rx%SKoAAceNOS03Nv9q@C4#c9pVtz zJ>5S^K~mLpRYr1qx4!)wsD+IM_XAfp7Y}MCY{Domrg)0&8ACd7YbmpJBb$pUUi!-k zyNk|B4iuw9El{K}uW`WlTCD{{ zgKbTj1-3`sj!9NxNsc?I$fggrU_ls?{$H}CnRrM->Z*C1YqLyu(HS1B{U2@! VS0jWSKIQ-b002ovPDHLkV1k2400;m8 literal 0 HcmV?d00001 diff --git a/lib/pandagl/examples/paint-boxshadow/src/main.c b/lib/pandagl/examples/paint-boxshadow/src/main.c new file mode 100644 index 000000000..148a96a50 --- /dev/null +++ b/lib/pandagl/examples/paint-boxshadow/src/main.c @@ -0,0 +1,121 @@ +/* + * lib/pandagl/examples/paint-boxshadow/src/main.c + * + * Copyright (c) 2023, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include + +int paint_background(pd_context_t* ctx, pd_rect_t* box) +{ + pd_canvas_t image; + pd_color_t green = pd_rgb(102, 204, 0); + pd_background_t bg = { 0 }; + + pd_canvas_init(&image); + if (pd_read_image_from_file("test_image_reader.png", &image) != 0) { + return -1; + } + bg.color = green; + bg.image = ℑ + bg.width = image.width; + bg.height = image.height; + bg.x = (box->width - image.width) / 2; + bg.y = (box->height - image.height) / 2; + pd_paint_background(ctx, &bg, box); + pd_canvas_destroy(&image); + return 0; +} + +void paint_border(pd_context_t* ctx, pd_rect_t* box, int size, int radius) +{ + pd_border_t border = { 0 }; + pd_color_t black = pd_rgb(0, 0, 0); + + border.top.color = black; + border.top.style = CSS_KEYWORD_SOLID; + border.top.width = size; + border.right.color = black; + border.right.style = CSS_KEYWORD_SOLID; + border.right.width = size; + border.bottom.color = black; + border.bottom.style = CSS_KEYWORD_SOLID; + border.bottom.width = size; + border.left.color = black; + border.left.style = CSS_KEYWORD_SOLID; + border.left.width = size; + border.top_left_radius = radius; + border.top_right_radius = radius; + border.bottom_left_radius = radius; + border.bottom_right_radius = radius; + pd_paint_border(ctx, &border, box); +} + +int main(void) +{ + int border_size = 4; + int border_radius = 32; + int width = 800; + int height = 600; + + pd_canvas_t canvas; + pd_canvas_t layer; + pd_color_t gray = pd_rgb(240, 240, 240); + pd_boxshadow_t shadow = { .x = 0, + .y = 0, + .blur = 40, + .spread = 0, + .color = pd_argb(150, 0, 0, 0), + .top_left_radius = border_radius, + .top_right_radius = border_radius, + .bottom_left_radius = border_radius, + .bottom_right_radius = border_radius }; + pd_rect_t shadow_box; + pd_rect_t border_box; + pd_rect_t bg_box; + pd_rect_t layer_rect; + pd_context_t* ctx; + + pd_canvas_init(&canvas); + pd_canvas_create(&canvas, width, height); + pd_canvas_fill(&canvas, gray); + + bg_box.width = 400; + bg_box.height = 300; + bg_box.x = (width - bg_box.width) / 2; + bg_box.y = (height - bg_box.height) / 2; + border_box.x = bg_box.x - border_size; + border_box.y = bg_box.y - border_size; + border_box.width = bg_box.width + border_size * 2; + border_box.height = bg_box.height + border_size * 2; + pd_get_boxshadow_canvas_rect(&shadow, &border_box, &shadow_box); + + pd_canvas_init(&layer); + layer_rect.x = 0; + layer_rect.y = 0; + layer_rect.width = shadow_box.width; + layer_rect.height = shadow_box.height; + layer.color_type = PD_COLOR_TYPE_ARGB; + pd_canvas_create(&layer, layer_rect.width, layer_rect.height); + + ctx = pd_context_create(&layer, &layer_rect); + ctx->with_alpha = true; + bg_box.x -= shadow_box.x; + bg_box.y -= shadow_box.y; + border_box.x -= shadow_box.x; + border_box.y -= shadow_box.y; + paint_background(ctx, &bg_box); + paint_border(ctx, &border_box, border_size, border_radius); + pd_paint_boxshadow(ctx, &shadow, &layer_rect, border_box.width, + border_box.height); + + pd_canvas_mix(&canvas, &layer, shadow_box.x, shadow_box.y, false); + pd_write_png_file("test_paint_boxshadow.png", &canvas); + pd_canvas_destroy(&canvas); + return 0; +} \ No newline at end of file diff --git a/lib/pandagl/examples/paint-boxshadow/xmake.lua b/lib/pandagl/examples/paint-boxshadow/xmake.lua new file mode 100644 index 000000000..934c63000 --- /dev/null +++ b/lib/pandagl/examples/paint-boxshadow/xmake.lua @@ -0,0 +1,7 @@ +target("paint-boxshadow") + set_default(false) + set_kind("binary") + set_rundir("app") + add_deps("pandagl") + add_files("src/*.c") + add_installfiles("app/*") \ No newline at end of file diff --git a/tests/dog.jpg b/lib/pandagl/examples/pixel-manipulation/app/dog.jpg similarity index 100% rename from tests/dog.jpg rename to lib/pandagl/examples/pixel-manipulation/app/dog.jpg diff --git a/lib/pandagl/examples/pixel-manipulation/src/main.c b/lib/pandagl/examples/pixel-manipulation/src/main.c new file mode 100644 index 000000000..b4535e698 --- /dev/null +++ b/lib/pandagl/examples/pixel-manipulation/src/main.c @@ -0,0 +1,85 @@ +/* + * lib/pandagl/examples/pixel-manipulation/src/main.c + * + * Copyright (c) 2023, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include + +#define PixelManipulationBegin \ + int x, y; \ + pd_color_t pixel; \ + \ + for (y = rect.y; y < rect.y + rect.height; ++y) { \ + for (x = rect.x; x < rect.x + rect.width; ++x) { \ + pixel = pd_canvas_get_pixel(graph, x, y); + +#define PixelManipulationEnd \ + pd_canvas_set_pixel(graph, x, y, pixel); \ + } \ + } + +void invert(pd_canvas_t *graph, pd_rect_t rect) +{ + PixelManipulationBegin; + pixel.red = (unsigned char)(255 - pixel.red); + pixel.green = (unsigned char)(255 - pixel.green); + pixel.blue = (unsigned char)(255 - pixel.blue); + PixelManipulationEnd; +} + +void grayscale(pd_canvas_t *graph, pd_rect_t rect) +{ + unsigned char avg; + + PixelManipulationBegin; + avg = (unsigned char)((pixel.red + pixel.green + pixel.blue) / 3); + pixel.red = avg; + pixel.green = avg; + pixel.blue = avg; + PixelManipulationEnd; +} + +void sepia(pd_canvas_t *graph, pd_rect_t rect) +{ + PixelManipulationBegin; + pixel.red = (unsigned char)y_min( + round(0.393 * pixel.red + 0.769 * pixel.green + 0.189 * pixel.blue), + 255); + pixel.green = (unsigned char)y_min( + round(0.349 * pixel.red + 0.686 * pixel.green + 0.168 * pixel.blue), + 255); + pixel.blue = (unsigned char)y_min( + round(0.272 * pixel.red + 0.534 * pixel.green + 0.131 * pixel.blue), + 255); + PixelManipulationEnd; +} + +int main(void) +{ + int i; + pd_canvas_t graph = { 0 }; + pd_rect_t rects[4]; + + if (pd_read_image_from_file("dog.jpg", &graph) != 0) { + return -1; + } + for (i = 0; i < 4; ++i) { + rects[i].height = graph.height; + rects[i].width = graph.width / 4; + rects[i].x = i * rects[i].width; + rects[i].y = 0; + } + sepia(&graph, rects[1]); + grayscale(&graph, rects[2]); + invert(&graph, rects[3]); + pd_write_png_file("test_pixel_manipulation.png", &graph); + return 0; +} \ No newline at end of file diff --git a/lib/pandagl/examples/pixel-manipulation/xmake.lua b/lib/pandagl/examples/pixel-manipulation/xmake.lua new file mode 100644 index 000000000..34c0ef937 --- /dev/null +++ b/lib/pandagl/examples/pixel-manipulation/xmake.lua @@ -0,0 +1,7 @@ +target("pixel-manipulation") + set_default(false) + set_kind("binary") + set_rundir("app") + add_deps("pandagl", "yutil") + add_files("src/*.c") + add_installfiles("app/*") \ No newline at end of file diff --git a/lib/pandagl/examples/string-render/src/main.c b/lib/pandagl/examples/string-render/src/main.c new file mode 100644 index 000000000..b0474aa12 --- /dev/null +++ b/lib/pandagl/examples/string-render/src/main.c @@ -0,0 +1,45 @@ +/* + * lib/pandagl/examples/string-render/src/main.c + * + * Copyright (c) 2023, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include + +int main(void) +{ + int ret; + pd_canvas_t img; + pd_pos_t pos = { 0, 80 }; + pd_rect_t area = { 0, 0, 320, 240 }; + pd_text_t* txt = pd_text_create(); + pd_text_style_t txtstyle; + + pd_font_library_init(); + + pd_canvas_init(&img); + pd_canvas_create(&img, 320, 240); + pd_canvas_fill(&img, pd_rgb(240, 240, 240)); + + pd_text_style_Init(&txtstyle); + txtstyle.pixel_size = 24; + txtstyle.has_pixel_size = true; + + pd_text_set_fixed_size(txt, 320, 240); + pd_text_set_style(txt, &txtstyle); + pd_text_set_align(txt, PD_TEXT_ALIGN_CENTER); + pd_text_write(txt, L"这是一段测试文本\nHello, World!", NULL); + pd_text_update(txt, NULL); + + pd_text_render_to(txt, area, pos, &img); + ret = pd_write_png_file("test_string_render.png", &img); + pd_canvas_destroy(&img); + + pd_font_library_destroy(); + return ret; +} \ No newline at end of file diff --git a/lib/pandagl/examples/string-render/xmake.lua b/lib/pandagl/examples/string-render/xmake.lua new file mode 100644 index 000000000..2ad5cf7f2 --- /dev/null +++ b/lib/pandagl/examples/string-render/xmake.lua @@ -0,0 +1,7 @@ +target("string-render") + set_default(false) + set_kind("binary") + set_rundir("app") + add_deps("pandagl") + add_files("src/*.c") + add_installfiles("app/*") \ No newline at end of file diff --git a/lib/pandagl/test/test.c b/lib/pandagl/test/test.c deleted file mode 100644 index 8b5f57ed9..000000000 --- a/lib/pandagl/test/test.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - * lib/pandagl/test/test.c - * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include "test.h" -#include "ctest.h" - -int main() -{ - ctest_describe("test_canvas_mix", test_canvas_mix); - return ctest_finish(); -} diff --git a/lib/pandagl/test/test.h b/lib/pandagl/test/test.h deleted file mode 100644 index 33aaef077..000000000 --- a/lib/pandagl/test/test.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * lib/pandagl/test/test.h - * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -void test_canvas_mix(void); diff --git a/lib/pandagl/test/test_canvas_mix.c b/lib/pandagl/test/test_canvas_mix.c deleted file mode 100644 index 595046ed2..000000000 --- a/lib/pandagl/test/test_canvas_mix.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * lib/pandagl/test/test_canvas_mix.c - * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include "test.h" -#include "ctest.h" -#include - -int color2str(char *str, const pd_color_t *color) -{ - return sprintf(str, "rgba(%d, %d, %d, %g)", color->r, color->g, - color->b, color->a / 255.f); -} - -void test_canvas_mix(void) -{ - char rgba_str[64]; - pd_color_t *pixel; - pd_color_t white = pd_rgb(255, 255, 255); - pd_color_t red = pd_rgb(255, 0, 0); - pd_color_t blue = pd_argb(204, 0, 0, 255); - pd_canvas_t white_layer; - pd_canvas_t red_layer; - pd_canvas_t blue_layer; - - pd_canvas_init(&white_layer); - white_layer.color_type = PD_COLOR_TYPE_ARGB; - pd_canvas_create(&white_layer, 100, 100); - pd_canvas_fill(&white_layer, white); - - pd_canvas_init(&red_layer); - red_layer.color_type = PD_COLOR_TYPE_ARGB; - red_layer.opacity = 0.5; - pd_canvas_create(&red_layer, 80, 80); - pd_canvas_fill(&red_layer, red); - - pd_canvas_init(&blue_layer); - blue_layer.color_type = PD_COLOR_TYPE_ARGB; - pd_canvas_create(&blue_layer, 60, 60); - pd_canvas_fill(&blue_layer, blue); - - pd_canvas_mix(&red_layer, &blue_layer, 10, 10, true); - pixel = pd_canvas_pixel_at(&red_layer, 15, 15); - color2str(rgba_str, pixel); - ctest_equal_str("red_layer(15, 15)", rgba_str, "rgba(50, 0, 204, 1)"); - - pd_canvas_mix(&white_layer, &red_layer, 10, 10, true); - pixel = pd_canvas_pixel_at(&white_layer, 0, 0); - color2str(rgba_str, pixel); - ctest_equal_str("white_layer(0, 0)", rgba_str, "rgba(255, 255, 255, 1)"); - - pixel = pd_canvas_pixel_at(&white_layer, 15, 15); - color2str(rgba_str, pixel); - ctest_equal_str("white_layer(15, 15)", rgba_str, "rgba(255, 127, 127, 1)"); - - pixel = pd_canvas_pixel_at(&white_layer, 25, 25); - color2str(rgba_str, pixel); - ctest_equal_str("white_layer(25, 25)", rgba_str, "rgba(152, 127, 229, 1)"); - - pd_canvas_destroy(&white_layer); - pd_canvas_destroy(&red_layer); - pd_canvas_destroy(&blue_layer); -} diff --git a/tests/test_font_load.ttf b/lib/pandagl/tests/fixtures/test_font_load.ttf similarity index 100% rename from tests/test_font_load.ttf rename to lib/pandagl/tests/fixtures/test_font_load.ttf diff --git a/tests/test_image_reader.bmp b/lib/pandagl/tests/fixtures/test_image_reader.bmp similarity index 100% rename from tests/test_image_reader.bmp rename to lib/pandagl/tests/fixtures/test_image_reader.bmp diff --git a/tests/test_image_reader.jpg b/lib/pandagl/tests/fixtures/test_image_reader.jpg similarity index 100% rename from tests/test_image_reader.jpg rename to lib/pandagl/tests/fixtures/test_image_reader.jpg diff --git a/lib/pandagl/tests/fixtures/test_image_reader.png b/lib/pandagl/tests/fixtures/test_image_reader.png new file mode 100644 index 0000000000000000000000000000000000000000..cb3fef4cf844324953cc45f21b479a338cb9c288 GIT binary patch literal 8695 zcmVy!Wh04#7r zK}=$AXLWNRb#7^Na{vGU00000|Nj62W^ZpVVqtOsF)lD=FaS0+E;TbXWiwYmdmI1& z01|UUK}-QMGc-0gMJ+ip05dT(F*ZduSlHFikA^FNzj*b{^&1C0y8`&+Xt>IiFrGR9x&RM` z#d+oH(XeM2U%ICvqn#2u*g>ce|htbC!_xPr2O(10B6Ss zt9kjw&gU;*43^7`d`CX(+??~wd5YZd`1zzWJvmyPPcE61ZZ>ye0IeFU`dWp)cKqK@ zPgb+Z6k`PAb>H;#YFOmgItMUXxbihWdwM!<8b+aApr(PIHEEOOI-^}M_KfCqQXUTX z3>S0P=@*7bWbVTC9go@_cz%5FMxFl!Kx}^w;PB~1=i93JokfJam#fi1&-(TMb>H@d zyX2Fj;VJ@;+f90O&|5j@QIa7d#2cIS)+s$dK3IKnG+doLxZaB=NBz~=4LzMrudqr1 z=}`8KMkFJ|hAKqHGuOFu@Tv1muRLYt`Q&K0>KFOS`^a?e`1GSu`hiG=2sT$MYZaLY zlesehO2MOp-s)f5&)yo`wCnHdhyWQdcY#Y^b2gcCc05|mUDcb;OZrw*RRJZ!LBH@y zG(_+|+^rUXfi)N{TwFS=(O4rGm62t_(bKUxKR)or2+wD((=-r?6h_bjh0QTqD68=L z;DymlT(W@D-o@#p>0VN-+|$l0`feej-DqbH;O>R&$^t&R_R=K$mR)r{tP7bz`+WSpoT z^ox~bg7bkY)I`A7_4s0bhiy3;7Ux$!a5^a&_U!1a)yNp($x(l;2J3y`LBCj4 zp=RGIO6QrBRp(;vI%O3O*Xp}9xNp+GSq82OhzO&8;Y(km$T%AIPUbEghS)H#JWWhC z$c5M`a&^9rKF*I1R#R6^Zw+p;bfoJ#;(U#6SG|dmi%ZAxXmFhVhGAjZvzizq!y;c< zqc^dH00Wy3ZVj%lcMw_$m#(4;5oMXF!R!F;;0ZBLftSZk|kXKKodcUyfSzdru#PMqk{oY zCnYY_tkqz&aCFe~AD>MJ_xCMEU{Y3{^O>VC8s9{$5p)Jf#46ptHTe0|oe1#Z^9i{K z)@ZaAs-~%$CV6}p!pzt8#!Jpz)rk=v4hldJ5eC-q;qzp2Z-$kXkYSbHEKJi-os8!_ zqXl2b8NlP`vySuiW_=z$yXZ_yKhu)2Z*_J5MyPSi`$xcPX=f%ppUurd&z>VNnY+!7 zD625O`MswX^8t6rt>dqGo8vKX*DQ5APc6t#W>Ruv*8#zgJNr z|2aKTk*n9Ti9dXR`W|wAe6T7*4GmbW5rNXx^a{iMpN((L^}S=vW)LVBacYjIWLN2i174q`z;?bXZu77EUK+H7Qd# z3@NuA?pp+yTsk5RN|Nn~L}E-iaADNuM6cyrYy6;R{lkIHecfP<=E-<^ICr=0jnT=b zmz76p%X-pEWOO*N=c9f>h>_FDB|?T0O^9j203zvfKA?m=#B1}jnRvUD=XHowb%O}h zF;cp~zRl?uhPm_j7#UC9;lpe&~B?4W0 zQ3@X-qn@P-fjSBwo?g3(evz*-;G?5Mo}FC~VuO;5L6Ot5h8QFF-;l-jZ9cl+x6gzu zFRU;x>)FTS*=^6fmJq1~*f;vtq|?hts2dLUaxQ&MjNq$)QNq)UIU<5qaQ@NJDp$#N zhdQ=+O-&$qdPwfhRS_2=!y-jeqn=%@Umx`BN~`SrvaIsLDnf{?Cw=F{0i=z(xN(}V ze2uFcB!kdEN(;HUAStI#K-KYEC%zWnM9Mni>PQBtEW;?xrK{){mO){#xhD8#lj_f1 z#o+O2C)OT=@1Gry&Qoj_u}X+B5{X>83g>I85XqI^!~-IN*6EV=@2YMnaz$a(+coZd zJ%eP13ZpnEa*jv)#0Ji$C9Y}+u|`PPL}4{Xbc!A$SS6!}PcJ%GuEK}F!@(ZDj`$Fn zI)CV^hPkhCA?4S@J%iR@P15mt!a8dM`49*(V$^jEedoj{m+mCSNG3@`ld|ID=TpvR zS4bvUl}wk`f=2K@(rX<>VHN$toCEyb>7)~5tVCeApJQ{O3UNGhRmWAKQ@VQA#E4Ns zVGJN-S+Ztz9T5?%QuM9Chuco*jSeWGKn-UTN0Dd5m^6`PDGk&a)D46fXLW2&?icpl z$ABQMZ7w%s7r7c84foI6$oaM36v&@E=zGH?KRak7W$ln>EeHRfSKj_)xpC7%B ztUns|rYe*CY;r}eGD1ulj@H7bmmUH3t-giQ{6V+J*`tFMl0woD;q>D2mS?m|j)y(d z7m*ZAhKN!vK-m^JW>=oxo*BR$pzj|-KD{jYbXwvAd^&YZ%F5h$JOAk6-~`~Tg$<3l z_MGd4*oBCB#e#e*P1{`cKf1p^u9_zATf={Q1=G0xVUX5^zX~CYde(zbhe#D_v}Bua zg~+XhxODZc?|v&y`zpB7*SXaha~IxP0u3>e2~3^e?8{NluCz`eZqMKRq6; zLJZWg!Pk*}YnaR(bpsCv79Uc=HMw%tcyzc)zWV1c)KOJ`-KAUtRV2$RYop6Ye@!YXz6|sTA zUYAp985Rp}>d8CwH(D1n@DEi3n z^=v*J7Wrz_FIIcTOhaG;D`YqFh}R}vhcub}J%!dOQ%)-o$W4axH4WFfNT?gKOn5q; z5@W-j(OiD=XtPb$yoowSBop?n!Ke(ak}-TZDEzRnt3hGTjmr9v5o1JJr*v6*VgtE) zOD)vZ;S9k0lu9+N#zSn#ZhTHjdQY;9rinD9Bo!L!0R6)D0j_*H+*$;iXQ@~vf(v!B z$HWcQ1i1A&0NWK7G7D<8-N zE>0dz0kkA?fDjQ9IVMR)9a2Vr6Los^iZQu%=if5vwPSL1q;A?6Ac7AKJ*#oPL1nOK z6k0US*N8xj4N42M(m|}boR^#&9Zap!uXQ4QS;42I3WXaW0_yG z9?pkpCT)ftujw5|Wt2XWn+)r8o4Kbc=u8Nqq4G7k(oCTWDlsVIq;uA9rawM5-nxYhl`AUj&BMqBP9Q8f#SIy1b$wB^i;(ilgiC7=8wENP(uEm(lL3yJ2t6y zuXS?8Rftp}kSoFDY6JfJ7~LBuZF5EGYD^|vI!}y=u9q|$Tdk%gj4`&L`L#WDzTSAn z()qD5k_ZUaY{JtB)$>`|nLA&tfqtvhX4~Z|jn$;6f{VF(8e2^8&PmT*pl6er5)q0# zx!}Smbe3pv=>Q6+ld@y-WNno|-9&td)Ad--Cgq`!Ox8`uasB?>#HOigz?zJGt0{7Y z)f%f58E`teI=or8d_#$YS?MD^Yc?5$)oJPLmLVa)vx~WbWWIEkB0{SbA>Iyv9-mDI zv4MSS?j*22em*nL#Rwqr{dhdWY7?jrdnp;%Gdgh?oqr?r`|mD(=a}Kdh!0$n%_b0oV3yUkQfQ=?$DWVe(4Txa)1ElE{tC-{C^kn+NAqM ze)8y`IF1pV_p|Y(J9(7>^+zXn(RcnVf0jSXx0PJU=s~~mkA}thH+}Yxrtx(XY?XpL4vbdig>8@!5dtfgnwd6ApZuxDHDY9urbr4PiI zP{v&J2G(5z?U6{Vuc6=@_rlb9BujR`e1j?ZPL=&=*qaUu(^oANR>w%?8?+Wq9t_VX zb2t0h8~R0F6S-N^7OD`iEh%{F{L{M>twct{!kmi;hXafAkv*gFA#zzJzqYO_ua#Uk zEjK(uD&AxpT<0c|7Gk9IH9cz%f3M2UmGrfU=~+Fvzi%J5Kb>DWUxmnYa^+6$`oU+D z`QUUi&xbubS0edv&yeekx=tA6uxI;PiGMPl^zH==MlytJ1WnonaCJTQA)JKB?BdN91bBn8 zl}K)s40={S+%sx)a|x|Z^#C6tv1xEVbs6L;*##HksL1t*7DF9R-FPy0kJjKsgzBR0 z7_LHnJ{sfIFkShE++?YvB2`#t-p5-&%Y(i>AMDwYT^AGEMXF-M z*{9{de`rN8~Mi2ugKMCG%U__wl2$obM=OY)ZEwzRY)}a;l4#F!B>IM zeqibEj3<1H9lPG3!#(rR3I`I zWoVLT-?!#ODM4wdV-rCZ z)(~Q94nb0lHMC5T!ltIi<_7P*YU1&mA{R)GRRn8|dYnO?E6x4=#Cobj#I$L=kZN&N zhZ{8J2FZmA>v6*BR6+-(^hZR(zD>}RD8B3qi0j+O^k3AlG0_} zE7LX%W?AHPGH1A#THt($m|UT9$xn|*{@KOsa58tdZXndrsZ8>9D{~?-wd)m|c1l93 zBxDdFGl?0vXB1a1pfVX0xq2*_478BTjq3NBR!G*LD+vI9f z3tY=PrRyKu(?8uoikBfG*%n^|aS_ROge+So$CD*95|&@FSVnfYxB0+mmYojOi&U5X z&5H#hu)`K+H#w|s7q+@xUPf5P2+Jk^_PJ+C#O&@6BmBTCyqZbi1%vEcu%F zljU+*nC)zv?$)h)?{;s#-eL)KmupsK+O09d2X>dZh=h8{?oO9~{#E%8uj=ug7?ZB5 z&kCz4tlq5hHIWPInhjGX5d<`KNZm+UNL;C=!G{`G)ws}bS*FH{HHFja6mFGOIxeNF znO^$jBYcf%2?zK4y<`9BCz~fQtey7y^_nPYl-_i*Cl*A@`Dqg&eIvDBe|K{(Tbk)6 zzP|CA8=qVMm#YIIv`tYo_;_~{_B$y%HtFU|SEr+tWoQkFMG`m3g-D`5RV}Gk0Oy-T z=&b^=S@XH#hUKF^;?I**ZvbB@}({Oac)t%^MFhY-)KNz4o_ z8JAZM?`!h*`9n7^NakasteBWgxl&~9lC5zNB`M|>mFO#K&Eet3CD(m+zK-NdP?;vw zk;8$##d?KzG$T9PqKTb69m?QXH4p;^L~WbAHl@#7D2_U~!jiyFS}z}6Q2MPyq#>}sJ) z7roPkWtZg=7I9hK+uqrJxmZw#$W|9(T&4v9eqeU)olQO)mQ_8w|6j~czgjGaOMoT! zc6WZVv)$$MFJI7=EtV}4XIF&(_1Whv=@6H#?QO5^?JiqO&^qIbu)u70S<Te zTkW-6zOIWbgRLcOW!Im}wqP5fyVXH&3tGhO%F{}Jh5|EjgOvPm`ns8 z0;Zi`|_r_tZ9acbC8YVd_EdF1OG-!ad#P zSD$(QrTmgFLj;!iMZ<4nhwW|x-?z4siJ-fL<#O@Y_jb2+wnga|$v*A~FY6SYd|(t> zwscvAU&JMg@vlGs$DUPxlWk@9%yyTTbwp)b{OE&wIKN<5!%jEj?BB}6|5Js3SS;c{ z{pbVpKkn^j+sogA&?UsLu|{)G2_Y`YvM$RmxN1RMF4@hxhzQ#P(uEM0tT(yLvgCbN5ei$>P10ZFYC={q5l1PdeQtFJCmgSVVsFa=~X`yyP=q z@vE}p#Uk>VtGFn?z%LdomrHiKTXehd1HFTEyDXMVmMqab+mK8M(v|J33p?2sFBg%m ztuBi?vMs{y?l#*3i%9Xoy`8@=zf44?UzOEqTrPKhWOoNI7b#49v55TWgIyMN2cx%{ zfBwa+TEub*i_fd@wEQys<03A9`NMnqeplEozX<%$?()?FcDErcIut(;mUO9?OBTxo z9l*U4d2_z_`c3?FBf#_@-lwKS8+)d0wKb^?PR;ZuXk9oBnFb=ce?CkUG&yA zaT(d#f?d5$r;~QWqIFS&37t+d{$Y_Ig%^uR=j$ck+Z6`IJ(gcD>2AS}bouAWzd!!fAVlJU6-C*T{9_t`#6FG0u}k1+a8JGx@!(@V<>CeSCh=&^vXXjjOO96I9d1T zWbGr4gcQf>OgNw3T@VlO@qlYV$;kXKc9UgJ}!`-91Xn|p^g#XH0d1x!oRL7bhQw7bOd=xNmLB`*r5it=-Tm05cgC|_2s4BYGPiFHF2v2_HeyVr zBxyOfqNU~G%BGBzo~xA}_olT#9jeo|(J4az2ofQ<3Y%Crk&%VEiPf9%ix^WM{>g*> zRLJ`4N24j7*>}0O$huV?Mm>8n*w2qs%&&>SzDZAKuqGjs2fc(cmc9l7=fdpCcsBYb z4F0_ezDNDy{9s^5B7$>)dFAmwZgy~LkGQVY(UR`7_L%`8#`V9|`P7YGRo>4ZrKYTT z=}Fa`l%-lDT+IE`xvO4F6ke5so;?}v=f^ZqSi{4oWAjZ)c#|k09~SnpP6?9Tx5`Y* zYC8Az`M052zE`D2G8{1_3&sd!1|en6>jr_FiY7}(EoE0AQJ6bFzDa)Fj4kA$ecX|> z3scvLKH36?`BHA3wf`dUDwfBl~_Pl33--r)m(RwSfh~E&Q>9j<*N{xT)M-% z9xDP#(f9Z5)VA#fbxcLrOJ8pat5^QbRPVRRho=+s&7b=2#|m| zZ>u#C!PVhbr|+whE9oB%i)lvk>HyPAKh_ycuKZby(cjf?`ll-I@=E zrH?3`5Wx^5zKNJNjek>^_MchaIjQMcb#nYS`=>7#5hId-_pg@;{0DY-1(wU%=U>#n z82|b=|1~a`U;Y8-{U<5kxU)xndp@xF$mk4LH?vDuP3NvY_aV5qQ4Rhqugm`fNI@&~ z^&rlb0002SdQ@0+L}hbha%pgMX>V=-00@~)%Rx%SKoAAceNOS03Nv9q@C4#c9pVtz zJ>5S^K~mLpRYr1qx4!)wsD+IM_XAfp7Y}MCY{Domrg)0&8ACd7YbmpJBb$pUUi!-k zyNk|B4iuw9El{K}uW`WlTCD{{ zgKbTj1-3`sj!9NxNsc?I$fggrU_ls?{$H}CnRrM->Z*C1YqLyu(HS1B{U2@! VS0jWSKIQ-b002ovPDHLkV1k2400;m8 literal 0 HcmV?d00001 diff --git a/lib/pandagl/tests/main.c b/lib/pandagl/tests/main.c new file mode 100644 index 000000000..ef77f1898 --- /dev/null +++ b/lib/pandagl/tests/main.c @@ -0,0 +1,25 @@ +/* + * lib/pandagl/tests/main.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include + +extern void test_pandagl_canvas_mix(void); +extern void test_pandagl_image_reader(void); +extern void test_pandagl_font_load(void); + +static const ctest_suite_t suites[] = { + { "pandagl/canvas mix", test_pandagl_canvas_mix }, + { "pandagl/image reader", test_pandagl_image_reader }, + { "pandagl/font load", test_pandagl_font_load }, + { NULL, NULL } +}; + +CTEST_MAIN(suites) diff --git a/lib/pandagl/tests/test_canvas_mix.c b/lib/pandagl/tests/test_canvas_mix.c new file mode 100644 index 000000000..739cdba4e --- /dev/null +++ b/lib/pandagl/tests/test_canvas_mix.c @@ -0,0 +1,73 @@ +/* + * lib/pandagl/test/test_canvas_mix.c + * + * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include + +int color2str(char *str, const pd_color_t *color) +{ + return sprintf(str, "rgba(%d, %d, %d, %g)", color->r, color->g, + color->b, color->a / 255.f); +} + +void test_pandagl_canvas_mix(void) +{ + char rgba_str[64]; + pd_color_t *pixel; + pd_color_t white = pd_rgb(255, 255, 255); + pd_color_t red = pd_rgb(255, 0, 0); + pd_color_t blue = pd_argb(204, 0, 0, 255); + pd_canvas_t white_layer; + pd_canvas_t red_layer; + pd_canvas_t blue_layer; + + pd_canvas_init(&white_layer); + white_layer.color_type = PD_COLOR_TYPE_ARGB; + pd_canvas_create(&white_layer, 100, 100); + pd_canvas_fill(&white_layer, white); + + pd_canvas_init(&red_layer); + red_layer.color_type = PD_COLOR_TYPE_ARGB; + red_layer.opacity = 0.5; + pd_canvas_create(&red_layer, 80, 80); + pd_canvas_fill(&red_layer, red); + + pd_canvas_init(&blue_layer); + blue_layer.color_type = PD_COLOR_TYPE_ARGB; + pd_canvas_create(&blue_layer, 60, 60); + pd_canvas_fill(&blue_layer, blue); + + pd_canvas_mix(&red_layer, &blue_layer, 10, 10, true); + pixel = pd_canvas_pixel_at(&red_layer, 15, 15); + color2str(rgba_str, pixel); + ctest_equal_str("red_layer(15, 15)", rgba_str, "rgba(50, 0, 204, 1)"); + + pd_canvas_mix(&white_layer, &red_layer, 10, 10, true); + pixel = pd_canvas_pixel_at(&white_layer, 0, 0); + color2str(rgba_str, pixel); + ctest_equal_str("white_layer(0, 0)", rgba_str, + "rgba(255, 255, 255, 1)"); + + pixel = pd_canvas_pixel_at(&white_layer, 15, 15); + color2str(rgba_str, pixel); + ctest_equal_str("white_layer(15, 15)", rgba_str, + "rgba(255, 127, 127, 1)"); + + pixel = pd_canvas_pixel_at(&white_layer, 25, 25); + color2str(rgba_str, pixel); + ctest_equal_str("white_layer(25, 25)", rgba_str, + "rgba(152, 127, 229, 1)"); + + pd_canvas_destroy(&white_layer); + pd_canvas_destroy(&red_layer); + pd_canvas_destroy(&blue_layer); +} diff --git a/tests/cases/test_font_load.c b/lib/pandagl/tests/test_font_load.c similarity index 58% rename from tests/cases/test_font_load.c rename to lib/pandagl/tests/test_font_load.c index 6477498c8..5cefbaf0f 100644 --- a/tests/cases/test_font_load.c +++ b/lib/pandagl/tests/test_font_load.c @@ -1,7 +1,7 @@ -/* - * tests/cases/test_font_load.c +/* + * lib/pandagl/tests/test_font_load.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -10,13 +10,14 @@ */ #include -#include -#include +#include +#include #define GetSegoeUIFont(S, W) pd_font_library_get_font_id("Segoe UI", S, W) #define GetArialFont(S, W) pd_font_library_get_font_id("Arial", S, W) -void test_segoe_ui_font_load(void) +#ifdef _WIN32 +static void test_segoe_ui_font_load(void) { pd_font_t *font; int id; @@ -24,82 +25,83 @@ void test_segoe_ui_font_load(void) return; } ctest_equal_int( - "load segoeui.ttf", + "should load segoeui.ttf", pd_font_library_load_file("C:/windows/fonts/segoeui.ttf"), 0); ctest_equal_int( - "load segoeuib.ttf", + "should load segoeuib.ttf", pd_font_library_load_file("C:/windows/fonts/segoeuib.ttf"), 0); ctest_equal_int( - "load segoeuii.ttf", + "should load segoeuii.ttf", pd_font_library_load_file("C:/windows/fonts/segoeuii.ttf"), 0); ctest_equal_int( - "load segoeuil.ttf", + "should load segoeuil.ttf", pd_font_library_load_file("C:/windows/fonts/segoeuil.ttf"), 0); ctest_equal_int( - "load segoeuisl.ttf", + "should load segoeuisl.ttf", pd_font_library_load_file("C:/windows/fonts/segoeuisl.ttf"), 0); ctest_equal_int( - "load segoeuiz.ttf", + "should load segoeuiz.ttf", pd_font_library_load_file("C:/windows/fonts/segoeuiz.ttf"), 0); ctest_equal_int( - "load seguibl.ttf", + "should load seguibl.ttf", pd_font_library_load_file("C:/windows/fonts/seguibl.ttf"), 0); ctest_equal_int( - "load seguili.ttf", + "should load seguili.ttf", pd_font_library_load_file("C:/windows/fonts/seguili.ttf"), 0); id = GetSegoeUIFont(PD_FONT_STYLE_NORMAL, PD_FONT_WEIGHT_NORMAL); - ctest_equal_bool("check get font (style: normal, weight: normal)", + ctest_equal_bool("should resolve font (style: normal, weight: normal)", id > 0, true); if (id > 0) { font = pd_font_library_get_font(id); - ctest_equal_int("check font style", font->style, + ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_NORMAL); - ctest_equal_int("check font weight", font->weight, + ctest_equal_int("should match font weight", font->weight, PD_FONT_WEIGHT_NORMAL); } id = GetSegoeUIFont(PD_FONT_STYLE_ITALIC, PD_FONT_WEIGHT_NORMAL); - ctest_equal_bool("check get font (style: italic, weight: normal)", + ctest_equal_bool("should resolve font (style: italic, weight: normal)", id > 0, true); if (id > 0) { font = pd_font_library_get_font(id); - ctest_equal_int("check font style", font->style, + ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_ITALIC); - ctest_equal_int("check font weight", font->weight, + ctest_equal_int("should match font weight", font->weight, PD_FONT_WEIGHT_NORMAL); } id = GetSegoeUIFont(PD_FONT_STYLE_NORMAL, PD_FONT_WEIGHT_BOLD); - ctest_equal_bool("check get font (style: normal, weight: bold)", id > 0, - true); + ctest_equal_bool("should resolve font (style: normal, weight: bold)", + id > 0, true); if (id > 0) { font = pd_font_library_get_font(id); - ctest_equal_int("check font style", font->style, + ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_NORMAL); - ctest_equal_int("check font weight", font->weight, + ctest_equal_int("should match font weight", font->weight, PD_FONT_WEIGHT_BOLD); } id = GetSegoeUIFont(PD_FONT_STYLE_NORMAL, PD_FONT_WEIGHT_LIGHT); - ctest_equal_bool("check get font (style: normal, weight: light)", + ctest_equal_bool("should resolve font (style: normal, weight: light)", id > 0, true); if (id > 0) { font = pd_font_library_get_font(id); - ctest_equal_int("check font style", font->style, + ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_NORMAL); - ctest_equal_int("check font weight", font->weight, + ctest_equal_int("should match font weight", font->weight, PD_FONT_WEIGHT_LIGHT); } id = GetSegoeUIFont(PD_FONT_STYLE_ITALIC, PD_FONT_WEIGHT_EXTRA_LIGHT); - ctest_equal_bool("check get font (style: italic, weight: extra light)", - id > 0, true); + ctest_equal_bool( + "should resolve font (style: italic, weight: extra light)", id > 0, + true); if (id > 0) { font = pd_font_library_get_font(id); - ctest_equal_int("check font style", font->style, + ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_ITALIC); - ctest_equal_int("check font weight", font->weight, + ctest_equal_int("should match font weight", font->weight, PD_FONT_WEIGHT_EXTRA_LIGHT); } } -void test_arial_font_load(void) +static void test_arial_font_load(void) { int id; pd_font_t *font; @@ -107,87 +109,78 @@ void test_arial_font_load(void) return; } ctest_equal_int( - "load arialbd.ttf", + "should load arialbd.ttf", pd_font_library_load_file("C:/windows/fonts/arialbd.ttf"), 0); ctest_equal_int( - "load arialblk.ttf", + "should load ariblk.ttf", pd_font_library_load_file("C:/windows/fonts/ariblk.ttf"), 0); ctest_equal_int( - "load arialbi.ttf", + "should load arialbi.ttf", pd_font_library_load_file("C:/windows/fonts/arialbi.ttf"), 0); ctest_equal_int( - "load ariali.ttf", + "should load ariali.ttf", pd_font_library_load_file("C:/windows/fonts/ariali.ttf"), 0); id = GetArialFont(PD_FONT_STYLE_NORMAL, PD_FONT_WEIGHT_NORMAL); - ctest_equal_bool("check get font (style: normal, weight: normal)", + ctest_equal_bool("should resolve font (style: normal, weight: normal)", id > 0, true); if (id > 0) { font = pd_font_library_get_font(id); - ctest_equal_int("check font style", font->style, + ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_NORMAL); - ctest_equal_int("check font weight", font->weight, + ctest_equal_int("should match font weight", font->weight, PD_FONT_WEIGHT_NORMAL); } id = GetArialFont(PD_FONT_STYLE_ITALIC, PD_FONT_WEIGHT_NORMAL); - ctest_equal_bool("check get font (style: italic, weight: normal)", + ctest_equal_bool("should resolve font (style: italic, weight: normal)", id > 0, true); if (id > 0) { font = pd_font_library_get_font(id); - ctest_equal_int("check font style", font->style, + ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_ITALIC); - ctest_equal_int("check font weight", font->weight, + ctest_equal_int("should match font weight", font->weight, PD_FONT_WEIGHT_NORMAL); } id = GetArialFont(PD_FONT_STYLE_NORMAL, PD_FONT_WEIGHT_BOLD); - ctest_equal_bool("check get font (style: normal, weight: bold)", id > 0, - true); + ctest_equal_bool("should resolve font (style: normal, weight: bold)", + id > 0, true); if (id > 0) { font = pd_font_library_get_font(id); - ctest_equal_int("check font style", font->style, + ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_NORMAL); - ctest_equal_int("check font weight", font->weight, + ctest_equal_int("should match font weight", font->weight, PD_FONT_WEIGHT_BOLD); } id = GetArialFont(PD_FONT_STYLE_NORMAL, PD_FONT_WEIGHT_BLACK); - ctest_equal_bool("check get font (style: normal, weight: black)", + ctest_equal_bool("should resolve font (style: normal, weight: black)", id > 0, true); if (id > 0) { font = pd_font_library_get_font(id); - ctest_equal_int("check font style", font->style, + ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_NORMAL); - ctest_equal_int("check font weight", font->weight, + ctest_equal_int("should match font weight", font->weight, PD_FONT_WEIGHT_BLACK); } id = GetSegoeUIFont(PD_FONT_STYLE_ITALIC, PD_FONT_WEIGHT_BOLD); - ctest_equal_bool("check get font (style: italic, weight: bold)", id > 0, - true); + ctest_equal_bool("should resolve font (style: italic, weight: bold)", + id > 0, true); if (id > 0) { font = pd_font_library_get_font(id); - ctest_equal_int("check font style", font->style, + ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_ITALIC); - ctest_equal_int("check font weight", font->weight, + ctest_equal_int("should match font weight", font->weight, PD_FONT_WEIGHT_BOLD); } } +#endif -void test_font_load(void) +void test_pandagl_font_load(void) { pd_font_library_init(); - /* 测试是否能够从字体文件中载入字体 */ - ctest_equal_int("check pd_font_library_load_file() success", + ctest_equal_int("should load font from file", pd_font_library_load_file("test_font_load.ttf"), 0); -#ifdef PTK_WIN32 - ctest_describe("test segoe ui font load", test_segoe_ui_font_load); - ctest_describe("test arial font load", test_arial_font_load); +#ifdef _WIN32 + ctest_describe("segoe ui font load", test_segoe_ui_font_load); + ctest_describe("arial font load", test_arial_font_load); #endif pd_font_library_destroy(); - - ui_init(); - /* 测试是否能够根据 CSS 文件中定义的 @font-face 规则来载入字体 */ - ctest_equal_int("check ui_load_css_file() success", - ui_load_css_file("test_font_load.css"), 0); - ctest_equal_bool("check pd_font_library_get_font_id() success", - pd_font_library_get_font_id("icomoon", 0, 0) > 0, - true); - ui_destroy(); } diff --git a/tests/cases/test_image_reader.c b/lib/pandagl/tests/test_image_reader.c similarity index 61% rename from tests/cases/test_image_reader.c rename to lib/pandagl/tests/test_image_reader.c index cb237f7a6..ab0553420 100644 --- a/tests/cases/test_image_reader.c +++ b/lib/pandagl/tests/test_image_reader.c @@ -1,5 +1,5 @@ /* - * tests/cases/test_image_reader.c + * lib/pandagl/tests/test_image_reader.c * * Copyright (c) 2023, Liu Chao All rights reserved. * @@ -10,10 +10,11 @@ */ #include -#include -#include +#include +#include +#include -void test_image_reader(void) +void test_pandagl_image_reader(void) { pd_canvas_t img; int i; @@ -23,12 +24,12 @@ void test_image_reader(void) pd_canvas_init(&img); snprintf(file, 255, "test_image_reader.%s", formats[i]); logger_debug("image file: %s\n", file); - ctest_equal_int("check pd_read_image_from_file", + ctest_equal_int("should read image from file successfully", pd_read_image_from_file(file, &img), 0); - ctest_equal_int("check image width with ReadImageFile", - img.width, 91); - ctest_equal_int("check image height with ReadImageFile", - img.height, 69); + ctest_equal_int("should have correct image width", img.width, + 91); + ctest_equal_int("should have correct image height", img.height, + 69); pd_canvas_destroy(&img); } } diff --git a/lib/pandagl/xmake.lua b/lib/pandagl/xmake.lua index 3cb9cae93..3149a3fe2 100644 --- a/lib/pandagl/xmake.lua +++ b/lib/pandagl/xmake.lua @@ -59,8 +59,14 @@ target("pandagl") end end -target("pandagl_tests") +target("pandagl-tests") set_default(false) set_kind("binary") - add_files("test/*.c") + set_group("tests") + set_rundir("tests/fixtures") + add_files("tests/main.c", "tests/test_canvas_mix.c", "tests/test_image_reader.c", "tests/test_font_load.c") add_deps("ctest", "pandagl") + add_rules("tests.runnable") + add_tests("default", {group = "tests"}) + +includes("examples/*/xmake.lua") diff --git a/lib/ptk/tests/main.c b/lib/ptk/tests/main.c new file mode 100644 index 000000000..43222e261 --- /dev/null +++ b/lib/ptk/tests/main.c @@ -0,0 +1,19 @@ +/* + * lib/ptk/tests/main.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include + +extern void test_ptk_steptimer(void); + +static const ctest_suite_t suites[] = { { "ptk/steptimer", test_ptk_steptimer }, + { NULL, NULL } }; + +CTEST_MAIN(suites) diff --git a/tests/cases/test_steptimer.c b/lib/ptk/tests/test_steptimer.c similarity index 96% rename from tests/cases/test_steptimer.c rename to lib/ptk/tests/test_steptimer.c index 2037aeabf..ac5b140cc 100644 --- a/tests/cases/test_steptimer.c +++ b/lib/ptk/tests/test_steptimer.c @@ -1,5 +1,5 @@ /* - * tests/cases/test_steptimer.c + * lib/ptk/tests/test_steptimer.c * * Copyright (c) 2026, Liu Chao All rights reserved. * @@ -11,7 +11,7 @@ #include #include -#include +#include typedef struct steptimer_probe { unsigned call_count; @@ -36,8 +36,8 @@ static void test_steptimer_init_sets_last_time(void) // After init, last_time is the wall clock, so the first tick should // observe a near-zero delta rather than a huge one. - ctest_equal_uint("first tick should call handler once", probe.call_count, - 1); + ctest_equal_uint("first tick should call handler once", + probe.call_count, 1); ctest_equal_bool("first tick elapsed_time should be small (< 100ms)", probe.last_elapsed_time < 100, true); } @@ -149,7 +149,7 @@ static void test_steptimer_max_delta_clamp(void) probe.last_elapsed_time <= 1000, true); } -void test_steptimer(void) +void test_ptk_steptimer(void) { ctest_describe("init sets last_time to wall clock", test_steptimer_init_sets_last_time); diff --git a/lib/ptk/xmake.lua b/lib/ptk/xmake.lua index e2c8a2967..8345b99a8 100644 --- a/lib/ptk/xmake.lua +++ b/lib/ptk/xmake.lua @@ -32,3 +32,14 @@ target("libptk") end add_syslinks("pthread", "dl") end + +target("libptk-tests") + set_default(false) + set_kind("binary") + set_group("tests") + set_rundir("tests") + add_files("tests/main.c", "tests/test_steptimer.c") + add_deps("ctest", "libptk") + add_rules("tests.runnable") + add_tests("default", {group = "tests"}) + diff --git a/lib/router/xmake.lua b/lib/router/xmake.lua index 9d1833b84..bd9cd1ad3 100644 --- a/lib/router/xmake.lua +++ b/lib/router/xmake.lua @@ -14,29 +14,12 @@ target("librouter") add_defines("LIBROUTER_DLL_EXPORT") end -target("librouter_tests") +target("librouter-tests") set_default(false) set_kind("binary") + set_group("tests") + set_rundir("tests") add_files("tests/test.c") - add_deps("librouter", "ctest") - on_run(function (target) - import("core.base.option") - local argv = {} - local options = {{nil, "memcheck", "k", nil, "enable memory check."}} - local args = option.raw_parse(option.get("arguments") or {}, options) - os.cd("$(projectdir)/tests") - if args.memcheck then - if is_plat("windows") then - table.insert(argv, target:targetfile()) - os.execv("drmemory", argv) - else - table.insert(argv, "valgrind") - table.insert(argv, "--leak-check=full") - table.insert(argv, "--error-exitcode=42") - table.insert(argv, target:targetfile()) - os.execv("sudo", argv) - end - else - os.execv(target:targetfile()) - end - end) + add_deps("ctest", "librouter") + add_rules("tests.runnable") + add_tests("default", {group = "tests"}) diff --git a/lib/thread/tests/main.c b/lib/thread/tests/main.c new file mode 100644 index 000000000..040169ea0 --- /dev/null +++ b/lib/thread/tests/main.c @@ -0,0 +1,19 @@ +/* + * lib/thread/tests/main.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include + +extern void test_thread_worker(void); + +static const ctest_suite_t suites[] = { { "thread/worker", test_thread_worker }, + { NULL, NULL } }; + +CTEST_MAIN(suites) diff --git a/lib/thread/tests/test_thread.c b/lib/thread/tests/test_thread.c new file mode 100644 index 000000000..0e3a2a070 --- /dev/null +++ b/lib/thread/tests/test_thread.c @@ -0,0 +1,95 @@ +/* + * lib/thread/tests/test_thread.c + * + * Copyright (c) 2023, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include + +typedef struct TestWorkerRec_ { + char data[32]; + int data_count; + bool cancel; + bool active; + thread_cond_t cond; + thread_mutex_t mutex; + thread_t thread; +} TestWorkerRec, *TestWorker; + +static void TestWorker_Thread(void *arg) +{ + TestWorker worker = arg; + + worker->cancel = false; + worker->active = true; + worker->data_count = 0; + thread_mutex_lock(&worker->mutex); + while (!worker->cancel && worker->data_count < 20) { + logger_debug("waiting...\n"); + thread_cond_wait(&worker->cond, &worker->mutex); + logger_debug("get data: %s\n", worker->data); + worker->data_count += 1; + } + thread_mutex_unlock(&worker->mutex); + logger_debug("count: %d\n", worker->data_count); + worker->active = false; + thread_exit(NULL); +} + +static void TestWorker_Send(TestWorker worker, const char *data) +{ + thread_mutex_lock(&worker->mutex); + strcpy(worker->data, data); + thread_cond_signal(&worker->cond); + thread_mutex_unlock(&worker->mutex); +} + +static void TestWorker_Init(TestWorker worker) +{ + thread_mutex_init(&worker->mutex); + thread_cond_init(&worker->cond); +} + +static void TestWorker_Destroy(TestWorker worker) +{ + thread_mutex_lock(&worker->mutex); + worker->cancel = true; + thread_cond_signal(&worker->cond); + thread_mutex_unlock(&worker->mutex); + thread_join(worker->thread, NULL); + thread_mutex_destroy(&worker->mutex); + thread_cond_destroy(&worker->cond); +} + +void test_thread_worker(void) +{ + TestWorkerRec worker; + + TestWorker_Init(&worker); + thread_create(&worker.thread, TestWorker_Thread, &worker); + sleep_ms(100); + TestWorker_Send(&worker, "hello"); + sleep_ms(20); + TestWorker_Send(&worker, "world"); + sleep_ms(100); + TestWorker_Send(&worker, "this"); + sleep_ms(50); + TestWorker_Send(&worker, "is"); + sleep_ms(100); + TestWorker_Send(&worker, "test"); + sleep_ms(50); + TestWorker_Send(&worker, "bye!"); + sleep_ms(100); + TestWorker_Destroy(&worker); + ctest_equal_int("should receive 7 data items", worker.data_count, 7); + ctest_equal_bool("should no longer be active", worker.active, false); +} diff --git a/lib/thread/xmake.lua b/lib/thread/xmake.lua index c8bd8b790..5a9e3e52b 100644 --- a/lib/thread/xmake.lua +++ b/lib/thread/xmake.lua @@ -15,3 +15,14 @@ target("libthread") elseif is_plat("windows") then add_defines("LIBTHREAD_DLL_EXPORT") end + +target("libthread-tests") + set_default(false) + set_kind("binary") + set_group("tests") + set_rundir("tests") + add_files("tests/main.c", "tests/test_thread.c") + add_deps("ctest", "libthread") + add_rules("tests.runnable") + add_tests("default", {group = "tests"}) + diff --git a/tests/test_xml_parser.nested.xml b/lib/ui-xml/tests/fixtures/test_xml_parser.nested.xml similarity index 100% rename from tests/test_xml_parser.nested.xml rename to lib/ui-xml/tests/fixtures/test_xml_parser.nested.xml diff --git a/tests/test_xml_parser.xml b/lib/ui-xml/tests/fixtures/test_xml_parser.xml similarity index 100% rename from tests/test_xml_parser.xml rename to lib/ui-xml/tests/fixtures/test_xml_parser.xml diff --git a/lib/ui-xml/tests/main.c b/lib/ui-xml/tests/main.c new file mode 100644 index 000000000..b8beb4f3e --- /dev/null +++ b/lib/ui-xml/tests/main.c @@ -0,0 +1,19 @@ +/* + * lib/ui-xml/tests/main.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include + +extern void test_ui_xml_parser(void); + +static const ctest_suite_t suites[] = { { "ui-xml/parser", test_ui_xml_parser }, + { NULL, NULL } }; + +CTEST_MAIN(suites) diff --git a/lib/ui-xml/tests/test_xml_parser.c b/lib/ui-xml/tests/test_xml_parser.c new file mode 100644 index 000000000..ef1b883f3 --- /dev/null +++ b/lib/ui-xml/tests/test_xml_parser.c @@ -0,0 +1,64 @@ +/* + * lib/ui-xml/tests/test_xml_parser.c + * + * Copyright (c) 2023, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include + +static void check_widget_attribute(void) +{ + ui_widget_t *w; + + w = ui_get_widget("test-attr-disabled-1"); + ctest_equal_bool("should be disabled for element-1", w->disabled, true); + w = ui_get_widget("test-attr-disabled-2"); + ctest_equal_bool("should be disabled for element-2", w->disabled, true); + w = ui_get_widget("test-attr-disabled-3"); + ctest_equal_bool("should be disabled for element-3", w->disabled, true); + w = ui_get_widget("test-attr-disabled-4"); + ctest_equal_bool("should not be disabled for element-4", w->disabled, + false); +} + +static void check_widget_loaded_from_nested_xml(void) +{ + ui_widget_t *w; + + w = ui_get_widget("test-nested-1"); + ctest_equal_bool("should exist for test-nested-1", w != NULL, true); + w = ui_get_widget("test-nested-2"); + ctest_equal_bool("should exist for test-nested-2", w != NULL, true); + w = ui_get_widget("test-nested-3"); + ctest_equal_bool("should exist for test-nested-3", w != NULL, true); + w = ui_get_widget("test-nested-4"); + ctest_equal_bool("should exist for test-nested-4", w != NULL, true); +} + +void test_ui_xml_parser(void) +{ + ui_widget_t *pack; + + ui_init(); + ctest_equal_bool( + "should load XML file", + (pack = ui_load_xml_file("test_xml_parser.xml")) != NULL, true); + if (!pack) { + ui_destroy(); + return; + } + ui_root_append(pack); + ui_widget_unwrap(pack); + ui_update(); + ctest_describe("widget attribute", check_widget_attribute); + ctest_describe("widgets loaded from nested xml", + check_widget_loaded_from_nested_xml); + ui_destroy(); +} diff --git a/lib/ui-xml/xmake.lua b/lib/ui-xml/xmake.lua index fd39c3be0..c4caf0874 100644 --- a/lib/ui-xml/xmake.lua +++ b/lib/ui-xml/xmake.lua @@ -18,3 +18,13 @@ target("libui-xml") elseif is_plat("windows") then add_defines("LIBUI_XML_DLL_EXPORT") end + +target("libui-xml-tests") + set_default(false) + set_kind("binary") + set_group("tests") + set_rundir("tests/fixtures") + add_files("tests/main.c", "tests/test_xml_parser.c") + add_deps("ctest", "libui-xml") + add_rules("tests.runnable") + add_tests("default", {group = "tests"}) diff --git a/tests/cases/test_flex_layout.c b/tests/cases/test_flex_layout.c deleted file mode 100644 index 7edeb60e6..000000000 --- a/tests/cases/test_flex_layout.c +++ /dev/null @@ -1,752 +0,0 @@ -/* - * tests/cases/test_flex_layout.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include - -#define SCROLLBAR_WIDTH 14 - -static void test_flex_layout_with_content_width(float width) -{ - float content_width = width - 22; - - ui_widget_t *w; - ui_widget_t *content; - ui_widget_t *example; - ui_widget_t *container; - ui_rect_t rect; - - container = ui_widget_get_child(ui_get_widget("main"), 0); - ui_update(); - - rect.y = 10; - rect.x = 10; - rect.width = width; - rect.height = 104; - w = ui_widget_get_child(container, 0); - ctest_equal_ui_rect("$('.example')[0].border_box", &w->border_box, &rect); - - rect.y += 114; - w = ui_widget_get_child(container, 1); - ctest_equal_ui_rect("$('.example')[1].border_box", &w->border_box, &rect); - - rect.y += 114; - w = ui_widget_get_child(container, 2); - ctest_equal_ui_rect("$('.example')[2].border_box", &w->border_box, &rect); - - rect.y += 114; - w = ui_widget_get_child(container, 3); - ctest_equal_ui_rect("$('.example')[3].border_box", &w->border_box, &rect); - - rect.y += 114; - w = ui_widget_get_child(container, 4); - ctest_equal_ui_rect("$('.example')[4].border_box", &w->border_box, &rect); - - rect.y += 114; - w = ui_widget_get_child(container, 5); - ctest_equal_ui_rect("$('.example')[5].border_box", &w->border_box, &rect); - - rect.y += 114; - w = ui_widget_get_child(container, 6); - ctest_equal_ui_rect("$('.example')[6].border_box", &w->border_box, &rect); - - rect.y += 114; - rect.height = 344; - w = ui_widget_get_child(container, 7); - ctest_equal_ui_rect("$('.example')[7].border_box", &w->border_box, &rect); - - rect.y += rect.height + 10; - rect.height = 204; - w = ui_widget_get_child(container, 8); - ctest_equal_ui_rect("$('.example')[8].border_box", &w->border_box, &rect); - - rect.y += rect.height + 10; - rect.height = 354; - w = ui_widget_get_child(container, 9); - ctest_equal_ui_rect("$('.example')[9].border_box", &w->border_box, &rect); - - rect.y += rect.height + 10; - rect.height = 354; - w = ui_widget_get_child(container, 10); - ctest_equal_ui_rect("$('.example')[10].border_box", &w->border_box, &rect); - - rect.y += rect.height + 10; - rect.height = 354; - w = ui_widget_get_child(container, 11); - ctest_equal_ui_rect("$('.example')[11].border_box", &w->border_box, &rect); - - rect.y += rect.height + 10; - rect.height = 354; - w = ui_widget_get_child(container, 12); - ctest_equal_ui_rect("$('.example')[12].border_box", &w->border_box, &rect); - - rect.y += rect.height + 10; - rect.height = 354; - w = ui_widget_get_child(container, 13); - ctest_equal_ui_rect("$('.example')[13].border_box", &w->border_box, &rect); - - rect.y += rect.height + 10; - rect.height = 254; - w = ui_widget_get_child(container, 14); - ctest_equal_ui_rect("$('.example')[14].border_box", &w->border_box, &rect); - - rect.y += rect.height + 10; - rect.height = 184; - w = ui_widget_get_child(container, 15); - ctest_equal_ui_rect("$('.example')[15].border_box", &w->border_box, &rect); - - rect.y += rect.height + 10; - rect.height = 354; - w = ui_widget_get_child(container, 16); - ctest_equal_ui_rect("$('.example')[16].border_box", &w->border_box, &rect); - - // (1) justify-content: center;; - - example = ui_widget_get_child(container, 1); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - rect.x = 5 + (content_width - 300) / 2.f; - rect.y = 5; - rect.width = 50; - rect.height = 50; - ctest_equal_ui_rect("$('.example:eq(1) .box')[0].border_box", &w->border_box, - &rect); - - // (2) justify-content: flex-end; - - example = ui_widget_get_child(container, 2); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - rect.x = 5 + (content_width - 300); - ctest_equal_ui_rect("$('.example:eq(2) .box')[0].border_box", &w->border_box, - &rect); - - // (3) justify-content: space-between; - - example = ui_widget_get_child(container, 3); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - rect.x = 5; - ctest_equal_ui_rect("$('.example:eq(3) .box')[0].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - rect.x = 5 + 50 + (content_width - 300) / 5.f; - ctest_equal_ui_rect("$('.example:eq(3) .box')[1].border_box", &w->border_box, - &rect); - - w = ui_widget_get_child(content, 5); - rect.x = 5 + (content_width - 50); - ctest_equal_ui_rect("$('.example:eq(3) .box')[5].border_box", &w->border_box, - &rect); - - // (4) justify-content: space-around; - - example = ui_widget_get_child(container, 4); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - rect.x = 5 + (content_width - 300) / 6.f / 2.f; - ctest_equal_ui_rect("$('.example:eq(4) .box')[0].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - rect.x += 50 + (content_width - 300) / 6.f; - ctest_equal_ui_rect("$('.example:eq(4) .box')[1].border_box", &w->border_box, - &rect); - - w = ui_widget_get_child(content, 5); - rect.x = 5 + content_width - (content_width - 300) / 6.f / 2.f - 50; - ctest_equal_ui_rect("$('.example:eq(4) .box')[5].border_box", &w->border_box, - &rect); - - // (5) Auto margin - - example = ui_widget_get_child(container, 5); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - rect.x = 5; - ctest_equal_ui_rect("$('.example:eq(5) .box')[0].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - rect.x += 50 + (content_width - 200) / 2.f; - ctest_equal_ui_rect("$('.example:eq(5) .box')[1].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - rect.x += 50; - ctest_equal_ui_rect("$('.example:eq(5) .box')[2].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - rect.x += 50 + (content_width - 200) / 2.f; - ctest_equal_ui_rect("$('.example:eq(5) .box')[3].border_box", &w->border_box, - &rect); - - // (7) flex-grow - - example = ui_widget_get_child(container, 7); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - rect.x = 5; - rect.width = content_width / 3.f; - ctest_equal_ui_rect("$('.example:eq(7) .box')[0].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - rect.x += rect.width; - ctest_equal_ui_rect("$('.example:eq(7) .box')[1].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - rect.x += rect.width; - ctest_equal_ui_rect("$('.example:eq(7) .box')[2].border_box", &w->border_box, - &rect); - - // line 1 - - content = ui_widget_get_child(example, 2); - w = ui_widget_get_child(content, 0); - rect.x = 5; - rect.width = content_width - 50 - 50; - ctest_equal_ui_rect("$('.example:eq(7) .box')[3].border_box", &w->border_box, - &rect); - - // line 2 - - content = ui_widget_get_child(example, 3); - w = ui_widget_get_child(content, 0); - rect.x = 5; - rect.width = (content_width - 50) / 2.f; - ctest_equal_ui_rect("$('.example:eq(7) .box')[6].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - rect.x += rect.width; - ctest_equal_ui_rect("$('.example:eq(7) .box')[7].border_box", &w->border_box, - &rect); - - // line 3 - - content = ui_widget_get_child(example, 4); - w = ui_widget_get_child(content, 1); - rect.x = 5 + 50; - ctest_equal_ui_rect("$('.example:eq(7) .box')[10].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - rect.x += rect.width; - ctest_equal_ui_rect("$('.example:eq(7) .box')[11].border_box", &w->border_box, - &rect); - - // line 4 - - content = ui_widget_get_child(example, 5); - w = ui_widget_get_child(content, 0); - rect.x = 5; - rect.width = 12 + (content_width - 3 * 12) * 4.f / 7.f; - ctest_equal_ui_rect("$('.example:eq(7) .box')[12].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - rect.x += rect.width; - rect.width = 12 + (content_width - 3 * 12) * 2.f / 7.f; - ctest_equal_ui_rect("$('.example:eq(7) .box')[13].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - rect.x += rect.width; - rect.width = 12 + (content_width - 3 * 12) / 7.f; - ctest_equal_ui_rect("$('.example:eq(7) .box')[14].border_box", &w->border_box, - &rect); - - // (10) align-items: center; height: 300px; - - example = ui_widget_get_child(container, 10); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - rect.x = 5; - rect.y = 5 + (300 / 3.f - 50) / 2.f; - rect.width = 50; - ctest_equal_ui_rect("$('.example:eq(10) .box')[0].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - rect.x += 50; - ctest_equal_ui_rect("$('.example:eq(10) .box')[1].border_box", &w->border_box, - &rect); - - // (11) align-items: end; height: 300px; - - example = ui_widget_get_child(container, 11); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - rect.x = 5; - rect.y = 5 + (300 / 3.f - 50); - rect.width = 50; - ctest_equal_ui_rect("$('.example:eq(11) .box')[0].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - rect.x += 50; - ctest_equal_ui_rect("$('.example:eq(11) .box')[1].border_box", &w->border_box, - &rect); - - // (12) align-items: stretch; height: 300px; - - example = ui_widget_get_child(container, 12); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - rect.x = 5; - rect.y = 5; - rect.width = 50; - rect.height = 100; - ctest_equal_ui_rect("$('.example:eq(12) .box')[0].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - rect.x += 50; - ctest_equal_ui_rect("$('.example:eq(12) .box')[1].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - w = ui_widget_next(w); - rect.x = 5 + 3 * 50; - rect.height = 50; - ctest_equal_ui_rect("$('.example:eq(12) .box')[3].border_box", &w->border_box, - &rect); - - // (13) Vertically Centered Layout - - example = ui_widget_get_child(container, 13); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - rect.x = 5 + (content_width - 50) / 2.f; - rect.y = 5 + (300 - 50) / 2.f; - rect.width = 50; - rect.height = 50; - ctest_equal_ui_rect("$('.example:eq(13) .box')[0].border_box", &w->border_box, - &rect); - - // (14) flex-direction: column; - - example = ui_widget_get_child(container, 14); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - rect.x = 5; - rect.y = 5; - rect.width = 50; - rect.height = 50; - ctest_equal_ui_rect("$('.example:eq(14) .box')[0].border_box", &w->border_box, - &rect); - - w = ui_widget_get_child(content, 4); - rect.x = 5 + 50 + (content_width - 50 - 150 - 200 - 50 - 50) / 5.f; - rect.width = 150; - ctest_equal_ui_rect("$('.example:eq(14) .box')[4].border_box", &w->border_box, - &rect); - - w = ui_widget_get_child(content, 8); - rect.x += 150 + (content_width - 50 - 150 - 200 - 50 - 50) / 5.f; - rect.width = 50; - ctest_equal_ui_rect("$('.example:eq(14) .box')[8].border_box", &w->border_box, - &rect); - - // (15) Holy Grail Layout - - example = ui_widget_get_child(container, 15); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - rect.x = 5; - rect.y = 5; - rect.width = content_width; - rect.height = 50; - ctest_equal_ui_rect("$('.example:eq(15) .layout__header')[0].border_box", - &w->border_box, &rect); - - w = ui_widget_get_child(content, 2); - rect.y = 5 + 50 + 30; - ctest_equal_ui_rect("$('.example:eq(15) .layout__footer')[0].border_box", - &w->border_box, &rect); - - rect.x = 0; - rect.y = 0; - rect.width = 100; - rect.height = 30; - w = ui_widget_get_child(content, 1); - w = ui_widget_get_child(w, 0); - ctest_equal_ui_rect("$('.example:eq(15) .layout__left')[0].border_box", - &w->border_box, &rect); - - w = ui_widget_next(w); - rect.x = 100; - rect.width = content_width - 100 - 100; - ctest_equal_ui_rect("$('.example:eq(15) .layout__center')[0].border_box", - &w->border_box, &rect); - - w = ui_widget_next(w); - rect.x += rect.width; - rect.width = 100; - ctest_equal_ui_rect("$('.example:eq(15) .layout__right')[0].border_box", - &w->border_box, &rect); - - // (16) Holy Grail Layout (height: 300px) - - example = ui_widget_get_child(container, 16); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - rect.x = 5; - rect.y = 5; - rect.width = content_width; - rect.height = 50; - ctest_equal_ui_rect("$('.example:eq(16) .layout__header')[0].border_box", - &w->border_box, &rect); - - w = ui_widget_get_child(content, 2); - rect.y = 5 + 50 + 200; - ctest_equal_ui_rect("$('.example:eq(16) .layout__footer')[0].border_box", - &w->border_box, &rect); - - rect.x = 0; - rect.y = 0; - rect.width = 100; - rect.height = 200; - w = ui_widget_get_child(content, 1); - w = ui_widget_get_child(w, 0); - ctest_equal_ui_rect("$('.example:eq(16) .layout__left')[0].border_box", - &w->border_box, &rect); - - w = ui_widget_next(w); - rect.x = 100; - rect.width = content_width - 100 - 100; - ctest_equal_ui_rect("$('.example:eq(16) .layout__center')[0].border_box", - &w->border_box, &rect); - - w = ui_widget_next(w); - rect.x += rect.width; - rect.width = 100; - ctest_equal_ui_rect("$('.example:eq(16) .layout__right')[0].border_box", - &w->border_box, &rect); -} - -static void test_browser_layout(void) -{ - ui_widget_t *w; - ui_rect_t rect; - - w = ui_get_widget("browser-tabbar"); - w = ui_widget_get_child(w, 0); - ctest_equal_int("$('#browser-tabbar .c-frame-tab')[0].width", - (int)w->border_box.width, 101); - w = ui_widget_next(w); - ctest_equal_int("$('#browser-tabbar .c-frame-tab')[1].width", - (int)w->border_box.width, 101); - w = ui_widget_next(w); - ctest_equal_int("$('#browser-tabbar .c-frame-tab')[2].width", - (int)w->border_box.width, 101); - w = ui_widget_next(w); - ctest_equal_int("$('#browser-tabbar .c-frame-tab')[3].width", - (int)w->border_box.width, 101); - w = ui_widget_next(w); - ctest_equal_int("$('#browser-tabbar .c-frame-tab')[4].width", - (int)w->border_box.width, 101); - - w = ui_get_widget("browser-frame-client"); - ctest_equal_int("$('#browser-frame-client')[0].height", (int)w->border_box.height, - 223); - w = ui_get_widget("browser-frame-content"); - ctest_equal_int("$('#browser-frame-content')[0].height", (int)w->border_box.height, - 223); - w = ui_get_widget("browser-page-home"); - ctest_equal_int("$('#browser-page-home')[0].height", (int)w->border_box.height, - 223); - w = ui_get_widget("browser-page-home-container"); - rect.width = 256; - rect.height = 70; - rect.x = - (538.f - rect.width) / 2.f + w->parent->computed_style.padding_left; - rect.y = - (203.f - rect.height) / 2.f + w->parent->computed_style.padding_top; - ctest_equal_ui_rect("$('#browser-page-home-container')[0].border_box", - &w->border_box, &rect); -} - -static void test_flex_layout_1280(void) -{ - ui_widget_resize(ui_root(), 1280, 800); - test_flex_layout_with_content_width(580); -} - -static void test_flex_layout_600(void) -{ - ui_widget_resize(ui_root(), 600, 400); - test_flex_layout_with_content_width(580 - SCROLLBAR_WIDTH); -} - -static void test_flex_layout_320(void) -{ - float width = 320 - 10 - 10 - SCROLLBAR_WIDTH; - float content_width = width - 12 - 10; - - ui_widget_t *w; - ui_widget_t *content; - ui_widget_t *example; - ui_widget_t *container; - ui_rect_t rect; - - container = ui_widget_get_child(ui_get_widget("main"), 0); - ui_widget_resize(ui_root(), 320, 240); - ui_update(); - - rect.y = 10; - rect.x = 10; - rect.width = width; - rect.height = 104; - w = ui_widget_get_child(container, 0); - ctest_equal_ui_rect("$('.example')[0].border_box", &w->border_box, &rect); - - rect.y += 114; - w = ui_widget_get_child(container, 1); - ctest_equal_ui_rect("$('.example')[1].border_box", &w->border_box, &rect); - - rect.y += 114; - w = ui_widget_get_child(container, 2); - ctest_equal_ui_rect("$('.example')[2].border_box", &w->border_box, &rect); - - rect.y += 114; - w = ui_widget_get_child(container, 3); - ctest_equal_ui_rect("$('.example')[3].border_box", &w->border_box, &rect); - - rect.y += 114; - w = ui_widget_get_child(container, 4); - ctest_equal_ui_rect("$('.example')[4].border_box", &w->border_box, &rect); - - rect.y += 114; - w = ui_widget_get_child(container, 5); - ctest_equal_ui_rect("$('.example')[5].border_box", &w->border_box, &rect); - - rect.y += 114; - w = ui_widget_get_child(container, 6); - ctest_equal_ui_rect("$('.example')[6].border_box", &w->border_box, &rect); - - rect.y += 114; - rect.height = 344; - w = ui_widget_get_child(container, 7); - ctest_equal_ui_rect("$('.example')[7].border_box", &w->border_box, &rect); - - rect.y += rect.height + 10; - rect.height = 354; - w = ui_widget_get_child(container, 8); - ctest_equal_ui_rect("$('.example')[8].border_box", &w->border_box, &rect); - - rect.y += rect.height + 10; - rect.height = 354; - w = ui_widget_get_child(container, 9); - ctest_equal_ui_rect("$('.example')[9].border_box", &w->border_box, &rect); - - rect.y += rect.height + 10; - rect.height = 354; - w = ui_widget_get_child(container, 10); - ctest_equal_ui_rect("$('.example')[10].border_box", &w->border_box, &rect); - - rect.y += rect.height + 10; - rect.height = 354; - w = ui_widget_get_child(container, 11); - ctest_equal_ui_rect("$('.example')[11].border_box", &w->border_box, &rect); - - rect.y += rect.height + 10; - rect.height = 354; - w = ui_widget_get_child(container, 12); - ctest_equal_ui_rect("$('.example')[12].border_box", &w->border_box, &rect); - - rect.y += rect.height + 10; - rect.height = 354; - w = ui_widget_get_child(container, 13); - ctest_equal_ui_rect("$('.example')[13].border_box", &w->border_box, &rect); - - rect.y += rect.height + 10; - rect.height = 254; - w = ui_widget_get_child(container, 14); - ctest_equal_ui_rect("$('.example')[14].border_box", &w->border_box, &rect); - - rect.y += rect.height + 10; - rect.height = 184; - w = ui_widget_get_child(container, 15); - ctest_equal_ui_rect("$('.example')[15].border_box", &w->border_box, &rect); - - rect.y += rect.height + 10; - rect.height = 354; - w = ui_widget_get_child(container, 16); - ctest_equal_ui_rect("$('.example')[16].border_box", &w->border_box, &rect); - - // (1) justify-content: center;; - - example = ui_widget_get_child(container, 1); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - rect.x = 5; - rect.y = 5; - rect.width = 50 + (content_width - 300) / 6.f; - rect.height = 50; - ctest_equal_ui_rect("$('.example:eq(1) .box')[0].border_box", &w->border_box, - &rect); - - // (2) justify-content: flex-end; - - example = ui_widget_get_child(container, 2); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - ctest_equal_ui_rect("$('.example:eq(2) .box')[0].border_box", &w->border_box, - &rect); - - // (3) justify-content: space-between; - - example = ui_widget_get_child(container, 3); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - ctest_equal_ui_rect("$('.example:eq(3) .box')[0].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - rect.x += rect.width; - ctest_equal_ui_rect("$('.example:eq(3) .box')[1].border_box", &w->border_box, - &rect); - - w = ui_widget_get_child(content, 5); - rect.x = 5 + content_width - rect.width; - ctest_equal_ui_rect("$('.example:eq(3) .box')[5].border_box", &w->border_box, - &rect); - - // (5) Auto margin - - example = ui_widget_get_child(container, 5); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - rect.x = 5; - rect.width = 50; - ctest_equal_ui_rect("$('.example:eq(5) .box')[0].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - rect.x += 50 + (content_width - 200) / 2.f; - ctest_equal_ui_rect("$('.example:eq(5) .box')[1].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - rect.x += 50; - ctest_equal_ui_rect("$('.example:eq(5) .box')[2].border_box", &w->border_box, - &rect); - - w = ui_widget_next(w); - rect.x += 50 + (content_width - 200) / 2.f; - ctest_equal_ui_rect("$('.example:eq(5) .box')[3].border_box", &w->border_box, - &rect); - - // (15) Holy Grail Layout - - example = ui_widget_get_child(container, 15); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - rect.x = 5; - rect.y = 5; - rect.width = content_width; - rect.height = 50; - ctest_equal_ui_rect("$('.example:eq(15) .layout__header')[0].border_box", - &w->border_box, &rect); - - w = ui_widget_get_child(content, 2); - rect.y = 5 + 50 + 30; - ctest_equal_ui_rect("$('.example:eq(15) .layout__footer')[0].border_box", - &w->border_box, &rect); - - rect.x = 0; - rect.y = 0; - rect.width = 100; - rect.height = 30; - w = ui_widget_get_child(content, 1); - w = ui_widget_get_child(w, 0); - ctest_equal_ui_rect("$('.example:eq(15) .layout__left')[0].border_box", - &w->border_box, &rect); - - w = ui_widget_next(w); - rect.x = 100; - rect.width = content_width - 100 - 100; - ctest_equal_ui_rect("$('.example:eq(15) .layout__center')[0].border_box", - &w->border_box, &rect); - - w = ui_widget_next(w); - rect.x += rect.width; - rect.width = 100; - ctest_equal_ui_rect("$('.example:eq(15) .layout__right')[0].border_box", - &w->border_box, &rect); - - // (16) Holy Grail Layout (height: 300px) - - example = ui_widget_get_child(container, 16); - content = ui_widget_get_child(example, 1); - w = ui_widget_get_child(content, 0); - rect.x = 5; - rect.y = 5; - rect.width = content_width; - rect.height = 50; - ctest_equal_ui_rect("$('.example:eq(15) .layout__header')[0].border_box", - &w->border_box, &rect); - - w = ui_widget_get_child(content, 2); - rect.y = 5 + 50 + 200; - ctest_equal_ui_rect("$('.example:eq(16) .layout__footer')[0].border_box", - &w->border_box, &rect); - - rect.x = 0; - rect.y = 0; - rect.width = 100; - rect.height = 200; - w = ui_widget_get_child(content, 1); - w = ui_widget_get_child(w, 0); - ctest_equal_ui_rect("$('.example:eq(16) .layout__left')[0].border_box", - &w->border_box, &rect); - - w = ui_widget_next(w); - rect.x = 100; - rect.width = content_width - 100 - 100; - ctest_equal_ui_rect("$('.example:eq(16) .layout__center')[0].border_box", - &w->border_box, &rect); - - w = ui_widget_next(w); - rect.x += rect.width; - rect.width = 100; - ctest_equal_ui_rect("$('.example:eq(16) .layout__right')[0].border_box", - &w->border_box, &rect); -} - -void test_flex_layout(void) -{ - ui_widget_t *root; - ui_widget_t *wrapper; - - lcui_init(); - wrapper = ui_load_xml_file("test_flex_layout.xml"); - root = ui_root(); - ui_widget_set_title(root, L"test flex layout"); - ui_widget_append(root, wrapper); - ui_widget_unwrap(wrapper); - ui_update(); - - ctest_describe("browser layout", test_browser_layout); - ctest_describe("root width 1280px", test_flex_layout_1280); - ctest_describe("root width 600px", test_flex_layout_600); - ctest_describe("root width 320px", test_flex_layout_320); - -#ifndef PREVIEW_MODE - lcui_quit(); - lcui_main(); -#endif -} diff --git a/tests/cases/test_scrollbar.c b/tests/cases/test_scrollbar.c deleted file mode 100644 index e4980f363..000000000 --- a/tests/cases/test_scrollbar.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * tests/cases/test_scrollbar.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include - -const char *test_css = "\ -.container {\ - width: 300px;\ - height: 240px;\ - padding: 10px;\ - margin: 20px auto 0 auto;\ - border: 1px solid #eee;\ -}\ -\ -text {\ - white-space: nowrap;\ - display: inline-block;\ -}\ -\ -);"; - -const char *test_content = "\n\ -/* ***************************************************************************\n\ - * test_scrollbar.c -- test scrollbar\n\ - *\n\ - * Copyright (c) 2021, Liu chao All rights reserved.\n\ - *\n\ - * Redistribution and use in source and binary forms, with or without\n\ - * modification, are permitted provided that the following conditions are met:\n\ - *\n\ - * * Redistributions of source code must retain the above copyright notice,\n\ - * this list of conditions and the following disclaimer.\n\ - * * Redistributions in binary form must reproduce the above copyright\n\ - * notice, this list of conditions and the following disclaimer in the\n\ - * documentation and/or other materials provided with the distribution.\n\ - * * Neither the name of LCUI nor the names of its contributors may be used\n\ - * to endorse or promote products derived from this software without\n\ - * specific prior written permission.\n\ - *\n\ - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n\ - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n\ - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n\ - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n\ - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n\ - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n\ - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n\ - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n\ - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n\ - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n\ - * POSSIBILITY OF SUCH DAMAGE.\n\ - */\n\ -"; - -void build_content_view(void) -{ - ui_widget_t *container = ui_create_scrollarea(); - ui_widget_t *content = ui_create_scrollarea_content(); - ui_widget_t *text = ui_create_widget("text"); - ui_widget_t *vscrollbar = ui_create_scrollbar(); - ui_widget_t *hscrollbar = ui_create_scrollbar(); - - ui_widget_set_id(content, "license_content"); - ui_text_set_content(text, test_content); - ui_scrollbar_set_orientation(hscrollbar, UI_SCROLLBAR_HORIZONTAL); - ui_widget_add_class(container, "container"); - ui_widget_append(content, text); - ui_widget_append(container, content); - ui_widget_append(container, vscrollbar); - ui_widget_append(container, hscrollbar); - ui_root_append(container); -} - -int build_content_view_from_xml(void) -{ - ui_widget_t *root = ui_root(); - ui_widget_t *pack = ui_load_xml_file("test_scrollbar.xml"); - - if (!pack) { - return -1; - } - ui_widget_append(root, pack); - ui_widget_unwrap(pack); - return 0; -} - -void test_scrollbar(void) -{ - float left, top; - ui_event_t e = { 0 }; - ui_widget_t *content; - - lcui_init(); - ui_widget_resize(ui_root(), 800, 640); - ui_load_css_string(test_css, __FILE__); - build_content_view(); - lcui_ui_update(); - - content = ui_get_widget("license_content"); - left = content->computed_style.left; - top = content->computed_style.top; - - e.type = UI_EVENT_MOUSEMOVE; - e.mouse.x = 300; - e.mouse.y = 275; - ui_dispatch_event(&e); - lcui_ui_update(); - - e.type = UI_EVENT_MOUSEDOWN; - e.mouse.button = MOUSE_BUTTON_LEFT; - e.mouse.x = 300; - e.mouse.y = 275; - ui_dispatch_event(&e); - lcui_ui_update(); - - e.type = UI_EVENT_MOUSEMOVE; - e.mouse.x = 600; - e.mouse.y = 275; - ui_dispatch_event(&e); - lcui_ui_update(); - - ctest_equal_bool("content should be moved to the left", - content->computed_style.left < left && - top == content->computed_style.top, - true); - - left = content->computed_style.left; - top = content->computed_style.top; - - e.type = UI_EVENT_MOUSEMOVE; - e.mouse.x = 400; - e.mouse.y = 275; - ui_dispatch_event(&e); - e.type = UI_EVENT_MOUSEUP; - e.mouse.button = MOUSE_BUTTON_LEFT; - e.mouse.x = 400; - e.mouse.y = 275; - ui_dispatch_event(&e); - lcui_ui_update(); - - ctest_equal_bool("content should be moved to the right", - content->computed_style.left > left && - top == content->computed_style.top, - true); - - left = content->computed_style.left; - top = content->computed_style.top; - - e.type = UI_EVENT_MOUSEMOVE; - e.mouse.x = 555; - e.mouse.y = 45; - ui_dispatch_event(&e); - lcui_ui_update(); - - e.type = UI_EVENT_MOUSEDOWN; - e.mouse.button = MOUSE_BUTTON_LEFT; - e.mouse.x = 555; - e.mouse.y = 45; - ui_dispatch_event(&e); - lcui_ui_update(); - - e.type = UI_EVENT_MOUSEMOVE; - e.mouse.x = 555; - e.mouse.y = 200; - ui_dispatch_event(&e); - lcui_ui_update(); - - ctest_equal_bool("content should be moved to the top", - content->computed_style.left == left && - top > content->computed_style.top, - true); - - left = content->computed_style.left; - top = content->computed_style.top; - - e.type = UI_EVENT_MOUSEMOVE; - e.mouse.x = 555; - e.mouse.y = 100; - ui_dispatch_event(&e); - e.type = UI_EVENT_MOUSEUP; - e.mouse.button = MOUSE_BUTTON_LEFT; - e.mouse.x = 555; - e.mouse.y = 100; - ui_dispatch_event(&e); - lcui_ui_update(); - - ctest_equal_bool("the content should have scrolled to the bottom", - content->computed_style.left == left && - top < content->computed_style.top, - true); - - lcui_quit(); - lcui_main(); -} diff --git a/tests/cases/test_settings.c b/tests/cases/test_settings.c deleted file mode 100644 index 0adb3bee3..000000000 --- a/tests/cases/test_settings.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * tests/cases/test_settings.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include -#include - -static void check_settings_fps_cap(void *arg) -{ - char str[256]; - int fps_limit = *((int *)arg); - int fps = (int)lcui_get_fps(); - - sprintf(str, "should work when frame cap is %u (actual %u)", fps_limit, - fps); - ctest_equal_bool(str, fps <= fps_limit + 2 && fps > fps_limit / 2, true); - lcui_quit(); -} - -static void test_default_settings(void) -{ - lcui_settings_t settings; - - lcui_init(); - lcui_reset_settings(); - lcui_get_settings(&settings); - - ctest_equal_int("check default frame rate cap", settings.fps_cap, 120); - ctest_equal_int("check default parallel rendering threads", - settings.parallel_rendering_threads, 4); - ctest_equal_bool("check default paint flashing", settings.paint_flashing, false); - lcui_quit(); - lcui_main(); -} - -static void test_apply_settings(void) -{ - lcui_settings_t settings; - - settings.fps_cap = 60; - settings.parallel_rendering_threads = 2; - settings.paint_flashing = true; - - lcui_init(); - lcui_apply_settings(&settings); - lcui_get_settings(&settings); - ctest_equal_int("check frame rate cap", settings.fps_cap, 60); - ctest_equal_int("check parallel rendering threads", - settings.parallel_rendering_threads, 2); - ctest_equal_bool("check paint flashing", settings.paint_flashing, true); - - settings.fps_cap = -1; - settings.parallel_rendering_threads = -1; - - lcui_apply_settings(&settings); - lcui_get_settings(&settings); - - ctest_equal_int("check frame rate cap minimum", settings.fps_cap, 1); - ctest_equal_int("check parallel rendering threads minimum", - settings.parallel_rendering_threads, 1); - - lcui_reset_settings(); - - lcui_get_settings(&settings); - ctest_equal_int("check frame rate cap", settings.fps_cap, LCUI_MAX_FRAMES_PER_SEC); - lcui_quit(); - lcui_main(); -} - -void test_settings_fps_cap(void) -{ - lcui_settings_t settings; - - lcui_init(); - lcui_get_settings(&settings); - - settings.fps_cap = 30; - lcui_apply_settings(&settings); - ptk_set_timeout(2000, check_settings_fps_cap, - &settings.fps_cap); - lcui_main(); - - lcui_init(); - settings.fps_cap = 5; - lcui_apply_settings(&settings); - ptk_set_timeout(2000, check_settings_fps_cap, - &settings.fps_cap); - lcui_main(); - - lcui_init(); - settings.fps_cap = 90; - lcui_apply_settings(&settings); - ptk_set_timeout(2000, check_settings_fps_cap, - &settings.fps_cap); - lcui_main(); - - lcui_init(); - settings.fps_cap = 25; - lcui_apply_settings(&settings); - ptk_set_timeout(2000, check_settings_fps_cap, - &settings.fps_cap); - lcui_main(); -} - -void test_settings(void) -{ - ctest_describe("test default settings", test_default_settings); - ctest_describe("test apply settings", test_apply_settings); - ctest_describe("test settings.fps_cap", test_settings_fps_cap); -} diff --git a/tests/cases/test_textinput.c b/tests/cases/test_textinput.c deleted file mode 100644 index 8ae62b378..000000000 --- a/tests/cases/test_textinput.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * tests/cases/test_textinput.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include - -void test_textinput(void) -{ - ui_widget_t* w; - wchar_t wcs[64]; - - lcui_init(); - - w = ui_create_widget("textinput"); - - ui_textinput_set_text_w(w, L"hello"); - ui_widget_update(w); - ctest_equal_bool("check TextEdit_GetLength after ui_textinput_set_text_w", - ui_textinput_get_text_length(w) == wcslen(L"hello"), true); - ctest_equal_bool("check ui_textinput_get_text_w after ui_textinput_set_text_w", - ui_textinput_get_text_w(w, 0, 64, wcs) == wcslen(L"hello"), true); - ctest_equal_bool("check string retrieved from ui_textinput_get_text_w", - wcscmp(L"hello", wcs) == 0, true); - - ui_widget_set_text(w, "hello"); - ui_widget_update(w); - ctest_equal_bool("check TextEdit_GetLength after ui_textinput_set_text", - ui_textinput_get_text_length(w) == wcslen(L"hello"), true); - ctest_equal_bool("check ui_textinput_get_text_w after ui_textinput_set_text", - ui_textinput_get_text_w(w, 0, 64, wcs) == wcslen(L"hello"), true); - ctest_equal_bool("check string retrieved from ui_textinput_get_text_w", - wcscmp(L"hello", wcs) == 0, true); - - ui_textinput_append_text_w(w, L"world"); - ui_widget_update(w); - ctest_equal_bool("check TextEdit_GetLength after ui_textinput_append_text_w", - ui_textinput_get_text_length(w) == wcslen(L"helloworld"), true); - ctest_equal_bool("check ui_textinput_get_text_w after ui_textinput_append_text_w", - ui_textinput_get_text_w(w, 0, 64, wcs) == wcslen(L"helloworld"), true); - ctest_equal_bool("check string retrieved from ui_textinput_get_text_w", - wcscmp(L"helloworld", wcs) == 0, true); - - ui_textinput_move_caret(w, 0, 5); - ui_textinput_insert_text_w(w, L", "); - ui_widget_update(w); - ui_textinput_move_caret(w, 0, 100); - ui_textinput_insert_text_w(w, L"!"); - ui_widget_update(w); - ctest_equal_bool("check TextEdit_GetLength after inserting text", - ui_textinput_get_text_length(w) == wcslen(L"hello, world!"), true); - ctest_equal_bool("check ui_textinput_get_text_w after inserting text", - ui_textinput_get_text_w(w, 0, 64, wcs) == wcslen(L"hello, world!"), - true); - ctest_equal_bool("check string retrieved from ui_textinput_get_text_w", - wcscmp(L"hello, world!", wcs) == 0, true); - ui_widget_destroy(w); - lcui_quit(); - lcui_main(); -} diff --git a/tests/cases/test_thread.c b/tests/cases/test_thread.c deleted file mode 100644 index 2395a7d8d..000000000 --- a/tests/cases/test_thread.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * tests/cases/test_thread.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include -#include -#include - -typedef struct TestWorkerRec_ { - char data[32]; - int data_count; - bool cancel; - bool active; - thread_cond_t cond; - thread_mutex_t mutex; - thread_t thread; -} TestWorkerRec, *TestWorker; - -static void TestWorker_Thread(void *arg) -{ - TestWorker worker = arg; - - worker->cancel = false; - worker->active = true; - worker->data_count = 0; - thread_mutex_lock(&worker->mutex); - while (!worker->cancel && worker->data_count < 20) { - logger_debug("waiting...\n"); - thread_cond_wait(&worker->cond, &worker->mutex); - logger_debug("get data: %s\n", worker->data); - worker->data_count += 1; - } - thread_mutex_unlock(&worker->mutex); - logger_debug("count: %d\n", worker->data_count); - worker->active = false; - thread_exit(NULL); -} - -static void TestWorker_Send(TestWorker worker, const char *data) -{ - thread_mutex_lock(&worker->mutex); - strcpy(worker->data, data); - thread_cond_signal(&worker->cond); - thread_mutex_unlock(&worker->mutex); -} - -static void TestWorker_Init(TestWorker worker) -{ - thread_mutex_init(&worker->mutex); - thread_cond_init(&worker->cond); -} - -static void TestWorker_Destroy(TestWorker worker) -{ - thread_mutex_lock(&worker->mutex); - worker->cancel = true; - thread_cond_signal(&worker->cond); - thread_mutex_unlock(&worker->mutex); - thread_join(worker->thread, NULL); - thread_mutex_destroy(&worker->mutex); - thread_cond_destroy(&worker->cond); -} - -void test_thread(void) -{ - TestWorkerRec worker; - - TestWorker_Init(&worker); - thread_create(&worker.thread, TestWorker_Thread, &worker); - sleep_ms(100); - TestWorker_Send(&worker, "hello"); - sleep_ms(20); - TestWorker_Send(&worker, "world"); - sleep_ms(100); - TestWorker_Send(&worker, "this"); - sleep_ms(50); - TestWorker_Send(&worker, "is"); - sleep_ms(100); - TestWorker_Send(&worker, "test"); - sleep_ms(50); - TestWorker_Send(&worker, "bye!"); - sleep_ms(100); - TestWorker_Destroy(&worker); - ctest_equal_int("check worker data count", worker.data_count, 7); - ctest_equal_bool("check worker is no longer active", worker.active, false); -} diff --git a/tests/cases/test_widget_event.c b/tests/cases/test_widget_event.c deleted file mode 100644 index 5e3bb7505..000000000 --- a/tests/cases/test_widget_event.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * tests/cases/test_widget_event.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include -#include -#include - -void test_widget_mouse_event(void) -{ - ui_widget_t *root; - ui_widget_t *parent, *child; - ui_event_t ev; - - lcui_init(); - root = ui_root(); - parent = ui_create_widget("button"); - child = ui_create_widget("text"); - - ui_widget_resize(root, 200, 200); - ui_widget_resize(parent, 100, 100); - ui_widget_resize(child, 50, 50); - ui_widget_append(parent, child); - ui_widget_append(root, parent); - ui_update(); - - ev.type = UI_EVENT_MOUSEMOVE; - ev.mouse.x = 150; - ev.mouse.y = 150; - ui_dispatch_event(&ev); - ui_update(); - ctest_equal_bool("mousemove(150, 150): root.hasStatus('hover') == true", - ui_widget_has_status(root, "hover"), true); - ctest_equal_bool("mousemove(150, 150): parent.hasStatus('hover') == false", - ui_widget_has_status(parent, "hover"), false); - ctest_equal_bool("mousemove(150, 150): child.hasStatus('hover') == false", - ui_widget_has_status(child, "hover"), false); - - ev.mouse.x = 80; - ev.mouse.y = 80; - ui_dispatch_event(&ev); - ui_update(); - ctest_equal_bool("mousemove(80, 80): root.hasStatus('hover') == true", - ui_widget_has_status(root, "hover"), true); - ctest_equal_bool("mousemove(80, 80): parent.hasStatus('hover') == true", - ui_widget_has_status(parent, "hover"), true); - ctest_equal_bool("mousemove(80, 80): child.hasStatus('hover') == false", - ui_widget_has_status(child, "hover"), false); - - ev.mouse.x = 40; - ev.mouse.y = 40; - ui_dispatch_event(&ev); - ui_update(); - ctest_equal_bool("mousemove(40, 40): root.hasStatus('hover') == true", - ui_widget_has_status(root, "hover"), true); - ctest_equal_bool("mousemove(40, 40): parent.hasStatus('hover') == true", - ui_widget_has_status(parent, "hover"), true); - ctest_equal_bool("mousemove(40, 40): child.hasStatus('hover') == true", - ui_widget_has_status(child, "hover"), true); - - ev.type = UI_EVENT_MOUSEDOWN; - ev.mouse.x = 40; - ev.mouse.y = 40; - ev.mouse.button = MOUSE_BUTTON_LEFT; - ui_dispatch_event(&ev); - ui_update(); - ctest_equal_bool("mousedown(40, 40): root.hasStatus('active') == true", - ui_widget_has_status(root, "active"), true); - ctest_equal_bool("mousedown(40, 40): parent.hasStatus('active') == true", - ui_widget_has_status(parent, "active"), true); - ctest_equal_bool("mousedown(40, 40): child.hasStatus('active') == true", - ui_widget_has_status(child, "active"), true); - - ev.type = UI_EVENT_MOUSEUP; - ui_dispatch_event(&ev); - ui_update(); - ctest_equal_bool("mouseup(40, 40): root.hasStatus('active') == false", - ui_widget_has_status(root, "active"), false); - ctest_equal_bool("mouseup(40, 40): parent.hasStatus('active') == false", - ui_widget_has_status(parent, "active"), false); - ctest_equal_bool("mouseup(40, 40): child.hasStatus('active') == false", - ui_widget_has_status(child, "active"), false); - - ev.type = UI_EVENT_MOUSEMOVE; - ev.mouse.x = 80; - ev.mouse.y = 80; - ui_dispatch_event(&ev); - ui_update(); - ctest_equal_bool("mousemove(80, 80): root.hasStatus('hover') == true", - ui_widget_has_status(root, "hover"), true); - ctest_equal_bool("mousemove(80, 80): parent.hasStatus('hover') == true", - ui_widget_has_status(parent, "hover"), true); - ctest_equal_bool("mousemove(80, 80): child.hasStatus('hover') == false", - ui_widget_has_status(child, "hover"), false); - - ev.mouse.x = 150; - ev.mouse.y = 150; - ui_dispatch_event(&ev); - ui_update(); - ctest_equal_bool("mousemove(150, 150): root.hasStatus('hover') == true", - ui_widget_has_status(root, "hover"), true); - ctest_equal_bool("mousemove(150, 150): parent.hasStatus('hover') == false", - ui_widget_has_status(parent, "hover"), false); - ctest_equal_bool("mousemove(150, 150): child.hasStatus('hover') == false", - ui_widget_has_status(child, "hover"), false); - - lcui_quit(); - lcui_main(); -} - -void test_widget_event(void) -{ - ctest_describe("test widget mouse event", test_widget_mouse_event); -} diff --git a/tests/cases/test_widget_rect.c b/tests/cases/test_widget_rect.c deleted file mode 100644 index 9207ff9ea..000000000 --- a/tests/cases/test_widget_rect.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * tests/cases/test_widget_rect.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include -#include -#include -#include -#include - -void test_widget_rect(void) -{ - ui_widget_t *root; - ui_widget_t *parent, *child; - ui_event_t e = { 0 }; - pd_rect_t rect = { 0 }; - pd_rect_t expected_rect; - ui_rect_t expected_ui_rect; - list_t rects; - - lcui_init(); - root = ui_root(); - parent = ui_create_widget("button"); - child = ui_create_widget("text"); - - ui_widget_set_style_keyword_value(parent, css_prop_box_sizing, - CSS_KEYWORD_BORDER_BOX); - ui_widget_resize(root, 200, 200); - ui_widget_resize(parent, 100, 100); - ui_widget_resize(child, 50, 50); - ui_widget_append(parent, child); - ui_widget_append(root, parent); - ui_update(); - - list_create(&rects); - ui_widget_get_dirty_rects(root, &rects); - list_destroy(&rects, free); - - e.type = UI_EVENT_MOUSEMOVE; - e.mouse.x = 150; - e.mouse.y = 150; - ui_dispatch_event(&e); - ui_update(); - ui_widget_get_dirty_rects(root, &rects); - ctest_equal_bool("app.trigger({ type: 'mousemove', x: 150, y: 150}), " - "root.getDirtyRects().length == 0", - rects.length == 0, true); - - e.mouse.x = 80; - e.mouse.y = 80; - ui_dispatch_event(&e); - ui_update(); - ui_widget_get_dirty_rects(root, &rects); - ctest_equal_bool("app.trigger({ type: 'mousemove', x: 80, y: 80 }), " - "root.getDirtyRects().length == 1", - rects.length == 1, true); - - expected_ui_rect.x = 0; - expected_ui_rect.y = 0; - expected_ui_rect.width = 100; - expected_ui_rect.height = 100; - ui_compute_rect(&expected_rect, &expected_ui_rect); - if (rects.length == 1) { - rect = *(pd_rect_t *)list_get(&rects, 0); - } - ctest_equal_pd_rect("root.getDirtyRects()[0]", &rect, &expected_rect); - list_destroy(&rects, free); - - e.mouse.x = 40; - e.mouse.y = 40; - ui_dispatch_event(&e); - ui_update(); - ui_widget_get_dirty_rects(root, &rects); - ctest_equal_bool("app.trigger({ type: 'mousemove', x: 40, y: 40 }), " - "root.getDirtyRects().length == 0", - rects.length == 0, true); - - e.type = UI_EVENT_MOUSEDOWN; - e.mouse.x = 40; - e.mouse.y = 40; - e.mouse.button = MOUSE_BUTTON_LEFT; - ui_dispatch_event(&e); - ui_update(); - ui_widget_get_dirty_rects(root, &rects); - ctest_equal_bool("app.trigger({ type: 'mousedown', x: 40, y: 40 }), " - "root.getDirtyRects().length == 1", - rects.length == 1, true); - if (rects.length == 1) { - rect = *(pd_rect_t *)list_get(&rects, 0); - } - ctest_equal_pd_rect("root.getDirtyRects()[0]", &rect, &expected_rect); - list_destroy(&rects, free); - - e.type = UI_EVENT_MOUSEUP; - ui_dispatch_event(&e); - ui_update(); - ui_widget_get_dirty_rects(root, &rects); - ctest_equal_bool("app.trigger({ type: 'mouseup', x: 40, y: 40 }), " - "root.getDirtyRects().length == 1", - rects.length == 1, true); - if (rects.length == 1) { - rect = *(pd_rect_t *)list_get(&rects, 0); - } - ctest_equal_pd_rect("root.getDirtyRects()[0]", &rect, &expected_rect); - list_destroy(&rects, free); - - e.type = UI_EVENT_MOUSEMOVE; - e.mouse.x = 80; - e.mouse.y = 80; - ui_dispatch_event(&e); - ui_update(); - ui_widget_get_dirty_rects(root, &rects); - ctest_equal_bool("app.trigger({ type: 'mousemove', x: 80, y: 80 }), " - "root.getDirtyRects().length == 0", - rects.length == 0, true); - - e.mouse.x = 150; - e.mouse.y = 150; - ui_dispatch_event(&e); - ui_update(); - ui_widget_get_dirty_rects(root, &rects); - - ctest_equal_bool("app.trigger({ type: 'mousemove', x: 150, y: 150 }), " - "root.getDirtyRects().length == 1", - rects.length == 1, true); - if (rects.length == 1) { - rect = *(pd_rect_t *)list_get(&rects, 0); - } - ctest_equal_pd_rect("root.getDirtyRects()[0]", &rect, &expected_rect); - list_destroy(&rects, free); - - expected_ui_rect.x = 21; - expected_ui_rect.y = 11; - expected_ui_rect.width = 50; - expected_ui_rect.height = 50; - ui_compute_rect(&expected_rect, &expected_ui_rect); - ui_widget_remove(child); - ui_update(); - ui_widget_get_dirty_rects(root, &rects); - ctest_equal_bool("child.destroy(), root.getDirtyRects().length == 1", - rects.length == 1, true); - if (rects.length == 1) { - rect = *(pd_rect_t *)list_get(&rects, 0); - } - ctest_equal_pd_rect("root.getDirtyRects()[0]", &rect, &expected_rect); - list_destroy(&rects, free); - - expected_ui_rect.x = 0; - expected_ui_rect.y = 0; - expected_ui_rect.width = 100; - expected_ui_rect.height = 100; - ui_compute_rect(&expected_rect, &expected_ui_rect); - ui_widget_remove(parent); - ui_update(); - ui_widget_get_dirty_rects(root, &rects); - ctest_equal_bool("parent.destroy(), root.getDirtyRects().length == 1", - rects.length == 1, true); - if (rects.length == 1) { - rect = *(pd_rect_t *)list_get(&rects, 0); - } - ctest_equal_pd_rect("root.getDirtyRects()[0]", &rect, &expected_rect); - list_destroy(&rects, free); - - lcui_destroy(); -} diff --git a/tests/cases/test_xml_parser.c b/tests/cases/test_xml_parser.c deleted file mode 100644 index b8f91d8a1..000000000 --- a/tests/cases/test_xml_parser.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * tests/cases/test_xml_parser.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include - -static void check_widget_attribute(void) -{ - ui_widget_t* w; - - w = ui_get_widget("test-attr-disabled-1"); - ctest_equal_bool("check element-1 is disabled", w->disabled, true); - w = ui_get_widget("test-attr-disabled-2"); - ctest_equal_bool("check element-2 is disabled", w->disabled, true); - w = ui_get_widget("test-attr-disabled-3"); - ctest_equal_bool("check element-3 is disabled", w->disabled, true); - w = ui_get_widget("test-attr-disabled-4"); - ctest_equal_bool("check element-4 is normal", w->disabled, false); -} - -static void check_widget_loaded_from_nested_xml(void) -{ - ui_widget_t* w; - - w = ui_get_widget("test-nested-1"); - ctest_equal_bool("check test-nested-1 should exist", w != NULL, true); - w = ui_get_widget("test-nested-2"); - ctest_equal_bool("check test-nested-2 should exist", w != NULL, true); - w = ui_get_widget("test-nested-3"); - ctest_equal_bool("check test-nested-3 should exist", w != NULL, true); - w = ui_get_widget("test-nested-4"); - ctest_equal_bool("check test-nested-4 should exist", w != NULL, true); -} - -void test_xml_parser(void) -{ - ui_widget_t *pack; - - ui_init(); - ctest_equal_bool("load XML file", - (pack = ui_load_xml_file("test_xml_parser.xml")) != NULL, - true); - if (!pack) { - lcui_destroy(); - return; - } - ui_root_append(pack); - ui_widget_unwrap(pack); - ui_update(); - ctest_describe("check widget attribute", check_widget_attribute); - ctest_describe("check widget loaded from nested xml", - check_widget_loaded_from_nested_xml); - ui_destroy(); -} diff --git a/tests/test_block_layout.css b/tests/fixtures/test_block_layout.css similarity index 100% rename from tests/test_block_layout.css rename to tests/fixtures/test_block_layout.css diff --git a/tests/test_block_layout.xml b/tests/fixtures/test_block_layout.xml similarity index 100% rename from tests/test_block_layout.xml rename to tests/fixtures/test_block_layout.xml diff --git a/tests/test_flex_layout.css b/tests/fixtures/test_flex_layout.css similarity index 100% rename from tests/test_flex_layout.css rename to tests/fixtures/test_flex_layout.css diff --git a/tests/test_flex_layout.xml b/tests/fixtures/test_flex_layout.xml similarity index 100% rename from tests/test_flex_layout.xml rename to tests/fixtures/test_flex_layout.xml diff --git a/tests/test_font_load.css b/tests/fixtures/test_font_face.css similarity index 71% rename from tests/test_font_load.css rename to tests/fixtures/test_font_face.css index 56f534d75..0eb67cbcc 100644 --- a/tests/test_font_load.css +++ b/tests/fixtures/test_font_face.css @@ -2,5 +2,5 @@ font-family: icomoon; font-weight: normal; font-style: normal; - src: url("test_font_load.ttf"); + src: url("test_font_face.ttf"); } diff --git a/tests/fixtures/test_font_face.ttf b/tests/fixtures/test_font_face.ttf new file mode 100644 index 0000000000000000000000000000000000000000..db2abdcbe836b0b836a2382dc5513dcd07dd43ce GIT binary patch literal 4496 zcmb_gO>7%Q6n?WC|HWO$k=NcN_8P}O>%<9;>G|Sxo^P{$ zfIMb!FXXQ;fdKCz{}u9{#r#6y_A%3+$lt>?US2A$uHim0wbJn(VA=1;YoG&QZZlt_ zd%2(q(kO2RBQW?Q zxSN5>R;5A*AsvxvQu(FwJ&x1POMqan7LAMnNDatcw)_3N48ORt*#x+2C#2vMT!N4fhT0~QB5{oAHjNFG+Of=|B+C?$j-PPOM)twbZ z`=mHKJUrU~W_K0bt1AS`_o6<234&AOT+?gL8YiCwDGze9JZ zomy@jFPj2O9Xpju+O&5N!3vW^Rf6=Mp<9oK`;IxCEk;p1JCM%whPp@HZo%pIo$2d) zy?R^9cOQ#3Gc46JmT8VQfZ^8d=GNB7T`td|RPsqdIA9LB-G2K4&crfgSv6R^-P+{V z37wsS&fR3Sqt~smU88Uk&cFqD9yS_BmQ}sP6GU+Z!$gNJ1Tl;WKFsJx5;0y+(xg91 z&j39FItR36NGIaxY0%5alFt9?vFC&Mjpws{;Y2AB?#uFgIm7#{PO-FED&4gD`I5L* zHkyepzQ=FbFNKthBj#vqdm`DrHHp z$>{X^oko+%s59vzBO?*4C|6I4Ap*t^S|9$@qj+##)FBdH-$T4o!l%^3B%Z|MM0t$f z1QrkLA9o}L(G~6aD9AIMP3kChNF}+nahsg2WaFl?Yu=>lj{HX-^9u0>(A~g!IwYxs z<|)o*<2)YDR)&#ur{a#RmQ=GDF{}04$Kfix)VS6Y#jftKwyZ<;+HRuwqr?#D$EXUG zKIsrT4-!GveIdfD&GBSPzAAf%(;+);afd;+u^h*_Ek+ZyGECgn(L*?aEi8_c-etKBkOl?u^y`u5(xyJ7mTlKv7WnKktXo zSRye-GeP*2sI~kkuZ67*Wx6r)rsicpUkMZs^&Mus|FL+fW#|EzQQI;7cqnmqyQVKN zSx#SoO2TpSds30pa{EQ6^sp#1DGVJ(`TvvU5zWAZ8$Kte$%#Tl)}7a9_1|DC zUC9FP()a*Vbw@Iz78dwO-46i+%9On^NKdIWi*!<@n~+{tX&wGUU{`59%Ewf?89Lw< z`o3*4p~QkM3XN9<=2V(RdRV2KkbYLBb>IMe!OLUyD4$g6W{AW4SEq{$#o{6w_-QD@ z0_Gwt<_asTSBs0D{%{0x_+nduRqTKbI8Q%>AyRi#UEyS5Zhbz#f{PY#qw6pad0462 zGh19-^UM_%3oH4x!i?wg4bSLw@i^`+3|V>YHC%lTr&*MDl!rB}XHa$-ZeTeof536& P18|SZKMLAY*+Kses8SD~ literal 0 HcmV?d00001 diff --git a/tests/test_scrollbar.xml b/tests/fixtures/test_scrollbar.xml similarity index 100% rename from tests/test_scrollbar.xml rename to tests/fixtures/test_scrollbar.xml diff --git a/tests/test_widget_opacity.css b/tests/fixtures/test_widget_opacity.css similarity index 100% rename from tests/test_widget_opacity.css rename to tests/fixtures/test_widget_opacity.css diff --git a/tests/test_widget_opacity.xml b/tests/fixtures/test_widget_opacity.xml similarity index 100% rename from tests/test_widget_opacity.xml rename to tests/fixtures/test_widget_opacity.xml diff --git a/tests/include/ctest-custom.h b/tests/helpers/ctest-custom.h similarity index 60% rename from tests/include/ctest-custom.h rename to tests/helpers/ctest-custom.h index 6a619f5bb..0ff21c9cf 100644 --- a/tests/include/ctest-custom.h +++ b/tests/helpers/ctest-custom.h @@ -15,13 +15,15 @@ #include static inline bool ctest_equal_pd_rect(const char *name, pd_rect_t *actual, - pd_rect_t *expected) + pd_rect_t *expected) { - return ctest_equal(name, (ctest_to_str_func_t)pd_rect_to_str, actual, expected); + return ctest_equal(name, (ctest_to_str_func_t)pd_rect_to_str, actual, + expected); } static inline bool ctest_equal_ui_rect(const char *name, ui_rect_t *actual, - ui_rect_t *expected) + ui_rect_t *expected) { - return ctest_equal(name, (ctest_to_str_func_t)ui_rect_to_str, actual, expected); + return ctest_equal(name, (ctest_to_str_func_t)ui_rect_to_str, actual, + expected); } diff --git a/tests/cases/test_block_layout.c b/tests/integration/test_block_layout.c similarity index 96% rename from tests/cases/test_block_layout.c rename to tests/integration/test_block_layout.c index d50112a05..f1bf13539 100644 --- a/tests/cases/test_block_layout.c +++ b/tests/integration/test_block_layout.c @@ -11,6 +11,7 @@ #include #include +#include "../scenes/block_layout_scene.h" #define SCROLLBAR_WIDTH 14 @@ -86,14 +87,14 @@ static void test_auto_size(void) (int)w->border_box.y, 5 + two_lines_box_height); w = ui_widget_next(w); - ctest_equal_int( - "$('#test-text-block-auto-height')[0].border_box.y", - (int)w->border_box.y, - 5 + two_lines_box_height + box_height); + ctest_equal_int("$('#test-text-block-auto-height')[0].border_box.y", + (int)w->border_box.y, + 5 + two_lines_box_height + box_height); - ctest_equal_int("$('.example')[2].border_box.height", - (int)example->border_box.height, - two_lines_box_height + 2 * box_height + container_height); + ctest_equal_int( + "$('.example')[2].border_box.height", + (int)example->border_box.height, + two_lines_box_height + 2 * box_height + container_height); // Update #test-text-auto-size content @@ -115,12 +116,12 @@ static void test_auto_size(void) w = ui_widget_next(w); ctest_equal_int("$('#test-text-block-auto-height')[0].border_box.y", - (int)w->border_box.y, - 5 + two_lines_box_height * 2); + (int)w->border_box.y, 5 + two_lines_box_height * 2); - ctest_equal_int("$('.example')[2].border_box.height", - (int)example->border_box.height, - container_height + box_height + 2 * two_lines_box_height); + ctest_equal_int( + "$('.example')[2].border_box.height", + (int)example->border_box.height, + container_height + box_height + 2 * two_lines_box_height); // Update test-text-block-auto-height content @@ -484,10 +485,10 @@ static void test_block_layout_1280(void) ctest_equal_int("$('#test-text-block-auto-height')[0].height", (int)w->border_box.height, (int)rect.height); - ctest_describe("test auto size", test_auto_size); - ctest_describe("test dropdown", test_dropdown); - ctest_describe("test inline block nesting", test_inline_block_nesting); - ctest_describe("test absolutely positioned progress bar", + ctest_describe("auto size", test_auto_size); + ctest_describe("dropdown", test_dropdown); + ctest_describe("inline block nesting", test_inline_block_nesting); + ctest_describe("absolutely positioned progress bar", test_absolutely_positioned_progress_bar); } @@ -814,22 +815,12 @@ static void test_block_layout_320(void) void test_block_layout(void) { - ui_widget_t *root; - ui_widget_t *wrapper; - lcui_init(); - wrapper = ui_load_xml_file("test_block_layout.xml"); - root = ui_root(); - ui_widget_append(root, wrapper); - ui_widget_unwrap(wrapper); - ui_update(); + block_layout_scene_build(); ctest_describe("root width 1280px", test_block_layout_1280); ctest_describe("root width 600px", test_block_layout_600); ctest_describe("root width 320px", test_block_layout_320); -#ifndef PREVIEW_MODE - lcui_quit(); - lcui_main(); -#endif + lcui_destroy(); } diff --git a/tests/cases/test_clipboard.c b/tests/integration/test_clipboard.c similarity index 94% rename from tests/cases/test_clipboard.c rename to tests/integration/test_clipboard.c index 695e1444a..039887240 100644 --- a/tests/cases/test_clipboard.c +++ b/tests/integration/test_clipboard.c @@ -49,7 +49,8 @@ static void on_check_text(ui_widget_t *w, ui_event_t *e, void *arg) if (clipboard && clipboard->text) { encode_utf8(actual_text, clipboard->text, 31); } - ctest_equal_str("check the pasted text", actual_text, "helloworld"); + ctest_equal_str("should paste the copied text", actual_text, + "helloworld"); lcui_quit(); } diff --git a/tests/integration/test_flex_layout.c b/tests/integration/test_flex_layout.c new file mode 100644 index 000000000..c5fd5b67b --- /dev/null +++ b/tests/integration/test_flex_layout.c @@ -0,0 +1,789 @@ +/* + * tests/cases/test_flex_layout.c + * + * Copyright (c) 2023, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include "../scenes/flex_layout_scene.h" + +#define SCROLLBAR_WIDTH 14 + +static void test_flex_layout_with_content_width(float width) +{ + float content_width = width - 22; + + ui_widget_t *w; + ui_widget_t *content; + ui_widget_t *example; + ui_widget_t *container; + ui_rect_t rect; + + container = ui_widget_get_child(ui_get_widget("main"), 0); + ui_update(); + + rect.y = 10; + rect.x = 10; + rect.width = width; + rect.height = 104; + w = ui_widget_get_child(container, 0); + ctest_equal_ui_rect("$('.example')[0].border_box", &w->border_box, + &rect); + + rect.y += 114; + w = ui_widget_get_child(container, 1); + ctest_equal_ui_rect("$('.example')[1].border_box", &w->border_box, + &rect); + + rect.y += 114; + w = ui_widget_get_child(container, 2); + ctest_equal_ui_rect("$('.example')[2].border_box", &w->border_box, + &rect); + + rect.y += 114; + w = ui_widget_get_child(container, 3); + ctest_equal_ui_rect("$('.example')[3].border_box", &w->border_box, + &rect); + + rect.y += 114; + w = ui_widget_get_child(container, 4); + ctest_equal_ui_rect("$('.example')[4].border_box", &w->border_box, + &rect); + + rect.y += 114; + w = ui_widget_get_child(container, 5); + ctest_equal_ui_rect("$('.example')[5].border_box", &w->border_box, + &rect); + + rect.y += 114; + w = ui_widget_get_child(container, 6); + ctest_equal_ui_rect("$('.example')[6].border_box", &w->border_box, + &rect); + + rect.y += 114; + rect.height = 344; + w = ui_widget_get_child(container, 7); + ctest_equal_ui_rect("$('.example')[7].border_box", &w->border_box, + &rect); + + rect.y += rect.height + 10; + rect.height = 204; + w = ui_widget_get_child(container, 8); + ctest_equal_ui_rect("$('.example')[8].border_box", &w->border_box, + &rect); + + rect.y += rect.height + 10; + rect.height = 354; + w = ui_widget_get_child(container, 9); + ctest_equal_ui_rect("$('.example')[9].border_box", &w->border_box, + &rect); + + rect.y += rect.height + 10; + rect.height = 354; + w = ui_widget_get_child(container, 10); + ctest_equal_ui_rect("$('.example')[10].border_box", &w->border_box, + &rect); + + rect.y += rect.height + 10; + rect.height = 354; + w = ui_widget_get_child(container, 11); + ctest_equal_ui_rect("$('.example')[11].border_box", &w->border_box, + &rect); + + rect.y += rect.height + 10; + rect.height = 354; + w = ui_widget_get_child(container, 12); + ctest_equal_ui_rect("$('.example')[12].border_box", &w->border_box, + &rect); + + rect.y += rect.height + 10; + rect.height = 354; + w = ui_widget_get_child(container, 13); + ctest_equal_ui_rect("$('.example')[13].border_box", &w->border_box, + &rect); + + rect.y += rect.height + 10; + rect.height = 254; + w = ui_widget_get_child(container, 14); + ctest_equal_ui_rect("$('.example')[14].border_box", &w->border_box, + &rect); + + rect.y += rect.height + 10; + rect.height = 184; + w = ui_widget_get_child(container, 15); + ctest_equal_ui_rect("$('.example')[15].border_box", &w->border_box, + &rect); + + rect.y += rect.height + 10; + rect.height = 354; + w = ui_widget_get_child(container, 16); + ctest_equal_ui_rect("$('.example')[16].border_box", &w->border_box, + &rect); + + // (1) justify-content: center;; + + example = ui_widget_get_child(container, 1); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + rect.x = 5 + (content_width - 300) / 2.f; + rect.y = 5; + rect.width = 50; + rect.height = 50; + ctest_equal_ui_rect("$('.example:eq(1) .box')[0].border_box", + &w->border_box, &rect); + + // (2) justify-content: flex-end; + + example = ui_widget_get_child(container, 2); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + rect.x = 5 + (content_width - 300); + ctest_equal_ui_rect("$('.example:eq(2) .box')[0].border_box", + &w->border_box, &rect); + + // (3) justify-content: space-between; + + example = ui_widget_get_child(container, 3); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + rect.x = 5; + ctest_equal_ui_rect("$('.example:eq(3) .box')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x = 5 + 50 + (content_width - 300) / 5.f; + ctest_equal_ui_rect("$('.example:eq(3) .box')[1].border_box", + &w->border_box, &rect); + + w = ui_widget_get_child(content, 5); + rect.x = 5 + (content_width - 50); + ctest_equal_ui_rect("$('.example:eq(3) .box')[5].border_box", + &w->border_box, &rect); + + // (4) justify-content: space-around; + + example = ui_widget_get_child(container, 4); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + rect.x = 5 + (content_width - 300) / 6.f / 2.f; + ctest_equal_ui_rect("$('.example:eq(4) .box')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += 50 + (content_width - 300) / 6.f; + ctest_equal_ui_rect("$('.example:eq(4) .box')[1].border_box", + &w->border_box, &rect); + + w = ui_widget_get_child(content, 5); + rect.x = 5 + content_width - (content_width - 300) / 6.f / 2.f - 50; + ctest_equal_ui_rect("$('.example:eq(4) .box')[5].border_box", + &w->border_box, &rect); + + // (5) Auto margin + + example = ui_widget_get_child(container, 5); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + rect.x = 5; + ctest_equal_ui_rect("$('.example:eq(5) .box')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += 50 + (content_width - 200) / 2.f; + ctest_equal_ui_rect("$('.example:eq(5) .box')[1].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += 50; + ctest_equal_ui_rect("$('.example:eq(5) .box')[2].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += 50 + (content_width - 200) / 2.f; + ctest_equal_ui_rect("$('.example:eq(5) .box')[3].border_box", + &w->border_box, &rect); + + // (7) flex-grow + + example = ui_widget_get_child(container, 7); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + rect.x = 5; + rect.width = content_width / 3.f; + ctest_equal_ui_rect("$('.example:eq(7) .box')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += rect.width; + ctest_equal_ui_rect("$('.example:eq(7) .box')[1].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += rect.width; + ctest_equal_ui_rect("$('.example:eq(7) .box')[2].border_box", + &w->border_box, &rect); + + // line 1 + + content = ui_widget_get_child(example, 2); + w = ui_widget_get_child(content, 0); + rect.x = 5; + rect.width = content_width - 50 - 50; + ctest_equal_ui_rect("$('.example:eq(7) .box')[3].border_box", + &w->border_box, &rect); + + // line 2 + + content = ui_widget_get_child(example, 3); + w = ui_widget_get_child(content, 0); + rect.x = 5; + rect.width = (content_width - 50) / 2.f; + ctest_equal_ui_rect("$('.example:eq(7) .box')[6].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += rect.width; + ctest_equal_ui_rect("$('.example:eq(7) .box')[7].border_box", + &w->border_box, &rect); + + // line 3 + + content = ui_widget_get_child(example, 4); + w = ui_widget_get_child(content, 1); + rect.x = 5 + 50; + ctest_equal_ui_rect("$('.example:eq(7) .box')[10].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += rect.width; + ctest_equal_ui_rect("$('.example:eq(7) .box')[11].border_box", + &w->border_box, &rect); + + // line 4 + + content = ui_widget_get_child(example, 5); + w = ui_widget_get_child(content, 0); + rect.x = 5; + rect.width = 12 + (content_width - 3 * 12) * 4.f / 7.f; + ctest_equal_ui_rect("$('.example:eq(7) .box')[12].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += rect.width; + rect.width = 12 + (content_width - 3 * 12) * 2.f / 7.f; + ctest_equal_ui_rect("$('.example:eq(7) .box')[13].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += rect.width; + rect.width = 12 + (content_width - 3 * 12) / 7.f; + ctest_equal_ui_rect("$('.example:eq(7) .box')[14].border_box", + &w->border_box, &rect); + + // (10) align-items: center; height: 300px; + + example = ui_widget_get_child(container, 10); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + rect.x = 5; + rect.y = 5 + (300 / 3.f - 50) / 2.f; + rect.width = 50; + ctest_equal_ui_rect("$('.example:eq(10) .box')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += 50; + ctest_equal_ui_rect("$('.example:eq(10) .box')[1].border_box", + &w->border_box, &rect); + + // (11) align-items: end; height: 300px; + + example = ui_widget_get_child(container, 11); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + rect.x = 5; + rect.y = 5 + (300 / 3.f - 50); + rect.width = 50; + ctest_equal_ui_rect("$('.example:eq(11) .box')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += 50; + ctest_equal_ui_rect("$('.example:eq(11) .box')[1].border_box", + &w->border_box, &rect); + + // (12) align-items: stretch; height: 300px; + + example = ui_widget_get_child(container, 12); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + rect.x = 5; + rect.y = 5; + rect.width = 50; + rect.height = 100; + ctest_equal_ui_rect("$('.example:eq(12) .box')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += 50; + ctest_equal_ui_rect("$('.example:eq(12) .box')[1].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + w = ui_widget_next(w); + rect.x = 5 + 3 * 50; + rect.height = 50; + ctest_equal_ui_rect("$('.example:eq(12) .box')[3].border_box", + &w->border_box, &rect); + + // (13) Vertically Centered Layout + + example = ui_widget_get_child(container, 13); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + rect.x = 5 + (content_width - 50) / 2.f; + rect.y = 5 + (300 - 50) / 2.f; + rect.width = 50; + rect.height = 50; + ctest_equal_ui_rect("$('.example:eq(13) .box')[0].border_box", + &w->border_box, &rect); + + // (14) flex-direction: column; + + example = ui_widget_get_child(container, 14); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + rect.x = 5; + rect.y = 5; + rect.width = 50; + rect.height = 50; + ctest_equal_ui_rect("$('.example:eq(14) .box')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_get_child(content, 4); + rect.x = 5 + 50 + (content_width - 50 - 150 - 200 - 50 - 50) / 5.f; + rect.width = 150; + ctest_equal_ui_rect("$('.example:eq(14) .box')[4].border_box", + &w->border_box, &rect); + + w = ui_widget_get_child(content, 8); + rect.x += 150 + (content_width - 50 - 150 - 200 - 50 - 50) / 5.f; + rect.width = 50; + ctest_equal_ui_rect("$('.example:eq(14) .box')[8].border_box", + &w->border_box, &rect); + + // (15) Holy Grail Layout + + example = ui_widget_get_child(container, 15); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + rect.x = 5; + rect.y = 5; + rect.width = content_width; + rect.height = 50; + ctest_equal_ui_rect( + "$('.example:eq(15) .layout__header')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_get_child(content, 2); + rect.y = 5 + 50 + 30; + ctest_equal_ui_rect( + "$('.example:eq(15) .layout__footer')[0].border_box", + &w->border_box, &rect); + + rect.x = 0; + rect.y = 0; + rect.width = 100; + rect.height = 30; + w = ui_widget_get_child(content, 1); + w = ui_widget_get_child(w, 0); + ctest_equal_ui_rect("$('.example:eq(15) .layout__left')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x = 100; + rect.width = content_width - 100 - 100; + ctest_equal_ui_rect( + "$('.example:eq(15) .layout__center')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += rect.width; + rect.width = 100; + ctest_equal_ui_rect("$('.example:eq(15) .layout__right')[0].border_box", + &w->border_box, &rect); + + // (16) Holy Grail Layout (height: 300px) + + example = ui_widget_get_child(container, 16); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + rect.x = 5; + rect.y = 5; + rect.width = content_width; + rect.height = 50; + ctest_equal_ui_rect( + "$('.example:eq(16) .layout__header')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_get_child(content, 2); + rect.y = 5 + 50 + 200; + ctest_equal_ui_rect( + "$('.example:eq(16) .layout__footer')[0].border_box", + &w->border_box, &rect); + + rect.x = 0; + rect.y = 0; + rect.width = 100; + rect.height = 200; + w = ui_widget_get_child(content, 1); + w = ui_widget_get_child(w, 0); + ctest_equal_ui_rect("$('.example:eq(16) .layout__left')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x = 100; + rect.width = content_width - 100 - 100; + ctest_equal_ui_rect( + "$('.example:eq(16) .layout__center')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += rect.width; + rect.width = 100; + ctest_equal_ui_rect("$('.example:eq(16) .layout__right')[0].border_box", + &w->border_box, &rect); +} + +static void test_browser_layout(void) +{ + ui_widget_t *w; + ui_rect_t rect; + + w = ui_get_widget("browser-tabbar"); + w = ui_widget_get_child(w, 0); + ctest_equal_int("$('#browser-tabbar .c-frame-tab')[0].width", + (int)w->border_box.width, 101); + w = ui_widget_next(w); + ctest_equal_int("$('#browser-tabbar .c-frame-tab')[1].width", + (int)w->border_box.width, 101); + w = ui_widget_next(w); + ctest_equal_int("$('#browser-tabbar .c-frame-tab')[2].width", + (int)w->border_box.width, 101); + w = ui_widget_next(w); + ctest_equal_int("$('#browser-tabbar .c-frame-tab')[3].width", + (int)w->border_box.width, 101); + w = ui_widget_next(w); + ctest_equal_int("$('#browser-tabbar .c-frame-tab')[4].width", + (int)w->border_box.width, 101); + + w = ui_get_widget("browser-frame-client"); + ctest_equal_int("$('#browser-frame-client')[0].height", + (int)w->border_box.height, 223); + w = ui_get_widget("browser-frame-content"); + ctest_equal_int("$('#browser-frame-content')[0].height", + (int)w->border_box.height, 223); + w = ui_get_widget("browser-page-home"); + ctest_equal_int("$('#browser-page-home')[0].height", + (int)w->border_box.height, 223); + w = ui_get_widget("browser-page-home-container"); + rect.width = 256; + rect.height = 70; + rect.x = + (538.f - rect.width) / 2.f + w->parent->computed_style.padding_left; + rect.y = + (203.f - rect.height) / 2.f + w->parent->computed_style.padding_top; + ctest_equal_ui_rect("$('#browser-page-home-container')[0].border_box", + &w->border_box, &rect); +} + +static void test_flex_layout_1280(void) +{ + ui_widget_resize(ui_root(), 1280, 800); + test_flex_layout_with_content_width(580); +} + +static void test_flex_layout_600(void) +{ + ui_widget_resize(ui_root(), 600, 400); + test_flex_layout_with_content_width(580 - SCROLLBAR_WIDTH); +} + +static void test_flex_layout_320(void) +{ + float width = 320 - 10 - 10 - SCROLLBAR_WIDTH; + float content_width = width - 12 - 10; + + ui_widget_t *w; + ui_widget_t *content; + ui_widget_t *example; + ui_widget_t *container; + ui_rect_t rect; + + container = ui_widget_get_child(ui_get_widget("main"), 0); + ui_widget_resize(ui_root(), 320, 240); + ui_update(); + + rect.y = 10; + rect.x = 10; + rect.width = width; + rect.height = 104; + w = ui_widget_get_child(container, 0); + ctest_equal_ui_rect("$('.example')[0].border_box", &w->border_box, + &rect); + + rect.y += 114; + w = ui_widget_get_child(container, 1); + ctest_equal_ui_rect("$('.example')[1].border_box", &w->border_box, + &rect); + + rect.y += 114; + w = ui_widget_get_child(container, 2); + ctest_equal_ui_rect("$('.example')[2].border_box", &w->border_box, + &rect); + + rect.y += 114; + w = ui_widget_get_child(container, 3); + ctest_equal_ui_rect("$('.example')[3].border_box", &w->border_box, + &rect); + + rect.y += 114; + w = ui_widget_get_child(container, 4); + ctest_equal_ui_rect("$('.example')[4].border_box", &w->border_box, + &rect); + + rect.y += 114; + w = ui_widget_get_child(container, 5); + ctest_equal_ui_rect("$('.example')[5].border_box", &w->border_box, + &rect); + + rect.y += 114; + w = ui_widget_get_child(container, 6); + ctest_equal_ui_rect("$('.example')[6].border_box", &w->border_box, + &rect); + + rect.y += 114; + rect.height = 344; + w = ui_widget_get_child(container, 7); + ctest_equal_ui_rect("$('.example')[7].border_box", &w->border_box, + &rect); + + rect.y += rect.height + 10; + rect.height = 354; + w = ui_widget_get_child(container, 8); + ctest_equal_ui_rect("$('.example')[8].border_box", &w->border_box, + &rect); + + rect.y += rect.height + 10; + rect.height = 354; + w = ui_widget_get_child(container, 9); + ctest_equal_ui_rect("$('.example')[9].border_box", &w->border_box, + &rect); + + rect.y += rect.height + 10; + rect.height = 354; + w = ui_widget_get_child(container, 10); + ctest_equal_ui_rect("$('.example')[10].border_box", &w->border_box, + &rect); + + rect.y += rect.height + 10; + rect.height = 354; + w = ui_widget_get_child(container, 11); + ctest_equal_ui_rect("$('.example')[11].border_box", &w->border_box, + &rect); + + rect.y += rect.height + 10; + rect.height = 354; + w = ui_widget_get_child(container, 12); + ctest_equal_ui_rect("$('.example')[12].border_box", &w->border_box, + &rect); + + rect.y += rect.height + 10; + rect.height = 354; + w = ui_widget_get_child(container, 13); + ctest_equal_ui_rect("$('.example')[13].border_box", &w->border_box, + &rect); + + rect.y += rect.height + 10; + rect.height = 254; + w = ui_widget_get_child(container, 14); + ctest_equal_ui_rect("$('.example')[14].border_box", &w->border_box, + &rect); + + rect.y += rect.height + 10; + rect.height = 184; + w = ui_widget_get_child(container, 15); + ctest_equal_ui_rect("$('.example')[15].border_box", &w->border_box, + &rect); + + rect.y += rect.height + 10; + rect.height = 354; + w = ui_widget_get_child(container, 16); + ctest_equal_ui_rect("$('.example')[16].border_box", &w->border_box, + &rect); + + // (1) justify-content: center;; + + example = ui_widget_get_child(container, 1); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + rect.x = 5; + rect.y = 5; + rect.width = 50 + (content_width - 300) / 6.f; + rect.height = 50; + ctest_equal_ui_rect("$('.example:eq(1) .box')[0].border_box", + &w->border_box, &rect); + + // (2) justify-content: flex-end; + + example = ui_widget_get_child(container, 2); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + ctest_equal_ui_rect("$('.example:eq(2) .box')[0].border_box", + &w->border_box, &rect); + + // (3) justify-content: space-between; + + example = ui_widget_get_child(container, 3); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + ctest_equal_ui_rect("$('.example:eq(3) .box')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += rect.width; + ctest_equal_ui_rect("$('.example:eq(3) .box')[1].border_box", + &w->border_box, &rect); + + w = ui_widget_get_child(content, 5); + rect.x = 5 + content_width - rect.width; + ctest_equal_ui_rect("$('.example:eq(3) .box')[5].border_box", + &w->border_box, &rect); + + // (5) Auto margin + + example = ui_widget_get_child(container, 5); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + rect.x = 5; + rect.width = 50; + ctest_equal_ui_rect("$('.example:eq(5) .box')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += 50 + (content_width - 200) / 2.f; + ctest_equal_ui_rect("$('.example:eq(5) .box')[1].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += 50; + ctest_equal_ui_rect("$('.example:eq(5) .box')[2].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += 50 + (content_width - 200) / 2.f; + ctest_equal_ui_rect("$('.example:eq(5) .box')[3].border_box", + &w->border_box, &rect); + + // (15) Holy Grail Layout + + example = ui_widget_get_child(container, 15); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + rect.x = 5; + rect.y = 5; + rect.width = content_width; + rect.height = 50; + ctest_equal_ui_rect( + "$('.example:eq(15) .layout__header')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_get_child(content, 2); + rect.y = 5 + 50 + 30; + ctest_equal_ui_rect( + "$('.example:eq(15) .layout__footer')[0].border_box", + &w->border_box, &rect); + + rect.x = 0; + rect.y = 0; + rect.width = 100; + rect.height = 30; + w = ui_widget_get_child(content, 1); + w = ui_widget_get_child(w, 0); + ctest_equal_ui_rect("$('.example:eq(15) .layout__left')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x = 100; + rect.width = content_width - 100 - 100; + ctest_equal_ui_rect( + "$('.example:eq(15) .layout__center')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += rect.width; + rect.width = 100; + ctest_equal_ui_rect("$('.example:eq(15) .layout__right')[0].border_box", + &w->border_box, &rect); + + // (16) Holy Grail Layout (height: 300px) + + example = ui_widget_get_child(container, 16); + content = ui_widget_get_child(example, 1); + w = ui_widget_get_child(content, 0); + rect.x = 5; + rect.y = 5; + rect.width = content_width; + rect.height = 50; + ctest_equal_ui_rect( + "$('.example:eq(15) .layout__header')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_get_child(content, 2); + rect.y = 5 + 50 + 200; + ctest_equal_ui_rect( + "$('.example:eq(16) .layout__footer')[0].border_box", + &w->border_box, &rect); + + rect.x = 0; + rect.y = 0; + rect.width = 100; + rect.height = 200; + w = ui_widget_get_child(content, 1); + w = ui_widget_get_child(w, 0); + ctest_equal_ui_rect("$('.example:eq(16) .layout__left')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x = 100; + rect.width = content_width - 100 - 100; + ctest_equal_ui_rect( + "$('.example:eq(16) .layout__center')[0].border_box", + &w->border_box, &rect); + + w = ui_widget_next(w); + rect.x += rect.width; + rect.width = 100; + ctest_equal_ui_rect("$('.example:eq(16) .layout__right')[0].border_box", + &w->border_box, &rect); +} + +void test_flex_layout(void) +{ + lcui_init(); + ui_widget_set_title(ui_root(), L"test flex layout"); + flex_layout_scene_build(); + + ctest_describe("browser layout", test_browser_layout); + ctest_describe("root width 1280px", test_flex_layout_1280); + ctest_describe("root width 600px", test_flex_layout_600); + ctest_describe("root width 320px", test_flex_layout_320); + + lcui_destroy(); +} diff --git a/tests/integration/test_font_face.c b/tests/integration/test_font_face.c new file mode 100644 index 000000000..943ddc7cc --- /dev/null +++ b/tests/integration/test_font_face.c @@ -0,0 +1,24 @@ +/* + * tests/cases/test_font_face.c + * + * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include + +void test_font_face(void) +{ + ui_init(); + ctest_equal_int("should load CSS file containing @font-face", + ui_load_css_file("test_font_face.css"), 0); + ctest_equal_bool("should resolve font registered via @font-face", + pd_font_library_get_font_id("icomoon", 0, 0) > 0, + true); + ui_destroy(); +} diff --git a/tests/cases/test_mainloop.c b/tests/integration/test_mainloop.c similarity index 96% rename from tests/cases/test_mainloop.c rename to tests/integration/test_mainloop.c index d11656f66..b15875230 100644 --- a/tests/cases/test_mainloop.c +++ b/tests/integration/test_mainloop.c @@ -52,7 +52,7 @@ static void observer_thread(void *arg) for (i = 0; i < 10 && !*exited; ++i) { sleep_ms(100); } - ctest_equal_bool("main loop should exit within 1000ms", *exited, true); + ctest_equal_bool("should exit main loop within 1000ms", *exited, true); if (!*exited) { exit(-ctest_finish()); return; diff --git a/tests/cases/test_router.c b/tests/integration/test_router.c similarity index 84% rename from tests/cases/test_router.c rename to tests/integration/test_router.c index df545d5ab..63a1bd656 100644 --- a/tests/cases/test_router.c +++ b/tests/integration/test_router.c @@ -58,42 +58,41 @@ void test_router_components(void) ui_event_init(&e, "click"); ui_widget_emit_event(link_foo, e, NULL); matched_widget = ui_router_view_get_matched_widget(view); - ctest_equal_bool("[/foo] widget should load widget", + ctest_equal_bool("[/foo] should load in ", strcmp(matched_widget->type, "foo") == 0, true); ctest_equal_bool( - "[/foo] linkFoo should has active classes", + "[/foo] should mark linkFoo with active classes", (ui_widget_has_class(link_foo, "router-link-active") && ui_widget_has_class(link_foo, "router-link-exact-active")), true); ui_widget_emit_event(link_bar, e, NULL); matched_widget = ui_router_view_get_matched_widget(view); - ctest_equal_bool("[/bar] widget should load widget", + ctest_equal_bool("[/bar] should load in ", strcmp(matched_widget->type, "bar") == 0, true); ctest_equal_bool( - "[/bar] linkFoo should not has active classes", + "[/bar] should remove active classes from linkFoo", (!ui_widget_has_class(link_foo, "router-link-exact-active") && !ui_widget_has_class(link_foo, "router-link-active")), true); ui_widget_emit_event(link_foobar, e, NULL); matched_widget = ui_router_view_get_matched_widget(view); + ctest_equal_bool("[/foo/bar] should load in ", + strcmp(matched_widget->type, "foobar") == 0, true); ctest_equal_bool( - "[/foo/bar] widget should load widget", - strcmp(matched_widget->type, "foobar") == 0, true); - ctest_equal_bool( - "[/foo/bar] linkFooBar should has active classes", + "[/foo/bar] should mark linkFooBar with active classes", (ui_widget_has_class(link_foobar, "router-link-exact-active") && ui_widget_has_class(link_foobar, "router-link-active")), true); ctest_equal_bool( - "[/foo/bar] linkFoo should only has the exact active class", + "[/foo/bar] should mark linkFoo with non-exact active class only", (!ui_widget_has_class(link_foo, "router-link-exact-active") && ui_widget_has_class(link_foo, "router-link-active")), true); ui_widget_set_attr(link_foo, "exact", "exact"); ui_widget_emit_event(link_foobar, e, NULL); ctest_equal_bool( - "[/foo/bar] linkFoo should not has any active classes (exact)", + "[/foo/bar] should remove all active classes when exact is set", (!ui_widget_has_class(link_foo, "router-link-exact-active") && !ui_widget_has_class(link_foo, "router-link-active")), true); diff --git a/tests/integration/test_scrollbar.c b/tests/integration/test_scrollbar.c new file mode 100644 index 000000000..c1fc55bb0 --- /dev/null +++ b/tests/integration/test_scrollbar.c @@ -0,0 +1,120 @@ +/* + * tests/cases/test_scrollbar.c + * + * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include "../scenes/scrollbar_scene.h" + +void test_scrollbar(void) +{ + float left, top; + ui_event_t e = { 0 }; + ui_widget_t *content; + + lcui_init(); + scrollbar_scene_build(); + lcui_ui_update(); + + content = ui_get_widget("license_content"); + left = content->computed_style.left; + top = content->computed_style.top; + + e.type = UI_EVENT_MOUSEMOVE; + e.mouse.x = 300; + e.mouse.y = 275; + ui_dispatch_event(&e); + lcui_ui_update(); + + e.type = UI_EVENT_MOUSEDOWN; + e.mouse.button = MOUSE_BUTTON_LEFT; + e.mouse.x = 300; + e.mouse.y = 275; + ui_dispatch_event(&e); + lcui_ui_update(); + + e.type = UI_EVENT_MOUSEMOVE; + e.mouse.x = 600; + e.mouse.y = 275; + ui_dispatch_event(&e); + lcui_ui_update(); + + ctest_equal_bool("should scroll content to the left", + content->computed_style.left < left && + top == content->computed_style.top, + true); + + left = content->computed_style.left; + top = content->computed_style.top; + + e.type = UI_EVENT_MOUSEMOVE; + e.mouse.x = 400; + e.mouse.y = 275; + ui_dispatch_event(&e); + e.type = UI_EVENT_MOUSEUP; + e.mouse.button = MOUSE_BUTTON_LEFT; + e.mouse.x = 400; + e.mouse.y = 275; + ui_dispatch_event(&e); + lcui_ui_update(); + + ctest_equal_bool("should scroll content to the right", + content->computed_style.left > left && + top == content->computed_style.top, + true); + + left = content->computed_style.left; + top = content->computed_style.top; + + e.type = UI_EVENT_MOUSEMOVE; + e.mouse.x = 555; + e.mouse.y = 45; + ui_dispatch_event(&e); + lcui_ui_update(); + + e.type = UI_EVENT_MOUSEDOWN; + e.mouse.button = MOUSE_BUTTON_LEFT; + e.mouse.x = 555; + e.mouse.y = 45; + ui_dispatch_event(&e); + lcui_ui_update(); + + e.type = UI_EVENT_MOUSEMOVE; + e.mouse.x = 555; + e.mouse.y = 200; + ui_dispatch_event(&e); + lcui_ui_update(); + + ctest_equal_bool("should scroll content to the top", + content->computed_style.left == left && + top > content->computed_style.top, + true); + + left = content->computed_style.left; + top = content->computed_style.top; + + e.type = UI_EVENT_MOUSEMOVE; + e.mouse.x = 555; + e.mouse.y = 100; + ui_dispatch_event(&e); + e.type = UI_EVENT_MOUSEUP; + e.mouse.button = MOUSE_BUTTON_LEFT; + e.mouse.x = 555; + e.mouse.y = 100; + ui_dispatch_event(&e); + lcui_ui_update(); + + ctest_equal_bool("should scroll content to the bottom", + content->computed_style.left == left && + top < content->computed_style.top, + true); + + lcui_destroy(); +} diff --git a/tests/integration/test_settings.c b/tests/integration/test_settings.c new file mode 100644 index 000000000..e2729984b --- /dev/null +++ b/tests/integration/test_settings.c @@ -0,0 +1,120 @@ +/* + * tests/cases/test_settings.c + * + * Copyright (c) 2023, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include + +static void check_settings_fps_cap(void *arg) +{ + char str[256]; + int fps_limit = *((int *)arg); + int fps = (int)lcui_get_fps(); + + sprintf(str, "should reach frame cap of %u (actual %u)", fps_limit, + fps); + ctest_equal_bool(str, fps <= fps_limit + 2 && fps > fps_limit / 2, + true); + lcui_quit(); +} + +static void test_default_settings(void) +{ + lcui_settings_t settings; + + lcui_init(); + lcui_reset_settings(); + lcui_get_settings(&settings); + + ctest_equal_int("should default frame rate cap to 120", + settings.fps_cap, 120); + ctest_equal_int("should default parallel rendering threads to 4", + settings.parallel_rendering_threads, 4); + ctest_equal_bool("should disable paint flashing by default", + settings.paint_flashing, false); + lcui_quit(); + lcui_main(); +} + +static void test_apply_settings(void) +{ + lcui_settings_t settings; + + settings.fps_cap = 60; + settings.parallel_rendering_threads = 2; + settings.paint_flashing = true; + + lcui_init(); + lcui_apply_settings(&settings); + lcui_get_settings(&settings); + ctest_equal_int("should apply frame rate cap", settings.fps_cap, 60); + ctest_equal_int("should apply parallel rendering threads", + settings.parallel_rendering_threads, 2); + ctest_equal_bool("should enable paint flashing", + settings.paint_flashing, true); + + settings.fps_cap = -1; + settings.parallel_rendering_threads = -1; + + lcui_apply_settings(&settings); + lcui_get_settings(&settings); + + ctest_equal_int("should clamp frame rate cap to minimum 1", + settings.fps_cap, 1); + ctest_equal_int("should clamp parallel rendering threads to minimum 1", + settings.parallel_rendering_threads, 1); + + lcui_reset_settings(); + + lcui_get_settings(&settings); + ctest_equal_int("should reset frame rate cap to default", + settings.fps_cap, LCUI_MAX_FRAMES_PER_SEC); + lcui_quit(); + lcui_main(); +} + +void test_settings_fps_cap(void) +{ + lcui_settings_t settings; + + lcui_init(); + lcui_get_settings(&settings); + + settings.fps_cap = 30; + lcui_apply_settings(&settings); + ptk_set_timeout(2000, check_settings_fps_cap, &settings.fps_cap); + lcui_main(); + + lcui_init(); + settings.fps_cap = 5; + lcui_apply_settings(&settings); + ptk_set_timeout(2000, check_settings_fps_cap, &settings.fps_cap); + lcui_main(); + + lcui_init(); + settings.fps_cap = 90; + lcui_apply_settings(&settings); + ptk_set_timeout(2000, check_settings_fps_cap, &settings.fps_cap); + lcui_main(); + + lcui_init(); + settings.fps_cap = 25; + lcui_apply_settings(&settings); + ptk_set_timeout(2000, check_settings_fps_cap, &settings.fps_cap); + lcui_main(); +} + +void test_settings(void) +{ + ctest_describe("default settings", test_default_settings); + ctest_describe("apply settings", test_apply_settings); + ctest_describe("settings.fps_cap", test_settings_fps_cap); +} diff --git a/tests/cases/test_text_resize.c b/tests/integration/test_text_resize.c similarity index 70% rename from tests/cases/test_text_resize.c rename to tests/integration/test_text_resize.c index 54b22f0a3..b77177caa 100644 --- a/tests/cases/test_text_resize.c +++ b/tests/integration/test_text_resize.c @@ -82,14 +82,14 @@ static void check_text_set_content(void) { ui_update(); - ctest_equal_float("check block width", - self.block->border_box.width, 122.f); - ctest_equal_bool("check block height", + ctest_equal_float("should match block width", + self.block->border_box.width, 122.f); + ctest_equal_bool("should expand block height beyond 140px", self.block->border_box.height > 140.f, true); - ctest_equal_float("check inline block width", - self.inline_block->border_box.width, 580.f); - ctest_equal_float("check inline block height", - self.inline_block->border_box.height, 62.f); + ctest_equal_float("should match inline block width", + self.inline_block->border_box.width, 580.f); + ctest_equal_float("should match inline block height", + self.inline_block->border_box.height, 62.f); } static void test_text_set_short_content_css(void *arg) @@ -102,14 +102,14 @@ static void check_text_set_short_content_css(void) { ui_update(); - ctest_equal_float("check block width", - self.block->border_box.width, 122.f); - ctest_equal_float("check block height", - self.block->border_box.height, 42.f); - ctest_equal_bool("check inline block width", + ctest_equal_float("should match block width with short content", + self.block->border_box.width, 122.f); + ctest_equal_float("should match block height with short content", + self.block->border_box.height, 42.f); + ctest_equal_bool("should shrink inline block width below 70px", self.inline_block->border_box.width < 70.f, true); - ctest_equal_float("check inline block height", - self.inline_block->border_box.height, 42.f); + ctest_equal_float("should match inline block height with short content", + self.inline_block->border_box.height, 42.f); } static void test_text_set_long_content_css(void *arg) @@ -124,13 +124,13 @@ static void check_text_set_long_content_css(void) { ui_update(); - ctest_equal_float("check block width", - self.block->border_box.width, 122.0f); - ctest_equal_bool("check block height", + ctest_equal_float("should match block width with long content", + self.block->border_box.width, 122.0f); + ctest_equal_bool("should expand block height beyond 60px", self.block->border_box.height > 60.0f, true); - ctest_equal_bool("check inline block width", + ctest_equal_bool("should expand inline block width beyond 250px", self.inline_block->border_box.width > 250.0f, true); - ctest_equal_bool("check inline block height", + ctest_equal_bool("should keep inline block height below 45px", self.inline_block->border_box.height < 45.0f, true); } @@ -142,14 +142,13 @@ void test_text_resize(void) ui_widget_resize(ui_root(), 600, 600); test_text_set_content(NULL); - ctest_describe("check text set content", check_text_set_content); + ctest_describe("text set content", check_text_set_content); test_text_set_short_content_css(NULL); - ctest_describe("check text set short content css", + ctest_describe("text set short content css", check_text_set_short_content_css); test_text_set_long_content_css(NULL); - ctest_describe("check text set long content css", + ctest_describe("text set long content css", check_text_set_long_content_css); - lcui_quit(); - lcui_main(); + lcui_destroy(); } diff --git a/tests/integration/test_textinput.c b/tests/integration/test_textinput.c new file mode 100644 index 000000000..85fba3da2 --- /dev/null +++ b/tests/integration/test_textinput.c @@ -0,0 +1,76 @@ +/* + * tests/cases/test_textinput.c + * + * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include + +void test_textinput(void) +{ + ui_widget_t *w; + wchar_t wcs[64]; + + lcui_init(); + + w = ui_create_widget("textinput"); + + ui_textinput_set_text_w(w, L"hello"); + ui_widget_update(w); + ctest_equal_bool("should match text length after set_text_w", + ui_textinput_get_text_length(w) == wcslen(L"hello"), + true); + ctest_equal_bool( + "should retrieve full text after set_text_w", + ui_textinput_get_text_w(w, 0, 64, wcs) == wcslen(L"hello"), true); + ctest_equal_bool( + "should retrieve identical wide string after set_text_w", + wcscmp(L"hello", wcs) == 0, true); + + ui_widget_set_text(w, "hello"); + ui_widget_update(w); + ctest_equal_bool("should match text length after set_text", + ui_textinput_get_text_length(w) == wcslen(L"hello"), + true); + ctest_equal_bool( + "should retrieve full text after set_text", + ui_textinput_get_text_w(w, 0, 64, wcs) == wcslen(L"hello"), true); + ctest_equal_bool("should retrieve identical wide string after set_text", + wcscmp(L"hello", wcs) == 0, true); + + ui_textinput_append_text_w(w, L"world"); + ui_widget_update(w); + ctest_equal_bool( + "should match text length after append_text_w", + ui_textinput_get_text_length(w) == wcslen(L"helloworld"), true); + ctest_equal_bool( + "should retrieve appended text via get_text_w", + ui_textinput_get_text_w(w, 0, 64, wcs) == wcslen(L"helloworld"), + true); + ctest_equal_bool("should retrieve identical appended wide string", + wcscmp(L"helloworld", wcs) == 0, true); + + ui_textinput_move_caret(w, 0, 5); + ui_textinput_insert_text_w(w, L", "); + ui_widget_update(w); + ui_textinput_move_caret(w, 0, 100); + ui_textinput_insert_text_w(w, L"!"); + ui_widget_update(w); + ctest_equal_bool( + "should match text length after inserting text", + ui_textinput_get_text_length(w) == wcslen(L"hello, world!"), true); + ctest_equal_bool( + "should retrieve inserted text via get_text_w", + ui_textinput_get_text_w(w, 0, 64, wcs) == wcslen(L"hello, world!"), + true); + ctest_equal_bool("should retrieve identical inserted wide string", + wcscmp(L"hello, world!", wcs) == 0, true); + ui_widget_destroy(w); + lcui_destroy(); +} diff --git a/tests/integration/test_widget_event.c b/tests/integration/test_widget_event.c new file mode 100644 index 000000000..9bb0a1033 --- /dev/null +++ b/tests/integration/test_widget_event.c @@ -0,0 +1,130 @@ +/* + * tests/cases/test_widget_event.c + * + * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +void test_widget_mouse_event(void) +{ + ui_widget_t *root; + ui_widget_t *parent, *child; + ui_event_t ev; + + lcui_init(); + root = ui_root(); + parent = ui_create_widget("button"); + child = ui_create_widget("text"); + + ui_widget_resize(root, 200, 200); + ui_widget_resize(parent, 100, 100); + ui_widget_resize(child, 50, 50); + ui_widget_append(parent, child); + ui_widget_append(root, parent); + ui_update(); + + ev.type = UI_EVENT_MOUSEMOVE; + ev.mouse.x = 150; + ev.mouse.y = 150; + ui_dispatch_event(&ev); + ui_update(); + ctest_equal_bool("should mark root as hover when mouse is at (150,150)", + ui_widget_has_status(root, "hover"), true); + ctest_equal_bool( + "should not mark parent as hover when mouse is at (150,150)", + ui_widget_has_status(parent, "hover"), false); + ctest_equal_bool( + "should not mark child as hover when mouse is at (150,150)", + ui_widget_has_status(child, "hover"), false); + + ev.mouse.x = 80; + ev.mouse.y = 80; + ui_dispatch_event(&ev); + ui_update(); + ctest_equal_bool("should mark root as hover when mouse is at (80,80)", + ui_widget_has_status(root, "hover"), true); + ctest_equal_bool("should mark parent as hover when mouse is at (80,80)", + ui_widget_has_status(parent, "hover"), true); + ctest_equal_bool( + "should not mark child as hover when mouse is at (80,80)", + ui_widget_has_status(child, "hover"), false); + + ev.mouse.x = 40; + ev.mouse.y = 40; + ui_dispatch_event(&ev); + ui_update(); + ctest_equal_bool("should mark root as hover when mouse is at (40,40)", + ui_widget_has_status(root, "hover"), true); + ctest_equal_bool("should mark parent as hover when mouse is at (40,40)", + ui_widget_has_status(parent, "hover"), true); + ctest_equal_bool("should mark child as hover when mouse is at (40,40)", + ui_widget_has_status(child, "hover"), true); + + ev.type = UI_EVENT_MOUSEDOWN; + ev.mouse.x = 40; + ev.mouse.y = 40; + ev.mouse.button = MOUSE_BUTTON_LEFT; + ui_dispatch_event(&ev); + ui_update(); + ctest_equal_bool("should mark root as active on mousedown", + ui_widget_has_status(root, "active"), true); + ctest_equal_bool("should mark parent as active on mousedown", + ui_widget_has_status(parent, "active"), true); + ctest_equal_bool("should mark child as active on mousedown", + ui_widget_has_status(child, "active"), true); + + ev.type = UI_EVENT_MOUSEUP; + ui_dispatch_event(&ev); + ui_update(); + ctest_equal_bool("should clear root active state on mouseup", + ui_widget_has_status(root, "active"), false); + ctest_equal_bool("should clear parent active state on mouseup", + ui_widget_has_status(parent, "active"), false); + ctest_equal_bool("should clear child active state on mouseup", + ui_widget_has_status(child, "active"), false); + + ev.type = UI_EVENT_MOUSEMOVE; + ev.mouse.x = 80; + ev.mouse.y = 80; + ui_dispatch_event(&ev); + ui_update(); + ctest_equal_bool( + "should keep root as hover when mouse moves back to (80,80)", + ui_widget_has_status(root, "hover"), true); + ctest_equal_bool( + "should keep parent as hover when mouse moves back to (80,80)", + ui_widget_has_status(parent, "hover"), true); + ctest_equal_bool( + "should clear child hover state when mouse moves back to (80,80)", + ui_widget_has_status(child, "hover"), false); + + ev.mouse.x = 150; + ev.mouse.y = 150; + ui_dispatch_event(&ev); + ui_update(); + ctest_equal_bool( + "should keep root as hover when mouse leaves to (150,150)", + ui_widget_has_status(root, "hover"), true); + ctest_equal_bool( + "should clear parent hover state when mouse leaves to (150,150)", + ui_widget_has_status(parent, "hover"), false); + ctest_equal_bool( + "should clear child hover state when mouse leaves to (150,150)", + ui_widget_has_status(child, "hover"), false); + + lcui_destroy(); +} + +void test_widget_event(void) +{ + ctest_describe("widget mouse event", test_widget_mouse_event); +} diff --git a/tests/cases/test_widget_opacity.c b/tests/integration/test_widget_opacity.c similarity index 70% rename from tests/cases/test_widget_opacity.c rename to tests/integration/test_widget_opacity.c index d65a83b59..835f72697 100644 --- a/tests/cases/test_widget_opacity.c +++ b/tests/integration/test_widget_opacity.c @@ -1,7 +1,7 @@ /* * tests/cases/test_widget_opacity.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -13,28 +13,12 @@ #include #include #include +#include "../scenes/widget_opacity_scene.h" #define PARENT_OPACITY 0.8f #define CHILD_OPACITY 0.5f -static struct { - ui_widget_t* parent; - ui_widget_t* child; - ui_widget_t* text; -} self; - -static void build(void) -{ - ui_widget_t *pack, *root; - - pack = ui_load_xml_file("test_widget_opacity.xml"); - root = ui_root(); - ui_widget_append(root, pack); - ui_widget_unwrap(pack); - self.parent = ui_get_widget("parent"); - self.child = ui_get_widget("child"); - self.text = ui_get_widget("current-opacity"); -} +static widget_opacity_scene_t scene; static int check_color(pd_color_t a, pd_color_t b) { @@ -59,8 +43,7 @@ static void check_widget_opactiy(void) pd_canvas_create(&canvas, rect.width, rect.height); pd_canvas_fill(&canvas, bgcolor); - // 重置 dpi,避免缩放 - ui_metrics.dpi = 96; + ui_metrics.dpi = 96; paint.with_alpha = false; paint.rect.width = 400; @@ -68,25 +51,25 @@ static void check_widget_opactiy(void) paint.rect.x = paint.rect.y = 0; pd_canvas_quote(&paint.canvas, &canvas, &rect); - ui_widget_set_style_string(self.parent, "opacity", "0.8"); - ui_widget_resize(self.parent, 512, 256); - ui_widget_request_refresh_style(self.child); - ui_widget_request_refresh_style(self.parent); - ui_widget_update(self.parent); - ui_widget_render(self.parent, &paint); + ui_widget_set_style_string(scene.parent, "opacity", "0.8"); + ui_widget_resize(scene.parent, 512, 256); + ui_widget_request_refresh_style(scene.child); + ui_widget_request_refresh_style(scene.parent); + ui_widget_update(scene.parent); + ui_widget_render(scene.parent, &paint); expected_color = bgcolor; color = pd_canvas_get_pixel(&canvas, 10, 10); pd_blend_pixel(&expected_color, &parent_bcolor, (int)(PARENT_OPACITY * 255)); - ctest_equal_bool("check parent border color", + ctest_equal_bool("should match parent border color", check_color(expected_color, color), true); expected_color = bgcolor; color = pd_canvas_get_pixel(&canvas, 30, 30); pd_blend_pixel(&expected_color, &parent_bgcolor, (int)(PARENT_OPACITY * 255)); - ctest_equal_bool("check parent background color", + ctest_equal_bool("should match parent background color", check_color(expected_color, color), true); tmp = parent_bgcolor; @@ -94,7 +77,7 @@ static void check_widget_opactiy(void) color = pd_canvas_get_pixel(&canvas, 60, 90); pd_blend_pixel(&tmp, &child_bgcolor, (int)(CHILD_OPACITY * 255)); pd_blend_pixel(&expected_color, &tmp, (int)(PARENT_OPACITY * 255)); - ctest_equal_bool("check child 1 background color", + ctest_equal_bool("should match child 1 background color", check_color(expected_color, color), true); tmp = parent_bgcolor; @@ -102,18 +85,18 @@ static void check_widget_opactiy(void) color = pd_canvas_get_pixel(&canvas, 60, 120); pd_blend_pixel(&tmp, &child_footer_bgcolor, (int)(CHILD_OPACITY * 255)); pd_blend_pixel(&expected_color, &tmp, (int)(PARENT_OPACITY * 255)); - ctest_equal_bool("check child 1 footer background color", + ctest_equal_bool("should match child 1 footer background color", check_color(expected_color, color), true); expected_color = bgcolor; color = pd_canvas_get_pixel(&canvas, 220, 90); pd_blend_pixel(&expected_color, &child_bgcolor, (int)(PARENT_OPACITY * 255)); - ctest_equal_bool("check child 2 background color", + ctest_equal_bool("should match child 2 background color", check_color(expected_color, color), true); expected_color = child_footer_bgcolor; color = pd_canvas_get_pixel(&canvas, 220, 120); - ctest_equal_bool("check child 2 footer background color", + ctest_equal_bool("should match child 2 footer background color", check_color(expected_color, color), true); pd_canvas_destroy(&canvas); @@ -122,7 +105,7 @@ static void check_widget_opactiy(void) void test_widget_opacity(void) { lcui_init(); - build(); - ctest_describe("check widget opacity", check_widget_opactiy); + widget_opacity_scene_build(&scene); + ctest_describe("widget opacity", check_widget_opactiy); lcui_destroy(); } diff --git a/tests/integration/test_widget_rect.c b/tests/integration/test_widget_rect.c new file mode 100644 index 000000000..ffd458601 --- /dev/null +++ b/tests/integration/test_widget_rect.c @@ -0,0 +1,180 @@ +/* + * tests/cases/test_widget_rect.c + * + * Copyright (c) 2023, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include + +void test_widget_rect(void) +{ + ui_widget_t *root; + ui_widget_t *parent, *child; + ui_event_t e = { 0 }; + pd_rect_t rect = { 0 }; + pd_rect_t expected_rect; + ui_rect_t expected_ui_rect; + list_t rects; + + lcui_init(); + root = ui_root(); + parent = ui_create_widget("button"); + child = ui_create_widget("text"); + + ui_widget_set_style_keyword_value(parent, css_prop_box_sizing, + CSS_KEYWORD_BORDER_BOX); + ui_widget_resize(root, 200, 200); + ui_widget_resize(parent, 100, 100); + ui_widget_resize(child, 50, 50); + ui_widget_append(parent, child); + ui_widget_append(root, parent); + ui_update(); + + list_create(&rects); + ui_widget_get_dirty_rects(root, &rects); + list_destroy(&rects, free); + + e.type = UI_EVENT_MOUSEMOVE; + e.mouse.x = 150; + e.mouse.y = 150; + ui_dispatch_event(&e); + ui_update(); + ui_widget_get_dirty_rects(root, &rects); + ctest_equal_bool("should not produce dirty rects when mouse hovers " + "outside (150,150)", + rects.length == 0, true); + + e.mouse.x = 80; + e.mouse.y = 80; + ui_dispatch_event(&e); + ui_update(); + ui_widget_get_dirty_rects(root, &rects); + ctest_equal_bool( + "should produce one dirty rect when mouse enters parent at (80,80)", + rects.length == 1, true); + + expected_ui_rect.x = 0; + expected_ui_rect.y = 0; + expected_ui_rect.width = 100; + expected_ui_rect.height = 100; + ui_compute_rect(&expected_rect, &expected_ui_rect); + if (rects.length == 1) { + rect = *(pd_rect_t *)list_get(&rects, 0); + } + ctest_equal_pd_rect("should match expected dirty rect", &rect, + &expected_rect); + list_destroy(&rects, free); + + e.mouse.x = 40; + e.mouse.y = 40; + ui_dispatch_event(&e); + ui_update(); + ui_widget_get_dirty_rects(root, &rects); + ctest_equal_bool("should not produce dirty rects when mouse moves to " + "child at (40,40)", + rects.length == 0, true); + + e.type = UI_EVENT_MOUSEDOWN; + e.mouse.x = 40; + e.mouse.y = 40; + e.mouse.button = MOUSE_BUTTON_LEFT; + ui_dispatch_event(&e); + ui_update(); + ui_widget_get_dirty_rects(root, &rects); + ctest_equal_bool( + "should produce one dirty rect on mousedown at (40,40)", + rects.length == 1, true); + if (rects.length == 1) { + rect = *(pd_rect_t *)list_get(&rects, 0); + } + ctest_equal_pd_rect("should match expected dirty rect", &rect, + &expected_rect); + list_destroy(&rects, free); + + e.type = UI_EVENT_MOUSEUP; + ui_dispatch_event(&e); + ui_update(); + ui_widget_get_dirty_rects(root, &rects); + ctest_equal_bool("should produce one dirty rect on mouseup at (40,40)", + rects.length == 1, true); + if (rects.length == 1) { + rect = *(pd_rect_t *)list_get(&rects, 0); + } + ctest_equal_pd_rect("should match expected dirty rect", &rect, + &expected_rect); + list_destroy(&rects, free); + + e.type = UI_EVENT_MOUSEMOVE; + e.mouse.x = 80; + e.mouse.y = 80; + ui_dispatch_event(&e); + ui_update(); + ui_widget_get_dirty_rects(root, &rects); + ctest_equal_bool("should not produce dirty rects when mouse moves back " + "to parent at (80,80)", + rects.length == 0, true); + + e.mouse.x = 150; + e.mouse.y = 150; + ui_dispatch_event(&e); + ui_update(); + ui_widget_get_dirty_rects(root, &rects); + + ctest_equal_bool("should produce one dirty rect when mouse leaves " + "parent at (150,150)", + rects.length == 1, true); + if (rects.length == 1) { + rect = *(pd_rect_t *)list_get(&rects, 0); + } + ctest_equal_pd_rect("should match expected dirty rect", &rect, + &expected_rect); + list_destroy(&rects, free); + + expected_ui_rect.x = 21; + expected_ui_rect.y = 11; + expected_ui_rect.width = 50; + expected_ui_rect.height = 50; + ui_compute_rect(&expected_rect, &expected_ui_rect); + ui_widget_remove(child); + ui_update(); + ui_widget_get_dirty_rects(root, &rects); + ctest_equal_bool( + "should produce one dirty rect when child is destroyed", + rects.length == 1, true); + if (rects.length == 1) { + rect = *(pd_rect_t *)list_get(&rects, 0); + } + ctest_equal_pd_rect("should match expected dirty rect", &rect, + &expected_rect); + list_destroy(&rects, free); + + expected_ui_rect.x = 0; + expected_ui_rect.y = 0; + expected_ui_rect.width = 100; + expected_ui_rect.height = 100; + ui_compute_rect(&expected_rect, &expected_ui_rect); + ui_widget_remove(parent); + ui_update(); + ui_widget_get_dirty_rects(root, &rects); + ctest_equal_bool( + "should produce one dirty rect when parent is destroyed", + rects.length == 1, true); + if (rects.length == 1) { + rect = *(pd_rect_t *)list_get(&rects, 0); + } + ctest_equal_pd_rect("should match expected dirty rect", &rect, + &expected_rect); + list_destroy(&rects, free); + + lcui_destroy(); +} diff --git a/tests/main.c b/tests/main.c new file mode 100644 index 000000000..dc500038c --- /dev/null +++ b/tests/main.c @@ -0,0 +1,53 @@ +/* + * tests/main.c + * + * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include + +extern void test_settings(void); +extern void test_clipboard(void); +extern void test_mainloop(void); +extern void test_router_components(void); +extern void test_widget_event(void); +extern void test_widget_rect(void); +extern void test_text_resize(void); +extern void test_textinput(void); +extern void test_font_face(void); +extern void test_widget_opacity(void); +extern void test_block_layout(void); +extern void test_flex_layout(void); +extern void test_scrollbar(void); + +static const ctest_suite_t suites[] = { + { "settings", test_settings }, + { "clipboard", test_clipboard }, + { "mainloop", test_mainloop }, + { "router components", test_router_components }, + { "widget event", test_widget_event }, + { "widget rect", test_widget_rect }, + { "text resize", test_text_resize }, + { "textinput", test_textinput }, + { "font face", test_font_face }, + { "widget opacity", test_widget_opacity }, + { "block layout", test_block_layout }, + { "flex layout", test_flex_layout }, + { "scrollbar", test_scrollbar }, + { NULL, NULL } +}; + +int main(int argc, char **argv) +{ + logger_set_level(LOGGER_LEVEL_ERROR); + if (ctest_parse_args(argc, argv) != 0) { + return 1; + } + return ctest_run_suites(suites); +} diff --git a/tests/previews/preview_block_layout.c b/tests/previews/preview_block_layout.c new file mode 100644 index 000000000..140a84bd0 --- /dev/null +++ b/tests/previews/preview_block_layout.c @@ -0,0 +1,24 @@ +/* + * tests/previews/preview_block_layout.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include "../scenes/block_layout_scene.h" + +int main(int argc, char **argv) +{ + (void)argc; + (void)argv; + lcui_init(); + ui_widget_set_title(ui_root(), L"block layout preview"); + block_layout_scene_build(); + return lcui_main(); +} diff --git a/tests/previews/preview_flex_layout.c b/tests/previews/preview_flex_layout.c new file mode 100644 index 000000000..ce3529e4a --- /dev/null +++ b/tests/previews/preview_flex_layout.c @@ -0,0 +1,24 @@ +/* + * tests/previews/preview_flex_layout.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include "../scenes/flex_layout_scene.h" + +int main(int argc, char **argv) +{ + (void)argc; + (void)argv; + lcui_init(); + ui_widget_set_title(ui_root(), L"flex layout preview"); + flex_layout_scene_build(); + return lcui_main(); +} diff --git a/tests/previews/preview_scrollbar.c b/tests/previews/preview_scrollbar.c new file mode 100644 index 000000000..4e69c55be --- /dev/null +++ b/tests/previews/preview_scrollbar.c @@ -0,0 +1,24 @@ +/* + * tests/previews/preview_scrollbar.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include "../scenes/scrollbar_scene.h" + +int main(int argc, char **argv) +{ + (void)argc; + (void)argv; + lcui_init(); + ui_widget_set_title(ui_root(), L"scrollbar preview"); + scrollbar_scene_build(); + return lcui_main(); +} diff --git a/tests/previews/preview_widget_opacity.c b/tests/previews/preview_widget_opacity.c new file mode 100644 index 000000000..ec5cbef7b --- /dev/null +++ b/tests/previews/preview_widget_opacity.c @@ -0,0 +1,26 @@ +/* + * tests/previews/preview_widget_opacity.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include "../scenes/widget_opacity_scene.h" + +int main(int argc, char **argv) +{ + widget_opacity_scene_t scene; + + (void)argc; + (void)argv; + lcui_init(); + ui_widget_set_title(ui_root(), L"widget opacity preview"); + widget_opacity_scene_build(&scene); + return lcui_main(); +} diff --git a/tests/previews/xmake.lua b/tests/previews/xmake.lua new file mode 100644 index 000000000..17738d011 --- /dev/null +++ b/tests/previews/xmake.lua @@ -0,0 +1,18 @@ +local previews = { + "flex_layout", + "block_layout", + "widget_opacity", + "scrollbar" +} + +for _, topic in ipairs(previews) do + target("preview_" .. topic) + set_default(false) + set_kind("binary") + set_group("previews") + set_rundir("../fixtures") + add_includedirs("../helpers") + add_files("preview_" .. topic .. ".c", + "../scenes/" .. topic .. "_scene.c") + add_deps("lcui") +end diff --git a/tests/run_tests.c b/tests/run_tests.c deleted file mode 100644 index 49540deb3..000000000 --- a/tests/run_tests.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * tests/run_tests.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include -#include -#include -#include -#include "run_tests.h" - -int main(int argc, char **argv) -{ - logger_set_level(LOGGER_LEVEL_ERROR); - ctest_describe("test settings", test_settings); - ctest_describe("test thread", test_thread); - ctest_describe("test steptimer", test_steptimer); - ctest_describe("test font load", test_font_load); - ctest_describe("test image reader", test_image_reader); - ctest_describe("test xml parser", test_xml_parser); - ctest_describe("test mainloop", test_mainloop); - ctest_describe("test clipboard", test_clipboard); - ctest_describe("test widget event", test_widget_event); - ctest_describe("test widget opacity", test_widget_opacity); - ctest_describe("test text resize", test_text_resize); - ctest_describe("test textinput", test_textinput); - ctest_describe("test scrollbar", test_scrollbar); - ctest_describe("test router components", test_router_components); - ctest_describe("test widget rect", test_widget_rect); - ctest_describe("test block layout", test_block_layout); - ctest_describe("test flex layout", test_flex_layout); - return ctest_finish(); -} diff --git a/tests/run_tests.h b/tests/run_tests.h deleted file mode 100644 index c0cd3ca1a..000000000 --- a/tests/run_tests.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * tests/run_tests.h - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -void test_settings(void); -void test_thread(void); -void test_font_load(void); -void test_xml_parser(void); -void test_widget_opacity(void); -void test_widget_event(void); -void test_text_resize(void); -void test_textinput(void); -void test_scrollbar(void); -void test_image_reader(void); -void test_mainloop(void); -void test_block_layout(void); -void test_flex_layout(void); -void test_widget_rect(void); -void test_clipboard(void); -void test_router_components(void); -void test_steptimer(void); diff --git a/tests/scenes/block_layout_scene.c b/tests/scenes/block_layout_scene.c new file mode 100644 index 000000000..0f47f02f4 --- /dev/null +++ b/tests/scenes/block_layout_scene.c @@ -0,0 +1,25 @@ +/* + * tests/scenes/block_layout_scene.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include "block_layout_scene.h" + +void block_layout_scene_build(void) +{ + ui_widget_t *root; + ui_widget_t *wrapper; + + wrapper = ui_load_xml_file("test_block_layout.xml"); + root = ui_root(); + ui_widget_append(root, wrapper); + ui_widget_unwrap(wrapper); + ui_update(); +} diff --git a/tests/scenes/block_layout_scene.h b/tests/scenes/block_layout_scene.h new file mode 100644 index 000000000..054f3bcd5 --- /dev/null +++ b/tests/scenes/block_layout_scene.h @@ -0,0 +1,19 @@ +/* + * tests/scenes/block_layout_scene.h + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#ifndef LCUI_TESTS_SCENES_BLOCK_LAYOUT_SCENE_H +#define LCUI_TESTS_SCENES_BLOCK_LAYOUT_SCENE_H + +#include + +void block_layout_scene_build(void); + +#endif diff --git a/tests/scenes/flex_layout_scene.c b/tests/scenes/flex_layout_scene.c new file mode 100644 index 000000000..fe7ee92c8 --- /dev/null +++ b/tests/scenes/flex_layout_scene.c @@ -0,0 +1,25 @@ +/* + * tests/scenes/flex_layout_scene.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include "flex_layout_scene.h" + +void flex_layout_scene_build(void) +{ + ui_widget_t *root; + ui_widget_t *wrapper; + + wrapper = ui_load_xml_file("test_flex_layout.xml"); + root = ui_root(); + ui_widget_append(root, wrapper); + ui_widget_unwrap(wrapper); + ui_update(); +} diff --git a/tests/scenes/flex_layout_scene.h b/tests/scenes/flex_layout_scene.h new file mode 100644 index 000000000..805c9b140 --- /dev/null +++ b/tests/scenes/flex_layout_scene.h @@ -0,0 +1,19 @@ +/* + * tests/scenes/flex_layout_scene.h + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#ifndef LCUI_TESTS_SCENES_FLEX_LAYOUT_SCENE_H +#define LCUI_TESTS_SCENES_FLEX_LAYOUT_SCENE_H + +#include + +void flex_layout_scene_build(void); + +#endif diff --git a/tests/scenes/scrollbar_scene.c b/tests/scenes/scrollbar_scene.c new file mode 100644 index 000000000..9ee81f61c --- /dev/null +++ b/tests/scenes/scrollbar_scene.c @@ -0,0 +1,81 @@ +/* + * tests/scenes/scrollbar_scene.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include "scrollbar_scene.h" + +static const char *scrollbar_scene_css = "\ +.container {\ + width: 300px;\ + height: 240px;\ + padding: 10px;\ + margin: 20px auto 0 auto;\ + border: 1px solid #eee;\ +}\ +\ +text {\ + white-space: nowrap;\ + display: inline-block;\ +}\ +"; + +static const char *scrollbar_scene_content = "\n\ +/* ***************************************************************************\n\ + * test_scrollbar.c -- test scrollbar\n\ + *\n\ + * Copyright (c) 2021, Liu chao All rights reserved.\n\ + *\n\ + * Redistribution and use in source and binary forms, with or without\n\ + * modification, are permitted provided that the following conditions are met:\n\ + *\n\ + * * Redistributions of source code must retain the above copyright notice,\n\ + * this list of conditions and the following disclaimer.\n\ + * * Redistributions in binary form must reproduce the above copyright\n\ + * notice, this list of conditions and the following disclaimer in the\n\ + * documentation and/or other materials provided with the distribution.\n\ + * * Neither the name of LCUI nor the names of its contributors may be used\n\ + * to endorse or promote products derived from this software without\n\ + * specific prior written permission.\n\ + *\n\ + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n\ + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n\ + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n\ + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n\ + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n\ + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n\ + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n\ + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n\ + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n\ + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n\ + * POSSIBILITY OF SUCH DAMAGE.\n\ + */\n\ +"; + +void scrollbar_scene_build(void) +{ + ui_widget_t *container = ui_create_scrollarea(); + ui_widget_t *content = ui_create_scrollarea_content(); + ui_widget_t *text = ui_create_widget("text"); + ui_widget_t *vscrollbar = ui_create_scrollbar(); + ui_widget_t *hscrollbar = ui_create_scrollbar(); + + ui_widget_resize(ui_root(), 800, 640); + ui_load_css_string(scrollbar_scene_css, __FILE__); + ui_widget_set_id(content, "license_content"); + ui_text_set_content(text, scrollbar_scene_content); + ui_scrollbar_set_orientation(hscrollbar, UI_SCROLLBAR_HORIZONTAL); + ui_widget_add_class(container, "container"); + ui_widget_append(content, text); + ui_widget_append(container, content); + ui_widget_append(container, vscrollbar); + ui_widget_append(container, hscrollbar); + ui_root_append(container); +} diff --git a/tests/scenes/scrollbar_scene.h b/tests/scenes/scrollbar_scene.h new file mode 100644 index 000000000..46e0f6e94 --- /dev/null +++ b/tests/scenes/scrollbar_scene.h @@ -0,0 +1,19 @@ +/* + * tests/scenes/scrollbar_scene.h + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#ifndef LCUI_TESTS_SCENES_SCROLLBAR_SCENE_H +#define LCUI_TESTS_SCENES_SCROLLBAR_SCENE_H + +#include + +void scrollbar_scene_build(void); + +#endif diff --git a/tests/scenes/widget_opacity_scene.c b/tests/scenes/widget_opacity_scene.c new file mode 100644 index 000000000..4f8053d92 --- /dev/null +++ b/tests/scenes/widget_opacity_scene.c @@ -0,0 +1,26 @@ +/* + * tests/scenes/widget_opacity_scene.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include "widget_opacity_scene.h" + +void widget_opacity_scene_build(widget_opacity_scene_t *scene) +{ + ui_widget_t *pack, *root; + + pack = ui_load_xml_file("test_widget_opacity.xml"); + root = ui_root(); + ui_widget_append(root, pack); + ui_widget_unwrap(pack); + scene->parent = ui_get_widget("parent"); + scene->child = ui_get_widget("child"); + scene->text = ui_get_widget("current-opacity"); +} diff --git a/tests/scenes/widget_opacity_scene.h b/tests/scenes/widget_opacity_scene.h new file mode 100644 index 000000000..efab51b26 --- /dev/null +++ b/tests/scenes/widget_opacity_scene.h @@ -0,0 +1,25 @@ +/* + * tests/scenes/widget_opacity_scene.h + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#ifndef LCUI_TESTS_SCENES_WIDGET_OPACITY_SCENE_H +#define LCUI_TESTS_SCENES_WIDGET_OPACITY_SCENE_H + +#include + +typedef struct widget_opacity_scene { + ui_widget_t *parent; + ui_widget_t *child; + ui_widget_t *text; +} widget_opacity_scene_t; + +void widget_opacity_scene_build(widget_opacity_scene_t *scene); + +#endif diff --git a/tests/test_block_layout.c b/tests/test_block_layout.c deleted file mode 100644 index 85ff2d552..000000000 --- a/tests/test_block_layout.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * tests/test_block_layout.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#define PREVIEW_MODE -#include "./cases/test_block_layout.c" -#include - -int main(int argc, char **argv) -{ - logger_set_level(LOGGER_LEVEL_ALL); - test_block_layout(); - return lcui_main(); -} diff --git a/tests/test_block_layout.html b/tests/test_block_layout.html deleted file mode 100644 index d3c526d9c..000000000 --- a/tests/test_block_layout.html +++ /dev/null @@ -1,157 +0,0 @@ - - - block layout - - - -
-
-
(0) Basic
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
w-3
-
w-3 ml-auto
-
w-3 ml-auto mr-auto
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
(1) Width
-
-
min-width: 50%; display: inline-block
-
width: 50%; display: block
-
width: 100%; display: block
-
width: 50%; display: inline-block
-
width: 50%; display: inline-block
-
width: 25%; display: inline-block
-
width: 25%; display: inline-block
-
width: 25%; display: inline-block
-
width: 25%; display: inline-block
-
-
-
-
(2) Auto size
-
-
block, limited width
-
inline block, auto size
-
block, auto size
-
-
-
-
(3) Margin
-
-
-
margin: 16px
-
m-1
-
m-1
-
m-1
-
m-1
-
mr--2
-
w-3 m-1
-
w-2 ml--2
-
margin: -16px
-
-
-
w-auto
-
w-auto ml--1
-
w-auto ml--1 mr--1
-
width: 200px; margin-left: -8px; margin-right: -8px
-
width: 100%; margin-left: -8px; margin-right: -8px
-
-
-
-
-
(4) vertical-align
-
-
-
-
middle
-
-
bottom
-
-
bottom
-
middle
-
-
-
middle
-
bottom
-
-
-
middle
-
-
-
-
-
(5) position: absolute
-
-
-
-
-
-
-
-
-
-
(6) Dropdown menu
-
- -
-
-
-
(7) Inline block nesting
-
-
-
inline-block > inline-block
-
inline-block > inline-block
-
inline-block > block
-
inline-block > block
-
-
-
absolute-position > inline-block
-
absolute-position > inline-block
-
absolute-position > block
-
absolute-position > block
-
-
-
-
-
(8) Absolutely positioned progress bar
-
-
-
loading...
-
-
-
-
-
-
-
- - diff --git a/tests/test_border.c b/tests/test_border.c deleted file mode 100644 index efcea1792..000000000 --- a/tests/test_border.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * tests/test_border.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include -#include -#include - -int main(void) -{ - int ret = 0; - ui_widget_t *root, *box; - - lcui_init(); - box = ui_load_xml_file("test_border.xml"); - if (!box) { - lcui_destroy(); - return ret; - } - root = ui_root(); - ui_widget_append(root, box); - ui_widget_unwrap(box); - return lcui_main(); -} diff --git a/tests/test_border.css b/tests/test_border.css deleted file mode 100644 index 80cdb7fac..000000000 --- a/tests/test_border.css +++ /dev/null @@ -1,47 +0,0 @@ -.box { - width: 100px; - height: 80px; - background-color: #eee; - margin: 10px; - box-sizing: border-box; - display: inline-block; -} -.box-content { - background-color: #fff; - border: 1px solid #888; -} -.rounded.box { - border-radius: 20px; -} -.square.box { - width: 80px; - height: 80px; - border: 40px solid #000; - border-left-color: #f00; - border-right-color: #00f; -} -.rounded-2.box { - border-radius: 40px; -} -.box-1 { - border: 1px solid #000; -} -.box-2 { - border: 10px solid #000; -} -.box-3 { - border: 10px solid #000; - border-left: 20px solid #f00; -} -.box-4 { - border: 10px solid #000; - border-top: 20px solid #f00; -} -.box-5 { - border: 10px solid #000; - border-right: 20px solid #f00; -} -.box-6 { - border: 10px solid #000; - border-bottom: 20px solid #f00; -} diff --git a/tests/test_border.html b/tests/test_border.html deleted file mode 100644 index cc1c3647b..000000000 --- a/tests/test_border.html +++ /dev/null @@ -1,40 +0,0 @@ - - - border - - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - diff --git a/tests/test_border.xml b/tests/test_border.xml deleted file mode 100644 index c89ed73ca..000000000 --- a/tests/test_border.xml +++ /dev/null @@ -1,150 +0,0 @@ - - - - - - - - - - - - - - - - - - - Box content 1 - - - Box content 2 - - - - - Box content 1 - - - Box content 2 - - - - - Box content 1 - - - Box content 2 - - - - - Box content 1 - - - Box content 2 - - - - - Box content 1 - - - Box content 2 - - - - - Box content 1 - - - Box content 2 - - - - - Box content 1 - - - Box content 2 - - - - - Box content 1 - - - Box content 2 - - - - - - - Box content 1 - - - Box content 2 - - - - - Box content 1 - - - Box content 2 - - - - - Box content 1 - - - Box content 2 - - - - - Box content 1 - - - Box content 2 - - - - - Box content 1 - - - Box content 2 - - - - - Box content 1 - - - Box content 2 - - - - - Box content 1 - - - Box content 2 - - - - - Box content 1 - - - Box content 2 - - - - - - diff --git a/tests/test_box_shadow.c b/tests/test_box_shadow.c deleted file mode 100644 index e2fe213da..000000000 --- a/tests/test_box_shadow.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * tests/test_box_shadow.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include -#include - -int main(void) -{ - int ret = 0; - ui_widget_t *box; - - lcui_init(); - box = ui_load_xml_file("test_box_shadow.xml"); - if (!box) { - lcui_destroy(); - return ret; - } - ui_root_append(box); - ui_widget_unwrap(box); - return lcui_main(); -} diff --git a/tests/test_box_shadow.css b/tests/test_box_shadow.css deleted file mode 100644 index b636eb977..000000000 --- a/tests/test_box_shadow.css +++ /dev/null @@ -1,46 +0,0 @@ - -.box { - width: 100px; - height: 80px; - margin: 10px; - box-sizing: border-box; - display: inline-block; - background-color: #eee; - border: 1px solid #f00; - box-shadow: 0 0 8px rgba(0, 0, 0, 0.8); -} -.box-content { - background-color: #fff; - border: 1px solid #888; -} -.shadow-container { - padding: 0 0 30px 0; -} -.shadow-2 .box { - box-shadow: 15px 15px 8px rgba(0, 0, 0, 0.8); -} -.shadow-3 .box { - box-shadow: 30px 30px 8px rgba(0, 0, 0, 0.8); -} -.rounded.box { - border-radius: 20px; -} -.rounded-2.box { - border-radius: 40px; -} -.rounded-3.box { - border-top-left-radius: 40px; - border-top-right-radius: 30px; - border-bottom-right-radius: 20px; - border-bottom-left-radius: 10px; -} -.rounded-4.box { - border-top-left-radius: 10px; - border-top-right-radius: 40px; - border-bottom-right-radius: 10px; - border-bottom-left-radius: 40px; -} -.square.box { - width: 80px; - height: 80px; -} diff --git a/tests/test_box_shadow.html b/tests/test_box_shadow.html deleted file mode 100644 index ad5bb44b6..000000000 --- a/tests/test_box_shadow.html +++ /dev/null @@ -1,34 +0,0 @@ - - - border - - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - diff --git a/tests/test_box_shadow.xml b/tests/test_box_shadow.xml deleted file mode 100644 index d3eeb633a..000000000 --- a/tests/test_box_shadow.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/test_char_render.c b/tests/test_char_render.c deleted file mode 100644 index ab0b2426e..000000000 --- a/tests/test_char_render.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * tests/test_char_render.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include - -int main(void) -{ - int ret, fid; - pd_canvas_t img; - pd_font_bitmap_t bmp; - pd_pos_t pos = { 25, 25 }; - pd_color_t bg = pd_rgb(240, 240, 240); - pd_color_t color = pd_rgb(255, 0, 0); - - /* 初始化字体处理功能 */ - pd_font_library_init(); - - /* 创建一个画布,并填充背景为灰色 */ - pd_canvas_init(&img); - pd_canvas_create(&img, 100, 100); - pd_canvas_fill(&img, bg); - - /* 载入字体文件 */ - ret = pd_font_library_load_file("C:/Windows/fonts/simsun.ttc"); - while (ret == 0) { - /* 获取字体ID */ - fid = pd_font_library_get_font_id("SimSun", 0, 0); - if (fid < 0) { - break; - } - /* 渲染对应的文字位图,大小为 48 像素 */ - ret = pd_font_library_render_bitmap(&bmp, L'字', fid, 48); - if (ret != 0) { - break; - } - /* 绘制红色文字到图像上 */ - pd_canvas_mix_font_bitmap(&img, pos, &bmp, color); - pd_write_png_file("test_char_render.png", &img); - /* 释放内存资源 */ - pd_font_bitmap_destroy(&bmp); - pd_canvas_destroy(&img); - break; - } - - /* 释放字体处理功能相关资源 */ - pd_font_library_destroy(); - return ret; -} diff --git a/tests/test_css_parser.css b/tests/test_css_parser.css deleted file mode 100644 index fdfb3d69f..000000000 --- a/tests/test_css_parser.css +++ /dev/null @@ -1,58 +0,0 @@ -.window .content .btn text { - width: 100px; -} -.window .content .btn .text { - height: 60px; -} -.window text { - position: absolute; -} -#test-text { - top: 12px; -} -.text { - left: 20px; -} -.window .content .btn:hover text { - background-color: #f00; -} -.window .content .btn:hover .text { - background-size: contain; -} - -#test-flex-auto { - flex: auto; -} - -#test-flex-none { - flex: none; -} - -#test-flex-initial { - flex: initial; -} - -#test-flex-1 { - flex: 1; -} - -#test-flex-100px { - flex: 100px; -} - -#test-flex-1-100px { - flex: 1 100px; -} - -#test-flex-0-0-100px { - flex: 0 0 100px; -} - -#test-flex-box { - flex: 0 0 auto; - flex-flow: column nowrap; - justify-content: center; - justify-items: center; - align-items: flex-end; - align-content: flex-end; -} diff --git a/tests/test_css_parser.xml b/tests/test_css_parser.xml deleted file mode 100644 index cfc006f85..000000000 --- a/tests/test_css_parser.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - test - - - - - diff --git a/tests/test_fill_rect.c b/tests/test_fill_rect.c deleted file mode 100644 index 716ccfab1..000000000 --- a/tests/test_fill_rect.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * tests/test_fill_rect.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include - -int main(void) -{ - int i, j; - pd_canvas_t canvas; - pd_color_t color; - pd_rect_t rect; - - pd_canvas_init(&canvas); - pd_canvas_create(&canvas, 150, 150); - for (i = 0; i < 6; ++i) { - for (j = 0; j < 6; ++j) { - color.red = (unsigned char)(255 - 42.5 * i); - color.green = (unsigned char)(255 - 42.5 * j); - color.blue = 0; - rect.x = j * 25; - rect.y = i * 25; - rect.width = 25; - rect.height = 25; - pd_canvas_fill_rect(&canvas, color, rect); - } - } - pd_write_png_file("test_fill_rect.png", &canvas); - pd_canvas_destroy(&canvas); - return 0; -} diff --git a/tests/test_fill_rect_with_rgba.c b/tests/test_fill_rect_with_rgba.c deleted file mode 100644 index 64084919d..000000000 --- a/tests/test_fill_rect_with_rgba.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * tests/test_fill_rect_with_rgba.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include -#include - -int main(void) -{ - int i, j; - pd_canvas_t canvas; - pd_canvas_t fore_canvas; - pd_color_t color; - pd_rect_t rect; - - pd_canvas_init(&canvas); - pd_canvas_init(&fore_canvas); - pd_canvas_create(&canvas, 160, 160); - // 画背景 - rect.x = 0; - rect.y = 0; - rect.width = 160; - rect.height = 40; - pd_canvas_fill_rect(&canvas, pd_rgb(255, 221, 0), rect); - rect.y += 40; - pd_canvas_fill_rect(&canvas, pd_rgb(102, 204, 0), rect); - rect.y += 40; - pd_canvas_fill_rect(&canvas, pd_rgb(0, 153, 255), rect); - rect.y += 40; - pd_canvas_fill_rect(&canvas, pd_rgb(255, 51, 0), rect); - color.red = 255; - color.green = 255; - color.blue = 255; - fore_canvas.color_type = PD_COLOR_TYPE_ARGB; - pd_canvas_create(&fore_canvas, 15, 30); - // 画半透明矩形 - for (i = 0; i < 10; ++i) { - color.alpha = (unsigned char)(255 * (i + 1) / 10.0); - pd_canvas_fill(&fore_canvas, color); - for (j = 0; j < 4; ++j) { - pd_canvas_mix(&canvas, &fore_canvas, 5 + i * 15, 5 + j * 40, true); - } - } - pd_write_png_file("test_fill_rect_with_rgba.png", &canvas); - pd_canvas_destroy(&fore_canvas); - pd_canvas_destroy(&canvas); - return 0; -} diff --git a/tests/test_flex_layout.c b/tests/test_flex_layout.c deleted file mode 100644 index 4d41cdc72..000000000 --- a/tests/test_flex_layout.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * tests/test_flex_layout.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#define PREVIEW_MODE -#include "./cases/test_flex_layout.c" -#include - -int main(int argc, char **argv) -{ - logger_set_level(LOGGER_LEVEL_ALL); - test_flex_layout(); - return lcui_main(); -} diff --git a/tests/test_flex_layout.html b/tests/test_flex_layout.html deleted file mode 100644 index 046413f08..000000000 --- a/tests/test_flex_layout.html +++ /dev/null @@ -1,359 +0,0 @@ - - - flex layout - - - -
-
-
(0) Default
-
-
-
-
-
-
-
-
-
-
-
(1) justify-content: center;
-
-
-
-
-
-
-
-
-
-
-
(2) justify-content: flex-end;
-
-
-
-
-
-
-
-
-
-
-
(3) justify-content: space-between;
-
-
-
-
-
-
-
-
-
-
-
(4) justify-content: space-around;
-
-
-
-
-
-
-
-
-
-
-
(5) Auto margin
-
-
mr-auto
-
-
-
ml-auto
-
-
-
-
(6) flex-shrink
-
-
-
-
-
-
width: 150px
-
-
-
width: 100px
-
-
-
width: 200px
-
-
-
-
-
-
-
-
-
-
-
-
-
(7) flex-grow
-
-
auto
-
auto
-
auto
-
-
-
auto
-
initial
-
initial
-
-
-
auto
-
auto
-
none
-
-
-
initial
-
auto
-
auto
-
-
-
flex: 4
-
flex: 2
-
flex: 1
-
-
-
-
(8) flex-wrap: wrap;
-
-
-
-
-
-
width: 150px
-
-
-
width: 100px
-
-
-
width: 200px
-
-
-
-
-
-
-
-
-
-
-
-
-
(9) flex-wrap: wrap; height: 300px;
-
-
-
-
-
-
width: 150px
-
-
-
width: 100px
-
-
-
width: 200px
-
-
-
-
-
-
-
-
-
-
-
-
-
(10) align-items: center; height: 300px;
-
-
-
-
-
-
width: 150px
-
-
-
width: 100px
-
-
-
width: 200px
-
-
-
-
-
-
-
-
-
-
-
-
-
(11) align-items: end; height: 300px;
-
-
-
-
-
-
width: 150px
-
-
-
width: 100px
-
-
-
width: 200px
-
-
-
-
-
-
-
-
-
-
-
-
-
(12) align-items: stretch; height: 300px;
-
-
h-auto
-
h-auto
-
h-auto
-
-
width: 150px
-
-
-
width: 100px
-
-
-
width: 200px
-
h-auto
-
h-auto
-
h-auto
-
-
-
h-auto
-
h-auto
-
-
-
-
-
-
(13) Vertically Centered Layout
-
-
-
-
-
-
(14) flex-direction: column;
-
-
-
-
-
-
width: 150px
-
-
-
width: 100px
-
-
-
width: 200px
-
-
-
-
-
-
-
-
-
-
-
-
-
(15) Holy Grail Layout
-
-
Header
-
-
Left
-
Center
-
Right
-
- -
-
-
-
(16) Holy Grail Layout (height: 300px)
-
-
Header
-
-
Left
-
Center
-
Right
-
- -
-
-
-
(17) Browser Layout
-
-
-
-
-
-
Tab 1
-
X
-
-
-
-
Tab 2
-
X
-
-
-
-
Tab 3
-
X
-
-
-
-
Tab 4
-
X
-
-
-
-
Tab 5
-
X
-
-
+
-
-
-
- Navbar -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - diff --git a/tests/test_image_scaling_bench.c b/tests/test_image_scaling_bench.c deleted file mode 100644 index 4eeb41014..000000000 --- a/tests/test_image_scaling_bench.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * tests/test_image_scaling_bench.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include -#include -#include -#include -#include -#include - -int main(int argc, char **argv) -{ - int i; - int64_t t0, t1, t2; - int resx[] = { 480, 960, 1280, 1366, 1920, 2560, 3840 }, resy; - char s_res[32], s_t0[32], s_t1[32]; - - pd_canvas_t g_src, g_dst; - pd_color_t t_color; - - pd_canvas_init(&g_src); - g_src.color_type = PD_COLOR_TYPE_ARGB; - if (pd_canvas_create(&g_src, 960, 540) < 0) { - return -2; - } - t_color.value = 0xffaa5500; - pd_canvas_fill(&g_src, t_color); - logger_info("%-20s%-20s%s\n", "image size\\method", "Graph_Zoom()", - "Graph_ZoomBilinear()"); - for (i = 0; i < sizeof(resx) / sizeof(int); i++) { - resy = resx[i] * 9 / 16; - t0 = get_time_ms(); - pd_canvas_init(&g_dst); - pd_canvas_zoom(&g_src, &g_dst, false, resx[i], resy); - pd_canvas_destroy(&g_dst); - t1 = get_time_ms(); - pd_canvas_init(&g_dst); - pd_canvas_zoom_bilinear(&g_src, &g_dst, false, resx[i], resy); - pd_canvas_destroy(&g_dst); - t2 = get_time_ms(); - sprintf(s_res, "%dx%d", resx[i], resy); - sprintf(s_t0, "%ldms", (int)(t1 - t0)); - sprintf(s_t1, "%ldms", (int)(t2 - t1)); - logger_info("%-20s%-20s%-20s\n", s_res, s_t0, s_t1); - } - pd_canvas_destroy(&g_src); - return 0; -} diff --git a/tests/test_mix_rect_with_opacity.c b/tests/test_mix_rect_with_opacity.c deleted file mode 100644 index ab095ee7f..000000000 --- a/tests/test_mix_rect_with_opacity.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * tests/test_mix_rect_with_opacity.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include - -int main(void) -{ - int i, size; - pd_canvas_t canvas; - pd_canvas_t fore_canvas; - pd_rect_t rect; - - pd_canvas_init(&canvas); - pd_canvas_init(&fore_canvas); - pd_canvas_create(&canvas, 150, 150); - // 画背景 - rect.x = 0; - rect.y = 0; - rect.width = 75; - rect.height = 75; - pd_canvas_fill_rect(&canvas, pd_rgb(255, 221, 0), rect); - rect.x = 75; - pd_canvas_fill_rect(&canvas, pd_rgb(102, 204, 0), rect); - rect.x = 0; - rect.y = 75; - pd_canvas_fill_rect(&canvas, pd_rgb(0, 153, 255), rect); - rect.x = 75; - pd_canvas_fill_rect(&canvas, pd_rgb(255, 51, 0), rect); - // 设置前景的 opacity 值 - fore_canvas.opacity = 0.2f; - // 仅当色彩模式为 ARGB 时 opacity 属性才会生效 - fore_canvas.color_type = PD_COLOR_TYPE_ARGB; - for (i = 0; i < 7; ++i) { - size = 2 * (10 + 10 * i); - // 使用新尺寸重新创建前景图 - pd_canvas_create(&fore_canvas, size, size); - // 重新填充颜色 - pd_canvas_fill(&fore_canvas, pd_rgb(255, 255, 255)); - // 将前景图混合到背景图中 - pd_canvas_mix(&canvas, &fore_canvas, 75 - size / 2, 75 - size / 2, - false); - } - pd_write_png_file("test_mix_rect_with_opacity.png", &canvas); - pd_canvas_destroy(&fore_canvas); - pd_canvas_destroy(&canvas); - return 0; -} diff --git a/tests/test_paint_background.c b/tests/test_paint_background.c deleted file mode 100644 index 7b93bd1dc..000000000 --- a/tests/test_paint_background.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * tests/test_paint_background.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include - -int test_paint_background_color(void) -{ - pd_canvas_t canvas; - pd_color_t gray = pd_rgb(240, 240, 240); - pd_color_t green = pd_rgb(102, 204, 0); - pd_rect_t rect = { 200, 100, 400, 300 }; - pd_background_t bg = { 0 }; - pd_context_t* ctx; - - pd_canvas_init(&canvas); - pd_canvas_create(&canvas, 800, 600); - pd_canvas_fill(&canvas, gray); - // 设置背景色 - bg.color = green; - // 创建绘制上下文 - ctx = pd_context_create(&canvas, &rect); - // 绘制背景 - pd_paint_background(ctx, &bg, &rect); - pd_write_png_file("test_paint_background_color.png", &canvas); - pd_context_destroy(ctx); - pd_canvas_destroy(&canvas); - return 0; -} - -int test_paint_background_image(void) -{ - pd_canvas_t canvas; - pd_canvas_t image; - pd_color_t gray = pd_rgb(240, 240, 240); - pd_color_t green = pd_rgb(102, 204, 0); - pd_rect_t rect = { 200, 100, 400, 300 }; - pd_background_t bg = { 0 }; - pd_context_t* ctx; - - pd_canvas_init(&canvas); - pd_canvas_init(&image); - pd_canvas_create(&canvas, 800, 600); - pd_canvas_fill(&canvas, gray); - // 读取背景图片 - if (pd_read_image_from_file("test_image_reader.png", &image) != 0) { - return -1; - } - // 设置背景色 - bg.color = green; - // 设置背景图 - bg.image = ℑ - bg.width = image.width; - bg.height = image.height; - // 创建绘制上下文 - ctx = pd_context_create(&canvas, &rect); - // 绘制背景 - pd_paint_background(ctx, &bg, &rect); - pd_write_png_file("test_paint_background_image.png", &canvas); - pd_context_destroy(ctx); - pd_canvas_destroy(&image); - pd_canvas_destroy(&canvas); - return 0; -} - -int test_paint_background_image_with_size(void) -{ - pd_canvas_t canvas; - pd_canvas_t image; - pd_color_t gray = pd_rgb(240, 240, 240); - pd_color_t green = pd_rgb(102, 204, 0); - pd_rect_t rect = { 200, 100, 400, 300 }; - pd_background_t bg = { 0 }; - pd_context_t* ctx; - - pd_canvas_init(&canvas); - pd_canvas_init(&image); - pd_canvas_create(&canvas, 800, 600); - pd_canvas_fill(&canvas, gray); - // 读取背景图片 - if (pd_read_image_from_file("test_image_reader.png", &image) != 0) { - return -1; - } - // 设置背景色 - bg.color = green; - // 设置背景图 - bg.image = ℑ - // 将背景图设置成与背景区域相同的尺寸 - bg.width = rect.width; - bg.height = rect.height; - // 创建绘制上下文 - ctx = pd_context_create(&canvas, &rect); - // 绘制背景 - pd_paint_background(ctx, &bg, &rect); - pd_write_png_file("test_paint_background_image_with_size.png", &canvas); - pd_context_destroy(ctx); - pd_canvas_destroy(&image); - pd_canvas_destroy(&canvas); - return 0; -} - -int test_paint_background_image_with_position(void) -{ - pd_canvas_t canvas; - pd_canvas_t image; - pd_color_t gray = pd_rgb(240, 240, 240); - pd_color_t green = pd_rgb(102, 204, 0); - pd_rect_t rect = { 200, 100, 400, 300 }; - pd_background_t bg = { 0 }; - pd_context_t* ctx; - - pd_canvas_init(&canvas); - pd_canvas_init(&image); - pd_canvas_create(&canvas, 800, 600); - pd_canvas_fill(&canvas, gray); - // 读取背景图片 - if (pd_read_image_from_file("test_image_reader.png", &image) != 0) { - return -1; - } - // 设置背景色 - bg.color = green; - // 设置背景图 - bg.image = ℑ - bg.width = image.width; - bg.height = image.height; - // 让背景图居中 - bg.x = (rect.width - image.width) / 2; - bg.y = (rect.height - image.height) / 2; - // 创建绘制上下文 - ctx = pd_context_create(&canvas, &rect); - // 绘制背景 - pd_paint_background(ctx, &bg, &rect); - pd_write_png_file("test_paint_background_image_with_position.png", - &canvas); - pd_context_destroy(ctx); - pd_canvas_destroy(&image); - pd_canvas_destroy(&canvas); - return 0; -} - -int main(void) -{ - test_paint_background_color(); - test_paint_background_image(); - test_paint_background_image_with_size(); - test_paint_background_image_with_position(); - return 0; -} diff --git a/tests/test_paint_border.c b/tests/test_paint_border.c deleted file mode 100644 index 132224399..000000000 --- a/tests/test_paint_border.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * tests/test_paint_border.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include - -int paint_background(pd_context_t* ctx, pd_rect_t* box) -{ - pd_canvas_t image; - pd_color_t green = pd_rgb(102, 204, 0); - pd_background_t bg = { 0 }; - - pd_canvas_init(&image); - // 读取背景图片 - if (pd_read_image_from_file("test_image_reader.png", &image) != 0) { - return -1; - } - // 设置背景色 - bg.color = green; - // 设置背景图 - bg.image = ℑ - bg.width = image.width; - bg.height = image.height; - // 让背景图居中 - bg.x = (box->width - image.width) / 2; - bg.y = (box->height - image.height) / 2; - // 绘制背景 - pd_paint_background(ctx, &bg, box); - pd_canvas_destroy(&image); - return 0; -} - -void paint_border(pd_context_t* ctx, pd_rect_t* box) -{ - pd_border_t border = { 0 }; - pd_color_t black = pd_rgb(0, 0, 0); - - border.top.color = black; - border.top.style = CSS_KEYWORD_SOLID; - border.top.width = 4; - border.right.color = black; - border.right.style = CSS_KEYWORD_SOLID; - border.right.width = 4; - border.bottom.color = black; - border.bottom.style = CSS_KEYWORD_SOLID; - border.bottom.width = 4; - border.left.color = black; - border.left.style = CSS_KEYWORD_SOLID; - border.left.width = 4; - border.top_left_radius = 32; - border.top_right_radius = 32; - border.bottom_left_radius = 32; - border.bottom_right_radius = 32; - pd_paint_border(ctx, &border, box); -} - -int main(void) -{ - int border_size = 4; - - pd_canvas_t canvas; - pd_canvas_t layer; - pd_color_t gray = pd_rgb(240, 240, 240); - pd_rect_t border_box = { 0, 0, 400, 300 }; - pd_rect_t bg_box = { border_box.x + border_size, - border_box.y + border_size, - border_box.width - border_size * 2, - border_box.height - border_size * 2 }; - pd_rect_t layer_rect = { 0, 0, border_box.width, border_box.height }; - pd_context_t* paint; - - pd_canvas_init(&canvas); - pd_canvas_create(&canvas, 800, 600); - pd_canvas_fill(&canvas, gray); - - pd_canvas_init(&layer); - layer.color_type = PD_COLOR_TYPE_ARGB; - pd_canvas_create(&layer, layer_rect.width, layer_rect.height); - - // 创建绘制上下文 - paint = pd_context_create(&layer, &layer_rect); - paint->with_alpha = true; - paint_background(paint, &bg_box); - paint_border(paint, &border_box); - pd_canvas_mix(&canvas, &layer, (canvas.width - layer_rect.width) / 2, - (canvas.height - layer_rect.height) / 2, false); - pd_write_png_file("test_paint_border.png", &canvas); - pd_canvas_destroy(&canvas); - return 0; -} diff --git a/tests/test_paint_boxshadow.c b/tests/test_paint_boxshadow.c deleted file mode 100644 index ae37ff265..000000000 --- a/tests/test_paint_boxshadow.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * tests/test_paint_boxshadow.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include - -int paint_background(pd_context_t* ctx, pd_rect_t* box) -{ - pd_canvas_t image; - pd_color_t green = pd_rgb(102, 204, 0); - pd_background_t bg = { 0 }; - - pd_canvas_init(&image); - // 读取背景图片 - if (pd_read_image_from_file("test_image_reader.png", &image) != 0) { - return -1; - } - // 设置背景色 - bg.color = green; - // 设置背景图 - bg.image = ℑ - bg.width = image.width; - bg.height = image.height; - // 让背景图居中 - bg.x = (box->width - image.width) / 2; - bg.y = (box->height - image.height) / 2; - // 绘制背景 - pd_paint_background(ctx, &bg, box); - pd_canvas_destroy(&image); - return 0; -} - -void paint_border(pd_context_t* ctx, pd_rect_t* box, int size, int radius) -{ - pd_border_t border = { 0 }; - pd_color_t black = pd_rgb(0, 0, 0); - - border.top.color = black; - border.top.style = CSS_KEYWORD_SOLID; - border.top.width = size; - border.right.color = black; - border.right.style = CSS_KEYWORD_SOLID; - border.right.width = size; - border.bottom.color = black; - border.bottom.style = CSS_KEYWORD_SOLID; - border.bottom.width = size; - border.left.color = black; - border.left.style = CSS_KEYWORD_SOLID; - border.left.width = size; - border.top_left_radius = radius; - border.top_right_radius = radius; - border.bottom_left_radius = radius; - border.bottom_right_radius = radius; - pd_paint_border(ctx, &border, box); -} - -int main(void) -{ - int border_size = 4; - int border_radius = 32; - int width = 800; - int height = 600; - - pd_canvas_t canvas; - pd_canvas_t layer; - pd_color_t gray = pd_rgb(240, 240, 240); - pd_boxshadow_t shadow = { .x = 0, - .y = 0, - .blur = 40, - .spread = 0, - .color = pd_argb(150, 0, 0, 0), - .top_left_radius = border_radius, - .top_right_radius = border_radius, - .bottom_left_radius = border_radius, - .bottom_right_radius = border_radius }; - pd_rect_t shadow_box; - pd_rect_t border_box; - pd_rect_t bg_box; - pd_rect_t layer_rect; - pd_context_t* ctx; - - pd_canvas_init(&canvas); - pd_canvas_create(&canvas, width, height); - pd_canvas_fill(&canvas, gray); - - // 设置居中的背景区域 - bg_box.width = 400; - bg_box.height = 300; - bg_box.x = (width - bg_box.width) / 2; - bg_box.y = (height - bg_box.height) / 2; - // 基于背景区域,计算边框区域 - border_box.x = bg_box.x - border_size; - border_box.y = bg_box.y - border_size; - border_box.width = bg_box.width + border_size * 2; - border_box.height = bg_box.height + border_size * 2; - // 基于边框区域,计算阴影区域 - pd_get_boxshadow_canvas_rect(&shadow, &border_box, &shadow_box); - - // 创建一个临时绘制层 - pd_canvas_init(&layer); - layer_rect.x = 0; - layer_rect.y = 0; - layer_rect.width = shadow_box.width; - layer_rect.height = shadow_box.height; - layer.color_type = PD_COLOR_TYPE_ARGB; - pd_canvas_create(&layer, layer_rect.width, layer_rect.height); - - // 基于临时绘制层创建绘制上下文 - ctx = pd_context_create(&layer, &layer_rect); - ctx->with_alpha = true; - // 将背景区域和边框区域的坐标转换成相对于阴影区域 - bg_box.x -= shadow_box.x; - bg_box.y -= shadow_box.y; - border_box.x -= shadow_box.x; - border_box.y -= shadow_box.y; - paint_background(ctx, &bg_box); - paint_border(ctx, &border_box, border_size, border_radius); - pd_paint_boxshadow(ctx, &shadow, &layer_rect, border_box.width, - border_box.height); - - // 将临时绘制层混合到画布中 - pd_canvas_mix(&canvas, &layer, shadow_box.x, shadow_box.y, false); - pd_write_png_file("test_paint_boxshadow.png", &canvas); - pd_canvas_destroy(&canvas); - return 0; -} diff --git a/tests/test_pixel_manipulation.c b/tests/test_pixel_manipulation.c deleted file mode 100644 index a3fb2e08d..000000000 --- a/tests/test_pixel_manipulation.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * tests/test_pixel_manipulation.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include - -#define PixelManipulationBegin \ - int x, y; \ - pd_color_t pixel; \ - \ - for (y = rect.y; y < rect.y + rect.height; ++y) { \ - for (x = rect.x; x < rect.x + rect.width; ++x) { \ - pixel = pd_canvas_get_pixel(graph, x, y); - -#define PixelManipulationEnd \ - pd_canvas_set_pixel(graph, x, y, pixel); \ - } \ - } - -void invert(pd_canvas_t *graph, pd_rect_t rect) -{ - PixelManipulationBegin; - pixel.red = (unsigned char)(255 - pixel.red); - pixel.green = (unsigned char)(255 - pixel.green); - pixel.blue = (unsigned char)(255 - pixel.blue); - PixelManipulationEnd; -} - -void grayscale(pd_canvas_t *graph, pd_rect_t rect) -{ - unsigned char avg; - - PixelManipulationBegin; - avg = (unsigned char)((pixel.red + pixel.green + pixel.blue) / 3); - pixel.red = avg; - pixel.green = avg; - pixel.blue = avg; - PixelManipulationEnd; -} - -void sepia(pd_canvas_t *graph, pd_rect_t rect) -{ - PixelManipulationBegin; - pixel.red = (unsigned char)y_min( - round(0.393 * pixel.red + 0.769 * pixel.green + 0.189 * pixel.blue), - 255); - pixel.green = (unsigned char)y_min( - round(0.349 * pixel.red + 0.686 * pixel.green + 0.168 * pixel.blue), - 255); - pixel.blue = (unsigned char)y_min( - round(0.272 * pixel.red + 0.534 * pixel.green + 0.131 * pixel.blue), - 255); - PixelManipulationEnd; -} - -int main(void) -{ - int i; - pd_canvas_t graph = { 0 }; - pd_rect_t rects[4]; - - if (pd_read_image_from_file("dog.jpg", &graph) != 0) { - return -1; - } - for (i = 0; i < 4; ++i) { - rects[i].height = graph.height; - rects[i].width = graph.width / 4; - rects[i].x = i * rects[i].width; - rects[i].y = 0; - } - sepia(&graph, rects[1]); - grayscale(&graph, rects[2]); - invert(&graph, rects[3]); - pd_write_png_file("test_pixel_manipulation.png", &graph); - return 0; -} diff --git a/tests/test_render.c b/tests/test_render.c deleted file mode 100644 index 724cce960..000000000 --- a/tests/test_render.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * tests/test_render.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include -#include -#include -#include - -#define SCREEN_WIDTH 1600 -#define SCREEN_HEIGHT 900 -#define BLOCK_COUNT 60 - -static struct TestStatus { - size_t color_index; - unsigned int fps; - ui_widget_t* box; -} self; - -void UpdateWidgetStyle(ui_widget_t* w, void* arg) -{ - size_t index; - pd_color_t color; - - index = w->index % BLOCK_COUNT + w->index / BLOCK_COUNT; - index = ((index + self.color_index) * 256 / BLOCK_COUNT) % 512; - color.red = 255; - color.green = (unsigned char)(index > 255 ? 511 - index : index); - color.blue = 0; - color.alpha = 255; - ui_widget_set_style_color_value(w, css_prop_background_color, - color.value); -} - -void UpdateFrame(void* arg) -{ - ui_widget_each(arg, UpdateWidgetStyle, NULL); -} - -void UpdateRenderStatus(void* arg) -{ - char str[32]; - - sprintf(str, "[size=24px]FPS: %d[/size]", self.fps); - ui_text_set_content(arg, str); - self.fps = 0; -} - -void InitModal(void) -{ - ui_widget_t* dimmer; - ui_widget_t* dialog; - - dimmer = ui_create_widget(NULL); - dialog = ui_create_widget(NULL); - ui_widget_resize(dialog, 400, 400); - ui_widget_set_style_string(dialog, "margin", "100px auto"); - ui_widget_set_style_string(dialog, "border-radius", "6px"); - ui_widget_set_style_string(dialog, "opacity", "0.9"); - ui_widget_set_style_string(dialog, "box-shadow", - "0 4px 8px rgba(0,0,0,0.4)"); - ui_widget_set_style_string(dialog, "background-color", "#fff"); - - ui_widget_set_style_string(dimmer, "top", "0"); - ui_widget_set_style_string(dimmer, "left", "0"); - ui_widget_set_style_string(dimmer, "width", "100%"); - ui_widget_set_style_string(dimmer, "height", "100%"); - ui_widget_set_style_string(dimmer, "position", "absolute"); - ui_widget_set_style_string(dimmer, "background-color", - "rgba(0,0,0,0.5)"); - - ui_widget_append(dimmer, dialog); - ui_widget_append(ui_root(), dimmer); -} - -void InitBackground(void) -{ - size_t i; - size_t c; - size_t n = BLOCK_COUNT; - ui_widget_t* w; - ui_widget_t* root; - pd_color_t color; - ui_widget_rules_t rules = { 0 }; - const float width = SCREEN_WIDTH * 1.0f / n; - const float height = SCREEN_HEIGHT * 1.0f / n; - - color.red = 255; - color.green = 0; - color.blue = 0; - color.alpha = 255; - root = ui_root(); - self.box = ui_create_widget(NULL); - for (i = 0; i < n * n; ++i) { - if (i % n == 0) { - ++self.color_index; - } - w = ui_create_widget(NULL); - c = ((i % n + i / n) * 256 / n) % 512; - color.green = (unsigned char)(c > 255 ? 511 - c : c); - ui_widget_resize(w, width, height); - ui_widget_set_style_string(w, "display", "inline-block"); - ui_widget_set_style_color_value(w, css_prop_background_color, - color.value); - ui_widget_append(self.box, w); - } - rules.cache_children_style = true; - rules.ignore_classes_change = true; - rules.ignore_status_change = true; - rules.max_update_children_count = -1; - rules.max_render_children_count = 0; - ui_widget_generate_hash(self.box); - ui_widget_set_rules(self.box, &rules); - ui_widget_append(root, self.box); -} - -void InitRenderStatus(void) -{ - ui_widget_t* root; - ui_widget_t* status; - - root = ui_root(); - status = ui_create_widget("text"); - ui_widget_set_style_string(status, "top", "10px"); - ui_widget_set_style_string(status, "right", "10px"); - ui_widget_set_style_string(status, "position", "absolute"); - ui_widget_set_style_string(status, "background", "#000"); - ui_widget_set_style_string(status, "color", "#fff"); - ui_widget_set_style_string(status, "padding", "10px 15px"); - ui_widget_append(root, status); - UpdateRenderStatus(status); - ptk_set_interval(1000, UpdateRenderStatus, status); -} - -int main(int argc, char* argv[]) -{ - size_t i; - int64_t t; - - logger_set_level(LOGGER_LEVEL_WARNING); - lcui_init(); - ui_widget_resize(ui_root(), SCREEN_WIDTH, SCREEN_HEIGHT); - InitBackground(); - InitModal(); - InitRenderStatus(); - printf("running rendering performance test\n"); - t = get_time_ms(); - self.color_index = 0; - for (i = 0; i < 600; ++i) { - UpdateFrame(self.box); - lcui_process_timers(); - lcui_ui_update(); - lcui_ui_render(); - ptk_app_present(); - ++self.fps; - ++self.color_index; - } - t = get_time_delta(t); - logger_warning( - "rendered %zu frames in %.2lfs, rendering speed is %.2lf fps\n", i, - t / 1000.f, i * 1000.f / t); - return 0; -} diff --git a/tests/test_scaling_support.c b/tests/test_scaling_support.c deleted file mode 100644 index 1b7303b97..000000000 --- a/tests/test_scaling_support.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * tests/test_scaling_support.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include -#include -#include - -enum { TYPE_DENSITY, TYPE_SCALED_DENSITY, TYPE_SCALE }; - -static void OnButtonClick(ui_widget_t *w, ui_event_t *e, void *arg) -{ - int *data = e->data; - switch (data[0]) { - case TYPE_DENSITY: - ui_set_density_level(data[1]); - break; - case TYPE_SCALED_DENSITY: - ui_set_scaled_density_level(data[1]); - break; - case TYPE_SCALE: - ui_set_scale(data[1] / 100.0f); - break; - } - ui_refresh_style(); -} - -static void SetButton(const char *id, int type, int level) -{ - int *data; - ui_widget_t *btn; - data = malloc(sizeof(int) * 2); - data[0] = type; - data[1] = level; - btn = ui_get_widget(id); - ui_widget_add_event_listener(btn, "click", OnButtonClick, data, free); -} - -static void InitButtons(void) -{ - SetButton("btn-density-small", TYPE_DENSITY, UI_DENSITY_LEVEL_SMALL); - SetButton("btn-density-normal", TYPE_DENSITY, UI_DENSITY_LEVEL_NORMAL); - SetButton("btn-density-large", TYPE_DENSITY, UI_DENSITY_LEVEL_LARGE); - SetButton("btn-density-big", TYPE_DENSITY, UI_DENSITY_LEVEL_BIG); - SetButton("btn-scaled-density-small", TYPE_SCALED_DENSITY, - UI_DENSITY_LEVEL_SMALL); - SetButton("btn-scaled-density-normal", TYPE_SCALED_DENSITY, - UI_DENSITY_LEVEL_NORMAL); - SetButton("btn-scaled-density-large", TYPE_SCALED_DENSITY, - UI_DENSITY_LEVEL_LARGE); - SetButton("btn-scaled-density-big", TYPE_SCALED_DENSITY, - UI_DENSITY_LEVEL_BIG); - SetButton("btn-scale-small", TYPE_SCALE, 75); - SetButton("btn-scale-normal", TYPE_SCALE, 100); - SetButton("btn-scale-large", TYPE_SCALE, 150); - SetButton("btn-scale-big", TYPE_SCALE, 200); -} - -int main(int argc, char **argv) -{ - ui_widget_t *pack; - - lcui_init(); - pack = ui_load_xml_file("test_scaling_support.xml"); - if (!pack) { - return -1; - } - ui_refresh_style(); - ui_root_append(pack); - ui_widget_unwrap(pack); - InitButtons(); - return lcui_main(); -} diff --git a/tests/test_scaling_support.css b/tests/test_scaling_support.css deleted file mode 100644 index 5c8781fae..000000000 --- a/tests/test_scaling_support.css +++ /dev/null @@ -1,49 +0,0 @@ -.text-box { - border: 1px solid #eee; - background: #f0f0f0; - display: inline-block; - margin-right: 10px; - padding: 5px 10px; - white-space: nowrap; -} -.image { - width: 91px; - height: 69px; - border: 1px solid #eee; - background-image: url(test_image_reader.png); - background-size: contain; - margin: 5px 0; -} -.container { - padding: 5px 0; -} -.text-sp { - font-size: 18sp; -} -.box-px { - width:80px; - text-align: center; -} -.box-dp { - width: 80dp; - border-width: 5dp; - text-align: center; -} -.text-px { - font-size: 18px; -} -.text-pt { - font-size: 12pt; -} -.p { - display: block; - font-size: 14px; - margin: 10px 0; -} -button { - margin-right: 10px; -} -root { - padding: 20px; - box-sizing: border-box; -} diff --git a/tests/test_scaling_support.xml b/tests/test_scaling_support.xml deleted file mode 100644 index 555c0b348..000000000 --- a/tests/test_scaling_support.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - Hello, World! - - - width: 80px - width: 80dp - - - font size: 18sp - font size: 18px - font size: 12pt - - Density level: - - Small - Normal - Large - Big - - Scaled density level: - - Small - Normal - Large - Big - - Scale level: - - Small - Normal - Large - Big - - - diff --git a/tests/test_scrollbar.c b/tests/test_scrollbar.c deleted file mode 100644 index 1822afde4..000000000 --- a/tests/test_scrollbar.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * tests/test_scrollbar.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#define PREVIEW_MODE -#include "./cases/test_scrollbar.c" -#include - -int main(int argc, char **argv) -{ - lcui_init(); - ui_widget_resize(ui_root(), 800, 640); - ui_load_css_string(test_css, __FILE__); - /* We have two ways to build content view */ - build_content_view_from_xml(); - build_content_view(); - return lcui_main(); -} diff --git a/tests/test_string_render.c b/tests/test_string_render.c deleted file mode 100644 index 7442f598b..000000000 --- a/tests/test_string_render.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * tests/test_string_render.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include - -int main(void) -{ - int ret; - pd_canvas_t img; - pd_pos_t pos = { 0, 80 }; - pd_rect_t area = { 0, 0, 320, 240 }; - pd_text_t* txt = pd_text_create(); - pd_text_style_t txtstyle; - - /* 初始化字体处理功能 */ - pd_font_library_init(); - - /* 创建一个图像,并使用灰色填充 */ - pd_canvas_init(&img); - pd_canvas_create(&img, 320, 240); - pd_canvas_fill(&img, pd_rgb(240, 240, 240)); - - /* 设置文本的字体大小 */ - pd_text_style_Init(&txtstyle); - txtstyle.pixel_size = 24; - txtstyle.has_pixel_size = true; - - /* 设置文本图层的固定尺寸、文本样式、文本内容、对齐方式 */ - pd_text_set_fixed_size(txt, 320, 240); - pd_text_set_style(txt, &txtstyle); - pd_text_set_align(txt, PD_TEXT_ALIGN_CENTER); - pd_text_write(txt, L"这是一段测试文本\nHello, World!", NULL); - pd_text_update(txt, NULL); - - /* 将文本图层绘制到图像中,然后将图像写入至 png 文件中 */ - pd_text_render_to(txt, area, pos, &img); - ret = pd_write_png_file("test_string_render.png", &img); - pd_canvas_destroy(&img); - - /* 释放字体处理功能相关资源 */ - pd_font_library_destroy(); - return ret; -} diff --git a/tests/test_text_resize.c b/tests/test_text_resize.c deleted file mode 100644 index 4ec40d007..000000000 --- a/tests/test_text_resize.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * tests/test_text_resize.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#define PREVIEW_MODE -#include "./cases/test_text_resize.c" -#include - -int main(int argc, char *argv[]) -{ - lcui_init(); - - build(); - ptk_set_timeout(2000, test_text_set_content, NULL); - ptk_set_timeout(3000, test_text_set_short_content_css, NULL); - ptk_set_timeout(4000, test_text_set_long_content_css, NULL); - - return lcui_main(); -} diff --git a/tests/test_touch.c b/tests/test_touch.c deleted file mode 100644 index d94a2f7a9..000000000 --- a/tests/test_touch.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * tests/test_touch.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -/** test_touch.c -- test touch support */ - -#include -#include -#include -#include - -/** 触点绑定记录 */ -typedef struct TouchPointBindingRec_ { - int point_id; /**< 触点 ID */ - ui_widget_t *widget; /**< 部件 */ - list_node_t node; /**< 在链表中的结点 */ - bool is_valid; /**< 是否有效 */ -} TouchPointBindingRec, *TouchPointBinding; - -/** 触点绑定记录列表 */ -static list_t touch_bindings; - -static void OnTouchWidget(ui_widget_t *w, ui_event_t *e, void *arg) -{ - ui_touch_point_t *point; - TouchPointBinding binding; - - if (e->touch.n_points == 0) { - return; - } - binding = e->data; - point = &e->touch.points[0]; - switch (point->state) { - case UI_EVENT_TOUCHMOVE: - ui_widget_move(w, point->x - 32.0f, point->y - 32.0f); - break; - case UI_EVENT_TOUCHUP: - if (!binding->is_valid) { - break; - } - /* 当触点释放后销毁部件及绑定记录 */ - ui_widget_release_touch_capture(w, -1); - list_unlink(&touch_bindings, &binding->node); - binding->is_valid = false; - ui_widget_remove(w); - free(binding); - break; - case UI_EVENT_TOUCHDOWN: - default: - break; - } -} - -static void OnTouch(ptk_event_t *e, void *arg) -{ - int i; - ui_widget_t *w; - list_node_t *node; - touch_point_t *point; - pd_color_t bgcolor = pd_rgb(255, 0, 0); - - for (i = 0; i < e->touch.n_points; ++i) { - TouchPointBinding binding; - bool is_existed = false; - point = &e->touch.points[i]; - _DEBUG_MSG("point: %d\n", point->id); - /* 检查该触点是否已经被绑定 */ - for (list_each(node, &touch_bindings)) { - binding = node->data; - if (binding->point_id == point->id) { - is_existed = true; - } - } - if (is_existed) { - continue; - } - w = ui_create_widget(NULL); - /* 新建绑定记录 */ - binding = malloc(sizeof(TouchPointBindingRec)); - binding->point_id = point->id; - binding->node.data = binding; - binding->is_valid = true; - binding->widget = w; - ui_widget_resize(w, 64, 64); - ui_widget_move(w, point->x - 32.0f, point->y - 32.0f); - /* 设置让该部件捕获当前触点 */ - ui_widget_set_touch_capture(w, binding->point_id); - ui_widget_on(w, "touch", OnTouchWidget, binding, NULL); - ui_widget_set_style_string(w, "position", "absolute"); - ui_widget_set_style_color_value(w, css_prop_background_color, - bgcolor.value); - list_append_node(&touch_bindings, &binding->node); - ui_root_append(w); - } -} - -int main(int argc, char **argv) -{ - lcui_init(); - list_create(&touch_bindings); - ptk_on_event(PTK_EVENT_TOUCH, OnTouch, NULL); - return lcui_main(); -} diff --git a/tests/test_widget.c b/tests/test_widget.c deleted file mode 100644 index a67be2c19..000000000 --- a/tests/test_widget.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * tests/test_widget.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include -#include -#include - -int main(void) -{ - clock_t c; - size_t i, n = 100000; - double sec; - - ui_widget_t *box, *w; - - ui_init(); - box = ui_create_widget(NULL); - - c = clock(); - logger_debug("start create %zu widgets...\n", n); - ui_widget_append(ui_root(), box); - for (i = 0; i < n; ++i) { - w = ui_create_widget("text"); - ui_text_set_content_w(w, L"hello, test"); - ui_widget_append(box, w); - } - sec = (clock() - c) * 1.0 / CLOCKS_PER_SEC; - logger_debug("%zu widgets have been created, which took %gs\n", n, sec); - logger_debug("it should take less than 1s\n"); - - logger_debug("start update %zu widgets...\n", n); - c = clock(); - ui_update(); - ui_update(); - sec = (clock() - c) * 1.0 / CLOCKS_PER_SEC; - logger_debug("%zu widgets have been updated, which took %gs\n", n, sec); - logger_debug("it should take less than 6s\n"); - - logger_debug("start remove %zu widgets...\n", n); - c = clock(); - ui_widget_empty(box); - sec = (clock() - c) * 1.0 / CLOCKS_PER_SEC; - logger_debug("%zu widgets have been removed, which took %gs\n", n, sec); - logger_debug("it should take less than 0.5s\n"); - - logger_debug("start destroy %zu widgets...\n", n); - c = clock(); - ui_update(); - sec = (clock() - c) * 1.0 / CLOCKS_PER_SEC; - logger_debug("%zu widgets have been destroyed, which took %gs\n", n, - sec); - logger_debug("it should take less than 1s\n"); - - ui_destroy(); - return 0; -} diff --git a/tests/test_widget_opacity.c b/tests/test_widget_opacity.c deleted file mode 100644 index 67e4378b0..000000000 --- a/tests/test_widget_opacity.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * tests/test_widget_opacity.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#define PREVIEW_MODE -#include -#include "./cases/test_widget_opacity.c" - -static void on_opacity_minus(ui_widget_t *w, ui_event_t *e, void *arg) -{ - wchar_t str[32]; - float opacity = self.parent->computed_style.opacity - 0.1f; - - if (opacity < 0.1f) { - opacity = 0.1f; - } - swprintf(str, 32, L"%.1f", opacity); - ui_widget_set_style_numeric_value(self.parent, css_prop_opacity, - opacity); - ui_text_set_content_w(self.text, str); -} - -static void on_opacity_plus(ui_widget_t *w, ui_event_t *e, void *arg) -{ - wchar_t str[32]; - float opacity = self.parent->computed_style.opacity + 0.1f; - - if (opacity > 1.0f) { - opacity = 1.0f; - } - swprintf(str, 32, L"%.1f", opacity); - ui_widget_set_style_numeric_value(self.parent, css_prop_opacity, - opacity); - ui_text_set_content_w(self.text, str); -} - -int main(int argc, char **argv) -{ - ui_widget_t *btn_plus, *btn_minus; - - lcui_init(); - build(); - btn_plus = ui_get_widget("btn-plus"); - btn_minus = ui_get_widget("btn-minus"); - ui_widget_on(btn_plus, "click", on_opacity_plus, NULL); - ui_widget_on(btn_minus, "click", on_opacity_minus, NULL); - return lcui_main(); -} diff --git a/tests/test_widget_render.c b/tests/test_widget_render.c deleted file mode 100644 index 83387fcfa..000000000 --- a/tests/test_widget_render.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * tests/test_widget_render.c - * - * Copyright (c) 2023, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#include -#include - -int main(void) -{ - int ret; - pd_canvas_t canvas; - ui_widget_t *root, *box, *txt; - pd_context_t paint; - pd_rect_t area = { 40, 40, 320, 240 }; - - lcui_init(); - - root = ui_create_widget(NULL); - box = ui_create_widget(NULL); - txt = ui_create_widget("text"); - - /* 创建一块灰色的画板 */ - pd_canvas_init(&canvas); - pd_canvas_create(&canvas, 320, 240); - pd_canvas_fill(&canvas, pd_rgb(240, 240, 240)); - - /* 初始化一个绘制实例,绘制区域为整个画板 */ - paint.with_alpha = false; - paint.rect.width = 320; - paint.rect.height = 320; - paint.rect.x = paint.rect.y = 0; - pd_canvas_quote(&paint.canvas, &canvas, &area); - - /* 设定基本的样式和内容 */ - ui_widget_set_style_string(box, "padding", "20px"); - ui_widget_set_style_string(box, "border", "1px solid rgb(201,230,242)"); - ui_widget_set_style_string(box, "background-color", "rgb(242,249,252)"); - ui_text_set_content_w(txt, L"[size=24px]这是一段测试文本[/size]"); - ui_widget_append(box, txt); - ui_widget_append(root, box); - /* 更新部件,此处的更新顺序必须是父级到子级 */ - ui_widget_update(root); - ui_widget_update(box); - ui_widget_update(txt); - - /* 渲染部件 */ - ui_widget_render(box, &paint); - ret = pd_write_png_file("test_widget_render.png", &canvas); - pd_canvas_destroy(&canvas); - - lcui_destroy(); - return ret; -} diff --git a/tests/xmake.lua b/tests/xmake.lua index 412795ae5..9a692de36 100644 --- a/tests/xmake.lua +++ b/tests/xmake.lua @@ -1,75 +1,12 @@ -add_deps("lcui") -set_default(false) -set_rundir("./") -add_includedirs("./include") - -target("test_block_layout") - add_files("test_block_layout.c") - add_deps("ctest") - -target("test_border") - add_files("test_border.c") - -target("test_box_shadow") - add_files("test_box_shadow.c") - -target("test_char_render") - add_files("test_char_render.c") - -target("test_fill_rect") - add_files("test_fill_rect.c") - -target("test_fill_rect_with_rgba") - add_files("test_fill_rect_with_rgba.c") - -target("test_flex_layout") - add_files("test_flex_layout.c") - add_deps("ctest") - -target("test_image_scaling_bench") - add_files("test_image_scaling_bench.c") - -target("test_mix_rect_with_opacity") - add_files("test_mix_rect_with_opacity.c") - -target("test_paint_background") - add_files("test_paint_background.c") - -target("test_paint_border") - add_files("test_paint_border.c") - -target("test_paint_boxshadow") - add_files("test_paint_boxshadow.c") - -target("test_pixel_manipulation") - add_files("test_pixel_manipulation.c") - -target("test_render") - add_files("test_render.c") - -target("test_scaling_support") - add_files("test_scaling_support.c") - -target("test_scrollbar") - add_files("test_scrollbar.c") - add_deps("ctest") - -target("test_string_render") - add_files("test_string_render.c") - -target("test_text_resize") - add_files("test_text_resize.c") - add_deps("ctest") - -target("test_touch") - add_files("test_touch.c") - -target("test_widget") - add_files("test_widget.c") - -target("test_widget_opacity") - add_files("test_widget_opacity.c") - add_deps("ctest") - -target("test_widget_render") - add_files("test_widget_render.c") +target("lcui-tests") + set_default(false) + set_kind("binary") + set_group("tests") + set_rundir("fixtures") + add_includedirs("helpers") + add_files("main.c", "integration/*.c", "scenes/*.c") + add_deps("lcui", "ctest") + add_rules("tests.runnable") + add_tests("default", {group = "tests"}) + +includes("previews/xmake.lua") diff --git a/xmake.lua b/xmake.lua index 768c83438..7e15f9d33 100644 --- a/xmake.lua +++ b/xmake.lua @@ -22,6 +22,50 @@ add_includedirs( "include", {public = true} ) + +option("memcheck") + set_default(false) + set_showmenu(true) + set_description("Enable memory check tools (drmemory on Windows, valgrind on Linux)") +option_end() + +rule("tests.runnable") + on_test(function (target, opt) + import("core.base.option") + opt = opt or {} + local args = opt.runargs or {} + local rundir = opt.rundir or target:rundir() + local envs = opt.runenvs + local exec_opt = {curdir = rundir, envs = envs} + local exepath = path.absolute(target:targetfile()) + if has_config("memcheck") then + local cmd + if is_plat("windows") then + cmd = {"drmemory", "--", exepath} + else + cmd = {"valgrind", + "--leak-check=full", + "--error-exitcode=42", + "--num-callers=20", + exepath} + end + for _, a in ipairs(args) do + table.insert(cmd, a) + end + local ok = try { function () + os.execv(cmd[1], table.slice(cmd, 2), exec_opt) + return true + end } + return ok ~= nil, ok == nil and "memcheck failed" or nil + end + local ok = try { function () + os.execv(exepath, args, exec_opt) + return true + end } + return ok ~= nil, ok == nil and "test failed" or nil + end) +rule_end() + includes("lib/*/xmake.lua") includes("tests/xmake.lua") @@ -41,36 +85,6 @@ else end end -target("lcui_tests") - set_default(false) - set_kind("binary") - set_rundir("tests") - add_includedirs("tests/include") - add_files("tests/run_tests.c", "tests/cases/*.c") - add_deps("ctest", "lcui") - on_run(function (target) - import("core.base.option") - local argv = {} - local options = {{nil, "memcheck", "k", nil, "enable memory check."}} - local args = option.raw_parse(option.get("arguments") or {}, options) - os.cd("$(scriptdir)/tests") - if args.memcheck then - if is_plat("windows") then - table.insert(argv, target:targetfile()) - os.execv("drmemory", argv) - else - table.insert(argv, "valgrind") - table.insert(argv, "--leak-check=full") - table.insert(argv, "--error-exitcode=42") - table.insert(argv, "--num-callers=20") - table.insert(argv, target:targetfile()) - os.execv("sudo", argv) - end - else - os.execv(target:targetfile()) - end - end) - target("lcui") set_kind("$(kind)") add_files("src/**.c") From 58a97023165b2aa2ed0061f979cfcba1e559f819 Mon Sep 17 00:00:00 2001 From: Liu Date: Sat, 23 May 2026 19:18:28 +0800 Subject: [PATCH 08/66] refactor(ui-router): extract router widgets into a new lib Create lib/ui-router/ as a thin UI binding layer between libui and librouter, exposing the router-link and router-view widgets under . * Move src/widgets/router_{link,view}.c and the matching public headers into lib/ui-router/src and lib/ui-router/include. * Drop include/LCUI/widgets/router_{link,view}.h and the corresponding entries in include/LCUI/widgets.h; src/lcui_widgets.c now pulls registrations from . * Wire libui-router into the root xmake.lua add_includedirs and lcui add_deps chain; libui-router depends on yutil + libui + librouter only. * tests/integration/test_router.c stays at the integration layer (router widgets exercise text inheritance and other libui internals); only its #include set is updated to use . * Bump CHANGELOG and add bilingual lib/ui-router/README. --- CHANGELOG.md | 1 + CHANGELOG.zh-cn.md | 1 + include/LCUI/widgets.h | 2 -- include/LCUI/widgets/router_link.h | 30 ----------------- include/LCUI/widgets/router_view.h | 27 --------------- lib/ui-router/README.md | 29 ++++++++++++++++ lib/ui-router/README.zh-cn.md | 29 ++++++++++++++++ lib/ui-router/include/ui_router.h | 19 +++++++++++ lib/ui-router/include/ui_router/common.h | 33 +++++++++++++++++++ lib/ui-router/include/ui_router/link.h | 30 +++++++++++++++++ lib/ui-router/include/ui_router/view.h | 27 +++++++++++++++ lib/ui-router/src/config.h.in | 5 +++ .../router_link.c => lib/ui-router/src/link.c | 8 ++--- .../router_view.c => lib/ui-router/src/view.c | 8 ++--- lib/ui-router/xmake.lua | 15 +++++++++ src/lcui_widgets.c | 1 + tests/integration/test_router.c | 1 + xmake.lua | 2 ++ 18 files changed, 201 insertions(+), 67 deletions(-) delete mode 100644 include/LCUI/widgets/router_link.h delete mode 100644 include/LCUI/widgets/router_view.h create mode 100644 lib/ui-router/README.md create mode 100644 lib/ui-router/README.zh-cn.md create mode 100644 lib/ui-router/include/ui_router.h create mode 100644 lib/ui-router/include/ui_router/common.h create mode 100644 lib/ui-router/include/ui_router/link.h create mode 100644 lib/ui-router/include/ui_router/view.h create mode 100644 lib/ui-router/src/config.h.in rename src/widgets/router_link.c => lib/ui-router/src/link.c (97%) rename src/widgets/router_view.c => lib/ui-router/src/view.c (97%) create mode 100644 lib/ui-router/xmake.lua diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c7270f6c..87278adaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - `lib/ptk` - `lib/thread` - `lib/router` + - `lib/ui-router` - `lib/worker` - `lib/ui` - `lib/ui-xml` diff --git a/CHANGELOG.zh-cn.md b/CHANGELOG.zh-cn.md index b41b197da..c6df4ed54 100644 --- a/CHANGELOG.zh-cn.md +++ b/CHANGELOG.zh-cn.md @@ -10,6 +10,7 @@ - lib/ptk - lib/thread - lib/router + - lib/ui-router - lib/worker - lib/ui - lib/ui-xml diff --git a/include/LCUI/widgets.h b/include/LCUI/widgets.h index 1b3b0a175..ce0c9cd19 100644 --- a/include/LCUI/widgets.h +++ b/include/LCUI/widgets.h @@ -17,5 +17,3 @@ #include "widgets/scrollbar.h" #include "widgets/textinput.h" #include "widgets/textcaret.h" -#include "widgets/router_link.h" -#include "widgets/router_view.h" diff --git a/include/LCUI/widgets/router_link.h b/include/LCUI/widgets/router_link.h deleted file mode 100644 index 2896ea7e0..000000000 --- a/include/LCUI/widgets/router_link.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * include/LCUI/widgets/router_link.h - * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#ifndef LCUI_INCOIDE_ROUTER_LINK_H -#define LCUI_INCOIDE_ROUTER_LINK_H - -#include -#include -#include - -LCUI_BEGIN_HEADER - -LCUI_API void ui_router_link_set_location( - ui_widget_t *w, router_location_t *location); - -LCUI_API void ui_router_link_set_exact(ui_widget_t *w, bool exact); - -LCUI_API void ui_register_router_link(void); - -LCUI_END_HEADER - -#endif diff --git a/include/LCUI/widgets/router_view.h b/include/LCUI/widgets/router_view.h deleted file mode 100644 index 850171644..000000000 --- a/include/LCUI/widgets/router_view.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * include/LCUI/widgets/router_view.h - * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. - * - * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. - */ - -#ifndef LCUI_INCOIDE_ROUTER_VIEW_H -#define LCUI_INCOIDE_ROUTER_VIEW_H - -#include -#include - -LCUI_BEGIN_HEADER - -LCUI_API ui_widget_t *ui_router_view_get_matched_widget( - ui_widget_t *w); - -LCUI_API void ui_register_router_view(void); - -LCUI_END_HEADER - -#endif diff --git a/lib/ui-router/README.md b/lib/ui-router/README.md new file mode 100644 index 000000000..3714eaa4d --- /dev/null +++ b/lib/ui-router/README.md @@ -0,0 +1,29 @@ +# libui-router + +(**English**/[中文](README.zh-cn.md)) + +`libui-router` is the UI binding layer that connects [librouter](../router/README.md) to [libui](../ui/) widgets. + +It ships two widgets: + +- `router-link` — a clickable widget that triggers navigation; mirrors `` from Vue Router. Toggles `router-link-active` and `router-link-exact-active` classes based on the current route. +- `router-view` — a route outlet that renders the matched component for the current route. + +## Usage + +```c +#include +#include + +ui_init(); +ui_register_router_link(); +ui_register_router_view(); + +/* Now "router-link" and "router-view" widget types are available. */ +``` + +When LCUI is used as a whole, `lcui_init()` already calls these registration functions through `lcui_widgets_init()`; this lib only needs to be called manually if you embed `libui-router` without the LCUI top-level shell. + +## License + +[MIT licensed](../../LICENSE.TXT). diff --git a/lib/ui-router/README.zh-cn.md b/lib/ui-router/README.zh-cn.md new file mode 100644 index 000000000..31b335efb --- /dev/null +++ b/lib/ui-router/README.zh-cn.md @@ -0,0 +1,29 @@ +# libui-router + +([English](README.md)/**中文**) + +`libui-router` 是连接 [librouter](../router/README.zh-cn.md) 与 [libui](../ui/) 部件系统的 UI 绑定层。 + +它提供两个部件: + +- `router-link` —— 可点击触发路由跳转的部件,对应 Vue Router 的 ``。会根据当前路由切换 `router-link-active` 和 `router-link-exact-active` 类名。 +- `router-view` —— 路由出口,渲染当前路由匹配到的组件。 + +## 用法 + +```c +#include +#include + +ui_init(); +ui_register_router_link(); +ui_register_router_view(); + +/* 此后 "router-link" 与 "router-view" 部件类型可用。 */ +``` + +在使用完整的 LCUI 时,`lcui_init()` 会通过 `lcui_widgets_init()` 自动调用上述注册函数;只有在脱离 LCUI 顶层壳直接嵌入 `libui-router` 时才需要手动调用。 + +## 许可 + +代码基于 [MIT 许可协议](../../LICENSE.TXT) 发布。 diff --git a/lib/ui-router/include/ui_router.h b/lib/ui-router/include/ui_router.h new file mode 100644 index 000000000..dcd300dc2 --- /dev/null +++ b/lib/ui-router/include/ui_router.h @@ -0,0 +1,19 @@ +/* + * lib/ui-router/include/ui_router.h: -- The router widgets for LCUI. + * + * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#ifndef LIB_UI_ROUTER_INCLUDE_UI_ROUTER_H +#define LIB_UI_ROUTER_INCLUDE_UI_ROUTER_H + +#include "ui_router/common.h" +#include "ui_router/link.h" +#include "ui_router/view.h" + +#endif diff --git a/lib/ui-router/include/ui_router/common.h b/lib/ui-router/include/ui_router/common.h new file mode 100644 index 000000000..f8f67d456 --- /dev/null +++ b/lib/ui-router/include/ui_router/common.h @@ -0,0 +1,33 @@ +/* + * lib/ui-router/include/ui_router/common.h + * + * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include "config.h" +#ifdef __cplusplus +#define LIBUI_ROUTER_BEGIN_DECLS extern "C" { +#define LIBUI_ROUTER_END_DECLS } +#else +#define LIBUI_ROUTER_BEGIN_DECLS +#define LIBUI_ROUTER_END_DECLS +#endif + +#ifndef LIBUI_ROUTER_PUBLIC +#if defined(_MSC_VER) && !defined(LIBUI_ROUTER_STATIC_BUILD) +#ifdef LIBUI_ROUTER_DLL_EXPORT +#define LIBUI_ROUTER_PUBLIC __declspec(dllexport) +#else +#define LIBUI_ROUTER_PUBLIC __declspec(dllimport) +#endif +#elif __GNUC__ >= 4 +#define LIBUI_ROUTER_PUBLIC extern __attribute__((visibility("default"))) +#else +#define LIBUI_ROUTER_PUBLIC extern +#endif +#endif diff --git a/lib/ui-router/include/ui_router/link.h b/lib/ui-router/include/ui_router/link.h new file mode 100644 index 000000000..5daf55f8a --- /dev/null +++ b/lib/ui-router/include/ui_router/link.h @@ -0,0 +1,30 @@ +/* + * lib/ui-router/include/ui_router/link.h + * + * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#ifndef LIB_UI_ROUTER_INCLUDE_LINK_H +#define LIB_UI_ROUTER_INCLUDE_LINK_H + +#include +#include +#include "common.h" + +LIBUI_ROUTER_BEGIN_DECLS + +LIBUI_ROUTER_PUBLIC void ui_router_link_set_location( + ui_widget_t *w, router_location_t *location); + +LIBUI_ROUTER_PUBLIC void ui_router_link_set_exact(ui_widget_t *w, bool exact); + +LIBUI_ROUTER_PUBLIC void ui_register_router_link(void); + +LIBUI_ROUTER_END_DECLS + +#endif diff --git a/lib/ui-router/include/ui_router/view.h b/lib/ui-router/include/ui_router/view.h new file mode 100644 index 000000000..06da5b04d --- /dev/null +++ b/lib/ui-router/include/ui_router/view.h @@ -0,0 +1,27 @@ +/* + * lib/ui-router/include/ui_router/view.h + * + * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#ifndef LIB_UI_ROUTER_INCLUDE_VIEW_H +#define LIB_UI_ROUTER_INCLUDE_VIEW_H + +#include +#include "common.h" + +LIBUI_ROUTER_BEGIN_DECLS + +LIBUI_ROUTER_PUBLIC ui_widget_t *ui_router_view_get_matched_widget( + ui_widget_t *w); + +LIBUI_ROUTER_PUBLIC void ui_register_router_view(void); + +LIBUI_ROUTER_END_DECLS + +#endif diff --git a/lib/ui-router/src/config.h.in b/lib/ui-router/src/config.h.in new file mode 100644 index 000000000..f90df4501 --- /dev/null +++ b/lib/ui-router/src/config.h.in @@ -0,0 +1,5 @@ +#define LIBUI_ROUTER_VERSION "${VERSION}" +#define LIBUI_ROUTER_VERSION_MAJOR ${VERSION_MAJOR} +#define LIBUI_ROUTER_VERSION_MINOR ${VERSION_MINOR} +#define LIBUI_ROUTER_VERSION_ALTER ${VERSION_ALTER} +${define LIBUI_ROUTER_STATIC_BUILD} diff --git a/src/widgets/router_link.c b/lib/ui-router/src/link.c similarity index 97% rename from src/widgets/router_link.c rename to lib/ui-router/src/link.c index 10ede9953..444adb5d1 100644 --- a/src/widgets/router_link.c +++ b/lib/ui-router/src/link.c @@ -1,7 +1,7 @@ -/* - * src/widgets/router_link.c +/* + * lib/ui-router/src/link.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -11,7 +11,7 @@ #include #include -#include +#include // Refer: https://router.vuejs.org/api/#router-link-props diff --git a/src/widgets/router_view.c b/lib/ui-router/src/view.c similarity index 97% rename from src/widgets/router_view.c rename to lib/ui-router/src/view.c index 4e8e4ee97..1a9f66bed 100644 --- a/src/widgets/router_view.c +++ b/lib/ui-router/src/view.c @@ -1,7 +1,7 @@ -/* - * src/widgets/router_view.c +/* + * lib/ui-router/src/view.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -11,7 +11,7 @@ #include #include -#include +#include typedef struct ui_router_view { size_t index; diff --git a/lib/ui-router/xmake.lua b/lib/ui-router/xmake.lua new file mode 100644 index 000000000..b244a5c0a --- /dev/null +++ b/lib/ui-router/xmake.lua @@ -0,0 +1,15 @@ +set_project("libui-router") +set_version("0.1.0-a") + +target("libui-router") + set_kind("$(kind)") + add_files("src/**.c") + add_deps("yutil", "libui", "librouter") + set_configdir("include/ui_router") + add_configfiles("src/config.h.in") + add_headerfiles("include/ui_router.h", "include/(ui_router/*.h)") + if is_kind("static") then + set_configvar("LIBUI_ROUTER_STATIC_BUILD", 1) + elseif is_plat("windows") then + add_defines("LIBUI_ROUTER_DLL_EXPORT") + end diff --git a/src/lcui_widgets.c b/src/lcui_widgets.c index a3fa23e33..2a314ee35 100644 --- a/src/lcui_widgets.c +++ b/src/lcui_widgets.c @@ -10,6 +10,7 @@ */ #include +#include void lcui_widgets_init(void) { diff --git a/tests/integration/test_router.c b/tests/integration/test_router.c index 63a1bd656..b2bae67d9 100644 --- a/tests/integration/test_router.c +++ b/tests/integration/test_router.c @@ -2,6 +2,7 @@ #include #include #include +#include void test_router_components(void) { diff --git a/xmake.lua b/xmake.lua index 7e15f9d33..4849472f8 100644 --- a/xmake.lua +++ b/xmake.lua @@ -19,6 +19,7 @@ add_includedirs( "lib/ui-server/include", "lib/ui-cursor/include", "lib/ui-xml/include", + "lib/ui-router/include", "include", {public = true} ) @@ -110,6 +111,7 @@ target("lcui") "libui-cursor", "libui-server", "librouter", + "libui-router", "libui-xml" ) add_headerfiles("include/LCUI.h", "include/(LCUI/**.h)") From ec90e378d78957ffd1cea2997c0731a4d2990090 Mon Sep 17 00:00:00 2001 From: Liu Date: Sat, 23 May 2026 22:32:49 +0800 Subject: [PATCH 09/66] build(yutil): bump submodule for tests rundir fix Pulls in yutil c91be801 which sets the yutil-tests rundir to scriptdir, fixing the Windows execv error 267 reported by xmake run yutil-tests. --- lib/yutil | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/yutil b/lib/yutil index e75df7841..c91be8015 160000 --- a/lib/yutil +++ b/lib/yutil @@ -1 +1 @@ -Subproject commit e75df78415a7087020d2aab85356a25e72b8b014 +Subproject commit c91be8015d01b0785794ec83bfa44079952f8aae From d89b1989103d8e42e48c07f9a4b84463de1e1641 Mon Sep 17 00:00:00 2001 From: Liu Date: Sat, 23 May 2026 22:46:37 +0800 Subject: [PATCH 10/66] ci: cache xmake packages and bump action versions Add actions/cache step covering xmake package and repository directories on both Linux and Windows runners. Cache key is keyed by runner OS, build mode (coverage on Linux, release on Windows) and the hashes of root and examples xmake-requires.lock so coverage and release artifacts do not pollute each other and examples deps share the same cache. Bump actions/checkout to v4 with submodules: recursive (replacing the manual submodule update step), upload-artifact to v4 and download-artifact to v4. --- .github/workflows/ccpp.yml | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 7ff01bcf3..f95d46954 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -14,15 +14,26 @@ jobs: runs-on: ${{ matrix.os }} name: "Builds binaries on ${{ matrix.os }}" steps: - - uses: actions/checkout@v1 - + - uses: actions/checkout@v4 + with: + submodules: recursive + - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: branch@dev - - name: Update git submodule - run: | - git submodule update --init + - name: Cache xmake packages + uses: actions/cache@v4 + with: + path: | + ~/.xmake/packages + ~/.xmake/repositories + ~/AppData/Local/.xmake/packages + ~/AppData/Local/.xmake/repositories + key: ${{ runner.os }}-xmake-${{ runner.os == 'Linux' && 'coverage' || 'release' }}-${{ hashFiles('xmake-requires.lock', 'examples/xmake-requires.lock') }} + restore-keys: | + ${{ runner.os }}-xmake-${{ runner.os == 'Linux' && 'coverage' || 'release' }}- + ${{ runner.os }}-xmake- - name: Install tools if: runner.os == 'Linux' @@ -80,13 +91,13 @@ jobs: mv ../dist/lcui-examples/bin/* ../dist/lcui-examples/ rm -r ../dist/lcui-examples/bin - - uses: actions/upload-artifact@master + - uses: actions/upload-artifact@v4 with: name: lcui${{ env.TARGET_MAJOR }}-${{ env.TARGET_VERSION }}-${{ env.TARGET_KIND }} (${{ runner.os }}) path: | dist/lcui-package - - uses: actions/upload-artifact@master + - uses: actions/upload-artifact@v4 with: name: lcui${{ env.TARGET_MAJOR }}-examples (${{ runner.os }}) path: | @@ -100,10 +111,10 @@ jobs: ARTIFACT_DIR: ./release steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: ${{ env.ARTIFACT_DIR }} From 61258dae7cb4b0ed303e4cb5bd0a40ac70d6815d Mon Sep 17 00:00:00 2001 From: Liu Date: Sat, 23 May 2026 23:04:17 +0800 Subject: [PATCH 11/66] =?UTF-8?q?fix(pandagl):=20implicit=20declaration=20?= =?UTF-8?q?of=20function=20=E2=80=98pd=5Frect=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pandagl/include/pandagl/rect.h | 6 ++++++ lib/pandagl/src/rect.c | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/pandagl/include/pandagl/rect.h b/lib/pandagl/include/pandagl/rect.h index 76e77801b..272b21390 100644 --- a/lib/pandagl/include/pandagl/rect.h +++ b/lib/pandagl/include/pandagl/rect.h @@ -18,6 +18,12 @@ PD_BEGIN_DECLS +PD_INLINE pd_rect_t pd_rect(int x, int y, int width, int height) +{ + pd_rect_t rect = { x, y, width, height }; + return rect; +} + PD_INLINE bool pd_rect_is_include(pd_rect_t *a, pd_rect_t *b) { return (b->x >= a->x && b->x + b->width <= a->x + a->width && diff --git a/lib/pandagl/src/rect.c b/lib/pandagl/src/rect.c index 8ee89740d..d2f63df0a 100644 --- a/lib/pandagl/src/rect.c +++ b/lib/pandagl/src/rect.c @@ -13,12 +13,6 @@ #include #include -pd_rect_t pd_rect(int x, int y, int width, int height) -{ - pd_rect_t rect = { x, y, width, height }; - return rect; -} - pd_rect_t pd_rect_crop(const pd_rect_t *rect, int container_width, int container_height) { From fb4ea2f0da6dda127ae385228673487f992fc8b2 Mon Sep 17 00:00:00 2001 From: Liu Date: Sun, 24 May 2026 17:55:45 +0800 Subject: [PATCH 12/66] ci: add xvfb and codecov-action --- .github/workflows/ccpp.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index f95d46954..158d37f98 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -39,7 +39,7 @@ jobs: if: runner.os == 'Linux' run: | sudo apt-get update --fix-missing - sudo apt-get install debhelper lcov valgrind -yy + sudo apt-get install debhelper lcov valgrind xvfb -yy sudo apt-get install libfreetype6-dev libpng-dev libyaml-dev libomp-dev libx11-dev ninja-build fontconfig libfontconfig1-dev libjpeg-dev - name: Configure @@ -66,11 +66,14 @@ jobs: if: runner.os == 'Linux' run: | xmake f -m debug --memcheck=y - xmake test + xvfb-run -a xmake test - name: Upload reports to Codecov if: runner.os == 'Linux' - run: bash <(curl -s https://codecov.io/bash); + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: false - name: Build for release run: | From befb118fa90b575821cab24ce16bd9f1fa25c1a8 Mon Sep 17 00:00:00 2001 From: Liu Date: Sun, 24 May 2026 18:04:54 +0800 Subject: [PATCH 13/66] ci: remove yutil tests --- .github/workflows/ccpp.yml | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 158d37f98..e6437ab4f 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -48,15 +48,10 @@ jobs: - name: Configure for coverage mode if: runner.os == 'Linux' - run: xmake config -y -v -k ${{ env.TARGET_KIND }} -m coverage --ci-env=y + run: xmake config -y -v -k ${{ env.TARGET_KIND }} -m coverage --ci-env=y --memcheck=y - name: Build - run: | - xmake - xmake build yutil-tests - - - name: Run yutil tests - run: xmake run yutil-tests + run: xmake - name: Run all tests if: runner.os == 'Windows' @@ -64,9 +59,7 @@ jobs: - name: Run all tests with memcheck if: runner.os == 'Linux' - run: | - xmake f -m debug --memcheck=y - xvfb-run -a xmake test + run: xvfb-run -a xmake test - name: Upload reports to Codecov if: runner.os == 'Linux' From f87d215363c83a8b3bf95fee6fb0758483af1965 Mon Sep 17 00:00:00 2001 From: Liu Date: Sun, 24 May 2026 22:23:27 +0800 Subject: [PATCH 14/66] fix(pandagl): text deletion crashes and pd_text_dump missing line breaks pd_text_delete_ex - Use-after-free: in same-line branch, pd_text_delete_line(end_y) was followed by pd_text_line_set_length / pd_text_update_line_size on the freed line. Now returns immediately after delete_line in that path. - Off-by-one: cross-line merge used j = end_x + 1, dropping one char when end_x is mid-line. Now j = end_x, and the line-tail special case resets end_x to 0 explicitly. - OOB read: prev_line = text->lines[char_y - 1] without bounds check. Now guarded with char_y > 0 ? ... : NULL. - Memory leak: chars in the deleted range were never freed and ownership transfer between lines could double-free on delete_line. pd_text_line_set_length - realloc-grown slots were not zeroed, leaving uninitialized pointer values that could be misread as live pd_char_t *. pd_text_dump - col was not reset when advancing to the next line, so output was truncated at the first line's length. - Did not emit the line-ending characters recorded in line->eol, so multi-line text was concatenated without separators. Helpers - Extract pd_text_line_erase / pd_text_line_move to centralize char ownership transfer; reused in pd_text_merge_line. Tests - Add lib/pandagl/tests/test_text_edit.c with 11 cases covering the original crash scenarios (backspace at last empty line, delete at line end), boundary cases, and dump behavior. Closes #270 --- lib/pandagl/src/text/text.c | 114 +++++++++++--- lib/pandagl/tests/main.c | 2 + lib/pandagl/tests/test_text_edit.c | 233 +++++++++++++++++++++++++++++ lib/pandagl/xmake.lua | 2 +- 4 files changed, 327 insertions(+), 24 deletions(-) create mode 100644 lib/pandagl/tests/test_text_edit.c diff --git a/lib/pandagl/src/text/text.c b/lib/pandagl/src/text/text.c index a51949e29..6d90b6c67 100644 --- a/lib/pandagl/src/text/text.c +++ b/lib/pandagl/src/text/text.c @@ -126,6 +126,8 @@ static void pd_text_update_line_size(pd_text_t *text, pd_text_line_t *line) static int pd_text_line_set_length(pd_text_line_t *line, int len) { + int i; + int old_len = line->length; pd_char_t **txtstr; if (len < 0) { @@ -135,12 +137,52 @@ static int pd_text_line_set_length(pd_text_line_t *line, int len) if (!txtstr) { return -1; } + /* 清零新增槽位,防止遗留指针被误用或重复释放 */ + for (i = old_len; i < len; ++i) { + txtstr[i] = NULL; + } txtstr[len] = NULL; line->string = txtstr; line->length = len; return 0; } +/* 释放并清空指定区间 [start, end) 内的字符槽位 */ +static void pd_text_line_erase(pd_text_line_t *line, int start, int end) +{ + int i; + + if (start < 0) { + start = 0; + } + if (end > line->length) { + end = line->length; + } + for (i = start; i < end; ++i) { + if (line->string[i]) { + free(line->string[i]); + line->string[i] = NULL; + } + } +} + +/* 将 src 行 [src_start, src_end) 的字符所有权转移到 dst 行的 dst_start 起始位置。 + * 转移后 src 对应槽位被置 NULL,防止 delete_line 时被重复释放。 + * 调用者负责保证 dst 已有足够容量。 */ +static void pd_text_line_move(pd_text_line_t *dst, int dst_start, + pd_text_line_t *src, int src_start, int src_end) +{ + int i, j; + + if (src_end > src->length) { + src_end = src->length; + } + for (i = dst_start, j = src_start; j < src_end; ++i, ++j) { + dst->string[i] = src->string[j]; + src->string[j] = NULL; + } +} + static int pd_text_line_insert(pd_text_line_t *line, int offset, pd_char_t *txtchar) { @@ -538,7 +580,7 @@ static void pd_text_break_line(pd_text_t *text, int line_num, int col, static void pd_text_merge_line(pd_text_t *text, int line_num) { - int i, j; + int old_len; pd_text_line_t *line = pd_text_get_line(text, line_num); pd_text_line_t *next = pd_text_get_line(text, line_num + 1); @@ -551,12 +593,9 @@ static void pd_text_merge_line(pd_text_t *text, int line_num) text->insert_x += line->length; } } - i = line->length; + old_len = line->length; pd_text_line_set_length(line, line->length + next->length); - for (j = 0; j < next->length; ++i, ++j) { - line->string[i] = next->string[j]; - next->string[j] = NULL; - } + pd_text_line_move(line, old_len, next, 0, next->length); line->eol = next->eol; pd_text_update_line_size(text, line); pd_text_delete_line(text, line_num + 1); @@ -805,6 +844,30 @@ size_t pd_text_dump(pd_text_t *text, size_t start_pos, size_t max_len, for (; col < line->length && i < max_len; ++col, ++i) { wstr_buff[i] = line->string[col]->code; } + /* 进入下一行前,按行尾符还原对应的换行字符 */ + if (i >= max_len) { + break; + } + switch (line->eol) { + case PD_TEXT_EOL_CR: + wstr_buff[i++] = L'\r'; + break; + case PD_TEXT_EOL_LF: + wstr_buff[i++] = L'\n'; + break; + case PD_TEXT_EOL_CR_LF: + wstr_buff[i++] = L'\r'; + if (i >= max_len) { + break; + } + wstr_buff[i++] = L'\n'; + break; + case PD_TEXT_EOL_NONE: + default: + break; + } + /* 切换到下一行时必须重置列号 */ + col = 0; } wstr_buff[i] = 0; return i; @@ -934,8 +997,8 @@ static int pd_text_delete_ex(pd_text_t *text, int char_y, int char_x, if (end_x == char_x && end_y == char_y) { return 0; } - /* 获取上一行文本 */ - prev_line = text->lines[char_y - 1]; + /* 获取上一行文本(首行时无上一行) */ + prev_line = char_y > 0 ? text->lines[char_y - 1] : NULL; // 计算起始行与结束行拼接后的长度 // 起始行:0 1 2 3 4 5,起点位置:2 // 结束行:0 1 2 3 4 5,终点位置:4 @@ -951,13 +1014,16 @@ static int pd_text_delete_ex(pd_text_t *text, int char_y, int char_x, } pd_text_mark_line_dirty(text, char_y, char_x, -1); pd_text_set_typeset_task(text, char_y); - for (i = char_x, j = end_x; j < line->length; ++i, ++j) { - line->string[i] = line->string[j]; - } - /* 如果当前行为空,也不是第一行,并且上一行没有结束符 */ - if (len <= 0 && end_y > 0 && + /* 释放被删除范围内的字符 */ + pd_text_line_erase(line, char_x, end_x); + /* 将结束点之后的内容向前搬移 */ + pd_text_line_move(line, char_x, line, end_x, line->length); + /* 如果当前行为空,也不是第一行,并且上一行没有结束符, + * 则直接移除当前行,不能再访问 line */ + if (len <= 0 && char_y > 0 && prev_line && prev_line->eol != PD_TEXT_EOL_NONE) { - pd_text_delete_line(text, end_y); + pd_text_delete_line(text, char_y); + return 0; } /* 调整起始行的容量 */ pd_text_line_set_length(line, len); @@ -965,11 +1031,16 @@ static int pd_text_delete_ex(pd_text_t *text, int char_y, int char_x, pd_text_update_line_size(text, line); return 0; } - /* 如果结束点在行尾,并且该行不是最后一行 */ + /* 释放起始行中被删除的字符(区间为 [char_x, line->length)) */ + pd_text_line_erase(line, char_x, line->length); + /* 释放结束行中被删除的字符(区间为 [0, end_x)) */ + pd_text_line_erase(end_line, 0, end_x); + /* 如果结束点在行尾,并且该行不是最后一行, + * 则将结束点推进到下一行的行首 */ if (end_x == end_line->length && end_y < text->lines_length - 1) { ++end_y; end_line = pd_text_get_line(text, end_y); - end_x = -1; + end_x = 0; len = char_x + end_line->length; } pd_text_line_set_length(line, len); @@ -980,20 +1051,17 @@ static int pd_text_delete_ex(pd_text_t *text, int char_y, int char_x, pd_text_mark_line_dirty(text, i, 0, -1); pd_text_delete_line(text, i); } - i = char_x; - j = end_x + 1; end_y = char_y + 1; - /* 将结束行的内容拼接至起始行 */ - for (; i < len && j < end_line->length; ++i, ++j) { - line->string[i] = end_line->string[j]; - } + /* 将结束行的内容拼接至起始行(所有权随之转移) */ + pd_text_line_move(line, char_x, end_line, end_x, end_line->length); pd_text_update_line_size(text, line); pd_text_mark_line_dirty(text, end_y, 0, -1); /* 移除结束行 */ pd_text_delete_line(text, end_y); /* 如果起始行无内容,并且上一行没有结束符(换行符),则 * 说明需要删除起始行 */ - if (len <= 0 && char_y > 0 && prev_line->eol != PD_TEXT_EOL_NONE) { + if (len <= 0 && char_y > 0 && prev_line && + prev_line->eol != PD_TEXT_EOL_NONE) { pd_text_mark_line_dirty(text, char_y, 0, -1); pd_text_delete_line(text, char_y); } diff --git a/lib/pandagl/tests/main.c b/lib/pandagl/tests/main.c index ef77f1898..4c55a7417 100644 --- a/lib/pandagl/tests/main.c +++ b/lib/pandagl/tests/main.c @@ -14,11 +14,13 @@ extern void test_pandagl_canvas_mix(void); extern void test_pandagl_image_reader(void); extern void test_pandagl_font_load(void); +extern void test_pandagl_text_edit(void); static const ctest_suite_t suites[] = { { "pandagl/canvas mix", test_pandagl_canvas_mix }, { "pandagl/image reader", test_pandagl_image_reader }, { "pandagl/font load", test_pandagl_font_load }, + { "pandagl/text edit", test_pandagl_text_edit }, { NULL, NULL } }; diff --git a/lib/pandagl/tests/test_text_edit.c b/lib/pandagl/tests/test_text_edit.c new file mode 100644 index 000000000..069214ce7 --- /dev/null +++ b/lib/pandagl/tests/test_text_edit.c @@ -0,0 +1,233 @@ +/* + * lib/pandagl/tests/test_text_edit.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +/* + * 这些用例覆盖 pd_text_delete_ex 的关键分支,包括同行删除、跨行合并、 + * 以及边界场景。由于 pd_text_dump 在多行场景下存在已知问题(不在本次 + * 修复范围),这里通过断言每行长度来验证缓冲区状态。 + */ + +static void should_backspace_last_char_on_last_line(void) +{ + pd_text_t *text = pd_text_create(); + + pd_text_set_multiline(text, true); + pd_text_write(text, L"123\n123\n123\n", NULL); + /* 光标置于末尾的空行,按退格删除前一行的换行符, + * 此时空行被丢弃 */ + pd_text_set_insert_position(text, 3, 0); + ctest_equal_int("should not crash on backspace last char", + pd_text_backspace(text, 1), 0); + ctest_equal_int("should drop the trailing empty line", + pd_text_get_lines_length(text), 3); + ctest_equal_int("line 0 keeps 3 chars", + pd_text_get_line_length(text, 0), 3); + ctest_equal_int("line 1 keeps 3 chars", + pd_text_get_line_length(text, 1), 3); + ctest_equal_int("line 2 keeps 3 chars", + pd_text_get_line_length(text, 2), 3); + pd_text_destroy(text); +} + +static void should_backspace_then_continue_typing(void) +{ + pd_text_t *text = pd_text_create(); + + pd_text_set_multiline(text, true); + pd_text_write(text, L"abc\ndef\n", NULL); + pd_text_set_insert_position(text, 2, 0); + pd_text_backspace(text, 1); + pd_text_insert(text, L"X", NULL); + ctest_equal_int("should merge into two lines after backspace + insert", + pd_text_get_lines_length(text), 2); + ctest_equal_int("line 0 keeps 'abc'", + pd_text_get_line_length(text, 0), 3); + ctest_equal_int("line 1 becomes 'defX'", + pd_text_get_line_length(text, 1), 4); + pd_text_destroy(text); +} + +static void should_not_crash_on_backspace_at_start(void) +{ + pd_text_t *text = pd_text_create(); + + pd_text_set_multiline(text, true); + pd_text_write(text, L"abc", NULL); + pd_text_set_insert_position(text, 0, 0); + ctest_equal_int("should return error at buffer start", + pd_text_backspace(text, 1), -1); + ctest_equal_int("should keep one line", pd_text_get_lines_length(text), + 1); + ctest_equal_int("line content unchanged", + pd_text_get_line_length(text, 0), 3); + pd_text_destroy(text); +} + +static void should_delete_char_at_caret(void) +{ + pd_text_t *text = pd_text_create(); + wchar_t buf[16]; + + pd_text_set_multiline(text, true); + pd_text_write(text, L"abcdef", NULL); + pd_text_set_insert_position(text, 0, 2); + ctest_equal_int("should delete one char", pd_text_delete(text, 1), 0); + pd_text_dump(text, 0, 16, buf); + ctest_equal_wcs("should produce expected text", buf, L"abdef"); + ctest_equal_int("line length is 5", + pd_text_get_line_length(text, 0), 5); + pd_text_destroy(text); +} + +static void should_join_next_line_when_delete_at_line_end(void) +{ + pd_text_t *text = pd_text_create(); + + pd_text_set_multiline(text, true); + pd_text_write(text, L"abc\ndef\nghi", NULL); + /* 在第二行最后一个字符处使用 delete,触发跨行拼接, + * 之前 +1 偏移 bug 会导致 'd' 字符丢失 */ + pd_text_set_insert_position(text, 1, 3); + ctest_equal_int("should not crash when delete at line end", + pd_text_delete(text, 1), 0); + ctest_equal_int("should reduce one line after merge", + pd_text_get_lines_length(text), 2); + ctest_equal_int("line 0 keeps 'abc'", + pd_text_get_line_length(text, 0), 3); + ctest_equal_int("line 1 becomes 'defghi' (6 chars)", + pd_text_get_line_length(text, 1), 6); + pd_text_destroy(text); +} + +static void should_preserve_chars_when_joining_lines(void) +{ + pd_text_t *text = pd_text_create(); + + pd_text_set_multiline(text, true); + pd_text_write(text, L"abc\ndef\n", NULL); + /* 在第一行末尾处用 delete 删除换行符 */ + pd_text_set_insert_position(text, 0, 3); + pd_text_delete(text, 1); + ctest_equal_int("should reduce to two lines", + pd_text_get_lines_length(text), 2); + ctest_equal_int("line 0 becomes 'abcdef' (6 chars)", + pd_text_get_line_length(text, 0), 6); + ctest_equal_int("line 1 stays empty", + pd_text_get_line_length(text, 1), 0); + pd_text_destroy(text); +} + +static void should_handle_multi_line_backspace_sequence(void) +{ + pd_text_t *text = pd_text_create(); + + pd_text_set_multiline(text, true); + pd_text_write(text, L"123\n123\n123\n", NULL); + pd_text_set_insert_position(text, 3, 0); + /* 连续 backspace,模拟用户按住退格。每次删一格: + * 1) 删第 4 行(空行) -> 3 行 + * 2) 删第 3 行的 '3' -> 2.x(剩 '12') + * 3) 删 '2' + * 4) 删 '1' -> 第 3 行空且无 eol,进入下次 backspace 跨行 */ + pd_text_backspace(text, 1); + pd_text_backspace(text, 1); + pd_text_backspace(text, 1); + pd_text_backspace(text, 1); + ctest_equal_int("should remain 2 full lines", + pd_text_get_lines_length(text), 2); + ctest_equal_int("line 0 keeps 3 chars", + pd_text_get_line_length(text, 0), 3); + ctest_equal_int("line 1 keeps 3 chars", + pd_text_get_line_length(text, 1), 3); + pd_text_destroy(text); +} + +static void should_dump_single_line(void) +{ + pd_text_t *text = pd_text_create(); + wchar_t buf[32]; + + pd_text_write(text, L"hello", NULL); + ctest_equal_uint("should return char count", + (unsigned)pd_text_dump(text, 0, 32, buf), 5u); + ctest_equal_wcs("should produce same single-line text", buf, L"hello"); + pd_text_destroy(text); +} + +static void should_dump_multiline_with_lf(void) +{ + pd_text_t *text = pd_text_create(); + wchar_t buf[32]; + + pd_text_set_multiline(text, true); + pd_text_write(text, L"abc\ndef\nghi", NULL); + pd_text_dump(text, 0, 32, buf); + ctest_equal_wcs("should preserve LF line endings", buf, + L"abc\ndef\nghi"); + pd_text_destroy(text); +} + +static void should_dump_multiline_with_trailing_newline(void) +{ + pd_text_t *text = pd_text_create(); + wchar_t buf[32]; + + pd_text_set_multiline(text, true); + pd_text_write(text, L"a\nb\n", NULL); + pd_text_dump(text, 0, 32, buf); + ctest_equal_wcs("should preserve trailing newline", buf, L"a\nb\n"); + pd_text_destroy(text); +} + +static void should_dump_respect_max_len(void) +{ + pd_text_t *text = pd_text_create(); + wchar_t buf[8]; + + pd_text_set_multiline(text, true); + pd_text_write(text, L"abc\ndef\nghi", NULL); + /* 只允许写 4 个 wchar,第 5 位是终止符 */ + ctest_equal_uint("should stop at max_len", + (unsigned)pd_text_dump(text, 0, 4, buf), 4u); + ctest_equal_wcs("should truncate without crossing buffer", buf, + L"abc\n"); + pd_text_destroy(text); +} + +void test_pandagl_text_edit(void) +{ + pd_font_library_init(); + ctest_describe("text backspace", + should_backspace_last_char_on_last_line); + ctest_describe("text backspace + insert", + should_backspace_then_continue_typing); + ctest_describe("text backspace at buffer start", + should_not_crash_on_backspace_at_start); + ctest_describe("text delete at caret", should_delete_char_at_caret); + ctest_describe("text delete at line end", + should_join_next_line_when_delete_at_line_end); + ctest_describe("text delete preserves chars", + should_preserve_chars_when_joining_lines); + ctest_describe("text backspace sequence", + should_handle_multi_line_backspace_sequence); + ctest_describe("text dump single line", should_dump_single_line); + ctest_describe("text dump multiline lf", + should_dump_multiline_with_lf); + ctest_describe("text dump trailing newline", + should_dump_multiline_with_trailing_newline); + ctest_describe("text dump max len", should_dump_respect_max_len); + pd_font_library_destroy(); +} diff --git a/lib/pandagl/xmake.lua b/lib/pandagl/xmake.lua index 3149a3fe2..829ceb668 100644 --- a/lib/pandagl/xmake.lua +++ b/lib/pandagl/xmake.lua @@ -64,7 +64,7 @@ target("pandagl-tests") set_kind("binary") set_group("tests") set_rundir("tests/fixtures") - add_files("tests/main.c", "tests/test_canvas_mix.c", "tests/test_image_reader.c", "tests/test_font_load.c") + add_files("tests/main.c", "tests/test_canvas_mix.c", "tests/test_image_reader.c", "tests/test_font_load.c", "tests/test_text_edit.c") add_deps("ctest", "pandagl") add_rules("tests.runnable") add_tests("default", {group = "tests"}) From 61f0aba32f8f739f48d268dcbe5e111140919114 Mon Sep 17 00:00:00 2001 From: Liu Date: Sun, 24 May 2026 22:41:28 +0800 Subject: [PATCH 15/66] refactor(pandagl): rename font API to align with typeface/glyph concepts The previous naming conflated multiple levels of the font model: pd_font_t actually owned a single typeface resource (FT_Face), while pd_font_bitmap_t represented a per-glyph bitmap. The pd_font_library_* prefix was redundant under the pd_font_ namespace and resulted in verbose call sites (up to 34 chars). Type renames - pd_font_t -> pd_font_face_t - pd_font_bitmap_t -> pd_glyph_bitmap_t - font_engine_t -> pd_font_engine_t - struct tags updated to match the typedef names. API renames (grouped by sub-object) - Face lifecycle: pd_font_create/destroy -> pd_font_face_create/destroy - Face registry: pd_font_library_add_font -> pd_font_register pd_font_library_get_font -> pd_font_get pd_font_library_get_font_id -> pd_font_get_id pd_font_library_query -> pd_font_query pd_font_library_load_file -> pd_font_load_file pd_font_library_get_font_path-> pd_font_find_path pd_font_library_get_default_font -> pd_font_get_default pd_font_library_set_default_font -> pd_font_set_default pd_font_library_set_font_family_alias -> pd_font_family_set_alias pd_font_library_update_font_weight -> pd_font_replace_weight pd_font_library_update_font_style -> pd_font_replace_style - Parsing helpers: pd_font_library_detect_weight -> pd_font_parse_weight pd_font_library_detect_style -> pd_font_parse_style - Glyph rendering: pd_font_library_render_bitmap -> pd_font_render_glyph pd_canvas_mix_font_bitmap -> pd_canvas_mix_glyph_bitmap pd_font_bitmap_init/destroy -> pd_glyph_bitmap_init/destroy - Glyph cache: pd_font_library_add_bitmap -> pd_font_cache_add_bitmap pd_font_library_get_bitmap -> pd_font_cache_get_bitmap pd_font_library_init/destroy are kept as the module lifecycle entry points, matching the FT_Init_FreeType / FT_Done_FreeType convention. All call sites in lib/pandagl, lib/ui, lib/ui-xml, src/, tests/ and examples/ are updated accordingly. --- lib/pandagl/examples/char-render/src/main.c | 12 +- lib/pandagl/include/pandagl/font.h | 58 ++++----- lib/pandagl/include/pandagl/text.h | 2 +- lib/pandagl/src/font/bitmap.c | 22 ++-- lib/pandagl/src/font/bitmap.h | 4 +- lib/pandagl/src/font/freetype.c | 18 +-- lib/pandagl/src/font/freetype.h | 2 +- lib/pandagl/src/font/inconsolata.c | 4 +- lib/pandagl/src/font/inconsolata.h | 2 +- lib/pandagl/src/font/incore.c | 14 +-- lib/pandagl/src/font/incore.h | 2 +- lib/pandagl/src/font/library.c | 124 ++++++++++---------- lib/pandagl/src/font/library.h | 4 +- lib/pandagl/src/text/style.c | 12 +- lib/pandagl/src/text/text.c | 8 +- lib/pandagl/tests/test_font_load.c | 58 ++++----- lib/ui-xml/src/ui_xml.c | 2 +- lib/ui/src/ui_css.c | 2 +- lib/ui/src/ui_text_style.c | 2 +- src/lcui_fonts.c | 24 ++-- tests/integration/test_font_face.c | 2 +- 21 files changed, 189 insertions(+), 189 deletions(-) diff --git a/lib/pandagl/examples/char-render/src/main.c b/lib/pandagl/examples/char-render/src/main.c index 79c3c75d6..2ecc66528 100644 --- a/lib/pandagl/examples/char-render/src/main.c +++ b/lib/pandagl/examples/char-render/src/main.c @@ -15,7 +15,7 @@ int main(void) { int ret, fid; pd_canvas_t img; - pd_font_bitmap_t bmp; + pd_glyph_bitmap_t bmp; pd_pos_t pos = { 25, 25 }; pd_color_t bg = pd_rgb(240, 240, 240); pd_color_t color = pd_rgb(255, 0, 0); @@ -26,19 +26,19 @@ int main(void) pd_canvas_create(&img, 100, 100); pd_canvas_fill(&img, bg); - ret = pd_font_library_load_file("C:/Windows/fonts/simsun.ttc"); + ret = pd_font_load_file("C:/Windows/fonts/simsun.ttc"); while (ret == 0) { - fid = pd_font_library_get_font_id("SimSun", 0, 0); + fid = pd_font_get_id("SimSun", 0, 0); if (fid < 0) { break; } - ret = pd_font_library_render_bitmap(&bmp, L'字', fid, 48); + ret = pd_font_render_glyph(&bmp, L'字', fid, 48); if (ret != 0) { break; } - pd_canvas_mix_font_bitmap(&img, pos, &bmp, color); + pd_canvas_mix_glyph_bitmap(&img, pos, &bmp, color); pd_write_png_file("test_char_render.png", &img); - pd_font_bitmap_destroy(&bmp); + pd_glyph_bitmap_destroy(&bmp); pd_canvas_destroy(&img); break; } diff --git a/lib/pandagl/include/pandagl/font.h b/lib/pandagl/include/pandagl/font.h index b75af6904..07293f860 100644 --- a/lib/pandagl/include/pandagl/font.h +++ b/lib/pandagl/include/pandagl/font.h @@ -35,7 +35,7 @@ typedef enum pd_font_weight_t { PD_FONT_WEIGHT_TOTAL_NUM } pd_font_weight_t; -typedef struct pd_font_bitmap { +typedef struct pd_glyph_bitmap { int top; /**< 与顶边框的距离 */ int left; /**< 与左边框的距离 */ int width; /**< 位图宽度 */ @@ -47,54 +47,54 @@ typedef struct pd_font_bitmap { int bbox_width, bbox_height; int ascender; } metrics; -} pd_font_bitmap_t; +} pd_glyph_bitmap_t; -typedef struct font_engine font_engine_t; +typedef struct pd_font_engine pd_font_engine_t; -typedef struct pd_font { +typedef struct pd_font_face { int id; /**< 字体信息ID */ char *style_name; /**< 样式名称 */ char *family_name; /**< 字族名称 */ void *data; /**< 相关数据 */ pd_font_style_t style; /**< 风格 */ pd_font_weight_t weight; /**< 粗细程度 */ - font_engine_t *engine; /**< 所属的字体引擎 */ -} pd_font_t; + pd_font_engine_t *engine; /**< 所属的字体引擎 */ +} pd_font_face_t; -struct font_engine { +struct pd_font_engine { char name[64]; - int (*open)(const char *, pd_font_t ***); - int (*render)(pd_font_bitmap_t *, unsigned, int, pd_font_t *); + int (*open)(const char *, pd_font_face_t ***); + int (*render)(pd_glyph_bitmap_t *, unsigned, int, pd_font_face_t *); void (*close)(void *); }; PD_BEGIN_DECLS /** 将字体位图绘制到目标图像上 */ -PD_PUBLIC int pd_canvas_mix_font_bitmap(pd_canvas_t *graph, pd_pos_t pos, - const pd_font_bitmap_t *bmp, +PD_PUBLIC int pd_canvas_mix_glyph_bitmap(pd_canvas_t *graph, pd_pos_t pos, + const pd_glyph_bitmap_t *bmp, pd_color_t color); -PD_PUBLIC char *pd_font_library_get_font_path(const char *name); +PD_PUBLIC char *pd_font_find_path(const char *name); /** * 根据字符串内容猜测字体粗细程度 * 文档:https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight */ -PD_PUBLIC pd_font_weight_t pd_font_library_detect_weight(const char *str); +PD_PUBLIC pd_font_weight_t pd_font_parse_weight(const char *str); /** * 根据字符串内容猜测字体风格 * 文档:https://developer.mozilla.org/en-US/docs/Web/CSS/font-style */ -PD_PUBLIC pd_font_style_t pd_font_library_detect_style(const char *str); +PD_PUBLIC pd_font_style_t pd_font_parse_style(const char *str); /** 载入字体位图 */ -PD_PUBLIC int pd_font_library_render_bitmap(pd_font_bitmap_t *buff, unsigned ch, +PD_PUBLIC int pd_font_render_glyph(pd_glyph_bitmap_t *buff, unsigned ch, int font_id, int pixel_size); /** 添加字体族,并返回该字族的ID */ -PD_PUBLIC int pd_font_library_add_font(pd_font_t *font); +PD_PUBLIC int pd_font_register(pd_font_face_t *font); /** * 获取字体的ID @@ -102,7 +102,7 @@ PD_PUBLIC int pd_font_library_add_font(pd_font_t *font); * @param[in] style 字体风格 * @param[in] weight 字体粗细程度,若为值 0,则默认为 PD_FONT_WEIGHT_NORMAL */ -PD_PUBLIC int pd_font_library_get_font_id(const char *family_name, +PD_PUBLIC int pd_font_get_id(const char *family_name, pd_font_style_t style, pd_font_weight_t weight); @@ -112,7 +112,7 @@ PD_PUBLIC int pd_font_library_get_font_id(const char *family_name, * @params[in] weight 字体粗细程度 * @params[out] new_font_ids 更新字体粗细程度后的字体 id 列表 */ -PD_PUBLIC size_t pd_font_library_update_font_weight(const int *font_ids, +PD_PUBLIC size_t pd_font_replace_weight(const int *font_ids, pd_font_weight_t weight, int **new_font_ids); @@ -122,7 +122,7 @@ PD_PUBLIC size_t pd_font_library_update_font_weight(const int *font_ids, * @params[in] style 字体风格 * @params[out] new_font_ids 更新字体粗细程度后的字体 id 列表 */ -PD_PUBLIC size_t pd_font_library_update_font_style(const int *font_ids, +PD_PUBLIC size_t pd_font_replace_style(const int *font_ids, pd_font_style_t style, int **new_font_ids); @@ -134,21 +134,21 @@ PD_PUBLIC size_t pd_font_library_update_font_style(const int *font_ids, * @param[in] names 字族名称,多个名字用逗号隔开 * @return 获取到的字体 ID 的数量 */ -PD_PUBLIC unsigned pd_font_library_query(int **font_ids, pd_font_style_t style, +PD_PUBLIC unsigned pd_font_query(int **font_ids, pd_font_style_t style, pd_font_weight_t weight, const char *const *names); /** 获取指定字体ID的字体信息 */ -PD_PUBLIC pd_font_t *pd_font_library_get_font(int id); +PD_PUBLIC pd_font_face_t *pd_font_get(int id); /** 获取默认的字体ID */ -PD_PUBLIC int pd_font_library_get_default_font(void); +PD_PUBLIC int pd_font_get_default(void); /** 设置默认的字体 */ -PD_PUBLIC void pd_font_library_set_default_font(int id); +PD_PUBLIC void pd_font_set_default(int id); /** 设置字体族的别名 */ -PD_PUBLIC bool pd_font_library_set_font_family_alias(const char *alias, +PD_PUBLIC bool pd_font_family_set_alias(const char *alias, const char *family_name); /** @@ -160,8 +160,8 @@ PD_PUBLIC bool pd_font_library_set_font_family_alias(const char *alias, * @warning 此函数仅仅是将 bmp 复制进缓存中,并未重新分配新的空间储存位图数 * 据,因此,请勿在调用此函数后手动释放 bmp。 */ -PD_PUBLIC pd_font_bitmap_t *pd_font_library_add_bitmap( - wchar_t ch, int font_id, int size, const pd_font_bitmap_t *bmp); +PD_PUBLIC pd_glyph_bitmap_t *pd_font_cache_add_bitmap( + wchar_t ch, int font_id, int size, const pd_glyph_bitmap_t *bmp); /** * 从缓存中获取字体位图 @@ -172,11 +172,11 @@ PD_PUBLIC pd_font_bitmap_t *pd_font_library_add_bitmap( * @warning 请勿释放 bmp,bmp 仅仅是引用缓存中的字体位图,并未建分配新 * 空间存储字体位图的拷贝。 */ -PD_PUBLIC int pd_font_library_get_bitmap(unsigned ch, int font_id, int size, - const pd_font_bitmap_t **bmp); +PD_PUBLIC int pd_font_cache_get_bitmap(unsigned ch, int font_id, int size, + const pd_glyph_bitmap_t **bmp); /** 载入字体至数据库中 */ -PD_PUBLIC int pd_font_library_load_file(const char *filepath); +PD_PUBLIC int pd_font_load_file(const char *filepath); /** 初始化字体处理模块 */ PD_PUBLIC void pd_font_library_init(void); diff --git a/lib/pandagl/include/pandagl/text.h b/lib/pandagl/include/pandagl/text.h index cc1794431..ff6b57589 100644 --- a/lib/pandagl/include/pandagl/text.h +++ b/lib/pandagl/include/pandagl/text.h @@ -46,7 +46,7 @@ typedef enum pd_text_align_t { typedef struct pd_char { wchar_t code; /**< 字符码 */ pd_text_style_t *style; /**< 该字符使用的样式数据 */ - const pd_font_bitmap_t *bitmap; /**< 字体位图数据(只读) */ + const pd_glyph_bitmap_t *bitmap; /**< 字体位图数据(只读) */ } pd_char_t; /** end of line character */ diff --git a/lib/pandagl/src/font/bitmap.c b/lib/pandagl/src/font/bitmap.c index 30ce76c1c..612c08a97 100644 --- a/lib/pandagl/src/font/bitmap.c +++ b/lib/pandagl/src/font/bitmap.c @@ -14,7 +14,7 @@ #include #include "bitmap.h" -void pd_font_bitmap_init(pd_font_bitmap_t *bitmap) +void pd_glyph_bitmap_init(pd_glyph_bitmap_t *bitmap) { bitmap->rows = 0; bitmap->width = 0; @@ -23,17 +23,17 @@ void pd_font_bitmap_init(pd_font_bitmap_t *bitmap) bitmap->buffer = NULL; } -void pd_font_bitmap_destroy(pd_font_bitmap_t *bitmap) +void pd_glyph_bitmap_destroy(pd_glyph_bitmap_t *bitmap) { if (bitmap->buffer) { free(bitmap->buffer); } - pd_font_bitmap_init(bitmap); + pd_glyph_bitmap_init(bitmap); } -static void pd_canvas_mix_font_bitmap_argb(pd_canvas_t *graph, +static void pd_canvas_mix_glyph_bitmap_argb(pd_canvas_t *graph, pd_rect_t *write_rect, - const pd_font_bitmap_t *bmp, + const pd_glyph_bitmap_t *bmp, pd_color_t color, pd_rect_t *read_rect) { @@ -59,9 +59,9 @@ static void pd_canvas_mix_font_bitmap_argb(pd_canvas_t *graph, } } -static void pd_canvas_mix_font_bitmap_rgb(pd_canvas_t *graph, +static void pd_canvas_mix_glyph_bitmap_rgb(pd_canvas_t *graph, pd_rect_t *write_rect, - const pd_font_bitmap_t *bmp, + const pd_glyph_bitmap_t *bmp, pd_color_t color, pd_rect_t *read_rect) { @@ -88,8 +88,8 @@ static void pd_canvas_mix_font_bitmap_rgb(pd_canvas_t *graph, } } -int pd_canvas_mix_font_bitmap(pd_canvas_t *graph, pd_pos_t pos, - const pd_font_bitmap_t *bmp, pd_color_t color) +int pd_canvas_mix_glyph_bitmap(pd_canvas_t *graph, pd_pos_t pos, + const pd_glyph_bitmap_t *bmp, pd_color_t color) { pd_canvas_t write_slot; pd_rect_t r_rect, w_rect; @@ -113,10 +113,10 @@ int pd_canvas_mix_font_bitmap(pd_canvas_t *graph, pd_pos_t pos, /* 获取背景图引用的源图形 */ graph = pd_canvas_get_quote_source(graph); if (graph->color_type == PD_COLOR_TYPE_ARGB) { - pd_canvas_mix_font_bitmap_argb(graph, &w_rect, bmp, color, + pd_canvas_mix_glyph_bitmap_argb(graph, &w_rect, bmp, color, &r_rect); } else { - pd_canvas_mix_font_bitmap_rgb(graph, &w_rect, bmp, color, + pd_canvas_mix_glyph_bitmap_rgb(graph, &w_rect, bmp, color, &r_rect); } return 0; diff --git a/lib/pandagl/src/font/bitmap.h b/lib/pandagl/src/font/bitmap.h index 6567b8ea0..45a8e2b77 100644 --- a/lib/pandagl/src/font/bitmap.h +++ b/lib/pandagl/src/font/bitmap.h @@ -10,7 +10,7 @@ */ /** 初始化字体位图 */ -void pd_font_bitmap_init(pd_font_bitmap_t *bitmap); +void pd_glyph_bitmap_init(pd_glyph_bitmap_t *bitmap); /** 释放字体位图占用的资源 */ -void pd_font_bitmap_destroy(pd_font_bitmap_t *bitmap); +void pd_glyph_bitmap_destroy(pd_glyph_bitmap_t *bitmap); diff --git a/lib/pandagl/src/font/freetype.c b/lib/pandagl/src/font/freetype.c index 766a929ba..c7a8524af 100644 --- a/lib/pandagl/src/font/freetype.c +++ b/lib/pandagl/src/font/freetype.c @@ -29,10 +29,10 @@ static struct { FT_Library library; } freetype; -static int pd_freetype_open(const char *filepath, pd_font_t ***outfonts) +static int pd_freetype_open(const char *filepath, pd_font_face_t ***outfonts) { FT_Face face; - pd_font_t *font, **fonts; + pd_font_face_t *font, **fonts; int i, err, num_faces; err = FT_New_Face(freetype.library, filepath, -1, &face); @@ -45,7 +45,7 @@ static int pd_freetype_open(const char *filepath, pd_font_t ***outfonts) if (num_faces < 1) { return 0; } - fonts = malloc(sizeof(pd_font_t *) * num_faces); + fonts = malloc(sizeof(pd_font_face_t *) * num_faces); if (!fonts) { return -ENOMEM; } @@ -56,7 +56,7 @@ static int pd_freetype_open(const char *filepath, pd_font_t ***outfonts) continue; } FT_Select_Charmap(face, FT_ENCODING_UNICODE); - font = pd_font_create(face->family_name, face->style_name); + font = pd_font_face_create(face->family_name, face->style_name); font->data = face; fonts[i] = font; } @@ -69,8 +69,8 @@ static void pd_freetype_close(void *face) FT_Done_Face(face); } -/** 转换 FT_GlyphSlot 类型数据为 pd_font_bitmap_t */ -static size_t convert_glyph(pd_font_bitmap_t *bmp, FT_GlyphSlot slot, int mode) +/** 转换 FT_GlyphSlot 类型数据为 pd_glyph_bitmap_t */ +static size_t convert_glyph(pd_glyph_bitmap_t *bmp, FT_GlyphSlot slot, int mode) { int error; size_t size; @@ -159,8 +159,8 @@ static size_t convert_glyph(pd_font_bitmap_t *bmp, FT_GlyphSlot slot, int mode) return size; } -static int pd_freetype_render(pd_font_bitmap_t *bmp, unsigned ch, - int pixel_size, pd_font_t *font) +static int pd_freetype_render(pd_glyph_bitmap_t *bmp, unsigned ch, + int pixel_size, pd_font_face_t *font) { int ret = 0; FT_UInt index; @@ -180,7 +180,7 @@ static int pd_freetype_render(pd_font_bitmap_t *bmp, unsigned ch, return ret; } -int pd_freetype_engine_init(font_engine_t *engine) +int pd_freetype_engine_init(pd_font_engine_t *engine) { if (FT_Init_FreeType(&freetype.library)) { return -1; diff --git a/lib/pandagl/src/font/freetype.h b/lib/pandagl/src/font/freetype.h index 5dde769c8..5e62de03e 100644 --- a/lib/pandagl/src/font/freetype.h +++ b/lib/pandagl/src/font/freetype.h @@ -9,5 +9,5 @@ * LICENSE.TXT file in the root directory of this source tree. */ -int pd_freetype_engine_init(font_engine_t *engine); +int pd_freetype_engine_init(pd_font_engine_t *engine); int pd_freetype_engine_destroy(void); diff --git a/lib/pandagl/src/font/inconsolata.c b/lib/pandagl/src/font/inconsolata.c index f19c6ba64..e9b3cdf0a 100644 --- a/lib/pandagl/src/font/inconsolata.c +++ b/lib/pandagl/src/font/inconsolata.c @@ -27,7 +27,7 @@ enum font_index { }; /* inconsolata 字体数据索引 */ -static const pd_font_bitmap_t pd_inconsolata_font_bitmap_info[SIZE_TOTAL][95] = { +static const pd_glyph_bitmap_t pd_inconsolata_font_bitmap_info[SIZE_TOTAL][95] = { { { 16, 0, 0, 0, 0, (uint8_t*)0x00000000, { 6, 12 } }, { 11, 1, 3, 9, 9, (uint8_t*)0x00000000, { 6, 12 } }, @@ -7585,7 +7585,7 @@ static const unsigned char *pd_inconsolata_font_bitmap[SIZE_TOTAL] = { pd_inconsolata_font_bitmap_18px_bytes }; -int pd_render_inconsolata_font_bitmap(pd_font_bitmap_t *bmp, unsigned ch, int size) +int pd_render_inconsolata_font_bitmap(pd_glyph_bitmap_t *bmp, unsigned ch, int size) { int i, j, *ptr; const uint8_t *byte_ptr; diff --git a/lib/pandagl/src/font/inconsolata.h b/lib/pandagl/src/font/inconsolata.h index a01d66d64..2cbc79e34 100644 --- a/lib/pandagl/src/font/inconsolata.h +++ b/lib/pandagl/src/font/inconsolata.h @@ -9,4 +9,4 @@ * LICENSE.TXT file in the root directory of this source tree. */ -int pd_render_inconsolata_font_bitmap(pd_font_bitmap_t *bmp, unsigned ch, int size); +int pd_render_inconsolata_font_bitmap(pd_glyph_bitmap_t *bmp, unsigned ch, int size); diff --git a/lib/pandagl/src/font/incore.c b/lib/pandagl/src/font/incore.c index c833a0bd1..5cc51a3e7 100644 --- a/lib/pandagl/src/font/incore.c +++ b/lib/pandagl/src/font/incore.c @@ -20,17 +20,17 @@ enum in_core_font_type { FONT_INCONSOLATA }; -static int pd_incore_font_open(const char *filepath, pd_font_t ***outfonts) +static int pd_incore_font_open(const char *filepath, pd_font_face_t ***outfonts) { int *code; - pd_font_t **fonts, *font; + pd_font_face_t **fonts, *font; if (strcmp(filepath, "in-core.inconsolata") != 0) { return 0; } code = malloc(sizeof(int)); *code = FONT_INCONSOLATA; - font = pd_font_create("inconsolata", "Regular"); - fonts = malloc(sizeof(pd_font_t*)); + font = pd_font_face_create("inconsolata", "Regular"); + fonts = malloc(sizeof(pd_font_face_t*)); font->data = code; fonts[0] = font; *outfonts = fonts; @@ -42,8 +42,8 @@ static void pd_incore_font_close(void *face) free(face); } -static int pd_incore_font_render(pd_font_bitmap_t *bmp, unsigned ch, - int pixel_size, pd_font_t *font) +static int pd_incore_font_render(pd_glyph_bitmap_t *bmp, unsigned ch, + int pixel_size, pd_font_face_t *font) { int *code = (int*)font->data; switch (*code) { @@ -54,7 +54,7 @@ static int pd_incore_font_render(pd_font_bitmap_t *bmp, unsigned ch, return -1; } -int pd_incore_font_create(font_engine_t *engine) +int pd_incore_font_create(pd_font_engine_t *engine) { engine->render = pd_incore_font_render; engine->close = pd_incore_font_close; diff --git a/lib/pandagl/src/font/incore.h b/lib/pandagl/src/font/incore.h index 5069bf409..0f112225c 100644 --- a/lib/pandagl/src/font/incore.h +++ b/lib/pandagl/src/font/incore.h @@ -9,5 +9,5 @@ * LICENSE.TXT file in the root directory of this source tree. */ -int pd_incore_font_create(font_engine_t *engine); +int pd_incore_font_create(pd_font_engine_t *engine); int pd_incore_font_destroy(void); diff --git a/lib/pandagl/src/font/library.c b/lib/pandagl/src/font/library.c index 8090b60b7..88d2f06b7 100644 --- a/lib/pandagl/src/font/library.c +++ b/lib/pandagl/src/font/library.c @@ -33,11 +33,11 @@ typedef struct font_style_node { /* 字体列表,按粗细程度存放 */ - pd_font_t *weights[PD_FONT_WEIGHT_TOTAL_NUM]; + pd_font_face_t *weights[PD_FONT_WEIGHT_TOTAL_NUM]; } font_style_node_t; typedef struct font_cache { - pd_font_t *fonts[FONT_CACHE_SIZE]; + pd_font_face_t *fonts[FONT_CACHE_SIZE]; } font_cache_t; /** 字体字族索引结点 */ @@ -60,14 +60,14 @@ static struct font_library_module { /** dict_t */ dict_t *font_family_aliases; - /** rbtree_t>> */ + /** rbtree_t>> */ rbtree_t bitmap_cache; font_cache_t **font_cache; - pd_font_t *default_font; - pd_font_t *incore_font; - font_engine_t engines[2]; - font_engine_t *engine; + pd_font_face_t *default_font; + pd_font_face_t *incore_font; + pd_font_engine_t engines[2]; + pd_font_engine_t *engine; } fontlib; /* clang-format on */ @@ -82,7 +82,7 @@ PD_INLINE rbtree_t *select_font_cache(rbtree_t *font_cache, int font_id) return rbtree_get_data_by_key(font_cache, font_id); } -PD_INLINE pd_font_bitmap_t *select_bitmap_cache(rbtree_t *bmp_cache, int size) +PD_INLINE pd_glyph_bitmap_t *select_bitmap_cache(rbtree_t *bmp_cache, int size) { return rbtree_get_data_by_key(bmp_cache, size); } @@ -96,7 +96,7 @@ PD_INLINE font_family_node_t *select_font_family_cache(const char *family_name) #include #endif -char *pd_font_library_get_font_path(const char *name) +char *pd_font_find_path(const char *name) { #ifdef PANDAGL_HAS_FONTCONFIG char *path = NULL; @@ -131,22 +131,22 @@ char *pd_font_library_get_font_path(const char *name) #endif } -pd_font_t *pd_font_create(const char *family_name, const char *style_name) +pd_font_face_t *pd_font_face_create(const char *family_name, const char *style_name) { - pd_font_t *font; + pd_font_face_t *font; - font = malloc(sizeof(pd_font_t)); + font = malloc(sizeof(pd_font_face_t)); font->id = 0; font->data = NULL; font->engine = NULL; font->family_name = strdup2(family_name); font->style_name = strdup2(style_name); - font->weight = pd_font_library_detect_weight(style_name); - font->style = pd_font_library_detect_style(style_name); + font->weight = pd_font_parse_weight(style_name); + font->style = pd_font_parse_style(style_name); return font; } -void pd_font_destroy(pd_font_t *font) +void pd_font_face_destroy(pd_font_face_t *font) { free(font->family_name); free(font->style_name); @@ -169,7 +169,7 @@ static void destroy_font_family_node(void *privdata, void *data) static void destroy_font_bitmap(void *arg) { - pd_font_bitmap_destroy(arg); + pd_glyph_bitmap_destroy(arg); free(arg); } @@ -179,10 +179,10 @@ static void destroy_tree_node(void *arg) free(arg); } -pd_font_bitmap_t *pd_font_library_add_bitmap(wchar_t ch, int font_id, int size, - const pd_font_bitmap_t *bmp) +pd_glyph_bitmap_t *pd_font_cache_add_bitmap(wchar_t ch, int font_id, int size, + const pd_glyph_bitmap_t *bmp) { - pd_font_bitmap_t *bmp_cache; + pd_glyph_bitmap_t *bmp_cache; rbtree_t *tree_font, *tree_bmp; if (!fontlib.active) { @@ -217,23 +217,23 @@ pd_font_bitmap_t *pd_font_library_add_bitmap(wchar_t ch, int font_id, int size, /* 在字体位图库中获取指定像素大小的字体位图 */ bmp_cache = select_bitmap_cache(tree_bmp, size); if (!bmp_cache) { - bmp_cache = malloc(sizeof(pd_font_bitmap_t)); + bmp_cache = malloc(sizeof(pd_glyph_bitmap_t)); if (!bmp_cache) { return NULL; } rbtree_insert_by_key(tree_bmp, size, bmp_cache); } /* 拷贝数据至该空间内 */ - memcpy(bmp_cache, bmp, sizeof(pd_font_bitmap_t)); + memcpy(bmp_cache, bmp, sizeof(pd_glyph_bitmap_t)); return bmp_cache; } -int pd_font_library_get_bitmap(unsigned ch, int font_id, int size, - const pd_font_bitmap_t **bmp) +int pd_font_cache_get_bitmap(unsigned ch, int font_id, int size, + const pd_glyph_bitmap_t **bmp) { int ret; rbtree_t *ctx; - pd_font_bitmap_t bmp_cache; + pd_glyph_bitmap_t bmp_cache; *bmp = NULL; if (!fontlib.active) { @@ -263,16 +263,16 @@ int pd_font_library_get_bitmap(unsigned ch, int font_id, int size, if (ch == 0) { return -1; } - pd_font_bitmap_init(&bmp_cache); - ret = pd_font_library_render_bitmap(&bmp_cache, ch, font_id, size); + pd_glyph_bitmap_init(&bmp_cache); + ret = pd_font_render_glyph(&bmp_cache, ch, font_id, size); if (ret == 0) { *bmp = - pd_font_library_add_bitmap(ch, font_id, size, &bmp_cache); + pd_font_cache_add_bitmap(ch, font_id, size, &bmp_cache); return 0; } - ret = pd_font_library_get_bitmap(0, font_id, size, bmp); + ret = pd_font_cache_get_bitmap(0, font_id, size, bmp); if (ret != 0) { - *bmp = pd_font_library_add_bitmap(0, font_id, size, &bmp_cache); + *bmp = pd_font_cache_add_bitmap(0, font_id, size, &bmp_cache); } return -1; } @@ -292,14 +292,14 @@ static void font_cache_destroy(font_cache_t *cache) int i; for (i = 0; i < FONT_CACHE_SIZE; ++i) { if (cache->fonts[i]) { - pd_font_destroy(cache->fonts[i]); + pd_font_face_destroy(cache->fonts[i]); } cache->fonts[i] = NULL; } free(cache); } -static pd_font_t *pd_font_library_get_cached_font(int id) +static pd_font_face_t *pd_font_library_get_cached_font(int id) { if (id > fontlib.font_cache_num * FONT_CACHE_SIZE) { return NULL; @@ -308,7 +308,7 @@ static pd_font_t *pd_font_library_get_cached_font(int id) ->fonts[id % FONT_CACHE_SIZE]; } -static int pd_font_library_add_cached_font(pd_font_t *font) +static int pd_font_library_add_cached_font(pd_font_face_t *font) { size_t size; font_cache_t **caches, *cache; @@ -337,7 +337,7 @@ static int pd_font_library_add_cached_font(pd_font_t *font) return 0; } -pd_font_weight_t pd_font_library_detect_weight(const char *str) +pd_font_weight_t pd_font_parse_weight(const char *str) { char *buf; pd_font_weight_t weight = PD_FONT_WEIGHT_NORMAL; @@ -366,7 +366,7 @@ pd_font_weight_t pd_font_library_detect_weight(const char *str) return weight; } -pd_font_style_t pd_font_library_detect_style(const char *str) +pd_font_style_t pd_font_parse_style(const char *str) { char *buf; pd_font_style_t style = PD_FONT_STYLE_NORMAL; @@ -385,9 +385,9 @@ pd_font_style_t pd_font_library_detect_style(const char *str) return style; } -int pd_font_library_add_font(pd_font_t *font) +int pd_font_register(pd_font_face_t *font) { - pd_font_t *exists_font; + pd_font_face_t *exists_font; font_family_node_t *node; font_style_node_t *style_node; @@ -407,7 +407,7 @@ int pd_font_library_add_font(pd_font_t *font) fontlib.default_font = font; } style_node->weights[font->weight - 1] = NULL; - pd_font_destroy(exists_font); + pd_font_face_destroy(exists_font); } else { font->id = ++fontlib.count; } @@ -416,7 +416,7 @@ int pd_font_library_add_font(pd_font_t *font) return font->id; } -pd_font_t *pd_font_library_get_font(int id) +pd_font_face_t *pd_font_get(int id) { if (!fontlib.active) { return NULL; @@ -478,7 +478,7 @@ static pd_font_weight_t font_weight_fallback(font_style_node_t *snode, return PD_FONT_WEIGHT_NONE; } -int pd_font_library_get_font_id(const char *family_name, pd_font_style_t style, +int pd_font_get_id(const char *family_name, pd_font_style_t style, pd_font_weight_t weight) { int style_num; @@ -514,12 +514,12 @@ int pd_font_library_get_font_id(const char *family_name, pd_font_style_t style, return -3; } -size_t pd_font_library_update_font_weight(const int *font_ids, +size_t pd_font_replace_weight(const int *font_ids, pd_font_weight_t weight, int **new_font_ids) { int id, *ids; - pd_font_t *font; + pd_font_face_t *font; size_t i, count, len; if (!font_ids) { @@ -534,8 +534,8 @@ size_t pd_font_library_update_font_weight(const int *font_ids, return 0; } for (i = 0, count = 0; i < len; ++i) { - font = pd_font_library_get_font(font_ids[i]); - id = pd_font_library_get_font_id(font->family_name, font->style, + font = pd_font_get(font_ids[i]); + id = pd_font_get_id(font->family_name, font->style, weight); if (id > 0) { ids[count++] = id; @@ -551,12 +551,12 @@ size_t pd_font_library_update_font_weight(const int *font_ids, return count; } -size_t pd_font_library_update_font_style(const int *font_ids, +size_t pd_font_replace_style(const int *font_ids, pd_font_style_t style, int **new_font_ids) { int id, *ids; - pd_font_t *font; + pd_font_face_t *font; size_t i, count, len; if (!font_ids) { @@ -571,8 +571,8 @@ size_t pd_font_library_update_font_style(const int *font_ids, return 0; } for (i = 0, count = 0; i < len; ++i) { - font = pd_font_library_get_font(font_ids[i]); - id = pd_font_library_get_font_id(font->family_name, style, + font = pd_font_get(font_ids[i]); + id = pd_font_get_id(font->family_name, style, font->weight); if (id > 0) { ids[count++] = id; @@ -588,7 +588,7 @@ size_t pd_font_library_update_font_style(const int *font_ids, return count; } -unsigned pd_font_library_query(int **font_ids, pd_font_style_t style, +unsigned pd_font_query(int **font_ids, pd_font_style_t style, pd_font_weight_t weight, const char *const *names) { @@ -609,7 +609,7 @@ unsigned pd_font_library_query(int **font_ids, pd_font_style_t style, } for (loaded_count = 0, i = 0; i < count; ++i) { ids[loaded_count] = - pd_font_library_get_font_id(names[i], style, weight); + pd_font_get_id(names[i], style, weight); if (ids[loaded_count] > 0) { ++loaded_count; } @@ -623,7 +623,7 @@ unsigned pd_font_library_query(int **font_ids, pd_font_style_t style, return loaded_count; } -int pd_font_library_get_default_font(void) +int pd_font_get_default(void) { if (!fontlib.default_font) { return -1; @@ -631,18 +631,18 @@ int pd_font_library_get_default_font(void) return fontlib.default_font->id; } -void pd_font_library_set_default_font(int id) +void pd_font_set_default(int id) { - pd_font_t *font = pd_font_library_get_font(id); + pd_font_face_t *font = pd_font_get(id); if (font) { fontlib.default_font = font; logger_debug("[font] select: %s\n", font->family_name); } } -int pd_font_library_load_file(const char *filepath) +int pd_font_load_file(const char *filepath) { - pd_font_t **fonts; + pd_font_face_t **fonts; int i, num_fonts, id; logger_debug("[font] load file: %s\n", filepath); @@ -656,7 +656,7 @@ int pd_font_library_load_file(const char *filepath) } for (i = 0; i < num_fonts; ++i) { fonts[i]->engine = fontlib.engine; - id = pd_font_library_add_font(fonts[i]); + id = pd_font_register(fonts[i]); logger_debug("[font] add font: %d, family: %s, style name: %s, " "weight: %d\n", id, fonts[i]->family_name, fonts[i]->style_name, @@ -666,15 +666,15 @@ int pd_font_library_load_file(const char *filepath) return 0; } -int pd_font_library_render_bitmap(pd_font_bitmap_t *buff, unsigned ch, +int pd_font_render_glyph(pd_glyph_bitmap_t *buff, unsigned ch, int font_id, int pixel_size) { - pd_font_t *font = fontlib.default_font; + pd_font_face_t *font = fontlib.default_font; do { if (font_id < 0 || !fontlib.engine) { break; } - font = pd_font_library_get_font(font_id); + font = pd_font_get(font_id); if (font) { break; } @@ -691,7 +691,7 @@ int pd_font_library_render_bitmap(pd_font_bitmap_t *buff, unsigned ch, return font->engine->render(buff, ch, pixel_size, font); } -bool pd_font_library_set_font_family_alias(const char *alias, +bool pd_font_family_set_alias(const char *alias, const char *family_name) { return dict_add(fontlib.font_family_aliases, (void *)alias, @@ -735,9 +735,9 @@ static void pd_font_library_init_engine(void) /* 先初始化内置的字体引擎 */ fontlib.engine = &fontlib.engines[0]; pd_incore_font_create(fontlib.engine); - pd_font_library_load_file("in-core.inconsolata"); - fid = pd_font_library_get_font_id("inconsolata", 0, 0); - fontlib.incore_font = pd_font_library_get_font(fid); + pd_font_load_file("in-core.inconsolata"); + fid = pd_font_get_id("inconsolata", 0, 0); + fontlib.incore_font = pd_font_get(fid); fontlib.default_font = fontlib.incore_font; /* 然后看情况启用其它字体引擎 */ #ifdef PANDAGL_HAS_FREETYPE diff --git a/lib/pandagl/src/font/library.h b/lib/pandagl/src/font/library.h index 5cb5608a5..8fa1ea35c 100644 --- a/lib/pandagl/src/font/library.h +++ b/lib/pandagl/src/font/library.h @@ -9,6 +9,6 @@ * LICENSE.TXT file in the root directory of this source tree. */ -pd_font_t *pd_font_create(const char *family_name, const char *style_name); +pd_font_face_t *pd_font_face_create(const char *family_name, const char *style_name); -void pd_font_destroy(pd_font_t *font); +void pd_font_face_destroy(pd_font_face_t *font); diff --git a/lib/pandagl/src/text/style.c b/lib/pandagl/src/text/style.c index 6208cbe84..55ff4fbfd 100644 --- a/lib/pandagl/src/text/style.c +++ b/lib/pandagl/src/text/style.c @@ -77,7 +77,7 @@ void pd_text_style_merge(pd_text_style_t *base, pd_text_style_t *target) base->has_style = true; base->style = target->style; } - if (pd_font_library_update_font_style(base->font_ids, base->style, + if (pd_font_replace_style(base->font_ids, base->style, &font_ids) > 0) { free(base->font_ids); base->font_ids = font_ids; @@ -87,7 +87,7 @@ void pd_text_style_merge(pd_text_style_t *base, pd_text_style_t *target) base->has_weight = true; base->weight = target->weight; } - if (pd_font_library_update_font_weight(base->font_ids, base->weight, + if (pd_font_replace_weight(base->font_ids, base->weight, &font_ids) > 0) { free(base->font_ids); base->font_ids = font_ids; @@ -117,7 +117,7 @@ int pd_text_style_set_weight(pd_text_style_t *ts, pd_font_weight_t weight) int *font_ids; ts->weight = weight; ts->has_weight = true; - if (pd_font_library_update_font_weight(ts->font_ids, weight, + if (pd_font_replace_weight(ts->font_ids, weight, &font_ids) > 0) { free(ts->font_ids); ts->font_ids = font_ids; @@ -131,7 +131,7 @@ int pd_text_style_set_style(pd_text_style_t *ts, pd_font_style_t style) int *font_ids; ts->style = style; ts->has_style = true; - if (pd_font_library_update_font_style(ts->font_ids, style, &font_ids) > + if (pd_font_replace_style(ts->font_ids, style, &font_ids) > 0) { free(ts->font_ids); ts->font_ids = font_ids; @@ -150,7 +150,7 @@ int pd_text_style_set_font(pd_text_style_t *ts, const char *const *names) ts->font_ids = NULL; ts->has_family = false; count = - pd_font_library_query(&ts->font_ids, ts->style, ts->weight, names); + pd_font_query(&ts->font_ids, ts->style, ts->weight, names); if (count > 0) { ts->has_family = true; return 0; @@ -170,7 +170,7 @@ int pd_text_style_set_default_font(pd_text_style_t *ts) return -ENOMEM; } ts->has_family = true; - ts->font_ids[0] = pd_font_library_get_default_font(); + ts->font_ids[0] = pd_font_get_default(); ts->font_ids[1] = 0; return 0; } diff --git a/lib/pandagl/src/text/text.c b/lib/pandagl/src/text/text.c index 6d90b6c67..a78ba7a17 100644 --- a/lib/pandagl/src/text/text.c +++ b/lib/pandagl/src/text/text.c @@ -230,14 +230,14 @@ static void pd_char_update_bitmap(pd_char_t *ch, pd_text_style_t *style) } } while (font_ids && font_ids[i] > 0) { - int ret = pd_font_library_get_bitmap(ch->code, font_ids[i], + int ret = pd_font_cache_get_bitmap(ch->code, font_ids[i], size, &ch->bitmap); if (ret == 0) { return; } ++i; } - pd_font_library_get_bitmap(ch->code, -1, size, &ch->bitmap); + pd_font_cache_get_bitmap(ch->code, -1, size, &ch->bitmap); } pd_text_t *pd_text_create(void) @@ -1224,10 +1224,10 @@ static void pd_text_render_char(pd_text_t *text, pd_char_t *ch, { /* 判断文字使用的前景颜色,再进行绘制 */ if (ch->style && ch->style->has_fore_color) { - pd_canvas_mix_font_bitmap(graph, ch_pos, ch->bitmap, + pd_canvas_mix_glyph_bitmap(graph, ch_pos, ch->bitmap, ch->style->fore_color); } else { - pd_canvas_mix_font_bitmap(graph, ch_pos, ch->bitmap, + pd_canvas_mix_glyph_bitmap(graph, ch_pos, ch->bitmap, text->default_style.fore_color); } } diff --git a/lib/pandagl/tests/test_font_load.c b/lib/pandagl/tests/test_font_load.c index 5cefbaf0f..90512893b 100644 --- a/lib/pandagl/tests/test_font_load.c +++ b/lib/pandagl/tests/test_font_load.c @@ -13,46 +13,46 @@ #include #include -#define GetSegoeUIFont(S, W) pd_font_library_get_font_id("Segoe UI", S, W) -#define GetArialFont(S, W) pd_font_library_get_font_id("Arial", S, W) +#define GetSegoeUIFont(S, W) pd_font_get_id("Segoe UI", S, W) +#define GetArialFont(S, W) pd_font_get_id("Arial", S, W) #ifdef _WIN32 static void test_segoe_ui_font_load(void) { - pd_font_t *font; + pd_font_face_t *font; int id; - if (pd_font_library_load_file("C:/windows/fonts/segoeui.ttf") != 0) { + if (pd_font_load_file("C:/windows/fonts/segoeui.ttf") != 0) { return; } ctest_equal_int( "should load segoeui.ttf", - pd_font_library_load_file("C:/windows/fonts/segoeui.ttf"), 0); + pd_font_load_file("C:/windows/fonts/segoeui.ttf"), 0); ctest_equal_int( "should load segoeuib.ttf", - pd_font_library_load_file("C:/windows/fonts/segoeuib.ttf"), 0); + pd_font_load_file("C:/windows/fonts/segoeuib.ttf"), 0); ctest_equal_int( "should load segoeuii.ttf", - pd_font_library_load_file("C:/windows/fonts/segoeuii.ttf"), 0); + pd_font_load_file("C:/windows/fonts/segoeuii.ttf"), 0); ctest_equal_int( "should load segoeuil.ttf", - pd_font_library_load_file("C:/windows/fonts/segoeuil.ttf"), 0); + pd_font_load_file("C:/windows/fonts/segoeuil.ttf"), 0); ctest_equal_int( "should load segoeuisl.ttf", - pd_font_library_load_file("C:/windows/fonts/segoeuisl.ttf"), 0); + pd_font_load_file("C:/windows/fonts/segoeuisl.ttf"), 0); ctest_equal_int( "should load segoeuiz.ttf", - pd_font_library_load_file("C:/windows/fonts/segoeuiz.ttf"), 0); + pd_font_load_file("C:/windows/fonts/segoeuiz.ttf"), 0); ctest_equal_int( "should load seguibl.ttf", - pd_font_library_load_file("C:/windows/fonts/seguibl.ttf"), 0); + pd_font_load_file("C:/windows/fonts/seguibl.ttf"), 0); ctest_equal_int( "should load seguili.ttf", - pd_font_library_load_file("C:/windows/fonts/seguili.ttf"), 0); + pd_font_load_file("C:/windows/fonts/seguili.ttf"), 0); id = GetSegoeUIFont(PD_FONT_STYLE_NORMAL, PD_FONT_WEIGHT_NORMAL); ctest_equal_bool("should resolve font (style: normal, weight: normal)", id > 0, true); if (id > 0) { - font = pd_font_library_get_font(id); + font = pd_font_get(id); ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_NORMAL); ctest_equal_int("should match font weight", font->weight, @@ -62,7 +62,7 @@ static void test_segoe_ui_font_load(void) ctest_equal_bool("should resolve font (style: italic, weight: normal)", id > 0, true); if (id > 0) { - font = pd_font_library_get_font(id); + font = pd_font_get(id); ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_ITALIC); ctest_equal_int("should match font weight", font->weight, @@ -72,7 +72,7 @@ static void test_segoe_ui_font_load(void) ctest_equal_bool("should resolve font (style: normal, weight: bold)", id > 0, true); if (id > 0) { - font = pd_font_library_get_font(id); + font = pd_font_get(id); ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_NORMAL); ctest_equal_int("should match font weight", font->weight, @@ -82,7 +82,7 @@ static void test_segoe_ui_font_load(void) ctest_equal_bool("should resolve font (style: normal, weight: light)", id > 0, true); if (id > 0) { - font = pd_font_library_get_font(id); + font = pd_font_get(id); ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_NORMAL); ctest_equal_int("should match font weight", font->weight, @@ -93,7 +93,7 @@ static void test_segoe_ui_font_load(void) "should resolve font (style: italic, weight: extra light)", id > 0, true); if (id > 0) { - font = pd_font_library_get_font(id); + font = pd_font_get(id); ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_ITALIC); ctest_equal_int("should match font weight", font->weight, @@ -104,27 +104,27 @@ static void test_segoe_ui_font_load(void) static void test_arial_font_load(void) { int id; - pd_font_t *font; - if (pd_font_library_load_file("C:/windows/fonts/arial.ttf") != 0) { + pd_font_face_t *font; + if (pd_font_load_file("C:/windows/fonts/arial.ttf") != 0) { return; } ctest_equal_int( "should load arialbd.ttf", - pd_font_library_load_file("C:/windows/fonts/arialbd.ttf"), 0); + pd_font_load_file("C:/windows/fonts/arialbd.ttf"), 0); ctest_equal_int( "should load ariblk.ttf", - pd_font_library_load_file("C:/windows/fonts/ariblk.ttf"), 0); + pd_font_load_file("C:/windows/fonts/ariblk.ttf"), 0); ctest_equal_int( "should load arialbi.ttf", - pd_font_library_load_file("C:/windows/fonts/arialbi.ttf"), 0); + pd_font_load_file("C:/windows/fonts/arialbi.ttf"), 0); ctest_equal_int( "should load ariali.ttf", - pd_font_library_load_file("C:/windows/fonts/ariali.ttf"), 0); + pd_font_load_file("C:/windows/fonts/ariali.ttf"), 0); id = GetArialFont(PD_FONT_STYLE_NORMAL, PD_FONT_WEIGHT_NORMAL); ctest_equal_bool("should resolve font (style: normal, weight: normal)", id > 0, true); if (id > 0) { - font = pd_font_library_get_font(id); + font = pd_font_get(id); ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_NORMAL); ctest_equal_int("should match font weight", font->weight, @@ -134,7 +134,7 @@ static void test_arial_font_load(void) ctest_equal_bool("should resolve font (style: italic, weight: normal)", id > 0, true); if (id > 0) { - font = pd_font_library_get_font(id); + font = pd_font_get(id); ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_ITALIC); ctest_equal_int("should match font weight", font->weight, @@ -144,7 +144,7 @@ static void test_arial_font_load(void) ctest_equal_bool("should resolve font (style: normal, weight: bold)", id > 0, true); if (id > 0) { - font = pd_font_library_get_font(id); + font = pd_font_get(id); ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_NORMAL); ctest_equal_int("should match font weight", font->weight, @@ -154,7 +154,7 @@ static void test_arial_font_load(void) ctest_equal_bool("should resolve font (style: normal, weight: black)", id > 0, true); if (id > 0) { - font = pd_font_library_get_font(id); + font = pd_font_get(id); ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_NORMAL); ctest_equal_int("should match font weight", font->weight, @@ -164,7 +164,7 @@ static void test_arial_font_load(void) ctest_equal_bool("should resolve font (style: italic, weight: bold)", id > 0, true); if (id > 0) { - font = pd_font_library_get_font(id); + font = pd_font_get(id); ctest_equal_int("should match font style", font->style, PD_FONT_STYLE_ITALIC); ctest_equal_int("should match font weight", font->weight, @@ -177,7 +177,7 @@ void test_pandagl_font_load(void) { pd_font_library_init(); ctest_equal_int("should load font from file", - pd_font_library_load_file("test_font_load.ttf"), 0); + pd_font_load_file("test_font_load.ttf"), 0); #ifdef _WIN32 ctest_describe("segoe ui font load", test_segoe_ui_font_load); ctest_describe("arial font load", test_arial_font_load); diff --git a/lib/ui-xml/src/ui_xml.c b/lib/ui-xml/src/ui_xml.c index 5d7dd07f3..5cc476967 100644 --- a/lib/ui-xml/src/ui_xml.c +++ b/lib/ui-xml/src/ui_xml.c @@ -92,7 +92,7 @@ static int ui_builder_parse_resource_node(xml_parser_t *parser, xmlNodePtr node) return PB_WARNING; } if (strstr(type, "application/font-")) { - if (pd_font_library_load_file(src) < 1) { + if (pd_font_load_file(src) < 1) { EXIT(PB_WARNING); } } else if (strcmp(type, "text/css") == 0) { diff --git a/lib/ui/src/ui_css.c b/lib/ui/src/ui_css.c index 363893b89..8b98d99a4 100644 --- a/lib/ui/src/ui_css.c +++ b/lib/ui/src/ui_css.c @@ -40,7 +40,7 @@ static void ui_on_parsed_font_face(const css_font_face_t *face) ui_event_t e; ui_event_init(&e, "css_font_face_load"); - pd_font_library_load_file(face->src); + pd_font_load_file(face->src); ui_post_event(&e, (css_font_face_t*)face, NULL); } diff --git a/lib/ui/src/ui_text_style.c b/lib/ui/src/ui_text_style.c index 08aa39a74..1181f18ec 100644 --- a/lib/ui/src/ui_text_style.c +++ b/lib/ui/src/ui_text_style.c @@ -223,7 +223,7 @@ void ui_compute_text_style(ui_text_style_t *fs, fs->font_ids = NULL; } if (style->font_family) { - pd_font_library_query(&fs->font_ids, fs->font_style, + pd_font_query(&fs->font_ids, fs->font_style, fs->font_weight, (const char *const *)style->font_family); } diff --git a/src/lcui_fonts.c b/src/lcui_fonts.c index 9dd23179e..e41c5c7a6 100644 --- a/src/lcui_fonts.c +++ b/src/lcui_fonts.c @@ -15,13 +15,13 @@ bool lcui_fonts_set_default(const char *family_name) { - int id = pd_font_library_get_font_id(family_name, PD_FONT_STYLE_NORMAL, + int id = pd_font_get_id(family_name, PD_FONT_STYLE_NORMAL, PD_FONT_WEIGHT_NORMAL); if (id < 0) { return false; } - pd_font_library_set_default_font(id); - pd_font_library_set_font_family_alias("system-ui", family_name); + pd_font_set_default(id); + pd_font_family_set_alias("system-ui", family_name); return true; } @@ -40,12 +40,12 @@ static void lcui_windows_fonts_init(void) "C:/Windows/Fonts/msyhl.ttc" }; for (i = 0; i < sizeof(fonts) / sizeof(char *); ++i) { - pd_font_library_load_file(fonts[i]); + pd_font_load_file(fonts[i]); } lcui_fonts_set_default("Microsoft YaHei"); - pd_font_library_set_font_family_alias("serif", "Simsun"); - pd_font_library_set_font_family_alias("sans-serif", "Microsoft YaHei"); - pd_font_library_set_font_family_alias("monospace", "Consola"); + pd_font_family_set_alias("serif", "Simsun"); + pd_font_family_set_alias("sans-serif", "Microsoft YaHei"); + pd_font_family_set_alias("monospace", "Consola"); } #else @@ -61,8 +61,8 @@ static void lcui_fc_fonts_init(void) "WenQuanYi Micro Hei" }; for (i = 0; i < sizeof(fonts) / sizeof(char *); ++i) { - path = pd_font_library_get_font_path(fonts[i]); - pd_font_library_load_file(path); + path = pd_font_find_path(fonts[i]); + pd_font_load_file(path); free(path); // TODO: 使用系统已设置的默认字体 if (!has_default) { @@ -104,14 +104,14 @@ static void lcui_linux_fonts_init(void) }; for (i = 0; i < sizeof(fonts) / sizeof(char *); ++i) { - pd_font_library_load_file(fonts[i]); + pd_font_load_file(fonts[i]); } // TODO: 使用系统已设置的默认字体 if (!lcui_fonts_set_default("Noto Sans CJK SC")) { lcui_fonts_set_default("Ubuntu"); } - pd_font_library_set_font_family_alias("sans-serif", "Ubuntu"); - pd_font_library_set_font_family_alias("monospace", "Ubuntu Mono"); + pd_font_family_set_alias("sans-serif", "Ubuntu"); + pd_font_family_set_alias("monospace", "Ubuntu Mono"); } #endif diff --git a/tests/integration/test_font_face.c b/tests/integration/test_font_face.c index 943ddc7cc..5f621e552 100644 --- a/tests/integration/test_font_face.c +++ b/tests/integration/test_font_face.c @@ -18,7 +18,7 @@ void test_font_face(void) ctest_equal_int("should load CSS file containing @font-face", ui_load_css_file("test_font_face.css"), 0); ctest_equal_bool("should resolve font registered via @font-face", - pd_font_library_get_font_id("icomoon", 0, 0) > 0, + pd_font_get_id("icomoon", 0, 0) > 0, true); ui_destroy(); } From ef23c9cd11bad7a64bed32098182200ce0d5ff08 Mon Sep 17 00:00:00 2001 From: Liu Date: Sun, 24 May 2026 23:11:04 +0800 Subject: [PATCH 16/66] refactor(pandagl): flatten glyph bitmap cache to hash + lru The previous bitmap cache was a three-level rbtree keyed by (wchar_t, font_id, size), which had two problems: 1. The wchar_t key collapses Unicode codepoints that map to the same glyph in a given face into separate cache slots, missing real reuse opportunities and bloating memory under text-heavy workloads. 2. There was no upper bound; long-running apps would grow the cache without limit until pd_font_library_destroy. Replace it with a flat hash table keyed by a packed 64-bit (face_id, glyph_index, size) tuple, plus a doubly-linked LRU list for O(1) eviction. - pd_font_engine gets a new get_glyph_index hook; FreeType maps via FT_Get_Char_Index, the in-core engine treats codepoints as identity (no cmap). - pd_font_cache_add_bitmap / pd_font_cache_get_bitmap now resolve the glyph index via the engine before keying the cache, so the same glyph reused across composed sequences hits the same entry. - pd_font_cache_set_capacity / pd_font_cache_count expose the LRU bound (default 8192 entries, 0 = unlimited) for runtime tuning and tests. Shrinking the capacity evicts immediately. - list_t is used with append at tail / evict from head so the yutil tail.prev pointer stays consistent (list_link does not update it). Adds lib/pandagl/tests/test_font_cache.c covering hit identity, size differentiation, unknown-codepoint fallback, and LRU eviction. --- lib/pandagl/include/pandagl/font.h | 10 + lib/pandagl/src/font/freetype.c | 8 + lib/pandagl/src/font/incore.c | 8 + lib/pandagl/src/font/library.c | 281 +++++++++++++++++++--------- lib/pandagl/tests/main.c | 2 + lib/pandagl/tests/test_font_cache.c | 95 ++++++++++ lib/pandagl/xmake.lua | 2 +- 7 files changed, 317 insertions(+), 89 deletions(-) create mode 100644 lib/pandagl/tests/test_font_cache.c diff --git a/lib/pandagl/include/pandagl/font.h b/lib/pandagl/include/pandagl/font.h index 07293f860..442cc9a04 100644 --- a/lib/pandagl/include/pandagl/font.h +++ b/lib/pandagl/include/pandagl/font.h @@ -64,6 +64,7 @@ typedef struct pd_font_face { struct pd_font_engine { char name[64]; int (*open)(const char *, pd_font_face_t ***); + unsigned (*get_glyph_index)(pd_font_face_t *, unsigned); int (*render)(pd_glyph_bitmap_t *, unsigned, int, pd_font_face_t *); void (*close)(void *); }; @@ -175,6 +176,15 @@ PD_PUBLIC pd_glyph_bitmap_t *pd_font_cache_add_bitmap( PD_PUBLIC int pd_font_cache_get_bitmap(unsigned ch, int font_id, int size, const pd_glyph_bitmap_t **bmp); +/** + * 设置字形位图缓存上限(按 entry 数)。0 表示不限制。 + * 当现有缓存超出新上限时,立即按 LRU 顺序驱逐多余 entry。 + */ +PD_PUBLIC void pd_font_cache_set_capacity(size_t capacity); + +/** 当前缓存中实际持有的 entry 数 */ +PD_PUBLIC size_t pd_font_cache_count(void); + /** 载入字体至数据库中 */ PD_PUBLIC int pd_font_load_file(const char *filepath); diff --git a/lib/pandagl/src/font/freetype.c b/lib/pandagl/src/font/freetype.c index c7a8524af..810a15e22 100644 --- a/lib/pandagl/src/font/freetype.c +++ b/lib/pandagl/src/font/freetype.c @@ -180,6 +180,13 @@ static int pd_freetype_render(pd_glyph_bitmap_t *bmp, unsigned ch, return ret; } +static unsigned pd_freetype_get_glyph_index(pd_font_face_t *font, unsigned ch) +{ + FT_Face ft_face = (FT_Face)font->data; + + return FT_Get_Char_Index(ft_face, ch); +} + int pd_freetype_engine_init(pd_font_engine_t *engine) { if (FT_Init_FreeType(&freetype.library)) { @@ -189,6 +196,7 @@ int pd_freetype_engine_init(pd_font_engine_t *engine) engine->render = pd_freetype_render; engine->open = pd_freetype_open; engine->close = pd_freetype_close; + engine->get_glyph_index = pd_freetype_get_glyph_index; return 0; } diff --git a/lib/pandagl/src/font/incore.c b/lib/pandagl/src/font/incore.c index 5cc51a3e7..21ece337d 100644 --- a/lib/pandagl/src/font/incore.c +++ b/lib/pandagl/src/font/incore.c @@ -54,11 +54,19 @@ static int pd_incore_font_render(pd_glyph_bitmap_t *bmp, unsigned ch, return -1; } +static unsigned pd_incore_font_get_glyph_index(pd_font_face_t *face, unsigned ch) +{ + (void)face; + /* 内置位图字体没有 cmap,字符码即字形索引 */ + return ch; +} + int pd_incore_font_create(pd_font_engine_t *engine) { engine->render = pd_incore_font_render; engine->close = pd_incore_font_close; engine->open = pd_incore_font_open; + engine->get_glyph_index = pd_incore_font_get_glyph_index; strcpy(engine->name, "in-core"); return 0; } diff --git a/lib/pandagl/src/font/library.c b/lib/pandagl/src/font/library.c index 88d2f06b7..3bf9d571c 100644 --- a/lib/pandagl/src/font/library.c +++ b/lib/pandagl/src/font/library.c @@ -22,13 +22,13 @@ #define FONT_CACHE_SIZE 32 #define FONT_CACHE_MAX_SIZE 1024 +#define GLYPH_CACHE_DEFAULT_CAPACITY 8192 /** - * 库中缓存的字体位图是分组存放的,共有三级分组,分别为: - * 字符->字体信息->字体大小 - * 获取字体位图时的搜索顺序为:先找到字符的记录,然后在记录中的字体数据库里找 - * 到指定字体样式标识号的字体位图库,之后在字体位图库中找到指定像素大小的字体 - * 位图。 + * 字形位图缓存使用扁平 hash 表 + LRU 双链表: + * key = (face_id, glyph_index, size) 打包为 64 位整数 + * value = glyph_cache_entry_t,包含位图数据和指向 LRU 链表节点的反向引用 + * 命中时移动到链首;超过 capacity 时从链尾驱逐。 */ typedef struct font_style_node { @@ -49,6 +49,18 @@ typedef struct font_family_node { font_style_node_t styles[PD_FONT_STYLE_TOTAL_NUM]; } font_family_node_t; +typedef struct glyph_cache_key { + int face_id; + unsigned glyph_index; + int size; +} glyph_cache_key_t; + +typedef struct glyph_cache_entry { + uint64_t key; + pd_glyph_bitmap_t bitmap; + list_node_t *lru_node; +} glyph_cache_entry_t; + static struct font_library_module { int count; int font_cache_num; @@ -60,8 +72,10 @@ static struct font_library_module { /** dict_t */ dict_t *font_family_aliases; - /** rbtree_t>> */ - rbtree_t bitmap_cache; + /** dict_t */ + dict_t *glyph_cache; + list_t glyph_lru; + size_t glyph_cache_capacity; font_cache_t **font_cache; pd_font_face_t *default_font; @@ -72,24 +86,101 @@ static struct font_library_module { /* clang-format on */ -PD_INLINE rbtree_t *select_char_cache(wchar_t ch) +PD_INLINE font_family_node_t *select_font_family_cache(const char *family_name) { - return rbtree_get_data_by_key(&fontlib.bitmap_cache, ch); + return dict_fetch_value(fontlib.font_families, family_name); } -PD_INLINE rbtree_t *select_font_cache(rbtree_t *font_cache, int font_id) +PD_INLINE uint64_t glyph_cache_pack_key(int face_id, unsigned glyph_index, + int size) { - return rbtree_get_data_by_key(font_cache, font_id); + /* face_id 占高 16 位,glyph_index 占中间 32 位,size 占低 16 位。 */ + return ((uint64_t)(unsigned)face_id << 48) | + ((uint64_t)glyph_index << 16) | + (uint64_t)((unsigned)size & 0xFFFFu); } -PD_INLINE pd_glyph_bitmap_t *select_bitmap_cache(rbtree_t *bmp_cache, int size) +static uint64_t glyph_cache_key_hash(const void *key) { - return rbtree_get_data_by_key(bmp_cache, size); + return dict_gen_hash_function(key, (int)sizeof(uint64_t)); } -PD_INLINE font_family_node_t *select_font_family_cache(const char *family_name) +static int glyph_cache_key_compare(void *priv_data, const void *key1, + const void *key2) { - return dict_fetch_value(fontlib.font_families, family_name); + (void)priv_data; + return *(const uint64_t *)key1 == *(const uint64_t *)key2; +} + +static void *glyph_cache_key_dup(void *priv_data, const void *key) +{ + uint64_t *copy; + (void)priv_data; + copy = malloc(sizeof(uint64_t)); + if (copy) { + *copy = *(const uint64_t *)key; + } + return copy; +} + +static void glyph_cache_key_destructor(void *priv_data, void *key) +{ + (void)priv_data; + free(key); +} + +static void glyph_cache_entry_destructor(void *priv_data, void *val) +{ + glyph_cache_entry_t *entry = val; + (void)priv_data; + if (!entry) { + return; + } + if (entry->lru_node) { + list_unlink(&fontlib.glyph_lru, entry->lru_node); + list_node_free(entry->lru_node); + } + pd_glyph_bitmap_destroy(&entry->bitmap); + free(entry); +} + +static void glyph_cache_evict_one(void) +{ + list_node_t *node = list_get_first_node(&fontlib.glyph_lru); + glyph_cache_entry_t *victim; + + if (!node) { + return; + } + victim = node->data; + /* dict_delete 触发 destructor 会再次解链 lru_node, + * 所以这里只清掉反向引用并把 list_node 自己处理掉 */ + list_unlink(&fontlib.glyph_lru, node); + list_node_free(node); + victim->lru_node = NULL; + dict_delete(fontlib.glyph_cache, &victim->key); +} + +static void glyph_cache_touch(glyph_cache_entry_t *entry) +{ + if (!entry->lru_node) { + return; + } + if (entry->lru_node == fontlib.glyph_lru.tail.prev) { + return; + } + list_unlink(&fontlib.glyph_lru, entry->lru_node); + list_append_node(&fontlib.glyph_lru, entry->lru_node); +} + +static unsigned resolve_glyph_index(unsigned ch, int font_id) +{ + pd_font_face_t *face = pd_font_get(font_id); + + if (!face || !face->engine || !face->engine->get_glyph_index) { + return ch; + } + return face->engine->get_glyph_index(face, ch); } #ifdef PANDAGL_HAS_FONTCONFIG @@ -167,73 +258,64 @@ static void destroy_font_family_node(void *privdata, void *data) free(node); } -static void destroy_font_bitmap(void *arg) -{ - pd_glyph_bitmap_destroy(arg); - free(arg); -} - -static void destroy_tree_node(void *arg) -{ - rbtree_destroy(arg); - free(arg); -} - pd_glyph_bitmap_t *pd_font_cache_add_bitmap(wchar_t ch, int font_id, int size, - const pd_glyph_bitmap_t *bmp) + const pd_glyph_bitmap_t *bmp) { - pd_glyph_bitmap_t *bmp_cache; - rbtree_t *tree_font, *tree_bmp; + uint64_t key; + unsigned glyph_index; + glyph_cache_entry_t *entry; if (!fontlib.active) { return NULL; } - /* 获取字符的字体信息集 */ - tree_font = select_char_cache(ch); - if (!tree_font) { - tree_font = malloc(sizeof(rbtree_t)); - if (!tree_font) { - return NULL; - } - rbtree_init(tree_font); - rbtree_set_destroy_func(tree_font, destroy_tree_node); - rbtree_insert_by_key(&fontlib.bitmap_cache, ch, tree_font); - } /* 当字体ID不大于0时,使用内置字体 */ if (font_id <= 0) { font_id = fontlib.incore_font->id; } - /* 获取相应字体样式标识号的字体位图库 */ - tree_bmp = select_font_cache(tree_font, font_id); - if (!tree_bmp) { - tree_bmp = malloc(sizeof(rbtree_t)); - if (!tree_bmp) { - return NULL; - } - rbtree_init(tree_bmp); - rbtree_set_destroy_func(tree_bmp, destroy_font_bitmap); - rbtree_insert_by_key(tree_font, font_id, tree_bmp); - } - /* 在字体位图库中获取指定像素大小的字体位图 */ - bmp_cache = select_bitmap_cache(tree_bmp, size); - if (!bmp_cache) { - bmp_cache = malloc(sizeof(pd_glyph_bitmap_t)); - if (!bmp_cache) { - return NULL; - } - rbtree_insert_by_key(tree_bmp, size, bmp_cache); + glyph_index = resolve_glyph_index(ch, font_id); + key = glyph_cache_pack_key(font_id, glyph_index, size); + entry = dict_fetch_value(fontlib.glyph_cache, &key); + if (entry) { + /* 已存在则就地覆盖位图数据 */ + pd_glyph_bitmap_destroy(&entry->bitmap); + memcpy(&entry->bitmap, bmp, sizeof(pd_glyph_bitmap_t)); + glyph_cache_touch(entry); + return &entry->bitmap; + } + /* 容量到上限时驱逐链尾 */ + while (fontlib.glyph_cache_capacity > 0 && + fontlib.glyph_lru.length >= fontlib.glyph_cache_capacity) { + glyph_cache_evict_one(); + } + entry = malloc(sizeof(glyph_cache_entry_t)); + if (!entry) { + return NULL; + } + entry->key = key; + memcpy(&entry->bitmap, bmp, sizeof(pd_glyph_bitmap_t)); + entry->lru_node = NULL; + if (dict_add(fontlib.glyph_cache, &key, entry) != DICT_OK) { + free(entry); + return NULL; } - /* 拷贝数据至该空间内 */ - memcpy(bmp_cache, bmp, sizeof(pd_glyph_bitmap_t)); - return bmp_cache; + entry->lru_node = malloc(sizeof(list_node_t)); + if (entry->lru_node) { + entry->lru_node->data = entry; + entry->lru_node->prev = NULL; + entry->lru_node->next = NULL; + list_append_node(&fontlib.glyph_lru, entry->lru_node); + } + return &entry->bitmap; } int pd_font_cache_get_bitmap(unsigned ch, int font_id, int size, - const pd_glyph_bitmap_t **bmp) + const pd_glyph_bitmap_t **bmp) { int ret; - rbtree_t *ctx; - pd_glyph_bitmap_t bmp_cache; + uint64_t key; + unsigned glyph_index; + glyph_cache_entry_t *entry; + pd_glyph_bitmap_t tmp; *bmp = NULL; if (!fontlib.active) { @@ -246,37 +328,47 @@ int pd_font_cache_get_bitmap(unsigned ch, int font_id, int size, font_id = fontlib.incore_font->id; } } - do { - if (!(ctx = select_char_cache(ch))) { - break; - } - ctx = select_font_cache(ctx, font_id); - if (!ctx) { - break; - } - *bmp = select_bitmap_cache(ctx, size); - if (*bmp) { - return 0; - } - break; - } while (0); + glyph_index = resolve_glyph_index(ch, font_id); + key = glyph_cache_pack_key(font_id, glyph_index, size); + entry = dict_fetch_value(fontlib.glyph_cache, &key); + if (entry) { + glyph_cache_touch(entry); + *bmp = &entry->bitmap; + return 0; + } if (ch == 0) { return -1; } - pd_glyph_bitmap_init(&bmp_cache); - ret = pd_font_render_glyph(&bmp_cache, ch, font_id, size); + pd_glyph_bitmap_init(&tmp); + ret = pd_font_render_glyph(&tmp, ch, font_id, size); if (ret == 0) { - *bmp = - pd_font_cache_add_bitmap(ch, font_id, size, &bmp_cache); + *bmp = pd_font_cache_add_bitmap(ch, font_id, size, &tmp); return 0; } + /* 渲染失败:回退到 .notdef(ch == 0)位图 */ ret = pd_font_cache_get_bitmap(0, font_id, size, bmp); if (ret != 0) { - *bmp = pd_font_cache_add_bitmap(0, font_id, size, &bmp_cache); + *bmp = pd_font_cache_add_bitmap(0, font_id, size, &tmp); } return -1; } +void pd_font_cache_set_capacity(size_t capacity) +{ + fontlib.glyph_cache_capacity = capacity; + if (capacity == 0) { + return; + } + while (fontlib.glyph_lru.length > capacity) { + glyph_cache_evict_one(); + } +} + +size_t pd_font_cache_count(void) +{ + return fontlib.glyph_lru.length; +} + static font_cache_t *font_cache_create(void) { font_cache_t *cache; @@ -712,12 +804,12 @@ static void pd_font_library_init_base(void) { static dict_type_t dict_type; static dict_type_t alias_dict_type; + static dict_type_t glyph_dict_type; fontlib.count = 0; fontlib.font_cache_num = 1; fontlib.font_cache = malloc(sizeof(font_cache_t)); fontlib.font_cache[0] = font_cache_create(); - rbtree_init(&fontlib.bitmap_cache); dict_init_string_key_type(&dict_type); dict_init_string_copy_key_type(&alias_dict_type); dict_type.val_destructor = destroy_font_family_node; @@ -725,7 +817,18 @@ static void pd_font_library_init_base(void) alias_dict_type.val_dup = font_family_dict_val_dup; fontlib.font_families = dict_create(&dict_type, NULL); fontlib.font_family_aliases = dict_create(&alias_dict_type, NULL); - rbtree_set_destroy_func(&fontlib.bitmap_cache, destroy_tree_node); + + /* glyph 位图缓存:key 为打包后的 64 位整数 */ + memset(&glyph_dict_type, 0, sizeof(glyph_dict_type)); + glyph_dict_type.hash_function = glyph_cache_key_hash; + glyph_dict_type.key_compare = glyph_cache_key_compare; + glyph_dict_type.key_dup = glyph_cache_key_dup; + glyph_dict_type.key_destructor = glyph_cache_key_destructor; + glyph_dict_type.val_destructor = glyph_cache_entry_destructor; + fontlib.glyph_cache = dict_create(&glyph_dict_type, NULL); + list_create(&fontlib.glyph_lru); + fontlib.glyph_cache_capacity = GLYPH_CACHE_DEFAULT_CAPACITY; + fontlib.active = true; } @@ -765,11 +868,13 @@ static void pd_font_library_destroy_base(void) } dict_destroy(fontlib.font_family_aliases); dict_destroy(fontlib.font_families); - rbtree_destroy(&fontlib.bitmap_cache); + /* dict 的 val_destructor 会解链并释放各 entry 的 LRU 节点 */ + dict_destroy(fontlib.glyph_cache); free(fontlib.font_cache); fontlib.font_cache = NULL; fontlib.font_families = NULL; fontlib.font_family_aliases = NULL; + fontlib.glyph_cache = NULL; } static void pd_font_library_destroy_engine(void) diff --git a/lib/pandagl/tests/main.c b/lib/pandagl/tests/main.c index 4c55a7417..e869d8c90 100644 --- a/lib/pandagl/tests/main.c +++ b/lib/pandagl/tests/main.c @@ -15,12 +15,14 @@ extern void test_pandagl_canvas_mix(void); extern void test_pandagl_image_reader(void); extern void test_pandagl_font_load(void); extern void test_pandagl_text_edit(void); +extern void test_pandagl_font_cache(void); static const ctest_suite_t suites[] = { { "pandagl/canvas mix", test_pandagl_canvas_mix }, { "pandagl/image reader", test_pandagl_image_reader }, { "pandagl/font load", test_pandagl_font_load }, { "pandagl/text edit", test_pandagl_text_edit }, + { "pandagl/font cache", test_pandagl_font_cache }, { NULL, NULL } }; diff --git a/lib/pandagl/tests/test_font_cache.c b/lib/pandagl/tests/test_font_cache.c new file mode 100644 index 000000000..c9b8a3616 --- /dev/null +++ b/lib/pandagl/tests/test_font_cache.c @@ -0,0 +1,95 @@ +/* + * lib/pandagl/tests/test_font_cache.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +/* + * 字形位图缓存的功能测试: + * - 同一 (face, ch, size) 第二次请求应命中缓存,返回相同指针; + * - 不同 size 应得到不同 entry; + * - 渲染失败的字符回退到 .notdef,不应崩溃。 + */ + +static void should_return_same_pointer_on_cache_hit(void) +{ + const pd_glyph_bitmap_t *bmp1 = NULL; + const pd_glyph_bitmap_t *bmp2 = NULL; + + ctest_equal_int("first lookup should succeed", + pd_font_cache_get_bitmap('A', -1, 14, &bmp1), 0); + ctest_equal_int("second lookup should succeed", + pd_font_cache_get_bitmap('A', -1, 14, &bmp2), 0); + ctest_equal_bool("cached bitmaps should share the same address", + bmp1 == bmp2, true); +} + +static void should_treat_different_sizes_as_different_entries(void) +{ + const pd_glyph_bitmap_t *bmp1 = NULL; + const pd_glyph_bitmap_t *bmp2 = NULL; + + pd_font_cache_get_bitmap('B', -1, 12, &bmp1); + pd_font_cache_get_bitmap('B', -1, 24, &bmp2); + ctest_equal_bool("different sizes should yield different entries", + bmp1 != NULL && bmp2 != NULL && bmp1 != bmp2, true); +} + +static void should_not_crash_on_unknown_codepoint(void) +{ + const pd_glyph_bitmap_t *bmp = NULL; + /* 超出 BMP 的字符大概率没有 glyph,应回退而非崩溃 */ + int ret = pd_font_cache_get_bitmap(0x10FFFD, -1, 14, &bmp); + ctest_equal_bool("should return non-positive code", ret <= 0, true); +} + +static void should_evict_least_recently_used(void) +{ + const pd_glyph_bitmap_t *bmp = NULL; + size_t before; + + /* 先用很大上限,预热若干 entry */ + pd_font_cache_set_capacity(1024); + pd_font_cache_get_bitmap('X', -1, 10, &bmp); + pd_font_cache_get_bitmap('Y', -1, 10, &bmp); + pd_font_cache_get_bitmap('Z', -1, 10, &bmp); + before = pd_font_cache_count(); + ctest_equal_bool("should hold at least 3 entries", before >= 3, true); + + /* 把上限缩到 2,应立即驱逐 */ + pd_font_cache_set_capacity(2); + ctest_equal_uint("count should drop to capacity", + (unsigned)pd_font_cache_count(), 2u); + + /* 添加新 entry 时仍不超过上限 */ + pd_font_cache_get_bitmap('W', -1, 10, &bmp); + ctest_equal_uint("count should stay at capacity after new insert", + (unsigned)pd_font_cache_count(), 2u); + + /* 恢复无限制 */ + pd_font_cache_set_capacity(0); +} + +void test_pandagl_font_cache(void) +{ + pd_font_library_init(); + ctest_describe("glyph cache hit returns same pointer", + should_return_same_pointer_on_cache_hit); + ctest_describe("glyph cache differentiates by size", + should_treat_different_sizes_as_different_entries); + ctest_describe("glyph cache handles unknown codepoint", + should_not_crash_on_unknown_codepoint); + ctest_describe("glyph cache lru eviction", + should_evict_least_recently_used); + pd_font_library_destroy(); +} diff --git a/lib/pandagl/xmake.lua b/lib/pandagl/xmake.lua index 829ceb668..95150ffc4 100644 --- a/lib/pandagl/xmake.lua +++ b/lib/pandagl/xmake.lua @@ -64,7 +64,7 @@ target("pandagl-tests") set_kind("binary") set_group("tests") set_rundir("tests/fixtures") - add_files("tests/main.c", "tests/test_canvas_mix.c", "tests/test_image_reader.c", "tests/test_font_load.c", "tests/test_text_edit.c") + add_files("tests/main.c", "tests/test_canvas_mix.c", "tests/test_image_reader.c", "tests/test_font_load.c", "tests/test_text_edit.c", "tests/test_font_cache.c") add_deps("ctest", "pandagl") add_rules("tests.runnable") add_tests("default", {group = "tests"}) From e463e0ba824eb06c0bbad6073ee12ed6cc9b49ff Mon Sep 17 00:00:00 2001 From: Liu Date: Sun, 24 May 2026 23:54:14 +0800 Subject: [PATCH 17/66] refactor(pandagl): split text.c and rename caret/text-IO API Split lib/pandagl/src/text/text.c into four cohesive units backed by a library-private header: - text.c : type lifecycle, line storage, geometry, dirty-rect bookkeeping, top-level update - text_typeset.c : line breaking, merging, autowrap, alignment - text_render.c : per-char bitmap refresh and drawing - text_edit.c : caret, insert/delete/backspace, text I/O - text_internal.h : library-private cross-file helpers (not installed) Drop the 'insert' overload that conflated 'cursor' with 'insertion point' and align the field/API names with the cursor concept used in mainstream GUI toolkits: insert_x, insert_y -> caret.x, caret.y (new pd_text_caret_t sub-struct) pd_text_set_insert_position -> pd_text_set_caret pd_text_set_insert_pixel_position -> pd_text_set_caret_pixel pd_text_get_insert_pixel_position -> pd_text_get_caret_pixel pd_text_get_char_pixel_position -> pd_text_get_char_pixel Make text I/O symmetric and intent-revealing: pd_text_dump -> pd_text_read (mirrors pd_text_write) pd_text_empty -> pd_text_clear (the previous static helper is renamed to pd_text_reset_lines) pd_text_set_typeset_task -> pd_text_request_typeset Add pd_text_to_wcs(text), which allocates and returns the full buffer contents including line endings. It complements the range-based pd_text_read for callers that just want the whole text as a wide string. Fix the mulitiline_enabled -> multiline_enabled typo while at it. All call sites in lib/pandagl, src/widgets and the tests are updated. test_text_edit.c gains two cases for pd_text_to_wcs covering full-text round-trip and the empty-text edge case. --- lib/pandagl/include/pandagl/text.h | 30 +- lib/pandagl/src/text/text.c | 870 +-------------------------- lib/pandagl/src/text/text_edit.c | 555 +++++++++++++++++ lib/pandagl/src/text/text_internal.h | 54 ++ lib/pandagl/src/text/text_render.c | 176 ++++++ lib/pandagl/src/text/text_typeset.c | 162 +++++ lib/pandagl/tests/test_text_edit.c | 59 +- src/widgets/text.c | 2 +- src/widgets/textinput.c | 28 +- 9 files changed, 1055 insertions(+), 881 deletions(-) create mode 100644 lib/pandagl/src/text/text_edit.c create mode 100644 lib/pandagl/src/text/text_internal.h create mode 100644 lib/pandagl/src/text/text_render.c create mode 100644 lib/pandagl/src/text/text_typeset.c diff --git a/lib/pandagl/include/pandagl/text.h b/lib/pandagl/include/pandagl/text.h index ff6b57589..3176fe072 100644 --- a/lib/pandagl/include/pandagl/text.h +++ b/lib/pandagl/include/pandagl/text.h @@ -84,13 +84,17 @@ typedef enum pd_word_break_t { PD_WORD_BREAK_BREAK_ALL } pd_word_break_t; +typedef struct pd_text_caret { + int x; /**< 光标所在列数 */ + int y; /**< 光标所在行数 */ +} pd_text_caret_t; + typedef struct pd_text { int offset_x; /**< x轴坐标偏移量 */ int offset_y; /**< y轴坐标偏移量 */ int new_offset_x; /**< 新的x轴坐标偏移量 */ int new_offset_y; /**< 新的y轴坐标偏移量 */ - int insert_x; /**< 光标所在列数 */ - int insert_y; /**< 光标所在行数 */ + pd_text_caret_t caret; /**< 光标位置 */ int width; /**< 实际文本宽度 */ /** @@ -109,7 +113,7 @@ typedef struct pd_text { int line_height; pd_text_align_t text_align; pd_word_break_t word_break; - bool mulitiline_enabled; + bool multiline_enabled; bool autowrap_enabled; bool style_tag_enabled; list_t dirty_rects; @@ -135,7 +139,7 @@ PD_PUBLIC int pd_text_get_line_height(pd_text_t *layer, int line_num); PD_PUBLIC int pd_text_get_line_length(pd_text_t *layer, int line_num); /** 添加 更新文本排版 的任务 */ -PD_PUBLIC void pd_text_set_typeset_task(pd_text_t *layer, int start_row); +PD_PUBLIC void pd_text_request_typeset(pd_text_t *layer, int start_row); /** 设置文本对齐方式 */ PD_PUBLIC void pd_text_set_align(pd_text_t *layer, int align); @@ -152,22 +156,22 @@ PD_PUBLIC void pd_text_destroy(pd_text_t *layer); PD_PUBLIC void pd_text_mark_dirty(pd_text_t *layer, int start_row, int end_row); /** 设置插入点的行列坐标 */ -PD_PUBLIC void pd_text_set_insert_position(pd_text_t *layer, int line_num, +PD_PUBLIC void pd_text_set_caret(pd_text_t *layer, int line_num, int col); /** 根据像素坐标设置文本光标的行列坐标 */ -PD_PUBLIC int pd_text_set_insert_pixel_position(pd_text_t *layer, int x, int y); +PD_PUBLIC int pd_text_set_caret_pixel(pd_text_t *layer, int x, int y); /** 获取指定行列的文字的像素坐标 */ -PD_PUBLIC int pd_text_get_char_pixel_position(pd_text_t *layer, int line_num, +PD_PUBLIC int pd_text_get_char_pixel(pd_text_t *layer, int line_num, int col, pd_pos_t *pixel_pos); /** 获取文本光标的像素坐标 */ -PD_PUBLIC int pd_text_get_insert_pixel_position(pd_text_t *layer, +PD_PUBLIC int pd_text_get_caret_pixel(pd_text_t *layer, pd_pos_t *pixel_pos); /** 清空文本 */ -PD_PUBLIC void pd_text_empty(pd_text_t *layer); +PD_PUBLIC void pd_text_clear(pd_text_t *layer); PD_PUBLIC int pd_text_insert(pd_text_t *layer, const wchar_t *wstr, list_t *tag_stack); @@ -179,9 +183,15 @@ PD_PUBLIC int pd_text_write(pd_text_t *layer, const wchar_t *wstr, list_t *tag_stack); /** 获取文本图层中的文本(宽字符版) */ -PD_PUBLIC size_t pd_text_dump(pd_text_t *text, size_t start_pos, size_t max_len, +PD_PUBLIC size_t pd_text_read(pd_text_t *text, size_t start_pos, size_t max_len, wchar_t *wstr_buff); +/** + * 取得文本图层完整内容(含按 line.eol 还原的换行符) + * 返回值由调用方负责 free,失败时返回 NULL + */ +PD_PUBLIC wchar_t *pd_text_to_wcs(pd_text_t *text); + /** 计算并获取文本的宽度 */ PD_PUBLIC int pd_text_get_width(pd_text_t *layer); diff --git a/lib/pandagl/src/text/text.c b/lib/pandagl/src/text/text.c index a78ba7a17..b86fd9ddd 100644 --- a/lib/pandagl/src/text/text.c +++ b/lib/pandagl/src/text/text.c @@ -1,7 +1,7 @@ /* * lib/pandagl/src/text/text.c * - * Copyright (c) 2018-2025, Liu Chao All rights reserved. + * Copyright (c) 2018-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -10,14 +10,12 @@ */ #include -#include -#include +#include #include - -typedef enum { PD_TEXT_ACTION_INSERT, PD_TEXT_ACTION_APPEND } pd_text_action_t; +#include +#include "text_internal.h" #define DEFAULT_LINE_HEIGHT 1.42857143 -#define isalpha(ch) (ch >= 'a' && ch <= 'z') || (ch >= 'a' && ch <= 'z') static void pd_text_line_init(pd_text_line_t *line) { @@ -45,7 +43,7 @@ static void pd_text_line_destroy(pd_text_line_t *line) line->string = NULL; } -static pd_text_line_t *pd_text_insert_line(pd_text_t *text, size_t line_num) +pd_text_line_t *pd_text_insert_line(pd_text_t *text, size_t line_num) { size_t i, size; pd_text_line_t *line, **lines; @@ -75,7 +73,7 @@ static pd_text_line_t *pd_text_insert_line(pd_text_t *text, size_t line_num) return line; } -static int pd_text_delete_line(pd_text_t *text, int line_num) +int pd_text_delete_line(pd_text_t *text, int line_num) { if (line_num < 0 || line_num >= text->lines_length) { return -1; @@ -90,17 +88,17 @@ static int pd_text_delete_line(pd_text_t *text, int line_num) return 0; } -PD_INLINE pd_text_line_t *pd_text_append_line(pd_text_t *text) +pd_text_line_t *pd_text_append_line(pd_text_t *text) { return pd_text_insert_line(text, text->lines_length); } -PD_INLINE pd_text_line_t *pd_text_get_line(pd_text_t *text, int line_num) +pd_text_line_t *pd_text_get_line(pd_text_t *text, int line_num) { return (line_num >= text->lines_length) ? NULL : text->lines[line_num]; } -static void pd_text_update_line_size(pd_text_t *text, pd_text_line_t *line) +void pd_text_update_line_size(pd_text_t *text, pd_text_line_t *line) { int i; int text_height = text->default_style.pixel_size; @@ -124,7 +122,7 @@ static void pd_text_update_line_size(pd_text_t *text, pd_text_line_t *line) } } -static int pd_text_line_set_length(pd_text_line_t *line, int len) +int pd_text_line_set_length(pd_text_line_t *line, int len) { int i; int old_len = line->length; @@ -148,7 +146,7 @@ static int pd_text_line_set_length(pd_text_line_t *line, int len) } /* 释放并清空指定区间 [start, end) 内的字符槽位 */ -static void pd_text_line_erase(pd_text_line_t *line, int start, int end) +void pd_text_line_erase(pd_text_line_t *line, int start, int end) { int i; @@ -169,7 +167,7 @@ static void pd_text_line_erase(pd_text_line_t *line, int start, int end) /* 将 src 行 [src_start, src_end) 的字符所有权转移到 dst 行的 dst_start 起始位置。 * 转移后 src 对应槽位被置 NULL,防止 delete_line 时被重复释放。 * 调用者负责保证 dst 已有足够容量。 */ -static void pd_text_line_move(pd_text_line_t *dst, int dst_start, +void pd_text_line_move(pd_text_line_t *dst, int dst_start, pd_text_line_t *src, int src_start, int src_end) { int i, j; @@ -183,7 +181,7 @@ static void pd_text_line_move(pd_text_line_t *dst, int dst_start, } } -static int pd_text_line_insert(pd_text_line_t *line, int offset, +int pd_text_line_insert(pd_text_line_t *line, int offset, pd_char_t *txtchar) { size_t i, insert_index; @@ -206,7 +204,7 @@ static int pd_text_line_insert(pd_text_line_t *line, int offset, return 0; } -static int pd_text_line_insert_copy(pd_text_line_t *line, int ins_pos, +int pd_text_line_insert_copy(pd_text_line_t *line, int ins_pos, pd_char_t *txtchar) { pd_char_t *txtchar2; @@ -215,31 +213,6 @@ static int pd_text_line_insert_copy(pd_text_line_t *line, int ins_pos, return pd_text_line_insert(line, ins_pos, txtchar2); } -static void pd_char_update_bitmap(pd_char_t *ch, pd_text_style_t *style) -{ - int i = 0; - int size = style->pixel_size; - int *font_ids = style->font_ids; - - if (ch->style) { - if (ch->style->has_family) { - font_ids = ch->style->font_ids; - } - if (ch->style->has_pixel_size) { - size = ch->style->pixel_size; - } - } - while (font_ids && font_ids[i] > 0) { - int ret = pd_font_cache_get_bitmap(ch->code, font_ids[i], - size, &ch->bitmap); - if (ret == 0) { - return; - } - ++i; - } - pd_font_cache_get_bitmap(ch->code, -1, size, &ch->bitmap); -} - pd_text_t *pd_text_create(void) { pd_text_t *text; @@ -248,8 +221,8 @@ pd_text_t *pd_text_create(void) text->length = 0; text->offset_x = 0; text->offset_y = 0; - text->insert_x = 0; - text->insert_y = 0; + text->caret.x = 0; + text->caret.y = 0; text->max_width = 0; text->max_height = 0; text->fixed_width = 0; @@ -261,7 +234,7 @@ pd_text_t *pd_text_create(void) text->lines = NULL; text->text_align = PD_TEXT_ALIGN_LEFT; text->autowrap_enabled = false; - text->mulitiline_enabled = false; + text->multiline_enabled = false; text->style_tag_enabled = false; text->word_break = PD_WORD_BREAK_NORMAL; text->task.typeset_start_line = 0; @@ -281,7 +254,7 @@ static void on_destroy_text_style(void *data) free(data); } -static void pd_text_clear(pd_text_t *text) +static void pd_text_reset_lines(pd_text_t *text) { int line_num; @@ -298,28 +271,28 @@ static void pd_text_clear(pd_text_t *text) text->lines_length = 0; text->width = 0; text->length = 0; - text->insert_x = 0; - text->insert_y = 0; + text->caret.x = 0; + text->caret.y = 0; list_destroy(&text->styles, on_destroy_text_style); text->task.redraw_all = true; } -void pd_text_empty(pd_text_t *text) +void pd_text_clear(pd_text_t *text) { - pd_text_clear(text); + pd_text_reset_lines(text); pd_text_insert_line(text, 0); } void pd_text_destroy(pd_text_t *text) { - pd_text_clear(text); + pd_text_reset_lines(text); pd_rects_clear(&text->dirty_rects); pd_text_style_destroy(&text->default_style); free(text); } /* 根据对齐方式,计算文本行的起始x轴位置 */ -static int pd_text_get_line_start_x(pd_text_t *text, pd_text_line_t *line) +int pd_text_get_line_start_x(pd_text_t *text, pd_text_line_t *line) { int width; if (text->fixed_width > 0) { @@ -360,7 +333,7 @@ int pd_text_get_line_length(pd_text_t *text, int line_num) return text->lines[line_num]->length; } -void pd_text_set_typeset_task(pd_text_t *text, int start_line) +void pd_text_request_typeset(pd_text_t *text, int start_line) { if (start_line < text->task.typeset_start_line) { text->task.typeset_start_line = start_line; @@ -369,7 +342,7 @@ void pd_text_set_typeset_task(pd_text_t *text, int start_line) } /** 获取指定文本行中的文本段的矩形区域 */ -static int pd_text_get_line_rect(pd_text_t *text, int line_num, int start_col, +int pd_text_get_line_rect(pd_text_t *text, int line_num, int start_col, int end_col, pd_rect_t *rect) { int i; @@ -415,7 +388,7 @@ static int pd_text_get_line_rect(pd_text_t *text, int line_num, int start_col, return 0; } -static void pd_text_mark_line_dirty(pd_text_t *text, int line_num, int start, +void pd_text_mark_line_dirty(pd_text_t *text, int line_num, int start, int end) { pd_rect_t rect; @@ -451,428 +424,6 @@ void pd_text_mark_dirty(pd_text_t *text, int start_line, int end_line) } } -void pd_text_set_insert_position(pd_text_t *text, int line_num, int col) -{ - if (line_num < 0) { - line_num = 0; - } else if (line_num >= text->lines_length) { - if (text->lines_length < 0) { - line_num = 0; - } else { - line_num = text->lines_length - 1; - } - } - if (col < 0) { - col = 0; - } else if (text->lines_length > 0) { - if (col >= text->lines[line_num]->length) { - col = text->lines[line_num]->length; - } - } else { - col = 0; - } - text->insert_x = col; - text->insert_y = line_num; -} - -int pd_text_set_insert_pixel_position(pd_text_t *text, int x, int y) -{ - pd_text_line_t *line; - int i, pixel_pos, ins_x, ins_y = 0; - - pixel_pos = text->offset_y; - for (i = 0; i < text->lines_length; ++i) { - pixel_pos += text->lines[i]->height; - if (pixel_pos >= y) { - ins_y = i; - break; - } - } - if (i >= text->lines_length) { - if (text->lines_length > 0) { - ins_y = text->lines_length - 1; - } else { - text->insert_x = 0; - text->insert_y = 0; - return -1; - } - } - line = text->lines[ins_y]; - ins_x = line->length; - pixel_pos = text->offset_x; - pixel_pos += pd_text_get_line_start_x(text, line); - for (i = 0; i < line->length; ++i) { - pd_char_t *txtchar; - txtchar = line->string[i]; - if (!txtchar->bitmap) { - continue; - } - pixel_pos += txtchar->bitmap->metrics.hori_advance; - /* 如果在当前字中心点的前面 */ - if (x <= - pixel_pos - txtchar->bitmap->metrics.hori_advance / 2) { - ins_x = i; - break; - } - } - pd_text_set_insert_position(text, ins_y, ins_x); - return 0; -} - -/** 获取指定行列的文字的像素坐标 */ -int pd_text_get_char_pixel_position(pd_text_t *text, int line_num, int col, - pd_pos_t *pixel_pos) -{ - pd_text_line_t *line; - int i, pixel_x = 0, pixel_y = 0; - - if (line_num < 0 || line_num >= text->lines_length) { - return -1; - } - if (col < 0) { - return -2; - } else if (col > text->lines[line_num]->length) { - return -3; - } - /* 累加前几行的高度 */ - for (i = 0; i < line_num; ++i) { - pixel_y += text->lines[i]->height; - } - line = text->lines[line_num]; - pixel_x = pd_text_get_line_start_x(text, line); - for (i = 0; i < col; ++i) { - pd_char_t *txtchar = line->string[i]; - if (!txtchar || !txtchar->bitmap) { - continue; - } - pixel_x += txtchar->bitmap->metrics.hori_advance; - } - pixel_pos->x = pixel_x; - pixel_pos->y = pixel_y; - return 0; -} - -int pd_text_get_insert_pixel_position(pd_text_t *text, pd_pos_t *pixel_pos) -{ - return pd_text_get_char_pixel_position(text, text->insert_y, - text->insert_x, pixel_pos); -} - -static void pd_text_break_line(pd_text_t *text, int line_num, int col, - pd_text_eol_t eol) -{ - int n; - pd_text_line_t *line, *next; - - line = pd_text_get_line(text, line_num); - next = pd_text_insert_line(text, line_num + 1); - /* 将本行原有的行尾符转移至下一行 */ - next->eol = line->eol; - line->eol = eol; - for (n = line->length - 1; n >= col; --n) { - pd_text_line_insert(next, 0, line->string[n]); - line->string[n] = NULL; - } - line->length = col; - pd_text_update_line_size(text, line); - pd_text_update_line_size(text, next); -} - -static void pd_text_merge_line(pd_text_t *text, int line_num) -{ - int old_len; - pd_text_line_t *line = pd_text_get_line(text, line_num); - pd_text_line_t *next = pd_text_get_line(text, line_num + 1); - - if (!line || !next) { - return; - } - if (text->insert_y > line_num) { - --text->insert_y; - if (text->insert_y == line_num) { - text->insert_x += line->length; - } - } - old_len = line->length; - pd_text_line_set_length(line, line->length + next->length); - pd_text_line_move(line, old_len, next, 0, next->length); - line->eol = next->eol; - pd_text_update_line_size(text, line); - pd_text_delete_line(text, line_num + 1); -} - -static void pd_text_typeset_line(pd_text_t *text, int line_num) -{ - int col, line_width = 0, word_col = 0; - int max_width = - text->fixed_width > 0 ? text->fixed_width : text->max_width; - - pd_char_t *txtchar; - pd_text_line_t *line = text->lines[line_num]; - bool autowrap = - max_width > 0 && text->autowrap_enabled && text->mulitiline_enabled; - - for (col = 0; col < line->length; ++col) { - txtchar = line->string[col]; - if (!txtchar->bitmap) { - continue; - } - /* 累加行宽度 */ - line_width += txtchar->bitmap->metrics.hori_advance; - /* 如果是当前行的第一个字符,或者行宽度没有超过宽度限制 */ - if (!autowrap || col < 1 || line_width <= max_width) { - if (isalpha(txtchar->code)) { - } else { - word_col = col + 1; - } - continue; - } - if (text->word_break == PD_WORD_BREAK_NORMAL) { - if (word_col < 1) { - continue; - } - col = word_col; - } - pd_text_break_line(text, line_num, col, PD_TEXT_EOL_NONE); - return; - } - pd_text_update_line_size(text, line); - /* 如果本行有换行符,或者是最后一行 */ - if (line->eol != PD_TEXT_EOL_NONE || - line_num == text->lines_length - 1) { - return; - } - line_width = line->width; - /* 本行的文本宽度未达到限制宽度,需要将下行的文本转移至本行 */ - if (line->eol == PD_TEXT_EOL_NONE) { - pd_text_mark_line_dirty(text, line_num, 0, -1); - pd_text_mark_line_dirty(text, line_num + 1, 0, -1); - pd_text_merge_line(text, line_num); - pd_text_typeset_line(text, line_num); - } -} - -/** 从指定行开始,对文本进行排版 */ -static void pd_text_typeset(pd_text_t *text, int start_line) -{ - int line_num; - /* 记录排版前各个文本行的矩形区域 */ - pd_text_mark_dirty(text, start_line, -1); - for (line_num = start_line; line_num < text->lines_length; ++line_num) { - pd_text_typeset_line(text, line_num); - } - /* 记录排版后各个文本行的矩形区域 */ - pd_text_mark_dirty(text, start_line, -1); -} - -static const wchar_t *pd_text_process_style_tags(pd_text_t *text, - const wchar_t *p, list_t *tags, - pd_text_style_t **style) -{ - pd_text_style_t *s; - const wchar_t *pp; - - pp = pd_style_tags_next_close_tag(tags, p); - if (pp) { - s = pd_style_tags_get_text_style(tags); - if (s) { - pd_text_style_merge(s, &text->default_style); - list_append(&text->styles, s); - } - *style = s; - return pp; - } - pp = pd_style_tags_next_open_tag(tags, p); - if (pp) { - s = pd_style_tags_get_text_style(tags); - if (s) { - pd_text_style_merge(s, &text->default_style); - list_append(&text->styles, s); - } - *style = s; - return pp; - } - return NULL; -} - -static int pd_text_process(pd_text_t *text, const wchar_t *wstr, - pd_text_action_t action, list_t *tags) -{ - pd_text_eol_t eol; - pd_text_line_t *line; - pd_char_t txtchar; - list_t tmp_tags; - const wchar_t *p; - int cur_col, cur_line, start_line, ins_x, ins_y; - bool need_typeset, rect_has_added; - pd_text_style_t *style = NULL; - - if (!wstr) { - return -1; - } - need_typeset = false; - rect_has_added = false; - list_create(&tmp_tags); - if (!tags) { - tags = &tmp_tags; - } - /* 如果是将文本追加至文本末尾 */ - if (action == PD_TEXT_ACTION_APPEND) { - if (text->lines_length > 0) { - cur_line = text->lines_length - 1; - } else { - cur_line = 0; - } - line = pd_text_get_line(text, cur_line); - if (!line) { - line = pd_text_append_line(text); - } - cur_col = line->length; - } else { /* 否则,是将文本插入至当前插入点 */ - cur_line = text->insert_y; - cur_col = text->insert_x; - line = pd_text_get_line(text, cur_line); - if (!line) { - line = pd_text_append_line(text); - } - } - start_line = cur_line; - ins_x = cur_col; - ins_y = cur_line; - for (p = wstr; *p; ++p) { - if (text->style_tag_enabled) { - const wchar_t *pp; - pp = pd_text_process_style_tags(text, p, tags, &style); - if (pp) { - p = pp - 1; - continue; - } - } - if (*p == '\r' || *p == '\n') { - /* 判断是哪一种换行模式 */ - if (*p == '\r') { - if (*(p + 1) == '\n') { - eol = PD_TEXT_EOL_CR_LF; - } else { - eol = PD_TEXT_EOL_CR; - } - } else { - eol = PD_TEXT_EOL_LF; - } - /* 如果没有记录过文本行的矩形区域 */ - if (!rect_has_added) { - pd_text_mark_dirty(text, ins_y, -1); - rect_has_added = true; - start_line = ins_y; - } - /* 将当前行中的插入点为截点,进行断行 */ - pd_text_break_line(text, ins_y, ins_x, eol); - text->width = y_max(text->width, line->width); - need_typeset = true; - ++text->length; - ins_x = 0; - ++ins_y; - line = pd_text_get_line(text, ins_y); - continue; - } - txtchar.style = style; - txtchar.code = *p; - pd_char_update_bitmap(&txtchar, &text->default_style); - pd_text_line_insert_copy(line, ins_x, &txtchar); - ++text->length; - ++ins_x; - } - /* 更新当前行的尺寸 */ - pd_text_update_line_size(text, line); - text->width = y_max(text->width, line->width); - if (action == PD_TEXT_ACTION_INSERT) { - text->insert_x = ins_x; - text->insert_y = ins_y; - } - /* 若启用了自动换行模式,则标记需要重新对文本进行排版 */ - if (text->autowrap_enabled || need_typeset) { - pd_text_set_typeset_task(text, cur_line); - } else { - pd_text_mark_line_dirty(text, cur_line, 0, -1); - } - /* 如果已经记录过文本行矩形区域 */ - if (rect_has_added) { - pd_text_mark_dirty(text, start_line, -1); - rect_has_added = true; - } - pd_style_tags_clear(&tmp_tags); - return 0; -} - -int pd_text_insert(pd_text_t *text, const wchar_t *wstr, list_t *tags) -{ - return pd_text_process(text, wstr, PD_TEXT_ACTION_INSERT, tags); -} - -int pd_text_append(pd_text_t *text, const wchar_t *wstr, list_t *tag_stack) -{ - return pd_text_process(text, wstr, PD_TEXT_ACTION_APPEND, tag_stack); -} - -int pd_text_write(pd_text_t *text, const wchar_t *wstr, list_t *tag_stack) -{ - pd_text_empty(text); - return pd_text_append(text, wstr, tag_stack); -} - -size_t pd_text_dump(pd_text_t *text, size_t start_pos, size_t max_len, - wchar_t *wstr_buff) -{ - size_t i, line_num, col; - pd_text_line_t *line; - - if (max_len == 0) { - wstr_buff[0] = 0; - return 0; - } - /* 先根据一维坐标计算行列坐标 */ - for (i = 0, line_num = 0, col = 0; line_num < text->lines_length; - ++line_num) { - if (i >= start_pos) { - col = start_pos - i; - break; - } - i += text->lines[line_num]->length; - } - for (i = 0; line_num < text->lines_length && i < max_len; ++line_num) { - line = text->lines[line_num]; - for (; col < line->length && i < max_len; ++col, ++i) { - wstr_buff[i] = line->string[col]->code; - } - /* 进入下一行前,按行尾符还原对应的换行字符 */ - if (i >= max_len) { - break; - } - switch (line->eol) { - case PD_TEXT_EOL_CR: - wstr_buff[i++] = L'\r'; - break; - case PD_TEXT_EOL_LF: - wstr_buff[i++] = L'\n'; - break; - case PD_TEXT_EOL_CR_LF: - wstr_buff[i++] = L'\r'; - if (i >= max_len) { - break; - } - wstr_buff[i++] = L'\n'; - break; - case PD_TEXT_EOL_NONE: - default: - break; - } - /* 切换到下一行时必须重置列号 */ - col = 0; - } - wstr_buff[i] = 0; - return i; -} - int pd_text_get_width(pd_text_t *text) { int i, line_num, w, max_w; @@ -928,249 +479,6 @@ int pd_text_set_max_size(pd_text_t *text, int width, int height) return 0; } -/** 设置是否启用多行文本模式 */ -void pd_text_set_multiline(pd_text_t *text, bool enabled) -{ - if (text->mulitiline_enabled != enabled) { - text->mulitiline_enabled = enabled; - pd_text_set_typeset_task(text, 0); - } -} - -/** 删除指定行列的文字及其右边的文本 */ -static int pd_text_delete_ex(pd_text_t *text, int char_y, int char_x, - int n_char) -{ - int end_x, end_y, i, j, len; - pd_text_line_t *line, *end_line, *prev_line; - - if (char_x < 0) { - char_x = 0; - } - if (char_y < 0) { - char_y = 0; - } - if (n_char <= 0) { - return -1; - } - if (char_y >= text->lines_length) { - return -2; - } - line = text->lines[char_y]; - if (char_x > line->length) { - char_x = line->length; - } - i = n_char; - end_x = char_x; - end_y = char_y; - /* 计算结束点的位置 */ - for (; end_y < text->lines_length && n_char > 0; ++end_y) { - line = text->lines[end_y]; - if (end_x + n_char <= line->length) { - end_x += n_char; - n_char = 0; - break; - } - n_char -= (line->length - end_x); - if (line->eol == PD_TEXT_EOL_NONE) { - end_x = 0; - } else { - n_char -= 1; - end_x = 0; - } - } - if (n_char >= 0) { - text->length -= i - n_char; - } else { - text->length -= n_char; - } - if (end_y >= text->lines_length) { - end_y = text->lines_length - 1; - end_line = text->lines[end_y]; - end_x = end_line->length; - } else { - end_line = text->lines[end_y]; - } - if (end_x > end_line->length) { - end_x = end_line->length; - } - if (end_x == char_x && end_y == char_y) { - return 0; - } - /* 获取上一行文本(首行时无上一行) */ - prev_line = char_y > 0 ? text->lines[char_y - 1] : NULL; - // 计算起始行与结束行拼接后的长度 - // 起始行:0 1 2 3 4 5,起点位置:2 - // 结束行:0 1 2 3 4 5,终点位置:4 - // 拼接后的长度:2 + 6 - 4 = 4 - len = char_x + end_line->length - end_x; - if (len < 0) { - return -3; - } - /* 如果是同一行 */ - if (line == end_line) { - if (end_x > end_line->length) { - return -4; - } - pd_text_mark_line_dirty(text, char_y, char_x, -1); - pd_text_set_typeset_task(text, char_y); - /* 释放被删除范围内的字符 */ - pd_text_line_erase(line, char_x, end_x); - /* 将结束点之后的内容向前搬移 */ - pd_text_line_move(line, char_x, line, end_x, line->length); - /* 如果当前行为空,也不是第一行,并且上一行没有结束符, - * 则直接移除当前行,不能再访问 line */ - if (len <= 0 && char_y > 0 && prev_line && - prev_line->eol != PD_TEXT_EOL_NONE) { - pd_text_delete_line(text, char_y); - return 0; - } - /* 调整起始行的容量 */ - pd_text_line_set_length(line, len); - /* 更新文本行的尺寸 */ - pd_text_update_line_size(text, line); - return 0; - } - /* 释放起始行中被删除的字符(区间为 [char_x, line->length)) */ - pd_text_line_erase(line, char_x, line->length); - /* 释放结束行中被删除的字符(区间为 [0, end_x)) */ - pd_text_line_erase(end_line, 0, end_x); - /* 如果结束点在行尾,并且该行不是最后一行, - * 则将结束点推进到下一行的行首 */ - if (end_x == end_line->length && end_y < text->lines_length - 1) { - ++end_y; - end_line = pd_text_get_line(text, end_y); - end_x = 0; - len = char_x + end_line->length; - } - pd_text_line_set_length(line, len); - /* 标记当前行后面的所有行的矩形需区域需要刷新 */ - pd_text_mark_dirty(text, char_y + 1, -1); - /* 移除起始行与结束行之间的文本行 */ - for (i = char_y + 1, j = i; j < end_y; ++j) { - pd_text_mark_line_dirty(text, i, 0, -1); - pd_text_delete_line(text, i); - } - end_y = char_y + 1; - /* 将结束行的内容拼接至起始行(所有权随之转移) */ - pd_text_line_move(line, char_x, end_line, end_x, end_line->length); - pd_text_update_line_size(text, line); - pd_text_mark_line_dirty(text, end_y, 0, -1); - /* 移除结束行 */ - pd_text_delete_line(text, end_y); - /* 如果起始行无内容,并且上一行没有结束符(换行符),则 - * 说明需要删除起始行 */ - if (len <= 0 && char_y > 0 && prev_line && - prev_line->eol != PD_TEXT_EOL_NONE) { - pd_text_mark_line_dirty(text, char_y, 0, -1); - pd_text_delete_line(text, char_y); - } - pd_text_set_typeset_task(text, char_y); - return 0; -} - -/** 删除文本光标的当前坐标右边的文本 */ -int pd_text_delete(pd_text_t *text, int n_char) -{ - return pd_text_delete_ex(text, text->insert_y, text->insert_x, n_char); -} - -/** 退格删除文本,即删除文本光标的当前坐标左边的文本 */ -int pd_text_backspace(pd_text_t *text, int n_char) -{ - int n_del; - int char_x, char_y; - pd_text_line_t *line; - - /* 先获取当前字的位置 */ - char_x = text->insert_x; - char_y = text->insert_y; - /* 再计算删除 n_char 个字后的位置 */ - for (n_del = n_char; char_y >= 0; --char_y) { - line = text->lines[char_y]; - /* 如果不是当前行,则重定位至行尾 */ - if (char_y < text->insert_y) { - char_x = line->length; - if (line->eol == PD_TEXT_EOL_NONE) { - --char_x; - } - } - if (char_x >= n_del) { - char_x = char_x - n_del; - n_del = 0; - break; - } - n_del = n_del - char_x - 1; - } - if (char_y < 0 || n_del == n_char) { - return -1; - } - /* 若能够被删除的字不够 n_char 个,则调整需删除的字数 */ - if (n_del > 0) { - n_char -= n_del; - } - /* 开始删除文本 */ - pd_text_delete_ex(text, char_y, char_x, n_char); - /* 若最后一行被完全移除,则移动输入点至上一行的行尾处 */ - if (char_x == 0 && text->lines_length > 0 && - char_y >= text->lines_length) { - char_y = text->lines_length - 1; - char_x = text->lines[char_y]->length; - } - /* 更新文本光标的位置 */ - pd_text_set_insert_position(text, char_y, char_x); - return 0; -} - -void pd_text_set_autowrap(pd_text_t *text, bool autowrap) -{ - if (text->autowrap_enabled != autowrap) { - text->autowrap_enabled = autowrap; - pd_text_set_typeset_task(text, 0); - } -} - -void pd_text_set_word_break(pd_text_t *text, pd_word_break_t word_break) -{ - if (text->word_break != word_break) { - text->word_break = word_break; - pd_text_set_typeset_task(text, 0); - } -} - -/** 设置是否使用样式标签 */ -void pd_text_set_style_tag(pd_text_t *text, bool enabled) -{ - text->style_tag_enabled = enabled; -} - -static void pd_text_update_style_cache(pd_text_t *text) -{ - list_node_t *node; - if (!text->default_style.has_family) { - pd_text_style_set_default_font(&text->default_style); - } - /* 替换缺省字体,确保能够正确应用字体设置 */ - for (list_each(node, &text->styles)) { - pd_text_style_merge(node->data, &text->default_style); - } -} - -/** 重新载入各个文字的字体位图 */ -void pd_text_reload_bitmap(pd_text_t *text) -{ - int line_num, col; - pd_text_update_style_cache(text); - for (line_num = 0; line_num < text->lines_length; ++line_num) { - pd_text_line_t *line = text->lines[line_num]; - for (col = 0; col < line->length; ++col) { - pd_char_t *txtchar = line->string[col]; - pd_char_update_bitmap(txtchar, &text->default_style); - } - pd_text_update_line_size(text, line); - } -} - void pd_text_update(pd_text_t *text, list_t *rects) { if (text->task.update_bitmap) { @@ -1200,130 +508,6 @@ void pd_text_update(pd_text_t *text, list_t *rects) } } -static void pd_text_validate_rect(pd_text_t *text, pd_rect_t *area) -{ - int width, height; - - if (text->fixed_width > 0) { - width = text->fixed_width; - } else if (text->max_width > 0) { - width = text->max_width; - } else { - width = text->width; - } - if (text->fixed_height > 0) { - height = text->fixed_height; - } else { - height = pd_text_get_height(text); - } - pd_rect_correct(area, width, height); -} - -static void pd_text_render_char(pd_text_t *text, pd_char_t *ch, - pd_canvas_t *graph, pd_pos_t ch_pos) -{ - /* 判断文字使用的前景颜色,再进行绘制 */ - if (ch->style && ch->style->has_fore_color) { - pd_canvas_mix_glyph_bitmap(graph, ch_pos, ch->bitmap, - ch->style->fore_color); - } else { - pd_canvas_mix_glyph_bitmap(graph, ch_pos, ch->bitmap, - text->default_style.fore_color); - } -} - -static void pd_text_render_line(pd_text_t *text, pd_rect_t *area, - pd_canvas_t *graph, pd_pos_t layer_pos, - pd_text_line_t *line, int y) -{ - pd_char_t *ch; - pd_pos_t pen; - int col, x; - - x = pd_text_get_line_start_x(text, line) + text->offset_x; - for (col = 0; col < line->length && x < area->x + area->width; ++col) { - ch = line->string[col]; - if (!ch->bitmap) { - continue; - } - if (x + ch->bitmap->metrics.hori_advance < area->x) { - x += ch->bitmap->metrics.hori_advance; - continue; - } - pen.x = layer_pos.x + x; - pen.y = layer_pos.y + y; - if (ch->style && ch->style->has_back_color) { - pd_rect_t rect; - rect.x = pen.x; - rect.y = pen.y; - rect.height = line->height; - rect.width = ch->bitmap->metrics.hori_advance; - pd_canvas_fill_rect(graph, ch->style->back_color, rect); - } - pen.x += ch->bitmap->left; - pen.y += (line->height - ch->bitmap->metrics.bbox_height) / 2 + - ch->bitmap->metrics.ascender - ch->bitmap->top; - pd_text_render_char(text, ch, graph, pen); - x += ch->bitmap->metrics.hori_advance; - } -} - -int pd_text_render_to(pd_text_t *text, pd_rect_t area, pd_pos_t layer_pos, - pd_canvas_t *canvas) -{ - int y; - int line_num; - pd_text_line_t *line; - - y = text->offset_y; - /* 确定可绘制的最大区域范围 */ - pd_text_validate_rect(text, &area); - for (line_num = 0; line_num < text->lines_length; ++line_num) { - line = pd_text_get_line(text, line_num); - y += line->height; - if (y > area.y) { - y -= line->height; - break; - } - } - /* 如果没有可绘制的文本行 */ - if (line_num >= text->lines_length) { - return -1; - } - for (; line_num < text->lines_length; ++line_num) { - line = pd_text_get_line(text, line_num); - pd_text_render_line(text, &area, canvas, layer_pos, line, y); - y += line->height; - /* 超出绘制区域范围就不绘制了 */ - if (y > area.y + area.height) { - break; - } - } - return 0; -} - -/** 设置全局文本样式 */ -void pd_text_set_style(pd_text_t *text, pd_text_style_t *style) -{ - pd_text_style_destroy(&text->default_style); - pd_text_style_copy(&text->default_style, style); - text->task.update_bitmap = true; -} - -void pd_text_set_align(pd_text_t *text, int align) -{ - text->text_align = align; - text->task.update_typeset = true; - text->task.typeset_start_line = 0; -} - -void pd_text_set_line_height(pd_text_t *text, int height) -{ - text->line_height = height; - text->task.update_typeset = true; - text->task.typeset_start_line = 0; -} - bool pd_text_set_offset(pd_text_t *text, int offset_x, int offset_y) { if (text->new_offset_x != offset_x || text->new_offset_y != offset_y) { diff --git a/lib/pandagl/src/text/text_edit.c b/lib/pandagl/src/text/text_edit.c new file mode 100644 index 000000000..c630b40f0 --- /dev/null +++ b/lib/pandagl/src/text/text_edit.c @@ -0,0 +1,555 @@ +/* + * lib/pandagl/src/text/text_edit.c + * + * Copyright (c) 2018-2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include "text_internal.h" + +typedef enum { PD_TEXT_ACTION_INSERT, PD_TEXT_ACTION_APPEND } pd_text_action_t; + +void pd_text_set_caret(pd_text_t *text, int line_num, int col) +{ + if (line_num < 0) { + line_num = 0; + } else if (line_num >= text->lines_length) { + if (text->lines_length < 0) { + line_num = 0; + } else { + line_num = text->lines_length - 1; + } + } + if (col < 0) { + col = 0; + } else if (text->lines_length > 0) { + if (col >= text->lines[line_num]->length) { + col = text->lines[line_num]->length; + } + } else { + col = 0; + } + text->caret.x = col; + text->caret.y = line_num; +} + +int pd_text_set_caret_pixel(pd_text_t *text, int x, int y) +{ + pd_text_line_t *line; + int i, pixel_pos, ins_x, ins_y = 0; + + pixel_pos = text->offset_y; + for (i = 0; i < text->lines_length; ++i) { + pixel_pos += text->lines[i]->height; + if (pixel_pos >= y) { + ins_y = i; + break; + } + } + if (i >= text->lines_length) { + if (text->lines_length > 0) { + ins_y = text->lines_length - 1; + } else { + text->caret.x = 0; + text->caret.y = 0; + return -1; + } + } + line = text->lines[ins_y]; + ins_x = line->length; + pixel_pos = text->offset_x; + pixel_pos += pd_text_get_line_start_x(text, line); + for (i = 0; i < line->length; ++i) { + pd_char_t *txtchar; + txtchar = line->string[i]; + if (!txtchar->bitmap) { + continue; + } + pixel_pos += txtchar->bitmap->metrics.hori_advance; + /* 如果在当前字中心点的前面 */ + if (x <= + pixel_pos - txtchar->bitmap->metrics.hori_advance / 2) { + ins_x = i; + break; + } + } + pd_text_set_caret(text, ins_y, ins_x); + return 0; +} + +/** 获取指定行列的文字的像素坐标 */ +int pd_text_get_char_pixel(pd_text_t *text, int line_num, int col, + pd_pos_t *pixel_pos) +{ + pd_text_line_t *line; + int i, pixel_x = 0, pixel_y = 0; + + if (line_num < 0 || line_num >= text->lines_length) { + return -1; + } + if (col < 0) { + return -2; + } else if (col > text->lines[line_num]->length) { + return -3; + } + /* 累加前几行的高度 */ + for (i = 0; i < line_num; ++i) { + pixel_y += text->lines[i]->height; + } + line = text->lines[line_num]; + pixel_x = pd_text_get_line_start_x(text, line); + for (i = 0; i < col; ++i) { + pd_char_t *txtchar = line->string[i]; + if (!txtchar || !txtchar->bitmap) { + continue; + } + pixel_x += txtchar->bitmap->metrics.hori_advance; + } + pixel_pos->x = pixel_x; + pixel_pos->y = pixel_y; + return 0; +} + +int pd_text_get_caret_pixel(pd_text_t *text, pd_pos_t *pixel_pos) +{ + return pd_text_get_char_pixel(text, text->caret.y, + text->caret.x, pixel_pos); +} + +static const wchar_t *pd_text_process_style_tags(pd_text_t *text, + const wchar_t *p, list_t *tags, + pd_text_style_t **style) +{ + pd_text_style_t *s; + const wchar_t *pp; + + pp = pd_style_tags_next_close_tag(tags, p); + if (pp) { + s = pd_style_tags_get_text_style(tags); + if (s) { + pd_text_style_merge(s, &text->default_style); + list_append(&text->styles, s); + } + *style = s; + return pp; + } + pp = pd_style_tags_next_open_tag(tags, p); + if (pp) { + s = pd_style_tags_get_text_style(tags); + if (s) { + pd_text_style_merge(s, &text->default_style); + list_append(&text->styles, s); + } + *style = s; + return pp; + } + return NULL; +} + +static int pd_text_process(pd_text_t *text, const wchar_t *wstr, + pd_text_action_t action, list_t *tags) +{ + pd_text_eol_t eol; + pd_text_line_t *line; + pd_char_t txtchar; + list_t tmp_tags; + const wchar_t *p; + int cur_col, cur_line, start_line, ins_x, ins_y; + bool need_typeset, rect_has_added; + pd_text_style_t *style = NULL; + + if (!wstr) { + return -1; + } + need_typeset = false; + rect_has_added = false; + list_create(&tmp_tags); + if (!tags) { + tags = &tmp_tags; + } + /* 如果是将文本追加至文本末尾 */ + if (action == PD_TEXT_ACTION_APPEND) { + if (text->lines_length > 0) { + cur_line = text->lines_length - 1; + } else { + cur_line = 0; + } + line = pd_text_get_line(text, cur_line); + if (!line) { + line = pd_text_append_line(text); + } + cur_col = line->length; + } else { /* 否则,是将文本插入至当前插入点 */ + cur_line = text->caret.y; + cur_col = text->caret.x; + line = pd_text_get_line(text, cur_line); + if (!line) { + line = pd_text_append_line(text); + } + } + start_line = cur_line; + ins_x = cur_col; + ins_y = cur_line; + for (p = wstr; *p; ++p) { + if (text->style_tag_enabled) { + const wchar_t *pp; + pp = pd_text_process_style_tags(text, p, tags, &style); + if (pp) { + p = pp - 1; + continue; + } + } + if (*p == '\r' || *p == '\n') { + /* 判断是哪一种换行模式 */ + if (*p == '\r') { + if (*(p + 1) == '\n') { + eol = PD_TEXT_EOL_CR_LF; + } else { + eol = PD_TEXT_EOL_CR; + } + } else { + eol = PD_TEXT_EOL_LF; + } + /* 如果没有记录过文本行的矩形区域 */ + if (!rect_has_added) { + pd_text_mark_dirty(text, ins_y, -1); + rect_has_added = true; + start_line = ins_y; + } + /* 将当前行中的插入点为截点,进行断行 */ + pd_text_break_line(text, ins_y, ins_x, eol); + text->width = y_max(text->width, line->width); + need_typeset = true; + ++text->length; + ins_x = 0; + ++ins_y; + line = pd_text_get_line(text, ins_y); + continue; + } + txtchar.style = style; + txtchar.code = *p; + pd_char_update_bitmap(&txtchar, &text->default_style); + pd_text_line_insert_copy(line, ins_x, &txtchar); + ++text->length; + ++ins_x; + } + /* 更新当前行的尺寸 */ + pd_text_update_line_size(text, line); + text->width = y_max(text->width, line->width); + if (action == PD_TEXT_ACTION_INSERT) { + text->caret.x = ins_x; + text->caret.y = ins_y; + } + /* 若启用了自动换行模式,则标记需要重新对文本进行排版 */ + if (text->autowrap_enabled || need_typeset) { + pd_text_request_typeset(text, cur_line); + } else { + pd_text_mark_line_dirty(text, cur_line, 0, -1); + } + /* 如果已经记录过文本行矩形区域 */ + if (rect_has_added) { + pd_text_mark_dirty(text, start_line, -1); + rect_has_added = true; + } + pd_style_tags_clear(&tmp_tags); + return 0; +} + +int pd_text_insert(pd_text_t *text, const wchar_t *wstr, list_t *tags) +{ + return pd_text_process(text, wstr, PD_TEXT_ACTION_INSERT, tags); +} + +int pd_text_append(pd_text_t *text, const wchar_t *wstr, list_t *tag_stack) +{ + return pd_text_process(text, wstr, PD_TEXT_ACTION_APPEND, tag_stack); +} + +int pd_text_write(pd_text_t *text, const wchar_t *wstr, list_t *tag_stack) +{ + pd_text_clear(text); + return pd_text_append(text, wstr, tag_stack); +} + +size_t pd_text_read(pd_text_t *text, size_t start_pos, size_t max_len, + wchar_t *wstr_buff) +{ + size_t i, line_num, col; + pd_text_line_t *line; + + if (max_len == 0) { + wstr_buff[0] = 0; + return 0; + } + /* 先根据一维坐标计算行列坐标 */ + for (i = 0, line_num = 0, col = 0; line_num < text->lines_length; + ++line_num) { + if (i >= start_pos) { + col = start_pos - i; + break; + } + i += text->lines[line_num]->length; + } + for (i = 0; line_num < text->lines_length && i < max_len; ++line_num) { + line = text->lines[line_num]; + for (; col < line->length && i < max_len; ++col, ++i) { + wstr_buff[i] = line->string[col]->code; + } + /* 进入下一行前,按行尾符还原对应的换行字符 */ + if (i >= max_len) { + break; + } + switch (line->eol) { + case PD_TEXT_EOL_CR: + wstr_buff[i++] = L'\r'; + break; + case PD_TEXT_EOL_LF: + wstr_buff[i++] = L'\n'; + break; + case PD_TEXT_EOL_CR_LF: + wstr_buff[i++] = L'\r'; + if (i >= max_len) { + break; + } + wstr_buff[i++] = L'\n'; + break; + case PD_TEXT_EOL_NONE: + default: + break; + } + /* 切换到下一行时必须重置列号 */ + col = 0; + } + wstr_buff[i] = 0; + return i; +} + +wchar_t *pd_text_to_wcs(pd_text_t *text) +{ + size_t total = 0; + int line_num; + pd_text_line_t *line; + wchar_t *buf; + + for (line_num = 0; line_num < text->lines_length; ++line_num) { + line = text->lines[line_num]; + total += (size_t)line->length; + switch (line->eol) { + case PD_TEXT_EOL_CR: + case PD_TEXT_EOL_LF: + total += 1; + break; + case PD_TEXT_EOL_CR_LF: + total += 2; + break; + default: + break; + } + } + buf = malloc(sizeof(wchar_t) * (total + 1)); + if (!buf) { + return NULL; + } + pd_text_read(text, 0, total, buf); + buf[total] = 0; + return buf; +} + +/** 删除指定行列的文字及其右边的文本 */ +static int pd_text_delete_ex(pd_text_t *text, int char_y, int char_x, + int n_char) +{ + int end_x, end_y, i, j, len; + pd_text_line_t *line, *end_line, *prev_line; + + if (char_x < 0) { + char_x = 0; + } + if (char_y < 0) { + char_y = 0; + } + if (n_char <= 0) { + return -1; + } + if (char_y >= text->lines_length) { + return -2; + } + line = text->lines[char_y]; + if (char_x > line->length) { + char_x = line->length; + } + i = n_char; + end_x = char_x; + end_y = char_y; + /* 计算结束点的位置 */ + for (; end_y < text->lines_length && n_char > 0; ++end_y) { + line = text->lines[end_y]; + if (end_x + n_char <= line->length) { + end_x += n_char; + n_char = 0; + break; + } + n_char -= (line->length - end_x); + if (line->eol == PD_TEXT_EOL_NONE) { + end_x = 0; + } else { + n_char -= 1; + end_x = 0; + } + } + if (n_char >= 0) { + text->length -= i - n_char; + } else { + text->length -= n_char; + } + if (end_y >= text->lines_length) { + end_y = text->lines_length - 1; + end_line = text->lines[end_y]; + end_x = end_line->length; + } else { + end_line = text->lines[end_y]; + } + if (end_x > end_line->length) { + end_x = end_line->length; + } + if (end_x == char_x && end_y == char_y) { + return 0; + } + /* 获取上一行文本(首行时无上一行) */ + prev_line = char_y > 0 ? text->lines[char_y - 1] : NULL; + // 计算起始行与结束行拼接后的长度 + // 起始行:0 1 2 3 4 5,起点位置:2 + // 结束行:0 1 2 3 4 5,终点位置:4 + // 拼接后的长度:2 + 6 - 4 = 4 + len = char_x + end_line->length - end_x; + if (len < 0) { + return -3; + } + /* 如果是同一行 */ + if (line == end_line) { + if (end_x > end_line->length) { + return -4; + } + pd_text_mark_line_dirty(text, char_y, char_x, -1); + pd_text_request_typeset(text, char_y); + /* 释放被删除范围内的字符 */ + pd_text_line_erase(line, char_x, end_x); + /* 将结束点之后的内容向前搬移 */ + pd_text_line_move(line, char_x, line, end_x, line->length); + /* 如果当前行为空,也不是第一行,并且上一行没有结束符, + * 则直接移除当前行,不能再访问 line */ + if (len <= 0 && char_y > 0 && prev_line && + prev_line->eol != PD_TEXT_EOL_NONE) { + pd_text_delete_line(text, char_y); + return 0; + } + /* 调整起始行的容量 */ + pd_text_line_set_length(line, len); + /* 更新文本行的尺寸 */ + pd_text_update_line_size(text, line); + return 0; + } + /* 释放起始行中被删除的字符(区间为 [char_x, line->length)) */ + pd_text_line_erase(line, char_x, line->length); + /* 释放结束行中被删除的字符(区间为 [0, end_x)) */ + pd_text_line_erase(end_line, 0, end_x); + /* 如果结束点在行尾,并且该行不是最后一行, + * 则将结束点推进到下一行的行首 */ + if (end_x == end_line->length && end_y < text->lines_length - 1) { + ++end_y; + end_line = pd_text_get_line(text, end_y); + end_x = 0; + len = char_x + end_line->length; + } + pd_text_line_set_length(line, len); + /* 标记当前行后面的所有行的矩形需区域需要刷新 */ + pd_text_mark_dirty(text, char_y + 1, -1); + /* 移除起始行与结束行之间的文本行 */ + for (i = char_y + 1, j = i; j < end_y; ++j) { + pd_text_mark_line_dirty(text, i, 0, -1); + pd_text_delete_line(text, i); + } + end_y = char_y + 1; + /* 将结束行的内容拼接至起始行(所有权随之转移) */ + pd_text_line_move(line, char_x, end_line, end_x, end_line->length); + pd_text_update_line_size(text, line); + pd_text_mark_line_dirty(text, end_y, 0, -1); + /* 移除结束行 */ + pd_text_delete_line(text, end_y); + /* 如果起始行无内容,并且上一行没有结束符(换行符),则 + * 说明需要删除起始行 */ + if (len <= 0 && char_y > 0 && prev_line && + prev_line->eol != PD_TEXT_EOL_NONE) { + pd_text_mark_line_dirty(text, char_y, 0, -1); + pd_text_delete_line(text, char_y); + } + pd_text_request_typeset(text, char_y); + return 0; +} + +/** 删除文本光标的当前坐标右边的文本 */ +int pd_text_delete(pd_text_t *text, int n_char) +{ + return pd_text_delete_ex(text, text->caret.y, text->caret.x, n_char); +} + +/** 退格删除文本,即删除文本光标的当前坐标左边的文本 */ +int pd_text_backspace(pd_text_t *text, int n_char) +{ + int n_del; + int char_x, char_y; + pd_text_line_t *line; + + /* 先获取当前字的位置 */ + char_x = text->caret.x; + char_y = text->caret.y; + /* 再计算删除 n_char 个字后的位置 */ + for (n_del = n_char; char_y >= 0; --char_y) { + line = text->lines[char_y]; + /* 如果不是当前行,则重定位至行尾 */ + if (char_y < text->caret.y) { + char_x = line->length; + if (line->eol == PD_TEXT_EOL_NONE) { + --char_x; + } + } + if (char_x >= n_del) { + char_x = char_x - n_del; + n_del = 0; + break; + } + n_del = n_del - char_x - 1; + } + if (char_y < 0 || n_del == n_char) { + return -1; + } + /* 若能够被删除的字不够 n_char 个,则调整需删除的字数 */ + if (n_del > 0) { + n_char -= n_del; + } + /* 开始删除文本 */ + pd_text_delete_ex(text, char_y, char_x, n_char); + /* 若最后一行被完全移除,则移动输入点至上一行的行尾处 */ + if (char_x == 0 && text->lines_length > 0 && + char_y >= text->lines_length) { + char_y = text->lines_length - 1; + char_x = text->lines[char_y]->length; + } + /* 更新文本光标的位置 */ + pd_text_set_caret(text, char_y, char_x); + return 0; +} + +/** 设置是否使用样式标签 */ +void pd_text_set_style_tag(pd_text_t *text, bool enabled) +{ + text->style_tag_enabled = enabled; +} diff --git a/lib/pandagl/src/text/text_internal.h b/lib/pandagl/src/text/text_internal.h new file mode 100644 index 000000000..e02c0eb21 --- /dev/null +++ b/lib/pandagl/src/text/text_internal.h @@ -0,0 +1,54 @@ +/* + * lib/pandagl/src/text/text_internal.h + * + * Copyright (c) 2018-2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + * + * Library-private helpers shared between text.c, text_typeset.c, + * text_render.c and text_edit.c. Not installed into the public include + * directory. + */ + +#ifndef LIB_PANDAGL_SRC_TEXT_TEXT_INTERNAL_H +#define LIB_PANDAGL_SRC_TEXT_TEXT_INTERNAL_H + +#include + +/* line storage */ +pd_text_line_t *pd_text_get_line(pd_text_t *text, int line_num); +pd_text_line_t *pd_text_insert_line(pd_text_t *text, size_t line_num); +pd_text_line_t *pd_text_append_line(pd_text_t *text); +int pd_text_delete_line(pd_text_t *text, int line_num); + +/* line-level helpers */ +int pd_text_line_set_length(pd_text_line_t *line, int len); +int pd_text_line_insert(pd_text_line_t *line, int offset, + pd_char_t *txtchar); +int pd_text_line_insert_copy(pd_text_line_t *line, int ins_pos, + pd_char_t *txtchar); +void pd_text_line_erase(pd_text_line_t *line, int start, int end); +void pd_text_line_move(pd_text_line_t *dst, int dst_start, + pd_text_line_t *src, int src_start, int src_end); + +/* line geometry */ +void pd_text_update_line_size(pd_text_t *text, pd_text_line_t *line); +int pd_text_get_line_start_x(pd_text_t *text, pd_text_line_t *line); +int pd_text_get_line_rect(pd_text_t *text, int line_num, int start_col, + int end_col, pd_rect_t *rect); +void pd_text_mark_line_dirty(pd_text_t *text, int line_num, int start, + int end); + +/* render helpers */ +void pd_char_update_bitmap(pd_char_t *ch, pd_text_style_t *style); +void pd_text_update_style_cache(pd_text_t *text); + +/* typeset entry called by core/edit */ +void pd_text_typeset(pd_text_t *text, int start_line); +void pd_text_break_line(pd_text_t *text, int line_num, int col, + pd_text_eol_t eol); + +#endif diff --git a/lib/pandagl/src/text/text_render.c b/lib/pandagl/src/text/text_render.c new file mode 100644 index 000000000..619eae5d1 --- /dev/null +++ b/lib/pandagl/src/text/text_render.c @@ -0,0 +1,176 @@ +/* + * lib/pandagl/src/text/text_render.c + * + * Copyright (c) 2018-2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include "text_internal.h" + +void pd_char_update_bitmap(pd_char_t *ch, pd_text_style_t *style) +{ + int i = 0; + int size = style->pixel_size; + int *font_ids = style->font_ids; + + if (ch->style) { + if (ch->style->has_family) { + font_ids = ch->style->font_ids; + } + if (ch->style->has_pixel_size) { + size = ch->style->pixel_size; + } + } + while (font_ids && font_ids[i] > 0) { + int ret = pd_font_cache_get_bitmap(ch->code, font_ids[i], + size, &ch->bitmap); + if (ret == 0) { + return; + } + ++i; + } + pd_font_cache_get_bitmap(ch->code, -1, size, &ch->bitmap); +} + +void pd_text_update_style_cache(pd_text_t *text) +{ + list_node_t *node; + if (!text->default_style.has_family) { + pd_text_style_set_default_font(&text->default_style); + } + /* 替换缺省字体,确保能够正确应用字体设置 */ + for (list_each(node, &text->styles)) { + pd_text_style_merge(node->data, &text->default_style); + } +} + +/** 重新载入各个文字的字体位图 */ +void pd_text_reload_bitmap(pd_text_t *text) +{ + int line_num, col; + pd_text_update_style_cache(text); + for (line_num = 0; line_num < text->lines_length; ++line_num) { + pd_text_line_t *line = text->lines[line_num]; + for (col = 0; col < line->length; ++col) { + pd_char_t *txtchar = line->string[col]; + pd_char_update_bitmap(txtchar, &text->default_style); + } + pd_text_update_line_size(text, line); + } +} + +static void pd_text_validate_rect(pd_text_t *text, pd_rect_t *area) +{ + int width, height; + + if (text->fixed_width > 0) { + width = text->fixed_width; + } else if (text->max_width > 0) { + width = text->max_width; + } else { + width = text->width; + } + if (text->fixed_height > 0) { + height = text->fixed_height; + } else { + height = pd_text_get_height(text); + } + pd_rect_correct(area, width, height); +} + +static void pd_text_render_char(pd_text_t *text, pd_char_t *ch, + pd_canvas_t *graph, pd_pos_t ch_pos) +{ + /* 判断文字使用的前景颜色,再进行绘制 */ + if (ch->style && ch->style->has_fore_color) { + pd_canvas_mix_glyph_bitmap(graph, ch_pos, ch->bitmap, + ch->style->fore_color); + } else { + pd_canvas_mix_glyph_bitmap(graph, ch_pos, ch->bitmap, + text->default_style.fore_color); + } +} + +static void pd_text_render_line(pd_text_t *text, pd_rect_t *area, + pd_canvas_t *graph, pd_pos_t layer_pos, + pd_text_line_t *line, int y) +{ + pd_char_t *ch; + pd_pos_t pen; + int col, x; + + x = pd_text_get_line_start_x(text, line) + text->offset_x; + for (col = 0; col < line->length && x < area->x + area->width; ++col) { + ch = line->string[col]; + if (!ch->bitmap) { + continue; + } + if (x + ch->bitmap->metrics.hori_advance < area->x) { + x += ch->bitmap->metrics.hori_advance; + continue; + } + pen.x = layer_pos.x + x; + pen.y = layer_pos.y + y; + if (ch->style && ch->style->has_back_color) { + pd_rect_t rect; + rect.x = pen.x; + rect.y = pen.y; + rect.height = line->height; + rect.width = ch->bitmap->metrics.hori_advance; + pd_canvas_fill_rect(graph, ch->style->back_color, rect); + } + pen.x += ch->bitmap->left; + pen.y += (line->height - ch->bitmap->metrics.bbox_height) / 2 + + ch->bitmap->metrics.ascender - ch->bitmap->top; + pd_text_render_char(text, ch, graph, pen); + x += ch->bitmap->metrics.hori_advance; + } +} + +int pd_text_render_to(pd_text_t *text, pd_rect_t area, pd_pos_t layer_pos, + pd_canvas_t *canvas) +{ + int y; + int line_num; + pd_text_line_t *line; + + y = text->offset_y; + /* 确定可绘制的最大区域范围 */ + pd_text_validate_rect(text, &area); + for (line_num = 0; line_num < text->lines_length; ++line_num) { + line = pd_text_get_line(text, line_num); + y += line->height; + if (y > area.y) { + y -= line->height; + break; + } + } + /* 如果没有可绘制的文本行 */ + if (line_num >= text->lines_length) { + return -1; + } + for (; line_num < text->lines_length; ++line_num) { + line = pd_text_get_line(text, line_num); + pd_text_render_line(text, &area, canvas, layer_pos, line, y); + y += line->height; + /* 超出绘制区域范围就不绘制了 */ + if (y > area.y + area.height) { + break; + } + } + return 0; +} + +/** 设置全局文本样式 */ +void pd_text_set_style(pd_text_t *text, pd_text_style_t *style) +{ + pd_text_style_destroy(&text->default_style); + pd_text_style_copy(&text->default_style, style); + text->task.update_bitmap = true; +} diff --git a/lib/pandagl/src/text/text_typeset.c b/lib/pandagl/src/text/text_typeset.c new file mode 100644 index 000000000..038915b66 --- /dev/null +++ b/lib/pandagl/src/text/text_typeset.c @@ -0,0 +1,162 @@ +/* + * lib/pandagl/src/text/text_typeset.c + * + * Copyright (c) 2018-2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include "text_internal.h" + +#define isalpha_(ch) ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) + +void pd_text_break_line(pd_text_t *text, int line_num, int col, + pd_text_eol_t eol) +{ + int n; + pd_text_line_t *line, *next; + + line = pd_text_get_line(text, line_num); + next = pd_text_insert_line(text, line_num + 1); + /* 将本行原有的行尾符转移至下一行 */ + next->eol = line->eol; + line->eol = eol; + for (n = line->length - 1; n >= col; --n) { + pd_text_line_insert(next, 0, line->string[n]); + line->string[n] = NULL; + } + line->length = col; + pd_text_update_line_size(text, line); + pd_text_update_line_size(text, next); +} + +static void pd_text_merge_line(pd_text_t *text, int line_num) +{ + int old_len; + pd_text_line_t *line = pd_text_get_line(text, line_num); + pd_text_line_t *next = pd_text_get_line(text, line_num + 1); + + if (!line || !next) { + return; + } + if (text->caret.y > line_num) { + --text->caret.y; + if (text->caret.y == line_num) { + text->caret.x += line->length; + } + } + old_len = line->length; + pd_text_line_set_length(line, line->length + next->length); + pd_text_line_move(line, old_len, next, 0, next->length); + line->eol = next->eol; + pd_text_update_line_size(text, line); + pd_text_delete_line(text, line_num + 1); +} + +static void pd_text_typeset_line(pd_text_t *text, int line_num) +{ + int col, line_width = 0, word_col = 0; + int max_width = + text->fixed_width > 0 ? text->fixed_width : text->max_width; + + pd_char_t *txtchar; + pd_text_line_t *line = text->lines[line_num]; + bool autowrap = + max_width > 0 && text->autowrap_enabled && text->multiline_enabled; + + for (col = 0; col < line->length; ++col) { + txtchar = line->string[col]; + if (!txtchar->bitmap) { + continue; + } + /* 累加行宽度 */ + line_width += txtchar->bitmap->metrics.hori_advance; + /* 如果是当前行的第一个字符,或者行宽度没有超过宽度限制 */ + if (!autowrap || col < 1 || line_width <= max_width) { + if (isalpha_(txtchar->code)) { + } else { + word_col = col + 1; + } + continue; + } + if (text->word_break == PD_WORD_BREAK_NORMAL) { + if (word_col < 1) { + continue; + } + col = word_col; + } + pd_text_break_line(text, line_num, col, PD_TEXT_EOL_NONE); + return; + } + pd_text_update_line_size(text, line); + /* 如果本行有换行符,或者是最后一行 */ + if (line->eol != PD_TEXT_EOL_NONE || + line_num == text->lines_length - 1) { + return; + } + line_width = line->width; + /* 本行的文本宽度未达到限制宽度,需要将下行的文本转移至本行 */ + if (line->eol == PD_TEXT_EOL_NONE) { + pd_text_mark_line_dirty(text, line_num, 0, -1); + pd_text_mark_line_dirty(text, line_num + 1, 0, -1); + pd_text_merge_line(text, line_num); + pd_text_typeset_line(text, line_num); + } +} + +/** 从指定行开始,对文本进行排版 */ +void pd_text_typeset(pd_text_t *text, int start_line) +{ + int line_num; + /* 记录排版前各个文本行的矩形区域 */ + pd_text_mark_dirty(text, start_line, -1); + for (line_num = start_line; line_num < text->lines_length; ++line_num) { + pd_text_typeset_line(text, line_num); + } + /* 记录排版后各个文本行的矩形区域 */ + pd_text_mark_dirty(text, start_line, -1); +} + +/** 设置是否启用多行文本模式 */ +void pd_text_set_multiline(pd_text_t *text, bool enabled) +{ + if (text->multiline_enabled != enabled) { + text->multiline_enabled = enabled; + pd_text_request_typeset(text, 0); + } +} + +void pd_text_set_autowrap(pd_text_t *text, bool autowrap) +{ + if (text->autowrap_enabled != autowrap) { + text->autowrap_enabled = autowrap; + pd_text_request_typeset(text, 0); + } +} + +void pd_text_set_word_break(pd_text_t *text, pd_word_break_t word_break) +{ + if (text->word_break != word_break) { + text->word_break = word_break; + pd_text_request_typeset(text, 0); + } +} + +void pd_text_set_align(pd_text_t *text, int align) +{ + text->text_align = align; + text->task.update_typeset = true; + text->task.typeset_start_line = 0; +} + +void pd_text_set_line_height(pd_text_t *text, int height) +{ + text->line_height = height; + text->task.update_typeset = true; + text->task.typeset_start_line = 0; +} diff --git a/lib/pandagl/tests/test_text_edit.c b/lib/pandagl/tests/test_text_edit.c index 069214ce7..d3b6f8161 100644 --- a/lib/pandagl/tests/test_text_edit.c +++ b/lib/pandagl/tests/test_text_edit.c @@ -16,7 +16,7 @@ /* * 这些用例覆盖 pd_text_delete_ex 的关键分支,包括同行删除、跨行合并、 - * 以及边界场景。由于 pd_text_dump 在多行场景下存在已知问题(不在本次 + * 以及边界场景。由于 pd_text_read 在多行场景下存在已知问题(不在本次 * 修复范围),这里通过断言每行长度来验证缓冲区状态。 */ @@ -28,7 +28,7 @@ static void should_backspace_last_char_on_last_line(void) pd_text_write(text, L"123\n123\n123\n", NULL); /* 光标置于末尾的空行,按退格删除前一行的换行符, * 此时空行被丢弃 */ - pd_text_set_insert_position(text, 3, 0); + pd_text_set_caret(text, 3, 0); ctest_equal_int("should not crash on backspace last char", pd_text_backspace(text, 1), 0); ctest_equal_int("should drop the trailing empty line", @@ -48,7 +48,7 @@ static void should_backspace_then_continue_typing(void) pd_text_set_multiline(text, true); pd_text_write(text, L"abc\ndef\n", NULL); - pd_text_set_insert_position(text, 2, 0); + pd_text_set_caret(text, 2, 0); pd_text_backspace(text, 1); pd_text_insert(text, L"X", NULL); ctest_equal_int("should merge into two lines after backspace + insert", @@ -66,7 +66,7 @@ static void should_not_crash_on_backspace_at_start(void) pd_text_set_multiline(text, true); pd_text_write(text, L"abc", NULL); - pd_text_set_insert_position(text, 0, 0); + pd_text_set_caret(text, 0, 0); ctest_equal_int("should return error at buffer start", pd_text_backspace(text, 1), -1); ctest_equal_int("should keep one line", pd_text_get_lines_length(text), @@ -83,9 +83,9 @@ static void should_delete_char_at_caret(void) pd_text_set_multiline(text, true); pd_text_write(text, L"abcdef", NULL); - pd_text_set_insert_position(text, 0, 2); + pd_text_set_caret(text, 0, 2); ctest_equal_int("should delete one char", pd_text_delete(text, 1), 0); - pd_text_dump(text, 0, 16, buf); + pd_text_read(text, 0, 16, buf); ctest_equal_wcs("should produce expected text", buf, L"abdef"); ctest_equal_int("line length is 5", pd_text_get_line_length(text, 0), 5); @@ -100,7 +100,7 @@ static void should_join_next_line_when_delete_at_line_end(void) pd_text_write(text, L"abc\ndef\nghi", NULL); /* 在第二行最后一个字符处使用 delete,触发跨行拼接, * 之前 +1 偏移 bug 会导致 'd' 字符丢失 */ - pd_text_set_insert_position(text, 1, 3); + pd_text_set_caret(text, 1, 3); ctest_equal_int("should not crash when delete at line end", pd_text_delete(text, 1), 0); ctest_equal_int("should reduce one line after merge", @@ -119,7 +119,7 @@ static void should_preserve_chars_when_joining_lines(void) pd_text_set_multiline(text, true); pd_text_write(text, L"abc\ndef\n", NULL); /* 在第一行末尾处用 delete 删除换行符 */ - pd_text_set_insert_position(text, 0, 3); + pd_text_set_caret(text, 0, 3); pd_text_delete(text, 1); ctest_equal_int("should reduce to two lines", pd_text_get_lines_length(text), 2); @@ -136,7 +136,7 @@ static void should_handle_multi_line_backspace_sequence(void) pd_text_set_multiline(text, true); pd_text_write(text, L"123\n123\n123\n", NULL); - pd_text_set_insert_position(text, 3, 0); + pd_text_set_caret(text, 3, 0); /* 连续 backspace,模拟用户按住退格。每次删一格: * 1) 删第 4 行(空行) -> 3 行 * 2) 删第 3 行的 '3' -> 2.x(剩 '12') @@ -162,7 +162,7 @@ static void should_dump_single_line(void) pd_text_write(text, L"hello", NULL); ctest_equal_uint("should return char count", - (unsigned)pd_text_dump(text, 0, 32, buf), 5u); + (unsigned)pd_text_read(text, 0, 32, buf), 5u); ctest_equal_wcs("should produce same single-line text", buf, L"hello"); pd_text_destroy(text); } @@ -174,7 +174,7 @@ static void should_dump_multiline_with_lf(void) pd_text_set_multiline(text, true); pd_text_write(text, L"abc\ndef\nghi", NULL); - pd_text_dump(text, 0, 32, buf); + pd_text_read(text, 0, 32, buf); ctest_equal_wcs("should preserve LF line endings", buf, L"abc\ndef\nghi"); pd_text_destroy(text); @@ -187,7 +187,7 @@ static void should_dump_multiline_with_trailing_newline(void) pd_text_set_multiline(text, true); pd_text_write(text, L"a\nb\n", NULL); - pd_text_dump(text, 0, 32, buf); + pd_text_read(text, 0, 32, buf); ctest_equal_wcs("should preserve trailing newline", buf, L"a\nb\n"); pd_text_destroy(text); } @@ -201,12 +201,43 @@ static void should_dump_respect_max_len(void) pd_text_write(text, L"abc\ndef\nghi", NULL); /* 只允许写 4 个 wchar,第 5 位是终止符 */ ctest_equal_uint("should stop at max_len", - (unsigned)pd_text_dump(text, 0, 4, buf), 4u); + (unsigned)pd_text_read(text, 0, 4, buf), 4u); ctest_equal_wcs("should truncate without crossing buffer", buf, L"abc\n"); pd_text_destroy(text); } +static void should_to_wcs_return_full_text(void) +{ + pd_text_t *text = pd_text_create(); + wchar_t *buf; + + pd_text_set_multiline(text, true); + pd_text_write(text, L"hello\nworld\n", NULL); + buf = pd_text_to_wcs(text); + ctest_equal_bool("should not return NULL", buf != NULL, true); + if (buf) { + ctest_equal_wcs("should match original including trailing LF", + buf, L"hello\nworld\n"); + free(buf); + } + pd_text_destroy(text); +} + +static void should_to_wcs_handle_empty_text(void) +{ + pd_text_t *text = pd_text_create(); + wchar_t *buf = pd_text_to_wcs(text); + + ctest_equal_bool("should not return NULL on empty text", buf != NULL, + true); + if (buf) { + ctest_equal_wcs("should produce empty wide string", buf, L""); + free(buf); + } + pd_text_destroy(text); +} + void test_pandagl_text_edit(void) { pd_font_library_init(); @@ -229,5 +260,7 @@ void test_pandagl_text_edit(void) ctest_describe("text dump trailing newline", should_dump_multiline_with_trailing_newline); ctest_describe("text dump max len", should_dump_respect_max_len); + ctest_describe("text to_wcs full text", should_to_wcs_return_full_text); + ctest_describe("text to_wcs empty", should_to_wcs_handle_empty_text); pd_font_library_destroy(); } diff --git a/src/widgets/text.c b/src/widgets/text.c index e5504b58c..202e7f3dd 100644 --- a/src/widgets/text.c +++ b/src/widgets/text.c @@ -61,7 +61,7 @@ static void ui_text_on_parse_attr(ui_widget_t *w, const char *name, } if (strcmp(name, "multiline") == 0) { bool enable = parse_boolean(value); - if (enable != txt->layer->mulitiline_enabled) { + if (enable != txt->layer->multiline_enabled) { ui_text_set_multiline(w, enable); } } diff --git a/src/widgets/textinput.c b/src/widgets/textinput.c index e592388a2..9595840f0 100644 --- a/src/widgets/textinput.c +++ b/src/widgets/textinput.c @@ -104,7 +104,7 @@ static void ui_textinput_update_caret(ui_widget_t *widget) { ui_textinput_t *edit = ui_widget_get_data(widget, ui_textinput_proto); - int row = edit->layer->insert_y; + int row = edit->layer->caret.y; int offset_x, offset_y; float height, width; float scale = ui_get_actual_scale(); @@ -112,7 +112,7 @@ static void ui_textinput_update_caret(ui_widget_t *widget) if (!edit->placeholder_visible) { pd_pos_t pos; - if (pd_text_get_insert_pixel_position(edit->layer, &pos) != 0) { + if (pd_text_get_caret_pixel(edit->layer, &pos) != 0) { return; } caret_x = pos.x / scale; @@ -158,9 +158,9 @@ static void ui_textinput_update_caret(ui_widget_t *widget) ui_widget_move(edit->caret, x, y); ui_textcaret_refresh(edit->caret); if (edit->password_char) { - pd_text_set_insert_position(edit->layer_source, - edit->layer->insert_y, - edit->layer->insert_x); + pd_text_set_caret(edit->layer_source, + edit->layer->caret.y, + edit->layer->caret.x); } } @@ -170,7 +170,7 @@ void ui_textinput_move_caret(ui_widget_t *widget, int row, int col) if (edit->placeholder_visible) { row = col = 0; } - pd_text_set_insert_position(edit->layer, row, col); + pd_text_set_caret(edit->layer, row, col); ui_textinput_update_caret(widget); } @@ -459,7 +459,7 @@ void ui_textinput_clear_text(ui_widget_t *widget) node = prev; } } - pd_text_empty(edit->layer_source); + pd_text_clear(edit->layer_source); pd_style_tags_clear(&edit->text_tags); edit->tasks[TASK_UPDATE] = true; ui_widget_request_update(widget); @@ -471,7 +471,7 @@ size_t ui_textinput_get_text_w(ui_widget_t *w, size_t start, size_t max_len, wchar_t *buf) { ui_textinput_t *edit = ui_widget_get_data(w, ui_textinput_proto); - return pd_text_dump(edit->layer_source, start, max_len, buf); + return pd_text_read(edit->layer_source, start, max_len, buf); } size_t ui_textinput_get_text_length(ui_widget_t *w) @@ -512,7 +512,7 @@ void ui_textinput_set_password_char(ui_widget_t *w, wchar_t ch) edit->password_char = ch; edit->tasks[TASK_UPDATE] = true; ui_widget_request_update(w); - pd_text_empty(edit->layer_mask); + pd_text_clear(edit->layer_mask); if (!edit->password_char) { edit->layer = edit->layer_source; return; @@ -542,7 +542,7 @@ int ui_textinput_set_placeholder_w(ui_widget_t *w, const wchar_t *wstr) { ui_textinput_t *edit = ui_widget_get_data(w, ui_textinput_proto); thread_mutex_lock(&edit->mutex); - pd_text_empty(edit->layer_placeholder); + pd_text_clear(edit->layer_placeholder); thread_mutex_unlock(&edit->mutex); if (edit->placeholder_visible) { ui_widget_mark_dirty_rect(w, NULL, UI_BOX_TYPE_PADDING_BOX); @@ -665,8 +665,8 @@ static void ui_textinput_on_keydown(ui_widget_t *widget, ui_event_t *e, int cur_col, cur_row; ui_textinput_t *edit = ui_widget_get_data(widget, ui_textinput_proto); - cur_row = edit->layer->insert_y; - cur_col = edit->layer->insert_x; + cur_row = edit->layer->caret.y; + cur_col = edit->layer->caret.x; rows = pd_text_get_lines_length(edit->layer); cols = pd_text_get_line_length(edit->layer, cur_row); e->cancel_bubble = true; @@ -796,7 +796,7 @@ static void ui_textinput_on_mousemove(ui_widget_t *w, ui_event_t *e, void *arg) return; } ui_widget_get_offset(w, NULL, &offset_x, &offset_y); - pd_text_set_insert_pixel_position( + pd_text_set_caret_pixel( edit->layer, ui_compute(e->mouse.x - offset_x - w->computed_style.padding_left), ui_compute(e->mouse.y - offset_y - w->computed_style.padding_top)); @@ -815,7 +815,7 @@ static void ui_textinput_on_mousedown(ui_widget_t *w, ui_event_t *e, void *arg) ui_textinput_t *edit = ui_widget_get_data(w, ui_textinput_proto); ui_widget_get_offset(w, NULL, &offset_x, &offset_y); - pd_text_set_insert_pixel_position( + pd_text_set_caret_pixel( edit->layer, ui_compute(e->mouse.x - offset_x - w->computed_style.padding_left), ui_compute(e->mouse.y - offset_y - w->computed_style.padding_top)); From eb275e34a076a93d9f5c6f424c6b9d2a1b41fb34 Mon Sep 17 00:00:00 2001 From: Liu Date: Wed, 27 May 2026 22:12:09 +0800 Subject: [PATCH 18/66] ci: add pre-commit formatting via lint-staged and clang-format --- .github/CONTRIBUTING.md | 7 +- .github/workflows/ccpp.yml | 18 + .husky/pre-commit | 2 + package-lock.json | 787 ++++++++++++++++++++++++++++++++ package.json | 12 +- scripts/clang-format-changed.js | 60 +++ 6 files changed, 882 insertions(+), 4 deletions(-) create mode 100644 .husky/pre-commit create mode 100644 package-lock.json create mode 100644 scripts/clang-format-changed.js diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 3e7c08295..8bfd53716 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -74,9 +74,10 @@ To ensure consistency throughout the source code, keep these rules in mind as yo - All features or bug fixes **must be tested** by one or more specs (unit-tests). - All public API methods **must be documented**. (Details TBC). -- Follow the existing code style. You have the following two ways to format the code: - - Use [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to format the changed files: `clang-format --style=file [src/????.c]`. - - Install the [NodeJS](https://nodejs.org/en/) Environment and run `npm install`, which will add a git hook to format the changed code, and it will run before you run `git commit`. +- Follow the existing code style. The project uses [clang-format](http://clang.llvm.org/docs/ClangFormat.html) with the rules defined in `.clang-format`. You have two options: + - Run `clang-format -i path/to/file.c` manually on the files you changed. + - Install [Node.js](https://nodejs.org/) and run `npm install` once. This installs [husky](https://typicode.github.io/husky/) + [lint-staged](https://github.com/lint-staged/lint-staged), which formats every staged `.c` / `.h` file with clang-format on `git commit` automatically. + - CI checks formatting of only the files changed in each PR, so pre-existing style deviations won't block you. ## Commit Message Guidelines diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index e6437ab4f..e0a2aabcb 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -1,6 +1,24 @@ name: C/C++ CI on: [push, pull_request] jobs: + format: + name: Check C/C++ formatting + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install clang-format + run: | + sudo apt-get update --fix-missing + sudo apt-get install -y clang-format + + - name: Check formatting of changed files + run: | + node scripts/clang-format-changed.js origin/${{ github.base_ref || 'develop' }} + build: env: TARGET_MAJOR: 3 diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 000000000..f841cf21a --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +npx lint-staged diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..b465a90d7 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,787 @@ +{ + "name": "lcui", + "version": "3.0.0-alpha.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "lcui", + "version": "3.0.0-alpha.0", + "license": "MIT", + "devDependencies": { + "husky": "^9.1.7", + "lint-staged": "^15.2.10" + } + }, + "node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmmirror.com/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmmirror.com/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmmirror.com/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmmirror.com/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmmirror.com/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lint-staged": { + "version": "15.5.2", + "resolved": "https://registry.npmmirror.com/lint-staged/-/lint-staged-15.5.2.tgz", + "integrity": "sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.4.1", + "commander": "^13.1.0", + "debug": "^4.4.0", + "execa": "^8.0.1", + "lilconfig": "^3.1.3", + "listr2": "^8.2.5", + "micromatch": "^4.0.8", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.7.0" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/listr2": { + "version": "8.3.3", + "resolved": "https://registry.npmmirror.com/listr2/-/listr2-8.3.3.tgz", + "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmmirror.com/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + } + } +} diff --git a/package.json b/package.json index fc12043eb..735d8f460 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,17 @@ "scripts": { "build-changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0", "update-changelog": "conventional-changelog -p angular -i CHANGELOG.md -s", - "update-copyright": "node scripts/add-copyright.js" + "update-copyright": "node scripts/add-copyright.js", + "prepare": "husky" + }, + "lint-staged": { + "**/*.{c,h}": [ + "clang-format -i" + ] + }, + "devDependencies": { + "husky": "^9.1.7", + "lint-staged": "^15.2.10" }, "repository": { "type": "git", diff --git a/scripts/clang-format-changed.js b/scripts/clang-format-changed.js new file mode 100644 index 000000000..4aa554e31 --- /dev/null +++ b/scripts/clang-format-changed.js @@ -0,0 +1,60 @@ +#!/usr/bin/env node +/* + * scripts/clang-format-changed.js + * + * Run clang-format --dry-run --Werror on .c / .h files that differ from + * a base ref. Designed for CI: it only inspects files actually touched by + * the current PR / push, leaving pre-existing formatting issues alone. + * + * Usage: + * node scripts/clang-format-changed.js [base-ref] + * + * Defaults to "origin/develop" if no base ref is given. + */ + +const { execFileSync, spawnSync } = require("node:child_process"); + +const baseRef = process.argv[2] || "origin/develop"; + +let files; +try { + const out = execFileSync( + "git", + ["diff", "--name-only", "--diff-filter=ACMR", `${baseRef}...HEAD`], + { encoding: "utf8" } + ); + files = out + .split(/\r?\n/) + .filter((f) => /\.(c|h)$/i.test(f)) + .filter(Boolean); +} catch (err) { + console.error(`failed to diff against ${baseRef}:`, err.message); + process.exit(1); +} + +if (files.length === 0) { + console.log("no changed C/C++ files"); + process.exit(0); +} + +console.log(`checking ${files.length} changed file(s) against ${baseRef}`); + +const BATCH = 50; +let exitCode = 0; +for (let i = 0; i < files.length; i += BATCH) { + const batch = files.slice(i, i + BATCH); + const result = spawnSync( + "clang-format", + ["--dry-run", "--Werror", ...batch], + { stdio: "inherit", shell: true } + ); + if (result.error) { + console.error("clang-format not found in PATH. Install LLVM clang-format."); + process.exit(1); + } + if ((result.status ?? 0) !== 0) { + exitCode = result.status ?? 1; + } +} + +process.exit(exitCode); From afa800dfaf01d44eb0d8657a4cdd0fa92ec8dafe Mon Sep 17 00:00:00 2001 From: Liu Date: Sun, 31 May 2026 13:32:02 +0800 Subject: [PATCH 19/66] build(xmake): fix package name, target naming and example install - Remove per-lib set_project() calls that overrode the global lcui project name; xmake show now correctly reports the project as lcui. - Move per-lib set_version() into the corresponding target() block so each sub-library keeps an independent version usable for standalone packaging. - Add set_default(false) and set_group(examples) to all pandagl examples so they are no longer picked up by xmake package. - Rename targets to use dashes for consistency: pandagl_cairo_example -> pandagl-cairo-example preview_block_layout -> preview-block-layout preview_flex_layout -> preview-flex-layout preview_scrollbar -> preview-scrollbar preview_widget_opacity -> preview-widget-opacity - Bump yutil submodule to drop its set_project() call as well. --- lib/css/xmake.lua | 4 +- lib/i18n/xmake.lua | 3 +- lib/pandagl/examples/cairo/xmake.lua | 75 +------------------ lib/pandagl/examples/char-render/xmake.lua | 1 + .../examples/fill-rect-with-rgba/xmake.lua | 1 + lib/pandagl/examples/fill-rect/xmake.lua | 1 + .../examples/image-scaling-bench/xmake.lua | 1 + .../examples/mix-rect-with-opacity/xmake.lua | 1 + .../examples/paint-background/xmake.lua | 1 + lib/pandagl/examples/paint-border/xmake.lua | 1 + .../examples/paint-boxshadow/xmake.lua | 1 + .../examples/pixel-manipulation/xmake.lua | 1 + lib/pandagl/examples/string-render/xmake.lua | 1 + lib/pandagl/xmake.lua | 3 +- lib/router/xmake.lua | 4 +- lib/thread/xmake.lua | 3 +- lib/ui-cursor/xmake.lua | 4 +- lib/ui-router/xmake.lua | 4 +- lib/ui-server/xmake.lua | 3 +- lib/ui-xml/xmake.lua | 3 +- lib/ui/xmake.lua | 4 +- lib/yutil | 2 +- tests/previews/xmake.lua | 2 +- 23 files changed, 25 insertions(+), 99 deletions(-) diff --git a/lib/css/xmake.lua b/lib/css/xmake.lua index 0aacb35e8..23f75abc2 100644 --- a/lib/css/xmake.lua +++ b/lib/css/xmake.lua @@ -1,7 +1,5 @@ -set_project("libcss") -set_version("0.1.0-a") - target("libcss") + set_version("0.1.0-a") set_kind("$(kind)") add_files("src/**.c") set_configdir("include/css") diff --git a/lib/i18n/xmake.lua b/lib/i18n/xmake.lua index 8724e2621..a4cc43a20 100644 --- a/lib/i18n/xmake.lua +++ b/lib/i18n/xmake.lua @@ -1,8 +1,7 @@ -set_project("i18n") -set_version("0.1.0-a") add_requires("libyaml", { optional = true }) target("libi18n") + set_version("0.1.0-a") set_kind("$(kind)") add_files("src/*.c") add_deps("yutil") diff --git a/lib/pandagl/examples/cairo/xmake.lua b/lib/pandagl/examples/cairo/xmake.lua index ab47f0517..91e46100f 100644 --- a/lib/pandagl/examples/cairo/xmake.lua +++ b/lib/pandagl/examples/cairo/xmake.lua @@ -1,78 +1,9 @@ -add_rules("mode.debug", "mode.release") add_requires("cairo") -target("pandagl_cairo_example") +target("pandagl-cairo-example") + set_default(false) set_kind("binary") + set_group("examples") add_files("src/*.c") add_packages("cairo") add_deps("pandagl", "yutil") - --- --- If you want to known more usage about xmake, please see https://xmake.io --- --- ## FAQ --- --- You can enter the project directory firstly before building project. --- --- $ cd projectdir --- --- 1. How to build project? --- --- $ xmake --- --- 2. How to configure project? --- --- $ xmake f -p [macosx|linux|iphoneos ..] -a [x86_64|i386|arm64 ..] -m [debug|release] --- --- 3. Where is the build output directory? --- --- The default output directory is `./build` and you can configure the output directory. --- --- $ xmake f -o outputdir --- $ xmake --- --- 4. How to run and debug target after building project? --- --- $ xmake run [targetname] --- $ xmake run -d [targetname] --- --- 5. How to install target to the system directory or other output directory? --- --- $ xmake install --- $ xmake install -o installdir --- --- 6. Add some frequently-used compilation flags in xmake.lua --- --- @code --- -- add debug and release modes --- add_rules("mode.debug", "mode.release") --- --- -- add macro defination --- add_defines("NDEBUG", "_GNU_SOURCE=1") --- --- -- set warning all as error --- set_warnings("all", "error") --- --- -- set language: c99, c++11 --- set_languages("c99", "c++11") --- --- -- set optimization: none, faster, fastest, smallest --- set_optimize("fastest") --- --- -- add include search directories --- add_includedirs("/usr/include", "/usr/local/include") --- --- -- add link libraries and search directories --- add_links("tbox") --- add_linkdirs("/usr/local/lib", "/usr/lib") --- --- -- add system link libraries --- add_syslinks("z", "pthread") --- --- -- add compilation and link flags --- add_cxflags("-stdnolib", "-fno-strict-aliasing") --- add_ldflags("-L/usr/local/lib", "-lpthread", {force = true}) --- --- @endcode --- - diff --git a/lib/pandagl/examples/char-render/xmake.lua b/lib/pandagl/examples/char-render/xmake.lua index 15cb4c29e..65bef22da 100644 --- a/lib/pandagl/examples/char-render/xmake.lua +++ b/lib/pandagl/examples/char-render/xmake.lua @@ -1,6 +1,7 @@ target("char-render") set_default(false) set_kind("binary") + set_group("examples") set_rundir("app") add_deps("pandagl") add_files("src/*.c") diff --git a/lib/pandagl/examples/fill-rect-with-rgba/xmake.lua b/lib/pandagl/examples/fill-rect-with-rgba/xmake.lua index d5e4a6995..17fac919c 100644 --- a/lib/pandagl/examples/fill-rect-with-rgba/xmake.lua +++ b/lib/pandagl/examples/fill-rect-with-rgba/xmake.lua @@ -1,6 +1,7 @@ target("fill-rect-with-rgba") set_default(false) set_kind("binary") + set_group("examples") set_rundir("app") add_deps("pandagl") add_files("src/*.c") diff --git a/lib/pandagl/examples/fill-rect/xmake.lua b/lib/pandagl/examples/fill-rect/xmake.lua index e6a5ee561..777ec91cb 100644 --- a/lib/pandagl/examples/fill-rect/xmake.lua +++ b/lib/pandagl/examples/fill-rect/xmake.lua @@ -1,6 +1,7 @@ target("fill-rect") set_default(false) set_kind("binary") + set_group("examples") set_rundir("app") add_deps("pandagl") add_files("src/*.c") diff --git a/lib/pandagl/examples/image-scaling-bench/xmake.lua b/lib/pandagl/examples/image-scaling-bench/xmake.lua index 167da6d90..cff56e9ed 100644 --- a/lib/pandagl/examples/image-scaling-bench/xmake.lua +++ b/lib/pandagl/examples/image-scaling-bench/xmake.lua @@ -1,6 +1,7 @@ target("image-scaling-bench") set_default(false) set_kind("binary") + set_group("examples") set_rundir("app") add_deps("pandagl", "yutil") add_files("src/*.c") diff --git a/lib/pandagl/examples/mix-rect-with-opacity/xmake.lua b/lib/pandagl/examples/mix-rect-with-opacity/xmake.lua index 5caea4a8c..bd7e8e21e 100644 --- a/lib/pandagl/examples/mix-rect-with-opacity/xmake.lua +++ b/lib/pandagl/examples/mix-rect-with-opacity/xmake.lua @@ -1,6 +1,7 @@ target("mix-rect-with-opacity") set_default(false) set_kind("binary") + set_group("examples") set_rundir("app") add_deps("pandagl") add_files("src/*.c") diff --git a/lib/pandagl/examples/paint-background/xmake.lua b/lib/pandagl/examples/paint-background/xmake.lua index c5619837e..1faa3404e 100644 --- a/lib/pandagl/examples/paint-background/xmake.lua +++ b/lib/pandagl/examples/paint-background/xmake.lua @@ -1,6 +1,7 @@ target("paint-background") set_default(false) set_kind("binary") + set_group("examples") set_rundir("app") add_deps("pandagl") add_files("src/*.c") diff --git a/lib/pandagl/examples/paint-border/xmake.lua b/lib/pandagl/examples/paint-border/xmake.lua index 919f6003d..59b1798f7 100644 --- a/lib/pandagl/examples/paint-border/xmake.lua +++ b/lib/pandagl/examples/paint-border/xmake.lua @@ -1,6 +1,7 @@ target("paint-border") set_default(false) set_kind("binary") + set_group("examples") set_rundir("app") add_deps("pandagl") add_files("src/*.c") diff --git a/lib/pandagl/examples/paint-boxshadow/xmake.lua b/lib/pandagl/examples/paint-boxshadow/xmake.lua index 934c63000..2465480a3 100644 --- a/lib/pandagl/examples/paint-boxshadow/xmake.lua +++ b/lib/pandagl/examples/paint-boxshadow/xmake.lua @@ -1,6 +1,7 @@ target("paint-boxshadow") set_default(false) set_kind("binary") + set_group("examples") set_rundir("app") add_deps("pandagl") add_files("src/*.c") diff --git a/lib/pandagl/examples/pixel-manipulation/xmake.lua b/lib/pandagl/examples/pixel-manipulation/xmake.lua index 34c0ef937..bcbcc9f57 100644 --- a/lib/pandagl/examples/pixel-manipulation/xmake.lua +++ b/lib/pandagl/examples/pixel-manipulation/xmake.lua @@ -1,6 +1,7 @@ target("pixel-manipulation") set_default(false) set_kind("binary") + set_group("examples") set_rundir("app") add_deps("pandagl", "yutil") add_files("src/*.c") diff --git a/lib/pandagl/examples/string-render/xmake.lua b/lib/pandagl/examples/string-render/xmake.lua index 2ad5cf7f2..4b8ac98dd 100644 --- a/lib/pandagl/examples/string-render/xmake.lua +++ b/lib/pandagl/examples/string-render/xmake.lua @@ -1,6 +1,7 @@ target("string-render") set_default(false) set_kind("binary") + set_group("examples") set_rundir("app") add_deps("pandagl") add_files("src/*.c") diff --git a/lib/pandagl/xmake.lua b/lib/pandagl/xmake.lua index 95150ffc4..eb4519ab6 100644 --- a/lib/pandagl/xmake.lua +++ b/lib/pandagl/xmake.lua @@ -1,5 +1,3 @@ -set_project("pandagl") -set_version("0.1.0-a") add_requires("libpng", "libjpeg", {optional = true}) add_requires("freetype", {optional = true, configs = {shared = false}}) @@ -23,6 +21,7 @@ option("with-pandagl-text") set_configvar("PANDAGL_HAS_TEXT", 1) target("pandagl") + set_version("0.1.0-a") set_kind("$(kind)") add_files("src/*.c") add_deps("yutil") diff --git a/lib/router/xmake.lua b/lib/router/xmake.lua index bd9cd1ad3..f548830bf 100644 --- a/lib/router/xmake.lua +++ b/lib/router/xmake.lua @@ -1,7 +1,5 @@ -set_project("librouter") -set_version("0.1.0-a") - target("librouter") + set_version("0.1.0-a") set_kind("$(kind)") add_files("src/*.c") add_deps("yutil", "libui") diff --git a/lib/thread/xmake.lua b/lib/thread/xmake.lua index 5a9e3e52b..53d0d2b07 100644 --- a/lib/thread/xmake.lua +++ b/lib/thread/xmake.lua @@ -1,6 +1,5 @@ -set_version("0.1.0-a") - target("libthread") + set_version("0.1.0-a") set_kind("$(kind)") add_files("src/*.c") set_configdir("include") diff --git a/lib/ui-cursor/xmake.lua b/lib/ui-cursor/xmake.lua index 3b99d0c76..0766a52a7 100644 --- a/lib/ui-cursor/xmake.lua +++ b/lib/ui-cursor/xmake.lua @@ -1,7 +1,5 @@ -set_project("libui-cursor") -set_version("0.1.0-a") - target("libui-cursor") + set_version("0.1.0-a") set_kind("$(kind)") add_files("src/**.c") add_deps("yutil", "pandagl", "libptk") diff --git a/lib/ui-router/xmake.lua b/lib/ui-router/xmake.lua index b244a5c0a..ce143c738 100644 --- a/lib/ui-router/xmake.lua +++ b/lib/ui-router/xmake.lua @@ -1,7 +1,5 @@ -set_project("libui-router") -set_version("0.1.0-a") - target("libui-router") + set_version("0.1.0-a") set_kind("$(kind)") add_files("src/**.c") add_deps("yutil", "libui", "librouter") diff --git a/lib/ui-server/xmake.lua b/lib/ui-server/xmake.lua index 50b4ac5bb..b256eaac2 100644 --- a/lib/ui-server/xmake.lua +++ b/lib/ui-server/xmake.lua @@ -1,10 +1,9 @@ -set_project("libui-server") -set_version("0.1.0-a") add_requires("libomp", {optional = true}) option("with-openmp", {showmenu = true, default = true}) target("libui-server") + set_version("0.1.0-a") set_kind("$(kind)") add_files("src/**.c") add_packages("libomp") diff --git a/lib/ui-xml/xmake.lua b/lib/ui-xml/xmake.lua index c4caf0874..166d066ec 100644 --- a/lib/ui-xml/xmake.lua +++ b/lib/ui-xml/xmake.lua @@ -1,8 +1,7 @@ -set_project("libui-xml") -set_version("0.1.0-a") add_requires("libxml2", {optional = true}) target("libui-xml") + set_version("0.1.0-a") add_packages("libxml2") if has_package("libxml2") then set_configvar("LIBUI_XML_HAS_LIBXML2", 1) diff --git a/lib/ui/xmake.lua b/lib/ui/xmake.lua index e5b4d62bd..01b547fd1 100644 --- a/lib/ui/xmake.lua +++ b/lib/ui/xmake.lua @@ -1,7 +1,5 @@ -set_project("libui") -set_version("0.1.0-a") - target("libui") + set_version("0.1.0-a") set_kind("$(kind)") add_files("src/**.c") add_deps("yutil", "pandagl", "libcss") diff --git a/lib/yutil b/lib/yutil index c91be8015..0f6feace9 160000 --- a/lib/yutil +++ b/lib/yutil @@ -1 +1 @@ -Subproject commit c91be8015d01b0785794ec83bfa44079952f8aae +Subproject commit 0f6feace9b3c4dde71f0cab2a8a733096cbf47bb diff --git a/tests/previews/xmake.lua b/tests/previews/xmake.lua index 17738d011..0af026add 100644 --- a/tests/previews/xmake.lua +++ b/tests/previews/xmake.lua @@ -6,7 +6,7 @@ local previews = { } for _, topic in ipairs(previews) do - target("preview_" .. topic) + target("preview-" .. topic:gsub("_", "-")) set_default(false) set_kind("binary") set_group("previews") From 038b378d9b06f2cde61633073cd0cb5b8dbaf68e Mon Sep 17 00:00:00 2001 From: Liu Date: Mon, 1 Jun 2026 21:18:42 +0800 Subject: [PATCH 20/66] fix(ui): avoid mbstowcs assertion in ui_print_tree on Windows The %ls format in logger_error went through UCRT's wide-to-multibyte path, which triggered a debug assertion in mbstowcs.cpp under non-UTF-8 locales and also produced unreadable output when the console code page was GBK. Switch the tree drawing to UTF-8 byte literals so the log path stays purely narrow, and temporarily set the console output code page to CP_UTF8 around the dump so the box-drawing characters render correctly. --- lib/ui/src/ui_tree.c | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/lib/ui/src/ui_tree.c b/lib/ui/src/ui_tree.c index d9e10696f..4d8eae967 100644 --- a/lib/ui/src/ui_tree.c +++ b/lib/ui/src/ui_tree.c @@ -10,9 +10,11 @@ */ #include -#include #include #include +#ifdef _WIN32 +#include +#endif #include #include #include @@ -369,34 +371,35 @@ ui_widget_t *ui_widget_at(ui_widget_t *widget, int ix, int iy) return target == widget ? NULL : target; } -static void _ui_print_tree(ui_widget_t *w, int depth, const wchar_t *prefix) +static void _ui_print_tree(ui_widget_t *w, int depth, const char *prefix) { ui_widget_t *child; list_node_t *node; css_selector_node_t *snode; - wchar_t str[16], child_prefix[512]; + char str[32], child_prefix[1024]; size_t len; - len = wcslen(prefix); - wcscpy(child_prefix, prefix); + len = strlen(prefix); + strcpy(child_prefix, prefix); for (list_each(node, &w->children)) { if (node == w->children.tail.prev) { - wcscpy(str, L"\u2514"); - wcscpy(child_prefix + len, L" "); + strcpy(str, "\xe2\x94\x94"); /* U+2514 └ */ + strcpy(child_prefix + len, " "); } else { - wcscpy(str, L"\u251C"); - wcscpy(child_prefix + len, L"\u2502 "); + strcpy(str, "\xe2\x94\x9c"); /* U+251C ├ */ + strcpy(child_prefix + len, + "\xe2\x94\x82 "); /* U+2502 │ */ } - wcscat(str, L"\u2500\u2500"); + strcat(str, "\xe2\x94\x80\xe2\x94\x80"); /* ── */ child = node->data; if (child->children.length == 0) { - wcscat(str, L"\u2500\u2500"); + strcat(str, "\xe2\x94\x80\xe2\x94\x80"); /* ── */ } else { - wcscat(str, L"\u252C\u2500"); + strcat(str, "\xe2\x94\xac\xe2\x94\x80"); /* ┬─ */ } snode = ui_widget_create_selector_node(child); logger_error( - "%ls%ls %s, xy:(%g,%g), size:(%g,%g), " + "%s%s %s, xy:(%g,%g), size:(%g,%g), " "visible: %s, display: %d, padding: (%g,%g,%g,%g), margin: " "(%g,%g,%g,%g)\n", prefix, str, snode->fullname, child->border_box.x, @@ -420,9 +423,11 @@ static void _ui_print_tree(ui_widget_t *w, int depth, const wchar_t *prefix) void ui_print_tree(ui_widget_t *w) { css_selector_node_t *node; - char *ctype = setlocale(LC_CTYPE, NULL); +#ifdef _WIN32 + UINT prev_cp = GetConsoleOutputCP(); - setlocale(LC_CTYPE, ""); + SetConsoleOutputCP(CP_UTF8); +#endif w = w ? w : ui_root(); node = ui_widget_create_selector_node(w); logger_error("%s, xy:(%g,%g), size:(%g,%g), visible: %s\n", @@ -430,6 +435,8 @@ void ui_print_tree(ui_widget_t *w) w->border_box.width, w->border_box.height, ui_widget_is_visible(w) ? "true" : "false"); css_selector_node_destroy(node); - _ui_print_tree(w, 0, L" "); - setlocale(LC_CTYPE, ctype); + _ui_print_tree(w, 0, " "); +#ifdef _WIN32 + SetConsoleOutputCP(prev_cp); +#endif } From 1ef42ee4ae3caea22142ee45124ddcdda32b638d Mon Sep 17 00:00:00 2001 From: Liu Date: Mon, 1 Jun 2026 22:18:44 +0800 Subject: [PATCH 21/66] fix(ui-server): correct inverted strcmp for update_visible flag The visible property check was missing '== 0', so any non-visible property change incorrectly set update_visible to true, while actual visible mutations were ignored. This caused the window to never receive ptk_window_show on Windows. --- lib/ui-server/src/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui-server/src/server.c b/lib/ui-server/src/server.c index 5550e92ae..cb6f2c9e2 100644 --- a/lib/ui-server/src/server.c +++ b/lib/ui-server/src/server.c @@ -612,7 +612,7 @@ static int window_mutation_list_add(list_t *list, strcmp(mutation->property_name, "title") == 0; wnd_mutation->update_visible = wnd_mutation->update_visible || - strcmp(mutation->property_name, "visible"); + strcmp(mutation->property_name, "visible") == 0; wnd_mutation->update_position = wnd_mutation->update_position || strcmp(mutation->property_name, "x") == 0 || From dac5283647a51e10e7c779e9364ea35a9c4bc6a7 Mon Sep 17 00:00:00 2001 From: Liu Date: Mon, 1 Jun 2026 22:19:02 +0800 Subject: [PATCH 22/66] fix(ptk): handle window creation failures on win32 --- lib/ptk/src/windows/win32app.c | 41 +++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/lib/ptk/src/windows/win32app.c b/lib/ptk/src/windows/win32app.c index 67e411a07..a9cd48906 100644 --- a/lib/ptk/src/windows/win32app.c +++ b/lib/ptk/src/windows/win32app.c @@ -136,7 +136,6 @@ static int ptk_process_native_event(void) return ret; } - static int ptk_win32_pending(void) { MSG msg; @@ -227,7 +226,8 @@ unsigned ptk_window_get_dpi(ptk_window_t *wnd) { UINT dpi = GetDpiForWindow(wnd->hwnd); if (dpi == 0) { - logger_error("[win32-app] GetDpiForWindow failed, hwnd: %p\n", wnd->hwnd); + logger_error("[win32-app] GetDpiForWindow failed, hwnd: %p\n", + wnd->hwnd); dpi = GetDpiForSystem(); } return dpi; @@ -498,11 +498,10 @@ ptk_window_t *ptk_window_create(const wchar_t *title, int x, int y, int width, int height, ptk_window_t *parent) { ptk_window_t *wnd; + DWORD err; + wchar_t errmsg[256]; wnd = malloc(sizeof(ptk_window_t)); - if (!wnd) { - return NULL; - } if (x == PTK_WINDOW_DEFAULT_X) { x = CW_USEDEFAULT; } else if (x == PTK_WINDOW_CENTER_X) { @@ -534,11 +533,43 @@ ptk_window_t *ptk_window_create(const wchar_t *title, int x, int y, int width, CreateWindowW(win32_app.class_name, title, WIN32_WINDOW_STYLE, x, y, width, height, parent ? parent->hwnd : NULL, NULL, win32_app.main_instance, NULL); + if (!wnd->hwnd) { + err = GetLastError(); + format_error_message(err, errmsg, 256); + logger_error( + "[win32-app] CreateWindowW failed, error %d: %ls\n", err, + errmsg); + list_unlink(&win32_app.windows, &wnd->node); + free(wnd); + return NULL; + } #ifdef PTK_TOUCH_ENABLED RegisterTouchWindow(wnd->hwnd, 0); #endif wnd->hdc_client = GetDC(wnd->hwnd); + if (!wnd->hdc_client) { + err = GetLastError(); + format_error_message(err, errmsg, 256); + logger_error("[win32-app] GetDC failed, error %d: %ls\n", err, + errmsg); + DestroyWindow(wnd->hwnd); + list_unlink(&win32_app.windows, &wnd->node); + free(wnd); + return NULL; + } wnd->hdc_fb = CreateCompatibleDC(wnd->hdc_client); + if (!wnd->hdc_fb) { + err = GetLastError(); + format_error_message(err, errmsg, 256); + logger_error( + "[win32-app] CreateCompatibleDC failed, error %d: %ls\n", + err, errmsg); + ReleaseDC(wnd->hwnd, wnd->hdc_client); + DestroyWindow(wnd->hwnd); + list_unlink(&win32_app.windows, &wnd->node); + free(wnd); + return NULL; + } return wnd; } From 01318a0807729ac7b442eda7422e1a8d17f2754b Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 00:15:50 +0800 Subject: [PATCH 23/66] refactor(ui): consolidate flexbox row/column axis logic Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Liu --- lib/ui/src/ui_debug.h | 37 +- lib/ui/src/ui_flexbox_layout.c | 823 +++++++++++---------------------- 2 files changed, 295 insertions(+), 565 deletions(-) diff --git a/lib/ui/src/ui_debug.h b/lib/ui/src/ui_debug.h index fc4e5ff2e..6f8db5a64 100644 --- a/lib/ui/src/ui_debug.h +++ b/lib/ui/src/ui_debug.h @@ -14,22 +14,41 @@ void ui_widget_size_to_string(ui_widget_t *w, char str[40]); void ui_widget_min_size_to_string(ui_widget_t *w, char str[40]); #define UI_WIDGET_STR(W, STR) \ - char STR[256]; \ - ui_widget_to_string(W, STR); + char STR[256]; \ + ui_widget_to_string(W, STR); #define UI_WIDGET_SIZE_STR(W, STR) \ - char STR[32]; \ - ui_widget_size_to_string(W, STR); + char STR[32]; \ + ui_widget_size_to_string(W, STR); #define UI_WIDGET_MIN_SIZE_STR(W, STR) \ - char STR[32]; \ - ui_widget_min_size_to_string(W, STR); + char STR[32]; \ + ui_widget_min_size_to_string(W, STR); #ifdef UI_DEBUG_ENABLED extern int ui_debug_msg_indent; -#define UI_DEBUG_MSG(FMT, ...) \ - logger_log(LOGGER_LEVEL_DEBUG, "%*s" FMT "\n", ui_debug_msg_indent * 4, \ - "", ##__VA_ARGS__) +/* clang-format off */ +#define UI_DEBUG_BEGIN do { +#define UI_DEBUG_END } while (0) +/* clang-format on */ + +#define UI_DEBUG_MSG(FMT, ...) \ + logger_log(LOGGER_LEVEL_DEBUG, "%*s" FMT "\n", \ + ui_debug_msg_indent * 4, "", ##__VA_ARGS__) + +#define UI_DEBUG_INDENT_INC ++ui_debug_msg_indent +#define UI_DEBUG_INDENT_DEC --ui_debug_msg_indent + +#else + +/* clang-format off */ +#define UI_DEBUG_BEGIN do { if (0) { +#define UI_DEBUG_END } } while (0) +/* clang-format on */ + +#define UI_DEBUG_MSG(FMT, ...) +#define UI_DEBUG_INDENT_INC +#define UI_DEBUG_INDENT_DEC #endif diff --git a/lib/ui/src/ui_flexbox_layout.c b/lib/ui/src/ui_flexbox_layout.c index c34b53bbc..9a8e0ad36 100644 --- a/lib/ui/src/ui_flexbox_layout.c +++ b/lib/ui/src/ui_flexbox_layout.c @@ -159,6 +159,38 @@ static void ui_compute_column_item_flex_basis(ui_widget_t *item) s->flex_basis = ui_widget_fix_height(item, s->flex_basis); } +/* 重置项目主轴方向上的尺寸与 flex_basis,返回其外框主轴尺寸 */ +static float ui_flexbox_item_reset_main_size(ui_flexbox_layout_context_t *ctx, + ui_widget_t *item) +{ + css_computed_style_t *cs = &item->computed_style; + + if (ctx->column_direction) { + ui_widget_reset_height(item); + ui_reset_column_item_flex_basis(item); + ui_compute_column_item_flex_basis(item); + return css_obox_height(cs, cs->flex_basis); + } + ui_widget_reset_width(item); + ui_reset_row_item_flex_basis(item); + ui_compute_row_item_flex_basis(item); + return css_obox_width(cs, cs->flex_basis); +} + +/* 返回项目主轴方向上基于 min_content_* 的最小外框尺寸 */ +static float ui_flexbox_item_min_main_size(ui_flexbox_layout_context_t *ctx, + ui_widget_t *item) +{ + css_computed_style_t *cs = &item->computed_style; + + if (ctx->column_direction) { + return css_obox_height( + cs, css_height_from_cbox(cs, item->min_content_height)); + } + return css_obox_width(cs, + css_width_from_cbox(cs, item->min_content_width)); +} + static void ui_flexbox_layout_compute_justify_content( ui_flexbox_layout_context_t *ctx, ui_flexbox_line_t *line, float *start_axis, float *space) @@ -200,124 +232,6 @@ static void ui_flexbox_layout_compute_justify_content( } } -static void ui_flexbox_row_layout_load_main_size( - ui_flexbox_layout_context_t *ctx) -{ - list_node_t *node; - ui_widget_t *child; - css_computed_style_t *cs; - float main_size, min_main_size; - -#ifdef UI_DEBUG_ENABLED - unsigned child_index = 0; - - UI_DEBUG_MSG("%s: begin, main_size_fixed?=%d", __FUNCTION__, - IS_CSS_FIXED_LENGTH(s, width)); - ui_debug_msg_indent++; -#endif - for (list_each(node, &ctx->widget->children)) { - child = node->data; - cs = &child->computed_style; - if (!ui_widget_in_layout_flow(child)) { - continue; - } - ui_widget_reset_layout(child); - ui_reset_row_item_flex_basis(child); - ui_compute_row_item_flex_basis(child); - main_size = css_obox_width(cs, cs->flex_basis); - if (cs->flex_shrink > 0) { - min_main_size = css_obox_width( - cs, - css_width_from_cbox(cs, child->min_content_width)); - } else { - min_main_size = main_size; - } - ui_resizer_load_item_main_size(ctx->resizer, main_size, - min_main_size); -#ifdef UI_DEBUG_ENABLED - { - UI_WIDGET_STR(child, str); - UI_WIDGET_SIZE_STR(child, size_str); - UI_DEBUG_MSG( - "children[%u]=%s, size=%s, max_content_size=(%g, " - "%g), max_width(%d)=%g, flex_basis(%d)=%g", - child_index, str, size_str, - child->max_content_width, child->max_content_height, - cs->type_bits.max_width, cs->max_width, - cs->type_bits.flex_basis, cs->flex_basis); - child_index++; - } -#endif - } - ui_resizer_commit_row_main_size(ctx->resizer); -#ifdef UI_DEBUG_ENABLED - { - ui_debug_msg_indent--; - UI_WIDGET_SIZE_STR(ctx->widget, size_str); - UI_DEBUG_MSG("%s: end, size=%s, main_size=%g, min_main_size=%g", - __FUNCTION__, size_str, main_size, min_main_size); - } -#endif -} - -static void ui_flexbox_column_layout_load_main_size( - ui_flexbox_layout_context_t *ctx) -{ - list_node_t *node; - ui_widget_t *child; - css_computed_style_t *cs; - float main_size = 0, min_main_size = 0; - -#ifdef UI_DEBUG_ENABLED - unsigned child_index = 0; - UI_DEBUG_MSG("%s: begin, main_size_fixed?=%d", __FUNCTION__, - IS_CSS_FIXED_LENGTH(s, height)); - ui_debug_msg_indent++; -#endif - for (list_each(node, &ctx->widget->children)) { - child = node->data; - cs = &child->computed_style; - if (!ui_widget_in_layout_flow(child)) { - continue; - } - ui_widget_reset_layout(child); - ui_reset_column_item_flex_basis(child); - ui_compute_column_item_flex_basis(child); - main_size = css_obox_height(cs, cs->flex_basis); - if (cs->flex_shrink > 0) { - min_main_size = css_obox_height( - cs, css_height_from_cbox( - cs, child->min_content_height)); - } else { - min_main_size = main_size; - } - ui_resizer_load_item_main_size(ctx->resizer, main_size, - min_main_size); -#ifdef UI_DEBUG_ENABLED - { - UI_WIDGET_STR(child, str); - UI_WIDGET_SIZE_STR(child, size_str); - UI_DEBUG_MSG( - "children[%u]=%s, size=%s, max_content_size=(%g, " - "%g), flex_basis(%d)=%g", - child_index, str, size_str, - child->max_content_width, child->max_content_height, - cs->type_bits.flex_basis, cs->flex_basis); - child_index++; - } -#endif - } - ui_resizer_commit_column_main_size(ctx->resizer); -#ifdef UI_DEBUG_ENABLED - { - ui_debug_msg_indent--; - UI_WIDGET_SIZE_STR(ctx->widget, size_str); - UI_DEBUG_MSG("%s: end, main_size=%g, size=%s", __FUNCTION__, - main_size, size_str); - } -#endif -} - static void ui_apply_row_item_main_size(ui_widget_t *item, float flex_space, float margin_space) { @@ -368,267 +282,184 @@ static void ui_apply_column_item_main_size(ui_widget_t *item, float flex_space, ui_widget_reflow_if_height_changed(item); } -static void ui_flexbox_row_layout_apply_main_size( - ui_flexbox_layout_context_t *ctx) +static void ui_flexbox_layout_load_main_size(ui_flexbox_layout_context_t *ctx) { - list_node_t *node, *line_node; + list_node_t *node; ui_widget_t *child; - ui_flexbox_line_t *line; - css_computed_style_t *s = &ctx->widget->computed_style; css_computed_style_t *cs; - - float main_size; - float max_main_size = ctx->widget->content_box.width; - float space, flex_space, margin_space; - -#ifdef UI_DEBUG_ENABLED + float main_size, min_main_size; unsigned child_index = 0; - { - UI_DEBUG_MSG("%s: begin, max_main_size=%g", __FUNCTION__, - max_main_size); - ui_debug_msg_indent++; - } -#endif - - line = ui_flexbox_layout_next_line(ctx); + UI_DEBUG_BEGIN; + UI_DEBUG_MSG( + "%s: begin, main_size_fixed?=%d", __FUNCTION__, + ctx->column_direction + ? IS_CSS_FIXED_LENGTH(&ctx->widget->computed_style, height) + : IS_CSS_FIXED_LENGTH(&ctx->widget->computed_style, width)); + UI_DEBUG_INDENT_INC; + UI_DEBUG_END; for (list_each(node, &ctx->widget->children)) { child = node->data; + cs = &child->computed_style; if (!ui_widget_in_layout_flow(child)) { -#ifdef UI_DEBUG_ENABLED - { - UI_WIDGET_STR(child, str); - UI_DEBUG_MSG("line[%zu]: children[%u]=%s, skip", - line->index, child_index, str); - } - child_index++; -#endif - list_append(&line->items, child); continue; } - cs = &child->computed_style; - ui_widget_reset_width(child); -#ifdef UI_DEBUG_ENABLED - { - UI_WIDGET_STR(child, str); - UI_WIDGET_SIZE_STR(child, size_str); - UI_DEBUG_MSG("line[%zu]: children[%u]=%s, size=%s, " - "flex_basis(%d)=%g", - line->index, child_index, str, size_str, - cs->type_bits.flex_basis, cs->flex_basis); - } -#endif - ui_reset_row_item_flex_basis(child); - ui_compute_row_item_flex_basis(child); - main_size = css_obox_width(cs, cs->flex_basis); -#ifdef UI_DEBUG_ENABLED - { - UI_WIDGET_STR(child, str); - UI_WIDGET_SIZE_STR(child, size_str); - UI_DEBUG_MSG("line[%zu]: children[%u]=%s, size=%s, " - "flex_basis(%d)=%g, main_size=%g, " - "outer_box.width=%g", - line->index, child_index, str, size_str, - cs->type_bits.flex_basis, cs->flex_basis, - main_size, child->outer_box.width); - } + ui_widget_reset_layout(child); + main_size = ui_flexbox_item_reset_main_size(ctx, child); + min_main_size = cs->flex_shrink > 0 + ? ui_flexbox_item_min_main_size(ctx, child) + : main_size; + ui_resizer_load_item_main_size(ctx->resizer, main_size, + min_main_size); + UI_DEBUG_BEGIN; + UI_WIDGET_STR(child, str); + UI_WIDGET_SIZE_STR(child, size_str); + UI_DEBUG_MSG("children[%u]=%s, size=%s, flex_basis(%d)=%g", + child_index, str, size_str, + cs->type_bits.flex_basis, cs->flex_basis); child_index++; -#endif - if (s->type_bits.flex_wrap == CSS_FLEX_WRAP_WRAP && - line->main_size > 0 && - line->main_size + main_size > max_main_size) { - line = ui_flexbox_layout_next_line(ctx); - } - line->main_size += main_size; - if (cs->type_bits.margin_left == CSS_MARGIN_AUTO) { - line->count_of_auto_margin_items++; - } - if (cs->type_bits.margin_right == CSS_MARGIN_AUTO) { - line->count_of_auto_margin_items++; - } - ui_flexbox_line_load_item(line, child); + UI_DEBUG_END; } - ctx->cross_size = 0; -#ifdef UI_DEBUG_ENABLED - ui_debug_msg_indent--; - UI_DEBUG_MSG("%s: all lines loaded", __FUNCTION__); - ui_debug_msg_indent++; -#endif - for (list_each(line_node, &ctx->lines)) { - line = line_node->data; - space = max_main_size - line->main_size; - flex_space = 0; - margin_space = 0; - if (space >= 0) { - if (line->sum_of_grow_value > 0) { - flex_space = space / line->sum_of_grow_value; - } else if (line->count_of_auto_margin_items > 0) { - margin_space = - space / line->count_of_auto_margin_items; - } - } else if (line->sum_of_shrink_value > 0) { - flex_space = space / line->sum_of_shrink_value; + if (ctx->column_direction) { + ui_resizer_commit_column_main_size(ctx->resizer); + } else { + ui_resizer_commit_row_main_size(ctx->resizer); + } + UI_DEBUG_BEGIN; + UI_DEBUG_INDENT_DEC; + UI_WIDGET_SIZE_STR(ctx->widget, size_str); + UI_DEBUG_MSG("%s: end, size=%s", __FUNCTION__, size_str); + UI_DEBUG_END; +} + +static void ui_flexbox_layout_apply_line(ui_flexbox_layout_context_t *ctx, + ui_flexbox_line_t *line, + float flex_space, float margin_space) +{ + list_node_t *node; + ui_widget_t *child; + float item_main_size, item_cross_size; + unsigned child_index = 0; + + line->main_size = 0; + line->cross_size = 0; + for (list_each(node, &line->items)) { + child = node->data; + if (!ui_widget_in_layout_flow(child)) { + continue; } -#ifdef UI_DEBUG_ENABLED - UI_DEBUG_MSG("line[%zu]: main_size=%g, space=%g, " - "flex_space=%g, margin_space=%g", - line->index, line->main_size, space, flex_space, - margin_space); - ui_debug_msg_indent++; - child_index = 0; -#endif - line->main_size = 0; - line->cross_size = 0; - for (list_each(node, &line->items)) { - child = node->data; - if (!ui_widget_in_layout_flow(child)) { - continue; - } -#ifdef UI_DEBUG_ENABLED - { - UI_WIDGET_STR(child, str); - UI_WIDGET_SIZE_STR(child, size_str); - UI_DEBUG_MSG("[%zu] %s: size=%s, " - "flex-shrink=%g, flex-grow=%g, " - "content_box_size=(%g, %g), " - "outer_box_size=(%g, %g)", - child_index, str, size_str, - child->computed_style.flex_shrink, - child->computed_style.flex_grow, - child->content_box.width, - child->content_box.height, - child->outer_box.width, - child->outer_box.height); - ui_debug_msg_indent++; - } -#endif + UI_DEBUG_BEGIN; + UI_WIDGET_STR(child, str); + UI_WIDGET_SIZE_STR(child, size_str); + UI_DEBUG_MSG("[%u] %s: size=%s, flex-shrink=%g, " + "flex-grow=%g", + child_index, str, size_str, + child->computed_style.flex_shrink, + child->computed_style.flex_grow); + UI_DEBUG_INDENT_INC; + UI_DEBUG_END; + if (ctx->column_direction) { + ui_apply_column_item_main_size(child, flex_space, + margin_space); + item_main_size = child->outer_box.height; + item_cross_size = child->outer_box.width; + } else { ui_apply_row_item_main_size(child, flex_space, margin_space); -#ifdef UI_DEBUG_ENABLED - { - ui_debug_msg_indent--; - UI_WIDGET_STR(child, str); - UI_WIDGET_SIZE_STR(child, size_str); - UI_DEBUG_MSG( - "[%zu] %s: size=%s, main_size=%g, " - "cross_size=%g, content_box_size=(%g, %g)", - child_index, str, size_str, - child->outer_box.width, - child->outer_box.height, - child->content_box.width, - child->content_box.height); - } - child_index++; -#endif - if (line->cross_size < child->outer_box.height) { - line->cross_size = child->outer_box.height; - } - line->main_size += child->outer_box.width; + item_main_size = child->outer_box.width; + item_cross_size = child->outer_box.height; + } + UI_DEBUG_BEGIN; + UI_DEBUG_INDENT_DEC; + UI_WIDGET_STR(child, str); + UI_WIDGET_SIZE_STR(child, size_str); + UI_DEBUG_MSG("[%u] %s: size=%s, main_size=%g, " + "cross_size=%g", + child_index, str, size_str, item_main_size, + item_cross_size); + child_index++; + UI_DEBUG_END; + if (line->cross_size < item_cross_size) { + line->cross_size = item_cross_size; } -#ifdef UI_DEBUG_ENABLED - --ui_debug_msg_indent; - UI_DEBUG_MSG("line[%zu]: cross_size=%g", line->index, - line->cross_size); -#endif - ctx->cross_size += line->cross_size; - } - if (ctx->cross_size < ctx->resizer->hint.max_height) { - ctx->cross_size = ctx->resizer->hint.max_height; + line->main_size += item_main_size; } - if (!IS_CSS_FIXED_LENGTH(s, height)) { - ui_widget_set_content_height(ctx->widget, ctx->cross_size); - } -#ifdef UI_DEBUG_ENABLED - ui_debug_msg_indent--; - UI_DEBUG_MSG("%s: end, cross_size=%g", __FUNCTION__, ctx->cross_size); -#endif } -static void ui_flexbox_column_layout_apply_main_size( - ui_flexbox_layout_context_t *ctx) +static void ui_flexbox_layout_apply_main_size(ui_flexbox_layout_context_t *ctx) { list_node_t *node, *line_node; ui_widget_t *child; ui_flexbox_line_t *line; css_computed_style_t *s = &ctx->widget->computed_style; css_computed_style_t *cs; + bool column = ctx->column_direction; float main_size; - float max_main_size = ctx->widget->content_box.height; + float max_main_size = column ? ctx->widget->content_box.height + : ctx->widget->content_box.width; + float hint_cross_size = column ? ctx->resizer->hint.max_width + : ctx->resizer->hint.max_height; float space, flex_space, margin_space; - -#ifdef UI_DEBUG_ENABLED unsigned child_index = 0; - { - UI_DEBUG_MSG("%s: begin, max_main_size=%g", __FUNCTION__, - max_main_size); - ui_debug_msg_indent++; - } -#endif + UI_DEBUG_BEGIN; + UI_DEBUG_MSG("%s: begin, max_main_size=%g", __FUNCTION__, + max_main_size); + UI_DEBUG_INDENT_INC; + UI_DEBUG_END; line = ui_flexbox_layout_next_line(ctx); for (list_each(node, &ctx->widget->children)) { child = node->data; if (!ui_widget_in_layout_flow(child)) { -#ifdef UI_DEBUG_ENABLED - { - UI_WIDGET_STR(child, str); - UI_DEBUG_MSG("line[%zu]: children[%u]=%s, skip", - line->index, child_index, str); - } + UI_DEBUG_BEGIN; + UI_WIDGET_STR(child, str); + UI_DEBUG_MSG("line[%zu]: children[%u]=%s, skip", + line->index, child_index, str); child_index++; -#endif + UI_DEBUG_END; list_append(&line->items, child); continue; } cs = &child->computed_style; - ui_widget_reset_height(child); -#ifdef UI_DEBUG_ENABLED - { - UI_WIDGET_STR(child, str); - UI_WIDGET_SIZE_STR(child, size_str); - UI_DEBUG_MSG("line[%zu]: children[%u]=%s, size=%s, " - "flex_basis(%d)=%g", - line->index, child_index, str, size_str, - cs->type_bits.flex_basis, cs->flex_basis); - } -#endif - ui_reset_column_item_flex_basis(child); - ui_compute_column_item_flex_basis(child); - main_size = css_obox_height(cs, cs->flex_basis); -#ifdef UI_DEBUG_ENABLED - { - UI_WIDGET_STR(child, str); - UI_WIDGET_SIZE_STR(child, size_str); - UI_DEBUG_MSG("line[%zu]: children[%u]=%s, size=%s, " - "flex_basis(%d)=%g, main_size=%g, " - "child->outer_box.height=%g", - line->index, child_index, str, size_str, - cs->type_bits.flex_basis, cs->flex_basis, - main_size, child->outer_box.height); - } + main_size = ui_flexbox_item_reset_main_size(ctx, child); + UI_DEBUG_BEGIN; + UI_WIDGET_STR(child, str); + UI_WIDGET_SIZE_STR(child, size_str); + UI_DEBUG_MSG("line[%zu]: children[%u]=%s, size=%s, " + "flex_basis(%d)=%g, main_size=%g", + line->index, child_index, str, size_str, + cs->type_bits.flex_basis, cs->flex_basis, + main_size); child_index++; -#endif + UI_DEBUG_END; if (s->type_bits.flex_wrap == CSS_FLEX_WRAP_WRAP && line->main_size > 0 && line->main_size + main_size > max_main_size) { line = ui_flexbox_layout_next_line(ctx); } line->main_size += main_size; - if (cs->type_bits.margin_top == CSS_MARGIN_AUTO) { - line->count_of_auto_margin_items++; - } - if (cs->type_bits.margin_bottom == CSS_MARGIN_AUTO) { - line->count_of_auto_margin_items++; + if (column) { + if (cs->type_bits.margin_top == CSS_MARGIN_AUTO) { + line->count_of_auto_margin_items++; + } + if (cs->type_bits.margin_bottom == CSS_MARGIN_AUTO) { + line->count_of_auto_margin_items++; + } + } else { + if (cs->type_bits.margin_left == CSS_MARGIN_AUTO) { + line->count_of_auto_margin_items++; + } + if (cs->type_bits.margin_right == CSS_MARGIN_AUTO) { + line->count_of_auto_margin_items++; + } } ui_flexbox_line_load_item(line, child); } ctx->cross_size = 0; -#ifdef UI_DEBUG_ENABLED - ui_debug_msg_indent--; + UI_DEBUG_BEGIN; UI_DEBUG_MSG("%s: all lines loaded", __FUNCTION__); - ui_debug_msg_indent++; -#endif + UI_DEBUG_END; for (list_each(line_node, &ctx->lines)) { line = line_node->data; space = max_main_size - line->main_size; @@ -644,270 +475,159 @@ static void ui_flexbox_column_layout_apply_main_size( } else if (line->sum_of_shrink_value > 0) { flex_space = space / line->sum_of_shrink_value; } -#ifdef UI_DEBUG_ENABLED + UI_DEBUG_BEGIN; UI_DEBUG_MSG("line[%zu]: main_size=%g, space=%g, " "flex_space=%g, margin_space=%g", line->index, line->main_size, space, flex_space, margin_space); - ui_debug_msg_indent++; - child_index = 0; -#endif - line->main_size = 0; - line->cross_size = 0; - for (list_each(node, &line->items)) { - child = node->data; - if (!ui_widget_in_layout_flow(child)) { - continue; - } -#ifdef UI_DEBUG_ENABLED - { - UI_WIDGET_STR(child, str); - UI_WIDGET_SIZE_STR(child, size_str); - UI_DEBUG_MSG("[%zu] %s: size=%s, " - "flex-shrink=%g, flex-grow=%g", - child_index, str, size_str, - child->computed_style.flex_shrink, - child->computed_style.flex_grow); - ui_debug_msg_indent++; - } -#endif - ui_apply_column_item_main_size(child, flex_space, - margin_space); -#ifdef UI_DEBUG_ENABLED - { - ui_debug_msg_indent--; - UI_WIDGET_STR(child, str); - UI_WIDGET_SIZE_STR(child, size_str); - UI_DEBUG_MSG("[%zu] %s: size=%s, main_size=%g, " - "cross_size=%g", - child_index, str, size_str, - child->outer_box.height, - child->outer_box.width); - } - child_index++; -#endif - if (line->cross_size < child->outer_box.width) { - line->cross_size = child->outer_box.width; - } - line->main_size += child->outer_box.height; - } -#ifdef UI_DEBUG_ENABLED - --ui_debug_msg_indent; + UI_DEBUG_INDENT_INC; + UI_DEBUG_END; + ui_flexbox_layout_apply_line(ctx, line, flex_space, + margin_space); + UI_DEBUG_BEGIN; + UI_DEBUG_INDENT_DEC; UI_DEBUG_MSG("line[%zu]: cross_size=%g", line->index, line->cross_size); -#endif + UI_DEBUG_END; ctx->cross_size += line->cross_size; } - if (ctx->cross_size < ctx->resizer->hint.max_width) { - ctx->cross_size = ctx->resizer->hint.max_width; + if (ctx->cross_size < hint_cross_size) { + ctx->cross_size = hint_cross_size; } - if (!IS_CSS_FIXED_LENGTH(s, width)) { - ui_widget_set_content_width(ctx->widget, ctx->cross_size); + if (column) { + if (!IS_CSS_FIXED_LENGTH(s, width)) { + ui_widget_set_content_width(ctx->widget, + ctx->cross_size); + } + } else { + if (!IS_CSS_FIXED_LENGTH(s, height)) { + ui_widget_set_content_height(ctx->widget, + ctx->cross_size); + } } -#ifdef UI_DEBUG_ENABLED - ui_debug_msg_indent--; + UI_DEBUG_BEGIN; + UI_DEBUG_INDENT_DEC; UI_DEBUG_MSG("%s: end, cross_size=%g", __FUNCTION__, ctx->cross_size); -#endif + UI_DEBUG_END; } -static float ui_compute_row_item_layout(ui_widget_t *item, float x, float y, - css_align_items_t align, - float line_max_cross_size) +static float ui_flexbox_compute_item_layout(ui_flexbox_layout_context_t *ctx, + ui_widget_t *item, float main_axis, + float cross_axis, + css_align_items_t align, + float line_max_cross_size) { css_computed_style_t *s = &item->computed_style; + bool column = ctx->column_direction; + float item_outer_cross; if (!ui_widget_in_layout_flow(item)) { - item->layout_x = x; - item->layout_y = y; + item->layout_x = column ? cross_axis : main_axis; + item->layout_y = column ? main_axis : cross_axis; ui_widget_reset_layout(item); ui_widget_reflow_if_width_changed(item); ui_widget_reflow_if_height_changed(item); ui_widget_update_box_position(item); return 0; } - if (IS_CSS_PERCENTAGE(&item->specified_style, height)) { - ui_widget_reset_height(item); - } else if (align == CSS_ALIGN_ITEMS_STRETCH && - item->specified_style.type_bits.height == CSS_HEIGHT_AUTO) { - CSS_SET_FIXED_LENGTH( - s, height, - css_border_box_height_to_height( - s, line_max_cross_size - css_margin_y(s))); - } - ui_widget_reflow_if_height_changed(item); - switch (align) { - case CSS_ALIGN_ITEMS_CENTER: - y += (line_max_cross_size - item->outer_box.height) * 0.5f; - break; - case CSS_ALIGN_ITEMS_FLEX_END: - y += line_max_cross_size - item->outer_box.height; - break; - default: - break; - } -#ifdef UI_DEBUG_ENABLED - { - UI_WIDGET_STR(item, str); - UI_DEBUG_MSG("%s: %s: x=%g, y=%g", __FUNCTION__, str, x, y); - } -#endif - item->layout_x = x; - item->layout_y = y; - ui_widget_update_box_position(item); - return item->outer_box.width; -} - -static float ui_compute_column_item_layout(ui_widget_t *item, float x, float y, - css_align_items_t align, - float line_max_cross_size) -{ - css_computed_style_t *s = &item->computed_style; - if (!ui_widget_in_layout_flow(item)) { - item->layout_x = x; - item->layout_y = y; - ui_widget_reset_layout(item); + if (column) { + if (IS_CSS_PERCENTAGE(&item->specified_style, width)) { + ui_widget_reset_width(item); + } else if (align == CSS_ALIGN_ITEMS_STRETCH && + item->specified_style.type_bits.width == + CSS_WIDTH_AUTO) { + CSS_SET_FIXED_LENGTH( + s, width, + css_border_box_width_to_width( + s, line_max_cross_size - css_margin_x(s))); + } ui_widget_reflow_if_width_changed(item); + item_outer_cross = item->outer_box.width; + } else { + if (IS_CSS_PERCENTAGE(&item->specified_style, height)) { + ui_widget_reset_height(item); + } else if (align == CSS_ALIGN_ITEMS_STRETCH && + item->specified_style.type_bits.height == + CSS_HEIGHT_AUTO) { + CSS_SET_FIXED_LENGTH( + s, height, + css_border_box_height_to_height( + s, line_max_cross_size - css_margin_y(s))); + } ui_widget_reflow_if_height_changed(item); - ui_widget_update_box_position(item); - return 0; + item_outer_cross = item->outer_box.height; } - if (IS_CSS_PERCENTAGE(&item->specified_style, width)) { - ui_widget_reset_width(item); - } else if (align == CSS_ALIGN_ITEMS_STRETCH && - item->specified_style.type_bits.width == CSS_WIDTH_AUTO) { - CSS_SET_FIXED_LENGTH( - s, width, - css_border_box_width_to_width( - s, line_max_cross_size - css_margin_x(s))); - } - ui_widget_reflow_if_width_changed(item); switch (align) { case CSS_ALIGN_ITEMS_CENTER: - x += (line_max_cross_size - item->outer_box.width) * 0.5f; + cross_axis += (line_max_cross_size - item_outer_cross) * 0.5f; break; case CSS_ALIGN_ITEMS_FLEX_END: - x += line_max_cross_size - item->outer_box.width; + cross_axis += line_max_cross_size - item_outer_cross; break; default: break; } -#ifdef UI_DEBUG_ENABLED - { - UI_WIDGET_STR(item, str); - UI_DEBUG_MSG("%s: %s: x=%g, y=%g", __FUNCTION__, str, x, y); - } -#endif - item->layout_x = x; - item->layout_y = y; + item->layout_x = column ? cross_axis : main_axis; + item->layout_y = column ? main_axis : cross_axis; + UI_DEBUG_BEGIN; + UI_WIDGET_STR(item, str); + UI_DEBUG_MSG("%s: %s: x=%g, y=%g", __FUNCTION__, str, item->layout_x, + item->layout_y); + UI_DEBUG_END; ui_widget_update_box_position(item); - return item->outer_box.height; + return column ? item->outer_box.height : item->outer_box.width; } -static void ui_flexbox_row_layout_reflow(ui_flexbox_layout_context_t *ctx) +static void ui_flexbox_layout_reflow_lines(ui_flexbox_layout_context_t *ctx) { list_node_t *line_node, *node; ui_widget_t *child; ui_flexbox_line_t *line; css_computed_style_t *s = &ctx->widget->computed_style; + bool column = ctx->column_direction; float space; float main_axis; - float cross_axis = s->padding_top; - float cross_space = - (ctx->widget->content_box.height - ctx->cross_size) / - ctx->lines.length; - float line_max_cross_size; - -#ifdef UI_DEBUG_ENABLED - { - UI_WIDGET_STR(ctx->widget, str); - UI_DEBUG_MSG("%s: %s: begin, cross_space=%g", __FUNCTION__, str, - cross_space); - } -#endif - for (list_each(line_node, &ctx->lines)) { - line = line_node->data; - line_max_cross_size = line->cross_size + cross_space; - ui_flexbox_layout_compute_justify_content(ctx, line, &main_axis, - &space); -#ifdef UI_DEBUG_ENABLED - UI_DEBUG_MSG("line[%zu]: main_axis=%g, cross_axis=%g, " - "space=%g, line_max_cross_size=%g", - line->index, main_axis, cross_axis, space, - line_max_cross_size); - ui_debug_msg_indent++; -#endif - for (list_each(node, &line->items)) { - child = node->data; - main_axis += space; - main_axis += ui_compute_row_item_layout( - child, main_axis, cross_axis, - s->type_bits.align_items, line_max_cross_size); - } - cross_axis += line_max_cross_size; -#ifdef UI_DEBUG_ENABLED - ui_debug_msg_indent--; -#endif - } -#ifdef UI_DEBUG_ENABLED - { - UI_WIDGET_STR(ctx->widget, str); - UI_DEBUG_MSG("%s: %s: end", __FUNCTION__, str); - } -#endif -} - -static void ui_flexbox_column_layout_reflow(ui_flexbox_layout_context_t *ctx) -{ - list_node_t *line_node, *node; - ui_widget_t *child; - ui_flexbox_line_t *line; - css_computed_style_t *s = &ctx->widget->computed_style; - - float space; - float main_axis; - float cross_axis = s->padding_left; - float cross_space = (ctx->widget->content_box.width - ctx->cross_size) / + float cross_axis = column ? s->padding_left : s->padding_top; + float cross_space = ((column ? ctx->widget->content_box.width + : ctx->widget->content_box.height) - + ctx->cross_size) / ctx->lines.length; float line_max_cross_size; -#ifdef UI_DEBUG_ENABLED - { - UI_WIDGET_STR(ctx->widget, str); - UI_DEBUG_MSG("%s: %s: begin, cross_space=%g", __FUNCTION__, str, - cross_space); - } -#endif + UI_DEBUG_BEGIN; + UI_WIDGET_STR(ctx->widget, str); + UI_DEBUG_MSG("%s: %s: begin, cross_space=%g", __FUNCTION__, str, + cross_space); + UI_DEBUG_END; for (list_each(line_node, &ctx->lines)) { line = line_node->data; line_max_cross_size = line->cross_size + cross_space; ui_flexbox_layout_compute_justify_content(ctx, line, &main_axis, &space); -#ifdef UI_DEBUG_ENABLED + UI_DEBUG_BEGIN; UI_DEBUG_MSG("line[%zu]: main_axis=%g, cross_axis=%g, " "space=%g, line_max_cross_size=%g", line->index, main_axis, cross_axis, space, line_max_cross_size); - ui_debug_msg_indent++; -#endif + UI_DEBUG_INDENT_INC; + UI_DEBUG_END; for (list_each(node, &line->items)) { child = node->data; main_axis += space; - main_axis += ui_compute_column_item_layout( - child, cross_axis, main_axis, + main_axis += ui_flexbox_compute_item_layout( + ctx, child, main_axis, cross_axis, s->type_bits.align_items, line_max_cross_size); } cross_axis += line_max_cross_size; -#ifdef UI_DEBUG_ENABLED - ui_debug_msg_indent--; -#endif - } -#ifdef UI_DEBUG_ENABLED - { - UI_WIDGET_STR(ctx->widget, str); - UI_DEBUG_MSG("%s: %s: end", __FUNCTION__, str); - } -#endif + UI_DEBUG_BEGIN; + UI_DEBUG_INDENT_DEC; + UI_DEBUG_END; + } + UI_DEBUG_BEGIN; + UI_WIDGET_STR(ctx->widget, str); + UI_DEBUG_MSG("%s: %s: end", __FUNCTION__, str); + UI_DEBUG_END; } void ui_flexbox_layout_reflow(ui_widget_t *w, ui_resizer_t *resizer) @@ -919,38 +639,29 @@ void ui_flexbox_layout_reflow(ui_widget_t *w, ui_resizer_t *resizer) ctx.column_direction = ui_widget_has_flex_column_direction(w); list_create(&ctx.lines); ui_resizer_init(resizer, w); -#ifdef UI_DEBUG_ENABLED - { - UI_WIDGET_STR(w, str); - UI_WIDGET_SIZE_STR(w, size_str); - UI_DEBUG_MSG("%s: %s: begin, direction=%s, size=%s, " - "content_size=(%g, %g)", - __FUNCTION__, str, - ctx.column_direction ? "column" : "row", size_str, - w->content_box.width, w->content_box.height); - ui_debug_msg_indent++; - } -#endif + UI_DEBUG_BEGIN; + UI_WIDGET_STR(w, str); + UI_WIDGET_SIZE_STR(w, size_str); + UI_DEBUG_MSG("%s: %s: begin, direction=%s, size=%s, " + "content_size=(%g, %g)", + __FUNCTION__, str, ctx.column_direction ? "column" : "row", + size_str, w->content_box.width, w->content_box.height); + UI_DEBUG_INDENT_INC; + UI_DEBUG_END; if (ctx.column_direction) { ui_resizer_load_column_minmaxinfo(resizer); - ui_flexbox_column_layout_load_main_size(&ctx); - ui_flexbox_column_layout_apply_main_size(&ctx); - ui_flexbox_column_layout_reflow(&ctx); } else { ui_resizer_load_row_minmaxinfo(resizer); - ui_flexbox_row_layout_load_main_size(&ctx); - ui_flexbox_row_layout_apply_main_size(&ctx); - ui_flexbox_row_layout_reflow(&ctx); } + ui_flexbox_layout_load_main_size(&ctx); + ui_flexbox_layout_apply_main_size(&ctx); + ui_flexbox_layout_reflow_lines(&ctx); w->proto->resize(w, w->content_box.width, w->content_box.height); list_destroy(&ctx.lines, ui_flexbox_line_destroy); -#ifdef UI_DEBUG_ENABLED - { - ui_debug_msg_indent--; - UI_WIDGET_STR(w, str); - UI_WIDGET_SIZE_STR(w, size_str); - UI_DEBUG_MSG("%s: %s: end, size=%s", __FUNCTION__, str, - size_str); - } -#endif + UI_DEBUG_BEGIN; + UI_DEBUG_INDENT_DEC; + UI_WIDGET_STR(w, str); + UI_WIDGET_SIZE_STR(w, size_str); + UI_DEBUG_MSG("%s: %s: end, size=%s", __FUNCTION__, str, size_str); + UI_DEBUG_END; } From d5bdae91fcace6eaee76515dab23ea61088a6401 Mon Sep 17 00:00:00 2001 From: Liu Date: Wed, 3 Jun 2026 00:16:42 +0800 Subject: [PATCH 24/66] ci: avoid duplicate builds on PR branch push --- .github/workflows/ccpp.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index e0a2aabcb..89cc3a749 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -1,5 +1,13 @@ name: C/C++ CI -on: [push, pull_request] +on: + push: + branches: + - develop + - master + - main + tags: + - 'v*' + pull_request: jobs: format: name: Check C/C++ formatting From 8ffaf66920f715ee8d2b08f40704a1c18e3f1d26 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Jun 2026 22:29:46 +0800 Subject: [PATCH 25/66] refactor(pandagl): unify rounded border and crop corner rendering (#327) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Liu --- lib/pandagl/examples/paint-border/src/main.c | 12 +- lib/pandagl/src/border.c | 1251 ++++++------------ 2 files changed, 438 insertions(+), 825 deletions(-) diff --git a/lib/pandagl/examples/paint-border/src/main.c b/lib/pandagl/examples/paint-border/src/main.c index 261dd5e01..8feb87674 100644 --- a/lib/pandagl/examples/paint-border/src/main.c +++ b/lib/pandagl/examples/paint-border/src/main.c @@ -11,7 +11,7 @@ #include -int paint_background(pd_context_t* ctx, pd_rect_t* box) +int paint_background(pd_context_t *ctx, pd_rect_t *box) { pd_canvas_t image; pd_color_t green = pd_rgb(102, 204, 0); @@ -32,22 +32,18 @@ int paint_background(pd_context_t* ctx, pd_rect_t* box) return 0; } -void paint_border(pd_context_t* ctx, pd_rect_t* box) +void paint_border(pd_context_t *ctx, pd_rect_t *box) { pd_border_t border = { 0 }; pd_color_t black = pd_rgb(0, 0, 0); border.top.color = black; - border.top.style = CSS_KEYWORD_SOLID; border.top.width = 4; border.right.color = black; - border.right.style = CSS_KEYWORD_SOLID; border.right.width = 4; border.bottom.color = black; - border.bottom.style = CSS_KEYWORD_SOLID; border.bottom.width = 4; border.left.color = black; - border.left.style = CSS_KEYWORD_SOLID; border.left.width = 4; border.top_left_radius = 32; border.top_right_radius = 32; @@ -69,7 +65,7 @@ int main(void) border_box.width - border_size * 2, border_box.height - border_size * 2 }; pd_rect_t layer_rect = { 0, 0, border_box.width, border_box.height }; - pd_context_t* paint; + pd_context_t *paint; pd_canvas_init(&canvas); pd_canvas_create(&canvas, 800, 600); @@ -88,4 +84,4 @@ int main(void) pd_write_png_file("test_paint_border.png", &canvas); pd_canvas_destroy(&canvas); return 0; -} \ No newline at end of file +} diff --git a/lib/pandagl/src/border.c b/lib/pandagl/src/border.c index 30eb6edd7..fb5d07ea0 100644 --- a/lib/pandagl/src/border.c +++ b/lib/pandagl/src/border.c @@ -17,7 +17,7 @@ #define CIRCLE_R(R) (R - 0.5) /* Convert screen Y coordinate to geometric Y coordinate */ -#define ToGeoY(Y, CENTER_Y) ((CENTER_Y)-Y) +#define ToGeoY(Y, CENTER_Y) ((CENTER_Y) - Y) /* Convert screen X coordinate to geometric X coordinate */ #define ToGeoX(X, CENTER_X) (X - (CENTER_X)) @@ -26,35 +26,35 @@ #define smooth_right_pixel(PX, X) (uint8_t)((PX)->a * (X - 1.0 * (int)X)) #define BorderRenderContext() \ - int x, y; \ - int right; \ - double circle_x, circle_y; \ - int outer_xi, inner_xi; \ - double outer_x, split_x, inner_x; \ - double outer_d, inner_d; \ + int x, y; \ + int right; \ + double circle_x, circle_y; \ + int outer_xi, inner_xi; \ + double outer_x, split_x, inner_x; \ + double outer_d, inner_d; \ \ - const double r = CIRCLE_R(radius); \ - const double radius_x = y_max(0, r - yline->width); \ - const double radius_y = y_max(0, r - xline->width); \ - const int width = y_max(radius, yline->width); \ + const double r = CIRCLE_R(radius); \ + const double radius_x = y_max(0, r - yline->width); \ + const double radius_y = y_max(0, r - xline->width); \ + const int width = y_max(radius, yline->width); \ \ - pd_rect_t rect; \ - pd_color_t *p; \ - pd_color_t color; + pd_rect_t rect; \ + pd_color_t *p; \ + pd_color_t color; static double ellipse_x(double radius_x, double radius_y, double y) { - double value; - if (radius_x == radius_y) { - value = radius_x * radius_x - y * y; - } else { - value = (1.0 - 1.0 * (y * y) / (radius_y * radius_y)) * - radius_x * radius_x; - } - if (value < 0) { - value = -value; - } - return sqrt(value); + double value; + if (radius_x == radius_y) { + value = radius_x * radius_x - y * y; + } else { + value = (1.0 - 1.0 * (y * y) / (radius_y * radius_y)) * + radius_x * radius_x; + } + if (value < 0) { + value = -value; + } + return sqrt(value); } /** @@ -62,361 +62,147 @@ static double ellipse_x(double radius_x, double radius_y, double y) * Merge the four functions of DrawBorder* into one function and make it simple. */ -/** Draw border top left corner */ -static int draw_border_top_left(pd_canvas_t *dst, int bound_left, int bound_top, - const pd_border_line_t *xline, - const pd_border_line_t *yline, - unsigned int radius) -{ - BorderRenderContext(); - - double cirlce_center_x = bound_left + r; - double circle_center_y = bound_top + r; - double split_k = 1.0 * yline->width / xline->width; - double split_center_x = bound_left + 1.0 * yline->width; - double split_center_y = bound_top + 1.0 * xline->width; - int inner_ellipse_top = (int)split_center_y; - - /* Get the actual rectangle that can be drawn */ - pd_canvas_get_quote_rect(dst, &rect); - dst = pd_canvas_get_quote_source(dst); - if (!pd_canvas_is_valid(dst)) { - return -1; - } - right = y_min(rect.width, bound_left + width); - for (y = 0; y < rect.height; ++y) { - outer_x = 0; - split_x = 0; - inner_x = width; - circle_y = ToGeoY(y, circle_center_y); - if (r > 0 && circle_y >= 0) { - outer_x = r - ellipse_x(r, r, circle_y); - if (radius_y > 0 && y >= inner_ellipse_top) { - inner_x = - r - ellipse_x(radius_x, radius_y, circle_y); - } - } - if (xline->width > 0) { - split_x = split_center_x - - ToGeoY(y, split_center_y) * split_k; - } - outer_x = bound_left + outer_x; - inner_x = bound_left + inner_x; - /* Limit coordinates into the current drawing region */ - outer_x = y_max(0, y_min(right, outer_x)); - inner_x = y_max(0, y_min(right, inner_x)); - outer_xi = y_max(0, (int)outer_x - (int)radius / 2); - inner_xi = y_min(right, (int)inner_x + (int)radius / 2); - p = pd_canvas_pixel_at(dst, rect.x, rect.y + y); - /* Clear the outer pixels */ - for (x = 0; x < outer_xi; ++x, ++p) { - p->alpha = 0; - } - for (; x < inner_xi; ++x, ++p) { - outer_d = -1; - inner_d = inner_x - 1.0 * x; - circle_x = ToGeoX(x, cirlce_center_x); - /* If in the circle */ - if (r > 0 && circle_y >= 0 && circle_x <= 0) { - outer_d = - sqrt(POW2(circle_x) + POW2(circle_y)) - r; - /* If the inside is a circle is not an ellipse, - * Use the same anti-aliasing method - */ - if (radius_x == radius_y && radius_y > 0 && - y >= inner_ellipse_top) { - inner_d = outer_d + r - radius_x; - } - } - if (outer_d >= 1.0) { - p->alpha = 0; - continue; - } - if (x < split_x) { - color = yline->color; - } else { - color = xline->color; - } - if (outer_d >= 0) { - /* Fill the border color if the border width is - * valid */ - if (inner_d - outer_d >= 0.5) { - *p = color; - } - p->a = smooth_left_pixel(p, outer_d); - } else if (inner_d >= 1.0) { - pd_over_pixel(p, &color, 1.0); - } else if (inner_d >= 0) { - color.a = smooth_right_pixel(&color, inner_d); - pd_over_pixel(p, &color, 1.0); - } else { - break; - } - } - } - return 0; -} - -static int draw_border_top_right(pd_canvas_t *dst, int bound_left, - int bound_top, const pd_border_line_t *xline, - const pd_border_line_t *yline, - unsigned int radius) -{ - BorderRenderContext(); - - double circle_center_y = bound_top + r; - double circle_center_x = bound_left + width - 1.0 * radius - 0.5; - double split_k = 1.0 * yline->width / xline->width; - double split_center_x = bound_left + width - 1.0 * yline->width; - double split_center_y = bound_top + 1.0 * xline->width; - double inner_ellipse_top = split_center_y; - - /* Get the actual rectangle that can be drawn */ - pd_canvas_get_quote_rect(dst, &rect); - dst = pd_canvas_get_quote_source(dst); - if (!pd_canvas_is_valid(dst)) { - return -1; - } - right = y_min(rect.width, bound_left + width); - for (y = 0; y < rect.height; ++y) { - outer_x = width; - split_x = 0; - inner_x = -1.0; - circle_y = ToGeoY(y, circle_center_y); - if (r > 0 && circle_y >= 0) { - outer_x = width - radius + ellipse_x(r, r, circle_y); - if (radius_y > 0 && y >= inner_ellipse_top) { - inner_x = - width - radius - 0.5 + - ellipse_x(radius_x, radius_y, circle_y); - } - } - if (xline->width > 0) { - split_x = split_center_x + - ToGeoY(y, split_center_y) * split_k; - } - outer_x = bound_left + outer_x; - inner_x = bound_left + inner_x; - /* Limit coordinates into the current drawing region */ - outer_x = y_max(0, y_min(right, outer_x)); - inner_x = y_max(-1.0, y_min(outer_x, inner_x)); - inner_xi = y_max(0, (int)inner_x - (int)radius / 2); - outer_xi = y_min(right, (int)outer_x + (int)radius / 2); - p = pd_canvas_pixel_at(dst, rect.x + inner_xi, rect.y + y); - for (x = inner_xi; x < outer_xi; ++x, ++p) { - outer_d = -1.0; - inner_d = x - inner_x; - circle_x = ToGeoX(x, circle_center_x); - if (r > 0 && circle_y >= 0 && circle_x >= 0) { - outer_d = - sqrt(POW2(circle_x) + POW2(circle_y)) - r; - if (radius_x == radius_y && radius_y > 0 && - y >= inner_ellipse_top) { - inner_d = outer_d + r - radius_x; - } - } - if (outer_d >= 1.0) { - break; - } - if (x < split_x) { - color = xline->color; - } else { - color = yline->color; - } - if (outer_d >= 0) { - if (inner_d - outer_d >= 0.5) { - *p = color; - } - p->a = smooth_left_pixel(p, outer_d); - } else if (inner_d >= 0.5) { - pd_over_pixel(p, &color, 1.0); - } else if (inner_d >= 0) { - color.a = smooth_right_pixel(&color, inner_d); - pd_over_pixel(p, &color, 1.0); - } - } - /* Clear the outer pixels */ - for (; x < right; ++x, ++p) { - p->alpha = 0; - } - } - return 0; -} - -static int draw_border_bottom_left(pd_canvas_t *dst, int bound_left, - int bound_top, const pd_border_line_t *xline, - const pd_border_line_t *yline, - unsigned int radius) -{ - BorderRenderContext(); - - int height = y_max(radius, xline->width); - double cirlce_center_x = bound_left + r; - double circle_center_y = bound_top + height - 1.0 * radius - 0.5; - double split_k = 1.0 * yline->width / xline->width; - double split_center_x = bound_left + 1.0 * yline->width; - double split_center_y = bound_top + height - 1.0 * xline->width; - double inner_ellipse_bottom = circle_center_y + radius_y; +typedef struct pd_corner_flags_t { + int is_right; + int is_bottom; +} pd_corner_flags_t; - /* Get the actual rectangle that can be drawn */ - pd_canvas_get_quote_rect(dst, &rect); - dst = pd_canvas_get_quote_source(dst); - if (!pd_canvas_is_valid(dst)) { - return -1; - } - right = y_min(rect.width, bound_left + width); - for (y = 0; y < rect.height; ++y) { - outer_x = 0; - split_x = 0; - inner_x = width; - circle_y = ToGeoY(y, circle_center_y); - if (r > 0 && circle_y <= 0) { - outer_x = r - ellipse_x(r, r, circle_y); - if (radius_y > 0 && y <= inner_ellipse_bottom) { - inner_x = - r - ellipse_x(radius_x, radius_y, circle_y); - } - } - if (xline->width > 0) { - split_x = split_center_x + - ToGeoY(y, split_center_y) * split_k; - } - outer_x = bound_left + outer_x; - inner_x = bound_left + inner_x; - /* Limit coordinates into the current drawing region */ - outer_x = y_max(0, y_min(right, outer_x)); - inner_x = y_max(0, y_min(right, inner_x)); - outer_xi = y_max(0, (int)outer_x - (int)radius / 2); - inner_xi = y_min(right, (int)inner_x + (int)radius / 2); - p = pd_canvas_pixel_at(dst, rect.x, rect.y + y); - for (x = 0; x < outer_xi; ++x, ++p) { - p->alpha = 0; - } - for (; x < inner_xi; ++x, ++p) { - outer_d = -1; - inner_d = inner_x - 1.0 * x; - circle_x = ToGeoX(x, cirlce_center_x); - if (r > 0 && circle_y <= 0 && circle_x <= 0) { - outer_d = - sqrt(POW2(circle_x) + POW2(circle_y)) - r; - if (radius_x == radius_y && radius_y > 0 && - y <= inner_ellipse_bottom) { - inner_d = outer_d + r - radius_x; - } - } - if (outer_d >= 1.0) { - p->alpha = 0; - continue; - } - if (x < split_x) { - color = yline->color; - } else { - color = xline->color; - } - if (outer_d >= 0) { - if (inner_d - outer_d >= 0.5) { - *p = color; - } - p->a = smooth_left_pixel(p, outer_d); - } else if (inner_d >= 1.0) { - pd_over_pixel(p, &color, 1.0); - } else if (inner_d >= 0) { - color.a = smooth_right_pixel(&color, inner_d); - pd_over_pixel(p, &color, 1.0); - } else { - break; - } - } - } - return 0; -} - -static int draw_border_bottom_right(pd_canvas_t *dst, int bound_left, - int bound_top, - const pd_border_line_t *xline, - const pd_border_line_t *yline, - unsigned int radius) +static int draw_border_corner(pd_canvas_t *dst, int bound_left, int bound_top, + const pd_border_line_t *xline, + const pd_border_line_t *yline, + unsigned int radius, + const pd_corner_flags_t *flags) { - BorderRenderContext(); - - int height = y_max(radius, xline->width); - double circle_center_y = bound_top + height - 1.0 * radius - 0.5; - double circle_center_x = bound_left + width - 1.0 * radius - 0.5; - double split_k = 1.0 * yline->width / xline->width; - double split_center_x = bound_left + width - 1.0 * yline->width; - double split_center_y = bound_top + height - 1.0 * xline->width; - double inner_ellipse_bottom = circle_center_y + radius_y; - - /* Get the actual rectangle that can be drawn */ - pd_canvas_get_quote_rect(dst, &rect); - dst = pd_canvas_get_quote_source(dst); - if (!pd_canvas_is_valid(dst)) { - return -1; - } - right = y_min(rect.width, bound_left + width); - for (y = 0; y < rect.height; ++y) { - outer_x = width; - split_x = 0; - inner_x = -1.0; - circle_y = ToGeoY(y, circle_center_y); - if (r > 0 && circle_y <= 0) { - outer_x = width - r + ellipse_x(r, r, circle_y); - if (radius_y > 0 && y <= inner_ellipse_bottom && - y >= circle_center_y) { - inner_x = - width - radius - 0.5 + - ellipse_x(radius_x, radius_y, circle_y); - } - } - if (xline->width > 0) { - split_x = split_center_x - - ToGeoY(y, split_center_y) * split_k; - } - outer_x = bound_left + outer_x; - inner_x = bound_left + inner_x; - outer_x = y_max(0, y_min(right, outer_x)); - inner_x = y_max(-1.0, y_min(outer_x, inner_x)); - inner_xi = y_max(0, (int)inner_x - (int)radius / 2); - outer_xi = y_min(right, (int)outer_x + (int)radius / 2); - p = pd_canvas_pixel_at(dst, rect.x + inner_xi, rect.y + y); - for (x = inner_xi; x < outer_xi; ++x, ++p) { - outer_d = -1.0; - inner_d = 1.0 * x - inner_x; - circle_x = ToGeoX(x, circle_center_x); - if (r > 0 && circle_y <= 0 && circle_x >= 0) { - outer_d = - sqrt(POW2(circle_x) + POW2(circle_y)) - r; - if (radius_x == radius_y && radius_y > 0 && - y <= inner_ellipse_bottom) { - inner_d = outer_d + r - radius_x; - } - } - if (outer_d >= 1.0) { - break; - } - if (x < split_x) { - color = xline->color; - } else { - color = yline->color; - } - if (outer_d >= 0) { - if (inner_d - outer_d >= 0.5) { - *p = color; - } - p->a = smooth_left_pixel(p, outer_d); - } else if (inner_d >= 0.5) { - pd_over_pixel(p, &color, 1.0); - } else if (inner_d >= 0) { - color.a = smooth_right_pixel(&color, inner_d); - pd_over_pixel(p, &color, 1.0); - } - } - /* Clear the outer pixels */ - for (; x < right; ++x, ++p) { - p->alpha = 0; - } - } - return 0; + BorderRenderContext(); + int bottom_corner_height = y_max(radius, xline->width); + double circle_center_y = + bound_top + + (flags->is_bottom ? bottom_corner_height - 1.0 * radius - 0.5 : r); + double circle_center_x = + bound_left + (flags->is_right ? width - 1.0 * radius - 0.5 : r); + double split_slope = + xline->width > 0 ? 1.0 * yline->width / xline->width : 0.0; + double split_center_x = + bound_left + + (flags->is_right ? width - 1.0 * yline->width : 1.0 * yline->width); + double split_center_y = + bound_top + (flags->is_bottom + ? bottom_corner_height - 1.0 * xline->width + : 1.0 * xline->width); + double inner_ellipse_limit = + flags->is_bottom ? circle_center_y + radius_y : split_center_y; + int split_sign = flags->is_right == flags->is_bottom ? -1 : 1; + + /* Get the actual rectangle that can be drawn */ + pd_canvas_get_quote_rect(dst, &rect); + dst = pd_canvas_get_quote_source(dst); + if (!pd_canvas_is_valid(dst)) { + return -1; + } + right = y_min(rect.width, bound_left + width); + for (y = 0; y < rect.height; ++y) { + outer_x = flags->is_right ? width : 0; + split_x = 0; + inner_x = flags->is_right ? -1.0 : width; + circle_y = ToGeoY(y, circle_center_y); + if (r > 0 && + (flags->is_bottom ? circle_y <= 0 : circle_y >= 0)) { + int should_draw_inner_ellipse = !flags->is_bottom || + !flags->is_right || + y >= circle_center_y; + outer_x = + flags->is_right + ? width - radius + ellipse_x(r, r, circle_y) + : r - ellipse_x(r, r, circle_y); + if (radius_y > 0 && should_draw_inner_ellipse && + (flags->is_bottom ? y <= inner_ellipse_limit + : y >= inner_ellipse_limit)) { + inner_x = + flags->is_right + ? width - radius - 0.5 + + ellipse_x(radius_x, radius_y, + circle_y) + : r - ellipse_x(radius_x, radius_y, + circle_y); + } + } + if (xline->width > 0) { + split_x = split_center_x + + split_sign * ToGeoY(y, split_center_y) * + split_slope; + } + outer_x = bound_left + outer_x; + inner_x = bound_left + inner_x; + outer_x = y_max(0, y_min(right, outer_x)); + if (flags->is_right) { + inner_x = y_max(-1.0, y_min(outer_x, inner_x)); + inner_xi = y_max(0, (int)inner_x - (int)radius / 2); + outer_xi = y_min(right, (int)outer_x + (int)radius / 2); + x = inner_xi; + p = pd_canvas_pixel_at(dst, rect.x + inner_xi, + rect.y + y); + } else { + inner_x = y_max(0, y_min(right, inner_x)); + outer_xi = y_max(0, (int)outer_x - (int)radius / 2); + inner_xi = y_min(right, (int)inner_x + (int)radius / 2); + x = 0; + p = pd_canvas_pixel_at(dst, rect.x, rect.y + y); + for (; x < outer_xi; ++x, ++p) { + p->alpha = 0; + } + } + for (; x < (flags->is_right ? outer_xi : inner_xi); ++x, ++p) { + outer_d = -1.0; + inner_d = flags->is_right ? x - inner_x : inner_x - x; + circle_x = ToGeoX(x, circle_center_x); + if (r > 0 && + (flags->is_bottom ? circle_y <= 0 + : circle_y >= 0) && + (flags->is_right ? circle_x >= 0 : circle_x <= 0)) { + outer_d = + sqrt(POW2(circle_x) + POW2(circle_y)) - r; + if (radius_x == radius_y && radius_y > 0 && + (flags->is_bottom + ? y <= inner_ellipse_limit + : y >= inner_ellipse_limit)) { + inner_d = outer_d + r - radius_x; + } + } + if (outer_d >= 1.0) { + if (flags->is_right) { + break; + } + p->alpha = 0; + continue; + } + if (x < split_x) { + color = flags->is_right ? xline->color + : yline->color; + } else { + color = flags->is_right ? yline->color + : xline->color; + } + if (outer_d >= 0) { + if (inner_d - outer_d >= 0.5) { + *p = color; + } + p->a = smooth_left_pixel(p, outer_d); + } else if (inner_d >= (flags->is_right ? 0.5 : 1.0)) { + pd_over_pixel(p, &color, 1.0); + } else if (inner_d >= 0) { + color.a = smooth_right_pixel(&color, inner_d); + pd_over_pixel(p, &color, 1.0); + } else if (!flags->is_right) { + break; + } + } + if (flags->is_right) { + for (; x < right; ++x, ++p) { + p->alpha = 0; + } + } + } + return 0; } /** @@ -426,452 +212,283 @@ static int draw_border_bottom_right(pd_canvas_t *dst, int bound_left, */ /** Crop the top left corner of the content area */ -static int crop_content_top_left(pd_canvas_t *dst, int bound_left, - int bound_top, double radius_x, - double radius_y) -{ - int xi, yi; - int outer_xi; - double x, y, d; - double outer_x; - double center_x, center_y; - - pd_rect_t rect; - pd_color_t *p; - - radius_x -= 0.5; - radius_y -= 0.5; - center_x = bound_left + radius_x; - center_y = bound_top + radius_y; - pd_canvas_get_quote_rect(dst, &rect); - dst = pd_canvas_get_quote_source(dst); - if (!pd_canvas_is_valid(dst)) { - return -1; - } - for (yi = 0; yi < rect.height; ++yi) { - y = ToGeoY(yi, center_y); - x = ellipse_x(radius_x + 1.0, radius_y + 1.0, y); - outer_xi = (int)(center_x - x); - outer_xi = y_max(0, y_min(outer_xi, rect.width)); - p = pd_canvas_pixel_at(dst, rect.x, rect.y + yi); - for (xi = 0; xi < outer_xi; ++xi, ++p) { - p->alpha = 0; - } - /* If inner ellipse is circle */ - if (radius_x == radius_y) { - for (; xi < rect.width; ++xi, ++p) { - x = ToGeoX(xi, center_x); - d = sqrt(x * x + y * y) - radius_x; - if (d >= 1.0) { - p->alpha = 0; - } else if (d >= 0) { - p->alpha = smooth_left_pixel(p, d); - } else { - break; - } - } - } else { - outer_x = - ToGeoX(ellipse_x(radius_x, radius_y, y), center_x); - for (; xi < rect.width; ++xi, ++p) { - x = ToGeoX(xi, center_x); - d = x - outer_x; - if (d >= 1.0) { - p->alpha = 0; - } else if (d >= 0) { - p->alpha = smooth_left_pixel(p, d); - } else { - break; - } - } - } - } - return 0; -} - -static int crop_content_top_right(pd_canvas_t *dst, int bound_left, - int bound_top, double radius_x, - double radius_y) -{ - int xi, yi; - int outer_xi; - double x, y, d; - double outer_x; - double center_x, center_y; - - pd_rect_t rect; - pd_color_t *p; - - radius_x -= 0.5; - radius_y -= 0.5; - center_x = bound_left; - center_y = bound_top + radius_y; - pd_canvas_get_quote_rect(dst, &rect); - dst = pd_canvas_get_quote_source(dst); - if (!pd_canvas_is_valid(dst)) { - return -1; - } - for (yi = 0; yi < rect.height; ++yi) { - y = ToGeoY(yi, center_y); - x = ellipse_x(y_max(0, radius_x - 1), y_max(0, radius_y - 1), - y); - outer_xi = (int)(center_x + x); - outer_xi = y_max(0, outer_xi); - p = pd_canvas_pixel_at(dst, rect.x + outer_xi, rect.y + yi); - if (radius_x == radius_y) { - for (xi = outer_xi; xi < rect.width; ++xi, ++p) { - x = ToGeoX(xi, center_x); - d = sqrt(x * x + y * y) - radius_x; - if (d >= 1.0) { - break; - } - if (d >= 0) { - p->alpha = smooth_left_pixel(p, d); - } - } - } else { - outer_x = - ToGeoX(ellipse_x(radius_x, radius_y, y), center_x); - for (xi = outer_xi; xi < rect.width; ++xi, ++p) { - x = ToGeoX(xi, center_x); - d = x - outer_x; - if (d >= 1.0) { - break; - } - if (d >= 0) { - p->alpha = smooth_left_pixel(p, d); - } - } - } - for (; xi < rect.width; ++xi, ++p) { - p->alpha = 0; - } - } - return 0; -} - -static int crop_content_bottom_left(pd_canvas_t *dst, int bound_left, - int bound_top, double radius_x, - double radius_y) -{ - int xi, yi; - int outer_xi; - double x, y, d; - double outer_x; - double center_x, center_y; - - pd_rect_t rect; - pd_color_t *p; - - radius_x -= 0.5; - radius_y -= 0.5; - center_x = bound_left + radius_x; - center_y = bound_top; - pd_canvas_get_quote_rect(dst, &rect); - dst = pd_canvas_get_quote_source(dst); - if (!pd_canvas_is_valid(dst)) { - return -1; - } - for (yi = 0; yi < rect.height; ++yi) { - y = ToGeoY(yi, center_y); - x = ellipse_x(radius_x + 1.0, radius_y + 1.0, y); - outer_xi = (int)(center_x - x); - outer_xi = y_max(0, y_min(outer_xi, rect.width)); - p = pd_canvas_pixel_at(dst, rect.x, rect.y + yi); - for (xi = 0; xi < outer_xi; ++xi, ++p) { - p->alpha = 0; - } - if (radius_x == radius_y) { - for (; xi < rect.width; ++xi, ++p) { - x = ToGeoX(xi, center_x); - d = sqrt(x * x + y * y) - radius_x; - if (d >= 1.0) { - p->alpha = 0; - } else if (d >= 0) { - p->alpha = smooth_left_pixel(p, d); - } else { - break; - } - } - } else { - outer_x = - ToGeoX(ellipse_x(radius_x, radius_y, y), center_x); - for (; xi < rect.width; ++xi, ++p) { - x = ToGeoX(xi, center_x); - d = x - outer_x; - if (d >= 1.0) { - p->alpha = 0; - } else if (d >= 0) { - p->alpha = smooth_left_pixel(p, d); - } else { - break; - } - } - } - } - return 0; -} - -static int crop_content_bottom_right(pd_canvas_t *dst, int bound_left, - int bound_top, double radius_x, - double radius_y) +static int crop_content_corner(pd_canvas_t *dst, int bound_left, int bound_top, + double radius_x, double radius_y, + const pd_corner_flags_t *flags) { - int xi, yi; - int outer_xi; - double x, y, d; - double outer_x; - double center_x, center_y; - - pd_rect_t rect; - pd_color_t *p; - - radius_x -= 0.5; - radius_y -= 0.5; - center_x = bound_left; - center_y = bound_top; - pd_canvas_get_quote_rect(dst, &rect); - dst = pd_canvas_get_quote_source(dst); - if (!pd_canvas_is_valid(dst)) { - return -1; - } - for (yi = 0; yi < rect.height; ++yi) { - y = ToGeoY(yi, center_y); - x = ellipse_x(y_max(0, radius_x - 1), y_max(0, radius_y - 1), - y); - outer_xi = (int)(center_x + x); - outer_xi = y_max(0, outer_xi); - p = pd_canvas_pixel_at(dst, rect.x + outer_xi, rect.y + yi); - if (radius_x == radius_y) { - for (xi = outer_xi; xi < rect.width; ++xi, ++p) { - x = ToGeoX(xi, center_x); - d = sqrt(x * x + y * y) - radius_x; - if (d >= 1.0) { - break; - } - if (d >= 0) { - p->alpha = smooth_left_pixel(p, d); - } - } - } else { - outer_x = - ToGeoX(ellipse_x(radius_x, radius_y, y), center_x); - for (xi = outer_xi; xi < rect.width; ++xi, ++p) { - x = ToGeoX(xi, center_x); - d = x - outer_x; - if (d >= 1.0) { - break; - } - if (d >= 0) { - p->alpha = smooth_left_pixel(p, d); - } - } - } - for (; xi < rect.width; ++xi, ++p) { - p->alpha = 0; - } - } - return 0; + int xi, yi; + int outer_xi; + double x, y, d; + double outer_x; + double center_x, center_y; + + pd_rect_t rect; + pd_color_t *p; + + radius_x -= 0.5; + radius_y -= 0.5; + center_x = flags->is_right ? bound_left : bound_left + radius_x; + center_y = flags->is_bottom ? bound_top : bound_top + radius_y; + pd_canvas_get_quote_rect(dst, &rect); + dst = pd_canvas_get_quote_source(dst); + if (!pd_canvas_is_valid(dst)) { + return -1; + } + for (yi = 0; yi < rect.height; ++yi) { + y = ToGeoY(yi, center_y); + x = flags->is_right + ? ellipse_x(y_max(0, radius_x - 1), + y_max(0, radius_y - 1), y) + : ellipse_x(radius_x + 1.0, radius_y + 1.0, y); + outer_xi = + flags->is_right ? (int)(center_x + x) : (int)(center_x - x); + if (flags->is_right) { + outer_xi = y_max(0, outer_xi); + xi = outer_xi; + p = pd_canvas_pixel_at(dst, rect.x + outer_xi, + rect.y + yi); + } else { + outer_xi = y_max(0, y_min(outer_xi, rect.width)); + xi = 0; + p = pd_canvas_pixel_at(dst, rect.x, rect.y + yi); + for (; xi < outer_xi; ++xi, ++p) { + p->alpha = 0; + } + } + if (radius_x == radius_y) { + for (; xi < rect.width; ++xi, ++p) { + x = ToGeoX(xi, center_x); + d = sqrt(x * x + y * y) - radius_x; + if (d >= 1.0) { + if (flags->is_right) { + break; + } + p->alpha = 0; + } else if (d >= 0) { + p->alpha = smooth_left_pixel(p, d); + } else if (!flags->is_right) { + break; + } + } + } else { + outer_x = + ToGeoX(ellipse_x(radius_x, radius_y, y), center_x); + for (; xi < rect.width; ++xi, ++p) { + x = ToGeoX(xi, center_x); + d = x - outer_x; + if (d >= 1.0) { + if (flags->is_right) { + break; + } + p->alpha = 0; + } else if (d >= 0) { + p->alpha = smooth_left_pixel(p, d); + } else if (!flags->is_right) { + break; + } + } + } + if (flags->is_right) { + for (; xi < rect.width; ++xi, ++p) { + p->alpha = 0; + } + } + } + return 0; } int pd_crop_border_content(pd_context_t *ctx, const pd_border_t *border, - const pd_rect_t *box) + const pd_rect_t *box) { - pd_canvas_t canvas; - pd_rect_t bound, rect; - - int radius; - int bound_top, bound_left; - - radius = border->top_left_radius; - bound.x = box->x + border->left.width; - bound.y = box->y + border->top.width; - bound.width = radius - border->left.width; - bound.height = radius - border->top.width; - if (bound.width > 0 && bound.height > 0 && - pd_rect_overlap(&bound, &ctx->rect, &rect)) { - bound_left = bound.x - rect.x; - bound_top = bound.y - rect.y; - rect.x -= ctx->rect.x; - rect.y -= ctx->rect.y; - pd_canvas_quote(&canvas, &ctx->canvas, &rect); - crop_content_top_left(&canvas, bound_left, bound_top, - bound.width, bound.height); - } - - radius = border->top_right_radius; - bound.x = box->x + box->width - radius; - bound.y = box->y + border->top.width; - bound.width = radius - border->right.width; - bound.height = radius - border->top.width; - if (bound.width > 0 && bound.height > 0 && - pd_rect_overlap(&bound, &ctx->rect, &rect)) { - bound_left = bound.x - rect.x; - bound_top = bound.y - rect.y; - rect.x -= ctx->rect.x; - rect.y -= ctx->rect.y; - pd_canvas_quote(&canvas, &ctx->canvas, &rect); - crop_content_top_right(&canvas, bound_left, bound_top, - bound.width, bound.height); - } - - radius = border->bottom_left_radius; - bound.x = box->x + border->left.width; - bound.y = box->y + box->height - radius; - bound.width = radius - border->left.width; - bound.height = radius - border->bottom.width; - if (bound.width > 0 && bound.height > 0 && - pd_rect_overlap(&bound, &ctx->rect, &rect)) { - bound_left = bound.x - rect.x; - bound_top = bound.y - rect.y; - rect.x -= ctx->rect.x; - rect.y -= ctx->rect.y; - pd_canvas_quote(&canvas, &ctx->canvas, &rect); - crop_content_bottom_left(&canvas, bound_left, bound_top, - bound.width, bound.height); - } - - radius = border->bottom_right_radius; - bound.x = box->x + box->width - radius; - bound.y = box->y + box->height - radius; - ; - bound.width = radius - border->right.width; - bound.height = radius - border->bottom.width; - if (bound.width > 0 && bound.height > 0 && - pd_rect_overlap(&bound, &ctx->rect, &rect)) { - bound_left = bound.x - rect.x; - bound_top = bound.y - rect.y; - rect.x -= ctx->rect.x; - rect.y -= ctx->rect.y; - pd_canvas_quote(&canvas, &ctx->canvas, &rect); - crop_content_bottom_right(&canvas, bound_left, bound_top, - bound.width, bound.height); - } - return 0; + pd_canvas_t canvas; + pd_rect_t bound, rect; + int bound_top, bound_left; + int i; + struct { + pd_corner_flags_t flags; + int x, y; + int width, height; + } corners[] = { + { + .flags = { .is_right = 0, .is_bottom = 0 }, + .x = box->x + border->left.width, + .y = box->y + border->top.width, + .width = border->top_left_radius - border->left.width, + .height = border->top_left_radius - border->top.width, + }, + { + .flags = { .is_right = 1, .is_bottom = 0 }, + .x = box->x + box->width - border->top_right_radius, + .y = box->y + border->top.width, + .width = border->top_right_radius - border->right.width, + .height = border->top_right_radius - border->top.width, + }, + { + .flags = { .is_right = 0, .is_bottom = 1 }, + .x = box->x + border->left.width, + .y = box->y + box->height - border->bottom_left_radius, + .width = border->bottom_left_radius - border->left.width, + .height = border->bottom_left_radius - border->bottom.width, + }, + { + .flags = { .is_right = 1, .is_bottom = 1 }, + .x = box->x + box->width - border->bottom_right_radius, + .y = box->y + box->height - border->bottom_right_radius, + .width = border->bottom_right_radius - border->right.width, + .height = + border->bottom_right_radius - border->bottom.width, + }, + }; + + for (i = 0; i < 4; ++i) { + bound.x = corners[i].x; + bound.y = corners[i].y; + bound.width = corners[i].width; + bound.height = corners[i].height; + if (bound.width > 0 && bound.height > 0 && + pd_rect_overlap(&bound, &ctx->rect, &rect)) { + bound_left = bound.x - rect.x; + bound_top = bound.y - rect.y; + rect.x -= ctx->rect.x; + rect.y -= ctx->rect.y; + pd_canvas_quote(&canvas, &ctx->canvas, &rect); + crop_content_corner(&canvas, bound_left, bound_top, + bound.width, bound.height, + &corners[i].flags); + } + } + return 0; } int pd_paint_border(pd_context_t *ctx, const pd_border_t *border, - const pd_rect_t *box) + const pd_rect_t *box) { - pd_canvas_t canvas; - pd_rect_t bound, rect; - - int bound_top, bound_left; - int tl_width = y_max(border->top_left_radius, border->left.width); - int tl_height = y_max(border->top_left_radius, border->top.width); - int tr_width = y_max(border->top_right_radius, border->right.width); - int tr_height = y_max(border->top_right_radius, border->top.width); - int bl_width = y_max(border->bottom_left_radius, border->left.width); - int bl_height = y_max(border->bottom_left_radius, border->bottom.width); - int br_width = y_max(border->bottom_right_radius, border->right.width); - int br_height = - y_max(border->bottom_right_radius, border->bottom.width); - - if (!pd_canvas_is_valid(&ctx->canvas)) { - return -1; - } - /* Draw border top left angle */ - bound.x = box->x; - bound.y = box->y; - bound.width = tl_width; - bound.height = tl_height; - if (pd_rect_overlap(&bound, &ctx->rect, &rect)) { - bound_left = bound.x - rect.x; - bound_top = bound.y - rect.y; - rect.x -= ctx->rect.x; - rect.y -= ctx->rect.y; - pd_canvas_quote(&canvas, &ctx->canvas, &rect); - draw_border_top_left(&canvas, bound_left, bound_top, - &border->top, &border->left, - border->top_left_radius); - } - /* Draw border top right angle */ - bound.y = box->y; - bound.width = tr_width; - bound.height = tr_height; - bound.x = box->x + box->width - bound.width; - if (pd_rect_overlap(&bound, &ctx->rect, &rect)) { - bound_left = bound.x - rect.x; - bound_top = bound.y - rect.y; - rect.x -= ctx->rect.x; - rect.y -= ctx->rect.y; - pd_canvas_quote(&canvas, &ctx->canvas, &rect); - draw_border_top_right(&canvas, bound_left, bound_top, - &border->top, &border->right, - border->top_right_radius); - } - /* Draw border bottom left angle */ - bound.x = box->x; - bound.width = bl_width; - bound.height = bl_height; - bound.y = box->y + box->height - bound.height; - if (pd_rect_overlap(&bound, &ctx->rect, &rect)) { - bound_left = bound.x - rect.x; - bound_top = bound.y - rect.y; - rect.x -= ctx->rect.x; - rect.y -= ctx->rect.y; - pd_canvas_quote(&canvas, &ctx->canvas, &rect); - draw_border_bottom_left(&canvas, bound_left, bound_top, - &border->bottom, &border->left, - border->bottom_left_radius); - } - /* Draw border bottom right angle */ - bound.width = br_width; - bound.height = br_height; - bound.x = box->x + box->width - bound.width; - bound.y = box->y + box->height - bound.height; - if (pd_rect_overlap(&bound, &ctx->rect, &rect)) { - bound_left = bound.x - rect.x; - bound_top = bound.y - rect.y; - rect.x -= ctx->rect.x; - rect.y -= ctx->rect.y; - pd_canvas_quote(&canvas, &ctx->canvas, &rect); - draw_border_bottom_right(&canvas, bound_left, bound_top, - &border->bottom, &border->right, - border->bottom_right_radius); - } - /* Draw top border line */ - bound.x = box->x + tl_width; - bound.y = box->y; - bound.width = box->width - tl_width - tr_width; - bound.height = border->top.width; - if (pd_rect_overlap(&bound, &ctx->rect, &bound)) { - bound.x -= ctx->rect.x; - bound.y -= ctx->rect.y; - pd_canvas_quote(&canvas, &ctx->canvas, &bound); - pd_canvas_fill(&canvas, border->top.color); - } - /* Draw bottom border line */ - bound.x = box->x + bl_width; - bound.y = box->y + box->height - border->bottom.width; - bound.width = box->width - bl_width - br_width; - bound.height = border->bottom.width; - if (pd_rect_overlap(&bound, &ctx->rect, &bound)) { - bound.x -= ctx->rect.x; - bound.y -= ctx->rect.y; - pd_canvas_quote(&canvas, &ctx->canvas, &bound); - pd_canvas_fill(&canvas, border->bottom.color); - } - /* Draw left border line */ - bound.y = box->y + tl_height; - bound.x = box->x; - bound.width = border->left.width; - bound.height = box->height - tl_height - bl_height; - if (pd_rect_overlap(&bound, &ctx->rect, &bound)) { - bound.x -= ctx->rect.x; - bound.y -= ctx->rect.y; - pd_canvas_quote(&canvas, &ctx->canvas, &bound); - pd_canvas_fill(&canvas, border->left.color); - } - /* Draw right border line */ - bound.x = box->x + box->width - border->right.width; - bound.y = box->y + tr_height; - bound.width = border->right.width; - bound.height = box->height - tr_height - br_height; - if (pd_rect_overlap(&bound, &ctx->rect, &bound)) { - bound.x -= ctx->rect.x; - bound.y -= ctx->rect.y; - pd_canvas_quote(&canvas, &ctx->canvas, &bound); - pd_canvas_fill(&canvas, border->right.color); - } - return 0; + pd_canvas_t canvas; + pd_rect_t bound, rect; + int bound_top, bound_left; + int i; + int tl_width = y_max(border->top_left_radius, border->left.width); + int tl_height = y_max(border->top_left_radius, border->top.width); + int tr_width = y_max(border->top_right_radius, border->right.width); + int tr_height = y_max(border->top_right_radius, border->top.width); + int bl_width = y_max(border->bottom_left_radius, border->left.width); + int bl_height = y_max(border->bottom_left_radius, border->bottom.width); + int br_width = y_max(border->bottom_right_radius, border->right.width); + int br_height = + y_max(border->bottom_right_radius, border->bottom.width); + struct { + pd_corner_flags_t flags; + int x, y; + int width, height; + const pd_border_line_t *xline; + const pd_border_line_t *yline; + unsigned int radius; + } corners[] = { + { + .flags = { .is_right = 0, .is_bottom = 0 }, + .x = box->x, + .y = box->y, + .width = tl_width, + .height = tl_height, + .xline = &border->top, + .yline = &border->left, + .radius = border->top_left_radius, + }, + { + .flags = { .is_right = 1, .is_bottom = 0 }, + .x = box->x + box->width - tr_width, + .y = box->y, + .width = tr_width, + .height = tr_height, + .xline = &border->top, + .yline = &border->right, + .radius = border->top_right_radius, + }, + { + .flags = { .is_right = 0, .is_bottom = 1 }, + .x = box->x, + .y = box->y + box->height - bl_height, + .width = bl_width, + .height = bl_height, + .xline = &border->bottom, + .yline = &border->left, + .radius = border->bottom_left_radius, + }, + { + .flags = { .is_right = 1, .is_bottom = 1 }, + .x = box->x + box->width - br_width, + .y = box->y + box->height - br_height, + .width = br_width, + .height = br_height, + .xline = &border->bottom, + .yline = &border->right, + .radius = border->bottom_right_radius, + }, + }; + + if (!pd_canvas_is_valid(&ctx->canvas)) { + return -1; + } + for (i = 0; i < 4; ++i) { + bound.x = corners[i].x; + bound.y = corners[i].y; + bound.width = corners[i].width; + bound.height = corners[i].height; + if (pd_rect_overlap(&bound, &ctx->rect, &rect)) { + bound_left = bound.x - rect.x; + bound_top = bound.y - rect.y; + rect.x -= ctx->rect.x; + rect.y -= ctx->rect.y; + pd_canvas_quote(&canvas, &ctx->canvas, &rect); + draw_border_corner(&canvas, bound_left, bound_top, + corners[i].xline, corners[i].yline, + corners[i].radius, + &corners[i].flags); + } + } + /* Draw top border line */ + bound.x = box->x + tl_width; + bound.y = box->y; + bound.width = box->width - tl_width - tr_width; + bound.height = border->top.width; + if (pd_rect_overlap(&bound, &ctx->rect, &bound)) { + bound.x -= ctx->rect.x; + bound.y -= ctx->rect.y; + pd_canvas_quote(&canvas, &ctx->canvas, &bound); + pd_canvas_fill(&canvas, border->top.color); + } + /* Draw bottom border line */ + bound.x = box->x + bl_width; + bound.y = box->y + box->height - border->bottom.width; + bound.width = box->width - bl_width - br_width; + bound.height = border->bottom.width; + if (pd_rect_overlap(&bound, &ctx->rect, &bound)) { + bound.x -= ctx->rect.x; + bound.y -= ctx->rect.y; + pd_canvas_quote(&canvas, &ctx->canvas, &bound); + pd_canvas_fill(&canvas, border->bottom.color); + } + /* Draw left border line */ + bound.y = box->y + tl_height; + bound.x = box->x; + bound.width = border->left.width; + bound.height = box->height - tl_height - bl_height; + if (pd_rect_overlap(&bound, &ctx->rect, &bound)) { + bound.x -= ctx->rect.x; + bound.y -= ctx->rect.y; + pd_canvas_quote(&canvas, &ctx->canvas, &bound); + pd_canvas_fill(&canvas, border->left.color); + } + /* Draw right border line */ + bound.x = box->x + box->width - border->right.width; + bound.y = box->y + tr_height; + bound.width = border->right.width; + bound.height = box->height - tr_height - br_height; + if (pd_rect_overlap(&bound, &ctx->rect, &bound)) { + bound.x -= ctx->rect.x; + bound.y -= ctx->rect.y; + pd_canvas_quote(&canvas, &ctx->canvas, &bound); + pd_canvas_fill(&canvas, border->right.color); + } + return 0; } From 58adb9e3bd5fb64576f8983de2699cc9b1a1bd8b Mon Sep 17 00:00:00 2001 From: Liu Date: Sat, 6 Jun 2026 20:25:57 +0800 Subject: [PATCH 26/66] fix(css): reset parse target on '}' to avoid stale property name When parsing a value-less declaration that ended with '}' (e.g. inside `.gap-2 { gap: 8px }` where `gap` is not yet a supported property), the parser stayed in CSS_PARSER_TARGET_VALUE state. The next rule was then fed into the value parser with style_parser.property already cleared, producing misleading "unsupported property" errors and corrupting subsequent parsing. Switch target to CSS_PARSER_TARGET_NONE on '}' and to CSS_PARSER_TARGET_KEY on ';' inside the switch, mirroring the end-of-block / end-of-declaration semantics. Add an assert to catch any future regression where css_parser_commit is reached without a property name. --- lib/css/src/parser.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/css/src/parser.c b/lib/css/src/parser.c index 630ca4e0d..53e090278 100644 --- a/lib/css/src/parser.c +++ b/lib/css/src/parser.c @@ -95,7 +95,8 @@ static int css_parser_parse_selector(css_parser_t *parser) case ',': css_parser_commit(parser); s = css_selector_create(parser->buffer); - DEBUG_MSG("[css-parser] selector=%s, valid=%s\n", parser->buffer, s == NULL ? "false" : "true"); + DEBUG_MSG("[css-parser] selector=%s, valid=%s\n", + parser->buffer, s == NULL ? "false" : "true"); if (!s) { return -1; } @@ -182,7 +183,10 @@ static int css_parser_parse_style_property_value(css_parser_t *parser) case '/': return css_parser_begin_parse_comment(parser); case '}': + parser->target = CSS_PARSER_TARGET_NONE; + break; case ';': + parser->target = CSS_PARSER_TARGET_KEY; break; CASE_WHITE_SPACE: if (parser->pos == 0) { @@ -192,10 +196,8 @@ static int css_parser_parse_style_property_value(css_parser_t *parser) css_parser_get_char(parser); return 0; } - if (*parser->cur == ';') { - parser->target = CSS_PARSER_TARGET_KEY; - } css_parser_commit(parser); + assert(parser->style_parser.property != NULL); propdef = css_get_propdef_by_name(parser->style_parser.property); if (!propdef) { logger_error( @@ -288,7 +290,7 @@ void css_parser_commit(css_parser_t *parser) for (i = parser->pos; i > 0; --i) { switch (parser->buffer[i]) { CASE_WHITE_SPACE: - case 0: + case 0: parser->buffer[i] = 0; break; default: From 3327943aa07d876595d9bb06d4d24604c7a23c98 Mon Sep 17 00:00:00 2001 From: Liu Date: Sat, 6 Jun 2026 23:30:09 +0800 Subject: [PATCH 27/66] feat(css): add gap, row-gap and column-gap support Add the CSS gap shorthand and its row-gap/column-gap longhands for flex containers. - Register row-gap/column-gap as longhand properties and gap as a shorthand accepting [ normal | ]{1,2}. - Add css_gap_t (CSS_GAP_INHERIT/SET/NORMAL) and corresponding type/unit/value fields on css_computed_style_t. - Implement cascade logic in lib/css/src/properties/gap.c, resolving normal to zero and rejecting auto. - Apply gaps in ui_flexbox_layout: main-axis gap participates in line size, wrap detection, justify-content space and per-item positioning; cross-axis gap participates in cross-size accumulation and line positioning. The last item/line never gets a trailing gap. Percentage gaps resolve against the container content-box on the corresponding axis. - Cover gap parsing/cascading in lib/css/tests (single/two values, axis-only, normal, percentage) and add a flex layout integration test exercising column-gap, row-gap, wrapped two-value gap and normal. --- lib/css/include/css/types.h | 1272 +++++++++++++------------- lib/css/src/properties.c | 23 +- lib/css/src/properties/gap.c | 96 ++ lib/css/tests/test_css_computed.c | 123 +++ lib/css/tests/test_css_computed.css | 26 + lib/ui/src/ui_flexbox_layout.c | 71 +- tests/integration/test_flex_layout.c | 204 +++++ 7 files changed, 1174 insertions(+), 641 deletions(-) create mode 100644 lib/css/src/properties/gap.c diff --git a/lib/css/include/css/types.h b/lib/css/include/css/types.h index 8554eff52..9cbb4d802 100644 --- a/lib/css/include/css/types.h +++ b/lib/css/include/css/types.h @@ -22,263 +22,265 @@ #define css_string(...) "" #__VA_ARGS__ "" typedef enum { - // position start - css_prop_left, - css_prop_right, - css_prop_top, - css_prop_bottom, - css_prop_position, - // position end - - // display start - css_prop_visibility, - css_prop_display, - // display end - - css_prop_z_index, - css_prop_opacity, - css_prop_box_sizing, - css_prop_width, - css_prop_height, - css_prop_min_width, - css_prop_min_height, - css_prop_max_width, - css_prop_max_height, - - // margin start - css_prop_margin_top, - css_prop_margin_right, - css_prop_margin_bottom, - css_prop_margin_left, - // margin end - - // padding start - css_prop_padding_top, - css_prop_padding_right, - css_prop_padding_bottom, - css_prop_padding_left, - // padding end - - css_prop_vertical_align, - - // border start - css_prop_border_top_width, - css_prop_border_top_style, - css_prop_border_top_color, - css_prop_border_right_width, - css_prop_border_right_style, - css_prop_border_right_color, - css_prop_border_bottom_width, - css_prop_border_bottom_style, - css_prop_border_bottom_color, - css_prop_border_left_width, - css_prop_border_left_style, - css_prop_border_left_color, - css_prop_border_top_left_radius, - css_prop_border_top_right_radius, - css_prop_border_bottom_left_radius, - css_prop_border_bottom_right_radius, - // border end - - // background start - css_prop_background_color, - css_prop_background_image, - css_prop_background_size, - css_prop_background_repeat, - css_prop_background_clip, - css_prop_background_position_x, - css_prop_background_position_y, - // background end - - css_prop_box_shadow, - - // flex style start - css_prop_flex_basis, - css_prop_flex_grow, - css_prop_flex_shrink, - css_prop_flex_direction, - css_prop_flex_wrap, - css_prop_justify_content, - css_prop_align_content, - css_prop_align_items, - // flex style end - - css_prop_color, - css_prop_font_size, - css_prop_font_style, - css_prop_font_weight, - css_prop_font_family, - css_prop_line_height, - css_prop_text_align, - css_prop_content, - css_prop_white_space, - css_prop_word_break, - - css_prop_pointer_events, - STYLE_KEY_TOTAL + // position start + css_prop_left, + css_prop_right, + css_prop_top, + css_prop_bottom, + css_prop_position, + // position end + + // display start + css_prop_visibility, + css_prop_display, + // display end + + css_prop_z_index, + css_prop_opacity, + css_prop_box_sizing, + css_prop_width, + css_prop_height, + css_prop_min_width, + css_prop_min_height, + css_prop_max_width, + css_prop_max_height, + + // margin start + css_prop_margin_top, + css_prop_margin_right, + css_prop_margin_bottom, + css_prop_margin_left, + // margin end + + // padding start + css_prop_padding_top, + css_prop_padding_right, + css_prop_padding_bottom, + css_prop_padding_left, + // padding end + + css_prop_vertical_align, + + // border start + css_prop_border_top_width, + css_prop_border_top_style, + css_prop_border_top_color, + css_prop_border_right_width, + css_prop_border_right_style, + css_prop_border_right_color, + css_prop_border_bottom_width, + css_prop_border_bottom_style, + css_prop_border_bottom_color, + css_prop_border_left_width, + css_prop_border_left_style, + css_prop_border_left_color, + css_prop_border_top_left_radius, + css_prop_border_top_right_radius, + css_prop_border_bottom_left_radius, + css_prop_border_bottom_right_radius, + // border end + + // background start + css_prop_background_color, + css_prop_background_image, + css_prop_background_size, + css_prop_background_repeat, + css_prop_background_clip, + css_prop_background_position_x, + css_prop_background_position_y, + // background end + + css_prop_box_shadow, + + // flex style start + css_prop_flex_basis, + css_prop_flex_grow, + css_prop_flex_shrink, + css_prop_flex_direction, + css_prop_flex_wrap, + css_prop_justify_content, + css_prop_align_content, + css_prop_align_items, + css_prop_row_gap, + css_prop_column_gap, + // flex style end + + css_prop_color, + css_prop_font_size, + css_prop_font_style, + css_prop_font_weight, + css_prop_font_family, + css_prop_line_height, + css_prop_text_align, + css_prop_content, + css_prop_white_space, + css_prop_word_break, + + css_prop_pointer_events, + STYLE_KEY_TOTAL } css_prop_key_t; typedef enum { - CSS_LENGTH_INHERIT, - CSS_LENGTH_SET, - CSS_LENGTH_AUTO + CSS_LENGTH_INHERIT, + CSS_LENGTH_SET, + CSS_LENGTH_AUTO } css_length_t; typedef enum { CSS_COLOR_INHERIT, CSS_COLOR_COLOR } css_color_t; typedef enum { - CSS_ALIGN_CONTENT_INHERIT, - CSS_ALIGN_CONTENT_STRETCH, - CSS_ALIGN_CONTENT_FLEX_START, - CSS_ALIGN_CONTENT_FLEX_END, - CSS_ALIGN_CONTENT_CENTER, - CSS_ALIGN_CONTENT_SPACE_BETWEEN, - CSS_ALIGN_CONTENT_SPACE_AROUND, - CSS_ALIGN_CONTENT_SPACE_EVENLY + CSS_ALIGN_CONTENT_INHERIT, + CSS_ALIGN_CONTENT_STRETCH, + CSS_ALIGN_CONTENT_FLEX_START, + CSS_ALIGN_CONTENT_FLEX_END, + CSS_ALIGN_CONTENT_CENTER, + CSS_ALIGN_CONTENT_SPACE_BETWEEN, + CSS_ALIGN_CONTENT_SPACE_AROUND, + CSS_ALIGN_CONTENT_SPACE_EVENLY } css_align_content_t; typedef enum { - CSS_ALIGN_ITEMS_INHERIT, - CSS_ALIGN_ITEMS_STRETCH, - CSS_ALIGN_ITEMS_FLEX_START, - CSS_ALIGN_ITEMS_FLEX_END, - CSS_ALIGN_ITEMS_CENTER, - CSS_ALIGN_ITEMS_BASELINE + CSS_ALIGN_ITEMS_INHERIT, + CSS_ALIGN_ITEMS_STRETCH, + CSS_ALIGN_ITEMS_FLEX_START, + CSS_ALIGN_ITEMS_FLEX_END, + CSS_ALIGN_ITEMS_CENTER, + CSS_ALIGN_ITEMS_BASELINE } css_align_items_t; typedef enum { - CSS_BACKGROUND_COLOR_INHERIT, - CSS_BACKGROUND_COLOR_COLOR, - CSS_BACKGROUND_COLOR_CURRENT_COLOR + CSS_BACKGROUND_COLOR_INHERIT, + CSS_BACKGROUND_COLOR_COLOR, + CSS_BACKGROUND_COLOR_CURRENT_COLOR } css_background_color_t; typedef enum { - CSS_BACKGROUND_IMAGE_INHERIT, - /* Consult pointer in struct to determine which */ - CSS_BACKGROUND_IMAGE_NONE, - CSS_BACKGROUND_IMAGE_IMAGE + CSS_BACKGROUND_IMAGE_INHERIT, + /* Consult pointer in struct to determine which */ + CSS_BACKGROUND_IMAGE_NONE, + CSS_BACKGROUND_IMAGE_IMAGE } css_background_image_t; typedef enum { - CSS_BACKGROUND_SIZE_INHERIT, - CSS_BACKGROUND_SIZE_SET, - CSS_BACKGROUND_SIZE_AUTO, - CSS_BACKGROUND_SIZE_COVER, - CSS_BACKGROUND_SIZE_CONTAIN + CSS_BACKGROUND_SIZE_INHERIT, + CSS_BACKGROUND_SIZE_SET, + CSS_BACKGROUND_SIZE_AUTO, + CSS_BACKGROUND_SIZE_COVER, + CSS_BACKGROUND_SIZE_CONTAIN } css_background_size_t; typedef enum { - CSS_BACKGROUND_POSITION_INHERIT, - CSS_BACKGROUND_POSITION_SET + CSS_BACKGROUND_POSITION_INHERIT, + CSS_BACKGROUND_POSITION_SET } css_background_position_t; typedef enum { - CSS_BACKGROUND_REPEAT_INHERIT, - CSS_BACKGROUND_REPEAT_REPEAT_X, - CSS_BACKGROUND_REPEAT_REPEAT_Y, - CSS_BACKGROUND_REPEAT_REPEAT, - CSS_BACKGROUND_REPEAT_NO_REPEAT + CSS_BACKGROUND_REPEAT_INHERIT, + CSS_BACKGROUND_REPEAT_REPEAT_X, + CSS_BACKGROUND_REPEAT_REPEAT_Y, + CSS_BACKGROUND_REPEAT_REPEAT, + CSS_BACKGROUND_REPEAT_NO_REPEAT } css_background_repeat_t; typedef enum { - CSS_BACKGROUND_CLIP_INHERIT, - CSS_BACKGROUND_CLIP_BORDER_BOX, - CSS_BACKGROUND_CLIP_PADDING_BOX, - CSS_BACKGROUND_CLIP_CONTENT_BOX + CSS_BACKGROUND_CLIP_INHERIT, + CSS_BACKGROUND_CLIP_BORDER_BOX, + CSS_BACKGROUND_CLIP_PADDING_BOX, + CSS_BACKGROUND_CLIP_CONTENT_BOX } css_background_clip_t; typedef enum { - CSS_BORDER_RADIUS_INHERIT, - CSS_BORDER_RADIUS_SET + CSS_BORDER_RADIUS_INHERIT, + CSS_BORDER_RADIUS_SET } css_border_radius_t; typedef enum { - CSS_BORDER_COLOR_INHERIT = CSS_BACKGROUND_COLOR_INHERIT, - CSS_BORDER_COLOR_COLOR = CSS_BACKGROUND_COLOR_COLOR, - CSS_BORDER_COLOR_CURRENT_COLOR = CSS_BACKGROUND_COLOR_CURRENT_COLOR + CSS_BORDER_COLOR_INHERIT = CSS_BACKGROUND_COLOR_INHERIT, + CSS_BORDER_COLOR_COLOR = CSS_BACKGROUND_COLOR_COLOR, + CSS_BORDER_COLOR_CURRENT_COLOR = CSS_BACKGROUND_COLOR_CURRENT_COLOR } css_border_color_t; typedef enum { - CSS_BORDER_STYLE_INHERIT, - CSS_BORDER_STYLE_NONE, - CSS_BORDER_STYLE_HIDDEN, - CSS_BORDER_STYLE_DOTTED, - CSS_BORDER_STYLE_DASHED, - CSS_BORDER_STYLE_SOLID, - CSS_BORDER_STYLE_DOUBLE, - CSS_BORDER_STYLE_GROOVE, - CSS_BORDER_STYLE_RIDGE, - CSS_BORDER_STYLE_INSET, - CSS_BORDER_STYLE_OUTSET + CSS_BORDER_STYLE_INHERIT, + CSS_BORDER_STYLE_NONE, + CSS_BORDER_STYLE_HIDDEN, + CSS_BORDER_STYLE_DOTTED, + CSS_BORDER_STYLE_DASHED, + CSS_BORDER_STYLE_SOLID, + CSS_BORDER_STYLE_DOUBLE, + CSS_BORDER_STYLE_GROOVE, + CSS_BORDER_STYLE_RIDGE, + CSS_BORDER_STYLE_INSET, + CSS_BORDER_STYLE_OUTSET } css_border_style_t; typedef enum { - CSS_BORDER_WIDTH_INHERIT, - CSS_BORDER_WIDTH_THIN, - CSS_BORDER_WIDTH_MEDIUM, - CSS_BORDER_WIDTH_THICK, - CSS_BORDER_WIDTH_WIDTH + CSS_BORDER_WIDTH_INHERIT, + CSS_BORDER_WIDTH_THIN, + CSS_BORDER_WIDTH_MEDIUM, + CSS_BORDER_WIDTH_THICK, + CSS_BORDER_WIDTH_WIDTH } css_border_width_t; typedef enum { - CSS_BOX_SHADOW_NONE, - CSS_BOX_SHADOW_SET, + CSS_BOX_SHADOW_NONE, + CSS_BOX_SHADOW_SET, } css_box_shadow_t; typedef enum { - CSS_BOTTOM_INHERIT, - CSS_BOTTOM_SET, - CSS_BOTTOM_AUTO + CSS_BOTTOM_INHERIT, + CSS_BOTTOM_SET, + CSS_BOTTOM_AUTO } css_bottom_t; typedef enum { - CSS_BOX_SIZING_INHERIT, - CSS_BOX_SIZING_CONTENT_BOX, - CSS_BOX_SIZING_BORDER_BOX + CSS_BOX_SIZING_INHERIT, + CSS_BOX_SIZING_CONTENT_BOX, + CSS_BOX_SIZING_BORDER_BOX } css_box_sizing_t; typedef enum { - CSS_CONTENT_INHERIT, - CSS_CONTENT_NONE, - CSS_CONTENT_NORMAL, - CSS_CONTENT_SET + CSS_CONTENT_INHERIT, + CSS_CONTENT_NONE, + CSS_CONTENT_NORMAL, + CSS_CONTENT_SET } css_content_t; typedef enum { - CSS_DISPLAY_INHERIT, - CSS_DISPLAY_NONE, - CSS_DISPLAY_BLOCK, - CSS_DISPLAY_FLEX, - CSS_DISPLAY_INLINE, - CSS_DISPLAY_INLINE_FLEX, - CSS_DISPLAY_LIST_ITEM, - CSS_DISPLAY_RUN_IN, - CSS_DISPLAY_INLINE_BLOCK, - CSS_DISPLAY_TABLE, - CSS_DISPLAY_INLINE_TABLE, - CSS_DISPLAY_TABLE_ROW_GROUP, - CSS_DISPLAY_TABLE_HEADER_GROUP, - CSS_DISPLAY_TABLE_FOOTER_GROUP, - CSS_DISPLAY_TABLE_ROWb, - CSS_DISPLAY_TABLE_COLUMN_GROUP, - CSS_DISPLAY_TABLE_COLUMN, - CSS_DISPLAY_TABLE_CELL, - CSS_DISPLAY_TABLE_CAPTION, + CSS_DISPLAY_INHERIT, + CSS_DISPLAY_NONE, + CSS_DISPLAY_BLOCK, + CSS_DISPLAY_FLEX, + CSS_DISPLAY_INLINE, + CSS_DISPLAY_INLINE_FLEX, + CSS_DISPLAY_LIST_ITEM, + CSS_DISPLAY_RUN_IN, + CSS_DISPLAY_INLINE_BLOCK, + CSS_DISPLAY_TABLE, + CSS_DISPLAY_INLINE_TABLE, + CSS_DISPLAY_TABLE_ROW_GROUP, + CSS_DISPLAY_TABLE_HEADER_GROUP, + CSS_DISPLAY_TABLE_FOOTER_GROUP, + CSS_DISPLAY_TABLE_ROWb, + CSS_DISPLAY_TABLE_COLUMN_GROUP, + CSS_DISPLAY_TABLE_COLUMN, + CSS_DISPLAY_TABLE_CELL, + CSS_DISPLAY_TABLE_CAPTION, } css_display_t; typedef enum { - CSS_FLEX_BASIS_INHERIT, - CSS_FLEX_BASIS_SET, - CSS_FLEX_BASIS_AUTO, - CSS_FLEX_BASIS_CONTENT + CSS_FLEX_BASIS_INHERIT, + CSS_FLEX_BASIS_SET, + CSS_FLEX_BASIS_AUTO, + CSS_FLEX_BASIS_CONTENT } css_flex_basis_t; typedef enum { - CSS_FLEX_DIRECTION_INHERIT, - CSS_FLEX_DIRECTION_ROW, - CSS_FLEX_DIRECTION_ROW_REVERSE, - CSS_FLEX_DIRECTION_COLUMN, - CSS_FLEX_DIRECTION_COLUMN_REVERSE + CSS_FLEX_DIRECTION_INHERIT, + CSS_FLEX_DIRECTION_ROW, + CSS_FLEX_DIRECTION_ROW_REVERSE, + CSS_FLEX_DIRECTION_COLUMN, + CSS_FLEX_DIRECTION_COLUMN_REVERSE } css_flex_direction_t; typedef enum { CSS_FLEX_GROW_INHERIT, CSS_FLEX_GROW_SET } css_flex_grow_t; @@ -286,115 +288,117 @@ typedef enum { CSS_FLEX_GROW_INHERIT, CSS_FLEX_GROW_SET } css_flex_grow_t; typedef enum { CSS_FLEX_SHRINK_INHERIT, CSS_FLEX_SHRINK_SET } css_flex_shrink_t; typedef enum { - CSS_FLEX_WRAP_INHERIT, - CSS_FLEX_WRAP_NOWRAP, - CSS_FLEX_WRAP_WRAP, - CSS_FLEX_WRAP_WRAP_REVERSE + CSS_FLEX_WRAP_INHERIT, + CSS_FLEX_WRAP_NOWRAP, + CSS_FLEX_WRAP_WRAP, + CSS_FLEX_WRAP_WRAP_REVERSE } css_flex_wrap_t; +typedef enum { CSS_GAP_INHERIT, CSS_GAP_SET, CSS_GAP_NORMAL } css_gap_t; + typedef enum { - CSS_FONT_FAMILY_INHERIT, - /* Named fonts exist if pointer is non-NULL */ - CSS_FONT_FAMILY_SERIF, - CSS_FONT_FAMILY_SANS_SERIF, - CSS_FONT_FAMILY_CURSIVE, - CSS_FONT_FAMILY_FANTASY, - CSS_FONT_FAMILY_MONOSPACE + CSS_FONT_FAMILY_INHERIT, + /* Named fonts exist if pointer is non-NULL */ + CSS_FONT_FAMILY_SERIF, + CSS_FONT_FAMILY_SANS_SERIF, + CSS_FONT_FAMILY_CURSIVE, + CSS_FONT_FAMILY_FANTASY, + CSS_FONT_FAMILY_MONOSPACE } css_font_family_t; typedef enum { - CSS_FONT_SIZE_INHERIT, - CSS_FONT_SIZE_XX_SMALL, - CSS_FONT_SIZE_X_SMALL, - CSS_FONT_SIZE_SMALL, - CSS_FONT_SIZE_MEDIUM, - CSS_FONT_SIZE_LARGE, - CSS_FONT_SIZE_X_LARGE, - CSS_FONT_SIZE_XX_LARGE, - CSS_FONT_SIZE_LARGER, - CSS_FONT_SIZE_SMALLER, - CSS_FONT_SIZE_DIMENSION + CSS_FONT_SIZE_INHERIT, + CSS_FONT_SIZE_XX_SMALL, + CSS_FONT_SIZE_X_SMALL, + CSS_FONT_SIZE_SMALL, + CSS_FONT_SIZE_MEDIUM, + CSS_FONT_SIZE_LARGE, + CSS_FONT_SIZE_X_LARGE, + CSS_FONT_SIZE_XX_LARGE, + CSS_FONT_SIZE_LARGER, + CSS_FONT_SIZE_SMALLER, + CSS_FONT_SIZE_DIMENSION } css_font_size_t; typedef enum { - CSS_FONT_STYLE_INHERIT, - CSS_FONT_STYLE_NORMAL, - CSS_FONT_STYLE_ITALIC, - CSS_FONT_STYLE_OBLIQUE + CSS_FONT_STYLE_INHERIT, + CSS_FONT_STYLE_NORMAL, + CSS_FONT_STYLE_ITALIC, + CSS_FONT_STYLE_OBLIQUE } css_font_style_t; typedef enum { - CSS_FONT_WEIGHT_INHERIT, - CSS_FONT_WEIGHT_NORMAL, - CSS_FONT_WEIGHT_BOLD, - CSS_FONT_WEIGHT_BOLDER, - CSS_FONT_WEIGHT_LIGHTER, - CSS_FONT_WEIGHT_100, - CSS_FONT_WEIGHT_200, - CSS_FONT_WEIGHT_300, - CSS_FONT_WEIGHT_400, - CSS_FONT_WEIGHT_500, - CSS_FONT_WEIGHT_600, - CSS_FONT_WEIGHT_700, - CSS_FONT_WEIGHT_800, - CSS_FONT_WEIGHT_900 + CSS_FONT_WEIGHT_INHERIT, + CSS_FONT_WEIGHT_NORMAL, + CSS_FONT_WEIGHT_BOLD, + CSS_FONT_WEIGHT_BOLDER, + CSS_FONT_WEIGHT_LIGHTER, + CSS_FONT_WEIGHT_100, + CSS_FONT_WEIGHT_200, + CSS_FONT_WEIGHT_300, + CSS_FONT_WEIGHT_400, + CSS_FONT_WEIGHT_500, + CSS_FONT_WEIGHT_600, + CSS_FONT_WEIGHT_700, + CSS_FONT_WEIGHT_800, + CSS_FONT_WEIGHT_900 } css_font_weight_t; typedef enum { - CSS_HEIGHT_INHERIT, - CSS_HEIGHT_SET, - CSS_HEIGHT_AUTO, - CSS_HEIGHT_FIT_CONTENT + CSS_HEIGHT_INHERIT, + CSS_HEIGHT_SET, + CSS_HEIGHT_AUTO, + CSS_HEIGHT_FIT_CONTENT } css_height_t; typedef enum { - CSS_JUSTIFY_CONTENT_INHERIT, - CSS_JUSTIFY_CONTENT_FLEX_START, - CSS_JUSTIFY_CONTENT_FLEX_END, - CSS_JUSTIFY_CONTENT_CENTER, - CSS_JUSTIFY_CONTENT_SPACE_BETWEEN, - CSS_JUSTIFY_CONTENT_SPACE_AROUND, - CSS_JUSTIFY_CONTENT_SPACE_EVENLY + CSS_JUSTIFY_CONTENT_INHERIT, + CSS_JUSTIFY_CONTENT_FLEX_START, + CSS_JUSTIFY_CONTENT_FLEX_END, + CSS_JUSTIFY_CONTENT_CENTER, + CSS_JUSTIFY_CONTENT_SPACE_BETWEEN, + CSS_JUSTIFY_CONTENT_SPACE_AROUND, + CSS_JUSTIFY_CONTENT_SPACE_EVENLY } css_justify_content_t; typedef enum { CSS_LEFT_INHERIT, CSS_LEFT_SET, CSS_LEFT_AUTO } css_left_t; typedef enum { - CSS_LINE_HEIGHT_INHERIT, - CSS_LINE_HEIGHT_NUMBER, - CSS_LINE_HEIGHT_DIMENSION, - CSS_LINE_HEIGHT_NORMAL + CSS_LINE_HEIGHT_INHERIT, + CSS_LINE_HEIGHT_NUMBER, + CSS_LINE_HEIGHT_DIMENSION, + CSS_LINE_HEIGHT_NORMAL } css_line_height_t; typedef enum { - CSS_MARGIN_INHERIT, - CSS_MARGIN_SET, - CSS_MARGIN_AUTO + CSS_MARGIN_INHERIT, + CSS_MARGIN_SET, + CSS_MARGIN_AUTO } css_margin_t; typedef enum { - CSS_MAX_HEIGHT_INHERIT, - CSS_MAX_HEIGHT_SET, - CSS_MAX_HEIGHT_NONE + CSS_MAX_HEIGHT_INHERIT, + CSS_MAX_HEIGHT_SET, + CSS_MAX_HEIGHT_NONE } css_max_height_t; typedef enum { - CSS_MAX_WIDTH_INHERIT, - CSS_MAX_WIDTH_SET, - CSS_MAX_WIDTH_NONE + CSS_MAX_WIDTH_INHERIT, + CSS_MAX_WIDTH_SET, + CSS_MAX_WIDTH_NONE } css_max_width_t; typedef enum { - CSS_MIN_HEIGHT_INHERIT, - CSS_MIN_HEIGHT_SET, - CSS_MIN_HEIGHT_AUTO, - CSS_MIN_HEIGHT_MIN_CONTENT + CSS_MIN_HEIGHT_INHERIT, + CSS_MIN_HEIGHT_SET, + CSS_MIN_HEIGHT_AUTO, + CSS_MIN_HEIGHT_MIN_CONTENT } css_min_height_t; typedef enum { - CSS_MIN_WIDTH_INHERIT, - CSS_MIN_WIDTH_SET, - CSS_MIN_WIDTH_AUTO, - CSS_MIN_WIDTH_MIN_CONTENT + CSS_MIN_WIDTH_INHERIT, + CSS_MIN_WIDTH_SET, + CSS_MIN_WIDTH_AUTO, + CSS_MIN_WIDTH_MIN_CONTENT } css_min_width_t; typedef enum { CSS_OPACITY_INHERIT, CSS_OPACITY_SET } css_opacity_t; @@ -402,96 +406,96 @@ typedef enum { CSS_OPACITY_INHERIT, CSS_OPACITY_SET } css_opacity_t; typedef enum { CSS_PADDING_INHERIT, CSS_PADDING_SET } css_padding_t; typedef enum { - CSS_POSITION_INHERIT, - CSS_POSITION_STATIC, - CSS_POSITION_RELATIVE, - CSS_POSITION_ABSOLUTE, - CSS_POSITION_FIXED + CSS_POSITION_INHERIT, + CSS_POSITION_STATIC, + CSS_POSITION_RELATIVE, + CSS_POSITION_ABSOLUTE, + CSS_POSITION_FIXED } css_position_t; typedef enum { CSS_RIGHT_INHERIT, CSS_RIGHT_SET, CSS_RIGHT_AUTO } css_right_t; typedef enum { - CSS_TEXT_ALIGN_INHERIT, - CSS_TEXT_ALIGN_INHERIT_IF_NON_MAGIC, - CSS_TEXT_ALIGN_LEFT, - CSS_TEXT_ALIGN_RIGHT, - CSS_TEXT_ALIGN_CENTER, - CSS_TEXT_ALIGN_JUSTIFY, - CSS_TEXT_ALIGN_DEFAULT, - CSS_TEXT_ALIGN_LIBCSS_LEFT, - CSS_TEXT_ALIGN_LIBCSS_CENTER, - CSS_TEXT_ALIGN_LIBCSS_RIGHT + CSS_TEXT_ALIGN_INHERIT, + CSS_TEXT_ALIGN_INHERIT_IF_NON_MAGIC, + CSS_TEXT_ALIGN_LEFT, + CSS_TEXT_ALIGN_RIGHT, + CSS_TEXT_ALIGN_CENTER, + CSS_TEXT_ALIGN_JUSTIFY, + CSS_TEXT_ALIGN_DEFAULT, + CSS_TEXT_ALIGN_LIBCSS_LEFT, + CSS_TEXT_ALIGN_LIBCSS_CENTER, + CSS_TEXT_ALIGN_LIBCSS_RIGHT } css_text_align_t; typedef enum { CSS_TOP_INHERIT, CSS_TOP_SET, CSS_TOP_AUTO } css_top_t; typedef enum { - CSS_VERTICAL_ALIGN_INHERIT, - CSS_VERTICAL_ALIGN_BASELINE, - CSS_VERTICAL_ALIGN_SUB, - CSS_VERTICAL_ALIGN_SUPER, - CSS_VERTICAL_ALIGN_TOP, - CSS_VERTICAL_ALIGN_TEXT_TOP, - CSS_VERTICAL_ALIGN_MIDDLE, - CSS_VERTICAL_ALIGN_BOTTOM, - CSS_VERTICAL_ALIGN_TEXT_BOTTOM, - CSS_VERTICAL_ALIGN_SET + CSS_VERTICAL_ALIGN_INHERIT, + CSS_VERTICAL_ALIGN_BASELINE, + CSS_VERTICAL_ALIGN_SUB, + CSS_VERTICAL_ALIGN_SUPER, + CSS_VERTICAL_ALIGN_TOP, + CSS_VERTICAL_ALIGN_TEXT_TOP, + CSS_VERTICAL_ALIGN_MIDDLE, + CSS_VERTICAL_ALIGN_BOTTOM, + CSS_VERTICAL_ALIGN_TEXT_BOTTOM, + CSS_VERTICAL_ALIGN_SET } css_vertical_align_t; typedef enum { - CSS_VISIBILITY_INHERIT, - CSS_VISIBILITY_VISIBLE, - CSS_VISIBILITY_HIDDEN, - CSS_VISIBILITY_COLLAPSE + CSS_VISIBILITY_INHERIT, + CSS_VISIBILITY_VISIBLE, + CSS_VISIBILITY_HIDDEN, + CSS_VISIBILITY_COLLAPSE } css_visibility_t; typedef enum { - CSS_WHITE_SPACE_INHERIT, - CSS_WHITE_SPACE_NORMAL, - CSS_WHITE_SPACE_PRE, - CSS_WHITE_SPACE_NOWRAP, - CSS_WHITE_SPACE_PRE_WRAP, - CSS_WHITE_SPACE_PRE_LINE + CSS_WHITE_SPACE_INHERIT, + CSS_WHITE_SPACE_NORMAL, + CSS_WHITE_SPACE_PRE, + CSS_WHITE_SPACE_NOWRAP, + CSS_WHITE_SPACE_PRE_WRAP, + CSS_WHITE_SPACE_PRE_LINE } css_white_space_t; typedef enum { - CSS_WORD_BREAK_INHERIT, - CSS_WORD_BREAK_NORMAL, - CSS_WORD_BREAK_BREAK_ALL + CSS_WORD_BREAK_INHERIT, + CSS_WORD_BREAK_NORMAL, + CSS_WORD_BREAK_BREAK_ALL } css_word_break_t; typedef enum { - CSS_WIDTH_INHERIT, - CSS_WIDTH_SET, - CSS_WIDTH_AUTO, - CSS_WIDTH_FIT_CONTENT + CSS_WIDTH_INHERIT, + CSS_WIDTH_SET, + CSS_WIDTH_AUTO, + CSS_WIDTH_FIT_CONTENT } css_width_t; typedef enum { - CSS_Z_INDEX_INHERIT, - CSS_Z_INDEX_SET, - CSS_Z_INDEX_AUTO + CSS_Z_INDEX_INHERIT, + CSS_Z_INDEX_SET, + CSS_Z_INDEX_AUTO } css_z_index_t; typedef enum { - CSS_POINTER_EVENTS_INHERT, - CSS_POINTER_EVENTS_AUTO, - CSS_POINTER_EVENTS_NONE + CSS_POINTER_EVENTS_INHERT, + CSS_POINTER_EVENTS_AUTO, + CSS_POINTER_EVENTS_NONE } css_pointer_events_t; typedef enum css_style_value_type_t { - CSS_NO_VALUE, - CSS_INVALID_VALUE, - CSS_UNPARSED_VALUE, - CSS_ARRAY_VALUE, - - CSS_NUMERIC_VALUE, - CSS_STRING_VALUE, - CSS_KEYWORD_VALUE, - CSS_COLOR_VALUE, - - CSS_UNIT_VALUE, - CSS_BOOLEAN_VALUE, + CSS_NO_VALUE, + CSS_INVALID_VALUE, + CSS_UNPARSED_VALUE, + CSS_ARRAY_VALUE, + + CSS_NUMERIC_VALUE, + CSS_STRING_VALUE, + CSS_KEYWORD_VALUE, + CSS_COLOR_VALUE, + + CSS_UNIT_VALUE, + CSS_BOOLEAN_VALUE, } css_style_value_type_t; typedef char *css_image_value_t; @@ -504,11 +508,11 @@ typedef void *css_private_value_t; typedef int css_boolean_value_t; typedef enum { - CSS_UNIT_PX, - CSS_UNIT_PERCENT, - CSS_UNIT_DIP, - CSS_UNIT_SP, - CSS_UNIT_PT + CSS_UNIT_PX, + CSS_UNIT_PERCENT, + CSS_UNIT_DIP, + CSS_UNIT_SP, + CSS_UNIT_PT } css_unit_t; typedef int32_t css_unit_ident_t; @@ -517,99 +521,99 @@ typedef int32_t css_unit_ident_t; /** https://developer.mozilla.org/en-US/docs/Web/API/CSSUnitValue */ typedef struct css_unit_value { - css_numeric_value_t value; - css_unit_t unit; + css_numeric_value_t value; + css_unit_t unit; } css_unit_value_t; typedef struct css_style_value css_style_value_t; typedef css_style_value_t *css_style_array_value_t; typedef enum css_keyword_value_t { - CSS_KEYWORD_INHERIT, - CSS_KEYWORD_INITIAL, - CSS_KEYWORD_NONE, - CSS_KEYWORD_AUTO, - CSS_KEYWORD_NORMAL, - - CSS_KEYWORD_STATIC, - CSS_KEYWORD_RELATIVE, - CSS_KEYWORD_ABSOLUTE, - - CSS_KEYWORD_BLOCK, - CSS_KEYWORD_INLINE_BLOCK, - CSS_KEYWORD_FLEX, - CSS_KEYWORD_INLINE_FLEX, - - CSS_KEYWORD_LEFT, - CSS_KEYWORD_CENTER, - CSS_KEYWORD_RIGHT, - CSS_KEYWORD_TOP, - CSS_KEYWORD_MIDDLE, - CSS_KEYWORD_BOTTOM, - - CSS_KEYWORD_ROW, - CSS_KEYWORD_COLUMN, - - CSS_KEYWORD_START, - CSS_KEYWORD_END, - CSS_KEYWORD_FLEX_START, - CSS_KEYWORD_FLEX_END, - CSS_KEYWORD_STRETCH, - CSS_KEYWORD_SPACE_BETWEEN, - CSS_KEYWORD_SPACE_AROUND, - CSS_KEYWORD_SPACE_EVENLY, - - CSS_KEYWORD_WRAP, - CSS_KEYWORD_NOWRAP, - - CSS_KEYWORD_BREAK_ALL, - - CSS_KEYWORD_ITALIC, - CSS_KEYWORD_OBLIQUE, - CSS_KEYWORD_SMALL, - CSS_KEYWORD_MEDIUM, - CSS_KEYWORD_LARGE, - CSS_KEYWORD_BOLD, - - CSS_KEYWORD_HIDDEN, - CSS_KEYWORD_VISIBLE, - - CSS_KEYWORD_CONTENT_BOX, - CSS_KEYWORD_PADDING_BOX, - CSS_KEYWORD_BORDER_BOX, - - CSS_KEYWORD_SOLID, - CSS_KEYWORD_DOTTED, - CSS_KEYWORD_DOUBLE, - CSS_KEYWORD_DASHED, - - CSS_KEYWORD_CONTAIN, - CSS_KEYWORD_COVER, - CSS_KEYWORD_REPEAT, - CSS_KEYWORD_NO_REPEAT, - CSS_KEYWORD_REPEAT_X, - CSS_KEYWORD_REPEAT_Y, - - CSS_KEYWORD_MAX_CONTENT, - CSS_KEYWORD_MIN_CONTENT, - CSS_KEYWORD_FIT_CONTENT, + CSS_KEYWORD_INHERIT, + CSS_KEYWORD_INITIAL, + CSS_KEYWORD_NONE, + CSS_KEYWORD_AUTO, + CSS_KEYWORD_NORMAL, + + CSS_KEYWORD_STATIC, + CSS_KEYWORD_RELATIVE, + CSS_KEYWORD_ABSOLUTE, + + CSS_KEYWORD_BLOCK, + CSS_KEYWORD_INLINE_BLOCK, + CSS_KEYWORD_FLEX, + CSS_KEYWORD_INLINE_FLEX, + + CSS_KEYWORD_LEFT, + CSS_KEYWORD_CENTER, + CSS_KEYWORD_RIGHT, + CSS_KEYWORD_TOP, + CSS_KEYWORD_MIDDLE, + CSS_KEYWORD_BOTTOM, + + CSS_KEYWORD_ROW, + CSS_KEYWORD_COLUMN, + + CSS_KEYWORD_START, + CSS_KEYWORD_END, + CSS_KEYWORD_FLEX_START, + CSS_KEYWORD_FLEX_END, + CSS_KEYWORD_STRETCH, + CSS_KEYWORD_SPACE_BETWEEN, + CSS_KEYWORD_SPACE_AROUND, + CSS_KEYWORD_SPACE_EVENLY, + + CSS_KEYWORD_WRAP, + CSS_KEYWORD_NOWRAP, + + CSS_KEYWORD_BREAK_ALL, + + CSS_KEYWORD_ITALIC, + CSS_KEYWORD_OBLIQUE, + CSS_KEYWORD_SMALL, + CSS_KEYWORD_MEDIUM, + CSS_KEYWORD_LARGE, + CSS_KEYWORD_BOLD, + + CSS_KEYWORD_HIDDEN, + CSS_KEYWORD_VISIBLE, + + CSS_KEYWORD_CONTENT_BOX, + CSS_KEYWORD_PADDING_BOX, + CSS_KEYWORD_BORDER_BOX, + + CSS_KEYWORD_SOLID, + CSS_KEYWORD_DOTTED, + CSS_KEYWORD_DOUBLE, + CSS_KEYWORD_DASHED, + + CSS_KEYWORD_CONTAIN, + CSS_KEYWORD_COVER, + CSS_KEYWORD_REPEAT, + CSS_KEYWORD_NO_REPEAT, + CSS_KEYWORD_REPEAT_X, + CSS_KEYWORD_REPEAT_Y, + + CSS_KEYWORD_MAX_CONTENT, + CSS_KEYWORD_MIN_CONTENT, + CSS_KEYWORD_FIT_CONTENT, } css_keyword_value_t; /** https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleValue */ struct css_style_value { - css_style_value_type_t type; - union { - css_private_value_t value; - css_numeric_value_t numeric_value; - css_integer_value_t integer_value; - css_string_value_t string_value; - css_unit_value_t unit_value; - css_color_value_t color_value; - css_image_value_t image_value; - css_unparsed_value_t unparsed_value; - css_keyword_value_t keyword_value; - css_style_array_value_t array_value; - css_boolean_value_t boolean_value; - }; + css_style_value_type_t type; + union { + css_private_value_t value; + css_numeric_value_t numeric_value; + css_integer_value_t integer_value; + css_string_value_t string_value; + css_unit_value_t unit_value; + css_color_value_t color_value; + css_image_value_t image_value; + css_unparsed_value_t unparsed_value; + css_keyword_value_t keyword_value; + css_style_array_value_t array_value; + css_boolean_value_t boolean_value; + }; }; typedef struct css_valdef css_valdef_t; @@ -620,244 +624,250 @@ typedef unsigned css_selector_hash_t; /** 样式规则记录 */ typedef struct css_style_rule { - int rank; /**< 权值,决定优先级 */ - int batch_num; /**< 批次号 */ - char *space; /**< 所属的空间 */ - char *selector; /**< 选择器 */ - css_style_decl_t *list; /**< 样式表 */ - list_node_t node; /**< 在链表中的结点 */ + int rank; /**< 权值,决定优先级 */ + int batch_num; /**< 批次号 */ + char *space; /**< 所属的空间 */ + char *selector; /**< 选择器 */ + css_style_decl_t *list; /**< 样式表 */ + list_node_t node; /**< 在链表中的结点 */ } css_style_rule_t; typedef struct css_prop { - css_prop_key_t key; - css_style_value_t value; - list_node_t node; + css_prop_key_t key; + css_style_value_t value; + list_node_t node; } css_prop_t; typedef struct css_selector_node { - char *id; - char *type; - char **classes; - char **status; - char *fullname; /**< 全名,由 id、type、classes、status 组合而成 */ - int rank; + char *id; + char *type; + char **classes; + char **status; + char *fullname; /**< 全名,由 id、type、classes、status 组合而成 */ + int rank; } css_selector_node_t; typedef struct css_selector { - int rank; /**< 权值,决定优先级 */ - int batch_num; /**< 批次号 */ - int length; /**< 选择器结点长度 */ - css_selector_hash_t hash; /**< 哈希值 */ - css_selector_node_t **nodes; /**< 选择器结点列表 */ + int rank; /**< 权值,决定优先级 */ + int batch_num; /**< 批次号 */ + int length; /**< 选择器结点长度 */ + css_selector_hash_t hash; /**< 哈希值 */ + css_selector_node_t **nodes; /**< 选择器结点列表 */ } css_selector_t; typedef struct css_font_face { - char *font_family; - css_font_style_t font_style; - css_font_weight_t font_weight; - char *src; + char *font_family; + css_font_style_t font_style; + css_font_weight_t font_weight; + char *src; } css_font_face_t; typedef struct css_metrics { - float dpi; - float density; - float scaled_density; - float scale; + float dpi; + float density; + float scaled_density; + float scale; } css_metrics_t; typedef struct css_computed_style { - /** - * 属性值类型的比特数据 - * 以比特位为单位分配的存储空间,用于节省属性值的内存占用 - */ - struct css_type_bits { - uint8_t display : 5; - uint8_t box_sizing : 2; - uint8_t visibility : 4; - uint8_t vertical_align : 4; - uint8_t pointer_events : 2; - uint8_t position : 3; - - uint8_t z_index : 2; - uint8_t opacity : 2; - - uint8_t left : 2; - uint8_t right : 2; - uint8_t top : 2; - uint8_t bottom : 2; - uint8_t width : 2; - uint8_t height : 2; - uint8_t min_width : 2; - uint8_t min_height : 2; - uint8_t max_width : 2; - uint8_t max_height : 2; - uint8_t margin_left : 2; - uint8_t margin_right : 2; - uint8_t margin_top : 2; - uint8_t margin_bottom : 2; - uint8_t padding_left : 2; - uint8_t padding_right : 2; - uint8_t padding_top : 2; - uint8_t padding_bottom : 2; - - uint8_t border_top_style : 4; - uint8_t border_right_style : 4; - uint8_t border_bottom_style : 4; - uint8_t border_left_style : 4; - - uint8_t background_image : 2; - uint8_t background_width : 3; - uint8_t background_height : 3; - uint8_t background_repeat : 3; - uint8_t background_clip : 3; - uint8_t background_position_x : 1; - uint8_t background_position_y : 1; - - uint8_t box_shadow : 1; - - uint8_t flex_basis : 2; - uint8_t flex_grow : 1; - uint8_t flex_shrink : 1; - uint8_t flex_direction : 3; - uint8_t flex_wrap : 2; - uint8_t justify_content : 3; - uint8_t align_content : 3; - uint8_t align_items : 3; - - uint8_t color : 2; - uint8_t font_size : 4; - uint8_t font_style : 2; - uint8_t font_weight : 4; - uint8_t font_family : 4; - uint8_t line_height : 2; - uint8_t text_align : 4; - uint8_t content : 2; - uint8_t white_space : 3; - uint8_t word_break : 3; - } type_bits; - - /** - * 属性值单位的比特数据 - */ - struct css_unit_bits { - css_unit_t left : 4; - css_unit_t right : 4; - css_unit_t top : 4; - css_unit_t bottom : 4; - css_unit_t width : 4; - css_unit_t height : 4; - css_unit_t min_width : 4; - css_unit_t min_height : 4; - css_unit_t max_width : 4; - css_unit_t max_height : 4; - css_unit_t margin_left : 4; - css_unit_t margin_right : 4; - css_unit_t margin_top : 4; - css_unit_t margin_bottom : 4; - css_unit_t padding_left : 4; - css_unit_t padding_right : 4; - css_unit_t padding_top : 4; - css_unit_t padding_bottom : 4; - css_unit_t background_width : 4; - css_unit_t background_height : 4; - css_unit_t background_position_x : 4; - css_unit_t background_position_y : 4; - css_unit_t border_top_width : 4; - css_unit_t border_right_width : 4; - css_unit_t border_bottom_width : 4; - css_unit_t border_left_width : 4; - css_unit_t border_top_left_radius : 4; - css_unit_t border_top_right_radius : 4; - css_unit_t border_bottom_left_radius : 4; - css_unit_t border_bottom_right_radius : 4; - css_unit_t box_shadow_x : 4; - css_unit_t box_shadow_y : 4; - css_unit_t box_shadow_blur : 4; - css_unit_t box_shadow_spread : 4; - css_unit_t flex_basis : 4; - css_unit_t font_size : 4; - css_unit_t line_height : 4; - } unit_bits; - - css_numeric_value_t z_index; - css_numeric_value_t opacity; - - css_numeric_value_t left; - css_numeric_value_t right; - css_numeric_value_t top; - css_numeric_value_t bottom; - - css_numeric_value_t width; - css_numeric_value_t height; - css_numeric_value_t min_width; - css_numeric_value_t min_height; - css_numeric_value_t max_width; - css_numeric_value_t max_height; - - css_numeric_value_t margin_left; - css_numeric_value_t margin_right; - css_numeric_value_t margin_top; - css_numeric_value_t margin_bottom; - css_numeric_value_t padding_left; - css_numeric_value_t padding_right; - css_numeric_value_t padding_top; - css_numeric_value_t padding_bottom; - - css_numeric_value_t flex_basis; - css_numeric_value_t flex_grow; - css_numeric_value_t flex_shrink; - - css_color_value_t color; - css_numeric_value_t font_size; - char **font_family; - - css_numeric_value_t line_height; - css_string_value_t content; - - css_numeric_value_t border_top_width; - css_numeric_value_t border_right_width; - css_numeric_value_t border_bottom_width; - css_numeric_value_t border_left_width; - css_color_value_t border_top_color; - css_color_value_t border_right_color; - css_color_value_t border_bottom_color; - css_color_value_t border_left_color; - css_numeric_value_t border_top_left_radius; - css_numeric_value_t border_top_right_radius; - css_numeric_value_t border_bottom_left_radius; - css_numeric_value_t border_bottom_right_radius; - - css_color_value_t background_color; - css_image_value_t background_image; - css_numeric_value_t background_width; - css_numeric_value_t background_height; - css_numeric_value_t background_position_x; - css_numeric_value_t background_position_y; - - // 针对 LCUI 的需求只支持单个阴影效果,暂不考虑支持设置多个阴影效果 - css_numeric_value_t box_shadow_x; - css_numeric_value_t box_shadow_y; - css_numeric_value_t box_shadow_blur; - css_numeric_value_t box_shadow_spread; - css_color_value_t box_shadow_color; - - css_style_value_t *custom_props; - size_t custom_props_count; + /** + * 属性值类型的比特数据 + * 以比特位为单位分配的存储空间,用于节省属性值的内存占用 + */ + struct css_type_bits { + uint8_t display : 5; + uint8_t box_sizing : 2; + uint8_t visibility : 4; + uint8_t vertical_align : 4; + uint8_t pointer_events : 2; + uint8_t position : 3; + + uint8_t z_index : 2; + uint8_t opacity : 2; + + uint8_t left : 2; + uint8_t right : 2; + uint8_t top : 2; + uint8_t bottom : 2; + uint8_t width : 2; + uint8_t height : 2; + uint8_t min_width : 2; + uint8_t min_height : 2; + uint8_t max_width : 2; + uint8_t max_height : 2; + uint8_t margin_left : 2; + uint8_t margin_right : 2; + uint8_t margin_top : 2; + uint8_t margin_bottom : 2; + uint8_t padding_left : 2; + uint8_t padding_right : 2; + uint8_t padding_top : 2; + uint8_t padding_bottom : 2; + + uint8_t border_top_style : 4; + uint8_t border_right_style : 4; + uint8_t border_bottom_style : 4; + uint8_t border_left_style : 4; + + uint8_t background_image : 2; + uint8_t background_width : 3; + uint8_t background_height : 3; + uint8_t background_repeat : 3; + uint8_t background_clip : 3; + uint8_t background_position_x : 1; + uint8_t background_position_y : 1; + + uint8_t box_shadow : 1; + + uint8_t flex_basis : 2; + uint8_t flex_grow : 1; + uint8_t flex_shrink : 1; + uint8_t flex_direction : 3; + uint8_t flex_wrap : 2; + uint8_t justify_content : 3; + uint8_t align_content : 3; + uint8_t align_items : 3; + uint8_t row_gap : 2; + uint8_t column_gap : 2; + + uint8_t color : 2; + uint8_t font_size : 4; + uint8_t font_style : 2; + uint8_t font_weight : 4; + uint8_t font_family : 4; + uint8_t line_height : 2; + uint8_t text_align : 4; + uint8_t content : 2; + uint8_t white_space : 3; + uint8_t word_break : 3; + } type_bits; + + /** + * 属性值单位的比特数据 + */ + struct css_unit_bits { + css_unit_t left : 4; + css_unit_t right : 4; + css_unit_t top : 4; + css_unit_t bottom : 4; + css_unit_t width : 4; + css_unit_t height : 4; + css_unit_t min_width : 4; + css_unit_t min_height : 4; + css_unit_t max_width : 4; + css_unit_t max_height : 4; + css_unit_t margin_left : 4; + css_unit_t margin_right : 4; + css_unit_t margin_top : 4; + css_unit_t margin_bottom : 4; + css_unit_t padding_left : 4; + css_unit_t padding_right : 4; + css_unit_t padding_top : 4; + css_unit_t padding_bottom : 4; + css_unit_t background_width : 4; + css_unit_t background_height : 4; + css_unit_t background_position_x : 4; + css_unit_t background_position_y : 4; + css_unit_t border_top_width : 4; + css_unit_t border_right_width : 4; + css_unit_t border_bottom_width : 4; + css_unit_t border_left_width : 4; + css_unit_t border_top_left_radius : 4; + css_unit_t border_top_right_radius : 4; + css_unit_t border_bottom_left_radius : 4; + css_unit_t border_bottom_right_radius : 4; + css_unit_t box_shadow_x : 4; + css_unit_t box_shadow_y : 4; + css_unit_t box_shadow_blur : 4; + css_unit_t box_shadow_spread : 4; + css_unit_t flex_basis : 4; + css_unit_t font_size : 4; + css_unit_t line_height : 4; + css_unit_t row_gap : 4; + css_unit_t column_gap : 4; + } unit_bits; + + css_numeric_value_t z_index; + css_numeric_value_t opacity; + + css_numeric_value_t left; + css_numeric_value_t right; + css_numeric_value_t top; + css_numeric_value_t bottom; + + css_numeric_value_t width; + css_numeric_value_t height; + css_numeric_value_t min_width; + css_numeric_value_t min_height; + css_numeric_value_t max_width; + css_numeric_value_t max_height; + + css_numeric_value_t margin_left; + css_numeric_value_t margin_right; + css_numeric_value_t margin_top; + css_numeric_value_t margin_bottom; + css_numeric_value_t padding_left; + css_numeric_value_t padding_right; + css_numeric_value_t padding_top; + css_numeric_value_t padding_bottom; + + css_numeric_value_t flex_basis; + css_numeric_value_t flex_grow; + css_numeric_value_t flex_shrink; + css_numeric_value_t row_gap; + css_numeric_value_t column_gap; + + css_color_value_t color; + css_numeric_value_t font_size; + char **font_family; + + css_numeric_value_t line_height; + css_string_value_t content; + + css_numeric_value_t border_top_width; + css_numeric_value_t border_right_width; + css_numeric_value_t border_bottom_width; + css_numeric_value_t border_left_width; + css_color_value_t border_top_color; + css_color_value_t border_right_color; + css_color_value_t border_bottom_color; + css_color_value_t border_left_color; + css_numeric_value_t border_top_left_radius; + css_numeric_value_t border_top_right_radius; + css_numeric_value_t border_bottom_left_radius; + css_numeric_value_t border_bottom_right_radius; + + css_color_value_t background_color; + css_image_value_t background_image; + css_numeric_value_t background_width; + css_numeric_value_t background_height; + css_numeric_value_t background_position_x; + css_numeric_value_t background_position_y; + + // 针对 LCUI 的需求只支持单个阴影效果,暂不考虑支持设置多个阴影效果 + css_numeric_value_t box_shadow_x; + css_numeric_value_t box_shadow_y; + css_numeric_value_t box_shadow_blur; + css_numeric_value_t box_shadow_spread; + css_color_value_t box_shadow_color; + + css_style_value_t *custom_props; + size_t custom_props_count; } css_computed_style_t; typedef struct css_propdef css_propdef_t; struct css_propdef { - /** - * 属性标识号 - * 值为 -1 时,则表明它是简写属性 - */ - int key; - char *name; - css_valdef_t *valdef; - css_style_value_t initial_value; - int (*parse)(const css_propdef_t *, const char *, css_style_decl_t *); - int (*cascade)(const css_style_array_value_t, css_computed_style_t *); + /** + * 属性标识号 + * 值为 -1 时,则表明它是简写属性 + */ + int key; + char *name; + css_valdef_t *valdef; + css_style_value_t initial_value; + int (*parse)(const css_propdef_t *, const char *, css_style_decl_t *); + int (*cascade)(const css_style_array_value_t, css_computed_style_t *); }; typedef bool (*css_value_parse_cb)(css_style_value_t *, const char *); diff --git a/lib/css/src/properties.c b/lib/css/src/properties.c index eec246eb4..f20f56232 100644 --- a/lib/css/src/properties.c +++ b/lib/css/src/properties.c @@ -21,9 +21,9 @@ css_register_property_with_key(css_prop_##PROP_KEY, PROP_NAME, VALDEF, \ INIT, css_cascade_##PROP_KEY) -#define DEFINE_SHORTHAND_PROP(PROP_KEY, NAME, VALDEF) \ +#define DEFINE_SHORTHAND_PROP(PROP_KEY, NAME, VALDEF) \ extern int css_parse_##PROP_KEY(const css_propdef_t *, const char *, \ - css_style_decl_t *); \ + css_style_decl_t *); \ css_register_shorthand_property(NAME, VALDEF, css_parse_##PROP_KEY) static struct css_properties_module { @@ -61,7 +61,8 @@ static void css_propdef_destroy(css_propdef_t *prop) } int css_register_shorthand_property(const char *name, const char *syntax, - int (*parse)(const css_propdef_t *, const char *, + int (*parse)(const css_propdef_t *, + const char *, css_style_decl_t *)) { css_propdef_t *prop; @@ -233,8 +234,8 @@ void css_init_properties(void) "auto | min-content | | ", "auto"); /** @see https://developer.mozilla.org/en-US/docs/Web/CSS/min-height */ - DEFINE_PROP(min_height, "min-height", "auto | min-content | | ", - "auto"); + DEFINE_PROP(min_height, "min-height", + "auto | min-content | | ", "auto"); /** @see https://developer.mozilla.org/en-US/docs/Web/CSS/max-width */ DEFINE_PROP(max_width, "max-width", "auto | | ", @@ -547,6 +548,18 @@ void css_init_properties(void) "normal | stretch | flex-start | flex-end | center", "normal"); + /** @see https://developer.mozilla.org/en-US/docs/Web/CSS/row-gap */ + DEFINE_PROP(row_gap, "row-gap", "normal | ", + "normal"); + + /** @see https://developer.mozilla.org/en-US/docs/Web/CSS/column-gap */ + DEFINE_PROP(column_gap, "column-gap", "normal | ", + "normal"); + + /** @see https://developer.mozilla.org/en-US/docs/Web/CSS/gap */ + DEFINE_SHORTHAND_PROP(gap, "gap", + "[ normal | ]{1,2}"); + /** @see https://developer.mozilla.org/en-US/docs/Web/CSS/color */ DEFINE_PROP(color, "color", "", "#000"); diff --git a/lib/css/src/properties/gap.c b/lib/css/src/properties/gap.c new file mode 100644 index 000000000..2549a377f --- /dev/null +++ b/lib/css/src/properties/gap.c @@ -0,0 +1,96 @@ +/* + * lib/css/src/properties/gap.c + * + * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include "../properties.h" +#include "./helpers.h" + +static void set_row_gap(css_computed_style_t *computed, uint8_t keyword, + css_numeric_value_t value, css_unit_t unit) +{ + computed->row_gap = value; + computed->unit_bits.row_gap = unit; + computed->type_bits.row_gap = keyword; +} + +static void set_column_gap(css_computed_style_t *computed, uint8_t keyword, + css_numeric_value_t value, css_unit_t unit) +{ + computed->column_gap = value; + computed->unit_bits.column_gap = unit; + computed->type_bits.column_gap = keyword; +} + +/* 仅接受 与 normal 关键字;不接受 auto */ +static int cascade_gap_length(const css_style_array_value_t input, + css_computed_style_t *computed, + void (*setter)(css_computed_style_t *, uint8_t, + css_numeric_value_t, css_unit_t)) +{ + switch (input[0].type) { + case CSS_UNIT_VALUE: + setter(computed, CSS_GAP_SET, input[0].unit_value.value, + input[0].unit_value.unit); + break; + case CSS_KEYWORD_VALUE: + if (input[0].keyword_value == CSS_KEYWORD_NORMAL) { + setter(computed, CSS_GAP_NORMAL, 0, CSS_UNIT_PX); + break; + } + return -1; + case CSS_NUMERIC_VALUE: + if (input[0].numeric_value == 0) { + setter(computed, CSS_GAP_SET, 0, CSS_UNIT_PX); + break; + } + return -1; + default: + return -1; + } + return 0; +} + +int css_cascade_row_gap(const css_style_array_value_t input, + css_computed_style_t *computed) +{ + return cascade_gap_length(input, computed, set_row_gap); +} + +int css_cascade_column_gap(const css_style_array_value_t input, + css_computed_style_t *computed) +{ + return cascade_gap_length(input, computed, set_column_gap); +} + +int css_parse_gap(const css_propdef_t *propdef, const char *input, + css_style_decl_t *s) +{ + css_style_value_t value; + int len = css_parse_value(propdef->valdef, input, &value); + + if (len <= 0) { + return len; + } + switch (css_style_value_get_array_length(&value)) { + case 1: + css_style_decl_add(s, css_prop_row_gap, value.array_value); + css_style_decl_add(s, css_prop_column_gap, value.array_value); + break; + case 2: + css_style_decl_add(s, css_prop_row_gap, value.array_value); + css_style_decl_add(s, css_prop_column_gap, + value.array_value + 1); + break; + default: + break; + } + css_style_value_destroy(&value); + return len; +} diff --git a/lib/css/tests/test_css_computed.c b/lib/css/tests/test_css_computed.c index a8f3a24cf..67c4eeab2 100644 --- a/lib/css/tests/test_css_computed.c +++ b/lib/css/tests/test_css_computed.c @@ -150,6 +150,122 @@ void test_button_borderless_style(void) css_computed_style_destroy(&computed); } +void test_flex_gap_shorthand_one_value(void) +{ + css_selector_t *selector; + css_style_decl_t *result; + css_computed_style_t computed; + + selector = css_selector_create(".flex-gap"); + result = css_select_style(selector); + css_cascade_style(result, &computed); + + ctest_equal_int("row-gap type", computed.type_bits.row_gap, + CSS_GAP_SET); + ctest_equal_int("column-gap type", computed.type_bits.column_gap, + CSS_GAP_SET); + ctest_equal_int("row-gap unit", computed.unit_bits.row_gap, + CSS_UNIT_PX); + ctest_equal_int("column-gap unit", computed.unit_bits.column_gap, + CSS_UNIT_PX); + check_length("row-gap", computed.row_gap, 12); + check_length("column-gap", computed.column_gap, 12); + + css_style_decl_destroy(result); + css_selector_destroy(selector); + css_computed_style_destroy(&computed); +} + +void test_flex_gap_shorthand_two_values(void) +{ + css_selector_t *selector; + css_style_decl_t *result; + css_computed_style_t computed; + + selector = css_selector_create(".flex-gap-two-values"); + result = css_select_style(selector); + css_cascade_style(result, &computed); + + ctest_equal_int("row-gap type", computed.type_bits.row_gap, + CSS_GAP_SET); + ctest_equal_int("column-gap type", computed.type_bits.column_gap, + CSS_GAP_SET); + check_length("row-gap", computed.row_gap, 8); + check_length("column-gap", computed.column_gap, 16); + + css_style_decl_destroy(result); + css_selector_destroy(selector); + css_computed_style_destroy(&computed); +} + +void test_flex_gap_axis(void) +{ + css_selector_t *selector; + css_style_decl_t *result; + css_computed_style_t computed; + + selector = css_selector_create(".flex-gap-axis"); + result = css_select_style(selector); + css_cascade_style(result, &computed); + + ctest_equal_int("row-gap type", computed.type_bits.row_gap, + CSS_GAP_SET); + ctest_equal_int("column-gap type", computed.type_bits.column_gap, + CSS_GAP_SET); + check_length("row-gap", computed.row_gap, 4); + check_length("column-gap", computed.column_gap, 20); + + css_style_decl_destroy(result); + css_selector_destroy(selector); + css_computed_style_destroy(&computed); +} + +void test_flex_gap_normal(void) +{ + css_selector_t *selector; + css_style_decl_t *result; + css_computed_style_t computed; + + selector = css_selector_create(".flex-gap-normal"); + result = css_select_style(selector); + css_cascade_style(result, &computed); + + ctest_equal_int("row-gap type", computed.type_bits.row_gap, + CSS_GAP_NORMAL); + ctest_equal_int("column-gap type", computed.type_bits.column_gap, + CSS_GAP_NORMAL); + + css_style_decl_destroy(result); + css_selector_destroy(selector); + css_computed_style_destroy(&computed); +} + +void test_flex_gap_percentage(void) +{ + css_selector_t *selector; + css_style_decl_t *result; + css_computed_style_t computed; + + selector = css_selector_create(".flex-gap-percentage"); + result = css_select_style(selector); + css_cascade_style(result, &computed); + + ctest_equal_int("row-gap type", computed.type_bits.row_gap, + CSS_GAP_SET); + ctest_equal_int("column-gap type", computed.type_bits.column_gap, + CSS_GAP_SET); + ctest_equal_int("row-gap unit", computed.unit_bits.row_gap, + CSS_UNIT_PERCENT); + ctest_equal_int("column-gap unit", computed.unit_bits.column_gap, + CSS_UNIT_PERCENT); + check_length("row-gap", computed.row_gap, 25); + check_length("column-gap", computed.column_gap, 50); + + css_style_decl_destroy(result); + css_selector_destroy(selector); + css_computed_style_destroy(&computed); +} + void test_css_computed(void) { size_t n; @@ -176,6 +292,13 @@ void test_css_computed(void) ctest_describe(".container", test_container_style); ctest_describe(".button.borderless", test_button_borderless_style); ctest_describe(".w-[360px]", test_w360px_style); + ctest_describe(".flex-gap (one value)", + test_flex_gap_shorthand_one_value); + ctest_describe(".flex-gap-two-values", + test_flex_gap_shorthand_two_values); + ctest_describe(".flex-gap-axis", test_flex_gap_axis); + ctest_describe(".flex-gap-normal", test_flex_gap_normal); + ctest_describe(".flex-gap-percentage", test_flex_gap_percentage); css_destroy(); } diff --git a/lib/css/tests/test_css_computed.css b/lib/css/tests/test_css_computed.css index 70b263219..6922dc01e 100644 --- a/lib/css/tests/test_css_computed.css +++ b/lib/css/tests/test_css_computed.css @@ -34,3 +34,29 @@ .w-\[360px\] { width: 360px; } + +.flex-gap { + display: flex; + gap: 12px; +} + +.flex-gap-two-values { + display: flex; + gap: 8px 16px; +} + +.flex-gap-axis { + display: flex; + row-gap: 4px; + column-gap: 20px; +} + +.flex-gap-normal { + display: flex; + gap: normal; +} + +.flex-gap-percentage { + display: flex; + gap: 25% 50%; +} diff --git a/lib/ui/src/ui_flexbox_layout.c b/lib/ui/src/ui_flexbox_layout.c index 9a8e0ad36..f35c961dd 100644 --- a/lib/ui/src/ui_flexbox_layout.c +++ b/lib/ui/src/ui_flexbox_layout.c @@ -43,6 +43,8 @@ typedef struct ui_flexbox_layout_context { bool column_direction; ui_resizer_t *resizer; float cross_size; + float main_gap; + float cross_gap; /** list_t lines */ list_t lines; @@ -91,6 +93,19 @@ static ui_flexbox_line_t *ui_flexbox_layout_next_line( return next_line; } +/* 将 gap 值解析为像素长度,percentage 引用容器对应轴上的内容尺寸 */ +static float ui_flexbox_resolve_gap(uint8_t type, css_numeric_value_t value, + css_unit_t unit, float reference) +{ + if (type != CSS_GAP_SET) { + return 0; + } + if (unit == CSS_UNIT_PERCENT) { + return value * reference / 100.f; + } + return value; +} + static void ui_reset_row_item_flex_basis(ui_widget_t *item) { css_computed_style_t *s = &item->computed_style; @@ -289,6 +304,7 @@ static void ui_flexbox_layout_load_main_size(ui_flexbox_layout_context_t *ctx) css_computed_style_t *cs; float main_size, min_main_size; unsigned child_index = 0; + unsigned in_flow_count = 0; UI_DEBUG_BEGIN; UI_DEBUG_MSG( @@ -309,8 +325,13 @@ static void ui_flexbox_layout_load_main_size(ui_flexbox_layout_context_t *ctx) min_main_size = cs->flex_shrink > 0 ? ui_flexbox_item_min_main_size(ctx, child) : main_size; + if (in_flow_count > 0 && ctx->main_gap > 0) { + ui_resizer_load_item_main_size( + ctx->resizer, ctx->main_gap, ctx->main_gap); + } ui_resizer_load_item_main_size(ctx->resizer, main_size, min_main_size); + in_flow_count++; UI_DEBUG_BEGIN; UI_WIDGET_STR(child, str); UI_WIDGET_SIZE_STR(child, size_str); @@ -340,6 +361,7 @@ static void ui_flexbox_layout_apply_line(ui_flexbox_layout_context_t *ctx, ui_widget_t *child; float item_main_size, item_cross_size; unsigned child_index = 0; + unsigned in_flow_count = 0; line->main_size = 0; line->cross_size = 0; @@ -382,7 +404,11 @@ static void ui_flexbox_layout_apply_line(ui_flexbox_layout_context_t *ctx, if (line->cross_size < item_cross_size) { line->cross_size = item_cross_size; } + if (in_flow_count > 0) { + line->main_size += ctx->main_gap; + } line->main_size += item_main_size; + in_flow_count++; } } @@ -435,9 +461,13 @@ static void ui_flexbox_layout_apply_main_size(ui_flexbox_layout_context_t *ctx) UI_DEBUG_END; if (s->type_bits.flex_wrap == CSS_FLEX_WRAP_WRAP && line->main_size > 0 && - line->main_size + main_size > max_main_size) { + line->main_size + ctx->main_gap + main_size > + max_main_size) { line = ui_flexbox_layout_next_line(ctx); } + if (line->items.length > 0) { + line->main_size += ctx->main_gap; + } line->main_size += main_size; if (column) { if (cs->type_bits.margin_top == CSS_MARGIN_AUTO) { @@ -489,6 +519,9 @@ static void ui_flexbox_layout_apply_main_size(ui_flexbox_layout_context_t *ctx) UI_DEBUG_MSG("line[%zu]: cross_size=%g", line->index, line->cross_size); UI_DEBUG_END; + if (line->index > 0) { + ctx->cross_size += ctx->cross_gap; + } ctx->cross_size += line->cross_size; } if (ctx->cross_size < hint_cross_size) { @@ -585,14 +618,16 @@ static void ui_flexbox_layout_reflow_lines(ui_flexbox_layout_context_t *ctx) ui_flexbox_line_t *line; css_computed_style_t *s = &ctx->widget->computed_style; bool column = ctx->column_direction; + unsigned item_index; float space; float main_axis; float cross_axis = column ? s->padding_left : s->padding_top; - float cross_space = ((column ? ctx->widget->content_box.width - : ctx->widget->content_box.height) - - ctx->cross_size) / - ctx->lines.length; + float cross_free_space = (column ? ctx->widget->content_box.width + : ctx->widget->content_box.height) - + ctx->cross_size; + float cross_space = + ctx->lines.length > 0 ? cross_free_space / ctx->lines.length : 0; float line_max_cross_size; UI_DEBUG_BEGIN; @@ -602,6 +637,9 @@ static void ui_flexbox_layout_reflow_lines(ui_flexbox_layout_context_t *ctx) UI_DEBUG_END; for (list_each(line_node, &ctx->lines)) { line = line_node->data; + if (line->index > 0) { + cross_axis += ctx->cross_gap; + } line_max_cross_size = line->cross_size + cross_space; ui_flexbox_layout_compute_justify_content(ctx, line, &main_axis, &space); @@ -612,12 +650,19 @@ static void ui_flexbox_layout_reflow_lines(ui_flexbox_layout_context_t *ctx) line_max_cross_size); UI_DEBUG_INDENT_INC; UI_DEBUG_END; + item_index = 0; for (list_each(node, &line->items)) { child = node->data; main_axis += space; + if (item_index > 0 && ui_widget_in_layout_flow(child)) { + main_axis += ctx->main_gap; + } main_axis += ui_flexbox_compute_item_layout( ctx, child, main_axis, cross_axis, s->type_bits.align_items, line_max_cross_size); + if (ui_widget_in_layout_flow(child)) { + item_index++; + } } cross_axis += line_max_cross_size; UI_DEBUG_BEGIN; @@ -639,6 +684,22 @@ void ui_flexbox_layout_reflow(ui_widget_t *w, ui_resizer_t *resizer) ctx.column_direction = ui_widget_has_flex_column_direction(w); list_create(&ctx.lines); ui_resizer_init(resizer, w); + { + css_computed_style_t *s = &w->computed_style; + float row_gap = ui_flexbox_resolve_gap( + s->type_bits.row_gap, s->row_gap, s->unit_bits.row_gap, + w->content_box.height); + float column_gap = ui_flexbox_resolve_gap( + s->type_bits.column_gap, s->column_gap, + s->unit_bits.column_gap, w->content_box.width); + if (ctx.column_direction) { + ctx.main_gap = row_gap; + ctx.cross_gap = column_gap; + } else { + ctx.main_gap = column_gap; + ctx.cross_gap = row_gap; + } + } UI_DEBUG_BEGIN; UI_WIDGET_STR(w, str); UI_WIDGET_SIZE_STR(w, size_str); diff --git a/tests/integration/test_flex_layout.c b/tests/integration/test_flex_layout.c index c5fd5b67b..9739d462d 100644 --- a/tests/integration/test_flex_layout.c +++ b/tests/integration/test_flex_layout.c @@ -774,6 +774,209 @@ static void test_flex_layout_320(void) &w->border_box, &rect); } +static void test_flex_layout_gap(void) +{ + ui_widget_t *root; + ui_widget_t *container; + ui_widget_t *child; + ui_rect_t rect; + + root = ui_root(); + ui_widget_resize(root, 800, 600); + + /* (1) row direction with column-gap shorthand */ + + container = ui_create_widget(NULL); + ui_widget_set_style_string(container, "display", "flex"); + ui_widget_set_style_string(container, "width", "300px"); + ui_widget_set_style_string(container, "height", "60px"); + ui_widget_set_style_string(container, "gap", "10px"); + ui_widget_append(root, container); + + child = ui_create_widget(NULL); + ui_widget_set_style_string(child, "width", "50px"); + ui_widget_set_style_string(child, "height", "50px"); + ui_widget_append(container, child); + child = ui_create_widget(NULL); + ui_widget_set_style_string(child, "width", "50px"); + ui_widget_set_style_string(child, "height", "50px"); + ui_widget_append(container, child); + child = ui_create_widget(NULL); + ui_widget_set_style_string(child, "width", "50px"); + ui_widget_set_style_string(child, "height", "50px"); + ui_widget_append(container, child); + child = ui_create_widget(NULL); + ui_widget_set_style_string(child, "width", "50px"); + ui_widget_set_style_string(child, "height", "50px"); + ui_widget_append(container, child); + ui_update(); + + rect.y = 0; + rect.width = 50; + rect.height = 50; + + child = ui_widget_get_child(container, 0); + rect.x = 0; + ctest_equal_ui_rect("row gap: child[0] border_box", &child->border_box, + &rect); + + child = ui_widget_get_child(container, 1); + rect.x = 60; + ctest_equal_ui_rect("row gap: child[1] border_box", &child->border_box, + &rect); + + child = ui_widget_get_child(container, 2); + rect.x = 120; + ctest_equal_ui_rect("row gap: child[2] border_box", &child->border_box, + &rect); + + child = ui_widget_get_child(container, 3); + rect.x = 180; + ctest_equal_ui_rect("row gap: child[3] border_box", &child->border_box, + &rect); + + ui_widget_remove(container); + + /* (2) column direction with row-gap */ + + container = ui_create_widget(NULL); + ui_widget_set_style_string(container, "display", "flex"); + ui_widget_set_style_string(container, "flex-direction", "column"); + ui_widget_set_style_string(container, "width", "100px"); + ui_widget_set_style_string(container, "height", "300px"); + ui_widget_set_style_string(container, "row-gap", "20px"); + ui_widget_append(root, container); + + child = ui_create_widget(NULL); + ui_widget_set_style_string(child, "width", "50px"); + ui_widget_set_style_string(child, "height", "50px"); + ui_widget_append(container, child); + child = ui_create_widget(NULL); + ui_widget_set_style_string(child, "width", "50px"); + ui_widget_set_style_string(child, "height", "50px"); + ui_widget_append(container, child); + child = ui_create_widget(NULL); + ui_widget_set_style_string(child, "width", "50px"); + ui_widget_set_style_string(child, "height", "50px"); + ui_widget_append(container, child); + ui_update(); + + rect.x = 0; + rect.width = 50; + rect.height = 50; + + child = ui_widget_get_child(container, 0); + rect.y = 0; + ctest_equal_ui_rect("column gap: child[0] border_box", + &child->border_box, &rect); + + child = ui_widget_get_child(container, 1); + rect.y = 70; + ctest_equal_ui_rect("column gap: child[1] border_box", + &child->border_box, &rect); + + child = ui_widget_get_child(container, 2); + rect.y = 140; + ctest_equal_ui_rect("column gap: child[2] border_box", + &child->border_box, &rect); + + ui_widget_remove(container); + + /* (3) row + wrap with two-value gap */ + + container = ui_create_widget(NULL); + ui_widget_set_style_string(container, "display", "flex"); + ui_widget_set_style_string(container, "flex-wrap", "wrap"); + ui_widget_set_style_string(container, "width", "200px"); + ui_widget_set_style_string(container, "height", "85px"); + ui_widget_set_style_string(container, "gap", "5px 10px"); + ui_widget_append(root, container); + + child = ui_create_widget(NULL); + ui_widget_set_style_string(child, "width", "80px"); + ui_widget_set_style_string(child, "height", "40px"); + ui_widget_append(container, child); + child = ui_create_widget(NULL); + ui_widget_set_style_string(child, "width", "80px"); + ui_widget_set_style_string(child, "height", "40px"); + ui_widget_append(container, child); + child = ui_create_widget(NULL); + ui_widget_set_style_string(child, "width", "80px"); + ui_widget_set_style_string(child, "height", "40px"); + ui_widget_append(container, child); + child = ui_create_widget(NULL); + ui_widget_set_style_string(child, "width", "80px"); + ui_widget_set_style_string(child, "height", "40px"); + ui_widget_append(container, child); + ui_update(); + + rect.width = 80; + rect.height = 40; + + child = ui_widget_get_child(container, 0); + rect.x = 0; + rect.y = 0; + ctest_equal_ui_rect("wrap gap: child[0] border_box", &child->border_box, + &rect); + + child = ui_widget_get_child(container, 1); + rect.x = 90; + rect.y = 0; + ctest_equal_ui_rect("wrap gap: child[1] border_box", &child->border_box, + &rect); + + child = ui_widget_get_child(container, 2); + rect.x = 0; + rect.y = 45; + ctest_equal_ui_rect("wrap gap: child[2] border_box", &child->border_box, + &rect); + + child = ui_widget_get_child(container, 3); + rect.x = 90; + rect.y = 45; + ctest_equal_ui_rect("wrap gap: child[3] border_box", &child->border_box, + &rect); + + ui_widget_remove(container); + + /* (4) gap: normal should fall back to 0 */ + + container = ui_create_widget(NULL); + ui_widget_set_style_string(container, "display", "flex"); + ui_widget_set_style_string(container, "width", "300px"); + ui_widget_set_style_string(container, "height", "60px"); + ui_widget_set_style_string(container, "gap", "normal"); + ui_widget_append(root, container); + + child = ui_create_widget(NULL); + ui_widget_set_style_string(child, "width", "50px"); + ui_widget_set_style_string(child, "height", "50px"); + ui_widget_append(container, child); + child = ui_create_widget(NULL); + ui_widget_set_style_string(child, "width", "50px"); + ui_widget_set_style_string(child, "height", "50px"); + ui_widget_append(container, child); + ui_update(); + + rect.width = 50; + rect.height = 50; + + child = ui_widget_get_child(container, 0); + rect.x = 0; + rect.y = 0; + ctest_equal_ui_rect("normal gap: child[0] border_box", + &child->border_box, &rect); + + child = ui_widget_get_child(container, 1); + rect.x = 50; + rect.y = 0; + ctest_equal_ui_rect("normal gap: child[1] border_box", + &child->border_box, &rect); + + ui_widget_remove(container); + ui_update(); +} + void test_flex_layout(void) { lcui_init(); @@ -784,6 +987,7 @@ void test_flex_layout(void) ctest_describe("root width 1280px", test_flex_layout_1280); ctest_describe("root width 600px", test_flex_layout_600); ctest_describe("root width 320px", test_flex_layout_320); + ctest_describe("flex gap", test_flex_layout_gap); lcui_destroy(); } From af2bd6fbf74366c30d0c9075376656483c5bc592 Mon Sep 17 00:00:00 2001 From: Liu Date: Sun, 7 Jun 2026 00:17:00 +0800 Subject: [PATCH 28/66] test(flex-layout): add gap example to preview fixture Add a new "(18) gap" example block in tests/fixtures/test_flex_layout.xml that exercises the gap shorthand and longhand variants: - gap: 10px - gap: 10px 5px with flex-wrap: wrap - row-gap: 10px with flex-direction: column - column-gap: 10px with justify-content: space-between Define the corresponding utility classes (.gap-2, .gap-2-1, .row-gap-2, .column-gap-2) in test_flex_layout.css so the example renders in `xmake run preview-flex-layout`. The new block is appended after the existing Browser Layout example to preserve the indices used by the flex-layout integration tests. --- tests/fixtures/test_flex_layout.css | 16 +++++++++++ tests/fixtures/test_flex_layout.xml | 42 ++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/tests/fixtures/test_flex_layout.css b/tests/fixtures/test_flex_layout.css index ad6169627..f3e1551e3 100644 --- a/tests/fixtures/test_flex_layout.css +++ b/tests/fixtures/test_flex_layout.css @@ -183,6 +183,22 @@ scrollarea-content { align-items: stretch; } +.gap-2 { + gap: 10px; +} + +.gap-2-1 { + gap: 10px 5px; +} + +.row-gap-2 { + row-gap: 10px; +} + +.column-gap-2 { + column-gap: 10px; +} + .example-1-flex-default .example__content { display: flex; } diff --git a/tests/fixtures/test_flex_layout.xml b/tests/fixtures/test_flex_layout.xml index b936cc892..966b3e914 100644 --- a/tests/fixtures/test_flex_layout.xml +++ b/tests/fixtures/test_flex_layout.xml @@ -2,7 +2,7 @@ - + (0) Default @@ -353,6 +353,46 @@ + + (18) gap: 10px; + + + + + + + + (18.1) gap: 10px 5px; flex-wrap: wrap; + + + + + + width: 150px + + + width: 100px + + + width: 200px + + + + (18.2) row-gap: 10px; flex-direction: column; + + + + + + + (18.3) column-gap: 10px; justify-content: space-between; + + + + + + + From 04a00f9c272f99d5ddf1ed832974fb6dcc7228f8 Mon Sep 17 00:00:00 2001 From: Liu Date: Sun, 7 Jun 2026 00:26:01 +0800 Subject: [PATCH 29/66] chore: remove unused debug log --- lib/ptk/src/windows/win32app.c | 4 ---- lib/ptk/src/windows/win32clipboard.c | 3 --- lib/ui-server/src/server.c | 26 -------------------------- 3 files changed, 33 deletions(-) diff --git a/lib/ptk/src/windows/win32app.c b/lib/ptk/src/windows/win32app.c index a9cd48906..c1be3bf99 100644 --- a/lib/ptk/src/windows/win32app.c +++ b/lib/ptk/src/windows/win32app.c @@ -113,7 +113,6 @@ static int ptk_process_native_event(void) ret = GetMessage(&msg, NULL, 0, 0); ptk_process_events(); if (ret == 0) { - logger_debug("[win32-app] WM_QUIT\n"); win32_app.exit_code = (int)msg.wParam; e.type = PTK_EVENT_QUIT; ptk_process_event(&e); @@ -310,9 +309,6 @@ static LRESULT CALLBACK ptk_window_process(HWND hwnd, UINT msg, WPARAM arg1, e.size.width = LOWORD(arg2); e.size.height = HIWORD(arg2); ptk_window_on_size(wnd, e.size.width, e.size.height); - logger_debug( - "[win32-app] [window %p] on WM_SIZE, size: (%d, %d)\n", wnd, - e.size.width, e.size.height); break; } case WM_GETMINMAXINFO: { diff --git a/lib/ptk/src/windows/win32clipboard.c b/lib/ptk/src/windows/win32clipboard.c index ba712cda6..fddbd4b4a 100644 --- a/lib/ptk/src/windows/win32clipboard.c +++ b/lib/ptk/src/windows/win32clipboard.c @@ -194,9 +194,6 @@ void ptk_win32clipboard_init(void) if (ptk_win32clipboard.hwnd == NULL) { ptk_win32clipboard.hwnd = GetDesktopWindow(); } - - logger_debug("Win32 clipboard initialized with HWND: %p\n", - ptk_win32clipboard.hwnd); } void ptk_win32clipboard_destroy(void) diff --git a/lib/ui-server/src/server.c b/lib/ui-server/src/server.c index cb6f2c9e2..3a820e310 100644 --- a/lib/ui-server/src/server.c +++ b/lib/ui-server/src/server.c @@ -137,9 +137,6 @@ int ui_server_disconnect(ui_widget_t *widget, ptk_window_t *window) conn = node->data; if ((widget && conn->widget == widget) || (window && conn->window == window)) { - logger_debug( - "[ui-server] [window %p] disconnect widget: %p\n", - conn->window, conn->widget); ptk_window_close(conn->window); count++; } @@ -164,7 +161,6 @@ static void ui_server_on_window_close(ptk_event_t *e, void *arg) ui_connection_t *conn; list_node_t *node; - logger_debug("[ui-server] [window %p] on close\n", e->window); for (list_each(node, &ui_server.connections)) { conn = node->data; if (conn->window == e->window) { @@ -224,16 +220,10 @@ static void ui_server_on_window_resize(ptk_event_t *e, void *arg) height = e->size.height / scale; ui_widget_mark_dirty_rect(conn->widget, NULL, UI_BOX_TYPE_GRAPH_BOX); ui_widget_resize(conn->widget, width, height); - logger_debug( - "[ui-server] [window %p] on_window_resize, widget: (%p, %s), size " - "(%g, %g)\n", - e->window, conn->widget, conn->widget->type, width, height); } static void ui_server_on_window_dpi_changed(ptk_event_t *e, void *arg) { - logger_debug("[ui-server] [window %p] on_window_dpi_changed, dpi: %d\n", - e->window, e->dpi_change.dpi); ui_refresh_style(); } @@ -326,8 +316,6 @@ void ui_server_connect(ui_widget_t *widget, ptk_window_t *window) ui_mutation_observer_observe(ui_server.observer, widget, options); // 在同步前处理所有消息,包括窗口位置、大小变更消息,避免在初次更新时组件的位置和尺寸被窗口覆盖 ptk_process_native_events(PTK_PROCESS_EVENTS_ALL_IF_PRESENT); - logger_debug("[ui-server] [window %p] connect widget(%p, %s)\n", window, - widget, widget->type); } static void get_rendering_layer_size(int *width, int *height) @@ -655,31 +643,17 @@ static void ui_server_on_widget_mutation(ui_mutation_list_t *mutation_list, ptk_window_set_position(wnd_mutation->window, wnd_mutation->x, wnd_mutation->y); - logger_debug("[ui-server] [window %p] update position: " - "(%d, %d)\n", - wnd_mutation->window, wnd_mutation->x, - wnd_mutation->y); } if (wnd_mutation->update_size) { ptk_window_set_size(wnd_mutation->window, wnd_mutation->width, wnd_mutation->height); - logger_debug( - "[ui-server] [window %p] update size: (%d, %d)\n", - wnd_mutation->window, wnd_mutation->width, - wnd_mutation->height); } if (wnd_mutation->update_title) { ptk_window_set_title(wnd_mutation->window, wnd_mutation->title); - logger_debug( - "[ui-server] [window %p] update title: %ls\n", - wnd_mutation->window, wnd_mutation->title); } if (wnd_mutation->update_visible) { - logger_debug( - "[ui-server] [window %p] update visible %d\n", - wnd_mutation->window, wnd_mutation->visible); if (wnd_mutation->visible) { ptk_window_show(wnd_mutation->window); } else { From 70afc7ea9999dd0bcafd1bda247822772a5afc0d Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Jun 2026 19:22:47 +0800 Subject: [PATCH 30/66] feat: update settings APIs and add persistent configuration support (#329) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- include/LCUI/app.h | 4 + include/LCUI/settings.h | 25 +- src/lcui.c | 7 +- src/lcui_app.c | 51 ++- src/lcui_settings.c | 547 +++++++++++++++++++++++++++++- tests/integration/test_settings.c | 291 +++++++++++----- 6 files changed, 828 insertions(+), 97 deletions(-) diff --git a/include/LCUI/app.h b/include/LCUI/app.h index 20bff2ea9..24e42ea43 100644 --- a/include/LCUI/app.h +++ b/include/LCUI/app.h @@ -13,10 +13,14 @@ #define LCUI_INCLUDE_LCUI_APP_H #include "common.h" +#include #include LCUI_BEGIN_HEADER +LCUI_API bool lcui_set_app_id(const char *app_id); +LCUI_API const char *lcui_get_app_id(void); + LCUI_API uint32_t lcui_get_fps(void); LCUI_API void lcui_set_fps_cap(unsigned fps_cap); diff --git a/include/LCUI/settings.h b/include/LCUI/settings.h index 8c5b3f2d5..0e94effc9 100644 --- a/include/LCUI/settings.h +++ b/include/LCUI/settings.h @@ -13,18 +13,37 @@ #define LCUI_INCLUDE_LCUI_SETTINGS_H #include "common.h" - -#define LCUI_MAX_FRAMES_PER_SEC 120 +#include + +#define LCUI_RENDERING_FPS_CAP_MIN 30 +#define LCUI_RENDERING_FPS_CAP_MAX 480 +#define LCUI_RENDERING_PARALLEL_THREADS_MIN 1 +#define LCUI_RENDERING_PARALLEL_THREADS_MAX 64 +#define LCUI_DEFAULT_FPS_CAP 120 +#define LCUI_DEFAULT_PARALLEL_THREADS 4 +#define LCUI_MAX_FRAMES_PER_SEC LCUI_DEFAULT_FPS_CAP #define LCUI_MAX_FRAME_MSEC ((int)(1000.0 / LCUI_MAX_FRAMES_PER_SEC + 0.5)) LCUI_BEGIN_HEADER +typedef struct lcui_rendering_settings { + int fps_cap; + int parallel_threads; + bool paint_flashing; +} lcui_rendering_settings_t; + typedef struct lcui_settings { int fps_cap; int parallel_rendering_threads; bool paint_flashing; } lcui_settings_t; +LCUI_API bool lcui_settings_load(void); +LCUI_API bool lcui_settings_flush(void); +LCUI_API void lcui_settings_unload(void); +LCUI_API bool lcui_settings_get_rendering(lcui_rendering_settings_t *out); +LCUI_API bool lcui_settings_set_rendering(const lcui_rendering_settings_t *in); + /* Initialize settings with the current global settings. */ LCUI_API void lcui_get_settings(lcui_settings_t *settings); @@ -34,4 +53,6 @@ LCUI_API void lcui_apply_settings(lcui_settings_t *settings); /* Reset global settings to their defaults. */ LCUI_API void lcui_reset_settings(void); +LCUI_END_HEADER + #endif diff --git a/src/lcui.c b/src/lcui.c index a8210404d..869ef52d2 100644 --- a/src/lcui.c +++ b/src/lcui.c @@ -41,11 +41,16 @@ void lcui_init(void) lcui_app_init(); lcui_fonts_init(); lcui_widgets_init(); - lcui_reset_settings(); + if (!lcui_settings_load()) { + logger_warning( + "failed to load settings, fallback to built-in defaults\n"); + lcui_reset_settings(); + } } void lcui_destroy(void) { + lcui_settings_unload(); lcui_widgets_destroy(); lcui_app_destroy(); } diff --git a/src/lcui_app.c b/src/lcui_app.c index ac98972d5..a74ab7f84 100644 --- a/src/lcui_app.c +++ b/src/lcui_app.c @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include #include @@ -46,6 +48,47 @@ static struct lcui_app { uint32_t frames_this_second; uint32_t frames_per_second; } lcui_app; +static char *lcui_app_id = NULL; + +static bool lcui_app_id_is_valid(const char *app_id) +{ + const unsigned char *p; + + if (!app_id || app_id[0] == 0) { + return false; + } + for (p = (const unsigned char *)app_id; *p; ++p) { + if (isalnum(*p) || *p == '.' || *p == '_' || *p == '-') { + continue; + } + return false; + } + return true; +} + +bool lcui_set_app_id(const char *app_id) +{ + size_t len; + char *new_app_id; + + if (!lcui_app_id_is_valid(app_id)) { + return false; + } + len = strlen(app_id); + new_app_id = malloc(sizeof(char) * (len + 1)); + if (!new_app_id) { + return false; + } + strcpy(new_app_id, app_id); + free(lcui_app_id); + lcui_app_id = new_app_id; + return true; +} + +const char *lcui_get_app_id(void) +{ + return lcui_app_id ? lcui_app_id : "lcui"; +} static void lcui_dispatch_ui_mouse_event(ui_event_type_t type, ptk_event_t *app_evt) @@ -168,7 +211,8 @@ static void lcui_app_on_anim_frame(ptk_steptimer_t *timer, void *data) uint64_t timestamp = (uint64_t)get_time_ms(); list_node_t *node; - list_for_each(node, &lcui_app.frame_cbs) { + list_for_each(node, &lcui_app.frame_cbs) + { lcui_frame_request_t *req = node->data; req->callback(timestamp, req->data); } @@ -193,7 +237,8 @@ void lcui_cancel_frame(int request_id) { list_node_t *node; - list_for_each(node, &lcui_app.frame_cbs) { + list_for_each(node, &lcui_app.frame_cbs) + { lcui_frame_request_t *req = node->data; if (req->id == request_id) { list_unlink(&lcui_app.frame_cbs, node); @@ -285,5 +330,7 @@ void lcui_app_destroy(void) lcui_ui_destroy(); lcui_worker_destroy(); list_destroy_without_node(&lcui_app.frame_cbs, NULL); + free(lcui_app_id); + lcui_app_id = NULL; ptk_destroy(); } diff --git a/src/lcui_settings.c b/src/lcui_settings.c index 78f26deda..656af95de 100644 --- a/src/lcui_settings.c +++ b/src/lcui_settings.c @@ -11,38 +11,555 @@ * LICENSE.TXT file in the root directory of this source tree. */ +#include +#include +#include +#include +#include +#include +#ifndef _WIN32 +#include +#endif +#ifdef _WIN32 +#include +#include +#else +#include +#include +#endif #include #include #include #include -static lcui_settings_t lcui_settings; +#ifdef _WIN32 +#define strcasecmp _stricmp +#endif + +typedef struct lcui_store_rendering { + int fps_cap; + int parallel_threads; + bool paint_flashing; +} lcui_store_rendering_t; + +static struct lcui_settings_module { + bool loaded; + bool dirty; + char *path; + lcui_store_rendering_t rendering; +} lcui_settings; + +static const lcui_store_rendering_t lcui_default_rendering_settings = { + LCUI_DEFAULT_FPS_CAP, LCUI_DEFAULT_PARALLEL_THREADS, false +}; + +static char *lcui_strdup(const char *str) +{ + size_t len; + char *copy; + + if (!str) { + return NULL; + } + len = strlen(str); + copy = malloc(sizeof(char) * (len + 1)); + if (!copy) { + return NULL; + } + strcpy(copy, str); + return copy; +} + +static int lcui_mkdir(const char *path) +{ +#ifdef _WIN32 + return _mkdir(path); +#else + return mkdir(path, 0700); +#endif +} + +static bool lcui_mkdir_recursive(const char *path) +{ + size_t i, len; + char ch; + char *buffer; + + if (!path || path[0] == 0) { + return false; + } + len = strlen(path); + buffer = lcui_strdup(path); + if (!buffer) { + return false; + } + for (i = 1; i <= len; ++i) { + if (buffer[i] != '/' && buffer[i] != '\\' && buffer[i] != 0) { + continue; + } + ch = buffer[i]; + if (ch != 0) { + buffer[i] = 0; + } + if (buffer[0] == 0) { + if (ch != 0) { + buffer[i] = ch; + } + continue; + } +#ifdef _WIN32 + if (isalpha((unsigned char)buffer[0]) && buffer[1] == ':' && + buffer[2] == 0) { + if (ch != 0) { + buffer[i] = ch; + } + continue; + } +#endif + if (lcui_mkdir(buffer) != 0 && errno != EEXIST) { + free(buffer); + return false; + } + if (ch != 0) { + buffer[i] = ch; + } + } + free(buffer); + return true; +} + +static char *lcui_join_path(const char *left, const char *right) +{ + size_t left_len, right_len; + char *path; + + if (!left || !right) { + return NULL; + } + left_len = strlen(left); + right_len = strlen(right); + path = malloc(sizeof(char) * (left_len + right_len + 2)); + if (!path) { + return NULL; + } + strcpy(path, left); + if (left_len > 0 && path[left_len - 1] != '/' && + path[left_len - 1] != '\\') { + path[left_len] = '/'; + path[left_len + 1] = 0; + } + strcat(path, right); + return path; +} + +static char *lcui_settings_get_config_root(void) +{ +#ifdef _WIN32 + const char *base = getenv("APPDATA"); + if (base && base[0] != 0) { + return lcui_strdup(base); + } + base = getenv("USERPROFILE"); + if (base && base[0] != 0) { + return lcui_join_path(base, "AppData/Roaming"); + } +#elif defined(__APPLE__) + const char *base = getenv("HOME"); + if (base && base[0] != 0) { + return lcui_join_path(base, "Library/Application Support"); + } +#else + const char *base = getenv("XDG_CONFIG_HOME"); + if (base && base[0] != 0) { + return lcui_strdup(base); + } + base = getenv("HOME"); + if (base && base[0] != 0) { + return lcui_join_path(base, ".config"); + } +#endif + return NULL; +} + +static bool lcui_settings_resolve_path(char **out_path) +{ + char *config_root, *app_dir, *settings_path; + const char *app_id = lcui_get_app_id(); + + if (!app_id || app_id[0] == 0) { + return false; + } + config_root = lcui_settings_get_config_root(); + if (!config_root) { + return false; + } + app_dir = lcui_join_path(config_root, app_id); + free(config_root); + if (!app_dir) { + return false; + } + if (!lcui_mkdir_recursive(app_dir)) { + free(app_dir); + return false; + } + settings_path = lcui_join_path(app_dir, "settings.ini"); + free(app_dir); + if (!settings_path) { + return false; + } + *out_path = settings_path; + return true; +} + +static char *lcui_store_trim(char *str) +{ + size_t len; + + while (*str && isspace((unsigned char)*str)) { + ++str; + } + len = strlen(str); + while (len > 0 && isspace((unsigned char)str[len - 1])) { + str[--len] = 0; + } + return str; +} + +static bool lcui_store_parse_int(const char *str, int *out) +{ + long value; + char *endptr; + + if (!str || !out) { + return false; + } + errno = 0; + value = strtol(str, &endptr, 10); + if (errno != 0 || endptr == str || *endptr != 0 || value > INT_MAX || + value < INT_MIN) { + return false; + } + *out = (int)value; + return true; +} + +static bool lcui_store_parse_bool(const char *str, bool *out) +{ + if (!str || !out) { + return false; + } + if (strcmp(str, "1") == 0 || strcasecmp(str, "true") == 0) { + *out = true; + return true; + } + if (strcmp(str, "0") == 0 || strcasecmp(str, "false") == 0) { + *out = false; + return true; + } + return false; +} + +static bool lcui_store_load(const char *path, lcui_store_rendering_t *settings, + bool *dirty, bool *exists) +{ + int value; + bool flag; + bool has_version = false; + char line[1024]; + char section[64] = { 0 }; + FILE *fp = fopen(path, "r"); + + if (!fp) { + if (errno == ENOENT) { + *exists = false; + return true; + } + return false; + } + *exists = true; + while (fgets(line, sizeof(line), fp)) { + char *data = lcui_store_trim(line); + char *equal; + + if (data[0] == 0 || data[0] == ';' || data[0] == '#') { + continue; + } + if (data[0] == '[') { + char *end = strchr(data, ']'); + if (!end) { + continue; + } + *end = 0; + snprintf(section, sizeof(section), "%s", data + 1); + continue; + } + equal = strchr(data, '='); + if (!equal) { + continue; + } + *equal++ = 0; + data = lcui_store_trim(data); + equal = lcui_store_trim(equal); + if (strcasecmp(section, "meta") == 0 && + strcasecmp(data, "version") == 0) { + has_version = true; + if (!lcui_store_parse_int(equal, &value) || + value != 1) { + *dirty = true; + } + continue; + } + if (strcasecmp(section, "rendering") != 0) { + continue; + } + if (strcasecmp(data, "fps_cap") == 0) { + if (lcui_store_parse_int(equal, &value)) { + settings->fps_cap = value; + } else { + *dirty = true; + } + continue; + } + if (strcasecmp(data, "parallel_threads") == 0) { + if (lcui_store_parse_int(equal, &value)) { + settings->parallel_threads = value; + } else { + *dirty = true; + } + continue; + } + if (strcasecmp(data, "paint_flashing") == 0) { + if (lcui_store_parse_bool(equal, &flag)) { + settings->paint_flashing = flag; + } else { + *dirty = true; + } + } + } + fclose(fp); + if (!has_version) { + *dirty = true; + } + return true; +} + +static bool lcui_store_save(const char *path, + const lcui_store_rendering_t *settings) +{ + size_t path_len; + char *tmp_path; + FILE *fp; + int ret; + + path_len = strlen(path); + tmp_path = malloc(sizeof(char) * (path_len + 5)); + if (!tmp_path) { + return false; + } + strcpy(tmp_path, path); + strcat(tmp_path, ".tmp"); + fp = fopen(tmp_path, "w"); + if (!fp) { + free(tmp_path); + return false; + } + fprintf(fp, "[meta]\nversion=1\n\n"); + fprintf(fp, "[rendering]\n"); + fprintf(fp, "fps_cap=%d\n", settings->fps_cap); + fprintf(fp, "parallel_threads=%d\n", settings->parallel_threads); + fprintf(fp, "paint_flashing=%d\n", settings->paint_flashing ? 1 : 0); + fclose(fp); +#ifdef _WIN32 + ret = MoveFileExA(tmp_path, path, + MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) + ? 0 + : -1; +#else + ret = rename(tmp_path, path); +#endif + free(tmp_path); + return ret == 0; +} + +static bool lcui_settings_repair_rendering(lcui_store_rendering_t *settings) +{ + bool valid = true; + + if (settings->fps_cap < LCUI_RENDERING_FPS_CAP_MIN || + settings->fps_cap > LCUI_RENDERING_FPS_CAP_MAX) { + settings->fps_cap = lcui_default_rendering_settings.fps_cap; + valid = false; + } + if (settings->parallel_threads < LCUI_RENDERING_PARALLEL_THREADS_MIN || + settings->parallel_threads > LCUI_RENDERING_PARALLEL_THREADS_MAX) { + settings->parallel_threads = + lcui_default_rendering_settings.parallel_threads; + valid = false; + } + return valid; +} + +static bool lcui_settings_validate_rendering( + const lcui_rendering_settings_t *settings) +{ + if (!settings) { + return false; + } + if (settings->fps_cap < LCUI_RENDERING_FPS_CAP_MIN || + settings->fps_cap > LCUI_RENDERING_FPS_CAP_MAX) { + return false; + } + if (settings->parallel_threads < LCUI_RENDERING_PARALLEL_THREADS_MIN || + settings->parallel_threads > LCUI_RENDERING_PARALLEL_THREADS_MAX) { + return false; + } + return true; +} + +static void lcui_settings_apply_rendering(void) +{ + ui_server_set_threads(lcui_settings.rendering.parallel_threads); + ui_server_set_paint_flashing_enabled( + lcui_settings.rendering.paint_flashing); + lcui_set_fps_cap((unsigned)lcui_settings.rendering.fps_cap); +} + +bool lcui_settings_load(void) +{ + bool exists = false; + char *path; + + if (lcui_settings.loaded) { + return true; + } + if (!lcui_settings_resolve_path(&path)) { + return false; + } + lcui_settings.rendering = lcui_default_rendering_settings; + lcui_settings.dirty = false; + if (!lcui_store_load(path, &lcui_settings.rendering, + &lcui_settings.dirty, &exists)) { + free(path); + return false; + } + if (!exists || + !lcui_settings_repair_rendering(&lcui_settings.rendering)) { + lcui_settings.dirty = true; + } + lcui_settings.loaded = true; + lcui_settings.path = path; + lcui_settings_apply_rendering(); + return true; +} + +bool lcui_settings_flush(void) +{ + if (!lcui_settings.loaded || !lcui_settings.path) { + return false; + } + if (!lcui_settings.dirty) { + return true; + } + if (!lcui_store_save(lcui_settings.path, &lcui_settings.rendering)) { + return false; + } + lcui_settings.dirty = false; + return true; +} + +void lcui_settings_unload(void) +{ + free(lcui_settings.path); + lcui_settings.path = NULL; + lcui_settings.loaded = false; + lcui_settings.dirty = false; + lcui_settings.rendering = lcui_default_rendering_settings; +} + +bool lcui_settings_get_rendering(lcui_rendering_settings_t *out) +{ + if (!lcui_settings.loaded || !out) { + return false; + } + out->fps_cap = lcui_settings.rendering.fps_cap; + out->parallel_threads = lcui_settings.rendering.parallel_threads; + out->paint_flashing = lcui_settings.rendering.paint_flashing; + return true; +} + +bool lcui_settings_set_rendering(const lcui_rendering_settings_t *in) +{ + if (!lcui_settings.loaded || !in || + !lcui_settings_validate_rendering(in)) { + return false; + } + if (lcui_settings.rendering.fps_cap == in->fps_cap && + lcui_settings.rendering.parallel_threads == in->parallel_threads && + lcui_settings.rendering.paint_flashing == in->paint_flashing) { + return true; + } + lcui_settings.rendering.fps_cap = in->fps_cap; + lcui_settings.rendering.parallel_threads = in->parallel_threads; + lcui_settings.rendering.paint_flashing = in->paint_flashing; + lcui_settings_apply_rendering(); + lcui_settings.dirty = true; + return true; +} /* Initialize settings with the current global settings. */ void lcui_get_settings(lcui_settings_t *settings) { - *settings = lcui_settings; + if (!settings) { + return; + } + settings->fps_cap = lcui_settings.rendering.fps_cap; + settings->parallel_rendering_threads = + lcui_settings.rendering.parallel_threads; + settings->paint_flashing = lcui_settings.rendering.paint_flashing; } /* Update global settings with the given input. */ void lcui_apply_settings(lcui_settings_t *settings) { - lcui_settings = *settings; - lcui_settings.fps_cap = y_max(lcui_settings.fps_cap, 1); - lcui_settings.parallel_rendering_threads = - y_max(lcui_settings.parallel_rendering_threads, 1); - ui_server_set_threads(lcui_settings.parallel_rendering_threads); - ui_server_set_paint_flashing_enabled(lcui_settings.paint_flashing); - lcui_set_fps_cap(lcui_settings.fps_cap); + lcui_rendering_settings_t rendering; + + if (!settings) { + return; + } + rendering.fps_cap = settings->fps_cap; + rendering.parallel_threads = settings->parallel_rendering_threads; + rendering.paint_flashing = settings->paint_flashing; + if (!lcui_settings_validate_rendering(&rendering)) { + lcui_store_rendering_t repaired = { rendering.fps_cap, + rendering.parallel_threads, + rendering.paint_flashing }; + lcui_settings_repair_rendering(&repaired); + rendering.fps_cap = repaired.fps_cap; + rendering.parallel_threads = repaired.parallel_threads; + } + if (lcui_settings.loaded) { + (void)lcui_settings_set_rendering(&rendering); + return; + } + lcui_settings.rendering.fps_cap = rendering.fps_cap; + lcui_settings.rendering.parallel_threads = rendering.parallel_threads; + lcui_settings.rendering.paint_flashing = rendering.paint_flashing; + lcui_settings_apply_rendering(); } /* Reset global settings to their defaults. */ void lcui_reset_settings(void) { - lcui_settings_t settings = { - .fps_cap = LCUI_MAX_FRAMES_PER_SEC, - .parallel_rendering_threads = 4, - .paint_flashing = false - }; - lcui_apply_settings(&settings); + lcui_rendering_settings_t settings = { + lcui_default_rendering_settings.fps_cap, + lcui_default_rendering_settings.parallel_threads, + lcui_default_rendering_settings.paint_flashing + }; + + if (lcui_settings.loaded) { + (void)lcui_settings_set_rendering(&settings); + return; + } + lcui_settings.rendering = lcui_default_rendering_settings; + lcui_settings_apply_rendering(); } diff --git a/tests/integration/test_settings.c b/tests/integration/test_settings.c index e2729984b..0658b62c9 100644 --- a/tests/integration/test_settings.c +++ b/tests/integration/test_settings.c @@ -9,112 +9,249 @@ * LICENSE.TXT file in the root directory of this source tree. */ +#include #include +#include +#include +#include +#ifdef _WIN32 +#include +#include +#else +#include +#include +#include +#endif #include #include -static void check_settings_fps_cap(void *arg) +static int test_mkdir(const char *path) { - char str[256]; - int fps_limit = *((int *)arg); - int fps = (int)lcui_get_fps(); - - sprintf(str, "should reach frame cap of %u (actual %u)", fps_limit, - fps); - ctest_equal_bool(str, fps <= fps_limit + 2 && fps > fps_limit / 2, - true); - lcui_quit(); +#ifdef _WIN32 + return _mkdir(path); +#else + return mkdir(path, 0700); +#endif } -static void test_default_settings(void) +static unsigned test_path_counter = 0; + +static bool test_set_env(const char *name, const char *value) { - lcui_settings_t settings; +#ifdef _WIN32 + return _putenv_s(name, value) == 0; +#else + return setenv(name, value, 1) == 0; +#endif +} - lcui_init(); - lcui_reset_settings(); - lcui_get_settings(&settings); +static bool test_prepare_env(char *base_dir, size_t base_dir_size, + const char *app_id) +{ + int ret; + const char *tmp_root; +#ifdef _WIN32 + int pid = _getpid(); + tmp_root = getenv("TEMP"); + if (!tmp_root || tmp_root[0] == 0) { + tmp_root = "C:/Temp"; + } +#else + int pid = getpid(); + tmp_root = getenv("TMPDIR"); + if (!tmp_root || tmp_root[0] == 0) { + tmp_root = "/tmp"; + } +#endif - ctest_equal_int("should default frame rate cap to 120", - settings.fps_cap, 120); - ctest_equal_int("should default parallel rendering threads to 4", - settings.parallel_rendering_threads, 4); - ctest_equal_bool("should disable paint flashing by default", - settings.paint_flashing, false); - lcui_quit(); - lcui_main(); + snprintf(base_dir, base_dir_size, "%s/lcui-settings-%d-%lu", tmp_root, + pid, (unsigned long)time(NULL) + ++test_path_counter); + ret = test_mkdir(base_dir); + if (ret != 0 && errno != EEXIST) { + return false; + } +#ifdef _WIN32 + if (!test_set_env("APPDATA", base_dir)) { + return false; + } +#else + if (!test_set_env("XDG_CONFIG_HOME", base_dir)) { + return false; + } +#endif + if (!lcui_set_app_id(app_id)) { + return false; + } + return true; } -static void test_apply_settings(void) +static bool test_write_config(const char *base_dir, const char *app_id, + const char *content) { - lcui_settings_t settings; + bool ok = false; + char app_dir[512]; + char config_file[600]; + FILE *fp; - settings.fps_cap = 60; - settings.parallel_rendering_threads = 2; - settings.paint_flashing = true; + snprintf(app_dir, sizeof(app_dir), "%s/%s", base_dir, app_id); + if (test_mkdir(app_dir) != 0 && errno != EEXIST) { + return false; + } + snprintf(config_file, sizeof(config_file), "%s/settings.ini", app_dir); + fp = fopen(config_file, "w"); + if (!fp) { + return false; + } + if (fputs(content, fp) >= 0) { + ok = true; + } + fclose(fp); + return ok; +} - lcui_init(); - lcui_apply_settings(&settings); - lcui_get_settings(&settings); - ctest_equal_int("should apply frame rate cap", settings.fps_cap, 60); - ctest_equal_int("should apply parallel rendering threads", - settings.parallel_rendering_threads, 2); - ctest_equal_bool("should enable paint flashing", - settings.paint_flashing, true); +static bool test_read_file_contains(const char *base_dir, const char *app_id, + const char *text) +{ + bool found = false; + char config_file[600]; + char content[1024]; + FILE *fp; + size_t len; - settings.fps_cap = -1; - settings.parallel_rendering_threads = -1; + snprintf(config_file, sizeof(config_file), "%s/%s/settings.ini", + base_dir, app_id); + fp = fopen(config_file, "r"); + if (!fp) { + return false; + } + len = fread(content, 1, sizeof(content) - 1, fp); + fclose(fp); + content[len] = 0; + if (strstr(content, text)) { + found = true; + } + return found; +} - lcui_apply_settings(&settings); - lcui_get_settings(&settings); +static void test_settings_rendering_accessors(void) +{ + char base_dir[256]; + lcui_rendering_settings_t settings; - ctest_equal_int("should clamp frame rate cap to minimum 1", - settings.fps_cap, 1); - ctest_equal_int("should clamp parallel rendering threads to minimum 1", - settings.parallel_rendering_threads, 1); + ctest_equal_bool("prepare settings test env", + test_prepare_env(base_dir, sizeof(base_dir), + "lcui-settings-rendering"), + true); + lcui_init(); + ctest_equal_bool("should load settings", lcui_settings_load(), true); + ctest_equal_bool("should get default rendering settings", + lcui_settings_get_rendering(&settings), true); + ctest_equal_int("should default frame rate cap to 120", + settings.fps_cap, LCUI_DEFAULT_FPS_CAP); + ctest_equal_int("should default parallel rendering threads to 4", + settings.parallel_threads, + LCUI_DEFAULT_PARALLEL_THREADS); + ctest_equal_bool("should disable paint flashing by default", + settings.paint_flashing, false); - lcui_reset_settings(); + settings.fps_cap = 240; + settings.parallel_threads = 8; + settings.paint_flashing = true; + ctest_equal_bool("should set rendering settings", + lcui_settings_set_rendering(&settings), true); + settings.fps_cap = 0; + settings.parallel_threads = 0; + settings.paint_flashing = false; + ctest_equal_bool("should get updated rendering settings", + lcui_settings_get_rendering(&settings), true); + ctest_equal_int("should apply frame rate cap", settings.fps_cap, 240); + ctest_equal_int("should apply parallel rendering threads", + settings.parallel_threads, 8); + ctest_equal_bool("should apply paint flashing", settings.paint_flashing, + true); - lcui_get_settings(&settings); - ctest_equal_int("should reset frame rate cap to default", - settings.fps_cap, LCUI_MAX_FRAMES_PER_SEC); - lcui_quit(); - lcui_main(); + settings.fps_cap = 20; + ctest_equal_bool("should reject out-of-range frame rate cap", + lcui_settings_set_rendering(&settings), false); + ctest_equal_bool("should keep current rendering settings", + lcui_settings_get_rendering(&settings), true); + ctest_equal_int("should keep previous frame rate cap", settings.fps_cap, + 240); + lcui_destroy(); } -void test_settings_fps_cap(void) +static void test_settings_load_merge_validate_flush(void) { - lcui_settings_t settings; - - lcui_init(); - lcui_get_settings(&settings); - - settings.fps_cap = 30; - lcui_apply_settings(&settings); - ptk_set_timeout(2000, check_settings_fps_cap, &settings.fps_cap); - lcui_main(); + const char *app_id = "lcui-settings-load"; + char base_dir[256]; + lcui_rendering_settings_t settings; - lcui_init(); - settings.fps_cap = 5; - lcui_apply_settings(&settings); - ptk_set_timeout(2000, check_settings_fps_cap, &settings.fps_cap); - lcui_main(); + ctest_equal_bool("prepare settings test env", + test_prepare_env(base_dir, sizeof(base_dir), app_id), + true); + ctest_equal_bool("write malformed settings file", + test_write_config(base_dir, app_id, + "[meta]\nversion=abc\n\n" + "[rendering]\n" + "fps_cap=999\n" + "parallel_threads=8\n" + "paint_flashing=oops\n"), + true); lcui_init(); - settings.fps_cap = 90; - lcui_apply_settings(&settings); - ptk_set_timeout(2000, check_settings_fps_cap, &settings.fps_cap); - lcui_main(); + ctest_equal_bool("should load settings", lcui_settings_load(), true); + ctest_equal_bool("should get merged rendering settings", + lcui_settings_get_rendering(&settings), true); + ctest_equal_int("should fallback fps_cap to default on invalid value", + settings.fps_cap, LCUI_DEFAULT_FPS_CAP); + ctest_equal_int("should keep valid parallel_threads", + settings.parallel_threads, 8); + ctest_equal_bool( + "should fallback paint_flashing to default on invalid value", + settings.paint_flashing, false); + ctest_equal_bool("should flush normalized settings", + lcui_settings_flush(), true); + ctest_equal_bool("should normalize version during flush", + test_read_file_contains(base_dir, app_id, "version=1"), + true); + ctest_equal_bool( + "should normalize fps_cap during flush", + test_read_file_contains(base_dir, app_id, "fps_cap=120"), true); + ctest_equal_bool( + "should keep valid parallel_threads during flush", + test_read_file_contains(base_dir, app_id, "parallel_threads=8"), + true); + ctest_equal_bool( + "should normalize paint_flashing during flush", + test_read_file_contains(base_dir, app_id, "paint_flashing=0"), + true); - lcui_init(); - settings.fps_cap = 25; - lcui_apply_settings(&settings); - ptk_set_timeout(2000, check_settings_fps_cap, &settings.fps_cap); - lcui_main(); + lcui_settings_unload(); + ctest_equal_bool("write valid boolean rendering config", + test_write_config(base_dir, app_id, + "[meta]\nversion=1\n\n" + "[rendering]\n" + "fps_cap=60\n" + "parallel_threads=5\n" + "paint_flashing=true\n"), + true); + ctest_equal_bool("should reload valid rendering settings", + lcui_settings_load(), true); + ctest_equal_bool("should get rendering settings after reload", + lcui_settings_get_rendering(&settings), true); + ctest_equal_int("should parse fps_cap from user config", + settings.fps_cap, 60); + ctest_equal_int("should parse parallel_threads from user config", + settings.parallel_threads, 5); + ctest_equal_bool("should parse true bool values from user config", + settings.paint_flashing, true); + lcui_destroy(); } void test_settings(void) { - ctest_describe("default settings", test_default_settings); - ctest_describe("apply settings", test_apply_settings); - ctest_describe("settings.fps_cap", test_settings_fps_cap); + ctest_describe("rendering settings accessors", + test_settings_rendering_accessors); + ctest_describe("settings load/merge/validate/flush", + test_settings_load_merge_validate_flush); } From 32f35c0bbcb77f86c0db180ad785975da277bc62 Mon Sep 17 00:00:00 2001 From: Liu Date: Mon, 8 Jun 2026 21:16:35 +0800 Subject: [PATCH 31/66] chore: update header files --- lib/i18n/include/i18n.h | 2 +- lib/router/include/router/version.h | 2 +- lib/thread/include/thread.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/i18n/include/i18n.h b/lib/i18n/include/i18n.h index 823942d96..1cc18e6f2 100644 --- a/lib/i18n/include/i18n.h +++ b/lib/i18n/include/i18n.h @@ -1,4 +1,4 @@ -/* +/* * lib/i18n/include/i18n.h * * Copyright (c) 2023-2025, Liu Chao All rights reserved. diff --git a/lib/router/include/router/version.h b/lib/router/include/router/version.h index bb1db901c..495f2a706 100644 --- a/lib/router/include/router/version.h +++ b/lib/router/include/router/version.h @@ -1,4 +1,4 @@ -/* +/* * lib/router/include/router/version.h * * Copyright (c) 2023-2025, Liu Chao All rights reserved. diff --git a/lib/thread/include/thread.h b/lib/thread/include/thread.h index 6bc2856e1..8daf8b25f 100644 --- a/lib/thread/include/thread.h +++ b/lib/thread/include/thread.h @@ -1,4 +1,4 @@ -/* +/* * lib/thread/include/thread.h: -- basic thread management * * Copyright (c) 2018-2025, Liu chao All rights reserved. From 4c05e3d5a3e064eac6eefd824d316e8a994f99c1 Mon Sep 17 00:00:00 2001 From: Liu Date: Mon, 8 Jun 2026 21:17:05 +0800 Subject: [PATCH 32/66] fix: Consola -> Consolas --- src/lcui_fonts.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lcui_fonts.c b/src/lcui_fonts.c index e41c5c7a6..2cd889b1d 100644 --- a/src/lcui_fonts.c +++ b/src/lcui_fonts.c @@ -16,7 +16,7 @@ bool lcui_fonts_set_default(const char *family_name) { int id = pd_font_get_id(family_name, PD_FONT_STYLE_NORMAL, - PD_FONT_WEIGHT_NORMAL); + PD_FONT_WEIGHT_NORMAL); if (id < 0) { return false; } @@ -45,7 +45,7 @@ static void lcui_windows_fonts_init(void) lcui_fonts_set_default("Microsoft YaHei"); pd_font_family_set_alias("serif", "Simsun"); pd_font_family_set_alias("sans-serif", "Microsoft YaHei"); - pd_font_family_set_alias("monospace", "Consola"); + pd_font_family_set_alias("monospace", "Consolas"); } #else From 2460d919d1d1bc92929a6690c3f777ef21eb4847 Mon Sep 17 00:00:00 2001 From: Liu Date: Wed, 10 Jun 2026 20:59:18 +0800 Subject: [PATCH 33/66] fix: UI display mode should be reset after destruction --- src/lcui_ui.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lcui_ui.c b/src/lcui_ui.c index 9b6116b50..4f9de54d5 100644 --- a/src/lcui_ui.c +++ b/src/lcui_ui.c @@ -213,6 +213,7 @@ void lcui_ui_destroy(void) ui_mutation_observer_destroy(lcui_ui.observer); lcui_ui.observer = NULL; } + lcui_ui.mode = LCUI_DISPLAY_DEFAULT; lcui_ui.image_loader.active = false; lcui_ui.quit_after_all_windows_closed = true; lcui_ui_image_loader_refresh(); From f9c171b18d1937379a6bb0a3ec1d3fde2e8af927 Mon Sep 17 00:00:00 2001 From: Liu Date: Wed, 10 Jun 2026 21:47:20 +0800 Subject: [PATCH 34/66] fix(ptk): handler self-removal during dispatch should not cause crash --- lib/ptk/src/events.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/ptk/src/events.c b/lib/ptk/src/events.c index 02aa69bad..df439cd86 100644 --- a/lib/ptk/src/events.c +++ b/lib/ptk/src/events.c @@ -158,23 +158,24 @@ int ptk_clear_timer(int timer_id) int ptk_set_timeout(long ms, ptk_timer_cb cb, void *cb_arg) { - return timer_list_add_timeout(ptk_events.timers, ms, cb, - cb_arg); + return timer_list_add_timeout(ptk_events.timers, ms, cb, cb_arg); } int ptk_set_interval(long ms, ptk_timer_cb cb, void *cb_arg) { - return timer_list_add_interval(ptk_events.timers, ms, cb, - cb_arg); + return timer_list_add_interval(ptk_events.timers, ms, cb, cb_arg); } int ptk_process_event(ptk_event_t *e) { int count = 0; list_node_t *node; + list_node_t *next; ptk_event_listener_t *listener; - for (list_each(node, &ptk_events.listeners)) { + for (node = list_get_first_node(&ptk_events.listeners); node; + node = next) { + next = node->next; listener = node->data; if (listener->type == e->type) { listener->handler(e, listener->data); From 4087f8c0b9d7c92ee92c42260aeaf45cde210760 Mon Sep 17 00:00:00 2001 From: Liu Date: Wed, 10 Jun 2026 23:03:57 +0800 Subject: [PATCH 35/66] fix(ptk): ui_server should not bypass platform window destruction flow --- lib/ptk/src/linux/fbapp.c | 6 +- lib/ptk/src/linux/x11app.c | 995 ++++++++++++++++----------------- lib/ptk/src/windows/win32app.c | 4 +- lib/ui-server/src/server.c | 1 - 4 files changed, 503 insertions(+), 503 deletions(-) diff --git a/lib/ptk/src/linux/fbapp.c b/lib/ptk/src/linux/fbapp.c index 39ed973cb..a233f1b8e 100644 --- a/lib/ptk/src/linux/fbapp.c +++ b/lib/ptk/src/linux/fbapp.c @@ -519,7 +519,6 @@ static int ptk_fb_off_event(int type, ptk_native_event_handler_t handler) static int ptk_fb_process_events(ptk_process_events_option_t option) { - fbapp.exit_code = 0; if (option == PTK_PROCESS_EVENTS_ONE_IF_PRESENT || option == PTK_PROCESS_EVENTS_ALL_IF_PRESENT) { @@ -531,7 +530,8 @@ static int ptk_fb_process_events(ptk_process_events_option_t option) ptk_tick(); ptk_process_events(); sleep_ms(1); - } while (option == PTK_PROCESS_EVENTS_UNTIL_QUIT && !fbapp.should_quit_loop); + } while (option == PTK_PROCESS_EVENTS_UNTIL_QUIT && + !fbapp.should_quit_loop); fbapp.should_quit_loop = false; return fbapp.exit_code; } @@ -560,7 +560,7 @@ void ptk_fbapp_driver_init(ptk_app_driver_t *driver) void ptk_fbwindow_driver_init(ptk_window_driver_t *driver) { driver->close = ptk_fb_window_close; - driver->close = ptk_fb_window_destroy; + driver->destroy = ptk_fb_window_destroy; driver->show = ptk_fb_window_show; driver->hide = ptk_fb_window_hide; driver->activate = ptk_fb_window_activate; diff --git a/lib/ptk/src/linux/x11app.c b/lib/ptk/src/linux/x11app.c index 5a8c5a534..38fa19525 100644 --- a/lib/ptk/src/linux/x11app.c +++ b/lib/ptk/src/linux/x11app.c @@ -25,37 +25,37 @@ #include struct ptk_window { - Window handle; - int x, y; - int width, height; - int min_width, min_height; - int max_width, max_height; - - GC gc; - XImage *ximage; - pd_canvas_t fb; - - /** list_t */ - list_t rects; - list_node_t node; + Window handle; + int x, y; + int width, height; + int min_width, min_height; + int max_width, max_height; + + GC gc; + XImage *ximage; + pd_canvas_t fb; + + /** list_t */ + list_t rects; + list_node_t node; }; static struct ptk_x11app { - int screen; - Display *display; - Window win_root; - Window win_events; - Atom wm_delete; - Atom wm_exit; - Colormap cmap; + int screen; + Display *display; + Window win_root; + Window win_events; + Atom wm_delete; + Atom wm_exit; + Colormap cmap; - int exit_code; + int exit_code; - /** list_t */ - list_t native_listeners; + /** list_t */ + list_t native_listeners; - /** list_t */ - list_t windows; + /** list_t */ + list_t windows; } x11_app; static void ptk_x11window__show(ptk_window_t *wnd); @@ -63,637 +63,636 @@ static void ptk_x11window__set_size(ptk_window_t *wnd, int width, int height); static int convert_keycode(KeySym keysym) { - switch (keysym) { - case XK_Tab: - return KEY_TAB; - case XK_Escape: - return KEY_ESCAPE; - case XK_Return: - return KEY_ENTER; - case XK_Delete: - return KEY_DELETE; - case XK_BackSpace: - return KEY_BACKSPACE; - case XK_Home: - return KEY_HOME; - case XK_Left: - return KEY_LEFT; - case XK_Up: - return KEY_UP; - case XK_Right: - return KEY_RIGHT; - case XK_Down: - return KEY_DOWN; - case XK_Page_Up: - return KEY_PAGEUP; - case XK_Page_Down: - return KEY_PAGEDOWN; - case XK_End: - return KEY_END; - case XK_Control_R: - case XK_Control_L: - return KEY_CONTROL; - case XK_Shift_R: - case XK_Shift_L: - return KEY_SHIFT; - case XK_Alt_L: - case XK_Alt_R: - return KEY_ALT; - case XK_Caps_Lock: - return KEY_CAPITAL; - case XK_comma: - return KEY_COMMA; - case XK_period: - return KEY_PERIOD; - case XK_minus: - return KEY_MINUS; - case XK_slash: - return KEY_SLASH; - case XK_semicolon: - return KEY_SEMICOLON; - case XK_equal: - return KEY_EQUAL; - case XK_bracketleft: - return KEY_BRACKETLEFT; - case XK_bracketright: - return KEY_BRACKETRIGHT; - case XK_backslash: - return KEY_BACKSLASH; - case XK_apostrophe: - return KEY_APOSTROPHE; - case XK_grave: - return KEY_GRAVE; - default: - break; - } - return keysym; + switch (keysym) { + case XK_Tab: + return KEY_TAB; + case XK_Escape: + return KEY_ESCAPE; + case XK_Return: + return KEY_ENTER; + case XK_Delete: + return KEY_DELETE; + case XK_BackSpace: + return KEY_BACKSPACE; + case XK_Home: + return KEY_HOME; + case XK_Left: + return KEY_LEFT; + case XK_Up: + return KEY_UP; + case XK_Right: + return KEY_RIGHT; + case XK_Down: + return KEY_DOWN; + case XK_Page_Up: + return KEY_PAGEUP; + case XK_Page_Down: + return KEY_PAGEDOWN; + case XK_End: + return KEY_END; + case XK_Control_R: + case XK_Control_L: + return KEY_CONTROL; + case XK_Shift_R: + case XK_Shift_L: + return KEY_SHIFT; + case XK_Alt_L: + case XK_Alt_R: + return KEY_ALT; + case XK_Caps_Lock: + return KEY_CAPITAL; + case XK_comma: + return KEY_COMMA; + case XK_period: + return KEY_PERIOD; + case XK_minus: + return KEY_MINUS; + case XK_slash: + return KEY_SLASH; + case XK_semicolon: + return KEY_SEMICOLON; + case XK_equal: + return KEY_EQUAL; + case XK_bracketleft: + return KEY_BRACKETLEFT; + case XK_bracketright: + return KEY_BRACKETRIGHT; + case XK_backslash: + return KEY_BACKSLASH; + case XK_apostrophe: + return KEY_APOSTROPHE; + case XK_grave: + return KEY_GRAVE; + default: + break; + } + return keysym; } static ptk_window_t *ptk_x11window__create(const wchar_t *title, int x, int y, - int width, int height, - ptk_window_t *parent) -{ - ptk_window_t *wnd; - unsigned long bdcolor = BlackPixel(x11_app.display, x11_app.screen); - unsigned long bgcolor = WhitePixel(x11_app.display, x11_app.screen); - - wnd = calloc(sizeof(ptk_window_t), 1); - wnd->gc = NULL; - wnd->ximage = NULL; - wnd->node.data = wnd; - wnd->width = width; - wnd->height = height; - wnd->x = x; - wnd->y = y; - pd_canvas_init(&wnd->fb); - list_create(&wnd->rects); - wnd->fb.color_type = PD_COLOR_TYPE_ARGB; - wnd->handle = XCreateSimpleWindow(x11_app.display, x11_app.win_root, x, - y, y_max(width, MIN_WINDOW_WIDTH), - y_max(height, MIN_WINDOW_HEIGHT), 1, - bdcolor, bgcolor); - list_append_node(&x11_app.windows, &wnd->node); - return wnd; + int width, int height, + ptk_window_t *parent) +{ + ptk_window_t *wnd; + unsigned long bdcolor = BlackPixel(x11_app.display, x11_app.screen); + unsigned long bgcolor = WhitePixel(x11_app.display, x11_app.screen); + + wnd = calloc(sizeof(ptk_window_t), 1); + wnd->gc = NULL; + wnd->ximage = NULL; + wnd->node.data = wnd; + wnd->width = width; + wnd->height = height; + wnd->x = x; + wnd->y = y; + pd_canvas_init(&wnd->fb); + list_create(&wnd->rects); + wnd->fb.color_type = PD_COLOR_TYPE_ARGB; + wnd->handle = XCreateSimpleWindow(x11_app.display, x11_app.win_root, x, + y, y_max(width, MIN_WINDOW_WIDTH), + y_max(height, MIN_WINDOW_HEIGHT), 1, + bdcolor, bgcolor); + list_append_node(&x11_app.windows, &wnd->node); + return wnd; } static void ptk_x11window__on_destroy(ptk_window_t *wnd) { - list_unlink(&x11_app.windows, &wnd->node); - list_destroy(&wnd->rects, free); - if (wnd->ximage) { - XDestroyImage(wnd->ximage); - wnd->ximage = NULL; - } - if (wnd->gc) { - XFreeGC(x11_app.display, wnd->gc); - wnd->gc = NULL; - } - free(wnd); + list_unlink(&x11_app.windows, &wnd->node); + list_destroy(&wnd->rects, free); + if (wnd->ximage) { + XDestroyImage(wnd->ximage); + wnd->ximage = NULL; + } + if (wnd->gc) { + XFreeGC(x11_app.display, wnd->gc); + wnd->gc = NULL; + } + free(wnd); } static ptk_window_t *ptk_x11app_get_window_by_handle(void *handle) { - list_node_t *node; + list_node_t *node; - for (list_each(node, &x11_app.windows)) { - if (((ptk_window_t *)node->data)->handle == *(Window *)handle) { - return node->data; - } - } - return NULL; + for (list_each(node, &x11_app.windows)) { + if (((ptk_window_t *)node->data)->handle == *(Window *)handle) { + return node->data; + } + } + return NULL; } static void ptk_x11window__on_size(ptk_window_t *wnd, int width, int height) { - int depth; - XGCValues gcv; - Visual *visual; - - width = y_max(MIN_WINDOW_WIDTH, width); - height = y_max(MIN_WINDOW_HEIGHT, height); - if (width == wnd->width && height == wnd->height && wnd->ximage && - wnd->gc) { - return; - } - if (wnd->ximage) { - XDestroyImage(wnd->ximage); - wnd->ximage = NULL; - } - if (wnd->gc) { - XFreeGC(x11_app.display, wnd->gc); - wnd->gc = NULL; - } - pd_canvas_init(&wnd->fb); - wnd->width = width; - wnd->height = height; - depth = DefaultDepth(x11_app.display, x11_app.screen); - switch (depth) { - case 32: - case 24: - wnd->fb.color_type = PD_COLOR_TYPE_ARGB; - break; - default: - logger_error("[x11_app] unsupport depth: %d.\n", depth); - break; - } - pd_canvas_create(&wnd->fb, width, height); - visual = DefaultVisual(x11_app.display, x11_app.screen); - wnd->ximage = - XCreateImage(x11_app.display, visual, depth, ZPixmap, 0, - (char *)(wnd->fb.bytes), width, height, 32, 0); - if (!wnd->ximage) { - pd_canvas_destroy(&wnd->fb); - logger_error("[x11_app] create XImage faild.\n"); - return; - } - gcv.graphics_exposures = False; - wnd->gc = - XCreateGC(x11_app.display, wnd->handle, GCGraphicsExposures, &gcv); - if (!wnd->gc) { - logger_error("[x11_app] create graphics context faild.\n"); - } + int depth; + XGCValues gcv; + Visual *visual; + + width = y_max(MIN_WINDOW_WIDTH, width); + height = y_max(MIN_WINDOW_HEIGHT, height); + if (width == wnd->width && height == wnd->height && wnd->ximage && + wnd->gc) { + return; + } + if (wnd->ximage) { + XDestroyImage(wnd->ximage); + wnd->ximage = NULL; + } + if (wnd->gc) { + XFreeGC(x11_app.display, wnd->gc); + wnd->gc = NULL; + } + pd_canvas_init(&wnd->fb); + wnd->width = width; + wnd->height = height; + depth = DefaultDepth(x11_app.display, x11_app.screen); + switch (depth) { + case 32: + case 24: + wnd->fb.color_type = PD_COLOR_TYPE_ARGB; + break; + default: + logger_error("[x11_app] unsupport depth: %d.\n", depth); + break; + } + pd_canvas_create(&wnd->fb, width, height); + visual = DefaultVisual(x11_app.display, x11_app.screen); + wnd->ximage = + XCreateImage(x11_app.display, visual, depth, ZPixmap, 0, + (char *)(wnd->fb.bytes), width, height, 32, 0); + if (!wnd->ximage) { + pd_canvas_destroy(&wnd->fb); + logger_error("[x11_app] create XImage faild.\n"); + return; + } + gcv.graphics_exposures = False; + wnd->gc = + XCreateGC(x11_app.display, wnd->handle, GCGraphicsExposures, &gcv); + if (!wnd->gc) { + logger_error("[x11_app] create graphics context faild.\n"); + } } static int x11_ptk_process_native_event(void) { - KeySym keysym; - Display *dsp = x11_app.display; - XEvent xe = { 0 }; - - list_node_t *node; - ptk_native_event_listener_t *listener; - ptk_event_t e = { 0 }; - - XNextEvent(x11_app.display, &xe); - e.window = ptk_x11app_get_window_by_handle(&xe.xany.window); - switch (xe.type) { - case ConfigureNotify: - e.type = PTK_EVENT_SIZE; - e.size.width = xe.xconfigure.width; - e.size.height = xe.xconfigure.height; - ptk_x11window__on_size(e.window, xe.xconfigure.width, - xe.xconfigure.height); - ptk_process_event(&e); - // TODO: add MOVE event? - break; - case Expose: - e.type = PTK_EVENT_PAINT; - e.paint.rect.x = xe.xexpose.x; - e.paint.rect.y = xe.xexpose.y; - e.paint.rect.width = xe.xexpose.width; - e.paint.rect.height = xe.xexpose.height; - ptk_process_event(&e); - break; - case KeyPress: - case KeyRelease: { - int min_keycode, max_keycode; - - e.type = - xe.type == KeyPress ? PTK_EVENT_KEYDOWN : PTK_EVENT_KEYUP; - XAutoRepeatOn(dsp); - keysym = XkbKeycodeToKeysym(dsp, xe.xkey.keycode, 0, 1); - e.key.code = convert_keycode(keysym); - e.key.shift_key = xe.xkey.state & ShiftMask ? true : false; - e.key.ctrl_key = xe.xkey.state & ControlMask ? true : false; - // @WhoAteDaCake - // TODO: this triggers and line 155 causes event to trigger - // twice? I tried to remove the one in if statement and put it - // to the end of the function but it doesn't seem to work - // properly then? Needs investigation - ptk_process_event(&e); - XDisplayKeycodes(dsp, &min_keycode, &max_keycode); - if (keysym >= min_keycode && keysym <= max_keycode && - e.type == PTK_EVENT_KEYDOWN && !e.key.ctrl_key) { - e.type = PTK_EVENT_KEYPRESS; - e.key.code = XkbKeycodeToKeysym( - dsp, xe.xkey.keycode, 0, - xe.xkey.state & ShiftMask ? 1 : 0); - ptk_process_event(&e); - } - break; - } - case MotionNotify: - e.type = PTK_EVENT_MOUSEMOVE; - e.mouse.x = xe.xmotion.x; - e.mouse.y = xe.xmotion.y; - ptk_process_event(&e); - break; - case ButtonPress: - if (xe.xbutton.button == Button4) { - e.type = PTK_EVENT_WHEEL; - e.wheel.delta_y = MOUSE_WHEEL_DELTA; - } else if (xe.xbutton.button == Button5) { - e.type = PTK_EVENT_WHEEL; - e.wheel.delta_y = -MOUSE_WHEEL_DELTA; - } else { - e.type = PTK_EVENT_MOUSEDOWN; - e.mouse.x = xe.xbutton.x; - e.mouse.y = xe.xbutton.y; - e.mouse.button = xe.xbutton.button; - } - ptk_process_event(&e); - break; - case ButtonRelease: - e.type = PTK_EVENT_MOUSEUP; - e.mouse.x = xe.xbutton.x; - e.mouse.y = xe.xbutton.y; - e.mouse.button = xe.xbutton.button; - ptk_process_event(&e); - break; - /** - * FIXME: 调用 XDestroyWindow() 后未接收到 DestroyNotify 事件 - */ - // case DestroyNotify: - case ClientMessage: - if (xe.xclient.data.l[0] == x11_app.wm_delete) { - logger_debug("WM_DELETE_WINNDOW\n"); - e.type = PTK_EVENT_CLOSE; - ptk_process_event(&e); - ptk_x11window__on_destroy(e.window); - } else if (xe.xclient.data.l[0] == x11_app.wm_exit) { - logger_debug("WM_EXIT\n"); - e.type = PTK_EVENT_QUIT; - ptk_process_event(&e); - return 0; - } - break; - default: - break; - } - ptk_event_destroy(&e); - for (list_each(node, &x11_app.native_listeners)) { - listener = node->data; - if (listener->type == xe.type) { - listener->handler(&xe, listener->data); - } - } - return 1; + KeySym keysym; + Display *dsp = x11_app.display; + XEvent xe = { 0 }; + + list_node_t *node; + ptk_native_event_listener_t *listener; + ptk_event_t e = { 0 }; + + XNextEvent(x11_app.display, &xe); + e.window = ptk_x11app_get_window_by_handle(&xe.xany.window); + switch (xe.type) { + case ConfigureNotify: + e.type = PTK_EVENT_SIZE; + e.size.width = xe.xconfigure.width; + e.size.height = xe.xconfigure.height; + ptk_x11window__on_size(e.window, xe.xconfigure.width, + xe.xconfigure.height); + ptk_process_event(&e); + // TODO: add MOVE event? + break; + case Expose: + e.type = PTK_EVENT_PAINT; + e.paint.rect.x = xe.xexpose.x; + e.paint.rect.y = xe.xexpose.y; + e.paint.rect.width = xe.xexpose.width; + e.paint.rect.height = xe.xexpose.height; + ptk_process_event(&e); + break; + case KeyPress: + case KeyRelease: { + int min_keycode, max_keycode; + + e.type = + xe.type == KeyPress ? PTK_EVENT_KEYDOWN : PTK_EVENT_KEYUP; + XAutoRepeatOn(dsp); + keysym = XkbKeycodeToKeysym(dsp, xe.xkey.keycode, 0, 1); + e.key.code = convert_keycode(keysym); + e.key.shift_key = xe.xkey.state & ShiftMask ? true : false; + e.key.ctrl_key = xe.xkey.state & ControlMask ? true : false; + // @WhoAteDaCake + // TODO: this triggers and line 155 causes event to trigger + // twice? I tried to remove the one in if statement and put it + // to the end of the function but it doesn't seem to work + // properly then? Needs investigation + ptk_process_event(&e); + XDisplayKeycodes(dsp, &min_keycode, &max_keycode); + if (keysym >= min_keycode && keysym <= max_keycode && + e.type == PTK_EVENT_KEYDOWN && !e.key.ctrl_key) { + e.type = PTK_EVENT_KEYPRESS; + e.key.code = XkbKeycodeToKeysym( + dsp, xe.xkey.keycode, 0, + xe.xkey.state & ShiftMask ? 1 : 0); + ptk_process_event(&e); + } + break; + } + case MotionNotify: + e.type = PTK_EVENT_MOUSEMOVE; + e.mouse.x = xe.xmotion.x; + e.mouse.y = xe.xmotion.y; + ptk_process_event(&e); + break; + case ButtonPress: + if (xe.xbutton.button == Button4) { + e.type = PTK_EVENT_WHEEL; + e.wheel.delta_y = MOUSE_WHEEL_DELTA; + } else if (xe.xbutton.button == Button5) { + e.type = PTK_EVENT_WHEEL; + e.wheel.delta_y = -MOUSE_WHEEL_DELTA; + } else { + e.type = PTK_EVENT_MOUSEDOWN; + e.mouse.x = xe.xbutton.x; + e.mouse.y = xe.xbutton.y; + e.mouse.button = xe.xbutton.button; + } + ptk_process_event(&e); + break; + case ButtonRelease: + e.type = PTK_EVENT_MOUSEUP; + e.mouse.x = xe.xbutton.x; + e.mouse.y = xe.xbutton.y; + e.mouse.button = xe.xbutton.button; + ptk_process_event(&e); + break; + /** + * FIXME: 调用 XDestroyWindow() 后未接收到 DestroyNotify 事件 + */ + // case DestroyNotify: + case ClientMessage: + if (xe.xclient.data.l[0] == x11_app.wm_delete) { + logger_debug("WM_DELETE_WINNDOW\n"); + e.type = PTK_EVENT_CLOSE; + ptk_process_event(&e); + ptk_x11window__on_destroy(e.window); + } else if (xe.xclient.data.l[0] == x11_app.wm_exit) { + logger_debug("WM_EXIT\n"); + e.type = PTK_EVENT_QUIT; + ptk_process_event(&e); + return 0; + } + break; + default: + break; + } + ptk_event_destroy(&e); + for (list_each(node, &x11_app.native_listeners)) { + listener = node->data; + if (listener->type == xe.type) { + listener->handler(&xe, listener->data); + } + } + return 1; } static int ptk_x11app_pending(void) { - XFlush(x11_app.display); - return XEventsQueued(x11_app.display, QueuedAlready); + XFlush(x11_app.display); + return XEventsQueued(x11_app.display, QueuedAlready); } static int x11_ptk_process_native_events(ptk_process_events_option_t option) { - int ret = 0; - - x11_app.exit_code = 0; - if (option == PTK_PROCESS_EVENTS_ONE_IF_PRESENT || - option == PTK_PROCESS_EVENTS_ALL_IF_PRESENT) { - do { - ptk_tick(); - if (!ptk_x11app_pending()) { - break; - } - x11_ptk_process_native_event(); - ptk_process_events(); - } while (option == PTK_PROCESS_EVENTS_ALL_IF_PRESENT); - return x11_app.exit_code; - } - do { - for (ptk_tick(); !ptk_x11app_pending(); ptk_tick()) { - ptk_process_events(); - sleep_ms(1); - } - ret = x11_ptk_process_native_event(); - ptk_process_events(); - } while (option == PTK_PROCESS_EVENTS_UNTIL_QUIT && ret != 0); - return x11_app.exit_code; + int ret = 0; + + x11_app.exit_code = 0; + if (option == PTK_PROCESS_EVENTS_ONE_IF_PRESENT || + option == PTK_PROCESS_EVENTS_ALL_IF_PRESENT) { + do { + ptk_tick(); + if (!ptk_x11app_pending()) { + break; + } + x11_ptk_process_native_event(); + ptk_process_events(); + } while (option == PTK_PROCESS_EVENTS_ALL_IF_PRESENT); + return x11_app.exit_code; + } + do { + for (ptk_tick(); !ptk_x11app_pending(); ptk_tick()) { + ptk_process_events(); + sleep_ms(1); + } + ret = x11_ptk_process_native_event(); + ptk_process_events(); + } while (option == PTK_PROCESS_EVENTS_UNTIL_QUIT && ret != 0); + return x11_app.exit_code; } static int x11_ptk_add_native_event_listener(int type, - ptk_native_event_handler_t handler, - void *data) + ptk_native_event_handler_t handler, + void *data) { - ptk_native_event_listener_t *listener; + ptk_native_event_listener_t *listener; - listener = malloc(sizeof(ptk_native_event_listener_t)); - if (!listener) { - return -1; - } - listener->handler = handler; - listener->data = data; - listener->type = type; - list_append(&x11_app.native_listeners, listener); - return 0; + listener = malloc(sizeof(ptk_native_event_listener_t)); + if (!listener) { + return -1; + } + listener->handler = handler; + listener->data = data; + listener->type = type; + list_append(&x11_app.native_listeners, listener); + return 0; } static int x11_ptk_remove_native_event_listener( int type, ptk_native_event_handler_t handler) { - list_node_t *node, *prev; - ptk_native_event_listener_t *listener; + list_node_t *node, *prev; + ptk_native_event_listener_t *listener; - for (list_each(node, &x11_app.native_listeners)) { - prev = node->prev; - listener = node->data; - if (listener->handler == handler && listener->type == type) { - list_delete_node(&x11_app.native_listeners, node); - free(listener); - node = prev; - return 0; - } - } - return -1; + for (list_each(node, &x11_app.native_listeners)) { + prev = node->prev; + listener = node->data; + if (listener->handler == handler && listener->type == type) { + list_delete_node(&x11_app.native_listeners, node); + free(listener); + node = prev; + return 0; + } + } + return -1; } static int x11_ptk_screen_get_width(void) { - Screen *s = DefaultScreenOfDisplay(x11_app.display); - return XWidthOfScreen(s); + Screen *s = DefaultScreenOfDisplay(x11_app.display); + return XWidthOfScreen(s); } static int x11_ptk_screen_get_height(void) { - Screen *s = DefaultScreenOfDisplay(x11_app.display); - return XHeightOfScreen(s); + Screen *s = DefaultScreenOfDisplay(x11_app.display); + return XHeightOfScreen(s); } static void ptk_x11window__activate(ptk_window_t *wnd) { - XSetWMProtocols(x11_app.display, wnd->handle, &x11_app.wm_delete, 1); - XSelectInput(x11_app.display, wnd->handle, - ExposureMask | KeyPressMask | ButtonPress | - StructureNotifyMask | ButtonReleaseMask | - KeyReleaseMask | EnterWindowMask | LeaveWindowMask | - PointerMotionMask | Button1MotionMask | - VisibilityChangeMask); - XFlush(x11_app.display); - ptk_x11window__show(wnd); + XSetWMProtocols(x11_app.display, wnd->handle, &x11_app.wm_delete, 1); + XSelectInput(x11_app.display, wnd->handle, + ExposureMask | KeyPressMask | ButtonPress | + StructureNotifyMask | ButtonReleaseMask | + KeyReleaseMask | EnterWindowMask | LeaveWindowMask | + PointerMotionMask | Button1MotionMask | + VisibilityChangeMask); + XFlush(x11_app.display); + ptk_x11window__show(wnd); } static void ptk_x11window__close(ptk_window_t *wnd) { - XEvent xe = { 0 }; + XEvent xe = { 0 }; - xe.xclient.type = ClientMessage; - xe.xclient.data.l[0] = x11_app.wm_delete; - xe.xclient.serial = 0; - xe.xclient.send_event = 1; - xe.xclient.format = 32; - xe.xclient.window = wnd->handle; - XSendEvent(x11_app.display, x11_app.win_events, 0, NoEventMask, - &xe); + xe.xclient.type = ClientMessage; + xe.xclient.data.l[0] = x11_app.wm_delete; + xe.xclient.serial = 0; + xe.xclient.send_event = 1; + xe.xclient.format = 32; + xe.xclient.window = wnd->handle; + XSendEvent(x11_app.display, x11_app.win_events, 0, NoEventMask, &xe); } static void ptk_x11window__destroy(ptk_window_t *wnd) { - XDestroyWindow(x11_app.display, wnd->handle); + XDestroyWindow(x11_app.display, wnd->handle); } static void ptk_x11window__set_title(ptk_window_t *wnd, const wchar_t *title) { - size_t len; - char *utf8_title; - XTextProperty name; + size_t len; + char *utf8_title; + XTextProperty name; - len = encode_utf8(NULL, title, 0) + 1; - utf8_title = malloc(sizeof(char) * len); - if (!title) { - return; - } - len = encode_utf8(utf8_title, title, len); - name.value = (unsigned char *)utf8_title; - name.encoding = XA_STRING; - name.format = 8 * sizeof(char); - name.nitems = len; - XSetWMName(x11_app.display, wnd->handle, &name); - free(utf8_title); + len = encode_utf8(NULL, title, 0) + 1; + utf8_title = malloc(sizeof(char) * len); + if (!title) { + return; + } + len = encode_utf8(utf8_title, title, len); + name.value = (unsigned char *)utf8_title; + name.encoding = XA_STRING; + name.format = 8 * sizeof(char); + name.nitems = len; + XSetWMName(x11_app.display, wnd->handle, &name); + free(utf8_title); } static void ptk_x11window__set_size(ptk_window_t *wnd, int width, int height) { - // Ignore useless events and avoid infinite window size changes - if (wnd->width == width && wnd->height == height) { - return; - } - XResizeWindow(x11_app.display, wnd->handle, width, height); - // When XResizeWindow() is called, the x and y values in the - // ConfigureNotify event sent by XResizeWindow() are old because the - // position set by the previous call to XMoveWindow() has not been - // updated. Therefore, we need to set the latest position again. - XMoveWindow(x11_app.display, wnd->handle, wnd->x, wnd->y); + // Ignore useless events and avoid infinite window size changes + if (wnd->width == width && wnd->height == height) { + return; + } + XResizeWindow(x11_app.display, wnd->handle, width, height); + // When XResizeWindow() is called, the x and y values in the + // ConfigureNotify event sent by XResizeWindow() are old because the + // position set by the previous call to XMoveWindow() has not been + // updated. Therefore, we need to set the latest position again. + XMoveWindow(x11_app.display, wnd->handle, wnd->x, wnd->y); } static void ptk_x11window__set_position(ptk_window_t *wnd, int x, int y) { - if (wnd->x == x && wnd->y == y) { - return; - } - wnd->x = x; - wnd->y = y; - XMoveWindow(x11_app.display, wnd->handle, x, y); + if (wnd->x == x && wnd->y == y) { + return; + } + wnd->x = x; + wnd->y = y; + XMoveWindow(x11_app.display, wnd->handle, x, y); } static void *ptk_x11window__get_handle(ptk_window_t *wnd) { - return &wnd->handle; + return &wnd->handle; } static int ptk_x11window__get_width(ptk_window_t *wnd) { - return wnd->width; + return wnd->width; } static int ptk_x11window__get_height(ptk_window_t *wnd) { - return wnd->height; + return wnd->height; } static void ptk_x11window__set_min_width(ptk_window_t *wnd, int min_width) { - wnd->min_width = min_width; + wnd->min_width = min_width; } static void ptk_x11window__set_min_height(ptk_window_t *wnd, int min_height) { - wnd->min_height = min_height; + wnd->min_height = min_height; } static void ptk_x11window__set_max_width(ptk_window_t *wnd, int max_width) { - wnd->max_width = max_width; + wnd->max_width = max_width; } static void ptk_x11window__set_max_height(ptk_window_t *wnd, int max_height) { - wnd->max_height = max_height; + wnd->max_height = max_height; } static void ptk_x11window__show(ptk_window_t *wnd) { - XMapWindow(x11_app.display, wnd->handle); + XMapWindow(x11_app.display, wnd->handle); } static void ptk_x11window__hide(ptk_window_t *wnd) { - XUnmapWindow(x11_app.display, wnd->handle); + XUnmapWindow(x11_app.display, wnd->handle); } static ptk_window_paint_t *ptk_x11window__begin_paint(ptk_window_t *wnd, - pd_rect_t *rect) + pd_rect_t *rect) { - pd_context_t *paint; + pd_context_t *paint; - paint = malloc(sizeof(pd_context_t)); - paint->rect = *rect; - paint->with_alpha = false; - pd_canvas_init(&paint->canvas); - pd_rect_correct(&paint->rect, wnd->width, wnd->height); - pd_canvas_quote(&paint->canvas, &wnd->fb, &paint->rect); - pd_canvas_fill(&paint->canvas, pd_rgb(255, 255, 255)); - return paint; + paint = malloc(sizeof(pd_context_t)); + paint->rect = *rect; + paint->with_alpha = false; + pd_canvas_init(&paint->canvas); + pd_rect_correct(&paint->rect, wnd->width, wnd->height); + pd_canvas_quote(&paint->canvas, &wnd->fb, &paint->rect); + pd_canvas_fill(&paint->canvas, pd_rgb(255, 255, 255)); + return paint; } static void ptk_x11window__end_paint(ptk_window_t *wnd, - ptk_window_paint_t *paint) + ptk_window_paint_t *paint) { - pd_rect_t *rect; + pd_rect_t *rect; - rect = malloc(sizeof(pd_rect_t)); - *rect = paint->rect; - list_append(&wnd->rects, rect); - pd_canvas_init(&paint->canvas); - free(paint); + rect = malloc(sizeof(pd_rect_t)); + *rect = paint->rect; + list_append(&wnd->rects, rect); + pd_canvas_init(&paint->canvas); + free(paint); } static void ptk_x11window__present(ptk_window_t *wnd) { - list_node_t *node; - list_t rects; - pd_rect_t *rect; + list_node_t *node; + list_t rects; + pd_rect_t *rect; - if (!wnd->gc || !wnd->ximage) { - return; - } - list_create(&rects); - list_concat(&rects, &wnd->rects); - for (list_each(node, &rects)) { - rect = node->data; - XPutImage(x11_app.display, wnd->handle, wnd->gc, wnd->ximage, - rect->x, rect->y, rect->x, rect->y, rect->width, - rect->height); - } - list_destroy(&rects, free); + if (!wnd->gc || !wnd->ximage) { + return; + } + list_create(&rects); + list_concat(&rects, &wnd->rects); + for (list_each(node, &rects)) { + rect = node->data; + XPutImage(x11_app.display, wnd->handle, wnd->gc, wnd->ximage, + rect->x, rect->y, rect->x, rect->y, rect->width, + rect->height); + } + list_destroy(&rects, free); } static void ptk_x11app_present(void) { - list_node_t *node; + list_node_t *node; - for (list_each(node, &x11_app.windows)) { - ptk_x11window__present(node->data); - } + for (list_each(node, &x11_app.windows)) { + ptk_x11window__present(node->data); + } } static int ptk_x11app_init(const wchar_t *name) { - x11_app.display = XOpenDisplay(NULL); - if (!x11_app.display) { - return -1; - } - x11_app.screen = DefaultScreen(x11_app.display); - x11_app.win_root = RootWindow(x11_app.display, x11_app.screen); - x11_app.win_events = XCreateSimpleWindow( - x11_app.display, x11_app.win_root, 0, 0, 10, 10, 0, 0, 0); - x11_app.cmap = DefaultColormap(x11_app.display, x11_app.screen); - x11_app.wm_delete = - XInternAtom(x11_app.display, "WM_DELETE_WINDOW", false); - x11_app.wm_exit = XInternAtom(x11_app.display, "WM_EXIT", false); - XSelectInput(x11_app.display, x11_app.win_events, StructureNotifyMask); - return 0; + x11_app.display = XOpenDisplay(NULL); + if (!x11_app.display) { + return -1; + } + x11_app.screen = DefaultScreen(x11_app.display); + x11_app.win_root = RootWindow(x11_app.display, x11_app.screen); + x11_app.win_events = XCreateSimpleWindow( + x11_app.display, x11_app.win_root, 0, 0, 10, 10, 0, 0, 0); + x11_app.cmap = DefaultColormap(x11_app.display, x11_app.screen); + x11_app.wm_delete = + XInternAtom(x11_app.display, "WM_DELETE_WINDOW", false); + x11_app.wm_exit = XInternAtom(x11_app.display, "WM_EXIT", false); + XSelectInput(x11_app.display, x11_app.win_events, StructureNotifyMask); + return 0; } static int ptk_x11app_destroy(void) { - list_destroy_without_node( - &x11_app.windows, - (list_item_destructor_t)ptk_x11window__on_destroy); - XCloseDisplay(x11_app.display); - return 0; + list_destroy_without_node( + &x11_app.windows, + (list_item_destructor_t)ptk_x11window__on_destroy); + XCloseDisplay(x11_app.display); + return 0; } static void ptk_x11app_exit(int exit_code) { - XEvent xe = { 0 }; + XEvent xe = { 0 }; - xe.xclient.type = ClientMessage; - xe.xclient.data.l[0] = x11_app.wm_exit; - xe.xclient.serial = 0; - xe.xclient.send_event = 1; - xe.xclient.format = 32; - xe.xclient.window = x11_app.win_events; - XSendEvent(x11_app.display, x11_app.win_events, 0, NoEventMask, &xe); + xe.xclient.type = ClientMessage; + xe.xclient.data.l[0] = x11_app.wm_exit; + xe.xclient.serial = 0; + xe.xclient.send_event = 1; + xe.xclient.format = 32; + xe.xclient.window = x11_app.win_events; + XSendEvent(x11_app.display, x11_app.win_events, 0, NoEventMask, &xe); } Display *ptk_x11_get_display(void) { - return x11_app.display; + return x11_app.display; } Window ptk_x11_get_main_window(void) { - return x11_app.win_events; + return x11_app.win_events; } void ptk_x11app_driver_init(ptk_app_driver_t *driver) { - driver->init = ptk_x11app_init; - driver->destroy = ptk_x11app_destroy; - driver->process_events = x11_ptk_process_native_events; - driver->on_event = x11_ptk_add_native_event_listener; - driver->off_event = x11_ptk_remove_native_event_listener; - driver->create_window = ptk_x11window__create; - driver->get_window = ptk_x11app_get_window_by_handle; - driver->get_screen_width = x11_ptk_screen_get_width; - driver->get_screen_height = x11_ptk_screen_get_height; - driver->present = ptk_x11app_present; - driver->exit = ptk_x11app_exit; + driver->init = ptk_x11app_init; + driver->destroy = ptk_x11app_destroy; + driver->process_events = x11_ptk_process_native_events; + driver->on_event = x11_ptk_add_native_event_listener; + driver->off_event = x11_ptk_remove_native_event_listener; + driver->create_window = ptk_x11window__create; + driver->get_window = ptk_x11app_get_window_by_handle; + driver->get_screen_width = x11_ptk_screen_get_width; + driver->get_screen_height = x11_ptk_screen_get_height; + driver->present = ptk_x11app_present; + driver->exit = ptk_x11app_exit; } void ptk_x11window_driver_init(ptk_window_driver_t *driver) { - driver->show = ptk_x11window__show; - driver->hide = ptk_x11window__hide; - driver->close = ptk_x11window__close; - driver->destroy = ptk_x11window__destroy; - driver->activate = ptk_x11window__activate; - driver->set_title = ptk_x11window__set_title; - driver->set_position = ptk_x11window__set_position; - driver->set_size = ptk_x11window__set_size; - driver->get_width = ptk_x11window__get_width; - driver->get_height = ptk_x11window__get_height; - driver->get_handle = ptk_x11window__get_handle; - driver->set_max_width = ptk_x11window__set_max_width; - driver->set_max_height = ptk_x11window__set_max_height; - driver->set_min_width = ptk_x11window__set_min_width; - driver->set_min_height = ptk_x11window__set_min_height; - driver->begin_paint = ptk_x11window__begin_paint; - driver->end_paint = ptk_x11window__end_paint; - driver->present = ptk_x11window__present; + driver->show = ptk_x11window__show; + driver->hide = ptk_x11window__hide; + driver->close = ptk_x11window__close; + driver->destroy = ptk_x11window__destroy; + driver->activate = ptk_x11window__activate; + driver->set_title = ptk_x11window__set_title; + driver->set_position = ptk_x11window__set_position; + driver->set_size = ptk_x11window__set_size; + driver->get_width = ptk_x11window__get_width; + driver->get_height = ptk_x11window__get_height; + driver->get_handle = ptk_x11window__get_handle; + driver->set_max_width = ptk_x11window__set_max_width; + driver->set_max_height = ptk_x11window__set_max_height; + driver->set_min_width = ptk_x11window__set_min_width; + driver->set_min_height = ptk_x11window__set_min_height; + driver->begin_paint = ptk_x11window__begin_paint; + driver->end_paint = ptk_x11window__end_paint; + driver->present = ptk_x11window__present; } #endif diff --git a/lib/ptk/src/windows/win32app.c b/lib/ptk/src/windows/win32app.c index c1be3bf99..44ec92370 100644 --- a/lib/ptk/src/windows/win32app.c +++ b/lib/ptk/src/windows/win32app.c @@ -369,7 +369,9 @@ static LRESULT CALLBACK ptk_window_process(HWND hwnd, UINT msg, WPARAM arg1, } case WM_CLOSE: e.type = PTK_EVENT_CLOSE; - break; + ptk_process_event(&e); + ptk_event_destroy(&e); + return DefWindowProc(hwnd, msg, arg1, arg2); case WM_DESTROY: if (wnd) { list_unlink(&win32_app.windows, &wnd->node); diff --git a/lib/ui-server/src/server.c b/lib/ui-server/src/server.c index 3a820e310..ecca0dc88 100644 --- a/lib/ui-server/src/server.c +++ b/lib/ui-server/src/server.c @@ -164,7 +164,6 @@ static void ui_server_on_window_close(ptk_event_t *e, void *arg) for (list_each(node, &ui_server.connections)) { conn = node->data; if (conn->window == e->window) { - ptk_window_destroy(conn->window); ui_connection_destroy(conn); list_delete_node(&ui_server.connections, node); break; From 7264d24ad5da4930949083c423921f36059c48d9 Mon Sep 17 00:00:00 2001 From: Liu Date: Thu, 11 Jun 2026 23:47:38 +0800 Subject: [PATCH 36/66] ci: use clang-format-node for consistent formatting --- .github/workflows/ccpp.yml | 11 +++++++---- package-lock.json | 19 +++++++++++++++++++ package.json | 5 +++-- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 89cc3a749..570fa84da 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -18,10 +18,13 @@ jobs: with: fetch-depth: 0 - - name: Install clang-format - run: | - sudo apt-get update --fix-missing - sudo apt-get install -y clang-format + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + run: npm ci - name: Check formatting of changed files run: | diff --git a/package-lock.json b/package-lock.json index b465a90d7..1dedf7154 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "3.0.0-alpha.0", "license": "MIT", "devDependencies": { + "clang-format-node": "^3.0.6", "husky": "^9.1.7", "lint-staged": "^15.2.10" } @@ -81,6 +82,24 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/clang-format-node": { + "version": "3.0.6", + "resolved": "https://registry.npmmirror.com/clang-format-node/-/clang-format-node-3.0.6.tgz", + "integrity": "sha512-AyhcATWwytqnUaswgtpelVP1/UjHWf+tmWrtsy8dRwGkgVXuX61uVa4194wtPHsUzZSwzbcbW0avzLd07tGMPQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "clang-format": "build/cli.js", + "clang-format-node": "build/cli.js" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/lumirlumir" + } + }, "node_modules/cli-cursor": { "version": "5.0.0", "resolved": "https://registry.npmmirror.com/cli-cursor/-/cli-cursor-5.0.0.tgz", diff --git a/package.json b/package.json index 735d8f460..84ec8d470 100644 --- a/package.json +++ b/package.json @@ -18,10 +18,11 @@ "clang-format -i" ] }, - "devDependencies": { + "devDependencies": { + "clang-format-node": "^3.0.6", "husky": "^9.1.7", "lint-staged": "^15.2.10" - }, + }, "repository": { "type": "git", "url": "git+https://github.com/lc-soft/LCUI.git" From 2ea7b4f948b3aa853b23389abf6a56fca660f82c Mon Sep 17 00:00:00 2001 From: Liu Date: Wed, 10 Jun 2026 00:36:00 +0800 Subject: [PATCH 37/66] feat(settings): schema-driven serialization and window state persistence - Per-window state with [window.] sections in settings.ini - Settings module split into rendering and window_state subsystems - Schema-driven (de)serialization with DEFINE_SETTING_INT/BOOL_FIELD macros - Listener-based change notification via deserialize/serialize callbacks - Integration tests for get/set, validation, and bind/restore lifecycle --- include/LCUI/app.h | 14 + include/LCUI/settings.h | 44 +-- include/LCUI/settings/base.h | 27 ++ include/LCUI/settings/rendering.h | 40 +++ include/LCUI/settings/window_state.h | 39 +++ lib/ptk/include/ptk/types.h | 389 ++++++++++----------- lib/ptk/include/ptk/window.h | 13 +- lib/ptk/src/linux/app.c | 15 + lib/ptk/src/linux/fbapp.c | 32 ++ lib/ptk/src/linux/x11app.c | 119 ++++++- lib/ptk/src/windows/win32app.c | 45 +++ lib/ui-server/src/server.c | 5 + src/ini_doc.c | 482 ++++++++++++++++++++++++++ src/ini_doc.h | 49 +++ src/lcui.c | 9 +- src/lcui_rendering.c | 104 ++++++ src/lcui_settings.c | 480 +++++++++----------------- src/lcui_settings.h | 45 +++ src/lcui_window_state.c | 499 +++++++++++++++++++++++++++ src/setting_field.c | 88 +++++ src/setting_field.h | 63 ++++ tests/integration/test_settings.c | 181 +++++++++- 22 files changed, 2218 insertions(+), 564 deletions(-) create mode 100644 include/LCUI/settings/base.h create mode 100644 include/LCUI/settings/rendering.h create mode 100644 include/LCUI/settings/window_state.h create mode 100644 src/ini_doc.c create mode 100644 src/ini_doc.h create mode 100644 src/lcui_rendering.c create mode 100644 src/lcui_settings.h create mode 100644 src/lcui_window_state.c create mode 100644 src/setting_field.c create mode 100644 src/setting_field.h diff --git a/include/LCUI/app.h b/include/LCUI/app.h index 24e42ea43..a191984fa 100644 --- a/include/LCUI/app.h +++ b/include/LCUI/app.h @@ -18,7 +18,21 @@ LCUI_BEGIN_HEADER +/* + * Set the application identifier used for config file resolution. + * + * The id is used as a subdirectory name under the platform config root + * (e.g., %APPDATA%//settings.ini on Windows, + * $XDG_CONFIG_HOME//settings.ini or ~/.config//settings.ini on + * Linux). + * + * Allowed characters: alphanumeric, '.', '_', '-'. Must be non-empty. + * Recommended format: reverse-domain notation, e.g. "com.example.myapp". + * + * Returns true on success, false if app_id is invalid. + */ LCUI_API bool lcui_set_app_id(const char *app_id); + LCUI_API const char *lcui_get_app_id(void); LCUI_API uint32_t lcui_get_fps(void); diff --git a/include/LCUI/settings.h b/include/LCUI/settings.h index 0e94effc9..a7d21ffe1 100644 --- a/include/LCUI/settings.h +++ b/include/LCUI/settings.h @@ -13,46 +13,8 @@ #define LCUI_INCLUDE_LCUI_SETTINGS_H #include "common.h" -#include - -#define LCUI_RENDERING_FPS_CAP_MIN 30 -#define LCUI_RENDERING_FPS_CAP_MAX 480 -#define LCUI_RENDERING_PARALLEL_THREADS_MIN 1 -#define LCUI_RENDERING_PARALLEL_THREADS_MAX 64 -#define LCUI_DEFAULT_FPS_CAP 120 -#define LCUI_DEFAULT_PARALLEL_THREADS 4 -#define LCUI_MAX_FRAMES_PER_SEC LCUI_DEFAULT_FPS_CAP -#define LCUI_MAX_FRAME_MSEC ((int)(1000.0 / LCUI_MAX_FRAMES_PER_SEC + 0.5)) - -LCUI_BEGIN_HEADER - -typedef struct lcui_rendering_settings { - int fps_cap; - int parallel_threads; - bool paint_flashing; -} lcui_rendering_settings_t; - -typedef struct lcui_settings { - int fps_cap; - int parallel_rendering_threads; - bool paint_flashing; -} lcui_settings_t; - -LCUI_API bool lcui_settings_load(void); -LCUI_API bool lcui_settings_flush(void); -LCUI_API void lcui_settings_unload(void); -LCUI_API bool lcui_settings_get_rendering(lcui_rendering_settings_t *out); -LCUI_API bool lcui_settings_set_rendering(const lcui_rendering_settings_t *in); - -/* Initialize settings with the current global settings. */ -LCUI_API void lcui_get_settings(lcui_settings_t *settings); - -/* Update global settings with the given input. */ -LCUI_API void lcui_apply_settings(lcui_settings_t *settings); - -/* Reset global settings to their defaults. */ -LCUI_API void lcui_reset_settings(void); - -LCUI_END_HEADER +#include "settings/base.h" +#include "settings/rendering.h" +#include "settings/window_state.h" #endif diff --git a/include/LCUI/settings/base.h b/include/LCUI/settings/base.h new file mode 100644 index 000000000..8b9b97651 --- /dev/null +++ b/include/LCUI/settings/base.h @@ -0,0 +1,27 @@ +/* + * include/LCUI/settings/base.h + * + * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#ifndef LCUI_INCLUDE_LCUI_SETTINGS_BASE_H +#define LCUI_INCLUDE_LCUI_SETTINGS_BASE_H + +#include +#include + +LCUI_BEGIN_HEADER + +LCUI_API bool lcui_settings_is_loaded(void); +LCUI_API bool lcui_settings_load(void); +LCUI_API bool lcui_settings_flush(void); +LCUI_API void lcui_settings_unload(void); + +LCUI_END_HEADER + +#endif diff --git a/include/LCUI/settings/rendering.h b/include/LCUI/settings/rendering.h new file mode 100644 index 000000000..0f670818f --- /dev/null +++ b/include/LCUI/settings/rendering.h @@ -0,0 +1,40 @@ +/* + * include/LCUI/settings/rendering.h + * + * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#ifndef LCUI_INCLUDE_LCUI_SETTINGS_RENDERING_H +#define LCUI_INCLUDE_LCUI_SETTINGS_RENDERING_H + +#include +#include + +#define LCUI_RENDERING_FPS_CAP_MIN 30 +#define LCUI_RENDERING_FPS_CAP_MAX 480 +#define LCUI_RENDERING_PARALLEL_THREADS_MIN 1 +#define LCUI_RENDERING_PARALLEL_THREADS_MAX 64 +#define LCUI_DEFAULT_FPS_CAP 120 +#define LCUI_DEFAULT_PARALLEL_THREADS 4 +#define LCUI_MAX_FRAMES_PER_SEC LCUI_DEFAULT_FPS_CAP +#define LCUI_MAX_FRAME_MSEC ((int)(1000.0 / LCUI_MAX_FRAMES_PER_SEC + 0.5)) + +LCUI_BEGIN_HEADER + +typedef struct lcui_rendering_settings { + int fps_cap; + int parallel_threads; + bool paint_flashing; +} lcui_rendering_settings_t; + +LCUI_API bool lcui_get_rendering(lcui_rendering_settings_t *out); +LCUI_API bool lcui_set_rendering(const lcui_rendering_settings_t *in); + +LCUI_END_HEADER + +#endif diff --git a/include/LCUI/settings/window_state.h b/include/LCUI/settings/window_state.h new file mode 100644 index 000000000..9007045f9 --- /dev/null +++ b/include/LCUI/settings/window_state.h @@ -0,0 +1,39 @@ +/* + * include/LCUI/settings/window_state.h + * + * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#ifndef LCUI_INCLUDE_LCUI_SETTINGS_WINDOW_STATE_H +#define LCUI_INCLUDE_LCUI_SETTINGS_WINDOW_STATE_H + +#include +#include +#include + +#define LCUI_WINDOW_STATE_SIZE_MIN 1 +#define LCUI_WINDOW_STATE_SIZE_MAX 32768 + +LCUI_BEGIN_HEADER + +typedef struct lcui_window_state { + int x; + int y; + int width; + int height; + bool maximized; +} lcui_window_state_t; + +LCUI_API bool lcui_get_window_state(const char *id, lcui_window_state_t *out); +LCUI_API bool lcui_set_window_state(const char *id, + const lcui_window_state_t *in); +LCUI_API bool lcui_bind_window_state(ui_widget_t *widget, const char *id); + +LCUI_END_HEADER + +#endif diff --git a/lib/ptk/include/ptk/types.h b/lib/ptk/include/ptk/types.h index bd5e19b80..affed0419 100644 --- a/lib/ptk/include/ptk/types.h +++ b/lib/ptk/include/ptk/types.h @@ -19,49 +19,51 @@ typedef pd_context_t ptk_window_paint_t; typedef void (*ptk_timer_cb)(void *); typedef enum { - PTK_APP_ID_UNKNOWN, - PTK_APP_ID_LINUX, - PTK_APP_ID_LINUX_X11, - PTK_APP_ID_WIN_DESKTOP, - PTK_APP_ID_UWP + PTK_APP_ID_UNKNOWN, + PTK_APP_ID_LINUX, + PTK_APP_ID_LINUX_X11, + PTK_APP_ID_WIN_DESKTOP, + PTK_APP_ID_UWP } ptk_app_id_t; /** @see * https://docs.microsoft.com/en-us/uwp/api/Windows.UI.Core.CoreProcessEventsOption?view=winrt-22000 */ typedef enum { - PTK_PROCESS_EVENTS_ONE_AND_ALL_PENDING, - PTK_PROCESS_EVENTS_ONE_IF_PRESENT, - PTK_PROCESS_EVENTS_UNTIL_QUIT, - PTK_PROCESS_EVENTS_ALL_IF_PRESENT, + PTK_PROCESS_EVENTS_ONE_AND_ALL_PENDING, + PTK_PROCESS_EVENTS_ONE_IF_PRESENT, + PTK_PROCESS_EVENTS_UNTIL_QUIT, + PTK_PROCESS_EVENTS_ALL_IF_PRESENT, } ptk_process_events_option_t; #define PTK_APP_ID_WIN32 PTK_APP_ID_WIN_DESKTOP typedef enum { - PTK_EVENT_NONE, - PTK_EVENT_TICK, - PTK_EVENT_QUIT, - PTK_EVENT_CLOSE, - PTK_EVENT_PAINT, - PTK_EVENT_SIZE, - PTK_EVENT_MINMAXINFO, - PTK_EVENT_VISIBILITY_CHANGE, - PTK_EVENT_KEYDOWN, - PTK_EVENT_KEYPRESS, - PTK_EVENT_KEYUP, - PTK_EVENT_MOUSE, - PTK_EVENT_MOUSEMOVE, - PTK_EVENT_MOUSEDOWN, - PTK_EVENT_MOUSEUP, - PTK_EVENT_WHEEL, - PTK_EVENT_COMPOSITION, - PTK_EVENT_TOUCH, - PTK_EVENT_TOUCHMOVE, - PTK_EVENT_TOUCHDOWN, - PTK_EVENT_TOUCHUP, - PTK_EVENT_DPICHANGED, - PTK_EVENT_USER = 100 + PTK_EVENT_NONE, + PTK_EVENT_TICK, + PTK_EVENT_QUIT, + PTK_EVENT_CREATE, + PTK_EVENT_CLOSE, + PTK_EVENT_PAINT, + PTK_EVENT_MOVE, + PTK_EVENT_SIZE, + PTK_EVENT_MINMAXINFO, + PTK_EVENT_VISIBILITY_CHANGE, + PTK_EVENT_KEYDOWN, + PTK_EVENT_KEYPRESS, + PTK_EVENT_KEYUP, + PTK_EVENT_MOUSE, + PTK_EVENT_MOUSEMOVE, + PTK_EVENT_MOUSEDOWN, + PTK_EVENT_MOUSEUP, + PTK_EVENT_WHEEL, + PTK_EVENT_COMPOSITION, + PTK_EVENT_TOUCH, + PTK_EVENT_TOUCHMOVE, + PTK_EVENT_TOUCHDOWN, + PTK_EVENT_TOUCHUP, + PTK_EVENT_DPICHANGED, + PTK_EVENT_USER = 100 } ptk_event_type_t; #define PTK_EVENT_TEXTINPUT PTK_EVENT_COMPOSITION @@ -73,81 +75,81 @@ typedef void (*ptk_event_handler_t)(ptk_event_t *, void *); typedef int (*ptk_event_dispatcher_t)(ptk_event_t *); typedef struct ptk_event_listener { - ptk_event_type_t type; - ptk_event_handler_t handler; - void *data; + ptk_event_type_t type; + ptk_event_handler_t handler; + void *data; } ptk_event_listener_t; /** * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode */ typedef enum { - KEY_BACKSPACE = 8, - KEY_TAB = 9, - KEY_ENTER = 13, - KEY_SHIFT = 16, - KEY_CONTROL = 17, - KEY_ALT = 18, - KEY_CAPITAL = 20, - KEY_ESCAPE = 27, - KEY_SPACE = ' ', - KEY_PAGEUP = 33, - KEY_PAGEDOWN = 34, - KEY_END = 35, - KEY_HOME = 36, - KEY_LEFT = 37, - KEY_UP = 38, - KEY_RIGHT = 39, - KEY_DOWN = 40, - KEY_INSERT = 45, - KEY_DELETE = 46, - KEY_0 = '0', - KEY_1 = '1', - KEY_2 = '2', - KEY_3 = '3', - KEY_4 = '4', - KEY_5 = '5', - KEY_6 = '6', - KEY_7 = '7', - KEY_8 = '8', - KEY_9 = '9', - KEY_A = 'A', - KEY_B = 'B', - KEY_C = 'C', - KEY_D = 'D', - KEY_E = 'E', - KEY_F = 'F', - KEY_G = 'G', - KEY_H = 'H', - KEY_I = 'I', - KEY_J = 'J', - KEY_K = 'K', - KEY_L = 'L', - KEY_M = 'M', - KEY_N = 'N', - KEY_O = 'O', - KEY_P = 'P', - KEY_Q = 'Q', - KEY_R = 'R', - KEY_S = 'S', - KEY_T = 'T', - KEY_U = 'U', - KEY_V = 'V', - KEY_W = 'W', - KEY_X = 'X', - KEY_Y = 'Y', - KEY_Z = 'Z', - KEY_SEMICOLON = 186, - KEY_EQUAL = 187, - KEY_COMMA = 188, - KEY_MINUS = 189, - KEY_PERIOD = 190, - KEY_SLASH = 191, - KEY_GRAVE = 192, - KEY_BRACKETLEFT = 219, - KEY_BACKSLASH = 220, - KEY_BRACKETRIGHT = 221, - KEY_APOSTROPHE = 222 + KEY_BACKSPACE = 8, + KEY_TAB = 9, + KEY_ENTER = 13, + KEY_SHIFT = 16, + KEY_CONTROL = 17, + KEY_ALT = 18, + KEY_CAPITAL = 20, + KEY_ESCAPE = 27, + KEY_SPACE = ' ', + KEY_PAGEUP = 33, + KEY_PAGEDOWN = 34, + KEY_END = 35, + KEY_HOME = 36, + KEY_LEFT = 37, + KEY_UP = 38, + KEY_RIGHT = 39, + KEY_DOWN = 40, + KEY_INSERT = 45, + KEY_DELETE = 46, + KEY_0 = '0', + KEY_1 = '1', + KEY_2 = '2', + KEY_3 = '3', + KEY_4 = '4', + KEY_5 = '5', + KEY_6 = '6', + KEY_7 = '7', + KEY_8 = '8', + KEY_9 = '9', + KEY_A = 'A', + KEY_B = 'B', + KEY_C = 'C', + KEY_D = 'D', + KEY_E = 'E', + KEY_F = 'F', + KEY_G = 'G', + KEY_H = 'H', + KEY_I = 'I', + KEY_J = 'J', + KEY_K = 'K', + KEY_L = 'L', + KEY_M = 'M', + KEY_N = 'N', + KEY_O = 'O', + KEY_P = 'P', + KEY_Q = 'Q', + KEY_R = 'R', + KEY_S = 'S', + KEY_T = 'T', + KEY_U = 'U', + KEY_V = 'V', + KEY_W = 'W', + KEY_X = 'X', + KEY_Y = 'Y', + KEY_Z = 'Z', + KEY_SEMICOLON = 186, + KEY_EQUAL = 187, + KEY_COMMA = 188, + KEY_MINUS = 189, + KEY_PERIOD = 190, + KEY_SLASH = 191, + KEY_GRAVE = 192, + KEY_BRACKETLEFT = 219, + KEY_BACKSLASH = 220, + KEY_BRACKETRIGHT = 221, + KEY_APOSTROPHE = 222 } ptk_key_t; /** @@ -155,11 +157,11 @@ typedef enum { * https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button#return_value */ typedef enum mouse_button_code_t { - MOUSE_BUTTON_MAIN, - MOUSE_BUTTON_AUXILIARY, - MOUSE_BUTTON_SECNODARY, - MOUSE_BUTTON_FORTH_BUTTON, - MOUSE_BUTTON_FIFTH_BUTTON + MOUSE_BUTTON_MAIN, + MOUSE_BUTTON_AUXILIARY, + MOUSE_BUTTON_SECNODARY, + MOUSE_BUTTON_FORTH_BUTTON, + MOUSE_BUTTON_FIFTH_BUTTON } mouse_button_code_t; #define MOUSE_BUTTON_LEFT MOUSE_BUTTON_MAIN @@ -171,146 +173,149 @@ typedef enum mouse_button_code_t { * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent */ typedef struct app_keyboard_event { - int code; - bool alt_key; - bool ctrl_key; - bool shift_key; - bool meta_key; - bool is_composing; + int code; + bool alt_key; + bool ctrl_key; + bool shift_key; + bool meta_key; + bool is_composing; } app_keyboard_event_t; typedef struct touch_point { - int x; - int y; - int id; - int state; - bool is_primary; + int x; + int y; + int id; + int state; + bool is_primary; } touch_point_t; typedef struct app_touch_event { - unsigned n_points; - touch_point_t *points; + unsigned n_points; + touch_point_t *points; } app_touch_event_t; typedef struct app_paint_event { - pd_rect_t rect; + pd_rect_t rect; } app_paint_event_t; typedef struct app_textinput_event { - wchar_t *text; - size_t length; + wchar_t *text; + size_t length; } app_textinput_event_t; /** * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent */ typedef struct app_mouse_event { - int x; - int y; - int button; + int x; + int y; + int button; } app_mouse_event_t; typedef enum app_wheel_delta_mode_t { - APP_WHEEL_DELTA_PIXEL = 0, - APP_WHEEL_DELTA_LINE, - APP_WHEEL_DELTA_PAGE + APP_WHEEL_DELTA_PIXEL = 0, + APP_WHEEL_DELTA_LINE, + APP_WHEEL_DELTA_PAGE } app_wheel_delta_mode_t; /** * @see https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent */ typedef struct app_wheel_event { - int delta_x; - int delta_y; - int delta_z; - int delta_mode; + int delta_x; + int delta_y; + int delta_z; + int delta_mode; } app_wheel_event_t; typedef struct app_size_event { - int width; - int height; + int width; + int height; } app_size_event_t; typedef struct app_minmaxinfo_event { - int min_width; - int min_height; - int max_width; - int max_height; + int min_width; + int min_height; + int max_width; + int max_height; } app_minmaxinfo_event_t; typedef struct app_visibility_change_event { - bool visible; + bool visible; } app_visibility_change_event_t; typedef struct app_dpi_change_event { - int dpi; + int dpi; } app_dpi_change_event_t; struct ptk_event { - ptk_event_type_t type; - ptk_window_t *window; - void *data; - - union { - app_mouse_event_t mouse; - app_wheel_event_t wheel; - app_textinput_event_t composition; - app_textinput_event_t text; - app_keyboard_event_t key; - app_touch_event_t touch; - app_paint_event_t paint; - app_size_event_t size; - app_minmaxinfo_event_t minmaxinfo; - app_visibility_change_event_t visibility_change; - app_dpi_change_event_t dpi_change; - }; + ptk_event_type_t type; + ptk_window_t *window; + void *data; + + union { + app_mouse_event_t mouse; + app_wheel_event_t wheel; + app_textinput_event_t composition; + app_textinput_event_t text; + app_keyboard_event_t key; + app_touch_event_t touch; + app_paint_event_t paint; + app_size_event_t size; + app_minmaxinfo_event_t minmaxinfo; + app_visibility_change_event_t visibility_change; + app_dpi_change_event_t dpi_change; + }; }; typedef void ptk_native_event_t; typedef void (*ptk_native_event_handler_t)(ptk_native_event_t *, void *); typedef struct ptk_native_event_listener { - int type; - ptk_native_event_handler_t handler; - void *data; + int type; + ptk_native_event_handler_t handler; + void *data; } ptk_native_event_listener_t; typedef struct ptk_window_driver { - void (*hide)(ptk_window_t *); - void (*show)(ptk_window_t *); - void (*activate)(ptk_window_t *); - void (*close)(ptk_window_t *); - void (*destroy)(ptk_window_t *); - void (*set_title)(ptk_window_t *, const wchar_t *); - void (*set_size)(ptk_window_t *, int, int); - void (*set_position)(ptk_window_t *, int, int); - void *(*get_handle)(ptk_window_t *); - int (*get_width)(ptk_window_t *); - int (*get_height)(ptk_window_t *); - void (*set_min_width)(ptk_window_t *, int); - void (*set_min_height)(ptk_window_t *, int); - void (*set_max_width)(ptk_window_t *, int); - void (*set_max_height)(ptk_window_t *, int); - ptk_window_paint_t *(*begin_paint)(ptk_window_t *, pd_rect_t *); - void (*end_paint)(ptk_window_t *, ptk_window_paint_t *); - void (*present)(ptk_window_t *); + void (*hide)(ptk_window_t *); + void (*show)(ptk_window_t *); + void (*activate)(ptk_window_t *); + void (*close)(ptk_window_t *); + void (*destroy)(ptk_window_t *); + void (*set_title)(ptk_window_t *, const wchar_t *); + void (*set_size)(ptk_window_t *, int, int); + void (*set_position)(ptk_window_t *, int, int); + void (*get_position)(ptk_window_t *, int *, int *); + void (*set_maximized)(ptk_window_t *, bool); + void *(*get_handle)(ptk_window_t *); + int (*get_width)(ptk_window_t *); + int (*get_height)(ptk_window_t *); + bool (*is_maximized)(ptk_window_t *); + void (*set_min_width)(ptk_window_t *, int); + void (*set_min_height)(ptk_window_t *, int); + void (*set_max_width)(ptk_window_t *, int); + void (*set_max_height)(ptk_window_t *, int); + ptk_window_paint_t *(*begin_paint)(ptk_window_t *, pd_rect_t *); + void (*end_paint)(ptk_window_t *, ptk_window_paint_t *); + void (*present)(ptk_window_t *); } ptk_window_driver_t; typedef struct ptk_app_driver { - int (*init)(const wchar_t *); - int (*destroy)(void); - int (*process_events)(ptk_process_events_option_t option); - int (*on_event)(int type, ptk_native_event_handler_t handler, - void *data); - int (*off_event)(int type, ptk_native_event_handler_t handler); - int (*get_screen_width)(void); - int (*get_screen_height)(void); - ptk_window_t *(*create_window)(const wchar_t *title, int x, int y, - int width, int height, - ptk_window_t *parent); - ptk_window_t *(*get_window)(void *handle); - void (*present)(void); - void (*exit)(int exit_code); + int (*init)(const wchar_t *); + int (*destroy)(void); + int (*process_events)(ptk_process_events_option_t option); + int (*on_event)(int type, ptk_native_event_handler_t handler, + void *data); + int (*off_event)(int type, ptk_native_event_handler_t handler); + int (*get_screen_width)(void); + int (*get_screen_height)(void); + ptk_window_t *(*create_window)(const wchar_t *title, int x, int y, + int width, int height, + ptk_window_t *parent); + ptk_window_t *(*get_window)(void *handle); + void (*present)(void); + void (*exit)(int exit_code); } ptk_app_driver_t; // Window diff --git a/lib/ptk/include/ptk/window.h b/lib/ptk/include/ptk/window.h index 20dba76be..cd75551cd 100644 --- a/lib/ptk/include/ptk/window.h +++ b/lib/ptk/include/ptk/window.h @@ -24,15 +24,17 @@ PTK_PUBLIC unsigned ptk_window_get_dpi(ptk_window_t *wnd); PTK_PUBLIC ptk_window_t *ptk_find_window(void *handle); PTK_PUBLIC ptk_window_t *ptk_window_create(const wchar_t *title, int x, int y, - int width, int height, - ptk_window_t *parent); + int width, int height, + ptk_window_t *parent); PTK_PUBLIC void ptk_window_close(ptk_window_t *wnd); PTK_PUBLIC void ptk_window_destroy(ptk_window_t *wnd); PTK_PUBLIC void ptk_window_set_fullscreen(ptk_window_t *wnd, bool fullscreen); PTK_PUBLIC void ptk_window_set_position(ptk_window_t *wnd, int x, int y); +PTK_PUBLIC void ptk_window_get_position(ptk_window_t *wnd, int *x, int *y); +PTK_PUBLIC void ptk_window_set_maximized(ptk_window_t *wnd, bool maximized); PTK_PUBLIC void ptk_window_set_framebuffer_size(ptk_window_t *wnd, int width, - int height); + int height); PTK_PUBLIC void ptk_window_set_size(ptk_window_t *wnd, int width, int height); PTK_PUBLIC void ptk_window_show(ptk_window_t *wnd); PTK_PUBLIC void ptk_window_hide(ptk_window_t *wnd); @@ -40,14 +42,15 @@ PTK_PUBLIC void ptk_window_activate(ptk_window_t *wnd); PTK_PUBLIC void ptk_window_set_title(ptk_window_t *wnd, const wchar_t *title); PTK_PUBLIC int ptk_window_get_width(ptk_window_t *wnd); PTK_PUBLIC int ptk_window_get_height(ptk_window_t *wnd); +PTK_PUBLIC bool ptk_window_is_maximized(ptk_window_t *wnd); PTK_PUBLIC void ptk_window_set_min_width(ptk_window_t *wnd, int min_width); PTK_PUBLIC void ptk_window_set_min_height(ptk_window_t *wnd, int min_height); PTK_PUBLIC void ptk_window_set_max_width(ptk_window_t *wnd, int max_width); PTK_PUBLIC void ptk_window_set_max_height(ptk_window_t *wnd, int max_height); PTK_PUBLIC ptk_window_paint_t *ptk_window_begin_paint(ptk_window_t *wnd, - pd_rect_t *rect); + pd_rect_t *rect); PTK_PUBLIC void ptk_window_end_paint(ptk_window_t *wnd, - ptk_window_paint_t *paint); + ptk_window_paint_t *paint); PTK_PUBLIC void ptk_window_present(ptk_window_t *wnd); PTK_END_DECLS diff --git a/lib/ptk/src/linux/app.c b/lib/ptk/src/linux/app.c index 7c14b8b3b..1ebd1de86 100644 --- a/lib/ptk/src/linux/app.c +++ b/lib/ptk/src/linux/app.c @@ -94,6 +94,16 @@ void ptk_window_set_position(ptk_window_t *wnd, int x, int y) return linux_app.window.set_position(wnd, x, y); } +void ptk_window_get_position(ptk_window_t *wnd, int *x, int *y) +{ + linux_app.window.get_position(wnd, x, y); +} + +void ptk_window_set_maximized(ptk_window_t *wnd, bool maximized) +{ + linux_app.window.set_maximized(wnd, maximized); +} + void *ptk_window_get_handle(ptk_window_t *wnd) { return linux_app.window.get_handle(wnd); @@ -115,6 +125,11 @@ int ptk_window_get_height(ptk_window_t *wnd) return linux_app.window.get_height(wnd); } +bool ptk_window_is_maximized(ptk_window_t *wnd) +{ + return linux_app.window.is_maximized(wnd); +} + void ptk_window_set_min_width(ptk_window_t *wnd, int min_width) { linux_app.window.set_min_width(wnd, min_width); diff --git a/lib/ptk/src/linux/fbapp.c b/lib/ptk/src/linux/fbapp.c index a233f1b8e..d52e03fd5 100644 --- a/lib/ptk/src/linux/fbapp.c +++ b/lib/ptk/src/linux/fbapp.c @@ -242,6 +242,35 @@ static void ptk_fb_window_set_size(ptk_window_t *wnd, int width, int height) static void ptk_fb_window_set_position(ptk_window_t *wnd, int x, int y) { + wnd->x = x; + wnd->y = y; + wnd->rect.x = x; + wnd->rect.y = y; + wnd->actual_rect = wnd->rect; + pd_rect_correct(&wnd->actual_rect, fbapp.screen_width, + fbapp.screen_height); +} + +static void ptk_fb_window_get_position(ptk_window_t *wnd, int *x, int *y) +{ + if (x) { + *x = wnd->x; + } + if (y) { + *y = wnd->y; + } +} + +static void ptk_fb_window_set_maximized(ptk_window_t *wnd, bool maximized) +{ + (void)wnd; + (void)maximized; +} + +static bool ptk_fb_window_is_maximized(ptk_window_t *wnd) +{ + (void)wnd; + return false; } static ptk_window_t *ptk_fbapp_get_window_by_handle(void *handle) @@ -567,8 +596,11 @@ void ptk_fbwindow_driver_init(ptk_window_driver_t *driver) driver->set_title = ptk_fb_window_set_title; driver->set_size = ptk_fb_window_set_size; driver->set_position = ptk_fb_window_set_position; + driver->get_position = ptk_fb_window_get_position; + driver->set_maximized = ptk_fb_window_set_maximized; driver->get_width = ptk_fb_window_get_width; driver->get_height = ptk_fb_window_get_height; + driver->is_maximized = ptk_fb_window_is_maximized; driver->get_handle = ptk_fb_window_get_handle; driver->set_max_width = ptk_fb_window_set_max_width; driver->set_max_height = ptk_fb_window_set_max_height; diff --git a/lib/ptk/src/linux/x11app.c b/lib/ptk/src/linux/x11app.c index 38fa19525..416825362 100644 --- a/lib/ptk/src/linux/x11app.c +++ b/lib/ptk/src/linux/x11app.c @@ -61,6 +61,103 @@ static struct ptk_x11app { static void ptk_x11window__show(ptk_window_t *wnd); static void ptk_x11window__set_size(ptk_window_t *wnd, int width, int height); +static bool ptk_x11window__update_position(ptk_window_t *wnd, int *x, int *y) +{ + Window child, root; + int actual_x = wnd ? wnd->x : 0; + int actual_y = wnd ? wnd->y : 0; + + if (!wnd) { + return false; + } + root = DefaultRootWindow(x11_app.display); + if (!XTranslateCoordinates(x11_app.display, wnd->handle, root, 0, 0, + &actual_x, &actual_y, &child)) { + return false; + } + wnd->x = actual_x; + wnd->y = actual_y; + if (x) { + *x = actual_x; + } + if (y) { + *y = actual_y; + } + return true; +} + +static bool ptk_x11window__is_maximized(ptk_window_t *wnd) +{ + Atom actual_type; + Atom wm_state; + Atom max_horz; + Atom max_vert; + int actual_format; + unsigned long i, nitems, bytes_after; + unsigned char *data = NULL; + bool maximized = false; + + if (!wnd) { + return false; + } + wm_state = XInternAtom(x11_app.display, "_NET_WM_STATE", False); + max_horz = + XInternAtom(x11_app.display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); + max_vert = + XInternAtom(x11_app.display, "_NET_WM_STATE_MAXIMIZED_VERT", False); + if (XGetWindowProperty(x11_app.display, wnd->handle, wm_state, 0, 32, + False, XA_ATOM, &actual_type, &actual_format, + &nitems, &bytes_after, &data) == Success && + actual_type == XA_ATOM && actual_format == 32 && data) { + Atom *atoms = (Atom *)data; + bool has_horz = false; + bool has_vert = false; + + for (i = 0; i < nitems; ++i) { + if (atoms[i] == max_horz) { + has_horz = true; + } else if (atoms[i] == max_vert) { + has_vert = true; + } + } + maximized = has_horz && has_vert; + } + if (data) { + XFree(data); + } + return maximized; +} + +static void ptk_x11window__set_maximized(ptk_window_t *wnd, bool maximized) +{ + Atom max_horz; + Atom max_vert; + Atom wm_state; + Window root; + XEvent event = { 0 }; + + if (!wnd) { + return; + } + root = DefaultRootWindow(x11_app.display); + wm_state = XInternAtom(x11_app.display, "_NET_WM_STATE", False); + max_horz = + XInternAtom(x11_app.display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); + max_vert = + XInternAtom(x11_app.display, "_NET_WM_STATE_MAXIMIZED_VERT", False); + event.xclient.type = ClientMessage; + event.xclient.window = wnd->handle; + event.xclient.message_type = wm_state; + event.xclient.format = 32; + event.xclient.data.l[0] = maximized ? 1 : 0; + event.xclient.data.l[1] = max_horz; + event.xclient.data.l[2] = max_vert; + event.xclient.data.l[3] = 1; + XSendEvent(x11_app.display, root, False, + SubstructureNotifyMask | SubstructureRedirectMask, &event); + XFlush(x11_app.display); +} + static int convert_keycode(KeySym keysym) { switch (keysym) { @@ -248,13 +345,18 @@ static int x11_ptk_process_native_event(void) e.window = ptk_x11app_get_window_by_handle(&xe.xany.window); switch (xe.type) { case ConfigureNotify: + if (!e.window) { + break; + } + ptk_x11window__update_position(e.window, NULL, NULL); + e.type = PTK_EVENT_MOVE; + ptk_process_event(&e); e.type = PTK_EVENT_SIZE; e.size.width = xe.xconfigure.width; e.size.height = xe.xconfigure.height; ptk_x11window__on_size(e.window, xe.xconfigure.width, xe.xconfigure.height); ptk_process_event(&e); - // TODO: add MOVE event? break; case Expose: e.type = PTK_EVENT_PAINT; @@ -507,6 +609,18 @@ static void ptk_x11window__set_position(ptk_window_t *wnd, int x, int y) XMoveWindow(x11_app.display, wnd->handle, x, y); } +static void ptk_x11window__get_position(ptk_window_t *wnd, int *x, int *y) +{ + if (!ptk_x11window__update_position(wnd, x, y)) { + if (x) { + *x = wnd ? wnd->x : 0; + } + if (y) { + *y = wnd ? wnd->y : 0; + } + } +} + static void *ptk_x11window__get_handle(ptk_window_t *wnd) { return &wnd->handle; @@ -682,9 +796,12 @@ void ptk_x11window_driver_init(ptk_window_driver_t *driver) driver->activate = ptk_x11window__activate; driver->set_title = ptk_x11window__set_title; driver->set_position = ptk_x11window__set_position; + driver->get_position = ptk_x11window__get_position; driver->set_size = ptk_x11window__set_size; + driver->set_maximized = ptk_x11window__set_maximized; driver->get_width = ptk_x11window__get_width; driver->get_height = ptk_x11window__get_height; + driver->is_maximized = ptk_x11window__is_maximized; driver->get_handle = ptk_x11window__get_handle; driver->set_max_width = ptk_x11window__set_max_width; driver->set_max_height = ptk_x11window__set_max_height; diff --git a/lib/ptk/src/windows/win32app.c b/lib/ptk/src/windows/win32app.c index 44ec92370..062c31dd0 100644 --- a/lib/ptk/src/windows/win32app.c +++ b/lib/ptk/src/windows/win32app.c @@ -35,6 +35,7 @@ struct ptk_window { DWORD ex_style; WINDOWPLACEMENT placement; + int x, y; int width, height; int min_width, min_height; int max_width, max_height; @@ -304,6 +305,14 @@ static LRESULT CALLBACK ptk_window_process(HWND hwnd, UINT msg, WPARAM arg1, e.window->visible = arg1 ? true : false; e.visibility_change.visible = e.window->visible; break; + case WM_MOVE: + if (!wnd) { + break; + } + e.type = PTK_EVENT_MOVE; + wnd->x = (int)(short)LOWORD(arg2); + wnd->y = (int)(short)HIWORD(arg2); + break; case WM_SIZE: { e.type = PTK_EVENT_SIZE; e.size.width = LOWORD(arg2); @@ -519,6 +528,8 @@ ptk_window_t *ptk_window_create(const wchar_t *title, int x, int y, int width, wnd->node.data = wnd; wnd->min_width = MIN_WIDTH; wnd->min_height = MIN_HEIGHT; + wnd->x = x; + wnd->y = y; wnd->width = width; wnd->height = height; wnd->visible = false; @@ -626,6 +637,35 @@ void ptk_window_set_position(ptk_window_t *wnd, int x, int y) SWP_NOSIZE | SWP_NOZORDER); } +void ptk_window_get_position(ptk_window_t *wnd, int *x, int *y) +{ + POINT point = { 0, 0 }; + + if (!wnd || !wnd->hwnd || !ClientToScreen(wnd->hwnd, &point)) { + if (x) { + *x = 0; + } + if (y) { + *y = 0; + } + return; + } + if (x) { + *x = point.x; + } + if (y) { + *y = point.y; + } +} + +void ptk_window_set_maximized(ptk_window_t *wnd, bool maximized) +{ + if (!wnd || !wnd->hwnd) { + return; + } + ShowWindow(wnd->hwnd, maximized ? SW_MAXIMIZE : SW_RESTORE); +} + void ptk_window_set_size(ptk_window_t *wnd, int width, int height) { if (wnd->width == width && wnd->height == height) { @@ -665,6 +705,11 @@ int ptk_window_get_height(ptk_window_t *wnd) return wnd->height; } +bool ptk_window_is_maximized(ptk_window_t *wnd) +{ + return wnd && wnd->hwnd && IsZoomed(wnd->hwnd) ? true : false; +} + void ptk_window_set_min_width(ptk_window_t *wnd, int min_width) { wnd->min_width = min_width; diff --git a/lib/ui-server/src/server.c b/lib/ui-server/src/server.c index ecca0dc88..013cdc78c 100644 --- a/lib/ui-server/src/server.c +++ b/lib/ui-server/src/server.c @@ -675,9 +675,14 @@ void ui_server_update(void) ui_metrics.dpi = 1.f * ptk_window_get_dpi(conn->window); ui_updater_update(conn->updater, conn->widget); if (conn->state == UI_CONNECTION_STATE_PENDING) { + ptk_event_t e = { 0 }; + conn->state = UI_CONNECTION_STATE_INITIALIZING; ui_server_refresh_window(conn); conn->state = UI_CONNECTION_STATE_INITIALIZED; + e.type = PTK_EVENT_CREATE; + e.window = conn->window; + ptk_process_event(&e); } } } else { diff --git a/src/ini_doc.c b/src/ini_doc.c new file mode 100644 index 000000000..16e9bca81 --- /dev/null +++ b/src/ini_doc.c @@ -0,0 +1,482 @@ +/* + * src/ini_doc.c -- generic INI document. + * + * Copyright (c) 2023-2025, Liu Chao + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include +#ifndef _WIN32 +#include +#endif + +#include "ini_doc.h" + +#ifdef _WIN32 +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#endif + +typedef struct ini_entry { + char *key; + char *value; +} ini_entry_t; + +typedef struct ini_section { + char *name; + ini_entry_t *entries; + size_t entry_count; + size_t entry_capacity; +} ini_section_t; + +struct ini_doc { + ini_section_t *sections; + size_t section_count; + size_t section_capacity; +}; + +static ini_section_t *ini_doc_find_section(ini_doc_t *doc, const char *name, + bool create) +{ + size_t i; + ini_section_t *section; + + for (i = 0; i < doc->section_count; ++i) { + if (strcasecmp(doc->sections[i].name, name) == 0) { + return &doc->sections[i]; + } + } + if (!create) { + return NULL; + } + if (doc->section_count >= doc->section_capacity) { + size_t cap = + doc->section_capacity ? doc->section_capacity * 2 : 8; + ini_section_t *s; + + s = realloc(doc->sections, cap * sizeof(ini_section_t)); + if (!s) { + return NULL; + } + doc->sections = s; + doc->section_capacity = cap; + } + section = &doc->sections[doc->section_count]; + memset(section, 0, sizeof(*section)); + section->name = strdup2(name); + if (!section->name) { + return NULL; + } + doc->section_count++; + return section; +} + +static const ini_section_t *ini_doc_find_section_const(const ini_doc_t *doc, + const char *name) +{ + size_t i; + + for (i = 0; i < doc->section_count; ++i) { + if (strcasecmp(doc->sections[i].name, name) == 0) { + return &doc->sections[i]; + } + } + return NULL; +} + +static ini_entry_t *ini_section_find_entry(ini_section_t *section, + const char *key) +{ + size_t i; + + for (i = 0; i < section->entry_count; ++i) { + if (strcasecmp(section->entries[i].key, key) == 0) { + return §ion->entries[i]; + } + } + return NULL; +} + +static const ini_entry_t *ini_section_find_entry_const( + const ini_section_t *section, const char *key) +{ + size_t i; + + for (i = 0; i < section->entry_count; ++i) { + if (strcasecmp(section->entries[i].key, key) == 0) { + return §ion->entries[i]; + } + } + return NULL; +} + +static ini_entry_t *ini_section_ensure_entry(ini_section_t *section, + const char *key) +{ + ini_entry_t *entry = ini_section_find_entry(section, key); + + if (entry) { + return entry; + } + if (section->entry_count >= section->entry_capacity) { + size_t cap = + section->entry_capacity ? section->entry_capacity * 2 : 4; + ini_entry_t *e; + + e = realloc(section->entries, cap * sizeof(ini_entry_t)); + if (!e) { + return NULL; + } + section->entries = e; + section->entry_capacity = cap; + } + entry = §ion->entries[section->entry_count]; + memset(entry, 0, sizeof(*entry)); + entry->key = strdup2(key); + if (!entry->key) { + return NULL; + } + section->entry_count++; + return entry; +} + +static bool ini_entry_set_value(ini_entry_t *entry, const char *value) +{ + char *copy = strdup2(value); + + if (!copy) { + return false; + } + free(entry->value); + entry->value = copy; + return true; +} + +static char *ini_trim(char *str) +{ + size_t len; + + while (*str && isspace((unsigned char)*str)) { + ++str; + } + len = strlen(str); + while (len > 0 && isspace((unsigned char)str[len - 1])) { + str[--len] = 0; + } + return str; +} + +static void ini_section_destroy(ini_section_t *section) +{ + size_t i; + + for (i = 0; i < section->entry_count; ++i) { + free(section->entries[i].key); + free(section->entries[i].value); + } + free(section->entries); + free(section->name); + memset(section, 0, sizeof(*section)); +} + +ini_doc_t *ini_doc_create(void) +{ + ini_doc_t *doc = calloc(1, sizeof(ini_doc_t)); + + return doc; +} + +ini_doc_t *ini_doc_load(const char *path) +{ + char line[1024]; + char section[256] = { 0 }; + FILE *fp; + ini_doc_t *doc; + + fp = fopen(path, "r"); + if (!fp) { + if (errno == ENOENT) { + return ini_doc_create(); + } + return NULL; + } + doc = ini_doc_create(); + if (!doc) { + fclose(fp); + return NULL; + } + while (fgets(line, sizeof(line), fp)) { + char *data, *value, *end; + + data = ini_trim(line); + if (data[0] == 0 || data[0] == ';' || data[0] == '#') { + continue; + } + if (data[0] == '[') { + end = strchr(data, ']'); + if (!end) { + continue; + } + *end = 0; + snprintf(section, sizeof(section), "%s", data + 1); + continue; + } + value = strchr(data, '='); + if (!value || section[0] == 0) { + continue; + } + *value++ = 0; + data = ini_trim(data); + value = ini_trim(value); + if (!ini_doc_set_string(doc, section, data, value)) { + ini_doc_destroy(doc); + fclose(fp); + return NULL; + } + } + fclose(fp); + return doc; +} + +bool ini_doc_save(const ini_doc_t *doc, const char *path) +{ + size_t i, j, path_len; + char *backup_path = NULL; + char *tmp_path; + FILE *fp; + int ret; + bool first_section = true; + + path_len = strlen(path); + tmp_path = malloc(sizeof(char) * (path_len + 5)); + if (!tmp_path) { + return false; + } + strcpy(tmp_path, path); + strcat(tmp_path, ".tmp"); + fp = fopen(tmp_path, "w"); + if (!fp) { + free(tmp_path); + return false; + } + for (i = 0; i < doc->section_count; ++i) { + const ini_section_t *s = &doc->sections[i]; + + if (!first_section) { + fprintf(fp, "\n"); + } + fprintf(fp, "[%s]\n", s->name); + for (j = 0; j < s->entry_count; ++j) { + fprintf(fp, "%s=%s\n", s->entries[j].key, + s->entries[j].value); + } + first_section = false; + } + fclose(fp); +#ifdef _WIN32 + backup_path = malloc(sizeof(char) * (path_len + 5)); + if (!backup_path) { + remove(tmp_path); + free(tmp_path); + return false; + } + snprintf(backup_path, path_len + 5, "%s.bak", path); + remove(backup_path); + ret = rename(path, backup_path); + if (ret != 0 && errno != ENOENT) { + remove(tmp_path); + free(backup_path); + free(tmp_path); + return false; + } + ret = rename(tmp_path, path); + if (ret == 0) { + remove(backup_path); + } else if (rename(backup_path, path) != 0) { + remove(backup_path); + } +#else + ret = rename(tmp_path, path); +#endif + free(backup_path); + free(tmp_path); + return ret == 0; +} + +void ini_doc_destroy(ini_doc_t *doc) +{ + size_t i; + + for (i = 0; i < doc->section_count; ++i) { + ini_section_destroy(&doc->sections[i]); + } + free(doc->sections); + free(doc); +} + +bool ini_doc_get_int(const ini_doc_t *doc, const char *section, const char *key, + int *out) +{ + long val; + char *endptr; + const ini_section_t *s; + const ini_entry_t *e; + + s = ini_doc_find_section_const(doc, section); + if (!s) { + return false; + } + e = ini_section_find_entry_const(s, key); + if (!e || !e->value) { + return false; + } + errno = 0; + val = strtol(e->value, &endptr, 10); + if (errno != 0 || endptr == e->value || *endptr != 0 || val > INT_MAX || + val < INT_MIN) { + return false; + } + *out = (int)val; + return true; +} + +bool ini_doc_get_bool(const ini_doc_t *doc, const char *section, + const char *key, bool *out) +{ + const ini_section_t *s; + const ini_entry_t *e; + + s = ini_doc_find_section_const(doc, section); + if (!s) { + return false; + } + e = ini_section_find_entry_const(s, key); + if (!e || !e->value) { + return false; + } + if (strcmp(e->value, "1") == 0 || strcasecmp(e->value, "true") == 0) { + *out = true; + return true; + } + if (strcmp(e->value, "0") == 0 || strcasecmp(e->value, "false") == 0) { + *out = false; + return true; + } + return false; +} + +bool ini_doc_get_string(const ini_doc_t *doc, const char *section, + const char *key, char **out) +{ + const ini_section_t *s; + const ini_entry_t *e; + + s = ini_doc_find_section_const(doc, section); + if (!s) { + return false; + } + e = ini_section_find_entry_const(s, key); + if (!e || !e->value) { + return false; + } + *out = strdup2(e->value); + return *out != NULL; +} + +bool ini_doc_set_int(ini_doc_t *doc, const char *section, const char *key, + int value) +{ + char buf[32]; + + snprintf(buf, sizeof(buf), "%d", value); + return ini_doc_set_string(doc, section, key, buf); +} + +bool ini_doc_set_bool(ini_doc_t *doc, const char *section, const char *key, + bool value) +{ + return ini_doc_set_string(doc, section, key, value ? "1" : "0"); +} + +bool ini_doc_set_string(ini_doc_t *doc, const char *section, const char *key, + const char *value) +{ + ini_section_t *s; + ini_entry_t *e; + + s = ini_doc_find_section(doc, section, true); + if (!s) { + return false; + } + e = ini_section_ensure_entry(s, key); + if (!e) { + return false; + } + return ini_entry_set_value(e, value); +} + +bool ini_doc_has_section(const ini_doc_t *doc, const char *section) +{ + return ini_doc_find_section_const(doc, section) != NULL; +} + +bool ini_doc_remove_section(ini_doc_t *doc, const char *section) +{ + size_t i; + ini_section_t *s; + + for (i = 0; i < doc->section_count; ++i) { + if (strcasecmp(doc->sections[i].name, section) == 0) { + s = &doc->sections[i]; + ini_section_destroy(s); + if (i + 1 < doc->section_count) { + memmove(&doc->sections[i], + &doc->sections[i + 1], + (doc->section_count - i - 1) * + sizeof(ini_section_t)); + } + doc->section_count--; + return true; + } + } + return false; +} + +bool ini_doc_has_key(const ini_doc_t *doc, const char *section, const char *key) +{ + const ini_section_t *s; + + s = ini_doc_find_section_const(doc, section); + if (!s) { + return false; + } + return ini_section_find_entry_const(s, key) != NULL; +} + +void ini_doc_foreach_section(const ini_doc_t *doc, const char *prefix, + ini_doc_section_fn fn, void *ctx) +{ + size_t i, prefix_len; + + prefix_len = strlen(prefix); + for (i = 0; i < doc->section_count; ++i) { + const char *name = doc->sections[i].name; + + if (strncasecmp(name, prefix, prefix_len) == 0) { + if (!fn(name + prefix_len, ctx)) { + return; + } + } + } +} diff --git a/src/ini_doc.h b/src/ini_doc.h new file mode 100644 index 000000000..376a5b375 --- /dev/null +++ b/src/ini_doc.h @@ -0,0 +1,49 @@ +/* + * src/ini_doc.h -- generic INI document. + * + * Copyright (c) 2023-2025, Liu Chao + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#ifndef LCUI_SRC_INI_DOC_H +#define LCUI_SRC_INI_DOC_H + +#include +#include + +typedef struct ini_doc ini_doc_t; + +typedef bool (*ini_doc_section_fn)(const char *suffix, void *ctx); + +ini_doc_t *ini_doc_create(void); +ini_doc_t *ini_doc_load(const char *path); +bool ini_doc_save(const ini_doc_t *doc, const char *path); +void ini_doc_destroy(ini_doc_t *doc); + +bool ini_doc_get_int(const ini_doc_t *doc, const char *section, const char *key, + int *out); +bool ini_doc_get_bool(const ini_doc_t *doc, const char *section, + const char *key, bool *out); +bool ini_doc_get_string(const ini_doc_t *doc, const char *section, + const char *key, char **out); + +bool ini_doc_set_int(ini_doc_t *doc, const char *section, const char *key, + int value); +bool ini_doc_set_bool(ini_doc_t *doc, const char *section, const char *key, + bool value); +bool ini_doc_set_string(ini_doc_t *doc, const char *section, const char *key, + const char *value); + +bool ini_doc_has_section(const ini_doc_t *doc, const char *section); +bool ini_doc_has_key(const ini_doc_t *doc, const char *section, + const char *key); +bool ini_doc_remove_section(ini_doc_t *doc, const char *section); +void ini_doc_foreach_section(const ini_doc_t *doc, const char *prefix, + ini_doc_section_fn fn, void *ctx); + +#endif diff --git a/src/lcui.c b/src/lcui.c index 869ef52d2..1e7881d41 100644 --- a/src/lcui.c +++ b/src/lcui.c @@ -18,6 +18,10 @@ #include extern void lcui_fonts_init(void); +extern void lcui_rendering_destroy(void); +extern void lcui_rendering_init(void); +extern void lcui_window_state_destroy(void); +extern void lcui_window_state_init(void); extern void lcui_widgets_init(void); extern void lcui_widgets_destroy(void); @@ -41,16 +45,19 @@ void lcui_init(void) lcui_app_init(); lcui_fonts_init(); lcui_widgets_init(); + lcui_rendering_init(); + lcui_window_state_init(); if (!lcui_settings_load()) { logger_warning( "failed to load settings, fallback to built-in defaults\n"); - lcui_reset_settings(); } } void lcui_destroy(void) { lcui_settings_unload(); + lcui_window_state_destroy(); + lcui_rendering_destroy(); lcui_widgets_destroy(); lcui_app_destroy(); } diff --git a/src/lcui_rendering.c b/src/lcui_rendering.c new file mode 100644 index 000000000..782ac2aa5 --- /dev/null +++ b/src/lcui_rendering.c @@ -0,0 +1,104 @@ +/* + * src/lcui_rendering.c -- rendering settings. + * + * Copyright (c) 2023-2025, Liu Chao + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include +#include "lcui_settings.h" +#include "setting_field.h" + +static lcui_rendering_settings_t g_rendering = { + .fps_cap = LCUI_DEFAULT_FPS_CAP, + .parallel_threads = LCUI_DEFAULT_PARALLEL_THREADS, + .paint_flashing = false +}; + +static const setting_field_def_t g_rendering_fields[] = { + DEFINE_SETTING_INT_FIELD( + lcui_rendering_settings_t, fps_cap, LCUI_DEFAULT_FPS_CAP, + LCUI_RENDERING_FPS_CAP_MIN, LCUI_RENDERING_FPS_CAP_MAX), + DEFINE_SETTING_INT_FIELD(lcui_rendering_settings_t, parallel_threads, + LCUI_DEFAULT_PARALLEL_THREADS, + LCUI_RENDERING_PARALLEL_THREADS_MIN, + LCUI_RENDERING_PARALLEL_THREADS_MAX), + DEFINE_SETTING_BOOL_FIELD(lcui_rendering_settings_t, paint_flashing, + false) +}; + +static void lcui_rendering_apply(void) +{ + ui_server_set_threads(g_rendering.parallel_threads); + ui_server_set_paint_flashing_enabled(g_rendering.paint_flashing); + lcui_set_fps_cap((unsigned)g_rendering.fps_cap); +} + +static void lcui_rendering_deserialize(ini_doc_t *doc, bool *dirty, void *data) +{ + (void)data; + setting_fields_deserialize( + doc, "rendering", g_rendering_fields, + sizeof(g_rendering_fields) / sizeof(g_rendering_fields[0]), + &g_rendering, dirty); + lcui_rendering_apply(); +} + +static void lcui_rendering_serialize(ini_doc_t *doc, void *data) +{ + (void)data; + setting_fields_serialize( + doc, "rendering", g_rendering_fields, + sizeof(g_rendering_fields) / sizeof(g_rendering_fields[0]), + &g_rendering); +} + +bool lcui_get_rendering(lcui_rendering_settings_t *out) +{ + if (!lcui_settings_is_loaded()) { + return false; + } + *out = g_rendering; + return true; +} + +bool lcui_set_rendering(const lcui_rendering_settings_t *in) +{ + if (!lcui_settings_is_loaded()) { + return false; + } + if (in->fps_cap < LCUI_RENDERING_FPS_CAP_MIN || + in->fps_cap > LCUI_RENDERING_FPS_CAP_MAX) { + return false; + } + if (in->parallel_threads < LCUI_RENDERING_PARALLEL_THREADS_MIN || + in->parallel_threads > LCUI_RENDERING_PARALLEL_THREADS_MAX) { + return false; + } + g_rendering = *in; + lcui_rendering_apply(); + lcui_settings_mark_dirty(); + return true; +} + +void lcui_rendering_init(void) +{ + lcui_settings_on_deserialize(lcui_rendering_deserialize, NULL); + lcui_settings_on_serialize(lcui_rendering_serialize, NULL); +} + +void lcui_rendering_destroy(void) +{ + lcui_settings_off_deserialize(lcui_rendering_deserialize, NULL); + lcui_settings_off_serialize(lcui_rendering_serialize, NULL); + g_rendering.fps_cap = LCUI_DEFAULT_FPS_CAP; + g_rendering.parallel_threads = LCUI_DEFAULT_PARALLEL_THREADS; + g_rendering.paint_flashing = false; +} diff --git a/src/lcui_settings.c b/src/lcui_settings.c index 656af95de..779d788af 100644 --- a/src/lcui_settings.c +++ b/src/lcui_settings.c @@ -1,5 +1,5 @@ -/* - * src/lcui_settings.c: -- global settings. +/* + * src/lcui_settings.c -- global settings infrastructure. * * Copyright (c) 2020, James Duong * Copyright (c) 2023-2025, Liu Chao @@ -13,61 +13,89 @@ #include #include -#include +#include #include #include #include +#include #ifndef _WIN32 #include #endif #ifdef _WIN32 #include -#include #else #include #include #endif -#include -#include -#include #include +#include "lcui_settings.h" #ifdef _WIN32 #define strcasecmp _stricmp #endif -typedef struct lcui_store_rendering { - int fps_cap; - int parallel_threads; - bool paint_flashing; -} lcui_store_rendering_t; +typedef struct lcui_settings_callback_entry { + void *fn; + void *data; +} lcui_settings_callback_entry_t; -static struct lcui_settings_module { - bool loaded; - bool dirty; - char *path; - lcui_store_rendering_t rendering; -} lcui_settings; +struct lcui_settings_module lcui_settings; -static const lcui_store_rendering_t lcui_default_rendering_settings = { - LCUI_DEFAULT_FPS_CAP, LCUI_DEFAULT_PARALLEL_THREADS, false -}; +static void lcui_settings_callback_entry_destroy(void *data) +{ + free(data); +} -static char *lcui_strdup(const char *str) +static bool lcui_settings_ensure_deserialize_list(void) { - size_t len; - char *copy; + if (lcui_settings.deserialize_ready) { + return true; + } + list_create(&lcui_settings.deserialize_callbacks); + lcui_settings.deserialize_ready = true; + return true; +} - if (!str) { - return NULL; +static bool lcui_settings_ensure_serialize_list(void) +{ + if (lcui_settings.serialize_ready) { + return true; } - len = strlen(str); - copy = malloc(sizeof(char) * (len + 1)); - if (!copy) { - return NULL; + list_create(&lcui_settings.serialize_callbacks); + lcui_settings.serialize_ready = true; + return true; +} + +static void lcui_settings_run_deserializers(void) +{ + list_node_t *node; + bool dirty = false; + + if (!lcui_settings.deserialize_ready || !lcui_settings.doc) { + return; + } + for (list_each(node, &lcui_settings.deserialize_callbacks)) { + lcui_settings_callback_entry_t *entry = node->data; + ((lcui_settings_deserialize_fn)entry->fn)(lcui_settings.doc, + &dirty, entry->data); + } + if (dirty) { + lcui_settings.dirty = true; + } +} + +static void lcui_settings_run_serializers(void) +{ + list_node_t *node; + + if (!lcui_settings.serialize_ready || !lcui_settings.doc) { + return; + } + for (list_each(node, &lcui_settings.serialize_callbacks)) { + lcui_settings_callback_entry_t *entry = node->data; + ((lcui_settings_serialize_fn)entry->fn)(lcui_settings.doc, + entry->data); } - strcpy(copy, str); - return copy; } static int lcui_mkdir(const char *path) @@ -85,11 +113,8 @@ static bool lcui_mkdir_recursive(const char *path) char ch; char *buffer; - if (!path || path[0] == 0) { - return false; - } len = strlen(path); - buffer = lcui_strdup(path); + buffer = strdup2(path); if (!buffer) { return false; } @@ -133,9 +158,6 @@ static char *lcui_join_path(const char *left, const char *right) size_t left_len, right_len; char *path; - if (!left || !right) { - return NULL; - } left_len = strlen(left); right_len = strlen(right); path = malloc(sizeof(char) * (left_len + right_len + 2)); @@ -157,7 +179,7 @@ static char *lcui_settings_get_config_root(void) #ifdef _WIN32 const char *base = getenv("APPDATA"); if (base && base[0] != 0) { - return lcui_strdup(base); + return strdup2(base); } base = getenv("USERPROFILE"); if (base && base[0] != 0) { @@ -171,7 +193,7 @@ static char *lcui_settings_get_config_root(void) #else const char *base = getenv("XDG_CONFIG_HOME"); if (base && base[0] != 0) { - return lcui_strdup(base); + return strdup2(base); } base = getenv("HOME"); if (base && base[0] != 0) { @@ -211,223 +233,123 @@ static bool lcui_settings_resolve_path(char **out_path) return true; } -static char *lcui_store_trim(char *str) +bool lcui_settings_on_deserialize(lcui_settings_deserialize_fn fn, void *data) { - size_t len; + lcui_settings_callback_entry_t *entry; + list_node_t *node; - while (*str && isspace((unsigned char)*str)) { - ++str; - } - len = strlen(str); - while (len > 0 && isspace((unsigned char)str[len - 1])) { - str[--len] = 0; - } - return str; -} - -static bool lcui_store_parse_int(const char *str, int *out) -{ - long value; - char *endptr; - - if (!str || !out) { + if (!lcui_settings_ensure_deserialize_list()) { return false; } - errno = 0; - value = strtol(str, &endptr, 10); - if (errno != 0 || endptr == str || *endptr != 0 || value > INT_MAX || - value < INT_MIN) { + for (list_each(node, &lcui_settings.deserialize_callbacks)) { + entry = node->data; + if (entry->fn == (void *)fn) { + return true; + } + } + entry = malloc(sizeof(*entry)); + if (!entry) { return false; } - *out = (int)value; + entry->fn = (void *)fn; + entry->data = data; + list_append(&lcui_settings.deserialize_callbacks, entry); return true; } -static bool lcui_store_parse_bool(const char *str, bool *out) +int lcui_settings_off_deserialize(lcui_settings_deserialize_fn fn, void *data) { - if (!str || !out) { - return false; - } - if (strcmp(str, "1") == 0 || strcasecmp(str, "true") == 0) { - *out = true; - return true; - } - if (strcmp(str, "0") == 0 || strcasecmp(str, "false") == 0) { - *out = false; - return true; + int count = 0; + list_node_t *node, *next; + + if (!lcui_settings.deserialize_ready) { + return 0; + } + for (node = lcui_settings.deserialize_callbacks.head.next; node; + node = next) { + next = node->next; + { + lcui_settings_callback_entry_t *entry = node->data; + if (entry->fn == (void *)fn) { + list_delete_node( + &lcui_settings.deserialize_callbacks, node); + lcui_settings_callback_entry_destroy(entry); + ++count; + } + } } - return false; + return count; } -static bool lcui_store_load(const char *path, lcui_store_rendering_t *settings, - bool *dirty, bool *exists) +bool lcui_settings_on_serialize(lcui_settings_serialize_fn fn, void *data) { - int value; - bool flag; - bool has_version = false; - char line[1024]; - char section[64] = { 0 }; - FILE *fp = fopen(path, "r"); + lcui_settings_callback_entry_t *entry; + list_node_t *node; - if (!fp) { - if (errno == ENOENT) { - *exists = false; - return true; - } + if (!lcui_settings_ensure_serialize_list()) { return false; } - *exists = true; - while (fgets(line, sizeof(line), fp)) { - char *data = lcui_store_trim(line); - char *equal; - - if (data[0] == 0 || data[0] == ';' || data[0] == '#') { - continue; - } - if (data[0] == '[') { - char *end = strchr(data, ']'); - if (!end) { - continue; - } - *end = 0; - snprintf(section, sizeof(section), "%s", data + 1); - continue; - } - equal = strchr(data, '='); - if (!equal) { - continue; - } - *equal++ = 0; - data = lcui_store_trim(data); - equal = lcui_store_trim(equal); - if (strcasecmp(section, "meta") == 0 && - strcasecmp(data, "version") == 0) { - has_version = true; - if (!lcui_store_parse_int(equal, &value) || - value != 1) { - *dirty = true; - } - continue; - } - if (strcasecmp(section, "rendering") != 0) { - continue; - } - if (strcasecmp(data, "fps_cap") == 0) { - if (lcui_store_parse_int(equal, &value)) { - settings->fps_cap = value; - } else { - *dirty = true; - } - continue; - } - if (strcasecmp(data, "parallel_threads") == 0) { - if (lcui_store_parse_int(equal, &value)) { - settings->parallel_threads = value; - } else { - *dirty = true; - } - continue; - } - if (strcasecmp(data, "paint_flashing") == 0) { - if (lcui_store_parse_bool(equal, &flag)) { - settings->paint_flashing = flag; - } else { - *dirty = true; - } + for (list_each(node, &lcui_settings.serialize_callbacks)) { + entry = node->data; + if (entry->fn == (void *)fn) { + return true; } } - fclose(fp); - if (!has_version) { - *dirty = true; + entry = malloc(sizeof(*entry)); + if (!entry) { + return false; } + entry->fn = (void *)fn; + entry->data = data; + list_append(&lcui_settings.serialize_callbacks, entry); return true; } -static bool lcui_store_save(const char *path, - const lcui_store_rendering_t *settings) +int lcui_settings_off_serialize(lcui_settings_serialize_fn fn, void *data) { - size_t path_len; - char *tmp_path; - FILE *fp; - int ret; - - path_len = strlen(path); - tmp_path = malloc(sizeof(char) * (path_len + 5)); - if (!tmp_path) { - return false; - } - strcpy(tmp_path, path); - strcat(tmp_path, ".tmp"); - fp = fopen(tmp_path, "w"); - if (!fp) { - free(tmp_path); - return false; + int count = 0; + list_node_t *node, *next; + + if (!lcui_settings.serialize_ready) { + return 0; + } + for (node = lcui_settings.serialize_callbacks.head.next; node; + node = next) { + next = node->next; + { + lcui_settings_callback_entry_t *entry = node->data; + if (entry->fn == (void *)fn) { + list_delete_node( + &lcui_settings.serialize_callbacks, node); + lcui_settings_callback_entry_destroy(entry); + ++count; + } + } } - fprintf(fp, "[meta]\nversion=1\n\n"); - fprintf(fp, "[rendering]\n"); - fprintf(fp, "fps_cap=%d\n", settings->fps_cap); - fprintf(fp, "parallel_threads=%d\n", settings->parallel_threads); - fprintf(fp, "paint_flashing=%d\n", settings->paint_flashing ? 1 : 0); - fclose(fp); -#ifdef _WIN32 - ret = MoveFileExA(tmp_path, path, - MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) - ? 0 - : -1; -#else - ret = rename(tmp_path, path); -#endif - free(tmp_path); - return ret == 0; + return count; } -static bool lcui_settings_repair_rendering(lcui_store_rendering_t *settings) +ini_doc_t *lcui_settings_get_doc(void) { - bool valid = true; - - if (settings->fps_cap < LCUI_RENDERING_FPS_CAP_MIN || - settings->fps_cap > LCUI_RENDERING_FPS_CAP_MAX) { - settings->fps_cap = lcui_default_rendering_settings.fps_cap; - valid = false; - } - if (settings->parallel_threads < LCUI_RENDERING_PARALLEL_THREADS_MIN || - settings->parallel_threads > LCUI_RENDERING_PARALLEL_THREADS_MAX) { - settings->parallel_threads = - lcui_default_rendering_settings.parallel_threads; - valid = false; - } - return valid; + return lcui_settings.doc; } -static bool lcui_settings_validate_rendering( - const lcui_rendering_settings_t *settings) +void lcui_settings_mark_dirty(void) { - if (!settings) { - return false; - } - if (settings->fps_cap < LCUI_RENDERING_FPS_CAP_MIN || - settings->fps_cap > LCUI_RENDERING_FPS_CAP_MAX) { - return false; - } - if (settings->parallel_threads < LCUI_RENDERING_PARALLEL_THREADS_MIN || - settings->parallel_threads > LCUI_RENDERING_PARALLEL_THREADS_MAX) { - return false; - } - return true; + lcui_settings.dirty = true; } -static void lcui_settings_apply_rendering(void) +bool lcui_settings_is_loaded(void) { - ui_server_set_threads(lcui_settings.rendering.parallel_threads); - ui_server_set_paint_flashing_enabled( - lcui_settings.rendering.paint_flashing); - lcui_set_fps_cap((unsigned)lcui_settings.rendering.fps_cap); + return lcui_settings.loaded; } bool lcui_settings_load(void) { - bool exists = false; + bool has_version = false; char *path; + ini_doc_t *doc; + int version = 0; if (lcui_settings.loaded) { return true; @@ -435,20 +357,25 @@ bool lcui_settings_load(void) if (!lcui_settings_resolve_path(&path)) { return false; } - lcui_settings.rendering = lcui_default_rendering_settings; - lcui_settings.dirty = false; - if (!lcui_store_load(path, &lcui_settings.rendering, - &lcui_settings.dirty, &exists)) { + doc = ini_doc_load(path); + if (!doc) { free(path); return false; } - if (!exists || - !lcui_settings_repair_rendering(&lcui_settings.rendering)) { + if (ini_doc_get_int(doc, "meta", "version", &version)) { + has_version = (version == 1); + } + if (!has_version) { + ini_doc_set_int(doc, "meta", "version", 1); lcui_settings.dirty = true; } - lcui_settings.loaded = true; + lcui_settings.doc = doc; lcui_settings.path = path; - lcui_settings_apply_rendering(); + lcui_settings.loaded = true; + lcui_settings_run_deserializers(); + if (!has_version) { + lcui_settings.dirty = true; + } return true; } @@ -460,7 +387,11 @@ bool lcui_settings_flush(void) if (!lcui_settings.dirty) { return true; } - if (!lcui_store_save(lcui_settings.path, &lcui_settings.rendering)) { + if (!lcui_settings.doc) { + return false; + } + lcui_settings_run_serializers(); + if (!ini_doc_save(lcui_settings.doc, lcui_settings.path)) { return false; } lcui_settings.dirty = false; @@ -469,97 +400,12 @@ bool lcui_settings_flush(void) void lcui_settings_unload(void) { + if (lcui_settings.doc) { + ini_doc_destroy(lcui_settings.doc); + lcui_settings.doc = NULL; + } free(lcui_settings.path); lcui_settings.path = NULL; lcui_settings.loaded = false; lcui_settings.dirty = false; - lcui_settings.rendering = lcui_default_rendering_settings; -} - -bool lcui_settings_get_rendering(lcui_rendering_settings_t *out) -{ - if (!lcui_settings.loaded || !out) { - return false; - } - out->fps_cap = lcui_settings.rendering.fps_cap; - out->parallel_threads = lcui_settings.rendering.parallel_threads; - out->paint_flashing = lcui_settings.rendering.paint_flashing; - return true; -} - -bool lcui_settings_set_rendering(const lcui_rendering_settings_t *in) -{ - if (!lcui_settings.loaded || !in || - !lcui_settings_validate_rendering(in)) { - return false; - } - if (lcui_settings.rendering.fps_cap == in->fps_cap && - lcui_settings.rendering.parallel_threads == in->parallel_threads && - lcui_settings.rendering.paint_flashing == in->paint_flashing) { - return true; - } - lcui_settings.rendering.fps_cap = in->fps_cap; - lcui_settings.rendering.parallel_threads = in->parallel_threads; - lcui_settings.rendering.paint_flashing = in->paint_flashing; - lcui_settings_apply_rendering(); - lcui_settings.dirty = true; - return true; -} - -/* Initialize settings with the current global settings. */ -void lcui_get_settings(lcui_settings_t *settings) -{ - if (!settings) { - return; - } - settings->fps_cap = lcui_settings.rendering.fps_cap; - settings->parallel_rendering_threads = - lcui_settings.rendering.parallel_threads; - settings->paint_flashing = lcui_settings.rendering.paint_flashing; -} - -/* Update global settings with the given input. */ -void lcui_apply_settings(lcui_settings_t *settings) -{ - lcui_rendering_settings_t rendering; - - if (!settings) { - return; - } - rendering.fps_cap = settings->fps_cap; - rendering.parallel_threads = settings->parallel_rendering_threads; - rendering.paint_flashing = settings->paint_flashing; - if (!lcui_settings_validate_rendering(&rendering)) { - lcui_store_rendering_t repaired = { rendering.fps_cap, - rendering.parallel_threads, - rendering.paint_flashing }; - lcui_settings_repair_rendering(&repaired); - rendering.fps_cap = repaired.fps_cap; - rendering.parallel_threads = repaired.parallel_threads; - } - if (lcui_settings.loaded) { - (void)lcui_settings_set_rendering(&rendering); - return; - } - lcui_settings.rendering.fps_cap = rendering.fps_cap; - lcui_settings.rendering.parallel_threads = rendering.parallel_threads; - lcui_settings.rendering.paint_flashing = rendering.paint_flashing; - lcui_settings_apply_rendering(); -} - -/* Reset global settings to their defaults. */ -void lcui_reset_settings(void) -{ - lcui_rendering_settings_t settings = { - lcui_default_rendering_settings.fps_cap, - lcui_default_rendering_settings.parallel_threads, - lcui_default_rendering_settings.paint_flashing - }; - - if (lcui_settings.loaded) { - (void)lcui_settings_set_rendering(&settings); - return; - } - lcui_settings.rendering = lcui_default_rendering_settings; - lcui_settings_apply_rendering(); } diff --git a/src/lcui_settings.h b/src/lcui_settings.h new file mode 100644 index 000000000..c852650eb --- /dev/null +++ b/src/lcui_settings.h @@ -0,0 +1,45 @@ +/* + * src/lcui_settings.h -- internal definitions for settings infrastructure. + * + * Copyright (c) 2023-2025, Liu Chao + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#ifndef LCUI_SRC_SETTINGS_H +#define LCUI_SRC_SETTINGS_H + +#include +#include +#include +#include "ini_doc.h" + +typedef void (*lcui_settings_deserialize_fn)(ini_doc_t *doc, bool *dirty, + void *data); +typedef void (*lcui_settings_serialize_fn)(ini_doc_t *doc, void *data); + +struct lcui_settings_module { + bool loaded; + bool dirty; + bool deserialize_ready; + bool serialize_ready; + char *path; + ini_doc_t *doc; + list_t deserialize_callbacks; + list_t serialize_callbacks; +}; + +extern struct lcui_settings_module lcui_settings; + +bool lcui_settings_on_deserialize(lcui_settings_deserialize_fn fn, void *data); +int lcui_settings_off_deserialize(lcui_settings_deserialize_fn fn, void *data); +bool lcui_settings_on_serialize(lcui_settings_serialize_fn fn, void *data); +int lcui_settings_off_serialize(lcui_settings_serialize_fn fn, void *data); +ini_doc_t *lcui_settings_get_doc(void); +void lcui_settings_mark_dirty(void); + +#endif diff --git a/src/lcui_window_state.c b/src/lcui_window_state.c new file mode 100644 index 000000000..43fc4e434 --- /dev/null +++ b/src/lcui_window_state.c @@ -0,0 +1,499 @@ +/* + * src/lcui_window_state.c -- window state settings. + * + * Copyright (c) 2023-2025, Liu Chao + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include "lcui_settings.h" +#include +#include +#include +#include +#include +#include +#include "setting_field.h" + +typedef struct wstate_binding { + ui_widget_t *widget; + ptk_window_t *window; + char *id; + lcui_window_state_t state; + bool has_state; +} wstate_binding_t; + +typedef struct wstate_entry { + char *id; + lcui_window_state_t state; +} wstate_entry_t; + +static struct wstate_module { + bool listeners_active; + list_t entries; + list_t bindings; +} window_state; + +static void wstate_on_widget_destroy(ui_widget_t *widget, ui_event_t *e, + void *arg); +static void wstate_binding_remove(wstate_binding_t *b); + +static wstate_binding_t *wstate_find_binding_by_widget(ui_widget_t *widget) +{ + list_node_t *node; + + for (list_each(node, &window_state.bindings)) { + wstate_binding_t *b = node->data; + if (b->widget == widget) { + return b; + } + } + return NULL; +} + +static wstate_binding_t *wstate_find_binding_by_window(ptk_window_t *window) +{ + list_node_t *node; + + for (list_each(node, &window_state.bindings)) { + wstate_binding_t *b = node->data; + if (b->window == window) { + return b; + } + } + return NULL; +} + +static wstate_binding_t *wstate_find_binding_by_id(const char *id) +{ + list_node_t *node; + + for (list_each(node, &window_state.bindings)) { + wstate_binding_t *b = node->data; + if (b->id && strcmp(b->id, id) == 0) { + return b; + } + } + return NULL; +} + +static bool wstate_id_is_valid(const char *id) +{ + const unsigned char *p; + + if (id[0] == 0) { + return false; + } + for (p = (const unsigned char *)id; *p; ++p) { + if (isalnum(*p) || *p == '.' || *p == '_' || *p == '-') { + continue; + } + return false; + } + return true; +} + +static bool wstate_validate(const lcui_window_state_t *state) +{ + if (state->width < LCUI_WINDOW_STATE_SIZE_MIN || + state->width > LCUI_WINDOW_STATE_SIZE_MAX) { + return false; + } + if (state->height < LCUI_WINDOW_STATE_SIZE_MIN || + state->height > LCUI_WINDOW_STATE_SIZE_MAX) { + return false; + } + return true; +} + +static bool wstate_equals(const lcui_window_state_t *a, + const lcui_window_state_t *b) +{ + return a->x == b->x && a->y == b->y && a->width == b->width && + a->height == b->height && a->maximized == b->maximized; +} + +static void wstate_entry_destroy(void *data) +{ + wstate_entry_t *entry = data; + + free(entry->id); + free(entry); +} + +static void wstate_binding_destroy(void *data) +{ + wstate_binding_t *binding = data; + + free(binding->id); + free(binding); +} + +static wstate_entry_t *wstate_find_entry(const char *id) +{ + list_node_t *node; + + for (list_each(node, &window_state.entries)) { + wstate_entry_t *entry = node->data; + if (strcmp(entry->id, id) == 0) { + return entry; + } + } + return NULL; +} + +static bool wstate_set_entry(const char *id, const lcui_window_state_t *state) +{ + wstate_entry_t *entry; + + entry = wstate_find_entry(id); + if (entry) { + entry->state = *state; + return true; + } + entry = malloc(sizeof(*entry)); + if (!entry) { + return false; + } + entry->id = strdup2(id); + if (!entry->id) { + free(entry); + return false; + } + entry->state = *state; + list_append(&window_state.entries, entry); + return true; +} + +static bool wstate_query(ptk_window_t *window, lcui_window_state_t *out) +{ + ptk_window_get_position(window, &out->x, &out->y); + out->width = ptk_window_get_width(window); + out->height = ptk_window_get_height(window); + out->maximized = ptk_window_is_maximized(window); + return wstate_validate(out); +} + +static bool wstate_apply(ptk_window_t *window, const lcui_window_state_t *state) +{ + if (!wstate_validate(state)) { + return false; + } + ptk_window_set_position(window, state->x, state->y); + ptk_window_set_size(window, state->width, state->height); + ptk_window_set_maximized(window, state->maximized); + return true; +} + +static void wstate_binding_sync(wstate_binding_t *binding) +{ + if (!binding->window) { + return; + } + if (!wstate_query(binding->window, &binding->state)) { + return; + } + binding->has_state = true; + if (wstate_set_entry(binding->id, &binding->state)) { + lcui_settings_mark_dirty(); + } + lcui_settings_flush(); +} + +static void wstate_binding_remove(wstate_binding_t *b) +{ + list_node_t *node; + + for (list_each(node, &window_state.bindings)) { + if (node->data == b) { + list_delete_node(&window_state.bindings, node); + break; + } + } + if (b->widget) { + ui_widget_off(b->widget, "destroy", wstate_on_widget_destroy, + NULL); + } + wstate_binding_destroy(b); +} + +static void wstate_on_widget_destroy(ui_widget_t *widget, ui_event_t *e, + void *arg) +{ + wstate_binding_t *b; + + (void)e; + (void)arg; + b = wstate_find_binding_by_widget(widget); + if (b) { + wstate_binding_remove(b); + } +} + +static void wstate_on_window_create(ptk_event_t *e, void *arg) +{ + wstate_binding_t *b; + ui_widget_t *widget; + + (void)arg; + if (!e->window) { + return; + } + widget = ui_server_get_widget(e->window); + b = wstate_find_binding_by_widget(widget); + if (!b) { + return; + } + b->window = e->window; + if (b->has_state) { + wstate_apply(e->window, &b->state); + } +} + +static void wstate_on_window_close(ptk_event_t *e, void *arg) +{ + wstate_binding_t *b; + + (void)arg; + if (!e->window) { + return; + } + b = wstate_find_binding_by_window(e->window); + if (!b) { + return; + } + wstate_binding_sync(b); + b->window = NULL; +} + +static void wstate_attach_listeners(void) +{ + if (window_state.listeners_active) { + return; + } + ptk_on_event(PTK_EVENT_CREATE, wstate_on_window_create, NULL); + ptk_on_event(PTK_EVENT_CLOSE, wstate_on_window_close, NULL); + window_state.listeners_active = true; +} + +static void wstate_detach_listeners(void) +{ + if (!window_state.listeners_active) { + return; + } + ptk_off_event(PTK_EVENT_CREATE, wstate_on_window_create); + ptk_off_event(PTK_EVENT_CLOSE, wstate_on_window_close); + window_state.listeners_active = false; +} + +static void wstate_serialize_window_sections(const char *id, void *ctx) +{ + char section[256]; + ini_doc_t *doc = (ini_doc_t *)ctx; + wstate_entry_t *entry = wstate_find_entry(id); + + if (!entry) { + return; + } + snprintf(section, sizeof(section), "window.%s", id); + ini_doc_set_int(doc, section, "x", entry->state.x); + ini_doc_set_int(doc, section, "y", entry->state.y); + ini_doc_set_int(doc, section, "width", entry->state.width); + ini_doc_set_int(doc, section, "height", entry->state.height); + ini_doc_set_bool(doc, section, "maximized", entry->state.maximized); +} + +typedef struct wstate_deserialize_ctx { + bool *dirty; + char **invalid_sections; + size_t invalid_count; + size_t invalid_capacity; +} wstate_deserialize_ctx_t; + +static bool wstate_add_invalid(wstate_deserialize_ctx_t *c, const char *section) +{ + char **new_arr; + char *copy; + + if (c->invalid_count >= c->invalid_capacity) { + size_t new_cap = + c->invalid_capacity ? c->invalid_capacity * 2 : 4; + + new_arr = + realloc(c->invalid_sections, new_cap * sizeof(char *)); + if (!new_arr) { + return false; + } + c->invalid_sections = new_arr; + c->invalid_capacity = new_cap; + } + copy = strdup2(section); + if (!copy) { + return false; + } + c->invalid_sections[c->invalid_count++] = copy; + return true; +} + +static bool wstate_on_section(const char *suffix, void *ctx) +{ + wstate_deserialize_ctx_t *c = (wstate_deserialize_ctx_t *)ctx; + lcui_window_state_t state = { 0 }; + ini_doc_t *doc = lcui_settings_get_doc(); + char section[256]; + + if (!wstate_id_is_valid(suffix)) { + *c->dirty = true; + snprintf(section, sizeof(section), "window.%s", suffix); + wstate_add_invalid(c, section); + return true; + } + snprintf(section, sizeof(section), "window.%s", suffix); + if (!ini_doc_get_int(doc, section, "x", &state.x) || + !ini_doc_get_int(doc, section, "y", &state.y) || + !ini_doc_get_int(doc, section, "width", &state.width) || + !ini_doc_get_int(doc, section, "height", &state.height) || + !ini_doc_get_bool(doc, section, "maximized", &state.maximized)) { + *c->dirty = true; + wstate_add_invalid(c, section); + return true; + } + if (!wstate_validate(&state)) { + *c->dirty = true; + wstate_add_invalid(c, section); + return true; + } + if (!wstate_set_entry(suffix, &state)) { + return true; + } + return true; +} + +static void wstate_deserialize(ini_doc_t *doc, bool *dirty, void *data) +{ + size_t i; + wstate_deserialize_ctx_t ctx = { dirty, NULL, 0, 0 }; + + (void)data; + list_destroy(&window_state.entries, wstate_entry_destroy); + list_create(&window_state.entries); + ini_doc_foreach_section(doc, "window.", wstate_on_section, &ctx); + for (i = 0; i < ctx.invalid_count; ++i) { + ini_doc_remove_section(doc, ctx.invalid_sections[i]); + free(ctx.invalid_sections[i]); + } + free(ctx.invalid_sections); +} + +static void wstate_serialize(ini_doc_t *doc, void *data) +{ + list_node_t *node; + + (void)data; + for (list_each(node, &window_state.entries)) { + wstate_entry_t *entry = node->data; + + wstate_serialize_window_sections(entry->id, doc); + } +} + +bool lcui_get_window_state(const char *id, lcui_window_state_t *out) +{ + wstate_entry_t *entry; + + if (!lcui_settings_is_loaded() || !wstate_id_is_valid(id)) { + return false; + } + entry = wstate_find_entry(id); + if (!entry) { + return false; + } + *out = entry->state; + return true; +} + +bool lcui_set_window_state(const char *id, const lcui_window_state_t *in) +{ + wstate_entry_t *entry; + + if (!lcui_settings_is_loaded() || !wstate_id_is_valid(id) || + !wstate_validate(in)) { + return false; + } + entry = wstate_find_entry(id); + if (entry && wstate_equals(&entry->state, in)) { + return true; + } + if (!wstate_set_entry(id, in)) { + return false; + } + lcui_settings_mark_dirty(); + return true; +} + +bool lcui_bind_window_state(ui_widget_t *widget, const char *id) +{ + wstate_binding_t *binding; + ptk_window_t *window; + lcui_window_state_t state; + + if (!lcui_settings_is_loaded() || !wstate_id_is_valid(id)) { + return false; + } + binding = wstate_find_binding_by_widget(widget); + if (binding) { + return strcmp(binding->id, id) == 0; + } + if (wstate_find_binding_by_id(id)) { + return false; + } + binding = calloc(1, sizeof(*binding)); + if (!binding) { + return false; + } + binding->id = strdup2(id); + if (!binding->id) { + free(binding); + return false; + } + binding->widget = widget; + list_append(&window_state.bindings, binding); + ui_widget_on(widget, "destroy", wstate_on_widget_destroy, NULL); + wstate_attach_listeners(); + if (lcui_get_window_state(id, &state)) { + binding->state = state; + binding->has_state = true; + ui_widget_resize(widget, (float)state.width, + (float)state.height); + } + window = ui_server_get_window(widget); + if (window) { + binding->window = window; + if (binding->has_state) { + wstate_apply(window, &binding->state); + } + } + return true; +} + +void lcui_window_state_init(void) +{ + list_create(&window_state.entries); + list_create(&window_state.bindings); + lcui_settings_on_deserialize(wstate_deserialize, NULL); + lcui_settings_on_serialize(wstate_serialize, NULL); +} + +void lcui_window_state_destroy(void) +{ + wstate_detach_listeners(); + lcui_settings_off_deserialize(wstate_deserialize, NULL); + lcui_settings_off_serialize(wstate_serialize, NULL); + list_destroy(&window_state.bindings, wstate_binding_destroy); + list_destroy(&window_state.entries, wstate_entry_destroy); + window_state.listeners_active = false; +} diff --git a/src/setting_field.c b/src/setting_field.c new file mode 100644 index 000000000..12b1f4e5e --- /dev/null +++ b/src/setting_field.c @@ -0,0 +1,88 @@ +/* + * src/setting_field.c -- schema-driven (de)serialization. + * + * Copyright (c) 2023-2025, Liu Chao + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include + +#include "setting_field.h" + +bool setting_fields_deserialize(ini_doc_t *doc, const char *section, + const setting_field_def_t *fields, + size_t field_count, void *out, bool *dirty) +{ + size_t i; + unsigned char *base = (unsigned char *)out; + + for (i = 0; i < field_count; ++i) { + const setting_field_def_t *f = &fields[i]; + + if (f->type == SETTING_FIELD_TYPE_INT) { + int value; + + if (!ini_doc_get_int(doc, section, f->name, &value)) { + int def = f->int_default; + + memcpy(base + f->offset, &def, sizeof(def)); + *dirty = true; + continue; + } + if (value < f->int_min || value > f->int_max) { + int def = f->int_default; + + memcpy(base + f->offset, &def, sizeof(def)); + *dirty = true; + continue; + } + memcpy(base + f->offset, &value, sizeof(value)); + } else if (f->type == SETTING_FIELD_TYPE_BOOL) { + bool value; + + if (!ini_doc_get_bool(doc, section, f->name, &value)) { + memcpy(base + f->offset, &f->bool_default, + sizeof(f->bool_default)); + *dirty = true; + continue; + } + memcpy(base + f->offset, &value, sizeof(value)); + } + } + return true; +} + +bool setting_fields_serialize(ini_doc_t *doc, const char *section, + const setting_field_def_t *fields, + size_t field_count, const void *src) +{ + size_t i; + const unsigned char *base = (const unsigned char *)src; + + for (i = 0; i < field_count; ++i) { + const setting_field_def_t *f = &fields[i]; + + if (f->type == SETTING_FIELD_TYPE_INT) { + int value; + + memcpy(&value, base + f->offset, sizeof(value)); + if (!ini_doc_set_int(doc, section, f->name, value)) { + return false; + } + } else if (f->type == SETTING_FIELD_TYPE_BOOL) { + bool value; + + memcpy(&value, base + f->offset, sizeof(value)); + if (!ini_doc_set_bool(doc, section, f->name, value)) { + return false; + } + } + } + return true; +} diff --git a/src/setting_field.h b/src/setting_field.h new file mode 100644 index 000000000..711c39b6a --- /dev/null +++ b/src/setting_field.h @@ -0,0 +1,63 @@ +/* + * src/setting_field.h -- schema-driven field definitions for settings. + * + * Copyright (c) 2023-2025, Liu Chao + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#ifndef LCUI_SRC_SETTING_FIELD_H +#define LCUI_SRC_SETTING_FIELD_H + +#include +#include +#include "ini_doc.h" + +typedef enum { + SETTING_FIELD_TYPE_INT, + SETTING_FIELD_TYPE_BOOL +} setting_field_type_t; + +typedef struct setting_field_def { + const char *name; + setting_field_type_t type; + size_t offset; + int int_default; + int int_min; + int int_max; + bool bool_default; +} setting_field_def_t; + +#define DEFINE_SETTING_INT_FIELD(struct_type, name, def, min, max) \ + { #name, \ + SETTING_FIELD_TYPE_INT, \ + offsetof(struct_type, name), \ + (def), \ + (min), \ + (max), \ + false } + +#define DEFINE_SETTING_BOOL_FIELD(struct_type, name, def) \ + { \ + #name, \ + SETTING_FIELD_TYPE_BOOL, \ + offsetof(struct_type, name), \ + 0, \ + 0, \ + 0, \ + (def) \ + } + +bool setting_fields_deserialize(ini_doc_t *doc, const char *section, + const setting_field_def_t *fields, + size_t field_count, void *out, bool *dirty); + +bool setting_fields_serialize(ini_doc_t *doc, const char *section, + const setting_field_def_t *fields, + size_t field_count, const void *src); + +#endif diff --git a/tests/integration/test_settings.c b/tests/integration/test_settings.c index 0658b62c9..c8eed8100 100644 --- a/tests/integration/test_settings.c +++ b/tests/integration/test_settings.c @@ -133,6 +133,29 @@ static bool test_read_file_contains(const char *base_dir, const char *app_id, return found; } +static void helper_process_window_events(unsigned rounds) +{ + unsigned i; + + for (i = 0; i < rounds; ++i) { + ptk_process_native_events(PTK_PROCESS_EVENTS_ALL_IF_PRESENT); + sleep_ms(10); + } +} + +static bool helper_query_window_state(ptk_window_t *window, + lcui_window_state_t *out) +{ + if (!window || !out) { + return false; + } + ptk_window_get_position(window, &out->x, &out->y); + out->width = ptk_window_get_width(window); + out->height = ptk_window_get_height(window); + out->maximized = ptk_window_is_maximized(window); + return true; +} + static void test_settings_rendering_accessors(void) { char base_dir[256]; @@ -145,7 +168,7 @@ static void test_settings_rendering_accessors(void) lcui_init(); ctest_equal_bool("should load settings", lcui_settings_load(), true); ctest_equal_bool("should get default rendering settings", - lcui_settings_get_rendering(&settings), true); + lcui_get_rendering(&settings), true); ctest_equal_int("should default frame rate cap to 120", settings.fps_cap, LCUI_DEFAULT_FPS_CAP); ctest_equal_int("should default parallel rendering threads to 4", @@ -158,12 +181,12 @@ static void test_settings_rendering_accessors(void) settings.parallel_threads = 8; settings.paint_flashing = true; ctest_equal_bool("should set rendering settings", - lcui_settings_set_rendering(&settings), true); + lcui_set_rendering(&settings), true); settings.fps_cap = 0; settings.parallel_threads = 0; settings.paint_flashing = false; ctest_equal_bool("should get updated rendering settings", - lcui_settings_get_rendering(&settings), true); + lcui_get_rendering(&settings), true); ctest_equal_int("should apply frame rate cap", settings.fps_cap, 240); ctest_equal_int("should apply parallel rendering threads", settings.parallel_threads, 8); @@ -172,9 +195,9 @@ static void test_settings_rendering_accessors(void) settings.fps_cap = 20; ctest_equal_bool("should reject out-of-range frame rate cap", - lcui_settings_set_rendering(&settings), false); + lcui_set_rendering(&settings), false); ctest_equal_bool("should keep current rendering settings", - lcui_settings_get_rendering(&settings), true); + lcui_get_rendering(&settings), true); ctest_equal_int("should keep previous frame rate cap", settings.fps_cap, 240); lcui_destroy(); @@ -201,7 +224,7 @@ static void test_settings_load_merge_validate_flush(void) lcui_init(); ctest_equal_bool("should load settings", lcui_settings_load(), true); ctest_equal_bool("should get merged rendering settings", - lcui_settings_get_rendering(&settings), true); + lcui_get_rendering(&settings), true); ctest_equal_int("should fallback fps_cap to default on invalid value", settings.fps_cap, LCUI_DEFAULT_FPS_CAP); ctest_equal_int("should keep valid parallel_threads", @@ -238,7 +261,7 @@ static void test_settings_load_merge_validate_flush(void) ctest_equal_bool("should reload valid rendering settings", lcui_settings_load(), true); ctest_equal_bool("should get rendering settings after reload", - lcui_settings_get_rendering(&settings), true); + lcui_get_rendering(&settings), true); ctest_equal_int("should parse fps_cap from user config", settings.fps_cap, 60); ctest_equal_int("should parse parallel_threads from user config", @@ -248,10 +271,154 @@ static void test_settings_load_merge_validate_flush(void) lcui_destroy(); } +static void test_window_state_accessors(void) +{ + char base_dir[256]; + lcui_window_state_t state; + lcui_window_state_t output; + + ctest_equal_bool( + "prepare window state test env", + test_prepare_env(base_dir, sizeof(base_dir), "lcui-window-state"), + true); + lcui_init(); + state.x = -120; + state.y = 48; + state.width = 640; + state.height = 480; + state.maximized = true; + ctest_equal_bool("should reject missing window state section", + lcui_get_window_state("main", &output), false); + ctest_equal_bool("should reject invalid window state id", + lcui_set_window_state("", &state), false); + ctest_equal_bool("should set window state", + lcui_set_window_state("main", &state), true); + memset(&output, 0, sizeof(output)); + ctest_equal_bool("should get window state", + lcui_get_window_state("main", &output), true); + ctest_equal_int("should round-trip window x", output.x, state.x); + ctest_equal_int("should round-trip window y", output.y, state.y); + ctest_equal_int("should round-trip window width", output.width, + state.width); + ctest_equal_int("should round-trip window height", output.height, + state.height); + ctest_equal_bool("should round-trip maximized flag", output.maximized, + state.maximized); + lcui_destroy(); +} + +static void test_window_state_invalid_values(void) +{ + const char *app_id = "lcui-window-invalid"; + char base_dir[256]; + lcui_window_state_t state; + + ctest_equal_bool("prepare invalid window state env", + test_prepare_env(base_dir, sizeof(base_dir), app_id), + true); + ctest_equal_bool("write invalid window state config", + test_write_config(base_dir, app_id, + "[meta]\nversion=1\n\n" + "[window.main]\n" + "x=-10\n" + "y=20\n" + "width=0\n" + "height=240\n" + "maximized=maybe\n"), + true); + lcui_init(); + ctest_equal_bool("should load settings with invalid window state", + lcui_settings_load(), true); + ctest_equal_bool("should reject invalid window state values", + lcui_get_window_state("main", &state), false); + ctest_equal_bool("should flush invalid window state removal", + lcui_settings_flush(), true); + ctest_equal_bool( + "should remove invalid window section on flush", + test_read_file_contains(base_dir, app_id, "[window.main]"), false); + lcui_destroy(); +} + +static void test_window_state_binding(void) +{ + const char *app_id = "lcui-window-bind"; + char base_dir[256]; + int new_width, new_height; + lcui_window_state_t saved; + lcui_window_state_t actual; + ui_widget_t *preview_widget; + ui_widget_t *widget; + ptk_window_t *window; + + ctest_equal_bool("prepare window binding env", + test_prepare_env(base_dir, sizeof(base_dir), app_id), + true); + ctest_equal_bool("write stored window state", + test_write_config(base_dir, app_id, + "[meta]\nversion=1\n\n" + "[window.main]\n" + "x=32\n" + "y=48\n" + "width=420\n" + "height=260\n" + "maximized=0\n\n" + "[window.preview]\n" + "x=8\n" + "y=12\n" + "width=210\n" + "height=180\n" + "maximized=0\n"), + true); + lcui_init(); + ctest_equal_bool("should load settings", lcui_settings_load(), true); + preview_widget = ui_create_widget(NULL); + ctest_equal_bool("should create preview widget", preview_widget != NULL, + true); + ctest_equal_bool("should bind pending widget state", + lcui_bind_window_state(preview_widget, "preview"), + true); + ui_root_append(preview_widget); + ui_update(); + ctest_equal_int("should resize pending widget width", + (int)preview_widget->border_box.width, 210); + ctest_equal_int("should resize pending widget height", + (int)preview_widget->border_box.height, 180); + ui_widget_destroy(preview_widget); + widget = ui_root(); + window = ui_server_get_window(widget); + ctest_equal_bool("should get root window", window != NULL, true); + helper_process_window_events(8); + ctest_equal_bool("should bind window state", + lcui_bind_window_state(widget, "main"), true); + helper_process_window_events(12); + ctest_equal_bool("should query restored window geometry", + helper_query_window_state(window, &actual), true); + ctest_equal_int("should restore saved width", actual.width, 420); + ctest_equal_int("should restore saved height", actual.height, 260); + ptk_window_set_size(window, 300, 220); + helper_process_window_events(12); + new_width = ptk_window_get_width(window); + new_height = ptk_window_get_height(window); + ptk_window_close(window); + helper_process_window_events(12); + ctest_equal_bool("should persist updated bound window state on close", + lcui_get_window_state("main", &saved), true); + ctest_equal_int("should save updated width", saved.width, new_width); + ctest_equal_int("should save updated height", saved.height, new_height); + ctest_equal_bool( + "should flush bound window section", + test_read_file_contains(base_dir, app_id, "[window.main]"), true); + lcui_destroy(); +} + void test_settings(void) { ctest_describe("rendering settings accessors", test_settings_rendering_accessors); ctest_describe("settings load/merge/validate/flush", test_settings_load_merge_validate_flush); + ctest_describe("window state accessors", test_window_state_accessors); + ctest_describe("window state invalid values", + test_window_state_invalid_values); + ctest_describe("window state binding", test_window_state_binding); } From 812b80b1224764ef40f924b3906782018647c52b Mon Sep 17 00:00:00 2001 From: Liu Date: Fri, 12 Jun 2026 22:43:28 +0800 Subject: [PATCH 38/66] ci: improve format check reliability - Use project-local clang-format from node_modules/.bin instead of system PATH to avoid version mismatches between CI and development environments - Print clang-format version and binary path in CI logs for debugging - Add format:check script to package.json so `npm run format:check` works - Add `needs: format` to build job so formatting failures block the build and don't waste CI resources --- .github/workflows/ccpp.yml | 4 +-- package.json | 1 + scripts/clang-format-changed.js | 49 +++++++++++++++++++++++++++++++-- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 570fa84da..50b47a3fa 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -27,10 +27,10 @@ jobs: run: npm ci - name: Check formatting of changed files - run: | - node scripts/clang-format-changed.js origin/${{ github.base_ref || 'develop' }} + run: npm run format:check -- origin/${{ github.base_ref || 'develop' }} build: + needs: format env: TARGET_MAJOR: 3 TARGET_VERSION: 3.0.0 diff --git a/package.json b/package.json index 84ec8d470..3371374f9 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "build-changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0", "update-changelog": "conventional-changelog -p angular -i CHANGELOG.md -s", "update-copyright": "node scripts/add-copyright.js", + "format:check": "node scripts/clang-format-changed.js", "prepare": "husky" }, "lint-staged": { diff --git a/scripts/clang-format-changed.js b/scripts/clang-format-changed.js index 4aa554e31..fe6ba0a44 100644 --- a/scripts/clang-format-changed.js +++ b/scripts/clang-format-changed.js @@ -6,16 +6,54 @@ * a base ref. Designed for CI: it only inspects files actually touched by * the current PR / push, leaving pre-existing formatting issues alone. * + * The clang-format binary is resolved from node_modules/.bin so that the + * project-local version (installed from the `clang-format-node` devDependency) + * is always used, regardless of system PATH. + * * Usage: * node scripts/clang-format-changed.js [base-ref] * * Defaults to "origin/develop" if no base ref is given. */ +const fs = require("node:fs"); +const path = require("node:path"); const { execFileSync, spawnSync } = require("node:child_process"); const baseRef = process.argv[2] || "origin/develop"; +function resolveClangFormat() { + const candidates = [ + path.join("node_modules", ".bin", "clang-format"), + path.join("node_modules", ".bin", "clang-format.cmd"), + ]; + for (const c of candidates) { + if (fs.existsSync(c)) { + return c; + } + } + return null; +} + +const clangFormat = resolveClangFormat(); +if (!clangFormat) { + console.error( + "clang-format not found in node_modules/.bin. Run: npm install" + ); + process.exit(1); +} + +let version; +try { + version = execFileSync(clangFormat, ["--version"], { + encoding: "utf8", + shell: true, + }).trim(); +} catch (err) { + console.error(`failed to run ${clangFormat} --version:`, err.message); + process.exit(1); +} + let files; try { const out = execFileSync( @@ -33,10 +71,14 @@ try { } if (files.length === 0) { + console.log(`clang-format: ${version}`); + console.log(`clang-format binary: ${clangFormat}`); console.log("no changed C/C++ files"); process.exit(0); } +console.log(`clang-format: ${version}`); +console.log(`clang-format binary: ${clangFormat}`); console.log(`checking ${files.length} changed file(s) against ${baseRef}`); const BATCH = 50; @@ -44,12 +86,15 @@ let exitCode = 0; for (let i = 0; i < files.length; i += BATCH) { const batch = files.slice(i, i + BATCH); const result = spawnSync( - "clang-format", + clangFormat, ["--dry-run", "--Werror", ...batch], { stdio: "inherit", shell: true } ); if (result.error) { - console.error("clang-format not found in PATH. Install LLVM clang-format."); + console.error( + `failed to execute ${clangFormat}:`, + result.error.message + ); process.exit(1); } if ((result.status ?? 0) !== 0) { From ec3dce33feebe3d69c23d13be6ace436e5a1b1c8 Mon Sep 17 00:00:00 2001 From: Liu Date: Sat, 13 Jun 2026 23:44:58 +0800 Subject: [PATCH 39/66] chore: update copyright and email --- .github/CODE_OF_CONDUCT.md | 2 +- CODE_OF_CONDUCT.md | 2 +- CODE_OF_CONDUCT.zh-cn.md | 2 +- include/LCUI.h | 9 +- include/LCUI/app.h | 9 +- include/LCUI/base.h | 9 +- include/LCUI/common.h | 9 +- include/LCUI/fonts.h | 9 +- include/LCUI/main.h | 2 +- include/LCUI/settings.h | 2 +- include/LCUI/settings/base.h | 11 +- include/LCUI/settings/rendering.h | 11 +- include/LCUI/settings/window_state.h | 11 +- include/LCUI/ui.h | 9 +- include/LCUI/widgets.h | 2 +- include/LCUI/widgets/anchor.h | 13 +- include/LCUI/widgets/button.h | 15 +- include/LCUI/widgets/canvas.h | 71 +- include/LCUI/widgets/scrollarea.h | 15 +- include/LCUI/widgets/scrollbar.h | 19 +- include/LCUI/widgets/text.h | 19 +- include/LCUI/widgets/textcaret.h | 18 +- include/LCUI/widgets/textinput.h | 49 +- include/LCUI/worker.h | 9 +- lib/css/include/css.h | 9 +- lib/css/include/css/common.h | 9 +- lib/css/include/css/computed.h | 9 +- lib/css/include/css/data_types.h | 15 +- lib/css/include/css/keywords.h | 14 +- lib/css/include/css/library.h | 11 +- lib/css/include/css/parser.h | 93 +- lib/css/include/css/properties.h | 16 +- lib/css/include/css/selector.h | 18 +- lib/css/include/css/style_decl.h | 17 +- lib/css/include/css/style_value.h | 35 +- lib/css/include/css/types.h | 9 +- lib/css/include/css/utils.h | 10 +- lib/css/include/css/value.h | 17 +- lib/css/src/computed.c | 9 +- lib/css/src/data_types.c | 621 +- lib/css/src/debug.h | 6 +- lib/css/src/dump.c | 43 +- lib/css/src/dump.h | 17 +- lib/css/src/font_face_parser.c | 418 +- lib/css/src/keywords.c | 315 +- lib/css/src/library.c | 14 +- lib/css/src/main.c | 27 +- lib/css/src/parser.c | 11 +- lib/css/src/parser.h | 10 +- lib/css/src/properties.c | 9 +- lib/css/src/properties.h | 2 +- lib/css/src/properties/align_content.c | 61 +- lib/css/src/properties/align_items.c | 43 +- lib/css/src/properties/background.c | 13 +- lib/css/src/properties/border.c | 9 +- lib/css/src/properties/bottom.c | 23 +- lib/css/src/properties/box_shadow.c | 95 +- lib/css/src/properties/box_sizing.c | 31 +- lib/css/src/properties/color.c | 29 +- lib/css/src/properties/content.c | 27 +- lib/css/src/properties/display.c | 55 +- lib/css/src/properties/flex.c | 311 +- lib/css/src/properties/font_family.c | 17 +- lib/css/src/properties/font_size.c | 57 +- lib/css/src/properties/font_style.c | 37 +- lib/css/src/properties/font_weight.c | 113 +- lib/css/src/properties/gap.c | 9 +- lib/css/src/properties/height.c | 23 +- lib/css/src/properties/helpers.c | 17 +- lib/css/src/properties/helpers.h | 21 +- lib/css/src/properties/justify_content.c | 65 +- lib/css/src/properties/left.c | 23 +- lib/css/src/properties/line_height.c | 50 +- lib/css/src/properties/margin.c | 127 +- lib/css/src/properties/max_height.c | 24 +- lib/css/src/properties/max_width.c | 23 +- lib/css/src/properties/min_height.c | 27 +- lib/css/src/properties/min_width.c | 16 +- lib/css/src/properties/opacity.c | 10 +- lib/css/src/properties/padding.c | 132 +- lib/css/src/properties/pointer_events.c | 29 +- lib/css/src/properties/position.c | 37 +- lib/css/src/properties/right.c | 23 +- lib/css/src/properties/text_align.c | 37 +- lib/css/src/properties/top.c | 23 +- lib/css/src/properties/vertical_align.c | 41 +- lib/css/src/properties/visibility.c | 31 +- lib/css/src/properties/white_space.c | 29 +- lib/css/src/properties/width.c | 23 +- lib/css/src/properties/word_break.c | 29 +- lib/css/src/properties/z_index.c | 25 +- lib/css/src/selector.c | 22 +- lib/css/src/style_decl.c | 9 +- lib/css/src/style_parser.c | 113 +- lib/css/src/style_value.c | 392 +- lib/css/src/utils.c | 77 +- lib/css/src/value.c | 1941 +-- lib/css/tests/test.c | 19 +- lib/css/tests/test.h | 2 +- lib/css/tests/test_css_computed.c | 9 +- lib/css/tests/test_css_keywords.c | 41 +- lib/css/tests/test_css_value.c | 775 +- lib/ctest/include/ctest.h | 9 +- lib/ctest/src/ctest.c | 9 +- lib/ctest/tests/main.c | 11 +- lib/ctest/tests/test_grep.c | 14 + lib/ctest/tests/test_str.c | 14 + lib/i18n/include/i18n.h | 2 +- lib/i18n/src/i18n-dict.c | 9 +- lib/i18n/src/i18n-private.h | 9 +- lib/i18n/src/i18n.c | 9 +- lib/i18n/src/i18n.h.in | 2 +- lib/i18n/src/yaml.c | 11 +- lib/i18n/tests/test.c | 9 +- lib/pandagl/examples/cairo/src/main.c | 19 +- lib/pandagl/examples/char-render/src/main.c | 13 +- .../examples/fill-rect-with-rgba/src/main.c | 17 +- lib/pandagl/examples/fill-rect/src/main.c | 13 +- .../examples/image-scaling-bench/src/main.c | 14 +- .../examples/mix-rect-with-opacity/src/main.c | 18 +- .../examples/paint-background/src/main.c | 22 +- lib/pandagl/examples/paint-border/src/main.c | 12 +- .../examples/paint-boxshadow/src/main.c | 20 +- .../examples/pixel-manipulation/src/main.c | 14 +- lib/pandagl/examples/string-render/src/main.c | 16 +- lib/pandagl/include/pandagl.h | 9 +- lib/pandagl/include/pandagl/background.h | 15 +- lib/pandagl/include/pandagl/border.h | 17 +- lib/pandagl/include/pandagl/boxshadow.h | 22 +- lib/pandagl/include/pandagl/canvas.h | 94 +- lib/pandagl/include/pandagl/color.h | 13 +- lib/pandagl/include/pandagl/common.h | 9 +- lib/pandagl/include/pandagl/context.h | 13 +- lib/pandagl/include/pandagl/file_reader.h | 18 +- lib/pandagl/include/pandagl/font.h | 50 +- lib/pandagl/include/pandagl/image.h | 13 +- lib/pandagl/include/pandagl/line.h | 27 +- lib/pandagl/include/pandagl/pixel.h | 114 +- lib/pandagl/include/pandagl/rect.h | 25 +- lib/pandagl/include/pandagl/text.h | 202 +- lib/pandagl/include/pandagl/types.h | 157 +- lib/pandagl/src/background.c | 11 +- lib/pandagl/src/border.c | 11 +- lib/pandagl/src/boxshadow.c | 1014 +- lib/pandagl/src/canvas.c | 747 +- lib/pandagl/src/context.c | 29 +- lib/pandagl/src/file_reader.c | 9 +- lib/pandagl/src/flip.c | 119 +- lib/pandagl/src/font/bitmap.c | 181 +- lib/pandagl/src/font/bitmap.h | 2 +- lib/pandagl/src/font/freetype.c | 311 +- lib/pandagl/src/font/freetype.h | 2 +- lib/pandagl/src/font/inconsolata.c | 12614 ++++++---------- lib/pandagl/src/font/inconsolata.h | 5 +- lib/pandagl/src/font/incore.c | 82 +- lib/pandagl/src/font/incore.h | 2 +- lib/pandagl/src/font/library.c | 45 +- lib/pandagl/src/font/library.h | 5 +- lib/pandagl/src/image/bmp.c | 11 +- lib/pandagl/src/image/bmp_private.h | 2 +- lib/pandagl/src/image/jpeg.c | 264 +- lib/pandagl/src/image/jpeg_private.h | 2 +- lib/pandagl/src/image/png.c | 11 +- lib/pandagl/src/image/png_private.h | 2 +- lib/pandagl/src/image/reader.c | 11 +- lib/pandagl/src/line.c | 209 +- lib/pandagl/src/pixel.c | 148 +- lib/pandagl/src/rect.c | 16 +- lib/pandagl/src/text/style.c | 232 +- lib/pandagl/src/text/style_tag.c | 653 +- lib/pandagl/src/text/text.c | 27 +- lib/pandagl/src/text/text_edit.c | 15 +- lib/pandagl/src/text/text_internal.h | 25 +- lib/pandagl/src/text/text_render.c | 17 +- lib/pandagl/src/text/text_typeset.c | 11 +- lib/pandagl/src/tile.c | 43 +- lib/pandagl/src/zoom.c | 307 +- lib/pandagl/tests/main.c | 11 +- lib/pandagl/tests/test_canvas_mix.c | 11 +- lib/pandagl/tests/test_font_cache.c | 9 +- lib/pandagl/tests/test_font_load.c | 71 +- lib/pandagl/tests/test_image_reader.c | 9 +- lib/pandagl/tests/test_text_edit.c | 28 +- lib/ptk/include/ptk.h | 9 +- lib/ptk/include/ptk/app.h | 9 +- lib/ptk/include/ptk/clipboard.h | 18 +- lib/ptk/include/ptk/common.h | 23 +- lib/ptk/include/ptk/events.h | 45 +- lib/ptk/include/ptk/ime.h | 19 +- lib/ptk/include/ptk/main.h | 2 +- lib/ptk/include/ptk/steptimer.h | 11 +- lib/ptk/include/ptk/types.h | 9 +- lib/ptk/include/ptk/win32_main.h | 43 +- lib/ptk/include/ptk/window.h | 9 +- lib/ptk/src/app.c | 9 +- lib/ptk/src/clipboard.c | 11 +- lib/ptk/src/clipboard.h | 2 +- lib/ptk/src/events.c | 9 +- lib/ptk/src/events.h | 2 +- lib/ptk/src/ime.c | 9 +- lib/ptk/src/ime.h | 2 +- lib/ptk/src/linux/app.c | 11 +- lib/ptk/src/linux/fbapp.c | 9 +- lib/ptk/src/linux/fbapp.h | 2 +- lib/ptk/src/linux/ime.c | 11 +- lib/ptk/src/linux/keyboard.c | 258 +- lib/ptk/src/linux/keyboard.h | 2 +- lib/ptk/src/linux/mouse.c | 11 +- lib/ptk/src/linux/mouse.h | 3 +- lib/ptk/src/linux/uri.c | 17 +- lib/ptk/src/linux/x11app.c | 9 +- lib/ptk/src/linux/x11app.h | 2 +- lib/ptk/src/linux/x11clipboard.c | 11 +- lib/ptk/src/linux/x11clipboard.h | 2 +- lib/ptk/src/steptimer.c | 208 +- lib/ptk/src/windows/uri.c | 19 +- lib/ptk/src/windows/win32app.c | 11 +- lib/ptk/src/windows/win32clipboard.c | 13 +- lib/ptk/src/windows/win32clipboard.h | 11 +- lib/ptk/src/windows/win32ime.c | 73 +- lib/ptk/tests/main.c | 2 +- lib/ptk/tests/test_steptimer.c | 11 +- lib/router/include/router.h | 2 +- lib/router/include/router/common.h | 9 +- lib/router/include/router/config.h | 17 +- lib/router/include/router/history.h | 18 +- lib/router/include/router/location.h | 21 +- lib/router/include/router/matcher.h | 9 +- lib/router/include/router/route.h | 27 +- lib/router/include/router/route_record.h | 9 +- lib/router/include/router/router.h | 24 +- lib/router/include/router/strmap.h | 11 +- lib/router/include/router/types.h | 9 +- lib/router/include/router/utils.h | 25 +- lib/router/include/router/version.h | 2 +- lib/router/src/config.c | 57 +- lib/router/src/history.c | 9 +- lib/router/src/location.c | 9 +- lib/router/src/matcher.c | 15 +- lib/router/src/private.h | 9 +- lib/router/src/route.c | 99 +- lib/router/src/route_record.c | 65 +- lib/router/src/router.c | 163 +- lib/router/src/strmap.c | 11 +- lib/router/src/utils.c | 9 +- lib/router/src/version.h.in | 2 +- lib/router/tests/test.c | 9 +- lib/thread/src/pthread.c | 276 +- lib/thread/src/windows.c | 413 +- lib/thread/tests/main.c | 2 +- lib/thread/tests/test_thread.c | 9 +- lib/ui-cursor/include/ui_cursor.h | 12 +- lib/ui-cursor/include/ui_cursor/common.h | 9 +- lib/ui-cursor/src/cursor.c | 323 +- lib/ui-router/include/ui_router.h | 4 +- lib/ui-router/include/ui_router/common.h | 11 +- lib/ui-router/include/ui_router/link.h | 11 +- lib/ui-router/include/ui_router/view.h | 11 +- lib/ui-router/src/link.c | 11 +- lib/ui-router/src/view.c | 11 +- lib/ui-server/include/ui_server.h | 15 +- lib/ui-server/include/ui_server/common.h | 9 +- lib/ui-server/src/server.c | 9 +- lib/ui-xml/include/ui_xml.h | 17 +- lib/ui-xml/include/ui_xml/common.h | 9 +- lib/ui-xml/src/ui_xml.c | 13 +- lib/ui-xml/tests/main.c | 2 +- lib/ui-xml/tests/test_xml_parser.c | 9 +- lib/ui/include/ui.h | 9 +- lib/ui/include/ui/base.h | 20 +- lib/ui/include/ui/common.h | 13 +- lib/ui/include/ui/css.h | 9 +- lib/ui/include/ui/events.h | 9 +- lib/ui/include/ui/hash.h | 13 +- lib/ui/include/ui/image.h | 9 +- lib/ui/include/ui/logger.h | 11 +- lib/ui/include/ui/metrics.h | 9 +- lib/ui/include/ui/mutation_observer.h | 9 +- lib/ui/include/ui/prototype.h | 9 +- lib/ui/include/ui/rect.h | 9 +- lib/ui/include/ui/style.h | 27 +- lib/ui/include/ui/text_style.h | 33 +- lib/ui/include/ui/types.h | 11 +- lib/ui/include/ui/updater.h | 9 +- lib/ui/src/ui.c | 43 +- lib/ui/src/ui_block_layout.c | 9 +- lib/ui/src/ui_block_layout.h | 3 +- lib/ui/src/ui_css.c | 91 +- lib/ui/src/ui_css.h | 2 +- lib/ui/src/ui_debug.c | 137 +- lib/ui/src/ui_debug.h | 9 +- lib/ui/src/ui_diff.c | 12 +- lib/ui/src/ui_diff.h | 9 +- lib/ui/src/ui_events.c | 1730 +-- lib/ui/src/ui_events.h | 2 +- lib/ui/src/ui_flexbox_layout.c | 9 +- lib/ui/src/ui_flexbox_layout.h | 2 +- lib/ui/src/ui_image.c | 16 +- lib/ui/src/ui_image.h | 2 +- lib/ui/src/ui_logger.c | 38 +- lib/ui/src/ui_metrics.c | 9 +- lib/ui/src/ui_mutation_observer.c | 9 +- lib/ui/src/ui_mutation_observer.h | 10 +- lib/ui/src/ui_rect.c | 12 +- lib/ui/src/ui_renderer.c | 20 +- lib/ui/src/ui_resizer.c | 9 +- lib/ui/src/ui_resizer.h | 9 +- lib/ui/src/ui_root.c | 19 +- lib/ui/src/ui_root.h | 2 +- lib/ui/src/ui_text_style.c | 16 +- lib/ui/src/ui_tree.c | 9 +- lib/ui/src/ui_updater.c | 9 +- lib/ui/src/ui_updater.h | 2 +- lib/ui/src/ui_widget.c | 9 +- lib/ui/src/ui_widget.h | 2 +- lib/ui/src/ui_widget_attributes.c | 9 +- lib/ui/src/ui_widget_attributes.h | 2 +- lib/ui/src/ui_widget_background.c | 9 +- lib/ui/src/ui_widget_background.h | 4 +- lib/ui/src/ui_widget_border.c | 91 +- lib/ui/src/ui_widget_border.h | 6 +- lib/ui/src/ui_widget_box_shadow.c | 55 +- lib/ui/src/ui_widget_box_shadow.h | 4 +- lib/ui/src/ui_widget_classes.c | 108 +- lib/ui/src/ui_widget_classes.h | 2 +- lib/ui/src/ui_widget_hash.c | 247 +- lib/ui/src/ui_widget_helper.c | 9 +- lib/ui/src/ui_widget_id.c | 154 +- lib/ui/src/ui_widget_id.h | 2 +- lib/ui/src/ui_widget_layout.c | 9 +- lib/ui/src/ui_widget_layout.h | 2 +- lib/ui/src/ui_widget_observer.c | 9 +- lib/ui/src/ui_widget_observer.h | 6 +- lib/ui/src/ui_widget_prototype.c | 9 +- lib/ui/src/ui_widget_prototype.h | 2 +- lib/ui/src/ui_widget_status.c | 156 +- lib/ui/src/ui_widget_status.h | 2 +- lib/ui/src/ui_widget_style.c | 9 +- lib/ui/src/ui_widget_style.h | 9 +- lib/worker/include/worker.h | 11 +- lib/worker/include/worker/common.h | 9 +- lib/worker/src/worker.c | 14 +- package.json | 2 +- scripts/add-copyright.js | 8 +- src/ini_doc.c | 16 +- src/ini_doc.h | 16 +- src/lcui.c | 13 +- src/lcui_app.c | 9 +- src/lcui_app.h | 6 +- src/lcui_fonts.c | 9 +- src/lcui_rendering.c | 16 +- src/lcui_settings.c | 14 +- src/lcui_settings.h | 16 +- src/lcui_ui.c | 9 +- src/lcui_widgets.c | 9 +- src/lcui_window_state.c | 16 +- src/lcui_worker.c | 9 +- src/setting_field.c | 16 +- src/setting_field.h | 16 +- src/widgets/anchor.c | 11 +- src/widgets/button.c | 31 +- src/widgets/canvas.c | 205 +- src/widgets/scrollarea.c | 11 +- src/widgets/scrollbar.c | 11 +- src/widgets/text.c | 13 +- src/widgets/textcaret.c | 13 +- src/widgets/textinput.c | 16 +- src/widgets/textstyle.c | 46 +- src/widgets/textstyle.h | 2 +- tests/helloworld_uwp/pch.h | 2 +- tests/helpers/ctest-custom.h | 2 +- tests/integration/test_block_layout.c | 2 +- tests/integration/test_clipboard.c | 2 +- tests/integration/test_flex_layout.c | 2 +- tests/integration/test_font_face.c | 5 +- tests/integration/test_mainloop.c | 2 +- tests/integration/test_scrollbar.c | 2 +- tests/integration/test_settings.c | 2 +- tests/integration/test_text_resize.c | 2 +- tests/integration/test_textinput.c | 2 +- tests/integration/test_widget_event.c | 2 +- tests/integration/test_widget_opacity.c | 2 +- tests/integration/test_widget_rect.c | 2 +- tests/previews/preview_block_layout.c | 2 +- tests/previews/preview_flex_layout.c | 2 +- tests/previews/preview_scrollbar.c | 2 +- tests/previews/preview_widget_opacity.c | 2 +- tests/scenes/block_layout_scene.c | 2 +- tests/scenes/block_layout_scene.h | 2 +- tests/scenes/flex_layout_scene.c | 2 +- tests/scenes/flex_layout_scene.h | 2 +- tests/scenes/scrollbar_scene.c | 2 +- tests/scenes/scrollbar_scene.h | 2 +- tests/scenes/widget_opacity_scene.c | 2 +- tests/scenes/widget_opacity_scene.h | 2 +- xmake-requires.lock | 50 +- 396 files changed, 15507 insertions(+), 17082 deletions(-) diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index 7acac1ddd..da2a74a89 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at admin@lc-soft.io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hello@lcui.dev. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 1d89b317c..6e8a5533f 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -55,7 +55,7 @@ a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at root@lc-soft.io. All +reported by contacting the project team at hello@lcui.dev. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. diff --git a/CODE_OF_CONDUCT.zh-cn.md b/CODE_OF_CONDUCT.zh-cn.md index cfbf93366..45039ac4b 100644 --- a/CODE_OF_CONDUCT.zh-cn.md +++ b/CODE_OF_CONDUCT.zh-cn.md @@ -38,7 +38,7 @@ ## 强制执行 -可以通过 root@lc-soft.io,来联系项目团队来举报滥用、骚扰或其他不被接受的行为。 +可以通过 hello@lcui.dev,来联系项目团队来举报滥用、骚扰或其他不被接受的行为。 任何维护团队认为有必要且适合的所有投诉都将进行审查及调查,并做出相对应的回应。项目小组有对事件回报者有保密的义务。具体执行的方针近一步细节可能会单独公布。 diff --git a/include/LCUI.h b/include/LCUI.h index f982dc808..53591370c 100644 --- a/include/LCUI.h +++ b/include/LCUI.h @@ -1,12 +1,15 @@ /* * include/LCUI.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is + * part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT + * file in the root directory of this source tree. */ #include diff --git a/include/LCUI/app.h b/include/LCUI/app.h index a191984fa..145b0bc25 100644 --- a/include/LCUI/app.h +++ b/include/LCUI/app.h @@ -1,12 +1,15 @@ /* * include/LCUI/app.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LCUI_INCLUDE_LCUI_APP_H diff --git a/include/LCUI/base.h b/include/LCUI/base.h index 11b7462a9..9486186e3 100644 --- a/include/LCUI/base.h +++ b/include/LCUI/base.h @@ -1,12 +1,15 @@ /* * include/LCUI/base.h * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LCUI_INCLUDE_LCUI_BASE_H diff --git a/include/LCUI/common.h b/include/LCUI/common.h index e9e4caff4..5c5e4a2b1 100644 --- a/include/LCUI/common.h +++ b/include/LCUI/common.h @@ -1,12 +1,15 @@ /* * include/LCUI/common.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LCUI_INCLUDE_LCUI_COMMON_H diff --git a/include/LCUI/fonts.h b/include/LCUI/fonts.h index 6eb9c1c90..72ce28c80 100644 --- a/include/LCUI/fonts.h +++ b/include/LCUI/fonts.h @@ -1,12 +1,15 @@ /* * include/LCUI/fonts.h * - * Copyright (c) 2025, Liu Chao All rights reserved. + * Copyright (c) 2025-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LCUI_INCLUDE_LCUI_FONTS_H diff --git a/include/LCUI/main.h b/include/LCUI/main.h index 515c4ddd4..f1190a932 100644 --- a/include/LCUI/main.h +++ b/include/LCUI/main.h @@ -1,7 +1,7 @@ /* * include/LCUI/main.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/include/LCUI/settings.h b/include/LCUI/settings.h index a7d21ffe1..cdbfaebec 100644 --- a/include/LCUI/settings.h +++ b/include/LCUI/settings.h @@ -1,7 +1,7 @@ /* * include/LCUI/settings.h * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/include/LCUI/settings/base.h b/include/LCUI/settings/base.h index 8b9b97651..90442310a 100644 --- a/include/LCUI/settings/base.h +++ b/include/LCUI/settings/base.h @@ -1,12 +1,15 @@ -/* +/* * include/LCUI/settings/base.h * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LCUI_INCLUDE_LCUI_SETTINGS_BASE_H diff --git a/include/LCUI/settings/rendering.h b/include/LCUI/settings/rendering.h index 0f670818f..f3351033e 100644 --- a/include/LCUI/settings/rendering.h +++ b/include/LCUI/settings/rendering.h @@ -1,12 +1,15 @@ -/* +/* * include/LCUI/settings/rendering.h * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LCUI_INCLUDE_LCUI_SETTINGS_RENDERING_H diff --git a/include/LCUI/settings/window_state.h b/include/LCUI/settings/window_state.h index 9007045f9..08e71a14b 100644 --- a/include/LCUI/settings/window_state.h +++ b/include/LCUI/settings/window_state.h @@ -1,11 +1,14 @@ -/* +/* * include/LCUI/settings/window_state.h * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ diff --git a/include/LCUI/ui.h b/include/LCUI/ui.h index 4a8158b98..bc6198af8 100644 --- a/include/LCUI/ui.h +++ b/include/LCUI/ui.h @@ -1,12 +1,15 @@ /* * include/LCUI/ui.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is + * part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT + * file in the root directory of this source tree. */ #ifndef LCUI_INCLUDE_UI_H diff --git a/include/LCUI/widgets.h b/include/LCUI/widgets.h index ce0c9cd19..b004a9999 100644 --- a/include/LCUI/widgets.h +++ b/include/LCUI/widgets.h @@ -1,7 +1,7 @@ /* * include/LCUI/widgets.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/include/LCUI/widgets/anchor.h b/include/LCUI/widgets/anchor.h index ce4ec9070..15d9b97c6 100644 --- a/include/LCUI/widgets/anchor.h +++ b/include/LCUI/widgets/anchor.h @@ -1,12 +1,15 @@ /* * include/LCUI/widgets/anchor.h: to element in HTML. * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #ifndef LCUI_INCLUDE_WIDGETS_ANCHOR_H @@ -17,7 +20,7 @@ LCUI_BEGIN_HEADER -LCUI_API void ui_anchor_open(ui_widget_t* w); +LCUI_API void ui_anchor_open(ui_widget_t *w); LCUI_API void ui_register_anchor(void); diff --git a/include/LCUI/widgets/button.h b/include/LCUI/widgets/button.h index a0a885cf9..4424b470e 100644 --- a/include/LCUI/widgets/button.h +++ b/include/LCUI/widgets/button.h @@ -1,12 +1,15 @@ /* * include/LCUI/widgets/button.h: -- LCUI‘s Button widget * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #ifndef LCUI_INCLUDE_WIDGETS_BUTTON_H @@ -17,9 +20,9 @@ LCUI_BEGIN_HEADER -LCUI_API void ui_button_set_text_w(ui_widget_t* w, const wchar_t *wstr); +LCUI_API void ui_button_set_text_w(ui_widget_t *w, const wchar_t *wstr); -LCUI_API void ui_button_set_text(ui_widget_t* w, const char *str); +LCUI_API void ui_button_set_text(ui_widget_t *w, const char *str); LCUI_API void ui_register_button(void); diff --git a/include/LCUI/widgets/canvas.h b/include/LCUI/widgets/canvas.h index bcc193b4f..823869361 100644 --- a/include/LCUI/widgets/canvas.h +++ b/include/LCUI/widgets/canvas.h @@ -1,12 +1,15 @@ /* * include/LCUI/widgets/canvas.h: -- canvas, used to draw custom graphics * - * Copyright (c) 2019-2025, Liu chao All rights reserved. - * + * Copyright (c) 2019-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #ifndef LCUI_INCLUDE_WIDGETS_CANVAS_H @@ -17,7 +20,9 @@ LCUI_BEGIN_HEADER -/** @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas#attributes */ +/** @see + * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas#attributes + */ #define UI_CANVAS_DEFAULT_WIDTH 300 #define UI_CANVAS_DEFAULT_HEIGHT 150 @@ -25,37 +30,39 @@ LCUI_BEGIN_HEADER typedef struct ui_canvas_rendering_context ui_canvas_context_t; typedef struct ui_canvas_rendering_context { - bool available; - pd_color_t fill_color; - pd_canvas_t buffer; - ui_widget_t* canvas; - list_node_t node; - - float scale; - int width; - int height; - - /** - * Draws a rectangle that is filled according to the current `fill_color`. - * Reference: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillRect - */ - void (*fill_rect)(ui_canvas_context_t*, int, int, int, int); - - /** - * Erases the pixels in a rectangular area by setting them to transparent black. - * Reference: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/clearRect - */ - void (*clear_rect)(ui_canvas_context_t*, int, int, int, int); - - - void (*release)(ui_canvas_context_t*); + bool available; + pd_color_t fill_color; + pd_canvas_t buffer; + ui_widget_t *canvas; + list_node_t node; + + float scale; + int width; + int height; + + /** + * Draws a rectangle that is filled according to the current + * `fill_color`. Reference: + * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillRect + */ + void (*fill_rect)(ui_canvas_context_t *, int, int, int, int); + + /** + * Erases the pixels in a rectangular area by setting them to + * transparent black. Reference: + * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/clearRect + */ + void (*clear_rect)(ui_canvas_context_t *, int, int, int, int); + + void (*release)(ui_canvas_context_t *); } ui_canvas_rendering_context_t; /** * Get a drawing context on the canvas - * Reference: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext -*/ -LCUI_API ui_canvas_context_t *ui_canvas_get_context(ui_widget_t* w); + * Reference: + * https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext + */ +LCUI_API ui_canvas_context_t *ui_canvas_get_context(ui_widget_t *w); LCUI_API void ui_register_canvas(void); diff --git a/include/LCUI/widgets/scrollarea.h b/include/LCUI/widgets/scrollarea.h index a41dffbc6..081d23d02 100644 --- a/include/LCUI/widgets/scrollarea.h +++ b/include/LCUI/widgets/scrollarea.h @@ -1,12 +1,15 @@ /* * include/LCUI/widgets/scrollarea.h * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LCUI_INCLUDE_WIDGETS_SCROLLAREA_H @@ -34,11 +37,9 @@ LCUI_API ui_widget_t *ui_create_scrollarea(void); LCUI_API ui_widget_t *ui_create_scrollarea_content(void); -LCUI_API void ui_scrollarea_set_scroll_top(ui_widget_t *w, - float value); +LCUI_API void ui_scrollarea_set_scroll_top(ui_widget_t *w, float value); -LCUI_API void ui_scrollarea_set_scroll_left(ui_widget_t *w, - float value); +LCUI_API void ui_scrollarea_set_scroll_left(ui_widget_t *w, float value); LCUI_API float ui_scrollarea_get_scroll_top(ui_widget_t *w); diff --git a/include/LCUI/widgets/scrollbar.h b/include/LCUI/widgets/scrollbar.h index cc80ac73a..f4f078206 100644 --- a/include/LCUI/widgets/scrollbar.h +++ b/include/LCUI/widgets/scrollbar.h @@ -1,12 +1,15 @@ /* * include/LCUI/widgets/scrollbar.h: -- LCUI's scrollbar widget * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #ifndef LCUI_INCLUDE_WIDGETS_SCROLLBAR_H @@ -18,14 +21,14 @@ LCUI_BEGIN_HEADER typedef enum { - UI_SCROLLBAR_HORIZONTAL, - UI_SCROLLBAR_VERTICAL + UI_SCROLLBAR_HORIZONTAL, + UI_SCROLLBAR_VERTICAL } ui_scrollbar_orientation_t; LCUI_API void ui_scrollbar_update(ui_widget_t *w); -LCUI_API void ui_scrollbar_set_orientation(ui_widget_t* w, - ui_scrollbar_orientation_t orientation); +LCUI_API void ui_scrollbar_set_orientation( + ui_widget_t *w, ui_scrollbar_orientation_t orientation); LCUI_API ui_widget_t *ui_create_scrollbar(void); diff --git a/include/LCUI/widgets/text.h b/include/LCUI/widgets/text.h index 286689005..fe6bf48ea 100644 --- a/include/LCUI/widgets/text.h +++ b/include/LCUI/widgets/text.h @@ -1,12 +1,15 @@ /* * include/LCUI/widgets/text.h: -- TextView widget for display * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #ifndef LCUI_INCLUDE_WIDGETS_TEXT_H @@ -17,14 +20,12 @@ LCUI_BEGIN_HEADER -LCUI_API int ui_text_set_content_w(ui_widget_t *w, - const wchar_t *text); +LCUI_API int ui_text_set_content_w(ui_widget_t *w, const wchar_t *text); LCUI_API size_t ui_text_get_content_w(ui_widget_t *w, wchar_t *buf, - size_t size); + size_t size); -LCUI_API int ui_text_set_content(ui_widget_t *w, - const char *utf8_text); +LCUI_API int ui_text_set_content(ui_widget_t *w, const char *utf8_text); LCUI_API void ui_text_set_multiline(ui_widget_t *w, bool enable); diff --git a/include/LCUI/widgets/textcaret.h b/include/LCUI/widgets/textcaret.h index 6cb548bf5..a20488579 100644 --- a/include/LCUI/widgets/textcaret.h +++ b/include/LCUI/widgets/textcaret.h @@ -1,12 +1,15 @@ /* * include/LCUI/widgets/textcaret.h: -- textcaret widget, used in textinput. * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #ifndef LCUI_INCLUDE_WIDGETS_TEXTCARET_H @@ -15,12 +18,13 @@ #include #include -LCUI_API void ui_textcaret_refresh(ui_widget_t* widget); +LCUI_API void ui_textcaret_refresh(ui_widget_t *widget); -LCUI_API void ui_textcaret_set_visible(ui_widget_t* widget, bool visible); +LCUI_API void ui_textcaret_set_visible(ui_widget_t *widget, bool visible); /** 设置闪烁的时间间隔 */ -LCUI_API void ui_textcaret_set_blink_time(ui_widget_t* widget, unsigned int n_ms); +LCUI_API void ui_textcaret_set_blink_time(ui_widget_t *widget, + unsigned int n_ms); LCUI_API void ui_register_textcaret(void); diff --git a/include/LCUI/widgets/textinput.h b/include/LCUI/widgets/textinput.h index 72bc8c7dc..2c782453f 100644 --- a/include/LCUI/widgets/textinput.h +++ b/include/LCUI/widgets/textinput.h @@ -1,12 +1,15 @@ /* - * include/LCUI/widgets/textinput.h: -- textinput widget, used to allow user edit text. - * - * Copyright (c) 2018-2025, Liu chao All rights reserved. + * include/LCUI/widgets/textinput.h: -- textinput widget, used to allow user + * edit text. + * Copyright (c) 2018-2026, Liu chao All rights + * reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #ifndef LCUI_INCLUDE_WIDGETS_TEXTINPUT_H @@ -18,43 +21,47 @@ LCUI_BEGIN_HEADER /** Enable style tag parser */ -LCUI_API void ui_textinput_enable_style_tag(ui_widget_t* widget, bool enable); +LCUI_API void ui_textinput_enable_style_tag(ui_widget_t *widget, bool enable); -LCUI_API void ui_textinput_enable_multiline(ui_widget_t* widget, bool enable); +LCUI_API void ui_textinput_enable_multiline(ui_widget_t *widget, bool enable); -LCUI_API void ui_textinput_move_caret(ui_widget_t* widget, int row, int col); +LCUI_API void ui_textinput_move_caret(ui_widget_t *widget, int row, int col); /** 清空文本内容 */ -LCUI_API void ui_textinput_clear_text(ui_widget_t* widget); +LCUI_API void ui_textinput_clear_text(ui_widget_t *widget); /** 获取文本内容 */ -LCUI_API size_t ui_textinput_get_text_w(ui_widget_t* w, size_t start, - size_t max_len, wchar_t *buf); +LCUI_API size_t ui_textinput_get_text_w(ui_widget_t *w, size_t start, + size_t max_len, wchar_t *buf); /** 获取文本长度 */ -LCUI_API size_t ui_textinput_get_text_length(ui_widget_t* w); +LCUI_API size_t ui_textinput_get_text_length(ui_widget_t *w); /** 设置文本编辑框内的光标,指定是否闪烁、闪烁时间间隔 */ -LCUI_API void ui_textinput_set_caret_blink(ui_widget_t* w, bool visible, int time); +LCUI_API void ui_textinput_set_caret_blink(ui_widget_t *w, bool visible, + int time); - /** 为文本框设置文本(宽字符版) */ -LCUI_API int ui_textinput_set_text_w(ui_widget_t* widget, const wchar_t *wstr); +/** 为文本框设置文本(宽字符版) */ +LCUI_API int ui_textinput_set_text_w(ui_widget_t *widget, const wchar_t *wstr); -LCUI_API int ui_textinput_set_text(ui_widget_t* widget, const char *utf8_str); +LCUI_API int ui_textinput_set_text(ui_widget_t *widget, const char *utf8_str); /** 为文本框追加文本(宽字符版) */ -LCUI_API int ui_textinput_append_text_w(ui_widget_t* widget, const wchar_t *wstr); +LCUI_API int ui_textinput_append_text_w(ui_widget_t *widget, + const wchar_t *wstr); /** 为文本框插入文本(宽字符版) */ -LCUI_API int ui_textinput_insert_text_w(ui_widget_t* widget, const wchar_t *wstr); +LCUI_API int ui_textinput_insert_text_w(ui_widget_t *widget, + const wchar_t *wstr); /** 设置占位符,当文本编辑框内容为空时显示占位符 */ -LCUI_API int ui_textinput_set_placeholder_w(ui_widget_t* w, const wchar_t *wstr); +LCUI_API int ui_textinput_set_placeholder_w(ui_widget_t *w, + const wchar_t *wstr); -LCUI_API int ui_textinput_set_placeholder(ui_widget_t* w, const char *str); +LCUI_API int ui_textinput_set_placeholder(ui_widget_t *w, const char *str); /** 设置密码屏蔽符 */ -LCUI_API void ui_textinput_set_password_char(ui_widget_t* w, wchar_t ch); +LCUI_API void ui_textinput_set_password_char(ui_widget_t *w, wchar_t ch); LCUI_API void ui_register_textinput(void); diff --git a/include/LCUI/worker.h b/include/LCUI/worker.h index c9f14a8c7..9319a4872 100644 --- a/include/LCUI/worker.h +++ b/include/LCUI/worker.h @@ -1,12 +1,15 @@ /* * include/LCUI/worker.h * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LCUI_INCLUDE_LCUI_WORKER_H diff --git a/lib/css/include/css.h b/lib/css/include/css.h index fce04dbd2..3e4c1473a 100644 --- a/lib/css/include/css.h +++ b/lib/css/include/css.h @@ -1,12 +1,15 @@ /* * lib/css/include/css.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIBCSS_INCLUDE_CSS_H diff --git a/lib/css/include/css/common.h b/lib/css/include/css/common.h index 27387dee9..bc3a44b69 100644 --- a/lib/css/include/css/common.h +++ b/lib/css/include/css/common.h @@ -1,12 +1,15 @@ /* * lib/css/include/css/common.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "config.h" diff --git a/lib/css/include/css/computed.h b/lib/css/include/css/computed.h index 450ff3f5a..85e4c3642 100644 --- a/lib/css/include/css/computed.h +++ b/lib/css/include/css/computed.h @@ -1,12 +1,15 @@ /* * lib/css/include/css/computed.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIBCSS_INCLUDE_CSS_COMPUTED_H diff --git a/lib/css/include/css/data_types.h b/lib/css/include/css/data_types.h index 3dfa62146..14300b5f6 100644 --- a/lib/css/include/css/data_types.h +++ b/lib/css/include/css/data_types.h @@ -1,12 +1,15 @@ /* * lib/css/include/css/data_types.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIBCSS_INCLUDE_CSS_DATA_TYPES_H @@ -18,13 +21,13 @@ LIBCSS_BEGIN_DECLS LIBCSS_PUBLIC bool css_parse_numeric_value(css_style_value_t *s, - const char *str); + const char *str); LIBCSS_PUBLIC bool css_parse_unit_value(css_style_value_t *s, const char *str); LIBCSS_PUBLIC bool css_parse_string_value(css_style_value_t *val, - const char *str); + const char *str); LIBCSS_PUBLIC bool css_parse_url_value(css_style_value_t *s, const char *str); LIBCSS_PUBLIC bool css_parse_color_value(css_style_value_t *val, - const char *str); + const char *str); LIBCSS_PUBLIC void css_init_data_types(void); LIBCSS_END_DECLS diff --git a/lib/css/include/css/keywords.h b/lib/css/include/css/keywords.h index 00e87d5ea..5e64191db 100644 --- a/lib/css/include/css/keywords.h +++ b/lib/css/include/css/keywords.h @@ -1,12 +1,15 @@ /* * lib/css/include/css/keywords.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIBCSS_INCLUDE_CSS_KEYWORDS_H @@ -17,9 +20,10 @@ LIBCSS_BEGIN_DECLS -LIBCSS_INLINE bool css_check_keyword(css_style_value_t *sv, css_keyword_value_t kv) +LIBCSS_INLINE bool css_check_keyword(css_style_value_t *sv, + css_keyword_value_t kv) { - return sv->type == CSS_KEYWORD_VALUE && sv->keyword_value == kv; + return sv->type == CSS_KEYWORD_VALUE && sv->keyword_value == kv; } LIBCSS_PUBLIC int css_register_keyword(const char *name); diff --git a/lib/css/include/css/library.h b/lib/css/include/css/library.h index e7a6a5590..50472261f 100644 --- a/lib/css/include/css/library.h +++ b/lib/css/include/css/library.h @@ -1,12 +1,15 @@ /* * lib/css/include/css/library.h: -- CSS library operation module. * - * Copyright (c) 2022-2025, Liu chao All rights reserved. - * + * Copyright (c) 2022-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #ifndef LIBCSS_INCLUDE_CSS_LIBRARY_H diff --git a/lib/css/include/css/parser.h b/lib/css/include/css/parser.h index 6864bd9fa..cddcb6458 100644 --- a/lib/css/include/css/parser.h +++ b/lib/css/include/css/parser.h @@ -1,12 +1,15 @@ /* * lib/css/include/css/parser.h: -- CSS parser module * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #ifndef LIBCSS_INCLUDE_CSS_PARSER_H @@ -20,22 +23,22 @@ LIBCSS_BEGIN_DECLS typedef enum css_parser_target_t { - CSS_PARSER_TARGET_NONE, /**< 无 */ - CSS_PARSER_TARGET_RULE_NAME, /**< 规则名称 */ - CSS_PARSER_TARGET_RULE_DATA, /**< 规则数据 */ - CSS_PARSER_TARGET_SELECTOR, /**< 选择器 */ - CSS_PARSER_TARGET_KEY, /**< 属性名 */ - CSS_PARSER_TARGET_VALUE, /**< 属性值 */ - CSS_PARSER_TARGET_COMMENT, /**< 注释 */ - CSS_PARSER_TARGET_TOTAL_NUM + CSS_PARSER_TARGET_NONE, /**< 无 */ + CSS_PARSER_TARGET_RULE_NAME, /**< 规则名称 */ + CSS_PARSER_TARGET_RULE_DATA, /**< 规则数据 */ + CSS_PARSER_TARGET_SELECTOR, /**< 选择器 */ + CSS_PARSER_TARGET_KEY, /**< 属性名 */ + CSS_PARSER_TARGET_VALUE, /**< 属性值 */ + CSS_PARSER_TARGET_COMMENT, /**< 注释 */ + CSS_PARSER_TARGET_TOTAL_NUM } css_parser_target_t; typedef enum css_rule_type_t { - CSS_RULE_NONE, - CSS_RULE_FONT_FACE, /**< @font-face */ - CSS_RULE_IMPORT, /**< @import */ - CSS_RULE_MEDIA, /**< @media */ - CSS_RULE_TOTAL_NUM + CSS_RULE_NONE, + CSS_RULE_FONT_FACE, /**< @font-face */ + CSS_RULE_IMPORT, /**< @import */ + CSS_RULE_MEDIA, /**< @media */ + CSS_RULE_TOTAL_NUM } css_rule_type_t; typedef struct css_parser css_parser_t; @@ -43,52 +46,52 @@ typedef struct css_style_parser css_style_parser_t; typedef int (*css_parser_cb)(css_parser_t *); typedef struct css_rule_parser { - char name[32]; - void *data; - css_parser_cb begin; - css_parser_cb parse; + char name[32]; + void *data; + css_parser_cb begin; + css_parser_cb parse; } css_rule_parser_t; typedef struct css_style_parser { - char *dirname; /**< 当前所在的目录 */ - char *space; /**< 样式记录所属的空间 */ - char *property; + char *dirname; /**< 当前所在的目录 */ + char *space; /**< 样式记录所属的空间 */ + char *property; - void (*style_handler)(int, css_style_value_t *, void *); - void *style_handler_arg; + void (*style_handler)(int, css_style_value_t *, void *); + void *style_handler_arg; - list_t selectors; /**< 当前匹配到的选择器列表 */ - css_style_decl_t *style; /**< 当前缓存的样式表 */ + list_t selectors; /**< 当前匹配到的选择器列表 */ + css_style_decl_t *style; /**< 当前缓存的样式表 */ } css_style_parser_t; typedef struct css_comment_parser { - /** 是否为单行注释 */ - bool is_line_comment; + /** 是否为单行注释 */ + bool is_line_comment; - /** 保存的上一个目标,解析完注释后将还原成该目标 */ - css_parser_target_t prev_target; + /** 保存的上一个目标,解析完注释后将还原成该目标 */ + css_parser_target_t prev_target; } css_comment_parser_t; /** CSS 代码解析器的环境参数(上下文数据) */ struct css_parser { - int pos; /**< 缓存中的字符串的下标位置 */ - const char *cur; /**< 用于遍历字符串的指针 */ - char *space; /**< 样式记录所属的空间 */ - char *buffer; - size_t buffer_size; - - css_parser_target_t target; - css_comment_parser_t comment_parser; - css_style_parser_t style_parser; - css_rule_type_t rule; - css_rule_parser_t rule_parsers[CSS_RULE_TOTAL_NUM]; + int pos; /**< 缓存中的字符串的下标位置 */ + const char *cur; /**< 用于遍历字符串的指针 */ + char *space; /**< 样式记录所属的空间 */ + char *buffer; + size_t buffer_size; + + css_parser_target_t target; + css_comment_parser_t comment_parser; + css_style_parser_t style_parser; + css_rule_type_t rule; + css_rule_parser_t rule_parsers[CSS_RULE_TOTAL_NUM]; }; // css parser LIBCSS_INLINE void css_parser_get_char(css_parser_t *parser) { - parser->buffer[parser->pos++] = *(parser->cur); + parser->buffer[parser->pos++] = *(parser->cur); } LIBCSS_PUBLIC css_parser_t *css_parser_create(const char *space); @@ -106,7 +109,7 @@ LIBCSS_PUBLIC int css_parser_begin_parse_comment(css_parser_t *parser); // css style parser LIBCSS_PUBLIC void css_style_parser_init(css_style_parser_t *parser, - const char *space); + const char *space); LIBCSS_PUBLIC void css_style_parser_destroy(css_style_parser_t *parser); diff --git a/lib/css/include/css/properties.h b/lib/css/include/css/properties.h index 9617a0130..c4a5f8612 100644 --- a/lib/css/include/css/properties.h +++ b/lib/css/include/css/properties.h @@ -1,12 +1,15 @@ /* * lib/css/include/css/properties.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIBCSS_INCLUDE_CSS_PROPERTIES_H @@ -17,10 +20,9 @@ LIBCSS_BEGIN_DECLS -LIBCSS_PUBLIC int css_register_property(const char *name, const char *syntax, - const char *initial_value, - int (*cascade)(const css_style_array_value_t, - css_computed_style_t *)); +LIBCSS_PUBLIC int css_register_property( + const char *name, const char *syntax, const char *initial_value, + int (*cascade)(const css_style_array_value_t, css_computed_style_t *)); LIBCSS_PUBLIC int css_register_shorthand_property( const char *name, const char *syntax, diff --git a/lib/css/include/css/selector.h b/lib/css/include/css/selector.h index 74f5188d8..cdc417b1a 100644 --- a/lib/css/include/css/selector.h +++ b/lib/css/include/css/selector.h @@ -1,12 +1,15 @@ /* * lib/css/include/css/selector.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIBCSS_INCLUDE_CSS_SELECTOR_H @@ -22,18 +25,19 @@ LIBCSS_PUBLIC css_selector_t *css_selector_create(const char *selector); LIBCSS_PUBLIC css_selector_t *css_selector_duplicate(css_selector_t *selector); LIBCSS_PUBLIC int css_selector_append(css_selector_t *selector, - css_selector_node_t *node); + css_selector_node_t *node); LIBCSS_PUBLIC void css_selector_update(css_selector_t *s); LIBCSS_PUBLIC void css_selector_destroy(css_selector_t *s); LIBCSS_PUBLIC int css_selector_node_get_name_list(css_selector_node_t *sn, - list_t *names); + list_t *names); LIBCSS_PUBLIC int css_selector_node_update(css_selector_node_t *node); -LIBCSS_PUBLIC css_selector_node_t * css_selector_node_duplicate(const css_selector_node_t *src); +LIBCSS_PUBLIC css_selector_node_t *css_selector_node_duplicate( + const css_selector_node_t *src); LIBCSS_PUBLIC void css_selector_node_destroy(css_selector_node_t *node); @@ -42,7 +46,7 @@ LIBCSS_PUBLIC void css_selector_node_destroy(css_selector_node_t *node); * 左边的选择器必须包含右边的选择器的所有属性。 */ LIBCSS_PUBLIC bool css_selector_node_match(css_selector_node_t *sn1, - css_selector_node_t *sn2); + css_selector_node_t *sn2); LIBCSS_END_DECLS diff --git a/lib/css/include/css/style_decl.h b/lib/css/include/css/style_decl.h index 352a92d6b..a3c48bfd8 100644 --- a/lib/css/include/css/style_decl.h +++ b/lib/css/include/css/style_decl.h @@ -1,12 +1,15 @@ /* * lib/css/include/css/style_decl.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIBCSS_INCLUDE_CSS_STYLE_DECL_H @@ -24,22 +27,22 @@ LIBCSS_PUBLIC void css_style_decl_destroy(css_style_decl_t *list); LIBCSS_PUBLIC css_prop_t *css_style_decl_alloc(css_style_decl_t *list, int key); LIBCSS_PUBLIC void css_style_decl_add(css_style_decl_t *list, int key, - const css_style_value_t *value); + const css_style_value_t *value); LIBCSS_PUBLIC void css_style_decl_set(css_style_decl_t *list, int key, - const css_style_value_t *value); + const css_style_value_t *value); LIBCSS_PUBLIC int css_style_decl_remove(css_style_decl_t *list, int key); LIBCSS_PUBLIC void css_style_decl_merge(css_style_decl_t *dst, - const css_style_decl_t *src); + const css_style_decl_t *src); LIBCSS_PUBLIC css_prop_t *css_style_decl_find(css_style_decl_t *list, int key); LIBCSS_PUBLIC size_t css_print_style_decl(const css_style_decl_t *s); LIBCSS_PUBLIC size_t css_style_decl_to_string(const css_style_decl_t *list, - char *str, size_t max_len); + char *str, size_t max_len); LIBCSS_END_DECLS #endif diff --git a/lib/css/include/css/style_value.h b/lib/css/include/css/style_value.h index 3d9aada4c..4de31958d 100644 --- a/lib/css/include/css/style_value.h +++ b/lib/css/include/css/style_value.h @@ -1,12 +1,15 @@ /* * lib/css/include/css/style_value.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIBCSS_INCLUDE_CSS_STYLE_VALUE_H @@ -19,23 +22,25 @@ LIBCSS_BEGIN_DECLS #define CSS_COLOR_TRANSPARENT css_color(0, 0xff, 0xff, 0xff) -LIBCSS_INLINE css_color_value_t css_color(uint8_t a, uint8_t r, uint8_t g, uint8_t b) +LIBCSS_INLINE css_color_value_t css_color(uint8_t a, uint8_t r, uint8_t g, + uint8_t b) { - return b | g << 8 | r << 16 | a << 24; + return b | g << 8 | r << 16 | a << 24; } LIBCSS_INLINE uint8_t css_color_alpha(css_color_value_t value) { - return value >> 24; + return value >> 24; } -LIBCSS_PUBLIC unsigned css_array_value_get_length(const css_style_array_value_t val); +LIBCSS_PUBLIC unsigned css_array_value_get_length( + const css_style_array_value_t val); LIBCSS_PUBLIC int css_array_value_set_length(css_style_array_value_t *arr, - unsigned new_len); + unsigned new_len); LIBCSS_PUBLIC unsigned css_array_value_concat(css_style_array_value_t *arr1, - css_style_array_value_t *arr2); + css_style_array_value_t *arr2); LIBCSS_PUBLIC css_style_array_value_t css_array_value_duplicate(const css_style_array_value_t arr); @@ -48,21 +53,21 @@ LIBCSS_PUBLIC unsigned css_style_value_get_array_length( const css_style_value_t *val); LIBCSS_PUBLIC int css_style_value_set_array_length(css_style_value_t *val, - unsigned new_len); + unsigned new_len); LIBCSS_PUBLIC void css_style_value_copy(css_style_value_t *dst, - const css_style_value_t *src); + const css_style_value_t *src); LIBCSS_PUBLIC size_t css_style_value_concat_array(css_style_value_t *val1, - css_style_value_t *val2); + css_style_value_t *val2); // https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleValue/parse LIBCSS_PUBLIC css_style_value_t *css_style_value_parse(const char *property, - const char *css_text); + const char *css_text); -LIBCSS_PUBLIC size_t css_style_value_to_string(const css_style_value_t *s, char *str, - size_t max_len); +LIBCSS_PUBLIC size_t css_style_value_to_string(const css_style_value_t *s, + char *str, size_t max_len); LIBCSS_PUBLIC size_t css_print_style_value(const css_style_value_t *s); diff --git a/lib/css/include/css/types.h b/lib/css/include/css/types.h index 9cbb4d802..48e8ad14d 100644 --- a/lib/css/include/css/types.h +++ b/lib/css/include/css/types.h @@ -1,12 +1,15 @@ /* * lib/css/include/css/types.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIBCSS_INCLUDE_CSS_DEF_H diff --git a/lib/css/include/css/utils.h b/lib/css/include/css/utils.h index c200c5dc8..e65be5667 100644 --- a/lib/css/include/css/utils.h +++ b/lib/css/include/css/utils.h @@ -1,12 +1,15 @@ /* * lib/css/include/css/utils.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIBCSS_INCLUDE_CSS_UTILS_H @@ -17,7 +20,6 @@ LIBCSS_BEGIN_DECLS - LIBCSS_INLINE float css_metrics_actual_scale(css_metrics_t *metrics) { return metrics->dpi / 96.0f * metrics->scale; diff --git a/lib/css/include/css/value.h b/lib/css/include/css/value.h index 2fb159254..9f199606e 100644 --- a/lib/css/include/css/value.h +++ b/lib/css/include/css/value.h @@ -1,12 +1,15 @@ /* * lib/css/include/css/value.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIBCSS_INCLUDE_CSS_VALUE_H @@ -24,7 +27,7 @@ LIBCSS_PUBLIC void css_init_value_definitons(void); LIBCSS_PUBLIC void css_destroy_value_definitons(void); LIBCSS_PUBLIC size_t css_valdef_to_string(const css_valdef_t *valdef, char *str, - size_t max_len); + size_t max_len); LIBCSS_PUBLIC const css_value_type_record_t *css_register_value_type( const char *type_name, css_value_parse_cb parse); @@ -33,7 +36,7 @@ LIBCSS_PUBLIC const css_value_type_record_t *css_get_value_type( const char *type_name); LIBCSS_PUBLIC int css_register_valdef_alias(const char *alias, - const char *definitons); + const char *definitons); LIBCSS_PUBLIC const css_valdef_t *css_resolve_valdef_alias(const char *alias); @@ -44,12 +47,12 @@ LIBCSS_PUBLIC css_valdef_t *css_compile_valdef(const char *definition_str); * @return 成功返回已解析的字符串长度,否则返回 -1 */ LIBCSS_PUBLIC int css_parse_value(const css_valdef_t *valdef, const char *str, - css_style_value_t *val); + css_style_value_t *val); LIBCSS_PUBLIC size_t css_print_valdef(const css_valdef_t *s); LIBCSS_PUBLIC size_t css_valdef_to_string(const css_valdef_t *s, char *str, - size_t max_len); + size_t max_len); LIBCSS_END_DECLS diff --git a/lib/css/src/computed.c b/lib/css/src/computed.c index 639d1a2f4..bdef51c37 100644 --- a/lib/css/src/computed.c +++ b/lib/css/src/computed.c @@ -1,12 +1,15 @@ /* * lib/css/src/computed.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/css/src/data_types.c b/lib/css/src/data_types.c index 9f116a386..019a328ca 100644 --- a/lib/css/src/data_types.c +++ b/lib/css/src/data_types.c @@ -1,12 +1,15 @@ /* * lib/css/src/data_types.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -19,360 +22,360 @@ bool css_parse_numeric_value(css_style_value_t *s, const char *str) { - s->type = CSS_NUMERIC_VALUE; - return sscanf(str, "%f", &s->numeric_value) == 1; + s->type = CSS_NUMERIC_VALUE; + return sscanf(str, "%f", &s->numeric_value) == 1; } bool css_parse_integer_value(css_style_value_t *s, const char *str) { - int num; - s->type = CSS_NUMERIC_VALUE; - if (sscanf(str, "%d", &num) == 1) { - s->numeric_value = 1.0f * num; - return 1; - } - return 0; + int num; + s->type = CSS_NUMERIC_VALUE; + if (sscanf(str, "%d", &num) == 1) { + s->numeric_value = 1.0f * num; + return 1; + } + return 0; } bool css_parse_unit_value(css_style_value_t *s, const char *str) { - int n = 0; - const char *p; - char num_str[32] = { 0 }; - char unit[4]; - css_numeric_value_t num; - bool has_point = false; + int n = 0; + const char *p; + char num_str[32] = { 0 }; + char unit[4]; + css_numeric_value_t num; + bool has_point = false; - if (str == NULL) { - return false; - } - /* 先取出数值 */ - for (p = str; *p && n < 30; ++p) { - if (*p >= '0' && *p <= '9') - ; - else if (*p == '-' || *p == '+') { - if (n > 0) { - n = 0; - break; - } - } else if (*p == '.') { - if (has_point) { - n = 0; - break; - } - has_point = true; - } else { - break; - } - num_str[n++] = *p; - } - if (n == 0) { - return false; - } - strncpy(unit, p, 3); - unit[3] = 0; - sscanf(num_str, "%f", &num); - if (strncmp(unit, "%", 4) == 0) { - s->unit_value.unit = CSS_UNIT_PERCENT; - } else if (strncmp(unit, "px", 4) == 0 || num == 0) { - s->unit_value.unit = CSS_UNIT_PX; - } else if (strncmp(unit, "dp", 4) == 0) { - s->unit_value.unit = CSS_UNIT_DIP; - } else if (strncmp(unit, "sp", 4) == 0) { - s->unit_value.unit = CSS_UNIT_SP; - } else if (strncmp(unit, "pt", 4) == 0) { - s->unit_value.unit = CSS_UNIT_PT; - } else { - return false; - } - num_str[n] = 0; - s->type = CSS_UNIT_VALUE; - s->unit_value.value = num; - return true; + if (str == NULL) { + return false; + } + /* 先取出数值 */ + for (p = str; *p && n < 30; ++p) { + if (*p >= '0' && *p <= '9') + ; + else if (*p == '-' || *p == '+') { + if (n > 0) { + n = 0; + break; + } + } else if (*p == '.') { + if (has_point) { + n = 0; + break; + } + has_point = true; + } else { + break; + } + num_str[n++] = *p; + } + if (n == 0) { + return false; + } + strncpy(unit, p, 3); + unit[3] = 0; + sscanf(num_str, "%f", &num); + if (strncmp(unit, "%", 4) == 0) { + s->unit_value.unit = CSS_UNIT_PERCENT; + } else if (strncmp(unit, "px", 4) == 0 || num == 0) { + s->unit_value.unit = CSS_UNIT_PX; + } else if (strncmp(unit, "dp", 4) == 0) { + s->unit_value.unit = CSS_UNIT_DIP; + } else if (strncmp(unit, "sp", 4) == 0) { + s->unit_value.unit = CSS_UNIT_SP; + } else if (strncmp(unit, "pt", 4) == 0) { + s->unit_value.unit = CSS_UNIT_PT; + } else { + return false; + } + num_str[n] = 0; + s->type = CSS_UNIT_VALUE; + s->unit_value.value = num; + return true; } bool css_parse_percentage_value(css_style_value_t *s, const char *str) { - if (css_parse_unit_value(s, str) && - s->unit_value.unit == CSS_UNIT_PERCENT) { - return true; - } - s->type = CSS_INVALID_VALUE; - return false; + if (css_parse_unit_value(s, str) && + s->unit_value.unit == CSS_UNIT_PERCENT) { + return true; + } + s->type = CSS_INVALID_VALUE; + return false; } bool css_parse_length_value(css_style_value_t *s, const char *str) { - if (css_parse_unit_value(s, str) && - s->unit_value.unit != CSS_UNIT_PERCENT) { - return true; - } - s->type = CSS_INVALID_VALUE; - return false; + if (css_parse_unit_value(s, str) && + s->unit_value.unit != CSS_UNIT_PERCENT) { + return true; + } + s->type = CSS_INVALID_VALUE; + return false; } bool css_parse_string_value(css_style_value_t *val, const char *str) { - size_t len; + size_t len; - len = strlen(str); - val->type = CSS_STRING_VALUE; - if (len > 0) { - if (str[0] == '"' && str[len - 1] == '"') { - val->string_value = strdup2(str + 1); - val->string_value[len - 2] = 0; - } else { - val->string_value = strdup2(str); - } - } else { - val->string_value = NULL; - } - return true; + len = strlen(str); + val->type = CSS_STRING_VALUE; + if (len > 0) { + if (str[0] == '"' && str[len - 1] == '"') { + val->string_value = strdup2(str + 1); + val->string_value[len - 2] = 0; + } else { + val->string_value = strdup2(str); + } + } else { + val->string_value = NULL; + } + return true; } bool css_parse_url_value(css_style_value_t *s, const char *str) { - size_t n; - const char *p, *head, *tail; + size_t n; + const char *p, *head, *tail; - p = str; - tail = head = strstr(p, "url("); - if (!head) { - return false; - } - while (p) { - tail = p; - p = strstr(p + 1, ")"); - } - if (tail == head) { - return false; - } - head += 4; - if (*head == '"') { - ++head; - } - n = tail - head; - s->string_value = malloc((n + 1) * sizeof(char)); - if (!s->string_value) { - return false; - } - strncpy(s->string_value, head, n); - s->string_value[n] = 0; - if (n > 0 && s->string_value[n - 1] == '"') { - n -= 1; - s->string_value[n] = 0; - } - s->type = CSS_STRING_VALUE; - return true; + p = str; + tail = head = strstr(p, "url("); + if (!head) { + return false; + } + while (p) { + tail = p; + p = strstr(p + 1, ")"); + } + if (tail == head) { + return false; + } + head += 4; + if (*head == '"') { + ++head; + } + n = tail - head; + s->string_value = malloc((n + 1) * sizeof(char)); + if (!s->string_value) { + return false; + } + strncpy(s->string_value, head, n); + s->string_value[n] = 0; + if (n > 0 && s->string_value[n - 1] == '"') { + n -= 1; + s->string_value[n] = 0; + } + s->type = CSS_STRING_VALUE; + return true; } static bool css_parse_rgba(css_style_value_t *val, const char *str) { - float data[4]; - char num_str[16]; - int i, j, count; + float data[4]; + char num_str[16]; + int i, j, count; - if (!strstr(str, "rgba(")) { - return false; - } - for (count = 0, i = 5, j = 0; str[i]; ++i) { - if (str[i] == ',' || str[i] == ')') { - if (sscanf(num_str, "%f", &data[count++]) != 1) { - return false; - } - j = 0; - if (str[i] == ')') { - break; - } - } else if ((str[i] == '.' || - (str[i] >= '0' && str[i] <= '9')) && - j < 15) { - num_str[j++] = str[i]; - num_str[j] = 0; - } - } - if (count != 4) { - return false; - } - val->type = CSS_COLOR_VALUE; - val->color_value = css_color((uint8_t)(255 * data[3]), (uint8_t)data[0], - (uint8_t)data[1], (uint8_t)data[2]); - return true; + if (!strstr(str, "rgba(")) { + return false; + } + for (count = 0, i = 5, j = 0; str[i]; ++i) { + if (str[i] == ',' || str[i] == ')') { + if (sscanf(num_str, "%f", &data[count++]) != 1) { + return false; + } + j = 0; + if (str[i] == ')') { + break; + } + } else if ((str[i] == '.' || + (str[i] >= '0' && str[i] <= '9')) && + j < 15) { + num_str[j++] = str[i]; + num_str[j] = 0; + } + } + if (count != 4) { + return false; + } + val->type = CSS_COLOR_VALUE; + val->color_value = css_color((uint8_t)(255 * data[3]), (uint8_t)data[0], + (uint8_t)data[1], (uint8_t)data[2]); + return true; } static bool css_parse_rgb(css_style_value_t *val, const char *str) { - float data[3]; - char num_str[16]; - int i, j, count; + float data[3]; + char num_str[16]; + int i, j, count; - if (!strstr(str, "rgb(")) { - return false; - } - for (count = 0, i = 4, j = 0; str[i]; ++i) { - if (str[i] == ',' || str[i] == ')') { - if (sscanf(num_str, "%f", &data[count++]) != 1) { - return false; - } - j = 0; - if (str[i] == ')') { - break; - } - } else if ((str[i] == '.' || - (str[i] >= '0' && str[i] <= '9')) && - j < 15) { - num_str[j++] = str[i]; - num_str[j] = 0; - } - } - if (count != 3) { - return false; - } - val->type = CSS_COLOR_VALUE; - val->color_value = css_color(255, (uint8_t)data[0], (uint8_t)data[1], - (uint8_t)data[2]); - return true; + if (!strstr(str, "rgb(")) { + return false; + } + for (count = 0, i = 4, j = 0; str[i]; ++i) { + if (str[i] == ',' || str[i] == ')') { + if (sscanf(num_str, "%f", &data[count++]) != 1) { + return false; + } + j = 0; + if (str[i] == ')') { + break; + } + } else if ((str[i] == '.' || + (str[i] >= '0' && str[i] <= '9')) && + j < 15) { + num_str[j++] = str[i]; + num_str[j] = 0; + } + } + if (count != 3) { + return false; + } + val->type = CSS_COLOR_VALUE; + val->color_value = css_color(255, (uint8_t)data[0], (uint8_t)data[1], + (uint8_t)data[2]); + return true; } bool css_parse_color_value(css_style_value_t *val, const char *str) { - const char *p; - int len = 0, status = 0, r, g, b; - for (p = str; *p; ++p, ++len) { - switch (*p) { - case '#': - len == 0 ? status = 3 : 0; - break; - case 'r': - status == 0 ? status = 1 : 0; - break; - case 'g': - status == 1 ? status <<= 1 : 0; - break; - case 'b': - status == 2 ? status <<= 1 : 0; - break; - case 'a': - status == 4 ? status <<= 1 : 0; - break; - default: - if (status < 3) { - break; - } - } - } - switch (status) { - case 3: - status = 0; - if (len == 4) { - status = sscanf(str, "#%1X%1X%1X", &r, &g, &b); - r *= 255 / 0xf; - g *= 255 / 0xf; - b *= 255 / 0xf; - } else if (len == 7) { - status = sscanf(str, "#%2X%2X%2X", &r, &g, &b); - } - break; - case 4: - return css_parse_rgb(val, str); - case 8: - return css_parse_rgba(val, str); - default: - break; - } - if (status == 3) { - val->type = CSS_COLOR_VALUE; - val->color_value = css_color(0xff, r, g, b); - return true; - } - if (strcmp("transparent", str) == 0) { - val->type = CSS_COLOR_VALUE; - val->color_value = CSS_COLOR_TRANSPARENT; - return true; - } - return false; + const char *p; + int len = 0, status = 0, r, g, b; + for (p = str; *p; ++p, ++len) { + switch (*p) { + case '#': + len == 0 ? status = 3 : 0; + break; + case 'r': + status == 0 ? status = 1 : 0; + break; + case 'g': + status == 1 ? status <<= 1 : 0; + break; + case 'b': + status == 2 ? status <<= 1 : 0; + break; + case 'a': + status == 4 ? status <<= 1 : 0; + break; + default: + if (status < 3) { + break; + } + } + } + switch (status) { + case 3: + status = 0; + if (len == 4) { + status = sscanf(str, "#%1X%1X%1X", &r, &g, &b); + r *= 255 / 0xf; + g *= 255 / 0xf; + b *= 255 / 0xf; + } else if (len == 7) { + status = sscanf(str, "#%2X%2X%2X", &r, &g, &b); + } + break; + case 4: + return css_parse_rgb(val, str); + case 8: + return css_parse_rgba(val, str); + default: + break; + } + if (status == 3) { + val->type = CSS_COLOR_VALUE; + val->color_value = css_color(0xff, r, g, b); + return true; + } + if (strcmp("transparent", str) == 0) { + val->type = CSS_COLOR_VALUE; + val->color_value = CSS_COLOR_TRANSPARENT; + return true; + } + return false; } bool css_parse_font_family_value(css_style_value_t *val, const char *str) { - char name[256]; - const char *p; - unsigned quotes = 0; - unsigned count, i; - uint8_t finished = 0; + char name[256]; + const char *p; + unsigned quotes = 0; + unsigned count, i; + uint8_t finished = 0; - val->type = CSS_ARRAY_VALUE; - val->array_value = NULL; - for (i = 0, p = str, count = 0; 1; ++p) { - switch (*p) { - case '"': - case '\'': - if (i > 0) { - if (quotes < 1) { - return false; - } - quotes--; - if (quotes < 1) { - finished = 1; - } - } else { - quotes++; - } - break; - case ',': - if (quotes > 0) { - goto save; - } - if (i < 1) { - return false; - } - goto append; - CASE_WHITE_SPACE: - if (!finished && i > 0) { - goto save; - } - continue; - case 0: - if (i > 0) { - goto append; - } - break; - default: - if (finished) { - return false; - } - break; - } - if (!*p) { - break; - } - save: - if (i < sizeof(name) / sizeof(char)) { - name[i++] = *p; - name[i] = 0; - } - continue; - append: - css_style_value_set_array_length(val, count + 1); - val->array_value[count].type = CSS_STRING_VALUE; - val->array_value[count].string_value = strdup2(name); - count++; - if (!*p) { - break; - } - } - return true; + val->type = CSS_ARRAY_VALUE; + val->array_value = NULL; + for (i = 0, p = str, count = 0; 1; ++p) { + switch (*p) { + case '"': + case '\'': + if (i > 0) { + if (quotes < 1) { + return false; + } + quotes--; + if (quotes < 1) { + finished = 1; + } + } else { + quotes++; + } + break; + case ',': + if (quotes > 0) { + goto save; + } + if (i < 1) { + return false; + } + goto append; + CASE_WHITE_SPACE: + if (!finished && i > 0) { + goto save; + } + continue; + case 0: + if (i > 0) { + goto append; + } + break; + default: + if (finished) { + return false; + } + break; + } + if (!*p) { + break; + } + save: + if (i < sizeof(name) / sizeof(char)) { + name[i++] = *p; + name[i] = 0; + } + continue; + append: + css_style_value_set_array_length(val, count + 1); + val->array_value[count].type = CSS_STRING_VALUE; + val->array_value[count].string_value = strdup2(name); + count++; + if (!*p) { + break; + } + } + return true; } void css_init_data_types(void) { - css_register_value_type("length", css_parse_length_value); - css_register_value_type("percentage", css_parse_percentage_value); - css_register_value_type("color", css_parse_color_value); - css_register_value_type("string", css_parse_string_value); - css_register_value_type("number", css_parse_numeric_value); - css_register_value_type("integer", css_parse_integer_value); - /** FIXME: 处理相对路径 */ - css_register_value_type("url", css_parse_url_value); - css_register_value_type("font-family", css_parse_font_family_value); + css_register_value_type("length", css_parse_length_value); + css_register_value_type("percentage", css_parse_percentage_value); + css_register_value_type("color", css_parse_color_value); + css_register_value_type("string", css_parse_string_value); + css_register_value_type("number", css_parse_numeric_value); + css_register_value_type("integer", css_parse_integer_value); + /** FIXME: 处理相对路径 */ + css_register_value_type("url", css_parse_url_value); + css_register_value_type("font-family", css_parse_font_family_value); } diff --git a/lib/css/src/debug.h b/lib/css/src/debug.h index feddd966d..1651da72f 100644 --- a/lib/css/src/debug.h +++ b/lib/css/src/debug.h @@ -1,7 +1,7 @@ /* * lib/css/src/debug.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -16,5 +16,5 @@ #endif #define _DEBUG_MSG(format, ...) \ - logger_log(LOGGER_LEVEL_DEBUG, __FILE__ ":%d: %s(): " format, \ - __LINE__, __FUNCTION__, ##__VA_ARGS__) + logger_log(LOGGER_LEVEL_DEBUG, __FILE__ ":%d: %s(): " format, \ + __LINE__, __FUNCTION__, ##__VA_ARGS__) diff --git a/lib/css/src/dump.c b/lib/css/src/dump.c index 0bd2f8b57..4f8f982ff 100644 --- a/lib/css/src/dump.c +++ b/lib/css/src/dump.c @@ -1,12 +1,15 @@ /* * lib/css/src/dump.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -15,27 +18,27 @@ size_t css_dump_to_stdout(css_dump_context_t *ctx, const char *fmt, ...) { - va_list args; - size_t n; + va_list args; + size_t n; - va_start(args, fmt); - n = vprintf(fmt, args); - ctx->len += n; - va_end(args); - return n; + va_start(args, fmt); + n = vprintf(fmt, args); + ctx->len += n; + va_end(args); + return n; } size_t css_dump_to_buffer(css_dump_context_t *ctx, const char *fmt, ...) { - va_list args; - size_t n; + va_list args; + size_t n; - if (ctx->len >= ctx->max_len) { - return 0; - } - va_start(args, fmt); - n = vsnprintf(ctx->data + ctx->len, ctx->max_len - ctx->len, fmt, args); - ctx->len += n; - va_end(args); - return n; + if (ctx->len >= ctx->max_len) { + return 0; + } + va_start(args, fmt); + n = vsnprintf(ctx->data + ctx->len, ctx->max_len - ctx->len, fmt, args); + ctx->len += n; + va_end(args); + return n; } diff --git a/lib/css/src/dump.h b/lib/css/src/dump.h index 66930d2bb..771fbc9e1 100644 --- a/lib/css/src/dump.h +++ b/lib/css/src/dump.h @@ -1,12 +1,15 @@ /* * lib/css/src/dump.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIBCSS_INCLUDE_CSS_DUMP_H @@ -18,10 +21,10 @@ typedef struct css_dump_context css_dump_context_t; struct css_dump_context { - char *data; - size_t len; - size_t max_len; - size_t (*func)(css_dump_context_t *, const char *, ...); + char *data; + size_t len; + size_t max_len; + size_t (*func)(css_dump_context_t *, const char *, ...); }; #define DUMP(_STR) ctx->func(ctx, "%s", _STR); diff --git a/lib/css/src/font_face_parser.c b/lib/css/src/font_face_parser.c index 74c601d85..48009daeb 100644 --- a/lib/css/src/font_face_parser.c +++ b/lib/css/src/font_face_parser.c @@ -1,12 +1,15 @@ /* * lib/css/src/font_face_parser.c: -- CSS @font-face rule parser module * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include @@ -19,279 +22,280 @@ enum FontFaceParserState { STATE_HEAD, STATE_KEY, STATE_KEY_END, STATE_VALUE }; enum FontFaceKey { - KEY_NONE, - KEY_FONT_FAMILY, - KEY_FONT_STYLE, - KEY_FONT_WEIGHT, - KEY_SRC + KEY_NONE, + KEY_FONT_FAMILY, + KEY_FONT_STYLE, + KEY_FONT_WEIGHT, + KEY_SRC }; typedef struct css_font_face_parser { - int key; - int state; - css_font_face_t *face; - void (*callback)(const css_font_face_t *); + int key; + int state; + css_font_face_t *face; + void (*callback)(const css_font_face_t *); } css_font_face_parser_t; -LIBCSS_INLINE css_font_face_parser_t *get_css_font_face_parser(css_parser_t *parser) +LIBCSS_INLINE css_font_face_parser_t *get_css_font_face_parser( + css_parser_t *parser) { - return parser->rule_parsers[CSS_RULE_FONT_FACE].data; + return parser->rule_parsers[CSS_RULE_FONT_FACE].data; } static int css_parser_begin_parse_font_face(css_parser_t *parser) { - get_css_font_face_parser(parser)->state = STATE_HEAD; - return 0; + get_css_font_face_parser(parser)->state = STATE_HEAD; + return 0; } static int get_font_face_key(const char *name) { - if (strcmp(name, "font-family") == 0) { - return KEY_FONT_FAMILY; - } else if (strcmp(name, "font-style") == 0) { - return KEY_FONT_STYLE; - } else if (strcmp(name, "font-weight") == 0) { - return KEY_FONT_WEIGHT; - } else if (strcmp(name, "src") == 0) { - return KEY_SRC; - } - return KEY_NONE; + if (strcmp(name, "font-family") == 0) { + return KEY_FONT_FAMILY; + } else if (strcmp(name, "font-style") == 0) { + return KEY_FONT_STYLE; + } else if (strcmp(name, "font-weight") == 0) { + return KEY_FONT_WEIGHT; + } else if (strcmp(name, "src") == 0) { + return KEY_SRC; + } + return KEY_NONE; } static void css_font_face_parser_end(css_parser_t *parser) { - css_font_face_parser_t *data = get_css_font_face_parser(parser); + css_font_face_parser_t *data = get_css_font_face_parser(parser); - if (data->face->font_family) { - free(data->face->font_family); - data->face->font_family = NULL; - } - if (data->face->src) { - free(data->face->src); - data->face->src = NULL; - } - data->key = KEY_NONE; + if (data->face->font_family) { + free(data->face->font_family); + data->face->font_family = NULL; + } + if (data->face->src) { + free(data->face->src); + data->face->src = NULL; + } + data->key = KEY_NONE; } static int css_font_face_parser_parse_head(css_parser_t *parser) { - switch (*parser->cur) { - CASE_WHITE_SPACE: - return 0; - case '/': - return css_parser_begin_parse_comment(parser); - case '{': - break; - default: - return -1; - } - get_css_font_face_parser(parser)->state = STATE_KEY; - css_parser_commit(parser); - return 0; + switch (*parser->cur) { + CASE_WHITE_SPACE: + return 0; + case '/': + return css_parser_begin_parse_comment(parser); + case '{': + break; + default: + return -1; + } + get_css_font_face_parser(parser)->state = STATE_KEY; + css_parser_commit(parser); + return 0; } static int css_font_face_parser_parse_tail(css_parser_t *parser) { - css_font_face_parser_t *data = get_css_font_face_parser(parser); + css_font_face_parser_t *data = get_css_font_face_parser(parser); - if (data->callback) { - data->callback(data->face); - } - css_font_face_parser_end(parser); - css_parser_end_parse_rule(parser); - if (parser->pos > 0) { - return -1; - } - return 0; + if (data->callback) { + data->callback(data->face); + } + css_font_face_parser_end(parser); + css_parser_end_parse_rule(parser); + if (parser->pos > 0) { + return -1; + } + return 0; } static int css_font_face_parser_parse_key_end(css_parser_t *parser) { - css_font_face_parser_t *data; + css_font_face_parser_t *data; - switch (*parser->cur) { - CASE_WHITE_SPACE: - return 0; - case ':': - break; - case '}': - return css_font_face_parser_parse_tail(parser); - default: - css_font_face_parser_end(parser); - return -1; - } - css_parser_commit(parser); - data = get_css_font_face_parser(parser); - data->key = get_font_face_key(parser->buffer); - data->state = STATE_VALUE; - return 0; + switch (*parser->cur) { + CASE_WHITE_SPACE: + return 0; + case ':': + break; + case '}': + return css_font_face_parser_parse_tail(parser); + default: + css_font_face_parser_end(parser); + return -1; + } + css_parser_commit(parser); + data = get_css_font_face_parser(parser); + data->key = get_font_face_key(parser->buffer); + data->state = STATE_VALUE; + return 0; } static int FontFaceParser_ParseKey(css_parser_t *parser) { - switch (*parser->cur) { - CASE_WHITE_SPACE: - if (parser->pos > 0) { - get_css_font_face_parser(parser)->state = STATE_KEY_END; - return 0; - } - break; - case '}': - return css_font_face_parser_parse_tail(parser); - case ':': - css_font_face_parser_parse_key_end(parser); - break; - default: - css_parser_get_char(parser); - break; - } - return 0; + switch (*parser->cur) { + CASE_WHITE_SPACE: + if (parser->pos > 0) { + get_css_font_face_parser(parser)->state = STATE_KEY_END; + return 0; + } + break; + case '}': + return css_font_face_parser_parse_tail(parser); + case ':': + css_font_face_parser_parse_key_end(parser); + break; + default: + css_parser_get_char(parser); + break; + } + return 0; } static int css_font_face_parser_parse_font_weight(css_font_face_t *face, - const char *str) + const char *str) { - int weight; - if (css_parse_font_weight(str, &weight)) { - face->font_weight = weight; - return 0; - } - return -1; + int weight; + if (css_parse_font_weight(str, &weight)) { + face->font_weight = weight; + return 0; + } + return -1; } static int css_font_face_parser_parse_font_style(css_font_face_t *face, - const char *str) + const char *str) { - int style; - if (css_parse_font_style(str, &style)) { - face->font_style = style; - return 0; - } - return -1; + int style; + if (css_parse_font_style(str, &style)) { + face->font_style = style; + return 0; + } + return -1; } static int css_font_face_parser_parse_src(css_font_face_t *face, - const char *str, const char *dirname) + const char *str, const char *dirname) { - css_style_value_t style; + css_style_value_t style; - if (face->src) { - free(face->src); - } - // TODO: dirname + str = absolutePath - if (css_parse_url_value(&style, str)) { - face->src = style.string_value; - return 0; - } - free(face->src); - face->src = NULL; - return -1; + if (face->src) { + free(face->src); + } + // TODO: dirname + str = absolutePath + if (css_parse_url_value(&style, str)) { + face->src = style.string_value; + return 0; + } + free(face->src); + face->src = NULL; + return -1; } static int css_font_face_parser_parse_value(css_parser_t *parser) { - css_font_face_parser_t *data; - switch (*parser->cur) { - case '}': - case ';': - break; - default: - css_parser_get_char(parser); - return 0; - } - css_parser_commit(parser); - data = get_css_font_face_parser(parser); - switch (data->key) { - case KEY_FONT_FAMILY: - if (data->face->font_family) { - free(data->face->font_family); - } - data->face->font_family = strdup2(parser->buffer); - if (!data->face->font_family) { - return -ENOMEM; - } - strtrim(data->face->font_family, parser->buffer, " \""); - break; - case KEY_FONT_STYLE: - css_font_face_parser_parse_font_style(data->face, - parser->buffer); - break; - case KEY_FONT_WEIGHT: - css_font_face_parser_parse_font_weight(data->face, - parser->buffer); - break; - case KEY_SRC: - css_font_face_parser_parse_src(data->face, parser->buffer, - parser->style_parser.dirname); - break; - default: - break; - } - data->key = KEY_NONE; - if (*parser->cur != '}') { - get_css_font_face_parser(parser)->state = STATE_KEY; - return 0; - } - return css_font_face_parser_parse_tail(parser); + css_font_face_parser_t *data; + switch (*parser->cur) { + case '}': + case ';': + break; + default: + css_parser_get_char(parser); + return 0; + } + css_parser_commit(parser); + data = get_css_font_face_parser(parser); + switch (data->key) { + case KEY_FONT_FAMILY: + if (data->face->font_family) { + free(data->face->font_family); + } + data->face->font_family = strdup2(parser->buffer); + if (!data->face->font_family) { + return -ENOMEM; + } + strtrim(data->face->font_family, parser->buffer, " \""); + break; + case KEY_FONT_STYLE: + css_font_face_parser_parse_font_style(data->face, + parser->buffer); + break; + case KEY_FONT_WEIGHT: + css_font_face_parser_parse_font_weight(data->face, + parser->buffer); + break; + case KEY_SRC: + css_font_face_parser_parse_src(data->face, parser->buffer, + parser->style_parser.dirname); + break; + default: + break; + } + data->key = KEY_NONE; + if (*parser->cur != '}') { + get_css_font_face_parser(parser)->state = STATE_KEY; + return 0; + } + return css_font_face_parser_parse_tail(parser); } int css_parser_parse_font_face(css_parser_t *parser) { - switch (get_css_font_face_parser(parser)->state) { - case STATE_HEAD: - return css_font_face_parser_parse_head(parser); - case STATE_KEY: - return FontFaceParser_ParseKey(parser); - case STATE_KEY_END: - return css_font_face_parser_parse_key_end(parser); - case STATE_VALUE: - return css_font_face_parser_parse_value(parser); - default: - break; - } - css_font_face_parser_end(parser); - return -1; + switch (get_css_font_face_parser(parser)->state) { + case STATE_HEAD: + return css_font_face_parser_parse_head(parser); + case STATE_KEY: + return FontFaceParser_ParseKey(parser); + case STATE_KEY_END: + return css_font_face_parser_parse_key_end(parser); + case STATE_VALUE: + return css_font_face_parser_parse_value(parser); + default: + break; + } + css_font_face_parser_end(parser); + return -1; } void css_font_face_parser_on_load(css_parser_t *parser, - void (*callback)(const css_font_face_t *)) + void (*callback)(const css_font_face_t *)) { - get_css_font_face_parser(parser)->callback = callback; + get_css_font_face_parser(parser)->callback = callback; } int css_font_face_parser_init(css_parser_t *parser) { - css_font_face_parser_t *data; - css_rule_parser_t *rule_parser; + css_font_face_parser_t *data; + css_rule_parser_t *rule_parser; - data = calloc(sizeof(css_font_face_parser_t), 1); - if (!data) { - return -ENOMEM; - } - data->face = calloc(sizeof(css_font_face_t), 1); - if (!data->face) { - free(data); - return -ENOMEM; - } - data->face->src = NULL; - data->face->font_family = NULL; - data->face->font_style = CSS_FONT_STYLE_NORMAL; - data->face->font_weight = CSS_FONT_WEIGHT_NORMAL; - rule_parser = &parser->rule_parsers[CSS_RULE_FONT_FACE]; - rule_parser->data = data; - rule_parser->parse = css_parser_parse_font_face; - rule_parser->begin = css_parser_begin_parse_font_face; - strcpy(rule_parser->name, "font-face"); - return 0; + data = calloc(sizeof(css_font_face_parser_t), 1); + if (!data) { + return -ENOMEM; + } + data->face = calloc(sizeof(css_font_face_t), 1); + if (!data->face) { + free(data); + return -ENOMEM; + } + data->face->src = NULL; + data->face->font_family = NULL; + data->face->font_style = CSS_FONT_STYLE_NORMAL; + data->face->font_weight = CSS_FONT_WEIGHT_NORMAL; + rule_parser = &parser->rule_parsers[CSS_RULE_FONT_FACE]; + rule_parser->data = data; + rule_parser->parse = css_parser_parse_font_face; + rule_parser->begin = css_parser_begin_parse_font_face; + strcpy(rule_parser->name, "font-face"); + return 0; } void css_font_face_parser_destroy(css_parser_t *parser) { - css_font_face_parser_t *data; + css_font_face_parser_t *data; - css_font_face_parser_end(parser); - data = get_css_font_face_parser(parser); - parser->rule_parsers[CSS_RULE_FONT_FACE].data = NULL; - free(data->face); - free(data); + css_font_face_parser_end(parser); + data = get_css_font_face_parser(parser); + parser->rule_parsers[CSS_RULE_FONT_FACE].data = NULL; + free(data->face); + free(data); } diff --git a/lib/css/src/keywords.c b/lib/css/src/keywords.c index 4c95e6f64..5531fb5a5 100644 --- a/lib/css/src/keywords.c +++ b/lib/css/src/keywords.c @@ -1,207 +1,210 @@ /* * lib/css/src/keywords.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include #include typedef struct css_keyword { - int key; - char *name; + int key; + char *name; } css_keyword_t; static struct css_keywords_module { - css_keyword_t **list; - unsigned used; - unsigned size; + css_keyword_t **list; + unsigned used; + unsigned size; - /** - * dict_t - */ - dict_t *name_map; + /** + * dict_t + */ + dict_t *name_map; } css_keywords; static void keyword_destroy(void *data) { - css_keyword_t *kw = data; - free(kw->name); - free(kw); + css_keyword_t *kw = data; + free(kw->name); + free(kw); } static css_keyword_t *keyword_create(int key, const char *name) { - css_keyword_t *kw; - kw = malloc(sizeof(css_keyword_t)); - kw->name = strdup2(name); - kw->key = key; - return kw; + css_keyword_t *kw; + kw = malloc(sizeof(css_keyword_t)); + kw->name = strdup2(name); + kw->key = key; + return kw; } static int css_set_keyword(int key, const char *name) { - unsigned i; - css_keyword_t **list; - css_keyword_t *kw; - - if ((unsigned)key >= css_keywords.size) { - i = css_keywords.size; - css_keywords.size += 32; - list = realloc(css_keywords.list, - css_keywords.size * sizeof(css_keyword_t *)); - if (!list) { - return -ENOMEM; - } - for (; i < css_keywords.size; ++i) { - list[i] = NULL; - } - css_keywords.list = list; - } - assert(css_keywords.list[key] == NULL); - kw = keyword_create(key, name); - css_keywords.list[key] = kw; - css_keywords.used++; - if (css_keywords.used <= (unsigned)key) { - css_keywords.used = (unsigned)key + 1; - } - if (dict_add(css_keywords.name_map, kw->name, kw) != 0) { - keyword_destroy(kw); - return -ENOMEM; - } - return 0; + unsigned i; + css_keyword_t **list; + css_keyword_t *kw; + + if ((unsigned)key >= css_keywords.size) { + i = css_keywords.size; + css_keywords.size += 32; + list = realloc(css_keywords.list, + css_keywords.size * sizeof(css_keyword_t *)); + if (!list) { + return -ENOMEM; + } + for (; i < css_keywords.size; ++i) { + list[i] = NULL; + } + css_keywords.list = list; + } + assert(css_keywords.list[key] == NULL); + kw = keyword_create(key, name); + css_keywords.list[key] = kw; + css_keywords.used++; + if (css_keywords.used <= (unsigned)key) { + css_keywords.used = (unsigned)key + 1; + } + if (dict_add(css_keywords.name_map, kw->name, kw) != 0) { + keyword_destroy(kw); + return -ENOMEM; + } + return 0; } int css_register_keyword(const char *name) { - int key = (int)css_keywords.used; - if (css_get_keyword_key(name) > 0) { - return -1; - } - if (css_set_keyword(key, name) == 0) { - return key; - } - return -1; + int key = (int)css_keywords.used; + if (css_get_keyword_key(name) > 0) { + return -1; + } + if (css_set_keyword(key, name) == 0) { + return key; + } + return -1; } int css_get_keyword_key(const char *name) { - css_keyword_t *kw; + css_keyword_t *kw; - kw = dict_fetch_value(css_keywords.name_map, name); - if (kw) { - return kw->key; - } - return -1; + kw = dict_fetch_value(css_keywords.name_map, name); + if (kw) { + return kw->key; + } + return -1; } const char *css_get_keyword_name(int val) { - if ((unsigned)val < css_keywords.size && css_keywords.list[val]) { - return css_keywords.list[val]->name; - } - return NULL; + if ((unsigned)val < css_keywords.size && css_keywords.list[val]) { + return css_keywords.list[val]->name; + } + return NULL; } void css_init_keywords(void) { - static dict_type_t names_dt = { 0 }; - - dict_init_string_key_type(&names_dt); - css_keywords.name_map = dict_create(&names_dt, NULL); - css_keywords.used = 0; - css_keywords.size = 0; - - css_set_keyword(CSS_KEYWORD_NONE, "none"); - css_set_keyword(CSS_KEYWORD_AUTO, "auto"); - css_set_keyword(CSS_KEYWORD_INHERIT, "inherit"); - css_set_keyword(CSS_KEYWORD_INITIAL, "initial"); - css_set_keyword(CSS_KEYWORD_NORMAL, "normal"); - - css_set_keyword(CSS_KEYWORD_LEFT, "left"); - css_set_keyword(CSS_KEYWORD_CENTER, "center"); - css_set_keyword(CSS_KEYWORD_RIGHT, "right"); - css_set_keyword(CSS_KEYWORD_TOP, "top"); - css_set_keyword(CSS_KEYWORD_MIDDLE, "middle"); - css_set_keyword(CSS_KEYWORD_BOTTOM, "bottom"); - - css_set_keyword(CSS_KEYWORD_STATIC, "static"); - css_set_keyword(CSS_KEYWORD_RELATIVE, "relative"); - css_set_keyword(CSS_KEYWORD_ABSOLUTE, "absolute"); - - css_set_keyword(CSS_KEYWORD_BLOCK, "block"); - css_set_keyword(CSS_KEYWORD_INLINE_BLOCK, "inline-block"); - css_set_keyword(CSS_KEYWORD_INLINE_FLEX, "inline-flex"); - css_set_keyword(CSS_KEYWORD_FLEX, "flex"); - - css_set_keyword(CSS_KEYWORD_START, "start"); - css_set_keyword(CSS_KEYWORD_END, "end"); - css_set_keyword(CSS_KEYWORD_FLEX_START, "flex-start"); - css_set_keyword(CSS_KEYWORD_FLEX_END, "flex-end"); - css_set_keyword(CSS_KEYWORD_STRETCH, "stretch"); - css_set_keyword(CSS_KEYWORD_SPACE_BETWEEN, "space-between"); - css_set_keyword(CSS_KEYWORD_SPACE_AROUND, "space-around"); - css_set_keyword(CSS_KEYWORD_SPACE_EVENLY, "space-evenly"); - - css_set_keyword(CSS_KEYWORD_ROW, "row"); - css_set_keyword(CSS_KEYWORD_COLUMN, "column"); - - css_set_keyword(CSS_KEYWORD_NOWRAP, "nowrap"); - css_set_keyword(CSS_KEYWORD_WRAP, "wrap"); - - css_set_keyword(CSS_KEYWORD_CONTENT_BOX, "content-box"); - css_set_keyword(CSS_KEYWORD_PADDING_BOX, "padding-box"); - css_set_keyword(CSS_KEYWORD_BORDER_BOX, "border-box"); - - css_set_keyword(CSS_KEYWORD_SOLID, "solid"); - css_set_keyword(CSS_KEYWORD_DOTTED, "dotted"); - css_set_keyword(CSS_KEYWORD_DOUBLE, "double"); - css_set_keyword(CSS_KEYWORD_DASHED, "dashed"); - - css_set_keyword(CSS_KEYWORD_CONTAIN, "contain"); - css_set_keyword(CSS_KEYWORD_COVER, "cover"); - css_set_keyword(CSS_KEYWORD_REPEAT, "repeat"); - css_set_keyword(CSS_KEYWORD_REPEAT_X, "repeat-x"); - css_set_keyword(CSS_KEYWORD_REPEAT_Y, "repeat-y"); - css_set_keyword(CSS_KEYWORD_NO_REPEAT, "no-repeat"); - - css_set_keyword(CSS_KEYWORD_BREAK_ALL, "break-all"); - - css_set_keyword(CSS_KEYWORD_ITALIC, "italic"); - css_set_keyword(CSS_KEYWORD_OBLIQUE, "oblique"); - css_set_keyword(CSS_KEYWORD_SMALL, "small"); - css_set_keyword(CSS_KEYWORD_MEDIUM, "medium"); - css_set_keyword(CSS_KEYWORD_LARGE, "large"); - css_set_keyword(CSS_KEYWORD_BOLD, "bold"); - - css_set_keyword(CSS_KEYWORD_VISIBLE, "visible"); - css_set_keyword(CSS_KEYWORD_HIDDEN, "hidden"); - - css_set_keyword(CSS_KEYWORD_FIT_CONTENT, "fit-content"); - css_set_keyword(CSS_KEYWORD_MIN_CONTENT, "min-content"); - css_set_keyword(CSS_KEYWORD_MAX_CONTENT, "max-content"); + static dict_type_t names_dt = { 0 }; + + dict_init_string_key_type(&names_dt); + css_keywords.name_map = dict_create(&names_dt, NULL); + css_keywords.used = 0; + css_keywords.size = 0; + + css_set_keyword(CSS_KEYWORD_NONE, "none"); + css_set_keyword(CSS_KEYWORD_AUTO, "auto"); + css_set_keyword(CSS_KEYWORD_INHERIT, "inherit"); + css_set_keyword(CSS_KEYWORD_INITIAL, "initial"); + css_set_keyword(CSS_KEYWORD_NORMAL, "normal"); + + css_set_keyword(CSS_KEYWORD_LEFT, "left"); + css_set_keyword(CSS_KEYWORD_CENTER, "center"); + css_set_keyword(CSS_KEYWORD_RIGHT, "right"); + css_set_keyword(CSS_KEYWORD_TOP, "top"); + css_set_keyword(CSS_KEYWORD_MIDDLE, "middle"); + css_set_keyword(CSS_KEYWORD_BOTTOM, "bottom"); + + css_set_keyword(CSS_KEYWORD_STATIC, "static"); + css_set_keyword(CSS_KEYWORD_RELATIVE, "relative"); + css_set_keyword(CSS_KEYWORD_ABSOLUTE, "absolute"); + + css_set_keyword(CSS_KEYWORD_BLOCK, "block"); + css_set_keyword(CSS_KEYWORD_INLINE_BLOCK, "inline-block"); + css_set_keyword(CSS_KEYWORD_INLINE_FLEX, "inline-flex"); + css_set_keyword(CSS_KEYWORD_FLEX, "flex"); + + css_set_keyword(CSS_KEYWORD_START, "start"); + css_set_keyword(CSS_KEYWORD_END, "end"); + css_set_keyword(CSS_KEYWORD_FLEX_START, "flex-start"); + css_set_keyword(CSS_KEYWORD_FLEX_END, "flex-end"); + css_set_keyword(CSS_KEYWORD_STRETCH, "stretch"); + css_set_keyword(CSS_KEYWORD_SPACE_BETWEEN, "space-between"); + css_set_keyword(CSS_KEYWORD_SPACE_AROUND, "space-around"); + css_set_keyword(CSS_KEYWORD_SPACE_EVENLY, "space-evenly"); + + css_set_keyword(CSS_KEYWORD_ROW, "row"); + css_set_keyword(CSS_KEYWORD_COLUMN, "column"); + + css_set_keyword(CSS_KEYWORD_NOWRAP, "nowrap"); + css_set_keyword(CSS_KEYWORD_WRAP, "wrap"); + + css_set_keyword(CSS_KEYWORD_CONTENT_BOX, "content-box"); + css_set_keyword(CSS_KEYWORD_PADDING_BOX, "padding-box"); + css_set_keyword(CSS_KEYWORD_BORDER_BOX, "border-box"); + + css_set_keyword(CSS_KEYWORD_SOLID, "solid"); + css_set_keyword(CSS_KEYWORD_DOTTED, "dotted"); + css_set_keyword(CSS_KEYWORD_DOUBLE, "double"); + css_set_keyword(CSS_KEYWORD_DASHED, "dashed"); + + css_set_keyword(CSS_KEYWORD_CONTAIN, "contain"); + css_set_keyword(CSS_KEYWORD_COVER, "cover"); + css_set_keyword(CSS_KEYWORD_REPEAT, "repeat"); + css_set_keyword(CSS_KEYWORD_REPEAT_X, "repeat-x"); + css_set_keyword(CSS_KEYWORD_REPEAT_Y, "repeat-y"); + css_set_keyword(CSS_KEYWORD_NO_REPEAT, "no-repeat"); + + css_set_keyword(CSS_KEYWORD_BREAK_ALL, "break-all"); + + css_set_keyword(CSS_KEYWORD_ITALIC, "italic"); + css_set_keyword(CSS_KEYWORD_OBLIQUE, "oblique"); + css_set_keyword(CSS_KEYWORD_SMALL, "small"); + css_set_keyword(CSS_KEYWORD_MEDIUM, "medium"); + css_set_keyword(CSS_KEYWORD_LARGE, "large"); + css_set_keyword(CSS_KEYWORD_BOLD, "bold"); + + css_set_keyword(CSS_KEYWORD_VISIBLE, "visible"); + css_set_keyword(CSS_KEYWORD_HIDDEN, "hidden"); + + css_set_keyword(CSS_KEYWORD_FIT_CONTENT, "fit-content"); + css_set_keyword(CSS_KEYWORD_MIN_CONTENT, "min-content"); + css_set_keyword(CSS_KEYWORD_MAX_CONTENT, "max-content"); } void css_destroy_keywords(void) { - unsigned i; - - dict_destroy(css_keywords.name_map); - for (i = 0; i < css_keywords.size; ++i) { - if (css_keywords.list[i]) { - keyword_destroy(css_keywords.list[i]); - css_keywords.list[i] = NULL; - } - } - free(css_keywords.list); - css_keywords.list = NULL; - css_keywords.name_map = NULL; - css_keywords.size = 0; - css_keywords.used = 0; + unsigned i; + + dict_destroy(css_keywords.name_map); + for (i = 0; i < css_keywords.size; ++i) { + if (css_keywords.list[i]) { + keyword_destroy(css_keywords.list[i]); + css_keywords.list[i] = NULL; + } + } + free(css_keywords.list); + css_keywords.list = NULL; + css_keywords.name_map = NULL; + css_keywords.size = 0; + css_keywords.used = 0; } diff --git a/lib/css/src/library.c b/lib/css/src/library.c index 8088d8220..8ec47927e 100644 --- a/lib/css/src/library.c +++ b/lib/css/src/library.c @@ -1,12 +1,15 @@ /* * lib/css/src/library.c: -- CSS library operation module. * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include @@ -445,7 +448,8 @@ static void css_each_style_link(css_style_link_t *link, const char *selector, char fullname[CSS_SELECTOR_MAX_LEN]; if (selector) { - snprintf(fullname, sizeof(fullname), "%s %s", link->group->name, selector); + snprintf(fullname, sizeof(fullname), "%s %s", link->group->name, + selector); } else { strcpy(fullname, link->group->name); } diff --git a/lib/css/src/main.c b/lib/css/src/main.c index 41767f2c6..e9eebad0a 100644 --- a/lib/css/src/main.c +++ b/lib/css/src/main.c @@ -1,29 +1,32 @@ /* * lib/css/src/main.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is + * part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT + * file in the root directory of this source tree. */ #include "../include/css.h" void css_init(void) { - css_init_value_definitons(); - css_init_data_types(); - css_init_library(); - css_init_keywords(); - css_init_properties(); + css_init_value_definitons(); + css_init_data_types(); + css_init_library(); + css_init_keywords(); + css_init_properties(); } void css_destroy(void) { - css_destroy_properties(); - css_destroy_keywords(); - css_destroy_library(); - css_destroy_value_definitons(); + css_destroy_properties(); + css_destroy_keywords(); + css_destroy_library(); + css_destroy_value_definitons(); } diff --git a/lib/css/src/parser.c b/lib/css/src/parser.c index 53e090278..c8f915572 100644 --- a/lib/css/src/parser.c +++ b/lib/css/src/parser.c @@ -1,12 +1,15 @@ /* * lib/css/src/parser.c: -- css parser module * - * Copyright (c) 2022-2025, Liu chao All rights reserved. - * + * Copyright (c) 2022-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include diff --git a/lib/css/src/parser.h b/lib/css/src/parser.h index c63ea88f7..e0f1d8232 100644 --- a/lib/css/src/parser.h +++ b/lib/css/src/parser.h @@ -1,7 +1,7 @@ /* * lib/css/src/parser.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -10,7 +10,7 @@ */ #define CASE_WHITE_SPACE \ - case ' ': \ - case '\n': \ - case '\r': \ - case '\t' + case ' ': \ + case '\n': \ + case '\r': \ + case '\t' diff --git a/lib/css/src/properties.c b/lib/css/src/properties.c index f20f56232..5b73c06d6 100644 --- a/lib/css/src/properties.c +++ b/lib/css/src/properties.c @@ -1,12 +1,15 @@ /* * lib/css/src/properties.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/css/src/properties.h b/lib/css/src/properties.h index b7c98d3a7..108dbbe3a 100644 --- a/lib/css/src/properties.h +++ b/lib/css/src/properties.h @@ -1,7 +1,7 @@ /* * lib/css/src/properties.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/css/src/properties/align_content.c b/lib/css/src/properties/align_content.c index 6e4b0949c..f066e1b53 100644 --- a/lib/css/src/properties/align_content.c +++ b/lib/css/src/properties/align_content.c @@ -1,43 +1,46 @@ /* * lib/css/src/properties/align_content.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" int css_cascade_align_content(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - uint8_t value = CSS_ALIGN_CONTENT_FLEX_START; + uint8_t value = CSS_ALIGN_CONTENT_FLEX_START; - switch (input[0].keyword_value) { - case CSS_KEYWORD_CENTER: - value = CSS_ALIGN_CONTENT_CENTER; - break; - case CSS_KEYWORD_FLEX_START: - value = CSS_ALIGN_CONTENT_FLEX_START; - break; - case CSS_KEYWORD_FLEX_END: - value = CSS_ALIGN_CONTENT_FLEX_END; - break; - case CSS_KEYWORD_SPACE_AROUND: - value = CSS_ALIGN_CONTENT_SPACE_AROUND; - break; - case CSS_KEYWORD_SPACE_BETWEEN: - value = CSS_ALIGN_CONTENT_SPACE_BETWEEN; - break; - case CSS_KEYWORD_SPACE_EVENLY: - value = CSS_ALIGN_CONTENT_SPACE_EVENLY; - break; - default: - break; - } - computed->type_bits.align_content = value; - return 0; + switch (input[0].keyword_value) { + case CSS_KEYWORD_CENTER: + value = CSS_ALIGN_CONTENT_CENTER; + break; + case CSS_KEYWORD_FLEX_START: + value = CSS_ALIGN_CONTENT_FLEX_START; + break; + case CSS_KEYWORD_FLEX_END: + value = CSS_ALIGN_CONTENT_FLEX_END; + break; + case CSS_KEYWORD_SPACE_AROUND: + value = CSS_ALIGN_CONTENT_SPACE_AROUND; + break; + case CSS_KEYWORD_SPACE_BETWEEN: + value = CSS_ALIGN_CONTENT_SPACE_BETWEEN; + break; + case CSS_KEYWORD_SPACE_EVENLY: + value = CSS_ALIGN_CONTENT_SPACE_EVENLY; + break; + default: + break; + } + computed->type_bits.align_content = value; + return 0; } diff --git a/lib/css/src/properties/align_items.c b/lib/css/src/properties/align_items.c index df2bcff3c..70a73c102 100644 --- a/lib/css/src/properties/align_items.c +++ b/lib/css/src/properties/align_items.c @@ -1,34 +1,37 @@ /* * lib/css/src/properties/align_items.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" int css_cascade_align_items(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - uint8_t value = CSS_ALIGN_ITEMS_STRETCH; + uint8_t value = CSS_ALIGN_ITEMS_STRETCH; - switch (input[0].keyword_value) { - case CSS_KEYWORD_CENTER: - value = CSS_ALIGN_ITEMS_CENTER; - break; - case CSS_KEYWORD_FLEX_START: - value = CSS_ALIGN_ITEMS_FLEX_START; - break; - case CSS_KEYWORD_FLEX_END: - value = CSS_ALIGN_ITEMS_FLEX_END; - break; - default: - break; - } - computed->type_bits.align_items = value; - return 0; + switch (input[0].keyword_value) { + case CSS_KEYWORD_CENTER: + value = CSS_ALIGN_ITEMS_CENTER; + break; + case CSS_KEYWORD_FLEX_START: + value = CSS_ALIGN_ITEMS_FLEX_START; + break; + case CSS_KEYWORD_FLEX_END: + value = CSS_ALIGN_ITEMS_FLEX_END; + break; + default: + break; + } + computed->type_bits.align_items = value; + return 0; } diff --git a/lib/css/src/properties/background.c b/lib/css/src/properties/background.c index 9e913d446..18f6fb33b 100644 --- a/lib/css/src/properties/background.c +++ b/lib/css/src/properties/background.c @@ -1,11 +1,14 @@ /* * lib/css/src/properties/background.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ @@ -310,8 +313,8 @@ static void css_parse_background_position_1(css_style_value_t *input, * background-position-x = calc(100% - 50px) * background-position-y = calc(100% - 50px) */ -int css_parse_background_position(const css_propdef_t *propdef, const char *input, - css_style_decl_t *s) +int css_parse_background_position(const css_propdef_t *propdef, + const char *input, css_style_decl_t *s) { unsigned len; const char *cur; diff --git a/lib/css/src/properties/border.c b/lib/css/src/properties/border.c index 8d5b34355..2848d3941 100644 --- a/lib/css/src/properties/border.c +++ b/lib/css/src/properties/border.c @@ -1,12 +1,15 @@ /* * lib/css/src/properties/border.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" diff --git a/lib/css/src/properties/bottom.c b/lib/css/src/properties/bottom.c index e72859b4a..a0934fb5d 100644 --- a/lib/css/src/properties/bottom.c +++ b/lib/css/src/properties/bottom.c @@ -1,27 +1,30 @@ /* * lib/css/src/properties/bottom.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" #include "./helpers.h" -static void set_bottom(css_computed_style_t* computed, uint8_t keyword, - css_numeric_value_t value, css_unit_t unit) +static void set_bottom(css_computed_style_t *computed, uint8_t keyword, + css_numeric_value_t value, css_unit_t unit) { - computed->bottom = value; - computed->unit_bits.bottom = unit; - computed->type_bits.bottom = keyword; + computed->bottom = value; + computed->unit_bits.bottom = unit; + computed->type_bits.bottom = keyword; } int css_cascade_bottom(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - return css_cascade_length_auto(input, computed, set_bottom); + return css_cascade_length_auto(input, computed, set_bottom); } diff --git a/lib/css/src/properties/box_shadow.c b/lib/css/src/properties/box_shadow.c index e6374bab9..c6e5d33b2 100644 --- a/lib/css/src/properties/box_shadow.c +++ b/lib/css/src/properties/box_shadow.c @@ -1,60 +1,63 @@ /* * lib/css/src/properties/box_shadow.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" int css_cascade_box_shadow(const css_style_array_value_t input, - css_computed_style_t* s) + css_computed_style_t *s) { - unsigned count; + unsigned count; - s->box_shadow_x = 0; - s->box_shadow_y = 0; - s->box_shadow_blur = 0; - s->box_shadow_spread = 0; - if (input[0].type == CSS_KEYWORD_VALUE) { - if (input[0].keyword_value == CSS_KEYWORD_NONE) { - s->type_bits.box_shadow = CSS_BOX_SHADOW_NONE; - } - return 0; - } - for (count = 0; count < 4; ++count) { - if (input[count].type == CSS_NO_VALUE || - input[count].type == CSS_COLOR_VALUE) { - break; - } - } - s->type_bits.box_shadow = CSS_BOX_SHADOW_SET; - s->box_shadow_x = input[0].unit_value.value; - s->box_shadow_y = input[1].unit_value.value; - s->unit_bits.box_shadow_x = input[0].unit_value.unit; - s->unit_bits.box_shadow_y = input[1].unit_value.unit; - if (count > 2) { - s->box_shadow_blur = input[2].unit_value.value; - s->unit_bits.box_shadow_blur = input[2].unit_value.unit; - } else { - s->box_shadow_blur = 0; - s->unit_bits.box_shadow_blur = 0; - } - if (count > 3) { - s->box_shadow_spread = input[3].unit_value.value; - s->unit_bits.box_shadow_spread = input[3].unit_value.unit; - } else { - s->box_shadow_spread = 0; - s->unit_bits.box_shadow_spread = 0; - } - if (input[count].type == CSS_COLOR_VALUE) { - s->box_shadow_color = input[count].color_value; - } else { - s->box_shadow_color = CSS_COLOR_TRANSPARENT; - } - return 0; + s->box_shadow_x = 0; + s->box_shadow_y = 0; + s->box_shadow_blur = 0; + s->box_shadow_spread = 0; + if (input[0].type == CSS_KEYWORD_VALUE) { + if (input[0].keyword_value == CSS_KEYWORD_NONE) { + s->type_bits.box_shadow = CSS_BOX_SHADOW_NONE; + } + return 0; + } + for (count = 0; count < 4; ++count) { + if (input[count].type == CSS_NO_VALUE || + input[count].type == CSS_COLOR_VALUE) { + break; + } + } + s->type_bits.box_shadow = CSS_BOX_SHADOW_SET; + s->box_shadow_x = input[0].unit_value.value; + s->box_shadow_y = input[1].unit_value.value; + s->unit_bits.box_shadow_x = input[0].unit_value.unit; + s->unit_bits.box_shadow_y = input[1].unit_value.unit; + if (count > 2) { + s->box_shadow_blur = input[2].unit_value.value; + s->unit_bits.box_shadow_blur = input[2].unit_value.unit; + } else { + s->box_shadow_blur = 0; + s->unit_bits.box_shadow_blur = 0; + } + if (count > 3) { + s->box_shadow_spread = input[3].unit_value.value; + s->unit_bits.box_shadow_spread = input[3].unit_value.unit; + } else { + s->box_shadow_spread = 0; + s->unit_bits.box_shadow_spread = 0; + } + if (input[count].type == CSS_COLOR_VALUE) { + s->box_shadow_color = input[count].color_value; + } else { + s->box_shadow_color = CSS_COLOR_TRANSPARENT; + } + return 0; } diff --git a/lib/css/src/properties/box_sizing.c b/lib/css/src/properties/box_sizing.c index 645b7ac16..df01987f9 100644 --- a/lib/css/src/properties/box_sizing.c +++ b/lib/css/src/properties/box_sizing.c @@ -1,28 +1,31 @@ /* * lib/css/src/properties/box_sizing.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" int css_cascade_box_sizing(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - uint8_t value = CSS_BOX_SIZING_CONTENT_BOX; + uint8_t value = CSS_BOX_SIZING_CONTENT_BOX; - switch (input[0].keyword_value) { - case CSS_KEYWORD_BORDER_BOX: - value = CSS_BOX_SIZING_BORDER_BOX; - break; - default: - break; - } - computed->type_bits.box_sizing = value; - return 0; + switch (input[0].keyword_value) { + case CSS_KEYWORD_BORDER_BOX: + value = CSS_BOX_SIZING_BORDER_BOX; + break; + default: + break; + } + computed->type_bits.box_sizing = value; + return 0; } diff --git a/lib/css/src/properties/color.c b/lib/css/src/properties/color.c index 1cf294d51..e3443a240 100644 --- a/lib/css/src/properties/color.c +++ b/lib/css/src/properties/color.c @@ -1,26 +1,29 @@ /* * lib/css/src/properties/color.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "./helpers.h" int css_cascade_color(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - switch (input[0].type) { - case CSS_COLOR_VALUE: - computed->color = input[0].color_value; - computed->type_bits.color = CSS_COLOR_COLOR; - break; - default: - return -1; - } - return 0; + switch (input[0].type) { + case CSS_COLOR_VALUE: + computed->color = input[0].color_value; + computed->type_bits.color = CSS_COLOR_COLOR; + break; + default: + return -1; + } + return 0; } diff --git a/lib/css/src/properties/content.c b/lib/css/src/properties/content.c index e30a0f429..c27fca546 100644 --- a/lib/css/src/properties/content.c +++ b/lib/css/src/properties/content.c @@ -1,25 +1,28 @@ /* * lib/css/src/properties/content.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" int css_cascade_content(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - if (input[0].type == CSS_STRING_VALUE && input[0].string_value) { - computed->content = strdup2(input[0].string_value); - computed->type_bits.content = CSS_CONTENT_SET; - } else { - computed->content = NULL; - computed->type_bits.content = CSS_CONTENT_NONE; - } - return 0; + if (input[0].type == CSS_STRING_VALUE && input[0].string_value) { + computed->content = strdup2(input[0].string_value); + computed->type_bits.content = CSS_CONTENT_SET; + } else { + computed->content = NULL; + computed->type_bits.content = CSS_CONTENT_NONE; + } + return 0; } diff --git a/lib/css/src/properties/display.c b/lib/css/src/properties/display.c index 3990462ae..eb55d064b 100644 --- a/lib/css/src/properties/display.c +++ b/lib/css/src/properties/display.c @@ -1,40 +1,43 @@ /* * lib/css/src/properties/display.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" int css_cascade_display(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - uint8_t value = CSS_DISPLAY_BLOCK; + uint8_t value = CSS_DISPLAY_BLOCK; - switch (input[0].keyword_value) { - case CSS_KEYWORD_NONE: - value = CSS_DISPLAY_NONE; - break; - case CSS_KEYWORD_BLOCK: - value = CSS_DISPLAY_BLOCK; - break; - case CSS_KEYWORD_INLINE_BLOCK: - value = CSS_DISPLAY_INLINE_BLOCK; - break; - case CSS_KEYWORD_FLEX: - value = CSS_DISPLAY_FLEX; - break; - case CSS_KEYWORD_INLINE_FLEX: - value = CSS_DISPLAY_INLINE_FLEX; - break; - default: - break; - } - computed->type_bits.display = value; - return 0; + switch (input[0].keyword_value) { + case CSS_KEYWORD_NONE: + value = CSS_DISPLAY_NONE; + break; + case CSS_KEYWORD_BLOCK: + value = CSS_DISPLAY_BLOCK; + break; + case CSS_KEYWORD_INLINE_BLOCK: + value = CSS_DISPLAY_INLINE_BLOCK; + break; + case CSS_KEYWORD_FLEX: + value = CSS_DISPLAY_FLEX; + break; + case CSS_KEYWORD_INLINE_FLEX: + value = CSS_DISPLAY_INLINE_FLEX; + break; + default: + break; + } + computed->type_bits.display = value; + return 0; } diff --git a/lib/css/src/properties/flex.c b/lib/css/src/properties/flex.c index 71e6788ee..659dfc0cc 100644 --- a/lib/css/src/properties/flex.c +++ b/lib/css/src/properties/flex.c @@ -1,204 +1,207 @@ /* * lib/css/src/properties/flex.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" #include "./helpers.h" static void set_flex_basis(css_computed_style_t *computed, uint8_t keyword, - css_numeric_value_t value, css_unit_t unit) + css_numeric_value_t value, css_unit_t unit) { - computed->flex_basis = value; - computed->unit_bits.flex_basis = unit; - computed->type_bits.flex_basis = keyword; + computed->flex_basis = value; + computed->unit_bits.flex_basis = unit; + computed->type_bits.flex_basis = keyword; } int css_cascade_flex_basis(const css_style_array_value_t input, - css_computed_style_t *computed) + css_computed_style_t *computed) { - return css_cascade_length_auto(input, computed, set_flex_basis); + return css_cascade_length_auto(input, computed, set_flex_basis); } int css_cascade_flex_direction(const css_style_array_value_t input, - css_computed_style_t *computed) + css_computed_style_t *computed) { - uint8_t value = CSS_FLEX_DIRECTION_ROW; - - switch (input[0].keyword_value) { - case CSS_KEYWORD_COLUMN: - value = CSS_FLEX_DIRECTION_COLUMN; - default: - break; - } - computed->type_bits.flex_direction = value; - return 0; + uint8_t value = CSS_FLEX_DIRECTION_ROW; + + switch (input[0].keyword_value) { + case CSS_KEYWORD_COLUMN: + value = CSS_FLEX_DIRECTION_COLUMN; + default: + break; + } + computed->type_bits.flex_direction = value; + return 0; } int css_cascade_flex_grow(const css_style_array_value_t input, - css_computed_style_t *computed) + css_computed_style_t *computed) { - if (input[0].type != CSS_NUMERIC_VALUE) { - return -1; - } - computed->flex_grow = input[0].numeric_value; - if (computed->flex_grow < 0) { - computed->flex_grow = 0; - } - computed->type_bits.flex_grow = CSS_FLEX_GROW_SET; - return 0; + if (input[0].type != CSS_NUMERIC_VALUE) { + return -1; + } + computed->flex_grow = input[0].numeric_value; + if (computed->flex_grow < 0) { + computed->flex_grow = 0; + } + computed->type_bits.flex_grow = CSS_FLEX_GROW_SET; + return 0; } int css_cascade_flex_shrink(const css_style_array_value_t input, - css_computed_style_t *computed) + css_computed_style_t *computed) { - if (input[0].type != CSS_NUMERIC_VALUE) { - return -1; - } - computed->flex_shrink = input[0].numeric_value; - if (computed->flex_shrink < 0) { - computed->flex_shrink = 1; - } - computed->type_bits.flex_shrink = CSS_FLEX_SHRINK_SET; - return 0; + if (input[0].type != CSS_NUMERIC_VALUE) { + return -1; + } + computed->flex_shrink = input[0].numeric_value; + if (computed->flex_shrink < 0) { + computed->flex_shrink = 1; + } + computed->type_bits.flex_shrink = CSS_FLEX_SHRINK_SET; + return 0; } int css_cascade_flex_wrap(const css_style_array_value_t input, - css_computed_style_t *computed) + css_computed_style_t *computed) { - uint8_t value = CSS_FLEX_WRAP_NOWRAP; - - switch (input[0].keyword_value) { - case CSS_KEYWORD_WRAP: - value = CSS_FLEX_WRAP_WRAP; - default: - break; - } - computed->type_bits.flex_wrap = value; - return 0; + uint8_t value = CSS_FLEX_WRAP_NOWRAP; + + switch (input[0].keyword_value) { + case CSS_KEYWORD_WRAP: + value = CSS_FLEX_WRAP_WRAP; + default: + break; + } + computed->type_bits.flex_wrap = value; + return 0; } static void css_parse_flex_1(const css_style_array_value_t input, - css_style_decl_t *s) + css_style_decl_t *s) { - css_style_value_t val[] = { - { .type = CSS_NUMERIC_VALUE, .numeric_value = 0 }, - { .type = CSS_NUMERIC_VALUE, .numeric_value = 1 }, - { .type = CSS_KEYWORD_VALUE, .keyword_value = CSS_KEYWORD_AUTO } - }; - - switch (input[0].type) { - case CSS_NUMERIC_VALUE: - // flex: 1 0 - val[0].numeric_value = input[0].numeric_value; - val[2].type = CSS_NUMERIC_VALUE; - val[2].numeric_value = 0; - break; - case CSS_UNIT_VALUE: - // flex: 1 1 - val[0].numeric_value = 1; - val[2] = input[0]; - break; - case CSS_KEYWORD_VALUE: - switch (input[0].keyword_value) { - case CSS_KEYWORD_AUTO: - // flex: 1 1 auto - val[0].numeric_value = 1; - break; - case CSS_KEYWORD_NONE: - // flex: 0 0 auto - val[0].numeric_value = 0; - val[1].numeric_value = 0; - break; - case CSS_KEYWORD_INITIAL: - // flex: 0 1 auto - break; - default: - return; - } - break; - default: - return; - } - css_style_decl_add(s, css_prop_flex_grow, val); - css_style_decl_add(s, css_prop_flex_shrink, val + 1); - css_style_decl_add(s, css_prop_flex_basis, val + 2); + css_style_value_t val[] = { + { .type = CSS_NUMERIC_VALUE, .numeric_value = 0 }, + { .type = CSS_NUMERIC_VALUE, .numeric_value = 1 }, + { .type = CSS_KEYWORD_VALUE, .keyword_value = CSS_KEYWORD_AUTO } + }; + + switch (input[0].type) { + case CSS_NUMERIC_VALUE: + // flex: 1 0 + val[0].numeric_value = input[0].numeric_value; + val[2].type = CSS_NUMERIC_VALUE; + val[2].numeric_value = 0; + break; + case CSS_UNIT_VALUE: + // flex: 1 1 + val[0].numeric_value = 1; + val[2] = input[0]; + break; + case CSS_KEYWORD_VALUE: + switch (input[0].keyword_value) { + case CSS_KEYWORD_AUTO: + // flex: 1 1 auto + val[0].numeric_value = 1; + break; + case CSS_KEYWORD_NONE: + // flex: 0 0 auto + val[0].numeric_value = 0; + val[1].numeric_value = 0; + break; + case CSS_KEYWORD_INITIAL: + // flex: 0 1 auto + break; + default: + return; + } + break; + default: + return; + } + css_style_decl_add(s, css_prop_flex_grow, val); + css_style_decl_add(s, css_prop_flex_shrink, val + 1); + css_style_decl_add(s, css_prop_flex_basis, val + 2); } static void css_parse_flex_2(const css_style_array_value_t input, - css_style_decl_t *s) + css_style_decl_t *s) { - if (input[0].type != CSS_NUMERIC_VALUE) { - return; - } - css_style_decl_add(s, css_prop_flex_grow, input); - switch (input[1].type) { - case CSS_NUMERIC_VALUE: - css_style_decl_add(s, css_prop_flex_shrink, input + 1); - break; - case CSS_UNIT_VALUE: - css_style_decl_add(s, css_prop_flex_basis, input + 1); - break; - default: - break; - } + if (input[0].type != CSS_NUMERIC_VALUE) { + return; + } + css_style_decl_add(s, css_prop_flex_grow, input); + switch (input[1].type) { + case CSS_NUMERIC_VALUE: + css_style_decl_add(s, css_prop_flex_shrink, input + 1); + break; + case CSS_UNIT_VALUE: + css_style_decl_add(s, css_prop_flex_basis, input + 1); + break; + default: + break; + } } static void css_parse_flex_3(const css_style_array_value_t input, - css_style_decl_t *s) + css_style_decl_t *s) { - int8_t i; - int8_t has_flex_grow = 0; - int8_t has_flex_shrink = 0; - int8_t has_flex_basis = 0; - - for (i = 0; i < 3 && input[i].type != CSS_NO_VALUE; ++i) { - if (!has_flex_grow && input[i].type == CSS_NUMERIC_VALUE) { - css_style_decl_add(s, css_prop_flex_grow, input + i); - has_flex_grow = 1; - } else if (!has_flex_shrink && - input[i].type == CSS_NUMERIC_VALUE) { - css_style_decl_add(s, css_prop_flex_shrink, input + i); - has_flex_shrink = 1; - } else if (!has_flex_basis && - (input[i].type == CSS_KEYWORD_VALUE || - input[i].type == CSS_UNIT_VALUE)) { - css_style_decl_add(s, css_prop_flex_basis, input + i); - has_flex_basis = 1; - } else { - break; - } - } + int8_t i; + int8_t has_flex_grow = 0; + int8_t has_flex_shrink = 0; + int8_t has_flex_basis = 0; + + for (i = 0; i < 3 && input[i].type != CSS_NO_VALUE; ++i) { + if (!has_flex_grow && input[i].type == CSS_NUMERIC_VALUE) { + css_style_decl_add(s, css_prop_flex_grow, input + i); + has_flex_grow = 1; + } else if (!has_flex_shrink && + input[i].type == CSS_NUMERIC_VALUE) { + css_style_decl_add(s, css_prop_flex_shrink, input + i); + has_flex_shrink = 1; + } else if (!has_flex_basis && + (input[i].type == CSS_KEYWORD_VALUE || + input[i].type == CSS_UNIT_VALUE)) { + css_style_decl_add(s, css_prop_flex_basis, input + i); + has_flex_basis = 1; + } else { + break; + } + } } int css_parse_flex(const css_propdef_t *propdef, const char *input, - css_style_decl_t *s) + css_style_decl_t *s) { - css_style_value_t value; - int len = css_parse_value(propdef->valdef, input, &value); - - if (len <= 0) { - return len; - } - switch (css_style_value_get_array_length(&value)) { - case 1: - css_parse_flex_1(value.array_value, s); - break; - case 2: - css_parse_flex_2(value.array_value, s); - break; - case 3: - css_parse_flex_3(value.array_value, s); - break; - default: - break; - } - css_style_value_destroy(&value); - return len; + css_style_value_t value; + int len = css_parse_value(propdef->valdef, input, &value); + + if (len <= 0) { + return len; + } + switch (css_style_value_get_array_length(&value)) { + case 1: + css_parse_flex_1(value.array_value, s); + break; + case 2: + css_parse_flex_2(value.array_value, s); + break; + case 3: + css_parse_flex_3(value.array_value, s); + break; + default: + break; + } + css_style_value_destroy(&value); + return len; } diff --git a/lib/css/src/properties/font_family.c b/lib/css/src/properties/font_family.c index ddc7f3fcc..86f510c23 100644 --- a/lib/css/src/properties/font_family.c +++ b/lib/css/src/properties/font_family.c @@ -1,11 +1,14 @@ /* * lib/css/src/properties/font_family.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ @@ -13,11 +16,11 @@ #include "./helpers.h" int css_cascade_font_family(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - char* str; + char *str; unsigned i, len; - size_t str_len; + size_t str_len; const css_style_array_value_t arr = input[0].array_value; computed->font_family = NULL; @@ -29,7 +32,7 @@ int css_cascade_font_family(const css_style_array_value_t input, if (len < 1) { return -1; } - computed->font_family = malloc(sizeof(char*) * (len + 1)); + computed->font_family = malloc(sizeof(char *) * (len + 1)); for (i = 0; i < len; ++i) { assert(arr[i].type == CSS_STRING_VALUE); str = arr[i].string_value; diff --git a/lib/css/src/properties/font_size.c b/lib/css/src/properties/font_size.c index 32406f4a5..9f24354ea 100644 --- a/lib/css/src/properties/font_size.c +++ b/lib/css/src/properties/font_size.c @@ -1,41 +1,44 @@ /* * lib/css/src/properties/font_size.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" #include "./helpers.h" int css_cascade_font_size(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - computed->type_bits.font_size = CSS_FONT_SIZE_MEDIUM; - switch (input[0].type) { - case CSS_UNIT_VALUE: - computed->font_size = input[0].unit_value.value; - computed->unit_bits.font_size = input[0].unit_value.unit; - computed->type_bits.font_size = CSS_FONT_SIZE_DIMENSION; - break; - case CSS_KEYWORD_VALUE: - switch (input[0].keyword_value) { - case CSS_KEYWORD_SMALL: - computed->type_bits.font_size = CSS_FONT_SIZE_SMALL; - break; - case CSS_KEYWORD_LARGE: - computed->type_bits.font_size = CSS_FONT_SIZE_LARGE; - break; - default: - break; - } - break; - default: - return -1; - } - return 0; + computed->type_bits.font_size = CSS_FONT_SIZE_MEDIUM; + switch (input[0].type) { + case CSS_UNIT_VALUE: + computed->font_size = input[0].unit_value.value; + computed->unit_bits.font_size = input[0].unit_value.unit; + computed->type_bits.font_size = CSS_FONT_SIZE_DIMENSION; + break; + case CSS_KEYWORD_VALUE: + switch (input[0].keyword_value) { + case CSS_KEYWORD_SMALL: + computed->type_bits.font_size = CSS_FONT_SIZE_SMALL; + break; + case CSS_KEYWORD_LARGE: + computed->type_bits.font_size = CSS_FONT_SIZE_LARGE; + break; + default: + break; + } + break; + default: + return -1; + } + return 0; } diff --git a/lib/css/src/properties/font_style.c b/lib/css/src/properties/font_style.c index 2e3c20ba0..44ec7b7ff 100644 --- a/lib/css/src/properties/font_style.c +++ b/lib/css/src/properties/font_style.c @@ -1,31 +1,34 @@ /* * lib/css/src/properties/font_style.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" int css_cascade_font_style(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - uint8_t value = CSS_FONT_STYLE_NORMAL; + uint8_t value = CSS_FONT_STYLE_NORMAL; - switch (input[0].keyword_value) { - case CSS_KEYWORD_OBLIQUE: - value = CSS_FONT_STYLE_OBLIQUE; - break; - case CSS_KEYWORD_ITALIC: - value = CSS_FONT_STYLE_ITALIC; - break; - default: - break; - } - computed->type_bits.font_style = value; - return 0; + switch (input[0].keyword_value) { + case CSS_KEYWORD_OBLIQUE: + value = CSS_FONT_STYLE_OBLIQUE; + break; + case CSS_KEYWORD_ITALIC: + value = CSS_FONT_STYLE_ITALIC; + break; + default: + break; + } + computed->type_bits.font_style = value; + return 0; } diff --git a/lib/css/src/properties/font_weight.c b/lib/css/src/properties/font_weight.c index 5738c2ebf..db306b20f 100644 --- a/lib/css/src/properties/font_weight.c +++ b/lib/css/src/properties/font_weight.c @@ -1,69 +1,72 @@ /* * lib/css/src/properties/font_weight.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" int css_cascade_font_weight(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - uint8_t value = CSS_FONT_STYLE_NORMAL; + uint8_t value = CSS_FONT_STYLE_NORMAL; - switch (input[0].type) { - case CSS_KEYWORD_VALUE: - switch (input[0].keyword_value) { - case CSS_KEYWORD_NORMAL: - value = CSS_FONT_WEIGHT_NORMAL; - break; - case CSS_KEYWORD_BOLD: - value = CSS_FONT_WEIGHT_BOLD; - break; - default: - break; - } - break; - case CSS_NUMERIC_VALUE: - switch ((int)input[0].numeric_value) { - case 100: - value = CSS_FONT_WEIGHT_100; - break; - case 200: - value = CSS_FONT_WEIGHT_200; - break; - case 300: - value = CSS_FONT_WEIGHT_300; - break; - case 400: - value = CSS_FONT_WEIGHT_400; - break; - case 500: - value = CSS_FONT_WEIGHT_500; - break; - case 600: - value = CSS_FONT_WEIGHT_600; - break; - case 700: - value = CSS_FONT_WEIGHT_700; - break; - case 800: - value = CSS_FONT_WEIGHT_800; - break; - case 900: - value = CSS_FONT_WEIGHT_900; - break; - default: - break; - } - default: - break; - } - computed->type_bits.font_weight = value; - return 0; + switch (input[0].type) { + case CSS_KEYWORD_VALUE: + switch (input[0].keyword_value) { + case CSS_KEYWORD_NORMAL: + value = CSS_FONT_WEIGHT_NORMAL; + break; + case CSS_KEYWORD_BOLD: + value = CSS_FONT_WEIGHT_BOLD; + break; + default: + break; + } + break; + case CSS_NUMERIC_VALUE: + switch ((int)input[0].numeric_value) { + case 100: + value = CSS_FONT_WEIGHT_100; + break; + case 200: + value = CSS_FONT_WEIGHT_200; + break; + case 300: + value = CSS_FONT_WEIGHT_300; + break; + case 400: + value = CSS_FONT_WEIGHT_400; + break; + case 500: + value = CSS_FONT_WEIGHT_500; + break; + case 600: + value = CSS_FONT_WEIGHT_600; + break; + case 700: + value = CSS_FONT_WEIGHT_700; + break; + case 800: + value = CSS_FONT_WEIGHT_800; + break; + case 900: + value = CSS_FONT_WEIGHT_900; + break; + default: + break; + } + default: + break; + } + computed->type_bits.font_weight = value; + return 0; } diff --git a/lib/css/src/properties/gap.c b/lib/css/src/properties/gap.c index 2549a377f..2319f04c5 100644 --- a/lib/css/src/properties/gap.c +++ b/lib/css/src/properties/gap.c @@ -1,12 +1,15 @@ /* * lib/css/src/properties/gap.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" diff --git a/lib/css/src/properties/height.c b/lib/css/src/properties/height.c index db4d477cf..3a4ef1dc2 100644 --- a/lib/css/src/properties/height.c +++ b/lib/css/src/properties/height.c @@ -1,27 +1,30 @@ /* * lib/css/src/properties/height.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" #include "./helpers.h" -static void set_height(css_computed_style_t* computed, uint8_t keyword, - css_numeric_value_t value, css_unit_t unit) +static void set_height(css_computed_style_t *computed, uint8_t keyword, + css_numeric_value_t value, css_unit_t unit) { - computed->height = value; - computed->unit_bits.height = unit; - computed->type_bits.height = keyword; + computed->height = value; + computed->unit_bits.height = unit; + computed->type_bits.height = keyword; } int css_cascade_height(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - return css_cascade_length_auto(input, computed, set_height); + return css_cascade_length_auto(input, computed, set_height); } diff --git a/lib/css/src/properties/helpers.c b/lib/css/src/properties/helpers.c index fcd457999..74c3a9f12 100644 --- a/lib/css/src/properties/helpers.c +++ b/lib/css/src/properties/helpers.c @@ -1,20 +1,23 @@ /* * lib/css/src/properties/helpers.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "helpers.h" #include "../properties.h" int css_cascade_length_auto(const css_style_array_value_t input, - css_computed_style_t* computed, - void (*setter)(css_computed_style_t*, uint8_t, + css_computed_style_t *computed, + void (*setter)(css_computed_style_t *, uint8_t, css_numeric_value_t, css_unit_t)) { switch (input[0].type) { @@ -41,8 +44,8 @@ int css_cascade_length_auto(const css_style_array_value_t input, } int css_cascade_bg_border_color(const css_style_array_value_t input, - css_computed_style_t* computed, - void (*setter)(css_computed_style_t*, uint8_t, + css_computed_style_t *computed, + void (*setter)(css_computed_style_t *, uint8_t, css_color_value_t)) { switch (input[0].type) { diff --git a/lib/css/src/properties/helpers.h b/lib/css/src/properties/helpers.h index 09a25cc8b..977115d78 100644 --- a/lib/css/src/properties/helpers.h +++ b/lib/css/src/properties/helpers.h @@ -1,12 +1,15 @@ /* * lib/css/src/properties/helpers.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_CSS_SRC_PROPERTIES_HELPERS_H @@ -15,12 +18,12 @@ #include int css_cascade_length_auto(const css_style_array_value_t input, - css_computed_style_t* computed, - void (*setter)(css_computed_style_t*, uint8_t, - css_numeric_value_t, css_unit_t)); + css_computed_style_t *computed, + void (*setter)(css_computed_style_t *, uint8_t, + css_numeric_value_t, css_unit_t)); int css_cascade_bg_border_color(const css_style_array_value_t input, - css_computed_style_t* computed, - void (*setter)(css_computed_style_t*, uint8_t, - css_color_value_t)); + css_computed_style_t *computed, + void (*setter)(css_computed_style_t *, uint8_t, + css_color_value_t)); #endif diff --git a/lib/css/src/properties/justify_content.c b/lib/css/src/properties/justify_content.c index ca72f0fc1..26ccef7bc 100644 --- a/lib/css/src/properties/justify_content.c +++ b/lib/css/src/properties/justify_content.c @@ -1,45 +1,48 @@ /* * lib/css/src/properties/justify_content.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, + * Liu Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" int css_cascade_justify_content(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - uint8_t value = CSS_JUSTIFY_CONTENT_FLEX_START; + uint8_t value = CSS_JUSTIFY_CONTENT_FLEX_START; - switch (input[0].keyword_value) { - case CSS_KEYWORD_CENTER: - value = CSS_JUSTIFY_CONTENT_CENTER; - break; - case CSS_KEYWORD_LEFT: - case CSS_KEYWORD_FLEX_START: - value = CSS_JUSTIFY_CONTENT_FLEX_START; - break; - case CSS_KEYWORD_RIGHT: - case CSS_KEYWORD_FLEX_END: - value = CSS_JUSTIFY_CONTENT_FLEX_END; - break; - case CSS_KEYWORD_SPACE_AROUND: - value = CSS_JUSTIFY_CONTENT_SPACE_AROUND; - break; - case CSS_KEYWORD_SPACE_BETWEEN: - value = CSS_JUSTIFY_CONTENT_SPACE_BETWEEN; - break; - case CSS_KEYWORD_SPACE_EVENLY: - value = CSS_JUSTIFY_CONTENT_SPACE_EVENLY; - break; - default: - break; - } - computed->type_bits.justify_content = value; - return 0; + switch (input[0].keyword_value) { + case CSS_KEYWORD_CENTER: + value = CSS_JUSTIFY_CONTENT_CENTER; + break; + case CSS_KEYWORD_LEFT: + case CSS_KEYWORD_FLEX_START: + value = CSS_JUSTIFY_CONTENT_FLEX_START; + break; + case CSS_KEYWORD_RIGHT: + case CSS_KEYWORD_FLEX_END: + value = CSS_JUSTIFY_CONTENT_FLEX_END; + break; + case CSS_KEYWORD_SPACE_AROUND: + value = CSS_JUSTIFY_CONTENT_SPACE_AROUND; + break; + case CSS_KEYWORD_SPACE_BETWEEN: + value = CSS_JUSTIFY_CONTENT_SPACE_BETWEEN; + break; + case CSS_KEYWORD_SPACE_EVENLY: + value = CSS_JUSTIFY_CONTENT_SPACE_EVENLY; + break; + default: + break; + } + computed->type_bits.justify_content = value; + return 0; } diff --git a/lib/css/src/properties/left.c b/lib/css/src/properties/left.c index 22bac3845..ff6d532ed 100644 --- a/lib/css/src/properties/left.c +++ b/lib/css/src/properties/left.c @@ -1,27 +1,30 @@ /* * lib/css/src/properties/left.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" #include "./helpers.h" -static void set_left(css_computed_style_t* computed, uint8_t keyword, - css_numeric_value_t value, css_unit_t unit) +static void set_left(css_computed_style_t *computed, uint8_t keyword, + css_numeric_value_t value, css_unit_t unit) { - computed->left = value; - computed->unit_bits.left = unit; - computed->type_bits.left = keyword; + computed->left = value; + computed->unit_bits.left = unit; + computed->type_bits.left = keyword; } int css_cascade_left(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - return css_cascade_length_auto(input, computed, set_left); + return css_cascade_length_auto(input, computed, set_left); } diff --git a/lib/css/src/properties/line_height.c b/lib/css/src/properties/line_height.c index 96e00e364..2f921a0ce 100644 --- a/lib/css/src/properties/line_height.c +++ b/lib/css/src/properties/line_height.c @@ -1,11 +1,14 @@ /* * lib/css/src/properties/line_height.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ @@ -13,25 +16,26 @@ #include "./helpers.h" int css_cascade_line_height(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - switch (input[0].type) { - case CSS_UNIT_VALUE: - computed->line_height = input[0].unit_value.value; - computed->unit_bits.line_height = input[0].unit_value.unit; - computed->type_bits.line_height = CSS_LINE_HEIGHT_DIMENSION; - break; - case CSS_NUMERIC_VALUE: - computed->line_height = input[0].numeric_value; - computed->type_bits.line_height = CSS_LINE_HEIGHT_NUMBER; - break; - case CSS_KEYWORD_VALUE: - if (input[0].keyword_value == CSS_KEYWORD_NORMAL) { - computed->type_bits.line_height = CSS_LINE_HEIGHT_NORMAL; - break; - } - default: - return -1; - } - return 0; + switch (input[0].type) { + case CSS_UNIT_VALUE: + computed->line_height = input[0].unit_value.value; + computed->unit_bits.line_height = input[0].unit_value.unit; + computed->type_bits.line_height = CSS_LINE_HEIGHT_DIMENSION; + break; + case CSS_NUMERIC_VALUE: + computed->line_height = input[0].numeric_value; + computed->type_bits.line_height = CSS_LINE_HEIGHT_NUMBER; + break; + case CSS_KEYWORD_VALUE: + if (input[0].keyword_value == CSS_KEYWORD_NORMAL) { + computed->type_bits.line_height = + CSS_LINE_HEIGHT_NORMAL; + break; + } + default: + return -1; + } + return 0; } diff --git a/lib/css/src/properties/margin.c b/lib/css/src/properties/margin.c index 11d69b0fa..02256957c 100644 --- a/lib/css/src/properties/margin.c +++ b/lib/css/src/properties/margin.c @@ -1,32 +1,35 @@ /* * lib/css/src/properties/margin.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" #include "./helpers.h" #define CSS_CASCADE_MARGIN_SIDE(PROP_KEY) \ - static void set_margin_##PROP_KEY( \ - css_computed_style_t *computed, uint8_t keyword, \ - css_numeric_value_t value, css_unit_t unit) \ - { \ - computed->margin_##PROP_KEY = value; \ - computed->unit_bits.margin_##PROP_KEY = unit; \ - computed->type_bits.margin_##PROP_KEY = keyword; \ - } \ - int css_cascade_margin_##PROP_KEY(const css_style_array_value_t input, \ - css_computed_style_t *computed) \ - { \ - return css_cascade_length_auto(input, computed, \ - set_margin_##PROP_KEY); \ - } + static void set_margin_##PROP_KEY( \ + css_computed_style_t *computed, uint8_t keyword, \ + css_numeric_value_t value, css_unit_t unit) \ + { \ + computed->margin_##PROP_KEY = value; \ + computed->unit_bits.margin_##PROP_KEY = unit; \ + computed->type_bits.margin_##PROP_KEY = keyword; \ + } \ + int css_cascade_margin_##PROP_KEY(const css_style_array_value_t input, \ + css_computed_style_t *computed) \ + { \ + return css_cascade_length_auto(input, computed, \ + set_margin_##PROP_KEY); \ + } CSS_CASCADE_MARGIN_SIDE(top) CSS_CASCADE_MARGIN_SIDE(right) @@ -34,50 +37,52 @@ CSS_CASCADE_MARGIN_SIDE(bottom) CSS_CASCADE_MARGIN_SIDE(left) int css_parse_margin(const css_propdef_t *propdef, const char *input, - css_style_decl_t *s) + css_style_decl_t *s) { - css_style_value_t value; - int len = css_parse_value(propdef->valdef, input, &value); + css_style_value_t value; + int len = css_parse_value(propdef->valdef, input, &value); - if (len <= 0) { - return len; - } - switch (css_style_value_get_array_length(&value)) { - case 1: - css_style_decl_add(s, css_prop_margin_top, value.array_value); - css_style_decl_add(s, css_prop_margin_right, value.array_value); - css_style_decl_add(s, css_prop_margin_bottom, value.array_value); - css_style_decl_add(s, css_prop_margin_left, value.array_value); - break; - case 2: - css_style_decl_add(s, css_prop_margin_top, value.array_value); - css_style_decl_add(s, css_prop_margin_bottom, value.array_value); - css_style_decl_add(s, css_prop_margin_left, - value.array_value + 1); - css_style_decl_add(s, css_prop_margin_right, - value.array_value + 1); - break; - case 3: - css_style_decl_add(s, css_prop_margin_top, value.array_value); - css_style_decl_add(s, css_prop_margin_left, - value.array_value + 1); - css_style_decl_add(s, css_prop_margin_right, - value.array_value + 1); - css_style_decl_add(s, css_prop_margin_bottom, - value.array_value + 2); - break; - case 4: - css_style_decl_add(s, css_prop_margin_top, value.array_value); - css_style_decl_add(s, css_prop_margin_right, - value.array_value + 1); - css_style_decl_add(s, css_prop_margin_bottom, - value.array_value + 2); - css_style_decl_add(s, css_prop_margin_left, - value.array_value + 3); - break; - default: - break; - } - css_style_value_destroy(&value); - return len; + if (len <= 0) { + return len; + } + switch (css_style_value_get_array_length(&value)) { + case 1: + css_style_decl_add(s, css_prop_margin_top, value.array_value); + css_style_decl_add(s, css_prop_margin_right, value.array_value); + css_style_decl_add(s, css_prop_margin_bottom, + value.array_value); + css_style_decl_add(s, css_prop_margin_left, value.array_value); + break; + case 2: + css_style_decl_add(s, css_prop_margin_top, value.array_value); + css_style_decl_add(s, css_prop_margin_bottom, + value.array_value); + css_style_decl_add(s, css_prop_margin_left, + value.array_value + 1); + css_style_decl_add(s, css_prop_margin_right, + value.array_value + 1); + break; + case 3: + css_style_decl_add(s, css_prop_margin_top, value.array_value); + css_style_decl_add(s, css_prop_margin_left, + value.array_value + 1); + css_style_decl_add(s, css_prop_margin_right, + value.array_value + 1); + css_style_decl_add(s, css_prop_margin_bottom, + value.array_value + 2); + break; + case 4: + css_style_decl_add(s, css_prop_margin_top, value.array_value); + css_style_decl_add(s, css_prop_margin_right, + value.array_value + 1); + css_style_decl_add(s, css_prop_margin_bottom, + value.array_value + 2); + css_style_decl_add(s, css_prop_margin_left, + value.array_value + 3); + break; + default: + break; + } + css_style_value_destroy(&value); + return len; } diff --git a/lib/css/src/properties/max_height.c b/lib/css/src/properties/max_height.c index 2bf650a36..9940e9a43 100644 --- a/lib/css/src/properties/max_height.c +++ b/lib/css/src/properties/max_height.c @@ -1,28 +1,30 @@ /* * lib/css/src/properties/max_height.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" #include "./helpers.h" -static void set_max_height(css_computed_style_t* computed, - uint8_t keyword, css_numeric_value_t value, - css_unit_t unit) +static void set_max_height(css_computed_style_t *computed, uint8_t keyword, + css_numeric_value_t value, css_unit_t unit) { - computed->max_height = value; - computed->unit_bits.max_height = unit; - computed->type_bits.max_height = keyword; + computed->max_height = value; + computed->unit_bits.max_height = unit; + computed->type_bits.max_height = keyword; } int css_cascade_max_height(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - return css_cascade_length_auto(input, computed, set_max_height); + return css_cascade_length_auto(input, computed, set_max_height); } diff --git a/lib/css/src/properties/max_width.c b/lib/css/src/properties/max_width.c index 71b607ff6..a56dc047f 100644 --- a/lib/css/src/properties/max_width.c +++ b/lib/css/src/properties/max_width.c @@ -1,27 +1,30 @@ /* * lib/css/src/properties/max_width.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" #include "./helpers.h" -static void set_max_width(css_computed_style_t* computed, uint8_t keyword, - css_numeric_value_t value, css_unit_t unit) +static void set_max_width(css_computed_style_t *computed, uint8_t keyword, + css_numeric_value_t value, css_unit_t unit) { - computed->max_width = value; - computed->unit_bits.max_width = unit; - computed->type_bits.max_width = keyword; + computed->max_width = value; + computed->unit_bits.max_width = unit; + computed->type_bits.max_width = keyword; } int css_cascade_max_width(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - return css_cascade_length_auto(input, computed, set_max_width); + return css_cascade_length_auto(input, computed, set_max_width); } diff --git a/lib/css/src/properties/min_height.c b/lib/css/src/properties/min_height.c index 59078e4f6..98d94a714 100644 --- a/lib/css/src/properties/min_height.c +++ b/lib/css/src/properties/min_height.c @@ -1,33 +1,36 @@ /* * lib/css/src/properties/min_height.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" #include "./helpers.h" -static void set_min_height(css_computed_style_t* computed, - uint8_t keyword, css_numeric_value_t value, - css_unit_t unit) +static void set_min_height(css_computed_style_t *computed, uint8_t keyword, + css_numeric_value_t value, css_unit_t unit) { - computed->min_height = value; - computed->unit_bits.min_height = unit; - computed->type_bits.min_height = keyword; + computed->min_height = value; + computed->unit_bits.min_height = unit; + computed->type_bits.min_height = keyword; } int css_cascade_min_height(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { if (input[0].type == CSS_KEYWORD_VALUE && input[0].keyword_value == CSS_KEYWORD_MIN_CONTENT) { - set_min_height(computed, CSS_MIN_WIDTH_MIN_CONTENT, 0, CSS_UNIT_PX); + set_min_height(computed, CSS_MIN_WIDTH_MIN_CONTENT, 0, + CSS_UNIT_PX); return 0; } - return css_cascade_length_auto(input, computed, set_min_height); + return css_cascade_length_auto(input, computed, set_min_height); } diff --git a/lib/css/src/properties/min_width.c b/lib/css/src/properties/min_width.c index 3c27ac0a4..85798c839 100644 --- a/lib/css/src/properties/min_width.c +++ b/lib/css/src/properties/min_width.c @@ -1,18 +1,21 @@ /* * lib/css/src/properties/min_width.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" #include "./helpers.h" -static void set_min_width(css_computed_style_t* computed, uint8_t keyword, +static void set_min_width(css_computed_style_t *computed, uint8_t keyword, css_numeric_value_t value, css_unit_t unit) { computed->min_width = value; @@ -21,11 +24,12 @@ static void set_min_width(css_computed_style_t* computed, uint8_t keyword, } int css_cascade_min_width(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { if (input[0].type == CSS_KEYWORD_VALUE && input[0].keyword_value == CSS_KEYWORD_MIN_CONTENT) { - set_min_width(computed, CSS_MIN_WIDTH_MIN_CONTENT, 0, CSS_UNIT_PX); + set_min_width(computed, CSS_MIN_WIDTH_MIN_CONTENT, 0, + CSS_UNIT_PX); return 0; } return css_cascade_length_auto(input, computed, set_min_width); diff --git a/lib/css/src/properties/opacity.c b/lib/css/src/properties/opacity.c index 8da2d1650..d659f7563 100644 --- a/lib/css/src/properties/opacity.c +++ b/lib/css/src/properties/opacity.c @@ -1,7 +1,7 @@ /* * lib/css/src/properties/opacity.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -12,9 +12,9 @@ #include "../properties.h" int css_cascade_opacity(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - computed->opacity = input[0].numeric_value; - computed->type_bits.opacity = CSS_OPACITY_SET; - return 0; + computed->opacity = input[0].numeric_value; + computed->type_bits.opacity = CSS_OPACITY_SET; + return 0; } diff --git a/lib/css/src/properties/padding.c b/lib/css/src/properties/padding.c index 3582edb3f..f463909d8 100644 --- a/lib/css/src/properties/padding.c +++ b/lib/css/src/properties/padding.c @@ -1,33 +1,36 @@ /* * lib/css/src/properties/padding.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" #include "./helpers.h" #define CSS_CASCADE_PADDING_SIDE(PROP_KEY) \ - static void set_padding_##PROP_KEY( \ - css_computed_style_t *computed, uint8_t keyword, \ - css_numeric_value_t value, css_unit_t unit) \ - { \ - computed->padding_##PROP_KEY = value; \ - computed->unit_bits.padding_##PROP_KEY = unit; \ - computed->type_bits.padding_##PROP_KEY = keyword; \ - } \ - int css_cascade_padding_##PROP_KEY( \ - const css_style_array_value_t input, \ - css_computed_style_t *computed) \ - { \ - return css_cascade_length_auto(input, computed, \ - set_padding_##PROP_KEY); \ - } + static void set_padding_##PROP_KEY( \ + css_computed_style_t *computed, uint8_t keyword, \ + css_numeric_value_t value, css_unit_t unit) \ + { \ + computed->padding_##PROP_KEY = value; \ + computed->unit_bits.padding_##PROP_KEY = unit; \ + computed->type_bits.padding_##PROP_KEY = keyword; \ + } \ + int css_cascade_padding_##PROP_KEY( \ + const css_style_array_value_t input, \ + css_computed_style_t *computed) \ + { \ + return css_cascade_length_auto(input, computed, \ + set_padding_##PROP_KEY); \ + } CSS_CASCADE_PADDING_SIDE(top) CSS_CASCADE_PADDING_SIDE(right) @@ -35,52 +38,53 @@ CSS_CASCADE_PADDING_SIDE(bottom) CSS_CASCADE_PADDING_SIDE(left) int css_parse_padding(const css_propdef_t *propdef, const char *input, - css_style_decl_t *s) + css_style_decl_t *s) { - css_style_value_t value; - int len = css_parse_value(propdef->valdef, input, &value); + css_style_value_t value; + int len = css_parse_value(propdef->valdef, input, &value); - if (len <= 0) { - return len; - } - switch (css_style_value_get_array_length(&value)) { - case 1: - css_style_decl_add(s, css_prop_padding_top, value.array_value); - css_style_decl_add(s, css_prop_padding_right, value.array_value); - css_style_decl_add(s, css_prop_padding_bottom, - value.array_value); - css_style_decl_add(s, css_prop_padding_left, value.array_value); - break; - case 2: - css_style_decl_add(s, css_prop_padding_top, value.array_value); - css_style_decl_add(s, css_prop_padding_bottom, - value.array_value); - css_style_decl_add(s, css_prop_padding_left, - value.array_value + 1); - css_style_decl_add(s, css_prop_padding_right, - value.array_value + 1); - break; - case 3: - css_style_decl_add(s, css_prop_padding_top, value.array_value); - css_style_decl_add(s, css_prop_padding_left, - value.array_value + 1); - css_style_decl_add(s, css_prop_padding_right, - value.array_value + 1); - css_style_decl_add(s, css_prop_padding_bottom, - value.array_value + 2); - break; - case 4: - css_style_decl_add(s, css_prop_padding_top, value.array_value); - css_style_decl_add(s, css_prop_padding_right, - value.array_value + 1); - css_style_decl_add(s, css_prop_padding_bottom, - value.array_value + 2); - css_style_decl_add(s, css_prop_padding_left, - value.array_value + 3); - break; - default: - break; - } - css_style_value_destroy(&value); - return len; + if (len <= 0) { + return len; + } + switch (css_style_value_get_array_length(&value)) { + case 1: + css_style_decl_add(s, css_prop_padding_top, value.array_value); + css_style_decl_add(s, css_prop_padding_right, + value.array_value); + css_style_decl_add(s, css_prop_padding_bottom, + value.array_value); + css_style_decl_add(s, css_prop_padding_left, value.array_value); + break; + case 2: + css_style_decl_add(s, css_prop_padding_top, value.array_value); + css_style_decl_add(s, css_prop_padding_bottom, + value.array_value); + css_style_decl_add(s, css_prop_padding_left, + value.array_value + 1); + css_style_decl_add(s, css_prop_padding_right, + value.array_value + 1); + break; + case 3: + css_style_decl_add(s, css_prop_padding_top, value.array_value); + css_style_decl_add(s, css_prop_padding_left, + value.array_value + 1); + css_style_decl_add(s, css_prop_padding_right, + value.array_value + 1); + css_style_decl_add(s, css_prop_padding_bottom, + value.array_value + 2); + break; + case 4: + css_style_decl_add(s, css_prop_padding_top, value.array_value); + css_style_decl_add(s, css_prop_padding_right, + value.array_value + 1); + css_style_decl_add(s, css_prop_padding_bottom, + value.array_value + 2); + css_style_decl_add(s, css_prop_padding_left, + value.array_value + 3); + break; + default: + break; + } + css_style_value_destroy(&value); + return len; } diff --git a/lib/css/src/properties/pointer_events.c b/lib/css/src/properties/pointer_events.c index bd5517f28..54a83091e 100644 --- a/lib/css/src/properties/pointer_events.c +++ b/lib/css/src/properties/pointer_events.c @@ -1,27 +1,30 @@ /* * lib/css/src/properties/pointer_events.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" int css_cascade_pointer_events(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - uint8_t value = CSS_POINTER_EVENTS_AUTO; + uint8_t value = CSS_POINTER_EVENTS_AUTO; - switch (input[0].keyword_value) { - case CSS_KEYWORD_NONE: - value = CSS_POINTER_EVENTS_NONE; - default: - break; - } - computed->type_bits.pointer_events = value; - return 0; + switch (input[0].keyword_value) { + case CSS_KEYWORD_NONE: + value = CSS_POINTER_EVENTS_NONE; + default: + break; + } + computed->type_bits.pointer_events = value; + return 0; } diff --git a/lib/css/src/properties/position.c b/lib/css/src/properties/position.c index 3eae69e43..0a5c7c5bc 100644 --- a/lib/css/src/properties/position.c +++ b/lib/css/src/properties/position.c @@ -1,31 +1,34 @@ /* * lib/css/src/properties/position.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" int css_cascade_position(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - uint8_t value = CSS_POSITION_STATIC; + uint8_t value = CSS_POSITION_STATIC; - switch (input[0].keyword_value) { - case CSS_KEYWORD_ABSOLUTE: - value = CSS_POSITION_ABSOLUTE; - break; - case CSS_KEYWORD_RELATIVE: - value = CSS_POSITION_RELATIVE; - break; - default: - break; - } - computed->type_bits.position = value; - return 0; + switch (input[0].keyword_value) { + case CSS_KEYWORD_ABSOLUTE: + value = CSS_POSITION_ABSOLUTE; + break; + case CSS_KEYWORD_RELATIVE: + value = CSS_POSITION_RELATIVE; + break; + default: + break; + } + computed->type_bits.position = value; + return 0; } diff --git a/lib/css/src/properties/right.c b/lib/css/src/properties/right.c index 4f262c92f..b55f6b3ee 100644 --- a/lib/css/src/properties/right.c +++ b/lib/css/src/properties/right.c @@ -1,27 +1,30 @@ /* * lib/css/src/properties/right.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" #include "./helpers.h" -static void set_right(css_computed_style_t* computed, uint8_t keyword, - css_numeric_value_t value, css_unit_t unit) +static void set_right(css_computed_style_t *computed, uint8_t keyword, + css_numeric_value_t value, css_unit_t unit) { - computed->right = value; - computed->unit_bits.right = unit; - computed->type_bits.right = keyword; + computed->right = value; + computed->unit_bits.right = unit; + computed->type_bits.right = keyword; } int css_cascade_right(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - return css_cascade_length_auto(input, computed, set_right); + return css_cascade_length_auto(input, computed, set_right); } diff --git a/lib/css/src/properties/text_align.c b/lib/css/src/properties/text_align.c index 51308e032..fec50a068 100644 --- a/lib/css/src/properties/text_align.c +++ b/lib/css/src/properties/text_align.c @@ -1,31 +1,34 @@ /* * lib/css/src/properties/text_align.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" int css_cascade_text_align(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - uint8_t value = CSS_TEXT_ALIGN_LEFT; + uint8_t value = CSS_TEXT_ALIGN_LEFT; - switch (input[0].keyword_value) { - case CSS_KEYWORD_CENTER: - value = CSS_TEXT_ALIGN_CENTER; - break; - case CSS_KEYWORD_RIGHT: - value = CSS_TEXT_ALIGN_RIGHT; - break; - default: - break; - } - computed->type_bits.text_align = value; - return 0; + switch (input[0].keyword_value) { + case CSS_KEYWORD_CENTER: + value = CSS_TEXT_ALIGN_CENTER; + break; + case CSS_KEYWORD_RIGHT: + value = CSS_TEXT_ALIGN_RIGHT; + break; + default: + break; + } + computed->type_bits.text_align = value; + return 0; } diff --git a/lib/css/src/properties/top.c b/lib/css/src/properties/top.c index 33c1489f7..48ac55fce 100644 --- a/lib/css/src/properties/top.c +++ b/lib/css/src/properties/top.c @@ -1,27 +1,30 @@ /* * lib/css/src/properties/top.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" #include "./helpers.h" -static void set_top(css_computed_style_t* computed, uint8_t keyword, - css_numeric_value_t value, css_unit_t unit) +static void set_top(css_computed_style_t *computed, uint8_t keyword, + css_numeric_value_t value, css_unit_t unit) { - computed->top = value; - computed->unit_bits.top = unit; - computed->type_bits.top = keyword; + computed->top = value; + computed->unit_bits.top = unit; + computed->type_bits.top = keyword; } int css_cascade_top(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - return css_cascade_length_auto(input, computed, set_top); + return css_cascade_length_auto(input, computed, set_top); } diff --git a/lib/css/src/properties/vertical_align.c b/lib/css/src/properties/vertical_align.c index 9d75fa8b1..09f8b38e3 100644 --- a/lib/css/src/properties/vertical_align.c +++ b/lib/css/src/properties/vertical_align.c @@ -1,33 +1,36 @@ /* * lib/css/src/properties/vertical_align.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" int css_cascade_vertical_align(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - css_vertical_align_t value; + css_vertical_align_t value; - switch (input[0].keyword_value) { - case CSS_KEYWORD_MIDDLE: - value = CSS_VERTICAL_ALIGN_MIDDLE; - break; - case CSS_KEYWORD_BOTTOM: - value = CSS_VERTICAL_ALIGN_BOTTOM; - break; - case CSS_KEYWORD_TOP: - default: - value = CSS_VERTICAL_ALIGN_TOP; - break; - } - computed->type_bits.vertical_align = value; - return 0; + switch (input[0].keyword_value) { + case CSS_KEYWORD_MIDDLE: + value = CSS_VERTICAL_ALIGN_MIDDLE; + break; + case CSS_KEYWORD_BOTTOM: + value = CSS_VERTICAL_ALIGN_BOTTOM; + break; + case CSS_KEYWORD_TOP: + default: + value = CSS_VERTICAL_ALIGN_TOP; + break; + } + computed->type_bits.vertical_align = value; + return 0; } diff --git a/lib/css/src/properties/visibility.c b/lib/css/src/properties/visibility.c index 21686fff5..676eb47df 100644 --- a/lib/css/src/properties/visibility.c +++ b/lib/css/src/properties/visibility.c @@ -1,28 +1,31 @@ /* * lib/css/src/properties/visibility.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" int css_cascade_visibility(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - uint8_t value = CSS_VISIBILITY_VISIBLE; + uint8_t value = CSS_VISIBILITY_VISIBLE; - switch (input[0].keyword_value) { - case CSS_KEYWORD_HIDDEN: - value = CSS_VISIBILITY_HIDDEN; - break; - default: - break; - } - computed->type_bits.visibility = value; - return 0; + switch (input[0].keyword_value) { + case CSS_KEYWORD_HIDDEN: + value = CSS_VISIBILITY_HIDDEN; + break; + default: + break; + } + computed->type_bits.visibility = value; + return 0; } diff --git a/lib/css/src/properties/white_space.c b/lib/css/src/properties/white_space.c index e2166092a..225dc022a 100644 --- a/lib/css/src/properties/white_space.c +++ b/lib/css/src/properties/white_space.c @@ -1,26 +1,29 @@ /* * lib/css/src/properties/white_space.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" int css_cascade_white_space(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - computed->type_bits.white_space = CSS_WHITE_SPACE_NORMAL; - switch (input[0].keyword_value) { - case CSS_KEYWORD_NOWRAP: - computed->type_bits.white_space = CSS_WHITE_SPACE_NOWRAP; - break; - default: - break; - } - return 0; + computed->type_bits.white_space = CSS_WHITE_SPACE_NORMAL; + switch (input[0].keyword_value) { + case CSS_KEYWORD_NOWRAP: + computed->type_bits.white_space = CSS_WHITE_SPACE_NOWRAP; + break; + default: + break; + } + return 0; } diff --git a/lib/css/src/properties/width.c b/lib/css/src/properties/width.c index 42281ec4b..659c88dff 100644 --- a/lib/css/src/properties/width.c +++ b/lib/css/src/properties/width.c @@ -1,27 +1,30 @@ /* * lib/css/src/properties/width.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" #include "./helpers.h" -static void set_width(css_computed_style_t* computed, uint8_t keyword, - css_numeric_value_t value, css_unit_t unit) +static void set_width(css_computed_style_t *computed, uint8_t keyword, + css_numeric_value_t value, css_unit_t unit) { - computed->width = value; - computed->unit_bits.width = unit; - computed->type_bits.width = keyword; + computed->width = value; + computed->unit_bits.width = unit; + computed->type_bits.width = keyword; } int css_cascade_width(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - return css_cascade_length_auto(input, computed, set_width); + return css_cascade_length_auto(input, computed, set_width); } diff --git a/lib/css/src/properties/word_break.c b/lib/css/src/properties/word_break.c index 899637ae1..dcb1e13c2 100644 --- a/lib/css/src/properties/word_break.c +++ b/lib/css/src/properties/word_break.c @@ -1,26 +1,29 @@ /* * lib/css/src/properties/word_break.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" int css_cascade_word_break(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - computed->type_bits.word_break = CSS_WORD_BREAK_NORMAL; - switch (input[0].keyword_value) { - case CSS_KEYWORD_BREAK_ALL: - computed->type_bits.word_break = CSS_WORD_BREAK_BREAK_ALL; - break; - default: - break; - } - return 0; + computed->type_bits.word_break = CSS_WORD_BREAK_NORMAL; + switch (input[0].keyword_value) { + case CSS_KEYWORD_BREAK_ALL: + computed->type_bits.word_break = CSS_WORD_BREAK_BREAK_ALL; + break; + default: + break; + } + return 0; } diff --git a/lib/css/src/properties/z_index.c b/lib/css/src/properties/z_index.c index f747648a1..b39d917a1 100644 --- a/lib/css/src/properties/z_index.c +++ b/lib/css/src/properties/z_index.c @@ -1,24 +1,27 @@ /* * lib/css/src/properties/z_index.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../properties.h" int css_cascade_z_index(const css_style_array_value_t input, - css_computed_style_t* computed) + css_computed_style_t *computed) { - if (input[0].type == CSS_NUMERIC_VALUE) { - computed->z_index = input[0].numeric_value; - } else { - computed->z_index = 0; - } - computed->type_bits.z_index = CSS_Z_INDEX_SET; - return 0; + if (input[0].type == CSS_NUMERIC_VALUE) { + computed->z_index = input[0].numeric_value; + } else { + computed->z_index = 0; + } + computed->type_bits.z_index = CSS_Z_INDEX_SET; + return 0; } diff --git a/lib/css/src/selector.c b/lib/css/src/selector.c index 1447418ff..02eb538db 100644 --- a/lib/css/src/selector.c +++ b/lib/css/src/selector.c @@ -1,12 +1,15 @@ /* * lib/css/src/selector.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -36,10 +39,10 @@ enum css_selector_name_finder_level { /* 样式表查找器的上下文数据结构 */ typedef struct css_selector_name_collector { - int level; /**< 当前选择器层级 */ - int class_i; /**< 当前处理到第几个类名 */ - int status_i; /**< 当前处理到第几个状态名(伪类名) */ - int name_i; /**< 选择器名称从第几个字符开始 */ + int level; /**< 当前选择器层级 */ + int class_i; /**< 当前处理到第几个类名 */ + int status_i; /**< 当前处理到第几个状态名(伪类名) */ + int name_i; /**< 选择器名称从第几个字符开始 */ char name[MAX_NAME_LEN]; /**< 选择器名称缓存 */ css_selector_node_t *node; /**< 针对的选择器结点 */ } css_selector_name_collector_t; @@ -111,7 +114,8 @@ static int css_selector_collect_name(css_selector_name_collector_t *sfinder, for (i = 0; sfinder->node->classes[i]; ++i) { sfinder->level += 1; sfinder->class_i = i; - snprintf(fullname + len, avail - len, "%s", sfinder->node->classes[i]); + snprintf(fullname + len, avail - len, "%s", + sfinder->node->classes[i]); list_append(list, strdup2(fullname)); /* 将当前选择器名与其它层级的选择器名组合 */ while (sfinder->level < LEVEL_TOTAL_NUM) { @@ -460,7 +464,7 @@ css_selector_t *css_selector_create(const char *selector) break; } } - escape = false; + escape = false; if (!name_valid) { type = 0; name_valid = true; diff --git a/lib/css/src/style_decl.c b/lib/css/src/style_decl.c index f4fe8ac93..ecb566d0c 100644 --- a/lib/css/src/style_decl.c +++ b/lib/css/src/style_decl.c @@ -1,12 +1,15 @@ /* * lib/css/src/style_decl.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/css/src/style_parser.c b/lib/css/src/style_parser.c index afae220d1..0233fee0f 100644 --- a/lib/css/src/style_parser.c +++ b/lib/css/src/style_parser.c @@ -1,12 +1,15 @@ /* * lib/css/src/style_parser.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -17,69 +20,69 @@ static char *getdirname(const char *path) { - char *dirname; - size_t i, pos; - for (i = 0, pos = SIZE_MAX; path[i]; ++i) { - if (path[i] == '/') { - pos = i; - } - } - if (pos > i) { - return NULL; - } - dirname = malloc(sizeof(char) * i); - if (!dirname) { - return NULL; - } - for (i = 0; i < pos; ++i) { - dirname[i] = path[i]; - } - dirname[i] = 0; - return dirname; + char *dirname; + size_t i, pos; + for (i = 0, pos = SIZE_MAX; path[i]; ++i) { + if (path[i] == '/') { + pos = i; + } + } + if (pos > i) { + return NULL; + } + dirname = malloc(sizeof(char) * i); + if (!dirname) { + return NULL; + } + for (i = 0; i < pos; ++i) { + dirname[i] = path[i]; + } + dirname[i] = 0; + return dirname; } void css_style_parser_init(css_style_parser_t *parser, const char *space) { - parser->property = NULL; - parser->style_handler = NULL; - parser->style_handler_arg = NULL; - list_create(&parser->selectors); - if (space) { - parser->space = strdup2(space); - parser->dirname = getdirname(parser->space); - } else { - parser->dirname = NULL; - parser->space = NULL; - } + parser->property = NULL; + parser->style_handler = NULL; + parser->style_handler_arg = NULL; + list_create(&parser->selectors); + if (space) { + parser->space = strdup2(space); + parser->dirname = getdirname(parser->space); + } else { + parser->dirname = NULL; + parser->space = NULL; + } } void css_style_parser_destroy(css_style_parser_t *parser) { - list_destroy(&parser->selectors, - (list_item_destructor_t)css_selector_destroy); - if (parser->dirname) { - free(parser->dirname); - } - if (parser->space) { - free(parser->space); - } - if (parser->property) { - free(parser->property); - } - parser->space = NULL; - parser->dirname = NULL; - parser->property = NULL; + list_destroy(&parser->selectors, + (list_item_destructor_t)css_selector_destroy); + if (parser->dirname) { + free(parser->dirname); + } + if (parser->space) { + free(parser->space); + } + if (parser->property) { + free(parser->property); + } + parser->space = NULL; + parser->dirname = NULL; + parser->property = NULL; } void css_style_parser_commit(css_style_parser_t *parser) { - list_node_t *node; + list_node_t *node; - /* 将记录的样式表添加至匹配到的选择器中 */ - for (list_each(node, &parser->selectors)) { - css_add_style_decl(node->data, parser->style, parser->space); - } - list_destroy(&parser->selectors, - (list_item_destructor_t)css_selector_destroy); - css_style_decl_destroy(parser->style); + /* 将记录的样式表添加至匹配到的选择器中 */ + for (list_each(node, &parser->selectors)) { + css_add_style_decl(node->data, parser->style, parser->space); + } + list_destroy(&parser->selectors, + (list_item_destructor_t)css_selector_destroy); + css_style_decl_destroy(parser->style); } diff --git a/lib/css/src/style_value.c b/lib/css/src/style_value.c index 8eaa072dd..35c6a96b7 100644 --- a/lib/css/src/style_value.c +++ b/lib/css/src/style_value.c @@ -1,12 +1,15 @@ /* * lib/css/src/style_value.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -20,259 +23,258 @@ unsigned css_array_value_get_length(const css_style_array_value_t val) { - unsigned len; + unsigned len; - if (!val) { - return 0; - } - for (len = 0; val[len].type != CSS_NO_VALUE; ++len) - ; - return len; + if (!val) { + return 0; + } + for (len = 0; val[len].type != CSS_NO_VALUE; ++len); + return len; } int css_array_value_set_length(css_style_array_value_t *arr, unsigned new_len) { - unsigned len; - css_style_array_value_t new_arr; + unsigned len; + css_style_array_value_t new_arr; - len = css_array_value_get_length(*arr); - new_arr = realloc(*arr, (new_len + 1) * sizeof(css_style_value_t)); - if (!new_arr) { - return -1; - } - for (; len < new_len; ++len) { - new_arr[len].type = CSS_INVALID_VALUE; - } - new_arr[new_len].type = CSS_NO_VALUE; - *arr = new_arr; - return 0; + len = css_array_value_get_length(*arr); + new_arr = realloc(*arr, (new_len + 1) * sizeof(css_style_value_t)); + if (!new_arr) { + return -1; + } + for (; len < new_len; ++len) { + new_arr[len].type = CSS_INVALID_VALUE; + } + new_arr[new_len].type = CSS_NO_VALUE; + *arr = new_arr; + return 0; } unsigned css_array_value_concat(css_style_array_value_t *arr1, - css_style_array_value_t *arr2) + css_style_array_value_t *arr2) { - unsigned len1 = css_array_value_get_length(*arr1); - unsigned len2 = css_array_value_get_length(*arr2); - unsigned new_len = len1 + len2; + unsigned len1 = css_array_value_get_length(*arr1); + unsigned len2 = css_array_value_get_length(*arr2); + unsigned new_len = len1 + len2; - if (css_array_value_set_length(arr1, new_len) != 0) { - return len1; - } - for (len2 = 0; len1 < new_len + 1; ++len1, ++len2) { - (*arr1)[len1] = (*arr2)[len2]; - } - free(*arr2); - *arr2 = NULL; - return new_len; + if (css_array_value_set_length(arr1, new_len) != 0) { + return len1; + } + for (len2 = 0; len1 < new_len + 1; ++len1, ++len2) { + (*arr1)[len1] = (*arr2)[len2]; + } + free(*arr2); + *arr2 = NULL; + return new_len; } css_style_array_value_t css_array_value_duplicate( const css_style_array_value_t arr) { - unsigned i, len; - css_style_array_value_t new_arr; + unsigned i, len; + css_style_array_value_t new_arr; - len = css_array_value_get_length(arr); - new_arr = malloc(sizeof(css_style_value_t) * (len + 1)); - if (!new_arr) { - return NULL; - } - for (i = 0; i <= len; ++i) { - css_style_value_copy(new_arr + i, arr + i); - } - return new_arr; + len = css_array_value_get_length(arr); + new_arr = malloc(sizeof(css_style_value_t) * (len + 1)); + if (!new_arr) { + return NULL; + } + for (i = 0; i <= len; ++i) { + css_style_value_copy(new_arr + i, arr + i); + } + return new_arr; } void css_array_value_destroy(css_style_array_value_t val) { - unsigned i; + unsigned i; - if (!val) { - return; - } - for (i = 0; val[i].type != CSS_NO_VALUE; ++i) { - css_style_value_destroy(val + i); - } - free(val); + if (!val) { + return; + } + for (i = 0; val[i].type != CSS_NO_VALUE; ++i) { + css_style_value_destroy(val + i); + } + free(val); } void css_style_value_destroy(css_style_value_t *val) { - switch (val->type) { - case CSS_ARRAY_VALUE: - css_array_value_destroy(val->array_value); - val->array_value = NULL; - break; - case CSS_UNPARSED_VALUE: - free(val->unparsed_value); - break; - case CSS_STRING_VALUE: - free(val->string_value); - val->string_value = NULL; - break; - default: - break; - } - val->type = CSS_NO_VALUE; + switch (val->type) { + case CSS_ARRAY_VALUE: + css_array_value_destroy(val->array_value); + val->array_value = NULL; + break; + case CSS_UNPARSED_VALUE: + free(val->unparsed_value); + break; + case CSS_STRING_VALUE: + free(val->string_value); + val->string_value = NULL; + break; + default: + break; + } + val->type = CSS_NO_VALUE; } unsigned css_style_value_get_array_length(const css_style_value_t *val) { - return css_array_value_get_length(val->array_value); + return css_array_value_get_length(val->array_value); } int css_style_value_set_array_length(css_style_value_t *val, unsigned new_len) { - return css_array_value_set_length(&val->array_value, new_len); + return css_array_value_set_length(&val->array_value, new_len); } void css_style_value_copy(css_style_value_t *dst, const css_style_value_t *src) { - switch (src->type) { - case CSS_STRING_VALUE: - case CSS_UNPARSED_VALUE: - if (src->string_value) { - dst->string_value = strdup2(src->string_value); - } else { - dst->string_value = NULL; - } - break; - case CSS_ARRAY_VALUE: - dst->array_value = css_array_value_duplicate(src->array_value); - break; - default: - *dst = *src; - break; - } - dst->type = src->type; + switch (src->type) { + case CSS_STRING_VALUE: + case CSS_UNPARSED_VALUE: + if (src->string_value) { + dst->string_value = strdup2(src->string_value); + } else { + dst->string_value = NULL; + } + break; + case CSS_ARRAY_VALUE: + dst->array_value = css_array_value_duplicate(src->array_value); + break; + default: + *dst = *src; + break; + } + dst->type = src->type; } size_t css_style_value_concat_array(css_style_value_t *val1, - css_style_value_t *val2) + css_style_value_t *val2) { - assert(val1->type == CSS_ARRAY_VALUE && val2->type == CSS_ARRAY_VALUE); - return css_array_value_concat(&val1->array_value, &val2->array_value); + assert(val1->type == CSS_ARRAY_VALUE && val2->type == CSS_ARRAY_VALUE); + return css_array_value_concat(&val1->array_value, &val2->array_value); } // https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleValue/parse css_style_value_t *css_style_value_parse(const char *property, - const char *css_text) + const char *css_text) { - const css_propdef_t *propdef; - css_style_value_t *value; + const css_propdef_t *propdef; + css_style_value_t *value; - propdef = css_get_propdef_by_name(property); - if (!propdef) { - return NULL; - } - value = malloc(sizeof(css_style_value_t)); - value->type = CSS_INVALID_VALUE; - if (css_parse_value(propdef->valdef, css_text, value) > 0) { - return value; - } - free(value); - return NULL; + propdef = css_get_propdef_by_name(property); + if (!propdef) { + return NULL; + } + value = malloc(sizeof(css_style_value_t)); + value->type = CSS_INVALID_VALUE; + if (css_parse_value(propdef->valdef, css_text, value) > 0) { + return value; + } + free(value); + return NULL; } void css_dump_style_value(const css_style_value_t *s, css_dump_context_t *ctx) { - const char *unit; - union { - uint32_t value; - struct { - unsigned char r; - unsigned char g; - unsigned char b; - unsigned char a; - }; - } color; + const char *unit; + union { + uint32_t value; + struct { + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; + }; + } color; - switch (s->type) { - case CSS_INVALID_VALUE: - DUMP(""); - break; - case CSS_COLOR_VALUE: - color.value = s->color_value; - if (color.a < 255) { - DUMPF("rgba(%d,%d,%d,%g)", color.r, color.g, color.b, - color.a / 255.0); - } else { - DUMPF("#%02x%02x%02x", color.r, color.g, color.b); - } - break; - case CSS_STRING_VALUE: - DUMP(s->string_value); - break; - case CSS_KEYWORD_VALUE: - DUMP(css_get_keyword_name(s->keyword_value)); - break; - case CSS_NUMERIC_VALUE: - DUMPF("%g", s->numeric_value); - break; - case CSS_UNIT_VALUE: - switch (s->unit_value.unit) { - case CSS_UNIT_PERCENT: - unit = "%"; - break; - case CSS_UNIT_DIP: - unit = "dip"; - break; - case CSS_UNIT_PT: - unit = "pt"; - break; - case CSS_UNIT_SP: - unit = "sp"; - break; - case CSS_UNIT_PX: - default: - unit = "px"; - break; - } - DUMPF("%g%s", s->unit_value.value, unit); - break; - case CSS_UNPARSED_VALUE: - DUMP(s->unparsed_value); - break; - case CSS_ARRAY_VALUE: { - unsigned arr_i, arr_len; + switch (s->type) { + case CSS_INVALID_VALUE: + DUMP(""); + break; + case CSS_COLOR_VALUE: + color.value = s->color_value; + if (color.a < 255) { + DUMPF("rgba(%d,%d,%d,%g)", color.r, color.g, color.b, + color.a / 255.0); + } else { + DUMPF("#%02x%02x%02x", color.r, color.g, color.b); + } + break; + case CSS_STRING_VALUE: + DUMP(s->string_value); + break; + case CSS_KEYWORD_VALUE: + DUMP(css_get_keyword_name(s->keyword_value)); + break; + case CSS_NUMERIC_VALUE: + DUMPF("%g", s->numeric_value); + break; + case CSS_UNIT_VALUE: + switch (s->unit_value.unit) { + case CSS_UNIT_PERCENT: + unit = "%"; + break; + case CSS_UNIT_DIP: + unit = "dip"; + break; + case CSS_UNIT_PT: + unit = "pt"; + break; + case CSS_UNIT_SP: + unit = "sp"; + break; + case CSS_UNIT_PX: + default: + unit = "px"; + break; + } + DUMPF("%g%s", s->unit_value.value, unit); + break; + case CSS_UNPARSED_VALUE: + DUMP(s->unparsed_value); + break; + case CSS_ARRAY_VALUE: { + unsigned arr_i, arr_len; - arr_len = css_style_value_get_array_length(s); - if (arr_len > 1) { - DUMP("["); - } - for (arr_i = 0; arr_i < arr_len; ++arr_i) { - css_dump_style_value(s->array_value + arr_i, ctx); - if (arr_i + 1 < arr_len) { - DUMP(", "); - } - } - if (arr_len > 1) { - DUMP("]"); - } - break; - } - default: - break; - } + arr_len = css_style_value_get_array_length(s); + if (arr_len > 1) { + DUMP("["); + } + for (arr_i = 0; arr_i < arr_len; ++arr_i) { + css_dump_style_value(s->array_value + arr_i, ctx); + if (arr_i + 1 < arr_len) { + DUMP(", "); + } + } + if (arr_len > 1) { + DUMP("]"); + } + break; + } + default: + break; + } } size_t css_style_value_to_string(const css_style_value_t *s, char *str, - size_t max_len) + size_t max_len) { - css_dump_context_t ctx = { .data = str, - .len = 0, - .max_len = max_len, - .func = css_dump_to_buffer }; - css_dump_style_value(s, &ctx); - return ctx.len; + css_dump_context_t ctx = { .data = str, + .len = 0, + .max_len = max_len, + .func = css_dump_to_buffer }; + css_dump_style_value(s, &ctx); + return ctx.len; } size_t css_print_style_value(const css_style_value_t *s) { - css_dump_context_t ctx = { - .data = NULL, .len = 0, .max_len = 0, .func = css_dump_to_stdout - }; - css_dump_style_value(s, &ctx); - return ctx.len; + css_dump_context_t ctx = { + .data = NULL, .len = 0, .max_len = 0, .func = css_dump_to_stdout + }; + css_dump_style_value(s, &ctx); + return ctx.len; } diff --git a/lib/css/src/utils.c b/lib/css/src/utils.c index 6d8fab3f3..7b8af978a 100644 --- a/lib/css/src/utils.c +++ b/lib/css/src/utils.c @@ -1,12 +1,15 @@ /* * lib/css/src/utils.c: -- Parse data from string * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include @@ -17,41 +20,41 @@ bool css_parse_font_weight(const char *str, int *weight) { - int value; - // TODO - if (strcmp(str, "normal") == 0) { - *weight = CSS_FONT_WEIGHT_NORMAL; - return true; - } - if (strcmp(str, "bold") == 0) { - *weight = CSS_FONT_WEIGHT_BOLD; - return true; - } - if (sscanf(str, "%d", &value) != 1) { - *weight = CSS_FONT_WEIGHT_NORMAL; - return false; - } - if (value < 100) { - *weight = CSS_FONT_WEIGHT_100; - return true; - } - *weight = y_iround(value / 100.0) * 100; - return true; + int value; + // TODO + if (strcmp(str, "normal") == 0) { + *weight = CSS_FONT_WEIGHT_NORMAL; + return true; + } + if (strcmp(str, "bold") == 0) { + *weight = CSS_FONT_WEIGHT_BOLD; + return true; + } + if (sscanf(str, "%d", &value) != 1) { + *weight = CSS_FONT_WEIGHT_NORMAL; + return false; + } + if (value < 100) { + *weight = CSS_FONT_WEIGHT_100; + return true; + } + *weight = y_iround(value / 100.0) * 100; + return true; } bool css_parse_font_style(const char *str, int *style) { - char value[64] = ""; - // TODO - strtrim(value, str, NULL); - if (strcmp(value, "normal") == 0) { - *style = CSS_FONT_STYLE_NORMAL; - } else if (strcmp(value, "italic") == 0) { - *style = CSS_FONT_STYLE_ITALIC; - } else if (strcmp(value, "oblique") == 0) { - *style = CSS_FONT_STYLE_OBLIQUE; - } else { - return false; - } - return true; + char value[64] = ""; + // TODO + strtrim(value, str, NULL); + if (strcmp(value, "normal") == 0) { + *style = CSS_FONT_STYLE_NORMAL; + } else if (strcmp(value, "italic") == 0) { + *style = CSS_FONT_STYLE_ITALIC; + } else if (strcmp(value, "oblique") == 0) { + *style = CSS_FONT_STYLE_OBLIQUE; + } else { + return false; + } + return true; } diff --git a/lib/css/src/value.c b/lib/css/src/value.c index e100f22be..ce3840554 100644 --- a/lib/css/src/value.c +++ b/lib/css/src/value.c @@ -1,12 +1,15 @@ /* * lib/css/src/value.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ /** @@ -31,876 +34,876 @@ #define CSS_VALDEF_PARSER_ERROR_SIZE 256 typedef enum css_valdef_sign_t { - CSS_VALDEF_SIGN_NONE, - CSS_VALDEF_SIGN_JUXTAPOSITION, - CSS_VALDEF_SIGN_DOUBLE_AMPERSAND, - CSS_VALDEF_SIGN_DOUBLE_BAR, - CSS_VALDEF_SIGN_SINGLE_BAR, - CSS_VALDEF_SIGN_BRACKETS, - CSS_VALDEF_SIGN_ANGLE_BRACKET + CSS_VALDEF_SIGN_NONE, + CSS_VALDEF_SIGN_JUXTAPOSITION, + CSS_VALDEF_SIGN_DOUBLE_AMPERSAND, + CSS_VALDEF_SIGN_DOUBLE_BAR, + CSS_VALDEF_SIGN_SINGLE_BAR, + CSS_VALDEF_SIGN_BRACKETS, + CSS_VALDEF_SIGN_ANGLE_BRACKET } css_valdef_sign_t; struct css_value_type_record { - char *name; - css_value_parse_cb parse_value; + char *name; + css_value_parse_cb parse_value; }; struct css_valdef { - css_valdef_sign_t sign; - unsigned min_count; - unsigned max_count; - const css_valdef_t *source; - union { - css_keyword_value_t ident; - /** list_t */ - list_t children; - const css_value_type_record_t *type; - }; + css_valdef_sign_t sign; + unsigned min_count; + unsigned max_count; + const css_valdef_t *source; + union { + css_keyword_value_t ident; + /** list_t */ + list_t children; + const css_value_type_record_t *type; + }; }; typedef enum css_valdef_parser_target_t { - CSS_VALDEF_PARSER_TARGET_NONE, - CSS_VALDEF_PARSER_TARGET_ERROR, - CSS_VALDEF_PARSER_TARGET_KEYWORD, - CSS_VALDEF_PARSER_TARGET_DATA_TYPE, - CSS_VALDEF_PARSER_TARGET_CURLY_BRACES, - CSS_VALDEF_PARSER_TARGET_BRACKETS, - CSS_VALDEF_PARSER_TARGET_QUESTION_MARK, - CSS_VALDEF_PARSER_TARGET_SIGN + CSS_VALDEF_PARSER_TARGET_NONE, + CSS_VALDEF_PARSER_TARGET_ERROR, + CSS_VALDEF_PARSER_TARGET_KEYWORD, + CSS_VALDEF_PARSER_TARGET_DATA_TYPE, + CSS_VALDEF_PARSER_TARGET_CURLY_BRACES, + CSS_VALDEF_PARSER_TARGET_BRACKETS, + CSS_VALDEF_PARSER_TARGET_QUESTION_MARK, + CSS_VALDEF_PARSER_TARGET_SIGN } css_valdef_parser_target_t; typedef struct css_valdef_parser { - const char *cur; - char *buffer; - char terminator; - size_t pos; - size_t buffer_size; - css_valdef_parser_target_t target; - char error[CSS_VALDEF_PARSER_ERROR_SIZE]; - - css_valdef_t *valdef; - - /** list_t */ - list_t valdef_parents; + const char *cur; + char *buffer; + char terminator; + size_t pos; + size_t buffer_size; + css_valdef_parser_target_t target; + char error[CSS_VALDEF_PARSER_ERROR_SIZE]; + + css_valdef_t *valdef; + + /** list_t */ + list_t valdef_parents; } css_valdef_parser_t; typedef struct css_value_matcher { - const char *cur; - const char *next; + const char *cur; + const char *next; - char *value_str; - size_t value_str_len; + char *value_str; + size_t value_str_len; - css_style_array_value_t value; - unsigned value_len; + css_style_array_value_t value; + unsigned value_len; } css_value_matcher_t; static struct css_value_module { - /** dict_t */ - dict_t *alias; + /** dict_t */ + dict_t *alias; - /** dict_t */ - dict_t *types; + /** dict_t */ + dict_t *types; } css_value; static bool css_valdef_has_children(css_valdef_t *valdef) { - switch (valdef->sign) { - case CSS_VALDEF_SIGN_JUXTAPOSITION: - case CSS_VALDEF_SIGN_DOUBLE_AMPERSAND: - case CSS_VALDEF_SIGN_DOUBLE_BAR: - case CSS_VALDEF_SIGN_SINGLE_BAR: - case CSS_VALDEF_SIGN_BRACKETS: - return true; - default: - break; - } - return false; + switch (valdef->sign) { + case CSS_VALDEF_SIGN_JUXTAPOSITION: + case CSS_VALDEF_SIGN_DOUBLE_AMPERSAND: + case CSS_VALDEF_SIGN_DOUBLE_BAR: + case CSS_VALDEF_SIGN_SINGLE_BAR: + case CSS_VALDEF_SIGN_BRACKETS: + return true; + default: + break; + } + return false; } void css_valdef_destroy(css_valdef_t *valdef) { - if (css_valdef_has_children(valdef)) { - list_destroy(&valdef->children, - (list_item_destructor_t)(css_valdef_destroy)); - } - free(valdef); + if (css_valdef_has_children(valdef)) { + list_destroy(&valdef->children, + (list_item_destructor_t)(css_valdef_destroy)); + } + free(valdef); } static void css_valdef_shallow_destroy(css_valdef_t *valdef) { - if (css_valdef_has_children(valdef)) { - list_destroy(&valdef->children, NULL); - } - free(valdef); + if (css_valdef_has_children(valdef)) { + list_destroy(&valdef->children, NULL); + } + free(valdef); } static void css_value_alias_destroy_value(void *priv, void *val) { - css_valdef_destroy(val); + css_valdef_destroy(val); } static void css_value_types_destroy_value(void *priv, void *val) { - css_value_type_record_t *t = val; + css_value_type_record_t *t = val; - free(t->name); - free(t); + free(t->name); + free(t); } void css_init_value_definitons(void) { - static dict_type_t alias_dt; - static dict_type_t types_dt; + static dict_type_t alias_dt; + static dict_type_t types_dt; - dict_init_string_copy_key_type(&alias_dt); - alias_dt.val_destructor = css_value_alias_destroy_value; - css_value.alias = dict_create(&alias_dt, NULL); + dict_init_string_copy_key_type(&alias_dt); + alias_dt.val_destructor = css_value_alias_destroy_value; + css_value.alias = dict_create(&alias_dt, NULL); - dict_init_string_key_type(&types_dt); - types_dt.val_destructor = css_value_types_destroy_value; - css_value.types = dict_create(&types_dt, NULL); + dict_init_string_key_type(&types_dt); + types_dt.val_destructor = css_value_types_destroy_value; + css_value.types = dict_create(&types_dt, NULL); } void css_destroy_value_definitons(void) { - dict_destroy(css_value.alias); - dict_destroy(css_value.types); - css_value.types = NULL; - css_value.alias = NULL; + dict_destroy(css_value.alias); + dict_destroy(css_value.types); + css_value.types = NULL; + css_value.alias = NULL; } static css_valdef_t *css_valdef_create(css_valdef_sign_t sign) { - css_valdef_t *valdef; - - valdef = calloc(1, sizeof(css_valdef_t)); - if (!valdef) { - return NULL; - } - valdef->max_count = 1; - valdef->min_count = 1; - valdef->sign = sign; - return valdef; + css_valdef_t *valdef; + + valdef = calloc(1, sizeof(css_valdef_t)); + if (!valdef) { + return NULL; + } + valdef->max_count = 1; + valdef->min_count = 1; + valdef->sign = sign; + return valdef; } static css_valdef_t *css_valdef_shallow_copy(const css_valdef_t *valdef) { - list_node_t *node; - css_valdef_t *copy; - - copy = css_valdef_create(valdef->sign); - if (!copy) { - return NULL; - } - *copy = *valdef; - if (valdef->sign != CSS_VALDEF_SIGN_NONE && - valdef->sign != CSS_VALDEF_SIGN_ANGLE_BRACKET) { - list_create(©->children); - for (list_each(node, &valdef->children)) { - list_append(©->children, node->data); - } - } - return copy; + list_node_t *node; + css_valdef_t *copy; + + copy = css_valdef_create(valdef->sign); + if (!copy) { + return NULL; + } + *copy = *valdef; + if (valdef->sign != CSS_VALDEF_SIGN_NONE && + valdef->sign != CSS_VALDEF_SIGN_ANGLE_BRACKET) { + list_create(©->children); + for (list_each(node, &valdef->children)) { + list_append(©->children, node->data); + } + } + return copy; } static void css_valdef_append(css_valdef_t *valdef, css_valdef_t *child) { - assert(valdef->sign != CSS_VALDEF_SIGN_NONE && - valdef->sign != CSS_VALDEF_SIGN_ANGLE_BRACKET); - list_append(&valdef->children, child); + assert(valdef->sign != CSS_VALDEF_SIGN_NONE && + valdef->sign != CSS_VALDEF_SIGN_ANGLE_BRACKET); + list_append(&valdef->children, child); } -const css_value_type_record_t *css_register_value_type( - const char *type_name, css_value_parse_cb parse) +const css_value_type_record_t *css_register_value_type(const char *type_name, + css_value_parse_cb parse) { - css_value_type_record_t *t; - - t = malloc(sizeof(css_value_type_record_t)); - if (!t) { - return NULL; - } - t->name = strdup2(type_name); - t->parse_value = parse; - if (dict_add(css_value.types, t->name, t) != 0) { - free(t->name); - free(t); - return NULL; - } - return t; + css_value_type_record_t *t; + + t = malloc(sizeof(css_value_type_record_t)); + if (!t) { + return NULL; + } + t->name = strdup2(type_name); + t->parse_value = parse; + if (dict_add(css_value.types, t->name, t) != 0) { + free(t->name); + free(t); + return NULL; + } + return t; } const css_value_type_record_t *css_get_value_type(const char *type_name) { - return dict_fetch_value(css_value.types, type_name); + return dict_fetch_value(css_value.types, type_name); } const css_valdef_t *css_resolve_valdef_alias(const char *alias) { - return dict_fetch_value(css_value.alias, alias); + return dict_fetch_value(css_value.alias, alias); } css_valdef_parser_t *css_valdef_parser_create(size_t buffer_size, - char terminator) + char terminator) { - css_valdef_parser_t *parser; - - parser = calloc(sizeof(css_valdef_parser_t), 1); - parser->buffer = calloc(sizeof(char), buffer_size); - parser->buffer_size = buffer_size; - parser->target = CSS_VALDEF_PARSER_TARGET_NONE; - parser->terminator = terminator; - list_create(&parser->valdef_parents); - list_append(&parser->valdef_parents, - css_valdef_create(CSS_VALDEF_SIGN_JUXTAPOSITION)); - return parser; + css_valdef_parser_t *parser; + + parser = calloc(sizeof(css_valdef_parser_t), 1); + parser->buffer = calloc(sizeof(char), buffer_size); + parser->buffer_size = buffer_size; + parser->target = CSS_VALDEF_PARSER_TARGET_NONE; + parser->terminator = terminator; + list_create(&parser->valdef_parents); + list_append(&parser->valdef_parents, + css_valdef_create(CSS_VALDEF_SIGN_JUXTAPOSITION)); + return parser; } void css_valdef_parser_destroy(css_valdef_parser_t *parser) { - free(parser->buffer); - free(parser); + free(parser->buffer); + free(parser); } LIBCSS_INLINE void css_valdef_parser_get_char(css_valdef_parser_t *parser) { - parser->buffer[parser->pos++] = *(parser->cur); - parser->buffer[parser->pos] = 0; + parser->buffer[parser->pos++] = *(parser->cur); + parser->buffer[parser->pos] = 0; } static int css_valdef_parser_error(css_valdef_parser_t *parser, const char *fmt, - ...) + ...) { - va_list args; - - va_start(args, fmt); - vsnprintf(parser->error, CSS_VALDEF_PARSER_ERROR_SIZE, fmt, args); - va_end(args); - parser->buffer[CSS_VALDEF_PARSER_ERROR_SIZE - 1] = 0; - parser->target = CSS_VALDEF_PARSER_TARGET_ERROR; - return -1; + va_list args; + + va_start(args, fmt); + vsnprintf(parser->error, CSS_VALDEF_PARSER_ERROR_SIZE, fmt, args); + va_end(args); + parser->buffer[CSS_VALDEF_PARSER_ERROR_SIZE - 1] = 0; + parser->target = CSS_VALDEF_PARSER_TARGET_ERROR; + return -1; } LIBCSS_INLINE css_valdef_t *css_valdef_parser_get_parent_valdef( css_valdef_parser_t *parser) { - assert(parser->valdef_parents.tail.prev); - return parser->valdef_parents.tail.prev->data; + assert(parser->valdef_parents.tail.prev); + return parser->valdef_parents.tail.prev->data; } LIBCSS_INLINE void css_valdef_parser_reset_buffer(css_valdef_parser_t *parser) { - parser->buffer[0] = 0; - parser->pos = 0; + parser->buffer[0] = 0; + parser->pos = 0; } // 在遇到符号时提交当前已解析的值定义 static int css_valdef_parser_commit(css_valdef_parser_t *parser, - css_valdef_sign_t sign) + css_valdef_sign_t sign) { - css_valdef_t *parent_valdef; - css_valdef_t *deleted_valdef = NULL; - css_valdef_t *child; - - // TODO: 处理 && 和 || 混写情况 - // TODO: 处理非数组值的情况 - if (!parser->valdef) { - return 0; - } + css_valdef_t *parent_valdef; + css_valdef_t *deleted_valdef = NULL; + css_valdef_t *child; + + // TODO: 处理 && 和 || 混写情况 + // TODO: 处理非数组值的情况 + if (!parser->valdef) { + return 0; + } #ifdef DEBUG - { - char str[256]; - parent_valdef = - list_get_first_node(&parser->valdef_parents)->data; - css_valdef_to_string(parser->valdef, str, 255); - DEBUG_MSG("css_valdef_parser_commit(): enter %d, valdef: %s\n", - sign, str); - } + { + char str[256]; + parent_valdef = + list_get_first_node(&parser->valdef_parents)->data; + css_valdef_to_string(parser->valdef, str, 255); + DEBUG_MSG("css_valdef_parser_commit(): enter %d, valdef: %s\n", + sign, str); + } #endif #ifdef DEBUG - { - char str[256]; - parent_valdef = - list_get_first_node(&parser->valdef_parents)->data; - css_valdef_to_string(parent_valdef, str, 255); - DEBUG_MSG("css_valdef_parser_commit(): before: %s\n", str); - } + { + char str[256]; + parent_valdef = + list_get_first_node(&parser->valdef_parents)->data; + css_valdef_to_string(parent_valdef, str, 255); + DEBUG_MSG("css_valdef_parser_commit(): before: %s\n", str); + } #endif - parent_valdef = css_valdef_parser_get_parent_valdef(parser); - if (parent_valdef->sign == sign) { - css_valdef_append(parent_valdef, parser->valdef); - parser->valdef = NULL; + parent_valdef = css_valdef_parser_get_parent_valdef(parser); + if (parent_valdef->sign == sign) { + css_valdef_append(parent_valdef, parser->valdef); + parser->valdef = NULL; #ifdef DEBUG - { - char str[256]; - parent_valdef = - list_get_first_node(&parser->valdef_parents)->data; - css_valdef_to_string(parent_valdef, str, 255); - DEBUG_MSG("css_valdef_parser_commit(): after: %s\n", - str); - } + { + char str[256]; + parent_valdef = + list_get_first_node(&parser->valdef_parents)->data; + css_valdef_to_string(parent_valdef, str, 255); + DEBUG_MSG("css_valdef_parser_commit(): after: %s\n", + str); + } #endif - return 0; - } - - // Before: - // left && right | - // ^ - // | - // current sign - // After: - // [left && right] | - if (sign == CSS_VALDEF_SIGN_SINGLE_BAR) { - css_valdef_append(parent_valdef, parser->valdef); - parser->valdef = NULL; - while (parent_valdef && parent_valdef->sign != sign) { - list_delete_last(&parser->valdef_parents); - deleted_valdef = parent_valdef; - parent_valdef = - css_valdef_parser_get_parent_valdef(parser); - } - // Before: - // none | top left | - // ^ - // | - // current sign - // After: - // none | [top left] | - if (parent_valdef && parent_valdef->sign == sign) { - return 0; - } - // Before: - // [top | center | bottom] && top left | - // ^ - // | - // current sign - // After: - // [[top | center | bottom] && [top left]] | - child = css_valdef_create(sign); - css_valdef_append(child, deleted_valdef); - list_append(&parser->valdef_parents, child); + return 0; + } + + // Before: + // left && right | + // ^ + // | + // current sign + // After: + // [left && right] | + if (sign == CSS_VALDEF_SIGN_SINGLE_BAR) { + css_valdef_append(parent_valdef, parser->valdef); + parser->valdef = NULL; + while (parent_valdef && parent_valdef->sign != sign) { + list_delete_last(&parser->valdef_parents); + deleted_valdef = parent_valdef; + parent_valdef = + css_valdef_parser_get_parent_valdef(parser); + } + // Before: + // none | top left | + // ^ + // | + // current sign + // After: + // none | [top left] | + if (parent_valdef && parent_valdef->sign == sign) { + return 0; + } + // Before: + // [top | center | bottom] && top left | + // ^ + // | + // current sign + // After: + // [[top | center | bottom] && [top left]] | + child = css_valdef_create(sign); + css_valdef_append(child, deleted_valdef); + list_append(&parser->valdef_parents, child); #ifdef DEBUG - { - char str[256]; - parent_valdef = - list_get_first_node(&parser->valdef_parents)->data; - css_valdef_to_string(parent_valdef, str, 255); - DEBUG_MSG("css_valdef_parser_commit(): after2: %s\n", - str); - } + { + char str[256]; + parent_valdef = + list_get_first_node(&parser->valdef_parents)->data; + css_valdef_to_string(parent_valdef, str, 255); + DEBUG_MSG("css_valdef_parser_commit(): after2: %s\n", + str); + } #endif - return 0; - } - // Before: - // left | right && - // ^ - // | - // current sign - // After: - // left | [right && ] - child = css_valdef_create(sign); - css_valdef_append(child, parser->valdef); - css_valdef_append(parent_valdef, child); - list_append(&parser->valdef_parents, child); - parser->valdef = NULL; + return 0; + } + // Before: + // left | right && + // ^ + // | + // current sign + // After: + // left | [right && ] + child = css_valdef_create(sign); + css_valdef_append(child, parser->valdef); + css_valdef_append(parent_valdef, child); + list_append(&parser->valdef_parents, child); + parser->valdef = NULL; #ifdef DEBUG - { - char str[256]; - parent_valdef = - list_get_first_node(&parser->valdef_parents)->data; - css_valdef_to_string(parent_valdef, str, 255); - DEBUG_MSG("css_valdef_parser_commit(): after3: %s\n", str); - } + { + char str[256]; + parent_valdef = + list_get_first_node(&parser->valdef_parents)->data; + css_valdef_to_string(parent_valdef, str, 255); + DEBUG_MSG("css_valdef_parser_commit(): after3: %s\n", str); + } #endif - return 0; + return 0; } static css_valdef_t *css_valdef_parser_parse(css_valdef_parser_t *parser, - const char *definition_str); + const char *definition_str); static int css_valdef_parser_parse_brackets(css_valdef_parser_t *parser) { - css_valdef_t *brackets_inner; - css_valdef_parser_t *subparser; + css_valdef_t *brackets_inner; + css_valdef_parser_t *subparser; #ifdef DEBUG - DEBUG_MSG("%s\n", "css_valdef_parser_parse_brackets(): enter"); + DEBUG_MSG("%s\n", "css_valdef_parser_parse_brackets(): enter"); #endif - subparser = css_valdef_parser_create(parser->buffer_size, ']'); - brackets_inner = css_valdef_parser_parse(subparser, parser->cur); - if (!brackets_inner) { - css_valdef_parser_error(parser, subparser->error); - css_valdef_parser_destroy(subparser); - return -1; - } - parser->cur = subparser->cur; - parser->target = CSS_VALDEF_PARSER_TARGET_NONE; - parser->valdef = css_valdef_create(CSS_VALDEF_SIGN_BRACKETS); - css_valdef_append(parser->valdef, brackets_inner); + subparser = css_valdef_parser_create(parser->buffer_size, ']'); + brackets_inner = css_valdef_parser_parse(subparser, parser->cur); + if (!brackets_inner) { + css_valdef_parser_error(parser, subparser->error); + css_valdef_parser_destroy(subparser); + return -1; + } + parser->cur = subparser->cur; + parser->target = CSS_VALDEF_PARSER_TARGET_NONE; + parser->valdef = css_valdef_create(CSS_VALDEF_SIGN_BRACKETS); + css_valdef_append(parser->valdef, brackets_inner); #ifdef DEBUG - char str[256]; - css_valdef_to_string(parser->valdef, str, 255); - DEBUG_MSG("css_valdef_parser_parse_brackets(): %s\n", str); + char str[256]; + css_valdef_to_string(parser->valdef, str, 255); + DEBUG_MSG("css_valdef_parser_parse_brackets(): %s\n", str); #endif - css_valdef_parser_destroy(subparser); - return 0; + css_valdef_parser_destroy(subparser); + return 0; } static int css_valdef_parser_parse_keyword_end(css_valdef_parser_t *parser) { - // Example: - // top left | right - // ^ - // | - // cur - parser->valdef = css_valdef_create(CSS_VALDEF_SIGN_NONE); - parser->valdef->ident = css_get_keyword_key(parser->buffer); - if (parser->valdef->ident == -1) { - parser->valdef->ident = css_register_keyword(parser->buffer); - } - parser->target = CSS_VALDEF_PARSER_TARGET_NONE; - return 0; + // Example: + // top left | right + // ^ + // | + // cur + parser->valdef = css_valdef_create(CSS_VALDEF_SIGN_NONE); + parser->valdef->ident = css_get_keyword_key(parser->buffer); + if (parser->valdef->ident == -1) { + parser->valdef->ident = css_register_keyword(parser->buffer); + } + parser->target = CSS_VALDEF_PARSER_TARGET_NONE; + return 0; } static int css_valdef_parser_parse_keyword(css_valdef_parser_t *parser) { - switch (*parser->cur) { - CASE_WHITE_SPACE: - case '|': - case '&': - case '[': - case ']': - case '<': - case '{': - break; - case '>': - return css_valdef_parser_error(parser, "syntax error"); - default: - css_valdef_parser_get_char(parser); - return 0; - } - return css_valdef_parser_parse_keyword_end(parser); + switch (*parser->cur) { + CASE_WHITE_SPACE: + case '|': + case '&': + case '[': + case ']': + case '<': + case '{': + break; + case '>': + return css_valdef_parser_error(parser, "syntax error"); + default: + css_valdef_parser_get_char(parser); + return 0; + } + return css_valdef_parser_parse_keyword_end(parser); } static int css_valdef_parser_parse_data_type_end(css_valdef_parser_t *parser) { - parser->target = CSS_VALDEF_PARSER_TARGET_NONE; - parser->valdef = css_valdef_create(CSS_VALDEF_SIGN_ANGLE_BRACKET); - parser->valdef->source = NULL; - parser->valdef->type = css_get_value_type(parser->buffer); - if (parser->valdef->type) { - return 0; - } - parser->valdef->source = css_resolve_valdef_alias(parser->buffer); - if (parser->valdef->source) { - return 0; - } - return css_valdef_parser_error(parser, "unknown data type: `%s`\n", - parser->buffer); + parser->target = CSS_VALDEF_PARSER_TARGET_NONE; + parser->valdef = css_valdef_create(CSS_VALDEF_SIGN_ANGLE_BRACKET); + parser->valdef->source = NULL; + parser->valdef->type = css_get_value_type(parser->buffer); + if (parser->valdef->type) { + return 0; + } + parser->valdef->source = css_resolve_valdef_alias(parser->buffer); + if (parser->valdef->source) { + return 0; + } + return css_valdef_parser_error(parser, "unknown data type: `%s`\n", + parser->buffer); } static int css_valdef_parser_parse_data_type(css_valdef_parser_t *parser) { - switch (*parser->cur) { - case '<': - case '&': - case '?': - case '|': - case '{': - case '}': - case '[': - case ']': - CASE_WHITE_SPACE: - return css_valdef_parser_error(parser, "syntax error"); - case '>': - break; - default: - css_valdef_parser_get_char(parser); - return 0; - } - return css_valdef_parser_parse_data_type_end(parser); + switch (*parser->cur) { + case '<': + case '&': + case '?': + case '|': + case '{': + case '}': + case '[': + case ']': + CASE_WHITE_SPACE: + return css_valdef_parser_error(parser, "syntax error"); + case '>': + break; + default: + css_valdef_parser_get_char(parser); + return 0; + } + return css_valdef_parser_parse_data_type_end(parser); } static int css_valdef_parser_parse_sign_end(css_valdef_parser_t *parser) { - if (parser->pos == 0) { - css_valdef_parser_commit(parser, CSS_VALDEF_SIGN_JUXTAPOSITION); - } else if (parser->pos == 1 && parser->buffer[0] == '|') { - css_valdef_parser_commit(parser, CSS_VALDEF_SIGN_SINGLE_BAR); - } else if (parser->pos == 2 && parser->buffer[0] == '|') { - css_valdef_parser_commit(parser, CSS_VALDEF_SIGN_DOUBLE_BAR); - } else if (parser->pos == 2 && parser->buffer[0] == '&') { - css_valdef_parser_commit(parser, - CSS_VALDEF_SIGN_DOUBLE_AMPERSAND); - } else { - return css_valdef_parser_error(parser, "unknown sign: `%s`\n", - parser->buffer); - } - // Example: - // auto | none - // ^ - // | - // cur - if (parser->target == CSS_VALDEF_PARSER_TARGET_KEYWORD) { - parser->target = CSS_VALDEF_PARSER_TARGET_NONE; - parser->cur--; - } - return 0; + if (parser->pos == 0) { + css_valdef_parser_commit(parser, CSS_VALDEF_SIGN_JUXTAPOSITION); + } else if (parser->pos == 1 && parser->buffer[0] == '|') { + css_valdef_parser_commit(parser, CSS_VALDEF_SIGN_SINGLE_BAR); + } else if (parser->pos == 2 && parser->buffer[0] == '|') { + css_valdef_parser_commit(parser, CSS_VALDEF_SIGN_DOUBLE_BAR); + } else if (parser->pos == 2 && parser->buffer[0] == '&') { + css_valdef_parser_commit(parser, + CSS_VALDEF_SIGN_DOUBLE_AMPERSAND); + } else { + return css_valdef_parser_error(parser, "unknown sign: `%s`\n", + parser->buffer); + } + // Example: + // auto | none + // ^ + // | + // cur + if (parser->target == CSS_VALDEF_PARSER_TARGET_KEYWORD) { + parser->target = CSS_VALDEF_PARSER_TARGET_NONE; + parser->cur--; + } + return 0; } static int css_valdef_parser_parse_sign(css_valdef_parser_t *parser) { - switch (*parser->cur) { - case '|': - case '&': - css_valdef_parser_get_char(parser); - switch (parser->pos) { - case 1: - break; - case 2: - if (parser->buffer[parser->pos] == - parser->buffer[parser->pos - 1]) { - break; - } - default: - break; - } - return 0; - case '[': - parser->cur--; - case ']': - parser->target = CSS_VALDEF_PARSER_TARGET_NONE; - break; - CASE_WHITE_SPACE: - // Example: - // none | left - // ^ - // | - // cur - return 0; - case '{': - case '}': - return css_valdef_parser_error(parser, "syntax error"); - default: - parser->target = CSS_VALDEF_PARSER_TARGET_KEYWORD; - break; - } - return css_valdef_parser_parse_sign_end(parser); + switch (*parser->cur) { + case '|': + case '&': + css_valdef_parser_get_char(parser); + switch (parser->pos) { + case 1: + break; + case 2: + if (parser->buffer[parser->pos] == + parser->buffer[parser->pos - 1]) { + break; + } + default: + break; + } + return 0; + case '[': + parser->cur--; + case ']': + parser->target = CSS_VALDEF_PARSER_TARGET_NONE; + break; + CASE_WHITE_SPACE: + // Example: + // none | left + // ^ + // | + // cur + return 0; + case '{': + case '}': + return css_valdef_parser_error(parser, "syntax error"); + default: + parser->target = CSS_VALDEF_PARSER_TARGET_KEYWORD; + break; + } + return css_valdef_parser_parse_sign_end(parser); } static int css_valdef_parser_parse_curly_braces(css_valdef_parser_t *parser) { - switch (*parser->cur) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case ',': - CASE_WHITE_SPACE: - css_valdef_parser_get_char(parser); - return 0; - case '{': - return 0; - case '}': - break; - default: - return -1; - } - if (sscanf(parser->buffer, "%u,%u", &parser->valdef->min_count, - &parser->valdef->max_count) == 2) { - parser->target = CSS_VALDEF_PARSER_TARGET_NONE; - return 0; - } - if (sscanf(parser->buffer, "%u", &parser->valdef->min_count) == 1) { - parser->valdef->max_count = parser->valdef->min_count; - parser->target = CSS_VALDEF_PARSER_TARGET_NONE; - return 0; - } - return css_valdef_parser_error(parser, "syntax error: %s\n", - parser->buffer); + switch (*parser->cur) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case ',': + CASE_WHITE_SPACE: + css_valdef_parser_get_char(parser); + return 0; + case '{': + return 0; + case '}': + break; + default: + return -1; + } + if (sscanf(parser->buffer, "%u,%u", &parser->valdef->min_count, + &parser->valdef->max_count) == 2) { + parser->target = CSS_VALDEF_PARSER_TARGET_NONE; + return 0; + } + if (sscanf(parser->buffer, "%u", &parser->valdef->min_count) == 1) { + parser->valdef->max_count = parser->valdef->min_count; + parser->target = CSS_VALDEF_PARSER_TARGET_NONE; + return 0; + } + return css_valdef_parser_error(parser, "syntax error: %s\n", + parser->buffer); } static int css_valdef_parser_parse_question_mark(css_valdef_parser_t *parser) { - if (!parser->valdef || parser->valdef->min_count == 0) { - return css_valdef_parser_error(parser, "syntax error"); - } - parser->valdef->min_count = 0; - parser->target = CSS_VALDEF_PARSER_TARGET_NONE; - return 0; + if (!parser->valdef || parser->valdef->min_count == 0) { + return css_valdef_parser_error(parser, "syntax error"); + } + parser->valdef->min_count = 0; + parser->target = CSS_VALDEF_PARSER_TARGET_NONE; + return 0; } static int css_valdef_parser_resolve_target(css_valdef_parser_t *parser) { - DEBUG_MSG("%c\n", *parser->cur); - switch (*parser->cur) { - case '|': - case '&': - CASE_WHITE_SPACE: - css_valdef_parser_reset_buffer(parser); - parser->target = CSS_VALDEF_PARSER_TARGET_SIGN; - parser->cur--; - break; - case '<': - css_valdef_parser_reset_buffer(parser); - parser->target = CSS_VALDEF_PARSER_TARGET_DATA_TYPE; - break; - case '?': - parser->target = CSS_VALDEF_PARSER_TARGET_QUESTION_MARK; - parser->cur--; - break; - case '[': - parser->target = CSS_VALDEF_PARSER_TARGET_BRACKETS; - break; - case '{': - css_valdef_parser_reset_buffer(parser); - parser->target = CSS_VALDEF_PARSER_TARGET_CURLY_BRACES; - break; - case ']': - case '}': - case '>': - return css_valdef_parser_error(parser, "syntax error"); - default: - css_valdef_parser_reset_buffer(parser); - parser->target = CSS_VALDEF_PARSER_TARGET_KEYWORD; - parser->cur--; - break; - } - return 0; + DEBUG_MSG("%c\n", *parser->cur); + switch (*parser->cur) { + case '|': + case '&': + CASE_WHITE_SPACE: + css_valdef_parser_reset_buffer(parser); + parser->target = CSS_VALDEF_PARSER_TARGET_SIGN; + parser->cur--; + break; + case '<': + css_valdef_parser_reset_buffer(parser); + parser->target = CSS_VALDEF_PARSER_TARGET_DATA_TYPE; + break; + case '?': + parser->target = CSS_VALDEF_PARSER_TARGET_QUESTION_MARK; + parser->cur--; + break; + case '[': + parser->target = CSS_VALDEF_PARSER_TARGET_BRACKETS; + break; + case '{': + css_valdef_parser_reset_buffer(parser); + parser->target = CSS_VALDEF_PARSER_TARGET_CURLY_BRACES; + break; + case ']': + case '}': + case '>': + return css_valdef_parser_error(parser, "syntax error"); + default: + css_valdef_parser_reset_buffer(parser); + parser->target = CSS_VALDEF_PARSER_TARGET_KEYWORD; + parser->cur--; + break; + } + return 0; } static size_t css_valdef_parser_parse_next(css_valdef_parser_t *parser) { - const char *start = parser->cur; - - // printf("parse: %s\n", parser->cur); - while (*parser->cur && *parser->cur != parser->terminator) { - if (parser->cur >= start + parser->buffer_size) { - ++parser->cur; - break; - } - switch (parser->target) { - case CSS_VALDEF_PARSER_TARGET_NONE: - css_valdef_parser_resolve_target(parser); - break; - case CSS_VALDEF_PARSER_TARGET_SIGN: - css_valdef_parser_parse_sign(parser); - break; - case CSS_VALDEF_PARSER_TARGET_BRACKETS: - css_valdef_parser_parse_brackets(parser); - break; - case CSS_VALDEF_PARSER_TARGET_DATA_TYPE: - css_valdef_parser_parse_data_type(parser); - break; - case CSS_VALDEF_PARSER_TARGET_KEYWORD: - css_valdef_parser_parse_keyword(parser); - break; - case CSS_VALDEF_PARSER_TARGET_CURLY_BRACES: - css_valdef_parser_parse_curly_braces(parser); - break; - case CSS_VALDEF_PARSER_TARGET_QUESTION_MARK: - css_valdef_parser_parse_question_mark(parser); - break; - case CSS_VALDEF_PARSER_TARGET_ERROR: - return 0; - default: - break; - } - ++parser->cur; - } - return parser->cur - start; + const char *start = parser->cur; + + // printf("parse: %s\n", parser->cur); + while (*parser->cur && *parser->cur != parser->terminator) { + if (parser->cur >= start + parser->buffer_size) { + ++parser->cur; + break; + } + switch (parser->target) { + case CSS_VALDEF_PARSER_TARGET_NONE: + css_valdef_parser_resolve_target(parser); + break; + case CSS_VALDEF_PARSER_TARGET_SIGN: + css_valdef_parser_parse_sign(parser); + break; + case CSS_VALDEF_PARSER_TARGET_BRACKETS: + css_valdef_parser_parse_brackets(parser); + break; + case CSS_VALDEF_PARSER_TARGET_DATA_TYPE: + css_valdef_parser_parse_data_type(parser); + break; + case CSS_VALDEF_PARSER_TARGET_KEYWORD: + css_valdef_parser_parse_keyword(parser); + break; + case CSS_VALDEF_PARSER_TARGET_CURLY_BRACES: + css_valdef_parser_parse_curly_braces(parser); + break; + case CSS_VALDEF_PARSER_TARGET_QUESTION_MARK: + css_valdef_parser_parse_question_mark(parser); + break; + case CSS_VALDEF_PARSER_TARGET_ERROR: + return 0; + default: + break; + } + ++parser->cur; + } + return parser->cur - start; } static int css_valdef_parser_finish(css_valdef_parser_t *parser) { - css_valdef_t *parent_valdef; - - switch (parser->target) { - case CSS_VALDEF_PARSER_TARGET_KEYWORD: - css_valdef_parser_parse_keyword_end(parser); - break; - case CSS_VALDEF_PARSER_TARGET_SIGN: - css_valdef_parser_parse_sign_end(parser); - break; - case CSS_VALDEF_PARSER_TARGET_ERROR: - return -1; - default: - break; - } - parent_valdef = css_valdef_parser_get_parent_valdef(parser); - return css_valdef_parser_commit(parser, parent_valdef->sign); + css_valdef_t *parent_valdef; + + switch (parser->target) { + case CSS_VALDEF_PARSER_TARGET_KEYWORD: + css_valdef_parser_parse_keyword_end(parser); + break; + case CSS_VALDEF_PARSER_TARGET_SIGN: + css_valdef_parser_parse_sign_end(parser); + break; + case CSS_VALDEF_PARSER_TARGET_ERROR: + return -1; + default: + break; + } + parent_valdef = css_valdef_parser_get_parent_valdef(parser); + return css_valdef_parser_commit(parser, parent_valdef->sign); } static css_valdef_t *css_valdef_parser_get_result(css_valdef_parser_t *parser) { - css_valdef_t *valdef = NULL; + css_valdef_t *valdef = NULL; - assert(parser->valdef_parents.length > 0); - valdef = list_get_first_node(&parser->valdef_parents)->data; - list_destroy(&parser->valdef_parents, NULL); - return valdef; + assert(parser->valdef_parents.length > 0); + valdef = list_get_first_node(&parser->valdef_parents)->data; + list_destroy(&parser->valdef_parents, NULL); + return valdef; } static css_valdef_t *css_valdef_parser_parse(css_valdef_parser_t *parser, - const char *definition_str) + const char *definition_str) { - parser->cur = definition_str; - while (css_valdef_parser_parse_next(parser) > 0) { - if (parser->target == CSS_VALDEF_PARSER_TARGET_ERROR) { - return NULL; - } - } - css_valdef_parser_finish(parser); - return css_valdef_parser_get_result(parser); + parser->cur = definition_str; + while (css_valdef_parser_parse_next(parser) > 0) { + if (parser->target == CSS_VALDEF_PARSER_TARGET_ERROR) { + return NULL; + } + } + css_valdef_parser_finish(parser); + return css_valdef_parser_get_result(parser); } css_valdef_t *css_compile_valdef(const char *definition_str) { - css_valdef_t *valdef; - css_valdef_parser_t *parser; + css_valdef_t *valdef; + css_valdef_parser_t *parser; - parser = css_valdef_parser_create(512, 0); - valdef = css_valdef_parser_parse(parser, definition_str); - css_valdef_parser_destroy(parser); - return valdef; + parser = css_valdef_parser_create(512, 0); + valdef = css_valdef_parser_parse(parser, definition_str); + css_valdef_parser_destroy(parser); + return valdef; } static int css_value_matcher_resolve_next_value(css_value_matcher_t *matcher) { - int quotes = 0; - int brackets = 0; - const char *p = matcher->next; + int quotes = 0; + int brackets = 0; + const char *p = matcher->next; #ifdef DEBUG - DEBUG_MSG("resolve_next_value(matcher<0x%p>): %s\n", matcher, - matcher->cur); + DEBUG_MSG("resolve_next_value(matcher<0x%p>): %s\n", matcher, + matcher->cur); #endif - while (*p) { - switch (*p) { - CASE_WHITE_SPACE: - p++; - break; - default: - goto resolve_value_str_tail; - } - } + while (*p) { + switch (*p) { + CASE_WHITE_SPACE: + p++; + break; + default: + goto resolve_value_str_tail; + } + } resolve_value_str_tail: - matcher->cur = p; - while (*p) { - switch (*p) { - CASE_WHITE_SPACE: - if (brackets < 1 && quotes < 1) { - goto copy_value_str; - } - break; - case '(': - if (quotes < 1) { - brackets++; - } - break; - case ')': - if (quotes < 1) { - brackets--; - } - break; - case '"': - if (quotes > 0) { - quotes--; - } else { - quotes++; - } - break; - default: - break; - } - p++; - } + matcher->cur = p; + while (*p) { + switch (*p) { + CASE_WHITE_SPACE: + if (brackets < 1 && quotes < 1) { + goto copy_value_str; + } + break; + case '(': + if (quotes < 1) { + brackets++; + } + break; + case ')': + if (quotes < 1) { + brackets--; + } + break; + case '"': + if (quotes > 0) { + quotes--; + } else { + quotes++; + } + break; + default: + break; + } + p++; + } copy_value_str: - if (matcher->value_str) { - free(matcher->value_str); - matcher->value_str = NULL; - } - matcher->value_str_len = p - matcher->cur; - matcher->value_str = - malloc(sizeof(char) * (matcher->value_str_len + 1)); - strncpy(matcher->value_str, matcher->cur, matcher->value_str_len); - matcher->value_str[matcher->value_str_len] = 0; - if (matcher->value_str_len < 1) { - return -1; - } - return 0; + if (matcher->value_str) { + free(matcher->value_str); + matcher->value_str = NULL; + } + matcher->value_str_len = p - matcher->cur; + matcher->value_str = + malloc(sizeof(char) * (matcher->value_str_len + 1)); + strncpy(matcher->value_str, matcher->cur, matcher->value_str_len); + matcher->value_str[matcher->value_str_len] = 0; + if (matcher->value_str_len < 1) { + return -1; + } + return 0; } static void css_value_matcher_push_value(css_value_matcher_t *matcher, - css_style_value_t *value) + css_style_value_t *value) { - unsigned i = matcher->value_len++; - css_array_value_set_length(&matcher->value, matcher->value_len); - matcher->value[i] = *value; - matcher->next = matcher->cur + matcher->value_str_len; + unsigned i = matcher->value_len++; + css_array_value_set_length(&matcher->value, matcher->value_len); + matcher->value[i] = *value; + matcher->next = matcher->cur + matcher->value_str_len; } css_value_matcher_t *css_value_matcher_create(const char *str) { - css_value_matcher_t *matcher; - - matcher = calloc(1, sizeof(css_value_matcher_t)); - if (!matcher) { - return NULL; - } - matcher->cur = str; - matcher->next = str; - matcher->value = NULL; - css_value_matcher_resolve_next_value(matcher); - return matcher; + css_value_matcher_t *matcher; + + matcher = calloc(1, sizeof(css_value_matcher_t)); + if (!matcher) { + return NULL; + } + matcher->cur = str; + matcher->next = str; + matcher->value = NULL; + css_value_matcher_resolve_next_value(matcher); + return matcher; } static void css_value_matcher_destroy(css_value_matcher_t *matcher) { - matcher->cur = NULL; - matcher->value_len = 0; - css_array_value_destroy(matcher->value); - free(matcher->value_str); - matcher->value_str = NULL; - matcher->value_str_len = 0; - free(matcher); + matcher->cur = NULL; + matcher->value_len = 0; + css_array_value_destroy(matcher->value); + free(matcher->value_str); + matcher->value_str = NULL; + matcher->value_str_len = 0; + free(matcher); } static int css_value_matcher_match(css_value_matcher_t *matcher, - const css_valdef_t *valdef); + const css_valdef_t *valdef); static int css_value_matcher_submatch(css_value_matcher_t *matcher, - const css_valdef_t *valdef); + const css_valdef_t *valdef); static int css_value_matcher_match_data_type(css_value_matcher_t *matcher, - const css_valdef_t *valdef) + const css_valdef_t *valdef) { - css_style_value_t value = { CSS_NO_VALUE }; - - if (valdef->source) { - return css_value_matcher_submatch(matcher, valdef->source) == 0 - ? 0 - : -1; - } - if (valdef->type && - valdef->type->parse_value(&value, matcher->value_str)) { - css_value_matcher_push_value(matcher, &value); - return 0; - } - return -1; + css_style_value_t value = { CSS_NO_VALUE }; + + if (valdef->source) { + return css_value_matcher_submatch(matcher, valdef->source) == 0 + ? 0 + : -1; + } + if (valdef->type && + valdef->type->parse_value(&value, matcher->value_str)) { + css_value_matcher_push_value(matcher, &value); + return 0; + } + return -1; } /** @@ -908,46 +911,46 @@ static int css_value_matcher_match_data_type(css_value_matcher_t *matcher, * https://developer.mozilla.org/en-US/docs/Web/CSS/Value_definition_syntax#double_bar */ static int css_value_matcher_match_double_bar(css_value_matcher_t *matcher, - const css_valdef_t *valdef) + const css_valdef_t *valdef) { - int ret; - unsigned i = 0; - list_node_t *node; - css_valdef_t *rest_valdef; - char str[256]; - - for (list_each(node, &valdef->children)) { - css_valdef_to_string(node->data, str, 255); - DEBUG_MSG("[%u/%zu] matcher->value_str: %s\n", i + 1, - valdef->children.length, matcher->value_str); - if (css_value_matcher_match(matcher, node->data) != 0) { - DEBUG_MSG("[%u/%zu] not matched valdef: %s\n", i + 1, - valdef->children.length, str); - i++; - continue; - } - if (valdef->children.length < 2) { - break; - } - DEBUG_MSG("[%u/%zu] matched valdef: %s\n", i + 1, - valdef->children.length, str); - rest_valdef = css_valdef_shallow_copy(valdef); - // || || - // ^ - // matched valdef - // - // The sub matcher will use the remaining value definitions: - // || - list_delete(&rest_valdef->children, i); - css_value_matcher_resolve_next_value(matcher); - ret = css_value_matcher_submatch(matcher, rest_valdef); - css_valdef_shallow_destroy(rest_valdef); - if (ret == -1) { - return -1; - } - break; - } - return 0; + int ret; + unsigned i = 0; + list_node_t *node; + css_valdef_t *rest_valdef; + char str[256]; + + for (list_each(node, &valdef->children)) { + css_valdef_to_string(node->data, str, 255); + DEBUG_MSG("[%u/%zu] matcher->value_str: %s\n", i + 1, + valdef->children.length, matcher->value_str); + if (css_value_matcher_match(matcher, node->data) != 0) { + DEBUG_MSG("[%u/%zu] not matched valdef: %s\n", i + 1, + valdef->children.length, str); + i++; + continue; + } + if (valdef->children.length < 2) { + break; + } + DEBUG_MSG("[%u/%zu] matched valdef: %s\n", i + 1, + valdef->children.length, str); + rest_valdef = css_valdef_shallow_copy(valdef); + // || || + // ^ + // matched valdef + // + // The sub matcher will use the remaining value definitions: + // || + list_delete(&rest_valdef->children, i); + css_value_matcher_resolve_next_value(matcher); + ret = css_value_matcher_submatch(matcher, rest_valdef); + css_valdef_shallow_destroy(rest_valdef); + if (ret == -1) { + return -1; + } + break; + } + return 0; } /** @@ -957,326 +960,326 @@ static int css_value_matcher_match_double_bar(css_value_matcher_t *matcher, static int css_value_matcher_match_double_ampersand( css_value_matcher_t *matcher, const css_valdef_t *valdef) { - int ret = -1; - unsigned i = 0; - list_node_t *node; - css_valdef_t *rest_valdef; - char str[256]; - - DEBUG_MSG("\n%s\n", - "css_value_matcher_match_double_ampersand() enter\n"); - for (list_each(node, &valdef->children)) { - css_valdef_to_string(node->data, str, 255); - DEBUG_MSG("[%u/%zu] matcher->value_str: %s\n", i + 1, - valdef->children.length, matcher->value_str); - if (css_value_matcher_match(matcher, node->data) != 0) { - i++; - DEBUG_MSG("[%u/%zu] not matched valdef: %s\n", i + 1, - valdef->children.length, str); - continue; - } - DEBUG_MSG("[%u/%zu] matched valdef: %s\n", i + 1, - valdef->children.length, str); - if (valdef->children.length < 2) { - ret = 0; - break; - } - DEBUG_MSG("match rest valdef %u\n", - valdef->children.length - 1); - rest_valdef = css_valdef_shallow_copy(valdef); - list_delete(&rest_valdef->children, i); - css_value_matcher_resolve_next_value(matcher); - ret = css_value_matcher_submatch(matcher, rest_valdef); - css_valdef_shallow_destroy(rest_valdef); - break; - } - DEBUG_MSG("%s\n\n", "css_value_matcher_match_double_ampersand() exit"); - return ret; + int ret = -1; + unsigned i = 0; + list_node_t *node; + css_valdef_t *rest_valdef; + char str[256]; + + DEBUG_MSG("\n%s\n", + "css_value_matcher_match_double_ampersand() enter\n"); + for (list_each(node, &valdef->children)) { + css_valdef_to_string(node->data, str, 255); + DEBUG_MSG("[%u/%zu] matcher->value_str: %s\n", i + 1, + valdef->children.length, matcher->value_str); + if (css_value_matcher_match(matcher, node->data) != 0) { + i++; + DEBUG_MSG("[%u/%zu] not matched valdef: %s\n", i + 1, + valdef->children.length, str); + continue; + } + DEBUG_MSG("[%u/%zu] matched valdef: %s\n", i + 1, + valdef->children.length, str); + if (valdef->children.length < 2) { + ret = 0; + break; + } + DEBUG_MSG("match rest valdef %u\n", + valdef->children.length - 1); + rest_valdef = css_valdef_shallow_copy(valdef); + list_delete(&rest_valdef->children, i); + css_value_matcher_resolve_next_value(matcher); + ret = css_value_matcher_submatch(matcher, rest_valdef); + css_valdef_shallow_destroy(rest_valdef); + break; + } + DEBUG_MSG("%s\n\n", "css_value_matcher_match_double_ampersand() exit"); + return ret; } static int css_value_matcher_match_single_bar(css_value_matcher_t *matcher, - const css_valdef_t *valdef) + const css_valdef_t *valdef) { - size_t i = 0; - list_node_t *node; - css_value_matcher_t **submatchers; - css_value_matcher_t *submatcher = NULL; - - submatchers = - malloc(valdef->children.length * sizeof(css_value_matcher_t *)); - if (!submatchers) { - return -1; - } - DEBUG_MSG("\n%s\n", "css_value_matcher_match_single_bar() enter"); - for (list_each(node, &valdef->children)) { + size_t i = 0; + list_node_t *node; + css_value_matcher_t **submatchers; + css_value_matcher_t *submatcher = NULL; + + submatchers = + malloc(valdef->children.length * sizeof(css_value_matcher_t *)); + if (!submatchers) { + return -1; + } + DEBUG_MSG("\n%s\n", "css_value_matcher_match_single_bar() enter"); + for (list_each(node, &valdef->children)) { #ifdef DEBUG - char str[256]; + char str[256]; - css_valdef_to_string(node->data, str, 255); - DEBUG_MSG("[%u/%zu] %s\n", i + 1, valdef->children.length, str); + css_valdef_to_string(node->data, str, 255); + DEBUG_MSG("[%u/%zu] %s\n", i + 1, valdef->children.length, str); #endif - submatchers[i] = css_value_matcher_create(matcher->cur); - if (css_value_matcher_match(submatchers[i], node->data) == 0) { - DEBUG_MSG("[%u/%zu] %s matched\n", i + 1, - valdef->children.length, str); - if (!submatcher || submatchers[i]->value_len >= - submatcher->value_len) { - submatcher = submatchers[i]; - } - } else { - DEBUG_MSG("[%u/%zu] %s not matched\n", i + 1, - valdef->children.length, str); - } - ++i; - } - if (submatcher) { - matcher->value_len = - css_array_value_concat(&matcher->value, &submatcher->value); - matcher->value_str_len = submatcher->next - matcher->cur; - matcher->next = submatcher->next; - if (matcher->value_str) { - free(matcher->value_str); - matcher->value_str = NULL; - } - } - for (i = 0; i < valdef->children.length; ++i) { - css_value_matcher_destroy(submatchers[i]); - } - free(submatchers); - DEBUG_MSG("%s\n\n", "css_value_matcher_match_single_bar() exit"); - return submatcher ? 0 : -1; + submatchers[i] = css_value_matcher_create(matcher->cur); + if (css_value_matcher_match(submatchers[i], node->data) == 0) { + DEBUG_MSG("[%u/%zu] %s matched\n", i + 1, + valdef->children.length, str); + if (!submatcher || submatchers[i]->value_len >= + submatcher->value_len) { + submatcher = submatchers[i]; + } + } else { + DEBUG_MSG("[%u/%zu] %s not matched\n", i + 1, + valdef->children.length, str); + } + ++i; + } + if (submatcher) { + matcher->value_len = + css_array_value_concat(&matcher->value, &submatcher->value); + matcher->value_str_len = submatcher->next - matcher->cur; + matcher->next = submatcher->next; + if (matcher->value_str) { + free(matcher->value_str); + matcher->value_str = NULL; + } + } + for (i = 0; i < valdef->children.length; ++i) { + css_value_matcher_destroy(submatchers[i]); + } + free(submatchers); + DEBUG_MSG("%s\n\n", "css_value_matcher_match_single_bar() exit"); + return submatcher ? 0 : -1; } static int css_value_matcher_submatch(css_value_matcher_t *matcher, - const css_valdef_t *valdef) + const css_valdef_t *valdef) { - css_value_matcher_t *submatcher; - - submatcher = css_value_matcher_create(matcher->cur); - DEBUG_MSG("submatch(matcher<0x%p>): 0x%p, cur: %s\n", matcher, - submatcher, submatcher->cur); - if (css_value_matcher_match(submatcher, valdef) == 0) { - // 可选值定义允许没有匹配的值,我们需要重置 next - // 指针到当前值的开头,以让匹 配器继续使用当前值匹配下个值定义 - if (css_array_value_get_length(submatcher->value) == 0) { - matcher->next = matcher->cur; - css_value_matcher_destroy(submatcher); - return 0; - } - css_array_value_concat(&matcher->value, &submatcher->value); - matcher->value_len = css_array_value_get_length(matcher->value); - matcher->value_str_len = submatcher->next - matcher->cur; - matcher->next = submatcher->next; - if (matcher->value_str) { - free(matcher->value_str); - matcher->value_str = NULL; - } - css_value_matcher_destroy(submatcher); - return 0; - } - css_value_matcher_destroy(submatcher); - return -1; + css_value_matcher_t *submatcher; + + submatcher = css_value_matcher_create(matcher->cur); + DEBUG_MSG("submatch(matcher<0x%p>): 0x%p, cur: %s\n", matcher, + submatcher, submatcher->cur); + if (css_value_matcher_match(submatcher, valdef) == 0) { + // 可选值定义允许没有匹配的值,我们需要重置 next + // 指针到当前值的开头,以让匹 配器继续使用当前值匹配下个值定义 + if (css_array_value_get_length(submatcher->value) == 0) { + matcher->next = matcher->cur; + css_value_matcher_destroy(submatcher); + return 0; + } + css_array_value_concat(&matcher->value, &submatcher->value); + matcher->value_len = css_array_value_get_length(matcher->value); + matcher->value_str_len = submatcher->next - matcher->cur; + matcher->next = submatcher->next; + if (matcher->value_str) { + free(matcher->value_str); + matcher->value_str = NULL; + } + css_value_matcher_destroy(submatcher); + return 0; + } + css_value_matcher_destroy(submatcher); + return -1; } static int css_value_matcher_match_once(css_value_matcher_t *matcher, - const css_valdef_t *valdef) + const css_valdef_t *valdef) { - size_t i = 0; - list_node_t *node; - css_style_value_t value = { CSS_NO_VALUE }; + size_t i = 0; + list_node_t *node; + css_style_value_t value = { CSS_NO_VALUE }; #ifdef DEBUG - char str[256]; + char str[256]; - css_valdef_to_string(valdef, str, 256); - str[255] = 0; - DEBUG_MSG("match(matcher<0x%p>, \"%s\")\n", matcher, str); + css_valdef_to_string(valdef, str, 256); + str[255] = 0; + DEBUG_MSG("match(matcher<0x%p>, \"%s\")\n", matcher, str); #endif - switch (valdef->sign) { - case CSS_VALDEF_SIGN_NONE: - value.keyword_value = css_get_keyword_key(matcher->value_str); - if (valdef->ident != value.keyword_value) { - return -1; - } - value.type = CSS_KEYWORD_VALUE; - css_value_matcher_push_value(matcher, &value); - break; - case CSS_VALDEF_SIGN_ANGLE_BRACKET: - return css_value_matcher_match_data_type(matcher, valdef); - case CSS_VALDEF_SIGN_JUXTAPOSITION: - case CSS_VALDEF_SIGN_BRACKETS: - for (list_each(node, &valdef->children)) { - if (i > 0) { - css_value_matcher_resolve_next_value(matcher); - } - if (css_value_matcher_submatch(matcher, node->data) != - 0) { - return -1; - } - i++; - } - break; - case CSS_VALDEF_SIGN_SINGLE_BAR: - return css_value_matcher_match_single_bar(matcher, valdef); - case CSS_VALDEF_SIGN_DOUBLE_BAR: - return css_value_matcher_match_double_bar(matcher, valdef); - case CSS_VALDEF_SIGN_DOUBLE_AMPERSAND: - return css_value_matcher_match_double_ampersand(matcher, - valdef); - default: - return -1; - } - return 0; + switch (valdef->sign) { + case CSS_VALDEF_SIGN_NONE: + value.keyword_value = css_get_keyword_key(matcher->value_str); + if (valdef->ident != value.keyword_value) { + return -1; + } + value.type = CSS_KEYWORD_VALUE; + css_value_matcher_push_value(matcher, &value); + break; + case CSS_VALDEF_SIGN_ANGLE_BRACKET: + return css_value_matcher_match_data_type(matcher, valdef); + case CSS_VALDEF_SIGN_JUXTAPOSITION: + case CSS_VALDEF_SIGN_BRACKETS: + for (list_each(node, &valdef->children)) { + if (i > 0) { + css_value_matcher_resolve_next_value(matcher); + } + if (css_value_matcher_submatch(matcher, node->data) != + 0) { + return -1; + } + i++; + } + break; + case CSS_VALDEF_SIGN_SINGLE_BAR: + return css_value_matcher_match_single_bar(matcher, valdef); + case CSS_VALDEF_SIGN_DOUBLE_BAR: + return css_value_matcher_match_double_bar(matcher, valdef); + case CSS_VALDEF_SIGN_DOUBLE_AMPERSAND: + return css_value_matcher_match_double_ampersand(matcher, + valdef); + default: + return -1; + } + return 0; } static int css_value_matcher_match(css_value_matcher_t *matcher, - const css_valdef_t *valdef) + const css_valdef_t *valdef) { - unsigned i; - - for (i = 0; i < valdef->max_count; ++i) { - if (i > 0) { - css_value_matcher_resolve_next_value(matcher); - } - if (css_value_matcher_match_once(matcher, valdef) != 0) { - break; - } - } - return i >= valdef->min_count ? 0 : -1; + unsigned i; + + for (i = 0; i < valdef->max_count; ++i) { + if (i > 0) { + css_value_matcher_resolve_next_value(matcher); + } + if (css_value_matcher_match_once(matcher, valdef) != 0) { + break; + } + } + return i >= valdef->min_count ? 0 : -1; } int css_parse_value(const css_valdef_t *valdef, const char *str, - css_style_value_t *val) + css_style_value_t *val) { - int ret; - css_value_matcher_t *matcher; - - matcher = css_value_matcher_create(str); - if (!matcher) { - return -1; - } - ret = css_value_matcher_match(matcher, valdef); - if (ret == 0) { - val->array_value = matcher->value; - val->type = CSS_ARRAY_VALUE; - matcher->value = NULL; - ret = (int)matcher->value_str_len; - } - css_value_matcher_destroy(matcher); - return ret; + int ret; + css_value_matcher_t *matcher; + + matcher = css_value_matcher_create(str); + if (!matcher) { + return -1; + } + ret = css_value_matcher_match(matcher, valdef); + if (ret == 0) { + val->array_value = matcher->value; + val->type = CSS_ARRAY_VALUE; + matcher->value = NULL; + ret = (int)matcher->value_str_len; + } + css_value_matcher_destroy(matcher); + return ret; } int css_register_valdef_alias(const char *alias, const char *definitons) { - css_valdef_t *valdef; - - if (css_get_keyword_key(alias) >= 0) { - return -1; - } - valdef = css_compile_valdef(definitons); - if (valdef) { - return dict_add(css_value.alias, (void *)alias, valdef); - } - return -3; + css_valdef_t *valdef; + + if (css_get_keyword_key(alias) >= 0) { + return -1; + } + valdef = css_compile_valdef(definitons); + if (valdef) { + return dict_add(css_value.alias, (void *)alias, valdef); + } + return -3; } static void css_dump_valdef(const css_valdef_t *valdef, css_dump_context_t *ctx) { - size_t len = 0, i = 0; - list_node_t *node; - const char *name; - - switch (valdef->sign) { - case CSS_VALDEF_SIGN_NONE: - name = css_get_keyword_name(valdef->ident); - if (!name) { - name = "unknown"; - } - DUMP(name); - break; - case CSS_VALDEF_SIGN_ANGLE_BRACKET: - DUMPF("<%s>", - valdef->type ? valdef->type->name : "unknown-type"); - break; - case CSS_VALDEF_SIGN_JUXTAPOSITION: - DUMP("("); - len++; - for (list_each(node, &valdef->children)) { - css_dump_valdef(node->data, ctx); - if (i + 1 < valdef->children.length) { - DUMP(" "); - } - i++; - } - DUMP(")"); - len++; - break; - case CSS_VALDEF_SIGN_SINGLE_BAR: - for (list_each(node, &valdef->children)) { - css_dump_valdef(node->data, ctx); - if (i + 1 < valdef->children.length) { - DUMP(" | "); - } - i++; - } - break; - case CSS_VALDEF_SIGN_DOUBLE_BAR: - for (list_each(node, &valdef->children)) { - css_dump_valdef(node->data, ctx); - if (i + 1 < valdef->children.length) { - DUMP(" || "); - } - i++; - } - break; - case CSS_VALDEF_SIGN_DOUBLE_AMPERSAND: - for (list_each(node, &valdef->children)) { - css_dump_valdef(node->data, ctx); - if (i + 1 < valdef->children.length) { - DUMP(" && "); - } - i++; - } - break; - case CSS_VALDEF_SIGN_BRACKETS: - DUMP("["); - for (list_each(node, &valdef->children)) { - css_dump_valdef(node->data, ctx); - if (i + 1 < valdef->children.length) { - DUMP(" "); - } - i++; - } - DUMP("]"); - break; - default: - DUMP("unknown syntax"); - break; - } - if (valdef->min_count == 0 && valdef->max_count == 1) { - DUMP("?"); - } else if (valdef->max_count > 1) { - DUMPF("{%u,%u}", valdef->min_count, valdef->max_count); - } + size_t len = 0, i = 0; + list_node_t *node; + const char *name; + + switch (valdef->sign) { + case CSS_VALDEF_SIGN_NONE: + name = css_get_keyword_name(valdef->ident); + if (!name) { + name = "unknown"; + } + DUMP(name); + break; + case CSS_VALDEF_SIGN_ANGLE_BRACKET: + DUMPF("<%s>", + valdef->type ? valdef->type->name : "unknown-type"); + break; + case CSS_VALDEF_SIGN_JUXTAPOSITION: + DUMP("("); + len++; + for (list_each(node, &valdef->children)) { + css_dump_valdef(node->data, ctx); + if (i + 1 < valdef->children.length) { + DUMP(" "); + } + i++; + } + DUMP(")"); + len++; + break; + case CSS_VALDEF_SIGN_SINGLE_BAR: + for (list_each(node, &valdef->children)) { + css_dump_valdef(node->data, ctx); + if (i + 1 < valdef->children.length) { + DUMP(" | "); + } + i++; + } + break; + case CSS_VALDEF_SIGN_DOUBLE_BAR: + for (list_each(node, &valdef->children)) { + css_dump_valdef(node->data, ctx); + if (i + 1 < valdef->children.length) { + DUMP(" || "); + } + i++; + } + break; + case CSS_VALDEF_SIGN_DOUBLE_AMPERSAND: + for (list_each(node, &valdef->children)) { + css_dump_valdef(node->data, ctx); + if (i + 1 < valdef->children.length) { + DUMP(" && "); + } + i++; + } + break; + case CSS_VALDEF_SIGN_BRACKETS: + DUMP("["); + for (list_each(node, &valdef->children)) { + css_dump_valdef(node->data, ctx); + if (i + 1 < valdef->children.length) { + DUMP(" "); + } + i++; + } + DUMP("]"); + break; + default: + DUMP("unknown syntax"); + break; + } + if (valdef->min_count == 0 && valdef->max_count == 1) { + DUMP("?"); + } else if (valdef->max_count > 1) { + DUMPF("{%u,%u}", valdef->min_count, valdef->max_count); + } } size_t css_print_valdef(const css_valdef_t *s) { - css_dump_context_t ctx = { - .data = NULL, .len = 0, .max_len = 0, .func = css_dump_to_stdout - }; + css_dump_context_t ctx = { + .data = NULL, .len = 0, .max_len = 0, .func = css_dump_to_stdout + }; - css_dump_valdef(s, &ctx); - return ctx.len; + css_dump_valdef(s, &ctx); + return ctx.len; } size_t css_valdef_to_string(const css_valdef_t *s, char *str, size_t max_len) { - css_dump_context_t ctx = { .data = str, - .len = 0, - .max_len = max_len, - .func = css_dump_to_buffer }; + css_dump_context_t ctx = { .data = str, + .len = 0, + .max_len = max_len, + .func = css_dump_to_buffer }; - css_dump_valdef(s, &ctx); - return ctx.len; + css_dump_valdef(s, &ctx); + return ctx.len; } diff --git a/lib/css/tests/test.c b/lib/css/tests/test.c index 8fb936f52..97156cb10 100644 --- a/lib/css/tests/test.c +++ b/lib/css/tests/test.c @@ -1,12 +1,15 @@ /* * lib/css/tests/test.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -15,9 +18,9 @@ int main() { - logger_set_level(LOGGER_LEVEL_ALL); - ctest_describe("test_css_keywords", test_css_keywords); - ctest_describe("test_css_value", test_css_value); - ctest_describe("test_css_computed", test_css_computed); - return ctest_finish(); + logger_set_level(LOGGER_LEVEL_ALL); + ctest_describe("test_css_keywords", test_css_keywords); + ctest_describe("test_css_value", test_css_value); + ctest_describe("test_css_computed", test_css_computed); + return ctest_finish(); } diff --git a/lib/css/tests/test.h b/lib/css/tests/test.h index fc37bb54b..dfd0b0282 100644 --- a/lib/css/tests/test.h +++ b/lib/css/tests/test.h @@ -1,7 +1,7 @@ /* * lib/css/tests/test.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/css/tests/test_css_computed.c b/lib/css/tests/test_css_computed.c index 67c4eeab2..afee41283 100644 --- a/lib/css/tests/test_css_computed.c +++ b/lib/css/tests/test_css_computed.c @@ -1,12 +1,15 @@ /* * lib/css/tests/test_css_computed.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/css/tests/test_css_keywords.c b/lib/css/tests/test_css_keywords.c index 1cadaef55..6e73ae6cb 100644 --- a/lib/css/tests/test_css_keywords.c +++ b/lib/css/tests/test_css_keywords.c @@ -1,12 +1,15 @@ /* * lib/css/tests/test_css_keywords.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -16,32 +19,32 @@ static void test_keyword_value(const char *name, int value) { - char str[256] = { 0 }; + char str[256] = { 0 }; - snprintf(str, 255, "keyword('%s').value", name); - ctest_equal_int(str, css_get_keyword_key(name), value); + snprintf(str, 255, "keyword('%s').value", name); + ctest_equal_int(str, css_get_keyword_key(name), value); } static void test_keyword_register(const char *name) { - char str[256] = { 0 }; - int a = css_register_keyword(name); - int b = css_get_keyword_key(name); + char str[256] = { 0 }; + int a = css_register_keyword(name); + int b = css_get_keyword_key(name); - snprintf(str, 255, "keyword('%s')", name); - ctest_equal_int(str, a, b); + snprintf(str, 255, "keyword('%s')", name); + ctest_equal_int(str, a, b); } void test_css_keywords(void) { - css_init_keywords(); + css_init_keywords(); - test_keyword_value("inherit", CSS_KEYWORD_INHERIT); - test_keyword_value("none", CSS_KEYWORD_NONE); - test_keyword_value("auto", CSS_KEYWORD_AUTO); - test_keyword_value("center", CSS_KEYWORD_CENTER); - test_keyword_value("inline-block", CSS_KEYWORD_INLINE_BLOCK); - test_keyword_register("custom-keyword"); + test_keyword_value("inherit", CSS_KEYWORD_INHERIT); + test_keyword_value("none", CSS_KEYWORD_NONE); + test_keyword_value("auto", CSS_KEYWORD_AUTO); + test_keyword_value("center", CSS_KEYWORD_CENTER); + test_keyword_value("inline-block", CSS_KEYWORD_INLINE_BLOCK); + test_keyword_register("custom-keyword"); - css_destroy_keywords(); + css_destroy_keywords(); } diff --git a/lib/css/tests/test_css_value.c b/lib/css/tests/test_css_value.c index 3c6d0a861..8b1bed579 100644 --- a/lib/css/tests/test_css_value.c +++ b/lib/css/tests/test_css_value.c @@ -1,12 +1,15 @@ /* * lib/css/tests/test_css_value.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -16,430 +19,440 @@ static void test_css_valdef_string(const css_valdef_t *valdef) { - int ret; - css_style_value_t val = { 0 }; - - ret = css_parse_value(valdef, "\"abc\"", &val) > 0 && - val.type == CSS_ARRAY_VALUE; - if (ret) { - ret = val.array_value[0].type == CSS_STRING_VALUE; - } - css_style_value_destroy(&val); - ctest_equal_bool("match('\"abc\"')", ret, 1); - ctest_equal_bool("match('auto')", css_parse_value(valdef, "auto", &val) > 0, 1); - css_style_value_destroy(&val); + int ret; + css_style_value_t val = { 0 }; + + ret = css_parse_value(valdef, "\"abc\"", &val) > 0 && + val.type == CSS_ARRAY_VALUE; + if (ret) { + ret = val.array_value[0].type == CSS_STRING_VALUE; + } + css_style_value_destroy(&val); + ctest_equal_bool("match('\"abc\"')", ret, 1); + ctest_equal_bool("match('auto')", + css_parse_value(valdef, "auto", &val) > 0, 1); + css_style_value_destroy(&val); } static void test_css_valdef_color(const css_valdef_t *valdef) { - css_color_value_t color; - css_style_value_t val = { 0 }; - - color = 0; - if (css_parse_value(valdef, "#fff", &val) > 0 && - val.array_value[0].type == CSS_COLOR_VALUE) { - color = val.array_value[0].color_value; - } - css_style_value_destroy(&val); - - ctest_equal_uint("match('#fff')", (int)color, (int)css_color(255, 255, 255, 255)); - - color = 0; - if (css_parse_value(valdef, "#ffffff", &val) > 0 && - val.array_value[0].type == CSS_COLOR_VALUE) { - color = val.array_value[0].color_value; - } - css_style_value_destroy(&val); - - ctest_equal_uint("match('#ffffff')", color, css_color(255, 255, 255, 255)); - - color = 0; - if (css_parse_value(valdef, "transparent", &val) > 0 && - val.array_value[0].type == CSS_COLOR_VALUE) { - color = val.array_value[0].color_value; - } - css_style_value_destroy(&val); - - ctest_equal_uint("match('transparent')", color, CSS_COLOR_TRANSPARENT); - - color = 0; - if (css_parse_value(valdef, "rgb(100, 200, 255)", &val) > 0 && - val.array_value[0].type == CSS_COLOR_VALUE) { - color = val.array_value[0].color_value; - } - css_style_value_destroy(&val); - - ctest_equal_uint("match('rgb(100, 200, 255)')", color, - css_color(255, 100, 200, 255)); - - color = 0; - if (css_parse_value(valdef, "rgba(100, 200, 255, 0.5)", &val) > 0 && - val.array_value[0].type == CSS_COLOR_VALUE) { - color = val.array_value[0].color_value; - } - css_style_value_destroy(&val); - - ctest_equal_uint("match('rgba(100, 200, 255, 0.5)')", color, - css_color(127, 100, 200, 255)); + css_color_value_t color; + css_style_value_t val = { 0 }; + + color = 0; + if (css_parse_value(valdef, "#fff", &val) > 0 && + val.array_value[0].type == CSS_COLOR_VALUE) { + color = val.array_value[0].color_value; + } + css_style_value_destroy(&val); + + ctest_equal_uint("match('#fff')", (int)color, + (int)css_color(255, 255, 255, 255)); + + color = 0; + if (css_parse_value(valdef, "#ffffff", &val) > 0 && + val.array_value[0].type == CSS_COLOR_VALUE) { + color = val.array_value[0].color_value; + } + css_style_value_destroy(&val); + + ctest_equal_uint("match('#ffffff')", color, + css_color(255, 255, 255, 255)); + + color = 0; + if (css_parse_value(valdef, "transparent", &val) > 0 && + val.array_value[0].type == CSS_COLOR_VALUE) { + color = val.array_value[0].color_value; + } + css_style_value_destroy(&val); + + ctest_equal_uint("match('transparent')", color, CSS_COLOR_TRANSPARENT); + + color = 0; + if (css_parse_value(valdef, "rgb(100, 200, 255)", &val) > 0 && + val.array_value[0].type == CSS_COLOR_VALUE) { + color = val.array_value[0].color_value; + } + css_style_value_destroy(&val); + + ctest_equal_uint("match('rgb(100, 200, 255)')", color, + css_color(255, 100, 200, 255)); + + color = 0; + if (css_parse_value(valdef, "rgba(100, 200, 255, 0.5)", &val) > 0 && + val.array_value[0].type == CSS_COLOR_VALUE) { + color = val.array_value[0].color_value; + } + css_style_value_destroy(&val); + + ctest_equal_uint("match('rgba(100, 200, 255, 0.5)')", color, + css_color(127, 100, 200, 255)); } static void test_css_valdef_none(const css_valdef_t *valdef) { - int ret; - css_style_value_t val = { 0 }; - - ret = css_parse_value(valdef, "none", &val) > 0 && - val.type == CSS_ARRAY_VALUE; - if (ret) { - ret = val.array_value[0].keyword_value == - css_get_keyword_key("none"); - } - css_style_value_destroy(&val); - ctest_equal_bool("match('none')", ret, 1); - ctest_equal_bool("notMatch('auto')", css_parse_value(valdef, "auto", &val) <= 0, 1); - css_style_value_destroy(&val); + int ret; + css_style_value_t val = { 0 }; + + ret = css_parse_value(valdef, "none", &val) > 0 && + val.type == CSS_ARRAY_VALUE; + if (ret) { + ret = val.array_value[0].keyword_value == + css_get_keyword_key("none"); + } + css_style_value_destroy(&val); + ctest_equal_bool("match('none')", ret, 1); + ctest_equal_bool("notMatch('auto')", + css_parse_value(valdef, "auto", &val) <= 0, 1); + css_style_value_destroy(&val); } static void test_css_valdef_none_or_auto(const css_valdef_t *valdef) { - int ret; - css_style_value_t val = { 0 }; - - ret = css_parse_value(valdef, "none", &val) > 0 && - val.type == CSS_ARRAY_VALUE; - if (ret) { - ret = val.array_value[0].keyword_value == - css_get_keyword_key("none"); - } - css_style_value_destroy(&val); - - ctest_equal_bool("match('none')", ret, 1); - - ret = css_parse_value(valdef, "auto", &val) > 0 && - val.type == CSS_ARRAY_VALUE; - ctest_equal_bool("match('auto')", ret, 1); - ctest_equal_bool("notMatch('normal')", css_parse_value(valdef, "normal", &val) <= 0, - 1); - css_style_value_destroy(&val); + int ret; + css_style_value_t val = { 0 }; + + ret = css_parse_value(valdef, "none", &val) > 0 && + val.type == CSS_ARRAY_VALUE; + if (ret) { + ret = val.array_value[0].keyword_value == + css_get_keyword_key("none"); + } + css_style_value_destroy(&val); + + ctest_equal_bool("match('none')", ret, 1); + + ret = css_parse_value(valdef, "auto", &val) > 0 && + val.type == CSS_ARRAY_VALUE; + ctest_equal_bool("match('auto')", ret, 1); + ctest_equal_bool("notMatch('normal')", + css_parse_value(valdef, "normal", &val) <= 0, 1); + css_style_value_destroy(&val); } static void test_css_valdef_border(const css_valdef_t *valdef) { - int ret; - css_style_value_t val = { 0 }; - - ctest_equal_bool("match('1px solid #eee')", - css_parse_value(valdef, "1px solid #eee", &val) > 0, 1); - css_style_value_destroy(&val); - - ctest_equal_bool("match('#eee 1px solid')", - css_parse_value(valdef, "#eee 1px solid", &val) > 0, 1); - css_style_value_destroy(&val); - - ctest_equal_bool("match('solid #eee 1px')", - css_parse_value(valdef, "solid #eee 1px", &val) > 0, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "1px", &val) > 0 && - val.type == CSS_ARRAY_VALUE; - if (ret) { - ret = val.array_value[0].type == CSS_UNIT_VALUE && - val.array_value[0].unit_value.value == 1.; - } - ctest_equal_bool("match('1px')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "solid", &val) > 0 && - val.type == CSS_ARRAY_VALUE; - if (ret) { - ret = val.array_value[0].type == CSS_KEYWORD_VALUE && - val.array_value[0].keyword_value == - css_get_keyword_key("solid"); - } - ctest_equal_bool("match('solid')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "#eee", &val) > 0 && - val.type == CSS_ARRAY_VALUE; - ret = val.array_value[0].color_value == 0xffeeeeee; - ctest_equal_bool("match('#eee')", ret, 1); - css_style_value_destroy(&val); + int ret; + css_style_value_t val = { 0 }; + + ctest_equal_bool("match('1px solid #eee')", + css_parse_value(valdef, "1px solid #eee", &val) > 0, + 1); + css_style_value_destroy(&val); + + ctest_equal_bool("match('#eee 1px solid')", + css_parse_value(valdef, "#eee 1px solid", &val) > 0, + 1); + css_style_value_destroy(&val); + + ctest_equal_bool("match('solid #eee 1px')", + css_parse_value(valdef, "solid #eee 1px", &val) > 0, + 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "1px", &val) > 0 && + val.type == CSS_ARRAY_VALUE; + if (ret) { + ret = val.array_value[0].type == CSS_UNIT_VALUE && + val.array_value[0].unit_value.value == 1.; + } + ctest_equal_bool("match('1px')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "solid", &val) > 0 && + val.type == CSS_ARRAY_VALUE; + if (ret) { + ret = val.array_value[0].type == CSS_KEYWORD_VALUE && + val.array_value[0].keyword_value == + css_get_keyword_key("solid"); + } + ctest_equal_bool("match('solid')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "#eee", &val) > 0 && + val.type == CSS_ARRAY_VALUE; + ret = val.array_value[0].color_value == 0xffeeeeee; + ctest_equal_bool("match('#eee')", ret, 1); + css_style_value_destroy(&val); } static void test_css_valdef_border_2(const css_valdef_t *valdef) { - int ret; - css_style_value_t val = { 0 }; - - ctest_equal_bool("match('1px solid #eee')", - css_parse_value(valdef, "1px solid #eee", &val) > 0, 1); - css_style_value_destroy(&val); - - ctest_equal_bool("match('#eee 1px solid')", - css_parse_value(valdef, "#eee 1px solid", &val) > 0, 1); - css_style_value_destroy(&val); - - ctest_equal_bool("match('solid #eee 1px')", - css_parse_value(valdef, "solid #eee 1px", &val) > 0, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "1px", &val) > 0 && - val.type == CSS_ARRAY_VALUE; - ctest_equal_bool("notMatch('1px')", ret, 0); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "solid", &val) > 0 && - val.type == CSS_ARRAY_VALUE; - ctest_equal_bool("notMatch('solid')", ret, 0); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "#eee", &val) > 0 && - val.type == CSS_ARRAY_VALUE; - ctest_equal_bool("notMatch('#eee')", ret, 0); - css_style_value_destroy(&val); + int ret; + css_style_value_t val = { 0 }; + + ctest_equal_bool("match('1px solid #eee')", + css_parse_value(valdef, "1px solid #eee", &val) > 0, + 1); + css_style_value_destroy(&val); + + ctest_equal_bool("match('#eee 1px solid')", + css_parse_value(valdef, "#eee 1px solid", &val) > 0, + 1); + css_style_value_destroy(&val); + + ctest_equal_bool("match('solid #eee 1px')", + css_parse_value(valdef, "solid #eee 1px", &val) > 0, + 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "1px", &val) > 0 && + val.type == CSS_ARRAY_VALUE; + ctest_equal_bool("notMatch('1px')", ret, 0); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "solid", &val) > 0 && + val.type == CSS_ARRAY_VALUE; + ctest_equal_bool("notMatch('solid')", ret, 0); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "#eee", &val) > 0 && + val.type == CSS_ARRAY_VALUE; + ctest_equal_bool("notMatch('#eee')", ret, 0); + css_style_value_destroy(&val); } static void test_css_valdef_box_shadow(const css_valdef_t *valdef) { - css_style_value_t val = { 0 }; - - ctest_equal_bool("match('none')", - css_parse_value(valdef, "none", &val) > 0 && - val.array_value[0].keyword_value == CSS_KEYWORD_NONE, - 1); - css_style_value_destroy(&val); - - ctest_equal_bool("match('0 0')", - css_parse_value(valdef, "0 0", &val) > 0 && - css_style_value_get_array_length(&val) == 2, - 1); - css_style_value_destroy(&val); - - ctest_equal_bool("match('0 0 4px')", - css_parse_value(valdef, "0 0 4px", &val) > 0 && - css_style_value_get_array_length(&val) == 3, - 1); - css_style_value_destroy(&val); - - ctest_equal_bool("match('0 0 4px #000')", - css_parse_value(valdef, "0 0 4px #000", &val) > 0 && - css_style_value_get_array_length(&val) == 4, - 1); - css_style_value_destroy(&val); - - ctest_equal_bool( - "match('0 0 6px rgba(33,150,243,0.4)')", - css_parse_value(valdef, "0 0 6px rgba(33,150,243,0.4)", &val) > 0 && - css_style_value_get_array_length(&val) == 4 && - val.array_value[3].color_value == - css_color((uint8_t)(0.4 * 0xff), 33, 150, 243), - 1); - css_style_value_destroy(&val); + css_style_value_t val = { 0 }; + + ctest_equal_bool( + "match('none')", + css_parse_value(valdef, "none", &val) > 0 && + val.array_value[0].keyword_value == CSS_KEYWORD_NONE, + 1); + css_style_value_destroy(&val); + + ctest_equal_bool("match('0 0')", + css_parse_value(valdef, "0 0", &val) > 0 && + css_style_value_get_array_length(&val) == 2, + 1); + css_style_value_destroy(&val); + + ctest_equal_bool("match('0 0 4px')", + css_parse_value(valdef, "0 0 4px", &val) > 0 && + css_style_value_get_array_length(&val) == 3, + 1); + css_style_value_destroy(&val); + + ctest_equal_bool("match('0 0 4px #000')", + css_parse_value(valdef, "0 0 4px #000", &val) > 0 && + css_style_value_get_array_length(&val) == 4, + 1); + css_style_value_destroy(&val); + + ctest_equal_bool( + "match('0 0 6px rgba(33,150,243,0.4)')", + css_parse_value(valdef, "0 0 6px rgba(33,150,243,0.4)", &val) > 0 && + css_style_value_get_array_length(&val) == 4 && + val.array_value[3].color_value == + css_color((uint8_t)(0.4 * 0xff), 33, 150, 243), + 1); + css_style_value_destroy(&val); } static void test_css_valdef_length_2(const css_valdef_t *valdef) { - int ret; - css_style_value_t val = { 0 }; - - ret = css_parse_value(valdef, "1px 2px", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 2; - ctest_equal_bool("match('1px 2px')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "1px", &val) != 0; - ctest_equal_bool("notMatch('1px')", ret, 1); - css_style_value_destroy(&val); + int ret; + css_style_value_t val = { 0 }; + + ret = css_parse_value(valdef, "1px 2px", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 2; + ctest_equal_bool("match('1px 2px')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "1px", &val) != 0; + ctest_equal_bool("notMatch('1px')", ret, 1); + css_style_value_destroy(&val); } static void test_css_valdef_length_1_4(const css_valdef_t *valdef) { - int ret; - css_style_value_t val = { 0 }; - - ret = css_parse_value(valdef, "", &val) <= 0; - ctest_equal_bool("notMatch('')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "1px", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 1; - ctest_equal_bool("match('1px')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "1px 2px", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 2; - ctest_equal_bool("match('1px 2px')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "1px 2px 3px", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 3; - ctest_equal_bool("match('1px 2px 3px')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "1px 2px 3px 4px", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 4; - ctest_equal_bool("match('1px 2px 3px 4px')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "1px 2px 3px 4px 5px", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 4; - ctest_equal_bool("Match('1px 2px 3px 4px 5px')", ret, 1); - css_style_value_destroy(&val); + int ret; + css_style_value_t val = { 0 }; + + ret = css_parse_value(valdef, "", &val) <= 0; + ctest_equal_bool("notMatch('')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "1px", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 1; + ctest_equal_bool("match('1px')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "1px 2px", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 2; + ctest_equal_bool("match('1px 2px')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "1px 2px 3px", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 3; + ctest_equal_bool("match('1px 2px 3px')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "1px 2px 3px 4px", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 4; + ctest_equal_bool("match('1px 2px 3px 4px')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "1px 2px 3px 4px 5px", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 4; + ctest_equal_bool("Match('1px 2px 3px 4px 5px')", ret, 1); + css_style_value_destroy(&val); } static void test_css_valdef_length_percentage_1_4(const css_valdef_t *valdef) { - int ret; - css_style_value_t val = { 0 }; - - ret = css_parse_value(valdef, "", &val) <= 0; - ctest_equal_bool("notMatch('')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "1px", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 1; - ctest_equal_bool("match('1px')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "1px", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 1; - ctest_equal_bool("match('50%')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "1px 2px", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 2; - ctest_equal_bool("match('1px 2px')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "1px 2px", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 2; - ctest_equal_bool("match('50% 50%')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "1px 2px 3px", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 3; - ctest_equal_bool("match('1px 2px 3px')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "1px 2px 3px", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 3; - ctest_equal_bool("match('50% 50% 50%')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "1px 2px 3px 4px", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 4; - ctest_equal_bool("match('1px 2px 3px 4px')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "1px 2px 3px 4px", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 4; - ctest_equal_bool("match('50% 50% 50% 50%')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "1px 2px 3px 4px 5px", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 4; - ctest_equal_bool("Match('1px 2px 3px 4px 5px')", ret, 1); - css_style_value_destroy(&val); + int ret; + css_style_value_t val = { 0 }; + + ret = css_parse_value(valdef, "", &val) <= 0; + ctest_equal_bool("notMatch('')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "1px", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 1; + ctest_equal_bool("match('1px')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "1px", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 1; + ctest_equal_bool("match('50%')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "1px 2px", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 2; + ctest_equal_bool("match('1px 2px')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "1px 2px", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 2; + ctest_equal_bool("match('50% 50%')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "1px 2px 3px", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 3; + ctest_equal_bool("match('1px 2px 3px')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "1px 2px 3px", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 3; + ctest_equal_bool("match('50% 50% 50%')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "1px 2px 3px 4px", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 4; + ctest_equal_bool("match('1px 2px 3px 4px')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "1px 2px 3px 4px", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 4; + ctest_equal_bool("match('50% 50% 50% 50%')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "1px 2px 3px 4px 5px", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 4; + ctest_equal_bool("Match('1px 2px 3px 4px 5px')", ret, 1); + css_style_value_destroy(&val); } static void test_css_valdef_background_position(const css_valdef_t *valdef) { - int ret; - size_t len; - css_style_value_t val = { 0 }; - - ret = css_parse_value(valdef, "center", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 1; - ctest_equal_bool("match('center')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "10px", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 1; - ctest_equal_bool("match('10px')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "50%", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 1; - ctest_equal_bool("match('50%')", ret, 1); - css_style_value_destroy(&val); - - if (css_parse_value(valdef, "top center", &val) > 0) { - len = css_style_value_get_array_length(&val); - ret = len == 2; - } else { - ret = 0; - } - ctest_equal_bool("match('top center')", ret, 1); - css_style_value_destroy(&val); - - ret = css_parse_value(valdef, "bottom 10px right 20px", &val) > 0 && - val.type == CSS_ARRAY_VALUE && - css_style_value_get_array_length(&val) == 4; - ctest_equal_bool("match('bottom 10px right 20px')", ret, 1); - css_style_value_destroy(&val); + int ret; + size_t len; + css_style_value_t val = { 0 }; + + ret = css_parse_value(valdef, "center", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 1; + ctest_equal_bool("match('center')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "10px", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 1; + ctest_equal_bool("match('10px')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "50%", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 1; + ctest_equal_bool("match('50%')", ret, 1); + css_style_value_destroy(&val); + + if (css_parse_value(valdef, "top center", &val) > 0) { + len = css_style_value_get_array_length(&val); + ret = len == 2; + } else { + ret = 0; + } + ctest_equal_bool("match('top center')", ret, 1); + css_style_value_destroy(&val); + + ret = css_parse_value(valdef, "bottom 10px right 20px", &val) > 0 && + val.type == CSS_ARRAY_VALUE && + css_style_value_get_array_length(&val) == 4; + ctest_equal_bool("match('bottom 10px right 20px')", ret, 1); + css_style_value_destroy(&val); } static void test_css_valdef(const char *definition, - void (*func)(const css_valdef_t *)) + void (*func)(const css_valdef_t *)) { - char str[256] = { 0 }; - css_valdef_t *valdef; - - snprintf(str, 255, "valdef('%s')", definition); - ctest_printf("%s\n", str); - ctest_group_begin(); - valdef = css_compile_valdef(definition); - if (valdef) { - func(valdef); - } else { - ctest_equal_bool("should be able to parse", 0, 1); - } - ctest_group_end(); - ctest_printf("\n"); - css_valdef_destroy(valdef); + char str[256] = { 0 }; + css_valdef_t *valdef; + + snprintf(str, 255, "valdef('%s')", definition); + ctest_printf("%s\n", str); + ctest_group_begin(); + valdef = css_compile_valdef(definition); + if (valdef) { + func(valdef); + } else { + ctest_equal_bool("should be able to parse", 0, 1); + } + ctest_group_end(); + ctest_printf("\n"); + css_valdef_destroy(valdef); } void test_css_value(void) { - css_init(); - - /** - * TODO: 添加 测试 - * 参考:https://developer.mozilla.org/zh-CN/docs/Web/CSS/Value_definition_syntax#%E4%BA%95%E5%8F%B7 - * 添加支持用 # 号标识值能出现一次或多次,多次时以逗号分隔 - */ - test_css_valdef("", test_css_valdef_string); - test_css_valdef("", test_css_valdef_color); - test_css_valdef("none", test_css_valdef_none); - test_css_valdef("none | auto", test_css_valdef_none_or_auto); - test_css_valdef(" || || ", - test_css_valdef_border); - test_css_valdef(" && && ", - test_css_valdef_border_2); - test_css_valdef("none | ", test_css_valdef_box_shadow); - test_css_valdef("{2}", test_css_valdef_length_2); - test_css_valdef("{1, 4}", test_css_valdef_length_1_4); - test_css_valdef("{1, 4}", - test_css_valdef_length_percentage_1_4); - test_css_valdef("", - test_css_valdef_background_position); - css_destroy(); + css_init(); + + /** + * TODO: 添加 测试 + * 参考:https://developer.mozilla.org/zh-CN/docs/Web/CSS/Value_definition_syntax#%E4%BA%95%E5%8F%B7 + * 添加支持用 # 号标识值能出现一次或多次,多次时以逗号分隔 + */ + test_css_valdef("", test_css_valdef_string); + test_css_valdef("", test_css_valdef_color); + test_css_valdef("none", test_css_valdef_none); + test_css_valdef("none | auto", test_css_valdef_none_or_auto); + test_css_valdef(" || || ", + test_css_valdef_border); + test_css_valdef(" && && ", + test_css_valdef_border_2); + test_css_valdef("none | ", test_css_valdef_box_shadow); + test_css_valdef("{2}", test_css_valdef_length_2); + test_css_valdef("{1, 4}", test_css_valdef_length_1_4); + test_css_valdef("{1, 4}", + test_css_valdef_length_percentage_1_4); + test_css_valdef("", test_css_valdef_background_position); + css_destroy(); } diff --git a/lib/ctest/include/ctest.h b/lib/ctest/include/ctest.h index c3682d5ab..e8efae8ef 100644 --- a/lib/ctest/include/ctest.h +++ b/lib/ctest/include/ctest.h @@ -1,12 +1,15 @@ /* * lib/ctest/include/ctest.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_CTEST_INCLUDE_CTEST_H diff --git a/lib/ctest/src/ctest.c b/lib/ctest/src/ctest.c index f5786a319..8e36d94ea 100644 --- a/lib/ctest/src/ctest.c +++ b/lib/ctest/src/ctest.c @@ -1,12 +1,15 @@ /* * lib/ctest/src/ctest.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ctest/tests/main.c b/lib/ctest/tests/main.c index 1fbf27786..c4ce6120a 100644 --- a/lib/ctest/tests/main.c +++ b/lib/ctest/tests/main.c @@ -1,12 +1,15 @@ -/* +/* * lib/ctest/tests/main.c * - * Copyright (c) 2026, Liu Chao All rights reserved. + * Copyright (c) 2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is + * part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT + * file in the root directory of this source tree. */ #include diff --git a/lib/ctest/tests/test_grep.c b/lib/ctest/tests/test_grep.c index 2b0e8256b..b3fb801e8 100644 --- a/lib/ctest/tests/test_grep.c +++ b/lib/ctest/tests/test_grep.c @@ -1,3 +1,17 @@ +/* + * lib/ctest/tests/test_grep.c + * + * Copyright (c) 2026, Liu Chao + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. + */ + #include #include #include diff --git a/lib/ctest/tests/test_str.c b/lib/ctest/tests/test_str.c index 97f50e29b..c86742b01 100644 --- a/lib/ctest/tests/test_str.c +++ b/lib/ctest/tests/test_str.c @@ -1,3 +1,17 @@ +/* + * lib/ctest/tests/test_str.c + * + * Copyright (c) 2026, Liu Chao + * All rights reserved. + * + * SPDX-License-Identifier: MIT + * + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. + */ + #include #include #include diff --git a/lib/i18n/include/i18n.h b/lib/i18n/include/i18n.h index 1cc18e6f2..7686cefe6 100644 --- a/lib/i18n/include/i18n.h +++ b/lib/i18n/include/i18n.h @@ -1,7 +1,7 @@ /* * lib/i18n/include/i18n.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2025, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/i18n/src/i18n-dict.c b/lib/i18n/src/i18n-dict.c index 1c2abfacf..2135316e2 100644 --- a/lib/i18n/src/i18n-dict.c +++ b/lib/i18n/src/i18n-dict.c @@ -1,12 +1,15 @@ /* * lib/i18n/src/i18n-dict.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "i18n-private.h" diff --git a/lib/i18n/src/i18n-private.h b/lib/i18n/src/i18n-private.h index adae3b577..9eaccfcf6 100644 --- a/lib/i18n/src/i18n-private.h +++ b/lib/i18n/src/i18n-private.h @@ -1,12 +1,15 @@ /* * lib/i18n/src/i18n-private.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/i18n/src/i18n.c b/lib/i18n/src/i18n.c index 8dac47c5c..675df3460 100644 --- a/lib/i18n/src/i18n.c +++ b/lib/i18n/src/i18n.c @@ -1,12 +1,15 @@ /* * lib/i18n/src/i18n.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "i18n-private.h" diff --git a/lib/i18n/src/i18n.h.in b/lib/i18n/src/i18n.h.in index 8b5bfd113..b0c660356 100644 --- a/lib/i18n/src/i18n.h.in +++ b/lib/i18n/src/i18n.h.in @@ -1,7 +1,7 @@ /* * lib/i18n/include/i18n.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2025, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/i18n/src/yaml.c b/lib/i18n/src/yaml.c index a605d1147..3ca593c84 100644 --- a/lib/i18n/src/yaml.c +++ b/lib/i18n/src/yaml.c @@ -1,12 +1,15 @@ /* * lib/i18n/src/yaml.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -73,7 +76,7 @@ dict_t *i18n_load_yaml_file(const char *path) return NULL; } if (!yaml_parser_initialize(&parser)) { - free(buffer); + free(buffer); logger_error("[i18n] failed to initialize parser!\n"); return NULL; } diff --git a/lib/i18n/tests/test.c b/lib/i18n/tests/test.c index e76cbd8e8..37dd67cda 100644 --- a/lib/i18n/tests/test.c +++ b/lib/i18n/tests/test.c @@ -1,12 +1,15 @@ /* * lib/i18n/tests/test.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/pandagl/examples/cairo/src/main.c b/lib/pandagl/examples/cairo/src/main.c index e04709ddf..10b51414b 100644 --- a/lib/pandagl/examples/cairo/src/main.c +++ b/lib/pandagl/examples/cairo/src/main.c @@ -1,11 +1,14 @@ /* * lib/pandagl/examples/cairo/src/main.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * * SPDX-License-Identifier: MIT - * - * This file is part of LCUI, distributed under the MIT License found in the + + * * + * This file is part of LCUI, distributed under the MIT License found in + * the * LICENSE.TXT file in the root directory of this source tree. */ @@ -16,12 +19,12 @@ // Source code from: https://www.cairographics.org/samples/text_align_center/ -void draw_cairo_text(cairo_surface_t* surface) +void draw_cairo_text(cairo_surface_t *surface) { - cairo_t* cr; + cairo_t *cr; cairo_text_extents_t extents; - const char* utf8 = "cairo"; + const char *utf8 = "cairo"; double x, y; cr = cairo_create(surface); @@ -50,10 +53,10 @@ void draw_cairo_text(cairo_surface_t* surface) cairo_destroy(cr); } -int main(int argc, char** argv) +int main(int argc, char **argv) { pd_canvas_t canvas; - cairo_surface_t* surface; + cairo_surface_t *surface; // Create a canvas pd_canvas_init(&canvas); diff --git a/lib/pandagl/examples/char-render/src/main.c b/lib/pandagl/examples/char-render/src/main.c index 2ecc66528..cfab14933 100644 --- a/lib/pandagl/examples/char-render/src/main.c +++ b/lib/pandagl/examples/char-render/src/main.c @@ -1,11 +1,14 @@ -/* +/* * lib/pandagl/examples/char-render/src/main.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, + * Liu Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ @@ -45,4 +48,4 @@ int main(void) pd_font_library_destroy(); return ret; -} \ No newline at end of file +} diff --git a/lib/pandagl/examples/fill-rect-with-rgba/src/main.c b/lib/pandagl/examples/fill-rect-with-rgba/src/main.c index 036f0702d..771f1dc1e 100644 --- a/lib/pandagl/examples/fill-rect-with-rgba/src/main.c +++ b/lib/pandagl/examples/fill-rect-with-rgba/src/main.c @@ -1,12 +1,16 @@ -/* +/* * lib/pandagl/examples/fill-rect-with-rgba/src/main.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) + * 2023-2026, Liu Chao All rights reserved. + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, distributed + * under the MIT License found in the + * LICENSE.TXT file in the root directory + * of this source tree. */ #include @@ -43,11 +47,12 @@ int main(void) color.alpha = (unsigned char)(255 * (i + 1) / 10.0); pd_canvas_fill(&fore_canvas, color); for (j = 0; j < 4; ++j) { - pd_canvas_mix(&canvas, &fore_canvas, 5 + i * 15, 5 + j * 40, true); + pd_canvas_mix(&canvas, &fore_canvas, 5 + i * 15, + 5 + j * 40, true); } } pd_write_png_file("test_fill_rect_with_rgba.png", &canvas); pd_canvas_destroy(&fore_canvas); pd_canvas_destroy(&canvas); return 0; -} \ No newline at end of file +} diff --git a/lib/pandagl/examples/fill-rect/src/main.c b/lib/pandagl/examples/fill-rect/src/main.c index efe5ecfbf..6a43b440a 100644 --- a/lib/pandagl/examples/fill-rect/src/main.c +++ b/lib/pandagl/examples/fill-rect/src/main.c @@ -1,11 +1,14 @@ -/* +/* * lib/pandagl/examples/fill-rect/src/main.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, + * Liu Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ @@ -35,4 +38,4 @@ int main(void) pd_write_png_file("test_fill_rect.png", &canvas); pd_canvas_destroy(&canvas); return 0; -} \ No newline at end of file +} diff --git a/lib/pandagl/examples/image-scaling-bench/src/main.c b/lib/pandagl/examples/image-scaling-bench/src/main.c index a56614f7e..72cf61d0e 100644 --- a/lib/pandagl/examples/image-scaling-bench/src/main.c +++ b/lib/pandagl/examples/image-scaling-bench/src/main.c @@ -1,12 +1,16 @@ -/* +/* * lib/pandagl/examples/image-scaling-bench/src/main.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) + * 2023-2026, Liu Chao All rights reserved. + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, distributed + * under the MIT License found in the + * LICENSE.TXT file in the root directory + * of this source tree. */ #include @@ -52,4 +56,4 @@ int main(int argc, char **argv) } pd_canvas_destroy(&g_src); return 0; -} \ No newline at end of file +} diff --git a/lib/pandagl/examples/mix-rect-with-opacity/src/main.c b/lib/pandagl/examples/mix-rect-with-opacity/src/main.c index 2b65d4049..471ec5e02 100644 --- a/lib/pandagl/examples/mix-rect-with-opacity/src/main.c +++ b/lib/pandagl/examples/mix-rect-with-opacity/src/main.c @@ -1,12 +1,16 @@ -/* +/* * lib/pandagl/examples/mix-rect-with-opacity/src/main.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) + * 2023-2026, Liu Chao All rights reserved. + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, distributed + * under the MIT License found in the + * LICENSE.TXT file in the root directory + * of this source tree. */ #include @@ -39,11 +43,11 @@ int main(void) size = 2 * (10 + 10 * i); pd_canvas_create(&fore_canvas, size, size); pd_canvas_fill(&fore_canvas, pd_rgb(255, 255, 255)); - pd_canvas_mix(&canvas, &fore_canvas, 75 - size / 2, 75 - size / 2, - false); + pd_canvas_mix(&canvas, &fore_canvas, 75 - size / 2, + 75 - size / 2, false); } pd_write_png_file("test_mix_rect_with_opacity.png", &canvas); pd_canvas_destroy(&fore_canvas); pd_canvas_destroy(&canvas); return 0; -} \ No newline at end of file +} diff --git a/lib/pandagl/examples/paint-background/src/main.c b/lib/pandagl/examples/paint-background/src/main.c index 88951d1c2..ea45015c5 100644 --- a/lib/pandagl/examples/paint-background/src/main.c +++ b/lib/pandagl/examples/paint-background/src/main.c @@ -1,12 +1,16 @@ -/* +/* * lib/pandagl/examples/paint-background/src/main.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) + * 2023-2026, Liu Chao All rights reserved. + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, distributed + * under the MIT License found in the + * LICENSE.TXT file in the root directory + * of this source tree. */ #include @@ -18,7 +22,7 @@ int test_paint_background_color(void) pd_color_t green = pd_rgb(102, 204, 0); pd_rect_t rect = { 200, 100, 400, 300 }; pd_background_t bg = { 0 }; - pd_context_t* ctx; + pd_context_t *ctx; pd_canvas_init(&canvas); pd_canvas_create(&canvas, 800, 600); @@ -40,7 +44,7 @@ int test_paint_background_image(void) pd_color_t green = pd_rgb(102, 204, 0); pd_rect_t rect = { 200, 100, 400, 300 }; pd_background_t bg = { 0 }; - pd_context_t* ctx; + pd_context_t *ctx; pd_canvas_init(&canvas); pd_canvas_init(&image); @@ -70,7 +74,7 @@ int test_paint_background_image_with_size(void) pd_color_t green = pd_rgb(102, 204, 0); pd_rect_t rect = { 200, 100, 400, 300 }; pd_background_t bg = { 0 }; - pd_context_t* ctx; + pd_context_t *ctx; pd_canvas_init(&canvas); pd_canvas_init(&image); @@ -100,7 +104,7 @@ int test_paint_background_image_with_position(void) pd_color_t green = pd_rgb(102, 204, 0); pd_rect_t rect = { 200, 100, 400, 300 }; pd_background_t bg = { 0 }; - pd_context_t* ctx; + pd_context_t *ctx; pd_canvas_init(&canvas); pd_canvas_init(&image); @@ -132,4 +136,4 @@ int main(void) test_paint_background_image_with_size(); test_paint_background_image_with_position(); return 0; -} \ No newline at end of file +} diff --git a/lib/pandagl/examples/paint-border/src/main.c b/lib/pandagl/examples/paint-border/src/main.c index 8feb87674..8e93d6080 100644 --- a/lib/pandagl/examples/paint-border/src/main.c +++ b/lib/pandagl/examples/paint-border/src/main.c @@ -1,12 +1,16 @@ -/* +/* * lib/pandagl/examples/paint-border/src/main.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) + * 2023-2026, Liu Chao All rights reserved. + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, distributed + * under the MIT License found in the + * LICENSE.TXT file in the root directory + * of this source tree. */ #include diff --git a/lib/pandagl/examples/paint-boxshadow/src/main.c b/lib/pandagl/examples/paint-boxshadow/src/main.c index 148a96a50..94d78bce1 100644 --- a/lib/pandagl/examples/paint-boxshadow/src/main.c +++ b/lib/pandagl/examples/paint-boxshadow/src/main.c @@ -1,17 +1,21 @@ -/* +/* * lib/pandagl/examples/paint-boxshadow/src/main.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) + * 2023-2026, Liu Chao All rights reserved. + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, distributed + * under the MIT License found in the + * LICENSE.TXT file in the root directory + * of this source tree. */ #include -int paint_background(pd_context_t* ctx, pd_rect_t* box) +int paint_background(pd_context_t *ctx, pd_rect_t *box) { pd_canvas_t image; pd_color_t green = pd_rgb(102, 204, 0); @@ -32,7 +36,7 @@ int paint_background(pd_context_t* ctx, pd_rect_t* box) return 0; } -void paint_border(pd_context_t* ctx, pd_rect_t* box, int size, int radius) +void paint_border(pd_context_t *ctx, pd_rect_t *box, int size, int radius) { pd_border_t border = { 0 }; pd_color_t black = pd_rgb(0, 0, 0); @@ -79,7 +83,7 @@ int main(void) pd_rect_t border_box; pd_rect_t bg_box; pd_rect_t layer_rect; - pd_context_t* ctx; + pd_context_t *ctx; pd_canvas_init(&canvas); pd_canvas_create(&canvas, width, height); @@ -118,4 +122,4 @@ int main(void) pd_write_png_file("test_paint_boxshadow.png", &canvas); pd_canvas_destroy(&canvas); return 0; -} \ No newline at end of file +} diff --git a/lib/pandagl/examples/pixel-manipulation/src/main.c b/lib/pandagl/examples/pixel-manipulation/src/main.c index b4535e698..6cfefd013 100644 --- a/lib/pandagl/examples/pixel-manipulation/src/main.c +++ b/lib/pandagl/examples/pixel-manipulation/src/main.c @@ -1,12 +1,16 @@ -/* +/* * lib/pandagl/examples/pixel-manipulation/src/main.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) + * 2023-2026, Liu Chao All rights reserved. + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, distributed + * under the MIT License found in the + * LICENSE.TXT file in the root directory + * of this source tree. */ #include @@ -82,4 +86,4 @@ int main(void) invert(&graph, rects[3]); pd_write_png_file("test_pixel_manipulation.png", &graph); return 0; -} \ No newline at end of file +} diff --git a/lib/pandagl/examples/string-render/src/main.c b/lib/pandagl/examples/string-render/src/main.c index b0474aa12..5bcfc7d8d 100644 --- a/lib/pandagl/examples/string-render/src/main.c +++ b/lib/pandagl/examples/string-render/src/main.c @@ -1,12 +1,16 @@ -/* +/* * lib/pandagl/examples/string-render/src/main.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) + * 2023-2026, Liu Chao All rights reserved. + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, distributed + * under the MIT License found in the + * LICENSE.TXT file in the root directory + * of this source tree. */ #include @@ -17,7 +21,7 @@ int main(void) pd_canvas_t img; pd_pos_t pos = { 0, 80 }; pd_rect_t area = { 0, 0, 320, 240 }; - pd_text_t* txt = pd_text_create(); + pd_text_t *txt = pd_text_create(); pd_text_style_t txtstyle; pd_font_library_init(); @@ -42,4 +46,4 @@ int main(void) pd_font_library_destroy(); return ret; -} \ No newline at end of file +} diff --git a/lib/pandagl/include/pandagl.h b/lib/pandagl/include/pandagl.h index 154590213..5f5a96556 100644 --- a/lib/pandagl/include/pandagl.h +++ b/lib/pandagl/include/pandagl.h @@ -1,12 +1,15 @@ /* * lib/pandagl/include/pandagl.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "pandagl/common.h" diff --git a/lib/pandagl/include/pandagl/background.h b/lib/pandagl/include/pandagl/background.h index 6d744660c..f17d5fafc 100644 --- a/lib/pandagl/include/pandagl/background.h +++ b/lib/pandagl/include/pandagl/background.h @@ -1,12 +1,15 @@ /* - * lib/pandagl/include/pandagl/background.h: -- Background image draw support. - * - * Copyright (c) 2018-2025, Liu chao All rights reserved. + * lib/pandagl/include/pandagl/background.h: -- Background image draw + * support. + * Copyright (c) 2018-2026, Liu chao All rights + * reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #ifndef LIB_PANDAGL_INCLUDE_PANDAGL_BACKGROUND_H @@ -24,7 +27,7 @@ PD_BEGIN_DECLS * @param[in] bg 背景样式参数 */ PD_PUBLIC void pd_paint_background(pd_context_t *ctx, const pd_background_t *bg, - const pd_rect_t *box); + const pd_rect_t *box); PD_END_DECLS diff --git a/lib/pandagl/include/pandagl/border.h b/lib/pandagl/include/pandagl/border.h index ffcc5bf67..1b3c100f3 100644 --- a/lib/pandagl/include/pandagl/border.h +++ b/lib/pandagl/include/pandagl/border.h @@ -1,12 +1,15 @@ /* * lib/pandagl/include/pandagl/border.h: -- Border drawing * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #ifndef LIB_PANDAGL_INCLUDE_PANDAGL_BORDER_H @@ -18,11 +21,11 @@ PD_BEGIN_DECLS PD_PUBLIC int pd_crop_border_content(pd_context_t *ctx, - const pd_border_t *border, - const pd_rect_t *box); + const pd_border_t *border, + const pd_rect_t *box); PD_PUBLIC int pd_paint_border(pd_context_t *ctx, const pd_border_t *border, - const pd_rect_t *box); + const pd_rect_t *box); PD_END_DECLS diff --git a/lib/pandagl/include/pandagl/boxshadow.h b/lib/pandagl/include/pandagl/boxshadow.h index 9529c0ef6..495e622d9 100644 --- a/lib/pandagl/include/pandagl/boxshadow.h +++ b/lib/pandagl/include/pandagl/boxshadow.h @@ -1,12 +1,15 @@ /* * lib/pandagl/include/pandagl/boxshadow.h: -- Box shadow drawing * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #ifndef LIB_PANDAGL_INCLUDE_PANDAGL_BOXSHADOW_H @@ -18,12 +21,13 @@ PD_BEGIN_DECLS PD_PUBLIC void pd_get_boxshadow_canvas_rect(const pd_boxshadow_t *shadow, - const pd_rect_t *box_rect, - pd_rect_t *canvas_rect); + const pd_rect_t *box_rect, + pd_rect_t *canvas_rect); -PD_PUBLIC int pd_paint_boxshadow(pd_context_t *ctx, const pd_boxshadow_t *shadow, - const pd_rect_t *box, int content_width, - int content_height); +PD_PUBLIC int pd_paint_boxshadow(pd_context_t *ctx, + const pd_boxshadow_t *shadow, + const pd_rect_t *box, int content_width, + int content_height); PD_END_DECLS diff --git a/lib/pandagl/include/pandagl/canvas.h b/lib/pandagl/include/pandagl/canvas.h index 1dd13714f..738e11b20 100644 --- a/lib/pandagl/include/pandagl/canvas.h +++ b/lib/pandagl/include/pandagl/canvas.h @@ -1,11 +1,14 @@ /* * lib/pandagl/include/pandagl/canvas.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ @@ -18,51 +21,51 @@ PD_BEGIN_DECLS PD_INLINE void *pd_canvas_pixel_at(const pd_canvas_t *canvas, unsigned x, - unsigned y) + unsigned y) { - return canvas->bytes + canvas->bytes_per_row * y + - (x % canvas->width) * canvas->bytes_per_pixel; + return canvas->bytes + canvas->bytes_per_row * y + + (x % canvas->width) * canvas->bytes_per_pixel; } PD_INLINE pd_color_t pd_canvas_get_pixel(const pd_canvas_t *canvas, unsigned x, - unsigned y) + unsigned y) { - pd_color_t color; - unsigned char *p = pd_canvas_pixel_at(canvas, x, y); - - if (canvas->color_type == PD_COLOR_TYPE_ARGB) { - return *(pd_color_t *)p; - } - color.b = p[0]; - color.g = p[1]; - color.r = p[2]; - color.a = 255; - return color; + pd_color_t color; + unsigned char *p = pd_canvas_pixel_at(canvas, x, y); + + if (canvas->color_type == PD_COLOR_TYPE_ARGB) { + return *(pd_color_t *)p; + } + color.b = p[0]; + color.g = p[1]; + color.r = p[2]; + color.a = 255; + return color; } PD_INLINE void pd_canvas_set_pixel(pd_canvas_t *canvas, unsigned x, unsigned y, - pd_color_t pixel) + pd_color_t pixel) { - unsigned char *p = pd_canvas_pixel_at(canvas, x, y); - - if (canvas->color_type == PD_COLOR_TYPE_ARGB) { - *(pd_color_t *)p = pixel; - } else { - p[0] = pixel.b; - p[1] = pixel.g; - p[2] = pixel.r; - } + unsigned char *p = pd_canvas_pixel_at(canvas, x, y); + + if (canvas->color_type == PD_COLOR_TYPE_ARGB) { + *(pd_color_t *)p = pixel; + } else { + p[0] = pixel.b; + p[1] = pixel.g; + p[2] = pixel.r; + } } PD_INLINE pd_canvas_t *pd_canvas_get_quote_source(pd_canvas_t *canvas) { - return canvas->quote.is_valid ? canvas->quote.source : canvas; + return canvas->quote.is_valid ? canvas->quote.source : canvas; } PD_INLINE const pd_canvas_t *pd_canvas_get_quote_source_readonly( const pd_canvas_t *canvas) { - return canvas->quote.is_valid ? canvas->quote.source : canvas; + return canvas->quote.is_valid ? canvas->quote.source : canvas; } PD_PUBLIC void pd_canvas_init(pd_canvas_t *canvas); @@ -70,51 +73,52 @@ PD_PUBLIC void pd_canvas_init(pd_canvas_t *canvas); PD_PUBLIC bool pd_canvas_is_valid(const pd_canvas_t *canvas); PD_PUBLIC int pd_canvas_quote(pd_canvas_t *self, pd_canvas_t *source, - const pd_rect_t *rect); + const pd_rect_t *rect); PD_PUBLIC void pd_canvas_get_quote_rect(const pd_canvas_t *canvas, - pd_rect_t *rect); + pd_rect_t *rect); PD_PUBLIC void pd_canvas_destroy(pd_canvas_t *canvas); PD_PUBLIC int pd_canvas_create(pd_canvas_t *canvas, unsigned width, - unsigned height); + unsigned height); PD_PUBLIC int pd_canvas_replace(pd_canvas_t *back, const pd_canvas_t *fore, - int left, int top); + int left, int top); PD_PUBLIC int pd_canvas_set_color_type(pd_canvas_t *canvas, int color_type); PD_PUBLIC int pd_canvas_cut(const pd_canvas_t *canvas, pd_rect_t rect, - pd_canvas_t *out_canvas); + pd_canvas_t *out_canvas); PD_PUBLIC void pd_canvas_copy(pd_canvas_t *des, const pd_canvas_t *src); -PD_PUBLIC int pd_canvas_mix(pd_canvas_t *back, const pd_canvas_t *fore, int left, - int top, bool with_alpha); +PD_PUBLIC int pd_canvas_mix(pd_canvas_t *back, const pd_canvas_t *fore, + int left, int top, bool with_alpha); PD_PUBLIC int pd_canvas_fill_rect(pd_canvas_t *canvas, pd_color_t color, - pd_rect_t rect); + pd_rect_t rect); PD_INLINE int pd_canvas_fill(pd_canvas_t *canvas, pd_color_t color) { - pd_rect_t rect = { 0, 0, canvas->width, canvas->height }; - return pd_canvas_fill_rect(canvas, color, rect); + pd_rect_t rect = { 0, 0, canvas->width, canvas->height }; + return pd_canvas_fill_rect(canvas, color, rect); } PD_PUBLIC int pd_canvas_tile(pd_canvas_t *buff, const pd_canvas_t *canvas, - bool replace, bool with_alpha); + bool replace, bool with_alpha); PD_PUBLIC int pd_canvas_veri_flip(const pd_canvas_t *canvas, pd_canvas_t *buff); -PD_PUBLIC int pd_canvas_horiz_flip(const pd_canvas_t *canvas, pd_canvas_t *buff); +PD_PUBLIC int pd_canvas_horiz_flip(const pd_canvas_t *canvas, + pd_canvas_t *buff); PD_PUBLIC int pd_canvas_zoom(const pd_canvas_t *canvas, pd_canvas_t *buff, - bool keep_scale, int width, int height); + bool keep_scale, int width, int height); PD_PUBLIC int pd_canvas_zoom_bilinear(const pd_canvas_t *canvas, - pd_canvas_t *buff, bool keep_scale, - int width, int height); + pd_canvas_t *buff, bool keep_scale, + int width, int height); PD_END_DECLS diff --git a/lib/pandagl/include/pandagl/color.h b/lib/pandagl/include/pandagl/color.h index 1bb41b240..21b6fb83c 100644 --- a/lib/pandagl/include/pandagl/color.h +++ b/lib/pandagl/include/pandagl/color.h @@ -1,11 +1,14 @@ /* * lib/pandagl/include/pandagl/color.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ @@ -17,8 +20,8 @@ PD_INLINE pd_color_t pd_color(uint8_t a, uint8_t r, uint8_t g, uint8_t b) { - pd_color_t color = { .a = a, .r = r, .g = g, .b = b }; - return color; + pd_color_t color = { .a = a, .r = r, .g = g, .b = b }; + return color; } #define pd_argb pd_color diff --git a/lib/pandagl/include/pandagl/common.h b/lib/pandagl/include/pandagl/common.h index c7817819b..c528113c6 100644 --- a/lib/pandagl/include/pandagl/common.h +++ b/lib/pandagl/include/pandagl/common.h @@ -1,11 +1,14 @@ /* * lib/pandagl/include/pandagl/common.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ diff --git a/lib/pandagl/include/pandagl/context.h b/lib/pandagl/include/pandagl/context.h index 3b4347529..7e7797465 100644 --- a/lib/pandagl/include/pandagl/context.h +++ b/lib/pandagl/include/pandagl/context.h @@ -1,11 +1,14 @@ /* * lib/pandagl/include/pandagl/context.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ @@ -17,9 +20,9 @@ PD_BEGIN_DECLS -PD_PUBLIC pd_context_t* pd_context_create(pd_canvas_t *canvas, pd_rect_t *rect); +PD_PUBLIC pd_context_t *pd_context_create(pd_canvas_t *canvas, pd_rect_t *rect); -PD_PUBLIC void pd_context_destroy(pd_context_t* paint); +PD_PUBLIC void pd_context_destroy(pd_context_t *paint); PD_END_DECLS diff --git a/lib/pandagl/include/pandagl/file_reader.h b/lib/pandagl/include/pandagl/file_reader.h index 66e496be2..69fa1061e 100644 --- a/lib/pandagl/include/pandagl/file_reader.h +++ b/lib/pandagl/include/pandagl/file_reader.h @@ -1,11 +1,14 @@ /* * lib/pandagl/include/pandagl/file_reader.h * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, + * Liu Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ @@ -19,14 +22,14 @@ PD_BEGIN_DECLS typedef struct pd_file_reader { void *stream_data; - void (*fn_close)(void*); - void (*fn_rewind)(void*); + void (*fn_close)(void *); + void (*fn_rewind)(void *); size_t (*fn_read)(void *, void *, size_t); void (*fn_skip)(void *, long); } pd_file_reader_t; PD_INLINE size_t pd_file_reader_read(pd_file_reader_t *reader, void *buffer, - size_t size) + size_t size) { return reader->fn_read(reader->stream_data, buffer, size); } @@ -42,7 +45,8 @@ PD_INLINE void pd_file_reader_skip(pd_file_reader_t *reader, long bytes) } PD_PUBLIC pd_file_reader_t *pd_file_reader_create(void); -PD_PUBLIC pd_file_reader_t *pd_file_reader_create_from_file(const char *filename); +PD_PUBLIC pd_file_reader_t *pd_file_reader_create_from_file( + const char *filename); PD_PUBLIC void pd_file_reader_destroy(pd_file_reader_t *reader); PD_END_DECLS diff --git a/lib/pandagl/include/pandagl/font.h b/lib/pandagl/include/pandagl/font.h index 442cc9a04..9f894c835 100644 --- a/lib/pandagl/include/pandagl/font.h +++ b/lib/pandagl/include/pandagl/font.h @@ -1,12 +1,15 @@ /* * lib/pandagl/include/pandagl/font.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_PANDAGL_INCLUDE_FONT_H @@ -52,13 +55,13 @@ typedef struct pd_glyph_bitmap { typedef struct pd_font_engine pd_font_engine_t; typedef struct pd_font_face { - int id; /**< 字体信息ID */ - char *style_name; /**< 样式名称 */ - char *family_name; /**< 字族名称 */ - void *data; /**< 相关数据 */ - pd_font_style_t style; /**< 风格 */ - pd_font_weight_t weight; /**< 粗细程度 */ - pd_font_engine_t *engine; /**< 所属的字体引擎 */ + int id; /**< 字体信息ID */ + char *style_name; /**< 样式名称 */ + char *family_name; /**< 字族名称 */ + void *data; /**< 相关数据 */ + pd_font_style_t style; /**< 风格 */ + pd_font_weight_t weight; /**< 粗细程度 */ + pd_font_engine_t *engine; /**< 所属的字体引擎 */ } pd_font_face_t; struct pd_font_engine { @@ -73,8 +76,8 @@ PD_BEGIN_DECLS /** 将字体位图绘制到目标图像上 */ PD_PUBLIC int pd_canvas_mix_glyph_bitmap(pd_canvas_t *graph, pd_pos_t pos, - const pd_glyph_bitmap_t *bmp, - pd_color_t color); + const pd_glyph_bitmap_t *bmp, + pd_color_t color); PD_PUBLIC char *pd_font_find_path(const char *name); @@ -92,7 +95,7 @@ PD_PUBLIC pd_font_style_t pd_font_parse_style(const char *str); /** 载入字体位图 */ PD_PUBLIC int pd_font_render_glyph(pd_glyph_bitmap_t *buff, unsigned ch, - int font_id, int pixel_size); + int font_id, int pixel_size); /** 添加字体族,并返回该字族的ID */ PD_PUBLIC int pd_font_register(pd_font_face_t *font); @@ -103,9 +106,8 @@ PD_PUBLIC int pd_font_register(pd_font_face_t *font); * @param[in] style 字体风格 * @param[in] weight 字体粗细程度,若为值 0,则默认为 PD_FONT_WEIGHT_NORMAL */ -PD_PUBLIC int pd_font_get_id(const char *family_name, - pd_font_style_t style, - pd_font_weight_t weight); +PD_PUBLIC int pd_font_get_id(const char *family_name, pd_font_style_t style, + pd_font_weight_t weight); /** * 更新当前字体的粗细程度 @@ -114,8 +116,8 @@ PD_PUBLIC int pd_font_get_id(const char *family_name, * @params[out] new_font_ids 更新字体粗细程度后的字体 id 列表 */ PD_PUBLIC size_t pd_font_replace_weight(const int *font_ids, - pd_font_weight_t weight, - int **new_font_ids); + pd_font_weight_t weight, + int **new_font_ids); /** * 更新当前字体的风格 @@ -124,8 +126,8 @@ PD_PUBLIC size_t pd_font_replace_weight(const int *font_ids, * @params[out] new_font_ids 更新字体粗细程度后的字体 id 列表 */ PD_PUBLIC size_t pd_font_replace_style(const int *font_ids, - pd_font_style_t style, - int **new_font_ids); + pd_font_style_t style, + int **new_font_ids); /** * 根据字族名称获取对应的字体 ID 列表 @@ -136,8 +138,8 @@ PD_PUBLIC size_t pd_font_replace_style(const int *font_ids, * @return 获取到的字体 ID 的数量 */ PD_PUBLIC unsigned pd_font_query(int **font_ids, pd_font_style_t style, - pd_font_weight_t weight, - const char *const *names); + pd_font_weight_t weight, + const char *const *names); /** 获取指定字体ID的字体信息 */ PD_PUBLIC pd_font_face_t *pd_font_get(int id); @@ -150,7 +152,7 @@ PD_PUBLIC void pd_font_set_default(int id); /** 设置字体族的别名 */ PD_PUBLIC bool pd_font_family_set_alias(const char *alias, - const char *family_name); + const char *family_name); /** * 向字体缓存中添加字体位图 @@ -174,7 +176,7 @@ PD_PUBLIC pd_glyph_bitmap_t *pd_font_cache_add_bitmap( * 空间存储字体位图的拷贝。 */ PD_PUBLIC int pd_font_cache_get_bitmap(unsigned ch, int font_id, int size, - const pd_glyph_bitmap_t **bmp); + const pd_glyph_bitmap_t **bmp); /** * 设置字形位图缓存上限(按 entry 数)。0 表示不限制。 diff --git a/lib/pandagl/include/pandagl/image.h b/lib/pandagl/include/pandagl/image.h index 141b9d83a..1b520cd95 100644 --- a/lib/pandagl/include/pandagl/image.h +++ b/lib/pandagl/include/pandagl/image.h @@ -1,12 +1,15 @@ /* - * lib/pandagl/include/pandagl/image.h: -- Image read and write operations set - * - * Copyright (c) 2018-2025, Liu chao All rights reserved. + * lib/pandagl/include/pandagl/image.h: -- Image read and write operations + * set + * Copyright (c) 2018-2026, Liu chao All rights + * reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #ifndef LIB_PANDAGL_INCLUDE_PANDAGL_IMAGE_H diff --git a/lib/pandagl/include/pandagl/line.h b/lib/pandagl/include/pandagl/line.h index a0d6cc0ef..43de79b86 100644 --- a/lib/pandagl/include/pandagl/line.h +++ b/lib/pandagl/include/pandagl/line.h @@ -1,12 +1,15 @@ /* * lib/pandagl/include/pandagl/line.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_PANDAGL_INCLUDE_PANDAGL_LINE_H @@ -18,23 +21,23 @@ PD_BEGIN_DECLS PD_PUBLIC void pd_canvas_draw_horizontal_line(pd_canvas_t *canvas, - pd_color_t color, int size, - pd_pos_t start, int end_x); + pd_color_t color, int size, + pd_pos_t start, int end_x); PD_PUBLIC void pd_canvas_draw_vertical_line(pd_canvas_t *canvas, - pd_color_t color, int size, - pd_pos_t start, int end_y); + pd_color_t color, int size, + pd_pos_t start, int end_y); PD_INLINE void pd_canvas_draw_hline(pd_canvas_t *canvas, pd_color_t color, - int size, pd_pos_t start, int end_x) + int size, pd_pos_t start, int end_x) { - pd_canvas_draw_horizontal_line(canvas, color, size, start, end_x); + pd_canvas_draw_horizontal_line(canvas, color, size, start, end_x); } -PD_INLINE void pd_canvas_draw_vline(pd_canvas_t *canvas, pd_color_t color, int size, - pd_pos_t start, int end_y) +PD_INLINE void pd_canvas_draw_vline(pd_canvas_t *canvas, pd_color_t color, + int size, pd_pos_t start, int end_y) { - pd_canvas_draw_vertical_line(canvas, color, size, start, end_y); + pd_canvas_draw_vertical_line(canvas, color, size, start, end_y); } PD_END_DECLS diff --git a/lib/pandagl/include/pandagl/pixel.h b/lib/pandagl/include/pandagl/pixel.h index 2c4cd8a5c..5e96c53af 100644 --- a/lib/pandagl/include/pandagl/pixel.h +++ b/lib/pandagl/include/pandagl/pixel.h @@ -1,11 +1,14 @@ /* * lib/pandagl/include/pandagl/pixel.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ @@ -16,78 +19,79 @@ #include "types.h" #define _pd_alpha_blend(__back__, __fore__, __alpha__) \ - ((((__fore__ - __back__) * (__alpha__)) >> 8) + __back__) + ((((__fore__ - __back__) * (__alpha__)) >> 8) + __back__) #define pd_alpha_blend(__back__, __fore__, __alpha__) \ - { \ - __back__ = _pd_alpha_blend(__back__, __fore__, __alpha__); \ - } + { \ + __back__ = _pd_alpha_blend(__back__, __fore__, __alpha__); \ + } #define pd_blend_pixel(px1, px2, a) \ - { \ - pd_alpha_blend((px1)->r, (px2)->r, a); \ - pd_alpha_blend((px1)->g, (px2)->g, a); \ - pd_alpha_blend((px1)->b, (px2)->b, a); \ - } + { \ + pd_alpha_blend((px1)->r, (px2)->r, a); \ + pd_alpha_blend((px1)->g, (px2)->g, a); \ + pd_alpha_blend((px1)->b, (px2)->b, a); \ + } PD_BEGIN_DECLS PD_PUBLIC unsigned pd_get_pixel_size(pd_color_type_t color_type); -PD_PUBLIC unsigned pd_get_pixel_row_size(pd_color_type_t color_type, size_t len); +PD_PUBLIC unsigned pd_get_pixel_row_size(pd_color_type_t color_type, + size_t len); PD_PUBLIC int pd_format_pixels(const uint8_t *in_pixels, - pd_color_type_t in_color_type, - uint8_t *out_pixels, - pd_color_type_t out_color_type, - size_t count); + pd_color_type_t in_color_type, + uint8_t *out_pixels, + pd_color_type_t out_color_type, size_t count); /* * Pixel over operator with alpha channel * See more: https://en.wikipedia.org/wiki/Alpha_compositing */ -PD_INLINE void pd_over_pixel(pd_color_t *dst, const pd_color_t *src, double opacity) +PD_INLINE void pd_over_pixel(pd_color_t *dst, const pd_color_t *src, + double opacity) { - /* - * Original formula: - * Co = (Ca * aa + Cb * ab * (1 - aa)) / (aa + ab * (1 - aa)) - * ao = aa + ab * (1 - aa) - * - * Variable full name: - * Co => colorOut - * Ca => colorA - * Cb => colorB - * aa => colorA.alpha - * ab => colorB.alpha - * ao => colorOut.alpha - * - * The formula used in the code: - * ai = ab * (1 - aa) - * Co = (Ca * aa + Cb * ai) / (aa + ai) - * ao = aa + ai - */ - double src_a = src->a * opacity / 255.0; - double a = (1.0 - src_a) * dst->a / 255.0; - double out_a = src_a + a; + /* + * Original formula: + * Co = (Ca * aa + Cb * ab * (1 - aa)) / (aa + ab * (1 - aa)) + * ao = aa + ab * (1 - aa) + * + * Variable full name: + * Co => colorOut + * Ca => colorA + * Cb => colorB + * aa => colorA.alpha + * ab => colorB.alpha + * ao => colorOut.alpha + * + * The formula used in the code: + * ai = ab * (1 - aa) + * Co = (Ca * aa + Cb * ai) / (aa + ai) + * ao = aa + ai + */ + double src_a = src->a * opacity / 255.0; + double a = (1.0 - src_a) * dst->a / 255.0; + double out_a = src_a + a; - if (out_a > 0) { - src_a /= out_a; - a /= out_a; - } - dst->r = (unsigned char)(src->r * src_a + dst->r * a); - dst->g = (unsigned char)(src->g * src_a + dst->g * a); - dst->b = (unsigned char)(src->b * src_a + dst->b * a); - dst->a = (unsigned char)(255.0 * out_a); + if (out_a > 0) { + src_a /= out_a; + a /= out_a; + } + dst->r = (unsigned char)(src->r * src_a + dst->r * a); + dst->g = (unsigned char)(src->g * src_a + dst->g * a); + dst->b = (unsigned char)(src->b * src_a + dst->b * a); + dst->a = (unsigned char)(255.0 * out_a); - /* If it is assumed that all color values are premultiplied by their - * alpha values, we can rewrite the equation for output color as: + /* If it is assumed that all color values are premultiplied by their + * alpha values, we can rewrite the equation for output color as: - const double a = 1.0 - src->a / 255.0; - dst->r = src->r + (unsigned char)(dst->r * a); - dst->g = src->g + (unsigned char)(dst->g * a); - dst->b = src->b + (unsigned char)(dst->b * a); - dst->a = src->a + (unsigned char)(dst->a * a); - */ + const double a = 1.0 - src->a / 255.0; + dst->r = src->r + (unsigned char)(dst->r * a); + dst->g = src->g + (unsigned char)(dst->g * a); + dst->b = src->b + (unsigned char)(dst->b * a); + dst->a = src->a + (unsigned char)(dst->a * a); + */ } PD_END_DECLS diff --git a/lib/pandagl/include/pandagl/rect.h b/lib/pandagl/include/pandagl/rect.h index 272b21390..19e60ba02 100644 --- a/lib/pandagl/include/pandagl/rect.h +++ b/lib/pandagl/include/pandagl/rect.h @@ -1,12 +1,15 @@ /* * lib/pandagl/include/pandagl/rect.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_PANDAGL_INCLUDE_PANDAGL_RECT_H @@ -26,17 +29,17 @@ PD_INLINE pd_rect_t pd_rect(int x, int y, int width, int height) PD_INLINE bool pd_rect_is_include(pd_rect_t *a, pd_rect_t *b) { - return (b->x >= a->x && b->x + b->width <= a->x + a->width && - b->y >= a->y && b->y + b->height <= a->y + a->height); + return (b->x >= a->x && b->x + b->width <= a->x + a->width && + b->y >= a->y && b->y + b->height <= a->y + a->height); } /** 根据容器尺寸,获取指定区域中需要裁剪的区域 */ PD_PUBLIC pd_rect_t pd_rect_crop(const pd_rect_t *rect, int container_width, - int container_height); + int container_height); /** 将矩形区域纠正在容器有效区域内 */ PD_PUBLIC bool pd_rect_correct(pd_rect_t *rect, int container_width, - int container_height); + int container_height); /** 检测矩形是否遮盖另一个矩形 */ PD_PUBLIC bool pd_rect_is_cover(const pd_rect_t *a, const pd_rect_t *b); @@ -49,15 +52,15 @@ PD_PUBLIC bool pd_rect_is_cover(const pd_rect_t *a, const pd_rect_t *b); * @returns 如果两个矩形重叠,则返回true,否则返回false */ PD_PUBLIC bool pd_rect_overlap(const pd_rect_t *a, const pd_rect_t *b, - pd_rect_t *overlapping_rect); + pd_rect_t *overlapping_rect); PD_PUBLIC void pd_rect_split(pd_rect_t *base, pd_rect_t *target, - pd_rect_t rects[4]); + pd_rect_t rects[4]); PD_INLINE bool pd_rect_is_equal(const pd_rect_t *a, const pd_rect_t *b) { - return a->x == b->x && a->y == b->y && a->width == b->width && - a->height == b->height; + return a->x == b->x && a->y == b->y && a->width == b->width && + a->height == b->height; } /** 添加一个脏矩形记录 */ diff --git a/lib/pandagl/include/pandagl/text.h b/lib/pandagl/include/pandagl/text.h index 3176fe072..4f692fd42 100644 --- a/lib/pandagl/include/pandagl/text.h +++ b/lib/pandagl/include/pandagl/text.h @@ -1,12 +1,15 @@ /* * lib/pandagl/include/pandagl/text.h: -- Text layout and rendering module. * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #ifndef LIB_PANDAGL_INCLUDE_PANDAGL_TEXT_H @@ -20,57 +23,57 @@ PD_BEGIN_DECLS typedef struct pd_text_style { - bool has_family : 1; - bool has_style : 1; - bool has_weight : 1; - bool has_back_color : 1; - bool has_fore_color : 1; - bool has_pixel_size : 1; + bool has_family : 1; + bool has_style : 1; + bool has_weight : 1; + bool has_back_color : 1; + bool has_fore_color : 1; + bool has_pixel_size : 1; - int style; - int weight; - int *font_ids; + int style; + int weight; + int *font_ids; - pd_color_t fore_color; - pd_color_t back_color; + pd_color_t fore_color; + pd_color_t back_color; - int pixel_size; + int pixel_size; } pd_text_style_t; typedef enum pd_text_align_t { - PD_TEXT_ALIGN_LEFT, - PD_TEXT_ALIGN_RIGHT, - PD_TEXT_ALIGN_CENTER + PD_TEXT_ALIGN_LEFT, + PD_TEXT_ALIGN_RIGHT, + PD_TEXT_ALIGN_CENTER } pd_text_align_t; typedef struct pd_char { - wchar_t code; /**< 字符码 */ - pd_text_style_t *style; /**< 该字符使用的样式数据 */ - const pd_glyph_bitmap_t *bitmap; /**< 字体位图数据(只读) */ + wchar_t code; /**< 字符码 */ + pd_text_style_t *style; /**< 该字符使用的样式数据 */ + const pd_glyph_bitmap_t *bitmap; /**< 字体位图数据(只读) */ } pd_char_t; /** end of line character */ typedef enum pd_text_eol_t { - /** 无换行 */ - PD_TEXT_EOL_NONE, + /** 无换行 */ + PD_TEXT_EOL_NONE, - /** mac os 格式换行,cf = carriage-return,字符:\r */ - PD_TEXT_EOL_CR, + /** mac os 格式换行,cf = carriage-return,字符:\r */ + PD_TEXT_EOL_CR, - /** unix/linux 格式换行,lf = line-feed,字符:\r */ - PD_TEXT_EOL_LF, + /** unix/linux 格式换行,lf = line-feed,字符:\r */ + PD_TEXT_EOL_LF, - /** windows 格式换行: \r\n */ - PD_TEXT_EOL_CR_LF + /** windows 格式换行: \r\n */ + PD_TEXT_EOL_CR_LF } pd_text_eol_t; /* 文本行 */ typedef struct pd_text_line { - int width; /**< 宽度 */ - int height; /**< 高度 */ - int length; /**< 该行文本长度 */ - pd_char_t **string; /**< 该行文本的数据 */ - pd_text_eol_t eol; /**< 行尾结束类型 */ + int width; /**< 宽度 */ + int height; /**< 高度 */ + int length; /**< 该行文本长度 */ + pd_char_t **string; /**< 该行文本的数据 */ + pd_text_eol_t eol; /**< 行尾结束类型 */ } pd_text_line_t; /** @@ -80,53 +83,53 @@ typedef struct pd_text_line { * content box. */ typedef enum pd_word_break_t { - PD_WORD_BREAK_NORMAL, - PD_WORD_BREAK_BREAK_ALL + PD_WORD_BREAK_NORMAL, + PD_WORD_BREAK_BREAK_ALL } pd_word_break_t; typedef struct pd_text_caret { - int x; /**< 光标所在列数 */ - int y; /**< 光标所在行数 */ + int x; /**< 光标所在列数 */ + int y; /**< 光标所在行数 */ } pd_text_caret_t; typedef struct pd_text { - int offset_x; /**< x轴坐标偏移量 */ - int offset_y; /**< y轴坐标偏移量 */ - int new_offset_x; /**< 新的x轴坐标偏移量 */ - int new_offset_y; /**< 新的y轴坐标偏移量 */ - pd_text_caret_t caret; /**< 光标位置 */ - int width; /**< 实际文本宽度 */ - - /** - * 固定宽高 - * 当它们等于0时,文本宽高会根据文本内容自动适应 - * 当它们大于0时,会直接根据该值处理文本对齐 - */ - int fixed_width, fixed_height; - /** - * 最大文本宽高 - * 当未设置固定宽度时,文字排版将按最大宽度进行 - */ - int max_width, max_height; - - int length; - int line_height; - pd_text_align_t text_align; - pd_word_break_t word_break; - bool multiline_enabled; - bool autowrap_enabled; - bool style_tag_enabled; - list_t dirty_rects; - list_t styles; - pd_text_style_t default_style; - pd_text_line_t **lines; - int lines_length; - struct { - bool update_bitmap; - bool update_typeset; - int typeset_start_line; - bool redraw_all; - } task; + int offset_x; /**< x轴坐标偏移量 */ + int offset_y; /**< y轴坐标偏移量 */ + int new_offset_x; /**< 新的x轴坐标偏移量 */ + int new_offset_y; /**< 新的y轴坐标偏移量 */ + pd_text_caret_t caret; /**< 光标位置 */ + int width; /**< 实际文本宽度 */ + + /** + * 固定宽高 + * 当它们等于0时,文本宽高会根据文本内容自动适应 + * 当它们大于0时,会直接根据该值处理文本对齐 + */ + int fixed_width, fixed_height; + /** + * 最大文本宽高 + * 当未设置固定宽度时,文字排版将按最大宽度进行 + */ + int max_width, max_height; + + int length; + int line_height; + pd_text_align_t text_align; + pd_word_break_t word_break; + bool multiline_enabled; + bool autowrap_enabled; + bool style_tag_enabled; + list_t dirty_rects; + list_t styles; + pd_text_style_t default_style; + pd_text_line_t **lines; + int lines_length; + struct { + bool update_bitmap; + bool update_typeset; + int typeset_start_line; + bool redraw_all; + } task; } pd_text_t; /** 获取文本行总数 */ @@ -145,8 +148,7 @@ PD_PUBLIC void pd_text_request_typeset(pd_text_t *layer, int start_row); PD_PUBLIC void pd_text_set_align(pd_text_t *layer, int align); /** 设置坐标偏移量 */ -PD_PUBLIC bool pd_text_set_offset(pd_text_t *layer, int offset_x, - int offset_y); +PD_PUBLIC bool pd_text_set_offset(pd_text_t *layer, int offset_x, int offset_y); PD_PUBLIC pd_text_t *pd_text_create(void); @@ -156,35 +158,33 @@ PD_PUBLIC void pd_text_destroy(pd_text_t *layer); PD_PUBLIC void pd_text_mark_dirty(pd_text_t *layer, int start_row, int end_row); /** 设置插入点的行列坐标 */ -PD_PUBLIC void pd_text_set_caret(pd_text_t *layer, int line_num, - int col); +PD_PUBLIC void pd_text_set_caret(pd_text_t *layer, int line_num, int col); /** 根据像素坐标设置文本光标的行列坐标 */ PD_PUBLIC int pd_text_set_caret_pixel(pd_text_t *layer, int x, int y); /** 获取指定行列的文字的像素坐标 */ -PD_PUBLIC int pd_text_get_char_pixel(pd_text_t *layer, int line_num, - int col, pd_pos_t *pixel_pos); +PD_PUBLIC int pd_text_get_char_pixel(pd_text_t *layer, int line_num, int col, + pd_pos_t *pixel_pos); /** 获取文本光标的像素坐标 */ -PD_PUBLIC int pd_text_get_caret_pixel(pd_text_t *layer, - pd_pos_t *pixel_pos); +PD_PUBLIC int pd_text_get_caret_pixel(pd_text_t *layer, pd_pos_t *pixel_pos); /** 清空文本 */ PD_PUBLIC void pd_text_clear(pd_text_t *layer); PD_PUBLIC int pd_text_insert(pd_text_t *layer, const wchar_t *wstr, - list_t *tag_stack); + list_t *tag_stack); PD_PUBLIC int pd_text_append(pd_text_t *layer, const wchar_t *wstr, - list_t *tag_stack); + list_t *tag_stack); PD_PUBLIC int pd_text_write(pd_text_t *layer, const wchar_t *wstr, - list_t *tag_stack); + list_t *tag_stack); /** 获取文本图层中的文本(宽字符版) */ PD_PUBLIC size_t pd_text_read(pd_text_t *text, size_t start_pos, size_t max_len, - wchar_t *wstr_buff); + wchar_t *wstr_buff); /** * 取得文本图层完整内容(含按 line.eol 还原的换行符) @@ -236,7 +236,7 @@ PD_PUBLIC void pd_text_update(pd_text_t *layer, list_t *rects); * @param cavans 目标画布 */ PD_PUBLIC int pd_text_render_to(pd_text_t *layer, pd_rect_t area, - pd_pos_t layer_pos, pd_canvas_t *canvas); + pd_pos_t layer_pos, pd_canvas_t *canvas); /** 设置全局文本样式 */ PD_PUBLIC void pd_text_set_style(pd_text_t *layer, pd_text_style_t *style); @@ -248,21 +248,21 @@ PD_PUBLIC void pd_text_set_line_height(pd_text_t *layer, int height); PD_PUBLIC void pd_text_style_init(pd_text_style_t *data); PD_PUBLIC int pd_text_style_copy_family(pd_text_style_t *dst, - pd_text_style_t *src); + pd_text_style_t *src); PD_PUBLIC int pd_text_style_copy(pd_text_style_t *dst, pd_text_style_t *src); PD_PUBLIC void pd_text_style_destroy(pd_text_style_t *data); PD_PUBLIC void pd_text_style_merge(pd_text_style_t *base, - pd_text_style_t *target); + pd_text_style_t *target); /* 设置字体粗细程度 */ PD_PUBLIC int pd_text_style_set_weight(pd_text_style_t *ts, - pd_font_weight_t weight); + pd_font_weight_t weight); PD_PUBLIC int pd_text_style_set_style(pd_text_style_t *ts, - pd_font_style_t style); + pd_font_style_t style); /** * 设置字体 @@ -270,27 +270,27 @@ PD_PUBLIC int pd_text_style_set_style(pd_text_style_t *ts, * @param[in] str 字体名称,如果有多个名称则用逗号分隔 */ PD_PUBLIC int pd_text_style_set_font(pd_text_style_t *ts, - const char *const *names); + const char *const *names); PD_PUBLIC void pd_text_style_set_size(pd_text_style_t *ts, int pixel_size); PD_PUBLIC void pd_text_style_set_fore_color(pd_text_style_t *ts, - pd_color_t color); + pd_color_t color); PD_PUBLIC void pd_text_style_set_back_color(pd_text_style_t *ts, - pd_color_t color); + pd_color_t color); /** 设置使用默认的字体 */ PD_PUBLIC int pd_text_style_set_default_font(pd_text_style_t *ts); /** 从字符串中获取样式标签的名字及样式属性 */ PD_PUBLIC const wchar_t *pd_scan_style_open_tag(const wchar_t *wstr, - wchar_t *name, int max_name_len, - wchar_t *data); + wchar_t *name, int max_name_len, + wchar_t *data); /** 在字符串中获取样式的结束标签,输出的是标签名 */ PD_PUBLIC const wchar_t *pd_scan_style_close_tag(const wchar_t *wstr, - wchar_t *name); + wchar_t *name); PD_PUBLIC void pd_style_tags_clear(list_t *tags); @@ -298,11 +298,11 @@ PD_PUBLIC pd_text_style_t *pd_style_tags_get_text_style(list_t *tags); /** 处理样式标签 */ PD_PUBLIC const wchar_t *pd_style_tags_next_open_tag(list_t *tags, - const wchar_t *str); + const wchar_t *str); /** 处理样式结束标签 */ PD_PUBLIC const wchar_t *pd_style_tags_next_close_tag(list_t *tags, - const wchar_t *str); + const wchar_t *str); PD_END_DECLS diff --git a/lib/pandagl/include/pandagl/types.h b/lib/pandagl/include/pandagl/types.h index 445a86caa..6b3dd3d8b 100644 --- a/lib/pandagl/include/pandagl/types.h +++ b/lib/pandagl/include/pandagl/types.h @@ -1,11 +1,14 @@ /* * lib/pandagl/include/pandagl/types.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ @@ -17,120 +20,120 @@ #include typedef enum pd_color_type_t { - PD_COLOR_TYPE_UNSUPPORTED, - PD_COLOR_TYPE_INDEX8, /**< 8位索引 */ - PD_COLOR_TYPE_GRAY8, /**< 8位灰度 */ - PD_COLOR_TYPE_RGB323, /**< RGB323 */ - PD_COLOR_TYPE_ARGB2222, /**< ARGB2222 */ - PD_COLOR_TYPE_RGB555, /**< RGB555 */ - PD_COLOR_TYPE_RGB565, /**< RGB565 */ - PD_COLOR_TYPE_RGB888, /**< RGB888 */ - PD_COLOR_TYPE_ARGB8888, /**< RGB8888 */ + PD_COLOR_TYPE_UNSUPPORTED, + PD_COLOR_TYPE_INDEX8, /**< 8位索引 */ + PD_COLOR_TYPE_GRAY8, /**< 8位灰度 */ + PD_COLOR_TYPE_RGB323, /**< RGB323 */ + PD_COLOR_TYPE_ARGB2222, /**< ARGB2222 */ + PD_COLOR_TYPE_RGB555, /**< RGB555 */ + PD_COLOR_TYPE_RGB565, /**< RGB565 */ + PD_COLOR_TYPE_RGB888, /**< RGB888 */ + PD_COLOR_TYPE_ARGB8888, /**< RGB8888 */ } pd_color_type_t; #define PD_COLOR_TYPE_RGB PD_COLOR_TYPE_RGB888 #define PD_COLOR_TYPE_ARGB PD_COLOR_TYPE_ARGB8888 typedef union pd_color_t { - uint32_t value; - struct { - uint8_t b; - uint8_t g; - uint8_t r; - uint8_t a; - }; - struct { - uint8_t blue; - uint8_t green; - uint8_t red; - uint8_t alpha; - }; + uint32_t value; + struct { + uint8_t b; + uint8_t g; + uint8_t r; + uint8_t a; + }; + struct { + uint8_t blue; + uint8_t green; + uint8_t red; + uint8_t alpha; + }; } pd_color_t; /** Position in plane coordinate system */ typedef struct pd_pos { - int x, y; + int x, y; } pd_pos_t; typedef struct pd_rect { - int x, y, width, height; + int x, y, width, height; } pd_rect_t; typedef struct pd_canvas pd_canvas_t; typedef struct pd_canvas_quote { - int top; - int left; - bool is_valid; - pd_canvas_t *source; + int top; + int left; + bool is_valid; + pd_canvas_t *source; } pd_canvas_quote_t; struct pd_canvas { - unsigned width; - unsigned height; - float opacity; - pd_canvas_quote_t quote; - union { - uint8_t *bytes; - pd_color_t *argb; - }; - pd_color_type_t color_type; - unsigned bytes_per_pixel; - unsigned bytes_per_row; - size_t mem_size; + unsigned width; + unsigned height; + float opacity; + pd_canvas_quote_t quote; + union { + uint8_t *bytes; + pd_color_t *argb; + }; + pd_color_type_t color_type; + unsigned bytes_per_pixel; + unsigned bytes_per_row; + size_t mem_size; }; /** 进行绘制时所需的上下文 */ typedef struct pd_context { - pd_rect_t rect; /**< 需要绘制的区域 */ - pd_canvas_t canvas; /**< 绘制后的位图缓存(可称为:画布) */ - bool with_alpha; /**< 绘制时是否需要处理 alpha 通道 */ + pd_rect_t rect; /**< 需要绘制的区域 */ + pd_canvas_t canvas; /**< 绘制后的位图缓存(可称为:画布) */ + bool with_alpha; /**< 绘制时是否需要处理 alpha 通道 */ } pd_context_t; typedef struct pd_background { - pd_canvas_t *image; - pd_color_t color; - bool repeat_x; - bool repeat_y; - int x; - int y; - int width; - int height; + pd_canvas_t *image; + pd_color_t color; + bool repeat_x; + bool repeat_y; + int x; + int y; + int width; + int height; } pd_background_t; typedef struct pd_boxshadow { - int x, y; - int blur; - int spread; - pd_color_t color; - int top_left_radius; - int top_right_radius; - int bottom_left_radius; - int bottom_right_radius; + int x, y; + int blur; + int spread; + pd_color_t color; + int top_left_radius; + int top_right_radius; + int bottom_left_radius; + int bottom_right_radius; } pd_boxshadow_t; typedef struct pd_border_line { - int style; - unsigned int width; - pd_color_t color; + int style; + unsigned int width; + pd_color_t color; } pd_border_line_t; typedef struct pd_border { - pd_border_line_t top, right, bottom, left; - unsigned int top_left_radius; - unsigned int top_right_radius; - unsigned int bottom_left_radius; - unsigned int bottom_right_radius; + pd_border_line_t top, right, bottom, left; + unsigned int top_left_radius; + unsigned int top_right_radius; + unsigned int bottom_left_radius; + unsigned int bottom_right_radius; } pd_border_t; typedef enum pd_error_t { - PD_OK = 0, - PD_ERROR_NOT_FOUND, - PD_ERROR_NOT_IMPLEMENTED, - PD_ERROR_IMAGE_HEADER_INVALID, - PD_ERROR_IMAGE_TYPE_INCORRECT, - PD_ERROR_IMAGE_DATA_NOT_SUPPORTED, - PD_ERROR_IMAGE_READING + PD_OK = 0, + PD_ERROR_NOT_FOUND, + PD_ERROR_NOT_IMPLEMENTED, + PD_ERROR_IMAGE_HEADER_INVALID, + PD_ERROR_IMAGE_TYPE_INCORRECT, + PD_ERROR_IMAGE_DATA_NOT_SUPPORTED, + PD_ERROR_IMAGE_READING } pd_error_t; #endif diff --git a/lib/pandagl/src/background.c b/lib/pandagl/src/background.c index 738954fe4..1a1827646 100644 --- a/lib/pandagl/src/background.c +++ b/lib/pandagl/src/background.c @@ -1,12 +1,15 @@ /* * lib/pandagl/src/background.c: -- canvas background image draw support. * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include diff --git a/lib/pandagl/src/border.c b/lib/pandagl/src/border.c index fb5d07ea0..1d6b28141 100644 --- a/lib/pandagl/src/border.c +++ b/lib/pandagl/src/border.c @@ -1,12 +1,15 @@ /* * lib/pandagl/src/border.c: -- Border drawing * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include diff --git a/lib/pandagl/src/boxshadow.c b/lib/pandagl/src/boxshadow.c index 26c11fa82..cdbe29db2 100644 --- a/lib/pandagl/src/boxshadow.c +++ b/lib/pandagl/src/boxshadow.c @@ -1,12 +1,15 @@ /* * lib/pandagl/src/boxshadow.c: -- Box shadow drawing * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ /** @@ -21,8 +24,8 @@ #define BLUR_N 1.5 #define BLUR_WIDTH(sd) (int)(sd->blur * BLUR_N) #define FULL_SHADOW_WIDTH(CTX) \ - SHADOW_WIDTH((CTX)->shadow) + BLUR_WIDTH((CTX)->shadow) - \ - (CTX)->shadow->blur + SHADOW_WIDTH((CTX)->shadow) + BLUR_WIDTH((CTX)->shadow) - \ + (CTX)->shadow->blur #define SHADOW_WIDTH(sd) (sd->blur + sd->spread) @@ -30,7 +33,7 @@ #define CIRCLE_R(R) (R - 0.5) /* Convert screen Y coordinate to geometric Y coordinate */ -#define ToGeoY(Y, CENTER_Y) ((CENTER_Y)-Y) +#define ToGeoY(Y, CENTER_Y) ((CENTER_Y) - Y) /* Convert screen X coordinate to geometric X coordinate */ #define ToGeoX(X, CENTER_X) (X - (CENTER_X)) @@ -39,598 +42,599 @@ #define smooth_right_pixel(PX, X) (uint8_t)((PX)->a * (X - 1.0 * (int)X)) typedef struct pd_boxshadow_context { - int max_radius; - const pd_boxshadow_t *shadow; - const pd_rect_t *box; - pd_rect_t shadow_box; - pd_rect_t content_box; - pd_context_t *paint; + int max_radius; + const pd_boxshadow_t *shadow; + const pd_rect_t *box; + pd_rect_t shadow_box; + pd_rect_t content_box; + pd_context_t *paint; } pd_boxshadow_context_t; typedef struct gradient { - int s; - double v; - double a; + int s; + double v; + double a; } gradient_t; /** 初始化渐变生成器 */ static void gradient_init(gradient_t *g, double t) { - /** - * s = vt - at²/2 - * a = 2x(vt - s)/t² - */ - g->s = 255; - g->v = 512.0f / t; - g->a = 2 * (g->v * t - g->s) / (t * t); + /** + * s = vt - at²/2 + * a = 2x(vt - s)/t² + */ + g->s = 255; + g->v = 512.0f / t; + g->a = 2 * (g->v * t - g->s) / (t * t); } /** 计算渐变后的值 */ static uint8_t gradient_compute(gradient_t *g, double t, int val) { - val *= g->s - (int)(g->v * t - (g->a * t * t) / 2.0); - return (uint8_t)(val >> 8); + val *= g->s - (int)(g->v * t - (g->a * t * t) / 2.0); + return (uint8_t)(val >> 8); } -PD_INLINE int get_boxshadow_width(const pd_boxshadow_t *shadow, int content_width) +PD_INLINE int get_boxshadow_width(const pd_boxshadow_t *shadow, + int content_width) { - return content_width + SHADOW_WIDTH(shadow) * 2; + return content_width + SHADOW_WIDTH(shadow) * 2; } PD_INLINE int get_boxshadow_height(const pd_boxshadow_t *shadow, - int content_height) + int content_height) { - return content_height + SHADOW_WIDTH(shadow) * 2; + return content_height + SHADOW_WIDTH(shadow) * 2; } static int get_boxshadow_box_x(const pd_boxshadow_t *shadow) { - return shadow->x >= SHADOW_WIDTH(shadow) - ? 0 - : SHADOW_WIDTH(shadow) - shadow->x; + return shadow->x >= SHADOW_WIDTH(shadow) + ? 0 + : SHADOW_WIDTH(shadow) - shadow->x; } static int get_boxshadow_box_y(const pd_boxshadow_t *shadow) { - return shadow->y >= SHADOW_WIDTH(shadow) - ? 0 - : SHADOW_WIDTH(shadow) - shadow->y; + return shadow->y >= SHADOW_WIDTH(shadow) + ? 0 + : SHADOW_WIDTH(shadow) - shadow->y; } static int get_boxshadow_y(const pd_boxshadow_t *shadow) { - return shadow->y <= SHADOW_WIDTH(shadow) - ? 0 - : shadow->y - SHADOW_WIDTH(shadow); + return shadow->y <= SHADOW_WIDTH(shadow) + ? 0 + : shadow->y - SHADOW_WIDTH(shadow); } static int get_boxshadow_x(const pd_boxshadow_t *shadow) { - return shadow->x <= SHADOW_WIDTH(shadow) - ? 0 - : shadow->x - SHADOW_WIDTH(shadow); + return shadow->x <= SHADOW_WIDTH(shadow) + ? 0 + : shadow->x - SHADOW_WIDTH(shadow); } void pd_boxshadow_init(pd_boxshadow_t *shadow) { - shadow->color.value = 0; - shadow->blur = 0; - shadow->spread = 0; - shadow->x = 0; - shadow->y = 0; + shadow->color.value = 0; + shadow->blur = 0; + shadow->spread = 0; + shadow->x = 0; + shadow->y = 0; } void pd_get_boxshadow_canvas_rect(const pd_boxshadow_t *shadow, - const pd_rect_t *content_rect, - pd_rect_t *canvas_rect) + const pd_rect_t *content_rect, + pd_rect_t *canvas_rect) { - pd_rect_t shadow_rect; - - shadow_rect.x = content_rect->x - SHADOW_WIDTH(shadow) + shadow->x; - shadow_rect.y = content_rect->y - SHADOW_WIDTH(shadow) + shadow->y; - shadow_rect.width = get_boxshadow_width(shadow, content_rect->width); - shadow_rect.height = get_boxshadow_height(shadow, content_rect->height); - canvas_rect->x = y_min(content_rect->x, shadow_rect.x); - canvas_rect->y = y_min(content_rect->y, shadow_rect.y); - canvas_rect->width = y_max(shadow_rect.x + shadow_rect.width, - content_rect->x + content_rect->width) - - canvas_rect->x; - canvas_rect->height = y_max(shadow_rect.y + shadow_rect.height, - content_rect->y + content_rect->height) - - canvas_rect->y; + pd_rect_t shadow_rect; + + shadow_rect.x = content_rect->x - SHADOW_WIDTH(shadow) + shadow->x; + shadow_rect.y = content_rect->y - SHADOW_WIDTH(shadow) + shadow->y; + shadow_rect.width = get_boxshadow_width(shadow, content_rect->width); + shadow_rect.height = get_boxshadow_height(shadow, content_rect->height); + canvas_rect->x = y_min(content_rect->x, shadow_rect.x); + canvas_rect->y = y_min(content_rect->y, shadow_rect.y); + canvas_rect->width = y_max(shadow_rect.x + shadow_rect.width, + content_rect->x + content_rect->width) - + canvas_rect->x; + canvas_rect->height = y_max(shadow_rect.y + shadow_rect.height, + content_rect->y + content_rect->height) - + canvas_rect->y; } static bool pd_paint_boxshadow_left_blur(pd_boxshadow_context_t *ctx) { - int x, y; - int right; - gradient_t g; - - pd_rect_t rect; - pd_rect_t paint_rect; - pd_canvas_t ref; - pd_canvas_t *canvas; - pd_color_t *p; - pd_color_t color = ctx->shadow->color; - - rect.x = ctx->shadow_box.x; - rect.y = ctx->shadow_box.y; - rect.width = BLUR_WIDTH(ctx->shadow); - rect.height = ctx->shadow_box.height; - right = rect.x + rect.width; - gradient_init(&g, BLUR_WIDTH(ctx->shadow)); - if (!pd_rect_overlap(&ctx->paint->rect, &rect, &rect)) { - return false; - } - right -= rect.x; - paint_rect.width = rect.width; - paint_rect.height = rect.height; - paint_rect.x = rect.x - ctx->paint->rect.x; - paint_rect.y = rect.y - ctx->paint->rect.y; - pd_canvas_quote(&ref, &ctx->paint->canvas, &paint_rect); - pd_canvas_get_quote_rect(&ref, &paint_rect); - canvas = pd_canvas_get_quote_source(&ref); - for (y = 0; y < paint_rect.height; ++y) { - p = pd_canvas_pixel_at(canvas, paint_rect.x, paint_rect.y + y); - for (x = 0; x < paint_rect.width; ++x, ++p) { - color.alpha = gradient_compute(&g, right - x, - ctx->shadow->color.a); - *p = color; - } - } - return true; + int x, y; + int right; + gradient_t g; + + pd_rect_t rect; + pd_rect_t paint_rect; + pd_canvas_t ref; + pd_canvas_t *canvas; + pd_color_t *p; + pd_color_t color = ctx->shadow->color; + + rect.x = ctx->shadow_box.x; + rect.y = ctx->shadow_box.y; + rect.width = BLUR_WIDTH(ctx->shadow); + rect.height = ctx->shadow_box.height; + right = rect.x + rect.width; + gradient_init(&g, BLUR_WIDTH(ctx->shadow)); + if (!pd_rect_overlap(&ctx->paint->rect, &rect, &rect)) { + return false; + } + right -= rect.x; + paint_rect.width = rect.width; + paint_rect.height = rect.height; + paint_rect.x = rect.x - ctx->paint->rect.x; + paint_rect.y = rect.y - ctx->paint->rect.y; + pd_canvas_quote(&ref, &ctx->paint->canvas, &paint_rect); + pd_canvas_get_quote_rect(&ref, &paint_rect); + canvas = pd_canvas_get_quote_source(&ref); + for (y = 0; y < paint_rect.height; ++y) { + p = pd_canvas_pixel_at(canvas, paint_rect.x, paint_rect.y + y); + for (x = 0; x < paint_rect.width; ++x, ++p) { + color.alpha = gradient_compute(&g, right - x, + ctx->shadow->color.a); + *p = color; + } + } + return true; } static bool pd_paint_boxshadow_right_blur(pd_boxshadow_context_t *ctx) { - int x, y; - int left; - gradient_t g; - - pd_rect_t rect; - pd_rect_t paint_rect; - pd_canvas_t ref; - pd_canvas_t *canvas; - pd_color_t *p; - pd_color_t color = ctx->shadow->color; - - rect.width = BLUR_WIDTH(ctx->shadow); - rect.height = ctx->shadow_box.height; - rect.x = ctx->shadow_box.x + ctx->shadow_box.width - rect.width; - rect.y = ctx->shadow_box.y; - left = rect.x; - gradient_init(&g, BLUR_WIDTH(ctx->shadow)); - if (!pd_rect_overlap(&ctx->paint->rect, &rect, &rect)) { - return false; - } - left -= rect.x + 1; - paint_rect.width = rect.width; - paint_rect.height = rect.height; - paint_rect.x = rect.x - ctx->paint->rect.x; - paint_rect.y = rect.y - ctx->paint->rect.y; - pd_canvas_quote(&ref, &ctx->paint->canvas, &paint_rect); - pd_canvas_get_quote_rect(&ref, &paint_rect); - canvas = pd_canvas_get_quote_source(&ref); - for (y = 0; y < paint_rect.height; ++y) { - p = pd_canvas_pixel_at(canvas, paint_rect.x, paint_rect.y + y); - for (x = 0; x < paint_rect.width; ++x, ++p) { - color.alpha = gradient_compute(&g, x - left, - ctx->shadow->color.a); - *p = color; - } - } - return true; + int x, y; + int left; + gradient_t g; + + pd_rect_t rect; + pd_rect_t paint_rect; + pd_canvas_t ref; + pd_canvas_t *canvas; + pd_color_t *p; + pd_color_t color = ctx->shadow->color; + + rect.width = BLUR_WIDTH(ctx->shadow); + rect.height = ctx->shadow_box.height; + rect.x = ctx->shadow_box.x + ctx->shadow_box.width - rect.width; + rect.y = ctx->shadow_box.y; + left = rect.x; + gradient_init(&g, BLUR_WIDTH(ctx->shadow)); + if (!pd_rect_overlap(&ctx->paint->rect, &rect, &rect)) { + return false; + } + left -= rect.x + 1; + paint_rect.width = rect.width; + paint_rect.height = rect.height; + paint_rect.x = rect.x - ctx->paint->rect.x; + paint_rect.y = rect.y - ctx->paint->rect.y; + pd_canvas_quote(&ref, &ctx->paint->canvas, &paint_rect); + pd_canvas_get_quote_rect(&ref, &paint_rect); + canvas = pd_canvas_get_quote_source(&ref); + for (y = 0; y < paint_rect.height; ++y) { + p = pd_canvas_pixel_at(canvas, paint_rect.x, paint_rect.y + y); + for (x = 0; x < paint_rect.width; ++x, ++p) { + color.alpha = gradient_compute(&g, x - left, + ctx->shadow->color.a); + *p = color; + } + } + return true; } static bool pd_paint_boxshadow_top_blur(pd_boxshadow_context_t *ctx) { - int x, y; - int bottom; - gradient_t g; - - pd_rect_t rect; - pd_rect_t paint_rect; - pd_canvas_t ref; - pd_canvas_t *canvas; - pd_color_t *p; - pd_color_t color = ctx->shadow->color; - - rect.width = ctx->shadow_box.width; - rect.height = BLUR_WIDTH(ctx->shadow); - rect.x = ctx->shadow_box.x; - rect.y = ctx->shadow_box.y; - bottom = rect.y + rect.height; - gradient_init(&g, BLUR_WIDTH(ctx->shadow)); - if (!pd_rect_overlap(&ctx->paint->rect, &rect, &rect)) { - return false; - } - bottom -= rect.y; - paint_rect.width = rect.width; - paint_rect.height = rect.height; - paint_rect.x = rect.x - ctx->paint->rect.x; - paint_rect.y = rect.y - ctx->paint->rect.y; - pd_canvas_quote(&ref, &ctx->paint->canvas, &paint_rect); - pd_canvas_get_quote_rect(&ref, &paint_rect); - canvas = pd_canvas_get_quote_source(&ref); - for (y = 0; y < paint_rect.height; ++y) { - p = pd_canvas_pixel_at(canvas, paint_rect.x, paint_rect.y + y); - color.alpha = - gradient_compute(&g, bottom - y, ctx->shadow->color.a); - for (x = 0; x < paint_rect.width; ++x, ++p) { - *p = color; - } - } - return true; + int x, y; + int bottom; + gradient_t g; + + pd_rect_t rect; + pd_rect_t paint_rect; + pd_canvas_t ref; + pd_canvas_t *canvas; + pd_color_t *p; + pd_color_t color = ctx->shadow->color; + + rect.width = ctx->shadow_box.width; + rect.height = BLUR_WIDTH(ctx->shadow); + rect.x = ctx->shadow_box.x; + rect.y = ctx->shadow_box.y; + bottom = rect.y + rect.height; + gradient_init(&g, BLUR_WIDTH(ctx->shadow)); + if (!pd_rect_overlap(&ctx->paint->rect, &rect, &rect)) { + return false; + } + bottom -= rect.y; + paint_rect.width = rect.width; + paint_rect.height = rect.height; + paint_rect.x = rect.x - ctx->paint->rect.x; + paint_rect.y = rect.y - ctx->paint->rect.y; + pd_canvas_quote(&ref, &ctx->paint->canvas, &paint_rect); + pd_canvas_get_quote_rect(&ref, &paint_rect); + canvas = pd_canvas_get_quote_source(&ref); + for (y = 0; y < paint_rect.height; ++y) { + p = pd_canvas_pixel_at(canvas, paint_rect.x, paint_rect.y + y); + color.alpha = + gradient_compute(&g, bottom - y, ctx->shadow->color.a); + for (x = 0; x < paint_rect.width; ++x, ++p) { + *p = color; + } + } + return true; } static bool pd_paint_boxshadow_bottom_blur(pd_boxshadow_context_t *ctx) { - int x, y; - int top; - gradient_t g; - - pd_rect_t rect; - pd_rect_t paint_rect; - pd_canvas_t ref; - pd_canvas_t *canvas; - pd_color_t *p; - pd_color_t color = ctx->shadow->color; - - rect.width = ctx->shadow_box.width; - rect.height = BLUR_WIDTH(ctx->shadow); - rect.x = ctx->shadow_box.x; - rect.y = ctx->shadow_box.y + ctx->shadow_box.height - rect.height; - top = rect.y; - gradient_init(&g, BLUR_WIDTH(ctx->shadow)); - if (!pd_rect_overlap(&ctx->paint->rect, &rect, &rect)) { - return false; - } - top -= rect.y + 1; - paint_rect.width = rect.width; - paint_rect.height = rect.height; - paint_rect.x = rect.x - ctx->paint->rect.x; - paint_rect.y = rect.y - ctx->paint->rect.y; - pd_canvas_quote(&ref, &ctx->paint->canvas, &paint_rect); - pd_canvas_get_quote_rect(&ref, &paint_rect); - canvas = pd_canvas_get_quote_source(&ref); - for (y = 0; y < paint_rect.height; ++y) { - p = pd_canvas_pixel_at(canvas, paint_rect.x, paint_rect.y + y); - color.a = gradient_compute(&g, y - top, ctx->shadow->color.a); - for (x = 0; x < paint_rect.width; ++x, ++p) { - *p = color; - } - } - return true; + int x, y; + int top; + gradient_t g; + + pd_rect_t rect; + pd_rect_t paint_rect; + pd_canvas_t ref; + pd_canvas_t *canvas; + pd_color_t *p; + pd_color_t color = ctx->shadow->color; + + rect.width = ctx->shadow_box.width; + rect.height = BLUR_WIDTH(ctx->shadow); + rect.x = ctx->shadow_box.x; + rect.y = ctx->shadow_box.y + ctx->shadow_box.height - rect.height; + top = rect.y; + gradient_init(&g, BLUR_WIDTH(ctx->shadow)); + if (!pd_rect_overlap(&ctx->paint->rect, &rect, &rect)) { + return false; + } + top -= rect.y + 1; + paint_rect.width = rect.width; + paint_rect.height = rect.height; + paint_rect.x = rect.x - ctx->paint->rect.x; + paint_rect.y = rect.y - ctx->paint->rect.y; + pd_canvas_quote(&ref, &ctx->paint->canvas, &paint_rect); + pd_canvas_get_quote_rect(&ref, &paint_rect); + canvas = pd_canvas_get_quote_source(&ref); + for (y = 0; y < paint_rect.height; ++y) { + p = pd_canvas_pixel_at(canvas, paint_rect.x, paint_rect.y + y); + color.a = gradient_compute(&g, y - top, ctx->shadow->color.a); + for (x = 0; x < paint_rect.width; ++x, ++p) { + *p = color; + } + } + return true; } static bool pd_paint_boxshadow_circle_blur(pd_boxshadow_context_t *ctx, - const pd_rect_t *circle_rect, - double center_x, double center_y, - int radius) + const pd_rect_t *circle_rect, + double center_x, double center_y, + int radius) { - double d; - double y2; - double r = y_max(0, CIRCLE_R(radius)); - double outer_r2 = POW2(r); - double inner_r = y_max(0, r - BLUR_WIDTH(ctx->shadow)); - double inner_smooth_r2 = POW2(inner_r + 1.0); - - int x, y; - unsigned char a = ctx->shadow->color.alpha; - - gradient_t g; - - pd_rect_t rect; - pd_canvas_t ref; - pd_color_t color; - pd_canvas_t *canvas; - pd_color_t *p; - - if (!pd_rect_overlap(&ctx->paint->rect, circle_rect, &rect)) { - return false; - } - color = ctx->shadow->color; - center_x = center_x + circle_rect->x - rect.x - 0.5; - center_y = center_y + circle_rect->y - rect.y - 0.5; - rect.x -= ctx->paint->rect.x; - rect.y -= ctx->paint->rect.y; - pd_canvas_quote(&ref, &ctx->paint->canvas, &rect); - pd_canvas_get_quote_rect(&ref, &rect); - canvas = pd_canvas_get_quote_source(&ref); - gradient_init(&g, BLUR_WIDTH(ctx->shadow)); - for (y = 0; y < rect.height; ++y) { - y2 = POW2(ToGeoY(y, center_y)); - p = pd_canvas_pixel_at(canvas, rect.x, rect.y + y); - for (x = 0; x < rect.width; ++x, ++p) { - d = y2 + POW2(ToGeoX(x, center_x)); - if (r - inner_r < 0.1) { - if (d >= inner_smooth_r2) { - p->alpha = 0; - continue; - } - color.a = a; - d = sqrt(d) - inner_r; - if (d > 0) { - color.a = smooth_left_pixel(&color, d); - } - *p = color; - continue; - } - if (d >= outer_r2) { - p->alpha = 0; - continue; - } - d = sqrt(d) - inner_r; - if (d < 0) { - color.a = a; - *p = color; - continue; - } - color.a = gradient_compute(&g, d, a); - *p = color; - } - } - return true; + double d; + double y2; + double r = y_max(0, CIRCLE_R(radius)); + double outer_r2 = POW2(r); + double inner_r = y_max(0, r - BLUR_WIDTH(ctx->shadow)); + double inner_smooth_r2 = POW2(inner_r + 1.0); + + int x, y; + unsigned char a = ctx->shadow->color.alpha; + + gradient_t g; + + pd_rect_t rect; + pd_canvas_t ref; + pd_color_t color; + pd_canvas_t *canvas; + pd_color_t *p; + + if (!pd_rect_overlap(&ctx->paint->rect, circle_rect, &rect)) { + return false; + } + color = ctx->shadow->color; + center_x = center_x + circle_rect->x - rect.x - 0.5; + center_y = center_y + circle_rect->y - rect.y - 0.5; + rect.x -= ctx->paint->rect.x; + rect.y -= ctx->paint->rect.y; + pd_canvas_quote(&ref, &ctx->paint->canvas, &rect); + pd_canvas_get_quote_rect(&ref, &rect); + canvas = pd_canvas_get_quote_source(&ref); + gradient_init(&g, BLUR_WIDTH(ctx->shadow)); + for (y = 0; y < rect.height; ++y) { + y2 = POW2(ToGeoY(y, center_y)); + p = pd_canvas_pixel_at(canvas, rect.x, rect.y + y); + for (x = 0; x < rect.width; ++x, ++p) { + d = y2 + POW2(ToGeoX(x, center_x)); + if (r - inner_r < 0.1) { + if (d >= inner_smooth_r2) { + p->alpha = 0; + continue; + } + color.a = a; + d = sqrt(d) - inner_r; + if (d > 0) { + color.a = smooth_left_pixel(&color, d); + } + *p = color; + continue; + } + if (d >= outer_r2) { + p->alpha = 0; + continue; + } + d = sqrt(d) - inner_r; + if (d < 0) { + color.a = a; + *p = color; + continue; + } + color.a = gradient_compute(&g, d, a); + *p = color; + } + } + return true; } static bool pd_paint_boxshadow_top_left_blur(pd_boxshadow_context_t *ctx) { - int radius; - pd_rect_t rect; - - radius = FULL_SHADOW_WIDTH(ctx) + ctx->shadow->top_left_radius; - radius = y_min(ctx->max_radius, radius); - rect.width = radius; - rect.height = rect.width; - rect.x = ctx->shadow_box.x; - rect.y = ctx->shadow_box.y; - return pd_paint_boxshadow_circle_blur(ctx, &rect, rect.width, - rect.height, radius); + int radius; + pd_rect_t rect; + + radius = FULL_SHADOW_WIDTH(ctx) + ctx->shadow->top_left_radius; + radius = y_min(ctx->max_radius, radius); + rect.width = radius; + rect.height = rect.width; + rect.x = ctx->shadow_box.x; + rect.y = ctx->shadow_box.y; + return pd_paint_boxshadow_circle_blur(ctx, &rect, rect.width, + rect.height, radius); } static bool pd_paint_boxshadow_top_right_blur(pd_boxshadow_context_t *ctx) { - int radius; - pd_rect_t rect; - - radius = FULL_SHADOW_WIDTH(ctx) + ctx->shadow->top_right_radius; - radius = y_min(ctx->max_radius, radius); - rect.width = radius; - rect.height = rect.width; - rect.x = ctx->shadow_box.x + ctx->shadow_box.width - rect.width; - rect.y = ctx->shadow_box.y; - return pd_paint_boxshadow_circle_blur(ctx, &rect, 0, rect.height, - radius); + int radius; + pd_rect_t rect; + + radius = FULL_SHADOW_WIDTH(ctx) + ctx->shadow->top_right_radius; + radius = y_min(ctx->max_radius, radius); + rect.width = radius; + rect.height = rect.width; + rect.x = ctx->shadow_box.x + ctx->shadow_box.width - rect.width; + rect.y = ctx->shadow_box.y; + return pd_paint_boxshadow_circle_blur(ctx, &rect, 0, rect.height, + radius); } static bool pd_paint_boxshadow_bottom_left_blur(pd_boxshadow_context_t *ctx) { - int radius; - pd_rect_t rect; - - radius = FULL_SHADOW_WIDTH(ctx) + ctx->shadow->bottom_left_radius; - radius = y_min(ctx->max_radius, radius); - rect.width = radius; - rect.height = rect.width; - rect.x = ctx->shadow_box.x; - rect.y = ctx->shadow_box.y + ctx->shadow_box.height - rect.height; - return pd_paint_boxshadow_circle_blur(ctx, &rect, rect.width, 0, - radius); + int radius; + pd_rect_t rect; + + radius = FULL_SHADOW_WIDTH(ctx) + ctx->shadow->bottom_left_radius; + radius = y_min(ctx->max_radius, radius); + rect.width = radius; + rect.height = rect.width; + rect.x = ctx->shadow_box.x; + rect.y = ctx->shadow_box.y + ctx->shadow_box.height - rect.height; + return pd_paint_boxshadow_circle_blur(ctx, &rect, rect.width, 0, + radius); } static bool pd_paint_boxshadow_bottom_right_blur(pd_boxshadow_context_t *ctx) { - int radius; - pd_rect_t rect; - - radius = FULL_SHADOW_WIDTH(ctx) + ctx->shadow->bottom_right_radius; - radius = y_min(ctx->max_radius, radius); - rect.width = radius; - rect.height = rect.width; - rect.x = ctx->shadow_box.x + ctx->shadow_box.width - rect.width; - rect.y = ctx->shadow_box.y + ctx->shadow_box.height - rect.height; - return pd_paint_boxshadow_circle_blur(ctx, &rect, 0, 0, radius); + int radius; + pd_rect_t rect; + + radius = FULL_SHADOW_WIDTH(ctx) + ctx->shadow->bottom_right_radius; + radius = y_min(ctx->max_radius, radius); + rect.width = radius; + rect.height = rect.width; + rect.x = ctx->shadow_box.x + ctx->shadow_box.width - rect.width; + rect.y = ctx->shadow_box.y + ctx->shadow_box.height - rect.height; + return pd_paint_boxshadow_circle_blur(ctx, &rect, 0, 0, radius); } static int clear_pixels_of_circle(pd_canvas_t *canvas, double center_x, - double center_y, int radius) + double center_y, int radius) { - double r = CIRCLE_R(radius); - double outer_r2 = POW2(r + 1.0); - double d; - double y2; - - int xi, yi; - - pd_rect_t rect; - pd_color_t *p; - - pd_canvas_get_quote_rect(canvas, &rect); - canvas = pd_canvas_get_quote_source(canvas); - if (!pd_canvas_is_valid(canvas)) { - return -1; - } - center_x -= 0.5; - center_y -= 0.5; - for (yi = 0; yi < rect.height; ++yi) { - y2 = POW2(ToGeoY(yi, center_y)); - p = pd_canvas_pixel_at(canvas, rect.x, rect.y + yi); - for (xi = 0; xi < rect.width; ++xi, ++p) { - d = y2 + POW2(ToGeoX(xi, center_x)); - if (d >= outer_r2) { - continue; - } - d = sqrt(d) - r; - if (d <= 0) { - p->alpha = 0; - } else { - p->alpha = smooth_right_pixel(p, d); - } - } - } - return 0; + double r = CIRCLE_R(radius); + double outer_r2 = POW2(r + 1.0); + double d; + double y2; + + int xi, yi; + + pd_rect_t rect; + pd_color_t *p; + + pd_canvas_get_quote_rect(canvas, &rect); + canvas = pd_canvas_get_quote_source(canvas); + if (!pd_canvas_is_valid(canvas)) { + return -1; + } + center_x -= 0.5; + center_y -= 0.5; + for (yi = 0; yi < rect.height; ++yi) { + y2 = POW2(ToGeoY(yi, center_y)); + p = pd_canvas_pixel_at(canvas, rect.x, rect.y + yi); + for (xi = 0; xi < rect.width; ++xi, ++p) { + d = y2 + POW2(ToGeoX(xi, center_x)); + if (d >= outer_r2) { + continue; + } + d = sqrt(d) - r; + if (d <= 0) { + p->alpha = 0; + } else { + p->alpha = smooth_right_pixel(p, d); + } + } + } + return 0; } static void pd_fill_boxshadow_rect(pd_boxshadow_context_t *ctx) { - pd_rect_t rect; - - rect = ctx->shadow_box; - if (pd_rect_overlap(&rect, &ctx->paint->rect, &rect)) { - rect.x -= ctx->paint->rect.x; - rect.y -= ctx->paint->rect.y; - pd_canvas_fill_rect(&ctx->paint->canvas, ctx->shadow->color, - rect); - } + pd_rect_t rect; + + rect = ctx->shadow_box; + if (pd_rect_overlap(&rect, &ctx->paint->rect, &rect)) { + rect.x -= ctx->paint->rect.x; + rect.y -= ctx->paint->rect.y; + pd_canvas_fill_rect(&ctx->paint->canvas, ctx->shadow->color, + rect); + } } static void pd_clear_boxshadow_content_rect(pd_boxshadow_context_t *ctx) { - int r; - double center_x, center_y; - - pd_rect_t rect; - pd_rect_t bound; - pd_canvas_t canvas; - list_t rects; - list_node_t *node; - - /* Initialize a queue for recording the area after the split content - * area */ - list_create(&rects); - pd_rects_add(&rects, &ctx->content_box); - - r = ctx->shadow->top_left_radius; - bound.x = ctx->content_box.x; - bound.y = ctx->content_box.y; - bound.width = r; - bound.height = r; - /* Delete the top left corner of the content area */ - pd_rects_remove(&rects, &bound); - if (pd_rect_overlap(&ctx->paint->rect, &bound, &rect)) { - center_x = bound.x - rect.x + r; - center_y = bound.y - rect.y + r; - rect.x -= ctx->paint->rect.x; - rect.y -= ctx->paint->rect.y; - pd_canvas_quote(&canvas, &ctx->paint->canvas, &rect); - clear_pixels_of_circle(&canvas, center_x, center_y, r); - } - - r = ctx->shadow->top_right_radius; - bound.x = ctx->content_box.x + ctx->content_box.width - r; - bound.y = ctx->content_box.y; - bound.width = r; - bound.height = r; - /* Delete the top right corner of the content area */ - pd_rects_remove(&rects, &bound); - if (pd_rect_overlap(&ctx->paint->rect, &bound, &rect)) { - center_x = bound.x - rect.x; - center_y = bound.y - rect.y + r; - rect.x -= ctx->paint->rect.x; - rect.y -= ctx->paint->rect.y; - pd_canvas_quote(&canvas, &ctx->paint->canvas, &rect); - clear_pixels_of_circle(&canvas, center_x, center_y, r); - } - - r = ctx->shadow->bottom_left_radius; - bound.x = ctx->content_box.x; - bound.y = ctx->content_box.y + ctx->content_box.height - r; - bound.width = r; - bound.height = r; - /* Delete the bottom left corner of the content area */ - pd_rects_remove(&rects, &bound); - if (pd_rect_overlap(&ctx->paint->rect, &bound, &rect)) { - center_x = bound.x - rect.x + r; - center_y = bound.y - rect.y; - rect.x -= ctx->paint->rect.x; - rect.y -= ctx->paint->rect.y; - pd_canvas_quote(&canvas, &ctx->paint->canvas, &rect); - clear_pixels_of_circle(&canvas, center_x, center_y, r); - } - - r = ctx->shadow->bottom_right_radius; - bound.x = ctx->content_box.x + ctx->content_box.width - r; - bound.y = ctx->content_box.y + ctx->content_box.height - r; - bound.width = r; - bound.height = r; - /* Delete the bottom right corner of the content area */ - pd_rects_remove(&rects, &bound); - if (pd_rect_overlap(&ctx->paint->rect, &bound, &rect)) { - center_x = bound.x - rect.x; - center_y = bound.y - rect.y; - rect.x -= ctx->paint->rect.x; - rect.y -= ctx->paint->rect.y; - pd_canvas_quote(&canvas, &ctx->paint->canvas, &rect); - clear_pixels_of_circle(&canvas, center_x, center_y, r); - } - - /* Clear pixels in the remaining areas of the content area */ - for (list_each(node, &rects)) { - if (pd_rect_overlap(&ctx->paint->rect, node->data, &rect)) { - rect.x -= ctx->paint->rect.x; - rect.y -= ctx->paint->rect.y; - pd_canvas_fill_rect(&ctx->paint->canvas, - pd_argb(0, 0, 0, 0), rect); - } - } - pd_rects_clear(&rects); + int r; + double center_x, center_y; + + pd_rect_t rect; + pd_rect_t bound; + pd_canvas_t canvas; + list_t rects; + list_node_t *node; + + /* Initialize a queue for recording the area after the split content + * area */ + list_create(&rects); + pd_rects_add(&rects, &ctx->content_box); + + r = ctx->shadow->top_left_radius; + bound.x = ctx->content_box.x; + bound.y = ctx->content_box.y; + bound.width = r; + bound.height = r; + /* Delete the top left corner of the content area */ + pd_rects_remove(&rects, &bound); + if (pd_rect_overlap(&ctx->paint->rect, &bound, &rect)) { + center_x = bound.x - rect.x + r; + center_y = bound.y - rect.y + r; + rect.x -= ctx->paint->rect.x; + rect.y -= ctx->paint->rect.y; + pd_canvas_quote(&canvas, &ctx->paint->canvas, &rect); + clear_pixels_of_circle(&canvas, center_x, center_y, r); + } + + r = ctx->shadow->top_right_radius; + bound.x = ctx->content_box.x + ctx->content_box.width - r; + bound.y = ctx->content_box.y; + bound.width = r; + bound.height = r; + /* Delete the top right corner of the content area */ + pd_rects_remove(&rects, &bound); + if (pd_rect_overlap(&ctx->paint->rect, &bound, &rect)) { + center_x = bound.x - rect.x; + center_y = bound.y - rect.y + r; + rect.x -= ctx->paint->rect.x; + rect.y -= ctx->paint->rect.y; + pd_canvas_quote(&canvas, &ctx->paint->canvas, &rect); + clear_pixels_of_circle(&canvas, center_x, center_y, r); + } + + r = ctx->shadow->bottom_left_radius; + bound.x = ctx->content_box.x; + bound.y = ctx->content_box.y + ctx->content_box.height - r; + bound.width = r; + bound.height = r; + /* Delete the bottom left corner of the content area */ + pd_rects_remove(&rects, &bound); + if (pd_rect_overlap(&ctx->paint->rect, &bound, &rect)) { + center_x = bound.x - rect.x + r; + center_y = bound.y - rect.y; + rect.x -= ctx->paint->rect.x; + rect.y -= ctx->paint->rect.y; + pd_canvas_quote(&canvas, &ctx->paint->canvas, &rect); + clear_pixels_of_circle(&canvas, center_x, center_y, r); + } + + r = ctx->shadow->bottom_right_radius; + bound.x = ctx->content_box.x + ctx->content_box.width - r; + bound.y = ctx->content_box.y + ctx->content_box.height - r; + bound.width = r; + bound.height = r; + /* Delete the bottom right corner of the content area */ + pd_rects_remove(&rects, &bound); + if (pd_rect_overlap(&ctx->paint->rect, &bound, &rect)) { + center_x = bound.x - rect.x; + center_y = bound.y - rect.y; + rect.x -= ctx->paint->rect.x; + rect.y -= ctx->paint->rect.y; + pd_canvas_quote(&canvas, &ctx->paint->canvas, &rect); + clear_pixels_of_circle(&canvas, center_x, center_y, r); + } + + /* Clear pixels in the remaining areas of the content area */ + for (list_each(node, &rects)) { + if (pd_rect_overlap(&ctx->paint->rect, node->data, &rect)) { + rect.x -= ctx->paint->rect.x; + rect.y -= ctx->paint->rect.y; + pd_canvas_fill_rect(&ctx->paint->canvas, + pd_argb(0, 0, 0, 0), rect); + } + } + pd_rects_clear(&rects); } int pd_paint_boxshadow(pd_context_t *ctx, const pd_boxshadow_t *shadow, - const pd_rect_t *box, int content_width, - int content_height) + const pd_rect_t *box, int content_width, + int content_height) { - pd_context_t tmp; - pd_boxshadow_context_t sd_ctx; - - /* 判断容器尺寸是否低于阴影占用的最小尺寸 */ - if (box->width < get_boxshadow_width(shadow, 0) || - box->height < get_boxshadow_height(shadow, 0)) { - return -1; - } - if (SHADOW_WIDTH(shadow) == 0 && shadow->x == 0 && shadow->y == 0) { - return 0; - } - - /* Initialize a rendering context for render shadow */ - sd_ctx.box = box; - sd_ctx.shadow = shadow; - sd_ctx.max_radius = - y_min(content_width, content_height) / 2 + SHADOW_WIDTH(shadow); - sd_ctx.shadow_box.x = get_boxshadow_x(shadow); - sd_ctx.shadow_box.y = get_boxshadow_y(shadow); - sd_ctx.shadow_box.width = get_boxshadow_width(shadow, content_width); - sd_ctx.shadow_box.height = get_boxshadow_width(shadow, content_height); - sd_ctx.content_box.x = get_boxshadow_box_x(shadow); - sd_ctx.content_box.y = get_boxshadow_box_y(shadow); - sd_ctx.content_box.width = content_width; - sd_ctx.content_box.height = content_height; - - /* Create a paint context for render shadow */ - sd_ctx.paint = &tmp; - pd_canvas_init(&tmp.canvas); - tmp.rect = ctx->rect; - tmp.with_alpha = true; - tmp.canvas.color_type = PD_COLOR_TYPE_ARGB; - pd_canvas_create(&sd_ctx.paint->canvas, ctx->rect.width, - ctx->rect.height); - - /* Render box shadow */ - pd_fill_boxshadow_rect(&sd_ctx); - pd_paint_boxshadow_left_blur(&sd_ctx); - pd_paint_boxshadow_right_blur(&sd_ctx); - pd_paint_boxshadow_top_blur(&sd_ctx); - pd_paint_boxshadow_bottom_blur(&sd_ctx); - pd_paint_boxshadow_top_left_blur(&sd_ctx); - pd_paint_boxshadow_top_right_blur(&sd_ctx); - pd_paint_boxshadow_bottom_left_blur(&sd_ctx); - pd_paint_boxshadow_bottom_right_blur(&sd_ctx); - /* Clear pixels that overlap the content area */ - pd_clear_boxshadow_content_rect(&sd_ctx); - - /* Render the rendered shadow bitmap to the canvas */ - pd_canvas_mix(&ctx->canvas, &sd_ctx.paint->canvas, 0, 0, - ctx->with_alpha); - pd_canvas_destroy(&sd_ctx.paint->canvas); - return 0; + pd_context_t tmp; + pd_boxshadow_context_t sd_ctx; + + /* 判断容器尺寸是否低于阴影占用的最小尺寸 */ + if (box->width < get_boxshadow_width(shadow, 0) || + box->height < get_boxshadow_height(shadow, 0)) { + return -1; + } + if (SHADOW_WIDTH(shadow) == 0 && shadow->x == 0 && shadow->y == 0) { + return 0; + } + + /* Initialize a rendering context for render shadow */ + sd_ctx.box = box; + sd_ctx.shadow = shadow; + sd_ctx.max_radius = + y_min(content_width, content_height) / 2 + SHADOW_WIDTH(shadow); + sd_ctx.shadow_box.x = get_boxshadow_x(shadow); + sd_ctx.shadow_box.y = get_boxshadow_y(shadow); + sd_ctx.shadow_box.width = get_boxshadow_width(shadow, content_width); + sd_ctx.shadow_box.height = get_boxshadow_width(shadow, content_height); + sd_ctx.content_box.x = get_boxshadow_box_x(shadow); + sd_ctx.content_box.y = get_boxshadow_box_y(shadow); + sd_ctx.content_box.width = content_width; + sd_ctx.content_box.height = content_height; + + /* Create a paint context for render shadow */ + sd_ctx.paint = &tmp; + pd_canvas_init(&tmp.canvas); + tmp.rect = ctx->rect; + tmp.with_alpha = true; + tmp.canvas.color_type = PD_COLOR_TYPE_ARGB; + pd_canvas_create(&sd_ctx.paint->canvas, ctx->rect.width, + ctx->rect.height); + + /* Render box shadow */ + pd_fill_boxshadow_rect(&sd_ctx); + pd_paint_boxshadow_left_blur(&sd_ctx); + pd_paint_boxshadow_right_blur(&sd_ctx); + pd_paint_boxshadow_top_blur(&sd_ctx); + pd_paint_boxshadow_bottom_blur(&sd_ctx); + pd_paint_boxshadow_top_left_blur(&sd_ctx); + pd_paint_boxshadow_top_right_blur(&sd_ctx); + pd_paint_boxshadow_bottom_left_blur(&sd_ctx); + pd_paint_boxshadow_bottom_right_blur(&sd_ctx); + /* Clear pixels that overlap the content area */ + pd_clear_boxshadow_content_rect(&sd_ctx); + + /* Render the rendered shadow bitmap to the canvas */ + pd_canvas_mix(&ctx->canvas, &sd_ctx.paint->canvas, 0, 0, + ctx->with_alpha); + pd_canvas_destroy(&sd_ctx.paint->canvas); + return 0; } diff --git a/lib/pandagl/src/canvas.c b/lib/pandagl/src/canvas.c index 374f1e78f..09b34303f 100644 --- a/lib/pandagl/src/canvas.c +++ b/lib/pandagl/src/canvas.c @@ -1,283 +1,286 @@ /* * lib/pandagl/src/canvas.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include void pd_canvas_init(pd_canvas_t *canvas) { - canvas->quote.is_valid = false; - canvas->quote.source = NULL; - canvas->quote.top = 0; - canvas->quote.left = 0; - canvas->color_type = PD_COLOR_TYPE_RGB; - canvas->bytes = NULL; - canvas->opacity = 1.0; - canvas->mem_size = 0; - canvas->width = 0; - canvas->height = 0; - canvas->bytes_per_pixel = 3; - canvas->bytes_per_row = 0; + canvas->quote.is_valid = false; + canvas->quote.source = NULL; + canvas->quote.top = 0; + canvas->quote.left = 0; + canvas->color_type = PD_COLOR_TYPE_RGB; + canvas->bytes = NULL; + canvas->opacity = 1.0; + canvas->mem_size = 0; + canvas->width = 0; + canvas->height = 0; + canvas->bytes_per_pixel = 3; + canvas->bytes_per_row = 0; } bool pd_canvas_is_valid(const pd_canvas_t *canvas) { - if (!canvas) { - return false; - } - if (canvas->quote.is_valid) { - return canvas->quote.source && - canvas->quote.source->width > 0 && - canvas->quote.source->height > 0; - } - return canvas->bytes && canvas->height > 0 && canvas->width > 0; + if (!canvas) { + return false; + } + if (canvas->quote.is_valid) { + return canvas->quote.source && + canvas->quote.source->width > 0 && + canvas->quote.source->height > 0; + } + return canvas->bytes && canvas->height > 0 && canvas->width > 0; } int pd_canvas_quote(pd_canvas_t *self, pd_canvas_t *source, - const pd_rect_t *rect) + const pd_rect_t *rect) { - pd_rect_t quote_rect; - if (!rect) { - quote_rect.x = 0; - quote_rect.y = 0; - quote_rect.width = source->width; - quote_rect.height = source->height; - } else { - quote_rect = *rect; - } - pd_rect_correct("e_rect, source->width, source->height); - /* 如果引用源本身已经引用了另一个源 */ - if (source->quote.is_valid) { - quote_rect.x += source->quote.left; - quote_rect.y += source->quote.top; - source = source->quote.source; - } - if (quote_rect.width <= 0 || quote_rect.height <= 0) { - self->width = 0; - self->height = 0; - self->opacity = 1.0; - self->quote.left = 0; - self->quote.top = 0; - self->bytes = NULL; - self->quote.source = NULL; - self->quote.is_valid = false; - return -1; - } - self->opacity = 1.0; - self->bytes = NULL; - self->mem_size = 0; - self->width = quote_rect.width; - self->height = quote_rect.height; - self->color_type = source->color_type; - self->bytes_per_pixel = source->bytes_per_pixel; - self->bytes_per_row = source->bytes_per_row; - self->quote.is_valid = true; - self->quote.source = source; - self->quote.left = quote_rect.x; - self->quote.top = quote_rect.y; - return 0; + pd_rect_t quote_rect; + if (!rect) { + quote_rect.x = 0; + quote_rect.y = 0; + quote_rect.width = source->width; + quote_rect.height = source->height; + } else { + quote_rect = *rect; + } + pd_rect_correct("e_rect, source->width, source->height); + /* 如果引用源本身已经引用了另一个源 */ + if (source->quote.is_valid) { + quote_rect.x += source->quote.left; + quote_rect.y += source->quote.top; + source = source->quote.source; + } + if (quote_rect.width <= 0 || quote_rect.height <= 0) { + self->width = 0; + self->height = 0; + self->opacity = 1.0; + self->quote.left = 0; + self->quote.top = 0; + self->bytes = NULL; + self->quote.source = NULL; + self->quote.is_valid = false; + return -1; + } + self->opacity = 1.0; + self->bytes = NULL; + self->mem_size = 0; + self->width = quote_rect.width; + self->height = quote_rect.height; + self->color_type = source->color_type; + self->bytes_per_pixel = source->bytes_per_pixel; + self->bytes_per_row = source->bytes_per_row; + self->quote.is_valid = true; + self->quote.source = source; + self->quote.left = quote_rect.x; + self->quote.top = quote_rect.y; + return 0; } void pd_canvas_get_quote_rect(const pd_canvas_t *canvas, pd_rect_t *rect) { - if (canvas->quote.is_valid) { - rect->x = canvas->quote.left; - rect->y = canvas->quote.top; - } else { - rect->x = 0; - rect->y = 0; - } - rect->width = canvas->width; - rect->height = canvas->height; + if (canvas->quote.is_valid) { + rect->x = canvas->quote.left; + rect->y = canvas->quote.top; + } else { + rect->x = 0; + rect->y = 0; + } + rect->width = canvas->width; + rect->height = canvas->height; } void pd_canvas_destroy(pd_canvas_t *canvas) { - /* 解除引用 */ - if (canvas && canvas->quote.is_valid) { - canvas->quote.source = NULL; - canvas->quote.is_valid = false; - return; - } - if (canvas->bytes) { - free(canvas->bytes); - canvas->bytes = NULL; - } - canvas->width = 0; - canvas->height = 0; - canvas->mem_size = 0; + /* 解除引用 */ + if (canvas && canvas->quote.is_valid) { + canvas->quote.source = NULL; + canvas->quote.is_valid = false; + return; + } + if (canvas->bytes) { + free(canvas->bytes); + canvas->bytes = NULL; + } + canvas->width = 0; + canvas->height = 0; + canvas->mem_size = 0; } int pd_canvas_create(pd_canvas_t *canvas, unsigned width, unsigned height) { - size_t size; - if (width > 100000 || height > 100000) { - logger_error("canvas size is too large!"); - abort(); - } - if (width < 1 || height < 1) { - pd_canvas_destroy(canvas); - return -1; - } - canvas->bytes_per_pixel = pd_get_pixel_size(canvas->color_type); - canvas->bytes_per_row = - pd_get_pixel_row_size(canvas->color_type, width); - size = canvas->bytes_per_row * height; - if (pd_canvas_is_valid(canvas)) { - /* 如果现有图形尺寸大于要创建的图形的尺寸,直接改尺寸即可 */ - if (canvas->mem_size >= size) { - memset(canvas->bytes, 0, canvas->mem_size); - canvas->width = width; - canvas->height = height; - return 0; - } - pd_canvas_destroy(canvas); - } - canvas->mem_size = size; - canvas->bytes = calloc(1, size); - if (!canvas->bytes) { - canvas->width = 0; - canvas->height = 0; - return -2; - } - canvas->width = width; - canvas->height = height; - return 0; + size_t size; + if (width > 100000 || height > 100000) { + logger_error("canvas size is too large!"); + abort(); + } + if (width < 1 || height < 1) { + pd_canvas_destroy(canvas); + return -1; + } + canvas->bytes_per_pixel = pd_get_pixel_size(canvas->color_type); + canvas->bytes_per_row = + pd_get_pixel_row_size(canvas->color_type, width); + size = canvas->bytes_per_row * height; + if (pd_canvas_is_valid(canvas)) { + /* 如果现有图形尺寸大于要创建的图形的尺寸,直接改尺寸即可 */ + if (canvas->mem_size >= size) { + memset(canvas->bytes, 0, canvas->mem_size); + canvas->width = width; + canvas->height = height; + return 0; + } + pd_canvas_destroy(canvas); + } + canvas->mem_size = size; + canvas->bytes = calloc(1, size); + if (!canvas->bytes) { + canvas->width = 0; + canvas->height = 0; + return -2; + } + canvas->width = width; + canvas->height = height; + return 0; } static void pd_canvas_direct_replace(pd_canvas_t *des, pd_rect_t des_rect, - const pd_canvas_t *src, int src_x, - int src_y) + const pd_canvas_t *src, int src_x, + int src_y) { - int y; - uint8_t *byte_row_des, *byte_row_src; - - byte_row_src = pd_canvas_pixel_at(src, src_x, src_y); - byte_row_des = pd_canvas_pixel_at(des, des_rect.x, des_rect.y); - for (y = 0; y < des_rect.height; ++y) { - pd_format_pixels(byte_row_src, src->color_type, byte_row_des, - des->color_type, des_rect.width); - byte_row_src += src->bytes_per_row; - byte_row_des += des->bytes_per_row; - } + int y; + uint8_t *byte_row_des, *byte_row_src; + + byte_row_src = pd_canvas_pixel_at(src, src_x, src_y); + byte_row_des = pd_canvas_pixel_at(des, des_rect.x, des_rect.y); + for (y = 0; y < des_rect.height; ++y) { + pd_format_pixels(byte_row_src, src->color_type, byte_row_des, + des->color_type, des_rect.width); + byte_row_src += src->bytes_per_row; + byte_row_des += des->bytes_per_row; + } } int pd_canvas_begin_writing(pd_canvas_t **canvas, pd_rect_t *rect) { - pd_canvas_t tmp; - - if (!pd_canvas_is_valid(*canvas)) { - return -1; - } - pd_canvas_quote(&tmp, *canvas, rect); - pd_canvas_get_quote_rect(&tmp, rect); - if (rect->width < 1 || rect->height < 1) { - return -1; - } - *canvas = pd_canvas_get_quote_source(&tmp); - return 0; + pd_canvas_t tmp; + + if (!pd_canvas_is_valid(*canvas)) { + return -1; + } + pd_canvas_quote(&tmp, *canvas, rect); + pd_canvas_get_quote_rect(&tmp, rect); + if (rect->width < 1 || rect->height < 1) { + return -1; + } + *canvas = pd_canvas_get_quote_source(&tmp); + return 0; } int pd_canvas_replace(pd_canvas_t *back, const pd_canvas_t *fore, int left, - int top) + int top) { - pd_rect_t read_rect, write_rect; - - if (!pd_canvas_is_valid(fore)) { - return -1; - } - write_rect.x = left; - write_rect.y = top; - write_rect.width = fore->width; - write_rect.height = fore->height; - if (pd_canvas_begin_writing(&back, &write_rect) != 0) { - return -1; - } - pd_canvas_get_quote_rect(fore, &read_rect); - if (read_rect.width <= 0 || read_rect.height <= 0) { - return -2; - } - left = read_rect.x; - top = read_rect.y; - fore = pd_canvas_get_quote_source_readonly(fore); - switch (fore->color_type) { - case PD_COLOR_TYPE_RGB888: - case PD_COLOR_TYPE_ARGB8888: - pd_canvas_direct_replace(back, write_rect, fore, left, top); - return 0; - default: - break; - } - return -1; + pd_rect_t read_rect, write_rect; + + if (!pd_canvas_is_valid(fore)) { + return -1; + } + write_rect.x = left; + write_rect.y = top; + write_rect.width = fore->width; + write_rect.height = fore->height; + if (pd_canvas_begin_writing(&back, &write_rect) != 0) { + return -1; + } + pd_canvas_get_quote_rect(fore, &read_rect); + if (read_rect.width <= 0 || read_rect.height <= 0) { + return -2; + } + left = read_rect.x; + top = read_rect.y; + fore = pd_canvas_get_quote_source_readonly(fore); + switch (fore->color_type) { + case PD_COLOR_TYPE_RGB888: + case PD_COLOR_TYPE_ARGB8888: + pd_canvas_direct_replace(back, write_rect, fore, left, top); + return 0; + default: + break; + } + return -1; } int pd_canvas_set_color_type(pd_canvas_t *canvas, int color_type) { - pd_canvas_t tmp; - - if (canvas->color_type == color_type) { - return -1; - } - pd_canvas_init(&tmp); - pd_canvas_create(&tmp, canvas->width, canvas->height); - if (pd_canvas_replace(&tmp, canvas, 0, 0) == 0) { - pd_canvas_destroy(canvas); - *canvas = tmp; - return 0; - } - pd_canvas_destroy(&tmp); - return -1; + pd_canvas_t tmp; + + if (canvas->color_type == color_type) { + return -1; + } + pd_canvas_init(&tmp); + pd_canvas_create(&tmp, canvas->width, canvas->height); + if (pd_canvas_replace(&tmp, canvas, 0, 0) == 0) { + pd_canvas_destroy(canvas); + *canvas = tmp; + return 0; + } + pd_canvas_destroy(&tmp); + return -1; } int pd_canvas_cut(const pd_canvas_t *canvas, pd_rect_t rect, - pd_canvas_t *out_canvas) + pd_canvas_t *out_canvas) { - int y; - uint8_t *src_row, *des_row; - - if (!pd_canvas_is_valid(canvas)) { - return -2; - } - pd_rect_correct(&rect, canvas->width, canvas->height); - if (rect.width <= 0 || rect.height <= 0) { - return -3; - } - out_canvas->color_type = canvas->color_type; - out_canvas->opacity = canvas->opacity; - if (0 != pd_canvas_create(out_canvas, rect.width, rect.height)) { - return -1; - } - des_row = out_canvas->bytes; - src_row = canvas->bytes + rect.y * canvas->bytes_per_row + - rect.x * canvas->bytes_per_pixel; - for (y = 0; y < rect.height; ++y) { - memcpy(des_row, src_row, out_canvas->bytes_per_row); - des_row += out_canvas->bytes_per_row; - src_row += canvas->bytes_per_row; - } - return 0; + int y; + uint8_t *src_row, *des_row; + + if (!pd_canvas_is_valid(canvas)) { + return -2; + } + pd_rect_correct(&rect, canvas->width, canvas->height); + if (rect.width <= 0 || rect.height <= 0) { + return -3; + } + out_canvas->color_type = canvas->color_type; + out_canvas->opacity = canvas->opacity; + if (0 != pd_canvas_create(out_canvas, rect.width, rect.height)) { + return -1; + } + des_row = out_canvas->bytes; + src_row = canvas->bytes + rect.y * canvas->bytes_per_row + + rect.x * canvas->bytes_per_pixel; + for (y = 0; y < rect.height; ++y) { + memcpy(des_row, src_row, out_canvas->bytes_per_row); + des_row += out_canvas->bytes_per_row; + src_row += canvas->bytes_per_row; + } + return 0; } void pd_canvas_copy(pd_canvas_t *des, const pd_canvas_t *src) { - const pd_canvas_t *canvas; - - if (!des || !pd_canvas_is_valid(src)) { - return; - } - canvas = pd_canvas_get_quote_source_readonly(src); - des->color_type = canvas->color_type; - /* 创建合适尺寸的Graph */ - pd_canvas_create(des, src->width, src->height); - pd_canvas_replace(des, src, 0, 0); - des->opacity = src->opacity; + const pd_canvas_t *canvas; + + if (!des || !pd_canvas_is_valid(src)) { + return; + } + canvas = pd_canvas_get_quote_source_readonly(src); + des->color_type = canvas->color_type; + /* 创建合适尺寸的Graph */ + pd_canvas_create(des, src->width, src->height); + pd_canvas_replace(des, src, 0, 0); + des->opacity = src->opacity; } /* FIXME: improve alpha blending method @@ -285,171 +288,171 @@ void pd_canvas_copy(pd_canvas_t *des, const pd_canvas_t *src) */ static void pd_canvas_mix_argb_with_alpha(pd_canvas_t *des, pd_rect_t des_rect, - const pd_canvas_t *src, int src_x, - int src_y) + const pd_canvas_t *src, int src_x, + int src_y) { - int x, y; - pd_color_t *px_src, *px_des; - - for (y = 0; y < des_rect.height; ++y) { - px_src = pd_canvas_pixel_at(src, src_x, src_y + y); - px_des = pd_canvas_pixel_at(des, des_rect.x, des_rect.y + y); - for (x = 0; x < des_rect.width; ++x) { - pd_over_pixel(px_des, px_src, src->opacity); - ++px_src; - ++px_des; - } - } + int x, y; + pd_color_t *px_src, *px_des; + + for (y = 0; y < des_rect.height; ++y) { + px_src = pd_canvas_pixel_at(src, src_x, src_y + y); + px_des = pd_canvas_pixel_at(des, des_rect.x, des_rect.y + y); + for (x = 0; x < des_rect.width; ++x) { + pd_over_pixel(px_des, px_src, src->opacity); + ++px_src; + ++px_des; + } + } } static void pd_canvas_mix_argb(pd_canvas_t *dest, pd_rect_t des_rect, - const pd_canvas_t *src, int src_x, int src_y) + const pd_canvas_t *src, int src_x, int src_y) { - int x, y; - uint8_t a; - pd_color_t *px_src, *px_dest; - - for (y = 0; y < des_rect.height; ++y) { - px_src = pd_canvas_pixel_at(src, src_x, src_y + y); - px_dest = pd_canvas_pixel_at(dest, des_rect.x, des_rect.y + y); - if (src->opacity < 1.0) { - for (x = 0; x < des_rect.width; ++x) { - a = (uint8_t)(px_src->a * src->opacity); - pd_blend_pixel(px_dest, px_src, a); - ++px_src; - ++px_dest; - } - continue; - } - for (x = 0; x < des_rect.width; ++x) { - pd_blend_pixel(px_dest, px_src, px_src->a); - ++px_src; - ++px_dest; - } - } + int x, y; + uint8_t a; + pd_color_t *px_src, *px_dest; + + for (y = 0; y < des_rect.height; ++y) { + px_src = pd_canvas_pixel_at(src, src_x, src_y + y); + px_dest = pd_canvas_pixel_at(dest, des_rect.x, des_rect.y + y); + if (src->opacity < 1.0) { + for (x = 0; x < des_rect.width; ++x) { + a = (uint8_t)(px_src->a * src->opacity); + pd_blend_pixel(px_dest, px_src, a); + ++px_src; + ++px_dest; + } + continue; + } + for (x = 0; x < des_rect.width; ++x) { + pd_blend_pixel(px_dest, px_src, px_src->a); + ++px_src; + ++px_dest; + } + } } static void pd_canvas_mix_argb2rgb(pd_canvas_t *des, pd_rect_t des_rect, - const pd_canvas_t *src, int src_x, int src_y) + const pd_canvas_t *src, int src_x, int src_y) { - int x, y; - uint8_t a; - pd_color_t *px, *px_row; - uint8_t *rowbytep, *bytep; - - /* 计算并保存第一行的首个像素的位置 */ - px_row = pd_canvas_pixel_at(src, src_x, src_y); - rowbytep = pd_canvas_pixel_at(des, des_rect.x, des_rect.y); - if (src->opacity < 1.0) { - goto mix_with_opacity; - } - for (y = 0; y < des_rect.height; ++y) { - px = px_row; - bytep = rowbytep; - for (x = 0; x < des_rect.width; ++x, ++px) { - *bytep = _pd_alpha_blend(*bytep, px->b, px->a); - ++bytep; - *bytep = _pd_alpha_blend(*bytep, px->g, px->a); - ++bytep; - *bytep = _pd_alpha_blend(*bytep, px->r, px->a); - ++bytep; - } - rowbytep += des->bytes_per_row; - px_row += src->width; - } - return; + int x, y; + uint8_t a; + pd_color_t *px, *px_row; + uint8_t *rowbytep, *bytep; + + /* 计算并保存第一行的首个像素的位置 */ + px_row = pd_canvas_pixel_at(src, src_x, src_y); + rowbytep = pd_canvas_pixel_at(des, des_rect.x, des_rect.y); + if (src->opacity < 1.0) { + goto mix_with_opacity; + } + for (y = 0; y < des_rect.height; ++y) { + px = px_row; + bytep = rowbytep; + for (x = 0; x < des_rect.width; ++x, ++px) { + *bytep = _pd_alpha_blend(*bytep, px->b, px->a); + ++bytep; + *bytep = _pd_alpha_blend(*bytep, px->g, px->a); + ++bytep; + *bytep = _pd_alpha_blend(*bytep, px->r, px->a); + ++bytep; + } + rowbytep += des->bytes_per_row; + px_row += src->width; + } + return; mix_with_opacity: - for (y = 0; y < des_rect.height; ++y) { - px = px_row; - bytep = rowbytep; - for (x = 0; x < des_rect.width; ++x, ++px) { - a = (uint8_t)(px->a * src->opacity); - *bytep = _pd_alpha_blend(*bytep, px->b, a); - ++bytep; - *bytep = _pd_alpha_blend(*bytep, px->g, a); - ++bytep; - *bytep = _pd_alpha_blend(*bytep, px->r, a); - ++bytep; - } - rowbytep += des->bytes_per_row; - px_row += src->width; - } + for (y = 0; y < des_rect.height; ++y) { + px = px_row; + bytep = rowbytep; + for (x = 0; x < des_rect.width; ++x, ++px) { + a = (uint8_t)(px->a * src->opacity); + *bytep = _pd_alpha_blend(*bytep, px->b, a); + ++bytep; + *bytep = _pd_alpha_blend(*bytep, px->g, a); + ++bytep; + *bytep = _pd_alpha_blend(*bytep, px->r, a); + ++bytep; + } + rowbytep += des->bytes_per_row; + px_row += src->width; + } } int pd_canvas_mix(pd_canvas_t *back, const pd_canvas_t *fore, int left, int top, - bool with_alpha) + bool with_alpha) { - pd_canvas_t w_slot; - pd_rect_t r_rect, w_rect; - - if (!pd_canvas_is_valid(back) || !pd_canvas_is_valid(fore)) { - return -1; - } - w_rect.x = left; - w_rect.y = top; - w_rect.width = fore->width; - w_rect.height = fore->height; - r_rect = pd_rect_crop(&w_rect, back->width, back->height); - w_rect.x += r_rect.x; - w_rect.y += r_rect.y; - w_rect.width = r_rect.width; - w_rect.height = r_rect.height; - pd_canvas_quote(&w_slot, back, &w_rect); - /* 获取实际操作区域 */ - pd_canvas_get_quote_rect(&w_slot, &w_rect); - pd_canvas_get_quote_rect(fore, &r_rect); - if (w_rect.width <= 0 || w_rect.height <= 0 || r_rect.width <= 0 || - r_rect.height <= 0) { - return -2; - } - top = r_rect.y; - left = r_rect.x; - /* 获取引用的源图像 */ - fore = pd_canvas_get_quote_source_readonly(fore); - back = pd_canvas_get_quote_source(back); - switch (fore->color_type) { - case PD_COLOR_TYPE_RGB888: - pd_canvas_direct_replace(back, w_rect, fore, left, top); - return 0; - case PD_COLOR_TYPE_ARGB8888: - if (back->color_type == PD_COLOR_TYPE_RGB888) { - pd_canvas_mix_argb2rgb(back, w_rect, fore, left, top); - return 0; - } - if (!with_alpha) { - pd_canvas_mix_argb(back, w_rect, fore, left, top); - return 0; - } - pd_canvas_mix_argb_with_alpha(back, w_rect, fore, left, top); - return 0; - default: - break; - } - return -3; + pd_canvas_t w_slot; + pd_rect_t r_rect, w_rect; + + if (!pd_canvas_is_valid(back) || !pd_canvas_is_valid(fore)) { + return -1; + } + w_rect.x = left; + w_rect.y = top; + w_rect.width = fore->width; + w_rect.height = fore->height; + r_rect = pd_rect_crop(&w_rect, back->width, back->height); + w_rect.x += r_rect.x; + w_rect.y += r_rect.y; + w_rect.width = r_rect.width; + w_rect.height = r_rect.height; + pd_canvas_quote(&w_slot, back, &w_rect); + /* 获取实际操作区域 */ + pd_canvas_get_quote_rect(&w_slot, &w_rect); + pd_canvas_get_quote_rect(fore, &r_rect); + if (w_rect.width <= 0 || w_rect.height <= 0 || r_rect.width <= 0 || + r_rect.height <= 0) { + return -2; + } + top = r_rect.y; + left = r_rect.x; + /* 获取引用的源图像 */ + fore = pd_canvas_get_quote_source_readonly(fore); + back = pd_canvas_get_quote_source(back); + switch (fore->color_type) { + case PD_COLOR_TYPE_RGB888: + pd_canvas_direct_replace(back, w_rect, fore, left, top); + return 0; + case PD_COLOR_TYPE_ARGB8888: + if (back->color_type == PD_COLOR_TYPE_RGB888) { + pd_canvas_mix_argb2rgb(back, w_rect, fore, left, top); + return 0; + } + if (!with_alpha) { + pd_canvas_mix_argb(back, w_rect, fore, left, top); + return 0; + } + pd_canvas_mix_argb_with_alpha(back, w_rect, fore, left, top); + return 0; + default: + break; + } + return -3; } int pd_canvas_fill_rect(pd_canvas_t *canvas, pd_color_t color, pd_rect_t rect) { - int x, y; - unsigned char *p; - - if (pd_canvas_begin_writing(&canvas, &rect) != 0) { - return -1; - } - for (y = 0; y < rect.height; ++y) { - p = pd_canvas_pixel_at(canvas, rect.x, rect.y + y); - if (canvas->color_type == PD_COLOR_TYPE_ARGB8888) { - for (x = 0; x < rect.width; ++x, p += 4) { - *(pd_color_t *)p = color; - } - } else { - for (x = 0; x < rect.width; ++x) { - *p++ = color.b; - *p++ = color.g; - *p++ = color.r; - } - } - } - return 0; + int x, y; + unsigned char *p; + + if (pd_canvas_begin_writing(&canvas, &rect) != 0) { + return -1; + } + for (y = 0; y < rect.height; ++y) { + p = pd_canvas_pixel_at(canvas, rect.x, rect.y + y); + if (canvas->color_type == PD_COLOR_TYPE_ARGB8888) { + for (x = 0; x < rect.width; ++x, p += 4) { + *(pd_color_t *)p = color; + } + } else { + for (x = 0; x < rect.width; ++x) { + *p++ = color.b; + *p++ = color.g; + *p++ = color.r; + } + } + } + return 0; } diff --git a/lib/pandagl/src/context.c b/lib/pandagl/src/context.c index 67e07cd0a..2734894db 100644 --- a/lib/pandagl/src/context.c +++ b/lib/pandagl/src/context.c @@ -1,28 +1,31 @@ /* * lib/pandagl/src/context.c: -- The PandaGL drawing context * - * Copyright (c) 2022-2025, Liu chao All rights reserved. - * + * Copyright (c) 2022-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include #include -pd_context_t* pd_context_create(pd_canvas_t *canvas, pd_rect_t *rect) +pd_context_t *pd_context_create(pd_canvas_t *canvas, pd_rect_t *rect) { - pd_context_t* paint = (pd_context_t*)malloc(sizeof(pd_context_t)); - paint->rect = *rect; - paint->with_alpha = false; - pd_canvas_init(&paint->canvas); - pd_canvas_quote(&paint->canvas, canvas, &paint->rect); - return paint; + pd_context_t *paint = (pd_context_t *)malloc(sizeof(pd_context_t)); + paint->rect = *rect; + paint->with_alpha = false; + pd_canvas_init(&paint->canvas); + pd_canvas_quote(&paint->canvas, canvas, &paint->rect); + return paint; } -void pd_context_destroy(pd_context_t* paint) +void pd_context_destroy(pd_context_t *paint) { - free(paint); + free(paint); } diff --git a/lib/pandagl/src/file_reader.c b/lib/pandagl/src/file_reader.c index 5c98db43f..a26f176fd 100644 --- a/lib/pandagl/src/file_reader.c +++ b/lib/pandagl/src/file_reader.c @@ -1,12 +1,15 @@ /* * lib/pandagl/src/file_reader.c * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/pandagl/src/flip.c b/lib/pandagl/src/flip.c index 89d63931d..8e0d007b9 100644 --- a/lib/pandagl/src/flip.c +++ b/lib/pandagl/src/flip.c @@ -1,77 +1,80 @@ /* * lib/pandagl/src/flip.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include int pd_canvas_veri_flip(const pd_canvas_t *canvas, pd_canvas_t *buff) { - int y; - pd_rect_t rect; - uint8_t *byte_src, *byte_des; + int y; + pd_rect_t rect; + uint8_t *byte_src, *byte_des; - if (!pd_canvas_is_valid(canvas)) { - return -1; - } - pd_canvas_get_quote_rect(canvas, &rect); - canvas = pd_canvas_get_quote_source_readonly(canvas); - buff->opacity = canvas->opacity; - buff->color_type = canvas->color_type; - if (0 != pd_canvas_create(buff, rect.width, rect.height)) { - return -2; - } - byte_src = pd_canvas_pixel_at(canvas, rect.x, rect.y + rect.height - 1); - byte_des = buff->bytes; - for (y = 0; y < rect.height; ++y) { - memcpy(byte_des, byte_src, buff->bytes_per_row); - byte_src -= canvas->bytes_per_row; - byte_des += buff->bytes_per_row; - } - return 0; + if (!pd_canvas_is_valid(canvas)) { + return -1; + } + pd_canvas_get_quote_rect(canvas, &rect); + canvas = pd_canvas_get_quote_source_readonly(canvas); + buff->opacity = canvas->opacity; + buff->color_type = canvas->color_type; + if (0 != pd_canvas_create(buff, rect.width, rect.height)) { + return -2; + } + byte_src = pd_canvas_pixel_at(canvas, rect.x, rect.y + rect.height - 1); + byte_des = buff->bytes; + for (y = 0; y < rect.height; ++y) { + memcpy(byte_des, byte_src, buff->bytes_per_row); + byte_src -= canvas->bytes_per_row; + byte_des += buff->bytes_per_row; + } + return 0; } int pd_canvas_horiz_flip(const pd_canvas_t *canvas, pd_canvas_t *buff) { - int x, y; - pd_rect_t rect; - uint8_t *src, *dest; + int x, y; + pd_rect_t rect; + uint8_t *src, *dest; - if (!pd_canvas_is_valid(canvas)) { - return -1; - } - pd_canvas_get_quote_rect(canvas, &rect); - canvas = pd_canvas_get_quote_source_readonly(canvas); - buff->opacity = canvas->opacity; - buff->color_type = canvas->color_type; - if (0 != pd_canvas_create(buff, rect.width, rect.height)) { - return -2; - } - for (y = 0; y < rect.height; ++y) { - dest = pd_canvas_pixel_at(buff, y, 0); - src = pd_canvas_pixel_at(canvas, rect.y + y, - rect.x + rect.width - 1); - if (canvas->color_type == PD_COLOR_TYPE_ARGB) { - for (x = 0; x < rect.width; ++x) { - *(pd_color_t *)dest = *(pd_color_t *)src; - dest += canvas->bytes_per_pixel; - src -= canvas->bytes_per_pixel; - } - } else { - for (x = 0; x < rect.width; ++x) { - dest[0] = src[0]; - dest[1] = src[1]; - dest[2] = src[2]; - dest += canvas->bytes_per_pixel; - src -= canvas->bytes_per_pixel; - } - } - } - return 0; + if (!pd_canvas_is_valid(canvas)) { + return -1; + } + pd_canvas_get_quote_rect(canvas, &rect); + canvas = pd_canvas_get_quote_source_readonly(canvas); + buff->opacity = canvas->opacity; + buff->color_type = canvas->color_type; + if (0 != pd_canvas_create(buff, rect.width, rect.height)) { + return -2; + } + for (y = 0; y < rect.height; ++y) { + dest = pd_canvas_pixel_at(buff, y, 0); + src = pd_canvas_pixel_at(canvas, rect.y + y, + rect.x + rect.width - 1); + if (canvas->color_type == PD_COLOR_TYPE_ARGB) { + for (x = 0; x < rect.width; ++x) { + *(pd_color_t *)dest = *(pd_color_t *)src; + dest += canvas->bytes_per_pixel; + src -= canvas->bytes_per_pixel; + } + } else { + for (x = 0; x < rect.width; ++x) { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest += canvas->bytes_per_pixel; + src -= canvas->bytes_per_pixel; + } + } + } + return 0; } diff --git a/lib/pandagl/src/font/bitmap.c b/lib/pandagl/src/font/bitmap.c index 612c08a97..d97302e71 100644 --- a/lib/pandagl/src/font/bitmap.c +++ b/lib/pandagl/src/font/bitmap.c @@ -1,12 +1,15 @@ /* * lib/pandagl/src/font/bitmap.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -16,108 +19,108 @@ void pd_glyph_bitmap_init(pd_glyph_bitmap_t *bitmap) { - bitmap->rows = 0; - bitmap->width = 0; - bitmap->top = 0; - bitmap->left = 0; - bitmap->buffer = NULL; + bitmap->rows = 0; + bitmap->width = 0; + bitmap->top = 0; + bitmap->left = 0; + bitmap->buffer = NULL; } void pd_glyph_bitmap_destroy(pd_glyph_bitmap_t *bitmap) { - if (bitmap->buffer) { - free(bitmap->buffer); - } - pd_glyph_bitmap_init(bitmap); + if (bitmap->buffer) { + free(bitmap->buffer); + } + pd_glyph_bitmap_init(bitmap); } static void pd_canvas_mix_glyph_bitmap_argb(pd_canvas_t *graph, - pd_rect_t *write_rect, - const pd_glyph_bitmap_t *bmp, - pd_color_t color, - pd_rect_t *read_rect) + pd_rect_t *write_rect, + const pd_glyph_bitmap_t *bmp, + pd_color_t color, + pd_rect_t *read_rect) { - int x, y; - pd_color_t c; - pd_color_t *px, *px_row_des; - uint8_t *byte_ptr, *byte_row_ptr; + int x, y; + pd_color_t c; + pd_color_t *px, *px_row_des; + uint8_t *byte_ptr, *byte_row_ptr; - byte_row_ptr = bmp->buffer + read_rect->y * bmp->width; - px_row_des = graph->argb + write_rect->y * graph->width; - byte_row_ptr += read_rect->x; - px_row_des += write_rect->x; - for (y = 0; y < read_rect->height; ++y) { - px = px_row_des; - byte_ptr = byte_row_ptr; - for (x = 0; x < read_rect->width; ++x, ++byte_ptr, ++px) { - c = color; - c.alpha = (uint8_t)(*byte_ptr * color.alpha / 255.0); - pd_over_pixel(px, &c, 1.0); - } - px_row_des += graph->width; - byte_row_ptr += bmp->width; - } + byte_row_ptr = bmp->buffer + read_rect->y * bmp->width; + px_row_des = graph->argb + write_rect->y * graph->width; + byte_row_ptr += read_rect->x; + px_row_des += write_rect->x; + for (y = 0; y < read_rect->height; ++y) { + px = px_row_des; + byte_ptr = byte_row_ptr; + for (x = 0; x < read_rect->width; ++x, ++byte_ptr, ++px) { + c = color; + c.alpha = (uint8_t)(*byte_ptr * color.alpha / 255.0); + pd_over_pixel(px, &c, 1.0); + } + px_row_des += graph->width; + byte_row_ptr += bmp->width; + } } static void pd_canvas_mix_glyph_bitmap_rgb(pd_canvas_t *graph, - pd_rect_t *write_rect, - const pd_glyph_bitmap_t *bmp, - pd_color_t color, - pd_rect_t *read_rect) + pd_rect_t *write_rect, + const pd_glyph_bitmap_t *bmp, + pd_color_t color, + pd_rect_t *read_rect) { - int x, y; - uint8_t *byte_src, *byte_row_src, *byte_row_des, *byte_des, alpha; - byte_row_src = bmp->buffer + read_rect->y * bmp->width + read_rect->x; - byte_row_des = graph->bytes + write_rect->y * graph->bytes_per_row; - byte_row_des += write_rect->x * graph->bytes_per_pixel; - for (y = 0; y < read_rect->height; ++y) { - byte_src = byte_row_src; - byte_des = byte_row_des; - for (x = 0; x < read_rect->width; ++x) { - alpha = (uint8_t)(*byte_src * color.alpha / 255); - pd_alpha_blend(*byte_des, color.b, alpha); - ++byte_des; - pd_alpha_blend(*byte_des, color.g, alpha); - ++byte_des; - pd_alpha_blend(*byte_des, color.r, alpha); - ++byte_des; - ++byte_src; - } - byte_row_des += graph->bytes_per_row; - byte_row_src += bmp->width; - } + int x, y; + uint8_t *byte_src, *byte_row_src, *byte_row_des, *byte_des, alpha; + byte_row_src = bmp->buffer + read_rect->y * bmp->width + read_rect->x; + byte_row_des = graph->bytes + write_rect->y * graph->bytes_per_row; + byte_row_des += write_rect->x * graph->bytes_per_pixel; + for (y = 0; y < read_rect->height; ++y) { + byte_src = byte_row_src; + byte_des = byte_row_des; + for (x = 0; x < read_rect->width; ++x) { + alpha = (uint8_t)(*byte_src * color.alpha / 255); + pd_alpha_blend(*byte_des, color.b, alpha); + ++byte_des; + pd_alpha_blend(*byte_des, color.g, alpha); + ++byte_des; + pd_alpha_blend(*byte_des, color.r, alpha); + ++byte_des; + ++byte_src; + } + byte_row_des += graph->bytes_per_row; + byte_row_src += bmp->width; + } } int pd_canvas_mix_glyph_bitmap(pd_canvas_t *graph, pd_pos_t pos, - const pd_glyph_bitmap_t *bmp, pd_color_t color) + const pd_glyph_bitmap_t *bmp, pd_color_t color) { - pd_canvas_t write_slot; - pd_rect_t r_rect, w_rect; + pd_canvas_t write_slot; + pd_rect_t r_rect, w_rect; - if (pos.x > (int)graph->width || pos.y > (int)graph->height) { - return -2; - } - /* 获取写入区域 */ - w_rect.x = pos.x; - w_rect.y = pos.y; - w_rect.width = bmp->width; - w_rect.height = bmp->rows; - /* 获取需要裁剪的区域 */ - r_rect = pd_rect_crop(&w_rect, graph->width, graph->height); - w_rect.x += r_rect.x; - w_rect.y += r_rect.y; - w_rect.width = r_rect.width; - w_rect.height = r_rect.height; - pd_canvas_quote(&write_slot, graph, &w_rect); - pd_canvas_get_quote_rect(&write_slot, &w_rect); - /* 获取背景图引用的源图形 */ - graph = pd_canvas_get_quote_source(graph); - if (graph->color_type == PD_COLOR_TYPE_ARGB) { - pd_canvas_mix_glyph_bitmap_argb(graph, &w_rect, bmp, color, - &r_rect); - } else { - pd_canvas_mix_glyph_bitmap_rgb(graph, &w_rect, bmp, color, - &r_rect); - } - return 0; + if (pos.x > (int)graph->width || pos.y > (int)graph->height) { + return -2; + } + /* 获取写入区域 */ + w_rect.x = pos.x; + w_rect.y = pos.y; + w_rect.width = bmp->width; + w_rect.height = bmp->rows; + /* 获取需要裁剪的区域 */ + r_rect = pd_rect_crop(&w_rect, graph->width, graph->height); + w_rect.x += r_rect.x; + w_rect.y += r_rect.y; + w_rect.width = r_rect.width; + w_rect.height = r_rect.height; + pd_canvas_quote(&write_slot, graph, &w_rect); + pd_canvas_get_quote_rect(&write_slot, &w_rect); + /* 获取背景图引用的源图形 */ + graph = pd_canvas_get_quote_source(graph); + if (graph->color_type == PD_COLOR_TYPE_ARGB) { + pd_canvas_mix_glyph_bitmap_argb(graph, &w_rect, bmp, color, + &r_rect); + } else { + pd_canvas_mix_glyph_bitmap_rgb(graph, &w_rect, bmp, color, + &r_rect); + } + return 0; } diff --git a/lib/pandagl/src/font/bitmap.h b/lib/pandagl/src/font/bitmap.h index 45a8e2b77..404d6757e 100644 --- a/lib/pandagl/src/font/bitmap.h +++ b/lib/pandagl/src/font/bitmap.h @@ -1,7 +1,7 @@ /* * lib/pandagl/src/font/bitmap.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/pandagl/src/font/freetype.c b/lib/pandagl/src/font/freetype.c index 810a15e22..a4301b988 100644 --- a/lib/pandagl/src/font/freetype.c +++ b/lib/pandagl/src/font/freetype.c @@ -1,12 +1,15 @@ /* - * lib/pandagl/src/font/freetype.c: -- The FreeType font-engine support module. - * - * Copyright (c) 2018-2025, Liu chao All rights reserved. + * lib/pandagl/src/font/freetype.c: -- The FreeType font-engine support + * module. + * Copyright (c) 2018-2026, Liu chao All rights + * reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include @@ -26,184 +29,186 @@ #define LCUI_FONT_LOAD_FALGS (FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT) static struct { - FT_Library library; + FT_Library library; } freetype; static int pd_freetype_open(const char *filepath, pd_font_face_t ***outfonts) { - FT_Face face; - pd_font_face_t *font, **fonts; - int i, err, num_faces; - - err = FT_New_Face(freetype.library, filepath, -1, &face); - if (err) { - *outfonts = NULL; - return -1; - } - num_faces = face->num_faces; - FT_Done_Face(face); - if (num_faces < 1) { - return 0; - } - fonts = malloc(sizeof(pd_font_face_t *) * num_faces); - if (!fonts) { - return -ENOMEM; - } - for (i = 0; i < num_faces; ++i) { - err = FT_New_Face(freetype.library, filepath, i, &face); - if (err) { - fonts[i] = NULL; - continue; - } - FT_Select_Charmap(face, FT_ENCODING_UNICODE); - font = pd_font_face_create(face->family_name, face->style_name); - font->data = face; - fonts[i] = font; - } - *outfonts = fonts; - return num_faces; + FT_Face face; + pd_font_face_t *font, **fonts; + int i, err, num_faces; + + err = FT_New_Face(freetype.library, filepath, -1, &face); + if (err) { + *outfonts = NULL; + return -1; + } + num_faces = face->num_faces; + FT_Done_Face(face); + if (num_faces < 1) { + return 0; + } + fonts = malloc(sizeof(pd_font_face_t *) * num_faces); + if (!fonts) { + return -ENOMEM; + } + for (i = 0; i < num_faces; ++i) { + err = FT_New_Face(freetype.library, filepath, i, &face); + if (err) { + fonts[i] = NULL; + continue; + } + FT_Select_Charmap(face, FT_ENCODING_UNICODE); + font = pd_font_face_create(face->family_name, face->style_name); + font->data = face; + fonts[i] = font; + } + *outfonts = fonts; + return num_faces; } static void pd_freetype_close(void *face) { - FT_Done_Face(face); + FT_Done_Face(face); } /** 转换 FT_GlyphSlot 类型数据为 pd_glyph_bitmap_t */ static size_t convert_glyph(pd_glyph_bitmap_t *bmp, FT_GlyphSlot slot, int mode) { - int error; - size_t size; - FT_BitmapGlyph bitmap_glyph; - FT_Glyph glyph; - - /* 从字形槽中提取一个字形图像 - * 请注意,创建的FT_Glyph对象必须与FT_Done_Glyph成对使用 */ - error = FT_Get_Glyph(slot, &glyph); - if (error) { - return -1; - } - /*---------------------- 打印字体信息 -------------------------- - LOG(" width= %ld, met->height= %ld\n" - "horiBearingX = %ld, horiBearingY = %ld, horiAdvance = %ld\n" - "vertBearingX = %ld, vertBearingY = %ld, vertAdvance = %ld\n", - slot->metrics.width>>6, slot->metrics.height>>6, - slot->metrics.horiBearingX>>6, slot->metrics.horiBearingY>>6, - slot->metrics.horiAdvance>>6, slot->metrics.vertBearingX>>6, - slot->metrics.vertBearingY>>6, slot->metrics.vertAdvance>>6 ); - ------------------------------------------------------------*/ - if (glyph->format != FT_GLYPH_FORMAT_BITMAP) { - error = FT_Glyph_To_Bitmap(&glyph, mode, 0, 1); - if (error) { - return -1; - } - } - bitmap_glyph = (FT_BitmapGlyph)glyph; - /* - * FT_Glyph_Metrics结构体中保存字形度量,通过face->glyph->metrics结 - * 构访问,可得到字形的宽、高、左边界距、上边界距、水平跨距等等。 - * 注意:因为不是所有的字体都包含垂直度量,当FT_HAS_VERTICAL为假时, - * vertBearingX,vertBearingY和vertAdvance的值是不可靠的,目前暂不考虑 - * 此情况的处理。 - * */ - bmp->top = bitmap_glyph->top; - bmp->left = bitmap_glyph->left; - bmp->rows = bitmap_glyph->bitmap.rows; - bmp->width = bitmap_glyph->bitmap.width; - bmp->pitch = bmp->width * sizeof(uint8_t); - bmp->metrics.ascender = slot->face->size->metrics.ascender >> 6; - bmp->metrics.bbox_width = slot->face->size->metrics.max_advance >> 6; - bmp->metrics.bbox_height = slot->face->size->metrics.height >> 6; - bmp->metrics.hori_advance = slot->metrics.horiAdvance >> 6; /* 水平跨距 */ - bmp->metrics.vert_advance = slot->metrics.vertAdvance >> 6; /* 垂直跨距 */ - /* 分配内存,用于保存字体位图 */ - size = bmp->rows * bmp->pitch; - bmp->buffer = (uint8_t *)malloc(size); - if (!bmp->buffer) { - FT_Done_Glyph(glyph); - return -1; - } - - switch (bitmap_glyph->bitmap.pixel_mode) { - /* 8位灰度位图,直接拷贝 */ - case FT_PIXEL_MODE_GRAY: - memcpy(bmp->buffer, bitmap_glyph->bitmap.buffer, size); - break; - /* 单色点阵图,需要转换 */ - case FT_PIXEL_MODE_MONO: { - FT_Bitmap bitmap; - FT_Int x, y; - uint8_t *bit_ptr, *byte_ptr; - - FT_Bitmap_New(&bitmap); - /* 转换位图bitmap_glyph->bitmap至bitmap,1个像素占1个字节 */ - FT_Bitmap_Convert(freetype.library, &bitmap_glyph->bitmap, - &bitmap, 1); - bit_ptr = bitmap.buffer; - byte_ptr = bmp->buffer; - for (y = 0; y < bmp->rows; ++y) { - for (x = 0; x < bmp->width; ++x) { - *byte_ptr = *bit_ptr ? 255 : 0; - ++byte_ptr, ++bit_ptr; - } - } - FT_Bitmap_Done(freetype.library, &bitmap); - break; - } - /* 其它像素模式的位图,暂时先直接填充255,等需要时再完善 */ - default: - memset(bmp->buffer, 255, size); - break; - } - FT_Done_Glyph(glyph); - return size; + int error; + size_t size; + FT_BitmapGlyph bitmap_glyph; + FT_Glyph glyph; + + /* 从字形槽中提取一个字形图像 + * 请注意,创建的FT_Glyph对象必须与FT_Done_Glyph成对使用 */ + error = FT_Get_Glyph(slot, &glyph); + if (error) { + return -1; + } + /*---------------------- 打印字体信息 -------------------------- + LOG(" width= %ld, met->height= %ld\n" + "horiBearingX = %ld, horiBearingY = %ld, horiAdvance = %ld\n" + "vertBearingX = %ld, vertBearingY = %ld, vertAdvance = %ld\n", + slot->metrics.width>>6, slot->metrics.height>>6, + slot->metrics.horiBearingX>>6, slot->metrics.horiBearingY>>6, + slot->metrics.horiAdvance>>6, slot->metrics.vertBearingX>>6, + slot->metrics.vertBearingY>>6, slot->metrics.vertAdvance>>6 ); + ------------------------------------------------------------*/ + if (glyph->format != FT_GLYPH_FORMAT_BITMAP) { + error = FT_Glyph_To_Bitmap(&glyph, mode, 0, 1); + if (error) { + return -1; + } + } + bitmap_glyph = (FT_BitmapGlyph)glyph; + /* + * FT_Glyph_Metrics结构体中保存字形度量,通过face->glyph->metrics结 + * 构访问,可得到字形的宽、高、左边界距、上边界距、水平跨距等等。 + * 注意:因为不是所有的字体都包含垂直度量,当FT_HAS_VERTICAL为假时, + * vertBearingX,vertBearingY和vertAdvance的值是不可靠的,目前暂不考虑 + * 此情况的处理。 + * */ + bmp->top = bitmap_glyph->top; + bmp->left = bitmap_glyph->left; + bmp->rows = bitmap_glyph->bitmap.rows; + bmp->width = bitmap_glyph->bitmap.width; + bmp->pitch = bmp->width * sizeof(uint8_t); + bmp->metrics.ascender = slot->face->size->metrics.ascender >> 6; + bmp->metrics.bbox_width = slot->face->size->metrics.max_advance >> 6; + bmp->metrics.bbox_height = slot->face->size->metrics.height >> 6; + bmp->metrics.hori_advance = + slot->metrics.horiAdvance >> 6; /* 水平跨距 */ + bmp->metrics.vert_advance = + slot->metrics.vertAdvance >> 6; /* 垂直跨距 */ + /* 分配内存,用于保存字体位图 */ + size = bmp->rows * bmp->pitch; + bmp->buffer = (uint8_t *)malloc(size); + if (!bmp->buffer) { + FT_Done_Glyph(glyph); + return -1; + } + + switch (bitmap_glyph->bitmap.pixel_mode) { + /* 8位灰度位图,直接拷贝 */ + case FT_PIXEL_MODE_GRAY: + memcpy(bmp->buffer, bitmap_glyph->bitmap.buffer, size); + break; + /* 单色点阵图,需要转换 */ + case FT_PIXEL_MODE_MONO: { + FT_Bitmap bitmap; + FT_Int x, y; + uint8_t *bit_ptr, *byte_ptr; + + FT_Bitmap_New(&bitmap); + /* 转换位图bitmap_glyph->bitmap至bitmap,1个像素占1个字节 */ + FT_Bitmap_Convert(freetype.library, &bitmap_glyph->bitmap, + &bitmap, 1); + bit_ptr = bitmap.buffer; + byte_ptr = bmp->buffer; + for (y = 0; y < bmp->rows; ++y) { + for (x = 0; x < bmp->width; ++x) { + *byte_ptr = *bit_ptr ? 255 : 0; + ++byte_ptr, ++bit_ptr; + } + } + FT_Bitmap_Done(freetype.library, &bitmap); + break; + } + /* 其它像素模式的位图,暂时先直接填充255,等需要时再完善 */ + default: + memset(bmp->buffer, 255, size); + break; + } + FT_Done_Glyph(glyph); + return size; } static int pd_freetype_render(pd_glyph_bitmap_t *bmp, unsigned ch, - int pixel_size, pd_font_face_t *font) + int pixel_size, pd_font_face_t *font) { - int ret = 0; - FT_UInt index; - FT_Face ft_face = (FT_Face)font->data; - - /* 设定字体尺寸 */ - FT_Set_Pixel_Sizes(ft_face, 0, pixel_size); - index = FT_Get_Char_Index(ft_face, ch); - if (index == 0) { - ret = -1; - } - /* 载入该字的字形数据 */ - if (FT_Load_Glyph(ft_face, index, LCUI_FONT_LOAD_FALGS) != 0) { - return -2; - } - convert_glyph(bmp, ft_face->glyph, LCUI_FONT_RENDER_MODE); - return ret; + int ret = 0; + FT_UInt index; + FT_Face ft_face = (FT_Face)font->data; + + /* 设定字体尺寸 */ + FT_Set_Pixel_Sizes(ft_face, 0, pixel_size); + index = FT_Get_Char_Index(ft_face, ch); + if (index == 0) { + ret = -1; + } + /* 载入该字的字形数据 */ + if (FT_Load_Glyph(ft_face, index, LCUI_FONT_LOAD_FALGS) != 0) { + return -2; + } + convert_glyph(bmp, ft_face->glyph, LCUI_FONT_RENDER_MODE); + return ret; } static unsigned pd_freetype_get_glyph_index(pd_font_face_t *font, unsigned ch) { - FT_Face ft_face = (FT_Face)font->data; + FT_Face ft_face = (FT_Face)font->data; - return FT_Get_Char_Index(ft_face, ch); + return FT_Get_Char_Index(ft_face, ch); } int pd_freetype_engine_init(pd_font_engine_t *engine) { - if (FT_Init_FreeType(&freetype.library)) { - return -1; - } - strcpy(engine->name, "FreeType"); - engine->render = pd_freetype_render; - engine->open = pd_freetype_open; - engine->close = pd_freetype_close; - engine->get_glyph_index = pd_freetype_get_glyph_index; - return 0; + if (FT_Init_FreeType(&freetype.library)) { + return -1; + } + strcpy(engine->name, "FreeType"); + engine->render = pd_freetype_render; + engine->open = pd_freetype_open; + engine->close = pd_freetype_close; + engine->get_glyph_index = pd_freetype_get_glyph_index; + return 0; } int pd_freetype_engine_destroy(void) { - FT_Done_FreeType(freetype.library); - return 0; + FT_Done_FreeType(freetype.library); + return 0; } #endif diff --git a/lib/pandagl/src/font/freetype.h b/lib/pandagl/src/font/freetype.h index 5e62de03e..931ec62db 100644 --- a/lib/pandagl/src/font/freetype.h +++ b/lib/pandagl/src/font/freetype.h @@ -1,7 +1,7 @@ /* * lib/pandagl/src/font/freetype.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/pandagl/src/font/inconsolata.c b/lib/pandagl/src/font/inconsolata.c index e9b3cdf0a..468656ed3 100644 --- a/lib/pandagl/src/font/inconsolata.c +++ b/lib/pandagl/src/font/inconsolata.c @@ -1,12 +1,15 @@ /* * lib/pandagl/src/font/inconsolata.c: bitmap data of the inconsolata font. * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ // TODO: 删除此文件,可考虑由 lcui-cli 提供字体位图到 C 源码的生成功能 @@ -16,7637 +19,5048 @@ #include enum font_index { - SIZE_12_PX, - SIZE_13_PX, - SIZE_14_PX, - SIZE_15_PX, - SIZE_16_PX, - SIZE_17_PX, - SIZE_18_PX, - SIZE_TOTAL + SIZE_12_PX, + SIZE_13_PX, + SIZE_14_PX, + SIZE_15_PX, + SIZE_16_PX, + SIZE_17_PX, + SIZE_18_PX, + SIZE_TOTAL }; /* inconsolata 字体数据索引 */ -static const pd_glyph_bitmap_t pd_inconsolata_font_bitmap_info[SIZE_TOTAL][95] = { - { - { 16, 0, 0, 0, 0, (uint8_t*)0x00000000, { 6, 12 } }, - { 11, 1, 3, 9, 9, (uint8_t*)0x00000000, { 6, 12 } }, - { 11, 1, 4, 3, 3, (uint8_t*)0x0000001B, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x00000027, { 6, 12 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x00000057, { 6, 12 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x0000008D, { 6, 12 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x000000C3, { 6, 12 } }, - { 11, 2, 2, 3, 3, (uint8_t*)0x000000F9, { 6, 12 } }, - { 11, 2, 3, 10, 10, (uint8_t*)0x000000FF, { 6, 12 } }, - { 11, 0, 3, 10, 10, (uint8_t*)0x0000011D, { 6, 12 } }, - { 10, 0, 6, 6, 6, (uint8_t*)0x0000013B, { 6, 12 } }, - { 10, 0, 6, 6, 6, (uint8_t*)0x0000015F, { 6, 12 } }, - { 5, 1, 3, 4, 4, (uint8_t*)0x00000183, { 6, 12 } }, - { 8, 0, 6, 2, 2, (uint8_t*)0x0000018F, { 6, 12 } }, - { 5, 1, 3, 3, 3, (uint8_t*)0x0000019B, { 6, 12 } }, - { 11, 3, 3, 9, 9, (uint8_t*)0x000001A4, { 6, 12 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x000001BF, { 6, 12 } }, - { 11, 0, 4, 8, 8, (uint8_t*)0x000001F5, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x00000215, { 6, 12 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x00000245, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x0000027B, { 6, 12 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x000002AB, { 6, 12 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x000002E1, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x00000317, { 6, 12 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x00000347, { 6, 12 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x0000037D, { 6, 12 } }, - { 8, 1, 3, 6, 6, (uint8_t*)0x000003B3, { 6, 12 } }, - { 8, 1, 3, 7, 7, (uint8_t*)0x000003C5, { 6, 12 } }, - { 10, 2, 4, 7, 7, (uint8_t*)0x000003DA, { 6, 12 } }, - { 9, 0, 6, 4, 4, (uint8_t*)0x000003F6, { 6, 12 } }, - { 10, 0, 4, 7, 7, (uint8_t*)0x0000040E, { 6, 12 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x0000042A, { 6, 12 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x00000460, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x00000496, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x000004C6, { 6, 12 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x000004F6, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x0000052C, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x0000055C, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x0000058C, { 6, 12 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x000005BC, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x000005F2, { 6, 12 } }, - { 11, 0, 5, 8, 8, (uint8_t*)0x00000622, { 6, 12 } }, - { 11, 1, 5, 9, 9, (uint8_t*)0x0000064A, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x00000677, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x000006A7, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x000006D7, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x00000707, { 6, 12 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x00000737, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x0000076D, { 6, 12 } }, - { 11, 0, 6, 10, 10, (uint8_t*)0x0000079D, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x000007D9, { 6, 12 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x00000809, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x0000083F, { 6, 12 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x0000086F, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x000008A5, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x000008D5, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x00000905, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x00000935, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x00000965, { 6, 12 } }, - { 11, 1, 5, 9, 9, (uint8_t*)0x00000995, { 6, 12 } }, - { 11, 0, 3, 9, 9, (uint8_t*)0x000009C2, { 6, 12 } }, - { 11, 0, 5, 9, 9, (uint8_t*)0x000009DD, { 6, 12 } }, - { 11, 0, 5, 4, 4, (uint8_t*)0x00000A0A, { 6, 12 } }, - { 16, 0, 6, 0, 0, (uint8_t*)0x00000A1E, { 6, 12 } }, - { 11, 1, 3, 3, 3, (uint8_t*)0x00000A1E, { 6, 12 } }, - { 9, 0, 6, 7, 7, (uint8_t*)0x00000A27, { 6, 12 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x00000A51, { 6, 12 } }, - { 9, 0, 6, 7, 7, (uint8_t*)0x00000A87, { 6, 12 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x00000AB1, { 6, 12 } }, - { 9, 0, 6, 7, 7, (uint8_t*)0x00000AE7, { 6, 12 } }, - { 11, 1, 5, 8, 8, (uint8_t*)0x00000B11, { 6, 12 } }, - { 9, 0, 6, 8, 8, (uint8_t*)0x00000B39, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x00000B69, { 6, 12 } }, - { 11, 0, 5, 8, 8, (uint8_t*)0x00000B99, { 6, 12 } }, - { 11, 0, 5, 10, 10, (uint8_t*)0x00000BC1, { 6, 12 } }, - { 11, 0, 6, 8, 8, (uint8_t*)0x00000BF3, { 6, 12 } }, - { 11, 0, 5, 8, 8, (uint8_t*)0x00000C23, { 6, 12 } }, - { 9, 0, 6, 6, 6, (uint8_t*)0x00000C4B, { 6, 12 } }, - { 9, 0, 6, 6, 6, (uint8_t*)0x00000C6F, { 6, 12 } }, - { 9, 0, 6, 7, 7, (uint8_t*)0x00000C93, { 6, 12 } }, - { 9, 0, 6, 8, 8, (uint8_t*)0x00000CBD, { 6, 12 } }, - { 9, 0, 6, 8, 8, (uint8_t*)0x00000CED, { 6, 12 } }, - { 9, 0, 6, 6, 6, (uint8_t*)0x00000D1D, { 6, 12 } }, - { 9, 0, 6, 7, 7, (uint8_t*)0x00000D41, { 6, 12 } }, - { 11, 0, 5, 9, 9, (uint8_t*)0x00000D6B, { 6, 12 } }, - { 9, 0, 6, 7, 7, (uint8_t*)0x00000D98, { 6, 12 } }, - { 9, 0, 6, 6, 6, (uint8_t*)0x00000DC2, { 6, 12 } }, - { 9, 0, 6, 6, 6, (uint8_t*)0x00000DE6, { 6, 12 } }, - { 9, 0, 6, 6, 6, (uint8_t*)0x00000E0A, { 6, 12 } }, - { 9, 0, 6, 8, 8, (uint8_t*)0x00000E2E, { 6, 12 } }, - { 9, 0, 6, 6, 6, (uint8_t*)0x00000E5E, { 6, 12 } }, - { 11, 1, 4, 10, 10, (uint8_t*)0x00000E82, { 6, 12 } }, - { 11, 2, 2, 10, 10, (uint8_t*)0x00000EAA, { 6, 12 } }, - { 11, 0, 4, 10, 10, (uint8_t*)0x00000EBE, { 6, 12 } }, - { 9, 0, 6, 3, 3, (uint8_t*)0x00000EE6, { 6, 12 } } - }, { - { 16, 0, 0, 0, 0, (uint8_t*)0x00000000, { 7, 13 } }, - { 11, 2, 2, 10, 10, (uint8_t*)0x00000000, { 7, 13 } }, - { 11, 1, 5, 4, 4, (uint8_t*)0x00000014, { 7, 13 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000028, { 7, 13 } }, - { 11, 0, 6, 10, 10, (uint8_t*)0x00000067, { 7, 13 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x000000A3, { 7, 13 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x000000E9, { 7, 13 } }, - { 11, 2, 3, 4, 4, (uint8_t*)0x0000012F, { 7, 13 } }, - { 11, 2, 4, 12, 12, (uint8_t*)0x0000013B, { 7, 13 } }, - { 11, 0, 4, 12, 12, (uint8_t*)0x0000016B, { 7, 13 } }, - { 9, 0, 6, 6, 6, (uint8_t*)0x0000019B, { 7, 13 } }, - { 9, 0, 7, 6, 6, (uint8_t*)0x000001BF, { 7, 13 } }, - { 4, 1, 3, 5, 5, (uint8_t*)0x000001E9, { 7, 13 } }, - { 7, 0, 6, 2, 2, (uint8_t*)0x000001F8, { 7, 13 } }, - { 4, 2, 2, 3, 3, (uint8_t*)0x00000204, { 7, 13 } }, - { 11, 3, 3, 10, 10, (uint8_t*)0x0000020A, { 7, 13 } }, - { 11, 0, 6, 10, 10, (uint8_t*)0x00000228, { 7, 13 } }, - { 11, 0, 4, 9, 9, (uint8_t*)0x00000264, { 7, 13 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x00000288, { 7, 13 } }, - { 11, 0, 6, 10, 10, (uint8_t*)0x000002BE, { 7, 13 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x000002FA, { 7, 13 } }, - { 11, 0, 6, 10, 10, (uint8_t*)0x00000330, { 7, 13 } }, - { 11, 0, 6, 10, 10, (uint8_t*)0x0000036C, { 7, 13 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x000003A8, { 7, 13 } }, - { 11, 0, 6, 10, 10, (uint8_t*)0x000003DE, { 7, 13 } }, - { 11, 0, 6, 10, 10, (uint8_t*)0x0000041A, { 7, 13 } }, - { 8, 2, 2, 7, 7, (uint8_t*)0x00000456, { 7, 13 } }, - { 8, 1, 3, 9, 9, (uint8_t*)0x00000464, { 7, 13 } }, - { 10, 1, 5, 8, 8, (uint8_t*)0x0000047F, { 7, 13 } }, - { 8, 0, 7, 4, 4, (uint8_t*)0x000004A7, { 7, 13 } }, - { 10, 2, 5, 8, 8, (uint8_t*)0x000004C3, { 7, 13 } }, - { 11, 0, 6, 10, 10, (uint8_t*)0x000004EB, { 7, 13 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x00000527, { 7, 13 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x0000056D, { 7, 13 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x000005AC, { 7, 13 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x000005E2, { 7, 13 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000628, { 7, 13 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x00000667, { 7, 13 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x0000069D, { 7, 13 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x000006D3, { 7, 13 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x00000719, { 7, 13 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x0000074F, { 7, 13 } }, - { 11, 1, 6, 10, 10, (uint8_t*)0x00000785, { 7, 13 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x000007C1, { 7, 13 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x00000800, { 7, 13 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000836, { 7, 13 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x00000875, { 7, 13 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x000008AB, { 7, 13 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x000008F1, { 7, 13 } }, - { 11, 0, 7, 11, 11, (uint8_t*)0x00000930, { 7, 13 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x0000097D, { 7, 13 } }, - { 11, 0, 6, 10, 10, (uint8_t*)0x000009B3, { 7, 13 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x000009EF, { 7, 13 } }, - { 11, 0, 6, 10, 10, (uint8_t*)0x00000A2E, { 7, 13 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000A6A, { 7, 13 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000AA9, { 7, 13 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x00000AE8, { 7, 13 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000B1E, { 7, 13 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x00000B5D, { 7, 13 } }, - { 11, 1, 5, 11, 11, (uint8_t*)0x00000B93, { 7, 13 } }, - { 11, 0, 3, 10, 10, (uint8_t*)0x00000BCA, { 7, 13 } }, - { 11, 0, 5, 11, 11, (uint8_t*)0x00000BE8, { 7, 13 } }, - { 11, 0, 6, 5, 5, (uint8_t*)0x00000C1F, { 7, 13 } }, - { 16, 0, 6, 0, 0, (uint8_t*)0x00000C3D, { 7, 13 } }, - { 11, 1, 3, 4, 4, (uint8_t*)0x00000C3D, { 7, 13 } }, - { 8, 0, 6, 7, 7, (uint8_t*)0x00000C49, { 7, 13 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x00000C73, { 7, 13 } }, - { 8, 0, 7, 7, 7, (uint8_t*)0x00000CB9, { 7, 13 } }, - { 11, 0, 6, 10, 10, (uint8_t*)0x00000CEA, { 7, 13 } }, - { 8, 0, 6, 7, 7, (uint8_t*)0x00000D26, { 7, 13 } }, - { 11, 1, 6, 9, 9, (uint8_t*)0x00000D50, { 7, 13 } }, - { 9, 0, 7, 10, 10, (uint8_t*)0x00000D86, { 7, 13 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x00000DCC, { 7, 13 } }, - { 11, 1, 5, 9, 9, (uint8_t*)0x00000E02, { 7, 13 } }, - { 11, 0, 5, 12, 12, (uint8_t*)0x00000E2F, { 7, 13 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000E6B, { 7, 13 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x00000EAA, { 7, 13 } }, - { 8, 0, 7, 6, 6, (uint8_t*)0x00000EE0, { 7, 13 } }, - { 8, 0, 6, 6, 6, (uint8_t*)0x00000F0A, { 7, 13 } }, - { 8, 0, 7, 7, 7, (uint8_t*)0x00000F2E, { 7, 13 } }, - { 8, 0, 7, 9, 9, (uint8_t*)0x00000F5F, { 7, 13 } }, - { 8, 0, 6, 9, 9, (uint8_t*)0x00000F9E, { 7, 13 } }, - { 8, 1, 5, 6, 6, (uint8_t*)0x00000FD4, { 7, 13 } }, - { 8, 0, 6, 7, 7, (uint8_t*)0x00000FF2, { 7, 13 } }, - { 10, 0, 6, 9, 9, (uint8_t*)0x0000101C, { 7, 13 } }, - { 8, 0, 6, 7, 7, (uint8_t*)0x00001052, { 7, 13 } }, - { 8, 0, 7, 6, 6, (uint8_t*)0x0000107C, { 7, 13 } }, - { 8, 0, 7, 6, 6, (uint8_t*)0x000010A6, { 7, 13 } }, - { 8, 0, 6, 6, 6, (uint8_t*)0x000010D0, { 7, 13 } }, - { 8, 0, 7, 9, 9, (uint8_t*)0x000010F4, { 7, 13 } }, - { 8, 0, 6, 6, 6, (uint8_t*)0x00001133, { 7, 13 } }, - { 11, 2, 4, 11, 11, (uint8_t*)0x00001157, { 7, 13 } }, - { 11, 2, 2, 11, 11, (uint8_t*)0x00001183, { 7, 13 } }, - { 11, 0, 5, 11, 11, (uint8_t*)0x00001199, { 7, 13 } }, - { 8, 0, 7, 2, 2, (uint8_t*)0x000011D0, { 7, 13 } } - }, { - { 16, 0, 0, 0, 0, (uint8_t*)0x00000000, { 7, 14 } }, - { 12, 2, 3, 11, 11, (uint8_t*)0x00000000, { 7, 14 } }, - { 12, 1, 5, 5, 5, (uint8_t*)0x00000021, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x0000003A, { 7, 14 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x00000079, { 7, 14 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x000000C6, { 7, 14 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x0000010C, { 7, 14 } }, - { 12, 2, 3, 5, 5, (uint8_t*)0x00000152, { 7, 14 } }, - { 12, 3, 3, 13, 13, (uint8_t*)0x00000161, { 7, 14 } }, - { 12, 0, 4, 13, 13, (uint8_t*)0x00000188, { 7, 14 } }, - { 10, 0, 7, 7, 7, (uint8_t*)0x000001BC, { 7, 14 } }, - { 10, 0, 7, 7, 7, (uint8_t*)0x000001ED, { 7, 14 } }, - { 4, 2, 3, 5, 5, (uint8_t*)0x0000021E, { 7, 14 } }, - { 16, 0, 6, 0, 0, (uint8_t*)0x0000022D, { 7, 14 } }, - { 4, 2, 3, 3, 3, (uint8_t*)0x0000022D, { 7, 14 } }, - { 12, 4, 3, 11, 11, (uint8_t*)0x00000236, { 7, 14 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x00000257, { 7, 14 } }, - { 11, 0, 5, 9, 9, (uint8_t*)0x0000029D, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x000002CA, { 7, 14 } }, - { 11, 0, 6, 10, 10, (uint8_t*)0x00000309, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000345, { 7, 14 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x00000384, { 7, 14 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x000003CA, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000410, { 7, 14 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x0000044F, { 7, 14 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x00000495, { 7, 14 } }, - { 8, 2, 3, 7, 7, (uint8_t*)0x000004DB, { 7, 14 } }, - { 8, 2, 3, 9, 9, (uint8_t*)0x000004F0, { 7, 14 } }, - { 10, 2, 5, 8, 8, (uint8_t*)0x0000050B, { 7, 14 } }, - { 9, 0, 7, 5, 5, (uint8_t*)0x00000533, { 7, 14 } }, - { 10, 0, 5, 8, 8, (uint8_t*)0x00000556, { 7, 14 } }, - { 12, 0, 6, 11, 11, (uint8_t*)0x0000057E, { 7, 14 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x000005C0, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000606, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000645, { 7, 14 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x00000684, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x000006CA, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000709, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000748, { 7, 14 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x00000787, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x000007CD, { 7, 14 } }, - { 11, 0, 6, 9, 9, (uint8_t*)0x0000080C, { 7, 14 } }, - { 11, 0, 6, 10, 10, (uint8_t*)0x00000842, { 7, 14 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x0000087E, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x000008C4, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000903, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000942, { 7, 14 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x00000981, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x000009C7, { 7, 14 } }, - { 11, 0, 7, 11, 11, (uint8_t*)0x00000A06, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000A53, { 7, 14 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x00000A92, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000AD8, { 7, 14 } }, - { 11, 0, 7, 10, 10, (uint8_t*)0x00000B17, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000B5D, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000B9C, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000BDB, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000C1A, { 7, 14 } }, - { 11, 0, 7, 9, 9, (uint8_t*)0x00000C59, { 7, 14 } }, - { 12, 1, 5, 12, 12, (uint8_t*)0x00000C98, { 7, 14 } }, - { 12, 0, 3, 11, 11, (uint8_t*)0x00000CD4, { 7, 14 } }, - { 12, 0, 6, 12, 12, (uint8_t*)0x00000CF5, { 7, 14 } }, - { 11, 1, 5, 5, 5, (uint8_t*)0x00000D3D, { 7, 14 } }, - { 2, 0, 7, 2, 2, (uint8_t*)0x00000D56, { 7, 14 } }, - { 12, 1, 3, 4, 4, (uint8_t*)0x00000D64, { 7, 14 } }, - { 9, 0, 7, 8, 8, (uint8_t*)0x00000D70, { 7, 14 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x00000DA8, { 7, 14 } }, - { 9, 0, 7, 8, 8, (uint8_t*)0x00000DF5, { 7, 14 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x00000E2D, { 7, 14 } }, - { 9, 0, 7, 8, 8, (uint8_t*)0x00000E7A, { 7, 14 } }, - { 12, 0, 6, 10, 10, (uint8_t*)0x00000EB2, { 7, 14 } }, - { 9, 0, 7, 10, 10, (uint8_t*)0x00000EEE, { 7, 14 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x00000F34, { 7, 14 } }, - { 12, 1, 5, 10, 10, (uint8_t*)0x00000F7A, { 7, 14 } }, - { 12, 0, 6, 13, 13, (uint8_t*)0x00000FAC, { 7, 14 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x00000FFA, { 7, 14 } }, - { 12, 0, 6, 10, 10, (uint8_t*)0x00001040, { 7, 14 } }, - { 9, 0, 7, 7, 7, (uint8_t*)0x0000107C, { 7, 14 } }, - { 9, 0, 7, 7, 7, (uint8_t*)0x000010AD, { 7, 14 } }, - { 9, 0, 7, 8, 8, (uint8_t*)0x000010DE, { 7, 14 } }, - { 9, 0, 7, 10, 10, (uint8_t*)0x00001116, { 7, 14 } }, - { 9, 0, 7, 10, 10, (uint8_t*)0x0000115C, { 7, 14 } }, - { 9, 1, 6, 7, 7, (uint8_t*)0x000011A2, { 7, 14 } }, - { 9, 0, 7, 8, 8, (uint8_t*)0x000011CC, { 7, 14 } }, - { 11, 0, 6, 10, 10, (uint8_t*)0x00001204, { 7, 14 } }, - { 9, 0, 7, 8, 8, (uint8_t*)0x00001240, { 7, 14 } }, - { 9, 0, 7, 7, 7, (uint8_t*)0x00001278, { 7, 14 } }, - { 9, 0, 7, 7, 7, (uint8_t*)0x000012A9, { 7, 14 } }, - { 9, 0, 7, 7, 7, (uint8_t*)0x000012DA, { 7, 14 } }, - { 9, 0, 7, 10, 10, (uint8_t*)0x0000130B, { 7, 14 } }, - { 9, 0, 7, 7, 7, (uint8_t*)0x00001351, { 7, 14 } }, - { 11, 2, 4, 12, 12, (uint8_t*)0x00001382, { 7, 14 } }, - { 12, 2, 3, 13, 13, (uint8_t*)0x000013B2, { 7, 14 } }, - { 11, 1, 4, 12, 12, (uint8_t*)0x000013D9, { 7, 14 } }, - { 9, 0, 7, 3, 3, (uint8_t*)0x00001409, { 7, 14 } } - }, { - { 17, 0, 0, 0, 0, (uint8_t*)0x00000000, { 8, 15 } }, - { 12, 2, 3, 11, 11, (uint8_t*)0x00000000, { 8, 15 } }, - { 12, 1, 5, 4, 4, (uint8_t*)0x00000021, { 8, 15 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000035, { 8, 15 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x00000085, { 8, 15 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x000000D2, { 8, 15 } }, - { 12, 0, 8, 11, 11, (uint8_t*)0x0000011F, { 8, 15 } }, - { 12, 2, 3, 4, 4, (uint8_t*)0x00000177, { 8, 15 } }, - { 12, 2, 4, 13, 13, (uint8_t*)0x00000183, { 8, 15 } }, - { 12, 1, 4, 13, 13, (uint8_t*)0x000001B7, { 8, 15 } }, - { 10, 0, 7, 7, 7, (uint8_t*)0x000001EB, { 8, 15 } }, - { 10, 0, 7, 7, 7, (uint8_t*)0x0000021C, { 8, 15 } }, - { 4, 2, 3, 5, 5, (uint8_t*)0x0000024D, { 8, 15 } }, - { 8, 0, 7, 2, 2, (uint8_t*)0x0000025C, { 8, 15 } }, - { 4, 2, 3, 3, 3, (uint8_t*)0x0000026A, { 8, 15 } }, - { 12, 4, 3, 11, 11, (uint8_t*)0x00000273, { 8, 15 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x00000294, { 8, 15 } }, - { 12, 1, 4, 10, 10, (uint8_t*)0x000002E1, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x00000309, { 8, 15 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x0000034F, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x0000039C, { 8, 15 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x000003E2, { 8, 15 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x0000042F, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x0000047C, { 8, 15 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x000004C2, { 8, 15 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x0000050F, { 8, 15 } }, - { 9, 2, 3, 8, 8, (uint8_t*)0x0000055C, { 8, 15 } }, - { 9, 2, 3, 10, 10, (uint8_t*)0x00000574, { 8, 15 } }, - { 11, 2, 5, 9, 9, (uint8_t*)0x00000592, { 8, 15 } }, - { 9, 0, 7, 5, 5, (uint8_t*)0x000005BF, { 8, 15 } }, - { 11, 1, 5, 9, 9, (uint8_t*)0x000005E2, { 8, 15 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x0000060F, { 8, 15 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x0000065C, { 8, 15 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x000006A9, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x000006F9, { 8, 15 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x0000073F, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x0000078C, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x000007D2, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x00000818, { 8, 15 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x0000085E, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x000008AB, { 8, 15 } }, - { 12, 0, 6, 10, 10, (uint8_t*)0x000008F1, { 8, 15 } }, - { 12, 0, 6, 11, 11, (uint8_t*)0x0000092D, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x0000096F, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x000009B5, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x000009FB, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x00000A41, { 8, 15 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x00000A87, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x00000AD4, { 8, 15 } }, - { 12, 0, 7, 13, 13, (uint8_t*)0x00000B1A, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x00000B75, { 8, 15 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x00000BBB, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x00000C08, { 8, 15 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x00000C4E, { 8, 15 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000C9B, { 8, 15 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000CEB, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x00000D3B, { 8, 15 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000D81, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x00000DD1, { 8, 15 } }, - { 12, 1, 6, 12, 12, (uint8_t*)0x00000E17, { 8, 15 } }, - { 12, 0, 3, 11, 11, (uint8_t*)0x00000E5F, { 8, 15 } }, - { 12, 0, 6, 12, 12, (uint8_t*)0x00000E80, { 8, 15 } }, - { 12, 1, 5, 5, 5, (uint8_t*)0x00000EC8, { 8, 15 } }, - { 2, 0, 7, 2, 2, (uint8_t*)0x00000EE1, { 8, 15 } }, - { 12, 1, 3, 4, 4, (uint8_t*)0x00000EEF, { 8, 15 } }, - { 9, 0, 7, 8, 8, (uint8_t*)0x00000EFB, { 8, 15 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x00000F33, { 8, 15 } }, - { 9, 0, 7, 8, 8, (uint8_t*)0x00000F80, { 8, 15 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x00000FB8, { 8, 15 } }, - { 9, 0, 7, 8, 8, (uint8_t*)0x00001005, { 8, 15 } }, - { 12, 2, 6, 10, 10, (uint8_t*)0x0000103D, { 8, 15 } }, - { 9, 1, 7, 10, 10, (uint8_t*)0x00001079, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x000010BF, { 8, 15 } }, - { 12, 1, 5, 10, 10, (uint8_t*)0x00001105, { 8, 15 } }, - { 12, 0, 6, 13, 13, (uint8_t*)0x00001137, { 8, 15 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00001185, { 8, 15 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x000011D5, { 8, 15 } }, - { 9, 0, 7, 7, 7, (uint8_t*)0x0000121B, { 8, 15 } }, - { 9, 0, 7, 7, 7, (uint8_t*)0x0000124C, { 8, 15 } }, - { 9, 0, 7, 8, 8, (uint8_t*)0x0000127D, { 8, 15 } }, - { 9, 0, 7, 10, 10, (uint8_t*)0x000012B5, { 8, 15 } }, - { 9, 0, 7, 10, 10, (uint8_t*)0x000012FB, { 8, 15 } }, - { 9, 1, 6, 7, 7, (uint8_t*)0x00001341, { 8, 15 } }, - { 9, 0, 7, 8, 8, (uint8_t*)0x0000136B, { 8, 15 } }, - { 11, 0, 6, 10, 10, (uint8_t*)0x000013A3, { 8, 15 } }, - { 9, 0, 7, 8, 8, (uint8_t*)0x000013DF, { 8, 15 } }, - { 9, 0, 7, 7, 7, (uint8_t*)0x00001417, { 8, 15 } }, - { 9, 0, 8, 7, 7, (uint8_t*)0x00001448, { 8, 15 } }, - { 9, 0, 7, 7, 7, (uint8_t*)0x00001480, { 8, 15 } }, - { 9, 0, 7, 10, 10, (uint8_t*)0x000014B1, { 8, 15 } }, - { 9, 0, 7, 7, 7, (uint8_t*)0x000014F7, { 8, 15 } }, - { 12, 2, 5, 13, 13, (uint8_t*)0x00001528, { 8, 15 } }, - { 12, 2, 3, 13, 13, (uint8_t*)0x00001569, { 8, 15 } }, - { 12, 1, 4, 13, 13, (uint8_t*)0x00001590, { 8, 15 } }, - { 9, 0, 8, 3, 3, (uint8_t*)0x000015C4, { 8, 15 } } - }, { - { 19, 0, 0, 0, 0, (uint8_t*)0x00000000, { 8, 16 } }, - { 13, 2, 3, 12, 12, (uint8_t*)0x00000000, { 8, 16 } }, - { 13, 1, 6, 5, 5, (uint8_t*)0x00000024, { 8, 16 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000042, { 8, 16 } }, - { 13, 0, 8, 12, 12, (uint8_t*)0x00000092, { 8, 16 } }, - { 13, 0, 8, 12, 12, (uint8_t*)0x000000F2, { 8, 16 } }, - { 12, 0, 8, 11, 11, (uint8_t*)0x00000152, { 8, 16 } }, - { 13, 3, 3, 5, 5, (uint8_t*)0x000001AA, { 8, 16 } }, - { 13, 3, 4, 14, 14, (uint8_t*)0x000001B9, { 8, 16 } }, - { 13, 0, 4, 14, 14, (uint8_t*)0x000001F1, { 8, 16 } }, - { 11, 0, 8, 8, 8, (uint8_t*)0x00000229, { 8, 16 } }, - { 11, 0, 8, 8, 8, (uint8_t*)0x00000269, { 8, 16 } }, - { 4, 2, 3, 5, 5, (uint8_t*)0x000002A9, { 8, 16 } }, - { 8, 0, 7, 2, 2, (uint8_t*)0x000002B8, { 8, 16 } }, - { 4, 2, 3, 3, 3, (uint8_t*)0x000002C6, { 8, 16 } }, - { 13, 4, 3, 12, 12, (uint8_t*)0x000002CF, { 8, 16 } }, - { 12, 0, 8, 11, 11, (uint8_t*)0x000002F3, { 8, 16 } }, - { 12, 1, 4, 10, 10, (uint8_t*)0x0000034B, { 8, 16 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x00000373, { 8, 16 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x000003B9, { 8, 16 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000406, { 8, 16 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x00000456, { 8, 16 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x000004A3, { 8, 16 } }, - { 12, 1, 6, 10, 10, (uint8_t*)0x000004F0, { 8, 16 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x0000052C, { 8, 16 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x00000579, { 8, 16 } }, - { 9, 2, 3, 8, 8, (uint8_t*)0x000005C6, { 8, 16 } }, - { 9, 2, 3, 10, 10, (uint8_t*)0x000005DE, { 8, 16 } }, - { 11, 3, 5, 9, 9, (uint8_t*)0x000005FC, { 8, 16 } }, - { 9, 0, 8, 5, 5, (uint8_t*)0x00000629, { 8, 16 } }, - { 11, 0, 5, 9, 9, (uint8_t*)0x00000651, { 8, 16 } }, - { 13, 0, 7, 12, 12, (uint8_t*)0x0000067E, { 8, 16 } }, - { 13, 0, 8, 12, 12, (uint8_t*)0x000006D2, { 8, 16 } }, - { 13, 0, 8, 11, 11, (uint8_t*)0x00000732, { 8, 16 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x0000078A, { 8, 16 } }, - { 12, 0, 8, 11, 11, (uint8_t*)0x000007DA, { 8, 16 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000832, { 8, 16 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x00000882, { 8, 16 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x000008C8, { 8, 16 } }, - { 12, 0, 8, 11, 11, (uint8_t*)0x0000090E, { 8, 16 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000966, { 8, 16 } }, - { 12, 1, 6, 10, 10, (uint8_t*)0x000009B6, { 8, 16 } }, - { 12, 2, 6, 11, 11, (uint8_t*)0x000009F2, { 8, 16 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000A34, { 8, 16 } }, - { 12, 0, 7, 10, 10, (uint8_t*)0x00000A84, { 8, 16 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000ACA, { 8, 16 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000B1A, { 8, 16 } }, - { 12, 0, 8, 11, 11, (uint8_t*)0x00000B6A, { 8, 16 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000BC2, { 8, 16 } }, - { 12, 0, 8, 13, 13, (uint8_t*)0x00000C12, { 8, 16 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000C7A, { 8, 16 } }, - { 12, 0, 8, 11, 11, (uint8_t*)0x00000CCA, { 8, 16 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000D22, { 8, 16 } }, - { 12, 0, 8, 11, 11, (uint8_t*)0x00000D72, { 8, 16 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000DCA, { 8, 16 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000E1A, { 8, 16 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000E6A, { 8, 16 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000EBA, { 8, 16 } }, - { 12, 0, 8, 10, 10, (uint8_t*)0x00000F0A, { 8, 16 } }, - { 13, 1, 6, 13, 13, (uint8_t*)0x00000F5A, { 8, 16 } }, - { 13, 0, 3, 12, 12, (uint8_t*)0x00000FA8, { 8, 16 } }, - { 13, 1, 5, 13, 13, (uint8_t*)0x00000FCC, { 8, 16 } }, - { 12, 1, 6, 5, 5, (uint8_t*)0x0000100D, { 8, 16 } }, - { 2, 0, 8, 2, 2, (uint8_t*)0x0000102B, { 8, 16 } }, - { 13, 1, 3, 4, 4, (uint8_t*)0x0000103B, { 8, 16 } }, - { 10, 0, 7, 9, 9, (uint8_t*)0x00001047, { 8, 16 } }, - { 13, 0, 8, 12, 12, (uint8_t*)0x00001086, { 8, 16 } }, - { 10, 0, 8, 9, 9, (uint8_t*)0x000010E6, { 8, 16 } }, - { 13, 0, 7, 12, 12, (uint8_t*)0x0000112E, { 8, 16 } }, - { 10, 0, 8, 9, 9, (uint8_t*)0x00001182, { 8, 16 } }, - { 13, 0, 7, 11, 11, (uint8_t*)0x000011CA, { 8, 16 } }, - { 10, 0, 8, 11, 11, (uint8_t*)0x00001217, { 8, 16 } }, - { 13, 0, 7, 11, 11, (uint8_t*)0x0000126F, { 8, 16 } }, - { 13, 1, 6, 11, 11, (uint8_t*)0x000012BC, { 8, 16 } }, - { 13, 0, 6, 14, 14, (uint8_t*)0x000012FE, { 8, 16 } }, - { 13, 0, 8, 11, 11, (uint8_t*)0x00001352, { 8, 16 } }, - { 13, 1, 6, 11, 11, (uint8_t*)0x000013AA, { 8, 16 } }, - { 10, 0, 8, 8, 8, (uint8_t*)0x000013EC, { 8, 16 } }, - { 10, 0, 7, 8, 8, (uint8_t*)0x0000142C, { 8, 16 } }, - { 10, 0, 8, 9, 9, (uint8_t*)0x00001464, { 8, 16 } }, - { 10, 0, 8, 11, 11, (uint8_t*)0x000014AC, { 8, 16 } }, - { 10, 0, 7, 11, 11, (uint8_t*)0x00001504, { 8, 16 } }, - { 10, 1, 7, 8, 8, (uint8_t*)0x00001551, { 8, 16 } }, - { 10, 0, 7, 9, 9, (uint8_t*)0x00001589, { 8, 16 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x000015C8, { 8, 16 } }, - { 10, 0, 7, 9, 9, (uint8_t*)0x00001615, { 8, 16 } }, - { 10, 0, 8, 8, 8, (uint8_t*)0x00001654, { 8, 16 } }, - { 10, 0, 8, 8, 8, (uint8_t*)0x00001694, { 8, 16 } }, - { 10, 0, 8, 8, 8, (uint8_t*)0x000016D4, { 8, 16 } }, - { 10, 0, 8, 11, 11, (uint8_t*)0x00001714, { 8, 16 } }, - { 10, 0, 8, 8, 8, (uint8_t*)0x0000176C, { 8, 16 } }, - { 13, 2, 5, 14, 14, (uint8_t*)0x000017AC, { 8, 16 } }, - { 13, 3, 2, 14, 14, (uint8_t*)0x000017F2, { 8, 16 } }, - { 13, 1, 5, 14, 14, (uint8_t*)0x0000180E, { 8, 16 } }, - { 10, 0, 8, 3, 3, (uint8_t*)0x00001854, { 8, 16 } } - }, { - { 20, 0, 0, 0, 0, (uint8_t*)0x00000000, { 9, 17 } }, - { 14, 2, 3, 13, 13, (uint8_t*)0x00000000, { 9, 17 } }, - { 14, 1, 6, 5, 5, (uint8_t*)0x00000027, { 9, 17 } }, - { 13, 0, 9, 11, 11, (uint8_t*)0x00000045, { 9, 17 } }, - { 14, 0, 8, 13, 13, (uint8_t*)0x000000A8, { 9, 17 } }, - { 13, 0, 8, 12, 12, (uint8_t*)0x00000110, { 9, 17 } }, - { 13, 0, 9, 12, 12, (uint8_t*)0x00000170, { 9, 17 } }, - { 14, 3, 3, 5, 5, (uint8_t*)0x000001DC, { 9, 17 } }, - { 14, 4, 4, 15, 15, (uint8_t*)0x000001EB, { 9, 17 } }, - { 14, 1, 4, 15, 15, (uint8_t*)0x00000227, { 9, 17 } }, - { 11, 0, 8, 8, 8, (uint8_t*)0x00000263, { 9, 17 } }, - { 11, 0, 8, 8, 8, (uint8_t*)0x000002A3, { 9, 17 } }, - { 4, 2, 4, 5, 5, (uint8_t*)0x000002E3, { 9, 17 } }, - { 8, 0, 8, 2, 2, (uint8_t*)0x000002F7, { 9, 17 } }, - { 4, 2, 3, 3, 3, (uint8_t*)0x00000307, { 9, 17 } }, - { 14, 5, 3, 13, 13, (uint8_t*)0x00000310, { 9, 17 } }, - { 13, 0, 8, 12, 12, (uint8_t*)0x00000337, { 9, 17 } }, - { 13, 1, 5, 11, 11, (uint8_t*)0x00000397, { 9, 17 } }, - { 13, 0, 8, 11, 11, (uint8_t*)0x000003CE, { 9, 17 } }, - { 13, 0, 7, 12, 12, (uint8_t*)0x00000426, { 9, 17 } }, - { 13, 0, 8, 11, 11, (uint8_t*)0x0000047A, { 9, 17 } }, - { 13, 0, 8, 12, 12, (uint8_t*)0x000004D2, { 9, 17 } }, - { 13, 0, 8, 12, 12, (uint8_t*)0x00000532, { 9, 17 } }, - { 13, 1, 7, 11, 11, (uint8_t*)0x00000592, { 9, 17 } }, - { 13, 0, 8, 12, 12, (uint8_t*)0x000005DF, { 9, 17 } }, - { 13, 0, 8, 12, 12, (uint8_t*)0x0000063F, { 9, 17 } }, - { 10, 2, 3, 9, 9, (uint8_t*)0x0000069F, { 9, 17 } }, - { 10, 2, 4, 11, 11, (uint8_t*)0x000006BA, { 9, 17 } }, - { 12, 2, 5, 10, 10, (uint8_t*)0x000006E6, { 9, 17 } }, - { 10, 0, 8, 6, 6, (uint8_t*)0x00000718, { 9, 17 } }, - { 12, 1, 5, 10, 10, (uint8_t*)0x00000748, { 9, 17 } }, - { 14, 0, 8, 13, 13, (uint8_t*)0x0000077A, { 9, 17 } }, - { 13, 0, 8, 12, 12, (uint8_t*)0x000007E2, { 9, 17 } }, - { 13, 0, 9, 12, 12, (uint8_t*)0x00000842, { 9, 17 } }, - { 13, 0, 8, 11, 11, (uint8_t*)0x000008AE, { 9, 17 } }, - { 13, 0, 8, 12, 12, (uint8_t*)0x00000906, { 9, 17 } }, - { 13, 0, 8, 11, 11, (uint8_t*)0x00000966, { 9, 17 } }, - { 13, 0, 8, 11, 11, (uint8_t*)0x000009BE, { 9, 17 } }, - { 13, 1, 7, 11, 11, (uint8_t*)0x00000A16, { 9, 17 } }, - { 13, 0, 8, 12, 12, (uint8_t*)0x00000A63, { 9, 17 } }, - { 13, 0, 8, 11, 11, (uint8_t*)0x00000AC3, { 9, 17 } }, - { 13, 1, 6, 11, 11, (uint8_t*)0x00000B1B, { 9, 17 } }, - { 13, 2, 6, 12, 12, (uint8_t*)0x00000B5D, { 9, 17 } }, - { 13, 0, 8, 11, 11, (uint8_t*)0x00000BA5, { 9, 17 } }, - { 13, 0, 8, 11, 11, (uint8_t*)0x00000BFD, { 9, 17 } }, - { 13, 0, 8, 11, 11, (uint8_t*)0x00000C55, { 9, 17 } }, - { 13, 0, 8, 11, 11, (uint8_t*)0x00000CAD, { 9, 17 } }, - { 13, 0, 8, 12, 12, (uint8_t*)0x00000D05, { 9, 17 } }, - { 13, 0, 8, 11, 11, (uint8_t*)0x00000D65, { 9, 17 } }, - { 13, 0, 8, 14, 14, (uint8_t*)0x00000DBD, { 9, 17 } }, - { 13, 0, 8, 11, 11, (uint8_t*)0x00000E2D, { 9, 17 } }, - { 13, 0, 8, 12, 12, (uint8_t*)0x00000E85, { 9, 17 } }, - { 13, 0, 8, 11, 11, (uint8_t*)0x00000EE5, { 9, 17 } }, - { 13, 0, 8, 12, 12, (uint8_t*)0x00000F3D, { 9, 17 } }, - { 13, 0, 9, 11, 11, (uint8_t*)0x00000F9D, { 9, 17 } }, - { 13, 0, 9, 11, 11, (uint8_t*)0x00001000, { 9, 17 } }, - { 13, 0, 8, 11, 11, (uint8_t*)0x00001063, { 9, 17 } }, - { 13, 0, 8, 11, 11, (uint8_t*)0x000010BB, { 9, 17 } }, - { 13, 0, 8, 11, 11, (uint8_t*)0x00001113, { 9, 17 } }, - { 14, 1, 7, 14, 14, (uint8_t*)0x0000116B, { 9, 17 } }, - { 14, 0, 3, 13, 13, (uint8_t*)0x000011CD, { 9, 17 } }, - { 14, 1, 6, 14, 14, (uint8_t*)0x000011F4, { 9, 17 } }, - { 13, 1, 6, 6, 6, (uint8_t*)0x00001248, { 9, 17 } }, - { 2, 0, 8, 2, 2, (uint8_t*)0x0000126C, { 9, 17 } }, - { 14, 2, 4, 5, 5, (uint8_t*)0x0000127C, { 9, 17 } }, - { 10, 0, 8, 9, 9, (uint8_t*)0x00001290, { 9, 17 } }, - { 14, 0, 8, 13, 13, (uint8_t*)0x000012D8, { 9, 17 } }, - { 10, 0, 8, 9, 9, (uint8_t*)0x00001340, { 9, 17 } }, - { 14, 0, 8, 13, 13, (uint8_t*)0x00001388, { 9, 17 } }, - { 10, 0, 8, 9, 9, (uint8_t*)0x000013F0, { 9, 17 } }, - { 14, 2, 7, 12, 12, (uint8_t*)0x00001438, { 9, 17 } }, - { 10, 0, 8, 11, 11, (uint8_t*)0x0000148C, { 9, 17 } }, - { 14, 0, 8, 12, 12, (uint8_t*)0x000014E4, { 9, 17 } }, - { 14, 1, 6, 12, 12, (uint8_t*)0x00001544, { 9, 17 } }, - { 14, 1, 6, 15, 15, (uint8_t*)0x0000158C, { 9, 17 } }, - { 14, 0, 9, 12, 12, (uint8_t*)0x000015E6, { 9, 17 } }, - { 14, 1, 7, 12, 12, (uint8_t*)0x00001652, { 9, 17 } }, - { 10, 0, 8, 8, 8, (uint8_t*)0x000016A6, { 9, 17 } }, - { 10, 0, 8, 8, 8, (uint8_t*)0x000016E6, { 9, 17 } }, - { 10, 0, 8, 9, 9, (uint8_t*)0x00001726, { 9, 17 } }, - { 10, 0, 8, 11, 11, (uint8_t*)0x0000176E, { 9, 17 } }, - { 10, 0, 8, 11, 11, (uint8_t*)0x000017C6, { 9, 17 } }, - { 10, 1, 7, 8, 8, (uint8_t*)0x0000181E, { 9, 17 } }, - { 10, 0, 8, 9, 9, (uint8_t*)0x00001856, { 9, 17 } }, - { 12, 0, 7, 11, 11, (uint8_t*)0x0000189E, { 9, 17 } }, - { 10, 0, 8, 9, 9, (uint8_t*)0x000018EB, { 9, 17 } }, - { 10, 0, 8, 8, 8, (uint8_t*)0x00001933, { 9, 17 } }, - { 10, 0, 9, 8, 8, (uint8_t*)0x00001973, { 9, 17 } }, - { 10, 0, 8, 8, 8, (uint8_t*)0x000019BB, { 9, 17 } }, - { 10, 0, 8, 11, 11, (uint8_t*)0x000019FB, { 9, 17 } }, - { 10, 0, 8, 8, 8, (uint8_t*)0x00001A53, { 9, 17 } }, - { 13, 2, 5, 14, 14, (uint8_t*)0x00001A93, { 9, 17 } }, - { 13, 3, 2, 14, 14, (uint8_t*)0x00001AD9, { 9, 17 } }, - { 13, 1, 5, 14, 14, (uint8_t*)0x00001AF5, { 9, 17 } }, - { 10, 1, 8, 3, 3, (uint8_t*)0x00001B3B, { 9, 17 } } - }, { - { 20, 0, 0, 0, 0, (uint8_t*)0x00000000, { 9, 18 } }, - { 14, 2, 4, 13, 13, (uint8_t*)0x00000000, { 9, 18 } }, - { 14, 2, 6, 5, 5, (uint8_t*)0x00000034, { 9, 18 } }, - { 14, 0, 9, 12, 12, (uint8_t*)0x00000052, { 9, 18 } }, - { 14, 1, 8, 13, 13, (uint8_t*)0x000000BE, { 9, 18 } }, - { 14, 0, 9, 13, 13, (uint8_t*)0x00000126, { 9, 18 } }, - { 14, 0, 9, 13, 13, (uint8_t*)0x0000019B, { 9, 18 } }, - { 14, 3, 3, 5, 5, (uint8_t*)0x00000210, { 9, 18 } }, - { 14, 4, 4, 16, 16, (uint8_t*)0x0000021F, { 9, 18 } }, - { 14, 1, 4, 16, 16, (uint8_t*)0x0000025F, { 9, 18 } }, - { 12, 0, 9, 8, 8, (uint8_t*)0x0000029F, { 9, 18 } }, - { 12, 0, 9, 9, 9, (uint8_t*)0x000002E7, { 9, 18 } }, - { 4, 2, 4, 5, 5, (uint8_t*)0x00000338, { 9, 18 } }, - { 9, 1, 7, 2, 2, (uint8_t*)0x0000034C, { 9, 18 } }, - { 4, 2, 4, 3, 3, (uint8_t*)0x0000035A, { 9, 18 } }, - { 14, 5, 3, 13, 13, (uint8_t*)0x00000366, { 9, 18 } }, - { 14, 0, 9, 13, 13, (uint8_t*)0x0000038D, { 9, 18 } }, - { 14, 1, 5, 12, 12, (uint8_t*)0x00000402, { 9, 18 } }, - { 14, 1, 7, 12, 12, (uint8_t*)0x0000043E, { 9, 18 } }, - { 14, 0, 8, 13, 13, (uint8_t*)0x00000492, { 9, 18 } }, - { 14, 0, 9, 12, 12, (uint8_t*)0x000004FA, { 9, 18 } }, - { 14, 0, 8, 13, 13, (uint8_t*)0x00000566, { 9, 18 } }, - { 14, 0, 8, 13, 13, (uint8_t*)0x000005CE, { 9, 18 } }, - { 14, 1, 7, 12, 12, (uint8_t*)0x00000636, { 9, 18 } }, - { 14, 0, 8, 13, 13, (uint8_t*)0x0000068A, { 9, 18 } }, - { 14, 0, 8, 13, 13, (uint8_t*)0x000006F2, { 9, 18 } }, - { 10, 2, 4, 9, 9, (uint8_t*)0x0000075A, { 9, 18 } }, - { 10, 2, 4, 11, 11, (uint8_t*)0x0000077E, { 9, 18 } }, - { 13, 3, 6, 11, 11, (uint8_t*)0x000007AA, { 9, 18 } }, - { 10, 0, 9, 5, 5, (uint8_t*)0x000007EC, { 9, 18 } }, - { 13, 0, 5, 11, 11, (uint8_t*)0x00000819, { 9, 18 } }, - { 14, 0, 8, 13, 13, (uint8_t*)0x00000850, { 9, 18 } }, - { 14, 0, 9, 13, 13, (uint8_t*)0x000008B8, { 9, 18 } }, - { 14, 0, 9, 12, 12, (uint8_t*)0x0000092D, { 9, 18 } }, - { 14, 0, 9, 12, 12, (uint8_t*)0x00000999, { 9, 18 } }, - { 14, 1, 8, 13, 13, (uint8_t*)0x00000A05, { 9, 18 } }, - { 14, 0, 9, 12, 12, (uint8_t*)0x00000A6D, { 9, 18 } }, - { 14, 0, 8, 12, 12, (uint8_t*)0x00000AD9, { 9, 18 } }, - { 14, 1, 7, 12, 12, (uint8_t*)0x00000B39, { 9, 18 } }, - { 14, 0, 9, 13, 13, (uint8_t*)0x00000B8D, { 9, 18 } }, - { 14, 0, 8, 12, 12, (uint8_t*)0x00000C02, { 9, 18 } }, - { 14, 1, 7, 12, 12, (uint8_t*)0x00000C62, { 9, 18 } }, - { 14, 2, 7, 13, 13, (uint8_t*)0x00000CB6, { 9, 18 } }, - { 14, 0, 9, 12, 12, (uint8_t*)0x00000D11, { 9, 18 } }, - { 14, 0, 8, 12, 12, (uint8_t*)0x00000D7D, { 9, 18 } }, - { 14, 0, 9, 12, 12, (uint8_t*)0x00000DDD, { 9, 18 } }, - { 14, 0, 9, 12, 12, (uint8_t*)0x00000E49, { 9, 18 } }, - { 14, 0, 9, 13, 13, (uint8_t*)0x00000EB5, { 9, 18 } }, - { 14, 0, 9, 12, 12, (uint8_t*)0x00000F2A, { 9, 18 } }, - { 14, 0, 9, 15, 15, (uint8_t*)0x00000F96, { 9, 18 } }, - { 14, 0, 9, 12, 12, (uint8_t*)0x0000101D, { 9, 18 } }, - { 14, 1, 8, 13, 13, (uint8_t*)0x00001089, { 9, 18 } }, - { 14, 0, 9, 12, 12, (uint8_t*)0x000010F1, { 9, 18 } }, - { 14, 0, 9, 13, 13, (uint8_t*)0x0000115D, { 9, 18 } }, - { 14, 0, 9, 12, 12, (uint8_t*)0x000011D2, { 9, 18 } }, - { 14, 0, 9, 12, 12, (uint8_t*)0x0000123E, { 9, 18 } }, - { 14, 0, 9, 12, 12, (uint8_t*)0x000012AA, { 9, 18 } }, - { 14, 0, 9, 12, 12, (uint8_t*)0x00001316, { 9, 18 } }, - { 14, 0, 9, 12, 12, (uint8_t*)0x00001382, { 9, 18 } }, - { 14, 2, 6, 14, 14, (uint8_t*)0x000013EE, { 9, 18 } }, - { 14, 0, 3, 13, 13, (uint8_t*)0x00001442, { 9, 18 } }, - { 14, 1, 6, 14, 14, (uint8_t*)0x00001469, { 9, 18 } }, - { 14, 1, 7, 6, 6, (uint8_t*)0x000014BD, { 9, 18 } }, - { 2, 0, 9, 2, 2, (uint8_t*)0x000014E7, { 9, 18 } }, - { 14, 2, 4, 5, 5, (uint8_t*)0x000014F9, { 9, 18 } }, - { 11, 0, 8, 10, 10, (uint8_t*)0x0000150D, { 9, 18 } }, - { 14, 0, 9, 13, 13, (uint8_t*)0x0000155D, { 9, 18 } }, - { 11, 1, 8, 10, 10, (uint8_t*)0x000015D2, { 9, 18 } }, - { 14, 0, 8, 13, 13, (uint8_t*)0x00001622, { 9, 18 } }, - { 11, 0, 8, 10, 10, (uint8_t*)0x0000168A, { 9, 18 } }, - { 14, 2, 7, 12, 12, (uint8_t*)0x000016DA, { 9, 18 } }, - { 11, 0, 9, 12, 12, (uint8_t*)0x0000172E, { 9, 18 } }, - { 14, 1, 7, 12, 12, (uint8_t*)0x0000179A, { 9, 18 } }, - { 14, 1, 7, 12, 12, (uint8_t*)0x000017EE, { 9, 18 } }, - { 14, 0, 7, 16, 16, (uint8_t*)0x00001842, { 9, 18 } }, - { 14, 0, 9, 12, 12, (uint8_t*)0x000018B2, { 9, 18 } }, - { 14, 1, 7, 12, 12, (uint8_t*)0x0000191E, { 9, 18 } }, - { 11, 0, 9, 9, 9, (uint8_t*)0x00001972, { 9, 18 } }, - { 11, 0, 8, 9, 9, (uint8_t*)0x000019C3, { 9, 18 } }, - { 11, 0, 9, 10, 10, (uint8_t*)0x00001A0B, { 9, 18 } }, - { 11, 0, 9, 12, 12, (uint8_t*)0x00001A65, { 9, 18 } }, - { 11, 0, 8, 12, 12, (uint8_t*)0x00001AD1, { 9, 18 } }, - { 11, 1, 8, 9, 9, (uint8_t*)0x00001B31, { 9, 18 } }, - { 11, 0, 8, 10, 10, (uint8_t*)0x00001B79, { 9, 18 } }, - { 13, 1, 7, 12, 12, (uint8_t*)0x00001BC9, { 9, 18 } }, - { 11, 0, 8, 10, 10, (uint8_t*)0x00001C1D, { 9, 18 } }, - { 11, 0, 9, 9, 9, (uint8_t*)0x00001C6D, { 9, 18 } }, - { 11, 0, 9, 9, 9, (uint8_t*)0x00001CBE, { 9, 18 } }, - { 11, 0, 9, 9, 9, (uint8_t*)0x00001D0F, { 9, 18 } }, - { 11, 0, 9, 13, 13, (uint8_t*)0x00001D60, { 9, 18 } }, - { 11, 0, 9, 9, 9, (uint8_t*)0x00001DD5, { 9, 18 } }, - { 14, 2, 6, 15, 15, (uint8_t*)0x00001E26, { 9, 18 } }, - { 14, 3, 3, 15, 15, (uint8_t*)0x00001E80, { 9, 18 } }, - { 14, 1, 5, 15, 15, (uint8_t*)0x00001EAD, { 9, 18 } }, - { 11, 0, 9, 4, 4, (uint8_t*)0x00001EF8, { 9, 18 } } - } -}; +static const pd_glyph_bitmap_t + pd_inconsolata_font_bitmap_info[SIZE_TOTAL][95] = { + { { 16, 0, 0, 0, 0, (uint8_t *)0x00000000, { 6, 12 } }, + { 11, 1, 3, 9, 9, (uint8_t *)0x00000000, { 6, 12 } }, + { 11, 1, 4, 3, 3, (uint8_t *)0x0000001B, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x00000027, { 6, 12 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x00000057, { 6, 12 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x0000008D, { 6, 12 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x000000C3, { 6, 12 } }, + { 11, 2, 2, 3, 3, (uint8_t *)0x000000F9, { 6, 12 } }, + { 11, 2, 3, 10, 10, (uint8_t *)0x000000FF, { 6, 12 } }, + { 11, 0, 3, 10, 10, (uint8_t *)0x0000011D, { 6, 12 } }, + { 10, 0, 6, 6, 6, (uint8_t *)0x0000013B, { 6, 12 } }, + { 10, 0, 6, 6, 6, (uint8_t *)0x0000015F, { 6, 12 } }, + { 5, 1, 3, 4, 4, (uint8_t *)0x00000183, { 6, 12 } }, + { 8, 0, 6, 2, 2, (uint8_t *)0x0000018F, { 6, 12 } }, + { 5, 1, 3, 3, 3, (uint8_t *)0x0000019B, { 6, 12 } }, + { 11, 3, 3, 9, 9, (uint8_t *)0x000001A4, { 6, 12 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x000001BF, { 6, 12 } }, + { 11, 0, 4, 8, 8, (uint8_t *)0x000001F5, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x00000215, { 6, 12 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x00000245, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x0000027B, { 6, 12 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x000002AB, { 6, 12 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x000002E1, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x00000317, { 6, 12 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x00000347, { 6, 12 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x0000037D, { 6, 12 } }, + { 8, 1, 3, 6, 6, (uint8_t *)0x000003B3, { 6, 12 } }, + { 8, 1, 3, 7, 7, (uint8_t *)0x000003C5, { 6, 12 } }, + { 10, 2, 4, 7, 7, (uint8_t *)0x000003DA, { 6, 12 } }, + { 9, 0, 6, 4, 4, (uint8_t *)0x000003F6, { 6, 12 } }, + { 10, 0, 4, 7, 7, (uint8_t *)0x0000040E, { 6, 12 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x0000042A, { 6, 12 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x00000460, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x00000496, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x000004C6, { 6, 12 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x000004F6, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x0000052C, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x0000055C, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x0000058C, { 6, 12 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x000005BC, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x000005F2, { 6, 12 } }, + { 11, 0, 5, 8, 8, (uint8_t *)0x00000622, { 6, 12 } }, + { 11, 1, 5, 9, 9, (uint8_t *)0x0000064A, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x00000677, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x000006A7, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x000006D7, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x00000707, { 6, 12 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x00000737, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x0000076D, { 6, 12 } }, + { 11, 0, 6, 10, 10, (uint8_t *)0x0000079D, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x000007D9, { 6, 12 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x00000809, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x0000083F, { 6, 12 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x0000086F, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x000008A5, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x000008D5, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x00000905, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x00000935, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x00000965, { 6, 12 } }, + { 11, 1, 5, 9, 9, (uint8_t *)0x00000995, { 6, 12 } }, + { 11, 0, 3, 9, 9, (uint8_t *)0x000009C2, { 6, 12 } }, + { 11, 0, 5, 9, 9, (uint8_t *)0x000009DD, { 6, 12 } }, + { 11, 0, 5, 4, 4, (uint8_t *)0x00000A0A, { 6, 12 } }, + { 16, 0, 6, 0, 0, (uint8_t *)0x00000A1E, { 6, 12 } }, + { 11, 1, 3, 3, 3, (uint8_t *)0x00000A1E, { 6, 12 } }, + { 9, 0, 6, 7, 7, (uint8_t *)0x00000A27, { 6, 12 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x00000A51, { 6, 12 } }, + { 9, 0, 6, 7, 7, (uint8_t *)0x00000A87, { 6, 12 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x00000AB1, { 6, 12 } }, + { 9, 0, 6, 7, 7, (uint8_t *)0x00000AE7, { 6, 12 } }, + { 11, 1, 5, 8, 8, (uint8_t *)0x00000B11, { 6, 12 } }, + { 9, 0, 6, 8, 8, (uint8_t *)0x00000B39, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x00000B69, { 6, 12 } }, + { 11, 0, 5, 8, 8, (uint8_t *)0x00000B99, { 6, 12 } }, + { 11, 0, 5, 10, 10, (uint8_t *)0x00000BC1, { 6, 12 } }, + { 11, 0, 6, 8, 8, (uint8_t *)0x00000BF3, { 6, 12 } }, + { 11, 0, 5, 8, 8, (uint8_t *)0x00000C23, { 6, 12 } }, + { 9, 0, 6, 6, 6, (uint8_t *)0x00000C4B, { 6, 12 } }, + { 9, 0, 6, 6, 6, (uint8_t *)0x00000C6F, { 6, 12 } }, + { 9, 0, 6, 7, 7, (uint8_t *)0x00000C93, { 6, 12 } }, + { 9, 0, 6, 8, 8, (uint8_t *)0x00000CBD, { 6, 12 } }, + { 9, 0, 6, 8, 8, (uint8_t *)0x00000CED, { 6, 12 } }, + { 9, 0, 6, 6, 6, (uint8_t *)0x00000D1D, { 6, 12 } }, + { 9, 0, 6, 7, 7, (uint8_t *)0x00000D41, { 6, 12 } }, + { 11, 0, 5, 9, 9, (uint8_t *)0x00000D6B, { 6, 12 } }, + { 9, 0, 6, 7, 7, (uint8_t *)0x00000D98, { 6, 12 } }, + { 9, 0, 6, 6, 6, (uint8_t *)0x00000DC2, { 6, 12 } }, + { 9, 0, 6, 6, 6, (uint8_t *)0x00000DE6, { 6, 12 } }, + { 9, 0, 6, 6, 6, (uint8_t *)0x00000E0A, { 6, 12 } }, + { 9, 0, 6, 8, 8, (uint8_t *)0x00000E2E, { 6, 12 } }, + { 9, 0, 6, 6, 6, (uint8_t *)0x00000E5E, { 6, 12 } }, + { 11, 1, 4, 10, 10, (uint8_t *)0x00000E82, { 6, 12 } }, + { 11, 2, 2, 10, 10, (uint8_t *)0x00000EAA, { 6, 12 } }, + { 11, 0, 4, 10, 10, (uint8_t *)0x00000EBE, { 6, 12 } }, + { 9, 0, 6, 3, 3, (uint8_t *)0x00000EE6, { 6, 12 } } }, + { { 16, 0, 0, 0, 0, (uint8_t *)0x00000000, { 7, 13 } }, + { 11, 2, 2, 10, 10, (uint8_t *)0x00000000, { 7, 13 } }, + { 11, 1, 5, 4, 4, (uint8_t *)0x00000014, { 7, 13 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000028, { 7, 13 } }, + { 11, 0, 6, 10, 10, (uint8_t *)0x00000067, { 7, 13 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x000000A3, { 7, 13 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x000000E9, { 7, 13 } }, + { 11, 2, 3, 4, 4, (uint8_t *)0x0000012F, { 7, 13 } }, + { 11, 2, 4, 12, 12, (uint8_t *)0x0000013B, { 7, 13 } }, + { 11, 0, 4, 12, 12, (uint8_t *)0x0000016B, { 7, 13 } }, + { 9, 0, 6, 6, 6, (uint8_t *)0x0000019B, { 7, 13 } }, + { 9, 0, 7, 6, 6, (uint8_t *)0x000001BF, { 7, 13 } }, + { 4, 1, 3, 5, 5, (uint8_t *)0x000001E9, { 7, 13 } }, + { 7, 0, 6, 2, 2, (uint8_t *)0x000001F8, { 7, 13 } }, + { 4, 2, 2, 3, 3, (uint8_t *)0x00000204, { 7, 13 } }, + { 11, 3, 3, 10, 10, (uint8_t *)0x0000020A, { 7, 13 } }, + { 11, 0, 6, 10, 10, (uint8_t *)0x00000228, { 7, 13 } }, + { 11, 0, 4, 9, 9, (uint8_t *)0x00000264, { 7, 13 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x00000288, { 7, 13 } }, + { 11, 0, 6, 10, 10, (uint8_t *)0x000002BE, { 7, 13 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x000002FA, { 7, 13 } }, + { 11, 0, 6, 10, 10, (uint8_t *)0x00000330, { 7, 13 } }, + { 11, 0, 6, 10, 10, (uint8_t *)0x0000036C, { 7, 13 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x000003A8, { 7, 13 } }, + { 11, 0, 6, 10, 10, (uint8_t *)0x000003DE, { 7, 13 } }, + { 11, 0, 6, 10, 10, (uint8_t *)0x0000041A, { 7, 13 } }, + { 8, 2, 2, 7, 7, (uint8_t *)0x00000456, { 7, 13 } }, + { 8, 1, 3, 9, 9, (uint8_t *)0x00000464, { 7, 13 } }, + { 10, 1, 5, 8, 8, (uint8_t *)0x0000047F, { 7, 13 } }, + { 8, 0, 7, 4, 4, (uint8_t *)0x000004A7, { 7, 13 } }, + { 10, 2, 5, 8, 8, (uint8_t *)0x000004C3, { 7, 13 } }, + { 11, 0, 6, 10, 10, (uint8_t *)0x000004EB, { 7, 13 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x00000527, { 7, 13 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x0000056D, { 7, 13 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x000005AC, { 7, 13 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x000005E2, { 7, 13 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000628, { 7, 13 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x00000667, { 7, 13 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x0000069D, { 7, 13 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x000006D3, { 7, 13 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x00000719, { 7, 13 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x0000074F, { 7, 13 } }, + { 11, 1, 6, 10, 10, (uint8_t *)0x00000785, { 7, 13 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x000007C1, { 7, 13 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x00000800, { 7, 13 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000836, { 7, 13 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x00000875, { 7, 13 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x000008AB, { 7, 13 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x000008F1, { 7, 13 } }, + { 11, 0, 7, 11, 11, (uint8_t *)0x00000930, { 7, 13 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x0000097D, { 7, 13 } }, + { 11, 0, 6, 10, 10, (uint8_t *)0x000009B3, { 7, 13 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x000009EF, { 7, 13 } }, + { 11, 0, 6, 10, 10, (uint8_t *)0x00000A2E, { 7, 13 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000A6A, { 7, 13 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000AA9, { 7, 13 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x00000AE8, { 7, 13 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000B1E, { 7, 13 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x00000B5D, { 7, 13 } }, + { 11, 1, 5, 11, 11, (uint8_t *)0x00000B93, { 7, 13 } }, + { 11, 0, 3, 10, 10, (uint8_t *)0x00000BCA, { 7, 13 } }, + { 11, 0, 5, 11, 11, (uint8_t *)0x00000BE8, { 7, 13 } }, + { 11, 0, 6, 5, 5, (uint8_t *)0x00000C1F, { 7, 13 } }, + { 16, 0, 6, 0, 0, (uint8_t *)0x00000C3D, { 7, 13 } }, + { 11, 1, 3, 4, 4, (uint8_t *)0x00000C3D, { 7, 13 } }, + { 8, 0, 6, 7, 7, (uint8_t *)0x00000C49, { 7, 13 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x00000C73, { 7, 13 } }, + { 8, 0, 7, 7, 7, (uint8_t *)0x00000CB9, { 7, 13 } }, + { 11, 0, 6, 10, 10, (uint8_t *)0x00000CEA, { 7, 13 } }, + { 8, 0, 6, 7, 7, (uint8_t *)0x00000D26, { 7, 13 } }, + { 11, 1, 6, 9, 9, (uint8_t *)0x00000D50, { 7, 13 } }, + { 9, 0, 7, 10, 10, (uint8_t *)0x00000D86, { 7, 13 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x00000DCC, { 7, 13 } }, + { 11, 1, 5, 9, 9, (uint8_t *)0x00000E02, { 7, 13 } }, + { 11, 0, 5, 12, 12, (uint8_t *)0x00000E2F, { 7, 13 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000E6B, { 7, 13 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x00000EAA, { 7, 13 } }, + { 8, 0, 7, 6, 6, (uint8_t *)0x00000EE0, { 7, 13 } }, + { 8, 0, 6, 6, 6, (uint8_t *)0x00000F0A, { 7, 13 } }, + { 8, 0, 7, 7, 7, (uint8_t *)0x00000F2E, { 7, 13 } }, + { 8, 0, 7, 9, 9, (uint8_t *)0x00000F5F, { 7, 13 } }, + { 8, 0, 6, 9, 9, (uint8_t *)0x00000F9E, { 7, 13 } }, + { 8, 1, 5, 6, 6, (uint8_t *)0x00000FD4, { 7, 13 } }, + { 8, 0, 6, 7, 7, (uint8_t *)0x00000FF2, { 7, 13 } }, + { 10, 0, 6, 9, 9, (uint8_t *)0x0000101C, { 7, 13 } }, + { 8, 0, 6, 7, 7, (uint8_t *)0x00001052, { 7, 13 } }, + { 8, 0, 7, 6, 6, (uint8_t *)0x0000107C, { 7, 13 } }, + { 8, 0, 7, 6, 6, (uint8_t *)0x000010A6, { 7, 13 } }, + { 8, 0, 6, 6, 6, (uint8_t *)0x000010D0, { 7, 13 } }, + { 8, 0, 7, 9, 9, (uint8_t *)0x000010F4, { 7, 13 } }, + { 8, 0, 6, 6, 6, (uint8_t *)0x00001133, { 7, 13 } }, + { 11, 2, 4, 11, 11, (uint8_t *)0x00001157, { 7, 13 } }, + { 11, 2, 2, 11, 11, (uint8_t *)0x00001183, { 7, 13 } }, + { 11, 0, 5, 11, 11, (uint8_t *)0x00001199, { 7, 13 } }, + { 8, 0, 7, 2, 2, (uint8_t *)0x000011D0, { 7, 13 } } }, + { { 16, 0, 0, 0, 0, (uint8_t *)0x00000000, { 7, 14 } }, + { 12, 2, 3, 11, 11, (uint8_t *)0x00000000, { 7, 14 } }, + { 12, 1, 5, 5, 5, (uint8_t *)0x00000021, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x0000003A, { 7, 14 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x00000079, { 7, 14 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x000000C6, { 7, 14 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x0000010C, { 7, 14 } }, + { 12, 2, 3, 5, 5, (uint8_t *)0x00000152, { 7, 14 } }, + { 12, 3, 3, 13, 13, (uint8_t *)0x00000161, { 7, 14 } }, + { 12, 0, 4, 13, 13, (uint8_t *)0x00000188, { 7, 14 } }, + { 10, 0, 7, 7, 7, (uint8_t *)0x000001BC, { 7, 14 } }, + { 10, 0, 7, 7, 7, (uint8_t *)0x000001ED, { 7, 14 } }, + { 4, 2, 3, 5, 5, (uint8_t *)0x0000021E, { 7, 14 } }, + { 16, 0, 6, 0, 0, (uint8_t *)0x0000022D, { 7, 14 } }, + { 4, 2, 3, 3, 3, (uint8_t *)0x0000022D, { 7, 14 } }, + { 12, 4, 3, 11, 11, (uint8_t *)0x00000236, { 7, 14 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x00000257, { 7, 14 } }, + { 11, 0, 5, 9, 9, (uint8_t *)0x0000029D, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x000002CA, { 7, 14 } }, + { 11, 0, 6, 10, 10, (uint8_t *)0x00000309, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000345, { 7, 14 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x00000384, { 7, 14 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x000003CA, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000410, { 7, 14 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x0000044F, { 7, 14 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x00000495, { 7, 14 } }, + { 8, 2, 3, 7, 7, (uint8_t *)0x000004DB, { 7, 14 } }, + { 8, 2, 3, 9, 9, (uint8_t *)0x000004F0, { 7, 14 } }, + { 10, 2, 5, 8, 8, (uint8_t *)0x0000050B, { 7, 14 } }, + { 9, 0, 7, 5, 5, (uint8_t *)0x00000533, { 7, 14 } }, + { 10, 0, 5, 8, 8, (uint8_t *)0x00000556, { 7, 14 } }, + { 12, 0, 6, 11, 11, (uint8_t *)0x0000057E, { 7, 14 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x000005C0, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000606, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000645, { 7, 14 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x00000684, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x000006CA, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000709, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000748, { 7, 14 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x00000787, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x000007CD, { 7, 14 } }, + { 11, 0, 6, 9, 9, (uint8_t *)0x0000080C, { 7, 14 } }, + { 11, 0, 6, 10, 10, (uint8_t *)0x00000842, { 7, 14 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x0000087E, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x000008C4, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000903, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000942, { 7, 14 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x00000981, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x000009C7, { 7, 14 } }, + { 11, 0, 7, 11, 11, (uint8_t *)0x00000A06, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000A53, { 7, 14 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x00000A92, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000AD8, { 7, 14 } }, + { 11, 0, 7, 10, 10, (uint8_t *)0x00000B17, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000B5D, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000B9C, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000BDB, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000C1A, { 7, 14 } }, + { 11, 0, 7, 9, 9, (uint8_t *)0x00000C59, { 7, 14 } }, + { 12, 1, 5, 12, 12, (uint8_t *)0x00000C98, { 7, 14 } }, + { 12, 0, 3, 11, 11, (uint8_t *)0x00000CD4, { 7, 14 } }, + { 12, 0, 6, 12, 12, (uint8_t *)0x00000CF5, { 7, 14 } }, + { 11, 1, 5, 5, 5, (uint8_t *)0x00000D3D, { 7, 14 } }, + { 2, 0, 7, 2, 2, (uint8_t *)0x00000D56, { 7, 14 } }, + { 12, 1, 3, 4, 4, (uint8_t *)0x00000D64, { 7, 14 } }, + { 9, 0, 7, 8, 8, (uint8_t *)0x00000D70, { 7, 14 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x00000DA8, { 7, 14 } }, + { 9, 0, 7, 8, 8, (uint8_t *)0x00000DF5, { 7, 14 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x00000E2D, { 7, 14 } }, + { 9, 0, 7, 8, 8, (uint8_t *)0x00000E7A, { 7, 14 } }, + { 12, 0, 6, 10, 10, (uint8_t *)0x00000EB2, { 7, 14 } }, + { 9, 0, 7, 10, 10, (uint8_t *)0x00000EEE, { 7, 14 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x00000F34, { 7, 14 } }, + { 12, 1, 5, 10, 10, (uint8_t *)0x00000F7A, { 7, 14 } }, + { 12, 0, 6, 13, 13, (uint8_t *)0x00000FAC, { 7, 14 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x00000FFA, { 7, 14 } }, + { 12, 0, 6, 10, 10, (uint8_t *)0x00001040, { 7, 14 } }, + { 9, 0, 7, 7, 7, (uint8_t *)0x0000107C, { 7, 14 } }, + { 9, 0, 7, 7, 7, (uint8_t *)0x000010AD, { 7, 14 } }, + { 9, 0, 7, 8, 8, (uint8_t *)0x000010DE, { 7, 14 } }, + { 9, 0, 7, 10, 10, (uint8_t *)0x00001116, { 7, 14 } }, + { 9, 0, 7, 10, 10, (uint8_t *)0x0000115C, { 7, 14 } }, + { 9, 1, 6, 7, 7, (uint8_t *)0x000011A2, { 7, 14 } }, + { 9, 0, 7, 8, 8, (uint8_t *)0x000011CC, { 7, 14 } }, + { 11, 0, 6, 10, 10, (uint8_t *)0x00001204, { 7, 14 } }, + { 9, 0, 7, 8, 8, (uint8_t *)0x00001240, { 7, 14 } }, + { 9, 0, 7, 7, 7, (uint8_t *)0x00001278, { 7, 14 } }, + { 9, 0, 7, 7, 7, (uint8_t *)0x000012A9, { 7, 14 } }, + { 9, 0, 7, 7, 7, (uint8_t *)0x000012DA, { 7, 14 } }, + { 9, 0, 7, 10, 10, (uint8_t *)0x0000130B, { 7, 14 } }, + { 9, 0, 7, 7, 7, (uint8_t *)0x00001351, { 7, 14 } }, + { 11, 2, 4, 12, 12, (uint8_t *)0x00001382, { 7, 14 } }, + { 12, 2, 3, 13, 13, (uint8_t *)0x000013B2, { 7, 14 } }, + { 11, 1, 4, 12, 12, (uint8_t *)0x000013D9, { 7, 14 } }, + { 9, 0, 7, 3, 3, (uint8_t *)0x00001409, { 7, 14 } } }, + { { 17, 0, 0, 0, 0, (uint8_t *)0x00000000, { 8, 15 } }, + { 12, 2, 3, 11, 11, (uint8_t *)0x00000000, { 8, 15 } }, + { 12, 1, 5, 4, 4, (uint8_t *)0x00000021, { 8, 15 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000035, { 8, 15 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x00000085, { 8, 15 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x000000D2, { 8, 15 } }, + { 12, 0, 8, 11, 11, (uint8_t *)0x0000011F, { 8, 15 } }, + { 12, 2, 3, 4, 4, (uint8_t *)0x00000177, { 8, 15 } }, + { 12, 2, 4, 13, 13, (uint8_t *)0x00000183, { 8, 15 } }, + { 12, 1, 4, 13, 13, (uint8_t *)0x000001B7, { 8, 15 } }, + { 10, 0, 7, 7, 7, (uint8_t *)0x000001EB, { 8, 15 } }, + { 10, 0, 7, 7, 7, (uint8_t *)0x0000021C, { 8, 15 } }, + { 4, 2, 3, 5, 5, (uint8_t *)0x0000024D, { 8, 15 } }, + { 8, 0, 7, 2, 2, (uint8_t *)0x0000025C, { 8, 15 } }, + { 4, 2, 3, 3, 3, (uint8_t *)0x0000026A, { 8, 15 } }, + { 12, 4, 3, 11, 11, (uint8_t *)0x00000273, { 8, 15 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x00000294, { 8, 15 } }, + { 12, 1, 4, 10, 10, (uint8_t *)0x000002E1, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x00000309, { 8, 15 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x0000034F, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x0000039C, { 8, 15 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x000003E2, { 8, 15 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x0000042F, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x0000047C, { 8, 15 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x000004C2, { 8, 15 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x0000050F, { 8, 15 } }, + { 9, 2, 3, 8, 8, (uint8_t *)0x0000055C, { 8, 15 } }, + { 9, 2, 3, 10, 10, (uint8_t *)0x00000574, { 8, 15 } }, + { 11, 2, 5, 9, 9, (uint8_t *)0x00000592, { 8, 15 } }, + { 9, 0, 7, 5, 5, (uint8_t *)0x000005BF, { 8, 15 } }, + { 11, 1, 5, 9, 9, (uint8_t *)0x000005E2, { 8, 15 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x0000060F, { 8, 15 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x0000065C, { 8, 15 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x000006A9, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x000006F9, { 8, 15 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x0000073F, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x0000078C, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x000007D2, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x00000818, { 8, 15 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x0000085E, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x000008AB, { 8, 15 } }, + { 12, 0, 6, 10, 10, (uint8_t *)0x000008F1, { 8, 15 } }, + { 12, 0, 6, 11, 11, (uint8_t *)0x0000092D, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x0000096F, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x000009B5, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x000009FB, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x00000A41, { 8, 15 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x00000A87, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x00000AD4, { 8, 15 } }, + { 12, 0, 7, 13, 13, (uint8_t *)0x00000B1A, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x00000B75, { 8, 15 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x00000BBB, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x00000C08, { 8, 15 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x00000C4E, { 8, 15 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000C9B, { 8, 15 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000CEB, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x00000D3B, { 8, 15 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000D81, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x00000DD1, { 8, 15 } }, + { 12, 1, 6, 12, 12, (uint8_t *)0x00000E17, { 8, 15 } }, + { 12, 0, 3, 11, 11, (uint8_t *)0x00000E5F, { 8, 15 } }, + { 12, 0, 6, 12, 12, (uint8_t *)0x00000E80, { 8, 15 } }, + { 12, 1, 5, 5, 5, (uint8_t *)0x00000EC8, { 8, 15 } }, + { 2, 0, 7, 2, 2, (uint8_t *)0x00000EE1, { 8, 15 } }, + { 12, 1, 3, 4, 4, (uint8_t *)0x00000EEF, { 8, 15 } }, + { 9, 0, 7, 8, 8, (uint8_t *)0x00000EFB, { 8, 15 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x00000F33, { 8, 15 } }, + { 9, 0, 7, 8, 8, (uint8_t *)0x00000F80, { 8, 15 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x00000FB8, { 8, 15 } }, + { 9, 0, 7, 8, 8, (uint8_t *)0x00001005, { 8, 15 } }, + { 12, 2, 6, 10, 10, (uint8_t *)0x0000103D, { 8, 15 } }, + { 9, 1, 7, 10, 10, (uint8_t *)0x00001079, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x000010BF, { 8, 15 } }, + { 12, 1, 5, 10, 10, (uint8_t *)0x00001105, { 8, 15 } }, + { 12, 0, 6, 13, 13, (uint8_t *)0x00001137, { 8, 15 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00001185, { 8, 15 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x000011D5, { 8, 15 } }, + { 9, 0, 7, 7, 7, (uint8_t *)0x0000121B, { 8, 15 } }, + { 9, 0, 7, 7, 7, (uint8_t *)0x0000124C, { 8, 15 } }, + { 9, 0, 7, 8, 8, (uint8_t *)0x0000127D, { 8, 15 } }, + { 9, 0, 7, 10, 10, (uint8_t *)0x000012B5, { 8, 15 } }, + { 9, 0, 7, 10, 10, (uint8_t *)0x000012FB, { 8, 15 } }, + { 9, 1, 6, 7, 7, (uint8_t *)0x00001341, { 8, 15 } }, + { 9, 0, 7, 8, 8, (uint8_t *)0x0000136B, { 8, 15 } }, + { 11, 0, 6, 10, 10, (uint8_t *)0x000013A3, { 8, 15 } }, + { 9, 0, 7, 8, 8, (uint8_t *)0x000013DF, { 8, 15 } }, + { 9, 0, 7, 7, 7, (uint8_t *)0x00001417, { 8, 15 } }, + { 9, 0, 8, 7, 7, (uint8_t *)0x00001448, { 8, 15 } }, + { 9, 0, 7, 7, 7, (uint8_t *)0x00001480, { 8, 15 } }, + { 9, 0, 7, 10, 10, (uint8_t *)0x000014B1, { 8, 15 } }, + { 9, 0, 7, 7, 7, (uint8_t *)0x000014F7, { 8, 15 } }, + { 12, 2, 5, 13, 13, (uint8_t *)0x00001528, { 8, 15 } }, + { 12, 2, 3, 13, 13, (uint8_t *)0x00001569, { 8, 15 } }, + { 12, 1, 4, 13, 13, (uint8_t *)0x00001590, { 8, 15 } }, + { 9, 0, 8, 3, 3, (uint8_t *)0x000015C4, { 8, 15 } } }, + { { 19, 0, 0, 0, 0, (uint8_t *)0x00000000, { 8, 16 } }, + { 13, 2, 3, 12, 12, (uint8_t *)0x00000000, { 8, 16 } }, + { 13, 1, 6, 5, 5, (uint8_t *)0x00000024, { 8, 16 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000042, { 8, 16 } }, + { 13, 0, 8, 12, 12, (uint8_t *)0x00000092, { 8, 16 } }, + { 13, 0, 8, 12, 12, (uint8_t *)0x000000F2, { 8, 16 } }, + { 12, 0, 8, 11, 11, (uint8_t *)0x00000152, { 8, 16 } }, + { 13, 3, 3, 5, 5, (uint8_t *)0x000001AA, { 8, 16 } }, + { 13, 3, 4, 14, 14, (uint8_t *)0x000001B9, { 8, 16 } }, + { 13, 0, 4, 14, 14, (uint8_t *)0x000001F1, { 8, 16 } }, + { 11, 0, 8, 8, 8, (uint8_t *)0x00000229, { 8, 16 } }, + { 11, 0, 8, 8, 8, (uint8_t *)0x00000269, { 8, 16 } }, + { 4, 2, 3, 5, 5, (uint8_t *)0x000002A9, { 8, 16 } }, + { 8, 0, 7, 2, 2, (uint8_t *)0x000002B8, { 8, 16 } }, + { 4, 2, 3, 3, 3, (uint8_t *)0x000002C6, { 8, 16 } }, + { 13, 4, 3, 12, 12, (uint8_t *)0x000002CF, { 8, 16 } }, + { 12, 0, 8, 11, 11, (uint8_t *)0x000002F3, { 8, 16 } }, + { 12, 1, 4, 10, 10, (uint8_t *)0x0000034B, { 8, 16 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x00000373, { 8, 16 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x000003B9, { 8, 16 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000406, { 8, 16 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x00000456, { 8, 16 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x000004A3, { 8, 16 } }, + { 12, 1, 6, 10, 10, (uint8_t *)0x000004F0, { 8, 16 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x0000052C, { 8, 16 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x00000579, { 8, 16 } }, + { 9, 2, 3, 8, 8, (uint8_t *)0x000005C6, { 8, 16 } }, + { 9, 2, 3, 10, 10, (uint8_t *)0x000005DE, { 8, 16 } }, + { 11, 3, 5, 9, 9, (uint8_t *)0x000005FC, { 8, 16 } }, + { 9, 0, 8, 5, 5, (uint8_t *)0x00000629, { 8, 16 } }, + { 11, 0, 5, 9, 9, (uint8_t *)0x00000651, { 8, 16 } }, + { 13, 0, 7, 12, 12, (uint8_t *)0x0000067E, { 8, 16 } }, + { 13, 0, 8, 12, 12, (uint8_t *)0x000006D2, { 8, 16 } }, + { 13, 0, 8, 11, 11, (uint8_t *)0x00000732, { 8, 16 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x0000078A, { 8, 16 } }, + { 12, 0, 8, 11, 11, (uint8_t *)0x000007DA, { 8, 16 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000832, { 8, 16 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x00000882, { 8, 16 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x000008C8, { 8, 16 } }, + { 12, 0, 8, 11, 11, (uint8_t *)0x0000090E, { 8, 16 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000966, { 8, 16 } }, + { 12, 1, 6, 10, 10, (uint8_t *)0x000009B6, { 8, 16 } }, + { 12, 2, 6, 11, 11, (uint8_t *)0x000009F2, { 8, 16 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000A34, { 8, 16 } }, + { 12, 0, 7, 10, 10, (uint8_t *)0x00000A84, { 8, 16 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000ACA, { 8, 16 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000B1A, { 8, 16 } }, + { 12, 0, 8, 11, 11, (uint8_t *)0x00000B6A, { 8, 16 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000BC2, { 8, 16 } }, + { 12, 0, 8, 13, 13, (uint8_t *)0x00000C12, { 8, 16 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000C7A, { 8, 16 } }, + { 12, 0, 8, 11, 11, (uint8_t *)0x00000CCA, { 8, 16 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000D22, { 8, 16 } }, + { 12, 0, 8, 11, 11, (uint8_t *)0x00000D72, { 8, 16 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000DCA, { 8, 16 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000E1A, { 8, 16 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000E6A, { 8, 16 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000EBA, { 8, 16 } }, + { 12, 0, 8, 10, 10, (uint8_t *)0x00000F0A, { 8, 16 } }, + { 13, 1, 6, 13, 13, (uint8_t *)0x00000F5A, { 8, 16 } }, + { 13, 0, 3, 12, 12, (uint8_t *)0x00000FA8, { 8, 16 } }, + { 13, 1, 5, 13, 13, (uint8_t *)0x00000FCC, { 8, 16 } }, + { 12, 1, 6, 5, 5, (uint8_t *)0x0000100D, { 8, 16 } }, + { 2, 0, 8, 2, 2, (uint8_t *)0x0000102B, { 8, 16 } }, + { 13, 1, 3, 4, 4, (uint8_t *)0x0000103B, { 8, 16 } }, + { 10, 0, 7, 9, 9, (uint8_t *)0x00001047, { 8, 16 } }, + { 13, 0, 8, 12, 12, (uint8_t *)0x00001086, { 8, 16 } }, + { 10, 0, 8, 9, 9, (uint8_t *)0x000010E6, { 8, 16 } }, + { 13, 0, 7, 12, 12, (uint8_t *)0x0000112E, { 8, 16 } }, + { 10, 0, 8, 9, 9, (uint8_t *)0x00001182, { 8, 16 } }, + { 13, 0, 7, 11, 11, (uint8_t *)0x000011CA, { 8, 16 } }, + { 10, 0, 8, 11, 11, (uint8_t *)0x00001217, { 8, 16 } }, + { 13, 0, 7, 11, 11, (uint8_t *)0x0000126F, { 8, 16 } }, + { 13, 1, 6, 11, 11, (uint8_t *)0x000012BC, { 8, 16 } }, + { 13, 0, 6, 14, 14, (uint8_t *)0x000012FE, { 8, 16 } }, + { 13, 0, 8, 11, 11, (uint8_t *)0x00001352, { 8, 16 } }, + { 13, 1, 6, 11, 11, (uint8_t *)0x000013AA, { 8, 16 } }, + { 10, 0, 8, 8, 8, (uint8_t *)0x000013EC, { 8, 16 } }, + { 10, 0, 7, 8, 8, (uint8_t *)0x0000142C, { 8, 16 } }, + { 10, 0, 8, 9, 9, (uint8_t *)0x00001464, { 8, 16 } }, + { 10, 0, 8, 11, 11, (uint8_t *)0x000014AC, { 8, 16 } }, + { 10, 0, 7, 11, 11, (uint8_t *)0x00001504, { 8, 16 } }, + { 10, 1, 7, 8, 8, (uint8_t *)0x00001551, { 8, 16 } }, + { 10, 0, 7, 9, 9, (uint8_t *)0x00001589, { 8, 16 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x000015C8, { 8, 16 } }, + { 10, 0, 7, 9, 9, (uint8_t *)0x00001615, { 8, 16 } }, + { 10, 0, 8, 8, 8, (uint8_t *)0x00001654, { 8, 16 } }, + { 10, 0, 8, 8, 8, (uint8_t *)0x00001694, { 8, 16 } }, + { 10, 0, 8, 8, 8, (uint8_t *)0x000016D4, { 8, 16 } }, + { 10, 0, 8, 11, 11, (uint8_t *)0x00001714, { 8, 16 } }, + { 10, 0, 8, 8, 8, (uint8_t *)0x0000176C, { 8, 16 } }, + { 13, 2, 5, 14, 14, (uint8_t *)0x000017AC, { 8, 16 } }, + { 13, 3, 2, 14, 14, (uint8_t *)0x000017F2, { 8, 16 } }, + { 13, 1, 5, 14, 14, (uint8_t *)0x0000180E, { 8, 16 } }, + { 10, 0, 8, 3, 3, (uint8_t *)0x00001854, { 8, 16 } } }, + { { 20, 0, 0, 0, 0, (uint8_t *)0x00000000, { 9, 17 } }, + { 14, 2, 3, 13, 13, (uint8_t *)0x00000000, { 9, 17 } }, + { 14, 1, 6, 5, 5, (uint8_t *)0x00000027, { 9, 17 } }, + { 13, 0, 9, 11, 11, (uint8_t *)0x00000045, { 9, 17 } }, + { 14, 0, 8, 13, 13, (uint8_t *)0x000000A8, { 9, 17 } }, + { 13, 0, 8, 12, 12, (uint8_t *)0x00000110, { 9, 17 } }, + { 13, 0, 9, 12, 12, (uint8_t *)0x00000170, { 9, 17 } }, + { 14, 3, 3, 5, 5, (uint8_t *)0x000001DC, { 9, 17 } }, + { 14, 4, 4, 15, 15, (uint8_t *)0x000001EB, { 9, 17 } }, + { 14, 1, 4, 15, 15, (uint8_t *)0x00000227, { 9, 17 } }, + { 11, 0, 8, 8, 8, (uint8_t *)0x00000263, { 9, 17 } }, + { 11, 0, 8, 8, 8, (uint8_t *)0x000002A3, { 9, 17 } }, + { 4, 2, 4, 5, 5, (uint8_t *)0x000002E3, { 9, 17 } }, + { 8, 0, 8, 2, 2, (uint8_t *)0x000002F7, { 9, 17 } }, + { 4, 2, 3, 3, 3, (uint8_t *)0x00000307, { 9, 17 } }, + { 14, 5, 3, 13, 13, (uint8_t *)0x00000310, { 9, 17 } }, + { 13, 0, 8, 12, 12, (uint8_t *)0x00000337, { 9, 17 } }, + { 13, 1, 5, 11, 11, (uint8_t *)0x00000397, { 9, 17 } }, + { 13, 0, 8, 11, 11, (uint8_t *)0x000003CE, { 9, 17 } }, + { 13, 0, 7, 12, 12, (uint8_t *)0x00000426, { 9, 17 } }, + { 13, 0, 8, 11, 11, (uint8_t *)0x0000047A, { 9, 17 } }, + { 13, 0, 8, 12, 12, (uint8_t *)0x000004D2, { 9, 17 } }, + { 13, 0, 8, 12, 12, (uint8_t *)0x00000532, { 9, 17 } }, + { 13, 1, 7, 11, 11, (uint8_t *)0x00000592, { 9, 17 } }, + { 13, 0, 8, 12, 12, (uint8_t *)0x000005DF, { 9, 17 } }, + { 13, 0, 8, 12, 12, (uint8_t *)0x0000063F, { 9, 17 } }, + { 10, 2, 3, 9, 9, (uint8_t *)0x0000069F, { 9, 17 } }, + { 10, 2, 4, 11, 11, (uint8_t *)0x000006BA, { 9, 17 } }, + { 12, 2, 5, 10, 10, (uint8_t *)0x000006E6, { 9, 17 } }, + { 10, 0, 8, 6, 6, (uint8_t *)0x00000718, { 9, 17 } }, + { 12, 1, 5, 10, 10, (uint8_t *)0x00000748, { 9, 17 } }, + { 14, 0, 8, 13, 13, (uint8_t *)0x0000077A, { 9, 17 } }, + { 13, 0, 8, 12, 12, (uint8_t *)0x000007E2, { 9, 17 } }, + { 13, 0, 9, 12, 12, (uint8_t *)0x00000842, { 9, 17 } }, + { 13, 0, 8, 11, 11, (uint8_t *)0x000008AE, { 9, 17 } }, + { 13, 0, 8, 12, 12, (uint8_t *)0x00000906, { 9, 17 } }, + { 13, 0, 8, 11, 11, (uint8_t *)0x00000966, { 9, 17 } }, + { 13, 0, 8, 11, 11, (uint8_t *)0x000009BE, { 9, 17 } }, + { 13, 1, 7, 11, 11, (uint8_t *)0x00000A16, { 9, 17 } }, + { 13, 0, 8, 12, 12, (uint8_t *)0x00000A63, { 9, 17 } }, + { 13, 0, 8, 11, 11, (uint8_t *)0x00000AC3, { 9, 17 } }, + { 13, 1, 6, 11, 11, (uint8_t *)0x00000B1B, { 9, 17 } }, + { 13, 2, 6, 12, 12, (uint8_t *)0x00000B5D, { 9, 17 } }, + { 13, 0, 8, 11, 11, (uint8_t *)0x00000BA5, { 9, 17 } }, + { 13, 0, 8, 11, 11, (uint8_t *)0x00000BFD, { 9, 17 } }, + { 13, 0, 8, 11, 11, (uint8_t *)0x00000C55, { 9, 17 } }, + { 13, 0, 8, 11, 11, (uint8_t *)0x00000CAD, { 9, 17 } }, + { 13, 0, 8, 12, 12, (uint8_t *)0x00000D05, { 9, 17 } }, + { 13, 0, 8, 11, 11, (uint8_t *)0x00000D65, { 9, 17 } }, + { 13, 0, 8, 14, 14, (uint8_t *)0x00000DBD, { 9, 17 } }, + { 13, 0, 8, 11, 11, (uint8_t *)0x00000E2D, { 9, 17 } }, + { 13, 0, 8, 12, 12, (uint8_t *)0x00000E85, { 9, 17 } }, + { 13, 0, 8, 11, 11, (uint8_t *)0x00000EE5, { 9, 17 } }, + { 13, 0, 8, 12, 12, (uint8_t *)0x00000F3D, { 9, 17 } }, + { 13, 0, 9, 11, 11, (uint8_t *)0x00000F9D, { 9, 17 } }, + { 13, 0, 9, 11, 11, (uint8_t *)0x00001000, { 9, 17 } }, + { 13, 0, 8, 11, 11, (uint8_t *)0x00001063, { 9, 17 } }, + { 13, 0, 8, 11, 11, (uint8_t *)0x000010BB, { 9, 17 } }, + { 13, 0, 8, 11, 11, (uint8_t *)0x00001113, { 9, 17 } }, + { 14, 1, 7, 14, 14, (uint8_t *)0x0000116B, { 9, 17 } }, + { 14, 0, 3, 13, 13, (uint8_t *)0x000011CD, { 9, 17 } }, + { 14, 1, 6, 14, 14, (uint8_t *)0x000011F4, { 9, 17 } }, + { 13, 1, 6, 6, 6, (uint8_t *)0x00001248, { 9, 17 } }, + { 2, 0, 8, 2, 2, (uint8_t *)0x0000126C, { 9, 17 } }, + { 14, 2, 4, 5, 5, (uint8_t *)0x0000127C, { 9, 17 } }, + { 10, 0, 8, 9, 9, (uint8_t *)0x00001290, { 9, 17 } }, + { 14, 0, 8, 13, 13, (uint8_t *)0x000012D8, { 9, 17 } }, + { 10, 0, 8, 9, 9, (uint8_t *)0x00001340, { 9, 17 } }, + { 14, 0, 8, 13, 13, (uint8_t *)0x00001388, { 9, 17 } }, + { 10, 0, 8, 9, 9, (uint8_t *)0x000013F0, { 9, 17 } }, + { 14, 2, 7, 12, 12, (uint8_t *)0x00001438, { 9, 17 } }, + { 10, 0, 8, 11, 11, (uint8_t *)0x0000148C, { 9, 17 } }, + { 14, 0, 8, 12, 12, (uint8_t *)0x000014E4, { 9, 17 } }, + { 14, 1, 6, 12, 12, (uint8_t *)0x00001544, { 9, 17 } }, + { 14, 1, 6, 15, 15, (uint8_t *)0x0000158C, { 9, 17 } }, + { 14, 0, 9, 12, 12, (uint8_t *)0x000015E6, { 9, 17 } }, + { 14, 1, 7, 12, 12, (uint8_t *)0x00001652, { 9, 17 } }, + { 10, 0, 8, 8, 8, (uint8_t *)0x000016A6, { 9, 17 } }, + { 10, 0, 8, 8, 8, (uint8_t *)0x000016E6, { 9, 17 } }, + { 10, 0, 8, 9, 9, (uint8_t *)0x00001726, { 9, 17 } }, + { 10, 0, 8, 11, 11, (uint8_t *)0x0000176E, { 9, 17 } }, + { 10, 0, 8, 11, 11, (uint8_t *)0x000017C6, { 9, 17 } }, + { 10, 1, 7, 8, 8, (uint8_t *)0x0000181E, { 9, 17 } }, + { 10, 0, 8, 9, 9, (uint8_t *)0x00001856, { 9, 17 } }, + { 12, 0, 7, 11, 11, (uint8_t *)0x0000189E, { 9, 17 } }, + { 10, 0, 8, 9, 9, (uint8_t *)0x000018EB, { 9, 17 } }, + { 10, 0, 8, 8, 8, (uint8_t *)0x00001933, { 9, 17 } }, + { 10, 0, 9, 8, 8, (uint8_t *)0x00001973, { 9, 17 } }, + { 10, 0, 8, 8, 8, (uint8_t *)0x000019BB, { 9, 17 } }, + { 10, 0, 8, 11, 11, (uint8_t *)0x000019FB, { 9, 17 } }, + { 10, 0, 8, 8, 8, (uint8_t *)0x00001A53, { 9, 17 } }, + { 13, 2, 5, 14, 14, (uint8_t *)0x00001A93, { 9, 17 } }, + { 13, 3, 2, 14, 14, (uint8_t *)0x00001AD9, { 9, 17 } }, + { 13, 1, 5, 14, 14, (uint8_t *)0x00001AF5, { 9, 17 } }, + { 10, 1, 8, 3, 3, (uint8_t *)0x00001B3B, { 9, 17 } } }, + { { 20, 0, 0, 0, 0, (uint8_t *)0x00000000, { 9, 18 } }, + { 14, 2, 4, 13, 13, (uint8_t *)0x00000000, { 9, 18 } }, + { 14, 2, 6, 5, 5, (uint8_t *)0x00000034, { 9, 18 } }, + { 14, 0, 9, 12, 12, (uint8_t *)0x00000052, { 9, 18 } }, + { 14, 1, 8, 13, 13, (uint8_t *)0x000000BE, { 9, 18 } }, + { 14, 0, 9, 13, 13, (uint8_t *)0x00000126, { 9, 18 } }, + { 14, 0, 9, 13, 13, (uint8_t *)0x0000019B, { 9, 18 } }, + { 14, 3, 3, 5, 5, (uint8_t *)0x00000210, { 9, 18 } }, + { 14, 4, 4, 16, 16, (uint8_t *)0x0000021F, { 9, 18 } }, + { 14, 1, 4, 16, 16, (uint8_t *)0x0000025F, { 9, 18 } }, + { 12, 0, 9, 8, 8, (uint8_t *)0x0000029F, { 9, 18 } }, + { 12, 0, 9, 9, 9, (uint8_t *)0x000002E7, { 9, 18 } }, + { 4, 2, 4, 5, 5, (uint8_t *)0x00000338, { 9, 18 } }, + { 9, 1, 7, 2, 2, (uint8_t *)0x0000034C, { 9, 18 } }, + { 4, 2, 4, 3, 3, (uint8_t *)0x0000035A, { 9, 18 } }, + { 14, 5, 3, 13, 13, (uint8_t *)0x00000366, { 9, 18 } }, + { 14, 0, 9, 13, 13, (uint8_t *)0x0000038D, { 9, 18 } }, + { 14, 1, 5, 12, 12, (uint8_t *)0x00000402, { 9, 18 } }, + { 14, 1, 7, 12, 12, (uint8_t *)0x0000043E, { 9, 18 } }, + { 14, 0, 8, 13, 13, (uint8_t *)0x00000492, { 9, 18 } }, + { 14, 0, 9, 12, 12, (uint8_t *)0x000004FA, { 9, 18 } }, + { 14, 0, 8, 13, 13, (uint8_t *)0x00000566, { 9, 18 } }, + { 14, 0, 8, 13, 13, (uint8_t *)0x000005CE, { 9, 18 } }, + { 14, 1, 7, 12, 12, (uint8_t *)0x00000636, { 9, 18 } }, + { 14, 0, 8, 13, 13, (uint8_t *)0x0000068A, { 9, 18 } }, + { 14, 0, 8, 13, 13, (uint8_t *)0x000006F2, { 9, 18 } }, + { 10, 2, 4, 9, 9, (uint8_t *)0x0000075A, { 9, 18 } }, + { 10, 2, 4, 11, 11, (uint8_t *)0x0000077E, { 9, 18 } }, + { 13, 3, 6, 11, 11, (uint8_t *)0x000007AA, { 9, 18 } }, + { 10, 0, 9, 5, 5, (uint8_t *)0x000007EC, { 9, 18 } }, + { 13, 0, 5, 11, 11, (uint8_t *)0x00000819, { 9, 18 } }, + { 14, 0, 8, 13, 13, (uint8_t *)0x00000850, { 9, 18 } }, + { 14, 0, 9, 13, 13, (uint8_t *)0x000008B8, { 9, 18 } }, + { 14, 0, 9, 12, 12, (uint8_t *)0x0000092D, { 9, 18 } }, + { 14, 0, 9, 12, 12, (uint8_t *)0x00000999, { 9, 18 } }, + { 14, 1, 8, 13, 13, (uint8_t *)0x00000A05, { 9, 18 } }, + { 14, 0, 9, 12, 12, (uint8_t *)0x00000A6D, { 9, 18 } }, + { 14, 0, 8, 12, 12, (uint8_t *)0x00000AD9, { 9, 18 } }, + { 14, 1, 7, 12, 12, (uint8_t *)0x00000B39, { 9, 18 } }, + { 14, 0, 9, 13, 13, (uint8_t *)0x00000B8D, { 9, 18 } }, + { 14, 0, 8, 12, 12, (uint8_t *)0x00000C02, { 9, 18 } }, + { 14, 1, 7, 12, 12, (uint8_t *)0x00000C62, { 9, 18 } }, + { 14, 2, 7, 13, 13, (uint8_t *)0x00000CB6, { 9, 18 } }, + { 14, 0, 9, 12, 12, (uint8_t *)0x00000D11, { 9, 18 } }, + { 14, 0, 8, 12, 12, (uint8_t *)0x00000D7D, { 9, 18 } }, + { 14, 0, 9, 12, 12, (uint8_t *)0x00000DDD, { 9, 18 } }, + { 14, 0, 9, 12, 12, (uint8_t *)0x00000E49, { 9, 18 } }, + { 14, 0, 9, 13, 13, (uint8_t *)0x00000EB5, { 9, 18 } }, + { 14, 0, 9, 12, 12, (uint8_t *)0x00000F2A, { 9, 18 } }, + { 14, 0, 9, 15, 15, (uint8_t *)0x00000F96, { 9, 18 } }, + { 14, 0, 9, 12, 12, (uint8_t *)0x0000101D, { 9, 18 } }, + { 14, 1, 8, 13, 13, (uint8_t *)0x00001089, { 9, 18 } }, + { 14, 0, 9, 12, 12, (uint8_t *)0x000010F1, { 9, 18 } }, + { 14, 0, 9, 13, 13, (uint8_t *)0x0000115D, { 9, 18 } }, + { 14, 0, 9, 12, 12, (uint8_t *)0x000011D2, { 9, 18 } }, + { 14, 0, 9, 12, 12, (uint8_t *)0x0000123E, { 9, 18 } }, + { 14, 0, 9, 12, 12, (uint8_t *)0x000012AA, { 9, 18 } }, + { 14, 0, 9, 12, 12, (uint8_t *)0x00001316, { 9, 18 } }, + { 14, 0, 9, 12, 12, (uint8_t *)0x00001382, { 9, 18 } }, + { 14, 2, 6, 14, 14, (uint8_t *)0x000013EE, { 9, 18 } }, + { 14, 0, 3, 13, 13, (uint8_t *)0x00001442, { 9, 18 } }, + { 14, 1, 6, 14, 14, (uint8_t *)0x00001469, { 9, 18 } }, + { 14, 1, 7, 6, 6, (uint8_t *)0x000014BD, { 9, 18 } }, + { 2, 0, 9, 2, 2, (uint8_t *)0x000014E7, { 9, 18 } }, + { 14, 2, 4, 5, 5, (uint8_t *)0x000014F9, { 9, 18 } }, + { 11, 0, 8, 10, 10, (uint8_t *)0x0000150D, { 9, 18 } }, + { 14, 0, 9, 13, 13, (uint8_t *)0x0000155D, { 9, 18 } }, + { 11, 1, 8, 10, 10, (uint8_t *)0x000015D2, { 9, 18 } }, + { 14, 0, 8, 13, 13, (uint8_t *)0x00001622, { 9, 18 } }, + { 11, 0, 8, 10, 10, (uint8_t *)0x0000168A, { 9, 18 } }, + { 14, 2, 7, 12, 12, (uint8_t *)0x000016DA, { 9, 18 } }, + { 11, 0, 9, 12, 12, (uint8_t *)0x0000172E, { 9, 18 } }, + { 14, 1, 7, 12, 12, (uint8_t *)0x0000179A, { 9, 18 } }, + { 14, 1, 7, 12, 12, (uint8_t *)0x000017EE, { 9, 18 } }, + { 14, 0, 7, 16, 16, (uint8_t *)0x00001842, { 9, 18 } }, + { 14, 0, 9, 12, 12, (uint8_t *)0x000018B2, { 9, 18 } }, + { 14, 1, 7, 12, 12, (uint8_t *)0x0000191E, { 9, 18 } }, + { 11, 0, 9, 9, 9, (uint8_t *)0x00001972, { 9, 18 } }, + { 11, 0, 8, 9, 9, (uint8_t *)0x000019C3, { 9, 18 } }, + { 11, 0, 9, 10, 10, (uint8_t *)0x00001A0B, { 9, 18 } }, + { 11, 0, 9, 12, 12, (uint8_t *)0x00001A65, { 9, 18 } }, + { 11, 0, 8, 12, 12, (uint8_t *)0x00001AD1, { 9, 18 } }, + { 11, 1, 8, 9, 9, (uint8_t *)0x00001B31, { 9, 18 } }, + { 11, 0, 8, 10, 10, (uint8_t *)0x00001B79, { 9, 18 } }, + { 13, 1, 7, 12, 12, (uint8_t *)0x00001BC9, { 9, 18 } }, + { 11, 0, 8, 10, 10, (uint8_t *)0x00001C1D, { 9, 18 } }, + { 11, 0, 9, 9, 9, (uint8_t *)0x00001C6D, { 9, 18 } }, + { 11, 0, 9, 9, 9, (uint8_t *)0x00001CBE, { 9, 18 } }, + { 11, 0, 9, 9, 9, (uint8_t *)0x00001D0F, { 9, 18 } }, + { 11, 0, 9, 13, 13, (uint8_t *)0x00001D60, { 9, 18 } }, + { 11, 0, 9, 9, 9, (uint8_t *)0x00001DD5, { 9, 18 } }, + { 14, 2, 6, 15, 15, (uint8_t *)0x00001E26, { 9, 18 } }, + { 14, 3, 3, 15, 15, (uint8_t *)0x00001E80, { 9, 18 } }, + { 14, 1, 5, 15, 15, (uint8_t *)0x00001EAD, { 9, 18 } }, + { 11, 0, 9, 4, 4, (uint8_t *)0x00001EF8, { 9, 18 } } } + }; /* font_inconsolata_12px */ static const unsigned char pd_inconsolata_font_bitmap_12px_bytes[] = { - /* ch = '!' */ - 0x00, 0xe5, 0x4d, - 0x00, 0xff, 0x5f, - 0x00, 0xe5, 0x3f, - 0x00, 0xb7, 0x3b, - 0x00, 0xb7, 0x32, - 0x00, 0x58, 0x1c, - 0x00, 0x15, 0x08, - 0x17, 0xff, 0x66, - 0x00, 0x0f, 0x04, - /* ch = '"' */ - 0x77, 0x77, 0x66, 0x97, - 0x7c, 0x6a, 0x54, 0x7c, - 0xc8, 0x29, 0xa7, 0x35, - /* ch = '#' */ - 0x00, 0x16, 0x58, 0x10, 0x2d, 0x00, - 0x00, 0x32, 0x90, 0x32, 0xa5, 0x00, - 0x2d, 0x82, 0xab, 0x7b, 0xbd, 0x26, - 0x12, 0x7b, 0x64, 0x6d, 0x5f, 0x00, - 0x00, 0x82, 0x3b, 0x7c, 0x3f, 0x00, - 0xa2, 0xef, 0x7c, 0xdb, 0x82, 0x39, - 0x00, 0xf7, 0x16, 0xe5, 0x22, 0x00, - 0x09, 0xcf, 0x10, 0xdd, 0x0d, 0x00, - /* ch = '$' */ - 0x00, 0x00, 0x45, 0x57, 0x00, 0x00, - 0x04, 0x94, 0xe5, 0xe5, 0xd4, 0x10, - 0x32, 0xcf, 0x50, 0x5f, 0x28, 0x0d, - 0x17, 0xef, 0xdb, 0x5f, 0x00, 0x00, - 0x00, 0x0c, 0x82, 0xf7, 0xa2, 0x04, - 0x00, 0x00, 0x50, 0x5f, 0x97, 0x5a, - 0x32, 0x5a, 0x50, 0x68, 0xb7, 0x43, - 0x10, 0x73, 0xe5, 0xe5, 0x50, 0x04, - 0x00, 0x00, 0x30, 0x39, 0x00, 0x00, - /* ch = '%' */ - 0x26, 0x74, 0x26, 0x00, 0x28, 0x28, - 0xe5, 0x3f, 0xff, 0x1c, 0xdb, 0x10, - 0xc8, 0x58, 0xdb, 0xa5, 0x47, 0x00, - 0x19, 0x5b, 0x4f, 0xb7, 0x0d, 0x00, - 0x00, 0x00, 0xb7, 0x32, 0x00, 0x00, - 0x00, 0x3b, 0xa5, 0xb1, 0xd4, 0x40, - 0x04, 0xdb, 0x3b, 0xcf, 0x32, 0xc8, - 0x54, 0x7c, 0x04, 0xd4, 0xc4, 0x5a, - 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, - /* ch = '&' */ - 0x00, 0x22, 0x74, 0x28, 0x00, 0x00, - 0x14, 0xff, 0x31, 0xe5, 0x2f, 0x00, - 0x1a, 0xff, 0x16, 0xcf, 0x32, 0x00, - 0x00, 0x7c, 0xef, 0x8a, 0x04, 0x00, - 0x1f, 0xe5, 0xdb, 0x3f, 0x16, 0x13, - 0x99, 0x54, 0x1f, 0xf7, 0xb1, 0x6f, - 0xb7, 0x4a, 0x00, 0x74, 0xea, 0x13, - 0x40, 0xf7, 0xc4, 0xbb, 0x9e, 0x6c, - 0x00, 0x08, 0x0f, 0x00, 0x08, 0x08, - /* ch = ''' */ - 0x4d, 0xb1, - 0x50, 0x90, - 0x90, 0x3b, - /* ch = '(' */ - 0x00, 0x48, 0xd4, - 0x50, 0xb1, 0x13, - 0xf7, 0x1f, 0x00, - 0xa5, 0x00, 0x00, - 0x5f, 0x00, 0x00, - 0x64, 0x00, 0x00, - 0xb7, 0x00, 0x00, - 0xf7, 0x2c, 0x00, - 0x4d, 0xf7, 0x10, - 0x00, 0x48, 0xe5, - /* ch = ')' */ - 0x2d, 0xd4, 0x19, - 0x00, 0x3b, 0xf7, - 0x00, 0x00, 0x5f, - 0x00, 0x00, 0x0d, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0d, - 0x00, 0x00, 0x54, - 0x00, 0x35, 0xef, - 0x33, 0xd4, 0x21, - /* ch = '*' */ - 0x00, 0x00, 0x12, 0x0c, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x50, 0x00, 0x00, - 0x78, 0xa2, 0xa5, 0x82, 0xbb, 0x39, - 0x00, 0x12, 0xea, 0x8d, 0x0c, 0x00, - 0x00, 0x7c, 0x5f, 0xb1, 0x3b, 0x00, - 0x10, 0x8d, 0x0d, 0x24, 0x65, 0x04, - /* ch = '+' */ - 0x00, 0x00, 0x0f, 0x0c, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x5f, 0x00, 0x00, - 0x12, 0x15, 0x88, 0x6d, 0x15, 0x0c, - 0x58, 0x74, 0xc8, 0xb1, 0x74, 0x39, - 0x00, 0x00, 0x7c, 0x5f, 0x00, 0x00, - 0x00, 0x00, 0x67, 0x51, 0x00, 0x00, - /* ch = ',' */ - 0x00, 0x12, 0x04, - 0x17, 0xff, 0x7c, - 0x00, 0x7c, 0x54, - 0x17, 0xa9, 0x10, - /* ch = '-' */ - 0x0c, 0x15, 0x15, 0x15, 0x15, 0x04, - 0x30, 0x74, 0x74, 0x74, 0x74, 0x1c, - /* ch = '.' */ - 0x00, 0x12, 0x08, - 0x17, 0xff, 0x5a, - 0x00, 0x0f, 0x04, - /* ch = '/' */ - 0x0d, 0xef, 0x17, - 0x48, 0x9e, 0x00, - 0xe5, 0x32, 0x00, - 0xb7, 0x04, 0x00, - 0x3b, 0x00, 0x00, - 0x0d, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* ch = '0' */ - 0x00, 0x10, 0x50, 0x37, 0x04, 0x00, - 0x0d, 0xdb, 0x47, 0x8a, 0x8a, 0x00, - 0x44, 0x9e, 0x00, 0x35, 0xff, 0x1c, - 0x7c, 0x50, 0x1f, 0xd4, 0xc8, 0x3b, - 0x7c, 0x4a, 0xdb, 0x3b, 0x7c, 0x3b, - 0x6b, 0xff, 0x5f, 0x00, 0xb1, 0x39, - 0x2c, 0xff, 0x08, 0x17, 0xf7, 0x16, - 0x00, 0x77, 0xd4, 0xe5, 0x3b, 0x00, - 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, - /* ch = '1' */ - 0x00, 0x00, 0x2a, 0x26, - 0x1a, 0xc4, 0xd4, 0x90, - 0x00, 0x00, 0x50, 0x90, - 0x00, 0x00, 0x50, 0x90, - 0x00, 0x00, 0x50, 0x90, - 0x00, 0x00, 0x50, 0x90, - 0x00, 0x00, 0x50, 0x90, - 0x00, 0x00, 0x50, 0x90, - /* ch = '2' */ - 0x00, 0x1b, 0x50, 0x47, 0x08, 0x00, - 0x25, 0xd4, 0x2a, 0x6a, 0xc8, 0x00, - 0x00, 0x0f, 0x00, 0x00, 0xff, 0x24, - 0x00, 0x00, 0x00, 0x24, 0xe5, 0x10, - 0x00, 0x00, 0x19, 0xd4, 0x3b, 0x00, - 0x00, 0x1f, 0xd4, 0x35, 0x00, 0x00, - 0x04, 0xb7, 0x3f, 0x00, 0x00, 0x00, - 0x40, 0xff, 0xd4, 0xcf, 0xcf, 0x32, - /* ch = '3' */ - 0x00, 0x1e, 0x50, 0x30, 0x04, 0x00, - 0x10, 0x9e, 0x30, 0x8a, 0x8a, 0x00, - 0x00, 0x00, 0x00, 0x21, 0xcf, 0x09, - 0x00, 0x04, 0x20, 0xb1, 0x5a, 0x00, - 0x00, 0x0d, 0x3e, 0xc4, 0x5a, 0x00, - 0x00, 0x00, 0x00, 0x17, 0xff, 0x0d, - 0x04, 0x21, 0x00, 0x24, 0xf7, 0x0d, - 0x27, 0xef, 0xab, 0xe5, 0x50, 0x00, - 0x00, 0x00, 0x12, 0x08, 0x00, 0x00, - /* ch = '4' */ - 0x00, 0x00, 0x00, 0x28, 0x1e, 0x00, - 0x00, 0x00, 0x24, 0xff, 0x5f, 0x00, - 0x00, 0x04, 0xc0, 0xb7, 0x5f, 0x00, - 0x00, 0x5f, 0x64, 0x7c, 0x5f, 0x00, - 0x24, 0xb7, 0x10, 0x7c, 0x5f, 0x00, - 0xa0, 0xef, 0xcf, 0xef, 0xef, 0x4e, - 0x00, 0x00, 0x00, 0x7c, 0x5f, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0x5f, 0x00, - /* ch = '5' */ - 0x04, 0x36, 0x36, 0x36, 0x36, 0x00, - 0x1c, 0xff, 0x1a, 0x15, 0x15, 0x04, - 0x1c, 0xcf, 0x0d, 0x00, 0x00, 0x00, - 0x2a, 0xff, 0xb7, 0xcf, 0x35, 0x00, - 0x16, 0x50, 0x04, 0x21, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x3b, - 0x13, 0x3d, 0x00, 0x10, 0xf7, 0x29, - 0x1f, 0xd4, 0xa4, 0xd4, 0x73, 0x04, - 0x00, 0x00, 0x0f, 0x0c, 0x00, 0x00, - /* ch = '6' */ - 0x00, 0x04, 0x47, 0x74, 0x22, 0x00, - 0x00, 0xb1, 0x6a, 0x20, 0x7e, 0x10, - 0x2a, 0xcf, 0x0d, 0x00, 0x00, 0x00, - 0x4d, 0xcf, 0xab, 0xcf, 0x2c, 0x00, - 0x50, 0xdb, 0x1b, 0x21, 0xff, 0x13, - 0x50, 0x90, 0x00, 0x00, 0xbd, 0x2f, - 0x27, 0xff, 0x04, 0x0d, 0xf7, 0x1c, - 0x00, 0x6b, 0xef, 0xd4, 0x5a, 0x00, - 0x00, 0x00, 0x08, 0x0c, 0x00, 0x00, - /* ch = '7' */ - 0x16, 0x36, 0x36, 0x36, 0x36, 0x0d, - 0x16, 0x36, 0x36, 0x67, 0xe5, 0x10, - 0x00, 0x00, 0x00, 0x7c, 0x6a, 0x00, - 0x00, 0x00, 0x0d, 0xf7, 0x1f, 0x00, - 0x00, 0x00, 0x48, 0xb7, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x47, 0x00, 0x00, - 0x00, 0x22, 0xff, 0x16, 0x00, 0x00, - 0x00, 0x5a, 0xa5, 0x00, 0x00, 0x00, - /* ch = '8' */ - 0x00, 0x19, 0x67, 0x5b, 0x08, 0x00, - 0x0d, 0xf7, 0x31, 0x54, 0xe0, 0x00, - 0x22, 0xff, 0x04, 0x1f, 0xf7, 0x0d, - 0x00, 0xa9, 0xb1, 0xb1, 0x5a, 0x00, - 0x04, 0x94, 0x85, 0xd4, 0x5a, 0x00, - 0x48, 0xa5, 0x00, 0x10, 0xf7, 0x29, - 0x5f, 0xab, 0x00, 0x0d, 0xe5, 0x2c, - 0x10, 0xbb, 0xcb, 0xe5, 0x73, 0x04, - 0x00, 0x00, 0x0f, 0x0c, 0x00, 0x00, - /* ch = '9' */ - 0x00, 0x1b, 0x67, 0x3f, 0x04, 0x00, - 0x17, 0xef, 0x31, 0x8a, 0x8a, 0x00, - 0x4d, 0x97, 0x00, 0x0d, 0xff, 0x1c, - 0x44, 0xa5, 0x00, 0x04, 0xff, 0x24, - 0x10, 0xdb, 0x84, 0xbb, 0xff, 0x24, - 0x00, 0x08, 0x15, 0x15, 0xff, 0x22, - 0x00, 0x0c, 0x00, 0x35, 0xc8, 0x0d, - 0x1e, 0xe5, 0xab, 0xdd, 0x26, 0x00, - 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - /* ch = ':' */ - 0x1a, 0xff, 0x5a, - 0x00, 0x25, 0x13, - 0x00, 0x00, 0x00, - 0x00, 0x12, 0x08, - 0x17, 0xff, 0x5a, - 0x00, 0x0f, 0x04, - /* ch = ';' */ - 0x1a, 0xff, 0x5a, - 0x00, 0x25, 0x13, - 0x00, 0x00, 0x00, - 0x00, 0x12, 0x04, - 0x17, 0xff, 0x7c, - 0x00, 0x7c, 0x54, - 0x17, 0xa9, 0x10, - /* ch = '<' */ - 0x00, 0x04, 0x3f, 0x4e, - 0x37, 0xdd, 0x66, 0x13, - 0x73, 0x16, 0x00, 0x00, - 0x1b, 0x00, 0x00, 0x00, - 0xd4, 0x84, 0x08, 0x00, - 0x04, 0x37, 0xef, 0x3e, - 0x00, 0x00, 0x08, 0x26, - /* ch = '=' */ - 0x12, 0x15, 0x15, 0x15, 0x15, 0x0c, - 0x2d, 0x36, 0x36, 0x36, 0x36, 0x26, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x95, 0xcf, 0xcf, 0xcf, 0xcf, 0x4e, - /* ch = '>' */ - 0x87, 0x28, 0x00, 0x00, - 0x1b, 0xa4, 0xcb, 0x1e, - 0x00, 0x00, 0x1e, 0xa4, - 0x00, 0x00, 0x00, 0x37, - 0x00, 0x1b, 0xbb, 0x94, - 0x7f, 0xbb, 0x25, 0x00, - 0x28, 0x04, 0x00, 0x00, - /* ch = '?' */ - 0x08, 0x8d, 0xe5, 0xef, 0x4d, 0x00, - 0x2f, 0x7e, 0x04, 0x26, 0xff, 0x1c, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x22, - 0x00, 0x00, 0x04, 0xb1, 0x84, 0x04, - 0x00, 0x00, 0x50, 0x90, 0x04, 0x00, - 0x00, 0x00, 0x67, 0x51, 0x00, 0x00, - 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, - 0x00, 0x00, 0xb1, 0xc0, 0x00, 0x00, - 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, - /* ch = '@' */ - 0x00, 0x13, 0x5b, 0x67, 0x1b, 0x00, - 0x1f, 0xd4, 0x25, 0x1b, 0xdb, 0x22, - 0x7c, 0x43, 0x04, 0x25, 0x87, 0x5f, - 0xcf, 0x26, 0xc4, 0x5a, 0x68, 0x5f, - 0xf7, 0x32, 0xd9, 0x00, 0x5f, 0x5f, - 0xb1, 0x35, 0x94, 0xdd, 0xcf, 0x51, - 0x44, 0xa5, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x66, 0xe5, 0x74, 0xd4, 0x1a, - 0x00, 0x00, 0x04, 0x15, 0x04, 0x00, - /* ch = 'A' */ - 0x00, 0x00, 0x39, 0x04, 0x00, 0x00, - 0x00, 0x00, 0xcf, 0x3b, 0x00, 0x00, - 0x00, 0x24, 0xff, 0x9e, 0x00, 0x00, - 0x00, 0x6b, 0x64, 0xf7, 0x1c, 0x00, - 0x00, 0xe5, 0x1f, 0x7c, 0x54, 0x00, - 0x2c, 0xef, 0xa2, 0xbd, 0xe0, 0x00, - 0x70, 0x5f, 0x00, 0x04, 0xe5, 0x29, - 0xe5, 0x24, 0x00, 0x00, 0x6b, 0x82, - /* ch = 'B' */ - 0x2d, 0x36, 0x36, 0x36, 0x08, 0x00, - 0xb7, 0x46, 0x15, 0x6a, 0xf7, 0x04, - 0xb7, 0x3b, 0x00, 0x04, 0xff, 0x24, - 0xb7, 0x73, 0x36, 0x94, 0x84, 0x04, - 0xb7, 0x62, 0x36, 0x77, 0xc0, 0x04, - 0xb7, 0x3b, 0x00, 0x00, 0xb7, 0x50, - 0xb7, 0x3b, 0x00, 0x04, 0xcf, 0x43, - 0xb7, 0xe5, 0xcf, 0xdd, 0x73, 0x04, - /* ch = 'C' */ - 0x00, 0x0c, 0x47, 0x5b, 0x1b, 0x00, - 0x10, 0xdb, 0x47, 0x20, 0xdb, 0x3b, - 0x5a, 0x82, 0x00, 0x00, 0x1e, 0x13, - 0xb1, 0x3f, 0x00, 0x00, 0x00, 0x00, - 0xb7, 0x3b, 0x00, 0x00, 0x00, 0x00, - 0x90, 0x5f, 0x00, 0x00, 0x00, 0x00, - 0x39, 0xe0, 0x04, 0x00, 0x3d, 0x13, - 0x00, 0x66, 0xef, 0x9e, 0xbb, 0x19, - 0x00, 0x00, 0x08, 0x0f, 0x00, 0x00, - /* ch = 'D' */ - 0x26, 0x36, 0x36, 0x2a, 0x04, 0x00, - 0x7c, 0x68, 0x20, 0x99, 0x90, 0x00, - 0x7c, 0x5f, 0x00, 0x0d, 0xe5, 0x2c, - 0x7c, 0x5f, 0x00, 0x00, 0x90, 0x5a, - 0x7c, 0x5f, 0x00, 0x00, 0x7c, 0x5f, - 0x7c, 0x5f, 0x00, 0x00, 0xa7, 0x47, - 0x7c, 0x5f, 0x00, 0x26, 0xf7, 0x16, - 0x7c, 0xc8, 0x9e, 0xc4, 0x2e, 0x00, - /* ch = 'E' */ - 0x26, 0x36, 0x36, 0x36, 0x36, 0x16, - 0x7c, 0x68, 0x15, 0x15, 0x15, 0x0c, - 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0x6d, 0x15, 0x15, 0x0f, 0x00, - 0x7c, 0x82, 0x36, 0x36, 0x2d, 0x00, - 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0xef, 0xcf, 0xcf, 0xcf, 0x32, - /* ch = 'F' */ - 0x16, 0x36, 0x36, 0x36, 0x36, 0x0d, - 0x32, 0xcf, 0x15, 0x15, 0x15, 0x08, - 0x32, 0xcf, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xea, 0x36, 0x36, 0x1e, 0x00, - 0x32, 0xcf, 0x36, 0x36, 0x26, 0x00, - 0x32, 0xcf, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xcf, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xcf, 0x00, 0x00, 0x00, 0x00, - /* ch = 'G' */ - 0x00, 0x13, 0x50, 0x5b, 0x1b, 0x00, - 0x1c, 0xe5, 0x3f, 0x25, 0xdb, 0x36, - 0x6b, 0x6f, 0x00, 0x00, 0x1e, 0x10, - 0xb7, 0x3b, 0x00, 0x00, 0x00, 0x00, - 0xb7, 0x3b, 0x00, 0x74, 0x74, 0x30, - 0xa0, 0x47, 0x00, 0x15, 0x88, 0x5f, - 0x44, 0xcf, 0x04, 0x00, 0x7c, 0x5f, - 0x04, 0x7e, 0xef, 0x9e, 0xe5, 0x32, - 0x00, 0x00, 0x04, 0x0f, 0x00, 0x00, - /* ch = 'H' */ - 0x26, 0x30, 0x00, 0x00, 0x2d, 0x16, - 0x7c, 0x5f, 0x00, 0x00, 0xb7, 0x3b, - 0x7c, 0x5f, 0x00, 0x00, 0xb7, 0x3b, - 0x7c, 0x6d, 0x15, 0x15, 0xbd, 0x3b, - 0x7c, 0x82, 0x36, 0x36, 0xcf, 0x3b, - 0x7c, 0x5f, 0x00, 0x00, 0xb7, 0x3b, - 0x7c, 0x5f, 0x00, 0x00, 0xb7, 0x3b, - 0x7c, 0x5f, 0x00, 0x00, 0xb7, 0x3b, - /* ch = 'I' */ - 0x16, 0x36, 0x36, 0x36, 0x2d, - 0x08, 0x15, 0xbd, 0x46, 0x15, - 0x00, 0x00, 0xb7, 0x3b, 0x00, - 0x00, 0x00, 0xb7, 0x3b, 0x00, - 0x00, 0x00, 0xb7, 0x3b, 0x00, - 0x00, 0x00, 0xb7, 0x3b, 0x00, - 0x00, 0x00, 0xb7, 0x3b, 0x00, - 0x22, 0x74, 0xe5, 0xb1, 0x58, - /* ch = 'J' */ - 0x16, 0x36, 0x36, 0x36, 0x1e, - 0x08, 0x15, 0xbd, 0x46, 0x0f, - 0x00, 0x00, 0xb7, 0x3b, 0x00, - 0x00, 0x00, 0xb7, 0x3b, 0x00, - 0x00, 0x00, 0xb7, 0x3b, 0x00, - 0x00, 0x00, 0xb7, 0x3b, 0x00, - 0x10, 0x04, 0xe5, 0x32, 0x00, - 0xef, 0xab, 0x99, 0x0d, 0x00, - 0x08, 0x12, 0x00, 0x00, 0x00, - /* ch = 'K' */ - 0x2d, 0x1c, 0x00, 0x04, 0x5b, 0x26, - 0xb7, 0x3b, 0x04, 0x7c, 0x8a, 0x04, - 0xb7, 0x3b, 0x7c, 0x8a, 0x04, 0x00, - 0xb7, 0xc8, 0xb7, 0x10, 0x00, 0x00, - 0xb7, 0xbb, 0xf7, 0x24, 0x00, 0x00, - 0xb7, 0x3b, 0x50, 0xcf, 0x04, 0x00, - 0xb7, 0x3b, 0x04, 0xb1, 0x6f, 0x00, - 0xb7, 0x3b, 0x00, 0x1c, 0xf7, 0x3b, - /* ch = 'L' */ - 0x1e, 0x39, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xf7, 0xcf, 0xcf, 0xcf, 0x32, - /* ch = 'M' */ - 0x2d, 0x10, 0x00, 0x00, 0x21, 0x1e, - 0xb7, 0x82, 0x00, 0x04, 0xdb, 0x5f, - 0xb7, 0xff, 0x24, 0x48, 0xff, 0x5f, - 0xb7, 0xb7, 0xa5, 0xdb, 0xb7, 0x5f, - 0xb7, 0x47, 0xe5, 0x6f, 0x7c, 0x5f, - 0xb7, 0x3b, 0x21, 0x19, 0x7c, 0x5f, - 0xb7, 0x3b, 0x00, 0x00, 0x7c, 0x5f, - 0xb7, 0x3b, 0x00, 0x00, 0x7c, 0x5f, - /* ch = 'N' */ - 0x26, 0x21, 0x00, 0x00, 0x2d, 0x28, - 0x7c, 0xf7, 0x0d, 0x00, 0xb7, 0x3b, - 0x7c, 0xf7, 0x6f, 0x00, 0xb7, 0x3b, - 0x7c, 0x5f, 0xff, 0x1c, 0xb7, 0x3b, - 0x7c, 0x3b, 0x6b, 0x90, 0xb7, 0x3b, - 0x7c, 0x3b, 0x10, 0xf7, 0xff, 0x3b, - 0x7c, 0x3b, 0x00, 0x50, 0xff, 0x3b, - 0x7c, 0x3b, 0x00, 0x04, 0xc8, 0x3b, - /* ch = 'O' */ - 0x00, 0x1b, 0x67, 0x50, 0x08, 0x00, - 0x24, 0xef, 0x37, 0x5f, 0xf7, 0x0d, - 0x8a, 0x54, 0x00, 0x00, 0xa7, 0x50, - 0xe5, 0x26, 0x00, 0x00, 0x5f, 0x8a, - 0xff, 0x24, 0x00, 0x00, 0x50, 0x90, - 0xbd, 0x3f, 0x00, 0x00, 0x6b, 0x6f, - 0x5a, 0xa5, 0x00, 0x10, 0xe5, 0x32, - 0x04, 0xa2, 0xe5, 0xef, 0x65, 0x04, - 0x00, 0x00, 0x0c, 0x08, 0x00, 0x00, - /* ch = 'P' */ - 0x26, 0x36, 0x36, 0x36, 0x13, 0x00, - 0x7c, 0x82, 0x36, 0x4f, 0xff, 0x22, - 0x7c, 0x5f, 0x00, 0x00, 0x97, 0x5a, - 0x7c, 0x5f, 0x00, 0x16, 0xe5, 0x2f, - 0x7c, 0xb1, 0x74, 0x74, 0x3f, 0x00, - 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x00, - /* ch = 'Q' */ - 0x00, 0x1b, 0x67, 0x50, 0x08, 0x00, - 0x24, 0xe5, 0x31, 0x5a, 0xf7, 0x0d, - 0x8a, 0x54, 0x00, 0x00, 0xa7, 0x50, - 0xe5, 0x26, 0x00, 0x00, 0x54, 0x8a, - 0xff, 0x24, 0x00, 0x00, 0x50, 0x90, - 0xbd, 0x3b, 0x00, 0x00, 0x6b, 0x6f, - 0x5a, 0xa5, 0x00, 0x08, 0xe5, 0x32, - 0x04, 0x94, 0xd4, 0xe5, 0x65, 0x04, - 0x00, 0x00, 0x6b, 0x74, 0x00, 0x00, - 0x00, 0x00, 0x16, 0x8f, 0xcf, 0x36, - /* ch = 'R' */ - 0x26, 0x36, 0x36, 0x36, 0x13, 0x00, - 0x7c, 0x82, 0x36, 0x5a, 0xff, 0x13, - 0x7c, 0x5f, 0x00, 0x00, 0xbd, 0x3b, - 0x7c, 0x5f, 0x00, 0x24, 0xf7, 0x1f, - 0x7c, 0xb1, 0x9c, 0xec, 0x2e, 0x00, - 0x7c, 0x5f, 0x04, 0xe5, 0x32, 0x00, - 0x7c, 0x5f, 0x00, 0x48, 0xbd, 0x00, - 0x7c, 0x5f, 0x00, 0x04, 0xe5, 0x35, - /* ch = 'S' */ - 0x00, 0x16, 0x47, 0x47, 0x16, 0x00, - 0x1c, 0xef, 0x31, 0x2b, 0xe5, 0x17, - 0x4d, 0xc6, 0x00, 0x00, 0x0f, 0x00, - 0x10, 0xdb, 0x8a, 0x16, 0x00, 0x00, - 0x00, 0x08, 0x3f, 0xd4, 0x92, 0x04, - 0x00, 0x00, 0x00, 0x04, 0xc8, 0x43, - 0x2a, 0x21, 0x00, 0x04, 0xb7, 0x43, - 0x2c, 0xef, 0x9e, 0xcb, 0x94, 0x10, - 0x00, 0x00, 0x0f, 0x0c, 0x00, 0x00, - /* ch = 'T' */ - 0x36, 0x36, 0x36, 0x36, 0x36, 0x1e, - 0x15, 0x15, 0xbd, 0x46, 0x15, 0x0f, - 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, - /* ch = 'U' */ - 0x26, 0x1e, 0x00, 0x00, 0x26, 0x1e, - 0x7c, 0x5f, 0x00, 0x00, 0x7c, 0x5f, - 0x7c, 0x5f, 0x00, 0x00, 0x7c, 0x5f, - 0x7c, 0x5f, 0x00, 0x00, 0x7c, 0x5f, - 0x7c, 0x5f, 0x00, 0x00, 0x7c, 0x5f, - 0x7c, 0x5f, 0x00, 0x00, 0x7c, 0x5f, - 0x6b, 0x82, 0x00, 0x04, 0xc8, 0x39, - 0x10, 0xcb, 0xbb, 0xbb, 0x84, 0x04, - 0x00, 0x00, 0x0f, 0x0c, 0x00, 0x00, - /* ch = 'V' */ - 0x33, 0x10, 0x00, 0x00, 0x1e, 0x26, - 0x8a, 0x5f, 0x00, 0x00, 0x90, 0x47, - 0x39, 0xcf, 0x00, 0x0d, 0xff, 0x16, - 0x0d, 0xf7, 0x24, 0x39, 0xa5, 0x00, - 0x00, 0x8a, 0x5f, 0x7c, 0x47, 0x00, - 0x00, 0x32, 0xcf, 0xf7, 0x16, 0x00, - 0x00, 0x04, 0xf7, 0xa5, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x47, 0x00, 0x00, - /* ch = 'W' */ - 0x36, 0x00, 0x00, 0x00, 0x0d, 0x2d, - 0xf7, 0x22, 0x44, 0x47, 0x32, 0x97, - 0xb1, 0x39, 0x90, 0x7c, 0x4d, 0x64, - 0x7c, 0x5f, 0xef, 0xea, 0x6b, 0x3f, - 0x50, 0xf7, 0x90, 0xe5, 0xcf, 0x2c, - 0x32, 0xff, 0x50, 0x7c, 0xff, 0x16, - 0x1c, 0xff, 0x24, 0x3b, 0xcf, 0x0d, - 0x00, 0xcf, 0x0d, 0x1a, 0xb7, 0x00, - /* ch = 'X' */ - 0x39, 0x21, 0x00, 0x00, 0x30, 0x13, - 0x2a, 0xff, 0x0d, 0x32, 0xc8, 0x0d, - 0x00, 0x90, 0x6f, 0xc8, 0x43, 0x00, - 0x00, 0x1c, 0xff, 0xb7, 0x0d, 0x00, - 0x00, 0x04, 0xe5, 0x90, 0x00, 0x00, - 0x00, 0x50, 0xb1, 0xf7, 0x2c, 0x00, - 0x10, 0xf7, 0x2c, 0x50, 0xb7, 0x00, - 0x5f, 0x90, 0x00, 0x04, 0xdb, 0x3f, - /* ch = 'Y' */ - 0x44, 0x19, 0x00, 0x00, 0x26, 0x24, - 0x50, 0xbd, 0x00, 0x0d, 0xe5, 0x29, - 0x0d, 0xe5, 0x35, 0x48, 0x9e, 0x04, - 0x00, 0x48, 0xbd, 0xc8, 0x35, 0x00, - 0x00, 0x04, 0xe5, 0xb7, 0x04, 0x00, - 0x00, 0x00, 0x7c, 0x5f, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x5f, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x5f, 0x00, 0x00, - /* ch = 'Z' */ - 0x26, 0x36, 0x36, 0x36, 0x36, 0x16, - 0x0f, 0x15, 0x15, 0x25, 0xf7, 0x1f, - 0x00, 0x00, 0x00, 0x90, 0x64, 0x00, - 0x00, 0x00, 0x2f, 0xdb, 0x10, 0x00, - 0x00, 0x04, 0xdb, 0x39, 0x00, 0x00, - 0x00, 0x5f, 0x9e, 0x04, 0x00, 0x00, - 0x1c, 0xf7, 0x1f, 0x00, 0x00, 0x00, - 0x77, 0xff, 0xcf, 0xcf, 0xcf, 0x4e, - /* ch = '[' */ - 0xb7, 0x9c, 0x74, 0x74, 0x0d, - 0xb7, 0x3b, 0x00, 0x00, 0x00, - 0xb7, 0x3b, 0x00, 0x00, 0x00, - 0xb7, 0x3b, 0x00, 0x00, 0x00, - 0xb7, 0x3b, 0x00, 0x00, 0x00, - 0xb7, 0x3b, 0x00, 0x00, 0x00, - 0xb7, 0x3b, 0x00, 0x00, 0x00, - 0xb7, 0x3b, 0x00, 0x00, 0x00, - 0xb7, 0xb1, 0x74, 0x74, 0x00, - /* ch = '\' */ - 0x3a, 0x9e, 0x00, - 0x0d, 0xf7, 0x24, - 0x00, 0x6b, 0x82, - 0x00, 0x17, 0xff, - 0x00, 0x00, 0x7c, - 0x00, 0x00, 0x22, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* ch = ']' */ - 0x22, 0x74, 0x74, 0xc8, 0x5f, - 0x00, 0x00, 0x00, 0x7c, 0x5f, - 0x00, 0x00, 0x00, 0x7c, 0x5f, - 0x00, 0x00, 0x00, 0x7c, 0x5f, - 0x00, 0x00, 0x00, 0x7c, 0x5f, - 0x00, 0x00, 0x00, 0x7c, 0x5f, - 0x00, 0x00, 0x00, 0x7c, 0x5f, - 0x00, 0x00, 0x00, 0x7c, 0x5f, - 0x22, 0x74, 0x74, 0xc8, 0x5f, - /* ch = '^' */ - 0x00, 0x00, 0x21, 0x16, 0x00, - 0x00, 0x04, 0xdb, 0xa5, 0x00, - 0x00, 0x5f, 0x7c, 0xc8, 0x32, - 0x0a, 0xbd, 0x16, 0x2f, 0x82, - /* ch = '_' */ - /* ch = '`' */ - 0x55, 0x6a, 0x00, - 0x22, 0xff, 0x24, - 0x00, 0x73, 0x6c, - /* ch = 'a' */ - 0x00, 0x2a, 0x74, 0x67, 0x1b, 0x00, - 0x0d, 0x8d, 0x20, 0x31, 0xff, 0x13, - 0x00, 0x00, 0x15, 0x15, 0xff, 0x24, - 0x24, 0xdd, 0x50, 0x36, 0xd9, 0x24, - 0x7c, 0x64, 0x00, 0x10, 0xff, 0x24, - 0x32, 0xef, 0x82, 0xd4, 0xff, 0x24, - 0x00, 0x08, 0x15, 0x00, 0x00, 0x00, - /* ch = 'b' */ - 0x7c, 0x90, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0x90, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0xab, 0x5b, 0x67, 0x1b, 0x00, - 0x7c, 0xe5, 0x25, 0x3f, 0xff, 0x1c, - 0x7c, 0x90, 0x00, 0x00, 0xbd, 0x50, - 0x7c, 0x90, 0x00, 0x00, 0xa7, 0x5f, - 0x7c, 0xab, 0x00, 0x10, 0xe5, 0x32, - 0x7c, 0xbb, 0xbb, 0xe5, 0x84, 0x04, - 0x00, 0x00, 0x0c, 0x0f, 0x00, 0x00, - /* ch = 'c' */ - 0x00, 0x13, 0x5b, 0x74, 0x31, 0x00, - 0x17, 0xef, 0x3f, 0x1a, 0xb1, 0x33, - 0x5f, 0x97, 0x00, 0x00, 0x0c, 0x04, - 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x39, 0xf7, 0x08, 0x00, 0x21, 0x00, - 0x00, 0x73, 0xef, 0xab, 0xd4, 0x24, - 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, - /* ch = 'd' */ - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x3b, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x3b, - 0x00, 0x2e, 0x74, 0x48, 0xbd, 0x3b, - 0x3b, 0xb7, 0x20, 0x54, 0xff, 0x3b, - 0x90, 0x50, 0x00, 0x00, 0xff, 0x3b, - 0xb1, 0x47, 0x00, 0x00, 0xff, 0x3b, - 0x6b, 0x97, 0x00, 0x1f, 0xff, 0x3b, - 0x10, 0xd4, 0xcb, 0xcb, 0xe5, 0x3b, - 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, - /* ch = 'e' */ - 0x00, 0x21, 0x74, 0x67, 0x19, 0x00, - 0x2a, 0xdb, 0x22, 0x37, 0xf7, 0x0d, - 0x77, 0x73, 0x15, 0x15, 0xc6, 0x39, - 0x8a, 0x82, 0x36, 0x36, 0x36, 0x1e, - 0x5a, 0xa5, 0x00, 0x00, 0x0c, 0x00, - 0x04, 0xa2, 0xcb, 0x8f, 0xbb, 0x13, - 0x00, 0x00, 0x0c, 0x0f, 0x00, 0x00, - /* ch = 'f' */ - 0x00, 0x73, 0xbb, 0xd4, 0x6c, - 0x2f, 0xcf, 0x0d, 0x04, 0x28, - 0x3e, 0xd9, 0x15, 0x0c, 0x00, - 0x9c, 0xe5, 0x74, 0x39, 0x00, - 0x32, 0xcf, 0x00, 0x00, 0x00, - 0x32, 0xcf, 0x00, 0x00, 0x00, - 0x32, 0xcf, 0x00, 0x00, 0x00, - 0x32, 0xcf, 0x00, 0x00, 0x00, - /* ch = 'g' */ - 0x00, 0x37, 0x74, 0x48, 0x5b, 0x42, - 0x40, 0xb1, 0x16, 0x82, 0x7b, 0x04, - 0x5f, 0x6f, 0x00, 0x54, 0x8a, 0x00, - 0x1c, 0xec, 0x9e, 0xd4, 0x26, 0x00, - 0x32, 0xab, 0x15, 0x04, 0x00, 0x00, - 0x22, 0xef, 0xcf, 0xcf, 0xdd, 0x10, - 0xa0, 0x3f, 0x00, 0x00, 0x88, 0x5a, - 0x44, 0xdd, 0x82, 0x9e, 0xa2, 0x16, - /* ch = 'h' */ - 0x50, 0x97, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x90, 0x3f, 0x74, 0x26, 0x00, - 0x50, 0xff, 0x47, 0x37, 0xff, 0x13, - 0x50, 0xb7, 0x00, 0x00, 0xff, 0x24, - 0x50, 0x90, 0x00, 0x00, 0xff, 0x24, - 0x50, 0x90, 0x00, 0x00, 0xff, 0x24, - 0x50, 0x90, 0x00, 0x00, 0xff, 0x24, - /* ch = 'i' */ - 0x00, 0x00, 0x87, 0x67, 0x00, - 0x00, 0x00, 0x22, 0x21, 0x00, - 0x00, 0x36, 0x36, 0x1e, 0x00, - 0x00, 0x15, 0x88, 0x5f, 0x00, - 0x00, 0x00, 0x7c, 0x5f, 0x00, - 0x00, 0x00, 0x7c, 0x5f, 0x00, - 0x00, 0x00, 0x7c, 0x5f, 0x00, - 0x14, 0x74, 0xc8, 0xc8, 0x58, - /* ch = 'j' */ - 0x00, 0x00, 0x00, 0xab, 0x5b, - 0x00, 0x00, 0x00, 0x28, 0x21, - 0x00, 0x2d, 0x36, 0x36, 0x1e, - 0x00, 0x12, 0x15, 0xbd, 0x5f, - 0x00, 0x00, 0x00, 0xb7, 0x5f, - 0x00, 0x00, 0x00, 0xb7, 0x5f, - 0x00, 0x00, 0x00, 0xb7, 0x5f, - 0x00, 0x00, 0x00, 0xb7, 0x5a, - 0x19, 0x10, 0x00, 0xcf, 0x39, - 0x51, 0xef, 0xcb, 0x94, 0x10, - /* ch = 'k' */ - 0x50, 0x97, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x90, 0x00, 0x10, 0x50, 0x10, - 0x50, 0x90, 0x13, 0xd4, 0x3f, 0x00, - 0x50, 0xcf, 0xdb, 0x3f, 0x00, 0x00, - 0x50, 0xdb, 0xb1, 0x90, 0x00, 0x00, - 0x50, 0x90, 0x10, 0xdb, 0x5f, 0x00, - 0x50, 0x90, 0x00, 0x1f, 0xf7, 0x3b, - /* ch = 'l' */ - 0x2d, 0xcf, 0xf7, 0x5f, 0x00, - 0x00, 0x00, 0xb7, 0x5f, 0x00, - 0x00, 0x00, 0xb7, 0x5f, 0x00, - 0x00, 0x00, 0xb7, 0x5f, 0x00, - 0x00, 0x00, 0xb7, 0x5f, 0x00, - 0x00, 0x00, 0xb7, 0x5f, 0x00, - 0x00, 0x00, 0xb7, 0x5f, 0x00, - 0x22, 0x74, 0xe5, 0xc8, 0x74, - /* ch = 'm' */ - 0x2d, 0x50, 0x67, 0x37, 0x74, 0x19, - 0xb7, 0x64, 0x97, 0x90, 0x68, 0x8a, - 0xb7, 0x26, 0x7c, 0x5f, 0x50, 0x90, - 0xb7, 0x24, 0x7c, 0x5f, 0x50, 0x90, - 0xb7, 0x24, 0x7c, 0x5f, 0x50, 0x90, - 0xb7, 0x24, 0x7c, 0x5f, 0x50, 0x90, - /* ch = 'n' */ - 0x1e, 0x28, 0x3f, 0x74, 0x21, 0x00, - 0x50, 0xff, 0x47, 0x3a, 0xff, 0x13, - 0x50, 0xa5, 0x00, 0x00, 0xff, 0x24, - 0x50, 0x90, 0x00, 0x00, 0xff, 0x24, - 0x50, 0x90, 0x00, 0x00, 0xff, 0x24, - 0x50, 0x90, 0x00, 0x00, 0xff, 0x24, - /* ch = 'o' */ - 0x00, 0x1b, 0x67, 0x5b, 0x13, 0x00, - 0x2f, 0xdb, 0x25, 0x3f, 0xf7, 0x0d, - 0x90, 0x64, 0x00, 0x00, 0xa7, 0x50, - 0xb7, 0x50, 0x00, 0x00, 0x7c, 0x5f, - 0x6b, 0xa5, 0x00, 0x04, 0xe5, 0x35, - 0x10, 0xa9, 0xbb, 0xcb, 0x84, 0x04, - 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, - /* ch = 'p' */ - 0x26, 0x2a, 0x5b, 0x74, 0x1b, 0x00, - 0x7c, 0xe5, 0x25, 0x3f, 0xff, 0x1c, - 0x7c, 0x90, 0x00, 0x00, 0xa0, 0x5a, - 0x7c, 0x90, 0x00, 0x00, 0x7c, 0x5f, - 0x7c, 0xab, 0x00, 0x04, 0xcf, 0x3b, - 0x7c, 0xef, 0xbb, 0xd4, 0x84, 0x04, - 0x7c, 0x90, 0x0c, 0x12, 0x00, 0x00, - 0x7c, 0x90, 0x00, 0x00, 0x00, 0x00, - /* ch = 'q' */ - 0x00, 0x28, 0x74, 0x50, 0x30, 0x16, - 0x35, 0xdb, 0x20, 0x43, 0xff, 0x3b, - 0xa0, 0x50, 0x00, 0x00, 0xff, 0x3b, - 0xb7, 0x47, 0x00, 0x00, 0xff, 0x3b, - 0x6b, 0xa5, 0x00, 0x17, 0xff, 0x3b, - 0x10, 0xd4, 0xcb, 0xdd, 0xe5, 0x3b, - 0x00, 0x00, 0x12, 0x00, 0xb7, 0x3b, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x3b, - /* ch = 'r' */ - 0x0d, 0x36, 0x26, 0x74, 0x5b, 0x10, - 0x1c, 0xff, 0xc4, 0x25, 0x50, 0x2c, - 0x1c, 0xff, 0x2e, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x10, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x0d, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x0d, 0x00, 0x00, 0x00, - /* ch = 's' */ - 0x00, 0x22, 0x74, 0x74, 0x22, 0x00, - 0x22, 0xff, 0x1e, 0x1e, 0xc4, 0x13, - 0x17, 0xf7, 0x6a, 0x18, 0x00, 0x00, - 0x00, 0x0c, 0x50, 0xcb, 0xc0, 0x04, - 0x1f, 0x24, 0x00, 0x04, 0xff, 0x2f, - 0x2f, 0xef, 0x9e, 0xbb, 0x94, 0x10, - 0x00, 0x00, 0x0f, 0x0c, 0x00, 0x00, - /* ch = 't' */ - 0x00, 0x00, 0x04, 0x08, 0x00, - 0x00, 0x1a, 0xff, 0x1c, 0x00, - 0x1e, 0x4a, 0xff, 0x40, 0x2d, - 0x0c, 0x2a, 0xff, 0x1a, 0x15, - 0x00, 0x32, 0xcf, 0x04, 0x00, - 0x00, 0x32, 0xcf, 0x00, 0x00, - 0x00, 0x32, 0xff, 0x00, 0x08, - 0x00, 0x0d, 0xd4, 0xdd, 0xdd, - 0x00, 0x00, 0x00, 0x0f, 0x00, - /* ch = 'u' */ - 0x1e, 0x26, 0x00, 0x00, 0x36, 0x0d, - 0x50, 0x90, 0x00, 0x00, 0xff, 0x24, - 0x6b, 0x90, 0x00, 0x00, 0xff, 0x24, - 0x7c, 0x90, 0x00, 0x00, 0xff, 0x24, - 0x4d, 0xa5, 0x00, 0x22, 0xff, 0x24, - 0x10, 0xd4, 0xa4, 0xc4, 0xff, 0x26, - 0x00, 0x00, 0x15, 0x04, 0x00, 0x00, - /* ch = 'v' */ - 0x2b, 0x1e, 0x00, 0x00, 0x26, 0x1c, - 0x48, 0xbd, 0x00, 0x00, 0xcf, 0x29, - 0x0d, 0xff, 0x1f, 0x2c, 0xb7, 0x04, - 0x00, 0x8a, 0x6a, 0x8a, 0x43, 0x00, - 0x00, 0x2c, 0xff, 0xe5, 0x10, 0x00, - 0x00, 0x00, 0xc8, 0x6a, 0x00, 0x00, - /* ch = 'w' */ - 0x36, 0x00, 0x00, 0x00, 0x16, 0x39, - 0xe5, 0x22, 0x7c, 0x50, 0x3b, 0x8a, - 0x90, 0x3f, 0xcf, 0xa5, 0x50, 0x5f, - 0x5f, 0xa5, 0xb7, 0xf7, 0xa5, 0x39, - 0x35, 0xff, 0x5f, 0x90, 0xff, 0x22, - 0x1a, 0xff, 0x2c, 0x44, 0xe5, 0x0d, - /* ch = 'x' */ - 0x24, 0x28, 0x00, 0x0d, 0x36, 0x09, - 0x10, 0xe5, 0x2c, 0x7c, 0x6f, 0x00, - 0x00, 0x32, 0xf7, 0xc8, 0x10, 0x00, - 0x00, 0x10, 0xec, 0x97, 0x00, 0x00, - 0x00, 0x90, 0x64, 0xc8, 0x47, 0x00, - 0x48, 0xb7, 0x10, 0x1f, 0xff, 0x24, - /* ch = 'y' */ - 0x39, 0x26, 0x00, 0x00, 0x28, 0x1e, - 0x39, 0xe0, 0x00, 0x00, 0xe5, 0x29, - 0x04, 0xe5, 0x29, 0x2c, 0xc8, 0x0d, - 0x00, 0x5a, 0x82, 0x70, 0x54, 0x00, - 0x00, 0x17, 0xff, 0xf7, 0x1f, 0x00, - 0x00, 0x00, 0xa0, 0x9e, 0x00, 0x00, - 0x0c, 0x00, 0xa7, 0x43, 0x00, 0x00, - 0xd4, 0xc4, 0xa9, 0x10, 0x00, 0x00, - /* ch = 'z' */ - 0x1e, 0x36, 0x36, 0x36, 0x36, 0x0d, - 0x0c, 0x15, 0x15, 0x67, 0xb1, 0x10, - 0x00, 0x00, 0x32, 0xdb, 0x19, 0x00, - 0x00, 0x1f, 0xef, 0x26, 0x00, 0x00, - 0x10, 0xdb, 0x3b, 0x00, 0x00, 0x00, - 0x77, 0xff, 0xcf, 0xcf, 0xcf, 0x32, - /* ch = '{' */ - 0x00, 0x28, 0x74, 0x58, - 0x22, 0xe5, 0x1b, 0x00, - 0x32, 0xcf, 0x00, 0x00, - 0x35, 0xc8, 0x00, 0x00, - 0xa9, 0x3b, 0x00, 0x00, - 0x90, 0x5a, 0x00, 0x00, - 0x35, 0xc8, 0x00, 0x00, - 0x3b, 0xcf, 0x00, 0x00, - 0x2f, 0xea, 0x04, 0x00, - 0x04, 0x8d, 0xcf, 0xa4, - /* ch = '|' */ - 0x67, 0x32, - 0x7c, 0x3b, - 0x7c, 0x3b, - 0x7c, 0x3b, - 0x7c, 0x3b, - 0x7c, 0x3b, - 0x7c, 0x3b, - 0x7c, 0x3b, - 0x7c, 0x3b, - 0x67, 0x36, - /* ch = '}' */ - 0x14, 0x74, 0x67, 0x13, - 0x00, 0x00, 0x37, 0xe0, - 0x00, 0x00, 0x1c, 0xff, - 0x00, 0x00, 0x1a, 0xff, - 0x00, 0x00, 0x00, 0x77, - 0x00, 0x00, 0x00, 0xb1, - 0x00, 0x00, 0x1a, 0xff, - 0x00, 0x00, 0x1c, 0xff, - 0x00, 0x00, 0x26, 0xf7, - 0x1a, 0xcf, 0xc6, 0x50, - /* ch = '~' */ - 0x08, 0x5b, 0x50, 0x08, 0x19, 0x19, - 0x64, 0x47, 0x5a, 0xef, 0xe5, 0x35, - 0x00, 0x00, 0x00, 0x08, 0x08, 0x00 + /* ch = '!' */ + 0x00, 0xe5, 0x4d, 0x00, 0xff, 0x5f, 0x00, 0xe5, 0x3f, 0x00, 0xb7, 0x3b, + 0x00, 0xb7, 0x32, 0x00, 0x58, 0x1c, 0x00, 0x15, 0x08, 0x17, 0xff, 0x66, + 0x00, 0x0f, 0x04, + /* ch = '"' */ + 0x77, 0x77, 0x66, 0x97, 0x7c, 0x6a, 0x54, 0x7c, 0xc8, 0x29, 0xa7, 0x35, + /* ch = '#' */ + 0x00, 0x16, 0x58, 0x10, 0x2d, 0x00, 0x00, 0x32, 0x90, 0x32, 0xa5, 0x00, + 0x2d, 0x82, 0xab, 0x7b, 0xbd, 0x26, 0x12, 0x7b, 0x64, 0x6d, 0x5f, 0x00, + 0x00, 0x82, 0x3b, 0x7c, 0x3f, 0x00, 0xa2, 0xef, 0x7c, 0xdb, 0x82, 0x39, + 0x00, 0xf7, 0x16, 0xe5, 0x22, 0x00, 0x09, 0xcf, 0x10, 0xdd, 0x0d, 0x00, + /* ch = '$' */ + 0x00, 0x00, 0x45, 0x57, 0x00, 0x00, 0x04, 0x94, 0xe5, 0xe5, 0xd4, 0x10, + 0x32, 0xcf, 0x50, 0x5f, 0x28, 0x0d, 0x17, 0xef, 0xdb, 0x5f, 0x00, 0x00, + 0x00, 0x0c, 0x82, 0xf7, 0xa2, 0x04, 0x00, 0x00, 0x50, 0x5f, 0x97, 0x5a, + 0x32, 0x5a, 0x50, 0x68, 0xb7, 0x43, 0x10, 0x73, 0xe5, 0xe5, 0x50, 0x04, + 0x00, 0x00, 0x30, 0x39, 0x00, 0x00, + /* ch = '%' */ + 0x26, 0x74, 0x26, 0x00, 0x28, 0x28, 0xe5, 0x3f, 0xff, 0x1c, 0xdb, 0x10, + 0xc8, 0x58, 0xdb, 0xa5, 0x47, 0x00, 0x19, 0x5b, 0x4f, 0xb7, 0x0d, 0x00, + 0x00, 0x00, 0xb7, 0x32, 0x00, 0x00, 0x00, 0x3b, 0xa5, 0xb1, 0xd4, 0x40, + 0x04, 0xdb, 0x3b, 0xcf, 0x32, 0xc8, 0x54, 0x7c, 0x04, 0xd4, 0xc4, 0x5a, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, + /* ch = '&' */ + 0x00, 0x22, 0x74, 0x28, 0x00, 0x00, 0x14, 0xff, 0x31, 0xe5, 0x2f, 0x00, + 0x1a, 0xff, 0x16, 0xcf, 0x32, 0x00, 0x00, 0x7c, 0xef, 0x8a, 0x04, 0x00, + 0x1f, 0xe5, 0xdb, 0x3f, 0x16, 0x13, 0x99, 0x54, 0x1f, 0xf7, 0xb1, 0x6f, + 0xb7, 0x4a, 0x00, 0x74, 0xea, 0x13, 0x40, 0xf7, 0xc4, 0xbb, 0x9e, 0x6c, + 0x00, 0x08, 0x0f, 0x00, 0x08, 0x08, + /* ch = ''' */ + 0x4d, 0xb1, 0x50, 0x90, 0x90, 0x3b, + /* ch = '(' */ + 0x00, 0x48, 0xd4, 0x50, 0xb1, 0x13, 0xf7, 0x1f, 0x00, 0xa5, 0x00, 0x00, + 0x5f, 0x00, 0x00, 0x64, 0x00, 0x00, 0xb7, 0x00, 0x00, 0xf7, 0x2c, 0x00, + 0x4d, 0xf7, 0x10, 0x00, 0x48, 0xe5, + /* ch = ')' */ + 0x2d, 0xd4, 0x19, 0x00, 0x3b, 0xf7, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x0d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x54, + 0x00, 0x35, 0xef, 0x33, 0xd4, 0x21, + /* ch = '*' */ + 0x00, 0x00, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x50, 0x00, 0x00, + 0x78, 0xa2, 0xa5, 0x82, 0xbb, 0x39, 0x00, 0x12, 0xea, 0x8d, 0x0c, 0x00, + 0x00, 0x7c, 0x5f, 0xb1, 0x3b, 0x00, 0x10, 0x8d, 0x0d, 0x24, 0x65, 0x04, + /* ch = '+' */ + 0x00, 0x00, 0x0f, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x5f, 0x00, 0x00, + 0x12, 0x15, 0x88, 0x6d, 0x15, 0x0c, 0x58, 0x74, 0xc8, 0xb1, 0x74, 0x39, + 0x00, 0x00, 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x67, 0x51, 0x00, 0x00, + /* ch = ',' */ + 0x00, 0x12, 0x04, 0x17, 0xff, 0x7c, 0x00, 0x7c, 0x54, 0x17, 0xa9, 0x10, + /* ch = '-' */ + 0x0c, 0x15, 0x15, 0x15, 0x15, 0x04, 0x30, 0x74, 0x74, 0x74, 0x74, 0x1c, + /* ch = '.' */ + 0x00, 0x12, 0x08, 0x17, 0xff, 0x5a, 0x00, 0x0f, 0x04, + /* ch = '/' */ + 0x0d, 0xef, 0x17, 0x48, 0x9e, 0x00, 0xe5, 0x32, 0x00, 0xb7, 0x04, 0x00, + 0x3b, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + /* ch = '0' */ + 0x00, 0x10, 0x50, 0x37, 0x04, 0x00, 0x0d, 0xdb, 0x47, 0x8a, 0x8a, 0x00, + 0x44, 0x9e, 0x00, 0x35, 0xff, 0x1c, 0x7c, 0x50, 0x1f, 0xd4, 0xc8, 0x3b, + 0x7c, 0x4a, 0xdb, 0x3b, 0x7c, 0x3b, 0x6b, 0xff, 0x5f, 0x00, 0xb1, 0x39, + 0x2c, 0xff, 0x08, 0x17, 0xf7, 0x16, 0x00, 0x77, 0xd4, 0xe5, 0x3b, 0x00, + 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, + /* ch = '1' */ + 0x00, 0x00, 0x2a, 0x26, 0x1a, 0xc4, 0xd4, 0x90, 0x00, 0x00, 0x50, 0x90, + 0x00, 0x00, 0x50, 0x90, 0x00, 0x00, 0x50, 0x90, 0x00, 0x00, 0x50, 0x90, + 0x00, 0x00, 0x50, 0x90, 0x00, 0x00, 0x50, 0x90, + /* ch = '2' */ + 0x00, 0x1b, 0x50, 0x47, 0x08, 0x00, 0x25, 0xd4, 0x2a, 0x6a, 0xc8, 0x00, + 0x00, 0x0f, 0x00, 0x00, 0xff, 0x24, 0x00, 0x00, 0x00, 0x24, 0xe5, 0x10, + 0x00, 0x00, 0x19, 0xd4, 0x3b, 0x00, 0x00, 0x1f, 0xd4, 0x35, 0x00, 0x00, + 0x04, 0xb7, 0x3f, 0x00, 0x00, 0x00, 0x40, 0xff, 0xd4, 0xcf, 0xcf, 0x32, + /* ch = '3' */ + 0x00, 0x1e, 0x50, 0x30, 0x04, 0x00, 0x10, 0x9e, 0x30, 0x8a, 0x8a, 0x00, + 0x00, 0x00, 0x00, 0x21, 0xcf, 0x09, 0x00, 0x04, 0x20, 0xb1, 0x5a, 0x00, + 0x00, 0x0d, 0x3e, 0xc4, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x17, 0xff, 0x0d, + 0x04, 0x21, 0x00, 0x24, 0xf7, 0x0d, 0x27, 0xef, 0xab, 0xe5, 0x50, 0x00, + 0x00, 0x00, 0x12, 0x08, 0x00, 0x00, + /* ch = '4' */ + 0x00, 0x00, 0x00, 0x28, 0x1e, 0x00, 0x00, 0x00, 0x24, 0xff, 0x5f, 0x00, + 0x00, 0x04, 0xc0, 0xb7, 0x5f, 0x00, 0x00, 0x5f, 0x64, 0x7c, 0x5f, 0x00, + 0x24, 0xb7, 0x10, 0x7c, 0x5f, 0x00, 0xa0, 0xef, 0xcf, 0xef, 0xef, 0x4e, + 0x00, 0x00, 0x00, 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x5f, 0x00, + /* ch = '5' */ + 0x04, 0x36, 0x36, 0x36, 0x36, 0x00, 0x1c, 0xff, 0x1a, 0x15, 0x15, 0x04, + 0x1c, 0xcf, 0x0d, 0x00, 0x00, 0x00, 0x2a, 0xff, 0xb7, 0xcf, 0x35, 0x00, + 0x16, 0x50, 0x04, 0x21, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x3b, + 0x13, 0x3d, 0x00, 0x10, 0xf7, 0x29, 0x1f, 0xd4, 0xa4, 0xd4, 0x73, 0x04, + 0x00, 0x00, 0x0f, 0x0c, 0x00, 0x00, + /* ch = '6' */ + 0x00, 0x04, 0x47, 0x74, 0x22, 0x00, 0x00, 0xb1, 0x6a, 0x20, 0x7e, 0x10, + 0x2a, 0xcf, 0x0d, 0x00, 0x00, 0x00, 0x4d, 0xcf, 0xab, 0xcf, 0x2c, 0x00, + 0x50, 0xdb, 0x1b, 0x21, 0xff, 0x13, 0x50, 0x90, 0x00, 0x00, 0xbd, 0x2f, + 0x27, 0xff, 0x04, 0x0d, 0xf7, 0x1c, 0x00, 0x6b, 0xef, 0xd4, 0x5a, 0x00, + 0x00, 0x00, 0x08, 0x0c, 0x00, 0x00, + /* ch = '7' */ + 0x16, 0x36, 0x36, 0x36, 0x36, 0x0d, 0x16, 0x36, 0x36, 0x67, 0xe5, 0x10, + 0x00, 0x00, 0x00, 0x7c, 0x6a, 0x00, 0x00, 0x00, 0x0d, 0xf7, 0x1f, 0x00, + 0x00, 0x00, 0x48, 0xb7, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x47, 0x00, 0x00, + 0x00, 0x22, 0xff, 0x16, 0x00, 0x00, 0x00, 0x5a, 0xa5, 0x00, 0x00, 0x00, + /* ch = '8' */ + 0x00, 0x19, 0x67, 0x5b, 0x08, 0x00, 0x0d, 0xf7, 0x31, 0x54, 0xe0, 0x00, + 0x22, 0xff, 0x04, 0x1f, 0xf7, 0x0d, 0x00, 0xa9, 0xb1, 0xb1, 0x5a, 0x00, + 0x04, 0x94, 0x85, 0xd4, 0x5a, 0x00, 0x48, 0xa5, 0x00, 0x10, 0xf7, 0x29, + 0x5f, 0xab, 0x00, 0x0d, 0xe5, 0x2c, 0x10, 0xbb, 0xcb, 0xe5, 0x73, 0x04, + 0x00, 0x00, 0x0f, 0x0c, 0x00, 0x00, + /* ch = '9' */ + 0x00, 0x1b, 0x67, 0x3f, 0x04, 0x00, 0x17, 0xef, 0x31, 0x8a, 0x8a, 0x00, + 0x4d, 0x97, 0x00, 0x0d, 0xff, 0x1c, 0x44, 0xa5, 0x00, 0x04, 0xff, 0x24, + 0x10, 0xdb, 0x84, 0xbb, 0xff, 0x24, 0x00, 0x08, 0x15, 0x15, 0xff, 0x22, + 0x00, 0x0c, 0x00, 0x35, 0xc8, 0x0d, 0x1e, 0xe5, 0xab, 0xdd, 0x26, 0x00, + 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + /* ch = ':' */ + 0x1a, 0xff, 0x5a, 0x00, 0x25, 0x13, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, + 0x17, 0xff, 0x5a, 0x00, 0x0f, 0x04, + /* ch = ';' */ + 0x1a, 0xff, 0x5a, 0x00, 0x25, 0x13, 0x00, 0x00, 0x00, 0x00, 0x12, 0x04, + 0x17, 0xff, 0x7c, 0x00, 0x7c, 0x54, 0x17, 0xa9, 0x10, + /* ch = '<' */ + 0x00, 0x04, 0x3f, 0x4e, 0x37, 0xdd, 0x66, 0x13, 0x73, 0x16, 0x00, 0x00, + 0x1b, 0x00, 0x00, 0x00, 0xd4, 0x84, 0x08, 0x00, 0x04, 0x37, 0xef, 0x3e, + 0x00, 0x00, 0x08, 0x26, + /* ch = '=' */ + 0x12, 0x15, 0x15, 0x15, 0x15, 0x0c, 0x2d, 0x36, 0x36, 0x36, 0x36, 0x26, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0xcf, 0xcf, 0xcf, 0xcf, 0x4e, + /* ch = '>' */ + 0x87, 0x28, 0x00, 0x00, 0x1b, 0xa4, 0xcb, 0x1e, 0x00, 0x00, 0x1e, 0xa4, + 0x00, 0x00, 0x00, 0x37, 0x00, 0x1b, 0xbb, 0x94, 0x7f, 0xbb, 0x25, 0x00, + 0x28, 0x04, 0x00, 0x00, + /* ch = '?' */ + 0x08, 0x8d, 0xe5, 0xef, 0x4d, 0x00, 0x2f, 0x7e, 0x04, 0x26, 0xff, 0x1c, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x22, 0x00, 0x00, 0x04, 0xb1, 0x84, 0x04, + 0x00, 0x00, 0x50, 0x90, 0x04, 0x00, 0x00, 0x00, 0x67, 0x51, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0xb1, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, + /* ch = '@' */ + 0x00, 0x13, 0x5b, 0x67, 0x1b, 0x00, 0x1f, 0xd4, 0x25, 0x1b, 0xdb, 0x22, + 0x7c, 0x43, 0x04, 0x25, 0x87, 0x5f, 0xcf, 0x26, 0xc4, 0x5a, 0x68, 0x5f, + 0xf7, 0x32, 0xd9, 0x00, 0x5f, 0x5f, 0xb1, 0x35, 0x94, 0xdd, 0xcf, 0x51, + 0x44, 0xa5, 0x04, 0x00, 0x00, 0x00, 0x00, 0x66, 0xe5, 0x74, 0xd4, 0x1a, + 0x00, 0x00, 0x04, 0x15, 0x04, 0x00, + /* ch = 'A' */ + 0x00, 0x00, 0x39, 0x04, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x3b, 0x00, 0x00, + 0x00, 0x24, 0xff, 0x9e, 0x00, 0x00, 0x00, 0x6b, 0x64, 0xf7, 0x1c, 0x00, + 0x00, 0xe5, 0x1f, 0x7c, 0x54, 0x00, 0x2c, 0xef, 0xa2, 0xbd, 0xe0, 0x00, + 0x70, 0x5f, 0x00, 0x04, 0xe5, 0x29, 0xe5, 0x24, 0x00, 0x00, 0x6b, 0x82, + /* ch = 'B' */ + 0x2d, 0x36, 0x36, 0x36, 0x08, 0x00, 0xb7, 0x46, 0x15, 0x6a, 0xf7, 0x04, + 0xb7, 0x3b, 0x00, 0x04, 0xff, 0x24, 0xb7, 0x73, 0x36, 0x94, 0x84, 0x04, + 0xb7, 0x62, 0x36, 0x77, 0xc0, 0x04, 0xb7, 0x3b, 0x00, 0x00, 0xb7, 0x50, + 0xb7, 0x3b, 0x00, 0x04, 0xcf, 0x43, 0xb7, 0xe5, 0xcf, 0xdd, 0x73, 0x04, + /* ch = 'C' */ + 0x00, 0x0c, 0x47, 0x5b, 0x1b, 0x00, 0x10, 0xdb, 0x47, 0x20, 0xdb, 0x3b, + 0x5a, 0x82, 0x00, 0x00, 0x1e, 0x13, 0xb1, 0x3f, 0x00, 0x00, 0x00, 0x00, + 0xb7, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x90, 0x5f, 0x00, 0x00, 0x00, 0x00, + 0x39, 0xe0, 0x04, 0x00, 0x3d, 0x13, 0x00, 0x66, 0xef, 0x9e, 0xbb, 0x19, + 0x00, 0x00, 0x08, 0x0f, 0x00, 0x00, + /* ch = 'D' */ + 0x26, 0x36, 0x36, 0x2a, 0x04, 0x00, 0x7c, 0x68, 0x20, 0x99, 0x90, 0x00, + 0x7c, 0x5f, 0x00, 0x0d, 0xe5, 0x2c, 0x7c, 0x5f, 0x00, 0x00, 0x90, 0x5a, + 0x7c, 0x5f, 0x00, 0x00, 0x7c, 0x5f, 0x7c, 0x5f, 0x00, 0x00, 0xa7, 0x47, + 0x7c, 0x5f, 0x00, 0x26, 0xf7, 0x16, 0x7c, 0xc8, 0x9e, 0xc4, 0x2e, 0x00, + /* ch = 'E' */ + 0x26, 0x36, 0x36, 0x36, 0x36, 0x16, 0x7c, 0x68, 0x15, 0x15, 0x15, 0x0c, + 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x6d, 0x15, 0x15, 0x0f, 0x00, + 0x7c, 0x82, 0x36, 0x36, 0x2d, 0x00, 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x00, + 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xef, 0xcf, 0xcf, 0xcf, 0x32, + /* ch = 'F' */ + 0x16, 0x36, 0x36, 0x36, 0x36, 0x0d, 0x32, 0xcf, 0x15, 0x15, 0x15, 0x08, + 0x32, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x32, 0xea, 0x36, 0x36, 0x1e, 0x00, + 0x32, 0xcf, 0x36, 0x36, 0x26, 0x00, 0x32, 0xcf, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x32, 0xcf, 0x00, 0x00, 0x00, 0x00, + /* ch = 'G' */ + 0x00, 0x13, 0x50, 0x5b, 0x1b, 0x00, 0x1c, 0xe5, 0x3f, 0x25, 0xdb, 0x36, + 0x6b, 0x6f, 0x00, 0x00, 0x1e, 0x10, 0xb7, 0x3b, 0x00, 0x00, 0x00, 0x00, + 0xb7, 0x3b, 0x00, 0x74, 0x74, 0x30, 0xa0, 0x47, 0x00, 0x15, 0x88, 0x5f, + 0x44, 0xcf, 0x04, 0x00, 0x7c, 0x5f, 0x04, 0x7e, 0xef, 0x9e, 0xe5, 0x32, + 0x00, 0x00, 0x04, 0x0f, 0x00, 0x00, + /* ch = 'H' */ + 0x26, 0x30, 0x00, 0x00, 0x2d, 0x16, 0x7c, 0x5f, 0x00, 0x00, 0xb7, 0x3b, + 0x7c, 0x5f, 0x00, 0x00, 0xb7, 0x3b, 0x7c, 0x6d, 0x15, 0x15, 0xbd, 0x3b, + 0x7c, 0x82, 0x36, 0x36, 0xcf, 0x3b, 0x7c, 0x5f, 0x00, 0x00, 0xb7, 0x3b, + 0x7c, 0x5f, 0x00, 0x00, 0xb7, 0x3b, 0x7c, 0x5f, 0x00, 0x00, 0xb7, 0x3b, + /* ch = 'I' */ + 0x16, 0x36, 0x36, 0x36, 0x2d, 0x08, 0x15, 0xbd, 0x46, 0x15, 0x00, 0x00, + 0xb7, 0x3b, 0x00, 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, 0x00, 0xb7, 0x3b, + 0x00, 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x22, + 0x74, 0xe5, 0xb1, 0x58, + /* ch = 'J' */ + 0x16, 0x36, 0x36, 0x36, 0x1e, 0x08, 0x15, 0xbd, 0x46, 0x0f, 0x00, 0x00, + 0xb7, 0x3b, 0x00, 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, 0x00, 0xb7, 0x3b, + 0x00, 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x10, 0x04, 0xe5, 0x32, 0x00, 0xef, + 0xab, 0x99, 0x0d, 0x00, 0x08, 0x12, 0x00, 0x00, 0x00, + /* ch = 'K' */ + 0x2d, 0x1c, 0x00, 0x04, 0x5b, 0x26, 0xb7, 0x3b, 0x04, 0x7c, 0x8a, 0x04, + 0xb7, 0x3b, 0x7c, 0x8a, 0x04, 0x00, 0xb7, 0xc8, 0xb7, 0x10, 0x00, 0x00, + 0xb7, 0xbb, 0xf7, 0x24, 0x00, 0x00, 0xb7, 0x3b, 0x50, 0xcf, 0x04, 0x00, + 0xb7, 0x3b, 0x04, 0xb1, 0x6f, 0x00, 0xb7, 0x3b, 0x00, 0x1c, 0xf7, 0x3b, + /* ch = 'L' */ + 0x1e, 0x39, 0x00, 0x00, 0x00, 0x00, 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf7, 0xcf, 0xcf, 0xcf, 0x32, + /* ch = 'M' */ + 0x2d, 0x10, 0x00, 0x00, 0x21, 0x1e, 0xb7, 0x82, 0x00, 0x04, 0xdb, 0x5f, + 0xb7, 0xff, 0x24, 0x48, 0xff, 0x5f, 0xb7, 0xb7, 0xa5, 0xdb, 0xb7, 0x5f, + 0xb7, 0x47, 0xe5, 0x6f, 0x7c, 0x5f, 0xb7, 0x3b, 0x21, 0x19, 0x7c, 0x5f, + 0xb7, 0x3b, 0x00, 0x00, 0x7c, 0x5f, 0xb7, 0x3b, 0x00, 0x00, 0x7c, 0x5f, + /* ch = 'N' */ + 0x26, 0x21, 0x00, 0x00, 0x2d, 0x28, 0x7c, 0xf7, 0x0d, 0x00, 0xb7, 0x3b, + 0x7c, 0xf7, 0x6f, 0x00, 0xb7, 0x3b, 0x7c, 0x5f, 0xff, 0x1c, 0xb7, 0x3b, + 0x7c, 0x3b, 0x6b, 0x90, 0xb7, 0x3b, 0x7c, 0x3b, 0x10, 0xf7, 0xff, 0x3b, + 0x7c, 0x3b, 0x00, 0x50, 0xff, 0x3b, 0x7c, 0x3b, 0x00, 0x04, 0xc8, 0x3b, + /* ch = 'O' */ + 0x00, 0x1b, 0x67, 0x50, 0x08, 0x00, 0x24, 0xef, 0x37, 0x5f, 0xf7, 0x0d, + 0x8a, 0x54, 0x00, 0x00, 0xa7, 0x50, 0xe5, 0x26, 0x00, 0x00, 0x5f, 0x8a, + 0xff, 0x24, 0x00, 0x00, 0x50, 0x90, 0xbd, 0x3f, 0x00, 0x00, 0x6b, 0x6f, + 0x5a, 0xa5, 0x00, 0x10, 0xe5, 0x32, 0x04, 0xa2, 0xe5, 0xef, 0x65, 0x04, + 0x00, 0x00, 0x0c, 0x08, 0x00, 0x00, + /* ch = 'P' */ + 0x26, 0x36, 0x36, 0x36, 0x13, 0x00, 0x7c, 0x82, 0x36, 0x4f, 0xff, 0x22, + 0x7c, 0x5f, 0x00, 0x00, 0x97, 0x5a, 0x7c, 0x5f, 0x00, 0x16, 0xe5, 0x2f, + 0x7c, 0xb1, 0x74, 0x74, 0x3f, 0x00, 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x00, + 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x00, + /* ch = 'Q' */ + 0x00, 0x1b, 0x67, 0x50, 0x08, 0x00, 0x24, 0xe5, 0x31, 0x5a, 0xf7, 0x0d, + 0x8a, 0x54, 0x00, 0x00, 0xa7, 0x50, 0xe5, 0x26, 0x00, 0x00, 0x54, 0x8a, + 0xff, 0x24, 0x00, 0x00, 0x50, 0x90, 0xbd, 0x3b, 0x00, 0x00, 0x6b, 0x6f, + 0x5a, 0xa5, 0x00, 0x08, 0xe5, 0x32, 0x04, 0x94, 0xd4, 0xe5, 0x65, 0x04, + 0x00, 0x00, 0x6b, 0x74, 0x00, 0x00, 0x00, 0x00, 0x16, 0x8f, 0xcf, 0x36, + /* ch = 'R' */ + 0x26, 0x36, 0x36, 0x36, 0x13, 0x00, 0x7c, 0x82, 0x36, 0x5a, 0xff, 0x13, + 0x7c, 0x5f, 0x00, 0x00, 0xbd, 0x3b, 0x7c, 0x5f, 0x00, 0x24, 0xf7, 0x1f, + 0x7c, 0xb1, 0x9c, 0xec, 0x2e, 0x00, 0x7c, 0x5f, 0x04, 0xe5, 0x32, 0x00, + 0x7c, 0x5f, 0x00, 0x48, 0xbd, 0x00, 0x7c, 0x5f, 0x00, 0x04, 0xe5, 0x35, + /* ch = 'S' */ + 0x00, 0x16, 0x47, 0x47, 0x16, 0x00, 0x1c, 0xef, 0x31, 0x2b, 0xe5, 0x17, + 0x4d, 0xc6, 0x00, 0x00, 0x0f, 0x00, 0x10, 0xdb, 0x8a, 0x16, 0x00, 0x00, + 0x00, 0x08, 0x3f, 0xd4, 0x92, 0x04, 0x00, 0x00, 0x00, 0x04, 0xc8, 0x43, + 0x2a, 0x21, 0x00, 0x04, 0xb7, 0x43, 0x2c, 0xef, 0x9e, 0xcb, 0x94, 0x10, + 0x00, 0x00, 0x0f, 0x0c, 0x00, 0x00, + /* ch = 'T' */ + 0x36, 0x36, 0x36, 0x36, 0x36, 0x1e, 0x15, 0x15, 0xbd, 0x46, 0x15, 0x0f, + 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, + 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, + 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, + /* ch = 'U' */ + 0x26, 0x1e, 0x00, 0x00, 0x26, 0x1e, 0x7c, 0x5f, 0x00, 0x00, 0x7c, 0x5f, + 0x7c, 0x5f, 0x00, 0x00, 0x7c, 0x5f, 0x7c, 0x5f, 0x00, 0x00, 0x7c, 0x5f, + 0x7c, 0x5f, 0x00, 0x00, 0x7c, 0x5f, 0x7c, 0x5f, 0x00, 0x00, 0x7c, 0x5f, + 0x6b, 0x82, 0x00, 0x04, 0xc8, 0x39, 0x10, 0xcb, 0xbb, 0xbb, 0x84, 0x04, + 0x00, 0x00, 0x0f, 0x0c, 0x00, 0x00, + /* ch = 'V' */ + 0x33, 0x10, 0x00, 0x00, 0x1e, 0x26, 0x8a, 0x5f, 0x00, 0x00, 0x90, 0x47, + 0x39, 0xcf, 0x00, 0x0d, 0xff, 0x16, 0x0d, 0xf7, 0x24, 0x39, 0xa5, 0x00, + 0x00, 0x8a, 0x5f, 0x7c, 0x47, 0x00, 0x00, 0x32, 0xcf, 0xf7, 0x16, 0x00, + 0x00, 0x04, 0xf7, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x47, 0x00, 0x00, + /* ch = 'W' */ + 0x36, 0x00, 0x00, 0x00, 0x0d, 0x2d, 0xf7, 0x22, 0x44, 0x47, 0x32, 0x97, + 0xb1, 0x39, 0x90, 0x7c, 0x4d, 0x64, 0x7c, 0x5f, 0xef, 0xea, 0x6b, 0x3f, + 0x50, 0xf7, 0x90, 0xe5, 0xcf, 0x2c, 0x32, 0xff, 0x50, 0x7c, 0xff, 0x16, + 0x1c, 0xff, 0x24, 0x3b, 0xcf, 0x0d, 0x00, 0xcf, 0x0d, 0x1a, 0xb7, 0x00, + /* ch = 'X' */ + 0x39, 0x21, 0x00, 0x00, 0x30, 0x13, 0x2a, 0xff, 0x0d, 0x32, 0xc8, 0x0d, + 0x00, 0x90, 0x6f, 0xc8, 0x43, 0x00, 0x00, 0x1c, 0xff, 0xb7, 0x0d, 0x00, + 0x00, 0x04, 0xe5, 0x90, 0x00, 0x00, 0x00, 0x50, 0xb1, 0xf7, 0x2c, 0x00, + 0x10, 0xf7, 0x2c, 0x50, 0xb7, 0x00, 0x5f, 0x90, 0x00, 0x04, 0xdb, 0x3f, + /* ch = 'Y' */ + 0x44, 0x19, 0x00, 0x00, 0x26, 0x24, 0x50, 0xbd, 0x00, 0x0d, 0xe5, 0x29, + 0x0d, 0xe5, 0x35, 0x48, 0x9e, 0x04, 0x00, 0x48, 0xbd, 0xc8, 0x35, 0x00, + 0x00, 0x04, 0xe5, 0xb7, 0x04, 0x00, 0x00, 0x00, 0x7c, 0x5f, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x5f, 0x00, 0x00, + /* ch = 'Z' */ + 0x26, 0x36, 0x36, 0x36, 0x36, 0x16, 0x0f, 0x15, 0x15, 0x25, 0xf7, 0x1f, + 0x00, 0x00, 0x00, 0x90, 0x64, 0x00, 0x00, 0x00, 0x2f, 0xdb, 0x10, 0x00, + 0x00, 0x04, 0xdb, 0x39, 0x00, 0x00, 0x00, 0x5f, 0x9e, 0x04, 0x00, 0x00, + 0x1c, 0xf7, 0x1f, 0x00, 0x00, 0x00, 0x77, 0xff, 0xcf, 0xcf, 0xcf, 0x4e, + /* ch = '[' */ + 0xb7, 0x9c, 0x74, 0x74, 0x0d, 0xb7, 0x3b, 0x00, 0x00, 0x00, 0xb7, 0x3b, + 0x00, 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, + 0x00, 0xb7, 0x3b, 0x00, 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, 0x00, 0xb7, + 0x3b, 0x00, 0x00, 0x00, 0xb7, 0xb1, 0x74, 0x74, 0x00, + /* ch = '\' */ + 0x3a, 0x9e, 0x00, 0x0d, 0xf7, 0x24, 0x00, 0x6b, 0x82, 0x00, 0x17, 0xff, + 0x00, 0x00, 0x7c, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + /* ch = ']' */ + 0x22, 0x74, 0x74, 0xc8, 0x5f, 0x00, 0x00, 0x00, 0x7c, 0x5f, 0x00, 0x00, + 0x00, 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x7c, + 0x5f, 0x00, 0x00, 0x00, 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x7c, 0x5f, 0x00, + 0x00, 0x00, 0x7c, 0x5f, 0x22, 0x74, 0x74, 0xc8, 0x5f, + /* ch = '^' */ + 0x00, 0x00, 0x21, 0x16, 0x00, 0x00, 0x04, 0xdb, 0xa5, 0x00, 0x00, 0x5f, + 0x7c, 0xc8, 0x32, 0x0a, 0xbd, 0x16, 0x2f, 0x82, + /* ch = '_' */ + /* ch = '`' */ + 0x55, 0x6a, 0x00, 0x22, 0xff, 0x24, 0x00, 0x73, 0x6c, + /* ch = 'a' */ + 0x00, 0x2a, 0x74, 0x67, 0x1b, 0x00, 0x0d, 0x8d, 0x20, 0x31, 0xff, 0x13, + 0x00, 0x00, 0x15, 0x15, 0xff, 0x24, 0x24, 0xdd, 0x50, 0x36, 0xd9, 0x24, + 0x7c, 0x64, 0x00, 0x10, 0xff, 0x24, 0x32, 0xef, 0x82, 0xd4, 0xff, 0x24, + 0x00, 0x08, 0x15, 0x00, 0x00, 0x00, + /* ch = 'b' */ + 0x7c, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x90, 0x00, 0x00, 0x00, 0x00, + 0x7c, 0xab, 0x5b, 0x67, 0x1b, 0x00, 0x7c, 0xe5, 0x25, 0x3f, 0xff, 0x1c, + 0x7c, 0x90, 0x00, 0x00, 0xbd, 0x50, 0x7c, 0x90, 0x00, 0x00, 0xa7, 0x5f, + 0x7c, 0xab, 0x00, 0x10, 0xe5, 0x32, 0x7c, 0xbb, 0xbb, 0xe5, 0x84, 0x04, + 0x00, 0x00, 0x0c, 0x0f, 0x00, 0x00, + /* ch = 'c' */ + 0x00, 0x13, 0x5b, 0x74, 0x31, 0x00, 0x17, 0xef, 0x3f, 0x1a, 0xb1, 0x33, + 0x5f, 0x97, 0x00, 0x00, 0x0c, 0x04, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x39, 0xf7, 0x08, 0x00, 0x21, 0x00, 0x00, 0x73, 0xef, 0xab, 0xd4, 0x24, + 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, + /* ch = 'd' */ + 0x00, 0x00, 0x00, 0x00, 0xb7, 0x3b, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x3b, + 0x00, 0x2e, 0x74, 0x48, 0xbd, 0x3b, 0x3b, 0xb7, 0x20, 0x54, 0xff, 0x3b, + 0x90, 0x50, 0x00, 0x00, 0xff, 0x3b, 0xb1, 0x47, 0x00, 0x00, 0xff, 0x3b, + 0x6b, 0x97, 0x00, 0x1f, 0xff, 0x3b, 0x10, 0xd4, 0xcb, 0xcb, 0xe5, 0x3b, + 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + /* ch = 'e' */ + 0x00, 0x21, 0x74, 0x67, 0x19, 0x00, 0x2a, 0xdb, 0x22, 0x37, 0xf7, 0x0d, + 0x77, 0x73, 0x15, 0x15, 0xc6, 0x39, 0x8a, 0x82, 0x36, 0x36, 0x36, 0x1e, + 0x5a, 0xa5, 0x00, 0x00, 0x0c, 0x00, 0x04, 0xa2, 0xcb, 0x8f, 0xbb, 0x13, + 0x00, 0x00, 0x0c, 0x0f, 0x00, 0x00, + /* ch = 'f' */ + 0x00, 0x73, 0xbb, 0xd4, 0x6c, 0x2f, 0xcf, 0x0d, 0x04, 0x28, 0x3e, 0xd9, + 0x15, 0x0c, 0x00, 0x9c, 0xe5, 0x74, 0x39, 0x00, 0x32, 0xcf, 0x00, 0x00, + 0x00, 0x32, 0xcf, 0x00, 0x00, 0x00, 0x32, 0xcf, 0x00, 0x00, 0x00, 0x32, + 0xcf, 0x00, 0x00, 0x00, + /* ch = 'g' */ + 0x00, 0x37, 0x74, 0x48, 0x5b, 0x42, 0x40, 0xb1, 0x16, 0x82, 0x7b, 0x04, + 0x5f, 0x6f, 0x00, 0x54, 0x8a, 0x00, 0x1c, 0xec, 0x9e, 0xd4, 0x26, 0x00, + 0x32, 0xab, 0x15, 0x04, 0x00, 0x00, 0x22, 0xef, 0xcf, 0xcf, 0xdd, 0x10, + 0xa0, 0x3f, 0x00, 0x00, 0x88, 0x5a, 0x44, 0xdd, 0x82, 0x9e, 0xa2, 0x16, + /* ch = 'h' */ + 0x50, 0x97, 0x00, 0x00, 0x00, 0x00, 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x90, 0x3f, 0x74, 0x26, 0x00, 0x50, 0xff, 0x47, 0x37, 0xff, 0x13, + 0x50, 0xb7, 0x00, 0x00, 0xff, 0x24, 0x50, 0x90, 0x00, 0x00, 0xff, 0x24, + 0x50, 0x90, 0x00, 0x00, 0xff, 0x24, 0x50, 0x90, 0x00, 0x00, 0xff, 0x24, + /* ch = 'i' */ + 0x00, 0x00, 0x87, 0x67, 0x00, 0x00, 0x00, 0x22, 0x21, 0x00, 0x00, 0x36, + 0x36, 0x1e, 0x00, 0x00, 0x15, 0x88, 0x5f, 0x00, 0x00, 0x00, 0x7c, 0x5f, + 0x00, 0x00, 0x00, 0x7c, 0x5f, 0x00, 0x00, 0x00, 0x7c, 0x5f, 0x00, 0x14, + 0x74, 0xc8, 0xc8, 0x58, + /* ch = 'j' */ + 0x00, 0x00, 0x00, 0xab, 0x5b, 0x00, 0x00, 0x00, 0x28, 0x21, 0x00, 0x2d, + 0x36, 0x36, 0x1e, 0x00, 0x12, 0x15, 0xbd, 0x5f, 0x00, 0x00, 0x00, 0xb7, + 0x5f, 0x00, 0x00, 0x00, 0xb7, 0x5f, 0x00, 0x00, 0x00, 0xb7, 0x5f, 0x00, + 0x00, 0x00, 0xb7, 0x5a, 0x19, 0x10, 0x00, 0xcf, 0x39, 0x51, 0xef, 0xcb, + 0x94, 0x10, + /* ch = 'k' */ + 0x50, 0x97, 0x00, 0x00, 0x00, 0x00, 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x90, 0x00, 0x10, 0x50, 0x10, 0x50, 0x90, 0x13, 0xd4, 0x3f, 0x00, + 0x50, 0xcf, 0xdb, 0x3f, 0x00, 0x00, 0x50, 0xdb, 0xb1, 0x90, 0x00, 0x00, + 0x50, 0x90, 0x10, 0xdb, 0x5f, 0x00, 0x50, 0x90, 0x00, 0x1f, 0xf7, 0x3b, + /* ch = 'l' */ + 0x2d, 0xcf, 0xf7, 0x5f, 0x00, 0x00, 0x00, 0xb7, 0x5f, 0x00, 0x00, 0x00, + 0xb7, 0x5f, 0x00, 0x00, 0x00, 0xb7, 0x5f, 0x00, 0x00, 0x00, 0xb7, 0x5f, + 0x00, 0x00, 0x00, 0xb7, 0x5f, 0x00, 0x00, 0x00, 0xb7, 0x5f, 0x00, 0x22, + 0x74, 0xe5, 0xc8, 0x74, + /* ch = 'm' */ + 0x2d, 0x50, 0x67, 0x37, 0x74, 0x19, 0xb7, 0x64, 0x97, 0x90, 0x68, 0x8a, + 0xb7, 0x26, 0x7c, 0x5f, 0x50, 0x90, 0xb7, 0x24, 0x7c, 0x5f, 0x50, 0x90, + 0xb7, 0x24, 0x7c, 0x5f, 0x50, 0x90, 0xb7, 0x24, 0x7c, 0x5f, 0x50, 0x90, + /* ch = 'n' */ + 0x1e, 0x28, 0x3f, 0x74, 0x21, 0x00, 0x50, 0xff, 0x47, 0x3a, 0xff, 0x13, + 0x50, 0xa5, 0x00, 0x00, 0xff, 0x24, 0x50, 0x90, 0x00, 0x00, 0xff, 0x24, + 0x50, 0x90, 0x00, 0x00, 0xff, 0x24, 0x50, 0x90, 0x00, 0x00, 0xff, 0x24, + /* ch = 'o' */ + 0x00, 0x1b, 0x67, 0x5b, 0x13, 0x00, 0x2f, 0xdb, 0x25, 0x3f, 0xf7, 0x0d, + 0x90, 0x64, 0x00, 0x00, 0xa7, 0x50, 0xb7, 0x50, 0x00, 0x00, 0x7c, 0x5f, + 0x6b, 0xa5, 0x00, 0x04, 0xe5, 0x35, 0x10, 0xa9, 0xbb, 0xcb, 0x84, 0x04, + 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, + /* ch = 'p' */ + 0x26, 0x2a, 0x5b, 0x74, 0x1b, 0x00, 0x7c, 0xe5, 0x25, 0x3f, 0xff, 0x1c, + 0x7c, 0x90, 0x00, 0x00, 0xa0, 0x5a, 0x7c, 0x90, 0x00, 0x00, 0x7c, 0x5f, + 0x7c, 0xab, 0x00, 0x04, 0xcf, 0x3b, 0x7c, 0xef, 0xbb, 0xd4, 0x84, 0x04, + 0x7c, 0x90, 0x0c, 0x12, 0x00, 0x00, 0x7c, 0x90, 0x00, 0x00, 0x00, 0x00, + /* ch = 'q' */ + 0x00, 0x28, 0x74, 0x50, 0x30, 0x16, 0x35, 0xdb, 0x20, 0x43, 0xff, 0x3b, + 0xa0, 0x50, 0x00, 0x00, 0xff, 0x3b, 0xb7, 0x47, 0x00, 0x00, 0xff, 0x3b, + 0x6b, 0xa5, 0x00, 0x17, 0xff, 0x3b, 0x10, 0xd4, 0xcb, 0xdd, 0xe5, 0x3b, + 0x00, 0x00, 0x12, 0x00, 0xb7, 0x3b, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x3b, + /* ch = 'r' */ + 0x0d, 0x36, 0x26, 0x74, 0x5b, 0x10, 0x1c, 0xff, 0xc4, 0x25, 0x50, 0x2c, + 0x1c, 0xff, 0x2e, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x10, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x0d, 0x00, 0x00, 0x00, + /* ch = 's' */ + 0x00, 0x22, 0x74, 0x74, 0x22, 0x00, 0x22, 0xff, 0x1e, 0x1e, 0xc4, 0x13, + 0x17, 0xf7, 0x6a, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x50, 0xcb, 0xc0, 0x04, + 0x1f, 0x24, 0x00, 0x04, 0xff, 0x2f, 0x2f, 0xef, 0x9e, 0xbb, 0x94, 0x10, + 0x00, 0x00, 0x0f, 0x0c, 0x00, 0x00, + /* ch = 't' */ + 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x1a, 0xff, 0x1c, 0x00, 0x1e, 0x4a, + 0xff, 0x40, 0x2d, 0x0c, 0x2a, 0xff, 0x1a, 0x15, 0x00, 0x32, 0xcf, 0x04, + 0x00, 0x00, 0x32, 0xcf, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, 0x08, 0x00, + 0x0d, 0xd4, 0xdd, 0xdd, 0x00, 0x00, 0x00, 0x0f, 0x00, + /* ch = 'u' */ + 0x1e, 0x26, 0x00, 0x00, 0x36, 0x0d, 0x50, 0x90, 0x00, 0x00, 0xff, 0x24, + 0x6b, 0x90, 0x00, 0x00, 0xff, 0x24, 0x7c, 0x90, 0x00, 0x00, 0xff, 0x24, + 0x4d, 0xa5, 0x00, 0x22, 0xff, 0x24, 0x10, 0xd4, 0xa4, 0xc4, 0xff, 0x26, + 0x00, 0x00, 0x15, 0x04, 0x00, 0x00, + /* ch = 'v' */ + 0x2b, 0x1e, 0x00, 0x00, 0x26, 0x1c, 0x48, 0xbd, 0x00, 0x00, 0xcf, 0x29, + 0x0d, 0xff, 0x1f, 0x2c, 0xb7, 0x04, 0x00, 0x8a, 0x6a, 0x8a, 0x43, 0x00, + 0x00, 0x2c, 0xff, 0xe5, 0x10, 0x00, 0x00, 0x00, 0xc8, 0x6a, 0x00, 0x00, + /* ch = 'w' */ + 0x36, 0x00, 0x00, 0x00, 0x16, 0x39, 0xe5, 0x22, 0x7c, 0x50, 0x3b, 0x8a, + 0x90, 0x3f, 0xcf, 0xa5, 0x50, 0x5f, 0x5f, 0xa5, 0xb7, 0xf7, 0xa5, 0x39, + 0x35, 0xff, 0x5f, 0x90, 0xff, 0x22, 0x1a, 0xff, 0x2c, 0x44, 0xe5, 0x0d, + /* ch = 'x' */ + 0x24, 0x28, 0x00, 0x0d, 0x36, 0x09, 0x10, 0xe5, 0x2c, 0x7c, 0x6f, 0x00, + 0x00, 0x32, 0xf7, 0xc8, 0x10, 0x00, 0x00, 0x10, 0xec, 0x97, 0x00, 0x00, + 0x00, 0x90, 0x64, 0xc8, 0x47, 0x00, 0x48, 0xb7, 0x10, 0x1f, 0xff, 0x24, + /* ch = 'y' */ + 0x39, 0x26, 0x00, 0x00, 0x28, 0x1e, 0x39, 0xe0, 0x00, 0x00, 0xe5, 0x29, + 0x04, 0xe5, 0x29, 0x2c, 0xc8, 0x0d, 0x00, 0x5a, 0x82, 0x70, 0x54, 0x00, + 0x00, 0x17, 0xff, 0xf7, 0x1f, 0x00, 0x00, 0x00, 0xa0, 0x9e, 0x00, 0x00, + 0x0c, 0x00, 0xa7, 0x43, 0x00, 0x00, 0xd4, 0xc4, 0xa9, 0x10, 0x00, 0x00, + /* ch = 'z' */ + 0x1e, 0x36, 0x36, 0x36, 0x36, 0x0d, 0x0c, 0x15, 0x15, 0x67, 0xb1, 0x10, + 0x00, 0x00, 0x32, 0xdb, 0x19, 0x00, 0x00, 0x1f, 0xef, 0x26, 0x00, 0x00, + 0x10, 0xdb, 0x3b, 0x00, 0x00, 0x00, 0x77, 0xff, 0xcf, 0xcf, 0xcf, 0x32, + /* ch = '{' */ + 0x00, 0x28, 0x74, 0x58, 0x22, 0xe5, 0x1b, 0x00, 0x32, 0xcf, 0x00, 0x00, + 0x35, 0xc8, 0x00, 0x00, 0xa9, 0x3b, 0x00, 0x00, 0x90, 0x5a, 0x00, 0x00, + 0x35, 0xc8, 0x00, 0x00, 0x3b, 0xcf, 0x00, 0x00, 0x2f, 0xea, 0x04, 0x00, + 0x04, 0x8d, 0xcf, 0xa4, + /* ch = '|' */ + 0x67, 0x32, 0x7c, 0x3b, 0x7c, 0x3b, 0x7c, 0x3b, 0x7c, 0x3b, 0x7c, 0x3b, + 0x7c, 0x3b, 0x7c, 0x3b, 0x7c, 0x3b, 0x67, 0x36, + /* ch = '}' */ + 0x14, 0x74, 0x67, 0x13, 0x00, 0x00, 0x37, 0xe0, 0x00, 0x00, 0x1c, 0xff, + 0x00, 0x00, 0x1a, 0xff, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0xb1, + 0x00, 0x00, 0x1a, 0xff, 0x00, 0x00, 0x1c, 0xff, 0x00, 0x00, 0x26, 0xf7, + 0x1a, 0xcf, 0xc6, 0x50, + /* ch = '~' */ + 0x08, 0x5b, 0x50, 0x08, 0x19, 0x19, 0x64, 0x47, 0x5a, 0xef, 0xe5, 0x35, + 0x00, 0x00, 0x00, 0x08, 0x08, 0x00 }; /* font_inconsolata_13px */ static const unsigned char pd_inconsolata_font_bitmap_13px_bytes[] = { - /* ch = '!' */ - 0x45, 0x3d, - 0xb7, 0xbd, - 0xa0, 0x88, - 0x7c, 0x82, - 0x7c, 0x64, - 0x6b, 0x54, - 0x1e, 0x21, - 0x22, 0x21, - 0xe5, 0xb7, - 0x0c, 0x0c, - /* ch = '"' */ - 0x2a, 0x4e, 0x1c, 0x74, 0x04, - 0x50, 0xbd, 0x2f, 0xff, 0x17, - 0x5f, 0x64, 0x35, 0xb7, 0x04, - 0x58, 0x1f, 0x36, 0x36, 0x00, - /* ch = '#' */ - 0x00, 0x00, 0x15, 0x00, 0x04, 0x08, 0x00, - 0x00, 0x1c, 0xf7, 0x04, 0xf7, 0x1f, 0x00, - 0x00, 0x2a, 0xbd, 0x0d, 0xff, 0x10, 0x00, - 0x77, 0xe5, 0xef, 0x95, 0xf7, 0x74, 0x17, - 0x00, 0x50, 0x70, 0x32, 0xbd, 0x00, 0x00, - 0x00, 0x77, 0x5e, 0x4f, 0x95, 0x15, 0x00, - 0x74, 0xe5, 0x9c, 0x87, 0x82, 0x30, 0x04, - 0x00, 0xb7, 0x26, 0x7c, 0x50, 0x00, 0x00, - 0x00, 0xcf, 0x1c, 0x8f, 0x2f, 0x00, 0x00, - /* ch = '$' */ - 0x00, 0x00, 0x16, 0x2d, 0x00, 0x00, - 0x00, 0x1b, 0x9c, 0xec, 0x50, 0x08, - 0x17, 0xf7, 0x59, 0xbd, 0x5f, 0x66, - 0x2a, 0xec, 0x3f, 0xbd, 0x00, 0x00, - 0x00, 0x66, 0xff, 0xd9, 0x16, 0x00, - 0x00, 0x00, 0x35, 0xe5, 0xdb, 0x50, - 0x00, 0x00, 0x32, 0xbd, 0x24, 0xff, - 0x32, 0x90, 0x37, 0xc6, 0x64, 0xa0, - 0x04, 0x48, 0xdd, 0xf7, 0x73, 0x13, - 0x00, 0x00, 0x22, 0x5c, 0x00, 0x00, - /* ch = '%' */ - 0x04, 0x15, 0x08, 0x00, 0x08, 0x15, 0x00, - 0x77, 0x94, 0xe5, 0x0d, 0x6b, 0x70, 0x00, - 0xf7, 0x1f, 0xbd, 0x44, 0xef, 0x13, 0x00, - 0x66, 0xc4, 0xd4, 0x88, 0x54, 0x00, 0x00, - 0x00, 0x12, 0x28, 0xdb, 0x08, 0x00, 0x00, - 0x00, 0x00, 0xa0, 0x43, 0x15, 0x08, 0x00, - 0x00, 0x32, 0xb7, 0x7c, 0x85, 0xe5, 0x0d, - 0x04, 0xc8, 0x2c, 0xf7, 0x1f, 0xb7, 0x2a, - 0x44, 0x90, 0x04, 0x66, 0xc4, 0xd4, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0x00, - /* ch = '&' */ - 0x00, 0x00, 0x12, 0x0c, 0x00, 0x00, 0x00, - 0x00, 0xa9, 0xab, 0xef, 0x32, 0x00, 0x00, - 0x1c, 0xff, 0x1f, 0x54, 0x82, 0x00, 0x00, - 0x00, 0xc8, 0x43, 0xb1, 0x48, 0x00, 0x00, - 0x00, 0x43, 0xff, 0x75, 0x04, 0x00, 0x00, - 0x2f, 0xf7, 0x77, 0xbd, 0x04, 0x5b, 0x04, - 0xa0, 0x64, 0x00, 0xb1, 0xdb, 0xc8, 0x08, - 0xb1, 0x68, 0x00, 0x2b, 0xff, 0x46, 0x00, - 0x32, 0xf7, 0xd4, 0xd4, 0x54, 0xf7, 0x0a, - 0x00, 0x04, 0x15, 0x00, 0x00, 0x0f, 0x00, - /* ch = ''' */ - 0x1c, 0x74, 0x04, - 0x2f, 0xff, 0x17, - 0x35, 0xa7, 0x04, - 0x36, 0x36, 0x00, - /* ch = '(' */ - 0x00, 0x04, 0x48, 0x1c, - 0x10, 0xb1, 0x84, 0x0f, - 0x77, 0x82, 0x04, 0x00, - 0xff, 0x1a, 0x00, 0x00, - 0xbd, 0x04, 0x00, 0x00, - 0x82, 0x00, 0x00, 0x00, - 0xb7, 0x00, 0x00, 0x00, - 0xff, 0x0d, 0x00, 0x00, - 0xc8, 0x54, 0x00, 0x00, - 0x2a, 0xff, 0x21, 0x00, - 0x00, 0x2c, 0xf7, 0x33, - 0x00, 0x00, 0x0c, 0x08, - /* ch = ')' */ - 0x14, 0x48, 0x04, 0x00, - 0x10, 0x99, 0xb7, 0x10, - 0x00, 0x00, 0x7c, 0xa7, - 0x00, 0x00, 0x10, 0xf7, - 0x00, 0x00, 0x00, 0x82, - 0x00, 0x00, 0x00, 0x50, - 0x00, 0x00, 0x00, 0x5f, - 0x00, 0x00, 0x00, 0xb7, - 0x00, 0x00, 0x2f, 0xf7, - 0x00, 0x19, 0xdb, 0x35, - 0x27, 0xef, 0x3f, 0x00, - 0x04, 0x0f, 0x00, 0x00, - /* ch = '*' */ - 0x00, 0x00, 0x45, 0x82, 0x00, 0x00, - 0x21, 0x13, 0x50, 0x82, 0x08, 0x21, - 0x40, 0xc4, 0xd4, 0xd1, 0xd4, 0x5b, - 0x00, 0x04, 0xb1, 0xdb, 0x10, 0x00, - 0x04, 0xb1, 0x59, 0x3b, 0xb7, 0x04, - 0x04, 0x50, 0x08, 0x00, 0x48, 0x0c, - /* ch = '+' */ - 0x00, 0x00, 0x45, 0x67, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, - 0x42, 0x74, 0xb1, 0xd1, 0x74, 0x74, 0x00, - 0x0f, 0x15, 0x5e, 0x88, 0x15, 0x15, 0x04, - 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x30, 0x45, 0x00, 0x00, 0x00, - /* ch = ',' */ - 0x00, 0x22, 0x16, - 0x00, 0xef, 0xec, - 0x00, 0x37, 0xa7, - 0x09, 0xd4, 0x21, - 0x00, 0x0f, 0x00, - /* ch = '-' */ - 0x22, 0x74, 0x74, 0x74, 0x74, 0x42, - 0x16, 0x36, 0x36, 0x36, 0x36, 0x28, - /* ch = '.' */ - 0x22, 0x1b, - 0xf7, 0xb7, - 0x0c, 0x0c, - /* ch = '/' */ - 0x00, 0x39, 0x26, - 0x04, 0xe5, 0x35, - 0x44, 0xc8, 0x04, - 0xc8, 0x3f, 0x00, - 0xe5, 0x08, 0x00, - 0x4c, 0x00, 0x00, - 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* ch = '0' */ - 0x00, 0x00, 0x0c, 0x0f, 0x00, 0x00, - 0x00, 0x44, 0xef, 0xcb, 0x7c, 0x00, - 0x17, 0xf7, 0x13, 0x04, 0xec, 0x35, - 0x50, 0x88, 0x00, 0x44, 0xff, 0x7c, - 0x7c, 0x54, 0x1f, 0xef, 0x54, 0xbd, - 0x7c, 0x6d, 0xdb, 0x35, 0x32, 0xbd, - 0x50, 0xff, 0x54, 0x00, 0x4d, 0x88, - 0x1c, 0xff, 0x21, 0x04, 0xb7, 0x3b, - 0x00, 0x44, 0xf7, 0xdd, 0x77, 0x04, - 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, - /* ch = '1' */ - 0x00, 0x00, 0x04, 0x12, - 0x00, 0x31, 0xd4, 0xbd, - 0x04, 0x50, 0x3e, 0xbd, - 0x00, 0x00, 0x32, 0xbd, - 0x00, 0x00, 0x32, 0xbd, - 0x00, 0x00, 0x32, 0xbd, - 0x00, 0x00, 0x32, 0xbd, - 0x00, 0x00, 0x32, 0xbd, - 0x00, 0x00, 0x32, 0xbd, - /* ch = '2' */ - 0x00, 0x00, 0x0c, 0x12, 0x00, 0x00, - 0x04, 0x94, 0xcb, 0xcb, 0xc4, 0x10, - 0x10, 0x48, 0x04, 0x00, 0xb7, 0x5f, - 0x00, 0x00, 0x00, 0x00, 0x82, 0x70, - 0x00, 0x00, 0x00, 0x1f, 0xf7, 0x1f, - 0x00, 0x00, 0x1f, 0xdb, 0x37, 0x00, - 0x00, 0x1f, 0xdb, 0x35, 0x00, 0x00, - 0x00, 0xb1, 0x54, 0x00, 0x00, 0x00, - 0x2f, 0xff, 0xd4, 0xcf, 0xcf, 0x7c, - /* ch = '3' */ - 0x00, 0x00, 0x0c, 0x08, 0x00, 0x00, - 0x09, 0xa9, 0xd4, 0xe5, 0x7c, 0x00, - 0x00, 0x22, 0x00, 0x04, 0xe5, 0x2c, - 0x00, 0x00, 0x00, 0x10, 0xe5, 0x2a, - 0x00, 0x00, 0x74, 0xe5, 0x53, 0x00, - 0x00, 0x00, 0x15, 0x37, 0xf7, 0x17, - 0x00, 0x00, 0x00, 0x00, 0x82, 0x54, - 0x04, 0x3d, 0x00, 0x08, 0xc8, 0x3b, - 0x22, 0xd4, 0xdd, 0xe5, 0x94, 0x08, - 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, - /* ch = '4' */ - 0x00, 0x00, 0x00, 0x08, 0x12, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0xbd, 0x00, - 0x00, 0x00, 0x32, 0xff, 0xbd, 0x00, - 0x00, 0x10, 0xd4, 0x82, 0xbd, 0x00, - 0x00, 0x7c, 0x50, 0x50, 0xbd, 0x00, - 0x32, 0xb1, 0x08, 0x50, 0xbd, 0x00, - 0x67, 0xcf, 0xcf, 0xe5, 0xf7, 0x9c, - 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, - 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, - /* ch = '5' */ - 0x00, 0x15, 0x15, 0x15, 0x15, 0x0c, - 0x00, 0xff, 0xd4, 0xcf, 0xcf, 0x49, - 0x04, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x15, 0x15, 0x04, 0x00, - 0x1c, 0xff, 0x8f, 0x8f, 0xe5, 0x1c, - 0x00, 0x15, 0x00, 0x00, 0x70, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, - 0x13, 0x73, 0x00, 0x00, 0x90, 0x70, - 0x10, 0xbb, 0xe5, 0xbb, 0xbb, 0x13, - 0x00, 0x00, 0x0c, 0x15, 0x00, 0x00, - /* ch = '6' */ - 0x00, 0x00, 0x04, 0x15, 0x08, 0x00, - 0x00, 0x2c, 0xe5, 0x8f, 0xef, 0x2b, - 0x04, 0xe5, 0x37, 0x00, 0x0c, 0x04, - 0x2a, 0xe5, 0x0f, 0x15, 0x04, 0x00, - 0x3b, 0xff, 0xd4, 0x95, 0xdb, 0x10, - 0x50, 0xe5, 0x0c, 0x00, 0x8a, 0x64, - 0x35, 0xc6, 0x00, 0x00, 0x50, 0x82, - 0x17, 0xff, 0x26, 0x00, 0x90, 0x5f, - 0x00, 0x44, 0xef, 0xd4, 0xa9, 0x10, - 0x00, 0x00, 0x04, 0x12, 0x00, 0x00, - /* ch = '7' */ - 0x08, 0x15, 0x15, 0x15, 0x15, 0x0f, - 0x2d, 0xcf, 0xcf, 0xcf, 0xf7, 0x5f, - 0x00, 0x00, 0x00, 0x17, 0xff, 0x1a, - 0x00, 0x00, 0x00, 0x5a, 0x90, 0x00, - 0x00, 0x00, 0x04, 0xe5, 0x3b, 0x00, - 0x00, 0x00, 0x32, 0xe5, 0x08, 0x00, - 0x00, 0x00, 0x8a, 0x75, 0x00, 0x00, - 0x00, 0x0d, 0xff, 0x2c, 0x00, 0x00, - 0x00, 0x3b, 0xe5, 0x04, 0x00, 0x00, - /* ch = '8' */ - 0x00, 0x00, 0x0f, 0x15, 0x00, 0x00, - 0x00, 0x77, 0xbb, 0xa4, 0xdb, 0x10, - 0x1a, 0xff, 0x1a, 0x00, 0xbd, 0x48, - 0x0d, 0xf7, 0x37, 0x10, 0xe5, 0x2a, - 0x00, 0x2b, 0xff, 0xef, 0x53, 0x00, - 0x10, 0xd4, 0x3f, 0x3f, 0xff, 0x1f, - 0x4d, 0xa7, 0x04, 0x00, 0x70, 0x7c, - 0x44, 0xcf, 0x04, 0x00, 0x90, 0x70, - 0x04, 0x94, 0xef, 0xdd, 0xbb, 0x13, - 0x00, 0x00, 0x0c, 0x12, 0x00, 0x00, - /* ch = '9' */ - 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, - 0x00, 0x77, 0xd4, 0xcb, 0x99, 0x00, - 0x2a, 0xe5, 0x10, 0x04, 0xc8, 0x3b, - 0x49, 0xbd, 0x00, 0x00, 0x7c, 0x70, - 0x2a, 0xff, 0x10, 0x04, 0xb7, 0x82, - 0x00, 0x66, 0xf7, 0xdd, 0xdb, 0x82, - 0x00, 0x00, 0x00, 0x00, 0x82, 0x59, - 0x00, 0x21, 0x00, 0x10, 0xf7, 0x24, - 0x17, 0xe5, 0xd4, 0xe5, 0x48, 0x00, - 0x00, 0x00, 0x12, 0x04, 0x00, 0x00, - /* ch = ':' */ - 0x28, 0x28, - 0xdb, 0xa0, - 0x00, 0x00, - 0x00, 0x00, - 0x22, 0x1b, - 0xf7, 0xb7, - 0x0c, 0x0c, - /* ch = ';' */ - 0x00, 0x28, 0x28, - 0x00, 0xdb, 0xa0, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x22, 0x16, - 0x00, 0xef, 0xec, - 0x00, 0x37, 0xa7, - 0x09, 0xd4, 0x21, - 0x00, 0x0f, 0x00, - /* ch = '<' */ - 0x00, 0x00, 0x00, 0x00, 0x22, - 0x00, 0x00, 0x1e, 0xbb, 0xbb, - 0x1b, 0xa4, 0xbb, 0x2b, 0x00, - 0xc4, 0x2b, 0x00, 0x00, 0x00, - 0xef, 0x66, 0x08, 0x00, 0x00, - 0x08, 0x50, 0xef, 0x37, 0x04, - 0x00, 0x00, 0x13, 0x94, 0xdb, - 0x00, 0x00, 0x00, 0x00, 0x22, - /* ch = '=' */ - 0x42, 0x74, 0x74, 0x74, 0x74, 0x74, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x67, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x04, - /* ch = '>' */ - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x31, 0x00, 0x00, 0x00, 0x00, - 0xa4, 0xc4, 0x28, 0x00, 0x00, - 0x00, 0x1b, 0xab, 0xc4, 0x00, - 0x04, 0x48, 0xe5, 0x50, 0x04, - 0xd4, 0x73, 0x16, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = '?' */ - 0x00, 0x1b, 0x67, 0x74, 0x2e, 0x00, - 0x2d, 0xf7, 0x37, 0x37, 0xf7, 0x35, - 0x00, 0x22, 0x00, 0x00, 0x88, 0x7c, - 0x00, 0x00, 0x00, 0x10, 0xe5, 0x48, - 0x00, 0x00, 0x04, 0xb1, 0x6b, 0x04, - 0x00, 0x00, 0x2f, 0xcf, 0x04, 0x00, - 0x00, 0x00, 0x22, 0x5c, 0x00, 0x00, - 0x00, 0x00, 0x0c, 0x25, 0x00, 0x00, - 0x00, 0x00, 0x77, 0xff, 0x1a, 0x00, - 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, - /* ch = '@' */ - 0x00, 0x00, 0x0c, 0x15, 0x08, 0x00, 0x00, - 0x00, 0x66, 0xbb, 0x67, 0xe5, 0x24, 0x00, - 0x39, 0xa0, 0x08, 0x00, 0x2c, 0xcf, 0x00, - 0xa0, 0x35, 0x19, 0x8f, 0xbd, 0xff, 0x04, - 0xbd, 0x1f, 0xdb, 0x3a, 0x0d, 0xff, 0x04, - 0xb7, 0x21, 0xf7, 0x28, 0x2f, 0xff, 0x04, - 0x90, 0x43, 0x35, 0xcf, 0xab, 0xcf, 0x04, - 0x2a, 0xe5, 0x10, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x44, 0xe5, 0x82, 0xbb, 0x4f, 0x00, - 0x00, 0x00, 0x00, 0x15, 0x0c, 0x00, 0x00, - /* ch = 'A' */ - 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x5a, 0x4c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xc8, 0xaf, 0x00, 0x00, 0x00, - 0x00, 0x24, 0xc8, 0xf7, 0x24, 0x00, 0x00, - 0x00, 0x5f, 0x5f, 0x70, 0x64, 0x00, 0x00, - 0x00, 0xe5, 0x24, 0x2a, 0xec, 0x04, 0x00, - 0x2a, 0xe5, 0x74, 0x74, 0xe5, 0x35, 0x00, - 0x70, 0x70, 0x00, 0x00, 0x5a, 0x90, 0x00, - 0xe5, 0x2c, 0x00, 0x00, 0x22, 0xff, 0x1a, - /* ch = 'B' */ - 0x0f, 0x15, 0x15, 0x00, 0x00, 0x00, - 0x7c, 0xb1, 0x74, 0xdd, 0xc4, 0x10, - 0x7c, 0x54, 0x00, 0x00, 0x97, 0x64, - 0x7c, 0x54, 0x00, 0x04, 0xa7, 0x4c, - 0x7c, 0xef, 0xcf, 0xe5, 0x9e, 0x08, - 0x7c, 0x54, 0x00, 0x16, 0xb1, 0x50, - 0x7c, 0x54, 0x00, 0x00, 0x35, 0xcf, - 0x7c, 0x54, 0x00, 0x00, 0x7c, 0xa7, - 0x7c, 0xef, 0xcf, 0xe5, 0xb3, 0x1b, - /* ch = 'C' */ - 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, 0x00, - 0x00, 0x4d, 0xe5, 0x82, 0xef, 0x3b, 0x00, - 0x2a, 0xe5, 0x13, 0x00, 0x24, 0x9e, 0x0a, - 0x6b, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb1, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb1, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x6b, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2a, 0xff, 0x1f, 0x00, 0x1f, 0x48, 0x00, - 0x00, 0x44, 0xf7, 0xab, 0xe5, 0x2f, 0x00, - 0x00, 0x00, 0x04, 0x15, 0x00, 0x00, 0x00, - /* ch = 'D' */ - 0x0f, 0x15, 0x0f, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0xb1, 0x9e, 0xef, 0x6b, 0x04, 0x00, - 0x7c, 0x54, 0x00, 0x10, 0xdb, 0x48, 0x00, - 0x7c, 0x54, 0x00, 0x00, 0x50, 0xb7, 0x00, - 0x7c, 0x54, 0x00, 0x00, 0x32, 0xff, 0x00, - 0x7c, 0x54, 0x00, 0x00, 0x32, 0xf7, 0x04, - 0x7c, 0x54, 0x00, 0x00, 0x50, 0xa7, 0x00, - 0x7c, 0x54, 0x00, 0x10, 0xdb, 0x3b, 0x00, - 0x7c, 0xef, 0xcf, 0xe5, 0x48, 0x04, 0x00, - /* ch = 'E' */ - 0x0c, 0x15, 0x15, 0x15, 0x15, 0x0f, - 0x50, 0xc8, 0x74, 0x74, 0x74, 0x45, - 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xd1, 0x74, 0x74, 0x74, 0x00, - 0x50, 0x88, 0x15, 0x15, 0x15, 0x04, - 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xf7, 0xcf, 0xcf, 0xcf, 0x67, - /* ch = 'F' */ - 0x08, 0x15, 0x15, 0x15, 0x15, 0x0f, - 0x32, 0xff, 0x74, 0x74, 0x74, 0x45, - 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x32, 0xff, 0xd4, 0xcf, 0xcf, 0x00, - 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, - /* ch = 'G' */ - 0x00, 0x00, 0x08, 0x15, 0x04, 0x00, 0x00, - 0x00, 0x5a, 0xef, 0x82, 0xf7, 0x39, 0x00, - 0x32, 0xdb, 0x13, 0x00, 0x24, 0x73, 0x04, - 0x82, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb7, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb7, 0x3f, 0x00, 0x67, 0xcf, 0xcf, 0x00, - 0x82, 0x64, 0x00, 0x00, 0x1c, 0xff, 0x04, - 0x32, 0xec, 0x13, 0x00, 0x1f, 0xff, 0x04, - 0x00, 0x50, 0xf7, 0xab, 0xe5, 0x73, 0x04, - 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - /* ch = 'H' */ - 0x0f, 0x0f, 0x00, 0x00, 0x0c, 0x12, - 0x7c, 0x82, 0x00, 0x00, 0x50, 0x88, - 0x7c, 0x82, 0x00, 0x00, 0x50, 0x82, - 0x7c, 0x82, 0x00, 0x00, 0x50, 0x82, - 0x7c, 0xd1, 0x74, 0x74, 0xb1, 0x82, - 0x7c, 0x88, 0x15, 0x15, 0x5e, 0x82, - 0x7c, 0x82, 0x00, 0x00, 0x50, 0x82, - 0x7c, 0x82, 0x00, 0x00, 0x50, 0x82, - 0x7c, 0x82, 0x00, 0x00, 0x50, 0x82, - /* ch = 'I' */ - 0x04, 0x15, 0x15, 0x15, 0x15, 0x04, - 0x14, 0x74, 0xc8, 0xb1, 0x74, 0x17, - 0x00, 0x00, 0x7c, 0x54, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x54, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x54, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x54, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x54, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x54, 0x00, 0x00, - 0x2d, 0xcf, 0xef, 0xef, 0xcf, 0x1a, - /* ch = 'J' */ - 0x04, 0x15, 0x15, 0x15, 0x15, 0x00, - 0x14, 0x74, 0xb1, 0xc8, 0x74, 0x04, - 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, - 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, - 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, - 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, - 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, - 0x19, 0x00, 0x8a, 0x64, 0x00, 0x00, - 0xf7, 0xc4, 0xd4, 0x13, 0x00, 0x00, - 0x04, 0x15, 0x00, 0x00, 0x00, 0x00, - /* ch = 'K' */ - 0x12, 0x0f, 0x00, 0x00, 0x0c, 0x12, 0x00, - 0xb7, 0x54, 0x00, 0x10, 0xdb, 0x35, 0x00, - 0xb7, 0x54, 0x10, 0xb1, 0x54, 0x00, 0x00, - 0xb7, 0x59, 0xb1, 0x7c, 0x04, 0x00, 0x00, - 0xb7, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, - 0xb7, 0x82, 0xb1, 0x7c, 0x00, 0x00, 0x00, - 0xb7, 0x54, 0x1c, 0xf7, 0x35, 0x00, 0x00, - 0xb7, 0x54, 0x00, 0x44, 0xec, 0x10, 0x00, - 0xb7, 0x54, 0x00, 0x00, 0x90, 0xa7, 0x04, - /* ch = 'L' */ - 0x0c, 0x15, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0xcf, 0xcf, 0xcf, 0x67, - /* ch = 'M' */ - 0x12, 0x04, 0x00, 0x00, 0x00, 0x15, 0x00, - 0xb7, 0x64, 0x00, 0x00, 0x32, 0xff, 0x04, - 0xb7, 0xff, 0x10, 0x00, 0xc8, 0xff, 0x04, - 0xb7, 0xe5, 0x64, 0x3b, 0xdb, 0xff, 0x04, - 0xb7, 0x54, 0xff, 0xc8, 0x48, 0xff, 0x04, - 0xb7, 0x35, 0x70, 0x90, 0x1f, 0xff, 0x04, - 0xb7, 0x35, 0x08, 0x0c, 0x1c, 0xff, 0x04, - 0xb7, 0x35, 0x00, 0x00, 0x1c, 0xff, 0x04, - 0xb7, 0x35, 0x00, 0x00, 0x1c, 0xff, 0x04, - /* ch = 'N' */ - 0x0f, 0x0c, 0x00, 0x00, 0x08, 0x12, - 0x7c, 0xcf, 0x04, 0x00, 0x32, 0xbd, - 0x7c, 0xff, 0x48, 0x00, 0x32, 0xbd, - 0x7c, 0xb7, 0xec, 0x0d, 0x32, 0xbd, - 0x7c, 0x54, 0xa0, 0x64, 0x32, 0xbd, - 0x7c, 0x54, 0x24, 0xff, 0x50, 0xbd, - 0x7c, 0x54, 0x00, 0x7c, 0xff, 0xbd, - 0x7c, 0x54, 0x00, 0x17, 0xf7, 0xbd, - 0x7c, 0x54, 0x00, 0x00, 0x50, 0xbd, - /* ch = 'O' */ - 0x00, 0x00, 0x0f, 0x15, 0x00, 0x00, 0x00, - 0x04, 0x84, 0xe5, 0xcb, 0xc4, 0x10, 0x00, - 0x48, 0xb7, 0x08, 0x00, 0x82, 0x90, 0x00, - 0xa0, 0x48, 0x00, 0x00, 0x2a, 0xff, 0x00, - 0xe5, 0x35, 0x00, 0x00, 0x1c, 0xff, 0x1c, - 0xcf, 0x35, 0x00, 0x00, 0x1c, 0xff, 0x1c, - 0xa0, 0x54, 0x00, 0x00, 0x2a, 0xf7, 0x04, - 0x44, 0xe5, 0x10, 0x04, 0x82, 0x70, 0x00, - 0x00, 0x66, 0xf7, 0xe5, 0xa9, 0x13, 0x00, - 0x00, 0x00, 0x08, 0x0f, 0x00, 0x00, 0x00, - /* ch = 'P' */ - 0x0c, 0x15, 0x15, 0x04, 0x00, 0x00, 0x00, - 0x50, 0xef, 0xcf, 0xd4, 0xef, 0x1f, 0x00, - 0x50, 0x82, 0x00, 0x00, 0x5f, 0xa7, 0x00, - 0x50, 0x82, 0x00, 0x00, 0x3b, 0xbd, 0x04, - 0x50, 0xab, 0x36, 0x3e, 0xdb, 0x50, 0x00, - 0x50, 0xa5, 0x36, 0x36, 0x25, 0x00, 0x00, - 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 'Q' */ - 0x00, 0x00, 0x0f, 0x15, 0x00, 0x00, 0x00, - 0x04, 0x84, 0xd4, 0xb3, 0xc4, 0x10, 0x00, - 0x48, 0xb7, 0x08, 0x00, 0x82, 0x90, 0x00, - 0xa0, 0x3f, 0x00, 0x00, 0x24, 0xff, 0x00, - 0xe5, 0x35, 0x00, 0x00, 0x1c, 0xff, 0x1c, - 0xe5, 0x35, 0x00, 0x00, 0x1a, 0xff, 0x1c, - 0xa0, 0x54, 0x00, 0x00, 0x24, 0xf7, 0x04, - 0x44, 0xe5, 0x10, 0x00, 0x82, 0x75, 0x00, - 0x00, 0x66, 0xf7, 0xdd, 0xa9, 0x13, 0x00, - 0x00, 0x00, 0x32, 0xbd, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x8d, 0xcf, 0x6c, 0x00, - /* ch = 'R' */ - 0x0f, 0x15, 0x15, 0x04, 0x00, 0x00, - 0x7c, 0xef, 0xcf, 0xdd, 0xdb, 0x1f, - 0x7c, 0x82, 0x00, 0x00, 0x82, 0x90, - 0x7c, 0x82, 0x00, 0x00, 0x54, 0xa7, - 0x7c, 0xab, 0x36, 0x47, 0xf7, 0x35, - 0x7c, 0xa5, 0x36, 0xf7, 0x39, 0x00, - 0x7c, 0x82, 0x00, 0x5f, 0x97, 0x00, - 0x7c, 0x82, 0x00, 0x10, 0xf7, 0x2c, - 0x7c, 0x82, 0x00, 0x00, 0x5f, 0xa7, - /* ch = 'S' */ - 0x00, 0x00, 0x0c, 0x12, 0x00, 0x00, - 0x00, 0x84, 0xbb, 0x8f, 0xef, 0x2c, - 0x2f, 0xe5, 0x08, 0x00, 0x2c, 0x21, - 0x2a, 0xff, 0x21, 0x00, 0x00, 0x00, - 0x00, 0x50, 0xf7, 0x7f, 0x1b, 0x00, - 0x00, 0x00, 0x08, 0x50, 0xf7, 0x44, - 0x00, 0x00, 0x00, 0x00, 0x3f, 0xcf, - 0x2f, 0x3b, 0x00, 0x00, 0x54, 0xa7, - 0x26, 0xd4, 0xdd, 0xd4, 0xd4, 0x21, - 0x00, 0x00, 0x0c, 0x12, 0x00, 0x00, - /* ch = 'T' */ - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, - 0xcf, 0xcf, 0xef, 0xef, 0xcf, 0xcf, 0x04, - 0x00, 0x00, 0x7c, 0x82, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x82, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x82, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x82, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x82, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x82, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x82, 0x00, 0x00, 0x00, - /* ch = 'U' */ - 0x0f, 0x0f, 0x00, 0x00, 0x08, 0x12, - 0x7c, 0x59, 0x00, 0x00, 0x32, 0xbd, - 0x7c, 0x54, 0x00, 0x00, 0x32, 0xbd, - 0x7c, 0x54, 0x00, 0x00, 0x32, 0xbd, - 0x7c, 0x54, 0x00, 0x00, 0x32, 0xbd, - 0x7c, 0x54, 0x00, 0x00, 0x32, 0xbd, - 0x7c, 0x59, 0x00, 0x00, 0x32, 0xbd, - 0x50, 0xbd, 0x04, 0x00, 0x5f, 0x90, - 0x04, 0xa2, 0xd4, 0xa4, 0xd4, 0x19, - 0x00, 0x00, 0x0c, 0x12, 0x00, 0x00, - /* ch = 'V' */ - 0x15, 0x08, 0x00, 0x00, 0x00, 0x15, 0x04, - 0xa7, 0x4c, 0x00, 0x00, 0x22, 0xf7, 0x08, - 0x48, 0xaf, 0x00, 0x00, 0x5a, 0x82, 0x00, - 0x17, 0xff, 0x1a, 0x00, 0xb7, 0x35, 0x00, - 0x00, 0xa7, 0x4c, 0x1c, 0xf7, 0x10, 0x00, - 0x00, 0x48, 0xaf, 0x48, 0x90, 0x00, 0x00, - 0x00, 0x14, 0xff, 0xd1, 0x3b, 0x00, 0x00, - 0x00, 0x00, 0xa0, 0xf7, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x44, 0x90, 0x00, 0x00, 0x00, - /* ch = 'W' */ - 0x15, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, - 0xff, 0x1f, 0x14, 0x32, 0x00, 0xb7, 0x26, - 0xbd, 0x35, 0x35, 0xa7, 0x00, 0xff, 0x17, - 0x82, 0x54, 0x6b, 0xff, 0x1f, 0xe5, 0x04, - 0x54, 0x7c, 0xcf, 0xdb, 0x64, 0xa7, 0x00, - 0x35, 0xf7, 0xb7, 0x64, 0xec, 0x7c, 0x00, - 0x1f, 0xff, 0x64, 0x2a, 0xff, 0x50, 0x00, - 0x0d, 0xff, 0x32, 0x0d, 0xff, 0x32, 0x00, - 0x00, 0xcf, 0x10, 0x00, 0xa0, 0x1f, 0x00, - /* ch = 'X' */ - 0x12, 0x0c, 0x00, 0x00, 0x08, 0x12, - 0x44, 0xcf, 0x04, 0x00, 0x90, 0x54, - 0x04, 0xc8, 0x48, 0x2a, 0xe5, 0x10, - 0x00, 0x32, 0xec, 0xb7, 0x54, 0x00, - 0x00, 0x00, 0xa7, 0xe5, 0x08, 0x00, - 0x00, 0x04, 0xdb, 0xff, 0x1f, 0x00, - 0x00, 0x48, 0xc8, 0x82, 0x97, 0x00, - 0x0d, 0xe5, 0x35, 0x17, 0xf7, 0x2c, - 0x5f, 0xa0, 0x04, 0x00, 0x5f, 0xa7, - /* ch = 'Y' */ - 0x15, 0x08, 0x00, 0x00, 0x04, 0x15, 0x04, - 0x7c, 0x90, 0x00, 0x00, 0x44, 0xc8, 0x04, - 0x17, 0xff, 0x26, 0x00, 0xc8, 0x3f, 0x00, - 0x00, 0x70, 0x97, 0x32, 0xdb, 0x08, 0x00, - 0x00, 0x17, 0xff, 0xe5, 0x4c, 0x00, 0x00, - 0x00, 0x00, 0x70, 0xe5, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, - /* ch = 'Z' */ - 0x0c, 0x15, 0x15, 0x15, 0x15, 0x12, - 0x45, 0xcf, 0xcf, 0xcf, 0xef, 0xa7, - 0x00, 0x00, 0x00, 0x10, 0xf7, 0x26, - 0x00, 0x00, 0x00, 0x82, 0x70, 0x00, - 0x00, 0x00, 0x2f, 0xe5, 0x13, 0x00, - 0x00, 0x04, 0xdb, 0x48, 0x00, 0x00, - 0x00, 0x54, 0xb1, 0x04, 0x00, 0x00, - 0x1c, 0xf7, 0x26, 0x00, 0x00, 0x00, - 0x77, 0xff, 0xcf, 0xcf, 0xcf, 0xcf, - /* ch = '[' */ - 0x67, 0xcf, 0xcf, 0xcf, 0x45, - 0x7c, 0x54, 0x00, 0x00, 0x00, - 0x7c, 0x54, 0x00, 0x00, 0x00, - 0x7c, 0x54, 0x00, 0x00, 0x00, - 0x7c, 0x54, 0x00, 0x00, 0x00, - 0x7c, 0x54, 0x00, 0x00, 0x00, - 0x7c, 0x54, 0x00, 0x00, 0x00, - 0x7c, 0x54, 0x00, 0x00, 0x00, - 0x7c, 0x54, 0x00, 0x00, 0x00, - 0x7c, 0xb9, 0x74, 0x74, 0x30, - 0x0f, 0x15, 0x15, 0x15, 0x0f, - /* ch = '\' */ - 0x19, 0x4e, 0x00, - 0x17, 0xff, 0x1a, - 0x00, 0x8a, 0x70, - 0x00, 0x22, 0xff, - 0x00, 0x00, 0xa0, - 0x00, 0x00, 0x2c, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* ch = ']' */ - 0x1a, 0xcf, 0xcf, 0xcf, 0x95, - 0x00, 0x00, 0x00, 0x32, 0xbd, - 0x00, 0x00, 0x00, 0x32, 0xbd, - 0x00, 0x00, 0x00, 0x32, 0xbd, - 0x00, 0x00, 0x00, 0x32, 0xbd, - 0x00, 0x00, 0x00, 0x32, 0xbd, - 0x00, 0x00, 0x00, 0x32, 0xbd, - 0x00, 0x00, 0x00, 0x32, 0xbd, - 0x00, 0x00, 0x00, 0x32, 0xbd, - 0x22, 0x74, 0x74, 0x9c, 0xbd, - 0x08, 0x15, 0x15, 0x15, 0x15, - /* ch = '^' */ - 0x00, 0x00, 0x04, 0x0c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xaf, 0x00, 0x00, - 0x00, 0x17, 0xef, 0xdb, 0x35, 0x00, - 0x00, 0x82, 0x59, 0x3b, 0xcf, 0x00, - 0x09, 0x50, 0x08, 0x00, 0x50, 0x08, - /* ch = '_' */ - /* ch = '`' */ - 0x27, 0x51, 0x00, - 0x22, 0xec, 0x10, - 0x00, 0xa0, 0xb7, - 0x00, 0x10, 0x2a, - /* ch = 'a' */ - 0x09, 0x8d, 0xdd, 0xd4, 0xc4, 0x10, - 0x00, 0x22, 0x04, 0x00, 0x90, 0x70, - 0x00, 0x0f, 0x36, 0x36, 0xa0, 0x82, - 0x2f, 0xdb, 0x31, 0x15, 0x5e, 0x82, - 0x7c, 0x82, 0x00, 0x04, 0xb7, 0x82, - 0x2a, 0xf7, 0x82, 0xcb, 0xd4, 0x82, - 0x00, 0x04, 0x15, 0x08, 0x00, 0x00, - /* ch = 'b' */ - 0x30, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0xd4, 0xdd, 0xd4, 0x10, 0x00, - 0x50, 0xe5, 0x0c, 0x04, 0x90, 0x90, 0x00, - 0x50, 0x88, 0x00, 0x00, 0x3b, 0xd9, 0x00, - 0x50, 0x88, 0x00, 0x00, 0x35, 0xcf, 0x04, - 0x50, 0xd9, 0x04, 0x00, 0x82, 0x75, 0x00, - 0x50, 0xc4, 0xe5, 0xdd, 0xd4, 0x13, 0x00, - 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, 0x00, - /* ch = 'c' */ - 0x00, 0x35, 0xdd, 0xcf, 0xf7, 0x3b, 0x00, - 0x22, 0xf7, 0x21, 0x00, 0x24, 0x50, 0x04, - 0x54, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x54, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2a, 0xff, 0x21, 0x00, 0x10, 0x1b, 0x00, - 0x00, 0x44, 0xf7, 0xcf, 0xe5, 0x48, 0x00, - 0x00, 0x00, 0x04, 0x15, 0x08, 0x00, 0x00, - /* ch = 'd' */ - 0x00, 0x00, 0x00, 0x00, 0x30, 0x4a, - 0x00, 0x00, 0x00, 0x00, 0x50, 0x82, - 0x00, 0x00, 0x00, 0x00, 0x50, 0x82, - 0x04, 0x94, 0xdd, 0xdd, 0xdb, 0x82, - 0x48, 0xa7, 0x04, 0x04, 0xb7, 0x82, - 0x7c, 0x54, 0x00, 0x00, 0x7c, 0x82, - 0x7c, 0x59, 0x00, 0x00, 0x7c, 0x82, - 0x48, 0xcf, 0x04, 0x04, 0xc8, 0x82, - 0x04, 0xa9, 0xef, 0xdd, 0xc4, 0x88, - 0x00, 0x00, 0x0f, 0x08, 0x00, 0x00, - /* ch = 'e' */ - 0x00, 0x66, 0xd4, 0xb3, 0xc4, 0x10, - 0x39, 0xc8, 0x08, 0x00, 0x82, 0x5f, - 0x77, 0xd1, 0x74, 0x74, 0xb1, 0xa7, - 0x7c, 0x6d, 0x15, 0x15, 0x15, 0x15, - 0x40, 0xcf, 0x04, 0x00, 0x0c, 0x08, - 0x04, 0x7e, 0xef, 0x82, 0xdd, 0x32, - 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, - /* ch = 'f' */ - 0x00, 0x19, 0x74, 0xab, 0x48, 0x00, - 0x04, 0xdb, 0x3a, 0x0f, 0xb1, 0x13, - 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x87, 0xff, 0x7b, 0x74, 0x00, 0x00, - 0x28, 0xff, 0x15, 0x15, 0x04, 0x00, - 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, - /* ch = 'g' */ - 0x00, 0x00, 0x0f, 0x08, 0x00, 0x00, 0x00, - 0x04, 0xa9, 0xa4, 0xef, 0xcb, 0x8f, 0x17, - 0x4d, 0x97, 0x04, 0x22, 0xff, 0x04, 0x00, - 0x44, 0xbd, 0x04, 0x26, 0xf7, 0x04, 0x00, - 0x04, 0xd9, 0xe5, 0xdd, 0x2f, 0x00, 0x00, - 0x2a, 0xc6, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x1b, 0xe0, 0xcf, 0xcf, 0xef, 0x4d, 0x00, - 0x99, 0x43, 0x00, 0x00, 0x32, 0xd1, 0x00, - 0x4d, 0xdb, 0x5b, 0x5b, 0xd4, 0x44, 0x00, - 0x00, 0x0c, 0x15, 0x15, 0x0c, 0x00, 0x00, - /* ch = 'h' */ - 0x30, 0x64, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xd9, 0xa9, 0xd4, 0xdb, 0x1c, - 0x50, 0xff, 0x24, 0x00, 0x97, 0x64, - 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, - 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, - 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, - 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, - /* ch = 'i' */ - 0x00, 0x26, 0x48, 0x00, 0x00, - 0x00, 0x49, 0x9c, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0xcf, 0xe5, 0xbd, 0x00, 0x00, - 0x00, 0x50, 0xbd, 0x00, 0x00, - 0x00, 0x50, 0xbd, 0x00, 0x00, - 0x00, 0x50, 0xbd, 0x00, 0x00, - 0x00, 0x50, 0xbd, 0x00, 0x00, - 0xcf, 0xe5, 0xff, 0xcf, 0x1a, - /* ch = 'j' */ - 0x00, 0x00, 0x00, 0x26, 0x48, - 0x00, 0x00, 0x00, 0x49, 0x9c, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x67, 0xcf, 0xe5, 0xbd, - 0x00, 0x00, 0x00, 0x50, 0xbd, - 0x00, 0x00, 0x00, 0x50, 0xbd, - 0x00, 0x00, 0x00, 0x50, 0xbd, - 0x00, 0x00, 0x00, 0x50, 0xbd, - 0x00, 0x00, 0x00, 0x50, 0xbd, - 0x10, 0x16, 0x00, 0x64, 0x97, - 0x5c, 0xdb, 0x82, 0xef, 0x21, - 0x00, 0x12, 0x15, 0x0c, 0x00, - /* ch = 'k' */ - 0x30, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x19, 0xdb, 0x3f, 0x00, - 0x50, 0xbd, 0x1f, 0xe5, 0x35, 0x00, 0x00, - 0x50, 0xec, 0xf7, 0x52, 0x00, 0x00, 0x00, - 0x50, 0xe5, 0x47, 0xff, 0x1f, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x50, 0xe5, 0x10, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0xb1, 0xb7, 0x04, - /* ch = 'l' */ - 0x14, 0x74, 0x74, 0x42, 0x00, 0x00, - 0x04, 0x15, 0x5e, 0x82, 0x00, 0x00, - 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, - 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, - 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, - 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, - 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, - 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, - 0x2d, 0xcf, 0xe5, 0xf7, 0xcf, 0x45, - /* ch = 'm' */ - 0xb7, 0xe5, 0xdb, 0xbb, 0xbb, 0xdb, 0x00, - 0xb7, 0x4c, 0x50, 0xbd, 0x1f, 0xff, 0x1f, - 0xb7, 0x35, 0x50, 0x82, 0x1c, 0xff, 0x1f, - 0xb7, 0x35, 0x50, 0x82, 0x1c, 0xff, 0x1f, - 0xb7, 0x35, 0x50, 0x82, 0x1c, 0xff, 0x1f, - 0xb7, 0x35, 0x50, 0x82, 0x1c, 0xff, 0x1f, - /* ch = 'n' */ - 0x50, 0xd9, 0xbb, 0xd4, 0xdb, 0x17, - 0x50, 0xff, 0x24, 0x00, 0xa7, 0x59, - 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, - 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, - 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, - 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, - /* ch = 'o' */ - 0x00, 0x66, 0xdd, 0xdd, 0xa9, 0x10, 0x00, - 0x44, 0xdb, 0x0c, 0x00, 0x90, 0x82, 0x00, - 0xa0, 0x64, 0x00, 0x00, 0x35, 0xec, 0x00, - 0xb1, 0x64, 0x00, 0x00, 0x32, 0xf7, 0x04, - 0x50, 0xcf, 0x04, 0x00, 0x82, 0x90, 0x00, - 0x04, 0x84, 0xef, 0xb3, 0xcb, 0x13, 0x00, - 0x00, 0x00, 0x0c, 0x15, 0x00, 0x00, 0x00, - /* ch = 'p' */ - 0x50, 0xbd, 0xcf, 0xdd, 0xdb, 0x19, 0x00, - 0x50, 0xe5, 0x0c, 0x00, 0x90, 0xa0, 0x00, - 0x50, 0x88, 0x00, 0x00, 0x35, 0xff, 0x04, - 0x50, 0x88, 0x00, 0x00, 0x32, 0xf7, 0x04, - 0x50, 0xd9, 0x04, 0x00, 0x75, 0x90, 0x00, - 0x50, 0xdb, 0xe5, 0xc4, 0xd4, 0x21, 0x00, - 0x50, 0x82, 0x08, 0x15, 0x04, 0x00, 0x00, - 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 'q' */ - 0x04, 0x94, 0xcb, 0xdd, 0xdb, 0x82, - 0x48, 0xb7, 0x08, 0x04, 0xa7, 0x82, - 0x90, 0x54, 0x00, 0x00, 0x54, 0x82, - 0x90, 0x64, 0x00, 0x00, 0x54, 0x82, - 0x48, 0xcf, 0x04, 0x04, 0xb7, 0x82, - 0x04, 0xa9, 0xef, 0xdd, 0xc4, 0x82, - 0x00, 0x00, 0x0f, 0x08, 0x50, 0x82, - 0x00, 0x00, 0x00, 0x00, 0x50, 0x82, - 0x00, 0x00, 0x00, 0x00, 0x0c, 0x12, - /* ch = 'r' */ - 0xff, 0xb1, 0xdd, 0xdd, 0xab, - 0xff, 0xb1, 0x08, 0x04, 0x28, - 0xff, 0x35, 0x00, 0x00, 0x00, - 0xff, 0x1f, 0x00, 0x00, 0x00, - 0xff, 0x1f, 0x00, 0x00, 0x00, - 0xff, 0x1f, 0x00, 0x00, 0x00, - /* ch = 's' */ - 0x00, 0x66, 0xcb, 0x9e, 0xdb, 0x26, - 0x1c, 0xff, 0x21, 0x00, 0x2c, 0x21, - 0x04, 0xa2, 0xef, 0x5b, 0x1e, 0x00, - 0x00, 0x00, 0x18, 0x5a, 0xf7, 0x44, - 0x24, 0x3b, 0x00, 0x00, 0x82, 0x7c, - 0x26, 0xd4, 0xcb, 0xab, 0xd4, 0x21, - 0x00, 0x00, 0x0c, 0x12, 0x00, 0x00, - /* ch = 't' */ - 0x00, 0x00, 0x5c, 0x28, 0x00, 0x00, - 0x00, 0x00, 0xff, 0x35, 0x00, 0x00, - 0x42, 0xcf, 0xff, 0xd4, 0xcf, 0x1c, - 0x00, 0x0d, 0xff, 0x1f, 0x00, 0x00, - 0x00, 0x1c, 0xff, 0x1f, 0x00, 0x00, - 0x00, 0x1c, 0xff, 0x1f, 0x00, 0x00, - 0x00, 0x1a, 0xff, 0x26, 0x04, 0x0c, - 0x00, 0x00, 0x99, 0xf7, 0xe5, 0x62, - 0x00, 0x00, 0x00, 0x0f, 0x04, 0x00, - /* ch = 'u' */ - 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, - 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, - 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, - 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, - 0x44, 0xd9, 0x04, 0x04, 0xc8, 0x82, - 0x04, 0xa9, 0xc4, 0xc4, 0xdb, 0x82, - 0x00, 0x00, 0x12, 0x08, 0x00, 0x00, - /* ch = 'v' */ - 0x70, 0x88, 0x00, 0x00, 0x35, 0xa7, 0x04, - 0x24, 0xff, 0x0d, 0x00, 0x70, 0x54, 0x00, - 0x00, 0xc8, 0x4c, 0x0d, 0xf7, 0x1a, 0x00, - 0x00, 0x48, 0xcf, 0x48, 0x90, 0x00, 0x00, - 0x00, 0x0d, 0xf7, 0xf7, 0x2f, 0x00, 0x00, - 0x00, 0x00, 0x8a, 0xb7, 0x04, 0x00, 0x00, - /* ch = 'w' */ - 0xff, 0x1f, 0x16, 0x26, 0x00, 0xff, 0x1f, - 0xbd, 0x32, 0x5f, 0xbd, 0x00, 0xff, 0x08, - 0x77, 0x59, 0xa0, 0xff, 0x2f, 0xcf, 0x04, - 0x44, 0x9e, 0xe5, 0x82, 0xa0, 0x97, 0x00, - 0x24, 0xff, 0x82, 0x3b, 0xff, 0x59, 0x00, - 0x04, 0xff, 0x3f, 0x14, 0xff, 0x37, 0x00, - /* ch = 'x' */ - 0x35, 0xe5, 0x10, 0x04, 0xdb, 0x37, - 0x00, 0x7c, 0x82, 0x6b, 0x82, 0x04, - 0x00, 0x0d, 0xdb, 0xe5, 0x13, 0x00, - 0x00, 0x10, 0xdb, 0xff, 0x1f, 0x00, - 0x00, 0x7c, 0x7c, 0x59, 0xb7, 0x04, - 0x35, 0xdb, 0x13, 0x04, 0xb1, 0x68, - /* ch = 'y' */ - 0x5a, 0x9e, 0x00, 0x00, 0x3b, 0xc8, 0x04, - 0x17, 0xff, 0x1a, 0x00, 0x8a, 0x5f, 0x00, - 0x00, 0x8a, 0x5f, 0x0d, 0xf7, 0x1a, 0x00, - 0x00, 0x39, 0xec, 0x3f, 0xa7, 0x04, 0x00, - 0x00, 0x04, 0xe5, 0xff, 0x3b, 0x00, 0x00, - 0x00, 0x00, 0x5a, 0xf7, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x5f, 0x75, 0x00, 0x00, 0x00, - 0xc0, 0x82, 0xef, 0x1f, 0x00, 0x00, 0x00, - 0x0c, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00, - /* ch = 'z' */ - 0x2d, 0xcf, 0xcf, 0xcf, 0xff, 0x50, - 0x00, 0x00, 0x00, 0x50, 0xb1, 0x08, - 0x00, 0x00, 0x32, 0xf7, 0x1f, 0x00, - 0x00, 0x1f, 0xf7, 0x35, 0x00, 0x00, - 0x10, 0xdb, 0x54, 0x00, 0x00, 0x00, - 0x77, 0xff, 0xd4, 0xcf, 0xcf, 0x95, - /* ch = '{' */ - 0x00, 0x15, 0x15, 0x08, - 0xa9, 0x99, 0x36, 0x19, - 0xff, 0x10, 0x00, 0x00, - 0xff, 0x04, 0x00, 0x00, - 0xe5, 0x04, 0x00, 0x00, - 0x2d, 0x00, 0x00, 0x00, - 0xa7, 0x00, 0x00, 0x00, - 0xff, 0x04, 0x00, 0x00, - 0xff, 0x04, 0x00, 0x00, - 0xff, 0x13, 0x00, 0x00, - 0x77, 0xef, 0x74, 0x22, - /* ch = '|' */ - 0x1e, 0x26, - 0x50, 0x82, - 0x50, 0x82, - 0x50, 0x82, - 0x50, 0x82, - 0x50, 0x82, - 0x50, 0x82, - 0x50, 0x82, - 0x50, 0x82, - 0x50, 0x82, - 0x50, 0x82, - /* ch = '}' */ - 0x04, 0x15, 0x15, 0x04, 0x00, - 0x0d, 0x36, 0x77, 0xdb, 0x0d, - 0x00, 0x00, 0x00, 0xbd, 0x35, - 0x00, 0x00, 0x00, 0xb7, 0x35, - 0x00, 0x00, 0x00, 0xa0, 0x4c, - 0x00, 0x00, 0x00, 0x1b, 0xec, - 0x00, 0x00, 0x00, 0x6b, 0x68, - 0x00, 0x00, 0x00, 0xb7, 0x35, - 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0x04, 0xcf, 0x37, - 0x14, 0x74, 0xcb, 0xa9, 0x08, - /* ch = '~' */ - 0x2c, 0xe5, 0xef, 0x6b, 0x1e, 0xc8, 0x09, - 0x2f, 0x21, 0x08, 0x8d, 0xbd, 0x31, 0x00 + /* ch = '!' */ + 0x45, 0x3d, 0xb7, 0xbd, 0xa0, 0x88, 0x7c, 0x82, 0x7c, 0x64, 0x6b, 0x54, + 0x1e, 0x21, 0x22, 0x21, 0xe5, 0xb7, 0x0c, 0x0c, + /* ch = '"' */ + 0x2a, 0x4e, 0x1c, 0x74, 0x04, 0x50, 0xbd, 0x2f, 0xff, 0x17, 0x5f, 0x64, + 0x35, 0xb7, 0x04, 0x58, 0x1f, 0x36, 0x36, 0x00, + /* ch = '#' */ + 0x00, 0x00, 0x15, 0x00, 0x04, 0x08, 0x00, 0x00, 0x1c, 0xf7, 0x04, 0xf7, + 0x1f, 0x00, 0x00, 0x2a, 0xbd, 0x0d, 0xff, 0x10, 0x00, 0x77, 0xe5, 0xef, + 0x95, 0xf7, 0x74, 0x17, 0x00, 0x50, 0x70, 0x32, 0xbd, 0x00, 0x00, 0x00, + 0x77, 0x5e, 0x4f, 0x95, 0x15, 0x00, 0x74, 0xe5, 0x9c, 0x87, 0x82, 0x30, + 0x04, 0x00, 0xb7, 0x26, 0x7c, 0x50, 0x00, 0x00, 0x00, 0xcf, 0x1c, 0x8f, + 0x2f, 0x00, 0x00, + /* ch = '$' */ + 0x00, 0x00, 0x16, 0x2d, 0x00, 0x00, 0x00, 0x1b, 0x9c, 0xec, 0x50, 0x08, + 0x17, 0xf7, 0x59, 0xbd, 0x5f, 0x66, 0x2a, 0xec, 0x3f, 0xbd, 0x00, 0x00, + 0x00, 0x66, 0xff, 0xd9, 0x16, 0x00, 0x00, 0x00, 0x35, 0xe5, 0xdb, 0x50, + 0x00, 0x00, 0x32, 0xbd, 0x24, 0xff, 0x32, 0x90, 0x37, 0xc6, 0x64, 0xa0, + 0x04, 0x48, 0xdd, 0xf7, 0x73, 0x13, 0x00, 0x00, 0x22, 0x5c, 0x00, 0x00, + /* ch = '%' */ + 0x04, 0x15, 0x08, 0x00, 0x08, 0x15, 0x00, 0x77, 0x94, 0xe5, 0x0d, 0x6b, + 0x70, 0x00, 0xf7, 0x1f, 0xbd, 0x44, 0xef, 0x13, 0x00, 0x66, 0xc4, 0xd4, + 0x88, 0x54, 0x00, 0x00, 0x00, 0x12, 0x28, 0xdb, 0x08, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x43, 0x15, 0x08, 0x00, 0x00, 0x32, 0xb7, 0x7c, 0x85, 0xe5, + 0x0d, 0x04, 0xc8, 0x2c, 0xf7, 0x1f, 0xb7, 0x2a, 0x44, 0x90, 0x04, 0x66, + 0xc4, 0xd4, 0x08, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0x00, + /* ch = '&' */ + 0x00, 0x00, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00, 0xa9, 0xab, 0xef, 0x32, + 0x00, 0x00, 0x1c, 0xff, 0x1f, 0x54, 0x82, 0x00, 0x00, 0x00, 0xc8, 0x43, + 0xb1, 0x48, 0x00, 0x00, 0x00, 0x43, 0xff, 0x75, 0x04, 0x00, 0x00, 0x2f, + 0xf7, 0x77, 0xbd, 0x04, 0x5b, 0x04, 0xa0, 0x64, 0x00, 0xb1, 0xdb, 0xc8, + 0x08, 0xb1, 0x68, 0x00, 0x2b, 0xff, 0x46, 0x00, 0x32, 0xf7, 0xd4, 0xd4, + 0x54, 0xf7, 0x0a, 0x00, 0x04, 0x15, 0x00, 0x00, 0x0f, 0x00, + /* ch = ''' */ + 0x1c, 0x74, 0x04, 0x2f, 0xff, 0x17, 0x35, 0xa7, 0x04, 0x36, 0x36, 0x00, + /* ch = '(' */ + 0x00, 0x04, 0x48, 0x1c, 0x10, 0xb1, 0x84, 0x0f, 0x77, 0x82, 0x04, 0x00, + 0xff, 0x1a, 0x00, 0x00, 0xbd, 0x04, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, + 0xb7, 0x00, 0x00, 0x00, 0xff, 0x0d, 0x00, 0x00, 0xc8, 0x54, 0x00, 0x00, + 0x2a, 0xff, 0x21, 0x00, 0x00, 0x2c, 0xf7, 0x33, 0x00, 0x00, 0x0c, 0x08, + /* ch = ')' */ + 0x14, 0x48, 0x04, 0x00, 0x10, 0x99, 0xb7, 0x10, 0x00, 0x00, 0x7c, 0xa7, + 0x00, 0x00, 0x10, 0xf7, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x50, + 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x2f, 0xf7, + 0x00, 0x19, 0xdb, 0x35, 0x27, 0xef, 0x3f, 0x00, 0x04, 0x0f, 0x00, 0x00, + /* ch = '*' */ + 0x00, 0x00, 0x45, 0x82, 0x00, 0x00, 0x21, 0x13, 0x50, 0x82, 0x08, 0x21, + 0x40, 0xc4, 0xd4, 0xd1, 0xd4, 0x5b, 0x00, 0x04, 0xb1, 0xdb, 0x10, 0x00, + 0x04, 0xb1, 0x59, 0x3b, 0xb7, 0x04, 0x04, 0x50, 0x08, 0x00, 0x48, 0x0c, + /* ch = '+' */ + 0x00, 0x00, 0x45, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x82, 0x00, + 0x00, 0x00, 0x42, 0x74, 0xb1, 0xd1, 0x74, 0x74, 0x00, 0x0f, 0x15, 0x5e, + 0x88, 0x15, 0x15, 0x04, 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x45, 0x00, 0x00, 0x00, + /* ch = ',' */ + 0x00, 0x22, 0x16, 0x00, 0xef, 0xec, 0x00, 0x37, 0xa7, 0x09, 0xd4, 0x21, + 0x00, 0x0f, 0x00, + /* ch = '-' */ + 0x22, 0x74, 0x74, 0x74, 0x74, 0x42, 0x16, 0x36, 0x36, 0x36, 0x36, 0x28, + /* ch = '.' */ + 0x22, 0x1b, 0xf7, 0xb7, 0x0c, 0x0c, + /* ch = '/' */ + 0x00, 0x39, 0x26, 0x04, 0xe5, 0x35, 0x44, 0xc8, 0x04, 0xc8, 0x3f, 0x00, + 0xe5, 0x08, 0x00, 0x4c, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = '0' */ + 0x00, 0x00, 0x0c, 0x0f, 0x00, 0x00, 0x00, 0x44, 0xef, 0xcb, 0x7c, 0x00, + 0x17, 0xf7, 0x13, 0x04, 0xec, 0x35, 0x50, 0x88, 0x00, 0x44, 0xff, 0x7c, + 0x7c, 0x54, 0x1f, 0xef, 0x54, 0xbd, 0x7c, 0x6d, 0xdb, 0x35, 0x32, 0xbd, + 0x50, 0xff, 0x54, 0x00, 0x4d, 0x88, 0x1c, 0xff, 0x21, 0x04, 0xb7, 0x3b, + 0x00, 0x44, 0xf7, 0xdd, 0x77, 0x04, 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, + /* ch = '1' */ + 0x00, 0x00, 0x04, 0x12, 0x00, 0x31, 0xd4, 0xbd, 0x04, 0x50, 0x3e, 0xbd, + 0x00, 0x00, 0x32, 0xbd, 0x00, 0x00, 0x32, 0xbd, 0x00, 0x00, 0x32, 0xbd, + 0x00, 0x00, 0x32, 0xbd, 0x00, 0x00, 0x32, 0xbd, 0x00, 0x00, 0x32, 0xbd, + /* ch = '2' */ + 0x00, 0x00, 0x0c, 0x12, 0x00, 0x00, 0x04, 0x94, 0xcb, 0xcb, 0xc4, 0x10, + 0x10, 0x48, 0x04, 0x00, 0xb7, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x82, 0x70, + 0x00, 0x00, 0x00, 0x1f, 0xf7, 0x1f, 0x00, 0x00, 0x1f, 0xdb, 0x37, 0x00, + 0x00, 0x1f, 0xdb, 0x35, 0x00, 0x00, 0x00, 0xb1, 0x54, 0x00, 0x00, 0x00, + 0x2f, 0xff, 0xd4, 0xcf, 0xcf, 0x7c, + /* ch = '3' */ + 0x00, 0x00, 0x0c, 0x08, 0x00, 0x00, 0x09, 0xa9, 0xd4, 0xe5, 0x7c, 0x00, + 0x00, 0x22, 0x00, 0x04, 0xe5, 0x2c, 0x00, 0x00, 0x00, 0x10, 0xe5, 0x2a, + 0x00, 0x00, 0x74, 0xe5, 0x53, 0x00, 0x00, 0x00, 0x15, 0x37, 0xf7, 0x17, + 0x00, 0x00, 0x00, 0x00, 0x82, 0x54, 0x04, 0x3d, 0x00, 0x08, 0xc8, 0x3b, + 0x22, 0xd4, 0xdd, 0xe5, 0x94, 0x08, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, + /* ch = '4' */ + 0x00, 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xbd, 0x00, + 0x00, 0x00, 0x32, 0xff, 0xbd, 0x00, 0x00, 0x10, 0xd4, 0x82, 0xbd, 0x00, + 0x00, 0x7c, 0x50, 0x50, 0xbd, 0x00, 0x32, 0xb1, 0x08, 0x50, 0xbd, 0x00, + 0x67, 0xcf, 0xcf, 0xe5, 0xf7, 0x9c, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, + 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, + /* ch = '5' */ + 0x00, 0x15, 0x15, 0x15, 0x15, 0x0c, 0x00, 0xff, 0xd4, 0xcf, 0xcf, 0x49, + 0x04, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x15, 0x15, 0x04, 0x00, + 0x1c, 0xff, 0x8f, 0x8f, 0xe5, 0x1c, 0x00, 0x15, 0x00, 0x00, 0x70, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x13, 0x73, 0x00, 0x00, 0x90, 0x70, + 0x10, 0xbb, 0xe5, 0xbb, 0xbb, 0x13, 0x00, 0x00, 0x0c, 0x15, 0x00, 0x00, + /* ch = '6' */ + 0x00, 0x00, 0x04, 0x15, 0x08, 0x00, 0x00, 0x2c, 0xe5, 0x8f, 0xef, 0x2b, + 0x04, 0xe5, 0x37, 0x00, 0x0c, 0x04, 0x2a, 0xe5, 0x0f, 0x15, 0x04, 0x00, + 0x3b, 0xff, 0xd4, 0x95, 0xdb, 0x10, 0x50, 0xe5, 0x0c, 0x00, 0x8a, 0x64, + 0x35, 0xc6, 0x00, 0x00, 0x50, 0x82, 0x17, 0xff, 0x26, 0x00, 0x90, 0x5f, + 0x00, 0x44, 0xef, 0xd4, 0xa9, 0x10, 0x00, 0x00, 0x04, 0x12, 0x00, 0x00, + /* ch = '7' */ + 0x08, 0x15, 0x15, 0x15, 0x15, 0x0f, 0x2d, 0xcf, 0xcf, 0xcf, 0xf7, 0x5f, + 0x00, 0x00, 0x00, 0x17, 0xff, 0x1a, 0x00, 0x00, 0x00, 0x5a, 0x90, 0x00, + 0x00, 0x00, 0x04, 0xe5, 0x3b, 0x00, 0x00, 0x00, 0x32, 0xe5, 0x08, 0x00, + 0x00, 0x00, 0x8a, 0x75, 0x00, 0x00, 0x00, 0x0d, 0xff, 0x2c, 0x00, 0x00, + 0x00, 0x3b, 0xe5, 0x04, 0x00, 0x00, + /* ch = '8' */ + 0x00, 0x00, 0x0f, 0x15, 0x00, 0x00, 0x00, 0x77, 0xbb, 0xa4, 0xdb, 0x10, + 0x1a, 0xff, 0x1a, 0x00, 0xbd, 0x48, 0x0d, 0xf7, 0x37, 0x10, 0xe5, 0x2a, + 0x00, 0x2b, 0xff, 0xef, 0x53, 0x00, 0x10, 0xd4, 0x3f, 0x3f, 0xff, 0x1f, + 0x4d, 0xa7, 0x04, 0x00, 0x70, 0x7c, 0x44, 0xcf, 0x04, 0x00, 0x90, 0x70, + 0x04, 0x94, 0xef, 0xdd, 0xbb, 0x13, 0x00, 0x00, 0x0c, 0x12, 0x00, 0x00, + /* ch = '9' */ + 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x77, 0xd4, 0xcb, 0x99, 0x00, + 0x2a, 0xe5, 0x10, 0x04, 0xc8, 0x3b, 0x49, 0xbd, 0x00, 0x00, 0x7c, 0x70, + 0x2a, 0xff, 0x10, 0x04, 0xb7, 0x82, 0x00, 0x66, 0xf7, 0xdd, 0xdb, 0x82, + 0x00, 0x00, 0x00, 0x00, 0x82, 0x59, 0x00, 0x21, 0x00, 0x10, 0xf7, 0x24, + 0x17, 0xe5, 0xd4, 0xe5, 0x48, 0x00, 0x00, 0x00, 0x12, 0x04, 0x00, 0x00, + /* ch = ':' */ + 0x28, 0x28, 0xdb, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x22, 0x1b, 0xf7, 0xb7, + 0x0c, 0x0c, + /* ch = ';' */ + 0x00, 0x28, 0x28, 0x00, 0xdb, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x22, 0x16, 0x00, 0xef, 0xec, 0x00, 0x37, 0xa7, 0x09, 0xd4, 0x21, + 0x00, 0x0f, 0x00, + /* ch = '<' */ + 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x1e, 0xbb, 0xbb, 0x1b, 0xa4, + 0xbb, 0x2b, 0x00, 0xc4, 0x2b, 0x00, 0x00, 0x00, 0xef, 0x66, 0x08, 0x00, + 0x00, 0x08, 0x50, 0xef, 0x37, 0x04, 0x00, 0x00, 0x13, 0x94, 0xdb, 0x00, + 0x00, 0x00, 0x00, 0x22, + /* ch = '=' */ + 0x42, 0x74, 0x74, 0x74, 0x74, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0xcf, 0xcf, + 0xcf, 0xcf, 0xcf, 0x04, + /* ch = '>' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0xa4, 0xc4, + 0x28, 0x00, 0x00, 0x00, 0x1b, 0xab, 0xc4, 0x00, 0x04, 0x48, 0xe5, 0x50, + 0x04, 0xd4, 0x73, 0x16, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* ch = '?' */ + 0x00, 0x1b, 0x67, 0x74, 0x2e, 0x00, 0x2d, 0xf7, 0x37, 0x37, 0xf7, 0x35, + 0x00, 0x22, 0x00, 0x00, 0x88, 0x7c, 0x00, 0x00, 0x00, 0x10, 0xe5, 0x48, + 0x00, 0x00, 0x04, 0xb1, 0x6b, 0x04, 0x00, 0x00, 0x2f, 0xcf, 0x04, 0x00, + 0x00, 0x00, 0x22, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x25, 0x00, 0x00, + 0x00, 0x00, 0x77, 0xff, 0x1a, 0x00, 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, + /* ch = '@' */ + 0x00, 0x00, 0x0c, 0x15, 0x08, 0x00, 0x00, 0x00, 0x66, 0xbb, 0x67, 0xe5, + 0x24, 0x00, 0x39, 0xa0, 0x08, 0x00, 0x2c, 0xcf, 0x00, 0xa0, 0x35, 0x19, + 0x8f, 0xbd, 0xff, 0x04, 0xbd, 0x1f, 0xdb, 0x3a, 0x0d, 0xff, 0x04, 0xb7, + 0x21, 0xf7, 0x28, 0x2f, 0xff, 0x04, 0x90, 0x43, 0x35, 0xcf, 0xab, 0xcf, + 0x04, 0x2a, 0xe5, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xe5, 0x82, + 0xbb, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x15, 0x0c, 0x00, 0x00, + /* ch = 'A' */ + 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x4c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc8, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x24, 0xc8, + 0xf7, 0x24, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x70, 0x64, 0x00, 0x00, 0x00, + 0xe5, 0x24, 0x2a, 0xec, 0x04, 0x00, 0x2a, 0xe5, 0x74, 0x74, 0xe5, 0x35, + 0x00, 0x70, 0x70, 0x00, 0x00, 0x5a, 0x90, 0x00, 0xe5, 0x2c, 0x00, 0x00, + 0x22, 0xff, 0x1a, + /* ch = 'B' */ + 0x0f, 0x15, 0x15, 0x00, 0x00, 0x00, 0x7c, 0xb1, 0x74, 0xdd, 0xc4, 0x10, + 0x7c, 0x54, 0x00, 0x00, 0x97, 0x64, 0x7c, 0x54, 0x00, 0x04, 0xa7, 0x4c, + 0x7c, 0xef, 0xcf, 0xe5, 0x9e, 0x08, 0x7c, 0x54, 0x00, 0x16, 0xb1, 0x50, + 0x7c, 0x54, 0x00, 0x00, 0x35, 0xcf, 0x7c, 0x54, 0x00, 0x00, 0x7c, 0xa7, + 0x7c, 0xef, 0xcf, 0xe5, 0xb3, 0x1b, + /* ch = 'C' */ + 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, 0x00, 0x00, 0x4d, 0xe5, 0x82, 0xef, + 0x3b, 0x00, 0x2a, 0xe5, 0x13, 0x00, 0x24, 0x9e, 0x0a, 0x6b, 0x70, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb1, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, + 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x75, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x2a, 0xff, 0x1f, 0x00, 0x1f, 0x48, 0x00, 0x00, 0x44, 0xf7, 0xab, + 0xe5, 0x2f, 0x00, 0x00, 0x00, 0x04, 0x15, 0x00, 0x00, 0x00, + /* ch = 'D' */ + 0x0f, 0x15, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb1, 0x9e, 0xef, 0x6b, + 0x04, 0x00, 0x7c, 0x54, 0x00, 0x10, 0xdb, 0x48, 0x00, 0x7c, 0x54, 0x00, + 0x00, 0x50, 0xb7, 0x00, 0x7c, 0x54, 0x00, 0x00, 0x32, 0xff, 0x00, 0x7c, + 0x54, 0x00, 0x00, 0x32, 0xf7, 0x04, 0x7c, 0x54, 0x00, 0x00, 0x50, 0xa7, + 0x00, 0x7c, 0x54, 0x00, 0x10, 0xdb, 0x3b, 0x00, 0x7c, 0xef, 0xcf, 0xe5, + 0x48, 0x04, 0x00, + /* ch = 'E' */ + 0x0c, 0x15, 0x15, 0x15, 0x15, 0x0f, 0x50, 0xc8, 0x74, 0x74, 0x74, 0x45, + 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, + 0x50, 0xd1, 0x74, 0x74, 0x74, 0x00, 0x50, 0x88, 0x15, 0x15, 0x15, 0x04, + 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, + 0x50, 0xf7, 0xcf, 0xcf, 0xcf, 0x67, + /* ch = 'F' */ + 0x08, 0x15, 0x15, 0x15, 0x15, 0x0f, 0x32, 0xff, 0x74, 0x74, 0x74, 0x45, + 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x32, 0xff, 0xd4, 0xcf, 0xcf, 0x00, 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, + /* ch = 'G' */ + 0x00, 0x00, 0x08, 0x15, 0x04, 0x00, 0x00, 0x00, 0x5a, 0xef, 0x82, 0xf7, + 0x39, 0x00, 0x32, 0xdb, 0x13, 0x00, 0x24, 0x73, 0x04, 0x82, 0x59, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb7, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, + 0x3f, 0x00, 0x67, 0xcf, 0xcf, 0x00, 0x82, 0x64, 0x00, 0x00, 0x1c, 0xff, + 0x04, 0x32, 0xec, 0x13, 0x00, 0x1f, 0xff, 0x04, 0x00, 0x50, 0xf7, 0xab, + 0xe5, 0x73, 0x04, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + /* ch = 'H' */ + 0x0f, 0x0f, 0x00, 0x00, 0x0c, 0x12, 0x7c, 0x82, 0x00, 0x00, 0x50, 0x88, + 0x7c, 0x82, 0x00, 0x00, 0x50, 0x82, 0x7c, 0x82, 0x00, 0x00, 0x50, 0x82, + 0x7c, 0xd1, 0x74, 0x74, 0xb1, 0x82, 0x7c, 0x88, 0x15, 0x15, 0x5e, 0x82, + 0x7c, 0x82, 0x00, 0x00, 0x50, 0x82, 0x7c, 0x82, 0x00, 0x00, 0x50, 0x82, + 0x7c, 0x82, 0x00, 0x00, 0x50, 0x82, + /* ch = 'I' */ + 0x04, 0x15, 0x15, 0x15, 0x15, 0x04, 0x14, 0x74, 0xc8, 0xb1, 0x74, 0x17, + 0x00, 0x00, 0x7c, 0x54, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0x54, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0x54, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x54, 0x00, 0x00, + 0x2d, 0xcf, 0xef, 0xef, 0xcf, 0x1a, + /* ch = 'J' */ + 0x04, 0x15, 0x15, 0x15, 0x15, 0x00, 0x14, 0x74, 0xb1, 0xc8, 0x74, 0x04, + 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, + 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, + 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, 0x19, 0x00, 0x8a, 0x64, 0x00, 0x00, + 0xf7, 0xc4, 0xd4, 0x13, 0x00, 0x00, 0x04, 0x15, 0x00, 0x00, 0x00, 0x00, + /* ch = 'K' */ + 0x12, 0x0f, 0x00, 0x00, 0x0c, 0x12, 0x00, 0xb7, 0x54, 0x00, 0x10, 0xdb, + 0x35, 0x00, 0xb7, 0x54, 0x10, 0xb1, 0x54, 0x00, 0x00, 0xb7, 0x59, 0xb1, + 0x7c, 0x04, 0x00, 0x00, 0xb7, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0xb7, + 0x82, 0xb1, 0x7c, 0x00, 0x00, 0x00, 0xb7, 0x54, 0x1c, 0xf7, 0x35, 0x00, + 0x00, 0xb7, 0x54, 0x00, 0x44, 0xec, 0x10, 0x00, 0xb7, 0x54, 0x00, 0x00, + 0x90, 0xa7, 0x04, + /* ch = 'L' */ + 0x0c, 0x15, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, + 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, + 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, + 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, + 0x50, 0xff, 0xcf, 0xcf, 0xcf, 0x67, + /* ch = 'M' */ + 0x12, 0x04, 0x00, 0x00, 0x00, 0x15, 0x00, 0xb7, 0x64, 0x00, 0x00, 0x32, + 0xff, 0x04, 0xb7, 0xff, 0x10, 0x00, 0xc8, 0xff, 0x04, 0xb7, 0xe5, 0x64, + 0x3b, 0xdb, 0xff, 0x04, 0xb7, 0x54, 0xff, 0xc8, 0x48, 0xff, 0x04, 0xb7, + 0x35, 0x70, 0x90, 0x1f, 0xff, 0x04, 0xb7, 0x35, 0x08, 0x0c, 0x1c, 0xff, + 0x04, 0xb7, 0x35, 0x00, 0x00, 0x1c, 0xff, 0x04, 0xb7, 0x35, 0x00, 0x00, + 0x1c, 0xff, 0x04, + /* ch = 'N' */ + 0x0f, 0x0c, 0x00, 0x00, 0x08, 0x12, 0x7c, 0xcf, 0x04, 0x00, 0x32, 0xbd, + 0x7c, 0xff, 0x48, 0x00, 0x32, 0xbd, 0x7c, 0xb7, 0xec, 0x0d, 0x32, 0xbd, + 0x7c, 0x54, 0xa0, 0x64, 0x32, 0xbd, 0x7c, 0x54, 0x24, 0xff, 0x50, 0xbd, + 0x7c, 0x54, 0x00, 0x7c, 0xff, 0xbd, 0x7c, 0x54, 0x00, 0x17, 0xf7, 0xbd, + 0x7c, 0x54, 0x00, 0x00, 0x50, 0xbd, + /* ch = 'O' */ + 0x00, 0x00, 0x0f, 0x15, 0x00, 0x00, 0x00, 0x04, 0x84, 0xe5, 0xcb, 0xc4, + 0x10, 0x00, 0x48, 0xb7, 0x08, 0x00, 0x82, 0x90, 0x00, 0xa0, 0x48, 0x00, + 0x00, 0x2a, 0xff, 0x00, 0xe5, 0x35, 0x00, 0x00, 0x1c, 0xff, 0x1c, 0xcf, + 0x35, 0x00, 0x00, 0x1c, 0xff, 0x1c, 0xa0, 0x54, 0x00, 0x00, 0x2a, 0xf7, + 0x04, 0x44, 0xe5, 0x10, 0x04, 0x82, 0x70, 0x00, 0x00, 0x66, 0xf7, 0xe5, + 0xa9, 0x13, 0x00, 0x00, 0x00, 0x08, 0x0f, 0x00, 0x00, 0x00, + /* ch = 'P' */ + 0x0c, 0x15, 0x15, 0x04, 0x00, 0x00, 0x00, 0x50, 0xef, 0xcf, 0xd4, 0xef, + 0x1f, 0x00, 0x50, 0x82, 0x00, 0x00, 0x5f, 0xa7, 0x00, 0x50, 0x82, 0x00, + 0x00, 0x3b, 0xbd, 0x04, 0x50, 0xab, 0x36, 0x3e, 0xdb, 0x50, 0x00, 0x50, + 0xa5, 0x36, 0x36, 0x25, 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, + 0x00, 0x00, 0x00, + /* ch = 'Q' */ + 0x00, 0x00, 0x0f, 0x15, 0x00, 0x00, 0x00, 0x04, 0x84, 0xd4, 0xb3, 0xc4, + 0x10, 0x00, 0x48, 0xb7, 0x08, 0x00, 0x82, 0x90, 0x00, 0xa0, 0x3f, 0x00, + 0x00, 0x24, 0xff, 0x00, 0xe5, 0x35, 0x00, 0x00, 0x1c, 0xff, 0x1c, 0xe5, + 0x35, 0x00, 0x00, 0x1a, 0xff, 0x1c, 0xa0, 0x54, 0x00, 0x00, 0x24, 0xf7, + 0x04, 0x44, 0xe5, 0x10, 0x00, 0x82, 0x75, 0x00, 0x00, 0x66, 0xf7, 0xdd, + 0xa9, 0x13, 0x00, 0x00, 0x00, 0x32, 0xbd, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x8d, 0xcf, 0x6c, 0x00, + /* ch = 'R' */ + 0x0f, 0x15, 0x15, 0x04, 0x00, 0x00, 0x7c, 0xef, 0xcf, 0xdd, 0xdb, 0x1f, + 0x7c, 0x82, 0x00, 0x00, 0x82, 0x90, 0x7c, 0x82, 0x00, 0x00, 0x54, 0xa7, + 0x7c, 0xab, 0x36, 0x47, 0xf7, 0x35, 0x7c, 0xa5, 0x36, 0xf7, 0x39, 0x00, + 0x7c, 0x82, 0x00, 0x5f, 0x97, 0x00, 0x7c, 0x82, 0x00, 0x10, 0xf7, 0x2c, + 0x7c, 0x82, 0x00, 0x00, 0x5f, 0xa7, + /* ch = 'S' */ + 0x00, 0x00, 0x0c, 0x12, 0x00, 0x00, 0x00, 0x84, 0xbb, 0x8f, 0xef, 0x2c, + 0x2f, 0xe5, 0x08, 0x00, 0x2c, 0x21, 0x2a, 0xff, 0x21, 0x00, 0x00, 0x00, + 0x00, 0x50, 0xf7, 0x7f, 0x1b, 0x00, 0x00, 0x00, 0x08, 0x50, 0xf7, 0x44, + 0x00, 0x00, 0x00, 0x00, 0x3f, 0xcf, 0x2f, 0x3b, 0x00, 0x00, 0x54, 0xa7, + 0x26, 0xd4, 0xdd, 0xd4, 0xd4, 0x21, 0x00, 0x00, 0x0c, 0x12, 0x00, 0x00, + /* ch = 'T' */ + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, 0xcf, 0xcf, 0xef, 0xef, 0xcf, + 0xcf, 0x04, 0x00, 0x00, 0x7c, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, + 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x82, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x82, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x82, + 0x00, 0x00, 0x00, + /* ch = 'U' */ + 0x0f, 0x0f, 0x00, 0x00, 0x08, 0x12, 0x7c, 0x59, 0x00, 0x00, 0x32, 0xbd, + 0x7c, 0x54, 0x00, 0x00, 0x32, 0xbd, 0x7c, 0x54, 0x00, 0x00, 0x32, 0xbd, + 0x7c, 0x54, 0x00, 0x00, 0x32, 0xbd, 0x7c, 0x54, 0x00, 0x00, 0x32, 0xbd, + 0x7c, 0x59, 0x00, 0x00, 0x32, 0xbd, 0x50, 0xbd, 0x04, 0x00, 0x5f, 0x90, + 0x04, 0xa2, 0xd4, 0xa4, 0xd4, 0x19, 0x00, 0x00, 0x0c, 0x12, 0x00, 0x00, + /* ch = 'V' */ + 0x15, 0x08, 0x00, 0x00, 0x00, 0x15, 0x04, 0xa7, 0x4c, 0x00, 0x00, 0x22, + 0xf7, 0x08, 0x48, 0xaf, 0x00, 0x00, 0x5a, 0x82, 0x00, 0x17, 0xff, 0x1a, + 0x00, 0xb7, 0x35, 0x00, 0x00, 0xa7, 0x4c, 0x1c, 0xf7, 0x10, 0x00, 0x00, + 0x48, 0xaf, 0x48, 0x90, 0x00, 0x00, 0x00, 0x14, 0xff, 0xd1, 0x3b, 0x00, + 0x00, 0x00, 0x00, 0xa0, 0xf7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x44, 0x90, + 0x00, 0x00, 0x00, + /* ch = 'W' */ + 0x15, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0xff, 0x1f, 0x14, 0x32, 0x00, + 0xb7, 0x26, 0xbd, 0x35, 0x35, 0xa7, 0x00, 0xff, 0x17, 0x82, 0x54, 0x6b, + 0xff, 0x1f, 0xe5, 0x04, 0x54, 0x7c, 0xcf, 0xdb, 0x64, 0xa7, 0x00, 0x35, + 0xf7, 0xb7, 0x64, 0xec, 0x7c, 0x00, 0x1f, 0xff, 0x64, 0x2a, 0xff, 0x50, + 0x00, 0x0d, 0xff, 0x32, 0x0d, 0xff, 0x32, 0x00, 0x00, 0xcf, 0x10, 0x00, + 0xa0, 0x1f, 0x00, + /* ch = 'X' */ + 0x12, 0x0c, 0x00, 0x00, 0x08, 0x12, 0x44, 0xcf, 0x04, 0x00, 0x90, 0x54, + 0x04, 0xc8, 0x48, 0x2a, 0xe5, 0x10, 0x00, 0x32, 0xec, 0xb7, 0x54, 0x00, + 0x00, 0x00, 0xa7, 0xe5, 0x08, 0x00, 0x00, 0x04, 0xdb, 0xff, 0x1f, 0x00, + 0x00, 0x48, 0xc8, 0x82, 0x97, 0x00, 0x0d, 0xe5, 0x35, 0x17, 0xf7, 0x2c, + 0x5f, 0xa0, 0x04, 0x00, 0x5f, 0xa7, + /* ch = 'Y' */ + 0x15, 0x08, 0x00, 0x00, 0x04, 0x15, 0x04, 0x7c, 0x90, 0x00, 0x00, 0x44, + 0xc8, 0x04, 0x17, 0xff, 0x26, 0x00, 0xc8, 0x3f, 0x00, 0x00, 0x70, 0x97, + 0x32, 0xdb, 0x08, 0x00, 0x00, 0x17, 0xff, 0xe5, 0x4c, 0x00, 0x00, 0x00, + 0x00, 0x70, 0xe5, 0x10, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, + 0x00, 0x00, 0x00, + /* ch = 'Z' */ + 0x0c, 0x15, 0x15, 0x15, 0x15, 0x12, 0x45, 0xcf, 0xcf, 0xcf, 0xef, 0xa7, + 0x00, 0x00, 0x00, 0x10, 0xf7, 0x26, 0x00, 0x00, 0x00, 0x82, 0x70, 0x00, + 0x00, 0x00, 0x2f, 0xe5, 0x13, 0x00, 0x00, 0x04, 0xdb, 0x48, 0x00, 0x00, + 0x00, 0x54, 0xb1, 0x04, 0x00, 0x00, 0x1c, 0xf7, 0x26, 0x00, 0x00, 0x00, + 0x77, 0xff, 0xcf, 0xcf, 0xcf, 0xcf, + /* ch = '[' */ + 0x67, 0xcf, 0xcf, 0xcf, 0x45, 0x7c, 0x54, 0x00, 0x00, 0x00, 0x7c, 0x54, + 0x00, 0x00, 0x00, 0x7c, 0x54, 0x00, 0x00, 0x00, 0x7c, 0x54, 0x00, 0x00, + 0x00, 0x7c, 0x54, 0x00, 0x00, 0x00, 0x7c, 0x54, 0x00, 0x00, 0x00, 0x7c, + 0x54, 0x00, 0x00, 0x00, 0x7c, 0x54, 0x00, 0x00, 0x00, 0x7c, 0xb9, 0x74, + 0x74, 0x30, 0x0f, 0x15, 0x15, 0x15, 0x0f, + /* ch = '\' */ + 0x19, 0x4e, 0x00, 0x17, 0xff, 0x1a, 0x00, 0x8a, 0x70, 0x00, 0x22, 0xff, + 0x00, 0x00, 0xa0, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = ']' */ + 0x1a, 0xcf, 0xcf, 0xcf, 0x95, 0x00, 0x00, 0x00, 0x32, 0xbd, 0x00, 0x00, + 0x00, 0x32, 0xbd, 0x00, 0x00, 0x00, 0x32, 0xbd, 0x00, 0x00, 0x00, 0x32, + 0xbd, 0x00, 0x00, 0x00, 0x32, 0xbd, 0x00, 0x00, 0x00, 0x32, 0xbd, 0x00, + 0x00, 0x00, 0x32, 0xbd, 0x00, 0x00, 0x00, 0x32, 0xbd, 0x22, 0x74, 0x74, + 0x9c, 0xbd, 0x08, 0x15, 0x15, 0x15, 0x15, + /* ch = '^' */ + 0x00, 0x00, 0x04, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x50, 0xaf, 0x00, 0x00, + 0x00, 0x17, 0xef, 0xdb, 0x35, 0x00, 0x00, 0x82, 0x59, 0x3b, 0xcf, 0x00, + 0x09, 0x50, 0x08, 0x00, 0x50, 0x08, + /* ch = '_' */ + /* ch = '`' */ + 0x27, 0x51, 0x00, 0x22, 0xec, 0x10, 0x00, 0xa0, 0xb7, 0x00, 0x10, 0x2a, + /* ch = 'a' */ + 0x09, 0x8d, 0xdd, 0xd4, 0xc4, 0x10, 0x00, 0x22, 0x04, 0x00, 0x90, 0x70, + 0x00, 0x0f, 0x36, 0x36, 0xa0, 0x82, 0x2f, 0xdb, 0x31, 0x15, 0x5e, 0x82, + 0x7c, 0x82, 0x00, 0x04, 0xb7, 0x82, 0x2a, 0xf7, 0x82, 0xcb, 0xd4, 0x82, + 0x00, 0x04, 0x15, 0x08, 0x00, 0x00, + /* ch = 'b' */ + 0x30, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0xd4, + 0xdd, 0xd4, 0x10, 0x00, 0x50, 0xe5, 0x0c, 0x04, 0x90, 0x90, 0x00, 0x50, + 0x88, 0x00, 0x00, 0x3b, 0xd9, 0x00, 0x50, 0x88, 0x00, 0x00, 0x35, 0xcf, + 0x04, 0x50, 0xd9, 0x04, 0x00, 0x82, 0x75, 0x00, 0x50, 0xc4, 0xe5, 0xdd, + 0xd4, 0x13, 0x00, 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, 0x00, + /* ch = 'c' */ + 0x00, 0x35, 0xdd, 0xcf, 0xf7, 0x3b, 0x00, 0x22, 0xf7, 0x21, 0x00, 0x24, + 0x50, 0x04, 0x54, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x97, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2a, 0xff, 0x21, 0x00, 0x10, 0x1b, 0x00, 0x00, + 0x44, 0xf7, 0xcf, 0xe5, 0x48, 0x00, 0x00, 0x00, 0x04, 0x15, 0x08, 0x00, + 0x00, + /* ch = 'd' */ + 0x00, 0x00, 0x00, 0x00, 0x30, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x50, 0x82, + 0x00, 0x00, 0x00, 0x00, 0x50, 0x82, 0x04, 0x94, 0xdd, 0xdd, 0xdb, 0x82, + 0x48, 0xa7, 0x04, 0x04, 0xb7, 0x82, 0x7c, 0x54, 0x00, 0x00, 0x7c, 0x82, + 0x7c, 0x59, 0x00, 0x00, 0x7c, 0x82, 0x48, 0xcf, 0x04, 0x04, 0xc8, 0x82, + 0x04, 0xa9, 0xef, 0xdd, 0xc4, 0x88, 0x00, 0x00, 0x0f, 0x08, 0x00, 0x00, + /* ch = 'e' */ + 0x00, 0x66, 0xd4, 0xb3, 0xc4, 0x10, 0x39, 0xc8, 0x08, 0x00, 0x82, 0x5f, + 0x77, 0xd1, 0x74, 0x74, 0xb1, 0xa7, 0x7c, 0x6d, 0x15, 0x15, 0x15, 0x15, + 0x40, 0xcf, 0x04, 0x00, 0x0c, 0x08, 0x04, 0x7e, 0xef, 0x82, 0xdd, 0x32, + 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, + /* ch = 'f' */ + 0x00, 0x19, 0x74, 0xab, 0x48, 0x00, 0x04, 0xdb, 0x3a, 0x0f, 0xb1, 0x13, + 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, 0x87, 0xff, 0x7b, 0x74, 0x00, 0x00, + 0x28, 0xff, 0x15, 0x15, 0x04, 0x00, 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, + /* ch = 'g' */ + 0x00, 0x00, 0x0f, 0x08, 0x00, 0x00, 0x00, 0x04, 0xa9, 0xa4, 0xef, 0xcb, + 0x8f, 0x17, 0x4d, 0x97, 0x04, 0x22, 0xff, 0x04, 0x00, 0x44, 0xbd, 0x04, + 0x26, 0xf7, 0x04, 0x00, 0x04, 0xd9, 0xe5, 0xdd, 0x2f, 0x00, 0x00, 0x2a, + 0xc6, 0x08, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe0, 0xcf, 0xcf, 0xef, 0x4d, + 0x00, 0x99, 0x43, 0x00, 0x00, 0x32, 0xd1, 0x00, 0x4d, 0xdb, 0x5b, 0x5b, + 0xd4, 0x44, 0x00, 0x00, 0x0c, 0x15, 0x15, 0x0c, 0x00, 0x00, + /* ch = 'h' */ + 0x30, 0x64, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, + 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x50, 0xd9, 0xa9, 0xd4, 0xdb, 0x1c, + 0x50, 0xff, 0x24, 0x00, 0x97, 0x64, 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, + 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, + 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, + /* ch = 'i' */ + 0x00, 0x26, 0x48, 0x00, 0x00, 0x00, 0x49, 0x9c, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xcf, 0xe5, 0xbd, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, + 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, + 0x50, 0xbd, 0x00, 0x00, 0xcf, 0xe5, 0xff, 0xcf, 0x1a, + /* ch = 'j' */ + 0x00, 0x00, 0x00, 0x26, 0x48, 0x00, 0x00, 0x00, 0x49, 0x9c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x67, 0xcf, 0xe5, 0xbd, 0x00, 0x00, 0x00, 0x50, + 0xbd, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, + 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x10, 0x16, 0x00, + 0x64, 0x97, 0x5c, 0xdb, 0x82, 0xef, 0x21, 0x00, 0x12, 0x15, 0x0c, 0x00, + /* ch = 'k' */ + 0x30, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, + 0x19, 0xdb, 0x3f, 0x00, 0x50, 0xbd, 0x1f, 0xe5, 0x35, 0x00, 0x00, 0x50, + 0xec, 0xf7, 0x52, 0x00, 0x00, 0x00, 0x50, 0xe5, 0x47, 0xff, 0x1f, 0x00, + 0x00, 0x50, 0xbd, 0x00, 0x50, 0xe5, 0x10, 0x00, 0x50, 0xbd, 0x00, 0x00, + 0xb1, 0xb7, 0x04, + /* ch = 'l' */ + 0x14, 0x74, 0x74, 0x42, 0x00, 0x00, 0x04, 0x15, 0x5e, 0x82, 0x00, 0x00, + 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, + 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, + 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, + 0x2d, 0xcf, 0xe5, 0xf7, 0xcf, 0x45, + /* ch = 'm' */ + 0xb7, 0xe5, 0xdb, 0xbb, 0xbb, 0xdb, 0x00, 0xb7, 0x4c, 0x50, 0xbd, 0x1f, + 0xff, 0x1f, 0xb7, 0x35, 0x50, 0x82, 0x1c, 0xff, 0x1f, 0xb7, 0x35, 0x50, + 0x82, 0x1c, 0xff, 0x1f, 0xb7, 0x35, 0x50, 0x82, 0x1c, 0xff, 0x1f, 0xb7, + 0x35, 0x50, 0x82, 0x1c, 0xff, 0x1f, + /* ch = 'n' */ + 0x50, 0xd9, 0xbb, 0xd4, 0xdb, 0x17, 0x50, 0xff, 0x24, 0x00, 0xa7, 0x59, + 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, + 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, + /* ch = 'o' */ + 0x00, 0x66, 0xdd, 0xdd, 0xa9, 0x10, 0x00, 0x44, 0xdb, 0x0c, 0x00, 0x90, + 0x82, 0x00, 0xa0, 0x64, 0x00, 0x00, 0x35, 0xec, 0x00, 0xb1, 0x64, 0x00, + 0x00, 0x32, 0xf7, 0x04, 0x50, 0xcf, 0x04, 0x00, 0x82, 0x90, 0x00, 0x04, + 0x84, 0xef, 0xb3, 0xcb, 0x13, 0x00, 0x00, 0x00, 0x0c, 0x15, 0x00, 0x00, + 0x00, + /* ch = 'p' */ + 0x50, 0xbd, 0xcf, 0xdd, 0xdb, 0x19, 0x00, 0x50, 0xe5, 0x0c, 0x00, 0x90, + 0xa0, 0x00, 0x50, 0x88, 0x00, 0x00, 0x35, 0xff, 0x04, 0x50, 0x88, 0x00, + 0x00, 0x32, 0xf7, 0x04, 0x50, 0xd9, 0x04, 0x00, 0x75, 0x90, 0x00, 0x50, + 0xdb, 0xe5, 0xc4, 0xd4, 0x21, 0x00, 0x50, 0x82, 0x08, 0x15, 0x04, 0x00, + 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, + /* ch = 'q' */ + 0x04, 0x94, 0xcb, 0xdd, 0xdb, 0x82, 0x48, 0xb7, 0x08, 0x04, 0xa7, 0x82, + 0x90, 0x54, 0x00, 0x00, 0x54, 0x82, 0x90, 0x64, 0x00, 0x00, 0x54, 0x82, + 0x48, 0xcf, 0x04, 0x04, 0xb7, 0x82, 0x04, 0xa9, 0xef, 0xdd, 0xc4, 0x82, + 0x00, 0x00, 0x0f, 0x08, 0x50, 0x82, 0x00, 0x00, 0x00, 0x00, 0x50, 0x82, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x12, + /* ch = 'r' */ + 0xff, 0xb1, 0xdd, 0xdd, 0xab, 0xff, 0xb1, 0x08, 0x04, 0x28, 0xff, 0x35, + 0x00, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, + 0x00, 0xff, 0x1f, 0x00, 0x00, 0x00, + /* ch = 's' */ + 0x00, 0x66, 0xcb, 0x9e, 0xdb, 0x26, 0x1c, 0xff, 0x21, 0x00, 0x2c, 0x21, + 0x04, 0xa2, 0xef, 0x5b, 0x1e, 0x00, 0x00, 0x00, 0x18, 0x5a, 0xf7, 0x44, + 0x24, 0x3b, 0x00, 0x00, 0x82, 0x7c, 0x26, 0xd4, 0xcb, 0xab, 0xd4, 0x21, + 0x00, 0x00, 0x0c, 0x12, 0x00, 0x00, + /* ch = 't' */ + 0x00, 0x00, 0x5c, 0x28, 0x00, 0x00, 0x00, 0x00, 0xff, 0x35, 0x00, 0x00, + 0x42, 0xcf, 0xff, 0xd4, 0xcf, 0x1c, 0x00, 0x0d, 0xff, 0x1f, 0x00, 0x00, + 0x00, 0x1c, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, 0x00, 0x00, + 0x00, 0x1a, 0xff, 0x26, 0x04, 0x0c, 0x00, 0x00, 0x99, 0xf7, 0xe5, 0x62, + 0x00, 0x00, 0x00, 0x0f, 0x04, 0x00, + /* ch = 'u' */ + 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, + 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, 0x50, 0xbd, 0x00, 0x00, 0x7c, 0x82, + 0x44, 0xd9, 0x04, 0x04, 0xc8, 0x82, 0x04, 0xa9, 0xc4, 0xc4, 0xdb, 0x82, + 0x00, 0x00, 0x12, 0x08, 0x00, 0x00, + /* ch = 'v' */ + 0x70, 0x88, 0x00, 0x00, 0x35, 0xa7, 0x04, 0x24, 0xff, 0x0d, 0x00, 0x70, + 0x54, 0x00, 0x00, 0xc8, 0x4c, 0x0d, 0xf7, 0x1a, 0x00, 0x00, 0x48, 0xcf, + 0x48, 0x90, 0x00, 0x00, 0x00, 0x0d, 0xf7, 0xf7, 0x2f, 0x00, 0x00, 0x00, + 0x00, 0x8a, 0xb7, 0x04, 0x00, 0x00, + /* ch = 'w' */ + 0xff, 0x1f, 0x16, 0x26, 0x00, 0xff, 0x1f, 0xbd, 0x32, 0x5f, 0xbd, 0x00, + 0xff, 0x08, 0x77, 0x59, 0xa0, 0xff, 0x2f, 0xcf, 0x04, 0x44, 0x9e, 0xe5, + 0x82, 0xa0, 0x97, 0x00, 0x24, 0xff, 0x82, 0x3b, 0xff, 0x59, 0x00, 0x04, + 0xff, 0x3f, 0x14, 0xff, 0x37, 0x00, + /* ch = 'x' */ + 0x35, 0xe5, 0x10, 0x04, 0xdb, 0x37, 0x00, 0x7c, 0x82, 0x6b, 0x82, 0x04, + 0x00, 0x0d, 0xdb, 0xe5, 0x13, 0x00, 0x00, 0x10, 0xdb, 0xff, 0x1f, 0x00, + 0x00, 0x7c, 0x7c, 0x59, 0xb7, 0x04, 0x35, 0xdb, 0x13, 0x04, 0xb1, 0x68, + /* ch = 'y' */ + 0x5a, 0x9e, 0x00, 0x00, 0x3b, 0xc8, 0x04, 0x17, 0xff, 0x1a, 0x00, 0x8a, + 0x5f, 0x00, 0x00, 0x8a, 0x5f, 0x0d, 0xf7, 0x1a, 0x00, 0x00, 0x39, 0xec, + 0x3f, 0xa7, 0x04, 0x00, 0x00, 0x04, 0xe5, 0xff, 0x3b, 0x00, 0x00, 0x00, + 0x00, 0x5a, 0xf7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x75, 0x00, 0x00, + 0x00, 0xc0, 0x82, 0xef, 0x1f, 0x00, 0x00, 0x00, 0x0c, 0x15, 0x0c, 0x00, + 0x00, 0x00, 0x00, + /* ch = 'z' */ + 0x2d, 0xcf, 0xcf, 0xcf, 0xff, 0x50, 0x00, 0x00, 0x00, 0x50, 0xb1, 0x08, + 0x00, 0x00, 0x32, 0xf7, 0x1f, 0x00, 0x00, 0x1f, 0xf7, 0x35, 0x00, 0x00, + 0x10, 0xdb, 0x54, 0x00, 0x00, 0x00, 0x77, 0xff, 0xd4, 0xcf, 0xcf, 0x95, + /* ch = '{' */ + 0x00, 0x15, 0x15, 0x08, 0xa9, 0x99, 0x36, 0x19, 0xff, 0x10, 0x00, 0x00, + 0xff, 0x04, 0x00, 0x00, 0xe5, 0x04, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, + 0xa7, 0x00, 0x00, 0x00, 0xff, 0x04, 0x00, 0x00, 0xff, 0x04, 0x00, 0x00, + 0xff, 0x13, 0x00, 0x00, 0x77, 0xef, 0x74, 0x22, + /* ch = '|' */ + 0x1e, 0x26, 0x50, 0x82, 0x50, 0x82, 0x50, 0x82, 0x50, 0x82, 0x50, 0x82, + 0x50, 0x82, 0x50, 0x82, 0x50, 0x82, 0x50, 0x82, 0x50, 0x82, + /* ch = '}' */ + 0x04, 0x15, 0x15, 0x04, 0x00, 0x0d, 0x36, 0x77, 0xdb, 0x0d, 0x00, 0x00, + 0x00, 0xbd, 0x35, 0x00, 0x00, 0x00, 0xb7, 0x35, 0x00, 0x00, 0x00, 0xa0, + 0x4c, 0x00, 0x00, 0x00, 0x1b, 0xec, 0x00, 0x00, 0x00, 0x6b, 0x68, 0x00, + 0x00, 0x00, 0xb7, 0x35, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x04, + 0xcf, 0x37, 0x14, 0x74, 0xcb, 0xa9, 0x08, + /* ch = '~' */ + 0x2c, 0xe5, 0xef, 0x6b, 0x1e, 0xc8, 0x09, 0x2f, 0x21, 0x08, 0x8d, 0xbd, + 0x31, 0x00 }; /* font_inconsolata_14px */ static const unsigned char pd_inconsolata_font_bitmap_14px_bytes[] = { - /* ch = '!' */ - 0x13, 0x28, 0x00, - 0x77, 0xff, 0x10, - 0x77, 0xff, 0x04, - 0x50, 0xff, 0x04, - 0x50, 0xbd, 0x04, - 0x44, 0xbd, 0x00, - 0x32, 0xa7, 0x00, - 0x08, 0x12, 0x00, - 0x21, 0x30, 0x00, - 0x99, 0xff, 0x17, - 0x08, 0x12, 0x00, - /* ch = '"' */ - 0x08, 0x2a, 0x00, 0x22, 0x08, - 0x39, 0xff, 0x1c, 0xff, 0x54, - 0x35, 0xe5, 0x04, 0xff, 0x3b, - 0x6b, 0x70, 0x1c, 0xf7, 0x10, - 0x12, 0x0c, 0x04, 0x15, 0x00, - /* ch = '#' */ - 0x00, 0x00, 0xbd, 0x1f, 0x32, 0x42, 0x00, - 0x00, 0x04, 0xff, 0x1c, 0x7c, 0x54, 0x00, - 0x28, 0x4a, 0xff, 0x39, 0xc8, 0x78, 0x26, - 0x2d, 0x62, 0xbd, 0x15, 0xd9, 0x3a, 0x12, - 0x00, 0x3b, 0xa7, 0x00, 0xff, 0x1f, 0x00, - 0x1a, 0x82, 0xab, 0x4a, 0xff, 0x39, 0x16, - 0x36, 0xa5, 0x82, 0x58, 0xcf, 0x15, 0x0c, - 0x00, 0xa0, 0x3f, 0x35, 0xb7, 0x00, 0x00, - 0x00, 0xa9, 0x2a, 0x45, 0x6c, 0x00, 0x00, - /* ch = '$' */ - 0x00, 0x00, 0x00, 0x15, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x0f, 0xff, 0x28, 0x00, 0x00, - 0x00, 0x77, 0xbb, 0xff, 0xd4, 0xb1, 0x0d, - 0x1c, 0xff, 0x10, 0xff, 0x1f, 0x40, 0x04, - 0x0d, 0xf7, 0x64, 0xff, 0x1f, 0x00, 0x00, - 0x00, 0x1b, 0xab, 0xff, 0x8b, 0x1b, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x77, 0xff, 0x1c, - 0x00, 0x0c, 0x00, 0xff, 0x1f, 0xb7, 0x44, - 0x2d, 0xc8, 0x1e, 0xff, 0x59, 0xf7, 0x1f, - 0x00, 0x37, 0xab, 0xff, 0xa4, 0x1e, 0x00, - 0x00, 0x00, 0x00, 0x74, 0x17, 0x00, 0x00, - /* ch = '%' */ - 0x2c, 0xc6, 0x9c, 0x0d, 0x0d, 0xbd, 0x22, - 0xb7, 0x35, 0x97, 0x50, 0x5f, 0x90, 0x04, - 0xb7, 0x43, 0xa7, 0x65, 0xf7, 0x1f, 0x00, - 0x26, 0xbd, 0x7f, 0x88, 0x70, 0x00, 0x00, - 0x00, 0x00, 0x24, 0xf7, 0x13, 0x00, 0x00, - 0x00, 0x00, 0xa0, 0x54, 0x30, 0x30, 0x04, - 0x00, 0x32, 0xdb, 0x59, 0x90, 0x82, 0x5f, - 0x04, 0xc8, 0x3f, 0x7c, 0x54, 0x50, 0x90, - 0x3b, 0xb7, 0x04, 0x2f, 0xdb, 0xdb, 0x35, - 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0f, 0x00, - /* ch = '&' */ - 0x00, 0x26, 0xbd, 0xbd, 0x26, 0x00, 0x00, - 0x00, 0xe5, 0x46, 0x37, 0xff, 0x00, 0x00, - 0x00, 0xf7, 0x37, 0x24, 0xf7, 0x04, 0x00, - 0x00, 0x5f, 0xbd, 0xb1, 0x54, 0x00, 0x00, - 0x00, 0x54, 0xff, 0xa4, 0x04, 0x00, 0x00, - 0x3b, 0xf7, 0x26, 0xf7, 0x35, 0x70, 0x40, - 0xa0, 0x7c, 0x00, 0x32, 0xff, 0xf7, 0x21, - 0xa0, 0x9e, 0x00, 0x13, 0xec, 0xc6, 0x04, - 0x1f, 0xef, 0xe5, 0xef, 0x48, 0xdb, 0x52, - 0x00, 0x04, 0x15, 0x04, 0x00, 0x0c, 0x04, - /* ch = ''' */ - 0x00, 0x2a, 0x08, - 0x0a, 0xff, 0x50, - 0x04, 0xff, 0x2c, - 0x2a, 0xe5, 0x04, - 0x0c, 0x12, 0x00, - /* ch = '(' */ - 0x00, 0x08, 0x21, - 0x21, 0xdb, 0x6d, - 0xf7, 0x3f, 0x00, - 0x82, 0x00, 0x00, - 0x26, 0x00, 0x00, - 0x04, 0x00, 0x00, - 0x04, 0x00, 0x00, - 0x08, 0x00, 0x00, - 0x2f, 0x00, 0x00, - 0xa7, 0x00, 0x00, - 0xdb, 0x54, 0x00, - 0x1f, 0xdb, 0x77, - 0x00, 0x08, 0x22, - /* ch = ')' */ - 0x00, 0x21, 0x00, 0x00, - 0x14, 0xef, 0x70, 0x04, - 0x00, 0x13, 0xdb, 0x82, - 0x00, 0x00, 0x1f, 0xf7, - 0x00, 0x00, 0x00, 0x70, - 0x00, 0x00, 0x00, 0x35, - 0x00, 0x00, 0x00, 0x21, - 0x00, 0x00, 0x00, 0x32, - 0x00, 0x00, 0x00, 0x70, - 0x00, 0x00, 0x10, 0xf7, - 0x00, 0x08, 0xb1, 0x7c, - 0x1a, 0xd4, 0x84, 0x08, - 0x0d, 0x25, 0x00, 0x00, - /* ch = '*' */ - 0x00, 0x00, 0x08, 0x15, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x2f, 0xff, 0x04, 0x00, 0x00, - 0x51, 0x73, 0x28, 0xbd, 0x20, 0x9e, 0x22, - 0x12, 0x47, 0xc4, 0xff, 0x95, 0x2a, 0x0c, - 0x00, 0x10, 0xdb, 0xbb, 0x82, 0x00, 0x00, - 0x04, 0xb1, 0x7c, 0x0d, 0xdb, 0x54, 0x00, - 0x00, 0x3d, 0x08, 0x00, 0x2a, 0x21, 0x00, - /* ch = '+' */ - 0x00, 0x00, 0x0d, 0x36, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x04, 0x00, 0x00, - 0x7c, 0xff, 0xff, 0xff, 0xff, 0xff, 0x35, - 0x00, 0x00, 0x1c, 0xff, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x14, 0x74, 0x04, 0x00, 0x00, - /* ch = ',' */ - 0x21, 0x2a, 0x00, - 0x99, 0xff, 0x24, - 0x1f, 0xff, 0x17, - 0x7c, 0x54, 0x00, - 0x22, 0x04, 0x00, - /* ch = '-' */ - /* ch = '.' */ - 0x21, 0x30, 0x00, - 0xa0, 0xff, 0x17, - 0x08, 0x12, 0x00, - /* ch = '/' */ - 0x0d, 0x1b, 0x00, - 0x44, 0xe5, 0x08, - 0xc8, 0x4c, 0x00, - 0xe5, 0x10, 0x00, - 0x5f, 0x00, 0x00, - 0x13, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* ch = '0' */ - 0x00, 0x08, 0x7f, 0xcf, 0x48, 0x00, 0x00, - 0x00, 0xa0, 0x7c, 0x1a, 0xdb, 0x50, 0x00, - 0x2a, 0xe5, 0x08, 0x00, 0x82, 0xec, 0x00, - 0x50, 0x88, 0x00, 0x50, 0xdb, 0xff, 0x1f, - 0x7c, 0x82, 0x1f, 0xef, 0x21, 0xff, 0x35, - 0x5f, 0x9e, 0xdb, 0x35, 0x00, 0xff, 0x26, - 0x3b, 0xff, 0x64, 0x00, 0x1c, 0xff, 0x17, - 0x0d, 0xe5, 0x3f, 0x00, 0x64, 0x90, 0x00, - 0x00, 0x2c, 0xef, 0xdd, 0xd4, 0x13, 0x00, - 0x00, 0x00, 0x04, 0x15, 0x04, 0x00, 0x00, - /* ch = '1' */ - 0x00, 0x00, 0x37, 0xbd, 0x1a, - 0x0a, 0xbd, 0xb3, 0xff, 0x1f, - 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x00, 0x00, 0x1c, 0xff, 0x1f, - /* ch = '2' */ - 0x00, 0x1b, 0x9e, 0xcf, 0x66, 0x08, 0x00, - 0x11, 0xe5, 0x37, 0x1a, 0xb1, 0x97, 0x00, - 0x00, 0x0f, 0x00, 0x00, 0x2c, 0xff, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x3f, 0xdb, 0x04, - 0x00, 0x00, 0x00, 0x1f, 0xf7, 0x35, 0x00, - 0x00, 0x00, 0x1f, 0xef, 0x48, 0x00, 0x00, - 0x00, 0x17, 0xdb, 0x3f, 0x00, 0x00, 0x00, - 0x00, 0xa0, 0x64, 0x00, 0x00, 0x00, 0x00, - 0x2f, 0xff, 0xdd, 0xcf, 0xcf, 0xdd, 0x1f, - /* ch = '3' */ - 0x00, 0x28, 0x9e, 0xbd, 0x48, 0x00, - 0x00, 0x8d, 0x2b, 0x20, 0xdb, 0x50, - 0x00, 0x00, 0x00, 0x00, 0x50, 0x92, - 0x00, 0x00, 0x00, 0x13, 0xdb, 0x48, - 0x00, 0x00, 0x95, 0xf7, 0xa4, 0x04, - 0x00, 0x00, 0x00, 0x04, 0x82, 0x82, - 0x00, 0x00, 0x00, 0x00, 0x32, 0xf7, - 0x04, 0x73, 0x04, 0x00, 0x82, 0xa7, - 0x10, 0xbb, 0xef, 0xdd, 0xd4, 0x21, - 0x00, 0x00, 0x0c, 0x15, 0x00, 0x00, - /* ch = '4' */ - 0x00, 0x00, 0x00, 0x17, 0xcf, 0x1a, 0x00, - 0x00, 0x00, 0x00, 0xa0, 0xff, 0x1f, 0x00, - 0x00, 0x00, 0x44, 0xdb, 0xff, 0x1f, 0x00, - 0x00, 0x17, 0xef, 0x2f, 0xff, 0x1f, 0x00, - 0x00, 0xa0, 0x48, 0x1c, 0xff, 0x1f, 0x00, - 0x44, 0xc6, 0x17, 0x28, 0xff, 0x2a, 0x08, - 0x42, 0x74, 0x74, 0x87, 0xff, 0x87, 0x24, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, 0x00, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, 0x00, - /* ch = '5' */ - 0x00, 0x95, 0xcf, 0xcf, 0xcf, 0x95, 0x00, - 0x00, 0xf7, 0x3e, 0x15, 0x15, 0x15, 0x00, - 0x00, 0xff, 0x21, 0x00, 0x00, 0x00, 0x00, - 0x04, 0xff, 0x7e, 0x74, 0x50, 0x04, 0x00, - 0x1a, 0xe5, 0x37, 0x1a, 0xb1, 0xa7, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x24, 0xff, 0x1c, - 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x19, 0x9c, 0x08, 0x00, 0x50, 0xe5, 0x08, - 0x04, 0x8d, 0xf7, 0xcf, 0xef, 0x2f, 0x00, - 0x00, 0x00, 0x08, 0x15, 0x04, 0x00, 0x00, - /* ch = '6' */ - 0x00, 0x04, 0x50, 0xcf, 0xbd, 0x37, 0x00, - 0x00, 0x6b, 0xb1, 0x18, 0x2e, 0x50, 0x00, - 0x0d, 0xf7, 0x26, 0x00, 0x00, 0x00, 0x00, - 0x2f, 0xff, 0x3a, 0x74, 0x48, 0x04, 0x00, - 0x32, 0xff, 0x99, 0x25, 0xb1, 0x7c, 0x00, - 0x32, 0xff, 0x08, 0x00, 0x24, 0xff, 0x10, - 0x2a, 0xff, 0x08, 0x00, 0x1c, 0xff, 0x1f, - 0x04, 0xe5, 0x4c, 0x00, 0x3f, 0xdb, 0x04, - 0x00, 0x2c, 0xef, 0xd4, 0xef, 0x28, 0x00, - 0x00, 0x00, 0x00, 0x15, 0x08, 0x00, 0x00, - /* ch = '7' */ - 0x1a, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x00, - 0x04, 0x15, 0x15, 0x15, 0x82, 0xa7, 0x04, - 0x00, 0x00, 0x00, 0x0d, 0xf7, 0x35, 0x00, - 0x00, 0x00, 0x00, 0x48, 0xe5, 0x08, 0x00, - 0x00, 0x00, 0x00, 0xb7, 0x5f, 0x00, 0x00, - 0x00, 0x00, 0x22, 0xff, 0x1f, 0x00, 0x00, - 0x00, 0x00, 0x5f, 0xb7, 0x04, 0x00, 0x00, - 0x00, 0x00, 0xe5, 0x54, 0x00, 0x00, 0x00, - 0x00, 0x2c, 0xff, 0x1f, 0x00, 0x00, 0x00, - /* ch = '8' */ - 0x00, 0x19, 0x9e, 0xcf, 0x7f, 0x10, 0x00, - 0x00, 0xc8, 0x59, 0x08, 0x90, 0x90, 0x00, - 0x00, 0xff, 0x26, 0x00, 0x48, 0xbd, 0x00, - 0x00, 0x77, 0xc8, 0x20, 0xdb, 0x48, 0x00, - 0x00, 0x1b, 0xec, 0xef, 0xb5, 0x08, 0x00, - 0x10, 0xef, 0x35, 0x04, 0x8a, 0xb7, 0x00, - 0x4d, 0xbd, 0x04, 0x00, 0x1f, 0xff, 0x1c, - 0x39, 0xff, 0x1a, 0x00, 0x3f, 0xf7, 0x10, - 0x00, 0x66, 0xff, 0xcf, 0xef, 0x2f, 0x00, - 0x00, 0x00, 0x08, 0x15, 0x04, 0x00, 0x00, - /* ch = '9' */ - 0x00, 0x19, 0x9e, 0xcf, 0x50, 0x04, 0x00, - 0x04, 0xdb, 0x54, 0x1a, 0xb7, 0x5f, 0x00, - 0x2f, 0xff, 0x08, 0x00, 0x35, 0xec, 0x00, - 0x32, 0xff, 0x00, 0x00, 0x1c, 0xff, 0x10, - 0x0d, 0xf7, 0x46, 0x08, 0x8a, 0xff, 0x1f, - 0x00, 0x26, 0xab, 0xcf, 0x70, 0xff, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x3b, 0xe5, 0x04, - 0x00, 0x22, 0x00, 0x04, 0xb1, 0x64, 0x00, - 0x09, 0xcb, 0xe5, 0xe5, 0x94, 0x08, 0x00, - 0x00, 0x00, 0x12, 0x0f, 0x00, 0x00, 0x00, - /* ch = ':' */ - 0x73, 0xdb, 0x0d, - 0x3d, 0x67, 0x08, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x21, 0x30, 0x00, - 0xa0, 0xff, 0x17, - 0x08, 0x12, 0x00, - /* ch = ';' */ - 0x73, 0xdb, 0x0d, - 0x3d, 0x67, 0x08, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x21, 0x2a, 0x00, - 0x99, 0xff, 0x24, - 0x1f, 0xff, 0x17, - 0x7c, 0x54, 0x00, - 0x22, 0x04, 0x00, - /* ch = '<' */ - 0x00, 0x00, 0x13, 0x7f, 0x37, - 0x0c, 0x73, 0xef, 0x5a, 0x0c, - 0xef, 0x5a, 0x0c, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x00, - 0xef, 0x37, 0x00, 0x00, 0x00, - 0x1b, 0xbb, 0xc4, 0x1e, 0x00, - 0x00, 0x00, 0x37, 0xef, 0x4d, - 0x00, 0x00, 0x00, 0x08, 0x21, - /* ch = '=' */ - 0x0f, 0x15, 0x15, 0x15, 0x15, 0x15, 0x08, - 0x67, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x2f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0f, 0x15, 0x15, 0x15, 0x15, 0x15, 0x08, - 0x42, 0x74, 0x74, 0x74, 0x74, 0x74, 0x24, - /* ch = '>' */ - 0x7c, 0x48, 0x04, 0x00, 0x00, - 0x1b, 0x8d, 0xef, 0x37, 0x04, - 0x00, 0x00, 0x1b, 0x94, 0xdb, - 0x00, 0x00, 0x00, 0x00, 0x27, - 0x00, 0x00, 0x08, 0x73, 0xe5, - 0x04, 0x37, 0xef, 0x73, 0x0c, - 0xa9, 0xbb, 0x1e, 0x00, 0x00, - 0x22, 0x04, 0x00, 0x00, 0x00, - /* ch = '?' */ - 0x00, 0x00, 0x12, 0x2a, 0x0f, 0x00, - 0x04, 0xa9, 0xe5, 0x8f, 0xff, 0x50, - 0x19, 0x8d, 0x08, 0x00, 0x50, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x48, 0xff, - 0x00, 0x00, 0x00, 0x10, 0xdb, 0x7c, - 0x00, 0x00, 0x00, 0xb1, 0x7c, 0x04, - 0x00, 0x00, 0x1c, 0xff, 0x1f, 0x00, - 0x00, 0x00, 0x0d, 0x36, 0x10, 0x00, - 0x00, 0x00, 0x10, 0x36, 0x08, 0x00, - 0x00, 0x00, 0x4d, 0xff, 0x48, 0x00, - 0x00, 0x00, 0x00, 0x15, 0x04, 0x00, - /* ch = '@' */ - 0x00, 0x13, 0x7f, 0xcf, 0xab, 0x21, 0x00, - 0x10, 0xdb, 0x37, 0x00, 0x28, 0xff, 0x10, - 0x5a, 0x75, 0x00, 0x04, 0x15, 0x9e, 0x48, - 0xb1, 0x37, 0x2c, 0xe5, 0x82, 0xa5, 0x54, - 0xb7, 0x2e, 0xb1, 0x3f, 0x00, 0x7c, 0x54, - 0xb7, 0x35, 0x99, 0x82, 0x20, 0xe5, 0x54, - 0x6b, 0x75, 0x10, 0x67, 0x74, 0x5b, 0x32, - 0x1c, 0xf7, 0x28, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x26, 0xd4, 0xb3, 0xab, 0xd4, 0x0a, - 0x00, 0x00, 0x00, 0x12, 0x12, 0x00, 0x00, - /* ch = 'A' */ - 0x00, 0x00, 0x1c, 0x51, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x5a, 0xec, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xc8, 0xff, 0x2f, 0x00, 0x00, - 0x00, 0x22, 0xe5, 0x68, 0x90, 0x00, 0x00, - 0x00, 0x5f, 0x70, 0x22, 0xff, 0x0d, 0x00, - 0x00, 0xcf, 0x67, 0x36, 0xd9, 0x4c, 0x00, - 0x2a, 0xf7, 0x36, 0x36, 0x7b, 0xaf, 0x00, - 0x6b, 0x82, 0x00, 0x00, 0x17, 0xff, 0x24, - 0xe5, 0x35, 0x00, 0x00, 0x00, 0xa7, 0x68, - /* ch = 'B' */ - 0x67, 0xcf, 0xcf, 0xab, 0x5b, 0x08, 0x00, - 0x7c, 0x88, 0x15, 0x1a, 0xa0, 0xa7, 0x00, - 0x7c, 0x82, 0x00, 0x00, 0x32, 0xff, 0x04, - 0x7c, 0x8f, 0x15, 0x1a, 0xa0, 0x7c, 0x04, - 0x7c, 0xef, 0xcf, 0xcf, 0xec, 0x2b, 0x00, - 0x7c, 0x82, 0x00, 0x00, 0x32, 0xff, 0x17, - 0x7c, 0x82, 0x00, 0x00, 0x00, 0xff, 0x35, - 0x7c, 0x82, 0x00, 0x00, 0x37, 0xff, 0x24, - 0x7c, 0xf7, 0xcf, 0xdd, 0xdd, 0x37, 0x00, - /* ch = 'C' */ - 0x00, 0x10, 0x66, 0xcf, 0xab, 0x26, 0x00, - 0x04, 0xb1, 0x77, 0x0c, 0x28, 0xf7, 0x32, - 0x40, 0xcf, 0x08, 0x00, 0x00, 0x28, 0x08, - 0x77, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xa0, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x17, 0xf7, 0x3a, 0x00, 0x08, 0x8d, 0x22, - 0x00, 0x2c, 0xef, 0xdd, 0xef, 0x7e, 0x08, - 0x00, 0x00, 0x00, 0x15, 0x08, 0x00, 0x00, - /* ch = 'D' */ - 0x67, 0xcf, 0xcf, 0x82, 0x37, 0x00, 0x00, - 0x7c, 0x88, 0x15, 0x2b, 0xdb, 0x70, 0x00, - 0x7c, 0x82, 0x00, 0x00, 0x2c, 0xff, 0x17, - 0x7c, 0x82, 0x00, 0x00, 0x04, 0xff, 0x35, - 0x7c, 0x82, 0x00, 0x00, 0x00, 0xbd, 0x48, - 0x7c, 0x82, 0x00, 0x00, 0x00, 0xe5, 0x37, - 0x7c, 0x82, 0x00, 0x00, 0x17, 0xff, 0x1f, - 0x7c, 0x82, 0x00, 0x04, 0xa0, 0x90, 0x04, - 0x7c, 0xf7, 0xcf, 0xe5, 0x8d, 0x0c, 0x00, - /* ch = 'E' */ - 0x45, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x1a, - 0x50, 0xbd, 0x15, 0x15, 0x15, 0x15, 0x08, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xf7, 0xcf, 0xcf, 0xcf, 0x2f, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0xcf, 0xcf, 0xcf, 0xcf, 0x1a, - /* ch = 'F' */ - 0x1a, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x1a, - 0x1c, 0xff, 0x15, 0x15, 0x15, 0x15, 0x08, - 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x17, 0x15, 0x15, 0x08, 0x00, - 0x1c, 0xff, 0xcf, 0xcf, 0xcf, 0x2f, 0x00, - 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - /* ch = 'G' */ - 0x00, 0x10, 0x73, 0xcf, 0xab, 0x28, 0x00, - 0x0d, 0xdb, 0x77, 0x12, 0x31, 0xf7, 0x27, - 0x48, 0xa7, 0x04, 0x00, 0x00, 0x22, 0x04, - 0x90, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb7, 0x54, 0x00, 0x08, 0x15, 0x15, 0x0c, - 0xb1, 0x59, 0x00, 0x22, 0x74, 0xe5, 0x54, - 0x6b, 0xa7, 0x00, 0x00, 0x00, 0xb7, 0x54, - 0x1c, 0xff, 0x37, 0x00, 0x00, 0xbd, 0x54, - 0x00, 0x2f, 0xef, 0xdd, 0xe5, 0xb3, 0x1b, - 0x00, 0x00, 0x00, 0x12, 0x08, 0x00, 0x00, - /* ch = 'H' */ - 0x45, 0x95, 0x00, 0x00, 0x1a, 0xcf, 0x1f, - 0x50, 0xbd, 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x50, 0xbd, 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x50, 0xbd, 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x50, 0xf7, 0xcf, 0xcf, 0xd4, 0xff, 0x1f, - 0x50, 0xbd, 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x50, 0xbd, 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x50, 0xbd, 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x50, 0xbd, 0x00, 0x00, 0x1c, 0xff, 0x1f, - /* ch = 'I' */ - 0x1a, 0xcf, 0xcf, 0xcf, 0xcf, 0x45, - 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, - 0x1a, 0xcf, 0xe5, 0xff, 0xcf, 0x67, - /* ch = 'J' */ - 0x00, 0x00, 0xcf, 0xcf, 0xcf, 0xcf, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x04, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x04, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x04, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x04, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x04, - 0x00, 0x00, 0x00, 0x2f, 0xff, 0x04, - 0x17, 0x2c, 0x00, 0x48, 0xc8, 0x04, - 0x2c, 0xef, 0xd4, 0xf7, 0x2f, 0x00, - 0x00, 0x04, 0x15, 0x08, 0x00, 0x00, - /* ch = 'K' */ - 0x67, 0x73, 0x00, 0x00, 0x32, 0xc6, 0x17, - 0x7c, 0x82, 0x00, 0x1f, 0xf7, 0x35, 0x00, - 0x7c, 0x82, 0x1f, 0xef, 0x48, 0x00, 0x00, - 0x7c, 0x9e, 0xdb, 0x54, 0x00, 0x00, 0x00, - 0x7c, 0xff, 0xf7, 0x37, 0x00, 0x00, 0x00, - 0x7c, 0x88, 0x44, 0xff, 0x17, 0x00, 0x00, - 0x7c, 0x82, 0x00, 0x90, 0xb7, 0x04, 0x00, - 0x7c, 0x82, 0x00, 0x10, 0xe5, 0x54, 0x00, - 0x7c, 0x82, 0x00, 0x00, 0x35, 0xff, 0x26, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, - /* ch = 'L' */ - 0x2d, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0xd4, 0xcf, 0xcf, 0xcf, 0x1a, - /* ch = 'M' */ - 0x95, 0x40, 0x00, 0x00, 0x00, 0x8d, 0x45, - 0xb7, 0xec, 0x04, 0x00, 0x2a, 0xff, 0x54, - 0xb7, 0xff, 0x4c, 0x00, 0xa0, 0xff, 0x54, - 0xb7, 0xb7, 0xec, 0x2f, 0xdb, 0xbd, 0x54, - 0xb7, 0x54, 0xa7, 0xff, 0x3f, 0xb7, 0x54, - 0xb7, 0x54, 0x2c, 0xb7, 0x04, 0xb7, 0x54, - 0xb7, 0x54, 0x00, 0x00, 0x00, 0xb7, 0x54, - 0xb7, 0x54, 0x00, 0x00, 0x00, 0xb7, 0x54, - 0xb7, 0x54, 0x00, 0x00, 0x00, 0xb7, 0x54, - /* ch = 'N' */ - 0x67, 0x8d, 0x00, 0x00, 0x00, 0xcf, 0x2d, - 0x7c, 0xff, 0x35, 0x00, 0x00, 0xff, 0x35, - 0x7c, 0xff, 0xcf, 0x04, 0x00, 0xff, 0x35, - 0x7c, 0x88, 0xdb, 0x54, 0x00, 0xff, 0x35, - 0x7c, 0x82, 0x3b, 0xff, 0x10, 0xff, 0x35, - 0x7c, 0x82, 0x00, 0xb7, 0x70, 0xff, 0x35, - 0x7c, 0x82, 0x00, 0x2a, 0xff, 0xff, 0x35, - 0x7c, 0x82, 0x00, 0x00, 0x7c, 0xff, 0x35, - 0x7c, 0x82, 0x00, 0x00, 0x17, 0xf7, 0x35, - /* ch = 'O' */ - 0x00, 0x1b, 0x9e, 0xcf, 0x7f, 0x10, 0x00, - 0x1c, 0xf7, 0x48, 0x1a, 0x99, 0xb7, 0x04, - 0x6b, 0x90, 0x04, 0x00, 0x10, 0xff, 0x2f, - 0xb7, 0x50, 0x00, 0x00, 0x00, 0xb7, 0x54, - 0xc8, 0x35, 0x00, 0x00, 0x00, 0x7c, 0x7c, - 0xb7, 0x50, 0x00, 0x00, 0x00, 0x90, 0x59, - 0x7c, 0x82, 0x00, 0x00, 0x00, 0xe5, 0x3f, - 0x2a, 0xff, 0x24, 0x00, 0x50, 0xe5, 0x10, - 0x00, 0x44, 0xf7, 0xef, 0xe5, 0x28, 0x00, - 0x00, 0x00, 0x04, 0x15, 0x00, 0x00, 0x00, - /* ch = 'P' */ - 0x45, 0xcf, 0xcf, 0xcf, 0x74, 0x19, 0x00, - 0x50, 0xbd, 0x15, 0x15, 0x77, 0xff, 0x0d, - 0x50, 0xbd, 0x00, 0x00, 0x04, 0xff, 0x35, - 0x50, 0xbd, 0x00, 0x00, 0x1f, 0xff, 0x2c, - 0x50, 0xff, 0xcf, 0xcf, 0xef, 0x66, 0x04, - 0x50, 0xbd, 0x15, 0x15, 0x0c, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 'Q' */ - 0x00, 0x1b, 0x9e, 0xcf, 0x7f, 0x10, 0x00, - 0x1c, 0xf7, 0x3f, 0x15, 0x8a, 0xb7, 0x04, - 0x6b, 0x90, 0x00, 0x00, 0x0d, 0xf7, 0x2f, - 0xb7, 0x48, 0x00, 0x00, 0x00, 0xa0, 0x54, - 0xc8, 0x35, 0x00, 0x00, 0x00, 0x7c, 0x7c, - 0xb7, 0x48, 0x00, 0x00, 0x00, 0x82, 0x59, - 0x7c, 0x82, 0x00, 0x00, 0x00, 0xcf, 0x3f, - 0x2a, 0xff, 0x21, 0x00, 0x37, 0xf7, 0x10, - 0x00, 0x44, 0xf7, 0xdd, 0xef, 0x2f, 0x00, - 0x00, 0x00, 0x1a, 0xff, 0x13, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x85, 0xf7, 0xe5, 0x1f, - /* ch = 'R' */ - 0x45, 0xcf, 0xcf, 0xbd, 0x67, 0x13, 0x00, - 0x50, 0xbd, 0x15, 0x1a, 0x8a, 0xe5, 0x04, - 0x50, 0xbd, 0x00, 0x00, 0x1c, 0xff, 0x24, - 0x50, 0xbd, 0x00, 0x00, 0x2c, 0xff, 0x17, - 0x50, 0xff, 0xcf, 0xcf, 0xf7, 0x50, 0x00, - 0x50, 0xbd, 0x15, 0x90, 0x82, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x22, 0xff, 0x24, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x8a, 0x97, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x1c, 0xff, 0x26, - /* ch = 'S' */ - 0x00, 0x1b, 0x8f, 0xcf, 0x8f, 0x1b, 0x00, - 0x0d, 0xf7, 0x43, 0x0c, 0x3f, 0xdb, 0x09, - 0x32, 0xff, 0x10, 0x00, 0x00, 0x0f, 0x00, - 0x0d, 0xdb, 0x90, 0x0c, 0x00, 0x00, 0x00, - 0x00, 0x13, 0x7f, 0xff, 0x94, 0x13, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0x77, 0xe5, 0x0d, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x35, - 0x32, 0x75, 0x04, 0x00, 0x26, 0xff, 0x24, - 0x1b, 0xbb, 0xf7, 0xcf, 0xf7, 0x48, 0x00, - 0x00, 0x00, 0x08, 0x15, 0x04, 0x00, 0x00, - /* ch = 'T' */ - 0x95, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x45, - 0x12, 0x15, 0x5e, 0xbd, 0x15, 0x15, 0x0f, - 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, - /* ch = 'U' */ - 0x67, 0x73, 0x00, 0x00, 0x00, 0x95, 0x2d, - 0x7c, 0x82, 0x00, 0x00, 0x00, 0xb7, 0x35, - 0x7c, 0x82, 0x00, 0x00, 0x00, 0xb7, 0x35, - 0x7c, 0x82, 0x00, 0x00, 0x00, 0xb7, 0x35, - 0x7c, 0x82, 0x00, 0x00, 0x00, 0xb7, 0x35, - 0x7c, 0x82, 0x00, 0x00, 0x00, 0xb7, 0x35, - 0x7c, 0x82, 0x00, 0x00, 0x00, 0xf7, 0x35, - 0x40, 0xec, 0x10, 0x00, 0x2c, 0xff, 0x1a, - 0x00, 0x73, 0xf7, 0xcf, 0xe5, 0x3f, 0x00, - 0x00, 0x00, 0x08, 0x15, 0x04, 0x00, 0x00, - /* ch = 'V' */ - 0xa4, 0x40, 0x00, 0x00, 0x00, 0x6c, 0x58, - 0x5f, 0xaf, 0x00, 0x00, 0x04, 0xf7, 0x2f, - 0x24, 0xff, 0x1a, 0x00, 0x2c, 0xe5, 0x08, - 0x00, 0xcf, 0x4c, 0x00, 0x70, 0x75, 0x00, - 0x00, 0x5a, 0xaf, 0x00, 0xe5, 0x2f, 0x00, - 0x00, 0x22, 0xff, 0x40, 0xe5, 0x08, 0x00, - 0x00, 0x00, 0xc8, 0xec, 0x75, 0x00, 0x00, - 0x00, 0x00, 0x5a, 0xff, 0x2f, 0x00, 0x00, - 0x00, 0x00, 0x22, 0xe5, 0x08, 0x00, 0x00, - /* ch = 'W' */ - 0xcf, 0x1a, 0x00, 0x00, 0x00, 0x2d, 0x8f, - 0xcf, 0x35, 0x04, 0xe5, 0x00, 0x50, 0x7c, - 0x90, 0x54, 0x2a, 0xff, 0x26, 0x77, 0x50, - 0x5f, 0x82, 0x5f, 0xff, 0x54, 0xa0, 0x35, - 0x44, 0xbd, 0xa0, 0x82, 0xa7, 0xcf, 0x1f, - 0x2a, 0xff, 0xf7, 0x24, 0xff, 0xff, 0x04, - 0x14, 0xff, 0x97, 0x00, 0xe5, 0xbd, 0x00, - 0x00, 0xe5, 0x48, 0x00, 0x7c, 0x88, 0x00, - 0x00, 0xa0, 0x21, 0x00, 0x3b, 0x59, 0x00, - /* ch = 'X' */ - 0x53, 0x8d, 0x00, 0x00, 0x1c, 0xcf, 0x17, - 0x10, 0xf7, 0x35, 0x00, 0x90, 0x75, 0x00, - 0x00, 0x50, 0xcf, 0x26, 0xff, 0x1a, 0x00, - 0x00, 0x04, 0xdb, 0xf7, 0x70, 0x00, 0x00, - 0x00, 0x00, 0x4a, 0xff, 0x24, 0x00, 0x00, - 0x00, 0x04, 0xc8, 0xff, 0x70, 0x00, 0x00, - 0x00, 0x44, 0xe5, 0x35, 0xff, 0x1f, 0x00, - 0x04, 0xdb, 0x48, 0x00, 0x90, 0x97, 0x00, - 0x54, 0xc8, 0x08, 0x00, 0x1c, 0xff, 0x2c, - /* ch = 'Y' */ - 0x8f, 0x60, 0x00, 0x00, 0x00, 0xab, 0x4a, - 0x2c, 0xff, 0x1a, 0x00, 0x2c, 0xf7, 0x10, - 0x00, 0xa7, 0x75, 0x00, 0xa7, 0x64, 0x00, - 0x00, 0x2c, 0xff, 0x35, 0xff, 0x1a, 0x00, - 0x00, 0x00, 0xa7, 0xff, 0x75, 0x00, 0x00, - 0x00, 0x00, 0x35, 0xff, 0x26, 0x00, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x1f, 0x00, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x1f, 0x00, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x1f, 0x00, 0x00, - /* ch = 'Z' */ - 0x45, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x2a, - 0x0c, 0x15, 0x15, 0x15, 0x58, 0xdb, 0x08, - 0x00, 0x00, 0x00, 0x10, 0xf7, 0x32, 0x00, - 0x00, 0x00, 0x00, 0x82, 0x90, 0x04, 0x00, - 0x00, 0x00, 0x2a, 0xf7, 0x1a, 0x00, 0x00, - 0x00, 0x04, 0xc8, 0x59, 0x00, 0x00, 0x00, - 0x00, 0x54, 0xdb, 0x08, 0x00, 0x00, 0x00, - 0x17, 0xf7, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x77, 0xff, 0xd4, 0xcf, 0xcf, 0xd4, 0x54, - /* ch = '[' */ - 0x1e, 0x36, 0x36, 0x36, 0x2d, - 0x50, 0xa5, 0x36, 0x36, 0x30, - 0x50, 0x82, 0x00, 0x00, 0x00, - 0x50, 0x82, 0x00, 0x00, 0x00, - 0x50, 0x82, 0x00, 0x00, 0x00, - 0x50, 0x82, 0x00, 0x00, 0x00, - 0x50, 0x82, 0x00, 0x00, 0x00, - 0x50, 0x82, 0x00, 0x00, 0x00, - 0x50, 0x82, 0x00, 0x00, 0x00, - 0x50, 0x82, 0x00, 0x00, 0x00, - 0x50, 0xd1, 0x74, 0x74, 0x58, - 0x0c, 0x15, 0x15, 0x15, 0x15, - /* ch = '\' */ - 0x00, 0x22, 0x00, - 0x2a, 0xff, 0x17, - 0x00, 0xa7, 0x5f, - 0x00, 0x32, 0xff, - 0x00, 0x00, 0xc8, - 0x00, 0x00, 0x3b, - 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* ch = ']' */ - 0x0d, 0x36, 0x36, 0x36, 0x36, 0x0d, - 0x0d, 0x36, 0x36, 0x36, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, - 0x14, 0x74, 0x74, 0x74, 0xff, 0x1f, - 0x04, 0x15, 0x15, 0x15, 0x15, 0x08, - /* ch = '^' */ - 0x00, 0x10, 0x9c, 0x00, 0x00, - 0x00, 0x6b, 0xff, 0x3f, 0x00, - 0x24, 0xf7, 0x4a, 0xe5, 0x04, - 0xb1, 0x48, 0x00, 0xb7, 0x48, - 0x0c, 0x04, 0x00, 0x0c, 0x08, - /* ch = '_' */ - 0x95, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x45, - 0x12, 0x15, 0x15, 0x15, 0x15, 0x15, 0x0f, - /* ch = '`' */ - 0x08, 0x22, 0x00, - 0x22, 0xff, 0x0d, - 0x00, 0xa7, 0x90, - 0x00, 0x2f, 0xef, - /* ch = 'a' */ - 0x00, 0x0c, 0x3e, 0x74, 0x30, 0x04, 0x00, - 0x00, 0xcb, 0x5a, 0x36, 0xa0, 0xa7, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x24, 0xff, 0x04, - 0x00, 0x28, 0x82, 0xcf, 0xd4, 0xff, 0x1f, - 0x36, 0xe5, 0x20, 0x00, 0x1c, 0xff, 0x1f, - 0x77, 0x9e, 0x00, 0x00, 0x59, 0xff, 0x1f, - 0x1f, 0xef, 0xab, 0xb3, 0xbb, 0xff, 0x1f, - 0x00, 0x00, 0x15, 0x0f, 0x00, 0x00, 0x00, - /* ch = 'b' */ - 0x1e, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbd, 0x22, 0x67, 0x3f, 0x04, 0x00, - 0x50, 0xff, 0x94, 0x3e, 0xdb, 0xa7, 0x00, - 0x50, 0xf7, 0x08, 0x00, 0x26, 0xff, 0x26, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0xff, 0x35, - 0x50, 0xbd, 0x00, 0x00, 0x04, 0xff, 0x35, - 0x50, 0xff, 0x1c, 0x00, 0x3f, 0xf7, 0x10, - 0x50, 0xb1, 0xef, 0xd4, 0xf7, 0x35, 0x00, - 0x00, 0x00, 0x00, 0x15, 0x08, 0x00, 0x00, - /* ch = 'c' */ - 0x00, 0x00, 0x25, 0x5b, 0x3e, 0x13, 0x00, - 0x00, 0x7c, 0xc4, 0x3e, 0x5a, 0xff, 0x1a, - 0x2c, 0xff, 0x1a, 0x00, 0x00, 0x22, 0x04, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x4d, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x17, 0xf7, 0x54, 0x00, 0x04, 0x40, 0x04, - 0x00, 0x2c, 0xef, 0xe5, 0xe5, 0x94, 0x13, - 0x00, 0x00, 0x00, 0x15, 0x0f, 0x00, 0x00, - /* ch = 'd' */ - 0x00, 0x00, 0x00, 0x00, 0x0d, 0x36, 0x13, - 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x00, 0x13, 0x50, 0x67, 0x31, 0xff, 0x1f, - 0x10, 0xdb, 0x6a, 0x31, 0xdb, 0xff, 0x1f, - 0x5a, 0xa7, 0x04, 0x00, 0x3b, 0xff, 0x1f, - 0x7c, 0x82, 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x77, 0x88, 0x00, 0x00, 0x24, 0xff, 0x1f, - 0x39, 0xff, 0x1a, 0x00, 0x6f, 0xff, 0x1f, - 0x00, 0x84, 0xff, 0xdd, 0xa9, 0xff, 0x1f, - 0x00, 0x00, 0x0c, 0x0f, 0x00, 0x00, 0x00, - /* ch = 'e' */ - 0x00, 0x08, 0x3f, 0x74, 0x37, 0x04, 0x00, - 0x04, 0xd4, 0x77, 0x25, 0xb1, 0x7c, 0x00, - 0x44, 0xc8, 0x04, 0x00, 0x1f, 0xff, 0x17, - 0x7c, 0xf7, 0xcf, 0xcf, 0xd4, 0xff, 0x1f, - 0x6b, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2c, 0xff, 0x1f, 0x00, 0x04, 0x22, 0x00, - 0x00, 0x5a, 0xf7, 0xab, 0xe5, 0x66, 0x04, - 0x00, 0x00, 0x04, 0x15, 0x0c, 0x00, 0x00, - /* ch = 'f' */ - 0x00, 0x00, 0x00, 0x18, 0x36, 0x25, - 0x00, 0x00, 0x50, 0xdb, 0x3e, 0xbb, - 0x00, 0x00, 0xf7, 0x37, 0x00, 0x0d, - 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, - 0x45, 0xcf, 0xff, 0xd4, 0xcf, 0x2f, - 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, - 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, - 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, - 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, - 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, - /* ch = 'g' */ - 0x00, 0x19, 0x67, 0x67, 0x25, 0x50, 0x32, - 0x1c, 0xf7, 0x3f, 0x3f, 0xff, 0x45, 0x12, - 0x4d, 0xbd, 0x00, 0x00, 0xb7, 0x50, 0x00, - 0x2a, 0xff, 0x21, 0x21, 0xf7, 0x2c, 0x00, - 0x00, 0x9e, 0xd4, 0xbd, 0x37, 0x00, 0x00, - 0x27, 0xff, 0x1d, 0x15, 0x0f, 0x00, 0x00, - 0x0c, 0xea, 0xbd, 0xcf, 0xdd, 0xdb, 0x0d, - 0x8a, 0x59, 0x00, 0x00, 0x00, 0xd9, 0x35, - 0x66, 0xe5, 0x47, 0x36, 0x85, 0xd4, 0x10, - 0x00, 0x18, 0x36, 0x36, 0x25, 0x08, 0x00, - /* ch = 'h' */ - 0x16, 0x36, 0x09, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x16, 0x50, 0x50, 0x08, 0x00, - 0x32, 0xff, 0xdb, 0x3e, 0xb1, 0xa7, 0x00, - 0x32, 0xff, 0x21, 0x00, 0x32, 0xff, 0x04, - 0x32, 0xff, 0x04, 0x00, 0x32, 0xff, 0x04, - 0x32, 0xff, 0x04, 0x00, 0x32, 0xff, 0x04, - 0x32, 0xff, 0x04, 0x00, 0x32, 0xff, 0x04, - 0x32, 0xff, 0x04, 0x00, 0x32, 0xff, 0x04, - /* ch = 'i' */ - 0x00, 0x04, 0x12, 0x00, 0x00, - 0x00, 0x49, 0xff, 0x2a, 0x00, - 0x00, 0x04, 0x15, 0x04, 0x00, - 0x2d, 0x36, 0x36, 0x00, 0x00, - 0x2d, 0x62, 0xff, 0x04, 0x00, - 0x00, 0x32, 0xff, 0x04, 0x00, - 0x00, 0x32, 0xff, 0x04, 0x00, - 0x00, 0x32, 0xff, 0x04, 0x00, - 0x00, 0x32, 0xff, 0x04, 0x00, - 0xcf, 0xdd, 0xff, 0xd4, 0x45, - /* ch = 'j' */ - 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, - 0x00, 0x00, 0x00, 0x2f, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x04, 0x15, 0x08, - 0x00, 0x1e, 0x36, 0x36, 0x36, 0x0d, - 0x00, 0x1e, 0x36, 0x4a, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x0d, 0x19, 0x00, 0x2c, 0xff, 0x17, - 0x52, 0xe5, 0x50, 0xd4, 0x77, 0x00, - 0x00, 0x25, 0x36, 0x25, 0x04, 0x00, - /* ch = 'k' */ - 0x16, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x04, 0x00, 0x19, 0x36, 0x10, - 0x32, 0xff, 0x04, 0x21, 0xf7, 0x37, 0x00, - 0x32, 0xff, 0x2f, 0xef, 0x2f, 0x00, 0x00, - 0x32, 0xff, 0xff, 0xbd, 0x04, 0x00, 0x00, - 0x32, 0xff, 0x25, 0xdb, 0x82, 0x00, 0x00, - 0x32, 0xff, 0x04, 0x1f, 0xf7, 0x54, 0x00, - 0x32, 0xff, 0x04, 0x00, 0x32, 0xff, 0x35, - /* ch = 'l' */ - 0x0d, 0x36, 0x36, 0x36, 0x00, 0x00, - 0x14, 0x74, 0x9c, 0xff, 0x04, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, - 0x1a, 0xcf, 0xdd, 0xff, 0xd4, 0x95, - /* ch = 'm' */ - 0x2d, 0x30, 0x67, 0x22, 0x3f, 0x5b, 0x08, - 0xb7, 0xb7, 0x64, 0xff, 0x54, 0xc8, 0x50, - 0xb7, 0x54, 0x32, 0xff, 0x08, 0x7c, 0x82, - 0xb7, 0x54, 0x32, 0xff, 0x04, 0x7c, 0x82, - 0xb7, 0x54, 0x32, 0xff, 0x04, 0x7c, 0x82, - 0xb7, 0x54, 0x32, 0xff, 0x04, 0x7c, 0x82, - 0xb7, 0x54, 0x32, 0xff, 0x04, 0x7c, 0x82, - /* ch = 'n' */ - 0x16, 0x36, 0x13, 0x50, 0x50, 0x08, 0x00, - 0x32, 0xff, 0xdb, 0x3e, 0xc4, 0xa7, 0x00, - 0x32, 0xff, 0x1a, 0x00, 0x35, 0xff, 0x04, - 0x32, 0xff, 0x04, 0x00, 0x32, 0xff, 0x04, - 0x32, 0xff, 0x04, 0x00, 0x32, 0xff, 0x04, - 0x32, 0xff, 0x04, 0x00, 0x32, 0xff, 0x04, - 0x32, 0xff, 0x04, 0x00, 0x32, 0xff, 0x04, - /* ch = 'o' */ - 0x00, 0x04, 0x30, 0x74, 0x2a, 0x00, 0x00, - 0x04, 0xc4, 0x99, 0x36, 0xd4, 0x82, 0x00, - 0x50, 0xc8, 0x08, 0x00, 0x22, 0xff, 0x24, - 0x90, 0x82, 0x00, 0x00, 0x00, 0xf7, 0x3f, - 0x7c, 0x97, 0x00, 0x00, 0x00, 0xff, 0x37, - 0x39, 0xff, 0x1f, 0x00, 0x35, 0xf7, 0x10, - 0x00, 0x5a, 0xff, 0xcf, 0xef, 0x35, 0x00, - 0x00, 0x00, 0x08, 0x15, 0x08, 0x00, 0x00, - /* ch = 'p' */ - 0x1e, 0x2d, 0x22, 0x5b, 0x37, 0x04, 0x00, - 0x50, 0xff, 0x94, 0x36, 0xc4, 0xb7, 0x00, - 0x50, 0xe5, 0x08, 0x00, 0x22, 0xff, 0x32, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0xf7, 0x54, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0xff, 0x48, - 0x50, 0xff, 0x1c, 0x00, 0x35, 0xff, 0x1a, - 0x50, 0xe5, 0xef, 0xcf, 0xf7, 0x48, 0x00, - 0x50, 0xbd, 0x04, 0x15, 0x0c, 0x00, 0x00, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 'q' */ - 0x00, 0x0c, 0x50, 0x67, 0x28, 0x36, 0x0d, - 0x10, 0xdb, 0x6a, 0x2a, 0xdb, 0xff, 0x1f, - 0x5a, 0xa7, 0x04, 0x00, 0x32, 0xff, 0x1f, - 0x7c, 0x82, 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x7c, 0x88, 0x00, 0x00, 0x1f, 0xff, 0x1f, - 0x39, 0xff, 0x1f, 0x00, 0x5f, 0xff, 0x1f, - 0x00, 0x77, 0xff, 0xdd, 0xbb, 0xff, 0x1f, - 0x00, 0x00, 0x0c, 0x0f, 0x1c, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, - 0x00, 0x00, 0x00, 0x00, 0x0d, 0x36, 0x10, - /* ch = 'r' */ - 0x36, 0x21, 0x2a, 0x74, 0x37, 0x04, - 0xff, 0xff, 0x99, 0x36, 0xc4, 0x24, - 0xff, 0xb7, 0x04, 0x00, 0x0c, 0x04, - 0xff, 0x48, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, - /* ch = 's' */ - 0x00, 0x08, 0x3e, 0x74, 0x3e, 0x08, 0x00, - 0x00, 0xc0, 0x7c, 0x1a, 0x77, 0xc8, 0x00, - 0x14, 0xff, 0x4f, 0x00, 0x00, 0x22, 0x00, - 0x00, 0x35, 0xe5, 0xef, 0x73, 0x13, 0x00, - 0x00, 0x00, 0x00, 0x1e, 0x99, 0xe5, 0x04, - 0x1c, 0x65, 0x04, 0x00, 0x26, 0xff, 0x17, - 0x19, 0xbb, 0xef, 0xcf, 0xef, 0x48, 0x00, - 0x00, 0x00, 0x08, 0x15, 0x08, 0x00, 0x00, - /* ch = 't' */ - 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, - 0x00, 0x00, 0x90, 0x70, 0x00, 0x00, - 0x16, 0x36, 0xcf, 0x87, 0x36, 0x1e, - 0x16, 0x36, 0xcf, 0x82, 0x36, 0x21, - 0x00, 0x00, 0xe5, 0x37, 0x00, 0x00, - 0x00, 0x00, 0xff, 0x35, 0x00, 0x00, - 0x00, 0x00, 0xff, 0x35, 0x00, 0x00, - 0x00, 0x00, 0xe5, 0x5f, 0x00, 0x22, - 0x00, 0x00, 0x4d, 0xff, 0xe5, 0xcb, - 0x00, 0x00, 0x00, 0x08, 0x0c, 0x00, - /* ch = 'u' */ - 0x1e, 0x2d, 0x00, 0x00, 0x16, 0x36, 0x0d, - 0x50, 0xbd, 0x00, 0x00, 0x32, 0xff, 0x1f, - 0x50, 0xbd, 0x00, 0x00, 0x32, 0xff, 0x1f, - 0x50, 0xbd, 0x00, 0x00, 0x32, 0xff, 0x1f, - 0x50, 0xc6, 0x00, 0x00, 0x32, 0xff, 0x1f, - 0x2f, 0xff, 0x1a, 0x00, 0x70, 0xff, 0x1f, - 0x00, 0x94, 0xf7, 0xd4, 0xcb, 0xff, 0x1f, - 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, - /* ch = 'v' */ - 0x2b, 0x2b, 0x00, 0x00, 0x00, 0x30, 0x16, - 0x44, 0xec, 0x04, 0x00, 0x0d, 0xff, 0x17, - 0x0d, 0xf7, 0x3b, 0x00, 0x44, 0xa7, 0x04, - 0x00, 0x70, 0x97, 0x00, 0xa7, 0x3b, 0x00, - 0x00, 0x24, 0xff, 0x40, 0xe5, 0x08, 0x00, - 0x00, 0x00, 0xc8, 0xff, 0x5f, 0x00, 0x00, - 0x00, 0x00, 0x48, 0xff, 0x1a, 0x00, 0x00, - /* ch = 'w' */ - 0x36, 0x13, 0x00, 0x00, 0x00, 0x1e, 0x26, - 0xe5, 0x2c, 0x1c, 0xbd, 0x00, 0x54, 0x70, - 0x90, 0x50, 0x3b, 0xff, 0x26, 0x7c, 0x50, - 0x54, 0x88, 0x77, 0xe5, 0x64, 0xb1, 0x32, - 0x2f, 0xd9, 0xcf, 0x48, 0xbd, 0xe5, 0x1c, - 0x1a, 0xff, 0xb7, 0x10, 0xff, 0xe5, 0x04, - 0x00, 0xe5, 0x64, 0x00, 0xa0, 0xa7, 0x00, - /* ch = 'x' */ - 0x24, 0x30, 0x00, 0x00, 0x19, 0x33, 0x09, - 0x10, 0xdb, 0x48, 0x04, 0xb7, 0x54, 0x00, - 0x00, 0x2f, 0xff, 0x7c, 0xb1, 0x08, 0x00, - 0x00, 0x00, 0x70, 0xff, 0x24, 0x00, 0x00, - 0x00, 0x04, 0xdb, 0xf7, 0x70, 0x00, 0x00, - 0x00, 0x77, 0xb1, 0x21, 0xf7, 0x35, 0x00, - 0x32, 0xf7, 0x1f, 0x00, 0x4d, 0xe5, 0x10, - /* ch = 'y' */ - 0x24, 0x2d, 0x00, 0x00, 0x00, 0x36, 0x1c, - 0x2c, 0xff, 0x0d, 0x00, 0x14, 0xff, 0x1f, - 0x04, 0xe5, 0x4c, 0x00, 0x48, 0xb7, 0x04, - 0x00, 0x5a, 0xcf, 0x00, 0xa7, 0x4c, 0x00, - 0x00, 0x17, 0xff, 0x3f, 0xff, 0x10, 0x00, - 0x00, 0x00, 0x8a, 0xff, 0x90, 0x00, 0x00, - 0x00, 0x00, 0x2c, 0xff, 0x2f, 0x00, 0x00, - 0x00, 0x00, 0x32, 0xe5, 0x08, 0x00, 0x00, - 0xa0, 0x54, 0xdb, 0x50, 0x00, 0x00, 0x00, - 0x1e, 0x36, 0x25, 0x00, 0x00, 0x00, 0x00, - /* ch = 'z' */ - 0x16, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, - 0x16, 0x36, 0x36, 0x36, 0xc4, 0xb1, 0x04, - 0x00, 0x00, 0x00, 0x50, 0xdb, 0x13, 0x00, - 0x00, 0x00, 0x32, 0xf7, 0x21, 0x00, 0x00, - 0x00, 0x1f, 0xf7, 0x35, 0x00, 0x00, 0x00, - 0x10, 0xdb, 0x64, 0x00, 0x00, 0x00, 0x00, - 0x77, 0xff, 0xdd, 0xcf, 0xcf, 0xdd, 0x35, - /* ch = '{' */ - 0x1f, 0xbd, 0xd4, 0x6c, - 0xc8, 0x4f, 0x00, 0x00, - 0xff, 0x35, 0x00, 0x00, - 0xff, 0x35, 0x00, 0x00, - 0xf7, 0x10, 0x00, 0x00, - 0x36, 0x00, 0x00, 0x00, - 0xff, 0x14, 0x00, 0x00, - 0xff, 0x2a, 0x00, 0x00, - 0xff, 0x1f, 0x00, 0x00, - 0xff, 0x35, 0x00, 0x00, - 0x73, 0xf7, 0x74, 0x42, - 0x00, 0x0f, 0x15, 0x12, - /* ch = '|' */ - 0x08, 0x15, 0x00, - 0x32, 0xff, 0x04, - 0x32, 0xff, 0x04, - 0x32, 0xff, 0x04, - 0x32, 0xff, 0x04, - 0x32, 0xff, 0x04, - 0x32, 0xff, 0x04, - 0x32, 0xff, 0x04, - 0x32, 0xff, 0x04, - 0x32, 0xff, 0x04, - 0x32, 0xff, 0x04, - 0x32, 0xff, 0x04, - 0x08, 0x15, 0x04, - /* ch = '}' */ - 0xcf, 0xdd, 0x8d, 0x0d, - 0x00, 0x04, 0xa7, 0x5f, - 0x00, 0x00, 0x7c, 0x82, - 0x00, 0x00, 0x77, 0x82, - 0x00, 0x00, 0x39, 0xcf, - 0x00, 0x00, 0x00, 0x7f, - 0x00, 0x00, 0x40, 0xcf, - 0x00, 0x00, 0x5a, 0x82, - 0x00, 0x00, 0x50, 0xbd, - 0x00, 0x00, 0x7c, 0x88, - 0x74, 0x8f, 0xf7, 0x32, - 0x15, 0x15, 0x0c, 0x00, - /* ch = '~' */ - 0x00, 0x2a, 0x50, 0x1b, 0x00, 0x19, 0x10, - 0x5b, 0xc4, 0x4f, 0xf7, 0x73, 0xdb, 0x35, - 0x04, 0x0c, 0x00, 0x1b, 0x36, 0x20, 0x00 + /* ch = '!' */ + 0x13, 0x28, 0x00, 0x77, 0xff, 0x10, 0x77, 0xff, 0x04, 0x50, 0xff, 0x04, + 0x50, 0xbd, 0x04, 0x44, 0xbd, 0x00, 0x32, 0xa7, 0x00, 0x08, 0x12, 0x00, + 0x21, 0x30, 0x00, 0x99, 0xff, 0x17, 0x08, 0x12, 0x00, + /* ch = '"' */ + 0x08, 0x2a, 0x00, 0x22, 0x08, 0x39, 0xff, 0x1c, 0xff, 0x54, 0x35, 0xe5, + 0x04, 0xff, 0x3b, 0x6b, 0x70, 0x1c, 0xf7, 0x10, 0x12, 0x0c, 0x04, 0x15, + 0x00, + /* ch = '#' */ + 0x00, 0x00, 0xbd, 0x1f, 0x32, 0x42, 0x00, 0x00, 0x04, 0xff, 0x1c, 0x7c, + 0x54, 0x00, 0x28, 0x4a, 0xff, 0x39, 0xc8, 0x78, 0x26, 0x2d, 0x62, 0xbd, + 0x15, 0xd9, 0x3a, 0x12, 0x00, 0x3b, 0xa7, 0x00, 0xff, 0x1f, 0x00, 0x1a, + 0x82, 0xab, 0x4a, 0xff, 0x39, 0x16, 0x36, 0xa5, 0x82, 0x58, 0xcf, 0x15, + 0x0c, 0x00, 0xa0, 0x3f, 0x35, 0xb7, 0x00, 0x00, 0x00, 0xa9, 0x2a, 0x45, + 0x6c, 0x00, 0x00, + /* ch = '$' */ + 0x00, 0x00, 0x00, 0x15, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x28, + 0x00, 0x00, 0x00, 0x77, 0xbb, 0xff, 0xd4, 0xb1, 0x0d, 0x1c, 0xff, 0x10, + 0xff, 0x1f, 0x40, 0x04, 0x0d, 0xf7, 0x64, 0xff, 0x1f, 0x00, 0x00, 0x00, + 0x1b, 0xab, 0xff, 0x8b, 0x1b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x77, 0xff, + 0x1c, 0x00, 0x0c, 0x00, 0xff, 0x1f, 0xb7, 0x44, 0x2d, 0xc8, 0x1e, 0xff, + 0x59, 0xf7, 0x1f, 0x00, 0x37, 0xab, 0xff, 0xa4, 0x1e, 0x00, 0x00, 0x00, + 0x00, 0x74, 0x17, 0x00, 0x00, + /* ch = '%' */ + 0x2c, 0xc6, 0x9c, 0x0d, 0x0d, 0xbd, 0x22, 0xb7, 0x35, 0x97, 0x50, 0x5f, + 0x90, 0x04, 0xb7, 0x43, 0xa7, 0x65, 0xf7, 0x1f, 0x00, 0x26, 0xbd, 0x7f, + 0x88, 0x70, 0x00, 0x00, 0x00, 0x00, 0x24, 0xf7, 0x13, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x54, 0x30, 0x30, 0x04, 0x00, 0x32, 0xdb, 0x59, 0x90, 0x82, + 0x5f, 0x04, 0xc8, 0x3f, 0x7c, 0x54, 0x50, 0x90, 0x3b, 0xb7, 0x04, 0x2f, + 0xdb, 0xdb, 0x35, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0f, 0x00, + /* ch = '&' */ + 0x00, 0x26, 0xbd, 0xbd, 0x26, 0x00, 0x00, 0x00, 0xe5, 0x46, 0x37, 0xff, + 0x00, 0x00, 0x00, 0xf7, 0x37, 0x24, 0xf7, 0x04, 0x00, 0x00, 0x5f, 0xbd, + 0xb1, 0x54, 0x00, 0x00, 0x00, 0x54, 0xff, 0xa4, 0x04, 0x00, 0x00, 0x3b, + 0xf7, 0x26, 0xf7, 0x35, 0x70, 0x40, 0xa0, 0x7c, 0x00, 0x32, 0xff, 0xf7, + 0x21, 0xa0, 0x9e, 0x00, 0x13, 0xec, 0xc6, 0x04, 0x1f, 0xef, 0xe5, 0xef, + 0x48, 0xdb, 0x52, 0x00, 0x04, 0x15, 0x04, 0x00, 0x0c, 0x04, + /* ch = ''' */ + 0x00, 0x2a, 0x08, 0x0a, 0xff, 0x50, 0x04, 0xff, 0x2c, 0x2a, 0xe5, 0x04, + 0x0c, 0x12, 0x00, + /* ch = '(' */ + 0x00, 0x08, 0x21, 0x21, 0xdb, 0x6d, 0xf7, 0x3f, 0x00, 0x82, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x2f, 0x00, 0x00, 0xa7, 0x00, 0x00, 0xdb, 0x54, 0x00, 0x1f, 0xdb, 0x77, + 0x00, 0x08, 0x22, + /* ch = ')' */ + 0x00, 0x21, 0x00, 0x00, 0x14, 0xef, 0x70, 0x04, 0x00, 0x13, 0xdb, 0x82, + 0x00, 0x00, 0x1f, 0xf7, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x35, + 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x10, 0xf7, 0x00, 0x08, 0xb1, 0x7c, 0x1a, 0xd4, 0x84, 0x08, + 0x0d, 0x25, 0x00, 0x00, + /* ch = '*' */ + 0x00, 0x00, 0x08, 0x15, 0x04, 0x00, 0x00, 0x00, 0x00, 0x2f, 0xff, 0x04, + 0x00, 0x00, 0x51, 0x73, 0x28, 0xbd, 0x20, 0x9e, 0x22, 0x12, 0x47, 0xc4, + 0xff, 0x95, 0x2a, 0x0c, 0x00, 0x10, 0xdb, 0xbb, 0x82, 0x00, 0x00, 0x04, + 0xb1, 0x7c, 0x0d, 0xdb, 0x54, 0x00, 0x00, 0x3d, 0x08, 0x00, 0x2a, 0x21, + 0x00, + /* ch = '+' */ + 0x00, 0x00, 0x0d, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x04, 0x00, 0x00, 0x7c, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x35, 0x00, 0x00, 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x14, 0x74, 0x04, 0x00, + 0x00, + /* ch = ',' */ + 0x21, 0x2a, 0x00, 0x99, 0xff, 0x24, 0x1f, 0xff, 0x17, 0x7c, 0x54, 0x00, + 0x22, 0x04, 0x00, + /* ch = '-' */ + /* ch = '.' */ + 0x21, 0x30, 0x00, 0xa0, 0xff, 0x17, 0x08, 0x12, 0x00, + /* ch = '/' */ + 0x0d, 0x1b, 0x00, 0x44, 0xe5, 0x08, 0xc8, 0x4c, 0x00, 0xe5, 0x10, 0x00, + 0x5f, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = '0' */ + 0x00, 0x08, 0x7f, 0xcf, 0x48, 0x00, 0x00, 0x00, 0xa0, 0x7c, 0x1a, 0xdb, + 0x50, 0x00, 0x2a, 0xe5, 0x08, 0x00, 0x82, 0xec, 0x00, 0x50, 0x88, 0x00, + 0x50, 0xdb, 0xff, 0x1f, 0x7c, 0x82, 0x1f, 0xef, 0x21, 0xff, 0x35, 0x5f, + 0x9e, 0xdb, 0x35, 0x00, 0xff, 0x26, 0x3b, 0xff, 0x64, 0x00, 0x1c, 0xff, + 0x17, 0x0d, 0xe5, 0x3f, 0x00, 0x64, 0x90, 0x00, 0x00, 0x2c, 0xef, 0xdd, + 0xd4, 0x13, 0x00, 0x00, 0x00, 0x04, 0x15, 0x04, 0x00, 0x00, + /* ch = '1' */ + 0x00, 0x00, 0x37, 0xbd, 0x1a, 0x0a, 0xbd, 0xb3, 0xff, 0x1f, 0x00, 0x00, + 0x1c, 0xff, 0x1f, 0x00, 0x00, 0x1c, 0xff, 0x1f, 0x00, 0x00, 0x1c, 0xff, + 0x1f, 0x00, 0x00, 0x1c, 0xff, 0x1f, 0x00, 0x00, 0x1c, 0xff, 0x1f, 0x00, + 0x00, 0x1c, 0xff, 0x1f, 0x00, 0x00, 0x1c, 0xff, 0x1f, + /* ch = '2' */ + 0x00, 0x1b, 0x9e, 0xcf, 0x66, 0x08, 0x00, 0x11, 0xe5, 0x37, 0x1a, 0xb1, + 0x97, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x2c, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x3f, 0xdb, 0x04, 0x00, 0x00, 0x00, 0x1f, 0xf7, 0x35, 0x00, 0x00, + 0x00, 0x1f, 0xef, 0x48, 0x00, 0x00, 0x00, 0x17, 0xdb, 0x3f, 0x00, 0x00, + 0x00, 0x00, 0xa0, 0x64, 0x00, 0x00, 0x00, 0x00, 0x2f, 0xff, 0xdd, 0xcf, + 0xcf, 0xdd, 0x1f, + /* ch = '3' */ + 0x00, 0x28, 0x9e, 0xbd, 0x48, 0x00, 0x00, 0x8d, 0x2b, 0x20, 0xdb, 0x50, + 0x00, 0x00, 0x00, 0x00, 0x50, 0x92, 0x00, 0x00, 0x00, 0x13, 0xdb, 0x48, + 0x00, 0x00, 0x95, 0xf7, 0xa4, 0x04, 0x00, 0x00, 0x00, 0x04, 0x82, 0x82, + 0x00, 0x00, 0x00, 0x00, 0x32, 0xf7, 0x04, 0x73, 0x04, 0x00, 0x82, 0xa7, + 0x10, 0xbb, 0xef, 0xdd, 0xd4, 0x21, 0x00, 0x00, 0x0c, 0x15, 0x00, 0x00, + /* ch = '4' */ + 0x00, 0x00, 0x00, 0x17, 0xcf, 0x1a, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xff, + 0x1f, 0x00, 0x00, 0x00, 0x44, 0xdb, 0xff, 0x1f, 0x00, 0x00, 0x17, 0xef, + 0x2f, 0xff, 0x1f, 0x00, 0x00, 0xa0, 0x48, 0x1c, 0xff, 0x1f, 0x00, 0x44, + 0xc6, 0x17, 0x28, 0xff, 0x2a, 0x08, 0x42, 0x74, 0x74, 0x87, 0xff, 0x87, + 0x24, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x1c, + 0xff, 0x1f, 0x00, + /* ch = '5' */ + 0x00, 0x95, 0xcf, 0xcf, 0xcf, 0x95, 0x00, 0x00, 0xf7, 0x3e, 0x15, 0x15, + 0x15, 0x00, 0x00, 0xff, 0x21, 0x00, 0x00, 0x00, 0x00, 0x04, 0xff, 0x7e, + 0x74, 0x50, 0x04, 0x00, 0x1a, 0xe5, 0x37, 0x1a, 0xb1, 0xa7, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x24, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, + 0x1f, 0x19, 0x9c, 0x08, 0x00, 0x50, 0xe5, 0x08, 0x04, 0x8d, 0xf7, 0xcf, + 0xef, 0x2f, 0x00, 0x00, 0x00, 0x08, 0x15, 0x04, 0x00, 0x00, + /* ch = '6' */ + 0x00, 0x04, 0x50, 0xcf, 0xbd, 0x37, 0x00, 0x00, 0x6b, 0xb1, 0x18, 0x2e, + 0x50, 0x00, 0x0d, 0xf7, 0x26, 0x00, 0x00, 0x00, 0x00, 0x2f, 0xff, 0x3a, + 0x74, 0x48, 0x04, 0x00, 0x32, 0xff, 0x99, 0x25, 0xb1, 0x7c, 0x00, 0x32, + 0xff, 0x08, 0x00, 0x24, 0xff, 0x10, 0x2a, 0xff, 0x08, 0x00, 0x1c, 0xff, + 0x1f, 0x04, 0xe5, 0x4c, 0x00, 0x3f, 0xdb, 0x04, 0x00, 0x2c, 0xef, 0xd4, + 0xef, 0x28, 0x00, 0x00, 0x00, 0x00, 0x15, 0x08, 0x00, 0x00, + /* ch = '7' */ + 0x1a, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x00, 0x04, 0x15, 0x15, 0x15, 0x82, + 0xa7, 0x04, 0x00, 0x00, 0x00, 0x0d, 0xf7, 0x35, 0x00, 0x00, 0x00, 0x00, + 0x48, 0xe5, 0x08, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x5f, 0x00, 0x00, 0x00, + 0x00, 0x22, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xb7, 0x04, 0x00, + 0x00, 0x00, 0x00, 0xe5, 0x54, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xff, 0x1f, + 0x00, 0x00, 0x00, + /* ch = '8' */ + 0x00, 0x19, 0x9e, 0xcf, 0x7f, 0x10, 0x00, 0x00, 0xc8, 0x59, 0x08, 0x90, + 0x90, 0x00, 0x00, 0xff, 0x26, 0x00, 0x48, 0xbd, 0x00, 0x00, 0x77, 0xc8, + 0x20, 0xdb, 0x48, 0x00, 0x00, 0x1b, 0xec, 0xef, 0xb5, 0x08, 0x00, 0x10, + 0xef, 0x35, 0x04, 0x8a, 0xb7, 0x00, 0x4d, 0xbd, 0x04, 0x00, 0x1f, 0xff, + 0x1c, 0x39, 0xff, 0x1a, 0x00, 0x3f, 0xf7, 0x10, 0x00, 0x66, 0xff, 0xcf, + 0xef, 0x2f, 0x00, 0x00, 0x00, 0x08, 0x15, 0x04, 0x00, 0x00, + /* ch = '9' */ + 0x00, 0x19, 0x9e, 0xcf, 0x50, 0x04, 0x00, 0x04, 0xdb, 0x54, 0x1a, 0xb7, + 0x5f, 0x00, 0x2f, 0xff, 0x08, 0x00, 0x35, 0xec, 0x00, 0x32, 0xff, 0x00, + 0x00, 0x1c, 0xff, 0x10, 0x0d, 0xf7, 0x46, 0x08, 0x8a, 0xff, 0x1f, 0x00, + 0x26, 0xab, 0xcf, 0x70, 0xff, 0x10, 0x00, 0x00, 0x00, 0x00, 0x3b, 0xe5, + 0x04, 0x00, 0x22, 0x00, 0x04, 0xb1, 0x64, 0x00, 0x09, 0xcb, 0xe5, 0xe5, + 0x94, 0x08, 0x00, 0x00, 0x00, 0x12, 0x0f, 0x00, 0x00, 0x00, + /* ch = ':' */ + 0x73, 0xdb, 0x0d, 0x3d, 0x67, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x30, 0x00, 0xa0, 0xff, 0x17, 0x08, 0x12, 0x00, + /* ch = ';' */ + 0x73, 0xdb, 0x0d, 0x3d, 0x67, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x2a, 0x00, 0x99, 0xff, 0x24, 0x1f, 0xff, 0x17, 0x7c, 0x54, 0x00, + 0x22, 0x04, 0x00, + /* ch = '<' */ + 0x00, 0x00, 0x13, 0x7f, 0x37, 0x0c, 0x73, 0xef, 0x5a, 0x0c, 0xef, 0x5a, + 0x0c, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xef, 0x37, 0x00, 0x00, + 0x00, 0x1b, 0xbb, 0xc4, 0x1e, 0x00, 0x00, 0x00, 0x37, 0xef, 0x4d, 0x00, + 0x00, 0x00, 0x08, 0x21, + /* ch = '=' */ + 0x0f, 0x15, 0x15, 0x15, 0x15, 0x15, 0x08, 0x67, 0xcf, 0xcf, 0xcf, 0xcf, + 0xcf, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x08, 0x42, 0x74, 0x74, 0x74, 0x74, 0x74, 0x24, + /* ch = '>' */ + 0x7c, 0x48, 0x04, 0x00, 0x00, 0x1b, 0x8d, 0xef, 0x37, 0x04, 0x00, 0x00, + 0x1b, 0x94, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x08, 0x73, + 0xe5, 0x04, 0x37, 0xef, 0x73, 0x0c, 0xa9, 0xbb, 0x1e, 0x00, 0x00, 0x22, + 0x04, 0x00, 0x00, 0x00, + /* ch = '?' */ + 0x00, 0x00, 0x12, 0x2a, 0x0f, 0x00, 0x04, 0xa9, 0xe5, 0x8f, 0xff, 0x50, + 0x19, 0x8d, 0x08, 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x48, 0xff, + 0x00, 0x00, 0x00, 0x10, 0xdb, 0x7c, 0x00, 0x00, 0x00, 0xb1, 0x7c, 0x04, + 0x00, 0x00, 0x1c, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x0d, 0x36, 0x10, 0x00, + 0x00, 0x00, 0x10, 0x36, 0x08, 0x00, 0x00, 0x00, 0x4d, 0xff, 0x48, 0x00, + 0x00, 0x00, 0x00, 0x15, 0x04, 0x00, + /* ch = '@' */ + 0x00, 0x13, 0x7f, 0xcf, 0xab, 0x21, 0x00, 0x10, 0xdb, 0x37, 0x00, 0x28, + 0xff, 0x10, 0x5a, 0x75, 0x00, 0x04, 0x15, 0x9e, 0x48, 0xb1, 0x37, 0x2c, + 0xe5, 0x82, 0xa5, 0x54, 0xb7, 0x2e, 0xb1, 0x3f, 0x00, 0x7c, 0x54, 0xb7, + 0x35, 0x99, 0x82, 0x20, 0xe5, 0x54, 0x6b, 0x75, 0x10, 0x67, 0x74, 0x5b, + 0x32, 0x1c, 0xf7, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0xd4, 0xb3, + 0xab, 0xd4, 0x0a, 0x00, 0x00, 0x00, 0x12, 0x12, 0x00, 0x00, + /* ch = 'A' */ + 0x00, 0x00, 0x1c, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0xec, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc8, 0xff, 0x2f, 0x00, 0x00, 0x00, 0x22, 0xe5, + 0x68, 0x90, 0x00, 0x00, 0x00, 0x5f, 0x70, 0x22, 0xff, 0x0d, 0x00, 0x00, + 0xcf, 0x67, 0x36, 0xd9, 0x4c, 0x00, 0x2a, 0xf7, 0x36, 0x36, 0x7b, 0xaf, + 0x00, 0x6b, 0x82, 0x00, 0x00, 0x17, 0xff, 0x24, 0xe5, 0x35, 0x00, 0x00, + 0x00, 0xa7, 0x68, + /* ch = 'B' */ + 0x67, 0xcf, 0xcf, 0xab, 0x5b, 0x08, 0x00, 0x7c, 0x88, 0x15, 0x1a, 0xa0, + 0xa7, 0x00, 0x7c, 0x82, 0x00, 0x00, 0x32, 0xff, 0x04, 0x7c, 0x8f, 0x15, + 0x1a, 0xa0, 0x7c, 0x04, 0x7c, 0xef, 0xcf, 0xcf, 0xec, 0x2b, 0x00, 0x7c, + 0x82, 0x00, 0x00, 0x32, 0xff, 0x17, 0x7c, 0x82, 0x00, 0x00, 0x00, 0xff, + 0x35, 0x7c, 0x82, 0x00, 0x00, 0x37, 0xff, 0x24, 0x7c, 0xf7, 0xcf, 0xdd, + 0xdd, 0x37, 0x00, + /* ch = 'C' */ + 0x00, 0x10, 0x66, 0xcf, 0xab, 0x26, 0x00, 0x04, 0xb1, 0x77, 0x0c, 0x28, + 0xf7, 0x32, 0x40, 0xcf, 0x08, 0x00, 0x00, 0x28, 0x08, 0x77, 0x7c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa0, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, + 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x17, 0xf7, 0x3a, 0x00, 0x08, 0x8d, 0x22, 0x00, 0x2c, 0xef, 0xdd, + 0xef, 0x7e, 0x08, 0x00, 0x00, 0x00, 0x15, 0x08, 0x00, 0x00, + /* ch = 'D' */ + 0x67, 0xcf, 0xcf, 0x82, 0x37, 0x00, 0x00, 0x7c, 0x88, 0x15, 0x2b, 0xdb, + 0x70, 0x00, 0x7c, 0x82, 0x00, 0x00, 0x2c, 0xff, 0x17, 0x7c, 0x82, 0x00, + 0x00, 0x04, 0xff, 0x35, 0x7c, 0x82, 0x00, 0x00, 0x00, 0xbd, 0x48, 0x7c, + 0x82, 0x00, 0x00, 0x00, 0xe5, 0x37, 0x7c, 0x82, 0x00, 0x00, 0x17, 0xff, + 0x1f, 0x7c, 0x82, 0x00, 0x04, 0xa0, 0x90, 0x04, 0x7c, 0xf7, 0xcf, 0xe5, + 0x8d, 0x0c, 0x00, + /* ch = 'E' */ + 0x45, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x1a, 0x50, 0xbd, 0x15, 0x15, 0x15, + 0x15, 0x08, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x50, 0xf7, 0xcf, 0xcf, 0xcf, 0x2f, 0x00, 0x50, + 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0xcf, 0xcf, + 0xcf, 0xcf, 0x1a, + /* ch = 'F' */ + 0x1a, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x1a, 0x1c, 0xff, 0x15, 0x15, 0x15, + 0x15, 0x08, 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x17, + 0x15, 0x15, 0x08, 0x00, 0x1c, 0xff, 0xcf, 0xcf, 0xcf, 0x2f, 0x00, 0x1c, + 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x04, 0x00, + 0x00, 0x00, 0x00, + /* ch = 'G' */ + 0x00, 0x10, 0x73, 0xcf, 0xab, 0x28, 0x00, 0x0d, 0xdb, 0x77, 0x12, 0x31, + 0xf7, 0x27, 0x48, 0xa7, 0x04, 0x00, 0x00, 0x22, 0x04, 0x90, 0x59, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb7, 0x54, 0x00, 0x08, 0x15, 0x15, 0x0c, 0xb1, + 0x59, 0x00, 0x22, 0x74, 0xe5, 0x54, 0x6b, 0xa7, 0x00, 0x00, 0x00, 0xb7, + 0x54, 0x1c, 0xff, 0x37, 0x00, 0x00, 0xbd, 0x54, 0x00, 0x2f, 0xef, 0xdd, + 0xe5, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x12, 0x08, 0x00, 0x00, + /* ch = 'H' */ + 0x45, 0x95, 0x00, 0x00, 0x1a, 0xcf, 0x1f, 0x50, 0xbd, 0x00, 0x00, 0x1c, + 0xff, 0x1f, 0x50, 0xbd, 0x00, 0x00, 0x1c, 0xff, 0x1f, 0x50, 0xbd, 0x00, + 0x00, 0x1c, 0xff, 0x1f, 0x50, 0xf7, 0xcf, 0xcf, 0xd4, 0xff, 0x1f, 0x50, + 0xbd, 0x00, 0x00, 0x1c, 0xff, 0x1f, 0x50, 0xbd, 0x00, 0x00, 0x1c, 0xff, + 0x1f, 0x50, 0xbd, 0x00, 0x00, 0x1c, 0xff, 0x1f, 0x50, 0xbd, 0x00, 0x00, + 0x1c, 0xff, 0x1f, + /* ch = 'I' */ + 0x1a, 0xcf, 0xcf, 0xcf, 0xcf, 0x45, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, + 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, + 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, + 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, + 0x1a, 0xcf, 0xe5, 0xff, 0xcf, 0x67, + /* ch = 'J' */ + 0x00, 0x00, 0xcf, 0xcf, 0xcf, 0xcf, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x04, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x04, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x04, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x04, + 0x00, 0x00, 0x00, 0x2f, 0xff, 0x04, 0x17, 0x2c, 0x00, 0x48, 0xc8, 0x04, + 0x2c, 0xef, 0xd4, 0xf7, 0x2f, 0x00, 0x00, 0x04, 0x15, 0x08, 0x00, 0x00, + /* ch = 'K' */ + 0x67, 0x73, 0x00, 0x00, 0x32, 0xc6, 0x17, 0x7c, 0x82, 0x00, 0x1f, 0xf7, + 0x35, 0x00, 0x7c, 0x82, 0x1f, 0xef, 0x48, 0x00, 0x00, 0x7c, 0x9e, 0xdb, + 0x54, 0x00, 0x00, 0x00, 0x7c, 0xff, 0xf7, 0x37, 0x00, 0x00, 0x00, 0x7c, + 0x88, 0x44, 0xff, 0x17, 0x00, 0x00, 0x7c, 0x82, 0x00, 0x90, 0xb7, 0x04, + 0x00, 0x7c, 0x82, 0x00, 0x10, 0xe5, 0x54, 0x00, 0x7c, 0x82, 0x00, 0x00, + 0x35, 0xff, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, + /* ch = 'L' */ + 0x2d, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x32, + 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0xd4, 0xcf, + 0xcf, 0xcf, 0x1a, + /* ch = 'M' */ + 0x95, 0x40, 0x00, 0x00, 0x00, 0x8d, 0x45, 0xb7, 0xec, 0x04, 0x00, 0x2a, + 0xff, 0x54, 0xb7, 0xff, 0x4c, 0x00, 0xa0, 0xff, 0x54, 0xb7, 0xb7, 0xec, + 0x2f, 0xdb, 0xbd, 0x54, 0xb7, 0x54, 0xa7, 0xff, 0x3f, 0xb7, 0x54, 0xb7, + 0x54, 0x2c, 0xb7, 0x04, 0xb7, 0x54, 0xb7, 0x54, 0x00, 0x00, 0x00, 0xb7, + 0x54, 0xb7, 0x54, 0x00, 0x00, 0x00, 0xb7, 0x54, 0xb7, 0x54, 0x00, 0x00, + 0x00, 0xb7, 0x54, + /* ch = 'N' */ + 0x67, 0x8d, 0x00, 0x00, 0x00, 0xcf, 0x2d, 0x7c, 0xff, 0x35, 0x00, 0x00, + 0xff, 0x35, 0x7c, 0xff, 0xcf, 0x04, 0x00, 0xff, 0x35, 0x7c, 0x88, 0xdb, + 0x54, 0x00, 0xff, 0x35, 0x7c, 0x82, 0x3b, 0xff, 0x10, 0xff, 0x35, 0x7c, + 0x82, 0x00, 0xb7, 0x70, 0xff, 0x35, 0x7c, 0x82, 0x00, 0x2a, 0xff, 0xff, + 0x35, 0x7c, 0x82, 0x00, 0x00, 0x7c, 0xff, 0x35, 0x7c, 0x82, 0x00, 0x00, + 0x17, 0xf7, 0x35, + /* ch = 'O' */ + 0x00, 0x1b, 0x9e, 0xcf, 0x7f, 0x10, 0x00, 0x1c, 0xf7, 0x48, 0x1a, 0x99, + 0xb7, 0x04, 0x6b, 0x90, 0x04, 0x00, 0x10, 0xff, 0x2f, 0xb7, 0x50, 0x00, + 0x00, 0x00, 0xb7, 0x54, 0xc8, 0x35, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0xb7, + 0x50, 0x00, 0x00, 0x00, 0x90, 0x59, 0x7c, 0x82, 0x00, 0x00, 0x00, 0xe5, + 0x3f, 0x2a, 0xff, 0x24, 0x00, 0x50, 0xe5, 0x10, 0x00, 0x44, 0xf7, 0xef, + 0xe5, 0x28, 0x00, 0x00, 0x00, 0x04, 0x15, 0x00, 0x00, 0x00, + /* ch = 'P' */ + 0x45, 0xcf, 0xcf, 0xcf, 0x74, 0x19, 0x00, 0x50, 0xbd, 0x15, 0x15, 0x77, + 0xff, 0x0d, 0x50, 0xbd, 0x00, 0x00, 0x04, 0xff, 0x35, 0x50, 0xbd, 0x00, + 0x00, 0x1f, 0xff, 0x2c, 0x50, 0xff, 0xcf, 0xcf, 0xef, 0x66, 0x04, 0x50, + 0xbd, 0x15, 0x15, 0x0c, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, + 0x00, 0x00, 0x00, + /* ch = 'Q' */ + 0x00, 0x1b, 0x9e, 0xcf, 0x7f, 0x10, 0x00, 0x1c, 0xf7, 0x3f, 0x15, 0x8a, + 0xb7, 0x04, 0x6b, 0x90, 0x00, 0x00, 0x0d, 0xf7, 0x2f, 0xb7, 0x48, 0x00, + 0x00, 0x00, 0xa0, 0x54, 0xc8, 0x35, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0xb7, + 0x48, 0x00, 0x00, 0x00, 0x82, 0x59, 0x7c, 0x82, 0x00, 0x00, 0x00, 0xcf, + 0x3f, 0x2a, 0xff, 0x21, 0x00, 0x37, 0xf7, 0x10, 0x00, 0x44, 0xf7, 0xdd, + 0xef, 0x2f, 0x00, 0x00, 0x00, 0x1a, 0xff, 0x13, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x85, 0xf7, 0xe5, 0x1f, + /* ch = 'R' */ + 0x45, 0xcf, 0xcf, 0xbd, 0x67, 0x13, 0x00, 0x50, 0xbd, 0x15, 0x1a, 0x8a, + 0xe5, 0x04, 0x50, 0xbd, 0x00, 0x00, 0x1c, 0xff, 0x24, 0x50, 0xbd, 0x00, + 0x00, 0x2c, 0xff, 0x17, 0x50, 0xff, 0xcf, 0xcf, 0xf7, 0x50, 0x00, 0x50, + 0xbd, 0x15, 0x90, 0x82, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x22, 0xff, 0x24, + 0x00, 0x50, 0xbd, 0x00, 0x00, 0x8a, 0x97, 0x00, 0x50, 0xbd, 0x00, 0x00, + 0x1c, 0xff, 0x26, + /* ch = 'S' */ + 0x00, 0x1b, 0x8f, 0xcf, 0x8f, 0x1b, 0x00, 0x0d, 0xf7, 0x43, 0x0c, 0x3f, + 0xdb, 0x09, 0x32, 0xff, 0x10, 0x00, 0x00, 0x0f, 0x00, 0x0d, 0xdb, 0x90, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x13, 0x7f, 0xff, 0x94, 0x13, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x77, 0xe5, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x35, 0x32, 0x75, 0x04, 0x00, 0x26, 0xff, 0x24, 0x1b, 0xbb, 0xf7, 0xcf, + 0xf7, 0x48, 0x00, 0x00, 0x00, 0x08, 0x15, 0x04, 0x00, 0x00, + /* ch = 'T' */ + 0x95, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x45, 0x12, 0x15, 0x5e, 0xbd, 0x15, + 0x15, 0x0f, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, + 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, + 0x00, 0x00, 0x00, + /* ch = 'U' */ + 0x67, 0x73, 0x00, 0x00, 0x00, 0x95, 0x2d, 0x7c, 0x82, 0x00, 0x00, 0x00, + 0xb7, 0x35, 0x7c, 0x82, 0x00, 0x00, 0x00, 0xb7, 0x35, 0x7c, 0x82, 0x00, + 0x00, 0x00, 0xb7, 0x35, 0x7c, 0x82, 0x00, 0x00, 0x00, 0xb7, 0x35, 0x7c, + 0x82, 0x00, 0x00, 0x00, 0xb7, 0x35, 0x7c, 0x82, 0x00, 0x00, 0x00, 0xf7, + 0x35, 0x40, 0xec, 0x10, 0x00, 0x2c, 0xff, 0x1a, 0x00, 0x73, 0xf7, 0xcf, + 0xe5, 0x3f, 0x00, 0x00, 0x00, 0x08, 0x15, 0x04, 0x00, 0x00, + /* ch = 'V' */ + 0xa4, 0x40, 0x00, 0x00, 0x00, 0x6c, 0x58, 0x5f, 0xaf, 0x00, 0x00, 0x04, + 0xf7, 0x2f, 0x24, 0xff, 0x1a, 0x00, 0x2c, 0xe5, 0x08, 0x00, 0xcf, 0x4c, + 0x00, 0x70, 0x75, 0x00, 0x00, 0x5a, 0xaf, 0x00, 0xe5, 0x2f, 0x00, 0x00, + 0x22, 0xff, 0x40, 0xe5, 0x08, 0x00, 0x00, 0x00, 0xc8, 0xec, 0x75, 0x00, + 0x00, 0x00, 0x00, 0x5a, 0xff, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x22, 0xe5, + 0x08, 0x00, 0x00, + /* ch = 'W' */ + 0xcf, 0x1a, 0x00, 0x00, 0x00, 0x2d, 0x8f, 0xcf, 0x35, 0x04, 0xe5, 0x00, + 0x50, 0x7c, 0x90, 0x54, 0x2a, 0xff, 0x26, 0x77, 0x50, 0x5f, 0x82, 0x5f, + 0xff, 0x54, 0xa0, 0x35, 0x44, 0xbd, 0xa0, 0x82, 0xa7, 0xcf, 0x1f, 0x2a, + 0xff, 0xf7, 0x24, 0xff, 0xff, 0x04, 0x14, 0xff, 0x97, 0x00, 0xe5, 0xbd, + 0x00, 0x00, 0xe5, 0x48, 0x00, 0x7c, 0x88, 0x00, 0x00, 0xa0, 0x21, 0x00, + 0x3b, 0x59, 0x00, + /* ch = 'X' */ + 0x53, 0x8d, 0x00, 0x00, 0x1c, 0xcf, 0x17, 0x10, 0xf7, 0x35, 0x00, 0x90, + 0x75, 0x00, 0x00, 0x50, 0xcf, 0x26, 0xff, 0x1a, 0x00, 0x00, 0x04, 0xdb, + 0xf7, 0x70, 0x00, 0x00, 0x00, 0x00, 0x4a, 0xff, 0x24, 0x00, 0x00, 0x00, + 0x04, 0xc8, 0xff, 0x70, 0x00, 0x00, 0x00, 0x44, 0xe5, 0x35, 0xff, 0x1f, + 0x00, 0x04, 0xdb, 0x48, 0x00, 0x90, 0x97, 0x00, 0x54, 0xc8, 0x08, 0x00, + 0x1c, 0xff, 0x2c, + /* ch = 'Y' */ + 0x8f, 0x60, 0x00, 0x00, 0x00, 0xab, 0x4a, 0x2c, 0xff, 0x1a, 0x00, 0x2c, + 0xf7, 0x10, 0x00, 0xa7, 0x75, 0x00, 0xa7, 0x64, 0x00, 0x00, 0x2c, 0xff, + 0x35, 0xff, 0x1a, 0x00, 0x00, 0x00, 0xa7, 0xff, 0x75, 0x00, 0x00, 0x00, + 0x00, 0x35, 0xff, 0x26, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1f, 0x00, + 0x00, 0x00, 0x00, 0x32, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, + 0x1f, 0x00, 0x00, + /* ch = 'Z' */ + 0x45, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x2a, 0x0c, 0x15, 0x15, 0x15, 0x58, + 0xdb, 0x08, 0x00, 0x00, 0x00, 0x10, 0xf7, 0x32, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x90, 0x04, 0x00, 0x00, 0x00, 0x2a, 0xf7, 0x1a, 0x00, 0x00, 0x00, + 0x04, 0xc8, 0x59, 0x00, 0x00, 0x00, 0x00, 0x54, 0xdb, 0x08, 0x00, 0x00, + 0x00, 0x17, 0xf7, 0x32, 0x00, 0x00, 0x00, 0x00, 0x77, 0xff, 0xd4, 0xcf, + 0xcf, 0xd4, 0x54, + /* ch = '[' */ + 0x1e, 0x36, 0x36, 0x36, 0x2d, 0x50, 0xa5, 0x36, 0x36, 0x30, 0x50, 0x82, + 0x00, 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, + 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, 0x50, + 0x82, 0x00, 0x00, 0x00, 0x50, 0x82, 0x00, 0x00, 0x00, 0x50, 0x82, 0x00, + 0x00, 0x00, 0x50, 0xd1, 0x74, 0x74, 0x58, 0x0c, 0x15, 0x15, 0x15, 0x15, + /* ch = '\' */ + 0x00, 0x22, 0x00, 0x2a, 0xff, 0x17, 0x00, 0xa7, 0x5f, 0x00, 0x32, 0xff, + 0x00, 0x00, 0xc8, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = ']' */ + 0x0d, 0x36, 0x36, 0x36, 0x36, 0x0d, 0x0d, 0x36, 0x36, 0x36, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, + 0x14, 0x74, 0x74, 0x74, 0xff, 0x1f, 0x04, 0x15, 0x15, 0x15, 0x15, 0x08, + /* ch = '^' */ + 0x00, 0x10, 0x9c, 0x00, 0x00, 0x00, 0x6b, 0xff, 0x3f, 0x00, 0x24, 0xf7, + 0x4a, 0xe5, 0x04, 0xb1, 0x48, 0x00, 0xb7, 0x48, 0x0c, 0x04, 0x00, 0x0c, + 0x08, + /* ch = '_' */ + 0x95, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x45, 0x12, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x0f, + /* ch = '`' */ + 0x08, 0x22, 0x00, 0x22, 0xff, 0x0d, 0x00, 0xa7, 0x90, 0x00, 0x2f, 0xef, + /* ch = 'a' */ + 0x00, 0x0c, 0x3e, 0x74, 0x30, 0x04, 0x00, 0x00, 0xcb, 0x5a, 0x36, 0xa0, + 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0xff, 0x04, 0x00, 0x28, 0x82, + 0xcf, 0xd4, 0xff, 0x1f, 0x36, 0xe5, 0x20, 0x00, 0x1c, 0xff, 0x1f, 0x77, + 0x9e, 0x00, 0x00, 0x59, 0xff, 0x1f, 0x1f, 0xef, 0xab, 0xb3, 0xbb, 0xff, + 0x1f, 0x00, 0x00, 0x15, 0x0f, 0x00, 0x00, 0x00, + /* ch = 'b' */ + 0x1e, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbd, 0x22, + 0x67, 0x3f, 0x04, 0x00, 0x50, 0xff, 0x94, 0x3e, 0xdb, 0xa7, 0x00, 0x50, + 0xf7, 0x08, 0x00, 0x26, 0xff, 0x26, 0x50, 0xbd, 0x00, 0x00, 0x00, 0xff, + 0x35, 0x50, 0xbd, 0x00, 0x00, 0x04, 0xff, 0x35, 0x50, 0xff, 0x1c, 0x00, + 0x3f, 0xf7, 0x10, 0x50, 0xb1, 0xef, 0xd4, 0xf7, 0x35, 0x00, 0x00, 0x00, + 0x00, 0x15, 0x08, 0x00, 0x00, + /* ch = 'c' */ + 0x00, 0x00, 0x25, 0x5b, 0x3e, 0x13, 0x00, 0x00, 0x7c, 0xc4, 0x3e, 0x5a, + 0xff, 0x1a, 0x2c, 0xff, 0x1a, 0x00, 0x00, 0x22, 0x04, 0x50, 0xbd, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4d, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, + 0xf7, 0x54, 0x00, 0x04, 0x40, 0x04, 0x00, 0x2c, 0xef, 0xe5, 0xe5, 0x94, + 0x13, 0x00, 0x00, 0x00, 0x15, 0x0f, 0x00, 0x00, + /* ch = 'd' */ + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x36, 0x13, 0x00, 0x00, 0x00, 0x00, 0x1c, + 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, 0x00, 0x13, 0x50, + 0x67, 0x31, 0xff, 0x1f, 0x10, 0xdb, 0x6a, 0x31, 0xdb, 0xff, 0x1f, 0x5a, + 0xa7, 0x04, 0x00, 0x3b, 0xff, 0x1f, 0x7c, 0x82, 0x00, 0x00, 0x1c, 0xff, + 0x1f, 0x77, 0x88, 0x00, 0x00, 0x24, 0xff, 0x1f, 0x39, 0xff, 0x1a, 0x00, + 0x6f, 0xff, 0x1f, 0x00, 0x84, 0xff, 0xdd, 0xa9, 0xff, 0x1f, 0x00, 0x00, + 0x0c, 0x0f, 0x00, 0x00, 0x00, + /* ch = 'e' */ + 0x00, 0x08, 0x3f, 0x74, 0x37, 0x04, 0x00, 0x04, 0xd4, 0x77, 0x25, 0xb1, + 0x7c, 0x00, 0x44, 0xc8, 0x04, 0x00, 0x1f, 0xff, 0x17, 0x7c, 0xf7, 0xcf, + 0xcf, 0xd4, 0xff, 0x1f, 0x6b, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, + 0xff, 0x1f, 0x00, 0x04, 0x22, 0x00, 0x00, 0x5a, 0xf7, 0xab, 0xe5, 0x66, + 0x04, 0x00, 0x00, 0x04, 0x15, 0x0c, 0x00, 0x00, + /* ch = 'f' */ + 0x00, 0x00, 0x00, 0x18, 0x36, 0x25, 0x00, 0x00, 0x50, 0xdb, 0x3e, 0xbb, + 0x00, 0x00, 0xf7, 0x37, 0x00, 0x0d, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, + 0x45, 0xcf, 0xff, 0xd4, 0xcf, 0x2f, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, + /* ch = 'g' */ + 0x00, 0x19, 0x67, 0x67, 0x25, 0x50, 0x32, 0x1c, 0xf7, 0x3f, 0x3f, 0xff, + 0x45, 0x12, 0x4d, 0xbd, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x2a, 0xff, 0x21, + 0x21, 0xf7, 0x2c, 0x00, 0x00, 0x9e, 0xd4, 0xbd, 0x37, 0x00, 0x00, 0x27, + 0xff, 0x1d, 0x15, 0x0f, 0x00, 0x00, 0x0c, 0xea, 0xbd, 0xcf, 0xdd, 0xdb, + 0x0d, 0x8a, 0x59, 0x00, 0x00, 0x00, 0xd9, 0x35, 0x66, 0xe5, 0x47, 0x36, + 0x85, 0xd4, 0x10, 0x00, 0x18, 0x36, 0x36, 0x25, 0x08, 0x00, + /* ch = 'h' */ + 0x16, 0x36, 0x09, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x16, + 0x50, 0x50, 0x08, 0x00, 0x32, 0xff, 0xdb, 0x3e, 0xb1, 0xa7, 0x00, 0x32, + 0xff, 0x21, 0x00, 0x32, 0xff, 0x04, 0x32, 0xff, 0x04, 0x00, 0x32, 0xff, + 0x04, 0x32, 0xff, 0x04, 0x00, 0x32, 0xff, 0x04, 0x32, 0xff, 0x04, 0x00, + 0x32, 0xff, 0x04, 0x32, 0xff, 0x04, 0x00, 0x32, 0xff, 0x04, + /* ch = 'i' */ + 0x00, 0x04, 0x12, 0x00, 0x00, 0x00, 0x49, 0xff, 0x2a, 0x00, 0x00, 0x04, + 0x15, 0x04, 0x00, 0x2d, 0x36, 0x36, 0x00, 0x00, 0x2d, 0x62, 0xff, 0x04, + 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, 0x00, + 0x32, 0xff, 0x04, 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, 0xcf, 0xdd, 0xff, + 0xd4, 0x45, + /* ch = 'j' */ + 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x2f, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x04, 0x15, 0x08, 0x00, 0x1e, 0x36, 0x36, 0x36, 0x0d, + 0x00, 0x1e, 0x36, 0x4a, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1f, + 0x0d, 0x19, 0x00, 0x2c, 0xff, 0x17, 0x52, 0xe5, 0x50, 0xd4, 0x77, 0x00, + 0x00, 0x25, 0x36, 0x25, 0x04, 0x00, + /* ch = 'k' */ + 0x16, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x04, + 0x00, 0x19, 0x36, 0x10, 0x32, 0xff, 0x04, 0x21, 0xf7, 0x37, 0x00, 0x32, + 0xff, 0x2f, 0xef, 0x2f, 0x00, 0x00, 0x32, 0xff, 0xff, 0xbd, 0x04, 0x00, + 0x00, 0x32, 0xff, 0x25, 0xdb, 0x82, 0x00, 0x00, 0x32, 0xff, 0x04, 0x1f, + 0xf7, 0x54, 0x00, 0x32, 0xff, 0x04, 0x00, 0x32, 0xff, 0x35, + /* ch = 'l' */ + 0x0d, 0x36, 0x36, 0x36, 0x00, 0x00, 0x14, 0x74, 0x9c, 0xff, 0x04, 0x00, + 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, + 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, + 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, + 0x00, 0x00, 0x32, 0xff, 0x04, 0x00, 0x1a, 0xcf, 0xdd, 0xff, 0xd4, 0x95, + /* ch = 'm' */ + 0x2d, 0x30, 0x67, 0x22, 0x3f, 0x5b, 0x08, 0xb7, 0xb7, 0x64, 0xff, 0x54, + 0xc8, 0x50, 0xb7, 0x54, 0x32, 0xff, 0x08, 0x7c, 0x82, 0xb7, 0x54, 0x32, + 0xff, 0x04, 0x7c, 0x82, 0xb7, 0x54, 0x32, 0xff, 0x04, 0x7c, 0x82, 0xb7, + 0x54, 0x32, 0xff, 0x04, 0x7c, 0x82, 0xb7, 0x54, 0x32, 0xff, 0x04, 0x7c, + 0x82, + /* ch = 'n' */ + 0x16, 0x36, 0x13, 0x50, 0x50, 0x08, 0x00, 0x32, 0xff, 0xdb, 0x3e, 0xc4, + 0xa7, 0x00, 0x32, 0xff, 0x1a, 0x00, 0x35, 0xff, 0x04, 0x32, 0xff, 0x04, + 0x00, 0x32, 0xff, 0x04, 0x32, 0xff, 0x04, 0x00, 0x32, 0xff, 0x04, 0x32, + 0xff, 0x04, 0x00, 0x32, 0xff, 0x04, 0x32, 0xff, 0x04, 0x00, 0x32, 0xff, + 0x04, + /* ch = 'o' */ + 0x00, 0x04, 0x30, 0x74, 0x2a, 0x00, 0x00, 0x04, 0xc4, 0x99, 0x36, 0xd4, + 0x82, 0x00, 0x50, 0xc8, 0x08, 0x00, 0x22, 0xff, 0x24, 0x90, 0x82, 0x00, + 0x00, 0x00, 0xf7, 0x3f, 0x7c, 0x97, 0x00, 0x00, 0x00, 0xff, 0x37, 0x39, + 0xff, 0x1f, 0x00, 0x35, 0xf7, 0x10, 0x00, 0x5a, 0xff, 0xcf, 0xef, 0x35, + 0x00, 0x00, 0x00, 0x08, 0x15, 0x08, 0x00, 0x00, + /* ch = 'p' */ + 0x1e, 0x2d, 0x22, 0x5b, 0x37, 0x04, 0x00, 0x50, 0xff, 0x94, 0x36, 0xc4, + 0xb7, 0x00, 0x50, 0xe5, 0x08, 0x00, 0x22, 0xff, 0x32, 0x50, 0xbd, 0x00, + 0x00, 0x00, 0xf7, 0x54, 0x50, 0xbd, 0x00, 0x00, 0x00, 0xff, 0x48, 0x50, + 0xff, 0x1c, 0x00, 0x35, 0xff, 0x1a, 0x50, 0xe5, 0xef, 0xcf, 0xf7, 0x48, + 0x00, 0x50, 0xbd, 0x04, 0x15, 0x0c, 0x00, 0x00, 0x50, 0xbd, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = 'q' */ + 0x00, 0x0c, 0x50, 0x67, 0x28, 0x36, 0x0d, 0x10, 0xdb, 0x6a, 0x2a, 0xdb, + 0xff, 0x1f, 0x5a, 0xa7, 0x04, 0x00, 0x32, 0xff, 0x1f, 0x7c, 0x82, 0x00, + 0x00, 0x1c, 0xff, 0x1f, 0x7c, 0x88, 0x00, 0x00, 0x1f, 0xff, 0x1f, 0x39, + 0xff, 0x1f, 0x00, 0x5f, 0xff, 0x1f, 0x00, 0x77, 0xff, 0xdd, 0xbb, 0xff, + 0x1f, 0x00, 0x00, 0x0c, 0x0f, 0x1c, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x36, 0x10, + /* ch = 'r' */ + 0x36, 0x21, 0x2a, 0x74, 0x37, 0x04, 0xff, 0xff, 0x99, 0x36, 0xc4, 0x24, + 0xff, 0xb7, 0x04, 0x00, 0x0c, 0x04, 0xff, 0x48, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, + /* ch = 's' */ + 0x00, 0x08, 0x3e, 0x74, 0x3e, 0x08, 0x00, 0x00, 0xc0, 0x7c, 0x1a, 0x77, + 0xc8, 0x00, 0x14, 0xff, 0x4f, 0x00, 0x00, 0x22, 0x00, 0x00, 0x35, 0xe5, + 0xef, 0x73, 0x13, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x99, 0xe5, 0x04, 0x1c, + 0x65, 0x04, 0x00, 0x26, 0xff, 0x17, 0x19, 0xbb, 0xef, 0xcf, 0xef, 0x48, + 0x00, 0x00, 0x00, 0x08, 0x15, 0x08, 0x00, 0x00, + /* ch = 't' */ + 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x90, 0x70, 0x00, 0x00, + 0x16, 0x36, 0xcf, 0x87, 0x36, 0x1e, 0x16, 0x36, 0xcf, 0x82, 0x36, 0x21, + 0x00, 0x00, 0xe5, 0x37, 0x00, 0x00, 0x00, 0x00, 0xff, 0x35, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x5f, 0x00, 0x22, + 0x00, 0x00, 0x4d, 0xff, 0xe5, 0xcb, 0x00, 0x00, 0x00, 0x08, 0x0c, 0x00, + /* ch = 'u' */ + 0x1e, 0x2d, 0x00, 0x00, 0x16, 0x36, 0x0d, 0x50, 0xbd, 0x00, 0x00, 0x32, + 0xff, 0x1f, 0x50, 0xbd, 0x00, 0x00, 0x32, 0xff, 0x1f, 0x50, 0xbd, 0x00, + 0x00, 0x32, 0xff, 0x1f, 0x50, 0xc6, 0x00, 0x00, 0x32, 0xff, 0x1f, 0x2f, + 0xff, 0x1a, 0x00, 0x70, 0xff, 0x1f, 0x00, 0x94, 0xf7, 0xd4, 0xcb, 0xff, + 0x1f, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, + /* ch = 'v' */ + 0x2b, 0x2b, 0x00, 0x00, 0x00, 0x30, 0x16, 0x44, 0xec, 0x04, 0x00, 0x0d, + 0xff, 0x17, 0x0d, 0xf7, 0x3b, 0x00, 0x44, 0xa7, 0x04, 0x00, 0x70, 0x97, + 0x00, 0xa7, 0x3b, 0x00, 0x00, 0x24, 0xff, 0x40, 0xe5, 0x08, 0x00, 0x00, + 0x00, 0xc8, 0xff, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x48, 0xff, 0x1a, 0x00, + 0x00, + /* ch = 'w' */ + 0x36, 0x13, 0x00, 0x00, 0x00, 0x1e, 0x26, 0xe5, 0x2c, 0x1c, 0xbd, 0x00, + 0x54, 0x70, 0x90, 0x50, 0x3b, 0xff, 0x26, 0x7c, 0x50, 0x54, 0x88, 0x77, + 0xe5, 0x64, 0xb1, 0x32, 0x2f, 0xd9, 0xcf, 0x48, 0xbd, 0xe5, 0x1c, 0x1a, + 0xff, 0xb7, 0x10, 0xff, 0xe5, 0x04, 0x00, 0xe5, 0x64, 0x00, 0xa0, 0xa7, + 0x00, + /* ch = 'x' */ + 0x24, 0x30, 0x00, 0x00, 0x19, 0x33, 0x09, 0x10, 0xdb, 0x48, 0x04, 0xb7, + 0x54, 0x00, 0x00, 0x2f, 0xff, 0x7c, 0xb1, 0x08, 0x00, 0x00, 0x00, 0x70, + 0xff, 0x24, 0x00, 0x00, 0x00, 0x04, 0xdb, 0xf7, 0x70, 0x00, 0x00, 0x00, + 0x77, 0xb1, 0x21, 0xf7, 0x35, 0x00, 0x32, 0xf7, 0x1f, 0x00, 0x4d, 0xe5, + 0x10, + /* ch = 'y' */ + 0x24, 0x2d, 0x00, 0x00, 0x00, 0x36, 0x1c, 0x2c, 0xff, 0x0d, 0x00, 0x14, + 0xff, 0x1f, 0x04, 0xe5, 0x4c, 0x00, 0x48, 0xb7, 0x04, 0x00, 0x5a, 0xcf, + 0x00, 0xa7, 0x4c, 0x00, 0x00, 0x17, 0xff, 0x3f, 0xff, 0x10, 0x00, 0x00, + 0x00, 0x8a, 0xff, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xff, 0x2f, 0x00, + 0x00, 0x00, 0x00, 0x32, 0xe5, 0x08, 0x00, 0x00, 0xa0, 0x54, 0xdb, 0x50, + 0x00, 0x00, 0x00, 0x1e, 0x36, 0x25, 0x00, 0x00, 0x00, 0x00, + /* ch = 'z' */ + 0x16, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x16, 0x36, 0x36, 0x36, 0xc4, + 0xb1, 0x04, 0x00, 0x00, 0x00, 0x50, 0xdb, 0x13, 0x00, 0x00, 0x00, 0x32, + 0xf7, 0x21, 0x00, 0x00, 0x00, 0x1f, 0xf7, 0x35, 0x00, 0x00, 0x00, 0x10, + 0xdb, 0x64, 0x00, 0x00, 0x00, 0x00, 0x77, 0xff, 0xdd, 0xcf, 0xcf, 0xdd, + 0x35, + /* ch = '{' */ + 0x1f, 0xbd, 0xd4, 0x6c, 0xc8, 0x4f, 0x00, 0x00, 0xff, 0x35, 0x00, 0x00, + 0xff, 0x35, 0x00, 0x00, 0xf7, 0x10, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, + 0xff, 0x14, 0x00, 0x00, 0xff, 0x2a, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x00, + 0xff, 0x35, 0x00, 0x00, 0x73, 0xf7, 0x74, 0x42, 0x00, 0x0f, 0x15, 0x12, + /* ch = '|' */ + 0x08, 0x15, 0x00, 0x32, 0xff, 0x04, 0x32, 0xff, 0x04, 0x32, 0xff, 0x04, + 0x32, 0xff, 0x04, 0x32, 0xff, 0x04, 0x32, 0xff, 0x04, 0x32, 0xff, 0x04, + 0x32, 0xff, 0x04, 0x32, 0xff, 0x04, 0x32, 0xff, 0x04, 0x32, 0xff, 0x04, + 0x08, 0x15, 0x04, + /* ch = '}' */ + 0xcf, 0xdd, 0x8d, 0x0d, 0x00, 0x04, 0xa7, 0x5f, 0x00, 0x00, 0x7c, 0x82, + 0x00, 0x00, 0x77, 0x82, 0x00, 0x00, 0x39, 0xcf, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x00, 0x40, 0xcf, 0x00, 0x00, 0x5a, 0x82, 0x00, 0x00, 0x50, 0xbd, + 0x00, 0x00, 0x7c, 0x88, 0x74, 0x8f, 0xf7, 0x32, 0x15, 0x15, 0x0c, 0x00, + /* ch = '~' */ + 0x00, 0x2a, 0x50, 0x1b, 0x00, 0x19, 0x10, 0x5b, 0xc4, 0x4f, 0xf7, 0x73, + 0xdb, 0x35, 0x04, 0x0c, 0x00, 0x1b, 0x36, 0x20, 0x00 }; /* font_inconsolata_15px */ static const unsigned char pd_inconsolata_font_bitmap_15px_bytes[] = { - /* ch = '!' */ - 0x39, 0xff, 0x27, - 0x50, 0xff, 0x32, - 0x32, 0xff, 0x32, - 0x32, 0xff, 0x1c, - 0x24, 0xff, 0x1c, - 0x1c, 0xff, 0x0d, - 0x1c, 0xff, 0x00, - 0x00, 0x00, 0x00, - 0x1f, 0x74, 0x10, - 0x66, 0xff, 0x40, - 0x04, 0x15, 0x00, - /* ch = '"' */ - 0x22, 0xff, 0x27, 0x66, 0xb1, - 0x1f, 0xff, 0x2a, 0x7c, 0xbd, - 0x32, 0xe5, 0x04, 0x90, 0x5f, - 0x46, 0x60, 0x00, 0xa5, 0x22, - /* ch = '#' */ - 0x00, 0x00, 0x28, 0x1e, 0x04, 0x2a, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x3b, 0x2f, 0xff, 0x00, 0x00, - 0x00, 0x00, 0xf7, 0x2f, 0x3b, 0xb7, 0x00, 0x00, - 0x6c, 0xcf, 0xff, 0xb1, 0xcf, 0xe5, 0xa2, 0x11, - 0x00, 0x1c, 0xff, 0x04, 0x7c, 0x6b, 0x00, 0x00, - 0x00, 0x32, 0xcf, 0x00, 0xa0, 0x50, 0x00, 0x00, - 0x5c, 0x9c, 0xe5, 0x74, 0xe5, 0x9c, 0x58, 0x00, - 0x15, 0x62, 0x88, 0x15, 0xff, 0x24, 0x00, 0x00, - 0x00, 0x7c, 0x54, 0x1a, 0xff, 0x1a, 0x00, 0x00, - 0x00, 0x8f, 0x3e, 0x1f, 0xcf, 0x00, 0x00, 0x00, - /* ch = '$' */ - 0x00, 0x00, 0x00, 0x95, 0x3a, 0x00, 0x00, - 0x00, 0x19, 0x9e, 0xf7, 0xdd, 0x66, 0x04, - 0x04, 0xdb, 0x54, 0xb7, 0x3a, 0xa0, 0x49, - 0x1a, 0xff, 0x26, 0xb7, 0x32, 0x00, 0x00, - 0x00, 0x7c, 0xef, 0xe5, 0x32, 0x00, 0x00, - 0x00, 0x00, 0x31, 0xe5, 0xff, 0x8d, 0x10, - 0x00, 0x00, 0x00, 0xb7, 0x37, 0xb1, 0x8a, - 0x00, 0x21, 0x00, 0xb7, 0x32, 0x50, 0xb7, - 0x2d, 0xf7, 0x37, 0xbd, 0x4f, 0xdb, 0x4d, - 0x00, 0x22, 0x8f, 0xf7, 0xbb, 0x37, 0x00, - 0x00, 0x00, 0x00, 0x58, 0x22, 0x00, 0x00, - /* ch = '%' */ - 0x08, 0x47, 0x37, 0x04, 0x00, 0x21, 0x2b, - 0x8a, 0x8a, 0xb1, 0x5a, 0x04, 0xdb, 0x3b, - 0xb7, 0x32, 0x50, 0xa9, 0x50, 0xb7, 0x00, - 0x6b, 0xa0, 0xb7, 0x5f, 0xf7, 0x2a, 0x00, - 0x04, 0x30, 0x2a, 0x6b, 0x90, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x90, 0x6b, 0x50, 0xbd, 0x35, - 0x00, 0x2a, 0xf7, 0x3f, 0xe5, 0x24, 0xff, - 0x00, 0xb7, 0x50, 0x44, 0xbd, 0x04, 0xff, - 0x3b, 0xdb, 0x04, 0x10, 0xdb, 0xc4, 0xa9, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x15, 0x00, - /* ch = '&' */ - 0x00, 0x00, 0x2a, 0x36, 0x13, 0x00, 0x00, 0x00, - 0x00, 0x77, 0xdb, 0x85, 0xf7, 0x17, 0x00, 0x00, - 0x00, 0xef, 0x47, 0x00, 0xd9, 0x40, 0x00, 0x00, - 0x00, 0x8a, 0x90, 0x17, 0xff, 0x22, 0x00, 0x00, - 0x00, 0x1f, 0xff, 0xef, 0x4d, 0x00, 0x00, 0x00, - 0x04, 0x94, 0xef, 0xf7, 0x1f, 0x04, 0x0c, 0x00, - 0x48, 0xf7, 0x10, 0x7c, 0xb1, 0x2f, 0xf7, 0x0a, - 0xa0, 0x82, 0x00, 0x0d, 0xdb, 0xff, 0x54, 0x00, - 0x7c, 0xc8, 0x08, 0x08, 0xb1, 0xff, 0x35, 0x00, - 0x1f, 0xd4, 0xef, 0xf7, 0x7e, 0x59, 0xd4, 0x0a, - 0x00, 0x00, 0x15, 0x08, 0x00, 0x04, 0x08, 0x00, - /* ch = ''' */ - 0x00, 0x99, 0x84, - 0x00, 0xb7, 0x82, - 0x00, 0xcf, 0x3b, - 0x11, 0xbd, 0x0d, - /* ch = '(' */ - 0x00, 0x00, 0x35, 0xef, - 0x00, 0x50, 0xf7, 0x26, - 0x2a, 0xff, 0x2c, 0x00, - 0xa0, 0x8a, 0x00, 0x00, - 0xff, 0x32, 0x00, 0x00, - 0xff, 0x1c, 0x00, 0x00, - 0xff, 0x1c, 0x00, 0x00, - 0xff, 0x2a, 0x00, 0x00, - 0xc8, 0x64, 0x00, 0x00, - 0x44, 0xf7, 0x10, 0x00, - 0x04, 0xb1, 0xb1, 0x04, - 0x00, 0x10, 0xc4, 0xc4, - 0x00, 0x00, 0x04, 0x51, - /* ch = ')' */ - 0xe5, 0x35, 0x00, 0x00, - 0x3f, 0xf7, 0x50, 0x00, - 0x00, 0x32, 0xff, 0x2f, - 0x00, 0x00, 0x70, 0xc8, - 0x00, 0x00, 0x24, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x0d, 0xff, - 0x00, 0x00, 0x39, 0xf7, - 0x00, 0x04, 0xc8, 0x6b, - 0x04, 0x7c, 0xdb, 0x10, - 0xa9, 0xd4, 0x19, 0x00, - 0x50, 0x08, 0x00, 0x00, - /* ch = '*' */ - 0x00, 0x00, 0x17, 0xcf, 0x2d, 0x00, 0x00, - 0x08, 0x08, 0x00, 0xff, 0x24, 0x04, 0x0c, - 0x58, 0xf7, 0x66, 0xff, 0x6b, 0xe5, 0x87, - 0x00, 0x0c, 0x51, 0xff, 0x6c, 0x0c, 0x00, - 0x00, 0x10, 0xdb, 0x54, 0xf7, 0x1f, 0x00, - 0x00, 0xa9, 0x7c, 0x00, 0x54, 0xdb, 0x09, - 0x00, 0x1b, 0x10, 0x00, 0x04, 0x21, 0x00, - /* ch = '+' */ - 0x00, 0x00, 0x00, 0xcf, 0x2d, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, - 0x0f, 0x15, 0x15, 0xff, 0x3e, 0x15, 0x12, - 0x42, 0x74, 0x74, 0xff, 0x9c, 0x74, 0x58, - 0x00, 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x36, 0x16, 0x00, 0x00, - /* ch = ',' */ - 0x19, 0x5b, 0x10, - 0x66, 0xff, 0x5a, - 0x04, 0xea, 0x39, - 0x35, 0xb1, 0x04, - 0x3d, 0x10, 0x00, - /* ch = '-' */ - 0x08, 0x15, 0x15, 0x15, 0x15, 0x15, 0x0c, - 0x2d, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x45, - /* ch = '.' */ - 0x19, 0x67, 0x10, - 0x66, 0xff, 0x40, - 0x04, 0x15, 0x00, - /* ch = '/' */ - 0x00, 0xc0, 0x33, - 0x39, 0xf7, 0x10, - 0xa7, 0x70, 0x00, - 0xff, 0x17, 0x00, - 0x8a, 0x00, 0x00, - 0x22, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* ch = '0' */ - 0x00, 0x00, 0x16, 0x36, 0x1e, 0x00, 0x00, - 0x00, 0x32, 0xef, 0x82, 0xef, 0x50, 0x00, - 0x04, 0xe5, 0x3b, 0x00, 0x26, 0xff, 0x17, - 0x32, 0xe5, 0x04, 0x00, 0x7c, 0xff, 0x50, - 0x50, 0xb7, 0x00, 0x50, 0xdb, 0x97, 0x7c, - 0x50, 0x90, 0x24, 0xf7, 0x1f, 0x54, 0x7c, - 0x50, 0xcf, 0xdb, 0x3b, 0x00, 0x7c, 0x7c, - 0x2a, 0xff, 0x7c, 0x00, 0x00, 0xb7, 0x4d, - 0x00, 0xb7, 0x7c, 0x00, 0x32, 0xf7, 0x17, - 0x00, 0x1f, 0xd4, 0xdd, 0xf7, 0x32, 0x00, - 0x00, 0x00, 0x00, 0x15, 0x08, 0x00, 0x00, - /* ch = '1' */ - 0x00, 0x00, 0x2a, 0x1e, - 0x31, 0xd4, 0xff, 0x50, - 0x48, 0x20, 0xb7, 0x50, - 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0xb7, 0x50, - /* ch = '2' */ - 0x00, 0x00, 0x1e, 0x36, 0x25, 0x00, 0x00, - 0x00, 0x77, 0xd4, 0x74, 0xdb, 0xa9, 0x04, - 0x04, 0x7e, 0x10, 0x00, 0x10, 0xff, 0x39, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x4d, - 0x00, 0x00, 0x00, 0x00, 0x2a, 0xff, 0x1c, - 0x00, 0x00, 0x00, 0x1f, 0xef, 0x50, 0x00, - 0x00, 0x00, 0x1f, 0xf7, 0x4d, 0x00, 0x00, - 0x00, 0x10, 0xdb, 0x50, 0x00, 0x00, 0x00, - 0x00, 0xa0, 0x82, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, - /* ch = '3' */ - 0x00, 0x00, 0x20, 0x36, 0x18, 0x00, 0x00, - 0x00, 0x9c, 0xcb, 0x82, 0xf7, 0x50, 0x00, - 0x00, 0x0c, 0x04, 0x00, 0x2c, 0xff, 0x14, - 0x00, 0x00, 0x00, 0x00, 0x2c, 0xff, 0x14, - 0x00, 0x00, 0x16, 0x3e, 0xdb, 0x4d, 0x00, - 0x00, 0x00, 0x42, 0x82, 0xe5, 0x4d, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x24, 0xff, 0x22, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, - 0x04, 0x8d, 0x13, 0x00, 0x37, 0xff, 0x17, - 0x08, 0x94, 0xf7, 0xd4, 0xf7, 0x3b, 0x00, - 0x00, 0x00, 0x0c, 0x15, 0x04, 0x00, 0x00, - /* ch = '4' */ - 0x00, 0x00, 0x00, 0x00, 0x28, 0x1e, 0x00, - 0x00, 0x00, 0x00, 0x1f, 0xff, 0x50, 0x00, - 0x00, 0x00, 0x04, 0xb7, 0xff, 0x50, 0x00, - 0x00, 0x00, 0x54, 0x90, 0xb7, 0x50, 0x00, - 0x00, 0x1f, 0xf7, 0x10, 0xb7, 0x50, 0x00, - 0x04, 0xb7, 0x3b, 0x00, 0xb7, 0x50, 0x00, - 0x50, 0xec, 0x74, 0x74, 0xe5, 0xb1, 0x58, - 0x26, 0x36, 0x36, 0x36, 0xcf, 0x82, 0x2d, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, - /* ch = '5' */ - 0x00, 0x28, 0x36, 0x36, 0x36, 0x36, 0x16, - 0x00, 0xb7, 0xb1, 0x74, 0x74, 0x74, 0x22, - 0x00, 0xb7, 0x44, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xf7, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xff, 0xf7, 0xd4, 0xf7, 0x5a, 0x00, - 0x00, 0x67, 0x21, 0x00, 0x21, 0xff, 0x39, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x77, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x77, - 0x13, 0xd4, 0x21, 0x00, 0x1f, 0xff, 0x39, - 0x00, 0x66, 0xf7, 0xcf, 0xf7, 0x66, 0x00, - 0x00, 0x00, 0x04, 0x15, 0x08, 0x00, 0x00, - /* ch = '6' */ - 0x00, 0x00, 0x08, 0x30, 0x36, 0x16, 0x00, - 0x00, 0x1f, 0xdb, 0xa4, 0x73, 0xef, 0x1e, - 0x00, 0xa0, 0x82, 0x00, 0x00, 0x0c, 0x00, - 0x14, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x00, - 0x2a, 0xff, 0xa2, 0xff, 0xf7, 0x44, 0x00, - 0x32, 0xff, 0x70, 0x04, 0x21, 0xff, 0x2a, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0xb7, 0x50, - 0x1a, 0xff, 0x24, 0x00, 0x00, 0xb7, 0x54, - 0x00, 0xb7, 0x82, 0x00, 0x1f, 0xff, 0x2c, - 0x00, 0x1f, 0xd4, 0xdd, 0xf7, 0x5a, 0x00, - 0x00, 0x00, 0x00, 0x12, 0x0c, 0x00, 0x00, - /* ch = '7' */ - 0x0d, 0x36, 0x36, 0x36, 0x36, 0x36, 0x1e, - 0x14, 0x74, 0x74, 0x74, 0x8d, 0xff, 0x39, - 0x00, 0x00, 0x00, 0x00, 0x50, 0xe5, 0x04, - 0x00, 0x00, 0x00, 0x00, 0xc8, 0x5a, 0x00, - 0x00, 0x00, 0x00, 0x2c, 0xff, 0x17, 0x00, - 0x00, 0x00, 0x00, 0x8a, 0x90, 0x00, 0x00, - 0x00, 0x00, 0x0d, 0xff, 0x39, 0x00, 0x00, - 0x00, 0x00, 0x44, 0xf7, 0x0d, 0x00, 0x00, - 0x00, 0x00, 0xa7, 0x8a, 0x00, 0x00, 0x00, - 0x00, 0x17, 0xff, 0x39, 0x00, 0x00, 0x00, - /* ch = '8' */ - 0x00, 0x00, 0x1e, 0x36, 0x30, 0x04, 0x00, - 0x00, 0x50, 0xef, 0x50, 0xc4, 0xb1, 0x04, - 0x00, 0xe5, 0x3b, 0x00, 0x17, 0xff, 0x2f, - 0x00, 0xc8, 0x5f, 0x00, 0x24, 0xff, 0x17, - 0x00, 0x2c, 0xf7, 0x85, 0xdb, 0x4d, 0x00, - 0x00, 0x2c, 0xe5, 0x8f, 0xf7, 0x5a, 0x00, - 0x17, 0xf7, 0x35, 0x00, 0x1f, 0xff, 0x39, - 0x39, 0xff, 0x00, 0x00, 0x00, 0xb7, 0x77, - 0x27, 0xff, 0x37, 0x00, 0x19, 0xf7, 0x40, - 0x00, 0x44, 0xf7, 0xd4, 0xf7, 0x66, 0x00, - 0x00, 0x00, 0x04, 0x15, 0x08, 0x00, 0x00, - /* ch = '9' */ - 0x00, 0x00, 0x1e, 0x36, 0x22, 0x00, 0x00, - 0x00, 0x50, 0xef, 0x74, 0xef, 0x73, 0x00, - 0x14, 0xff, 0x2c, 0x00, 0x24, 0xff, 0x22, - 0x32, 0xff, 0x04, 0x00, 0x00, 0xcf, 0x44, - 0x24, 0xff, 0x22, 0x00, 0x04, 0xcf, 0x50, - 0x00, 0xa0, 0xc4, 0x36, 0x99, 0xff, 0x50, - 0x00, 0x04, 0x48, 0x74, 0x37, 0xbd, 0x50, - 0x00, 0x00, 0x00, 0x00, 0x0d, 0xff, 0x2a, - 0x00, 0x3d, 0x04, 0x00, 0x6f, 0xdb, 0x04, - 0x09, 0xa9, 0xef, 0xe5, 0xd4, 0x19, 0x00, - 0x00, 0x00, 0x0f, 0x12, 0x00, 0x00, 0x00, - /* ch = ':' */ - 0x08, 0x30, 0x04, - 0x73, 0xff, 0x49, - 0x10, 0x36, 0x04, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x19, 0x67, 0x10, - 0x66, 0xff, 0x40, - 0x04, 0x15, 0x00, - /* ch = ';' */ - 0x08, 0x30, 0x04, - 0x73, 0xff, 0x49, - 0x10, 0x36, 0x04, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x19, 0x5b, 0x10, - 0x66, 0xff, 0x5a, - 0x04, 0xea, 0x39, - 0x35, 0xb1, 0x04, - 0x3d, 0x10, 0x00, - /* ch = '<' */ - 0x00, 0x00, 0x00, 0x04, 0x3d, - 0x00, 0x04, 0x3f, 0xef, 0x8d, - 0x37, 0xd4, 0xb3, 0x1e, 0x00, - 0xbb, 0x22, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x00, - 0xd4, 0xb3, 0x1b, 0x00, 0x00, - 0x04, 0x50, 0xf7, 0x73, 0x13, - 0x00, 0x00, 0x13, 0x94, 0xb7, - 0x00, 0x00, 0x00, 0x00, 0x0c, - /* ch = '=' */ - 0x42, 0x74, 0x74, 0x74, 0x74, 0x74, 0x58, - 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x2d, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x2d, - 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x2d, - /* ch = '>' */ - 0x08, 0x00, 0x00, 0x00, 0x00, - 0xf7, 0x5a, 0x08, 0x00, 0x00, - 0x16, 0x8d, 0xef, 0x48, 0x04, - 0x00, 0x00, 0x1b, 0x94, 0xef, - 0x00, 0x00, 0x00, 0x1b, 0xc8, - 0x00, 0x13, 0x8d, 0xef, 0x37, - 0x5a, 0xf7, 0x73, 0x08, 0x00, - 0xbb, 0x1b, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = '?' */ - 0x00, 0x28, 0xc4, 0xff, 0xe5, 0x44, 0x00, - 0x22, 0xff, 0x48, 0x04, 0x54, 0xff, 0x27, - 0x00, 0x0f, 0x00, 0x00, 0x04, 0xff, 0x50, - 0x00, 0x00, 0x00, 0x00, 0x2c, 0xff, 0x39, - 0x00, 0x00, 0x00, 0x19, 0xdb, 0x7c, 0x00, - 0x00, 0x00, 0x00, 0x99, 0x82, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x15, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x50, 0x21, 0x00, 0x00, - 0x00, 0x00, 0x27, 0xff, 0x99, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x12, 0x08, 0x00, 0x00, - /* ch = '@' */ - 0x00, 0x00, 0x1b, 0x36, 0x36, 0x0c, 0x00, - 0x00, 0x4d, 0xd4, 0x3e, 0x5a, 0xef, 0x1f, - 0x2a, 0xf7, 0x10, 0x00, 0x00, 0x50, 0xa0, - 0x6b, 0x5f, 0x00, 0x22, 0x74, 0x9c, 0xf7, - 0xb7, 0x35, 0x39, 0xdb, 0x25, 0x3a, 0xff, - 0xb7, 0x32, 0x7c, 0x6f, 0x00, 0x35, 0xff, - 0xa0, 0x4d, 0x44, 0xdb, 0x3e, 0xc4, 0xff, - 0x50, 0xa7, 0x00, 0x2a, 0x50, 0x30, 0x36, - 0x0d, 0xdb, 0x54, 0x00, 0x00, 0x08, 0x04, - 0x00, 0x19, 0xbb, 0xe5, 0xcf, 0xe5, 0x2d, - 0x00, 0x00, 0x00, 0x0f, 0x15, 0x04, 0x00, - /* ch = 'A' */ - 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xf7, 0x0d, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x3b, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xc8, 0xc0, 0xa7, 0x00, 0x00, 0x00, - 0x00, 0x22, 0xf7, 0x24, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x5a, 0x8a, 0x00, 0xa7, 0x5a, 0x00, 0x00, - 0x00, 0xcf, 0xb1, 0x74, 0xb1, 0xe5, 0x00, 0x00, - 0x24, 0xff, 0x21, 0x15, 0x21, 0xff, 0x2c, 0x00, - 0x6b, 0xa0, 0x00, 0x00, 0x00, 0x90, 0x8a, 0x00, - 0xe5, 0x44, 0x00, 0x00, 0x00, 0x39, 0xf7, 0x0d, - /* ch = 'B' */ - 0x26, 0x36, 0x36, 0x36, 0x20, 0x00, 0x00, - 0x7c, 0xe5, 0x74, 0x74, 0xe5, 0xb1, 0x0d, - 0x7c, 0xb7, 0x00, 0x00, 0x10, 0xff, 0x44, - 0x7c, 0xb7, 0x00, 0x00, 0x0d, 0xff, 0x39, - 0x7c, 0xcf, 0x36, 0x50, 0xd4, 0xa9, 0x04, - 0x7c, 0xcf, 0x36, 0x36, 0xa4, 0xbb, 0x10, - 0x7c, 0xb7, 0x00, 0x00, 0x00, 0xa7, 0x7c, - 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x70, 0xb7, - 0x7c, 0xb7, 0x00, 0x00, 0x1b, 0xe5, 0x5f, - 0x7c, 0xff, 0xff, 0xff, 0xef, 0x73, 0x04, - /* ch = 'C' */ - 0x00, 0x00, 0x0c, 0x36, 0x36, 0x0c, 0x00, - 0x00, 0x39, 0xef, 0x66, 0x66, 0xf7, 0x32, - 0x17, 0xf7, 0x35, 0x00, 0x00, 0x3f, 0x8d, - 0x50, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x77, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x44, 0xf7, 0x0d, 0x00, 0x00, 0x00, 0x00, - 0x0d, 0xdb, 0x7c, 0x04, 0x00, 0x50, 0x5c, - 0x00, 0x1f, 0xcb, 0xe5, 0xdd, 0xcb, 0x19, - 0x00, 0x00, 0x00, 0x12, 0x0f, 0x00, 0x00, - /* ch = 'D' */ - 0x1e, 0x36, 0x36, 0x30, 0x0f, 0x00, 0x00, - 0x50, 0xe5, 0x74, 0x8f, 0xf7, 0x66, 0x00, - 0x50, 0xb7, 0x00, 0x00, 0x2c, 0xff, 0x2c, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0xa7, 0x7c, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x5f, 0xb7, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x5f, 0xb1, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0xc8, 0x5a, - 0x50, 0xb7, 0x00, 0x04, 0x5f, 0xf7, 0x10, - 0x50, 0xf7, 0xcf, 0xef, 0xab, 0x19, 0x00, - /* ch = 'E' */ - 0x1e, 0x36, 0x36, 0x36, 0x36, 0x36, 0x26, - 0x50, 0xe5, 0x74, 0x74, 0x74, 0x74, 0x42, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xcf, 0x36, 0x36, 0x36, 0x2d, 0x00, - 0x50, 0xe5, 0x74, 0x74, 0x74, 0x58, 0x00, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, - /* ch = 'F' */ - 0x0d, 0x36, 0x36, 0x36, 0x36, 0x36, 0x1e, - 0x1c, 0xff, 0x87, 0x74, 0x74, 0x74, 0x30, - 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x87, 0x74, 0x74, 0x42, 0x00, - 0x1c, 0xff, 0x4a, 0x36, 0x36, 0x26, 0x00, - 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - /* ch = 'G' */ - 0x00, 0x00, 0x0f, 0x36, 0x36, 0x0c, 0x00, - 0x00, 0x44, 0xf7, 0x82, 0x8f, 0xf7, 0x32, - 0x22, 0xff, 0x32, 0x00, 0x00, 0x49, 0x4d, - 0x5f, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x90, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb7, 0x6b, 0x00, 0x0d, 0x36, 0x36, 0x2d, - 0x7c, 0x7c, 0x00, 0x0d, 0x36, 0x62, 0xb7, - 0x50, 0xe5, 0x04, 0x00, 0x00, 0x32, 0xb7, - 0x10, 0xe5, 0x5f, 0x04, 0x00, 0x43, 0xb7, - 0x00, 0x21, 0xd4, 0xe5, 0xdd, 0xe5, 0x35, - 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, - /* ch = 'H' */ - 0x1e, 0x36, 0x00, 0x00, 0x00, 0x2d, 0x26, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x50, 0xcf, 0x36, 0x36, 0x36, 0xcf, 0x7c, - 0x50, 0xe5, 0x74, 0x74, 0x74, 0xe5, 0x7c, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0xb7, 0x7c, - /* ch = 'I' */ - 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x00, 0x74, 0x9c, 0xff, 0x87, 0x74, - 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, - 0x1a, 0xcf, 0xdd, 0xff, 0xd4, 0xcf, - /* ch = 'J' */ - 0x00, 0x00, 0x2d, 0x36, 0x36, 0x36, - 0x00, 0x00, 0x58, 0x74, 0xff, 0x9c, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, - 0x10, 0x5a, 0x00, 0x24, 0xff, 0x22, - 0x26, 0xef, 0xdd, 0xf7, 0x66, 0x00, - 0x00, 0x00, 0x15, 0x0c, 0x00, 0x00, - /* ch = 'K' */ - 0x26, 0x2d, 0x00, 0x00, 0x00, 0x30, 0x2b, - 0x7c, 0x7c, 0x00, 0x00, 0x50, 0xdb, 0x19, - 0x7c, 0x7c, 0x00, 0x32, 0xf7, 0x1f, 0x00, - 0x7c, 0x7c, 0x32, 0xff, 0x32, 0x00, 0x00, - 0x7c, 0xb7, 0xf7, 0x59, 0x00, 0x00, 0x00, - 0x7c, 0xff, 0xd4, 0xb1, 0x04, 0x00, 0x00, - 0x7c, 0x82, 0x10, 0xe5, 0x5f, 0x00, 0x00, - 0x7c, 0x7c, 0x00, 0x35, 0xff, 0x2f, 0x00, - 0x7c, 0x7c, 0x00, 0x00, 0x7c, 0xdb, 0x10, - 0x7c, 0x7c, 0x00, 0x00, 0x10, 0xdb, 0x82, - /* ch = 'L' */ - 0x16, 0x36, 0x0d, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0xd4, 0xcf, 0xcf, 0xcf, 0x67, - /* ch = 'M' */ - 0x26, 0x1e, 0x00, 0x00, 0x00, 0x16, 0x2d, - 0x7c, 0xc8, 0x00, 0x00, 0x00, 0x7c, 0xb7, - 0x7c, 0xff, 0x39, 0x00, 0x1c, 0xff, 0xb7, - 0x7c, 0xff, 0xc8, 0x00, 0x8a, 0xf7, 0xb7, - 0x7c, 0x82, 0xe5, 0x6a, 0xf7, 0x64, 0xb7, - 0x7c, 0x7c, 0x48, 0xff, 0x5a, 0x50, 0xb7, - 0x7c, 0x7c, 0x04, 0xab, 0x0d, 0x50, 0xb7, - 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x50, 0xb7, - /* ch = 'N' */ - 0x1e, 0x2d, 0x00, 0x00, 0x00, 0x26, 0x2b, - 0x50, 0xff, 0x2a, 0x00, 0x00, 0x7c, 0x7c, - 0x50, 0xff, 0xb7, 0x00, 0x00, 0x7c, 0x7c, - 0x50, 0xe5, 0xf7, 0x3b, 0x00, 0x7c, 0x7c, - 0x50, 0xb7, 0x5f, 0xdb, 0x04, 0x7c, 0x7c, - 0x50, 0xb7, 0x0d, 0xe5, 0x50, 0x7c, 0x7c, - 0x50, 0xb7, 0x00, 0x44, 0xf7, 0xa7, 0x7c, - 0x50, 0xb7, 0x00, 0x04, 0xb7, 0xff, 0x7c, - 0x50, 0xb7, 0x00, 0x00, 0x2a, 0xff, 0x7c, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x90, 0x7c, - /* ch = 'O' */ - 0x00, 0x00, 0x1e, 0x36, 0x2a, 0x04, 0x00, - 0x00, 0x77, 0xef, 0x74, 0xd4, 0xc4, 0x0d, - 0x32, 0xf7, 0x1f, 0x00, 0x10, 0xdb, 0x5a, - 0x82, 0x82, 0x00, 0x00, 0x00, 0x5f, 0xcf, - 0xb7, 0x50, 0x00, 0x00, 0x00, 0x32, 0xff, - 0xb7, 0x50, 0x00, 0x00, 0x00, 0x32, 0xff, - 0xb1, 0x6b, 0x00, 0x00, 0x00, 0x35, 0xff, - 0x6b, 0xc8, 0x00, 0x00, 0x00, 0x70, 0xb1, - 0x1c, 0xf7, 0x54, 0x00, 0x21, 0xf7, 0x3b, - 0x00, 0x2c, 0xef, 0xff, 0xf7, 0x66, 0x00, - 0x00, 0x00, 0x00, 0x15, 0x04, 0x00, 0x00, - /* ch = 'P' */ - 0x1e, 0x36, 0x36, 0x36, 0x2a, 0x08, 0x00, - 0x50, 0xff, 0x74, 0x74, 0xdd, 0xef, 0x1f, - 0x50, 0xff, 0x00, 0x00, 0x04, 0xb7, 0x8a, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x70, 0xb7, - 0x50, 0xff, 0x00, 0x00, 0x1e, 0xe5, 0x5a, - 0x50, 0xff, 0xcf, 0xcf, 0xcf, 0x5b, 0x04, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 'Q' */ - 0x00, 0x00, 0x1e, 0x36, 0x2a, 0x04, 0x00, - 0x00, 0x77, 0xef, 0x74, 0xd4, 0xc4, 0x0d, - 0x32, 0xf7, 0x1a, 0x00, 0x08, 0xdb, 0x5a, - 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x50, 0xcf, - 0xb7, 0x50, 0x00, 0x00, 0x00, 0x32, 0xff, - 0xb7, 0x50, 0x00, 0x00, 0x00, 0x32, 0xff, - 0xb1, 0x5f, 0x00, 0x00, 0x00, 0x32, 0xff, - 0x6b, 0xb7, 0x00, 0x00, 0x00, 0x5f, 0xb1, - 0x1c, 0xf7, 0x50, 0x00, 0x21, 0xf7, 0x3b, - 0x00, 0x2c, 0xef, 0xdd, 0xff, 0x66, 0x00, - 0x00, 0x00, 0x00, 0xe5, 0x3b, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x50, 0xf7, 0xcf, 0x67, - 0x00, 0x00, 0x00, 0x00, 0x0f, 0x15, 0x0f, - /* ch = 'R' */ - 0x1e, 0x36, 0x36, 0x36, 0x25, 0x04, 0x00, - 0x50, 0xe5, 0x74, 0x74, 0xe5, 0xd4, 0x10, - 0x50, 0xb7, 0x00, 0x00, 0x04, 0xcf, 0x6b, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x82, 0x7c, - 0x50, 0xb7, 0x00, 0x00, 0x2b, 0xf7, 0x39, - 0x50, 0xf7, 0xcf, 0xef, 0xf7, 0x50, 0x00, - 0x50, 0xb7, 0x00, 0x2c, 0xff, 0x1c, 0x00, - 0x50, 0xb7, 0x00, 0x00, 0xa7, 0x7c, 0x00, - 0x50, 0xb7, 0x00, 0x00, 0x2c, 0xff, 0x1c, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0xa7, 0x90, - /* ch = 'S' */ - 0x00, 0x00, 0x18, 0x36, 0x2a, 0x08, 0x00, - 0x00, 0x77, 0xdb, 0x67, 0xa4, 0xef, 0x24, - 0x1a, 0xff, 0x24, 0x00, 0x00, 0x3d, 0x10, - 0x1a, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x66, 0xf7, 0x73, 0x16, 0x00, 0x00, - 0x00, 0x00, 0x1e, 0x9e, 0xff, 0x7e, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x13, 0xdb, 0x6b, - 0x00, 0x0c, 0x00, 0x00, 0x00, 0x59, 0xb7, - 0x2a, 0xb1, 0x10, 0x00, 0x10, 0xc8, 0x66, - 0x10, 0x94, 0xff, 0xcf, 0xf7, 0x94, 0x04, - 0x00, 0x00, 0x08, 0x15, 0x08, 0x00, 0x00, - /* ch = 'T' */ - 0x2d, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x58, 0x74, 0x87, 0xff, 0x87, 0x74, 0x74, - 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, - /* ch = 'U' */ - 0x1e, 0x33, 0x00, 0x00, 0x00, 0x1e, 0x2d, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x5f, 0xb1, - 0x2a, 0xff, 0x26, 0x00, 0x10, 0xdb, 0x5a, - 0x00, 0x5a, 0xf7, 0xcf, 0xf7, 0x7e, 0x04, - 0x00, 0x00, 0x04, 0x15, 0x08, 0x00, 0x00, - /* ch = 'V' */ - 0x33, 0x1e, 0x00, 0x00, 0x00, 0x10, 0x36, 0x0d, - 0x7c, 0xa0, 0x00, 0x00, 0x00, 0x48, 0xcf, 0x00, - 0x32, 0xff, 0x14, 0x00, 0x00, 0xa0, 0x5f, 0x00, - 0x04, 0xf7, 0x44, 0x00, 0x14, 0xff, 0x24, 0x00, - 0x00, 0x7c, 0xa0, 0x00, 0x3b, 0xcf, 0x00, 0x00, - 0x00, 0x2c, 0xff, 0x14, 0x90, 0x5f, 0x00, 0x00, - 0x00, 0x04, 0xe5, 0x50, 0xff, 0x24, 0x00, 0x00, - 0x00, 0x00, 0x70, 0xf7, 0xcf, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x2c, 0xff, 0x5f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x04, 0xe5, 0x24, 0x00, 0x00, 0x00, - /* ch = 'W' */ - 0x36, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x16, - 0xe5, 0x35, 0x00, 0x42, 0x14, 0x00, 0xff, 0x1c, - 0xa0, 0x54, 0x00, 0xcf, 0x3b, 0x1c, 0xff, 0x04, - 0x77, 0x7c, 0x1c, 0xff, 0x77, 0x2f, 0xbd, 0x00, - 0x4d, 0xb7, 0x44, 0xf7, 0xcf, 0x44, 0x82, 0x00, - 0x2f, 0xff, 0x90, 0x50, 0xff, 0x82, 0x5f, 0x00, - 0x1a, 0xff, 0xff, 0x14, 0xb7, 0xff, 0x3b, 0x00, - 0x00, 0xff, 0xcf, 0x00, 0x5f, 0xff, 0x24, 0x00, - 0x00, 0xb7, 0x6b, 0x00, 0x32, 0xff, 0x0d, 0x00, - 0x00, 0x7c, 0x32, 0x00, 0x0d, 0xe5, 0x00, 0x00, - /* ch = 'X' */ - 0x24, 0x30, 0x00, 0x00, 0x00, 0x28, 0x26, - 0x24, 0xff, 0x2a, 0x00, 0x17, 0xf7, 0x2a, - 0x00, 0x7c, 0xb7, 0x00, 0x7c, 0xa0, 0x00, - 0x00, 0x17, 0xf7, 0x6a, 0xff, 0x2a, 0x00, - 0x00, 0x00, 0x5f, 0xff, 0x90, 0x00, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x54, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0xdb, 0xf7, 0x10, 0x00, - 0x00, 0x3b, 0xf7, 0x1a, 0xc8, 0x6b, 0x00, - 0x04, 0xdb, 0x5f, 0x00, 0x32, 0xff, 0x1c, - 0x44, 0xf7, 0x0d, 0x00, 0x00, 0xa0, 0x90, - /* ch = 'Y' */ - 0x2d, 0x26, 0x00, 0x00, 0x00, 0x19, 0x36, 0x09, - 0x48, 0xf7, 0x10, 0x00, 0x00, 0x90, 0x8a, 0x00, - 0x04, 0xe5, 0x5f, 0x00, 0x22, 0xff, 0x22, 0x00, - 0x00, 0x48, 0xf7, 0x10, 0x70, 0xa0, 0x00, 0x00, - 0x00, 0x04, 0xdb, 0x7c, 0xff, 0x2c, 0x00, 0x00, - 0x00, 0x00, 0x44, 0xff, 0xa7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x04, 0xff, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, - /* ch = 'Z' */ - 0x16, 0x36, 0x36, 0x36, 0x36, 0x36, 0x26, - 0x22, 0x74, 0x74, 0x74, 0x74, 0xff, 0x66, - 0x00, 0x00, 0x00, 0x00, 0x44, 0xe5, 0x10, - 0x00, 0x00, 0x00, 0x10, 0xe5, 0x44, 0x00, - 0x00, 0x00, 0x00, 0x77, 0xb7, 0x00, 0x00, - 0x00, 0x00, 0x2a, 0xff, 0x24, 0x00, 0x00, - 0x00, 0x04, 0xc8, 0x6b, 0x00, 0x00, 0x00, - 0x00, 0x4d, 0xe5, 0x10, 0x00, 0x00, 0x00, - 0x17, 0xf7, 0x44, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* ch = '[' */ - 0x32, 0xff, 0xcf, 0xcf, 0xcf, 0x2d, - 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x74, 0x74, 0x74, 0x22, - 0x16, 0x36, 0x36, 0x36, 0x36, 0x16, - /* ch = '\' */ - 0x20, 0xe5, 0x10, - 0x04, 0xc8, 0x5a, - 0x00, 0x48, 0xe5, - 0x00, 0x04, 0xe5, - 0x00, 0x00, 0x5a, - 0x00, 0x00, 0x0d, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* ch = ']' */ - 0x00, 0xcf, 0xcf, 0xcf, 0xf7, 0x50, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x14, 0x74, 0x74, 0x74, 0xe5, 0x50, - 0x0d, 0x36, 0x36, 0x36, 0x36, 0x1e, - /* ch = '^' */ - 0x00, 0x00, 0x28, 0x04, 0x00, - 0x00, 0x1c, 0xf7, 0x44, 0x00, - 0x00, 0x90, 0xd4, 0xe5, 0x0d, - 0x32, 0xe5, 0x10, 0xb7, 0x50, - 0x82, 0x32, 0x00, 0x2a, 0xa5, - /* ch = '_' */ - 0x95, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, - 0x12, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - /* ch = '`' */ - 0x17, 0xf7, 0x17, - 0x00, 0xa7, 0x64, - 0x00, 0x39, 0xff, - 0x00, 0x00, 0x30, - /* ch = 'a' */ - 0x00, 0x37, 0xdd, 0xf7, 0xef, 0x50, 0x00, - 0x00, 0x3d, 0x1b, 0x00, 0x1f, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x50, 0xdd, 0xcf, 0xcf, 0xf7, 0x50, - 0x40, 0xf7, 0x13, 0x00, 0x00, 0xb7, 0x50, - 0x5a, 0xcf, 0x04, 0x00, 0x2c, 0xff, 0x50, - 0x10, 0xd4, 0xdd, 0xbd, 0xcb, 0xe5, 0x50, - 0x00, 0x00, 0x12, 0x0f, 0x00, 0x00, 0x00, - /* ch = 'b' */ - 0x50, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x7e, 0xff, 0xf7, 0x66, 0x00, - 0x50, 0xff, 0x54, 0x00, 0x35, 0xff, 0x44, - 0x50, 0xff, 0x04, 0x00, 0x00, 0xa0, 0xa0, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x7c, 0xb7, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x82, 0xa0, - 0x50, 0xff, 0x35, 0x00, 0x21, 0xf7, 0x44, - 0x50, 0xb7, 0xd4, 0xd4, 0xff, 0x77, 0x00, - 0x00, 0x00, 0x00, 0x12, 0x0c, 0x00, 0x00, - /* ch = 'c' */ - 0x00, 0x10, 0x8d, 0xf7, 0xff, 0xab, 0x19, - 0x04, 0xb7, 0x8a, 0x08, 0x08, 0x7c, 0x73, - 0x32, 0xff, 0x17, 0x00, 0x00, 0x08, 0x04, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3b, 0xff, 0x17, 0x00, 0x00, 0x00, 0x00, - 0x0d, 0xdb, 0x8a, 0x04, 0x00, 0x37, 0x26, - 0x00, 0x1f, 0xd4, 0xef, 0xe5, 0xe5, 0x2c, - 0x00, 0x00, 0x00, 0x12, 0x12, 0x00, 0x00, - /* ch = 'd' */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x5f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x35, 0xe5, 0xe5, 0xcb, 0xcf, 0x50, - 0x22, 0xff, 0x32, 0x00, 0x35, 0xff, 0x50, - 0x5f, 0xbd, 0x00, 0x00, 0x00, 0xcf, 0x5f, - 0x7c, 0x82, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x5f, 0xbd, 0x00, 0x00, 0x00, 0xcf, 0x7c, - 0x2a, 0xff, 0x32, 0x00, 0x37, 0xff, 0x7c, - 0x00, 0x5a, 0xff, 0xdd, 0xd4, 0xcf, 0x7c, - 0x00, 0x00, 0x0c, 0x12, 0x00, 0x00, 0x00, - /* ch = 'e' */ - 0x00, 0x26, 0xcb, 0xdd, 0xef, 0x48, 0x00, - 0x17, 0xf7, 0x37, 0x00, 0x1f, 0xf7, 0x2a, - 0x44, 0xd9, 0x15, 0x15, 0x15, 0x9e, 0x6b, - 0x6b, 0xf7, 0xcf, 0xcf, 0xcf, 0xcf, 0x67, - 0x50, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x22, 0xff, 0x37, 0x00, 0x00, 0x2a, 0x08, - 0x00, 0x35, 0xef, 0xd4, 0xdd, 0xbb, 0x19, - 0x00, 0x00, 0x00, 0x15, 0x0f, 0x00, 0x00, - /* ch = 'f' */ - 0x10, 0xb3, 0xe5, 0xef, 0x8d, 0x04, - 0x8a, 0xa0, 0x04, 0x04, 0x8d, 0x04, - 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, - 0xcf, 0x82, 0x36, 0x26, 0x00, 0x00, - 0xcf, 0x82, 0x36, 0x26, 0x00, 0x00, - 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, - 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, - 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, - 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, - 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, - /* ch = 'g' */ - 0x44, 0xef, 0xdd, 0xbb, 0xcb, 0xd4, 0x09, - 0xff, 0x1f, 0x00, 0x82, 0x90, 0x00, 0x00, - 0xcf, 0x00, 0x00, 0x50, 0xb7, 0x00, 0x00, - 0xf7, 0x5f, 0x2b, 0xdb, 0x4d, 0x00, 0x00, - 0x82, 0x95, 0x74, 0x37, 0x00, 0x00, 0x00, - 0xff, 0x2d, 0x15, 0x15, 0x08, 0x00, 0x00, - 0xc4, 0x9e, 0xcf, 0xcf, 0xf7, 0x49, 0x00, - 0x75, 0x00, 0x00, 0x00, 0x59, 0xb7, 0x00, - 0xdb, 0x37, 0x15, 0x37, 0xdb, 0x4d, 0x00, - 0x2a, 0x5b, 0x74, 0x5b, 0x1e, 0x00, 0x00, - /* ch = 'h' */ - 0x32, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x54, 0xef, 0xff, 0x7e, 0x00, - 0x32, 0xff, 0xb1, 0x13, 0x21, 0xff, 0x32, - 0x32, 0xff, 0x24, 0x00, 0x00, 0xe5, 0x50, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0xb7, 0x50, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0xb7, 0x50, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0xb7, 0x50, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0xb7, 0x50, - /* ch = 'i' */ - 0x00, 0x17, 0xcf, 0x39, 0x00, - 0x00, 0x10, 0x9e, 0x2a, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x67, 0xcf, 0xcf, 0x2d, 0x00, - 0x00, 0x1c, 0xff, 0x32, 0x00, - 0x00, 0x1c, 0xff, 0x32, 0x00, - 0x00, 0x1c, 0xff, 0x32, 0x00, - 0x00, 0x1c, 0xff, 0x32, 0x00, - 0x00, 0x1c, 0xff, 0x32, 0x00, - 0x95, 0xd4, 0xff, 0xdd, 0xcf, - /* ch = 'j' */ - 0x00, 0x00, 0x00, 0x04, 0xbd, 0x57, - 0x00, 0x00, 0x00, 0x00, 0x8d, 0x39, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x45, 0xcf, 0xcf, 0xcf, 0x45, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x0c, 0x00, 0x04, 0xf7, 0x44, - 0x45, 0xdb, 0x3e, 0x8a, 0xdb, 0x10, - 0x04, 0x3f, 0x74, 0x5b, 0x13, 0x00, - /* ch = 'k' */ - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x26, 0xcf, 0x2d, 0x00, - 0x32, 0xff, 0x1c, 0x32, 0xef, 0x32, 0x00, 0x00, - 0x32, 0xff, 0x5f, 0xf7, 0x2c, 0x00, 0x00, 0x00, - 0x32, 0xff, 0xef, 0xff, 0x32, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x21, 0x7c, 0xf7, 0x1f, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x04, 0xb1, 0xdb, 0x10, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x10, 0xdb, 0xb1, 0x04, - /* ch = 'l' */ - 0x00, 0xff, 0xff, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, - 0x1a, 0xcf, 0xd4, 0xff, 0xdd, 0xcf, 0x2d, - /* ch = 'm' */ - 0x95, 0xbd, 0xef, 0xd4, 0xa2, 0xef, 0x8b, - 0xb7, 0x97, 0x0d, 0xff, 0x5f, 0x35, 0xff, - 0xb7, 0x50, 0x00, 0xff, 0x32, 0x32, 0xff, - 0xb7, 0x50, 0x00, 0xff, 0x32, 0x32, 0xff, - 0xb7, 0x50, 0x00, 0xff, 0x32, 0x32, 0xff, - 0xb7, 0x50, 0x00, 0xff, 0x32, 0x32, 0xff, - 0xb7, 0x50, 0x00, 0xff, 0x32, 0x32, 0xff, - /* ch = 'n' */ - 0x2d, 0xcf, 0x50, 0xef, 0xff, 0x7e, 0x00, - 0x32, 0xff, 0xb1, 0x0c, 0x26, 0xff, 0x32, - 0x32, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x50, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0xff, 0x50, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0xff, 0x50, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0xff, 0x50, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0xff, 0x50, - /* ch = 'o' */ - 0x00, 0x21, 0xc4, 0xff, 0xe5, 0x48, 0x00, - 0x17, 0xf7, 0x54, 0x00, 0x28, 0xff, 0x39, - 0x5f, 0xcf, 0x00, 0x00, 0x00, 0x90, 0xa0, - 0x7c, 0xa5, 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x6b, 0xcf, 0x00, 0x00, 0x00, 0x6b, 0xb1, - 0x2a, 0xff, 0x37, 0x00, 0x13, 0xf7, 0x44, - 0x00, 0x3b, 0xf7, 0xd4, 0xf7, 0x66, 0x00, - 0x00, 0x00, 0x04, 0x15, 0x0c, 0x00, 0x00, - /* ch = 'p' */ - 0x45, 0xcf, 0x73, 0xf7, 0xf7, 0x66, 0x04, - 0x50, 0xff, 0x54, 0x00, 0x28, 0xff, 0x4d, - 0x50, 0xff, 0x04, 0x00, 0x00, 0x7c, 0xb1, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x50, 0xef, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x6b, 0xb1, - 0x50, 0xff, 0x35, 0x00, 0x13, 0xe5, 0x5a, - 0x50, 0xff, 0xc4, 0xd4, 0xf7, 0x94, 0x04, - 0x50, 0xff, 0x00, 0x12, 0x0f, 0x00, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1e, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 'q' */ - 0x00, 0x2f, 0xe5, 0xef, 0xcb, 0x9c, 0x67, - 0x22, 0xff, 0x35, 0x00, 0x35, 0xff, 0x7c, - 0x6b, 0xbd, 0x00, 0x00, 0x00, 0xbd, 0x7c, - 0x7c, 0x82, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x6b, 0xcf, 0x00, 0x00, 0x00, 0xcf, 0x7c, - 0x2a, 0xff, 0x35, 0x00, 0x32, 0xff, 0x7c, - 0x00, 0x4d, 0xff, 0xdd, 0xd4, 0xcf, 0x7c, - 0x00, 0x00, 0x08, 0x12, 0x00, 0xb7, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x26, - /* ch = 'r' */ - 0x95, 0x7e, 0x8d, 0xff, 0xf7, 0x60, - 0xb7, 0xff, 0x5f, 0x04, 0x21, 0x51, - 0xb7, 0xb7, 0x00, 0x00, 0x00, 0x00, - 0xb7, 0x5f, 0x00, 0x00, 0x00, 0x00, - 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, - 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, - 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, - /* ch = 's' */ - 0x00, 0x26, 0xcb, 0xd4, 0xef, 0x8d, 0x08, - 0x00, 0xe5, 0x4f, 0x00, 0x08, 0xb1, 0x1f, - 0x00, 0xc8, 0xc4, 0x25, 0x00, 0x00, 0x00, - 0x00, 0x13, 0x7f, 0xef, 0xef, 0x66, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x2b, 0xf7, 0x50, - 0x1c, 0xb1, 0x08, 0x00, 0x08, 0xe5, 0x50, - 0x13, 0x94, 0xf7, 0xcf, 0xef, 0x94, 0x04, - 0x00, 0x00, 0x08, 0x15, 0x0c, 0x00, 0x00, - /* ch = 't' */ - 0x00, 0x00, 0x45, 0xb5, 0x00, 0x00, - 0x00, 0x00, 0x6b, 0xb7, 0x00, 0x00, - 0x2d, 0xcf, 0xef, 0xef, 0xcf, 0xcf, - 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb1, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xa0, 0xa7, 0x00, 0x1b, - 0x00, 0x00, 0x2f, 0xf7, 0xef, 0xef, - 0x00, 0x00, 0x00, 0x04, 0x12, 0x00, - /* ch = 'u' */ - 0x2d, 0xcf, 0x00, 0x00, 0x00, 0x95, 0x45, - 0x32, 0xff, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x32, 0xff, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x32, 0xff, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x32, 0xff, 0x04, 0x00, 0x00, 0xf7, 0x50, - 0x22, 0xff, 0x35, 0x00, 0x35, 0xff, 0x50, - 0x00, 0x66, 0xf7, 0xcf, 0xbb, 0xcf, 0x54, - 0x00, 0x00, 0x0c, 0x12, 0x00, 0x00, 0x00, - /* ch = 'v' */ - 0x58, 0xab, 0x00, 0x00, 0x00, 0x51, 0x82, - 0x22, 0xff, 0x24, 0x00, 0x00, 0xb7, 0x48, - 0x00, 0xa7, 0x70, 0x00, 0x22, 0xff, 0x0d, - 0x00, 0x3b, 0xf7, 0x0d, 0x70, 0x8a, 0x00, - 0x00, 0x0d, 0xf7, 0x54, 0xf7, 0x22, 0x00, - 0x00, 0x00, 0x70, 0xff, 0xa7, 0x00, 0x00, - 0x00, 0x00, 0x22, 0xff, 0x39, 0x00, 0x00, - /* ch = 'w' */ - 0xdd, 0x2d, 0x00, 0x12, 0x04, 0x1a, 0xcf, 0x1a, - 0xb1, 0x44, 0x0d, 0xff, 0x32, 0x1c, 0xff, 0x00, - 0x77, 0x77, 0x2a, 0xff, 0x70, 0x32, 0xbd, 0x00, - 0x44, 0xbd, 0x54, 0xb7, 0xe5, 0x44, 0x82, 0x00, - 0x24, 0xff, 0xb7, 0x2c, 0xf7, 0xb7, 0x54, 0x00, - 0x04, 0xff, 0xf7, 0x04, 0x90, 0xff, 0x35, 0x00, - 0x00, 0xb1, 0x90, 0x00, 0x44, 0xff, 0x1c, 0x00, - /* ch = 'x' */ - 0x28, 0xcf, 0x1f, 0x00, 0x1c, 0xcf, 0x28, - 0x00, 0x77, 0xb7, 0x08, 0xb1, 0x77, 0x00, - 0x00, 0x04, 0xdb, 0xd4, 0xdb, 0x0d, 0x00, - 0x00, 0x00, 0x31, 0xff, 0x4a, 0x00, 0x00, - 0x00, 0x04, 0xc8, 0xd4, 0xe5, 0x10, 0x00, - 0x00, 0x6b, 0xdb, 0x04, 0xb1, 0xa0, 0x00, - 0x2c, 0xff, 0x2a, 0x00, 0x10, 0xf7, 0x50, - /* ch = 'y' */ - 0x4a, 0xcf, 0x04, 0x00, 0x00, 0x5c, 0xa2, - 0x17, 0xff, 0x39, 0x00, 0x00, 0xc8, 0x48, - 0x00, 0x8a, 0xa0, 0x00, 0x22, 0xff, 0x17, - 0x00, 0x2c, 0xff, 0x17, 0x5f, 0x90, 0x00, - 0x00, 0x00, 0xc8, 0x5a, 0xe5, 0x39, 0x00, - 0x00, 0x00, 0x48, 0xff, 0xe5, 0x04, 0x00, - 0x00, 0x00, 0x0d, 0xf7, 0x70, 0x00, 0x00, - 0x00, 0x00, 0x17, 0xff, 0x22, 0x00, 0x00, - 0x82, 0x3e, 0xb1, 0xa0, 0x00, 0x00, 0x00, - 0x2e, 0x74, 0x50, 0x08, 0x00, 0x00, 0x00, - /* ch = 'z' */ - 0x2d, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x2d, - 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb1, 0x04, - 0x00, 0x00, 0x00, 0x50, 0xf7, 0x1c, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x1f, 0xf7, 0x50, 0x00, 0x00, 0x00, - 0x10, 0xdb, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, - /* ch = '{' */ - 0x00, 0x2a, 0x74, 0x74, 0x14, - 0x4d, 0xdb, 0x30, 0x30, 0x0d, - 0xb7, 0x54, 0x00, 0x00, 0x00, - 0xb7, 0x50, 0x00, 0x00, 0x00, - 0xbd, 0x4d, 0x00, 0x00, 0x00, - 0xdb, 0x10, 0x00, 0x00, 0x00, - 0x99, 0x04, 0x00, 0x00, 0x00, - 0xf7, 0x32, 0x00, 0x00, 0x00, - 0xb7, 0x50, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, - 0xbd, 0x5f, 0x00, 0x00, 0x00, - 0x4d, 0xf7, 0x5b, 0x36, 0x0d, - 0x00, 0x18, 0x36, 0x36, 0x0d, - /* ch = '|' */ - 0x1a, 0xcf, 0x2d, - 0x1c, 0xff, 0x32, - 0x1c, 0xff, 0x32, - 0x1c, 0xff, 0x32, - 0x1c, 0xff, 0x32, - 0x1c, 0xff, 0x32, - 0x1c, 0xff, 0x32, - 0x1c, 0xff, 0x32, - 0x1c, 0xff, 0x32, - 0x1c, 0xff, 0x32, - 0x1c, 0xff, 0x32, - 0x1c, 0xff, 0x32, - 0x04, 0x15, 0x08, - /* ch = '}' */ - 0x74, 0x74, 0x37, 0x04, - 0x36, 0x2a, 0xb1, 0x77, - 0x00, 0x00, 0x35, 0xff, - 0x00, 0x00, 0x32, 0xff, - 0x00, 0x00, 0x2f, 0xff, - 0x00, 0x00, 0x04, 0xb1, - 0x00, 0x00, 0x00, 0x6b, - 0x00, 0x00, 0x1c, 0xff, - 0x00, 0x00, 0x32, 0xff, - 0x00, 0x00, 0x32, 0xff, - 0x00, 0x00, 0x3b, 0xff, - 0x36, 0x50, 0xdb, 0x77, - 0x36, 0x36, 0x20, 0x00, - /* ch = '~' */ - 0x10, 0xab, 0xff, 0xa2, 0x13, 0x1f, 0x8d, 0x09, - 0x3e, 0x73, 0x08, 0x6b, 0xf7, 0xef, 0x4d, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x00, 0x00 + /* ch = '!' */ + 0x39, 0xff, 0x27, 0x50, 0xff, 0x32, 0x32, 0xff, 0x32, 0x32, 0xff, 0x1c, + 0x24, 0xff, 0x1c, 0x1c, 0xff, 0x0d, 0x1c, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x1f, 0x74, 0x10, 0x66, 0xff, 0x40, 0x04, 0x15, 0x00, + /* ch = '"' */ + 0x22, 0xff, 0x27, 0x66, 0xb1, 0x1f, 0xff, 0x2a, 0x7c, 0xbd, 0x32, 0xe5, + 0x04, 0x90, 0x5f, 0x46, 0x60, 0x00, 0xa5, 0x22, + /* ch = '#' */ + 0x00, 0x00, 0x28, 0x1e, 0x04, 0x2a, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x3b, + 0x2f, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x2f, 0x3b, 0xb7, 0x00, 0x00, + 0x6c, 0xcf, 0xff, 0xb1, 0xcf, 0xe5, 0xa2, 0x11, 0x00, 0x1c, 0xff, 0x04, + 0x7c, 0x6b, 0x00, 0x00, 0x00, 0x32, 0xcf, 0x00, 0xa0, 0x50, 0x00, 0x00, + 0x5c, 0x9c, 0xe5, 0x74, 0xe5, 0x9c, 0x58, 0x00, 0x15, 0x62, 0x88, 0x15, + 0xff, 0x24, 0x00, 0x00, 0x00, 0x7c, 0x54, 0x1a, 0xff, 0x1a, 0x00, 0x00, + 0x00, 0x8f, 0x3e, 0x1f, 0xcf, 0x00, 0x00, 0x00, + /* ch = '$' */ + 0x00, 0x00, 0x00, 0x95, 0x3a, 0x00, 0x00, 0x00, 0x19, 0x9e, 0xf7, 0xdd, + 0x66, 0x04, 0x04, 0xdb, 0x54, 0xb7, 0x3a, 0xa0, 0x49, 0x1a, 0xff, 0x26, + 0xb7, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xef, 0xe5, 0x32, 0x00, 0x00, 0x00, + 0x00, 0x31, 0xe5, 0xff, 0x8d, 0x10, 0x00, 0x00, 0x00, 0xb7, 0x37, 0xb1, + 0x8a, 0x00, 0x21, 0x00, 0xb7, 0x32, 0x50, 0xb7, 0x2d, 0xf7, 0x37, 0xbd, + 0x4f, 0xdb, 0x4d, 0x00, 0x22, 0x8f, 0xf7, 0xbb, 0x37, 0x00, 0x00, 0x00, + 0x00, 0x58, 0x22, 0x00, 0x00, + /* ch = '%' */ + 0x08, 0x47, 0x37, 0x04, 0x00, 0x21, 0x2b, 0x8a, 0x8a, 0xb1, 0x5a, 0x04, + 0xdb, 0x3b, 0xb7, 0x32, 0x50, 0xa9, 0x50, 0xb7, 0x00, 0x6b, 0xa0, 0xb7, + 0x5f, 0xf7, 0x2a, 0x00, 0x04, 0x30, 0x2a, 0x6b, 0x90, 0x00, 0x00, 0x00, + 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x90, 0x6b, 0x50, 0xbd, + 0x35, 0x00, 0x2a, 0xf7, 0x3f, 0xe5, 0x24, 0xff, 0x00, 0xb7, 0x50, 0x44, + 0xbd, 0x04, 0xff, 0x3b, 0xdb, 0x04, 0x10, 0xdb, 0xc4, 0xa9, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x15, 0x00, + /* ch = '&' */ + 0x00, 0x00, 0x2a, 0x36, 0x13, 0x00, 0x00, 0x00, 0x00, 0x77, 0xdb, 0x85, + 0xf7, 0x17, 0x00, 0x00, 0x00, 0xef, 0x47, 0x00, 0xd9, 0x40, 0x00, 0x00, + 0x00, 0x8a, 0x90, 0x17, 0xff, 0x22, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xef, + 0x4d, 0x00, 0x00, 0x00, 0x04, 0x94, 0xef, 0xf7, 0x1f, 0x04, 0x0c, 0x00, + 0x48, 0xf7, 0x10, 0x7c, 0xb1, 0x2f, 0xf7, 0x0a, 0xa0, 0x82, 0x00, 0x0d, + 0xdb, 0xff, 0x54, 0x00, 0x7c, 0xc8, 0x08, 0x08, 0xb1, 0xff, 0x35, 0x00, + 0x1f, 0xd4, 0xef, 0xf7, 0x7e, 0x59, 0xd4, 0x0a, 0x00, 0x00, 0x15, 0x08, + 0x00, 0x04, 0x08, 0x00, + /* ch = ''' */ + 0x00, 0x99, 0x84, 0x00, 0xb7, 0x82, 0x00, 0xcf, 0x3b, 0x11, 0xbd, 0x0d, + /* ch = '(' */ + 0x00, 0x00, 0x35, 0xef, 0x00, 0x50, 0xf7, 0x26, 0x2a, 0xff, 0x2c, 0x00, + 0xa0, 0x8a, 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, 0xff, 0x1c, 0x00, 0x00, + 0xff, 0x1c, 0x00, 0x00, 0xff, 0x2a, 0x00, 0x00, 0xc8, 0x64, 0x00, 0x00, + 0x44, 0xf7, 0x10, 0x00, 0x04, 0xb1, 0xb1, 0x04, 0x00, 0x10, 0xc4, 0xc4, + 0x00, 0x00, 0x04, 0x51, + /* ch = ')' */ + 0xe5, 0x35, 0x00, 0x00, 0x3f, 0xf7, 0x50, 0x00, 0x00, 0x32, 0xff, 0x2f, + 0x00, 0x00, 0x70, 0xc8, 0x00, 0x00, 0x24, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x0d, 0xff, 0x00, 0x00, 0x39, 0xf7, + 0x00, 0x04, 0xc8, 0x6b, 0x04, 0x7c, 0xdb, 0x10, 0xa9, 0xd4, 0x19, 0x00, + 0x50, 0x08, 0x00, 0x00, + /* ch = '*' */ + 0x00, 0x00, 0x17, 0xcf, 0x2d, 0x00, 0x00, 0x08, 0x08, 0x00, 0xff, 0x24, + 0x04, 0x0c, 0x58, 0xf7, 0x66, 0xff, 0x6b, 0xe5, 0x87, 0x00, 0x0c, 0x51, + 0xff, 0x6c, 0x0c, 0x00, 0x00, 0x10, 0xdb, 0x54, 0xf7, 0x1f, 0x00, 0x00, + 0xa9, 0x7c, 0x00, 0x54, 0xdb, 0x09, 0x00, 0x1b, 0x10, 0x00, 0x04, 0x21, + 0x00, + /* ch = '+' */ + 0x00, 0x00, 0x00, 0xcf, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, + 0x00, 0x00, 0x0f, 0x15, 0x15, 0xff, 0x3e, 0x15, 0x12, 0x42, 0x74, 0x74, + 0xff, 0x9c, 0x74, 0x58, 0x00, 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x16, 0x00, + 0x00, + /* ch = ',' */ + 0x19, 0x5b, 0x10, 0x66, 0xff, 0x5a, 0x04, 0xea, 0x39, 0x35, 0xb1, 0x04, + 0x3d, 0x10, 0x00, + /* ch = '-' */ + 0x08, 0x15, 0x15, 0x15, 0x15, 0x15, 0x0c, 0x2d, 0xcf, 0xcf, 0xcf, 0xcf, + 0xcf, 0x45, + /* ch = '.' */ + 0x19, 0x67, 0x10, 0x66, 0xff, 0x40, 0x04, 0x15, 0x00, + /* ch = '/' */ + 0x00, 0xc0, 0x33, 0x39, 0xf7, 0x10, 0xa7, 0x70, 0x00, 0xff, 0x17, 0x00, + 0x8a, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = '0' */ + 0x00, 0x00, 0x16, 0x36, 0x1e, 0x00, 0x00, 0x00, 0x32, 0xef, 0x82, 0xef, + 0x50, 0x00, 0x04, 0xe5, 0x3b, 0x00, 0x26, 0xff, 0x17, 0x32, 0xe5, 0x04, + 0x00, 0x7c, 0xff, 0x50, 0x50, 0xb7, 0x00, 0x50, 0xdb, 0x97, 0x7c, 0x50, + 0x90, 0x24, 0xf7, 0x1f, 0x54, 0x7c, 0x50, 0xcf, 0xdb, 0x3b, 0x00, 0x7c, + 0x7c, 0x2a, 0xff, 0x7c, 0x00, 0x00, 0xb7, 0x4d, 0x00, 0xb7, 0x7c, 0x00, + 0x32, 0xf7, 0x17, 0x00, 0x1f, 0xd4, 0xdd, 0xf7, 0x32, 0x00, 0x00, 0x00, + 0x00, 0x15, 0x08, 0x00, 0x00, + /* ch = '1' */ + 0x00, 0x00, 0x2a, 0x1e, 0x31, 0xd4, 0xff, 0x50, 0x48, 0x20, 0xb7, 0x50, + 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0xb7, 0x50, + 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0xb7, 0x50, + 0x00, 0x00, 0xb7, 0x50, + /* ch = '2' */ + 0x00, 0x00, 0x1e, 0x36, 0x25, 0x00, 0x00, 0x00, 0x77, 0xd4, 0x74, 0xdb, + 0xa9, 0x04, 0x04, 0x7e, 0x10, 0x00, 0x10, 0xff, 0x39, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xcf, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x2a, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x1f, 0xef, 0x50, 0x00, 0x00, 0x00, 0x1f, 0xf7, 0x4d, 0x00, + 0x00, 0x00, 0x10, 0xdb, 0x50, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x82, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, + /* ch = '3' */ + 0x00, 0x00, 0x20, 0x36, 0x18, 0x00, 0x00, 0x00, 0x9c, 0xcb, 0x82, 0xf7, + 0x50, 0x00, 0x00, 0x0c, 0x04, 0x00, 0x2c, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x2c, 0xff, 0x14, 0x00, 0x00, 0x16, 0x3e, 0xdb, 0x4d, 0x00, 0x00, + 0x00, 0x42, 0x82, 0xe5, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0xff, + 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, 0x04, 0x8d, 0x13, 0x00, + 0x37, 0xff, 0x17, 0x08, 0x94, 0xf7, 0xd4, 0xf7, 0x3b, 0x00, 0x00, 0x00, + 0x0c, 0x15, 0x04, 0x00, 0x00, + /* ch = '4' */ + 0x00, 0x00, 0x00, 0x00, 0x28, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, + 0x50, 0x00, 0x00, 0x00, 0x04, 0xb7, 0xff, 0x50, 0x00, 0x00, 0x00, 0x54, + 0x90, 0xb7, 0x50, 0x00, 0x00, 0x1f, 0xf7, 0x10, 0xb7, 0x50, 0x00, 0x04, + 0xb7, 0x3b, 0x00, 0xb7, 0x50, 0x00, 0x50, 0xec, 0x74, 0x74, 0xe5, 0xb1, + 0x58, 0x26, 0x36, 0x36, 0x36, 0xcf, 0x82, 0x2d, 0x00, 0x00, 0x00, 0x00, + 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, + /* ch = '5' */ + 0x00, 0x28, 0x36, 0x36, 0x36, 0x36, 0x16, 0x00, 0xb7, 0xb1, 0x74, 0x74, + 0x74, 0x22, 0x00, 0xb7, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf7, 0xd4, 0xf7, 0x5a, 0x00, 0x00, + 0x67, 0x21, 0x00, 0x21, 0xff, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, + 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x77, 0x13, 0xd4, 0x21, 0x00, + 0x1f, 0xff, 0x39, 0x00, 0x66, 0xf7, 0xcf, 0xf7, 0x66, 0x00, 0x00, 0x00, + 0x04, 0x15, 0x08, 0x00, 0x00, + /* ch = '6' */ + 0x00, 0x00, 0x08, 0x30, 0x36, 0x16, 0x00, 0x00, 0x1f, 0xdb, 0xa4, 0x73, + 0xef, 0x1e, 0x00, 0xa0, 0x82, 0x00, 0x00, 0x0c, 0x00, 0x14, 0xff, 0x2a, + 0x00, 0x00, 0x00, 0x00, 0x2a, 0xff, 0xa2, 0xff, 0xf7, 0x44, 0x00, 0x32, + 0xff, 0x70, 0x04, 0x21, 0xff, 0x2a, 0x32, 0xff, 0x1c, 0x00, 0x00, 0xb7, + 0x50, 0x1a, 0xff, 0x24, 0x00, 0x00, 0xb7, 0x54, 0x00, 0xb7, 0x82, 0x00, + 0x1f, 0xff, 0x2c, 0x00, 0x1f, 0xd4, 0xdd, 0xf7, 0x5a, 0x00, 0x00, 0x00, + 0x00, 0x12, 0x0c, 0x00, 0x00, + /* ch = '7' */ + 0x0d, 0x36, 0x36, 0x36, 0x36, 0x36, 0x1e, 0x14, 0x74, 0x74, 0x74, 0x8d, + 0xff, 0x39, 0x00, 0x00, 0x00, 0x00, 0x50, 0xe5, 0x04, 0x00, 0x00, 0x00, + 0x00, 0xc8, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xff, 0x17, 0x00, 0x00, + 0x00, 0x00, 0x8a, 0x90, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xff, 0x39, 0x00, + 0x00, 0x00, 0x00, 0x44, 0xf7, 0x0d, 0x00, 0x00, 0x00, 0x00, 0xa7, 0x8a, + 0x00, 0x00, 0x00, 0x00, 0x17, 0xff, 0x39, 0x00, 0x00, 0x00, + /* ch = '8' */ + 0x00, 0x00, 0x1e, 0x36, 0x30, 0x04, 0x00, 0x00, 0x50, 0xef, 0x50, 0xc4, + 0xb1, 0x04, 0x00, 0xe5, 0x3b, 0x00, 0x17, 0xff, 0x2f, 0x00, 0xc8, 0x5f, + 0x00, 0x24, 0xff, 0x17, 0x00, 0x2c, 0xf7, 0x85, 0xdb, 0x4d, 0x00, 0x00, + 0x2c, 0xe5, 0x8f, 0xf7, 0x5a, 0x00, 0x17, 0xf7, 0x35, 0x00, 0x1f, 0xff, + 0x39, 0x39, 0xff, 0x00, 0x00, 0x00, 0xb7, 0x77, 0x27, 0xff, 0x37, 0x00, + 0x19, 0xf7, 0x40, 0x00, 0x44, 0xf7, 0xd4, 0xf7, 0x66, 0x00, 0x00, 0x00, + 0x04, 0x15, 0x08, 0x00, 0x00, + /* ch = '9' */ + 0x00, 0x00, 0x1e, 0x36, 0x22, 0x00, 0x00, 0x00, 0x50, 0xef, 0x74, 0xef, + 0x73, 0x00, 0x14, 0xff, 0x2c, 0x00, 0x24, 0xff, 0x22, 0x32, 0xff, 0x04, + 0x00, 0x00, 0xcf, 0x44, 0x24, 0xff, 0x22, 0x00, 0x04, 0xcf, 0x50, 0x00, + 0xa0, 0xc4, 0x36, 0x99, 0xff, 0x50, 0x00, 0x04, 0x48, 0x74, 0x37, 0xbd, + 0x50, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xff, 0x2a, 0x00, 0x3d, 0x04, 0x00, + 0x6f, 0xdb, 0x04, 0x09, 0xa9, 0xef, 0xe5, 0xd4, 0x19, 0x00, 0x00, 0x00, + 0x0f, 0x12, 0x00, 0x00, 0x00, + /* ch = ':' */ + 0x08, 0x30, 0x04, 0x73, 0xff, 0x49, 0x10, 0x36, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x19, 0x67, 0x10, 0x66, 0xff, 0x40, 0x04, 0x15, 0x00, + /* ch = ';' */ + 0x08, 0x30, 0x04, 0x73, 0xff, 0x49, 0x10, 0x36, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x19, 0x5b, 0x10, 0x66, 0xff, 0x5a, 0x04, 0xea, 0x39, + 0x35, 0xb1, 0x04, 0x3d, 0x10, 0x00, + /* ch = '<' */ + 0x00, 0x00, 0x00, 0x04, 0x3d, 0x00, 0x04, 0x3f, 0xef, 0x8d, 0x37, 0xd4, + 0xb3, 0x1e, 0x00, 0xbb, 0x22, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x00, 0xd4, 0xb3, 0x1b, 0x00, 0x00, 0x04, 0x50, 0xf7, 0x73, 0x13, 0x00, + 0x00, 0x13, 0x94, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x0c, + /* ch = '=' */ + 0x42, 0x74, 0x74, 0x74, 0x74, 0x74, 0x58, 0x26, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x2d, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x2d, + /* ch = '>' */ + 0x08, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x5a, 0x08, 0x00, 0x00, 0x16, 0x8d, + 0xef, 0x48, 0x04, 0x00, 0x00, 0x1b, 0x94, 0xef, 0x00, 0x00, 0x00, 0x1b, + 0xc8, 0x00, 0x13, 0x8d, 0xef, 0x37, 0x5a, 0xf7, 0x73, 0x08, 0x00, 0xbb, + 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = '?' */ + 0x00, 0x28, 0xc4, 0xff, 0xe5, 0x44, 0x00, 0x22, 0xff, 0x48, 0x04, 0x54, + 0xff, 0x27, 0x00, 0x0f, 0x00, 0x00, 0x04, 0xff, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x2c, 0xff, 0x39, 0x00, 0x00, 0x00, 0x19, 0xdb, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0x99, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x15, 0x08, 0x00, 0x00, 0x00, 0x00, 0x04, 0x50, + 0x21, 0x00, 0x00, 0x00, 0x00, 0x27, 0xff, 0x99, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x12, 0x08, 0x00, 0x00, + /* ch = '@' */ + 0x00, 0x00, 0x1b, 0x36, 0x36, 0x0c, 0x00, 0x00, 0x4d, 0xd4, 0x3e, 0x5a, + 0xef, 0x1f, 0x2a, 0xf7, 0x10, 0x00, 0x00, 0x50, 0xa0, 0x6b, 0x5f, 0x00, + 0x22, 0x74, 0x9c, 0xf7, 0xb7, 0x35, 0x39, 0xdb, 0x25, 0x3a, 0xff, 0xb7, + 0x32, 0x7c, 0x6f, 0x00, 0x35, 0xff, 0xa0, 0x4d, 0x44, 0xdb, 0x3e, 0xc4, + 0xff, 0x50, 0xa7, 0x00, 0x2a, 0x50, 0x30, 0x36, 0x0d, 0xdb, 0x54, 0x00, + 0x00, 0x08, 0x04, 0x00, 0x19, 0xbb, 0xe5, 0xcf, 0xe5, 0x2d, 0x00, 0x00, + 0x00, 0x0f, 0x15, 0x04, 0x00, + /* ch = 'A' */ + 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xf7, + 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x3b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc8, 0xc0, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x22, 0xf7, 0x24, + 0xff, 0x1c, 0x00, 0x00, 0x00, 0x5a, 0x8a, 0x00, 0xa7, 0x5a, 0x00, 0x00, + 0x00, 0xcf, 0xb1, 0x74, 0xb1, 0xe5, 0x00, 0x00, 0x24, 0xff, 0x21, 0x15, + 0x21, 0xff, 0x2c, 0x00, 0x6b, 0xa0, 0x00, 0x00, 0x00, 0x90, 0x8a, 0x00, + 0xe5, 0x44, 0x00, 0x00, 0x00, 0x39, 0xf7, 0x0d, + /* ch = 'B' */ + 0x26, 0x36, 0x36, 0x36, 0x20, 0x00, 0x00, 0x7c, 0xe5, 0x74, 0x74, 0xe5, + 0xb1, 0x0d, 0x7c, 0xb7, 0x00, 0x00, 0x10, 0xff, 0x44, 0x7c, 0xb7, 0x00, + 0x00, 0x0d, 0xff, 0x39, 0x7c, 0xcf, 0x36, 0x50, 0xd4, 0xa9, 0x04, 0x7c, + 0xcf, 0x36, 0x36, 0xa4, 0xbb, 0x10, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0xa7, + 0x7c, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x70, 0xb7, 0x7c, 0xb7, 0x00, 0x00, + 0x1b, 0xe5, 0x5f, 0x7c, 0xff, 0xff, 0xff, 0xef, 0x73, 0x04, + /* ch = 'C' */ + 0x00, 0x00, 0x0c, 0x36, 0x36, 0x0c, 0x00, 0x00, 0x39, 0xef, 0x66, 0x66, + 0xf7, 0x32, 0x17, 0xf7, 0x35, 0x00, 0x00, 0x3f, 0x8d, 0x50, 0xcf, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x90, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x44, 0xf7, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xdb, 0x7c, 0x04, + 0x00, 0x50, 0x5c, 0x00, 0x1f, 0xcb, 0xe5, 0xdd, 0xcb, 0x19, 0x00, 0x00, + 0x00, 0x12, 0x0f, 0x00, 0x00, + /* ch = 'D' */ + 0x1e, 0x36, 0x36, 0x30, 0x0f, 0x00, 0x00, 0x50, 0xe5, 0x74, 0x8f, 0xf7, + 0x66, 0x00, 0x50, 0xb7, 0x00, 0x00, 0x2c, 0xff, 0x2c, 0x50, 0xb7, 0x00, + 0x00, 0x00, 0xa7, 0x7c, 0x50, 0xb7, 0x00, 0x00, 0x00, 0x5f, 0xb7, 0x50, + 0xb7, 0x00, 0x00, 0x00, 0x50, 0xb7, 0x50, 0xb7, 0x00, 0x00, 0x00, 0x5f, + 0xb1, 0x50, 0xb7, 0x00, 0x00, 0x00, 0xc8, 0x5a, 0x50, 0xb7, 0x00, 0x04, + 0x5f, 0xf7, 0x10, 0x50, 0xf7, 0xcf, 0xef, 0xab, 0x19, 0x00, + /* ch = 'E' */ + 0x1e, 0x36, 0x36, 0x36, 0x36, 0x36, 0x26, 0x50, 0xe5, 0x74, 0x74, 0x74, + 0x74, 0x42, 0x50, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xb7, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x50, 0xcf, 0x36, 0x36, 0x36, 0x2d, 0x00, 0x50, + 0xe5, 0x74, 0x74, 0x74, 0x58, 0x00, 0x50, 0xb7, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x50, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xb7, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, + /* ch = 'F' */ + 0x0d, 0x36, 0x36, 0x36, 0x36, 0x36, 0x1e, 0x1c, 0xff, 0x87, 0x74, 0x74, + 0x74, 0x30, 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1c, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x87, 0x74, 0x74, 0x42, 0x00, 0x1c, + 0xff, 0x4a, 0x36, 0x36, 0x26, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, + /* ch = 'G' */ + 0x00, 0x00, 0x0f, 0x36, 0x36, 0x0c, 0x00, 0x00, 0x44, 0xf7, 0x82, 0x8f, + 0xf7, 0x32, 0x22, 0xff, 0x32, 0x00, 0x00, 0x49, 0x4d, 0x5f, 0xa7, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x90, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, + 0x6b, 0x00, 0x0d, 0x36, 0x36, 0x2d, 0x7c, 0x7c, 0x00, 0x0d, 0x36, 0x62, + 0xb7, 0x50, 0xe5, 0x04, 0x00, 0x00, 0x32, 0xb7, 0x10, 0xe5, 0x5f, 0x04, + 0x00, 0x43, 0xb7, 0x00, 0x21, 0xd4, 0xe5, 0xdd, 0xe5, 0x35, 0x00, 0x00, + 0x00, 0x0f, 0x0f, 0x00, 0x00, + /* ch = 'H' */ + 0x1e, 0x36, 0x00, 0x00, 0x00, 0x2d, 0x26, 0x50, 0xb7, 0x00, 0x00, 0x00, + 0xb7, 0x7c, 0x50, 0xb7, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x50, 0xb7, 0x00, + 0x00, 0x00, 0xb7, 0x7c, 0x50, 0xcf, 0x36, 0x36, 0x36, 0xcf, 0x7c, 0x50, + 0xe5, 0x74, 0x74, 0x74, 0xe5, 0x7c, 0x50, 0xb7, 0x00, 0x00, 0x00, 0xb7, + 0x7c, 0x50, 0xb7, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x50, 0xb7, 0x00, 0x00, + 0x00, 0xb7, 0x7c, 0x50, 0xb7, 0x00, 0x00, 0x00, 0xb7, 0x7c, + /* ch = 'I' */ + 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x74, 0x9c, 0xff, 0x87, 0x74, + 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x1a, 0xcf, 0xdd, 0xff, 0xd4, 0xcf, + /* ch = 'J' */ + 0x00, 0x00, 0x2d, 0x36, 0x36, 0x36, 0x00, 0x00, 0x58, 0x74, 0xff, 0x9c, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, + 0x10, 0x5a, 0x00, 0x24, 0xff, 0x22, 0x26, 0xef, 0xdd, 0xf7, 0x66, 0x00, + 0x00, 0x00, 0x15, 0x0c, 0x00, 0x00, + /* ch = 'K' */ + 0x26, 0x2d, 0x00, 0x00, 0x00, 0x30, 0x2b, 0x7c, 0x7c, 0x00, 0x00, 0x50, + 0xdb, 0x19, 0x7c, 0x7c, 0x00, 0x32, 0xf7, 0x1f, 0x00, 0x7c, 0x7c, 0x32, + 0xff, 0x32, 0x00, 0x00, 0x7c, 0xb7, 0xf7, 0x59, 0x00, 0x00, 0x00, 0x7c, + 0xff, 0xd4, 0xb1, 0x04, 0x00, 0x00, 0x7c, 0x82, 0x10, 0xe5, 0x5f, 0x00, + 0x00, 0x7c, 0x7c, 0x00, 0x35, 0xff, 0x2f, 0x00, 0x7c, 0x7c, 0x00, 0x00, + 0x7c, 0xdb, 0x10, 0x7c, 0x7c, 0x00, 0x00, 0x10, 0xdb, 0x82, + /* ch = 'L' */ + 0x16, 0x36, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, + 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, + 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x32, + 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x32, 0xff, 0xd4, 0xcf, 0xcf, 0xcf, 0x67, + /* ch = 'M' */ + 0x26, 0x1e, 0x00, 0x00, 0x00, 0x16, 0x2d, 0x7c, 0xc8, 0x00, 0x00, 0x00, + 0x7c, 0xb7, 0x7c, 0xff, 0x39, 0x00, 0x1c, 0xff, 0xb7, 0x7c, 0xff, 0xc8, + 0x00, 0x8a, 0xf7, 0xb7, 0x7c, 0x82, 0xe5, 0x6a, 0xf7, 0x64, 0xb7, 0x7c, + 0x7c, 0x48, 0xff, 0x5a, 0x50, 0xb7, 0x7c, 0x7c, 0x04, 0xab, 0x0d, 0x50, + 0xb7, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x50, 0xb7, 0x7c, 0x7c, 0x00, 0x00, + 0x00, 0x50, 0xb7, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x50, 0xb7, + /* ch = 'N' */ + 0x1e, 0x2d, 0x00, 0x00, 0x00, 0x26, 0x2b, 0x50, 0xff, 0x2a, 0x00, 0x00, + 0x7c, 0x7c, 0x50, 0xff, 0xb7, 0x00, 0x00, 0x7c, 0x7c, 0x50, 0xe5, 0xf7, + 0x3b, 0x00, 0x7c, 0x7c, 0x50, 0xb7, 0x5f, 0xdb, 0x04, 0x7c, 0x7c, 0x50, + 0xb7, 0x0d, 0xe5, 0x50, 0x7c, 0x7c, 0x50, 0xb7, 0x00, 0x44, 0xf7, 0xa7, + 0x7c, 0x50, 0xb7, 0x00, 0x04, 0xb7, 0xff, 0x7c, 0x50, 0xb7, 0x00, 0x00, + 0x2a, 0xff, 0x7c, 0x50, 0xb7, 0x00, 0x00, 0x00, 0x90, 0x7c, + /* ch = 'O' */ + 0x00, 0x00, 0x1e, 0x36, 0x2a, 0x04, 0x00, 0x00, 0x77, 0xef, 0x74, 0xd4, + 0xc4, 0x0d, 0x32, 0xf7, 0x1f, 0x00, 0x10, 0xdb, 0x5a, 0x82, 0x82, 0x00, + 0x00, 0x00, 0x5f, 0xcf, 0xb7, 0x50, 0x00, 0x00, 0x00, 0x32, 0xff, 0xb7, + 0x50, 0x00, 0x00, 0x00, 0x32, 0xff, 0xb1, 0x6b, 0x00, 0x00, 0x00, 0x35, + 0xff, 0x6b, 0xc8, 0x00, 0x00, 0x00, 0x70, 0xb1, 0x1c, 0xf7, 0x54, 0x00, + 0x21, 0xf7, 0x3b, 0x00, 0x2c, 0xef, 0xff, 0xf7, 0x66, 0x00, 0x00, 0x00, + 0x00, 0x15, 0x04, 0x00, 0x00, + /* ch = 'P' */ + 0x1e, 0x36, 0x36, 0x36, 0x2a, 0x08, 0x00, 0x50, 0xff, 0x74, 0x74, 0xdd, + 0xef, 0x1f, 0x50, 0xff, 0x00, 0x00, 0x04, 0xb7, 0x8a, 0x50, 0xff, 0x00, + 0x00, 0x00, 0x70, 0xb7, 0x50, 0xff, 0x00, 0x00, 0x1e, 0xe5, 0x5a, 0x50, + 0xff, 0xcf, 0xcf, 0xcf, 0x5b, 0x04, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = 'Q' */ + 0x00, 0x00, 0x1e, 0x36, 0x2a, 0x04, 0x00, 0x00, 0x77, 0xef, 0x74, 0xd4, + 0xc4, 0x0d, 0x32, 0xf7, 0x1a, 0x00, 0x08, 0xdb, 0x5a, 0x7c, 0x7c, 0x00, + 0x00, 0x00, 0x50, 0xcf, 0xb7, 0x50, 0x00, 0x00, 0x00, 0x32, 0xff, 0xb7, + 0x50, 0x00, 0x00, 0x00, 0x32, 0xff, 0xb1, 0x5f, 0x00, 0x00, 0x00, 0x32, + 0xff, 0x6b, 0xb7, 0x00, 0x00, 0x00, 0x5f, 0xb1, 0x1c, 0xf7, 0x50, 0x00, + 0x21, 0xf7, 0x3b, 0x00, 0x2c, 0xef, 0xdd, 0xff, 0x66, 0x00, 0x00, 0x00, + 0x00, 0xe5, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf7, 0xcf, 0x67, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x15, 0x0f, + /* ch = 'R' */ + 0x1e, 0x36, 0x36, 0x36, 0x25, 0x04, 0x00, 0x50, 0xe5, 0x74, 0x74, 0xe5, + 0xd4, 0x10, 0x50, 0xb7, 0x00, 0x00, 0x04, 0xcf, 0x6b, 0x50, 0xb7, 0x00, + 0x00, 0x00, 0x82, 0x7c, 0x50, 0xb7, 0x00, 0x00, 0x2b, 0xf7, 0x39, 0x50, + 0xf7, 0xcf, 0xef, 0xf7, 0x50, 0x00, 0x50, 0xb7, 0x00, 0x2c, 0xff, 0x1c, + 0x00, 0x50, 0xb7, 0x00, 0x00, 0xa7, 0x7c, 0x00, 0x50, 0xb7, 0x00, 0x00, + 0x2c, 0xff, 0x1c, 0x50, 0xb7, 0x00, 0x00, 0x00, 0xa7, 0x90, + /* ch = 'S' */ + 0x00, 0x00, 0x18, 0x36, 0x2a, 0x08, 0x00, 0x00, 0x77, 0xdb, 0x67, 0xa4, + 0xef, 0x24, 0x1a, 0xff, 0x24, 0x00, 0x00, 0x3d, 0x10, 0x1a, 0xff, 0x3b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0xf7, 0x73, 0x16, 0x00, 0x00, 0x00, + 0x00, 0x1e, 0x9e, 0xff, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0xdb, + 0x6b, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x59, 0xb7, 0x2a, 0xb1, 0x10, 0x00, + 0x10, 0xc8, 0x66, 0x10, 0x94, 0xff, 0xcf, 0xf7, 0x94, 0x04, 0x00, 0x00, + 0x08, 0x15, 0x08, 0x00, 0x00, + /* ch = 'T' */ + 0x2d, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x58, 0x74, 0x87, 0xff, 0x87, + 0x74, 0x74, 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x1c, + 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, + 0x1c, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, + /* ch = 'U' */ + 0x1e, 0x33, 0x00, 0x00, 0x00, 0x1e, 0x2d, 0x50, 0xb7, 0x00, 0x00, 0x00, + 0x50, 0xb7, 0x50, 0xb7, 0x00, 0x00, 0x00, 0x50, 0xb7, 0x50, 0xb7, 0x00, + 0x00, 0x00, 0x50, 0xb7, 0x50, 0xb7, 0x00, 0x00, 0x00, 0x50, 0xb7, 0x50, + 0xb7, 0x00, 0x00, 0x00, 0x50, 0xb7, 0x50, 0xb7, 0x00, 0x00, 0x00, 0x50, + 0xb7, 0x50, 0xb7, 0x00, 0x00, 0x00, 0x5f, 0xb1, 0x2a, 0xff, 0x26, 0x00, + 0x10, 0xdb, 0x5a, 0x00, 0x5a, 0xf7, 0xcf, 0xf7, 0x7e, 0x04, 0x00, 0x00, + 0x04, 0x15, 0x08, 0x00, 0x00, + /* ch = 'V' */ + 0x33, 0x1e, 0x00, 0x00, 0x00, 0x10, 0x36, 0x0d, 0x7c, 0xa0, 0x00, 0x00, + 0x00, 0x48, 0xcf, 0x00, 0x32, 0xff, 0x14, 0x00, 0x00, 0xa0, 0x5f, 0x00, + 0x04, 0xf7, 0x44, 0x00, 0x14, 0xff, 0x24, 0x00, 0x00, 0x7c, 0xa0, 0x00, + 0x3b, 0xcf, 0x00, 0x00, 0x00, 0x2c, 0xff, 0x14, 0x90, 0x5f, 0x00, 0x00, + 0x00, 0x04, 0xe5, 0x50, 0xff, 0x24, 0x00, 0x00, 0x00, 0x00, 0x70, 0xf7, + 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xff, 0x5f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe5, 0x24, 0x00, 0x00, 0x00, + /* ch = 'W' */ + 0x36, 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x16, 0xe5, 0x35, 0x00, 0x42, + 0x14, 0x00, 0xff, 0x1c, 0xa0, 0x54, 0x00, 0xcf, 0x3b, 0x1c, 0xff, 0x04, + 0x77, 0x7c, 0x1c, 0xff, 0x77, 0x2f, 0xbd, 0x00, 0x4d, 0xb7, 0x44, 0xf7, + 0xcf, 0x44, 0x82, 0x00, 0x2f, 0xff, 0x90, 0x50, 0xff, 0x82, 0x5f, 0x00, + 0x1a, 0xff, 0xff, 0x14, 0xb7, 0xff, 0x3b, 0x00, 0x00, 0xff, 0xcf, 0x00, + 0x5f, 0xff, 0x24, 0x00, 0x00, 0xb7, 0x6b, 0x00, 0x32, 0xff, 0x0d, 0x00, + 0x00, 0x7c, 0x32, 0x00, 0x0d, 0xe5, 0x00, 0x00, + /* ch = 'X' */ + 0x24, 0x30, 0x00, 0x00, 0x00, 0x28, 0x26, 0x24, 0xff, 0x2a, 0x00, 0x17, + 0xf7, 0x2a, 0x00, 0x7c, 0xb7, 0x00, 0x7c, 0xa0, 0x00, 0x00, 0x17, 0xf7, + 0x6a, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x5f, 0xff, 0x90, 0x00, 0x00, 0x00, + 0x00, 0x32, 0xff, 0x54, 0x00, 0x00, 0x00, 0x00, 0xb7, 0xdb, 0xf7, 0x10, + 0x00, 0x00, 0x3b, 0xf7, 0x1a, 0xc8, 0x6b, 0x00, 0x04, 0xdb, 0x5f, 0x00, + 0x32, 0xff, 0x1c, 0x44, 0xf7, 0x0d, 0x00, 0x00, 0xa0, 0x90, + /* ch = 'Y' */ + 0x2d, 0x26, 0x00, 0x00, 0x00, 0x19, 0x36, 0x09, 0x48, 0xf7, 0x10, 0x00, + 0x00, 0x90, 0x8a, 0x00, 0x04, 0xe5, 0x5f, 0x00, 0x22, 0xff, 0x22, 0x00, + 0x00, 0x48, 0xf7, 0x10, 0x70, 0xa0, 0x00, 0x00, 0x00, 0x04, 0xdb, 0x7c, + 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x44, 0xff, 0xa7, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, + /* ch = 'Z' */ + 0x16, 0x36, 0x36, 0x36, 0x36, 0x36, 0x26, 0x22, 0x74, 0x74, 0x74, 0x74, + 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, 0x44, 0xe5, 0x10, 0x00, 0x00, 0x00, + 0x10, 0xe5, 0x44, 0x00, 0x00, 0x00, 0x00, 0x77, 0xb7, 0x00, 0x00, 0x00, + 0x00, 0x2a, 0xff, 0x24, 0x00, 0x00, 0x00, 0x04, 0xc8, 0x6b, 0x00, 0x00, + 0x00, 0x00, 0x4d, 0xe5, 0x10, 0x00, 0x00, 0x00, 0x17, 0xf7, 0x44, 0x00, + 0x00, 0x00, 0x00, 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* ch = '[' */ + 0x32, 0xff, 0xcf, 0xcf, 0xcf, 0x2d, 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x74, 0x74, 0x74, 0x22, 0x16, 0x36, 0x36, 0x36, 0x36, 0x16, + /* ch = '\' */ + 0x20, 0xe5, 0x10, 0x04, 0xc8, 0x5a, 0x00, 0x48, 0xe5, 0x00, 0x04, 0xe5, + 0x00, 0x00, 0x5a, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = ']' */ + 0x00, 0xcf, 0xcf, 0xcf, 0xf7, 0x50, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, + 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, + 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, + 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, + 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, + 0x14, 0x74, 0x74, 0x74, 0xe5, 0x50, 0x0d, 0x36, 0x36, 0x36, 0x36, 0x1e, + /* ch = '^' */ + 0x00, 0x00, 0x28, 0x04, 0x00, 0x00, 0x1c, 0xf7, 0x44, 0x00, 0x00, 0x90, + 0xd4, 0xe5, 0x0d, 0x32, 0xe5, 0x10, 0xb7, 0x50, 0x82, 0x32, 0x00, 0x2a, + 0xa5, + /* ch = '_' */ + 0x95, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x12, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, + /* ch = '`' */ + 0x17, 0xf7, 0x17, 0x00, 0xa7, 0x64, 0x00, 0x39, 0xff, 0x00, 0x00, 0x30, + /* ch = 'a' */ + 0x00, 0x37, 0xdd, 0xf7, 0xef, 0x50, 0x00, 0x00, 0x3d, 0x1b, 0x00, 0x1f, + 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x50, 0xdd, + 0xcf, 0xcf, 0xf7, 0x50, 0x40, 0xf7, 0x13, 0x00, 0x00, 0xb7, 0x50, 0x5a, + 0xcf, 0x04, 0x00, 0x2c, 0xff, 0x50, 0x10, 0xd4, 0xdd, 0xbd, 0xcb, 0xe5, + 0x50, 0x00, 0x00, 0x12, 0x0f, 0x00, 0x00, 0x00, + /* ch = 'b' */ + 0x50, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x7e, + 0xff, 0xf7, 0x66, 0x00, 0x50, 0xff, 0x54, 0x00, 0x35, 0xff, 0x44, 0x50, + 0xff, 0x04, 0x00, 0x00, 0xa0, 0xa0, 0x50, 0xff, 0x00, 0x00, 0x00, 0x7c, + 0xb7, 0x50, 0xff, 0x00, 0x00, 0x00, 0x82, 0xa0, 0x50, 0xff, 0x35, 0x00, + 0x21, 0xf7, 0x44, 0x50, 0xb7, 0xd4, 0xd4, 0xff, 0x77, 0x00, 0x00, 0x00, + 0x00, 0x12, 0x0c, 0x00, 0x00, + /* ch = 'c' */ + 0x00, 0x10, 0x8d, 0xf7, 0xff, 0xab, 0x19, 0x04, 0xb7, 0x8a, 0x08, 0x08, + 0x7c, 0x73, 0x32, 0xff, 0x17, 0x00, 0x00, 0x08, 0x04, 0x50, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3b, 0xff, 0x17, 0x00, 0x00, 0x00, 0x00, 0x0d, + 0xdb, 0x8a, 0x04, 0x00, 0x37, 0x26, 0x00, 0x1f, 0xd4, 0xef, 0xe5, 0xe5, + 0x2c, 0x00, 0x00, 0x00, 0x12, 0x12, 0x00, 0x00, + /* ch = 'd' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x35, 0xe5, + 0xe5, 0xcb, 0xcf, 0x50, 0x22, 0xff, 0x32, 0x00, 0x35, 0xff, 0x50, 0x5f, + 0xbd, 0x00, 0x00, 0x00, 0xcf, 0x5f, 0x7c, 0x82, 0x00, 0x00, 0x00, 0xb7, + 0x7c, 0x5f, 0xbd, 0x00, 0x00, 0x00, 0xcf, 0x7c, 0x2a, 0xff, 0x32, 0x00, + 0x37, 0xff, 0x7c, 0x00, 0x5a, 0xff, 0xdd, 0xd4, 0xcf, 0x7c, 0x00, 0x00, + 0x0c, 0x12, 0x00, 0x00, 0x00, + /* ch = 'e' */ + 0x00, 0x26, 0xcb, 0xdd, 0xef, 0x48, 0x00, 0x17, 0xf7, 0x37, 0x00, 0x1f, + 0xf7, 0x2a, 0x44, 0xd9, 0x15, 0x15, 0x15, 0x9e, 0x6b, 0x6b, 0xf7, 0xcf, + 0xcf, 0xcf, 0xcf, 0x67, 0x50, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, + 0xff, 0x37, 0x00, 0x00, 0x2a, 0x08, 0x00, 0x35, 0xef, 0xd4, 0xdd, 0xbb, + 0x19, 0x00, 0x00, 0x00, 0x15, 0x0f, 0x00, 0x00, + /* ch = 'f' */ + 0x10, 0xb3, 0xe5, 0xef, 0x8d, 0x04, 0x8a, 0xa0, 0x04, 0x04, 0x8d, 0x04, + 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x82, 0x36, 0x26, 0x00, 0x00, + 0xcf, 0x82, 0x36, 0x26, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, + 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, + 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, + /* ch = 'g' */ + 0x44, 0xef, 0xdd, 0xbb, 0xcb, 0xd4, 0x09, 0xff, 0x1f, 0x00, 0x82, 0x90, + 0x00, 0x00, 0xcf, 0x00, 0x00, 0x50, 0xb7, 0x00, 0x00, 0xf7, 0x5f, 0x2b, + 0xdb, 0x4d, 0x00, 0x00, 0x82, 0x95, 0x74, 0x37, 0x00, 0x00, 0x00, 0xff, + 0x2d, 0x15, 0x15, 0x08, 0x00, 0x00, 0xc4, 0x9e, 0xcf, 0xcf, 0xf7, 0x49, + 0x00, 0x75, 0x00, 0x00, 0x00, 0x59, 0xb7, 0x00, 0xdb, 0x37, 0x15, 0x37, + 0xdb, 0x4d, 0x00, 0x2a, 0x5b, 0x74, 0x5b, 0x1e, 0x00, 0x00, + /* ch = 'h' */ + 0x32, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, + 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x54, + 0xef, 0xff, 0x7e, 0x00, 0x32, 0xff, 0xb1, 0x13, 0x21, 0xff, 0x32, 0x32, + 0xff, 0x24, 0x00, 0x00, 0xe5, 0x50, 0x32, 0xff, 0x1c, 0x00, 0x00, 0xb7, + 0x50, 0x32, 0xff, 0x1c, 0x00, 0x00, 0xb7, 0x50, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0xb7, 0x50, 0x32, 0xff, 0x1c, 0x00, 0x00, 0xb7, 0x50, + /* ch = 'i' */ + 0x00, 0x17, 0xcf, 0x39, 0x00, 0x00, 0x10, 0x9e, 0x2a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x67, 0xcf, 0xcf, 0x2d, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, + 0x1c, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x95, 0xd4, 0xff, + 0xdd, 0xcf, + /* ch = 'j' */ + 0x00, 0x00, 0x00, 0x04, 0xbd, 0x57, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x39, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xcf, 0xcf, 0xcf, 0x45, + 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, + 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, + 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, + 0x00, 0x0c, 0x00, 0x04, 0xf7, 0x44, 0x45, 0xdb, 0x3e, 0x8a, 0xdb, 0x10, + 0x04, 0x3f, 0x74, 0x5b, 0x13, 0x00, + /* ch = 'k' */ + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x1c, 0x00, 0x26, 0xcf, 0x2d, 0x00, 0x32, 0xff, 0x1c, 0x32, + 0xef, 0x32, 0x00, 0x00, 0x32, 0xff, 0x5f, 0xf7, 0x2c, 0x00, 0x00, 0x00, + 0x32, 0xff, 0xef, 0xff, 0x32, 0x00, 0x00, 0x00, 0x32, 0xff, 0x21, 0x7c, + 0xf7, 0x1f, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x04, 0xb1, 0xdb, 0x10, 0x00, + 0x32, 0xff, 0x1c, 0x00, 0x10, 0xdb, 0xb1, 0x04, + /* ch = 'l' */ + 0x00, 0xff, 0xff, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x1c, + 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, + 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, + 0x32, 0x00, 0x00, 0x1a, 0xcf, 0xd4, 0xff, 0xdd, 0xcf, 0x2d, + /* ch = 'm' */ + 0x95, 0xbd, 0xef, 0xd4, 0xa2, 0xef, 0x8b, 0xb7, 0x97, 0x0d, 0xff, 0x5f, + 0x35, 0xff, 0xb7, 0x50, 0x00, 0xff, 0x32, 0x32, 0xff, 0xb7, 0x50, 0x00, + 0xff, 0x32, 0x32, 0xff, 0xb7, 0x50, 0x00, 0xff, 0x32, 0x32, 0xff, 0xb7, + 0x50, 0x00, 0xff, 0x32, 0x32, 0xff, 0xb7, 0x50, 0x00, 0xff, 0x32, 0x32, + 0xff, + /* ch = 'n' */ + 0x2d, 0xcf, 0x50, 0xef, 0xff, 0x7e, 0x00, 0x32, 0xff, 0xb1, 0x0c, 0x26, + 0xff, 0x32, 0x32, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x50, 0x32, 0xff, 0x1c, + 0x00, 0x00, 0xff, 0x50, 0x32, 0xff, 0x1c, 0x00, 0x00, 0xff, 0x50, 0x32, + 0xff, 0x1c, 0x00, 0x00, 0xff, 0x50, 0x32, 0xff, 0x1c, 0x00, 0x00, 0xff, + 0x50, + /* ch = 'o' */ + 0x00, 0x21, 0xc4, 0xff, 0xe5, 0x48, 0x00, 0x17, 0xf7, 0x54, 0x00, 0x28, + 0xff, 0x39, 0x5f, 0xcf, 0x00, 0x00, 0x00, 0x90, 0xa0, 0x7c, 0xa5, 0x00, + 0x00, 0x00, 0x50, 0xb7, 0x6b, 0xcf, 0x00, 0x00, 0x00, 0x6b, 0xb1, 0x2a, + 0xff, 0x37, 0x00, 0x13, 0xf7, 0x44, 0x00, 0x3b, 0xf7, 0xd4, 0xf7, 0x66, + 0x00, 0x00, 0x00, 0x04, 0x15, 0x0c, 0x00, 0x00, + /* ch = 'p' */ + 0x45, 0xcf, 0x73, 0xf7, 0xf7, 0x66, 0x04, 0x50, 0xff, 0x54, 0x00, 0x28, + 0xff, 0x4d, 0x50, 0xff, 0x04, 0x00, 0x00, 0x7c, 0xb1, 0x50, 0xff, 0x00, + 0x00, 0x00, 0x50, 0xef, 0x50, 0xff, 0x00, 0x00, 0x00, 0x6b, 0xb1, 0x50, + 0xff, 0x35, 0x00, 0x13, 0xe5, 0x5a, 0x50, 0xff, 0xc4, 0xd4, 0xf7, 0x94, + 0x04, 0x50, 0xff, 0x00, 0x12, 0x0f, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1e, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = 'q' */ + 0x00, 0x2f, 0xe5, 0xef, 0xcb, 0x9c, 0x67, 0x22, 0xff, 0x35, 0x00, 0x35, + 0xff, 0x7c, 0x6b, 0xbd, 0x00, 0x00, 0x00, 0xbd, 0x7c, 0x7c, 0x82, 0x00, + 0x00, 0x00, 0xb7, 0x7c, 0x6b, 0xcf, 0x00, 0x00, 0x00, 0xcf, 0x7c, 0x2a, + 0xff, 0x35, 0x00, 0x32, 0xff, 0x7c, 0x00, 0x4d, 0xff, 0xdd, 0xd4, 0xcf, + 0x7c, 0x00, 0x00, 0x08, 0x12, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x26, + /* ch = 'r' */ + 0x95, 0x7e, 0x8d, 0xff, 0xf7, 0x60, 0xb7, 0xff, 0x5f, 0x04, 0x21, 0x51, + 0xb7, 0xb7, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x5f, 0x00, 0x00, 0x00, 0x00, + 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, + 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, + /* ch = 's' */ + 0x00, 0x26, 0xcb, 0xd4, 0xef, 0x8d, 0x08, 0x00, 0xe5, 0x4f, 0x00, 0x08, + 0xb1, 0x1f, 0x00, 0xc8, 0xc4, 0x25, 0x00, 0x00, 0x00, 0x00, 0x13, 0x7f, + 0xef, 0xef, 0x66, 0x04, 0x00, 0x00, 0x00, 0x00, 0x2b, 0xf7, 0x50, 0x1c, + 0xb1, 0x08, 0x00, 0x08, 0xe5, 0x50, 0x13, 0x94, 0xf7, 0xcf, 0xef, 0x94, + 0x04, 0x00, 0x00, 0x08, 0x15, 0x0c, 0x00, 0x00, + /* ch = 't' */ + 0x00, 0x00, 0x45, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x6b, 0xb7, 0x00, 0x00, + 0x2d, 0xcf, 0xef, 0xef, 0xcf, 0xcf, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xb1, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xa7, 0x00, 0x1b, + 0x00, 0x00, 0x2f, 0xf7, 0xef, 0xef, 0x00, 0x00, 0x00, 0x04, 0x12, 0x00, + /* ch = 'u' */ + 0x2d, 0xcf, 0x00, 0x00, 0x00, 0x95, 0x45, 0x32, 0xff, 0x00, 0x00, 0x00, + 0xb7, 0x50, 0x32, 0xff, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x32, 0xff, 0x00, + 0x00, 0x00, 0xb7, 0x50, 0x32, 0xff, 0x04, 0x00, 0x00, 0xf7, 0x50, 0x22, + 0xff, 0x35, 0x00, 0x35, 0xff, 0x50, 0x00, 0x66, 0xf7, 0xcf, 0xbb, 0xcf, + 0x54, 0x00, 0x00, 0x0c, 0x12, 0x00, 0x00, 0x00, + /* ch = 'v' */ + 0x58, 0xab, 0x00, 0x00, 0x00, 0x51, 0x82, 0x22, 0xff, 0x24, 0x00, 0x00, + 0xb7, 0x48, 0x00, 0xa7, 0x70, 0x00, 0x22, 0xff, 0x0d, 0x00, 0x3b, 0xf7, + 0x0d, 0x70, 0x8a, 0x00, 0x00, 0x0d, 0xf7, 0x54, 0xf7, 0x22, 0x00, 0x00, + 0x00, 0x70, 0xff, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x22, 0xff, 0x39, 0x00, + 0x00, + /* ch = 'w' */ + 0xdd, 0x2d, 0x00, 0x12, 0x04, 0x1a, 0xcf, 0x1a, 0xb1, 0x44, 0x0d, 0xff, + 0x32, 0x1c, 0xff, 0x00, 0x77, 0x77, 0x2a, 0xff, 0x70, 0x32, 0xbd, 0x00, + 0x44, 0xbd, 0x54, 0xb7, 0xe5, 0x44, 0x82, 0x00, 0x24, 0xff, 0xb7, 0x2c, + 0xf7, 0xb7, 0x54, 0x00, 0x04, 0xff, 0xf7, 0x04, 0x90, 0xff, 0x35, 0x00, + 0x00, 0xb1, 0x90, 0x00, 0x44, 0xff, 0x1c, 0x00, + /* ch = 'x' */ + 0x28, 0xcf, 0x1f, 0x00, 0x1c, 0xcf, 0x28, 0x00, 0x77, 0xb7, 0x08, 0xb1, + 0x77, 0x00, 0x00, 0x04, 0xdb, 0xd4, 0xdb, 0x0d, 0x00, 0x00, 0x00, 0x31, + 0xff, 0x4a, 0x00, 0x00, 0x00, 0x04, 0xc8, 0xd4, 0xe5, 0x10, 0x00, 0x00, + 0x6b, 0xdb, 0x04, 0xb1, 0xa0, 0x00, 0x2c, 0xff, 0x2a, 0x00, 0x10, 0xf7, + 0x50, + /* ch = 'y' */ + 0x4a, 0xcf, 0x04, 0x00, 0x00, 0x5c, 0xa2, 0x17, 0xff, 0x39, 0x00, 0x00, + 0xc8, 0x48, 0x00, 0x8a, 0xa0, 0x00, 0x22, 0xff, 0x17, 0x00, 0x2c, 0xff, + 0x17, 0x5f, 0x90, 0x00, 0x00, 0x00, 0xc8, 0x5a, 0xe5, 0x39, 0x00, 0x00, + 0x00, 0x48, 0xff, 0xe5, 0x04, 0x00, 0x00, 0x00, 0x0d, 0xf7, 0x70, 0x00, + 0x00, 0x00, 0x00, 0x17, 0xff, 0x22, 0x00, 0x00, 0x82, 0x3e, 0xb1, 0xa0, + 0x00, 0x00, 0x00, 0x2e, 0x74, 0x50, 0x08, 0x00, 0x00, 0x00, + /* ch = 'z' */ + 0x2d, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x7c, + 0xb1, 0x04, 0x00, 0x00, 0x00, 0x50, 0xf7, 0x1c, 0x00, 0x00, 0x00, 0x32, + 0xff, 0x32, 0x00, 0x00, 0x00, 0x1f, 0xf7, 0x50, 0x00, 0x00, 0x00, 0x10, + 0xdb, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7c, + /* ch = '{' */ + 0x00, 0x2a, 0x74, 0x74, 0x14, 0x4d, 0xdb, 0x30, 0x30, 0x0d, 0xb7, 0x54, + 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, 0xbd, 0x4d, 0x00, 0x00, + 0x00, 0xdb, 0x10, 0x00, 0x00, 0x00, 0x99, 0x04, 0x00, 0x00, 0x00, 0xf7, + 0x32, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, + 0x00, 0x00, 0xbd, 0x5f, 0x00, 0x00, 0x00, 0x4d, 0xf7, 0x5b, 0x36, 0x0d, + 0x00, 0x18, 0x36, 0x36, 0x0d, + /* ch = '|' */ + 0x1a, 0xcf, 0x2d, 0x1c, 0xff, 0x32, 0x1c, 0xff, 0x32, 0x1c, 0xff, 0x32, + 0x1c, 0xff, 0x32, 0x1c, 0xff, 0x32, 0x1c, 0xff, 0x32, 0x1c, 0xff, 0x32, + 0x1c, 0xff, 0x32, 0x1c, 0xff, 0x32, 0x1c, 0xff, 0x32, 0x1c, 0xff, 0x32, + 0x04, 0x15, 0x08, + /* ch = '}' */ + 0x74, 0x74, 0x37, 0x04, 0x36, 0x2a, 0xb1, 0x77, 0x00, 0x00, 0x35, 0xff, + 0x00, 0x00, 0x32, 0xff, 0x00, 0x00, 0x2f, 0xff, 0x00, 0x00, 0x04, 0xb1, + 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x1c, 0xff, 0x00, 0x00, 0x32, 0xff, + 0x00, 0x00, 0x32, 0xff, 0x00, 0x00, 0x3b, 0xff, 0x36, 0x50, 0xdb, 0x77, + 0x36, 0x36, 0x20, 0x00, + /* ch = '~' */ + 0x10, 0xab, 0xff, 0xa2, 0x13, 0x1f, 0x8d, 0x09, 0x3e, 0x73, 0x08, 0x6b, + 0xf7, 0xef, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x00, 0x00 }; /* font_inconsolata_16px */ static const unsigned char pd_inconsolata_font_bitmap_16px_bytes[] = { - /* ch = '!' */ - 0x0d, 0x74, 0x2a, - 0x32, 0xff, 0x7c, - 0x1c, 0xff, 0x7c, - 0x1c, 0xff, 0x50, - 0x0d, 0xff, 0x50, - 0x00, 0xff, 0x35, - 0x00, 0xff, 0x32, - 0x00, 0xab, 0x2d, - 0x00, 0x00, 0x00, - 0x16, 0x9e, 0x32, - 0x39, 0xff, 0x84, - 0x00, 0x12, 0x04, - /* ch = '"' */ - 0x04, 0x67, 0x2a, 0x1c, 0x74, 0x10, - 0x1c, 0xff, 0x5a, 0x32, 0xff, 0x32, - 0x0d, 0xff, 0x32, 0x32, 0xff, 0x14, - 0x32, 0xf7, 0x04, 0x5f, 0xa0, 0x00, - 0x13, 0x28, 0x00, 0x1e, 0x1e, 0x00, - /* ch = '#' */ - 0x00, 0x00, 0x77, 0x7c, 0x00, 0xcf, 0x44, 0x00, - 0x00, 0x00, 0x90, 0x54, 0x00, 0xff, 0x32, 0x00, - 0x0f, 0x15, 0xbd, 0x53, 0x33, 0xff, 0x4a, 0x24, - 0x42, 0x5b, 0xff, 0x62, 0x62, 0xff, 0x36, 0x1e, - 0x00, 0x14, 0xff, 0x1c, 0x35, 0xe5, 0x00, 0x00, - 0x00, 0x1f, 0xff, 0x0d, 0x50, 0xb7, 0x00, 0x00, - 0x9c, 0xdd, 0xff, 0xcf, 0xe5, 0xdd, 0xa2, 0x28, - 0x00, 0x4d, 0xb7, 0x00, 0x90, 0x5f, 0x00, 0x00, - 0x00, 0x5f, 0x82, 0x00, 0xb7, 0x4d, 0x00, 0x00, - 0x00, 0x67, 0x5c, 0x00, 0xcf, 0x2d, 0x00, 0x00, - /* ch = '$' */ - 0x00, 0x00, 0x00, 0x1e, 0x2b, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x16, 0x82, 0xa5, 0x25, 0x00, 0x00, - 0x00, 0x4d, 0xef, 0xb1, 0xc8, 0xd4, 0xa9, 0x00, - 0x00, 0xf7, 0x35, 0x50, 0x7c, 0x10, 0x3d, 0x00, - 0x00, 0xe5, 0x7c, 0x54, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x26, 0xef, 0xff, 0xa5, 0x0f, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x68, 0xef, 0xf7, 0x66, 0x00, - 0x00, 0x00, 0x00, 0x50, 0x7c, 0x26, 0xff, 0x2a, - 0x00, 0x22, 0x00, 0x50, 0x7c, 0x0d, 0xff, 0x2f, - 0x20, 0xff, 0x73, 0x68, 0xa5, 0xa9, 0xb1, 0x04, - 0x00, 0x1b, 0x67, 0xe5, 0xdb, 0x5b, 0x08, 0x00, - 0x00, 0x00, 0x00, 0x45, 0x67, 0x00, 0x00, 0x00, - /* ch = '%' */ - 0x00, 0x0c, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xef, 0xef, 0x4d, 0x00, 0x32, 0xf7, 0x10, - 0xb1, 0x54, 0x35, 0xf7, 0x04, 0xc8, 0x50, 0x00, - 0xb1, 0x54, 0x3b, 0xe5, 0x44, 0xdb, 0x04, 0x00, - 0x2c, 0xef, 0xef, 0x4d, 0xe5, 0x3b, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x5f, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x17, 0xf7, 0x2a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x90, 0x4d, 0xef, 0xd4, 0x16, - 0x00, 0x24, 0xff, 0x2a, 0xff, 0x24, 0x8a, 0x77, - 0x00, 0xa0, 0x6b, 0x1a, 0xff, 0x1f, 0x6b, 0x77, - 0x35, 0xf7, 0x10, 0x00, 0x7c, 0xcb, 0xef, 0x1f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0x00, - /* ch = '&' */ - 0x00, 0x1f, 0xe5, 0xff, 0xd4, 0x1f, 0x00, 0x00, - 0x00, 0xa0, 0x97, 0x04, 0x97, 0x8a, 0x00, 0x00, - 0x00, 0xb1, 0x7c, 0x00, 0x82, 0xa0, 0x00, 0x00, - 0x00, 0x44, 0xf7, 0x37, 0xf7, 0x2f, 0x00, 0x00, - 0x00, 0x08, 0xd9, 0xff, 0x3f, 0x00, 0x00, 0x00, - 0x04, 0xc4, 0xb1, 0xdb, 0x7c, 0x00, 0x39, 0x08, - 0x5a, 0xf7, 0x10, 0x2f, 0xff, 0x3b, 0xe5, 0x4d, - 0x8a, 0xb7, 0x00, 0x00, 0x50, 0xff, 0xb1, 0x04, - 0x6b, 0xf7, 0x1a, 0x04, 0x6b, 0xff, 0xb1, 0x04, - 0x10, 0xbb, 0xff, 0xff, 0xbb, 0x28, 0xf7, 0x43, - 0x00, 0x00, 0x12, 0x0c, 0x00, 0x00, 0x0c, 0x00, - /* ch = ''' */ - 0x2c, 0x67, 0x00, - 0x77, 0xff, 0x11, - 0x54, 0xc8, 0x00, - 0xa7, 0x5a, 0x00, - 0x2a, 0x10, 0x00, - /* ch = '(' */ - 0x00, 0x00, 0x37, 0x2a, - 0x04, 0xa9, 0xd4, 0x31, - 0x82, 0xdb, 0x10, 0x00, - 0xff, 0x24, 0x00, 0x00, - 0x90, 0x00, 0x00, 0x00, - 0x4d, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x00, 0x00, - 0x35, 0x00, 0x00, 0x00, - 0x5f, 0x00, 0x00, 0x00, - 0xc8, 0x00, 0x00, 0x00, - 0xff, 0x35, 0x00, 0x00, - 0x77, 0xf7, 0x1f, 0x00, - 0x04, 0x99, 0xef, 0x28, - 0x00, 0x00, 0x50, 0x40, - /* ch = ')' */ - 0x00, 0x51, 0x13, 0x00, - 0x09, 0x94, 0xf7, 0x2c, - 0x00, 0x00, 0x5f, 0xf7, - 0x00, 0x00, 0x00, 0x90, - 0x00, 0x00, 0x00, 0x22, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x17, - 0x00, 0x00, 0x00, 0x82, - 0x00, 0x00, 0x50, 0xff, - 0x04, 0x77, 0xf7, 0x35, - 0x04, 0x9e, 0x1b, 0x00, - /* ch = '*' */ - 0x00, 0x00, 0x00, 0x22, 0x0f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb7, 0x5f, 0x00, 0x00, 0x00, - 0x24, 0x48, 0x08, 0xa0, 0x50, 0x16, 0x5b, 0x04, - 0x29, 0x9e, 0xe5, 0xdb, 0xcb, 0xe5, 0x73, 0x13, - 0x00, 0x00, 0x21, 0xff, 0xbd, 0x04, 0x00, 0x00, - 0x00, 0x10, 0xdb, 0x44, 0xa0, 0x7c, 0x00, 0x00, - 0x00, 0xa4, 0x90, 0x00, 0x17, 0xf7, 0x43, 0x00, - 0x00, 0x10, 0x16, 0x00, 0x00, 0x0f, 0x00, 0x00, - /* ch = '+' */ - 0x00, 0x00, 0x00, 0x2d, 0x1e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, - 0x42, 0x74, 0x74, 0xe5, 0xb1, 0x74, 0x74, 0x22, - 0x26, 0x36, 0x36, 0xcf, 0x82, 0x36, 0x36, 0x16, - 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x2d, 0x1e, 0x00, 0x00, 0x00, - /* ch = ',' */ - 0x16, 0x74, 0x2c, - 0x40, 0xff, 0xb7, - 0x00, 0x82, 0x8a, - 0x17, 0xef, 0x1f, - 0x32, 0x2c, 0x00, - /* ch = '-' */ - 0x14, 0x74, 0x74, 0x74, 0x74, 0x74, 0x58, - 0x0d, 0x36, 0x36, 0x36, 0x36, 0x36, 0x2d, - /* ch = '.' */ - 0x10, 0x74, 0x2c, - 0x39, 0xff, 0x84, - 0x00, 0x12, 0x04, - /* ch = '/' */ - 0x00, 0x2a, 0x37, - 0x00, 0xa7, 0x8a, - 0x2c, 0xff, 0x22, - 0x90, 0xa0, 0x00, - 0xff, 0x2c, 0x00, - 0xb7, 0x00, 0x00, - 0x39, 0x00, 0x00, - 0x04, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* ch = '0' */ - 0x00, 0x04, 0x7e, 0xff, 0xef, 0x44, 0x00, 0x00, - 0x00, 0x6b, 0xc8, 0x13, 0x35, 0xff, 0x2a, 0x00, - 0x14, 0xff, 0x2c, 0x00, 0x10, 0xe5, 0xa0, 0x00, - 0x35, 0xff, 0x00, 0x00, 0x82, 0xf7, 0xff, 0x04, - 0x50, 0xb7, 0x00, 0x50, 0xdb, 0x28, 0xff, 0x1c, - 0x50, 0xb7, 0x2f, 0xff, 0x1f, 0x1c, 0xff, 0x1c, - 0x3b, 0xff, 0xdb, 0x50, 0x00, 0x2a, 0xff, 0x14, - 0x17, 0xff, 0x82, 0x00, 0x00, 0x50, 0xc8, 0x00, - 0x00, 0x90, 0xb7, 0x10, 0x13, 0xe5, 0x44, 0x00, - 0x00, 0x10, 0xa9, 0xf7, 0xf7, 0x6b, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x12, 0x0f, 0x00, 0x00, 0x00, - /* ch = '1' */ - 0x00, 0x31, 0xd4, 0xb7, - 0xab, 0xab, 0xc8, 0xb7, - 0x00, 0x00, 0x7c, 0xb7, - 0x00, 0x00, 0x7c, 0xb7, - 0x00, 0x00, 0x7c, 0xb7, - 0x00, 0x00, 0x7c, 0xb7, - 0x00, 0x00, 0x7c, 0xb7, - 0x00, 0x00, 0x7c, 0xb7, - 0x00, 0x00, 0x7c, 0xb7, - 0x00, 0x00, 0x7c, 0xb7, - /* ch = '2' */ - 0x00, 0x19, 0xb3, 0xff, 0xf7, 0x73, 0x04, - 0x0a, 0xcb, 0x5f, 0x04, 0x1b, 0xe5, 0x6b, - 0x00, 0x0c, 0x04, 0x00, 0x00, 0x5f, 0xc8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xb1, - 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf7, 0x3b, - 0x00, 0x00, 0x00, 0x21, 0xef, 0x5f, 0x00, - 0x00, 0x00, 0x1f, 0xf7, 0x54, 0x00, 0x00, - 0x00, 0x10, 0xdb, 0x54, 0x00, 0x00, 0x00, - 0x00, 0x90, 0xb1, 0x00, 0x00, 0x00, 0x0c, - 0x1a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* ch = '3' */ - 0x00, 0x26, 0xcb, 0xff, 0xe5, 0x48, 0x00, - 0x00, 0x4d, 0x3f, 0x04, 0x35, 0xff, 0x2c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x32, - 0x00, 0x00, 0x30, 0xab, 0xf7, 0x4a, 0x00, - 0x00, 0x00, 0x0c, 0x20, 0x77, 0xf7, 0x1f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0xb1, - 0x04, 0xb1, 0x21, 0x00, 0x21, 0xf7, 0x50, - 0x04, 0x73, 0xff, 0xe5, 0xff, 0x7e, 0x04, - 0x00, 0x00, 0x08, 0x15, 0x0c, 0x00, 0x00, - /* ch = '4' */ - 0x00, 0x00, 0x00, 0x00, 0x77, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x2f, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x0d, 0xdb, 0xb1, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x77, 0x82, 0x50, 0xff, 0x00, 0x00, - 0x00, 0x2f, 0xe5, 0x10, 0x50, 0xff, 0x00, 0x00, - 0x0d, 0xdb, 0x35, 0x00, 0x50, 0xff, 0x00, 0x00, - 0x4d, 0xff, 0xcf, 0xcf, 0xe5, 0xff, 0xcf, 0x1a, - 0x0c, 0x15, 0x15, 0x15, 0x5e, 0xff, 0x15, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, - /* ch = '5' */ - 0x00, 0x7c, 0xff, 0xff, 0xff, 0xff, 0xb7, - 0x00, 0x82, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xb7, 0x74, 0x36, 0x36, 0x13, 0x00, - 0x00, 0xf7, 0xdb, 0x50, 0xa4, 0xf7, 0x32, - 0x00, 0x25, 0x10, 0x00, 0x00, 0x82, 0xc8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xff, - 0x1a, 0xd4, 0x37, 0x00, 0x10, 0xb7, 0xa0, - 0x00, 0x44, 0xef, 0xdd, 0xf7, 0xbb, 0x10, - 0x00, 0x00, 0x00, 0x15, 0x0f, 0x00, 0x00, - /* ch = '6' */ - 0x00, 0x00, 0x48, 0xef, 0xff, 0xe5, 0x35, - 0x00, 0x3b, 0xf7, 0x28, 0x00, 0x40, 0x1f, - 0x00, 0xc8, 0x64, 0x00, 0x00, 0x00, 0x00, - 0x14, 0xff, 0x35, 0x30, 0x36, 0x0c, 0x00, - 0x1c, 0xff, 0xef, 0xa4, 0xa4, 0xf7, 0x1f, - 0x2d, 0xff, 0x50, 0x00, 0x00, 0x90, 0xa7, - 0x1c, 0xff, 0x24, 0x00, 0x00, 0x44, 0xff, - 0x0d, 0xff, 0x3b, 0x00, 0x00, 0x4d, 0xf7, - 0x00, 0x7c, 0xdb, 0x10, 0x08, 0xb7, 0x7c, - 0x00, 0x10, 0xa9, 0xf7, 0xef, 0xbb, 0x10, - 0x00, 0x00, 0x00, 0x0f, 0x12, 0x00, 0x00, - /* ch = '7' */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xb7, - 0x00, 0x00, 0x00, 0x04, 0xe5, 0x5a, - 0x00, 0x00, 0x00, 0x39, 0xff, 0x17, - 0x00, 0x00, 0x00, 0xa7, 0x8a, 0x00, - 0x00, 0x00, 0x22, 0xff, 0x32, 0x00, - 0x00, 0x00, 0x5f, 0xe5, 0x04, 0x00, - 0x00, 0x04, 0xe5, 0x6b, 0x00, 0x00, - 0x00, 0x2c, 0xff, 0x24, 0x00, 0x00, - 0x00, 0x70, 0xcf, 0x00, 0x00, 0x00, - 0x04, 0xf7, 0x6b, 0x00, 0x00, 0x00, - /* ch = '8' */ - 0x00, 0x10, 0xbb, 0xef, 0xf7, 0x94, 0x08, - 0x00, 0x8a, 0xb1, 0x04, 0x13, 0xe5, 0x5a, - 0x00, 0xb7, 0x54, 0x00, 0x00, 0x82, 0x7c, - 0x00, 0x6b, 0xf7, 0x21, 0x1f, 0xf7, 0x2f, - 0x00, 0x04, 0x88, 0xf7, 0xf7, 0x46, 0x00, - 0x00, 0x4d, 0xef, 0x31, 0x94, 0xf7, 0x24, - 0x17, 0xff, 0x32, 0x00, 0x00, 0x82, 0xc8, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x47, 0xff, - 0x17, 0xff, 0x64, 0x04, 0x08, 0xb1, 0xa7, - 0x00, 0x2f, 0xef, 0xe5, 0xf7, 0xbb, 0x13, - 0x00, 0x00, 0x00, 0x15, 0x0f, 0x00, 0x00, - /* ch = '9' */ - 0x00, 0x13, 0xbb, 0xff, 0xf7, 0x5a, 0x00, - 0x00, 0xb1, 0x9e, 0x04, 0x26, 0xff, 0x39, - 0x1a, 0xff, 0x2a, 0x00, 0x00, 0x7c, 0xa0, - 0x1c, 0xff, 0x1f, 0x00, 0x00, 0x50, 0xe5, - 0x04, 0xf7, 0x54, 0x00, 0x04, 0x90, 0xff, - 0x00, 0x40, 0xff, 0x8f, 0xcb, 0xf7, 0xff, - 0x00, 0x00, 0x16, 0x36, 0x25, 0x54, 0xcf, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0x7c, - 0x00, 0x2c, 0x1f, 0x00, 0x35, 0xff, 0x24, - 0x00, 0x94, 0xff, 0xef, 0xef, 0x3b, 0x00, - 0x00, 0x00, 0x0c, 0x15, 0x00, 0x00, 0x00, - /* ch = ':' */ - 0x1c, 0xbd, 0x40, - 0x36, 0xff, 0x6b, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x10, 0x74, 0x2c, - 0x39, 0xff, 0x84, - 0x00, 0x12, 0x04, - /* ch = ';' */ - 0x1c, 0xbd, 0x40, - 0x36, 0xff, 0x6b, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x16, 0x74, 0x2c, - 0x40, 0xff, 0xb7, - 0x00, 0x82, 0x8a, - 0x17, 0xef, 0x1f, - 0x32, 0x2c, 0x00, - /* ch = '<' */ - 0x00, 0x00, 0x28, 0xbb, 0x32, - 0x1e, 0xb3, 0xef, 0x48, 0x08, - 0xef, 0x50, 0x08, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x73, 0x08, 0x00, 0x00, - 0x1b, 0xbb, 0xef, 0x3f, 0x04, - 0x00, 0x00, 0x28, 0xd4, 0x32, - 0x00, 0x00, 0x00, 0x04, 0x08, - /* ch = '=' */ - 0x7c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x67, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x2d, - 0x0f, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x08, - /* ch = '>' */ - 0x7c, 0x7f, 0x13, 0x00, 0x00, - 0x13, 0x7f, 0xf7, 0x73, 0x0c, - 0x00, 0x00, 0x16, 0x8d, 0xf7, - 0x00, 0x00, 0x00, 0x00, 0x1b, - 0x00, 0x00, 0x00, 0x00, 0x28, - 0x00, 0x00, 0x1b, 0xbb, 0xef, - 0x13, 0x73, 0xff, 0x73, 0x08, - 0x7c, 0x94, 0x16, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x00, - /* ch = '?' */ - 0x00, 0x04, 0x31, 0x74, 0x74, 0x22, 0x00, - 0x04, 0xa9, 0xef, 0x47, 0x94, 0xff, 0x44, - 0x08, 0x8d, 0x10, 0x00, 0x00, 0xa7, 0xbd, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xe5, - 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x6b, - 0x00, 0x00, 0x00, 0x1c, 0xef, 0x77, 0x04, - 0x00, 0x00, 0x00, 0x6b, 0xa7, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x51, 0x51, 0x00, 0x00, - 0x00, 0x00, 0x09, 0xf7, 0xf7, 0x09, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0x0f, 0x00, 0x00, - /* ch = '@' */ - 0x00, 0x00, 0x00, 0x04, 0x0f, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x94, 0xe5, 0xd4, 0xd4, 0x21, 0x00, - 0x04, 0xb7, 0x6b, 0x04, 0x00, 0x47, 0xdb, 0x0d, - 0x39, 0xc8, 0x04, 0x00, 0x00, 0x0c, 0xff, 0x2f, - 0x82, 0x5f, 0x00, 0x66, 0xef, 0xcf, 0xe5, 0x44, - 0xb7, 0x50, 0x39, 0xe5, 0x10, 0x00, 0xb7, 0x50, - 0xb7, 0x50, 0x50, 0xbd, 0x00, 0x0d, 0xf7, 0x50, - 0x7c, 0x6b, 0x17, 0xef, 0xa4, 0xbb, 0xff, 0x50, - 0x39, 0xe5, 0x10, 0x08, 0x30, 0x18, 0x12, 0x0c, - 0x04, 0xb1, 0x99, 0x08, 0x00, 0x00, 0x0f, 0x00, - 0x00, 0x10, 0x8d, 0xf7, 0xcf, 0xe5, 0x97, 0x00, - 0x00, 0x00, 0x00, 0x08, 0x15, 0x0c, 0x00, 0x00, - /* ch = 'A' */ - 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xa7, 0x17, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x17, 0xff, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0xc8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x5f, 0xff, 0x2a, 0x00, 0x00, - 0x00, 0x22, 0xff, 0x14, 0xa0, 0x70, 0x00, 0x00, - 0x00, 0x5a, 0xa0, 0x00, 0x39, 0xf7, 0x0d, 0x00, - 0x00, 0xc8, 0xe5, 0xcf, 0xd4, 0xff, 0x3b, 0x00, - 0x24, 0xff, 0x1c, 0x00, 0x00, 0x8a, 0xa7, 0x00, - 0x5f, 0xb7, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, - 0xe5, 0x50, 0x00, 0x00, 0x00, 0x04, 0xe5, 0x5a, - /* ch = 'B' */ - 0x50, 0xff, 0xff, 0xff, 0xef, 0x8d, 0x10, 0x00, - 0x50, 0xb7, 0x00, 0x00, 0x1e, 0xdb, 0x8a, 0x00, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x64, 0xc8, 0x00, - 0x50, 0xb7, 0x00, 0x00, 0x13, 0xc8, 0x6b, 0x00, - 0x50, 0xf7, 0xcf, 0xcf, 0xff, 0x9e, 0x04, 0x00, - 0x50, 0xb7, 0x00, 0x12, 0x2b, 0xdb, 0x7c, 0x00, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x24, 0xff, 0x2f, - 0x50, 0xb7, 0x00, 0x00, 0x0c, 0xb1, 0xdb, 0x04, - 0x50, 0xff, 0xff, 0xff, 0xff, 0xab, 0x19, 0x00, - /* ch = 'C' */ - 0x00, 0x04, 0x73, 0xf7, 0xe5, 0xe5, 0x2c, 0x00, - 0x00, 0x90, 0xb1, 0x13, 0x00, 0x43, 0xff, 0x2a, - 0x27, 0xff, 0x24, 0x00, 0x00, 0x00, 0x2a, 0x04, - 0x5f, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x5f, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2c, 0xff, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xb1, 0xb1, 0x13, 0x00, 0x28, 0xe5, 0x18, - 0x00, 0x10, 0x94, 0xf7, 0xd4, 0xef, 0x3b, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0x15, 0x00, 0x00, 0x00, - /* ch = 'D' */ - 0x50, 0xff, 0xff, 0xff, 0xd4, 0x37, 0x00, 0x00, - 0x50, 0xff, 0x00, 0x04, 0x3f, 0xff, 0x44, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x70, 0xe5, 0x04, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x2a, 0xff, 0x24, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x24, 0xff, 0x24, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x5f, 0xe5, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x37, 0xff, 0x35, 0x00, - 0x50, 0xff, 0xcf, 0xff, 0xdd, 0x35, 0x00, 0x00, - /* ch = 'E' */ - 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0xcf, 0xcf, 0xcf, 0xcf, 0x1a, - 0x32, 0xff, 0x36, 0x36, 0x36, 0x36, 0x0d, - 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* ch = 'F' */ - 0x1c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0xdd, 0xcf, 0xcf, 0xcf, 0x1a, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - /* ch = 'G' */ - 0x00, 0x08, 0x8d, 0xff, 0xff, 0xe5, 0x2f, 0x00, - 0x00, 0xb1, 0xb1, 0x13, 0x00, 0x54, 0xff, 0x1e, - 0x32, 0xff, 0x17, 0x00, 0x00, 0x00, 0x22, 0x00, - 0x6b, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x82, 0x7c, 0x00, 0x00, 0x95, 0xcf, 0xcf, 0x2d, - 0x77, 0xbd, 0x00, 0x00, 0x12, 0x15, 0xff, 0x32, - 0x39, 0xff, 0x17, 0x00, 0x00, 0x00, 0xff, 0x32, - 0x04, 0xc8, 0xb1, 0x0c, 0x00, 0x16, 0xff, 0x32, - 0x00, 0x13, 0xb3, 0xff, 0xd4, 0xf7, 0x73, 0x08, - 0x00, 0x00, 0x00, 0x0c, 0x15, 0x00, 0x00, 0x00, - /* ch = 'H' */ - 0x50, 0xff, 0x04, 0x00, 0x00, 0x32, 0xff, 0x0d, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, - 0x50, 0xff, 0xcf, 0xcf, 0xcf, 0xdd, 0xff, 0x00, - 0x50, 0xff, 0x15, 0x15, 0x15, 0x3e, 0xff, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, - /* ch = 'I' */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0x32, - 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, - /* ch = 'J' */ - 0x7c, 0xff, 0xff, 0xff, 0xff, 0x32, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, - 0x00, 0x00, 0x82, 0x82, 0x00, 0x00, - 0x04, 0x10, 0xe5, 0x5a, 0x00, 0x00, - 0xef, 0xef, 0xa9, 0x04, 0x00, 0x00, - 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, - /* ch = 'K' */ - 0x7c, 0xbd, 0x00, 0x00, 0x04, 0xb1, 0xb1, 0x08, - 0x7c, 0xb7, 0x00, 0x00, 0x7c, 0xdb, 0x10, 0x00, - 0x7c, 0xb7, 0x00, 0x5f, 0xf7, 0x1f, 0x00, 0x00, - 0x7c, 0xb7, 0x50, 0xf7, 0x21, 0x00, 0x00, 0x00, - 0x7c, 0xf7, 0xff, 0x82, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0xf7, 0x50, 0xff, 0x32, 0x00, 0x00, 0x00, - 0x7c, 0xb7, 0x00, 0x7c, 0xe5, 0x10, 0x00, 0x00, - 0x7c, 0xb7, 0x00, 0x10, 0xdb, 0xa0, 0x00, 0x00, - 0x7c, 0xb7, 0x00, 0x00, 0x2f, 0xff, 0x4d, 0x00, - 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x6b, 0xf7, 0x1f, - /* ch = 'L' */ - 0x32, 0xff, 0x24, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* ch = 'M' */ - 0x7c, 0xa0, 0x00, 0x00, 0x00, 0x10, 0xf7, 0x32, - 0x7c, 0xff, 0x2a, 0x00, 0x00, 0x5f, 0xff, 0x32, - 0x7c, 0xff, 0xa0, 0x00, 0x17, 0xf7, 0xff, 0x32, - 0x7c, 0xa7, 0xff, 0x2c, 0x6b, 0x90, 0xff, 0x32, - 0x7c, 0x7c, 0x70, 0xc8, 0xf7, 0x24, 0xff, 0x32, - 0x7c, 0x7c, 0x17, 0xff, 0x7c, 0x00, 0xff, 0x32, - 0x7c, 0x7c, 0x00, 0x28, 0x10, 0x00, 0xff, 0x32, - 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, - 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, - 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, - /* ch = 'N' */ - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x32, 0xff, 0x1f, - 0x50, 0xff, 0x90, 0x00, 0x00, 0x32, 0xff, 0x1c, - 0x50, 0xf7, 0xff, 0x2a, 0x00, 0x32, 0xff, 0x1c, - 0x50, 0xb7, 0x90, 0xb7, 0x00, 0x32, 0xff, 0x1c, - 0x50, 0xb7, 0x1c, 0xff, 0x44, 0x32, 0xff, 0x1c, - 0x50, 0xb7, 0x00, 0x6b, 0xe5, 0x3b, 0xff, 0x1c, - 0x50, 0xb7, 0x00, 0x10, 0xf7, 0xc8, 0xff, 0x1c, - 0x50, 0xb7, 0x00, 0x00, 0x44, 0xff, 0xff, 0x1c, - 0x50, 0xb7, 0x00, 0x00, 0x04, 0xc8, 0xff, 0x1c, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, - /* ch = 'O' */ - 0x00, 0x19, 0xbb, 0xff, 0xff, 0x8d, 0x08, 0x00, - 0x0d, 0xdb, 0x8a, 0x08, 0x1b, 0xdb, 0x90, 0x00, - 0x48, 0xf7, 0x04, 0x00, 0x00, 0x39, 0xff, 0x22, - 0x90, 0x82, 0x00, 0x00, 0x00, 0x04, 0xff, 0x44, - 0xb7, 0x6b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, - 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x50, - 0x90, 0x90, 0x00, 0x00, 0x00, 0x04, 0xff, 0x44, - 0x48, 0xf7, 0x10, 0x00, 0x00, 0x2c, 0xff, 0x22, - 0x0d, 0xdb, 0x8a, 0x08, 0x13, 0xc8, 0xa0, 0x00, - 0x00, 0x1f, 0xd4, 0xff, 0xff, 0xbb, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x12, 0x0c, 0x00, 0x00, 0x00, - /* ch = 'P' */ - 0x32, 0xff, 0xff, 0xff, 0xff, 0xab, 0x19, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x1a, 0xb1, 0xdb, 0x04, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x24, 0xff, 0x24, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x2c, 0xff, 0x1c, - 0x32, 0xff, 0x4a, 0x36, 0x47, 0xef, 0x8a, 0x00, - 0x32, 0xff, 0x87, 0x74, 0x74, 0x37, 0x04, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 'Q' */ - 0x00, 0x19, 0xbb, 0xff, 0xff, 0x8d, 0x08, 0x00, - 0x0d, 0xdb, 0x8a, 0x08, 0x16, 0xdb, 0xa0, 0x00, - 0x48, 0xe5, 0x04, 0x00, 0x00, 0x2c, 0xff, 0x22, - 0x90, 0x82, 0x00, 0x00, 0x00, 0x04, 0xff, 0x44, - 0xb7, 0x5f, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x50, - 0xb7, 0x77, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, - 0x90, 0x90, 0x00, 0x00, 0x00, 0x00, 0xff, 0x44, - 0x48, 0xf7, 0x0d, 0x00, 0x00, 0x24, 0xff, 0x22, - 0x10, 0xdb, 0x7c, 0x04, 0x08, 0xb1, 0xa0, 0x00, - 0x00, 0x1f, 0xd4, 0xff, 0xff, 0xbb, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x82, 0x82, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x36, 0xff, 0xcf, 0xcf, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0f, 0x30, 0x36, 0x00, - /* ch = 'R' */ - 0x50, 0xff, 0xff, 0xff, 0xf7, 0x9e, 0x13, 0x00, - 0x50, 0xff, 0x00, 0x04, 0x20, 0xdb, 0xb7, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x3b, 0xff, 0x1a, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x48, 0xff, 0x0d, - 0x50, 0xff, 0x36, 0x36, 0x50, 0xf7, 0x6b, 0x00, - 0x50, 0xff, 0x74, 0x95, 0xff, 0x46, 0x00, 0x00, - 0x50, 0xff, 0x00, 0x04, 0xdb, 0x6b, 0x00, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x3b, 0xff, 0x17, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x04, 0xc8, 0x7c, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x3b, 0xff, 0x1f, - /* ch = 'S' */ - 0x00, 0x19, 0xab, 0xff, 0xff, 0xb3, 0x1b, 0x00, - 0x00, 0xdb, 0x7c, 0x04, 0x04, 0x5f, 0xa9, 0x00, - 0x1c, 0xff, 0x35, 0x00, 0x00, 0x04, 0x08, 0x00, - 0x04, 0xdb, 0xb1, 0x13, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x19, 0xbb, 0xf7, 0x7f, 0x16, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x25, 0xa4, 0xff, 0x4d, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x17, - 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x2a, - 0x2a, 0xdb, 0x1e, 0x00, 0x04, 0x7c, 0xe5, 0x0d, - 0x08, 0x7f, 0xff, 0xe5, 0xf7, 0xd4, 0x21, 0x00, - 0x00, 0x00, 0x04, 0x15, 0x0f, 0x00, 0x00, 0x00, - /* ch = 'T' */ - 0xb7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x32, - 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, - /* ch = 'U' */ - 0x50, 0xcf, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x50, 0xb7, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x50, 0xbd, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x4d, 0xff, 0x04, 0x00, 0x00, 0x24, 0xff, 0x1c, - 0x22, 0xff, 0x50, 0x00, 0x04, 0x82, 0xc8, 0x04, - 0x00, 0x3b, 0xef, 0xdd, 0xef, 0xcb, 0x19, 0x00, - 0x00, 0x00, 0x00, 0x15, 0x0f, 0x00, 0x00, 0x00, - /* ch = 'V' */ - 0xa7, 0x90, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x50, - 0x44, 0xff, 0x0d, 0x00, 0x00, 0x2a, 0xff, 0x1c, - 0x14, 0xff, 0x3b, 0x00, 0x00, 0x5f, 0xb7, 0x00, - 0x00, 0xa0, 0x90, 0x00, 0x00, 0xcf, 0x50, 0x00, - 0x00, 0x44, 0xff, 0x0d, 0x22, 0xff, 0x1c, 0x00, - 0x00, 0x0d, 0xff, 0x3b, 0x50, 0xb7, 0x00, 0x00, - 0x00, 0x00, 0x90, 0x90, 0xb7, 0x50, 0x00, 0x00, - 0x00, 0x00, 0x3b, 0xff, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x0d, 0xff, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x90, 0x50, 0x00, 0x00, 0x00, - /* ch = 'W' */ - 0xff, 0x3b, 0x00, 0x08, 0x08, 0x00, 0x54, 0x90, - 0xb7, 0x54, 0x00, 0x5f, 0x5f, 0x00, 0x7c, 0x5f, - 0x7c, 0x82, 0x00, 0xb1, 0xa0, 0x00, 0xb1, 0x3b, - 0x50, 0xbd, 0x0d, 0xff, 0xff, 0x0d, 0xe5, 0x2a, - 0x32, 0xff, 0x35, 0xb7, 0xf7, 0x3b, 0xff, 0x14, - 0x1c, 0xff, 0xa0, 0x5f, 0x90, 0xa7, 0xe5, 0x00, - 0x04, 0xff, 0xff, 0x2a, 0x4d, 0xff, 0xb1, 0x00, - 0x00, 0xbd, 0xf7, 0x04, 0x24, 0xff, 0x77, 0x00, - 0x00, 0x82, 0x90, 0x00, 0x00, 0xe5, 0x4d, 0x00, - 0x00, 0x54, 0x50, 0x00, 0x00, 0x82, 0x32, 0x00, - /* ch = 'X' */ - 0x3b, 0xff, 0x1c, 0x00, 0x00, 0x5f, 0xdb, 0x04, - 0x00, 0xb7, 0x90, 0x00, 0x10, 0xf7, 0x3b, 0x00, - 0x00, 0x2a, 0xff, 0x2a, 0x6b, 0xc8, 0x04, 0x00, - 0x00, 0x00, 0x90, 0xc8, 0xff, 0x3b, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0xc8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x2a, 0xff, 0xe5, 0x0d, 0x00, 0x00, - 0x00, 0x00, 0xa7, 0xb1, 0xf7, 0x5f, 0x00, 0x00, - 0x00, 0x32, 0xff, 0x24, 0x50, 0xf7, 0x17, 0x00, - 0x04, 0xc8, 0x7c, 0x00, 0x04, 0xdb, 0x7c, 0x00, - 0x3b, 0xff, 0x1c, 0x00, 0x00, 0x3b, 0xff, 0x24, - /* ch = 'Y' */ - 0x70, 0xe5, 0x04, 0x00, 0x00, 0x1c, 0xff, 0x39, - 0x17, 0xff, 0x48, 0x00, 0x00, 0x70, 0xc8, 0x00, - 0x00, 0x6b, 0xe5, 0x04, 0x17, 0xf7, 0x3b, 0x00, - 0x00, 0x17, 0xf7, 0x48, 0x5a, 0xe5, 0x04, 0x00, - 0x00, 0x00, 0x6b, 0xe5, 0xe5, 0x48, 0x00, 0x00, - 0x00, 0x00, 0x17, 0xf7, 0xe5, 0x0d, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, - /* ch = 'Z' */ - 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x90, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3b, 0xf7, 0x17, 0x00, - 0x00, 0x00, 0x00, 0x10, 0xe5, 0x54, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x77, 0xdb, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x24, 0xff, 0x32, 0x00, 0x00, 0x00, - 0x00, 0x04, 0xb7, 0x90, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x4d, 0xf7, 0x17, 0x00, 0x00, 0x00, 0x00, - 0x17, 0xf7, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x32, - /* ch = '[' */ - 0x1a, 0xcf, 0xcf, 0xcf, 0xcf, 0x67, - 0x1c, 0xff, 0x28, 0x15, 0x15, 0x0f, - 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x4a, 0x36, 0x36, 0x26, - 0x0d, 0x36, 0x36, 0x36, 0x36, 0x26, - /* ch = '\' */ - 0x08, 0x5b, 0x0d, - 0x0d, 0xf7, 0x50, - 0x00, 0x5a, 0xe5, - 0x00, 0x10, 0xf7, - 0x00, 0x00, 0x70, - 0x00, 0x00, 0x17, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* ch = ']' */ - 0xcf, 0xcf, 0xcf, 0xcf, 0x95, - 0x15, 0x15, 0x15, 0x5e, 0xb7, - 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x00, 0x00, 0x00, 0x50, 0xb7, - 0x36, 0x36, 0x36, 0x82, 0xb7, - 0x36, 0x36, 0x36, 0x36, 0x2d, - /* ch = '^' */ - 0x00, 0x00, 0x7c, 0x5a, 0x00, 0x00, - 0x00, 0x2a, 0xff, 0xf7, 0x10, 0x00, - 0x04, 0xc8, 0x5f, 0xb7, 0x6b, 0x00, - 0x4d, 0xdb, 0x04, 0x2a, 0xf7, 0x17, - 0x28, 0x2a, 0x00, 0x00, 0x48, 0x0c, - /* ch = '_' */ - 0x58, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x30, - 0x12, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x0c, - /* ch = '`' */ - 0x09, 0x7f, 0x1c, - 0x00, 0xa7, 0x5f, - 0x00, 0x44, 0xff, - 0x00, 0x04, 0xb1, - /* ch = 'a' */ - 0x00, 0x00, 0x20, 0x36, 0x36, 0x16, 0x00, - 0x00, 0x7f, 0xd4, 0x5b, 0x82, 0xff, 0x32, - 0x00, 0x0c, 0x04, 0x00, 0x00, 0x64, 0xbd, - 0x00, 0x00, 0x08, 0x15, 0x2a, 0x82, 0xff, - 0x04, 0x7e, 0xef, 0x82, 0x74, 0xb1, 0xff, - 0x44, 0xff, 0x1a, 0x00, 0x00, 0x54, 0xff, - 0x4d, 0xff, 0x10, 0x00, 0x13, 0xdb, 0xff, - 0x10, 0xbb, 0xef, 0xcf, 0xef, 0xc4, 0xff, - 0x00, 0x00, 0x12, 0x15, 0x00, 0x00, 0x00, - /* ch = 'b' */ - 0x22, 0x74, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x21, 0x30, 0x36, 0x1b, 0x00, 0x00, - 0x32, 0xff, 0xe5, 0x82, 0xa4, 0xff, 0x39, 0x00, - 0x32, 0xff, 0x3b, 0x00, 0x00, 0x82, 0xf7, 0x0d, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x32, 0xff, 0x2a, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x32, 0xff, 0x1f, 0x00, 0x00, 0x35, 0xff, 0x1c, - 0x32, 0xff, 0x59, 0x00, 0x10, 0xb7, 0xa0, 0x00, - 0x32, 0xc8, 0x94, 0xe5, 0xff, 0xd4, 0x19, 0x00, - 0x00, 0x00, 0x00, 0x0f, 0x12, 0x00, 0x00, 0x00, - /* ch = 'c' */ - 0x00, 0x00, 0x08, 0x30, 0x36, 0x2a, 0x04, 0x00, - 0x00, 0x2c, 0xef, 0xb3, 0x74, 0xe5, 0xd4, 0x10, - 0x0d, 0xe5, 0x7c, 0x00, 0x00, 0x08, 0x8d, 0x04, - 0x2f, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x40, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2a, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xb1, 0xdb, 0x13, 0x00, 0x1b, 0x7e, 0x04, - 0x00, 0x10, 0xb3, 0xff, 0xf7, 0xf7, 0x66, 0x04, - 0x00, 0x00, 0x00, 0x0f, 0x15, 0x08, 0x00, 0x00, - /* ch = 'd' */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x74, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, - 0x00, 0x00, 0x2a, 0x36, 0x30, 0x35, 0xff, - 0x00, 0x7c, 0xdb, 0x47, 0xab, 0xf7, 0xff, - 0x2c, 0xff, 0x1f, 0x00, 0x00, 0x97, 0xff, - 0x54, 0xbd, 0x00, 0x00, 0x00, 0x50, 0xff, - 0x77, 0xb7, 0x00, 0x00, 0x00, 0x50, 0xff, - 0x4d, 0xff, 0x0d, 0x00, 0x00, 0x6b, 0xff, - 0x17, 0xff, 0x59, 0x00, 0x21, 0xe5, 0xff, - 0x00, 0x3b, 0xf7, 0xef, 0xef, 0x99, 0xff, - 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, 0x00, - /* ch = 'e' */ - 0x00, 0x00, 0x1b, 0x36, 0x36, 0x16, 0x00, 0x00, - 0x00, 0x50, 0xf7, 0x50, 0x73, 0xff, 0x32, 0x00, - 0x22, 0xff, 0x2c, 0x00, 0x00, 0x64, 0xc8, 0x00, - 0x4d, 0xff, 0x36, 0x36, 0x36, 0x62, 0xff, 0x0d, - 0x50, 0xff, 0x74, 0x74, 0x74, 0x74, 0x74, 0x14, - 0x44, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0xf7, 0x7c, 0x04, 0x00, 0x21, 0x2f, 0x00, - 0x00, 0x26, 0xd4, 0xe5, 0xd4, 0xef, 0x35, 0x00, - 0x00, 0x00, 0x00, 0x12, 0x15, 0x00, 0x00, 0x00, - /* ch = 'f' */ - 0x00, 0x00, 0x00, 0x21, 0x82, 0xbd, 0x5b, - 0x00, 0x00, 0x2a, 0xff, 0x47, 0x1a, 0x99, - 0x00, 0x00, 0x7c, 0xa0, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x00, - 0x2d, 0xcf, 0xef, 0xef, 0xcf, 0xcf, 0x1a, - 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x00, - /* ch = 'g' */ - 0x00, 0x04, 0x37, 0x74, 0x37, 0x16, 0x3e, 0x2a, - 0x00, 0xa9, 0xc4, 0x36, 0xd4, 0xff, 0x50, 0x30, - 0x2a, 0xff, 0x17, 0x00, 0x24, 0xff, 0x1c, 0x00, - 0x2f, 0xff, 0x17, 0x00, 0x24, 0xff, 0x1c, 0x00, - 0x04, 0xb1, 0xd4, 0x47, 0xd4, 0x7c, 0x00, 0x00, - 0x00, 0x7c, 0x6a, 0x50, 0x2a, 0x00, 0x00, 0x00, - 0x11, 0xff, 0x53, 0x15, 0x15, 0x15, 0x00, 0x00, - 0x04, 0xab, 0xa4, 0x8f, 0xcf, 0xe5, 0xb1, 0x04, - 0x66, 0x97, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x27, - 0x66, 0xe5, 0x2b, 0x15, 0x1a, 0x8a, 0xdb, 0x0d, - 0x04, 0x3f, 0x8f, 0xcf, 0xab, 0x5b, 0x08, 0x00, - /* ch = 'h' */ - 0x14, 0x74, 0x28, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x22, 0x36, 0x25, 0x00, - 0x1c, 0xff, 0xd4, 0xbb, 0x8f, 0xff, 0x4d, - 0x1c, 0xff, 0x82, 0x04, 0x00, 0x7c, 0xb7, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x50, 0xf7, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x50, 0xff, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x50, 0xff, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x50, 0xff, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x50, 0xff, - /* ch = 'i' */ - 0x00, 0x00, 0x30, 0x28, 0x00, 0x00, - 0x00, 0x09, 0xf7, 0xb1, 0x00, 0x00, - 0x00, 0x00, 0x0c, 0x08, 0x00, 0x00, - 0x26, 0x36, 0x36, 0x26, 0x00, 0x00, - 0x42, 0x74, 0xe5, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x7c, 0xff, 0xff, 0xff, 0xff, 0x32, - /* ch = 'j' */ - 0x00, 0x00, 0x00, 0x00, 0x21, 0x30, - 0x00, 0x00, 0x00, 0x00, 0xa0, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x0c, - 0x00, 0x16, 0x36, 0x36, 0x36, 0x2d, - 0x00, 0x22, 0x74, 0x74, 0xc8, 0xb7, - 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, - 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, - 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, - 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, - 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, - 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, - 0x00, 0x0c, 0x00, 0x00, 0x82, 0xb1, - 0x2f, 0xdb, 0x2b, 0x37, 0xff, 0x44, - 0x04, 0x5b, 0xcf, 0xbd, 0x37, 0x00, - /* ch = 'k' */ - 0x22, 0x74, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x21, 0x25, 0x09, - 0x32, 0xff, 0x1c, 0x00, 0x35, 0xff, 0x35, 0x00, - 0x32, 0xff, 0x1c, 0x44, 0xf7, 0x2c, 0x00, 0x00, - 0x32, 0xff, 0x7c, 0xff, 0x31, 0x00, 0x00, 0x00, - 0x32, 0xff, 0xdb, 0xdb, 0xb1, 0x04, 0x00, 0x00, - 0x32, 0xff, 0x1f, 0x1f, 0xf7, 0x7c, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x44, 0xff, 0x4d, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x7c, 0xf7, 0x21, - /* ch = 'l' */ - 0x74, 0x74, 0x74, 0x42, 0x00, 0x00, - 0x15, 0x15, 0xbd, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, - /* ch = 'm' */ - 0x26, 0x28, 0x30, 0x30, 0x08, 0x36, 0x30, 0x00, - 0x7c, 0xff, 0x66, 0xf7, 0xef, 0x5a, 0xff, 0x39, - 0x7c, 0x90, 0x00, 0xb7, 0x90, 0x00, 0xbd, 0x50, - 0x7c, 0x7c, 0x00, 0xb7, 0x7c, 0x00, 0xb7, 0x50, - 0x7c, 0x7c, 0x00, 0xb7, 0x7c, 0x00, 0xb7, 0x50, - 0x7c, 0x7c, 0x00, 0xb7, 0x7c, 0x00, 0xb7, 0x50, - 0x7c, 0x7c, 0x00, 0xb7, 0x7c, 0x00, 0xb7, 0x50, - 0x7c, 0x7c, 0x00, 0xb7, 0x7c, 0x00, 0xb7, 0x50, - /* ch = 'n' */ - 0x0d, 0x36, 0x16, 0x25, 0x36, 0x22, 0x00, - 0x1c, 0xff, 0xd4, 0xbb, 0x8f, 0xff, 0x44, - 0x1c, 0xff, 0x7c, 0x00, 0x00, 0x90, 0xb1, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x50, 0xb7, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x50, 0xb7, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x50, 0xb7, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x50, 0xb7, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x50, 0xb7, - /* ch = 'o' */ - 0x00, 0x00, 0x16, 0x36, 0x36, 0x0c, 0x00, 0x00, - 0x00, 0x4d, 0xf7, 0x82, 0xa4, 0xf7, 0x32, 0x00, - 0x24, 0xff, 0x35, 0x00, 0x00, 0x82, 0xe5, 0x04, - 0x6b, 0xe5, 0x00, 0x00, 0x00, 0x24, 0xff, 0x2a, - 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x5f, 0xff, 0x0d, 0x00, 0x00, 0x2c, 0xff, 0x24, - 0x17, 0xf7, 0x7c, 0x04, 0x08, 0xb1, 0xb7, 0x00, - 0x00, 0x26, 0xef, 0xe5, 0xef, 0xbb, 0x13, 0x00, - 0x00, 0x00, 0x00, 0x15, 0x12, 0x00, 0x00, 0x00, - /* ch = 'p' */ - 0x16, 0x36, 0x13, 0x30, 0x36, 0x1e, 0x00, 0x00, - 0x32, 0xff, 0xe5, 0x82, 0xa4, 0xff, 0x4d, 0x00, - 0x32, 0xff, 0x3b, 0x00, 0x00, 0x6b, 0xf7, 0x14, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x24, 0xff, 0x32, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x32, 0xff, 0x1f, 0x00, 0x00, 0x2a, 0xff, 0x2a, - 0x32, 0xff, 0x64, 0x00, 0x08, 0xb1, 0xc8, 0x04, - 0x32, 0xff, 0xbb, 0xe5, 0xf7, 0xd4, 0x1f, 0x00, - 0x32, 0xff, 0x1c, 0x0f, 0x15, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x22, 0x74, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 'q' */ - 0x00, 0x00, 0x25, 0x36, 0x30, 0x19, 0x36, - 0x00, 0x7c, 0xef, 0x50, 0xa4, 0xf7, 0xff, - 0x2c, 0xff, 0x24, 0x00, 0x00, 0x90, 0xff, - 0x6b, 0xcf, 0x00, 0x00, 0x00, 0x50, 0xff, - 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x50, 0xff, - 0x50, 0xff, 0x0d, 0x00, 0x00, 0x5f, 0xff, - 0x17, 0xf7, 0x7c, 0x00, 0x13, 0xe5, 0xff, - 0x00, 0x35, 0xf7, 0xef, 0xef, 0x7c, 0xff, - 0x00, 0x00, 0x04, 0x15, 0x04, 0x32, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x74, - /* ch = 'r' */ - 0x26, 0x2d, 0x0c, 0x36, 0x36, 0x1e, 0x00, - 0x7c, 0xe5, 0xef, 0x9e, 0x82, 0xff, 0x1d, - 0x7c, 0xff, 0x50, 0x00, 0x00, 0x22, 0x00, - 0x7c, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 's' */ - 0x00, 0x00, 0x1e, 0x36, 0x36, 0x1e, 0x00, - 0x00, 0x50, 0xf7, 0x47, 0x50, 0xef, 0x7e, - 0x00, 0xef, 0x68, 0x00, 0x00, 0x1f, 0x2c, - 0x00, 0x73, 0xff, 0x7f, 0x25, 0x04, 0x00, - 0x00, 0x00, 0x22, 0x8f, 0xf7, 0xef, 0x2c, - 0x00, 0x0c, 0x00, 0x00, 0x04, 0x82, 0xf7, - 0x17, 0xd4, 0x1b, 0x00, 0x00, 0x82, 0xc8, - 0x0c, 0x7f, 0xff, 0xd4, 0xef, 0xd4, 0x21, - 0x00, 0x00, 0x04, 0x15, 0x12, 0x00, 0x00, - /* ch = 't' */ - 0x00, 0x00, 0x10, 0x36, 0x13, 0x00, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x14, 0x00, 0x00, - 0x0d, 0x36, 0x82, 0xff, 0x36, 0x36, 0x16, - 0x14, 0x74, 0xb1, 0xff, 0x74, 0x74, 0x22, - 0x00, 0x00, 0x50, 0xcf, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x5f, 0xff, 0x1a, 0x0c, 0x48, - 0x00, 0x00, 0x1c, 0xdb, 0xff, 0xff, 0x8d, - 0x00, 0x00, 0x00, 0x00, 0x15, 0x04, 0x00, - /* ch = 'u' */ - 0x16, 0x36, 0x0d, 0x00, 0x00, 0x1e, 0x36, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x50, 0xff, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x50, 0xff, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x50, 0xff, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x50, 0xff, - 0x32, 0xff, 0x1f, 0x00, 0x00, 0x6b, 0xff, - 0x14, 0xff, 0x54, 0x00, 0x19, 0xf7, 0xff, - 0x00, 0x44, 0xf7, 0xd4, 0xe5, 0xa0, 0xff, - 0x00, 0x00, 0x08, 0x15, 0x04, 0x00, 0x00, - /* ch = 'v' */ - 0x26, 0x36, 0x00, 0x00, 0x00, 0x04, 0x36, 0x13, - 0x39, 0xff, 0x17, 0x00, 0x00, 0x2a, 0xff, 0x14, - 0x04, 0xe5, 0x5a, 0x00, 0x00, 0x5f, 0xa0, 0x00, - 0x00, 0x6b, 0xe5, 0x04, 0x04, 0xe5, 0x39, 0x00, - 0x00, 0x22, 0xff, 0x32, 0x39, 0xe5, 0x04, 0x00, - 0x00, 0x00, 0xa7, 0x8a, 0xa7, 0x5a, 0x00, 0x00, - 0x00, 0x00, 0x3b, 0xff, 0xff, 0x17, 0x00, 0x00, - 0x00, 0x00, 0x0d, 0xf7, 0x8a, 0x00, 0x00, 0x00, - /* ch = 'w' */ - 0x36, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x26, 0x26, - 0xe5, 0x44, 0x00, 0x45, 0x30, 0x00, 0x7c, 0x5f, - 0x90, 0x77, 0x00, 0xcf, 0x90, 0x00, 0xb7, 0x44, - 0x54, 0xb1, 0x1a, 0xff, 0xff, 0x0d, 0xe5, 0x2a, - 0x2f, 0xff, 0x3f, 0x90, 0xe5, 0x3b, 0xff, 0x1a, - 0x14, 0xff, 0xc8, 0x44, 0x7c, 0xb7, 0xe5, 0x00, - 0x00, 0xcf, 0xff, 0x1c, 0x3b, 0xff, 0xa0, 0x00, - 0x00, 0x90, 0xcf, 0x00, 0x0d, 0xff, 0x5f, 0x00, - /* ch = 'x' */ - 0x1c, 0x36, 0x04, 0x00, 0x00, 0x21, 0x33, 0x00, - 0x0d, 0xdb, 0x7c, 0x00, 0x17, 0xf7, 0x44, 0x00, - 0x00, 0x2a, 0xff, 0x32, 0xa0, 0xa0, 0x00, 0x00, - 0x00, 0x00, 0x5f, 0xff, 0xf7, 0x17, 0x00, 0x00, - 0x00, 0x00, 0x21, 0xff, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x04, 0xb1, 0xb1, 0xf7, 0x50, 0x00, 0x00, - 0x00, 0x54, 0xf7, 0x10, 0x44, 0xff, 0x1f, 0x00, - 0x24, 0xff, 0x3b, 0x00, 0x00, 0x82, 0xdb, 0x08, - /* ch = 'y' */ - 0x24, 0x36, 0x0d, 0x00, 0x00, 0x0d, 0x36, 0x16, - 0x2c, 0xff, 0x2c, 0x00, 0x00, 0x32, 0xff, 0x17, - 0x00, 0xc8, 0x70, 0x00, 0x00, 0x70, 0xa7, 0x00, - 0x00, 0x48, 0xf7, 0x0d, 0x04, 0xe5, 0x3b, 0x00, - 0x00, 0x0d, 0xf7, 0x48, 0x32, 0xf7, 0x0d, 0x00, - 0x00, 0x00, 0x70, 0xc8, 0x8a, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0x22, 0xff, 0xff, 0x2c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xa7, 0xcf, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xc8, 0x5a, 0x00, 0x00, 0x00, - 0x60, 0x2b, 0x5f, 0xf7, 0x17, 0x00, 0x00, 0x00, - 0x48, 0xcf, 0x9e, 0x26, 0x00, 0x00, 0x00, 0x00, - /* ch = 'z' */ - 0x0d, 0x36, 0x36, 0x36, 0x36, 0x36, 0x2d, 0x00, - 0x14, 0x74, 0x74, 0x74, 0x7b, 0xff, 0x99, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7c, 0xdb, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x50, 0xf7, 0x1f, 0x00, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, - 0x00, 0x1f, 0xf7, 0x5f, 0x00, 0x00, 0x00, 0x00, - 0x10, 0xdb, 0xb1, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1c, - /* ch = '{' */ - 0x00, 0x00, 0x12, 0x15, 0x0c, - 0x10, 0xbb, 0xe5, 0xcf, 0x45, - 0x66, 0xcf, 0x04, 0x00, 0x00, - 0x7c, 0x7c, 0x00, 0x00, 0x00, - 0x7c, 0xa9, 0x00, 0x00, 0x00, - 0xa7, 0x6b, 0x00, 0x00, 0x00, - 0xbb, 0x10, 0x00, 0x00, 0x00, - 0xf7, 0x1f, 0x00, 0x00, 0x00, - 0xa0, 0x77, 0x00, 0x00, 0x00, - 0x82, 0x7c, 0x00, 0x00, 0x00, - 0xb7, 0x7c, 0x00, 0x00, 0x00, - 0x90, 0xa7, 0x00, 0x00, 0x00, - 0x2f, 0xff, 0x65, 0x36, 0x1e, - 0x00, 0x22, 0x67, 0x74, 0x30, - /* ch = '|' */ - 0x2d, 0x1e, - 0xb7, 0x50, - 0xb7, 0x50, - 0xb7, 0x50, - 0xb7, 0x50, - 0xb7, 0x50, - 0xb7, 0x50, - 0xb7, 0x50, - 0xb7, 0x50, - 0xb7, 0x50, - 0xb7, 0x50, - 0xb7, 0x50, - 0xb7, 0x50, - 0x2d, 0x1e, - /* ch = '}' */ - 0x12, 0x15, 0x0c, 0x00, 0x00, - 0x95, 0xcf, 0xef, 0x66, 0x00, - 0x00, 0x00, 0x26, 0xff, 0x2a, - 0x00, 0x00, 0x00, 0xff, 0x32, - 0x00, 0x00, 0x0a, 0xff, 0x32, - 0x00, 0x00, 0x00, 0xe5, 0x48, - 0x00, 0x00, 0x00, 0x2c, 0xe5, - 0x00, 0x00, 0x00, 0x50, 0xdb, - 0x00, 0x00, 0x00, 0xf7, 0x4d, - 0x00, 0x00, 0x00, 0xff, 0x3b, - 0x00, 0x00, 0x00, 0xff, 0x50, - 0x00, 0x00, 0x17, 0xff, 0x3b, - 0x2d, 0x36, 0x99, 0xef, 0x10, - 0x58, 0x74, 0x50, 0x13, 0x00, - /* ch = '~' */ - 0x00, 0x13, 0x36, 0x25, 0x00, 0x00, 0x0f, 0x00, - 0x32, 0xf7, 0x8f, 0xef, 0x94, 0x31, 0xef, 0x45, - 0x13, 0x3d, 0x00, 0x13, 0x9e, 0xcf, 0x37, 0x00 + /* ch = '!' */ + 0x0d, 0x74, 0x2a, 0x32, 0xff, 0x7c, 0x1c, 0xff, 0x7c, 0x1c, 0xff, 0x50, + 0x0d, 0xff, 0x50, 0x00, 0xff, 0x35, 0x00, 0xff, 0x32, 0x00, 0xab, 0x2d, + 0x00, 0x00, 0x00, 0x16, 0x9e, 0x32, 0x39, 0xff, 0x84, 0x00, 0x12, 0x04, + /* ch = '"' */ + 0x04, 0x67, 0x2a, 0x1c, 0x74, 0x10, 0x1c, 0xff, 0x5a, 0x32, 0xff, 0x32, + 0x0d, 0xff, 0x32, 0x32, 0xff, 0x14, 0x32, 0xf7, 0x04, 0x5f, 0xa0, 0x00, + 0x13, 0x28, 0x00, 0x1e, 0x1e, 0x00, + /* ch = '#' */ + 0x00, 0x00, 0x77, 0x7c, 0x00, 0xcf, 0x44, 0x00, 0x00, 0x00, 0x90, 0x54, + 0x00, 0xff, 0x32, 0x00, 0x0f, 0x15, 0xbd, 0x53, 0x33, 0xff, 0x4a, 0x24, + 0x42, 0x5b, 0xff, 0x62, 0x62, 0xff, 0x36, 0x1e, 0x00, 0x14, 0xff, 0x1c, + 0x35, 0xe5, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x0d, 0x50, 0xb7, 0x00, 0x00, + 0x9c, 0xdd, 0xff, 0xcf, 0xe5, 0xdd, 0xa2, 0x28, 0x00, 0x4d, 0xb7, 0x00, + 0x90, 0x5f, 0x00, 0x00, 0x00, 0x5f, 0x82, 0x00, 0xb7, 0x4d, 0x00, 0x00, + 0x00, 0x67, 0x5c, 0x00, 0xcf, 0x2d, 0x00, 0x00, + /* ch = '$' */ + 0x00, 0x00, 0x00, 0x1e, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x82, + 0xa5, 0x25, 0x00, 0x00, 0x00, 0x4d, 0xef, 0xb1, 0xc8, 0xd4, 0xa9, 0x00, + 0x00, 0xf7, 0x35, 0x50, 0x7c, 0x10, 0x3d, 0x00, 0x00, 0xe5, 0x7c, 0x54, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x26, 0xef, 0xff, 0xa5, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x68, 0xef, 0xf7, 0x66, 0x00, 0x00, 0x00, 0x00, 0x50, + 0x7c, 0x26, 0xff, 0x2a, 0x00, 0x22, 0x00, 0x50, 0x7c, 0x0d, 0xff, 0x2f, + 0x20, 0xff, 0x73, 0x68, 0xa5, 0xa9, 0xb1, 0x04, 0x00, 0x1b, 0x67, 0xe5, + 0xdb, 0x5b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x45, 0x67, 0x00, 0x00, 0x00, + /* ch = '%' */ + 0x00, 0x0c, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xef, 0xef, 0x4d, + 0x00, 0x32, 0xf7, 0x10, 0xb1, 0x54, 0x35, 0xf7, 0x04, 0xc8, 0x50, 0x00, + 0xb1, 0x54, 0x3b, 0xe5, 0x44, 0xdb, 0x04, 0x00, 0x2c, 0xef, 0xef, 0x4d, + 0xe5, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xb7, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x17, 0xf7, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x90, + 0x4d, 0xef, 0xd4, 0x16, 0x00, 0x24, 0xff, 0x2a, 0xff, 0x24, 0x8a, 0x77, + 0x00, 0xa0, 0x6b, 0x1a, 0xff, 0x1f, 0x6b, 0x77, 0x35, 0xf7, 0x10, 0x00, + 0x7c, 0xcb, 0xef, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0x00, + /* ch = '&' */ + 0x00, 0x1f, 0xe5, 0xff, 0xd4, 0x1f, 0x00, 0x00, 0x00, 0xa0, 0x97, 0x04, + 0x97, 0x8a, 0x00, 0x00, 0x00, 0xb1, 0x7c, 0x00, 0x82, 0xa0, 0x00, 0x00, + 0x00, 0x44, 0xf7, 0x37, 0xf7, 0x2f, 0x00, 0x00, 0x00, 0x08, 0xd9, 0xff, + 0x3f, 0x00, 0x00, 0x00, 0x04, 0xc4, 0xb1, 0xdb, 0x7c, 0x00, 0x39, 0x08, + 0x5a, 0xf7, 0x10, 0x2f, 0xff, 0x3b, 0xe5, 0x4d, 0x8a, 0xb7, 0x00, 0x00, + 0x50, 0xff, 0xb1, 0x04, 0x6b, 0xf7, 0x1a, 0x04, 0x6b, 0xff, 0xb1, 0x04, + 0x10, 0xbb, 0xff, 0xff, 0xbb, 0x28, 0xf7, 0x43, 0x00, 0x00, 0x12, 0x0c, + 0x00, 0x00, 0x0c, 0x00, + /* ch = ''' */ + 0x2c, 0x67, 0x00, 0x77, 0xff, 0x11, 0x54, 0xc8, 0x00, 0xa7, 0x5a, 0x00, + 0x2a, 0x10, 0x00, + /* ch = '(' */ + 0x00, 0x00, 0x37, 0x2a, 0x04, 0xa9, 0xd4, 0x31, 0x82, 0xdb, 0x10, 0x00, + 0xff, 0x24, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, + 0xc8, 0x00, 0x00, 0x00, 0xff, 0x35, 0x00, 0x00, 0x77, 0xf7, 0x1f, 0x00, + 0x04, 0x99, 0xef, 0x28, 0x00, 0x00, 0x50, 0x40, + /* ch = ')' */ + 0x00, 0x51, 0x13, 0x00, 0x09, 0x94, 0xf7, 0x2c, 0x00, 0x00, 0x5f, 0xf7, + 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x50, 0xff, + 0x04, 0x77, 0xf7, 0x35, 0x04, 0x9e, 0x1b, 0x00, + /* ch = '*' */ + 0x00, 0x00, 0x00, 0x22, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, + 0x5f, 0x00, 0x00, 0x00, 0x24, 0x48, 0x08, 0xa0, 0x50, 0x16, 0x5b, 0x04, + 0x29, 0x9e, 0xe5, 0xdb, 0xcb, 0xe5, 0x73, 0x13, 0x00, 0x00, 0x21, 0xff, + 0xbd, 0x04, 0x00, 0x00, 0x00, 0x10, 0xdb, 0x44, 0xa0, 0x7c, 0x00, 0x00, + 0x00, 0xa4, 0x90, 0x00, 0x17, 0xf7, 0x43, 0x00, 0x00, 0x10, 0x16, 0x00, + 0x00, 0x0f, 0x00, 0x00, + /* ch = '+' */ + 0x00, 0x00, 0x00, 0x2d, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, + 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, + 0x42, 0x74, 0x74, 0xe5, 0xb1, 0x74, 0x74, 0x22, 0x26, 0x36, 0x36, 0xcf, + 0x82, 0x36, 0x36, 0x16, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, + 0x1e, 0x00, 0x00, 0x00, + /* ch = ',' */ + 0x16, 0x74, 0x2c, 0x40, 0xff, 0xb7, 0x00, 0x82, 0x8a, 0x17, 0xef, 0x1f, + 0x32, 0x2c, 0x00, + /* ch = '-' */ + 0x14, 0x74, 0x74, 0x74, 0x74, 0x74, 0x58, 0x0d, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x2d, + /* ch = '.' */ + 0x10, 0x74, 0x2c, 0x39, 0xff, 0x84, 0x00, 0x12, 0x04, + /* ch = '/' */ + 0x00, 0x2a, 0x37, 0x00, 0xa7, 0x8a, 0x2c, 0xff, 0x22, 0x90, 0xa0, 0x00, + 0xff, 0x2c, 0x00, 0xb7, 0x00, 0x00, 0x39, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = '0' */ + 0x00, 0x04, 0x7e, 0xff, 0xef, 0x44, 0x00, 0x00, 0x00, 0x6b, 0xc8, 0x13, + 0x35, 0xff, 0x2a, 0x00, 0x14, 0xff, 0x2c, 0x00, 0x10, 0xe5, 0xa0, 0x00, + 0x35, 0xff, 0x00, 0x00, 0x82, 0xf7, 0xff, 0x04, 0x50, 0xb7, 0x00, 0x50, + 0xdb, 0x28, 0xff, 0x1c, 0x50, 0xb7, 0x2f, 0xff, 0x1f, 0x1c, 0xff, 0x1c, + 0x3b, 0xff, 0xdb, 0x50, 0x00, 0x2a, 0xff, 0x14, 0x17, 0xff, 0x82, 0x00, + 0x00, 0x50, 0xc8, 0x00, 0x00, 0x90, 0xb7, 0x10, 0x13, 0xe5, 0x44, 0x00, + 0x00, 0x10, 0xa9, 0xf7, 0xf7, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, + 0x0f, 0x00, 0x00, 0x00, + /* ch = '1' */ + 0x00, 0x31, 0xd4, 0xb7, 0xab, 0xab, 0xc8, 0xb7, 0x00, 0x00, 0x7c, 0xb7, + 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x7c, 0xb7, + 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x7c, 0xb7, + 0x00, 0x00, 0x7c, 0xb7, + /* ch = '2' */ + 0x00, 0x19, 0xb3, 0xff, 0xf7, 0x73, 0x04, 0x0a, 0xcb, 0x5f, 0x04, 0x1b, + 0xe5, 0x6b, 0x00, 0x0c, 0x04, 0x00, 0x00, 0x5f, 0xc8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x70, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf7, 0x3b, 0x00, + 0x00, 0x00, 0x21, 0xef, 0x5f, 0x00, 0x00, 0x00, 0x1f, 0xf7, 0x54, 0x00, + 0x00, 0x00, 0x10, 0xdb, 0x54, 0x00, 0x00, 0x00, 0x00, 0x90, 0xb1, 0x00, + 0x00, 0x00, 0x0c, 0x1a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* ch = '3' */ + 0x00, 0x26, 0xcb, 0xff, 0xe5, 0x48, 0x00, 0x00, 0x4d, 0x3f, 0x04, 0x35, + 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x1f, 0xff, 0x32, 0x00, 0x00, 0x30, 0xab, 0xf7, 0x4a, 0x00, 0x00, + 0x00, 0x0c, 0x20, 0x77, 0xf7, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0xb1, 0x04, 0xb1, 0x21, 0x00, + 0x21, 0xf7, 0x50, 0x04, 0x73, 0xff, 0xe5, 0xff, 0x7e, 0x04, 0x00, 0x00, + 0x08, 0x15, 0x0c, 0x00, 0x00, + /* ch = '4' */ + 0x00, 0x00, 0x00, 0x00, 0x77, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xdb, 0xb1, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x77, 0x82, 0x50, 0xff, 0x00, 0x00, 0x00, 0x2f, 0xe5, 0x10, + 0x50, 0xff, 0x00, 0x00, 0x0d, 0xdb, 0x35, 0x00, 0x50, 0xff, 0x00, 0x00, + 0x4d, 0xff, 0xcf, 0xcf, 0xe5, 0xff, 0xcf, 0x1a, 0x0c, 0x15, 0x15, 0x15, + 0x5e, 0xff, 0x15, 0x04, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, + /* ch = '5' */ + 0x00, 0x7c, 0xff, 0xff, 0xff, 0xff, 0xb7, 0x00, 0x82, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x74, + 0x36, 0x36, 0x13, 0x00, 0x00, 0xf7, 0xdb, 0x50, 0xa4, 0xf7, 0x32, 0x00, + 0x25, 0x10, 0x00, 0x00, 0x82, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xff, 0x1a, 0xd4, 0x37, 0x00, + 0x10, 0xb7, 0xa0, 0x00, 0x44, 0xef, 0xdd, 0xf7, 0xbb, 0x10, 0x00, 0x00, + 0x00, 0x15, 0x0f, 0x00, 0x00, + /* ch = '6' */ + 0x00, 0x00, 0x48, 0xef, 0xff, 0xe5, 0x35, 0x00, 0x3b, 0xf7, 0x28, 0x00, + 0x40, 0x1f, 0x00, 0xc8, 0x64, 0x00, 0x00, 0x00, 0x00, 0x14, 0xff, 0x35, + 0x30, 0x36, 0x0c, 0x00, 0x1c, 0xff, 0xef, 0xa4, 0xa4, 0xf7, 0x1f, 0x2d, + 0xff, 0x50, 0x00, 0x00, 0x90, 0xa7, 0x1c, 0xff, 0x24, 0x00, 0x00, 0x44, + 0xff, 0x0d, 0xff, 0x3b, 0x00, 0x00, 0x4d, 0xf7, 0x00, 0x7c, 0xdb, 0x10, + 0x08, 0xb7, 0x7c, 0x00, 0x10, 0xa9, 0xf7, 0xef, 0xbb, 0x10, 0x00, 0x00, + 0x00, 0x0f, 0x12, 0x00, 0x00, + /* ch = '7' */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xb7, 0x00, 0x00, 0x00, 0x04, 0xe5, 0x5a, + 0x00, 0x00, 0x00, 0x39, 0xff, 0x17, 0x00, 0x00, 0x00, 0xa7, 0x8a, 0x00, + 0x00, 0x00, 0x22, 0xff, 0x32, 0x00, 0x00, 0x00, 0x5f, 0xe5, 0x04, 0x00, + 0x00, 0x04, 0xe5, 0x6b, 0x00, 0x00, 0x00, 0x2c, 0xff, 0x24, 0x00, 0x00, + 0x00, 0x70, 0xcf, 0x00, 0x00, 0x00, 0x04, 0xf7, 0x6b, 0x00, 0x00, 0x00, + /* ch = '8' */ + 0x00, 0x10, 0xbb, 0xef, 0xf7, 0x94, 0x08, 0x00, 0x8a, 0xb1, 0x04, 0x13, + 0xe5, 0x5a, 0x00, 0xb7, 0x54, 0x00, 0x00, 0x82, 0x7c, 0x00, 0x6b, 0xf7, + 0x21, 0x1f, 0xf7, 0x2f, 0x00, 0x04, 0x88, 0xf7, 0xf7, 0x46, 0x00, 0x00, + 0x4d, 0xef, 0x31, 0x94, 0xf7, 0x24, 0x17, 0xff, 0x32, 0x00, 0x00, 0x82, + 0xc8, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x47, 0xff, 0x17, 0xff, 0x64, 0x04, + 0x08, 0xb1, 0xa7, 0x00, 0x2f, 0xef, 0xe5, 0xf7, 0xbb, 0x13, 0x00, 0x00, + 0x00, 0x15, 0x0f, 0x00, 0x00, + /* ch = '9' */ + 0x00, 0x13, 0xbb, 0xff, 0xf7, 0x5a, 0x00, 0x00, 0xb1, 0x9e, 0x04, 0x26, + 0xff, 0x39, 0x1a, 0xff, 0x2a, 0x00, 0x00, 0x7c, 0xa0, 0x1c, 0xff, 0x1f, + 0x00, 0x00, 0x50, 0xe5, 0x04, 0xf7, 0x54, 0x00, 0x04, 0x90, 0xff, 0x00, + 0x40, 0xff, 0x8f, 0xcb, 0xf7, 0xff, 0x00, 0x00, 0x16, 0x36, 0x25, 0x54, + 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0x7c, 0x00, 0x2c, 0x1f, 0x00, + 0x35, 0xff, 0x24, 0x00, 0x94, 0xff, 0xef, 0xef, 0x3b, 0x00, 0x00, 0x00, + 0x0c, 0x15, 0x00, 0x00, 0x00, + /* ch = ':' */ + 0x1c, 0xbd, 0x40, 0x36, 0xff, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x74, 0x2c, 0x39, 0xff, 0x84, 0x00, 0x12, 0x04, + /* ch = ';' */ + 0x1c, 0xbd, 0x40, 0x36, 0xff, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x16, 0x74, 0x2c, 0x40, 0xff, 0xb7, 0x00, 0x82, 0x8a, + 0x17, 0xef, 0x1f, 0x32, 0x2c, 0x00, + /* ch = '<' */ + 0x00, 0x00, 0x28, 0xbb, 0x32, 0x1e, 0xb3, 0xef, 0x48, 0x08, 0xef, 0x50, + 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x73, 0x08, 0x00, 0x00, 0x1b, 0xbb, 0xef, 0x3f, 0x04, 0x00, + 0x00, 0x28, 0xd4, 0x32, 0x00, 0x00, 0x00, 0x04, 0x08, + /* ch = '=' */ + 0x7c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x67, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x2d, 0x0f, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x08, + /* ch = '>' */ + 0x7c, 0x7f, 0x13, 0x00, 0x00, 0x13, 0x7f, 0xf7, 0x73, 0x0c, 0x00, 0x00, + 0x16, 0x8d, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x1b, 0xbb, 0xef, 0x13, 0x73, 0xff, 0x73, 0x08, 0x7c, + 0x94, 0x16, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, + /* ch = '?' */ + 0x00, 0x04, 0x31, 0x74, 0x74, 0x22, 0x00, 0x04, 0xa9, 0xef, 0x47, 0x94, + 0xff, 0x44, 0x08, 0x8d, 0x10, 0x00, 0x00, 0xa7, 0xbd, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x90, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x6b, 0x00, + 0x00, 0x00, 0x1c, 0xef, 0x77, 0x04, 0x00, 0x00, 0x00, 0x6b, 0xa7, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x51, 0x00, 0x00, 0x00, 0x00, + 0x09, 0xf7, 0xf7, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0f, 0x00, 0x00, + /* ch = '@' */ + 0x00, 0x00, 0x00, 0x04, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x10, 0x94, 0xe5, + 0xd4, 0xd4, 0x21, 0x00, 0x04, 0xb7, 0x6b, 0x04, 0x00, 0x47, 0xdb, 0x0d, + 0x39, 0xc8, 0x04, 0x00, 0x00, 0x0c, 0xff, 0x2f, 0x82, 0x5f, 0x00, 0x66, + 0xef, 0xcf, 0xe5, 0x44, 0xb7, 0x50, 0x39, 0xe5, 0x10, 0x00, 0xb7, 0x50, + 0xb7, 0x50, 0x50, 0xbd, 0x00, 0x0d, 0xf7, 0x50, 0x7c, 0x6b, 0x17, 0xef, + 0xa4, 0xbb, 0xff, 0x50, 0x39, 0xe5, 0x10, 0x08, 0x30, 0x18, 0x12, 0x0c, + 0x04, 0xb1, 0x99, 0x08, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x10, 0x8d, 0xf7, + 0xcf, 0xe5, 0x97, 0x00, 0x00, 0x00, 0x00, 0x08, 0x15, 0x0c, 0x00, 0x00, + /* ch = 'A' */ + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, + 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xff, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x50, 0xff, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x5f, + 0xff, 0x2a, 0x00, 0x00, 0x00, 0x22, 0xff, 0x14, 0xa0, 0x70, 0x00, 0x00, + 0x00, 0x5a, 0xa0, 0x00, 0x39, 0xf7, 0x0d, 0x00, 0x00, 0xc8, 0xe5, 0xcf, + 0xd4, 0xff, 0x3b, 0x00, 0x24, 0xff, 0x1c, 0x00, 0x00, 0x8a, 0xa7, 0x00, + 0x5f, 0xb7, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0xe5, 0x50, 0x00, 0x00, + 0x00, 0x04, 0xe5, 0x5a, + /* ch = 'B' */ + 0x50, 0xff, 0xff, 0xff, 0xef, 0x8d, 0x10, 0x00, 0x50, 0xb7, 0x00, 0x00, + 0x1e, 0xdb, 0x8a, 0x00, 0x50, 0xb7, 0x00, 0x00, 0x00, 0x64, 0xc8, 0x00, + 0x50, 0xb7, 0x00, 0x00, 0x13, 0xc8, 0x6b, 0x00, 0x50, 0xf7, 0xcf, 0xcf, + 0xff, 0x9e, 0x04, 0x00, 0x50, 0xb7, 0x00, 0x12, 0x2b, 0xdb, 0x7c, 0x00, + 0x50, 0xb7, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x50, 0xb7, 0x00, 0x00, + 0x00, 0x24, 0xff, 0x2f, 0x50, 0xb7, 0x00, 0x00, 0x0c, 0xb1, 0xdb, 0x04, + 0x50, 0xff, 0xff, 0xff, 0xff, 0xab, 0x19, 0x00, + /* ch = 'C' */ + 0x00, 0x04, 0x73, 0xf7, 0xe5, 0xe5, 0x2c, 0x00, 0x00, 0x90, 0xb1, 0x13, + 0x00, 0x43, 0xff, 0x2a, 0x27, 0xff, 0x24, 0x00, 0x00, 0x00, 0x2a, 0x04, + 0x5f, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb1, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xff, 0x24, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0xb1, 0x13, 0x00, 0x28, 0xe5, 0x18, + 0x00, 0x10, 0x94, 0xf7, 0xd4, 0xef, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x15, 0x00, 0x00, 0x00, + /* ch = 'D' */ + 0x50, 0xff, 0xff, 0xff, 0xd4, 0x37, 0x00, 0x00, 0x50, 0xff, 0x00, 0x04, + 0x3f, 0xff, 0x44, 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, 0x70, 0xe5, 0x04, + 0x50, 0xff, 0x00, 0x00, 0x00, 0x2a, 0xff, 0x24, 0x50, 0xff, 0x00, 0x00, + 0x00, 0x1c, 0xff, 0x32, 0x50, 0xff, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x50, 0xff, 0x00, 0x00, 0x00, 0x24, 0xff, 0x24, 0x50, 0xff, 0x00, 0x00, + 0x00, 0x5f, 0xe5, 0x00, 0x50, 0xff, 0x00, 0x00, 0x37, 0xff, 0x35, 0x00, + 0x50, 0xff, 0xcf, 0xff, 0xdd, 0x35, 0x00, 0x00, + /* ch = 'E' */ + 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x32, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0xcf, 0xcf, 0xcf, 0xcf, 0x1a, 0x32, + 0xff, 0x36, 0x36, 0x36, 0x36, 0x0d, 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* ch = 'F' */ + 0x1c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1c, 0xff, 0x32, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0xdd, 0xcf, 0xcf, 0xcf, 0x1a, 0x1c, + 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, + 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, + /* ch = 'G' */ + 0x00, 0x08, 0x8d, 0xff, 0xff, 0xe5, 0x2f, 0x00, 0x00, 0xb1, 0xb1, 0x13, + 0x00, 0x54, 0xff, 0x1e, 0x32, 0xff, 0x17, 0x00, 0x00, 0x00, 0x22, 0x00, + 0x6b, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x82, 0x7c, 0x00, 0x00, 0x95, 0xcf, 0xcf, 0x2d, + 0x77, 0xbd, 0x00, 0x00, 0x12, 0x15, 0xff, 0x32, 0x39, 0xff, 0x17, 0x00, + 0x00, 0x00, 0xff, 0x32, 0x04, 0xc8, 0xb1, 0x0c, 0x00, 0x16, 0xff, 0x32, + 0x00, 0x13, 0xb3, 0xff, 0xd4, 0xf7, 0x73, 0x08, 0x00, 0x00, 0x00, 0x0c, + 0x15, 0x00, 0x00, 0x00, + /* ch = 'H' */ + 0x50, 0xff, 0x04, 0x00, 0x00, 0x32, 0xff, 0x0d, 0x50, 0xff, 0x00, 0x00, + 0x00, 0x32, 0xff, 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, + 0x50, 0xff, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, 0x50, 0xff, 0xcf, 0xcf, + 0xcf, 0xdd, 0xff, 0x00, 0x50, 0xff, 0x15, 0x15, 0x15, 0x3e, 0xff, 0x00, + 0x50, 0xff, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, 0x50, 0xff, 0x00, 0x00, + 0x00, 0x32, 0xff, 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, + 0x50, 0xff, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, + /* ch = 'I' */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x32, 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, + /* ch = 'J' */ + 0x7c, 0xff, 0xff, 0xff, 0xff, 0x32, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x82, 0x82, 0x00, 0x00, + 0x04, 0x10, 0xe5, 0x5a, 0x00, 0x00, 0xef, 0xef, 0xa9, 0x04, 0x00, 0x00, + 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, + /* ch = 'K' */ + 0x7c, 0xbd, 0x00, 0x00, 0x04, 0xb1, 0xb1, 0x08, 0x7c, 0xb7, 0x00, 0x00, + 0x7c, 0xdb, 0x10, 0x00, 0x7c, 0xb7, 0x00, 0x5f, 0xf7, 0x1f, 0x00, 0x00, + 0x7c, 0xb7, 0x50, 0xf7, 0x21, 0x00, 0x00, 0x00, 0x7c, 0xf7, 0xff, 0x82, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0xf7, 0x50, 0xff, 0x32, 0x00, 0x00, 0x00, + 0x7c, 0xb7, 0x00, 0x7c, 0xe5, 0x10, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x10, + 0xdb, 0xa0, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x2f, 0xff, 0x4d, 0x00, + 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x6b, 0xf7, 0x1f, + /* ch = 'L' */ + 0x32, 0xff, 0x24, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, + 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, + 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x32, + 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* ch = 'M' */ + 0x7c, 0xa0, 0x00, 0x00, 0x00, 0x10, 0xf7, 0x32, 0x7c, 0xff, 0x2a, 0x00, + 0x00, 0x5f, 0xff, 0x32, 0x7c, 0xff, 0xa0, 0x00, 0x17, 0xf7, 0xff, 0x32, + 0x7c, 0xa7, 0xff, 0x2c, 0x6b, 0x90, 0xff, 0x32, 0x7c, 0x7c, 0x70, 0xc8, + 0xf7, 0x24, 0xff, 0x32, 0x7c, 0x7c, 0x17, 0xff, 0x7c, 0x00, 0xff, 0x32, + 0x7c, 0x7c, 0x00, 0x28, 0x10, 0x00, 0xff, 0x32, 0x7c, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x32, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, + 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xff, 0x32, + /* ch = 'N' */ + 0x50, 0xff, 0x1c, 0x00, 0x00, 0x32, 0xff, 0x1f, 0x50, 0xff, 0x90, 0x00, + 0x00, 0x32, 0xff, 0x1c, 0x50, 0xf7, 0xff, 0x2a, 0x00, 0x32, 0xff, 0x1c, + 0x50, 0xb7, 0x90, 0xb7, 0x00, 0x32, 0xff, 0x1c, 0x50, 0xb7, 0x1c, 0xff, + 0x44, 0x32, 0xff, 0x1c, 0x50, 0xb7, 0x00, 0x6b, 0xe5, 0x3b, 0xff, 0x1c, + 0x50, 0xb7, 0x00, 0x10, 0xf7, 0xc8, 0xff, 0x1c, 0x50, 0xb7, 0x00, 0x00, + 0x44, 0xff, 0xff, 0x1c, 0x50, 0xb7, 0x00, 0x00, 0x04, 0xc8, 0xff, 0x1c, + 0x50, 0xb7, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, + /* ch = 'O' */ + 0x00, 0x19, 0xbb, 0xff, 0xff, 0x8d, 0x08, 0x00, 0x0d, 0xdb, 0x8a, 0x08, + 0x1b, 0xdb, 0x90, 0x00, 0x48, 0xf7, 0x04, 0x00, 0x00, 0x39, 0xff, 0x22, + 0x90, 0x82, 0x00, 0x00, 0x00, 0x04, 0xff, 0x44, 0xb7, 0x6b, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x50, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x50, + 0x90, 0x90, 0x00, 0x00, 0x00, 0x04, 0xff, 0x44, 0x48, 0xf7, 0x10, 0x00, + 0x00, 0x2c, 0xff, 0x22, 0x0d, 0xdb, 0x8a, 0x08, 0x13, 0xc8, 0xa0, 0x00, + 0x00, 0x1f, 0xd4, 0xff, 0xff, 0xbb, 0x10, 0x00, 0x00, 0x00, 0x00, 0x12, + 0x0c, 0x00, 0x00, 0x00, + /* ch = 'P' */ + 0x32, 0xff, 0xff, 0xff, 0xff, 0xab, 0x19, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x1a, 0xb1, 0xdb, 0x04, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x24, 0xff, 0x24, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x2c, 0xff, 0x1c, 0x32, 0xff, 0x4a, 0x36, + 0x47, 0xef, 0x8a, 0x00, 0x32, 0xff, 0x87, 0x74, 0x74, 0x37, 0x04, 0x00, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = 'Q' */ + 0x00, 0x19, 0xbb, 0xff, 0xff, 0x8d, 0x08, 0x00, 0x0d, 0xdb, 0x8a, 0x08, + 0x16, 0xdb, 0xa0, 0x00, 0x48, 0xe5, 0x04, 0x00, 0x00, 0x2c, 0xff, 0x22, + 0x90, 0x82, 0x00, 0x00, 0x00, 0x04, 0xff, 0x44, 0xb7, 0x5f, 0x00, 0x00, + 0x00, 0x00, 0xbd, 0x50, 0xb7, 0x77, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x50, + 0x90, 0x90, 0x00, 0x00, 0x00, 0x00, 0xff, 0x44, 0x48, 0xf7, 0x0d, 0x00, + 0x00, 0x24, 0xff, 0x22, 0x10, 0xdb, 0x7c, 0x04, 0x08, 0xb1, 0xa0, 0x00, + 0x00, 0x1f, 0xd4, 0xff, 0xff, 0xbb, 0x10, 0x00, 0x00, 0x00, 0x00, 0x82, + 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0xff, 0xcf, 0xcf, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x30, 0x36, 0x00, + /* ch = 'R' */ + 0x50, 0xff, 0xff, 0xff, 0xf7, 0x9e, 0x13, 0x00, 0x50, 0xff, 0x00, 0x04, + 0x20, 0xdb, 0xb7, 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, 0x3b, 0xff, 0x1a, + 0x50, 0xff, 0x00, 0x00, 0x00, 0x48, 0xff, 0x0d, 0x50, 0xff, 0x36, 0x36, + 0x50, 0xf7, 0x6b, 0x00, 0x50, 0xff, 0x74, 0x95, 0xff, 0x46, 0x00, 0x00, + 0x50, 0xff, 0x00, 0x04, 0xdb, 0x6b, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, + 0x3b, 0xff, 0x17, 0x00, 0x50, 0xff, 0x00, 0x00, 0x04, 0xc8, 0x7c, 0x00, + 0x50, 0xff, 0x00, 0x00, 0x00, 0x3b, 0xff, 0x1f, + /* ch = 'S' */ + 0x00, 0x19, 0xab, 0xff, 0xff, 0xb3, 0x1b, 0x00, 0x00, 0xdb, 0x7c, 0x04, + 0x04, 0x5f, 0xa9, 0x00, 0x1c, 0xff, 0x35, 0x00, 0x00, 0x04, 0x08, 0x00, + 0x04, 0xdb, 0xb1, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xbb, 0xf7, + 0x7f, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0xa4, 0xff, 0x4d, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x17, 0x00, 0x0c, 0x00, 0x00, + 0x00, 0x1f, 0xff, 0x2a, 0x2a, 0xdb, 0x1e, 0x00, 0x04, 0x7c, 0xe5, 0x0d, + 0x08, 0x7f, 0xff, 0xe5, 0xf7, 0xd4, 0x21, 0x00, 0x00, 0x00, 0x04, 0x15, + 0x0f, 0x00, 0x00, 0x00, + /* ch = 'T' */ + 0xb7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x32, 0x00, 0x00, 0x00, 0xff, + 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, + /* ch = 'U' */ + 0x50, 0xcf, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x50, 0xb7, 0x00, 0x00, + 0x00, 0x1c, 0xff, 0x32, 0x50, 0xb7, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x50, 0xb7, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x50, 0xb7, 0x00, 0x00, + 0x00, 0x1c, 0xff, 0x32, 0x50, 0xb7, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x50, 0xbd, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x4d, 0xff, 0x04, 0x00, + 0x00, 0x24, 0xff, 0x1c, 0x22, 0xff, 0x50, 0x00, 0x04, 0x82, 0xc8, 0x04, + 0x00, 0x3b, 0xef, 0xdd, 0xef, 0xcb, 0x19, 0x00, 0x00, 0x00, 0x00, 0x15, + 0x0f, 0x00, 0x00, 0x00, + /* ch = 'V' */ + 0xa7, 0x90, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x50, 0x44, 0xff, 0x0d, 0x00, + 0x00, 0x2a, 0xff, 0x1c, 0x14, 0xff, 0x3b, 0x00, 0x00, 0x5f, 0xb7, 0x00, + 0x00, 0xa0, 0x90, 0x00, 0x00, 0xcf, 0x50, 0x00, 0x00, 0x44, 0xff, 0x0d, + 0x22, 0xff, 0x1c, 0x00, 0x00, 0x0d, 0xff, 0x3b, 0x50, 0xb7, 0x00, 0x00, + 0x00, 0x00, 0x90, 0x90, 0xb7, 0x50, 0x00, 0x00, 0x00, 0x00, 0x3b, 0xff, + 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xff, 0xb7, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x90, 0x50, 0x00, 0x00, 0x00, + /* ch = 'W' */ + 0xff, 0x3b, 0x00, 0x08, 0x08, 0x00, 0x54, 0x90, 0xb7, 0x54, 0x00, 0x5f, + 0x5f, 0x00, 0x7c, 0x5f, 0x7c, 0x82, 0x00, 0xb1, 0xa0, 0x00, 0xb1, 0x3b, + 0x50, 0xbd, 0x0d, 0xff, 0xff, 0x0d, 0xe5, 0x2a, 0x32, 0xff, 0x35, 0xb7, + 0xf7, 0x3b, 0xff, 0x14, 0x1c, 0xff, 0xa0, 0x5f, 0x90, 0xa7, 0xe5, 0x00, + 0x04, 0xff, 0xff, 0x2a, 0x4d, 0xff, 0xb1, 0x00, 0x00, 0xbd, 0xf7, 0x04, + 0x24, 0xff, 0x77, 0x00, 0x00, 0x82, 0x90, 0x00, 0x00, 0xe5, 0x4d, 0x00, + 0x00, 0x54, 0x50, 0x00, 0x00, 0x82, 0x32, 0x00, + /* ch = 'X' */ + 0x3b, 0xff, 0x1c, 0x00, 0x00, 0x5f, 0xdb, 0x04, 0x00, 0xb7, 0x90, 0x00, + 0x10, 0xf7, 0x3b, 0x00, 0x00, 0x2a, 0xff, 0x2a, 0x6b, 0xc8, 0x04, 0x00, + 0x00, 0x00, 0x90, 0xc8, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, + 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0xff, 0xe5, 0x0d, 0x00, 0x00, + 0x00, 0x00, 0xa7, 0xb1, 0xf7, 0x5f, 0x00, 0x00, 0x00, 0x32, 0xff, 0x24, + 0x50, 0xf7, 0x17, 0x00, 0x04, 0xc8, 0x7c, 0x00, 0x04, 0xdb, 0x7c, 0x00, + 0x3b, 0xff, 0x1c, 0x00, 0x00, 0x3b, 0xff, 0x24, + /* ch = 'Y' */ + 0x70, 0xe5, 0x04, 0x00, 0x00, 0x1c, 0xff, 0x39, 0x17, 0xff, 0x48, 0x00, + 0x00, 0x70, 0xc8, 0x00, 0x00, 0x6b, 0xe5, 0x04, 0x17, 0xf7, 0x3b, 0x00, + 0x00, 0x17, 0xf7, 0x48, 0x5a, 0xe5, 0x04, 0x00, 0x00, 0x00, 0x6b, 0xe5, + 0xe5, 0x48, 0x00, 0x00, 0x00, 0x00, 0x17, 0xf7, 0xe5, 0x0d, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, + /* ch = 'Z' */ + 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0xf7, 0x17, 0x00, + 0x00, 0x00, 0x00, 0x10, 0xe5, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0xdb, 0x04, 0x00, 0x00, 0x00, 0x00, 0x24, 0xff, 0x32, 0x00, 0x00, 0x00, + 0x00, 0x04, 0xb7, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0xf7, 0x17, + 0x00, 0x00, 0x00, 0x00, 0x17, 0xf7, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x32, + /* ch = '[' */ + 0x1a, 0xcf, 0xcf, 0xcf, 0xcf, 0x67, 0x1c, 0xff, 0x28, 0x15, 0x15, 0x0f, + 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x4a, 0x36, 0x36, 0x26, + 0x0d, 0x36, 0x36, 0x36, 0x36, 0x26, + /* ch = '\' */ + 0x08, 0x5b, 0x0d, 0x0d, 0xf7, 0x50, 0x00, 0x5a, 0xe5, 0x00, 0x10, 0xf7, + 0x00, 0x00, 0x70, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = ']' */ + 0xcf, 0xcf, 0xcf, 0xcf, 0x95, 0x15, 0x15, 0x15, 0x5e, 0xb7, 0x00, 0x00, + 0x00, 0x50, 0xb7, 0x00, 0x00, 0x00, 0x50, 0xb7, 0x00, 0x00, 0x00, 0x50, + 0xb7, 0x00, 0x00, 0x00, 0x50, 0xb7, 0x00, 0x00, 0x00, 0x50, 0xb7, 0x00, + 0x00, 0x00, 0x50, 0xb7, 0x00, 0x00, 0x00, 0x50, 0xb7, 0x00, 0x00, 0x00, + 0x50, 0xb7, 0x00, 0x00, 0x00, 0x50, 0xb7, 0x36, 0x36, 0x36, 0x82, 0xb7, + 0x36, 0x36, 0x36, 0x36, 0x2d, + /* ch = '^' */ + 0x00, 0x00, 0x7c, 0x5a, 0x00, 0x00, 0x00, 0x2a, 0xff, 0xf7, 0x10, 0x00, + 0x04, 0xc8, 0x5f, 0xb7, 0x6b, 0x00, 0x4d, 0xdb, 0x04, 0x2a, 0xf7, 0x17, + 0x28, 0x2a, 0x00, 0x00, 0x48, 0x0c, + /* ch = '_' */ + 0x58, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x30, 0x12, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x0c, + /* ch = '`' */ + 0x09, 0x7f, 0x1c, 0x00, 0xa7, 0x5f, 0x00, 0x44, 0xff, 0x00, 0x04, 0xb1, + /* ch = 'a' */ + 0x00, 0x00, 0x20, 0x36, 0x36, 0x16, 0x00, 0x00, 0x7f, 0xd4, 0x5b, 0x82, + 0xff, 0x32, 0x00, 0x0c, 0x04, 0x00, 0x00, 0x64, 0xbd, 0x00, 0x00, 0x08, + 0x15, 0x2a, 0x82, 0xff, 0x04, 0x7e, 0xef, 0x82, 0x74, 0xb1, 0xff, 0x44, + 0xff, 0x1a, 0x00, 0x00, 0x54, 0xff, 0x4d, 0xff, 0x10, 0x00, 0x13, 0xdb, + 0xff, 0x10, 0xbb, 0xef, 0xcf, 0xef, 0xc4, 0xff, 0x00, 0x00, 0x12, 0x15, + 0x00, 0x00, 0x00, + /* ch = 'b' */ + 0x22, 0x74, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x21, 0x30, 0x36, 0x1b, 0x00, 0x00, 0x32, 0xff, 0xe5, 0x82, + 0xa4, 0xff, 0x39, 0x00, 0x32, 0xff, 0x3b, 0x00, 0x00, 0x82, 0xf7, 0x0d, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x32, 0xff, 0x2a, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x1c, 0xff, 0x32, 0x32, 0xff, 0x1f, 0x00, 0x00, 0x35, 0xff, 0x1c, + 0x32, 0xff, 0x59, 0x00, 0x10, 0xb7, 0xa0, 0x00, 0x32, 0xc8, 0x94, 0xe5, + 0xff, 0xd4, 0x19, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x12, 0x00, 0x00, 0x00, + /* ch = 'c' */ + 0x00, 0x00, 0x08, 0x30, 0x36, 0x2a, 0x04, 0x00, 0x00, 0x2c, 0xef, 0xb3, + 0x74, 0xe5, 0xd4, 0x10, 0x0d, 0xe5, 0x7c, 0x00, 0x00, 0x08, 0x8d, 0x04, + 0x2f, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2a, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xb1, 0xdb, 0x13, 0x00, 0x1b, 0x7e, 0x04, 0x00, 0x10, 0xb3, 0xff, + 0xf7, 0xf7, 0x66, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x15, 0x08, 0x00, 0x00, + /* ch = 'd' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, 0x00, 0x2a, + 0x36, 0x30, 0x35, 0xff, 0x00, 0x7c, 0xdb, 0x47, 0xab, 0xf7, 0xff, 0x2c, + 0xff, 0x1f, 0x00, 0x00, 0x97, 0xff, 0x54, 0xbd, 0x00, 0x00, 0x00, 0x50, + 0xff, 0x77, 0xb7, 0x00, 0x00, 0x00, 0x50, 0xff, 0x4d, 0xff, 0x0d, 0x00, + 0x00, 0x6b, 0xff, 0x17, 0xff, 0x59, 0x00, 0x21, 0xe5, 0xff, 0x00, 0x3b, + 0xf7, 0xef, 0xef, 0x99, 0xff, 0x00, 0x00, 0x08, 0x15, 0x00, 0x00, 0x00, + /* ch = 'e' */ + 0x00, 0x00, 0x1b, 0x36, 0x36, 0x16, 0x00, 0x00, 0x00, 0x50, 0xf7, 0x50, + 0x73, 0xff, 0x32, 0x00, 0x22, 0xff, 0x2c, 0x00, 0x00, 0x64, 0xc8, 0x00, + 0x4d, 0xff, 0x36, 0x36, 0x36, 0x62, 0xff, 0x0d, 0x50, 0xff, 0x74, 0x74, + 0x74, 0x74, 0x74, 0x14, 0x44, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xf7, 0x7c, 0x04, 0x00, 0x21, 0x2f, 0x00, 0x00, 0x26, 0xd4, 0xe5, + 0xd4, 0xef, 0x35, 0x00, 0x00, 0x00, 0x00, 0x12, 0x15, 0x00, 0x00, 0x00, + /* ch = 'f' */ + 0x00, 0x00, 0x00, 0x21, 0x82, 0xbd, 0x5b, 0x00, 0x00, 0x2a, 0xff, 0x47, + 0x1a, 0x99, 0x00, 0x00, 0x7c, 0xa0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x7c, + 0x7c, 0x00, 0x00, 0x00, 0x2d, 0xcf, 0xef, 0xef, 0xcf, 0xcf, 0x1a, 0x00, + 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7c, 0x7c, 0x00, 0x00, 0x00, + /* ch = 'g' */ + 0x00, 0x04, 0x37, 0x74, 0x37, 0x16, 0x3e, 0x2a, 0x00, 0xa9, 0xc4, 0x36, + 0xd4, 0xff, 0x50, 0x30, 0x2a, 0xff, 0x17, 0x00, 0x24, 0xff, 0x1c, 0x00, + 0x2f, 0xff, 0x17, 0x00, 0x24, 0xff, 0x1c, 0x00, 0x04, 0xb1, 0xd4, 0x47, + 0xd4, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x6a, 0x50, 0x2a, 0x00, 0x00, 0x00, + 0x11, 0xff, 0x53, 0x15, 0x15, 0x15, 0x00, 0x00, 0x04, 0xab, 0xa4, 0x8f, + 0xcf, 0xe5, 0xb1, 0x04, 0x66, 0x97, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x27, + 0x66, 0xe5, 0x2b, 0x15, 0x1a, 0x8a, 0xdb, 0x0d, 0x04, 0x3f, 0x8f, 0xcf, + 0xab, 0x5b, 0x08, 0x00, + /* ch = 'h' */ + 0x14, 0x74, 0x28, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x22, 0x36, 0x25, 0x00, 0x1c, 0xff, 0xd4, 0xbb, 0x8f, 0xff, 0x4d, 0x1c, + 0xff, 0x82, 0x04, 0x00, 0x7c, 0xb7, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x50, + 0xf7, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x50, 0xff, 0x1c, 0xff, 0x32, 0x00, + 0x00, 0x50, 0xff, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x50, 0xff, 0x1c, 0xff, + 0x32, 0x00, 0x00, 0x50, 0xff, + /* ch = 'i' */ + 0x00, 0x00, 0x30, 0x28, 0x00, 0x00, 0x00, 0x09, 0xf7, 0xb1, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x08, 0x00, 0x00, 0x26, 0x36, 0x36, 0x26, 0x00, 0x00, + 0x42, 0x74, 0xe5, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, + 0x7c, 0xff, 0xff, 0xff, 0xff, 0x32, + /* ch = 'j' */ + 0x00, 0x00, 0x00, 0x00, 0x21, 0x30, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x0c, 0x00, 0x16, 0x36, 0x36, 0x36, 0x2d, + 0x00, 0x22, 0x74, 0x74, 0xc8, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x0c, 0x00, 0x00, 0x82, 0xb1, + 0x2f, 0xdb, 0x2b, 0x37, 0xff, 0x44, 0x04, 0x5b, 0xcf, 0xbd, 0x37, 0x00, + /* ch = 'k' */ + 0x22, 0x74, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x21, 0x25, 0x09, 0x32, 0xff, 0x1c, 0x00, + 0x35, 0xff, 0x35, 0x00, 0x32, 0xff, 0x1c, 0x44, 0xf7, 0x2c, 0x00, 0x00, + 0x32, 0xff, 0x7c, 0xff, 0x31, 0x00, 0x00, 0x00, 0x32, 0xff, 0xdb, 0xdb, + 0xb1, 0x04, 0x00, 0x00, 0x32, 0xff, 0x1f, 0x1f, 0xf7, 0x7c, 0x00, 0x00, + 0x32, 0xff, 0x1c, 0x00, 0x44, 0xff, 0x4d, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x7c, 0xf7, 0x21, + /* ch = 'l' */ + 0x74, 0x74, 0x74, 0x42, 0x00, 0x00, 0x15, 0x15, 0xbd, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, + /* ch = 'm' */ + 0x26, 0x28, 0x30, 0x30, 0x08, 0x36, 0x30, 0x00, 0x7c, 0xff, 0x66, 0xf7, + 0xef, 0x5a, 0xff, 0x39, 0x7c, 0x90, 0x00, 0xb7, 0x90, 0x00, 0xbd, 0x50, + 0x7c, 0x7c, 0x00, 0xb7, 0x7c, 0x00, 0xb7, 0x50, 0x7c, 0x7c, 0x00, 0xb7, + 0x7c, 0x00, 0xb7, 0x50, 0x7c, 0x7c, 0x00, 0xb7, 0x7c, 0x00, 0xb7, 0x50, + 0x7c, 0x7c, 0x00, 0xb7, 0x7c, 0x00, 0xb7, 0x50, 0x7c, 0x7c, 0x00, 0xb7, + 0x7c, 0x00, 0xb7, 0x50, + /* ch = 'n' */ + 0x0d, 0x36, 0x16, 0x25, 0x36, 0x22, 0x00, 0x1c, 0xff, 0xd4, 0xbb, 0x8f, + 0xff, 0x44, 0x1c, 0xff, 0x7c, 0x00, 0x00, 0x90, 0xb1, 0x1c, 0xff, 0x32, + 0x00, 0x00, 0x50, 0xb7, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x50, 0xb7, 0x1c, + 0xff, 0x32, 0x00, 0x00, 0x50, 0xb7, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x50, + 0xb7, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x50, 0xb7, + /* ch = 'o' */ + 0x00, 0x00, 0x16, 0x36, 0x36, 0x0c, 0x00, 0x00, 0x00, 0x4d, 0xf7, 0x82, + 0xa4, 0xf7, 0x32, 0x00, 0x24, 0xff, 0x35, 0x00, 0x00, 0x82, 0xe5, 0x04, + 0x6b, 0xe5, 0x00, 0x00, 0x00, 0x24, 0xff, 0x2a, 0x7c, 0xb7, 0x00, 0x00, + 0x00, 0x1c, 0xff, 0x32, 0x5f, 0xff, 0x0d, 0x00, 0x00, 0x2c, 0xff, 0x24, + 0x17, 0xf7, 0x7c, 0x04, 0x08, 0xb1, 0xb7, 0x00, 0x00, 0x26, 0xef, 0xe5, + 0xef, 0xbb, 0x13, 0x00, 0x00, 0x00, 0x00, 0x15, 0x12, 0x00, 0x00, 0x00, + /* ch = 'p' */ + 0x16, 0x36, 0x13, 0x30, 0x36, 0x1e, 0x00, 0x00, 0x32, 0xff, 0xe5, 0x82, + 0xa4, 0xff, 0x4d, 0x00, 0x32, 0xff, 0x3b, 0x00, 0x00, 0x6b, 0xf7, 0x14, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x24, 0xff, 0x32, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x1c, 0xff, 0x32, 0x32, 0xff, 0x1f, 0x00, 0x00, 0x2a, 0xff, 0x2a, + 0x32, 0xff, 0x64, 0x00, 0x08, 0xb1, 0xc8, 0x04, 0x32, 0xff, 0xbb, 0xe5, + 0xf7, 0xd4, 0x1f, 0x00, 0x32, 0xff, 0x1c, 0x0f, 0x15, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x74, 0x14, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* ch = 'q' */ + 0x00, 0x00, 0x25, 0x36, 0x30, 0x19, 0x36, 0x00, 0x7c, 0xef, 0x50, 0xa4, + 0xf7, 0xff, 0x2c, 0xff, 0x24, 0x00, 0x00, 0x90, 0xff, 0x6b, 0xcf, 0x00, + 0x00, 0x00, 0x50, 0xff, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x50, 0xff, 0x50, + 0xff, 0x0d, 0x00, 0x00, 0x5f, 0xff, 0x17, 0xf7, 0x7c, 0x00, 0x13, 0xe5, + 0xff, 0x00, 0x35, 0xf7, 0xef, 0xef, 0x7c, 0xff, 0x00, 0x00, 0x04, 0x15, + 0x04, 0x32, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x74, + /* ch = 'r' */ + 0x26, 0x2d, 0x0c, 0x36, 0x36, 0x1e, 0x00, 0x7c, 0xe5, 0xef, 0x9e, 0x82, + 0xff, 0x1d, 0x7c, 0xff, 0x50, 0x00, 0x00, 0x22, 0x00, 0x7c, 0xcf, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = 's' */ + 0x00, 0x00, 0x1e, 0x36, 0x36, 0x1e, 0x00, 0x00, 0x50, 0xf7, 0x47, 0x50, + 0xef, 0x7e, 0x00, 0xef, 0x68, 0x00, 0x00, 0x1f, 0x2c, 0x00, 0x73, 0xff, + 0x7f, 0x25, 0x04, 0x00, 0x00, 0x00, 0x22, 0x8f, 0xf7, 0xef, 0x2c, 0x00, + 0x0c, 0x00, 0x00, 0x04, 0x82, 0xf7, 0x17, 0xd4, 0x1b, 0x00, 0x00, 0x82, + 0xc8, 0x0c, 0x7f, 0xff, 0xd4, 0xef, 0xd4, 0x21, 0x00, 0x00, 0x04, 0x15, + 0x12, 0x00, 0x00, + /* ch = 't' */ + 0x00, 0x00, 0x10, 0x36, 0x13, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x14, + 0x00, 0x00, 0x0d, 0x36, 0x82, 0xff, 0x36, 0x36, 0x16, 0x14, 0x74, 0xb1, + 0xff, 0x74, 0x74, 0x22, 0x00, 0x00, 0x50, 0xcf, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xff, + 0x1a, 0x0c, 0x48, 0x00, 0x00, 0x1c, 0xdb, 0xff, 0xff, 0x8d, 0x00, 0x00, + 0x00, 0x00, 0x15, 0x04, 0x00, + /* ch = 'u' */ + 0x16, 0x36, 0x0d, 0x00, 0x00, 0x1e, 0x36, 0x32, 0xff, 0x1c, 0x00, 0x00, + 0x50, 0xff, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x50, 0xff, 0x32, 0xff, 0x1c, + 0x00, 0x00, 0x50, 0xff, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x50, 0xff, 0x32, + 0xff, 0x1f, 0x00, 0x00, 0x6b, 0xff, 0x14, 0xff, 0x54, 0x00, 0x19, 0xf7, + 0xff, 0x00, 0x44, 0xf7, 0xd4, 0xe5, 0xa0, 0xff, 0x00, 0x00, 0x08, 0x15, + 0x04, 0x00, 0x00, + /* ch = 'v' */ + 0x26, 0x36, 0x00, 0x00, 0x00, 0x04, 0x36, 0x13, 0x39, 0xff, 0x17, 0x00, + 0x00, 0x2a, 0xff, 0x14, 0x04, 0xe5, 0x5a, 0x00, 0x00, 0x5f, 0xa0, 0x00, + 0x00, 0x6b, 0xe5, 0x04, 0x04, 0xe5, 0x39, 0x00, 0x00, 0x22, 0xff, 0x32, + 0x39, 0xe5, 0x04, 0x00, 0x00, 0x00, 0xa7, 0x8a, 0xa7, 0x5a, 0x00, 0x00, + 0x00, 0x00, 0x3b, 0xff, 0xff, 0x17, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xf7, + 0x8a, 0x00, 0x00, 0x00, + /* ch = 'w' */ + 0x36, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x26, 0x26, 0xe5, 0x44, 0x00, 0x45, + 0x30, 0x00, 0x7c, 0x5f, 0x90, 0x77, 0x00, 0xcf, 0x90, 0x00, 0xb7, 0x44, + 0x54, 0xb1, 0x1a, 0xff, 0xff, 0x0d, 0xe5, 0x2a, 0x2f, 0xff, 0x3f, 0x90, + 0xe5, 0x3b, 0xff, 0x1a, 0x14, 0xff, 0xc8, 0x44, 0x7c, 0xb7, 0xe5, 0x00, + 0x00, 0xcf, 0xff, 0x1c, 0x3b, 0xff, 0xa0, 0x00, 0x00, 0x90, 0xcf, 0x00, + 0x0d, 0xff, 0x5f, 0x00, + /* ch = 'x' */ + 0x1c, 0x36, 0x04, 0x00, 0x00, 0x21, 0x33, 0x00, 0x0d, 0xdb, 0x7c, 0x00, + 0x17, 0xf7, 0x44, 0x00, 0x00, 0x2a, 0xff, 0x32, 0xa0, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x5f, 0xff, 0xf7, 0x17, 0x00, 0x00, 0x00, 0x00, 0x21, 0xff, + 0xb7, 0x00, 0x00, 0x00, 0x00, 0x04, 0xb1, 0xb1, 0xf7, 0x50, 0x00, 0x00, + 0x00, 0x54, 0xf7, 0x10, 0x44, 0xff, 0x1f, 0x00, 0x24, 0xff, 0x3b, 0x00, + 0x00, 0x82, 0xdb, 0x08, + /* ch = 'y' */ + 0x24, 0x36, 0x0d, 0x00, 0x00, 0x0d, 0x36, 0x16, 0x2c, 0xff, 0x2c, 0x00, + 0x00, 0x32, 0xff, 0x17, 0x00, 0xc8, 0x70, 0x00, 0x00, 0x70, 0xa7, 0x00, + 0x00, 0x48, 0xf7, 0x0d, 0x04, 0xe5, 0x3b, 0x00, 0x00, 0x0d, 0xf7, 0x48, + 0x32, 0xf7, 0x0d, 0x00, 0x00, 0x00, 0x70, 0xc8, 0x8a, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0x22, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, + 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x5a, 0x00, 0x00, 0x00, + 0x60, 0x2b, 0x5f, 0xf7, 0x17, 0x00, 0x00, 0x00, 0x48, 0xcf, 0x9e, 0x26, + 0x00, 0x00, 0x00, 0x00, + /* ch = 'z' */ + 0x0d, 0x36, 0x36, 0x36, 0x36, 0x36, 0x2d, 0x00, 0x14, 0x74, 0x74, 0x74, + 0x7b, 0xff, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xdb, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x50, 0xf7, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, + 0x32, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf7, 0x5f, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xdb, 0xb1, 0x04, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x1c, + /* ch = '{' */ + 0x00, 0x00, 0x12, 0x15, 0x0c, 0x10, 0xbb, 0xe5, 0xcf, 0x45, 0x66, 0xcf, + 0x04, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0xa9, 0x00, 0x00, + 0x00, 0xa7, 0x6b, 0x00, 0x00, 0x00, 0xbb, 0x10, 0x00, 0x00, 0x00, 0xf7, + 0x1f, 0x00, 0x00, 0x00, 0xa0, 0x77, 0x00, 0x00, 0x00, 0x82, 0x7c, 0x00, + 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x90, 0xa7, 0x00, 0x00, 0x00, + 0x2f, 0xff, 0x65, 0x36, 0x1e, 0x00, 0x22, 0x67, 0x74, 0x30, + /* ch = '|' */ + 0x2d, 0x1e, 0xb7, 0x50, 0xb7, 0x50, 0xb7, 0x50, 0xb7, 0x50, 0xb7, 0x50, + 0xb7, 0x50, 0xb7, 0x50, 0xb7, 0x50, 0xb7, 0x50, 0xb7, 0x50, 0xb7, 0x50, + 0xb7, 0x50, 0x2d, 0x1e, + /* ch = '}' */ + 0x12, 0x15, 0x0c, 0x00, 0x00, 0x95, 0xcf, 0xef, 0x66, 0x00, 0x00, 0x00, + 0x26, 0xff, 0x2a, 0x00, 0x00, 0x00, 0xff, 0x32, 0x00, 0x00, 0x0a, 0xff, + 0x32, 0x00, 0x00, 0x00, 0xe5, 0x48, 0x00, 0x00, 0x00, 0x2c, 0xe5, 0x00, + 0x00, 0x00, 0x50, 0xdb, 0x00, 0x00, 0x00, 0xf7, 0x4d, 0x00, 0x00, 0x00, + 0xff, 0x3b, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x17, 0xff, 0x3b, + 0x2d, 0x36, 0x99, 0xef, 0x10, 0x58, 0x74, 0x50, 0x13, 0x00, + /* ch = '~' */ + 0x00, 0x13, 0x36, 0x25, 0x00, 0x00, 0x0f, 0x00, 0x32, 0xf7, 0x8f, 0xef, + 0x94, 0x31, 0xef, 0x45, 0x13, 0x3d, 0x00, 0x13, 0x9e, 0xcf, 0x37, 0x00 }; /* font_inconsolata_17px */ static const unsigned char pd_inconsolata_font_bitmap_17px_bytes[] = { - /* ch = '!' */ - 0x00, 0x22, 0x1b, - 0x04, 0xff, 0xe5, - 0x04, 0xff, 0xf7, - 0x00, 0xff, 0xb7, - 0x00, 0xbd, 0xb7, - 0x00, 0xb7, 0x7c, - 0x00, 0xb7, 0x7c, - 0x00, 0x90, 0x5f, - 0x00, 0x42, 0x30, - 0x00, 0x00, 0x00, - 0x0d, 0xab, 0x8d, - 0x1c, 0xff, 0xe5, - 0x00, 0x0f, 0x0c, - /* ch = '"' */ - 0x00, 0x22, 0x13, 0x00, 0x22, 0x13, - 0x00, 0xf7, 0xa0, 0x00, 0xff, 0x7c, - 0x00, 0xec, 0x7c, 0x00, 0xff, 0x6b, - 0x0d, 0xff, 0x39, 0x14, 0xff, 0x2c, - 0x30, 0xef, 0x0d, 0x3a, 0xe5, 0x04, - /* ch = '#' */ - 0x00, 0x00, 0x2a, 0x6f, 0x00, 0x30, 0x58, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xb7, 0x00, 0x77, 0xa0, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0x82, 0x00, 0x90, 0x77, 0x00, 0x00, - 0x67, 0xcf, 0xef, 0xef, 0xcf, 0xf7, 0xe5, 0xcf, 0x09, - 0x0f, 0x00, 0xbd, 0x50, 0x00, 0xff, 0x35, 0x00, 0x00, - 0x00, 0x00, 0xff, 0x32, 0x14, 0xff, 0x2a, 0x00, 0x00, - 0x00, 0x14, 0xff, 0x24, 0x1f, 0xff, 0x28, 0x12, 0x00, - 0x95, 0xdd, 0xff, 0xcf, 0xdd, 0xff, 0x74, 0x45, 0x00, - 0x00, 0x32, 0xff, 0x00, 0x4d, 0xcf, 0x00, 0x00, 0x00, - 0x00, 0x4d, 0xb7, 0x00, 0x6b, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0x4e, 0x78, 0x00, 0x67, 0x67, 0x00, 0x00, 0x00, - /* ch = '$' */ - 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x8d, 0xff, 0xff, 0xf7, 0x73, 0x04, - 0x00, 0x99, 0xb1, 0x37, 0xff, 0x1e, 0xdb, 0x2d, - 0x00, 0xff, 0x54, 0x32, 0xff, 0x00, 0x0c, 0x00, - 0x00, 0x77, 0xf7, 0x7c, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x5b, 0xef, 0xff, 0x73, 0x1b, 0x00, - 0x00, 0x00, 0x00, 0x32, 0xff, 0x94, 0xf7, 0x32, - 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, 0x97, 0xa0, - 0x00, 0x40, 0x00, 0x32, 0xff, 0x00, 0x97, 0x90, - 0x1a, 0xf7, 0xbb, 0x62, 0xff, 0x77, 0xf7, 0x2a, - 0x00, 0x13, 0x50, 0xbb, 0xff, 0x73, 0x1b, 0x00, - 0x00, 0x00, 0x00, 0x2d, 0xcf, 0x00, 0x00, 0x00, - /* ch = '%' */ - 0x10, 0x8d, 0xbd, 0x2f, 0x00, 0x00, 0x51, 0x47, - 0x7c, 0x90, 0x3a, 0xf7, 0x14, 0x2a, 0xff, 0x1c, - 0xb7, 0x50, 0x1c, 0xff, 0x2f, 0xb7, 0x6b, 0x00, - 0x6b, 0xb7, 0x53, 0xf7, 0x47, 0xf7, 0x10, 0x00, - 0x04, 0x5b, 0x74, 0x28, 0xdb, 0x50, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x50, 0xdb, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x10, 0xf7, 0x3b, 0x0f, 0x15, 0x00, - 0x00, 0x00, 0x6b, 0xb7, 0x49, 0xef, 0xd4, 0x7c, - 0x00, 0x1c, 0xff, 0x2a, 0xbd, 0x54, 0x1f, 0xff, - 0x00, 0x90, 0x90, 0x00, 0xbd, 0x54, 0x24, 0xff, - 0x2a, 0xff, 0x1c, 0x00, 0x32, 0xf7, 0xe5, 0x77, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x12, 0x00, - /* ch = '&' */ - 0x00, 0x00, 0x3f, 0x74, 0x67, 0x13, 0x00, 0x00, 0x00, - 0x00, 0x4d, 0xf7, 0x47, 0xb1, 0xc8, 0x00, 0x00, 0x00, - 0x00, 0xa9, 0x97, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x5f, 0xe5, 0x0d, 0x50, 0xe5, 0x04, 0x00, 0x00, - 0x00, 0x10, 0xf7, 0xab, 0xf7, 0x32, 0x00, 0x00, 0x00, - 0x00, 0x19, 0xdb, 0xff, 0x4f, 0x00, 0x00, 0x00, 0x00, - 0x10, 0xdb, 0x8a, 0x70, 0xf7, 0x1c, 0x2f, 0x5a, 0x04, - 0x5a, 0xff, 0x17, 0x04, 0xb1, 0xb1, 0x90, 0xb7, 0x00, - 0x7c, 0xd9, 0x00, 0x00, 0x1c, 0xf7, 0xf7, 0x1f, 0x00, - 0x5a, 0xff, 0x35, 0x04, 0x50, 0xff, 0xff, 0x32, 0x00, - 0x04, 0xa9, 0xff, 0xff, 0xe5, 0x2c, 0x82, 0xbb, 0x00, - 0x00, 0x00, 0x0f, 0x12, 0x00, 0x00, 0x08, 0x04, 0x00, - /* ch = ''' */ - 0x04, 0x2a, 0x04, - 0x32, 0xff, 0x39, - 0x32, 0xff, 0x2a, - 0x44, 0xe5, 0x04, - 0x7e, 0x70, 0x00, - /* ch = '(' */ - 0x00, 0x04, 0x22, 0x00, - 0x19, 0xd4, 0xdd, 0x09, - 0xef, 0x8a, 0x04, 0x00, - 0xb1, 0x04, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x00, 0x00, - 0x82, 0x00, 0x00, 0x00, - 0xff, 0x35, 0x00, 0x00, - 0x6b, 0xff, 0x48, 0x00, - 0x00, 0x35, 0xd4, 0x04, - /* ch = ')' */ - 0x22, 0x00, 0x00, 0x00, - 0xdb, 0xbb, 0x19, 0x00, - 0x13, 0xb1, 0xdb, 0x1f, - 0x00, 0x08, 0xb7, 0xc8, - 0x00, 0x00, 0x24, 0xff, - 0x00, 0x00, 0x00, 0xa0, - 0x00, 0x00, 0x00, 0x4d, - 0x00, 0x00, 0x00, 0x32, - 0x00, 0x00, 0x00, 0x35, - 0x00, 0x00, 0x00, 0x5f, - 0x00, 0x00, 0x04, 0xcf, - 0x00, 0x00, 0x4d, 0xff, - 0x00, 0x26, 0xf7, 0x54, - 0x3f, 0xf7, 0x77, 0x00, - 0xd4, 0x37, 0x00, 0x00, - /* ch = '*' */ - 0x00, 0x00, 0x00, 0x67, 0xb5, 0x00, 0x00, 0x00, - 0x08, 0x04, 0x00, 0x6b, 0xb7, 0x00, 0x00, 0x00, - 0x48, 0xe5, 0x48, 0x59, 0x7c, 0x31, 0xbb, 0x5f, - 0x08, 0x2a, 0x8f, 0xef, 0xf7, 0x9e, 0x37, 0x0c, - 0x00, 0x00, 0x1f, 0xef, 0xdb, 0x32, 0x00, 0x00, - 0x00, 0x1f, 0xdb, 0x50, 0x32, 0xf7, 0x1f, 0x00, - 0x00, 0x8d, 0xb1, 0x04, 0x00, 0x82, 0xa4, 0x00, - 0x00, 0x04, 0x08, 0x00, 0x00, 0x08, 0x04, 0x00, - /* ch = '+' */ - 0x00, 0x00, 0x00, 0x45, 0x95, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x50, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x50, 0xb7, 0x00, 0x00, 0x00, - 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, - 0x00, 0x00, 0x00, 0x50, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x50, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x50, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0x12, 0x00, 0x00, 0x00, - /* ch = ',' */ - 0x0d, 0x9e, 0x5b, 0x00, - 0x22, 0xf7, 0xff, 0x1c, - 0x00, 0x54, 0xf7, 0x0d, - 0x04, 0xb1, 0x50, 0x00, - 0x2d, 0x73, 0x00, 0x00, - /* ch = '-' */ - 0x1c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x32, - 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x08, - /* ch = '.' */ - 0x0d, 0x9e, 0x66, - 0x22, 0xff, 0xe5, - 0x00, 0x0f, 0x0c, - /* ch = '/' */ - 0x00, 0x12, 0x00, - 0x2c, 0xff, 0x2d, - 0xa0, 0xb7, 0x00, - 0xff, 0x39, 0x00, - 0xc8, 0x04, 0x00, - 0x44, 0x00, 0x00, - 0x04, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* ch = '0' */ - 0x00, 0x00, 0x19, 0x67, 0x74, 0x22, 0x00, 0x00, - 0x00, 0x1f, 0xf7, 0x85, 0x5a, 0xff, 0x32, 0x00, - 0x00, 0xa0, 0x90, 0x00, 0x00, 0x64, 0xe5, 0x04, - 0x1c, 0xff, 0x2a, 0x00, 0x10, 0xdb, 0xff, 0x32, - 0x35, 0xff, 0x04, 0x00, 0xa0, 0xb1, 0xcf, 0x50, - 0x50, 0xff, 0x00, 0x50, 0xe5, 0x10, 0xb7, 0x7c, - 0x4d, 0xff, 0x32, 0xff, 0x32, 0x00, 0xb7, 0x77, - 0x2f, 0xff, 0xff, 0x50, 0x00, 0x00, 0xe5, 0x4d, - 0x0d, 0xf7, 0x97, 0x00, 0x00, 0x22, 0xff, 0x24, - 0x00, 0x5f, 0xf7, 0x21, 0x08, 0xb1, 0xa0, 0x00, - 0x00, 0x04, 0x84, 0xff, 0xff, 0xbb, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x0f, 0x12, 0x00, 0x00, 0x00, - /* ch = '1' */ - 0x00, 0x00, 0x37, 0x74, 0x14, - 0x28, 0xcb, 0xff, 0xff, 0x1c, - 0x39, 0x25, 0x54, 0xff, 0x1c, - 0x00, 0x00, 0x50, 0xff, 0x1c, - 0x00, 0x00, 0x50, 0xff, 0x1c, - 0x00, 0x00, 0x50, 0xff, 0x1c, - 0x00, 0x00, 0x50, 0xff, 0x1c, - 0x00, 0x00, 0x50, 0xff, 0x1c, - 0x00, 0x00, 0x50, 0xff, 0x1c, - 0x00, 0x00, 0x50, 0xff, 0x1c, - 0x00, 0x00, 0x50, 0xff, 0x1c, - /* ch = '2' */ - 0x00, 0x00, 0x22, 0x74, 0x74, 0x37, 0x04, 0x00, - 0x00, 0x5b, 0xf7, 0x50, 0x5a, 0xf7, 0x7c, 0x00, - 0x00, 0x48, 0x2f, 0x00, 0x00, 0x3b, 0xff, 0x24, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xff, 0x14, - 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf7, 0x50, 0x00, - 0x00, 0x00, 0x00, 0x26, 0xf7, 0x77, 0x00, 0x00, - 0x00, 0x00, 0x1f, 0xf7, 0x6b, 0x00, 0x00, 0x00, - 0x00, 0x10, 0xdb, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x7c, 0xdb, 0x04, 0x00, 0x00, 0x04, 0x0c, - 0x1a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, - /* ch = '3' */ - 0x00, 0x00, 0x31, 0x74, 0x74, 0x22, 0x00, - 0x00, 0x6d, 0xe5, 0x50, 0x7f, 0xff, 0x40, - 0x00, 0x08, 0x08, 0x00, 0x00, 0x70, 0xe5, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xe5, - 0x00, 0x00, 0x00, 0x04, 0x2b, 0xf7, 0x4d, - 0x00, 0x00, 0x32, 0xff, 0xff, 0x9e, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x16, 0xc4, 0xa0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0xff, - 0x04, 0xb1, 0x43, 0x00, 0x13, 0xb7, 0xc8, - 0x00, 0x50, 0xf7, 0xff, 0xff, 0xcb, 0x19, - 0x00, 0x00, 0x04, 0x15, 0x0f, 0x00, 0x00, - /* ch = '4' */ - 0x00, 0x00, 0x00, 0x00, 0x10, 0x74, 0x22, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x90, 0xff, 0x32, 0x00, - 0x00, 0x00, 0x00, 0x3b, 0xf7, 0xff, 0x32, 0x00, - 0x00, 0x00, 0x10, 0xf7, 0x4d, 0xff, 0x32, 0x00, - 0x00, 0x00, 0x90, 0x77, 0x1c, 0xff, 0x32, 0x00, - 0x00, 0x3b, 0xdb, 0x10, 0x1c, 0xff, 0x32, 0x00, - 0x10, 0xf7, 0x32, 0x00, 0x1c, 0xff, 0x32, 0x00, - 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, - /* ch = '5' */ - 0x00, 0x30, 0x74, 0x74, 0x74, 0x74, 0x74, 0x14, - 0x00, 0x77, 0xcf, 0x36, 0x36, 0x36, 0x36, 0x0d, - 0x00, 0x7c, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x90, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xb7, 0xc8, 0xcf, 0xcf, 0x8d, 0x13, 0x00, - 0x00, 0xb1, 0xa9, 0x20, 0x20, 0xc4, 0xdb, 0x0d, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xff, 0x3b, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, - 0x00, 0x08, 0x04, 0x00, 0x00, 0x14, 0xff, 0x4d, - 0x11, 0xdb, 0x5f, 0x04, 0x04, 0x7c, 0xf7, 0x17, - 0x00, 0x2f, 0xe5, 0xf7, 0xef, 0xef, 0x2c, 0x00, - 0x00, 0x00, 0x00, 0x12, 0x15, 0x00, 0x00, 0x00, - /* ch = '6' */ - 0x00, 0x00, 0x08, 0x50, 0xab, 0x74, 0x22, 0x00, - 0x00, 0x0d, 0xd4, 0xc4, 0x3e, 0x77, 0xdb, 0x09, - 0x00, 0x5a, 0xe5, 0x10, 0x00, 0x00, 0x0c, 0x00, - 0x00, 0xcf, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x14, 0xff, 0x52, 0x9e, 0xcf, 0x7f, 0x10, 0x00, - 0x1c, 0xff, 0xff, 0x50, 0x20, 0xc4, 0xb7, 0x04, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x24, 0xff, 0x2f, - 0x1a, 0xff, 0x3b, 0x00, 0x00, 0x00, 0xff, 0x50, - 0x00, 0xe5, 0x70, 0x00, 0x00, 0x14, 0xff, 0x35, - 0x00, 0x5a, 0xf7, 0x21, 0x00, 0x6f, 0xf7, 0x0d, - 0x00, 0x04, 0x7e, 0xff, 0xff, 0xef, 0x2c, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0x15, 0x00, 0x00, 0x00, - /* ch = '7' */ - 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x22, - 0x74, 0x74, 0x74, 0x74, 0xb9, 0xff, 0x17, - 0x00, 0x00, 0x00, 0x00, 0xc8, 0x8a, 0x00, - 0x00, 0x00, 0x00, 0x2c, 0xff, 0x2c, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0xe5, 0x00, 0x00, - 0x00, 0x00, 0x0d, 0xf7, 0x5a, 0x00, 0x00, - 0x00, 0x00, 0x48, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0xa7, 0xa7, 0x00, 0x00, 0x00, - 0x00, 0x1c, 0xff, 0x48, 0x00, 0x00, 0x00, - 0x00, 0x50, 0xff, 0x17, 0x00, 0x00, 0x00, - 0x00, 0xc8, 0xa7, 0x00, 0x00, 0x00, 0x00, - /* ch = '8' */ - 0x00, 0x00, 0x28, 0x82, 0xab, 0x50, 0x04, 0x00, - 0x00, 0x32, 0xff, 0x5a, 0x31, 0xdb, 0xa0, 0x00, - 0x00, 0xa0, 0x90, 0x00, 0x00, 0x3b, 0xff, 0x1a, - 0x00, 0x90, 0xc8, 0x04, 0x00, 0x50, 0xf7, 0x0d, - 0x00, 0x1f, 0xf7, 0x99, 0x31, 0xf7, 0x50, 0x00, - 0x00, 0x00, 0x57, 0xff, 0xff, 0x9e, 0x08, 0x00, - 0x00, 0x77, 0xdb, 0x1b, 0x1b, 0xdb, 0xb1, 0x04, - 0x1c, 0xff, 0x3b, 0x00, 0x00, 0x24, 0xff, 0x39, - 0x2f, 0xff, 0x32, 0x00, 0x00, 0x0d, 0xff, 0x50, - 0x0d, 0xe5, 0xb1, 0x08, 0x04, 0x64, 0xff, 0x1c, - 0x00, 0x26, 0xd4, 0xff, 0xff, 0xef, 0x35, 0x00, - 0x00, 0x00, 0x00, 0x12, 0x15, 0x00, 0x00, 0x00, - /* ch = '9' */ - 0x00, 0x00, 0x28, 0x74, 0x74, 0x2e, 0x00, 0x00, - 0x00, 0x40, 0xff, 0x5a, 0x5a, 0xff, 0x4d, 0x00, - 0x00, 0xe5, 0x64, 0x00, 0x00, 0x5f, 0xf7, 0x0d, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x1f, 0xff, 0x2a, - 0x14, 0xff, 0x3b, 0x00, 0x00, 0x1c, 0xff, 0x35, - 0x00, 0xa0, 0xb7, 0x08, 0x08, 0x8a, 0xff, 0x50, - 0x00, 0x10, 0xcb, 0xff, 0xff, 0xbb, 0xff, 0x35, - 0x00, 0x00, 0x00, 0x12, 0x0c, 0x24, 0xff, 0x2f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xf7, 0x0d, - 0x00, 0x32, 0x3b, 0x00, 0x24, 0xe5, 0x5f, 0x00, - 0x00, 0x66, 0xff, 0xff, 0xff, 0x73, 0x04, 0x00, - 0x00, 0x00, 0x08, 0x15, 0x08, 0x00, 0x00, 0x00, - /* ch = ':' */ - 0x00, 0x0f, 0x0c, - 0x22, 0xff, 0xe5, - 0x0d, 0xab, 0x66, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x0d, 0x9e, 0x66, - 0x22, 0xff, 0xe5, - 0x00, 0x0f, 0x0c, - /* ch = ';' */ - 0x00, 0x0f, 0x0c, 0x00, - 0x22, 0xff, 0xe5, 0x00, - 0x0d, 0xab, 0x66, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x0d, 0x9e, 0x5b, 0x00, - 0x22, 0xf7, 0xff, 0x1c, - 0x00, 0x54, 0xf7, 0x0d, - 0x04, 0xb1, 0x50, 0x00, - 0x2d, 0x73, 0x00, 0x00, - /* ch = '<' */ - 0x00, 0x00, 0x00, 0x00, 0x13, - 0x00, 0x00, 0x13, 0x73, 0xff, - 0x08, 0x66, 0xf7, 0xa4, 0x1b, - 0xf7, 0xb3, 0x1e, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x00, - 0xf7, 0x50, 0x08, 0x00, 0x00, - 0x28, 0xd4, 0xef, 0x37, 0x00, - 0x00, 0x04, 0x37, 0xef, 0xbb, - 0x00, 0x00, 0x00, 0x08, 0x73, - 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = '=' */ - 0x1e, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x26, - 0x30, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x42, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, - 0x0c, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x0f, - /* ch = '>' */ - 0x1b, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x94, 0x1b, 0x00, 0x00, - 0x13, 0x7f, 0xff, 0x7f, 0x13, - 0x00, 0x00, 0x16, 0x8d, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x1a, - 0x00, 0x00, 0x00, 0x37, 0xef, - 0x00, 0x28, 0xd4, 0xef, 0x37, - 0xa4, 0xf7, 0x5a, 0x08, 0x00, - 0x94, 0x13, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = '?' */ - 0x00, 0x00, 0x04, 0x1a, 0x25, 0x0c, 0x00, 0x00, - 0x00, 0x35, 0xef, 0xef, 0xe5, 0xff, 0x4d, 0x00, - 0x11, 0xf7, 0x6b, 0x04, 0x04, 0x82, 0xff, 0x17, - 0x00, 0x0c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0xff, 0x2a, - 0x00, 0x00, 0x00, 0x00, 0x26, 0xf7, 0x7c, 0x00, - 0x00, 0x00, 0x00, 0x17, 0xf7, 0x7c, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x44, 0xff, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x45, 0xcf, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3d, 0xab, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb1, 0xff, 0x36, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, 0x00, - /* ch = '@' */ - 0x00, 0x00, 0x1e, 0x82, 0xcf, 0x73, 0x19, 0x00, - 0x00, 0x40, 0xf7, 0x3f, 0x15, 0x6a, 0xf7, 0x1c, - 0x17, 0xf7, 0x32, 0x00, 0x00, 0x00, 0x90, 0x7c, - 0x50, 0xb7, 0x00, 0x00, 0x2a, 0x67, 0xb1, 0xb7, - 0x82, 0x6b, 0x04, 0xb1, 0xc4, 0x3e, 0x82, 0xb7, - 0xb7, 0x50, 0x2f, 0xff, 0x17, 0x00, 0x50, 0xb7, - 0xa0, 0x5f, 0x2a, 0xff, 0x24, 0x00, 0x90, 0xb7, - 0x5f, 0xa7, 0x00, 0x77, 0xf7, 0xdd, 0xef, 0xb7, - 0x2a, 0xff, 0x24, 0x00, 0x0f, 0x0f, 0x00, 0x00, - 0x00, 0x7c, 0xdb, 0x21, 0x00, 0x00, 0x22, 0x00, - 0x00, 0x04, 0x66, 0xf7, 0xdd, 0xdd, 0xe5, 0x20, - 0x00, 0x00, 0x00, 0x04, 0x15, 0x12, 0x00, 0x00, - /* ch = 'A' */ - 0x00, 0x00, 0x00, 0x3e, 0x22, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xa7, 0x70, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x17, 0xff, 0xe5, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x48, 0xc8, 0xff, 0x39, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x5a, 0x8a, 0x90, 0x00, 0x00, 0x00, - 0x00, 0x1c, 0xff, 0x22, 0x32, 0xff, 0x17, 0x00, 0x00, - 0x00, 0x5a, 0xb7, 0x00, 0x04, 0xe5, 0x5a, 0x00, 0x00, - 0x00, 0xc8, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x00, 0x00, - 0x22, 0xff, 0x2a, 0x00, 0x00, 0x2c, 0xff, 0x2c, 0x00, - 0x5f, 0xe5, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x70, 0x00, - 0xcf, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x5a, 0xf7, 0x0d, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 'B' */ - 0x30, 0x74, 0x74, 0x74, 0x74, 0x37, 0x04, 0x00, - 0x50, 0xff, 0x36, 0x36, 0x66, 0xf7, 0xb1, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x35, 0xff, 0x2a, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x26, 0xff, 0x2a, - 0x50, 0xff, 0x15, 0x15, 0x25, 0xd4, 0xb1, 0x04, - 0x50, 0xff, 0xcf, 0xcf, 0xe5, 0xec, 0x2b, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x43, 0xff, 0x2a, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x7c, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x82, - 0x50, 0xff, 0x00, 0x00, 0x0c, 0x5f, 0xff, 0x2f, - 0x50, 0xff, 0xff, 0xff, 0xff, 0xd4, 0x35, 0x00, - /* ch = 'C' */ - 0x00, 0x00, 0x13, 0x5b, 0x74, 0x67, 0x1b, 0x00, - 0x00, 0x2c, 0xf7, 0x94, 0x36, 0x77, 0xf7, 0x32, - 0x04, 0xdb, 0x82, 0x00, 0x00, 0x00, 0x82, 0x7b, - 0x39, 0xff, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x54, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x77, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x44, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x22, 0xff, 0x48, 0x00, 0x00, 0x00, 0x0c, 0x00, - 0x00, 0x77, 0xf7, 0x28, 0x00, 0x13, 0xc8, 0x7b, - 0x00, 0x04, 0x73, 0xff, 0xe5, 0xff, 0x8d, 0x08, - 0x00, 0x00, 0x00, 0x08, 0x15, 0x08, 0x00, 0x00, - /* ch = 'D' */ - 0x30, 0x74, 0x74, 0x74, 0x5b, 0x1b, 0x00, 0x00, - 0x50, 0xff, 0x36, 0x36, 0xa4, 0xff, 0x4d, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x64, 0xff, 0x1c, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x0d, 0xff, 0x5a, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x90, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x82, 0xb7, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x90, 0xb1, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x6b, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x2c, 0xff, 0x2c, - 0x50, 0xff, 0x00, 0x00, 0x28, 0xdb, 0x7c, 0x00, - 0x50, 0xff, 0xff, 0xff, 0xe5, 0x66, 0x04, 0x00, - /* ch = 'E' */ - 0x22, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x30, - 0x32, 0xff, 0x4a, 0x36, 0x36, 0x36, 0x36, 0x1e, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, - /* ch = 'F' */ - 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x30, - 0xff, 0x82, 0x36, 0x36, 0x36, 0x36, 0x1e, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x5e, 0x15, 0x15, 0x15, 0x0c, 0x00, - 0xff, 0xe5, 0xcf, 0xcf, 0xcf, 0x45, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 'G' */ - 0x00, 0x00, 0x1b, 0x67, 0x74, 0x67, 0x1b, 0x00, - 0x00, 0x32, 0xf7, 0x94, 0x36, 0x85, 0xff, 0x32, - 0x0d, 0xf7, 0x5f, 0x00, 0x00, 0x00, 0x82, 0x35, - 0x44, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x77, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0xb7, 0x00, 0x00, 0x50, 0xff, 0xff, 0xb7, - 0x5f, 0xf7, 0x04, 0x00, 0x00, 0x00, 0x7c, 0xb7, - 0x2a, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xb7, - 0x00, 0x90, 0xdb, 0x24, 0x00, 0x0c, 0xa5, 0xb7, - 0x00, 0x04, 0x7f, 0xff, 0xff, 0xff, 0xb3, 0x28, - 0x00, 0x00, 0x00, 0x08, 0x15, 0x08, 0x00, 0x00, - /* ch = 'H' */ - 0x22, 0x74, 0x1a, 0x00, 0x00, 0x00, 0x74, 0x37, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xff, 0x50, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xff, 0x50, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xff, 0x50, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xff, 0x50, - 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xff, 0x50, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xff, 0x50, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xff, 0x50, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xff, 0x50, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xff, 0x50, - /* ch = 'I' */ - 0x58, 0x74, 0x74, 0x74, 0x74, 0x42, - 0x2d, 0x36, 0xcf, 0xa5, 0x36, 0x26, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xb7, - /* ch = 'J' */ - 0x22, 0x74, 0x74, 0x74, 0x74, 0x58, - 0x16, 0x36, 0x62, 0xff, 0x4a, 0x2d, - 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, - 0x00, 0x00, 0x44, 0xff, 0x14, 0x00, - 0x13, 0x04, 0xb1, 0xb7, 0x00, 0x00, - 0xff, 0xf7, 0xd4, 0x1f, 0x00, 0x00, - 0x12, 0x15, 0x00, 0x00, 0x00, 0x00, - /* ch = 'K' */ - 0x42, 0x74, 0x0a, 0x00, 0x00, 0x19, 0x74, 0x35, - 0x7c, 0xff, 0x00, 0x00, 0x10, 0xdb, 0xb1, 0x04, - 0x7c, 0xff, 0x00, 0x04, 0xb1, 0xb1, 0x08, 0x00, - 0x7c, 0xff, 0x04, 0x99, 0xdb, 0x10, 0x00, 0x00, - 0x7c, 0xff, 0x7c, 0xf7, 0x1f, 0x00, 0x00, 0x00, - 0x7c, 0xff, 0xff, 0xf7, 0x17, 0x00, 0x00, 0x00, - 0x7c, 0xff, 0x26, 0xdb, 0xb1, 0x04, 0x00, 0x00, - 0x7c, 0xff, 0x00, 0x2f, 0xff, 0x50, 0x00, 0x00, - 0x7c, 0xff, 0x00, 0x00, 0x6b, 0xff, 0x1f, 0x00, - 0x7c, 0xff, 0x00, 0x00, 0x04, 0xc8, 0xdb, 0x04, - 0x7c, 0xff, 0x00, 0x00, 0x00, 0x24, 0xff, 0x7c, - /* ch = 'L' */ - 0x14, 0x74, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, - /* ch = 'M' */ - 0x42, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x32, 0x58, - 0x7c, 0xff, 0x1c, 0x00, 0x00, 0x04, 0xe5, 0xb7, - 0x7c, 0xff, 0x8a, 0x00, 0x00, 0x50, 0xff, 0xb7, - 0x7c, 0xff, 0xff, 0x22, 0x0d, 0xe5, 0xf7, 0xb7, - 0x7c, 0xb7, 0xa7, 0x8a, 0x5a, 0xc8, 0x82, 0xb7, - 0x7c, 0xb7, 0x2c, 0xff, 0xf7, 0x32, 0x7c, 0xb7, - 0x7c, 0xb7, 0x00, 0xa0, 0xb7, 0x00, 0x7c, 0xb7, - 0x7c, 0xb7, 0x00, 0x0c, 0x0c, 0x00, 0x7c, 0xb7, - 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, - 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, - 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, - /* ch = 'N' */ - 0x30, 0x74, 0x10, 0x00, 0x00, 0x00, 0x58, 0x42, - 0x50, 0xff, 0x6b, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x50, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xb7, 0x7c, - 0x50, 0xff, 0xc8, 0xa0, 0x00, 0x00, 0xb7, 0x7c, - 0x50, 0xff, 0x32, 0xff, 0x32, 0x00, 0xb7, 0x7c, - 0x50, 0xff, 0x00, 0xa0, 0xc8, 0x04, 0xb7, 0x7c, - 0x50, 0xff, 0x00, 0x24, 0xff, 0x44, 0xb7, 0x7c, - 0x50, 0xff, 0x00, 0x00, 0x6b, 0xe5, 0xcf, 0x7c, - 0x50, 0xff, 0x00, 0x00, 0x10, 0xf7, 0xff, 0x7c, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x50, 0xff, 0x7c, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x04, 0xdb, 0x7c, - /* ch = 'O' */ - 0x00, 0x00, 0x2b, 0x82, 0x9e, 0x48, 0x04, 0x00, - 0x00, 0x50, 0xff, 0x66, 0x50, 0xf7, 0xb1, 0x04, - 0x22, 0xff, 0x3b, 0x00, 0x00, 0x24, 0xff, 0x48, - 0x5f, 0xe5, 0x04, 0x00, 0x00, 0x00, 0xa0, 0xa0, - 0xa0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xf7, - 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, - 0xb7, 0x82, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, - 0x77, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x77, 0xbd, - 0x39, 0xff, 0x24, 0x00, 0x00, 0x04, 0xe5, 0x6b, - 0x04, 0xb7, 0xdb, 0x1b, 0x08, 0x8a, 0xf7, 0x1c, - 0x00, 0x10, 0xbb, 0xff, 0xff, 0xe5, 0x26, 0x00, - 0x00, 0x00, 0x00, 0x0f, 0x12, 0x00, 0x00, 0x00, - /* ch = 'P' */ - 0x22, 0x74, 0x74, 0x74, 0x74, 0x50, 0x08, 0x00, - 0x32, 0xff, 0x87, 0x74, 0x74, 0xef, 0xef, 0x10, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x10, 0xf7, 0x6b, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x1f, 0xff, 0x5a, - 0x32, 0xff, 0xd4, 0xcf, 0xcf, 0xf7, 0xa9, 0x04, - 0x32, 0xff, 0x4a, 0x36, 0x2a, 0x15, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 'Q' */ - 0x00, 0x00, 0x2b, 0x82, 0x9e, 0x48, 0x04, 0x00, - 0x00, 0x50, 0xf7, 0x66, 0x47, 0xef, 0xb1, 0x04, - 0x22, 0xff, 0x3b, 0x00, 0x00, 0x1f, 0xff, 0x48, - 0x5f, 0xe5, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xa0, - 0xa0, 0x90, 0x00, 0x00, 0x00, 0x00, 0x54, 0xf7, - 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, - 0xb7, 0x82, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, - 0x77, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x77, 0xbd, - 0x39, 0xff, 0x24, 0x00, 0x00, 0x04, 0xe5, 0x6b, - 0x04, 0xc8, 0xd4, 0x16, 0x04, 0x70, 0xf7, 0x1c, - 0x00, 0x10, 0xb3, 0xff, 0xff, 0xe5, 0x2c, 0x00, - 0x00, 0x00, 0x00, 0x54, 0xec, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x1c, 0xf7, 0xa4, 0x74, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x16, 0x36, 0x36, 0x1e, - /* ch = 'R' */ - 0x22, 0x74, 0x74, 0x74, 0x74, 0x47, 0x08, 0x00, - 0x32, 0xff, 0x87, 0x74, 0x74, 0xef, 0xd4, 0x0d, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x24, 0xff, 0x44, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xff, 0x66, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x32, 0xff, 0x39, - 0x32, 0xff, 0xd4, 0xcf, 0xcf, 0xff, 0x7c, 0x00, - 0x32, 0xff, 0x4a, 0x36, 0xf7, 0x6d, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x5a, 0xf7, 0x10, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x0d, 0xf7, 0x6b, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x5a, 0xf7, 0x17, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x0d, 0xf7, 0x70, - /* ch = 'S' */ - 0x00, 0x00, 0x22, 0x74, 0x74, 0x50, 0x13, 0x00, - 0x00, 0x50, 0xf7, 0x5a, 0x36, 0xab, 0xf7, 0x1a, - 0x04, 0xf7, 0x54, 0x00, 0x00, 0x00, 0x51, 0x00, - 0x04, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x6b, 0xff, 0x73, 0x0c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x37, 0xe5, 0xff, 0x7f, 0x13, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2b, 0xc4, 0xf7, 0x1f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe5, 0x77, - 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x7c, - 0x2d, 0xf7, 0x37, 0x04, 0x00, 0x3f, 0xff, 0x39, - 0x04, 0x5b, 0xef, 0xff, 0xff, 0xf7, 0x50, 0x00, - 0x00, 0x00, 0x00, 0x15, 0x15, 0x04, 0x00, 0x00, - /* ch = 'T' */ - 0x58, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x58, - 0x2d, 0x36, 0x36, 0xcf, 0xa5, 0x36, 0x36, 0x2d, - 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, - /* ch = 'U' */ - 0x30, 0x74, 0x11, 0x00, 0x00, 0x00, 0x42, 0x42, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x7c, - 0x3b, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xcf, 0x77, - 0x17, 0xf7, 0x8a, 0x04, 0x00, 0x4a, 0xff, 0x2a, - 0x00, 0x26, 0xe5, 0xef, 0xe5, 0xef, 0x3b, 0x00, - 0x00, 0x00, 0x00, 0x12, 0x15, 0x04, 0x00, 0x00, - /* ch = 'V' */ - 0x53, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x74, 0x0a, - 0x5a, 0xf7, 0x0d, 0x00, 0x00, 0x00, 0x90, 0xa0, 0x00, - 0x22, 0xff, 0x39, 0x00, 0x00, 0x0d, 0xf7, 0x44, 0x00, - 0x00, 0xc8, 0x8a, 0x00, 0x00, 0x39, 0xff, 0x14, 0x00, - 0x00, 0x5a, 0xf7, 0x0d, 0x00, 0x7c, 0xa0, 0x00, 0x00, - 0x00, 0x1c, 0xff, 0x39, 0x04, 0xf7, 0x44, 0x00, 0x00, - 0x00, 0x00, 0xb7, 0x8a, 0x2c, 0xff, 0x14, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xf7, 0x7c, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0xff, 0x44, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb7, 0xff, 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x50, 0xa0, 0x00, 0x00, 0x00, 0x00, - /* ch = 'W' */ - 0x74, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x04, 0x74, 0x1a, - 0xbd, 0x5f, 0x00, 0x1c, 0x6c, 0x00, 0x1c, 0xff, 0x1a, - 0x82, 0x90, 0x00, 0x44, 0xe5, 0x00, 0x32, 0xf7, 0x00, - 0x54, 0xcf, 0x00, 0x90, 0xff, 0x24, 0x4d, 0xb1, 0x00, - 0x3b, 0xff, 0x08, 0xf7, 0xff, 0x50, 0x6b, 0x7c, 0x00, - 0x24, 0xff, 0x3f, 0xe5, 0x6b, 0xa0, 0x90, 0x50, 0x00, - 0x0d, 0xff, 0xb7, 0x7c, 0x3b, 0xff, 0xcf, 0x32, 0x00, - 0x00, 0xcf, 0xff, 0x44, 0x14, 0xff, 0xff, 0x1c, 0x00, - 0x00, 0x90, 0xff, 0x1c, 0x00, 0xbd, 0xff, 0x00, 0x00, - 0x00, 0x6b, 0xcf, 0x00, 0x00, 0x6b, 0xbd, 0x00, 0x00, - 0x00, 0x44, 0x6b, 0x00, 0x00, 0x32, 0x82, 0x00, 0x00, - /* ch = 'X' */ - 0x42, 0x74, 0x17, 0x00, 0x00, 0x04, 0x74, 0x35, - 0x0d, 0xe5, 0x70, 0x00, 0x00, 0x50, 0xf7, 0x10, - 0x00, 0x44, 0xff, 0x1c, 0x10, 0xf7, 0x5a, 0x00, - 0x00, 0x04, 0xc8, 0x90, 0x5f, 0xf7, 0x0d, 0x00, - 0x00, 0x00, 0x32, 0xff, 0xf7, 0x50, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xbd, 0xff, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x24, 0xff, 0xff, 0x44, 0x00, 0x00, - 0x00, 0x00, 0xa0, 0xc8, 0x82, 0xe5, 0x0d, 0x00, - 0x00, 0x2c, 0xff, 0x32, 0x17, 0xf7, 0x5f, 0x00, - 0x00, 0xb7, 0xa7, 0x00, 0x00, 0x5f, 0xf7, 0x17, - 0x3b, 0xff, 0x2a, 0x00, 0x00, 0x0d, 0xe5, 0x82, - /* ch = 'Y' */ - 0x4a, 0x67, 0x04, 0x00, 0x00, 0x00, 0x45, 0x64, - 0x2c, 0xff, 0x3b, 0x00, 0x00, 0x0d, 0xf7, 0x5a, - 0x00, 0xa0, 0xc8, 0x04, 0x00, 0x5a, 0xf7, 0x0d, - 0x00, 0x2a, 0xff, 0x3b, 0x04, 0xe5, 0x6b, 0x00, - 0x00, 0x00, 0xa0, 0xc8, 0x48, 0xff, 0x17, 0x00, - 0x00, 0x00, 0x2a, 0xff, 0xf7, 0x70, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xa7, 0xff, 0x22, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, - /* ch = 'Z' */ - 0x22, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x42, - 0x16, 0x36, 0x36, 0x36, 0x36, 0x57, 0xff, 0x44, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xb7, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3b, 0xff, 0x24, 0x00, - 0x00, 0x00, 0x00, 0x0d, 0xe5, 0x6b, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x6b, 0xe5, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x24, 0xff, 0x44, 0x00, 0x00, 0x00, - 0x00, 0x04, 0xb7, 0xb7, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x44, 0xff, 0x24, 0x00, 0x00, 0x00, 0x00, - 0x10, 0xf7, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x0c, - 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb7, - /* ch = '[' */ - 0x0d, 0x36, 0x36, 0x36, 0x36, 0x36, 0x0d, - 0x1c, 0xff, 0x9c, 0x74, 0x74, 0x74, 0x14, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x62, 0x36, 0x36, 0x36, 0x0d, - 0x14, 0x74, 0x74, 0x74, 0x74, 0x74, 0x14, - /* ch = '\' */ - 0x00, 0x0f, 0x04, - 0x11, 0xff, 0x48, - 0x00, 0x70, 0xdb, - 0x00, 0x22, 0xff, - 0x00, 0x00, 0x8a, - 0x00, 0x00, 0x2a, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* ch = ']' */ - 0x2d, 0x36, 0x36, 0x36, 0x36, 0x16, - 0x58, 0x74, 0x74, 0x87, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x36, 0x36, 0x36, 0x4a, 0xff, 0x32, - 0x74, 0x74, 0x74, 0x74, 0x74, 0x22, - /* ch = '^' */ - 0x00, 0x00, 0x1f, 0x45, 0x00, 0x00, - 0x00, 0x00, 0xb1, 0xf7, 0x17, 0x00, - 0x00, 0x3b, 0xf7, 0xdb, 0x7c, 0x00, - 0x0d, 0xe5, 0x4d, 0x32, 0xff, 0x1c, - 0x60, 0xb7, 0x04, 0x00, 0xa0, 0x7e, - 0x00, 0x0c, 0x00, 0x00, 0x0c, 0x04, - /* ch = '_' */ - 0x42, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, - 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - /* ch = '`' */ - 0x1b, 0x16, 0x00, 0x00, - 0xa7, 0x70, 0x00, 0x00, - 0x44, 0xf7, 0x1f, 0x00, - 0x0d, 0xe5, 0xef, 0x14, - 0x00, 0x26, 0x74, 0x0d, - /* ch = 'a' */ - 0x00, 0x13, 0x8d, 0xe5, 0xef, 0xab, 0x21, 0x00, - 0x00, 0x54, 0x84, 0x18, 0x0f, 0x7c, 0xf7, 0x0d, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x25, 0x47, 0x74, 0x87, 0xff, 0x32, - 0x04, 0xa9, 0xdb, 0x47, 0x36, 0x36, 0xff, 0x32, - 0x44, 0xff, 0x1c, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x44, 0xff, 0x28, 0x00, 0x08, 0xa0, 0xff, 0x32, - 0x04, 0x94, 0xff, 0xcf, 0xf7, 0x94, 0xff, 0x32, - 0x00, 0x00, 0x0f, 0x15, 0x08, 0x00, 0x00, 0x00, - /* ch = 'b' */ - 0x16, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x64, 0xbd, 0xff, 0xc4, 0x26, 0x00, - 0x32, 0xff, 0xdb, 0x20, 0x1a, 0xb1, 0xf7, 0x17, - 0x32, 0xff, 0x3b, 0x00, 0x00, 0x17, 0xff, 0x5f, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0xbd, 0x90, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0xb7, 0x90, - 0x32, 0xff, 0x35, 0x00, 0x00, 0x04, 0xf7, 0x5f, - 0x32, 0xff, 0xb1, 0x08, 0x04, 0x7c, 0xff, 0x1c, - 0x32, 0xf7, 0x73, 0xff, 0xff, 0xf7, 0x3b, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0x15, 0x04, 0x00, 0x00, - /* ch = 'c' */ - 0x00, 0x00, 0x35, 0xbd, 0xef, 0xcf, 0x5b, 0x04, - 0x00, 0x50, 0xff, 0x50, 0x15, 0x31, 0xef, 0x6d, - 0x14, 0xf7, 0x5f, 0x00, 0x00, 0x00, 0x30, 0x10, - 0x32, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x77, 0xf7, 0x31, 0x00, 0x13, 0x8d, 0x2c, - 0x00, 0x04, 0x7f, 0xff, 0xff, 0xff, 0xbb, 0x19, - 0x00, 0x00, 0x00, 0x08, 0x15, 0x0f, 0x00, 0x00, - /* ch = 'd' */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x24, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, - 0x00, 0x13, 0x9e, 0xff, 0xe5, 0x50, 0xff, 0x50, - 0x04, 0xdb, 0xb1, 0x16, 0x16, 0xc4, 0xff, 0x50, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x2c, 0xff, 0x50, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x50, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x50, - 0x3b, 0xff, 0x24, 0x00, 0x00, 0x2c, 0xff, 0x50, - 0x0d, 0xf7, 0xb1, 0x08, 0x0c, 0xb1, 0xff, 0x50, - 0x00, 0x2c, 0xef, 0xff, 0xff, 0x66, 0xff, 0x50, - 0x00, 0x00, 0x04, 0x15, 0x08, 0x00, 0x00, 0x00, - /* ch = 'e' */ - 0x00, 0x04, 0x73, 0xe5, 0xff, 0xab, 0x19, 0x00, - 0x00, 0xa0, 0xc8, 0x16, 0x08, 0x8a, 0xdb, 0x0d, - 0x24, 0xff, 0x2c, 0x00, 0x00, 0x0d, 0xff, 0x3b, - 0x4d, 0xff, 0x7b, 0x74, 0x74, 0x74, 0xff, 0x50, - 0x50, 0xff, 0x17, 0x15, 0x15, 0x15, 0x15, 0x0c, - 0x32, 0xff, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0xdb, 0xb1, 0x13, 0x00, 0x13, 0x5b, 0x08, - 0x00, 0x19, 0xbb, 0xff, 0xcf, 0xff, 0x8d, 0x04, - 0x00, 0x00, 0x00, 0x0f, 0x15, 0x08, 0x00, 0x00, - /* ch = 'f' */ - 0x00, 0x00, 0x1e, 0x36, 0x2a, 0x04, 0x00, - 0x04, 0x99, 0xef, 0x74, 0xd4, 0xd4, 0x0d, - 0x39, 0xff, 0x24, 0x00, 0x04, 0x73, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x82, 0xff, 0x36, 0x36, 0x1e, 0x00, 0x00, - 0xb1, 0xff, 0x74, 0x74, 0x30, 0x00, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 'g' */ - 0x00, 0x19, 0xb3, 0xff, 0xef, 0x66, 0xc4, 0xff, - 0x0d, 0xdb, 0x7c, 0x04, 0x28, 0xff, 0x4f, 0x00, - 0x2f, 0xff, 0x1c, 0x00, 0x00, 0xb7, 0x77, 0x00, - 0x1c, 0xff, 0x3b, 0x00, 0x10, 0xe5, 0x50, 0x00, - 0x00, 0x50, 0xff, 0x9e, 0xef, 0xa9, 0x04, 0x00, - 0x00, 0xa0, 0x64, 0x36, 0x20, 0x00, 0x00, 0x00, - 0x00, 0xf7, 0x7c, 0x36, 0x36, 0x36, 0x0f, 0x00, - 0x04, 0x8f, 0xab, 0x74, 0x74, 0xd4, 0xff, 0x32, - 0x5a, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x97, 0x7c, - 0x66, 0xf7, 0x2b, 0x04, 0x04, 0x2b, 0xf7, 0x44, - 0x04, 0x5b, 0xcf, 0xef, 0xe5, 0xbd, 0x37, 0x00, - /* ch = 'h' */ - 0x04, 0x15, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x59, 0x7f, 0xf7, 0xdd, 0x2f, 0x00, - 0x1c, 0xff, 0xff, 0x65, 0x15, 0x8a, 0xf7, 0x14, - 0x1c, 0xff, 0x7c, 0x00, 0x00, 0x24, 0xff, 0x32, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x1c, 0xff, 0x32, - /* ch = 'i' */ - 0x00, 0x00, 0x08, 0x0c, 0x00, 0x00, - 0x00, 0x00, 0xb1, 0xff, 0x14, 0x00, - 0x00, 0x00, 0x35, 0x5b, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x45, 0xcf, 0xcf, 0x95, 0x00, 0x00, - 0x0c, 0x15, 0x88, 0xb7, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, - 0x7c, 0xff, 0xff, 0xff, 0xff, 0x7c, - /* ch = 'j' */ - 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, - 0x00, 0x00, 0x00, 0x4d, 0xff, 0x44, - 0x00, 0x00, 0x00, 0x19, 0x74, 0x19, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1a, 0xcf, 0xcf, 0xcf, 0xcf, 0x2d, - 0x04, 0x15, 0x15, 0x3e, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x32, 0xff, 0x2f, - 0x0c, 0x00, 0x00, 0x3b, 0xff, 0x1c, - 0xdb, 0x2b, 0x1a, 0xc8, 0xb1, 0x00, - 0x8d, 0xf7, 0xf7, 0x8d, 0x10, 0x00, - /* ch = 'k' */ - 0x04, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x3b, 0xcf, 0x2d, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x50, 0xf7, 0x32, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x5f, 0xf7, 0x26, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0xd4, 0xff, 0x5e, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0xd4, 0x8a, 0xff, 0x32, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x04, 0xb1, 0xe5, 0x10, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x10, 0xdb, 0xb1, 0x04, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x1f, 0xf7, 0x7c, 0x04, - /* ch = 'l' */ - 0x12, 0x15, 0x15, 0x12, 0x00, 0x00, 0x00, - 0x58, 0x74, 0xc8, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1c, - /* ch = 'm' */ - 0x67, 0xbd, 0xcb, 0xef, 0x47, 0xc4, 0xf7, 0x4d, - 0x7c, 0xff, 0x1f, 0x97, 0xff, 0x32, 0x64, 0xf7, - 0x7c, 0xb7, 0x00, 0x7c, 0xe5, 0x00, 0x50, 0xff, - 0x7c, 0xb7, 0x00, 0x7c, 0xb7, 0x00, 0x50, 0xff, - 0x7c, 0xb7, 0x00, 0x7c, 0xb7, 0x00, 0x50, 0xff, - 0x7c, 0xb7, 0x00, 0x7c, 0xb7, 0x00, 0x50, 0xff, - 0x7c, 0xb7, 0x00, 0x7c, 0xb7, 0x00, 0x50, 0xff, - 0x7c, 0xb7, 0x00, 0x7c, 0xb7, 0x00, 0x50, 0xff, - /* ch = 'n' */ - 0x1a, 0xcf, 0x32, 0x7f, 0xf7, 0xdd, 0x2c, 0x00, - 0x1c, 0xff, 0xf7, 0x5a, 0x15, 0x90, 0xf7, 0x0d, - 0x1c, 0xff, 0x70, 0x00, 0x00, 0x24, 0xff, 0x32, - 0x1c, 0xff, 0x3b, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, - /* ch = 'o' */ - 0x00, 0x04, 0x66, 0xdd, 0xef, 0x9e, 0x19, 0x00, - 0x00, 0x99, 0xdb, 0x2b, 0x1a, 0xb1, 0xe5, 0x10, - 0x2c, 0xff, 0x2c, 0x00, 0x00, 0x17, 0xff, 0x5a, - 0x6b, 0xff, 0x04, 0x00, 0x00, 0x00, 0xb7, 0xb1, - 0x77, 0xff, 0x00, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0x44, 0xff, 0x24, 0x00, 0x00, 0x04, 0xe5, 0x6b, - 0x0d, 0xdb, 0xb1, 0x08, 0x00, 0x5f, 0xff, 0x24, - 0x00, 0x19, 0xcb, 0xf7, 0xe5, 0xef, 0x35, 0x00, - 0x00, 0x00, 0x00, 0x12, 0x15, 0x04, 0x00, 0x00, - /* ch = 'p' */ - 0x2d, 0xcf, 0x50, 0xab, 0xf7, 0xbd, 0x26, 0x00, - 0x32, 0xff, 0xdb, 0x25, 0x1a, 0xb1, 0xff, 0x1f, - 0x32, 0xff, 0x3b, 0x00, 0x00, 0x10, 0xff, 0x77, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0xa7, 0xb7, - 0x32, 0xff, 0x35, 0x00, 0x00, 0x04, 0xe5, 0x7c, - 0x32, 0xff, 0xb1, 0x08, 0x04, 0x5f, 0xff, 0x2a, - 0x32, 0xff, 0xbb, 0xff, 0xf7, 0xf7, 0x44, 0x00, - 0x32, 0xff, 0x32, 0x0c, 0x15, 0x08, 0x00, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2d, 0xcf, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 'q' */ - 0x00, 0x10, 0x8d, 0xf7, 0xef, 0x66, 0xcf, 0x45, - 0x04, 0xc8, 0xb1, 0x16, 0x16, 0xb1, 0xff, 0x50, - 0x39, 0xff, 0x22, 0x00, 0x00, 0x24, 0xff, 0x50, - 0x5f, 0xff, 0x00, 0x00, 0x00, 0x1a, 0xff, 0x50, - 0x5f, 0xff, 0x00, 0x00, 0x00, 0x14, 0xff, 0x50, - 0x44, 0xff, 0x24, 0x00, 0x00, 0x24, 0xff, 0x50, - 0x0d, 0xe5, 0xb1, 0x08, 0x08, 0xb1, 0xff, 0x50, - 0x00, 0x21, 0xef, 0xff, 0xff, 0x66, 0xff, 0x50, - 0x00, 0x00, 0x00, 0x15, 0x0c, 0x00, 0xff, 0x50, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x45, - /* ch = 'r' */ - 0x67, 0xcf, 0x2f, 0xbd, 0xff, 0xd4, 0x2f, - 0x7c, 0xff, 0xf7, 0x37, 0x15, 0x64, 0x50, - 0x7c, 0xff, 0x44, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 's' */ - 0x00, 0x08, 0x73, 0xe5, 0xff, 0xbd, 0x37, 0x00, - 0x00, 0x8a, 0xdb, 0x16, 0x04, 0x3f, 0xff, 0x1a, - 0x00, 0xb1, 0xc8, 0x08, 0x00, 0x00, 0x21, 0x00, - 0x00, 0x2c, 0xef, 0xf7, 0x8f, 0x2a, 0x04, 0x00, - 0x00, 0x00, 0x08, 0x31, 0x9e, 0xff, 0xd4, 0x10, - 0x00, 0x0c, 0x00, 0x00, 0x00, 0x28, 0xff, 0x4d, - 0x17, 0xef, 0x31, 0x00, 0x00, 0x3a, 0xff, 0x2c, - 0x04, 0x5b, 0xef, 0xef, 0xef, 0xf7, 0x50, 0x00, - 0x00, 0x00, 0x00, 0x15, 0x15, 0x00, 0x00, 0x00, - /* ch = 't' */ - 0x00, 0x00, 0x1a, 0xf7, 0x44, 0x00, 0x00, - 0x00, 0x00, 0x1f, 0xff, 0x32, 0x00, 0x00, - 0x1a, 0xcf, 0xdd, 0xff, 0xdd, 0xcf, 0x95, - 0x04, 0x15, 0x3e, 0xff, 0x28, 0x15, 0x12, - 0x00, 0x00, 0x35, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x3b, 0xff, 0x3f, 0x08, 0x48, - 0x00, 0x00, 0x04, 0xa9, 0xff, 0xff, 0xcb, - 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x00, - /* ch = 'u' */ - 0x2d, 0xcf, 0x2d, 0x00, 0x00, 0x1a, 0xcf, 0x2d, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x24, 0xff, 0x35, 0x00, 0x00, 0x2a, 0xff, 0x32, - 0x04, 0xe5, 0xa0, 0x04, 0x08, 0xb1, 0xff, 0x32, - 0x00, 0x2c, 0xef, 0xe5, 0xef, 0x84, 0xff, 0x3b, - 0x00, 0x00, 0x04, 0x15, 0x0c, 0x00, 0x00, 0x00, - /* ch = 'v' */ - 0x4a, 0xcf, 0x1a, 0x00, 0x00, 0x00, 0x78, 0x73, - 0x17, 0xff, 0x48, 0x00, 0x00, 0x04, 0xf7, 0x3b, - 0x00, 0xa7, 0xc8, 0x00, 0x00, 0x39, 0xf7, 0x0d, - 0x00, 0x39, 0xff, 0x22, 0x00, 0x97, 0x70, 0x00, - 0x00, 0x04, 0xe5, 0x70, 0x22, 0xff, 0x22, 0x00, - 0x00, 0x00, 0x6b, 0xf7, 0x82, 0xa7, 0x00, 0x00, - 0x00, 0x00, 0x22, 0xff, 0xff, 0x39, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xa7, 0xe5, 0x04, 0x00, 0x00, - /* ch = 'w' */ - 0xcf, 0x45, 0x00, 0x00, 0x00, 0x00, 0x2d, 0xcf, 0x17, - 0xb1, 0x6b, 0x00, 0x54, 0xb7, 0x00, 0x32, 0xff, 0x00, - 0x6b, 0xb1, 0x00, 0xa0, 0xff, 0x17, 0x4d, 0xb7, 0x00, - 0x3b, 0xff, 0x04, 0xff, 0xf7, 0x44, 0x5f, 0x82, 0x00, - 0x1f, 0xff, 0x48, 0xcf, 0x6b, 0x90, 0x82, 0x54, 0x00, - 0x04, 0xff, 0xc8, 0x6b, 0x32, 0xff, 0xcf, 0x35, 0x00, - 0x00, 0xb1, 0xff, 0x32, 0x0d, 0xf7, 0xff, 0x1c, 0x00, - 0x00, 0x6b, 0xff, 0x0d, 0x00, 0x90, 0xf7, 0x00, 0x00, - /* ch = 'x' */ - 0x28, 0xcf, 0x32, 0x00, 0x00, 0x32, 0xcf, 0x1d, - 0x00, 0x6b, 0xf7, 0x17, 0x10, 0xe5, 0x5f, 0x00, - 0x00, 0x04, 0xb7, 0xb1, 0x82, 0xc8, 0x04, 0x00, - 0x00, 0x00, 0x1f, 0xf7, 0xff, 0x24, 0x00, 0x00, - 0x00, 0x00, 0x17, 0xf7, 0xff, 0x24, 0x00, 0x00, - 0x00, 0x00, 0xb1, 0xb7, 0xa0, 0xdb, 0x0d, 0x00, - 0x00, 0x50, 0xff, 0x1f, 0x10, 0xe5, 0x7c, 0x00, - 0x1f, 0xf7, 0x54, 0x00, 0x00, 0x32, 0xff, 0x35, - /* ch = 'y' */ - 0x3a, 0xcf, 0x2d, 0x00, 0x00, 0x00, 0x87, 0x82, - 0x0d, 0xf7, 0x5a, 0x00, 0x00, 0x0d, 0xff, 0x44, - 0x00, 0x70, 0xe5, 0x04, 0x00, 0x3b, 0xff, 0x14, - 0x00, 0x22, 0xff, 0x39, 0x00, 0x90, 0x8a, 0x00, - 0x00, 0x00, 0xa7, 0xa0, 0x14, 0xff, 0x32, 0x00, - 0x00, 0x00, 0x39, 0xff, 0x65, 0xe5, 0x04, 0x00, - 0x00, 0x00, 0x04, 0xf7, 0xff, 0x5f, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x70, 0xff, 0x22, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x70, 0xa7, 0x00, 0x00, 0x00, - 0x49, 0x28, 0x2b, 0xff, 0x44, 0x00, 0x00, 0x00, - 0x6c, 0xf7, 0xef, 0x50, 0x00, 0x00, 0x00, 0x00, - /* ch = 'z' */ - 0x1a, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x1a, - 0x04, 0x15, 0x15, 0x15, 0x17, 0xc6, 0xb1, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x7c, 0xf7, 0x1c, 0x00, - 0x00, 0x00, 0x00, 0x50, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x1f, 0xf7, 0x7c, 0x00, 0x00, 0x00, 0x00, - 0x10, 0xdb, 0xb1, 0x04, 0x00, 0x00, 0x00, 0x0f, - 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, - /* ch = '{' */ - 0x00, 0x28, 0xab, 0xcf, 0xcf, - 0x22, 0xff, 0x5f, 0x15, 0x15, - 0x50, 0xff, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x00, 0x00, 0x00, - 0xa7, 0x8a, 0x00, 0x00, 0x00, - 0xc6, 0x08, 0x00, 0x00, 0x00, - 0xdb, 0x4d, 0x00, 0x00, 0x00, - 0x6b, 0xcf, 0x00, 0x00, 0x00, - 0x5f, 0xff, 0x00, 0x00, 0x00, - 0x7c, 0xcf, 0x00, 0x00, 0x00, - 0x5f, 0xff, 0x04, 0x00, 0x00, - 0x2a, 0xff, 0x84, 0x1a, 0x15, - 0x00, 0x28, 0x74, 0xbd, 0x8f, - /* ch = '|' */ - 0x7c, 0xb7, - 0x7c, 0xb7, - 0x7c, 0xb7, - 0x7c, 0xb7, - 0x7c, 0xb7, - 0x7c, 0xb7, - 0x7c, 0xb7, - 0x7c, 0xb7, - 0x7c, 0xb7, - 0x7c, 0xb7, - 0x7c, 0xb7, - 0x7c, 0xb7, - 0x7c, 0xb7, - 0x42, 0x58, - /* ch = '}' */ - 0x95, 0xcf, 0xbd, 0x37, 0x00, - 0x12, 0x15, 0x3f, 0xff, 0x39, - 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x00, 0x00, 0x00, 0x5a, 0xe5, - 0x00, 0x00, 0x00, 0x04, 0x8f, - 0x00, 0x00, 0x00, 0x2f, 0xf7, - 0x00, 0x00, 0x00, 0x90, 0xb1, - 0x00, 0x00, 0x00, 0xb7, 0xb1, - 0x00, 0x00, 0x00, 0x82, 0xb7, - 0x00, 0x00, 0x00, 0xb7, 0x90, - 0x0f, 0x15, 0x65, 0xff, 0x44, - 0x4a, 0xcf, 0x74, 0x37, 0x00, - /* ch = '~' */ - 0x50, 0xcf, 0xbd, 0x28, 0x00, 0x24, 0x5a, 0x04, - 0xf7, 0x2b, 0x5a, 0xff, 0xa4, 0xf7, 0x77, 0x00, - 0x0c, 0x00, 0x00, 0x21, 0x36, 0x22, 0x00, 0x00 + /* ch = '!' */ + 0x00, 0x22, 0x1b, 0x04, 0xff, 0xe5, 0x04, 0xff, 0xf7, 0x00, 0xff, 0xb7, + 0x00, 0xbd, 0xb7, 0x00, 0xb7, 0x7c, 0x00, 0xb7, 0x7c, 0x00, 0x90, 0x5f, + 0x00, 0x42, 0x30, 0x00, 0x00, 0x00, 0x0d, 0xab, 0x8d, 0x1c, 0xff, 0xe5, + 0x00, 0x0f, 0x0c, + /* ch = '"' */ + 0x00, 0x22, 0x13, 0x00, 0x22, 0x13, 0x00, 0xf7, 0xa0, 0x00, 0xff, 0x7c, + 0x00, 0xec, 0x7c, 0x00, 0xff, 0x6b, 0x0d, 0xff, 0x39, 0x14, 0xff, 0x2c, + 0x30, 0xef, 0x0d, 0x3a, 0xe5, 0x04, + /* ch = '#' */ + 0x00, 0x00, 0x2a, 0x6f, 0x00, 0x30, 0x58, 0x00, 0x00, 0x00, 0x00, 0x50, + 0xb7, 0x00, 0x77, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x82, 0x00, 0x90, + 0x77, 0x00, 0x00, 0x67, 0xcf, 0xef, 0xef, 0xcf, 0xf7, 0xe5, 0xcf, 0x09, + 0x0f, 0x00, 0xbd, 0x50, 0x00, 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x32, 0x14, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x14, 0xff, 0x24, 0x1f, 0xff, + 0x28, 0x12, 0x00, 0x95, 0xdd, 0xff, 0xcf, 0xdd, 0xff, 0x74, 0x45, 0x00, + 0x00, 0x32, 0xff, 0x00, 0x4d, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x4d, 0xb7, + 0x00, 0x6b, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x78, 0x00, 0x67, 0x67, + 0x00, 0x00, 0x00, + /* ch = '$' */ + 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x8d, 0xff, 0xff, 0xf7, 0x73, 0x04, + 0x00, 0x99, 0xb1, 0x37, 0xff, 0x1e, 0xdb, 0x2d, 0x00, 0xff, 0x54, 0x32, + 0xff, 0x00, 0x0c, 0x00, 0x00, 0x77, 0xf7, 0x7c, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x5b, 0xef, 0xff, 0x73, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x32, + 0xff, 0x94, 0xf7, 0x32, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, 0x97, 0xa0, + 0x00, 0x40, 0x00, 0x32, 0xff, 0x00, 0x97, 0x90, 0x1a, 0xf7, 0xbb, 0x62, + 0xff, 0x77, 0xf7, 0x2a, 0x00, 0x13, 0x50, 0xbb, 0xff, 0x73, 0x1b, 0x00, + 0x00, 0x00, 0x00, 0x2d, 0xcf, 0x00, 0x00, 0x00, + /* ch = '%' */ + 0x10, 0x8d, 0xbd, 0x2f, 0x00, 0x00, 0x51, 0x47, 0x7c, 0x90, 0x3a, 0xf7, + 0x14, 0x2a, 0xff, 0x1c, 0xb7, 0x50, 0x1c, 0xff, 0x2f, 0xb7, 0x6b, 0x00, + 0x6b, 0xb7, 0x53, 0xf7, 0x47, 0xf7, 0x10, 0x00, 0x04, 0x5b, 0x74, 0x28, + 0xdb, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xdb, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x10, 0xf7, 0x3b, 0x0f, 0x15, 0x00, 0x00, 0x00, 0x6b, 0xb7, + 0x49, 0xef, 0xd4, 0x7c, 0x00, 0x1c, 0xff, 0x2a, 0xbd, 0x54, 0x1f, 0xff, + 0x00, 0x90, 0x90, 0x00, 0xbd, 0x54, 0x24, 0xff, 0x2a, 0xff, 0x1c, 0x00, + 0x32, 0xf7, 0xe5, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x12, 0x00, + /* ch = '&' */ + 0x00, 0x00, 0x3f, 0x74, 0x67, 0x13, 0x00, 0x00, 0x00, 0x00, 0x4d, 0xf7, + 0x47, 0xb1, 0xc8, 0x00, 0x00, 0x00, 0x00, 0xa9, 0x97, 0x00, 0x32, 0xff, + 0x1c, 0x00, 0x00, 0x00, 0x5f, 0xe5, 0x0d, 0x50, 0xe5, 0x04, 0x00, 0x00, + 0x00, 0x10, 0xf7, 0xab, 0xf7, 0x32, 0x00, 0x00, 0x00, 0x00, 0x19, 0xdb, + 0xff, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x10, 0xdb, 0x8a, 0x70, 0xf7, 0x1c, + 0x2f, 0x5a, 0x04, 0x5a, 0xff, 0x17, 0x04, 0xb1, 0xb1, 0x90, 0xb7, 0x00, + 0x7c, 0xd9, 0x00, 0x00, 0x1c, 0xf7, 0xf7, 0x1f, 0x00, 0x5a, 0xff, 0x35, + 0x04, 0x50, 0xff, 0xff, 0x32, 0x00, 0x04, 0xa9, 0xff, 0xff, 0xe5, 0x2c, + 0x82, 0xbb, 0x00, 0x00, 0x00, 0x0f, 0x12, 0x00, 0x00, 0x08, 0x04, 0x00, + /* ch = ''' */ + 0x04, 0x2a, 0x04, 0x32, 0xff, 0x39, 0x32, 0xff, 0x2a, 0x44, 0xe5, 0x04, + 0x7e, 0x70, 0x00, + /* ch = '(' */ + 0x00, 0x04, 0x22, 0x00, 0x19, 0xd4, 0xdd, 0x09, 0xef, 0x8a, 0x04, 0x00, + 0xb1, 0x04, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, + 0xff, 0x35, 0x00, 0x00, 0x6b, 0xff, 0x48, 0x00, 0x00, 0x35, 0xd4, 0x04, + /* ch = ')' */ + 0x22, 0x00, 0x00, 0x00, 0xdb, 0xbb, 0x19, 0x00, 0x13, 0xb1, 0xdb, 0x1f, + 0x00, 0x08, 0xb7, 0xc8, 0x00, 0x00, 0x24, 0xff, 0x00, 0x00, 0x00, 0xa0, + 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x35, + 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x04, 0xcf, 0x00, 0x00, 0x4d, 0xff, + 0x00, 0x26, 0xf7, 0x54, 0x3f, 0xf7, 0x77, 0x00, 0xd4, 0x37, 0x00, 0x00, + /* ch = '*' */ + 0x00, 0x00, 0x00, 0x67, 0xb5, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x6b, + 0xb7, 0x00, 0x00, 0x00, 0x48, 0xe5, 0x48, 0x59, 0x7c, 0x31, 0xbb, 0x5f, + 0x08, 0x2a, 0x8f, 0xef, 0xf7, 0x9e, 0x37, 0x0c, 0x00, 0x00, 0x1f, 0xef, + 0xdb, 0x32, 0x00, 0x00, 0x00, 0x1f, 0xdb, 0x50, 0x32, 0xf7, 0x1f, 0x00, + 0x00, 0x8d, 0xb1, 0x04, 0x00, 0x82, 0xa4, 0x00, 0x00, 0x04, 0x08, 0x00, + 0x00, 0x08, 0x04, 0x00, + /* ch = '+' */ + 0x00, 0x00, 0x00, 0x45, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, + 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xb7, 0x00, 0x00, 0x00, + 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0x00, 0x00, 0x00, 0x50, + 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xb7, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x50, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x12, 0x00, 0x00, 0x00, + /* ch = ',' */ + 0x0d, 0x9e, 0x5b, 0x00, 0x22, 0xf7, 0xff, 0x1c, 0x00, 0x54, 0xf7, 0x0d, + 0x04, 0xb1, 0x50, 0x00, 0x2d, 0x73, 0x00, 0x00, + /* ch = '-' */ + 0x1c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x32, 0x04, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x08, + /* ch = '.' */ + 0x0d, 0x9e, 0x66, 0x22, 0xff, 0xe5, 0x00, 0x0f, 0x0c, + /* ch = '/' */ + 0x00, 0x12, 0x00, 0x2c, 0xff, 0x2d, 0xa0, 0xb7, 0x00, 0xff, 0x39, 0x00, + 0xc8, 0x04, 0x00, 0x44, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + /* ch = '0' */ + 0x00, 0x00, 0x19, 0x67, 0x74, 0x22, 0x00, 0x00, 0x00, 0x1f, 0xf7, 0x85, + 0x5a, 0xff, 0x32, 0x00, 0x00, 0xa0, 0x90, 0x00, 0x00, 0x64, 0xe5, 0x04, + 0x1c, 0xff, 0x2a, 0x00, 0x10, 0xdb, 0xff, 0x32, 0x35, 0xff, 0x04, 0x00, + 0xa0, 0xb1, 0xcf, 0x50, 0x50, 0xff, 0x00, 0x50, 0xe5, 0x10, 0xb7, 0x7c, + 0x4d, 0xff, 0x32, 0xff, 0x32, 0x00, 0xb7, 0x77, 0x2f, 0xff, 0xff, 0x50, + 0x00, 0x00, 0xe5, 0x4d, 0x0d, 0xf7, 0x97, 0x00, 0x00, 0x22, 0xff, 0x24, + 0x00, 0x5f, 0xf7, 0x21, 0x08, 0xb1, 0xa0, 0x00, 0x00, 0x04, 0x84, 0xff, + 0xff, 0xbb, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x12, 0x00, 0x00, 0x00, + /* ch = '1' */ + 0x00, 0x00, 0x37, 0x74, 0x14, 0x28, 0xcb, 0xff, 0xff, 0x1c, 0x39, 0x25, + 0x54, 0xff, 0x1c, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x50, 0xff, + 0x1c, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, + 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x50, + 0xff, 0x1c, 0x00, 0x00, 0x50, 0xff, 0x1c, + /* ch = '2' */ + 0x00, 0x00, 0x22, 0x74, 0x74, 0x37, 0x04, 0x00, 0x00, 0x5b, 0xf7, 0x50, + 0x5a, 0xf7, 0x7c, 0x00, 0x00, 0x48, 0x2f, 0x00, 0x00, 0x3b, 0xff, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x48, 0xff, 0x14, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf7, 0x50, 0x00, + 0x00, 0x00, 0x00, 0x26, 0xf7, 0x77, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf7, + 0x6b, 0x00, 0x00, 0x00, 0x00, 0x10, 0xdb, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0xdb, 0x04, 0x00, 0x00, 0x04, 0x0c, 0x1a, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x50, + /* ch = '3' */ + 0x00, 0x00, 0x31, 0x74, 0x74, 0x22, 0x00, 0x00, 0x6d, 0xe5, 0x50, 0x7f, + 0xff, 0x40, 0x00, 0x08, 0x08, 0x00, 0x00, 0x70, 0xe5, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x5f, 0xe5, 0x00, 0x00, 0x00, 0x04, 0x2b, 0xf7, 0x4d, 0x00, + 0x00, 0x32, 0xff, 0xff, 0x9e, 0x08, 0x00, 0x00, 0x00, 0x00, 0x16, 0xc4, + 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x35, 0xff, 0x04, 0xb1, 0x43, 0x00, 0x13, 0xb7, 0xc8, 0x00, 0x50, + 0xf7, 0xff, 0xff, 0xcb, 0x19, 0x00, 0x00, 0x04, 0x15, 0x0f, 0x00, 0x00, + /* ch = '4' */ + 0x00, 0x00, 0x00, 0x00, 0x10, 0x74, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x90, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x3b, 0xf7, 0xff, 0x32, 0x00, + 0x00, 0x00, 0x10, 0xf7, 0x4d, 0xff, 0x32, 0x00, 0x00, 0x00, 0x90, 0x77, + 0x1c, 0xff, 0x32, 0x00, 0x00, 0x3b, 0xdb, 0x10, 0x1c, 0xff, 0x32, 0x00, + 0x10, 0xf7, 0x32, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x50, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x32, 0x00, + /* ch = '5' */ + 0x00, 0x30, 0x74, 0x74, 0x74, 0x74, 0x74, 0x14, 0x00, 0x77, 0xcf, 0x36, + 0x36, 0x36, 0x36, 0x0d, 0x00, 0x7c, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x90, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0xc8, 0xcf, + 0xcf, 0x8d, 0x13, 0x00, 0x00, 0xb1, 0xa9, 0x20, 0x20, 0xc4, 0xdb, 0x0d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x50, 0x00, 0x08, 0x04, 0x00, 0x00, 0x14, 0xff, 0x4d, + 0x11, 0xdb, 0x5f, 0x04, 0x04, 0x7c, 0xf7, 0x17, 0x00, 0x2f, 0xe5, 0xf7, + 0xef, 0xef, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x12, 0x15, 0x00, 0x00, 0x00, + /* ch = '6' */ + 0x00, 0x00, 0x08, 0x50, 0xab, 0x74, 0x22, 0x00, 0x00, 0x0d, 0xd4, 0xc4, + 0x3e, 0x77, 0xdb, 0x09, 0x00, 0x5a, 0xe5, 0x10, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0xcf, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xff, 0x52, 0x9e, + 0xcf, 0x7f, 0x10, 0x00, 0x1c, 0xff, 0xff, 0x50, 0x20, 0xc4, 0xb7, 0x04, + 0x1c, 0xff, 0x50, 0x00, 0x00, 0x24, 0xff, 0x2f, 0x1a, 0xff, 0x3b, 0x00, + 0x00, 0x00, 0xff, 0x50, 0x00, 0xe5, 0x70, 0x00, 0x00, 0x14, 0xff, 0x35, + 0x00, 0x5a, 0xf7, 0x21, 0x00, 0x6f, 0xf7, 0x0d, 0x00, 0x04, 0x7e, 0xff, + 0xff, 0xef, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x15, 0x00, 0x00, 0x00, + /* ch = '7' */ + 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x22, 0x74, 0x74, 0x74, 0x74, 0xb9, + 0xff, 0x17, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x8a, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xe5, 0x00, 0x00, 0x00, + 0x00, 0x0d, 0xf7, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x48, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0xa7, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x48, + 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x17, 0x00, 0x00, 0x00, 0x00, 0xc8, + 0xa7, 0x00, 0x00, 0x00, 0x00, + /* ch = '8' */ + 0x00, 0x00, 0x28, 0x82, 0xab, 0x50, 0x04, 0x00, 0x00, 0x32, 0xff, 0x5a, + 0x31, 0xdb, 0xa0, 0x00, 0x00, 0xa0, 0x90, 0x00, 0x00, 0x3b, 0xff, 0x1a, + 0x00, 0x90, 0xc8, 0x04, 0x00, 0x50, 0xf7, 0x0d, 0x00, 0x1f, 0xf7, 0x99, + 0x31, 0xf7, 0x50, 0x00, 0x00, 0x00, 0x57, 0xff, 0xff, 0x9e, 0x08, 0x00, + 0x00, 0x77, 0xdb, 0x1b, 0x1b, 0xdb, 0xb1, 0x04, 0x1c, 0xff, 0x3b, 0x00, + 0x00, 0x24, 0xff, 0x39, 0x2f, 0xff, 0x32, 0x00, 0x00, 0x0d, 0xff, 0x50, + 0x0d, 0xe5, 0xb1, 0x08, 0x04, 0x64, 0xff, 0x1c, 0x00, 0x26, 0xd4, 0xff, + 0xff, 0xef, 0x35, 0x00, 0x00, 0x00, 0x00, 0x12, 0x15, 0x00, 0x00, 0x00, + /* ch = '9' */ + 0x00, 0x00, 0x28, 0x74, 0x74, 0x2e, 0x00, 0x00, 0x00, 0x40, 0xff, 0x5a, + 0x5a, 0xff, 0x4d, 0x00, 0x00, 0xe5, 0x64, 0x00, 0x00, 0x5f, 0xf7, 0x0d, + 0x1c, 0xff, 0x32, 0x00, 0x00, 0x1f, 0xff, 0x2a, 0x14, 0xff, 0x3b, 0x00, + 0x00, 0x1c, 0xff, 0x35, 0x00, 0xa0, 0xb7, 0x08, 0x08, 0x8a, 0xff, 0x50, + 0x00, 0x10, 0xcb, 0xff, 0xff, 0xbb, 0xff, 0x35, 0x00, 0x00, 0x00, 0x12, + 0x0c, 0x24, 0xff, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xf7, 0x0d, + 0x00, 0x32, 0x3b, 0x00, 0x24, 0xe5, 0x5f, 0x00, 0x00, 0x66, 0xff, 0xff, + 0xff, 0x73, 0x04, 0x00, 0x00, 0x00, 0x08, 0x15, 0x08, 0x00, 0x00, 0x00, + /* ch = ':' */ + 0x00, 0x0f, 0x0c, 0x22, 0xff, 0xe5, 0x0d, 0xab, 0x66, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x9e, 0x66, 0x22, 0xff, 0xe5, + 0x00, 0x0f, 0x0c, + /* ch = ';' */ + 0x00, 0x0f, 0x0c, 0x00, 0x22, 0xff, 0xe5, 0x00, 0x0d, 0xab, 0x66, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0d, 0x9e, 0x5b, 0x00, 0x22, 0xf7, 0xff, 0x1c, 0x00, 0x54, 0xf7, 0x0d, + 0x04, 0xb1, 0x50, 0x00, 0x2d, 0x73, 0x00, 0x00, + /* ch = '<' */ + 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x13, 0x73, 0xff, 0x08, 0x66, + 0xf7, 0xa4, 0x1b, 0xf7, 0xb3, 0x1e, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, + 0x00, 0xf7, 0x50, 0x08, 0x00, 0x00, 0x28, 0xd4, 0xef, 0x37, 0x00, 0x00, + 0x04, 0x37, 0xef, 0xbb, 0x00, 0x00, 0x00, 0x08, 0x73, 0x00, 0x00, 0x00, + 0x00, 0x00, + /* ch = '=' */ + 0x1e, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x26, 0x30, 0x74, 0x74, 0x74, + 0x74, 0x74, 0x74, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7c, 0x0c, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x0f, + /* ch = '>' */ + 0x1b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x94, 0x1b, 0x00, 0x00, 0x13, 0x7f, + 0xff, 0x7f, 0x13, 0x00, 0x00, 0x16, 0x8d, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x1a, 0x00, 0x00, 0x00, 0x37, 0xef, 0x00, 0x28, 0xd4, 0xef, 0x37, 0xa4, + 0xf7, 0x5a, 0x08, 0x00, 0x94, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + /* ch = '?' */ + 0x00, 0x00, 0x04, 0x1a, 0x25, 0x0c, 0x00, 0x00, 0x00, 0x35, 0xef, 0xef, + 0xe5, 0xff, 0x4d, 0x00, 0x11, 0xf7, 0x6b, 0x04, 0x04, 0x82, 0xff, 0x17, + 0x00, 0x0c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x5a, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x26, 0xf7, 0x7c, 0x00, + 0x00, 0x00, 0x00, 0x17, 0xf7, 0x7c, 0x04, 0x00, 0x00, 0x00, 0x00, 0x44, + 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xcf, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, + 0xab, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0xff, 0x36, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, 0x00, + /* ch = '@' */ + 0x00, 0x00, 0x1e, 0x82, 0xcf, 0x73, 0x19, 0x00, 0x00, 0x40, 0xf7, 0x3f, + 0x15, 0x6a, 0xf7, 0x1c, 0x17, 0xf7, 0x32, 0x00, 0x00, 0x00, 0x90, 0x7c, + 0x50, 0xb7, 0x00, 0x00, 0x2a, 0x67, 0xb1, 0xb7, 0x82, 0x6b, 0x04, 0xb1, + 0xc4, 0x3e, 0x82, 0xb7, 0xb7, 0x50, 0x2f, 0xff, 0x17, 0x00, 0x50, 0xb7, + 0xa0, 0x5f, 0x2a, 0xff, 0x24, 0x00, 0x90, 0xb7, 0x5f, 0xa7, 0x00, 0x77, + 0xf7, 0xdd, 0xef, 0xb7, 0x2a, 0xff, 0x24, 0x00, 0x0f, 0x0f, 0x00, 0x00, + 0x00, 0x7c, 0xdb, 0x21, 0x00, 0x00, 0x22, 0x00, 0x00, 0x04, 0x66, 0xf7, + 0xdd, 0xdd, 0xe5, 0x20, 0x00, 0x00, 0x00, 0x04, 0x15, 0x12, 0x00, 0x00, + /* ch = 'A' */ + 0x00, 0x00, 0x00, 0x3e, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa7, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xff, 0xe5, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xc8, 0xff, 0x39, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xb7, 0x5a, 0x8a, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, + 0x22, 0x32, 0xff, 0x17, 0x00, 0x00, 0x00, 0x5a, 0xb7, 0x00, 0x04, 0xe5, + 0x5a, 0x00, 0x00, 0x00, 0xc8, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x00, 0x00, + 0x22, 0xff, 0x2a, 0x00, 0x00, 0x2c, 0xff, 0x2c, 0x00, 0x5f, 0xe5, 0x00, + 0x00, 0x00, 0x00, 0xe5, 0x70, 0x00, 0xcf, 0x6b, 0x00, 0x00, 0x00, 0x00, + 0x5a, 0xf7, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = 'B' */ + 0x30, 0x74, 0x74, 0x74, 0x74, 0x37, 0x04, 0x00, 0x50, 0xff, 0x36, 0x36, + 0x66, 0xf7, 0xb1, 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, 0x35, 0xff, 0x2a, + 0x50, 0xff, 0x00, 0x00, 0x00, 0x26, 0xff, 0x2a, 0x50, 0xff, 0x15, 0x15, + 0x25, 0xd4, 0xb1, 0x04, 0x50, 0xff, 0xcf, 0xcf, 0xe5, 0xec, 0x2b, 0x00, + 0x50, 0xff, 0x00, 0x00, 0x00, 0x43, 0xff, 0x2a, 0x50, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xcf, 0x7c, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x82, + 0x50, 0xff, 0x00, 0x00, 0x0c, 0x5f, 0xff, 0x2f, 0x50, 0xff, 0xff, 0xff, + 0xff, 0xd4, 0x35, 0x00, + /* ch = 'C' */ + 0x00, 0x00, 0x13, 0x5b, 0x74, 0x67, 0x1b, 0x00, 0x00, 0x2c, 0xf7, 0x94, + 0x36, 0x77, 0xf7, 0x32, 0x04, 0xdb, 0x82, 0x00, 0x00, 0x00, 0x82, 0x7b, + 0x39, 0xff, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0xe5, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x77, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xff, 0x0d, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x22, 0xff, 0x48, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x77, 0xf7, 0x28, 0x00, 0x13, 0xc8, 0x7b, 0x00, 0x04, 0x73, 0xff, + 0xe5, 0xff, 0x8d, 0x08, 0x00, 0x00, 0x00, 0x08, 0x15, 0x08, 0x00, 0x00, + /* ch = 'D' */ + 0x30, 0x74, 0x74, 0x74, 0x5b, 0x1b, 0x00, 0x00, 0x50, 0xff, 0x36, 0x36, + 0xa4, 0xff, 0x4d, 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, 0x64, 0xff, 0x1c, + 0x50, 0xff, 0x00, 0x00, 0x00, 0x0d, 0xff, 0x5a, 0x50, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xb7, 0x90, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x82, 0xb7, + 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x90, 0xb1, 0x50, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xcf, 0x6b, 0x50, 0xff, 0x00, 0x00, 0x00, 0x2c, 0xff, 0x2c, + 0x50, 0xff, 0x00, 0x00, 0x28, 0xdb, 0x7c, 0x00, 0x50, 0xff, 0xff, 0xff, + 0xe5, 0x66, 0x04, 0x00, + /* ch = 'E' */ + 0x22, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x30, 0x32, 0xff, 0x4a, 0x36, + 0x36, 0x36, 0x36, 0x1e, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, 0x00, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x50, + /* ch = 'F' */ + 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x30, 0xff, 0x82, 0x36, 0x36, 0x36, + 0x36, 0x1e, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x5e, 0x15, 0x15, 0x15, 0x0c, 0x00, 0xff, + 0xe5, 0xcf, 0xcf, 0xcf, 0x45, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, + 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = 'G' */ + 0x00, 0x00, 0x1b, 0x67, 0x74, 0x67, 0x1b, 0x00, 0x00, 0x32, 0xf7, 0x94, + 0x36, 0x85, 0xff, 0x32, 0x0d, 0xf7, 0x5f, 0x00, 0x00, 0x00, 0x82, 0x35, + 0x44, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0xb7, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7c, 0xb7, 0x00, 0x00, 0x50, 0xff, 0xff, 0xb7, 0x5f, 0xf7, 0x04, 0x00, + 0x00, 0x00, 0x7c, 0xb7, 0x2a, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xb7, + 0x00, 0x90, 0xdb, 0x24, 0x00, 0x0c, 0xa5, 0xb7, 0x00, 0x04, 0x7f, 0xff, + 0xff, 0xff, 0xb3, 0x28, 0x00, 0x00, 0x00, 0x08, 0x15, 0x08, 0x00, 0x00, + /* ch = 'H' */ + 0x22, 0x74, 0x1a, 0x00, 0x00, 0x00, 0x74, 0x37, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0xff, 0x50, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xff, 0x50, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xff, 0x50, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0xff, 0x50, 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xff, 0x50, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0xff, 0x50, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xff, 0x50, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xff, 0x50, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0xff, 0x50, + /* ch = 'I' */ + 0x58, 0x74, 0x74, 0x74, 0x74, 0x42, 0x2d, 0x36, 0xcf, 0xa5, 0x36, 0x26, + 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xb7, + /* ch = 'J' */ + 0x22, 0x74, 0x74, 0x74, 0x74, 0x58, 0x16, 0x36, 0x62, 0xff, 0x4a, 0x2d, + 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x44, 0xff, 0x14, 0x00, 0x13, 0x04, 0xb1, 0xb7, 0x00, 0x00, + 0xff, 0xf7, 0xd4, 0x1f, 0x00, 0x00, 0x12, 0x15, 0x00, 0x00, 0x00, 0x00, + /* ch = 'K' */ + 0x42, 0x74, 0x0a, 0x00, 0x00, 0x19, 0x74, 0x35, 0x7c, 0xff, 0x00, 0x00, + 0x10, 0xdb, 0xb1, 0x04, 0x7c, 0xff, 0x00, 0x04, 0xb1, 0xb1, 0x08, 0x00, + 0x7c, 0xff, 0x04, 0x99, 0xdb, 0x10, 0x00, 0x00, 0x7c, 0xff, 0x7c, 0xf7, + 0x1f, 0x00, 0x00, 0x00, 0x7c, 0xff, 0xff, 0xf7, 0x17, 0x00, 0x00, 0x00, + 0x7c, 0xff, 0x26, 0xdb, 0xb1, 0x04, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x2f, + 0xff, 0x50, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x6b, 0xff, 0x1f, 0x00, + 0x7c, 0xff, 0x00, 0x00, 0x04, 0xc8, 0xdb, 0x04, 0x7c, 0xff, 0x00, 0x00, + 0x00, 0x24, 0xff, 0x7c, + /* ch = 'L' */ + 0x14, 0x74, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x50, + /* ch = 'M' */ + 0x42, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x32, 0x58, 0x7c, 0xff, 0x1c, 0x00, + 0x00, 0x04, 0xe5, 0xb7, 0x7c, 0xff, 0x8a, 0x00, 0x00, 0x50, 0xff, 0xb7, + 0x7c, 0xff, 0xff, 0x22, 0x0d, 0xe5, 0xf7, 0xb7, 0x7c, 0xb7, 0xa7, 0x8a, + 0x5a, 0xc8, 0x82, 0xb7, 0x7c, 0xb7, 0x2c, 0xff, 0xf7, 0x32, 0x7c, 0xb7, + 0x7c, 0xb7, 0x00, 0xa0, 0xb7, 0x00, 0x7c, 0xb7, 0x7c, 0xb7, 0x00, 0x0c, + 0x0c, 0x00, 0x7c, 0xb7, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, + 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, 0x7c, 0xb7, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xb7, + /* ch = 'N' */ + 0x30, 0x74, 0x10, 0x00, 0x00, 0x00, 0x58, 0x42, 0x50, 0xff, 0x6b, 0x00, + 0x00, 0x00, 0xb7, 0x7c, 0x50, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xb7, 0x7c, + 0x50, 0xff, 0xc8, 0xa0, 0x00, 0x00, 0xb7, 0x7c, 0x50, 0xff, 0x32, 0xff, + 0x32, 0x00, 0xb7, 0x7c, 0x50, 0xff, 0x00, 0xa0, 0xc8, 0x04, 0xb7, 0x7c, + 0x50, 0xff, 0x00, 0x24, 0xff, 0x44, 0xb7, 0x7c, 0x50, 0xff, 0x00, 0x00, + 0x6b, 0xe5, 0xcf, 0x7c, 0x50, 0xff, 0x00, 0x00, 0x10, 0xf7, 0xff, 0x7c, + 0x50, 0xff, 0x00, 0x00, 0x00, 0x50, 0xff, 0x7c, 0x50, 0xff, 0x00, 0x00, + 0x00, 0x04, 0xdb, 0x7c, + /* ch = 'O' */ + 0x00, 0x00, 0x2b, 0x82, 0x9e, 0x48, 0x04, 0x00, 0x00, 0x50, 0xff, 0x66, + 0x50, 0xf7, 0xb1, 0x04, 0x22, 0xff, 0x3b, 0x00, 0x00, 0x24, 0xff, 0x48, + 0x5f, 0xe5, 0x04, 0x00, 0x00, 0x00, 0xa0, 0xa0, 0xa0, 0x90, 0x00, 0x00, + 0x00, 0x00, 0x5f, 0xf7, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, + 0xb7, 0x82, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x77, 0xcf, 0x00, 0x00, + 0x00, 0x00, 0x77, 0xbd, 0x39, 0xff, 0x24, 0x00, 0x00, 0x04, 0xe5, 0x6b, + 0x04, 0xb7, 0xdb, 0x1b, 0x08, 0x8a, 0xf7, 0x1c, 0x00, 0x10, 0xbb, 0xff, + 0xff, 0xe5, 0x26, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x12, 0x00, 0x00, 0x00, + /* ch = 'P' */ + 0x22, 0x74, 0x74, 0x74, 0x74, 0x50, 0x08, 0x00, 0x32, 0xff, 0x87, 0x74, + 0x74, 0xef, 0xef, 0x10, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x10, 0xf7, 0x6b, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x1f, 0xff, 0x5a, 0x32, 0xff, 0xd4, 0xcf, 0xcf, 0xf7, 0xa9, 0x04, + 0x32, 0xff, 0x4a, 0x36, 0x2a, 0x15, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* ch = 'Q' */ + 0x00, 0x00, 0x2b, 0x82, 0x9e, 0x48, 0x04, 0x00, 0x00, 0x50, 0xf7, 0x66, + 0x47, 0xef, 0xb1, 0x04, 0x22, 0xff, 0x3b, 0x00, 0x00, 0x1f, 0xff, 0x48, + 0x5f, 0xe5, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xa0, 0xa0, 0x90, 0x00, 0x00, + 0x00, 0x00, 0x54, 0xf7, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, + 0xb7, 0x82, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x77, 0xcf, 0x00, 0x00, + 0x00, 0x00, 0x77, 0xbd, 0x39, 0xff, 0x24, 0x00, 0x00, 0x04, 0xe5, 0x6b, + 0x04, 0xc8, 0xd4, 0x16, 0x04, 0x70, 0xf7, 0x1c, 0x00, 0x10, 0xb3, 0xff, + 0xff, 0xe5, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x54, 0xec, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0xf7, 0xa4, 0x74, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x36, 0x36, 0x1e, + /* ch = 'R' */ + 0x22, 0x74, 0x74, 0x74, 0x74, 0x47, 0x08, 0x00, 0x32, 0xff, 0x87, 0x74, + 0x74, 0xef, 0xd4, 0x0d, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x24, 0xff, 0x44, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xff, 0x66, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x32, 0xff, 0x39, 0x32, 0xff, 0xd4, 0xcf, 0xcf, 0xff, 0x7c, 0x00, + 0x32, 0xff, 0x4a, 0x36, 0xf7, 0x6d, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x5a, 0xf7, 0x10, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x0d, 0xf7, 0x6b, 0x00, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x5a, 0xf7, 0x17, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x0d, 0xf7, 0x70, + /* ch = 'S' */ + 0x00, 0x00, 0x22, 0x74, 0x74, 0x50, 0x13, 0x00, 0x00, 0x50, 0xf7, 0x5a, + 0x36, 0xab, 0xf7, 0x1a, 0x04, 0xf7, 0x54, 0x00, 0x00, 0x00, 0x51, 0x00, + 0x04, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0xff, 0x73, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0xe5, 0xff, 0x7f, 0x13, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2b, 0xc4, 0xf7, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0xe5, 0x77, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x7c, + 0x2d, 0xf7, 0x37, 0x04, 0x00, 0x3f, 0xff, 0x39, 0x04, 0x5b, 0xef, 0xff, + 0xff, 0xf7, 0x50, 0x00, 0x00, 0x00, 0x00, 0x15, 0x15, 0x04, 0x00, 0x00, + /* ch = 'T' */ + 0x58, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x58, 0x2d, 0x36, 0x36, 0xcf, + 0xa5, 0x36, 0x36, 0x2d, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, + 0x7c, 0x00, 0x00, 0x00, + /* ch = 'U' */ + 0x30, 0x74, 0x11, 0x00, 0x00, 0x00, 0x42, 0x42, 0x50, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0x7c, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, + 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x50, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0x7c, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, + 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x50, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xa0, 0x7c, 0x3b, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xcf, 0x77, + 0x17, 0xf7, 0x8a, 0x04, 0x00, 0x4a, 0xff, 0x2a, 0x00, 0x26, 0xe5, 0xef, + 0xe5, 0xef, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x12, 0x15, 0x04, 0x00, 0x00, + /* ch = 'V' */ + 0x53, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x74, 0x0a, 0x5a, 0xf7, 0x0d, + 0x00, 0x00, 0x00, 0x90, 0xa0, 0x00, 0x22, 0xff, 0x39, 0x00, 0x00, 0x0d, + 0xf7, 0x44, 0x00, 0x00, 0xc8, 0x8a, 0x00, 0x00, 0x39, 0xff, 0x14, 0x00, + 0x00, 0x5a, 0xf7, 0x0d, 0x00, 0x7c, 0xa0, 0x00, 0x00, 0x00, 0x1c, 0xff, + 0x39, 0x04, 0xf7, 0x44, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x8a, 0x2c, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf7, 0x7c, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0xff, 0xff, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb7, 0xff, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xa0, 0x00, + 0x00, 0x00, 0x00, + /* ch = 'W' */ + 0x74, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x04, 0x74, 0x1a, 0xbd, 0x5f, 0x00, + 0x1c, 0x6c, 0x00, 0x1c, 0xff, 0x1a, 0x82, 0x90, 0x00, 0x44, 0xe5, 0x00, + 0x32, 0xf7, 0x00, 0x54, 0xcf, 0x00, 0x90, 0xff, 0x24, 0x4d, 0xb1, 0x00, + 0x3b, 0xff, 0x08, 0xf7, 0xff, 0x50, 0x6b, 0x7c, 0x00, 0x24, 0xff, 0x3f, + 0xe5, 0x6b, 0xa0, 0x90, 0x50, 0x00, 0x0d, 0xff, 0xb7, 0x7c, 0x3b, 0xff, + 0xcf, 0x32, 0x00, 0x00, 0xcf, 0xff, 0x44, 0x14, 0xff, 0xff, 0x1c, 0x00, + 0x00, 0x90, 0xff, 0x1c, 0x00, 0xbd, 0xff, 0x00, 0x00, 0x00, 0x6b, 0xcf, + 0x00, 0x00, 0x6b, 0xbd, 0x00, 0x00, 0x00, 0x44, 0x6b, 0x00, 0x00, 0x32, + 0x82, 0x00, 0x00, + /* ch = 'X' */ + 0x42, 0x74, 0x17, 0x00, 0x00, 0x04, 0x74, 0x35, 0x0d, 0xe5, 0x70, 0x00, + 0x00, 0x50, 0xf7, 0x10, 0x00, 0x44, 0xff, 0x1c, 0x10, 0xf7, 0x5a, 0x00, + 0x00, 0x04, 0xc8, 0x90, 0x5f, 0xf7, 0x0d, 0x00, 0x00, 0x00, 0x32, 0xff, + 0xf7, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0xff, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x24, 0xff, 0xff, 0x44, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xc8, + 0x82, 0xe5, 0x0d, 0x00, 0x00, 0x2c, 0xff, 0x32, 0x17, 0xf7, 0x5f, 0x00, + 0x00, 0xb7, 0xa7, 0x00, 0x00, 0x5f, 0xf7, 0x17, 0x3b, 0xff, 0x2a, 0x00, + 0x00, 0x0d, 0xe5, 0x82, + /* ch = 'Y' */ + 0x4a, 0x67, 0x04, 0x00, 0x00, 0x00, 0x45, 0x64, 0x2c, 0xff, 0x3b, 0x00, + 0x00, 0x0d, 0xf7, 0x5a, 0x00, 0xa0, 0xc8, 0x04, 0x00, 0x5a, 0xf7, 0x0d, + 0x00, 0x2a, 0xff, 0x3b, 0x04, 0xe5, 0x6b, 0x00, 0x00, 0x00, 0xa0, 0xc8, + 0x48, 0xff, 0x17, 0x00, 0x00, 0x00, 0x2a, 0xff, 0xf7, 0x70, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xa7, 0xff, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, + 0xff, 0x00, 0x00, 0x00, + /* ch = 'Z' */ + 0x22, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x42, 0x16, 0x36, 0x36, 0x36, + 0x36, 0x57, 0xff, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xb7, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3b, 0xff, 0x24, 0x00, 0x00, 0x00, 0x00, 0x0d, + 0xe5, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0xe5, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x24, 0xff, 0x44, 0x00, 0x00, 0x00, 0x00, 0x04, 0xb7, 0xb7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xff, 0x24, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xf7, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x50, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xb7, + /* ch = '[' */ + 0x0d, 0x36, 0x36, 0x36, 0x36, 0x36, 0x0d, 0x1c, 0xff, 0x9c, 0x74, 0x74, + 0x74, 0x14, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x1c, + 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, + 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, + 0x32, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x62, 0x36, 0x36, 0x36, 0x0d, 0x14, 0x74, 0x74, 0x74, 0x74, + 0x74, 0x14, + /* ch = '\' */ + 0x00, 0x0f, 0x04, 0x11, 0xff, 0x48, 0x00, 0x70, 0xdb, 0x00, 0x22, 0xff, + 0x00, 0x00, 0x8a, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + /* ch = ']' */ + 0x2d, 0x36, 0x36, 0x36, 0x36, 0x16, 0x58, 0x74, 0x74, 0x87, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x36, 0x36, 0x36, 0x4a, 0xff, 0x32, 0x74, 0x74, 0x74, 0x74, 0x74, 0x22, + /* ch = '^' */ + 0x00, 0x00, 0x1f, 0x45, 0x00, 0x00, 0x00, 0x00, 0xb1, 0xf7, 0x17, 0x00, + 0x00, 0x3b, 0xf7, 0xdb, 0x7c, 0x00, 0x0d, 0xe5, 0x4d, 0x32, 0xff, 0x1c, + 0x60, 0xb7, 0x04, 0x00, 0xa0, 0x7e, 0x00, 0x0c, 0x00, 0x00, 0x0c, 0x04, + /* ch = '_' */ + 0x42, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x26, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, + /* ch = '`' */ + 0x1b, 0x16, 0x00, 0x00, 0xa7, 0x70, 0x00, 0x00, 0x44, 0xf7, 0x1f, 0x00, + 0x0d, 0xe5, 0xef, 0x14, 0x00, 0x26, 0x74, 0x0d, + /* ch = 'a' */ + 0x00, 0x13, 0x8d, 0xe5, 0xef, 0xab, 0x21, 0x00, 0x00, 0x54, 0x84, 0x18, + 0x0f, 0x7c, 0xf7, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x00, 0x00, 0x25, 0x47, 0x74, 0x87, 0xff, 0x32, 0x04, 0xa9, 0xdb, 0x47, + 0x36, 0x36, 0xff, 0x32, 0x44, 0xff, 0x1c, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x44, 0xff, 0x28, 0x00, 0x08, 0xa0, 0xff, 0x32, 0x04, 0x94, 0xff, 0xcf, + 0xf7, 0x94, 0xff, 0x32, 0x00, 0x00, 0x0f, 0x15, 0x08, 0x00, 0x00, 0x00, + /* ch = 'b' */ + 0x16, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x64, 0xbd, + 0xff, 0xc4, 0x26, 0x00, 0x32, 0xff, 0xdb, 0x20, 0x1a, 0xb1, 0xf7, 0x17, + 0x32, 0xff, 0x3b, 0x00, 0x00, 0x17, 0xff, 0x5f, 0x32, 0xff, 0x32, 0x00, + 0x00, 0x00, 0xbd, 0x90, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0xb7, 0x90, + 0x32, 0xff, 0x35, 0x00, 0x00, 0x04, 0xf7, 0x5f, 0x32, 0xff, 0xb1, 0x08, + 0x04, 0x7c, 0xff, 0x1c, 0x32, 0xf7, 0x73, 0xff, 0xff, 0xf7, 0x3b, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x15, 0x04, 0x00, 0x00, + /* ch = 'c' */ + 0x00, 0x00, 0x35, 0xbd, 0xef, 0xcf, 0x5b, 0x04, 0x00, 0x50, 0xff, 0x50, + 0x15, 0x31, 0xef, 0x6d, 0x14, 0xf7, 0x5f, 0x00, 0x00, 0x00, 0x30, 0x10, + 0x32, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x2a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x77, 0xf7, 0x31, 0x00, 0x13, 0x8d, 0x2c, 0x00, 0x04, 0x7f, 0xff, + 0xff, 0xff, 0xbb, 0x19, 0x00, 0x00, 0x00, 0x08, 0x15, 0x0f, 0x00, 0x00, + /* ch = 'd' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x24, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x13, 0x9e, 0xff, + 0xe5, 0x50, 0xff, 0x50, 0x04, 0xdb, 0xb1, 0x16, 0x16, 0xc4, 0xff, 0x50, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x2c, 0xff, 0x50, 0x50, 0xff, 0x00, 0x00, + 0x00, 0x1c, 0xff, 0x50, 0x50, 0xff, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x50, + 0x3b, 0xff, 0x24, 0x00, 0x00, 0x2c, 0xff, 0x50, 0x0d, 0xf7, 0xb1, 0x08, + 0x0c, 0xb1, 0xff, 0x50, 0x00, 0x2c, 0xef, 0xff, 0xff, 0x66, 0xff, 0x50, + 0x00, 0x00, 0x04, 0x15, 0x08, 0x00, 0x00, 0x00, + /* ch = 'e' */ + 0x00, 0x04, 0x73, 0xe5, 0xff, 0xab, 0x19, 0x00, 0x00, 0xa0, 0xc8, 0x16, + 0x08, 0x8a, 0xdb, 0x0d, 0x24, 0xff, 0x2c, 0x00, 0x00, 0x0d, 0xff, 0x3b, + 0x4d, 0xff, 0x7b, 0x74, 0x74, 0x74, 0xff, 0x50, 0x50, 0xff, 0x17, 0x15, + 0x15, 0x15, 0x15, 0x0c, 0x32, 0xff, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0xdb, 0xb1, 0x13, 0x00, 0x13, 0x5b, 0x08, 0x00, 0x19, 0xbb, 0xff, + 0xcf, 0xff, 0x8d, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x15, 0x08, 0x00, 0x00, + /* ch = 'f' */ + 0x00, 0x00, 0x1e, 0x36, 0x2a, 0x04, 0x00, 0x04, 0x99, 0xef, 0x74, 0xd4, + 0xd4, 0x0d, 0x39, 0xff, 0x24, 0x00, 0x04, 0x73, 0x00, 0x50, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x82, 0xff, 0x36, 0x36, 0x1e, 0x00, 0x00, 0xb1, + 0xff, 0x74, 0x74, 0x30, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = 'g' */ + 0x00, 0x19, 0xb3, 0xff, 0xef, 0x66, 0xc4, 0xff, 0x0d, 0xdb, 0x7c, 0x04, + 0x28, 0xff, 0x4f, 0x00, 0x2f, 0xff, 0x1c, 0x00, 0x00, 0xb7, 0x77, 0x00, + 0x1c, 0xff, 0x3b, 0x00, 0x10, 0xe5, 0x50, 0x00, 0x00, 0x50, 0xff, 0x9e, + 0xef, 0xa9, 0x04, 0x00, 0x00, 0xa0, 0x64, 0x36, 0x20, 0x00, 0x00, 0x00, + 0x00, 0xf7, 0x7c, 0x36, 0x36, 0x36, 0x0f, 0x00, 0x04, 0x8f, 0xab, 0x74, + 0x74, 0xd4, 0xff, 0x32, 0x5a, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x97, 0x7c, + 0x66, 0xf7, 0x2b, 0x04, 0x04, 0x2b, 0xf7, 0x44, 0x04, 0x5b, 0xcf, 0xef, + 0xe5, 0xbd, 0x37, 0x00, + /* ch = 'h' */ + 0x04, 0x15, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x50, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x59, 0x7f, + 0xf7, 0xdd, 0x2f, 0x00, 0x1c, 0xff, 0xff, 0x65, 0x15, 0x8a, 0xf7, 0x14, + 0x1c, 0xff, 0x7c, 0x00, 0x00, 0x24, 0xff, 0x32, 0x1c, 0xff, 0x50, 0x00, + 0x00, 0x1c, 0xff, 0x32, 0x1c, 0xff, 0x50, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x1c, 0xff, 0x50, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x1c, 0xff, 0x50, 0x00, + 0x00, 0x1c, 0xff, 0x32, 0x1c, 0xff, 0x50, 0x00, 0x00, 0x1c, 0xff, 0x32, + /* ch = 'i' */ + 0x00, 0x00, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x00, 0xb1, 0xff, 0x14, 0x00, + 0x00, 0x00, 0x35, 0x5b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x45, 0xcf, 0xcf, 0x95, 0x00, 0x00, 0x0c, 0x15, 0x88, 0xb7, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x7c, 0xff, 0xff, 0xff, 0xff, 0x7c, + /* ch = 'j' */ + 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x4d, 0xff, 0x44, + 0x00, 0x00, 0x00, 0x19, 0x74, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1a, 0xcf, 0xcf, 0xcf, 0xcf, 0x2d, 0x04, 0x15, 0x15, 0x3e, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x32, 0xff, 0x2f, + 0x0c, 0x00, 0x00, 0x3b, 0xff, 0x1c, 0xdb, 0x2b, 0x1a, 0xc8, 0xb1, 0x00, + 0x8d, 0xf7, 0xf7, 0x8d, 0x10, 0x00, + /* ch = 'k' */ + 0x04, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x32, 0x00, 0x00, 0x3b, 0xcf, 0x2d, 0x00, 0x1c, 0xff, 0x32, + 0x00, 0x50, 0xf7, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x5f, 0xf7, 0x26, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0xd4, 0xff, 0x5e, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0xd4, 0x8a, 0xff, 0x32, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x04, 0xb1, 0xe5, 0x10, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x10, 0xdb, + 0xb1, 0x04, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x1f, 0xf7, 0x7c, 0x04, + /* ch = 'l' */ + 0x12, 0x15, 0x15, 0x12, 0x00, 0x00, 0x00, 0x58, 0x74, 0xc8, 0xb7, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, + 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7c, 0xb7, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1c, + /* ch = 'm' */ + 0x67, 0xbd, 0xcb, 0xef, 0x47, 0xc4, 0xf7, 0x4d, 0x7c, 0xff, 0x1f, 0x97, + 0xff, 0x32, 0x64, 0xf7, 0x7c, 0xb7, 0x00, 0x7c, 0xe5, 0x00, 0x50, 0xff, + 0x7c, 0xb7, 0x00, 0x7c, 0xb7, 0x00, 0x50, 0xff, 0x7c, 0xb7, 0x00, 0x7c, + 0xb7, 0x00, 0x50, 0xff, 0x7c, 0xb7, 0x00, 0x7c, 0xb7, 0x00, 0x50, 0xff, + 0x7c, 0xb7, 0x00, 0x7c, 0xb7, 0x00, 0x50, 0xff, 0x7c, 0xb7, 0x00, 0x7c, + 0xb7, 0x00, 0x50, 0xff, + /* ch = 'n' */ + 0x1a, 0xcf, 0x32, 0x7f, 0xf7, 0xdd, 0x2c, 0x00, 0x1c, 0xff, 0xf7, 0x5a, + 0x15, 0x90, 0xf7, 0x0d, 0x1c, 0xff, 0x70, 0x00, 0x00, 0x24, 0xff, 0x32, + 0x1c, 0xff, 0x3b, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x1c, 0xff, 0x32, 0x00, + 0x00, 0x1c, 0xff, 0x32, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x1c, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x1c, 0xff, 0x32, 0x00, + 0x00, 0x1c, 0xff, 0x32, + /* ch = 'o' */ + 0x00, 0x04, 0x66, 0xdd, 0xef, 0x9e, 0x19, 0x00, 0x00, 0x99, 0xdb, 0x2b, + 0x1a, 0xb1, 0xe5, 0x10, 0x2c, 0xff, 0x2c, 0x00, 0x00, 0x17, 0xff, 0x5a, + 0x6b, 0xff, 0x04, 0x00, 0x00, 0x00, 0xb7, 0xb1, 0x77, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xb7, 0xb7, 0x44, 0xff, 0x24, 0x00, 0x00, 0x04, 0xe5, 0x6b, + 0x0d, 0xdb, 0xb1, 0x08, 0x00, 0x5f, 0xff, 0x24, 0x00, 0x19, 0xcb, 0xf7, + 0xe5, 0xef, 0x35, 0x00, 0x00, 0x00, 0x00, 0x12, 0x15, 0x04, 0x00, 0x00, + /* ch = 'p' */ + 0x2d, 0xcf, 0x50, 0xab, 0xf7, 0xbd, 0x26, 0x00, 0x32, 0xff, 0xdb, 0x25, + 0x1a, 0xb1, 0xff, 0x1f, 0x32, 0xff, 0x3b, 0x00, 0x00, 0x10, 0xff, 0x77, + 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0xb7, 0xb7, 0x32, 0xff, 0x32, 0x00, + 0x00, 0x00, 0xa7, 0xb7, 0x32, 0xff, 0x35, 0x00, 0x00, 0x04, 0xe5, 0x7c, + 0x32, 0xff, 0xb1, 0x08, 0x04, 0x5f, 0xff, 0x2a, 0x32, 0xff, 0xbb, 0xff, + 0xf7, 0xf7, 0x44, 0x00, 0x32, 0xff, 0x32, 0x0c, 0x15, 0x08, 0x00, 0x00, + 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0xcf, 0x2d, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* ch = 'q' */ + 0x00, 0x10, 0x8d, 0xf7, 0xef, 0x66, 0xcf, 0x45, 0x04, 0xc8, 0xb1, 0x16, + 0x16, 0xb1, 0xff, 0x50, 0x39, 0xff, 0x22, 0x00, 0x00, 0x24, 0xff, 0x50, + 0x5f, 0xff, 0x00, 0x00, 0x00, 0x1a, 0xff, 0x50, 0x5f, 0xff, 0x00, 0x00, + 0x00, 0x14, 0xff, 0x50, 0x44, 0xff, 0x24, 0x00, 0x00, 0x24, 0xff, 0x50, + 0x0d, 0xe5, 0xb1, 0x08, 0x08, 0xb1, 0xff, 0x50, 0x00, 0x21, 0xef, 0xff, + 0xff, 0x66, 0xff, 0x50, 0x00, 0x00, 0x00, 0x15, 0x0c, 0x00, 0xff, 0x50, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xcf, 0x45, + /* ch = 'r' */ + 0x67, 0xcf, 0x2f, 0xbd, 0xff, 0xd4, 0x2f, 0x7c, 0xff, 0xf7, 0x37, 0x15, + 0x64, 0x50, 0x7c, 0xff, 0x44, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = 's' */ + 0x00, 0x08, 0x73, 0xe5, 0xff, 0xbd, 0x37, 0x00, 0x00, 0x8a, 0xdb, 0x16, + 0x04, 0x3f, 0xff, 0x1a, 0x00, 0xb1, 0xc8, 0x08, 0x00, 0x00, 0x21, 0x00, + 0x00, 0x2c, 0xef, 0xf7, 0x8f, 0x2a, 0x04, 0x00, 0x00, 0x00, 0x08, 0x31, + 0x9e, 0xff, 0xd4, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x28, 0xff, 0x4d, + 0x17, 0xef, 0x31, 0x00, 0x00, 0x3a, 0xff, 0x2c, 0x04, 0x5b, 0xef, 0xef, + 0xef, 0xf7, 0x50, 0x00, 0x00, 0x00, 0x00, 0x15, 0x15, 0x00, 0x00, 0x00, + /* ch = 't' */ + 0x00, 0x00, 0x1a, 0xf7, 0x44, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x32, + 0x00, 0x00, 0x1a, 0xcf, 0xdd, 0xff, 0xdd, 0xcf, 0x95, 0x04, 0x15, 0x3e, + 0xff, 0x28, 0x15, 0x12, 0x00, 0x00, 0x35, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x3b, 0xff, + 0x3f, 0x08, 0x48, 0x00, 0x00, 0x04, 0xa9, 0xff, 0xff, 0xcb, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0x0c, 0x00, + /* ch = 'u' */ + 0x2d, 0xcf, 0x2d, 0x00, 0x00, 0x1a, 0xcf, 0x2d, 0x32, 0xff, 0x32, 0x00, + 0x00, 0x1c, 0xff, 0x32, 0x32, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, + 0x32, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x32, 0xff, 0x32, 0x00, + 0x00, 0x1c, 0xff, 0x32, 0x24, 0xff, 0x35, 0x00, 0x00, 0x2a, 0xff, 0x32, + 0x04, 0xe5, 0xa0, 0x04, 0x08, 0xb1, 0xff, 0x32, 0x00, 0x2c, 0xef, 0xe5, + 0xef, 0x84, 0xff, 0x3b, 0x00, 0x00, 0x04, 0x15, 0x0c, 0x00, 0x00, 0x00, + /* ch = 'v' */ + 0x4a, 0xcf, 0x1a, 0x00, 0x00, 0x00, 0x78, 0x73, 0x17, 0xff, 0x48, 0x00, + 0x00, 0x04, 0xf7, 0x3b, 0x00, 0xa7, 0xc8, 0x00, 0x00, 0x39, 0xf7, 0x0d, + 0x00, 0x39, 0xff, 0x22, 0x00, 0x97, 0x70, 0x00, 0x00, 0x04, 0xe5, 0x70, + 0x22, 0xff, 0x22, 0x00, 0x00, 0x00, 0x6b, 0xf7, 0x82, 0xa7, 0x00, 0x00, + 0x00, 0x00, 0x22, 0xff, 0xff, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, + 0xe5, 0x04, 0x00, 0x00, + /* ch = 'w' */ + 0xcf, 0x45, 0x00, 0x00, 0x00, 0x00, 0x2d, 0xcf, 0x17, 0xb1, 0x6b, 0x00, + 0x54, 0xb7, 0x00, 0x32, 0xff, 0x00, 0x6b, 0xb1, 0x00, 0xa0, 0xff, 0x17, + 0x4d, 0xb7, 0x00, 0x3b, 0xff, 0x04, 0xff, 0xf7, 0x44, 0x5f, 0x82, 0x00, + 0x1f, 0xff, 0x48, 0xcf, 0x6b, 0x90, 0x82, 0x54, 0x00, 0x04, 0xff, 0xc8, + 0x6b, 0x32, 0xff, 0xcf, 0x35, 0x00, 0x00, 0xb1, 0xff, 0x32, 0x0d, 0xf7, + 0xff, 0x1c, 0x00, 0x00, 0x6b, 0xff, 0x0d, 0x00, 0x90, 0xf7, 0x00, 0x00, + /* ch = 'x' */ + 0x28, 0xcf, 0x32, 0x00, 0x00, 0x32, 0xcf, 0x1d, 0x00, 0x6b, 0xf7, 0x17, + 0x10, 0xe5, 0x5f, 0x00, 0x00, 0x04, 0xb7, 0xb1, 0x82, 0xc8, 0x04, 0x00, + 0x00, 0x00, 0x1f, 0xf7, 0xff, 0x24, 0x00, 0x00, 0x00, 0x00, 0x17, 0xf7, + 0xff, 0x24, 0x00, 0x00, 0x00, 0x00, 0xb1, 0xb7, 0xa0, 0xdb, 0x0d, 0x00, + 0x00, 0x50, 0xff, 0x1f, 0x10, 0xe5, 0x7c, 0x00, 0x1f, 0xf7, 0x54, 0x00, + 0x00, 0x32, 0xff, 0x35, + /* ch = 'y' */ + 0x3a, 0xcf, 0x2d, 0x00, 0x00, 0x00, 0x87, 0x82, 0x0d, 0xf7, 0x5a, 0x00, + 0x00, 0x0d, 0xff, 0x44, 0x00, 0x70, 0xe5, 0x04, 0x00, 0x3b, 0xff, 0x14, + 0x00, 0x22, 0xff, 0x39, 0x00, 0x90, 0x8a, 0x00, 0x00, 0x00, 0xa7, 0xa0, + 0x14, 0xff, 0x32, 0x00, 0x00, 0x00, 0x39, 0xff, 0x65, 0xe5, 0x04, 0x00, + 0x00, 0x00, 0x04, 0xf7, 0xff, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0xff, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xa7, 0x00, 0x00, 0x00, + 0x49, 0x28, 0x2b, 0xff, 0x44, 0x00, 0x00, 0x00, 0x6c, 0xf7, 0xef, 0x50, + 0x00, 0x00, 0x00, 0x00, + /* ch = 'z' */ + 0x1a, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x1a, 0x04, 0x15, 0x15, 0x15, + 0x17, 0xc6, 0xb1, 0x04, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xf7, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x50, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, + 0x50, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf7, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xdb, 0xb1, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x50, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7c, + /* ch = '{' */ + 0x00, 0x28, 0xab, 0xcf, 0xcf, 0x22, 0xff, 0x5f, 0x15, 0x15, 0x50, 0xff, + 0x00, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, + 0x00, 0xa7, 0x8a, 0x00, 0x00, 0x00, 0xc6, 0x08, 0x00, 0x00, 0x00, 0xdb, + 0x4d, 0x00, 0x00, 0x00, 0x6b, 0xcf, 0x00, 0x00, 0x00, 0x5f, 0xff, 0x00, + 0x00, 0x00, 0x7c, 0xcf, 0x00, 0x00, 0x00, 0x5f, 0xff, 0x04, 0x00, 0x00, + 0x2a, 0xff, 0x84, 0x1a, 0x15, 0x00, 0x28, 0x74, 0xbd, 0x8f, + /* ch = '|' */ + 0x7c, 0xb7, 0x7c, 0xb7, 0x7c, 0xb7, 0x7c, 0xb7, 0x7c, 0xb7, 0x7c, 0xb7, + 0x7c, 0xb7, 0x7c, 0xb7, 0x7c, 0xb7, 0x7c, 0xb7, 0x7c, 0xb7, 0x7c, 0xb7, + 0x7c, 0xb7, 0x42, 0x58, + /* ch = '}' */ + 0x95, 0xcf, 0xbd, 0x37, 0x00, 0x12, 0x15, 0x3f, 0xff, 0x39, 0x00, 0x00, + 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0xb7, + 0x7c, 0x00, 0x00, 0x00, 0x5a, 0xe5, 0x00, 0x00, 0x00, 0x04, 0x8f, 0x00, + 0x00, 0x00, 0x2f, 0xf7, 0x00, 0x00, 0x00, 0x90, 0xb1, 0x00, 0x00, 0x00, + 0xb7, 0xb1, 0x00, 0x00, 0x00, 0x82, 0xb7, 0x00, 0x00, 0x00, 0xb7, 0x90, + 0x0f, 0x15, 0x65, 0xff, 0x44, 0x4a, 0xcf, 0x74, 0x37, 0x00, + /* ch = '~' */ + 0x50, 0xcf, 0xbd, 0x28, 0x00, 0x24, 0x5a, 0x04, 0xf7, 0x2b, 0x5a, 0xff, + 0xa4, 0xf7, 0x77, 0x00, 0x0c, 0x00, 0x00, 0x21, 0x36, 0x22, 0x00, 0x00 }; /* font_inconsolata_18px */ static const unsigned char pd_inconsolata_font_bitmap_18px_bytes[] = { - /* ch = '!' */ - 0x00, 0x94, 0xef, 0x14, - 0x00, 0xb7, 0xff, 0x27, - 0x00, 0xb7, 0xff, 0x1c, - 0x00, 0x82, 0xff, 0x1a, - 0x00, 0x7c, 0xff, 0x00, - 0x00, 0x7c, 0xff, 0x00, - 0x00, 0x54, 0xbd, 0x00, - 0x00, 0x50, 0xb7, 0x00, - 0x00, 0x30, 0x58, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0xa2, 0xe5, 0x1c, - 0x04, 0xe5, 0xff, 0x27, - 0x00, 0x0c, 0x12, 0x00, - /* ch = '"' */ - 0x99, 0xc0, 0x00, 0x6b, 0xdb, 0x04, - 0xb7, 0xf7, 0x00, 0x82, 0xff, 0x14, - 0xb7, 0x90, 0x00, 0x82, 0xb7, 0x00, - 0xff, 0x39, 0x00, 0xe5, 0x50, 0x00, - 0x5b, 0x0d, 0x0d, 0x5b, 0x17, 0x00, - /* ch = '#' */ - 0x00, 0x00, 0x04, 0x15, 0x04, 0x04, 0x15, 0x08, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x1a, 0x24, 0xff, 0x1f, 0x00, - 0x00, 0x00, 0x3b, 0xff, 0x00, 0x32, 0xff, 0x0d, 0x00, - 0x0c, 0x15, 0x5e, 0xc6, 0x15, 0x5e, 0xff, 0x15, 0x0c, - 0x42, 0x74, 0xc8, 0xc8, 0x74, 0xc8, 0xe5, 0x74, 0x30, - 0x00, 0x00, 0xa0, 0x77, 0x00, 0x82, 0x82, 0x00, 0x00, - 0x00, 0x00, 0xbd, 0x50, 0x00, 0xb7, 0x6b, 0x00, 0x00, - 0x12, 0x15, 0xff, 0x42, 0x2a, 0xf7, 0x82, 0x36, 0x0d, - 0x58, 0x87, 0xff, 0x87, 0x87, 0xff, 0x6f, 0x36, 0x0d, - 0x00, 0x24, 0xff, 0x1c, 0x1c, 0xff, 0x1f, 0x00, 0x00, - 0x00, 0x32, 0xff, 0x00, 0x32, 0xff, 0x14, 0x00, 0x00, - 0x00, 0x45, 0xab, 0x00, 0x3a, 0xcf, 0x00, 0x00, 0x00, - /* ch = '$' */ - 0x00, 0x00, 0x1a, 0xcf, 0x2d, 0x00, 0x00, 0x00, - 0x00, 0x1b, 0x6b, 0xff, 0x9c, 0x25, 0x00, 0x00, - 0x32, 0xff, 0x94, 0xff, 0xab, 0xf7, 0x84, 0x00, - 0xb1, 0x82, 0x1c, 0xff, 0x32, 0x2a, 0x39, 0x00, - 0xb1, 0xb7, 0x1f, 0xff, 0x32, 0x00, 0x00, 0x00, - 0x32, 0xf7, 0xef, 0xff, 0x32, 0x00, 0x00, 0x00, - 0x00, 0x13, 0x6b, 0xff, 0xf7, 0x8d, 0x13, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0x58, 0xd4, 0xdb, 0x04, - 0x00, 0x00, 0x1c, 0xff, 0x32, 0x2c, 0xff, 0x2a, - 0x73, 0x10, 0x1c, 0xff, 0x32, 0x3f, 0xff, 0x1a, - 0xdb, 0xdb, 0x5f, 0xff, 0x99, 0xf7, 0x73, 0x00, - 0x04, 0x3f, 0x95, 0xff, 0x9c, 0x31, 0x00, 0x00, - 0x00, 0x00, 0x1a, 0xcf, 0x2d, 0x00, 0x00, 0x00, - /* ch = '%' */ - 0x00, 0x22, 0x36, 0x13, 0x00, 0x00, 0x08, 0x15, 0x04, - 0x39, 0xf7, 0x95, 0xf7, 0x17, 0x00, 0x7c, 0xb7, 0x00, - 0xa0, 0x82, 0x04, 0xff, 0x4d, 0x24, 0xff, 0x2a, 0x00, - 0xa0, 0x82, 0x04, 0xff, 0x4d, 0xa0, 0x90, 0x00, 0x00, - 0x2f, 0xff, 0xdd, 0xdb, 0x3f, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x0f, 0x15, 0x0c, 0xc8, 0x6b, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x44, 0xf7, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0d, 0xe5, 0x50, 0x22, 0x36, 0x22, 0x00, - 0x00, 0x00, 0x5f, 0xdb, 0x2c, 0xff, 0x73, 0xff, 0x2f, - 0x00, 0x17, 0xf7, 0x3b, 0x77, 0xa0, 0x00, 0x90, 0x77, - 0x00, 0x7c, 0xb7, 0x00, 0x6b, 0xb7, 0x00, 0xb7, 0x6b, - 0x24, 0xff, 0x2a, 0x00, 0x17, 0xdb, 0xdd, 0xdb, 0x1c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x15, 0x04, 0x00, - /* ch = '&' */ - 0x00, 0x00, 0x08, 0x25, 0x20, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x1c, 0xdb, 0xe5, 0xef, 0xd4, 0x0d, 0x00, 0x00, - 0x00, 0x6b, 0xf7, 0x10, 0x1c, 0xff, 0x44, 0x00, 0x00, - 0x00, 0x77, 0xe5, 0x04, 0x04, 0xff, 0x4d, 0x00, 0x00, - 0x00, 0x2a, 0xff, 0x3b, 0x50, 0xf7, 0x17, 0x00, 0x00, - 0x00, 0x00, 0x82, 0xff, 0xf7, 0x32, 0x00, 0x00, 0x00, - 0x00, 0x32, 0xf7, 0xff, 0xc8, 0x04, 0x00, 0x0c, 0x00, - 0x1c, 0xf7, 0x7c, 0x1f, 0xf7, 0x77, 0x04, 0xe5, 0x2f, - 0x5f, 0xff, 0x17, 0x00, 0x4d, 0xff, 0x94, 0xf7, 0x1c, - 0x7c, 0xff, 0x04, 0x00, 0x00, 0x88, 0xff, 0x54, 0x00, - 0x48, 0xff, 0x54, 0x00, 0x37, 0xf7, 0xf7, 0xb1, 0x04, - 0x04, 0x84, 0xff, 0xff, 0xf7, 0x50, 0x2f, 0xf7, 0x33, - 0x00, 0x00, 0x0c, 0x15, 0x04, 0x00, 0x00, 0x0f, 0x00, - /* ch = ''' */ - 0x0d, 0xef, 0x66, - 0x1a, 0xff, 0x7c, - 0x14, 0xff, 0x44, - 0x32, 0xff, 0x14, - 0x24, 0x4e, 0x00, - /* ch = '(' */ - 0x00, 0x28, 0xd4, 0x2c, - 0x4d, 0xff, 0x77, 0x0f, - 0xff, 0x50, 0x00, 0x00, - 0xa0, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x0d, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, - 0xdb, 0x04, 0x00, 0x00, - 0xff, 0x7c, 0x00, 0x00, - 0x32, 0xff, 0x8a, 0x08, - 0x00, 0x26, 0xef, 0x44, - 0x00, 0x00, 0x08, 0x04, - /* ch = ')' */ - 0x8a, 0x66, 0x04, 0x00, - 0x37, 0xf7, 0xb1, 0x10, - 0x00, 0x1f, 0xf7, 0xb1, - 0x00, 0x00, 0x32, 0xff, - 0x00, 0x00, 0x00, 0x90, - 0x00, 0x00, 0x00, 0x3b, - 0x00, 0x00, 0x00, 0x1c, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x1c, - 0x00, 0x00, 0x00, 0x32, - 0x00, 0x00, 0x00, 0x8a, - 0x00, 0x00, 0x24, 0xff, - 0x00, 0x10, 0xdb, 0xb1, - 0x28, 0xdb, 0xd4, 0x10, - 0xcf, 0x8d, 0x08, 0x00, - 0x0c, 0x00, 0x00, 0x00, - /* ch = '*' */ - 0x00, 0x00, 0x00, 0x1e, 0x36, 0x13, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x44, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x17, 0x37, 0x04, 0x32, 0xff, 0x04, 0x08, 0x2a, 0x00, - 0x4a, 0xf7, 0xe5, 0x6f, 0xff, 0x66, 0xf7, 0xdd, 0x11, - 0x00, 0x04, 0x25, 0xa7, 0xff, 0x74, 0x0f, 0x00, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x97, 0xdb, 0x10, 0x00, 0x00, - 0x00, 0x1f, 0xf7, 0x5f, 0x04, 0xc8, 0xb1, 0x04, 0x00, - 0x00, 0x51, 0xb7, 0x04, 0x00, 0x2a, 0xef, 0x22, 0x00, - /* ch = '+' */ - 0x00, 0x00, 0x00, 0x16, 0x36, 0x0d, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x1e, 0x36, 0x36, 0x62, 0xff, 0x4a, 0x36, 0x36, 0x0d, - 0x45, 0xcf, 0xcf, 0xdd, 0xff, 0xd4, 0xcf, 0xcf, 0x1a, - 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x08, 0x15, 0x04, 0x00, 0x00, 0x00, - /* ch = ',' */ - 0x00, 0x9c, 0xbd, 0x10, - 0x0d, 0xef, 0xff, 0x4d, - 0x00, 0x26, 0xff, 0x32, - 0x00, 0x5f, 0xb1, 0x00, - 0x1e, 0xd4, 0x10, 0x00, - /* ch = '-' */ - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x12, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb7, - /* ch = '.' */ - 0x00, 0x8d, 0xbd, 0x17, - 0x04, 0xf7, 0xff, 0x27, - 0x00, 0x0c, 0x0f, 0x00, - /* ch = '/' */ - 0x00, 0xa0, 0x5c, - 0x22, 0xff, 0x44, - 0x8a, 0xe5, 0x04, - 0xff, 0x50, 0x00, - 0xf7, 0x0d, 0x00, - 0x5f, 0x00, 0x00, - 0x17, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* ch = '0' */ - 0x00, 0x00, 0x00, 0x0f, 0x15, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x6b, 0xff, 0xdd, 0xf7, 0x2c, 0x00, 0x00, - 0x00, 0x44, 0xff, 0x26, 0x00, 0x64, 0xf7, 0x17, 0x00, - 0x00, 0xcf, 0x70, 0x00, 0x00, 0x21, 0xff, 0x5f, 0x00, - 0x1f, 0xff, 0x2a, 0x00, 0x10, 0xdb, 0xf7, 0xbd, 0x00, - 0x32, 0xff, 0x1c, 0x04, 0xb1, 0xb1, 0x54, 0xff, 0x00, - 0x49, 0xff, 0x17, 0x50, 0xf7, 0x1f, 0x3b, 0xff, 0x11, - 0x32, 0xff, 0x50, 0xff, 0x32, 0x00, 0x50, 0xff, 0x00, - 0x1f, 0xff, 0xff, 0x50, 0x00, 0x00, 0x6b, 0xcf, 0x00, - 0x00, 0xc8, 0xd9, 0x00, 0x00, 0x04, 0xcf, 0x70, 0x00, - 0x00, 0x3b, 0xff, 0x54, 0x04, 0x5f, 0xf7, 0x1c, 0x00, - 0x00, 0x00, 0x5a, 0xff, 0xff, 0xef, 0x2c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0x15, 0x04, 0x00, 0x00, 0x00, - /* ch = '1' */ - 0x00, 0x00, 0x00, 0x15, 0x08, - 0x00, 0x31, 0xd4, 0xff, 0x32, - 0x60, 0xc4, 0x78, 0xff, 0x32, - 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x1c, 0xff, 0x32, - /* ch = '2' */ - 0x00, 0x00, 0x12, 0x15, 0x0f, 0x00, 0x00, - 0x19, 0xbb, 0xf7, 0xdd, 0xff, 0x77, 0x00, - 0xa4, 0xb1, 0x08, 0x00, 0x3b, 0xff, 0x44, - 0x04, 0x08, 0x00, 0x00, 0x00, 0xbd, 0xa0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x90, - 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x39, - 0x00, 0x00, 0x00, 0x21, 0xf7, 0x7c, 0x00, - 0x00, 0x00, 0x26, 0xf7, 0x7c, 0x04, 0x00, - 0x00, 0x1f, 0xf7, 0x7c, 0x00, 0x00, 0x00, - 0x10, 0xdb, 0xa0, 0x04, 0x00, 0x00, 0x00, - 0x6b, 0xec, 0x1f, 0x15, 0x15, 0x15, 0x12, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb7, - /* ch = '3' */ - 0x00, 0x00, 0x00, 0x15, 0x15, 0x08, 0x00, 0x00, - 0x00, 0x26, 0xd4, 0xff, 0xef, 0xf7, 0x3b, 0x00, - 0x00, 0x24, 0x5a, 0x04, 0x04, 0x6f, 0xff, 0x17, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0xff, 0x22, - 0x00, 0x00, 0x0d, 0x36, 0x66, 0xf7, 0x4d, 0x00, - 0x00, 0x00, 0x14, 0x74, 0xc4, 0xf7, 0x5a, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0xff, 0x2c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x6b, - 0x00, 0x04, 0x08, 0x00, 0x00, 0x0d, 0xff, 0x6b, - 0x04, 0x7c, 0x8a, 0x08, 0x08, 0x8a, 0xff, 0x24, - 0x00, 0x35, 0xef, 0xff, 0xff, 0xef, 0x35, 0x00, - 0x00, 0x00, 0x00, 0x15, 0x15, 0x00, 0x00, 0x00, - /* ch = '4' */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0f, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf7, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x04, 0xb1, 0xff, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x50, 0xdb, 0xff, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0x1f, 0xf7, 0x2a, 0xff, 0x7c, 0x00, 0x00, - 0x00, 0x04, 0xb1, 0x6b, 0x00, 0xff, 0x7c, 0x00, 0x00, - 0x00, 0x50, 0xdb, 0x0d, 0x00, 0xff, 0x7c, 0x00, 0x00, - 0x1f, 0xf7, 0x42, 0x15, 0x15, 0xff, 0x88, 0x15, 0x04, - 0x45, 0xcf, 0xcf, 0xcf, 0xcf, 0xff, 0xff, 0xff, 0x1c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, 0x00, 0x00, - /* ch = '5' */ - 0x00, 0x0c, 0x15, 0x15, 0x15, 0x15, 0x15, 0x0f, - 0x00, 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, - 0x00, 0x50, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x77, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x7c, 0xb7, 0x12, 0x15, 0x0f, 0x00, 0x00, - 0x00, 0x90, 0xff, 0xef, 0xd4, 0xff, 0x94, 0x04, - 0x00, 0x6d, 0x73, 0x04, 0x00, 0x32, 0xff, 0x5f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xe5, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, - 0x00, 0x10, 0x16, 0x00, 0x00, 0x00, 0xa7, 0xcf, - 0x0a, 0xe5, 0xb1, 0x13, 0x00, 0x3f, 0xff, 0x50, - 0x00, 0x21, 0xcb, 0xff, 0xff, 0xff, 0x66, 0x04, - 0x00, 0x00, 0x00, 0x0f, 0x15, 0x08, 0x00, 0x00, - /* ch = '6' */ - 0x00, 0x00, 0x00, 0x08, 0x2a, 0x25, 0x08, 0x00, - 0x00, 0x00, 0x3b, 0xf7, 0xe5, 0xe5, 0xf7, 0x36, - 0x00, 0x1c, 0xff, 0x5f, 0x00, 0x00, 0x48, 0x08, - 0x00, 0x7c, 0xe5, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xcf, 0x6b, 0x08, 0x15, 0x0f, 0x00, 0x00, - 0x04, 0xff, 0xb1, 0xf7, 0xf7, 0xff, 0x84, 0x04, - 0x1c, 0xff, 0xf7, 0x28, 0x00, 0x35, 0xff, 0x44, - 0x1c, 0xff, 0x54, 0x00, 0x00, 0x00, 0xa0, 0xb1, - 0x00, 0xff, 0x5f, 0x00, 0x00, 0x00, 0x7c, 0xb7, - 0x00, 0xa0, 0xc8, 0x00, 0x00, 0x00, 0xa7, 0xa0, - 0x00, 0x3b, 0xff, 0x54, 0x00, 0x35, 0xff, 0x3b, - 0x00, 0x00, 0x50, 0xf7, 0xff, 0xff, 0x66, 0x00, - 0x00, 0x00, 0x00, 0x08, 0x15, 0x08, 0x00, 0x00, - /* ch = '7' */ - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x12, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa0, - 0x00, 0x00, 0x00, 0x00, 0x2c, 0xff, 0x39, - 0x00, 0x00, 0x00, 0x00, 0x8a, 0xe5, 0x04, - 0x00, 0x00, 0x00, 0x17, 0xff, 0x5a, 0x00, - 0x00, 0x00, 0x00, 0x5a, 0xff, 0x17, 0x00, - 0x00, 0x00, 0x04, 0xe5, 0x90, 0x00, 0x00, - 0x00, 0x00, 0x2c, 0xff, 0x39, 0x00, 0x00, - 0x00, 0x00, 0x8a, 0xf7, 0x0d, 0x00, 0x00, - 0x00, 0x0d, 0xf7, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x39, 0xff, 0x32, 0x00, 0x00, 0x00, - 0x00, 0x90, 0xf7, 0x04, 0x00, 0x00, 0x00, - /* ch = '8' */ - 0x00, 0x00, 0x00, 0x20, 0x36, 0x18, 0x00, 0x00, - 0x00, 0x04, 0xa9, 0xf7, 0xcf, 0xff, 0x99, 0x04, - 0x00, 0x5a, 0xf7, 0x13, 0x00, 0x32, 0xff, 0x40, - 0x00, 0x7c, 0xbd, 0x00, 0x00, 0x00, 0xff, 0x50, - 0x00, 0x48, 0xff, 0x32, 0x00, 0x3b, 0xff, 0x2a, - 0x00, 0x04, 0x94, 0xff, 0x9e, 0xf7, 0x44, 0x00, - 0x00, 0x04, 0x84, 0xef, 0xb3, 0xff, 0x5a, 0x00, - 0x00, 0x7c, 0xdb, 0x10, 0x00, 0x3b, 0xff, 0x4d, - 0x1a, 0xff, 0x48, 0x00, 0x00, 0x00, 0xa7, 0xbd, - 0x1c, 0xff, 0x48, 0x00, 0x00, 0x00, 0x90, 0xcf, - 0x00, 0xc8, 0xdb, 0x1b, 0x00, 0x37, 0xff, 0x5f, - 0x00, 0x19, 0xbb, 0xff, 0xff, 0xff, 0x73, 0x04, - 0x00, 0x00, 0x00, 0x0f, 0x15, 0x08, 0x00, 0x00, - /* ch = '9' */ - 0x00, 0x00, 0x00, 0x1a, 0x2a, 0x0c, 0x00, 0x00, - 0x00, 0x10, 0xbb, 0xf7, 0xdd, 0xff, 0x44, 0x00, - 0x00, 0x7c, 0xe5, 0x13, 0x00, 0x54, 0xff, 0x22, - 0x00, 0xf7, 0x5f, 0x00, 0x00, 0x04, 0xf7, 0x6b, - 0x11, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb1, - 0x00, 0xe5, 0x7c, 0x00, 0x00, 0x04, 0xcf, 0xb7, - 0x00, 0x4d, 0xff, 0x47, 0x1a, 0x99, 0xff, 0xb7, - 0x00, 0x00, 0x50, 0xdd, 0xe5, 0x7f, 0xaf, 0xb7, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xff, 0x39, - 0x00, 0x32, 0x50, 0x04, 0x16, 0xc4, 0xc8, 0x04, - 0x00, 0x44, 0xf7, 0xff, 0xff, 0xbb, 0x13, 0x00, - 0x00, 0x00, 0x04, 0x15, 0x0f, 0x00, 0x00, 0x00, - /* ch = ':' */ - 0x00, 0x48, 0x67, 0x04, - 0x0a, 0xff, 0xff, 0x2f, - 0x00, 0x22, 0x30, 0x04, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x8d, 0xbd, 0x17, - 0x04, 0xf7, 0xff, 0x27, - 0x00, 0x0c, 0x0f, 0x00, - /* ch = ';' */ - 0x00, 0x48, 0x67, 0x04, - 0x0a, 0xff, 0xff, 0x2f, - 0x00, 0x22, 0x30, 0x04, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x9c, 0xbd, 0x10, - 0x0d, 0xef, 0xff, 0x4d, - 0x00, 0x26, 0xff, 0x32, - 0x00, 0x5f, 0xb1, 0x00, - 0x1e, 0xd4, 0x10, 0x00, - /* ch = '<' */ - 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, - 0x00, 0x00, 0x04, 0x48, 0xef, 0x1c, - 0x04, 0x37, 0xe5, 0xef, 0x3f, 0x04, - 0xd4, 0xef, 0x48, 0x04, 0x00, 0x00, - 0x50, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xd4, 0x2b, 0x00, 0x00, 0x00, 0x00, - 0x5a, 0xf7, 0xbb, 0x1b, 0x00, 0x00, - 0x00, 0x13, 0x94, 0xff, 0x8d, 0x10, - 0x00, 0x00, 0x00, 0x28, 0xd4, 0x32, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, - /* ch = '=' */ - 0x45, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x1a, - 0x0c, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x04, - 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1c, - /* ch = '>' */ - 0x0c, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xbb, 0x28, 0x00, 0x00, - 0x13, 0x73, 0xff, 0xb3, 0x1e, - 0x00, 0x00, 0x13, 0x7f, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x16, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x08, 0x50, - 0x00, 0x00, 0x37, 0xef, 0xd4, - 0x26, 0xbb, 0xf7, 0x50, 0x04, - 0x7c, 0x94, 0x13, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x00, - /* ch = '?' */ - 0x00, 0x04, 0x66, 0xe5, 0xff, 0xdd, 0x35, 0x00, - 0x04, 0xb1, 0xf7, 0x3f, 0x20, 0x99, 0xff, 0x2f, - 0x00, 0x5a, 0x2a, 0x00, 0x00, 0x0d, 0xff, 0x90, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xff, 0xb1, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xff, 0x5a, - 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x8a, 0x04, - 0x00, 0x00, 0x00, 0x0d, 0xe5, 0x82, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x24, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x22, 0x74, 0x22, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x32, 0xcf, 0x40, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x66, 0xff, 0x84, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x15, 0x04, 0x00, 0x00, - /* ch = '@' */ - 0x00, 0x00, 0x00, 0x18, 0x36, 0x2a, 0x08, 0x00, 0x00, - 0x00, 0x08, 0xa2, 0xef, 0x82, 0xcb, 0xdb, 0x1f, 0x00, - 0x00, 0x90, 0xb1, 0x08, 0x00, 0x00, 0x7c, 0xc8, 0x00, - 0x2a, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x24, - 0x5f, 0xb7, 0x00, 0x13, 0x8d, 0xf7, 0xff, 0xff, 0x32, - 0x90, 0x7c, 0x00, 0xc8, 0xb1, 0x0c, 0x00, 0xff, 0x32, - 0xb7, 0x7c, 0x1c, 0xff, 0x32, 0x00, 0x14, 0xff, 0x32, - 0x7c, 0x82, 0x0d, 0xf7, 0x7c, 0x08, 0x64, 0xff, 0x32, - 0x50, 0xe5, 0x04, 0x2c, 0xe5, 0xff, 0xb3, 0xcf, 0x2d, - 0x17, 0xff, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x50, 0xf7, 0x3f, 0x00, 0x00, 0x13, 0x19, 0x00, - 0x00, 0x00, 0x40, 0xef, 0xef, 0xd4, 0xff, 0x5e, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x15, 0x15, 0x04, 0x00, 0x00, - /* ch = 'A' */ - 0x00, 0x00, 0x00, 0x0d, 0x19, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x44, 0x8a, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xa0, 0xff, 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x17, 0xff, 0xff, 0x48, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x48, 0xe5, 0x7c, 0xc8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xa7, 0x6b, 0x2c, 0xff, 0x22, 0x00, 0x00, - 0x00, 0x1c, 0xff, 0x2a, 0x00, 0xe5, 0x70, 0x00, 0x00, - 0x00, 0x50, 0xec, 0x15, 0x15, 0x6d, 0xe5, 0x04, 0x00, - 0x00, 0xc8, 0xe5, 0xcf, 0xcf, 0xd4, 0xff, 0x39, 0x00, - 0x22, 0xff, 0x32, 0x00, 0x00, 0x00, 0xc8, 0xa0, 0x00, - 0x5a, 0xf7, 0x04, 0x00, 0x00, 0x00, 0x5a, 0xff, 0x17, - 0xcf, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x17, 0xff, 0x5a, - /* ch = 'B' */ - 0x0c, 0x15, 0x15, 0x15, 0x15, 0x0c, 0x00, 0x00, 0x00, - 0x50, 0xff, 0xd4, 0xcf, 0xef, 0xff, 0x94, 0x04, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x35, 0xff, 0x5a, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xbd, 0xb1, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x13, 0xf7, 0x66, 0x00, - 0x50, 0xff, 0x87, 0x74, 0x82, 0xef, 0xa9, 0x04, 0x00, - 0x50, 0xff, 0x4a, 0x36, 0x74, 0xd4, 0xcb, 0x19, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x04, 0xb7, 0xc8, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x5f, 0xff, 0x1a, - 0x50, 0xff, 0x28, 0x15, 0x15, 0x3f, 0xff, 0x90, 0x00, - 0x50, 0xff, 0xff, 0xff, 0xff, 0xe5, 0x66, 0x04, 0x00, - /* ch = 'C' */ - 0x00, 0x00, 0x0c, 0x25, 0x1a, 0x04, 0x00, 0x00, - 0x04, 0x66, 0xff, 0xcf, 0xe5, 0xef, 0x2f, 0x00, - 0x6b, 0xf7, 0x26, 0x00, 0x04, 0x7c, 0xff, 0x1f, - 0xff, 0x5f, 0x00, 0x00, 0x00, 0x14, 0x37, 0x00, - 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xf7, 0x82, 0x00, 0x00, 0x00, 0x04, 0x0f, 0x00, - 0x50, 0xff, 0x5f, 0x04, 0x08, 0x8a, 0xef, 0x17, - 0x00, 0x50, 0xf7, 0xff, 0xff, 0xcb, 0x21, 0x00, - 0x00, 0x00, 0x04, 0x15, 0x12, 0x00, 0x00, 0x00, - /* ch = 'D' */ - 0x08, 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0xd4, 0xd4, 0xff, 0xef, 0x35, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x08, 0x8a, 0xff, 0x2f, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x04, 0xdb, 0xa7, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x5f, 0xff, 0x14, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x35, 0xff, 0x24, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x35, 0xff, 0x1c, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x5f, 0xf7, 0x04, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x10, 0xe5, 0x7c, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x1e, 0xb1, 0xdb, 0x10, 0x00, - 0x32, 0xff, 0xff, 0xff, 0xf7, 0x8d, 0x13, 0x00, 0x00, - /* ch = 'E' */ - 0x08, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x32, 0xff, 0xdd, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x62, 0x36, 0x36, 0x36, 0x36, 0x00, - 0x32, 0xff, 0xdd, 0xcf, 0xcf, 0xcf, 0xcf, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x3e, 0x15, 0x15, 0x15, 0x15, 0x12, - 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb7, - /* ch = 'F' */ - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x12, - 0xff, 0xef, 0xcf, 0xcf, 0xcf, 0xcf, 0x95, - 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xc8, 0x74, 0x74, 0x74, 0x58, 0x00, - 0xff, 0xa5, 0x36, 0x36, 0x36, 0x2d, 0x00, - 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 'G' */ - 0x00, 0x00, 0x00, 0x0f, 0x2a, 0x20, 0x08, 0x00, 0x00, - 0x00, 0x04, 0x84, 0xff, 0xd4, 0xef, 0xef, 0x2f, 0x00, - 0x00, 0x7c, 0xf7, 0x28, 0x00, 0x04, 0x7c, 0xf7, 0x11, - 0x22, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x0d, 0x21, 0x00, - 0x4d, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7c, 0xbd, 0x00, 0x00, 0x16, 0x36, 0x36, 0x36, 0x16, - 0x7c, 0xff, 0x00, 0x00, 0x2d, 0xcf, 0xd4, 0xff, 0x32, - 0x4d, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x17, 0xff, 0x5f, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x00, 0x6b, 0xff, 0x3f, 0x04, 0x04, 0x43, 0xff, 0x32, - 0x00, 0x00, 0x5b, 0xf7, 0xff, 0xff, 0xe5, 0x48, 0x04, - 0x00, 0x00, 0x00, 0x04, 0x15, 0x12, 0x00, 0x00, 0x00, - /* ch = 'H' */ - 0x08, 0x15, 0x08, 0x00, 0x00, 0x00, 0x0f, 0x15, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xff, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xff, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xff, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xff, - 0x32, 0xff, 0x62, 0x36, 0x36, 0x36, 0xa5, 0xff, - 0x32, 0xff, 0x9c, 0x74, 0x74, 0x74, 0xc8, 0xff, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xff, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xff, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xff, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xff, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xff, - /* ch = 'I' */ - 0x0f, 0x15, 0x15, 0x15, 0x15, 0x15, 0x04, - 0x67, 0xcf, 0xef, 0xff, 0xcf, 0xcf, 0x1a, - 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, - 0xb7, 0xff, 0xff, 0xff, 0xff, 0xff, 0x32, - /* ch = 'J' */ - 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x04, - 0x1a, 0xcf, 0xcf, 0xff, 0xe5, 0xcf, 0x1a, - 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, - 0x00, 0x00, 0x14, 0xff, 0x50, 0x00, 0x00, - 0x00, 0x00, 0x1f, 0xff, 0x44, 0x00, 0x00, - 0x21, 0x00, 0x7c, 0xff, 0x17, 0x00, 0x00, - 0xff, 0xff, 0xf7, 0x3b, 0x00, 0x00, 0x00, - 0x0f, 0x15, 0x08, 0x00, 0x00, 0x00, 0x00, - /* ch = 'K' */ - 0x0c, 0x15, 0x08, 0x00, 0x00, 0x00, 0x21, 0x15, 0x04, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x32, 0xf7, 0x50, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x1f, 0xf7, 0x7c, 0x00, 0x00, - 0x50, 0xff, 0x1c, 0x10, 0xdb, 0xb1, 0x04, 0x00, 0x00, - 0x50, 0xff, 0x26, 0xd4, 0xdb, 0x10, 0x00, 0x00, 0x00, - 0x50, 0xff, 0xdb, 0xff, 0x13, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0xd4, 0xff, 0x5f, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x1f, 0x6b, 0xff, 0x2a, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x1c, 0x04, 0xc8, 0xdb, 0x10, 0x00, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x1f, 0xff, 0x7c, 0x00, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x54, 0xff, 0x3b, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x04, 0xb1, 0xf7, 0x1f, - /* ch = 'L' */ - 0x04, 0x15, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb7, - /* ch = 'M' */ - 0x0f, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x08, - 0x7c, 0xf7, 0x17, 0x00, 0x00, 0x00, 0x39, 0xff, 0x32, - 0x7c, 0xff, 0x6b, 0x00, 0x00, 0x04, 0xc8, 0xff, 0x32, - 0x7c, 0xff, 0xf7, 0x17, 0x00, 0x3b, 0xff, 0xff, 0x32, - 0x7c, 0xbd, 0xe5, 0x6b, 0x04, 0xdb, 0x90, 0xff, 0x32, - 0x7c, 0xb7, 0x48, 0xf7, 0x5f, 0xf7, 0x24, 0xff, 0x32, - 0x7c, 0xb7, 0x04, 0xdb, 0xff, 0x50, 0x1c, 0xff, 0x32, - 0x7c, 0xb7, 0x00, 0x44, 0xdb, 0x04, 0x1c, 0xff, 0x32, - 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, - /* ch = 'N' */ - 0x0c, 0x15, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x15, 0x04, - 0x50, 0xff, 0x5f, 0x00, 0x00, 0x00, 0x50, 0xff, 0x00, - 0x50, 0xff, 0xf7, 0x17, 0x00, 0x00, 0x50, 0xff, 0x00, - 0x50, 0xff, 0xff, 0x7c, 0x00, 0x00, 0x50, 0xff, 0x00, - 0x50, 0xff, 0x7c, 0xff, 0x24, 0x00, 0x50, 0xff, 0x00, - 0x50, 0xff, 0x1f, 0xdb, 0xa0, 0x00, 0x50, 0xff, 0x00, - 0x50, 0xff, 0x1c, 0x3b, 0xff, 0x3b, 0x50, 0xff, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0xa0, 0xdb, 0x54, 0xff, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x24, 0xff, 0xe5, 0xff, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x7c, 0xff, 0xff, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x17, 0xf7, 0xff, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x5f, 0xff, 0x00, - /* ch = 'O' */ - 0x00, 0x00, 0x00, 0x1a, 0x36, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x13, 0xcb, 0xff, 0xe5, 0xff, 0x94, 0x04, 0x00, - 0x04, 0xb7, 0xdb, 0x13, 0x00, 0x35, 0xff, 0x77, 0x00, - 0x39, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x70, 0xff, 0x0d, - 0x77, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x2f, 0xff, 0x2f, - 0xa0, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x4d, - 0xb7, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x50, - 0x90, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x44, - 0x6b, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x32, 0xff, 0x2a, - 0x2c, 0xff, 0x48, 0x00, 0x00, 0x00, 0x7c, 0xf7, 0x04, - 0x00, 0x90, 0xf7, 0x37, 0x0f, 0x5a, 0xff, 0x50, 0x00, - 0x00, 0x04, 0x8d, 0xff, 0xff, 0xf7, 0x5a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0x15, 0x04, 0x00, 0x00, 0x00, - /* ch = 'P' */ - 0x08, 0x15, 0x15, 0x15, 0x15, 0x12, 0x00, 0x00, 0x00, - 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd4, 0x19, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x1e, 0xdb, 0xc8, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x54, 0xff, 0x1c, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x54, 0xff, 0x1a, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x26, 0xe5, 0xa0, 0x00, - 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8d, 0x10, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 'Q' */ - 0x00, 0x00, 0x00, 0x1a, 0x36, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x13, 0xcb, 0xff, 0xd4, 0xff, 0x94, 0x04, 0x00, - 0x04, 0xb7, 0xc8, 0x13, 0x00, 0x28, 0xf7, 0x6b, 0x00, - 0x39, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x64, 0xff, 0x0d, - 0x77, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x2a, 0xff, 0x2f, - 0xa0, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xff, 0x4d, - 0xb7, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, - 0x82, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xff, 0x44, - 0x5f, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x2a, 0xff, 0x2f, - 0x2a, 0xff, 0x44, 0x00, 0x00, 0x00, 0x70, 0xf7, 0x0d, - 0x00, 0x90, 0xf7, 0x2b, 0x04, 0x3f, 0xff, 0x50, 0x00, - 0x00, 0x04, 0x8d, 0xff, 0xff, 0xf7, 0x50, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x2a, 0xff, 0x24, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0d, 0xdb, 0xc4, 0x74, 0x74, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x13, 0x5b, 0x74, 0x74, 0x00, - /* ch = 'R' */ - 0x08, 0x15, 0x15, 0x15, 0x15, 0x0f, 0x00, 0x00, 0x00, - 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbb, 0x10, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x28, 0xf7, 0x8a, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x82, 0xff, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x82, 0xf7, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x04, 0x31, 0xf7, 0x6b, 0x00, - 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8d, 0x04, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x70, 0xf7, 0x0d, 0x00, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x17, 0xff, 0x5a, 0x00, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x70, 0xf7, 0x10, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x17, 0xff, 0x5f, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x70, 0xf7, 0x17, - /* ch = 'S' */ - 0x00, 0x00, 0x12, 0x15, 0x12, 0x00, 0x00, 0x00, - 0x10, 0xbb, 0xf7, 0xcf, 0xf7, 0xd4, 0x21, 0x00, - 0xa0, 0xc8, 0x10, 0x00, 0x08, 0xb1, 0x54, 0x00, - 0xff, 0x7c, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, - 0xb7, 0xe5, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1f, 0xef, 0xf7, 0x66, 0x16, 0x00, 0x00, 0x00, - 0x00, 0x08, 0x50, 0xe5, 0xff, 0x7e, 0x08, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x37, 0xf7, 0xa0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1a, - 0x39, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1a, - 0xff, 0x77, 0x0c, 0x00, 0x28, 0xef, 0xa0, 0x00, - 0x48, 0xe5, 0xff, 0xff, 0xff, 0x94, 0x10, 0x00, - 0x00, 0x00, 0x12, 0x15, 0x0c, 0x00, 0x00, 0x00, - /* ch = 'T' */ - 0x12, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x08, - 0xb7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x32, - 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, - /* ch = 'U' */ - 0x0c, 0x15, 0x08, 0x00, 0x00, 0x00, 0x08, 0x15, 0x04, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, - 0x4d, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, - 0x2f, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x5f, 0xff, 0x0d, - 0x04, 0xdb, 0xc8, 0x13, 0x00, 0x28, 0xf7, 0x7c, 0x00, - 0x00, 0x19, 0xcb, 0xff, 0xf7, 0xff, 0x7e, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x0f, 0x15, 0x0c, 0x00, 0x00, 0x00, - /* ch = 'V' */ - 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x0f, - 0x70, 0xf7, 0x04, 0x00, 0x00, 0x00, 0x22, 0xff, 0x39, - 0x2c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x50, 0xf7, 0x0d, - 0x04, 0xe5, 0x7c, 0x00, 0x00, 0x00, 0xb7, 0x8a, 0x00, - 0x00, 0x70, 0xf7, 0x04, 0x00, 0x17, 0xff, 0x39, 0x00, - 0x00, 0x2c, 0xff, 0x32, 0x00, 0x48, 0xf7, 0x0d, 0x00, - 0x00, 0x00, 0xe5, 0x7c, 0x00, 0xa0, 0x8a, 0x00, 0x00, - 0x00, 0x00, 0x6b, 0xf7, 0x17, 0xff, 0x39, 0x00, 0x00, - 0x00, 0x00, 0x2a, 0xff, 0x90, 0xf7, 0x0d, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xe5, 0xff, 0x8a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x6b, 0xff, 0x39, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x2a, 0xf7, 0x0d, 0x00, 0x00, 0x00, - /* ch = 'W' */ - 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x12, - 0xcf, 0x6b, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x82, 0x7c, - 0x90, 0x90, 0x00, 0x0d, 0xff, 0x14, 0x00, 0xb7, 0x50, - 0x6b, 0xcf, 0x00, 0x32, 0xff, 0x3b, 0x00, 0xff, 0x32, - 0x44, 0xff, 0x0d, 0x6b, 0xff, 0x7c, 0x1a, 0xff, 0x1f, - 0x2a, 0xff, 0x24, 0xcf, 0xcf, 0xe5, 0x24, 0xff, 0x04, - 0x14, 0xff, 0x5f, 0xff, 0x39, 0xff, 0x54, 0xbd, 0x00, - 0x00, 0xf7, 0xcf, 0xb7, 0x04, 0xf7, 0xe5, 0x90, 0x00, - 0x00, 0xb1, 0xff, 0x5f, 0x00, 0xa0, 0xff, 0x5f, 0x00, - 0x00, 0x77, 0xff, 0x2f, 0x00, 0x50, 0xff, 0x3b, 0x00, - 0x00, 0x4d, 0xff, 0x0d, 0x00, 0x24, 0xff, 0x2a, 0x00, - 0x00, 0x2f, 0xa0, 0x00, 0x00, 0x00, 0xf7, 0x14, 0x00, - /* ch = 'X' */ - 0x0c, 0x15, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x15, 0x00, - 0x1c, 0xff, 0x5f, 0x00, 0x00, 0x04, 0xc8, 0x8a, 0x00, - 0x00, 0x6b, 0xf7, 0x17, 0x00, 0x44, 0xff, 0x1c, 0x00, - 0x00, 0x10, 0xf7, 0x7c, 0x0d, 0xe5, 0x7c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x97, 0xff, 0x17, 0x00, 0x00, - 0x00, 0x00, 0x04, 0xdb, 0xff, 0x70, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x82, 0xff, 0x3f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0xff, 0xff, 0xdb, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x90, 0xe5, 0x32, 0xff, 0x50, 0x00, 0x00, - 0x00, 0x2a, 0xff, 0x44, 0x00, 0x90, 0xf7, 0x10, 0x00, - 0x00, 0xa7, 0xdb, 0x04, 0x00, 0x1c, 0xff, 0x6b, 0x00, - 0x35, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x6b, 0xff, 0x1f, - /* ch = 'Y' */ - 0x12, 0x15, 0x00, 0x00, 0x00, 0x00, 0x04, 0x15, 0x0c, - 0x44, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x48, 0xff, 0x22, - 0x04, 0xdb, 0xa7, 0x00, 0x00, 0x04, 0xe5, 0x8a, 0x00, - 0x00, 0x44, 0xff, 0x32, 0x00, 0x39, 0xff, 0x24, 0x00, - 0x00, 0x04, 0xdb, 0xb7, 0x00, 0xc8, 0xa0, 0x00, 0x00, - 0x00, 0x00, 0x44, 0xff, 0x70, 0xff, 0x2c, 0x00, 0x00, - 0x00, 0x00, 0x04, 0xc8, 0xff, 0xb7, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3f, 0xff, 0x3b, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, - /* ch = 'Z' */ - 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, - 0x1c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xf7, 0x54, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xdb, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x35, 0xff, 0x32, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0d, 0xdb, 0x90, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x6b, 0xf7, 0x17, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1f, 0xff, 0x54, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xb1, 0xdb, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x44, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0xf7, 0xa4, 0x15, 0x15, 0x15, 0x15, 0x15, 0x08, - 0x4d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x32, - /* ch = '[' */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x82, 0x36, 0x36, 0x36, 0x1e, - 0x74, 0x74, 0x74, 0x74, 0x74, 0x30, - /* ch = '\' */ - 0x09, 0xb3, 0x48, - 0x00, 0xa0, 0xc8, - 0x00, 0x2c, 0xff, - 0x00, 0x00, 0xb7, - 0x00, 0x00, 0x39, - 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* ch = ']' */ - 0xb7, 0xff, 0xff, 0xff, 0xff, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, - 0x2d, 0x36, 0x36, 0x36, 0xcf, 0x7c, - 0x58, 0x74, 0x74, 0x74, 0x74, 0x42, - /* ch = '^' */ - 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x22, 0x00, 0x00, - 0x00, 0x04, 0xdb, 0xff, 0x90, 0x00, 0x00, - 0x00, 0x54, 0xe5, 0x3f, 0xff, 0x2a, 0x00, - 0x17, 0xf7, 0x3b, 0x00, 0xa0, 0xa0, 0x00, - 0x36, 0x8d, 0x00, 0x00, 0x24, 0x9e, 0x13, - /* ch = '_' */ - 0x42, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x22, - 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x16, - /* ch = '`' */ - 0x7f, 0x70, 0x00, 0x00, - 0x3b, 0xf7, 0x17, 0x00, - 0x0d, 0xf7, 0xc4, 0x10, - 0x00, 0x50, 0xff, 0x4d, - 0x00, 0x00, 0x12, 0x04, - /* ch = 'a' */ - 0x00, 0x00, 0x08, 0x2a, 0x36, 0x25, 0x04, 0x00, - 0x00, 0x36, 0xf7, 0xdd, 0x8f, 0xef, 0xd4, 0x10, - 0x00, 0x1f, 0x35, 0x00, 0x00, 0x10, 0xe5, 0x70, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xb7, - 0x00, 0x08, 0x50, 0xab, 0xcf, 0xcf, 0xef, 0xb7, - 0x0d, 0xd4, 0xc4, 0x25, 0x15, 0x15, 0x88, 0xb7, - 0x3b, 0xff, 0x24, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0x32, 0xff, 0x3f, 0x00, 0x04, 0x5f, 0xff, 0xb7, - 0x00, 0x73, 0xff, 0xd4, 0xef, 0xb3, 0xa5, 0xb7, - 0x00, 0x00, 0x0c, 0x15, 0x0c, 0x00, 0x00, 0x00, - /* ch = 'b' */ - 0x32, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x32, 0x16, 0x36, 0x2a, 0x04, 0x00, 0x00, - 0x32, 0xff, 0xa9, 0xef, 0xcf, 0xff, 0xdb, 0x16, 0x00, - 0x32, 0xff, 0xb7, 0x08, 0x00, 0x21, 0xff, 0xa0, 0x00, - 0x32, 0xff, 0x4d, 0x00, 0x00, 0x00, 0x7c, 0xff, 0x14, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, - 0x32, 0xff, 0x35, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, - 0x32, 0xff, 0x54, 0x00, 0x00, 0x00, 0x8a, 0xf7, 0x04, - 0x32, 0xff, 0xdb, 0x1b, 0x04, 0x3f, 0xff, 0x6b, 0x00, - 0x32, 0xff, 0x5b, 0xf7, 0xff, 0xff, 0x84, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x08, 0x15, 0x0c, 0x00, 0x00, 0x00, - /* ch = 'c' */ - 0x00, 0x00, 0x0f, 0x36, 0x36, 0x0f, 0x00, 0x00, - 0x04, 0x94, 0xff, 0xd4, 0xdd, 0xff, 0x66, 0x00, - 0x77, 0xf7, 0x21, 0x00, 0x00, 0x3f, 0xb1, 0x04, - 0xff, 0x5f, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, - 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xf7, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x5f, 0x08, 0x08, 0x5a, 0xa0, 0x04, - 0x00, 0x50, 0xf7, 0xff, 0xff, 0xef, 0x35, 0x00, - 0x00, 0x00, 0x04, 0x15, 0x15, 0x00, 0x00, 0x00, - /* ch = 'd' */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xcf, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, - 0x00, 0x00, 0x0c, 0x36, 0x36, 0x16, 0x7c, 0xb7, - 0x00, 0x32, 0xf7, 0xcb, 0x9e, 0xff, 0xdb, 0xb7, - 0x0d, 0xf7, 0x7c, 0x00, 0x00, 0x26, 0xff, 0xb7, - 0x3b, 0xff, 0x1f, 0x00, 0x00, 0x00, 0xbd, 0xb7, - 0x50, 0xff, 0x0d, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0x2f, 0xff, 0x3b, 0x00, 0x00, 0x04, 0xe5, 0xb7, - 0x04, 0xdb, 0xdb, 0x1b, 0x08, 0x6b, 0xff, 0xb7, - 0x00, 0x1f, 0xd4, 0xff, 0xff, 0xa9, 0x97, 0xcf, - 0x00, 0x00, 0x00, 0x12, 0x0f, 0x00, 0x00, 0x00, - /* ch = 'e' */ - 0x00, 0x00, 0x04, 0x2a, 0x36, 0x25, 0x04, 0x00, - 0x00, 0x1f, 0xdb, 0xd4, 0x74, 0xef, 0xc4, 0x10, - 0x00, 0xc8, 0xb1, 0x04, 0x00, 0x10, 0xe5, 0x70, - 0x2a, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xcf, - 0x44, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x44, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x24, 0xff, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xa0, 0xf7, 0x24, 0x00, 0x04, 0x66, 0x35, - 0x00, 0x10, 0x94, 0xff, 0xe5, 0xff, 0xcb, 0x1f, - 0x00, 0x00, 0x00, 0x08, 0x15, 0x0f, 0x00, 0x00, - /* ch = 'f' */ - 0x00, 0x1f, 0xc4, 0xff, 0xff, 0xb3, 0x19, - 0x0d, 0xdb, 0x90, 0x08, 0x0c, 0x99, 0x48, - 0x32, 0xff, 0x24, 0x00, 0x00, 0x08, 0x04, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0xdd, 0xff, 0xd4, 0xcf, 0x95, 0x00, 0x00, - 0x3e, 0xff, 0x28, 0x15, 0x12, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, - /* ch = 'g' */ - 0x00, 0x00, 0x16, 0x36, 0x36, 0x13, 0x16, 0x36, 0x19, - 0x00, 0x44, 0xff, 0x8f, 0xa4, 0xf7, 0xf7, 0x8f, 0x30, - 0x0d, 0xf7, 0x54, 0x00, 0x00, 0x82, 0xc8, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, - 0x04, 0xe5, 0x90, 0x04, 0x10, 0xb7, 0xa0, 0x00, 0x00, - 0x00, 0x31, 0xff, 0xef, 0xf7, 0xbb, 0x10, 0x00, 0x00, - 0x00, 0x99, 0x75, 0x15, 0x12, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xe5, 0xc4, 0x3e, 0x36, 0x36, 0x25, 0x04, 0x00, - 0x00, 0x6d, 0xbb, 0x74, 0x74, 0x8f, 0xf7, 0xb1, 0x00, - 0x44, 0xe5, 0x04, 0x00, 0x00, 0x00, 0x3b, 0xff, 0x1c, - 0x6b, 0xff, 0x28, 0x00, 0x00, 0x0c, 0x90, 0xdb, 0x04, - 0x08, 0x7f, 0xf7, 0xff, 0xef, 0xff, 0x9e, 0x19, 0x00, - /* ch = 'h' */ - 0xff, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0x50, 0x04, 0x30, 0x36, 0x0c, 0x00, - 0xff, 0x82, 0xdb, 0xd4, 0xef, 0xf7, 0x1f, - 0xff, 0xff, 0x35, 0x00, 0x17, 0xff, 0x77, - 0xff, 0x82, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0xff, 0x54, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, - /* ch = 'i' */ - 0x00, 0x00, 0x39, 0xcf, 0x24, 0x00, 0x00, - 0x00, 0x00, 0x60, 0xff, 0x3e, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x15, 0x15, 0x15, 0x04, 0x00, 0x00, - 0x45, 0xcf, 0xe5, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, - 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1c, - /* ch = 'j' */ - 0x00, 0x00, 0x00, 0x00, 0x0d, 0xab, 0x60, - 0x00, 0x00, 0x00, 0x00, 0x17, 0xf7, 0xa0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x15, 0x15, 0x15, 0x15, 0x0f, - 0x00, 0x00, 0xcf, 0xcf, 0xcf, 0xff, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, - 0x00, 0x0c, 0x00, 0x00, 0x0d, 0xff, 0x5f, - 0x1a, 0xef, 0x24, 0x04, 0x7c, 0xff, 0x2a, - 0x10, 0xb3, 0xff, 0xff, 0xef, 0x3b, 0x00, - 0x00, 0x00, 0x08, 0x0f, 0x00, 0x00, 0x00, - /* ch = 'k' */ - 0x1c, 0xff, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x12, 0x15, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x5f, 0xf7, 0x35, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x6b, 0xf7, 0x2c, 0x00, 0x00, - 0x1c, 0xff, 0x54, 0x7c, 0xf7, 0x26, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0xf7, 0xff, 0xdb, 0x04, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0xc4, 0x35, 0xff, 0x7c, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x50, 0xff, 0x50, 0x00, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x7c, 0xff, 0x32, 0x00, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x04, 0xb1, 0xf7, 0x21, - /* ch = 'l' */ - 0xb7, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, - /* ch = 'm' */ - 0x0f, 0x12, 0x1e, 0x36, 0x13, 0x13, 0x36, 0x22, 0x00, - 0x7c, 0xf7, 0xc4, 0xdb, 0xdb, 0xef, 0xab, 0xff, 0x27, - 0x7c, 0xff, 0x10, 0x3b, 0xff, 0x3b, 0x1c, 0xff, 0x50, - 0x7c, 0xb7, 0x00, 0x32, 0xff, 0x1c, 0x1c, 0xff, 0x50, - 0x7c, 0xb7, 0x00, 0x32, 0xff, 0x1c, 0x1c, 0xff, 0x50, - 0x7c, 0xb7, 0x00, 0x32, 0xff, 0x1c, 0x1c, 0xff, 0x50, - 0x7c, 0xb7, 0x00, 0x32, 0xff, 0x1c, 0x1c, 0xff, 0x50, - 0x7c, 0xb7, 0x00, 0x32, 0xff, 0x1c, 0x1c, 0xff, 0x50, - 0x7c, 0xb7, 0x00, 0x32, 0xff, 0x1c, 0x1c, 0xff, 0x50, - /* ch = 'n' */ - 0x04, 0x15, 0x0c, 0x08, 0x30, 0x36, 0x0c, 0x00, - 0x1c, 0xff, 0x82, 0xdb, 0xd4, 0xef, 0xef, 0x1c, - 0x1c, 0xff, 0xff, 0x35, 0x00, 0x1a, 0xff, 0x6b, - 0x1c, 0xff, 0x7c, 0x00, 0x00, 0x00, 0xb7, 0x90, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, - /* ch = 'o' */ - 0x00, 0x00, 0x04, 0x25, 0x36, 0x25, 0x00, 0x00, 0x00, - 0x00, 0x1f, 0xd4, 0xef, 0xcf, 0xf7, 0xbb, 0x10, 0x00, - 0x04, 0xdb, 0xb1, 0x08, 0x00, 0x1f, 0xf7, 0x8a, 0x00, - 0x39, 0xff, 0x32, 0x00, 0x00, 0x00, 0x64, 0xff, 0x14, - 0x54, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x35, 0xff, 0x24, - 0x54, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x35, 0xff, 0x24, - 0x32, 0xff, 0x48, 0x00, 0x00, 0x00, 0x70, 0xf7, 0x0d, - 0x04, 0xb1, 0xf7, 0x21, 0x00, 0x35, 0xff, 0x6b, 0x00, - 0x00, 0x10, 0xa2, 0xff, 0xff, 0xff, 0x73, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x0f, 0x15, 0x0c, 0x00, 0x00, 0x00, - /* ch = 'p' */ - 0x08, 0x15, 0x08, 0x16, 0x36, 0x2a, 0x08, 0x00, 0x00, - 0x32, 0xff, 0xa9, 0xef, 0xcf, 0xf7, 0xdb, 0x1f, 0x00, - 0x32, 0xff, 0xb7, 0x08, 0x00, 0x1f, 0xf7, 0xb7, 0x00, - 0x32, 0xff, 0x4d, 0x00, 0x00, 0x00, 0x5f, 0xff, 0x1c, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x35, 0xff, 0x32, - 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x35, 0xff, 0x2f, - 0x32, 0xff, 0x54, 0x00, 0x00, 0x00, 0x70, 0xff, 0x14, - 0x32, 0xff, 0xdb, 0x1b, 0x00, 0x31, 0xf7, 0x77, 0x00, - 0x32, 0xff, 0x8a, 0xf7, 0xff, 0xff, 0x94, 0x08, 0x00, - 0x1c, 0xff, 0x32, 0x08, 0x15, 0x0f, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 'q' */ - 0x00, 0x00, 0x0c, 0x30, 0x36, 0x16, 0x0f, 0x15, - 0x00, 0x2c, 0xf7, 0xcb, 0x8f, 0xf7, 0xdb, 0xff, - 0x0d, 0xf7, 0x82, 0x00, 0x00, 0x26, 0xff, 0xff, - 0x3b, 0xff, 0x24, 0x00, 0x00, 0x00, 0xb1, 0xff, - 0x50, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x7c, 0xff, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x82, 0xff, - 0x32, 0xff, 0x3f, 0x00, 0x00, 0x04, 0xcf, 0xff, - 0x04, 0xc8, 0xdb, 0x21, 0x04, 0x5f, 0xff, 0xff, - 0x00, 0x19, 0xcb, 0xff, 0xff, 0xbb, 0x97, 0xff, - 0x00, 0x00, 0x00, 0x12, 0x0f, 0x00, 0x7c, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, - /* ch = 'r' */ - 0x0c, 0x15, 0x04, 0x16, 0x36, 0x30, 0x0c, 0x00, - 0x50, 0xff, 0x99, 0xff, 0xcf, 0xe5, 0xf7, 0x11, - 0x50, 0xff, 0xf7, 0x21, 0x00, 0x04, 0x73, 0x00, - 0x50, 0xff, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 's' */ - 0x00, 0x00, 0x04, 0x2a, 0x36, 0x2a, 0x08, 0x00, - 0x00, 0x1f, 0xef, 0xcb, 0x74, 0xd4, 0xf7, 0x3b, - 0x00, 0x90, 0xcf, 0x04, 0x00, 0x04, 0x7c, 0x35, - 0x00, 0x6b, 0xff, 0x3f, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x08, 0x8d, 0xff, 0xff, 0x9e, 0x2b, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0x37, 0xbb, 0xff, 0x50, - 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0xbd, 0xc8, - 0x17, 0xf7, 0x5a, 0x08, 0x00, 0x1b, 0xe5, 0x8a, - 0x00, 0x48, 0xe5, 0xff, 0xff, 0xff, 0x94, 0x10, - 0x00, 0x00, 0x00, 0x12, 0x15, 0x08, 0x00, 0x00, - /* ch = 't' */ - 0x00, 0x00, 0x50, 0x4a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0x77, 0x00, 0x00, 0x00, - 0x15, 0x1a, 0xff, 0x5e, 0x15, 0x15, 0x04, - 0xcf, 0xd4, 0xff, 0xe5, 0xcf, 0xcf, 0x1a, - 0x00, 0x1c, 0xff, 0x44, 0x00, 0x00, 0x00, - 0x00, 0x2a, 0xff, 0x32, 0x00, 0x00, 0x00, - 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, - 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, - 0x00, 0x32, 0xff, 0x35, 0x00, 0x00, 0x00, - 0x00, 0x1c, 0xff, 0x9e, 0x0c, 0x2b, 0x6c, - 0x00, 0x00, 0x77, 0xff, 0xff, 0xf7, 0x5b, - 0x00, 0x00, 0x00, 0x0c, 0x15, 0x00, 0x00, - /* ch = 'u' */ - 0x04, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x12, 0x12, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, - 0x1c, 0xff, 0x54, 0x00, 0x00, 0x04, 0xe5, 0xb7, - 0x00, 0xc8, 0xdb, 0x13, 0x04, 0x70, 0xff, 0xb7, - 0x00, 0x1f, 0xd4, 0xff, 0xef, 0xa2, 0xcf, 0xbd, - 0x00, 0x00, 0x00, 0x15, 0x12, 0x00, 0x00, 0x00, - /* ch = 'v' */ - 0x0f, 0x15, 0x08, 0x00, 0x00, 0x00, 0x08, 0x15, 0x04, - 0x32, 0xff, 0x39, 0x00, 0x00, 0x00, 0x44, 0xf7, 0x04, - 0x04, 0xe5, 0x8a, 0x00, 0x00, 0x00, 0x90, 0x8a, 0x00, - 0x00, 0x5a, 0xff, 0x17, 0x00, 0x17, 0xff, 0x32, 0x00, - 0x00, 0x17, 0xff, 0x5a, 0x00, 0x5a, 0xe5, 0x04, 0x00, - 0x00, 0x00, 0xa0, 0xe5, 0x04, 0xe5, 0x5a, 0x00, 0x00, - 0x00, 0x00, 0x39, 0xff, 0x7c, 0xf7, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x04, 0xe5, 0xff, 0x70, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x5f, 0xff, 0x22, 0x00, 0x00, 0x00, - /* ch = 'w' */ - 0x15, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0f, - 0xcf, 0x5f, 0x00, 0x10, 0x36, 0x00, 0x00, 0xb7, 0x54, - 0x82, 0xa0, 0x00, 0x3b, 0xff, 0x24, 0x00, 0xff, 0x3b, - 0x54, 0xf7, 0x00, 0x77, 0xff, 0x5f, 0x0d, 0xff, 0x2a, - 0x2f, 0xff, 0x1c, 0xcf, 0xc8, 0xb7, 0x1f, 0xff, 0x14, - 0x14, 0xff, 0x48, 0xff, 0x32, 0xff, 0x4c, 0xe5, 0x00, - 0x00, 0xcf, 0xcf, 0xa0, 0x04, 0xf7, 0xe5, 0xa0, 0x00, - 0x00, 0x82, 0xff, 0x50, 0x00, 0x7c, 0xff, 0x5f, 0x00, - 0x00, 0x4d, 0xff, 0x24, 0x00, 0x3b, 0xff, 0x3b, 0x00, - /* ch = 'x' */ - 0x1c, 0x15, 0x08, 0x00, 0x00, 0x00, 0x12, 0x12, 0x00, - 0x04, 0xdb, 0xb1, 0x04, 0x00, 0x2f, 0xff, 0x35, 0x00, - 0x00, 0x1f, 0xff, 0x54, 0x0d, 0xdb, 0x82, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xff, 0xa9, 0xe5, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x04, 0xb7, 0xff, 0x37, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x10, 0xf7, 0xff, 0x7c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xa0, 0xdb, 0x43, 0xff, 0x3b, 0x00, 0x00, - 0x00, 0x44, 0xff, 0x32, 0x00, 0x7c, 0xf7, 0x1c, 0x00, - 0x1f, 0xf7, 0x7c, 0x00, 0x00, 0x0d, 0xdb, 0xb1, 0x04, - /* ch = 'y' */ - 0x0c, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x15, 0x08, - 0x22, 0xff, 0x48, 0x00, 0x00, 0x00, 0x54, 0xff, 0x14, - 0x00, 0xa7, 0xc8, 0x00, 0x00, 0x00, 0xa7, 0xa0, 0x00, - 0x00, 0x39, 0xff, 0x2c, 0x00, 0x1c, 0xff, 0x39, 0x00, - 0x00, 0x04, 0xe5, 0x70, 0x00, 0x5a, 0xf7, 0x04, 0x00, - 0x00, 0x00, 0x6b, 0xf7, 0x0d, 0xc8, 0x70, 0x00, 0x00, - 0x00, 0x00, 0x22, 0xff, 0x7c, 0xff, 0x2a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xa7, 0xff, 0xc8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x39, 0xff, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3b, 0xff, 0x17, 0x00, 0x00, 0x00, - 0x39, 0x26, 0x13, 0xdb, 0x8a, 0x00, 0x00, 0x00, 0x00, - 0x97, 0xff, 0xff, 0xbb, 0x10, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ch = 'z' */ - 0x00, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x0f, 0x00, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0xb1, 0xdb, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7c, 0xf7, 0x1f, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x50, 0xff, 0x32, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x32, 0xff, 0x5f, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x1f, 0xf7, 0xb1, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x04, 0xdb, 0xec, 0x1f, 0x15, 0x15, 0x15, 0x15, 0x04, - 0x4d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1c, - /* ch = '{' */ - 0x00, 0x00, 0x20, 0x36, 0x36, 0x16, - 0x00, 0x7c, 0xf7, 0x82, 0x74, 0x22, - 0x2a, 0xff, 0x39, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x3b, 0xff, 0x1a, 0x00, 0x00, 0x00, - 0xb1, 0x99, 0x00, 0x00, 0x00, 0x00, - 0xd9, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x90, 0xc8, 0x00, 0x00, 0x00, 0x00, - 0x44, 0xff, 0x1a, 0x00, 0x00, 0x00, - 0x4d, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, - 0x3b, 0xff, 0x24, 0x00, 0x00, 0x00, - 0x17, 0xf7, 0xb1, 0x1a, 0x15, 0x08, - 0x00, 0x26, 0xab, 0xcf, 0xcf, 0x2d, - /* ch = '|' */ - 0x45, 0xcf, 0x1a, - 0x50, 0xff, 0x1c, - 0x50, 0xff, 0x1c, - 0x50, 0xff, 0x1c, - 0x50, 0xff, 0x1c, - 0x50, 0xff, 0x1c, - 0x50, 0xff, 0x1c, - 0x50, 0xff, 0x1c, - 0x50, 0xff, 0x1c, - 0x50, 0xff, 0x1c, - 0x50, 0xff, 0x1c, - 0x50, 0xff, 0x1c, - 0x50, 0xff, 0x1c, - 0x50, 0xff, 0x1c, - 0x45, 0xcf, 0x1a, - /* ch = '}' */ - 0x26, 0x36, 0x36, 0x16, 0x00, - 0x42, 0x74, 0xa4, 0xff, 0x39, - 0x00, 0x00, 0x00, 0x8a, 0xe5, - 0x00, 0x00, 0x00, 0x50, 0xff, - 0x00, 0x00, 0x00, 0x50, 0xff, - 0x00, 0x00, 0x00, 0x4d, 0xff, - 0x00, 0x00, 0x00, 0x10, 0xef, - 0x00, 0x00, 0x00, 0x00, 0x36, - 0x00, 0x00, 0x00, 0x1c, 0xff, - 0x00, 0x00, 0x00, 0x4d, 0xff, - 0x00, 0x00, 0x00, 0x50, 0xff, - 0x00, 0x00, 0x00, 0x50, 0xff, - 0x00, 0x00, 0x00, 0x5f, 0xff, - 0x0f, 0x15, 0x2b, 0xf7, 0xa0, - 0x67, 0xcf, 0xcf, 0x7f, 0x10, - /* ch = '~' */ - 0x00, 0x04, 0x2a, 0x2a, 0x04, 0x00, 0x00, 0x0c, 0x00, - 0x10, 0xc4, 0xe5, 0xef, 0xd4, 0x24, 0x21, 0xf7, 0x33, - 0x29, 0x9c, 0x08, 0x08, 0x94, 0xff, 0xff, 0x66, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0c, 0x00, 0x00 + /* ch = '!' */ + 0x00, 0x94, 0xef, 0x14, 0x00, 0xb7, 0xff, 0x27, 0x00, 0xb7, 0xff, 0x1c, + 0x00, 0x82, 0xff, 0x1a, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x7c, 0xff, 0x00, + 0x00, 0x54, 0xbd, 0x00, 0x00, 0x50, 0xb7, 0x00, 0x00, 0x30, 0x58, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa2, 0xe5, 0x1c, 0x04, 0xe5, 0xff, 0x27, + 0x00, 0x0c, 0x12, 0x00, + /* ch = '"' */ + 0x99, 0xc0, 0x00, 0x6b, 0xdb, 0x04, 0xb7, 0xf7, 0x00, 0x82, 0xff, 0x14, + 0xb7, 0x90, 0x00, 0x82, 0xb7, 0x00, 0xff, 0x39, 0x00, 0xe5, 0x50, 0x00, + 0x5b, 0x0d, 0x0d, 0x5b, 0x17, 0x00, + /* ch = '#' */ + 0x00, 0x00, 0x04, 0x15, 0x04, 0x04, 0x15, 0x08, 0x00, 0x00, 0x00, 0x32, + 0xff, 0x1a, 0x24, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x3b, 0xff, 0x00, 0x32, + 0xff, 0x0d, 0x00, 0x0c, 0x15, 0x5e, 0xc6, 0x15, 0x5e, 0xff, 0x15, 0x0c, + 0x42, 0x74, 0xc8, 0xc8, 0x74, 0xc8, 0xe5, 0x74, 0x30, 0x00, 0x00, 0xa0, + 0x77, 0x00, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x50, 0x00, 0xb7, + 0x6b, 0x00, 0x00, 0x12, 0x15, 0xff, 0x42, 0x2a, 0xf7, 0x82, 0x36, 0x0d, + 0x58, 0x87, 0xff, 0x87, 0x87, 0xff, 0x6f, 0x36, 0x0d, 0x00, 0x24, 0xff, + 0x1c, 0x1c, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x32, 0xff, 0x00, 0x32, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x45, 0xab, 0x00, 0x3a, 0xcf, 0x00, 0x00, 0x00, + /* ch = '$' */ + 0x00, 0x00, 0x1a, 0xcf, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x6b, 0xff, + 0x9c, 0x25, 0x00, 0x00, 0x32, 0xff, 0x94, 0xff, 0xab, 0xf7, 0x84, 0x00, + 0xb1, 0x82, 0x1c, 0xff, 0x32, 0x2a, 0x39, 0x00, 0xb1, 0xb7, 0x1f, 0xff, + 0x32, 0x00, 0x00, 0x00, 0x32, 0xf7, 0xef, 0xff, 0x32, 0x00, 0x00, 0x00, + 0x00, 0x13, 0x6b, 0xff, 0xf7, 0x8d, 0x13, 0x00, 0x00, 0x00, 0x1c, 0xff, + 0x58, 0xd4, 0xdb, 0x04, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x2c, 0xff, 0x2a, + 0x73, 0x10, 0x1c, 0xff, 0x32, 0x3f, 0xff, 0x1a, 0xdb, 0xdb, 0x5f, 0xff, + 0x99, 0xf7, 0x73, 0x00, 0x04, 0x3f, 0x95, 0xff, 0x9c, 0x31, 0x00, 0x00, + 0x00, 0x00, 0x1a, 0xcf, 0x2d, 0x00, 0x00, 0x00, + /* ch = '%' */ + 0x00, 0x22, 0x36, 0x13, 0x00, 0x00, 0x08, 0x15, 0x04, 0x39, 0xf7, 0x95, + 0xf7, 0x17, 0x00, 0x7c, 0xb7, 0x00, 0xa0, 0x82, 0x04, 0xff, 0x4d, 0x24, + 0xff, 0x2a, 0x00, 0xa0, 0x82, 0x04, 0xff, 0x4d, 0xa0, 0x90, 0x00, 0x00, + 0x2f, 0xff, 0xdd, 0xdb, 0x3f, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x0f, 0x15, + 0x0c, 0xc8, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xf7, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xe5, 0x50, 0x22, 0x36, 0x22, 0x00, + 0x00, 0x00, 0x5f, 0xdb, 0x2c, 0xff, 0x73, 0xff, 0x2f, 0x00, 0x17, 0xf7, + 0x3b, 0x77, 0xa0, 0x00, 0x90, 0x77, 0x00, 0x7c, 0xb7, 0x00, 0x6b, 0xb7, + 0x00, 0xb7, 0x6b, 0x24, 0xff, 0x2a, 0x00, 0x17, 0xdb, 0xdd, 0xdb, 0x1c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x15, 0x04, 0x00, + /* ch = '&' */ + 0x00, 0x00, 0x08, 0x25, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xdb, + 0xe5, 0xef, 0xd4, 0x0d, 0x00, 0x00, 0x00, 0x6b, 0xf7, 0x10, 0x1c, 0xff, + 0x44, 0x00, 0x00, 0x00, 0x77, 0xe5, 0x04, 0x04, 0xff, 0x4d, 0x00, 0x00, + 0x00, 0x2a, 0xff, 0x3b, 0x50, 0xf7, 0x17, 0x00, 0x00, 0x00, 0x00, 0x82, + 0xff, 0xf7, 0x32, 0x00, 0x00, 0x00, 0x00, 0x32, 0xf7, 0xff, 0xc8, 0x04, + 0x00, 0x0c, 0x00, 0x1c, 0xf7, 0x7c, 0x1f, 0xf7, 0x77, 0x04, 0xe5, 0x2f, + 0x5f, 0xff, 0x17, 0x00, 0x4d, 0xff, 0x94, 0xf7, 0x1c, 0x7c, 0xff, 0x04, + 0x00, 0x00, 0x88, 0xff, 0x54, 0x00, 0x48, 0xff, 0x54, 0x00, 0x37, 0xf7, + 0xf7, 0xb1, 0x04, 0x04, 0x84, 0xff, 0xff, 0xf7, 0x50, 0x2f, 0xf7, 0x33, + 0x00, 0x00, 0x0c, 0x15, 0x04, 0x00, 0x00, 0x0f, 0x00, + /* ch = ''' */ + 0x0d, 0xef, 0x66, 0x1a, 0xff, 0x7c, 0x14, 0xff, 0x44, 0x32, 0xff, 0x14, + 0x24, 0x4e, 0x00, + /* ch = '(' */ + 0x00, 0x28, 0xd4, 0x2c, 0x4d, 0xff, 0x77, 0x0f, 0xff, 0x50, 0x00, 0x00, + 0xa0, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xdb, 0x04, 0x00, 0x00, + 0xff, 0x7c, 0x00, 0x00, 0x32, 0xff, 0x8a, 0x08, 0x00, 0x26, 0xef, 0x44, + 0x00, 0x00, 0x08, 0x04, + /* ch = ')' */ + 0x8a, 0x66, 0x04, 0x00, 0x37, 0xf7, 0xb1, 0x10, 0x00, 0x1f, 0xf7, 0xb1, + 0x00, 0x00, 0x32, 0xff, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x3b, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, + 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x24, 0xff, + 0x00, 0x10, 0xdb, 0xb1, 0x28, 0xdb, 0xd4, 0x10, 0xcf, 0x8d, 0x08, 0x00, + 0x0c, 0x00, 0x00, 0x00, + /* ch = '*' */ + 0x00, 0x00, 0x00, 0x1e, 0x36, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x44, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x17, 0x37, 0x04, 0x32, 0xff, 0x04, + 0x08, 0x2a, 0x00, 0x4a, 0xf7, 0xe5, 0x6f, 0xff, 0x66, 0xf7, 0xdd, 0x11, + 0x00, 0x04, 0x25, 0xa7, 0xff, 0x74, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x32, + 0xff, 0x97, 0xdb, 0x10, 0x00, 0x00, 0x00, 0x1f, 0xf7, 0x5f, 0x04, 0xc8, + 0xb1, 0x04, 0x00, 0x00, 0x51, 0xb7, 0x04, 0x00, 0x2a, 0xef, 0x22, 0x00, + /* ch = '+' */ + 0x00, 0x00, 0x00, 0x16, 0x36, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, + 0x00, 0x00, 0x00, 0x1e, 0x36, 0x36, 0x62, 0xff, 0x4a, 0x36, 0x36, 0x0d, + 0x45, 0xcf, 0xcf, 0xdd, 0xff, 0xd4, 0xcf, 0xcf, 0x1a, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x15, 0x04, 0x00, 0x00, 0x00, + /* ch = ',' */ + 0x00, 0x9c, 0xbd, 0x10, 0x0d, 0xef, 0xff, 0x4d, 0x00, 0x26, 0xff, 0x32, + 0x00, 0x5f, 0xb1, 0x00, 0x1e, 0xd4, 0x10, 0x00, + /* ch = '-' */ + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xb7, + /* ch = '.' */ + 0x00, 0x8d, 0xbd, 0x17, 0x04, 0xf7, 0xff, 0x27, 0x00, 0x0c, 0x0f, 0x00, + /* ch = '/' */ + 0x00, 0xa0, 0x5c, 0x22, 0xff, 0x44, 0x8a, 0xe5, 0x04, 0xff, 0x50, 0x00, + 0xf7, 0x0d, 0x00, 0x5f, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + /* ch = '0' */ + 0x00, 0x00, 0x00, 0x0f, 0x15, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, + 0xff, 0xdd, 0xf7, 0x2c, 0x00, 0x00, 0x00, 0x44, 0xff, 0x26, 0x00, 0x64, + 0xf7, 0x17, 0x00, 0x00, 0xcf, 0x70, 0x00, 0x00, 0x21, 0xff, 0x5f, 0x00, + 0x1f, 0xff, 0x2a, 0x00, 0x10, 0xdb, 0xf7, 0xbd, 0x00, 0x32, 0xff, 0x1c, + 0x04, 0xb1, 0xb1, 0x54, 0xff, 0x00, 0x49, 0xff, 0x17, 0x50, 0xf7, 0x1f, + 0x3b, 0xff, 0x11, 0x32, 0xff, 0x50, 0xff, 0x32, 0x00, 0x50, 0xff, 0x00, + 0x1f, 0xff, 0xff, 0x50, 0x00, 0x00, 0x6b, 0xcf, 0x00, 0x00, 0xc8, 0xd9, + 0x00, 0x00, 0x04, 0xcf, 0x70, 0x00, 0x00, 0x3b, 0xff, 0x54, 0x04, 0x5f, + 0xf7, 0x1c, 0x00, 0x00, 0x00, 0x5a, 0xff, 0xff, 0xef, 0x2c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x15, 0x04, 0x00, 0x00, 0x00, + /* ch = '1' */ + 0x00, 0x00, 0x00, 0x15, 0x08, 0x00, 0x31, 0xd4, 0xff, 0x32, 0x60, 0xc4, + 0x78, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, + 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, + 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x1c, + 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x1c, 0xff, 0x32, + /* ch = '2' */ + 0x00, 0x00, 0x12, 0x15, 0x0f, 0x00, 0x00, 0x19, 0xbb, 0xf7, 0xdd, 0xff, + 0x77, 0x00, 0xa4, 0xb1, 0x08, 0x00, 0x3b, 0xff, 0x44, 0x04, 0x08, 0x00, + 0x00, 0x00, 0xbd, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x90, 0x00, + 0x00, 0x00, 0x00, 0x32, 0xff, 0x39, 0x00, 0x00, 0x00, 0x21, 0xf7, 0x7c, + 0x00, 0x00, 0x00, 0x26, 0xf7, 0x7c, 0x04, 0x00, 0x00, 0x1f, 0xf7, 0x7c, + 0x00, 0x00, 0x00, 0x10, 0xdb, 0xa0, 0x04, 0x00, 0x00, 0x00, 0x6b, 0xec, + 0x1f, 0x15, 0x15, 0x15, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb7, + /* ch = '3' */ + 0x00, 0x00, 0x00, 0x15, 0x15, 0x08, 0x00, 0x00, 0x00, 0x26, 0xd4, 0xff, + 0xef, 0xf7, 0x3b, 0x00, 0x00, 0x24, 0x5a, 0x04, 0x04, 0x6f, 0xff, 0x17, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3b, 0xff, 0x22, 0x00, 0x00, 0x0d, 0x36, 0x66, 0xf7, 0x4d, 0x00, + 0x00, 0x00, 0x14, 0x74, 0xc4, 0xf7, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x37, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x6b, + 0x00, 0x04, 0x08, 0x00, 0x00, 0x0d, 0xff, 0x6b, 0x04, 0x7c, 0x8a, 0x08, + 0x08, 0x8a, 0xff, 0x24, 0x00, 0x35, 0xef, 0xff, 0xff, 0xef, 0x35, 0x00, + 0x00, 0x00, 0x00, 0x15, 0x15, 0x00, 0x00, 0x00, + /* ch = '4' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1f, 0xf7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xb1, 0xff, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xdb, 0xff, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0x1f, 0xf7, 0x2a, 0xff, 0x7c, 0x00, 0x00, 0x00, 0x04, 0xb1, + 0x6b, 0x00, 0xff, 0x7c, 0x00, 0x00, 0x00, 0x50, 0xdb, 0x0d, 0x00, 0xff, + 0x7c, 0x00, 0x00, 0x1f, 0xf7, 0x42, 0x15, 0x15, 0xff, 0x88, 0x15, 0x04, + 0x45, 0xcf, 0xcf, 0xcf, 0xcf, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, 0x00, 0x00, + /* ch = '5' */ + 0x00, 0x0c, 0x15, 0x15, 0x15, 0x15, 0x15, 0x0f, 0x00, 0x50, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7c, 0x00, 0x50, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x77, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, 0x12, + 0x15, 0x0f, 0x00, 0x00, 0x00, 0x90, 0xff, 0xef, 0xd4, 0xff, 0x94, 0x04, + 0x00, 0x6d, 0x73, 0x04, 0x00, 0x32, 0xff, 0x5f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x90, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, + 0x00, 0x10, 0x16, 0x00, 0x00, 0x00, 0xa7, 0xcf, 0x0a, 0xe5, 0xb1, 0x13, + 0x00, 0x3f, 0xff, 0x50, 0x00, 0x21, 0xcb, 0xff, 0xff, 0xff, 0x66, 0x04, + 0x00, 0x00, 0x00, 0x0f, 0x15, 0x08, 0x00, 0x00, + /* ch = '6' */ + 0x00, 0x00, 0x00, 0x08, 0x2a, 0x25, 0x08, 0x00, 0x00, 0x00, 0x3b, 0xf7, + 0xe5, 0xe5, 0xf7, 0x36, 0x00, 0x1c, 0xff, 0x5f, 0x00, 0x00, 0x48, 0x08, + 0x00, 0x7c, 0xe5, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x6b, 0x08, + 0x15, 0x0f, 0x00, 0x00, 0x04, 0xff, 0xb1, 0xf7, 0xf7, 0xff, 0x84, 0x04, + 0x1c, 0xff, 0xf7, 0x28, 0x00, 0x35, 0xff, 0x44, 0x1c, 0xff, 0x54, 0x00, + 0x00, 0x00, 0xa0, 0xb1, 0x00, 0xff, 0x5f, 0x00, 0x00, 0x00, 0x7c, 0xb7, + 0x00, 0xa0, 0xc8, 0x00, 0x00, 0x00, 0xa7, 0xa0, 0x00, 0x3b, 0xff, 0x54, + 0x00, 0x35, 0xff, 0x3b, 0x00, 0x00, 0x50, 0xf7, 0xff, 0xff, 0x66, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x15, 0x08, 0x00, 0x00, + /* ch = '7' */ + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xff, 0x39, 0x00, 0x00, 0x00, + 0x00, 0x8a, 0xe5, 0x04, 0x00, 0x00, 0x00, 0x17, 0xff, 0x5a, 0x00, 0x00, + 0x00, 0x00, 0x5a, 0xff, 0x17, 0x00, 0x00, 0x00, 0x04, 0xe5, 0x90, 0x00, + 0x00, 0x00, 0x00, 0x2c, 0xff, 0x39, 0x00, 0x00, 0x00, 0x00, 0x8a, 0xf7, + 0x0d, 0x00, 0x00, 0x00, 0x0d, 0xf7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x39, + 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x90, 0xf7, 0x04, 0x00, 0x00, 0x00, + /* ch = '8' */ + 0x00, 0x00, 0x00, 0x20, 0x36, 0x18, 0x00, 0x00, 0x00, 0x04, 0xa9, 0xf7, + 0xcf, 0xff, 0x99, 0x04, 0x00, 0x5a, 0xf7, 0x13, 0x00, 0x32, 0xff, 0x40, + 0x00, 0x7c, 0xbd, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x48, 0xff, 0x32, + 0x00, 0x3b, 0xff, 0x2a, 0x00, 0x04, 0x94, 0xff, 0x9e, 0xf7, 0x44, 0x00, + 0x00, 0x04, 0x84, 0xef, 0xb3, 0xff, 0x5a, 0x00, 0x00, 0x7c, 0xdb, 0x10, + 0x00, 0x3b, 0xff, 0x4d, 0x1a, 0xff, 0x48, 0x00, 0x00, 0x00, 0xa7, 0xbd, + 0x1c, 0xff, 0x48, 0x00, 0x00, 0x00, 0x90, 0xcf, 0x00, 0xc8, 0xdb, 0x1b, + 0x00, 0x37, 0xff, 0x5f, 0x00, 0x19, 0xbb, 0xff, 0xff, 0xff, 0x73, 0x04, + 0x00, 0x00, 0x00, 0x0f, 0x15, 0x08, 0x00, 0x00, + /* ch = '9' */ + 0x00, 0x00, 0x00, 0x1a, 0x2a, 0x0c, 0x00, 0x00, 0x00, 0x10, 0xbb, 0xf7, + 0xdd, 0xff, 0x44, 0x00, 0x00, 0x7c, 0xe5, 0x13, 0x00, 0x54, 0xff, 0x22, + 0x00, 0xf7, 0x5f, 0x00, 0x00, 0x04, 0xf7, 0x6b, 0x11, 0xff, 0x50, 0x00, + 0x00, 0x00, 0xb7, 0xb1, 0x00, 0xe5, 0x7c, 0x00, 0x00, 0x04, 0xcf, 0xb7, + 0x00, 0x4d, 0xff, 0x47, 0x1a, 0x99, 0xff, 0xb7, 0x00, 0x00, 0x50, 0xdd, + 0xe5, 0x7f, 0xaf, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xff, 0x39, 0x00, 0x32, 0x50, 0x04, + 0x16, 0xc4, 0xc8, 0x04, 0x00, 0x44, 0xf7, 0xff, 0xff, 0xbb, 0x13, 0x00, + 0x00, 0x00, 0x04, 0x15, 0x0f, 0x00, 0x00, 0x00, + /* ch = ':' */ + 0x00, 0x48, 0x67, 0x04, 0x0a, 0xff, 0xff, 0x2f, 0x00, 0x22, 0x30, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x8d, 0xbd, 0x17, 0x04, 0xf7, 0xff, 0x27, 0x00, 0x0c, 0x0f, 0x00, + /* ch = ';' */ + 0x00, 0x48, 0x67, 0x04, 0x0a, 0xff, 0xff, 0x2f, 0x00, 0x22, 0x30, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x9c, 0xbd, 0x10, 0x0d, 0xef, 0xff, 0x4d, 0x00, 0x26, 0xff, 0x32, + 0x00, 0x5f, 0xb1, 0x00, 0x1e, 0xd4, 0x10, 0x00, + /* ch = '<' */ + 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x04, 0x48, 0xef, 0x1c, + 0x04, 0x37, 0xe5, 0xef, 0x3f, 0x04, 0xd4, 0xef, 0x48, 0x04, 0x00, 0x00, + 0x50, 0x08, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd4, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x5a, 0xf7, 0xbb, 0x1b, 0x00, 0x00, + 0x00, 0x13, 0x94, 0xff, 0x8d, 0x10, 0x00, 0x00, 0x00, 0x28, 0xd4, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, + /* ch = '=' */ + 0x45, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0x1a, 0x0c, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x04, + 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1c, + /* ch = '>' */ + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x50, 0xbb, 0x28, 0x00, 0x00, 0x13, 0x73, + 0xff, 0xb3, 0x1e, 0x00, 0x00, 0x13, 0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x50, 0x00, + 0x00, 0x37, 0xef, 0xd4, 0x26, 0xbb, 0xf7, 0x50, 0x04, 0x7c, 0x94, 0x13, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, + /* ch = '?' */ + 0x00, 0x04, 0x66, 0xe5, 0xff, 0xdd, 0x35, 0x00, 0x04, 0xb1, 0xf7, 0x3f, + 0x20, 0x99, 0xff, 0x2f, 0x00, 0x5a, 0x2a, 0x00, 0x00, 0x0d, 0xff, 0x90, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xff, 0xb1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x48, 0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x8a, 0x04, + 0x00, 0x00, 0x00, 0x0d, 0xe5, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, + 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x74, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, + 0xcf, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0xff, 0x84, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x15, 0x04, 0x00, 0x00, + /* ch = '@' */ + 0x00, 0x00, 0x00, 0x18, 0x36, 0x2a, 0x08, 0x00, 0x00, 0x00, 0x08, 0xa2, + 0xef, 0x82, 0xcb, 0xdb, 0x1f, 0x00, 0x00, 0x90, 0xb1, 0x08, 0x00, 0x00, + 0x7c, 0xc8, 0x00, 0x2a, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x24, + 0x5f, 0xb7, 0x00, 0x13, 0x8d, 0xf7, 0xff, 0xff, 0x32, 0x90, 0x7c, 0x00, + 0xc8, 0xb1, 0x0c, 0x00, 0xff, 0x32, 0xb7, 0x7c, 0x1c, 0xff, 0x32, 0x00, + 0x14, 0xff, 0x32, 0x7c, 0x82, 0x0d, 0xf7, 0x7c, 0x08, 0x64, 0xff, 0x32, + 0x50, 0xe5, 0x04, 0x2c, 0xe5, 0xff, 0xb3, 0xcf, 0x2d, 0x17, 0xff, 0x4d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf7, 0x3f, 0x00, 0x00, + 0x13, 0x19, 0x00, 0x00, 0x00, 0x40, 0xef, 0xef, 0xd4, 0xff, 0x5e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x15, 0x15, 0x04, 0x00, 0x00, + /* ch = 'A' */ + 0x00, 0x00, 0x00, 0x0d, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x44, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xff, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xff, 0xff, 0x48, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x48, 0xe5, 0x7c, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, + 0x6b, 0x2c, 0xff, 0x22, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x2a, 0x00, 0xe5, + 0x70, 0x00, 0x00, 0x00, 0x50, 0xec, 0x15, 0x15, 0x6d, 0xe5, 0x04, 0x00, + 0x00, 0xc8, 0xe5, 0xcf, 0xcf, 0xd4, 0xff, 0x39, 0x00, 0x22, 0xff, 0x32, + 0x00, 0x00, 0x00, 0xc8, 0xa0, 0x00, 0x5a, 0xf7, 0x04, 0x00, 0x00, 0x00, + 0x5a, 0xff, 0x17, 0xcf, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x17, 0xff, 0x5a, + /* ch = 'B' */ + 0x0c, 0x15, 0x15, 0x15, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x50, 0xff, 0xd4, + 0xcf, 0xef, 0xff, 0x94, 0x04, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x35, + 0xff, 0x5a, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xbd, 0xb1, 0x00, + 0x50, 0xff, 0x1c, 0x00, 0x00, 0x13, 0xf7, 0x66, 0x00, 0x50, 0xff, 0x87, + 0x74, 0x82, 0xef, 0xa9, 0x04, 0x00, 0x50, 0xff, 0x4a, 0x36, 0x74, 0xd4, + 0xcb, 0x19, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x04, 0xb7, 0xc8, 0x00, + 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x50, 0xff, 0x1c, + 0x00, 0x00, 0x00, 0x5f, 0xff, 0x1a, 0x50, 0xff, 0x28, 0x15, 0x15, 0x3f, + 0xff, 0x90, 0x00, 0x50, 0xff, 0xff, 0xff, 0xff, 0xe5, 0x66, 0x04, 0x00, + /* ch = 'C' */ + 0x00, 0x00, 0x0c, 0x25, 0x1a, 0x04, 0x00, 0x00, 0x04, 0x66, 0xff, 0xcf, + 0xe5, 0xef, 0x2f, 0x00, 0x6b, 0xf7, 0x26, 0x00, 0x04, 0x7c, 0xff, 0x1f, + 0xff, 0x5f, 0x00, 0x00, 0x00, 0x14, 0x37, 0x00, 0xff, 0x1f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf7, 0x82, 0x00, 0x00, 0x00, 0x04, 0x0f, 0x00, 0x50, 0xff, 0x5f, 0x04, + 0x08, 0x8a, 0xef, 0x17, 0x00, 0x50, 0xf7, 0xff, 0xff, 0xcb, 0x21, 0x00, + 0x00, 0x00, 0x04, 0x15, 0x12, 0x00, 0x00, 0x00, + /* ch = 'D' */ + 0x08, 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0xd4, + 0xd4, 0xff, 0xef, 0x35, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x08, 0x8a, + 0xff, 0x2f, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x04, 0xdb, 0xa7, 0x00, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x5f, 0xff, 0x14, 0x32, 0xff, 0x1c, + 0x00, 0x00, 0x00, 0x35, 0xff, 0x24, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x32, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x35, 0xff, 0x1c, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x5f, 0xf7, 0x04, 0x32, 0xff, 0x1c, + 0x00, 0x00, 0x10, 0xe5, 0x7c, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x1e, 0xb1, + 0xdb, 0x10, 0x00, 0x32, 0xff, 0xff, 0xff, 0xf7, 0x8d, 0x13, 0x00, 0x00, + /* ch = 'E' */ + 0x08, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x32, 0xff, 0xdd, 0xcf, + 0xcf, 0xcf, 0xcf, 0xcf, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x62, 0x36, 0x36, 0x36, 0x36, 0x00, + 0x32, 0xff, 0xdd, 0xcf, 0xcf, 0xcf, 0xcf, 0x00, 0x32, 0xff, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x3e, 0x15, + 0x15, 0x15, 0x15, 0x12, 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb7, + /* ch = 'F' */ + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x12, 0xff, 0xef, 0xcf, 0xcf, 0xcf, + 0xcf, 0x95, 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xc8, 0x74, 0x74, 0x74, 0x58, 0x00, 0xff, 0xa5, 0x36, 0x36, 0x36, 0x2d, + 0x00, 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = 'G' */ + 0x00, 0x00, 0x00, 0x0f, 0x2a, 0x20, 0x08, 0x00, 0x00, 0x00, 0x04, 0x84, + 0xff, 0xd4, 0xef, 0xef, 0x2f, 0x00, 0x00, 0x7c, 0xf7, 0x28, 0x00, 0x04, + 0x7c, 0xf7, 0x11, 0x22, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x0d, 0x21, 0x00, + 0x4d, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xe5, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xbd, 0x00, 0x00, 0x16, 0x36, + 0x36, 0x36, 0x16, 0x7c, 0xff, 0x00, 0x00, 0x2d, 0xcf, 0xd4, 0xff, 0x32, + 0x4d, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x17, 0xff, 0x5f, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x6b, 0xff, 0x3f, 0x04, 0x04, + 0x43, 0xff, 0x32, 0x00, 0x00, 0x5b, 0xf7, 0xff, 0xff, 0xe5, 0x48, 0x04, + 0x00, 0x00, 0x00, 0x04, 0x15, 0x12, 0x00, 0x00, 0x00, + /* ch = 'H' */ + 0x08, 0x15, 0x08, 0x00, 0x00, 0x00, 0x0f, 0x15, 0x32, 0xff, 0x32, 0x00, + 0x00, 0x00, 0x7c, 0xff, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xff, + 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xff, 0x32, 0xff, 0x32, 0x00, + 0x00, 0x00, 0x7c, 0xff, 0x32, 0xff, 0x62, 0x36, 0x36, 0x36, 0xa5, 0xff, + 0x32, 0xff, 0x9c, 0x74, 0x74, 0x74, 0xc8, 0xff, 0x32, 0xff, 0x32, 0x00, + 0x00, 0x00, 0x7c, 0xff, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xff, + 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xff, 0x32, 0xff, 0x32, 0x00, + 0x00, 0x00, 0x7c, 0xff, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xff, + /* ch = 'I' */ + 0x0f, 0x15, 0x15, 0x15, 0x15, 0x15, 0x04, 0x67, 0xcf, 0xef, 0xff, 0xcf, + 0xcf, 0x1a, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7c, 0xff, 0x00, 0x00, 0x00, 0xb7, 0xff, 0xff, 0xff, 0xff, 0xff, 0x32, + /* ch = 'J' */ + 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x04, 0x1a, 0xcf, 0xcf, 0xff, 0xe5, + 0xcf, 0x1a, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x14, 0xff, + 0x50, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x44, 0x00, 0x00, 0x21, 0x00, + 0x7c, 0xff, 0x17, 0x00, 0x00, 0xff, 0xff, 0xf7, 0x3b, 0x00, 0x00, 0x00, + 0x0f, 0x15, 0x08, 0x00, 0x00, 0x00, 0x00, + /* ch = 'K' */ + 0x0c, 0x15, 0x08, 0x00, 0x00, 0x00, 0x21, 0x15, 0x04, 0x50, 0xff, 0x1c, + 0x00, 0x00, 0x32, 0xf7, 0x50, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x1f, 0xf7, + 0x7c, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x10, 0xdb, 0xb1, 0x04, 0x00, 0x00, + 0x50, 0xff, 0x26, 0xd4, 0xdb, 0x10, 0x00, 0x00, 0x00, 0x50, 0xff, 0xdb, + 0xff, 0x13, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0xd4, 0xff, 0x5f, 0x00, + 0x00, 0x00, 0x00, 0x50, 0xff, 0x1f, 0x6b, 0xff, 0x2a, 0x00, 0x00, 0x00, + 0x50, 0xff, 0x1c, 0x04, 0xc8, 0xdb, 0x10, 0x00, 0x00, 0x50, 0xff, 0x1c, + 0x00, 0x1f, 0xff, 0x7c, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x54, + 0xff, 0x3b, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x04, 0xb1, 0xf7, 0x1f, + /* ch = 'L' */ + 0x04, 0x15, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x50, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x50, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x50, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x50, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb7, + /* ch = 'M' */ + 0x0f, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x08, 0x7c, 0xf7, 0x17, + 0x00, 0x00, 0x00, 0x39, 0xff, 0x32, 0x7c, 0xff, 0x6b, 0x00, 0x00, 0x04, + 0xc8, 0xff, 0x32, 0x7c, 0xff, 0xf7, 0x17, 0x00, 0x3b, 0xff, 0xff, 0x32, + 0x7c, 0xbd, 0xe5, 0x6b, 0x04, 0xdb, 0x90, 0xff, 0x32, 0x7c, 0xb7, 0x48, + 0xf7, 0x5f, 0xf7, 0x24, 0xff, 0x32, 0x7c, 0xb7, 0x04, 0xdb, 0xff, 0x50, + 0x1c, 0xff, 0x32, 0x7c, 0xb7, 0x00, 0x44, 0xdb, 0x04, 0x1c, 0xff, 0x32, + 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x7c, 0xb7, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x32, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, + /* ch = 'N' */ + 0x0c, 0x15, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x15, 0x04, 0x50, 0xff, 0x5f, + 0x00, 0x00, 0x00, 0x50, 0xff, 0x00, 0x50, 0xff, 0xf7, 0x17, 0x00, 0x00, + 0x50, 0xff, 0x00, 0x50, 0xff, 0xff, 0x7c, 0x00, 0x00, 0x50, 0xff, 0x00, + 0x50, 0xff, 0x7c, 0xff, 0x24, 0x00, 0x50, 0xff, 0x00, 0x50, 0xff, 0x1f, + 0xdb, 0xa0, 0x00, 0x50, 0xff, 0x00, 0x50, 0xff, 0x1c, 0x3b, 0xff, 0x3b, + 0x50, 0xff, 0x00, 0x50, 0xff, 0x1c, 0x00, 0xa0, 0xdb, 0x54, 0xff, 0x00, + 0x50, 0xff, 0x1c, 0x00, 0x24, 0xff, 0xe5, 0xff, 0x00, 0x50, 0xff, 0x1c, + 0x00, 0x00, 0x7c, 0xff, 0xff, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x17, + 0xf7, 0xff, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x5f, 0xff, 0x00, + /* ch = 'O' */ + 0x00, 0x00, 0x00, 0x1a, 0x36, 0x12, 0x00, 0x00, 0x00, 0x00, 0x13, 0xcb, + 0xff, 0xe5, 0xff, 0x94, 0x04, 0x00, 0x04, 0xb7, 0xdb, 0x13, 0x00, 0x35, + 0xff, 0x77, 0x00, 0x39, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x70, 0xff, 0x0d, + 0x77, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x2f, 0xff, 0x2f, 0xa0, 0xb7, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x4d, 0xb7, 0xb7, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0x50, 0x90, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x44, + 0x6b, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x32, 0xff, 0x2a, 0x2c, 0xff, 0x48, + 0x00, 0x00, 0x00, 0x7c, 0xf7, 0x04, 0x00, 0x90, 0xf7, 0x37, 0x0f, 0x5a, + 0xff, 0x50, 0x00, 0x00, 0x04, 0x8d, 0xff, 0xff, 0xf7, 0x5a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x15, 0x04, 0x00, 0x00, 0x00, + /* ch = 'P' */ + 0x08, 0x15, 0x15, 0x15, 0x15, 0x12, 0x00, 0x00, 0x00, 0x32, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xd4, 0x19, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x1e, + 0xdb, 0xc8, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x54, 0xff, 0x1c, + 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x54, 0xff, 0x1a, 0x32, 0xff, 0x32, + 0x00, 0x00, 0x26, 0xe5, 0xa0, 0x00, 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x8d, 0x10, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = 'Q' */ + 0x00, 0x00, 0x00, 0x1a, 0x36, 0x12, 0x00, 0x00, 0x00, 0x00, 0x13, 0xcb, + 0xff, 0xd4, 0xff, 0x94, 0x04, 0x00, 0x04, 0xb7, 0xc8, 0x13, 0x00, 0x28, + 0xf7, 0x6b, 0x00, 0x39, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x64, 0xff, 0x0d, + 0x77, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x2a, 0xff, 0x2f, 0xa0, 0xb7, 0x00, + 0x00, 0x00, 0x00, 0x1a, 0xff, 0x4d, 0xb7, 0xb7, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x50, 0x82, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xff, 0x44, + 0x5f, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x2a, 0xff, 0x2f, 0x2a, 0xff, 0x44, + 0x00, 0x00, 0x00, 0x70, 0xf7, 0x0d, 0x00, 0x90, 0xf7, 0x2b, 0x04, 0x3f, + 0xff, 0x50, 0x00, 0x00, 0x04, 0x8d, 0xff, 0xff, 0xf7, 0x50, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x2a, 0xff, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0d, 0xdb, 0xc4, 0x74, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x5b, + 0x74, 0x74, 0x00, + /* ch = 'R' */ + 0x08, 0x15, 0x15, 0x15, 0x15, 0x0f, 0x00, 0x00, 0x00, 0x32, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xbb, 0x10, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x28, + 0xf7, 0x8a, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x82, 0xff, 0x00, + 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x82, 0xf7, 0x00, 0x32, 0xff, 0x32, + 0x00, 0x04, 0x31, 0xf7, 0x6b, 0x00, 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x8d, 0x04, 0x00, 0x32, 0xff, 0x32, 0x00, 0x70, 0xf7, 0x0d, 0x00, 0x00, + 0x32, 0xff, 0x32, 0x00, 0x17, 0xff, 0x5a, 0x00, 0x00, 0x32, 0xff, 0x32, + 0x00, 0x00, 0x70, 0xf7, 0x10, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x17, + 0xff, 0x5f, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x70, 0xf7, 0x17, + /* ch = 'S' */ + 0x00, 0x00, 0x12, 0x15, 0x12, 0x00, 0x00, 0x00, 0x10, 0xbb, 0xf7, 0xcf, + 0xf7, 0xd4, 0x21, 0x00, 0xa0, 0xc8, 0x10, 0x00, 0x08, 0xb1, 0x54, 0x00, + 0xff, 0x7c, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0xb7, 0xe5, 0x13, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1f, 0xef, 0xf7, 0x66, 0x16, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x50, 0xe5, 0xff, 0x7e, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x37, 0xf7, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1a, + 0x39, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1a, 0xff, 0x77, 0x0c, 0x00, + 0x28, 0xef, 0xa0, 0x00, 0x48, 0xe5, 0xff, 0xff, 0xff, 0x94, 0x10, 0x00, + 0x00, 0x00, 0x12, 0x15, 0x0c, 0x00, 0x00, 0x00, + /* ch = 'T' */ + 0x12, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x08, 0xb7, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, + /* ch = 'U' */ + 0x0c, 0x15, 0x08, 0x00, 0x00, 0x00, 0x08, 0x15, 0x04, 0x50, 0xff, 0x1c, + 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x1c, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, + 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x50, 0xff, 0x1c, + 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x1c, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, + 0x4d, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x2f, 0xff, 0x2c, + 0x00, 0x00, 0x00, 0x5f, 0xff, 0x0d, 0x04, 0xdb, 0xc8, 0x13, 0x00, 0x28, + 0xf7, 0x7c, 0x00, 0x00, 0x19, 0xcb, 0xff, 0xf7, 0xff, 0x7e, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x0f, 0x15, 0x0c, 0x00, 0x00, 0x00, + /* ch = 'V' */ + 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x0f, 0x70, 0xf7, 0x04, + 0x00, 0x00, 0x00, 0x22, 0xff, 0x39, 0x2c, 0xff, 0x32, 0x00, 0x00, 0x00, + 0x50, 0xf7, 0x0d, 0x04, 0xe5, 0x7c, 0x00, 0x00, 0x00, 0xb7, 0x8a, 0x00, + 0x00, 0x70, 0xf7, 0x04, 0x00, 0x17, 0xff, 0x39, 0x00, 0x00, 0x2c, 0xff, + 0x32, 0x00, 0x48, 0xf7, 0x0d, 0x00, 0x00, 0x00, 0xe5, 0x7c, 0x00, 0xa0, + 0x8a, 0x00, 0x00, 0x00, 0x00, 0x6b, 0xf7, 0x17, 0xff, 0x39, 0x00, 0x00, + 0x00, 0x00, 0x2a, 0xff, 0x90, 0xf7, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe5, 0xff, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0xff, 0x39, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0xf7, 0x0d, 0x00, 0x00, 0x00, + /* ch = 'W' */ + 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x12, 0xcf, 0x6b, 0x00, + 0x00, 0x2a, 0x00, 0x00, 0x82, 0x7c, 0x90, 0x90, 0x00, 0x0d, 0xff, 0x14, + 0x00, 0xb7, 0x50, 0x6b, 0xcf, 0x00, 0x32, 0xff, 0x3b, 0x00, 0xff, 0x32, + 0x44, 0xff, 0x0d, 0x6b, 0xff, 0x7c, 0x1a, 0xff, 0x1f, 0x2a, 0xff, 0x24, + 0xcf, 0xcf, 0xe5, 0x24, 0xff, 0x04, 0x14, 0xff, 0x5f, 0xff, 0x39, 0xff, + 0x54, 0xbd, 0x00, 0x00, 0xf7, 0xcf, 0xb7, 0x04, 0xf7, 0xe5, 0x90, 0x00, + 0x00, 0xb1, 0xff, 0x5f, 0x00, 0xa0, 0xff, 0x5f, 0x00, 0x00, 0x77, 0xff, + 0x2f, 0x00, 0x50, 0xff, 0x3b, 0x00, 0x00, 0x4d, 0xff, 0x0d, 0x00, 0x24, + 0xff, 0x2a, 0x00, 0x00, 0x2f, 0xa0, 0x00, 0x00, 0x00, 0xf7, 0x14, 0x00, + /* ch = 'X' */ + 0x0c, 0x15, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x15, 0x00, 0x1c, 0xff, 0x5f, + 0x00, 0x00, 0x04, 0xc8, 0x8a, 0x00, 0x00, 0x6b, 0xf7, 0x17, 0x00, 0x44, + 0xff, 0x1c, 0x00, 0x00, 0x10, 0xf7, 0x7c, 0x0d, 0xe5, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0x50, 0xff, 0x97, 0xff, 0x17, 0x00, 0x00, 0x00, 0x00, 0x04, + 0xdb, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0xff, 0x3f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0xdb, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x90, 0xe5, 0x32, 0xff, 0x50, 0x00, 0x00, 0x00, 0x2a, 0xff, + 0x44, 0x00, 0x90, 0xf7, 0x10, 0x00, 0x00, 0xa7, 0xdb, 0x04, 0x00, 0x1c, + 0xff, 0x6b, 0x00, 0x35, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x6b, 0xff, 0x1f, + /* ch = 'Y' */ + 0x12, 0x15, 0x00, 0x00, 0x00, 0x00, 0x04, 0x15, 0x0c, 0x44, 0xff, 0x2c, + 0x00, 0x00, 0x00, 0x48, 0xff, 0x22, 0x04, 0xdb, 0xa7, 0x00, 0x00, 0x04, + 0xe5, 0x8a, 0x00, 0x00, 0x44, 0xff, 0x32, 0x00, 0x39, 0xff, 0x24, 0x00, + 0x00, 0x04, 0xdb, 0xb7, 0x00, 0xc8, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x44, + 0xff, 0x70, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x04, 0xc8, 0xff, 0xb7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x3b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, + /* ch = 'Z' */ + 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, 0x1c, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, + 0xf7, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xdb, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x35, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0d, 0xdb, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0xf7, 0x17, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x54, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xb1, 0xdb, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xff, + 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xf7, 0xa4, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x08, 0x4d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x32, + /* ch = '[' */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x82, 0x36, 0x36, 0x36, 0x1e, 0x74, 0x74, 0x74, 0x74, 0x74, 0x30, + /* ch = '\' */ + 0x09, 0xb3, 0x48, 0x00, 0xa0, 0xc8, 0x00, 0x2c, 0xff, 0x00, 0x00, 0xb7, + 0x00, 0x00, 0x39, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + /* ch = ']' */ + 0xb7, 0xff, 0xff, 0xff, 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x7c, + 0x2d, 0x36, 0x36, 0x36, 0xcf, 0x7c, 0x58, 0x74, 0x74, 0x74, 0x74, 0x42, + /* ch = '^' */ + 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x22, + 0x00, 0x00, 0x00, 0x04, 0xdb, 0xff, 0x90, 0x00, 0x00, 0x00, 0x54, 0xe5, + 0x3f, 0xff, 0x2a, 0x00, 0x17, 0xf7, 0x3b, 0x00, 0xa0, 0xa0, 0x00, 0x36, + 0x8d, 0x00, 0x00, 0x24, 0x9e, 0x13, + /* ch = '_' */ + 0x42, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x22, 0x26, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x16, + /* ch = '`' */ + 0x7f, 0x70, 0x00, 0x00, 0x3b, 0xf7, 0x17, 0x00, 0x0d, 0xf7, 0xc4, 0x10, + 0x00, 0x50, 0xff, 0x4d, 0x00, 0x00, 0x12, 0x04, + /* ch = 'a' */ + 0x00, 0x00, 0x08, 0x2a, 0x36, 0x25, 0x04, 0x00, 0x00, 0x36, 0xf7, 0xdd, + 0x8f, 0xef, 0xd4, 0x10, 0x00, 0x1f, 0x35, 0x00, 0x00, 0x10, 0xe5, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xb7, 0x00, 0x08, 0x50, 0xab, + 0xcf, 0xcf, 0xef, 0xb7, 0x0d, 0xd4, 0xc4, 0x25, 0x15, 0x15, 0x88, 0xb7, + 0x3b, 0xff, 0x24, 0x00, 0x00, 0x00, 0xb7, 0xb7, 0x32, 0xff, 0x3f, 0x00, + 0x04, 0x5f, 0xff, 0xb7, 0x00, 0x73, 0xff, 0xd4, 0xef, 0xb3, 0xa5, 0xb7, + 0x00, 0x00, 0x0c, 0x15, 0x0c, 0x00, 0x00, 0x00, + /* ch = 'b' */ + 0x32, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x16, 0x36, 0x2a, 0x04, 0x00, 0x00, + 0x32, 0xff, 0xa9, 0xef, 0xcf, 0xff, 0xdb, 0x16, 0x00, 0x32, 0xff, 0xb7, + 0x08, 0x00, 0x21, 0xff, 0xa0, 0x00, 0x32, 0xff, 0x4d, 0x00, 0x00, 0x00, + 0x7c, 0xff, 0x14, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, + 0x32, 0xff, 0x35, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x32, 0xff, 0x54, + 0x00, 0x00, 0x00, 0x8a, 0xf7, 0x04, 0x32, 0xff, 0xdb, 0x1b, 0x04, 0x3f, + 0xff, 0x6b, 0x00, 0x32, 0xff, 0x5b, 0xf7, 0xff, 0xff, 0x84, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x15, 0x0c, 0x00, 0x00, 0x00, + /* ch = 'c' */ + 0x00, 0x00, 0x0f, 0x36, 0x36, 0x0f, 0x00, 0x00, 0x04, 0x94, 0xff, 0xd4, + 0xdd, 0xff, 0x66, 0x00, 0x77, 0xf7, 0x21, 0x00, 0x00, 0x3f, 0xb1, 0x04, + 0xff, 0x5f, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0xff, 0x32, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf7, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x5f, 0x08, + 0x08, 0x5a, 0xa0, 0x04, 0x00, 0x50, 0xf7, 0xff, 0xff, 0xef, 0x35, 0x00, + 0x00, 0x00, 0x04, 0x15, 0x15, 0x00, 0x00, 0x00, + /* ch = 'd' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xcf, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xb7, + 0x00, 0x00, 0x0c, 0x36, 0x36, 0x16, 0x7c, 0xb7, 0x00, 0x32, 0xf7, 0xcb, + 0x9e, 0xff, 0xdb, 0xb7, 0x0d, 0xf7, 0x7c, 0x00, 0x00, 0x26, 0xff, 0xb7, + 0x3b, 0xff, 0x1f, 0x00, 0x00, 0x00, 0xbd, 0xb7, 0x50, 0xff, 0x0d, 0x00, + 0x00, 0x00, 0xb7, 0xb7, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0xb7, 0xb7, + 0x2f, 0xff, 0x3b, 0x00, 0x00, 0x04, 0xe5, 0xb7, 0x04, 0xdb, 0xdb, 0x1b, + 0x08, 0x6b, 0xff, 0xb7, 0x00, 0x1f, 0xd4, 0xff, 0xff, 0xa9, 0x97, 0xcf, + 0x00, 0x00, 0x00, 0x12, 0x0f, 0x00, 0x00, 0x00, + /* ch = 'e' */ + 0x00, 0x00, 0x04, 0x2a, 0x36, 0x25, 0x04, 0x00, 0x00, 0x1f, 0xdb, 0xd4, + 0x74, 0xef, 0xc4, 0x10, 0x00, 0xc8, 0xb1, 0x04, 0x00, 0x10, 0xe5, 0x70, + 0x2a, 0xff, 0x32, 0x00, 0x00, 0x00, 0x7c, 0xcf, 0x44, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x44, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x24, 0xff, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xf7, 0x24, + 0x00, 0x04, 0x66, 0x35, 0x00, 0x10, 0x94, 0xff, 0xe5, 0xff, 0xcb, 0x1f, + 0x00, 0x00, 0x00, 0x08, 0x15, 0x0f, 0x00, 0x00, + /* ch = 'f' */ + 0x00, 0x1f, 0xc4, 0xff, 0xff, 0xb3, 0x19, 0x0d, 0xdb, 0x90, 0x08, 0x0c, + 0x99, 0x48, 0x32, 0xff, 0x24, 0x00, 0x00, 0x08, 0x04, 0x32, 0xff, 0x1c, + 0x00, 0x00, 0x00, 0x00, 0xdd, 0xff, 0xd4, 0xcf, 0x95, 0x00, 0x00, 0x3e, + 0xff, 0x28, 0x15, 0x12, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, + 0x1c, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, + /* ch = 'g' */ + 0x00, 0x00, 0x16, 0x36, 0x36, 0x13, 0x16, 0x36, 0x19, 0x00, 0x44, 0xff, + 0x8f, 0xa4, 0xf7, 0xf7, 0x8f, 0x30, 0x0d, 0xf7, 0x54, 0x00, 0x00, 0x82, + 0xc8, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, + 0x04, 0xe5, 0x90, 0x04, 0x10, 0xb7, 0xa0, 0x00, 0x00, 0x00, 0x31, 0xff, + 0xef, 0xf7, 0xbb, 0x10, 0x00, 0x00, 0x00, 0x99, 0x75, 0x15, 0x12, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe5, 0xc4, 0x3e, 0x36, 0x36, 0x25, 0x04, 0x00, + 0x00, 0x6d, 0xbb, 0x74, 0x74, 0x8f, 0xf7, 0xb1, 0x00, 0x44, 0xe5, 0x04, + 0x00, 0x00, 0x00, 0x3b, 0xff, 0x1c, 0x6b, 0xff, 0x28, 0x00, 0x00, 0x0c, + 0x90, 0xdb, 0x04, 0x08, 0x7f, 0xf7, 0xff, 0xef, 0xff, 0x9e, 0x19, 0x00, + /* ch = 'h' */ + 0xff, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x50, 0x04, + 0x30, 0x36, 0x0c, 0x00, 0xff, 0x82, 0xdb, 0xd4, 0xef, 0xf7, 0x1f, 0xff, + 0xff, 0x35, 0x00, 0x17, 0xff, 0x77, 0xff, 0x82, 0x00, 0x00, 0x00, 0xb7, + 0xb7, 0xff, 0x54, 0x00, 0x00, 0x00, 0xb7, 0xb7, 0xff, 0x50, 0x00, 0x00, + 0x00, 0xb7, 0xb7, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, 0xff, 0x50, + 0x00, 0x00, 0x00, 0xb7, 0xb7, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, + /* ch = 'i' */ + 0x00, 0x00, 0x39, 0xcf, 0x24, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x15, 0x15, + 0x15, 0x04, 0x00, 0x00, 0x45, 0xcf, 0xe5, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, + 0x1c, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x50, 0xff, 0x1c, 0x00, 0x00, 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1c, + /* ch = 'j' */ + 0x00, 0x00, 0x00, 0x00, 0x0d, 0xab, 0x60, 0x00, 0x00, 0x00, 0x00, 0x17, + 0xf7, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, + 0x15, 0x15, 0x15, 0x0f, 0x00, 0x00, 0xcf, 0xcf, 0xcf, 0xff, 0x7c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7c, + 0x00, 0x0c, 0x00, 0x00, 0x0d, 0xff, 0x5f, 0x1a, 0xef, 0x24, 0x04, 0x7c, + 0xff, 0x2a, 0x10, 0xb3, 0xff, 0xff, 0xef, 0x3b, 0x00, 0x00, 0x00, 0x08, + 0x0f, 0x00, 0x00, 0x00, + /* ch = 'k' */ + 0x1c, 0xff, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x50, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0x12, 0x15, 0x00, + 0x1c, 0xff, 0x50, 0x00, 0x00, 0x5f, 0xf7, 0x35, 0x00, 0x1c, 0xff, 0x50, + 0x00, 0x6b, 0xf7, 0x2c, 0x00, 0x00, 0x1c, 0xff, 0x54, 0x7c, 0xf7, 0x26, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0xf7, 0xff, 0xdb, 0x04, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0xc4, 0x35, 0xff, 0x7c, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x50, + 0x00, 0x50, 0xff, 0x50, 0x00, 0x00, 0x1c, 0xff, 0x50, 0x00, 0x00, 0x7c, + 0xff, 0x32, 0x00, 0x1c, 0xff, 0x50, 0x00, 0x00, 0x04, 0xb1, 0xf7, 0x21, + /* ch = 'l' */ + 0xb7, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, + 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x50, + 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, + 0x1c, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x50, 0xff, 0x1c, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, + /* ch = 'm' */ + 0x0f, 0x12, 0x1e, 0x36, 0x13, 0x13, 0x36, 0x22, 0x00, 0x7c, 0xf7, 0xc4, + 0xdb, 0xdb, 0xef, 0xab, 0xff, 0x27, 0x7c, 0xff, 0x10, 0x3b, 0xff, 0x3b, + 0x1c, 0xff, 0x50, 0x7c, 0xb7, 0x00, 0x32, 0xff, 0x1c, 0x1c, 0xff, 0x50, + 0x7c, 0xb7, 0x00, 0x32, 0xff, 0x1c, 0x1c, 0xff, 0x50, 0x7c, 0xb7, 0x00, + 0x32, 0xff, 0x1c, 0x1c, 0xff, 0x50, 0x7c, 0xb7, 0x00, 0x32, 0xff, 0x1c, + 0x1c, 0xff, 0x50, 0x7c, 0xb7, 0x00, 0x32, 0xff, 0x1c, 0x1c, 0xff, 0x50, + 0x7c, 0xb7, 0x00, 0x32, 0xff, 0x1c, 0x1c, 0xff, 0x50, + /* ch = 'n' */ + 0x04, 0x15, 0x0c, 0x08, 0x30, 0x36, 0x0c, 0x00, 0x1c, 0xff, 0x82, 0xdb, + 0xd4, 0xef, 0xef, 0x1c, 0x1c, 0xff, 0xff, 0x35, 0x00, 0x1a, 0xff, 0x6b, + 0x1c, 0xff, 0x7c, 0x00, 0x00, 0x00, 0xb7, 0x90, 0x1c, 0xff, 0x50, 0x00, + 0x00, 0x00, 0xb7, 0xb7, 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, + 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, 0x1c, 0xff, 0x50, 0x00, + 0x00, 0x00, 0xb7, 0xb7, 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, + /* ch = 'o' */ + 0x00, 0x00, 0x04, 0x25, 0x36, 0x25, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xd4, + 0xef, 0xcf, 0xf7, 0xbb, 0x10, 0x00, 0x04, 0xdb, 0xb1, 0x08, 0x00, 0x1f, + 0xf7, 0x8a, 0x00, 0x39, 0xff, 0x32, 0x00, 0x00, 0x00, 0x64, 0xff, 0x14, + 0x54, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x35, 0xff, 0x24, 0x54, 0xff, 0x1c, + 0x00, 0x00, 0x00, 0x35, 0xff, 0x24, 0x32, 0xff, 0x48, 0x00, 0x00, 0x00, + 0x70, 0xf7, 0x0d, 0x04, 0xb1, 0xf7, 0x21, 0x00, 0x35, 0xff, 0x6b, 0x00, + 0x00, 0x10, 0xa2, 0xff, 0xff, 0xff, 0x73, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0x15, 0x0c, 0x00, 0x00, 0x00, + /* ch = 'p' */ + 0x08, 0x15, 0x08, 0x16, 0x36, 0x2a, 0x08, 0x00, 0x00, 0x32, 0xff, 0xa9, + 0xef, 0xcf, 0xf7, 0xdb, 0x1f, 0x00, 0x32, 0xff, 0xb7, 0x08, 0x00, 0x1f, + 0xf7, 0xb7, 0x00, 0x32, 0xff, 0x4d, 0x00, 0x00, 0x00, 0x5f, 0xff, 0x1c, + 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x35, 0xff, 0x32, 0x32, 0xff, 0x32, + 0x00, 0x00, 0x00, 0x35, 0xff, 0x2f, 0x32, 0xff, 0x54, 0x00, 0x00, 0x00, + 0x70, 0xff, 0x14, 0x32, 0xff, 0xdb, 0x1b, 0x00, 0x31, 0xf7, 0x77, 0x00, + 0x32, 0xff, 0x8a, 0xf7, 0xff, 0xff, 0x94, 0x08, 0x00, 0x1c, 0xff, 0x32, + 0x08, 0x15, 0x0f, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = 'q' */ + 0x00, 0x00, 0x0c, 0x30, 0x36, 0x16, 0x0f, 0x15, 0x00, 0x2c, 0xf7, 0xcb, + 0x8f, 0xf7, 0xdb, 0xff, 0x0d, 0xf7, 0x82, 0x00, 0x00, 0x26, 0xff, 0xff, + 0x3b, 0xff, 0x24, 0x00, 0x00, 0x00, 0xb1, 0xff, 0x50, 0xff, 0x0d, 0x00, + 0x00, 0x00, 0x7c, 0xff, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x82, 0xff, + 0x32, 0xff, 0x3f, 0x00, 0x00, 0x04, 0xcf, 0xff, 0x04, 0xc8, 0xdb, 0x21, + 0x04, 0x5f, 0xff, 0xff, 0x00, 0x19, 0xcb, 0xff, 0xff, 0xbb, 0x97, 0xff, + 0x00, 0x00, 0x00, 0x12, 0x0f, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, + /* ch = 'r' */ + 0x0c, 0x15, 0x04, 0x16, 0x36, 0x30, 0x0c, 0x00, 0x50, 0xff, 0x99, 0xff, + 0xcf, 0xe5, 0xf7, 0x11, 0x50, 0xff, 0xf7, 0x21, 0x00, 0x04, 0x73, 0x00, + 0x50, 0xff, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = 's' */ + 0x00, 0x00, 0x04, 0x2a, 0x36, 0x2a, 0x08, 0x00, 0x00, 0x1f, 0xef, 0xcb, + 0x74, 0xd4, 0xf7, 0x3b, 0x00, 0x90, 0xcf, 0x04, 0x00, 0x04, 0x7c, 0x35, + 0x00, 0x6b, 0xff, 0x3f, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x8d, 0xff, + 0xff, 0x9e, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x37, 0xbb, 0xff, 0x50, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0xbd, 0xc8, 0x17, 0xf7, 0x5a, 0x08, + 0x00, 0x1b, 0xe5, 0x8a, 0x00, 0x48, 0xe5, 0xff, 0xff, 0xff, 0x94, 0x10, + 0x00, 0x00, 0x00, 0x12, 0x15, 0x08, 0x00, 0x00, + /* ch = 't' */ + 0x00, 0x00, 0x50, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x77, 0x00, + 0x00, 0x00, 0x15, 0x1a, 0xff, 0x5e, 0x15, 0x15, 0x04, 0xcf, 0xd4, 0xff, + 0xe5, 0xcf, 0xcf, 0x1a, 0x00, 0x1c, 0xff, 0x44, 0x00, 0x00, 0x00, 0x00, + 0x2a, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, + 0x00, 0x00, 0x32, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x32, 0xff, 0x35, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x9e, 0x0c, 0x2b, 0x6c, 0x00, 0x00, + 0x77, 0xff, 0xff, 0xf7, 0x5b, 0x00, 0x00, 0x00, 0x0c, 0x15, 0x00, 0x00, + /* ch = 'u' */ + 0x04, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x12, 0x12, 0x1c, 0xff, 0x50, 0x00, + 0x00, 0x00, 0xb7, 0xb7, 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, + 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, 0x1c, 0xff, 0x50, 0x00, + 0x00, 0x00, 0xb7, 0xb7, 0x1c, 0xff, 0x50, 0x00, 0x00, 0x00, 0xb7, 0xb7, + 0x1c, 0xff, 0x54, 0x00, 0x00, 0x04, 0xe5, 0xb7, 0x00, 0xc8, 0xdb, 0x13, + 0x04, 0x70, 0xff, 0xb7, 0x00, 0x1f, 0xd4, 0xff, 0xef, 0xa2, 0xcf, 0xbd, + 0x00, 0x00, 0x00, 0x15, 0x12, 0x00, 0x00, 0x00, + /* ch = 'v' */ + 0x0f, 0x15, 0x08, 0x00, 0x00, 0x00, 0x08, 0x15, 0x04, 0x32, 0xff, 0x39, + 0x00, 0x00, 0x00, 0x44, 0xf7, 0x04, 0x04, 0xe5, 0x8a, 0x00, 0x00, 0x00, + 0x90, 0x8a, 0x00, 0x00, 0x5a, 0xff, 0x17, 0x00, 0x17, 0xff, 0x32, 0x00, + 0x00, 0x17, 0xff, 0x5a, 0x00, 0x5a, 0xe5, 0x04, 0x00, 0x00, 0x00, 0xa0, + 0xe5, 0x04, 0xe5, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x39, 0xff, 0x7c, 0xf7, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe5, 0xff, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x5f, 0xff, 0x22, 0x00, 0x00, 0x00, + /* ch = 'w' */ + 0x15, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0f, 0xcf, 0x5f, 0x00, + 0x10, 0x36, 0x00, 0x00, 0xb7, 0x54, 0x82, 0xa0, 0x00, 0x3b, 0xff, 0x24, + 0x00, 0xff, 0x3b, 0x54, 0xf7, 0x00, 0x77, 0xff, 0x5f, 0x0d, 0xff, 0x2a, + 0x2f, 0xff, 0x1c, 0xcf, 0xc8, 0xb7, 0x1f, 0xff, 0x14, 0x14, 0xff, 0x48, + 0xff, 0x32, 0xff, 0x4c, 0xe5, 0x00, 0x00, 0xcf, 0xcf, 0xa0, 0x04, 0xf7, + 0xe5, 0xa0, 0x00, 0x00, 0x82, 0xff, 0x50, 0x00, 0x7c, 0xff, 0x5f, 0x00, + 0x00, 0x4d, 0xff, 0x24, 0x00, 0x3b, 0xff, 0x3b, 0x00, + /* ch = 'x' */ + 0x1c, 0x15, 0x08, 0x00, 0x00, 0x00, 0x12, 0x12, 0x00, 0x04, 0xdb, 0xb1, + 0x04, 0x00, 0x2f, 0xff, 0x35, 0x00, 0x00, 0x1f, 0xff, 0x54, 0x0d, 0xdb, + 0x82, 0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0xa9, 0xe5, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xb7, 0xff, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0xf7, 0xff, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xdb, 0x43, 0xff, + 0x3b, 0x00, 0x00, 0x00, 0x44, 0xff, 0x32, 0x00, 0x7c, 0xf7, 0x1c, 0x00, + 0x1f, 0xf7, 0x7c, 0x00, 0x00, 0x0d, 0xdb, 0xb1, 0x04, + /* ch = 'y' */ + 0x0c, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x15, 0x08, 0x22, 0xff, 0x48, + 0x00, 0x00, 0x00, 0x54, 0xff, 0x14, 0x00, 0xa7, 0xc8, 0x00, 0x00, 0x00, + 0xa7, 0xa0, 0x00, 0x00, 0x39, 0xff, 0x2c, 0x00, 0x1c, 0xff, 0x39, 0x00, + 0x00, 0x04, 0xe5, 0x70, 0x00, 0x5a, 0xf7, 0x04, 0x00, 0x00, 0x00, 0x6b, + 0xf7, 0x0d, 0xc8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x22, 0xff, 0x7c, 0xff, + 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0xff, 0xc8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x39, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3b, 0xff, 0x17, 0x00, 0x00, 0x00, 0x39, 0x26, 0x13, 0xdb, 0x8a, 0x00, + 0x00, 0x00, 0x00, 0x97, 0xff, 0xff, 0xbb, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ch = 'z' */ + 0x00, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x0f, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xb1, + 0xdb, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xf7, 0x1f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x50, 0xff, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, + 0xff, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf7, 0xb1, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x04, 0xdb, 0xec, 0x1f, 0x15, 0x15, 0x15, 0x15, 0x04, + 0x4d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1c, + /* ch = '{' */ + 0x00, 0x00, 0x20, 0x36, 0x36, 0x16, 0x00, 0x7c, 0xf7, 0x82, 0x74, 0x22, + 0x2a, 0xff, 0x39, 0x00, 0x00, 0x00, 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x32, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x3b, 0xff, 0x1a, 0x00, 0x00, 0x00, + 0xb1, 0x99, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x90, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x44, 0xff, 0x1a, 0x00, 0x00, 0x00, + 0x4d, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x50, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x3b, 0xff, 0x24, 0x00, 0x00, 0x00, 0x17, 0xf7, 0xb1, 0x1a, 0x15, 0x08, + 0x00, 0x26, 0xab, 0xcf, 0xcf, 0x2d, + /* ch = '|' */ + 0x45, 0xcf, 0x1a, 0x50, 0xff, 0x1c, 0x50, 0xff, 0x1c, 0x50, 0xff, 0x1c, + 0x50, 0xff, 0x1c, 0x50, 0xff, 0x1c, 0x50, 0xff, 0x1c, 0x50, 0xff, 0x1c, + 0x50, 0xff, 0x1c, 0x50, 0xff, 0x1c, 0x50, 0xff, 0x1c, 0x50, 0xff, 0x1c, + 0x50, 0xff, 0x1c, 0x50, 0xff, 0x1c, 0x45, 0xcf, 0x1a, + /* ch = '}' */ + 0x26, 0x36, 0x36, 0x16, 0x00, 0x42, 0x74, 0xa4, 0xff, 0x39, 0x00, 0x00, + 0x00, 0x8a, 0xe5, 0x00, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, 0x50, + 0xff, 0x00, 0x00, 0x00, 0x4d, 0xff, 0x00, 0x00, 0x00, 0x10, 0xef, 0x00, + 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x1c, 0xff, 0x00, 0x00, 0x00, + 0x4d, 0xff, 0x00, 0x00, 0x00, 0x50, 0xff, 0x00, 0x00, 0x00, 0x50, 0xff, + 0x00, 0x00, 0x00, 0x5f, 0xff, 0x0f, 0x15, 0x2b, 0xf7, 0xa0, 0x67, 0xcf, + 0xcf, 0x7f, 0x10, + /* ch = '~' */ + 0x00, 0x04, 0x2a, 0x2a, 0x04, 0x00, 0x00, 0x0c, 0x00, 0x10, 0xc4, 0xe5, + 0xef, 0xd4, 0x24, 0x21, 0xf7, 0x33, 0x29, 0x9c, 0x08, 0x08, 0x94, 0xff, + 0xff, 0x66, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0c, 0x00, 0x00 }; static const unsigned char *pd_inconsolata_font_bitmap[SIZE_TOTAL] = { - pd_inconsolata_font_bitmap_12px_bytes, - pd_inconsolata_font_bitmap_13px_bytes, - pd_inconsolata_font_bitmap_14px_bytes, - pd_inconsolata_font_bitmap_15px_bytes, - pd_inconsolata_font_bitmap_16px_bytes, - pd_inconsolata_font_bitmap_17px_bytes, - pd_inconsolata_font_bitmap_18px_bytes + pd_inconsolata_font_bitmap_12px_bytes, + pd_inconsolata_font_bitmap_13px_bytes, + pd_inconsolata_font_bitmap_14px_bytes, + pd_inconsolata_font_bitmap_15px_bytes, + pd_inconsolata_font_bitmap_16px_bytes, + pd_inconsolata_font_bitmap_17px_bytes, + pd_inconsolata_font_bitmap_18px_bytes }; -int pd_render_inconsolata_font_bitmap(pd_glyph_bitmap_t *bmp, unsigned ch, int size) +int pd_render_inconsolata_font_bitmap(pd_glyph_bitmap_t *bmp, unsigned ch, + int size) { - int i, j, *ptr; - const uint8_t *byte_ptr; + int i, j, *ptr; + const uint8_t *byte_ptr; - if (size < 12) { - return -1; - } - /* 不在范围内的字符都用框框表示 */ - if (ch < ' ' || ch > '~' || size > 18) { - bmp->metrics.hori_advance = (int)(size / 2.0 + 0.5); - bmp->metrics.vert_advance = size; - bmp->metrics.bbox_height = size; - bmp->metrics.bbox_width = bmp->metrics.hori_advance; - bmp->metrics.ascender = size * 4 / 5; - bmp->rows = size; - bmp->width = bmp->metrics.hori_advance; - bmp->buffer = calloc(bmp->rows * bmp->width, 1); - bmp->pitch = bmp->width; - bmp->top = size * 4 / 5; - bmp->left = 0; - j = (bmp->rows - 1) * bmp->width; - for (i = 0; i < bmp->width; ++i, ++j) { - bmp->buffer[i] = 255; - bmp->buffer[j] = 255; - } - i = 0; - j = bmp->width - 1; - size = bmp->width * bmp->rows; - while (i < size) { - bmp->buffer[i] = 255; - bmp->buffer[j] = 255; - i += bmp->width; - j += bmp->width; - } - return -2; - } - /* 空格就直接填充空白 */ - if (ch == ' ') { - bmp->metrics.hori_advance = (int)(size / 2.0 + 0.5); - bmp->metrics.vert_advance = size; - bmp->metrics.bbox_height = size; - bmp->metrics.bbox_width = bmp->metrics.hori_advance; - bmp->metrics.ascender = size; - bmp->rows = size; - bmp->width = bmp->metrics.hori_advance; - bmp->buffer = calloc(bmp->rows*bmp->width, 1); - bmp->pitch = bmp->width; - bmp->top = 0; - bmp->left = 0; - return 0; - } - i = size - 12; - j = ch - ' '; - *bmp = pd_inconsolata_font_bitmap_info[i][j]; - j = *(ptr = (int*)&bmp->buffer); - byte_ptr = &pd_inconsolata_font_bitmap[i][j]; - size = sizeof(unsigned char)*bmp->width*bmp->rows; - bmp->metrics.bbox_height = size; - bmp->metrics.bbox_width = bmp->metrics.hori_advance; - bmp->metrics.ascender = bmp->top; - bmp->buffer = (uint8_t*)malloc(size); - memcpy(bmp->buffer, byte_ptr, size); - return 0; + if (size < 12) { + return -1; + } + /* 不在范围内的字符都用框框表示 */ + if (ch < ' ' || ch > '~' || size > 18) { + bmp->metrics.hori_advance = (int)(size / 2.0 + 0.5); + bmp->metrics.vert_advance = size; + bmp->metrics.bbox_height = size; + bmp->metrics.bbox_width = bmp->metrics.hori_advance; + bmp->metrics.ascender = size * 4 / 5; + bmp->rows = size; + bmp->width = bmp->metrics.hori_advance; + bmp->buffer = calloc(bmp->rows * bmp->width, 1); + bmp->pitch = bmp->width; + bmp->top = size * 4 / 5; + bmp->left = 0; + j = (bmp->rows - 1) * bmp->width; + for (i = 0; i < bmp->width; ++i, ++j) { + bmp->buffer[i] = 255; + bmp->buffer[j] = 255; + } + i = 0; + j = bmp->width - 1; + size = bmp->width * bmp->rows; + while (i < size) { + bmp->buffer[i] = 255; + bmp->buffer[j] = 255; + i += bmp->width; + j += bmp->width; + } + return -2; + } + /* 空格就直接填充空白 */ + if (ch == ' ') { + bmp->metrics.hori_advance = (int)(size / 2.0 + 0.5); + bmp->metrics.vert_advance = size; + bmp->metrics.bbox_height = size; + bmp->metrics.bbox_width = bmp->metrics.hori_advance; + bmp->metrics.ascender = size; + bmp->rows = size; + bmp->width = bmp->metrics.hori_advance; + bmp->buffer = calloc(bmp->rows * bmp->width, 1); + bmp->pitch = bmp->width; + bmp->top = 0; + bmp->left = 0; + return 0; + } + i = size - 12; + j = ch - ' '; + *bmp = pd_inconsolata_font_bitmap_info[i][j]; + j = *(ptr = (int *)&bmp->buffer); + byte_ptr = &pd_inconsolata_font_bitmap[i][j]; + size = sizeof(unsigned char) * bmp->width * bmp->rows; + bmp->metrics.bbox_height = size; + bmp->metrics.bbox_width = bmp->metrics.hori_advance; + bmp->metrics.ascender = bmp->top; + bmp->buffer = (uint8_t *)malloc(size); + memcpy(bmp->buffer, byte_ptr, size); + return 0; } diff --git a/lib/pandagl/src/font/inconsolata.h b/lib/pandagl/src/font/inconsolata.h index 2cbc79e34..d4aa4dc34 100644 --- a/lib/pandagl/src/font/inconsolata.h +++ b/lib/pandagl/src/font/inconsolata.h @@ -1,7 +1,7 @@ /* * lib/pandagl/src/font/inconsolata.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -9,4 +9,5 @@ * LICENSE.TXT file in the root directory of this source tree. */ -int pd_render_inconsolata_font_bitmap(pd_glyph_bitmap_t *bmp, unsigned ch, int size); +int pd_render_inconsolata_font_bitmap(pd_glyph_bitmap_t *bmp, unsigned ch, + int size); diff --git a/lib/pandagl/src/font/incore.c b/lib/pandagl/src/font/incore.c index 21ece337d..8a60ac17b 100644 --- a/lib/pandagl/src/font/incore.c +++ b/lib/pandagl/src/font/incore.c @@ -1,12 +1,15 @@ /* * lib/pandagl/src/font/incore.c: -- basic in-core font-engine. * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include @@ -16,62 +19,61 @@ #include "incore.h" #include "inconsolata.h" -enum in_core_font_type { - FONT_INCONSOLATA -}; +enum in_core_font_type { FONT_INCONSOLATA }; static int pd_incore_font_open(const char *filepath, pd_font_face_t ***outfonts) { - int *code; - pd_font_face_t **fonts, *font; - if (strcmp(filepath, "in-core.inconsolata") != 0) { - return 0; - } - code = malloc(sizeof(int)); - *code = FONT_INCONSOLATA; - font = pd_font_face_create("inconsolata", "Regular"); - fonts = malloc(sizeof(pd_font_face_t*)); - font->data = code; - fonts[0] = font; - *outfonts = fonts; - return 1; + int *code; + pd_font_face_t **fonts, *font; + if (strcmp(filepath, "in-core.inconsolata") != 0) { + return 0; + } + code = malloc(sizeof(int)); + *code = FONT_INCONSOLATA; + font = pd_font_face_create("inconsolata", "Regular"); + fonts = malloc(sizeof(pd_font_face_t *)); + font->data = code; + fonts[0] = font; + *outfonts = fonts; + return 1; } static void pd_incore_font_close(void *face) { - free(face); + free(face); } static int pd_incore_font_render(pd_glyph_bitmap_t *bmp, unsigned ch, - int pixel_size, pd_font_face_t *font) + int pixel_size, pd_font_face_t *font) { - int *code = (int*)font->data; - switch (*code) { - case FONT_INCONSOLATA: - default: - return pd_render_inconsolata_font_bitmap(bmp, ch, pixel_size); - } - return -1; + int *code = (int *)font->data; + switch (*code) { + case FONT_INCONSOLATA: + default: + return pd_render_inconsolata_font_bitmap(bmp, ch, pixel_size); + } + return -1; } -static unsigned pd_incore_font_get_glyph_index(pd_font_face_t *face, unsigned ch) +static unsigned pd_incore_font_get_glyph_index(pd_font_face_t *face, + unsigned ch) { - (void)face; - /* 内置位图字体没有 cmap,字符码即字形索引 */ - return ch; + (void)face; + /* 内置位图字体没有 cmap,字符码即字形索引 */ + return ch; } int pd_incore_font_create(pd_font_engine_t *engine) { - engine->render = pd_incore_font_render; - engine->close = pd_incore_font_close; - engine->open = pd_incore_font_open; - engine->get_glyph_index = pd_incore_font_get_glyph_index; - strcpy(engine->name, "in-core"); - return 0; + engine->render = pd_incore_font_render; + engine->close = pd_incore_font_close; + engine->open = pd_incore_font_open; + engine->get_glyph_index = pd_incore_font_get_glyph_index; + strcpy(engine->name, "in-core"); + return 0; } int pd_incore_font_destroy(void) { - return 0; + return 0; } diff --git a/lib/pandagl/src/font/incore.h b/lib/pandagl/src/font/incore.h index 0f112225c..cc0d0aee8 100644 --- a/lib/pandagl/src/font/incore.h +++ b/lib/pandagl/src/font/incore.h @@ -1,7 +1,7 @@ /* * lib/pandagl/src/font/incore.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/pandagl/src/font/library.c b/lib/pandagl/src/font/library.c index 3bf9d571c..bfae8092e 100644 --- a/lib/pandagl/src/font/library.c +++ b/lib/pandagl/src/font/library.c @@ -1,12 +1,15 @@ /* * lib/pandagl/src/font/library.c: -- The font info and font bitmap cache * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include @@ -222,7 +225,8 @@ char *pd_font_find_path(const char *name) #endif } -pd_font_face_t *pd_font_face_create(const char *family_name, const char *style_name) +pd_font_face_t *pd_font_face_create(const char *family_name, + const char *style_name) { pd_font_face_t *font; @@ -571,7 +575,7 @@ static pd_font_weight_t font_weight_fallback(font_style_node_t *snode, } int pd_font_get_id(const char *family_name, pd_font_style_t style, - pd_font_weight_t weight) + pd_font_weight_t weight) { int style_num; const char *name; @@ -606,9 +610,8 @@ int pd_font_get_id(const char *family_name, pd_font_style_t style, return -3; } -size_t pd_font_replace_weight(const int *font_ids, - pd_font_weight_t weight, - int **new_font_ids) +size_t pd_font_replace_weight(const int *font_ids, pd_font_weight_t weight, + int **new_font_ids) { int id, *ids; pd_font_face_t *font; @@ -627,8 +630,7 @@ size_t pd_font_replace_weight(const int *font_ids, } for (i = 0, count = 0; i < len; ++i) { font = pd_font_get(font_ids[i]); - id = pd_font_get_id(font->family_name, font->style, - weight); + id = pd_font_get_id(font->family_name, font->style, weight); if (id > 0) { ids[count++] = id; } @@ -643,9 +645,8 @@ size_t pd_font_replace_weight(const int *font_ids, return count; } -size_t pd_font_replace_style(const int *font_ids, - pd_font_style_t style, - int **new_font_ids) +size_t pd_font_replace_style(const int *font_ids, pd_font_style_t style, + int **new_font_ids) { int id, *ids; pd_font_face_t *font; @@ -664,8 +665,7 @@ size_t pd_font_replace_style(const int *font_ids, } for (i = 0, count = 0; i < len; ++i) { font = pd_font_get(font_ids[i]); - id = pd_font_get_id(font->family_name, style, - font->weight); + id = pd_font_get_id(font->family_name, style, font->weight); if (id > 0) { ids[count++] = id; } @@ -681,8 +681,7 @@ size_t pd_font_replace_style(const int *font_ids, } unsigned pd_font_query(int **font_ids, pd_font_style_t style, - pd_font_weight_t weight, - const char *const *names) + pd_font_weight_t weight, const char *const *names) { int *ids; unsigned i, count, loaded_count; @@ -700,8 +699,7 @@ unsigned pd_font_query(int **font_ids, pd_font_style_t style, return 0; } for (loaded_count = 0, i = 0; i < count; ++i) { - ids[loaded_count] = - pd_font_get_id(names[i], style, weight); + ids[loaded_count] = pd_font_get_id(names[i], style, weight); if (ids[loaded_count] > 0) { ++loaded_count; } @@ -758,8 +756,8 @@ int pd_font_load_file(const char *filepath) return 0; } -int pd_font_render_glyph(pd_glyph_bitmap_t *buff, unsigned ch, - int font_id, int pixel_size) +int pd_font_render_glyph(pd_glyph_bitmap_t *buff, unsigned ch, int font_id, + int pixel_size) { pd_font_face_t *font = fontlib.default_font; do { @@ -783,8 +781,7 @@ int pd_font_render_glyph(pd_glyph_bitmap_t *buff, unsigned ch, return font->engine->render(buff, ch, pixel_size, font); } -bool pd_font_family_set_alias(const char *alias, - const char *family_name) +bool pd_font_family_set_alias(const char *alias, const char *family_name) { return dict_add(fontlib.font_family_aliases, (void *)alias, (void *)family_name) == DICT_OK; diff --git a/lib/pandagl/src/font/library.h b/lib/pandagl/src/font/library.h index 8fa1ea35c..7d542d88f 100644 --- a/lib/pandagl/src/font/library.h +++ b/lib/pandagl/src/font/library.h @@ -1,7 +1,7 @@ /* * lib/pandagl/src/font/library.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -9,6 +9,7 @@ * LICENSE.TXT file in the root directory of this source tree. */ -pd_font_face_t *pd_font_face_create(const char *family_name, const char *style_name); +pd_font_face_t *pd_font_face_create(const char *family_name, + const char *style_name); void pd_font_face_destroy(pd_font_face_t *font); diff --git a/lib/pandagl/src/image/bmp.c b/lib/pandagl/src/image/bmp.c index ad8d8cbab..19e3bab79 100644 --- a/lib/pandagl/src/image/bmp.c +++ b/lib/pandagl/src/image/bmp.c @@ -1,12 +1,15 @@ /* * lib/pandagl/src/image/bmp.c: -- LCUI BMP image file processing module. * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include diff --git a/lib/pandagl/src/image/bmp_private.h b/lib/pandagl/src/image/bmp_private.h index 646c5e765..178990a2f 100644 --- a/lib/pandagl/src/image/bmp_private.h +++ b/lib/pandagl/src/image/bmp_private.h @@ -1,7 +1,7 @@ /* * lib/pandagl/src/image/bmp_private.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/pandagl/src/image/jpeg.c b/lib/pandagl/src/image/jpeg.c index 31ff7565e..4c4516875 100644 --- a/lib/pandagl/src/image/jpeg.c +++ b/lib/pandagl/src/image/jpeg.c @@ -1,12 +1,15 @@ /* * lib/pandagl/src/image/jpeg.c: -- LCUI JPEG image file processing module. * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include @@ -25,185 +28,184 @@ #define BUFFER_SIZE 4096 typedef struct pd_jpeg_error { - struct jpeg_error_mgr pub; - pd_image_reader_t *reader; + struct jpeg_error_mgr pub; + pd_image_reader_t *reader; } pd_jpeg_error_t; typedef struct pd_jpeg_reader { - struct jpeg_source_mgr src; - struct jpeg_decompress_struct cinfo; - jmp_buf env; - pd_jpeg_error_t err; - bool start_of_file; - pd_image_reader_t *base; - unsigned char buffer[BUFFER_SIZE]; + struct jpeg_source_mgr src; + struct jpeg_decompress_struct cinfo; + jmp_buf env; + pd_jpeg_error_t err; + bool start_of_file; + pd_image_reader_t *base; + unsigned char buffer[BUFFER_SIZE]; } pd_jpeg_reader_t; METHODDEF(void) pd_jpeg_reader_on_error_exit(j_common_ptr cinfo) { - pd_jpeg_error_t *err = (pd_jpeg_error_t *)cinfo->err; - pd_jpeg_reader_t *reader = err->reader->reader_data; - cinfo->err->format_message(cinfo, err->reader->error_message); - longjmp(reader->env, PD_ERROR_IMAGE_READING); + pd_jpeg_error_t *err = (pd_jpeg_error_t *)cinfo->err; + pd_jpeg_reader_t *reader = err->reader->reader_data; + cinfo->err->format_message(cinfo, err->reader->error_message); + longjmp(reader->env, PD_ERROR_IMAGE_READING); } static void pd_jpeg_reader_on_init(j_decompress_ptr cinfo) { - pd_jpeg_reader_t *jpeg_reader; - jpeg_reader = (pd_jpeg_reader_t *)cinfo->src; - jpeg_reader->start_of_file = true; + pd_jpeg_reader_t *jpeg_reader; + jpeg_reader = (pd_jpeg_reader_t *)cinfo->src; + jpeg_reader->start_of_file = true; } static boolean pd_jpeg_reader_on_read(j_decompress_ptr cinfo) { - size_t size; - pd_jpeg_reader_t *jpeg_reader = (pd_jpeg_reader_t *)cinfo->src; - pd_image_reader_t *reader = jpeg_reader->base; - - size = pd_file_reader_read(reader->file_reader, jpeg_reader->buffer, - BUFFER_SIZE); - if (size <= 0) { - /* 将空的输入文件视为致命错误 */ - if (jpeg_reader->start_of_file) { - ERREXIT(cinfo, JERR_INPUT_EMPTY); - } - WARNMS(cinfo, JWRN_JPEG_EOF); - /* 插入一个无用的 EOI 标记 */ - jpeg_reader->buffer[0] = (JOCTET)0xFF; - jpeg_reader->buffer[1] = (JOCTET)JPEG_EOI; - size = 2; - } - /* 设置数据缓存地址和大小,供 jpeg 解码器使用 */ - jpeg_reader->src.next_input_byte = jpeg_reader->buffer; - jpeg_reader->src.bytes_in_buffer = size; - jpeg_reader->start_of_file = false; - return true; + size_t size; + pd_jpeg_reader_t *jpeg_reader = (pd_jpeg_reader_t *)cinfo->src; + pd_image_reader_t *reader = jpeg_reader->base; + + size = pd_file_reader_read(reader->file_reader, jpeg_reader->buffer, + BUFFER_SIZE); + if (size <= 0) { + /* 将空的输入文件视为致命错误 */ + if (jpeg_reader->start_of_file) { + ERREXIT(cinfo, JERR_INPUT_EMPTY); + } + WARNMS(cinfo, JWRN_JPEG_EOF); + /* 插入一个无用的 EOI 标记 */ + jpeg_reader->buffer[0] = (JOCTET)0xFF; + jpeg_reader->buffer[1] = (JOCTET)JPEG_EOI; + size = 2; + } + /* 设置数据缓存地址和大小,供 jpeg 解码器使用 */ + jpeg_reader->src.next_input_byte = jpeg_reader->buffer; + jpeg_reader->src.bytes_in_buffer = size; + jpeg_reader->start_of_file = false; + return true; } static void pd_jpeg_reader_on_skip(j_decompress_ptr cinfo, long num_bytes) { - struct jpeg_source_mgr *src = cinfo->src; - pd_jpeg_reader_t * jpeg_reader = (pd_jpeg_reader_t *)cinfo->src; - pd_image_reader_t *reader = jpeg_reader->base; - - /* 如果跳过的字节数小于当前缓存的数据大小,则直接移动数据读取指针 */ - if (src->bytes_in_buffer > (size_t)num_bytes) { - src->next_input_byte += num_bytes; - src->bytes_in_buffer -= num_bytes; - return; - } - num_bytes -= (long)src->bytes_in_buffer; - pd_file_reader_skip(reader->file_reader, num_bytes); - /* 重置当前缓存 */ - src->bytes_in_buffer = 0; - src->next_input_byte = jpeg_reader->buffer; + struct jpeg_source_mgr *src = cinfo->src; + pd_jpeg_reader_t *jpeg_reader = (pd_jpeg_reader_t *)cinfo->src; + pd_image_reader_t *reader = jpeg_reader->base; + + /* 如果跳过的字节数小于当前缓存的数据大小,则直接移动数据读取指针 */ + if (src->bytes_in_buffer > (size_t)num_bytes) { + src->next_input_byte += num_bytes; + src->bytes_in_buffer -= num_bytes; + return; + } + num_bytes -= (long)src->bytes_in_buffer; + pd_file_reader_skip(reader->file_reader, num_bytes); + /* 重置当前缓存 */ + src->bytes_in_buffer = 0; + src->next_input_byte = jpeg_reader->buffer; } static void pd_jpeg_reader_on_terminate(j_decompress_ptr cinfo) { } - void pd_jpeg_reader_create(pd_image_reader_t *reader) { - pd_jpeg_reader_t *jpeg_reader; - - jpeg_reader = malloc(sizeof(pd_jpeg_reader_t)); - jpeg_reader->src.init_source = pd_jpeg_reader_on_init; - jpeg_reader->src.term_source = pd_jpeg_reader_on_terminate; - jpeg_reader->src.skip_input_data = pd_jpeg_reader_on_skip; - jpeg_reader->src.fill_input_buffer = pd_jpeg_reader_on_read; - jpeg_reader->src.resync_to_restart = jpeg_resync_to_restart; - jpeg_reader->src.bytes_in_buffer = 0; - jpeg_reader->src.next_input_byte = NULL; - jpeg_reader->err.pub.error_exit = pd_jpeg_reader_on_error_exit; - jpeg_reader->err.reader = reader; - jpeg_reader->base = reader; - jpeg_create_decompress(&jpeg_reader->cinfo); - jpeg_reader->cinfo.src = &jpeg_reader->src; - jpeg_reader->cinfo.err = jpeg_std_error(&jpeg_reader->err.pub); - reader->reader_data = jpeg_reader; + pd_jpeg_reader_t *jpeg_reader; + + jpeg_reader = malloc(sizeof(pd_jpeg_reader_t)); + jpeg_reader->src.init_source = pd_jpeg_reader_on_init; + jpeg_reader->src.term_source = pd_jpeg_reader_on_terminate; + jpeg_reader->src.skip_input_data = pd_jpeg_reader_on_skip; + jpeg_reader->src.fill_input_buffer = pd_jpeg_reader_on_read; + jpeg_reader->src.resync_to_restart = jpeg_resync_to_restart; + jpeg_reader->src.bytes_in_buffer = 0; + jpeg_reader->src.next_input_byte = NULL; + jpeg_reader->err.pub.error_exit = pd_jpeg_reader_on_error_exit; + jpeg_reader->err.reader = reader; + jpeg_reader->base = reader; + jpeg_create_decompress(&jpeg_reader->cinfo); + jpeg_reader->cinfo.src = &jpeg_reader->src; + jpeg_reader->cinfo.err = jpeg_std_error(&jpeg_reader->err.pub); + reader->reader_data = jpeg_reader; } void pd_jpeg_reader_start(pd_image_reader_t *reader) { - pd_jpeg_reader_t *jpeg_reader = reader->reader_data; - jpeg_start_decompress(&jpeg_reader->cinfo); + pd_jpeg_reader_t *jpeg_reader = reader->reader_data; + jpeg_start_decompress(&jpeg_reader->cinfo); } void pd_jpeg_reader_finish(pd_image_reader_t *reader) { - pd_jpeg_reader_t *jpeg_reader = reader->reader_data; + pd_jpeg_reader_t *jpeg_reader = reader->reader_data; - jpeg_finish_decompress(&jpeg_reader->cinfo); + jpeg_finish_decompress(&jpeg_reader->cinfo); } void pd_jpeg_reader_destroy(pd_image_reader_t *reader) { - pd_jpeg_reader_t *jpeg_reader = reader->reader_data; - jpeg_destroy_decompress(&jpeg_reader->cinfo); - free(jpeg_reader); + pd_jpeg_reader_t *jpeg_reader = reader->reader_data; + jpeg_destroy_decompress(&jpeg_reader->cinfo); + free(jpeg_reader); } jmp_buf *pd_jpeg_reader_jmpbuf(pd_image_reader_t *reader) { - pd_jpeg_reader_t *jpeg_reader = reader->reader_data; - return &jpeg_reader->env; + pd_jpeg_reader_t *jpeg_reader = reader->reader_data; + return &jpeg_reader->env; } pd_error_t pd_jpeg_reader_read_header(pd_image_reader_t *reader) { - size_t size; - short int *buffer; - pd_image_header_t *header = &reader->header; - pd_jpeg_reader_t *jpeg_reader = reader->reader_data; - j_decompress_ptr cinfo = &jpeg_reader->cinfo; - - size = pd_file_reader_read(reader->file_reader, jpeg_reader->buffer, - sizeof(short int)); - if (size < sizeof(short int)) { - return PD_ERROR_IMAGE_HEADER_INVALID; - } - jpeg_reader->src.bytes_in_buffer = sizeof(short int); - jpeg_reader->src.next_input_byte = jpeg_reader->buffer; - buffer = (short int *)jpeg_reader->buffer; - if (buffer[0] != -9985) { - return PD_ERROR_IMAGE_HEADER_INVALID; - } - if (setjmp(jpeg_reader->env)) { - return PD_ERROR_IMAGE_HEADER_INVALID; - } - jpeg_read_header(cinfo, true); - header->width = cinfo->image_width; - header->height = cinfo->image_height; - header->type = PD_JPEG_IMAGE; - header->color_type = PD_COLOR_TYPE_RGB; - if (cinfo->jpeg_color_space == JCS_RGB) { - header->bit_depth = 24; - } - return PD_OK; + size_t size; + short int *buffer; + pd_image_header_t *header = &reader->header; + pd_jpeg_reader_t *jpeg_reader = reader->reader_data; + j_decompress_ptr cinfo = &jpeg_reader->cinfo; + + size = pd_file_reader_read(reader->file_reader, jpeg_reader->buffer, + sizeof(short int)); + if (size < sizeof(short int)) { + return PD_ERROR_IMAGE_HEADER_INVALID; + } + jpeg_reader->src.bytes_in_buffer = sizeof(short int); + jpeg_reader->src.next_input_byte = jpeg_reader->buffer; + buffer = (short int *)jpeg_reader->buffer; + if (buffer[0] != -9985) { + return PD_ERROR_IMAGE_HEADER_INVALID; + } + if (setjmp(jpeg_reader->env)) { + return PD_ERROR_IMAGE_HEADER_INVALID; + } + jpeg_read_header(cinfo, true); + header->width = cinfo->image_width; + header->height = cinfo->image_height; + header->type = PD_JPEG_IMAGE; + header->color_type = PD_COLOR_TYPE_RGB; + if (cinfo->jpeg_color_space == JCS_RGB) { + header->bit_depth = 24; + } + return PD_OK; } void pd_jpeg_reader_read_row(pd_image_reader_t *reader, pd_canvas_t *out) { - uint8_t *bytep; - JSAMPARRAY buffer; - pd_jpeg_reader_t *jpeg_reader = reader->reader_data; - j_decompress_ptr cinfo = &jpeg_reader->cinfo; - int row_stride = cinfo->output_width * cinfo->output_components; - int k; - unsigned x; - - buffer = cinfo->mem->alloc_sarray((j_common_ptr)cinfo, JPOOL_IMAGE, - row_stride, 1); - bytep = out->bytes + cinfo->output_scanline * out->bytes_per_row; - jpeg_read_scanlines(cinfo, buffer, 1); - for (x = 0; x < out->width; ++x) { - k = x * 3; - *bytep++ = buffer[0][k + 2]; - *bytep++ = buffer[0][k + 1]; - *bytep++ = buffer[0][k]; - } + uint8_t *bytep; + JSAMPARRAY buffer; + pd_jpeg_reader_t *jpeg_reader = reader->reader_data; + j_decompress_ptr cinfo = &jpeg_reader->cinfo; + int row_stride = cinfo->output_width * cinfo->output_components; + int k; + unsigned x; + + buffer = cinfo->mem->alloc_sarray((j_common_ptr)cinfo, JPOOL_IMAGE, + row_stride, 1); + bytep = out->bytes + cinfo->output_scanline * out->bytes_per_row; + jpeg_read_scanlines(cinfo, buffer, 1); + for (x = 0; x < out->width; ++x) { + k = x * 3; + *bytep++ = buffer[0][k + 2]; + *bytep++ = buffer[0][k + 1]; + *bytep++ = buffer[0][k]; + } } #endif diff --git a/lib/pandagl/src/image/jpeg_private.h b/lib/pandagl/src/image/jpeg_private.h index d7d8ef43e..4d7a32950 100644 --- a/lib/pandagl/src/image/jpeg_private.h +++ b/lib/pandagl/src/image/jpeg_private.h @@ -1,7 +1,7 @@ /* * lib/pandagl/src/image/jpeg_private.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/pandagl/src/image/png.c b/lib/pandagl/src/image/png.c index d1f6a7454..cbe028dda 100644 --- a/lib/pandagl/src/image/png.c +++ b/lib/pandagl/src/image/png.c @@ -1,12 +1,15 @@ /* * lib/pandagl/src/image/png.c: -- LCUI PNG image file processing module. * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include diff --git a/lib/pandagl/src/image/png_private.h b/lib/pandagl/src/image/png_private.h index 4f3c8a956..807557c2b 100644 --- a/lib/pandagl/src/image/png_private.h +++ b/lib/pandagl/src/image/png_private.h @@ -1,7 +1,7 @@ /* * lib/pandagl/src/image/png_private.h * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/pandagl/src/image/reader.c b/lib/pandagl/src/image/reader.c index 0889544f7..de461cd98 100644 --- a/lib/pandagl/src/image/reader.c +++ b/lib/pandagl/src/image/reader.c @@ -1,12 +1,15 @@ /* * lib/pandagl/src/image/reader.c: -- Image read operations set * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include diff --git a/lib/pandagl/src/line.c b/lib/pandagl/src/line.c index 08131aa35..3b652a35b 100644 --- a/lib/pandagl/src/line.c +++ b/lib/pandagl/src/line.c @@ -1,126 +1,129 @@ /* * lib/pandagl/src/line.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include void pd_canvas_draw_horizontal_line(pd_canvas_t *canvas, pd_color_t color, - int size, pd_pos_t start, int len) + int size, pd_pos_t start, int len) { - int y, x; - pd_rect_t area; - pd_canvas_t *des; + int y, x; + pd_rect_t area; + pd_canvas_t *des; - des = pd_canvas_get_quote_source(canvas); - pd_canvas_get_quote_rect(canvas, &area); - start.x = area.x + start.x; - start.y = area.y + start.y; + des = pd_canvas_get_quote_source(canvas); + pd_canvas_get_quote_rect(canvas, &area); + start.x = area.x + start.x; + start.y = area.y + start.y; - if (start.x < area.x) { - len -= (area.x - start.x); - start.x = area.x; - } - if (len > area.x + area.width) { - len = area.x + area.width; - } - if (start.y < area.y) { - size -= (area.y - start.y); - start.y = area.y; - } - if (start.y + size > area.y + area.height) { - size = area.y + area.height - start.y; - } - if (des->color_type == PD_COLOR_TYPE_ARGB) { - pd_color_t *pPixel, *pRowPixel; - pRowPixel = des->argb + start.y * des->width + start.x; - for (y = 0; y < size; ++y) { - pPixel = pRowPixel; - for (x = 0; x < len; ++x) { - pPixel->b = color.blue; - pPixel->g = color.green; - pPixel->r = color.red; - pPixel->a = 255; - ++pPixel; - } - pRowPixel += des->width; - } - } else { - uint8_t *pByte, *pRowByte; - pRowByte = - des->bytes + start.y * des->bytes_per_row + start.x * 3; - for (y = 0; y < size; ++y) { - pByte = pRowByte; - for (x = 0; x < len; ++x) { - *pByte++ = color.blue; - *pByte++ = color.green; - *pByte++ = color.red; - } - pRowByte += des->bytes_per_row; - } - } + if (start.x < area.x) { + len -= (area.x - start.x); + start.x = area.x; + } + if (len > area.x + area.width) { + len = area.x + area.width; + } + if (start.y < area.y) { + size -= (area.y - start.y); + start.y = area.y; + } + if (start.y + size > area.y + area.height) { + size = area.y + area.height - start.y; + } + if (des->color_type == PD_COLOR_TYPE_ARGB) { + pd_color_t *pPixel, *pRowPixel; + pRowPixel = des->argb + start.y * des->width + start.x; + for (y = 0; y < size; ++y) { + pPixel = pRowPixel; + for (x = 0; x < len; ++x) { + pPixel->b = color.blue; + pPixel->g = color.green; + pPixel->r = color.red; + pPixel->a = 255; + ++pPixel; + } + pRowPixel += des->width; + } + } else { + uint8_t *pByte, *pRowByte; + pRowByte = + des->bytes + start.y * des->bytes_per_row + start.x * 3; + for (y = 0; y < size; ++y) { + pByte = pRowByte; + for (x = 0; x < len; ++x) { + *pByte++ = color.blue; + *pByte++ = color.green; + *pByte++ = color.red; + } + pRowByte += des->bytes_per_row; + } + } } void pd_canvas_draw_vertical_line(pd_canvas_t *canvas, pd_color_t color, - int size, pd_pos_t start, int len) + int size, pd_pos_t start, int len) { - int y, x; - pd_rect_t area; - pd_canvas_t *des; + int y, x; + pd_rect_t area; + pd_canvas_t *des; - des = pd_canvas_get_quote_source(canvas); - pd_canvas_get_quote_rect(canvas, &area); - start.x = area.x + start.x; - start.y = area.y + start.y; + des = pd_canvas_get_quote_source(canvas); + pd_canvas_get_quote_rect(canvas, &area); + start.x = area.x + start.x; + start.y = area.y + start.y; - if (start.x < area.x) { - size -= (area.x - start.x); - start.x = area.x; - } - if (start.x + size > area.x + area.width) { - size = area.x + area.width - start.x; - } + if (start.x < area.x) { + size -= (area.x - start.x); + start.x = area.x; + } + if (start.x + size > area.x + area.width) { + size = area.x + area.width - start.x; + } - if (start.y < area.y) { - len -= (area.y - start.y); - start.y = area.y; - } - if (start.y + len > area.y + area.height) { - len = area.y + area.height - start.y; - } + if (start.y < area.y) { + len -= (area.y - start.y); + start.y = area.y; + } + if (start.y + len > area.y + area.height) { + len = area.y + area.height - start.y; + } - if (des->color_type == PD_COLOR_TYPE_ARGB) { - pd_color_t *pPixel, *pRowPixel; - pRowPixel = des->argb + start.y * des->width + start.x; - for (y = 0; y < len; ++y) { - pPixel = pRowPixel; - for (x = 0; x < size; ++x) { - pPixel->b = color.blue; - pPixel->g = color.green; - pPixel->r = color.red; - pPixel->a = 255; - ++pPixel; - } - pRowPixel += des->width; - } - } else { - uint8_t *pByte, *pRowByte; - pRowByte = - des->bytes + start.y * des->bytes_per_row + start.x * 3; - for (y = 0; y < len; ++y) { - pByte = pRowByte; - for (x = 0; x < size; ++x) { - *pByte++ = color.blue; - *pByte++ = color.green; - *pByte++ = color.red; - } - pRowByte += des->bytes_per_row; - } - } + if (des->color_type == PD_COLOR_TYPE_ARGB) { + pd_color_t *pPixel, *pRowPixel; + pRowPixel = des->argb + start.y * des->width + start.x; + for (y = 0; y < len; ++y) { + pPixel = pRowPixel; + for (x = 0; x < size; ++x) { + pPixel->b = color.blue; + pPixel->g = color.green; + pPixel->r = color.red; + pPixel->a = 255; + ++pPixel; + } + pRowPixel += des->width; + } + } else { + uint8_t *pByte, *pRowByte; + pRowByte = + des->bytes + start.y * des->bytes_per_row + start.x * 3; + for (y = 0; y < len; ++y) { + pByte = pRowByte; + for (x = 0; x < size; ++x) { + *pByte++ = color.blue; + *pByte++ = color.green; + *pByte++ = color.red; + } + pRowByte += des->bytes_per_row; + } + } } diff --git a/lib/pandagl/src/pixel.c b/lib/pandagl/src/pixel.c index cc6d7ff77..93efb45b8 100644 --- a/lib/pandagl/src/pixel.c +++ b/lib/pandagl/src/pixel.c @@ -1,12 +1,15 @@ /* * lib/pandagl/src/pixel.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -15,90 +18,93 @@ unsigned pd_get_pixel_size(pd_color_type_t color_type) { - switch (color_type) { - case PD_COLOR_TYPE_INDEX8: - case PD_COLOR_TYPE_GRAY8: - case PD_COLOR_TYPE_RGB323: - case PD_COLOR_TYPE_ARGB2222: - return 1; - case PD_COLOR_TYPE_RGB555: - case PD_COLOR_TYPE_RGB565: - return 2; - case PD_COLOR_TYPE_RGB888: - return 3; - case PD_COLOR_TYPE_ARGB8888: - default: - break; - } - return 4; + switch (color_type) { + case PD_COLOR_TYPE_INDEX8: + case PD_COLOR_TYPE_GRAY8: + case PD_COLOR_TYPE_RGB323: + case PD_COLOR_TYPE_ARGB2222: + return 1; + case PD_COLOR_TYPE_RGB555: + case PD_COLOR_TYPE_RGB565: + return 2; + case PD_COLOR_TYPE_RGB888: + return 3; + case PD_COLOR_TYPE_ARGB8888: + default: + break; + } + return 4; } unsigned pd_get_pixel_row_size(pd_color_type_t color_type, size_t len) { - return (unsigned)(ceil(pd_get_pixel_size(color_type) * len / 4.0)) * 4; + return (unsigned)(ceil(pd_get_pixel_size(color_type) * len / 4.0)) * 4; } static void pd_format_pixels_argb2rgb(const pd_color_t *in_pixels, - uint8_t *out_pixels, size_t count) + uint8_t *out_pixels, size_t count) { - const pd_color_t *p_px, *p_end_px; - uint8_t *p_out_byte; + const pd_color_t *p_px, *p_end_px; + uint8_t *p_out_byte; - p_px = in_pixels; - p_out_byte = out_pixels; - /* 遍历到倒数第二个像素为止 */ - p_end_px = p_px + count - 1; - for (; p_px < p_end_px; ++p_px) { - *((pd_color_t*)p_out_byte) = *p_px; - p_out_byte += 3; - } - /* 最后一个像素,以逐个字节的形式写数据 */ - *p_out_byte++ = p_px->blue; - *p_out_byte++ = p_px->green; - *p_out_byte++ = p_px->red; + p_px = in_pixels; + p_out_byte = out_pixels; + /* 遍历到倒数第二个像素为止 */ + p_end_px = p_px + count - 1; + for (; p_px < p_end_px; ++p_px) { + *((pd_color_t *)p_out_byte) = *p_px; + p_out_byte += 3; + } + /* 最后一个像素,以逐个字节的形式写数据 */ + *p_out_byte++ = p_px->blue; + *p_out_byte++ = p_px->green; + *p_out_byte++ = p_px->red; } static void pd_format_pixels_rgb2argb(const uint8_t *in_bytes, - pd_color_t *out_pixels, size_t count) + pd_color_t *out_pixels, size_t count) { - pd_color_t *p_px, *p_end_px; - const uint8_t *p_in_byte; + pd_color_t *p_px, *p_end_px; + const uint8_t *p_in_byte; - p_in_byte = in_bytes; - p_px = (pd_color_t *)out_pixels; - p_end_px = p_px + count; - while (p_px < p_end_px) { - p_px->blue = *p_in_byte++; - p_px->green = *p_in_byte++; - p_px->red = *p_in_byte++; - p_px->alpha = 255; - ++p_px; - } + p_in_byte = in_bytes; + p_px = (pd_color_t *)out_pixels; + p_end_px = p_px + count; + while (p_px < p_end_px) { + p_px->blue = *p_in_byte++; + p_px->green = *p_in_byte++; + p_px->red = *p_in_byte++; + p_px->alpha = 255; + ++p_px; + } } int pd_format_pixels(const uint8_t *in_pixels, pd_color_type_t in_color_type, - uint8_t *out_pixels, pd_color_type_t out_color_type, - size_t count) + uint8_t *out_pixels, pd_color_type_t out_color_type, + size_t count) { - if (in_color_type == out_color_type) { - memcpy(out_pixels, in_pixels, pd_get_pixel_row_size(in_color_type, count)); - return 0; - } - switch (in_color_type) { - case PD_COLOR_TYPE_ARGB8888: - if (out_color_type == PD_COLOR_TYPE_RGB888) { - pd_format_pixels_argb2rgb((pd_color_t*)in_pixels, out_pixels, count); - return 0; - } - break; - case PD_COLOR_TYPE_RGB888: - if (out_color_type == PD_COLOR_TYPE_ARGB8888) { - pd_format_pixels_rgb2argb(in_pixels, (pd_color_t*)out_pixels, count); - return 0; - } - break; - default: - break; - } - return -1; + if (in_color_type == out_color_type) { + memcpy(out_pixels, in_pixels, + pd_get_pixel_row_size(in_color_type, count)); + return 0; + } + switch (in_color_type) { + case PD_COLOR_TYPE_ARGB8888: + if (out_color_type == PD_COLOR_TYPE_RGB888) { + pd_format_pixels_argb2rgb((pd_color_t *)in_pixels, + out_pixels, count); + return 0; + } + break; + case PD_COLOR_TYPE_RGB888: + if (out_color_type == PD_COLOR_TYPE_ARGB8888) { + pd_format_pixels_rgb2argb( + in_pixels, (pd_color_t *)out_pixels, count); + return 0; + } + break; + default: + break; + } + return -1; } diff --git a/lib/pandagl/src/rect.c b/lib/pandagl/src/rect.c index d2f63df0a..197f8c108 100644 --- a/lib/pandagl/src/rect.c +++ b/lib/pandagl/src/rect.c @@ -1,12 +1,15 @@ /* * lib/pandagl/src/rect.c: -- Rectangle area handling * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include @@ -36,8 +39,7 @@ pd_rect_t pd_rect_crop(const pd_rect_t *rect, int container_width, return cropped_rect; } -bool pd_rect_correct(pd_rect_t *rect, int container_width, - int container_height) +bool pd_rect_correct(pd_rect_t *rect, int container_width, int container_height) { bool overflow = false; @@ -95,7 +97,7 @@ bool pd_rect_is_cover(const pd_rect_t *a, const pd_rect_t *b) } bool pd_rect_overlap(const pd_rect_t *a, const pd_rect_t *b, - pd_rect_t *overlapping_rect) + pd_rect_t *overlapping_rect) { if (a->x > b->x) { if (b->x + b->width > a->x + a->width) { diff --git a/lib/pandagl/src/text/style.c b/lib/pandagl/src/text/style.c index 55ff4fbfd..8a1c46d38 100644 --- a/lib/pandagl/src/text/style.c +++ b/lib/pandagl/src/text/style.c @@ -1,12 +1,15 @@ /* * lib/pandagl/src/text/style.c: -- text style processing module. * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include @@ -16,161 +19,156 @@ void pd_text_style_init(pd_text_style_t *data) { - data->has_style = false; - data->has_weight = false; - data->has_family = false; - data->has_pixel_size = false; - data->has_back_color = false; - data->has_fore_color = false; - data->font_ids = NULL; - data->style = PD_FONT_STYLE_NORMAL; - data->weight = PD_FONT_WEIGHT_NORMAL; - data->fore_color.value = 0xff333333; - data->back_color.value = 0xffffffff; - data->pixel_size = 13; + data->has_style = false; + data->has_weight = false; + data->has_family = false; + data->has_pixel_size = false; + data->has_back_color = false; + data->has_fore_color = false; + data->font_ids = NULL; + data->style = PD_FONT_STYLE_NORMAL; + data->weight = PD_FONT_WEIGHT_NORMAL; + data->fore_color.value = 0xff333333; + data->back_color.value = 0xffffffff; + data->pixel_size = 13; } int pd_text_style_copy_family(pd_text_style_t *dst, pd_text_style_t *src) { - size_t len; - - if (!src->font_ids) { - return 0; - } - for (len = 0; src->font_ids[len]; ++len) - ; - len += 1; - if (dst->font_ids) { - free(dst->font_ids); - } - dst->font_ids = malloc(len * sizeof(int)); - if (!dst->font_ids) { - return -ENOMEM; - } - dst->has_family = true; - memcpy(dst->font_ids, src->font_ids, len * sizeof(int)); - return 0; + size_t len; + + if (!src->font_ids) { + return 0; + } + for (len = 0; src->font_ids[len]; ++len); + len += 1; + if (dst->font_ids) { + free(dst->font_ids); + } + dst->font_ids = malloc(len * sizeof(int)); + if (!dst->font_ids) { + return -ENOMEM; + } + dst->has_family = true; + memcpy(dst->font_ids, src->font_ids, len * sizeof(int)); + return 0; } int pd_text_style_copy(pd_text_style_t *dst, pd_text_style_t *src) { - *dst = *src; - dst->font_ids = NULL; - return pd_text_style_copy_family(dst, src); + *dst = *src; + dst->font_ids = NULL; + return pd_text_style_copy_family(dst, src); } void pd_text_style_destroy(pd_text_style_t *data) { - if (data->font_ids) { - free(data->font_ids); - } - data->font_ids = NULL; + if (data->font_ids) { + free(data->font_ids); + } + data->font_ids = NULL; } void pd_text_style_merge(pd_text_style_t *base, pd_text_style_t *target) { - int *font_ids = NULL; - base->has_family = true; - pd_text_style_copy_family(base, target); - if (target->has_style && !base->has_style && - target->style != PD_FONT_STYLE_NORMAL) { - base->has_style = true; - base->style = target->style; - } - if (pd_font_replace_style(base->font_ids, base->style, - &font_ids) > 0) { - free(base->font_ids); - base->font_ids = font_ids; - } - if (target->has_weight && !base->has_weight && - target->weight != PD_FONT_WEIGHT_NORMAL) { - base->has_weight = true; - base->weight = target->weight; - } - if (pd_font_replace_weight(base->font_ids, base->weight, - &font_ids) > 0) { - free(base->font_ids); - base->font_ids = font_ids; - } + int *font_ids = NULL; + base->has_family = true; + pd_text_style_copy_family(base, target); + if (target->has_style && !base->has_style && + target->style != PD_FONT_STYLE_NORMAL) { + base->has_style = true; + base->style = target->style; + } + if (pd_font_replace_style(base->font_ids, base->style, &font_ids) > 0) { + free(base->font_ids); + base->font_ids = font_ids; + } + if (target->has_weight && !base->has_weight && + target->weight != PD_FONT_WEIGHT_NORMAL) { + base->has_weight = true; + base->weight = target->weight; + } + if (pd_font_replace_weight(base->font_ids, base->weight, &font_ids) > + 0) { + free(base->font_ids); + base->font_ids = font_ids; + } } void pd_text_style_set_size(pd_text_style_t *ts, int pixel_size) { - ts->pixel_size = pixel_size; - ts->has_pixel_size = true; + ts->pixel_size = pixel_size; + ts->has_pixel_size = true; } void pd_text_style_set_fore_color(pd_text_style_t *ts, pd_color_t color) { - ts->fore_color = color; - ts->has_fore_color = true; + ts->fore_color = color; + ts->has_fore_color = true; } void pd_text_style_set_back_color(pd_text_style_t *ts, pd_color_t color) { - ts->back_color = color; - ts->has_back_color = true; + ts->back_color = color; + ts->has_back_color = true; } int pd_text_style_set_weight(pd_text_style_t *ts, pd_font_weight_t weight) { - int *font_ids; - ts->weight = weight; - ts->has_weight = true; - if (pd_font_replace_weight(ts->font_ids, weight, - &font_ids) > 0) { - free(ts->font_ids); - ts->font_ids = font_ids; - return 0; - } - return -1; + int *font_ids; + ts->weight = weight; + ts->has_weight = true; + if (pd_font_replace_weight(ts->font_ids, weight, &font_ids) > 0) { + free(ts->font_ids); + ts->font_ids = font_ids; + return 0; + } + return -1; } int pd_text_style_set_style(pd_text_style_t *ts, pd_font_style_t style) { - int *font_ids; - ts->style = style; - ts->has_style = true; - if (pd_font_replace_style(ts->font_ids, style, &font_ids) > - 0) { - free(ts->font_ids); - ts->font_ids = font_ids; - return 0; - } - return -1; + int *font_ids; + ts->style = style; + ts->has_style = true; + if (pd_font_replace_style(ts->font_ids, style, &font_ids) > 0) { + free(ts->font_ids); + ts->font_ids = font_ids; + return 0; + } + return -1; } int pd_text_style_set_font(pd_text_style_t *ts, const char *const *names) { - size_t count; - - if (ts->has_family && ts->font_ids) { - free(ts->font_ids); - } - ts->font_ids = NULL; - ts->has_family = false; - count = - pd_font_query(&ts->font_ids, ts->style, ts->weight, names); - if (count > 0) { - ts->has_family = true; - return 0; - } - return -1; + size_t count; + + if (ts->has_family && ts->font_ids) { + free(ts->font_ids); + } + ts->font_ids = NULL; + ts->has_family = false; + count = pd_font_query(&ts->font_ids, ts->style, ts->weight, names); + if (count > 0) { + ts->has_family = true; + return 0; + } + return -1; } int pd_text_style_set_default_font(pd_text_style_t *ts) { - if (ts->has_family && ts->font_ids) { - free(ts->font_ids); - ts->has_family = false; - } - ts->font_ids = malloc(sizeof(int) * 2); - if (!ts->font_ids) { - ts->font_ids = NULL; - return -ENOMEM; - } - ts->has_family = true; - ts->font_ids[0] = pd_font_get_default(); - ts->font_ids[1] = 0; - return 0; + if (ts->has_family && ts->font_ids) { + free(ts->font_ids); + ts->has_family = false; + } + ts->font_ids = malloc(sizeof(int) * 2); + if (!ts->font_ids) { + ts->font_ids = NULL; + return -ENOMEM; + } + ts->has_family = true; + ts->font_ids[0] = pd_font_get_default(); + ts->font_ids[1] = 0; + return 0; } diff --git a/lib/pandagl/src/text/style_tag.c b/lib/pandagl/src/text/style_tag.c index 21f884c80..ddeed91f1 100644 --- a/lib/pandagl/src/text/style_tag.c +++ b/lib/pandagl/src/text/style_tag.c @@ -1,398 +1,401 @@ /* * lib/pandagl/src/text/style_tag.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include #include typedef enum pd_text_style_type_t { - PD_TEXT_STYLE_TYPE_STYLE, - PD_TEXT_STYLE_TYPE_BOLD, - PD_TEXT_STYLE_TYPE_ITALIC, - PD_TEXT_STYLE_TYPE_SIZE, - PD_TEXT_STYLE_TYPE_COLOR, - PD_TEXT_STYLE_TYPE_BG_COLOR, - PD_TEXT_STYLE_TYPE_TOTAL_NUM + PD_TEXT_STYLE_TYPE_STYLE, + PD_TEXT_STYLE_TYPE_BOLD, + PD_TEXT_STYLE_TYPE_ITALIC, + PD_TEXT_STYLE_TYPE_SIZE, + PD_TEXT_STYLE_TYPE_COLOR, + PD_TEXT_STYLE_TYPE_BG_COLOR, + PD_TEXT_STYLE_TYPE_TOTAL_NUM } pd_text_style_type_t; typedef struct pd_style_tag { - pd_text_style_type_t id; - union { - pd_color_t color; - int number; - } data; + pd_text_style_type_t id; + union { + pd_color_t color; + int number; + } data; } pd_style_tag_t; void pd_style_tags_clear(list_t *tags) { - list_destroy(tags, free); + list_destroy(tags, free); } /** 获取当前的文本样式 */ pd_text_style_t *pd_style_tags_get_text_style(list_t *tags) { - int count = 0; - list_node_t *node; - pd_style_tag_t *tag; - pd_text_style_t *style; - bool found_tags[PD_TEXT_STYLE_TYPE_TOTAL_NUM] = { 0 }; + int count = 0; + list_node_t *node; + pd_style_tag_t *tag; + pd_text_style_t *style; + bool found_tags[PD_TEXT_STYLE_TYPE_TOTAL_NUM] = { 0 }; - if (tags->length <= 0) { - return NULL; - } - style = malloc(sizeof(pd_text_style_t)); - pd_text_style_init(style); - /* 根据已经记录的各种样式,生成当前应有的文本样式 */ - for (list_each_reverse(node, tags)) { - tag = node->data; - switch (tag->id) { - case PD_TEXT_STYLE_TYPE_COLOR: - if (found_tags[tag->id]) { - break; - } - style->has_fore_color = true; - style->fore_color = tag->data.color; - found_tags[tag->id] = true; - ++count; - break; - case PD_TEXT_STYLE_TYPE_BG_COLOR: - if (found_tags[tag->id]) { - break; - } - style->has_back_color = true; - style->back_color = tag->data.color; - found_tags[tag->id] = true; - ++count; - break; - case PD_TEXT_STYLE_TYPE_BOLD: - if (found_tags[tag->id]) { - break; - } - found_tags[tag->id] = true; - pd_text_style_set_weight(style, PD_FONT_WEIGHT_BOLD); - ++count; - break; - case PD_TEXT_STYLE_TYPE_ITALIC: - if (found_tags[tag->id]) { - break; - } - found_tags[tag->id] = true; - pd_text_style_set_style(style, PD_FONT_STYLE_ITALIC); - ++count; - break; - case PD_TEXT_STYLE_TYPE_SIZE: - if (found_tags[tag->id]) { - break; - } - style->has_pixel_size = true; - style->pixel_size = tag->data.number; - found_tags[tag->id] = true; - ++count; - break; - default: - break; - } - if (count == 4) { - break; - } - } - if (count == 0) { - free(style); - return NULL; - } - return style; + if (tags->length <= 0) { + return NULL; + } + style = malloc(sizeof(pd_text_style_t)); + pd_text_style_init(style); + /* 根据已经记录的各种样式,生成当前应有的文本样式 */ + for (list_each_reverse(node, tags)) { + tag = node->data; + switch (tag->id) { + case PD_TEXT_STYLE_TYPE_COLOR: + if (found_tags[tag->id]) { + break; + } + style->has_fore_color = true; + style->fore_color = tag->data.color; + found_tags[tag->id] = true; + ++count; + break; + case PD_TEXT_STYLE_TYPE_BG_COLOR: + if (found_tags[tag->id]) { + break; + } + style->has_back_color = true; + style->back_color = tag->data.color; + found_tags[tag->id] = true; + ++count; + break; + case PD_TEXT_STYLE_TYPE_BOLD: + if (found_tags[tag->id]) { + break; + } + found_tags[tag->id] = true; + pd_text_style_set_weight(style, PD_FONT_WEIGHT_BOLD); + ++count; + break; + case PD_TEXT_STYLE_TYPE_ITALIC: + if (found_tags[tag->id]) { + break; + } + found_tags[tag->id] = true; + pd_text_style_set_style(style, PD_FONT_STYLE_ITALIC); + ++count; + break; + case PD_TEXT_STYLE_TYPE_SIZE: + if (found_tags[tag->id]) { + break; + } + style->has_pixel_size = true; + style->pixel_size = tag->data.number; + found_tags[tag->id] = true; + ++count; + break; + default: + break; + } + if (count == 4) { + break; + } + } + if (count == 0) { + free(style); + return NULL; + } + return style; } /** 将指定标签的样式数据从队列中删除,只删除队列尾部第一个匹配的标签 */ static void pd_style_tags_remove(list_t *tags, int id) { - pd_style_tag_t *tag; - list_node_t *node; + pd_style_tag_t *tag; + list_node_t *node; - if (tags->length <= 0) { - return; - } - for (list_each(node, tags)) { - tag = node->data; - if (tag->id == id) { - free(tag); - list_delete_node(tags, node); - break; - } - } + if (tags->length <= 0) { + return; + } + for (list_each(node, tags)) { + tag = node->data; + if (tag->id == id) { + free(tag); + list_delete_node(tags, node); + break; + } + } } /** 在字符串中获取样式的结束标签,输出的是标签名 */ const wchar_t *pd_scan_style_close_tag(const wchar_t *wstr, wchar_t *name) { - size_t i, j, len; + size_t i, j, len; - len = wcslen(wstr); - if (wstr[0] != '[' || wstr[1] != '/') { - return NULL; - } - /* 匹配标签,获取标签名 */ - for (j = 0, i = 2; i < len; ++i) { - switch (wstr[i]) { - case ' ': - break; - case ']': - ++i; - goto end_tag_search; - default: - if (name) { - name[j] = wstr[i]; - } - ++j; - break; - } - } + len = wcslen(wstr); + if (wstr[0] != '[' || wstr[1] != '/') { + return NULL; + } + /* 匹配标签,获取标签名 */ + for (j = 0, i = 2; i < len; ++i) { + switch (wstr[i]) { + case ' ': + break; + case ']': + ++i; + goto end_tag_search; + default: + if (name) { + name[j] = wstr[i]; + } + ++j; + break; + } + } end_tag_search:; - if (name) { - name[j] = 0; - } - if (j < 1) { - return NULL; - } - return wstr + i; + if (name) { + name[j] = 0; + } + if (j < 1) { + return NULL; + } + return wstr + i; } /** 从字符串中获取样式标签的名字及样式属性 */ const wchar_t *pd_scan_style_open_tag(const wchar_t *wstr, wchar_t *name, - int max_name_len, wchar_t *data) + int max_name_len, wchar_t *data) { - size_t i, j, len; - bool end_name = false; + size_t i, j, len; + bool end_name = false; - len = wcslen(wstr); - if (wstr[0] != '<') { - return NULL; - } - /* 匹配标签前半部分 */ - for (j = 0, i = 1; i < len; ++i) { - if (wstr[i] == ' ') { - /* 如果上个字符不是空格,说明标签名已经结束 */ - if (i > 0 && wstr[i - 1] != ' ') { - end_name = true; - } - /* 标签名首部和尾部可包含空格 */ - if (j == 0 || max_name_len == 0 || - (max_name_len > 0 && end_name)) { - continue; - } - /* 标签名中间不能包含空格 */ - return NULL; - } - /* 如果标签名部分已经匹配完 */ - if (wstr[i] == '=') { - ++i; - break; - } - /* 如果标签名已经结束了 */ - if (end_name) { - return NULL; - } - if (max_name_len > 0 && data) { - name[j] = wstr[i]; - } - ++j; - } + len = wcslen(wstr); + if (wstr[0] != '<') { + return NULL; + } + /* 匹配标签前半部分 */ + for (j = 0, i = 1; i < len; ++i) { + if (wstr[i] == ' ') { + /* 如果上个字符不是空格,说明标签名已经结束 */ + if (i > 0 && wstr[i - 1] != ' ') { + end_name = true; + } + /* 标签名首部和尾部可包含空格 */ + if (j == 0 || max_name_len == 0 || + (max_name_len > 0 && end_name)) { + continue; + } + /* 标签名中间不能包含空格 */ + return NULL; + } + /* 如果标签名部分已经匹配完 */ + if (wstr[i] == '=') { + ++i; + break; + } + /* 如果标签名已经结束了 */ + if (end_name) { + return NULL; + } + if (max_name_len > 0 && data) { + name[j] = wstr[i]; + } + ++j; + } - if (data) { - name[j] = 0; - } - /* 获取标签后半部分 */ - for (j = 0; i < len; ++i) { - if (wstr[i] == ' ') { - continue; - } - /* 标签结束,退出 */ - if (wstr[i] == '>') { - ++i; - break; - } - if (data) { - /* 保存标签内的数据 */ - data[j] = wstr[i]; - } - ++j; - } - if (data) { - data[j] = 0; - } - if (i >= len) { - return NULL; - } - return wstr + i; + if (data) { + name[j] = 0; + } + /* 获取标签后半部分 */ + for (j = 0; i < len; ++i) { + if (wstr[i] == ' ') { + continue; + } + /* 标签结束,退出 */ + if (wstr[i] == '>') { + ++i; + break; + } + if (data) { + /* 保存标签内的数据 */ + data[j] = wstr[i]; + } + ++j; + } + if (data) { + data[j] = 0; + } + if (i >= len) { + return NULL; + } + return wstr + i; } /** 在字符串中获取指定样式标签中的数据 */ static const wchar_t *pd_scan_style_tag_by_name(const wchar_t *wstr, - const wchar_t *name, char *data) + const wchar_t *name, char *data) { - size_t i, j, len, tag_len; + size_t i, j, len, tag_len; - len = wcslen(wstr); - tag_len = wcslen(name); - if (wstr[0] != '[') { - return NULL; - } - /* 匹配标签前半部分 */ - for (j = 0, i = 1; i < len; ++i) { - if (wstr[i] == ' ') { - if (j == 0 || j >= tag_len) { - continue; - } - return NULL; - } - if (j < tag_len) { - if (wstr[i] == name[j]) { - ++j; - continue; - } - } else if (wstr[i] == '=') { - ++i; - break; - } else if (wstr[i] == ']') { - break; - } - return NULL; - } - /* 获取标签后半部分 */ - for (j = 0; i < len; ++i) { - if (wstr[i] == ' ') { - continue; - } - /* 标签结束,退出 */ - if (wstr[i] == ']') { - ++i; - break; - } - /* 保存标签内的数据 */ - data[j] = (char)wstr[i]; - ++j; - } - data[j] = 0; - if (i >= len) { - return NULL; - } - return wstr + i; + len = wcslen(wstr); + tag_len = wcslen(name); + if (wstr[0] != '[') { + return NULL; + } + /* 匹配标签前半部分 */ + for (j = 0, i = 1; i < len; ++i) { + if (wstr[i] == ' ') { + if (j == 0 || j >= tag_len) { + continue; + } + return NULL; + } + if (j < tag_len) { + if (wstr[i] == name[j]) { + ++j; + continue; + } + } else if (wstr[i] == '=') { + ++i; + break; + } else if (wstr[i] == ']') { + break; + } + return NULL; + } + /* 获取标签后半部分 */ + for (j = 0; i < len; ++i) { + if (wstr[i] == ' ') { + continue; + } + /* 标签结束,退出 */ + if (wstr[i] == ']') { + ++i; + break; + } + /* 保存标签内的数据 */ + data[j] = (char)wstr[i]; + ++j; + } + data[j] = 0; + if (i >= len) { + return NULL; + } + return wstr + i; } static bool pd_parse_color(const char *str, pd_color_t *value) { - size_t len = strlen(str); - int r, g, b; + size_t len = strlen(str); + int r, g, b; - if (str[0] != '#') { - return false; - } - if (len == 4) { - len = sscanf(str, "#%1X%1X%1X", &r, &g, &b); - r *= 255 / 0xf; - g *= 255 / 0xf; - b *= 255 / 0xf; - } else if (len == 7) { - len = sscanf(str, "#%2X%2X%2X", &r, &g, &b); - } else { - return false; - } - if (len == 3) { - value->r = r; - value->g = g; - value->b = b; - value->a = 255; - return true; - } - return false; + if (str[0] != '#') { + return false; + } + if (len == 4) { + len = sscanf(str, "#%1X%1X%1X", &r, &g, &b); + r *= 255 / 0xf; + g *= 255 / 0xf; + b *= 255 / 0xf; + } else if (len == 7) { + len = sscanf(str, "#%2X%2X%2X", &r, &g, &b); + } else { + return false; + } + if (len == 3) { + value->r = r; + value->g = g; + value->b = b; + value->a = 255; + return true; + } + return false; } /** 根据字符串中的标签得到相应的样式数据,并返回指向标签后面字符的指针 */ static const wchar_t *pd_scan_style_tag_by_name_data(const wchar_t *wstr, - pd_style_tag_t *tag) + pd_style_tag_t *tag) { - const wchar_t *p, *q; - char tag_data[256]; + const wchar_t *p, *q; + char tag_data[256]; - p = wstr; - if ((q = pd_scan_style_tag_by_name(p, L"color", tag_data))) { - if (!pd_parse_color(tag_data, &tag->data.color)) { - return NULL; - } - tag->id = PD_TEXT_STYLE_TYPE_COLOR; - return q; - } - if ((q = pd_scan_style_tag_by_name(p, L"bgcolor", tag_data))) { - if (pd_parse_color(tag_data, &tag->data.color) != 1) { - return NULL; - } - tag->id = PD_TEXT_STYLE_TYPE_BG_COLOR; - return q; - } - if ((q = pd_scan_style_tag_by_name(p, L"size", tag_data))) { - if (sscanf(tag_data, "%d", &tag->data.number) != 1) { - return NULL; - } - tag->id = PD_TEXT_STYLE_TYPE_SIZE; - return q; - } - if ((q = pd_scan_style_tag_by_name(p, L"b", tag_data))) { - tag->id = PD_TEXT_STYLE_TYPE_BOLD; - return q; - } - if ((q = pd_scan_style_tag_by_name(p, L"i", tag_data))) { - tag->id = PD_TEXT_STYLE_TYPE_ITALIC; - return q; - } - return NULL; + p = wstr; + if ((q = pd_scan_style_tag_by_name(p, L"color", tag_data))) { + if (!pd_parse_color(tag_data, &tag->data.color)) { + return NULL; + } + tag->id = PD_TEXT_STYLE_TYPE_COLOR; + return q; + } + if ((q = pd_scan_style_tag_by_name(p, L"bgcolor", tag_data))) { + if (pd_parse_color(tag_data, &tag->data.color) != 1) { + return NULL; + } + tag->id = PD_TEXT_STYLE_TYPE_BG_COLOR; + return q; + } + if ((q = pd_scan_style_tag_by_name(p, L"size", tag_data))) { + if (sscanf(tag_data, "%d", &tag->data.number) != 1) { + return NULL; + } + tag->id = PD_TEXT_STYLE_TYPE_SIZE; + return q; + } + if ((q = pd_scan_style_tag_by_name(p, L"b", tag_data))) { + tag->id = PD_TEXT_STYLE_TYPE_BOLD; + return q; + } + if ((q = pd_scan_style_tag_by_name(p, L"i", tag_data))) { + tag->id = PD_TEXT_STYLE_TYPE_ITALIC; + return q; + } + return NULL; } const wchar_t *pd_style_tags_next_open_tag(list_t *tags, const wchar_t *str) { - const wchar_t *q; - pd_style_tag_t *tag; + const wchar_t *q; + pd_style_tag_t *tag; - tag = malloc(sizeof(pd_style_tag_t)); - q = pd_scan_style_tag_by_name_data(str, tag); - if (q) { - /* 将标签样式数据加入队列 */ - list_insert(tags, 0, tag); - } else { - free(tag); - } - return q; + tag = malloc(sizeof(pd_style_tag_t)); + q = pd_scan_style_tag_by_name_data(str, tag); + if (q) { + /* 将标签样式数据加入队列 */ + list_insert(tags, 0, tag); + } else { + free(tag); + } + return q; } const wchar_t *pd_style_tags_next_close_tag(list_t *tags, const wchar_t *str) { - const wchar_t *p; - wchar_t tagname[256]; - /* 获取标签名 */ - p = pd_scan_style_close_tag(str, tagname); - if (!p) { - return NULL; - } - /* 删除相应的样式标签 */ - if (wcscmp(tagname, L"color") == 0) { - pd_style_tags_remove(tags, PD_TEXT_STYLE_TYPE_COLOR); - } else if (wcscmp(tagname, L"bgcolor") == 0) { - pd_style_tags_remove(tags, PD_TEXT_STYLE_TYPE_BG_COLOR); - } else if (wcscmp(tagname, L"size") == 0) { - pd_style_tags_remove(tags, PD_TEXT_STYLE_TYPE_SIZE); - } else if (wcscmp(tagname, L"b") == 0) { - pd_style_tags_remove(tags, PD_TEXT_STYLE_TYPE_BOLD); - } else if (wcscmp(tagname, L"i") == 0) { - pd_style_tags_remove(tags, PD_TEXT_STYLE_TYPE_ITALIC); - } else { - return NULL; - } - return p; + const wchar_t *p; + wchar_t tagname[256]; + /* 获取标签名 */ + p = pd_scan_style_close_tag(str, tagname); + if (!p) { + return NULL; + } + /* 删除相应的样式标签 */ + if (wcscmp(tagname, L"color") == 0) { + pd_style_tags_remove(tags, PD_TEXT_STYLE_TYPE_COLOR); + } else if (wcscmp(tagname, L"bgcolor") == 0) { + pd_style_tags_remove(tags, PD_TEXT_STYLE_TYPE_BG_COLOR); + } else if (wcscmp(tagname, L"size") == 0) { + pd_style_tags_remove(tags, PD_TEXT_STYLE_TYPE_SIZE); + } else if (wcscmp(tagname, L"b") == 0) { + pd_style_tags_remove(tags, PD_TEXT_STYLE_TYPE_BOLD); + } else if (wcscmp(tagname, L"i") == 0) { + pd_style_tags_remove(tags, PD_TEXT_STYLE_TYPE_ITALIC); + } else { + return NULL; + } + return p; } diff --git a/lib/pandagl/src/text/text.c b/lib/pandagl/src/text/text.c index b86fd9ddd..ec9aec976 100644 --- a/lib/pandagl/src/text/text.c +++ b/lib/pandagl/src/text/text.c @@ -1,12 +1,15 @@ /* * lib/pandagl/src/text/text.c * - * Copyright (c) 2018-2026, Liu Chao All rights reserved. + * Copyright (c) 2018-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -164,11 +167,11 @@ void pd_text_line_erase(pd_text_line_t *line, int start, int end) } } -/* 将 src 行 [src_start, src_end) 的字符所有权转移到 dst 行的 dst_start 起始位置。 - * 转移后 src 对应槽位被置 NULL,防止 delete_line 时被重复释放。 +/* 将 src 行 [src_start, src_end) 的字符所有权转移到 dst 行的 dst_start + * 起始位置。 转移后 src 对应槽位被置 NULL,防止 delete_line 时被重复释放。 * 调用者负责保证 dst 已有足够容量。 */ -void pd_text_line_move(pd_text_line_t *dst, int dst_start, - pd_text_line_t *src, int src_start, int src_end) +void pd_text_line_move(pd_text_line_t *dst, int dst_start, pd_text_line_t *src, + int src_start, int src_end) { int i, j; @@ -181,8 +184,7 @@ void pd_text_line_move(pd_text_line_t *dst, int dst_start, } } -int pd_text_line_insert(pd_text_line_t *line, int offset, - pd_char_t *txtchar) +int pd_text_line_insert(pd_text_line_t *line, int offset, pd_char_t *txtchar) { size_t i, insert_index; @@ -205,7 +207,7 @@ int pd_text_line_insert(pd_text_line_t *line, int offset, } int pd_text_line_insert_copy(pd_text_line_t *line, int ins_pos, - pd_char_t *txtchar) + pd_char_t *txtchar) { pd_char_t *txtchar2; txtchar2 = malloc(sizeof(pd_char_t)); @@ -343,7 +345,7 @@ void pd_text_request_typeset(pd_text_t *text, int start_line) /** 获取指定文本行中的文本段的矩形区域 */ int pd_text_get_line_rect(pd_text_t *text, int line_num, int start_col, - int end_col, pd_rect_t *rect) + int end_col, pd_rect_t *rect) { int i; pd_text_line_t *line; @@ -388,8 +390,7 @@ int pd_text_get_line_rect(pd_text_t *text, int line_num, int start_col, return 0; } -void pd_text_mark_line_dirty(pd_text_t *text, int line_num, int start, - int end) +void pd_text_mark_line_dirty(pd_text_t *text, int line_num, int start, int end) { pd_rect_t rect; if (pd_text_get_line_rect(text, line_num, start, end, &rect) == 0) { diff --git a/lib/pandagl/src/text/text_edit.c b/lib/pandagl/src/text/text_edit.c index c630b40f0..67e9b79c5 100644 --- a/lib/pandagl/src/text/text_edit.c +++ b/lib/pandagl/src/text/text_edit.c @@ -1,12 +1,15 @@ /* * lib/pandagl/src/text/text_edit.c * - * Copyright (c) 2018-2026, Liu Chao All rights reserved. + * Copyright (c) 2018-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -87,7 +90,7 @@ int pd_text_set_caret_pixel(pd_text_t *text, int x, int y) /** 获取指定行列的文字的像素坐标 */ int pd_text_get_char_pixel(pd_text_t *text, int line_num, int col, - pd_pos_t *pixel_pos) + pd_pos_t *pixel_pos) { pd_text_line_t *line; int i, pixel_x = 0, pixel_y = 0; @@ -120,8 +123,8 @@ int pd_text_get_char_pixel(pd_text_t *text, int line_num, int col, int pd_text_get_caret_pixel(pd_text_t *text, pd_pos_t *pixel_pos) { - return pd_text_get_char_pixel(text, text->caret.y, - text->caret.x, pixel_pos); + return pd_text_get_char_pixel(text, text->caret.y, text->caret.x, + pixel_pos); } static const wchar_t *pd_text_process_style_tags(pd_text_t *text, diff --git a/lib/pandagl/src/text/text_internal.h b/lib/pandagl/src/text/text_internal.h index e02c0eb21..313cfd0bc 100644 --- a/lib/pandagl/src/text/text_internal.h +++ b/lib/pandagl/src/text/text_internal.h @@ -1,16 +1,15 @@ -/* +/* * lib/pandagl/src/text/text_internal.h * - * Copyright (c) 2018-2026, Liu Chao All rights reserved. + * Copyright (c) 2018-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. - * - * Library-private helpers shared between text.c, text_typeset.c, - * text_render.c and text_edit.c. Not installed into the public include - * directory. */ #ifndef LIB_PANDAGL_SRC_TEXT_TEXT_INTERNAL_H @@ -26,21 +25,19 @@ int pd_text_delete_line(pd_text_t *text, int line_num); /* line-level helpers */ int pd_text_line_set_length(pd_text_line_t *line, int len); -int pd_text_line_insert(pd_text_line_t *line, int offset, - pd_char_t *txtchar); +int pd_text_line_insert(pd_text_line_t *line, int offset, pd_char_t *txtchar); int pd_text_line_insert_copy(pd_text_line_t *line, int ins_pos, pd_char_t *txtchar); void pd_text_line_erase(pd_text_line_t *line, int start, int end); -void pd_text_line_move(pd_text_line_t *dst, int dst_start, - pd_text_line_t *src, int src_start, int src_end); +void pd_text_line_move(pd_text_line_t *dst, int dst_start, pd_text_line_t *src, + int src_start, int src_end); /* line geometry */ void pd_text_update_line_size(pd_text_t *text, pd_text_line_t *line); int pd_text_get_line_start_x(pd_text_t *text, pd_text_line_t *line); int pd_text_get_line_rect(pd_text_t *text, int line_num, int start_col, int end_col, pd_rect_t *rect); -void pd_text_mark_line_dirty(pd_text_t *text, int line_num, int start, - int end); +void pd_text_mark_line_dirty(pd_text_t *text, int line_num, int start, int end); /* render helpers */ void pd_char_update_bitmap(pd_char_t *ch, pd_text_style_t *style); diff --git a/lib/pandagl/src/text/text_render.c b/lib/pandagl/src/text/text_render.c index 619eae5d1..71810ca08 100644 --- a/lib/pandagl/src/text/text_render.c +++ b/lib/pandagl/src/text/text_render.c @@ -1,12 +1,15 @@ /* * lib/pandagl/src/text/text_render.c * - * Copyright (c) 2018-2026, Liu Chao All rights reserved. + * Copyright (c) 2018-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -28,8 +31,8 @@ void pd_char_update_bitmap(pd_char_t *ch, pd_text_style_t *style) } } while (font_ids && font_ids[i] > 0) { - int ret = pd_font_cache_get_bitmap(ch->code, font_ids[i], - size, &ch->bitmap); + int ret = pd_font_cache_get_bitmap(ch->code, font_ids[i], size, + &ch->bitmap); if (ret == 0) { return; } @@ -90,10 +93,10 @@ static void pd_text_render_char(pd_text_t *text, pd_char_t *ch, /* 判断文字使用的前景颜色,再进行绘制 */ if (ch->style && ch->style->has_fore_color) { pd_canvas_mix_glyph_bitmap(graph, ch_pos, ch->bitmap, - ch->style->fore_color); + ch->style->fore_color); } else { pd_canvas_mix_glyph_bitmap(graph, ch_pos, ch->bitmap, - text->default_style.fore_color); + text->default_style.fore_color); } } diff --git a/lib/pandagl/src/text/text_typeset.c b/lib/pandagl/src/text/text_typeset.c index 038915b66..b3767fdf9 100644 --- a/lib/pandagl/src/text/text_typeset.c +++ b/lib/pandagl/src/text/text_typeset.c @@ -1,11 +1,14 @@ /* * lib/pandagl/src/text/text_typeset.c * - * Copyright (c) 2018-2026, Liu Chao All rights reserved. + * Copyright (c) 2018-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ @@ -16,7 +19,7 @@ #define isalpha_(ch) ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) void pd_text_break_line(pd_text_t *text, int line_num, int col, - pd_text_eol_t eol) + pd_text_eol_t eol) { int n; pd_text_line_t *line, *next; diff --git a/lib/pandagl/src/tile.c b/lib/pandagl/src/tile.c index 81a7ded93..c7599eb34 100644 --- a/lib/pandagl/src/tile.c +++ b/lib/pandagl/src/tile.c @@ -1,33 +1,36 @@ /* * lib/pandagl/src/tile.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include -int pd_canvas_tile(pd_canvas_t *buff, const pd_canvas_t *canvas, - bool replace, bool with_alpha) +int pd_canvas_tile(pd_canvas_t *buff, const pd_canvas_t *canvas, bool replace, + bool with_alpha) { - int ret = 0; - unsigned x, y; + int ret = 0; + unsigned x, y; - if (!pd_canvas_is_valid(canvas) || !pd_canvas_is_valid(buff)) { - return -1; - } - for (y = 0; y < buff->height; y += canvas->height) { - for (x = 0; x < buff->width; x += canvas->width) { - if (replace) { - ret += pd_canvas_replace(buff, canvas, y, x); - continue; - } - ret += pd_canvas_mix(buff, canvas, y, x, with_alpha); - } - } - return ret; + if (!pd_canvas_is_valid(canvas) || !pd_canvas_is_valid(buff)) { + return -1; + } + for (y = 0; y < buff->height; y += canvas->height) { + for (x = 0; x < buff->width; x += canvas->width) { + if (replace) { + ret += pd_canvas_replace(buff, canvas, y, x); + continue; + } + ret += pd_canvas_mix(buff, canvas, y, x, with_alpha); + } + } + return ret; } diff --git a/lib/pandagl/src/zoom.c b/lib/pandagl/src/zoom.c index 8ba2a16b0..f2a60c59d 100644 --- a/lib/pandagl/src/zoom.c +++ b/lib/pandagl/src/zoom.c @@ -1,176 +1,179 @@ /* * lib/pandagl/src/zoom.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include static uint8_t canvas_bilinear_resampling_core(uint8_t a, uint8_t b, uint8_t c, - uint8_t d, float dx, float dy) + uint8_t d, float dx, float dy) { - return (uint8_t)(a * (1 - dx) * (1 - dy) + b * (dx) * (1 - dy) + - c * (dy) * (1 - dx) + d * (dx * dy)); + return (uint8_t)(a * (1 - dx) * (1 - dy) + b * (dx) * (1 - dy) + + c * (dy) * (1 - dx) + d * (dx * dy)); } int pd_canvas_zoom(const pd_canvas_t *canvas, pd_canvas_t *buff, - bool keep_scale, int width, int height) + bool keep_scale, int width, int height) { - pd_rect_t rect; - int x, y, src_x, src_y; - double scale_x = 0.0, scale_y = 0.0; + pd_rect_t rect; + int x, y, src_x, src_y; + double scale_x = 0.0, scale_y = 0.0; - if (!pd_canvas_is_valid(canvas) || (width <= 0 && height <= 0)) { - return -1; - } - /* 获取引用的有效区域,以及指向引用的对象的指针 */ - pd_canvas_get_quote_rect(canvas, &rect); - canvas = pd_canvas_get_quote_source_readonly(canvas); - if (width > 0) { - scale_x = 1.0 * rect.width / width; - } - if (height > 0) { - scale_y = 1.0 * rect.height / height; - } - if (width <= 0) { - scale_x = scale_y; - width = (int)(0.5 + 1.0 * canvas->width / scale_x); - } - if (height <= 0) { - scale_y = scale_x; - height = (int)(0.5 + 1.0 * canvas->height / scale_y); - } - /* 如果保持宽高比 */ - if (keep_scale) { - if (scale_x < scale_y) { - scale_y = scale_x; - } else { - scale_x = scale_y; - } - } - buff->color_type = canvas->color_type; - if (pd_canvas_create(buff, width, height) < 0) { - return -2; - } - if (canvas->color_type == PD_COLOR_TYPE_ARGB) { - pd_color_t *px_src, *px_des, *px_row_src; - for (y = 0; y < height; ++y) { - src_y = (int)(y * scale_y); - px_row_src = canvas->argb; - px_row_src += (src_y + rect.y) * canvas->width + rect.x; - px_des = buff->argb + y * width; - for (x = 0; x < width; ++x) { - src_x = (int)(x * scale_x); - px_src = px_row_src + src_x; - *px_des++ = *px_src; - } - } - } else { - uint8_t *byte_src, *byte_des, *byte_row_src; - for (y = 0; y < height; ++y) { - byte_row_src = pd_canvas_pixel_at( - canvas, rect.x, (int)(y * scale_y) + rect.y); - byte_des = pd_canvas_pixel_at(buff, 0, y); - for (x = 0; x < width; ++x) { - src_x = (int)(x * scale_x); - src_x *= canvas->bytes_per_pixel; - byte_src = byte_row_src + src_x; - *byte_des++ = *byte_src++; - *byte_des++ = *byte_src++; - *byte_des++ = *byte_src; - } - } - } - return 0; + if (!pd_canvas_is_valid(canvas) || (width <= 0 && height <= 0)) { + return -1; + } + /* 获取引用的有效区域,以及指向引用的对象的指针 */ + pd_canvas_get_quote_rect(canvas, &rect); + canvas = pd_canvas_get_quote_source_readonly(canvas); + if (width > 0) { + scale_x = 1.0 * rect.width / width; + } + if (height > 0) { + scale_y = 1.0 * rect.height / height; + } + if (width <= 0) { + scale_x = scale_y; + width = (int)(0.5 + 1.0 * canvas->width / scale_x); + } + if (height <= 0) { + scale_y = scale_x; + height = (int)(0.5 + 1.0 * canvas->height / scale_y); + } + /* 如果保持宽高比 */ + if (keep_scale) { + if (scale_x < scale_y) { + scale_y = scale_x; + } else { + scale_x = scale_y; + } + } + buff->color_type = canvas->color_type; + if (pd_canvas_create(buff, width, height) < 0) { + return -2; + } + if (canvas->color_type == PD_COLOR_TYPE_ARGB) { + pd_color_t *px_src, *px_des, *px_row_src; + for (y = 0; y < height; ++y) { + src_y = (int)(y * scale_y); + px_row_src = canvas->argb; + px_row_src += (src_y + rect.y) * canvas->width + rect.x; + px_des = buff->argb + y * width; + for (x = 0; x < width; ++x) { + src_x = (int)(x * scale_x); + px_src = px_row_src + src_x; + *px_des++ = *px_src; + } + } + } else { + uint8_t *byte_src, *byte_des, *byte_row_src; + for (y = 0; y < height; ++y) { + byte_row_src = pd_canvas_pixel_at( + canvas, rect.x, (int)(y * scale_y) + rect.y); + byte_des = pd_canvas_pixel_at(buff, 0, y); + for (x = 0; x < width; ++x) { + src_x = (int)(x * scale_x); + src_x *= canvas->bytes_per_pixel; + byte_src = byte_row_src + src_x; + *byte_des++ = *byte_src++; + *byte_des++ = *byte_src++; + *byte_des++ = *byte_src; + } + } + } + return 0; } int pd_canvas_zoom_bilinear(const pd_canvas_t *canvas, pd_canvas_t *buff, - bool keep_scale, int width, int height) + bool keep_scale, int width, int height) { - pd_rect_t rect; - pd_color_t a, b, c, d, t_color; + pd_rect_t rect; + pd_color_t a, b, c, d, t_color; - int x, y, i, j; - float x_diff, y_diff; - double scale_x = 0.0, scale_y = 0.0; + int x, y, i, j; + float x_diff, y_diff; + double scale_x = 0.0, scale_y = 0.0; - if (canvas->color_type != PD_COLOR_TYPE_RGB && - canvas->color_type != PD_COLOR_TYPE_ARGB) { - /* fall back to nearest scaling */ - logger_debug("[canvas] unable to perform bilinear scaling, " - "fallback...\n"); - return pd_canvas_zoom(canvas, buff, keep_scale, width, height); - } - if (!pd_canvas_is_valid(canvas) || (width <= 0 && height <= 0)) { - return -1; - } - /* 获取引用的有效区域,以及指向引用的对象的指针 */ - pd_canvas_get_quote_rect(canvas, &rect); - canvas = pd_canvas_get_quote_source_readonly(canvas); - if (width > 0) { - scale_x = 1.0 * rect.width / width; - } - if (height > 0) { - scale_y = 1.0 * rect.height / height; - } - if (width <= 0) { - scale_x = scale_y; - width = (int)(0.5 + 1.0 * canvas->width / scale_x); - } - if (height <= 0) { - scale_y = scale_x; - height = (int)(0.5 + 1.0 * canvas->height / scale_y); - } - /* 如果保持宽高比 */ - if (keep_scale) { - if (scale_x < scale_y) { - scale_y = scale_x; - } else { - scale_x = scale_y; - } - } - buff->color_type = canvas->color_type; - if (pd_canvas_create(buff, width, height) < 0) { - return -2; - } - for (i = 0; i < height; i++) { - for (j = 0; j < width; j++) { - /* - * Qmn = (m, n). - * Qxy1 = (x2 - x) / (x2 - x1) * Q11 + (x - x1) / (x2 - * - x1) * Q21 - * Qxy2 = (x2 - x) / (x2 - x1) * Q12 + (x - x1) / (x2 - * - x1) * Q22 - * Qxy = (y2 - y) / (y2 - y1) * Qxy1 + (y - y1) / (y2 - - * y1) * Qxy2 - */ - x = (int)(scale_x * j); - y = (int)(scale_y * i); - x_diff = (float)((scale_x * j) - x); - y_diff = (float)((scale_y * i) - y); - a = pd_canvas_get_pixel(canvas, x + rect.x + 0, - y + rect.y + 0); - b = pd_canvas_get_pixel(canvas, x + rect.x + 1, - y + rect.y + 0); - c = pd_canvas_get_pixel(canvas, x + rect.x + 0, - y + rect.y + 1); - d = pd_canvas_get_pixel(canvas, x + rect.x + 1, - y + rect.y + 1); - t_color.b = canvas_bilinear_resampling_core( - a.b, b.b, c.b, d.b, x_diff, y_diff); - t_color.g = canvas_bilinear_resampling_core( - a.g, b.g, c.g, d.g, x_diff, y_diff); - t_color.r = canvas_bilinear_resampling_core( - a.r, b.r, c.r, d.r, x_diff, y_diff); - t_color.a = canvas_bilinear_resampling_core( - a.a, b.a, c.a, d.a, x_diff, y_diff); - pd_canvas_set_pixel(buff, j, i, t_color); - } - } - return 0; + if (canvas->color_type != PD_COLOR_TYPE_RGB && + canvas->color_type != PD_COLOR_TYPE_ARGB) { + /* fall back to nearest scaling */ + logger_debug("[canvas] unable to perform bilinear scaling, " + "fallback...\n"); + return pd_canvas_zoom(canvas, buff, keep_scale, width, height); + } + if (!pd_canvas_is_valid(canvas) || (width <= 0 && height <= 0)) { + return -1; + } + /* 获取引用的有效区域,以及指向引用的对象的指针 */ + pd_canvas_get_quote_rect(canvas, &rect); + canvas = pd_canvas_get_quote_source_readonly(canvas); + if (width > 0) { + scale_x = 1.0 * rect.width / width; + } + if (height > 0) { + scale_y = 1.0 * rect.height / height; + } + if (width <= 0) { + scale_x = scale_y; + width = (int)(0.5 + 1.0 * canvas->width / scale_x); + } + if (height <= 0) { + scale_y = scale_x; + height = (int)(0.5 + 1.0 * canvas->height / scale_y); + } + /* 如果保持宽高比 */ + if (keep_scale) { + if (scale_x < scale_y) { + scale_y = scale_x; + } else { + scale_x = scale_y; + } + } + buff->color_type = canvas->color_type; + if (pd_canvas_create(buff, width, height) < 0) { + return -2; + } + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + /* + * Qmn = (m, n). + * Qxy1 = (x2 - x) / (x2 - x1) * Q11 + (x - x1) / (x2 + * - x1) * Q21 + * Qxy2 = (x2 - x) / (x2 - x1) * Q12 + (x - x1) / (x2 + * - x1) * Q22 + * Qxy = (y2 - y) / (y2 - y1) * Qxy1 + (y - y1) / (y2 - + * y1) * Qxy2 + */ + x = (int)(scale_x * j); + y = (int)(scale_y * i); + x_diff = (float)((scale_x * j) - x); + y_diff = (float)((scale_y * i) - y); + a = pd_canvas_get_pixel(canvas, x + rect.x + 0, + y + rect.y + 0); + b = pd_canvas_get_pixel(canvas, x + rect.x + 1, + y + rect.y + 0); + c = pd_canvas_get_pixel(canvas, x + rect.x + 0, + y + rect.y + 1); + d = pd_canvas_get_pixel(canvas, x + rect.x + 1, + y + rect.y + 1); + t_color.b = canvas_bilinear_resampling_core( + a.b, b.b, c.b, d.b, x_diff, y_diff); + t_color.g = canvas_bilinear_resampling_core( + a.g, b.g, c.g, d.g, x_diff, y_diff); + t_color.r = canvas_bilinear_resampling_core( + a.r, b.r, c.r, d.r, x_diff, y_diff); + t_color.a = canvas_bilinear_resampling_core( + a.a, b.a, c.a, d.a, x_diff, y_diff); + pd_canvas_set_pixel(buff, j, i, t_color); + } + } + return 0; } diff --git a/lib/pandagl/tests/main.c b/lib/pandagl/tests/main.c index e869d8c90..ba0b106b5 100644 --- a/lib/pandagl/tests/main.c +++ b/lib/pandagl/tests/main.c @@ -1,12 +1,15 @@ -/* +/* * lib/pandagl/tests/main.c * - * Copyright (c) 2026, Liu Chao All rights reserved. + * Copyright (c) 2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is + * part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT + * file in the root directory of this source tree. */ #include diff --git a/lib/pandagl/tests/test_canvas_mix.c b/lib/pandagl/tests/test_canvas_mix.c index 739cdba4e..b58be3fac 100644 --- a/lib/pandagl/tests/test_canvas_mix.c +++ b/lib/pandagl/tests/test_canvas_mix.c @@ -1,11 +1,14 @@ /* - * lib/pandagl/test/test_canvas_mix.c + * lib/pandagl/tests/test_canvas_mix.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ diff --git a/lib/pandagl/tests/test_font_cache.c b/lib/pandagl/tests/test_font_cache.c index c9b8a3616..3a56b1663 100644 --- a/lib/pandagl/tests/test_font_cache.c +++ b/lib/pandagl/tests/test_font_cache.c @@ -1,12 +1,15 @@ /* * lib/pandagl/tests/test_font_cache.c * - * Copyright (c) 2026, Liu Chao All rights reserved. + * Copyright (c) 2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/pandagl/tests/test_font_load.c b/lib/pandagl/tests/test_font_load.c index 90512893b..1c6ad5e8a 100644 --- a/lib/pandagl/tests/test_font_load.c +++ b/lib/pandagl/tests/test_font_load.c @@ -1,12 +1,15 @@ -/* +/* * lib/pandagl/tests/test_font_load.c * - * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -24,30 +27,22 @@ static void test_segoe_ui_font_load(void) if (pd_font_load_file("C:/windows/fonts/segoeui.ttf") != 0) { return; } - ctest_equal_int( - "should load segoeui.ttf", - pd_font_load_file("C:/windows/fonts/segoeui.ttf"), 0); - ctest_equal_int( - "should load segoeuib.ttf", - pd_font_load_file("C:/windows/fonts/segoeuib.ttf"), 0); - ctest_equal_int( - "should load segoeuii.ttf", - pd_font_load_file("C:/windows/fonts/segoeuii.ttf"), 0); - ctest_equal_int( - "should load segoeuil.ttf", - pd_font_load_file("C:/windows/fonts/segoeuil.ttf"), 0); - ctest_equal_int( - "should load segoeuisl.ttf", - pd_font_load_file("C:/windows/fonts/segoeuisl.ttf"), 0); - ctest_equal_int( - "should load segoeuiz.ttf", - pd_font_load_file("C:/windows/fonts/segoeuiz.ttf"), 0); - ctest_equal_int( - "should load seguibl.ttf", - pd_font_load_file("C:/windows/fonts/seguibl.ttf"), 0); - ctest_equal_int( - "should load seguili.ttf", - pd_font_load_file("C:/windows/fonts/seguili.ttf"), 0); + ctest_equal_int("should load segoeui.ttf", + pd_font_load_file("C:/windows/fonts/segoeui.ttf"), 0); + ctest_equal_int("should load segoeuib.ttf", + pd_font_load_file("C:/windows/fonts/segoeuib.ttf"), 0); + ctest_equal_int("should load segoeuii.ttf", + pd_font_load_file("C:/windows/fonts/segoeuii.ttf"), 0); + ctest_equal_int("should load segoeuil.ttf", + pd_font_load_file("C:/windows/fonts/segoeuil.ttf"), 0); + ctest_equal_int("should load segoeuisl.ttf", + pd_font_load_file("C:/windows/fonts/segoeuisl.ttf"), 0); + ctest_equal_int("should load segoeuiz.ttf", + pd_font_load_file("C:/windows/fonts/segoeuiz.ttf"), 0); + ctest_equal_int("should load seguibl.ttf", + pd_font_load_file("C:/windows/fonts/seguibl.ttf"), 0); + ctest_equal_int("should load seguili.ttf", + pd_font_load_file("C:/windows/fonts/seguili.ttf"), 0); id = GetSegoeUIFont(PD_FONT_STYLE_NORMAL, PD_FONT_WEIGHT_NORMAL); ctest_equal_bool("should resolve font (style: normal, weight: normal)", id > 0, true); @@ -108,18 +103,14 @@ static void test_arial_font_load(void) if (pd_font_load_file("C:/windows/fonts/arial.ttf") != 0) { return; } - ctest_equal_int( - "should load arialbd.ttf", - pd_font_load_file("C:/windows/fonts/arialbd.ttf"), 0); - ctest_equal_int( - "should load ariblk.ttf", - pd_font_load_file("C:/windows/fonts/ariblk.ttf"), 0); - ctest_equal_int( - "should load arialbi.ttf", - pd_font_load_file("C:/windows/fonts/arialbi.ttf"), 0); - ctest_equal_int( - "should load ariali.ttf", - pd_font_load_file("C:/windows/fonts/ariali.ttf"), 0); + ctest_equal_int("should load arialbd.ttf", + pd_font_load_file("C:/windows/fonts/arialbd.ttf"), 0); + ctest_equal_int("should load ariblk.ttf", + pd_font_load_file("C:/windows/fonts/ariblk.ttf"), 0); + ctest_equal_int("should load arialbi.ttf", + pd_font_load_file("C:/windows/fonts/arialbi.ttf"), 0); + ctest_equal_int("should load ariali.ttf", + pd_font_load_file("C:/windows/fonts/ariali.ttf"), 0); id = GetArialFont(PD_FONT_STYLE_NORMAL, PD_FONT_WEIGHT_NORMAL); ctest_equal_bool("should resolve font (style: normal, weight: normal)", id > 0, true); diff --git a/lib/pandagl/tests/test_image_reader.c b/lib/pandagl/tests/test_image_reader.c index ab0553420..a00ef528e 100644 --- a/lib/pandagl/tests/test_image_reader.c +++ b/lib/pandagl/tests/test_image_reader.c @@ -1,11 +1,14 @@ /* * lib/pandagl/tests/test_image_reader.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ diff --git a/lib/pandagl/tests/test_text_edit.c b/lib/pandagl/tests/test_text_edit.c index d3b6f8161..88a3f7fe0 100644 --- a/lib/pandagl/tests/test_text_edit.c +++ b/lib/pandagl/tests/test_text_edit.c @@ -1,12 +1,15 @@ /* * lib/pandagl/tests/test_text_edit.c * - * Copyright (c) 2026, Liu Chao All rights reserved. + * Copyright (c) 2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -53,8 +56,8 @@ static void should_backspace_then_continue_typing(void) pd_text_insert(text, L"X", NULL); ctest_equal_int("should merge into two lines after backspace + insert", pd_text_get_lines_length(text), 2); - ctest_equal_int("line 0 keeps 'abc'", - pd_text_get_line_length(text, 0), 3); + ctest_equal_int("line 0 keeps 'abc'", pd_text_get_line_length(text, 0), + 3); ctest_equal_int("line 1 becomes 'defX'", pd_text_get_line_length(text, 1), 4); pd_text_destroy(text); @@ -87,8 +90,8 @@ static void should_delete_char_at_caret(void) ctest_equal_int("should delete one char", pd_text_delete(text, 1), 0); pd_text_read(text, 0, 16, buf); ctest_equal_wcs("should produce expected text", buf, L"abdef"); - ctest_equal_int("line length is 5", - pd_text_get_line_length(text, 0), 5); + ctest_equal_int("line length is 5", pd_text_get_line_length(text, 0), + 5); pd_text_destroy(text); } @@ -105,8 +108,8 @@ static void should_join_next_line_when_delete_at_line_end(void) pd_text_delete(text, 1), 0); ctest_equal_int("should reduce one line after merge", pd_text_get_lines_length(text), 2); - ctest_equal_int("line 0 keeps 'abc'", - pd_text_get_line_length(text, 0), 3); + ctest_equal_int("line 0 keeps 'abc'", pd_text_get_line_length(text, 0), + 3); ctest_equal_int("line 1 becomes 'defghi' (6 chars)", pd_text_get_line_length(text, 1), 6); pd_text_destroy(text); @@ -125,8 +128,8 @@ static void should_preserve_chars_when_joining_lines(void) pd_text_get_lines_length(text), 2); ctest_equal_int("line 0 becomes 'abcdef' (6 chars)", pd_text_get_line_length(text, 0), 6); - ctest_equal_int("line 1 stays empty", - pd_text_get_line_length(text, 1), 0); + ctest_equal_int("line 1 stays empty", pd_text_get_line_length(text, 1), + 0); pd_text_destroy(text); } @@ -255,8 +258,7 @@ void test_pandagl_text_edit(void) ctest_describe("text backspace sequence", should_handle_multi_line_backspace_sequence); ctest_describe("text dump single line", should_dump_single_line); - ctest_describe("text dump multiline lf", - should_dump_multiline_with_lf); + ctest_describe("text dump multiline lf", should_dump_multiline_with_lf); ctest_describe("text dump trailing newline", should_dump_multiline_with_trailing_newline); ctest_describe("text dump max len", should_dump_respect_max_len); diff --git a/lib/ptk/include/ptk.h b/lib/ptk/include/ptk.h index e3abaafd8..acd1a913c 100644 --- a/lib/ptk/include/ptk.h +++ b/lib/ptk/include/ptk.h @@ -1,12 +1,15 @@ /* * lib/ptk/include/ptk.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef PTK_INCLUDE_PLATFORM_H diff --git a/lib/ptk/include/ptk/app.h b/lib/ptk/include/ptk/app.h index 36e861762..0f0fabc22 100644 --- a/lib/ptk/include/ptk/app.h +++ b/lib/ptk/include/ptk/app.h @@ -1,12 +1,15 @@ /* * lib/ptk/include/ptk/app.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef PTK_INCLUDE_PLATFORM_APP_H diff --git a/lib/ptk/include/ptk/clipboard.h b/lib/ptk/include/ptk/clipboard.h index 2ba29637e..a8cfbaba6 100644 --- a/lib/ptk/include/ptk/clipboard.h +++ b/lib/ptk/include/ptk/clipboard.h @@ -1,12 +1,15 @@ /* * lib/ptk/include/ptk/clipboard.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef PTK_INCLUDE_PLATFORM_CLIPBOARD_H @@ -23,14 +26,15 @@ PTK_BEGIN_DECLS */ typedef struct ptk_clipboard { - pd_canvas_t *image; - wchar_t *text; - size_t len; + pd_canvas_t *image; + wchar_t *text; + size_t len; } ptk_clipboard_t; typedef void (*ptk_clipboard_callback_t)(ptk_clipboard_t *, void *); -PTK_PUBLIC int ptk_clipboard_request_text(ptk_clipboard_callback_t action, void *arg); +PTK_PUBLIC int ptk_clipboard_request_text(ptk_clipboard_callback_t action, + void *arg); PTK_PUBLIC int ptk_clipboard_set_text(const wchar_t *text, size_t len); PTK_END_DECLS diff --git a/lib/ptk/include/ptk/common.h b/lib/ptk/include/ptk/common.h index 5eefc5094..8a4bb233b 100644 --- a/lib/ptk/include/ptk/common.h +++ b/lib/ptk/include/ptk/common.h @@ -1,12 +1,15 @@ /* * lib/ptk/include/ptk/common.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "config.h" @@ -39,12 +42,12 @@ #endif #ifdef _WIN32 - #define PTK_WIN32 - #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) - #define PTK_UWP - #else - #define PTK_WIN_DESKTOP - #endif +#define PTK_WIN32 +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +#define PTK_UWP +#else +#define PTK_WIN_DESKTOP +#endif #else - #define PTK_LINUX +#define PTK_LINUX #endif diff --git a/lib/ptk/include/ptk/events.h b/lib/ptk/include/ptk/events.h index a6eb9e982..2040abe6e 100644 --- a/lib/ptk/include/ptk/events.h +++ b/lib/ptk/include/ptk/events.h @@ -1,12 +1,15 @@ /* * lib/ptk/include/ptk/events.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef PTK_INCLUDE_PLATFORM_EVENTS_H @@ -20,50 +23,52 @@ PTK_BEGIN_DECLS PTK_PUBLIC int ptk_process_native_events(ptk_process_events_option_t option); PTK_PUBLIC int ptk_add_native_event_listener(int event_type, - ptk_native_event_handler_t handler, - void *data); + ptk_native_event_handler_t handler, + void *data); PTK_PUBLIC int ptk_remove_native_event_listener( int event_type, ptk_native_event_handler_t handler); PTK_INLINE int ptk_on_native_event(int event_type, - ptk_native_event_handler_t handler, void *data) + ptk_native_event_handler_t handler, + void *data) { - return ptk_add_native_event_listener(event_type, handler, data); + return ptk_add_native_event_listener(event_type, handler, data); } PTK_INLINE int ptk_off_native_event(int event_type, - ptk_native_event_handler_t handler) + ptk_native_event_handler_t handler) { - return ptk_remove_native_event_listener(event_type, handler); + return ptk_remove_native_event_listener(event_type, handler); } // Events PTK_PUBLIC int ptk_touch_event_init(ptk_event_t *e, touch_point_t *points, - int n_points); + int n_points); PTK_PUBLIC int ptk_composition_event_init(ptk_event_t *e, const wchar_t *text, - size_t len); + size_t len); PTK_PUBLIC int ptk_event_copy(ptk_event_t *dest, ptk_event_t *src); PTK_PUBLIC void ptk_event_destroy(ptk_event_t *e); PTK_PUBLIC int ptk_touch_event_init(ptk_event_t *e, touch_point_t *points, - int n_points); + int n_points); PTK_PUBLIC void ptk_tick(void); PTK_PUBLIC int ptk_post_event(ptk_event_t *e); PTK_PUBLIC int ptk_process_event(ptk_event_t *e); -PTK_PUBLIC int ptk_add_event_listener(int event_type, ptk_event_handler_t handler, - void *data); +PTK_PUBLIC int ptk_add_event_listener(int event_type, + ptk_event_handler_t handler, void *data); PTK_PUBLIC int ptk_remove_event_listener(int event_type, - ptk_event_handler_t handler); + ptk_event_handler_t handler); -PTK_INLINE int ptk_on_event(int event_type, ptk_event_handler_t handler, void *data) +PTK_INLINE int ptk_on_event(int event_type, ptk_event_handler_t handler, + void *data) { - return ptk_add_event_listener(event_type, handler, data); + return ptk_add_event_listener(event_type, handler, data); } PTK_INLINE int ptk_off_event(int event_type, ptk_event_handler_t handler) { - return ptk_remove_event_listener(event_type, handler); + return ptk_remove_event_listener(event_type, handler); } PTK_PUBLIC void ptk_set_event_dispatcher(ptk_event_dispatcher_t dispatcher); @@ -77,12 +82,12 @@ PTK_PUBLIC int ptk_reset_timer(int timer_id, long ms); PTK_INLINE int ptk_clear_timeout(int timer_id) { - return ptk_clear_timer(timer_id); + return ptk_clear_timer(timer_id); } PTK_INLINE int ptk_clear_interval(int timer_id) { - return ptk_clear_timer(timer_id); + return ptk_clear_timer(timer_id); } PTK_END_DECLS diff --git a/lib/ptk/include/ptk/ime.h b/lib/ptk/include/ptk/ime.h index bebd152e2..620f6b749 100644 --- a/lib/ptk/include/ptk/ime.h +++ b/lib/ptk/include/ptk/ime.h @@ -1,12 +1,15 @@ /* * lib/ptk/include/ptk/ime.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef PTK_INCLUDE_PLATFORM_IME_H @@ -18,11 +21,11 @@ PTK_BEGIN_DECLS typedef struct ptk_ime_handler { - bool (*prockey)(int, bool); - void (*totext)(int); - bool (*open)(void); - bool (*close)(void); - void (*setcaret)(int, int); + bool (*prockey)(int, bool); + void (*totext)(int); + bool (*open)(void); + bool (*close)(void); + void (*setcaret)(int, int); } ptk_ime_handler_t; PTK_PUBLIC int ptk_ime_add(const char *ime_name, ptk_ime_handler_t *handler); diff --git a/lib/ptk/include/ptk/main.h b/lib/ptk/include/ptk/main.h index 639308e16..41d3e71bd 100644 --- a/lib/ptk/include/ptk/main.h +++ b/lib/ptk/include/ptk/main.h @@ -1,7 +1,7 @@ /* * lib/ptk/include/ptk/main.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ptk/include/ptk/steptimer.h b/lib/ptk/include/ptk/steptimer.h index f0496db3e..a447a561b 100644 --- a/lib/ptk/include/ptk/steptimer.h +++ b/lib/ptk/include/ptk/steptimer.h @@ -1,12 +1,15 @@ /* * lib/ptk/include/ptk/steptimer.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef PTK_INCLUDE_PLATFORM_STEP_TIMER_H @@ -67,7 +70,7 @@ PTK_PUBLIC void ptk_steptimer_init(ptk_steptimer_t *timer); // Update timer state, calling the specified Update function the appropriate // number of times. PTK_PUBLIC void ptk_steptimer_tick(ptk_steptimer_t *timer, - ptk_steptimer_handler_t handler, void *data); + ptk_steptimer_handler_t handler, void *data); // After an intentional timing discontinuity (for instance a blocking IO // operation or a long pause), call this to avoid having the fixed timestep diff --git a/lib/ptk/include/ptk/types.h b/lib/ptk/include/ptk/types.h index affed0419..424b3e2f7 100644 --- a/lib/ptk/include/ptk/types.h +++ b/lib/ptk/include/ptk/types.h @@ -1,12 +1,15 @@ /* * lib/ptk/include/ptk/types.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef PTK_INCLUDE_PLATFORM_TYPES_H diff --git a/lib/ptk/include/ptk/win32_main.h b/lib/ptk/include/ptk/win32_main.h index 84567109e..44b239ab1 100644 --- a/lib/ptk/include/ptk/win32_main.h +++ b/lib/ptk/include/ptk/win32_main.h @@ -1,12 +1,15 @@ /* * lib/ptk/include/ptk/win32_main.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIBPLATFORM_INCLUDE_PLATFORM_MAIN_H @@ -21,25 +24,23 @@ extern int main(int argc, char *argv[]); -int APIENTRY WinMain(_In_ HINSTANCE hInstance, - _In_opt_ HINSTANCE hPrevInstance, - _In_ LPSTR lpCmdLine, - _In_ int nCmdShow) +int APIENTRY WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, + _In_ LPSTR lpCmdLine, _In_ int nCmdShow) { - char *cmdline; - int ret, argc = 0; - char **argv = NULL; - UNREFERENCED_PARAMETER(hPrevInstance); - UNREFERENCED_PARAMETER(lpCmdLine); - ptk_set_instance(hInstance); - cmdline = GetCommandLineA(); - argc = cmdsplit(cmdline, &argv); - ret = main(argc, (char**)argv); - while (argc-- > 0) { - free(argv[argc]); - } - free(argv); - return ret; + char *cmdline; + int ret, argc = 0; + char **argv = NULL; + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); + ptk_set_instance(hInstance); + cmdline = GetCommandLineA(); + argc = cmdsplit(cmdline, &argv); + ret = main(argc, (char **)argv); + while (argc-- > 0) { + free(argv[argc]); + } + free(argv); + return ret; } #endif diff --git a/lib/ptk/include/ptk/window.h b/lib/ptk/include/ptk/window.h index cd75551cd..176a459a2 100644 --- a/lib/ptk/include/ptk/window.h +++ b/lib/ptk/include/ptk/window.h @@ -1,12 +1,15 @@ /* * lib/ptk/include/ptk/window.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef PTK_INCLUDE_PLATFORM_WINDOW_H diff --git a/lib/ptk/src/app.c b/lib/ptk/src/app.c index 2e834c12c..24e539f10 100644 --- a/lib/ptk/src/app.c +++ b/lib/ptk/src/app.c @@ -1,12 +1,15 @@ /* * lib/ptk/src/app.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is + * part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT + * file in the root directory of this source tree. */ #include "ptk/app.h" diff --git a/lib/ptk/src/clipboard.c b/lib/ptk/src/clipboard.c index 8014046e4..6f2055a9c 100644 --- a/lib/ptk/src/clipboard.c +++ b/lib/ptk/src/clipboard.c @@ -1,12 +1,15 @@ /* * lib/ptk/src/clipboard.c: -- Clipboard support * - * Copyright (c) 2022-2025, Liu chao All rights reserved. - * + * Copyright (c) 2022-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include diff --git a/lib/ptk/src/clipboard.h b/lib/ptk/src/clipboard.h index ada5ab3c3..cfb822307 100644 --- a/lib/ptk/src/clipboard.h +++ b/lib/ptk/src/clipboard.h @@ -1,7 +1,7 @@ /* * lib/ptk/src/clipboard.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ptk/src/events.c b/lib/ptk/src/events.c index df439cd86..6a4c5a38b 100644 --- a/lib/ptk/src/events.c +++ b/lib/ptk/src/events.c @@ -1,12 +1,15 @@ /* * lib/ptk/src/events.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ptk/src/events.h b/lib/ptk/src/events.h index bb7537006..c9434713e 100644 --- a/lib/ptk/src/events.h +++ b/lib/ptk/src/events.h @@ -1,7 +1,7 @@ /* * lib/ptk/src/events.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ptk/src/ime.c b/lib/ptk/src/ime.c index 0a48414c0..6bacc1e5f 100644 --- a/lib/ptk/src/ime.c +++ b/lib/ptk/src/ime.c @@ -1,12 +1,15 @@ /* * lib/ptk/src/ime.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is + * part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT + * file in the root directory of this source tree. */ #include diff --git a/lib/ptk/src/ime.h b/lib/ptk/src/ime.h index 37bc7d1bb..d6d5e1331 100644 --- a/lib/ptk/src/ime.h +++ b/lib/ptk/src/ime.h @@ -1,7 +1,7 @@ /* * lib/ptk/src/ime.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ptk/src/linux/app.c b/lib/ptk/src/linux/app.c index 1ebd1de86..9907ba2d7 100644 --- a/lib/ptk/src/linux/app.c +++ b/lib/ptk/src/linux/app.c @@ -1,12 +1,15 @@ -/* +/* * lib/ptk/src/linux/app.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ptk/src/linux/fbapp.c b/lib/ptk/src/linux/fbapp.c index d52e03fd5..4eb2069db 100644 --- a/lib/ptk/src/linux/fbapp.c +++ b/lib/ptk/src/linux/fbapp.c @@ -1,12 +1,15 @@ /* * lib/ptk/src/linux/fbapp.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "ptk.h" diff --git a/lib/ptk/src/linux/fbapp.h b/lib/ptk/src/linux/fbapp.h index 046ec0927..2275d2c4e 100644 --- a/lib/ptk/src/linux/fbapp.h +++ b/lib/ptk/src/linux/fbapp.h @@ -1,7 +1,7 @@ /* * lib/ptk/src/linux/fbapp.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ptk/src/linux/ime.c b/lib/ptk/src/linux/ime.c index 177015756..8914eaabd 100644 --- a/lib/ptk/src/linux/ime.c +++ b/lib/ptk/src/linux/ime.c @@ -1,12 +1,15 @@ /* * lib/ptk/src/linux/ime.c: -- The input method engine support for linux. * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include "ptk.h" diff --git a/lib/ptk/src/linux/keyboard.c b/lib/ptk/src/linux/keyboard.c index 08bf48272..e5f24ee59 100644 --- a/lib/ptk/src/linux/keyboard.c +++ b/lib/ptk/src/linux/keyboard.c @@ -1,12 +1,15 @@ /* * lib/ptk/src/linux/keyboard.c: -- Keyboard support for linux. * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include "ptk.h" @@ -22,157 +25,158 @@ #include static struct linux_keyboard { - int fd; - struct termios tm; - thread_t tid; - bool active; + int fd; + struct termios tm; + thread_t tid; + bool active; } linux_keyboard; static void linux_keyboard_dispatch_event(int key) { - wchar_t str[2]; - ptk_event_t ev = { 0 }; - - ev.key.code = key; - switch (ev.key.code) { - case 183: - ev.key.code = KEY_UP; - break; - case 184: - ev.key.code = KEY_DOWN; - break; - case 185: - ev.key.code = KEY_RIGHT; - break; - case 186: - ev.key.code = KEY_LEFT; - break; - case 127: - ev.key.code = KEY_BACKSPACE; - break; - case 293: - ev.key.code = KEY_HOME; - break; - case 295: - ev.key.code = KEY_DELETE; - break; - case 296: - ev.key.code = KEY_END; - break; - case 297: - ev.key.code = KEY_PAGEUP; - break; - case 298: - ev.key.code = KEY_PAGEDOWN; - default: - break; - } - ev.type = PTK_EVENT_KEYDOWN; - ptk_post_event(&ev); - ptk_event_destroy(&ev); - /* FIXME: this driver is not yet possible to get the key state directly, - * the following is a temporary solution. - */ - ev.type = PTK_EVENT_KEYUP; - ptk_post_event(&ev); - ptk_event_destroy(&ev); - if (ev.key.code >= ' ' && ev.key.code <= '~') { - str[0] = ev.key.code; - ev.type = PTK_EVENT_KEYPRESS; - ptk_post_event(&ev); - ptk_event_destroy(&ev); - ptk_ime_commit(str, 1); - } + wchar_t str[2]; + ptk_event_t ev = { 0 }; + + ev.key.code = key; + switch (ev.key.code) { + case 183: + ev.key.code = KEY_UP; + break; + case 184: + ev.key.code = KEY_DOWN; + break; + case 185: + ev.key.code = KEY_RIGHT; + break; + case 186: + ev.key.code = KEY_LEFT; + break; + case 127: + ev.key.code = KEY_BACKSPACE; + break; + case 293: + ev.key.code = KEY_HOME; + break; + case 295: + ev.key.code = KEY_DELETE; + break; + case 296: + ev.key.code = KEY_END; + break; + case 297: + ev.key.code = KEY_PAGEUP; + break; + case 298: + ev.key.code = KEY_PAGEDOWN; + default: + break; + } + ev.type = PTK_EVENT_KEYDOWN; + ptk_post_event(&ev); + ptk_event_destroy(&ev); + /* FIXME: this driver is not yet possible to get the key state directly, + * the following is a temporary solution. + */ + ev.type = PTK_EVENT_KEYUP; + ptk_post_event(&ev); + ptk_event_destroy(&ev); + if (ev.key.code >= ' ' && ev.key.code <= '~') { + str[0] = ev.key.code; + ev.type = PTK_EVENT_KEYPRESS; + ptk_post_event(&ev); + ptk_event_destroy(&ev); + ptk_ime_commit(str, 1); + } } static bool kbhit(void) { - int ch, flags; - struct termios tm; - - tcgetattr(linux_keyboard.fd, &tm); - flags = fcntl(linux_keyboard.fd, F_GETFL, 0); - fcntl(linux_keyboard.fd, F_SETFL, flags | O_NONBLOCK); - ch = getchar(); - tcsetattr(linux_keyboard.fd, TCSANOW, &tm); - fcntl(linux_keyboard.fd, F_SETFL, flags); - if (ch != EOF) { - ungetc(ch, stdin); - return true; - } - return false; + int ch, flags; + struct termios tm; + + tcgetattr(linux_keyboard.fd, &tm); + flags = fcntl(linux_keyboard.fd, F_GETFL, 0); + fcntl(linux_keyboard.fd, F_SETFL, flags | O_NONBLOCK); + ch = getchar(); + tcsetattr(linux_keyboard.fd, TCSANOW, &tm); + fcntl(linux_keyboard.fd, F_SETFL, flags); + if (ch != EOF) { + ungetc(ch, stdin); + return true; + } + return false; } static int getch(void) { - int c = EOF; - struct termios tm; - - tm = linux_keyboard.tm; - - /* canonical input and echo modes */ - tm.c_lflag &= ~(ICANON | ECHO); - tm.c_cc[VMIN] = 0; - tm.c_cc[VTIME] = 1; - tcsetattr(linux_keyboard.fd, TCSANOW, &tm); - /* get char from modified stdin */ - c = getchar(); - /* reset stdin to previous state */ - tcsetattr(linux_keyboard.fd, TCSANOW, &linux_keyboard.tm); - return c; + int c = EOF; + struct termios tm; + + tm = linux_keyboard.tm; + + /* canonical input and echo modes */ + tm.c_lflag &= ~(ICANON | ECHO); + tm.c_cc[VMIN] = 0; + tm.c_cc[VTIME] = 1; + tcsetattr(linux_keyboard.fd, TCSANOW, &tm); + /* get char from modified stdin */ + c = getchar(); + /* reset stdin to previous state */ + tcsetattr(linux_keyboard.fd, TCSANOW, &linux_keyboard.tm); + return c; } static void on_signal(int signal) { - tcsetattr(linux_keyboard.fd, TCSANOW, &linux_keyboard.tm); - exit(1); + tcsetattr(linux_keyboard.fd, TCSANOW, &linux_keyboard.tm); + exit(1); } static void linux_keyboard_thread(void *arg) { - int key; - while (linux_keyboard.active) { - key = getch(); - if (key == EOF) { - continue; - } - while (kbhit()) { - key += getch(); - } - linux_keyboard_dispatch_event(key); - } + int key; + while (linux_keyboard.active) { + key = getch(); + if (key == EOF) { + continue; + } + while (kbhit()) { + key += getch(); + } + linux_keyboard_dispatch_event(key); + } } int ptk_linux_keyboard_init(void) { - int i = 0; - int signals[] = { SIGABRT, SIGINT, SIGKILL, SIGQUIT, SIGSTOP, SIGTERM }; - int len = sizeof(signals) / sizeof(signals[0]); - - linux_keyboard.fd = STDIN_FILENO; - if (tcgetattr(linux_keyboard.fd, &linux_keyboard.tm) < 0) { - return -1; - } - for (; i < len; ++i) { - signal(signals[i], on_signal); - } - linux_keyboard.active = true; - thread_create(&linux_keyboard.tid, linux_keyboard_thread, NULL); - logger_debug("[input] keyboard driver thread: %lld\n", linux_keyboard.tid); - return 0; + int i = 0; + int signals[] = { SIGABRT, SIGINT, SIGKILL, SIGQUIT, SIGSTOP, SIGTERM }; + int len = sizeof(signals) / sizeof(signals[0]); + + linux_keyboard.fd = STDIN_FILENO; + if (tcgetattr(linux_keyboard.fd, &linux_keyboard.tm) < 0) { + return -1; + } + for (; i < len; ++i) { + signal(signals[i], on_signal); + } + linux_keyboard.active = true; + thread_create(&linux_keyboard.tid, linux_keyboard_thread, NULL); + logger_debug("[input] keyboard driver thread: %lld\n", + linux_keyboard.tid); + return 0; } int ptk_linux_keyboard_destroy(void) { - if (!linux_keyboard.active) { - return 0; - } - linux_keyboard.active = false; - thread_join(linux_keyboard.tid, NULL); - if (tcsetattr(linux_keyboard.fd, TCSANOW, &linux_keyboard.tm) < 0) { - return -1; - } - return 0; + if (!linux_keyboard.active) { + return 0; + } + linux_keyboard.active = false; + thread_join(linux_keyboard.tid, NULL); + if (tcsetattr(linux_keyboard.fd, TCSANOW, &linux_keyboard.tm) < 0) { + return -1; + } + return 0; } #endif diff --git a/lib/ptk/src/linux/keyboard.h b/lib/ptk/src/linux/keyboard.h index af553ce08..063e9fc18 100644 --- a/lib/ptk/src/linux/keyboard.h +++ b/lib/ptk/src/linux/keyboard.h @@ -1,7 +1,7 @@ /* * lib/ptk/src/linux/keyboard.h * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ptk/src/linux/mouse.c b/lib/ptk/src/linux/mouse.c index 3572bd5d5..20bfa6384 100644 --- a/lib/ptk/src/linux/mouse.c +++ b/lib/ptk/src/linux/mouse.c @@ -1,12 +1,15 @@ /* * lib/ptk/src/linux/mouse.c: -- Mouse support for linux. * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include "ptk.h" diff --git a/lib/ptk/src/linux/mouse.h b/lib/ptk/src/linux/mouse.h index f6e761dbe..d623ac080 100644 --- a/lib/ptk/src/linux/mouse.h +++ b/lib/ptk/src/linux/mouse.h @@ -1,7 +1,7 @@ /* * lib/ptk/src/linux/mouse.h * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -11,4 +11,3 @@ int ptk_linux_mouse_init(void); int ptk_linux_mouse_destroy(void); - diff --git a/lib/ptk/src/linux/uri.c b/lib/ptk/src/linux/uri.c index 066ced555..5e16caf99 100644 --- a/lib/ptk/src/linux/uri.c +++ b/lib/ptk/src/linux/uri.c @@ -1,12 +1,15 @@ /* * lib/ptk/src/linux/uri.c: -- uri processing * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include @@ -18,9 +21,9 @@ int ptk_open_uri(const char *uri) { - char cmd[512] = { 0 }; - snprintf(cmd, 511, "xdg-open %s", uri); - return system(cmd); + char cmd[512] = { 0 }; + snprintf(cmd, 511, "xdg-open %s", uri); + return system(cmd); } #endif diff --git a/lib/ptk/src/linux/x11app.c b/lib/ptk/src/linux/x11app.c index 416825362..4babfb115 100644 --- a/lib/ptk/src/linux/x11app.c +++ b/lib/ptk/src/linux/x11app.c @@ -1,12 +1,15 @@ /* * lib/ptk/src/linux/x11app.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ptk/src/linux/x11app.h b/lib/ptk/src/linux/x11app.h index 0bc5c871b..3226d2701 100644 --- a/lib/ptk/src/linux/x11app.h +++ b/lib/ptk/src/linux/x11app.h @@ -1,7 +1,7 @@ /* * lib/ptk/src/linux/x11app.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ptk/src/linux/x11clipboard.c b/lib/ptk/src/linux/x11clipboard.c index 8ba6e7178..4444a03c4 100644 --- a/lib/ptk/src/linux/x11clipboard.c +++ b/lib/ptk/src/linux/x11clipboard.c @@ -1,12 +1,15 @@ /* * lib/ptk/src/linux/x11clipboard.c: clipboard support for linux x11 * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ /* diff --git a/lib/ptk/src/linux/x11clipboard.h b/lib/ptk/src/linux/x11clipboard.h index 8461508fd..8662b01e7 100644 --- a/lib/ptk/src/linux/x11clipboard.h +++ b/lib/ptk/src/linux/x11clipboard.h @@ -1,7 +1,7 @@ /* * lib/ptk/src/linux/x11clipboard.h * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ptk/src/steptimer.c b/lib/ptk/src/steptimer.c index 36a6d4ff5..c272bae12 100644 --- a/lib/ptk/src/steptimer.c +++ b/lib/ptk/src/steptimer.c @@ -1,12 +1,15 @@ /* * lib/ptk/src/steptimer.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ /** @@ -19,109 +22,114 @@ void ptk_steptimer_init(ptk_steptimer_t *timer) { - timer->last_time = get_time_ms(); - timer->elapsed_time = 0; - timer->total_time = 0; - timer->left_over_time = 0; - timer->frame_count = 0; - timer->frames_per_second = 0; - timer->frames_this_second = 0; - timer->second_counter = 0; - timer->is_fixed_time_step = false; - timer->enable_catch_up = false; - timer->target_elapsed_time = 1000 / 60; - timer->max_delta = 1000; + timer->last_time = get_time_ms(); + timer->elapsed_time = 0; + timer->total_time = 0; + timer->left_over_time = 0; + timer->frame_count = 0; + timer->frames_per_second = 0; + timer->frames_this_second = 0; + timer->second_counter = 0; + timer->is_fixed_time_step = false; + timer->enable_catch_up = false; + timer->target_elapsed_time = 1000 / 60; + timer->max_delta = 1000; } void ptk_steptimer_tick(ptk_steptimer_t *timer, ptk_steptimer_handler_t handler, - void *data) + void *data) { - // Query the current time. - uint64_t current_time = get_time_ms(); - uint64_t time_delta = current_time - timer->last_time; - - timer->last_time = current_time; - timer->second_counter += time_delta; - - // Clamp excessively large time deltas (e.g. after paused in the - // debugger). - if (time_delta > timer->max_delta) { - time_delta = timer->max_delta; - } - - uint32_t last_frame_count = timer->frame_count; - - if (timer->is_fixed_time_step) { - // Fixed timestep update logic - - // If the app is running very close to the target elapsed time - // (within 1/4 of a millisecond) just clamp the clock to exactly - // match the target value. This prevents tiny and irrelevant - // errors from accumulating over time. Without this clamping, a - // game that requested a 60 fps fixed update, running with vsync - // enabled on a 59.94 NTSC display, would eventually accumulate - // enough tiny errors that it would drop a frame. It is better - // to just round small deviations down to zero to leave things - // running smoothly. - - if (abs((int)(time_delta - timer->target_elapsed_time)) < 4) { - time_delta = timer->target_elapsed_time; - } - - timer->left_over_time += time_delta; - - if (timer->enable_catch_up) { - // DirectXTK behavior: catch up by invoking the handler - // multiple times to fully consume accumulated time. - while (timer->left_over_time >= timer->target_elapsed_time) { - timer->elapsed_time = timer->target_elapsed_time; - timer->total_time += timer->target_elapsed_time; - timer->left_over_time -= timer->target_elapsed_time; - timer->frame_count++; - - handler(timer, data); - } - } else if (timer->left_over_time >= timer->target_elapsed_time) { - // No catch-up: invoke the handler at most once per tick. - // elapsed_time reflects the actual accumulated delta so - // the handler can respond to real-time passage (useful - // for visual callbacks like requestAnimationFrame). The - // remainder is preserved via modulo to prevent long-term - // drift without causing a burst of calls. - timer->elapsed_time = timer->left_over_time; - timer->total_time += timer->left_over_time; - timer->left_over_time %= timer->target_elapsed_time; - timer->frame_count++; - - handler(timer, data); - } - } else { - // Variable timestep update logic. - timer->elapsed_time = time_delta; - timer->total_time += time_delta; - timer->left_over_time = 0; - timer->frame_count++; - - handler(timer, data); - } - - // Track the current framerate. - if (timer->frame_count != last_frame_count) { - timer->frames_this_second++; - } - - if (timer->second_counter >= 1000) { - timer->frames_per_second = timer->frames_this_second; - timer->frames_this_second = 0; - timer->second_counter %= 1000; - } + // Query the current time. + uint64_t current_time = get_time_ms(); + uint64_t time_delta = current_time - timer->last_time; + + timer->last_time = current_time; + timer->second_counter += time_delta; + + // Clamp excessively large time deltas (e.g. after paused in the + // debugger). + if (time_delta > timer->max_delta) { + time_delta = timer->max_delta; + } + + uint32_t last_frame_count = timer->frame_count; + + if (timer->is_fixed_time_step) { + // Fixed timestep update logic + + // If the app is running very close to the target elapsed time + // (within 1/4 of a millisecond) just clamp the clock to exactly + // match the target value. This prevents tiny and irrelevant + // errors from accumulating over time. Without this clamping, a + // game that requested a 60 fps fixed update, running with vsync + // enabled on a 59.94 NTSC display, would eventually accumulate + // enough tiny errors that it would drop a frame. It is better + // to just round small deviations down to zero to leave things + // running smoothly. + + if (abs((int)(time_delta - timer->target_elapsed_time)) < 4) { + time_delta = timer->target_elapsed_time; + } + + timer->left_over_time += time_delta; + + if (timer->enable_catch_up) { + // DirectXTK behavior: catch up by invoking the handler + // multiple times to fully consume accumulated time. + while (timer->left_over_time >= + timer->target_elapsed_time) { + timer->elapsed_time = + timer->target_elapsed_time; + timer->total_time += timer->target_elapsed_time; + timer->left_over_time -= + timer->target_elapsed_time; + timer->frame_count++; + + handler(timer, data); + } + } else if (timer->left_over_time >= + timer->target_elapsed_time) { + // No catch-up: invoke the handler at most once per + // tick. elapsed_time reflects the actual accumulated + // delta so the handler can respond to real-time passage + // (useful for visual callbacks like + // requestAnimationFrame). The remainder is preserved + // via modulo to prevent long-term drift without causing + // a burst of calls. + timer->elapsed_time = timer->left_over_time; + timer->total_time += timer->left_over_time; + timer->left_over_time %= timer->target_elapsed_time; + timer->frame_count++; + + handler(timer, data); + } + } else { + // Variable timestep update logic. + timer->elapsed_time = time_delta; + timer->total_time += time_delta; + timer->left_over_time = 0; + timer->frame_count++; + + handler(timer, data); + } + + // Track the current framerate. + if (timer->frame_count != last_frame_count) { + timer->frames_this_second++; + } + + if (timer->second_counter >= 1000) { + timer->frames_per_second = timer->frames_this_second; + timer->frames_this_second = 0; + timer->second_counter %= 1000; + } } void ptk_steptimer_reset_elapsed_time(ptk_steptimer_t *timer) { - timer->last_time = get_time_ms(); - timer->left_over_time = 0; - timer->frames_per_second = 0; - timer->frames_this_second = 0; - timer->second_counter = 0; + timer->last_time = get_time_ms(); + timer->left_over_time = 0; + timer->frames_per_second = 0; + timer->frames_this_second = 0; + timer->second_counter = 0; } diff --git a/lib/ptk/src/windows/uri.c b/lib/ptk/src/windows/uri.c index 8ad57f71c..f2741f7be 100644 --- a/lib/ptk/src/windows/uri.c +++ b/lib/ptk/src/windows/uri.c @@ -1,12 +1,15 @@ /* * lib/ptk/src/windows/uri.c: -- uri processing * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include @@ -15,20 +18,20 @@ #include "ptk/app.h" #if defined(PTK_WIN32) && !defined(WINAPI_PARTITION_APP) -#pragma warning(disable:4091) +#pragma warning(disable : 4091) #include #include int ptk_open_uri(const char *uri) { - ShellExecuteA(NULL, "open", uri, NULL, NULL, SW_SHOW); - return 0; + ShellExecuteA(NULL, "open", uri, NULL, NULL, SW_SHOW); + return 0; } #else int ptk_open_uri(const char *uri) { - return -1; + return -1; } #endif diff --git a/lib/ptk/src/windows/win32app.c b/lib/ptk/src/windows/win32app.c index 062c31dd0..135d663b2 100644 --- a/lib/ptk/src/windows/win32app.c +++ b/lib/ptk/src/windows/win32app.c @@ -1,12 +1,15 @@ /* - * lib/ptk/src/windows/win32_app.c + * lib/ptk/src/windows/win32app.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "ptk/app.h" diff --git a/lib/ptk/src/windows/win32clipboard.c b/lib/ptk/src/windows/win32clipboard.c index fddbd4b4a..1db42e536 100644 --- a/lib/ptk/src/windows/win32clipboard.c +++ b/lib/ptk/src/windows/win32clipboard.c @@ -1,12 +1,15 @@ -/* +/* * lib/ptk/src/windows/win32clipboard.c: clipboard support for Windows * - * Copyright (c) 2025, Liu Chao All rights reserved. - * + * Copyright (c) 2025-2026, Liu Chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ /* diff --git a/lib/ptk/src/windows/win32clipboard.h b/lib/ptk/src/windows/win32clipboard.h index 289fd8b36..0b1df4d19 100644 --- a/lib/ptk/src/windows/win32clipboard.h +++ b/lib/ptk/src/windows/win32clipboard.h @@ -1,11 +1,14 @@ -/* +/* * lib/ptk/src/windows/win32clipboard.h * - * Copyright (c) 2025, Liu Chao All rights reserved. + * Copyright (c) 2025-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ diff --git a/lib/ptk/src/windows/win32ime.c b/lib/ptk/src/windows/win32ime.c index b404d71a2..6b2fa2ddd 100644 --- a/lib/ptk/src/windows/win32ime.c +++ b/lib/ptk/src/windows/win32ime.c @@ -1,12 +1,15 @@ /* - * lib/ptk/src/windows/win32_ime.c + * lib/ptk/src/windows/win32ime.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -22,63 +25,63 @@ static bool ptk_win32ime_process_key(int key, bool is_pressed) { - return false; + return false; } static void ptk_win32ime_to_text(int ch) { - wchar_t text[2] = { ch, 0 }; - ptk_ime_commit(text, 2); + wchar_t text[2] = { ch, 0 }; + ptk_ime_commit(text, 2); } static void ptk_win32ime_on_char(MSG *msg, void *arg) { - wchar_t text[2]; + wchar_t text[2]; - if (GetKeyState(VK_CONTROL) & 0x8000) { - return; - } - text[0] = (wchar_t)msg->wParam; - text[1] = 0; - ptk_ime_commit(text, 2); + if (GetKeyState(VK_CONTROL) & 0x8000) { + return; + } + text[0] = (wchar_t)msg->wParam; + text[1] = 0; + ptk_ime_commit(text, 2); } static void ptk_win32ime_set_caret(int x, int y) { - HWND hwnd = GetActiveWindow(); - HIMC himc = ImmGetContext(hwnd); - if (himc) { - COMPOSITIONFORM composition; - composition.dwStyle = CFS_POINT; - composition.ptCurrentPos.x = x; - composition.ptCurrentPos.y = y; - ImmSetCompositionWindow(himc, &composition); - ImmReleaseContext(hwnd, himc); - } + HWND hwnd = GetActiveWindow(); + HIMC himc = ImmGetContext(hwnd); + if (himc) { + COMPOSITIONFORM composition; + composition.dwStyle = CFS_POINT; + composition.ptCurrentPos.x = x; + composition.ptCurrentPos.y = y; + ImmSetCompositionWindow(himc, &composition); + ImmReleaseContext(hwnd, himc); + } } static bool ptk_win32ime_open(void) { - ptk_on_native_event(WM_CHAR, ptk_win32ime_on_char, NULL); - return true; + ptk_on_native_event(WM_CHAR, ptk_win32ime_on_char, NULL); + return true; } static bool ptk_win32ime_close(void) { - ptk_off_native_event(WM_CHAR, ptk_win32ime_on_char); - return true; + ptk_off_native_event(WM_CHAR, ptk_win32ime_on_char); + return true; } int ptk_ime_add_win32(void) { - ptk_ime_handler_t handler; + ptk_ime_handler_t handler; - handler.prockey = ptk_win32ime_process_key; - handler.totext = ptk_win32ime_to_text; - handler.close = ptk_win32ime_close; - handler.open = ptk_win32ime_open; - handler.setcaret = ptk_win32ime_set_caret; - return ptk_ime_add("Win32 Input Method", &handler); + handler.prockey = ptk_win32ime_process_key; + handler.totext = ptk_win32ime_to_text; + handler.close = ptk_win32ime_close; + handler.open = ptk_win32ime_open; + handler.setcaret = ptk_win32ime_set_caret; + return ptk_ime_add("Win32 Input Method", &handler); } #endif diff --git a/lib/ptk/tests/main.c b/lib/ptk/tests/main.c index 43222e261..b4c5dfeb9 100644 --- a/lib/ptk/tests/main.c +++ b/lib/ptk/tests/main.c @@ -1,4 +1,4 @@ -/* +/* * lib/ptk/tests/main.c * * Copyright (c) 2026, Liu Chao All rights reserved. diff --git a/lib/ptk/tests/test_steptimer.c b/lib/ptk/tests/test_steptimer.c index ac5b140cc..1e1455315 100644 --- a/lib/ptk/tests/test_steptimer.c +++ b/lib/ptk/tests/test_steptimer.c @@ -1,12 +1,15 @@ -/* +/* * lib/ptk/tests/test_steptimer.c * - * Copyright (c) 2026, Liu Chao All rights reserved. + * Copyright (c) 2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/router/include/router.h b/lib/router/include/router.h index a3d2fcc28..2a9ed7a93 100644 --- a/lib/router/include/router.h +++ b/lib/router/include/router.h @@ -1,7 +1,7 @@ /* * lib/router/include/router.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/router/include/router/common.h b/lib/router/include/router/common.h index ccd75b60d..ce3cfdcb1 100644 --- a/lib/router/include/router/common.h +++ b/lib/router/include/router/common.h @@ -1,12 +1,15 @@ /* * lib/router/include/router/common.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "version.h" diff --git a/lib/router/include/router/config.h b/lib/router/include/router/config.h index c1f43a5b6..4b7f58089 100644 --- a/lib/router/include/router/config.h +++ b/lib/router/include/router/config.h @@ -1,12 +1,15 @@ /* * lib/router/include/router/config.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_ROUTER_INCLUDE_ROUTER_CONFIG_H @@ -22,14 +25,14 @@ LIBROUTER_PUBLIC router_config_t *router_config_create(void); LIBROUTER_PUBLIC void router_config_destroy(router_config_t *config); LIBROUTER_PUBLIC void router_config_set_name(router_config_t *config, - const char *name); + const char *name); LIBROUTER_PUBLIC void router_config_set_path(router_config_t *config, - const char *path); + const char *path); LIBROUTER_PUBLIC void router_config_set_component(router_config_t *config, - const char *name, - const char *component); + const char *name, + const char *component); LIBROUTER_END_DECLS diff --git a/lib/router/include/router/history.h b/lib/router/include/router/history.h index 16b86af87..8dc1e33e2 100644 --- a/lib/router/include/router/history.h +++ b/lib/router/include/router/history.h @@ -1,11 +1,14 @@ /* * lib/router/include/router/history.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ @@ -25,16 +28,15 @@ LIBROUTER_PUBLIC router_watcher_t *router_history_watch( router_history_t *history, router_callback_t callback, void *data); LIBROUTER_PUBLIC void router_history_unwatch(router_history_t *history, - router_watcher_t *watcher); + router_watcher_t *watcher); LIBROUTER_PUBLIC void router_history_push(router_history_t *history, - router_route_t *route); + router_route_t *route); LIBROUTER_PUBLIC void router_history_replace(router_history_t *history, - router_route_t *route); + router_route_t *route); -LIBROUTER_PUBLIC void router_history_go(router_history_t *history, - int delta); +LIBROUTER_PUBLIC void router_history_go(router_history_t *history, int delta); LIBROUTER_PUBLIC size_t router_history_get_index(const router_history_t *history); diff --git a/lib/router/include/router/location.h b/lib/router/include/router/location.h index c7e2563a9..56c78d1a3 100644 --- a/lib/router/include/router/location.h +++ b/lib/router/include/router/location.h @@ -1,11 +1,14 @@ /* * lib/router/include/router/location.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ @@ -18,12 +21,12 @@ LIBROUTER_BEGIN_DECLS LIBROUTER_PUBLIC router_location_t *router_location_create(const char *name, - const char *path); + const char *path); LIBROUTER_PUBLIC void router_location_destroy(router_location_t *location); LIBROUTER_PUBLIC void router_location_set_name(router_location_t *location, - const char *name); + const char *name); LIBROUTER_PUBLIC router_location_t *router_location_duplicate( const router_location_t *location); @@ -32,15 +35,15 @@ LIBROUTER_PUBLIC router_location_t *router_location_normalize( const router_location_t *raw, const router_route_t *current, bool append); LIBROUTER_PUBLIC int router_location_set_param(router_location_t *location, - const char *key, - const char *value); + const char *key, + const char *value); LIBROUTER_PUBLIC const char *router_location_get_param( const router_location_t *location, const char *key); LIBROUTER_PUBLIC int router_location_set_query(router_location_t *location, - const char *key, - const char *value); + const char *key, + const char *value); LIBROUTER_PUBLIC const char *router_location_get_query( const router_location_t *location, const char *key); diff --git a/lib/router/include/router/matcher.h b/lib/router/include/router/matcher.h index a40e47a46..5a997bf75 100644 --- a/lib/router/include/router/matcher.h +++ b/lib/router/include/router/matcher.h @@ -1,11 +1,14 @@ /* * lib/router/include/router/matcher.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ diff --git a/lib/router/include/router/route.h b/lib/router/include/router/route.h index adfa28498..da77d29fb 100644 --- a/lib/router/include/router/route.h +++ b/lib/router/include/router/route.h @@ -1,12 +1,15 @@ /* * lib/router/include/router/route.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_ROUTER_INCLUDE_ROUTER_ROUTE_H @@ -22,23 +25,21 @@ LIBROUTER_PUBLIC router_route_t *router_route_create( LIBROUTER_PUBLIC void router_route_destroy(router_route_t *route); -LIBROUTER_PUBLIC const router_route_record_t * -router_route_get_matched_record(const router_route_t *route, size_t index); +LIBROUTER_PUBLIC const router_route_record_t *router_route_get_matched_record( + const router_route_t *route, size_t index); LIBROUTER_PUBLIC const char *router_route_get_full_path( const router_route_t *route); -LIBROUTER_PUBLIC const char *router_route_get_path( - const router_route_t *route); +LIBROUTER_PUBLIC const char *router_route_get_path(const router_route_t *route); -LIBROUTER_PUBLIC const char *router_route_get_hash( - const router_route_t *route); +LIBROUTER_PUBLIC const char *router_route_get_hash(const router_route_t *route); -LIBROUTER_PUBLIC const char *router_route_get_param( - const router_route_t *route, const char *key); +LIBROUTER_PUBLIC const char *router_route_get_param(const router_route_t *route, + const char *key); -LIBROUTER_PUBLIC const char *router_route_get_query( - const router_route_t *route, const char *key); +LIBROUTER_PUBLIC const char *router_route_get_query(const router_route_t *route, + const char *key); LIBROUTER_END_DECLS diff --git a/lib/router/include/router/route_record.h b/lib/router/include/router/route_record.h index e86c70ff5..65f22f2ef 100644 --- a/lib/router/include/router/route_record.h +++ b/lib/router/include/router/route_record.h @@ -1,11 +1,14 @@ /* * lib/router/include/router/route_record.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, + * Liu Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ diff --git a/lib/router/include/router/router.h b/lib/router/include/router/router.h index 34368bccb..622fd0ff1 100644 --- a/lib/router/include/router/router.h +++ b/lib/router/include/router/router.h @@ -1,12 +1,15 @@ /* * lib/router/include/router/router.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_ROUTER_INCLUDE_ROUTER_ROUTER_H @@ -35,14 +38,15 @@ LIBROUTER_PUBLIC router_route_record_t *router_get_matched_route_record( LIBROUTER_PUBLIC router_history_t *router_get_history(router_t *router); LIBROUTER_PUBLIC router_watcher_t *router_watch(router_t *router, - router_callback_t callback, - void *data); + router_callback_t callback, + void *data); LIBROUTER_PUBLIC void router_unwatch(router_t *router, - router_watcher_t *watcher); + router_watcher_t *watcher); -LIBROUTER_PUBLIC router_resolved_t *router_resolve( - router_t *router, router_location_t *location, bool append); +LIBROUTER_PUBLIC router_resolved_t *router_resolve(router_t *router, + router_location_t *location, + bool append); LIBROUTER_PUBLIC router_location_t *router_resolved_get_location( router_resolved_t *resolved); @@ -56,10 +60,10 @@ LIBROUTER_PUBLIC const router_route_t *router_get_current_route( router_t *router); LIBROUTER_PUBLIC void router_push(router_t *router, - router_location_t *location); + router_location_t *location); LIBROUTER_PUBLIC void router_replace(router_t *router, - router_location_t *location); + router_location_t *location); LIBROUTER_PUBLIC void router_go(router_t *router, int delta); diff --git a/lib/router/include/router/strmap.h b/lib/router/include/router/strmap.h index fc0cc11cb..52a0ffabe 100644 --- a/lib/router/include/router/strmap.h +++ b/lib/router/include/router/strmap.h @@ -1,12 +1,15 @@ /* * lib/router/include/router/strmap.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_ROUTER_INCLUDE_ROUTER_STRMAP_H @@ -24,7 +27,7 @@ LIBROUTER_PUBLIC void strmap_destroy(strmap_t *dict); LIBROUTER_PUBLIC void strmap_delete(strmap_t *dict, const char *key); LIBROUTER_PUBLIC int strmap_set(strmap_t *dict, const char *key, - const char *value); + const char *value); LIBROUTER_PUBLIC const char *strmap_get(strmap_t *dict, const char *key); diff --git a/lib/router/include/router/types.h b/lib/router/include/router/types.h index 38b988651..0f8e0ded5 100644 --- a/lib/router/include/router/types.h +++ b/lib/router/include/router/types.h @@ -1,12 +1,15 @@ /* * lib/router/include/router/types.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_ROUTER_INCLUDE_ROUTER_TYPES_H diff --git a/lib/router/include/router/utils.h b/lib/router/include/router/utils.h index e5129d8be..b5c994c49 100644 --- a/lib/router/include/router/utils.h +++ b/lib/router/include/router/utils.h @@ -1,12 +1,15 @@ /* * lib/router/include/router/utils.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_ROUTER_INCLUDE_ROUTER_UTILS_H @@ -18,17 +21,17 @@ LIBROUTER_BEGIN_DECLS LIBROUTER_PUBLIC char *router_path_fill_params(const char *path, - strmap_t *params); + strmap_t *params); LIBROUTER_PUBLIC const char *router_path_parse_key(const char *path, - char key[256], - size_t *key_len); + char key[256], + size_t *key_len); LIBROUTER_PUBLIC size_t router_path_parse_keys(const char *path, - router_linkedlist_t *keys); + router_linkedlist_t *keys); LIBROUTER_PUBLIC char *router_path_resolve(const char *relative, - const char *base, bool append); + const char *base, bool append); LIBROUTER_PUBLIC strmap_t *router_parse_query(const char *query_str); @@ -37,13 +40,13 @@ LIBROUTER_PUBLIC int router_string_compare(const char *a, const char *b); LIBROUTER_PUBLIC int router_path_compare(const char *a, const char *b); LIBROUTER_PUBLIC bool router_path_starts_with(const char *path, - const char *subpath); + const char *subpath); LIBROUTER_PUBLIC bool router_is_same_route(const router_route_t *a, - const router_route_t *b); + const router_route_t *b); LIBROUTER_PUBLIC bool router_is_included_route(const router_route_t *current, - const router_route_t *target); + const router_route_t *target); LIBROUTER_END_DECLS diff --git a/lib/router/include/router/version.h b/lib/router/include/router/version.h index 495f2a706..48cf575bc 100644 --- a/lib/router/include/router/version.h +++ b/lib/router/include/router/version.h @@ -1,7 +1,7 @@ /* * lib/router/include/router/version.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2025, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/router/src/config.c b/lib/router/src/config.c index 855506d95..d564a4982 100644 --- a/lib/router/src/config.c +++ b/lib/router/src/config.c @@ -1,12 +1,15 @@ /* * lib/router/src/config.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "private.h" @@ -14,45 +17,45 @@ router_config_t *router_config_create(void) { - router_config_t *config; + router_config_t *config; - config = malloc(sizeof(router_config_t)); - config->components = strmap_create(); - config->name = NULL; - config->path = NULL; - return config; + config = malloc(sizeof(router_config_t)); + config->components = strmap_create(); + config->name = NULL; + config->path = NULL; + return config; } void router_config_destroy(router_config_t *config) { - router_mem_free(config->name); - router_mem_free(config->path); - strmap_destroy(config->components); - config->components = NULL; - free(config); + router_mem_free(config->name); + router_mem_free(config->path); + strmap_destroy(config->components); + config->components = NULL; + free(config); } void router_config_set_name(router_config_t *config, const char *name) { - router_mem_free(config->name); - if (name) { - config->name = strdup(name); - } + router_mem_free(config->name); + if (name) { + config->name = strdup(name); + } } void router_config_set_path(router_config_t *config, const char *path) { - router_mem_free(config->path); - if (path) { - config->path = strdup(path); - } + router_mem_free(config->path); + if (path) { + config->path = strdup(path); + } } void router_config_set_component(router_config_t *config, const char *name, - const char *component) + const char *component) { - if (!name) { - name = "default"; - } - strmap_set(config->components, name, component); + if (!name) { + name = "default"; + } + strmap_set(config->components, name, component); } diff --git a/lib/router/src/history.c b/lib/router/src/history.c index 0f2d1b432..a3d5ebd82 100644 --- a/lib/router/src/history.c +++ b/lib/router/src/history.c @@ -1,12 +1,15 @@ /* * lib/router/src/history.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "private.h" diff --git a/lib/router/src/location.c b/lib/router/src/location.c index 3b45458aa..971abd6f0 100644 --- a/lib/router/src/location.c +++ b/lib/router/src/location.c @@ -1,12 +1,15 @@ /* * lib/router/src/location.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "private.h" diff --git a/lib/router/src/matcher.c b/lib/router/src/matcher.c index dc567e696..403e86a84 100644 --- a/lib/router/src/matcher.c +++ b/lib/router/src/matcher.c @@ -1,12 +1,15 @@ /* * lib/router/src/matcher.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "private.h" @@ -172,9 +175,9 @@ bool router_matcher_match_route(router_route_record_t *record, const char *path, // https://github.com/vuejs/vue-router/blob/65de048ee9f0ebf899ae99c82b71ad397727e55d/dist/vue-router.esm.js#L1457 -router_route_t *router_matcher_match_by_name(router_matcher_t *matcher, - router_location_t *location, - const router_route_t *current_route) +router_route_t *router_matcher_match_by_name( + router_matcher_t *matcher, router_location_t *location, + const router_route_t *current_route) { char *key; const char *value; diff --git a/lib/router/src/private.h b/lib/router/src/private.h index 1611b07fd..e87eba3d5 100644 --- a/lib/router/src/private.h +++ b/lib/router/src/private.h @@ -1,12 +1,15 @@ /* * lib/router/src/private.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef ROUTER_PRIVATE_H diff --git a/lib/router/src/route.c b/lib/router/src/route.c index 037997a93..c3562b763 100644 --- a/lib/router/src/route.c +++ b/lib/router/src/route.c @@ -1,12 +1,15 @@ /* * lib/router/src/route.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "private.h" @@ -16,80 +19,80 @@ // https://github.com/vuejs/vue-router/blob/65de048ee9f0ebf899ae99c82b71ad397727e55d/dist/vue-router.esm.js#L266 router_route_t *router_route_create(const router_route_record_t *record, - const router_location_t *location) + const router_location_t *location) { - router_route_t *route; + router_route_t *route; - route = malloc(sizeof(router_route_t)); - if (location->name) { - route->name = strdup(location->name); - } else if (record && record->name) { - route->name = strdup(record->name); - } else { - route->name = NULL; - } - route->path = strdup(location->path ? location->path : "/"); - route->hash = strdup(location->hash ? location->hash : ""); - route->query = strmap_duplicate(location->query); - route->params = strmap_duplicate(location->params); - route->full_path = router_location_stringify(location); - list_create(&route->matched); - while (record) { - list_insert(&route->matched, 0, (void *)record); - record = record->parent; - } - return route; + route = malloc(sizeof(router_route_t)); + if (location->name) { + route->name = strdup(location->name); + } else if (record && record->name) { + route->name = strdup(record->name); + } else { + route->name = NULL; + } + route->path = strdup(location->path ? location->path : "/"); + route->hash = strdup(location->hash ? location->hash : ""); + route->query = strmap_duplicate(location->query); + route->params = strmap_duplicate(location->params); + route->full_path = router_location_stringify(location); + list_create(&route->matched); + while (record) { + list_insert(&route->matched, 0, (void *)record); + record = record->parent; + } + return route; } void router_route_destroy(router_route_t *route) { - router_mem_free(route->name); - router_mem_free(route->path); - router_mem_free(route->full_path); - router_mem_free(route->hash); - if (route->params) { - strmap_destroy(route->params); - } - if (route->query) { - strmap_destroy(route->query); - } - list_destroy(&route->matched, NULL); - free(route); + router_mem_free(route->name); + router_mem_free(route->path); + router_mem_free(route->full_path); + router_mem_free(route->hash); + if (route->params) { + strmap_destroy(route->params); + } + if (route->query) { + strmap_destroy(route->query); + } + list_destroy(&route->matched, NULL); + free(route); } const router_route_record_t *router_route_get_matched_record( const router_route_t *route, size_t index) { - return list_get(&route->matched, index); + return list_get(&route->matched, index); } const char *router_route_get_full_path(const router_route_t *route) { - return route->full_path; + return route->full_path; } const char *router_route_get_path(const router_route_t *route) { - return route->path; + return route->path; } const char *router_route_get_hash(const router_route_t *route) { - return route->hash; + return route->hash; } const char *router_route_get_param(const router_route_t *route, const char *key) { - if (!route->params) { - return NULL; - } - return strmap_get(route->params, key); + if (!route->params) { + return NULL; + } + return strmap_get(route->params, key); } const char *router_route_get_query(const router_route_t *route, const char *key) { - if (!route->query) { - return NULL; - } - return strmap_get(route->query, key); + if (!route->query) { + return NULL; + } + return strmap_get(route->query, key); } diff --git a/lib/router/src/route_record.c b/lib/router/src/route_record.c index 432109182..0d7bd72ff 100644 --- a/lib/router/src/route_record.c +++ b/lib/router/src/route_record.c @@ -1,12 +1,15 @@ /* * lib/router/src/route_record.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "private.h" @@ -14,45 +17,45 @@ router_route_record_t *router_route_record_create(void) { - router_route_record_t *record; - - record = malloc(sizeof(router_route_record_t)); - record->name = NULL; - record->path = NULL; - record->components = strmap_create(); - record->node.data = record; - record->node.prev = NULL; - record->node.next = NULL; - record->parent = NULL; - return record; + router_route_record_t *record; + + record = malloc(sizeof(router_route_record_t)); + record->name = NULL; + record->path = NULL; + record->components = strmap_create(); + record->node.data = record; + record->node.prev = NULL; + record->node.next = NULL; + record->parent = NULL; + return record; } void router_route_record_destroy(router_route_record_t *record) { - if (record->name) { - free(record->name); - } - if (record->path) { - free(record->path); - } - record->name = NULL; - record->path = NULL; - strmap_destroy(record->components); - free(record); + if (record->name) { + free(record->name); + } + if (record->path) { + free(record->path); + } + record->name = NULL; + record->path = NULL; + strmap_destroy(record->components); + free(record); } void router_route_record_set_path(router_route_record_t *record, - const char *path) + const char *path) { - router_mem_free(record->path); - record->path = strdup(path); + router_mem_free(record->path); + record->path = strdup(path); } const char *router_route_record_get_component( const router_route_record_t *record, const char *key) { - if (!key) { - key = "default"; - } - return strmap_get(record->components, key); + if (!key) { + key = "default"; + } + return strmap_get(record->components, key); } diff --git a/lib/router/src/router.c b/lib/router/src/router.c index c0b5cd377..ff6bc5119 100644 --- a/lib/router/src/router.c +++ b/lib/router/src/router.c @@ -1,12 +1,15 @@ /* * lib/router/src/router.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "private.h" @@ -17,165 +20,165 @@ static dict_type_t routers_dict_type; router_t *router_create(const char *name) { - router_t *router; - - router = malloc(sizeof(router_t)); - if (!name) { - name = "default"; - } - router->name = strdup(name); - router->link_active_class = strdup("router-link-active"); - router->link_exact_active_class = strdup("router-link-exact-active"); - router->matcher = router_matcher_create(); - router->history = router_history_create(); - if (!routers) { - dict_init_string_key_type(&routers_dict_type); - routers = dict_create(&routers_dict_type, NULL); - } - dict_add(routers, router->name, router); - return router; + router_t *router; + + router = malloc(sizeof(router_t)); + if (!name) { + name = "default"; + } + router->name = strdup(name); + router->link_active_class = strdup("router-link-active"); + router->link_exact_active_class = strdup("router-link-exact-active"); + router->matcher = router_matcher_create(); + router->history = router_history_create(); + if (!routers) { + dict_init_string_key_type(&routers_dict_type); + routers = dict_create(&routers_dict_type, NULL); + } + dict_add(routers, router->name, router); + return router; } void router_destroy(router_t *router) { - dict_delete(routers, router->name); - router_mem_free(router->name); - router_mem_free(router->link_active_class); - router_mem_free(router->link_exact_active_class); - router_matcher_destroy(router->matcher); - router_history_destroy(router->history); - router->matcher = NULL; - free(router); + dict_delete(routers, router->name); + router_mem_free(router->name); + router_mem_free(router->link_active_class); + router_mem_free(router->link_exact_active_class); + router_matcher_destroy(router->matcher); + router_history_destroy(router->history); + router->matcher = NULL; + free(router); } router_route_record_t *router_add_route_record( router_t *router, const router_config_t *config, const router_route_record_t *parent) { - return router_matcher_add_route_record(router->matcher, config, parent); + return router_matcher_add_route_record(router->matcher, config, parent); } router_route_t *router_match(router_t *router, - const router_location_t *raw_location, - const router_route_t *current_route) + const router_location_t *raw_location, + const router_route_t *current_route) { - return router_matcher_match(router->matcher, raw_location, - current_route); + return router_matcher_match(router->matcher, raw_location, + current_route); } router_route_record_t *router_get_matched_route_record(router_t *router, - size_t index) + size_t index) { - return list_get(&router->history->current->matched, index); + return list_get(&router->history->current->matched, index); } router_history_t *router_get_history(router_t *router) { - return router->history; + return router->history; } router_watcher_t *router_watch(router_t *router, router_callback_t callback, - void *data) + void *data) { - return router_history_watch(router->history, callback, data); + return router_history_watch(router->history, callback, data); } void router_unwatch(router_t *router, router_watcher_t *watcher) { - router_history_unwatch(router->history, watcher); + router_history_unwatch(router->history, watcher); } // https://github.com/vuejs/vue-router/blob/65de048ee9f0ebf899ae99c82b71ad397727e55d/dist/vue-router.esm.js#L2827 router_resolved_t *router_resolve(router_t *router, router_location_t *location, - bool append) + bool append) { - const router_route_t *current; - router_resolved_t *resolved; + const router_route_t *current; + router_resolved_t *resolved; - current = router->history->current; - resolved = malloc(sizeof(router_resolved_t)); - resolved->location = - router_location_normalize(location, current, append); - resolved->route = router_match(router, resolved->location, current); - return resolved; + current = router->history->current; + resolved = malloc(sizeof(router_resolved_t)); + resolved->location = + router_location_normalize(location, current, append); + resolved->route = router_match(router, resolved->location, current); + return resolved; } router_location_t *router_resolved_get_location(router_resolved_t *resolved) { - return resolved->location; + return resolved->location; } router_route_t *router_resolved_get_route(router_resolved_t *resolved) { - return resolved->route; + return resolved->route; } void router_resolved_destroy(router_resolved_t *resolved) { - router_location_destroy(resolved->location); - if (resolved->route) { - router_route_destroy(resolved->route); - } - free(resolved); + router_location_destroy(resolved->location); + if (resolved->route) { + router_route_destroy(resolved->route); + } + free(resolved); } const router_route_t *router_get_current_route(router_t *router) { - return router->history->current; + return router->history->current; } void router_push(router_t *router, router_location_t *location) { - router_resolved_t *resolved; + router_resolved_t *resolved; - resolved = router_resolve(router, location, false); - router_history_push(router->history, resolved->route); - resolved->route = NULL; - router_resolved_destroy(resolved); + resolved = router_resolve(router, location, false); + router_history_push(router->history, resolved->route); + resolved->route = NULL; + router_resolved_destroy(resolved); } void router_replace(router_t *router, router_location_t *location) { - router_resolved_t *resolved; + router_resolved_t *resolved; - resolved = router_resolve(router, location, false); - router_history_replace(router->history, resolved->route); - resolved->route = NULL; - router_resolved_destroy(resolved); + resolved = router_resolve(router, location, false); + router_history_replace(router->history, resolved->route); + resolved->route = NULL; + router_resolved_destroy(resolved); } void router_go(router_t *router, int delta) { - router_history_go(router->history, delta); + router_history_go(router->history, delta); } void router_back(router_t *router) { - router_history_go(router->history, -1); + router_history_go(router->history, -1); } void router_forward(router_t *router) { - router_history_go(router->history, 1); + router_history_go(router->history, 1); } router_t *router_get_by_name(const char *name) { - router_t *router; + router_t *router; - if (!routers) { - return NULL; - } - router = dict_fetch_value(routers, name); - if (router) { - return router; - } - logger_error("no router named \"%s\" was found", name); - return NULL; + if (!routers) { + return NULL; + } + router = dict_fetch_value(routers, name); + if (router) { + return router; + } + logger_error("no router named \"%s\" was found", name); + return NULL; } const char *router_get_version(void) { - return LIBROUTER_VERSION; + return LIBROUTER_VERSION; } diff --git a/lib/router/src/strmap.c b/lib/router/src/strmap.c index a0562b944..d2364ba6e 100644 --- a/lib/router/src/strmap.c +++ b/lib/router/src/strmap.c @@ -1,12 +1,15 @@ /* * lib/router/src/strmap.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "private.h" @@ -176,4 +179,4 @@ strmap_item_t *strmap_next(strmap_iterator_t *iter) iter->next_item = NULL; } return iter->item; -} \ No newline at end of file +} diff --git a/lib/router/src/utils.c b/lib/router/src/utils.c index 973588549..d0d61265f 100644 --- a/lib/router/src/utils.c +++ b/lib/router/src/utils.c @@ -1,12 +1,15 @@ /* * lib/router/src/utils.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "private.h" diff --git a/lib/router/src/version.h.in b/lib/router/src/version.h.in index 3a873e83e..14585d148 100644 --- a/lib/router/src/version.h.in +++ b/lib/router/src/version.h.in @@ -1,7 +1,7 @@ /* * lib/router/include/router/version.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2025, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/router/tests/test.c b/lib/router/tests/test.c index c2bb4f391..82fbdd3fb 100644 --- a/lib/router/tests/test.c +++ b/lib/router/tests/test.c @@ -1,12 +1,15 @@ /* * lib/router/tests/test.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "../src/private.h" diff --git a/lib/thread/src/pthread.c b/lib/thread/src/pthread.c index dc332acf0..4b87c4cf5 100644 --- a/lib/thread/src/pthread.c +++ b/lib/thread/src/pthread.c @@ -1,12 +1,15 @@ /* * lib/thread/src/pthread.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef _WIN32 @@ -19,238 +22,239 @@ #include "thread.h" typedef union thread_mutex_record_t { - pthread_mutex_t handle; + pthread_mutex_t handle; } thread_mutex_record_t; typedef union thread_cond_record_t { - pthread_cond_t handle; + pthread_cond_t handle; } thread_cond_record_t; typedef struct thread_info { - void (*func)(void *); - void *arg; - thread_t tid; - list_node_t node; + void (*func)(void *); + void *arg; + thread_t tid; + list_node_t node; } thread_info_t; static struct thread_manager_module { - bool active; - thread_mutex_t mutex; - list_t threads; + bool active; + thread_mutex_t mutex; + list_t threads; } thread_manager; /** 初始化一个条件变量 */ int thread_cond_init(thread_cond_t *cond) { - *cond = malloc(sizeof(thread_cond_record_t)); - if (!*cond) { - return -1; - } - if (pthread_cond_init(&(*cond)->handle, NULL) != 0) { - free(*cond); - *cond = NULL; - return -1; - } - return 0; + *cond = malloc(sizeof(thread_cond_record_t)); + if (!*cond) { + return -1; + } + if (pthread_cond_init(&(*cond)->handle, NULL) != 0) { + free(*cond); + *cond = NULL; + return -1; + } + return 0; } /** 销毁一个条件变量 */ int thread_cond_destroy(thread_cond_t *cond) { - if (pthread_cond_destroy(&(*cond)->handle) != 0) { - return -1; - } - free(*cond); - *cond = NULL; - return 0; + if (pthread_cond_destroy(&(*cond)->handle) != 0) { + return -1; + } + free(*cond); + *cond = NULL; + return 0; } /** 阻塞当前线程,等待条件成立 */ int thread_cond_wait(thread_cond_t *cond, thread_mutex_t *mutex) { - return pthread_cond_wait(&(*cond)->handle, &(*mutex)->handle); + return pthread_cond_wait(&(*cond)->handle, &(*mutex)->handle); } /** 计时阻塞当前线程,等待条件成立 */ int thread_cond_timedwait(thread_cond_t *cond, thread_mutex_t *mutex, - unsigned int ms) + unsigned int ms) { - int ret; - long int out_usec; - struct timeval now; - struct timespec outtime; - - gettimeofday(&now, NULL); - out_usec = now.tv_usec + ms * 1000; - outtime.tv_sec = now.tv_sec + out_usec / 1000000; - outtime.tv_nsec = (out_usec % 1000000) * 1000; - ret = pthread_cond_timedwait(&(*cond)->handle, &(*mutex)->handle, &outtime); - switch (ret) { - case 0: - return 0; - case ETIMEDOUT: - return 1; - default: - break; - } - return -1; + int ret; + long int out_usec; + struct timeval now; + struct timespec outtime; + + gettimeofday(&now, NULL); + out_usec = now.tv_usec + ms * 1000; + outtime.tv_sec = now.tv_sec + out_usec / 1000000; + outtime.tv_nsec = (out_usec % 1000000) * 1000; + ret = pthread_cond_timedwait(&(*cond)->handle, &(*mutex)->handle, + &outtime); + switch (ret) { + case 0: + return 0; + case ETIMEDOUT: + return 1; + default: + break; + } + return -1; } /** 唤醒一个阻塞等待条件成立的线程 */ int thread_cond_signal(thread_cond_t *cond) { - return pthread_cond_signal(&(*cond)->handle); + return pthread_cond_signal(&(*cond)->handle); } /** 唤醒所有阻塞等待条件成立的线程 */ int thread_cond_broadcast(thread_cond_t *cond) { - return pthread_cond_broadcast(&(*cond)->handle); + return pthread_cond_broadcast(&(*cond)->handle); } /* init the mutex */ int thread_mutex_init(thread_mutex_t *mutex) { - pthread_mutexattr_t attr; - - *mutex = malloc(sizeof(thread_mutex_record_t)); - if (!*mutex) { - return -1; - } - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - if (pthread_mutex_init(&(*mutex)->handle, &attr) != 0) { - free(*mutex); - *mutex = NULL; - return -1; - } - return 0; + pthread_mutexattr_t attr; + + *mutex = malloc(sizeof(thread_mutex_record_t)); + if (!*mutex) { + return -1; + } + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + if (pthread_mutex_init(&(*mutex)->handle, &attr) != 0) { + free(*mutex); + *mutex = NULL; + return -1; + } + return 0; } /* Free the mutex */ void thread_mutex_destroy(thread_mutex_t *mutex) { - pthread_mutex_destroy(&(*mutex)->handle); - free(*mutex); - *mutex = NULL; + pthread_mutex_destroy(&(*mutex)->handle); + free(*mutex); + *mutex = NULL; } /* Try lock the mutex */ int thread_mutex_trylock(thread_mutex_t *mutex) { - return pthread_mutex_trylock(&(*mutex)->handle); + return pthread_mutex_trylock(&(*mutex)->handle); } /* Lock the mutex */ int thread_mutex_lock(thread_mutex_t *mutex) { - return pthread_mutex_lock(&(*mutex)->handle); + return pthread_mutex_lock(&(*mutex)->handle); } /* Unlock the mutex */ int thread_mutex_unlock(thread_mutex_t *mutex) { - return pthread_mutex_unlock(&(*mutex)->handle); + return pthread_mutex_unlock(&(*mutex)->handle); } static void *run_thread(void *arg) { - thread_info_t *thread = arg; - - thread->func(thread->arg); - thread_mutex_lock(&thread_manager.mutex); - list_unlink(&thread_manager.threads, &thread->node); - thread_mutex_unlock(&thread_manager.mutex); - free(thread); - pthread_exit(NULL); + thread_info_t *thread = arg; + + thread->func(thread->arg); + thread_mutex_lock(&thread_manager.mutex); + list_unlink(&thread_manager.threads, &thread->node); + thread_mutex_unlock(&thread_manager.mutex); + free(thread); + pthread_exit(NULL); } static thread_info_t *get_thread_info(thread_t tid) { - list_node_t *node; - thread_info_t *thread; - - for (list_each(node, &thread_manager.threads)) { - thread = node->data; - if (thread && thread->tid == tid) { - return thread; - } - } - return NULL; + list_node_t *node; + thread_info_t *thread; + + for (list_each(node, &thread_manager.threads)) { + thread = node->data; + if (thread && thread->tid == tid) { + return thread; + } + } + return NULL; } static thread_info_t *unlink_thread_info(thread_t tid) { - thread_info_t *thread; - - thread_mutex_lock(&thread_manager.mutex); - thread = get_thread_info(tid); - if (thread) { - list_unlink(&thread_manager.threads, &thread->node); - } - thread_mutex_unlock(&thread_manager.mutex); - return thread; + thread_info_t *thread; + + thread_mutex_lock(&thread_manager.mutex); + thread = get_thread_info(tid); + if (thread) { + list_unlink(&thread_manager.threads, &thread->node); + } + thread_mutex_unlock(&thread_manager.mutex); + return thread; } int thread_create(thread_t *tid, void (*func)(void *), void *arg) { - int ret; - thread_info_t *thread; - - if (!thread_manager.active) { - list_create(&thread_manager.threads); - thread_mutex_init(&thread_manager.mutex); - thread_manager.active = true; - } - thread = malloc(sizeof(thread_info_t)); - if (!thread) { - return -ENOMEM; - } - thread->arg = arg; - thread->func = func; - thread->node.data = thread; - ret = pthread_create(&thread->tid, NULL, run_thread, thread); - if (ret != 0) { - free(thread); - return ret; - } - thread_mutex_lock(&thread_manager.mutex); - list_append_node(&thread_manager.threads, &thread->node); - thread_mutex_unlock(&thread_manager.mutex); - *tid = thread->tid; - return ret; + int ret; + thread_info_t *thread; + + if (!thread_manager.active) { + list_create(&thread_manager.threads); + thread_mutex_init(&thread_manager.mutex); + thread_manager.active = true; + } + thread = malloc(sizeof(thread_info_t)); + if (!thread) { + return -ENOMEM; + } + thread->arg = arg; + thread->func = func; + thread->node.data = thread; + ret = pthread_create(&thread->tid, NULL, run_thread, thread); + if (ret != 0) { + free(thread); + return ret; + } + thread_mutex_lock(&thread_manager.mutex); + list_append_node(&thread_manager.threads, &thread->node); + thread_mutex_unlock(&thread_manager.mutex); + *tid = thread->tid; + return ret; } thread_t thread_self(void) { - return pthread_self(); + return pthread_self(); } void thread_exit(void *retval) { - thread_t tid; - thread_info_t *thread; - - tid = thread_self(); - thread = unlink_thread_info(tid); - if (thread) { - free(thread); - } - pthread_exit(retval); + thread_t tid; + thread_info_t *thread; + + tid = thread_self(); + thread = unlink_thread_info(tid); + if (thread) { + free(thread); + } + pthread_exit(retval); } void thread_cancel(thread_t tid) { #ifdef PTHREAD_CANCEL_ASYNCHRONOUS - pthread_cancel(tid); + pthread_cancel(tid); #else - pthread_kill(tid, SIGKILL); + pthread_kill(tid, SIGKILL); #endif } int thread_join(thread_t tid, void **retval) { - return pthread_join(tid, retval); + return pthread_join(tid, retval); } #endif diff --git a/lib/thread/src/windows.c b/lib/thread/src/windows.c index e129622cd..af48fb7fd 100644 --- a/lib/thread/src/windows.c +++ b/lib/thread/src/windows.c @@ -1,12 +1,15 @@ /* * lib/thread/src/windows.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifdef _WIN32 @@ -18,315 +21,315 @@ #include "thread.h" typedef union thread_mutex_record_t { - HANDLE handle; + HANDLE handle; } thread_mutex_record_t; typedef union thread_cond_record_t { - HANDLE handle; + HANDLE handle; } thread_cond_record_t; typedef struct thread_info { - HANDLE handle; - thread_t tid; - void (*func)(void *); - void *arg; - void *retval; - int has_waiter; - list_node_t node; + HANDLE handle; + thread_t tid; + void (*func)(void *); + void *arg; + void *retval; + int has_waiter; + list_node_t node; } thread_info_t; static struct thread_manager_module { - int active; - thread_mutex_t mutex; - list_t threads; + int active; + thread_mutex_t mutex; + list_t threads; } thread_manager; /** 初始化一个条件变量 */ int thread_cond_init(thread_cond_t *cond) { - HANDLE handle; - - handle = CreateEvent(NULL, false, false, NULL); - if (handle == 0) { - return -1; - } - *cond = malloc(sizeof(thread_cond_record_t)); - if (!*cond) { - return -1; - } - (*cond)->handle = handle; - return 0; + HANDLE handle; + + handle = CreateEvent(NULL, false, false, NULL); + if (handle == 0) { + return -1; + } + *cond = malloc(sizeof(thread_cond_record_t)); + if (!*cond) { + return -1; + } + (*cond)->handle = handle; + return 0; } /** 销毁一个条件变量 */ int thread_cond_destroy(thread_cond_t *cond) { - CloseHandle((*cond)->handle); - free(*cond); - *cond = NULL; - return 0; + CloseHandle((*cond)->handle); + free(*cond); + *cond = NULL; + return 0; } /** 阻塞当前线程,等待条件成立 */ int thread_cond_wait(thread_cond_t *cond, thread_mutex_t *mutex) { - int ret; - thread_mutex_unlock(mutex); - ret = WaitForSingleObject((*cond)->handle, INFINITE); - switch (ret) { - case WAIT_TIMEOUT: - ret = ETIMEDOUT; - break; - case WAIT_OBJECT_0: - ret = 0; - break; - case WAIT_FAILED: - default: - ret = GetLastError(); - break; - } - thread_mutex_lock(mutex); - return ret; + int ret; + thread_mutex_unlock(mutex); + ret = WaitForSingleObject((*cond)->handle, INFINITE); + switch (ret) { + case WAIT_TIMEOUT: + ret = ETIMEDOUT; + break; + case WAIT_OBJECT_0: + ret = 0; + break; + case WAIT_FAILED: + default: + ret = GetLastError(); + break; + } + thread_mutex_lock(mutex); + return ret; } /** 计时阻塞当前线程,等待条件成立 */ int thread_cond_timedwait(thread_cond_t *cond, thread_mutex_t *mutex, - unsigned int ms) + unsigned int ms) { - int ret; - thread_mutex_unlock(mutex); - ret = WaitForSingleObject((*cond)->handle, ms); - switch (ret) { - case WAIT_TIMEOUT: - ret = ETIMEDOUT; - break; - case WAIT_OBJECT_0: - ret = 0; - break; - case WAIT_FAILED: - default: - ret = GetLastError(); - break; - } - thread_mutex_lock(mutex); - return ret; + int ret; + thread_mutex_unlock(mutex); + ret = WaitForSingleObject((*cond)->handle, ms); + switch (ret) { + case WAIT_TIMEOUT: + ret = ETIMEDOUT; + break; + case WAIT_OBJECT_0: + ret = 0; + break; + case WAIT_FAILED: + default: + ret = GetLastError(); + break; + } + thread_mutex_lock(mutex); + return ret; } /** 唤醒一个阻塞等待条件成立的线程 */ int thread_cond_signal(thread_cond_t *cond) { - /* 当编译为 Windows 运行时组件时,直接改为广播 */ + /* 当编译为 Windows 运行时组件时,直接改为广播 */ #ifdef PTK_UWP - return thread_cond_broadcast(cond); + return thread_cond_broadcast(cond); #else - if (PulseEvent((*cond)->handle)) { - return 0; - } - return -1; + if (PulseEvent((*cond)->handle)) { + return 0; + } + return -1; #endif } /** 唤醒所有阻塞等待条件成立的线程 */ int thread_cond_broadcast(thread_cond_t *cond) { - if (SetEvent((*cond)->handle)) { - return 0; - } - return -1; + if (SetEvent((*cond)->handle)) { + return 0; + } + return -1; } int thread_mutex_init(thread_mutex_t *mutex) { - *mutex = malloc(sizeof(thread_mutex_record_t)); - if (!*mutex) { - return -1; - } - (*mutex)->handle = CreateMutex(NULL, false, NULL); - return 0; + *mutex = malloc(sizeof(thread_mutex_record_t)); + if (!*mutex) { + return -1; + } + (*mutex)->handle = CreateMutex(NULL, false, NULL); + return 0; } /* Free the mutex */ void thread_mutex_destroy(thread_mutex_t *mutex) { - CloseHandle((*mutex)->handle); - free(*mutex); - *mutex = NULL; + CloseHandle((*mutex)->handle); + free(*mutex); + *mutex = NULL; } /* Try lock the mutex */ int thread_mutex_trylock(thread_mutex_t *mutex) { - switch (WaitForSingleObject((*mutex)->handle, 0)) { - case WAIT_FAILED: - return -1; - case WAIT_OBJECT_0: - break; - default: - return -2; - } - return 0; + switch (WaitForSingleObject((*mutex)->handle, 0)) { + case WAIT_FAILED: + return -1; + case WAIT_OBJECT_0: + break; + default: + return -2; + } + return 0; } /* Lock the mutex */ int thread_mutex_lock(thread_mutex_t *mutex) { - if (WaitForSingleObject((*mutex)->handle, INFINITE) == WAIT_FAILED) { - return -1; - } - return 0; + if (WaitForSingleObject((*mutex)->handle, INFINITE) == WAIT_FAILED) { + return -1; + } + return 0; } /* Unlock the mutex */ int thread_mutex_unlock(thread_mutex_t *mutex) { - if (ReleaseMutex((*mutex)->handle) == false) { - return -1; - } - return 0; + if (ReleaseMutex((*mutex)->handle) == false) { + return -1; + } + return 0; } static unsigned __stdcall run_thread(void *arg) { - thread_info_t *thread = arg; + thread_info_t *thread = arg; - thread->func(thread->arg); - return 0; + thread->func(thread->arg); + return 0; } int thread_create(thread_t *tid, void (*func)(void *), void *arg) { - thread_info_t *thread; - - if (!thread_manager.active) { - list_create(&thread_manager.threads); - thread_mutex_init(&thread_manager.mutex); - thread_manager.active = true; - } - thread = malloc(sizeof(thread_info_t)); - if (!thread) { - return -ENOMEM; - } - thread->func = func; - thread->arg = arg; - thread->retval = NULL; - thread->node.data = thread; - thread->handle = (HANDLE)_beginthreadex(NULL, 0, run_thread, thread, 0, - &thread->tid); - if (thread->handle == 0) { - *tid = 0; - return -1; - } - thread_mutex_lock(&thread_manager.mutex); - list_append_node(&thread_manager.threads, &thread->node); - thread_mutex_unlock(&thread_manager.mutex); - *tid = thread->tid; - return 0; + thread_info_t *thread; + + if (!thread_manager.active) { + list_create(&thread_manager.threads); + thread_mutex_init(&thread_manager.mutex); + thread_manager.active = true; + } + thread = malloc(sizeof(thread_info_t)); + if (!thread) { + return -ENOMEM; + } + thread->func = func; + thread->arg = arg; + thread->retval = NULL; + thread->node.data = thread; + thread->handle = (HANDLE)_beginthreadex(NULL, 0, run_thread, thread, 0, + &thread->tid); + if (thread->handle == 0) { + *tid = 0; + return -1; + } + thread_mutex_lock(&thread_manager.mutex); + list_append_node(&thread_manager.threads, &thread->node); + thread_mutex_unlock(&thread_manager.mutex); + *tid = thread->tid; + return 0; } static thread_info_t *get_thread_info(thread_t tid) { - thread_info_t *thread; - list_node_t *node; - - for (list_each(node, &thread_manager.threads)) { - thread = node->data; - if (thread && thread->tid == tid) { - return thread; - } - } - return NULL; + thread_info_t *thread; + list_node_t *node; + + for (list_each(node, &thread_manager.threads)) { + thread = node->data; + if (thread && thread->tid == tid) { + return thread; + } + } + return NULL; } static thread_info_t *unlink_thread_info(thread_t tid) { - thread_info_t *thread; - - thread_mutex_lock(&thread_manager.mutex); - thread = get_thread_info(tid); - if (thread) { - list_unlink(&thread_manager.threads, &thread->node); - } - thread_mutex_unlock(&thread_manager.mutex); - return thread; + thread_info_t *thread; + + thread_mutex_lock(&thread_manager.mutex); + thread = get_thread_info(tid); + if (thread) { + list_unlink(&thread_manager.threads, &thread->node); + } + thread_mutex_unlock(&thread_manager.mutex); + return thread; } static void thread_info_destroy(thread_info_t *thread) { - CloseHandle(thread->handle); - thread->handle = NULL; - free(thread); + CloseHandle(thread->handle); + thread->handle = NULL; + free(thread); } thread_t thread_self(void) { - return GetCurrentThreadId(); + return GetCurrentThreadId(); } void thread_exit(void *retval) { - thread_t tid; - thread_info_t *thread; - - tid = thread_self(); - thread = unlink_thread_info(tid); - if (!thread) { - return; - } - thread->retval = retval; - if (!thread->has_waiter) { - thread_info_destroy(thread); - } - _endthread(); + thread_t tid; + thread_info_t *thread; + + tid = thread_self(); + thread = unlink_thread_info(tid); + if (!thread) { + return; + } + thread->retval = retval; + if (!thread->has_waiter) { + thread_info_destroy(thread); + } + _endthread(); } void thread_cancel(thread_t tid) { #ifdef PTK_UWP - abort(); + abort(); #else - thread_info_t *thread; + thread_info_t *thread; - thread = unlink_thread_info(tid); - if (thread) { - TerminateThread(thread->handle, 0); - thread_info_destroy(thread); - } + thread = unlink_thread_info(tid); + if (thread) { + TerminateThread(thread->handle, 0); + thread_info_destroy(thread); + } #endif } int thread_join(thread_t tid, void **retval) { - DWORD code; - thread_info_t *thread; - - thread_mutex_lock(&thread_manager.mutex); - thread = get_thread_info(tid); - if (thread == NULL) { - thread_mutex_unlock(&thread_manager.mutex); - return -1; - } - thread->has_waiter = true; - thread_mutex_unlock(&thread_manager.mutex); - do { - code = 0; - if (GetExitCodeThread(thread->handle, &code) == 0) { - break; - } - if (code == STILL_ACTIVE) { - WaitForSingleObject(thread->handle, 5000); - } else { - break; - } - } while (1); - thread = unlink_thread_info(tid); - if (thread) { - if (retval) { - *retval = thread->retval; - } - thread_info_destroy(thread); - return 0; - } - return -1; + DWORD code; + thread_info_t *thread; + + thread_mutex_lock(&thread_manager.mutex); + thread = get_thread_info(tid); + if (thread == NULL) { + thread_mutex_unlock(&thread_manager.mutex); + return -1; + } + thread->has_waiter = true; + thread_mutex_unlock(&thread_manager.mutex); + do { + code = 0; + if (GetExitCodeThread(thread->handle, &code) == 0) { + break; + } + if (code == STILL_ACTIVE) { + WaitForSingleObject(thread->handle, 5000); + } else { + break; + } + } while (1); + thread = unlink_thread_info(tid); + if (thread) { + if (retval) { + *retval = thread->retval; + } + thread_info_destroy(thread); + return 0; + } + return -1; } #endif diff --git a/lib/thread/tests/main.c b/lib/thread/tests/main.c index 040169ea0..61c72f2dd 100644 --- a/lib/thread/tests/main.c +++ b/lib/thread/tests/main.c @@ -1,4 +1,4 @@ -/* +/* * lib/thread/tests/main.c * * Copyright (c) 2026, Liu Chao All rights reserved. diff --git a/lib/thread/tests/test_thread.c b/lib/thread/tests/test_thread.c index 0e3a2a070..71e26d58c 100644 --- a/lib/thread/tests/test_thread.c +++ b/lib/thread/tests/test_thread.c @@ -1,12 +1,15 @@ /* * lib/thread/tests/test_thread.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ui-cursor/include/ui_cursor.h b/lib/ui-cursor/include/ui_cursor.h index 647af038b..6b67e5a19 100644 --- a/lib/ui-cursor/include/ui_cursor.h +++ b/lib/ui-cursor/include/ui_cursor.h @@ -1,12 +1,15 @@ /* * lib/ui-cursor/include/ui_cursor.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_UI_CURSOR_INCLUDE_UI_CURSOR_H @@ -26,7 +29,8 @@ LIBUI_CURSOR_PUBLIC void ui_cursor_hide(void); LIBUI_CURSOR_PUBLIC void ui_cursor_set_position(int x, int y); LIBUI_CURSOR_PUBLIC int ui_cursor_set_image(pd_canvas_t *image); LIBUI_CURSOR_PUBLIC void ui_cursor_get_position(int *x, int *y); -LIBUI_CURSOR_PUBLIC int ui_cursor_paint(ptk_window_t *w, ptk_window_paint_t* paint); +LIBUI_CURSOR_PUBLIC int ui_cursor_paint(ptk_window_t *w, + ptk_window_paint_t *paint); LIBUI_CURSOR_PUBLIC void ui_cursor_init(void); LIBUI_CURSOR_PUBLIC void ui_cursor_destroy(void); diff --git a/lib/ui-cursor/include/ui_cursor/common.h b/lib/ui-cursor/include/ui_cursor/common.h index 7c0531673..7fa9242d9 100644 --- a/lib/ui-cursor/include/ui_cursor/common.h +++ b/lib/ui-cursor/include/ui_cursor/common.h @@ -1,11 +1,14 @@ /* * lib/ui-cursor/include/ui_cursor/common.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, + * Liu Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ diff --git a/lib/ui-cursor/src/cursor.c b/lib/ui-cursor/src/cursor.c index c5fdd3302..b99de4343 100644 --- a/lib/ui-cursor/src/cursor.c +++ b/lib/ui-cursor/src/cursor.c @@ -1,226 +1,229 @@ /* * lib/ui-cursor/src/cursor.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include static struct ui_cursor { - int x, y; - bool visible; - pd_canvas_t image; - ptk_window_t *window; + int x, y; + bool visible; + pd_canvas_t image; + ptk_window_t *window; } ui_cursor; static unsigned char ui_cursor_image_data[4][12 * 19] = { - { 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, - 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 229, 3, 3, - 0, 0, 0, 0, 0, 0, 0, 0, 3, 255, 229, 3, 3, 0, - 0, 0, 0, 0, 0, 0, 3, 255, 255, 229, 3, 3, 0, 0, - 0, 0, 0, 0, 3, 255, 255, 255, 229, 3, 3, 0, 0, 0, - 0, 0, 3, 255, 255, 255, 255, 229, 3, 3, 0, 0, 0, 0, - 3, 255, 255, 255, 255, 253, 226, 3, 3, 0, 0, 0, 3, 255, - 255, 255, 253, 251, 248, 220, 3, 3, 0, 0, 3, 255, 255, 253, - 251, 248, 245, 241, 214, 3, 3, 0, 3, 255, 253, 251, 248, 245, - 241, 238, 234, 207, 3, 3, 3, 253, 251, 248, 245, 241, 238, 234, - 230, 226, 201, 3, 3, 251, 248, 245, 217, 238, 234, 3, 3, 3, - 3, 3, 3, 248, 245, 217, 3, 164, 230, 3, 3, 0, 0, 0, - 3, 245, 217, 3, 3, 3, 226, 201, 3, 0, 0, 0, 3, 217, - 3, 3, 0, 3, 176, 219, 3, 3, 0, 0, 3, 3, 3, 0, - 0, 3, 3, 216, 192, 3, 0, 0, 0, 0, 0, 0, 0, 0, - 3, 192, 211, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, - 3, 3, 0, 0 }, - { 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, - 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 230, 6, 6, - 0, 0, 0, 0, 0, 0, 0, 0, 6, 255, 230, 6, 6, 0, - 0, 0, 0, 0, 0, 0, 6, 255, 255, 230, 6, 6, 0, 0, - 0, 0, 0, 0, 6, 255, 255, 255, 230, 6, 6, 0, 0, 0, - 0, 0, 6, 255, 255, 255, 255, 230, 6, 6, 0, 0, 0, 0, - 6, 255, 255, 255, 255, 253, 226, 6, 6, 0, 0, 0, 6, 255, - 255, 255, 253, 251, 248, 221, 6, 6, 0, 0, 6, 255, 255, 253, - 251, 248, 245, 241, 214, 6, 6, 0, 6, 255, 253, 251, 248, 245, - 241, 238, 234, 207, 6, 6, 6, 253, 251, 248, 245, 241, 238, 234, - 230, 226, 201, 6, 6, 251, 248, 245, 217, 238, 234, 6, 6, 6, - 6, 6, 6, 248, 245, 217, 6, 165, 230, 6, 6, 0, 0, 0, - 6, 245, 217, 6, 6, 6, 226, 201, 6, 0, 0, 0, 6, 217, - 6, 6, 0, 6, 176, 219, 6, 6, 0, 0, 6, 6, 6, 0, - 0, 6, 6, 216, 192, 6, 0, 0, 0, 0, 0, 0, 0, 0, - 6, 192, 211, 6, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, - 6, 6, 0, 0 }, - { 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, - 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 232, 26, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 26, 255, 232, 26, 26, 0, - 0, 0, 0, 0, 0, 0, 26, 255, 255, 232, 26, 26, 0, 0, - 0, 0, 0, 0, 26, 255, 255, 255, 232, 26, 26, 0, 0, 0, - 0, 0, 26, 255, 255, 255, 255, 232, 26, 26, 0, 0, 0, 0, - 26, 255, 255, 255, 255, 253, 228, 26, 26, 0, 0, 0, 26, 255, - 255, 255, 253, 251, 248, 223, 26, 26, 0, 0, 26, 255, 255, 253, - 251, 248, 245, 241, 216, 26, 26, 0, 26, 255, 253, 251, 248, 245, - 241, 238, 234, 209, 26, 26, 26, 253, 251, 248, 245, 241, 238, 234, - 230, 226, 203, 26, 26, 251, 248, 245, 219, 238, 234, 26, 26, 26, - 26, 26, 26, 248, 245, 219, 26, 171, 230, 26, 26, 0, 0, 0, - 26, 245, 219, 26, 26, 26, 226, 203, 26, 0, 0, 0, 26, 219, - 26, 26, 0, 26, 181, 219, 26, 26, 0, 0, 26, 26, 26, 0, - 0, 26, 26, 216, 194, 26, 0, 0, 0, 0, 0, 0, 0, 0, - 26, 194, 211, 26, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, - 26, 26, 0, 0 }, - { 231, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 189, - 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 255, 189, 55, - 0, 0, 0, 0, 0, 0, 0, 0, 231, 255, 255, 189, 55, 0, - 0, 0, 0, 0, 0, 0, 231, 255, 255, 255, 189, 55, 0, 0, - 0, 0, 0, 0, 231, 255, 255, 255, 255, 189, 55, 0, 0, 0, - 0, 0, 231, 255, 255, 255, 255, 255, 189, 55, 0, 0, 0, 0, - 231, 255, 255, 255, 255, 255, 255, 189, 55, 0, 0, 0, 231, 255, - 255, 255, 255, 255, 255, 255, 189, 55, 0, 0, 231, 255, 255, 255, - 255, 255, 255, 255, 255, 189, 55, 0, 231, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 189, 55, 231, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 189, 231, 255, 255, 255, 255, 255, 255, 189, 189, 189, - 189, 189, 231, 255, 255, 255, 244, 255, 255, 188, 77, 0, 0, 0, - 231, 255, 255, 244, 55, 211, 255, 255, 211, 0, 0, 0, 231, 255, - 244, 55, 0, 180, 255, 255, 180, 77, 0, 0, 189, 244, 55, 0, - 0, 55, 215, 255, 255, 209, 0, 0, 0, 0, 0, 0, 0, 0, - 180, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 26, 215, - 158, 49, 0, 0 } + { 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, + 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 229, 3, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 3, 255, 229, 3, 3, 0, + 0, 0, 0, 0, 0, 0, 3, 255, 255, 229, 3, 3, 0, 0, + 0, 0, 0, 0, 3, 255, 255, 255, 229, 3, 3, 0, 0, 0, + 0, 0, 3, 255, 255, 255, 255, 229, 3, 3, 0, 0, 0, 0, + 3, 255, 255, 255, 255, 253, 226, 3, 3, 0, 0, 0, 3, 255, + 255, 255, 253, 251, 248, 220, 3, 3, 0, 0, 3, 255, 255, 253, + 251, 248, 245, 241, 214, 3, 3, 0, 3, 255, 253, 251, 248, 245, + 241, 238, 234, 207, 3, 3, 3, 253, 251, 248, 245, 241, 238, 234, + 230, 226, 201, 3, 3, 251, 248, 245, 217, 238, 234, 3, 3, 3, + 3, 3, 3, 248, 245, 217, 3, 164, 230, 3, 3, 0, 0, 0, + 3, 245, 217, 3, 3, 3, 226, 201, 3, 0, 0, 0, 3, 217, + 3, 3, 0, 3, 176, 219, 3, 3, 0, 0, 3, 3, 3, 0, + 0, 3, 3, 216, 192, 3, 0, 0, 0, 0, 0, 0, 0, 0, + 3, 192, 211, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, + 3, 3, 0, 0 }, + { 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, + 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 230, 6, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 6, 255, 230, 6, 6, 0, + 0, 0, 0, 0, 0, 0, 6, 255, 255, 230, 6, 6, 0, 0, + 0, 0, 0, 0, 6, 255, 255, 255, 230, 6, 6, 0, 0, 0, + 0, 0, 6, 255, 255, 255, 255, 230, 6, 6, 0, 0, 0, 0, + 6, 255, 255, 255, 255, 253, 226, 6, 6, 0, 0, 0, 6, 255, + 255, 255, 253, 251, 248, 221, 6, 6, 0, 0, 6, 255, 255, 253, + 251, 248, 245, 241, 214, 6, 6, 0, 6, 255, 253, 251, 248, 245, + 241, 238, 234, 207, 6, 6, 6, 253, 251, 248, 245, 241, 238, 234, + 230, 226, 201, 6, 6, 251, 248, 245, 217, 238, 234, 6, 6, 6, + 6, 6, 6, 248, 245, 217, 6, 165, 230, 6, 6, 0, 0, 0, + 6, 245, 217, 6, 6, 6, 226, 201, 6, 0, 0, 0, 6, 217, + 6, 6, 0, 6, 176, 219, 6, 6, 0, 0, 6, 6, 6, 0, + 0, 6, 6, 216, 192, 6, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 192, 211, 6, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, + 6, 6, 0, 0 }, + { 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, + 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 232, 26, 26, + 0, 0, 0, 0, 0, 0, 0, 0, 26, 255, 232, 26, 26, 0, + 0, 0, 0, 0, 0, 0, 26, 255, 255, 232, 26, 26, 0, 0, + 0, 0, 0, 0, 26, 255, 255, 255, 232, 26, 26, 0, 0, 0, + 0, 0, 26, 255, 255, 255, 255, 232, 26, 26, 0, 0, 0, 0, + 26, 255, 255, 255, 255, 253, 228, 26, 26, 0, 0, 0, 26, 255, + 255, 255, 253, 251, 248, 223, 26, 26, 0, 0, 26, 255, 255, 253, + 251, 248, 245, 241, 216, 26, 26, 0, 26, 255, 253, 251, 248, 245, + 241, 238, 234, 209, 26, 26, 26, 253, 251, 248, 245, 241, 238, 234, + 230, 226, 203, 26, 26, 251, 248, 245, 219, 238, 234, 26, 26, 26, + 26, 26, 26, 248, 245, 219, 26, 171, 230, 26, 26, 0, 0, 0, + 26, 245, 219, 26, 26, 26, 226, 203, 26, 0, 0, 0, 26, 219, + 26, 26, 0, 26, 181, 219, 26, 26, 0, 0, 26, 26, 26, 0, + 0, 26, 26, 216, 194, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 26, 194, 211, 26, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, + 26, 26, 0, 0 }, + { 231, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 189, + 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 255, 189, 55, + 0, 0, 0, 0, 0, 0, 0, 0, 231, 255, 255, 189, 55, 0, + 0, 0, 0, 0, 0, 0, 231, 255, 255, 255, 189, 55, 0, 0, + 0, 0, 0, 0, 231, 255, 255, 255, 255, 189, 55, 0, 0, 0, + 0, 0, 231, 255, 255, 255, 255, 255, 189, 55, 0, 0, 0, 0, + 231, 255, 255, 255, 255, 255, 255, 189, 55, 0, 0, 0, 231, 255, + 255, 255, 255, 255, 255, 255, 189, 55, 0, 0, 231, 255, 255, 255, + 255, 255, 255, 255, 255, 189, 55, 0, 231, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 189, 55, 231, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 189, 231, 255, 255, 255, 255, 255, 255, 189, 189, 189, + 189, 189, 231, 255, 255, 255, 244, 255, 255, 188, 77, 0, 0, 0, + 231, 255, 255, 244, 55, 211, 255, 255, 211, 0, 0, 0, 231, 255, + 244, 55, 0, 180, 255, 255, 180, 77, 0, 0, 189, 244, 55, 0, + 0, 55, 215, 255, 255, 209, 0, 0, 0, 0, 0, 0, 0, 0, + 180, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 26, 215, + 158, 49, 0, 0 } }; static int ui_cursor_load_default_image(pd_canvas_t *buff) { - unsigned x, y; - size_t i; - pd_color_t *p; - - if (pd_canvas_is_valid(buff)) { - pd_canvas_destroy(buff); - } - pd_canvas_init(buff); - buff->color_type = PD_COLOR_TYPE_ARGB; - if (pd_canvas_create(buff, 12, 19) != 0) { - return -1; - } - for (y = 0; y < buff->height; ++y) { - i = y * buff->width; - p = buff->argb + i; - for (x = 0; x < buff->width; ++x, ++i) { - p->r = ui_cursor_image_data[0][i]; - p->g = ui_cursor_image_data[1][i]; - p->b = ui_cursor_image_data[2][i]; - p->a = ui_cursor_image_data[3][i]; - } - } - return 0; + unsigned x, y; + size_t i; + pd_color_t *p; + + if (pd_canvas_is_valid(buff)) { + pd_canvas_destroy(buff); + } + pd_canvas_init(buff); + buff->color_type = PD_COLOR_TYPE_ARGB; + if (pd_canvas_create(buff, 12, 19) != 0) { + return -1; + } + for (y = 0; y < buff->height; ++y) { + i = y * buff->width; + p = buff->argb + i; + for (x = 0; x < buff->width; ++x, ++i) { + p->r = ui_cursor_image_data[0][i]; + p->g = ui_cursor_image_data[1][i]; + p->b = ui_cursor_image_data[2][i]; + p->a = ui_cursor_image_data[3][i]; + } + } + return 0; } static void ui_cursor_on_mouse_event(ptk_event_t *e, void *arg) { - // TODO: 事件中的 xy 是否需要转换为相对于窗口客户区? - ui_cursor.x = e->mouse.x; - ui_cursor.y = e->mouse.y; - if (ui_cursor.window != e->window) { - ui_cursor_refresh(); - } - ui_cursor.window = e->window; - ui_cursor_refresh(); + // TODO: 事件中的 xy 是否需要转换为相对于窗口客户区? + ui_cursor.x = e->mouse.x; + ui_cursor.y = e->mouse.y; + if (ui_cursor.window != e->window) { + ui_cursor_refresh(); + } + ui_cursor.window = e->window; + ui_cursor_refresh(); } static void ui_cursor_get_rect(pd_rect_t *rect) { - rect->x = ui_cursor.x; - rect->y = ui_cursor.y; - rect->width = ui_cursor.image.width; - rect->height = ui_cursor.image.height; + rect->x = ui_cursor.x; + rect->y = ui_cursor.y; + rect->width = ui_cursor.image.width; + rect->height = ui_cursor.image.height; } void ui_cursor_refresh(void) { - ptk_event_t e = { 0 }; - - if (!ui_cursor.visible || !ui_cursor.window) { - return; - } - e.type = PTK_EVENT_PAINT; - e.window = ui_cursor.window; - ui_cursor_get_rect(&e.paint.rect); - ptk_post_event(&e); + ptk_event_t e = { 0 }; + + if (!ui_cursor.visible || !ui_cursor.window) { + return; + } + e.type = PTK_EVENT_PAINT; + e.window = ui_cursor.window; + ui_cursor_get_rect(&e.paint.rect); + ptk_post_event(&e); } bool ui_cursor_is_visible(void) { - return ui_cursor.visible; + return ui_cursor.visible; } void ui_cursor_show(void) { - ui_cursor.visible = true; - ui_cursor_refresh(); + ui_cursor.visible = true; + ui_cursor_refresh(); } void ui_cursor_hide(void) { - ui_cursor_refresh(); - ui_cursor.visible = false; + ui_cursor_refresh(); + ui_cursor.visible = false; } void ui_cursor_set_position(int x, int y) { - ui_cursor_refresh(); - ui_cursor.x = x; - ui_cursor.y = y; - ui_cursor_refresh(); + ui_cursor_refresh(); + ui_cursor.x = x; + ui_cursor.y = y; + ui_cursor_refresh(); } int ui_cursor_set_image(pd_canvas_t *image) { - if (pd_canvas_is_valid(image)) { - ui_cursor_refresh(); - if (pd_canvas_is_valid(&ui_cursor.image)) { - pd_canvas_destroy(&ui_cursor.image); - } - pd_canvas_copy(&ui_cursor.image, image); - ui_cursor_refresh(); - return 0; - } - return -1; + if (pd_canvas_is_valid(image)) { + ui_cursor_refresh(); + if (pd_canvas_is_valid(&ui_cursor.image)) { + pd_canvas_destroy(&ui_cursor.image); + } + pd_canvas_copy(&ui_cursor.image, image); + ui_cursor_refresh(); + return 0; + } + return -1; } void ui_cursor_get_position(int *x, int *y) { - *x = ui_cursor.x; - *y = ui_cursor.y; + *x = ui_cursor.x; + *y = ui_cursor.y; } -int ui_cursor_paint(ptk_window_t *w, ptk_window_paint_t* paint) +int ui_cursor_paint(ptk_window_t *w, ptk_window_paint_t *paint) { - int x, y; - if (!ui_cursor.visible) { - return 0; - } - // TODO: 转换为窗口客户区内的坐标 - x = ui_cursor.x - paint->rect.x; - y = ui_cursor.y - paint->rect.y; - return pd_canvas_mix(&paint->canvas, &ui_cursor.image, x, y, false); + int x, y; + if (!ui_cursor.visible) { + return 0; + } + // TODO: 转换为窗口客户区内的坐标 + x = ui_cursor.x - paint->rect.x; + y = ui_cursor.y - paint->rect.y; + return pd_canvas_mix(&paint->canvas, &ui_cursor.image, x, y, false); } void ui_cursor_init(void) { - pd_canvas_t image; - - pd_canvas_init(&image); - pd_canvas_init(&ui_cursor.image); - /* 载入自带的游标的图形数据 */ - ui_cursor_load_default_image(&image); - // TODO: 移除 app 依赖 - ptk_on_event(PTK_EVENT_MOUSEMOVE, ui_cursor_on_mouse_event, NULL); - ui_cursor_set_image(&image); - pd_canvas_destroy(&image); + pd_canvas_t image; + + pd_canvas_init(&image); + pd_canvas_init(&ui_cursor.image); + /* 载入自带的游标的图形数据 */ + ui_cursor_load_default_image(&image); + // TODO: 移除 app 依赖 + ptk_on_event(PTK_EVENT_MOUSEMOVE, ui_cursor_on_mouse_event, NULL); + ui_cursor_set_image(&image); + pd_canvas_destroy(&image); } void ui_cursor_destroy(void) { - pd_canvas_destroy(&ui_cursor.image); + pd_canvas_destroy(&ui_cursor.image); } diff --git a/lib/ui-router/include/ui_router.h b/lib/ui-router/include/ui_router.h index dcd300dc2..ccbe2b26b 100644 --- a/lib/ui-router/include/ui_router.h +++ b/lib/ui-router/include/ui_router.h @@ -1,7 +1,7 @@ -/* +/* * lib/ui-router/include/ui_router.h: -- The router widgets for LCUI. * - * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ui-router/include/ui_router/common.h b/lib/ui-router/include/ui_router/common.h index f8f67d456..e4363a57f 100644 --- a/lib/ui-router/include/ui_router/common.h +++ b/lib/ui-router/include/ui_router/common.h @@ -1,11 +1,14 @@ -/* +/* * lib/ui-router/include/ui_router/common.h * - * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, + * Liu Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ diff --git a/lib/ui-router/include/ui_router/link.h b/lib/ui-router/include/ui_router/link.h index 5daf55f8a..f8809289f 100644 --- a/lib/ui-router/include/ui_router/link.h +++ b/lib/ui-router/include/ui_router/link.h @@ -1,11 +1,14 @@ -/* +/* * lib/ui-router/include/ui_router/link.h * - * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ diff --git a/lib/ui-router/include/ui_router/view.h b/lib/ui-router/include/ui_router/view.h index 06da5b04d..a46ebb0c5 100644 --- a/lib/ui-router/include/ui_router/view.h +++ b/lib/ui-router/include/ui_router/view.h @@ -1,11 +1,14 @@ -/* +/* * lib/ui-router/include/ui_router/view.h * - * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ diff --git a/lib/ui-router/src/link.c b/lib/ui-router/src/link.c index 444adb5d1..be2afcce0 100644 --- a/lib/ui-router/src/link.c +++ b/lib/ui-router/src/link.c @@ -1,12 +1,15 @@ -/* +/* * lib/ui-router/src/link.c * - * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ui-router/src/view.c b/lib/ui-router/src/view.c index 1a9f66bed..490f1f86a 100644 --- a/lib/ui-router/src/view.c +++ b/lib/ui-router/src/view.c @@ -1,12 +1,15 @@ -/* +/* * lib/ui-router/src/view.c * - * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ui-server/include/ui_server.h b/lib/ui-server/include/ui_server.h index 035e023b5..539bca9fe 100644 --- a/lib/ui-server/include/ui_server.h +++ b/lib/ui-server/include/ui_server.h @@ -1,12 +1,15 @@ /* * lib/ui-server/include/ui_server.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_UI_SERVER_INCLUDE_UI_SERVER_H @@ -21,8 +24,10 @@ LIBUI_SERVER_BEGIN_DECLS LIBUI_SERVER_PUBLIC ui_widget_t *ui_server_get_widget(ptk_window_t *window); LIBUI_SERVER_PUBLIC ptk_window_t *ui_server_get_window(ui_widget_t *widget); LIBUI_SERVER_PUBLIC float ui_server_get_window_scale(ptk_window_t *window); -LIBUI_SERVER_PUBLIC int ui_server_disconnect(ui_widget_t *widget, ptk_window_t *window); -LIBUI_SERVER_PUBLIC void ui_server_connect(ui_widget_t *widget, ptk_window_t *window); +LIBUI_SERVER_PUBLIC int ui_server_disconnect(ui_widget_t *widget, + ptk_window_t *window); +LIBUI_SERVER_PUBLIC void ui_server_connect(ui_widget_t *widget, + ptk_window_t *window); LIBUI_SERVER_PUBLIC size_t ui_server_render(void); LIBUI_SERVER_PUBLIC void ui_server_present(void); LIBUI_SERVER_PUBLIC void ui_server_update(void); diff --git a/lib/ui-server/include/ui_server/common.h b/lib/ui-server/include/ui_server/common.h index 01c65e8ae..d852ba082 100644 --- a/lib/ui-server/include/ui_server/common.h +++ b/lib/ui-server/include/ui_server/common.h @@ -1,11 +1,14 @@ /* * lib/ui-server/include/ui_server/common.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, + * Liu Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ diff --git a/lib/ui-server/src/server.c b/lib/ui-server/src/server.c index 013cdc78c..1e9ba0338 100644 --- a/lib/ui-server/src/server.c +++ b/lib/ui-server/src/server.c @@ -1,12 +1,15 @@ /* * lib/ui-server/src/server.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ui-xml/include/ui_xml.h b/lib/ui-xml/include/ui_xml.h index 8edd3bdc7..731cced06 100644 --- a/lib/ui-xml/include/ui_xml.h +++ b/lib/ui-xml/include/ui_xml.h @@ -1,12 +1,15 @@ /* - * lib/ui-xml/include/ui_xml.h: -- The GUI build module, parse UI config code and build UI. - * - * Copyright (c) 2018-2025, Liu chao All rights reserved. + * lib/ui-xml/include/ui_xml.h: -- The GUI build module, parse UI config code + * and build UI. + * Copyright (c) 2018-2026, Liu chao All + * rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part + * of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file + * in the root directory of this source tree. */ #ifndef LIB_UI_XML_INCLUDE_XML_H @@ -22,14 +25,14 @@ LIBUI_XML_BEGIN_DECLS * @param[in] str 包含界面配置代码的字符串 * @return 正常解析会返回一个部件,出现错误则返回 NULL */ -LIBUI_XML_PUBLIC ui_widget_t* ui_load_xml_string(const char *str, int size); +LIBUI_XML_PUBLIC ui_widget_t *ui_load_xml_string(const char *str, int size); /** * 从文件中载入界面配置代码,解析并生成相应的图形界面(元素) * @param[in] filepath 文件路径 * @return 正常解析会返回一个部件,出现错误则返回 NULL */ -LIBUI_XML_PUBLIC ui_widget_t* ui_load_xml_file(const char *filepath); +LIBUI_XML_PUBLIC ui_widget_t *ui_load_xml_file(const char *filepath); LIBUI_XML_END_DECLS diff --git a/lib/ui-xml/include/ui_xml/common.h b/lib/ui-xml/include/ui_xml/common.h index c2325d6b1..b424c2c2c 100644 --- a/lib/ui-xml/include/ui_xml/common.h +++ b/lib/ui-xml/include/ui_xml/common.h @@ -1,12 +1,15 @@ /* * lib/ui-xml/include/ui_xml/common.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "config.h" diff --git a/lib/ui-xml/src/ui_xml.c b/lib/ui-xml/src/ui_xml.c index 5cc476967..cbde59267 100644 --- a/lib/ui-xml/src/ui_xml.c +++ b/lib/ui-xml/src/ui_xml.c @@ -1,12 +1,15 @@ /* - * lib/ui-xml/src/ui_xml.c: -- the GUI build module, parse UI config code and build UI. - * - * Copyright (c) 2018-2025, Liu chao All rights reserved. + * lib/ui-xml/src/ui_xml.c: -- the GUI build module, parse UI config code and + * build UI. + * Copyright (c) 2018-2026, Liu chao All rights + * reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include diff --git a/lib/ui-xml/tests/main.c b/lib/ui-xml/tests/main.c index b8beb4f3e..0d402e9a9 100644 --- a/lib/ui-xml/tests/main.c +++ b/lib/ui-xml/tests/main.c @@ -1,4 +1,4 @@ -/* +/* * lib/ui-xml/tests/main.c * * Copyright (c) 2026, Liu Chao All rights reserved. diff --git a/lib/ui-xml/tests/test_xml_parser.c b/lib/ui-xml/tests/test_xml_parser.c index ef1b883f3..fa1efcf9e 100644 --- a/lib/ui-xml/tests/test_xml_parser.c +++ b/lib/ui-xml/tests/test_xml_parser.c @@ -1,12 +1,15 @@ /* * lib/ui-xml/tests/test_xml_parser.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ui/include/ui.h b/lib/ui/include/ui.h index 2856c380c..31f953722 100644 --- a/lib/ui/include/ui.h +++ b/lib/ui/include/ui.h @@ -1,12 +1,15 @@ /* * lib/ui/include/ui.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_UI_INCLUDE_UI_H diff --git a/lib/ui/include/ui/base.h b/lib/ui/include/ui/base.h index 3d95d9cd1..9ab61d29a 100644 --- a/lib/ui/include/ui/base.h +++ b/lib/ui/include/ui/base.h @@ -1,12 +1,15 @@ /* * lib/ui/include/ui/base.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_UI_INCLUDE_UI_BASE_H @@ -88,8 +91,8 @@ LIBUI_PUBLIC int ui_widget_unlink(ui_widget_t *w); LIBUI_PUBLIC ui_widget_t *ui_widget_prev(ui_widget_t *w); LIBUI_PUBLIC ui_widget_t *ui_widget_next(ui_widget_t *w); LIBUI_PUBLIC ui_widget_t *ui_widget_get_child(ui_widget_t *w, size_t index); -LIBUI_PUBLIC size_t ui_widget_each(ui_widget_t *w, - ui_widget_cb callback, void *arg); +LIBUI_PUBLIC size_t ui_widget_each(ui_widget_t *w, ui_widget_cb callback, + void *arg); LIBUI_PUBLIC ui_widget_t *ui_widget_at(ui_widget_t *widget, int ix, int iy); LIBUI_PUBLIC void ui_print_tree(ui_widget_t *w); @@ -98,7 +101,8 @@ LIBUI_PUBLIC void ui_print_tree(ui_widget_t *w); LIBUI_PUBLIC bool ui_widget_is_visible(ui_widget_t *w); LIBUI_PUBLIC void ui_widget_move(ui_widget_t *w, float left, float top); LIBUI_PUBLIC void ui_widget_resize(ui_widget_t *w, float width, float height); -LIBUI_PUBLIC void ui_widget_set_background_image_url(ui_widget_t *w, const char *path); +LIBUI_PUBLIC void ui_widget_set_background_image_url(ui_widget_t *w, + const char *path); LIBUI_PUBLIC void ui_widget_show(ui_widget_t *w); LIBUI_PUBLIC void ui_widget_hide(ui_widget_t *w); LIBUI_PUBLIC ui_widget_t *ui_widget_get_closest(ui_widget_t *w, @@ -124,8 +128,8 @@ LIBUI_PUBLIC void ui_widget_reset_width(ui_widget_t *w); LIBUI_PUBLIC void ui_widget_reset_height(ui_widget_t *w); -LIBUI_PUBLIC void ui_widget_compute_size(ui_widget_t *w, float *width, float *height); - +LIBUI_PUBLIC void ui_widget_compute_size(ui_widget_t *w, float *width, + float *height); LIBUI_PUBLIC void ui_widget_reflow_if_width_changed(ui_widget_t *w); LIBUI_PUBLIC void ui_widget_reflow_if_height_changed(ui_widget_t *w); diff --git a/lib/ui/include/ui/common.h b/lib/ui/include/ui/common.h index a868967d6..58fdf8853 100644 --- a/lib/ui/include/ui/common.h +++ b/lib/ui/include/ui/common.h @@ -1,12 +1,15 @@ /* * lib/ui/include/ui/common.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_UI_INCLUDE_UI_COMMON_H @@ -49,7 +52,7 @@ #endif #define _DEBUG_MSG(format, ...) \ - logger_log(LOGGER_LEVEL_DEBUG, __FILE__ ":%d: %s(): " format, \ - __LINE__, __FUNCTION__, ##__VA_ARGS__) + logger_log(LOGGER_LEVEL_DEBUG, __FILE__ ":%d: %s(): " format, \ + __LINE__, __FUNCTION__, ##__VA_ARGS__) #endif diff --git a/lib/ui/include/ui/css.h b/lib/ui/include/ui/css.h index 465a7fde7..9beaa6b2c 100644 --- a/lib/ui/include/ui/css.h +++ b/lib/ui/include/ui/css.h @@ -1,12 +1,15 @@ /* * lib/ui/include/ui/css.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_UI_INCLUDE_UI_CSS_H diff --git a/lib/ui/include/ui/events.h b/lib/ui/include/ui/events.h index 2463e7f4f..e21527e5b 100644 --- a/lib/ui/include/ui/events.h +++ b/lib/ui/include/ui/events.h @@ -1,12 +1,15 @@ /* * lib/ui/include/ui/events.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_UI_INCLUDE_UI_EVENTS_H diff --git a/lib/ui/include/ui/hash.h b/lib/ui/include/ui/hash.h index 37fe030d7..74df6d5ef 100644 --- a/lib/ui/include/ui/hash.h +++ b/lib/ui/include/ui/hash.h @@ -1,12 +1,15 @@ /* * lib/ui/include/ui/hash.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_UI_INCLUDE_UI_HASH_H @@ -20,9 +23,9 @@ LIBUI_BEGIN_DECLS LIBUI_PUBLIC void ui_widget_generate_self_hash(ui_widget_t *widget); LIBUI_PUBLIC void ui_widget_generate_hash(ui_widget_t *w); LIBUI_PUBLIC size_t ui_widget_export_hash(ui_widget_t *w, unsigned *hash_list, - size_t len); + size_t len); LIBUI_PUBLIC size_t ui_widget_import_hash(ui_widget_t *w, unsigned *hash_list, - size_t maxlen); + size_t maxlen); LIBUI_END_DECLS diff --git a/lib/ui/include/ui/image.h b/lib/ui/include/ui/image.h index 87eef7290..0a58e2484 100644 --- a/lib/ui/include/ui/image.h +++ b/lib/ui/include/ui/image.h @@ -1,12 +1,15 @@ /* * lib/ui/include/ui/image.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_UI_INCLUDE_UI_IMAGE_H diff --git a/lib/ui/include/ui/logger.h b/lib/ui/include/ui/logger.h index 1c0fda9c2..92a0b62f5 100644 --- a/lib/ui/include/ui/logger.h +++ b/lib/ui/include/ui/logger.h @@ -1,12 +1,15 @@ /* * lib/ui/include/ui/logger.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_UI_INCLUDE_UI_LOGGER_H @@ -18,7 +21,7 @@ LIBUI_BEGIN_DECLS LIBUI_PUBLIC int ui_logger_log(logger_level_e level, ui_widget_t *w, - const char *fmt, ...); + const char *fmt, ...); #define ui_debug(W, ...) ui_logger_log(LOGGER_LEVEL_DEBUG, W, ##__VA_ARGS__) diff --git a/lib/ui/include/ui/metrics.h b/lib/ui/include/ui/metrics.h index 9446446dd..5d4ea8fbc 100644 --- a/lib/ui/include/ui/metrics.h +++ b/lib/ui/include/ui/metrics.h @@ -1,12 +1,15 @@ /* * lib/ui/include/ui/metrics.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_UI_INCLUDE_UI_METRICS_H diff --git a/lib/ui/include/ui/mutation_observer.h b/lib/ui/include/ui/mutation_observer.h index 8b3920d6d..6da2b85af 100644 --- a/lib/ui/include/ui/mutation_observer.h +++ b/lib/ui/include/ui/mutation_observer.h @@ -1,11 +1,14 @@ /* * lib/ui/include/ui/mutation_observer.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu + * Chao All rights reserved. * - * SPDX-License-Identifier: MIT + * SPDX-License-Identifier: + * MIT * - * This file is part of LCUI, distributed under the MIT License found in the + * This file is part of LCUI, distributed under the MIT License found + * in the * LICENSE.TXT file in the root directory of this source tree. */ diff --git a/lib/ui/include/ui/prototype.h b/lib/ui/include/ui/prototype.h index d74ab0ed7..5408e1a77 100644 --- a/lib/ui/include/ui/prototype.h +++ b/lib/ui/include/ui/prototype.h @@ -1,12 +1,15 @@ /* * lib/ui/include/ui/prototype.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_UI_INCLUDE_UI_PROTOTYPE_H diff --git a/lib/ui/include/ui/rect.h b/lib/ui/include/ui/rect.h index 9c7de04fd..b25030536 100644 --- a/lib/ui/include/ui/rect.h +++ b/lib/ui/include/ui/rect.h @@ -1,12 +1,15 @@ /* * lib/ui/include/ui/rect.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_UI_INCLUDE_UI_RECT_H diff --git a/lib/ui/include/ui/style.h b/lib/ui/include/ui/style.h index f992d48a0..e223ba121 100644 --- a/lib/ui/include/ui/style.h +++ b/lib/ui/include/ui/style.h @@ -1,12 +1,15 @@ /* * lib/ui/include/ui/style.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_UI_INCLUDE_UI_STYLE_H @@ -20,9 +23,9 @@ LIBUI_BEGIN_DECLS LIBUI_PUBLIC void ui_widget_get_style(ui_widget_t *w, int key, - css_style_value_t *value); + css_style_value_t *value); LIBUI_PUBLIC void ui_widget_set_style(ui_widget_t *w, int key, - const css_style_value_t *value); + const css_style_value_t *value); LIBUI_PUBLIC int ui_widget_unset_style(ui_widget_t *w, int key); LIBUI_PUBLIC css_selector_node_t *ui_widget_create_selector_node( ui_widget_t *w); @@ -30,17 +33,17 @@ LIBUI_PUBLIC css_selector_t *ui_widget_create_selector(ui_widget_t *w); LIBUI_PUBLIC void ui_widget_update_children_style(ui_widget_t *w); LIBUI_PUBLIC void ui_widget_refresh_children_style(ui_widget_t *w); LIBUI_PUBLIC int ui_widget_set_style_string(ui_widget_t *w, - const char *property, - const char *css_text); + const char *property, + const char *css_text); LIBUI_PUBLIC void ui_widget_set_style_unit_value(ui_widget_t *w, int key, - css_numeric_value_t value, - css_unit_t unit); + css_numeric_value_t value, + css_unit_t unit); LIBUI_PUBLIC void ui_widget_set_style_keyword_value(ui_widget_t *w, int key, - css_keyword_value_t value); + css_keyword_value_t value); LIBUI_PUBLIC void ui_widget_set_style_color_value(ui_widget_t *w, int key, - css_color_value_t value); + css_color_value_t value); LIBUI_PUBLIC void ui_widget_set_style_numeric_value(ui_widget_t *w, int key, - css_numeric_value_t value); + css_numeric_value_t value); LIBUI_PUBLIC void ui_widget_compute_style(ui_widget_t *w); LIBUI_PUBLIC void ui_widget_update_style(ui_widget_t *w); diff --git a/lib/ui/include/ui/text_style.h b/lib/ui/include/ui/text_style.h index cac516802..8a4914386 100644 --- a/lib/ui/include/ui/text_style.h +++ b/lib/ui/include/ui/text_style.h @@ -1,12 +1,15 @@ /* * lib/ui/include/ui/text_style.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_UI_INCLUDE_UI_TEXT_STYLE_H @@ -25,16 +28,16 @@ LIBUI_BEGIN_DECLS #define UI_LINE_HEIGHT_SCALE 1.42857143 typedef struct ui_text_style { - int font_size; - int line_height; - int *font_ids; - wchar_t *content; - pd_color_t color; - uint8_t font_style; - uint8_t font_weight; - uint8_t text_align; - uint8_t white_space; - uint8_t word_break; + int font_size; + int line_height; + int *font_ids; + wchar_t *content; + pd_color_t color; + uint8_t font_style; + uint8_t font_weight; + uint8_t text_align; + uint8_t white_space; + uint8_t word_break; } ui_text_style_t; LIBUI_PUBLIC void ui_text_style_init(ui_text_style_t *fs); @@ -42,10 +45,10 @@ LIBUI_PUBLIC void ui_text_style_init(ui_text_style_t *fs); LIBUI_PUBLIC void ui_text_style_destroy(ui_text_style_t *fs); LIBUI_PUBLIC bool ui_text_style_is_equal(const ui_text_style_t *a, - const ui_text_style_t *b); + const ui_text_style_t *b); LIBUI_PUBLIC void ui_compute_text_style(ui_text_style_t *fs, - const css_computed_style_t *ss); + const css_computed_style_t *ss); LIBUI_END_DECLS diff --git a/lib/ui/include/ui/types.h b/lib/ui/include/ui/types.h index d3e5e2d42..c72e88f7b 100644 --- a/lib/ui/include/ui/types.h +++ b/lib/ui/include/ui/types.h @@ -1,12 +1,15 @@ /* * lib/ui/include/ui/types.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_UI_INCLUDE_UI_TPYES_H @@ -182,7 +185,7 @@ struct ui_widget_prototype { void (*update)(ui_widget_t *, ui_task_type_t); void (*setattr)(ui_widget_t *, const char *, const char *); void (*settext)(ui_widget_t *, const char *); - void (*sizehint)(ui_widget_t *, ui_sizehint_t*); + void (*sizehint)(ui_widget_t *, ui_sizehint_t *); void (*resize)(ui_widget_t *, float, float); void (*paint)(ui_widget_t *, pd_context_t *, ui_widget_actual_style_t *); diff --git a/lib/ui/include/ui/updater.h b/lib/ui/include/ui/updater.h index 1987c8044..c3f3be062 100644 --- a/lib/ui/include/ui/updater.h +++ b/lib/ui/include/ui/updater.h @@ -1,12 +1,15 @@ /* * lib/ui/include/ui/updater.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #ifndef LIB_UI_INCLUDE_UI_UPDATER_H diff --git a/lib/ui/src/ui.c b/lib/ui/src/ui.c index fccfad5ef..cb3e931d2 100644 --- a/lib/ui/src/ui.c +++ b/lib/ui/src/ui.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is + * part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT + * file in the root directory of this source tree. */ #include @@ -22,25 +25,25 @@ void ui_init(void) { - pd_font_library_init(); - ui_init_widget_id(); - ui_init_widget_prototype(); - ui_init_updater(); - ui_init_root(); - ui_init_events(); - ui_init_css(); - ui_init_image_loader(); + pd_font_library_init(); + ui_init_widget_id(); + ui_init_widget_prototype(); + ui_init_updater(); + ui_init_root(); + ui_init_events(); + ui_init_css(); + ui_init_image_loader(); } void ui_destroy(void) { - pd_font_library_destroy(); - ui_clear_trash(); - ui_destroy_root(); - ui_destroy_events(); - ui_destroy_image_loader(); - ui_destroy_widget_id(); - ui_destroy_widget_prototype(); - ui_destroy_css(); - ui_destroy_updater(); + pd_font_library_destroy(); + ui_clear_trash(); + ui_destroy_root(); + ui_destroy_events(); + ui_destroy_image_loader(); + ui_destroy_widget_id(); + ui_destroy_widget_prototype(); + ui_destroy_css(); + ui_destroy_updater(); } diff --git a/lib/ui/src/ui_block_layout.c b/lib/ui/src/ui_block_layout.c index db6dec177..913bbb802 100644 --- a/lib/ui/src/ui_block_layout.c +++ b/lib/ui/src/ui_block_layout.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_block_layout.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ // #define UI_DEBUG_ENABLED diff --git a/lib/ui/src/ui_block_layout.h b/lib/ui/src/ui_block_layout.h index c22fb1b44..f7bcca296 100644 --- a/lib/ui/src/ui_block_layout.h +++ b/lib/ui/src/ui_block_layout.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_block_layout.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -10,4 +10,3 @@ */ void ui_block_layout_reflow(ui_widget_t *w, ui_resizer_t *resizer); - diff --git a/lib/ui/src/ui_css.c b/lib/ui/src/ui_css.c index 8b98d99a4..41fe6775d 100644 --- a/lib/ui/src/ui_css.c +++ b/lib/ui/src/ui_css.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_css.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -37,70 +40,70 @@ root {\ static void ui_on_parsed_font_face(const css_font_face_t *face) { - ui_event_t e; + ui_event_t e; - ui_event_init(&e, "css_font_face_load"); - pd_font_load_file(face->src); - ui_post_event(&e, (css_font_face_t*)face, NULL); + ui_event_init(&e, "css_font_face_load"); + pd_font_load_file(face->src); + ui_post_event(&e, (css_font_face_t *)face, NULL); } static void ui_on_css_loaded(void) { - ui_event_t e; + ui_event_t e; ui_refresh_style(); - ui_event_init(&e, "css_load"); - ui_post_event(&e, NULL, NULL); + ui_event_init(&e, "css_load"); + ui_post_event(&e, NULL, NULL); } int ui_load_css_file(const char *filepath) { - size_t n; - FILE *fp; - char buff[512]; - css_parser_t *parser; + size_t n; + FILE *fp; + char buff[512]; + css_parser_t *parser; - fp = fopen(filepath, "r"); - if (!fp) { - return -1; - } - parser = css_parser_create(filepath); - css_font_face_parser_on_load(parser, ui_on_parsed_font_face); - while ((n = fread(buff, 1, 511, fp)) > 0) { - buff[n] = 0; - css_parser_parse(parser, buff); - } - css_parser_destroy(parser); - fclose(fp); - ui_on_css_loaded(); - return 0; + fp = fopen(filepath, "r"); + if (!fp) { + return -1; + } + parser = css_parser_create(filepath); + css_font_face_parser_on_load(parser, ui_on_parsed_font_face); + while ((n = fread(buff, 1, 511, fp)) > 0) { + buff[n] = 0; + css_parser_parse(parser, buff); + } + css_parser_destroy(parser); + fclose(fp); + ui_on_css_loaded(); + return 0; } size_t ui_load_css_string(const char *str, const char *space) { - size_t len = 1; - const char *cur; - css_parser_t *parser; + size_t len = 1; + const char *cur; + css_parser_t *parser; - DEBUG_MSG("parse begin\n"); - parser = css_parser_create(space); - css_font_face_parser_on_load(parser, ui_on_parsed_font_face); - for (cur = str; len > 0; cur += len) { - len = css_parser_parse(parser, cur); - } - css_parser_destroy(parser); - ui_on_css_loaded(); - DEBUG_MSG("parse end\n"); - return 0; + DEBUG_MSG("parse begin\n"); + parser = css_parser_create(space); + css_font_face_parser_on_load(parser, ui_on_parsed_font_face); + for (cur = str; len > 0; cur += len) { + len = css_parser_parse(parser, cur); + } + css_parser_destroy(parser); + ui_on_css_loaded(); + DEBUG_MSG("parse end\n"); + return 0; } void ui_init_css(void) { - css_init(); - ui_load_css_string(ui_default_css, __FILE__); + css_init(); + ui_load_css_string(ui_default_css, __FILE__); } void ui_destroy_css(void) { - css_destroy(); + css_destroy(); } diff --git a/lib/ui/src/ui_css.h b/lib/ui/src/ui_css.h index b1dd46c65..c1eeeca10 100644 --- a/lib/ui/src/ui_css.h +++ b/lib/ui/src/ui_css.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_css.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ui/src/ui_debug.c b/lib/ui/src/ui_debug.c index fbb87b446..2268c5b21 100644 --- a/lib/ui/src/ui_debug.c +++ b/lib/ui/src/ui_debug.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_debug.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -17,81 +20,83 @@ int ui_debug_msg_indent = 0; LIBUI_INLINE const char *get_css_unit_str(css_unit_t unit) { - switch (unit) { - case CSS_UNIT_PERCENT: - return "%"; - case CSS_UNIT_DIP: - return "dip"; - case CSS_UNIT_PT: - return "pt"; - case CSS_UNIT_SP: - return "sp"; - case CSS_UNIT_PX: - return "px"; - default: - break; - } - return ""; + switch (unit) { + case CSS_UNIT_PERCENT: + return "%"; + case CSS_UNIT_DIP: + return "dip"; + case CSS_UNIT_PT: + return "pt"; + case CSS_UNIT_SP: + return "sp"; + case CSS_UNIT_PX: + return "px"; + default: + break; + } + return ""; } void ui_widget_to_string(ui_widget_t *w, char *str) { - css_selector_node_t *node = ui_widget_create_selector_node(w); - if (node->status) { - strlist_free(node->status); - node->status = NULL; - css_selector_node_update(node); - } - strcpy(str, node->fullname ? node->fullname : ""); - css_selector_node_destroy(node); + css_selector_node_t *node = ui_widget_create_selector_node(w); + if (node->status) { + strlist_free(node->status); + node->status = NULL; + css_selector_node_update(node); + } + strcpy(str, node->fullname ? node->fullname : ""); + css_selector_node_destroy(node); } void ui_widget_size_to_string(ui_widget_t *w, char str[40]) { - char width_str[16] = "auto"; - char height_str[16] = "auto"; + char width_str[16] = "auto"; + char height_str[16] = "auto"; - switch (w->computed_style.type_bits.width) { - case CSS_WIDTH_FIT_CONTENT: - strcpy(width_str, "fit-content"); - break; - case CSS_WIDTH_SET: - snprintf(width_str, 16, "%g%s", w->computed_style.width, - get_css_unit_str(w->computed_style.unit_bits.width)); - break; - default: - break; - } - switch (w->computed_style.type_bits.height) { - case CSS_HEIGHT_SET: - snprintf(height_str, 16, "%g%s", w->computed_style.height, - get_css_unit_str(w->computed_style.unit_bits.height)); - break; - } - snprintf(str, 40, "(%s, %s)", width_str, height_str); + switch (w->computed_style.type_bits.width) { + case CSS_WIDTH_FIT_CONTENT: + strcpy(width_str, "fit-content"); + break; + case CSS_WIDTH_SET: + snprintf(width_str, 16, "%g%s", w->computed_style.width, + get_css_unit_str(w->computed_style.unit_bits.width)); + break; + default: + break; + } + switch (w->computed_style.type_bits.height) { + case CSS_HEIGHT_SET: + snprintf(height_str, 16, "%g%s", w->computed_style.height, + get_css_unit_str(w->computed_style.unit_bits.height)); + break; + } + snprintf(str, 40, "(%s, %s)", width_str, height_str); } void ui_widget_min_size_to_string(ui_widget_t *w, char str[40]) { - char width_str[16] = "auto"; - char height_str[16] = "auto"; + char width_str[16] = "auto"; + char height_str[16] = "auto"; - switch (w->computed_style.type_bits.min_width) { - case CSS_MIN_WIDTH_MIN_CONTENT: - strcpy(width_str, "min-content"); - break; - case CSS_WIDTH_SET: - snprintf(width_str, 16, "%g%s", w->computed_style.min_width, - get_css_unit_str(w->computed_style.unit_bits.min_width)); - break; - default: - break; - } - switch (w->computed_style.type_bits.min_height) { - case CSS_HEIGHT_SET: - snprintf(height_str, 16, "%g%s", w->computed_style.min_height, - get_css_unit_str(w->computed_style.unit_bits.min_height)); - break; - } - snprintf(str, 40, "(%s, %s)", width_str, height_str); + switch (w->computed_style.type_bits.min_width) { + case CSS_MIN_WIDTH_MIN_CONTENT: + strcpy(width_str, "min-content"); + break; + case CSS_WIDTH_SET: + snprintf( + width_str, 16, "%g%s", w->computed_style.min_width, + get_css_unit_str(w->computed_style.unit_bits.min_width)); + break; + default: + break; + } + switch (w->computed_style.type_bits.min_height) { + case CSS_HEIGHT_SET: + snprintf( + height_str, 16, "%g%s", w->computed_style.min_height, + get_css_unit_str(w->computed_style.unit_bits.min_height)); + break; + } + snprintf(str, 40, "(%s, %s)", width_str, height_str); } diff --git a/lib/ui/src/ui_debug.h b/lib/ui/src/ui_debug.h index 6f8db5a64..73d539ed0 100644 --- a/lib/ui/src/ui_debug.h +++ b/lib/ui/src/ui_debug.h @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_debug.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ void ui_widget_to_string(ui_widget_t *w, char *str); diff --git a/lib/ui/src/ui_diff.c b/lib/ui/src/ui_diff.c index f521f2dca..275bf6867 100644 --- a/lib/ui/src/ui_diff.c +++ b/lib/ui/src/ui_diff.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_diff.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ // #define UI_DEBUG_ENABLED @@ -72,7 +75,8 @@ void ui_style_diff_end(ui_style_diff_t *diff, ui_widget_t *w) { UI_WIDGET_STR(w, str); UI_WIDGET_SIZE_STR(w, size_str); - UI_DEBUG_MSG("%s: %s: size=%s, reflow", __FUNCTION__, str, size_str); + UI_DEBUG_MSG("%s: %s: size=%s, reflow", __FUNCTION__, + str, size_str); } #endif ui_widget_request_reflow(w); diff --git a/lib/ui/src/ui_diff.h b/lib/ui/src/ui_diff.h index e9f90d257..084216444 100644 --- a/lib/ui/src/ui_diff.h +++ b/lib/ui/src/ui_diff.h @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_diff.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ typedef struct ui_diff_item { diff --git a/lib/ui/src/ui_events.c b/lib/ui/src/ui_events.c index f19d08b8b..2ebe2bff7 100644 --- a/lib/ui/src/ui_events.c +++ b/lib/ui/src/ui_events.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_events.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -95,1106 +98,1107 @@ static struct ui_events { static int ui_use_widget_event_id(const char *event_name) { - int id = ui_get_event_id(event_name); - if (id < 0) { - id = ui_alloc_event_id(); - ui_set_event_id(id, event_name); - } - return id; + int id = ui_get_event_id(event_name); + if (id < 0) { + id = ui_alloc_event_id(); + ui_set_event_id(id, event_name); + } + return id; } int ui_set_event_id(int event_id, const char *event_name) { - int ret; - ui_event_mapping_t *mapping; - - if (dict_fetch_value(ui_events.event_ids, event_name)) { - return -1; - } - mapping = malloc(sizeof(ui_event_mapping_t)); - if (!mapping) { - return -2; - } - mapping->name = strdup2(event_name); - mapping->id = event_id; - list_append(&ui_events.event_mappings, mapping); - rbtree_insert_by_key(&ui_events.event_names, event_id, mapping); - ret = dict_add(ui_events.event_ids, mapping->name, mapping); - return ret; + int ret; + ui_event_mapping_t *mapping; + + if (dict_fetch_value(ui_events.event_ids, event_name)) { + return -1; + } + mapping = malloc(sizeof(ui_event_mapping_t)); + if (!mapping) { + return -2; + } + mapping->name = strdup2(event_name); + mapping->id = event_id; + list_append(&ui_events.event_mappings, mapping); + rbtree_insert_by_key(&ui_events.event_names, event_id, mapping); + ret = dict_add(ui_events.event_ids, mapping->name, mapping); + return ret; } int ui_alloc_event_id(void) { - return ui_events.base_event_id++; + return ui_events.base_event_id++; } const char *ui_get_event_name(int event_id) { - ui_event_mapping_t *mapping; - mapping = rbtree_get_data_by_key(&ui_events.event_names, event_id); - return mapping ? mapping->name : NULL; + ui_event_mapping_t *mapping; + mapping = rbtree_get_data_by_key(&ui_events.event_names, event_id); + return mapping ? mapping->name : NULL; } int ui_get_event_id(const char *event_name) { - ui_event_mapping_t *mapping; - mapping = dict_fetch_value(ui_events.event_ids, event_name); - return mapping ? mapping->id : -1; + ui_event_mapping_t *mapping; + mapping = dict_fetch_value(ui_events.event_ids, event_name); + return mapping ? mapping->id : -1; } void ui_event_init(ui_event_t *e, const char *name) { - e->target = NULL; - e->type = ui_use_widget_event_id(name); - e->cancel_bubble = false; - e->data = NULL; + e->target = NULL; + e->type = ui_use_widget_event_id(name); + e->cancel_bubble = false; + e->data = NULL; } void ui_event_destroy(ui_event_t *e) { - switch (e->type) { - case UI_EVENT_TOUCH: - if (e->touch.points) { - free(e->touch.points); - } - e->touch.points = NULL; - e->touch.n_points = 0; - break; - case UI_EVENT_TEXTINPUT: - if (e->text.text) { - free(e->text.text); - } - e->text.text = NULL; - e->text.length = 0; - break; - default: - break; - } + switch (e->type) { + case UI_EVENT_TOUCH: + if (e->touch.points) { + free(e->touch.points); + } + e->touch.points = NULL; + e->touch.n_points = 0; + break; + case UI_EVENT_TEXTINPUT: + if (e->text.text) { + free(e->text.text); + } + e->text.text = NULL; + e->text.length = 0; + break; + default: + break; + } } static int ui_event_copy(const ui_event_t *src, ui_event_t *dst) { - int n; - size_t size; - - *dst = *src; - switch (src->type) { - case UI_EVENT_TOUCH: - if (dst->touch.n_points <= 0) { - break; - } - n = dst->touch.n_points; - size = sizeof(ui_touch_point_t) * n; - dst->touch.points = malloc(size); - if (!dst->touch.points) { - return -ENOMEM; - } - memcpy(dst->touch.points, src->touch.points, size); - break; - case UI_EVENT_TEXTINPUT: - if (!dst->text.text) { - break; - } - dst->text.text = - malloc(sizeof(wchar_t) * (dst->text.length + 1)); - if (!dst->text.text) { - return -ENOMEM; - } - wcsncpy(dst->text.text, src->text.text, dst->text.length + 1); - default: - break; - } - return 0; + int n; + size_t size; + + *dst = *src; + switch (src->type) { + case UI_EVENT_TOUCH: + if (dst->touch.n_points <= 0) { + break; + } + n = dst->touch.n_points; + size = sizeof(ui_touch_point_t) * n; + dst->touch.points = malloc(size); + if (!dst->touch.points) { + return -ENOMEM; + } + memcpy(dst->touch.points, src->touch.points, size); + break; + case UI_EVENT_TEXTINPUT: + if (!dst->text.text) { + break; + } + dst->text.text = + malloc(sizeof(wchar_t) * (dst->text.length + 1)); + if (!dst->text.text) { + return -ENOMEM; + } + wcsncpy(dst->text.text, src->text.text, dst->text.length + 1); + default: + break; + } + return 0; } static void ui_event_mapping_destroy(void *data) { - ui_event_mapping_t *mapping = data; - free(mapping->name); - free(mapping); + ui_event_mapping_t *mapping = data; + free(mapping->name); + free(mapping); } static void ui_event_pack_destroy(ui_event_pack_t *pack) { - if (pack->data && pack->destroy_data) { - pack->destroy_data(pack->data); - } - ui_event_destroy(&pack->event); - pack->data = NULL; - free(pack); + if (pack->data && pack->destroy_data) { + pack->destroy_data(pack->data); + } + ui_event_destroy(&pack->event); + pack->data = NULL; + free(pack); } static void ui_event_listener_destroy(ui_event_listener_t *listener) { - if (listener->data && listener->destroy_data) { - listener->destroy_data(listener->data); - } - listener->destroy_data = NULL; - listener->handler = NULL; - listener->data = NULL; - free(listener); + if (listener->data && listener->destroy_data) { + listener->destroy_data(listener->data); + } + listener->destroy_data = NULL; + listener->handler = NULL; + listener->data = NULL; + free(listener); } static void ui_touch_capturer_destroy(void *arg) { - ui_touch_capturer_t *tc = arg; - list_destroy(&tc->points, free); - tc->widget = NULL; - free(tc); + ui_touch_capturer_t *tc = arg; + list_destroy(&tc->points, free); + tc->widget = NULL; + free(tc); } LIBUI_INLINE void ui_clear_touch_capturers(list_t *list) { - list_destroy_without_node(list, ui_touch_capturer_destroy); + list_destroy_without_node(list, ui_touch_capturer_destroy); } static int ui_add_touch_capturer(list_t *list, ui_widget_t *w, int point_id) { - int *data; - ui_touch_capturer_t *tc = NULL; - list_node_t *node, *ptnode; - - if (point_id < 0) { - tc = malloc(sizeof(ui_touch_capturer_t)); - if (!tc) { - return -1; - } - tc->widget = w; - list_create(&tc->points); - ui_clear_touch_capturers(list); - list_append(list, tc); - return 0; - } - /* 获取该部件的触点捕捉记录 */ - for (list_each(node, list)) { - tc = node->data; - /* 清除与该触点绑定的其它捕捉记录 */ - for (list_each(ptnode, &tc->points)) { - if (point_id == *(int *)ptnode->data) { - if (tc->widget == w) { - return 0; - } - return -1; - } - } - if (tc->widget == w) { - break; - } - } - /* 如果没有该部件的触点捕捉记录 */ - if (!tc || tc->widget != w) { - tc = malloc(sizeof(ui_touch_capturer_t)); - tc->widget = w; - tc->node.data = tc; - list_create(&tc->points); - list_append_node(list, &tc->node); - } - /* 追加触点捕捉记录 */ - data = malloc(sizeof(int)); - *data = point_id; - list_append(&tc->points, data); - return 0; + int *data; + ui_touch_capturer_t *tc = NULL; + list_node_t *node, *ptnode; + + if (point_id < 0) { + tc = malloc(sizeof(ui_touch_capturer_t)); + if (!tc) { + return -1; + } + tc->widget = w; + list_create(&tc->points); + ui_clear_touch_capturers(list); + list_append(list, tc); + return 0; + } + /* 获取该部件的触点捕捉记录 */ + for (list_each(node, list)) { + tc = node->data; + /* 清除与该触点绑定的其它捕捉记录 */ + for (list_each(ptnode, &tc->points)) { + if (point_id == *(int *)ptnode->data) { + if (tc->widget == w) { + return 0; + } + return -1; + } + } + if (tc->widget == w) { + break; + } + } + /* 如果没有该部件的触点捕捉记录 */ + if (!tc || tc->widget != w) { + tc = malloc(sizeof(ui_touch_capturer_t)); + tc->widget = w; + tc->node.data = tc; + list_create(&tc->points); + list_append_node(list, &tc->node); + } + /* 追加触点捕捉记录 */ + data = malloc(sizeof(int)); + *data = point_id; + list_append(&tc->points, data); + return 0; } static int ui_remove_touch_capturer(list_t *list, ui_widget_t *w, int point_id) { - ui_touch_capturer_t *tc = NULL; - list_node_t *node, *ptnode; - for (list_each(node, list)) { - tc = node->data; - if (tc->widget == w) { - break; - } - } - if (!tc || tc->widget != w) { - return -1; - } - if (point_id < 0) { - list_destroy(&tc->points, free); - } else { - for (list_each(ptnode, &tc->points)) { - if (*(int *)ptnode->data == point_id) { - free(node->data); - list_delete_node(&tc->points, ptnode); - } - } - } - if (tc->points.length == 0) { - list_unlink(&ui_events.touch_capturers, &tc->node); - free(tc); - } - return 0; + ui_touch_capturer_t *tc = NULL; + list_node_t *node, *ptnode; + for (list_each(node, list)) { + tc = node->data; + if (tc->widget == w) { + break; + } + } + if (!tc || tc->widget != w) { + return -1; + } + if (point_id < 0) { + list_destroy(&tc->points, free); + } else { + for (list_each(ptnode, &tc->points)) { + if (*(int *)ptnode->data == point_id) { + free(node->data); + list_delete_node(&tc->points, ptnode); + } + } + } + if (tc->points.length == 0) { + list_unlink(&ui_events.touch_capturers, &tc->node); + free(tc); + } + return 0; } ui_event_listener_t *ui_widget_add_event_listener( ui_widget_t *w, int event_id, ui_event_handler_t handler, void *data, ui_event_arg_destructor_t destroy_data) { - ui_event_listener_t *listener; - - listener = malloc(sizeof(ui_event_listener_t)); - if (!listener) { - return NULL; - } - listener->ref_count = 0; - listener->active = true; - listener->handler = handler; - listener->data = data; - listener->event_id = event_id; - listener->destroy_data = destroy_data; - listener->node.data = listener; - list_append_node(&ui_widget_use_extra_data(w)->listeners, - &listener->node); - return listener; + ui_event_listener_t *listener; + + listener = malloc(sizeof(ui_event_listener_t)); + if (!listener) { + return NULL; + } + listener->ref_count = 0; + listener->active = true; + listener->handler = handler; + listener->data = data; + listener->event_id = event_id; + listener->destroy_data = destroy_data; + listener->node.data = listener; + list_append_node(&ui_widget_use_extra_data(w)->listeners, + &listener->node); + return listener; } ui_event_listener_t *ui_widget_on(ui_widget_t *w, const char *event_name, - ui_event_handler_t handler, void *data) + ui_event_handler_t handler, void *data) { - int id = ui_use_widget_event_id(event_name); - return ui_widget_add_event_listener(w, id, handler, data, NULL); + int id = ui_use_widget_event_id(event_name); + return ui_widget_add_event_listener(w, id, handler, data, NULL); } int ui_widget_remove_event_listener(ui_widget_t *w, int event_id, - ui_event_handler_t handler, void *data) + ui_event_handler_t handler, void *data) { - int count = 0; - list_node_t *node, *prev; - ui_event_listener_t *listener; - - if (!w->extra) { - return 0; - } - for (list_each(node, &w->extra->listeners)) { - listener = node->data; - if (listener->event_id != event_id || - (handler && handler != listener->handler) || - data != listener->data) { - continue; - } - listener->active = false; - if (listener->ref_count == 0) { - prev = node->prev; - list_unlink(&w->extra->listeners, node); - ui_event_listener_destroy(listener); - node = prev; - } - count++; - } - return count; + int count = 0; + list_node_t *node, *prev; + ui_event_listener_t *listener; + + if (!w->extra) { + return 0; + } + for (list_each(node, &w->extra->listeners)) { + listener = node->data; + if (listener->event_id != event_id || + (handler && handler != listener->handler) || + data != listener->data) { + continue; + } + listener->active = false; + if (listener->ref_count == 0) { + prev = node->prev; + list_unlink(&w->extra->listeners, node); + ui_event_listener_destroy(listener); + node = prev; + } + count++; + } + return count; } int ui_widget_off(ui_widget_t *w, const char *event_name, - ui_event_handler_t handler, void *data) + ui_event_handler_t handler, void *data) { - int id = ui_use_widget_event_id(event_name); - return ui_widget_remove_event_listener(w, id, handler, data); + int id = ui_use_widget_event_id(event_name); + return ui_widget_remove_event_listener(w, id, handler, data); } int ui_emit_event(ui_event_t e, void *arg) { - return ui_widget_emit_event(ui_root(), e, arg); + return ui_widget_emit_event(ui_root(), e, arg); } int ui_post_event(const ui_event_t *e, void *arg, - ui_event_arg_destructor_t destroy_arg) + ui_event_arg_destructor_t destroy_arg) { - return ui_widget_post_event(ui_root(), e, arg, destroy_arg); + return ui_widget_post_event(ui_root(), e, arg, destroy_arg); } ui_event_listener_t *ui_add_event_listener( ui_widget_t *widget, int event_id, ui_event_handler_t handler, void *arg, ui_event_arg_destructor_t destroy_arg) { - return ui_widget_add_event_listener(ui_root(), event_id, handler, arg, - destroy_arg); + return ui_widget_add_event_listener(ui_root(), event_id, handler, arg, + destroy_arg); } int ui_remove_event_listener(ui_widget_t *w, int event_id, - ui_event_handler_t handler, void *data) + ui_event_handler_t handler, void *data) { - return ui_widget_remove_event_listener(ui_root(), event_id, handler, - data); + return ui_widget_remove_event_listener(ui_root(), event_id, handler, + data); } ui_event_listener_t *ui_on_event(const char *event_name, - ui_event_handler_t handler, void *data) + ui_event_handler_t handler, void *data) { - return ui_widget_on(ui_root(), event_name, handler, data); + return ui_widget_on(ui_root(), event_name, handler, data); } int ui_off_event(const char *event_name, ui_event_handler_t handler, void *data) { - return ui_widget_off(ui_root(), event_name, handler, data); + return ui_widget_off(ui_root(), event_name, handler, data); } static ui_widget_t *ui_widget_get_next_at(ui_widget_t *widget, float x, float y) { - ui_widget_t *w; - list_node_t *node; - - node = &widget->node; - for (node = node->next; node; node = node->next) { - w = node->data; - /* 如果忽略事件处理,则向它底层的兄弟部件传播事件 */ - if (w->computed_style.type_bits.pointer_events == - CSS_POINTER_EVENTS_NONE) { - continue; - } - if (!ui_widget_is_visible(w)) { - continue; - } - if (!ui_rect_has_point(&w->border_box, x, y)) { - continue; - } - return w; - } - return NULL; + ui_widget_t *w; + list_node_t *node; + + node = &widget->node; + for (node = node->next; node; node = node->next) { + w = node->data; + /* 如果忽略事件处理,则向它底层的兄弟部件传播事件 */ + if (w->computed_style.type_bits.pointer_events == + CSS_POINTER_EVENTS_NONE) { + continue; + } + if (!ui_widget_is_visible(w)) { + continue; + } + if (!ui_rect_has_point(&w->border_box, x, y)) { + continue; + } + return w; + } + return NULL; } static int ui_widget_call_listeners(ui_widget_t *w, ui_event_t e, void *arg) { - int count = 0; - list_node_t *node; - list_node_t *prev; - ui_event_listener_t *listener; - - if (!w->extra) { - return count; - } - for (list_each(node, &w->extra->listeners)) { - listener = node->data; - if (listener->event_id != e.type) { - continue; - } - e.data = listener->data; - listener->ref_count++; - listener->handler(w, &e, arg); - if (!e.cancel_bubble && w->parent) { - ui_widget_call_listeners(w->parent, e, arg); - } - listener->ref_count--; - if (!listener->active && listener->ref_count < 1) { - prev = node->prev; - list_unlink(&w->extra->listeners, node); - ui_event_listener_destroy(listener); - node = prev; - } - count++; - } - return count; + int count = 0; + list_node_t *node; + list_node_t *prev; + ui_event_listener_t *listener; + + if (!w->extra) { + return count; + } + for (list_each(node, &w->extra->listeners)) { + listener = node->data; + if (listener->event_id != e.type) { + continue; + } + e.data = listener->data; + listener->ref_count++; + listener->handler(w, &e, arg); + if (!e.cancel_bubble && w->parent) { + ui_widget_call_listeners(w->parent, e, arg); + } + listener->ref_count--; + if (!listener->active && listener->ref_count < 1) { + prev = node->prev; + list_unlink(&w->extra->listeners, node); + ui_event_listener_destroy(listener); + node = prev; + } + count++; + } + return count; } int ui_widget_post_event(ui_widget_t *w, const ui_event_t *e, void *data, - void (*destroy_data)(void *)) + void (*destroy_data)(void *)) { - ui_event_pack_t *pack; - - if (w->state == UI_WIDGET_STATE_DELETED) { - return -EPERM; - } - pack = malloc(sizeof(ui_event_pack_t)); - if (!pack) { - return -ENOMEM; - } - ui_event_copy(e, &pack->event); - if (!pack->event.target) { - pack->event.target = w; - } - pack->widget = w; - pack->data = data; - pack->destroy_data = destroy_data; - pack->node.data = pack; - list_append_node(&ui_events.queue, &pack->node); - return 0; + ui_event_pack_t *pack; + + if (w->state == UI_WIDGET_STATE_DELETED) { + return -EPERM; + } + pack = malloc(sizeof(ui_event_pack_t)); + if (!pack) { + return -ENOMEM; + } + ui_event_copy(e, &pack->event); + if (!pack->event.target) { + pack->event.target = w; + } + pack->widget = w; + pack->data = data; + pack->destroy_data = destroy_data; + pack->node.data = pack; + list_append_node(&ui_events.queue, &pack->node); + return 0; } int ui_widget_emit_event(ui_widget_t *w, ui_event_t e, void *arg) { - float x, y; - float pointer_x, pointer_y; - - ui_widget_t *sibling; - bool is_pointer_event = false; - - if (!e.target) { - e.target = w; - } - switch (e.type) { - case UI_EVENT_CLICK: - case UI_EVENT_MOUSEDOWN: - case UI_EVENT_MOUSEUP: - case UI_EVENT_MOUSEMOVE: - case UI_EVENT_MOUSEOVER: - case UI_EVENT_MOUSEOUT: - case UI_EVENT_WHEEL: - pointer_x = e.mouse.x; - pointer_y = e.mouse.y; - is_pointer_event = true; - if (w->computed_style.type_bits.pointer_events == - CSS_POINTER_EVENTS_NONE) { - break; - } - default: - if (ui_widget_call_listeners(w, e, arg) > 0) { - return 0; - } - } - if (!w->parent || e.cancel_bubble) { - return -1; - } - if (!w->extra || w->computed_style.type_bits.pointer_events != - CSS_POINTER_EVENTS_NONE) { - return ui_widget_emit_event(w->parent, e, arg); - } - if (is_pointer_event) { - ui_widget_get_offset(w->parent, NULL, &x, &y); - /* 转换成相对于父级部件内容框的坐标 */ - x = pointer_x - x; - y = pointer_y - y; - /* 从当前部件后面找到当前坐标点命中的兄弟部件 */ - sibling = ui_widget_get_next_at(w, x, y); - if (sibling) { - return ui_widget_call_listeners(sibling, e, arg); - } - } - return ui_widget_emit_event(w->parent, e, arg); + float x, y; + float pointer_x, pointer_y; + + ui_widget_t *sibling; + bool is_pointer_event = false; + + if (!e.target) { + e.target = w; + } + switch (e.type) { + case UI_EVENT_CLICK: + case UI_EVENT_MOUSEDOWN: + case UI_EVENT_MOUSEUP: + case UI_EVENT_MOUSEMOVE: + case UI_EVENT_MOUSEOVER: + case UI_EVENT_MOUSEOUT: + case UI_EVENT_WHEEL: + pointer_x = e.mouse.x; + pointer_y = e.mouse.y; + is_pointer_event = true; + if (w->computed_style.type_bits.pointer_events == + CSS_POINTER_EVENTS_NONE) { + break; + } + default: + if (ui_widget_call_listeners(w, e, arg) > 0) { + return 0; + } + } + if (!w->parent || e.cancel_bubble) { + return -1; + } + if (!w->extra || w->computed_style.type_bits.pointer_events != + CSS_POINTER_EVENTS_NONE) { + return ui_widget_emit_event(w->parent, e, arg); + } + if (is_pointer_event) { + ui_widget_get_offset(w->parent, NULL, &x, &y); + /* 转换成相对于父级部件内容框的坐标 */ + x = pointer_x - x; + y = pointer_y - y; + /* 从当前部件后面找到当前坐标点命中的兄弟部件 */ + sibling = ui_widget_get_next_at(w, x, y); + if (sibling) { + return ui_widget_call_listeners(sibling, e, arg); + } + } + return ui_widget_emit_event(w->parent, e, arg); } static ui_widget_t *ui_get_same_parent(ui_widget_t *a, ui_widget_t *b) { - int depth = 0, i; - ui_widget_t *w; - - for (w = a; w; w = w->parent) { - ++depth; - } - for (w = b; w; w = w->parent) { - --depth; - } - if (depth > 0) { - for (i = 0; i < depth; ++i) { - a = a->parent; - } - } else { - for (i = 0; i < -depth; ++i) { - b = b->parent; - } - } - while (a && b && a != b) { - a = a->parent; - b = b->parent; - } - if (a && a == b) { - return a; - } - return NULL; + int depth = 0, i; + ui_widget_t *w; + + for (w = a; w; w = w->parent) { + ++depth; + } + for (w = b; w; w = w->parent) { + --depth; + } + if (depth > 0) { + for (i = 0; i < depth; ++i) { + a = a->parent; + } + } else { + for (i = 0; i < -depth; ++i) { + b = b->parent; + } + } + while (a && b && a != b) { + a = a->parent; + b = b->parent; + } + if (a && a == b) { + return a; + } + return NULL; } static ui_widget_t *ui_widget_get_event_target(ui_widget_t *widget, float x, - float y, - uint8_t inherited_pointer_events) + float y, + uint8_t inherited_pointer_events) { - uint8_t pointer_events; - - ui_widget_t *child; - ui_widget_t *target = NULL; - list_node_t *node; - - for (list_each(node, &widget->stacking_context)) { - child = node->data; - if (!ui_widget_is_visible(child) || - child->state != UI_WIDGET_STATE_NORMAL || - !ui_rect_has_point(&child->border_box, x, y)) { - continue; - } - pointer_events = child->computed_style.type_bits.pointer_events; - if (pointer_events == CSS_POINTER_EVENTS_INHERT) { - pointer_events = inherited_pointer_events; - } - target = ui_widget_get_event_target( - child, x - child->padding_box.x, y - child->padding_box.y, - pointer_events); - if (target) { - return target; - } - if (pointer_events == CSS_POINTER_EVENTS_AUTO) { - return child; - } - } - return target; + uint8_t pointer_events; + + ui_widget_t *child; + ui_widget_t *target = NULL; + list_node_t *node; + + for (list_each(node, &widget->stacking_context)) { + child = node->data; + if (!ui_widget_is_visible(child) || + child->state != UI_WIDGET_STATE_NORMAL || + !ui_rect_has_point(&child->border_box, x, y)) { + continue; + } + pointer_events = child->computed_style.type_bits.pointer_events; + if (pointer_events == CSS_POINTER_EVENTS_INHERT) { + pointer_events = inherited_pointer_events; + } + target = ui_widget_get_event_target( + child, x - child->padding_box.x, y - child->padding_box.y, + pointer_events); + if (target) { + return target; + } + if (pointer_events == CSS_POINTER_EVENTS_AUTO) { + return child; + } + } + return target; } static void ui_widget_trigger_mouseover_event(ui_widget_t *widget, - ui_widget_t *parent) + ui_widget_t *parent) { - ui_widget_t *w; - ui_event_t e = { 0 }; - - e.cancel_bubble = false; - e.type = UI_EVENT_MOUSEOVER; - for (w = widget; w && w != parent; w = w->parent) { - e.target = w; - ui_widget_add_status(w, "hover"); - ui_widget_emit_event(w, e, NULL); - } + ui_widget_t *w; + ui_event_t e = { 0 }; + + e.cancel_bubble = false; + e.type = UI_EVENT_MOUSEOVER; + for (w = widget; w && w != parent; w = w->parent) { + e.target = w; + ui_widget_add_status(w, "hover"); + ui_widget_emit_event(w, e, NULL); + } } static void ui_widget_trigger_mouseout_event(ui_widget_t *widget, - ui_widget_t *parent) + ui_widget_t *parent) { - ui_widget_t *w; - ui_event_t e = { 0 }; - - e.cancel_bubble = false; - e.type = UI_EVENT_MOUSEOUT; - for (w = widget; w && w != parent; w = w->parent) { - e.target = w; - ui_widget_remove_status(w, "hover"); - ui_widget_emit_event(w, e, NULL); - } + ui_widget_t *w; + ui_event_t e = { 0 }; + + e.cancel_bubble = false; + e.type = UI_EVENT_MOUSEOUT; + for (w = widget; w && w != parent; w = w->parent) { + e.target = w; + ui_widget_remove_status(w, "hover"); + ui_widget_emit_event(w, e, NULL); + } } static void ui_widget_on_mouseover_event(ui_widget_t *widget) { - ui_widget_t *parent = NULL; - - if (ui_events.targets[UI_WIDGET_STATUS_HOVER] == widget) { - return; - } - parent = ui_get_same_parent(widget, - ui_events.targets[UI_WIDGET_STATUS_HOVER]); - if (widget) { - ui_widget_trigger_mouseover_event(widget, parent); - } - if (ui_events.targets[UI_WIDGET_STATUS_HOVER]) { - ui_widget_trigger_mouseout_event( - ui_events.targets[UI_WIDGET_STATUS_HOVER], parent); - } - ui_events.targets[UI_WIDGET_STATUS_HOVER] = widget; + ui_widget_t *parent = NULL; + + if (ui_events.targets[UI_WIDGET_STATUS_HOVER] == widget) { + return; + } + parent = ui_get_same_parent(widget, + ui_events.targets[UI_WIDGET_STATUS_HOVER]); + if (widget) { + ui_widget_trigger_mouseover_event(widget, parent); + } + if (ui_events.targets[UI_WIDGET_STATUS_HOVER]) { + ui_widget_trigger_mouseout_event( + ui_events.targets[UI_WIDGET_STATUS_HOVER], parent); + } + ui_events.targets[UI_WIDGET_STATUS_HOVER] = widget; } static void ui_widget_on_mousedown_event(ui_widget_t *widget) { - ui_widget_t *parent; - ui_widget_t *w = ui_events.targets[UI_WIDGET_STATUS_ACTIVE]; - - if (w == widget) { - return; - } - parent = ui_get_same_parent(widget, w); - for (; w && w != parent; w = w->parent) { - ui_widget_remove_status(w, "active"); - } - for (w = widget; w && w != parent; w = w->parent) { - ui_widget_add_status(w, "active"); - } - ui_events.targets[UI_WIDGET_STATUS_ACTIVE] = widget; + ui_widget_t *parent; + ui_widget_t *w = ui_events.targets[UI_WIDGET_STATUS_ACTIVE]; + + if (w == widget) { + return; + } + parent = ui_get_same_parent(widget, w); + for (; w && w != parent; w = w->parent) { + ui_widget_remove_status(w, "active"); + } + for (w = widget; w && w != parent; w = w->parent) { + ui_widget_add_status(w, "active"); + } + ui_events.targets[UI_WIDGET_STATUS_ACTIVE] = widget; } static void ui_clear_mouseover_target(ui_widget_t *target) { - ui_widget_t *w; - - if (!target) { - ui_widget_on_mouseover_event(NULL); - return; - } - for (w = ui_events.targets[UI_WIDGET_STATUS_HOVER]; w; w = w->parent) { - if (w == target) { - ui_widget_on_mouseover_event(NULL); - break; - } - } + ui_widget_t *w; + + if (!target) { + ui_widget_on_mouseover_event(NULL); + return; + } + for (w = ui_events.targets[UI_WIDGET_STATUS_HOVER]; w; w = w->parent) { + if (w == target) { + ui_widget_on_mouseover_event(NULL); + break; + } + } } static void ui_clear_mousedown_target(ui_widget_t *target) { - ui_widget_t *w; - - if (!target) { - ui_widget_on_mousedown_event(NULL); - return; - } - for (w = ui_events.targets[UI_WIDGET_STATUS_ACTIVE]; w; w = w->parent) { - if (w == target) { - ui_widget_on_mousedown_event(NULL); - break; - } - } + ui_widget_t *w; + + if (!target) { + ui_widget_on_mousedown_event(NULL); + return; + } + for (w = ui_events.targets[UI_WIDGET_STATUS_ACTIVE]; w; w = w->parent) { + if (w == target) { + ui_widget_on_mousedown_event(NULL); + break; + } + } } static void ui_clear_focus_target(ui_widget_t *target) { - ui_widget_t *w; - - if (!target) { - ui_events.targets[UI_WIDGET_STATUS_FOCUS] = NULL; - return; - } - for (w = ui_events.targets[UI_WIDGET_STATUS_FOCUS]; w; w = w->parent) { - if (w == target) { - ui_events.targets[UI_WIDGET_STATUS_FOCUS] = NULL; - break; - } - } + ui_widget_t *w; + + if (!target) { + ui_events.targets[UI_WIDGET_STATUS_FOCUS] = NULL; + return; + } + for (w = ui_events.targets[UI_WIDGET_STATUS_FOCUS]; w; w = w->parent) { + if (w == target) { + ui_events.targets[UI_WIDGET_STATUS_FOCUS] = NULL; + break; + } + } } void ui_clear_event_target(ui_widget_t *w) { - list_node_t *node, *prev; - ui_event_pack_t *pack; - - for (list_each(node, &ui_events.queue)) { - prev = node->prev; - pack = node->data; - if (pack->widget == w) { - list_unlink(&ui_events.queue, node); - ui_event_pack_destroy(pack); - node = prev; - } - } - ui_clear_mouseover_target(w); - ui_clear_mousedown_target(w); - ui_clear_focus_target(w); + list_node_t *node, *prev; + ui_event_pack_t *pack; + + for (list_each(node, &ui_events.queue)) { + prev = node->prev; + pack = node->data; + if (pack->widget == w) { + list_unlink(&ui_events.queue, node); + ui_event_pack_destroy(pack); + node = prev; + } + } + ui_clear_mouseover_target(w); + ui_clear_mousedown_target(w); + ui_clear_focus_target(w); } LIBUI_INLINE bool ui_widget_is_focusable(ui_widget_t *w) { - return w && - w->computed_style.type_bits.pointer_events != - CSS_POINTER_EVENTS_NONE && - w->tab_index >= 0 && !w->disabled; + return w && + w->computed_style.type_bits.pointer_events != + CSS_POINTER_EVENTS_NONE && + w->tab_index >= 0 && !w->disabled; } ui_widget_t *ui_get_focus(void) { - return ui_events.targets[UI_WIDGET_STATUS_FOCUS]; + return ui_events.targets[UI_WIDGET_STATUS_FOCUS]; } int ui_set_focus(ui_widget_t *widget) { - ui_widget_t *w; - ui_event_t e = { 0 }; - - for (w = widget; w; w = w->parent) { - if (ui_widget_is_focusable(w)) { - break; - } - } - if (ui_events.targets[UI_WIDGET_STATUS_FOCUS] == w) { - return 0; - } - if (ui_events.targets[UI_WIDGET_STATUS_FOCUS]) { - e.type = UI_EVENT_BLUR; - e.target = ui_events.targets[UI_WIDGET_STATUS_FOCUS]; - ui_widget_remove_status(e.target, "focus"); - ui_widget_post_event(e.target, &e, NULL, NULL); - ui_events.targets[UI_WIDGET_STATUS_FOCUS] = NULL; - } - if (!ui_widget_is_focusable(w)) { - return -1; - } - e.target = w; - e.type = UI_EVENT_FOCUS; - e.cancel_bubble = false; - ui_events.targets[UI_WIDGET_STATUS_FOCUS] = w; - ui_widget_add_status(e.target, "focus"); - ui_widget_post_event(e.target, &e, NULL, NULL); - return 0; + ui_widget_t *w; + ui_event_t e = { 0 }; + + for (w = widget; w; w = w->parent) { + if (ui_widget_is_focusable(w)) { + break; + } + } + if (ui_events.targets[UI_WIDGET_STATUS_FOCUS] == w) { + return 0; + } + if (ui_events.targets[UI_WIDGET_STATUS_FOCUS]) { + e.type = UI_EVENT_BLUR; + e.target = ui_events.targets[UI_WIDGET_STATUS_FOCUS]; + ui_widget_remove_status(e.target, "focus"); + ui_widget_post_event(e.target, &e, NULL, NULL); + ui_events.targets[UI_WIDGET_STATUS_FOCUS] = NULL; + } + if (!ui_widget_is_focusable(w)) { + return -1; + } + e.target = w; + e.type = UI_EVENT_FOCUS; + e.cancel_bubble = false; + ui_events.targets[UI_WIDGET_STATUS_FOCUS] = w; + ui_widget_add_status(e.target, "focus"); + ui_widget_post_event(e.target, &e, NULL, NULL); + return 0; } static ui_widget_t *ui_resolve_event_target(float x, float y) { - ui_widget_t *w; - ui_widget_t *root; - ui_widget_t *target; - - root = ui_root(); - if (ui_events.mouse_capturer) { - target = ui_events.mouse_capturer; - } else { - target = ui_widget_get_event_target(root, x, y, - CSS_POINTER_EVENTS_AUTO); - } - for (w = target; w; w = w->parent) { - if (w->event_blocked) { - return NULL; - } - } - if (!target) { - target = root; - } - return target; + ui_widget_t *w; + ui_widget_t *root; + ui_widget_t *target; + + root = ui_root(); + if (ui_events.mouse_capturer) { + target = ui_events.mouse_capturer; + } else { + target = ui_widget_get_event_target(root, x, y, + CSS_POINTER_EVENTS_AUTO); + } + for (w = target; w; w = w->parent) { + if (w->event_blocked) { + return NULL; + } + } + if (!target) { + target = root; + } + return target; } static int ui_on_wheel_event(ui_event_t *origin_event) { - ui_event_t e = *origin_event; - - e.cancel_bubble = false; - e.target = ui_events.targets[UI_WIDGET_STATUS_HOVER]; - if (!e.target) { - return -1; - } - ui_widget_emit_event(e.target, e, NULL); - return 0; + ui_event_t e = *origin_event; + + e.cancel_bubble = false; + e.target = ui_events.targets[UI_WIDGET_STATUS_HOVER]; + if (!e.target) { + return -1; + } + ui_widget_emit_event(e.target, e, NULL); + return 0; } static int ui_on_mouse_event(ui_event_t *origin_event) { - ui_event_t e = *origin_event; - - e.cancel_bubble = false; - switch (e.type) { - case UI_EVENT_MOUSEDOWN: - e.target = ui_resolve_event_target(e.mouse.x, e.mouse.y); - if (!e.target) { - return -1; - } - ui_widget_emit_event(e.target, e, NULL); - ui_events.click.interval = DBLCLICK_INTERVAL; - if (e.mouse.button == UI_MOUSE_BUTTON_LEFT && - ui_events.click.widget == e.target) { - int delta; - delta = (int)get_time_delta(ui_events.click.time); - ui_events.click.interval = delta; - } else if (e.mouse.button == UI_MOUSE_BUTTON_RIGHT && - ui_events.click.widget != e.target) { - ui_events.click.x = e.mouse.x; - ui_events.click.y = e.mouse.y; - } - ui_events.click.time = get_time_ms(); - ui_events.click.widget = e.target; - ui_widget_on_mousedown_event(e.target); - ui_set_focus(e.target); - break; - case UI_EVENT_MOUSEUP: - e.target = ui_resolve_event_target(e.mouse.x, e.mouse.y); - if (!e.target) { - return -1; - } - ui_widget_emit_event(e.target, e, NULL); - if (ui_events.targets[UI_WIDGET_STATUS_ACTIVE] != e.target || - e.mouse.button != UI_MOUSE_BUTTON_LEFT) { - ui_events.click.x = 0; - ui_events.click.y = 0; - ui_events.click.time = 0; - ui_events.click.widget = NULL; - ui_clear_mousedown_target(NULL); - break; - } - e.type = UI_EVENT_CLICK; - ui_widget_emit_event(e.target, e, NULL); - ui_clear_mousedown_target(NULL); - if (ui_events.click.widget != e.target) { - ui_events.click.x = 0; - ui_events.click.y = 0; - ui_events.click.time = 0; - ui_events.click.widget = NULL; - break; - } - if (ui_events.click.interval < DBLCLICK_INTERVAL) { - e.type = UI_EVENT_DBLCLICK; - ui_events.click.x = 0; - ui_events.click.y = 0; - ui_events.click.time = 0; - ui_events.click.widget = NULL; - ui_widget_emit_event(e.target, e, NULL); - } - ui_clear_mousedown_target(NULL); - break; - case UI_EVENT_MOUSEMOVE: - e.target = ui_resolve_event_target(e.mouse.x, e.mouse.y); - if (!e.target) { - return -1; - } - if (fabs(ui_events.click.x - e.mouse.x) >= 8.f || - fabs(ui_events.click.y - e.mouse.y) >= 8.f) { - ui_events.click.time = 0; - ui_events.click.widget = NULL; - } - ui_widget_emit_event(e.target, e, NULL); - break; - default: - return -1; - } - ui_widget_on_mouseover_event(e.target); - return 0; + ui_event_t e = *origin_event; + + e.cancel_bubble = false; + switch (e.type) { + case UI_EVENT_MOUSEDOWN: + e.target = ui_resolve_event_target(e.mouse.x, e.mouse.y); + if (!e.target) { + return -1; + } + ui_widget_emit_event(e.target, e, NULL); + ui_events.click.interval = DBLCLICK_INTERVAL; + if (e.mouse.button == UI_MOUSE_BUTTON_LEFT && + ui_events.click.widget == e.target) { + int delta; + delta = (int)get_time_delta(ui_events.click.time); + ui_events.click.interval = delta; + } else if (e.mouse.button == UI_MOUSE_BUTTON_RIGHT && + ui_events.click.widget != e.target) { + ui_events.click.x = e.mouse.x; + ui_events.click.y = e.mouse.y; + } + ui_events.click.time = get_time_ms(); + ui_events.click.widget = e.target; + ui_widget_on_mousedown_event(e.target); + ui_set_focus(e.target); + break; + case UI_EVENT_MOUSEUP: + e.target = ui_resolve_event_target(e.mouse.x, e.mouse.y); + if (!e.target) { + return -1; + } + ui_widget_emit_event(e.target, e, NULL); + if (ui_events.targets[UI_WIDGET_STATUS_ACTIVE] != e.target || + e.mouse.button != UI_MOUSE_BUTTON_LEFT) { + ui_events.click.x = 0; + ui_events.click.y = 0; + ui_events.click.time = 0; + ui_events.click.widget = NULL; + ui_clear_mousedown_target(NULL); + break; + } + e.type = UI_EVENT_CLICK; + ui_widget_emit_event(e.target, e, NULL); + ui_clear_mousedown_target(NULL); + if (ui_events.click.widget != e.target) { + ui_events.click.x = 0; + ui_events.click.y = 0; + ui_events.click.time = 0; + ui_events.click.widget = NULL; + break; + } + if (ui_events.click.interval < DBLCLICK_INTERVAL) { + e.type = UI_EVENT_DBLCLICK; + ui_events.click.x = 0; + ui_events.click.y = 0; + ui_events.click.time = 0; + ui_events.click.widget = NULL; + ui_widget_emit_event(e.target, e, NULL); + } + ui_clear_mousedown_target(NULL); + break; + case UI_EVENT_MOUSEMOVE: + e.target = ui_resolve_event_target(e.mouse.x, e.mouse.y); + if (!e.target) { + return -1; + } + if (fabs(ui_events.click.x - e.mouse.x) >= 8.f || + fabs(ui_events.click.y - e.mouse.y) >= 8.f) { + ui_events.click.time = 0; + ui_events.click.widget = NULL; + } + ui_widget_emit_event(e.target, e, NULL); + break; + default: + return -1; + } + ui_widget_on_mouseover_event(e.target); + return 0; } static int ui_on_keyboard_event(ui_event_t *origin_event) { - ui_event_t e = *origin_event; - - e.target = ui_events.targets[UI_WIDGET_STATUS_FOCUS]; - if (!e.target) { - e.target = ui_root(); - } - e.cancel_bubble = false; - ui_widget_emit_event(e.target, e, NULL); - return 0; + ui_event_t e = *origin_event; + + e.target = ui_events.targets[UI_WIDGET_STATUS_FOCUS]; + if (!e.target) { + e.target = ui_root(); + } + e.cancel_bubble = false; + ui_widget_emit_event(e.target, e, NULL); + return 0; } static int ui_on_text_input(ui_event_t *origin_event) { - ui_event_t e = *origin_event; - - e.target = ui_events.targets[UI_WIDGET_STATUS_FOCUS]; - if (!e.target) { - return -1; - } - e.cancel_bubble = false; - ui_widget_emit_event(e.target, e, NULL); - return 0; + ui_event_t e = *origin_event; + + e.target = ui_events.targets[UI_WIDGET_STATUS_FOCUS]; + if (!e.target) { + return -1; + } + e.cancel_bubble = false; + ui_widget_emit_event(e.target, e, NULL); + return 0; } /** 分发触控事件给对应的部件 */ static int ui_dispatch_touch_event(list_t *capturers, ui_touch_point_t *points, - int n_points) + int n_points) { - int i, count; - float scale; - list_node_t *node, *ptnode; - ui_event_t e = { 0 }; - ui_widget_t *target, *root, *w; - ui_touch_capturer_t *tc; - - root = ui_root(); - scale = ui_get_actual_scale(); - e.type = UI_EVENT_TOUCH; - e.cancel_bubble = false; - e.touch.points = malloc(sizeof(ui_touch_point_t) * n_points); - /* 先将各个触点按命中的部件进行分组 */ - for (i = 0; i < n_points; ++i) { - target = ui_widget_at(root, y_iround(points[i].x / scale), - y_iround(points[i].y / scale)); - if (!target) { - continue; - } - for (w = target; w; w = w->parent) { - if (w->event_blocked) { - break; - } - } - if (w && w->event_blocked) { - continue; - } - ui_add_touch_capturer(capturers, target, points[i].id); - } - count = 0; - e.touch.n_points = 0; - /* 然后向命中的部件发送触控事件 */ - for (list_each(node, capturers)) { - tc = node->data; - for (i = 0; i < n_points; ++i) { - for (list_each(ptnode, &tc->points)) { - if (points[i].id != *(int *)ptnode->data) { - continue; - } - e.touch.points[e.touch.n_points] = points[i]; - ++e.touch.n_points; - } - } - if (e.touch.n_points == 0) { - continue; - } - ui_widget_post_event(tc->widget, &e, NULL, NULL); - e.touch.n_points = 0; - ++count; - } - ui_event_destroy(&e); - return count; + int i, count; + float scale; + list_node_t *node, *ptnode; + ui_event_t e = { 0 }; + ui_widget_t *target, *root, *w; + ui_touch_capturer_t *tc; + + root = ui_root(); + scale = ui_get_actual_scale(); + e.type = UI_EVENT_TOUCH; + e.cancel_bubble = false; + e.touch.points = malloc(sizeof(ui_touch_point_t) * n_points); + /* 先将各个触点按命中的部件进行分组 */ + for (i = 0; i < n_points; ++i) { + target = ui_widget_at(root, y_iround(points[i].x / scale), + y_iround(points[i].y / scale)); + if (!target) { + continue; + } + for (w = target; w; w = w->parent) { + if (w->event_blocked) { + break; + } + } + if (w && w->event_blocked) { + continue; + } + ui_add_touch_capturer(capturers, target, points[i].id); + } + count = 0; + e.touch.n_points = 0; + /* 然后向命中的部件发送触控事件 */ + for (list_each(node, capturers)) { + tc = node->data; + for (i = 0; i < n_points; ++i) { + for (list_each(ptnode, &tc->points)) { + if (points[i].id != *(int *)ptnode->data) { + continue; + } + e.touch.points[e.touch.n_points] = points[i]; + ++e.touch.n_points; + } + } + if (e.touch.n_points == 0) { + continue; + } + ui_widget_post_event(tc->widget, &e, NULL, NULL); + e.touch.n_points = 0; + ++count; + } + ui_event_destroy(&e); + return count; } static int ui_on_touch_event(ui_event_t *e) { - int i, n; - list_t capturers; - list_node_t *node, *ptnode; - ui_touch_point_t *points; - - n = e->touch.n_points; - points = e->touch.points; - list_create(&capturers); - /* 合并现有的触点捕捉记录 */ - for (list_each(node, &ui_events.touch_capturers)) { - ui_touch_capturer_t *tc = node->data; - for (i = 0; i < n; ++i) { - /* 如果没有触点记录,则说明是捕获全部触点 */ - if (tc->points.length == 0) { - ui_add_touch_capturer(&capturers, tc->widget, - points[i].id); - continue; - } - for (list_each(ptnode, &tc->points)) { - if (points[i].id != *(int *)ptnode->data) { - continue; - } - ui_add_touch_capturer(&capturers, tc->widget, - points[i].id); - } - } - } - ui_dispatch_touch_event(&capturers, points, n); - ui_clear_touch_capturers(&capturers); - return 0; + int i, n; + list_t capturers; + list_node_t *node, *ptnode; + ui_touch_point_t *points; + + n = e->touch.n_points; + points = e->touch.points; + list_create(&capturers); + /* 合并现有的触点捕捉记录 */ + for (list_each(node, &ui_events.touch_capturers)) { + ui_touch_capturer_t *tc = node->data; + for (i = 0; i < n; ++i) { + /* 如果没有触点记录,则说明是捕获全部触点 */ + if (tc->points.length == 0) { + ui_add_touch_capturer(&capturers, tc->widget, + points[i].id); + continue; + } + for (list_each(ptnode, &tc->points)) { + if (points[i].id != *(int *)ptnode->data) { + continue; + } + ui_add_touch_capturer(&capturers, tc->widget, + points[i].id); + } + } + } + ui_dispatch_touch_event(&capturers, points, n); + ui_clear_touch_capturers(&capturers); + return 0; } void ui_widget_set_mouse_capture(ui_widget_t *w) { - ui_events.mouse_capturer = w; + ui_events.mouse_capturer = w; } void ui_widget_release_mouse_capture(ui_widget_t *w) { - ui_events.mouse_capturer = NULL; + ui_events.mouse_capturer = NULL; } int ui_widget_set_touch_capture(ui_widget_t *w, int point_id) { - int ret; - ret = ui_add_touch_capturer(&ui_events.touch_capturers, w, point_id); - return ret; + int ret; + ret = ui_add_touch_capturer(&ui_events.touch_capturers, w, point_id); + return ret; } int ui_widget_release_touch_capture(ui_widget_t *w, int point_id) { - int ret; + int ret; - if (ui_events.touch_capturers.length <= 1) { - return 0; - } - ret = ui_remove_touch_capturer(&ui_events.touch_capturers, w, point_id); - return ret; + if (ui_events.touch_capturers.length <= 1) { + return 0; + } + ret = ui_remove_touch_capturer(&ui_events.touch_capturers, w, point_id); + return ret; } static void ui_widget_on_destroy_listener(void *arg) { - ui_event_listener_destroy(arg); + ui_event_listener_destroy(arg); } void ui_widget_destroy_listeners(ui_widget_t *w) { - ui_event_t e = { UI_EVENT_DESTROY, 0 }; - - ui_widget_emit_event(w, e, NULL); - ui_widget_release_mouse_capture(w); - ui_widget_release_touch_capture(w, -1); - ui_clear_event_target(w); - if (w->extra) { - list_destroy_without_node(&w->extra->listeners, - ui_widget_on_destroy_listener); - } + ui_event_t e = { UI_EVENT_DESTROY, 0 }; + + ui_widget_emit_event(w, e, NULL); + ui_widget_release_mouse_capture(w); + ui_widget_release_touch_capture(w, -1); + ui_clear_event_target(w); + if (w->extra) { + list_destroy_without_node(&w->extra->listeners, + ui_widget_on_destroy_listener); + } } void ui_init_events(void) { - int i, n; - struct EventNameMapping { - int id; - const char *name; - } mappings[] = { { UI_EVENT_LINK, "link" }, - { UI_EVENT_UNLINK, "unlink" }, - { UI_EVENT_READY, "ready" }, - { UI_EVENT_DESTROY, "destroy" }, - { UI_EVENT_MOUSEDOWN, "mousedown" }, - { UI_EVENT_MOUSEUP, "mouseup" }, - { UI_EVENT_MOUSEMOVE, "mousemove" }, - { UI_EVENT_WHEEL, "mousewheel" }, - { UI_EVENT_CLICK, "click" }, - { UI_EVENT_DBLCLICK, "dblclick" }, - { UI_EVENT_MOUSEOUT, "mouseout" }, - { UI_EVENT_MOUSEOVER, "mouseover" }, - { UI_EVENT_KEYDOWN, "keydown" }, - { UI_EVENT_KEYUP, "keyup" }, - { UI_EVENT_KEYPRESS, "keypress" }, - { UI_EVENT_TOUCH, "touch" }, - { UI_EVENT_TEXTINPUT, "textinput" }, - { UI_EVENT_TOUCHDOWN, "touchdown" }, - { UI_EVENT_TOUCHMOVE, "touchmove" }, - { UI_EVENT_TOUCHUP, "touchup" }, - { UI_EVENT_AFTERLAYOUT, "afterlayout" }, - { UI_EVENT_FOCUS, "focus" }, - { UI_EVENT_BLUR, "blur" }, - { UI_EVENT_PASTE, "paste" }, - { UI_EVENT_CSS_LOAD, "css_load" }, - { UI_EVENT_CSS_FONT_FACE_LOAD, "css_font_face_load" } }; - - rbtree_init(&ui_events.event_names); - list_create(&ui_events.event_mappings); - list_create(&ui_events.touch_capturers); - list_create(&ui_events.queue); - ui_events.targets[UI_WIDGET_STATUS_ACTIVE] = NULL; - ui_events.targets[UI_WIDGET_STATUS_HOVER] = NULL; - ui_events.targets[UI_WIDGET_STATUS_FOCUS] = NULL; - ui_events.mouse_capturer = NULL; - ui_events.click.x = 0; - ui_events.click.y = 0; - ui_events.click.time = 0; - ui_events.click.widget = NULL; - ui_events.click.interval = DBLCLICK_INTERVAL; - ui_events.base_event_id = UI_EVENT_USER + 1000; - dict_init_string_key_type(&ui_events.event_ids_type); - ui_events.event_ids = dict_create(&ui_events.event_ids_type, NULL); - n = sizeof(mappings) / sizeof(mappings[0]); - for (i = 0; i < n; ++i) { - ui_set_event_id(mappings[i].id, mappings[i].name); - } + int i, n; + struct EventNameMapping { + int id; + const char *name; + } mappings[] = { { UI_EVENT_LINK, "link" }, + { UI_EVENT_UNLINK, "unlink" }, + { UI_EVENT_READY, "ready" }, + { UI_EVENT_DESTROY, "destroy" }, + { UI_EVENT_MOUSEDOWN, "mousedown" }, + { UI_EVENT_MOUSEUP, "mouseup" }, + { UI_EVENT_MOUSEMOVE, "mousemove" }, + { UI_EVENT_WHEEL, "mousewheel" }, + { UI_EVENT_CLICK, "click" }, + { UI_EVENT_DBLCLICK, "dblclick" }, + { UI_EVENT_MOUSEOUT, "mouseout" }, + { UI_EVENT_MOUSEOVER, "mouseover" }, + { UI_EVENT_KEYDOWN, "keydown" }, + { UI_EVENT_KEYUP, "keyup" }, + { UI_EVENT_KEYPRESS, "keypress" }, + { UI_EVENT_TOUCH, "touch" }, + { UI_EVENT_TEXTINPUT, "textinput" }, + { UI_EVENT_TOUCHDOWN, "touchdown" }, + { UI_EVENT_TOUCHMOVE, "touchmove" }, + { UI_EVENT_TOUCHUP, "touchup" }, + { UI_EVENT_AFTERLAYOUT, "afterlayout" }, + { UI_EVENT_FOCUS, "focus" }, + { UI_EVENT_BLUR, "blur" }, + { UI_EVENT_PASTE, "paste" }, + { UI_EVENT_CSS_LOAD, "css_load" }, + { UI_EVENT_CSS_FONT_FACE_LOAD, + "css_font_face_load" } }; + + rbtree_init(&ui_events.event_names); + list_create(&ui_events.event_mappings); + list_create(&ui_events.touch_capturers); + list_create(&ui_events.queue); + ui_events.targets[UI_WIDGET_STATUS_ACTIVE] = NULL; + ui_events.targets[UI_WIDGET_STATUS_HOVER] = NULL; + ui_events.targets[UI_WIDGET_STATUS_FOCUS] = NULL; + ui_events.mouse_capturer = NULL; + ui_events.click.x = 0; + ui_events.click.y = 0; + ui_events.click.time = 0; + ui_events.click.widget = NULL; + ui_events.click.interval = DBLCLICK_INTERVAL; + ui_events.base_event_id = UI_EVENT_USER + 1000; + dict_init_string_key_type(&ui_events.event_ids_type); + ui_events.event_ids = dict_create(&ui_events.event_ids_type, NULL); + n = sizeof(mappings) / sizeof(mappings[0]); + for (i = 0; i < n; ++i) { + ui_set_event_id(mappings[i].id, mappings[i].name); + } } int ui_dispatch_event(ui_event_t *e) { - switch (e->type) { - case UI_EVENT_WHEEL: - return ui_on_wheel_event(e); - case UI_EVENT_MOUSEDOWN: - case UI_EVENT_MOUSEMOVE: - case UI_EVENT_MOUSEUP: - return ui_on_mouse_event(e); - case UI_EVENT_KEYPRESS: - case UI_EVENT_KEYDOWN: - case UI_EVENT_KEYUP: - return ui_on_keyboard_event(e); - case UI_EVENT_TOUCH: - return ui_on_touch_event(e); - case UI_EVENT_TEXTINPUT: - return ui_on_text_input(e); - default: - break; - } - return -1; + switch (e->type) { + case UI_EVENT_WHEEL: + return ui_on_wheel_event(e); + case UI_EVENT_MOUSEDOWN: + case UI_EVENT_MOUSEMOVE: + case UI_EVENT_MOUSEUP: + return ui_on_mouse_event(e); + case UI_EVENT_KEYPRESS: + case UI_EVENT_KEYDOWN: + case UI_EVENT_KEYUP: + return ui_on_keyboard_event(e); + case UI_EVENT_TOUCH: + return ui_on_touch_event(e); + case UI_EVENT_TEXTINPUT: + return ui_on_text_input(e); + default: + break; + } + return -1; } static void ui_on_destroy_event_pack(void *arg) { - ui_event_pack_destroy(arg); + ui_event_pack_destroy(arg); } void ui_process_events(void) { - list_t queue; - list_node_t *node; - ui_event_pack_t *pack; - - list_create(&queue); - list_concat(&queue, &ui_events.queue); - for (list_each(node, &queue)) { - pack = node->data; - if (pack->widget) { - ui_widget_emit_event(pack->widget, pack->event, - pack->data); - } - } - list_destroy_without_node(&queue, ui_on_destroy_event_pack); + list_t queue; + list_node_t *node; + ui_event_pack_t *pack; + + list_create(&queue); + list_concat(&queue, &ui_events.queue); + for (list_each(node, &queue)) { + pack = node->data; + if (pack->widget) { + ui_widget_emit_event(pack->widget, pack->event, + pack->data); + } + } + list_destroy_without_node(&queue, ui_on_destroy_event_pack); } void ui_destroy_events(void) { - rbtree_destroy(&ui_events.event_names); - dict_destroy(ui_events.event_ids); - ui_clear_touch_capturers(&ui_events.touch_capturers); - list_destroy_without_node(&ui_events.queue, ui_on_destroy_event_pack); - list_destroy(&ui_events.event_mappings, ui_event_mapping_destroy); - ui_events.event_ids = NULL; + rbtree_destroy(&ui_events.event_names); + dict_destroy(ui_events.event_ids); + ui_clear_touch_capturers(&ui_events.touch_capturers); + list_destroy_without_node(&ui_events.queue, ui_on_destroy_event_pack); + list_destroy(&ui_events.event_mappings, ui_event_mapping_destroy); + ui_events.event_ids = NULL; } diff --git a/lib/ui/src/ui_events.h b/lib/ui/src/ui_events.h index f70ff4248..865aa7006 100644 --- a/lib/ui/src/ui_events.h +++ b/lib/ui/src/ui_events.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_events.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ui/src/ui_flexbox_layout.c b/lib/ui/src/ui_flexbox_layout.c index f35c961dd..88f4e5fe2 100644 --- a/lib/ui/src/ui_flexbox_layout.c +++ b/lib/ui/src/ui_flexbox_layout.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_flexbox_layout.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ /** diff --git a/lib/ui/src/ui_flexbox_layout.h b/lib/ui/src/ui_flexbox_layout.h index 833eeb144..6a687d83f 100644 --- a/lib/ui/src/ui_flexbox_layout.h +++ b/lib/ui/src/ui_flexbox_layout.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_flexbox_layout.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ui/src/ui_image.c b/lib/ui/src/ui_image.c index 93054e418..0275347be 100644 --- a/lib/ui/src/ui_image.c +++ b/lib/ui/src/ui_image.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_image.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -144,7 +147,7 @@ void ui_image_destroy(ui_image_t *image) } bool ui_image_add_event_listener(ui_image_t *image, ui_image_event_type_t type, - ui_image_event_handler_t handler, void *data) + ui_image_event_handler_t handler, void *data) { ui_image_event_t ev = { .type = type, .image = image, .data = data }; ui_image_event_listener_t *listener; @@ -168,8 +171,9 @@ bool ui_image_add_event_listener(ui_image_t *image, ui_image_event_type_t type, } bool ui_image_remove_event_listener(ui_image_t *image, - ui_image_event_type_t type, - ui_image_event_handler_t handler, void *data) + ui_image_event_type_t type, + ui_image_event_handler_t handler, + void *data) { list_node_t *node, *next; ui_image_source_t *src = (ui_image_source_t *)image; diff --git a/lib/ui/src/ui_image.h b/lib/ui/src/ui_image.h index 96da7c686..a0eabe3f3 100644 --- a/lib/ui/src/ui_image.h +++ b/lib/ui/src/ui_image.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_image.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ui/src/ui_logger.c b/lib/ui/src/ui_logger.c index 3260a20c6..69d85a5f7 100644 --- a/lib/ui/src/ui_logger.c +++ b/lib/ui/src/ui_logger.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_logger.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -20,19 +23,20 @@ int ui_logger_log(logger_level_e level, ui_widget_t *w, const char *fmt, ...) { - va_list args; - css_selector_node_t *node; - char buffer[LOG_BUFFER_SIZE]; + va_list args; + css_selector_node_t *node; + char buffer[LOG_BUFFER_SIZE]; - va_start(args, fmt); - vsnprintf(buffer, LOG_BUFFER_SIZE, fmt, args); - va_end(args); - if (w) { - node = ui_widget_create_selector_node(w); - strreplace(buffer, LOG_BUFFER_SIZE, "${widget}", node->fullname); - css_selector_node_destroy(node); - } else { - strreplace(buffer, LOG_BUFFER_SIZE, "${widget}", "(null)"); - } - return logger_log(level, buffer); + va_start(args, fmt); + vsnprintf(buffer, LOG_BUFFER_SIZE, fmt, args); + va_end(args); + if (w) { + node = ui_widget_create_selector_node(w); + strreplace(buffer, LOG_BUFFER_SIZE, "${widget}", + node->fullname); + css_selector_node_destroy(node); + } else { + strreplace(buffer, LOG_BUFFER_SIZE, "${widget}", "(null)"); + } + return logger_log(level, buffer); } diff --git a/lib/ui/src/ui_metrics.c b/lib/ui/src/ui_metrics.c index 9322b2e37..20d9f4619 100644 --- a/lib/ui/src/ui_metrics.c +++ b/lib/ui/src/ui_metrics.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_metrics.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ui/src/ui_mutation_observer.c b/lib/ui/src/ui_mutation_observer.c index fa47e3226..77d9b20d0 100644 --- a/lib/ui/src/ui_mutation_observer.c +++ b/lib/ui/src/ui_mutation_observer.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_mutation_observer.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ui/src/ui_mutation_observer.h b/lib/ui/src/ui_mutation_observer.h index 1dc618d5f..5ca0013b5 100644 --- a/lib/ui/src/ui_mutation_observer.h +++ b/lib/ui/src/ui_mutation_observer.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_mutation_observer.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -10,8 +10,8 @@ */ typedef struct ui_mutation_connection { - ui_widget_t *widget; - ui_mutation_observer_t *observer; - ui_mutation_observer_init_t options; - list_node_t node; + ui_widget_t *widget; + ui_mutation_observer_t *observer; + ui_mutation_observer_init_t options; + list_node_t node; } ui_mutation_connection_t; diff --git a/lib/ui/src/ui_rect.c b/lib/ui/src/ui_rect.c index c16c2f13b..6adccc09c 100644 --- a/lib/ui/src/ui_rect.c +++ b/lib/ui/src/ui_rect.c @@ -1,19 +1,23 @@ /* * lib/ui/src/ui_rect.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include #include #include -void ui_rect_from_pd_rect(ui_rect_t *ui_rect, const pd_rect_t *rect, float scale) +void ui_rect_from_pd_rect(ui_rect_t *ui_rect, const pd_rect_t *rect, + float scale) { ui_rect->x = rect->x / scale; ui_rect->y = rect->y / scale; diff --git a/lib/ui/src/ui_renderer.c b/lib/ui/src/ui_renderer.c index c6ee563f9..3b070f0fe 100644 --- a/lib/ui/src/ui_renderer.c +++ b/lib/ui/src/ui_renderer.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_renderer.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -149,7 +152,8 @@ bool ui_widget_mark_dirty_rect(ui_widget_t *w, ui_rect_t *in_rect, break; } if (w->rendering.dirty_rect_type > UI_DIRTY_RECT_TYPE_NONE) { - ui_rect_merge(&w->rendering.dirty_rect, &rect, &w->rendering.dirty_rect); + ui_rect_merge(&w->rendering.dirty_rect, &rect, + &w->rendering.dirty_rect); } else { w->rendering.dirty_rect = rect; } @@ -219,7 +223,7 @@ size_t ui_widget_get_dirty_rects(ui_widget_t *w, list_t *rects) int x = ui_compute(w->padding_box.x); int y = ui_compute(w->padding_box.y); - + ui_widget_collect_dirty_rect(w, rects, 0, 0, w->padding_box); for (list_each(node, rects)) { rect = node->data; @@ -299,9 +303,9 @@ static ui_renderer_t *ui_renderer_create(ui_widget_t *w, pd_context_t *paint, that->can_render_content = pd_rect_overlap(&that->style->padding_box, &that->actual_paint_rect, &that->actual_content_rect); - - ui_rect_from_pd_rect(&that->content_rect, &that->actual_content_rect, - ui_get_actual_scale()); + + ui_rect_from_pd_rect(&that->content_rect, &that->actual_content_rect, + ui_get_actual_scale()); DEBUG_MSG("[%s] content_rect: (%d, %d, %d, %d)\n", w->id, that->actual_content_rect.x, that->actual_content_rect.y, that->actual_content_rect.width, diff --git a/lib/ui/src/ui_resizer.c b/lib/ui/src/ui_resizer.c index 0969e8306..f8ec12aba 100644 --- a/lib/ui/src/ui_resizer.c +++ b/lib/ui/src/ui_resizer.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_resizer.c * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ui/src/ui_resizer.h b/lib/ui/src/ui_resizer.h index ae4447cb3..dca80d8a9 100644 --- a/lib/ui/src/ui_resizer.h +++ b/lib/ui/src/ui_resizer.h @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_resizer.h * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ui/src/ui_root.c b/lib/ui/src/ui_root.c index d7438fbc9..df07fbe6f 100644 --- a/lib/ui/src/ui_root.c +++ b/lib/ui/src/ui_root.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_root.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -16,21 +19,21 @@ static ui_widget_t *ui_root_widget; ui_widget_t *ui_root(void) { - return ui_root_widget; + return ui_root_widget; } int ui_root_append(ui_widget_t *w) { - return ui_widget_append(ui_root_widget, w); + return ui_widget_append(ui_root_widget, w); } void ui_init_root(void) { - ui_root_widget = ui_create_widget("root"); - ui_widget_set_title(ui_root_widget, L"LCUI Display"); + ui_root_widget = ui_create_widget("root"); + ui_widget_set_title(ui_root_widget, L"LCUI Display"); } void ui_destroy_root(void) { - ui_widget_destroy(ui_root_widget); + ui_widget_destroy(ui_root_widget); } diff --git a/lib/ui/src/ui_root.h b/lib/ui/src/ui_root.h index 4d6fc5043..75dc353cd 100644 --- a/lib/ui/src/ui_root.h +++ b/lib/ui/src/ui_root.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_root.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ui/src/ui_text_style.c b/lib/ui/src/ui_text_style.c index 1181f18ec..8dbd586c1 100644 --- a/lib/ui/src/ui_text_style.c +++ b/lib/ui/src/ui_text_style.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_text_style.c: -- CSS font style parse and operation set. * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include @@ -223,8 +226,7 @@ void ui_compute_text_style(ui_text_style_t *fs, fs->font_ids = NULL; } if (style->font_family) { - pd_font_query(&fs->font_ids, fs->font_style, - fs->font_weight, - (const char *const *)style->font_family); + pd_font_query(&fs->font_ids, fs->font_style, fs->font_weight, + (const char *const *)style->font_family); } } diff --git a/lib/ui/src/ui_tree.c b/lib/ui/src/ui_tree.c index 4d8eae967..ba946272c 100644 --- a/lib/ui/src/ui_tree.c +++ b/lib/ui/src/ui_tree.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_tree.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ui/src/ui_updater.c b/lib/ui/src/ui_updater.c index d9df6f98b..d17cbb7c5 100644 --- a/lib/ui/src/ui_updater.c +++ b/lib/ui/src/ui_updater.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_updater.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ // #define UI_DEBUG_ENABLED diff --git a/lib/ui/src/ui_updater.h b/lib/ui/src/ui_updater.h index d2052798d..42c39e5e4 100644 --- a/lib/ui/src/ui_updater.h +++ b/lib/ui/src/ui_updater.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_updater.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ui/src/ui_widget.c b/lib/ui/src/ui_widget.c index 8c8bd928b..10c815d0c 100644 --- a/lib/ui/src/ui_widget.c +++ b/lib/ui/src/ui_widget.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_widget.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ui/src/ui_widget.h b/lib/ui/src/ui_widget.h index 1cd054909..3af3cc158 100644 --- a/lib/ui/src/ui_widget.h +++ b/lib/ui/src/ui_widget.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_widget.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ui/src/ui_widget_attributes.c b/lib/ui/src/ui_widget_attributes.c index 1919893ae..e1722dab7 100644 --- a/lib/ui/src/ui_widget_attributes.c +++ b/lib/ui/src/ui_widget_attributes.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_widget_attributes.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ui/src/ui_widget_attributes.h b/lib/ui/src/ui_widget_attributes.h index 7c443622a..4624458d9 100644 --- a/lib/ui/src/ui_widget_attributes.h +++ b/lib/ui/src/ui_widget_attributes.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_widget_attributes.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ui/src/ui_widget_background.c b/lib/ui/src/ui_widget_background.c index 862156101..48f002390 100644 --- a/lib/ui/src/ui_widget_background.c +++ b/lib/ui/src/ui_widget_background.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_widget_background.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ui/src/ui_widget_background.h b/lib/ui/src/ui_widget_background.h index 106e7e0cd..9095ee8bc 100644 --- a/lib/ui/src/ui_widget_background.h +++ b/lib/ui/src/ui_widget_background.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_widget_background.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -10,4 +10,4 @@ */ void ui_widget_paint_background(ui_widget_t *w, pd_context_t *paint, - ui_widget_actual_style_t *style); + ui_widget_actual_style_t *style); diff --git a/lib/ui/src/ui_widget_border.c b/lib/ui/src/ui_widget_border.c index f75f2496e..8142a27ca 100644 --- a/lib/ui/src/ui_widget_border.c +++ b/lib/ui/src/ui_widget_border.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_widget_border.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -14,55 +17,55 @@ #include #include "ui_widget_border.h" -static void ui_widget_compute_border(ui_widget_t* w, pd_border_t* b) +static void ui_widget_compute_border(ui_widget_t *w, pd_border_t *b) { - css_computed_style_t* s = &w->computed_style; - float r = y_min(w->border_box.width, w->border_box.width) / 2.0f; + css_computed_style_t *s = &w->computed_style; + float r = y_min(w->border_box.width, w->border_box.width) / 2.0f; - b->top.color.value = s->border_top_color; - b->left.color.value = s->border_left_color; - b->right.color.value = s->border_right_color; - b->bottom.color.value = s->border_bottom_color; - b->top.style = s->type_bits.border_top_style; - b->left.style = s->type_bits.border_left_style; - b->right.style = s->type_bits.border_right_style; - b->bottom.style = s->type_bits.border_bottom_style; - b->top.width = ui_compute(s->border_top_width); - b->left.width = ui_compute(s->border_left_width); - b->right.width = ui_compute(s->border_right_width); - b->bottom.width = ui_compute(s->border_bottom_width); - b->top_left_radius = ui_compute(y_min(s->border_top_left_radius, r)); - b->top_right_radius = ui_compute(y_min(s->border_top_right_radius, r)); - b->bottom_left_radius = - ui_compute(y_min(s->border_bottom_left_radius, r)); - b->bottom_right_radius = - ui_compute(y_min(s->border_bottom_right_radius, r)); + b->top.color.value = s->border_top_color; + b->left.color.value = s->border_left_color; + b->right.color.value = s->border_right_color; + b->bottom.color.value = s->border_bottom_color; + b->top.style = s->type_bits.border_top_style; + b->left.style = s->type_bits.border_left_style; + b->right.style = s->type_bits.border_right_style; + b->bottom.style = s->type_bits.border_bottom_style; + b->top.width = ui_compute(s->border_top_width); + b->left.width = ui_compute(s->border_left_width); + b->right.width = ui_compute(s->border_right_width); + b->bottom.width = ui_compute(s->border_bottom_width); + b->top_left_radius = ui_compute(y_min(s->border_top_left_radius, r)); + b->top_right_radius = ui_compute(y_min(s->border_top_right_radius, r)); + b->bottom_left_radius = + ui_compute(y_min(s->border_bottom_left_radius, r)); + b->bottom_right_radius = + ui_compute(y_min(s->border_bottom_right_radius, r)); } -void ui_widget_paint_border(ui_widget_t* w, pd_context_t* ctx, - ui_widget_actual_style_t* style) +void ui_widget_paint_border(ui_widget_t *w, pd_context_t *ctx, + ui_widget_actual_style_t *style) { - pd_rect_t box; - pd_border_t border; + pd_rect_t box; + pd_border_t border; - box.x = style->border_box.x - style->canvas_box.x; - box.y = style->border_box.y - style->canvas_box.y; - box.width = style->border_box.width; - box.height = style->border_box.height; - ui_widget_compute_border(w, &border); - pd_paint_border(ctx, &border, &box); + box.x = style->border_box.x - style->canvas_box.x; + box.y = style->border_box.y - style->canvas_box.y; + box.width = style->border_box.width; + box.height = style->border_box.height; + ui_widget_compute_border(w, &border); + pd_paint_border(ctx, &border, &box); } -void ui_widget_crop_content(ui_widget_t* w, pd_context_t* ctx, - ui_widget_actual_style_t* style) +void ui_widget_crop_content(ui_widget_t *w, pd_context_t *ctx, + ui_widget_actual_style_t *style) { - pd_rect_t box; - pd_border_t border; + pd_rect_t box; + pd_border_t border; - box.x = style->border_box.x - style->canvas_box.x; - box.y = style->border_box.y - style->canvas_box.y; - box.width = style->border_box.width; - box.height = style->border_box.height; - ui_widget_compute_border(w, &border); - pd_crop_border_content(ctx, &border, &box); + box.x = style->border_box.x - style->canvas_box.x; + box.y = style->border_box.y - style->canvas_box.y; + box.width = style->border_box.width; + box.height = style->border_box.height; + ui_widget_compute_border(w, &border); + pd_crop_border_content(ctx, &border, &box); } diff --git a/lib/ui/src/ui_widget_border.h b/lib/ui/src/ui_widget_border.h index f4b19a6c8..06033c98c 100644 --- a/lib/ui/src/ui_widget_border.h +++ b/lib/ui/src/ui_widget_border.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_widget_border.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -10,6 +10,6 @@ */ void ui_widget_paint_border(ui_widget_t *w, pd_context_t *paint, - ui_widget_actual_style_t *style); + ui_widget_actual_style_t *style); void ui_widget_crop_content(ui_widget_t *w, pd_context_t *paint, - ui_widget_actual_style_t *style); + ui_widget_actual_style_t *style); diff --git a/lib/ui/src/ui_widget_box_shadow.c b/lib/ui/src/ui_widget_box_shadow.c index 08973b93d..af577ad66 100644 --- a/lib/ui/src/ui_widget_box_shadow.c +++ b/lib/ui/src/ui_widget_box_shadow.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_widget_box_shadow.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -14,29 +17,29 @@ #include #include "ui_widget_box_shadow.h" -void ui_widget_paint_box_shadow(ui_widget_t* w, pd_context_t* ctx, - ui_widget_actual_style_t* style) +void ui_widget_paint_box_shadow(ui_widget_t *w, pd_context_t *ctx, + ui_widget_actual_style_t *style) { - pd_rect_t box; - pd_boxshadow_t bs; - css_computed_style_t* s = &w->computed_style; + pd_rect_t box; + pd_boxshadow_t bs; + css_computed_style_t *s = &w->computed_style; - if (s->type_bits.box_shadow == CSS_BOX_SHADOW_NONE || - s->box_shadow_color < 1) { - return; - } - bs.x = ui_compute(s->box_shadow_x); - bs.y = ui_compute(s->box_shadow_y); - bs.blur = ui_compute(s->box_shadow_blur); - bs.spread = ui_compute(s->box_shadow_spread); - bs.color.value = s->box_shadow_color; - bs.top_left_radius = ui_compute(s->border_top_left_radius); - bs.top_right_radius = ui_compute(s->border_top_right_radius); - bs.bottom_left_radius = ui_compute(s->border_bottom_left_radius); - bs.bottom_right_radius = ui_compute(s->border_bottom_right_radius); - box.x = box.y = 0; - box.width = style->canvas_box.width; - box.height = style->canvas_box.height; - pd_paint_boxshadow(ctx, &bs, &box, style->border_box.width, - style->border_box.height); + if (s->type_bits.box_shadow == CSS_BOX_SHADOW_NONE || + s->box_shadow_color < 1) { + return; + } + bs.x = ui_compute(s->box_shadow_x); + bs.y = ui_compute(s->box_shadow_y); + bs.blur = ui_compute(s->box_shadow_blur); + bs.spread = ui_compute(s->box_shadow_spread); + bs.color.value = s->box_shadow_color; + bs.top_left_radius = ui_compute(s->border_top_left_radius); + bs.top_right_radius = ui_compute(s->border_top_right_radius); + bs.bottom_left_radius = ui_compute(s->border_bottom_left_radius); + bs.bottom_right_radius = ui_compute(s->border_bottom_right_radius); + box.x = box.y = 0; + box.width = style->canvas_box.width; + box.height = style->canvas_box.height; + pd_paint_boxshadow(ctx, &bs, &box, style->border_box.width, + style->border_box.height); } diff --git a/lib/ui/src/ui_widget_box_shadow.h b/lib/ui/src/ui_widget_box_shadow.h index a3cae5976..ae8300c10 100644 --- a/lib/ui/src/ui_widget_box_shadow.h +++ b/lib/ui/src/ui_widget_box_shadow.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_widget_box_shadow.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -10,4 +10,4 @@ */ void ui_widget_paint_box_shadow(ui_widget_t *w, pd_context_t *paint, - ui_widget_actual_style_t *style); + ui_widget_actual_style_t *style); diff --git a/lib/ui/src/ui_widget_classes.c b/lib/ui/src/ui_widget_classes.c index 53f48c032..8c80d193d 100644 --- a/lib/ui/src/ui_widget_classes.c +++ b/lib/ui/src/ui_widget_classes.c @@ -1,82 +1,86 @@ /* * lib/ui/src/ui_widget_classes.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include #include "ui_widget_classes.h" #include "ui_widget_style.h" -static void ui_widget_refresh_children_by_classes(ui_widget_t* w) +static void ui_widget_refresh_children_by_classes(ui_widget_t *w) { - list_node_t *node; + list_node_t *node; - if (w->extra && w->extra->rules.ignore_classes_change) { - return; - } - ui_widget_request_refresh_style(w); - for (list_each(node, &w->children)) { - ui_widget_refresh_children_by_classes(node->data); - } + if (w->extra && w->extra->rules.ignore_classes_change) { + return; + } + ui_widget_request_refresh_style(w); + for (list_each(node, &w->children)) { + ui_widget_refresh_children_by_classes(node->data); + } } -static int ui_widget_handle_classes_change(ui_widget_t* w, const char *name) +static int ui_widget_handle_classes_change(ui_widget_t *w, const char *name) { - ui_widget_request_refresh_style(w); - if (w->extra && w->extra->rules.ignore_classes_change) { - return 0; - } - /* If widget is not ready, indicate that the style of the children has - * been marked needs to be refreshed */ - if (w->state < UI_WIDGET_STATE_READY || w->state == UI_WIDGET_STATE_DELETED) { - return 1; - } - if (ui_widget_get_children_style_changes(w, 0, name) > 0) { - ui_widget_refresh_children_by_classes(w); - return 1; - } - return 0; + ui_widget_request_refresh_style(w); + if (w->extra && w->extra->rules.ignore_classes_change) { + return 0; + } + /* If widget is not ready, indicate that the style of the children has + * been marked needs to be refreshed */ + if (w->state < UI_WIDGET_STATE_READY || + w->state == UI_WIDGET_STATE_DELETED) { + return 1; + } + if (ui_widget_get_children_style_changes(w, 0, name) > 0) { + ui_widget_refresh_children_by_classes(w); + return 1; + } + return 0; } -int ui_widget_add_class(ui_widget_t* w, const char *class_name) +int ui_widget_add_class(ui_widget_t *w, const char *class_name) { - if (strlist_has(w->classes, class_name)) { - return 1; - } - if (strlist_add(&w->classes, class_name) <= 0) { - return 0; - } - return ui_widget_handle_classes_change(w, class_name); + if (strlist_has(w->classes, class_name)) { + return 1; + } + if (strlist_add(&w->classes, class_name) <= 0) { + return 0; + } + return ui_widget_handle_classes_change(w, class_name); } -bool ui_widget_has_class(ui_widget_t* w, const char *class_name) +bool ui_widget_has_class(ui_widget_t *w, const char *class_name) { - if (strlist_has(w->classes, class_name)) { - return true; - } - return false; + if (strlist_has(w->classes, class_name)) { + return true; + } + return false; } -int ui_widget_remove_class(ui_widget_t* w, const char *class_name) +int ui_widget_remove_class(ui_widget_t *w, const char *class_name) { - if (strlist_has(w->classes, class_name)) { - ui_widget_handle_classes_change(w, class_name); - strlist_remove(&w->classes, class_name); - return 1; - } - return 0; + if (strlist_has(w->classes, class_name)) { + ui_widget_handle_classes_change(w, class_name); + strlist_remove(&w->classes, class_name); + return 1; + } + return 0; } -void ui_widget_destroy_classes(ui_widget_t* w) +void ui_widget_destroy_classes(ui_widget_t *w) { - if (w->classes) { - strlist_free(w->classes); - } - w->classes = NULL; + if (w->classes) { + strlist_free(w->classes); + } + w->classes = NULL; } diff --git a/lib/ui/src/ui_widget_classes.h b/lib/ui/src/ui_widget_classes.h index 22211c13f..b49844d45 100644 --- a/lib/ui/src/ui_widget_classes.h +++ b/lib/ui/src/ui_widget_classes.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_widget_classes.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ui/src/ui_widget_hash.c b/lib/ui/src/ui_widget_hash.c index 88bd0d6db..b44520aa4 100644 --- a/lib/ui/src/ui_widget_hash.c +++ b/lib/ui/src/ui_widget_hash.c @@ -1,148 +1,151 @@ /* * lib/ui/src/ui_widget_hash.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include #include -void ui_widget_generate_self_hash(ui_widget_t* widget) +void ui_widget_generate_self_hash(ui_widget_t *widget) { - int i; - unsigned hash = 1080; - ui_widget_t* w; + int i; + unsigned hash = 1080; + ui_widget_t *w; - for (w = widget; w; w = w->parent) { - if (w != widget) { - hash = strhash(hash, " "); - } - if (w->type) { - hash = strhash(hash, w->type); - } else { - hash = strhash(hash, "*"); - } - if (w->id) { - hash = strhash(hash, "#"); - hash = strhash(hash, w->id); - } - if (w->classes) { - for (i = 0; w->classes[i]; ++i) { - hash = strhash(hash, "."); - hash = strhash(hash, w->classes[i]); - } - } - if (w->status) { - for (i = 0; w->status[i]; ++i) { - hash = strhash(hash, ":"); - hash = strhash(hash, w->status[i]); - } - } - } - widget->hash = hash; + for (w = widget; w; w = w->parent) { + if (w != widget) { + hash = strhash(hash, " "); + } + if (w->type) { + hash = strhash(hash, w->type); + } else { + hash = strhash(hash, "*"); + } + if (w->id) { + hash = strhash(hash, "#"); + hash = strhash(hash, w->id); + } + if (w->classes) { + for (i = 0; w->classes[i]; ++i) { + hash = strhash(hash, "."); + hash = strhash(hash, w->classes[i]); + } + } + if (w->status) { + for (i = 0; w->status[i]; ++i) { + hash = strhash(hash, ":"); + hash = strhash(hash, w->status[i]); + } + } + } + widget->hash = hash; } -void ui_widget_generate_hash(ui_widget_t* w) +void ui_widget_generate_hash(ui_widget_t *w) { - list_node_t *node; + list_node_t *node; - ui_widget_generate_self_hash(w); - for (list_each(node, &w->children)) { - ui_widget_generate_hash(node->data); - } + ui_widget_generate_self_hash(w); + for (list_each(node, &w->children)) { + ui_widget_generate_hash(node->data); + } } -size_t ui_widget_export_hash(ui_widget_t* w, unsigned *hash_list, size_t len) +size_t ui_widget_export_hash(ui_widget_t *w, unsigned *hash_list, size_t len) { - size_t count = 0; - ui_widget_t* child; + size_t count = 0; + ui_widget_t *child; - child = w; - if (hash_list) { - child->hash = hash_list[count]; - } - ++count; - if (len > 0 && count >= len) { - return count; - } - while (child->children.length > 0) { - child = child->children.head.next->data; - } - while (child != w) { - while (child->children.length > 0) { - child = child->children.head.next->data; - } - if (hash_list) { - child->hash = hash_list[count]; - } - ++count; - if (len > 0 && count >= len) { - break; - } - if (child->node.next) { - child = child->node.next->data; - continue; - } - do { - child = child->parent; - if (child == w) { - break; - } - if (child->node.next) { - child = child->node.next->data; - break; - } - } while (1); - } - return count; + child = w; + if (hash_list) { + child->hash = hash_list[count]; + } + ++count; + if (len > 0 && count >= len) { + return count; + } + while (child->children.length > 0) { + child = child->children.head.next->data; + } + while (child != w) { + while (child->children.length > 0) { + child = child->children.head.next->data; + } + if (hash_list) { + child->hash = hash_list[count]; + } + ++count; + if (len > 0 && count >= len) { + break; + } + if (child->node.next) { + child = child->node.next->data; + continue; + } + do { + child = child->parent; + if (child == w) { + break; + } + if (child->node.next) { + child = child->node.next->data; + break; + } + } while (1); + } + return count; } -size_t ui_widget_import_hash(ui_widget_t* w, unsigned *hash_list, size_t maxlen) +size_t ui_widget_import_hash(ui_widget_t *w, unsigned *hash_list, size_t maxlen) { - size_t count = 0; - ui_widget_t* child; + size_t count = 0; + ui_widget_t *child; - child = w; - if (hash_list) { - hash_list[count] = child->hash; - } - ++count; - if (maxlen > 0 && count >= maxlen) { - return count; - } - while (child->children.length > 0) { - child = child->children.head.next->data; - } - while (child != w) { - while (child->children.length > 0) { - child = child->children.head.next->data; - } - if (hash_list) { - hash_list[count] = child->hash; - } - ++count; - if (maxlen > 0 && count >= maxlen) { - break; - } - if (child->node.next) { - child = child->node.next->data; - continue; - } - do { - child = child->parent; - if (child == w) { - break; - } - if (child->node.next) { - child = child->node.next->data; - break; - } - } while (1); - } - return count; + child = w; + if (hash_list) { + hash_list[count] = child->hash; + } + ++count; + if (maxlen > 0 && count >= maxlen) { + return count; + } + while (child->children.length > 0) { + child = child->children.head.next->data; + } + while (child != w) { + while (child->children.length > 0) { + child = child->children.head.next->data; + } + if (hash_list) { + hash_list[count] = child->hash; + } + ++count; + if (maxlen > 0 && count >= maxlen) { + break; + } + if (child->node.next) { + child = child->node.next->data; + continue; + } + do { + child = child->parent; + if (child == w) { + break; + } + if (child->node.next) { + child = child->node.next->data; + break; + } + } while (1); + } + return count; } diff --git a/lib/ui/src/ui_widget_helper.c b/lib/ui/src/ui_widget_helper.c index 99e99c226..174a39401 100644 --- a/lib/ui/src/ui_widget_helper.c +++ b/lib/ui/src/ui_widget_helper.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_widget_helper.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ui/src/ui_widget_id.c b/lib/ui/src/ui_widget_id.c index 24cf1e02f..b85d2abc9 100644 --- a/lib/ui/src/ui_widget_id.c +++ b/lib/ui/src/ui_widget_id.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_widget_id.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -14,102 +17,101 @@ #include #include "ui_widget_id.h" -static dict_t* ui_widget_id_dict; +static dict_t *ui_widget_id_dict; -int ui_widget_destroy_id(ui_widget_t* w) +int ui_widget_destroy_id(ui_widget_t *w) { - list_t *list; - list_node_t *node; + list_t *list; + list_node_t *node; - if (!w->id) { - return -1; - } - list = dict_fetch_value(ui_widget_id_dict, w->id); - if (!list) { - return -2; - } - for (list_each(node, list)) { - if (node->data == w) { - free(w->id); - w->id = NULL; - list_unlink(list, node); - free(node); - return 0; - } - } - return -3; + if (!w->id) { + return -1; + } + list = dict_fetch_value(ui_widget_id_dict, w->id); + if (!list) { + return -2; + } + for (list_each(node, list)) { + if (node->data == w) { + free(w->id); + w->id = NULL; + list_unlink(list, node); + free(node); + return 0; + } + } + return -3; } -int ui_widget_set_id(ui_widget_t* w, const char *idstr) +int ui_widget_set_id(ui_widget_t *w, const char *idstr) { - list_t *list; + list_t *list; - ui_widget_destroy_id(w); - if (!idstr) { - return -1; - } - w->id = strdup2(idstr); - if (!w->id) { - goto error_exit; - } - list = dict_fetch_value(ui_widget_id_dict, w->id); - if (!list) { - list = malloc(sizeof(list_t)); - if (!list) { - goto error_exit; - } - list_create(list); - if (dict_add(ui_widget_id_dict, w->id, list) != 0) { - free(list); - goto error_exit; - } - } - if (!list_append(list, w)) { - goto error_exit; - } - return 0; + ui_widget_destroy_id(w); + if (!idstr) { + return -1; + } + w->id = strdup2(idstr); + if (!w->id) { + goto error_exit; + } + list = dict_fetch_value(ui_widget_id_dict, w->id); + if (!list) { + list = malloc(sizeof(list_t)); + if (!list) { + goto error_exit; + } + list_create(list); + if (dict_add(ui_widget_id_dict, w->id, list) != 0) { + free(list); + goto error_exit; + } + } + if (!list_append(list, w)) { + goto error_exit; + } + return 0; error_exit: - if (w->id) { - free(w->id); - w->id = NULL; - } - return -2; + if (w->id) { + free(w->id); + w->id = NULL; + } + return -2; } -ui_widget_t* ui_get_widget(const char *id) +ui_widget_t *ui_get_widget(const char *id) { - list_t *list; - ui_widget_t* w = NULL; + list_t *list; + ui_widget_t *w = NULL; - if (!id) { - return NULL; - } - list = dict_fetch_value(ui_widget_id_dict, id); - if (list) { - w = list_get(list, 0); - } - return w; + if (!id) { + return NULL; + } + list = dict_fetch_value(ui_widget_id_dict, id); + if (list) { + w = list_get(list, 0); + } + return w; } - static void ui_widget_id_dict_val_destructor(void *privdata, void *data) { - list_t *list = data; - list_destroy(list, NULL); - free(list); + list_t *list = data; + list_destroy(list, NULL); + free(list); } void ui_init_widget_id(void) { - static dict_type_t type; - dict_init_string_copy_key_type(&type); - type.val_destructor = ui_widget_id_dict_val_destructor; - ui_widget_id_dict = dict_create(&type, NULL); + static dict_type_t type; + dict_init_string_copy_key_type(&type); + type.val_destructor = ui_widget_id_dict_val_destructor; + ui_widget_id_dict = dict_create(&type, NULL); } void ui_destroy_widget_id(void) { - dict_destroy(ui_widget_id_dict); - ui_widget_id_dict = NULL; + dict_destroy(ui_widget_id_dict); + ui_widget_id_dict = NULL; } diff --git a/lib/ui/src/ui_widget_id.h b/lib/ui/src/ui_widget_id.h index edc96a9e2..ec43f1c0f 100644 --- a/lib/ui/src/ui_widget_id.h +++ b/lib/ui/src/ui_widget_id.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_widget_id.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ui/src/ui_widget_layout.c b/lib/ui/src/ui_widget_layout.c index 79b6d01ab..e7cdfd085 100644 --- a/lib/ui/src/ui_widget_layout.c +++ b/lib/ui/src/ui_widget_layout.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_widget_layout.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ // #define UI_DEBUG_ENABLED diff --git a/lib/ui/src/ui_widget_layout.h b/lib/ui/src/ui_widget_layout.h index e0f401654..ae8e18d5d 100644 --- a/lib/ui/src/ui_widget_layout.h +++ b/lib/ui/src/ui_widget_layout.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_widget_layout.h * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ui/src/ui_widget_observer.c b/lib/ui/src/ui_widget_observer.c index 12c59a9bf..9232c88a4 100644 --- a/lib/ui/src/ui_widget_observer.c +++ b/lib/ui/src/ui_widget_observer.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_widget_observer.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ui/src/ui_widget_observer.h b/lib/ui/src/ui_widget_observer.h index 1930a0b36..6461c63ec 100644 --- a/lib/ui/src/ui_widget_observer.h +++ b/lib/ui/src/ui_widget_observer.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_widget_observer.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -10,7 +10,7 @@ */ bool ui_widget_has_observer(ui_widget_t *widget, - ui_mutation_record_type_t type); + ui_mutation_record_type_t type); int ui_widget_add_mutation_record(ui_widget_t *widget, - ui_mutation_record_t *record); + ui_mutation_record_t *record); diff --git a/lib/ui/src/ui_widget_prototype.c b/lib/ui/src/ui_widget_prototype.c index d6630986e..9e3ca9f54 100644 --- a/lib/ui/src/ui_widget_prototype.c +++ b/lib/ui/src/ui_widget_prototype.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_widget_prototype.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ui/src/ui_widget_prototype.h b/lib/ui/src/ui_widget_prototype.h index 880a2e3e8..989b4b537 100644 --- a/lib/ui/src/ui_widget_prototype.h +++ b/lib/ui/src/ui_widget_prototype.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_widget_prototype.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ui/src/ui_widget_status.c b/lib/ui/src/ui_widget_status.c index ed457a1da..04e15d2c1 100644 --- a/lib/ui/src/ui_widget_status.c +++ b/lib/ui/src/ui_widget_status.c @@ -1,113 +1,117 @@ /* * lib/ui/src/ui_widget_status.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include #include "ui_widget_status.h" #include "ui_widget_style.h" -static void ui_widget_refresh_children_by_status(ui_widget_t* w) +static void ui_widget_refresh_children_by_status(ui_widget_t *w) { - list_node_t *node; + list_node_t *node; - if (w->extra && w->extra->rules.ignore_status_change) { - return; - } - ui_widget_request_refresh_style(w); - for (list_each(node, &w->children)) { - ui_widget_refresh_children_by_status(node->data); - } + if (w->extra && w->extra->rules.ignore_status_change) { + return; + } + ui_widget_request_refresh_style(w); + for (list_each(node, &w->children)) { + ui_widget_refresh_children_by_status(node->data); + } } -static int ui_wdiget_handle_status_change(ui_widget_t* w, const char *name) +static int ui_wdiget_handle_status_change(ui_widget_t *w, const char *name) { - ui_widget_request_refresh_style(w); - if (w->state < UI_WIDGET_STATE_READY || w->state == UI_WIDGET_STATE_DELETED) { - return 1; - } - if (w->extra && w->extra->rules.ignore_status_change) { - return 0; - } - if (ui_widget_get_children_style_changes(w, 1, name) > 0) { - ui_widget_refresh_children_by_status(w); - return 1; - } - return 0; + ui_widget_request_refresh_style(w); + if (w->state < UI_WIDGET_STATE_READY || + w->state == UI_WIDGET_STATE_DELETED) { + return 1; + } + if (w->extra && w->extra->rules.ignore_status_change) { + return 0; + } + if (ui_widget_get_children_style_changes(w, 1, name) > 0) { + ui_widget_refresh_children_by_status(w); + return 1; + } + return 0; } -int ui_widget_add_status(ui_widget_t* w, const char *status_name) +int ui_widget_add_status(ui_widget_t *w, const char *status_name) { - if (strlist_has(w->status, status_name)) { - return 0; - } - if (strlist_add(&w->status, status_name) <= 0) { - return 0; - } - return ui_wdiget_handle_status_change(w, status_name); + if (strlist_has(w->status, status_name)) { + return 0; + } + if (strlist_add(&w->status, status_name) <= 0) { + return 0; + } + return ui_wdiget_handle_status_change(w, status_name); } -bool ui_widget_has_status(ui_widget_t* w, const char *status_name) +bool ui_widget_has_status(ui_widget_t *w, const char *status_name) { - if (strlist_has(w->status, status_name)) { - return true; - } - return false; + if (strlist_has(w->status, status_name)) { + return true; + } + return false; } -int ui_widget_remove_status(ui_widget_t* w, const char *status_name) +int ui_widget_remove_status(ui_widget_t *w, const char *status_name) { - if (strlist_has(w->status, status_name)) { - ui_wdiget_handle_status_change(w, status_name); - strlist_remove(&w->status, status_name); - return 1; - } - return 0; + if (strlist_has(w->status, status_name)) { + ui_wdiget_handle_status_change(w, status_name); + strlist_remove(&w->status, status_name); + return 1; + } + return 0; } -void ui_widget_update_status(ui_widget_t* widget) +void ui_widget_update_status(ui_widget_t *widget) { - ui_widget_t* child; + ui_widget_t *child; - if (!widget->parent) { - return; - } - if (widget->index == widget->parent->children.length - 1) { - ui_widget_add_status(widget, "last-child"); - child = ui_widget_prev(widget); - if (child) { - ui_widget_remove_status(child, "last-child"); - } - } - if (widget->index == 0) { - ui_widget_add_status(widget, "first-child"); - child = ui_widget_next(widget); - if (child) { - ui_widget_remove_status(child, "first-child"); - } - } + if (!widget->parent) { + return; + } + if (widget->index == widget->parent->children.length - 1) { + ui_widget_add_status(widget, "last-child"); + child = ui_widget_prev(widget); + if (child) { + ui_widget_remove_status(child, "last-child"); + } + } + if (widget->index == 0) { + ui_widget_add_status(widget, "first-child"); + child = ui_widget_next(widget); + if (child) { + ui_widget_remove_status(child, "first-child"); + } + } } -void ui_widget_set_disabled(ui_widget_t* w, bool disabled) +void ui_widget_set_disabled(ui_widget_t *w, bool disabled) { - w->disabled = disabled; - if (w->disabled) { - ui_widget_add_status(w, "disabled"); - } else { - ui_widget_remove_status(w, "disabled"); - } + w->disabled = disabled; + if (w->disabled) { + ui_widget_add_status(w, "disabled"); + } else { + ui_widget_remove_status(w, "disabled"); + } } -void ui_widget_destroy_status(ui_widget_t* w) +void ui_widget_destroy_status(ui_widget_t *w) { - if (w->status) { - strlist_free(w->status); - } - w->status = NULL; + if (w->status) { + strlist_free(w->status); + } + w->status = NULL; } diff --git a/lib/ui/src/ui_widget_status.h b/lib/ui/src/ui_widget_status.h index b69d5e13d..1ef9bfa38 100644 --- a/lib/ui/src/ui_widget_status.h +++ b/lib/ui/src/ui_widget_status.h @@ -1,7 +1,7 @@ /* * lib/ui/src/ui_widget_status.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/lib/ui/src/ui_widget_style.c b/lib/ui/src/ui_widget_style.c index b22dcb380..8dbb93bfd 100644 --- a/lib/ui/src/ui_widget_style.c +++ b/lib/ui/src/ui_widget_style.c @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_widget_style.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/ui/src/ui_widget_style.h b/lib/ui/src/ui_widget_style.h index 11bed0b61..82479003f 100644 --- a/lib/ui/src/ui_widget_style.h +++ b/lib/ui/src/ui_widget_style.h @@ -1,12 +1,15 @@ /* * lib/ui/src/ui_widget_style.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/lib/worker/include/worker.h b/lib/worker/include/worker.h index 40b4bdce4..093d0e280 100644 --- a/lib/worker/include/worker.h +++ b/lib/worker/include/worker.h @@ -1,12 +1,15 @@ /* * lib/worker/include/worker.h: -- worker threading and task * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #ifndef LIB_WORKER_INCLULDE_WORKER_H diff --git a/lib/worker/include/worker/common.h b/lib/worker/include/worker/common.h index 540baa34e..6737fb117 100644 --- a/lib/worker/include/worker/common.h +++ b/lib/worker/include/worker/common.h @@ -1,12 +1,15 @@ /* * lib/worker/include/worker/common.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "config.h" diff --git a/lib/worker/src/worker.c b/lib/worker/src/worker.c index f1091efe2..1ea8f3842 100644 --- a/lib/worker/src/worker.c +++ b/lib/worker/src/worker.c @@ -1,12 +1,15 @@ /* * lib/worker/src/worker.c: -- worker threading and task * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include @@ -68,7 +71,8 @@ void worker_destroy(worker_t *worker) thread_mutex_unlock(&worker->mutex); thread_join(thread, NULL); } - list_destroy(&worker->tasks, (list_item_destructor_t)worker_task_destroy); + list_destroy(&worker->tasks, + (list_item_destructor_t)worker_task_destroy); thread_mutex_unlock(&worker->mutex); thread_mutex_destroy(&worker->mutex); thread_cond_destroy(&worker->cond); diff --git a/package.json b/package.json index 3371374f9..6816a00c8 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "gui", "framework" ], - "author": "Liu Chao (https://lc-soft.io/)", + "author": "Liu Chao (https://lcui.dev)", "license": "MIT", "bugs": { "url": "https://github.com/lc-soft/LCUI/issues" diff --git a/scripts/add-copyright.js b/scripts/add-copyright.js index 4a6320c54..f6827d840 100644 --- a/scripts/add-copyright.js +++ b/scripts/add-copyright.js @@ -9,7 +9,7 @@ const includes = ["lib", "include", "src"].map((file) => ); const excludes = ["lib/yutil"].map((file) => path.resolve(cwd, file)); const extensions = [".c", ".h", ".h.in"]; -const copyrightHolder = "Liu Chao "; +const copyrightHolder = "Liu Chao "; const copyright = `/* * {{filePath}}{{summary}} * @@ -159,4 +159,8 @@ function traverseFolder(folderPath) { }); } -traverseFolder(cwd); +for (const include of includes) { + if (fs.existsSync(include) && fs.statSync(include).isDirectory()) { + traverseFolder(include); + } +} diff --git a/src/ini_doc.c b/src/ini_doc.c index 16e9bca81..e3224bb32 100644 --- a/src/ini_doc.c +++ b/src/ini_doc.c @@ -1,13 +1,15 @@ -/* - * src/ini_doc.c -- generic INI document. - * - * Copyright (c) 2023-2025, Liu Chao - * All rights reserved. +/* + * src/ini_doc.c: -- generic INI document. * + * Copyright (c) 2023-2026, Liu Chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include diff --git a/src/ini_doc.h b/src/ini_doc.h index 376a5b375..176051b65 100644 --- a/src/ini_doc.h +++ b/src/ini_doc.h @@ -1,13 +1,15 @@ -/* - * src/ini_doc.h -- generic INI document. - * - * Copyright (c) 2023-2025, Liu Chao - * All rights reserved. +/* + * src/ini_doc.h: -- generic INI document. * + * Copyright (c) 2023-2026, Liu Chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #ifndef LCUI_SRC_INI_DOC_H diff --git a/src/lcui.c b/src/lcui.c index 1e7881d41..d4d181217 100644 --- a/src/lcui.c +++ b/src/lcui.c @@ -1,12 +1,15 @@ /* * src/lcui.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All + * rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part + * of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file + * in the root directory of this source tree. */ #include @@ -37,10 +40,10 @@ void lcui_init(void) "Build at "__DATE__ " - "__TIME__ "\n" - "Copyright (C) 2012-2024 Liu Chao .\n" + "Copyright (C) 2012-2026 Liu Chao .\n" "This is open source software, licensed under MIT. \n" "See source distribution for detailed copyright notices.\n" - "To learn more, visit http://www.lcui.org.\n\n"); + "To learn more, visit http://lcui.dev\n\n"); lcui_app_init(); lcui_fonts_init(); diff --git a/src/lcui_app.c b/src/lcui_app.c index a74ab7f84..326051549 100644 --- a/src/lcui_app.c +++ b/src/lcui_app.c @@ -1,12 +1,15 @@ /* * src/lcui_app.c * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is + * part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT + * file in the root directory of this source tree. */ #include diff --git a/src/lcui_app.h b/src/lcui_app.h index d78c82c0f..f5c065334 100644 --- a/src/lcui_app.h +++ b/src/lcui_app.h @@ -1,7 +1,7 @@ -/* +/* * src/lcui_app.h * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -18,4 +18,4 @@ void lcui_app_init(void); void lcui_app_destroy(void); int lcui_app_process_events(ptk_process_events_option_t option); -#endif \ No newline at end of file +#endif diff --git a/src/lcui_fonts.c b/src/lcui_fonts.c index 2cd889b1d..68d3303c7 100644 --- a/src/lcui_fonts.c +++ b/src/lcui_fonts.c @@ -1,12 +1,15 @@ /* * src/lcui_fonts.c * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is + * part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT + * file in the root directory of this source tree. */ #include diff --git a/src/lcui_rendering.c b/src/lcui_rendering.c index 782ac2aa5..8c210aaf7 100644 --- a/src/lcui_rendering.c +++ b/src/lcui_rendering.c @@ -1,13 +1,15 @@ -/* - * src/lcui_rendering.c -- rendering settings. - * - * Copyright (c) 2023-2025, Liu Chao - * All rights reserved. +/* + * src/lcui_rendering.c: -- rendering settings. * + * Copyright (c) 2023-2026, Liu Chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include diff --git a/src/lcui_settings.c b/src/lcui_settings.c index 779d788af..3ef0d78e8 100644 --- a/src/lcui_settings.c +++ b/src/lcui_settings.c @@ -1,14 +1,18 @@ -/* - * src/lcui_settings.c -- global settings infrastructure. +/* + * src/lcui_settings.c: -- global settings infrastructure. * * Copyright (c) 2020, James Duong - * Copyright (c) 2023-2025, Liu Chao + * Copyright (c) + * 2023-2026, Liu Chao * All rights reserved. * + * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, distributed + * under the MIT License found in the + * LICENSE.TXT file in the root directory + * of this source tree. */ #include diff --git a/src/lcui_settings.h b/src/lcui_settings.h index c852650eb..6fad56115 100644 --- a/src/lcui_settings.h +++ b/src/lcui_settings.h @@ -1,13 +1,15 @@ -/* - * src/lcui_settings.h -- internal definitions for settings infrastructure. - * - * Copyright (c) 2023-2025, Liu Chao - * All rights reserved. +/* + * src/lcui_settings.h: -- internal definitions for settings infrastructure. * + * Copyright (c) 2023-2026, Liu Chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #ifndef LCUI_SRC_SETTINGS_H diff --git a/src/lcui_ui.c b/src/lcui_ui.c index 4f9de54d5..34b1773d7 100644 --- a/src/lcui_ui.c +++ b/src/lcui_ui.c @@ -1,12 +1,15 @@ /* * src/lcui_ui.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All + * rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part + * of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file + * in the root directory of this source tree. */ #include diff --git a/src/lcui_widgets.c b/src/lcui_widgets.c index 2a314ee35..d833a5768 100644 --- a/src/lcui_widgets.c +++ b/src/lcui_widgets.c @@ -1,12 +1,15 @@ /* * src/lcui_widgets.c * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include diff --git a/src/lcui_window_state.c b/src/lcui_window_state.c index 43fc4e434..77d5bda5f 100644 --- a/src/lcui_window_state.c +++ b/src/lcui_window_state.c @@ -1,13 +1,15 @@ -/* - * src/lcui_window_state.c -- window state settings. - * - * Copyright (c) 2023-2025, Liu Chao - * All rights reserved. +/* + * src/lcui_window_state.c: -- window state settings. * + * Copyright (c) 2023-2026, Liu Chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include "lcui_settings.h" diff --git a/src/lcui_worker.c b/src/lcui_worker.c index 15892c194..0a78e8d84 100644 --- a/src/lcui_worker.c +++ b/src/lcui_worker.c @@ -1,12 +1,15 @@ /* * src/lcui_worker.c * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is + * part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT + * file in the root directory of this source tree. */ #include diff --git a/src/setting_field.c b/src/setting_field.c index 12b1f4e5e..733c5a434 100644 --- a/src/setting_field.c +++ b/src/setting_field.c @@ -1,13 +1,15 @@ -/* - * src/setting_field.c -- schema-driven (de)serialization. - * - * Copyright (c) 2023-2025, Liu Chao - * All rights reserved. +/* + * src/setting_field.c: -- schema-driven (de)serialization. * + * Copyright (c) 2023-2026, Liu Chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include diff --git a/src/setting_field.h b/src/setting_field.h index 711c39b6a..48de4a03d 100644 --- a/src/setting_field.h +++ b/src/setting_field.h @@ -1,13 +1,15 @@ -/* - * src/setting_field.h -- schema-driven field definitions for settings. - * - * Copyright (c) 2023-2025, Liu Chao - * All rights reserved. +/* + * src/setting_field.h: -- schema-driven field definitions for settings. * + * Copyright (c) 2023-2026, Liu Chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #ifndef LCUI_SRC_SETTING_FIELD_H diff --git a/src/widgets/anchor.c b/src/widgets/anchor.c index 39f2c26bd..ed47bac00 100644 --- a/src/widgets/anchor.c +++ b/src/widgets/anchor.c @@ -1,12 +1,15 @@ /* * src/widgets/anchor.c: to element in HTML. * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include diff --git a/src/widgets/button.c b/src/widgets/button.c index 84bbac28c..7b9617c3a 100644 --- a/src/widgets/button.c +++ b/src/widgets/button.c @@ -1,12 +1,15 @@ /* * src/widgets/button.c: -- Button widget * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include @@ -43,25 +46,25 @@ button:disabled { ); -static void ui_button_on_init(ui_widget_t* w) +static void ui_button_on_init(ui_widget_t *w) { - ui_button_prototype->proto->init(w); - w->tab_index = 0; + ui_button_prototype->proto->init(w); + w->tab_index = 0; } -void ui_button_set_text_w(ui_widget_t* w, const wchar_t *wstr) +void ui_button_set_text_w(ui_widget_t *w, const wchar_t *wstr) { - ui_text_set_content_w(w, wstr); + ui_text_set_content_w(w, wstr); } -void ui_button_set_text(ui_widget_t* w, const char *str) +void ui_button_set_text(ui_widget_t *w, const char *str) { - ui_text_set_content(w, str); + ui_text_set_content(w, str); } void ui_register_button(void) { - ui_button_prototype = ui_create_widget_prototype("button", "text"); - ui_button_prototype->init = ui_button_on_init; - ui_load_css_string(ui_button_css, __FILE__); + ui_button_prototype = ui_create_widget_prototype("button", "text"); + ui_button_prototype->init = ui_button_on_init; + ui_load_css_string(ui_button_css, __FILE__); } diff --git a/src/widgets/canvas.c b/src/widgets/canvas.c index 81f44f39a..cddc4435a 100644 --- a/src/widgets/canvas.c +++ b/src/widgets/canvas.c @@ -1,12 +1,15 @@ /* * src/widgets/canvas.c: -- canvas, used to draw custom graphics * - * Copyright (c) 2019-2025, Liu chao All rights reserved. - * + * Copyright (c) 2019-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include @@ -15,148 +18,148 @@ #include typedef struct ui_canvas { - pd_canvas_t buffer; - list_t contexts; + pd_canvas_t buffer; + list_t contexts; } ui_canvas_t; static struct { - ui_widget_prototype_t *proto; + ui_widget_prototype_t *proto; } ui_canvas; static void ui_canvas_on_resize(ui_widget_t *w, float width, float height) { - float scale = ui_get_actual_scale(); - - pd_canvas_t buffer; - ui_canvas_t *canvas = ui_widget_get_data(w, ui_canvas.proto); - - pd_canvas_init(&buffer); - buffer.color_type = PD_COLOR_TYPE_ARGB; - pd_canvas_create(&buffer, (unsigned)(width * scale), - (unsigned)(height * scale)); - pd_canvas_replace(&buffer, &canvas->buffer, 0, 0); - pd_canvas_destroy(&canvas->buffer); - canvas->buffer = buffer; + float scale = ui_get_actual_scale(); + + pd_canvas_t buffer; + ui_canvas_t *canvas = ui_widget_get_data(w, ui_canvas.proto); + + pd_canvas_init(&buffer); + buffer.color_type = PD_COLOR_TYPE_ARGB; + pd_canvas_create(&buffer, (unsigned)(width * scale), + (unsigned)(height * scale)); + pd_canvas_replace(&buffer, &canvas->buffer, 0, 0); + pd_canvas_destroy(&canvas->buffer); + canvas->buffer = buffer; } static void ui_canvas_on_init(ui_widget_t *w) { - ui_canvas_t *canvas; + ui_canvas_t *canvas; - canvas = ui_widget_add_data(w, ui_canvas.proto, sizeof(ui_canvas_t)); - pd_canvas_init(&canvas->buffer); - list_create(&canvas->contexts); + canvas = ui_widget_add_data(w, ui_canvas.proto, sizeof(ui_canvas_t)); + pd_canvas_init(&canvas->buffer); + list_create(&canvas->contexts); } static void ui_canvas_on_destroy(ui_widget_t *w) { - list_node_t *node; - ui_canvas_context_t *ctx; - ui_canvas_t *canvas; - - canvas = ui_widget_add_data(w, ui_canvas.proto, sizeof(ui_canvas_t)); - for (list_each(node, &canvas->contexts)) { - ctx = node->data; - ctx->available = false; - } - list_destroy_without_node(&canvas->contexts, NULL); - pd_canvas_destroy(&canvas->buffer); + list_node_t *node; + ui_canvas_context_t *ctx; + ui_canvas_t *canvas; + + canvas = ui_widget_add_data(w, ui_canvas.proto, sizeof(ui_canvas_t)); + for (list_each(node, &canvas->contexts)) { + ctx = node->data; + ctx->available = false; + } + list_destroy_without_node(&canvas->contexts, NULL); + pd_canvas_destroy(&canvas->buffer); } static void ui_canvas_on_sizehint(ui_widget_t *w, ui_sizehint_t *hint) { - hint->max_width = UI_CANVAS_DEFAULT_WIDTH; - hint->max_height = UI_CANVAS_DEFAULT_HEIGHT; + hint->max_width = UI_CANVAS_DEFAULT_WIDTH; + hint->max_height = UI_CANVAS_DEFAULT_HEIGHT; } static void ui_canvas_on_paint(ui_widget_t *w, pd_context_t *paint, - ui_widget_actual_style_t *style) + ui_widget_actual_style_t *style) { - pd_canvas_t src, dest; - pd_rect_t content_rect, rect; - ui_canvas_t *canvas = ui_widget_get_data(w, ui_canvas.proto); - - content_rect.width = style->content_box.width; - content_rect.height = style->content_box.height; - content_rect.x = style->content_box.x - style->canvas_box.x; - content_rect.y = style->content_box.y - style->canvas_box.y; - if (!pd_rect_overlap(&content_rect, &paint->rect, &rect)) { - return; - } - content_rect.x = rect.x - content_rect.x; - content_rect.y = rect.y - content_rect.y; - content_rect.width = rect.width; - content_rect.height = rect.height; - rect.x -= paint->rect.x; - rect.y -= paint->rect.y; - pd_canvas_quote(&dest, &paint->canvas, &rect); - pd_canvas_quote(&src, &canvas->buffer, &content_rect); - pd_canvas_replace(&dest, &src, 0, 0); + pd_canvas_t src, dest; + pd_rect_t content_rect, rect; + ui_canvas_t *canvas = ui_widget_get_data(w, ui_canvas.proto); + + content_rect.width = style->content_box.width; + content_rect.height = style->content_box.height; + content_rect.x = style->content_box.x - style->canvas_box.x; + content_rect.y = style->content_box.y - style->canvas_box.y; + if (!pd_rect_overlap(&content_rect, &paint->rect, &rect)) { + return; + } + content_rect.x = rect.x - content_rect.x; + content_rect.y = rect.y - content_rect.y; + content_rect.width = rect.width; + content_rect.height = rect.height; + rect.x -= paint->rect.x; + rect.y -= paint->rect.y; + pd_canvas_quote(&dest, &paint->canvas, &rect); + pd_canvas_quote(&src, &canvas->buffer, &content_rect); + pd_canvas_replace(&dest, &src, 0, 0); } static void ui_canvas_context_clear_rect(ui_canvas_context_t *ctx, int x, int y, - int width, int height) + int width, int height) { - pd_rect_t rect; + pd_rect_t rect; - rect.x = x; - rect.y = y; - rect.width = width; - rect.height = height; - pd_canvas_fill_rect(&ctx->buffer, pd_argb(0, 0, 0, 0), rect); + rect.x = x; + rect.y = y; + rect.width = width; + rect.height = height; + pd_canvas_fill_rect(&ctx->buffer, pd_argb(0, 0, 0, 0), rect); } static void ui_canvas_context_fill_rect(ui_canvas_context_t *ctx, int x, int y, - int width, int height) + int width, int height) { - pd_rect_t rect; + pd_rect_t rect; - rect.x = x; - rect.y = y; - rect.width = width; - rect.height = height; - pd_canvas_fill_rect(&ctx->buffer, ctx->fill_color, rect); + rect.x = x; + rect.y = y; + rect.width = width; + rect.height = height; + pd_canvas_fill_rect(&ctx->buffer, ctx->fill_color, rect); } static void ui_canvas_context_release(ui_canvas_context_t *ctx) { - ui_canvas_t *canvas; + ui_canvas_t *canvas; - if (ctx->available) { - canvas = ui_widget_get_data(ctx->canvas, ui_canvas.proto); - list_unlink(&canvas->contexts, &ctx->node); - } - free(ctx); + if (ctx->available) { + canvas = ui_widget_get_data(ctx->canvas, ui_canvas.proto); + list_unlink(&canvas->contexts, &ctx->node); + } + free(ctx); } ui_canvas_context_t *ui_canvas_get_context(ui_widget_t *w) { - ui_canvas_context_t *ctx; - ui_canvas_t *canvas = ui_widget_get_data(w, ui_canvas.proto); - - ctx = malloc(sizeof(ui_canvas_context_t)); - ctx->canvas = w; - ctx->available = true; - ctx->buffer = canvas->buffer; - ctx->width = ctx->buffer.width; - ctx->height = ctx->buffer.height; - ctx->fill_color = pd_rgb(0, 0, 0); - ctx->scale = ui_get_actual_scale(); - ctx->clear_rect = ui_canvas_context_clear_rect; - ctx->fill_rect = ui_canvas_context_fill_rect; - ctx->release = ui_canvas_context_release; - ctx->node.data = ctx; - ctx->node.next = ctx->node.prev = NULL; - list_append_node(&canvas->contexts, &ctx->node); - return ctx; + ui_canvas_context_t *ctx; + ui_canvas_t *canvas = ui_widget_get_data(w, ui_canvas.proto); + + ctx = malloc(sizeof(ui_canvas_context_t)); + ctx->canvas = w; + ctx->available = true; + ctx->buffer = canvas->buffer; + ctx->width = ctx->buffer.width; + ctx->height = ctx->buffer.height; + ctx->fill_color = pd_rgb(0, 0, 0); + ctx->scale = ui_get_actual_scale(); + ctx->clear_rect = ui_canvas_context_clear_rect; + ctx->fill_rect = ui_canvas_context_fill_rect; + ctx->release = ui_canvas_context_release; + ctx->node.data = ctx; + ctx->node.next = ctx->node.prev = NULL; + list_append_node(&canvas->contexts, &ctx->node); + return ctx; } void ui_register_canvas(void) { - ui_canvas.proto = ui_create_widget_prototype("canvas", NULL); - ui_canvas.proto->init = ui_canvas_on_init; - ui_canvas.proto->destroy = ui_canvas_on_destroy; - ui_canvas.proto->paint = ui_canvas_on_paint; - ui_canvas.proto->sizehint = ui_canvas_on_sizehint; - ui_canvas.proto->resize = ui_canvas_on_resize; + ui_canvas.proto = ui_create_widget_prototype("canvas", NULL); + ui_canvas.proto->init = ui_canvas_on_init; + ui_canvas.proto->destroy = ui_canvas_on_destroy; + ui_canvas.proto->paint = ui_canvas_on_paint; + ui_canvas.proto->sizehint = ui_canvas_on_sizehint; + ui_canvas.proto->resize = ui_canvas_on_resize; } diff --git a/src/widgets/scrollarea.c b/src/widgets/scrollarea.c index 3db84b71f..34fe28f6f 100644 --- a/src/widgets/scrollarea.c +++ b/src/widgets/scrollarea.c @@ -1,12 +1,15 @@ /* * src/widgets/scrollarea.c * - * Copyright (c) 2024-2025, Liu Chao All rights reserved. + * Copyright (c) 2024-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include @@ -34,7 +37,7 @@ typedef struct ui_scrollarea_content { static ui_widget_prototype_t *ui_scrollarea_proto; static ui_widget_prototype_t *ui_scrollarea_content_proto; -static const char *ui_scrollarea_css ="\ +static const char *ui_scrollarea_css = "\ scrollarea-content {\ min-width: min-content;\ }"; diff --git a/src/widgets/scrollbar.c b/src/widgets/scrollbar.c index e48b4c218..2a75b9616 100644 --- a/src/widgets/scrollbar.c +++ b/src/widgets/scrollbar.c @@ -1,12 +1,15 @@ /* * src/widgets/scrollbar.c: -- Scrollbar widget * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include diff --git a/src/widgets/text.c b/src/widgets/text.c index 202e7f3dd..156e5fd12 100644 --- a/src/widgets/text.c +++ b/src/widgets/text.c @@ -1,12 +1,15 @@ /* - * src/widgets/text.c: -- TextView widget for display text. - * - * Copyright (c) 2018-2025, Liu chao All rights reserved. + * src/widgets/text.c: -- Text widget for display text. * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include diff --git a/src/widgets/textcaret.c b/src/widgets/textcaret.c index dbd98b22f..f4e7e96d5 100644 --- a/src/widgets/textcaret.c +++ b/src/widgets/textcaret.c @@ -1,12 +1,15 @@ /* * src/widgets/textcaret.c: -- textcaret widget, used in textinput. * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include @@ -100,7 +103,7 @@ static void ui_textcaret_on_init(ui_widget_t *widget) caret->blink_interval = 500; caret->visible = false; caret->timer_id = ptk_set_interval(caret->blink_interval, - ui_textcaret_on_blink, caret->task); + ui_textcaret_on_blink, caret->task); } void ui_textcaret_set_blink_time(ui_widget_t *widget, unsigned int n_ms) diff --git a/src/widgets/textinput.c b/src/widgets/textinput.c index 9595840f0..002c27738 100644 --- a/src/widgets/textinput.c +++ b/src/widgets/textinput.c @@ -1,12 +1,15 @@ /* * src/widgets/textinput.c: -- textinput widget, used to allow user edit * - * Copyright (c) 2018-2025, Liu chao All rights reserved. - * + * Copyright (c) 2018-2026, Liu chao All rights reserved. + + * * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + * This file is part of LCUI, + * distributed under the MIT License found in the + * LICENSE.TXT file in the + * root directory of this source tree. */ #include @@ -158,9 +161,8 @@ static void ui_textinput_update_caret(ui_widget_t *widget) ui_widget_move(edit->caret, x, y); ui_textcaret_refresh(edit->caret); if (edit->password_char) { - pd_text_set_caret(edit->layer_source, - edit->layer->caret.y, - edit->layer->caret.x); + pd_text_set_caret(edit->layer_source, edit->layer->caret.y, + edit->layer->caret.x); } } diff --git a/src/widgets/textstyle.c b/src/widgets/textstyle.c index 0115fc9de..1f7becde5 100644 --- a/src/widgets/textstyle.c +++ b/src/widgets/textstyle.c @@ -1,35 +1,37 @@ /* * src/widgets/textstyle.c * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao + * All rights reserved. * * SPDX-License-Identifier: MIT * - * This file is part of LCUI, distributed under the MIT License found in the - * LICENSE.TXT file in the root directory of this source tree. + + * * This file is part of LCUI, distributed under the MIT License found in the + + * * LICENSE.TXT file in the root directory of this source tree. */ #include "textstyle.h" void convert_font_style_to_text_style(ui_text_style_t *fs, pd_text_style_t *ts) { - size_t len; - ts->font_ids = NULL; - ts->has_style = true; - ts->has_weight = true; - ts->has_family = false; - ts->has_back_color = false; - ts->has_pixel_size = true; - ts->has_fore_color = true; - ts->fore_color = fs->color; - ts->pixel_size = fs->font_size; - ts->weight = fs->font_weight; - ts->style = fs->font_style; - if (fs->font_ids) { - for (len = 0; fs->font_ids[len]; ++len) - ; - ts->font_ids = malloc(sizeof(int) * ++len); - memcpy(ts->font_ids, fs->font_ids, len * sizeof(int)); - ts->has_family = true; - } + size_t len; + ts->font_ids = NULL; + ts->has_style = true; + ts->has_weight = true; + ts->has_family = false; + ts->has_back_color = false; + ts->has_pixel_size = true; + ts->has_fore_color = true; + ts->fore_color = fs->color; + ts->pixel_size = fs->font_size; + ts->weight = fs->font_weight; + ts->style = fs->font_style; + if (fs->font_ids) { + for (len = 0; fs->font_ids[len]; ++len); + ts->font_ids = malloc(sizeof(int) * ++len); + memcpy(ts->font_ids, fs->font_ids, len * sizeof(int)); + ts->has_family = true; + } } diff --git a/src/widgets/textstyle.h b/src/widgets/textstyle.h index f35b8d05a..24a4a83c5 100644 --- a/src/widgets/textstyle.h +++ b/src/widgets/textstyle.h @@ -1,7 +1,7 @@ /* * src/widgets/textstyle.h * - * Copyright (c) 2023-2025, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/helloworld_uwp/pch.h b/tests/helloworld_uwp/pch.h index 0a63d548b..19816775d 100644 --- a/tests/helloworld_uwp/pch.h +++ b/tests/helloworld_uwp/pch.h @@ -1,7 +1,7 @@ /* * tests/helloworld_uwp/pch.h * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) 2023, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/helpers/ctest-custom.h b/tests/helpers/ctest-custom.h index 0ff21c9cf..ef1c744ff 100644 --- a/tests/helpers/ctest-custom.h +++ b/tests/helpers/ctest-custom.h @@ -1,7 +1,7 @@ /* * tests/include/ctest-custom.h * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) 2023, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/integration/test_block_layout.c b/tests/integration/test_block_layout.c index f1bf13539..f2e6ff619 100644 --- a/tests/integration/test_block_layout.c +++ b/tests/integration/test_block_layout.c @@ -1,7 +1,7 @@ /* * tests/cases/test_block_layout.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) 2023, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/integration/test_clipboard.c b/tests/integration/test_clipboard.c index 039887240..1aa9a6e1f 100644 --- a/tests/integration/test_clipboard.c +++ b/tests/integration/test_clipboard.c @@ -1,7 +1,7 @@ /* * tests/cases/test_clipboard.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) 2023, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/integration/test_flex_layout.c b/tests/integration/test_flex_layout.c index 9739d462d..b551ff81c 100644 --- a/tests/integration/test_flex_layout.c +++ b/tests/integration/test_flex_layout.c @@ -1,7 +1,7 @@ /* * tests/cases/test_flex_layout.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) 2023, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/integration/test_font_face.c b/tests/integration/test_font_face.c index 5f621e552..39bf3ea68 100644 --- a/tests/integration/test_font_face.c +++ b/tests/integration/test_font_face.c @@ -1,7 +1,7 @@ /* * tests/cases/test_font_face.c * - * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * @@ -18,7 +18,6 @@ void test_font_face(void) ctest_equal_int("should load CSS file containing @font-face", ui_load_css_file("test_font_face.css"), 0); ctest_equal_bool("should resolve font registered via @font-face", - pd_font_get_id("icomoon", 0, 0) > 0, - true); + pd_font_get_id("icomoon", 0, 0) > 0, true); ui_destroy(); } diff --git a/tests/integration/test_mainloop.c b/tests/integration/test_mainloop.c index b15875230..10b4e03d0 100644 --- a/tests/integration/test_mainloop.c +++ b/tests/integration/test_mainloop.c @@ -1,7 +1,7 @@ /* * tests/cases/test_mainloop.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) 2023, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/integration/test_scrollbar.c b/tests/integration/test_scrollbar.c index c1fc55bb0..2a835d243 100644 --- a/tests/integration/test_scrollbar.c +++ b/tests/integration/test_scrollbar.c @@ -1,7 +1,7 @@ /* * tests/cases/test_scrollbar.c * - * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/integration/test_settings.c b/tests/integration/test_settings.c index c8eed8100..23d09c44c 100644 --- a/tests/integration/test_settings.c +++ b/tests/integration/test_settings.c @@ -1,7 +1,7 @@ /* * tests/cases/test_settings.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) 2023, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/integration/test_text_resize.c b/tests/integration/test_text_resize.c index b77177caa..25e87d999 100644 --- a/tests/integration/test_text_resize.c +++ b/tests/integration/test_text_resize.c @@ -1,7 +1,7 @@ /* * tests/cases/test_text_resize.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) 2023, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/integration/test_textinput.c b/tests/integration/test_textinput.c index 85fba3da2..9a2280262 100644 --- a/tests/integration/test_textinput.c +++ b/tests/integration/test_textinput.c @@ -1,7 +1,7 @@ /* * tests/cases/test_textinput.c * - * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/integration/test_widget_event.c b/tests/integration/test_widget_event.c index 9bb0a1033..300c4add4 100644 --- a/tests/integration/test_widget_event.c +++ b/tests/integration/test_widget_event.c @@ -1,7 +1,7 @@ /* * tests/cases/test_widget_event.c * - * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/integration/test_widget_opacity.c b/tests/integration/test_widget_opacity.c index 835f72697..97f51c9e3 100644 --- a/tests/integration/test_widget_opacity.c +++ b/tests/integration/test_widget_opacity.c @@ -1,7 +1,7 @@ /* * tests/cases/test_widget_opacity.c * - * Copyright (c) 2023-2026, Liu Chao All rights reserved. + * Copyright (c) 2023-2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/integration/test_widget_rect.c b/tests/integration/test_widget_rect.c index ffd458601..4fac0c581 100644 --- a/tests/integration/test_widget_rect.c +++ b/tests/integration/test_widget_rect.c @@ -1,7 +1,7 @@ /* * tests/cases/test_widget_rect.c * - * Copyright (c) 2023, Liu Chao All rights reserved. + * Copyright (c) 2023, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/previews/preview_block_layout.c b/tests/previews/preview_block_layout.c index 140a84bd0..fb4a869b4 100644 --- a/tests/previews/preview_block_layout.c +++ b/tests/previews/preview_block_layout.c @@ -1,7 +1,7 @@ /* * tests/previews/preview_block_layout.c * - * Copyright (c) 2026, Liu Chao All rights reserved. + * Copyright (c) 2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/previews/preview_flex_layout.c b/tests/previews/preview_flex_layout.c index ce3529e4a..bb838f193 100644 --- a/tests/previews/preview_flex_layout.c +++ b/tests/previews/preview_flex_layout.c @@ -1,7 +1,7 @@ /* * tests/previews/preview_flex_layout.c * - * Copyright (c) 2026, Liu Chao All rights reserved. + * Copyright (c) 2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/previews/preview_scrollbar.c b/tests/previews/preview_scrollbar.c index 4e69c55be..17c37473f 100644 --- a/tests/previews/preview_scrollbar.c +++ b/tests/previews/preview_scrollbar.c @@ -1,7 +1,7 @@ /* * tests/previews/preview_scrollbar.c * - * Copyright (c) 2026, Liu Chao All rights reserved. + * Copyright (c) 2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/previews/preview_widget_opacity.c b/tests/previews/preview_widget_opacity.c index ec5cbef7b..0721dba8d 100644 --- a/tests/previews/preview_widget_opacity.c +++ b/tests/previews/preview_widget_opacity.c @@ -1,7 +1,7 @@ /* * tests/previews/preview_widget_opacity.c * - * Copyright (c) 2026, Liu Chao All rights reserved. + * Copyright (c) 2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/scenes/block_layout_scene.c b/tests/scenes/block_layout_scene.c index 0f47f02f4..1f5c2a8c4 100644 --- a/tests/scenes/block_layout_scene.c +++ b/tests/scenes/block_layout_scene.c @@ -1,7 +1,7 @@ /* * tests/scenes/block_layout_scene.c * - * Copyright (c) 2026, Liu Chao All rights reserved. + * Copyright (c) 2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/scenes/block_layout_scene.h b/tests/scenes/block_layout_scene.h index 054f3bcd5..ff2431684 100644 --- a/tests/scenes/block_layout_scene.h +++ b/tests/scenes/block_layout_scene.h @@ -1,7 +1,7 @@ /* * tests/scenes/block_layout_scene.h * - * Copyright (c) 2026, Liu Chao All rights reserved. + * Copyright (c) 2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/scenes/flex_layout_scene.c b/tests/scenes/flex_layout_scene.c index fe7ee92c8..c7a79a820 100644 --- a/tests/scenes/flex_layout_scene.c +++ b/tests/scenes/flex_layout_scene.c @@ -1,7 +1,7 @@ /* * tests/scenes/flex_layout_scene.c * - * Copyright (c) 2026, Liu Chao All rights reserved. + * Copyright (c) 2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/scenes/flex_layout_scene.h b/tests/scenes/flex_layout_scene.h index 805c9b140..edb6b4d3d 100644 --- a/tests/scenes/flex_layout_scene.h +++ b/tests/scenes/flex_layout_scene.h @@ -1,7 +1,7 @@ /* * tests/scenes/flex_layout_scene.h * - * Copyright (c) 2026, Liu Chao All rights reserved. + * Copyright (c) 2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/scenes/scrollbar_scene.c b/tests/scenes/scrollbar_scene.c index 9ee81f61c..290e1d23e 100644 --- a/tests/scenes/scrollbar_scene.c +++ b/tests/scenes/scrollbar_scene.c @@ -1,7 +1,7 @@ /* * tests/scenes/scrollbar_scene.c * - * Copyright (c) 2026, Liu Chao All rights reserved. + * Copyright (c) 2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/scenes/scrollbar_scene.h b/tests/scenes/scrollbar_scene.h index 46e0f6e94..d9683ca36 100644 --- a/tests/scenes/scrollbar_scene.h +++ b/tests/scenes/scrollbar_scene.h @@ -1,7 +1,7 @@ /* * tests/scenes/scrollbar_scene.h * - * Copyright (c) 2026, Liu Chao All rights reserved. + * Copyright (c) 2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/scenes/widget_opacity_scene.c b/tests/scenes/widget_opacity_scene.c index 4f8053d92..bfe485482 100644 --- a/tests/scenes/widget_opacity_scene.c +++ b/tests/scenes/widget_opacity_scene.c @@ -1,7 +1,7 @@ /* * tests/scenes/widget_opacity_scene.c * - * Copyright (c) 2026, Liu Chao All rights reserved. + * Copyright (c) 2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/tests/scenes/widget_opacity_scene.h b/tests/scenes/widget_opacity_scene.h index efab51b26..bdbb0915a 100644 --- a/tests/scenes/widget_opacity_scene.h +++ b/tests/scenes/widget_opacity_scene.h @@ -1,7 +1,7 @@ /* * tests/scenes/widget_opacity_scene.h * - * Copyright (c) 2026, Liu Chao All rights reserved. + * Copyright (c) 2026, Liu Chao All rights reserved. * * SPDX-License-Identifier: MIT * diff --git a/xmake-requires.lock b/xmake-requires.lock index f7674df84..21c0278d3 100644 --- a/xmake-requires.lock +++ b/xmake-requires.lock @@ -237,6 +237,14 @@ } }, ["windows|x64"] = { + ["cairo#31fecfc4"] = { + repo = { + branch = "master", + commit = "c406b5487b71cbbdd7487b432e2d962409663cbe", + url = "https://gitee.com/tboox/xmake-repo.git" + }, + version = "1.18.0" + }, ["cmake#31fecfc4"] = { repo = { branch = "master", @@ -245,7 +253,23 @@ }, version = "3.30.5-msvc23" }, - ["freetype#8cb27d06"] = { + ["expat#31fecfc4"] = { + repo = { + branch = "master", + commit = "c406b5487b71cbbdd7487b432e2d962409663cbe", + url = "https://gitee.com/tboox/xmake-repo.git" + }, + version = "2.7.1" + }, + ["fontconfig#31fecfc4"] = { + repo = { + branch = "master", + commit = "c406b5487b71cbbdd7487b432e2d962409663cbe", + url = "https://gitee.com/tboox/xmake-repo.git" + }, + version = "2.14.2" + }, + ["freetype#31fecfc4"] = { repo = { branch = "master", commit = "c406b5487b71cbbdd7487b432e2d962409663cbe", @@ -253,6 +277,22 @@ }, version = "2.13.3" }, + ["gperf#31fecfc4"] = { + repo = { + branch = "master", + commit = "c406b5487b71cbbdd7487b432e2d962409663cbe", + url = "https://gitee.com/tboox/xmake-repo.git" + }, + version = "3.2.1" + }, + ["libintl#31fecfc4"] = { + repo = { + branch = "master", + commit = "c406b5487b71cbbdd7487b432e2d962409663cbe", + url = "https://gitee.com/tboox/xmake-repo.git" + }, + version = "0.22.3" + }, ["libjpeg#31fecfc4"] = { repo = { branch = "master", @@ -309,6 +349,14 @@ }, version = "1.12.1" }, + ["pixman#31fecfc4"] = { + repo = { + branch = "master", + commit = "c406b5487b71cbbdd7487b432e2d962409663cbe", + url = "https://gitee.com/tboox/xmake-repo.git" + }, + version = "0.46.2" + }, ["pkgconf#31fecfc4"] = { repo = { branch = "master", From 4a3d190a947a29cef30f0dbe8a195ae261d81280 Mon Sep 17 00:00:00 2001 From: Liu Date: Sun, 21 Jun 2026 14:41:22 +0800 Subject: [PATCH 40/66] fix(widgets): ceil text bbox size to avoid rounding precision loss MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Floating point truncation during cbox↔bbox round-trip conversion caused accumulated error, e.g. 57.3333321 → 57.3333282, resulting in unexpected line wrap. Using ceil() prevents value shrinkage and ensures stable text layout. --- src/widgets/text.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/widgets/text.c b/src/widgets/text.c index 156e5fd12..bd924f972 100644 --- a/src/widgets/text.c +++ b/src/widgets/text.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -203,9 +204,10 @@ static void ui_text_on_sizehint(ui_widget_t *w, ui_sizehint_t *hint) pd_text_set_max_size(txt->layer, ui_compute(max_width), ui_compute(max_height)); pd_text_update(txt->layer, &rects); - hint->max_width = pd_text_get_width(txt->layer) / ui_get_actual_scale(); + hint->max_width = + ceilf(pd_text_get_width(txt->layer) / ui_get_actual_scale()); hint->max_height = - pd_text_get_height(txt->layer) / ui_get_actual_scale(); + ceilf(pd_text_get_height(txt->layer) / ui_get_actual_scale()); pd_rects_clear(&rects); if (!txt->layer->autowrap_enabled) { hint->min_width = hint->max_width; From 69a3ab3f6132ea09cd1d4fd649ceebdd8a1abb11 Mon Sep 17 00:00:00 2001 From: Liu Date: Wed, 17 Jun 2026 00:22:05 +0800 Subject: [PATCH 41/66] feat(settings): add custom string settings API Expose lcui_settings_get_string / lcui_settings_set_string for reading and writing custom [section] key-value pairs. Writes mark the settings dirty; persistence requires a subsequent lcui_settings_flush() call. --- include/LCUI/settings/base.h | 10 ++++++++++ src/lcui_settings.c | 27 +++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/include/LCUI/settings/base.h b/include/LCUI/settings/base.h index 90442310a..b69342245 100644 --- a/include/LCUI/settings/base.h +++ b/include/LCUI/settings/base.h @@ -25,6 +25,16 @@ LCUI_API bool lcui_settings_load(void); LCUI_API bool lcui_settings_flush(void); LCUI_API void lcui_settings_unload(void); +/* Read / write a custom string setting under [section]. `section` + * and `key` must be ASCII. Returns true on read if the key exists + * (the caller owns the returned string). Returns true on write if + * the value was stored (the setting is not persisted until the next + * call to lcui_settings_flush()). */ +LCUI_API bool lcui_settings_get_string(const char *section, const char *key, + char **out); +LCUI_API bool lcui_settings_set_string(const char *section, const char *key, + const char *value); + LCUI_END_HEADER #endif diff --git a/src/lcui_settings.c b/src/lcui_settings.c index 3ef0d78e8..6bbeb4d1b 100644 --- a/src/lcui_settings.c +++ b/src/lcui_settings.c @@ -1,9 +1,7 @@ /* - * src/lcui_settings.c: -- global settings infrastructure. + * src/lcui_settings.c -- global settings infrastructure. * - * Copyright (c) 2020, James Duong - * Copyright (c) - * 2023-2026, Liu Chao + * Copyright (c) 2023-2026, Liu Chao * All rights reserved. * * @@ -413,3 +411,24 @@ void lcui_settings_unload(void) lcui_settings.loaded = false; lcui_settings.dirty = false; } + +bool lcui_settings_get_string(const char *section, const char *key, char **out) +{ + if (!lcui_settings.loaded || !lcui_settings.doc) { + return false; + } + return ini_doc_get_string(lcui_settings.doc, section, key, out); +} + +bool lcui_settings_set_string(const char *section, const char *key, + const char *value) +{ + if (!lcui_settings.loaded || !lcui_settings.doc) { + return false; + } + if (!ini_doc_set_string(lcui_settings.doc, section, key, value)) { + return false; + } + lcui_settings.dirty = true; + return true; +} From b8642c99527dbef34c36c889777411682fa60dfb Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Jun 2026 22:37:32 +0800 Subject: [PATCH 42/66] docs: add native doc-viewer and widget documentation (#324) - Add examples/doc-viewer, an LCUI-based documentation viewer with an MDX compiler pipeline that converts source MDX files into C/TSX page components rendered by lcui build. - Add zh-CN and en documentation for 5 widgets (anchor, button, scrollarea, text, text-input), each with C/TSX/XML example variants and widget-fields data. - Add handbook and overview documentation. Co-authored-by: Liu --- .github/workflows/ccpp.yml | 50 +- .gitignore | 3 +- AGENTS.md | 25 + docs/en/devtools/css-modules.mdx | 29 + docs/en/devtools/icon-library.mdx | 29 + docs/en/devtools/sass.mdx | 15 + docs/en/devtools/tailwind-css.mdx | 31 + docs/en/devtools/tsx-and-dev-tools.mdx | 201 ++ docs/en/handbook/customization.mdx | 136 ++ docs/en/handbook/styling.mdx | 151 ++ docs/en/overview/about.mdx | 59 + docs/en/overview/quick-start.mdx | 44 + docs/en/widgets/anchor.mdx | 50 + docs/en/widgets/button.mdx | 25 + docs/en/widgets/scrollarea.mdx | 103 + docs/en/widgets/text-input.mdx | 128 ++ docs/en/widgets/text.mdx | 63 + docs/examples/anchor-basic-tsx/example.tsx | 5 + docs/examples/anchor-basic-tsx/main.c | 10 + docs/examples/anchor-basic-xml/main.c | 10 + docs/examples/anchor-basic-xml/ui.xml | 6 + docs/examples/anchor-basic/main.c | 11 + docs/examples/button-basic-tsx/example.tsx | 5 + docs/examples/button-basic-tsx/main.c | 12 + docs/examples/button-basic-xml/main.c | 10 + docs/examples/button-basic-xml/ui.xml | 6 + docs/examples/button-basic/main.c | 11 + .../examples/scrollarea-basic-tsx/example.css | 5 + .../examples/scrollarea-basic-tsx/example.tsx | 20 + docs/examples/scrollarea-basic-tsx/main.c | 10 + docs/examples/scrollarea-basic-xml/main.c | 10 + docs/examples/scrollarea-basic-xml/ui.xml | 17 + docs/examples/scrollarea-basic/main.c | 31 + .../example.css | 23 + .../example.tsx | 18 + .../scrollarea-dual-scrollbars-tsx/main.c | 10 + .../scrollarea-dual-scrollbars-xml/main.c | 10 + .../scrollarea-dual-scrollbars-xml/ui.xml | 44 + .../scrollarea-dual-scrollbars/main.c | 45 + docs/examples/text-basic-tsx/example.tsx | 5 + docs/examples/text-basic-tsx/main.c | 10 + docs/examples/text-basic-xml/main.c | 10 + docs/examples/text-basic-xml/ui.xml | 6 + docs/examples/text-basic/main.c | 11 + .../examples/text-input-basic-tsx/example.tsx | 5 + docs/examples/text-input-basic-tsx/main.c | 10 + docs/examples/text-input-basic-xml/main.c | 10 + docs/examples/text-input-basic-xml/ui.xml | 6 + docs/examples/text-input-basic/main.c | 10 + docs/sidebars.json | 42 + docs/widget-fields/anchor.ts | 14 + docs/widget-fields/button.ts | 14 + docs/widget-fields/scrollarea-content.ts | 3 + docs/widget-fields/scrollarea.ts | 3 + docs/widget-fields/scrollbar.ts | 14 + docs/widget-fields/text-input.ts | 14 + docs/widget-fields/text.ts | 3 + docs/widget-fields/widget.ts | 27 + docs/zh-CN/devtools/css-modules.mdx | 29 + docs/zh-CN/devtools/icon-library.mdx | 29 + docs/zh-CN/devtools/sass.mdx | 15 + docs/zh-CN/devtools/tailwind-css.mdx | 31 + docs/zh-CN/devtools/tsx-and-dev-tools.mdx | 201 ++ docs/zh-CN/handbook/customization.mdx | 136 ++ docs/zh-CN/handbook/styling.mdx | 151 ++ docs/zh-CN/overview/about.mdx | 59 + docs/zh-CN/overview/quick-start.mdx | 44 + docs/zh-CN/widgets/anchor.mdx | 14 + docs/zh-CN/widgets/button.mdx | 25 + docs/zh-CN/widgets/scrollarea.mdx | 53 + docs/zh-CN/widgets/text-input.mdx | 24 + docs/zh-CN/widgets/text.mdx | 24 + examples/doc-viewer/.gitignore | 19 + examples/doc-viewer/AGENTS.md | 208 ++ .../app/components/code-block-copy.c | 123 ++ .../app/components/code-block-copy.h | 9 + .../app/components/code-block-copy.tsx | 14 + .../doc-viewer/app/components/demo-provider.c | 226 ++ .../doc-viewer/app/components/demo-provider.h | 9 + .../app/components/demo-provider.tsx | 41 + .../doc-viewer/app/components/field-table.c | 60 + .../doc-viewer/app/components/field-table.css | 77 + .../doc-viewer/app/components/field-table.h | 4 + .../doc-viewer/app/components/field-table.tsx | 102 + examples/doc-viewer/app/components/list.c | 169 ++ examples/doc-viewer/app/components/list.h | 11 + examples/doc-viewer/app/components/navbar.c | 229 +++ examples/doc-viewer/app/components/navbar.css | 51 + examples/doc-viewer/app/components/navbar.h | 9 + examples/doc-viewer/app/components/navbar.tsx | 38 + examples/doc-viewer/app/components/sidebar.c | 52 + .../doc-viewer/app/components/sidebar.css | 52 + examples/doc-viewer/app/components/sidebar.h | 9 + .../doc-viewer/app/components/sidebar.json | 42 + .../doc-viewer/app/components/sidebar.tsx | 47 + .../app/en/devtools/css-modules/page.c | 57 + .../app/en/devtools/css-modules/page.h | 9 + .../app/en/devtools/css-modules/page.tsx | 49 + .../app/en/devtools/icon-library/page.c | 57 + .../app/en/devtools/icon-library/page.h | 9 + .../app/en/devtools/icon-library/page.tsx | 52 + .../doc-viewer/app/en/devtools/sass/page.c | 53 + .../doc-viewer/app/en/devtools/sass/page.h | 9 + .../doc-viewer/app/en/devtools/sass/page.tsx | 26 + .../app/en/devtools/tailwind-css/page.c | 57 + .../app/en/devtools/tailwind-css/page.h | 9 + .../app/en/devtools/tailwind-css/page.tsx | 51 + .../app/en/devtools/tsx-and-dev-tools/page.c | 57 + .../app/en/devtools/tsx-and-dev-tools/page.h | 9 + .../en/devtools/tsx-and-dev-tools/page.tsx | 260 +++ .../app/en/handbook/composition/page.c | 56 + .../app/en/handbook/composition/page.h | 9 + .../app/en/handbook/composition/page.tsx | 238 +++ .../app/en/handbook/css-modules/page.c | 57 + .../app/en/handbook/css-modules/page.h | 9 + .../app/en/handbook/css-modules/page.tsx | 49 + .../app/en/handbook/customization/page.c | 56 + .../app/en/handbook/customization/page.h | 9 + .../app/en/handbook/customization/page.tsx | 173 ++ .../app/en/handbook/icon-library/page.c | 57 + .../app/en/handbook/icon-library/page.h | 9 + .../app/en/handbook/icon-library/page.tsx | 52 + .../doc-viewer/app/en/handbook/sass/page.c | 53 + .../doc-viewer/app/en/handbook/sass/page.h | 9 + .../doc-viewer/app/en/handbook/sass/page.tsx | 26 + .../doc-viewer/app/en/handbook/styling/page.c | 53 + .../doc-viewer/app/en/handbook/styling/page.h | 9 + .../app/en/handbook/styling/page.tsx | 183 ++ .../app/en/handbook/tailwind-css/page.c | 57 + .../app/en/handbook/tailwind-css/page.h | 9 + .../app/en/handbook/tailwind-css/page.tsx | 51 + .../app/en/handbook/tsx-and-dev-tools/page.c | 57 + .../app/en/handbook/tsx-and-dev-tools/page.h | 9 + .../en/handbook/tsx-and-dev-tools/page.tsx | 260 +++ .../app/en/handbook/typescript/page.c | 56 + .../app/en/handbook/typescript/page.h | 9 + .../app/en/handbook/typescript/page.tsx | 192 ++ .../doc-viewer/app/en/overview/about/page.c | 52 + .../doc-viewer/app/en/overview/about/page.h | 9 + .../doc-viewer/app/en/overview/about/page.tsx | 61 + .../app/en/overview/quick-start/page.c | 56 + .../app/en/overview/quick-start/page.h | 9 + .../app/en/overview/quick-start/page.tsx | 65 + .../doc-viewer/app/en/widgets/anchor/page.c | 52 + .../doc-viewer/app/en/widgets/anchor/page.h | 9 + .../doc-viewer/app/en/widgets/anchor/page.tsx | 111 + .../doc-viewer/app/en/widgets/button/page.c | 52 + .../doc-viewer/app/en/widgets/button/page.h | 9 + .../doc-viewer/app/en/widgets/button/page.tsx | 42 + .../app/en/widgets/scrollarea/page.c | 56 + .../app/en/widgets/scrollarea/page.h | 9 + .../app/en/widgets/scrollarea/page.tsx | 175 ++ .../app/en/widgets/text-input/page.c | 56 + .../app/en/widgets/text-input/page.h | 9 + .../app/en/widgets/text-input/page.tsx | 215 ++ .../doc-viewer/app/en/widgets/text/page.c | 52 + .../doc-viewer/app/en/widgets/text/page.h | 9 + .../doc-viewer/app/en/widgets/text/page.tsx | 152 ++ .../app/examples/anchor-basic/index.c | 51 + .../app/examples/anchor-basic/index.tsx | 84 + .../app/examples/button-basic/index.c | 45 + .../app/examples/button-basic/index.tsx | 86 + .../app/examples/scrollarea-basic/index.c | 45 + .../app/examples/scrollarea-basic/index.tsx | 139 ++ .../scrollarea-dual-scrollbars/index.c | 45 + .../scrollarea-dual-scrollbars/index.tsx | 196 ++ .../app/examples/text-basic/index.c | 45 + .../app/examples/text-basic/index.tsx | 84 + .../app/examples/text-input-basic/index.c | 45 + .../app/examples/text-input-basic/index.tsx | 83 + examples/doc-viewer/app/global.css | 267 +++ examples/doc-viewer/app/layout.c | 51 + examples/doc-viewer/app/layout.h | 9 + examples/doc-viewer/app/layout.tsx | 20 + examples/doc-viewer/app/locale.c | 119 ++ examples/doc-viewer/app/locale.h | 27 + examples/doc-viewer/app/main.c | 62 + .../doc-viewer/app/widget-fields/anchor.ts | 14 + .../doc-viewer/app/widget-fields/button.ts | 14 + .../app/widget-fields/scrollarea-content.ts | 3 + .../app/widget-fields/scrollarea.ts | 3 + .../doc-viewer/app/widget-fields/scrollbar.ts | 14 + .../app/widget-fields/text-input.ts | 14 + examples/doc-viewer/app/widget-fields/text.ts | 3 + .../doc-viewer/app/widget-fields/widget.ts | 27 + .../app/zh-CN/devtools/css-modules/page.c | 57 + .../app/zh-CN/devtools/css-modules/page.h | 9 + .../app/zh-CN/devtools/css-modules/page.tsx | 49 + .../app/zh-CN/devtools/icon-library/page.c | 57 + .../app/zh-CN/devtools/icon-library/page.h | 9 + .../app/zh-CN/devtools/icon-library/page.tsx | 52 + .../doc-viewer/app/zh-CN/devtools/sass/page.c | 54 + .../doc-viewer/app/zh-CN/devtools/sass/page.h | 9 + .../app/zh-CN/devtools/sass/page.tsx | 26 + .../app/zh-CN/devtools/tailwind-css/page.c | 57 + .../app/zh-CN/devtools/tailwind-css/page.h | 9 + .../app/zh-CN/devtools/tailwind-css/page.tsx | 51 + .../zh-CN/devtools/tsx-and-dev-tools/page.c | 58 + .../zh-CN/devtools/tsx-and-dev-tools/page.h | 9 + .../zh-CN/devtools/tsx-and-dev-tools/page.tsx | 260 +++ .../app/zh-CN/handbook/composition/page.c | 56 + .../app/zh-CN/handbook/composition/page.h | 9 + .../app/zh-CN/handbook/composition/page.tsx | 213 ++ .../app/zh-CN/handbook/css-modules/page.c | 57 + .../app/zh-CN/handbook/css-modules/page.h | 9 + .../app/zh-CN/handbook/css-modules/page.tsx | 49 + .../app/zh-CN/handbook/customization/page.c | 56 + .../app/zh-CN/handbook/customization/page.h | 9 + .../app/zh-CN/handbook/customization/page.tsx | 173 ++ .../app/zh-CN/handbook/icon-library/page.c | 57 + .../app/zh-CN/handbook/icon-library/page.h | 9 + .../app/zh-CN/handbook/icon-library/page.tsx | 52 + .../doc-viewer/app/zh-CN/handbook/sass/page.c | 54 + .../doc-viewer/app/zh-CN/handbook/sass/page.h | 9 + .../app/zh-CN/handbook/sass/page.tsx | 26 + .../app/zh-CN/handbook/styling/page.c | 56 + .../app/zh-CN/handbook/styling/page.h | 9 + .../app/zh-CN/handbook/styling/page.tsx | 183 ++ .../app/zh-CN/handbook/tailwind-css/page.c | 57 + .../app/zh-CN/handbook/tailwind-css/page.h | 9 + .../app/zh-CN/handbook/tailwind-css/page.tsx | 51 + .../zh-CN/handbook/tsx-and-dev-tools/page.c | 58 + .../zh-CN/handbook/tsx-and-dev-tools/page.h | 9 + .../zh-CN/handbook/tsx-and-dev-tools/page.tsx | 260 +++ .../app/zh-CN/handbook/typescript/page.c | 56 + .../app/zh-CN/handbook/typescript/page.h | 9 + .../app/zh-CN/handbook/typescript/page.tsx | 379 ++++ .../app/zh-CN/overview/about/page.c | 54 + .../app/zh-CN/overview/about/page.h | 9 + .../app/zh-CN/overview/about/page.tsx | 61 + .../app/zh-CN/overview/quick-start/page.c | 56 + .../app/zh-CN/overview/quick-start/page.h | 9 + .../app/zh-CN/overview/quick-start/page.tsx | 65 + .../app/zh-CN/widgets/anchor/page.c | 54 + .../app/zh-CN/widgets/anchor/page.h | 9 + .../app/zh-CN/widgets/anchor/page.tsx | 26 + .../app/zh-CN/widgets/button/page.c | 54 + .../app/zh-CN/widgets/button/page.h | 9 + .../app/zh-CN/widgets/button/page.tsx | 42 + .../app/zh-CN/widgets/scrollarea/page.c | 56 + .../app/zh-CN/widgets/scrollarea/page.h | 9 + .../app/zh-CN/widgets/scrollarea/page.tsx | 63 + .../app/zh-CN/widgets/text-input/page.c | 56 + .../app/zh-CN/widgets/text-input/page.h | 9 + .../app/zh-CN/widgets/text-input/page.tsx | 41 + .../doc-viewer/app/zh-CN/widgets/text/page.c | 53 + .../doc-viewer/app/zh-CN/widgets/text/page.h | 9 + .../app/zh-CN/widgets/text/page.tsx | 41 + examples/doc-viewer/bun.lock | 209 ++ examples/doc-viewer/env.d.ts | 1 + examples/doc-viewer/package-lock.json | 1832 +++++++++++++++++ examples/doc-viewer/package.json | 27 + examples/doc-viewer/postcss.config.js | 6 + .../scripts/compiler/css-extractor.ts | 94 + .../scripts/compiler/example-compiler.ts | 186 ++ examples/doc-viewer/scripts/compiler/index.ts | 218 ++ .../doc-viewer/scripts/compiler/mdx-parser.ts | 276 +++ .../scripts/compiler/page-generator.ts | 1248 +++++++++++ .../scripts/compiler/style-tag-renderer.ts | 212 ++ .../doc-viewer/scripts/compiler/tsconfig.json | 13 + examples/doc-viewer/tailwind.config.js | 38 + examples/doc-viewer/tsconfig.json | 13 + examples/doc-viewer/xmake.lua | 10 + examples/fabric/xmake.lua | 6 +- examples/hello/xmake.lua | 7 +- examples/todolist/xmake.lua | 7 +- examples/xmake.lua | 6 +- xmake.lua | 1 + 268 files changed, 17452 insertions(+), 33 deletions(-) create mode 100644 docs/en/devtools/css-modules.mdx create mode 100644 docs/en/devtools/icon-library.mdx create mode 100644 docs/en/devtools/sass.mdx create mode 100644 docs/en/devtools/tailwind-css.mdx create mode 100644 docs/en/devtools/tsx-and-dev-tools.mdx create mode 100644 docs/en/handbook/customization.mdx create mode 100644 docs/en/handbook/styling.mdx create mode 100644 docs/en/overview/about.mdx create mode 100644 docs/en/overview/quick-start.mdx create mode 100644 docs/en/widgets/anchor.mdx create mode 100644 docs/en/widgets/button.mdx create mode 100644 docs/en/widgets/scrollarea.mdx create mode 100644 docs/en/widgets/text-input.mdx create mode 100644 docs/en/widgets/text.mdx create mode 100644 docs/examples/anchor-basic-tsx/example.tsx create mode 100644 docs/examples/anchor-basic-tsx/main.c create mode 100644 docs/examples/anchor-basic-xml/main.c create mode 100644 docs/examples/anchor-basic-xml/ui.xml create mode 100644 docs/examples/anchor-basic/main.c create mode 100644 docs/examples/button-basic-tsx/example.tsx create mode 100644 docs/examples/button-basic-tsx/main.c create mode 100644 docs/examples/button-basic-xml/main.c create mode 100644 docs/examples/button-basic-xml/ui.xml create mode 100644 docs/examples/button-basic/main.c create mode 100644 docs/examples/scrollarea-basic-tsx/example.css create mode 100644 docs/examples/scrollarea-basic-tsx/example.tsx create mode 100644 docs/examples/scrollarea-basic-tsx/main.c create mode 100644 docs/examples/scrollarea-basic-xml/main.c create mode 100644 docs/examples/scrollarea-basic-xml/ui.xml create mode 100644 docs/examples/scrollarea-basic/main.c create mode 100644 docs/examples/scrollarea-dual-scrollbars-tsx/example.css create mode 100644 docs/examples/scrollarea-dual-scrollbars-tsx/example.tsx create mode 100644 docs/examples/scrollarea-dual-scrollbars-tsx/main.c create mode 100644 docs/examples/scrollarea-dual-scrollbars-xml/main.c create mode 100644 docs/examples/scrollarea-dual-scrollbars-xml/ui.xml create mode 100644 docs/examples/scrollarea-dual-scrollbars/main.c create mode 100644 docs/examples/text-basic-tsx/example.tsx create mode 100644 docs/examples/text-basic-tsx/main.c create mode 100644 docs/examples/text-basic-xml/main.c create mode 100644 docs/examples/text-basic-xml/ui.xml create mode 100644 docs/examples/text-basic/main.c create mode 100644 docs/examples/text-input-basic-tsx/example.tsx create mode 100644 docs/examples/text-input-basic-tsx/main.c create mode 100644 docs/examples/text-input-basic-xml/main.c create mode 100644 docs/examples/text-input-basic-xml/ui.xml create mode 100644 docs/examples/text-input-basic/main.c create mode 100644 docs/sidebars.json create mode 100644 docs/widget-fields/anchor.ts create mode 100644 docs/widget-fields/button.ts create mode 100644 docs/widget-fields/scrollarea-content.ts create mode 100644 docs/widget-fields/scrollarea.ts create mode 100644 docs/widget-fields/scrollbar.ts create mode 100644 docs/widget-fields/text-input.ts create mode 100644 docs/widget-fields/text.ts create mode 100644 docs/widget-fields/widget.ts create mode 100644 docs/zh-CN/devtools/css-modules.mdx create mode 100644 docs/zh-CN/devtools/icon-library.mdx create mode 100644 docs/zh-CN/devtools/sass.mdx create mode 100644 docs/zh-CN/devtools/tailwind-css.mdx create mode 100644 docs/zh-CN/devtools/tsx-and-dev-tools.mdx create mode 100644 docs/zh-CN/handbook/customization.mdx create mode 100644 docs/zh-CN/handbook/styling.mdx create mode 100644 docs/zh-CN/overview/about.mdx create mode 100644 docs/zh-CN/overview/quick-start.mdx create mode 100644 docs/zh-CN/widgets/anchor.mdx create mode 100644 docs/zh-CN/widgets/button.mdx create mode 100644 docs/zh-CN/widgets/scrollarea.mdx create mode 100644 docs/zh-CN/widgets/text-input.mdx create mode 100644 docs/zh-CN/widgets/text.mdx create mode 100644 examples/doc-viewer/.gitignore create mode 100644 examples/doc-viewer/AGENTS.md create mode 100644 examples/doc-viewer/app/components/code-block-copy.c create mode 100644 examples/doc-viewer/app/components/code-block-copy.h create mode 100644 examples/doc-viewer/app/components/code-block-copy.tsx create mode 100644 examples/doc-viewer/app/components/demo-provider.c create mode 100644 examples/doc-viewer/app/components/demo-provider.h create mode 100644 examples/doc-viewer/app/components/demo-provider.tsx create mode 100644 examples/doc-viewer/app/components/field-table.c create mode 100644 examples/doc-viewer/app/components/field-table.css create mode 100644 examples/doc-viewer/app/components/field-table.h create mode 100644 examples/doc-viewer/app/components/field-table.tsx create mode 100644 examples/doc-viewer/app/components/list.c create mode 100644 examples/doc-viewer/app/components/list.h create mode 100644 examples/doc-viewer/app/components/navbar.c create mode 100644 examples/doc-viewer/app/components/navbar.css create mode 100644 examples/doc-viewer/app/components/navbar.h create mode 100644 examples/doc-viewer/app/components/navbar.tsx create mode 100644 examples/doc-viewer/app/components/sidebar.c create mode 100644 examples/doc-viewer/app/components/sidebar.css create mode 100644 examples/doc-viewer/app/components/sidebar.h create mode 100644 examples/doc-viewer/app/components/sidebar.json create mode 100644 examples/doc-viewer/app/components/sidebar.tsx create mode 100644 examples/doc-viewer/app/en/devtools/css-modules/page.c create mode 100644 examples/doc-viewer/app/en/devtools/css-modules/page.h create mode 100644 examples/doc-viewer/app/en/devtools/css-modules/page.tsx create mode 100644 examples/doc-viewer/app/en/devtools/icon-library/page.c create mode 100644 examples/doc-viewer/app/en/devtools/icon-library/page.h create mode 100644 examples/doc-viewer/app/en/devtools/icon-library/page.tsx create mode 100644 examples/doc-viewer/app/en/devtools/sass/page.c create mode 100644 examples/doc-viewer/app/en/devtools/sass/page.h create mode 100644 examples/doc-viewer/app/en/devtools/sass/page.tsx create mode 100644 examples/doc-viewer/app/en/devtools/tailwind-css/page.c create mode 100644 examples/doc-viewer/app/en/devtools/tailwind-css/page.h create mode 100644 examples/doc-viewer/app/en/devtools/tailwind-css/page.tsx create mode 100644 examples/doc-viewer/app/en/devtools/tsx-and-dev-tools/page.c create mode 100644 examples/doc-viewer/app/en/devtools/tsx-and-dev-tools/page.h create mode 100644 examples/doc-viewer/app/en/devtools/tsx-and-dev-tools/page.tsx create mode 100644 examples/doc-viewer/app/en/handbook/composition/page.c create mode 100644 examples/doc-viewer/app/en/handbook/composition/page.h create mode 100644 examples/doc-viewer/app/en/handbook/composition/page.tsx create mode 100644 examples/doc-viewer/app/en/handbook/css-modules/page.c create mode 100644 examples/doc-viewer/app/en/handbook/css-modules/page.h create mode 100644 examples/doc-viewer/app/en/handbook/css-modules/page.tsx create mode 100644 examples/doc-viewer/app/en/handbook/customization/page.c create mode 100644 examples/doc-viewer/app/en/handbook/customization/page.h create mode 100644 examples/doc-viewer/app/en/handbook/customization/page.tsx create mode 100644 examples/doc-viewer/app/en/handbook/icon-library/page.c create mode 100644 examples/doc-viewer/app/en/handbook/icon-library/page.h create mode 100644 examples/doc-viewer/app/en/handbook/icon-library/page.tsx create mode 100644 examples/doc-viewer/app/en/handbook/sass/page.c create mode 100644 examples/doc-viewer/app/en/handbook/sass/page.h create mode 100644 examples/doc-viewer/app/en/handbook/sass/page.tsx create mode 100644 examples/doc-viewer/app/en/handbook/styling/page.c create mode 100644 examples/doc-viewer/app/en/handbook/styling/page.h create mode 100644 examples/doc-viewer/app/en/handbook/styling/page.tsx create mode 100644 examples/doc-viewer/app/en/handbook/tailwind-css/page.c create mode 100644 examples/doc-viewer/app/en/handbook/tailwind-css/page.h create mode 100644 examples/doc-viewer/app/en/handbook/tailwind-css/page.tsx create mode 100644 examples/doc-viewer/app/en/handbook/tsx-and-dev-tools/page.c create mode 100644 examples/doc-viewer/app/en/handbook/tsx-and-dev-tools/page.h create mode 100644 examples/doc-viewer/app/en/handbook/tsx-and-dev-tools/page.tsx create mode 100644 examples/doc-viewer/app/en/handbook/typescript/page.c create mode 100644 examples/doc-viewer/app/en/handbook/typescript/page.h create mode 100644 examples/doc-viewer/app/en/handbook/typescript/page.tsx create mode 100644 examples/doc-viewer/app/en/overview/about/page.c create mode 100644 examples/doc-viewer/app/en/overview/about/page.h create mode 100644 examples/doc-viewer/app/en/overview/about/page.tsx create mode 100644 examples/doc-viewer/app/en/overview/quick-start/page.c create mode 100644 examples/doc-viewer/app/en/overview/quick-start/page.h create mode 100644 examples/doc-viewer/app/en/overview/quick-start/page.tsx create mode 100644 examples/doc-viewer/app/en/widgets/anchor/page.c create mode 100644 examples/doc-viewer/app/en/widgets/anchor/page.h create mode 100644 examples/doc-viewer/app/en/widgets/anchor/page.tsx create mode 100644 examples/doc-viewer/app/en/widgets/button/page.c create mode 100644 examples/doc-viewer/app/en/widgets/button/page.h create mode 100644 examples/doc-viewer/app/en/widgets/button/page.tsx create mode 100644 examples/doc-viewer/app/en/widgets/scrollarea/page.c create mode 100644 examples/doc-viewer/app/en/widgets/scrollarea/page.h create mode 100644 examples/doc-viewer/app/en/widgets/scrollarea/page.tsx create mode 100644 examples/doc-viewer/app/en/widgets/text-input/page.c create mode 100644 examples/doc-viewer/app/en/widgets/text-input/page.h create mode 100644 examples/doc-viewer/app/en/widgets/text-input/page.tsx create mode 100644 examples/doc-viewer/app/en/widgets/text/page.c create mode 100644 examples/doc-viewer/app/en/widgets/text/page.h create mode 100644 examples/doc-viewer/app/en/widgets/text/page.tsx create mode 100644 examples/doc-viewer/app/examples/anchor-basic/index.c create mode 100644 examples/doc-viewer/app/examples/anchor-basic/index.tsx create mode 100644 examples/doc-viewer/app/examples/button-basic/index.c create mode 100644 examples/doc-viewer/app/examples/button-basic/index.tsx create mode 100644 examples/doc-viewer/app/examples/scrollarea-basic/index.c create mode 100644 examples/doc-viewer/app/examples/scrollarea-basic/index.tsx create mode 100644 examples/doc-viewer/app/examples/scrollarea-dual-scrollbars/index.c create mode 100644 examples/doc-viewer/app/examples/scrollarea-dual-scrollbars/index.tsx create mode 100644 examples/doc-viewer/app/examples/text-basic/index.c create mode 100644 examples/doc-viewer/app/examples/text-basic/index.tsx create mode 100644 examples/doc-viewer/app/examples/text-input-basic/index.c create mode 100644 examples/doc-viewer/app/examples/text-input-basic/index.tsx create mode 100644 examples/doc-viewer/app/global.css create mode 100644 examples/doc-viewer/app/layout.c create mode 100644 examples/doc-viewer/app/layout.h create mode 100644 examples/doc-viewer/app/layout.tsx create mode 100644 examples/doc-viewer/app/locale.c create mode 100644 examples/doc-viewer/app/locale.h create mode 100644 examples/doc-viewer/app/main.c create mode 100644 examples/doc-viewer/app/widget-fields/anchor.ts create mode 100644 examples/doc-viewer/app/widget-fields/button.ts create mode 100644 examples/doc-viewer/app/widget-fields/scrollarea-content.ts create mode 100644 examples/doc-viewer/app/widget-fields/scrollarea.ts create mode 100644 examples/doc-viewer/app/widget-fields/scrollbar.ts create mode 100644 examples/doc-viewer/app/widget-fields/text-input.ts create mode 100644 examples/doc-viewer/app/widget-fields/text.ts create mode 100644 examples/doc-viewer/app/widget-fields/widget.ts create mode 100644 examples/doc-viewer/app/zh-CN/devtools/css-modules/page.c create mode 100644 examples/doc-viewer/app/zh-CN/devtools/css-modules/page.h create mode 100644 examples/doc-viewer/app/zh-CN/devtools/css-modules/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/devtools/icon-library/page.c create mode 100644 examples/doc-viewer/app/zh-CN/devtools/icon-library/page.h create mode 100644 examples/doc-viewer/app/zh-CN/devtools/icon-library/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/devtools/sass/page.c create mode 100644 examples/doc-viewer/app/zh-CN/devtools/sass/page.h create mode 100644 examples/doc-viewer/app/zh-CN/devtools/sass/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/devtools/tailwind-css/page.c create mode 100644 examples/doc-viewer/app/zh-CN/devtools/tailwind-css/page.h create mode 100644 examples/doc-viewer/app/zh-CN/devtools/tailwind-css/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/devtools/tsx-and-dev-tools/page.c create mode 100644 examples/doc-viewer/app/zh-CN/devtools/tsx-and-dev-tools/page.h create mode 100644 examples/doc-viewer/app/zh-CN/devtools/tsx-and-dev-tools/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/handbook/composition/page.c create mode 100644 examples/doc-viewer/app/zh-CN/handbook/composition/page.h create mode 100644 examples/doc-viewer/app/zh-CN/handbook/composition/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/handbook/css-modules/page.c create mode 100644 examples/doc-viewer/app/zh-CN/handbook/css-modules/page.h create mode 100644 examples/doc-viewer/app/zh-CN/handbook/css-modules/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/handbook/customization/page.c create mode 100644 examples/doc-viewer/app/zh-CN/handbook/customization/page.h create mode 100644 examples/doc-viewer/app/zh-CN/handbook/customization/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/handbook/icon-library/page.c create mode 100644 examples/doc-viewer/app/zh-CN/handbook/icon-library/page.h create mode 100644 examples/doc-viewer/app/zh-CN/handbook/icon-library/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/handbook/sass/page.c create mode 100644 examples/doc-viewer/app/zh-CN/handbook/sass/page.h create mode 100644 examples/doc-viewer/app/zh-CN/handbook/sass/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/handbook/styling/page.c create mode 100644 examples/doc-viewer/app/zh-CN/handbook/styling/page.h create mode 100644 examples/doc-viewer/app/zh-CN/handbook/styling/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/handbook/tailwind-css/page.c create mode 100644 examples/doc-viewer/app/zh-CN/handbook/tailwind-css/page.h create mode 100644 examples/doc-viewer/app/zh-CN/handbook/tailwind-css/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/handbook/tsx-and-dev-tools/page.c create mode 100644 examples/doc-viewer/app/zh-CN/handbook/tsx-and-dev-tools/page.h create mode 100644 examples/doc-viewer/app/zh-CN/handbook/tsx-and-dev-tools/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/handbook/typescript/page.c create mode 100644 examples/doc-viewer/app/zh-CN/handbook/typescript/page.h create mode 100644 examples/doc-viewer/app/zh-CN/handbook/typescript/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/overview/about/page.c create mode 100644 examples/doc-viewer/app/zh-CN/overview/about/page.h create mode 100644 examples/doc-viewer/app/zh-CN/overview/about/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/overview/quick-start/page.c create mode 100644 examples/doc-viewer/app/zh-CN/overview/quick-start/page.h create mode 100644 examples/doc-viewer/app/zh-CN/overview/quick-start/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/widgets/anchor/page.c create mode 100644 examples/doc-viewer/app/zh-CN/widgets/anchor/page.h create mode 100644 examples/doc-viewer/app/zh-CN/widgets/anchor/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/widgets/button/page.c create mode 100644 examples/doc-viewer/app/zh-CN/widgets/button/page.h create mode 100644 examples/doc-viewer/app/zh-CN/widgets/button/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/widgets/scrollarea/page.c create mode 100644 examples/doc-viewer/app/zh-CN/widgets/scrollarea/page.h create mode 100644 examples/doc-viewer/app/zh-CN/widgets/scrollarea/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/widgets/text-input/page.c create mode 100644 examples/doc-viewer/app/zh-CN/widgets/text-input/page.h create mode 100644 examples/doc-viewer/app/zh-CN/widgets/text-input/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/widgets/text/page.c create mode 100644 examples/doc-viewer/app/zh-CN/widgets/text/page.h create mode 100644 examples/doc-viewer/app/zh-CN/widgets/text/page.tsx create mode 100644 examples/doc-viewer/bun.lock create mode 100644 examples/doc-viewer/env.d.ts create mode 100644 examples/doc-viewer/package-lock.json create mode 100644 examples/doc-viewer/package.json create mode 100644 examples/doc-viewer/postcss.config.js create mode 100644 examples/doc-viewer/scripts/compiler/css-extractor.ts create mode 100644 examples/doc-viewer/scripts/compiler/example-compiler.ts create mode 100644 examples/doc-viewer/scripts/compiler/index.ts create mode 100644 examples/doc-viewer/scripts/compiler/mdx-parser.ts create mode 100644 examples/doc-viewer/scripts/compiler/page-generator.ts create mode 100644 examples/doc-viewer/scripts/compiler/style-tag-renderer.ts create mode 100644 examples/doc-viewer/scripts/compiler/tsconfig.json create mode 100644 examples/doc-viewer/tailwind.config.js create mode 100644 examples/doc-viewer/tsconfig.json create mode 100644 examples/doc-viewer/xmake.lua diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 50b47a3fa..9a0ebb6b5 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -21,7 +21,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '24' - name: Install dependencies run: npm ci @@ -49,20 +49,8 @@ jobs: - uses: xmake-io/github-action-setup-xmake@v1 with: - xmake-version: branch@dev - - - name: Cache xmake packages - uses: actions/cache@v4 - with: - path: | - ~/.xmake/packages - ~/.xmake/repositories - ~/AppData/Local/.xmake/packages - ~/AppData/Local/.xmake/repositories - key: ${{ runner.os }}-xmake-${{ runner.os == 'Linux' && 'coverage' || 'release' }}-${{ hashFiles('xmake-requires.lock', 'examples/xmake-requires.lock') }} - restore-keys: | - ${{ runner.os }}-xmake-${{ runner.os == 'Linux' && 'coverage' || 'release' }}- - ${{ runner.os }}-xmake- + package-cache: true + actions-cache-folder: '.xmake-cache' - name: Install tools if: runner.os == 'Linux' @@ -107,14 +95,32 @@ jobs: xmake package xmake install -o dist/lcui-package + - uses: actions/setup-node@v4 + with: + node-version: '22' + + - uses: oven-sh/setup-bun@v2 + + - name: Install doc-viewer dependencies + working-directory: examples/doc-viewer + run: bun install + + - name: Install lcui-cli + run: npm install -g @lcui/cli + + - name: Generate doc-viewer sources + working-directory: examples/doc-viewer + run: bun run compile + + - name: Process doc-viewer TSX files + working-directory: examples/doc-viewer + run: lcui build + - name: Build examples - run: | - cd examples - xmake config -P . -y - xmake build -P . - xmake install -P . -o ../dist/lcui-examples - mv ../dist/lcui-examples/bin/* ../dist/lcui-examples/ - rm -r ../dist/lcui-examples/bin + run: xmake build -yg lcui-examples + + - name: Install examples + run: xmake install -o dist/lcui-examples -g lcui-examples - uses: actions/upload-artifact@v4 with: diff --git a/.gitignore b/.gitignore index 7186f43e6..a8d76765b 100644 --- a/.gitignore +++ b/.gitignore @@ -69,4 +69,5 @@ build/*.jpg config.h test/build vsxmake* -compile_commands.json \ No newline at end of file +compile_commands.json +docs/build/ diff --git a/AGENTS.md b/AGENTS.md index 3113d8ed8..d118d57ef 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -155,6 +155,31 @@ write_log(logger, msg); 若公共逻辑较长,可提取为独立函数,并保持调用路径一致,减少分叉实现。 +## LCUI CSS 引擎约束 + +### 选择器 + +- 仅支持:通配符 `*`、类型 `type`、类 `.cls`、ID `#id`、后代空格 `A B` +- 不支持:子代 `>`、相邻兄弟 `+`、通用兄弟 `~` +- 不支持:属性选择器 `[attr]` `[data-x]` +- 不支持:功能性伪类 `:not()` `:is()` `:where()` `:has()` `:nth-child()`(解析器无 `(` 语法) +- 不支持:伪元素 `::before` `::after` + +### 优先级 + +- Rank:`GENERAL=0`,`TYPE=1`,`CLASS=10`,`PCLASS=10`,`ID=100` +- 同 rank 用 `batch_num`(声明顺序)决胜,后声明覆盖先声明 +- 无 `!important` 机制 +- class 与 pclass rank 相同(都是 10) + +### 属性与值 + +- `position`:仅 `static` / `relative` / `absolute`,无 `fixed` +- `white-space`:仅 `normal` / `nowrap` +- `border-style`:仅 `none` / `solid` +- 无 `calc()` / `var()` / CSS 自定义属性 +- 无 `calc()` / `var()` / `em` / `rem` / `vh` / `vw` 单位(可用 `dp` / `px` / `pt` / `%`) + ## 指令 ### gen-commit diff --git a/docs/en/devtools/css-modules.mdx b/docs/en/devtools/css-modules.mdx new file mode 100644 index 000000000..f8e733da9 --- /dev/null +++ b/docs/en/devtools/css-modules.mdx @@ -0,0 +1,29 @@ +# CSS Modules + +CSS Modules create locally scoped CSS classes for TSX components, avoiding naming conflicts and improving maintainability. + +## Usage + +Create a file with the `.module.css` suffix: + +```css title="MyComponent.module.css" +.card { + border: 1px solid #eee; + border-radius: 4px; +} +``` + +Import it in a `.tsx` file: + +```tsx title="MyComponent.tsx" +import styles from "./MyComponent.module.css"; +``` + +Use the `styles` object instead of string class names in JSX: + +```diff +- ++ +``` + +During compilation, `@lcui/cli` converts `.module.css` into C identifier bindings, automatically generating unique C constant names for class names to avoid global conflicts. diff --git a/docs/en/devtools/icon-library.mdx b/docs/en/devtools/icon-library.mdx new file mode 100644 index 000000000..aae574bb9 --- /dev/null +++ b/docs/en/devtools/icon-library.mdx @@ -0,0 +1,29 @@ +# Icon Library + +`@lcui/fluent-icons` is an icon library adapted for LCUI. All icons come from Microsoft's [fluentui-system-icons](https://github.com/microsoft/fluentui-system-icons) project. + +## Installation + +```sh +npm install @lcui/fluent-icons +``` + +## Choosing icons + +Search and select icons on [flicon.io](https://www.flicon.io/). For example, the zoom-in icon is typically named "Zoom In" in English. + +fluentui-system-icons icons are available in sizes like 16, 20, and 24, named in the format "icon name + size + style". `@lcui/fluent-icons` uses the naming format "icon name + style", and when the style is Regular it can be omitted. + +## Usage + +```tsx +import { ZoomIn } from "@lcui/fluent-icons"; + + +``` + +The default size is 20. If the icon size is fixed and you want better rendering, specify the size parameter: + +```tsx + +``` diff --git a/docs/en/devtools/sass.mdx b/docs/en/devtools/sass.mdx new file mode 100644 index 000000000..4c13fdbd7 --- /dev/null +++ b/docs/en/devtools/sass.mdx @@ -0,0 +1,15 @@ +# Sass + +Sass is a popular CSS preprocessor that extends CSS with variables, nesting rules, mixins, and more. + +## Usage + +`@lcui/cli` has a built-in Sass preprocessor that is automatically invoked when compiling `.sass` and `.scss` files — no additional installation or configuration needed. + +Import Sass files directly in TSX: + +```tsx title="MyComponent.tsx" +import "./MyComponent.scss"; +``` + +The CLI compiles Sass files into CSS, then converts them to C code for runtime loading. diff --git a/docs/en/devtools/tailwind-css.mdx b/docs/en/devtools/tailwind-css.mdx new file mode 100644 index 000000000..3ce304d5b --- /dev/null +++ b/docs/en/devtools/tailwind-css.mdx @@ -0,0 +1,31 @@ +# Tailwind CSS + +Tailwind CSS is a utility-first CSS framework that helps developers quickly apply styles through predefined CSS classes. Compared to traditional CSS, you don't need to create new CSS files, write rules, or think up class names. + +## Installation + +```sh +npm install -D tailwindcss postcss @thedutchcoder/postcss-rem-to-px +``` + +## Configuration + +Copy the following files from the [lcui-quick-start](https://github.com/lcui-dev/lcui-quick-start) template project to your project root: + +- `postcss.config.js` +- `tailwind.config.js` +- `app/global.css` + +`global.css` contains the Tailwind directives: + +```css title="app/global.css" +@tailwind base; +@tailwind components; +@tailwind utilities; +``` + +When compiling, `@lcui/cli` processes Tailwind directives through the PostCSS chain (postcss + tailwindcss + postcss-rem-to-px) to generate the final CSS output. + +:::tip +If you don't want to place global.css inside the app directory, change the `content` path matching rules in `tailwind.config.js`. +::: diff --git a/docs/en/devtools/tsx-and-dev-tools.mdx b/docs/en/devtools/tsx-and-dev-tools.mdx new file mode 100644 index 000000000..0f112bad3 --- /dev/null +++ b/docs/en/devtools/tsx-and-dev-tools.mdx @@ -0,0 +1,201 @@ +# TSX & Dev Tools + +With `@lcui/cli`, you can write declarative UIs using TypeScript with JSX syntax. The CLI compiles TSX into C code, so you don't need to manually write widget tree construction logic. + +The benefit is that the declarative approach makes state binding, event binding, and resource imports more concise and intuitive. Handling logic and view in the same file reduces context switching. + +However, `@lcui/react` currently has limited capabilities — you can only declare component state, data bindings, and event bindings. For complex operations like conditional rendering or list rendering, you still need to write C code. + +## Installing dev tools + +`@lcui/cli` is a command-line tool that integrates a TypeScript compiler, Sass preprocessor, resource file loader, and more. It requires a Node.js runtime: + +```sh +npm install -g @lcui/cli +``` + +## How the preprocessor works + +LCUI uses a preprocessor approach: TSX files are only executed during preprocessing and do not become runtime code. You can think of TSX files as configuration files, where the TypeScript code acts as preprocessing directives. + +The preprocessor matches the appropriate loader by file extension, parses the TSX code, collects dependencies, executes component functions, and then generates C source files based on the returned JSX elements and Hook call results. + +## Usage overview + +```tsx title="src/App.tsx" +import { useState, TextInput, Button } from "@lcui/react"; + +export default function App() { + const inputRef = { current: { value: "" } }; + const [name, setName] = useState("LCUI"); + + return ( + + + Hello, {name}! + + + + + ); +} +``` + +## React library + +`@lcui/react` is a UI library tailored for LCUI's features and preprocessor workflow, providing built-in components, utility functions, and hooks. + +Installation: + +```sh +npm install @lcui/react +``` + +### Component functions + +The preprocessor executes component functions, collects data from `useState`, `useRef`, etc. and the returned JSX elements, then converts them into C code. + +:::warning +- Component function return values must be a single JSX element — ``, null, undefined, strings, numbers, or other objects are not supported. +- Declaring and passing component props is not yet supported. +::: + +### State management + +`useState` declares a state variable for a component: + +```tsx +import { useState } from "@lcui/react"; + +function MyComponent() { + const [age, setAge] = useState(23); + const [name, setName] = useState("Taylor"); + // ... +} +``` + +`useState` returns an array: + +- The state variable, initialized to the value passed to `useState`. +- A set function, which lets you change the state variable in response to interactions. + +`useState` adds a member to the component's state struct and generates initialization code in the init function: + +```c +/* Component state struct */ +struct MyComponent_state { + int age; + char *name; +}; + +/* Code in component init function */ +_that->state.age = 23; +_that->state.name = strdup2("Taylor"); +``` + +The state's set function inserts C code in the current scope, e.g. `setAge(30)` generates `_that->state.age = 30;`. + +:::warning +`useState` parameters can only be string or number types. +::: + +### Refs + +Use the `$ref` attribute to reference a widget object: + +```tsx + +``` + +Then operate on it in C code: + +```c +ui_textinput_set_content(_that->refs.input, "hello"); +``` + +The `$ref` value can also be a reference object returned by `useRef`: + +```tsx +import { useRef } from "@lcui/react"; + +function MyComponent() { + const inputRef = useRef(); + + return ; +} +``` + +`useRef` currently only implements value property read/write binding for TextInput: + +```tsx +inputRef.current.value = "World"; + + +``` + +:::warning +`@lcui/react`'s `useRef` is different from React's `useRef` — it is only for referencing widget objects. +::: + +### Responding to events + +Declare event handlers using the `on + event name` attribute: + +```tsx + +``` + +The preprocessor generates C code to bind the event: + +```c +ui_widget_on(_that->refs.ref_0, "click", handleClick, w); +``` + +You can also bind JavaScript functions to events: + +```tsx +import { useState, Text, Button } from "@lcui/react"; + +export default function Counter() { + const [text, setText] = useState("Click me"); + + function handleClick() { + setText("You clicked"); + } + + return ( + + ); +} +``` + +The preprocessor generates a C-language version of the event handler based on the code executed inside the handler function. + +:::warning +Currently, only state variable set functions can be called inside event handlers. Accessing the event object or executing other statements is not supported. +::: + +### Conditional rendering + +:::warning +Not yet supported. +We are considering implementing conditional rendering with a `` component, inspired by Solid.js's ``. +::: + +### Rendering lists + +:::warning +Not yet supported. +We are considering implementing array iteration with a `` component, inspired by Solid.js's ``. +::: diff --git a/docs/en/handbook/customization.mdx b/docs/en/handbook/customization.mdx new file mode 100644 index 000000000..2a271bbe9 --- /dev/null +++ b/docs/en/handbook/customization.mdx @@ -0,0 +1,136 @@ +# Customization + +You can create entirely new widget types or extend existing ones. + +## Creating a custom widget + +Use `ui_create_widget_prototype()` to register a new widget type: + +```c title="src/counter.c" +#include + +typedef struct { + int value; +} counter_data_t; + +static ui_widget_prototype_t *counter_proto; + +static void counter_init(ui_widget_t *w) +{ + counter_data_t *data; + ui_widget_t *text; + + data = ui_widget_add_data(w, counter_proto, sizeof(counter_data_t)); + data->value = 0; + + text = ui_create_widget("text"); + ui_text_set_content(text, "0"); + ui_widget_append(w, text); +} + +static void counter_destroy(ui_widget_t *w) +{ + /* Release owned resources (if any) */ +} + +void register_counter_widget(void) +{ + counter_proto = ui_create_widget_prototype("counter", NULL); + counter_proto->init = counter_init; + counter_proto->destroy = counter_destroy; +} +``` + +Use the custom widget: + +```c title="src/main.c" +extern void register_counter_widget(void); + +int main(void) +{ + ui_widget_t *counter; + + lcui_init(); + register_counter_widget(); + + counter = ui_create_widget("counter"); + ui_widget_append(ui_root(), counter); + return lcui_main(); +} +``` + +## Extending an existing widget + +Pass a parent type name as the second argument to `ui_create_widget_prototype()`: + +```c title="src/icon_button.c" +static ui_widget_prototype_t *icon_button_proto; + +static void icon_button_init(ui_widget_t *w) +{ + /* Call parent (button) init logic */ + icon_button_proto->proto->init(w); + ui_widget_add_class(w, "icon-button"); +} + +void register_icon_button(void) +{ + icon_button_proto = + ui_create_widget_prototype("icon-button", "button"); + icon_button_proto->init = icon_button_init; +} +``` + +:::warning +**Parent `init` must be called manually.** LCUI does not automatically call the parent type's `init` when creating a subtype widget. If you forget to call `proto->proto->init(w)`, the widget will lack the parent type's base behaviors (e.g. `button` won't register click events or set default styles). +::: + +## Widget lifecycle + +`ui_widget_prototype_t` has several callback hooks covering each lifecycle stage: + +- **`init`** — When the widget is created. Responsible for initializing owned data, child widgets, and event bindings. +- **`destroy`** — When the widget is destroyed. Responsible for releasing owned memory and unbinding events. +- **`update`** — When the widget needs updating, receives a `ui_task_type_t` parameter indicating the update type (style update, property update, etc.). Called by LCUI during each frame's update loop. +- **`setattr`** — When an XML attribute is set (for responding to attribute changes). +- **`settext`** — When text content is set. +- **`sizehint`** — Estimates the widget's natural size constraints (min/max content size) without external constraints. The layout engine uses this when computing child widget sizes. +- **`resize`** — When the widget size changes. Receives the new content area width and height as parameters. +- **`paint`** — When the widget needs to be redrawn. Used for custom drawing logic. + +## Custom painting + +Override the `paint` callback to draw custom graphics on a widget: + +```c title="src/my_widget.c" +static void my_widget_paint(ui_widget_t *w, pd_context_t *paint_ctx, + ui_widget_actual_style_t *style) +{ + pd_canvas_t *canvas = paint_ctx->canvas; + pd_color_t color = pd_color_from_rgb(255, 0, 0); + pd_rect_t rect = { style->left, style->top, w->width, w->height }; + + pd_canvas_fill_rect(canvas, color, rect); +} + +static void register_my_widget(void) +{ + ui_widget_prototype_t *proto = + ui_create_widget_prototype("my-widget", NULL); + proto->paint = my_widget_paint; +} +``` + +:::warning +**`paint` is only for drawing.** Widget size estimation is handled by `sizehint`; do not modify widget size or the child widget tree inside `paint`, as it may cause infinite loops. +::: + +## Caveats + +:::warning +**`destroy` must release owned resources.** If a custom widget allocated memory, opened files, or subscribed to system events (e.g. `lcui_settings_on_deserialize`) in `init`, it must perform symmetric cleanup in `destroy`. +::: + +:::warning +**Custom widgets must be registered after `lcui_init()` and before first instantiation.** Calling your `register_xxx()` function right at the start of `main()` is the safest place, ensuring all consumers (XML loading, router instantiation, TSX compilation results) can see the prototype. +::: diff --git a/docs/en/handbook/styling.mdx b/docs/en/handbook/styling.mdx new file mode 100644 index 000000000..3d120aca9 --- /dev/null +++ b/docs/en/handbook/styling.mdx @@ -0,0 +1,151 @@ +# Styling + +Use CSS to set colors, borders, padding, margins, dimensions, and layout for widgets. + +## How to set styles + +### Inline styles + +Use `ui_widget_set_style_string()` to set individual CSS properties directly: + +```c title="main.c" +ui_widget_t *w = ui_create_widget("text"); + +ui_widget_set_style_string(w, "color", "#336699"); +ui_widget_set_style_string(w, "font-size", "20px"); +ui_widget_set_style_string(w, "padding", "8px 16px"); +``` + +### CSS class selectors + +Use `ui_load_css_string()` or `ui_load_css_file()` to load CSS rules, then apply them to widgets with `ui_widget_add_class()`: + +```c title="main.c" +ui_load_css_file("styles.css"); + +ui_widget_t *w = ui_create_widget("text"); +ui_widget_add_class(w, "title"); +``` + +```css title="app/styles.css" +.title { + font-size: 24px; + font-weight: bold; + margin-bottom: 16px; +} +``` + +You can also use `ui_load_css_string()` to load CSS rules from a string. The second parameter is a source identifier used for debugging to locate conflicting rules: + +```c title="main.c" +ui_load_css_string(".title { font-size: 24px; }", "app.css"); +``` + +## Supported CSS features + +LCUI's CSS engine implements a subset of the web standard. This section lists all supported features and their supported values; **anything not listed is not supported by default**. + +### At Rules + +- **`@font-face`** — Load external fonts + +### Selectors + +- `*` (universal), `type`, `#id`, `.class` +- Pseudo-classes `:hover`, `:focus`, `:active`, `:first-child`, `:last-child` +- `!important` is not supported + +### Units + +- `px`, `dp`, `sp`, `pt`, `%` + +### Properties + +#### Layout + +- **`display`** — `none`, `inline-block`, `block`, `flex`, `inline-flex`, `table`, `inline-table`, `table-row`, `table-cell` +- **`position`** — `static`, `relative`, `absolute` +- **`top` / `right` / `bottom` / `left`** — `` or `` or `auto` +- **`z-index`** — `auto` or integer +- **`box-sizing`** — `content-box`, `border-box` + +#### Box model + +- **`width` / `height`** — ``, ``, `auto` +- **`min-width` / `max-width` / `min-height` / `max-height`** — same as above +- **`padding`** — shorthand, 1-4 `` values (e.g. `8px`, `4px 8px`, `4px 8px 12px`, `4px 8px 12px 16px`) +- **`padding-top` / `padding-right` / `padding-bottom` / `padding-left`** — longhand properties +- **`margin`** — shorthand, same syntax as padding +- **`margin-top` / `margin-right` / `margin-bottom` / `margin-left`** +- **`border`** — shorthand `1px solid #ccc` (width + style + color) +- **`border-color` / `border-width` / `border-style` / `border-radius`** — multi-value shorthand, same syntax as padding +- **`border-top` / `border-right` / `border-bottom` / `border-left`** — per-side shorthand +- **`border-top-color` / `border-right-color` / `border-bottom-color` / `border-left-color`** +- **`border-top-width` / `border-right-width` / `border-bottom-width` / `border-left-width`** +- **`border-top-style` / `border-right-style` / `border-bottom-style` / `border-left-style`** +- **`border-top-left-radius` / `border-top-right-radius` / `border-bottom-left-radius` / `border-bottom-right-radius`** +- **`border-style` values** — `none`, `solid` +- **`table-layout`** — `auto`, `fixed` +- **`border-spacing`** — `{1,2}` + +#### Background + +- **`background`** — shorthand `bg-image || bg-position || bg-size || repeat-style || color` (single layer only) +- **`background-color`** — `` +- **`background-image`** — `none` or `` +- **`background-position`** — two values: x y +- **`background-position-x` / `background-position-y`** +- **`background-repeat`** — `` +- **`background-size`** — `` +- **`background-clip`** — `border-box`, `padding-box`, `content-box` + +#### Flexbox layout + +- **`flex`** — shorthand (`flex-grow` + `flex-shrink` + `flex-basis`) +- **`flex-shrink` / `flex-grow` / `flex-basis`** +- **`flex-wrap`** — `nowrap`, `wrap` +- **`flex-direction`** — `row`, `column` +- **`justify-content`** — `flex-start`, `center`, `flex-end` +- **`align-items`** — `flex-start`, `center`, `flex-end`, `stretch` +- **`align-content`** — same as justify-content plus `space-between`, `space-around`, `space-evenly` +- **`gap`** — shorthand, sets both row-gap and column-gap +- **`row-gap` / `column-gap`** — `normal` or `` + +#### Typography + +- **`font-face`** — (load fonts via `@font-face` rule) +- **`font-family`** — `` (recommended to use built-in aliases like `monospace`) +- **`font-size`** — `` +- **`font-style`** — `normal`, `italic`, `oblique` +- **`font-weight`** — `normal`, `bold`, `` +- **`text-align`** — `left`, `center`, `right` +- **`line-height`** — `normal` or `` or `` +- **`color`** — `` +- **`white-space`** — `normal`, `nowrap` +- **`word-break`** — `normal`, `break-all` +- **`content`** — `` or `none` + +#### Other + +- **`opacity`** — `` or `` +- **`visibility`** — `visible`, `hidden` +- **`pointer-events`** — `auto`, `none` +- **`box-shadow`** — `none` or `` (format `{2,4} && ?`) + +## Caveats + +:::warning +**`white-space: pre` does not work.** LCUI's `white-space` only implements `normal` and `nowrap`. If you need to preserve leading whitespace from source code, replace spaces with U+00A0 (NBSP). +::: + +:::warning +**`overflow` does not clip content.** To clip or scroll child content, use the `scrollarea` built-in widget instead. +::: + +:::warning +**`background` shorthand does not support multiple layers.** Writing multi-background syntax like `background: url(a.png) no-repeat, url(b.png) center;` will not work. Use individual properties like `background-image` / `background-position` to set each layer separately. +::: + +:::warning +**CSS does not support inheritance.** Properties like `color`, `font-family`, and `font-size` do not cascade from parent to child widgets. Every widget that displays text (e.g. `text`, `button`) must explicitly set these properties. +::: diff --git a/docs/en/overview/about.mdx b/docs/en/overview/about.mdx new file mode 100644 index 000000000..87b910c5b --- /dev/null +++ b/docs/en/overview/about.mdx @@ -0,0 +1,59 @@ +# About LCUI + +LCUI is an open-source desktop graphical user interface library written in C, designed to provide C developers with a simple and easy-to-use GUI development experience, while incorporating CSS styling and declarative UI description from web development to lower the learning barrier. + +## Key features + +- **Cross-platform** — Supports Windows and Linux. +- **Fully self-drawn widgets** — Widgets maintain consistent appearance and behavior across platforms. +- **DPI-adaptive** — Automatically scales the UI on high-resolution screens for crisp display. +- **Built-in CSS engine** — Supports using CSS to define UI styles and layouts, making it easy to pick up for those with web development experience. +- **Modern development tools** — Through the `@lcui/cli` tool, you can use TypeScript with JSX syntax to write user interfaces. + +## Who should use LCUI + +LCUI is suitable for these developers: + +- Want to keep using C on the desktop, but want to escape the tedious Win32 / X11 native development experience. +- Already familiar with web frontend (HTML, CSS) and want to transfer that experience to desktop applications. +- Need to build single-window desktop tools with simple UI content. + +If your use case is a large commercial desktop product, a game engine, or a tool deeply integrated with the OS, LCUI may not be the best choice; in such scenarios, consider Qt, GTK, or native APIs instead. + +## Architecture + +LCUI is divided into four layers from top to bottom: + +### Application layer + +Your business code: custom widgets, CSS styles, TSX/JSX code, event handling. This is the only part tied to your project domain. + +### LCUI Runtime + +Initialization, event loop, application lifecycle management. Responsible for running the app, dispatching events, and driving rendering. + +### UI Helpers + +UI XML parsing, UI Router, cursor management, internationalization (i18n), and other helper modules. These package common UI behaviors into pluggable subsystems. + +### Foundation layer + +YUtil (general utility library), PandaGL (2D rendering engine), CSS engine, UI widget system, Thread / Worker abstractions. These modules can also be used independently. + +The platform layer (Windows / Linux) handles window management and input events. + +## License + +LCUI is released under the MIT License. See LICENSE.TXT in the repository root for details. + +## Contributing + +Contributions are welcome! Before submitting a Pull Request, please read CONTRIBUTING.md in the repository root. + +- **Bug reports** — Open an issue on GitHub Issues. +- **Feature requests** — Start a discussion on GitHub Discussions. +- **Code contributions** — Fork the repo, create a branch, and submit a PR. + +## Community + +If you run into issues, you can ask questions on GitHub Discussions (use the `Q&A` label). We also encourage experienced users to help newcomers. diff --git a/docs/en/overview/quick-start.mdx b/docs/en/overview/quick-start.mdx new file mode 100644 index 000000000..4dce35446 --- /dev/null +++ b/docs/en/overview/quick-start.mdx @@ -0,0 +1,44 @@ +# Quick Start + +Get up and running with LCUI in minutes. + +## Prerequisites + +- **Operating system** — Windows (recommended) or Linux +- **Node.js** — Required to run `@lcui/cli` +- **xmake** — C/C++ build tool +- **Git** — Download and manage source code + +## Installation + +Install the LCUI CLI globally: + +```sh +npm install -g @lcui/cli +``` + +Create and run your first app: + +```sh +lcui create my-app +cd my-app +lcui build +xmake run app +``` + +`lcui create` clones a minimal project from the lcui-quick-start template repository, including xmake.lua configuration, example code, and dependencies. Once done, run `lcui build` to compile TSX resources, then `xmake run app` to launch the application. + +## Next steps + +- Explore the sample project generated by `lcui create` — look at the code and file structure to understand the basics of an LCUI application. +- Read the widget reference (Button, Text, TextInput, Anchor, ScrollArea) to learn about built-in widgets. +- Read the Styling chapter to learn how to apply CSS properties to widgets. +- Read the Customization chapter to learn how to create custom widgets. +- Read the TSX & Dev Tools chapter to understand `@lcui/react` usage and limitations in depth. + +## Having trouble? + +If you run into problems while learning, you can get help through: + +- Ask questions on GitHub Discussions (use the `Q&A` label). +- Check CONTRIBUTING.md in the repository root to learn how to contribute. diff --git a/docs/en/widgets/anchor.mdx b/docs/en/widgets/anchor.mdx new file mode 100644 index 000000000..21bc8fb46 --- /dev/null +++ b/docs/en/widgets/anchor.mdx @@ -0,0 +1,50 @@ +# Anchor + +A navigation widget similar to the HTML `` element. It can open external URLs in the system browser or load an XML view into a target container widget. + + + +## API + +### `ui_anchor_open` + +```c +void ui_anchor_open(ui_widget_t *w); +``` + +Programmatically triggers the anchor's action (same as a click). Reads the `href` attribute from the widget: + +- If `href` starts with `http://` or `https://` — opens in the system browser. +- If `href` starts with `file:///` — opens the local file in the system browser. +- Otherwise — asynchronously loads an XML file at the given path and injects its content into the widget identified by the `target` attribute. + +## XML tag + +```xml +Link text +``` + +Attributes: + +| Attribute | Required | Description | +|---|---|---| +| `href` | Yes | URL to open, or relative XML file path to load | +| `target` | For view loading | ID of the container widget where the loaded view is injected | +| `key` | No | Arbitrary string passed as `event.data` to the `loaded.anchor` event | + +## Events + +### `loaded.anchor` + +Fired on `ui_root()` after a view has been loaded and injected: + +```c +static void on_view_loaded(ui_widget_t *w, ui_event_t *e, void *arg) +{ + /* e->data contains the value of the anchor's "key" attribute */ + printf("Loaded view key: %s\n", (char *)e->data); +} + +ui_widget_on(ui_root(), "loaded.anchor", on_view_loaded, NULL); +``` + diff --git a/docs/en/widgets/button.mdx b/docs/en/widgets/button.mdx new file mode 100644 index 000000000..e16f66ba0 --- /dev/null +++ b/docs/en/widgets/button.mdx @@ -0,0 +1,25 @@ +# Button + +A clickable button widget, typically used to trigger an action. + + + +## Use cases + +- **Suitable**: users click to perform an action (submit a form, open a page, toggle a state) +- **Suitable**: interactive entry points in toolbars, dialogs, and navbars +- **Not suitable**: non-interactive text display (use `text` instead) + +## Anatomy + +```tsx title="Anatomy" +import { Button } from "@lcui/react"; + +; +} diff --git a/docs/examples/button-basic-tsx/main.c b/docs/examples/button-basic-tsx/main.c new file mode 100644 index 000000000..dbf3e8d1a --- /dev/null +++ b/docs/examples/button-basic-tsx/main.c @@ -0,0 +1,12 @@ +#include +#include + +/* example.tsx is compiled to example.h by @lcui/cli */ +#include "example.h" + +int main(void) +{ + lcui_init(); + example_load(); + return lcui_main(); +} diff --git a/docs/examples/button-basic-xml/main.c b/docs/examples/button-basic-xml/main.c new file mode 100644 index 000000000..f701cdb30 --- /dev/null +++ b/docs/examples/button-basic-xml/main.c @@ -0,0 +1,10 @@ +#include +#include +#include + +int main(void) +{ + lcui_init(); + ui_load_xml_file("ui.xml"); + return lcui_main(); +} diff --git a/docs/examples/button-basic-xml/ui.xml b/docs/examples/button-basic-xml/ui.xml new file mode 100644 index 000000000..9f94d1610 --- /dev/null +++ b/docs/examples/button-basic-xml/ui.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/docs/examples/button-basic/main.c b/docs/examples/button-basic/main.c new file mode 100644 index 000000000..90c3cea1d --- /dev/null +++ b/docs/examples/button-basic/main.c @@ -0,0 +1,11 @@ +#include +#include + +void button_basic_init(ui_widget_t *parent) +{ + ui_widget_t *btn; + + btn = ui_create_widget("button"); + ui_button_set_text(btn, "Click me"); + ui_widget_append(parent, btn); +} diff --git a/docs/examples/scrollarea-basic-tsx/example.css b/docs/examples/scrollarea-basic-tsx/example.css new file mode 100644 index 000000000..8bd14e40e --- /dev/null +++ b/docs/examples/scrollarea-basic-tsx/example.css @@ -0,0 +1,5 @@ +.demo-scrollarea { + width: 300px; + height: 200px; + border: 1px solid #d0d7de; +} diff --git a/docs/examples/scrollarea-basic-tsx/example.tsx b/docs/examples/scrollarea-basic-tsx/example.tsx new file mode 100644 index 000000000..104217e18 --- /dev/null +++ b/docs/examples/scrollarea-basic-tsx/example.tsx @@ -0,0 +1,20 @@ +import { ScrollArea, ScrollAreaContent, Scrollbar, Text } from "@lcui/react"; +import "./example.css"; + +const content = `这是一段用于演示滚动区域功能的示例文本。 +当文本内容超出容器高度时,用户可以通过滚动条来查看其余内容。 +滚动区域适合阅读长篇文章、展示数据列表。 +在实际项目中,滚动区域的尺寸通常由其父布局决定,开发者只需关注内容本身。 +滚动区域可以嵌套使用,构建复杂的多层滚动界面。 +合理配置滚动方向和样式,可以让界面更加整洁且易于使用。`; + +export default function App() { + return ( + + + {content} + + + + ); +} diff --git a/docs/examples/scrollarea-basic-tsx/main.c b/docs/examples/scrollarea-basic-tsx/main.c new file mode 100644 index 000000000..003262d6f --- /dev/null +++ b/docs/examples/scrollarea-basic-tsx/main.c @@ -0,0 +1,10 @@ +#include +#include +#include "example.h" + +int main(void) +{ + lcui_init(); + example_load(); + return lcui_main(); +} diff --git a/docs/examples/scrollarea-basic-xml/main.c b/docs/examples/scrollarea-basic-xml/main.c new file mode 100644 index 000000000..f701cdb30 --- /dev/null +++ b/docs/examples/scrollarea-basic-xml/main.c @@ -0,0 +1,10 @@ +#include +#include +#include + +int main(void) +{ + lcui_init(); + ui_load_xml_file("ui.xml"); + return lcui_main(); +} diff --git a/docs/examples/scrollarea-basic-xml/ui.xml b/docs/examples/scrollarea-basic-xml/ui.xml new file mode 100644 index 000000000..8e48239cb --- /dev/null +++ b/docs/examples/scrollarea-basic-xml/ui.xml @@ -0,0 +1,17 @@ + + + + + Item 1 + Item 2 + Item 3 + Item 4 + Item 5 + Item 6 + Item 7 + Item 8 + Item 9 + Item 10 + + + diff --git a/docs/examples/scrollarea-basic/main.c b/docs/examples/scrollarea-basic/main.c new file mode 100644 index 000000000..d8e4f967f --- /dev/null +++ b/docs/examples/scrollarea-basic/main.c @@ -0,0 +1,31 @@ +#include +#include + +void scrollarea_basic_init(ui_widget_t *parent) +{ + ui_widget_t *scroll, *content, *vbar, *text; + + scroll = ui_create_scrollarea(); + ui_widget_set_style_string(scroll, "width", "300px"); + ui_widget_set_style_string(scroll, "height", "200px"); + ui_widget_set_style_string(scroll, "border", "1px solid #d0d7de"); + + content = ui_create_scrollarea_content(); + text = ui_create_widget("text"); + ui_text_set_content_w( + text, + L"这是一段用于演示滚动区域功能的示例文本。\n" + L"当文本内容超出容器高度时,用户可以通过滚动条来查看其余内容。\n" + L"滚动区域适合阅读长篇文章、展示数据列表。\n" + L"在实际项目中,滚动区域的尺寸通常由其父布局决定," + L"开发者只需关注内容本身。\n" + L"滚动区域可以嵌套使用,构建复杂的多层滚动界面。\n" + L"合理配置滚动方向和样式,可以让界面更加整洁且易于使用。"); + ui_widget_append(content, text); + + vbar = ui_create_widget("scrollbar"); + + ui_widget_append(scroll, content); + ui_widget_append(scroll, vbar); + ui_widget_append(parent, scroll); +} diff --git a/docs/examples/scrollarea-dual-scrollbars-tsx/example.css b/docs/examples/scrollarea-dual-scrollbars-tsx/example.css new file mode 100644 index 000000000..39d567802 --- /dev/null +++ b/docs/examples/scrollarea-dual-scrollbars-tsx/example.css @@ -0,0 +1,23 @@ +.demo-scrollarea { + width: 400px; + height: 300px; + border: 1px solid #d0d7de; +} + +.demo-grid { + display: flex; + flex-wrap: wrap; + width: 1088px; + height: 1088px; + gap: 8px; + padding: 8px; +} + +.demo-cell { + width: 100px; + height: 100px; + background: #e1e5e9; + border: 1px solid #b0b8c0; + text-align: center; + line-height: 100px; +} diff --git a/docs/examples/scrollarea-dual-scrollbars-tsx/example.tsx b/docs/examples/scrollarea-dual-scrollbars-tsx/example.tsx new file mode 100644 index 000000000..814fa7dcd --- /dev/null +++ b/docs/examples/scrollarea-dual-scrollbars-tsx/example.tsx @@ -0,0 +1,18 @@ +import { ScrollArea, ScrollAreaContent, Scrollbar, Text } from "@lcui/react"; +import "./example.css"; + +export default function App() { + return ( + + + {Array.from({ length: 100 }, (_, i) => ( + + {i + 1} + + ))} + + + + + ); +} diff --git a/docs/examples/scrollarea-dual-scrollbars-tsx/main.c b/docs/examples/scrollarea-dual-scrollbars-tsx/main.c new file mode 100644 index 000000000..003262d6f --- /dev/null +++ b/docs/examples/scrollarea-dual-scrollbars-tsx/main.c @@ -0,0 +1,10 @@ +#include +#include +#include "example.h" + +int main(void) +{ + lcui_init(); + example_load(); + return lcui_main(); +} diff --git a/docs/examples/scrollarea-dual-scrollbars-xml/main.c b/docs/examples/scrollarea-dual-scrollbars-xml/main.c new file mode 100644 index 000000000..f701cdb30 --- /dev/null +++ b/docs/examples/scrollarea-dual-scrollbars-xml/main.c @@ -0,0 +1,10 @@ +#include +#include +#include + +int main(void) +{ + lcui_init(); + ui_load_xml_file("ui.xml"); + return lcui_main(); +} diff --git a/docs/examples/scrollarea-dual-scrollbars-xml/ui.xml b/docs/examples/scrollarea-dual-scrollbars-xml/ui.xml new file mode 100644 index 000000000..e401a4bb5 --- /dev/null +++ b/docs/examples/scrollarea-dual-scrollbars-xml/ui.xml @@ -0,0 +1,44 @@ + + + + + + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + + + + + + diff --git a/docs/examples/scrollarea-dual-scrollbars/main.c b/docs/examples/scrollarea-dual-scrollbars/main.c new file mode 100644 index 000000000..f1a8b6bcd --- /dev/null +++ b/docs/examples/scrollarea-dual-scrollbars/main.c @@ -0,0 +1,45 @@ +#include +#include +#include + +void scrollarea_dual_scrollbars_init(ui_widget_t *parent) +{ + int i; + char buf[8]; + ui_widget_t *area, *content, *hbar, *vbar, *box; + + area = ui_create_scrollarea(); + ui_widget_set_style_string(area, "width", "420px"); + ui_widget_set_style_string(area, "height", "300px"); + ui_widget_set_style_string(area, "border", "1px solid #d0d7de"); + + content = ui_create_scrollarea_content(); + ui_widget_set_style_string(content, "display", "flex"); + ui_widget_set_style_string(content, "flex-wrap", "wrap"); + ui_widget_set_style_string(content, "width", "1088px"); + ui_widget_set_style_string(content, "height", "1088px"); + ui_widget_set_style_string(content, "gap", "8px"); + ui_widget_set_style_string(content, "padding", "8px"); + + for (i = 0; i < 100; ++i) { + snprintf(buf, sizeof(buf), "%d", i + 1); + box = ui_create_widget("text"); + ui_text_set_content(box, buf); + ui_widget_set_style_string(box, "width", "100px"); + ui_widget_set_style_string(box, "height", "100px"); + ui_widget_set_style_string(box, "background", "#e1e5e9"); + ui_widget_set_style_string(box, "border", "1px solid #b0b8c0"); + ui_widget_set_style_string(box, "text-align", "center"); + ui_widget_set_style_string(box, "line-height", "100px"); + ui_widget_append(content, box); + } + + hbar = ui_create_widget("scrollbar"); + ui_widget_set_attr(hbar, "orientation", "horizontal"); + vbar = ui_create_widget("scrollbar"); + + ui_widget_append(area, content); + ui_widget_append(area, hbar); + ui_widget_append(area, vbar); + ui_widget_append(parent, area); +} diff --git a/docs/examples/text-basic-tsx/example.tsx b/docs/examples/text-basic-tsx/example.tsx new file mode 100644 index 000000000..46f4fec31 --- /dev/null +++ b/docs/examples/text-basic-tsx/example.tsx @@ -0,0 +1,5 @@ +import { Text } from "@lcui/react"; + +export default function App() { + return Hello, LCUI!; +} diff --git a/docs/examples/text-basic-tsx/main.c b/docs/examples/text-basic-tsx/main.c new file mode 100644 index 000000000..003262d6f --- /dev/null +++ b/docs/examples/text-basic-tsx/main.c @@ -0,0 +1,10 @@ +#include +#include +#include "example.h" + +int main(void) +{ + lcui_init(); + example_load(); + return lcui_main(); +} diff --git a/docs/examples/text-basic-xml/main.c b/docs/examples/text-basic-xml/main.c new file mode 100644 index 000000000..f701cdb30 --- /dev/null +++ b/docs/examples/text-basic-xml/main.c @@ -0,0 +1,10 @@ +#include +#include +#include + +int main(void) +{ + lcui_init(); + ui_load_xml_file("ui.xml"); + return lcui_main(); +} diff --git a/docs/examples/text-basic-xml/ui.xml b/docs/examples/text-basic-xml/ui.xml new file mode 100644 index 000000000..0be3c58ba --- /dev/null +++ b/docs/examples/text-basic-xml/ui.xml @@ -0,0 +1,6 @@ + + + + Hello, LCUI! + + diff --git a/docs/examples/text-basic/main.c b/docs/examples/text-basic/main.c new file mode 100644 index 000000000..3718ecd15 --- /dev/null +++ b/docs/examples/text-basic/main.c @@ -0,0 +1,11 @@ +#include +#include + +void text_basic_init(ui_widget_t *parent) +{ + ui_widget_t *w; + + w = ui_create_widget("text"); + ui_text_set_content(w, "Hello, LCUI!"); + ui_widget_append(parent, w); +} diff --git a/docs/examples/text-input-basic-tsx/example.tsx b/docs/examples/text-input-basic-tsx/example.tsx new file mode 100644 index 000000000..c2d23dae2 --- /dev/null +++ b/docs/examples/text-input-basic-tsx/example.tsx @@ -0,0 +1,5 @@ +import { TextInput } from "@lcui/react"; + +export default function App() { + return ; +} diff --git a/docs/examples/text-input-basic-tsx/main.c b/docs/examples/text-input-basic-tsx/main.c new file mode 100644 index 000000000..003262d6f --- /dev/null +++ b/docs/examples/text-input-basic-tsx/main.c @@ -0,0 +1,10 @@ +#include +#include +#include "example.h" + +int main(void) +{ + lcui_init(); + example_load(); + return lcui_main(); +} diff --git a/docs/examples/text-input-basic-xml/main.c b/docs/examples/text-input-basic-xml/main.c new file mode 100644 index 000000000..f701cdb30 --- /dev/null +++ b/docs/examples/text-input-basic-xml/main.c @@ -0,0 +1,10 @@ +#include +#include +#include + +int main(void) +{ + lcui_init(); + ui_load_xml_file("ui.xml"); + return lcui_main(); +} diff --git a/docs/examples/text-input-basic-xml/ui.xml b/docs/examples/text-input-basic-xml/ui.xml new file mode 100644 index 000000000..f3362eeb9 --- /dev/null +++ b/docs/examples/text-input-basic-xml/ui.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/docs/examples/text-input-basic/main.c b/docs/examples/text-input-basic/main.c new file mode 100644 index 000000000..7dc14f0a4 --- /dev/null +++ b/docs/examples/text-input-basic/main.c @@ -0,0 +1,10 @@ +#include + +void text_input_basic_init(ui_widget_t *parent) +{ + ui_widget_t *w; + + w = ui_create_widget("textinput"); + ui_textinput_set_placeholder(w, u8"请输入..."); + ui_widget_append(parent, w); +} diff --git a/docs/sidebars.json b/docs/sidebars.json new file mode 100644 index 000000000..dd34d7625 --- /dev/null +++ b/docs/sidebars.json @@ -0,0 +1,42 @@ +{ + "sidebar": [ + { + "slug": "overview", + "label": { "en": "Overview", "zh-CN": "概述" }, + "items": [ + { "slug": "quick-start", "label": { "en": "Quick Start", "zh-CN": "快速开始" } }, + { "slug": "about", "label": { "en": "About", "zh-CN": "关于" } } + ] + }, + { + "slug": "handbook", + "label": { "en": "Handbook", "zh-CN": "手册" }, + "items": [ + { "slug": "styling", "label": { "en": "Styling", "zh-CN": "样式" } }, + { "slug": "customization", "label": { "en": "Customization", "zh-CN": "自定义" } } + ] + }, + { + "slug": "devtools", + "label": { "en": "Dev Tools", "zh-CN": "开发工具" }, + "items": [ + { "slug": "tsx-and-dev-tools", "label": { "en": "TSX & @lcui/cli", "zh-CN": "TSX 与 @lcui/cli" } }, + { "slug": "css-modules", "label": { "en": "CSS Modules", "zh-CN": "CSS Modules" } }, + { "slug": "tailwind-css", "label": { "en": "Tailwind CSS", "zh-CN": "Tailwind CSS" } }, + { "slug": "sass", "label": { "en": "Sass", "zh-CN": "Sass" } }, + { "slug": "icon-library", "label": { "en": "Icon Library", "zh-CN": "图标库" } } + ] + }, + { + "slug": "widgets", + "label": { "en": "Widgets", "zh-CN": "组件" }, + "items": [ + { "slug": "anchor", "label": { "en": "Anchor", "zh-CN": "Anchor 锚点" } }, + { "slug": "button", "label": { "en": "Button", "zh-CN": "Button 按钮" } }, + { "slug": "scrollarea", "label": { "en": "ScrollArea", "zh-CN": "ScrollArea 滚动区域" } }, + { "slug": "text", "label": { "en": "Text", "zh-CN": "Text 文本" } }, + { "slug": "text-input", "label": { "en": "TextInput", "zh-CN": "TextInput 文本输入" } } + ] + } + ] +} diff --git a/docs/widget-fields/anchor.ts b/docs/widget-fields/anchor.ts new file mode 100644 index 000000000..0e7682e80 --- /dev/null +++ b/docs/widget-fields/anchor.ts @@ -0,0 +1,14 @@ +import { widgetFields, FieldData } from "./widget"; + +export const anchorFields: FieldData[] = [ + ...widgetFields, + { + name: "href", + type: "string", + default: "-", + description: { + en: "The URL the link points to.", + "zh-CN": "链接的目标 URL。", + }, + }, +]; diff --git a/docs/widget-fields/button.ts b/docs/widget-fields/button.ts new file mode 100644 index 000000000..7f38e7aaf --- /dev/null +++ b/docs/widget-fields/button.ts @@ -0,0 +1,14 @@ +import { widgetFields, FieldData } from "./widget"; + +export const buttonFields: FieldData[] = [ + ...widgetFields, + { + name: "disabled", + type: "string", + default: "-", + description: { + en: "Disables the button when set to \"true\".", + "zh-CN": "值为 \"true\" 时禁用按钮。", + }, + }, +]; diff --git a/docs/widget-fields/scrollarea-content.ts b/docs/widget-fields/scrollarea-content.ts new file mode 100644 index 000000000..32aed3890 --- /dev/null +++ b/docs/widget-fields/scrollarea-content.ts @@ -0,0 +1,3 @@ +import { widgetFields, FieldData } from "./widget"; + +export const scrollareaContentFields: FieldData[] = [...widgetFields]; diff --git a/docs/widget-fields/scrollarea.ts b/docs/widget-fields/scrollarea.ts new file mode 100644 index 000000000..d1068a53a --- /dev/null +++ b/docs/widget-fields/scrollarea.ts @@ -0,0 +1,3 @@ +import { widgetFields, FieldData } from "./widget"; + +export const scrollareaFields: FieldData[] = [...widgetFields]; diff --git a/docs/widget-fields/scrollbar.ts b/docs/widget-fields/scrollbar.ts new file mode 100644 index 000000000..3de4c3327 --- /dev/null +++ b/docs/widget-fields/scrollbar.ts @@ -0,0 +1,14 @@ +import { widgetFields, FieldData } from "./widget"; + +export const scrollbarFields: FieldData[] = [ + ...widgetFields, + { + name: "orientation", + type: '"vertical" | "horizontal"', + default: '"vertical"', + description: { + en: "The scroll direction of the scrollbar.", + "zh-CN": "滚动条的滚动方向。", + }, + }, +]; diff --git a/docs/widget-fields/text-input.ts b/docs/widget-fields/text-input.ts new file mode 100644 index 000000000..31fc7dad9 --- /dev/null +++ b/docs/widget-fields/text-input.ts @@ -0,0 +1,14 @@ +import { widgetFields, FieldData } from "./widget"; + +export const textInputFields: FieldData[] = [ + ...widgetFields, + { + name: "placeholder", + type: "string", + default: "-", + description: { + en: "Placeholder text shown when the input is empty.", + "zh-CN": "输入为空时显示的占位文本。", + }, + }, +]; diff --git a/docs/widget-fields/text.ts b/docs/widget-fields/text.ts new file mode 100644 index 000000000..d67964c25 --- /dev/null +++ b/docs/widget-fields/text.ts @@ -0,0 +1,3 @@ +import { widgetFields, FieldData } from "./widget"; + +export const textFields: FieldData[] = [...widgetFields]; diff --git a/docs/widget-fields/widget.ts b/docs/widget-fields/widget.ts new file mode 100644 index 000000000..18133a1ba --- /dev/null +++ b/docs/widget-fields/widget.ts @@ -0,0 +1,27 @@ +export interface FieldData { + name: string; + type: string; + default: string; + description: { en: string; "zh-CN": string }; +} + +export const widgetFields: FieldData[] = [ + { + name: "className", + type: "string", + default: "-", + description: { + en: "CSS class name applied to the element.", + "zh-CN": "应用于元素的 CSS 类名。", + }, + }, + { + name: "children", + type: "any", + default: "-", + description: { + en: "Child elements.", + "zh-CN": "子元素。", + }, + }, +]; diff --git a/docs/zh-CN/devtools/css-modules.mdx b/docs/zh-CN/devtools/css-modules.mdx new file mode 100644 index 000000000..a688a927f --- /dev/null +++ b/docs/zh-CN/devtools/css-modules.mdx @@ -0,0 +1,29 @@ +# CSS Modules + +CSS Modules 为 TSX 组件创建局部作用域的 CSS 类,避免命名冲突并提高可维护性。 + +## 用法 + +创建 `.module.css` 后缀的文件: + +```css title="MyComponent.module.css" +.card { + border: 1px solid #eee; + border-radius: 4px; +} +``` + +在 `.tsx` 文件中导入: + +```tsx title="MyComponent.tsx" +import styles from "./MyComponent.module.css"; +``` + +在 JSX 中用 `styles` 对象替代字符串类名: + +```diff +- ++ +``` + +`@lcui/cli` 编译时会将 `.module.css` 转换为 C 标识符绑定,类名会自动生成唯一的 C 常量名,避免全局冲突。 diff --git a/docs/zh-CN/devtools/icon-library.mdx b/docs/zh-CN/devtools/icon-library.mdx new file mode 100644 index 000000000..1a444aa13 --- /dev/null +++ b/docs/zh-CN/devtools/icon-library.mdx @@ -0,0 +1,29 @@ +# 图标库 + +`@lcui/fluent-icons` 是专为 LCUI 适配的图标库,图标都来自 Microsoft 的 [fluentui-system-icons](https://github.com/microsoft/fluentui-system-icons) 项目。 + +## 安装 + +```sh +npm install @lcui/fluent-icons +``` + +## 选取图标 + +在 [flicon.io](https://www.flicon.io/) 网站中搜索和选取图标。以放大图标为例,英文名通常是 Zoom In。 + +fluentui-system-icons 的图标有 16、20、24 等几种尺寸可选,命名方式是"图标名+尺寸+风格"。`@lcui/fluent-icons` 的命名方式是"图标名+风格",当风格为 Regular 时可以省略它。 + +## 用法 + +```tsx +import { ZoomIn } from "@lcui/fluent-icons"; + + +``` + +默认尺寸是 20。如果图标尺寸固定且希望更好的渲染效果,可以指定 size 参数: + +```tsx + +``` diff --git a/docs/zh-CN/devtools/sass.mdx b/docs/zh-CN/devtools/sass.mdx new file mode 100644 index 000000000..a8d6a444d --- /dev/null +++ b/docs/zh-CN/devtools/sass.mdx @@ -0,0 +1,15 @@ +# Sass + +Sass 是一个流行的 CSS 预处理器,通过变量、嵌套规则和混合元素等功能扩展 CSS。 + +## 用法 + +`@lcui/cli` 已内置 Sass 预处理器,在编译 `.sass` 和 `.scss` 后缀的文件时会自动调用,无需额外安装或配置。 + +在 TSX 中直接导入 Sass 文件: + +```tsx title="MyComponent.tsx" +import "./MyComponent.scss"; +``` + +CLI 会将 Sass 文件编译为 CSS,再转换为 C 代码在运行时加载。 diff --git a/docs/zh-CN/devtools/tailwind-css.mdx b/docs/zh-CN/devtools/tailwind-css.mdx new file mode 100644 index 000000000..a91b66794 --- /dev/null +++ b/docs/zh-CN/devtools/tailwind-css.mdx @@ -0,0 +1,31 @@ +# Tailwind CSS + +Tailwind CSS 是一个功能类优先(Utility-First)的 CSS 框架,通过预定义的 CSS 类帮助开发者快速设置样式。相比传统 CSS 编写方式,无需新建 CSS 文件、编写规则和思考类名。 + +## 安装 + +```sh +npm install -D tailwindcss postcss @thedutchcoder/postcss-rem-to-px +``` + +## 配置 + +从 [lcui-quick-start](https://github.com/lcui-dev/lcui-quick-start) 模板项目复制以下文件到项目根目录: + +- `postcss.config.js` +- `tailwind.config.js` +- `app/global.css` + +`global.css` 中包含 Tailwind 的指令: + +```css title="app/global.css" +@tailwind base; +@tailwind components; +@tailwind utilities; +``` + +`@lcui/cli` 编译时会通过 PostCSS 链(postcss + tailwindcss + postcss-rem-to-px)处理 Tailwind 指令,生成最终的 CSS 输出。 + +:::tip +如果你不想将 global.css 放到 app 目录内,请更改 `tailwind.config.js` 中 `content` 配置项的路径匹配规则。 +::: diff --git a/docs/zh-CN/devtools/tsx-and-dev-tools.mdx b/docs/zh-CN/devtools/tsx-and-dev-tools.mdx new file mode 100644 index 000000000..aebd4655b --- /dev/null +++ b/docs/zh-CN/devtools/tsx-and-dev-tools.mdx @@ -0,0 +1,201 @@ +# TSX 与开发工具 + +配合 `@lcui/cli`,你可以用 TypeScript 搭配 JSX 语法编写声明式界面。CLI 会编译 TSX 为 C 代码,你无需手动编写部件树构建逻辑。 + +这样做的好处是:声明式编程方式使得状态绑定、事件绑定和资源引入更加简洁直观,在同一份文件中处理逻辑和视图可以减少上下文切换。 + +不过,`@lcui/react` 目前功能有限,你只能声明组件的状态、数据绑定和事件绑定。对于条件渲染、列表渲染等复杂操作,你仍需要编写 C 代码。 + +## 安装开发工具 + +`@lcui/cli` 是一个命令行工具,集成了 TypeScript 编译器、Sass 预处理器、资源文件加载器等功能。它依赖 Node.js 运行时环境: + +```sh +npm install -g @lcui/cli +``` + +## 预处理器工作原理 + +LCUI 采用预处理器方案:TSX 文件只在预处理阶段执行,不会成为运行时代码。你可以理解为 TSX 文件是配置文件,其中的 TypeScript 代码都是预处理指令。 + +预处理器按文件后缀名匹配合适的加载器,解析 TSX 代码、收集依赖、执行组件函数,然后根据返回的 JSX 元素和 Hook 调用结果生成 C 源文件。 + +## 用法概览 + +```tsx title="src/App.tsx" +import { useState, TextInput, Button } from "@lcui/react"; + +export default function App() { + const inputRef = { current: { value: "" } }; + const [name, setName] = useState("LCUI"); + + return ( + + + Hello, {name}! + + + + + ); +} +``` + +## React 库 + +`@lcui/react` 是针对 LCUI 特性和预处理器工作模式的用户界面库,提供预置组件、工具函数和 Hook 函数。 + +安装方法: + +```sh +npm install @lcui/react +``` + +### 组件函数 + +预处理器会执行组件函数,收集 `useState`、`useRef` 等产出的数据和返回的 JSX 元素,然后转换成 C 代码。 + +:::warning +- 组件函数返回值必须是一个 JSX 元素,不能是 ``、null、undefined、字符串、数字等对象。 +- 暂不支持声明和传递组件 props 参数。 +::: + +### 状态管理 + +`useState` 为组件声明状态变量: + +```tsx +import { useState } from "@lcui/react"; + +function MyComponent() { + const [age, setAge] = useState(23); + const [name, setName] = useState("Taylor"); + // ... +} +``` + +`useState` 返回一个数组: + +- 状态变量,初始值为你传给 `useState` 的值。 +- set 函数,允许你在响应交互时更改状态变量。 + +`useState` 会为组件的状态结构体添加成员,并在初始化函数中添加初始化代码: + +```c +/* 组件状态结构体 */ +struct MyComponent_state { + int age; + char *name; +}; + +/* 组件初始化函数中的代码 */ +_that->state.age = 23; +_that->state.name = strdup2("Taylor"); +``` + +状态的 set 函数会在当前作用域中插入 C 代码,例如 `setAge(30)` 会生成 `_that->state.age = 30;`。 + +:::warning +`useState` 的参数只能是 string、number 类型。 +::: + +### 引用 + +用 `$ref` 属性引用部件对象: + +```tsx + +``` + +之后在 C 代码中操作它: + +```c +ui_textinput_set_content(_that->refs.input, "hello"); +``` + +`$ref` 的值也可以是 `useRef` 返回的引用对象: + +```tsx +import { useRef } from "@lcui/react"; + +function MyComponent() { + const inputRef = useRef(); + + return ; +} +``` + +`useRef` 目前只实现了 TextInput 的 value 属性读写绑定: + +```tsx +inputRef.current.value = "World"; + + +``` + +:::warning +`@lcui/react` 的 `useRef` 和 React 的 `useRef` 不同,仅用于引用部件对象。 +::: + +### 响应事件 + +通过 `on + 事件名` 属性声明事件处理函数: + +```tsx + +``` + +预处理器会生成 C 代码绑定事件: + +```c +ui_widget_on(_that->refs.ref_0, "click", handleClick, w); +``` + +也可以将 JavaScript 函数与事件绑定: + +```tsx +import { useState, Text, Button } from "@lcui/react"; + +export default function Counter() { + const [text, setText] = useState("点我"); + + function handleClick() { + setText("你已点击"); + } + + return ( + + ); +} +``` + +预处理器会根据事件处理函数内部的代码执行结果,为其生成 C 语言版本的事件处理函数。 + +:::warning +暂时只支持在事件处理函数中执行状态变量的 set 函数,不支持访问事件对象,不支持执行其它语句。 +::: + +### 条件渲染 + +:::warning +暂不支持。 +我们正考虑使用 `` 组件实现条件渲染,参考 Solid.js 的 ``。 +::: + +### 渲染列表 + +:::warning +暂不支持。 +我们正考虑使用 `` 组件实现数组遍历,参考 Solid.js 的 ``。 +::: diff --git a/docs/zh-CN/handbook/customization.mdx b/docs/zh-CN/handbook/customization.mdx new file mode 100644 index 000000000..e27736db2 --- /dev/null +++ b/docs/zh-CN/handbook/customization.mdx @@ -0,0 +1,136 @@ +# 自定义 + +你可以创建全新的部件类型,也可以在现有部件基础上进行扩展。 + +## 创建自定义部件 + +使用 `ui_create_widget_prototype()` 注册新的部件类型: + +```c title="src/counter.c" +#include + +typedef struct { + int value; +} counter_data_t; + +static ui_widget_prototype_t *counter_proto; + +static void counter_init(ui_widget_t *w) +{ + counter_data_t *data; + ui_widget_t *text; + + data = ui_widget_add_data(w, counter_proto, sizeof(counter_data_t)); + data->value = 0; + + text = ui_create_widget("text"); + ui_text_set_content(text, "0"); + ui_widget_append(w, text); +} + +static void counter_destroy(ui_widget_t *w) +{ + /* 释放自有资源(如有) */ +} + +void register_counter_widget(void) +{ + counter_proto = ui_create_widget_prototype("counter", NULL); + counter_proto->init = counter_init; + counter_proto->destroy = counter_destroy; +} +``` + +使用这个自定义部件: + +```c title="src/main.c" +extern void register_counter_widget(void); + +int main(void) +{ + ui_widget_t *counter; + + lcui_init(); + register_counter_widget(); + + counter = ui_create_widget("counter"); + ui_widget_append(ui_root(), counter); + return lcui_main(); +} +``` + +## 扩展现有部件 + +把父类型名作为 `ui_create_widget_prototype()` 的第二个参数传入: + +```c title="src/icon_button.c" +static ui_widget_prototype_t *icon_button_proto; + +static void icon_button_init(ui_widget_t *w) +{ + /* 调用父类(button)的初始化逻辑 */ + icon_button_proto->proto->init(w); + ui_widget_add_class(w, "icon-button"); +} + +void register_icon_button(void) +{ + icon_button_proto = + ui_create_widget_prototype("icon-button", "button"); + icon_button_proto->init = icon_button_init; +} +``` + +:::warning +**父类的 `init` 必须手动调用。** LCUI 在创建子类型部件时不会自动调用父类型的 `init`。如果你忘记调用 `proto->proto->init(w)`,部件会缺少父类型的基础行为(例如 `button` 不会注册点击事件、不会设置默认样式)。 +::: + +## 部件生命周期 + +`ui_widget_prototype_t` 上有多个回调钩子,覆盖部件的各个生命周期阶段: + +- **`init`** — 部件创建时。负责初始化自有数据、子部件、事件绑定。 +- **`destroy`** — 部件销毁时。负责释放自有内存、解绑事件。 +- **`update`** — 部件需要更新时,接收 `ui_task_type_t` 参数标识更新类型(样式更新、属性更新等)。LCUI 内部在每帧更新循环中调用此钩子。 +- **`setattr`** — 设置 XML 属性时(用于响应属性变更)。 +- **`settext`** — 设置文本内容时。 +- **`sizehint`** — 估算部件在无外部约束时的自然尺寸约束(最小/最大内容尺寸)。布局引擎在计算子部件尺寸时会参考此结果。 +- **`resize`** — 部件尺寸变化时。接收新的内容区域宽高作为参数。 +- **`paint`** — 部件需要重绘时。用于自定义绘制逻辑。 + +## 自定义绘制 + +可以重写 `paint` 回调,在部件上绘制自定义图形: + +```c title="src/my_widget.c" +static void my_widget_paint(ui_widget_t *w, pd_context_t *paint_ctx, + ui_widget_actual_style_t *style) +{ + pd_canvas_t *canvas = paint_ctx->canvas; + pd_color_t color = pd_color_from_rgb(255, 0, 0); + pd_rect_t rect = { style->left, style->top, w->width, w->height }; + + pd_canvas_fill_rect(canvas, color, rect); +} + +static void register_my_widget(void) +{ + ui_widget_prototype_t *proto = + ui_create_widget_prototype("my-widget", NULL); + proto->paint = my_widget_paint; +} +``` + +:::warning +**`paint` 只负责绘制。** 部件尺寸估算由 `sizehint` 处理;不要在 `paint` 里修改部件尺寸或子部件树,否则可能触发无限循环。 +::: + +## 注意事项 + +:::warning +**`destroy` 回调要释放自有资源。** 如果自定义部件在 `init` 里分配了内存、打开了文件、订阅了系统事件(如 `lcui_settings_on_deserialize`),必须在 `destroy` 里做对称释放。 +::: + +:::warning +**自定义部件必须在 `lcui_init()` 之后、首次实例化之前注册。** 在 `main()` 开头立即调用你的 `register_xxx()` 函数是最稳妥的位置,可以确保所有使用方(XML 加载、路由实例化、TSX 编译结果)都能看到原型。 +::: diff --git a/docs/zh-CN/handbook/styling.mdx b/docs/zh-CN/handbook/styling.mdx new file mode 100644 index 000000000..9e87dc9d2 --- /dev/null +++ b/docs/zh-CN/handbook/styling.mdx @@ -0,0 +1,151 @@ +# 样式 + +用 CSS 给部件设置颜色、边框、内外边距、尺寸和布局。 + +## 设置方式 + +### 内联样式 + +用 `ui_widget_set_style_string()` 直接设置单个 CSS 属性: + +```c title="main.c" +ui_widget_t *w = ui_create_widget("text"); + +ui_widget_set_style_string(w, "color", "#336699"); +ui_widget_set_style_string(w, "font-size", "20px"); +ui_widget_set_style_string(w, "padding", "8px 16px"); +``` + +### CSS 类选择器 + +用 `ui_load_css_string()` 或 `ui_load_css_file()` 加载 CSS 规则,再用 `ui_widget_add_class()` 给部件加类名使其生效: + +```c title="main.c" +ui_load_css_file("styles.css"); + +ui_widget_t *w = ui_create_widget("text"); +ui_widget_add_class(w, "title"); +``` + +```css title="app/styles.css" +.title { + font-size: 24px; + font-weight: bold; + margin-bottom: 16px; +} +``` + +也可以用 `ui_load_css_string()` 从字符串加载 CSS 规则,第二个参数是来源标识,用于调试定位冲突规则: + +```c title="main.c" +ui_load_css_string(".title { font-size: 24px; }", "app.css"); +``` + +## 支持的 CSS 特性 + +LCUI 的 CSS 引擎实现了 Web 标准的一个子集。本节列出所有已支持的特性和它们支持的值;**未列出的特性默认不支持**。 + +### At Rules + +- **`@font-face`** — 加载外部字体 + +### 选择器 + +- `*`(通配符)、`type`、`#id`、`.class` +- 伪类 `:hover`、`:focus`、`:active`、`:first-child`、`:last-child` +- 不支持 `!important` + +### 单位 + +- `px`、`dp`、`sp`、`pt`、`%` + +### 属性 + +#### 布局 + +- **`display`** — `none`、`inline-block`、`block`、`flex`、`inline-flex`、`table`、`inline-table`、`table-row`、`table-cell` +- **`position`** — `static`、`relative`、`absolute` +- **`top` / `right` / `bottom` / `left`** — `` 或 `` 或 `auto` +- **`z-index`** — `auto` 或整数 +- **`box-sizing`** — `content-box`、`border-box` + +#### 盒模型 + +- **`width` / `height`** — ``、``、`auto` +- **`min-width` / `max-width` / `min-height` / `max-height`** — 同上 +- **`padding`** — 简写,1-4 个 `` 值(如 `8px`、`4px 8px`、`4px 8px 12px`、`4px 8px 12px 16px`) +- **`padding-top` / `padding-right` / `padding-bottom` / `padding-left`** — 长边属性 +- **`margin`** — 简写,同 padding +- **`margin-top` / `margin-right` / `margin-bottom` / `margin-left`** +- **`border`** — 简写 `1px solid #ccc`(width + style + color) +- **`border-color` / `border-width` / `border-style` / `border-radius`** — 同 padding 语法的多值简写 +- **`border-top` / `border-right` / `border-bottom` / `border-left`** — 单边简写 +- **`border-top-color` / `border-right-color` / `border-bottom-color` / `border-left-color`** +- **`border-top-width` / `border-right-width` / `border-bottom-width` / `border-left-width`** +- **`border-top-style` / `border-right-style` / `border-bottom-style` / `border-left-style`** +- **`border-top-left-radius` / `border-top-right-radius` / `border-bottom-left-radius` / `border-bottom-right-radius`** +- **`border-style` 可取值** — `none`、`solid` +- **`table-layout`** — `auto`、`fixed` +- **`border-spacing`** — `{1,2}` + +#### 背景 + +- **`background`** — 简写形式 `bg-image || bg-position || bg-size || repeat-style || color`(仅单图层) +- **`background-color`** — `` +- **`background-image`** — `none` 或 `` +- **`background-position`** — x y 两个值 +- **`background-position-x` / `background-position-y`** +- **`background-repeat`** — `` +- **`background-size`** — `` +- **`background-clip`** — `border-box`、`padding-box`、`content-box` + +#### Flexbox 布局 + +- **`flex`** — 简写(`flex-grow` + `flex-shrink` + `flex-basis`) +- **`flex-shrink` / `flex-grow` / `flex-basis`** +- **`flex-wrap`** — `nowrap`、`wrap` +- **`flex-direction`** — `row`、`column` +- **`justify-content`** — `flex-start`、`center`、`flex-end` +- **`align-items`** — `flex-start`、`center`、`flex-end`、`stretch` +- **`align-content`** — 同 justify-content 加 `space-between`、`space-around`、`space-evenly` +- **`gap`** — 简写,同时设 row-gap + column-gap +- **`row-gap` / `column-gap`** — `normal` 或 `` + +#### 排版 + +- **`font-face`** — (通过 `@font-face` 规则加载字体) +- **`font-family`** — ``(建议用内置别名如 `monospace`) +- **`font-size`** — `` +- **`font-style`** — `normal`、`italic`、`oblique` +- **`font-weight`** — `normal`、`bold`、`` +- **`text-align`** — `left`、`center`、`right` +- **`line-height`** — `normal` 或 `` 或 `` +- **`color`** — `` +- **`white-space`** — `normal`、`nowrap` +- **`word-break`** — `normal`、`break-all` +- **`content`** — `` 或 `none` + +#### 其他 + +- **`opacity`** — `` 或 `` +- **`visibility`** — `visible`、`hidden` +- **`pointer-events`** — `auto`、`none` +- **`box-shadow`** — `none` 或 ``(格式 `{2,4} && ?`) + +## 注意事项 + +:::warning +**`white-space: pre` 无效。** LCUI 的 `white-space` 仅实现 `normal` 和 `nowrap`。如需保留源代码前导缩进,把空格换成 U+00A0 (NBSP)。 +::: + +:::warning +**`overflow` 不裁切内容。** 要裁切或滚动子内容,改用 `scrollarea` 内置部件。 +::: + +:::warning +**`background` 简写不支持多图层。** 写 `background: url(a.png) no-repeat, url(b.png) center;` 这种多背景语法不会生效。请拆成 `background-image` / `background-position` 等分属性逐个设置。 +::: + +:::warning +**CSS 不支持继承。** 像 `color`、`font-family`、`font-size` 不会从父部件流向子部件。每个 `text` / `button` 等需要文本显示的部件都必须显式设置这些属性。 +::: diff --git a/docs/zh-CN/overview/about.mdx b/docs/zh-CN/overview/about.mdx new file mode 100644 index 000000000..d75dc65ee --- /dev/null +++ b/docs/zh-CN/overview/about.mdx @@ -0,0 +1,59 @@ +# 关于 LCUI + +LCUI 是一个用 C 语言编写的开源桌面图形界面库,旨在为 C 开发者提供简洁易用的 GUI 开发体验,同时融入 CSS 样式、声明式界面描述等 Web 开发技术降低学习门槛。 + +## 主要特性 + +- **跨平台** — 支持 Windows 和 Linux。 +- **全自绘组件** — 组件在多个平台中都能保持一致的外观和行为。 +- **DPI 自适应** — 自动在高分辨率屏幕上缩放 UI,保持清晰显示。 +- **自带 CSS 引擎** — 支持使用 CSS 来定义用户界面的样式和布局,对于有网页开发经验的人比较容易上手。 +- **提供现代化的开发工具** — 通过 `@lcui/cli` 工具,允许你使用 TypeScript 语言搭配 JSX 语法来编写用户界面。 + +## 适合谁使用 + +LCUI 适合这些开发者: + +- 想在桌面端继续使用 C 语言,但希望摆脱繁琐的 Win32 / X11 原生开发体验。 +- 已经熟悉 Web 前端(HTML、CSS),想把这套经验迁移到桌面应用。 +- 需要构建单窗口、界面内容简单的桌面小工具。 + +如果场景是大型商业桌面产品、游戏引擎或与操作系统深度集成的工具,LCUI 可能不是最合适的选择;这种场景下建议参考 Qt、GTK 或原生 API。 + +## 架构 + +LCUI 从上到下分为四层: + +### 应用层 + +你的业务代码:自定义组件、CSS 样式、TSX/JSX 代码、事件处理。这是唯一与你的项目领域相关的部分。 + +### LCUI 运行时 + +初始化、事件循环、应用生命周期管理。负责把应用跑起、派发事件、驱动渲染。 + +### UI 辅助层 + +UI XML 解析、UI Router 路由、光标管理、国际化(i18n)等辅助模块。把常用 UI 行为封装成可插拔的子系统。 + +### 基础设施层 + +YUtil(通用工具库)、PandaGL(2D 渲染引擎)、CSS 引擎、UI 部件系统、Thread / Worker 抽象。这些模块也可以单独使用。 + +平台层(Windows / Linux)负责窗口管理与输入事件。 + +## 许可证 + +LCUI 基于 MIT License 发布。详情请查看仓库根目录的 LICENSE.TXT。 + +## 如何参与贡献 + +欢迎贡献!在提交 Pull Request 之前,请先阅读仓库根目录的 CONTRIBUTING.md。 + +- **Bug 反馈** — 在 GitHub Issues 提交问题。 +- **功能建议** — 在 GitHub Discussions 发起讨论。 +- **代码贡献** — Fork 仓库,创建分支,然后提交 PR。 + +## 社区 + +遇到使用问题时,可以通过 GitHub Discussions 提问(建议使用 `Q&A` 标签)。同时我们也鼓励资深用户给新人提供帮助。 diff --git a/docs/zh-CN/overview/quick-start.mdx b/docs/zh-CN/overview/quick-start.mdx new file mode 100644 index 000000000..93c06b875 --- /dev/null +++ b/docs/zh-CN/overview/quick-start.mdx @@ -0,0 +1,44 @@ +# 快速开始 + +几分钟内上手 LCUI。 + +## 环境要求 + +- **操作系统** — Windows(推荐)或 Linux +- **Node.js** — 运行 `@lcui/cli` 工具 +- **xmake** — C/C++ 构建工具 +- **Git** — 下载和管理源码 + +## 安装 + +全局安装 LCUI CLI: + +```sh +npm install -g @lcui/cli +``` + +创建并运行你的第一个应用: + +```sh +lcui create my-app +cd my-app +lcui build +xmake run app +``` + +`lcui create` 会从 lcui-quick-start 模板仓库克隆一个最小项目,包含 xmake.lua 配置、示例代码和依赖。完成后运行 `lcui build` 编译 TSX 资源,再运行 `xmake run app` 启动应用。 + +## 下一步 + +- 查看样板项目(`lcui create` 生成的项目)中的代码和文件结构,了解 LCUI 应用的基本用法。 +- 阅读组件参考(Button、Text、TextInput、Anchor、ScrollArea),了解内置部件。 +- 阅读样式章节,学习如何用 CSS 为部件添加外观。 +- 阅读自定义章节,学习如何创建自定义部件。 +- 阅读 TSX 与开发工具章节,深入理解 `@lcui/react` 的用法和限制。 + +## 遇到问题? + +如果你在学习过程中遇到问题,可以通过以下途径获取帮助: + +- 在 GitHub Discussions 提问(建议使用 `Q&A` 标签)。 +- 在仓库根目录查看 CONTRIBUTING.md,了解如何参与贡献。 diff --git a/docs/zh-CN/widgets/anchor.mdx b/docs/zh-CN/widgets/anchor.mdx new file mode 100644 index 000000000..f600bc252 --- /dev/null +++ b/docs/zh-CN/widgets/anchor.mdx @@ -0,0 +1,14 @@ +# Anchor + +链接部件,用法与 HTML 的 `` 标签相同,用于打开外部 URL。 + + + +## 适用场景 + +- **适用** — 在页面中放置外部链接(点击后在系统浏览器中打开)。 +- **不适用** — 需要执行动作的按钮(用 `button`)。 + +## API 参考 + + diff --git a/docs/zh-CN/widgets/button.mdx b/docs/zh-CN/widgets/button.mdx new file mode 100644 index 000000000..22cb5059b --- /dev/null +++ b/docs/zh-CN/widgets/button.mdx @@ -0,0 +1,25 @@ +# Button + +可点击的按钮部件,通常用于触发某个操作。 + + + +## 适用场景 + +- **适用**:用户点击执行动作(提交表单、打开页面、切换状态) +- **适用**:工具栏、对话框、导航栏中的交互入口 +- **不适用**:不需要交互的纯文本展示(用 `text`) + +## 结构 + +导入部件: + +```tsx +import { Button } from "@lcui/react"; + + + + + {packageJson.version} + + GitHub + + + + ); +} diff --git a/examples/doc-viewer/app/components/sidebar.c b/examples/doc-viewer/app/components/sidebar.c new file mode 100644 index 000000000..df49b6941 --- /dev/null +++ b/examples/doc-viewer/app/components/sidebar.c @@ -0,0 +1,52 @@ +#include "sidebar.h" +#include "sidebar.tsx.h" + +typedef struct { + sidebar_react_t base; + // Add additional states to your component here + // ... +} sidebar_t; + +static void sidebar_init(ui_widget_t *w) +{ + ui_widget_add_data(w, sidebar_proto, sizeof(sidebar_t)); + sidebar_proto->proto->init(w); + sidebar_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + sidebar_update(w); +} + +static sidebar_t *sidebar_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, sidebar_proto); +} + +static void sidebar_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + sidebar_react_destroy(w); +} + +void sidebar_update(ui_widget_t *w) +{ + sidebar_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_sidebar(void) +{ + return ui_create_widget_with_prototype(sidebar_proto); +} + +void ui_register_sidebar(void) +{ + sidebar_init_prototype(); + sidebar_proto->init = sidebar_init; + sidebar_proto->destroy = sidebar_destroy; +} diff --git a/examples/doc-viewer/app/components/sidebar.css b/examples/doc-viewer/app/components/sidebar.css new file mode 100644 index 000000000..573594a31 --- /dev/null +++ b/examples/doc-viewer/app/components/sidebar.css @@ -0,0 +1,52 @@ +.sidebar-container { + width: 240px; + min-width: 240px; + height: 100%; + background-color: #f8f9fa; + border-right: 1px solid #e8e8e8; +} + +.sidebar { + flex-direction: column; + padding: 16px 0; +} + +/* Override .lang's display:block with flex for sidebar layout. */ +.en .sidebar.en, +.zh-CN .sidebar.zh-CN { + display: flex; +} + +.sidebar-section { + margin-bottom: 8px; +} + +.sidebar-heading { + padding: 4px 16px; + font-size: 12px; + font-weight: bold; + color: #999; +} + +.sidebar-list { + display: flex; + flex-direction: column; +} + +.sidebar-item { + display: block; + padding: 6px 16px 6px 24px; + color: #333; + font-size: 14px; +} + +.sidebar-item:hover { + background-color: #e6f4ff; + color: #1890ff; +} + +.sidebar-item.active { + background-color: #e6f4ff; + color: #1890ff; + font-weight: 500; +} diff --git a/examples/doc-viewer/app/components/sidebar.h b/examples/doc-viewer/app/components/sidebar.h new file mode 100644 index 000000000..5f86e9575 --- /dev/null +++ b/examples/doc-viewer/app/components/sidebar.h @@ -0,0 +1,9 @@ +#include + +void ui_register_sidebar(void); + +ui_widget_t *ui_create_sidebar(void); + +void sidebar_update(ui_widget_t *w); + +void ui_load_sidebar_resources(void); diff --git a/examples/doc-viewer/app/components/sidebar.json b/examples/doc-viewer/app/components/sidebar.json new file mode 100644 index 000000000..dd34d7625 --- /dev/null +++ b/examples/doc-viewer/app/components/sidebar.json @@ -0,0 +1,42 @@ +{ + "sidebar": [ + { + "slug": "overview", + "label": { "en": "Overview", "zh-CN": "概述" }, + "items": [ + { "slug": "quick-start", "label": { "en": "Quick Start", "zh-CN": "快速开始" } }, + { "slug": "about", "label": { "en": "About", "zh-CN": "关于" } } + ] + }, + { + "slug": "handbook", + "label": { "en": "Handbook", "zh-CN": "手册" }, + "items": [ + { "slug": "styling", "label": { "en": "Styling", "zh-CN": "样式" } }, + { "slug": "customization", "label": { "en": "Customization", "zh-CN": "自定义" } } + ] + }, + { + "slug": "devtools", + "label": { "en": "Dev Tools", "zh-CN": "开发工具" }, + "items": [ + { "slug": "tsx-and-dev-tools", "label": { "en": "TSX & @lcui/cli", "zh-CN": "TSX 与 @lcui/cli" } }, + { "slug": "css-modules", "label": { "en": "CSS Modules", "zh-CN": "CSS Modules" } }, + { "slug": "tailwind-css", "label": { "en": "Tailwind CSS", "zh-CN": "Tailwind CSS" } }, + { "slug": "sass", "label": { "en": "Sass", "zh-CN": "Sass" } }, + { "slug": "icon-library", "label": { "en": "Icon Library", "zh-CN": "图标库" } } + ] + }, + { + "slug": "widgets", + "label": { "en": "Widgets", "zh-CN": "组件" }, + "items": [ + { "slug": "anchor", "label": { "en": "Anchor", "zh-CN": "Anchor 锚点" } }, + { "slug": "button", "label": { "en": "Button", "zh-CN": "Button 按钮" } }, + { "slug": "scrollarea", "label": { "en": "ScrollArea", "zh-CN": "ScrollArea 滚动区域" } }, + { "slug": "text", "label": { "en": "Text", "zh-CN": "Text 文本" } }, + { "slug": "text-input", "label": { "en": "TextInput", "zh-CN": "TextInput 文本输入" } } + ] + } + ] +} diff --git a/examples/doc-viewer/app/components/sidebar.tsx b/examples/doc-viewer/app/components/sidebar.tsx new file mode 100644 index 000000000..a9146a73f --- /dev/null +++ b/examples/doc-viewer/app/components/sidebar.tsx @@ -0,0 +1,47 @@ +import { RouterLink, ScrollArea, ScrollAreaContent, Scrollbar, Text } from "@lcui/react"; +import "./sidebar.css"; +import sidebarData from "./sidebar.json"; + +interface SidebarItemData { + slug: string; + label: { en: string; "zh-CN": string }; +} + +interface SidebarSection { + slug: string; + label: { en: string; "zh-CN": string }; + items: SidebarItemData[]; +} + +export default function Sidebar() { + return ( + + {(["zh-CN", "en"] as const).map((locale) => ( + + {(sidebarData as { sidebar: SidebarSection[] }).sidebar.map( + (section: SidebarSection) => ( +
+ + {section.label[locale]} + +
+ {section.items.map((item: SidebarItemData) => ( + + {item.label[locale]} + + ))} +
+
+ ) + )} +
+ ))} + +
+ ); +} diff --git a/examples/doc-viewer/app/en/devtools/css-modules/page.c b/examples/doc-viewer/app/en/devtools/css-modules/page.c new file mode 100644 index 000000000..cc478f21e --- /dev/null +++ b/examples/doc-viewer/app/en/devtools/css-modules/page.c @@ -0,0 +1,57 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_devtools_css_modules_page_react_t base; + // Add additional states to your component here + // ... +} en_devtools_css_modules_page_t; + +static void en_devtools_css_modules_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_devtools_css_modules_page_proto, + sizeof(en_devtools_css_modules_page_t)); + + en_devtools_css_modules_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_devtools_css_modules_page_update(w); +} + +static en_devtools_css_modules_page_t *en_devtools_css_modules_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, en_devtools_css_modules_page_proto); +} + +static void en_devtools_css_modules_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_devtools_css_modules_page_react_destroy(w); +} + +void en_devtools_css_modules_page_update(ui_widget_t *w) +{ + en_devtools_css_modules_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_devtools_css_modules_page(void) +{ + return ui_create_widget_with_prototype( + en_devtools_css_modules_page_proto); +} + +void ui_register_en_devtools_css_modules_page(void) +{ + en_devtools_css_modules_page_init_prototype(); + en_devtools_css_modules_page_proto->init = + en_devtools_css_modules_page_init; + en_devtools_css_modules_page_proto->destroy = + en_devtools_css_modules_page_destroy; +} diff --git a/examples/doc-viewer/app/en/devtools/css-modules/page.h b/examples/doc-viewer/app/en/devtools/css-modules/page.h new file mode 100644 index 000000000..54e7ff8ca --- /dev/null +++ b/examples/doc-viewer/app/en/devtools/css-modules/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_devtools_css_modules_page(void); + +ui_widget_t *ui_create_en_devtools_css_modules_page(void); + +void en_devtools_css_modules_page_update(ui_widget_t *w); + +void ui_load_en_devtools_css_modules_page_resources(void); diff --git a/examples/doc-viewer/app/en/devtools/css-modules/page.tsx b/examples/doc-viewer/app/en/devtools/css-modules/page.tsx new file mode 100644 index 000000000..dc9e009a0 --- /dev/null +++ b/examples/doc-viewer/app/en/devtools/css-modules/page.tsx @@ -0,0 +1,49 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function CssModulesDocPage() { + return ( + +

CSS Modules

+

{`CSS Modules create locally scoped CSS classes for TSX components, avoiding naming conflicts and improving maintainability.`}

+ +

Usage

+

{`Create a file with the [bgcolor=#eee] .module.css [/bgcolor] suffix:`}

+ + + MyComponent.module.css + + + + {`[color=#953800].card[/color] {`} + {`  border: [color=#0550ae]1px[/color] solid [color=#0550ae]#eee[/color];`} + {`  border-radius: [color=#0550ae]4px[/color];`} + {`}`} + + +

{`Import it in a [bgcolor=#eee] .tsx [/bgcolor] file:`}

+ + + MyComponent.tsx + + + + {`[color=#cf222e]import[/color] styles [color=#cf222e]from[/color] [color=#0a3069]"./MyComponent.module.css"[/color];`} + + +

{`Use the [bgcolor=#eee] styles [/bgcolor] object instead of string class names in JSX:`}

+ + + DIFF + + + + {`- `} + {`+ `} + + +

{`During compilation, [bgcolor=#eee] @lcui/cli [/bgcolor] converts [bgcolor=#eee] .module.css [/bgcolor] into C identifier bindings, automatically generating unique C constant names for class names to avoid global conflicts.`}

+
+
+ ); +} diff --git a/examples/doc-viewer/app/en/devtools/icon-library/page.c b/examples/doc-viewer/app/en/devtools/icon-library/page.c new file mode 100644 index 000000000..654f6af08 --- /dev/null +++ b/examples/doc-viewer/app/en/devtools/icon-library/page.c @@ -0,0 +1,57 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_devtools_icon_library_page_react_t base; + // Add additional states to your component here + // ... +} en_devtools_icon_library_page_t; + +static void en_devtools_icon_library_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_devtools_icon_library_page_proto, + sizeof(en_devtools_icon_library_page_t)); + + en_devtools_icon_library_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_devtools_icon_library_page_update(w); +} + +static en_devtools_icon_library_page_t *en_devtools_icon_library_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, en_devtools_icon_library_page_proto); +} + +static void en_devtools_icon_library_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_devtools_icon_library_page_react_destroy(w); +} + +void en_devtools_icon_library_page_update(ui_widget_t *w) +{ + en_devtools_icon_library_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_devtools_icon_library_page(void) +{ + return ui_create_widget_with_prototype( + en_devtools_icon_library_page_proto); +} + +void ui_register_en_devtools_icon_library_page(void) +{ + en_devtools_icon_library_page_init_prototype(); + en_devtools_icon_library_page_proto->init = + en_devtools_icon_library_page_init; + en_devtools_icon_library_page_proto->destroy = + en_devtools_icon_library_page_destroy; +} diff --git a/examples/doc-viewer/app/en/devtools/icon-library/page.h b/examples/doc-viewer/app/en/devtools/icon-library/page.h new file mode 100644 index 000000000..0c31a9334 --- /dev/null +++ b/examples/doc-viewer/app/en/devtools/icon-library/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_devtools_icon_library_page(void); + +ui_widget_t *ui_create_en_devtools_icon_library_page(void); + +void en_devtools_icon_library_page_update(ui_widget_t *w); + +void ui_load_en_devtools_icon_library_page_resources(void); diff --git a/examples/doc-viewer/app/en/devtools/icon-library/page.tsx b/examples/doc-viewer/app/en/devtools/icon-library/page.tsx new file mode 100644 index 000000000..0b6179a88 --- /dev/null +++ b/examples/doc-viewer/app/en/devtools/icon-library/page.tsx @@ -0,0 +1,52 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function IconLibraryDocPage() { + return ( + +

Icon Library

+

{`[bgcolor=#eee] @lcui/fluent-icons [/bgcolor] is an icon library adapted for LCUI. All icons come from Microsoft's fluentui-system-icons project.`}

+ +

Installation

+ + + Shell + + + + {`npm install @lcui/fluent-icons`} + + +
+ +

Choosing icons

+

{`Search and select icons on flicon.io. For example, the zoom-in icon is typically named "Zoom In" in English.`}

+

{`fluentui-system-icons icons are available in sizes like 16, 20, and 24, named in the format "icon name + size + style". [bgcolor=#eee] @lcui/fluent-icons [/bgcolor] uses the naming format "icon name + style", and when the style is Regular it can be omitted.`}

+
+ +

Usage

+ + + TypeScript + + + + {`[color=#cf222e]import[/color] { [color=#8250df]ZoomIn[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/fluent-icons"[/color];`} + {` `} + {`[color=#116329]<[color=#0550ae]ZoomIn[/color] />[/color]`} + + +

{`The default size is 20. If the icon size is fixed and you want better rendering, specify the size parameter:`}

+ + + TypeScript + + + + {`<[color=#8250df]ZoomIn[/color] size={[color=#0550ae]32[/color]} />`} + + +
+
+ ); +} diff --git a/examples/doc-viewer/app/en/devtools/sass/page.c b/examples/doc-viewer/app/en/devtools/sass/page.c new file mode 100644 index 000000000..558d6111b --- /dev/null +++ b/examples/doc-viewer/app/en/devtools/sass/page.c @@ -0,0 +1,53 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_devtools_sass_page_react_t base; + // Add additional states to your component here + // ... +} en_devtools_sass_page_t; + +static void en_devtools_sass_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_devtools_sass_page_proto, + sizeof(en_devtools_sass_page_t)); + + en_devtools_sass_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_devtools_sass_page_update(w); +} + +static en_devtools_sass_page_t *en_devtools_sass_page_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, en_devtools_sass_page_proto); +} + +static void en_devtools_sass_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_devtools_sass_page_react_destroy(w); +} + +void en_devtools_sass_page_update(ui_widget_t *w) +{ + en_devtools_sass_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_devtools_sass_page(void) +{ + return ui_create_widget_with_prototype(en_devtools_sass_page_proto); +} + +void ui_register_en_devtools_sass_page(void) +{ + en_devtools_sass_page_init_prototype(); + en_devtools_sass_page_proto->init = en_devtools_sass_page_init; + en_devtools_sass_page_proto->destroy = en_devtools_sass_page_destroy; +} diff --git a/examples/doc-viewer/app/en/devtools/sass/page.h b/examples/doc-viewer/app/en/devtools/sass/page.h new file mode 100644 index 000000000..88b43289c --- /dev/null +++ b/examples/doc-viewer/app/en/devtools/sass/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_devtools_sass_page(void); + +ui_widget_t *ui_create_en_devtools_sass_page(void); + +void en_devtools_sass_page_update(ui_widget_t *w); + +void ui_load_en_devtools_sass_page_resources(void); diff --git a/examples/doc-viewer/app/en/devtools/sass/page.tsx b/examples/doc-viewer/app/en/devtools/sass/page.tsx new file mode 100644 index 000000000..b56ab5b7f --- /dev/null +++ b/examples/doc-viewer/app/en/devtools/sass/page.tsx @@ -0,0 +1,26 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function SassDocPage() { + return ( + +

Sass

+

{`Sass is a popular CSS preprocessor that extends CSS with variables, nesting rules, mixins, and more.`}

+ +

Usage

+

{`[bgcolor=#eee] @lcui/cli [/bgcolor] has a built-in Sass preprocessor that is automatically invoked when compiling [bgcolor=#eee] .sass [/bgcolor] and [bgcolor=#eee] .scss [/bgcolor] files — no additional installation or configuration needed.`}

+

{`Import Sass files directly in TSX:`}

+ + + MyComponent.tsx + + + + {`[color=#cf222e]import[/color] [color=#0a3069]"./MyComponent.scss"[/color];`} + + +

{`The CLI compiles Sass files into CSS, then converts them to C code for runtime loading.`}

+
+
+ ); +} diff --git a/examples/doc-viewer/app/en/devtools/tailwind-css/page.c b/examples/doc-viewer/app/en/devtools/tailwind-css/page.c new file mode 100644 index 000000000..6f9b27810 --- /dev/null +++ b/examples/doc-viewer/app/en/devtools/tailwind-css/page.c @@ -0,0 +1,57 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_devtools_tailwind_css_page_react_t base; + // Add additional states to your component here + // ... +} en_devtools_tailwind_css_page_t; + +static void en_devtools_tailwind_css_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_devtools_tailwind_css_page_proto, + sizeof(en_devtools_tailwind_css_page_t)); + + en_devtools_tailwind_css_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_devtools_tailwind_css_page_update(w); +} + +static en_devtools_tailwind_css_page_t *en_devtools_tailwind_css_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, en_devtools_tailwind_css_page_proto); +} + +static void en_devtools_tailwind_css_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_devtools_tailwind_css_page_react_destroy(w); +} + +void en_devtools_tailwind_css_page_update(ui_widget_t *w) +{ + en_devtools_tailwind_css_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_devtools_tailwind_css_page(void) +{ + return ui_create_widget_with_prototype( + en_devtools_tailwind_css_page_proto); +} + +void ui_register_en_devtools_tailwind_css_page(void) +{ + en_devtools_tailwind_css_page_init_prototype(); + en_devtools_tailwind_css_page_proto->init = + en_devtools_tailwind_css_page_init; + en_devtools_tailwind_css_page_proto->destroy = + en_devtools_tailwind_css_page_destroy; +} diff --git a/examples/doc-viewer/app/en/devtools/tailwind-css/page.h b/examples/doc-viewer/app/en/devtools/tailwind-css/page.h new file mode 100644 index 000000000..76fd5e195 --- /dev/null +++ b/examples/doc-viewer/app/en/devtools/tailwind-css/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_devtools_tailwind_css_page(void); + +ui_widget_t *ui_create_en_devtools_tailwind_css_page(void); + +void en_devtools_tailwind_css_page_update(ui_widget_t *w); + +void ui_load_en_devtools_tailwind_css_page_resources(void); diff --git a/examples/doc-viewer/app/en/devtools/tailwind-css/page.tsx b/examples/doc-viewer/app/en/devtools/tailwind-css/page.tsx new file mode 100644 index 000000000..265280eea --- /dev/null +++ b/examples/doc-viewer/app/en/devtools/tailwind-css/page.tsx @@ -0,0 +1,51 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function TailwindCssDocPage() { + return ( + +

Tailwind CSS

+

{`Tailwind CSS is a utility-first CSS framework that helps developers quickly apply styles through predefined CSS classes. Compared to traditional CSS, you don't need to create new CSS files, write rules, or think up class names.`}

+ +

Installation

+ + + Shell + + + + {`npm install -D tailwindcss postcss @thedutchcoder/postcss-rem-to-px`} + + +
+ +

Configuration

+

{`Copy the following files from the lcui-quick-start template project to your project root:`}

+
    +
  • {`[bgcolor=#eee] postcss.config.js [/bgcolor]`}
  • +
  • {`[bgcolor=#eee] tailwind.config.js [/bgcolor]`}
  • +
  • {`[bgcolor=#eee] app/global.css [/bgcolor]`}
  • +
+

{`[bgcolor=#eee] global.css [/bgcolor] contains the Tailwind directives:`}

+ + + app/global.css + + + + {`[color=#cf222e]@tailwind[/color] base;`} + {`[color=#cf222e]@tailwind[/color] components;`} + {`[color=#cf222e]@tailwind[/color] utilities;`} + + +

{`When compiling, [bgcolor=#eee] @lcui/cli [/bgcolor] processes Tailwind directives through the PostCSS chain (postcss + tailwindcss + postcss-rem-to-px) to generate the final CSS output.`}

+ + 技巧 + +

{`If you don't want to place global.css inside the app directory, change the [bgcolor=#eee] content [/bgcolor] path matching rules in [bgcolor=#eee] tailwind.config.js [/bgcolor].`}

+
+
+
+
+ ); +} diff --git a/examples/doc-viewer/app/en/devtools/tsx-and-dev-tools/page.c b/examples/doc-viewer/app/en/devtools/tsx-and-dev-tools/page.c new file mode 100644 index 000000000..83f7923fd --- /dev/null +++ b/examples/doc-viewer/app/en/devtools/tsx-and-dev-tools/page.c @@ -0,0 +1,57 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_devtools_tsx_and_dev_tools_page_react_t base; + // Add additional states to your component here + // ... +} en_devtools_tsx_and_dev_tools_page_t; + +static void en_devtools_tsx_and_dev_tools_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_devtools_tsx_and_dev_tools_page_proto, + sizeof(en_devtools_tsx_and_dev_tools_page_t)); + + en_devtools_tsx_and_dev_tools_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_devtools_tsx_and_dev_tools_page_update(w); +} + +static en_devtools_tsx_and_dev_tools_page_t * +en_devtools_tsx_and_dev_tools_page_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, en_devtools_tsx_and_dev_tools_page_proto); +} + +static void en_devtools_tsx_and_dev_tools_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_devtools_tsx_and_dev_tools_page_react_destroy(w); +} + +void en_devtools_tsx_and_dev_tools_page_update(ui_widget_t *w) +{ + en_devtools_tsx_and_dev_tools_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_devtools_tsx_and_dev_tools_page(void) +{ + return ui_create_widget_with_prototype( + en_devtools_tsx_and_dev_tools_page_proto); +} + +void ui_register_en_devtools_tsx_and_dev_tools_page(void) +{ + en_devtools_tsx_and_dev_tools_page_init_prototype(); + en_devtools_tsx_and_dev_tools_page_proto->init = + en_devtools_tsx_and_dev_tools_page_init; + en_devtools_tsx_and_dev_tools_page_proto->destroy = + en_devtools_tsx_and_dev_tools_page_destroy; +} diff --git a/examples/doc-viewer/app/en/devtools/tsx-and-dev-tools/page.h b/examples/doc-viewer/app/en/devtools/tsx-and-dev-tools/page.h new file mode 100644 index 000000000..dc8669bda --- /dev/null +++ b/examples/doc-viewer/app/en/devtools/tsx-and-dev-tools/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_devtools_tsx_and_dev_tools_page(void); + +ui_widget_t *ui_create_en_devtools_tsx_and_dev_tools_page(void); + +void en_devtools_tsx_and_dev_tools_page_update(ui_widget_t *w); + +void ui_load_en_devtools_tsx_and_dev_tools_page_resources(void); diff --git a/examples/doc-viewer/app/en/devtools/tsx-and-dev-tools/page.tsx b/examples/doc-viewer/app/en/devtools/tsx-and-dev-tools/page.tsx new file mode 100644 index 000000000..f1a9de44c --- /dev/null +++ b/examples/doc-viewer/app/en/devtools/tsx-and-dev-tools/page.tsx @@ -0,0 +1,260 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function TsxAndDevToolsDocPage() { + return ( + +

TSX & Dev Tools

+

{`With [bgcolor=#eee] @lcui/cli [/bgcolor], you can write declarative UIs using TypeScript with JSX syntax. The CLI compiles TSX into C code, so you don't need to manually write widget tree construction logic.`}

+

{`The benefit is that the declarative approach makes state binding, event binding, and resource imports more concise and intuitive. Handling logic and view in the same file reduces context switching.`}

+

{`However, [bgcolor=#eee] @lcui/react [/bgcolor] currently has limited capabilities — you can only declare component state, data bindings, and event bindings. For complex operations like conditional rendering or list rendering, you still need to write C code.`}

+ +

Installing dev tools

+

{`[bgcolor=#eee] @lcui/cli [/bgcolor] is a command-line tool that integrates a TypeScript compiler, Sass preprocessor, resource file loader, and more. It requires a Node.js runtime:`}

+ + + Shell + + + + {`npm install -g @lcui/cli`} + + +
+ +

How the preprocessor works

+

{`LCUI uses a preprocessor approach: TSX files are only executed during preprocessing and do not become runtime code. You can think of TSX files as configuration files, where the TypeScript code acts as preprocessing directives.`}

+

{`The preprocessor matches the appropriate loader by file extension, parses the TSX code, collects dependencies, executes component functions, and then generates C source files based on the returned JSX elements and Hook call results.`}

+
+ +

Usage overview

+ + + src/App.tsx + + + + {`[color=#cf222e]import[/color] { useState, [color=#8250df]TextInput[/color], [color=#8250df]Button[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]const[/color] inputRef = { [color=#0550ae]current[/color]: { [color=#0550ae]value[/color]: [color=#0a3069]""[/color] } };`} + {`  [color=#cf222e]const[/color] \\[name, setName] = [color=#8250df]useState[/color]([color=#0a3069]"LCUI"[/color]);`} + {` `} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]Widget[/color] [color=#0550ae]className[/color]=[color=#0a3069]"container"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]Widget[/color] [color=#0550ae]className[/color]=[color=#0a3069]"flex flex-col items-center pt-6"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]Text[/color] [color=#0550ae]className[/color]=[color=#0a3069]"my-4 text-2xl text-center"[/color]>[/color]Hello, {name}![color=#116329][/color]`} + {`        [color=#116329]<[color=#0550ae]TextInput[/color][/color]`} + {`[color=#116329] \$[color=#0550ae]ref[/color]=[color=#0a3069]{inputRef}[/color][/color]`} + {`[color=#116329] [color=#0550ae]className[/color]=[color=#0a3069]"mt-2"[/color][/color]`} + {`[color=#116329] [color=#0550ae]placeholder[/color]=[color=#0a3069]"Please input..."[/color][/color]`} + {`[color=#116329] />[/color]`} + {`        [color=#116329]<[color=#0550ae]Button[/color][/color]`} + {`[color=#116329] [color=#0550ae]className[/color]=[color=#0a3069]"mt-2"[/color][/color]`} + {`[color=#116329] [color=#0550ae]onClick[/color]=[color=#0a3069]{()[/color] =>[/color] setName(inputRef.current.value)}`} + {`        >`} + {`          Change`} + {`        [color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + + +
+ +

React library

+

{`[bgcolor=#eee] @lcui/react [/bgcolor] is a UI library tailored for LCUI's features and preprocessor workflow, providing built-in components, utility functions, and hooks.`}

+

{`Installation:`}

+ + + Shell + + + + {`npm install @lcui/react`} + + +

Component functions

+

{`The preprocessor executes component functions, collects data from [bgcolor=#eee] useState [/bgcolor], [bgcolor=#eee] useRef [/bgcolor], etc. and the returned JSX elements, then converts them into C code.`}

+ + 注意 + +
    +
  • {`Component function return values must be a single JSX element — [bgcolor=#eee] [/bgcolor], null, undefined, strings, numbers, or other objects are not supported.`}
  • +
  • {`Declaring and passing component props is not yet supported.`}
  • +
+
+
+

State management

+

{`[bgcolor=#eee] useState [/bgcolor] declares a state variable for a component:`}

+ + + TypeScript + + + + {`[color=#cf222e]import[/color] { useState } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]function[/color] [color=#8250df]MyComponent[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]const[/color] \\[age, setAge] = [color=#8250df]useState[/color]([color=#0550ae]23[/color]);`} + {`  [color=#cf222e]const[/color] \\[name, setName] = [color=#8250df]useState[/color]([color=#0a3069]"Taylor"[/color]);`} + {`  [color=#6e7781]// ...[/color]`} + {`}`} + + +

{`[bgcolor=#eee] useState [/bgcolor] returns an array:`}

+
    +
  • {`The state variable, initialized to the value passed to [bgcolor=#eee] useState [/bgcolor].`}
  • +
  • {`A set function, which lets you change the state variable in response to interactions.`}
  • +
+

{`[bgcolor=#eee] useState [/bgcolor] adds a member to the component's state struct and generates initialization code in the init function:`}

+ + + C + + + + {`[color=#6e7781]/* Component state struct */[/color]`} + {`[color=#cf222e]struct[/color] [color=#8250df]MyComponent_state[/color] {`} + {`  [color=#953800]int[/color] age;`} + {`  [color=#953800]char[/color] *name;`} + {`};`} + {` `} + {`[color=#6e7781]/* Code in component init function */[/color]`} + {`_that->state.age = [color=#0550ae]23[/color];`} + {`_that->state.name = strdup2([color=#0a3069]"Taylor"[/color]);`} + + +

{`The state's set function inserts C code in the current scope, e.g. [bgcolor=#eee] setAge(30) [/bgcolor] generates [bgcolor=#eee] _that->state.age = 30; [/bgcolor].`}

+ + 注意 + +

{`[bgcolor=#eee] useState [/bgcolor] parameters can only be string or number types.`}

+
+
+

Refs

+

{`Use the [bgcolor=#eee] \$ref [/bgcolor] attribute to reference a widget object:`}

+ + + TypeScript + + + + {`<[color=#8250df]TextInput[/color] \$ref=[color=#0a3069]"input"[/color] />`} + + +

{`Then operate on it in C code:`}

+ + + C + + + + {`ui_textinput_set_content(_that->refs.input, [color=#0a3069]"hello"[/color]);`} + + +

{`The [bgcolor=#eee] \$ref [/bgcolor] value can also be a reference object returned by [bgcolor=#eee] useRef [/bgcolor]:`}

+ + + TypeScript + + + + {`[color=#cf222e]import[/color] { useRef } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]function[/color] [color=#8250df]MyComponent[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]const[/color] inputRef = [color=#8250df]useRef[/color]();`} + {` `} + {`  [color=#cf222e]return[/color] [color=#116329]<[color=#0550ae]TextInput[/color] \$[color=#0550ae]ref[/color]=[color=#0a3069]{inputRef}[/color] />[/color];`} + {`}`} + + +

{`[bgcolor=#eee] useRef [/bgcolor] currently only implements value property read/write binding for TextInput:`}

+ + + TypeScript + + + + {`inputRef.[color=#0550ae]current[/color].[color=#0550ae]value[/color] = [color=#0a3069]"World"[/color];`} + {` `} + {`[color=#116329]<[color=#0550ae]Button[/color] [color=#0550ae]onClick[/color]=[color=#0a3069]{()[/color] =>[/color] setName(inputRef.current.value)}>Click[color=#116329][/color]`} + + + + 注意 + +

{`[bgcolor=#eee] @lcui/react [/bgcolor]'s [bgcolor=#eee] useRef [/bgcolor] is different from React's [bgcolor=#eee] useRef [/bgcolor] — it is only for referencing widget objects.`}

+
+
+

Responding to events

+

{`Declare event handlers using the [bgcolor=#eee] on + event name [/bgcolor] attribute:`}

+ + + TypeScript + + + + {`<[color=#8250df]Button[/color] onClick=[color=#0a3069]"handleClick"[/color]>[color=#8250df]Click[/color] me`} + + +

{`The preprocessor generates C code to bind the event:`}

+ + + C + + + + {`ui_widget_on(_that->refs.ref_0, [color=#0a3069]"click"[/color], handleClick, w);`} + + +

{`You can also bind JavaScript functions to events:`}

+ + + TypeScript + + + + {`[color=#cf222e]import[/color] { useState, [color=#8250df]Text[/color], [color=#8250df]Button[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]Counter[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]const[/color] \\[text, setText] = [color=#8250df]useState[/color]([color=#0a3069]"Click me"[/color]);`} + {` `} + {`  [color=#cf222e]function[/color] [color=#8250df]handleClick[/color]([color=#0550ae][/color]) {`} + {`    [color=#8250df]setText[/color]([color=#0a3069]"You clicked"[/color]);`} + {`  }`} + {` `} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]Button[/color] [color=#0550ae]onClick[/color]=[color=#0a3069]{handleClick}[/color]>[/color]`} + {`      {text}`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + + +

{`The preprocessor generates a C-language version of the event handler based on the code executed inside the handler function.`}

+ + 注意 + +

{`Currently, only state variable set functions can be called inside event handlers. Accessing the event object or executing other statements is not supported.`}

+
+
+

Conditional rendering

+ + 注意 + +

{`Not yet supported. We are considering implementing conditional rendering with a [bgcolor=#eee] [/bgcolor] component, inspired by Solid.js's [bgcolor=#eee] [/bgcolor].`}

+
+
+

Rendering lists

+ + 注意 + +

{`Not yet supported. We are considering implementing array iteration with a [bgcolor=#eee] [/bgcolor] component, inspired by Solid.js's [bgcolor=#eee] [/bgcolor].`}

+
+
+
+
+ ); +} diff --git a/examples/doc-viewer/app/en/handbook/composition/page.c b/examples/doc-viewer/app/en/handbook/composition/page.c new file mode 100644 index 000000000..42e3574b5 --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/composition/page.c @@ -0,0 +1,56 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_handbook_composition_page_react_t base; + // Add additional states to your component here + // ... +} en_handbook_composition_page_t; + +static void en_handbook_composition_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_handbook_composition_page_proto, + sizeof(en_handbook_composition_page_t)); + en_handbook_composition_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_handbook_composition_page_update(w); +} + +static en_handbook_composition_page_t *en_handbook_composition_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, en_handbook_composition_page_proto); +} + +static void en_handbook_composition_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_handbook_composition_page_react_destroy(w); +} + +void en_handbook_composition_page_update(ui_widget_t *w) +{ + en_handbook_composition_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_handbook_composition_page(void) +{ + return ui_create_widget_with_prototype( + en_handbook_composition_page_proto); +} + +void ui_register_en_handbook_composition_page(void) +{ + en_handbook_composition_page_init_prototype(); + en_handbook_composition_page_proto->init = + en_handbook_composition_page_init; + en_handbook_composition_page_proto->destroy = + en_handbook_composition_page_destroy; +} diff --git a/examples/doc-viewer/app/en/handbook/composition/page.h b/examples/doc-viewer/app/en/handbook/composition/page.h new file mode 100644 index 000000000..1a9b159c4 --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/composition/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_handbook_composition_page(void); + +ui_widget_t *ui_create_en_handbook_composition_page(void); + +void en_handbook_composition_page_update(ui_widget_t *w); + +void ui_load_en_handbook_composition_page_resources(void); diff --git a/examples/doc-viewer/app/en/handbook/composition/page.tsx b/examples/doc-viewer/app/en/handbook/composition/page.tsx new file mode 100644 index 000000000..a701923e8 --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/composition/page.tsx @@ -0,0 +1,238 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function CompositionDocPage() { + return ( + +

Composition

+

{`Building complex UIs means composing many widgets together. LCUI provides three ways to do this.`}

+ +

Building widget hierarchies in C

+

{`Use [bgcolor=#eee] ui_widget_append() [/bgcolor] to nest widgets:`}

+ + + C + + + + {`[color=#953800]ui_widget_t[/color] *root = ui_root();`} + {`[color=#953800]ui_widget_t[/color] *container = ui_create_widget([color=#0550ae]NULL[/color]);`} + {`[color=#953800]ui_widget_t[/color] *title = ui_create_widget([color=#0a3069]"text"[/color]);`} + {`[color=#953800]ui_widget_t[/color] *btn = ui_create_widget([color=#0a3069]"button"[/color]);`} + {` `} + {`ui_text_set_content(title, [color=#0a3069]"My App"[/color]);`} + {`ui_button_set_text(btn, [color=#0a3069]"Click me"[/color]);`} + {` `} + {`ui_widget_append(container, title);`} + {`ui_widget_append(container, btn);`} + {`ui_widget_append(root, container);`} + + +
+ +

Composing with XML

+

{`Define your entire widget tree in XML:`}

+ + + XML + + + + {`[color=#6e7781][/color]`} + {`[color=#116329]<[color=#0550ae]lcui-app[/color]>[/color]`} + {`  [color=#116329]<[color=#0550ae]ui[/color]>[/color]`} + {`    [color=#116329]<[color=#0550ae]widget[/color] [color=#0550ae]style[/color]=[color=#0a3069]"display: flex; flex-direction: column; padding: 16px;"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]text[/color] [color=#0550ae]style[/color]=[color=#0a3069]"font-size: 24px; font-weight: bold;"[/color]>[/color]My App[color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]button[/color] [color=#0550ae]id[/color]=[color=#0a3069]"action-btn"[/color]>[/color]Click me[color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  [color=#116329][/color]`} + {`[color=#116329][/color]`} + + +

{`Load it at runtime:`}

+ + + C + + + + {`lcui_init();`} + {`ui_load_xml_file([color=#0a3069]"ui.xml"[/color]);`} + {` `} + {`[color=#953800]ui_widget_t[/color] *btn = ui_get_widget([color=#0a3069]"action-btn"[/color]);`} + {`[color=#cf222e]if[/color] (btn) {`} + {`        ui_widget_on(btn, [color=#0a3069]"click"[/color], on_click, [color=#0550ae]NULL[/color]);`} + {`}`} + + +
+ +

Composing with TSX

+

{`With [bgcolor=#eee] @lcui/cli [/bgcolor] you can write reusable components in TSX:`}

+ + + TypeScript + + + + {`[color=#6e7781]// components/Card.tsx[/color]`} + {`[color=#cf222e]import[/color] { [color=#8250df]Button[/color], [color=#8250df]Text[/color], [color=#cf222e]type[/color] [color=#8250df]ReactNode[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]interface[/color] [color=#8250df]CardProps[/color] {`} + {`  [color=#0550ae]title[/color]: [color=#953800]string[/color];`} + {`  [color=#0550ae]children[/color]?: [color=#8250df]ReactNode[/color];`} + {`}`} + {` `} + {`[color=#cf222e]function[/color] [color=#8250df]Card[/color]([color=#0550ae]{ title, children }: [color=#8250df]CardProps[/color][/color]) {`} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]style[/color]=[color=#0a3069]{{[/color] [color=#0550ae]border:[/color] "[color=#0550ae]1px[/color] [color=#0550ae]solid[/color] #[color=#0550ae]ccc[/color]", [color=#0550ae]padding:[/color] [color=#0550ae]16[/color], [color=#0550ae]borderRadius:[/color] [color=#0550ae]4[/color] }}>[/color]`} + {`      [color=#116329]<[color=#0550ae]Text[/color] [color=#0550ae]style[/color]=[color=#0a3069]{{[/color] [color=#0550ae]fontWeight:[/color] "[color=#0550ae]bold[/color]", [color=#0550ae]fontSize:[/color] [color=#0550ae]18[/color] }}>[/color]{title}[color=#116329][/color]`} + {`      {children}`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + {` `} + {`[color=#6e7781]// App.tsx[/color]`} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]Card[/color] [color=#0550ae]title[/color]=[color=#0a3069]"Welcome"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]Button[/color]>[/color]Get started[color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + + +
+ +

Event handling

+

{`Widgets communicate through events. Bind a handler with [bgcolor=#eee] ui_widget_on() [/bgcolor]:`}

+ + + C + + + + {`[color=#953800]static[/color] [color=#953800]void[/color] [color=#8250df]on_button_click[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w, [color=#953800]ui_event_t[/color] *e, [color=#953800]void[/color] *arg)[/color]`} + {`{`} + {`        [color=#953800]ui_widget_t[/color] *label = arg;`} + {`        ui_text_set_content(label, [color=#0a3069]"Button was clicked!"[/color]);`} + {`}`} + {` `} + {`[color=#953800]ui_widget_t[/color] *btn = ui_create_widget([color=#0a3069]"button"[/color]);`} + {`[color=#953800]ui_widget_t[/color] *label = ui_create_widget([color=#0a3069]"text"[/color]);`} + {` `} + {`ui_button_set_text(btn, [color=#0a3069]"Click me"[/color]);`} + {`ui_widget_on(btn, [color=#0a3069]"click"[/color], on_button_click, label);`} + + +

{`Common events:`}

+ + + + {`Event`} + + + {`Trigger`} + + + + + {`[bgcolor=#eee] click [/bgcolor]`} + + + {`Mouse click`} + + + + + {`[bgcolor=#eee] mousedown [/bgcolor]`} + + + {`Mouse button pressed`} + + + + + {`[bgcolor=#eee] mouseup [/bgcolor]`} + + + {`Mouse button released`} + + + + + {`[bgcolor=#eee] mousemove [/bgcolor]`} + + + {`Mouse moved over widget`} + + + + + {`[bgcolor=#eee] mouseenter [/bgcolor]`} + + + {`Mouse enters widget area`} + + + + + {`[bgcolor=#eee] mouseleave [/bgcolor]`} + + + {`Mouse leaves widget area`} + + + + + {`[bgcolor=#eee] keydown [/bgcolor]`} + + + {`Key pressed`} + + + + + {`[bgcolor=#eee] keyup [/bgcolor]`} + + + {`Key released`} + + + + + {`[bgcolor=#eee] focus [/bgcolor]`} + + + {`Widget gains focus`} + + + + + {`[bgcolor=#eee] blur [/bgcolor]`} + + + {`Widget loses focus`} + + + + + {`[bgcolor=#eee] change [/bgcolor]`} + + + {`Value changed (inputs)`} + + + + + {`[bgcolor=#eee] destroy [/bgcolor]`} + + + {`Widget destroyed`} + + + +
+
+ ); +} diff --git a/examples/doc-viewer/app/en/handbook/css-modules/page.c b/examples/doc-viewer/app/en/handbook/css-modules/page.c new file mode 100644 index 000000000..617ff2ee4 --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/css-modules/page.c @@ -0,0 +1,57 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_handbook_css_modules_page_react_t base; + // Add additional states to your component here + // ... +} en_handbook_css_modules_page_t; + +static void en_handbook_css_modules_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_handbook_css_modules_page_proto, + sizeof(en_handbook_css_modules_page_t)); + + en_handbook_css_modules_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_handbook_css_modules_page_update(w); +} + +static en_handbook_css_modules_page_t *en_handbook_css_modules_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, en_handbook_css_modules_page_proto); +} + +static void en_handbook_css_modules_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_handbook_css_modules_page_react_destroy(w); +} + +void en_handbook_css_modules_page_update(ui_widget_t *w) +{ + en_handbook_css_modules_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_handbook_css_modules_page(void) +{ + return ui_create_widget_with_prototype( + en_handbook_css_modules_page_proto); +} + +void ui_register_en_handbook_css_modules_page(void) +{ + en_handbook_css_modules_page_init_prototype(); + en_handbook_css_modules_page_proto->init = + en_handbook_css_modules_page_init; + en_handbook_css_modules_page_proto->destroy = + en_handbook_css_modules_page_destroy; +} diff --git a/examples/doc-viewer/app/en/handbook/css-modules/page.h b/examples/doc-viewer/app/en/handbook/css-modules/page.h new file mode 100644 index 000000000..4a632ea7a --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/css-modules/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_handbook_css_modules_page(void); + +ui_widget_t *ui_create_en_handbook_css_modules_page(void); + +void en_handbook_css_modules_page_update(ui_widget_t *w); + +void ui_load_en_handbook_css_modules_page_resources(void); diff --git a/examples/doc-viewer/app/en/handbook/css-modules/page.tsx b/examples/doc-viewer/app/en/handbook/css-modules/page.tsx new file mode 100644 index 000000000..ffc31f624 --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/css-modules/page.tsx @@ -0,0 +1,49 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function CssModulesDocPage() { + return ( + +

CSS Modules

+

{`CSS Modules create locally scoped CSS classes for TSX components, avoiding naming conflicts and improving maintainability.`}

+ +

Usage

+

{`Create a file with the [bgcolor=#eee] .module.css [/bgcolor] suffix:`}

+ + + MyComponent.module.css + + + + {`[color=#953800].card[/color] {`} + {`  border: [color=#0550ae]1px[/color] solid [color=#0550ae]#eee[/color];`} + {`  border-radius: [color=#0550ae]4px[/color];`} + {`}`} + + +

{`Import it in a [bgcolor=#eee] .tsx [/bgcolor] file:`}

+ + + MyComponent.tsx + + + + {`[color=#cf222e]import[/color] styles [color=#cf222e]from[/color] [color=#0a3069]"./MyComponent.module.css"[/color];`} + + +

{`Use the [bgcolor=#eee] styles [/bgcolor] object instead of string class names in JSX:`}

+ + + DIFF + + + + {`- `} + {`+ `} + + +

{`During compilation, [bgcolor=#eee] @lcui/cli [/bgcolor] converts [bgcolor=#eee] .module.css [/bgcolor] into C identifier bindings, automatically generating unique C constant names for class names to avoid global conflicts.`}

+
+
+ ); +} diff --git a/examples/doc-viewer/app/en/handbook/customization/page.c b/examples/doc-viewer/app/en/handbook/customization/page.c new file mode 100644 index 000000000..a87d0114b --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/customization/page.c @@ -0,0 +1,56 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_handbook_customization_page_react_t base; + // Add additional states to your component here + // ... +} en_handbook_customization_page_t; + +static void en_handbook_customization_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_handbook_customization_page_proto, + sizeof(en_handbook_customization_page_t)); + en_handbook_customization_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_handbook_customization_page_update(w); +} + +static en_handbook_customization_page_t *en_handbook_customization_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, en_handbook_customization_page_proto); +} + +static void en_handbook_customization_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_handbook_customization_page_react_destroy(w); +} + +void en_handbook_customization_page_update(ui_widget_t *w) +{ + en_handbook_customization_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_handbook_customization_page(void) +{ + return ui_create_widget_with_prototype( + en_handbook_customization_page_proto); +} + +void ui_register_en_handbook_customization_page(void) +{ + en_handbook_customization_page_init_prototype(); + en_handbook_customization_page_proto->init = + en_handbook_customization_page_init; + en_handbook_customization_page_proto->destroy = + en_handbook_customization_page_destroy; +} diff --git a/examples/doc-viewer/app/en/handbook/customization/page.h b/examples/doc-viewer/app/en/handbook/customization/page.h new file mode 100644 index 000000000..526615168 --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/customization/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_handbook_customization_page(void); + +ui_widget_t *ui_create_en_handbook_customization_page(void); + +void en_handbook_customization_page_update(ui_widget_t *w); + +void ui_load_en_handbook_customization_page_resources(void); diff --git a/examples/doc-viewer/app/en/handbook/customization/page.tsx b/examples/doc-viewer/app/en/handbook/customization/page.tsx new file mode 100644 index 000000000..3cb5f75b2 --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/customization/page.tsx @@ -0,0 +1,173 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function CustomizationDocPage() { + return ( + +

Customization

+

{`You can create entirely new widget types or extend existing ones.`}

+ +

Creating a custom widget

+

{`Use [bgcolor=#eee] ui_create_widget_prototype() [/bgcolor] to register a new widget type:`}

+ + + src/counter.c + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#cf222e]typedef[/color] [color=#cf222e]struct[/color] {`} + {`        [color=#953800]int[/color] value;`} + {`} [color=#953800]counter_data_t[/color];`} + {` `} + {`[color=#953800]static[/color] [color=#953800]ui_widget_prototype_t[/color] *counter_proto;`} + {` `} + {`[color=#953800]static[/color] [color=#953800]void[/color] [color=#8250df]counter_init[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w)[/color]`} + {`{`} + {`        [color=#953800]counter_data_t[/color] *data;`} + {`        [color=#953800]ui_widget_t[/color] *text;`} + {` `} + {`        data = ui_widget_add_data(w, counter_proto, [color=#cf222e]sizeof[/color]([color=#953800]counter_data_t[/color]));`} + {`        data->value = [color=#0550ae]0[/color];`} + {` `} + {`        text = ui_create_widget([color=#0a3069]"text"[/color]);`} + {`        ui_text_set_content(text, [color=#0a3069]"0"[/color]);`} + {`        ui_widget_append(w, text);`} + {`}`} + {` `} + {`[color=#953800]static[/color] [color=#953800]void[/color] [color=#8250df]counter_destroy[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w)[/color]`} + {`{`} + {`        [color=#6e7781]/* Release owned resources (if any) */[/color]`} + {`}`} + {` `} + {`[color=#953800]void[/color] [color=#8250df]register_counter_widget[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        counter_proto = ui_create_widget_prototype([color=#0a3069]"counter"[/color], [color=#0550ae]NULL[/color]);`} + {`        counter_proto->init = counter_init;`} + {`        counter_proto->destroy = counter_destroy;`} + {`}`} + + +

{`Use the custom widget:`}

+ + + src/main.c + + + + {`[color=#cf222e]extern[/color] [color=#953800]void[/color] [color=#8250df]register_counter_widget[/color][color=#0550ae]([color=#953800]void[/color])[/color];`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        [color=#953800]ui_widget_t[/color] *counter;`} + {` `} + {`        lcui_init();`} + {`        register_counter_widget();`} + {` `} + {`        counter = ui_create_widget([color=#0a3069]"counter"[/color]);`} + {`        ui_widget_append(ui_root(), counter);`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + +
+ +

Extending an existing widget

+

{`Pass a parent type name as the second argument to [bgcolor=#eee] ui_create_widget_prototype() [/bgcolor]:`}

+ + + src/icon_button.c + + + + {`[color=#953800]static[/color] [color=#953800]ui_widget_prototype_t[/color] *icon_button_proto;`} + {` `} + {`[color=#953800]static[/color] [color=#953800]void[/color] [color=#8250df]icon_button_init[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w)[/color]`} + {`{`} + {`        [color=#6e7781]/* Call parent (button) init logic */[/color]`} + {`        icon_button_proto->proto->init(w);`} + {`        ui_widget_add_class(w, [color=#0a3069]"icon-button"[/color]);`} + {`}`} + {` `} + {`[color=#953800]void[/color] [color=#8250df]register_icon_button[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        icon_button_proto =`} + {`            ui_create_widget_prototype([color=#0a3069]"icon-button"[/color], [color=#0a3069]"button"[/color]);`} + {`        icon_button_proto->init = icon_button_init;`} + {`}`} + + + + 注意 + +

{`[b]Parent [bgcolor=#eee] init [/bgcolor] must be called manually.[/b] LCUI does not automatically call the parent type's [bgcolor=#eee] init [/bgcolor] when creating a subtype widget. If you forget to call [bgcolor=#eee] proto->proto->init(w) [/bgcolor], the widget will lack the parent type's base behaviors (e.g. [bgcolor=#eee] button [/bgcolor] won't register click events or set default styles).`}

+
+
+
+ +

Widget lifecycle

+

{`[bgcolor=#eee] ui_widget_prototype_t [/bgcolor] has several callback hooks covering each lifecycle stage:`}

+
    +
  • {`[b][bgcolor=#eee] init [/bgcolor][/b] — When the widget is created. Responsible for initializing owned data, child widgets, and event bindings.`}
  • +
  • {`[b][bgcolor=#eee] destroy [/bgcolor][/b] — When the widget is destroyed. Responsible for releasing owned memory and unbinding events.`}
  • +
  • {`[b][bgcolor=#eee] update [/bgcolor][/b] — When the widget needs updating, receives a [bgcolor=#eee] ui_task_type_t [/bgcolor] parameter indicating the update type (style update, property update, etc.). Called by LCUI during each frame's update loop.`}
  • +
  • {`[b][bgcolor=#eee] setattr [/bgcolor][/b] — When an XML attribute is set (for responding to attribute changes).`}
  • +
  • {`[b][bgcolor=#eee] settext [/bgcolor][/b] — When text content is set.`}
  • +
  • {`[b][bgcolor=#eee] sizehint [/bgcolor][/b] — Estimates the widget's natural size constraints (min/max content size) without external constraints. The layout engine uses this when computing child widget sizes.`}
  • +
  • {`[b][bgcolor=#eee] resize [/bgcolor][/b] — When the widget size changes. Receives the new content area width and height as parameters.`}
  • +
  • {`[b][bgcolor=#eee] paint [/bgcolor][/b] — When the widget needs to be redrawn. Used for custom drawing logic.`}
  • +
+
+ +

Custom painting

+

{`Override the [bgcolor=#eee] paint [/bgcolor] callback to draw custom graphics on a widget:`}

+ + + src/my_widget.c + + + + {`[color=#953800]static[/color] [color=#953800]void[/color] [color=#8250df]my_widget_paint[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w, [color=#953800]pd_context_t[/color] *paint_ctx,[/color]`} + {`[color=#0550ae] [color=#953800]ui_widget_actual_style_t[/color] *style)[/color]`} + {`{`} + {`        [color=#953800]pd_canvas_t[/color] *canvas = paint_ctx->canvas;`} + {`        [color=#953800]pd_color_t[/color] color = pd_color_from_rgb([color=#0550ae]255[/color], [color=#0550ae]0[/color], [color=#0550ae]0[/color]);`} + {`        [color=#953800]pd_rect_t[/color] rect = { style->left, style->top, w->width, w->height };`} + {` `} + {`        pd_canvas_fill_rect(canvas, color, rect);`} + {`}`} + {` `} + {`[color=#953800]static[/color] [color=#953800]void[/color] [color=#8250df]register_my_widget[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        [color=#953800]ui_widget_prototype_t[/color] *proto =`} + {`            ui_create_widget_prototype([color=#0a3069]"my-widget"[/color], [color=#0550ae]NULL[/color]);`} + {`        proto->paint = my_widget_paint;`} + {`}`} + + + + 注意 + +

{`[b][bgcolor=#eee] paint [/bgcolor] is only for drawing.[/b] Widget size estimation is handled by [bgcolor=#eee] sizehint [/bgcolor]; do not modify widget size or the child widget tree inside [bgcolor=#eee] paint [/bgcolor], as it may cause infinite loops.`}

+
+
+
+ +

Caveats

+ + 注意 + +

{`[b][bgcolor=#eee] destroy [/bgcolor] must release owned resources.[/b] If a custom widget allocated memory, opened files, or subscribed to system events (e.g. [bgcolor=#eee] lcui_settings_on_deserialize [/bgcolor]) in [bgcolor=#eee] init [/bgcolor], it must perform symmetric cleanup in [bgcolor=#eee] destroy [/bgcolor].`}

+
+
+ + 注意 + +

{`[b]Custom widgets must be registered after [bgcolor=#eee] lcui_init() [/bgcolor] and before first instantiation.[/b] Calling your [bgcolor=#eee] register_xxx() [/bgcolor] function right at the start of [bgcolor=#eee] main() [/bgcolor] is the safest place, ensuring all consumers (XML loading, router instantiation, TSX compilation results) can see the prototype.`}

+
+
+
+
+ ); +} diff --git a/examples/doc-viewer/app/en/handbook/icon-library/page.c b/examples/doc-viewer/app/en/handbook/icon-library/page.c new file mode 100644 index 000000000..17c78c7e9 --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/icon-library/page.c @@ -0,0 +1,57 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_handbook_icon_library_page_react_t base; + // Add additional states to your component here + // ... +} en_handbook_icon_library_page_t; + +static void en_handbook_icon_library_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_handbook_icon_library_page_proto, + sizeof(en_handbook_icon_library_page_t)); + + en_handbook_icon_library_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_handbook_icon_library_page_update(w); +} + +static en_handbook_icon_library_page_t *en_handbook_icon_library_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, en_handbook_icon_library_page_proto); +} + +static void en_handbook_icon_library_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_handbook_icon_library_page_react_destroy(w); +} + +void en_handbook_icon_library_page_update(ui_widget_t *w) +{ + en_handbook_icon_library_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_handbook_icon_library_page(void) +{ + return ui_create_widget_with_prototype( + en_handbook_icon_library_page_proto); +} + +void ui_register_en_handbook_icon_library_page(void) +{ + en_handbook_icon_library_page_init_prototype(); + en_handbook_icon_library_page_proto->init = + en_handbook_icon_library_page_init; + en_handbook_icon_library_page_proto->destroy = + en_handbook_icon_library_page_destroy; +} diff --git a/examples/doc-viewer/app/en/handbook/icon-library/page.h b/examples/doc-viewer/app/en/handbook/icon-library/page.h new file mode 100644 index 000000000..fcccb0cb5 --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/icon-library/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_handbook_icon_library_page(void); + +ui_widget_t *ui_create_en_handbook_icon_library_page(void); + +void en_handbook_icon_library_page_update(ui_widget_t *w); + +void ui_load_en_handbook_icon_library_page_resources(void); diff --git a/examples/doc-viewer/app/en/handbook/icon-library/page.tsx b/examples/doc-viewer/app/en/handbook/icon-library/page.tsx new file mode 100644 index 000000000..818b62d0c --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/icon-library/page.tsx @@ -0,0 +1,52 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function IconLibraryDocPage() { + return ( + +

Icon Library

+

{`[bgcolor=#eee] @lcui/fluent-icons [/bgcolor] is an icon library adapted for LCUI. All icons come from Microsoft's fluentui-system-icons project.`}

+ +

Installation

+ + + Shell + + + + {`npm install @lcui/fluent-icons`} + + +
+ +

Choosing icons

+

{`Search and select icons on flicon.io. For example, the zoom-in icon is typically named "Zoom In" in English.`}

+

{`fluentui-system-icons icons are available in sizes like 16, 20, and 24, named in the format "icon name + size + style". [bgcolor=#eee] @lcui/fluent-icons [/bgcolor] uses the naming format "icon name + style", and when the style is Regular it can be omitted.`}

+
+ +

Usage

+ + + TypeScript + + + + {`[color=#cf222e]import[/color] { [color=#8250df]ZoomIn[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/fluent-icons"[/color];`} + {` `} + {`[color=#116329]<[color=#0550ae]ZoomIn[/color] />[/color]`} + + +

{`The default size is 20. If the icon size is fixed and you want better rendering, specify the size parameter:`}

+ + + TypeScript + + + + {`<[color=#8250df]ZoomIn[/color] size={[color=#0550ae]32[/color]} />`} + + +
+
+ ); +} diff --git a/examples/doc-viewer/app/en/handbook/sass/page.c b/examples/doc-viewer/app/en/handbook/sass/page.c new file mode 100644 index 000000000..1b728d92e --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/sass/page.c @@ -0,0 +1,53 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_handbook_sass_page_react_t base; + // Add additional states to your component here + // ... +} en_handbook_sass_page_t; + +static void en_handbook_sass_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_handbook_sass_page_proto, + sizeof(en_handbook_sass_page_t)); + + en_handbook_sass_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_handbook_sass_page_update(w); +} + +static en_handbook_sass_page_t *en_handbook_sass_page_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, en_handbook_sass_page_proto); +} + +static void en_handbook_sass_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_handbook_sass_page_react_destroy(w); +} + +void en_handbook_sass_page_update(ui_widget_t *w) +{ + en_handbook_sass_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_handbook_sass_page(void) +{ + return ui_create_widget_with_prototype(en_handbook_sass_page_proto); +} + +void ui_register_en_handbook_sass_page(void) +{ + en_handbook_sass_page_init_prototype(); + en_handbook_sass_page_proto->init = en_handbook_sass_page_init; + en_handbook_sass_page_proto->destroy = en_handbook_sass_page_destroy; +} diff --git a/examples/doc-viewer/app/en/handbook/sass/page.h b/examples/doc-viewer/app/en/handbook/sass/page.h new file mode 100644 index 000000000..5697b8d9c --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/sass/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_handbook_sass_page(void); + +ui_widget_t *ui_create_en_handbook_sass_page(void); + +void en_handbook_sass_page_update(ui_widget_t *w); + +void ui_load_en_handbook_sass_page_resources(void); diff --git a/examples/doc-viewer/app/en/handbook/sass/page.tsx b/examples/doc-viewer/app/en/handbook/sass/page.tsx new file mode 100644 index 000000000..5da420bfd --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/sass/page.tsx @@ -0,0 +1,26 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function SassDocPage() { + return ( + +

Sass

+

{`Sass is a popular CSS preprocessor that extends CSS with variables, nesting rules, mixins, and more.`}

+ +

Usage

+

{`[bgcolor=#eee] @lcui/cli [/bgcolor] has a built-in Sass preprocessor that is automatically invoked when compiling [bgcolor=#eee] .sass [/bgcolor] and [bgcolor=#eee] .scss [/bgcolor] files — no additional installation or configuration needed.`}

+

{`Import Sass files directly in TSX:`}

+ + + MyComponent.tsx + + + + {`[color=#cf222e]import[/color] [color=#0a3069]"./MyComponent.scss"[/color];`} + + +

{`The CLI compiles Sass files into CSS, then converts them to C code for runtime loading.`}

+
+
+ ); +} diff --git a/examples/doc-viewer/app/en/handbook/styling/page.c b/examples/doc-viewer/app/en/handbook/styling/page.c new file mode 100644 index 000000000..3b082d487 --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/styling/page.c @@ -0,0 +1,53 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_handbook_styling_page_react_t base; + // Add additional states to your component here + // ... +} en_handbook_styling_page_t; + +static void en_handbook_styling_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_handbook_styling_page_proto, + sizeof(en_handbook_styling_page_t)); + en_handbook_styling_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_handbook_styling_page_update(w); +} + +static en_handbook_styling_page_t *en_handbook_styling_page_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, en_handbook_styling_page_proto); +} + +static void en_handbook_styling_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_handbook_styling_page_react_destroy(w); +} + +void en_handbook_styling_page_update(ui_widget_t *w) +{ + en_handbook_styling_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_handbook_styling_page(void) +{ + return ui_create_widget_with_prototype(en_handbook_styling_page_proto); +} + +void ui_register_en_handbook_styling_page(void) +{ + en_handbook_styling_page_init_prototype(); + en_handbook_styling_page_proto->init = en_handbook_styling_page_init; + en_handbook_styling_page_proto->destroy = + en_handbook_styling_page_destroy; +} diff --git a/examples/doc-viewer/app/en/handbook/styling/page.h b/examples/doc-viewer/app/en/handbook/styling/page.h new file mode 100644 index 000000000..eb0b6d169 --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/styling/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_handbook_styling_page(void); + +ui_widget_t *ui_create_en_handbook_styling_page(void); + +void en_handbook_styling_page_update(ui_widget_t *w); + +void ui_load_en_handbook_styling_page_resources(void); diff --git a/examples/doc-viewer/app/en/handbook/styling/page.tsx b/examples/doc-viewer/app/en/handbook/styling/page.tsx new file mode 100644 index 000000000..f5e1eb1af --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/styling/page.tsx @@ -0,0 +1,183 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function StylingDocPage() { + return ( + +

Styling

+

{`Use CSS to set colors, borders, padding, margins, dimensions, and layout for widgets.`}

+ +

How to set styles

+

Inline styles

+

{`Use [bgcolor=#eee] ui_widget_set_style_string() [/bgcolor] to set individual CSS properties directly:`}

+ + + main.c + + + + {`[color=#953800]ui_widget_t[/color] *w = ui_create_widget([color=#0a3069]"text"[/color]);`} + {` `} + {`ui_widget_set_style_string(w, [color=#0a3069]"color"[/color], [color=#0a3069]"#336699"[/color]);`} + {`ui_widget_set_style_string(w, [color=#0a3069]"font-size"[/color], [color=#0a3069]"20px"[/color]);`} + {`ui_widget_set_style_string(w, [color=#0a3069]"padding"[/color], [color=#0a3069]"8px 16px"[/color]);`} + + +

CSS class selectors

+

{`Use [bgcolor=#eee] ui_load_css_string() [/bgcolor] or [bgcolor=#eee] ui_load_css_file() [/bgcolor] to load CSS rules, then apply them to widgets with [bgcolor=#eee] ui_widget_add_class() [/bgcolor]:`}

+ + + main.c + + + + {`ui_load_css_file([color=#0a3069]"styles.css"[/color]);`} + {` `} + {`[color=#953800]ui_widget_t[/color] *w = ui_create_widget([color=#0a3069]"text"[/color]);`} + {`ui_widget_add_class(w, [color=#0a3069]"title"[/color]);`} + + + + + app/styles.css + + + + {`[color=#953800].title[/color] {`} + {`  font-size: [color=#0550ae]24px[/color];`} + {`  font-weight: bold;`} + {`  margin-bottom: [color=#0550ae]16px[/color];`} + {`}`} + + +

{`You can also use [bgcolor=#eee] ui_load_css_string() [/bgcolor] to load CSS rules from a string. The second parameter is a source identifier used for debugging to locate conflicting rules:`}

+ + + main.c + + + + {`ui_load_css_string([color=#0a3069]".title { font-size: 24px; }"[/color], [color=#0a3069]"app.css"[/color]);`} + + +
+ +

Supported CSS features

+

{`LCUI's CSS engine implements a subset of the web standard. This section lists all supported features and their supported values; [b]anything not listed is not supported by default[/b].`}

+

At Rules

+
    +
  • {`[b][bgcolor=#eee] @font-face [/bgcolor][/b] — Load external fonts`}
  • +
+

Selectors

+
    +
  • {`[bgcolor=#eee] * [/bgcolor] (universal), [bgcolor=#eee] type [/bgcolor], [bgcolor=#eee] #id [/bgcolor], [bgcolor=#eee] .class [/bgcolor]`}
  • +
  • {`Pseudo-classes [bgcolor=#eee] :hover [/bgcolor], [bgcolor=#eee] :focus [/bgcolor], [bgcolor=#eee] :active [/bgcolor], [bgcolor=#eee] :first-child [/bgcolor], [bgcolor=#eee] :last-child [/bgcolor]`}
  • +
  • {`[bgcolor=#eee] !important [/bgcolor] is not supported`}
  • +
+

Units

+
    +
  • {`[bgcolor=#eee] px [/bgcolor], [bgcolor=#eee] dp [/bgcolor], [bgcolor=#eee] sp [/bgcolor], [bgcolor=#eee] pt [/bgcolor], [bgcolor=#eee] % [/bgcolor]`}
  • +
+

Properties

+

Layout

+
    +
  • {`[b][bgcolor=#eee] display [/bgcolor][/b] — [bgcolor=#eee] none [/bgcolor], [bgcolor=#eee] inline-block [/bgcolor], [bgcolor=#eee] block [/bgcolor], [bgcolor=#eee] flex [/bgcolor], [bgcolor=#eee] inline-flex [/bgcolor], [bgcolor=#eee] table [/bgcolor], [bgcolor=#eee] inline-table [/bgcolor], [bgcolor=#eee] table-row [/bgcolor], [bgcolor=#eee] table-cell [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] position [/bgcolor][/b] — [bgcolor=#eee] static [/bgcolor], [bgcolor=#eee] relative [/bgcolor], [bgcolor=#eee] absolute [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] top [/bgcolor] / [bgcolor=#eee] right [/bgcolor] / [bgcolor=#eee] bottom [/bgcolor] / [bgcolor=#eee] left [/bgcolor][/b] — [bgcolor=#eee] [/bgcolor] or [bgcolor=#eee] [/bgcolor] or [bgcolor=#eee] auto [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] z-index [/bgcolor][/b] — [bgcolor=#eee] auto [/bgcolor] or integer`}
  • +
  • {`[b][bgcolor=#eee] box-sizing [/bgcolor][/b] — [bgcolor=#eee] content-box [/bgcolor], [bgcolor=#eee] border-box [/bgcolor]`}
  • +
+

Box model

+
    +
  • {`[b][bgcolor=#eee] width [/bgcolor] / [bgcolor=#eee] height [/bgcolor][/b] — [bgcolor=#eee] [/bgcolor], [bgcolor=#eee] [/bgcolor], [bgcolor=#eee] auto [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] min-width [/bgcolor] / [bgcolor=#eee] max-width [/bgcolor] / [bgcolor=#eee] min-height [/bgcolor] / [bgcolor=#eee] max-height [/bgcolor][/b] — same as above`}
  • +
  • {`[b][bgcolor=#eee] padding [/bgcolor][/b] — shorthand, 1-4 [bgcolor=#eee] [/bgcolor] values (e.g. [bgcolor=#eee] 8px [/bgcolor], [bgcolor=#eee] 4px 8px [/bgcolor], [bgcolor=#eee] 4px 8px 12px [/bgcolor], [bgcolor=#eee] 4px 8px 12px 16px [/bgcolor])`}
  • +
  • {`[b][bgcolor=#eee] padding-top [/bgcolor] / [bgcolor=#eee] padding-right [/bgcolor] / [bgcolor=#eee] padding-bottom [/bgcolor] / [bgcolor=#eee] padding-left [/bgcolor][/b] — longhand properties`}
  • +
  • {`[b][bgcolor=#eee] margin [/bgcolor][/b] — shorthand, same syntax as padding`}
  • +
  • {`[b][bgcolor=#eee] margin-top [/bgcolor] / [bgcolor=#eee] margin-right [/bgcolor] / [bgcolor=#eee] margin-bottom [/bgcolor] / [bgcolor=#eee] margin-left [/bgcolor][/b]`}
  • +
  • {`[b][bgcolor=#eee] border [/bgcolor][/b] — shorthand [bgcolor=#eee] 1px solid #ccc [/bgcolor] (width + style + color)`}
  • +
  • {`[b][bgcolor=#eee] border-color [/bgcolor] / [bgcolor=#eee] border-width [/bgcolor] / [bgcolor=#eee] border-style [/bgcolor] / [bgcolor=#eee] border-radius [/bgcolor][/b] — multi-value shorthand, same syntax as padding`}
  • +
  • {`[b][bgcolor=#eee] border-top [/bgcolor] / [bgcolor=#eee] border-right [/bgcolor] / [bgcolor=#eee] border-bottom [/bgcolor] / [bgcolor=#eee] border-left [/bgcolor][/b] — per-side shorthand`}
  • +
  • {`[b][bgcolor=#eee] border-top-color [/bgcolor] / [bgcolor=#eee] border-right-color [/bgcolor] / [bgcolor=#eee] border-bottom-color [/bgcolor] / [bgcolor=#eee] border-left-color [/bgcolor][/b]`}
  • +
  • {`[b][bgcolor=#eee] border-top-width [/bgcolor] / [bgcolor=#eee] border-right-width [/bgcolor] / [bgcolor=#eee] border-bottom-width [/bgcolor] / [bgcolor=#eee] border-left-width [/bgcolor][/b]`}
  • +
  • {`[b][bgcolor=#eee] border-top-style [/bgcolor] / [bgcolor=#eee] border-right-style [/bgcolor] / [bgcolor=#eee] border-bottom-style [/bgcolor] / [bgcolor=#eee] border-left-style [/bgcolor][/b]`}
  • +
  • {`[b][bgcolor=#eee] border-top-left-radius [/bgcolor] / [bgcolor=#eee] border-top-right-radius [/bgcolor] / [bgcolor=#eee] border-bottom-left-radius [/bgcolor] / [bgcolor=#eee] border-bottom-right-radius [/bgcolor][/b]`}
  • +
  • {`[b][bgcolor=#eee] border-style [/bgcolor] values[/b] — [bgcolor=#eee] none [/bgcolor], [bgcolor=#eee] solid [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] table-layout [/bgcolor][/b] — [bgcolor=#eee] auto [/bgcolor], [bgcolor=#eee] fixed [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] border-spacing [/bgcolor][/b] — [bgcolor=#eee] {1,2} [/bgcolor]`}
  • +
+

Background

+
    +
  • {`[b][bgcolor=#eee] background [/bgcolor][/b] — shorthand [bgcolor=#eee] bg-image || bg-position || bg-size || repeat-style || color [/bgcolor] (single layer only)`}
  • +
  • {`[b][bgcolor=#eee] background-color [/bgcolor][/b] — [bgcolor=#eee] [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] background-image [/bgcolor][/b] — [bgcolor=#eee] none [/bgcolor] or [bgcolor=#eee] [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] background-position [/bgcolor][/b] — two values: x y`}
  • +
  • {`[b][bgcolor=#eee] background-position-x [/bgcolor] / [bgcolor=#eee] background-position-y [/bgcolor][/b]`}
  • +
  • {`[b][bgcolor=#eee] background-repeat [/bgcolor][/b] — [bgcolor=#eee] [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] background-size [/bgcolor][/b] — [bgcolor=#eee] [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] background-clip [/bgcolor][/b] — [bgcolor=#eee] border-box [/bgcolor], [bgcolor=#eee] padding-box [/bgcolor], [bgcolor=#eee] content-box [/bgcolor]`}
  • +
+

Flexbox layout

+
    +
  • {`[b][bgcolor=#eee] flex [/bgcolor][/b] — shorthand ([bgcolor=#eee] flex-grow [/bgcolor] + [bgcolor=#eee] flex-shrink [/bgcolor] + [bgcolor=#eee] flex-basis [/bgcolor])`}
  • +
  • {`[b][bgcolor=#eee] flex-shrink [/bgcolor] / [bgcolor=#eee] flex-grow [/bgcolor] / [bgcolor=#eee] flex-basis [/bgcolor][/b]`}
  • +
  • {`[b][bgcolor=#eee] flex-wrap [/bgcolor][/b] — [bgcolor=#eee] nowrap [/bgcolor], [bgcolor=#eee] wrap [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] flex-direction [/bgcolor][/b] — [bgcolor=#eee] row [/bgcolor], [bgcolor=#eee] column [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] justify-content [/bgcolor][/b] — [bgcolor=#eee] flex-start [/bgcolor], [bgcolor=#eee] center [/bgcolor], [bgcolor=#eee] flex-end [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] align-items [/bgcolor][/b] — [bgcolor=#eee] flex-start [/bgcolor], [bgcolor=#eee] center [/bgcolor], [bgcolor=#eee] flex-end [/bgcolor], [bgcolor=#eee] stretch [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] align-content [/bgcolor][/b] — same as justify-content plus [bgcolor=#eee] space-between [/bgcolor], [bgcolor=#eee] space-around [/bgcolor], [bgcolor=#eee] space-evenly [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] gap [/bgcolor][/b] — shorthand, sets both row-gap and column-gap`}
  • +
  • {`[b][bgcolor=#eee] row-gap [/bgcolor] / [bgcolor=#eee] column-gap [/bgcolor][/b] — [bgcolor=#eee] normal [/bgcolor] or [bgcolor=#eee] [/bgcolor]`}
  • +
+

Typography

+
    +
  • {`[b][bgcolor=#eee] font-face [/bgcolor][/b] — (load fonts via [bgcolor=#eee] @font-face [/bgcolor] rule)`}
  • +
  • {`[b][bgcolor=#eee] font-family [/bgcolor][/b] — [bgcolor=#eee] [/bgcolor] (recommended to use built-in aliases like [bgcolor=#eee] monospace [/bgcolor])`}
  • +
  • {`[b][bgcolor=#eee] font-size [/bgcolor][/b] — [bgcolor=#eee] [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] font-style [/bgcolor][/b] — [bgcolor=#eee] normal [/bgcolor], [bgcolor=#eee] italic [/bgcolor], [bgcolor=#eee] oblique [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] font-weight [/bgcolor][/b] — [bgcolor=#eee] normal [/bgcolor], [bgcolor=#eee] bold [/bgcolor], [bgcolor=#eee] [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] text-align [/bgcolor][/b] — [bgcolor=#eee] left [/bgcolor], [bgcolor=#eee] center [/bgcolor], [bgcolor=#eee] right [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] line-height [/bgcolor][/b] — [bgcolor=#eee] normal [/bgcolor] or [bgcolor=#eee] [/bgcolor] or [bgcolor=#eee] [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] color [/bgcolor][/b] — [bgcolor=#eee] [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] white-space [/bgcolor][/b] — [bgcolor=#eee] normal [/bgcolor], [bgcolor=#eee] nowrap [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] word-break [/bgcolor][/b] — [bgcolor=#eee] normal [/bgcolor], [bgcolor=#eee] break-all [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] content [/bgcolor][/b] — [bgcolor=#eee] [/bgcolor] or [bgcolor=#eee] none [/bgcolor]`}
  • +
+

Other

+
    +
  • {`[b][bgcolor=#eee] opacity [/bgcolor][/b] — [bgcolor=#eee] [/bgcolor] or [bgcolor=#eee] [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] visibility [/bgcolor][/b] — [bgcolor=#eee] visible [/bgcolor], [bgcolor=#eee] hidden [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] pointer-events [/bgcolor][/b] — [bgcolor=#eee] auto [/bgcolor], [bgcolor=#eee] none [/bgcolor]`}
  • +
  • {`[b][bgcolor=#eee] box-shadow [/bgcolor][/b] — [bgcolor=#eee] none [/bgcolor] or [bgcolor=#eee] [/bgcolor] (format [bgcolor=#eee] {2,4} && ? [/bgcolor])`}
  • +
+
+ +

Caveats

+ + 注意 + +

{`[b][bgcolor=#eee] white-space: pre [/bgcolor] does not work.[/b] LCUI's [bgcolor=#eee] white-space [/bgcolor] only implements [bgcolor=#eee] normal [/bgcolor] and [bgcolor=#eee] nowrap [/bgcolor]. If you need to preserve leading whitespace from source code, replace spaces with U+00A0 (NBSP).`}

+
+
+ + 注意 + +

{`[b][bgcolor=#eee] overflow [/bgcolor] does not clip content.[/b] To clip or scroll child content, use the [bgcolor=#eee] scrollarea [/bgcolor] built-in widget instead.`}

+
+
+ + 注意 + +

{`[b][bgcolor=#eee] background [/bgcolor] shorthand does not support multiple layers.[/b] Writing multi-background syntax like [bgcolor=#eee] background: url(a.png) no-repeat, url(b.png) center; [/bgcolor] will not work. Use individual properties like [bgcolor=#eee] background-image [/bgcolor] / [bgcolor=#eee] background-position [/bgcolor] to set each layer separately.`}

+
+
+ + 注意 + +

{`[b]CSS does not support inheritance.[/b] Properties like [bgcolor=#eee] color [/bgcolor], [bgcolor=#eee] font-family [/bgcolor], and [bgcolor=#eee] font-size [/bgcolor] do not cascade from parent to child widgets. Every widget that displays text (e.g. [bgcolor=#eee] text [/bgcolor], [bgcolor=#eee] button [/bgcolor]) must explicitly set these properties.`}

+
+
+
+
+ ); +} diff --git a/examples/doc-viewer/app/en/handbook/tailwind-css/page.c b/examples/doc-viewer/app/en/handbook/tailwind-css/page.c new file mode 100644 index 000000000..86a29f438 --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/tailwind-css/page.c @@ -0,0 +1,57 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_handbook_tailwind_css_page_react_t base; + // Add additional states to your component here + // ... +} en_handbook_tailwind_css_page_t; + +static void en_handbook_tailwind_css_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_handbook_tailwind_css_page_proto, + sizeof(en_handbook_tailwind_css_page_t)); + + en_handbook_tailwind_css_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_handbook_tailwind_css_page_update(w); +} + +static en_handbook_tailwind_css_page_t *en_handbook_tailwind_css_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, en_handbook_tailwind_css_page_proto); +} + +static void en_handbook_tailwind_css_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_handbook_tailwind_css_page_react_destroy(w); +} + +void en_handbook_tailwind_css_page_update(ui_widget_t *w) +{ + en_handbook_tailwind_css_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_handbook_tailwind_css_page(void) +{ + return ui_create_widget_with_prototype( + en_handbook_tailwind_css_page_proto); +} + +void ui_register_en_handbook_tailwind_css_page(void) +{ + en_handbook_tailwind_css_page_init_prototype(); + en_handbook_tailwind_css_page_proto->init = + en_handbook_tailwind_css_page_init; + en_handbook_tailwind_css_page_proto->destroy = + en_handbook_tailwind_css_page_destroy; +} diff --git a/examples/doc-viewer/app/en/handbook/tailwind-css/page.h b/examples/doc-viewer/app/en/handbook/tailwind-css/page.h new file mode 100644 index 000000000..92ab43ca1 --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/tailwind-css/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_handbook_tailwind_css_page(void); + +ui_widget_t *ui_create_en_handbook_tailwind_css_page(void); + +void en_handbook_tailwind_css_page_update(ui_widget_t *w); + +void ui_load_en_handbook_tailwind_css_page_resources(void); diff --git a/examples/doc-viewer/app/en/handbook/tailwind-css/page.tsx b/examples/doc-viewer/app/en/handbook/tailwind-css/page.tsx new file mode 100644 index 000000000..e438feb58 --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/tailwind-css/page.tsx @@ -0,0 +1,51 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function TailwindCssDocPage() { + return ( + +

Tailwind CSS

+

{`Tailwind CSS is a utility-first CSS framework that helps developers quickly apply styles through predefined CSS classes. Compared to traditional CSS, you don't need to create new CSS files, write rules, or think up class names.`}

+ +

Installation

+ + + Shell + + + + {`npm install -D tailwindcss postcss @thedutchcoder/postcss-rem-to-px`} + + +
+ +

Configuration

+

{`Copy the following files from the lcui-quick-start template project to your project root:`}

+
    +
  • {`[bgcolor=#eee] postcss.config.js [/bgcolor]`}
  • +
  • {`[bgcolor=#eee] tailwind.config.js [/bgcolor]`}
  • +
  • {`[bgcolor=#eee] app/global.css [/bgcolor]`}
  • +
+

{`[bgcolor=#eee] global.css [/bgcolor] contains the Tailwind directives:`}

+ + + app/global.css + + + + {`[color=#cf222e]@tailwind[/color] base;`} + {`[color=#cf222e]@tailwind[/color] components;`} + {`[color=#cf222e]@tailwind[/color] utilities;`} + + +

{`When compiling, [bgcolor=#eee] @lcui/cli [/bgcolor] processes Tailwind directives through the PostCSS chain (postcss + tailwindcss + postcss-rem-to-px) to generate the final CSS output.`}

+ + 技巧 + +

{`If you don't want to place global.css inside the app directory, change the [bgcolor=#eee] content [/bgcolor] path matching rules in [bgcolor=#eee] tailwind.config.js [/bgcolor].`}

+
+
+
+
+ ); +} diff --git a/examples/doc-viewer/app/en/handbook/tsx-and-dev-tools/page.c b/examples/doc-viewer/app/en/handbook/tsx-and-dev-tools/page.c new file mode 100644 index 000000000..0659d10ef --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/tsx-and-dev-tools/page.c @@ -0,0 +1,57 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_handbook_tsx_and_dev_tools_page_react_t base; + // Add additional states to your component here + // ... +} en_handbook_tsx_and_dev_tools_page_t; + +static void en_handbook_tsx_and_dev_tools_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_handbook_tsx_and_dev_tools_page_proto, + sizeof(en_handbook_tsx_and_dev_tools_page_t)); + + en_handbook_tsx_and_dev_tools_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_handbook_tsx_and_dev_tools_page_update(w); +} + +static en_handbook_tsx_and_dev_tools_page_t * +en_handbook_tsx_and_dev_tools_page_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, en_handbook_tsx_and_dev_tools_page_proto); +} + +static void en_handbook_tsx_and_dev_tools_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_handbook_tsx_and_dev_tools_page_react_destroy(w); +} + +void en_handbook_tsx_and_dev_tools_page_update(ui_widget_t *w) +{ + en_handbook_tsx_and_dev_tools_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_handbook_tsx_and_dev_tools_page(void) +{ + return ui_create_widget_with_prototype( + en_handbook_tsx_and_dev_tools_page_proto); +} + +void ui_register_en_handbook_tsx_and_dev_tools_page(void) +{ + en_handbook_tsx_and_dev_tools_page_init_prototype(); + en_handbook_tsx_and_dev_tools_page_proto->init = + en_handbook_tsx_and_dev_tools_page_init; + en_handbook_tsx_and_dev_tools_page_proto->destroy = + en_handbook_tsx_and_dev_tools_page_destroy; +} diff --git a/examples/doc-viewer/app/en/handbook/tsx-and-dev-tools/page.h b/examples/doc-viewer/app/en/handbook/tsx-and-dev-tools/page.h new file mode 100644 index 000000000..9be2920ff --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/tsx-and-dev-tools/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_handbook_tsx_and_dev_tools_page(void); + +ui_widget_t *ui_create_en_handbook_tsx_and_dev_tools_page(void); + +void en_handbook_tsx_and_dev_tools_page_update(ui_widget_t *w); + +void ui_load_en_handbook_tsx_and_dev_tools_page_resources(void); diff --git a/examples/doc-viewer/app/en/handbook/tsx-and-dev-tools/page.tsx b/examples/doc-viewer/app/en/handbook/tsx-and-dev-tools/page.tsx new file mode 100644 index 000000000..ae5a1cb87 --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/tsx-and-dev-tools/page.tsx @@ -0,0 +1,260 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function TsxAndDevToolsDocPage() { + return ( + +

TSX & Dev Tools

+

{`With [bgcolor=#eee] @lcui/cli [/bgcolor], you can write declarative UIs using TypeScript with JSX syntax. The CLI compiles TSX into C code, so you don't need to manually write widget tree construction logic.`}

+

{`The benefit is that the declarative approach makes state binding, event binding, and resource imports more concise and intuitive. Handling logic and view in the same file reduces context switching.`}

+

{`However, [bgcolor=#eee] @lcui/react [/bgcolor] currently has limited capabilities — you can only declare component state, data bindings, and event bindings. For complex operations like conditional rendering or list rendering, you still need to write C code.`}

+ +

Installing dev tools

+

{`[bgcolor=#eee] @lcui/cli [/bgcolor] is a command-line tool that integrates a TypeScript compiler, Sass preprocessor, resource file loader, and more. It requires a Node.js runtime:`}

+ + + Shell + + + + {`npm install -g @lcui/cli`} + + +
+ +

How the preprocessor works

+

{`LCUI uses a preprocessor approach: TSX files are only executed during preprocessing and do not become runtime code. You can think of TSX files as configuration files, where the TypeScript code acts as preprocessing directives.`}

+

{`The preprocessor matches the appropriate loader by file extension, parses the TSX code, collects dependencies, executes component functions, and then generates C source files based on the returned JSX elements and Hook call results.`}

+
+ +

Usage overview

+ + + src/App.tsx + + + + {`[color=#cf222e]import[/color] { useState, [color=#8250df]TextInput[/color], [color=#8250df]Button[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]const[/color] inputRef = { [color=#0550ae]current[/color]: { [color=#0550ae]value[/color]: [color=#0a3069]""[/color] } };`} + {`  [color=#cf222e]const[/color] \\[name, setName] = [color=#8250df]useState[/color]([color=#0a3069]"LCUI"[/color]);`} + {` `} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]Widget[/color] [color=#0550ae]className[/color]=[color=#0a3069]"container"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]Widget[/color] [color=#0550ae]className[/color]=[color=#0a3069]"flex flex-col items-center pt-6"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]Text[/color] [color=#0550ae]className[/color]=[color=#0a3069]"my-4 text-2xl text-center"[/color]>[/color]Hello, {name}![color=#116329][/color]`} + {`        [color=#116329]<[color=#0550ae]TextInput[/color][/color]`} + {`[color=#116329] \$[color=#0550ae]ref[/color]=[color=#0a3069]{inputRef}[/color][/color]`} + {`[color=#116329] [color=#0550ae]className[/color]=[color=#0a3069]"mt-2"[/color][/color]`} + {`[color=#116329] [color=#0550ae]placeholder[/color]=[color=#0a3069]"Please input..."[/color][/color]`} + {`[color=#116329] />[/color]`} + {`        [color=#116329]<[color=#0550ae]Button[/color][/color]`} + {`[color=#116329] [color=#0550ae]className[/color]=[color=#0a3069]"mt-2"[/color][/color]`} + {`[color=#116329] [color=#0550ae]onClick[/color]=[color=#0a3069]{()[/color] =>[/color] setName(inputRef.current.value)}`} + {`        >`} + {`          Change`} + {`        [color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + + +
+ +

React library

+

{`[bgcolor=#eee] @lcui/react [/bgcolor] is a UI library tailored for LCUI's features and preprocessor workflow, providing built-in components, utility functions, and hooks.`}

+

{`Installation:`}

+ + + Shell + + + + {`npm install @lcui/react`} + + +

Component functions

+

{`The preprocessor executes component functions, collects data from [bgcolor=#eee] useState [/bgcolor], [bgcolor=#eee] useRef [/bgcolor], etc. and the returned JSX elements, then converts them into C code.`}

+ + 注意 + +
    +
  • {`Component function return values must be a single JSX element — [bgcolor=#eee] [/bgcolor], null, undefined, strings, numbers, or other objects are not supported.`}
  • +
  • {`Declaring and passing component props is not yet supported.`}
  • +
+
+
+

State management

+

{`[bgcolor=#eee] useState [/bgcolor] declares a state variable for a component:`}

+ + + TypeScript + + + + {`[color=#cf222e]import[/color] { useState } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]function[/color] [color=#8250df]MyComponent[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]const[/color] \\[age, setAge] = [color=#8250df]useState[/color]([color=#0550ae]23[/color]);`} + {`  [color=#cf222e]const[/color] \\[name, setName] = [color=#8250df]useState[/color]([color=#0a3069]"Taylor"[/color]);`} + {`  [color=#6e7781]// ...[/color]`} + {`}`} + + +

{`[bgcolor=#eee] useState [/bgcolor] returns an array:`}

+
    +
  • {`The state variable, initialized to the value passed to [bgcolor=#eee] useState [/bgcolor].`}
  • +
  • {`A set function, which lets you change the state variable in response to interactions.`}
  • +
+

{`[bgcolor=#eee] useState [/bgcolor] adds a member to the component's state struct and generates initialization code in the init function:`}

+ + + C + + + + {`[color=#6e7781]/* Component state struct */[/color]`} + {`[color=#cf222e]struct[/color] [color=#8250df]MyComponent_state[/color] {`} + {`  [color=#953800]int[/color] age;`} + {`  [color=#953800]char[/color] *name;`} + {`};`} + {` `} + {`[color=#6e7781]/* Code in component init function */[/color]`} + {`_that->state.age = [color=#0550ae]23[/color];`} + {`_that->state.name = strdup2([color=#0a3069]"Taylor"[/color]);`} + + +

{`The state's set function inserts C code in the current scope, e.g. [bgcolor=#eee] setAge(30) [/bgcolor] generates [bgcolor=#eee] _that->state.age = 30; [/bgcolor].`}

+ + 注意 + +

{`[bgcolor=#eee] useState [/bgcolor] parameters can only be string or number types.`}

+
+
+

Refs

+

{`Use the [bgcolor=#eee] \$ref [/bgcolor] attribute to reference a widget object:`}

+ + + TypeScript + + + + {`<[color=#8250df]TextInput[/color] \$ref=[color=#0a3069]"input"[/color] />`} + + +

{`Then operate on it in C code:`}

+ + + C + + + + {`ui_textinput_set_content(_that->refs.input, [color=#0a3069]"hello"[/color]);`} + + +

{`The [bgcolor=#eee] \$ref [/bgcolor] value can also be a reference object returned by [bgcolor=#eee] useRef [/bgcolor]:`}

+ + + TypeScript + + + + {`[color=#cf222e]import[/color] { useRef } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]function[/color] [color=#8250df]MyComponent[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]const[/color] inputRef = [color=#8250df]useRef[/color]();`} + {` `} + {`  [color=#cf222e]return[/color] [color=#116329]<[color=#0550ae]TextInput[/color] \$[color=#0550ae]ref[/color]=[color=#0a3069]{inputRef}[/color] />[/color];`} + {`}`} + + +

{`[bgcolor=#eee] useRef [/bgcolor] currently only implements value property read/write binding for TextInput:`}

+ + + TypeScript + + + + {`inputRef.[color=#0550ae]current[/color].[color=#0550ae]value[/color] = [color=#0a3069]"World"[/color];`} + {` `} + {`[color=#116329]<[color=#0550ae]Button[/color] [color=#0550ae]onClick[/color]=[color=#0a3069]{()[/color] =>[/color] setName(inputRef.current.value)}>Click[color=#116329][/color]`} + + + + 注意 + +

{`[bgcolor=#eee] @lcui/react [/bgcolor]'s [bgcolor=#eee] useRef [/bgcolor] is different from React's [bgcolor=#eee] useRef [/bgcolor] — it is only for referencing widget objects.`}

+
+
+

Responding to events

+

{`Declare event handlers using the [bgcolor=#eee] on + event name [/bgcolor] attribute:`}

+ + + TypeScript + + + + {`<[color=#8250df]Button[/color] onClick=[color=#0a3069]"handleClick"[/color]>[color=#8250df]Click[/color] me`} + + +

{`The preprocessor generates C code to bind the event:`}

+ + + C + + + + {`ui_widget_on(_that->refs.ref_0, [color=#0a3069]"click"[/color], handleClick, w);`} + + +

{`You can also bind JavaScript functions to events:`}

+ + + TypeScript + + + + {`[color=#cf222e]import[/color] { useState, [color=#8250df]Text[/color], [color=#8250df]Button[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]Counter[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]const[/color] \\[text, setText] = [color=#8250df]useState[/color]([color=#0a3069]"Click me"[/color]);`} + {` `} + {`  [color=#cf222e]function[/color] [color=#8250df]handleClick[/color]([color=#0550ae][/color]) {`} + {`    [color=#8250df]setText[/color]([color=#0a3069]"You clicked"[/color]);`} + {`  }`} + {` `} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]Button[/color] [color=#0550ae]onClick[/color]=[color=#0a3069]{handleClick}[/color]>[/color]`} + {`      {text}`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + + +

{`The preprocessor generates a C-language version of the event handler based on the code executed inside the handler function.`}

+ + 注意 + +

{`Currently, only state variable set functions can be called inside event handlers. Accessing the event object or executing other statements is not supported.`}

+
+
+

Conditional rendering

+ + 注意 + +

{`Not yet supported. We are considering implementing conditional rendering with a [bgcolor=#eee] [/bgcolor] component, inspired by Solid.js's [bgcolor=#eee] [/bgcolor].`}

+
+
+

Rendering lists

+ + 注意 + +

{`Not yet supported. We are considering implementing array iteration with a [bgcolor=#eee] [/bgcolor] component, inspired by Solid.js's [bgcolor=#eee] [/bgcolor].`}

+
+
+
+
+ ); +} diff --git a/examples/doc-viewer/app/en/handbook/typescript/page.c b/examples/doc-viewer/app/en/handbook/typescript/page.c new file mode 100644 index 000000000..ed036a71c --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/typescript/page.c @@ -0,0 +1,56 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_handbook_typescript_page_react_t base; + // Add additional states to your component here + // ... +} en_handbook_typescript_page_t; + +static void en_handbook_typescript_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_handbook_typescript_page_proto, + sizeof(en_handbook_typescript_page_t)); + en_handbook_typescript_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_handbook_typescript_page_update(w); +} + +static en_handbook_typescript_page_t *en_handbook_typescript_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, en_handbook_typescript_page_proto); +} + +static void en_handbook_typescript_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_handbook_typescript_page_react_destroy(w); +} + +void en_handbook_typescript_page_update(ui_widget_t *w) +{ + en_handbook_typescript_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_handbook_typescript_page(void) +{ + return ui_create_widget_with_prototype( + en_handbook_typescript_page_proto); +} + +void ui_register_en_handbook_typescript_page(void) +{ + en_handbook_typescript_page_init_prototype(); + en_handbook_typescript_page_proto->init = + en_handbook_typescript_page_init; + en_handbook_typescript_page_proto->destroy = + en_handbook_typescript_page_destroy; +} diff --git a/examples/doc-viewer/app/en/handbook/typescript/page.h b/examples/doc-viewer/app/en/handbook/typescript/page.h new file mode 100644 index 000000000..578535aaf --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/typescript/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_handbook_typescript_page(void); + +ui_widget_t *ui_create_en_handbook_typescript_page(void); + +void en_handbook_typescript_page_update(ui_widget_t *w); + +void ui_load_en_handbook_typescript_page_resources(void); diff --git a/examples/doc-viewer/app/en/handbook/typescript/page.tsx b/examples/doc-viewer/app/en/handbook/typescript/page.tsx new file mode 100644 index 000000000..193092adb --- /dev/null +++ b/examples/doc-viewer/app/en/handbook/typescript/page.tsx @@ -0,0 +1,192 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function TypescriptDocPage() { + return ( + +

TypeScript & TSX Development

+

{`LCUI supports a React-like development experience using TypeScript and JSX syntax, compiled by [bgcolor=#eee] @lcui/cli [/bgcolor].`}

+ +

Setup

+

{`Install the CLI:`}

+ + + Shell + + + + {`npm install -g @lcui/cli`} + + +

{`Create a new project:`}

+ + + Shell + + + + {`lcui create my-app`} + {`[color=#953800]cd[/color] my-app`} + + +

{`The generated project includes:`}

+
    +
  • {`[bgcolor=#eee] src/app.tsx [/bgcolor] — Root component`}
  • +
  • {`[bgcolor=#eee] xmake.lua [/bgcolor] — Build configuration`}
  • +
  • {`[bgcolor=#eee] package.json [/bgcolor] — Node dependencies`}
  • +
+
+ +

Writing components

+

{`Components are plain TypeScript functions that return JSX:`}

+ + + TypeScript + + + + {`[color=#cf222e]import[/color] { [color=#8250df]Button[/color], [color=#8250df]Text[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]interface[/color] [color=#8250df]GreetingProps[/color] {`} + {`  [color=#0550ae]name[/color]: [color=#953800]string[/color];`} + {`}`} + {` `} + {`[color=#cf222e]function[/color] [color=#8250df]Greeting[/color]([color=#0550ae]{ name }: [color=#8250df]GreetingProps[/color][/color]) {`} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]style[/color]=[color=#0a3069]{{[/color] [color=#0550ae]padding:[/color] [color=#0550ae]16[/color] }}>[/color]`} + {`      [color=#116329]<[color=#0550ae]Text[/color]>[/color]Hello, {name}![color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]return[/color] [color=#116329]<[color=#0550ae]Greeting[/color] [color=#0550ae]name[/color]=[color=#0a3069]"World"[/color] />[/color];`} + {`}`} + + +
+ +

State management

+

{`Use the [bgcolor=#eee] useState [/bgcolor] hook:`}

+ + + TypeScript + + + + {`[color=#cf222e]import[/color] { [color=#8250df]Button[/color], [color=#8250df]Text[/color], useState } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]Counter[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]const[/color] \\[count, setCount] = [color=#8250df]useState[/color]([color=#0550ae]0[/color]);`} + {` `} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]div[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]Text[/color]>[/color]Count: {count}[color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]Button[/color] [color=#0550ae]onClick[/color]=[color=#0a3069]{()[/color] =>[/color] setCount(count + 1)}>Increment[color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + + +
+ +

Compiling TSX to C

+

{`The CLI compiles TSX to a C header at build time:`}

+ + + Shell + + + + {`lcui build`} + + +

{`This generates [bgcolor=#eee] ui.h [/bgcolor] from [bgcolor=#eee] ui.tsx [/bgcolor], which you include in your C code:`}

+ + + C + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069]"ui.h"[/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        ui_load(); [color=#6e7781]/* calls the generated widget setup code */[/color]`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + +
+ +

Available packages

+ + + + {`Package`} + + + {`Description`} + + + + + {`[bgcolor=#eee] @lcui/react [/bgcolor]`} + + + {`Core React-like runtime, hooks, and built-in widget bindings (Button, Text, TextInput, …)`} + + + + + {`[bgcolor=#eee] @lcui/router [/bgcolor]`} + + + {`File-system based page router`} + + + +
+ +

CSS Modules

+

{`You can import [bgcolor=#eee] .module.css [/bgcolor] files in your TSX components:`}

+ + + TypeScript + + + + {`[color=#cf222e]import[/color] styles [color=#cf222e]from[/color] [color=#0a3069]"./App.module.css"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]return[/color] [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]className[/color]=[color=#0a3069]{styles.container}[/color]>[/color]Hello[color=#116329][/color];`} + {`}`} + + +
+ +

Tailwind CSS

+

{`Tailwind CSS class names are supported out of the box in LCUI CLI projects:`}

+ + + TypeScript + + + + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]className[/color]=[color=#0a3069]"flex flex-col p-4 gap-2"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]span[/color] [color=#0550ae]className[/color]=[color=#0a3069]"text-lg font-bold"[/color]>[/color]Title[color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]button[/color] [color=#0550ae]className[/color]=[color=#0a3069]"bg-blue-500 text-white px-4 py-2 rounded"[/color]>[/color]`} + {`        Click me`} + {`      [color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + + +
+
+ ); +} diff --git a/examples/doc-viewer/app/en/overview/about/page.c b/examples/doc-viewer/app/en/overview/about/page.c new file mode 100644 index 000000000..17fb006de --- /dev/null +++ b/examples/doc-viewer/app/en/overview/about/page.c @@ -0,0 +1,52 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_overview_about_page_react_t base; + // Add additional states to your component here + // ... +} en_overview_about_page_t; + +static void en_overview_about_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_overview_about_page_proto, + sizeof(en_overview_about_page_t)); + en_overview_about_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_overview_about_page_update(w); +} + +static en_overview_about_page_t *en_overview_about_page_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, en_overview_about_page_proto); +} + +static void en_overview_about_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_overview_about_page_react_destroy(w); +} + +void en_overview_about_page_update(ui_widget_t *w) +{ + en_overview_about_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_overview_about_page(void) +{ + return ui_create_widget_with_prototype(en_overview_about_page_proto); +} + +void ui_register_en_overview_about_page(void) +{ + en_overview_about_page_init_prototype(); + en_overview_about_page_proto->init = en_overview_about_page_init; + en_overview_about_page_proto->destroy = en_overview_about_page_destroy; +} diff --git a/examples/doc-viewer/app/en/overview/about/page.h b/examples/doc-viewer/app/en/overview/about/page.h new file mode 100644 index 000000000..25f033cad --- /dev/null +++ b/examples/doc-viewer/app/en/overview/about/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_overview_about_page(void); + +ui_widget_t *ui_create_en_overview_about_page(void); + +void en_overview_about_page_update(ui_widget_t *w); + +void ui_load_en_overview_about_page_resources(void); diff --git a/examples/doc-viewer/app/en/overview/about/page.tsx b/examples/doc-viewer/app/en/overview/about/page.tsx new file mode 100644 index 000000000..95ccff85f --- /dev/null +++ b/examples/doc-viewer/app/en/overview/about/page.tsx @@ -0,0 +1,61 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function AboutDocPage() { + return ( + +

About LCUI

+

{`LCUI is an open-source desktop graphical user interface library written in C, designed to provide C developers with a simple and easy-to-use GUI development experience, while incorporating CSS styling and declarative UI description from web development to lower the learning barrier.`}

+ +

Key features

+
    +
  • {`[b]Cross-platform[/b] — Supports Windows and Linux.`}
  • +
  • {`[b]Fully self-drawn widgets[/b] — Widgets maintain consistent appearance and behavior across platforms.`}
  • +
  • {`[b]DPI-adaptive[/b] — Automatically scales the UI on high-resolution screens for crisp display.`}
  • +
  • {`[b]Built-in CSS engine[/b] — Supports using CSS to define UI styles and layouts, making it easy to pick up for those with web development experience.`}
  • +
  • {`[b]Modern development tools[/b] — Through the [bgcolor=#eee] @lcui/cli [/bgcolor] tool, you can use TypeScript with JSX syntax to write user interfaces.`}
  • +
+
+ +

Who should use LCUI

+

{`LCUI is suitable for these developers:`}

+
    +
  • {`Want to keep using C on the desktop, but want to escape the tedious Win32 / X11 native development experience.`}
  • +
  • {`Already familiar with web frontend (HTML, CSS) and want to transfer that experience to desktop applications.`}
  • +
  • {`Need to build single-window desktop tools with simple UI content.`}
  • +
+

{`If your use case is a large commercial desktop product, a game engine, or a tool deeply integrated with the OS, LCUI may not be the best choice; in such scenarios, consider Qt, GTK, or native APIs instead.`}

+
+ +

Architecture

+

{`LCUI is divided into four layers from top to bottom:`}

+

Application layer

+

{`Your business code: custom widgets, CSS styles, TSX/JSX code, event handling. This is the only part tied to your project domain.`}

+

LCUI Runtime

+

{`Initialization, event loop, application lifecycle management. Responsible for running the app, dispatching events, and driving rendering.`}

+

UI Helpers

+

{`UI XML parsing, UI Router, cursor management, internationalization (i18n), and other helper modules. These package common UI behaviors into pluggable subsystems.`}

+

Foundation layer

+

{`YUtil (general utility library), PandaGL (2D rendering engine), CSS engine, UI widget system, Thread / Worker abstractions. These modules can also be used independently.`}

+

{`The platform layer (Windows / Linux) handles window management and input events.`}

+
+ +

License

+

{`LCUI is released under the MIT License. See LICENSE.TXT in the repository root for details.`}

+
+ +

Contributing

+

{`Contributions are welcome! Before submitting a Pull Request, please read CONTRIBUTING.md in the repository root.`}

+
    +
  • {`[b]Bug reports[/b] — Open an issue on GitHub Issues.`}
  • +
  • {`[b]Feature requests[/b] — Start a discussion on GitHub Discussions.`}
  • +
  • {`[b]Code contributions[/b] — Fork the repo, create a branch, and submit a PR.`}
  • +
+
+ +

Community

+

{`If you run into issues, you can ask questions on GitHub Discussions (use the [bgcolor=#eee] Q&A [/bgcolor] label). We also encourage experienced users to help newcomers.`}

+
+
+ ); +} diff --git a/examples/doc-viewer/app/en/overview/quick-start/page.c b/examples/doc-viewer/app/en/overview/quick-start/page.c new file mode 100644 index 000000000..b9ad9b0a7 --- /dev/null +++ b/examples/doc-viewer/app/en/overview/quick-start/page.c @@ -0,0 +1,56 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_overview_quick_start_page_react_t base; + // Add additional states to your component here + // ... +} en_overview_quick_start_page_t; + +static void en_overview_quick_start_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_overview_quick_start_page_proto, + sizeof(en_overview_quick_start_page_t)); + en_overview_quick_start_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_overview_quick_start_page_update(w); +} + +static en_overview_quick_start_page_t *en_overview_quick_start_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, en_overview_quick_start_page_proto); +} + +static void en_overview_quick_start_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_overview_quick_start_page_react_destroy(w); +} + +void en_overview_quick_start_page_update(ui_widget_t *w) +{ + en_overview_quick_start_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_overview_quick_start_page(void) +{ + return ui_create_widget_with_prototype( + en_overview_quick_start_page_proto); +} + +void ui_register_en_overview_quick_start_page(void) +{ + en_overview_quick_start_page_init_prototype(); + en_overview_quick_start_page_proto->init = + en_overview_quick_start_page_init; + en_overview_quick_start_page_proto->destroy = + en_overview_quick_start_page_destroy; +} diff --git a/examples/doc-viewer/app/en/overview/quick-start/page.h b/examples/doc-viewer/app/en/overview/quick-start/page.h new file mode 100644 index 000000000..8e58cadd2 --- /dev/null +++ b/examples/doc-viewer/app/en/overview/quick-start/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_overview_quick_start_page(void); + +ui_widget_t *ui_create_en_overview_quick_start_page(void); + +void en_overview_quick_start_page_update(ui_widget_t *w); + +void ui_load_en_overview_quick_start_page_resources(void); diff --git a/examples/doc-viewer/app/en/overview/quick-start/page.tsx b/examples/doc-viewer/app/en/overview/quick-start/page.tsx new file mode 100644 index 000000000..4655af24e --- /dev/null +++ b/examples/doc-viewer/app/en/overview/quick-start/page.tsx @@ -0,0 +1,65 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function QuickStartDocPage() { + return ( + +

Quick Start

+

{`Get up and running with LCUI in minutes.`}

+ +

Prerequisites

+
    +
  • {`[b]Operating system[/b] — Windows (recommended) or Linux`}
  • +
  • {`[b]Node.js[/b] — Required to run [bgcolor=#eee] @lcui/cli [/bgcolor]`}
  • +
  • {`[b]xmake[/b] — C/C++ build tool`}
  • +
  • {`[b]Git[/b] — Download and manage source code`}
  • +
+
+ +

Installation

+

{`Install the LCUI CLI globally:`}

+ + + Shell + + + + {`npm install -g @lcui/cli`} + + +

{`Create and run your first app:`}

+ + + Shell + + + + {`lcui create my-app`} + {`[color=#953800]cd[/color] my-app`} + {`lcui build`} + {`xmake run app`} + + +

{`[bgcolor=#eee] lcui create [/bgcolor] clones a minimal project from the lcui-quick-start template repository, including xmake.lua configuration, example code, and dependencies. Once done, run [bgcolor=#eee] lcui build [/bgcolor] to compile TSX resources, then [bgcolor=#eee] xmake run app [/bgcolor] to launch the application.`}

+
+ +

Next steps

+
    +
  • {`Explore the sample project generated by [bgcolor=#eee] lcui create [/bgcolor] — look at the code and file structure to understand the basics of an LCUI application.`}
  • +
  • {`Read the widget reference (Button, Text, TextInput, Anchor, ScrollArea) to learn about built-in widgets.`}
  • +
  • {`Read the Styling chapter to learn how to apply CSS properties to widgets.`}
  • +
  • {`Read the Customization chapter to learn how to create custom widgets.`}
  • +
  • {`Read the TSX & Dev Tools chapter to understand [bgcolor=#eee] @lcui/react [/bgcolor] usage and limitations in depth.`}
  • +
+
+ +

Having trouble?

+

{`If you run into problems while learning, you can get help through:`}

+
    +
  • {`Ask questions on GitHub Discussions (use the [bgcolor=#eee] Q&A [/bgcolor] label).`}
  • +
  • {`Check CONTRIBUTING.md in the repository root to learn how to contribute.`}
  • +
+
+
+ ); +} diff --git a/examples/doc-viewer/app/en/widgets/anchor/page.c b/examples/doc-viewer/app/en/widgets/anchor/page.c new file mode 100644 index 000000000..643005608 --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/anchor/page.c @@ -0,0 +1,52 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_widgets_anchor_page_react_t base; + // Add additional states to your component here + // ... +} en_widgets_anchor_page_t; + +static void en_widgets_anchor_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_widgets_anchor_page_proto, + sizeof(en_widgets_anchor_page_t)); + en_widgets_anchor_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_widgets_anchor_page_update(w); +} + +static en_widgets_anchor_page_t *en_widgets_anchor_page_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, en_widgets_anchor_page_proto); +} + +static void en_widgets_anchor_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_widgets_anchor_page_react_destroy(w); +} + +void en_widgets_anchor_page_update(ui_widget_t *w) +{ + en_widgets_anchor_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_widgets_anchor_page(void) +{ + return ui_create_widget_with_prototype(en_widgets_anchor_page_proto); +} + +void ui_register_en_widgets_anchor_page(void) +{ + en_widgets_anchor_page_init_prototype(); + en_widgets_anchor_page_proto->init = en_widgets_anchor_page_init; + en_widgets_anchor_page_proto->destroy = en_widgets_anchor_page_destroy; +} diff --git a/examples/doc-viewer/app/en/widgets/anchor/page.h b/examples/doc-viewer/app/en/widgets/anchor/page.h new file mode 100644 index 000000000..cf7ae444c --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/anchor/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_widgets_anchor_page(void); + +ui_widget_t *ui_create_en_widgets_anchor_page(void); + +void en_widgets_anchor_page_update(ui_widget_t *w); + +void ui_load_en_widgets_anchor_page_resources(void); diff --git a/examples/doc-viewer/app/en/widgets/anchor/page.tsx b/examples/doc-viewer/app/en/widgets/anchor/page.tsx new file mode 100644 index 000000000..5e7e8e82b --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/anchor/page.tsx @@ -0,0 +1,111 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; +import AnchorBasicDemo from "../../../examples/anchor-basic/index"; + +export default function AnchorDocPage() { + return ( + +

Anchor

+

{`A navigation widget similar to the HTML [bgcolor=#eee] [/bgcolor] element. It can open external URLs in the system browser or load an XML view into a target container widget.`}

+ + +

API

+

`ui_anchor_open`

+ + + C + + + + {`[color=#953800]void[/color] [color=#8250df]ui_anchor_open[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w)[/color];`} + + +

{`Programmatically triggers the anchor's action (same as a click). Reads the [bgcolor=#eee] href [/bgcolor] attribute from the widget:`}

+
    +
  • {`If [bgcolor=#eee] href [/bgcolor] starts with [bgcolor=#eee] http:// [/bgcolor] or [bgcolor=#eee] https:// [/bgcolor] — opens in the system browser.`}
  • +
  • {`If [bgcolor=#eee] href [/bgcolor] starts with [bgcolor=#eee] file:/// [/bgcolor] — opens the local file in the system browser.`}
  • +
  • {`Otherwise — asynchronously loads an XML file at the given path and injects its content into the widget identified by the [bgcolor=#eee] target [/bgcolor] attribute.`}
  • +
+
+ +

XML tag

+ + + XML + + + + {`[color=#116329]<[color=#0550ae]a[/color] [color=#0550ae]href[/color]=[color=#0a3069]"..."[/color] [color=#0550ae]target[/color]=[color=#0a3069]"..."[/color] [color=#0550ae]key[/color]=[color=#0a3069]"..."[/color]>[/color]Link text[color=#116329][/color]`} + + +

{`Attributes:`}

+ + + + {`Attribute`} + + + {`Required`} + + + {`Description`} + + + + + {`[bgcolor=#eee] href [/bgcolor]`} + + + {`Yes`} + + + {`URL to open, or relative XML file path to load`} + + + + + {`[bgcolor=#eee] target [/bgcolor]`} + + + {`For view loading`} + + + {`ID of the container widget where the loaded view is injected`} + + + + + {`[bgcolor=#eee] key [/bgcolor]`} + + + {`No`} + + + {`Arbitrary string passed as [bgcolor=#eee] event.data [/bgcolor] to the [bgcolor=#eee] loaded.anchor [/bgcolor] event`} + + + +
+ +

Events

+

`loaded.anchor`

+

{`Fired on [bgcolor=#eee] ui_root() [/bgcolor] after a view has been loaded and injected:`}

+ + + C + + + + {`[color=#953800]static[/color] [color=#953800]void[/color] [color=#8250df]on_view_loaded[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w, [color=#953800]ui_event_t[/color] *e, [color=#953800]void[/color] *arg)[/color]`} + {`{`} + {`        [color=#6e7781]/* e->data contains the value of the anchor's "key" attribute */[/color]`} + {`        [color=#953800]printf[/color]([color=#0a3069]"Loaded view key: %s\\n"[/color], ([color=#953800]char[/color] *)e->data);`} + {`}`} + {` `} + {`ui_widget_on(ui_root(), [color=#0a3069]"loaded.anchor"[/color], on_view_loaded, [color=#0550ae]NULL[/color]);`} + + +
+
+ ); +} diff --git a/examples/doc-viewer/app/en/widgets/button/page.c b/examples/doc-viewer/app/en/widgets/button/page.c new file mode 100644 index 000000000..dfcc118c5 --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/button/page.c @@ -0,0 +1,52 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_widgets_button_page_react_t base; + // Add additional states to your component here + // ... +} en_widgets_button_page_t; + +static void en_widgets_button_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_widgets_button_page_proto, + sizeof(en_widgets_button_page_t)); + en_widgets_button_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_widgets_button_page_update(w); +} + +static en_widgets_button_page_t *en_widgets_button_page_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, en_widgets_button_page_proto); +} + +static void en_widgets_button_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_widgets_button_page_react_destroy(w); +} + +void en_widgets_button_page_update(ui_widget_t *w) +{ + en_widgets_button_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_widgets_button_page(void) +{ + return ui_create_widget_with_prototype(en_widgets_button_page_proto); +} + +void ui_register_en_widgets_button_page(void) +{ + en_widgets_button_page_init_prototype(); + en_widgets_button_page_proto->init = en_widgets_button_page_init; + en_widgets_button_page_proto->destroy = en_widgets_button_page_destroy; +} diff --git a/examples/doc-viewer/app/en/widgets/button/page.h b/examples/doc-viewer/app/en/widgets/button/page.h new file mode 100644 index 000000000..5a6b93c65 --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/button/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_widgets_button_page(void); + +ui_widget_t *ui_create_en_widgets_button_page(void); + +void en_widgets_button_page_update(ui_widget_t *w); + +void ui_load_en_widgets_button_page_resources(void); diff --git a/examples/doc-viewer/app/en/widgets/button/page.tsx b/examples/doc-viewer/app/en/widgets/button/page.tsx new file mode 100644 index 000000000..8e6444d95 --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/button/page.tsx @@ -0,0 +1,42 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; +import ButtonBasicDemo from "../../../examples/button-basic/index"; +import FieldTable from "../../../components/field-table"; +import { buttonFields } from "../../../widget-fields/button"; + +export default function ButtonDocPage() { + return ( + +

Button

+

{`A clickable button widget, typically used to trigger an action.`}

+ + +

Use cases

+
    +
  • {`[b]Suitable[/b]: users click to perform an action (submit a form, open a page, toggle a state)`}
  • +
  • {`[b]Suitable[/b]: interactive entry points in toolbars, dialogs, and navbars`}
  • +
  • {`[b]Not suitable[/b]: non-interactive text display (use [bgcolor=#eee] text [/bgcolor] instead)`}
  • +
+
+ +

Anatomy

+ + + Anatomy + + + + {`[color=#cf222e]import[/color] { [color=#8250df]Button[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#116329]<[color=#0550ae]Button[/color] />[/color]`} + + +

{`Button is a single-line widget composed of a background layer and text content. The [bgcolor=#eee] :hover [/bgcolor] / [bgcolor=#eee] :active [/bgcolor] pseudo-classes toggle the background color to provide click feedback.`}

+
+ +

API Reference

+ +
+
+ ); +} diff --git a/examples/doc-viewer/app/en/widgets/scrollarea/page.c b/examples/doc-viewer/app/en/widgets/scrollarea/page.c new file mode 100644 index 000000000..0e4470e41 --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/scrollarea/page.c @@ -0,0 +1,56 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_widgets_scrollarea_page_react_t base; + // Add additional states to your component here + // ... +} en_widgets_scrollarea_page_t; + +static void en_widgets_scrollarea_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_widgets_scrollarea_page_proto, + sizeof(en_widgets_scrollarea_page_t)); + en_widgets_scrollarea_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_widgets_scrollarea_page_update(w); +} + +static en_widgets_scrollarea_page_t *en_widgets_scrollarea_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, en_widgets_scrollarea_page_proto); +} + +static void en_widgets_scrollarea_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_widgets_scrollarea_page_react_destroy(w); +} + +void en_widgets_scrollarea_page_update(ui_widget_t *w) +{ + en_widgets_scrollarea_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_widgets_scrollarea_page(void) +{ + return ui_create_widget_with_prototype( + en_widgets_scrollarea_page_proto); +} + +void ui_register_en_widgets_scrollarea_page(void) +{ + en_widgets_scrollarea_page_init_prototype(); + en_widgets_scrollarea_page_proto->init = + en_widgets_scrollarea_page_init; + en_widgets_scrollarea_page_proto->destroy = + en_widgets_scrollarea_page_destroy; +} diff --git a/examples/doc-viewer/app/en/widgets/scrollarea/page.h b/examples/doc-viewer/app/en/widgets/scrollarea/page.h new file mode 100644 index 000000000..303961c3f --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/scrollarea/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_widgets_scrollarea_page(void); + +ui_widget_t *ui_create_en_widgets_scrollarea_page(void); + +void en_widgets_scrollarea_page_update(ui_widget_t *w); + +void ui_load_en_widgets_scrollarea_page_resources(void); diff --git a/examples/doc-viewer/app/en/widgets/scrollarea/page.tsx b/examples/doc-viewer/app/en/widgets/scrollarea/page.tsx new file mode 100644 index 000000000..e6e1a6494 --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/scrollarea/page.tsx @@ -0,0 +1,175 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; +import ScrollareaBasicDemo from "../../../examples/scrollarea-basic/index"; + +export default function ScrollareaDocPage() { + return ( + +

ScrollArea

+

{`A container that provides scrollable content when children overflow.`}

+ + +

API

+

`ui_create_scrollarea`

+ + + C + + + + {`[color=#953800]ui_widget_t[/color] *[color=#8250df]ui_create_scrollarea[/color][color=#0550ae]([color=#953800]void[/color])[/color];`} + + +

{`Creates and returns a new scroll area widget.`}

+

`ui_create_scrollarea_content`

+ + + C + + + + {`[color=#953800]ui_widget_t[/color] *[color=#8250df]ui_create_scrollarea_content[/color][color=#0550ae]([color=#953800]void[/color])[/color];`} + + +

{`Creates and returns a new scroll content container to be appended inside a scroll area.`}

+

`ui_scrollarea_set_scroll_top`

+ + + C + + + + {`[color=#953800]void[/color] [color=#8250df]ui_scrollarea_set_scroll_top[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w, [color=#953800]float[/color] value)[/color];`} + + +

{`Sets the vertical scroll position in pixels.`}

+

`ui_scrollarea_set_scroll_left`

+ + + C + + + + {`[color=#953800]void[/color] [color=#8250df]ui_scrollarea_set_scroll_left[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w, [color=#953800]float[/color] value)[/color];`} + + +

{`Sets the horizontal scroll position in pixels.`}

+

`ui_scrollarea_get_scroll_top`

+ + + C + + + + {`[color=#953800]float[/color] [color=#8250df]ui_scrollarea_get_scroll_top[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w)[/color];`} + + +

{`Returns the current vertical scroll position.`}

+

`ui_scrollarea_get_scroll_left`

+ + + C + + + + {`[color=#953800]float[/color] [color=#8250df]ui_scrollarea_get_scroll_left[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w)[/color];`} + + +

{`Returns the current horizontal scroll position.`}

+

`ui_scrollarea_get_scroll_width`

+ + + C + + + + {`[color=#953800]float[/color] [color=#8250df]ui_scrollarea_get_scroll_width[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w)[/color];`} + + +

{`Returns the total scrollable width of the content.`}

+

`ui_scrollarea_get_scroll_height`

+ + + C + + + + {`[color=#953800]float[/color] [color=#8250df]ui_scrollarea_get_scroll_height[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w)[/color];`} + + +

{`Returns the total scrollable height of the content.`}

+

`ui_scrollarea_set_wheel_scroll_direction`

+ + + C + + + + {`[color=#953800]void[/color] [color=#8250df]ui_scrollarea_set_wheel_scroll_direction[/color][color=#0550ae]([/color]`} + {`[color=#0550ae] [color=#953800]ui_widget_t[/color] *w, [color=#953800]ui_scrollarea_direction_t[/color] direction)[/color];`} + + +

{`Sets which direction the mouse wheel scrolls.`}

+ + + + {`Value`} + + + {`Description`} + + + + + {`[bgcolor=#eee] UI_SCROLLAREA_AUTO [/bgcolor]`} + + + {`Vertical if content is taller; horizontal if wider`} + + + + + {`[bgcolor=#eee] UI_SCROLLAREA_VERTICAL [/bgcolor]`} + + + {`Always scroll vertically`} + + + + + {`[bgcolor=#eee] UI_SCROLLAREA_HORIZONTAL [/bgcolor]`} + + + {`Always scroll horizontally`} + + + +

`ui_scrollarea_update`

+ + + C + + + + {`[color=#953800]void[/color] [color=#8250df]ui_scrollarea_update[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w)[/color];`} + + +

{`Forces the scroll area to recalculate its layout and scrollbar positions.`}

+
+ +

XML tag

+ + + XML + + + + {`[color=#116329]<[color=#0550ae]scrollarea[/color] [color=#0550ae]style[/color]=[color=#0a3069]"width: 300px; height: 200px;"[/color]>[/color]`} + {`  [color=#6e7781][/color]`} + {`[color=#116329][/color]`} + + +
+
+ ); +} diff --git a/examples/doc-viewer/app/en/widgets/text-input/page.c b/examples/doc-viewer/app/en/widgets/text-input/page.c new file mode 100644 index 000000000..a8a40ceba --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/text-input/page.c @@ -0,0 +1,56 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_widgets_text_input_page_react_t base; + // Add additional states to your component here + // ... +} en_widgets_text_input_page_t; + +static void en_widgets_text_input_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_widgets_text_input_page_proto, + sizeof(en_widgets_text_input_page_t)); + en_widgets_text_input_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_widgets_text_input_page_update(w); +} + +static en_widgets_text_input_page_t *en_widgets_text_input_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, en_widgets_text_input_page_proto); +} + +static void en_widgets_text_input_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_widgets_text_input_page_react_destroy(w); +} + +void en_widgets_text_input_page_update(ui_widget_t *w) +{ + en_widgets_text_input_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_widgets_text_input_page(void) +{ + return ui_create_widget_with_prototype( + en_widgets_text_input_page_proto); +} + +void ui_register_en_widgets_text_input_page(void) +{ + en_widgets_text_input_page_init_prototype(); + en_widgets_text_input_page_proto->init = + en_widgets_text_input_page_init; + en_widgets_text_input_page_proto->destroy = + en_widgets_text_input_page_destroy; +} diff --git a/examples/doc-viewer/app/en/widgets/text-input/page.h b/examples/doc-viewer/app/en/widgets/text-input/page.h new file mode 100644 index 000000000..740082950 --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/text-input/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_widgets_text_input_page(void); + +ui_widget_t *ui_create_en_widgets_text_input_page(void); + +void en_widgets_text_input_page_update(ui_widget_t *w); + +void ui_load_en_widgets_text_input_page_resources(void); diff --git a/examples/doc-viewer/app/en/widgets/text-input/page.tsx b/examples/doc-viewer/app/en/widgets/text-input/page.tsx new file mode 100644 index 000000000..88301fece --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/text-input/page.tsx @@ -0,0 +1,215 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; +import TextInputBasicDemo from "../../../examples/text-input-basic/index"; + +export default function TextInputDocPage() { + return ( + +

TextInput

+

{`An editable text input widget. Supports single-line, multiline, password, placeholder, and readonly modes.`}

+ + +

API

+

`ui_textinput_set_text`

+ + + C + + + + {`[color=#953800]int[/color] [color=#8250df]ui_textinput_set_text[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *widget, [color=#953800]const[/color] [color=#953800]char[/color] *utf8_str)[/color];`} + + +

{`Sets the input value from a UTF-8 string.`}

+

`ui_textinput_set_text_w`

+ + + C + + + + {`[color=#953800]int[/color] [color=#8250df]ui_textinput_set_text_w[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *widget, [color=#953800]const[/color] [color=#953800]wchar_t[/color] *wstr)[/color];`} + + +

{`Sets the input value from a wide character string.`}

+

`ui_textinput_get_text_w`

+ + + C + + + + {`[color=#953800]size_t[/color] [color=#8250df]ui_textinput_get_text_w[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w, [color=#953800]size_t[/color] start,[/color]`} + {`[color=#0550ae] [color=#953800]size_t[/color] max_len, [color=#953800]wchar_t[/color] *buf)[/color];`} + + +

{`Reads the current input value. Returns the number of characters written.`}

+

`ui_textinput_get_text_length`

+ + + C + + + + {`[color=#953800]size_t[/color] [color=#8250df]ui_textinput_get_text_length[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w)[/color];`} + + +

{`Returns the current text length in characters.`}

+

`ui_textinput_clear_text`

+ + + C + + + + {`[color=#953800]void[/color] [color=#8250df]ui_textinput_clear_text[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *widget)[/color];`} + + +

{`Clears all text from the input.`}

+

`ui_textinput_set_placeholder`

+ + + C + + + + {`[color=#953800]int[/color] [color=#8250df]ui_textinput_set_placeholder[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w, [color=#953800]const[/color] [color=#953800]char[/color] *str)[/color];`} + + +

{`Sets the placeholder text shown when the input is empty.`}

+

`ui_textinput_set_placeholder_w`

+ + + C + + + + {`[color=#953800]int[/color] [color=#8250df]ui_textinput_set_placeholder_w[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w, [color=#953800]const[/color] [color=#953800]wchar_t[/color] *wstr)[/color];`} + + +

{`Sets the placeholder text from a wide character string.`}

+

`ui_textinput_set_password_char`

+ + + C + + + + {`[color=#953800]void[/color] [color=#8250df]ui_textinput_set_password_char[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w, [color=#953800]wchar_t[/color] ch)[/color];`} + + +

{`Masks the input with the given character (e.g. [bgcolor=#eee] L'*' [/bgcolor] for password fields).`}

+

`ui_textinput_enable_multiline`

+ + + C + + + + {`[color=#953800]void[/color] [color=#8250df]ui_textinput_enable_multiline[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *widget, [color=#953800]bool[/color] enable)[/color];`} + + +

{`Enables or disables multiline input mode.`}

+

`ui_textinput_enable_style_tag`

+ + + C + + + + {`[color=#953800]void[/color] [color=#8250df]ui_textinput_enable_style_tag[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *widget, [color=#953800]bool[/color] enable)[/color];`} + + +

{`Enables or disables inline style tag parsing in the input.`}

+

`ui_textinput_append_text_w`

+ + + C + + + + {`[color=#953800]int[/color] [color=#8250df]ui_textinput_append_text_w[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *widget, [color=#953800]const[/color] [color=#953800]wchar_t[/color] *wstr)[/color];`} + + +

{`Appends text at the end of the current content.`}

+

`ui_textinput_insert_text_w`

+ + + C + + + + {`[color=#953800]int[/color] [color=#8250df]ui_textinput_insert_text_w[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *widget, [color=#953800]const[/color] [color=#953800]wchar_t[/color] *wstr)[/color];`} + + +

{`Inserts text at the current caret position.`}

+

`ui_textinput_set_caret_blink`

+ + + C + + + + {`[color=#953800]void[/color] [color=#8250df]ui_textinput_set_caret_blink[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w, [color=#953800]bool[/color] visible, [color=#953800]int[/color] time)[/color];`} + + +

{`Controls the caret blink animation. [bgcolor=#eee] time [/bgcolor] is the blink interval in milliseconds.`}

+
+ +

XML tag

+ + + XML + + + + {`[color=#116329]<[color=#0550ae]textedit[/color] [color=#0550ae]placeholder[/color]=[color=#0a3069]"..."[/color] [color=#0550ae]style[/color]=[color=#0a3069]"width: 200px;"[/color] />[/color]`} + + +

{`Attributes:`}

+ + + + {`Attribute`} + + + {`Description`} + + + + + {`[bgcolor=#eee] placeholder [/bgcolor]`} + + + {`Placeholder text`} + + + + + {`[bgcolor=#eee] multiline [/bgcolor]`} + + + {`[bgcolor=#eee] "true" [/bgcolor] for multiline mode`} + + + + + {`[bgcolor=#eee] readonly [/bgcolor]`} + + + {`[bgcolor=#eee] "true" [/bgcolor] to make the input read-only`} + + + + + {`[bgcolor=#eee] type [/bgcolor]`} + + + {`[bgcolor=#eee] "password" [/bgcolor] to mask input`} + + + +
+
+ ); +} diff --git a/examples/doc-viewer/app/en/widgets/text/page.c b/examples/doc-viewer/app/en/widgets/text/page.c new file mode 100644 index 000000000..5e2e3a4e4 --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/text/page.c @@ -0,0 +1,52 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_widgets_text_page_react_t base; + // Add additional states to your component here + // ... +} en_widgets_text_page_t; + +static void en_widgets_text_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_widgets_text_page_proto, + sizeof(en_widgets_text_page_t)); + en_widgets_text_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_widgets_text_page_update(w); +} + +static en_widgets_text_page_t *en_widgets_text_page_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, en_widgets_text_page_proto); +} + +static void en_widgets_text_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_widgets_text_page_react_destroy(w); +} + +void en_widgets_text_page_update(ui_widget_t *w) +{ + en_widgets_text_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_widgets_text_page(void) +{ + return ui_create_widget_with_prototype(en_widgets_text_page_proto); +} + +void ui_register_en_widgets_text_page(void) +{ + en_widgets_text_page_init_prototype(); + en_widgets_text_page_proto->init = en_widgets_text_page_init; + en_widgets_text_page_proto->destroy = en_widgets_text_page_destroy; +} diff --git a/examples/doc-viewer/app/en/widgets/text/page.h b/examples/doc-viewer/app/en/widgets/text/page.h new file mode 100644 index 000000000..6251e3312 --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/text/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_widgets_text_page(void); + +ui_widget_t *ui_create_en_widgets_text_page(void); + +void en_widgets_text_page_update(ui_widget_t *w); + +void ui_load_en_widgets_text_page_resources(void); diff --git a/examples/doc-viewer/app/en/widgets/text/page.tsx b/examples/doc-viewer/app/en/widgets/text/page.tsx new file mode 100644 index 000000000..fa4e8e437 --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/text/page.tsx @@ -0,0 +1,152 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; +import TextBasicDemo from "../../../examples/text-basic/index"; + +export default function TextDocPage() { + return ( + +

Text

+

{`A widget for displaying text. Supports single-line and multiline modes, inline style tags, and CSS styling.`}

+ + +

API

+

`ui_text_set_content`

+ + + C + + + + {`[color=#953800]int[/color] [color=#8250df]ui_text_set_content[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w, [color=#953800]const[/color] [color=#953800]char[/color] *utf8_text)[/color];`} + + +

{`Sets the text content from a UTF-8 string. Supports inline style tags.`}

+

`ui_text_set_content_w`

+ + + C + + + + {`[color=#953800]int[/color] [color=#8250df]ui_text_set_content_w[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w, [color=#953800]const[/color] [color=#953800]wchar_t[/color] *text)[/color];`} + + +

{`Sets the text content from a wide character string.`}

+

`ui_text_get_content_w`

+ + + C + + + + {`[color=#953800]size_t[/color] [color=#8250df]ui_text_get_content_w[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w, [color=#953800]wchar_t[/color] *buf, [color=#953800]size_t[/color] size)[/color];`} + + +

{`Reads the current text content into [bgcolor=#eee] buf [/bgcolor] (up to [bgcolor=#eee] size [/bgcolor] wide characters). Returns the number of characters written.`}

+

`ui_text_set_multiline`

+ + + C + + + + {`[color=#953800]void[/color] [color=#8250df]ui_text_set_multiline[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w, [color=#953800]bool[/color] enable)[/color];`} + + +

{`Enables or disables multiline mode. When enabled, [bgcolor=#eee] \\n [/bgcolor] characters create new lines.`}

+
+ +

XML tag

+ + + XML + + + + {`[color=#116329]<[color=#0550ae]text[/color]>[/color]Text content here[color=#116329][/color]`} + + +

{`Attributes:`}

+ + + + {`Attribute`} + + + {`Description`} + + + + + {`[bgcolor=#eee] multiline [/bgcolor]`} + + + {`Set to [bgcolor=#eee] "true" [/bgcolor] to enable multiline mode`} + + + +
+ +

Inline style tags

+

{`The text widget supports a BBCode-like inline styling syntax:`}

+ + + + {`Tag`} + + + {`Example`} + + + {`Effect`} + + + + + {`[bgcolor=#eee] [color=X] [/bgcolor]`} + + + {`[bgcolor=#eee] [color=#ff0000]Red[/color] [/bgcolor]`} + + + {`Text color`} + + + + + {`[bgcolor=#eee] [b] [/bgcolor]`} + + + {`[bgcolor=#eee] [b]Bold[/b] [/bgcolor]`} + + + {`Bold font`} + + + + + {`[bgcolor=#eee] [i] [/bgcolor]`} + + + {`[bgcolor=#eee] [i]Italic[/i] [/bgcolor]`} + + + {`Italic font`} + + + + + {`[bgcolor=#eee] [size=X] [/bgcolor]`} + + + {`[bgcolor=#eee] [size=20]Large[/size] [/bgcolor]`} + + + {`Font size in px`} + + + +
+
+ ); +} diff --git a/examples/doc-viewer/app/examples/anchor-basic/index.c b/examples/doc-viewer/app/examples/anchor-basic/index.c new file mode 100644 index 000000000..4441c76fd --- /dev/null +++ b/examples/doc-viewer/app/examples/anchor-basic/index.c @@ -0,0 +1,51 @@ +#include "index.tsx.h" +#include "index.h" +#include "../../../../../docs/examples/anchor-basic/main.c" + +typedef struct { + anchor_basic_demo_react_t base; + // Add additional states to your component here + // ... +} anchor_basic_demo_t; + +static void anchor_basic_demo_init(ui_widget_t *w) +{ + anchor_basic_demo_t *_that = ui_widget_add_data( + w, anchor_basic_demo_proto, sizeof(anchor_basic_demo_t)); + anchor_basic_demo_proto->proto->init(w); + anchor_basic_demo_react_init(w); + anchor_basic_init(_that->base.refs.preview); + anchor_basic_demo_update(w); +} + +static anchor_basic_demo_t *anchor_basic_demo_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, anchor_basic_demo_proto); +} + +static void anchor_basic_demo_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + anchor_basic_demo_react_destroy(w); +} + +void anchor_basic_demo_update(ui_widget_t *w) +{ + anchor_basic_demo_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_anchor_basic_demo(void) +{ + return ui_create_widget_with_prototype(anchor_basic_demo_proto); +} + +void ui_register_anchor_basic_demo(void) +{ + anchor_basic_demo_init_prototype(); + anchor_basic_demo_proto->init = anchor_basic_demo_init; + anchor_basic_demo_proto->destroy = anchor_basic_demo_destroy; +} diff --git a/examples/doc-viewer/app/examples/anchor-basic/index.tsx b/examples/doc-viewer/app/examples/anchor-basic/index.tsx new file mode 100644 index 000000000..98e11bb12 --- /dev/null +++ b/examples/doc-viewer/app/examples/anchor-basic/index.tsx @@ -0,0 +1,84 @@ +import { Text, Widget } from "@lcui/react"; +import DemoProvider from "../../components/demo-provider"; +import CodeBlockCopy from "../../components/code-block-copy"; + +export default function AnchorBasicDemo() { + return ( + + + + + + example.tsx + main.c + main.c + main.c + ui.xml + + + TSX + C + XML + + + + + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]a[/color] [color=#0550ae]href[/color]=[color=#0a3069]"https://lcui.dev"[/color]>[/color]LCUI Homepage[color=#116329][/color]`} + {`  );`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069]"example.h"[/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        example_load();`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]void[/color] [color=#8250df]anchor_basic_init[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *parent)[/color]`} + {`{`} + {`        [color=#953800]ui_widget_t[/color] *a;`} + {` `} + {`        a = ui_create_widget([color=#0a3069]"a"[/color]);`} + {`        ui_text_set_content(a, [color=#0a3069]"LCUI Homepage"[/color]);`} + {`        ui_widget_set_attr(a, [color=#0a3069]"href"[/color], [color=#0a3069]"https://lcui.dev"[/color]);`} + {`        ui_widget_append(parent, a);`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        ui_load_xml_file([color=#0a3069]"ui.xml"[/color]);`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + {`[color=#6e7781][/color]`} + {`[color=#116329]<[color=#0550ae]lcui-app[/color]>[/color]`} + {`  [color=#116329]<[color=#0550ae]ui[/color]>[/color]`} + {`    [color=#116329]<[color=#0550ae]a[/color] [color=#0550ae]href[/color]=[color=#0a3069]"https://lcui.lc-soft.io"[/color]>[/color]Open LCUI Homepage[color=#116329][/color]`} + {`  [color=#116329][/color]`} + {`[color=#116329][/color]`} + + + + ); +} diff --git a/examples/doc-viewer/app/examples/button-basic/index.c b/examples/doc-viewer/app/examples/button-basic/index.c new file mode 100644 index 000000000..bec3e3542 --- /dev/null +++ b/examples/doc-viewer/app/examples/button-basic/index.c @@ -0,0 +1,45 @@ +#include "index.tsx.h" +#include "index.h" +#include "../../../../../docs/examples/button-basic/main.c" + +typedef struct { + button_basic_demo_react_t base; +} button_basic_demo_t; + +static void button_basic_demo_init(ui_widget_t *w) +{ + button_basic_demo_t *_that = ui_widget_add_data( + w, button_basic_demo_proto, sizeof(button_basic_demo_t)); + button_basic_demo_proto->proto->init(w); + button_basic_demo_react_init(w); + button_basic_init(_that->base.refs.preview); + button_basic_demo_update(w); +} + +static button_basic_demo_t *button_basic_demo_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, button_basic_demo_proto); +} + +static void button_basic_demo_destroy(ui_widget_t *w) +{ + button_basic_demo_proto->proto->destroy(w); + button_basic_demo_react_destroy(w); +} + +void button_basic_demo_update(ui_widget_t *w) +{ + button_basic_demo_react_update(w); +} + +ui_widget_t *ui_create_button_basic_demo(void) +{ + return ui_create_widget_with_prototype(button_basic_demo_proto); +} + +void ui_register_button_basic_demo(void) +{ + button_basic_demo_init_prototype(); + button_basic_demo_proto->init = button_basic_demo_init; + button_basic_demo_proto->destroy = button_basic_demo_destroy; +} diff --git a/examples/doc-viewer/app/examples/button-basic/index.tsx b/examples/doc-viewer/app/examples/button-basic/index.tsx new file mode 100644 index 000000000..b718fbe0b --- /dev/null +++ b/examples/doc-viewer/app/examples/button-basic/index.tsx @@ -0,0 +1,86 @@ +import { Text, Widget } from "@lcui/react"; +import DemoProvider from "../../components/demo-provider"; +import CodeBlockCopy from "../../components/code-block-copy"; + +export default function ButtonBasicDemo() { + return ( + + + + + + example.tsx + main.c + main.c + main.c + ui.xml + + + TSX + C + XML + + + + + {`[color=#cf222e]import[/color] { [color=#8250df]Button[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]return[/color] [color=#116329]<[color=#0550ae]Button[/color]>[/color]Click me[color=#116329][/color];`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#6e7781]/* example.tsx is compiled to example.h by @lcui/cli */[/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069]"example.h"[/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        example_load();`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]void[/color] [color=#8250df]button_basic_init[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *parent)[/color]`} + {`{`} + {`        [color=#953800]ui_widget_t[/color] *btn;`} + {` `} + {`        btn = ui_create_widget([color=#0a3069]"button"[/color]);`} + {`        ui_button_set_text(btn, [color=#0a3069]"Click me"[/color]);`} + {`        ui_widget_append(parent, btn);`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        ui_load_xml_file([color=#0a3069]"ui.xml"[/color]);`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + {`[color=#6e7781][/color]`} + {`[color=#116329]<[color=#0550ae]lcui-app[/color]>[/color]`} + {`  [color=#116329]<[color=#0550ae]ui[/color]>[/color]`} + {`    [color=#116329]<[color=#0550ae]button[/color]>[/color]Click me[color=#116329][/color]`} + {`  [color=#116329][/color]`} + {`[color=#116329][/color]`} + + + + ); +} diff --git a/examples/doc-viewer/app/examples/scrollarea-basic/index.c b/examples/doc-viewer/app/examples/scrollarea-basic/index.c new file mode 100644 index 000000000..bd4a71acb --- /dev/null +++ b/examples/doc-viewer/app/examples/scrollarea-basic/index.c @@ -0,0 +1,45 @@ +#include "index.tsx.h" +#include "index.h" +#include "../../../../../docs/examples/scrollarea-basic/main.c" + +typedef struct { + scrollarea_basic_demo_react_t base; +} scrollarea_basic_demo_t; + +static void scrollarea_basic_demo_init(ui_widget_t *w) +{ + scrollarea_basic_demo_t *_that = ui_widget_add_data( + w, scrollarea_basic_demo_proto, sizeof(scrollarea_basic_demo_t)); + scrollarea_basic_demo_proto->proto->init(w); + scrollarea_basic_demo_react_init(w); + scrollarea_basic_init(_that->base.refs.preview); + scrollarea_basic_demo_update(w); +} + +static scrollarea_basic_demo_t *scrollarea_basic_demo_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, scrollarea_basic_demo_proto); +} + +static void scrollarea_basic_demo_destroy(ui_widget_t *w) +{ + scrollarea_basic_demo_proto->proto->destroy(w); + scrollarea_basic_demo_react_destroy(w); +} + +void scrollarea_basic_demo_update(ui_widget_t *w) +{ + scrollarea_basic_demo_react_update(w); +} + +ui_widget_t *ui_create_scrollarea_basic_demo(void) +{ + return ui_create_widget_with_prototype(scrollarea_basic_demo_proto); +} + +void ui_register_scrollarea_basic_demo(void) +{ + scrollarea_basic_demo_init_prototype(); + scrollarea_basic_demo_proto->init = scrollarea_basic_demo_init; + scrollarea_basic_demo_proto->destroy = scrollarea_basic_demo_destroy; +} diff --git a/examples/doc-viewer/app/examples/scrollarea-basic/index.tsx b/examples/doc-viewer/app/examples/scrollarea-basic/index.tsx new file mode 100644 index 000000000..f9cf0fec7 --- /dev/null +++ b/examples/doc-viewer/app/examples/scrollarea-basic/index.tsx @@ -0,0 +1,139 @@ +import { Text, Widget } from "@lcui/react"; +import DemoProvider from "../../components/demo-provider"; +import CodeBlockCopy from "../../components/code-block-copy"; + +export default function ScrollareaBasicDemo() { + return ( + + + + + + example.tsx + main.c + example.css + main.c + main.c + ui.xml + + + TSX + C + XML + + + + + {`[color=#cf222e]import[/color] { [color=#8250df]ScrollArea[/color], [color=#8250df]ScrollAreaContent[/color], [color=#8250df]Scrollbar[/color], [color=#8250df]Text[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {`[color=#cf222e]import[/color] [color=#0a3069]"./example.css"[/color];`} + {` `} + {`[color=#cf222e]const[/color] content = [color=#0a3069]\`这是一段用于演示滚动区域功能的示例文本。[/color]`} + {`[color=#0a3069]当文本内容超出容器高度时,用户可以通过滚动条来查看其余内容。[/color]`} + {`[color=#0a3069]滚动区域适合阅读长篇文章、展示数据列表。[/color]`} + {`[color=#0a3069]在实际项目中,滚动区域的尺寸通常由其父布局决定,开发者只需关注内容本身。[/color]`} + {`[color=#0a3069]滚动区域可以嵌套使用,构建复杂的多层滚动界面。[/color]`} + {`[color=#0a3069]合理配置滚动方向和样式,可以让界面更加整洁且易于使用。\`[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]ScrollArea[/color] [color=#0550ae]className[/color]=[color=#0a3069]"demo-scrollarea"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]ScrollAreaContent[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]Text[/color]>[/color]{content}[color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]Scrollbar[/color] />[/color]`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069]"example.h"[/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        example_load();`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + {`[color=#953800].demo-scrollarea[/color] {`} + {`  width: [color=#0550ae]300px[/color];`} + {`  height: [color=#0550ae]200px[/color];`} + {`  border: [color=#0550ae]1px[/color] solid [color=#0550ae]#d0d7de[/color];`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]void[/color] [color=#8250df]scrollarea_basic_init[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *parent)[/color]`} + {`{`} + {`        [color=#953800]ui_widget_t[/color] *scroll, *content, *vbar, *text;`} + {` `} + {`        scroll = ui_create_scrollarea();`} + {`        ui_widget_set_style_string(scroll, [color=#0a3069]"width"[/color], [color=#0a3069]"300px"[/color]);`} + {`        ui_widget_set_style_string(scroll, [color=#0a3069]"height"[/color], [color=#0a3069]"200px"[/color]);`} + {`        ui_widget_set_style_string(scroll, [color=#0a3069]"border"[/color], [color=#0a3069]"1px solid #d0d7de"[/color]);`} + {` `} + {`        content = ui_create_scrollarea_content();`} + {`        text = ui_create_widget([color=#0a3069]"text"[/color]);`} + {`        ui_text_set_content_w(`} + {`            text,`} + {`            [color=#0a3069]L"这是一段用于演示滚动区域功能的示例文本。\\n"[/color]`} + {`            [color=#0a3069]L"当文本内容超出容器高度时,用户可以通过滚动条来查看其余内容。\\n"[/color]`} + {`            [color=#0a3069]L"滚动区域适合阅读长篇文章、展示数据列表。\\n"[/color]`} + {`            [color=#0a3069]L"在实际项目中,滚动区域的尺寸通常由其父布局决定,"[/color]`} + {`            [color=#0a3069]L"开发者只需关注内容本身。\\n"[/color]`} + {`            [color=#0a3069]L"滚动区域可以嵌套使用,构建复杂的多层滚动界面。\\n"[/color]`} + {`            [color=#0a3069]L"合理配置滚动方向和样式,可以让界面更加整洁且易于使用。"[/color]);`} + {`        ui_widget_append(content, text);`} + {` `} + {`        vbar = ui_create_widget([color=#0a3069]"scrollbar"[/color]);`} + {` `} + {`        ui_widget_append(scroll, content);`} + {`        ui_widget_append(scroll, vbar);`} + {`        ui_widget_append(parent, scroll);`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        ui_load_xml_file([color=#0a3069]"ui.xml"[/color]);`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + {`[color=#6e7781][/color]`} + {`[color=#116329]<[color=#0550ae]lcui-app[/color]>[/color]`} + {`  [color=#116329]<[color=#0550ae]ui[/color]>[/color]`} + {`    [color=#116329]<[color=#0550ae]scrollarea[/color] [color=#0550ae]style[/color]=[color=#0a3069]"width: 300px; height: 200px;"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]text[/color]>[/color]Item 1[color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]text[/color]>[/color]Item 2[color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]text[/color]>[/color]Item 3[color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]text[/color]>[/color]Item 4[color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]text[/color]>[/color]Item 5[color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]text[/color]>[/color]Item 6[color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]text[/color]>[/color]Item 7[color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]text[/color]>[/color]Item 8[color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]text[/color]>[/color]Item 9[color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]text[/color]>[/color]Item 10[color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  [color=#116329][/color]`} + {`[color=#116329][/color]`} + + + + ); +} diff --git a/examples/doc-viewer/app/examples/scrollarea-dual-scrollbars/index.c b/examples/doc-viewer/app/examples/scrollarea-dual-scrollbars/index.c new file mode 100644 index 000000000..e1b37b26e --- /dev/null +++ b/examples/doc-viewer/app/examples/scrollarea-dual-scrollbars/index.c @@ -0,0 +1,45 @@ +#include "index.tsx.h" +#include "index.h" + +#include "../../../../../docs/examples/scrollarea-dual-scrollbars/main.c" + +typedef struct { + scrollarea_dual_scrollbars_demo_react_t base; +} scrollarea_dual_scrollbars_demo_t; + +static void scrollarea_dual_scrollbars_demo_init(ui_widget_t *w) +{ + scrollarea_dual_scrollbars_demo_t *_that = + ui_widget_add_data(w, scrollarea_dual_scrollbars_demo_proto, + sizeof(scrollarea_dual_scrollbars_demo_t)); + scrollarea_dual_scrollbars_demo_proto->proto->init(w); + scrollarea_dual_scrollbars_demo_react_init(w); + scrollarea_dual_scrollbars_init(_that->base.refs.preview); + scrollarea_dual_scrollbars_demo_update(w); +} + +static void scrollarea_dual_scrollbars_demo_destroy(ui_widget_t *w) +{ + scrollarea_dual_scrollbars_demo_proto->proto->destroy(w); + scrollarea_dual_scrollbars_demo_react_destroy(w); +} + +void scrollarea_dual_scrollbars_demo_update(ui_widget_t *w) +{ + scrollarea_dual_scrollbars_demo_react_update(w); +} + +ui_widget_t *ui_create_scrollarea_dual_scrollbars_demo(void) +{ + return ui_create_widget_with_prototype( + scrollarea_dual_scrollbars_demo_proto); +} + +void ui_register_scrollarea_dual_scrollbars_demo(void) +{ + scrollarea_dual_scrollbars_demo_init_prototype(); + scrollarea_dual_scrollbars_demo_proto->init = + scrollarea_dual_scrollbars_demo_init; + scrollarea_dual_scrollbars_demo_proto->destroy = + scrollarea_dual_scrollbars_demo_destroy; +} diff --git a/examples/doc-viewer/app/examples/scrollarea-dual-scrollbars/index.tsx b/examples/doc-viewer/app/examples/scrollarea-dual-scrollbars/index.tsx new file mode 100644 index 000000000..56b614f00 --- /dev/null +++ b/examples/doc-viewer/app/examples/scrollarea-dual-scrollbars/index.tsx @@ -0,0 +1,196 @@ +import { Text, Widget } from "@lcui/react"; +import DemoProvider from "../../components/demo-provider"; +import CodeBlockCopy from "../../components/code-block-copy"; + +export default function ScrollareaDualScrollbarsDemo() { + return ( + + + + + + example.tsx + main.c + example.css + main.c + main.c + ui.xml + + + TSX + C + XML + + + + + {`[color=#cf222e]import[/color] { [color=#8250df]ScrollArea[/color], [color=#8250df]ScrollAreaContent[/color], [color=#8250df]Scrollbar[/color], [color=#8250df]Text[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {`[color=#cf222e]import[/color] [color=#0a3069]"./example.css"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]ScrollArea[/color] [color=#0550ae]className[/color]=[color=#0a3069]"demo-scrollarea"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]ScrollAreaContent[/color] [color=#0550ae]className[/color]=[color=#0a3069]"demo-grid"[/color]>[/color]`} + {`        {Array.from({ length: 100 }, (_, i) => (`} + {`          [color=#116329]<[color=#0550ae]Text[/color] [color=#0550ae]key[/color]=[color=#0a3069]{i}[/color] [color=#0550ae]className[/color]=[color=#0a3069]"demo-cell"[/color]>[/color]`} + {`            {i + 1}`} + {`          [color=#116329][/color]`} + {`        ))}`} + {`      [color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]Scrollbar[/color] [color=#0550ae]orientation[/color]=[color=#0a3069]"horizontal"[/color] />[/color]`} + {`      [color=#116329]<[color=#0550ae]Scrollbar[/color] />[/color]`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069]"example.h"[/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        example_load();`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + {`[color=#953800].demo-scrollarea[/color] {`} + {`  width: [color=#0550ae]400px[/color];`} + {`  height: [color=#0550ae]300px[/color];`} + {`  border: [color=#0550ae]1px[/color] solid [color=#0550ae]#d0d7de[/color];`} + {`}`} + {` `} + {`[color=#953800].demo-grid[/color] {`} + {`  display: flex;`} + {`  flex-wrap: wrap;`} + {`  width: [color=#0550ae]1088px[/color];`} + {`  height: [color=#0550ae]1088px[/color];`} + {`  gap: [color=#0550ae]8px[/color];`} + {`  padding: [color=#0550ae]8px[/color];`} + {`}`} + {` `} + {`[color=#953800].demo-cell[/color] {`} + {`  width: [color=#0550ae]100px[/color];`} + {`  height: [color=#0550ae]100px[/color];`} + {`  background: [color=#0550ae]#e1e5e9[/color];`} + {`  border: [color=#0550ae]1px[/color] solid [color=#0550ae]#b0b8c0[/color];`} + {`  text-align: center;`} + {`  line-height: [color=#0550ae]100px[/color];`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]void[/color] [color=#8250df]scrollarea_dual_scrollbars_init[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *parent)[/color]`} + {`{`} + {`        [color=#953800]int[/color] i;`} + {`        [color=#953800]char[/color] buf\\[[color=#0550ae]8[/color]];`} + {`        [color=#953800]ui_widget_t[/color] *area, *content, *hbar, *vbar, *box;`} + {` `} + {`        area = ui_create_scrollarea();`} + {`        ui_widget_set_style_string(area, [color=#0a3069]"width"[/color], [color=#0a3069]"420px"[/color]);`} + {`        ui_widget_set_style_string(area, [color=#0a3069]"height"[/color], [color=#0a3069]"300px"[/color]);`} + {`        ui_widget_set_style_string(area, [color=#0a3069]"border"[/color], [color=#0a3069]"1px solid #d0d7de"[/color]);`} + {` `} + {`        content = ui_create_scrollarea_content();`} + {`        ui_widget_set_style_string(content, [color=#0a3069]"display"[/color], [color=#0a3069]"flex"[/color]);`} + {`        ui_widget_set_style_string(content, [color=#0a3069]"flex-wrap"[/color], [color=#0a3069]"wrap"[/color]);`} + {`        ui_widget_set_style_string(content, [color=#0a3069]"width"[/color], [color=#0a3069]"1088px"[/color]);`} + {`        ui_widget_set_style_string(content, [color=#0a3069]"height"[/color], [color=#0a3069]"1088px"[/color]);`} + {`        ui_widget_set_style_string(content, [color=#0a3069]"gap"[/color], [color=#0a3069]"8px"[/color]);`} + {`        ui_widget_set_style_string(content, [color=#0a3069]"padding"[/color], [color=#0a3069]"8px"[/color]);`} + {` `} + {`        [color=#cf222e]for[/color] (i = [color=#0550ae]0[/color]; i < [color=#0550ae]100[/color]; ++i) {`} + {`                [color=#953800]snprintf[/color](buf, [color=#cf222e]sizeof[/color](buf), [color=#0a3069]"%d"[/color], i + [color=#0550ae]1[/color]);`} + {`                box = ui_create_widget([color=#0a3069]"text"[/color]);`} + {`                ui_text_set_content(box, buf);`} + {`                ui_widget_set_style_string(box, [color=#0a3069]"width"[/color], [color=#0a3069]"100px"[/color]);`} + {`                ui_widget_set_style_string(box, [color=#0a3069]"height"[/color], [color=#0a3069]"100px"[/color]);`} + {`                ui_widget_set_style_string(box, [color=#0a3069]"background"[/color], [color=#0a3069]"#e1e5e9"[/color]);`} + {`                ui_widget_set_style_string(box, [color=#0a3069]"border"[/color], [color=#0a3069]"1px solid #b0b8c0"[/color]);`} + {`                ui_widget_set_style_string(box, [color=#0a3069]"text-align"[/color], [color=#0a3069]"center"[/color]);`} + {`                ui_widget_set_style_string(box, [color=#0a3069]"line-height"[/color], [color=#0a3069]"100px"[/color]);`} + {`                ui_widget_append(content, box);`} + {`        }`} + {` `} + {`        hbar = ui_create_widget([color=#0a3069]"scrollbar"[/color]);`} + {`        ui_widget_set_attr(hbar, [color=#0a3069]"orientation"[/color], [color=#0a3069]"horizontal"[/color]);`} + {`        vbar = ui_create_widget([color=#0a3069]"scrollbar"[/color]);`} + {` `} + {`        ui_widget_append(area, content);`} + {`        ui_widget_append(area, hbar);`} + {`        ui_widget_append(area, vbar);`} + {`        ui_widget_append(parent, area);`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        ui_load_xml_file([color=#0a3069]"ui.xml"[/color]);`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + {`[color=#6e7781][/color]`} + {`[color=#116329]<[color=#0550ae]lcui-app[/color]>[/color]`} + {`  [color=#116329]<[color=#0550ae]style[/color]>[/color]`} + {`    [color=#953800].demo-scrollarea[/color] {`} + {`        width: [color=#0550ae]400px[/color];`} + {`        height: [color=#0550ae]300px[/color];`} + {`        border: [color=#0550ae]1px[/color] solid [color=#0550ae]#d0d7de[/color];`} + {`    }`} + {`    [color=#953800].demo-grid[/color] {`} + {`        display: flex;`} + {`        flex-wrap: wrap;`} + {`        width: [color=#0550ae]1088px[/color];`} + {`        height: [color=#0550ae]1088px[/color];`} + {`        gap: [color=#0550ae]8px[/color];`} + {`        padding: [color=#0550ae]8px[/color];`} + {`    }`} + {`    [color=#953800].demo-cell[/color] {`} + {`        width: [color=#0550ae]100px[/color];`} + {`        height: [color=#0550ae]100px[/color];`} + {`        background: [color=#0550ae]#e1e5e9[/color];`} + {`        border: [color=#0550ae]1px[/color] solid [color=#0550ae]#b0b8c0[/color];`} + {`        text-align: center;`} + {`        line-height: [color=#0550ae]100px[/color];`} + {`    }`} + {`  [color=#116329][/color]`} + {`  [color=#116329]<[color=#0550ae]ui[/color]>[/color]`} + {`    [color=#116329]<[color=#0550ae]scrollarea[/color] [color=#0550ae]class[/color]=[color=#0a3069]"demo-scrollarea"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]scrollarea-content[/color] [color=#0550ae]class[/color]=[color=#0a3069]"demo-grid"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]text[/color] [color=#0550ae]class[/color]=[color=#0a3069]"demo-cell"[/color]>[/color]1[color=#116329][/color]`} + {`        [color=#116329]<[color=#0550ae]text[/color] [color=#0550ae]class[/color]=[color=#0a3069]"demo-cell"[/color]>[/color]2[color=#116329][/color]`} + {`        [color=#116329]<[color=#0550ae]text[/color] [color=#0550ae]class[/color]=[color=#0a3069]"demo-cell"[/color]>[/color]3[color=#116329][/color]`} + {`        [color=#116329]<[color=#0550ae]text[/color] [color=#0550ae]class[/color]=[color=#0a3069]"demo-cell"[/color]>[/color]4[color=#116329][/color]`} + {`        [color=#116329]<[color=#0550ae]text[/color] [color=#0550ae]class[/color]=[color=#0a3069]"demo-cell"[/color]>[/color]5[color=#116329][/color]`} + {`        [color=#116329]<[color=#0550ae]text[/color] [color=#0550ae]class[/color]=[color=#0a3069]"demo-cell"[/color]>[/color]6[color=#116329][/color]`} + {`        [color=#116329]<[color=#0550ae]text[/color] [color=#0550ae]class[/color]=[color=#0a3069]"demo-cell"[/color]>[/color]7[color=#116329][/color]`} + {`        [color=#116329]<[color=#0550ae]text[/color] [color=#0550ae]class[/color]=[color=#0a3069]"demo-cell"[/color]>[/color]8[color=#116329][/color]`} + {`        [color=#116329]<[color=#0550ae]text[/color] [color=#0550ae]class[/color]=[color=#0a3069]"demo-cell"[/color]>[/color]9[color=#116329][/color]`} + {`        [color=#116329]<[color=#0550ae]text[/color] [color=#0550ae]class[/color]=[color=#0a3069]"demo-cell"[/color]>[/color]10[color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]scrollbar[/color] [color=#0550ae]orientation[/color]=[color=#0a3069]"horizontal"[/color] />[/color]`} + {`      [color=#116329]<[color=#0550ae]scrollbar[/color] />[/color]`} + {`    [color=#116329][/color]`} + {`  [color=#116329][/color]`} + {`[color=#116329][/color]`} + + + + ); +} diff --git a/examples/doc-viewer/app/examples/text-basic/index.c b/examples/doc-viewer/app/examples/text-basic/index.c new file mode 100644 index 000000000..a0d5a67ff --- /dev/null +++ b/examples/doc-viewer/app/examples/text-basic/index.c @@ -0,0 +1,45 @@ +#include "index.tsx.h" +#include "index.h" +#include "../../../../../docs/examples/text-basic/main.c" + +typedef struct { + text_basic_demo_react_t base; +} text_basic_demo_t; + +static void text_basic_demo_init(ui_widget_t *w) +{ + text_basic_demo_t *_that = ui_widget_add_data( + w, text_basic_demo_proto, sizeof(text_basic_demo_t)); + text_basic_demo_proto->proto->init(w); + text_basic_demo_react_init(w); + text_basic_init(_that->base.refs.preview); + text_basic_demo_update(w); +} + +static text_basic_demo_t *text_basic_demo_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, text_basic_demo_proto); +} + +static void text_basic_demo_destroy(ui_widget_t *w) +{ + text_basic_demo_proto->proto->destroy(w); + text_basic_demo_react_destroy(w); +} + +void text_basic_demo_update(ui_widget_t *w) +{ + text_basic_demo_react_update(w); +} + +ui_widget_t *ui_create_text_basic_demo(void) +{ + return ui_create_widget_with_prototype(text_basic_demo_proto); +} + +void ui_register_text_basic_demo(void) +{ + text_basic_demo_init_prototype(); + text_basic_demo_proto->init = text_basic_demo_init; + text_basic_demo_proto->destroy = text_basic_demo_destroy; +} diff --git a/examples/doc-viewer/app/examples/text-basic/index.tsx b/examples/doc-viewer/app/examples/text-basic/index.tsx new file mode 100644 index 000000000..9d48aa508 --- /dev/null +++ b/examples/doc-viewer/app/examples/text-basic/index.tsx @@ -0,0 +1,84 @@ +import { Text, Widget } from "@lcui/react"; +import DemoProvider from "../../components/demo-provider"; +import CodeBlockCopy from "../../components/code-block-copy"; + +export default function TextBasicDemo() { + return ( + + + + + + example.tsx + main.c + main.c + main.c + ui.xml + + + TSX + C + XML + + + + + {`[color=#cf222e]import[/color] { [color=#8250df]Text[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]return[/color] [color=#116329]<[color=#0550ae]Text[/color]>[/color]Hello, LCUI![color=#116329][/color];`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069]"example.h"[/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        example_load();`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]void[/color] [color=#8250df]text_basic_init[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *parent)[/color]`} + {`{`} + {`        [color=#953800]ui_widget_t[/color] *w;`} + {` `} + {`        w = ui_create_widget([color=#0a3069]"text"[/color]);`} + {`        ui_text_set_content(w, [color=#0a3069]"Hello, LCUI!"[/color]);`} + {`        ui_widget_append(parent, w);`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        ui_load_xml_file([color=#0a3069]"ui.xml"[/color]);`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + {`[color=#6e7781][/color]`} + {`[color=#116329]<[color=#0550ae]lcui-app[/color]>[/color]`} + {`  [color=#116329]<[color=#0550ae]ui[/color]>[/color]`} + {`    [color=#116329]<[color=#0550ae]text[/color]>[/color]Hello, LCUI![color=#116329][/color]`} + {`  [color=#116329][/color]`} + {`[color=#116329][/color]`} + + + + ); +} diff --git a/examples/doc-viewer/app/examples/text-input-basic/index.c b/examples/doc-viewer/app/examples/text-input-basic/index.c new file mode 100644 index 000000000..cbdd7180c --- /dev/null +++ b/examples/doc-viewer/app/examples/text-input-basic/index.c @@ -0,0 +1,45 @@ +#include "index.tsx.h" +#include "index.h" +#include "../../../../../docs/examples/text-input-basic/main.c" + +typedef struct { + text_input_basic_demo_react_t base; +} text_input_basic_demo_t; + +static void text_input_basic_demo_init(ui_widget_t *w) +{ + text_input_basic_demo_t *_that = ui_widget_add_data( + w, text_input_basic_demo_proto, sizeof(text_input_basic_demo_t)); + text_input_basic_demo_proto->proto->init(w); + text_input_basic_demo_react_init(w); + text_input_basic_init(_that->base.refs.preview); + text_input_basic_demo_update(w); +} + +static text_input_basic_demo_t *text_input_basic_demo_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, text_input_basic_demo_proto); +} + +static void text_input_basic_demo_destroy(ui_widget_t *w) +{ + text_input_basic_demo_proto->proto->destroy(w); + text_input_basic_demo_react_destroy(w); +} + +void text_input_basic_demo_update(ui_widget_t *w) +{ + text_input_basic_demo_react_update(w); +} + +ui_widget_t *ui_create_text_input_basic_demo(void) +{ + return ui_create_widget_with_prototype(text_input_basic_demo_proto); +} + +void ui_register_text_input_basic_demo(void) +{ + text_input_basic_demo_init_prototype(); + text_input_basic_demo_proto->init = text_input_basic_demo_init; + text_input_basic_demo_proto->destroy = text_input_basic_demo_destroy; +} diff --git a/examples/doc-viewer/app/examples/text-input-basic/index.tsx b/examples/doc-viewer/app/examples/text-input-basic/index.tsx new file mode 100644 index 000000000..4dc0f6bd8 --- /dev/null +++ b/examples/doc-viewer/app/examples/text-input-basic/index.tsx @@ -0,0 +1,83 @@ +import { Text, Widget } from "@lcui/react"; +import DemoProvider from "../../components/demo-provider"; +import CodeBlockCopy from "../../components/code-block-copy"; + +export default function TextInputBasicDemo() { + return ( + + + + + + example.tsx + main.c + main.c + main.c + ui.xml + + + TSX + C + XML + + + + + {`[color=#cf222e]import[/color] { [color=#8250df]TextInput[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]return[/color] [color=#116329]<[color=#0550ae]TextInput[/color] [color=#0550ae]placeholder[/color]=[color=#0a3069]"请输入..."[/color] />[/color];`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069]"example.h"[/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        example_load();`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]void[/color] [color=#8250df]text_input_basic_init[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *parent)[/color]`} + {`{`} + {`        [color=#953800]ui_widget_t[/color] *w;`} + {` `} + {`        w = ui_create_widget([color=#0a3069]"textinput"[/color]);`} + {`        ui_textinput_set_placeholder(w, [color=#0a3069]u8"请输入..."[/color]);`} + {`        ui_widget_append(parent, w);`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        ui_load_xml_file([color=#0a3069]"ui.xml"[/color]);`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + {`[color=#6e7781][/color]`} + {`[color=#116329]<[color=#0550ae]lcui-app[/color]>[/color]`} + {`  [color=#116329]<[color=#0550ae]ui[/color]>[/color]`} + {`    [color=#116329]<[color=#0550ae]textedit[/color] [color=#0550ae]style[/color]=[color=#0a3069]"width: 200px;"[/color] />[/color]`} + {`  [color=#116329][/color]`} + {`[color=#116329][/color]`} + + + + ); +} diff --git a/examples/doc-viewer/app/global.css b/examples/doc-viewer/app/global.css new file mode 100644 index 000000000..250f784ad --- /dev/null +++ b/examples/doc-viewer/app/global.css @@ -0,0 +1,267 @@ +/* LCUI Documentation Viewer - Global styles + * + * Hand-maintained. Loaded into the doc-viewer via `import "./global.css"` + * in app/layout.tsx; lcui-cli converts this file to app/global.css.h on + * each build and the runtime registers the rules via + * `ui_load_css_string`. + * + * Tailwind utilities are reused through @apply where possible so the + * spacing / typography scale stays consistent with any inline tailwind + * class an MDX-derived page widget might emit. + */ + +@tailwind components; +@tailwind utilities; + +* { + box-sizing: border-box; +} + +root { + min-width: 800px; + min-height: 480px; +} + +text, +p { + @apply text-base text-gray-800; +} + +/* -- Page -- */ + +.doc-page { + @apply px-4 py-8 max-w-3xl mx-auto; +} +.doc-page-desc { + @apply text-lg text-gray-600 mb-6 leading-relaxed; +} +.doc-section { + @apply mb-8; +} + +/* -- Locale-controlled visibility -- + * + * Any element that should only appear when a specific locale is active + * on ui_root() gets both `.lang` and the matching locale class. + * `.lang` hides by default; the override below shows it when the root + * locale matches. Components like sidebar and code-block-copy share + * this pattern. */ + +.lang { + display: none; +} +.en .lang.en, +.zh-CN .lang.zh-CN { + display: block; +} + +/* -- Semantic typography (h1-h6, p) -- + * + * These are registered as `text` widget aliases in app/main.c. Each + * tag maps to a tailwind size on the default type scale; p shares the + * h6 size and is distinguished only by weight. */ + +h1 { + @apply text-4xl font-bold text-gray-900 mb-4; +} +h2 { + @apply text-3xl font-bold text-gray-900 mt-8 mb-3; +} +h3 { + @apply text-2xl font-bold text-gray-900 mt-6 mb-2; +} +h4 { + @apply text-xl font-bold text-gray-900 mt-6 mb-2; +} +h5 { + @apply text-lg font-bold text-gray-900 mt-4 mb-2; +} +h6 { + @apply text-base font-bold text-gray-900 mt-4 mb-2; +} +p { + @apply text-base text-gray-800 mb-3 leading-relaxed; +} + +/* -- Code block card -- + * + * Light-themed card: a 1px border with rounded corners, a gray header + * carrying the file name (or language) plus a clickable Copy button, + * and a white body with one per source line. Both the demo + * code blocks and MDX-derived fenced blocks share this structure + * (see scripts/compiler/page-generator.ts). */ + +.code-block { + @apply rounded border border-gray-200 my-4 bg-white; +} +.code-block-header { + @apply flex flex-row items-center pl-3 pr-1 py-1 bg-gray-50 border-b border-gray-200 min-h-[36px]; +} +.code-block-title { + @apply flex-1 text-sm text-gray-700; +} +.code-block-copy { + position: absolute; + top: 8px; + right: 8px; + @apply flex gap-1 items-center px-2 py-1 text-sm text-gray-600 cursor-pointer rounded; +} +.code-block-copy text { + white-space: nowrap; +} +.code-block-copy .copy-icon, +.code-block-copy .check-icon { + position: relative; + top: 1px; +} +.code-block-copy .check-icon { + display: none; +} +.code-block-copy.copied .copy-icon { + display: none; +} +.code-block-copy.copied .check-icon { + display: inline-block; +} +.code-block-copy:hover { + @apply bg-gray-100 text-gray-900; +} +.code-block-body { + @apply p-3 text-sm text-gray-800 whitespace-pre; + position: relative; + font-family: monospace; +} +.code-line { + @apply text-gray-800; + font-family: monospace; +} + +/* -- Demo widget (see app/components/demo-provider.tsx) -- */ + +.demo { + @apply mb-6; +} +.demo-preview { + @apply px-6 py-8 bg-white border rounded-tl-md rounded-tr-md border-gray-200 flex items-center justify-center min-h-[128px]; +} +.demo .code-block { + @apply rounded-tr-none rounded-tl-none border-t-0 my-0; +} + +/* The code-block wrapper holds the shared card chrome. Inner code + * block bodies are siblings of the header and carry data attributes + * for language/file/source selection. */ + +/* The header uses flex so that the file tab group, the language tab + * group, and the copy button share a single row. The `.demo-files` + * and `.demo-languages` containers themselves are plain blocks; their + * `.demo-tab` children are laid out with `display: inline-block` (see + * "CSS `display` property" in .opencode/skills/lcui-cli/SKILL.md). */ + +.code-block-header .demo-files { + flex: 1; +} +.code-block-header .demo-languages, +.code-block-header .demo-files { + @apply px-1 py-1; +} + +.demo .code-block-header { + @apply px-1; +} + +.demo-tab { + display: inline-block; + @apply px-2 py-1 text-sm rounded-lg mr-1; +} +.demo-tab:hover { + @apply bg-gray-100; +} +.demo-tab.active { + box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.2); + @apply text-gray-900 font-bold bg-white; +} + +/* -- Lists (ol/ul/li) -- + * + * ol/ul are registered as native widgets in app/components/list.c. + * Each li has an absolutely-positioned marker child created in C + * (class .list-marker). The container's padding-left is set per-li + * at runtime in px (LCUI does not currently support em on padding). + * The defaults below apply when no inline override is present. */ + +ol, +ul { + display: block; + @apply my-3; +} +li { + display: block; + position: relative; + padding-left: 20px; + @apply text-base text-gray-800 mb-1; +} +.list-marker { + position: absolute; + left: 0; + top: 0; + @apply text-gray-700; +} + +/* -- Admonitions (:::note / :::info / :::tip / :::caution / :::warning) + * + * Docusaurus-style admonition containers rendered by + * page-generator.ts. Each admonition is a rounded container with a + * coloured left border and a bold title that takes its colour from + * the admonition type. The generator recurses into the body so + * admonitions can contain paragraphs, lists, fenced code blocks, + * and other admonitions. */ + +.admonition { + display: block; + @apply my-4 py-3 px-4 rounded border-l-4 bg-gray-50; +} +.admonition-note { border-left-color: #3b82f6; } +.admonition-info { border-left-color: #06b6d4; } +.admonition-tip { border-left-color: #10b981; } +.admonition-caution { border-left-color: #eab308; } +.admonition-warning { border-left-color: #ef4444; } +.admonition-title { + @apply font-bold mb-1; +} +.admonition-note .admonition-title { color: #1d4ed8; } +.admonition-info .admonition-title { color: #0891b2; } +.admonition-tip .admonition-title { color: #047857; } +.admonition-caution .admonition-title { color: #ca8a04; } +.admonition-warning .admonition-title { color: #b91c1c; } +.admonition-content p, +.admonition-content ul, +.admonition-content ol { + @apply my-1; +} + +/* -- Markdown tables (-- generated by scripts/compiler/page-generator.ts) + * + * LCUI does not support display: table, so every markdown table is + * emitted as a vertical stack of horizontal flex rows. Each cell is + * a widget with either a fixed width (for short, label-style columns) + * or flex-grow (for the last "description" column). A minimum width + * is applied so empty cells do not collapse. */ + +.mdx-table { + display: block; + @apply my-4 rounded border border-gray-200 bg-white; +} +.mdx-table-row { + display: flex; + flex-direction: row; +} +.mdx-table-head { + @apply bg-gray-50 border-b border-gray-200; +} +.mdx-table-cell { + @apply px-3 py-2 text-sm text-gray-800; +} +.mdx-table-head-cell { + @apply font-bold text-gray-900; +} diff --git a/examples/doc-viewer/app/layout.c b/examples/doc-viewer/app/layout.c new file mode 100644 index 000000000..b0e1bf7e0 --- /dev/null +++ b/examples/doc-viewer/app/layout.c @@ -0,0 +1,51 @@ +#include "layout.h" +#include "layout.tsx.h" + +typedef struct { + root_layout_react_t base; + // Add additional states to your component here + // ... +} root_layout_t; + +static void root_layout_init(ui_widget_t *w) +{ + ui_widget_add_data(w, root_layout_proto, sizeof(root_layout_t)); + root_layout_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + root_layout_update(w); +} + +static root_layout_t *root_layout_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, root_layout_proto); +} + +static void root_layout_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + root_layout_react_destroy(w); +} + +void root_layout_update(ui_widget_t *w) +{ + root_layout_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_root_layout(void) +{ + return ui_create_widget_with_prototype(root_layout_proto); +} + +void ui_register_root_layout(void) +{ + root_layout_init_prototype(); + root_layout_proto->init = root_layout_init; + root_layout_proto->destroy = root_layout_destroy; +} diff --git a/examples/doc-viewer/app/layout.h b/examples/doc-viewer/app/layout.h new file mode 100644 index 000000000..8f9c491f5 --- /dev/null +++ b/examples/doc-viewer/app/layout.h @@ -0,0 +1,9 @@ +#include + +void ui_register_root_layout(void); + +ui_widget_t *ui_create_root_layout(void); + +void root_layout_update(ui_widget_t *w); + +void ui_load_root_layout_resources(void); diff --git a/examples/doc-viewer/app/layout.tsx b/examples/doc-viewer/app/layout.tsx new file mode 100644 index 000000000..755ebd744 --- /dev/null +++ b/examples/doc-viewer/app/layout.tsx @@ -0,0 +1,20 @@ +import { PropsWithChildren, ScrollArea, ScrollAreaContent, Scrollbar } from "@lcui/react"; +import Navbar from "./components/navbar"; +import Sidebar from "./components/sidebar"; +import "@lcui/fluent-icons/dist/style.css"; +import "./global.css"; + +export default function AppLayout({ children }: PropsWithChildren) { + return ( +
+ +
+ + + {children} + + +
+
+ ); +} diff --git a/examples/doc-viewer/app/locale.c b/examples/doc-viewer/app/locale.c new file mode 100644 index 000000000..64db942da --- /dev/null +++ b/examples/doc-viewer/app/locale.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include +#include "locale.h" + +#define SETTINGS_SECTION "app" +#define SETTINGS_KEY "locale" +#define DEFAULT_LOCALE "en" + +/* Locales the doc-viewer ships. Used to validate both persisted values + * and OS-detected values, and as the router path-prefix vocabulary. */ +static const char *supported_locales[] = { "en", "zh-CN", NULL }; + +/* Returns true when `needle` is a member of supported_locales. */ +static bool is_supported(const char *value) +{ + const char **it; + + for (it = supported_locales; *it; ++it) { + if (strcmp(value, *it) == 0) { + return true; + } + } + return false; +} + +/* Match a detected system locale string (Windows GetUserDefaultLocaleName + * produces BCP-47 like "zh-CN"; POSIX $LANG is normalized by lib/i18n to + * the same shape, e.g. "zh_CN" -> "zh-CN") against supported_locales. + * A language-only match counts: "zh-TW" falls back to "zh-CN" since + * zh-TW is not shipped; both '-' and '_' are accepted as separators. */ +static const char *match_supported_locale(const char *detected) +{ + const char **it; + + if (!detected || !*detected) { + return NULL; + } + for (it = supported_locales; *it; ++it) { + if (strcmp(detected, *it) == 0) { + return *it; + } + } + for (it = supported_locales; *it; ++it) { + size_t prefix_len = strcspn(*it, "-"); + char sep = detected[prefix_len]; + if (strncmp(detected, *it, prefix_len) == 0 && + (sep == 0 || sep == '-' || sep == '_')) { + return *it; + } + } + return NULL; +} + +/* Copy `value` into a stable static buffer so callers can hold the + * pointer past the next call. Caller is responsible for `free`-ing + * the lcui_settings-owned `value` buffer. */ +static const char *stash_locale(const char *value) +{ + static char buf[32]; + size_t n = strlen(value); + + if (n >= sizeof(buf)) { + n = sizeof(buf) - 1; + } + memcpy(buf, value, n); + buf[n] = 0; + return buf; +} + +const char *app_get_locale(void) +{ + char *saved = NULL; + const char *matched; + + if (!lcui_settings_is_loaded()) { + lcui_settings_load(); + } + if (lcui_settings_get_string(SETTINGS_SECTION, SETTINGS_KEY, &saved) && + saved) { + matched = match_supported_locale(saved); + free(saved); + if (matched) { + return stash_locale(matched); + } + } + + /* No usable persisted locale: ask the operating system. */ + wchar_t wbuf[32]; + size_t wlen = i18n_detect_language(wbuf, 32); + if (wlen > 0 && wlen < 32) { + char nbuf[32]; + size_t i; + for (i = 0; i < wlen; ++i) { + nbuf[i] = (char)wbuf[i]; + } + nbuf[i] = 0; + matched = match_supported_locale(nbuf); + if (matched) { + return matched; + } + } + + return DEFAULT_LOCALE; +} + +void app_set_locale(const char *locale) +{ + if (!locale || !is_supported(locale)) { + return; + } + if (!lcui_settings_is_loaded()) { + return; + } + lcui_settings_set_string(SETTINGS_SECTION, SETTINGS_KEY, locale); +} diff --git a/examples/doc-viewer/app/locale.h b/examples/doc-viewer/app/locale.h new file mode 100644 index 000000000..179dee984 --- /dev/null +++ b/examples/doc-viewer/app/locale.h @@ -0,0 +1,27 @@ +#ifndef APP_LOCALE_H +#define APP_LOCALE_H + +/* + * app/locale.h - Application-level locale resolution and persistence. + * + * Locale selection at startup follows this order: + * 1. Locale persisted via lcui_settings under [app] locale. + * 2. Locale detected from the operating system (Windows + * GetUserDefaultLocaleName, or $LANG on POSIX). Detection is + * driven by lib/i18n's i18n_detect_language. Detected values + * are matched against the locales shipped with the doc-viewer. + * 3. The default locale ("en"). + * + * The doc-viewer only ships a fixed set of locales; values outside + * that set are rejected at every step. Callers receive a pointer + * into a static buffer that is overwritten on the next call. + */ + +/* Returns the locale to use, picked from the shipped locale set. */ +const char *app_get_locale(void); + +/* Persists the given locale through lcui_settings. No-op if the + * settings doc has not been loaded. */ +void app_set_locale(const char *locale); + +#endif diff --git a/examples/doc-viewer/app/main.c b/examples/doc-viewer/app/main.c new file mode 100644 index 000000000..dc2386390 --- /dev/null +++ b/examples/doc-viewer/app/main.c @@ -0,0 +1,62 @@ +/** + * app/main.c - Documentation viewer entry point. + * + * lcui-cli regenerates app/main.h on every build with: + * - app_router_init() -- every route from sidebars.json + * - app_init() -- lcui_init, resource loaders, widget registrations, + * and the initial root_layout mount + * - app_run() -- the LCUI main loop + * + * This main.c only orchestrates the entry point and registers the doc + * viewer's semantic text aliases (h1-h6, p) before any page widget is + * created. LCUI ships only a "text" prototype; without these aliases, + *

/

/... widgets emitted from MDX would have no text renderer + * and their content would not paint. + * + * The aliases are registered AFTER app_init() (so lcui_init() has set up + * the prototype system) and BEFORE app_run() (so they exist before the + * router instantiates the first page widget). app_init() itself only + * mounts the root layout, which contains no h1/p widgets -- those + * appear only once a page is routed in. + */ + +#include "main.h" +#include "components/list.h" +#include "locale.h" +#include + +static void register_semantic_text_aliases(void) +{ + static const char *aliases[] = { + "h1", "h2", "h3", "h4", "h5", "h6", "p", NULL, + }; + const char **name; + + for (name = aliases; *name; ++name) { + ui_create_widget_prototype(*name, "text"); + } +} + +int main(int argc, char *argv[]) +{ + lcui_set_app_id("dev.lcui.doc-viewer"); + app_init(); + register_semantic_text_aliases(); + ui_register_list_widgets(); + + router_t *router = router_get_by_name("AppRouter"); + const char *locale = app_get_locale(); + char initial_path[128]; + router_location_t *location; + + snprintf(initial_path, sizeof(initial_path), "/%s/overview/quick-start", + locale ? locale : "en"); + location = router_location_create(NULL, initial_path); + router_push(router, location); + router_location_destroy(location); + + ui_widget_resize(ui_root(), 1280, 720); + lcui_bind_window_state(ui_root(), "main"); + + return app_run(); +} diff --git a/examples/doc-viewer/app/widget-fields/anchor.ts b/examples/doc-viewer/app/widget-fields/anchor.ts new file mode 100644 index 000000000..0e7682e80 --- /dev/null +++ b/examples/doc-viewer/app/widget-fields/anchor.ts @@ -0,0 +1,14 @@ +import { widgetFields, FieldData } from "./widget"; + +export const anchorFields: FieldData[] = [ + ...widgetFields, + { + name: "href", + type: "string", + default: "-", + description: { + en: "The URL the link points to.", + "zh-CN": "链接的目标 URL。", + }, + }, +]; diff --git a/examples/doc-viewer/app/widget-fields/button.ts b/examples/doc-viewer/app/widget-fields/button.ts new file mode 100644 index 000000000..7f38e7aaf --- /dev/null +++ b/examples/doc-viewer/app/widget-fields/button.ts @@ -0,0 +1,14 @@ +import { widgetFields, FieldData } from "./widget"; + +export const buttonFields: FieldData[] = [ + ...widgetFields, + { + name: "disabled", + type: "string", + default: "-", + description: { + en: "Disables the button when set to \"true\".", + "zh-CN": "值为 \"true\" 时禁用按钮。", + }, + }, +]; diff --git a/examples/doc-viewer/app/widget-fields/scrollarea-content.ts b/examples/doc-viewer/app/widget-fields/scrollarea-content.ts new file mode 100644 index 000000000..32aed3890 --- /dev/null +++ b/examples/doc-viewer/app/widget-fields/scrollarea-content.ts @@ -0,0 +1,3 @@ +import { widgetFields, FieldData } from "./widget"; + +export const scrollareaContentFields: FieldData[] = [...widgetFields]; diff --git a/examples/doc-viewer/app/widget-fields/scrollarea.ts b/examples/doc-viewer/app/widget-fields/scrollarea.ts new file mode 100644 index 000000000..d1068a53a --- /dev/null +++ b/examples/doc-viewer/app/widget-fields/scrollarea.ts @@ -0,0 +1,3 @@ +import { widgetFields, FieldData } from "./widget"; + +export const scrollareaFields: FieldData[] = [...widgetFields]; diff --git a/examples/doc-viewer/app/widget-fields/scrollbar.ts b/examples/doc-viewer/app/widget-fields/scrollbar.ts new file mode 100644 index 000000000..3de4c3327 --- /dev/null +++ b/examples/doc-viewer/app/widget-fields/scrollbar.ts @@ -0,0 +1,14 @@ +import { widgetFields, FieldData } from "./widget"; + +export const scrollbarFields: FieldData[] = [ + ...widgetFields, + { + name: "orientation", + type: '"vertical" | "horizontal"', + default: '"vertical"', + description: { + en: "The scroll direction of the scrollbar.", + "zh-CN": "滚动条的滚动方向。", + }, + }, +]; diff --git a/examples/doc-viewer/app/widget-fields/text-input.ts b/examples/doc-viewer/app/widget-fields/text-input.ts new file mode 100644 index 000000000..31fc7dad9 --- /dev/null +++ b/examples/doc-viewer/app/widget-fields/text-input.ts @@ -0,0 +1,14 @@ +import { widgetFields, FieldData } from "./widget"; + +export const textInputFields: FieldData[] = [ + ...widgetFields, + { + name: "placeholder", + type: "string", + default: "-", + description: { + en: "Placeholder text shown when the input is empty.", + "zh-CN": "输入为空时显示的占位文本。", + }, + }, +]; diff --git a/examples/doc-viewer/app/widget-fields/text.ts b/examples/doc-viewer/app/widget-fields/text.ts new file mode 100644 index 000000000..d67964c25 --- /dev/null +++ b/examples/doc-viewer/app/widget-fields/text.ts @@ -0,0 +1,3 @@ +import { widgetFields, FieldData } from "./widget"; + +export const textFields: FieldData[] = [...widgetFields]; diff --git a/examples/doc-viewer/app/widget-fields/widget.ts b/examples/doc-viewer/app/widget-fields/widget.ts new file mode 100644 index 000000000..18133a1ba --- /dev/null +++ b/examples/doc-viewer/app/widget-fields/widget.ts @@ -0,0 +1,27 @@ +export interface FieldData { + name: string; + type: string; + default: string; + description: { en: string; "zh-CN": string }; +} + +export const widgetFields: FieldData[] = [ + { + name: "className", + type: "string", + default: "-", + description: { + en: "CSS class name applied to the element.", + "zh-CN": "应用于元素的 CSS 类名。", + }, + }, + { + name: "children", + type: "any", + default: "-", + description: { + en: "Child elements.", + "zh-CN": "子元素。", + }, + }, +]; diff --git a/examples/doc-viewer/app/zh-CN/devtools/css-modules/page.c b/examples/doc-viewer/app/zh-CN/devtools/css-modules/page.c new file mode 100644 index 000000000..a439096ec --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/devtools/css-modules/page.c @@ -0,0 +1,57 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + zh_cn_devtools_css_modules_page_react_t base; + // Add additional states to your component here + // ... +} zh_cn_devtools_css_modules_page_t; + +static void zh_cn_devtools_css_modules_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, zh_cn_devtools_css_modules_page_proto, + sizeof(zh_cn_devtools_css_modules_page_t)); + + zh_cn_devtools_css_modules_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + zh_cn_devtools_css_modules_page_update(w); +} + +static zh_cn_devtools_css_modules_page_t *zh_cn_devtools_css_modules_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, zh_cn_devtools_css_modules_page_proto); +} + +static void zh_cn_devtools_css_modules_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + zh_cn_devtools_css_modules_page_react_destroy(w); +} + +void zh_cn_devtools_css_modules_page_update(ui_widget_t *w) +{ + zh_cn_devtools_css_modules_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_zh_cn_devtools_css_modules_page(void) +{ + return ui_create_widget_with_prototype( + zh_cn_devtools_css_modules_page_proto); +} + +void ui_register_zh_cn_devtools_css_modules_page(void) +{ + zh_cn_devtools_css_modules_page_init_prototype(); + zh_cn_devtools_css_modules_page_proto->init = + zh_cn_devtools_css_modules_page_init; + zh_cn_devtools_css_modules_page_proto->destroy = + zh_cn_devtools_css_modules_page_destroy; +} diff --git a/examples/doc-viewer/app/zh-CN/devtools/css-modules/page.h b/examples/doc-viewer/app/zh-CN/devtools/css-modules/page.h new file mode 100644 index 000000000..6329d19a6 --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/devtools/css-modules/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_zh_cn_devtools_css_modules_page(void); + +ui_widget_t *ui_create_zh_cn_devtools_css_modules_page(void); + +void zh_cn_devtools_css_modules_page_update(ui_widget_t *w); + +void ui_load_zh_cn_devtools_css_modules_page_resources(void); diff --git a/examples/doc-viewer/app/zh-CN/devtools/css-modules/page.tsx b/examples/doc-viewer/app/zh-CN/devtools/css-modules/page.tsx new file mode 100644 index 000000000..8fefe658d --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/devtools/css-modules/page.tsx @@ -0,0 +1,49 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function CssModulesDocPage() { + return ( + +

CSS Modules

+

{`CSS Modules 为 TSX 组件创建局部作用域的 CSS 类,避免命名冲突并提高可维护性。`}

+ +

用法

+

{`创建 [bgcolor=#eee] .module.css [/bgcolor] 后缀的文件:`}

+ + + MyComponent.module.css + + + + {`[color=#953800].card[/color] {`} + {`  border: [color=#0550ae]1px[/color] solid [color=#0550ae]#eee[/color];`} + {`  border-radius: [color=#0550ae]4px[/color];`} + {`}`} + + +

{`在 [bgcolor=#eee] .tsx [/bgcolor] 文件中导入:`}

+ + + MyComponent.tsx + + + + {`[color=#cf222e]import[/color] styles [color=#cf222e]from[/color] [color=#0a3069]"./MyComponent.module.css"[/color];`} + + +

{`在 JSX 中用 [bgcolor=#eee] styles [/bgcolor] 对象替代字符串类名:`}

+ + + DIFF + + + + {`- `} + {`+ `} + + +

{`[bgcolor=#eee] @lcui/cli [/bgcolor] 编译时会将 [bgcolor=#eee] .module.css [/bgcolor] 转换为 C 标识符绑定,类名会自动生成唯一的 C 常量名,避免全局冲突。`}

+
+
+ ); +} diff --git a/examples/doc-viewer/app/zh-CN/devtools/icon-library/page.c b/examples/doc-viewer/app/zh-CN/devtools/icon-library/page.c new file mode 100644 index 000000000..bd235f9f8 --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/devtools/icon-library/page.c @@ -0,0 +1,57 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + zh_cn_devtools_icon_library_page_react_t base; + // Add additional states to your component here + // ... +} zh_cn_devtools_icon_library_page_t; + +static void zh_cn_devtools_icon_library_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, zh_cn_devtools_icon_library_page_proto, + sizeof(zh_cn_devtools_icon_library_page_t)); + + zh_cn_devtools_icon_library_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + zh_cn_devtools_icon_library_page_update(w); +} + +static zh_cn_devtools_icon_library_page_t *zh_cn_devtools_icon_library_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, zh_cn_devtools_icon_library_page_proto); +} + +static void zh_cn_devtools_icon_library_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + zh_cn_devtools_icon_library_page_react_destroy(w); +} + +void zh_cn_devtools_icon_library_page_update(ui_widget_t *w) +{ + zh_cn_devtools_icon_library_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_zh_cn_devtools_icon_library_page(void) +{ + return ui_create_widget_with_prototype( + zh_cn_devtools_icon_library_page_proto); +} + +void ui_register_zh_cn_devtools_icon_library_page(void) +{ + zh_cn_devtools_icon_library_page_init_prototype(); + zh_cn_devtools_icon_library_page_proto->init = + zh_cn_devtools_icon_library_page_init; + zh_cn_devtools_icon_library_page_proto->destroy = + zh_cn_devtools_icon_library_page_destroy; +} diff --git a/examples/doc-viewer/app/zh-CN/devtools/icon-library/page.h b/examples/doc-viewer/app/zh-CN/devtools/icon-library/page.h new file mode 100644 index 000000000..90d15ba98 --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/devtools/icon-library/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_zh_cn_devtools_icon_library_page(void); + +ui_widget_t *ui_create_zh_cn_devtools_icon_library_page(void); + +void zh_cn_devtools_icon_library_page_update(ui_widget_t *w); + +void ui_load_zh_cn_devtools_icon_library_page_resources(void); diff --git a/examples/doc-viewer/app/zh-CN/devtools/icon-library/page.tsx b/examples/doc-viewer/app/zh-CN/devtools/icon-library/page.tsx new file mode 100644 index 000000000..93406113d --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/devtools/icon-library/page.tsx @@ -0,0 +1,52 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function IconLibraryDocPage() { + return ( + +

图标库

+

{`[bgcolor=#eee] @lcui/fluent-icons [/bgcolor] 是专为 LCUI 适配的图标库,图标都来自 Microsoft 的 fluentui-system-icons 项目。`}

+ +

安装

+ + + Shell + + + + {`npm install @lcui/fluent-icons`} + + +
+ +

选取图标

+

{`在 flicon.io 网站中搜索和选取图标。以放大图标为例,英文名通常是 Zoom In。`}

+

{`fluentui-system-icons 的图标有 16、20、24 等几种尺寸可选,命名方式是"图标名+尺寸+风格"。[bgcolor=#eee] @lcui/fluent-icons [/bgcolor] 的命名方式是"图标名+风格",当风格为 Regular 时可以省略它。`}

+
+ +

用法

+ + + TypeScript + + + + {`[color=#cf222e]import[/color] { [color=#8250df]ZoomIn[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/fluent-icons"[/color];`} + {` `} + {`[color=#116329]<[color=#0550ae]ZoomIn[/color] />[/color]`} + + +

{`默认尺寸是 20。如果图标尺寸固定且希望更好的渲染效果,可以指定 size 参数:`}

+ + + TypeScript + + + + {`<[color=#8250df]ZoomIn[/color] size={[color=#0550ae]32[/color]} />`} + + +
+
+ ); +} diff --git a/examples/doc-viewer/app/zh-CN/devtools/sass/page.c b/examples/doc-viewer/app/zh-CN/devtools/sass/page.c new file mode 100644 index 000000000..4de03df73 --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/devtools/sass/page.c @@ -0,0 +1,54 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + zh_cn_devtools_sass_page_react_t base; + // Add additional states to your component here + // ... +} zh_cn_devtools_sass_page_t; + +static void zh_cn_devtools_sass_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, zh_cn_devtools_sass_page_proto, + sizeof(zh_cn_devtools_sass_page_t)); + + zh_cn_devtools_sass_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + zh_cn_devtools_sass_page_update(w); +} + +static zh_cn_devtools_sass_page_t *zh_cn_devtools_sass_page_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, zh_cn_devtools_sass_page_proto); +} + +static void zh_cn_devtools_sass_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + zh_cn_devtools_sass_page_react_destroy(w); +} + +void zh_cn_devtools_sass_page_update(ui_widget_t *w) +{ + zh_cn_devtools_sass_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_zh_cn_devtools_sass_page(void) +{ + return ui_create_widget_with_prototype(zh_cn_devtools_sass_page_proto); +} + +void ui_register_zh_cn_devtools_sass_page(void) +{ + zh_cn_devtools_sass_page_init_prototype(); + zh_cn_devtools_sass_page_proto->init = zh_cn_devtools_sass_page_init; + zh_cn_devtools_sass_page_proto->destroy = + zh_cn_devtools_sass_page_destroy; +} diff --git a/examples/doc-viewer/app/zh-CN/devtools/sass/page.h b/examples/doc-viewer/app/zh-CN/devtools/sass/page.h new file mode 100644 index 000000000..81461f7c6 --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/devtools/sass/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_zh_cn_devtools_sass_page(void); + +ui_widget_t *ui_create_zh_cn_devtools_sass_page(void); + +void zh_cn_devtools_sass_page_update(ui_widget_t *w); + +void ui_load_zh_cn_devtools_sass_page_resources(void); diff --git a/examples/doc-viewer/app/zh-CN/devtools/sass/page.tsx b/examples/doc-viewer/app/zh-CN/devtools/sass/page.tsx new file mode 100644 index 000000000..9c1278aa8 --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/devtools/sass/page.tsx @@ -0,0 +1,26 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function SassDocPage() { + return ( + +

Sass

+

{`Sass 是一个流行的 CSS 预处理器,通过变量、嵌套规则和混合元素等功能扩展 CSS。`}

+ +

用法

+

{`[bgcolor=#eee] @lcui/cli [/bgcolor] 已内置 Sass 预处理器,在编译 [bgcolor=#eee] .sass [/bgcolor] 和 [bgcolor=#eee] .scss [/bgcolor] 后缀的文件时会自动调用,无需额外安装或配置。`}

+

{`在 TSX 中直接导入 Sass 文件:`}

+ + + MyComponent.tsx + + + + {`[color=#cf222e]import[/color] [color=#0a3069]"./MyComponent.scss"[/color];`} + + +

{`CLI 会将 Sass 文件编译为 CSS,再转换为 C 代码在运行时加载。`}

+
+
+ ); +} diff --git a/examples/doc-viewer/app/zh-CN/devtools/tailwind-css/page.c b/examples/doc-viewer/app/zh-CN/devtools/tailwind-css/page.c new file mode 100644 index 000000000..88cf899f0 --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/devtools/tailwind-css/page.c @@ -0,0 +1,57 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + zh_cn_devtools_tailwind_css_page_react_t base; + // Add additional states to your component here + // ... +} zh_cn_devtools_tailwind_css_page_t; + +static void zh_cn_devtools_tailwind_css_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, zh_cn_devtools_tailwind_css_page_proto, + sizeof(zh_cn_devtools_tailwind_css_page_t)); + + zh_cn_devtools_tailwind_css_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + zh_cn_devtools_tailwind_css_page_update(w); +} + +static zh_cn_devtools_tailwind_css_page_t *zh_cn_devtools_tailwind_css_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, zh_cn_devtools_tailwind_css_page_proto); +} + +static void zh_cn_devtools_tailwind_css_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + zh_cn_devtools_tailwind_css_page_react_destroy(w); +} + +void zh_cn_devtools_tailwind_css_page_update(ui_widget_t *w) +{ + zh_cn_devtools_tailwind_css_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_zh_cn_devtools_tailwind_css_page(void) +{ + return ui_create_widget_with_prototype( + zh_cn_devtools_tailwind_css_page_proto); +} + +void ui_register_zh_cn_devtools_tailwind_css_page(void) +{ + zh_cn_devtools_tailwind_css_page_init_prototype(); + zh_cn_devtools_tailwind_css_page_proto->init = + zh_cn_devtools_tailwind_css_page_init; + zh_cn_devtools_tailwind_css_page_proto->destroy = + zh_cn_devtools_tailwind_css_page_destroy; +} diff --git a/examples/doc-viewer/app/zh-CN/devtools/tailwind-css/page.h b/examples/doc-viewer/app/zh-CN/devtools/tailwind-css/page.h new file mode 100644 index 000000000..ef2b1e6df --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/devtools/tailwind-css/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_zh_cn_devtools_tailwind_css_page(void); + +ui_widget_t *ui_create_zh_cn_devtools_tailwind_css_page(void); + +void zh_cn_devtools_tailwind_css_page_update(ui_widget_t *w); + +void ui_load_zh_cn_devtools_tailwind_css_page_resources(void); diff --git a/examples/doc-viewer/app/zh-CN/devtools/tailwind-css/page.tsx b/examples/doc-viewer/app/zh-CN/devtools/tailwind-css/page.tsx new file mode 100644 index 000000000..5715d68f7 --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/devtools/tailwind-css/page.tsx @@ -0,0 +1,51 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function TailwindCssDocPage() { + return ( + +

Tailwind CSS

+

{`Tailwind CSS 是一个功能类优先(Utility-First)的 CSS 框架,通过预定义的 CSS 类帮助开发者快速设置样式。相比传统 CSS 编写方式,无需新建 CSS 文件、编写规则和思考类名。`}

+ +

安装

+ + + Shell + + + + {`npm install -D tailwindcss postcss @thedutchcoder/postcss-rem-to-px`} + + +
+ +

配置

+

{`从 lcui-quick-start 模板项目复制以下文件到项目根目录:`}

+
    +
  • {`[bgcolor=#eee] postcss.config.js [/bgcolor]`}
  • +
  • {`[bgcolor=#eee] tailwind.config.js [/bgcolor]`}
  • +
  • {`[bgcolor=#eee] app/global.css [/bgcolor]`}
  • +
+

{`[bgcolor=#eee] global.css [/bgcolor] 中包含 Tailwind 的指令:`}

+ + + app/global.css + + + + {`[color=#cf222e]@tailwind[/color] base;`} + {`[color=#cf222e]@tailwind[/color] components;`} + {`[color=#cf222e]@tailwind[/color] utilities;`} + + +

{`[bgcolor=#eee] @lcui/cli [/bgcolor] 编译时会通过 PostCSS 链(postcss + tailwindcss + postcss-rem-to-px)处理 Tailwind 指令,生成最终的 CSS 输出。`}

+ + 技巧 + +

{`如果你不想将 global.css 放到 app 目录内,请更改 [bgcolor=#eee] tailwind.config.js [/bgcolor] 中 [bgcolor=#eee] content [/bgcolor] 配置项的路径匹配规则。`}

+
+
+
+
+ ); +} diff --git a/examples/doc-viewer/app/zh-CN/devtools/tsx-and-dev-tools/page.c b/examples/doc-viewer/app/zh-CN/devtools/tsx-and-dev-tools/page.c new file mode 100644 index 000000000..4f6bc807c --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/devtools/tsx-and-dev-tools/page.c @@ -0,0 +1,58 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + zh_cn_devtools_tsx_and_dev_tools_page_react_t base; + // Add additional states to your component here + // ... +} zh_cn_devtools_tsx_and_dev_tools_page_t; + +static void zh_cn_devtools_tsx_and_dev_tools_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, zh_cn_devtools_tsx_and_dev_tools_page_proto, + sizeof(zh_cn_devtools_tsx_and_dev_tools_page_t)); + + zh_cn_devtools_tsx_and_dev_tools_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + zh_cn_devtools_tsx_and_dev_tools_page_update(w); +} + +static zh_cn_devtools_tsx_and_dev_tools_page_t * +zh_cn_devtools_tsx_and_dev_tools_page_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, + zh_cn_devtools_tsx_and_dev_tools_page_proto); +} + +static void zh_cn_devtools_tsx_and_dev_tools_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + zh_cn_devtools_tsx_and_dev_tools_page_react_destroy(w); +} + +void zh_cn_devtools_tsx_and_dev_tools_page_update(ui_widget_t *w) +{ + zh_cn_devtools_tsx_and_dev_tools_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_zh_cn_devtools_tsx_and_dev_tools_page(void) +{ + return ui_create_widget_with_prototype( + zh_cn_devtools_tsx_and_dev_tools_page_proto); +} + +void ui_register_zh_cn_devtools_tsx_and_dev_tools_page(void) +{ + zh_cn_devtools_tsx_and_dev_tools_page_init_prototype(); + zh_cn_devtools_tsx_and_dev_tools_page_proto->init = + zh_cn_devtools_tsx_and_dev_tools_page_init; + zh_cn_devtools_tsx_and_dev_tools_page_proto->destroy = + zh_cn_devtools_tsx_and_dev_tools_page_destroy; +} diff --git a/examples/doc-viewer/app/zh-CN/devtools/tsx-and-dev-tools/page.h b/examples/doc-viewer/app/zh-CN/devtools/tsx-and-dev-tools/page.h new file mode 100644 index 000000000..48c5ee665 --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/devtools/tsx-and-dev-tools/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_zh_cn_devtools_tsx_and_dev_tools_page(void); + +ui_widget_t *ui_create_zh_cn_devtools_tsx_and_dev_tools_page(void); + +void zh_cn_devtools_tsx_and_dev_tools_page_update(ui_widget_t *w); + +void ui_load_zh_cn_devtools_tsx_and_dev_tools_page_resources(void); diff --git a/examples/doc-viewer/app/zh-CN/devtools/tsx-and-dev-tools/page.tsx b/examples/doc-viewer/app/zh-CN/devtools/tsx-and-dev-tools/page.tsx new file mode 100644 index 000000000..91e36fb5e --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/devtools/tsx-and-dev-tools/page.tsx @@ -0,0 +1,260 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function TsxAndDevToolsDocPage() { + return ( + +

TSX 与开发工具

+

{`配合 [bgcolor=#eee] @lcui/cli [/bgcolor],你可以用 TypeScript 搭配 JSX 语法编写声明式界面。CLI 会编译 TSX 为 C 代码,你无需手动编写部件树构建逻辑。`}

+

{`这样做的好处是:声明式编程方式使得状态绑定、事件绑定和资源引入更加简洁直观,在同一份文件中处理逻辑和视图可以减少上下文切换。`}

+

{`不过,[bgcolor=#eee] @lcui/react [/bgcolor] 目前功能有限,你只能声明组件的状态、数据绑定和事件绑定。对于条件渲染、列表渲染等复杂操作,你仍需要编写 C 代码。`}

+ +

安装开发工具

+

{`[bgcolor=#eee] @lcui/cli [/bgcolor] 是一个命令行工具,集成了 TypeScript 编译器、Sass 预处理器、资源文件加载器等功能。它依赖 Node.js 运行时环境:`}

+ + + Shell + + + + {`npm install -g @lcui/cli`} + + +
+ +

预处理器工作原理

+

{`LCUI 采用预处理器方案:TSX 文件只在预处理阶段执行,不会成为运行时代码。你可以理解为 TSX 文件是配置文件,其中的 TypeScript 代码都是预处理指令。`}

+

{`预处理器按文件后缀名匹配合适的加载器,解析 TSX 代码、收集依赖、执行组件函数,然后根据返回的 JSX 元素和 Hook 调用结果生成 C 源文件。`}

+
+ +

用法概览

+ + + src/App.tsx + + + + {`[color=#cf222e]import[/color] { useState, [color=#8250df]TextInput[/color], [color=#8250df]Button[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]const[/color] inputRef = { [color=#0550ae]current[/color]: { [color=#0550ae]value[/color]: [color=#0a3069]""[/color] } };`} + {`  [color=#cf222e]const[/color] \\[name, setName] = [color=#8250df]useState[/color]([color=#0a3069]"LCUI"[/color]);`} + {` `} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]Widget[/color] [color=#0550ae]className[/color]=[color=#0a3069]"container"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]Widget[/color] [color=#0550ae]className[/color]=[color=#0a3069]"flex flex-col items-center pt-6"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]Text[/color] [color=#0550ae]className[/color]=[color=#0a3069]"my-4 text-2xl text-center"[/color]>[/color]Hello, {name}![color=#116329][/color]`} + {`        [color=#116329]<[color=#0550ae]TextInput[/color][/color]`} + {`[color=#116329] \$[color=#0550ae]ref[/color]=[color=#0a3069]{inputRef}[/color][/color]`} + {`[color=#116329] [color=#0550ae]className[/color]=[color=#0a3069]"mt-2"[/color][/color]`} + {`[color=#116329] [color=#0550ae]placeholder[/color]=[color=#0a3069]"Please input..."[/color][/color]`} + {`[color=#116329] />[/color]`} + {`        [color=#116329]<[color=#0550ae]Button[/color][/color]`} + {`[color=#116329] [color=#0550ae]className[/color]=[color=#0a3069]"mt-2"[/color][/color]`} + {`[color=#116329] [color=#0550ae]onClick[/color]=[color=#0a3069]{()[/color] =>[/color] setName(inputRef.current.value)}`} + {`        >`} + {`          Change`} + {`        [color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + + +
+ +

React 库

+

{`[bgcolor=#eee] @lcui/react [/bgcolor] 是针对 LCUI 特性和预处理器工作模式的用户界面库,提供预置组件、工具函数和 Hook 函数。`}

+

{`安装方法:`}

+ + + Shell + + + + {`npm install @lcui/react`} + + +

组件函数

+

{`预处理器会执行组件函数,收集 [bgcolor=#eee] useState [/bgcolor]、[bgcolor=#eee] useRef [/bgcolor] 等产出的数据和返回的 JSX 元素,然后转换成 C 代码。`}

+ + 注意 + +
    +
  • {`组件函数返回值必须是一个 JSX 元素,不能是 [bgcolor=#eee] [/bgcolor]、null、undefined、字符串、数字等对象。`}
  • +
  • {`暂不支持声明和传递组件 props 参数。`}
  • +
+
+
+

状态管理

+

{`[bgcolor=#eee] useState [/bgcolor] 为组件声明状态变量:`}

+ + + TypeScript + + + + {`[color=#cf222e]import[/color] { useState } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]function[/color] [color=#8250df]MyComponent[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]const[/color] \\[age, setAge] = [color=#8250df]useState[/color]([color=#0550ae]23[/color]);`} + {`  [color=#cf222e]const[/color] \\[name, setName] = [color=#8250df]useState[/color]([color=#0a3069]"Taylor"[/color]);`} + {`  [color=#6e7781]// ...[/color]`} + {`}`} + + +

{`[bgcolor=#eee] useState [/bgcolor] 返回一个数组:`}

+
    +
  • {`状态变量,初始值为你传给 [bgcolor=#eee] useState [/bgcolor] 的值。`}
  • +
  • {`set 函数,允许你在响应交互时更改状态变量。`}
  • +
+

{`[bgcolor=#eee] useState [/bgcolor] 会为组件的状态结构体添加成员,并在初始化函数中添加初始化代码:`}

+ + + C + + + + {`[color=#6e7781]/* 组件状态结构体 */[/color]`} + {`[color=#cf222e]struct[/color] [color=#8250df]MyComponent_state[/color] {`} + {`  [color=#953800]int[/color] age;`} + {`  [color=#953800]char[/color] *name;`} + {`};`} + {` `} + {`[color=#6e7781]/* 组件初始化函数中的代码 */[/color]`} + {`_that->state.age = [color=#0550ae]23[/color];`} + {`_that->state.name = strdup2([color=#0a3069]"Taylor"[/color]);`} + + +

{`状态的 set 函数会在当前作用域中插入 C 代码,例如 [bgcolor=#eee] setAge(30) [/bgcolor] 会生成 [bgcolor=#eee] _that->state.age = 30; [/bgcolor]。`}

+ + 注意 + +

{`[bgcolor=#eee] useState [/bgcolor] 的参数只能是 string、number 类型。`}

+
+
+

引用

+

{`用 [bgcolor=#eee] \$ref [/bgcolor] 属性引用部件对象:`}

+ + + TypeScript + + + + {`<[color=#8250df]TextInput[/color] \$ref=[color=#0a3069]"input"[/color] />`} + + +

{`之后在 C 代码中操作它:`}

+ + + C + + + + {`ui_textinput_set_content(_that->refs.input, [color=#0a3069]"hello"[/color]);`} + + +

{`[bgcolor=#eee] \$ref [/bgcolor] 的值也可以是 [bgcolor=#eee] useRef [/bgcolor] 返回的引用对象:`}

+ + + TypeScript + + + + {`[color=#cf222e]import[/color] { useRef } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]function[/color] [color=#8250df]MyComponent[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]const[/color] inputRef = [color=#8250df]useRef[/color]();`} + {` `} + {`  [color=#cf222e]return[/color] [color=#116329]<[color=#0550ae]TextInput[/color] \$[color=#0550ae]ref[/color]=[color=#0a3069]{inputRef}[/color] />[/color];`} + {`}`} + + +

{`[bgcolor=#eee] useRef [/bgcolor] 目前只实现了 TextInput 的 value 属性读写绑定:`}

+ + + TypeScript + + + + {`inputRef.[color=#0550ae]current[/color].[color=#0550ae]value[/color] = [color=#0a3069]"World"[/color];`} + {` `} + {`[color=#116329]<[color=#0550ae]Button[/color] [color=#0550ae]onClick[/color]=[color=#0a3069]{()[/color] =>[/color] setName(inputRef.current.value)}>Click[color=#116329][/color]`} + + + + 注意 + +

{`[bgcolor=#eee] @lcui/react [/bgcolor] 的 [bgcolor=#eee] useRef [/bgcolor] 和 React 的 [bgcolor=#eee] useRef [/bgcolor] 不同,仅用于引用部件对象。`}

+
+
+

响应事件

+

{`通过 [bgcolor=#eee] on + 事件名 [/bgcolor] 属性声明事件处理函数:`}

+ + + TypeScript + + + + {`<[color=#8250df]Button[/color] onClick=[color=#0a3069]"handleClick"[/color]>点我`} + + +

{`预处理器会生成 C 代码绑定事件:`}

+ + + C + + + + {`ui_widget_on(_that->refs.ref_0, [color=#0a3069]"click"[/color], handleClick, w);`} + + +

{`也可以将 JavaScript 函数与事件绑定:`}

+ + + TypeScript + + + + {`[color=#cf222e]import[/color] { useState, [color=#8250df]Text[/color], [color=#8250df]Button[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]Counter[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]const[/color] \\[text, setText] = [color=#8250df]useState[/color]([color=#0a3069]"点我"[/color]);`} + {` `} + {`  [color=#cf222e]function[/color] [color=#8250df]handleClick[/color]([color=#0550ae][/color]) {`} + {`    [color=#8250df]setText[/color]([color=#0a3069]"你已点击"[/color]);`} + {`  }`} + {` `} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]Button[/color] [color=#0550ae]onClick[/color]=[color=#0a3069]{handleClick}[/color]>[/color]`} + {`      {text}`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + + +

{`预处理器会根据事件处理函数内部的代码执行结果,为其生成 C 语言版本的事件处理函数。`}

+ + 注意 + +

{`暂时只支持在事件处理函数中执行状态变量的 set 函数,不支持访问事件对象,不支持执行其它语句。`}

+
+
+

条件渲染

+ + 注意 + +

{`暂不支持。 我们正考虑使用 [bgcolor=#eee] [/bgcolor] 组件实现条件渲染,参考 Solid.js 的 [bgcolor=#eee] [/bgcolor]。`}

+
+
+

渲染列表

+ + 注意 + +

{`暂不支持。 我们正考虑使用 [bgcolor=#eee] [/bgcolor] 组件实现数组遍历,参考 Solid.js 的 [bgcolor=#eee] [/bgcolor]。`}

+
+
+
+
+ ); +} diff --git a/examples/doc-viewer/app/zh-CN/handbook/composition/page.c b/examples/doc-viewer/app/zh-CN/handbook/composition/page.c new file mode 100644 index 000000000..e01e528c5 --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/handbook/composition/page.c @@ -0,0 +1,56 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + zh_cn_handbook_composition_page_react_t base; + // Add additional states to your component here + // ... +} zh_cn_handbook_composition_page_t; + +static void zh_cn_handbook_composition_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, zh_cn_handbook_composition_page_proto, + sizeof(zh_cn_handbook_composition_page_t)); + zh_cn_handbook_composition_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + zh_cn_handbook_composition_page_update(w); +} + +static zh_cn_handbook_composition_page_t *zh_cn_handbook_composition_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, zh_cn_handbook_composition_page_proto); +} + +static void zh_cn_handbook_composition_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + zh_cn_handbook_composition_page_react_destroy(w); +} + +void zh_cn_handbook_composition_page_update(ui_widget_t *w) +{ + zh_cn_handbook_composition_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_zh_cn_handbook_composition_page(void) +{ + return ui_create_widget_with_prototype( + zh_cn_handbook_composition_page_proto); +} + +void ui_register_zh_cn_handbook_composition_page(void) +{ + zh_cn_handbook_composition_page_init_prototype(); + zh_cn_handbook_composition_page_proto->init = + zh_cn_handbook_composition_page_init; + zh_cn_handbook_composition_page_proto->destroy = + zh_cn_handbook_composition_page_destroy; +} diff --git a/examples/doc-viewer/app/zh-CN/handbook/composition/page.h b/examples/doc-viewer/app/zh-CN/handbook/composition/page.h new file mode 100644 index 000000000..17a2bd801 --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/handbook/composition/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_zh_cn_handbook_composition_page(void); + +ui_widget_t *ui_create_zh_cn_handbook_composition_page(void); + +void zh_cn_handbook_composition_page_update(ui_widget_t *w); + +void ui_load_zh_cn_handbook_composition_page_resources(void); diff --git a/examples/doc-viewer/app/zh-CN/handbook/composition/page.tsx b/examples/doc-viewer/app/zh-CN/handbook/composition/page.tsx new file mode 100644 index 000000000..ab81e8cfd --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/handbook/composition/page.tsx @@ -0,0 +1,213 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; + +export default function CompositionDocPage() { + return ( + +

组合

+

{`构建复杂界面意味着把多个部件组合成层级结构。LCUI 提供三种常见方式来完成这件事:在 C 中构建部件层级、用 XML 组合界面、用 TSX 组合组件。`}

+ +

在 C 中构建部件层级

+

{`使用 [bgcolor=#eee] ui_widget_append() [/bgcolor] 嵌套部件:`}

+ + + main.c + + + + {`[color=#953800]ui_widget_t[/color] *root = ui_root();`} + {`[color=#953800]ui_widget_t[/color] *container = ui_create_widget([color=#0550ae]NULL[/color]);`} + {`[color=#953800]ui_widget_t[/color] *title = ui_create_widget([color=#0a3069]"text"[/color]);`} + {`[color=#953800]ui_widget_t[/color] *btn = ui_create_widget([color=#0a3069]"button"[/color]);`} + {` `} + {`ui_text_set_content(title, [color=#0a3069]"My App"[/color]);`} + {`ui_button_set_text(btn, [color=#0a3069]"Click me"[/color]);`} + {` `} + {`ui_widget_append(container, title);`} + {`ui_widget_append(container, btn);`} + {`ui_widget_append(root, container);`} + + +

{`容器部件([bgcolor=#eee] container [/bgcolor])是普通的未命名部件([bgcolor=#eee] ui_create_widget(NULL) [/bgcolor] 创建),它的作用就是把多个子部件组合成一组。`}

+ + 技巧 + +

{`LCUI 没有原生的 [bgcolor=#eee] h1 [/bgcolor] / [bgcolor=#eee] p [/bgcolor] 等语义标签。如果你在用 [bgcolor=#eee] @lcui/cli [/bgcolor] 的编译流程,可以用注册别名的方式添加文本原型的语义组件(见下方 语义标签)。`}

+
+
+
+ +

使用 XML 组合界面

+

{`用 XML 直接描述整个部件树:`}

+ + + app/ui.xml + + + + {`[color=#6e7781][/color]`} + {`[color=#116329]<[color=#0550ae]lcui-app[/color]>[/color]`} + {`  [color=#116329]<[color=#0550ae]ui[/color]>[/color]`} + {`    [color=#116329]<[color=#0550ae]widget[/color] [color=#0550ae]style[/color]=[color=#0a3069]"display: flex; flex-direction: column; padding: 16px;"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]text[/color] [color=#0550ae]style[/color]=[color=#0a3069]"font-size: 24px; font-weight: bold;"[/color]>[/color]My App[color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]button[/color] [color=#0550ae]id[/color]=[color=#0a3069]"action-btn"[/color]>[/color]Click me[color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  [color=#116329][/color]`} + {`[color=#116329][/color]`} + + +

{`在 C 代码里加载并绑定事件:`}

+ + + src/main.c + + + + {`[color=#953800]static[/color] [color=#953800]void[/color] [color=#8250df]on_action_click[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w, [color=#953800]ui_event_t[/color] *e, [color=#953800]void[/color] *arg)[/color]`} + {`{`} + {`        ui_text_set_content(([color=#953800]ui_widget_t[/color] *)arg, [color=#0a3069]"按钮被点击!"[/color]);`} + {`}`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        [color=#953800]ui_widget_t[/color] *root, *btn, *title;`} + {` `} + {`        lcui_init();`} + {` `} + {`        root = ui_load_xml_file([color=#0a3069]"ui.xml"[/color]);`} + {`        ui_widget_append(ui_root(), root);`} + {`        ui_widget_unwrap(root);`} + {` `} + {`        btn = ui_get_widget([color=#0a3069]"action-btn"[/color]);`} + {`        title = ui_get_widget([color=#0a3069]"title"[/color]);`} + {`        [color=#cf222e]if[/color] (btn) {`} + {`                ui_widget_on(btn, [color=#0a3069]"click"[/color], on_action_click, title);`} + {`        }`} + {` `} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + +
+ +

使用 TSX 组合组件

+

{`配合 [bgcolor=#eee] @lcui/cli [/bgcolor],你可以用 TSX 编写可复用组件:`}

+ + + components/Card.tsx + + + + {`[color=#cf222e]import[/color] { [color=#8250df]Button[/color], [color=#8250df]Text[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]function[/color] [color=#8250df]Card[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]style[/color]=[color=#0a3069]{{[/color] [color=#0550ae]border:[/color] "[color=#0550ae]1px[/color] [color=#0550ae]solid[/color] #[color=#0550ae]ccc[/color]", [color=#0550ae]padding:[/color] [color=#0550ae]16[/color], [color=#0550ae]borderRadius:[/color] [color=#0550ae]4[/color] }}>[/color]`} + {`      [color=#116329]<[color=#0550ae]Text[/color] [color=#0550ae]style[/color]=[color=#0a3069]{{[/color] [color=#0550ae]fontWeight:[/color] "[color=#0550ae]bold[/color]", [color=#0550ae]fontSize:[/color] [color=#0550ae]18[/color] }}>[/color]标题[color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]Button[/color]>[/color]开始使用[color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + + +

{`在应用中使用:`}

+ + + src/App.tsx + + + + {`[color=#cf222e]import[/color] { [color=#8250df]Card[/color] } [color=#cf222e]from[/color] [color=#0a3069]"./components/Card"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]return[/color] [color=#116329]<[color=#0550ae]Card[/color] />[/color];`} + {`}`} + + +
+ +

事件处理

+

{`部件之间通常通过事件通信。使用 [bgcolor=#eee] ui_widget_on() [/bgcolor] 绑定处理函数:`}

+ + + main.c + + + + {`[color=#953800]static[/color] [color=#953800]void[/color] [color=#8250df]on_button_click[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *w, [color=#953800]ui_event_t[/color] *e, [color=#953800]void[/color] *arg)[/color]`} + {`{`} + {`        [color=#953800]ui_widget_t[/color] *label = arg;`} + {`        ui_text_set_content(label, [color=#0a3069]"按钮已被点击!"[/color]);`} + {`}`} + {` `} + {`[color=#953800]ui_widget_t[/color] *btn = ui_create_widget([color=#0a3069]"button"[/color]);`} + {`[color=#953800]ui_widget_t[/color] *label = ui_create_widget([color=#0a3069]"text"[/color]);`} + {` `} + {`ui_button_set_text(btn, [color=#0a3069]"Click me"[/color]);`} + {`ui_widget_on(btn, [color=#0a3069]"click"[/color], on_button_click, label);`} + + +

{`事件处理函数签名固定为 [bgcolor=#eee] (ui_widget_t *w, ui_event_t *e, void *arg) [/bgcolor]:`}

+
    +
  • {`[b][bgcolor=#eee] w [/bgcolor][/b] — 触发事件的部件。`}
  • +
  • {`[b][bgcolor=#eee] e [/bgcolor][/b] — 事件对象,包含事件类型和附带数据。`}
  • +
  • {`[b][bgcolor=#eee] arg [/bgcolor][/b] — 绑定事件时传入的自定义上下文(通常指向另一个部件或状态结构)。`}
  • +
+
+ +

语义标签

+

{`LCUI 默认的部件原型只有 [bgcolor=#eee] text [/bgcolor]、[bgcolor=#eee] button [/bgcolor]、[bgcolor=#eee] textinput [/bgcolor]、[bgcolor=#eee] scrollarea [/bgcolor] 等。[bgcolor=#eee] h1 [/bgcolor] / [bgcolor=#eee] h2 [/bgcolor] / [bgcolor=#eee] p [/bgcolor] 这些语义标签需要自行注册为 [bgcolor=#eee] text [/bgcolor] 的别名:`}

+ + + src/main.c + + + + {`[color=#953800]static[/color] [color=#953800]const[/color] [color=#953800]char[/color] *aliases\\[] = { [color=#0a3069]"h1"[/color], [color=#0a3069]"h2"[/color], [color=#0a3069]"h3"[/color], [color=#0a3069]"h4"[/color], [color=#0a3069]"h5"[/color], [color=#0a3069]"h6"[/color], [color=#0a3069]"p"[/color], [color=#0550ae]NULL[/color] };`} + {` `} + {`[color=#953800]static[/color] [color=#953800]void[/color] [color=#8250df]register_semantic_tags[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        [color=#cf222e]for[/color] ([color=#953800]const[/color] [color=#953800]char[/color] **n = aliases; *n; ++n) {`} + {`                ui_create_widget_prototype(*n, [color=#0a3069]"text"[/color]);`} + {`        }`} + {`}`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        register_semantic_tags();`} + {`        [color=#6e7781]/* ... 之后再实例化 h1 / p 等部件 */[/color]`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + +

{`注册完成后就可以在 XML 或 TSX 里像写 HTML 那样使用语义标签:`}

+ + + XML + + + + {`[color=#116329]<[color=#0550ae]h1[/color]>[/color]页面标题[color=#116329][/color]`} + {`[color=#116329]<[color=#0550ae]p[/color]>[/color]正文段落[color=#116329][/color]`} + + +
+ +

注意事项

+ + 注意 + +

{`[b]混合文本与元素不被支持。[/b] LCUI 的部件树里,一个部件要么是纯文本([bgcolor=#eee] [/bgcolor]),要么全是子部件。不能在同一个部件内混用"一段文本"和"一个嵌套的 [bgcolor=#eee] +``` ## API Reference diff --git a/docs/en/widgets/progress.mdx b/docs/en/widgets/progress.mdx index 90c49d331..ddb30d69e 100644 --- a/docs/en/widgets/progress.mdx +++ b/docs/en/widgets/progress.mdx @@ -10,17 +10,15 @@ A linear progress bar widget used to indicate the completion of a task such as f - **Suitable**: form submission or async operations that need a wait indicator - **Not suitable**: scenarios that require precise numeric values or indeterminate progress (use `text` to render manually) -## Anatomy - -Import the component: +## Usage ```tsx -import { Progress } from "@lcui/react"; - - +import { Progress } from "@lcui/react" ``` -Progress is composed of two strip-shaped children: a bottom `progress-track` that serves as the rail, and a foreground `progress-indicator` whose width is a percentage of the track driven by the current `value`. The `value` accepts a number in the range `0~100`; values outside this range are clamped to the nearest boundary. +```tsx + +``` ## API Reference diff --git a/docs/en/widgets/scrollarea.mdx b/docs/en/widgets/scrollarea.mdx index 4090f037f..828095f25 100644 --- a/docs/en/widgets/scrollarea.mdx +++ b/docs/en/widgets/scrollarea.mdx @@ -4,6 +4,36 @@ A container that provides scrollable content when children overflow. +## Use cases + +- **Suitable** — content height or width may exceed the container (long lists, documents, logs). +- **Suitable** — scrollbars needed for visual feedback. +- **Not suitable** — content always fits within the container (use a plain `widget`). + +## Usage + +```tsx +import { ScrollArea, ScrollAreaContent, Scrollbar } from "@lcui/react" +``` + +```tsx + + {/* child content */} + + + +``` + +## Composition + +Use the following composition to build a `ScrollArea`: + +``` +ScrollArea +├── ScrollAreaContent +└── Scrollbar +``` + ## API ### `ui_create_scrollarea` diff --git a/docs/en/widgets/text-input.mdx b/docs/en/widgets/text-input.mdx index 125a46496..b800d5823 100644 --- a/docs/en/widgets/text-input.mdx +++ b/docs/en/widgets/text-input.mdx @@ -4,6 +4,21 @@ An editable text input widget. Supports single-line, multiline, password, placeh +## Use cases + +- **Suitable** — user text input (form fields, search boxes). +- **Not suitable** — text display only (use `text`). + +## Usage + +```tsx +import { TextInput } from "@lcui/react" +``` + +```tsx + +``` + ## API ### `ui_textinput_set_text` diff --git a/docs/en/widgets/text.mdx b/docs/en/widgets/text.mdx index 50c60c050..e425825c5 100644 --- a/docs/en/widgets/text.mdx +++ b/docs/en/widgets/text.mdx @@ -4,6 +4,21 @@ A widget for displaying text. Supports single-line and multiline modes, inline s +## Use cases + +- **Suitable** — static text display (titles, labels, descriptions). +- **Not suitable** — editable text input (use `textinput`). + +## Usage + +```tsx +import { Text } from "@lcui/react" +``` + +```tsx +Hello +``` + ## API ### `ui_text_set_content` diff --git a/docs/zh-CN/widgets/anchor.mdx b/docs/zh-CN/widgets/anchor.mdx index f600bc252..421e5c41a 100644 --- a/docs/zh-CN/widgets/anchor.mdx +++ b/docs/zh-CN/widgets/anchor.mdx @@ -9,6 +9,12 @@ - **适用** — 在页面中放置外部链接(点击后在系统浏览器中打开)。 - **不适用** — 需要执行动作的按钮(用 `button`)。 +## 用法 + +```tsx +链接 +``` + ## API 参考 diff --git a/docs/zh-CN/widgets/button.mdx b/docs/zh-CN/widgets/button.mdx index 22cb5059b..0273b1a92 100644 --- a/docs/zh-CN/widgets/button.mdx +++ b/docs/zh-CN/widgets/button.mdx @@ -10,14 +10,14 @@ - **适用**:工具栏、对话框、导航栏中的交互入口 - **不适用**:不需要交互的纯文本展示(用 `text`) -## 结构 - -导入部件: +## 用法 ```tsx -import { Button } from "@lcui/react"; +import { Button } from "@lcui/react" +``` - ``` ## API 参考 diff --git a/docs/zh-CN/widgets/progress.mdx b/docs/zh-CN/widgets/progress.mdx index 72cd0c3fd..7f8b39f76 100644 --- a/docs/zh-CN/widgets/progress.mdx +++ b/docs/zh-CN/widgets/progress.mdx @@ -10,14 +10,14 @@ - **适用**:表单提交、异步操作的等待反馈 - **不适用**:需要精确数值或不确定进度的场景(用 `text` 自行绘制) -## 结构 - -导入部件: +## 用法 ```tsx -import { Progress } from "@lcui/react"; +import { Progress } from "@lcui/react" +``` - +```tsx + ``` ## API 参考 diff --git a/docs/zh-CN/widgets/scrollarea.mdx b/docs/zh-CN/widgets/scrollarea.mdx index 4a8b4c52b..dc9d9a415 100644 --- a/docs/zh-CN/widgets/scrollarea.mdx +++ b/docs/zh-CN/widgets/scrollarea.mdx @@ -10,13 +10,13 @@ - **适用** — 需要滚动条可视化反馈的场景。 - **不适用** — 内容总是小于容器(直接用普通 `widget` 即可)。 -## 结构 - -导入部件并组装其子组件: +## 用法 ```tsx -import { ScrollArea, ScrollAreaContent, Scrollbar } from "@lcui/react"; +import { ScrollArea, ScrollAreaContent, Scrollbar } from "@lcui/react" +``` +```tsx {/* 子内容 */} @@ -24,6 +24,16 @@ import { ScrollArea, ScrollAreaContent, Scrollbar } from "@lcui/react"; ``` +## 组合 + +使用以下组合来构建 `ScrollArea`: + +``` +ScrollArea +├── ScrollAreaContent +└── Scrollbar +``` + ## 示例 ### 双向滚动 diff --git a/docs/zh-CN/widgets/text-input.mdx b/docs/zh-CN/widgets/text-input.mdx index 20550f0f6..568bd13eb 100644 --- a/docs/zh-CN/widgets/text-input.mdx +++ b/docs/zh-CN/widgets/text-input.mdx @@ -9,13 +9,13 @@ - **适用** — 用户输入文本(表单字段、搜索框)。 - **不适用** — 仅需要展示文本(用 `text`)。 -## 结构 - -导入部件: +## 用法 ```tsx -import { TextInput } from "@lcui/react"; +import { TextInput } from "@lcui/react" +``` +```tsx ``` diff --git a/docs/zh-CN/widgets/text.mdx b/docs/zh-CN/widgets/text.mdx index 34a2ad134..72e84e4d8 100644 --- a/docs/zh-CN/widgets/text.mdx +++ b/docs/zh-CN/widgets/text.mdx @@ -9,14 +9,14 @@ - **适用** — 静态文本显示(标题、标签、说明文字)。 - **不适用** — 需要用户编辑文本(用 `textinput`)。 -## 结构 - -导入部件: +## 用法 ```tsx -import { Text } from "@lcui/react"; +import { Text } from "@lcui/react" +``` - +```tsx +Hello ``` ## API 参考 diff --git a/examples/doc-viewer/AGENTS.md b/examples/doc-viewer/AGENTS.md index 24ed5ec1b..eda0c9c53 100644 --- a/examples/doc-viewer/AGENTS.md +++ b/examples/doc-viewer/AGENTS.md @@ -35,16 +35,26 @@ examples/doc-viewer/ - **适用**:... - **不适用**:... -## 结构 - -引导语... +## 用法 \`\`\`tsx -import { WidgetName } from "@lcui/react"; +import { WidgetName } from "@lcui/react" +\`\`\` +\`\`\`tsx \`\`\` +## 组合(可选) + +使用以下组合来构建 `WidgetName`: + +\`\`\` +WidgetName +├── SubComponent +└── SubComponent +\`\`\` + ## API 参考 @@ -65,12 +75,17 @@ import { WidgetName } from "@lcui/react"; - 每个列表项以 `- **适用**:` 或 `- **不适用**:` 开头 - 中文用全角冒号 `:`,英文用半角冒号 `: ` -#### ## 结构(Anatomy) -- 代码块标签:` ```tsx `(无 title 属性) -- 内容:`import { X } from "@lcui/react"` + 组件用法 -- 代码块**前**写一行引导语,二选一: - - 单组件即可使用(如 Button、Text)→ `Import the component:` - - 需多个部件组合使用(如 ScrollArea + Scrollbar)→ `Import the component and assemble its parts:` +#### ## 用法(Usage) +- 两个代码块,均为 ` ```tsx `(无 title 属性) +- 第一个代码块:import 语句 +- 第二个代码块:组件核心用法(无需构造完整函数实现) +- 代码块**前**无需引导语 + +#### ## 组合(Composition)—— 仅多部件组件需要 +- 仅当组件包含子部件(如 ScrollArea 由 ScrollAreaContent + Scrollbar 组成)时才写此小节,单组件省略 +- 代码块标签:` ``` `(无语言标记,纯文本块) +- 内容:用树形结构展示组件层次关系(`├──` / `└──`) +- 代码块**前**写一行引导语:`使用以下组合来构建 `WidgetName`:`(英文:`Use the following composition to build a `WidgetName`:`) - 代码块后**禁止**写"X 由 Y + Z 组成"等内部实现说明 - **可以**写行为/模式描述(如 Anchor 的 URL 与 XML 视图模式区别) @@ -175,13 +190,13 @@ interface FieldData { | zh-CN | en | |-------|-----| | 适用场景 | Use cases | -| 结构 | Anatomy | +| 用法 | Usage | +| 组合 | Composition | | API 参考 | API Reference | | 示例 | Examples | | 注意事项 | Caveats | | 内联样式标签 | Inline style tags | -| 导入部件: | Import the component: | -| 导入部件并组装其子组件: | Import the component and assemble its parts: | +| 使用以下组合来构建 `WidgetName`: | Use the following composition to build a `WidgetName`: | ### FieldTable labels diff --git a/examples/doc-viewer/app/en/widgets/anchor/page.tsx b/examples/doc-viewer/app/en/widgets/anchor/page.tsx index 5e7e8e82b..861eda095 100644 --- a/examples/doc-viewer/app/en/widgets/anchor/page.tsx +++ b/examples/doc-viewer/app/en/widgets/anchor/page.tsx @@ -8,10 +8,42 @@ export default function AnchorDocPage() {

Anchor

{`A navigation widget similar to the HTML [bgcolor=#eee] [/bgcolor] element. It can open external URLs in the system browser or load an XML view into a target container widget.`}

+ +

Use cases

+
    +
  • {`[b]Suitable[/b] — placing external links in a page (opens in the system browser).`}
  • +
  • {`[b]Not suitable[/b] — performing an action (use [bgcolor=#eee] button [/bgcolor]).`}
  • +
+
+ +

Usage

+ + + TypeScript + + + + {`
[color=#8250df]Link[/color] text`} +
+ + + +

Composition

+

{`Use the following composition to build an [bgcolor=#eee] Anchor [/bgcolor]:`}

+ + + TEXT + + + + {`Anchor`} + + +

API

`ui_anchor_open`

- + C @@ -29,7 +61,7 @@ export default function AnchorDocPage() {

XML tag

- + XML @@ -90,7 +122,7 @@ export default function AnchorDocPage() {

Events

`loaded.anchor`

{`Fired on [bgcolor=#eee] ui_root() [/bgcolor] after a view has been loaded and injected:`}

- + C diff --git a/examples/doc-viewer/app/en/widgets/button/page.tsx b/examples/doc-viewer/app/en/widgets/button/page.tsx index 8e6444d95..ccc5df2a8 100644 --- a/examples/doc-viewer/app/en/widgets/button/page.tsx +++ b/examples/doc-viewer/app/en/widgets/button/page.tsx @@ -19,19 +19,38 @@ export default function ButtonDocPage() { -

Anatomy

+

Usage

- Anatomy + TypeScript - {`[color=#cf222e]import[/color] { [color=#8250df]Button[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} - {` `} - {`[color=#116329]<[color=#0550ae]Button[/color] />[/color]`} + {`[color=#cf222e]import[/color] { [color=#8250df]Button[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color]`} + + + + + TypeScript + + + + {`<[color=#8250df]Button[/color]>[color=#8250df]Button[/color]`} + + +
+ +

Composition

+

{`Use the following composition to build a [bgcolor=#eee] Button [/bgcolor]:`}

+ + + TEXT + + + + {`Button`} -

{`Button is a single-line widget composed of a background layer and text content. The [bgcolor=#eee] :hover [/bgcolor] / [bgcolor=#eee] :active [/bgcolor] pseudo-classes toggle the background color to provide click feedback.`}

API Reference

diff --git a/examples/doc-viewer/app/en/widgets/progress/page.tsx b/examples/doc-viewer/app/en/widgets/progress/page.tsx index b0bf8da6f..78b1009bc 100644 --- a/examples/doc-viewer/app/en/widgets/progress/page.tsx +++ b/examples/doc-viewer/app/en/widgets/progress/page.tsx @@ -19,20 +19,38 @@ export default function ProgressDocPage() {
-

Anatomy

-

{`Import the component:`}

+

Usage

TypeScript - {`[color=#cf222e]import[/color] { [color=#8250df]Progress[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} - {` `} - {`[color=#116329]<[color=#0550ae]Progress[/color] />[/color]`} + {`[color=#cf222e]import[/color] { [color=#8250df]Progress[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color]`} + + + + + TypeScript + + + + {`<[color=#8250df]Progress[/color] value={[color=#0550ae]20[/color]} />`} + + +
+ +

Composition

+

{`Use the following composition to build a [bgcolor=#eee] Progress [/bgcolor]:`}

+ + + TEXT + + + + {`Progress`} -

{`Progress is composed of two strip-shaped children: a bottom [bgcolor=#eee] progress-track [/bgcolor] that serves as the rail, and a foreground [bgcolor=#eee] progress-indicator [/bgcolor] whose width is a percentage of the track driven by the current [bgcolor=#eee] value [/bgcolor]. The [bgcolor=#eee] value [/bgcolor] accepts a number in the range [bgcolor=#eee] 0~100 [/bgcolor]; values outside this range are clamped to the nearest boundary.`}

API Reference

diff --git a/examples/doc-viewer/app/en/widgets/scrollarea/page.tsx b/examples/doc-viewer/app/en/widgets/scrollarea/page.tsx index e6e1a6494..ec26334a7 100644 --- a/examples/doc-viewer/app/en/widgets/scrollarea/page.tsx +++ b/examples/doc-viewer/app/en/widgets/scrollarea/page.tsx @@ -8,10 +8,58 @@ export default function ScrollareaDocPage() {

ScrollArea

{`A container that provides scrollable content when children overflow.`}

+ +

Use cases

+
    +
  • {`[b]Suitable[/b] — content height or width may exceed the container (long lists, documents, logs).`}
  • +
  • {`[b]Suitable[/b] — scrollbars needed for visual feedback.`}
  • +
  • {`[b]Not suitable[/b] — content always fits within the container (use a plain [bgcolor=#eee] widget [/bgcolor]).`}
  • +
+
+ +

Usage

+ + + TypeScript + + + + {`[color=#cf222e]import[/color] { [color=#8250df]ScrollArea[/color], [color=#8250df]ScrollAreaContent[/color], [color=#8250df]Scrollbar[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color]`} + + + + + TypeScript + + + + {`<[color=#8250df]ScrollArea[/color]>`} + {`  [color=#116329]<[color=#0550ae]ScrollAreaContent[/color]>[/color]{/* child content */}[color=#116329][/color]`} + {`  [color=#116329]<[color=#0550ae]Scrollbar[/color] [color=#0550ae]orientation[/color]=[color=#0a3069]"horizontal"[/color] />[/color]`} + {`  [color=#116329]<[color=#0550ae]Scrollbar[/color] />[/color]`} + {``} + + +
+ +

Composition

+

{`Use the following composition to build a [bgcolor=#eee] ScrollArea [/bgcolor]:`}

+ + + TEXT + + + + {`ScrollArea`} + {`├── ScrollAreaContent`} + {`└── Scrollbar`} + + +

API

`ui_create_scrollarea`

- + C @@ -22,7 +70,7 @@ export default function ScrollareaDocPage() {

{`Creates and returns a new scroll area widget.`}

`ui_create_scrollarea_content`

- + C @@ -33,7 +81,7 @@ export default function ScrollareaDocPage() {

{`Creates and returns a new scroll content container to be appended inside a scroll area.`}

`ui_scrollarea_set_scroll_top`

- + C @@ -44,7 +92,7 @@ export default function ScrollareaDocPage() {

{`Sets the vertical scroll position in pixels.`}

`ui_scrollarea_set_scroll_left`

- + C @@ -55,7 +103,7 @@ export default function ScrollareaDocPage() {

{`Sets the horizontal scroll position in pixels.`}

`ui_scrollarea_get_scroll_top`

- + C @@ -66,7 +114,7 @@ export default function ScrollareaDocPage() {

{`Returns the current vertical scroll position.`}

`ui_scrollarea_get_scroll_left`

- + C @@ -77,7 +125,7 @@ export default function ScrollareaDocPage() {

{`Returns the current horizontal scroll position.`}

`ui_scrollarea_get_scroll_width`

- + C @@ -88,7 +136,7 @@ export default function ScrollareaDocPage() {

{`Returns the total scrollable width of the content.`}

`ui_scrollarea_get_scroll_height`

- + C @@ -99,7 +147,7 @@ export default function ScrollareaDocPage() {

{`Returns the total scrollable height of the content.`}

`ui_scrollarea_set_wheel_scroll_direction`

- + C @@ -145,7 +193,7 @@ export default function ScrollareaDocPage() {

`ui_scrollarea_update`

- + C @@ -158,7 +206,7 @@ export default function ScrollareaDocPage() {

XML tag

- + XML diff --git a/examples/doc-viewer/app/en/widgets/text-input/page.tsx b/examples/doc-viewer/app/en/widgets/text-input/page.tsx index 88301fece..1998ef14c 100644 --- a/examples/doc-viewer/app/en/widgets/text-input/page.tsx +++ b/examples/doc-viewer/app/en/widgets/text-input/page.tsx @@ -8,10 +8,51 @@ export default function TextInputDocPage() {

TextInput

{`An editable text input widget. Supports single-line, multiline, password, placeholder, and readonly modes.`}

+ +

Use cases

+
    +
  • {`[b]Suitable[/b] — user text input (form fields, search boxes).`}
  • +
  • {`[b]Not suitable[/b] — text display only (use [bgcolor=#eee] text [/bgcolor]).`}
  • +
+
+ +

Usage

+ + + TypeScript + + + + {`[color=#cf222e]import[/color] { [color=#8250df]TextInput[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color]`} + + + + + TypeScript + + + + {`<[color=#8250df]TextInput[/color] placeholder=[color=#0a3069]"Enter text"[/color] />`} + + +
+ +

Composition

+

{`Use the following composition to build a [bgcolor=#eee] TextInput [/bgcolor]:`}

+ + + TEXT + + + + {`TextInput`} + + +

API

`ui_textinput_set_text`

- + C @@ -22,7 +63,7 @@ export default function TextInputDocPage() {

{`Sets the input value from a UTF-8 string.`}

`ui_textinput_set_text_w`

- + C @@ -33,7 +74,7 @@ export default function TextInputDocPage() {

{`Sets the input value from a wide character string.`}

`ui_textinput_get_text_w`

- + C @@ -45,7 +86,7 @@ export default function TextInputDocPage() {

{`Reads the current input value. Returns the number of characters written.`}

`ui_textinput_get_text_length`

- + C @@ -56,7 +97,7 @@ export default function TextInputDocPage() {

{`Returns the current text length in characters.`}

`ui_textinput_clear_text`

- + C @@ -67,7 +108,7 @@ export default function TextInputDocPage() {

{`Clears all text from the input.`}

`ui_textinput_set_placeholder`

- + C @@ -78,7 +119,7 @@ export default function TextInputDocPage() {

{`Sets the placeholder text shown when the input is empty.`}

`ui_textinput_set_placeholder_w`

- + C @@ -89,7 +130,7 @@ export default function TextInputDocPage() {

{`Sets the placeholder text from a wide character string.`}

`ui_textinput_set_password_char`

- + C @@ -100,7 +141,7 @@ export default function TextInputDocPage() {

{`Masks the input with the given character (e.g. [bgcolor=#eee] L'*' [/bgcolor] for password fields).`}

`ui_textinput_enable_multiline`

- + C @@ -111,7 +152,7 @@ export default function TextInputDocPage() {

{`Enables or disables multiline input mode.`}

`ui_textinput_enable_style_tag`

- + C @@ -122,7 +163,7 @@ export default function TextInputDocPage() {

{`Enables or disables inline style tag parsing in the input.`}

`ui_textinput_append_text_w`

- + C @@ -133,7 +174,7 @@ export default function TextInputDocPage() {

{`Appends text at the end of the current content.`}

`ui_textinput_insert_text_w`

- + C @@ -144,7 +185,7 @@ export default function TextInputDocPage() {

{`Inserts text at the current caret position.`}

`ui_textinput_set_caret_blink`

- + C @@ -157,7 +198,7 @@ export default function TextInputDocPage() {

XML tag

- + XML diff --git a/examples/doc-viewer/app/en/widgets/text/page.tsx b/examples/doc-viewer/app/en/widgets/text/page.tsx index fa4e8e437..779931129 100644 --- a/examples/doc-viewer/app/en/widgets/text/page.tsx +++ b/examples/doc-viewer/app/en/widgets/text/page.tsx @@ -8,10 +8,51 @@ export default function TextDocPage() {

Text

{`A widget for displaying text. Supports single-line and multiline modes, inline style tags, and CSS styling.`}

+ +

Use cases

+
    +
  • {`[b]Suitable[/b] — static text display (titles, labels, descriptions).`}
  • +
  • {`[b]Not suitable[/b] — editable text input (use [bgcolor=#eee] textinput [/bgcolor]).`}
  • +
+
+ +

Usage

+ + + TypeScript + + + + {`[color=#cf222e]import[/color] { [color=#8250df]Text[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color]`} + + + + + TypeScript + + + + {`<[color=#8250df]Text[/color]>[color=#8250df]Hello[/color]`} + + +
+ +

Composition

+

{`Use the following composition to build a [bgcolor=#eee] Text [/bgcolor]:`}

+ + + TEXT + + + + {`Text`} + + +

API

`ui_text_set_content`

- + C @@ -22,7 +63,7 @@ export default function TextDocPage() {

{`Sets the text content from a UTF-8 string. Supports inline style tags.`}

`ui_text_set_content_w`

- + C @@ -33,7 +74,7 @@ export default function TextDocPage() {

{`Sets the text content from a wide character string.`}

`ui_text_get_content_w`

- + C @@ -44,7 +85,7 @@ export default function TextDocPage() {

{`Reads the current text content into [bgcolor=#eee] buf [/bgcolor] (up to [bgcolor=#eee] size [/bgcolor] wide characters). Returns the number of characters written.`}

`ui_text_set_multiline`

- + C @@ -57,7 +98,7 @@ export default function TextDocPage() {

XML tag

- + XML diff --git a/examples/doc-viewer/app/examples/progress-basic/index.tsx b/examples/doc-viewer/app/examples/progress-basic/index.tsx index 4871e027e..195a14f4e 100644 --- a/examples/doc-viewer/app/examples/progress-basic/index.tsx +++ b/examples/doc-viewer/app/examples/progress-basic/index.tsx @@ -133,6 +133,7 @@ export default function ProgressBasicDemo() { {`        ui_progress_set_value(progress, progress_value);`} {`        ui_widget_append(parent, progress);`} {`        timer_id = ptk_set_interval([color=#0550ae]500[/color], on_timer, progress);`} + {`        progress_value = [color=#0550ae]20.0f[/color];`} {`}`} {` `} {`[color=#953800]void[/color] [color=#8250df]progress_basic_destroy[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} diff --git a/examples/doc-viewer/app/zh-CN/widgets/anchor/page.tsx b/examples/doc-viewer/app/zh-CN/widgets/anchor/page.tsx index dac40bcae..ea8057667 100644 --- a/examples/doc-viewer/app/zh-CN/widgets/anchor/page.tsx +++ b/examples/doc-viewer/app/zh-CN/widgets/anchor/page.tsx @@ -17,6 +17,31 @@ export default function AnchorDocPage() {
  • {`[b]不适用[/b] — 需要执行动作的按钮(用 [bgcolor=#eee] button [/bgcolor])。`}
  • + +

    用法

    + + + TypeScript + + + + {`链接`} + + +
    + +

    组合

    +

    {`使用以下组合来构建 [bgcolor=#eee] Anchor [/bgcolor]:`}

    + + + TEXT + + + + {`Anchor`} + + +

    API 参考

    diff --git a/examples/doc-viewer/app/zh-CN/widgets/button/page.tsx b/examples/doc-viewer/app/zh-CN/widgets/button/page.tsx index 700e9c304..038ebb16b 100644 --- a/examples/doc-viewer/app/zh-CN/widgets/button/page.tsx +++ b/examples/doc-viewer/app/zh-CN/widgets/button/page.tsx @@ -19,17 +19,36 @@ export default function ButtonDocPage() {
    -

    结构

    -

    {`导入部件:`}

    +

    用法

    TypeScript - {`[color=#cf222e]import[/color] { [color=#8250df]Button[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} - {` `} - {`[color=#116329]<[color=#0550ae]Button[/color] />[/color]`} + {`[color=#cf222e]import[/color] { [color=#8250df]Button[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color]`} + + + + + TypeScript + + + + {`<[color=#8250df]Button[/color]>[color=#8250df]Button[/color]`} + + +
    + +

    组合

    +

    {`使用以下组合来构建 [bgcolor=#eee] Button [/bgcolor]:`}

    + + + TEXT + + + + {`Button`}
    diff --git a/examples/doc-viewer/app/zh-CN/widgets/progress/page.tsx b/examples/doc-viewer/app/zh-CN/widgets/progress/page.tsx index d456d8042..bfdce3b08 100644 --- a/examples/doc-viewer/app/zh-CN/widgets/progress/page.tsx +++ b/examples/doc-viewer/app/zh-CN/widgets/progress/page.tsx @@ -19,20 +19,38 @@ export default function ProgressDocPage() {
    -

    结构

    -

    {`导入部件:`}

    +

    用法

    TypeScript - {`[color=#cf222e]import[/color] { [color=#8250df]Progress[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} - {` `} - {`[color=#116329]<[color=#0550ae]Progress[/color] />[/color]`} + {`[color=#cf222e]import[/color] { [color=#8250df]Progress[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color]`} + + + + + TypeScript + + + + {`<[color=#8250df]Progress[/color] value={[color=#0550ae]20[/color]} />`} + + +
    + +

    组合

    +

    {`使用以下组合来构建 [bgcolor=#eee] Progress [/bgcolor]:`}

    + + + TEXT + + + + {`Progress`} -

    {`Progress 由两条带状子部件自动组合:底层 [bgcolor=#eee] progress-track [/bgcolor] 充当轨道,前景 [bgcolor=#eee] progress-indicator [/bgcolor] 根据当前 [bgcolor=#eee] value [/bgcolor] 占据轨道左侧的百分比宽度。[bgcolor=#eee] value [/bgcolor] 取值范围为 [bgcolor=#eee] 0~100 [/bgcolor],超出范围的值会被自动截断到边界。`}

    API 参考

    diff --git a/examples/doc-viewer/app/zh-CN/widgets/scrollarea/page.tsx b/examples/doc-viewer/app/zh-CN/widgets/scrollarea/page.tsx index d46a3e236..3fb51ae58 100644 --- a/examples/doc-viewer/app/zh-CN/widgets/scrollarea/page.tsx +++ b/examples/doc-viewer/app/zh-CN/widgets/scrollarea/page.tsx @@ -22,21 +22,42 @@ export default function ScrollareaDocPage() {
    -

    结构

    -

    {`导入部件并组装其子组件:`}

    +

    用法

    TypeScript - {`[color=#cf222e]import[/color] { [color=#8250df]ScrollArea[/color], [color=#8250df]ScrollAreaContent[/color], [color=#8250df]Scrollbar[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} - {` `} - {`[color=#116329]<[color=#0550ae]ScrollArea[/color]>[/color]`} + {`[color=#cf222e]import[/color] { [color=#8250df]ScrollArea[/color], [color=#8250df]ScrollAreaContent[/color], [color=#8250df]Scrollbar[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color]`} + + + + + TypeScript + + + + {`<[color=#8250df]ScrollArea[/color]>`} {`  [color=#116329]<[color=#0550ae]ScrollAreaContent[/color]>[/color]{/* 子内容 */}[color=#116329][/color]`} {`  [color=#116329]<[color=#0550ae]Scrollbar[/color] [color=#0550ae]orientation[/color]=[color=#0a3069]"horizontal"[/color] />[/color]`} {`  [color=#116329]<[color=#0550ae]Scrollbar[/color] />[/color]`} - {`[color=#116329][/color]`} + {``} + + +
    + +

    组合

    +

    {`使用以下组合来构建 [bgcolor=#eee] ScrollArea [/bgcolor]:`}

    + + + TEXT + + + + {`ScrollArea`} + {`├── ScrollAreaContent`} + {`└── Scrollbar`}
    diff --git a/examples/doc-viewer/app/zh-CN/widgets/text-input/page.tsx b/examples/doc-viewer/app/zh-CN/widgets/text-input/page.tsx index 48b64cc6d..138a3c75b 100644 --- a/examples/doc-viewer/app/zh-CN/widgets/text-input/page.tsx +++ b/examples/doc-viewer/app/zh-CN/widgets/text-input/page.tsx @@ -18,17 +18,36 @@ export default function TextInputDocPage() {
    -

    结构

    -

    {`导入部件:`}

    +

    用法

    TypeScript - {`[color=#cf222e]import[/color] { [color=#8250df]TextInput[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} - {` `} - {`[color=#116329]<[color=#0550ae]TextInput[/color] />[/color]`} + {`[color=#cf222e]import[/color] { [color=#8250df]TextInput[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color]`} + + + + + TypeScript + + + + {`<[color=#8250df]TextInput[/color] />`} + + +
    + +

    组合

    +

    {`使用以下组合来构建 [bgcolor=#eee] TextInput [/bgcolor]:`}

    + + + TEXT + + + + {`TextInput`}
    diff --git a/examples/doc-viewer/app/zh-CN/widgets/text/page.tsx b/examples/doc-viewer/app/zh-CN/widgets/text/page.tsx index 6d8fd8732..98cc6ec6f 100644 --- a/examples/doc-viewer/app/zh-CN/widgets/text/page.tsx +++ b/examples/doc-viewer/app/zh-CN/widgets/text/page.tsx @@ -18,17 +18,36 @@ export default function TextDocPage() {
    -

    结构

    -

    {`导入部件:`}

    +

    用法

    TypeScript - {`[color=#cf222e]import[/color] { [color=#8250df]Text[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} - {` `} - {`[color=#116329]<[color=#0550ae]Text[/color] />[/color]`} + {`[color=#cf222e]import[/color] { [color=#8250df]Text[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color]`} + + + + + TypeScript + + + + {`<[color=#8250df]Text[/color]>[color=#8250df]Hello[/color]`} + + +
    + +

    组合

    +

    {`使用以下组合来构建 [bgcolor=#eee] Text [/bgcolor]:`}

    + + + TEXT + + + + {`Text`}
    From b9a0591cfefee064a635c1f0d4cff9f17e81d5dc Mon Sep 17 00:00:00 2001 From: Liu Date: Sun, 28 Jun 2026 22:20:52 +0800 Subject: [PATCH 51/66] feat(widgets): add label widget --- include/LCUI/widgets.h | 1 + include/LCUI/widgets/label.h | 36 +++++++++ src/lcui_widgets.c | 1 + src/widgets/label.c | 61 +++++++++++++++ tests/integration/test_label.c | 137 +++++++++++++++++++++++++++++++++ tests/main.c | 2 + 6 files changed, 238 insertions(+) create mode 100644 include/LCUI/widgets/label.h create mode 100644 src/widgets/label.c create mode 100644 tests/integration/test_label.c diff --git a/include/LCUI/widgets.h b/include/LCUI/widgets.h index 3d9bc72f1..0e2ac0782 100644 --- a/include/LCUI/widgets.h +++ b/include/LCUI/widgets.h @@ -18,3 +18,4 @@ #include "widgets/scrollbar.h" #include "widgets/textinput.h" #include "widgets/textcaret.h" +#include "widgets/label.h" diff --git a/include/LCUI/widgets/label.h b/include/LCUI/widgets/label.h new file mode 100644 index 000000000..1b2255a3d --- /dev/null +++ b/include/LCUI/widgets/label.h @@ -0,0 +1,36 @@ +/* + * include/LCUI/widgets/label.h: -- LCUI's Label widget + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#ifndef LCUI_INCLUDE_WIDGETS_LABEL_H +#define LCUI_INCLUDE_WIDGETS_LABEL_H + +#include +#include + +LCUI_BEGIN_HEADER + +LCUI_API ui_widget_t *ui_create_label(void); + +LCUI_API void ui_register_label(void); + +static inline int ui_label_set_for(ui_widget_t *w, const char *id) +{ + return ui_widget_set_attr(w, "for", id); +} + +static inline const char *ui_label_get_for(ui_widget_t *w) +{ + return ui_widget_get_attr(w, "for"); +} + +LCUI_END_HEADER + +#endif diff --git a/src/lcui_widgets.c b/src/lcui_widgets.c index 5d4fe4f6b..183b920bc 100644 --- a/src/lcui_widgets.c +++ b/src/lcui_widgets.c @@ -25,6 +25,7 @@ void lcui_widgets_init(void) ui_register_textinput(); ui_register_router_link(); ui_register_router_view(); + ui_register_label(); } void lcui_widgets_destroy(void) diff --git a/src/widgets/label.c b/src/widgets/label.c new file mode 100644 index 000000000..72b7dc98b --- /dev/null +++ b/src/widgets/label.c @@ -0,0 +1,61 @@ +/* + * src/widgets/label.c: -- Label widget + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include + +static ui_widget_prototype_t *ui_label_prototype = NULL; + +static const char *ui_label_css = "label:disabled {\ +opacity: 0.6;\ +}"; + +static void ui_label_on_click(ui_widget_t *w, ui_event_t *e, void *arg) +{ + const char *for_id; + ui_widget_t *target; + ui_event_t forwarded; + + if (w->disabled) { + return; + } + for_id = ui_widget_get_attr(w, "for"); + if (!for_id) { + return; + } + target = ui_get_widget(for_id); + if (!target) { + return; + } + ui_event_init(&forwarded, "click"); + ui_widget_emit_event(target, forwarded, NULL); +} + +static void ui_label_on_init(ui_widget_t *w) +{ + ui_label_prototype->proto->init(w); + ui_widget_on(w, "click", ui_label_on_click, NULL); +} + +ui_widget_t *ui_create_label(void) +{ + return ui_create_widget("label"); +} + +void ui_register_label(void) +{ + ui_label_prototype = ui_create_widget_prototype("label", "text"); + ui_label_prototype->init = ui_label_on_init; + ui_load_css_string(ui_label_css, __FILE__); +} diff --git a/tests/integration/test_label.c b/tests/integration/test_label.c new file mode 100644 index 000000000..afdde1853 --- /dev/null +++ b/tests/integration/test_label.c @@ -0,0 +1,137 @@ +/* + * tests/integration/test_label.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include + +static int g_target_click_count; + +static void on_target_click(ui_widget_t *w, ui_event_t *e, void *arg) +{ + (void)w; + (void)e; + (void)arg; + ++g_target_click_count; +} + +static void test_get_for_default(void) +{ + ui_widget_t *label = ui_create_label(); + + ctest_equal_bool("should return NULL when no 'for' attribute set", + ui_label_get_for(label) == NULL, true); + + ui_widget_destroy(label); +} + +static void test_set_for_roundtrip(void) +{ + ui_widget_t *label = ui_create_label(); + + ui_label_set_for(label, "my-target"); + ctest_equal_str("should return the id that was set", + ui_label_get_for(label), "my-target"); + + ui_label_set_for(label, "other-target"); + ctest_equal_str("should overwrite previous id", ui_label_get_for(label), + "other-target"); + + ui_widget_destroy(label); +} + +static void test_click_forwards_to_target(void) +{ + ui_widget_t *label; + ui_widget_t *target; + ui_event_t ev; + + g_target_click_count = 0; + + target = ui_create_widget("button"); + ui_widget_set_id(target, "tgt"); + ui_widget_on(target, "click", on_target_click, NULL); + + label = ui_create_label(); + ui_label_set_for(label, "tgt"); + + ui_widget_append(ui_root(), target); + ui_widget_append(ui_root(), label); + + ui_event_init(&ev, "click"); + ui_widget_emit_event(label, ev, NULL); + + ctest_equal_int("should fire click on target widget", + g_target_click_count, 1); + + ui_widget_destroy(label); + ui_widget_destroy(target); +} + +static void test_disabled_blocks_forward(void) +{ + ui_widget_t *label; + ui_widget_t *target; + ui_event_t ev; + + g_target_click_count = 0; + + target = ui_create_widget("button"); + ui_widget_set_id(target, "tgt2"); + ui_widget_on(target, "click", on_target_click, NULL); + + label = ui_create_label(); + ui_label_set_for(label, "tgt2"); + ui_widget_set_disabled(label, true); + + ui_widget_append(ui_root(), target); + ui_widget_append(ui_root(), label); + + ui_event_init(&ev, "click"); + ui_widget_emit_event(label, ev, NULL); + + ctest_equal_int("should not fire click when label is disabled", + g_target_click_count, 0); + + ui_widget_destroy(label); + ui_widget_destroy(target); +} + +static void test_click_without_for_is_safe(void) +{ + ui_widget_t *label; + ui_event_t ev; + + label = ui_create_label(); + ui_widget_append(ui_root(), label); + + ui_event_init(&ev, "click"); + ui_widget_emit_event(label, ev, NULL); + + ctest_equal_bool("should not crash when 'for' is unset", true, true); + + ui_widget_destroy(label); +} + +void test_label(void) +{ + lcui_init(); + + ctest_describe("label get_for default", test_get_for_default); + ctest_describe("label set_for roundtrip", test_set_for_roundtrip); + ctest_describe("label click forwards to target", + test_click_forwards_to_target); + ctest_describe("label click without for is safe", + test_click_without_for_is_safe); + ctest_describe("label disabled blocks forward", + test_disabled_blocks_forward); + + lcui_destroy(); +} diff --git a/tests/main.c b/tests/main.c index 64a8173ba..a4810513d 100644 --- a/tests/main.c +++ b/tests/main.c @@ -26,6 +26,7 @@ extern void test_block_layout(void); extern void test_flex_layout(void); extern void test_scrollbar(void); extern void test_progress(void); +extern void test_label(void); static const ctest_suite_t suites[] = { { "settings", test_settings }, @@ -42,6 +43,7 @@ static const ctest_suite_t suites[] = { { "flex layout", test_flex_layout }, { "scrollbar", test_scrollbar }, { "progress", test_progress }, + { "label", test_label }, { NULL, NULL } }; From 95dbe942345c347ce5d83499c8b6203ee70dfaeb Mon Sep 17 00:00:00 2001 From: Liu Date: Sun, 28 Jun 2026 22:52:43 +0800 Subject: [PATCH 52/66] feat(widgets): add checkbox widget --- include/LCUI/widgets.h | 1 + include/LCUI/widgets/checkbox.h | 53 +++++++++ src/lcui_widgets.c | 1 + src/widgets/checkbox.c | 120 +++++++++++++++++++++ tests/integration/test_checkbox.c | 171 ++++++++++++++++++++++++++++++ tests/main.c | 2 + 6 files changed, 348 insertions(+) create mode 100644 include/LCUI/widgets/checkbox.h create mode 100644 src/widgets/checkbox.c create mode 100644 tests/integration/test_checkbox.c diff --git a/include/LCUI/widgets.h b/include/LCUI/widgets.h index 0e2ac0782..f7327442e 100644 --- a/include/LCUI/widgets.h +++ b/include/LCUI/widgets.h @@ -19,3 +19,4 @@ #include "widgets/textinput.h" #include "widgets/textcaret.h" #include "widgets/label.h" +#include "widgets/checkbox.h" diff --git a/include/LCUI/widgets/checkbox.h b/include/LCUI/widgets/checkbox.h new file mode 100644 index 000000000..6e866e30e --- /dev/null +++ b/include/LCUI/widgets/checkbox.h @@ -0,0 +1,53 @@ +/* + * include/LCUI/widgets/checkbox.h: -- LCUI's Checkbox widget + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#ifndef LCUI_INCLUDE_WIDGETS_CHECKBOX_H +#define LCUI_INCLUDE_WIDGETS_CHECKBOX_H + +#include +#include +#include + +LCUI_BEGIN_HEADER + +LCUI_API ui_widget_t *ui_create_checkbox(void); + +LCUI_API void ui_register_checkbox(void); + +static inline int ui_checkbox_set_checked(ui_widget_t *w, int checked) +{ + return ui_widget_set_attr(w, "checked", checked ? "true" : "false"); +} + +static inline int ui_checkbox_get_checked(ui_widget_t *w) +{ + const char *v = ui_widget_get_attr(w, "checked"); + + return v && strcmp(v, "true") == 0; +} + +static inline int ui_checkbox_set_indeterminate(ui_widget_t *w, + int indeterminate) +{ + return ui_widget_set_attr(w, "indeterminate", + indeterminate ? "true" : "false"); +} + +static inline int ui_checkbox_get_indeterminate(ui_widget_t *w) +{ + const char *v = ui_widget_get_attr(w, "indeterminate"); + + return v && strcmp(v, "true") == 0; +} + +LCUI_END_HEADER + +#endif diff --git a/src/lcui_widgets.c b/src/lcui_widgets.c index 183b920bc..fac033006 100644 --- a/src/lcui_widgets.c +++ b/src/lcui_widgets.c @@ -26,6 +26,7 @@ void lcui_widgets_init(void) ui_register_router_link(); ui_register_router_view(); ui_register_label(); + ui_register_checkbox(); } void lcui_widgets_destroy(void) diff --git a/src/widgets/checkbox.c b/src/widgets/checkbox.c new file mode 100644 index 000000000..381959013 --- /dev/null +++ b/src/widgets/checkbox.c @@ -0,0 +1,120 @@ +/* + * src/widgets/checkbox.c: -- Checkbox widget + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include + +static ui_widget_prototype_t *ui_checkbox_prototype = NULL; + +static const char *ui_checkbox_css = "\ +checkbox {\ + display: inline-block;\ + width: 16px; height: 16px;\ + border: 1px solid #ccc;\ + vertical-align: middle;\ + text-align: center;\ + line-height: 14px;\ +}\ +checkbox:checked {\ + background-color: #1e88e5;\ + color: #fff;\ + border-color: #1e88e5;\ +}\ +checkbox:indeterminate {\ + background-color: #1e88e5;\ + color: #fff;\ + border-color: #1e88e5;\ +}\ +checkbox:disabled { opacity: 0.5; }"; + +static void ui_checkbox_update_visual(ui_widget_t *w) +{ + const char *mark; + int checked; + int indeterminate; + + checked = ui_checkbox_get_checked(w); + indeterminate = ui_checkbox_get_indeterminate(w); + if (indeterminate) { + mark = "\xe2\x80\x94"; + } else if (checked) { + mark = "\xe2\x88\x9a"; + } else { + mark = ""; + } + ui_text_set_content(w, mark); +} + +static void ui_checkbox_sync_status(ui_widget_t *w) +{ + if (ui_checkbox_get_checked(w)) { + ui_widget_add_status(w, "checked"); + } else { + ui_widget_remove_status(w, "checked"); + } + if (ui_checkbox_get_indeterminate(w)) { + ui_widget_add_status(w, "indeterminate"); + } else { + ui_widget_remove_status(w, "indeterminate"); + } +} + +static void ui_checkbox_on_click(ui_widget_t *w, ui_event_t *e, void *arg) +{ + ui_event_t ev; + + if (w->disabled) { + return; + } + if (ui_checkbox_get_indeterminate(w)) { + ui_checkbox_set_indeterminate(w, 0); + ui_checkbox_set_checked(w, 1); + } else { + ui_checkbox_set_checked(w, !ui_checkbox_get_checked(w)); + } + ui_event_init(&ev, "change"); + ui_widget_emit_event(w, ev, NULL); +} + +static void ui_checkbox_on_set_attr(ui_widget_t *w, const char *name, + const char *value) +{ + if (strcmp(name, "checked") == 0 || + strcmp(name, "indeterminate") == 0) { + ui_checkbox_update_visual(w); + ui_checkbox_sync_status(w); + } +} + +static void ui_checkbox_on_init(ui_widget_t *w) +{ + ui_checkbox_prototype->proto->init(w); + ui_widget_on(w, "click", ui_checkbox_on_click, NULL); + ui_checkbox_update_visual(w); + ui_checkbox_sync_status(w); +} + +ui_widget_t *ui_create_checkbox(void) +{ + return ui_create_widget("checkbox"); +} + +void ui_register_checkbox(void) +{ + ui_checkbox_prototype = ui_create_widget_prototype("checkbox", "text"); + ui_checkbox_prototype->init = ui_checkbox_on_init; + ui_checkbox_prototype->setattr = ui_checkbox_on_set_attr; + ui_load_css_string(ui_checkbox_css, __FILE__); +} diff --git a/tests/integration/test_checkbox.c b/tests/integration/test_checkbox.c new file mode 100644 index 000000000..37e3da3f3 --- /dev/null +++ b/tests/integration/test_checkbox.c @@ -0,0 +1,171 @@ +/* + * tests/integration/test_checkbox.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include + +static int g_change_count; + +static void on_checkbox_change(ui_widget_t *w, ui_event_t *e, void *arg) +{ + ++g_change_count; +} + +static void test_checked_roundtrip(void) +{ + ui_widget_t *cb = ui_create_checkbox(); + + ctest_equal_int("should default to unchecked", + ui_checkbox_get_checked(cb), 0); + + ui_checkbox_set_checked(cb, 1); + ctest_equal_int("should return 1 after set_checked(1)", + ui_checkbox_get_checked(cb), 1); + + ui_checkbox_set_checked(cb, 0); + ctest_equal_int("should return 0 after set_checked(0)", + ui_checkbox_get_checked(cb), 0); + + ui_widget_destroy(cb); +} + +static void test_click_toggles(void) +{ + ui_widget_t *cb = ui_create_checkbox(); + ui_event_t ev; + + ui_widget_append(ui_root(), cb); + + ui_event_init(&ev, "click"); + ui_widget_emit_event(cb, ev, NULL); + ctest_equal_int("first click should check", ui_checkbox_get_checked(cb), + 1); + + ui_widget_emit_event(cb, ev, NULL); + ctest_equal_int("second click should uncheck", + ui_checkbox_get_checked(cb), 0); + + ui_widget_destroy(cb); +} + +static void test_click_emits_change(void) +{ + ui_widget_t *cb = ui_create_checkbox(); + ui_event_t ev; + + g_change_count = 0; + ui_widget_on(cb, "change", on_checkbox_change, NULL); + + ui_widget_append(ui_root(), cb); + + ui_event_init(&ev, "click"); + ui_widget_emit_event(cb, ev, NULL); + + ctest_equal_int("should emit change once after click", g_change_count, + 1); + + ui_widget_destroy(cb); +} + +static void test_disabled_blocks_toggle(void) +{ + ui_widget_t *cb = ui_create_checkbox(); + ui_event_t ev; + + ui_widget_append(ui_root(), cb); + ui_widget_set_disabled(cb, true); + + ui_event_init(&ev, "click"); + ui_widget_emit_event(cb, ev, NULL); + + ctest_equal_int("disabled checkbox should stay unchecked", + ui_checkbox_get_checked(cb), 0); + + ui_widget_destroy(cb); +} + +static void test_indeterminate_roundtrip(void) +{ + ui_widget_t *cb = ui_create_checkbox(); + + ctest_equal_int("should default to not indeterminate", + ui_checkbox_get_indeterminate(cb), 0); + + ui_checkbox_set_indeterminate(cb, 1); + ctest_equal_int("should return 1 after set_indeterminate(1)", + ui_checkbox_get_indeterminate(cb), 1); + + ui_checkbox_set_indeterminate(cb, 0); + ctest_equal_int("should return 0 after set_indeterminate(0)", + ui_checkbox_get_indeterminate(cb), 0); + + ui_widget_destroy(cb); +} + +static void test_indeterminate_click_transitions_to_checked(void) +{ + ui_widget_t *cb = ui_create_checkbox(); + ui_event_t ev; + + ui_widget_append(ui_root(), cb); + ui_checkbox_set_indeterminate(cb, 1); + + ui_event_init(&ev, "click"); + ui_widget_emit_event(cb, ev, NULL); + + ctest_equal_int("indeterminate click should set checked", + ui_checkbox_get_checked(cb), 1); + ctest_equal_int("indeterminate click should clear indeterminate", + ui_checkbox_get_indeterminate(cb), 0); + + ui_widget_destroy(cb); +} + +static void test_status_sync(void) +{ + ui_widget_t *cb = ui_create_checkbox(); + + ctest_equal_int("should not have checked status by default", + ui_widget_has_status(cb, "checked"), 0); + + ui_checkbox_set_checked(cb, 1); + ctest_equal_int("checked status should be set after set_checked(1)", + ui_widget_has_status(cb, "checked"), 1); + + ui_checkbox_set_checked(cb, 0); + ctest_equal_int("checked status should be cleared after set_checked(0)", + ui_widget_has_status(cb, "checked"), 0); + + ui_checkbox_set_indeterminate(cb, 1); + ctest_equal_int( + "indeterminate status should be set after set_indeterminate(1)", + ui_widget_has_status(cb, "indeterminate"), 1); + + ui_widget_destroy(cb); +} + +void test_checkbox(void) +{ + lcui_init(); + + ctest_describe("checkbox checked roundtrip", test_checked_roundtrip); + ctest_describe("checkbox click toggles", test_click_toggles); + ctest_describe("checkbox click emits change", test_click_emits_change); + ctest_describe("checkbox disabled blocks toggle", + test_disabled_blocks_toggle); + ctest_describe("checkbox indeterminate roundtrip", + test_indeterminate_roundtrip); + ctest_describe("checkbox indeterminate click transitions to checked", + test_indeterminate_click_transitions_to_checked); + ctest_describe("checkbox status sync", test_status_sync); + + lcui_destroy(); +} diff --git a/tests/main.c b/tests/main.c index a4810513d..83bdd8077 100644 --- a/tests/main.c +++ b/tests/main.c @@ -27,6 +27,7 @@ extern void test_flex_layout(void); extern void test_scrollbar(void); extern void test_progress(void); extern void test_label(void); +extern void test_checkbox(void); static const ctest_suite_t suites[] = { { "settings", test_settings }, @@ -44,6 +45,7 @@ static const ctest_suite_t suites[] = { { "scrollbar", test_scrollbar }, { "progress", test_progress }, { "label", test_label }, + { "checkbox", test_checkbox }, { NULL, NULL } }; From 89f9f9366b85719a5ee24b14232fdafc10d3fcf9 Mon Sep 17 00:00:00 2001 From: Liu Date: Sun, 28 Jun 2026 23:40:28 +0800 Subject: [PATCH 53/66] docs(doc-viewer): add label and checkbox widget documentation --- docs/en/widgets/checkbox.mdx | 37 +++++ docs/en/widgets/label.mdx | 25 ++++ docs/examples/checkbox-basic-tsx/example.tsx | 11 ++ docs/examples/checkbox-basic-tsx/main.c | 11 ++ docs/examples/checkbox-basic-xml/main.c | 9 ++ docs/examples/checkbox-basic-xml/ui.xml | 7 + docs/examples/checkbox-basic/main.c | 17 +++ .../checkbox-disabled-tsx/example.tsx | 17 +++ docs/examples/checkbox-disabled-tsx/main.c | 11 ++ docs/examples/checkbox-disabled-xml/main.c | 8 ++ docs/examples/checkbox-disabled-xml/ui.xml | 15 ++ docs/examples/checkbox-disabled/main.c | 40 ++++++ docs/examples/label-basic-tsx/example.tsx | 10 ++ docs/examples/label-basic-tsx/main.c | 11 ++ docs/examples/label-basic-xml/main.c | 9 ++ docs/examples/label-basic-xml/ui.xml | 7 + docs/examples/label-basic/main.c | 17 +++ docs/sidebars.json | 2 + docs/widget-fields/checkbox.ts | 23 +++ docs/widget-fields/label.ts | 14 ++ docs/zh-CN/widgets/checkbox.mdx | 37 +++++ docs/zh-CN/widgets/label.mdx | 25 ++++ .../doc-viewer/app/components/sidebar.json | 2 + .../doc-viewer/app/en/widgets/anchor/page.tsx | 19 +-- .../doc-viewer/app/en/widgets/button/page.tsx | 13 -- .../doc-viewer/app/en/widgets/checkbox/page.c | 54 +++++++ .../doc-viewer/app/en/widgets/checkbox/page.h | 9 ++ .../app/en/widgets/checkbox/page.tsx | 63 +++++++++ .../doc-viewer/app/en/widgets/label/page.c | 53 +++++++ .../doc-viewer/app/en/widgets/label/page.h | 9 ++ .../doc-viewer/app/en/widgets/label/page.tsx | 48 +++++++ .../app/en/widgets/progress/page.tsx | 13 -- .../app/en/widgets/text-input/page.tsx | 41 ++---- .../doc-viewer/app/en/widgets/text/page.tsx | 23 +-- .../app/examples/checkbox-basic/index.c | 41 ++++++ .../app/examples/checkbox-basic/index.tsx | 97 +++++++++++++ .../app/examples/checkbox-disabled/index.c | 41 ++++++ .../app/examples/checkbox-disabled/index.tsx | 133 ++++++++++++++++++ .../app/examples/label-basic/index.c | 41 ++++++ .../app/examples/label-basic/index.tsx | 96 +++++++++++++ .../doc-viewer/app/widget-fields/checkbox.ts | 23 +++ .../doc-viewer/app/widget-fields/label.ts | 14 ++ .../app/zh-CN/widgets/anchor/page.tsx | 13 -- .../app/zh-CN/widgets/button/page.tsx | 13 -- .../app/zh-CN/widgets/checkbox/page.c | 57 ++++++++ .../app/zh-CN/widgets/checkbox/page.h | 9 ++ .../app/zh-CN/widgets/checkbox/page.tsx | 57 ++++++++ .../doc-viewer/app/zh-CN/widgets/label/page.c | 54 +++++++ .../doc-viewer/app/zh-CN/widgets/label/page.h | 9 ++ .../app/zh-CN/widgets/label/page.tsx | 48 +++++++ .../app/zh-CN/widgets/progress/page.tsx | 13 -- .../app/zh-CN/widgets/text-input/page.tsx | 13 -- .../app/zh-CN/widgets/text/page.tsx | 13 -- 53 files changed, 1343 insertions(+), 152 deletions(-) create mode 100644 docs/en/widgets/checkbox.mdx create mode 100644 docs/en/widgets/label.mdx create mode 100644 docs/examples/checkbox-basic-tsx/example.tsx create mode 100644 docs/examples/checkbox-basic-tsx/main.c create mode 100644 docs/examples/checkbox-basic-xml/main.c create mode 100644 docs/examples/checkbox-basic-xml/ui.xml create mode 100644 docs/examples/checkbox-basic/main.c create mode 100644 docs/examples/checkbox-disabled-tsx/example.tsx create mode 100644 docs/examples/checkbox-disabled-tsx/main.c create mode 100644 docs/examples/checkbox-disabled-xml/main.c create mode 100644 docs/examples/checkbox-disabled-xml/ui.xml create mode 100644 docs/examples/checkbox-disabled/main.c create mode 100644 docs/examples/label-basic-tsx/example.tsx create mode 100644 docs/examples/label-basic-tsx/main.c create mode 100644 docs/examples/label-basic-xml/main.c create mode 100644 docs/examples/label-basic-xml/ui.xml create mode 100644 docs/examples/label-basic/main.c create mode 100644 docs/widget-fields/checkbox.ts create mode 100644 docs/widget-fields/label.ts create mode 100644 docs/zh-CN/widgets/checkbox.mdx create mode 100644 docs/zh-CN/widgets/label.mdx create mode 100644 examples/doc-viewer/app/en/widgets/checkbox/page.c create mode 100644 examples/doc-viewer/app/en/widgets/checkbox/page.h create mode 100644 examples/doc-viewer/app/en/widgets/checkbox/page.tsx create mode 100644 examples/doc-viewer/app/en/widgets/label/page.c create mode 100644 examples/doc-viewer/app/en/widgets/label/page.h create mode 100644 examples/doc-viewer/app/en/widgets/label/page.tsx create mode 100644 examples/doc-viewer/app/examples/checkbox-basic/index.c create mode 100644 examples/doc-viewer/app/examples/checkbox-basic/index.tsx create mode 100644 examples/doc-viewer/app/examples/checkbox-disabled/index.c create mode 100644 examples/doc-viewer/app/examples/checkbox-disabled/index.tsx create mode 100644 examples/doc-viewer/app/examples/label-basic/index.c create mode 100644 examples/doc-viewer/app/examples/label-basic/index.tsx create mode 100644 examples/doc-viewer/app/widget-fields/checkbox.ts create mode 100644 examples/doc-viewer/app/widget-fields/label.ts create mode 100644 examples/doc-viewer/app/zh-CN/widgets/checkbox/page.c create mode 100644 examples/doc-viewer/app/zh-CN/widgets/checkbox/page.h create mode 100644 examples/doc-viewer/app/zh-CN/widgets/checkbox/page.tsx create mode 100644 examples/doc-viewer/app/zh-CN/widgets/label/page.c create mode 100644 examples/doc-viewer/app/zh-CN/widgets/label/page.h create mode 100644 examples/doc-viewer/app/zh-CN/widgets/label/page.tsx diff --git a/docs/en/widgets/checkbox.mdx b/docs/en/widgets/checkbox.mdx new file mode 100644 index 000000000..fec46c1c6 --- /dev/null +++ b/docs/en/widgets/checkbox.mdx @@ -0,0 +1,37 @@ +# Checkbox + +A control that allows the user to toggle between checked and not checked. + + + +## Use cases + +- **Suitable**: a single binary choice (accepting terms, toggling a subscription). +- **Suitable**: checkable options inside a form. +- **Not suitable**: mutually exclusive single-choice scenarios (use `radio-group`). + +## Usage + +```tsx +import { Checkbox } from "@lcui/react" +``` + +```tsx + +``` + +## Caveats + +:::caution +**indeterminate is a state, not a default value.** The half-selected state (`indeterminate="true"`) expresses the visual notion that some sub-items are selected (for example, a parent checkbox shown as indeterminate when only some of its children are checked). Clicking a checkbox in the indeterminate state transitions it to the checked state. +::: + +## Examples + +### Disabled + + + +## API Reference + + \ No newline at end of file diff --git a/docs/en/widgets/label.mdx b/docs/en/widgets/label.mdx new file mode 100644 index 000000000..b477af6b5 --- /dev/null +++ b/docs/en/widgets/label.mdx @@ -0,0 +1,25 @@ +# Label + +Renders an accessible label associated with controls. Click events are forwarded to the target widget referenced by the `for` attribute. + + + +## Use cases + +- **Suitable**: extending the clickable area of interactive widgets such as checkbox and text-input so that clicking the label text also triggers the widget. +- **Suitable**: associating text with a control for accessibility (a11y). +- **Not suitable**: purely decorative text display (use the `text` widget instead). + +## Usage + +```tsx +import { Label } from "@lcui/react" +``` + +```tsx + +``` + +## API Reference + + \ No newline at end of file diff --git a/docs/examples/checkbox-basic-tsx/example.tsx b/docs/examples/checkbox-basic-tsx/example.tsx new file mode 100644 index 000000000..e1d3bab5e --- /dev/null +++ b/docs/examples/checkbox-basic-tsx/example.tsx @@ -0,0 +1,11 @@ +import { Checkbox } from "@lcui/react"; +import { Label } from "@lcui/react"; + +export default function App() { + return ( + + + + + ); +} \ No newline at end of file diff --git a/docs/examples/checkbox-basic-tsx/main.c b/docs/examples/checkbox-basic-tsx/main.c new file mode 100644 index 000000000..c508b339d --- /dev/null +++ b/docs/examples/checkbox-basic-tsx/main.c @@ -0,0 +1,11 @@ +#include + +/* example.tsx is compiled to example.h by @lcui/cli */ +#include "example.h" + +int main(void) +{ + lcui_init(); + example_load(); + return lcui_main(); +} diff --git a/docs/examples/checkbox-basic-xml/main.c b/docs/examples/checkbox-basic-xml/main.c new file mode 100644 index 000000000..d8d8b6973 --- /dev/null +++ b/docs/examples/checkbox-basic-xml/main.c @@ -0,0 +1,9 @@ +#include +#include + +int main(void) +{ + lcui_init(); + ui_load_xml_file("ui.xml"); + return lcui_main(); +} diff --git a/docs/examples/checkbox-basic-xml/ui.xml b/docs/examples/checkbox-basic-xml/ui.xml new file mode 100644 index 000000000..59e41eb89 --- /dev/null +++ b/docs/examples/checkbox-basic-xml/ui.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/docs/examples/checkbox-basic/main.c b/docs/examples/checkbox-basic/main.c new file mode 100644 index 000000000..141317ecc --- /dev/null +++ b/docs/examples/checkbox-basic/main.c @@ -0,0 +1,17 @@ +#include + +void checkbox_basic_init(ui_widget_t *parent) +{ + ui_widget_t *cb = ui_create_checkbox(); + ui_widget_t *label = ui_create_label(); + ui_widget_t *box = ui_create_widget(NULL); + + ui_widget_set_id(cb, "terms"); + ui_widget_append(box, cb); + ui_widget_set_style_string(box, "display", "flex"); + ui_widget_set_style_string(box, "gap", "8px"); + ui_label_set_for(label, "terms"); + ui_text_set_content(label, "Accept terms and conditions"); + ui_widget_append(box, label); + ui_widget_append(parent, box); +} diff --git a/docs/examples/checkbox-disabled-tsx/example.tsx b/docs/examples/checkbox-disabled-tsx/example.tsx new file mode 100644 index 000000000..c61408621 --- /dev/null +++ b/docs/examples/checkbox-disabled-tsx/example.tsx @@ -0,0 +1,17 @@ +import { Checkbox } from "@lcui/react"; +import { Label } from "@lcui/react"; + +export default function App() { + return ( + +
    + + +
    +
    + + +
    +
    + ); +} \ No newline at end of file diff --git a/docs/examples/checkbox-disabled-tsx/main.c b/docs/examples/checkbox-disabled-tsx/main.c new file mode 100644 index 000000000..c508b339d --- /dev/null +++ b/docs/examples/checkbox-disabled-tsx/main.c @@ -0,0 +1,11 @@ +#include + +/* example.tsx is compiled to example.h by @lcui/cli */ +#include "example.h" + +int main(void) +{ + lcui_init(); + example_load(); + return lcui_main(); +} diff --git a/docs/examples/checkbox-disabled-xml/main.c b/docs/examples/checkbox-disabled-xml/main.c new file mode 100644 index 000000000..9f6a1e964 --- /dev/null +++ b/docs/examples/checkbox-disabled-xml/main.c @@ -0,0 +1,8 @@ +#include + +int main(void) +{ + lcui_init(); + ui_load_xml_file("ui.xml"); + return lcui_main(); +} diff --git a/docs/examples/checkbox-disabled-xml/ui.xml b/docs/examples/checkbox-disabled-xml/ui.xml new file mode 100644 index 000000000..98cee7cfe --- /dev/null +++ b/docs/examples/checkbox-disabled-xml/ui.xml @@ -0,0 +1,15 @@ + + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    \ No newline at end of file diff --git a/docs/examples/checkbox-disabled/main.c b/docs/examples/checkbox-disabled/main.c new file mode 100644 index 000000000..1865e1e2d --- /dev/null +++ b/docs/examples/checkbox-disabled/main.c @@ -0,0 +1,40 @@ +#include + +void checkbox_disabled_init(ui_widget_t *parent) +{ + ui_widget_t *box; + ui_widget_t *rows[2]; + ui_widget_t *boxes[2]; + ui_widget_t *labels[2]; + const char *ids[2] = { "d1", "d2" }; + const char *texts[2] = { "Disabled (pre-checked)", "Normal" }; + int i; + + box = ui_create_widget(NULL); + ui_widget_set_style_string(box, "display", "flex"); + ui_widget_set_style_string(box, "flex-direction", "column"); + ui_widget_set_style_string(box, "gap", "8px"); + + for (i = 0; i < 2; ++i) { + rows[i] = ui_create_widget(NULL); + ui_widget_set_style_string(rows[i], "display", "flex"); + ui_widget_set_style_string(rows[i], "align-items", "center"); + ui_widget_set_style_string(rows[i], "gap", "8px"); + + boxes[i] = ui_create_checkbox(); + ui_widget_set_id(boxes[i], ids[i]); + ui_widget_set_attr(boxes[i], "checked", "true"); + if (i == 0) { + ui_widget_set_disabled(boxes[i], true); + } + ui_widget_append(rows[i], boxes[i]); + + labels[i] = ui_create_label(); + ui_label_set_for(labels[i], ids[i]); + ui_text_set_content(labels[i], texts[i]); + ui_widget_append(rows[i], labels[i]); + + ui_widget_append(box, rows[i]); + } + ui_widget_append(parent, box); +} diff --git a/docs/examples/label-basic-tsx/example.tsx b/docs/examples/label-basic-tsx/example.tsx new file mode 100644 index 000000000..bfb657ae9 --- /dev/null +++ b/docs/examples/label-basic-tsx/example.tsx @@ -0,0 +1,10 @@ +import { Label, Checkbox } from "@lcui/react"; + +export default function App() { + return ( + + + + + ); +} \ No newline at end of file diff --git a/docs/examples/label-basic-tsx/main.c b/docs/examples/label-basic-tsx/main.c new file mode 100644 index 000000000..c508b339d --- /dev/null +++ b/docs/examples/label-basic-tsx/main.c @@ -0,0 +1,11 @@ +#include + +/* example.tsx is compiled to example.h by @lcui/cli */ +#include "example.h" + +int main(void) +{ + lcui_init(); + example_load(); + return lcui_main(); +} diff --git a/docs/examples/label-basic-xml/main.c b/docs/examples/label-basic-xml/main.c new file mode 100644 index 000000000..d8d8b6973 --- /dev/null +++ b/docs/examples/label-basic-xml/main.c @@ -0,0 +1,9 @@ +#include +#include + +int main(void) +{ + lcui_init(); + ui_load_xml_file("ui.xml"); + return lcui_main(); +} diff --git a/docs/examples/label-basic-xml/ui.xml b/docs/examples/label-basic-xml/ui.xml new file mode 100644 index 000000000..59e41eb89 --- /dev/null +++ b/docs/examples/label-basic-xml/ui.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/docs/examples/label-basic/main.c b/docs/examples/label-basic/main.c new file mode 100644 index 000000000..af868339a --- /dev/null +++ b/docs/examples/label-basic/main.c @@ -0,0 +1,17 @@ +#include + +void label_basic_init(ui_widget_t *parent) +{ + ui_widget_t *cb = ui_create_checkbox(); + ui_widget_t *label = ui_create_label(); + ui_widget_t *box = ui_create_widget(NULL); + + ui_widget_set_id(cb, "terms"); + ui_widget_append(box, cb); + ui_widget_set_style_string(box, "display", "flex"); + ui_widget_set_style_string(box, "gap", "8px"); + ui_label_set_for(label, "terms"); + ui_text_set_content(label, "Accept terms and conditions"); + ui_widget_append(box, label); + ui_widget_append(parent, box); +} diff --git a/docs/sidebars.json b/docs/sidebars.json index 23d598248..6569d8121 100644 --- a/docs/sidebars.json +++ b/docs/sidebars.json @@ -33,6 +33,8 @@ "items": [ { "slug": "anchor", "label": { "en": "Anchor", "zh-CN": "Anchor 锚点" } }, { "slug": "button", "label": { "en": "Button", "zh-CN": "Button 按钮" } }, + { "slug": "checkbox", "label": { "en": "Checkbox", "zh-CN": "Checkbox 复选框" } }, + { "slug": "label", "label": { "en": "Label", "zh-CN": "Label 标签" } }, { "slug": "progress", "label": { "en": "Progress", "zh-CN": "Progress 进度条" } }, { "slug": "scrollarea", "label": { "en": "ScrollArea", "zh-CN": "ScrollArea 滚动区域" } }, { "slug": "text", "label": { "en": "Text", "zh-CN": "Text 文本" } }, diff --git a/docs/widget-fields/checkbox.ts b/docs/widget-fields/checkbox.ts new file mode 100644 index 000000000..97633accd --- /dev/null +++ b/docs/widget-fields/checkbox.ts @@ -0,0 +1,23 @@ +import { widgetFields, FieldData } from "./widget"; + +export const checkboxFields: FieldData[] = [ + ...widgetFields, + { + name: "checked", + type: "boolean", + default: "false", + description: { + en: "Whether the checkbox is in the checked state.", + "zh-CN": "checkbox 是否处于勾选状态。", + }, + }, + { + name: "indeterminate", + type: "boolean", + default: "false", + description: { + en: "Whether the checkbox is in the indeterminate (mixed) state. A click transitions it to the checked state.", + "zh-CN": "checkbox 是否处于半选状态。点击会转为已选状态。", + }, + }, +]; \ No newline at end of file diff --git a/docs/widget-fields/label.ts b/docs/widget-fields/label.ts new file mode 100644 index 000000000..c46221b2d --- /dev/null +++ b/docs/widget-fields/label.ts @@ -0,0 +1,14 @@ +import { widgetFields, FieldData } from "./widget"; + +export const labelFields: FieldData[] = [ + ...widgetFields, + { + name: "for", + type: "string", + default: "-", + description: { + en: "ID of the target widget that this label is associated with. Clicks on the label forward a click event to the target.", + "zh-CN": "标签关联的目标部件 ID。点击标签时会把 click 事件转发给目标。", + }, + }, +]; \ No newline at end of file diff --git a/docs/zh-CN/widgets/checkbox.mdx b/docs/zh-CN/widgets/checkbox.mdx new file mode 100644 index 000000000..b349eb45f --- /dev/null +++ b/docs/zh-CN/widgets/checkbox.mdx @@ -0,0 +1,37 @@ +# Checkbox + +允许用户在已选和未选之间切换的控件。 + + + +## 适用场景 + +- **适用**:单条二元选择(同意条款、订阅开关) +- **适用**:表单中的勾选项 +- **不适用**:互斥的多选一场景(用 `radio-group`) + +## 用法 + +```tsx +import { Checkbox } from "@lcui/react" +``` + +```tsx + +``` + +## 注意事项 + +:::caution +**indeterminate 是状态,不是默认值**。半选态(`indeterminate="true"`)用于表达"子项部分被选中"的视觉状态(例如父级 checkbox 在部分子项被选时显示半选)。点击 indeterminate 状态的 checkbox 会转为 checked 状态。 +::: + +## 示例 + +### 禁用 + + + +## API 参考 + + \ No newline at end of file diff --git a/docs/zh-CN/widgets/label.mdx b/docs/zh-CN/widgets/label.mdx new file mode 100644 index 000000000..a931f3d30 --- /dev/null +++ b/docs/zh-CN/widgets/label.mdx @@ -0,0 +1,25 @@ +# Label + +渲染与控件关联的可访问标签,点击时将 click 事件转发到 `for` 指向的目标部件。 + + + +## 适用场景 + +- **适用**:为 checkbox、text-input 等可交互控件提供点击区域扩展(点击文字也能触发控件) +- **适用**:辅助功能(a11y)中将文本与控件关联 +- **不适用**:纯展示文本(用 `text` 部件) + +## 用法 + +```tsx +import { Label } from "@lcui/react" +``` + +```tsx + +``` + +## API 参考 + + \ No newline at end of file diff --git a/examples/doc-viewer/app/components/sidebar.json b/examples/doc-viewer/app/components/sidebar.json index 23d598248..6569d8121 100644 --- a/examples/doc-viewer/app/components/sidebar.json +++ b/examples/doc-viewer/app/components/sidebar.json @@ -33,6 +33,8 @@ "items": [ { "slug": "anchor", "label": { "en": "Anchor", "zh-CN": "Anchor 锚点" } }, { "slug": "button", "label": { "en": "Button", "zh-CN": "Button 按钮" } }, + { "slug": "checkbox", "label": { "en": "Checkbox", "zh-CN": "Checkbox 复选框" } }, + { "slug": "label", "label": { "en": "Label", "zh-CN": "Label 标签" } }, { "slug": "progress", "label": { "en": "Progress", "zh-CN": "Progress 进度条" } }, { "slug": "scrollarea", "label": { "en": "ScrollArea", "zh-CN": "ScrollArea 滚动区域" } }, { "slug": "text", "label": { "en": "Text", "zh-CN": "Text 文本" } }, diff --git a/examples/doc-viewer/app/en/widgets/anchor/page.tsx b/examples/doc-viewer/app/en/widgets/anchor/page.tsx index 861eda095..ba7b46e2f 100644 --- a/examples/doc-viewer/app/en/widgets/anchor/page.tsx +++ b/examples/doc-viewer/app/en/widgets/anchor/page.tsx @@ -27,23 +27,10 @@ export default function AnchorDocPage() {
    - -

    Composition

    -

    {`Use the following composition to build an [bgcolor=#eee] Anchor [/bgcolor]:`}

    - - - TEXT - - - - {`Anchor`} - - -

    API

    `ui_anchor_open`

    - + C @@ -61,7 +48,7 @@ export default function AnchorDocPage() {

    XML tag

    - + XML @@ -122,7 +109,7 @@ export default function AnchorDocPage() {

    Events

    `loaded.anchor`

    {`Fired on [bgcolor=#eee] ui_root() [/bgcolor] after a view has been loaded and injected:`}

    - + C diff --git a/examples/doc-viewer/app/en/widgets/button/page.tsx b/examples/doc-viewer/app/en/widgets/button/page.tsx index ccc5df2a8..fa159ef87 100644 --- a/examples/doc-viewer/app/en/widgets/button/page.tsx +++ b/examples/doc-viewer/app/en/widgets/button/page.tsx @@ -39,19 +39,6 @@ export default function ButtonDocPage() {
    - -

    Composition

    -

    {`Use the following composition to build a [bgcolor=#eee] Button [/bgcolor]:`}

    - - - TEXT - - - - {`Button`} - - -

    API Reference

    diff --git a/examples/doc-viewer/app/en/widgets/checkbox/page.c b/examples/doc-viewer/app/en/widgets/checkbox/page.c new file mode 100644 index 000000000..572117723 --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/checkbox/page.c @@ -0,0 +1,54 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_widgets_checkbox_page_react_t base; + // Add additional states to your component here + // ... +} en_widgets_checkbox_page_t; + +static void en_widgets_checkbox_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_widgets_checkbox_page_proto, + sizeof(en_widgets_checkbox_page_t)); + + en_widgets_checkbox_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_widgets_checkbox_page_update(w); +} + +static en_widgets_checkbox_page_t *en_widgets_checkbox_page_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, en_widgets_checkbox_page_proto); +} + +static void en_widgets_checkbox_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_widgets_checkbox_page_react_destroy(w); +} + +void en_widgets_checkbox_page_update(ui_widget_t *w) +{ + en_widgets_checkbox_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_widgets_checkbox_page(void) +{ + return ui_create_widget_with_prototype(en_widgets_checkbox_page_proto); +} + +void ui_register_en_widgets_checkbox_page(void) +{ + en_widgets_checkbox_page_init_prototype(); + en_widgets_checkbox_page_proto->init = en_widgets_checkbox_page_init; + en_widgets_checkbox_page_proto->destroy = + en_widgets_checkbox_page_destroy; +} diff --git a/examples/doc-viewer/app/en/widgets/checkbox/page.h b/examples/doc-viewer/app/en/widgets/checkbox/page.h new file mode 100644 index 000000000..24f8e86c9 --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/checkbox/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_widgets_checkbox_page(void); + +ui_widget_t *ui_create_en_widgets_checkbox_page(void); + +void en_widgets_checkbox_page_update(ui_widget_t *w); + +void ui_load_en_widgets_checkbox_page_resources(void); diff --git a/examples/doc-viewer/app/en/widgets/checkbox/page.tsx b/examples/doc-viewer/app/en/widgets/checkbox/page.tsx new file mode 100644 index 000000000..8096fa711 --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/checkbox/page.tsx @@ -0,0 +1,63 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; +import CheckboxBasicDemo from "../../../examples/checkbox-basic/index"; +import CheckboxDisabledDemo from "../../../examples/checkbox-disabled/index"; +import FieldTable from "../../../components/field-table"; +import { checkboxFields } from "../../../widget-fields/checkbox"; + +export default function CheckboxDocPage() { + return ( + +

    Checkbox

    +

    {`A control that allows the user to toggle between checked and not checked.`}

    + + +

    Use cases

    +
      +
    • {`[b]Suitable[/b]: a single binary choice (accepting terms, toggling a subscription).`}
    • +
    • {`[b]Suitable[/b]: checkable options inside a form.`}
    • +
    • {`[b]Not suitable[/b]: mutually exclusive single-choice scenarios (use [bgcolor=#eee] radio-group [/bgcolor]).`}
    • +
    +
    + +

    Usage

    + + + TypeScript + + + + {`[color=#cf222e]import[/color] { [color=#8250df]Checkbox[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color]`} + + + + + TypeScript + + + + {`<[color=#8250df]Checkbox[/color] />`} + + +
    + +

    Caveats

    + + 警告 + +

    {`[b]indeterminate is a state, not a default value.[/b] The half-selected state ([bgcolor=#eee] indeterminate="true" [/bgcolor]) expresses the visual notion that some sub-items are selected (for example, a parent checkbox shown as indeterminate when only some of its children are checked). Clicking a checkbox in the indeterminate state transitions it to the checked state.`}

    +
    +
    +
    + +

    Examples

    +

    Disabled

    + +
    + +

    API Reference

    + +
    +
    + ); +} diff --git a/examples/doc-viewer/app/en/widgets/label/page.c b/examples/doc-viewer/app/en/widgets/label/page.c new file mode 100644 index 000000000..e9c37fd8c --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/label/page.c @@ -0,0 +1,53 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_widgets_label_page_react_t base; + // Add additional states to your component here + // ... +} en_widgets_label_page_t; + +static void en_widgets_label_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_widgets_label_page_proto, + sizeof(en_widgets_label_page_t)); + + en_widgets_label_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_widgets_label_page_update(w); +} + +static en_widgets_label_page_t *en_widgets_label_page_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, en_widgets_label_page_proto); +} + +static void en_widgets_label_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_widgets_label_page_react_destroy(w); +} + +void en_widgets_label_page_update(ui_widget_t *w) +{ + en_widgets_label_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_widgets_label_page(void) +{ + return ui_create_widget_with_prototype(en_widgets_label_page_proto); +} + +void ui_register_en_widgets_label_page(void) +{ + en_widgets_label_page_init_prototype(); + en_widgets_label_page_proto->init = en_widgets_label_page_init; + en_widgets_label_page_proto->destroy = en_widgets_label_page_destroy; +} diff --git a/examples/doc-viewer/app/en/widgets/label/page.h b/examples/doc-viewer/app/en/widgets/label/page.h new file mode 100644 index 000000000..0361a0cd5 --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/label/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_widgets_label_page(void); + +ui_widget_t *ui_create_en_widgets_label_page(void); + +void en_widgets_label_page_update(ui_widget_t *w); + +void ui_load_en_widgets_label_page_resources(void); diff --git a/examples/doc-viewer/app/en/widgets/label/page.tsx b/examples/doc-viewer/app/en/widgets/label/page.tsx new file mode 100644 index 000000000..8cdf16548 --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/label/page.tsx @@ -0,0 +1,48 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; +import LabelBasicDemo from "../../../examples/label-basic/index"; +import FieldTable from "../../../components/field-table"; +import { labelFields } from "../../../widget-fields/label"; + +export default function LabelDocPage() { + return ( + +

    Label

    +

    {`Renders an accessible label associated with controls. Click events are forwarded to the target widget referenced by the [bgcolor=#eee] for [/bgcolor] attribute.`}

    + + +

    Use cases

    +
      +
    • {`[b]Suitable[/b]: extending the clickable area of interactive widgets such as checkbox and text-input so that clicking the label text also triggers the widget.`}
    • +
    • {`[b]Suitable[/b]: associating text with a control for accessibility (a11y).`}
    • +
    • {`[b]Not suitable[/b]: purely decorative text display (use the [bgcolor=#eee] text [/bgcolor] widget instead).`}
    • +
    +
    + +

    Usage

    + + + TypeScript + + + + {`[color=#cf222e]import[/color] { [color=#8250df]Label[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color]`} + + + + + TypeScript + + + + {`<[color=#8250df]Label[/color] [color=#cf222e]for[/color]=[color=#0a3069]"agree"[/color]>I agree`} + + +
    + +

    API Reference

    + +
    +
    + ); +} diff --git a/examples/doc-viewer/app/en/widgets/progress/page.tsx b/examples/doc-viewer/app/en/widgets/progress/page.tsx index 78b1009bc..a04fb97a9 100644 --- a/examples/doc-viewer/app/en/widgets/progress/page.tsx +++ b/examples/doc-viewer/app/en/widgets/progress/page.tsx @@ -39,19 +39,6 @@ export default function ProgressDocPage() {
    - -

    Composition

    -

    {`Use the following composition to build a [bgcolor=#eee] Progress [/bgcolor]:`}

    - - - TEXT - - - - {`Progress`} - - -

    API Reference

    diff --git a/examples/doc-viewer/app/en/widgets/text-input/page.tsx b/examples/doc-viewer/app/en/widgets/text-input/page.tsx index 1998ef14c..e8f1ce573 100644 --- a/examples/doc-viewer/app/en/widgets/text-input/page.tsx +++ b/examples/doc-viewer/app/en/widgets/text-input/page.tsx @@ -36,23 +36,10 @@ export default function TextInputDocPage() {
    - -

    Composition

    -

    {`Use the following composition to build a [bgcolor=#eee] TextInput [/bgcolor]:`}

    - - - TEXT - - - - {`TextInput`} - - -

    API

    `ui_textinput_set_text`

    - + C @@ -63,7 +50,7 @@ export default function TextInputDocPage() {

    {`Sets the input value from a UTF-8 string.`}

    `ui_textinput_set_text_w`

    - + C @@ -74,7 +61,7 @@ export default function TextInputDocPage() {

    {`Sets the input value from a wide character string.`}

    `ui_textinput_get_text_w`

    - + C @@ -86,7 +73,7 @@ export default function TextInputDocPage() {

    {`Reads the current input value. Returns the number of characters written.`}

    `ui_textinput_get_text_length`

    - + C @@ -97,7 +84,7 @@ export default function TextInputDocPage() {

    {`Returns the current text length in characters.`}

    `ui_textinput_clear_text`

    - + C @@ -108,7 +95,7 @@ export default function TextInputDocPage() {

    {`Clears all text from the input.`}

    `ui_textinput_set_placeholder`

    - + C @@ -119,7 +106,7 @@ export default function TextInputDocPage() {

    {`Sets the placeholder text shown when the input is empty.`}

    `ui_textinput_set_placeholder_w`

    - + C @@ -130,7 +117,7 @@ export default function TextInputDocPage() {

    {`Sets the placeholder text from a wide character string.`}

    `ui_textinput_set_password_char`

    - + C @@ -141,7 +128,7 @@ export default function TextInputDocPage() {

    {`Masks the input with the given character (e.g. [bgcolor=#eee] L'*' [/bgcolor] for password fields).`}

    `ui_textinput_enable_multiline`

    - + C @@ -152,7 +139,7 @@ export default function TextInputDocPage() {

    {`Enables or disables multiline input mode.`}

    `ui_textinput_enable_style_tag`

    - + C @@ -163,7 +150,7 @@ export default function TextInputDocPage() {

    {`Enables or disables inline style tag parsing in the input.`}

    `ui_textinput_append_text_w`

    - + C @@ -174,7 +161,7 @@ export default function TextInputDocPage() {

    {`Appends text at the end of the current content.`}

    `ui_textinput_insert_text_w`

    - + C @@ -185,7 +172,7 @@ export default function TextInputDocPage() {

    {`Inserts text at the current caret position.`}

    `ui_textinput_set_caret_blink`

    - + C @@ -198,7 +185,7 @@ export default function TextInputDocPage() {

    XML tag

    - + XML diff --git a/examples/doc-viewer/app/en/widgets/text/page.tsx b/examples/doc-viewer/app/en/widgets/text/page.tsx index 779931129..3b39ae307 100644 --- a/examples/doc-viewer/app/en/widgets/text/page.tsx +++ b/examples/doc-viewer/app/en/widgets/text/page.tsx @@ -36,23 +36,10 @@ export default function TextDocPage() {
    - -

    Composition

    -

    {`Use the following composition to build a [bgcolor=#eee] Text [/bgcolor]:`}

    - - - TEXT - - - - {`Text`} - - -

    API

    `ui_text_set_content`

    - + C @@ -63,7 +50,7 @@ export default function TextDocPage() {

    {`Sets the text content from a UTF-8 string. Supports inline style tags.`}

    `ui_text_set_content_w`

    - + C @@ -74,7 +61,7 @@ export default function TextDocPage() {

    {`Sets the text content from a wide character string.`}

    `ui_text_get_content_w`

    - + C @@ -85,7 +72,7 @@ export default function TextDocPage() {

    {`Reads the current text content into [bgcolor=#eee] buf [/bgcolor] (up to [bgcolor=#eee] size [/bgcolor] wide characters). Returns the number of characters written.`}

    `ui_text_set_multiline`

    - + C @@ -98,7 +85,7 @@ export default function TextDocPage() {

    XML tag

    - + XML diff --git a/examples/doc-viewer/app/examples/checkbox-basic/index.c b/examples/doc-viewer/app/examples/checkbox-basic/index.c new file mode 100644 index 000000000..c9fbe1303 --- /dev/null +++ b/examples/doc-viewer/app/examples/checkbox-basic/index.c @@ -0,0 +1,41 @@ +#include "index.tsx.h" +#include "index.h" + +#include "../../../../../docs/examples/checkbox-basic/main.c" + +typedef struct { + checkbox_basic_demo_react_t base; +} checkbox_basic_demo_t; + +void checkbox_basic_demo_update(ui_widget_t *w) +{ + checkbox_basic_demo_react_update(w); +} + +static void checkbox_basic_demo_init(ui_widget_t *w) +{ + checkbox_basic_demo_t *_that = ui_widget_add_data( + w, checkbox_basic_demo_proto, sizeof(checkbox_basic_demo_t)); + checkbox_basic_demo_proto->proto->init(w); + checkbox_basic_demo_react_init(w); + checkbox_basic_init(_that->base.refs.preview); + checkbox_basic_demo_update(w); +} + +static void checkbox_basic_demo_destroy(ui_widget_t *w) +{ + checkbox_basic_demo_proto->proto->destroy(w); + checkbox_basic_demo_react_destroy(w); +} + +ui_widget_t *ui_create_checkbox_basic_demo(void) +{ + return ui_create_widget_with_prototype(checkbox_basic_demo_proto); +} + +void ui_register_checkbox_basic_demo(void) +{ + checkbox_basic_demo_init_prototype(); + checkbox_basic_demo_proto->init = checkbox_basic_demo_init; + checkbox_basic_demo_proto->destroy = checkbox_basic_demo_destroy; +} diff --git a/examples/doc-viewer/app/examples/checkbox-basic/index.tsx b/examples/doc-viewer/app/examples/checkbox-basic/index.tsx new file mode 100644 index 000000000..5e7dd23b2 --- /dev/null +++ b/examples/doc-viewer/app/examples/checkbox-basic/index.tsx @@ -0,0 +1,97 @@ +import { Text, Widget } from "@lcui/react"; +import DemoProvider from "../../components/demo-provider"; +import CodeBlockCopy from "../../components/code-block-copy"; + +export default function CheckboxBasicDemo() { + return ( + + + + + + example.tsx + main.c + main.c + ui.xml + main.c + + + TSX + C + XML + + + + + {`[color=#cf222e]import[/color] { [color=#8250df]Checkbox[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {`[color=#cf222e]import[/color] { [color=#8250df]Label[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]Widget[/color] [color=#0550ae]className[/color]=[color=#0a3069]"flex gap-2"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]Checkbox[/color] [color=#0550ae]id[/color]=[color=#0a3069]"terms"[/color] />[/color]`} + {`      [color=#116329]<[color=#0550ae]Label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"terms"[/color]>[/color]Accept terms and conditions[color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#6e7781]/* example.tsx is compiled to example.h by @lcui/cli */[/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069]"example.h"[/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        example_load();`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]void[/color] [color=#8250df]checkbox_basic_init[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *parent)[/color]`} + {`{`} + {`        [color=#953800]ui_widget_t[/color] *cb = ui_create_checkbox();`} + {`        [color=#953800]ui_widget_t[/color] *label = ui_create_label();`} + {`        [color=#953800]ui_widget_t[/color] *box = ui_create_widget([color=#0550ae]NULL[/color]);`} + {` `} + {`        ui_widget_set_id(cb, [color=#0a3069]"terms"[/color]);`} + {`        ui_widget_append(box, cb);`} + {`        ui_widget_set_style_string(box, [color=#0a3069]"display"[/color], [color=#0a3069]"flex"[/color]);`} + {`        ui_widget_set_style_string(box, [color=#0a3069]"gap"[/color], [color=#0a3069]"8px"[/color]);`} + {`        ui_label_set_for(label, [color=#0a3069]"terms"[/color]);`} + {`        ui_text_set_content(label, [color=#0a3069]"Accept terms and conditions"[/color]);`} + {`        ui_widget_append(box, label);`} + {`        ui_widget_append(parent, box);`} + {`}`} + + + + {`[color=#6e7781][/color]`} + {`[color=#116329]<[color=#0550ae]lcui-app[/color]>[/color]`} + {`  [color=#116329]<[color=#0550ae]ui[/color]>[/color]`} + {`    [color=#116329]<[color=#0550ae]checkbox[/color] [color=#0550ae]id[/color]=[color=#0a3069]"terms"[/color] />[/color]`} + {`    [color=#116329]<[color=#0550ae]label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"terms"[/color]>[/color]Accept terms and conditions[color=#116329][/color]`} + {`  [color=#116329][/color]`} + {`[color=#116329][/color]`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        ui_load_xml_file([color=#0a3069]"ui.xml"[/color]);`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + ); +} diff --git a/examples/doc-viewer/app/examples/checkbox-disabled/index.c b/examples/doc-viewer/app/examples/checkbox-disabled/index.c new file mode 100644 index 000000000..5a65fd71c --- /dev/null +++ b/examples/doc-viewer/app/examples/checkbox-disabled/index.c @@ -0,0 +1,41 @@ +#include "index.tsx.h" +#include "index.h" + +#include "../../../../../docs/examples/checkbox-disabled/main.c" + +typedef struct { + checkbox_disabled_demo_react_t base; +} checkbox_disabled_demo_t; + +static void checkbox_disabled_demo_init(ui_widget_t *w) +{ + checkbox_disabled_demo_t *_that = ui_widget_add_data( + w, checkbox_disabled_demo_proto, sizeof(checkbox_disabled_demo_t)); + checkbox_disabled_demo_proto->proto->init(w); + checkbox_disabled_demo_react_init(w); + checkbox_disabled_init(_that->base.refs.preview); + checkbox_disabled_demo_update(w); +} + +static void checkbox_disabled_demo_destroy(ui_widget_t *w) +{ + checkbox_disabled_demo_proto->proto->destroy(w); + checkbox_disabled_demo_react_destroy(w); +} + +void checkbox_disabled_demo_update(ui_widget_t *w) +{ + checkbox_disabled_demo_react_update(w); +} + +ui_widget_t *ui_create_checkbox_disabled_demo(void) +{ + return ui_create_widget_with_prototype(checkbox_disabled_demo_proto); +} + +void ui_register_checkbox_disabled_demo(void) +{ + checkbox_disabled_demo_init_prototype(); + checkbox_disabled_demo_proto->init = checkbox_disabled_demo_init; + checkbox_disabled_demo_proto->destroy = checkbox_disabled_demo_destroy; +} diff --git a/examples/doc-viewer/app/examples/checkbox-disabled/index.tsx b/examples/doc-viewer/app/examples/checkbox-disabled/index.tsx new file mode 100644 index 000000000..9467b919d --- /dev/null +++ b/examples/doc-viewer/app/examples/checkbox-disabled/index.tsx @@ -0,0 +1,133 @@ +import { Text, Widget } from "@lcui/react"; +import DemoProvider from "../../components/demo-provider"; +import CodeBlockCopy from "../../components/code-block-copy"; + +export default function CheckboxDisabledDemo() { + return ( + + + + + + example.tsx + main.c + main.c + ui.xml + main.c + + + TSX + C + XML + + + + + {`[color=#cf222e]import[/color] { [color=#8250df]Checkbox[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {`[color=#cf222e]import[/color] { [color=#8250df]Label[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]Widget[/color] [color=#0550ae]className[/color]=[color=#0a3069]"flex flex-col gap-2"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]className[/color]=[color=#0a3069]"flex items-center gap-2"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]Checkbox[/color] [color=#0550ae]id[/color]=[color=#0a3069]"d1"[/color] [color=#0550ae]disabled[/color]=[color=#0a3069]{true}[/color] [color=#0550ae]checked[/color]=[color=#0a3069]{true}[/color] />[/color]`} + {`        [color=#116329]<[color=#0550ae]Label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"d1"[/color]>[/color]Disabled (pre-checked)[color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]className[/color]=[color=#0a3069]"flex items-center gap-2"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]Checkbox[/color] [color=#0550ae]id[/color]=[color=#0a3069]"d2"[/color] [color=#0550ae]checked[/color]=[color=#0a3069]{true}[/color] />[/color]`} + {`        [color=#116329]<[color=#0550ae]Label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"d2"[/color]>[/color]Normal[color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#6e7781]/* example.tsx is compiled to example.h by @lcui/cli */[/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069]"example.h"[/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        example_load();`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]void[/color] [color=#8250df]checkbox_disabled_init[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *parent)[/color]`} + {`{`} + {`        [color=#953800]ui_widget_t[/color] *box;`} + {`        [color=#953800]ui_widget_t[/color] *rows\\[[color=#0550ae]2[/color]];`} + {`        [color=#953800]ui_widget_t[/color] *boxes\\[[color=#0550ae]2[/color]];`} + {`        [color=#953800]ui_widget_t[/color] *labels\\[[color=#0550ae]2[/color]];`} + {`        [color=#953800]const[/color] [color=#953800]char[/color] *ids\\[[color=#0550ae]2[/color]] = { [color=#0a3069]"d1"[/color], [color=#0a3069]"d2"[/color] };`} + {`        [color=#953800]const[/color] [color=#953800]char[/color] *texts\\[[color=#0550ae]2[/color]] = { [color=#0a3069]"Disabled (pre-checked)"[/color], [color=#0a3069]"Normal"[/color] };`} + {`        [color=#953800]int[/color] i;`} + {` `} + {`        box = ui_create_widget([color=#0550ae]NULL[/color]);`} + {`        ui_widget_set_style_string(box, [color=#0a3069]"display"[/color], [color=#0a3069]"flex"[/color]);`} + {`        ui_widget_set_style_string(box, [color=#0a3069]"flex-direction"[/color], [color=#0a3069]"column"[/color]);`} + {`        ui_widget_set_style_string(box, [color=#0a3069]"gap"[/color], [color=#0a3069]"8px"[/color]);`} + {` `} + {`        [color=#cf222e]for[/color] (i = [color=#0550ae]0[/color]; i < [color=#0550ae]2[/color]; ++i) {`} + {`                rows\\[i] = ui_create_widget([color=#0550ae]NULL[/color]);`} + {`                ui_widget_set_style_string(rows\\[i], [color=#0a3069]"display"[/color], [color=#0a3069]"flex"[/color]);`} + {`                ui_widget_set_style_string(rows\\[i], [color=#0a3069]"align-items"[/color], [color=#0a3069]"center"[/color]);`} + {`                ui_widget_set_style_string(rows\\[i], [color=#0a3069]"gap"[/color], [color=#0a3069]"8px"[/color]);`} + {` `} + {`                boxes\\[i] = ui_create_checkbox();`} + {`                ui_widget_set_id(boxes\\[i], ids\\[i]);`} + {`                ui_widget_set_attr(boxes\\[i], [color=#0a3069]"checked"[/color], [color=#0a3069]"true"[/color]);`} + {`                [color=#cf222e]if[/color] (i == [color=#0550ae]0[/color]) {`} + {`                        ui_widget_set_disabled(boxes\\[i], [color=#0550ae]true[/color]);`} + {`                }`} + {`                ui_widget_append(rows\\[i], boxes\\[i]);`} + {` `} + {`                labels\\[i] = ui_create_label();`} + {`                ui_label_set_for(labels\\[i], ids\\[i]);`} + {`                ui_text_set_content(labels\\[i], texts\\[i]);`} + {`                ui_widget_append(rows\\[i], labels\\[i]);`} + {` `} + {`                ui_widget_append(box, rows\\[i]);`} + {`        }`} + {`        ui_widget_append(parent, box);`} + {`}`} + + + + {`[color=#6e7781][/color]`} + {`[color=#116329]<[color=#0550ae]lcui-app[/color]>[/color]`} + {`  [color=#116329]<[color=#0550ae]ui[/color]>[/color]`} + {`    [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]style[/color]=[color=#0a3069]"display:flex; flex-direction:column; gap:8px"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]style[/color]=[color=#0a3069]"display:flex; align-items:center; gap:8px"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]checkbox[/color] [color=#0550ae]id[/color]=[color=#0a3069]"d1"[/color] [color=#0550ae]disabled[/color]=[color=#0a3069]"true"[/color] [color=#0550ae]checked[/color]=[color=#0a3069]"true"[/color] />[/color]`} + {`        [color=#116329]<[color=#0550ae]label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"d1"[/color]>[/color]Disabled (pre-checked)[color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]style[/color]=[color=#0a3069]"display:flex; align-items:center; gap:8px"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]checkbox[/color] [color=#0550ae]id[/color]=[color=#0a3069]"d2"[/color] [color=#0550ae]checked[/color]=[color=#0a3069]"true"[/color] />[/color]`} + {`        [color=#116329]<[color=#0550ae]label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"d2"[/color]>[/color]Normal[color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  [color=#116329][/color]`} + {`[color=#116329][/color]`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        ui_load_xml_file([color=#0a3069]"ui.xml"[/color]);`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + ); +} diff --git a/examples/doc-viewer/app/examples/label-basic/index.c b/examples/doc-viewer/app/examples/label-basic/index.c new file mode 100644 index 000000000..ac75ab078 --- /dev/null +++ b/examples/doc-viewer/app/examples/label-basic/index.c @@ -0,0 +1,41 @@ +#include "index.tsx.h" +#include "index.h" + +#include "../../../../../docs/examples/label-basic/main.c" + +typedef struct { + label_basic_demo_react_t base; +} label_basic_demo_t; + +void label_basic_demo_update(ui_widget_t *w) +{ + label_basic_demo_react_update(w); +} + +static void label_basic_demo_init(ui_widget_t *w) +{ + label_basic_demo_t *_that = ui_widget_add_data( + w, label_basic_demo_proto, sizeof(label_basic_demo_t)); + label_basic_demo_proto->proto->init(w); + label_basic_demo_react_init(w); + label_basic_init(_that->base.refs.preview); + label_basic_demo_update(w); +} + +static void label_basic_demo_destroy(ui_widget_t *w) +{ + label_basic_demo_proto->proto->destroy(w); + label_basic_demo_react_destroy(w); +} + +ui_widget_t *ui_create_label_basic_demo(void) +{ + return ui_create_widget_with_prototype(label_basic_demo_proto); +} + +void ui_register_label_basic_demo(void) +{ + label_basic_demo_init_prototype(); + label_basic_demo_proto->init = label_basic_demo_init; + label_basic_demo_proto->destroy = label_basic_demo_destroy; +} diff --git a/examples/doc-viewer/app/examples/label-basic/index.tsx b/examples/doc-viewer/app/examples/label-basic/index.tsx new file mode 100644 index 000000000..934a1c3b8 --- /dev/null +++ b/examples/doc-viewer/app/examples/label-basic/index.tsx @@ -0,0 +1,96 @@ +import { Text, Widget } from "@lcui/react"; +import DemoProvider from "../../components/demo-provider"; +import CodeBlockCopy from "../../components/code-block-copy"; + +export default function LabelBasicDemo() { + return ( + + + + + + example.tsx + main.c + main.c + ui.xml + main.c + + + TSX + C + XML + + + + + {`[color=#cf222e]import[/color] { [color=#8250df]Label[/color], [color=#8250df]Checkbox[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]Widget[/color] [color=#0550ae]className[/color]=[color=#0a3069]"flex gap-2"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]Checkbox[/color] [color=#0550ae]id[/color]=[color=#0a3069]"terms"[/color] />[/color]`} + {`      [color=#116329]<[color=#0550ae]Label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"terms"[/color]>[/color]Accept terms and conditions[color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#6e7781]/* example.tsx is compiled to example.h by @lcui/cli */[/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069]"example.h"[/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        example_load();`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]void[/color] [color=#8250df]label_basic_init[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *parent)[/color]`} + {`{`} + {`        [color=#953800]ui_widget_t[/color] *cb = ui_create_checkbox();`} + {`        [color=#953800]ui_widget_t[/color] *label = ui_create_label();`} + {`        [color=#953800]ui_widget_t[/color] *box = ui_create_widget([color=#0550ae]NULL[/color]);`} + {` `} + {`        ui_widget_set_id(cb, [color=#0a3069]"terms"[/color]);`} + {`        ui_widget_append(box, cb);`} + {`        ui_widget_set_style_string(box, [color=#0a3069]"display"[/color], [color=#0a3069]"flex"[/color]);`} + {`        ui_widget_set_style_string(box, [color=#0a3069]"gap"[/color], [color=#0a3069]"8px"[/color]);`} + {`        ui_label_set_for(label, [color=#0a3069]"terms"[/color]);`} + {`        ui_text_set_content(label, [color=#0a3069]"Accept terms and conditions"[/color]);`} + {`        ui_widget_append(box, label);`} + {`        ui_widget_append(parent, box);`} + {`}`} + + + + {`[color=#6e7781][/color]`} + {`[color=#116329]<[color=#0550ae]lcui-app[/color]>[/color]`} + {`  [color=#116329]<[color=#0550ae]ui[/color]>[/color]`} + {`    [color=#116329]<[color=#0550ae]checkbox[/color] [color=#0550ae]id[/color]=[color=#0a3069]"terms"[/color] />[/color]`} + {`    [color=#116329]<[color=#0550ae]label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"terms"[/color]>[/color]Accept terms and conditions[color=#116329][/color]`} + {`  [color=#116329][/color]`} + {`[color=#116329][/color]`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        ui_load_xml_file([color=#0a3069]"ui.xml"[/color]);`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + ); +} diff --git a/examples/doc-viewer/app/widget-fields/checkbox.ts b/examples/doc-viewer/app/widget-fields/checkbox.ts new file mode 100644 index 000000000..97633accd --- /dev/null +++ b/examples/doc-viewer/app/widget-fields/checkbox.ts @@ -0,0 +1,23 @@ +import { widgetFields, FieldData } from "./widget"; + +export const checkboxFields: FieldData[] = [ + ...widgetFields, + { + name: "checked", + type: "boolean", + default: "false", + description: { + en: "Whether the checkbox is in the checked state.", + "zh-CN": "checkbox 是否处于勾选状态。", + }, + }, + { + name: "indeterminate", + type: "boolean", + default: "false", + description: { + en: "Whether the checkbox is in the indeterminate (mixed) state. A click transitions it to the checked state.", + "zh-CN": "checkbox 是否处于半选状态。点击会转为已选状态。", + }, + }, +]; \ No newline at end of file diff --git a/examples/doc-viewer/app/widget-fields/label.ts b/examples/doc-viewer/app/widget-fields/label.ts new file mode 100644 index 000000000..c46221b2d --- /dev/null +++ b/examples/doc-viewer/app/widget-fields/label.ts @@ -0,0 +1,14 @@ +import { widgetFields, FieldData } from "./widget"; + +export const labelFields: FieldData[] = [ + ...widgetFields, + { + name: "for", + type: "string", + default: "-", + description: { + en: "ID of the target widget that this label is associated with. Clicks on the label forward a click event to the target.", + "zh-CN": "标签关联的目标部件 ID。点击标签时会把 click 事件转发给目标。", + }, + }, +]; \ No newline at end of file diff --git a/examples/doc-viewer/app/zh-CN/widgets/anchor/page.tsx b/examples/doc-viewer/app/zh-CN/widgets/anchor/page.tsx index ea8057667..eb08aa57f 100644 --- a/examples/doc-viewer/app/zh-CN/widgets/anchor/page.tsx +++ b/examples/doc-viewer/app/zh-CN/widgets/anchor/page.tsx @@ -29,19 +29,6 @@ export default function AnchorDocPage() {
    - -

    组合

    -

    {`使用以下组合来构建 [bgcolor=#eee] Anchor [/bgcolor]:`}

    - - - TEXT - - - - {`Anchor`} - - -

    API 参考

    diff --git a/examples/doc-viewer/app/zh-CN/widgets/button/page.tsx b/examples/doc-viewer/app/zh-CN/widgets/button/page.tsx index 038ebb16b..19a6f87eb 100644 --- a/examples/doc-viewer/app/zh-CN/widgets/button/page.tsx +++ b/examples/doc-viewer/app/zh-CN/widgets/button/page.tsx @@ -39,19 +39,6 @@ export default function ButtonDocPage() {
    - -

    组合

    -

    {`使用以下组合来构建 [bgcolor=#eee] Button [/bgcolor]:`}

    - - - TEXT - - - - {`Button`} - - -

    API 参考

    diff --git a/examples/doc-viewer/app/zh-CN/widgets/checkbox/page.c b/examples/doc-viewer/app/zh-CN/widgets/checkbox/page.c new file mode 100644 index 000000000..897846d53 --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/widgets/checkbox/page.c @@ -0,0 +1,57 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + zh_cn_widgets_checkbox_page_react_t base; + // Add additional states to your component here + // ... +} zh_cn_widgets_checkbox_page_t; + +static void zh_cn_widgets_checkbox_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, zh_cn_widgets_checkbox_page_proto, + sizeof(zh_cn_widgets_checkbox_page_t)); + + zh_cn_widgets_checkbox_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + zh_cn_widgets_checkbox_page_update(w); +} + +static zh_cn_widgets_checkbox_page_t *zh_cn_widgets_checkbox_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, zh_cn_widgets_checkbox_page_proto); +} + +static void zh_cn_widgets_checkbox_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + zh_cn_widgets_checkbox_page_react_destroy(w); +} + +void zh_cn_widgets_checkbox_page_update(ui_widget_t *w) +{ + zh_cn_widgets_checkbox_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_zh_cn_widgets_checkbox_page(void) +{ + return ui_create_widget_with_prototype( + zh_cn_widgets_checkbox_page_proto); +} + +void ui_register_zh_cn_widgets_checkbox_page(void) +{ + zh_cn_widgets_checkbox_page_init_prototype(); + zh_cn_widgets_checkbox_page_proto->init = + zh_cn_widgets_checkbox_page_init; + zh_cn_widgets_checkbox_page_proto->destroy = + zh_cn_widgets_checkbox_page_destroy; +} diff --git a/examples/doc-viewer/app/zh-CN/widgets/checkbox/page.h b/examples/doc-viewer/app/zh-CN/widgets/checkbox/page.h new file mode 100644 index 000000000..079816c07 --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/widgets/checkbox/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_zh_cn_widgets_checkbox_page(void); + +ui_widget_t *ui_create_zh_cn_widgets_checkbox_page(void); + +void zh_cn_widgets_checkbox_page_update(ui_widget_t *w); + +void ui_load_zh_cn_widgets_checkbox_page_resources(void); diff --git a/examples/doc-viewer/app/zh-CN/widgets/checkbox/page.tsx b/examples/doc-viewer/app/zh-CN/widgets/checkbox/page.tsx new file mode 100644 index 000000000..8d6946e2c --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/widgets/checkbox/page.tsx @@ -0,0 +1,57 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; +import CheckboxBasicDemo from "../../../examples/checkbox-basic/index"; +import FieldTable from "../../../components/field-table"; +import { checkboxFields } from "../../../widget-fields/checkbox"; + +export default function CheckboxDocPage() { + return ( + +

    Checkbox

    +

    {`允许用户在已选和未选之间切换的控件。`}

    + + +

    适用场景

    +
      +
    • {`[b]适用[/b]:单条二元选择(同意条款、订阅开关)`}
    • +
    • {`[b]适用[/b]:表单中的勾选项`}
    • +
    • {`[b]不适用[/b]:互斥的多选一场景(用 [bgcolor=#eee] radio-group [/bgcolor])`}
    • +
    +
    + +

    用法

    + + + TypeScript + + + + {`[color=#cf222e]import[/color] { [color=#8250df]Checkbox[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color]`} + + + + + TypeScript + + + + {`<[color=#8250df]Checkbox[/color] />`} + + +
    + +

    注意事项

    + + 警告 + +

    {`[b]indeterminate 是状态,不是默认值[/b]。半选态([bgcolor=#eee] indeterminate="true" [/bgcolor])用于表达"子项部分被选中"的视觉状态(例如父级 checkbox 在部分子项被选时显示半选)。点击 indeterminate 状态的 checkbox 会转为 checked 状态。`}

    +
    +
    +
    + +

    API 参考

    + +
    +
    + ); +} diff --git a/examples/doc-viewer/app/zh-CN/widgets/label/page.c b/examples/doc-viewer/app/zh-CN/widgets/label/page.c new file mode 100644 index 000000000..3e4b5355a --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/widgets/label/page.c @@ -0,0 +1,54 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + zh_cn_widgets_label_page_react_t base; + // Add additional states to your component here + // ... +} zh_cn_widgets_label_page_t; + +static void zh_cn_widgets_label_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, zh_cn_widgets_label_page_proto, + sizeof(zh_cn_widgets_label_page_t)); + + zh_cn_widgets_label_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + zh_cn_widgets_label_page_update(w); +} + +static zh_cn_widgets_label_page_t *zh_cn_widgets_label_page_get(ui_widget_t *w) +{ + return ui_widget_get_data(w, zh_cn_widgets_label_page_proto); +} + +static void zh_cn_widgets_label_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + zh_cn_widgets_label_page_react_destroy(w); +} + +void zh_cn_widgets_label_page_update(ui_widget_t *w) +{ + zh_cn_widgets_label_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_zh_cn_widgets_label_page(void) +{ + return ui_create_widget_with_prototype(zh_cn_widgets_label_page_proto); +} + +void ui_register_zh_cn_widgets_label_page(void) +{ + zh_cn_widgets_label_page_init_prototype(); + zh_cn_widgets_label_page_proto->init = zh_cn_widgets_label_page_init; + zh_cn_widgets_label_page_proto->destroy = + zh_cn_widgets_label_page_destroy; +} diff --git a/examples/doc-viewer/app/zh-CN/widgets/label/page.h b/examples/doc-viewer/app/zh-CN/widgets/label/page.h new file mode 100644 index 000000000..1319588e1 --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/widgets/label/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_zh_cn_widgets_label_page(void); + +ui_widget_t *ui_create_zh_cn_widgets_label_page(void); + +void zh_cn_widgets_label_page_update(ui_widget_t *w); + +void ui_load_zh_cn_widgets_label_page_resources(void); diff --git a/examples/doc-viewer/app/zh-CN/widgets/label/page.tsx b/examples/doc-viewer/app/zh-CN/widgets/label/page.tsx new file mode 100644 index 000000000..41f9e203e --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/widgets/label/page.tsx @@ -0,0 +1,48 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; +import LabelBasicDemo from "../../../examples/label-basic/index"; +import FieldTable from "../../../components/field-table"; +import { labelFields } from "../../../widget-fields/label"; + +export default function LabelDocPage() { + return ( + +

    Label

    +

    {`渲染与控件关联的可访问标签,点击时将 click 事件转发到 [bgcolor=#eee] for [/bgcolor] 指向的目标部件。`}

    + + +

    适用场景

    +
      +
    • {`[b]适用[/b]:为 checkbox、text-input 等可交互控件提供点击区域扩展(点击文字也能触发控件)`}
    • +
    • {`[b]适用[/b]:辅助功能(a11y)中将文本与控件关联`}
    • +
    • {`[b]不适用[/b]:纯展示文本(用 [bgcolor=#eee] text [/bgcolor] 部件)`}
    • +
    +
    + +

    用法

    + + + TypeScript + + + + {`[color=#cf222e]import[/color] { [color=#8250df]Label[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color]`} + + + + + TypeScript + + + + {`<[color=#8250df]Label[/color] [color=#cf222e]for[/color]=[color=#0a3069]"agree"[/color]>I agree`} + + +
    + +

    API 参考

    + +
    +
    + ); +} diff --git a/examples/doc-viewer/app/zh-CN/widgets/progress/page.tsx b/examples/doc-viewer/app/zh-CN/widgets/progress/page.tsx index bfdce3b08..59b897fe5 100644 --- a/examples/doc-viewer/app/zh-CN/widgets/progress/page.tsx +++ b/examples/doc-viewer/app/zh-CN/widgets/progress/page.tsx @@ -39,19 +39,6 @@ export default function ProgressDocPage() {
    - -

    组合

    -

    {`使用以下组合来构建 [bgcolor=#eee] Progress [/bgcolor]:`}

    - - - TEXT - - - - {`Progress`} - - -

    API 参考

    diff --git a/examples/doc-viewer/app/zh-CN/widgets/text-input/page.tsx b/examples/doc-viewer/app/zh-CN/widgets/text-input/page.tsx index 138a3c75b..6ef40f106 100644 --- a/examples/doc-viewer/app/zh-CN/widgets/text-input/page.tsx +++ b/examples/doc-viewer/app/zh-CN/widgets/text-input/page.tsx @@ -38,19 +38,6 @@ export default function TextInputDocPage() {
    - -

    组合

    -

    {`使用以下组合来构建 [bgcolor=#eee] TextInput [/bgcolor]:`}

    - - - TEXT - - - - {`TextInput`} - - -

    API 参考

    diff --git a/examples/doc-viewer/app/zh-CN/widgets/text/page.tsx b/examples/doc-viewer/app/zh-CN/widgets/text/page.tsx index 98cc6ec6f..6d4f31bab 100644 --- a/examples/doc-viewer/app/zh-CN/widgets/text/page.tsx +++ b/examples/doc-viewer/app/zh-CN/widgets/text/page.tsx @@ -38,19 +38,6 @@ export default function TextDocPage() {
    - -

    组合

    -

    {`使用以下组合来构建 [bgcolor=#eee] Text [/bgcolor]:`}

    - - - TEXT - - - - {`Text`} - - -

    API 参考

    From d4a6e12df0c5b49791b88498936db5ed052f7579 Mon Sep 17 00:00:00 2001 From: Liu Date: Mon, 29 Jun 2026 23:05:21 +0800 Subject: [PATCH 54/66] feat(widgets): add radio-group widget --- AGENTS.md | 28 ++ docs/en/widgets/radio-group.mdx | 58 ++++ .../radio-group-basic-tsx/example.tsx | 21 ++ docs/examples/radio-group-basic-tsx/main.c | 11 + docs/examples/radio-group-basic-xml/main.c | 8 + docs/examples/radio-group-basic-xml/ui.xml | 19 ++ docs/examples/radio-group-basic/main.c | 39 +++ .../radio-group-disabled-tsx/example.tsx | 21 ++ docs/examples/radio-group-disabled-tsx/main.c | 11 + docs/examples/radio-group-disabled-xml/main.c | 8 + docs/examples/radio-group-disabled-xml/ui.xml | 19 ++ docs/examples/radio-group-disabled/main.c | 42 +++ docs/sidebars.json | 1 + docs/widget-fields/radio-group-item.ts | 23 ++ docs/widget-fields/radio-group.ts | 14 + docs/zh-CN/widgets/radio-group.mdx | 58 ++++ examples/doc-viewer/AGENTS.md | 93 ++++++ .../doc-viewer/app/components/sidebar.json | 1 + .../app/en/widgets/radio-group/page.c | 57 ++++ .../app/en/widgets/radio-group/page.h | 9 + .../app/en/widgets/radio-group/page.tsx | 81 +++++ .../app/examples/radio-group-basic/index.c | 41 +++ .../app/examples/radio-group-basic/index.tsx | 140 +++++++++ .../app/examples/radio-group-disabled/index.c | 43 +++ .../examples/radio-group-disabled/index.tsx | 143 +++++++++ .../app/widget-fields/radio-group-item.ts | 23 ++ .../app/widget-fields/radio-group.ts | 14 + .../app/zh-CN/widgets/checkbox/page.tsx | 6 + .../app/zh-CN/widgets/radio-group/page.c | 57 ++++ .../app/zh-CN/widgets/radio-group/page.h | 9 + .../app/zh-CN/widgets/radio-group/page.tsx | 81 +++++ include/LCUI/widgets.h | 1 + include/LCUI/widgets/radio_group.h | 67 +++++ src/lcui_widgets.c | 1 + src/widgets/radio_group.c | 164 ++++++++++ tests/integration/test_radio_group.c | 282 ++++++++++++++++++ tests/main.c | 2 + 37 files changed, 1696 insertions(+) create mode 100644 docs/en/widgets/radio-group.mdx create mode 100644 docs/examples/radio-group-basic-tsx/example.tsx create mode 100644 docs/examples/radio-group-basic-tsx/main.c create mode 100644 docs/examples/radio-group-basic-xml/main.c create mode 100644 docs/examples/radio-group-basic-xml/ui.xml create mode 100644 docs/examples/radio-group-basic/main.c create mode 100644 docs/examples/radio-group-disabled-tsx/example.tsx create mode 100644 docs/examples/radio-group-disabled-tsx/main.c create mode 100644 docs/examples/radio-group-disabled-xml/main.c create mode 100644 docs/examples/radio-group-disabled-xml/ui.xml create mode 100644 docs/examples/radio-group-disabled/main.c create mode 100644 docs/widget-fields/radio-group-item.ts create mode 100644 docs/widget-fields/radio-group.ts create mode 100644 docs/zh-CN/widgets/radio-group.mdx create mode 100644 examples/doc-viewer/app/en/widgets/radio-group/page.c create mode 100644 examples/doc-viewer/app/en/widgets/radio-group/page.h create mode 100644 examples/doc-viewer/app/en/widgets/radio-group/page.tsx create mode 100644 examples/doc-viewer/app/examples/radio-group-basic/index.c create mode 100644 examples/doc-viewer/app/examples/radio-group-basic/index.tsx create mode 100644 examples/doc-viewer/app/examples/radio-group-disabled/index.c create mode 100644 examples/doc-viewer/app/examples/radio-group-disabled/index.tsx create mode 100644 examples/doc-viewer/app/widget-fields/radio-group-item.ts create mode 100644 examples/doc-viewer/app/widget-fields/radio-group.ts create mode 100644 examples/doc-viewer/app/zh-CN/widgets/radio-group/page.c create mode 100644 examples/doc-viewer/app/zh-CN/widgets/radio-group/page.h create mode 100644 examples/doc-viewer/app/zh-CN/widgets/radio-group/page.tsx create mode 100644 include/LCUI/widgets/radio_group.h create mode 100644 src/widgets/radio_group.c create mode 100644 tests/integration/test_radio_group.c diff --git a/AGENTS.md b/AGENTS.md index 725dc3747..a5c4578e0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -53,6 +53,34 @@ void object2_func2() { 注意!优先通过调整函数定义代码块的顺序来解决声明问题,而不是前置声明函数。 +### 未使用参数 + +未使用的函数参数(包括回调签名里必须存在的 `void *arg`、事件回调的 `ui_event_t *e` 等) +**不要写 `(void)xxx;`**。GCC、Clang、MSVC 都默认不警告未使用参数名,只有未使用局部变量 +才会警告。`(void)xxx;` 是冗余噪音,掩盖真正该处理的警告。 + +❌ 禁止: +```c +static void on_event(ui_widget_t *w, ui_event_t *e, void *arg) +{ + (void)w; + (void)e; + (void)arg; + /* 实际逻辑 */ +} +``` + +✅ 允许: +```c +static void on_event(ui_widget_t *w, ui_event_t *e, void *arg) +{ + /* 直接用到的参数正常使用;用不到的参数名直接保留在签名里 */ +} +``` + +> 例外:C++ 模式下某些编译器会警告未使用参数,需要按上下文决定。LCUI 是纯 C, +> 不适用此例外。 + ## 测试用例 ### 归属规则 diff --git a/docs/en/widgets/radio-group.mdx b/docs/en/widgets/radio-group.mdx new file mode 100644 index 000000000..1b2f3f89e --- /dev/null +++ b/docs/en/widgets/radio-group.mdx @@ -0,0 +1,58 @@ +# RadioGroup + +A set of mutually exclusive radio buttons—only one item in the group can be selected at a time. + + + +## Use cases + +- **Suitable**: pick exactly one option from a mutually exclusive set (view density, sort order, single-choice enumerations). +- **Suitable**: simple cases with a fixed 2–7 options. +- **Not suitable**: scenarios that allow multiple concurrent selections (use `checkbox`). +- **Not suitable**: large option lists that need search or filtering (no `select` provided yet). + +## Usage + +```tsx +import { RadioGroup, RadioGroupItem } from "@lcui/react" +``` + +```tsx + + + + + +``` + +## Composition + +Use the following composition to build a `RadioGroup`: + +``` +RadioGroup +├── RadioGroupItem +└── RadioGroupItem +``` + +In practice, each item is paired with a `Label` placed in the same flex row, with the Label's `for` pointing at the RadioGroupItem's `id`—clicking the Label forwards the click event to the matching item. + +## Examples + +### Disabled + + + +## API Reference + +### RadioGroup + +The container that manages mutually exclusive selection across its items. + + + +### RadioGroupItem + +A single selectable option. At most one RadioGroupItem within the same RadioGroup is checked at any time. + + \ No newline at end of file diff --git a/docs/examples/radio-group-basic-tsx/example.tsx b/docs/examples/radio-group-basic-tsx/example.tsx new file mode 100644 index 000000000..fa8215fd2 --- /dev/null +++ b/docs/examples/radio-group-basic-tsx/example.tsx @@ -0,0 +1,21 @@ +import { RadioGroup, RadioGroupItem } from "@lcui/react"; +import { Label } from "@lcui/react"; + +export default function App() { + return ( + +
    + + +
    +
    + + +
    +
    + + +
    +
    + ); +} \ No newline at end of file diff --git a/docs/examples/radio-group-basic-tsx/main.c b/docs/examples/radio-group-basic-tsx/main.c new file mode 100644 index 000000000..c508b339d --- /dev/null +++ b/docs/examples/radio-group-basic-tsx/main.c @@ -0,0 +1,11 @@ +#include + +/* example.tsx is compiled to example.h by @lcui/cli */ +#include "example.h" + +int main(void) +{ + lcui_init(); + example_load(); + return lcui_main(); +} diff --git a/docs/examples/radio-group-basic-xml/main.c b/docs/examples/radio-group-basic-xml/main.c new file mode 100644 index 000000000..9f6a1e964 --- /dev/null +++ b/docs/examples/radio-group-basic-xml/main.c @@ -0,0 +1,8 @@ +#include + +int main(void) +{ + lcui_init(); + ui_load_xml_file("ui.xml"); + return lcui_main(); +} diff --git a/docs/examples/radio-group-basic-xml/ui.xml b/docs/examples/radio-group-basic-xml/ui.xml new file mode 100644 index 000000000..6c30734db --- /dev/null +++ b/docs/examples/radio-group-basic-xml/ui.xml @@ -0,0 +1,19 @@ + + + + +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    \ No newline at end of file diff --git a/docs/examples/radio-group-basic/main.c b/docs/examples/radio-group-basic/main.c new file mode 100644 index 000000000..76ccba78b --- /dev/null +++ b/docs/examples/radio-group-basic/main.c @@ -0,0 +1,39 @@ +#include + +void radio_group_basic_init(ui_widget_t *parent) +{ + ui_widget_t *group; + ui_widget_t *rows[3]; + ui_widget_t *items[3]; + ui_widget_t *labels[3]; + const char *ids[3] = { "r1", "r2", "r3" }; + const char *values[3] = { "default", "comfortable", "compact" }; + const char *texts[3] = { "Default", "Comfortable", "Compact" }; + int i; + + group = ui_create_radio_group(); + ui_widget_set_attr(group, "value", "comfortable"); + + for (i = 0; i < 3; ++i) { + rows[i] = ui_create_widget(NULL); + ui_widget_set_style_string(rows[i], "display", "flex"); + ui_widget_set_style_string(rows[i], "align-items", "center"); + ui_widget_set_style_string(rows[i], "gap", "8px"); + + items[i] = ui_create_radio_group_item(); + ui_widget_set_id(items[i], ids[i]); + ui_widget_set_attr(items[i], "value", values[i]); + if (i == 1) { + ui_widget_set_attr(items[i], "checked", "true"); + } + ui_widget_append(rows[i], items[i]); + + labels[i] = ui_create_label(); + ui_label_set_for(labels[i], ids[i]); + ui_text_set_content(labels[i], texts[i]); + ui_widget_append(rows[i], labels[i]); + + ui_widget_append(group, rows[i]); + } + ui_widget_append(parent, group); +} diff --git a/docs/examples/radio-group-disabled-tsx/example.tsx b/docs/examples/radio-group-disabled-tsx/example.tsx new file mode 100644 index 000000000..8e9dac19e --- /dev/null +++ b/docs/examples/radio-group-disabled-tsx/example.tsx @@ -0,0 +1,21 @@ +import { RadioGroup, RadioGroupItem } from "@lcui/react"; +import { Label } from "@lcui/react"; + +export default function App() { + return ( + +
    + + +
    +
    + + +
    +
    + + +
    +
    + ); +} \ No newline at end of file diff --git a/docs/examples/radio-group-disabled-tsx/main.c b/docs/examples/radio-group-disabled-tsx/main.c new file mode 100644 index 000000000..c508b339d --- /dev/null +++ b/docs/examples/radio-group-disabled-tsx/main.c @@ -0,0 +1,11 @@ +#include + +/* example.tsx is compiled to example.h by @lcui/cli */ +#include "example.h" + +int main(void) +{ + lcui_init(); + example_load(); + return lcui_main(); +} diff --git a/docs/examples/radio-group-disabled-xml/main.c b/docs/examples/radio-group-disabled-xml/main.c new file mode 100644 index 000000000..9f6a1e964 --- /dev/null +++ b/docs/examples/radio-group-disabled-xml/main.c @@ -0,0 +1,8 @@ +#include + +int main(void) +{ + lcui_init(); + ui_load_xml_file("ui.xml"); + return lcui_main(); +} diff --git a/docs/examples/radio-group-disabled-xml/ui.xml b/docs/examples/radio-group-disabled-xml/ui.xml new file mode 100644 index 000000000..0764b8c6a --- /dev/null +++ b/docs/examples/radio-group-disabled-xml/ui.xml @@ -0,0 +1,19 @@ + + + + +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    \ No newline at end of file diff --git a/docs/examples/radio-group-disabled/main.c b/docs/examples/radio-group-disabled/main.c new file mode 100644 index 000000000..514358d4b --- /dev/null +++ b/docs/examples/radio-group-disabled/main.c @@ -0,0 +1,42 @@ +#include + +void radio_group_disabled_init(ui_widget_t *parent) +{ + ui_widget_t *group; + ui_widget_t *rows[3]; + ui_widget_t *items[3]; + ui_widget_t *labels[3]; + const char *ids[3] = { "rd1", "rd2", "rd3" }; + const char *values[3] = { "disabled", "option2", "option3" }; + const char *texts[3] = { "Disabled", "Option 2", "Option 3" }; + int i; + + group = ui_create_radio_group(); + ui_widget_set_attr(group, "value", "option2"); + + for (i = 0; i < 3; ++i) { + rows[i] = ui_create_widget(NULL); + ui_widget_set_style_string(rows[i], "display", "flex"); + ui_widget_set_style_string(rows[i], "align-items", "center"); + ui_widget_set_style_string(rows[i], "gap", "8px"); + + items[i] = ui_create_radio_group_item(); + ui_widget_set_id(items[i], ids[i]); + ui_widget_set_attr(items[i], "value", values[i]); + if (i == 0) { + ui_widget_set_disabled(items[i], true); + } + if (i == 1) { + ui_widget_set_attr(items[i], "checked", "true"); + } + ui_widget_append(rows[i], items[i]); + + labels[i] = ui_create_label(); + ui_label_set_for(labels[i], ids[i]); + ui_text_set_content(labels[i], texts[i]); + ui_widget_append(rows[i], labels[i]); + + ui_widget_append(group, rows[i]); + } + ui_widget_append(parent, group); +} diff --git a/docs/sidebars.json b/docs/sidebars.json index 6569d8121..ec7632de9 100644 --- a/docs/sidebars.json +++ b/docs/sidebars.json @@ -36,6 +36,7 @@ { "slug": "checkbox", "label": { "en": "Checkbox", "zh-CN": "Checkbox 复选框" } }, { "slug": "label", "label": { "en": "Label", "zh-CN": "Label 标签" } }, { "slug": "progress", "label": { "en": "Progress", "zh-CN": "Progress 进度条" } }, + { "slug": "radio-group", "label": { "en": "RadioGroup", "zh-CN": "RadioGroup 单选组" } }, { "slug": "scrollarea", "label": { "en": "ScrollArea", "zh-CN": "ScrollArea 滚动区域" } }, { "slug": "text", "label": { "en": "Text", "zh-CN": "Text 文本" } }, { "slug": "text-input", "label": { "en": "TextInput", "zh-CN": "TextInput 文本输入" } } diff --git a/docs/widget-fields/radio-group-item.ts b/docs/widget-fields/radio-group-item.ts new file mode 100644 index 000000000..f27bd7e5e --- /dev/null +++ b/docs/widget-fields/radio-group-item.ts @@ -0,0 +1,23 @@ +import { widgetFields, FieldData } from "./widget"; + +export const radioGroupItemFields: FieldData[] = [ + ...widgetFields, + { + name: "value", + type: "string", + default: "", + description: { + en: "The value submitted when this item is selected. Must be unique within the same RadioGroup.", + "zh-CN": "选中本项时提交的值。同一 RadioGroup 内各 item 的 value 必须唯一。", + }, + }, + { + name: "checked", + type: "boolean", + default: "false", + description: { + en: "Whether this item is in the selected state. Driven by the parent RadioGroup's value; you usually don't set this directly.", + "zh-CN": "本项是否处于选中状态。由父 RadioGroup 的 value 推导,一般不直接设置。", + }, + }, +]; \ No newline at end of file diff --git a/docs/widget-fields/radio-group.ts b/docs/widget-fields/radio-group.ts new file mode 100644 index 000000000..3c0186114 --- /dev/null +++ b/docs/widget-fields/radio-group.ts @@ -0,0 +1,14 @@ +import { widgetFields, FieldData } from "./widget"; + +export const radioGroupFields: FieldData[] = [ + ...widgetFields, + { + name: "value", + type: "string", + default: "", + description: { + en: "Currently selected item value. Items whose value attribute matches are shown as selected.", + "zh-CN": "当前选中项的值。值匹配项的 value 属性的 item 会显示为选中状态。", + }, + }, +]; \ No newline at end of file diff --git a/docs/zh-CN/widgets/radio-group.mdx b/docs/zh-CN/widgets/radio-group.mdx new file mode 100644 index 000000000..40b7c7433 --- /dev/null +++ b/docs/zh-CN/widgets/radio-group.mdx @@ -0,0 +1,58 @@ +# RadioGroup + +一组互斥的单选按钮,同一时刻最多只有一项被选中。 + + + +## 适用场景 + +- **适用**:从一组互斥的选项中选出唯一一个(视图密度、排序方式、单选枚举等) +- **适用**:选项数量固定为 2~7 个的简单场景 +- **不适用**:需要并选多个选项的场景(用 `checkbox`) +- **不适用**:选项数量大到需要搜索或筛选(暂未提供 `select`) + +## 用法 + +```tsx +import { RadioGroup, RadioGroupItem } from "@lcui/react" +``` + +```tsx + + + + + +``` + +## 组合 + +使用以下组合来构建 `RadioGroup`: + +``` +RadioGroup +├── RadioGroupItem +└── RadioGroupItem +``` + +通常每项会与一个 `Label` 搭配放置在同一行 flex 容器里,Label 的 `for` 指向 RadioGroupItem 的 `id`,点击 Label 会把 click 事件转发到对应的 item。 + +## 示例 + +### 禁用 + + + +## API 参考 + +### RadioGroup + +单选组容器,管理组内各项的互斥选中状态。 + + + +### RadioGroupItem + +单选项,每一项代表一个可选值。同一 RadioGroup 内同一时刻最多只有一项处于 checked 状态。 + + \ No newline at end of file diff --git a/examples/doc-viewer/AGENTS.md b/examples/doc-viewer/AGENTS.md index eda0c9c53..053a70e99 100644 --- a/examples/doc-viewer/AGENTS.md +++ b/examples/doc-viewer/AGENTS.md @@ -97,6 +97,23 @@ WidgetName #### ## API 参考 - 只用 ``,编译器自动从 `docs/widget-fields/{name}.ts` 读取字段数据 - 不手写 API 小节、属性列表或事件列表 +- **多部件组件**:每个 FieldTable 前必须用 `### ` 三级标题 + 一句话描述(参考 `docs/zh-CN/widgets/scrollarea.mdx`)。zh-CN 模板: + ```mdx + ## API 参考 + + ### RadioGroup + + 单选组容器,管理组内各项的互斥选中状态。 + + + + ### RadioGroupItem + + 单选项,每一项代表一个可选值。 + + + ``` + en 模板:标题 `## API Reference`,子标题 PascalCase,描述同步翻译。 #### ## 注意事项(可选) - 每个注意点独立一个 admonition 容器 @@ -224,3 +241,79 @@ bun run compile npx lcui build app --force xmake build doc-viewer ``` + +> ⚠️ `npx lcui build app --force` 输出末尾的 `unknown target(lcui) for doc-viewer.deps!` 警告无害,是已知问题,可忽略。`bun run compile` 自动复制 `widget-fields/` 并触发页面生成;任何一步失败都会产生连锁错误。 + +## Demo 变体命名约定 + +`docs/examples/` 下的 demo 目录名是文档里 `` 的 `name` 属性值: + +| 变体后缀 | 含义 | 内容 | +|---------|------|------| +| (无后缀) | 基础 / 唯一示例 | `main.c` 实现 `void _basic_init(ui_widget_t *parent)` | +| `-xml` | XML 标记声明式 | `ui.xml` + `main.c`(`lcui_init` + `ui_load_xml_file`) | +| `-tsx` | TSX 声明式 | `example.tsx` + `main.c`(`lcui_init` + `example_load()`) | +| `-` | 特性示例 | 镜像 `-tsx` 三件套结构,如 `-disabled`、`-dual-scrollbars` | + +**三变体必齐**:C、XML、TSX 三种实现都要提供。即使 widget 暂未在 `@lcui/react` 中导出,也要给出 TSX 变体作为前瞻占位(`example.tsx` 仅作为代码块展示,不会实际编译)。 + +## widget-fields 文件命名与目录复制陷阱 + +`` 解析为 `docs/widget-fields/radio-group-item.ts`。**文件名必须用 `-`(dash)**,不能用 `_`(underscore)。命名约定是 slug 原文,camelCase 变量名(如 `radioGroupItemFields`)由文件作者自己定。 + +⚠️ **`examples/doc-viewer/app/widget-fields/` 是编译时副本,不会自动清理**: + +`scripts/compiler/index.ts:55` 的 `copyWidgetFields()` 只 `copyFileSync` 不删除。如果在 `docs/widget-fields/` 重命名或删除文件,旧的 `app/widget-fields/.ts` 会残留。下次编译时编译器可能: + +- 找不到新名(如果旧文件还在 dest)→ 报 `ModuleLoaderError: File does not exist` +- 引用错文件(如果同名但内容已变) + +**修正步骤**:删 `examples/doc-viewer/app/widget-fields/` 下 stale 文件,或 `git clean -fd examples/doc-viewer/app/widget-fields` 强制重生成。 + +## Demo 预览容器布局陷阱 + +doc-viewer 的 demo preview 区域本身是 flex 容器,所以**多个独立 flex 行直接 append 到 parent 会横排**。需要在 C/XML demo 外层包一个 `display:flex; flex-direction:column; gap:8px` 容器: + +```c +ui_widget_t *box = ui_create_widget(NULL); +ui_widget_set_style_string(box, "display", "flex"); +ui_widget_set_style_string(box, "flex-direction", "column"); +ui_widget_set_style_string(box, "gap", "8px"); +ui_widget_append(box, row1); +ui_widget_append(box, row2); +ui_widget_append(parent, box); +``` + +XML 用外层 `
    ` 包裹。TSX 用 `...` 包裹。 + +RadioGroup / ScrollArea / Field 等本身是垂直容器,item 直接 append 进 group 即可,无需外层 wrapper。 + +## 生成的 `index.c` 在 Linux 上的 `static` 不一致问题 + +`lcui build app --force` 对 `examples/doc-viewer/app/examples//index.c` +使用 skeleton-once 策略:只在文件不存在时写入,后续构建保留手写改动。 +首次生成的 `index.c` 中 `_demo_update` 函数被声明为 `static`, +但同名的 `_demo_update(ui_widget_t *)` 在对应 `index.h` 里是非 +`static` 的全局声明。MSVC 默认不报警告;GCC/Clang 在开启 `-Wall` +或项目使用 `set_warnings("all", "error")`(LCUI 在 Ubuntu 上的 +默认配置)时会因声明/定义不一致而**编译失败**。 + +**触发场景**:每次新增 demo(含 `WidgetExample` 引用)或首次为新 +demo 生成 `index.c` 后。 + +**手动修复**:在生成的 `index.c` 里删除 `static` 关键字: + +```c +// before +static void checkbox_disabled_demo_update(ui_widget_t *w) { ... } + +// after +void checkbox_disabled_demo_update(ui_widget_t *w) { ... } +``` + +⚠️ 只去掉 `_demo_update` 上的 `static`,**保留** `_demo_init` / +`_demo_destroy` 上的 `static`——这两个没有对应 header 声明,是 +prototype 内部回调,加 `static` 是正确的。 + +详细说明见 `~/.config/opencode/skills/lcui-cli/SKILL.md` 的 +"Known limitations / open bugs" 节。 diff --git a/examples/doc-viewer/app/components/sidebar.json b/examples/doc-viewer/app/components/sidebar.json index 6569d8121..ec7632de9 100644 --- a/examples/doc-viewer/app/components/sidebar.json +++ b/examples/doc-viewer/app/components/sidebar.json @@ -36,6 +36,7 @@ { "slug": "checkbox", "label": { "en": "Checkbox", "zh-CN": "Checkbox 复选框" } }, { "slug": "label", "label": { "en": "Label", "zh-CN": "Label 标签" } }, { "slug": "progress", "label": { "en": "Progress", "zh-CN": "Progress 进度条" } }, + { "slug": "radio-group", "label": { "en": "RadioGroup", "zh-CN": "RadioGroup 单选组" } }, { "slug": "scrollarea", "label": { "en": "ScrollArea", "zh-CN": "ScrollArea 滚动区域" } }, { "slug": "text", "label": { "en": "Text", "zh-CN": "Text 文本" } }, { "slug": "text-input", "label": { "en": "TextInput", "zh-CN": "TextInput 文本输入" } } diff --git a/examples/doc-viewer/app/en/widgets/radio-group/page.c b/examples/doc-viewer/app/en/widgets/radio-group/page.c new file mode 100644 index 000000000..0cb9a186f --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/radio-group/page.c @@ -0,0 +1,57 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + en_widgets_radio_group_page_react_t base; + // Add additional states to your component here + // ... +} en_widgets_radio_group_page_t; + +static void en_widgets_radio_group_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, en_widgets_radio_group_page_proto, + sizeof(en_widgets_radio_group_page_t)); + + en_widgets_radio_group_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + en_widgets_radio_group_page_update(w); +} + +static en_widgets_radio_group_page_t *en_widgets_radio_group_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, en_widgets_radio_group_page_proto); +} + +static void en_widgets_radio_group_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + en_widgets_radio_group_page_react_destroy(w); +} + +void en_widgets_radio_group_page_update(ui_widget_t *w) +{ + en_widgets_radio_group_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_en_widgets_radio_group_page(void) +{ + return ui_create_widget_with_prototype( + en_widgets_radio_group_page_proto); +} + +void ui_register_en_widgets_radio_group_page(void) +{ + en_widgets_radio_group_page_init_prototype(); + en_widgets_radio_group_page_proto->init = + en_widgets_radio_group_page_init; + en_widgets_radio_group_page_proto->destroy = + en_widgets_radio_group_page_destroy; +} diff --git a/examples/doc-viewer/app/en/widgets/radio-group/page.h b/examples/doc-viewer/app/en/widgets/radio-group/page.h new file mode 100644 index 000000000..ef35d3380 --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/radio-group/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_en_widgets_radio_group_page(void); + +ui_widget_t *ui_create_en_widgets_radio_group_page(void); + +void en_widgets_radio_group_page_update(ui_widget_t *w); + +void ui_load_en_widgets_radio_group_page_resources(void); diff --git a/examples/doc-viewer/app/en/widgets/radio-group/page.tsx b/examples/doc-viewer/app/en/widgets/radio-group/page.tsx new file mode 100644 index 000000000..7e87993bd --- /dev/null +++ b/examples/doc-viewer/app/en/widgets/radio-group/page.tsx @@ -0,0 +1,81 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; +import RadioGroupBasicDemo from "../../../examples/radio-group-basic/index"; +import RadioGroupDisabledDemo from "../../../examples/radio-group-disabled/index"; +import FieldTable from "../../../components/field-table"; +import { radioGroupFields } from "../../../widget-fields/radio-group"; +import { radioGroupItemFields } from "../../../widget-fields/radio-group-item"; + +export default function RadioGroupDocPage() { + return ( + +

    RadioGroup

    +

    {`A set of mutually exclusive radio buttons—only one item in the group can be selected at a time.`}

    + + +

    Use cases

    +
      +
    • {`[b]Suitable[/b]: pick exactly one option from a mutually exclusive set (view density, sort order, single-choice enumerations).`}
    • +
    • {`[b]Suitable[/b]: simple cases with a fixed 2–7 options.`}
    • +
    • {`[b]Not suitable[/b]: scenarios that allow multiple concurrent selections (use [bgcolor=#eee] checkbox [/bgcolor]).`}
    • +
    • {`[b]Not suitable[/b]: large option lists that need search or filtering (no [bgcolor=#eee] select [/bgcolor] provided yet).`}
    • +
    +
    + +

    Usage

    + + + TypeScript + + + + {`[color=#cf222e]import[/color] { [color=#8250df]RadioGroup[/color], [color=#8250df]RadioGroupItem[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color]`} + + + + + TypeScript + + + + {`<[color=#8250df]RadioGroup[/color] value=[color=#0a3069]"comfortable"[/color]>`} + {`  [color=#116329]<[color=#0550ae]RadioGroupItem[/color] [color=#0550ae]value[/color]=[color=#0a3069]"default"[/color] [color=#0550ae]id[/color]=[color=#0a3069]"r1"[/color] />[/color]`} + {`  [color=#116329]<[color=#0550ae]RadioGroupItem[/color] [color=#0550ae]value[/color]=[color=#0a3069]"comfortable"[/color] [color=#0550ae]id[/color]=[color=#0a3069]"r2"[/color] />[/color]`} + {`  [color=#116329]<[color=#0550ae]RadioGroupItem[/color] [color=#0550ae]value[/color]=[color=#0a3069]"compact"[/color] [color=#0550ae]id[/color]=[color=#0a3069]"r3"[/color] />[/color]`} + {``} + + +
    + +

    Composition

    +

    {`Use the following composition to build a [bgcolor=#eee] RadioGroup [/bgcolor]:`}

    + + + TEXT + + + + {`RadioGroup`} + {`├── RadioGroupItem`} + {`└── RadioGroupItem`} + + +

    {`In practice, each item is paired with a [bgcolor=#eee] Label [/bgcolor] placed in the same flex row, with the Label's [bgcolor=#eee] for [/bgcolor] pointing at the RadioGroupItem's [bgcolor=#eee] id [/bgcolor]—clicking the Label forwards the click event to the matching item.`}

    +
    + +

    Examples

    +

    Disabled

    + +
    + +

    API Reference

    +

    RadioGroup

    +

    {`The container that manages mutually exclusive selection across its items.`}

    + +

    RadioGroupItem

    +

    {`A single selectable option. At most one RadioGroupItem within the same RadioGroup is checked at any time.`}

    + +
    +
    + ); +} diff --git a/examples/doc-viewer/app/examples/radio-group-basic/index.c b/examples/doc-viewer/app/examples/radio-group-basic/index.c new file mode 100644 index 000000000..d092f6d8c --- /dev/null +++ b/examples/doc-viewer/app/examples/radio-group-basic/index.c @@ -0,0 +1,41 @@ +#include "index.tsx.h" +#include "index.h" + +#include "../../../../../docs/examples/radio-group-basic/main.c" + +typedef struct { + radio_group_basic_demo_react_t base; +} radio_group_basic_demo_t; + +static void radio_group_basic_demo_init(ui_widget_t *w) +{ + radio_group_basic_demo_t *_that = ui_widget_add_data( + w, radio_group_basic_demo_proto, sizeof(radio_group_basic_demo_t)); + radio_group_basic_demo_proto->proto->init(w); + radio_group_basic_demo_react_init(w); + radio_group_basic_init(_that->base.refs.preview); + radio_group_basic_demo_update(w); +} + +static void radio_group_basic_demo_destroy(ui_widget_t *w) +{ + radio_group_basic_demo_proto->proto->destroy(w); + radio_group_basic_demo_react_destroy(w); +} + +void radio_group_basic_demo_update(ui_widget_t *w) +{ + radio_group_basic_demo_react_update(w); +} + +ui_widget_t *ui_create_radio_group_basic_demo(void) +{ + return ui_create_widget_with_prototype(radio_group_basic_demo_proto); +} + +void ui_register_radio_group_basic_demo(void) +{ + radio_group_basic_demo_init_prototype(); + radio_group_basic_demo_proto->init = radio_group_basic_demo_init; + radio_group_basic_demo_proto->destroy = radio_group_basic_demo_destroy; +} diff --git a/examples/doc-viewer/app/examples/radio-group-basic/index.tsx b/examples/doc-viewer/app/examples/radio-group-basic/index.tsx new file mode 100644 index 000000000..806cc9f37 --- /dev/null +++ b/examples/doc-viewer/app/examples/radio-group-basic/index.tsx @@ -0,0 +1,140 @@ +import { Text, Widget } from "@lcui/react"; +import DemoProvider from "../../components/demo-provider"; +import CodeBlockCopy from "../../components/code-block-copy"; + +export default function RadioGroupBasicDemo() { + return ( + + + + + + example.tsx + main.c + main.c + ui.xml + main.c + + + TSX + C + XML + + + + + {`[color=#cf222e]import[/color] { [color=#8250df]RadioGroup[/color], [color=#8250df]RadioGroupItem[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {`[color=#cf222e]import[/color] { [color=#8250df]Label[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]RadioGroup[/color] [color=#0550ae]value[/color]=[color=#0a3069]"comfortable"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]className[/color]=[color=#0a3069]"flex items-center gap-3"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]RadioGroupItem[/color] [color=#0550ae]value[/color]=[color=#0a3069]"default"[/color] [color=#0550ae]id[/color]=[color=#0a3069]"r1"[/color] />[/color]`} + {`        [color=#116329]<[color=#0550ae]Label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"r1"[/color]>[/color]Default[color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]className[/color]=[color=#0a3069]"flex items-center gap-3"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]RadioGroupItem[/color] [color=#0550ae]value[/color]=[color=#0a3069]"comfortable"[/color] [color=#0550ae]id[/color]=[color=#0a3069]"r2"[/color] [color=#0550ae]checked[/color]=[color=#0a3069]{true}[/color] />[/color]`} + {`        [color=#116329]<[color=#0550ae]Label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"r2"[/color]>[/color]Comfortable[color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]className[/color]=[color=#0a3069]"flex items-center gap-3"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]RadioGroupItem[/color] [color=#0550ae]value[/color]=[color=#0a3069]"compact"[/color] [color=#0550ae]id[/color]=[color=#0a3069]"r3"[/color] />[/color]`} + {`        [color=#116329]<[color=#0550ae]Label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"r3"[/color]>[/color]Compact[color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#6e7781]/* example.tsx is compiled to example.h by @lcui/cli */[/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069]"example.h"[/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        example_load();`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]void[/color] [color=#8250df]radio_group_basic_init[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *parent)[/color]`} + {`{`} + {`        [color=#953800]ui_widget_t[/color] *group;`} + {`        [color=#953800]ui_widget_t[/color] *rows\\[[color=#0550ae]3[/color]];`} + {`        [color=#953800]ui_widget_t[/color] *items\\[[color=#0550ae]3[/color]];`} + {`        [color=#953800]ui_widget_t[/color] *labels\\[[color=#0550ae]3[/color]];`} + {`        [color=#953800]const[/color] [color=#953800]char[/color] *ids\\[[color=#0550ae]3[/color]] = { [color=#0a3069]"r1"[/color], [color=#0a3069]"r2"[/color], [color=#0a3069]"r3"[/color] };`} + {`        [color=#953800]const[/color] [color=#953800]char[/color] *values\\[[color=#0550ae]3[/color]] = { [color=#0a3069]"default"[/color], [color=#0a3069]"comfortable"[/color], [color=#0a3069]"compact"[/color] };`} + {`        [color=#953800]const[/color] [color=#953800]char[/color] *texts\\[[color=#0550ae]3[/color]] = { [color=#0a3069]"Default"[/color], [color=#0a3069]"Comfortable"[/color], [color=#0a3069]"Compact"[/color] };`} + {`        [color=#953800]int[/color] i;`} + {` `} + {`        group = ui_create_radio_group();`} + {`        ui_widget_set_attr(group, [color=#0a3069]"value"[/color], [color=#0a3069]"comfortable"[/color]);`} + {` `} + {`        [color=#cf222e]for[/color] (i = [color=#0550ae]0[/color]; i < [color=#0550ae]3[/color]; ++i) {`} + {`                rows\\[i] = ui_create_widget([color=#0550ae]NULL[/color]);`} + {`                ui_widget_set_style_string(rows\\[i], [color=#0a3069]"display"[/color], [color=#0a3069]"flex"[/color]);`} + {`                ui_widget_set_style_string(rows\\[i], [color=#0a3069]"align-items"[/color], [color=#0a3069]"center"[/color]);`} + {`                ui_widget_set_style_string(rows\\[i], [color=#0a3069]"gap"[/color], [color=#0a3069]"8px"[/color]);`} + {` `} + {`                items\\[i] = ui_create_radio_group_item();`} + {`                ui_widget_set_id(items\\[i], ids\\[i]);`} + {`                ui_widget_set_attr(items\\[i], [color=#0a3069]"value"[/color], values\\[i]);`} + {`                [color=#cf222e]if[/color] (i == [color=#0550ae]1[/color]) {`} + {`                        ui_widget_set_attr(items\\[i], [color=#0a3069]"checked"[/color], [color=#0a3069]"true"[/color]);`} + {`                }`} + {`                ui_widget_append(rows\\[i], items\\[i]);`} + {` `} + {`                labels\\[i] = ui_create_label();`} + {`                ui_label_set_for(labels\\[i], ids\\[i]);`} + {`                ui_text_set_content(labels\\[i], texts\\[i]);`} + {`                ui_widget_append(rows\\[i], labels\\[i]);`} + {` `} + {`                ui_widget_append(group, rows\\[i]);`} + {`        }`} + {`        ui_widget_append(parent, group);`} + {`}`} + + + + {`[color=#6e7781][/color]`} + {`[color=#116329]<[color=#0550ae]lcui-app[/color]>[/color]`} + {`  [color=#116329]<[color=#0550ae]ui[/color]>[/color]`} + {`    [color=#116329]<[color=#0550ae]radio-group[/color] [color=#0550ae]value[/color]=[color=#0a3069]"comfortable"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]style[/color]=[color=#0a3069]"display:flex; align-items:center; gap:8px"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]radio-group-item[/color] [color=#0550ae]id[/color]=[color=#0a3069]"r1"[/color] [color=#0550ae]value[/color]=[color=#0a3069]"default"[/color] />[/color]`} + {`        [color=#116329]<[color=#0550ae]label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"r1"[/color]>[/color]Default[color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]style[/color]=[color=#0a3069]"display:flex; align-items:center; gap:8px"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]radio-group-item[/color] [color=#0550ae]id[/color]=[color=#0a3069]"r2"[/color] [color=#0550ae]value[/color]=[color=#0a3069]"comfortable"[/color] [color=#0550ae]checked[/color]=[color=#0a3069]"true"[/color] />[/color]`} + {`        [color=#116329]<[color=#0550ae]label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"r2"[/color]>[/color]Comfortable[color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]style[/color]=[color=#0a3069]"display:flex; align-items:center; gap:8px"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]radio-group-item[/color] [color=#0550ae]id[/color]=[color=#0a3069]"r3"[/color] [color=#0550ae]value[/color]=[color=#0a3069]"compact"[/color] />[/color]`} + {`        [color=#116329]<[color=#0550ae]label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"r3"[/color]>[/color]Compact[color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  [color=#116329][/color]`} + {`[color=#116329][/color]`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        ui_load_xml_file([color=#0a3069]"ui.xml"[/color]);`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + ); +} diff --git a/examples/doc-viewer/app/examples/radio-group-disabled/index.c b/examples/doc-viewer/app/examples/radio-group-disabled/index.c new file mode 100644 index 000000000..69f0b5811 --- /dev/null +++ b/examples/doc-viewer/app/examples/radio-group-disabled/index.c @@ -0,0 +1,43 @@ +#include "index.tsx.h" +#include "index.h" + +#include "../../../../../docs/examples/radio-group-disabled/main.c" + +typedef struct { + radio_group_disabled_demo_react_t base; +} radio_group_disabled_demo_t; + +static void radio_group_disabled_demo_init(ui_widget_t *w) +{ + radio_group_disabled_demo_t *_that = + ui_widget_add_data(w, radio_group_disabled_demo_proto, + sizeof(radio_group_disabled_demo_t)); + radio_group_disabled_demo_proto->proto->init(w); + radio_group_disabled_demo_react_init(w); + radio_group_disabled_init(_that->base.refs.preview); + radio_group_disabled_demo_update(w); +} + +static void radio_group_disabled_demo_destroy(ui_widget_t *w) +{ + radio_group_disabled_demo_proto->proto->destroy(w); + radio_group_disabled_demo_react_destroy(w); +} + +void radio_group_disabled_demo_update(ui_widget_t *w) +{ + radio_group_disabled_demo_react_update(w); +} + +ui_widget_t *ui_create_radio_group_disabled_demo(void) +{ + return ui_create_widget_with_prototype(radio_group_disabled_demo_proto); +} + +void ui_register_radio_group_disabled_demo(void) +{ + radio_group_disabled_demo_init_prototype(); + radio_group_disabled_demo_proto->init = radio_group_disabled_demo_init; + radio_group_disabled_demo_proto->destroy = + radio_group_disabled_demo_destroy; +} diff --git a/examples/doc-viewer/app/examples/radio-group-disabled/index.tsx b/examples/doc-viewer/app/examples/radio-group-disabled/index.tsx new file mode 100644 index 000000000..ba321ac63 --- /dev/null +++ b/examples/doc-viewer/app/examples/radio-group-disabled/index.tsx @@ -0,0 +1,143 @@ +import { Text, Widget } from "@lcui/react"; +import DemoProvider from "../../components/demo-provider"; +import CodeBlockCopy from "../../components/code-block-copy"; + +export default function RadioGroupDisabledDemo() { + return ( + + + + + + example.tsx + main.c + main.c + ui.xml + main.c + + + TSX + C + XML + + + + + {`[color=#cf222e]import[/color] { [color=#8250df]RadioGroup[/color], [color=#8250df]RadioGroupItem[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {`[color=#cf222e]import[/color] { [color=#8250df]Label[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color];`} + {` `} + {`[color=#cf222e]export[/color] [color=#cf222e]default[/color] [color=#cf222e]function[/color] [color=#8250df]App[/color]([color=#0550ae][/color]) {`} + {`  [color=#cf222e]return[/color] (`} + {`    [color=#116329]<[color=#0550ae]RadioGroup[/color] [color=#0550ae]value[/color]=[color=#0a3069]"option2"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]className[/color]=[color=#0a3069]"flex items-center gap-3"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]RadioGroupItem[/color] [color=#0550ae]value[/color]=[color=#0a3069]"disabled"[/color] [color=#0550ae]id[/color]=[color=#0a3069]"rd1"[/color] [color=#0550ae]disabled[/color]=[color=#0a3069]{true}[/color] />[/color]`} + {`        [color=#116329]<[color=#0550ae]Label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"rd1"[/color]>[/color]Disabled[color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]className[/color]=[color=#0a3069]"flex items-center gap-3"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]RadioGroupItem[/color] [color=#0550ae]value[/color]=[color=#0a3069]"option2"[/color] [color=#0550ae]id[/color]=[color=#0a3069]"rd2"[/color] [color=#0550ae]checked[/color]=[color=#0a3069]{true}[/color] />[/color]`} + {`        [color=#116329]<[color=#0550ae]Label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"rd2"[/color]>[/color]Option 2[color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]className[/color]=[color=#0a3069]"flex items-center gap-3"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]RadioGroupItem[/color] [color=#0550ae]value[/color]=[color=#0a3069]"option3"[/color] [color=#0550ae]id[/color]=[color=#0a3069]"rd3"[/color] />[/color]`} + {`        [color=#116329]<[color=#0550ae]Label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"rd3"[/color]>[/color]Option 3[color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  );`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#6e7781]/* example.tsx is compiled to example.h by @lcui/cli */[/color]`} + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069]"example.h"[/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        example_load();`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]void[/color] [color=#8250df]radio_group_disabled_init[/color][color=#0550ae]([color=#953800]ui_widget_t[/color] *parent)[/color]`} + {`{`} + {`        [color=#953800]ui_widget_t[/color] *group;`} + {`        [color=#953800]ui_widget_t[/color] *rows\\[[color=#0550ae]3[/color]];`} + {`        [color=#953800]ui_widget_t[/color] *items\\[[color=#0550ae]3[/color]];`} + {`        [color=#953800]ui_widget_t[/color] *labels\\[[color=#0550ae]3[/color]];`} + {`        [color=#953800]const[/color] [color=#953800]char[/color] *ids\\[[color=#0550ae]3[/color]] = { [color=#0a3069]"rd1"[/color], [color=#0a3069]"rd2"[/color], [color=#0a3069]"rd3"[/color] };`} + {`        [color=#953800]const[/color] [color=#953800]char[/color] *values\\[[color=#0550ae]3[/color]] = { [color=#0a3069]"disabled"[/color], [color=#0a3069]"option2"[/color], [color=#0a3069]"option3"[/color] };`} + {`        [color=#953800]const[/color] [color=#953800]char[/color] *texts\\[[color=#0550ae]3[/color]] = { [color=#0a3069]"Disabled"[/color], [color=#0a3069]"Option 2"[/color], [color=#0a3069]"Option 3"[/color] };`} + {`        [color=#953800]int[/color] i;`} + {` `} + {`        group = ui_create_radio_group();`} + {`        ui_widget_set_attr(group, [color=#0a3069]"value"[/color], [color=#0a3069]"option2"[/color]);`} + {` `} + {`        [color=#cf222e]for[/color] (i = [color=#0550ae]0[/color]; i < [color=#0550ae]3[/color]; ++i) {`} + {`                rows\\[i] = ui_create_widget([color=#0550ae]NULL[/color]);`} + {`                ui_widget_set_style_string(rows\\[i], [color=#0a3069]"display"[/color], [color=#0a3069]"flex"[/color]);`} + {`                ui_widget_set_style_string(rows\\[i], [color=#0a3069]"align-items"[/color], [color=#0a3069]"center"[/color]);`} + {`                ui_widget_set_style_string(rows\\[i], [color=#0a3069]"gap"[/color], [color=#0a3069]"8px"[/color]);`} + {` `} + {`                items\\[i] = ui_create_radio_group_item();`} + {`                ui_widget_set_id(items\\[i], ids\\[i]);`} + {`                ui_widget_set_attr(items\\[i], [color=#0a3069]"value"[/color], values\\[i]);`} + {`                [color=#cf222e]if[/color] (i == [color=#0550ae]0[/color]) {`} + {`                        ui_widget_set_disabled(items\\[i], [color=#0550ae]true[/color]);`} + {`                }`} + {`                [color=#cf222e]if[/color] (i == [color=#0550ae]1[/color]) {`} + {`                        ui_widget_set_attr(items\\[i], [color=#0a3069]"checked"[/color], [color=#0a3069]"true"[/color]);`} + {`                }`} + {`                ui_widget_append(rows\\[i], items\\[i]);`} + {` `} + {`                labels\\[i] = ui_create_label();`} + {`                ui_label_set_for(labels\\[i], ids\\[i]);`} + {`                ui_text_set_content(labels\\[i], texts\\[i]);`} + {`                ui_widget_append(rows\\[i], labels\\[i]);`} + {` `} + {`                ui_widget_append(group, rows\\[i]);`} + {`        }`} + {`        ui_widget_append(parent, group);`} + {`}`} + + + + {`[color=#6e7781][/color]`} + {`[color=#116329]<[color=#0550ae]lcui-app[/color]>[/color]`} + {`  [color=#116329]<[color=#0550ae]ui[/color]>[/color]`} + {`    [color=#116329]<[color=#0550ae]radio-group[/color] [color=#0550ae]value[/color]=[color=#0a3069]"option2"[/color]>[/color]`} + {`      [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]style[/color]=[color=#0a3069]"display:flex; align-items:center; gap:8px"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]radio-group-item[/color] [color=#0550ae]id[/color]=[color=#0a3069]"rd1"[/color] [color=#0550ae]value[/color]=[color=#0a3069]"disabled"[/color] [color=#0550ae]disabled[/color]=[color=#0a3069]"true"[/color] />[/color]`} + {`        [color=#116329]<[color=#0550ae]label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"rd1"[/color]>[/color]Disabled[color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]style[/color]=[color=#0a3069]"display:flex; align-items:center; gap:8px"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]radio-group-item[/color] [color=#0550ae]id[/color]=[color=#0a3069]"rd2"[/color] [color=#0550ae]value[/color]=[color=#0a3069]"option2"[/color] [color=#0550ae]checked[/color]=[color=#0a3069]"true"[/color] />[/color]`} + {`        [color=#116329]<[color=#0550ae]label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"rd2"[/color]>[/color]Option 2[color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`      [color=#116329]<[color=#0550ae]div[/color] [color=#0550ae]style[/color]=[color=#0a3069]"display:flex; align-items:center; gap:8px"[/color]>[/color]`} + {`        [color=#116329]<[color=#0550ae]radio-group-item[/color] [color=#0550ae]id[/color]=[color=#0a3069]"rd3"[/color] [color=#0550ae]value[/color]=[color=#0a3069]"option3"[/color] />[/color]`} + {`        [color=#116329]<[color=#0550ae]label[/color] [color=#0550ae]for[/color]=[color=#0a3069]"rd3"[/color]>[/color]Option 3[color=#116329][/color]`} + {`      [color=#116329][/color]`} + {`    [color=#116329][/color]`} + {`  [color=#116329][/color]`} + {`[color=#116329][/color]`} + + + + {`[color=#6e7781]#[color=#cf222e]include[/color] [color=#0a3069][/color][/color]`} + {` `} + {`[color=#953800]int[/color] [color=#8250df]main[/color][color=#0550ae]([color=#953800]void[/color])[/color]`} + {`{`} + {`        lcui_init();`} + {`        ui_load_xml_file([color=#0a3069]"ui.xml"[/color]);`} + {`        [color=#cf222e]return[/color] lcui_main();`} + {`}`} + + + + ); +} diff --git a/examples/doc-viewer/app/widget-fields/radio-group-item.ts b/examples/doc-viewer/app/widget-fields/radio-group-item.ts new file mode 100644 index 000000000..f27bd7e5e --- /dev/null +++ b/examples/doc-viewer/app/widget-fields/radio-group-item.ts @@ -0,0 +1,23 @@ +import { widgetFields, FieldData } from "./widget"; + +export const radioGroupItemFields: FieldData[] = [ + ...widgetFields, + { + name: "value", + type: "string", + default: "", + description: { + en: "The value submitted when this item is selected. Must be unique within the same RadioGroup.", + "zh-CN": "选中本项时提交的值。同一 RadioGroup 内各 item 的 value 必须唯一。", + }, + }, + { + name: "checked", + type: "boolean", + default: "false", + description: { + en: "Whether this item is in the selected state. Driven by the parent RadioGroup's value; you usually don't set this directly.", + "zh-CN": "本项是否处于选中状态。由父 RadioGroup 的 value 推导,一般不直接设置。", + }, + }, +]; \ No newline at end of file diff --git a/examples/doc-viewer/app/widget-fields/radio-group.ts b/examples/doc-viewer/app/widget-fields/radio-group.ts new file mode 100644 index 000000000..3c0186114 --- /dev/null +++ b/examples/doc-viewer/app/widget-fields/radio-group.ts @@ -0,0 +1,14 @@ +import { widgetFields, FieldData } from "./widget"; + +export const radioGroupFields: FieldData[] = [ + ...widgetFields, + { + name: "value", + type: "string", + default: "", + description: { + en: "Currently selected item value. Items whose value attribute matches are shown as selected.", + "zh-CN": "当前选中项的值。值匹配项的 value 属性的 item 会显示为选中状态。", + }, + }, +]; \ No newline at end of file diff --git a/examples/doc-viewer/app/zh-CN/widgets/checkbox/page.tsx b/examples/doc-viewer/app/zh-CN/widgets/checkbox/page.tsx index 8d6946e2c..f58db8fe6 100644 --- a/examples/doc-viewer/app/zh-CN/widgets/checkbox/page.tsx +++ b/examples/doc-viewer/app/zh-CN/widgets/checkbox/page.tsx @@ -1,6 +1,7 @@ import { Text, Widget } from "@lcui/react"; import CodeBlockCopy from "../../../components/code-block-copy"; import CheckboxBasicDemo from "../../../examples/checkbox-basic/index"; +import CheckboxDisabledDemo from "../../../examples/checkbox-disabled/index"; import FieldTable from "../../../components/field-table"; import { checkboxFields } from "../../../widget-fields/checkbox"; @@ -48,6 +49,11 @@ export default function CheckboxDocPage() { + +

    示例

    +

    禁用

    + +

    API 参考

    diff --git a/examples/doc-viewer/app/zh-CN/widgets/radio-group/page.c b/examples/doc-viewer/app/zh-CN/widgets/radio-group/page.c new file mode 100644 index 000000000..7167e4fe0 --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/widgets/radio-group/page.c @@ -0,0 +1,57 @@ +#include "page.tsx.h" +#include "page.h" + +typedef struct { + zh_cn_widgets_radio_group_page_react_t base; + // Add additional states to your component here + // ... +} zh_cn_widgets_radio_group_page_t; + +static void zh_cn_widgets_radio_group_page_init(ui_widget_t *w) +{ + ui_widget_add_data(w, zh_cn_widgets_radio_group_page_proto, + sizeof(zh_cn_widgets_radio_group_page_t)); + + zh_cn_widgets_radio_group_page_react_init(w); + // Write the initialization code for your component here + // such as state initialization, event binding, etc + // ... + + zh_cn_widgets_radio_group_page_update(w); +} + +static zh_cn_widgets_radio_group_page_t *zh_cn_widgets_radio_group_page_get( + ui_widget_t *w) +{ + return ui_widget_get_data(w, zh_cn_widgets_radio_group_page_proto); +} + +static void zh_cn_widgets_radio_group_page_destroy(ui_widget_t *w) +{ + // Write code here to destroy the relevant resources of the component + // ... + + zh_cn_widgets_radio_group_page_react_destroy(w); +} + +void zh_cn_widgets_radio_group_page_update(ui_widget_t *w) +{ + zh_cn_widgets_radio_group_page_react_update(w); + // Write code here to update other content of your component + // ... +} + +ui_widget_t *ui_create_zh_cn_widgets_radio_group_page(void) +{ + return ui_create_widget_with_prototype( + zh_cn_widgets_radio_group_page_proto); +} + +void ui_register_zh_cn_widgets_radio_group_page(void) +{ + zh_cn_widgets_radio_group_page_init_prototype(); + zh_cn_widgets_radio_group_page_proto->init = + zh_cn_widgets_radio_group_page_init; + zh_cn_widgets_radio_group_page_proto->destroy = + zh_cn_widgets_radio_group_page_destroy; +} diff --git a/examples/doc-viewer/app/zh-CN/widgets/radio-group/page.h b/examples/doc-viewer/app/zh-CN/widgets/radio-group/page.h new file mode 100644 index 000000000..6f311cae2 --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/widgets/radio-group/page.h @@ -0,0 +1,9 @@ +#include + +void ui_register_zh_cn_widgets_radio_group_page(void); + +ui_widget_t *ui_create_zh_cn_widgets_radio_group_page(void); + +void zh_cn_widgets_radio_group_page_update(ui_widget_t *w); + +void ui_load_zh_cn_widgets_radio_group_page_resources(void); diff --git a/examples/doc-viewer/app/zh-CN/widgets/radio-group/page.tsx b/examples/doc-viewer/app/zh-CN/widgets/radio-group/page.tsx new file mode 100644 index 000000000..b2791cd40 --- /dev/null +++ b/examples/doc-viewer/app/zh-CN/widgets/radio-group/page.tsx @@ -0,0 +1,81 @@ +import { Text, Widget } from "@lcui/react"; +import CodeBlockCopy from "../../../components/code-block-copy"; +import RadioGroupBasicDemo from "../../../examples/radio-group-basic/index"; +import RadioGroupDisabledDemo from "../../../examples/radio-group-disabled/index"; +import FieldTable from "../../../components/field-table"; +import { radioGroupFields } from "../../../widget-fields/radio-group"; +import { radioGroupItemFields } from "../../../widget-fields/radio-group-item"; + +export default function RadioGroupDocPage() { + return ( + +

    RadioGroup

    +

    {`一组互斥的单选按钮,同一时刻最多只有一项被选中。`}

    + + +

    适用场景

    +
      +
    • {`[b]适用[/b]:从一组互斥的选项中选出唯一一个(视图密度、排序方式、单选枚举等)`}
    • +
    • {`[b]适用[/b]:选项数量固定为 2~7 个的简单场景`}
    • +
    • {`[b]不适用[/b]:需要并选多个选项的场景(用 [bgcolor=#eee] checkbox [/bgcolor])`}
    • +
    • {`[b]不适用[/b]:选项数量大到需要搜索或筛选(暂未提供 [bgcolor=#eee] select [/bgcolor])`}
    • +
    +
    + +

    用法

    + + + TypeScript + + + + {`[color=#cf222e]import[/color] { [color=#8250df]RadioGroup[/color], [color=#8250df]RadioGroupItem[/color] } [color=#cf222e]from[/color] [color=#0a3069]"@lcui/react"[/color]`} + + + + + TypeScript + + + + {`<[color=#8250df]RadioGroup[/color] value=[color=#0a3069]"comfortable"[/color]>`} + {`  [color=#116329]<[color=#0550ae]RadioGroupItem[/color] [color=#0550ae]value[/color]=[color=#0a3069]"default"[/color] [color=#0550ae]id[/color]=[color=#0a3069]"r1"[/color] />[/color]`} + {`  [color=#116329]<[color=#0550ae]RadioGroupItem[/color] [color=#0550ae]value[/color]=[color=#0a3069]"comfortable"[/color] [color=#0550ae]id[/color]=[color=#0a3069]"r2"[/color] />[/color]`} + {`  [color=#116329]<[color=#0550ae]RadioGroupItem[/color] [color=#0550ae]value[/color]=[color=#0a3069]"compact"[/color] [color=#0550ae]id[/color]=[color=#0a3069]"r3"[/color] />[/color]`} + {``} + + +
    + +

    组合

    +

    {`使用以下组合来构建 [bgcolor=#eee] RadioGroup [/bgcolor]:`}

    + + + TEXT + + + + {`RadioGroup`} + {`├── RadioGroupItem`} + {`└── RadioGroupItem`} + + +

    {`通常每项会与一个 [bgcolor=#eee] Label [/bgcolor] 搭配放置在同一行 flex 容器里,Label 的 [bgcolor=#eee] for [/bgcolor] 指向 RadioGroupItem 的 [bgcolor=#eee] id [/bgcolor],点击 Label 会把 click 事件转发到对应的 item。`}

    +
    + +

    示例

    +

    禁用

    + +
    + +

    API 参考

    +

    RadioGroup

    +

    {`单选组容器,管理组内各项的互斥选中状态。`}

    + +

    RadioGroupItem

    +

    {`单选项,每一项代表一个可选值。同一 RadioGroup 内同一时刻最多只有一项处于 checked 状态。`}

    + +
    +
    + ); +} diff --git a/include/LCUI/widgets.h b/include/LCUI/widgets.h index f7327442e..815b7f11f 100644 --- a/include/LCUI/widgets.h +++ b/include/LCUI/widgets.h @@ -20,3 +20,4 @@ #include "widgets/textcaret.h" #include "widgets/label.h" #include "widgets/checkbox.h" +#include "widgets/radio_group.h" diff --git a/include/LCUI/widgets/radio_group.h b/include/LCUI/widgets/radio_group.h new file mode 100644 index 000000000..d1155b3ed --- /dev/null +++ b/include/LCUI/widgets/radio_group.h @@ -0,0 +1,67 @@ +/* + * include/LCUI/widgets/radio_group.h: -- RadioGroup and RadioGroupItem widgets + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found + * in the LICENSE.TXT file in the root directory of this source tree. + */ + +#ifndef LCUI_INCLUDE_WIDGETS_RADIO_GROUP_H +#define LCUI_INCLUDE_WIDGETS_RADIO_GROUP_H + +#include +#include +#include + +LCUI_BEGIN_HEADER + +LCUI_API ui_widget_t *ui_create_radio_group(void); + +LCUI_API ui_widget_t *ui_create_radio_group_item(void); + +LCUI_API void ui_register_radio_group(void); + +/** + * Sync item checked states with the group's current value. + * + * Walks all radio-group-item descendants of w and sets checked=1 on the + * item whose "value" attribute equals w's "value", others to checked=0. + * + * Called automatically by ui_radio_group_set_value(). App code may also + * call it directly after appending new items at runtime to refresh the + * visual selection without changing the group's value. + */ +LCUI_API void ui_radio_group_update(ui_widget_t *w); + +INLINE const char *ui_radio_group_get_value(ui_widget_t *w) +{ + return ui_widget_get_attr(w, "value"); +} + +INLINE int ui_radio_group_set_value(ui_widget_t *w, const char *value) +{ + if (ui_widget_set_attr(w, "value", value) < 0) { + return -1; + } + ui_radio_group_update(w); + return 0; +} + +INLINE int ui_radio_group_item_get_checked(ui_widget_t *w) +{ + const char *v = ui_widget_get_attr(w, "checked"); + + return v && strcmp(v, "true") == 0; +} + +INLINE int ui_radio_group_item_set_checked(ui_widget_t *w, int checked) +{ + return ui_widget_set_attr(w, "checked", checked ? "true" : "false"); +} + +LCUI_END_HEADER + +#endif diff --git a/src/lcui_widgets.c b/src/lcui_widgets.c index fac033006..53c96301d 100644 --- a/src/lcui_widgets.c +++ b/src/lcui_widgets.c @@ -27,6 +27,7 @@ void lcui_widgets_init(void) ui_register_router_view(); ui_register_label(); ui_register_checkbox(); + ui_register_radio_group(); } void lcui_widgets_destroy(void) diff --git a/src/widgets/radio_group.c b/src/widgets/radio_group.c new file mode 100644 index 000000000..a2c1df67a --- /dev/null +++ b/src/widgets/radio_group.c @@ -0,0 +1,164 @@ +/* + * src/widgets/radio_group.c: -- RadioGroup and RadioGroupItem widgets + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include + +static ui_widget_prototype_t *ui_radio_group_prototype = NULL; +static ui_widget_prototype_t *ui_radio_group_item_prototype = NULL; + +static const char *ui_radio_group_css = "\ +radio-group {\ + display: inline-block;\ +}\ +radio-group-item {\ + display: inline-flex;\ + align-items: center;\ + justify-content: center;\ + width: 16px; height: 16px;\ + border: 1px solid #ccc;\ + border-radius: 8px;\ + vertical-align: middle;\ +}\ +radio-group-item:checked {\ + border-color: #1e88e5;\ +}\ +radio-group-item .indicator {\ + display: none;\ + width: 8px; height: 8px;\ + background-color: #1e88e5; border-radius: 4px;\ +}\ +radio-group-item:checked .indicator { display: block; }\ +radio-group-item:disabled { opacity: 0.5; }"; + +static bool ui_widget_is_radio_item(ui_widget_t *w) +{ + return w && w->proto == ui_radio_group_item_prototype; +} + +struct radio_update_args { + const char *target_value; +}; + +static void ui_radio_group_clear_each(ui_widget_t *w, void *arg) +{ + if (ui_widget_is_radio_item(w)) { + ui_radio_group_item_set_checked(w, 0); + } +} + +static void ui_radio_group_sync_each(ui_widget_t *w, void *arg) +{ + struct radio_update_args *args = arg; + const char *v; + + if (!ui_widget_is_radio_item(w)) { + return; + } + v = ui_widget_get_attr(w, "value"); + if (args->target_value && v && strcmp(args->target_value, v) == 0) { + ui_radio_group_item_set_checked(w, 1); + } else { + ui_radio_group_item_set_checked(w, 0); + } +} + +void ui_radio_group_update(ui_widget_t *w) +{ + struct radio_update_args args; + + args.target_value = ui_widget_get_attr(w, "value"); + ui_widget_each(w, ui_radio_group_sync_each, &args); +} + +static void ui_radio_group_on_click(ui_widget_t *w, ui_event_t *e, void *arg) +{ + ui_widget_t *target; + const char *value; + ui_event_t ev; + + target = e->target; + while (target && target != w) { + if (ui_widget_is_radio_item(target)) { + break; + } + target = target->parent; + } + if (!target || target == w || target->disabled) { + return; + } + ui_widget_each(w, ui_radio_group_clear_each, NULL); + ui_radio_group_item_set_checked(target, 1); + value = ui_widget_get_attr(target, "value"); + ui_widget_set_attr(w, "value", value); + ui_event_init(&ev, "change"); + ui_widget_emit_event(w, ev, NULL); +} + +static void ui_radio_group_on_init(ui_widget_t *w) +{ + ui_widget_on(w, "click", ui_radio_group_on_click, NULL); +} + +static void ui_radio_group_item_sync_status(ui_widget_t *w) +{ + if (ui_radio_group_item_get_checked(w)) { + ui_widget_add_status(w, "checked"); + } else { + ui_widget_remove_status(w, "checked"); + } +} + +static void ui_radio_group_item_on_set_attr(ui_widget_t *w, const char *name, + const char *value) +{ + if (strcmp(name, "checked") == 0) { + ui_radio_group_item_sync_status(w); + } +} + +static void ui_radio_group_item_on_init(ui_widget_t *w) +{ + ui_widget_t *indicator; + + indicator = ui_create_widget(NULL); + ui_widget_add_class(indicator, "indicator"); + ui_widget_append(w, indicator); + ui_radio_group_item_sync_status(w); +} + +ui_widget_t *ui_create_radio_group(void) +{ + return ui_create_widget_with_prototype(ui_radio_group_prototype); +} + +ui_widget_t *ui_create_radio_group_item(void) +{ + return ui_create_widget_with_prototype(ui_radio_group_item_prototype); +} + +void ui_register_radio_group(void) +{ + ui_radio_group_prototype = + ui_create_widget_prototype("radio-group", NULL); + ui_radio_group_prototype->init = ui_radio_group_on_init; + + ui_radio_group_item_prototype = + ui_create_widget_prototype("radio-group-item", NULL); + ui_radio_group_item_prototype->init = ui_radio_group_item_on_init; + ui_radio_group_item_prototype->setattr = + ui_radio_group_item_on_set_attr; + + ui_load_css_string(ui_radio_group_css, __FILE__); +} diff --git a/tests/integration/test_radio_group.c b/tests/integration/test_radio_group.c new file mode 100644 index 000000000..9a1929263 --- /dev/null +++ b/tests/integration/test_radio_group.c @@ -0,0 +1,282 @@ +/* + * tests/integration/test_radio_group.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found in the + * LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include + +static int g_change_count; + +static void on_radio_group_change(ui_widget_t *w, ui_event_t *e, void *arg) +{ + (void)w; + (void)e; + (void)arg; + ++g_change_count; +} + +static void test_value_roundtrip(void) +{ + ui_widget_t *g = ui_create_radio_group(); + + ctest_equal_str("should default to empty value", + ui_widget_get_attr(g, "value"), NULL); + + ui_radio_group_set_value(g, "comfortable"); + ctest_equal_str("should return set value", + ui_widget_get_attr(g, "value"), "comfortable"); + + ui_radio_group_set_value(g, NULL); + ctest_equal_str("should clear value when NULL", + ui_widget_get_attr(g, "value"), NULL); + + ui_widget_destroy(g); +} + +static void test_item_checked_roundtrip(void) +{ + ui_widget_t *item = ui_create_radio_group_item(); + + ctest_equal_int("should default to unchecked", + ui_radio_group_item_get_checked(item), 0); + + ui_radio_group_item_set_checked(item, 1); + ctest_equal_int("should return 1 after set_checked(1)", + ui_radio_group_item_get_checked(item), 1); + + ui_radio_group_item_set_checked(item, 0); + ctest_equal_int("should return 0 after set_checked(0)", + ui_radio_group_item_get_checked(item), 0); + + ui_widget_destroy(item); +} + +static void test_click_selects_item(void) +{ + ui_widget_t *g = ui_create_radio_group(); + ui_widget_t *item = ui_create_radio_group_item(); + ui_event_t ev; + + ui_widget_set_attr(item, "value", "default"); + ui_widget_append(g, item); + ui_widget_append(ui_root(), g); + + ui_event_init(&ev, "click"); + ui_widget_emit_event(item, ev, NULL); + + ctest_equal_int("clicked item should be checked", + ui_radio_group_item_get_checked(item), 1); + ctest_equal_str("group value should match clicked item", + ui_radio_group_get_value(g), "default"); + + ui_widget_destroy(g); +} + +static void test_click_emits_change(void) +{ + ui_widget_t *g = ui_create_radio_group(); + ui_widget_t *item = ui_create_radio_group_item(); + ui_event_t ev; + + g_change_count = 0; + ui_widget_on(g, "change", on_radio_group_change, NULL); + + ui_widget_append(g, item); + ui_widget_append(ui_root(), g); + + ui_event_init(&ev, "click"); + ui_widget_emit_event(item, ev, NULL); + + ctest_equal_int("should emit change once on group", g_change_count, 1); + + ui_widget_destroy(g); +} + +static void test_click_deselects_siblings(void) +{ + ui_widget_t *g = ui_create_radio_group(); + ui_widget_t *item1 = ui_create_radio_group_item(); + ui_widget_t *item2 = ui_create_radio_group_item(); + ui_event_t ev; + + ui_widget_set_attr(item1, "value", "default"); + ui_widget_set_attr(item2, "value", "compact"); + ui_widget_append(g, item1); + ui_widget_append(g, item2); + ui_widget_append(ui_root(), g); + + ui_event_init(&ev, "click"); + ui_widget_emit_event(item1, ev, NULL); + ctest_equal_int("item1 checked after first click", + ui_radio_group_item_get_checked(item1), 1); + ctest_equal_int("item2 still unchecked", + ui_radio_group_item_get_checked(item2), 0); + + ui_widget_emit_event(item2, ev, NULL); + ctest_equal_int("item1 unchecked after second click", + ui_radio_group_item_get_checked(item1), 0); + ctest_equal_int("item2 checked after second click", + ui_radio_group_item_get_checked(item2), 1); + ctest_equal_str("group value tracks latest selection", + ui_radio_group_get_value(g), "compact"); + + ui_widget_destroy(g); +} + +static void test_disabled_item_blocks_click(void) +{ + ui_widget_t *g = ui_create_radio_group(); + ui_widget_t *item = ui_create_radio_group_item(); + ui_event_t ev; + + ui_widget_append(g, item); + ui_widget_append(ui_root(), g); + ui_widget_set_disabled(item, true); + + ui_event_init(&ev, "click"); + ui_widget_emit_event(item, ev, NULL); + + ctest_equal_int("disabled item should stay unchecked", + ui_radio_group_item_get_checked(item), 0); + ctest_equal_str("group value should remain unset", + ui_radio_group_get_value(g), NULL); + + ui_widget_destroy(g); +} + +static void test_click_through_wrapper_div(void) +{ + ui_widget_t *g = ui_create_radio_group(); + ui_widget_t *wrap = ui_create_widget(NULL); + ui_widget_t *item = ui_create_radio_group_item(); + ui_event_t ev; + + ui_widget_set_attr(item, "value", "comfortable"); + ui_widget_append(wrap, item); + ui_widget_append(g, wrap); + ui_widget_append(ui_root(), g); + + ui_event_init(&ev, "click"); + ui_widget_emit_event(item, ev, NULL); + + ctest_equal_int("item inside wrapper div still gets selected", + ui_radio_group_item_get_checked(item), 1); + ctest_equal_str("group value updated from nested item", + ui_radio_group_get_value(g), "comfortable"); + + ui_widget_destroy(g); +} + +static void test_click_on_indicator_child(void) +{ + ui_widget_t *g = ui_create_radio_group(); + ui_widget_t *item = ui_create_radio_group_item(); + ui_widget_t *indicator; + ui_event_t ev; + + ui_widget_set_attr(item, "value", "compact"); + ui_widget_append(g, item); + ui_widget_append(ui_root(), g); + + indicator = ui_widget_get_child(item, 0); + + ui_event_init(&ev, "click"); + ui_widget_emit_event(indicator, ev, NULL); + + ctest_equal_int("clicking indicator child should select item", + ui_radio_group_item_get_checked(item), 1); + ctest_equal_str("group value updated from indicator click", + ui_radio_group_get_value(g), "compact"); + + ui_widget_destroy(g); +} + +static void test_update_syncs_items_to_value(void) +{ + ui_widget_t *g = ui_create_radio_group(); + ui_widget_t *item1 = ui_create_radio_group_item(); + ui_widget_t *item2 = ui_create_radio_group_item(); + + ui_widget_set_attr(item1, "value", "default"); + ui_widget_set_attr(item2, "value", "comfortable"); + ui_widget_append(g, item1); + ui_widget_append(g, item2); + ui_widget_append(ui_root(), g); + + ui_radio_group_set_value(g, "comfortable"); + ctest_equal_int("item matching value should be checked", + ui_radio_group_item_get_checked(item2), 1); + ctest_equal_int("item not matching value should be unchecked", + ui_radio_group_item_get_checked(item1), 0); + + ui_radio_group_set_value(g, "default"); + ctest_equal_int("after value change, new match should be checked", + ui_radio_group_item_get_checked(item1), 1); + ctest_equal_int("after value change, old match should be unchecked", + ui_radio_group_item_get_checked(item2), 0); + + ui_radio_group_set_value(g, NULL); + ctest_equal_int("NULL value clears all checks", + ui_radio_group_item_get_checked(item1), 0); + ctest_equal_int("NULL value clears all checks (other)", + ui_radio_group_item_get_checked(item2), 0); + + ui_widget_destroy(g); +} + +static void test_update_finds_items_in_nested_wrappers(void) +{ + ui_widget_t *g = ui_create_radio_group(); + ui_widget_t *item = ui_create_radio_group_item(); + ui_widget_t *wrap = ui_create_widget(NULL); + + ui_widget_set_attr(item, "value", "opt"); + ui_widget_append(wrap, item); + ui_widget_append(g, wrap); + ui_widget_append(ui_root(), g); + + ui_radio_group_set_value(g, "opt"); + ctest_equal_int("item nested in wrapper div should still be checked", + ui_radio_group_item_get_checked(item), 1); + + ui_radio_group_set_value(g, "other"); + ctest_equal_int( + "item nested in wrapper div should be unchecked when value differs", + ui_radio_group_item_get_checked(item), 0); + + ui_widget_destroy(g); +} + +void test_radio_group(void) +{ + lcui_init(); + + ctest_describe("radio-group value roundtrip", test_value_roundtrip); + ctest_describe("radio-group-item checked roundtrip", + test_item_checked_roundtrip); + ctest_describe("radio-group click selects item", + test_click_selects_item); + ctest_describe("radio-group click emits change", + test_click_emits_change); + ctest_describe("radio-group click deselects siblings", + test_click_deselects_siblings); + ctest_describe("radio-group disabled item blocks click", + test_disabled_item_blocks_click); + ctest_describe("radio-group click through wrapper div", + test_click_through_wrapper_div); + ctest_describe("radio-group click on indicator child", + test_click_on_indicator_child); + ctest_describe("radio-group update syncs items to value", + test_update_syncs_items_to_value); + ctest_describe("radio-group update finds items in nested wrappers", + test_update_finds_items_in_nested_wrappers); + + lcui_destroy(); +} diff --git a/tests/main.c b/tests/main.c index 83bdd8077..f7d0ec360 100644 --- a/tests/main.c +++ b/tests/main.c @@ -28,6 +28,7 @@ extern void test_scrollbar(void); extern void test_progress(void); extern void test_label(void); extern void test_checkbox(void); +extern void test_radio_group(void); static const ctest_suite_t suites[] = { { "settings", test_settings }, @@ -46,6 +47,7 @@ static const ctest_suite_t suites[] = { { "progress", test_progress }, { "label", test_label }, { "checkbox", test_checkbox }, + { "radio-group", test_radio_group }, { NULL, NULL } }; From fa37c80de18fabe3d1f273669274d1973f0b728d Mon Sep 17 00:00:00 2001 From: Liu Date: Thu, 2 Jul 2026 23:44:54 +0800 Subject: [PATCH 55/66] fix(pandagl): nested [color] tags should use innermost tag's color --- lib/pandagl/src/text/style_tag.c | 4 +- lib/pandagl/tests/main.c | 2 + lib/pandagl/tests/test_text_style_tag.c | 217 ++++++++++++++++++++++++ lib/pandagl/xmake.lua | 2 +- 4 files changed, 222 insertions(+), 3 deletions(-) create mode 100644 lib/pandagl/tests/test_text_style_tag.c diff --git a/lib/pandagl/src/text/style_tag.c b/lib/pandagl/src/text/style_tag.c index 076e33662..d32dd1e8a 100644 --- a/lib/pandagl/src/text/style_tag.c +++ b/lib/pandagl/src/text/style_tag.c @@ -50,7 +50,7 @@ pd_text_style_t *pd_style_tags_get_text_style(list_t *tags) style = malloc(sizeof(pd_text_style_t)); pd_text_style_init(style); /* 根据已经记录的各种样式,生成当前应有的文本样式 */ - for (list_each_reverse(node, tags)) { + for (list_each(node, tags)) { tag = node->data; switch (tag->id) { case PD_TEXT_STYLE_TYPE_COLOR: @@ -110,7 +110,7 @@ pd_text_style_t *pd_style_tags_get_text_style(list_t *tags) return style; } -/** 将指定标签的样式数据从队列中删除,只删除队列尾部第一个匹配的标签 */ +/** 将指定标签的样式数据从队列中删除,只删除队列头部第一个匹配的标签 */ static void pd_style_tags_remove(list_t *tags, int id) { pd_style_tag_t *tag; diff --git a/lib/pandagl/tests/main.c b/lib/pandagl/tests/main.c index efa424c84..f43b886aa 100644 --- a/lib/pandagl/tests/main.c +++ b/lib/pandagl/tests/main.c @@ -17,6 +17,7 @@ extern void test_pandagl_font_load(void); extern void test_pandagl_text_edit(void); extern void test_pandagl_font_cache(void); extern void test_pandagl_text_baseline(void); +extern void test_pandagl_text_style_tag(void); static const ctest_suite_t suites[] = { { "pandagl/canvas mix", test_pandagl_canvas_mix }, @@ -25,6 +26,7 @@ static const ctest_suite_t suites[] = { { "pandagl/text edit", test_pandagl_text_edit }, { "pandagl/font cache", test_pandagl_font_cache }, { "pandagl/text baseline", test_pandagl_text_baseline }, + { "pandagl/text style tag", test_pandagl_text_style_tag }, { NULL, NULL } }; diff --git a/lib/pandagl/tests/test_text_style_tag.c b/lib/pandagl/tests/test_text_style_tag.c new file mode 100644 index 000000000..3bffafb04 --- /dev/null +++ b/lib/pandagl/tests/test_text_style_tag.c @@ -0,0 +1,217 @@ +/* + * lib/pandagl/tests/test_text_style_tag.c + * + * Copyright (c) 2026, Liu Chao All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This file is part of LCUI, distributed under the MIT License found + * in the LICENSE.TXT file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include + +/* + * 这些用例覆盖 pd_text 在 style_tag 模式下对嵌套 [color] / [bgcolor] + * 标签的处理。bug 是 pd_style_tags_get_text_style 用了 list_each_reverse + * 反向遍历标签栈,导致嵌套时取到最旧(最外层)的颜色而不是最新(最内 + * 层)的颜色。例如对于 + * + * [color=#116329]<[color=#0550ae]Field[/color]>[/color] + * + * 修复前 "Field" 的 fore_color 是 #116329(外层绿色),修复后应是 + * #0550ae(内层蓝色)。这是 field-basic.tsx 渲染异常("全部字符都 + * 是 #116329")的根因。 + * + * 用例通过遍历 pd_text_t 的字符缓冲区(text->lines[0]->string[col]) + * 检查每个字符的 style->has_fore_color 与 fore_color.r/g/b 来断言, + * 不依赖字体渲染,因此不调用 pd_font_library_init。 + */ + +#define GREEN pd_color(255, 0x11, 0x63, 0x29) +#define BLUE pd_color(255, 0x05, 0x50, 0xae) +#define DBLUE pd_color(255, 0x0a, 0x30, 0x69) +#define RED pd_color(255, 0xcf, 0x22, 0x2e) + +static void assert_char_fore(pd_text_t *text, int col, pd_color_t expect, + const char *scope) +{ + pd_char_t *ch = text->lines[0]->string[col]; + char prefix[64]; + + if (!ch->style) { + snprintf(prefix, sizeof(prefix), "%s[%d] should have style", + scope, col); + ctest_equal_bool(prefix, false, true); + return; + } + snprintf(prefix, sizeof(prefix), "%s[%d] has_fore_color", scope, col); + ctest_equal_bool(prefix, ch->style->has_fore_color, true); + snprintf(prefix, sizeof(prefix), "%s[%d] fore.r", scope, col); + ctest_equal_int(prefix, ch->style->fore_color.r, expect.r); + snprintf(prefix, sizeof(prefix), "%s[%d] fore.g", scope, col); + ctest_equal_int(prefix, ch->style->fore_color.g, expect.g); + snprintf(prefix, sizeof(prefix), "%s[%d] fore.b", scope, col); + ctest_equal_int(prefix, ch->style->fore_color.b, expect.b); +} + +static void assert_char_back(pd_text_t *text, int col, pd_color_t expect, + const char *scope) +{ + pd_char_t *ch = text->lines[0]->string[col]; + char prefix[64]; + + if (!ch->style) { + snprintf(prefix, sizeof(prefix), "%s[%d] should have style", + scope, col); + ctest_equal_bool(prefix, false, true); + return; + } + snprintf(prefix, sizeof(prefix), "%s[%d] has_back_color", scope, col); + ctest_equal_bool(prefix, ch->style->has_back_color, true); + snprintf(prefix, sizeof(prefix), "%s[%d] back.r", scope, col); + ctest_equal_int(prefix, ch->style->back_color.r, expect.r); + snprintf(prefix, sizeof(prefix), "%s[%d] back.g", scope, col); + ctest_equal_int(prefix, ch->style->back_color.g, expect.g); + snprintf(prefix, sizeof(prefix), "%s[%d] back.b", scope, col); + ctest_equal_int(prefix, ch->style->back_color.b, expect.b); +} + +static pd_text_t *make_text_with_tag(const wchar_t *wstr) +{ + pd_text_t *text = pd_text_create(); + pd_text_set_style_tag(text, true); + pd_text_write(text, wstr, NULL); + return text; +} + +static void should_apply_single_color_tag(void) +{ + pd_text_t *text = make_text_with_tag(L"[color=#116329]hello[/color]"); + + ctest_equal_int("single color line length", text->lines[0]->length, 5); + for (int i = 0; i < 5; ++i) { + assert_char_fore(text, i, GREEN, "single"); + } + pd_text_destroy(text); +} + +static void should_use_innermost_color_in_two_level_nesting(void) +{ + pd_text_t *text = make_text_with_tag( + L"[color=#116329]<[color=#0550ae]Field[/color]>[/color]"); + + ctest_equal_int("two-level line length", text->lines[0]->length, 7); + assert_char_fore(text, 0, GREEN, "<"); + assert_char_fore(text, 1, BLUE, "Field[0]"); + assert_char_fore(text, 2, BLUE, "Field[1]"); + assert_char_fore(text, 3, BLUE, "Field[2]"); + assert_char_fore(text, 4, BLUE, "Field[3]"); + assert_char_fore(text, 5, BLUE, "Field[4]"); + assert_char_fore(text, 6, GREEN, ">"); + pd_text_destroy(text); +} + +static void should_use_innermost_color_in_three_level_nesting(void) +{ + pd_text_t *text = make_text_with_tag( + L"[color=#116329]A[color=#0550ae]B[color=#0a3069]C" + L"[/color][/color][/color]"); + + ctest_equal_int("three-level line length", text->lines[0]->length, 3); + assert_char_fore(text, 0, GREEN, "A"); + assert_char_fore(text, 1, BLUE, "B"); + assert_char_fore(text, 2, DBLUE, "C"); + pd_text_destroy(text); +} + +static void should_handle_field_basic_flex_1_line(void) +{ + pd_text_t *text = make_text_with_tag( + L"[color=#116329]<[color=#0550ae]Field[/color] " + L"[color=#0550ae]className[/color]=[color=#0a3069]" + L"\"flex-1\"[/color]>[/color]"); + + /* 期望字符序列与染色(0-indexed): + * '<' (0) 绿 + * 'Field' (1-5) 蓝 + * ' ' (6) 绿 + * 'className' (7-15) 蓝 + * '=' (16) 绿 + * '"' (17) 深蓝 + * 'flex-1' (18-23) 深蓝 + * '"' (24) 深蓝 + * '>' (25) 绿 + */ + ctest_equal_int("field basic line length", text->lines[0]->length, 26); + + assert_char_fore(text, 0, GREEN, "<"); + for (int i = 1; i <= 5; ++i) { + assert_char_fore(text, i, BLUE, "Field"); + } + assert_char_fore(text, 6, GREEN, "space"); + for (int i = 7; i <= 15; ++i) { + assert_char_fore(text, i, BLUE, "className"); + } + assert_char_fore(text, 16, GREEN, "eq"); + for (int i = 17; i <= 24; ++i) { + assert_char_fore(text, i, DBLUE, "string"); + } + assert_char_fore(text, 25, GREEN, ">"); + + pd_text_destroy(text); +} + +static void should_reapply_color_after_sibling_close(void) +{ + pd_text_t *text = make_text_with_tag( + L"[color=#0550ae]A[/color][color=#cf222e]B[/color]"); + + ctest_equal_int("sibling line length", text->lines[0]->length, 2); + assert_char_fore(text, 0, BLUE, "A"); + assert_char_fore(text, 1, RED, "B"); + pd_text_destroy(text); +} + +static void should_use_innermost_bgcolor_in_two_level_nesting(void) +{ + pd_text_t *text = make_text_with_tag( + L"[bgcolor=#116329]<[bgcolor=#0550ae]X[/bgcolor]>[/bgcolor]"); + + ctest_equal_int("nested bgcolor line length", text->lines[0]->length, + 3); + assert_char_back(text, 1, BLUE, "X"); + pd_text_destroy(text); +} + +static void should_keep_color_and_bgcolor_independent_when_nested(void) +{ + pd_text_t *text = make_text_with_tag( + L"[bgcolor=#116329][color=#0550ae]X[/color][/bgcolor]"); + + ctest_equal_int("bg+fg nested line length", text->lines[0]->length, 1); + assert_char_fore(text, 0, BLUE, "X.fore"); + assert_char_back(text, 0, GREEN, "X.back"); + pd_text_destroy(text); +} + +void test_pandagl_text_style_tag(void) +{ + ctest_describe("single color tag", should_apply_single_color_tag); + ctest_describe("nested color two levels", + should_use_innermost_color_in_two_level_nesting); + ctest_describe("nested color three levels", + should_use_innermost_color_in_three_level_nesting); + ctest_describe("field basic flex-1 line", + should_handle_field_basic_flex_1_line); + ctest_describe("sibling color reopen", + should_reapply_color_after_sibling_close); + ctest_describe("nested bgcolor two levels", + should_use_innermost_bgcolor_in_two_level_nesting); + ctest_describe("nested color and bgcolor sibling", + should_keep_color_and_bgcolor_independent_when_nested); +} diff --git a/lib/pandagl/xmake.lua b/lib/pandagl/xmake.lua index 1b1fd8c63..aaa191a0a 100644 --- a/lib/pandagl/xmake.lua +++ b/lib/pandagl/xmake.lua @@ -63,7 +63,7 @@ target("pandagl-tests") set_kind("binary") set_group("tests") set_rundir("tests/fixtures") - add_files("tests/main.c", "tests/test_canvas_mix.c", "tests/test_image_reader.c", "tests/test_font_load.c", "tests/test_text_edit.c", "tests/test_font_cache.c", "tests/test_text_baseline.c") + add_files("tests/main.c", "tests/test_canvas_mix.c", "tests/test_image_reader.c", "tests/test_font_load.c", "tests/test_text_edit.c", "tests/test_font_cache.c", "tests/test_text_baseline.c", "tests/test_text_style_tag.c") add_deps("ctest", "pandagl") add_rules("tests.runnable") add_tests("default", {group = "tests"}) From 4a3a65e1e14dd6e5c78b609317565e1fec583184 Mon Sep 17 00:00:00 2001 From: rewine Date: Thu, 16 Jul 2026 15:36:15 +0800 Subject: [PATCH 56/66] fix: build for string-render example (#331) --- lib/pandagl/examples/string-render/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pandagl/examples/string-render/src/main.c b/lib/pandagl/examples/string-render/src/main.c index cac1dcc22..645537aed 100644 --- a/lib/pandagl/examples/string-render/src/main.c +++ b/lib/pandagl/examples/string-render/src/main.c @@ -26,7 +26,7 @@ int main(void) pd_canvas_create(&img, 320, 240); pd_canvas_fill(&img, pd_rgb(240, 240, 240)); - pd_text_style_Init(&txtstyle); + pd_text_style_init(&txtstyle); txtstyle.pixel_size = 24; txtstyle.has_pixel_size = true; From fb15837529342a145bd536b5430d8056cc262f0d Mon Sep 17 00:00:00 2001 From: rewine Date: Sat, 23 May 2026 17:37:01 +0800 Subject: [PATCH 57/66] feat(ptk): add preliminary Wayland backend implementation --- lib/ptk/include/ptk/types.h | 4 +- lib/ptk/rules/xmake.lua | 27 ++ lib/ptk/src/linux/app.c | 23 +- lib/ptk/src/linux/ime.c | 25 +- lib/ptk/src/linux/wayland_internal.h | 115 +++++++ lib/ptk/src/linux/waylandapp.h | 9 + lib/ptk/src/linux/waylandapp_core.c | 316 +++++++++++++++++++ lib/ptk/src/linux/waylandapp_input.c | 430 +++++++++++++++++++++++++ lib/ptk/src/linux/waylandapp_output.c | 56 ++++ lib/ptk/src/linux/waylandapp_window.c | 432 ++++++++++++++++++++++++++ lib/ptk/xmake.lua | 16 +- 11 files changed, 1441 insertions(+), 12 deletions(-) create mode 100644 lib/ptk/rules/xmake.lua create mode 100644 lib/ptk/src/linux/wayland_internal.h create mode 100644 lib/ptk/src/linux/waylandapp.h create mode 100644 lib/ptk/src/linux/waylandapp_core.c create mode 100644 lib/ptk/src/linux/waylandapp_input.c create mode 100644 lib/ptk/src/linux/waylandapp_output.c create mode 100644 lib/ptk/src/linux/waylandapp_window.c diff --git a/lib/ptk/include/ptk/types.h b/lib/ptk/include/ptk/types.h index e3085cd83..711b5aace 100644 --- a/lib/ptk/include/ptk/types.h +++ b/lib/ptk/include/ptk/types.h @@ -1,4 +1,4 @@ -/* +/* * lib/ptk/include/ptk/types.h * * Copyright (c) 2023-2026, Liu Chao All rights reserved. @@ -22,6 +22,7 @@ typedef enum { PTK_APP_ID_UNKNOWN, PTK_APP_ID_LINUX, PTK_APP_ID_LINUX_X11, + PTK_APP_ID_LINUX_WAYLAND, PTK_APP_ID_WIN_DESKTOP, PTK_APP_ID_UWP } ptk_app_id_t; @@ -289,6 +290,7 @@ typedef struct ptk_window_driver { void (*get_position)(ptk_window_t *, int *, int *); void (*set_maximized)(ptk_window_t *, bool); void *(*get_handle)(ptk_window_t *); + unsigned (*get_dpi)(ptk_window_t *); int (*get_width)(ptk_window_t *); int (*get_height)(ptk_window_t *); bool (*is_maximized)(ptk_window_t *); diff --git a/lib/ptk/rules/xmake.lua b/lib/ptk/rules/xmake.lua new file mode 100644 index 000000000..2959b9a7b --- /dev/null +++ b/lib/ptk/rules/xmake.lua @@ -0,0 +1,27 @@ +rule("wayland.protocol") + on_load(function(target) + if target:sourcebatches()["wayland.protocol"] then + local generatedir = path.join(target:autogendir(), "rules", "wayland") + target:add("includedirs", generatedir) + end + end) + + before_buildcmd_file(function(target, batchcmds, sourcefile, opt) + local generatedir = path.join(target:autogendir(), "rules", "wayland") + local basename = path.basename(sourcefile) + local headerfile = path.join(generatedir, basename .. "-client-protocol.h") + local sourcefile_c = path.join(generatedir, basename .. "-protocol.c") + local objectfile = target:objectfile(sourcefile_c) + local scanner = os.getenv("WAYLAND_SCANNER") or "/usr/bin/wayland-scanner" + local code_mode = target:kind() == "shared" and "public-code" or "private-code" + + table.insert(target:objectfiles(), objectfile) + batchcmds:show_progress(opt.progress, "${color.build.object}wayland-scanner %s", sourcefile) + batchcmds:mkdir(generatedir) + batchcmds:vrunv(scanner, {"client-header", path(sourcefile), path(headerfile)}) + batchcmds:vrunv(scanner, {code_mode, path(sourcefile), path(sourcefile_c)}) + batchcmds:compile(sourcefile_c, objectfile) + batchcmds:add_depfiles(sourcefile) + batchcmds:set_depmtime(os.mtime(objectfile)) + batchcmds:set_depcache(target:dependfile(objectfile)) + end) diff --git a/lib/ptk/src/linux/app.c b/lib/ptk/src/linux/app.c index 7c3ddb5a7..aaa94ceb8 100644 --- a/lib/ptk/src/linux/app.c +++ b/lib/ptk/src/linux/app.c @@ -16,6 +16,10 @@ #include "keyboard.h" #include "fbapp.h" #include "x11app.h" + +#ifdef PTK_HAS_WAYLAND +#include "waylandapp.h" +#endif #include "x11clipboard.h" #ifdef PTK_LINUX @@ -111,7 +115,9 @@ void *ptk_window_get_handle(ptk_window_t *wnd) unsigned ptk_window_get_dpi(ptk_window_t *wnd) { - // TODO: get dpi from x11 window or framebuffer? + if (linux_app.window.get_dpi) { + return linux_app.window.get_dpi(wnd); + } return 96; } @@ -199,7 +205,20 @@ ptk_app_id_t ptk_get_app_id(void) int ptk_app_init(const wchar_t *name) { linux_app.id = PTK_APP_ID_LINUX; +#ifdef PTK_HAS_WAYLAND + ptk_waylandapp_driver_init(&linux_app.app); + ptk_waylandwindow_driver_init(&linux_app.window); + if (linux_app.app.init(name) == 0) { + logger_debug("[app] use engine: waylandapp\n"); + linux_app.id = PTK_APP_ID_LINUX_WAYLAND; + linux_app.active = true; + return 0; + } + memset(&linux_app.app, 0, sizeof(linux_app.app)); + memset(&linux_app.window, 0, sizeof(linux_app.window)); +#endif #ifdef PTK_HAS_LIBX11 + ptk_x11app_driver_init(&linux_app.app); ptk_x11window_driver_init(&linux_app.window); if (linux_app.app.init(name) == 0) { @@ -229,7 +248,7 @@ int ptk_app_destroy(void) return -1; } linux_app.active = false; - if (linux_app.id != PTK_APP_ID_LINUX_X11) { + if (linux_app.id == PTK_APP_ID_LINUX) { ptk_linux_mouse_destroy(); ptk_linux_keyboard_destroy(); } diff --git a/lib/ptk/src/linux/ime.c b/lib/ptk/src/linux/ime.c index 0447c787a..f04af5011 100644 --- a/lib/ptk/src/linux/ime.c +++ b/lib/ptk/src/linux/ime.c @@ -1,4 +1,4 @@ -/* +/* * lib/ptk/src/linux/ime.c: -- The input method engine support for linux. * * Copyright (c) 2018-2026, Liu chao All rights reserved. @@ -17,6 +17,14 @@ #include #include +/* Shared by both X11 and Wayland: convert KEYPRESS key.code (Unicode codepoint) + * to a wchar_t and commit it through the IME layer. */ +static void on_key_press(ptk_event_t *e, void *arg) +{ + wchar_t text[2] = { (wchar_t)e->key.code, 0 }; + ptk_ime_commit(text, 2); +} + #ifdef PTK_HAS_LIBX11 static bool ptk_x11ime_process_key(int key, bool pressed) @@ -30,12 +38,6 @@ static void ptk_x11ime_to_text(int ch) ptk_ime_commit(text, 2); } -static void on_key_press(ptk_event_t *e, void *arg) -{ - wchar_t text[2] = { e->key.code, 0 }; - ptk_ime_commit(text, 2); -} - static bool ptk_x11ime_open(void) { ptk_on_event(PTK_EVENT_KEYPRESS, on_key_press, NULL); @@ -62,6 +64,15 @@ int ptk_ime_add_linux(void) return ptk_ime_add("LCUI X11 Input Method", &handler); } #endif + if (ptk_get_app_id() == PTK_APP_ID_LINUX_WAYLAND) { + /* Wayland backend: PTK_EVENT_KEYPRESS carries the Unicode + * codepoint in key.code (written by xkb_state_key_get_utf32). + * Register directly — no full IME handler needed for basic + * ASCII/Unicode input without a compositor text-input protocol. + */ + ptk_on_event(PTK_EVENT_KEYPRESS, on_key_press, NULL); + return 0; + } return -1; } diff --git a/lib/ptk/src/linux/wayland_internal.h b/lib/ptk/src/linux/wayland_internal.h new file mode 100644 index 000000000..abd3805a3 --- /dev/null +++ b/lib/ptk/src/linux/wayland_internal.h @@ -0,0 +1,115 @@ +#ifndef PTK_LINUX_WAYLAND_INTERNAL_H +#define PTK_LINUX_WAYLAND_INTERNAL_H + +#if defined(PTK_LINUX) && defined(PTK_HAS_WAYLAND) + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ptk.h" +#include "keyboard.h" +#include "waylandapp.h" +#include "xdg-shell-client-protocol.h" +#include "xdg-decoration-unstable-v1-client-protocol.h" + +#ifndef WL_KEYBOARD_KEY_STATE_REPEATED +#define WL_KEYBOARD_KEY_STATE_REPEATED 2 +#endif + +#define WAYLAND_DEFAULT_SCREEN_WIDTH 1280 +#define WAYLAND_DEFAULT_SCREEN_HEIGHT 720 + +typedef struct ptk_window { + struct wl_surface *surface; + struct xdg_surface *xdg_surface; + struct xdg_toplevel *xdg_toplevel; + struct zxdg_toplevel_decoration_v1 *decoration; + struct wl_buffer *buffer; + void *buffer_data; + size_t buffer_size; + int width; + int height; + bool configured; + int min_width; + int min_height; + int max_width; + int max_height; + /** Full-window canvas wrapping buffer_data (external memory, not + * owned by pandagl). Used as the quote source in begin_paint. */ + pd_canvas_t canvas; + pd_context_t *paint_ctx; + list_node_t node; +} ptk_window_t; + +typedef struct ptk_wayland_app { + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_shm *shm; + struct zxdg_decoration_manager_v1 *decoration_manager; + struct xdg_wm_base *wm_base; + struct wl_output *output; + struct wl_seat *seat; + struct wl_pointer *pointer; + struct wl_keyboard *keyboard; + ptk_window_t *pointer_focus; + ptk_window_t *keyboard_focus; + double pointer_x; + double pointer_y; + list_t windows; + int exit_code; + int screen_width; + int screen_height; + int output_scale; + + struct xkb_context *xkb_context; + struct xkb_keymap *xkb_map; + struct xkb_state *xkb_state; + uint32_t shift_mask; + uint32_t ctrl_mask; + uint32_t alt_mask; + uint32_t meta_mask; + uint32_t modifiers; + + /* Key repeat parameters from wl_keyboard.repeat_info (rate=0 means + * disabled) */ + int repeat_rate; /* characters/second */ + int repeat_delay; /* milliseconds before first repeat */ + + struct wl_cursor_theme *cursor_theme; + struct wl_cursor *default_cursor; + struct wl_surface *cursor_surface; + + bool running; +} ptk_wayland_app_t; + +extern ptk_wayland_app_t wl_app; + +extern const struct wl_output_listener output_listener; +extern const struct wl_seat_listener seat_listener; +extern const struct wl_registry_listener registry_listener; +extern const struct xdg_wm_base_listener wm_base_listener; +extern const struct xdg_surface_listener xdg_surface_listener; +extern const struct xdg_toplevel_listener xdg_toplevel_listener; + +ptk_window_t *ptk_waylandapp_get_window(void *handle); +void ptk_waylandwindow_destroy_buffer(ptk_window_t *wnd); +void ptk_waylandwindow_post_size_event(ptk_window_t *wnd); +ptk_window_t *ptk_waylandwindow_create(const wchar_t *title, int x, int y, + int width, int height, + ptk_window_t *parent); + +#endif /* PTK_LINUX && PTK_HAS_WAYLAND */ + +#endif diff --git a/lib/ptk/src/linux/waylandapp.h b/lib/ptk/src/linux/waylandapp.h new file mode 100644 index 000000000..48760aea1 --- /dev/null +++ b/lib/ptk/src/linux/waylandapp.h @@ -0,0 +1,9 @@ +#ifndef LIB_PTK_SRC_LINUX_WAYLANDAPP_H +#define LIB_PTK_SRC_LINUX_WAYLANDAPP_H + +#include "ptk/types.h" + +void ptk_waylandapp_driver_init(ptk_app_driver_t *driver); +void ptk_waylandwindow_driver_init(ptk_window_driver_t *driver); + +#endif diff --git a/lib/ptk/src/linux/waylandapp_core.c b/lib/ptk/src/linux/waylandapp_core.c new file mode 100644 index 000000000..72f8b038c --- /dev/null +++ b/lib/ptk/src/linux/waylandapp_core.c @@ -0,0 +1,316 @@ +#if defined(PTK_LINUX) && defined(PTK_HAS_WAYLAND) + +#include "wayland_internal.h" + +ptk_wayland_app_t wl_app; + +ptk_window_t *ptk_waylandapp_get_window(void *handle) +{ + list_node_t *node; + + for (list_each(node, &wl_app.windows)) { + ptk_window_t *wnd = node->data; + + if (wnd && wnd->surface == handle) { + return wnd; + } + } + return NULL; +} + +static void ptk_waylandapp_on_registry_global(void *data, + struct wl_registry *registry, + uint32_t name, + const char *interface, + uint32_t version) +{ + if (strcmp(interface, wl_compositor_interface.name) == 0) { + wl_app.compositor = wl_registry_bind( + registry, name, &wl_compositor_interface, 4); + return; + } + if (strcmp(interface, wl_shm_interface.name) == 0) { + wl_app.shm = + wl_registry_bind(registry, name, &wl_shm_interface, 1); + return; + } + if (strcmp(interface, xdg_wm_base_interface.name) == 0) { + uint32_t bind_version = version < 1 ? version : 1; + wl_app.wm_base = wl_registry_bind( + registry, name, &xdg_wm_base_interface, bind_version); + return; + } + if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) { + wl_app.decoration_manager = wl_registry_bind( + registry, name, &zxdg_decoration_manager_v1_interface, 1); + return; + } + if (strcmp(interface, wl_output_interface.name) == 0 && + !wl_app.output) { + wl_app.output = + wl_registry_bind(registry, name, &wl_output_interface, 2); + wl_output_add_listener(wl_app.output, &output_listener, NULL); + return; + } + if (strcmp(interface, wl_seat_interface.name) == 0 && !wl_app.seat) { + wl_app.seat = + wl_registry_bind(registry, name, &wl_seat_interface, 5); + wl_seat_add_listener(wl_app.seat, &seat_listener, NULL); + return; + } +} + +static void ptk_waylandapp_on_registry_global_remove( + void *data, struct wl_registry *registry, uint32_t name) +{ +} + +const struct wl_registry_listener registry_listener = { + ptk_waylandapp_on_registry_global, + ptk_waylandapp_on_registry_global_remove +}; + +static int ptk_waylandapp_poll_events(int timeout_ms, bool dispatch_all) +{ + struct pollfd pfd; + int result; + + result = wl_display_dispatch_pending(wl_app.display); + if (result < 0) { + return -1; + } + if (dispatch_all && result > 0) { + do { + result = wl_display_dispatch_pending(wl_app.display); + } while (result > 0); + if (result < 0) { + return -1; + } + } + if (wl_display_flush(wl_app.display) < 0 && errno != EAGAIN) { + return -1; + } + + pfd.fd = wl_display_get_fd(wl_app.display); + pfd.events = POLLIN; + pfd.revents = 0; + result = poll(&pfd, 1, timeout_ms); + if (result <= 0) { + return result; + } + if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) { + return -1; + } + if (!(pfd.revents & POLLIN)) { + return 0; + } + result = wl_display_dispatch(wl_app.display); + if (result < 0) { + return -1; + } + if (!dispatch_all) { + return result; + } + while ((result = wl_display_dispatch_pending(wl_app.display)) > 0) { + } + return result < 0 ? -1 : 1; +} + +static int ptk_waylandapp_init(const wchar_t *name) +{ + memset(&wl_app, 0, sizeof(wl_app)); + wl_app.output_scale = 1; + wl_app.display = wl_display_connect(NULL); + if (!wl_app.display) { + logger_error("[wayland] wl_display_connect() failed\n"); + return -1; + } + wl_app.screen_width = WAYLAND_DEFAULT_SCREEN_WIDTH; + wl_app.screen_height = WAYLAND_DEFAULT_SCREEN_HEIGHT; + wl_app.registry = wl_display_get_registry(wl_app.display); + if (!wl_app.registry) { + logger_error("[wayland] wl_display_get_registry() failed\n"); + wl_display_disconnect(wl_app.display); + wl_app.display = NULL; + return -1; + } + list_create(&wl_app.windows); + wl_registry_add_listener(wl_app.registry, ®istry_listener, NULL); + if (wl_display_roundtrip(wl_app.display) < 0) { + logger_error("[wayland] wl_display_roundtrip() failed during " + "registry init\n"); + ptk_waylandapp_destroy(); + return -1; + } + if (!wl_app.compositor || !wl_app.shm || !wl_app.wm_base) { + logger_error("[wayland] missing globals: compositor=%p shm=%p " + "wm_base=%p\n", + wl_app.compositor, wl_app.shm, wl_app.wm_base); + ptk_waylandapp_destroy(); + return -1; + } + xdg_wm_base_add_listener(wl_app.wm_base, &wm_base_listener, NULL); + wl_app.running = true; + wl_app.exit_code = 0; + return 0; +} + +static int ptk_waylandapp_destroy(void) +{ + list_node_t *node, *next; + ptk_window_t *wnd; + + for (node = wl_app.windows.head.next; node; node = next) { + next = node->next; + wnd = node->data; + if (wnd) { + if (wnd->decoration) { + zxdg_toplevel_decoration_v1_destroy( + wnd->decoration); + } + if (wnd->xdg_toplevel) { + xdg_toplevel_destroy(wnd->xdg_toplevel); + } + if (wnd->xdg_surface) { + xdg_surface_destroy(wnd->xdg_surface); + } + if (wnd->surface) { + wl_surface_destroy(wnd->surface); + } + ptk_waylandwindow_destroy_buffer(wnd); + free(wnd->paint_ctx); + free(wnd); + } + } + list_create(&wl_app.windows); + if (wl_app.pointer) { + wl_pointer_destroy(wl_app.pointer); + } + if (wl_app.cursor_surface) { + wl_surface_destroy(wl_app.cursor_surface); + wl_app.cursor_surface = NULL; + } + if (wl_app.cursor_theme) { + wl_cursor_theme_destroy(wl_app.cursor_theme); + wl_app.cursor_theme = NULL; + wl_app.default_cursor = NULL; + } + if (wl_app.keyboard) { + wl_keyboard_destroy(wl_app.keyboard); + } + if (wl_app.xkb_state) { + xkb_state_unref(wl_app.xkb_state); + wl_app.xkb_state = NULL; + } + if (wl_app.xkb_map) { + xkb_keymap_unref(wl_app.xkb_map); + wl_app.xkb_map = NULL; + } + if (wl_app.xkb_context) { + xkb_context_unref(wl_app.xkb_context); + wl_app.xkb_context = NULL; + } + if (wl_app.seat) { + wl_seat_destroy(wl_app.seat); + } + if (wl_app.output) { + wl_output_destroy(wl_app.output); + } + if (wl_app.decoration_manager) { + zxdg_decoration_manager_v1_destroy(wl_app.decoration_manager); + } + if (wl_app.wm_base) { + xdg_wm_base_destroy(wl_app.wm_base); + } + if (wl_app.shm) { + wl_shm_destroy(wl_app.shm); + } + if (wl_app.compositor) { + wl_compositor_destroy(wl_app.compositor); + } + if (wl_app.registry) { + wl_registry_destroy(wl_app.registry); + } + if (wl_app.display) { + wl_display_disconnect(wl_app.display); + } + memset(&wl_app, 0, sizeof(wl_app)); + return 0; +} + +static int ptk_waylandapp_process_events(ptk_process_events_option_t option) +{ + int result = 0; + + wl_app.exit_code = 0; + if (option == PTK_PROCESS_EVENTS_ONE_IF_PRESENT || + option == PTK_PROCESS_EVENTS_ALL_IF_PRESENT) { + ptk_tick(); + ptk_process_events(); + result = ptk_waylandapp_poll_events( + 0, option == PTK_PROCESS_EVENTS_ALL_IF_PRESENT); + ptk_process_events(); + return result < 0 ? -1 : wl_app.exit_code; + } + while (wl_app.running) { + ptk_tick(); + ptk_process_events(); + result = ptk_waylandapp_poll_events(1, true); + if (result < 0) { + break; + } + ptk_process_events(); + } + return wl_app.exit_code; +} + +static void ptk_waylandapp_present(void) +{ + wl_display_flush(wl_app.display); +} + +static void ptk_waylandapp_exit(int exit_code) +{ + wl_app.running = false; + wl_app.exit_code = exit_code; +} + +static int ptk_waylandapp_on_event(int type, ptk_native_event_handler_t handler, + void *data) +{ + return -1; +} + +static int ptk_waylandapp_off_event(int type, + ptk_native_event_handler_t handler) +{ + return -1; +} + +static int ptk_waylandapp_get_screen_width(void) +{ + return wl_app.screen_width / wl_app.output_scale; +} + +static int ptk_waylandapp_get_screen_height(void) +{ + return wl_app.screen_height / wl_app.output_scale; +} + +void ptk_waylandapp_driver_init(ptk_app_driver_t *driver) +{ + memset(driver, 0, sizeof(*driver)); + driver->init = ptk_waylandapp_init; + driver->destroy = ptk_waylandapp_destroy; + driver->process_events = ptk_waylandapp_process_events; + driver->on_event = ptk_waylandapp_on_event; + driver->off_event = ptk_waylandapp_off_event; + driver->get_screen_width = ptk_waylandapp_get_screen_width; + driver->get_screen_height = ptk_waylandapp_get_screen_height; + driver->create_window = ptk_waylandwindow_create; + driver->get_window = ptk_waylandapp_get_window; + driver->present = ptk_waylandapp_present; + driver->exit = ptk_waylandapp_exit; +} + +#endif /* PTK_LINUX && PTK_HAS_WAYLAND */ diff --git a/lib/ptk/src/linux/waylandapp_input.c b/lib/ptk/src/linux/waylandapp_input.c new file mode 100644 index 000000000..810371622 --- /dev/null +++ b/lib/ptk/src/linux/waylandapp_input.c @@ -0,0 +1,430 @@ +#if defined(PTK_LINUX) && defined(PTK_HAS_WAYLAND) + +#include "wayland_internal.h" + +static void ptk_waylandapp_on_pointer_enter( + void *data, struct wl_pointer *wl_pointer, uint32_t serial, + struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) +{ + wl_app.pointer_focus = ptk_waylandapp_get_window(surface); + /* surface_x/y are in logical pixels (compositor coordinate space); + * store physical coords internally for cursor hotspot math */ + wl_app.pointer_x = wl_fixed_to_double(surface_x); + wl_app.pointer_y = wl_fixed_to_double(surface_y); + + if (wl_app.default_cursor && wl_app.cursor_surface) { + struct wl_cursor_image *image = + wl_app.default_cursor->images[0]; + wl_pointer_set_cursor(wl_pointer, serial, wl_app.cursor_surface, + image->hotspot_x / wl_app.output_scale, + image->hotspot_y / wl_app.output_scale); + wl_surface_set_buffer_scale(wl_app.cursor_surface, + wl_app.output_scale); + wl_surface_attach(wl_app.cursor_surface, + wl_cursor_image_get_buffer(image), 0, 0); + wl_surface_damage_buffer(wl_app.cursor_surface, 0, 0, + image->width, image->height); + wl_surface_commit(wl_app.cursor_surface); + } + + /* Wayland enter does not emit motion, but LCUI needs initial coordinate + * state applied immediately */ + if (wl_app.pointer_focus) { + ptk_event_t e = { 0 }; + e.type = PTK_EVENT_MOUSEMOVE; + e.window = wl_app.pointer_focus; + e.mouse.x = (int)wl_app.pointer_x; + e.mouse.y = (int)wl_app.pointer_y; + ptk_post_event(&e); + } +} + +static void ptk_waylandapp_on_pointer_leave(void *data, + struct wl_pointer *wl_pointer, + uint32_t serial, + struct wl_surface *surface) +{ + wl_app.pointer_focus = NULL; +} + +static void ptk_waylandapp_on_pointer_motion(void *data, + struct wl_pointer *wl_pointer, + uint32_t time, + wl_fixed_t surface_x, + wl_fixed_t surface_y) +{ + ptk_event_t e = { 0 }; + + /* surface_x/y are in logical pixels (compositor coordinate space) */ + wl_app.pointer_x = wl_fixed_to_double(surface_x); + wl_app.pointer_y = wl_fixed_to_double(surface_y); + + if (wl_app.pointer_focus) { + e.type = PTK_EVENT_MOUSEMOVE; + e.window = wl_app.pointer_focus; + e.mouse.x = (int)wl_app.pointer_x; + e.mouse.y = (int)wl_app.pointer_y; + ptk_post_event(&e); + } +} + +static void ptk_waylandapp_on_pointer_button(void *data, + struct wl_pointer *wl_pointer, + uint32_t serial, uint32_t time, + uint32_t button, uint32_t state) +{ + ptk_event_t e = { 0 }; + + if (wl_app.pointer_focus) { + e.type = state == WL_POINTER_BUTTON_STATE_PRESSED + ? PTK_EVENT_MOUSEDOWN + : PTK_EVENT_MOUSEUP; + e.window = wl_app.pointer_focus; + e.mouse.x = (int)wl_app.pointer_x; + e.mouse.y = (int)wl_app.pointer_y; + if (button == (0x110)) { /* BTN_LEFT */ + e.mouse.button = MOUSE_BUTTON_LEFT; + } else if (button == (0x111)) { /* BTN_RIGHT */ + e.mouse.button = MOUSE_BUTTON_RIGHT; + } else if (button == (0x112)) { /* BTN_MIDDLE */ + e.mouse.button = MOUSE_BUTTON_MIDDLE; + } + ptk_post_event(&e); + } +} + +static void ptk_waylandapp_on_pointer_axis(void *data, + struct wl_pointer *wl_pointer, + uint32_t time, uint32_t axis, + wl_fixed_t value) +{ + ptk_event_t e = { 0 }; + + if (wl_app.pointer_focus) { + e.type = PTK_EVENT_WHEEL; + e.window = wl_app.pointer_focus; + e.wheel.delta_mode = APP_WHEEL_DELTA_PIXEL; + if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { + e.wheel.delta_y = (int)wl_fixed_to_double(value); + } else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { + e.wheel.delta_x = (int)wl_fixed_to_double(value); + } + ptk_post_event(&e); + } +} + +static void ptk_waylandapp_on_pointer_frame(void *data, + struct wl_pointer *wl_pointer) +{ +} + +static void ptk_waylandapp_on_pointer_axis_source(void *data, + struct wl_pointer *wl_pointer, + uint32_t axis_source) +{ +} + +static void ptk_waylandapp_on_pointer_axis_stop(void *data, + struct wl_pointer *wl_pointer, + uint32_t time, uint32_t axis) +{ +} + +static void ptk_waylandapp_on_pointer_axis_discrete( + void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) +{ +} + +static const struct wl_pointer_listener pointer_listener = { + .enter = ptk_waylandapp_on_pointer_enter, + .leave = ptk_waylandapp_on_pointer_leave, + .motion = ptk_waylandapp_on_pointer_motion, + .button = ptk_waylandapp_on_pointer_button, + .axis = ptk_waylandapp_on_pointer_axis, + .frame = ptk_waylandapp_on_pointer_frame, + .axis_source = ptk_waylandapp_on_pointer_axis_source, + .axis_stop = ptk_waylandapp_on_pointer_axis_stop, + .axis_discrete = ptk_waylandapp_on_pointer_axis_discrete, +}; + +/* Map an XKB keysym to LCUI's keycode (Web/Windows-style virtual key codes). */ +static int ptk_waylandapp_keysym_to_keycode(xkb_keysym_t sym) +{ + /* Latin letters: XKB_KEY_a..z → KEY_A..Z ('A'..'Z') */ + if (sym >= XKB_KEY_a && sym <= XKB_KEY_z) { + return KEY_A + (sym - XKB_KEY_a); + } + /* Already uppercase */ + if (sym >= XKB_KEY_A && sym <= XKB_KEY_Z) { + return (int)sym; /* XKB_KEY_A = 0x41 = 'A' = KEY_A */ + } + /* Digits: XKB_KEY_0..9 = 0x30..0x39 = '0'..'9' = KEY_0..KEY_9 */ + if (sym >= XKB_KEY_0 && sym <= XKB_KEY_9) { + return (int)sym; + } + switch (sym) { + case XKB_KEY_BackSpace: + return KEY_BACKSPACE; + case XKB_KEY_Tab: + return KEY_TAB; + case XKB_KEY_Return: + return KEY_ENTER; + case XKB_KEY_Escape: + return KEY_ESCAPE; + case XKB_KEY_space: + return KEY_SPACE; + case XKB_KEY_Delete: + return KEY_DELETE; + case XKB_KEY_Insert: + return KEY_INSERT; + case XKB_KEY_Home: + return KEY_HOME; + case XKB_KEY_End: + return KEY_END; + case XKB_KEY_Page_Up: + return KEY_PAGEUP; + case XKB_KEY_Page_Down: + return KEY_PAGEDOWN; + case XKB_KEY_Left: + return KEY_LEFT; + case XKB_KEY_Right: + return KEY_RIGHT; + case XKB_KEY_Up: + return KEY_UP; + case XKB_KEY_Down: + return KEY_DOWN; + case XKB_KEY_Shift_L: + case XKB_KEY_Shift_R: + return KEY_SHIFT; + case XKB_KEY_Control_L: + case XKB_KEY_Control_R: + return KEY_CONTROL; + case XKB_KEY_Alt_L: + case XKB_KEY_Alt_R: + return KEY_ALT; + case XKB_KEY_Caps_Lock: + return KEY_CAPITAL; + case XKB_KEY_semicolon: + return KEY_SEMICOLON; + case XKB_KEY_equal: + return KEY_EQUAL; + case XKB_KEY_comma: + return KEY_COMMA; + case XKB_KEY_minus: + return KEY_MINUS; + case XKB_KEY_period: + return KEY_PERIOD; + case XKB_KEY_slash: + return KEY_SLASH; + case XKB_KEY_grave: + return KEY_GRAVE; + case XKB_KEY_bracketleft: + return KEY_BRACKETLEFT; + case XKB_KEY_backslash: + return KEY_BACKSLASH; + case XKB_KEY_bracketright: + return KEY_BRACKETRIGHT; + case XKB_KEY_apostrophe: + return KEY_APOSTROPHE; + default: + return 0; + } +} + +static void ptk_waylandapp_on_keyboard_keymap(void *data, + struct wl_keyboard *wl_keyboard, + uint32_t format, int32_t fd, + uint32_t size) +{ + void *map_str; + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + return; + } + map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (map_str == MAP_FAILED) { + close(fd); + return; + } + if (!wl_app.xkb_context) { + wl_app.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!wl_app.xkb_context) { + munmap(map_str, size); + close(fd); + return; + } + } + if (wl_app.xkb_state) { + xkb_state_unref(wl_app.xkb_state); + wl_app.xkb_state = NULL; + } + if (wl_app.xkb_map) { + xkb_keymap_unref(wl_app.xkb_map); + } + wl_app.xkb_map = xkb_keymap_new_from_string( + wl_app.xkb_context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, + XKB_KEYMAP_COMPILE_NO_FLAGS); + munmap(map_str, size); + close(fd); + if (!wl_app.xkb_map) { + return; + } + wl_app.xkb_state = xkb_state_new(wl_app.xkb_map); + /* Cache modifier indices for fast lookup in modifiers handler */ + wl_app.shift_mask = + 1u << xkb_keymap_mod_get_index(wl_app.xkb_map, "Shift"); + wl_app.ctrl_mask = + 1u << xkb_keymap_mod_get_index(wl_app.xkb_map, "Control"); + wl_app.alt_mask = 1u + << xkb_keymap_mod_get_index(wl_app.xkb_map, "Mod1"); + wl_app.meta_mask = 1u + << xkb_keymap_mod_get_index(wl_app.xkb_map, "Super"); +} + +static void ptk_waylandapp_on_keyboard_enter(void *data, + struct wl_keyboard *wl_keyboard, + uint32_t serial, + struct wl_surface *surface, + struct wl_array *keys) +{ + wl_app.keyboard_focus = ptk_waylandapp_get_window(surface); +} + +static void ptk_waylandapp_on_keyboard_leave(void *data, + struct wl_keyboard *wl_keyboard, + uint32_t serial, + struct wl_surface *surface) +{ + wl_app.keyboard_focus = NULL; +} + +static void ptk_waylandapp_on_keyboard_key(void *data, + struct wl_keyboard *wl_keyboard, + uint32_t serial, uint32_t time, + uint32_t key, uint32_t state) +{ + /* evdev scancode → XKB keycode: XKB adds a fixed offset of 8 */ + xkb_keycode_t xkb_key = key + 8; + xkb_keysym_t sym = XKB_KEY_NoSymbol; + uint32_t codepoint; + ptk_event_t e = { 0 }; + bool pressed; + + /* Some compositors send WL_KEYBOARD_KEY_STATE_REPEATED for + * auto-repeat. Map it to pressed, same as SDL does + * (SDL_waylandevents.c). */ + if (state == WL_KEYBOARD_KEY_STATE_PRESSED || + state == WL_KEYBOARD_KEY_STATE_REPEATED) { + pressed = true; + } else { + pressed = false; + } + + if (wl_app.xkb_state) { + sym = xkb_state_key_get_one_sym(wl_app.xkb_state, xkb_key); + } + if (!wl_app.keyboard_focus || sym == XKB_KEY_NoSymbol) { + return; + } + e.type = pressed ? PTK_EVENT_KEYDOWN : PTK_EVENT_KEYUP; + e.window = wl_app.keyboard_focus; + e.key.code = ptk_waylandapp_keysym_to_keycode(sym); + e.key.shift_key = !!(wl_app.modifiers & wl_app.shift_mask); + e.key.ctrl_key = !!(wl_app.modifiers & wl_app.ctrl_mask); + e.key.alt_key = !!(wl_app.modifiers & wl_app.alt_mask); + e.key.meta_key = !!(wl_app.modifiers & wl_app.meta_mask); + ptk_post_event(&e); + + /* After KEYDOWN/REPEATED, post PTK_EVENT_KEYPRESS for printable chars + * (non-Ctrl combinations). key.code = Unicode codepoint, matching the + * X11 backend and what the LCUI text widget / IME layer expect. */ + if (pressed && !e.key.ctrl_key && wl_app.xkb_state) { + codepoint = xkb_state_key_get_utf32(wl_app.xkb_state, xkb_key); + if (codepoint >= 0x20 && codepoint != 0x7f) { + e.type = PTK_EVENT_KEYPRESS; + e.key.code = (int)codepoint; + ptk_post_event(&e); + } + } +} + +static void ptk_waylandapp_on_keyboard_modifiers( + void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, + uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, + uint32_t group) +{ + if (!wl_app.xkb_state) { + return; + } + xkb_state_update_mask(wl_app.xkb_state, mods_depressed, mods_latched, + mods_locked, 0, 0, group); + wl_app.modifiers = xkb_state_serialize_mods(wl_app.xkb_state, + XKB_STATE_MODS_EFFECTIVE); +} + +static void ptk_waylandapp_on_keyboard_repeat_info( + void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay) +{ + /* rate: characters per second (0 = no repeat); delay: ms before repeat + * starts. Store for future key-repeat implementation (cf. SDL + * keyboard_handle_repeat_info). */ + wl_app.repeat_rate = rate; + wl_app.repeat_delay = delay; +} + +static const struct wl_keyboard_listener keyboard_listener = { + .keymap = ptk_waylandapp_on_keyboard_keymap, + .enter = ptk_waylandapp_on_keyboard_enter, + .leave = ptk_waylandapp_on_keyboard_leave, + .key = ptk_waylandapp_on_keyboard_key, + .modifiers = ptk_waylandapp_on_keyboard_modifiers, + .repeat_info = ptk_waylandapp_on_keyboard_repeat_info, +}; + +static void ptk_waylandapp_on_seat_capabilities(void *data, + struct wl_seat *seat, + uint32_t caps) +{ + if ((caps & WL_SEAT_CAPABILITY_POINTER) && !wl_app.pointer) { + wl_app.pointer = wl_seat_get_pointer(seat); + wl_pointer_add_listener(wl_app.pointer, &pointer_listener, + NULL); + if (wl_app.shm && !wl_app.cursor_theme) { + wl_app.cursor_theme = wl_cursor_theme_load( + NULL, 32 * wl_app.output_scale, wl_app.shm); + if (wl_app.cursor_theme) { + wl_app.default_cursor = + wl_cursor_theme_get_cursor( + wl_app.cursor_theme, "left_ptr"); + wl_app.cursor_surface = + wl_compositor_create_surface( + wl_app.compositor); + } + } + } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && wl_app.pointer) { + wl_pointer_destroy(wl_app.pointer); + wl_app.pointer = NULL; + } + + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !wl_app.keyboard) { + wl_app.keyboard = wl_seat_get_keyboard(seat); + wl_keyboard_add_listener(wl_app.keyboard, &keyboard_listener, + NULL); + } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && wl_app.keyboard) { + wl_keyboard_destroy(wl_app.keyboard); + wl_app.keyboard = NULL; + } +} + +static void ptk_waylandapp_on_seat_name(void *data, struct wl_seat *seat, + const char *name) +{ +} + +const struct wl_seat_listener seat_listener = { + .capabilities = ptk_waylandapp_on_seat_capabilities, + .name = ptk_waylandapp_on_seat_name, +}; + +#endif /* PTK_LINUX && PTK_HAS_WAYLAND */ diff --git a/lib/ptk/src/linux/waylandapp_output.c b/lib/ptk/src/linux/waylandapp_output.c new file mode 100644 index 000000000..c210a8a38 --- /dev/null +++ b/lib/ptk/src/linux/waylandapp_output.c @@ -0,0 +1,56 @@ +#if defined(PTK_LINUX) && defined(PTK_HAS_WAYLAND) + +#include "wayland_internal.h" + +static void ptk_waylandapp_on_output_geometry( + void *data, struct wl_output *wl_output, int32_t x, int32_t y, + int32_t physical_width, int32_t physical_height, int32_t subpixel, + const char *make, const char *model, int32_t transform) +{ +} + +static void ptk_waylandapp_on_output_mode(void *data, + struct wl_output *wl_output, + uint32_t flags, int32_t width, + int32_t height, int32_t refresh) +{ + if (flags & WL_OUTPUT_MODE_CURRENT) { + wl_app.screen_width = width; + wl_app.screen_height = height; + } +} + +static void ptk_waylandapp_on_output_done(void *data, + struct wl_output *wl_output) +{ +} + +static void ptk_waylandapp_on_output_scale(void *data, + struct wl_output *wl_output, + int32_t factor) +{ + list_node_t *node; + + if (factor <= 0 || wl_app.output_scale == factor) { + return; + } + wl_app.output_scale = factor; + /* Destroy buffers so they are recreated at the new scale on + * the next paint. The compositor will send a configure event + * with updated logical size. */ + for (list_each(node, &wl_app.windows)) { + ptk_window_t *wnd = node->data; + if (wnd) { + ptk_waylandwindow_destroy_buffer(wnd); + } + } +} + +const struct wl_output_listener output_listener = { + .geometry = ptk_waylandapp_on_output_geometry, + .mode = ptk_waylandapp_on_output_mode, + .done = ptk_waylandapp_on_output_done, + .scale = ptk_waylandapp_on_output_scale, +}; + +#endif /* PTK_LINUX && PTK_HAS_WAYLAND */ diff --git a/lib/ptk/src/linux/waylandapp_window.c b/lib/ptk/src/linux/waylandapp_window.c new file mode 100644 index 000000000..6a56e6c48 --- /dev/null +++ b/lib/ptk/src/linux/waylandapp_window.c @@ -0,0 +1,432 @@ +#if defined(PTK_LINUX) && defined(PTK_HAS_WAYLAND) + +#include "wayland_internal.h" + +void ptk_waylandwindow_destroy_buffer(ptk_window_t *wnd) +{ + if (wnd->buffer) { + wl_buffer_destroy(wnd->buffer); + wnd->buffer = NULL; + } + if (wnd->buffer_data) { + munmap(wnd->buffer_data, wnd->buffer_size); + wnd->buffer_data = NULL; + wnd->canvas.bytes = NULL; + } + wnd->buffer_size = 0; +} + +void ptk_waylandwindow_post_size_event(ptk_window_t *wnd) +{ + ptk_event_t e = { 0 }; + + e.type = PTK_EVENT_SIZE; + e.window = wnd; + e.size.width = wnd->width; + e.size.height = wnd->height; + ptk_post_event(&e); +} + +static int ptk_waylandwindow_get_buffer_size(int size) +{ + return size * wl_app.output_scale; +} + +static void ptk_waylandapp_on_wm_base_ping(void *data, + struct xdg_wm_base *wm_base, + uint32_t serial) +{ + xdg_wm_base_pong(wm_base, serial); +} + +const struct xdg_wm_base_listener wm_base_listener = { + ptk_waylandapp_on_wm_base_ping +}; + +static void ptk_waylandwindow_on_xdg_surface_configure( + void *data, struct xdg_surface *surface, uint32_t serial) +{ + ptk_window_t *wnd = data; + + xdg_surface_ack_configure(surface, serial); + wnd->configured = true; +} + +const struct xdg_surface_listener xdg_surface_listener = { + ptk_waylandwindow_on_xdg_surface_configure +}; + +static void ptk_waylandwindow_on_toplevel_configure( + void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, + int32_t height, struct wl_array *states) +{ + ptk_window_t *wnd = data; + int buffer_width; + int buffer_height; + + if (width <= 0 || height <= 0) { + return; + } + buffer_width = ptk_waylandwindow_get_buffer_size(width); + buffer_height = ptk_waylandwindow_get_buffer_size(height); + if (wnd->width == buffer_width && wnd->height == buffer_height) { + return; + } + wnd->width = buffer_width; + wnd->height = buffer_height; + ptk_waylandwindow_destroy_buffer(wnd); + ptk_waylandwindow_post_size_event(wnd); +} + +static void ptk_waylandwindow_on_toplevel_close( + void *data, struct xdg_toplevel *xdg_toplevel) +{ + ptk_window_t *wnd = data; + ptk_event_t e = { 0 }; + + e.type = PTK_EVENT_CLOSE; + e.window = wnd; + ptk_post_event(&e); +} + +static void ptk_waylandwindow_on_toplevel_configure_bounds( + void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, + int32_t height) +{ +} + +static void ptk_waylandwindow_on_toplevel_wm_capabilities( + void *data, struct xdg_toplevel *xdg_toplevel, + struct wl_array *capabilities) +{ +} + +const struct xdg_toplevel_listener xdg_toplevel_listener = { + ptk_waylandwindow_on_toplevel_configure, + ptk_waylandwindow_on_toplevel_close, + ptk_waylandwindow_on_toplevel_configure_bounds, + ptk_waylandwindow_on_toplevel_wm_capabilities +}; + +ptk_window_t *ptk_waylandwindow_create(const wchar_t *title, int x, int y, + int width, int height, + ptk_window_t *parent) +{ + ptk_window_t *wnd; + + if (!wl_app.compositor || !wl_app.wm_base || !wl_app.shm) { + return NULL; + } + wnd = calloc(1, sizeof(*wnd)); + if (!wnd) { + return NULL; + } + wnd->width = ptk_waylandwindow_get_buffer_size( + width > 0 ? width : PTK_WINDOW_DEFAULT_WIDTH); + wnd->height = ptk_waylandwindow_get_buffer_size( + height > 0 ? height : PTK_WINDOW_DEFAULT_HEIGHT); + wnd->surface = wl_compositor_create_surface(wl_app.compositor); + if (!wnd->surface) { + free(wnd); + return NULL; + } + wnd->xdg_surface = + xdg_wm_base_get_xdg_surface(wl_app.wm_base, wnd->surface); + wnd->xdg_toplevel = xdg_surface_get_toplevel(wnd->xdg_surface); + if (!wnd->xdg_surface || !wnd->xdg_toplevel) { + if (wnd->xdg_toplevel) { + xdg_toplevel_destroy(wnd->xdg_toplevel); + } + if (wnd->xdg_surface) { + xdg_surface_destroy(wnd->xdg_surface); + } + wl_surface_destroy(wnd->surface); + free(wnd); + return NULL; + } + wnd->node.data = wnd; + xdg_surface_add_listener(wnd->xdg_surface, &xdg_surface_listener, wnd); + xdg_toplevel_add_listener(wnd->xdg_toplevel, &xdg_toplevel_listener, + wnd); + + if (wl_app.decoration_manager) { + wnd->decoration = + zxdg_decoration_manager_v1_get_toplevel_decoration( + wl_app.decoration_manager, wnd->xdg_toplevel); + if (wnd->decoration) { + zxdg_toplevel_decoration_v1_set_mode( + wnd->decoration, + ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } + } + if (title) { + size_t len = encode_utf8(NULL, title, 0) + 1; + char *utf8_title = malloc(sizeof(char) * len); + + if (utf8_title) { + encode_utf8(utf8_title, title, len); + xdg_toplevel_set_title(wnd->xdg_toplevel, utf8_title); + free(utf8_title); + } + } + wl_surface_commit(wnd->surface); + wl_display_roundtrip(wl_app.display); + list_append_node(&wl_app.windows, &wnd->node); + return wnd; +} + +static void ptk_waylandwindow_close(ptk_window_t *wnd) +{ + ptk_event_t e = { 0 }; + + e.type = PTK_EVENT_CLOSE; + e.window = wnd; + ptk_post_event(&e); +} + +static void ptk_waylandwindow_show(ptk_window_t *wnd) +{ + wl_surface_commit(wnd->surface); +} + +static void ptk_waylandwindow_activate(ptk_window_t *wnd) +{ + wl_surface_commit(wnd->surface); +} + +static void ptk_waylandwindow_set_title(ptk_window_t *wnd, const wchar_t *title) +{ + size_t len; + char *utf8_title; + + if (!title || !wnd->xdg_toplevel) { + return; + } + len = encode_utf8(NULL, title, 0) + 1; + utf8_title = malloc(sizeof(char) * len); + if (!utf8_title) { + return; + } + encode_utf8(utf8_title, title, len); + xdg_toplevel_set_title(wnd->xdg_toplevel, utf8_title); + free(utf8_title); +} + +static void ptk_waylandwindow_destroy(ptk_window_t *wnd) +{ + if (!wnd) { + return; + } + list_unlink(&wl_app.windows, &wnd->node); + if (wnd->decoration) { + zxdg_toplevel_decoration_v1_destroy(wnd->decoration); + } + if (wnd->xdg_toplevel) { + xdg_toplevel_destroy(wnd->xdg_toplevel); + } + if (wnd->xdg_surface) { + xdg_surface_destroy(wnd->xdg_surface); + } + if (wnd->surface) { + wl_surface_destroy(wnd->surface); + } + ptk_waylandwindow_destroy_buffer(wnd); + free(wnd->paint_ctx); + free(wnd); +} + +static void ptk_waylandwindow_set_size(ptk_window_t *wnd, int width, int height) +{ + int physical_width; + int physical_height; + + if (width <= 0 || height <= 0) { + return; + } + physical_width = ptk_waylandwindow_get_buffer_size(width); + physical_height = ptk_waylandwindow_get_buffer_size(height); + + if (wnd->width == physical_width && wnd->height == physical_height) { + return; + } + wnd->width = physical_width; + wnd->height = physical_height; + ptk_waylandwindow_destroy_buffer(wnd); +} + +static void ptk_waylandwindow_set_position(ptk_window_t *wnd, int x, int y) +{ +} + +static void *ptk_waylandwindow_get_handle(ptk_window_t *wnd) +{ + return wnd->surface; +} + +static int ptk_waylandwindow_get_width(ptk_window_t *wnd) +{ + return wnd->width / wl_app.output_scale; +} + +static int ptk_waylandwindow_get_height(ptk_window_t *wnd) +{ + return wnd->height / wl_app.output_scale; +} + +static void ptk_waylandwindow_apply_size_hints(ptk_window_t *wnd) +{ + if (!wnd->xdg_toplevel) { + return; + } + xdg_toplevel_set_min_size(wnd->xdg_toplevel, + wnd->min_width * wl_app.output_scale, + wnd->min_height * wl_app.output_scale); + xdg_toplevel_set_max_size(wnd->xdg_toplevel, + wnd->max_width * wl_app.output_scale, + wnd->max_height * wl_app.output_scale); +} + +static void ptk_waylandwindow_set_min_width(ptk_window_t *wnd, int min_width) +{ + wnd->min_width = min_width; + ptk_waylandwindow_apply_size_hints(wnd); +} + +static void ptk_waylandwindow_set_min_height(ptk_window_t *wnd, int min_height) +{ + wnd->min_height = min_height; + ptk_waylandwindow_apply_size_hints(wnd); +} + +static void ptk_waylandwindow_set_max_width(ptk_window_t *wnd, int max_width) +{ + wnd->max_width = max_width; + ptk_waylandwindow_apply_size_hints(wnd); +} + +static void ptk_waylandwindow_set_max_height(ptk_window_t *wnd, int max_height) +{ + wnd->max_height = max_height; + ptk_waylandwindow_apply_size_hints(wnd); +} + +static unsigned ptk_waylandwindow_get_dpi(ptk_window_t *wnd) +{ + return wl_app.output_scale * 96; +} + +static ptk_window_paint_t *ptk_waylandwindow_begin_paint(ptk_window_t *wnd, + pd_rect_t *rect) +{ + size_t size; + int fd; + struct wl_shm_pool *pool; + + if (!wnd->configured || !rect) { + return NULL; + } + if (!wnd->buffer) { + size = (size_t)wnd->width * (size_t)wnd->height * 4; + fd = memfd_create("lcui-wayland-buffer", MFD_CLOEXEC); + if (fd < 0) { + return NULL; + } + if (ftruncate(fd, (off_t)size) < 0) { + close(fd); + return NULL; + } + wnd->buffer_data = + mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (wnd->buffer_data == MAP_FAILED) { + wnd->buffer_data = NULL; + close(fd); + return NULL; + } + pool = wl_shm_create_pool(wl_app.shm, fd, (int)size); + wnd->buffer = wl_shm_pool_create_buffer( + pool, 0, wnd->width, wnd->height, wnd->width * 4, + WL_SHM_FORMAT_XRGB8888); + wl_shm_pool_destroy(pool); + close(fd); + wnd->buffer_size = size; + /* Initialize the backing canvas once per buffer lifetime. + * pd_canvas_init leaves mem_size=0 and bytes=NULL; we + * override bytes to point at the mmap'd shm buffer. + * The canvas must NOT be passed to pd_canvas_destroy(), + * which would free() the pointer — use destroy_buffer instead. + */ + pd_canvas_init(&wnd->canvas); + wnd->canvas.width = wnd->width; + wnd->canvas.height = wnd->height; + wnd->canvas.color_type = PD_COLOR_TYPE_ARGB; + wnd->canvas.bytes = wnd->buffer_data; + wnd->canvas.bytes_per_pixel = 4; + wnd->canvas.bytes_per_row = wnd->width * 4; + } + if (!wnd->paint_ctx) { + wnd->paint_ctx = calloc(1, sizeof(*wnd->paint_ctx)); + if (!wnd->paint_ctx) { + return NULL; + } + } + /* Set up the paint context following pd_context_create() semantics: + * paint->canvas must be a pd_canvas_quote() of the full backing canvas + * clipped to the dirty rect. Pandagl renderers draw at (0,0) within + * this quoted canvas, which corresponds to (rect->x, rect->y) in the + * actual shm buffer. Setting canvas = full buffer (old code) caused + * all renders to write to buffer[0,0] regardless of the dirty rect. */ + wnd->paint_ctx->rect = *rect; + wnd->paint_ctx->with_alpha = false; + pd_rect_correct(&wnd->paint_ctx->rect, wnd->width, wnd->height); + pd_canvas_init(&wnd->paint_ctx->canvas); + pd_canvas_quote(&wnd->paint_ctx->canvas, &wnd->canvas, + &wnd->paint_ctx->rect); + /* Clear the dirty region to white before the widget renders into it */ + pd_canvas_fill(&wnd->paint_ctx->canvas, pd_rgb(255, 255, 255)); + return wnd->paint_ctx; +} + +static void ptk_waylandwindow_end_paint(ptk_window_t *wnd, + ptk_window_paint_t *paint) +{ + if (!wnd || !paint || !wnd->buffer) { + return; + } + wl_surface_set_buffer_scale(wnd->surface, wl_app.output_scale); + wl_surface_attach(wnd->surface, wnd->buffer, 0, 0); + wl_surface_damage_buffer(wnd->surface, paint->rect.x, paint->rect.y, + paint->rect.width, paint->rect.height); + wl_surface_commit(wnd->surface); + wl_display_flush(wl_app.display); +} + +static void ptk_waylandwindow_present(ptk_window_t *wnd) +{ + wl_surface_commit(wnd->surface); + wl_display_flush(wl_app.display); +} + +void ptk_waylandwindow_driver_init(ptk_window_driver_t *driver) +{ + memset(driver, 0, sizeof(*driver)); + driver->show = ptk_waylandwindow_show; + driver->activate = ptk_waylandwindow_activate; + driver->close = ptk_waylandwindow_close; + driver->destroy = ptk_waylandwindow_destroy; + driver->set_title = ptk_waylandwindow_set_title; + driver->set_size = ptk_waylandwindow_set_size; + driver->set_position = ptk_waylandwindow_set_position; + driver->get_handle = ptk_waylandwindow_get_handle; + driver->get_width = ptk_waylandwindow_get_width; + driver->get_height = ptk_waylandwindow_get_height; + driver->get_dpi = ptk_waylandwindow_get_dpi; + driver->set_min_width = ptk_waylandwindow_set_min_width; + driver->set_min_height = ptk_waylandwindow_set_min_height; + driver->set_max_width = ptk_waylandwindow_set_max_width; + driver->set_max_height = ptk_waylandwindow_set_max_height; + driver->begin_paint = ptk_waylandwindow_begin_paint; + driver->end_paint = ptk_waylandwindow_end_paint; + driver->present = ptk_waylandwindow_present; +} + +#endif /* PTK_LINUX && PTK_HAS_WAYLAND */ diff --git a/lib/ptk/xmake.lua b/lib/ptk/xmake.lua index d7ec728c5..e0775a7bb 100644 --- a/lib/ptk/xmake.lua +++ b/lib/ptk/xmake.lua @@ -1,5 +1,11 @@ +includes("rules/xmake.lua") + +local wayland_protocol_root = os.getenv("WAYLAND_PROTOCOLS_DIR") or "/usr/share/wayland-protocols" +local xdg_shell_xml = path.join(wayland_protocol_root, "stable", "xdg-shell", "xdg-shell.xml") +local xdg_decoration_xml = path.join(wayland_protocol_root, "unstable", "xdg-decoration", "xdg-decoration-unstable-v1.xml") + if is_plat("linux") then - add_requires("libx11", {optional = true}) + add_requires("libx11", "wayland", "xkbcommon", "wayland-cursor", {optional = true}) end option("enable-touch") @@ -26,10 +32,16 @@ target("libptk") add_links("Shell32") else add_files("src/linux/*.c") - add_packages("libx11") + add_packages("libx11", "wayland", "xkbcommon", "wayland-cursor") if has_package("libx11") then set_configvar("PTK_HAS_LIBX11", 1) end + if has_package("wayland") then + add_rules("wayland.protocol") + add_files(xdg_shell_xml, {rule = "wayland.protocol"}) + add_files(xdg_decoration_xml, {rule = "wayland.protocol"}) + set_configvar("PTK_HAS_WAYLAND", 1) + end add_syslinks("pthread", "dl") end From 8034064b65bfa1d4dd64bf9431cade21c8c497a0 Mon Sep 17 00:00:00 2001 From: rewine Date: Wed, 29 Jul 2026 11:04:46 +0800 Subject: [PATCH 58/66] chore(ci): support wayland build --- .github/workflows/ccpp.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 9a0ebb6b5..f902afebd 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -57,7 +57,7 @@ jobs: run: | sudo apt-get update --fix-missing sudo apt-get install debhelper lcov valgrind xvfb -yy - sudo apt-get install libfreetype6-dev libpng-dev libyaml-dev libomp-dev libx11-dev ninja-build fontconfig libfontconfig1-dev libjpeg-dev + sudo apt-get install libfreetype6-dev libpng-dev libyaml-dev libomp-dev libx11-dev ninja-build fontconfig libfontconfig1-dev libjpeg-dev libwayland-dev libxkbcommon-dev wayland-protocols - name: Configure if: runner.os == 'Windows' From c8ccc60857c76b19b8de23e3bac26976f9fdc8d3 Mon Sep 17 00:00:00 2001 From: rewine Date: Sat, 23 May 2026 17:36:35 +0800 Subject: [PATCH 59/66] build: update xmake-requires.lock dependency versions Update xmake-repo source from gitee mirror to github/gitlab upstream, refresh dependency versions and add new transitive dependencies. --- examples/xmake-requires.lock | 256 +++++++++++++++++++++++++++++-- xmake-requires.lock | 282 +++++++++++++++++++++-------------- 2 files changed, 413 insertions(+), 125 deletions(-) diff --git a/examples/xmake-requires.lock b/examples/xmake-requires.lock index 30817716d..8d1ecdada 100644 --- a/examples/xmake-requires.lock +++ b/examples/xmake-requires.lock @@ -1,4 +1,230 @@ { + ["linux|x86_64"] = { + ["ca-certificates#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "20250131" + }, + ["cairo#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "1.18.0" + }, + ["cmake#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "4.2.3" + }, + ["expat#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "2.7.4" + }, + ["fontconfig#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "2.17.1" + }, + ["freetype#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "2.14.1" + }, + ["gperf#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "3.2.1" + }, + ["libffi#0b3b0fcf"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "3.4.8" + }, + ["libpng#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "v1.6.55" + }, + ["libpthread-stubs#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "0.5" + }, + ["libx11#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "1.8.13" + }, + ["libxau#16fb575b"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "1.0.12" + }, + ["libxcb#16fb575b"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "1.17.0" + }, + ["libxdmcp#16fb575b"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "1.1.5" + }, + ["libxext#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "1.3.7" + }, + ["libxrender#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "0.9.12" + }, + ["meson#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "1.10.2" + }, + ["ninja#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "v1.13.1" + }, + ["openssl >=1.1.1-a#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "1.1.1-w" + }, + ["pixman#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "0.46.2" + }, + ["pkg-config#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "0.29.2" + }, + ["python 3.x#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "3.13.11" + }, + ["util-macros#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "1.20.0" + }, + ["xcb-proto#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "1.17.0" + }, + ["xorgproto#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "2023.2" + }, + ["xtrans#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "1.6.0" + }, + ["zlib#0b3b0fcf"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "v1.3.2" + }, + ["zlib#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://gitlab.com/tboox/xmake-repo.git" + }, + version = "v1.3.2" + } + }, __meta__ = { version = "1.0" }, @@ -53,19 +279,19 @@ }, ["lcui#31fecfc4"] = { repo = { - url = "../build" + url = "../build/packages" }, version = "latest" }, ["libcss#31fecfc4"] = { repo = { - url = "../build" + url = "../build/packages" }, version = "latest" }, ["libi18n#31fecfc4"] = { repo = { - url = "../build" + url = "../build/packages" }, version = "latest" }, @@ -95,7 +321,7 @@ }, ["libplatform#31fecfc4"] = { repo = { - url = "../build" + url = "../build/packages" }, version = "latest" }, @@ -109,55 +335,55 @@ }, ["libthread#31fecfc4"] = { repo = { - url = "../build" + url = "../build/packages" }, version = "latest" }, ["libtimer#31fecfc4"] = { repo = { - url = "../build" + url = "../build/packages" }, version = "latest" }, ["libui#31fecfc4"] = { repo = { - url = "../build" + url = "../build/packages" }, version = "latest" }, ["libui-cursor#31fecfc4"] = { repo = { - url = "../build" + url = "../build/packages" }, version = "latest" }, ["libui-router#31fecfc4"] = { repo = { - url = "../build" + url = "../build/packages" }, version = "latest" }, ["libui-server#31fecfc4"] = { repo = { - url = "../build" + url = "../build/packages" }, version = "latest" }, ["libui-widgets#31fecfc4"] = { repo = { - url = "../build" + url = "../build/packages" }, version = "latest" }, ["libui-xml#31fecfc4"] = { repo = { - url = "../build" + url = "../build/packages" }, version = "latest" }, ["libworker#31fecfc4"] = { repo = { - url = "../build" + url = "../build/packages" }, version = "latest" }, @@ -195,7 +421,7 @@ }, ["pandagl#31fecfc4"] = { repo = { - url = "../build" + url = "../build/packages" }, version = "latest" }, @@ -225,7 +451,7 @@ }, ["yutil#31fecfc4"] = { repo = { - url = "../build" + url = "../build/packages" }, version = "latest" }, diff --git a/xmake-requires.lock b/xmake-requires.lock index 21c0278d3..0b97e9c6e 100644 --- a/xmake-requires.lock +++ b/xmake-requires.lock @@ -1,241 +1,303 @@ { - __meta__ = { - version = "1.0" - }, ["linux|x86_64"] = { - ["ca-certificates#31fecfc4"] = { + ["bison#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "20240207" + version = "3.8.2" }, - ["cmake#31fecfc4"] = { + ["ca-certificates#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "3.28.3" + version = "20250131" }, - ["expat#31fecfc4"] = { + ["cairo#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", url = "https://gitee.com/tboox/xmake-repo.git" }, - version = "2.6.1" + version = "1.18.0" }, - ["fontconfig#31fecfc4"] = { + ["cmake#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "2.15.0" + version = "4.2.3" }, - ["freetype#31fecfc4"] = { + ["expat#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "26.1.20" + version = "2.7.4" }, - ["freetype#8cb27d06"] = { + ["fontconfig#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "26.1.20" + version = "2.17.1" }, - ["gperf#31fecfc4"] = { + ["freetype#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", url = "https://gitee.com/tboox/xmake-repo.git" }, - version = "3.1" + version = "2.14.1" }, - ["libffi#f26e00a1"] = { + ["gperf#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "3.4.6" + version = "3.2.1" }, - ["libjpeg#31fecfc4"] = { + ["libffi#0b3b0fcf"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" + }, + version = "3.4.8" + }, + ["libffi#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" + }, + version = "3.4.8" + }, + ["libjpeg#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, version = "v9f" }, - ["libomp#31fecfc4"] = { + ["libomp#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "12.0.1" + version = "19.1.0" }, - ["libpng#31fecfc4"] = { + ["libpng#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "1.6.43" + version = "v1.6.55" }, - ["libpthread-stubs#31fecfc4"] = { + ["libpthread-stubs#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "0.4" + version = "0.5" }, - ["libx11#31fecfc4"] = { + ["libx11#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "1.8.7" + version = "1.8.13" }, - ["libxau#31fecfc4"] = { + ["libxau#16fb575b"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "1.0.9" + version = "1.0.12" }, - ["libxcb#31fecfc4"] = { + ["libxcb#16fb575b"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "1.15" + version = "1.17.0" }, - ["libxdmcp#31fecfc4"] = { + ["libxdmcp#16fb575b"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "1.1.3" + version = "1.1.5" }, - ["libxml2#31fecfc4"] = { + ["libxext#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", url = "https://gitee.com/tboox/xmake-repo.git" }, - version = "2.9.14" + version = "1.3.7" }, - ["libyaml#31fecfc4"] = { + ["libxml2#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" + }, + version = "v2.14.3" + }, + ["libxrender#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", url = "https://gitee.com/tboox/xmake-repo.git" }, + version = "0.9.12" + }, + ["libyaml#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" + }, version = "0.2.5" }, - ["meson#31fecfc4"] = { + ["m4#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "1.3.2" + version = "1.4.19" }, - ["ninja#31fecfc4"] = { + ["meson#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "1.11.1" + version = "1.10.2" }, - ["openssl >=1.1.1-a#31fecfc4"] = { + ["ninja#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" + }, + version = "v1.13.1" + }, + ["openssl >=1.1.1-a#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, version = "1.1.1-w" }, - ["pkg-config#31fecfc4"] = { + ["pixman#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", url = "https://gitee.com/tboox/xmake-repo.git" }, - version = "1.8.1" + version = "0.46.2" }, - ["python 3.x#31fecfc4"] = { + ["pkg-config#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "3.12.3" + version = "0.29.2" }, - ["util-macros#31fecfc4"] = { + ["python 3.x#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" + }, + version = "3.13.11" + }, + ["util-macros#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, version = "1.20.0" }, - ["xcb-proto#31fecfc4"] = { + ["wayland-cursor#f56260b5"] = { + version = "latest" + }, + ["wayland#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "1.16.0" + version = "1.24.0" }, - ["xorgproto#31fecfc4"] = { + ["xcb-proto#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "1.0" + version = "1.17.0" + }, + ["xkbcommon#f56260b5"] = { + version = "latest" }, - ["xtrans#31fecfc4"] = { + ["xorgproto#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "1.4.0" + version = "2023.2" }, - ["zlib#31fecfc4"] = { + ["xtrans#f56260b5"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "v1.3.1" + version = "1.6.0" }, - ["zlib#f26e00a1"] = { + ["zlib#0b3b0fcf"] = { repo = { branch = "master", - commit = "d5382a3bab22616b1c5b0292a6ce460d116df916", - url = "https://gitee.com/tboox/xmake-repo.git" + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" }, - version = "v1.3.1" + version = "v1.3.2" + }, + ["zlib#f56260b5"] = { + repo = { + branch = "master", + commit = "75c3fcffb897a8aeb37863c495b9f58266216b26", + url = "https://github.com/xmake-io/xmake-repo.git" + }, + version = "v1.3.2" } }, + __meta__ = { + version = "1.0" + }, ["windows|x64"] = { ["cairo#31fecfc4"] = { repo = { From 0ed720ec97292b161921104033c6cb2e80623d58 Mon Sep 17 00:00:00 2001 From: rewine Date: Wed, 29 Jul 2026 17:07:04 +0800 Subject: [PATCH 60/66] feat(ptk): rename PTK_APP_ID_LINUX to PTK_APP_ID_LINUX_FRAMEBUFFER for clarity --- lib/ptk/include/ptk/types.h | 2 +- lib/ptk/src/linux/app.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ptk/include/ptk/types.h b/lib/ptk/include/ptk/types.h index 711b5aace..637f24882 100644 --- a/lib/ptk/include/ptk/types.h +++ b/lib/ptk/include/ptk/types.h @@ -20,7 +20,7 @@ typedef void (*ptk_timer_cb)(void *); typedef enum { PTK_APP_ID_UNKNOWN, - PTK_APP_ID_LINUX, + PTK_APP_ID_LINUX_FRAMEBUFFER, PTK_APP_ID_LINUX_X11, PTK_APP_ID_LINUX_WAYLAND, PTK_APP_ID_WIN_DESKTOP, diff --git a/lib/ptk/src/linux/app.c b/lib/ptk/src/linux/app.c index aaa94ceb8..12b2196a9 100644 --- a/lib/ptk/src/linux/app.c +++ b/lib/ptk/src/linux/app.c @@ -204,7 +204,7 @@ ptk_app_id_t ptk_get_app_id(void) int ptk_app_init(const wchar_t *name) { - linux_app.id = PTK_APP_ID_LINUX; + linux_app.id = PTK_APP_ID_LINUX_FRAMEBUFFER; #ifdef PTK_HAS_WAYLAND ptk_waylandapp_driver_init(&linux_app.app); ptk_waylandwindow_driver_init(&linux_app.window); @@ -248,7 +248,7 @@ int ptk_app_destroy(void) return -1; } linux_app.active = false; - if (linux_app.id == PTK_APP_ID_LINUX) { + if (linux_app.id == PTK_APP_ID_LINUX_FRAMEBUFFER) { ptk_linux_mouse_destroy(); ptk_linux_keyboard_destroy(); } From 2e23606df3a0edeff059d3df2398a9c08995eb03 Mon Sep 17 00:00:00 2001 From: rewine Date: Wed, 29 Jul 2026 18:39:20 +0800 Subject: [PATCH 61/66] feat(ptk): select linux backend by environment variables Check WAYLAND_DISPLAY for wayland, DISPLAY for x11, and fallback to framebuffer. Log warnings when preferred backend is not compiled in. --- lib/ptk/src/linux/app.c | 56 +++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/lib/ptk/src/linux/app.c b/lib/ptk/src/linux/app.c index 12b2196a9..ecf97d8e5 100644 --- a/lib/ptk/src/linux/app.c +++ b/lib/ptk/src/linux/app.c @@ -9,6 +9,7 @@ * in the LICENSE.TXT file in the root directory of this source tree. */ +#include #include #include #include "ptk.h" @@ -204,32 +205,45 @@ ptk_app_id_t ptk_get_app_id(void) int ptk_app_init(const wchar_t *name) { + const char *env; + linux_app.id = PTK_APP_ID_LINUX_FRAMEBUFFER; + env = getenv("WAYLAND_DISPLAY"); + if (env && *env) { #ifdef PTK_HAS_WAYLAND - ptk_waylandapp_driver_init(&linux_app.app); - ptk_waylandwindow_driver_init(&linux_app.window); - if (linux_app.app.init(name) == 0) { - logger_debug("[app] use engine: waylandapp\n"); - linux_app.id = PTK_APP_ID_LINUX_WAYLAND; - linux_app.active = true; - return 0; - } - memset(&linux_app.app, 0, sizeof(linux_app.app)); - memset(&linux_app.window, 0, sizeof(linux_app.window)); + ptk_waylandapp_driver_init(&linux_app.app); + ptk_waylandwindow_driver_init(&linux_app.window); + if (linux_app.app.init(name) == 0) { + logger_debug("[app] use engine: waylandapp\n"); + linux_app.id = PTK_APP_ID_LINUX_WAYLAND; + linux_app.active = true; + return 0; + } + memset(&linux_app.app, 0, sizeof(linux_app.app)); + memset(&linux_app.window, 0, sizeof(linux_app.window)); +#else + logger_warning("[app] WAYLAND_DISPLAY is set but wayland " + "backend is not compiled in\n"); #endif -#ifdef PTK_HAS_LIBX11 - - ptk_x11app_driver_init(&linux_app.app); - ptk_x11window_driver_init(&linux_app.window); - if (linux_app.app.init(name) == 0) { - logger_debug("[app] use engine: x11app\n"); - linux_app.id = PTK_APP_ID_LINUX_X11; - linux_app.active = true; - return 0; } - memset(&linux_app.app, 0, sizeof(linux_app.app)); - memset(&linux_app.window, 0, sizeof(linux_app.window)); + env = getenv("DISPLAY"); + if (env && *env) { +#ifdef PTK_HAS_LIBX11 + ptk_x11app_driver_init(&linux_app.app); + ptk_x11window_driver_init(&linux_app.window); + if (linux_app.app.init(name) == 0) { + logger_debug("[app] use engine: x11app\n"); + linux_app.id = PTK_APP_ID_LINUX_X11; + linux_app.active = true; + return 0; + } + memset(&linux_app.app, 0, sizeof(linux_app.app)); + memset(&linux_app.window, 0, sizeof(linux_app.window)); +#else + logger_warning("[app] DISPLAY is set but x11 backend is not " + "compiled in\n"); #endif + } logger_debug("[app] use engine: fbapp\n"); ptk_fbapp_driver_init(&linux_app.app); ptk_fbwindow_driver_init(&linux_app.window); From eb76e3964458146e9ba3285b35cf4974c505ff90 Mon Sep 17 00:00:00 2001 From: rewine Date: Thu, 30 Jul 2026 10:24:53 +0800 Subject: [PATCH 62/66] fix(ptk): enable wayland backend build and fix cursor scaling Add missing PTK_HAS_WAYLAND template in config.h.in so the macro is actually defined in generated config.h. Include ptk.h before the #if guard in wayland source files so the macro is visible at the preprocessor check. Move ptk_waylandapp_destroy() before ptk_waylandapp_init() to resolve forward declaration warning. Fix cursor scaling on HiDPI: load cursor theme at logical size (32) instead of physical size (32*output_scale) and remove redundant hotspot division by output_scale, avoiding double scaling via wl_surface_set_buffer_scale. Only compile wayland source files when the wayland package is available. --- lib/ptk/src/config.h.in | 1 + lib/ptk/src/linux/wayland_internal.h | 2 + lib/ptk/src/linux/waylandapp_core.c | 81 ++++++++++++++------------- lib/ptk/src/linux/waylandapp_input.c | 10 ++-- lib/ptk/src/linux/waylandapp_output.c | 3 + lib/ptk/src/linux/waylandapp_window.c | 3 + lib/ptk/xmake.lua | 4 ++ 7 files changed, 61 insertions(+), 43 deletions(-) diff --git a/lib/ptk/src/config.h.in b/lib/ptk/src/config.h.in index a7d50bbfb..39a0a46e4 100644 --- a/lib/ptk/src/config.h.in +++ b/lib/ptk/src/config.h.in @@ -4,3 +4,4 @@ #define PTK_VERSION_ALTER ${VERSION_ALTER} ${define PTK_STATIC_BUILD} ${define PTK_HAS_LIBX11} +${define PTK_HAS_WAYLAND} diff --git a/lib/ptk/src/linux/wayland_internal.h b/lib/ptk/src/linux/wayland_internal.h index abd3805a3..a9da73189 100644 --- a/lib/ptk/src/linux/wayland_internal.h +++ b/lib/ptk/src/linux/wayland_internal.h @@ -3,7 +3,9 @@ #if defined(PTK_LINUX) && defined(PTK_HAS_WAYLAND) +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif #include #include #include diff --git a/lib/ptk/src/linux/waylandapp_core.c b/lib/ptk/src/linux/waylandapp_core.c index 72f8b038c..b696f21aa 100644 --- a/lib/ptk/src/linux/waylandapp_core.c +++ b/lib/ptk/src/linux/waylandapp_core.c @@ -1,3 +1,6 @@ +#define _GNU_SOURCE +#include "ptk.h" + #if defined(PTK_LINUX) && defined(PTK_HAS_WAYLAND) #include "wayland_internal.h" @@ -116,45 +119,6 @@ static int ptk_waylandapp_poll_events(int timeout_ms, bool dispatch_all) return result < 0 ? -1 : 1; } -static int ptk_waylandapp_init(const wchar_t *name) -{ - memset(&wl_app, 0, sizeof(wl_app)); - wl_app.output_scale = 1; - wl_app.display = wl_display_connect(NULL); - if (!wl_app.display) { - logger_error("[wayland] wl_display_connect() failed\n"); - return -1; - } - wl_app.screen_width = WAYLAND_DEFAULT_SCREEN_WIDTH; - wl_app.screen_height = WAYLAND_DEFAULT_SCREEN_HEIGHT; - wl_app.registry = wl_display_get_registry(wl_app.display); - if (!wl_app.registry) { - logger_error("[wayland] wl_display_get_registry() failed\n"); - wl_display_disconnect(wl_app.display); - wl_app.display = NULL; - return -1; - } - list_create(&wl_app.windows); - wl_registry_add_listener(wl_app.registry, ®istry_listener, NULL); - if (wl_display_roundtrip(wl_app.display) < 0) { - logger_error("[wayland] wl_display_roundtrip() failed during " - "registry init\n"); - ptk_waylandapp_destroy(); - return -1; - } - if (!wl_app.compositor || !wl_app.shm || !wl_app.wm_base) { - logger_error("[wayland] missing globals: compositor=%p shm=%p " - "wm_base=%p\n", - wl_app.compositor, wl_app.shm, wl_app.wm_base); - ptk_waylandapp_destroy(); - return -1; - } - xdg_wm_base_add_listener(wl_app.wm_base, &wm_base_listener, NULL); - wl_app.running = true; - wl_app.exit_code = 0; - return 0; -} - static int ptk_waylandapp_destroy(void) { list_node_t *node, *next; @@ -238,6 +202,45 @@ static int ptk_waylandapp_destroy(void) return 0; } +static int ptk_waylandapp_init(const wchar_t *name) +{ + memset(&wl_app, 0, sizeof(wl_app)); + wl_app.output_scale = 1; + wl_app.display = wl_display_connect(NULL); + if (!wl_app.display) { + logger_error("[wayland] wl_display_connect() failed\n"); + return -1; + } + wl_app.screen_width = WAYLAND_DEFAULT_SCREEN_WIDTH; + wl_app.screen_height = WAYLAND_DEFAULT_SCREEN_HEIGHT; + wl_app.registry = wl_display_get_registry(wl_app.display); + if (!wl_app.registry) { + logger_error("[wayland] wl_display_get_registry() failed\n"); + wl_display_disconnect(wl_app.display); + wl_app.display = NULL; + return -1; + } + list_create(&wl_app.windows); + wl_registry_add_listener(wl_app.registry, ®istry_listener, NULL); + if (wl_display_roundtrip(wl_app.display) < 0) { + logger_error("[wayland] wl_display_roundtrip() failed during " + "registry init\n"); + ptk_waylandapp_destroy(); + return -1; + } + if (!wl_app.compositor || !wl_app.shm || !wl_app.wm_base) { + logger_error("[wayland] missing globals: compositor=%p shm=%p " + "wm_base=%p\n", + wl_app.compositor, wl_app.shm, wl_app.wm_base); + ptk_waylandapp_destroy(); + return -1; + } + xdg_wm_base_add_listener(wl_app.wm_base, &wm_base_listener, NULL); + wl_app.running = true; + wl_app.exit_code = 0; + return 0; +} + static int ptk_waylandapp_process_events(ptk_process_events_option_t option) { int result = 0; diff --git a/lib/ptk/src/linux/waylandapp_input.c b/lib/ptk/src/linux/waylandapp_input.c index 810371622..6ee6da80d 100644 --- a/lib/ptk/src/linux/waylandapp_input.c +++ b/lib/ptk/src/linux/waylandapp_input.c @@ -1,3 +1,6 @@ +#define _GNU_SOURCE +#include "ptk.h" + #if defined(PTK_LINUX) && defined(PTK_HAS_WAYLAND) #include "wayland_internal.h" @@ -16,8 +19,7 @@ static void ptk_waylandapp_on_pointer_enter( struct wl_cursor_image *image = wl_app.default_cursor->images[0]; wl_pointer_set_cursor(wl_pointer, serial, wl_app.cursor_surface, - image->hotspot_x / wl_app.output_scale, - image->hotspot_y / wl_app.output_scale); + image->hotspot_x, image->hotspot_y); wl_surface_set_buffer_scale(wl_app.cursor_surface, wl_app.output_scale); wl_surface_attach(wl_app.cursor_surface, @@ -391,8 +393,8 @@ static void ptk_waylandapp_on_seat_capabilities(void *data, wl_pointer_add_listener(wl_app.pointer, &pointer_listener, NULL); if (wl_app.shm && !wl_app.cursor_theme) { - wl_app.cursor_theme = wl_cursor_theme_load( - NULL, 32 * wl_app.output_scale, wl_app.shm); + wl_app.cursor_theme = + wl_cursor_theme_load(NULL, 32, wl_app.shm); if (wl_app.cursor_theme) { wl_app.default_cursor = wl_cursor_theme_get_cursor( diff --git a/lib/ptk/src/linux/waylandapp_output.c b/lib/ptk/src/linux/waylandapp_output.c index c210a8a38..c6deafd8e 100644 --- a/lib/ptk/src/linux/waylandapp_output.c +++ b/lib/ptk/src/linux/waylandapp_output.c @@ -1,3 +1,6 @@ +#define _GNU_SOURCE +#include "ptk.h" + #if defined(PTK_LINUX) && defined(PTK_HAS_WAYLAND) #include "wayland_internal.h" diff --git a/lib/ptk/src/linux/waylandapp_window.c b/lib/ptk/src/linux/waylandapp_window.c index 6a56e6c48..bf1085c4e 100644 --- a/lib/ptk/src/linux/waylandapp_window.c +++ b/lib/ptk/src/linux/waylandapp_window.c @@ -1,3 +1,6 @@ +#define _GNU_SOURCE +#include "ptk.h" + #if defined(PTK_LINUX) && defined(PTK_HAS_WAYLAND) #include "wayland_internal.h" diff --git a/lib/ptk/xmake.lua b/lib/ptk/xmake.lua index e0775a7bb..d38e28fbc 100644 --- a/lib/ptk/xmake.lua +++ b/lib/ptk/xmake.lua @@ -41,6 +41,10 @@ target("libptk") add_files(xdg_shell_xml, {rule = "wayland.protocol"}) add_files(xdg_decoration_xml, {rule = "wayland.protocol"}) set_configvar("PTK_HAS_WAYLAND", 1) + add_files("src/linux/waylandapp_core.c") + add_files("src/linux/waylandapp_input.c") + add_files("src/linux/waylandapp_output.c") + add_files("src/linux/waylandapp_window.c") end add_syslinks("pthread", "dl") end From d4161d8ccd513350634919dc48b4bdaf5ec4d84b Mon Sep 17 00:00:00 2001 From: rewine Date: Thu, 30 Jul 2026 10:56:59 +0800 Subject: [PATCH 63/66] fix(ptk): fix wayland window rendering with unified logical coordinate space Store wnd->width/height as logical pixels (matching xdg_toplevel configure), allocate buffer at logical size, and let buffer_scale handle the upscaling to physical pixels. This eliminates the physical/logical coordinate mismatch that caused content to render in only a quarter of the window on HiDPI displays. Size events send physical dimensions (logical * scale) so the upper layer correctly divides by DPI scale. Size hints pass logical values directly to the Wayland protocol as it expects. --- lib/ptk/src/linux/waylandapp_window.c | 83 ++++++++------------------- 1 file changed, 25 insertions(+), 58 deletions(-) diff --git a/lib/ptk/src/linux/waylandapp_window.c b/lib/ptk/src/linux/waylandapp_window.c index bf1085c4e..a696438e0 100644 --- a/lib/ptk/src/linux/waylandapp_window.c +++ b/lib/ptk/src/linux/waylandapp_window.c @@ -19,22 +19,27 @@ void ptk_waylandwindow_destroy_buffer(ptk_window_t *wnd) wnd->buffer_size = 0; } +static int ptk_waylandwindow_get_width(ptk_window_t *wnd) +{ + return wnd->width; +} + +static int ptk_waylandwindow_get_height(ptk_window_t *wnd) +{ + return wnd->height; +} + void ptk_waylandwindow_post_size_event(ptk_window_t *wnd) { ptk_event_t e = { 0 }; e.type = PTK_EVENT_SIZE; e.window = wnd; - e.size.width = wnd->width; - e.size.height = wnd->height; + e.size.width = wnd->width * wl_app.output_scale; + e.size.height = wnd->height * wl_app.output_scale; ptk_post_event(&e); } -static int ptk_waylandwindow_get_buffer_size(int size) -{ - return size * wl_app.output_scale; -} - static void ptk_waylandapp_on_wm_base_ping(void *data, struct xdg_wm_base *wm_base, uint32_t serial) @@ -64,19 +69,15 @@ static void ptk_waylandwindow_on_toplevel_configure( int32_t height, struct wl_array *states) { ptk_window_t *wnd = data; - int buffer_width; - int buffer_height; if (width <= 0 || height <= 0) { return; } - buffer_width = ptk_waylandwindow_get_buffer_size(width); - buffer_height = ptk_waylandwindow_get_buffer_size(height); - if (wnd->width == buffer_width && wnd->height == buffer_height) { + if (wnd->width == width && wnd->height == height) { return; } - wnd->width = buffer_width; - wnd->height = buffer_height; + wnd->width = width; + wnd->height = height; ptk_waylandwindow_destroy_buffer(wnd); ptk_waylandwindow_post_size_event(wnd); } @@ -124,10 +125,8 @@ ptk_window_t *ptk_waylandwindow_create(const wchar_t *title, int x, int y, if (!wnd) { return NULL; } - wnd->width = ptk_waylandwindow_get_buffer_size( - width > 0 ? width : PTK_WINDOW_DEFAULT_WIDTH); - wnd->height = ptk_waylandwindow_get_buffer_size( - height > 0 ? height : PTK_WINDOW_DEFAULT_HEIGHT); + wnd->width = width > 0 ? width : PTK_WINDOW_DEFAULT_WIDTH; + wnd->height = height > 0 ? height : PTK_WINDOW_DEFAULT_HEIGHT; wnd->surface = wl_compositor_create_surface(wl_app.compositor); if (!wnd->surface) { free(wnd); @@ -240,20 +239,14 @@ static void ptk_waylandwindow_destroy(ptk_window_t *wnd) static void ptk_waylandwindow_set_size(ptk_window_t *wnd, int width, int height) { - int physical_width; - int physical_height; - if (width <= 0 || height <= 0) { return; } - physical_width = ptk_waylandwindow_get_buffer_size(width); - physical_height = ptk_waylandwindow_get_buffer_size(height); - - if (wnd->width == physical_width && wnd->height == physical_height) { + if (wnd->width == width && wnd->height == height) { return; } - wnd->width = physical_width; - wnd->height = physical_height; + wnd->width = width; + wnd->height = height; ptk_waylandwindow_destroy_buffer(wnd); } @@ -266,27 +259,15 @@ static void *ptk_waylandwindow_get_handle(ptk_window_t *wnd) return wnd->surface; } -static int ptk_waylandwindow_get_width(ptk_window_t *wnd) -{ - return wnd->width / wl_app.output_scale; -} - -static int ptk_waylandwindow_get_height(ptk_window_t *wnd) -{ - return wnd->height / wl_app.output_scale; -} - static void ptk_waylandwindow_apply_size_hints(ptk_window_t *wnd) { if (!wnd->xdg_toplevel) { return; } - xdg_toplevel_set_min_size(wnd->xdg_toplevel, - wnd->min_width * wl_app.output_scale, - wnd->min_height * wl_app.output_scale); - xdg_toplevel_set_max_size(wnd->xdg_toplevel, - wnd->max_width * wl_app.output_scale, - wnd->max_height * wl_app.output_scale); + xdg_toplevel_set_min_size(wnd->xdg_toplevel, wnd->min_width, + wnd->min_height); + xdg_toplevel_set_max_size(wnd->xdg_toplevel, wnd->max_width, + wnd->max_height); } static void ptk_waylandwindow_set_min_width(ptk_window_t *wnd, int min_width) @@ -321,7 +302,6 @@ static unsigned ptk_waylandwindow_get_dpi(ptk_window_t *wnd) static ptk_window_paint_t *ptk_waylandwindow_begin_paint(ptk_window_t *wnd, pd_rect_t *rect) { - size_t size; int fd; struct wl_shm_pool *pool; @@ -329,7 +309,7 @@ static ptk_window_paint_t *ptk_waylandwindow_begin_paint(ptk_window_t *wnd, return NULL; } if (!wnd->buffer) { - size = (size_t)wnd->width * (size_t)wnd->height * 4; + size_t size = (size_t)wnd->width * (size_t)wnd->height * 4; fd = memfd_create("lcui-wayland-buffer", MFD_CLOEXEC); if (fd < 0) { return NULL; @@ -352,12 +332,6 @@ static ptk_window_paint_t *ptk_waylandwindow_begin_paint(ptk_window_t *wnd, wl_shm_pool_destroy(pool); close(fd); wnd->buffer_size = size; - /* Initialize the backing canvas once per buffer lifetime. - * pd_canvas_init leaves mem_size=0 and bytes=NULL; we - * override bytes to point at the mmap'd shm buffer. - * The canvas must NOT be passed to pd_canvas_destroy(), - * which would free() the pointer — use destroy_buffer instead. - */ pd_canvas_init(&wnd->canvas); wnd->canvas.width = wnd->width; wnd->canvas.height = wnd->height; @@ -372,19 +346,12 @@ static ptk_window_paint_t *ptk_waylandwindow_begin_paint(ptk_window_t *wnd, return NULL; } } - /* Set up the paint context following pd_context_create() semantics: - * paint->canvas must be a pd_canvas_quote() of the full backing canvas - * clipped to the dirty rect. Pandagl renderers draw at (0,0) within - * this quoted canvas, which corresponds to (rect->x, rect->y) in the - * actual shm buffer. Setting canvas = full buffer (old code) caused - * all renders to write to buffer[0,0] regardless of the dirty rect. */ wnd->paint_ctx->rect = *rect; wnd->paint_ctx->with_alpha = false; pd_rect_correct(&wnd->paint_ctx->rect, wnd->width, wnd->height); pd_canvas_init(&wnd->paint_ctx->canvas); pd_canvas_quote(&wnd->paint_ctx->canvas, &wnd->canvas, &wnd->paint_ctx->rect); - /* Clear the dirty region to white before the widget renders into it */ pd_canvas_fill(&wnd->paint_ctx->canvas, pd_rgb(255, 255, 255)); return wnd->paint_ctx; } From 089ef811edf3105a99dc99742379d447c20409fc Mon Sep 17 00:00:00 2001 From: rewine Date: Thu, 30 Jul 2026 17:30:31 +0800 Subject: [PATCH 64/66] fix(ptk): correct HiDPI scaling for Wayland integer scale factors - Allocate SHM buffer at physical pixel dimensions (logical * scale) - Scale pointer coordinates to physical pixels in mouse events - Return physical pixel dimensions from screen and window size getters - Convert physical pixels to logical in set_size and size hints - Post size event on output_scale change to trigger layout refresh --- lib/ptk/src/linux/waylandapp_core.c | 4 +- lib/ptk/src/linux/waylandapp_input.c | 12 +++--- lib/ptk/src/linux/waylandapp_output.c | 1 + lib/ptk/src/linux/waylandapp_window.c | 58 ++++++++++++++++++--------- 4 files changed, 48 insertions(+), 27 deletions(-) diff --git a/lib/ptk/src/linux/waylandapp_core.c b/lib/ptk/src/linux/waylandapp_core.c index b696f21aa..c22f07594 100644 --- a/lib/ptk/src/linux/waylandapp_core.c +++ b/lib/ptk/src/linux/waylandapp_core.c @@ -292,12 +292,12 @@ static int ptk_waylandapp_off_event(int type, static int ptk_waylandapp_get_screen_width(void) { - return wl_app.screen_width / wl_app.output_scale; + return wl_app.screen_width; } static int ptk_waylandapp_get_screen_height(void) { - return wl_app.screen_height / wl_app.output_scale; + return wl_app.screen_height; } void ptk_waylandapp_driver_init(ptk_app_driver_t *driver) diff --git a/lib/ptk/src/linux/waylandapp_input.c b/lib/ptk/src/linux/waylandapp_input.c index 6ee6da80d..b2699c1c7 100644 --- a/lib/ptk/src/linux/waylandapp_input.c +++ b/lib/ptk/src/linux/waylandapp_input.c @@ -35,8 +35,8 @@ static void ptk_waylandapp_on_pointer_enter( ptk_event_t e = { 0 }; e.type = PTK_EVENT_MOUSEMOVE; e.window = wl_app.pointer_focus; - e.mouse.x = (int)wl_app.pointer_x; - e.mouse.y = (int)wl_app.pointer_y; + e.mouse.x = (int)(wl_app.pointer_x * wl_app.output_scale); + e.mouse.y = (int)(wl_app.pointer_y * wl_app.output_scale); ptk_post_event(&e); } } @@ -64,8 +64,8 @@ static void ptk_waylandapp_on_pointer_motion(void *data, if (wl_app.pointer_focus) { e.type = PTK_EVENT_MOUSEMOVE; e.window = wl_app.pointer_focus; - e.mouse.x = (int)wl_app.pointer_x; - e.mouse.y = (int)wl_app.pointer_y; + e.mouse.x = (int)(wl_app.pointer_x * wl_app.output_scale); + e.mouse.y = (int)(wl_app.pointer_y * wl_app.output_scale); ptk_post_event(&e); } } @@ -82,8 +82,8 @@ static void ptk_waylandapp_on_pointer_button(void *data, ? PTK_EVENT_MOUSEDOWN : PTK_EVENT_MOUSEUP; e.window = wl_app.pointer_focus; - e.mouse.x = (int)wl_app.pointer_x; - e.mouse.y = (int)wl_app.pointer_y; + e.mouse.x = (int)(wl_app.pointer_x * wl_app.output_scale); + e.mouse.y = (int)(wl_app.pointer_y * wl_app.output_scale); if (button == (0x110)) { /* BTN_LEFT */ e.mouse.button = MOUSE_BUTTON_LEFT; } else if (button == (0x111)) { /* BTN_RIGHT */ diff --git a/lib/ptk/src/linux/waylandapp_output.c b/lib/ptk/src/linux/waylandapp_output.c index c6deafd8e..01814f015 100644 --- a/lib/ptk/src/linux/waylandapp_output.c +++ b/lib/ptk/src/linux/waylandapp_output.c @@ -45,6 +45,7 @@ static void ptk_waylandapp_on_output_scale(void *data, ptk_window_t *wnd = node->data; if (wnd) { ptk_waylandwindow_destroy_buffer(wnd); + ptk_waylandwindow_post_size_event(wnd); } } } diff --git a/lib/ptk/src/linux/waylandapp_window.c b/lib/ptk/src/linux/waylandapp_window.c index a696438e0..c864d8aec 100644 --- a/lib/ptk/src/linux/waylandapp_window.c +++ b/lib/ptk/src/linux/waylandapp_window.c @@ -21,22 +21,27 @@ void ptk_waylandwindow_destroy_buffer(ptk_window_t *wnd) static int ptk_waylandwindow_get_width(ptk_window_t *wnd) { - return wnd->width; + int scale = wl_app.output_scale > 0 ? wl_app.output_scale : 1; + + return wnd->width * scale; } static int ptk_waylandwindow_get_height(ptk_window_t *wnd) { - return wnd->height; + int scale = wl_app.output_scale > 0 ? wl_app.output_scale : 1; + + return wnd->height * scale; } void ptk_waylandwindow_post_size_event(ptk_window_t *wnd) { ptk_event_t e = { 0 }; + int scale = wl_app.output_scale > 0 ? wl_app.output_scale : 1; e.type = PTK_EVENT_SIZE; e.window = wnd; - e.size.width = wnd->width * wl_app.output_scale; - e.size.height = wnd->height * wl_app.output_scale; + e.size.width = wnd->width * scale; + e.size.height = wnd->height * scale; ptk_post_event(&e); } @@ -117,6 +122,9 @@ ptk_window_t *ptk_waylandwindow_create(const wchar_t *title, int x, int y, ptk_window_t *parent) { ptk_window_t *wnd; + int scale = wl_app.output_scale > 0 ? wl_app.output_scale : 1; + int physical_w; + int physical_h; if (!wl_app.compositor || !wl_app.wm_base || !wl_app.shm) { return NULL; @@ -125,8 +133,10 @@ ptk_window_t *ptk_waylandwindow_create(const wchar_t *title, int x, int y, if (!wnd) { return NULL; } - wnd->width = width > 0 ? width : PTK_WINDOW_DEFAULT_WIDTH; - wnd->height = height > 0 ? height : PTK_WINDOW_DEFAULT_HEIGHT; + physical_w = width > 0 ? width : PTK_WINDOW_DEFAULT_WIDTH; + physical_h = height > 0 ? height : PTK_WINDOW_DEFAULT_HEIGHT; + wnd->width = physical_w / scale; + wnd->height = physical_h / scale; wnd->surface = wl_compositor_create_surface(wl_app.compositor); if (!wnd->surface) { free(wnd); @@ -239,14 +249,18 @@ static void ptk_waylandwindow_destroy(ptk_window_t *wnd) static void ptk_waylandwindow_set_size(ptk_window_t *wnd, int width, int height) { + int scale = wl_app.output_scale > 0 ? wl_app.output_scale : 1; + int logical_w = width / scale; + int logical_h = height / scale; + if (width <= 0 || height <= 0) { return; } - if (wnd->width == width && wnd->height == height) { + if (wnd->width == logical_w && wnd->height == logical_h) { return; } - wnd->width = width; - wnd->height = height; + wnd->width = logical_w; + wnd->height = logical_h; ptk_waylandwindow_destroy_buffer(wnd); } @@ -261,13 +275,15 @@ static void *ptk_waylandwindow_get_handle(ptk_window_t *wnd) static void ptk_waylandwindow_apply_size_hints(ptk_window_t *wnd) { + int scale = wl_app.output_scale > 0 ? wl_app.output_scale : 1; + if (!wnd->xdg_toplevel) { return; } - xdg_toplevel_set_min_size(wnd->xdg_toplevel, wnd->min_width, - wnd->min_height); - xdg_toplevel_set_max_size(wnd->xdg_toplevel, wnd->max_width, - wnd->max_height); + xdg_toplevel_set_min_size(wnd->xdg_toplevel, wnd->min_width / scale, + wnd->min_height / scale); + xdg_toplevel_set_max_size(wnd->xdg_toplevel, wnd->max_width / scale, + wnd->max_height / scale); } static void ptk_waylandwindow_set_min_width(ptk_window_t *wnd, int min_width) @@ -303,13 +319,17 @@ static ptk_window_paint_t *ptk_waylandwindow_begin_paint(ptk_window_t *wnd, pd_rect_t *rect) { int fd; + int buf_width; + int buf_height; struct wl_shm_pool *pool; if (!wnd->configured || !rect) { return NULL; } + buf_width = wnd->width * wl_app.output_scale; + buf_height = wnd->height * wl_app.output_scale; if (!wnd->buffer) { - size_t size = (size_t)wnd->width * (size_t)wnd->height * 4; + size_t size = (size_t)buf_width * (size_t)buf_height * 4; fd = memfd_create("lcui-wayland-buffer", MFD_CLOEXEC); if (fd < 0) { return NULL; @@ -327,18 +347,18 @@ static ptk_window_paint_t *ptk_waylandwindow_begin_paint(ptk_window_t *wnd, } pool = wl_shm_create_pool(wl_app.shm, fd, (int)size); wnd->buffer = wl_shm_pool_create_buffer( - pool, 0, wnd->width, wnd->height, wnd->width * 4, + pool, 0, buf_width, buf_height, buf_width * 4, WL_SHM_FORMAT_XRGB8888); wl_shm_pool_destroy(pool); close(fd); wnd->buffer_size = size; pd_canvas_init(&wnd->canvas); - wnd->canvas.width = wnd->width; - wnd->canvas.height = wnd->height; + wnd->canvas.width = buf_width; + wnd->canvas.height = buf_height; wnd->canvas.color_type = PD_COLOR_TYPE_ARGB; wnd->canvas.bytes = wnd->buffer_data; wnd->canvas.bytes_per_pixel = 4; - wnd->canvas.bytes_per_row = wnd->width * 4; + wnd->canvas.bytes_per_row = buf_width * 4; } if (!wnd->paint_ctx) { wnd->paint_ctx = calloc(1, sizeof(*wnd->paint_ctx)); @@ -348,7 +368,7 @@ static ptk_window_paint_t *ptk_waylandwindow_begin_paint(ptk_window_t *wnd, } wnd->paint_ctx->rect = *rect; wnd->paint_ctx->with_alpha = false; - pd_rect_correct(&wnd->paint_ctx->rect, wnd->width, wnd->height); + pd_rect_correct(&wnd->paint_ctx->rect, buf_width, buf_height); pd_canvas_init(&wnd->paint_ctx->canvas); pd_canvas_quote(&wnd->paint_ctx->canvas, &wnd->canvas, &wnd->paint_ctx->rect); From e868b17b781efde2e720d9aed1c7da888c04a91e Mon Sep 17 00:00:00 2001 From: rewine Date: Thu, 30 Jul 2026 20:21:37 +0800 Subject: [PATCH 65/66] feat(ptk): add fractional scale support for Wayland backend Add wp_viewporter and wp_fractional_scale_v1 protocol support to handle non-integer HiDPI scaling on Wayland. - Bind viewporter and fractional-scale manager from registry - Create wp_viewport per window with source following buffer size - Use wp_fractional_scale_v1 to receive per-window scale from compositor - Fall back to wl_surface_set_buffer_scale when viewporter unavailable - Change output_scale from int to double, use lround for int conversions - Fix initial window size by setting xdg_surface window geometry - Use per-window scale for input coordinate conversion - Reuse ptk_waylandwindow_destroy in app destroy to avoid resource leak --- lib/ptk/src/linux/wayland_internal.h | 12 +++- lib/ptk/src/linux/waylandapp_core.c | 42 ++++++------ lib/ptk/src/linux/waylandapp_input.c | 24 ++++--- lib/ptk/src/linux/waylandapp_output.c | 7 +- lib/ptk/src/linux/waylandapp_window.c | 99 ++++++++++++++++++++------- lib/ptk/xmake.lua | 4 ++ 6 files changed, 128 insertions(+), 60 deletions(-) diff --git a/lib/ptk/src/linux/wayland_internal.h b/lib/ptk/src/linux/wayland_internal.h index a9da73189..d72b56f90 100644 --- a/lib/ptk/src/linux/wayland_internal.h +++ b/lib/ptk/src/linux/wayland_internal.h @@ -8,6 +8,7 @@ #endif #include #include +#include #include #include #include @@ -24,6 +25,8 @@ #include "waylandapp.h" #include "xdg-shell-client-protocol.h" #include "xdg-decoration-unstable-v1-client-protocol.h" +#include "viewporter-client-protocol.h" +#include "fractional-scale-v1-client-protocol.h" #ifndef WL_KEYBOARD_KEY_STATE_REPEATED #define WL_KEYBOARD_KEY_STATE_REPEATED 2 @@ -37,11 +40,14 @@ typedef struct ptk_window { struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; struct zxdg_toplevel_decoration_v1 *decoration; + struct wp_viewport *viewport; + struct wp_fractional_scale_v1 *fractional_scale; struct wl_buffer *buffer; void *buffer_data; size_t buffer_size; int width; int height; + double scale; bool configured; int min_width; int min_height; @@ -60,6 +66,8 @@ typedef struct ptk_wayland_app { struct wl_compositor *compositor; struct wl_shm *shm; struct zxdg_decoration_manager_v1 *decoration_manager; + struct wp_viewporter *viewporter; + struct wp_fractional_scale_manager_v1 *fractional_scale_manager; struct xdg_wm_base *wm_base; struct wl_output *output; struct wl_seat *seat; @@ -73,7 +81,7 @@ typedef struct ptk_wayland_app { int exit_code; int screen_width; int screen_height; - int output_scale; + double output_scale; struct xkb_context *xkb_context; struct xkb_keymap *xkb_map; @@ -104,6 +112,8 @@ extern const struct wl_registry_listener registry_listener; extern const struct xdg_wm_base_listener wm_base_listener; extern const struct xdg_surface_listener xdg_surface_listener; extern const struct xdg_toplevel_listener xdg_toplevel_listener; +extern const struct wp_fractional_scale_v1_listener fractional_scale_listener; +void ptk_waylandwindow_destroy(ptk_window_t *wnd); ptk_window_t *ptk_waylandapp_get_window(void *handle); void ptk_waylandwindow_destroy_buffer(ptk_window_t *wnd); diff --git a/lib/ptk/src/linux/waylandapp_core.c b/lib/ptk/src/linux/waylandapp_core.c index c22f07594..000dd0f73 100644 --- a/lib/ptk/src/linux/waylandapp_core.c +++ b/lib/ptk/src/linux/waylandapp_core.c @@ -61,6 +61,18 @@ static void ptk_waylandapp_on_registry_global(void *data, wl_seat_add_listener(wl_app.seat, &seat_listener, NULL); return; } + if (strcmp(interface, wp_viewporter_interface.name) == 0) { + wl_app.viewporter = wl_registry_bind( + registry, name, &wp_viewporter_interface, 1); + return; + } + if (strcmp(interface, wp_fractional_scale_manager_v1_interface.name) == + 0) { + wl_app.fractional_scale_manager = wl_registry_bind( + registry, name, &wp_fractional_scale_manager_v1_interface, + 1); + return; + } } static void ptk_waylandapp_on_registry_global_remove( @@ -122,29 +134,10 @@ static int ptk_waylandapp_poll_events(int timeout_ms, bool dispatch_all) static int ptk_waylandapp_destroy(void) { list_node_t *node, *next; - ptk_window_t *wnd; for (node = wl_app.windows.head.next; node; node = next) { next = node->next; - wnd = node->data; - if (wnd) { - if (wnd->decoration) { - zxdg_toplevel_decoration_v1_destroy( - wnd->decoration); - } - if (wnd->xdg_toplevel) { - xdg_toplevel_destroy(wnd->xdg_toplevel); - } - if (wnd->xdg_surface) { - xdg_surface_destroy(wnd->xdg_surface); - } - if (wnd->surface) { - wl_surface_destroy(wnd->surface); - } - ptk_waylandwindow_destroy_buffer(wnd); - free(wnd->paint_ctx); - free(wnd); - } + ptk_waylandwindow_destroy(node->data); } list_create(&wl_app.windows); if (wl_app.pointer) { @@ -180,6 +173,13 @@ static int ptk_waylandapp_destroy(void) if (wl_app.output) { wl_output_destroy(wl_app.output); } + if (wl_app.fractional_scale_manager) { + wp_fractional_scale_manager_v1_destroy( + wl_app.fractional_scale_manager); + } + if (wl_app.viewporter) { + wp_viewporter_destroy(wl_app.viewporter); + } if (wl_app.decoration_manager) { zxdg_decoration_manager_v1_destroy(wl_app.decoration_manager); } @@ -205,7 +205,7 @@ static int ptk_waylandapp_destroy(void) static int ptk_waylandapp_init(const wchar_t *name) { memset(&wl_app, 0, sizeof(wl_app)); - wl_app.output_scale = 1; + wl_app.output_scale = 1.0; wl_app.display = wl_display_connect(NULL); if (!wl_app.display) { logger_error("[wayland] wl_display_connect() failed\n"); diff --git a/lib/ptk/src/linux/waylandapp_input.c b/lib/ptk/src/linux/waylandapp_input.c index b2699c1c7..db8c617fc 100644 --- a/lib/ptk/src/linux/waylandapp_input.c +++ b/lib/ptk/src/linux/waylandapp_input.c @@ -21,7 +21,7 @@ static void ptk_waylandapp_on_pointer_enter( wl_pointer_set_cursor(wl_pointer, serial, wl_app.cursor_surface, image->hotspot_x, image->hotspot_y); wl_surface_set_buffer_scale(wl_app.cursor_surface, - wl_app.output_scale); + wl_app.pointer_focus->scale); wl_surface_attach(wl_app.cursor_surface, wl_cursor_image_get_buffer(image), 0, 0); wl_surface_damage_buffer(wl_app.cursor_surface, 0, 0, @@ -29,14 +29,16 @@ static void ptk_waylandapp_on_pointer_enter( wl_surface_commit(wl_app.cursor_surface); } - /* Wayland enter does not emit motion, but LCUI needs initial coordinate - * state applied immediately */ + /* Wayland enter does not emit motion, but LCUI needs initial + * coordinate state applied immediately */ if (wl_app.pointer_focus) { ptk_event_t e = { 0 }; + double scale = wl_app.pointer_focus->scale; + e.type = PTK_EVENT_MOUSEMOVE; e.window = wl_app.pointer_focus; - e.mouse.x = (int)(wl_app.pointer_x * wl_app.output_scale); - e.mouse.y = (int)(wl_app.pointer_y * wl_app.output_scale); + e.mouse.x = (int)lround(wl_app.pointer_x * scale); + e.mouse.y = (int)lround(wl_app.pointer_y * scale); ptk_post_event(&e); } } @@ -62,10 +64,12 @@ static void ptk_waylandapp_on_pointer_motion(void *data, wl_app.pointer_y = wl_fixed_to_double(surface_y); if (wl_app.pointer_focus) { + double scale = wl_app.pointer_focus->scale; + e.type = PTK_EVENT_MOUSEMOVE; e.window = wl_app.pointer_focus; - e.mouse.x = (int)(wl_app.pointer_x * wl_app.output_scale); - e.mouse.y = (int)(wl_app.pointer_y * wl_app.output_scale); + e.mouse.x = (int)lround(wl_app.pointer_x * scale); + e.mouse.y = (int)lround(wl_app.pointer_y * scale); ptk_post_event(&e); } } @@ -78,12 +82,14 @@ static void ptk_waylandapp_on_pointer_button(void *data, ptk_event_t e = { 0 }; if (wl_app.pointer_focus) { + double scale = wl_app.pointer_focus->scale; + e.type = state == WL_POINTER_BUTTON_STATE_PRESSED ? PTK_EVENT_MOUSEDOWN : PTK_EVENT_MOUSEUP; e.window = wl_app.pointer_focus; - e.mouse.x = (int)(wl_app.pointer_x * wl_app.output_scale); - e.mouse.y = (int)(wl_app.pointer_y * wl_app.output_scale); + e.mouse.x = (int)lround(wl_app.pointer_x * scale); + e.mouse.y = (int)lround(wl_app.pointer_y * scale); if (button == (0x110)) { /* BTN_LEFT */ e.mouse.button = MOUSE_BUTTON_LEFT; } else if (button == (0x111)) { /* BTN_RIGHT */ diff --git a/lib/ptk/src/linux/waylandapp_output.c b/lib/ptk/src/linux/waylandapp_output.c index 01814f015..a40ecf740 100644 --- a/lib/ptk/src/linux/waylandapp_output.c +++ b/lib/ptk/src/linux/waylandapp_output.c @@ -34,16 +34,17 @@ static void ptk_waylandapp_on_output_scale(void *data, { list_node_t *node; - if (factor <= 0 || wl_app.output_scale == factor) { + if (factor <= 0 || wl_app.output_scale == (double)factor) { return; } - wl_app.output_scale = factor; + wl_app.output_scale = (double)factor; /* Destroy buffers so they are recreated at the new scale on * the next paint. The compositor will send a configure event * with updated logical size. */ for (list_each(node, &wl_app.windows)) { ptk_window_t *wnd = node->data; - if (wnd) { + if (wnd && !wnd->fractional_scale) { + wnd->scale = wl_app.output_scale; ptk_waylandwindow_destroy_buffer(wnd); ptk_waylandwindow_post_size_event(wnd); } diff --git a/lib/ptk/src/linux/waylandapp_window.c b/lib/ptk/src/linux/waylandapp_window.c index c864d8aec..c835cc56e 100644 --- a/lib/ptk/src/linux/waylandapp_window.c +++ b/lib/ptk/src/linux/waylandapp_window.c @@ -21,27 +21,22 @@ void ptk_waylandwindow_destroy_buffer(ptk_window_t *wnd) static int ptk_waylandwindow_get_width(ptk_window_t *wnd) { - int scale = wl_app.output_scale > 0 ? wl_app.output_scale : 1; - - return wnd->width * scale; + return (int)lround(wnd->width * wnd->scale); } static int ptk_waylandwindow_get_height(ptk_window_t *wnd) { - int scale = wl_app.output_scale > 0 ? wl_app.output_scale : 1; - - return wnd->height * scale; + return (int)lround(wnd->height * wnd->scale); } void ptk_waylandwindow_post_size_event(ptk_window_t *wnd) { ptk_event_t e = { 0 }; - int scale = wl_app.output_scale > 0 ? wl_app.output_scale : 1; e.type = PTK_EVENT_SIZE; e.window = wnd; - e.size.width = wnd->width * scale; - e.size.height = wnd->height * scale; + e.size.width = (int)lround(wnd->width * wnd->scale); + e.size.height = (int)lround(wnd->height * wnd->scale); ptk_post_event(&e); } @@ -117,12 +112,29 @@ const struct xdg_toplevel_listener xdg_toplevel_listener = { ptk_waylandwindow_on_toplevel_wm_capabilities }; +static void ptk_waylandwindow_on_fractional_scale_preferred( + void *data, struct wp_fractional_scale_v1 *wp_fractional_scale_v1, + uint32_t scale) +{ + ptk_window_t *wnd = data; + double new_scale = scale / 120.0; + + if (new_scale != wnd->scale) { + wnd->scale = new_scale; + ptk_waylandwindow_destroy_buffer(wnd); + ptk_waylandwindow_post_size_event(wnd); + } +} + +const struct wp_fractional_scale_v1_listener fractional_scale_listener = { + ptk_waylandwindow_on_fractional_scale_preferred +}; + ptk_window_t *ptk_waylandwindow_create(const wchar_t *title, int x, int y, int width, int height, ptk_window_t *parent) { ptk_window_t *wnd; - int scale = wl_app.output_scale > 0 ? wl_app.output_scale : 1; int physical_w; int physical_h; @@ -133,10 +145,11 @@ ptk_window_t *ptk_waylandwindow_create(const wchar_t *title, int x, int y, if (!wnd) { return NULL; } + wnd->scale = wl_app.output_scale > 0.0 ? wl_app.output_scale : 1.0; physical_w = width > 0 ? width : PTK_WINDOW_DEFAULT_WIDTH; physical_h = height > 0 ? height : PTK_WINDOW_DEFAULT_HEIGHT; - wnd->width = physical_w / scale; - wnd->height = physical_h / scale; + wnd->width = (int)lround(physical_w / wnd->scale); + wnd->height = (int)lround(physical_h / wnd->scale); wnd->surface = wl_compositor_create_surface(wl_app.compositor); if (!wnd->surface) { free(wnd); @@ -171,6 +184,25 @@ ptk_window_t *ptk_waylandwindow_create(const wchar_t *title, int x, int y, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); } } + if (wl_app.viewporter) { + /* -1 means "source size follows the attached buffer"; the + * viewport will scale the buffer to the destination set in + * end_paint. */ + wnd->viewport = + wp_viewporter_get_viewport(wl_app.viewporter, wnd->surface); + wp_viewport_set_source( + wnd->viewport, wl_fixed_from_int(-1), wl_fixed_from_int(-1), + wl_fixed_from_int(-1), wl_fixed_from_int(-1)); + } + if (wl_app.fractional_scale_manager) { + wnd->fractional_scale = + wp_fractional_scale_manager_v1_get_fractional_scale( + wl_app.fractional_scale_manager, wnd->surface); + wp_fractional_scale_v1_add_listener( + wnd->fractional_scale, &fractional_scale_listener, wnd); + } + xdg_surface_set_window_geometry(wnd->xdg_surface, 0, 0, wnd->width, + wnd->height); if (title) { size_t len = encode_utf8(NULL, title, 0) + 1; char *utf8_title = malloc(sizeof(char) * len); @@ -224,12 +256,18 @@ static void ptk_waylandwindow_set_title(ptk_window_t *wnd, const wchar_t *title) free(utf8_title); } -static void ptk_waylandwindow_destroy(ptk_window_t *wnd) +void ptk_waylandwindow_destroy(ptk_window_t *wnd) { if (!wnd) { return; } list_unlink(&wl_app.windows, &wnd->node); + if (wnd->fractional_scale) { + wp_fractional_scale_v1_destroy(wnd->fractional_scale); + } + if (wnd->viewport) { + wp_viewport_destroy(wnd->viewport); + } if (wnd->decoration) { zxdg_toplevel_decoration_v1_destroy(wnd->decoration); } @@ -249,9 +287,8 @@ static void ptk_waylandwindow_destroy(ptk_window_t *wnd) static void ptk_waylandwindow_set_size(ptk_window_t *wnd, int width, int height) { - int scale = wl_app.output_scale > 0 ? wl_app.output_scale : 1; - int logical_w = width / scale; - int logical_h = height / scale; + int logical_w = (int)lround(width / wnd->scale); + int logical_h = (int)lround(height / wnd->scale); if (width <= 0 || height <= 0) { return; @@ -275,15 +312,15 @@ static void *ptk_waylandwindow_get_handle(ptk_window_t *wnd) static void ptk_waylandwindow_apply_size_hints(ptk_window_t *wnd) { - int scale = wl_app.output_scale > 0 ? wl_app.output_scale : 1; - if (!wnd->xdg_toplevel) { return; } - xdg_toplevel_set_min_size(wnd->xdg_toplevel, wnd->min_width / scale, - wnd->min_height / scale); - xdg_toplevel_set_max_size(wnd->xdg_toplevel, wnd->max_width / scale, - wnd->max_height / scale); + xdg_toplevel_set_min_size(wnd->xdg_toplevel, + (int)lround(wnd->min_width / wnd->scale), + (int)lround(wnd->min_height / wnd->scale)); + xdg_toplevel_set_max_size(wnd->xdg_toplevel, + (int)lround(wnd->max_width / wnd->scale), + (int)lround(wnd->max_height / wnd->scale)); } static void ptk_waylandwindow_set_min_width(ptk_window_t *wnd, int min_width) @@ -312,7 +349,7 @@ static void ptk_waylandwindow_set_max_height(ptk_window_t *wnd, int max_height) static unsigned ptk_waylandwindow_get_dpi(ptk_window_t *wnd) { - return wl_app.output_scale * 96; + return (unsigned)lround(wnd->scale * 96); } static ptk_window_paint_t *ptk_waylandwindow_begin_paint(ptk_window_t *wnd, @@ -326,8 +363,12 @@ static ptk_window_paint_t *ptk_waylandwindow_begin_paint(ptk_window_t *wnd, if (!wnd->configured || !rect) { return NULL; } - buf_width = wnd->width * wl_app.output_scale; - buf_height = wnd->height * wl_app.output_scale; + buf_width = (int)lround(wnd->width * wnd->scale); + buf_height = (int)lround(wnd->height * wnd->scale); + if (buf_width <= 0) + buf_width = 1; + if (buf_height <= 0) + buf_height = 1; if (!wnd->buffer) { size_t size = (size_t)buf_width * (size_t)buf_height * 4; fd = memfd_create("lcui-wayland-buffer", MFD_CLOEXEC); @@ -382,7 +423,13 @@ static void ptk_waylandwindow_end_paint(ptk_window_t *wnd, if (!wnd || !paint || !wnd->buffer) { return; } - wl_surface_set_buffer_scale(wnd->surface, wl_app.output_scale); + if (wnd->viewport) { + wp_viewport_set_destination(wnd->viewport, wnd->width, + wnd->height); + wl_surface_set_buffer_scale(wnd->surface, 1); + } else { + wl_surface_set_buffer_scale(wnd->surface, (int)wnd->scale); + } wl_surface_attach(wnd->surface, wnd->buffer, 0, 0); wl_surface_damage_buffer(wnd->surface, paint->rect.x, paint->rect.y, paint->rect.width, paint->rect.height); diff --git a/lib/ptk/xmake.lua b/lib/ptk/xmake.lua index d38e28fbc..39b96961a 100644 --- a/lib/ptk/xmake.lua +++ b/lib/ptk/xmake.lua @@ -3,6 +3,8 @@ includes("rules/xmake.lua") local wayland_protocol_root = os.getenv("WAYLAND_PROTOCOLS_DIR") or "/usr/share/wayland-protocols" local xdg_shell_xml = path.join(wayland_protocol_root, "stable", "xdg-shell", "xdg-shell.xml") local xdg_decoration_xml = path.join(wayland_protocol_root, "unstable", "xdg-decoration", "xdg-decoration-unstable-v1.xml") +local viewporter_xml = path.join(wayland_protocol_root, "stable", "viewporter", "viewporter.xml") +local fractional_scale_xml = path.join(wayland_protocol_root, "staging", "fractional-scale", "fractional-scale-v1.xml") if is_plat("linux") then add_requires("libx11", "wayland", "xkbcommon", "wayland-cursor", {optional = true}) @@ -40,6 +42,8 @@ target("libptk") add_rules("wayland.protocol") add_files(xdg_shell_xml, {rule = "wayland.protocol"}) add_files(xdg_decoration_xml, {rule = "wayland.protocol"}) + add_files(viewporter_xml, {rule = "wayland.protocol"}) + add_files(fractional_scale_xml, {rule = "wayland.protocol"}) set_configvar("PTK_HAS_WAYLAND", 1) add_files("src/linux/waylandapp_core.c") add_files("src/linux/waylandapp_input.c") From 49f1d59c6f9ebe5489fbbd96ebbb434909606df6 Mon Sep 17 00:00:00 2001 From: rewine Date: Thu, 30 Jul 2026 20:24:53 +0800 Subject: [PATCH 66/66] fix(ptk): sync window geometry with compositor on every frame Call xdg_surface_set_window_geometry before each surface commit so that SSD decorations track resize correctly. --- lib/ptk/src/linux/waylandapp_window.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ptk/src/linux/waylandapp_window.c b/lib/ptk/src/linux/waylandapp_window.c index c835cc56e..8b43e478c 100644 --- a/lib/ptk/src/linux/waylandapp_window.c +++ b/lib/ptk/src/linux/waylandapp_window.c @@ -431,6 +431,8 @@ static void ptk_waylandwindow_end_paint(ptk_window_t *wnd, wl_surface_set_buffer_scale(wnd->surface, (int)wnd->scale); } wl_surface_attach(wnd->surface, wnd->buffer, 0, 0); + xdg_surface_set_window_geometry(wnd->xdg_surface, 0, 0, wnd->width, + wnd->height); wl_surface_damage_buffer(wnd->surface, paint->rect.x, paint->rect.y, paint->rect.width, paint->rect.height); wl_surface_commit(wnd->surface);