X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=vg_imgui.h;h=1b5aceac38bfc931a723ac4bf24213ada60381c7;hb=13737a7a9faa5b31696c711f153b7de4201c404e;hp=bb98812f3d90a76148ea0bcedac79f1e6b91188b;hpb=ffd724233b7a3cb89d0d5d253ba4c475d87c76e2;p=vg.git diff --git a/vg_imgui.h b/vg_imgui.h index bb98812..1b5acea 100644 --- a/vg_imgui.h +++ b/vg_imgui.h @@ -6,6 +6,10 @@ * 1. layout is defined by subdividing * 2. a parent node should never be resized by the content after creation * 3. when the ui is in an interactive state, no controls should ever move + * 4. controls directly reference a memory location and use that as their + * unique id + * 5. a maximum of ONE control per memory location can be drawn at any given + * point. */ #ifndef VG_IMGUI_H @@ -28,6 +32,7 @@ enum ui_axis { /* Relative to cursor p0 */ enum ui_align { /* DC BA */ + k_ui_align_lwr = 0xff, k_ui_align_left = 0x0000| 0x00, k_ui_align_right = 0x0000| 0x01, k_ui_align_center = 0x0000| 0x02, @@ -92,26 +97,47 @@ struct{ void *focused_control_id; /* uses the memory location of various locking controls as an id */ char *textbuf; + struct ui_dropdown_value{ + i32 index, value; + } + *ptr_dropdown; }; u32 focused_control_hit; enum ui_control_type{ k_ui_control_none, k_ui_control_textbox, + k_ui_control_dropdown } focused_control_type; + union{ struct ui_textbuf{ int cursor_user, cursor_pos; u32 len; u32 flags; + + struct ui_textbox_callbacks{ + void (*enter)( char *, u32 ), + (*up)( char *, u32 ), + (*down)( char *, u32 ), + (*change)( char *, u32 ); + } + callbacks; } textbox; - void (*textbuf_on_enter) ( char *buf, u32 len ); - void (*textbuf_on_up) ( char *buf, u32 len ); - void (*textbuf_on_down) ( char *buf, u32 len ); - void (*textbuf_on_change)( char *buf, u32 len ); + struct ui_dropdown{ + struct ui_dropdown_opt{ + const char *alias; + i32 value; + } + *options; + u32 option_count; + ui_rect rect; + } + dropdown; + }; GLuint tex_glyphs, vao, vbo, ebo; @@ -273,16 +299,6 @@ static struct vg_shader _shader_ui_image = "void main()" "{" "vec4 colour = texture( uTexImage, aTexCoords );" - - /* wtf is this?? */ -#if 0 - "float value = dot(vec4(1.0),colour)*0.25;" - - "vec3 col = vec3(pow(cos(value*3.14159265*2.0)*0.5+0.5,0.5))" - "* vec3(step(value,0.5),0.3,step(1.0-value,0.5));" - "FragColor = vec4( col*4.0, 1.0 );" -#endif - "FragColor = colour;" "}" } @@ -434,6 +450,7 @@ VG_STATIC void ui_flush( enum ui_shader shader ) glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glBlendEquation( GL_FUNC_ADD ); + glDisable( GL_CULL_FACE ); m3x3f view = M3X3_IDENTITY; m3x3_translate( view, (v3f){ -1.0f, 1.0f, 0.0f } ); @@ -560,25 +577,29 @@ static void ui_outline( ui_rect rect, ui_px thickness, u32 colour ) vg_ui.cur_vert += 8; } -static void ui_split_px( ui_rect rect, - enum ui_axis other, ui_px width, ui_px pad, - ui_rect l, ui_rect r ) +static void ui_split( ui_rect rect, + enum ui_axis other, ui_px width, ui_px gap, + ui_rect l, ui_rect r ) { enum ui_axis dir = other ^ 0x1; + if( width < 0 ) width = rect[ 2+dir ] + width; + ui_rect temp; rect_copy( rect, temp ); - l[ dir ] = temp[ dir ] + pad; - r[ dir ] = temp[ dir ] + width + (pad/2); - l[ other ] = temp[ other ] + pad; - r[ other ] = temp[ other ] + pad; - l[ 2+dir ] = width - ((3*pad)/2); - r[ 2+dir ] = temp[ 2+dir ] - width - ((3*pad)/2); - l[ 2+other ] = temp[ 2+other ] - pad*2; - r[ 2+other ] = temp[ 2+other ] - pad*2; + l[ dir ] = temp[ dir ]; + r[ dir ] = temp[ dir ] + width + (gap/2); + l[ other ] = temp[ other ]; + r[ other ] = temp[ other ]; + l[ 2+dir ] = width - (gap/2); + r[ 2+dir ] = temp[ 2+dir ] - width - (gap/2); + l[ 2+other ] = temp[ 2+other ]; + r[ 2+other ] = temp[ 2+other ]; } +static ui_px ui_text_line_width( const char *str ); + static void ui_rect_center( ui_rect parent, ui_rect rect ) { rect[0] = parent[0] + (parent[2]-rect[2])/2; @@ -602,18 +623,18 @@ static void ui_fit_item( ui_rect rect, ui_px size[2], ui_rect d ) } static void ui_split_ratio( ui_rect rect, enum ui_axis dir, float ratio, - ui_px pad, ui_rect l, ui_rect r ) + ui_px gap, ui_rect l, ui_rect r ) { ui_px width = (float)rect[ 2+(dir^0x1) ] * ratio; - ui_split_px( rect, dir, width, pad, l, r ); + ui_split( rect, dir, width, gap, l, r ); } -static void ui_rect_pad( ui_rect rect, ui_px pad ) +static void ui_rect_pad( ui_rect rect, ui_px pad[2] ) { - rect[0] += pad; - rect[1] += pad; - rect[2] -= pad*2; - rect[3] -= pad*2; + rect[0] += pad[0]; + rect[1] += pad[1]; + rect[2] -= pad[0]*2; + rect[3] -= pad[1]*2; } static ui_px ui_text_line_width( const char *str ) @@ -646,13 +667,14 @@ static ui_px ui_text_string_height( const char *str ) static ui_px ui_text_aligned_x( const char *str, ui_rect rect, ui_px scale, enum ui_align align ) { - if( align == k_ui_align_left ){ + enum ui_align lwr = k_ui_align_lwr & align; + if( lwr == k_ui_align_left ){ return rect[0]; } else{ ui_px width = ui_text_line_width( str ) * scale; - if( align == k_ui_align_right ) + if( lwr == k_ui_align_right ) return rect[0] + rect[2]-width; else return rect[0] + (rect[2]-width)/2; @@ -693,8 +715,8 @@ static int ui_inside_rect( ui_rect rect, ui_px co[2] ) { if( co[0] >= rect[0] && co[1] >= rect[1] && - co[0] <= rect[0]+rect[2] && - co[1] <= rect[1]+rect[3] ) + co[0] < rect[0]+rect[2] && + co[1] < rect[1]+rect[3] ) { return 1; } @@ -770,6 +792,15 @@ static u32 ui_colourcont( enum ui_scheme_colour id ) else return ui_colour( k_ui_fg+1 ); } +static void ui_hex_to_norm( u32 hex, v4f norm ) +{ + norm[0] = ((hex ) & 0xff); + norm[1] = ((hex>>8 ) & 0xff); + norm[2] = ((hex>>16) & 0xff); + norm[3] = ((hex>>24) & 0xff); + v4_muls( norm, 1.0f/255.0f, norm ); +} + static u32 ui_ntext( ui_rect rect, const char *str, u32 len, ui_px scale, enum ui_align align, u32 colour ) { @@ -905,7 +936,6 @@ static void ui_text( ui_rect rect, const char *str, ui_px scale, static void ui_image( ui_rect rect, GLuint image ) { ui_flush( k_ui_shader_colour ); - glActiveTexture( GL_TEXTURE0 ); glBindTexture( GL_TEXTURE_2D, image ); ui_fill_rect( rect, 0xffffffff, (ui_px[4]){ 0,128, 128, 0 } ); @@ -944,6 +974,13 @@ static int ui_colourbutton( ui_rect rect, enum ui_scheme_colour colour ) col_highlight = vg_ui.scheme[ k_ui_fg ], col_hover = vg_ui.scheme[ colour + k_ui_brighter ]; + if( vg_ui.focused_control_type != k_ui_control_none ){ + clickup = 0; + click = 0; + target = 0; + hover = 0; + } + if( hover ){ vg_ui.cursor = k_ui_cursor_hand; } @@ -1007,10 +1044,10 @@ static int ui_button_text( ui_rect rect, const char *string, ui_px scale ) return ui_colourbutton_text( rect, string, scale, k_ui_bg+4 ); } +static void ui_enum_post(void); static void ui_postrender(void) { if( vg_ui.click_fade_opacity > 0.0f ){ - float scale = vg_ui.click_fade_opacity; scale = vg_maxf( 1.0f/255.0f, scale*scale ); @@ -1032,6 +1069,11 @@ static void ui_postrender(void) ui_fill( rect, colour ); } + + if( vg_ui.focused_control_type == k_ui_control_dropdown ){ + ui_enum_post(); + } + ui_flush( k_ui_shader_colour ); if( !vg_ui.focused_control_hit ){ @@ -1068,12 +1110,12 @@ static void ui_dev_colourview(void) "k_ui_aqua+8","k_ui_blue+8","k_ui_purple+8","k_ui_gray+8" }; ui_rect col[2]; - ui_split_ratio( window, k_ui_axis_v, 0.5f, 0.0f, col[0], col[1] ); + ui_split_ratio( window, k_ui_axis_v, 0.5f, 0, col[0], col[1] ); for( int i=0; iindex ].alias, 1 ) ){ + vg_ui.focused_control_type = k_ui_control_dropdown; + vg_ui.ptr_dropdown = value; + vg_ui.dropdown.option_count = len; + vg_ui.dropdown.options = options; + rect_copy( box, vg_ui.dropdown.rect ); + } +} + +static void ui_enum_post(void) +{ + ui_rect drawer; + rect_copy( vg_ui.dropdown.rect, drawer ); + drawer[3] *= vg_ui.dropdown.option_count; + + int close = 0; + int clickany= ui_click_up(UI_MOUSE_LEFT|UI_MOUSE_RIGHT|UI_MOUSE_MIDDLE), + hover = ui_inside_rect( drawer, vg_ui.mouse ); + + if( clickany && !hover ){ + return; + } + + /* HACK */ + vg_ui.focused_control_type = k_ui_control_none; + struct ui_dropdown_value *value = vg_ui.ptr_dropdown; + + for( u32 i=0; iindex ) colour = k_ui_orange; + + if( ui_colourbutton_text( button, vg_ui.dropdown.options[i].alias, 1, + colour ) ){ + value->index = i; + value->value = vg_ui.dropdown.options[i].value; + close = 1; + } + } + + /* HACK */ + vg_ui.focused_control_type = k_ui_control_dropdown; + + if( !close ) + vg_ui.focused_control_hit = 1; +} + /* * Textbox chaos * ----------------------------------------------------------------------------- @@ -1265,8 +1374,8 @@ static void _ui_textbox_up(void) } } else{ - if( vg_ui.textbuf_on_up ){ - vg_ui.textbuf_on_up( vg_ui.textbuf, vg_ui.textbox.len ); + if( vg_ui.textbox.callbacks.up ){ + vg_ui.textbox.callbacks.up( vg_ui.textbuf, vg_ui.textbox.len ); } } } @@ -1320,8 +1429,8 @@ static void _ui_textbox_down(void) vg_ui.textbox.cursor_pos = line_below_begin+offset; } else{ - if( vg_ui.textbuf_on_down ){ - vg_ui.textbuf_on_down( vg_ui.textbuf, vg_ui.textbox.len ); + if( vg_ui.textbox.callbacks.down ){ + vg_ui.textbox.callbacks.down( vg_ui.textbuf, vg_ui.textbox.len ); } } } @@ -1345,8 +1454,9 @@ static void _ui_textbox_backspace(void) vg_ui.textbox.cursor_user = _ui_textbox_delete_char( -1 ); vg_ui.textbox.cursor_pos = vg_ui.textbox.cursor_user; - if( vg_ui.textbuf_on_change ) - vg_ui.textbuf_on_change( vg_ui.textbuf, vg_ui.textbox.len ); + if( vg_ui.textbox.callbacks.change ){ + vg_ui.textbox.callbacks.change( vg_ui.textbuf, vg_ui.textbox.len ); + } } } @@ -1356,8 +1466,9 @@ static void _ui_textbox_delete(void) vg_ui.textbox.cursor_user = _ui_textbox_delete_char( 1 ); vg_ui.textbox.cursor_pos = vg_ui.textbox.cursor_user; - if( vg_ui.textbuf_on_change ) - vg_ui.textbuf_on_change( vg_ui.textbuf, vg_ui.textbox.len ); + if( vg_ui.textbox.callbacks.change ){ + vg_ui.textbox.callbacks.change( vg_ui.textbuf, vg_ui.textbox.len ); + } } } @@ -1408,8 +1519,8 @@ static void _ui_textbox_enter(void) ui_defocus_all(); } - if( vg_ui.textbuf_on_enter ){ - vg_ui.textbuf_on_enter( vg_ui.textbuf, vg_ui.textbox.len ); + if( vg_ui.textbox.callbacks.enter ){ + vg_ui.textbox.callbacks.enter( vg_ui.textbuf, vg_ui.textbox.len ); } } } @@ -1499,13 +1610,25 @@ static int _ui_textbox_run_remaining( int index[3], int wrap_length ) return printed_chars+1; } -static int ui_textbox( ui_rect rect, char *buf, u32 len, u32 flags ) +static int ui_textbox( ui_rect rect, char *buf, u32 len, u32 flags, + struct ui_textbox_callbacks *callbacks ) { int clickup= ui_click_up(UI_MOUSE_LEFT), + clickdown = ui_click_down(UI_MOUSE_LEFT), click = ui_clicking(UI_MOUSE_LEFT) | clickup, target = ui_inside_rect( rect, vg_ui.mouse_click ) && click, hover = ui_inside_rect( rect, vg_ui.mouse ); + /* allow instant transitions from textbox->textbox */ + if( (vg_ui.focused_control_type != k_ui_control_none) && + (vg_ui.focused_control_type != k_ui_control_textbox) ){ + clickup = 0; + clickdown = 0; + click = 0; + target = 0; + hover = 0; + } + u32 col_base = ui_colour( k_ui_bg ), col_highlight = ui_colour( k_ui_fg ), col_cursor = (0x00ffffff & ui_colour(k_ui_fg))|0x7f000000; @@ -1534,8 +1657,7 @@ static int ui_textbox( ui_rect rect, char *buf, u32 len, u32 flags ) ui_fill( rect, col_base ); ui_ntext( text_rect, buf, wrap_length, 1, k_ui_align_left, 0 ); - if( !(flags & UI_TEXTBOX_AUTOFOCUS) && - ((clickup||ui_click_down(UI_MOUSE_LEFT)) && !target) ){ + if( !(flags & UI_TEXTBOX_AUTOFOCUS) && ((clickup||clickdown) && !target)){ ui_defocus_all(); } else{ @@ -1593,9 +1715,6 @@ static int ui_textbox( ui_rect rect, char *buf, u32 len, u32 flags ) } else{ while( remaining ){ - /* TODO: scan for newlines and stuff - * eol or wrap_length can have line breaks! */ - int run = _ui_textbox_run_remaining( pos, wrap_length ); run = VG_MIN( run, remaining ); @@ -1656,6 +1775,16 @@ static int ui_textbox( ui_rect rect, char *buf, u32 len, u32 flags ) vg_ui.textbox.cursor_pos = 0; vg_ui.textbox.cursor_user = 0; + if( callbacks ){ + vg_ui.textbox.callbacks = *callbacks; + } + else{ + vg_ui.textbox.callbacks.change = NULL; + vg_ui.textbox.callbacks.down = NULL; + vg_ui.textbox.callbacks.up = NULL; + vg_ui.textbox.callbacks.enter = NULL; + } + SDL_StartTextInput(); } } @@ -1757,10 +1886,19 @@ VG_STATIC void ui_proc_utf8( const char *text ) ptr ++; } - if( vg_ui.textbuf_on_change ){ - vg_ui.textbuf_on_change( vg_ui.textbuf, vg_ui.textbox.len ); + if( vg_ui.textbox.callbacks.change ){ + vg_ui.textbox.callbacks.change( vg_ui.textbuf, vg_ui.textbox.len ); } } } +static void ui_label( ui_rect rect, const char *text, ui_px size, + ui_px gap, ui_rect r ) +{ + ui_rect l; + ui_px width = (ui_text_line_width(text)+UI_GLYPH_SPACING_X) * size; + ui_split( rect, k_ui_axis_v, width, gap, l, r ); + ui_text( l, text, 1, k_ui_align_middle_left, 0 ); +} + #endif /* VG_IMGUI_H */