diff --git a/applications/fetcher/OS.okm b/applications/fetcher/OS.okm index 4465b7e..acf683a 100644 --- a/applications/fetcher/OS.okm +++ b/applications/fetcher/OS.okm @@ -1,7 +1,7 @@ (* FIXME: this module should probably be moved somewhere global so all applications can use it *) MODULE OS; - CONST WINDOW_STRUCT_SIZE = 36; + CONST WINDOW_STRUCT_SIZE = 40; CONST FILE_STRUCT_SIZE = 32; EXTERN PROCEDURE new_window, destroy_window, draw_str_to_overlay, get_window_overlay_number, diff --git a/applications/foxpaint/main.asm b/applications/foxpaint/main.asm index 0ebea12..520e660 100644 --- a/applications/foxpaint/main.asm +++ b/applications/foxpaint/main.asm @@ -367,10 +367,10 @@ drag_or_close_tools_window: ret canvas_window_title: data.strz "FoxPaint canvas" -canvas_window_struct: data.fill 0, 36 +canvas_window_struct: data.fill 0, 40 tools_window_title: data.strz "FoxPaint tools" -tools_window_struct: data.fill 0, 36 +tools_window_struct: data.fill 0, 40 color_section_text: data.strz "Color " color_button_black_widget: diff --git a/applications/launcher/main.asm b/applications/launcher/main.asm index 9341301..2ed98b1 100644 --- a/applications/launcher/main.asm +++ b/applications/launcher/main.asm @@ -91,7 +91,7 @@ close_window: call end_current_task window_title: data.strz "Launcher" -window_struct: data.fill 0, 36 +window_struct: data.fill 0, 40 terminal_button_fxf: data.strz "terminal.fxf" terminal_button_widget: diff --git a/applications/okmpaint/OkmPaint.okm b/applications/okmpaint/OkmPaint.okm index 9db8cab..eba2f84 100644 --- a/applications/okmpaint/OkmPaint.okm +++ b/applications/okmpaint/OkmPaint.okm @@ -23,7 +23,7 @@ MODULE OkmPaint; drawing: CHAR; size: CHAR; color: INT; - canvasWindow: ARRAY 36 OF CHAR; + canvasWindow: ARRAY 40 OF CHAR; PROCEDURE Main(); BEGIN diff --git a/applications/terminal/main.asm b/applications/terminal/main.asm index c19e983..5f169fa 100644 --- a/applications/terminal/main.asm +++ b/applications/terminal/main.asm @@ -117,7 +117,7 @@ sh_fxf_missing_yield_loop: rjmp sh_fxf_missing_yield_loop window_title: data.strz "Terminal" -window_struct: data.fill 0, 36 +window_struct: data.fill 0, 40 sh_fxf_name: data.strz "sh.fxf" sh_fxf_missing_str: data.str "sh could not be launched! hanging here" data.8 10 data.8 0 diff --git a/fox32os.def b/fox32os.def index 340052d..e612a71 100644 --- a/fox32os.def +++ b/fox32os.def @@ -55,15 +55,19 @@ copy: jmp [0x00000D30] ; widget jump table draw_widgets_to_window: jmp [0x00000E10] handle_widget_click: jmp [0x00000E14] +handle_widget_key_down: jmp [0x00000E18] +handle_widget_key_up: jmp [0x00000E1C] ; resource jump table get_resource: jmp [0x00000F10] ; event types -const EVENT_TYPE_BUTTON_CLICK: 0x80000000 +const EVENT_TYPE_BUTTON_CLICK: 0x80000000 +const EVENT_TYPE_TEXTBOX_REFRESH: 0x80000001 ; widget types -const WIDGET_TYPE_BUTTON: 0x00000000 +const WIDGET_TYPE_BUTTON: 0x00000000 +const WIDGET_TYPE_TEXTBOX_SL: 0x00000001 ; window flags const WINDOW_FLAG_ALWAYS_BACKGROUND: 1 diff --git a/kernel/main.asm b/kernel/main.asm index e168f40..4ce9471 100644 --- a/kernel/main.asm +++ b/kernel/main.asm @@ -81,6 +81,8 @@ jump_table: org.pad 0x00000610 data.32 draw_widgets_to_window data.32 handle_widget_click + data.32 handle_widget_key_down + data.32 handle_widget_key_up ; resource jump table org.pad 0x00000710 diff --git a/kernel/widget/textbox_sl.asm b/kernel/widget/textbox_sl.asm new file mode 100644 index 0000000..be4a9ab --- /dev/null +++ b/kernel/widget/textbox_sl.asm @@ -0,0 +1,87 @@ +; textbox_sl widget routines + +; textbox_sl widget struct: +; data.32 next_ptr - pointer to next widget, or 0 for none +; data.32 id - the ID number of this widget +; data.32 type - the type of this widget +; data.32 buffer_ptr - pointer to null-terminated input string +; data.32 foreground_color - text foreground color +; data.32 background_color - textbox_sl background color +; data.16 width - width of this textbox_sl +; data.16 buffer_max - maximum input length including null-terminator +; data.16 x_pos - X coordinate of this widget +; data.16 y_pos - Y coordinate of this widget + +const TEXTBOX_SL_WIDGET_STRUCT_SIZE: 32 ; 8 words = 32 bytes +const TEXTBOX_SL_HEIGHT: 20 + +; draw a textbox_sl widget to a window +; inputs: +; r0: pointer to window struct +; r1: pointer to a null-terminated input string +; r2: foreground color +; r3: background color +; r4: textbox_sl width +; r5: X coordinate +; r6: Y coordinate +; r7: non-zero if textbox is active +draw_textbox_sl_widget: + push r0 + push r1 + push r2 + push r3 + push r4 + push r5 + push r10 + + call get_window_overlay_number + mov r10, r0 + + push r1 + push r2 + push r3 + push r4 + push r5 + mov r0, r5 + mov r1, r6 + mov r2, r4 + mov r4, r3 + push r4 + cmp r7, 0 + ifz jmp draw_textbox_sl_widget_not_active + not r4 + or r4, 0xFF000000 +draw_textbox_sl_widget_not_active: + mov r3, TEXTBOX_SL_HEIGHT + mov r5, r10 + call draw_filled_rectangle_to_overlay + sub r2, 4 + sub r3, 4 + add r0, 2 + add r1, 2 + pop r4 + call draw_filled_rectangle_to_overlay + pop r5 + pop r4 + pop r3 + pop r2 + pop r1 + + mov r4, r3 + mov r3, r2 + mov r0, r1 + mov r1, r5 + add r1, 2 + mov r2, r6 + add r2, 2 + mov r5, r10 + call draw_str_to_overlay + + pop r10 + pop r5 + pop r4 + pop r3 + pop r2 + pop r1 + pop r0 + ret diff --git a/kernel/widget/widget.asm b/kernel/widget/widget.asm index 7f0aedc..3f55069 100644 --- a/kernel/widget/widget.asm +++ b/kernel/widget/widget.asm @@ -1,7 +1,8 @@ ; widget management routines ; widget types -const WIDGET_TYPE_BUTTON: 0x00000000 +const WIDGET_TYPE_BUTTON: 0x00000000 +const WIDGET_TYPE_TEXTBOX_SL: 0x00000001 ; widget struct: ; data.32 next_ptr - pointer to next widget, or 0 for none @@ -18,14 +19,14 @@ draw_widgets_to_window: push r10 ; get pointer to first widget - mov r10, r0 - add r10, 32 - mov r10, [r10] + mov r10, [r0+32] draw_widgets_to_window_next: ; check widget type add r10, 8 cmp [r10], WIDGET_TYPE_BUTTON ifz call draw_widgets_to_window_button + cmp [r10], WIDGET_TYPE_TEXTBOX_SL + ifz call draw_widgets_to_window_textbox_sl ; point to the next widget, if any sub r10, 8 @@ -44,25 +45,49 @@ draw_widgets_to_window_button: push r5 push r6 push r7 - push r10 ; put button parameters in registers for the drawing routine - add r10, 4 - mov r1, [r10] ; text_ptr - add r10, 4 - mov r2, [r10] ; foreground_color - add r10, 4 - mov r3, [r10] ; background_color - add r10, 4 - movz.16 r4, [r10] ; width - add r10, 2 - movz.16 r7, [r10] ; height - add r10, 2 - movz.16 r5, [r10] ; x_pos - add r10, 2 - movz.16 r6, [r10] ; y_pos + mov r1, [r10+4] ; text_ptr + mov r2, [r10+8] ; foreground_color + mov r3, [r10+12] ; background_color + movz.16 r4, [r10+16] ; width + movz.16 r7, [r10+18] ; height + movz.16 r5, [r10+20] ; x_pos + movz.16 r6, [r10+22] ; y_pos call draw_button_widget + pop r7 + pop r6 + pop r5 + pop r4 + pop r3 + pop r2 + pop r1 + ret +draw_widgets_to_window_textbox_sl: + push r1 + push r2 + push r3 + push r4 + push r5 + push r6 + push r7 + push r10 + + ; put textbox_sl parameters in registers for the drawing routine + mov r1, [r10+4] ; buffer_ptr + mov r2, [r10+8] ; foreground_color + mov r3, [r10+12] ; background_color + movz.16 r4, [r10+16] ; width + movz.16 r5, [r10+20] ; x_pos + movz.16 r6, [r10+22] ; y_pos + mov r7, [r0+36] ; check active widget ID + sub r10, 4 + cmp [r10], [r7+4] + ifz mov r7, 1 + ifnz mov r7, 0 + call draw_textbox_sl_widget + pop r10 pop r7 pop r6 @@ -95,14 +120,21 @@ handle_widget_click: mov r30, r0 ; get pointer to first widget - add r0, 32 - mov r0, [r0] + mov r0, [r0+32] + push r0 handle_widget_click_check_type: - ; check widget type + add rsp, 4 + push r0 + add r0, 8 + ; check widget type cmp [r0], WIDGET_TYPE_BUTTON ifz jmp handle_widget_click_button + cmp [r0], WIDGET_TYPE_TEXTBOX_SL + ifz jmp handle_widget_click_textbox_sl handle_widget_click_done: + pop r0 + pop r30 pop r8 pop r7 @@ -182,6 +214,10 @@ handle_widget_click_button: mov r0, EVENT_TYPE_BUTTON_CLICK call new_window_event + ; set active widget pointer + mov r0, [rsp] + mov [r30+36], r0 + jmp handle_widget_click_done handle_widget_click_button_no_click: pop r22 @@ -202,6 +238,243 @@ handle_widget_click_button_no_click: ; retry jmp handle_widget_click_check_type +handle_widget_click_textbox_sl: + push r0 + push r10 + push r11 + push r12 + push r13 + push r21 + push r22 + + ; get textbox width + add r0, 16 + movz.16 r10, [r0] + + ; get textbox height + mov r13, TEXTBOX_SL_HEIGHT + + ; get textbox X coordinate + add r0, 4 + movz.16 r11, [r0] + + ; get textbox Y coordinate + add r0, 2 + movz.16 r12, [r0] + + ; calculate textbox's right side coordinate + mov r21, r11 + add r21, r10 + + ; calculate textbox's bottom right corner coordinate + mov r22, r12 + add r22, r13 + + ; check if r1 is between r11 and r21 + ; and if r2 is between r12 and r22 + cmp r1, r11 + iflt jmp handle_widget_click_textbox_sl_no_click + cmp r1, r21 + ifgt jmp handle_widget_click_textbox_sl_no_click + cmp r2, r12 + iflt jmp handle_widget_click_textbox_sl_no_click + cmp r2, r22 + ifgt jmp handle_widget_click_textbox_sl_no_click + + ; if we reach this point then the textbox was clicked!! + pop r22 + pop r21 + pop r13 + pop r12 + pop r11 + pop r10 + + ; set active widget pointer + mov r0, [rsp+4] + mov [r30+36], r0 + + pop r0 + + ; redraw the textbox + mov r10, r0 + mov r0, r30 + call draw_widgets_to_window_textbox_sl + + jmp handle_widget_click_done +handle_widget_click_textbox_sl_no_click: + pop r22 + pop r21 + pop r13 + pop r12 + pop r11 + pop r10 + pop r0 + + ; get pointer to next widget + sub r0, 8 + mov r0, [r0] + + ; if this is the last widget, then exit + cmp r0, 0 + ifz jmp handle_widget_click_done + + ; retry + jmp handle_widget_click_check_type + +; handle key-down events for the active widget +; inputs: +; r0: pointer to window struct +; r1: key scancode +; outputs: +; none +handle_widget_key_down: + push r0 + push r1 + push r2 + push r3 + push r4 + push r5 + push r6 + push r7 + push r8 + push r30 + + mov r30, r0 + + ; get pointer to current widget + mov r0, [r0+36] +handle_widget_key_down_check_type: + ; check widget type + cmp [r0+8], WIDGET_TYPE_TEXTBOX_SL + ifz jmp handle_widget_key_down_textbox_sl +handle_widget_key_down_done: + pop r30 + pop r8 + pop r7 + pop r6 + pop r5 + pop r4 + pop r3 + pop r2 + pop r1 + pop r0 + ret +handle_widget_key_down_textbox_sl: + ; r0: pointer to textbox widget struct + ; r1: key scancode + ; r30: pointer to window struct + + mov r2, [r0+12] ; r2: pointer to text buffer + movz.16 r3, [r0+26] ; r3: max length of buffer + push r0 + mov r0, r2 + call string_length + mov r4, r0 ; r4: current length of text buffer + pop r0 + + cmp.8 r1, KEY_CTRL + ifz jmp handle_widget_key_down_done + cmp.8 r1, KEY_LSHIFT + ifz push handle_widget_key_down_done + ifz jmp shift_pressed + cmp.8 r1, KEY_RSHIFT + ifz push handle_widget_key_down_done + ifz jmp shift_pressed + cmp.8 r1, KEY_CAPS + ifz push handle_widget_key_down_done + ifz jmp caps_pressed + + ; convert scancode to ascii + push r0 + mov r0, r1 + call scancode_to_ascii + mov r1, r0 + pop r0 + + ; if this is a backspace, delete a char + cmp r1, 8 + ifz jmp handle_widget_key_down_textbox_sl_backspace + + ; insert character at the end + dec r3 + cmp r4, r3 + ifgteq jmp handle_widget_key_down_done + add r2, r4 ; point to end of text buffer + mov.8 [r2], r1 + mov.8 [r2+1], 0 + + ; redraw the textbox + mov r10, r0 + add r10, 8 + mov r0, r30 + call draw_widgets_to_window_textbox_sl + + jmp handle_widget_key_down_done +handle_widget_key_down_textbox_sl_backspace: + ; delete character at the end + dec r4 + add r2, r4 ; point to end of text buffer + mov.8 [r2], 0 + + ; redraw the textbox + mov r10, r0 + add r10, 8 + mov r0, r30 + call draw_widgets_to_window_textbox_sl + + jmp handle_widget_key_down_done + +; handle key-up events for the active widget +; inputs: +; r0: pointer to window struct +; r1: key scancode +; outputs: +; none +handle_widget_key_up: + push r0 + push r1 + push r2 + push r3 + push r4 + push r5 + push r6 + push r7 + push r8 + push r30 + + mov r30, r0 + + ; get pointer to current widget + mov r0, [r0+36] +handle_widget_key_up_check_type: + ; check widget type + cmp [r0+8], WIDGET_TYPE_TEXTBOX_SL + ifz jmp handle_widget_key_up_textbox_sl +handle_widget_key_up_done: + pop r30 + pop r8 + pop r7 + pop r6 + pop r5 + pop r4 + pop r3 + pop r2 + pop r1 + pop r0 + ret +handle_widget_key_up_textbox_sl: + cmp.8 r1, KEY_LSHIFT + ifz push handle_widget_key_up_done + ifz jmp shift_released + cmp.8 r1, KEY_RSHIFT + ifz push handle_widget_key_up_done + ifz jmp shift_released + cmp.8 r1, KEY_CAPS + ifz push handle_widget_key_up_done + ifz jmp caps_pressed + + jmp handle_widget_key_up_done ; include widget types #include "widget/button.asm" + #include "widget/textbox_sl.asm" diff --git a/kernel/window/event.asm b/kernel/window/event.asm index a0f4b43..63ff5d6 100644 --- a/kernel/window/event.asm +++ b/kernel/window/event.asm @@ -2,6 +2,7 @@ ; event types const EVENT_TYPE_BUTTON_CLICK: 0x80000000 +const EVENT_TYPE_TEXTBOX_REFRESH: 0x80000001 const WINDOW_EVENT_SIZE: 32 diff --git a/kernel/window/messagebox.asm b/kernel/window/messagebox.asm index 4b2f7c3..0f7a6de 100644 --- a/kernel/window/messagebox.asm +++ b/kernel/window/messagebox.asm @@ -100,7 +100,7 @@ messagebox_ok_clicked: ret messagebox_window_title: data.strz "Messagebox" -messagebox_window_struct: data.fill 0, 36 +messagebox_window_struct: data.fill 0, 40 messagebox_ok_button_widget: data.32 0 ; next_ptr data.32 0 ; id diff --git a/kernel/window/window.asm b/kernel/window/window.asm index 8c5eb29..42d07b7 100644 --- a/kernel/window/window.asm +++ b/kernel/window/window.asm @@ -14,8 +14,9 @@ ; data.16 flags - flags for this window ; data.32 menu_bar_ptr - pointer to this window's menu bar root struct, or 0 for none ; data.32 first_widget_ptr - pointer to this window's first widget +; data.32 active_widget_ptr - pointer to the currently active widget -const WINDOW_STRUCT_SIZE: 36 ; 9 words = 36 bytes +const WINDOW_STRUCT_SIZE: 40 ; 10 words = 40 bytes const TITLE_BAR_HEIGHT: 16 const TITLE_BAR_TEXT_FOREGROUND: 0xFF000000 const TITLE_BAR_TEXT_BACKGROUND: 0xFFFFFFFF @@ -23,7 +24,7 @@ const WINDOW_FLAG_ALWAYS_BACKGROUND: 1 ; create a new window and allocate memory as required ; inputs: -; r0: pointer to empty 36 byte window struct +; r0: pointer to empty 40 byte window struct ; r1: pointer to null-terminated title string ; r2: window width ; r3: window height, not including the title bar @@ -65,6 +66,9 @@ new_window: ; first widget pointer add r10, 4 mov [r10], r7 + ; active widget pointer + add r10, 4 + mov [r10], 0 ; then, allocate memory for the framebuffer ; the space required is width * (height + TITLE_BAR_HEIGHT) * 4