mirror of
https://github.com/JannisHeydemann/BoredOS.git
synced 2026-05-30 10:26:59 +00:00
FEAT: libwidget.c
This commit is contained in:
@@ -11,7 +11,7 @@ LDFLAGS = -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic
|
||||
BIN_DIR = bin
|
||||
|
||||
LIBC_SOURCES = $(wildcard libc/*.c)
|
||||
LIBC_OBJS = $(patsubst libc/%.c, $(BIN_DIR)/%.o, $(LIBC_SOURCES)) $(BIN_DIR)/crt0.o
|
||||
LIBC_OBJS = $(patsubst libc/%.c, $(BIN_DIR)/%.o, $(LIBC_SOURCES)) $(BIN_DIR)/crt0.o $(BIN_DIR)/libwidget.o
|
||||
|
||||
VPATH = cli gui sys games libc net
|
||||
vpath %.c cli gui sys games libc net
|
||||
@@ -34,6 +34,9 @@ $(BIN_DIR)/crt0.o: crt0.asm
|
||||
$(BIN_DIR)/%.o: libc/%.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BIN_DIR)/libwidget.o: ../wm/libwidget.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BIN_DIR)/stb_image.o: stb_image.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "libc/syscall.h"
|
||||
#include "libc/libui.h"
|
||||
#include "libc/stdlib.h"
|
||||
#include "../../wm/libwidget.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#define COLOR_DARK_PANEL 0xFF202020
|
||||
@@ -90,8 +91,30 @@ static char open_filename[256] = "";
|
||||
static _Bool file_modified = 0;
|
||||
static int scroll_y = 0;
|
||||
|
||||
static _Bool is_dragging_scrollbar = 0;
|
||||
static int scrollbar_drag_offset_y = 0;
|
||||
static widget_scrollbar_t doc_scrollbar;
|
||||
|
||||
static void word_draw_rect(void *user_data, int x, int y, int w, int h, uint32_t color) {
|
||||
ui_draw_rect((ui_window_t)user_data, x, y, w, h, color);
|
||||
}
|
||||
static void word_draw_rounded_rect_filled(void *user_data, int x, int y, int w, int h, int r, uint32_t color) {
|
||||
ui_draw_rounded_rect_filled((ui_window_t)user_data, x, y, w, h, r, color);
|
||||
}
|
||||
static void word_draw_string(void *user_data, int x, int y, const char *str, uint32_t color) {
|
||||
ui_draw_string((ui_window_t)user_data, x, y, str, color);
|
||||
}
|
||||
|
||||
static widget_context_t word_ctx = {
|
||||
.user_data = 0,
|
||||
.draw_rect = word_draw_rect,
|
||||
.draw_rounded_rect_filled = word_draw_rounded_rect_filled,
|
||||
.draw_string = word_draw_string,
|
||||
.mark_dirty = NULL
|
||||
};
|
||||
|
||||
static void word_on_scroll(void *user_data, int new_scroll_y) {
|
||||
(void)user_data;
|
||||
scroll_y = new_scroll_y;
|
||||
}
|
||||
|
||||
static _Bool is_in_selection(int p, int r, int c);
|
||||
|
||||
@@ -1301,20 +1324,13 @@ static void draw_document(ui_window_t win) {
|
||||
set_active_font(win, 0);
|
||||
|
||||
int content_h = current_page * (page_h + 20) + page_h + 20;
|
||||
if (content_h > win_h - 40) {
|
||||
int sb_x = win_w - 12;
|
||||
int sb_w = 12;
|
||||
int sb_h = win_h - 40;
|
||||
float ratio = (float)(win_h - 40) / (float)content_h;
|
||||
int thumb_h = (int)(sb_h * ratio);
|
||||
if (thumb_h < 20) thumb_h = 20;
|
||||
int max_scroll = content_h - (win_h - 40);
|
||||
if (scroll_y > max_scroll) scroll_y = max_scroll;
|
||||
int thumb_y = 40 + (int)(((float)scroll_y / max_scroll) * (sb_h - thumb_h));
|
||||
|
||||
ui_draw_rect(win, sb_x, 40, sb_w, sb_h, 0xFF303030);
|
||||
ui_draw_rounded_rect_filled(win, sb_x+2, thumb_y+2, sb_w-4, thumb_h-4, 4, 0xFF606060);
|
||||
}
|
||||
doc_scrollbar.x = win_w - 12;
|
||||
doc_scrollbar.y = 40;
|
||||
doc_scrollbar.w = 12;
|
||||
doc_scrollbar.h = win_h - 40;
|
||||
doc_scrollbar.on_scroll = word_on_scroll;
|
||||
widget_scrollbar_update(&doc_scrollbar, content_h, scroll_y);
|
||||
widget_scrollbar_draw(&word_ctx, &doc_scrollbar);
|
||||
}
|
||||
|
||||
static void ensure_cursor_visible(ui_window_t win) {
|
||||
@@ -1645,32 +1661,8 @@ static void handle_click(ui_window_t win, int x, int y) {
|
||||
}
|
||||
}
|
||||
content_h = dummy_page * (page_h + 20) + page_h + 20;
|
||||
|
||||
int sb_x = win_w - 12;
|
||||
int sb_w = 12;
|
||||
int sb_h = win_h - 40;
|
||||
int thumb_y = 40;
|
||||
int thumb_h = 0;
|
||||
int max_scroll = 0;
|
||||
if (content_h > win_h - 40) {
|
||||
float ratio = (float)(win_h - 40) / (float)content_h;
|
||||
thumb_h = (int)(sb_h * ratio);
|
||||
if (thumb_h < 20) thumb_h = 20;
|
||||
max_scroll = content_h - (win_h - 40);
|
||||
if (scroll_y > max_scroll) scroll_y = max_scroll;
|
||||
thumb_y = 40 + (int)(((float)scroll_y / max_scroll) * (sb_h - thumb_h));
|
||||
}
|
||||
|
||||
if (content_h > win_h - 40 && x >= sb_x && x < sb_x + sb_w) {
|
||||
if (y >= thumb_y && y < thumb_y + thumb_h) {
|
||||
is_dragging_scrollbar = 1;
|
||||
scrollbar_drag_offset_y = y - thumb_y;
|
||||
} else {
|
||||
if (y < thumb_y) scroll_y -= (win_h - 40);
|
||||
else scroll_y += (win_h - 40);
|
||||
if (scroll_y < 0) scroll_y = 0;
|
||||
if (scroll_y > max_scroll) scroll_y = max_scroll;
|
||||
}
|
||||
widget_scrollbar_update(&doc_scrollbar, content_h, scroll_y);
|
||||
if (widget_scrollbar_handle_mouse(&doc_scrollbar, x, y, true, NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1848,12 +1840,15 @@ int main(int argc, char **argv) {
|
||||
(void)argv;
|
||||
ui_window_t win = ui_window_create("BoredWord", 100, 100, win_w, win_h);
|
||||
if (!win) return 1;
|
||||
word_ctx.user_data = (void*)win;
|
||||
ui_window_set_resizable(win, 1);
|
||||
|
||||
load_fonts();
|
||||
set_active_font(win, 0);
|
||||
init_doc();
|
||||
|
||||
widget_scrollbar_init(&doc_scrollbar, win_w - 12, 40, 12, win_h - 40);
|
||||
|
||||
if (argc > 1) {
|
||||
load_file(win, argv[1]);
|
||||
}
|
||||
@@ -1892,61 +1887,12 @@ int main(int argc, char **argv) {
|
||||
needs_repaint = 1;
|
||||
} else if (ev.type == GUI_EVENT_MOUSE_UP) {
|
||||
is_dragging = 0;
|
||||
is_dragging_scrollbar = 0;
|
||||
widget_scrollbar_handle_mouse(&doc_scrollbar, ev.arg1, ev.arg2, false, NULL);
|
||||
needs_repaint = 1;
|
||||
} else if (ev.type == GUI_EVENT_MOUSE_MOVE) {
|
||||
if (is_dragging_scrollbar) {
|
||||
int pw, ph; get_page_size(&pw, &ph);
|
||||
int doc_view_w = win_w - 40;
|
||||
float scale = (float)doc_view_w / (float)pw; if (scale > 1.0f) scale = 1.0f;
|
||||
int page_w = (int)(pw * scale);
|
||||
int page_h = (int)(ph * scale);
|
||||
|
||||
int content_h = 0;
|
||||
int dummy_y = 10; int dummy_page = 0;
|
||||
for(int p=0; p<para_count; p++) {
|
||||
Paragraph *para = ¶graphs[p]; int start_run = 0; int start_char = 0;
|
||||
while(start_run < para->run_count) {
|
||||
int max_h = 16; int end_run = start_run; int end_char = start_char; int line_w = 0;
|
||||
int r_idx = start_run; int c_idx = start_char; int last_space_run = -1; int last_space_char = -1; int last_space_w = 0;
|
||||
while(r_idx < para->run_count) {
|
||||
TextRun *run = ¶->runs[r_idx]; set_active_font(win, run->font_idx);
|
||||
int fh = ui_get_font_height_scaled(run->font_size); if (fh > max_h) max_h = fh;
|
||||
while(c_idx < run->len) {
|
||||
char buf[2] = {run->text[c_idx], 0}; int cw = ui_get_string_width_scaled(buf, run->font_size);
|
||||
if (run->text[c_idx] == ' ') { last_space_run = r_idx; last_space_char = c_idx; last_space_w = line_w + cw; }
|
||||
if (line_w + cw > page_w - 20) break;
|
||||
line_w += cw; c_idx++;
|
||||
}
|
||||
if (c_idx < run->len) break;
|
||||
r_idx++; c_idx = 0;
|
||||
}
|
||||
if (r_idx < para->run_count || (r_idx == para->run_count - 1 && c_idx < para->runs[r_idx].len)) {
|
||||
if (last_space_run != -1 && (last_space_run > start_run || last_space_char > start_char)) { end_run = last_space_run; end_char = last_space_char; line_w = last_space_w; }
|
||||
else { end_run = r_idx; end_char = c_idx; }
|
||||
} else { end_run = para->run_count; end_char = 0; }
|
||||
int line_h = (int)(max_h * para->spacing) + 4;
|
||||
if (dummy_y + line_h > dummy_page * (page_h + 20) + page_h - 10) { dummy_page++; dummy_y = dummy_page * (page_h + 20) + 10; }
|
||||
dummy_y += line_h; start_run = end_run; start_char = end_char;
|
||||
if (start_run < para->run_count && para->runs[start_run].text[start_char] == ' ') { start_char++; if (start_char >= para->runs[start_run].len) { start_char = 0; start_run++; } }
|
||||
}
|
||||
}
|
||||
content_h = dummy_page * (page_h + 20) + page_h + 20;
|
||||
|
||||
if (content_h > win_h - 40) {
|
||||
int sb_h = win_h - 40;
|
||||
float ratio = (float)(win_h - 40) / (float)content_h;
|
||||
int thumb_h = (int)(sb_h * ratio);
|
||||
if (thumb_h < 20) thumb_h = 20;
|
||||
int max_scroll = content_h - (win_h - 40);
|
||||
|
||||
int new_thumb_y = ev.arg2 - scrollbar_drag_offset_y;
|
||||
if (new_thumb_y < 40) new_thumb_y = 40;
|
||||
if (new_thumb_y > 40 + sb_h - thumb_h) new_thumb_y = 40 + sb_h - thumb_h;
|
||||
|
||||
scroll_y = (int)(((float)(new_thumb_y - 40) / (sb_h - thumb_h)) * max_scroll);
|
||||
needs_repaint = 1;
|
||||
}
|
||||
if (doc_scrollbar.is_dragging) {
|
||||
widget_scrollbar_handle_mouse(&doc_scrollbar, ev.arg1, ev.arg2, true, NULL);
|
||||
needs_repaint = 1;
|
||||
} else if (is_dragging && ev.arg2 >= 40 && active_dialog == 0 && active_dropdown == 0) {
|
||||
handle_click(win, ev.arg1, ev.arg2);
|
||||
needs_repaint = 1;
|
||||
|
||||
@@ -137,6 +137,38 @@ static int scroll_y = 0;
|
||||
static int total_content_height = 0;
|
||||
static int focused_element = -1;
|
||||
|
||||
#include "../../wm/libwidget.h"
|
||||
|
||||
static void browser_draw_rect(void *user_data, int x, int y, int w, int h, uint32_t color) {
|
||||
ui_draw_rect((ui_window_t)user_data, x, y, w, h, color);
|
||||
}
|
||||
static void browser_draw_rounded_rect_filled(void *user_data, int x, int y, int w, int h, int r, uint32_t color) {
|
||||
ui_draw_rounded_rect_filled((ui_window_t)user_data, x, y, w, h, r, color);
|
||||
}
|
||||
static void browser_draw_string(void *user_data, int x, int y, const char *str, uint32_t color) {
|
||||
ui_draw_string((ui_window_t)user_data, x, y, str, color);
|
||||
}
|
||||
static int browser_measure_string_width(void *user_data, const char *str) {
|
||||
(void)user_data;
|
||||
return (int)ui_get_string_width(str);
|
||||
}
|
||||
static void browser_mark_dirty(void *user_data, int x, int y, int w, int h) {
|
||||
ui_mark_dirty((ui_window_t)user_data, x, y, w, h);
|
||||
}
|
||||
|
||||
static widget_context_t browser_ctx = {
|
||||
.draw_rect = browser_draw_rect,
|
||||
.draw_rounded_rect_filled = browser_draw_rounded_rect_filled,
|
||||
.draw_string = browser_draw_string,
|
||||
.measure_string_width = browser_measure_string_width,
|
||||
.mark_dirty = browser_mark_dirty
|
||||
};
|
||||
|
||||
static widget_scrollbar_t browser_scrollbar;
|
||||
static widget_textbox_t url_tb;
|
||||
static widget_button_t btn_back;
|
||||
static widget_button_t btn_home;
|
||||
|
||||
static void parse_html(const char *html);
|
||||
static void parse_html_incremental(const char *html, int safe_len);
|
||||
static void browser_reflow(void);
|
||||
@@ -1506,6 +1538,7 @@ static void parse_html_incremental(const char *html, int safe_len) {
|
||||
}
|
||||
|
||||
static void browser_paint(void) {
|
||||
browser_ctx.user_data = (void *)win_browser;
|
||||
ui_draw_rect(win_browser, 0, 0, win_w, win_h, COLOR_BG);
|
||||
|
||||
for (int i = 0; i < element_count; i++) {
|
||||
@@ -1520,53 +1553,35 @@ static void browser_paint(void) {
|
||||
if (pixels) ui_draw_image(win_browser, el->x, draw_y, el->img_w, el->img_h, pixels);
|
||||
else ui_draw_rect(win_browser, el->x, draw_y, 100, 80, 0xFFCCCCCC);
|
||||
} else if (el->tag == TAG_INPUT) {
|
||||
ui_draw_rect(win_browser, el->x, draw_y, el->w, el->h, 0xFFFFFFFF);
|
||||
uint32_t border = (focused_element == i) ? 0xFF0000FF : 0xFF808080;
|
||||
ui_draw_rect(win_browser, el->x, draw_y, el->w, 1, border);
|
||||
ui_draw_rect(win_browser, el->x, draw_y + el->h - 1, el->w, 1, border);
|
||||
ui_draw_rect(win_browser, el->x, draw_y, 1, el->h, border);
|
||||
ui_draw_rect(win_browser, el->x + el->w - 1, draw_y, 1, el->h, border);
|
||||
|
||||
char visible[64];
|
||||
char visible[128];
|
||||
int v_len = 0;
|
||||
int max_v = (el->w - 10) / 8;
|
||||
if (max_v > 63) max_v = 63;
|
||||
if (max_v > 127) max_v = 127;
|
||||
for (int k = el->input_scroll; el->attr_value[k] && v_len < max_v; k++) {
|
||||
visible[v_len++] = el->attr_value[k];
|
||||
}
|
||||
visible[v_len] = 0;
|
||||
ui_draw_string(win_browser, el->x + 5, draw_y + 2, visible, (focused_element == i) ? 0xFF000000 : 0xFF808080);
|
||||
|
||||
if (focused_element == i) {
|
||||
int cursor_pos = el->input_cursor - el->input_scroll;
|
||||
if (cursor_pos >= 0 && cursor_pos < max_v) {
|
||||
char sub[64];
|
||||
int k;
|
||||
for (k = 0; k < cursor_pos && visible[k]; k++) sub[k] = visible[k];
|
||||
sub[k] = 0;
|
||||
int cx = ui_get_string_width(sub);
|
||||
ui_draw_rect(win_browser, el->x + 5 + cx, draw_y + 16, 8, 2, 0xFF000000);
|
||||
}
|
||||
}
|
||||
|
||||
widget_textbox_t tb;
|
||||
widget_textbox_init(&tb, el->x, draw_y, el->w, el->h, visible, max_v);
|
||||
tb.cursor_pos = el->input_cursor - el->input_scroll;
|
||||
if (tb.cursor_pos < 0) tb.cursor_pos = 0;
|
||||
tb.focused = (focused_element == i);
|
||||
widget_textbox_draw(&browser_ctx, &tb);
|
||||
} else if (el->tag == TAG_BUTTON) {
|
||||
ui_draw_rect(win_browser, el->x, draw_y, el->w, el->h, 0xFFDDDDDD);
|
||||
ui_draw_rect(win_browser, el->x, draw_y, el->w, 1, 0xFFFFFFFF);
|
||||
ui_draw_rect(win_browser, el->x, draw_y + el->h - 1, el->w, 1, 0xFF888888);
|
||||
ui_draw_rect(win_browser, el->x, draw_y, 1, el->h, 0xFFFFFFFF);
|
||||
ui_draw_rect(win_browser, el->x + el->w - 1, draw_y, 1, el->h, 0xFF888888);
|
||||
ui_draw_string(win_browser, el->x + 10, draw_y + 4, el->attr_value, 0xFF000000);
|
||||
widget_button_t btn;
|
||||
widget_button_init(&btn, el->x, draw_y, el->w, el->h, el->attr_value);
|
||||
widget_button_draw(&browser_ctx, &btn);
|
||||
} else if (el->tag == TAG_RADIO) {
|
||||
ui_draw_rounded_rect_filled(win_browser, el->x, draw_y, el->w, el->h, el->w/2, 0xFF808080);
|
||||
ui_draw_rounded_rect_filled(win_browser, el->x + 1, draw_y + 1, el->w - 2, el->h - 2, (el->w-2)/2, 0xFFFFFFFF);
|
||||
if (el->checked) {
|
||||
ui_draw_rounded_rect_filled(win_browser, el->x + 4, draw_y + 4, el->w - 8, el->h - 8, (el->w-8)/2, 0xFF000000);
|
||||
}
|
||||
widget_checkbox_t cb;
|
||||
widget_checkbox_init(&cb, el->x, draw_y, el->w, el->h, "", true);
|
||||
cb.checked = el->checked;
|
||||
widget_checkbox_draw(&browser_ctx, &cb);
|
||||
} else if (el->tag == TAG_CHECKBOX) {
|
||||
ui_draw_rect(win_browser, el->x, draw_y, el->w, el->h, 0xFF808080);
|
||||
ui_draw_rect(win_browser, el->x + 1, draw_y + 1, el->w - 2, el->h - 2, 0xFFFFFFFF);
|
||||
if (el->checked) {
|
||||
ui_draw_rect(win_browser, el->x + 4, draw_y + 4, el->w - 8, el->h - 8, 0xFF000000);
|
||||
}
|
||||
widget_checkbox_t cb;
|
||||
widget_checkbox_init(&cb, el->x, draw_y, el->w, el->h, "", false);
|
||||
cb.checked = el->checked;
|
||||
widget_checkbox_draw(&browser_ctx, &cb);
|
||||
} else if (el->tag == TAG_HR) {
|
||||
ui_draw_rect(win_browser, el->x, draw_y + el->h / 2, el->w, 2, 0xFF888888);
|
||||
ui_draw_rect(win_browser, el->x, draw_y + (el->h / 2) + 2, el->w, 1, 0xFFFFFFFF);
|
||||
@@ -1588,40 +1603,26 @@ static void browser_paint(void) {
|
||||
}
|
||||
|
||||
ui_draw_rect(win_browser, 0, 0, win_w, URL_BAR_H, COLOR_URL_BAR);
|
||||
ui_draw_string(win_browser, 10, 8, url_input_buffer, COLOR_URL_TEXT);
|
||||
if (focused_element == -1) {
|
||||
char sub[512];
|
||||
int k;
|
||||
for (k = 0; k < url_cursor && url_input_buffer[k]; k++) sub[k] = url_input_buffer[k];
|
||||
sub[k] = 0;
|
||||
int cx = ui_get_string_width(sub);
|
||||
ui_draw_rect(win_browser, 10 + cx, 22, 8, 2, COLOR_URL_TEXT);
|
||||
}
|
||||
|
||||
widget_textbox_init(&url_tb, 10, 5, win_w - SCROLL_BAR_W - BTN_W*2 - BTN_PAD*2 - 20, 20, url_input_buffer, 511);
|
||||
url_tb.cursor_pos = url_cursor;
|
||||
url_tb.focused = (focused_element == -1);
|
||||
widget_textbox_draw(&browser_ctx, &url_tb);
|
||||
|
||||
// Back button
|
||||
int btn_y = (URL_BAR_H - BTN_H) / 2;
|
||||
uint32_t back_col = history_count > 0 ? 0xFF505050 : 0xFF404040;
|
||||
ui_draw_rect(win_browser, BACK_BTN_X, btn_y, BTN_W, BTN_H, back_col);
|
||||
ui_draw_rect(win_browser, BACK_BTN_X, btn_y, BTN_W, 1, 0xFF606060);
|
||||
ui_draw_rect(win_browser, BACK_BTN_X, btn_y, 1, BTN_H, 0xFF606060);
|
||||
ui_draw_rect(win_browser, BACK_BTN_X, btn_y + BTN_H - 1, BTN_W, 1, 0xFF202020);
|
||||
ui_draw_rect(win_browser, BACK_BTN_X + BTN_W - 1, btn_y, 1, BTN_H, 0xFF202020);
|
||||
ui_draw_string(win_browser, BACK_BTN_X + 10, btn_y + 4, "<", history_count > 0 ? 0xFFFFFFFF : 0xFF808080);
|
||||
widget_button_init(&btn_back, BACK_BTN_X, btn_y, BTN_W, BTN_H, "<");
|
||||
widget_button_draw(&browser_ctx, &btn_back);
|
||||
|
||||
// Home button
|
||||
ui_draw_rect(win_browser, HOME_BTN_X, btn_y, BTN_W, BTN_H, 0xFF505050);
|
||||
ui_draw_rect(win_browser, HOME_BTN_X, btn_y, BTN_W, 1, 0xFF606060);
|
||||
ui_draw_rect(win_browser, HOME_BTN_X, btn_y, 1, BTN_H, 0xFF606060);
|
||||
ui_draw_rect(win_browser, HOME_BTN_X, btn_y + BTN_H - 1, BTN_W, 1, 0xFF202020);
|
||||
ui_draw_rect(win_browser, HOME_BTN_X + BTN_W - 1, btn_y, 1, BTN_H, 0xFF202020);
|
||||
ui_draw_string(win_browser, HOME_BTN_X + 10, btn_y + 4, "H", 0xFFFFFFFF);
|
||||
widget_button_init(&btn_home, HOME_BTN_X, btn_y, BTN_W, BTN_H, "H");
|
||||
widget_button_draw(&browser_ctx, &btn_home);
|
||||
|
||||
// Scroll bar
|
||||
ui_draw_rect(win_browser, win_w - SCROLL_BAR_W, URL_BAR_H, SCROLL_BAR_W, win_h - URL_BAR_H, COLOR_SCROLL_BG);
|
||||
int thumb_h = (win_h - URL_BAR_H) * (win_h - URL_BAR_H) / (total_content_height > win_h ? total_content_height : win_h);
|
||||
if (thumb_h < 20) thumb_h = 20;
|
||||
int thumb_y = URL_BAR_H + (scroll_y * (win_h - URL_BAR_H - thumb_h)) / (total_content_height > win_h - URL_BAR_H ? total_content_height - (win_h - URL_BAR_H) : 1);
|
||||
ui_draw_rect(win_browser, win_w - SCROLL_BAR_W + 2, thumb_y, SCROLL_BAR_W - 4, thumb_h, COLOR_SCROLL_BTN);
|
||||
int viewport_h = win_h - URL_BAR_H;
|
||||
widget_scrollbar_init(&browser_scrollbar, win_w - SCROLL_BAR_W, URL_BAR_H, SCROLL_BAR_W, viewport_h);
|
||||
widget_scrollbar_update(&browser_scrollbar, total_content_height, scroll_y);
|
||||
widget_scrollbar_draw(&browser_ctx, &browser_scrollbar);
|
||||
}
|
||||
|
||||
static void navigate(const char *url) {
|
||||
@@ -1670,34 +1671,52 @@ int main(int argc, char **argv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
else if (ev.type == GUI_EVENT_CLICK) {
|
||||
else if (ev.type == GUI_EVENT_CLICK || ev.type == GUI_EVENT_MOUSE_DOWN || ev.type == GUI_EVENT_MOUSE_UP || ev.type == GUI_EVENT_MOUSE_MOVE) {
|
||||
int mx = ev.arg1;
|
||||
if (mx >= win_w - SCROLL_BAR_W) {
|
||||
if (ev.arg2 < URL_BAR_H + (win_h - URL_BAR_H)/2) scroll_y -= 100;
|
||||
else scroll_y += 100;
|
||||
if (scroll_y < 0) scroll_y = 0;
|
||||
needs_repaint = true;
|
||||
int my = ev.arg2;
|
||||
bool is_down = (ev.type == GUI_EVENT_MOUSE_DOWN || (ev.type == GUI_EVENT_MOUSE_MOVE && browser_scrollbar.is_dragging));
|
||||
bool is_click = (ev.type == GUI_EVENT_CLICK);
|
||||
|
||||
if (widget_scrollbar_handle_mouse(&browser_scrollbar, mx, my, is_down, &browser_ctx)) {
|
||||
if (scroll_y != browser_scrollbar.scroll_y) {
|
||||
scroll_y = browser_scrollbar.scroll_y;
|
||||
needs_repaint = true;
|
||||
}
|
||||
if (ev.type == GUI_EVENT_MOUSE_MOVE) continue;
|
||||
if (is_down || is_click) continue;
|
||||
}
|
||||
|
||||
if (ev.type != GUI_EVENT_CLICK && ev.type != GUI_EVENT_MOUSE_DOWN) continue;
|
||||
|
||||
if (my < URL_BAR_H) {
|
||||
if (widget_textbox_handle_mouse(&url_tb, mx, my, is_click, NULL)) {
|
||||
focused_element = -1;
|
||||
needs_repaint = true;
|
||||
continue;
|
||||
}
|
||||
if (widget_button_handle_mouse(&btn_back, mx, my, is_down, is_click, NULL)) {
|
||||
if (is_click && history_count > 0) {
|
||||
history_count--;
|
||||
int j=0; while(history_stack[history_count][j]) { url_input_buffer[j] = history_stack[history_count][j]; j++; } url_input_buffer[j] = 0; url_cursor = j;
|
||||
navigate(url_input_buffer); scroll_y = 0; focused_element = -1;
|
||||
}
|
||||
needs_repaint = true; continue;
|
||||
}
|
||||
if (widget_button_handle_mouse(&btn_home, mx, my, is_down, is_click, NULL)) {
|
||||
if (is_click) {
|
||||
if (history_count < HISTORY_MAX) { int j=0; while(url_input_buffer[j]) { history_stack[history_count][j] = url_input_buffer[j]; j++; } history_stack[history_count][j] = 0; history_count++; }
|
||||
const char *home = "http://find.boreddev.nl";
|
||||
int j=0; while(home[j]) { url_input_buffer[j] = home[j]; j++; } url_input_buffer[j] = 0; url_cursor = j;
|
||||
navigate(url_input_buffer); scroll_y = 0; focused_element = -1;
|
||||
}
|
||||
needs_repaint = true; continue;
|
||||
}
|
||||
if (is_click) {
|
||||
focused_element = -1; needs_repaint = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (ev.arg2 < URL_BAR_H) {
|
||||
// Check back button
|
||||
if (mx >= BACK_BTN_X && mx < BACK_BTN_X + BTN_W && history_count > 0) {
|
||||
history_count--;
|
||||
int j=0; while(history_stack[history_count][j]) { url_input_buffer[j] = history_stack[history_count][j]; j++; } url_input_buffer[j] = 0; url_cursor = j;
|
||||
navigate(url_input_buffer); scroll_y = 0; focused_element = -1;
|
||||
needs_repaint = true; continue;
|
||||
}
|
||||
// Check home button
|
||||
if (mx >= HOME_BTN_X && mx < HOME_BTN_X + BTN_W) {
|
||||
if (history_count < HISTORY_MAX) { int j=0; while(url_input_buffer[j]) { history_stack[history_count][j] = url_input_buffer[j]; j++; } history_stack[history_count][j] = 0; history_count++; }
|
||||
const char *home = "http://find.boreddev.nl";
|
||||
int j=0; while(home[j]) { url_input_buffer[j] = home[j]; j++; } url_input_buffer[j] = 0; url_cursor = j;
|
||||
navigate(url_input_buffer); scroll_y = 0; focused_element = -1;
|
||||
needs_repaint = true; continue;
|
||||
}
|
||||
focused_element = -1; needs_repaint = true; continue;
|
||||
}
|
||||
int my = ev.arg2 - URL_BAR_H + scroll_y;
|
||||
my = ev.arg2 - URL_BAR_H + scroll_y;
|
||||
bool found = false;
|
||||
for (int i = 0; i < element_count; i++) {
|
||||
RenderElement *el = &elements[i];
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||
#include "syscall.h"
|
||||
#include "libui.h"
|
||||
#include "../../wm/libwidget.h"
|
||||
#include <stdbool.h>
|
||||
#include "stdlib.h"
|
||||
|
||||
@@ -25,6 +26,33 @@ static long long calc_decimal_divisor = 10;
|
||||
static char display_buffer[1024];
|
||||
static int display_buf_len = 0;
|
||||
|
||||
static widget_button_t buttons[20];
|
||||
static const char *labels[] = {
|
||||
"C", "sqr", "rt", "/",
|
||||
"7", "8", "9", "*",
|
||||
"4", "5", "6", "-",
|
||||
"1", "2", "3", "+",
|
||||
"0", ".", "BS", "="
|
||||
};
|
||||
|
||||
static void calc_draw_rect(void *user_data, int x, int y, int w, int h, uint32_t color) {
|
||||
ui_draw_rect((ui_window_t)user_data, x, y, w, h, color);
|
||||
}
|
||||
static void calc_draw_rounded_rect_filled(void *user_data, int x, int y, int w, int h, int r, uint32_t color) {
|
||||
ui_draw_rounded_rect_filled((ui_window_t)user_data, x, y, w, h, r, color);
|
||||
}
|
||||
static void calc_draw_string(void *user_data, int x, int y, const char *str, uint32_t color) {
|
||||
ui_draw_string((ui_window_t)user_data, x, y, str, color);
|
||||
}
|
||||
|
||||
static widget_context_t calc_ctx = {
|
||||
.user_data = 0,
|
||||
.draw_rect = calc_draw_rect,
|
||||
.draw_rounded_rect_filled = calc_draw_rounded_rect_filled,
|
||||
.draw_string = calc_draw_string,
|
||||
.mark_dirty = NULL
|
||||
};
|
||||
|
||||
static long long isqrt(long long n) {
|
||||
if (n < 0) return -1;
|
||||
if (n == 0) return 0;
|
||||
@@ -97,27 +125,8 @@ static void calculator_paint(void) {
|
||||
int text_x = w - 15 - text_w;
|
||||
ui_draw_string(win_calculator, text_x, 18, display_buffer, COLOR_DARK_TEXT);
|
||||
|
||||
const char *labels[] = {
|
||||
"C", "sqr", "rt", "/",
|
||||
"7", "8", "9", "*",
|
||||
"4", "5", "6", "-",
|
||||
"1", "2", "3", "+",
|
||||
"0", ".", "BS", "="
|
||||
};
|
||||
|
||||
int bw = 35;
|
||||
int bh = 25;
|
||||
int gap = 5;
|
||||
int start_x = 10;
|
||||
int start_y = 40;
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
int r = i / 4;
|
||||
int c = i % 4;
|
||||
ui_draw_rounded_rect_filled(win_calculator, start_x + c*(bw+gap), start_y + r*(bh+gap), bw, bh, 4, COLOR_DARK_BORDER);
|
||||
int label_x = start_x + c*(bw+gap) + 5;
|
||||
int label_y = start_y + r*(bh+gap) + 9;
|
||||
ui_draw_string(win_calculator, label_x, label_y, labels[i], COLOR_DARK_TEXT);
|
||||
widget_button_draw(&calc_ctx, &buttons[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,105 +144,93 @@ static void do_op(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static void calculator_click(int x, int y) {
|
||||
int bw = 35;
|
||||
int bh = 25;
|
||||
int gap = 5;
|
||||
int start_x = 10;
|
||||
int start_y = 35; // Matches the hitboxes
|
||||
static void handle_button_click(int idx) {
|
||||
const char *labels_map[] = {
|
||||
"C", "s", "r", "/",
|
||||
"7", "8", "9", "*",
|
||||
"4", "5", "6", "-",
|
||||
"1", "2", "3", "+",
|
||||
"0", ".", "B", "="
|
||||
};
|
||||
char lbl = labels_map[idx][0];
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
int r = i / 4;
|
||||
int c = i % 4;
|
||||
int bx = start_x + c*(bw+gap);
|
||||
int by = start_y + r*(bh+gap);
|
||||
|
||||
if (x >= bx && x < bx + bw && y >= by && y < by + bh) {
|
||||
const char *labels[] = {
|
||||
"C", "s", "r", "/",
|
||||
"7", "8", "9", "*",
|
||||
"4", "5", "6", "-",
|
||||
"1", "2", "3", "+",
|
||||
"0", ".", "B", "="
|
||||
};
|
||||
char lbl = labels[i][0];
|
||||
|
||||
if (lbl >= '0' && lbl <= '9') {
|
||||
if (calc_new_entry || calc_error) {
|
||||
calc_curr = (lbl - '0') * SCALE;
|
||||
calc_new_entry = false;
|
||||
calc_decimal_mode = false;
|
||||
} else {
|
||||
if (calc_decimal_mode) {
|
||||
if (calc_decimal_divisor <= SCALE) {
|
||||
long long digit_val = ((long long)(lbl - '0') * SCALE) / calc_decimal_divisor;
|
||||
if (calc_curr >= 0) calc_curr += digit_val;
|
||||
else calc_curr -= digit_val;
|
||||
calc_decimal_divisor *= 10;
|
||||
}
|
||||
} else {
|
||||
if (calc_curr >= 0) calc_curr = calc_curr * 10 + (lbl - '0') * SCALE;
|
||||
else calc_curr = calc_curr * 10 - (lbl - '0') * SCALE;
|
||||
}
|
||||
}
|
||||
calc_error = false;
|
||||
} else if (lbl == '.') {
|
||||
if (calc_new_entry) {
|
||||
calc_curr = 0;
|
||||
calc_new_entry = false;
|
||||
}
|
||||
if (!calc_decimal_mode) {
|
||||
calc_decimal_mode = true;
|
||||
calc_decimal_divisor = 10;
|
||||
}
|
||||
} else if (lbl == 'C') {
|
||||
calc_curr = 0; calc_acc = 0; calc_op = 0;
|
||||
calc_new_entry = true; calc_error = false; calc_decimal_mode = false;
|
||||
} else if (lbl == 'B') {
|
||||
if (!calc_new_entry && !calc_error) {
|
||||
if (calc_decimal_mode) {
|
||||
if (calc_decimal_divisor > 10) {
|
||||
calc_decimal_divisor /= 10;
|
||||
long long unit = SCALE / calc_decimal_divisor;
|
||||
calc_curr = (calc_curr / (unit * 10)) * (unit * 10);
|
||||
} else {
|
||||
calc_decimal_mode = false;
|
||||
calc_decimal_divisor = 10;
|
||||
calc_curr = (calc_curr / SCALE) * SCALE;
|
||||
}
|
||||
} else {
|
||||
calc_curr = (calc_curr / SCALE / 10) * SCALE;
|
||||
}
|
||||
}
|
||||
} else if (lbl == 's') { // sqr
|
||||
calc_curr = (calc_curr * calc_curr) / SCALE; calc_new_entry = true;
|
||||
} else if (lbl == 'r') { // rt
|
||||
long long s = isqrt(calc_curr);
|
||||
if (s == -1) calc_error = true;
|
||||
else calc_curr = s * 1000;
|
||||
calc_new_entry = true;
|
||||
} else if (lbl == '=') {
|
||||
do_op();
|
||||
calc_curr = calc_acc; calc_op = 0; calc_new_entry = true; calc_decimal_mode = false;
|
||||
if (lbl >= '0' && lbl <= '9') {
|
||||
if (calc_new_entry || calc_error) {
|
||||
calc_curr = (lbl - '0') * SCALE;
|
||||
calc_new_entry = false;
|
||||
calc_decimal_mode = false;
|
||||
} else {
|
||||
if (calc_decimal_mode) {
|
||||
if (calc_decimal_divisor <= SCALE) {
|
||||
long long digit_val = ((long long)(lbl - '0') * SCALE) / calc_decimal_divisor;
|
||||
if (calc_curr >= 0) calc_curr += digit_val;
|
||||
else calc_curr -= digit_val;
|
||||
calc_decimal_divisor *= 10;
|
||||
}
|
||||
} else {
|
||||
if (!calc_new_entry) {
|
||||
if (calc_op) do_op();
|
||||
else calc_acc = calc_curr;
|
||||
}
|
||||
calc_op = lbl; calc_new_entry = true; calc_decimal_mode = false;
|
||||
if (calc_curr >= 0) calc_curr = calc_curr * 10 + (lbl - '0') * SCALE;
|
||||
else calc_curr = calc_curr * 10 - (lbl - '0') * SCALE;
|
||||
}
|
||||
|
||||
update_display();
|
||||
calculator_paint();
|
||||
ui_mark_dirty(win_calculator, 0, 0, 180, 230);
|
||||
return;
|
||||
}
|
||||
calc_error = false;
|
||||
} else if (lbl == '.') {
|
||||
if (calc_new_entry) {
|
||||
calc_curr = 0;
|
||||
calc_new_entry = false;
|
||||
}
|
||||
if (!calc_decimal_mode) {
|
||||
calc_decimal_mode = true;
|
||||
calc_decimal_divisor = 10;
|
||||
}
|
||||
} else if (lbl == 'C') {
|
||||
calc_curr = 0; calc_acc = 0; calc_op = 0;
|
||||
calc_new_entry = true; calc_error = false; calc_decimal_mode = false;
|
||||
} else if (lbl == 'B') {
|
||||
if (!calc_new_entry && !calc_error) {
|
||||
if (calc_decimal_mode) {
|
||||
if (calc_decimal_divisor > 10) {
|
||||
calc_decimal_divisor /= 10;
|
||||
long long unit = SCALE / calc_decimal_divisor;
|
||||
calc_curr = (calc_curr / (unit * 10)) * (unit * 10);
|
||||
} else {
|
||||
calc_decimal_mode = false;
|
||||
calc_decimal_divisor = 10;
|
||||
calc_curr = (calc_curr / SCALE) * SCALE;
|
||||
}
|
||||
} else {
|
||||
calc_curr = (calc_curr / SCALE / 10) * SCALE;
|
||||
}
|
||||
}
|
||||
} else if (lbl == 's') { // sqr
|
||||
calc_curr = (calc_curr * calc_curr) / SCALE; calc_new_entry = true;
|
||||
} else if (lbl == 'r') { // rt
|
||||
long long s = isqrt(calc_curr);
|
||||
if (s == -1) calc_error = true;
|
||||
else calc_curr = s * 1000;
|
||||
calc_new_entry = true;
|
||||
} else if (lbl == '=') {
|
||||
do_op();
|
||||
calc_curr = calc_acc; calc_op = 0; calc_new_entry = true; calc_decimal_mode = false;
|
||||
} else {
|
||||
if (!calc_new_entry) {
|
||||
if (calc_op) do_op();
|
||||
else calc_acc = calc_curr;
|
||||
}
|
||||
calc_op = lbl; calc_new_entry = true; calc_decimal_mode = false;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
win_calculator = ui_window_create("Calculator", 200, 200, 180, 230);
|
||||
calc_ctx.user_data = (void *)win_calculator;
|
||||
|
||||
int bw = 35, bh = 25, gap = 5, start_x = 10, start_y = 40;
|
||||
for (int i = 0; i < 20; i++) {
|
||||
int r = i / 4;
|
||||
int c = i % 4;
|
||||
widget_button_init(&buttons[i], start_x + c*(bw+gap), start_y + r*(bh+gap), bw, bh, labels[i]);
|
||||
}
|
||||
|
||||
calc_curr = 0;
|
||||
calc_acc = 0;
|
||||
calc_op = 0;
|
||||
@@ -249,8 +246,21 @@ int main(void) {
|
||||
if (ev.type == GUI_EVENT_PAINT) {
|
||||
calculator_paint();
|
||||
ui_mark_dirty(win_calculator, 0, 0, 180, 230);
|
||||
} else if (ev.type == GUI_EVENT_CLICK) {
|
||||
calculator_click(ev.arg1, ev.arg2);
|
||||
} else if (ev.type == GUI_EVENT_CLICK || ev.type == GUI_EVENT_MOUSE_DOWN || ev.type == GUI_EVENT_MOUSE_UP) {
|
||||
bool needs_paint = false;
|
||||
for (int i=0; i<20; i++) {
|
||||
if (widget_button_handle_mouse(&buttons[i], ev.arg1, ev.arg2, ev.type == GUI_EVENT_MOUSE_DOWN, ev.type == GUI_EVENT_CLICK, NULL)) {
|
||||
needs_paint = true;
|
||||
if (ev.type == GUI_EVENT_CLICK) {
|
||||
handle_button_click(i);
|
||||
update_display();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (needs_paint) {
|
||||
calculator_paint();
|
||||
ui_mark_dirty(win_calculator, 0, 0, 180, 230);
|
||||
}
|
||||
} else if (ev.type == GUI_EVENT_CLOSE) {
|
||||
sys_exit(0);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user