level selector
authorhgn <hgodden00@gmail.com>
Sun, 5 Dec 2021 23:35:27 +0000 (23:35 +0000)
committerhgn <hgodden00@gmail.com>
Sun, 5 Dec 2021 23:35:27 +0000 (23:35 +0000)
fishladder.c
fishladder_resources.h
vg/vg.h
vg/vg_ui.h

index 7cda200bd7727d537cc849e214f27d7c3c3e5ec1..76e09a20dcac919fdadbb0fda5010fd6ce0f758c 100644 (file)
@@ -2240,98 +2240,115 @@ void vg_render(void)
                
        use_mesh( &world.numbers );
        draw_numbers( (v3f){ 2.0f, (float)world.h-1.875f, 0.3333f }, world.score );
-               
-       // Level selection UI
-       use_mesh( &world.circle );
-       float ratio = ((float)vg_window_x/(float)vg_window_y);
-       
-       m3x3f ui_view = M3X3_IDENTITY;
-       m3x3_scale( ui_view, (v3f){ 1.0f, ratio, 1.0f } );
-       glUniformMatrix3fv( SHADER_UNIFORM( shader_tile_colour, "uPv" ), 1, GL_FALSE, (float *)ui_view );
+}
 
-       // Calculate mouse in UIsp
-       v3f mouse_ui_space = { ((float)vg_mouse[0] / (float)(vg_window_x)) * 2.0f - 1.0f,
-                                                                 (((float)vg_mouse[1] / (float)(vg_window_y)) * 2.0f - 1.0f)*(-1.0f/ratio), 0.0125f };
+static ui_colourset flcol_list_a = {
+       .main = 0xff877979,
+       .hover = 0xffa09393,
+       .active = 0xffbfb1b0
+};
+static ui_colourset flcol_list_b = {
+       .main = 0xff7c6e6e,
+       .hover = 0xffa09393,
+       .active = 0xffbfb1b0
+};
 
-       // Get selected level
-       const float selection_scale = 0.05f;
-       int const level_count = vg_list_size( level_pack_1 );
-       int level_select = -1;
-       
-       if( mouse_ui_space[0] <= -0.8f )
-       {
-               float levels_range = (float)level_count*selection_scale*0.6f;
-               float level_offset = ((-mouse_ui_space[1] + levels_range) / levels_range) * 0.5f * (float)level_count;
-               level_select = ceilf( level_offset );
+static ui_colourset flcol_list_complete_a = {
+       .main = 0xff62a064,
+       .hover = 0xff8dc18f,
+       .active = 0xffb2ddb3
+};
 
-               // Draw selector
-               if( level_select >= 0 && level_select < vg_list_size( level_pack_1 ) )
-               {
-                       glUniform4f( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 0.369768f, 0.3654f, 0.42f, 1.0f );
-                       
-                       use_mesh( &world.tile );
-                       glUniform3f( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), 
-                               -1.0f, 
-                               ((float)level_count - (float)level_select * 2.0f ) * selection_scale * 0.6f,
-                               selection_scale
-                       );
-                       draw_mesh( 2, 2 );
-                       
-                       use_mesh( &world.circle );
-                       
-                       if( vg_get_button_down( "primary" ) )
-                       {
-                               console_changelevel( 1, level_pack_1 + level_select );
-                       }
-               }
-       }
-       else mouse_ui_space[1] = INFINITY;
+static ui_colourset flcol_list_complete_b = {
+       .main = 0xff79b37b,
+       .hover = 0xff8dc18f,
+       .active = 0xffb2ddb3
+};
+
+static ui_colourset flcol_list_locked = {
+       .main = 0xff655959,
+       .hover = 0xff655959,
+       .active = 0xff655959
+};
 
-       glUniform4f( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 0.4f, 0.39f, 0.45f, 1.0f );
 
-       // Draw levels
-       for( int i = 0; i < level_count; i ++ )
-       {
-               struct career_level *clevel = &career.levels[i];
        
-               v3f level_ui_space = { 
-                       -0.97f, 
-                       ((float)level_count - (float)i * 2.0f ) * selection_scale * 0.6f + selection_scale * 0.5f,
-                       selection_scale * 0.5f
-               };
-               
-               float scale = vg_clampf( 1.0f - fabsf(level_ui_space[1] - mouse_ui_space[1]) * 2.0f, 0.9f, 1.0f );
-               level_ui_space[2] *= scale;
+static void draw_levels_list( struct cmp_level *levels, int count, int unlocked )
+{
+       static struct ui_scrollbar sb = {
+               .bar_height = 400
+       };
+       
+       ui_px view_height = ui_global_ctx.cursor[3];
+       ui_px level_height = 50;
+
+       // Level scroll view
+       gui_new_node();
+       {
+               gui_fill_rect( ui_global_ctx.cursor, 0xff5a4e4d );
+               gui_set_clip( ui_global_ctx.cursor );
                
-               glUniform3fv( SHADER_UNIFORM( shader_tile_colour, "uOffset" ), 1, level_ui_space );
+               ui_global_ctx.cursor[2] = 14;
+               gui_align_right();
                
-               if( clevel->completed )
-                       draw_mesh( filled_start, filled_count );
+               ui_px content_height = count*level_height;
+               if( content_height > view_height )
+               {
+                       ui_scrollbar( &ui_global_ctx, &sb, 1 );
+                       ui_global_ctx.cursor[1] -= ui_calculate_content_scroll( &sb, content_height );
+               }
                else
-                       draw_mesh( empty_start, empty_count );
-       }
-       
-       // Level scores
-       glUniform4f( SHADER_UNIFORM( shader_tile_colour, "uColour" ), 0.4f*1.25f, 0.39f*1.25f, 0.45f*1.25f, 1.0f );
-       
-       use_mesh( &world.numbers );
-       for( int i = 0; i < level_count; i ++ )
-       {
-               struct career_level *clevel = &career.levels[i];
-       
-               v3f level_ui_space = { 
-                       -0.94f, 
-                       ((float)level_count - (float)i * 2.0f ) * selection_scale * 0.6f + selection_scale * 0.5f,
-                       0.02f
-               };
+               {
+                       gui_fill_rect( ui_global_ctx.cursor, 0xff807373 );
+               }
+               
+               ui_global_ctx.cursor[2] = 240;
+               ui_global_ctx.cursor[3] = level_height;
+               gui_align_left();
+               
+               for( int i = 0; i < count; i ++ )
+               {
+                       struct cmp_level *lvl_info = &levels[i];
                
-               if( clevel->completed )
-                       draw_numbers( level_ui_space, clevel->score );
+                       if( i < unlocked )
+                       {
+                               if( lvl_info->completed_score != 0 )
+                                       gui_override_colours( i&0x1? &flcol_list_complete_a: &flcol_list_complete_b );
+                               else
+                                       gui_override_colours( i&0x1? &flcol_list_a: &flcol_list_b );
+                       }
+                       else
+                               gui_override_colours( &flcol_list_locked );
+                       
+                       if( i < unlocked )
+                       {
+                               if( gui_button( 2 + i ) == k_button_click )
+                               {
+                                       console_changelevel( 1, &lvl_info->map_name );
+                               }
+                       
+                               ui_global_ctx.override_colour = 0xffffffff;
+                               gui_text( lvl_info->title, 3, 0 );
+                               ui_global_ctx.cursor[1] += 18;
+                               gui_text( "incomplete", 2, 0 );
+                       }
+                       else
+                       {
+                               gui_button( 2 + i );
+                               
+                               ui_global_ctx.override_colour = 0xff786f6f;
+                               gui_text( "???", 3, 0 );
+                               ui_global_ctx.cursor[1] += 18;
+                               gui_text( "locked", 2, 0 );
+                       }
                        
-               level_ui_space[0] = -0.975f;
-               level_ui_space[1] -= 0.01f;
-               draw_numbers( level_ui_space, i );
+                       gui_end_down();
+               }
+               
+               gui_reset_colours();            
+               gui_release_clip();
        }
+       gui_end_down();
 }
 
 void vg_ui(void)
@@ -2344,51 +2361,66 @@ void vg_ui(void)
        
        ui_global_ctx.id_base = 4 << 16;
        
+       static int pack_selection = 0;
+       static struct pack_info
+       {
+               struct cmp_level *levels;
+               u32 level_count;
+               const char *name;
+       }
+       pack_infos[] = 
+       {
+               {
+                       .levels = cmp_levels_tutorials,
+                       .level_count = vg_list_size(cmp_levels_tutorials),
+                       .name = "Training"
+               },
+               {
+                       .levels = cmp_levels_basic,
+                       .level_count = vg_list_size(cmp_levels_basic),
+                       .name = "Main"
+               },
+               {
+                       .levels = cmp_levels_grad,
+                       .level_count = vg_list_size(cmp_levels_tutorials),
+                       .name = "Expert"
+               }
+       };
+       
        gui_new_node();
        {
                gui_fill_rect( ui_global_ctx.cursor, 0xff5577ff );
                
-               gui_text( "MARBLE COMPUTING", 4, 0 );
+               gui_text( "ASSIGNMENTS", 4, 0 );
                
-               ui_global_ctx.cursor[1] += 45;
-               ui_global_ctx.cursor[3] = 709;
+               ui_global_ctx.cursor[1] += 30;
+               ui_global_ctx.cursor[3] = 25;
                
-               // Level scroll view
                gui_new_node();
                {
-                       gui_fill_rect( ui_global_ctx.cursor, 0xffff7729 );
-                       gui_set_clip( ui_global_ctx.cursor );
-                       
-                       ui_global_ctx.cursor[2] = 16;
-                       gui_align_right();
-                       
-                       static struct ui_scrollbar sb = {
-                               .bar_height = 400
-                       };
-                       ui_scrollbar( &ui_global_ctx, &sb, 0 );
-                       
-                       ui_global_ctx.cursor[2] = 240;
-                       ui_global_ctx.cursor[3] = 50;
-                       gui_align_left();
-                       
-                       ui_px content_height = vg_list_size(cmp_levels_basic)*ui_global_ctx.cursor[3];
-                       ui_global_ctx.cursor[1] -= ui_calculate_content_scroll( &sb, content_height );
+                       ui_rect_pad( ui_global_ctx.cursor, 2 );
+                       ui_global_ctx.cursor[2] = 84;
                        
-                       for( int i = 0; i < vg_list_size(cmp_levels_basic); i ++ )
+                       for( int i = 0; i < 3; i ++ )
                        {
-                               struct cmp_level *lvl_info = &cmp_levels_basic[i];
-                       
-                               gui_new_node();
-                               {
-                                       gui_fill_rect( ui_global_ctx.cursor, i&0x1?0xff23fce45:0xff8722f8 );
-                                       gui_text( lvl_info->title, 3, 0 );
-                               }
-                               gui_end_down();
-                       }
-                       
-                       gui_release_clip();
+                               if( i == pack_selection )
+                                       gui_override_colours( &flcol_list_locked );
+
+                               if( gui_button( 2000 + i ) == k_button_click )
+                                       pack_selection = i;
+                               
+                               ui_global_ctx.cursor[1] += 2;
+                               gui_text( pack_infos[i].name, 2, 0 );
+                               gui_end_right();
+                               
+                               gui_reset_colours();
+                       } 
                }
                gui_end_down();
+               
+               ui_global_ctx.cursor[3] = 500;
+               
+               draw_levels_list( pack_infos[ pack_selection ].levels, pack_infos[ pack_selection ].level_count, 3 );
        }
        gui_end();
 }
index da8b8ea2052b31275b22735697b7924168351468..f3b15ca8578b375b164ec58aa18b45a8735c2f74 100644 (file)
@@ -90,12 +90,27 @@ sfx_system audio_system_balls_extra =
        .name = "Balls Extra"
 };
 
+ui_colourset ui_fl_colours = {
+       .main = 0xff807373,
+       .hover = 0xff918484,
+       .active = 0xffad9f9e
+};
+
+ui_colourset ui_fl_colours_inactive = {
+       .main = 0xff655958,
+       .hover = 0xff655958,
+       .active = 0xff655958
+};
+
 static void resource_load_main(void)
 {
        // Textures
        vg_tex2d_init( texture_list, vg_list_size( texture_list ) );
        
        ui_override_font( tex_monofur.name, 7 );
+
+       ui_global_ctx.colours_main = &ui_fl_colours;
+       gui_reset_colours();
        
        // Audio
        sfx_set_init( &audio_tile_mod, NULL );
@@ -550,6 +565,11 @@ struct cmp_level
        const char *title;
        const char *description;
        
+       int completed_score;
+       
+       int unlocks;                    // When completed, unlock this many levels
+       int linked_unlocks;     // When unlocked, unlock this many levels additionally
+       
        int serial_id;
 };
 
@@ -560,28 +580,32 @@ struct cmp_level cmp_levels_tutorials[] =
                .map_name = "cmp_t01",
                .description = "Utilize basic transport methods",
                
-               .serial_id = 0
+               .serial_id = 0,
+               .unlocks = 1
        },
        {
                .title = "PRINCIPLE 2",
                .map_name = "cmp_t02",
                .description = "Utilize the twisty turny(TM) piece",
                
-               .serial_id = 1
+               .serial_id = 1,
+               .unlocks = 1
        },
        {
                .title = "PRINCIPLE 3",
                .map_name = "cmp_t03",
                .description = "Merge transport into one",
                
-               .serial_id = 2
+               .serial_id = 2,
+               .unlocks = 1,
        },
        {
                .title = "PRINCIPLE 4",
                .map_name = "cmp_t04",
                .description = "Some stages require multiple runs to succeed in order to pass",
                
-               .serial_id = 12
+               .serial_id = 12,
+               .unlocks = 3
        }
 };
 
@@ -592,63 +616,72 @@ struct cmp_level cmp_levels_basic[] =
                .map_name = "cmp_b01",
                .description = "Simple maths, branching required.",
                
-               .serial_id = 3
+               .serial_id = 3,
+               .unlocks = 1
        },
        {
                .title = "SUBDIVISION 2",
                .map_name = "cmp_b02",
                .description = "Simple maths. Futher.",
 
-               .serial_id = 4
+               .serial_id = 4,
+               .unlocks = 1
        },
        {
                .title = "RESTRUCTURE",
                .map_name = "cmp_b03",
                .description = "Not so simple swap",
                
-               .serial_id = 5
+               .serial_id = 5,
+               .unlocks = 1
        },
        {
                .title = "SERIALIZE",
                .map_name = "cmp_b04",
                .description = "Merge and sort",
                
-               .serial_id = 6
+               .serial_id = 6,
+               .unlocks = 1
        },
        {
                .title = "PATTERNS 1",
                .map_name = "cmp_b05",
                .description = "Replicate",
                
-               .serial_id = 7
+               .serial_id = 7,
+               .unlocks = 1
        },
        {
                .title = "PATTERNS 2",
                .map_name = "cmp_b06",
                .description = "Replicate MORE",
                
-               .serial_id = 8
+               .serial_id = 8,
+               .unlocks = 1
        },
        {
                .title = "MIGHTY CONSUMER",
                .map_name = "cmp_b07",
                .description = "Build a greedy system",
                
-               .serial_id = 9
+               .serial_id = 9,
+               .unlocks = 1
        },
        {
                .title = "ENCRYPTED 1",
                .map_name = "cmp_b08",
                .description = "Some configurations may not be valid",
 
-               .serial_id = 10
+               .serial_id = 10,
+               .unlocks = 1
        },
        {
                .title = "REVERSE",
                .map_name = "cmp_b09",
                .description = "Reverse the incoming order. Always length 4",
                
-               .serial_id = 11
+               .serial_id = 11,
+               .unlocks = 1
        },
        {
                .title = "PRINCIPLE 5",
@@ -661,7 +694,8 @@ struct cmp_level cmp_levels_basic[] =
                        "as part of your training package, you will now be\n"
                        "tasked to complete them",
 
-               .serial_id = 15
+               .serial_id = 15,
+               .linked_unlocks = 1
        },
        {
                .title = "ROUTING PROBLEM",
@@ -671,7 +705,8 @@ struct cmp_level cmp_levels_basic[] =
                        "Do your best to utilize principle 5 to get the job\n"
                        "done.",
                
-               .serial_id = 16
+               .serial_id = 16,
+               .unlocks = 1
        },
        {
                .title = "PRINCIPLE 6",
@@ -695,7 +730,8 @@ struct cmp_level cmp_levels_basic[] =
                        "time, this results in no operation being performed,\n"
                        "and no state changes take place in the Twisty Turny(TM)\n",
 
-                       .serial_id = 17
+                       .serial_id = 17,
+                       .linked_unlocks = 1
        },
        {
                .title = "NOT GATE",
@@ -704,7 +740,8 @@ struct cmp_level cmp_levels_basic[] =
                        "Test your knowledge of triggers, build an 'NOT GATE'\n"
                        "emulated by marble logic.",
                
-               .serial_id = 18
+               .serial_id = 18,
+               .unlocks = 1
        },
        {
                .title = "AND GATE",
@@ -713,7 +750,8 @@ struct cmp_level cmp_levels_basic[] =
                        "A slightly more complicated gate, but shouldn't be\n"
                        "too difficult for your skillset.",
                
-               .serial_id = 19
+               .serial_id = 19,
+               .unlocks = 1
        },
        {
                .title = "QUALIFICATION PROJECT",
@@ -721,7 +759,8 @@ struct cmp_level cmp_levels_basic[] =
                .description =
                        "There's no instructions here, resolve and complete this\n"
                        "task to qualify yourself as an official marble engineer",
-               .serial_id = 20
+               .serial_id = 20,
+               .unlocks = 3
        }
 };
 
@@ -741,7 +780,7 @@ struct cmp_level cmp_levels_grad[] =
                .title = "THIRDS",
                .map_name = "cmp_i02",
                .description = 
-                       "Spit your inputs up into a third of its value\n"
+                       "Split the inputs up into a third of their values\n"
                        "Is this possible? -HG",
                
                .serial_id = 14
@@ -764,3 +803,12 @@ struct cmp_level cmp_levels_grad[] =
                .serial_id = 22
        }
 };
+
+struct
+{
+       int total_unlocked;
+}
+career_local = 
+{
+       .total_unlocked = 1
+};
diff --git a/vg/vg.h b/vg/vg.h
index cdcf431555158d07289fcd75577550e3a7b2c504..ba392bb99adba028461ce7278a6775880a1c9632 100644 (file)
--- a/vg/vg.h
+++ b/vg/vg.h
@@ -35,8 +35,8 @@ m3x3f vg_pv;
 
 // Engine globals
 GLFWwindow* vg_window;
-int vg_window_x = 1280;
-int vg_window_y = 720;
+int vg_window_x = 1366;
+int vg_window_y = 768;
 
 v2f vg_mouse;
 v3f vg_mouse_ws;
@@ -150,6 +150,7 @@ static void vg_init( int argc, char *argv[], const char *window_name )
        glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 );
        glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
        glfwWindowHint( GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE );
+       glfwWindowHint( GLFW_RESIZABLE, GLFW_FALSE );
        
        glfwWindowHint( GLFW_SAMPLES, 4 );
        
index 35a3e3b8df9294a8ab30aac94f4d2d41a33bbb72..fe46da0040a8bcd795f9628134d3519d78807b63 100644 (file)
@@ -55,6 +55,26 @@ typedef i16                          ui_px;
 typedef u32                            ui_colour;
 typedef ui_px                          ui_rect[4];
 typedef struct ui_ctx  ui_ctx;
+typedef struct ui_colourset ui_colourset;
+
+struct ui_colourset
+{
+       union
+       {
+               struct
+               {
+                       ui_colour main;
+                       ui_colour hover;
+                       ui_colour active;
+               };
+               struct
+               {
+                       ui_colour background;
+                       ui_colour bar;
+                       ui_colour bar_hover;
+               };
+       };
+};
 
 struct ui_ctx
 {
@@ -96,6 +116,9 @@ struct ui_ctx
        // User input
        ui_px mouse[2];
        int click_state;        // 0: released, 1: on down, 2: pressed, 3: on release
+       
+       ui_colourset *colours_main;
+       ui_colourset *colours_current;
 };
 
 // Shortnames
@@ -105,7 +128,7 @@ struct ui_ctx
 #define gui_hasmouse(...) ui_hasmouse( &ui_global_ctx, __VA_ARGS__)
 #define gui_end() ui_end( &ui_global_ctx )
 #define gui_end_down() ui_end_down( &ui_global_ctx )
-#define gui_end_right() ui_fill_right( &ui_global_ctx )
+#define gui_end_right() ui_end_right( &ui_global_ctx )
 #define gui_fill_y() ui_fill_y( &ui_global_ctx)
 #define gui_fill_x() ui_fill_x( &ui_global_ctx)
 #define gui_align_bottom() ui_align_bottom( &ui_global_ctx )
@@ -127,6 +150,10 @@ struct ui_ctx
 #define gui_window(...) ui_window( &ui_global_ctx, __VA_ARGS__)
 #define gui_want_mouse() ui_want_mouse( &ui_global_ctx )
 
+#define gui_scrollbar(...) ui_scrollbar( &ui_global_ctx, __VA_ARGS__)
+#define gui_override_colours(...) ui_override_colours( &ui_global_ctx, __VA_ARGS__)
+#define gui_reset_colours(...) ui_reset_colours( &ui_global_ctx )
+
 // Globals
 // ===========================================================================================================
 
@@ -141,7 +168,16 @@ GLuint ui_ebo;
 #define UI_BUFFER_SIZE 30000
 #define UI_INDEX_SIZE 20000
 
-ui_ctx ui_global_ctx = { .padding = 8 };
+ui_colourset ui_default_colours = {
+       .main = 0xff00ff00,
+       .hover = 0xffff00ff,
+       .active = 0xffff0000
+};
+ui_ctx ui_global_ctx = { 
+       .padding = 8, 
+       .colours_current = &ui_default_colours, 
+       .colours_main = &ui_default_colours 
+};
 
 
 // Initialization
@@ -678,7 +714,7 @@ static int ui_button( ui_ctx *ctx, u32 id )
                
                if( ui_hasmouse(ctx) )
                {
-                       ui_fill_rect( ctx, ctx->cursor, 0xffcccccc );
+                       ui_fill_rect( ctx, ctx->cursor, ctx->colours_current->hover );
                        
                        if( ctx->click_state == 1 )
                        {
@@ -691,7 +727,7 @@ static int ui_button( ui_ctx *ctx, u32 id )
                                return k_button_hold;
                }
                else
-                       ui_fill_rect( ctx, ctx->cursor, 0xff999999 );
+                       ui_fill_rect( ctx, ctx->cursor, ctx->colours_current->main );
        }
        
        return k_button_released;
@@ -796,8 +832,8 @@ static void ui_scrollbar( ui_ctx *ctx, struct ui_scrollbar *scrollbar, u32 id )
        
        ui_new_node( ctx );
        {
-               ui_fill_rect( ctx, ctx->cursor, 0xff000000 );
-               ui_capture_mouse( ctx, __COUNTER__ );
+               ui_fill_rect( ctx, ctx->cursor, ctx->colours_current->background );
+               ui_capture_mouse( ctx, id );
                
                ctx->cursor[1] += scrollbar->py;
                ctx->cursor[3] = scrollbar->bar_height;
@@ -805,14 +841,14 @@ static void ui_scrollbar( ui_ctx *ctx, struct ui_scrollbar *scrollbar, u32 id )
                ui_new_node( ctx );
                {
                        ui_capture_mouse( ctx, __COUNTER__ );
-                       struct ui_vert *drag_bar = ui_fill_rect( ctx, ctx->cursor, 0xff555555 );
+                       struct ui_vert *drag_bar = ui_fill_rect( ctx, ctx->cursor, ctx->colours_current->bar );
 
                        if( ui_hasmouse( ctx ) || scrollbar->drag )
                        {
-                               drag_bar[0].colour = 0xff777777;
-                               drag_bar[1].colour = 0xff777777;
-                               drag_bar[2].colour = 0xff777777;
-                               drag_bar[3].colour = 0xff777777;
+                               drag_bar[0].colour = ctx->colours_current->bar_hover;
+                               drag_bar[1].colour = ctx->colours_current->bar_hover;
+                               drag_bar[2].colour = ctx->colours_current->bar_hover;
+                               drag_bar[3].colour = ctx->colours_current->bar_hover;
                        
                                // start drag
                                if( ctx->click_state == 1 )
@@ -834,3 +870,14 @@ static ui_px ui_calculate_content_scroll( struct ui_scrollbar *scrollbar, ui_px
        float range = scrollbar->view_height - scrollbar->bar_height;
        return ((float)scrollbar->py / range) * overlap;
 }
+
+static void ui_override_colours( ui_ctx *ctx, ui_colourset *set )
+{
+       ctx->colours_current = set;
+}
+
+static void ui_reset_colours( ui_ctx *ctx )
+{
+       ctx->colours_current = ctx->colours_main;
+       ctx->override_colour = 0xffffffff;
+}