Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI styling revision #100

Merged
merged 59 commits into from
Feb 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
3f9bd20
[wip] box style setters from typed value
martinfouilleul Jan 27, 2025
ece80e7
[wip] reworking rule system
martinfouilleul Jan 28, 2025
bd623ff
[wip] API to define rules
martinfouilleul Jan 28, 2025
ce95ea7
[wip] matching style rules
martinfouilleul Jan 29, 2025
a3d09f2
parse style rule pattern from string
martinfouilleul Jan 29, 2025
709a858
[wip] implement specificity precedence for style rules
martinfouilleul Jan 29, 2025
482f92c
[wip] automatically add hover and active tags
martinfouilleul Jan 29, 2025
8e1d5d4
[wip] ui-bench sketch: wait for ui thread to finish before exiting (G…
martinfouilleul Jan 29, 2025
2edad56
[wip] remove OC_UI_FLAG_DRAW_TEXT flag, infer from presence of text, …
martinfouilleul Jan 29, 2025
4b238e9
[wip] custom style variables
martinfouilleul Jan 30, 2025
a4ac573
[wip] replacing theme with style variables
martinfouilleul Jan 30, 2025
ca9f6a4
[wip] default dark and light themes
martinfouilleul Jan 31, 2025
5ac0f9d
[wip] panel
martinfouilleul Jan 31, 2025
fbb7af1
pushing panel features to generic box, move overflow behaviour to sty…
martinfouilleul Jan 31, 2025
3477618
[wip] fix overlay
martinfouilleul Jan 31, 2025
527772d
[wip] remove overlay flag in favour of oc_ui_set_overlay()
martinfouilleul Jan 31, 2025
22585b7
[wip] removed ui box flags
martinfouilleul Jan 31, 2025
d3ff856
[wip] cleanup - renaming attribute/variables functions
martinfouilleul Jan 31, 2025
28f2ba4
[wip] checkbox and slider
martinfouilleul Feb 1, 2025
6457018
[wip] radio group
martinfouilleul Feb 1, 2025
37c7fa9
[wip] cleanup header
martinfouilleul Feb 3, 2025
ad7394c
split widgets from ui.c, add oc_ui_box_rect() and oc_ui_box_style()
martinfouilleul Feb 3, 2025
6a78473
[wip] remove activate/deactivate and replace with oc_ui_box_set_active
martinfouilleul Feb 3, 2025
f4fe676
[wip] tooltip, but we raised some questions about custom draw proc an…
martinfouilleul Feb 3, 2025
6b318c8
add OC_UI_DRAW_FLAGS attribute, with one bit per feature (border, bac…
martinfouilleul Feb 4, 2025
68062ca
[wip] debugging select popup
martinfouilleul Feb 4, 2025
bffd9d5
[wip] finish select popup
martinfouilleul Feb 4, 2025
9ca1ab9
[wip] working on text box
martinfouilleul Feb 5, 2025
2220522
[wip] fixed text box active style
martinfouilleul Feb 5, 2025
c83ebc1
[wip] removed inner box in oc_ui_text_box
martinfouilleul Feb 5, 2025
264725d
[wip] port runtime debug overlay to new UI system
martinfouilleul Feb 5, 2025
348b669
[wip] working on porting the UI sample
martinfouilleul Feb 6, 2025
abd085b
[wip] working on porting the UI sample
martinfouilleul Feb 6, 2025
aaf146b
[wip] working on porting the UI sample
martinfouilleul Feb 6, 2025
fb8ecd8
[wip] passing theme proc in oc_ui_frame_begin()?
martinfouilleul Feb 6, 2025
03e0645
[wip] finish UI sample
martinfouilleul Feb 7, 2025
eecde72
[wip] fix slider jumping
martinfouilleul Feb 7, 2025
b78c8fc
[wip] Fix sliders and radio button border clipping. Fix UI sample rad…
martinfouilleul Feb 7, 2025
58a0254
[wip] change value of light theme background
martinfouilleul Feb 7, 2025
21b9bb3
[wip] update api.json
martinfouilleul Feb 7, 2025
a33a683
Merge branch 'main' into ui-styling-revision
martinfouilleul Feb 7, 2025
1886972
fix widgets module name in api.json
martinfouilleul Feb 7, 2025
4748685
update doc site CI upload artifact to v4
martinfouilleul Feb 7, 2025
bcd7598
update doc site CI upload artifact to v4
martinfouilleul Feb 7, 2025
d6f680a
clean up UI sample
martinfouilleul Feb 7, 2025
0f01366
[wip] children never block parent's hover
martinfouilleul Feb 11, 2025
4ba6aef
[wip] Take border size into account when doing layout. Border now tak…
martinfouilleul Feb 11, 2025
89658e3
add implicit top box wrappers for box status getters/setters
martinfouilleul Feb 11, 2025
981c5cd
[wip] fixing msvc being dumb about OC_STR8_LIT
martinfouilleul Feb 11, 2025
7883149
[wip] fix slider thumb offset and clipping
martinfouilleul Feb 11, 2025
f4daeff
update api.json
martinfouilleul Feb 11, 2025
c872570
[wip] remove hot status (already covered by hover)
martinfouilleul Feb 12, 2025
11d1afa
[wip] removing use of active status in menu, using cached user pointe…
martinfouilleul Feb 12, 2025
0ac605e
- Hover/Active status are now computed from input
martinfouilleul Feb 12, 2025
b155e9c
replace oc_ui_attr with oc_ui_attribute
martinfouilleul Feb 16, 2025
da4a691
[wip] removed stale comments/TODOs
martinfouilleul Feb 16, 2025
aa9ec10
Merge branch 'main' into ui-styling-revision
martinfouilleul Feb 16, 2025
8a3a85e
fix UI sample hovering -> hover
martinfouilleul Feb 16, 2025
8d93179
fix slider thumb clipping
martinfouilleul Feb 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/mkdocs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ nav:
- Canvas API: 'api/Graphics/Canvas API.md'
- GLES Surface: 'api/Graphics/GLES Surface.md'
- UI: 'api/UI.md'
- UI Core: 'api/UI Core.md'
- UI Widgets: 'api/UI Widgets.md'

- Developer Guide:
- Building: 'building.md'
Expand Down
795 changes: 376 additions & 419 deletions samples/ui/src/main.c

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions scripts/api_dump.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ def generate_type_entry(entries, ast, tu):
}

if ast.kind == cindex.CursorKind.TYPEDEF_DECL:

underlying = ast.underlying_typedef_type

if underlying.kind == cindex.TypeKind.RECORD or underlying.kind == cindex.TypeKind.ENUM:
Expand Down
Binary file added sketches/ui-bench/OpenSans-Bold.ttf
Binary file not shown.
Binary file added sketches/ui-bench/OpenSans-Regular.ttf
Binary file not shown.
18 changes: 18 additions & 0 deletions sketches/ui-bench/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash

BINDIR=bin
LIBDIR=../../build/bin
RESDIR=../resources
SRCDIR=../../src

INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app"
LIBS="-L$LIBDIR -lorca"
FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG"

mkdir -p $BINDIR
clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_ui main.c

cp $LIBDIR/liborca.dylib $BINDIR/
cp $LIBDIR/libwebgpu.dylib $BINDIR/

install_name_tool -add_rpath "@executable_path" $BINDIR/example_ui
330 changes: 330 additions & 0 deletions sketches/ui-bench/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,330 @@
/*************************************************************************
*
* Orca
* Copyright 2023 Martin Fouilleul and the Orca project contributors
* See LICENSE.txt for licensing information
*
**************************************************************************/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define _USE_MATH_DEFINES //NOTE: necessary for MSVC
#include <math.h>

#include "orca.h"

oc_vec2 frameSize = { 1200, 838 };

oc_surface surface;
oc_canvas_renderer renderer;
oc_canvas_context context;
oc_font fontRegular;
oc_font fontBold;

i32 ui_runloop(void* user)
{
context = oc_canvas_context_create();

oc_ui_context* ui = oc_ui_context_create(fontRegular);

oc_ui_radio_group_info radioInfo = {
.optionCount = 4,
.options = (oc_str8[]){
OC_STR8("Option One"),
OC_STR8("Option Two"),
OC_STR8("Option Three"),
OC_STR8("Option Four"),
},
};

oc_ui_select_popup_info popupInfo = {
.selectedIndex = -1,
.optionCount = 3,
.options = (oc_str8[]){
OC_STR8("Option One"),
OC_STR8("Option Two"),
OC_STR8("Options Three"),
},
.placeholder = OC_STR8("None"),
};

oc_arena textArena = { 0 };
oc_arena_init(&textArena);

oc_ui_text_box_info textBoxInfo = {
.defaultText = OC_STR8_LIT("type here"),
};

oc_arena textArena2 = { 0 };
oc_arena_init(&textArena2);

oc_ui_text_box_info textBoxInfo2 = {
.defaultText = OC_STR8_LIT("type here"),
};

while(!oc_should_quit())
{
oc_arena_scope scratch = oc_scratch_begin();

oc_event* event = 0;
while((event = oc_next_event(scratch.arena)) != 0)
{
oc_ui_process_event(event);

switch(event->type)
{
case OC_EVENT_WINDOW_CLOSE:
{
oc_request_quit();
}
break;

case OC_EVENT_WINDOW_RESIZE:
{
frameSize = (oc_vec2){ event->move.content.w, event->move.content.h };
}
break;

default:
break;
}
}

oc_ui_frame(frameSize)
{
oc_ui_menu_bar("menu")
{
oc_ui_menu("file-menu", "File")
{
oc_ui_menu_button("quit", "Quit");
}
oc_ui_menu("theme-menu", "Theme")
{
if(oc_ui_menu_button("dark", "Dark").pressed)
{
oc_log_info("selected dark theme\n");
}
if(oc_ui_menu_button("ligth", "Light").pressed)
{
oc_log_info("selected light theme\n");
}
}
}

oc_ui_style_rule("inner lb")
{
oc_ui_style_set_color(OC_UI_BG_COLOR, (oc_color){ 0, 1, 0, 1 });
}

oc_ui_style_rule("inner .label")
{
oc_ui_style_set_color(OC_UI_BG_COLOR, (oc_color){ 1, 0, 0, 1 });
}

oc_ui_box("outer-box")
{
oc_ui_style_set_size(OC_UI_WIDTH, (oc_ui_size){ OC_UI_SIZE_PIXELS, 200 });
oc_ui_style_set_size(OC_UI_HEIGHT, (oc_ui_size){ OC_UI_SIZE_PIXELS, 200 });
oc_ui_style_set_color(OC_UI_BG_COLOR, (oc_color){ 1, 0, 0, 1 });

// oc_ui_style_set_i32(OC_UI_ALIGN_Y, OC_UI_ALIGN_CENTER);

oc_ui_box("inner-box")
{
oc_ui_style_set_size(OC_UI_WIDTH, (oc_ui_size){ OC_UI_SIZE_PIXELS, 100 });
oc_ui_style_set_size(OC_UI_HEIGHT, (oc_ui_size){ OC_UI_SIZE_PIXELS, 100 });

oc_ui_style_set_color(OC_UI_BG_COLOR, (oc_color){ 0, 1, 0, 1 });
oc_ui_style_set_color(OC_UI_BORDER_COLOR, (oc_color){ 0, 0, 1, 0.5 });
oc_ui_style_set_f32(OC_UI_BORDER_SIZE, 50);
}
}
oc_ui_box("container")
{
oc_ui_style_set_size(OC_UI_WIDTH, (oc_ui_size){ OC_UI_SIZE_CHILDREN });
oc_ui_style_set_size(OC_UI_HEIGHT, (oc_ui_size){ OC_UI_SIZE_CHILDREN });
oc_ui_style_set_var(OC_UI_BG_COLOR, "bg-1");

oc_ui_style_set_i32(OC_UI_AXIS, OC_UI_AXIS_Y);
oc_ui_style_set_f32(OC_UI_MARGIN_X, 10);
oc_ui_style_set_f32(OC_UI_MARGIN_Y, 10);
oc_ui_style_set_f32(OC_UI_SPACING, 10);

oc_ui_style_rule(".label.hover")
{
oc_ui_style_set_color(OC_UI_BG_COLOR, (oc_color){ 1, 0, 1, 1 });
}

oc_ui_label("la", "Label A");
oc_ui_label("lb", "Label B");
oc_ui_label("lc", "Label C");

oc_ui_button("ba", "Button A");
oc_ui_button("bb", "Button B");
oc_ui_button("bc", "Button C");

oc_ui_box("inner")
{
oc_ui_style_set_color(OC_UI_BG_COLOR, (oc_color){ 0, 0, 1, 1 });

oc_ui_style_set_size(OC_UI_WIDTH, (oc_ui_size){ OC_UI_SIZE_CHILDREN });
oc_ui_style_set_size(OC_UI_HEIGHT, (oc_ui_size){ OC_UI_SIZE_CHILDREN });
oc_ui_style_set_f32(OC_UI_MARGIN_X, 10);
oc_ui_style_set_f32(OC_UI_MARGIN_Y, 10);
oc_ui_style_set_f32(OC_UI_SPACING, 10);

oc_ui_label("la", "label A");
oc_ui_label("lb", "label B");
}
popupInfo = oc_ui_select_popup("popup", &popupInfo);

{
oc_ui_text_box_result result = oc_ui_text_box("textbox", scratch.arena, &textBoxInfo);
if(result.changed)
{
oc_arena_clear(&textArena);
textBoxInfo.text = oc_str8_push_copy(&textArena, result.text);
}
}

{
oc_ui_text_box_result result = oc_ui_text_box("textbox2", scratch.arena, &textBoxInfo2);
if(result.changed)
{
oc_arena_clear(&textArena2);
textBoxInfo2.text = oc_str8_push_copy(&textArena2, result.text);
}
}
}

oc_ui_box("panel")
{
oc_ui_style_set_size(OC_UI_WIDTH, (oc_ui_size){ OC_UI_SIZE_PIXELS, 300 });
oc_ui_style_set_size(OC_UI_HEIGHT, (oc_ui_size){ OC_UI_SIZE_PIXELS, 200 });
oc_ui_style_set_var_str8(OC_UI_BG_COLOR, OC_UI_THEME_BG_1);

oc_ui_style_set_i32(OC_UI_OVERFLOW_X, OC_UI_OVERFLOW_CLIP);
oc_ui_style_set_i32(OC_UI_OVERFLOW_Y, OC_UI_OVERFLOW_ALLOW);

/*
oc_ui_style_set_i32(OC_UI_AXIS, OC_UI_AXIS_Y);
oc_ui_style_set_f32(OC_UI_SPACING, 10);
*/
oc_ui_style_set_f32(OC_UI_MARGIN_X, 20);
oc_ui_style_set_f32(OC_UI_MARGIN_Y, 20);

oc_ui_box* box = oc_ui_box("box")
{
// oc_ui_style_set_size(OC_UI_WIDTH, (oc_ui_size){ OC_UI_SIZE_PARENT, 1 });
oc_ui_style_set_size(OC_UI_WIDTH, (oc_ui_size){ OC_UI_SIZE_PIXELS, 250 });
oc_ui_style_set_size(OC_UI_HEIGHT, (oc_ui_size){ OC_UI_SIZE_PIXELS, 400 });

oc_ui_style_set_f32(OC_UI_MARGIN_X, 10);
oc_ui_style_set_f32(OC_UI_MARGIN_Y, 10);
oc_ui_style_set_f32(OC_UI_SPACING, 5);

oc_ui_style_set_color(OC_UI_BG_COLOR, (oc_color){ 0, 0, 0, 1 });

static bool check = true;
oc_ui_checkbox("check", &check);

static f32 slider = 0;
oc_ui_slider("slider", &slider);

radioInfo = oc_ui_radio_group("radio", &radioInfo);

if(oc_ui_box_get_sig(box).hover)
{
oc_ui_tooltip("tooltip", "This is a black box");
}
}
oc_ui_button("mybutton", "clickMe");
}

/*
oc_ui_box("note")
{
oc_ui_set_overlay(true);

oc_ui_style_set_size(OC_UI_WIDTH, (oc_ui_size){ OC_UI_SIZE_PIXELS, 100 });
oc_ui_style_set_size(OC_UI_HEIGHT, (oc_ui_size){ OC_UI_SIZE_PIXELS, 50 });
oc_ui_style_set_color(OC_UI_BG_COLOR, (oc_color){ 1, 0, 0, 1 });
}
*/
}

oc_ui_draw();
oc_canvas_render(renderer, context, surface);
oc_canvas_present(renderer, surface);

oc_scratch_end(scratch);
}
return (0);
}

int main()
{
oc_init();
oc_clock_init(); //TODO put that in oc_init()?

oc_rect windowRect = { .x = 100, .y = 100, .w = frameSize.x, .h = frameSize.y };
oc_window window = oc_window_create(windowRect, OC_STR8("test"), 0);

oc_rect contentRect = oc_window_get_content_rect(window);

oc_window_set_title(window, OC_STR8("UI Test"));

renderer = oc_canvas_renderer_create();
surface = oc_canvas_surface_create_for_window(renderer, window);

oc_arena_scope scratch = oc_scratch_begin();

oc_font* fonts[2] = { &fontRegular, &fontBold };
oc_str8 fontNames[2] = {
oc_path_executable_relative(scratch.arena, OC_STR8("../OpenSans-Regular.ttf")),
oc_path_executable_relative(scratch.arena, OC_STR8("../OpenSans-Bold.ttf"))
};

for(int i = 0; i < 2; i++)
{
oc_file file = oc_file_open(fontNames[i], OC_FILE_ACCESS_READ, 0);
if(oc_file_last_error(file) != OC_IO_OK)
{
oc_log_error("Couldn't open file %.*s\n", oc_str8_ip(fontNames[i]));
}
u64 size = oc_file_size(file);
char* buffer = (char*)oc_arena_push(scratch.arena, size);
oc_file_read(file, size, buffer);
oc_file_close(file);
oc_unicode_range ranges[5] = { OC_UNICODE_BASIC_LATIN,
OC_UNICODE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT,
OC_UNICODE_LATIN_EXTENDED_A,
OC_UNICODE_LATIN_EXTENDED_B,
OC_UNICODE_SPECIALS };

*fonts[i] = oc_font_create_from_memory(oc_str8_from_buffer(size, buffer), 5, ranges);
}
oc_scratch_end(scratch);

// start app
oc_window_bring_to_front(window);
oc_window_focus(window);

oc_thread* runloopThread = oc_thread_create(ui_runloop, 0);

while(!oc_should_quit())
{
oc_pump_events(-1);
//TODO: what to do with mem scratch here?
}

i64 exitCode = 0;
oc_thread_join(runloopThread, &exitCode);

oc_surface_destroy(surface);
oc_terminate();

return (0);
}
Loading