more ui
authorhgn <hgodden00@gmail.com>
Wed, 31 Dec 2025 02:18:53 +0000 (02:18 +0000)
committerhgn <hgodden00@gmail.com>
Wed, 31 Dec 2025 02:18:53 +0000 (02:18 +0000)
source/engine/engine.kv
source/engine/vg_input.c
source/engine/vg_input.h
source/foundation/string.c
source/graphics/ui.c
source/graphics/vg_graphics.h
source/types.h

index b4b141707ca10d88f9085828ac813471b7096196..7c60d4913b830a972a9e4a86a497d3a20f5414ce 100644 (file)
@@ -132,6 +132,7 @@ config "bind DOWN ui_down"
 config "bind MOUSE_LEFT ui_click"
 config "bind LEFT_SHIFT ui_select"
 config "bind RIGHT_SHIFT ui_select"
+config "bind MOUSE_RIGHT ui_click_right"
 
 input
 {
@@ -206,6 +207,12 @@ input
    type action
    layer_mask ui
 }
+input 
+{
+   name ui_click_right
+   type action
+   layer_mask ui
+}
 
 test_feature
 {
index 74c57091fcc35f5cdaa5b9cf27d10a84da1c9e32..0dd614deadbb0752e232da07d9d38fe74e92b2d0 100644 (file)
@@ -443,8 +443,8 @@ static _input_states[2][k_input_count];
 struct bind
 {
    u16 device, input_index;
-   u16 id;
-   i16 polarity;
+   i16 polarity, unused0;
+   u32 id;
    u32 modifiers;
 };
 struct stretchy_allocator _bind_allocator;
@@ -562,8 +562,13 @@ i32 _input_unbind_ccmd( struct console_arguments *args )
    return -1;
 }
 
-void _input_callback_buttonlike( enum input_device device, i32 id, enum input_button_action action, u32 mods )
+void _input_callback_buttonlike( enum input_device device, u32 id, enum input_button_action action, u32 mods )
 {
+#if 0
+   $log( $info, {"dev: "}, $unsigned(device), {", id: "}, $unsigned(id,.base=16), {", action: "}, 
+                $signed(action), {", mods: "}, $unsigned(mods) );
+#endif
+
    for( u32 i=0; i<stretchy_count( &_bind_allocator ); i ++ )
    {
       struct bind *bind = stretchy_get( &_bind_allocator, i );
index 8fadff234aa5ecdcf200f060a639da7fcb06fe6b..b49b8597d422562a3c23ee29acc364b005f6124d 100644 (file)
@@ -31,7 +31,7 @@ enum input_button_action
    k_button_os_repeat,
    k_button_up
 };
-void _input_callback_buttonlike( enum input_device device, i32 id, enum input_button_action action, u32 mods );
+void _input_callback_buttonlike( enum input_device device, u32 id, enum input_button_action action, u32 mods );
 
 void _input_init(void);
 void _input_update(void);
index 1639112ca3460c7c47606c3899e9b272df37c4d7..9ca94f1ce0439ecd5e78f194c01c18fd30963ca4 100644 (file)
@@ -98,9 +98,9 @@ void string_append_f64( struct stream *string, f64 value, u64 base, u32 decimal_
    u64 m = 10;
    for( u32 i=0; i<(decimal_places-1); i ++ )
       m *= 10;
-   /* decimal part gets +1.0f because anything less than 1 does not have leading 0s 
+   /* decimal part gets +1.0 because anything less than 1 does not have leading 0s 
     * when printing it in the u64 print */
-   u64 decimal_part = (u64)((f64)m * (value+1.0f) + 0.5),
+   u64 decimal_part = (u64)((f64)m * (value+1.0)),
        normal_part  = (u64)value;
    string_append_u64( string, normal_part, base );
    string_append_c8( string, '.' );
index b2a024bc0acfd19328cace30a5145e773bebaa09..3e34a825cbd50e806fa916d76232cf931ad3e8b9 100644 (file)
@@ -8,6 +8,7 @@ struct
    //i16 clipping_area[4];
    i16 mouse_co[2], mouse_co_clicked[2];
    u32 mouse_mods;
+   u8  click_which;
 
    i16 mouse_co_container_last[4],
        mouse_co_container[4],
@@ -27,7 +28,7 @@ struct
    active_control_type;
    b8 active_control_touched;
    b8 redraw;
-   b8 fiddling;
+   u8 fiddling;
 
    union
    {
@@ -75,6 +76,46 @@ struct
 }
 _ui;
 
+#define UI_RGB( RGB ) (union colour){{ (RGB>>16) & 0xff, (RGB>>8) & 0xff, (RGB>>0) & 0xff, 0xff }}
+
+union colour _ui_scheme[ 8*4 ] =
+{
+   [ k_ui_bg+0 ] = UI_RGB( 0x1d2021 ),
+   [ k_ui_bg+1 ] = UI_RGB( 0x282828 ),
+   [ k_ui_bg+2 ] = UI_RGB( 0x3c3836 ),
+   [ k_ui_bg+3 ] = UI_RGB( 0x504945 ),
+   [ k_ui_bg+4 ] = UI_RGB( 0x665c54 ),
+   [ k_ui_bg+5 ] = UI_RGB( 0x7c6f64 ),
+   [ k_ui_bg+6 ] = UI_RGB( 0x928374 ),
+   [ k_ui_bg+7 ] = UI_RGB( 0xa89984 ),
+
+   [ k_ui_fg+0 ] = UI_RGB( 0xebdbb2 ),
+   [ k_ui_fg+1 ] = UI_RGB( 0xfbf1c7 ),
+   [ k_ui_fg+2 ] = UI_RGB( 0xd5c4a1 ),
+   [ k_ui_fg+3 ] = UI_RGB( 0xbdae93 ),
+   [ k_ui_fg+4 ] = UI_RGB( 0xa89984 ),
+   [ k_ui_fg+5 ] = UI_RGB( 0x000000 ), // FIXME
+   [ k_ui_fg+6 ] = UI_RGB( 0x000000 ), // FIXME
+   [ k_ui_fg+7 ] = UI_RGB( 0x000000 ), // FIXME
+
+   [ k_ui_red    ] = UI_RGB( 0xcc241d ),
+   [ k_ui_orange ] = UI_RGB( 0xd65d0e ),
+   [ k_ui_yellow ] = UI_RGB( 0xd79921 ),
+   [ k_ui_green  ] = UI_RGB( 0x98971a ),
+   [ k_ui_aqua   ] = UI_RGB( 0x689d6a ),
+   [ k_ui_blue   ] = UI_RGB( 0x458588 ),
+   [ k_ui_purple ] = UI_RGB( 0xb16286 ),
+   [ k_ui_gray   ] = UI_RGB( 0x928374 ),
+   [ k_ui_red    + k_ui_brighter ] = UI_RGB( 0xfb4934 ),
+   [ k_ui_orange + k_ui_brighter ] = UI_RGB( 0xfe8019 ),
+   [ k_ui_yellow + k_ui_brighter ] = UI_RGB( 0xfabd2f ),
+   [ k_ui_green  + k_ui_brighter ] = UI_RGB( 0xb8bb26 ),
+   [ k_ui_aqua   + k_ui_brighter ] = UI_RGB( 0x8ec07c ),
+   [ k_ui_blue   + k_ui_brighter ] = UI_RGB( 0x83a598 ),
+   [ k_ui_purple + k_ui_brighter ] = UI_RGB( 0xd3869b ),
+   [ k_ui_gray   + k_ui_brighter ] = UI_RGB( 0xa89984 ),
+};
+
 void _ui_get_mouse_co( i16 out_co[2] )
 {
    out_co[0] = _ui.mouse_co[0];
@@ -203,6 +244,7 @@ decode_loop:
          {
             i16 char_root[2] = { text_root[0] + decoder.grid_co[0]*kerning[0],
                                  text_root[1] + decoder.grid_co[1]*kerning[1] };
+            _graphics_glyph( (i16[2]){ char_root[0], char_root[1]+1 }, decoder.c, 1, (union colour){{0,0,0,128}} );
             _graphics_glyph( char_root, decoder.c, 1, colour );
          }
    }
@@ -237,9 +279,7 @@ enum button_action _ui_button( i16 rect[4] )
    union colour debug_colour = (union colour){{ 200, 200, 200, 50 }};
    enum button_action action = k_button_none;
 
-   b8 mouse_in_box = 0,
-      clicked_in_box = 0;
-
+   b8 mouse_in_box = 0;
    if( ui_inside_rect( rect, _ui.mouse_co ) )
    {
       rect_copy( rect, _ui.mouse_co_container );
@@ -247,10 +287,6 @@ enum button_action _ui_button( i16 rect[4] )
          mouse_in_box = 1;
    }
 
-   if( ui_inside_rect( rect, _ui.mouse_co_clicked ) )
-      if( rect_eq( rect, _ui.mouse_co_clicked_container_last ) )
-         clicked_in_box = 1;
-
    if( mouse_in_box )
    {
       if( _input_button_down( k_input_action_ui_click, 0 ) )
@@ -262,10 +298,18 @@ enum button_action _ui_button( i16 rect[4] )
 
       if( !_input_button( k_input_action_ui_click ) )
          action = k_button_hover;
+
+      if( _input_button_down( k_input_action_ui_click_right, 0 ) )
+         action = k_button_click_alt;
    }
 
-   if( clicked_in_box && _input_button( k_input_action_ui_click ) && !_input_button_down( k_input_action_ui_click, 0 ) )
-      action = k_button_repeat;
+   /* repeat test */
+   if( _input_button( k_input_action_ui_click ) && !_input_button_down( k_input_action_ui_click, 0 ) )
+   {
+      if( ui_inside_rect( rect, _ui.mouse_co_clicked ) )
+         if( rect_eq( rect, _ui.mouse_co_clicked_container_last ) )
+            action = k_button_repeat;
+   }
 
    if( action == k_button_click || action == k_button_repeat )
       _ui.active_control_touched = 1;
@@ -278,7 +322,7 @@ enum button_action _ui_checkbox( i16 rect[4], i32 *value )
    if( action == k_button_click )
       *value = (*value) ^ 0x1;
    if( *value )
-      _ui_text( rect, "\xB3", k_ui_align_center, (union colour){{0,255,0,255}} );
+      _ui_text( rect, "\xB3", k_ui_align_center, _ui_scheme[ k_ui_green ] );
    return action;
 }
 
@@ -384,6 +428,7 @@ enum textbox_action _ui_textbox( i16 rect[4], c8 *text_buffer, u32 text_buffer_l
 {
    i16 kerning[3];
    _font_get_kerning( kerning );
+   _graphics_fill_rect( rect, _ui_scheme[ k_ui_bg ] );
 
    b8 init = 0;
    if( _ui_button( rect ) == k_button_click )
@@ -419,12 +464,12 @@ enum textbox_action _ui_textbox( i16 rect[4], c8 *text_buffer, u32 text_buffer_l
 
    enum textbox_action return_action = k_textbox_no_action;
 
-   union colour text_colour = (union colour){{255,255,255,255}};
+   union colour text_colour = _ui_scheme[ k_ui_fg + 2 ];
    if( _ui.active_control_type == k_ui_control_textbox )
    {
       if( _ui.controls.textbox.text_buffer == text_buffer )
       {
-         text_colour = (union colour){{0,255,0,255}};
+         text_colour = _ui_scheme[ k_ui_fg ];
          _ui.active_control_touched = 1;
 
          struct ui_string_decoder decoder;
@@ -452,7 +497,7 @@ enum textbox_action _ui_textbox( i16 rect[4], c8 *text_buffer, u32 text_buffer_l
                    pw = (decoder.grid_co[0] - x_start) * kerning[0];
 
                i16 box[4] = { rect[0]+px, rect[1]+decoder.grid_co[1]*kerning[1], pw, kerning[1] };
-               _graphics_line_rect( box, (union colour){{255,0,0,255}} );
+               _graphics_line_rect( box, _ui_scheme[ k_ui_red ] );
                if( decoder.character_index >= i1 )
                   loop = 0;
 
@@ -465,7 +510,7 @@ enum textbox_action _ui_textbox( i16 rect[4], c8 *text_buffer, u32 text_buffer_l
          } while( loop );
          _graphics_line_rect( (i16[]){ rect[0] + user_co[0]*kerning[0],
                                        rect[1] + user_co[1]*kerning[1], kerning[0],kerning[1] },
-                                       (union colour){{255,255,0,255}} );
+                                       _ui_scheme[ k_ui_yellow ] );
 
          if( _input_button( k_input_action_ui_click ) )
          {
@@ -495,7 +540,7 @@ enum textbox_action _ui_textbox( i16 rect[4], c8 *text_buffer, u32 text_buffer_l
          }
       }
    }
-   _ui_text( rect, text_buffer, k_ui_align_x_left, text_colour );
+   _ui_text( rect, text_buffer, k_ui_align_x_left | (lines==1?k_ui_align_y_center:0), text_colour );
 
    return return_action;
 }
@@ -510,19 +555,37 @@ enum dropdown_action _ui_dropdown( i16 rect[4], struct ui_dropdown_option *optio
          break;
       }
 
-   if( _ui_button( rect ) == k_button_click )
+   b8 allow_interact = 1;
+   if( _ui.active_control_type == k_ui_control_dropdown )
+      if( _ui.controls.dropdown.value == value )
+         allow_interact = 0;
+
+   union colour c = _ui_scheme[ k_ui_bg+2 ];
+   union colour tc = _ui_scheme[ k_ui_fg ];
+   if( allow_interact )
    {
-      _ui.active_control_type = k_ui_control_dropdown;
-      rect_copy( rect, _ui.controls.dropdown.source_rect );
-      _ui.controls.dropdown.options = options;
-      _ui.controls.dropdown.option_count = option_count;
-      _ui.controls.dropdown.action = k_dropdown_none;
-      _ui.controls.dropdown.value = value;
+      enum button_action action = _ui_button( rect );
+      if( action == k_button_click )
+      {
+         _ui.active_control_type = k_ui_control_dropdown;
+         rect_copy( rect, _ui.controls.dropdown.source_rect );
+         _ui.controls.dropdown.options = options;
+         _ui.controls.dropdown.option_count = option_count;
+         _ui.controls.dropdown.action = k_dropdown_none;
+         _ui.controls.dropdown.value = value;
+      }
+
+      // FIXME: Duplicated
+      if( action == k_button_hover )
+         c = _ui_scheme[ k_ui_bg+3 ];
+      else if( action != k_button_none )
+         c = _ui_scheme[ k_ui_bg+7 ];
    }
+   _graphics_fill_rect( rect, c );
 
-   _ui_text( rect, display_text, k_ui_align_center, (union colour){{255,255,255,255}});
+   _ui_text( rect, display_text, k_ui_align_center, _ui_scheme[ k_ui_fg ] );
    i16 icon_box[4] = { rect[0] + rect[2]-UI_PADDING_PX*2, rect[1], UI_PADDING_PX*2, rect[3] };
-   _ui_text( icon_box, "\x96", k_ui_align_center, (union colour){{255,255,255,255}} );
+   _ui_text( icon_box, "\x96", k_ui_align_center, _ui_scheme[ k_ui_fg ] );
 
    if( _ui.active_control_type == k_ui_control_dropdown )
       if( _ui.controls.dropdown.value == value )
@@ -576,14 +639,14 @@ b8 _ui_update(void)
       }
 
       b8 select_mode = _input_button( k_input_button_ui_select );
-
       for( u8 i=0; i<_input_button_down( k_input_button_ui_home, 1 ); i ++ ) 
          _ui_textbox_set_cursor_user( 0, select_mode );
       for( u8 i=0; i<_input_button_down( k_input_button_ui_end, 1 ); i ++ ) 
          _ui_textbox_set_cursor_user( buffer_last_index( _ui.controls.textbox.text_buffer, 0, 0 ), select_mode );
       for( u8 i=0; i<_input_button_down( k_input_button_ui_right, 1 ); i ++ ) 
       {
-         i32 p1 = i32_min( buffer_last_index( _ui.controls.textbox.text_buffer, 0, 0 ), _ui.controls.textbox.cursor_user+1 );
+         i32 p1 = i32_min( buffer_last_index( _ui.controls.textbox.text_buffer, 0, 0 ), 
+                           _ui.controls.textbox.cursor_user+1 );
          _ui_textbox_set_cursor_user( p1, select_mode );
       }
       for( u8 i=0; i<_input_button_down( k_input_button_ui_left, 1 ); i ++ ) 
@@ -653,10 +716,8 @@ b8 _ui_update(void)
             _ui.controls.textbox.action = k_textbox_input_up;
       }
    }
-
    _ui.active_control_touched = 0;
    _ui.mouse_went_in_click_hole = 0;
-
    return _ui.redraw;
 }
 
@@ -683,32 +744,76 @@ void _ui_draw( i16 window_size[2] )
             $log( $info, {"Set dropdown enum value to: "}, $signed( option->value ) );
          }
 
-         union colour c = (union colour){{100,100,100,255}};
+         union colour c = _ui_scheme[ k_ui_bg + 1 ];
          if( action == k_button_hover )
-            c = (union colour){{160,160,160,255}};
+            c = _ui_scheme[ k_ui_bg + 3 ];
          else if( action != k_button_none )
-            c = (union colour){{200,200,200,255}};
+            c = _ui_scheme[ k_ui_fg ];
          _graphics_fill_rect( button_rect, c );
          
          c8 temp[32];
          struct stream string;
          stream_open_buffer_write( &string, temp, sizeof(temp), k_stream_null_terminate );
          string_append_i64( &string, option->value, 10 );
-         _ui_text( button_rect, temp, k_ui_align_y_center, (union colour){{128,128,128,255}} );
-         _ui_text( button_rect, option->display_name, k_ui_align_center, (union colour){{255,255,255,255}} );
+         _ui_text( button_rect, temp, k_ui_align_y_center, _ui_scheme[ k_ui_fg + 3 ] );
+         _ui_text( button_rect, option->display_name, k_ui_align_center, _ui_scheme[ k_ui_fg ] );
 
          if( current_value == option->value )
          {
             i16 tick_rect[4] = { button_rect[0]+button_rect[2]-UI_PADDING_PX*2, button_rect[1],
                                  UI_PADDING_PX*2, button_rect[3] };
-            _ui_text( tick_rect, "\xB3", k_ui_align_center, (union colour){{0,255,0,255}} );
+            _ui_text( tick_rect, "\xB3", k_ui_align_center, _ui_scheme[ k_ui_green ] );
          }
       }
       _ui.active_control_type = k_ui_control_dropdown;
       _ui.active_control_touched = 1;
    }
 
-   if( _ui.fiddling )
+   if( _ui.fiddling == 3 )
+   {
+      i16 w = 300,
+          h = 300,
+          px = i16_clamp( _ui.fiddle.co[0], 0, window_size[0]-w ),
+          py = i16_clamp( _ui.fiddle.co[1], 0, window_size[1]-h );
+
+      _ui_panel( &_ui.fiddle.panel, (i16[]){ px,py,w,h }, "Fiddle", UI_NO_OPTIONS );
+      if( _ui_panel_content( &_ui.fiddle.panel ) )
+      {
+         enum data_type semantic = DATATYPE_GET_SEMANTIC( _ui.fiddle.data_type ),
+                        single   = DATATYPE_GET_SINGLE( _ui.fiddle.data_type );
+         u32 count = DATATYPE_GET_COUNT( _ui.fiddle.data_type );
+         if( single == k_data_type_f32 )
+         {
+            f32 *f32s = _ui.fiddle.value;
+            if( count > 1 ) /* which it should be...? */
+            {
+               if( _ui_panel_button( &_ui.fiddle.panel, "Normalize", 0 ) == k_button_click )
+               {
+                  f32 total = 0.0f;
+                  for( u32 i=0; i<count; i ++ )
+                     total += f32s[i]*f32s[i];
+                  if( total < 0.00001f )
+                  {
+                     for( u32 i=0; i<count-1; i ++ )
+                        f32s[i] = 0.0f;
+                     f32s[count-1] = 1.0f;
+                  }
+                  else
+                     for( u32 i=0; i<count; i ++ )
+                        f32s[i] /= sqrtf(total);
+               }
+            }
+         }
+
+         enum button_action close_action = _ui_panel_button( &_ui.fiddle.panel, "DONE", 0 );
+         if( close_action == k_button_click )
+         {
+            $log( $low, {"Cancel fiddle"} ); 
+            _ui.fiddling = 0;
+         }
+      }
+   }
+   else if( _ui.fiddling > 0 )
    {
       i16 w = 300,
           h = 96,
@@ -719,7 +824,9 @@ void _ui_draw( i16 window_size[2] )
       if( _ui_panel_content( &_ui.fiddle.panel ) )
       {
          enum textbox_action text_action = 
-            _ui_panel_textbox( &_ui.fiddle.panel, _ui.fiddle.buf, sizeof(_ui.fiddle.buf), 1, UI_AUTOFOCUS, "value" );
+            _ui_panel_textbox( &_ui.fiddle.panel, _ui.fiddle.buf, sizeof(_ui.fiddle.buf), 1, 
+                               _ui.fiddling==2?UI_AUTOFOCUS: 0, "value" );
+         _ui.fiddling = 1;
 
          struct ui_panel cols[2];
          _ui_panel_grid( &_ui.fiddle.panel, cols, 1, 2, 1, UI_PADDING_PX, NULL );
@@ -775,8 +882,10 @@ void _ui_draw( i16 window_size[2] )
    }
 
    _ui.redraw = 0;
+#if 0
    _graphics_fill_rect( (i16[]){ _ui.mouse_co[0],_ui.mouse_co[1], 4,4 }, (union colour){{0,0,0,255}} );
    _graphics_fill_rect( (i16[]){ _ui.mouse_co[0],_ui.mouse_co[1], 3,3 }, (union colour){{255,255,255,255}} );
+#endif
 
    i16 padded_container[4],
        padded_container_click[4];
@@ -833,7 +942,8 @@ void _ui_panel_row( struct ui_panel *panel, i16 size, i16 padding, struct ui_pan
    out_row->flags = UI_FULL_HEIGHT;
    i16 kerning[3];
    _font_get_kerning( kerning );
-   rect_split( panel->content_area, UI_HORIZONTAL, kerning[1]*size + UI_PADDING_PX, 0, out_row->content_area, panel->content_area );
+   rect_split( panel->content_area, UI_HORIZONTAL, (kerning[1]+UI_PADDING_PX)*size, 0, 
+               out_row->content_area, panel->content_area );
 
    if( padding )
    {
@@ -842,7 +952,8 @@ void _ui_panel_row( struct ui_panel *panel, i16 size, i16 padding, struct ui_pan
    }
 }
 
-void _ui_panel_grid( struct ui_panel *panel, struct ui_panel *out_panels, i32 rows, i32 columns, i16 row_size, i16 padding, f32 *column_bias )
+void _ui_panel_grid( struct ui_panel *panel, struct ui_panel *out_panels, i32 rows, i32 columns, 
+                     i16 row_size, i16 padding, f32 *column_bias )
 {
    f32 column_total_bias = 0.0f;
    if( column_bias )
@@ -892,17 +1003,17 @@ enum button_action _ui_panel_button_internal( i16 rect[4], const c8 *text, u32 f
    if( !(flag & UI_DISABLED) )
       action = _ui_button( rect );
 
-   union colour c = (union colour){{200,200,200,255}};
-   union colour tc = (flag & UI_DULL)? (union colour){{140,140,140,255}}: (union colour){{20,20,20,255}};
+   union colour c = _ui_scheme[ k_ui_bg+2 ];
+   union colour tc = (flag & UI_DULL)? _ui_scheme[ k_ui_fg+4 ]: _ui_scheme[ k_ui_fg ];
 
    if( action == k_button_hover )
-      c = (union colour){{230,230,230,255}};
+      c = _ui_scheme[ k_ui_bg+3 ];
    else if( action != k_button_none )
-      c = (union colour){{255,255,255,255}};
+      c = _ui_scheme[ k_ui_bg+7 ];
    if( flag & UI_DISABLED )
    {
-      c = (union colour){{140,140,140,255}};
-      tc = (union colour){{160,160,160,255}};
+      c = _ui_scheme[ k_ui_bg+4 ];
+      tc = _ui_scheme[ k_ui_bg+5 ];
    }
 
    _graphics_fill_rect( rect, c );
@@ -919,14 +1030,14 @@ enum button_action _ui_panel_button_internal( i16 rect[4], const c8 *text, u32 f
 b8 _ui_panel_content( struct ui_panel *panel )
 {
    ASSERT_CRITICAL( panel->flags & UI_MAIN );
-   _graphics_fill_rect( panel->main.rect_base, (union colour){{50,50,50,160}} );
+   _graphics_fill_rect( panel->main.rect_base, _ui_scheme[ k_ui_bg+1 ] );
 
    i16 kerning[3];
    _font_get_kerning( kerning );
 
    i16 title_box[4] = { panel->main.rect_base[0], panel->main.rect_base[1], 
                         panel->main.rect_base[2], kerning[1] + UI_PADDING_PX };
-   _ui_text( title_box, panel->main.title, k_ui_align_center, (union colour){{255,255,255,255}} );
+   _ui_text( title_box, panel->main.title, k_ui_align_center, _ui_scheme[ k_ui_fg ] );
 
    b8 show = !panel->main.hidden;
    if( !(panel->flags & UI_NO_OPTIONS) )
@@ -1006,19 +1117,93 @@ void _ui_panel_number( struct ui_panel *panel, const c8 *label,
    i32 *maxs_i32 = maxs;
    i32 *start_i32s = (void *)_ui.controls.number.start_values;
 
-   struct ui_panel grid[6*16];
-   _ui_panel_grid( panel, grid, DATATYPE_GET_COUNT(data_type), 6, 1, 0, (f32[]){ 4.0f,0.5f,0.75f,2.0f,0.75f,0.75f } );
-
    i16 label_box[4];
-   _ui_panel_widget( &grid[0], label_box );
-   union colour tc = (flag & UI_DULL)? (union colour){{20,20,20,255}}: (union colour){{200,200,200,255}};
-   _ui_text( label_box, label, k_ui_align_y_center | k_ui_align_x_right, tc );
+   union colour tc = (flag & UI_DULL)? _ui_scheme[ k_ui_bg+3 ]: _ui_scheme[ k_ui_fg+3 ];
+
+   if( (DATATYPE_GET_SEMANTIC( data_type ) == k_data_semantic_transform) &&
+       (DATATYPE_GET_COUNT( data_type ) == 10) )
+   {
+      _ui_panel_widget( panel, label_box );
+      _ui_text( label_box, label, k_ui_align_center, tc );
+
+      struct ui_panel cols[3];
+      _ui_panel_grid( panel, cols, 1, 3, 5, UI_PADDING_PX/2, NULL );
+      _ui_panel_number( &cols[0], "CO", values_f32+0, mins_f32? mins_f32+0: NULL,
+                                                      maxs_f32? maxs_f32+0: NULL, k_data_type_vec3, UI_LABEL_ABOVE );
+      _ui_panel_number( &cols[1], "S",  values_f32+3, mins_f32? mins_f32+3: NULL,
+                                                      maxs_f32? maxs_f32+3: NULL, k_data_type_vec3, UI_LABEL_ABOVE );
+      _ui_panel_number( &cols[2], "Q",  values_f32+6, NULL, NULL, k_data_type_quat, UI_LABEL_ABOVE );
+      return;
+   }
+
+   struct ui_panel grid[3*16];
+   if( flag & UI_LABEL_ABOVE )
+   {
+      u32 panel_flag = panel->flags;
+      panel->flags &= ~(u32)UI_FULL_HEIGHT;
+      _ui_panel_widget( panel, label_box );
+      panel->flags = panel_flag;
+      _ui_panel_grid( panel, grid, DATATYPE_GET_COUNT(data_type), 3, 1, 0, (f32[]){ 0.4f,2.0f,0.4f } );
+      label_box[3] = grid[0].content_area[1] - label_box[1];
+   }
+   else
+   {
+      struct ui_panel cols[2];
+      _ui_panel_grid( panel, cols, 1, 2, DATATYPE_GET_COUNT(data_type), 0, (f32[]){2.0f,3.0f} );
+      rect_copy( cols[0].content_area, label_box );
+      _ui_panel_grid( &cols[1], grid, DATATYPE_GET_COUNT(data_type), 3, 1, 0, (f32[]){ 0.4f,2.0f,0.4f } );
+   }
+
+   enum data_type semantic = DATATYPE_GET_SEMANTIC( data_type );
+   if( semantic == k_data_semantic_vector ||
+       semantic == k_data_semantic_rotation ||
+       semantic == k_data_semantic_colour )
+   {
+      union colour cc = _ui_scheme[ k_ui_bg+2 ];
+      if( semantic == k_data_semantic_colour )
+      {
+         cc = (union colour){{0,0,0,255}};
+         for( u32 i=0; i<u32_min( 4, DATATYPE_GET_COUNT( data_type ) ); i ++ )
+            cc.channels[i] = f32_clamp( values_f32[i] * 255.0f, 0.0f, 255.0f );
+         if( DATATYPE_GET_COUNT( data_type ) == 4 )
+         {
+            _graphics_fill_rect( label_box, _ui_scheme[k_ui_gray] );
+            i16 tile[4] = {label_box[0],label_box[1],label_box[2]/2,label_box[3]/2};
+            _graphics_fill_rect( tile, _ui_scheme[k_ui_gray+k_ui_brighter] );
+            tile[0] = tile[0]+tile[2];
+            tile[1] = tile[1]+tile[3];
+            tile[2] = (label_box[0] + label_box[2]) - tile[0];
+            tile[3] = (label_box[1] + label_box[3]) - tile[1];
+            _graphics_fill_rect( tile, _ui_scheme[k_ui_gray+k_ui_brighter] );
+         }
+      }
+      _graphics_fill_rect( label_box, cc );
+
+      if( _ui_button( label_box ) == k_button_click_alt )
+      {
+         _ui.fiddling = 3;
+         _ui.fiddle.value = values;
+         _ui.fiddle.data_type = data_type;
+
+         if( flag & UI_LABEL_ABOVE )
+         {
+            _ui.fiddle.co[0] = label_box[0]+label_box[2];
+            _ui.fiddle.co[1] = label_box[1];
+         }
+         else
+         {
+            _ui.fiddle.co[0] = grid[2].content_area[0]+grid[2].content_area[2];
+            _ui.fiddle.co[1] = grid[2].content_area[1];
+         }
+      }
+   }
+
+   _ui_text( label_box, label, k_ui_align_center, tc );
 
    for( u32 i=0; i<DATATYPE_GET_COUNT(data_type); i ++ )
    {
-      struct ui_panel *buttons = grid + (i*6) + 2;
+      struct ui_panel *buttons = grid + (i*3);
       enum button_action down_a = _ui_panel_button( &buttons[0], "-", flag ),
-                         edit_a = _ui_panel_button( &buttons[3], "=", flag ),
                          up_a   = _ui_panel_button( &buttons[2], "+", flag );
       enum button_action main_a = _ui_button( buttons[1].content_area );
 
@@ -1082,14 +1267,21 @@ void _ui_panel_number( struct ui_panel *panel, const c8 *label,
       }
 
       _ui_panel_widget( &buttons[1], label_box );
-      _graphics_fill_rect( label_box, (union colour){{20,20,20,255}} );
+
+      union colour background = {{20,20,20,255}};
+      if( (DATATYPE_GET_SEMANTIC( data_type ) == k_data_semantic_vector) && (i < 3) )
+      {
+         background = ((union colour[]){_ui_scheme[k_ui_red],_ui_scheme[k_ui_green],_ui_scheme[k_ui_blue]})[ i ];
+      }
+
+      _graphics_fill_rect( label_box, background );
       _graphics_line_rect( label_box, (union colour){{60,60,60,255}} );
       _ui_text( label_box, buf, k_ui_align_center, tc );
 
-      if( edit_a == k_button_click )
+      if( main_a == k_button_click_alt )
       {
          buffer_copy( buf, 0, _ui.fiddle.buf, sizeof(_ui.fiddle.buf) );
-         _ui.fiddling = 1;
+         _ui.fiddling = 2;
          _ui.fiddle.value = values + DATATYPE_GET_WIDTH(data_type) * i;
          _ui.fiddle.data_type = single_type;
          _ui.fiddle.co[0] = buttons[2].content_area[0];
@@ -1107,7 +1299,7 @@ enum dropdown_action _ui_panel_enum( struct ui_panel *panel, const c8 *label, i3
    i16 label_box[4];
    _ui_panel_widget( &cols[0], label_box );
    
-   union colour tc = (flag & UI_DULL)? (union colour){{20,20,20,255}}: (union colour){{200,200,200,255}};
+   union colour tc = (flag & UI_DULL)? _ui_scheme[ k_ui_fg+4 ]: _ui_scheme[ k_ui_fg ];
    _ui_text( label_box, label, k_ui_align_y_center | k_ui_align_x_right, tc );
 
    i16 rect[4];
index 3c53591b01d2ecd21ba27e69596182b33c464235..3064a1ffce6851e9b59045be187793a9533cbc30 100644 (file)
@@ -119,6 +119,26 @@ b8 _ui_want_text(void);
 #define UI_MAIN         0x800
 #define UI_DISABLED     0x1000
 #define UI_NO_OPTIONS   0x2000
+#define UI_LABEL_ABOVE  0x4000
+#define UI_COLOUR_HDR   0x8000
+#define UI_COLOUR_HSV   0x10000
+
+enum ui_scheme_colour
+{
+   k_ui_bg      = 0,
+   k_ui_fg      = 8,
+   k_ui_hue     = 16,
+   k_ui_red     = 16,
+   k_ui_orange,
+   k_ui_yellow,
+   k_ui_green,
+   k_ui_aqua,
+   k_ui_blue,
+   k_ui_purple,
+   k_ui_gray,
+   k_ui_brighter = 8
+};
+extern union colour _ui_scheme[ 8*4 ];
 
 b8 _ui_update(void);
 void _ui_draw( i16 window_size[2] );
@@ -174,6 +194,7 @@ enum button_action
    k_button_click = 1,
    k_button_repeat = 2,
    k_button_hover  = 3,
+   k_button_click_alt = 4,
 };
 enum button_action _ui_button( i16 rect[4] );
 
index 8df1618f3b4ba0835156a88fffcda0a4809ef80b..d908532ea6a0b194e636ed5aad88282f20f8fe95 100644 (file)
@@ -15,7 +15,10 @@ typedef unsigned        char b8;
 #define DATATYPE_SIZE( COUNT, BYTES ) (0x0100*(COUNT-1) | 0x0020*(BYTES-1))
 #define DATATYPE_GET_WIDTH( DATA_TYPE ) (((DATA_TYPE & k_data_mask_width) >> 5)+1)
 #define DATATYPE_GET_COUNT( DATA_TYPE ) (((DATA_TYPE & k_data_mask_count) >> 8)+1)
-#define DATATYPE_GET_SINGLE( DATA_TYPE ) (data_type & (k_data_mask_format | k_data_mask_width))
+#define DATATYPE_GET_FORMAT( DATA_TYPE ) (DATA_TYPE & k_data_mask_format)
+#define DATATYPE_GET_SINGLE( DATA_TYPE ) (DATA_TYPE & (k_data_mask_format | k_data_mask_width))
+#define DATATYPE_GET_SEMANTIC( DATA_TYPE ) (DATA_TYPE & k_data_mask_semantic)
+
 enum data_type
 {
    k_data_mask_semantic = 0x001f, /* intended purpose      0 -> 31 (x1F) */
@@ -67,7 +70,9 @@ enum data_type
     /* vectors */
     k_data_type_vec2 = k_data_format_float | DATATYPE_SIZE( 2, 4 ) | k_data_semantic_vector,
     k_data_type_vec3 = k_data_format_float | DATATYPE_SIZE( 3, 4 ) | k_data_semantic_vector,
+    k_data_type_rgb  = k_data_format_float | DATATYPE_SIZE( 3, 4 ) | k_data_semantic_colour,
     k_data_type_vec4 = k_data_format_float | DATATYPE_SIZE( 4, 4 ) | k_data_semantic_vector,
+    k_data_type_rgba = k_data_format_float | DATATYPE_SIZE( 4, 4 ) | k_data_semantic_colour,
     k_data_type_quat = k_data_format_float | DATATYPE_SIZE( 4, 4 ) | k_data_semantic_rotation,
 
     /* CO|SCALE|QUAT */