2016-02-20 21:36:16 +00:00
|
|
|
/*
|
|
|
|
* Mr. 4th Dimention - Allen Webster
|
|
|
|
*
|
|
|
|
* 19.08.2015
|
|
|
|
*
|
|
|
|
* Panel layout and general view functions for 4coder
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
// TOP
|
|
|
|
|
|
|
|
struct Panel_Divider{
|
2016-03-01 03:57:55 +00:00
|
|
|
Panel_Divider *next;
|
2016-02-20 21:36:16 +00:00
|
|
|
i32 parent;
|
|
|
|
i32 which_child;
|
|
|
|
i32 child1, child2;
|
2016-03-01 03:57:55 +00:00
|
|
|
b32 v_divider;
|
2016-02-20 21:36:16 +00:00
|
|
|
i32 pos;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Screen_Region{
|
|
|
|
i32_Rect full;
|
|
|
|
i32_Rect inner;
|
|
|
|
i32_Rect prev_inner;
|
|
|
|
i32 l_margin, r_margin;
|
|
|
|
i32 t_margin, b_margin;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Panel{
|
2016-03-02 16:18:10 +00:00
|
|
|
Panel *next;
|
|
|
|
Panel *prev;
|
|
|
|
|
|
|
|
struct View *view;
|
2016-02-20 21:36:16 +00:00
|
|
|
i32 parent;
|
|
|
|
i32 which_child;
|
2016-03-02 16:18:10 +00:00
|
|
|
|
|
|
|
int ALLOCED;
|
|
|
|
|
2016-02-20 21:36:16 +00:00
|
|
|
union{
|
|
|
|
struct{
|
|
|
|
i32_Rect full;
|
|
|
|
i32_Rect inner;
|
|
|
|
i32_Rect prev_inner;
|
|
|
|
i32 l_margin, r_margin;
|
|
|
|
i32 t_margin, b_margin;
|
|
|
|
};
|
|
|
|
Screen_Region screen_region;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Editing_Layout{
|
|
|
|
Panel *panels;
|
2016-03-02 16:18:10 +00:00
|
|
|
Panel free_sentinel;
|
|
|
|
Panel used_sentinel;
|
2016-02-20 21:36:16 +00:00
|
|
|
Panel_Divider *dividers;
|
|
|
|
Panel_Divider *free_divider;
|
|
|
|
i32 panel_count, panel_max_count;
|
|
|
|
i32 root;
|
|
|
|
i32 active_panel;
|
|
|
|
i32 full_width, full_height;
|
|
|
|
};
|
|
|
|
|
2016-03-02 16:18:10 +00:00
|
|
|
struct Divider_And_ID{
|
|
|
|
Panel_Divider* divider;
|
|
|
|
i32 id;
|
|
|
|
};
|
2016-02-20 21:36:16 +00:00
|
|
|
|
2016-03-02 16:18:10 +00:00
|
|
|
struct Panel_And_ID{
|
|
|
|
Panel* panel;
|
|
|
|
i32 id;
|
|
|
|
};
|
2016-02-20 21:36:16 +00:00
|
|
|
|
|
|
|
internal void
|
|
|
|
panel_init(Panel *panel){
|
2016-03-02 16:18:10 +00:00
|
|
|
panel->view = 0;
|
2016-02-20 21:36:16 +00:00
|
|
|
panel->parent = -1;
|
2016-03-02 16:18:10 +00:00
|
|
|
panel->which_child = 0;
|
|
|
|
panel->screen_region.full = {};
|
|
|
|
panel->screen_region.inner = {};
|
|
|
|
panel->screen_region.prev_inner = {};
|
2016-02-20 21:36:16 +00:00
|
|
|
panel->l_margin = 3;
|
|
|
|
panel->r_margin = 3;
|
|
|
|
panel->t_margin = 3;
|
|
|
|
panel->b_margin = 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal Divider_And_ID
|
|
|
|
layout_alloc_divider(Editing_Layout *layout){
|
|
|
|
Divider_And_ID result;
|
2016-03-01 03:57:55 +00:00
|
|
|
|
|
|
|
Assert(layout->free_divider);
|
2016-02-20 21:36:16 +00:00
|
|
|
result.divider = layout->free_divider;
|
2016-03-01 03:57:55 +00:00
|
|
|
layout->free_divider = result.divider->next;
|
|
|
|
|
2016-02-20 21:36:16 +00:00
|
|
|
*result.divider = {};
|
|
|
|
result.divider->parent = -1;
|
|
|
|
result.divider->child1 = -1;
|
|
|
|
result.divider->child2 = -1;
|
|
|
|
result.id = (i32)(result.divider - layout->dividers);
|
|
|
|
if (layout->panel_count == 1){
|
|
|
|
layout->root = result.id;
|
|
|
|
}
|
2016-03-01 03:57:55 +00:00
|
|
|
|
|
|
|
return(result);
|
2016-02-20 21:36:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
internal Divider_And_ID
|
|
|
|
layout_get_divider(Editing_Layout *layout, i32 id){
|
|
|
|
Divider_And_ID result;
|
2016-03-02 16:18:10 +00:00
|
|
|
|
|
|
|
Assert(id >= 0 && id < layout->panel_max_count-1);
|
2016-02-20 21:36:16 +00:00
|
|
|
result.id = id;
|
|
|
|
result.divider = layout->dividers + id;
|
2016-03-02 16:18:10 +00:00
|
|
|
|
|
|
|
return(result);
|
2016-02-20 21:36:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
|
|
|
layout_free_divider(Editing_Layout *layout, Panel_Divider *divider){
|
2016-03-01 03:57:55 +00:00
|
|
|
divider->next = layout->free_divider;
|
2016-02-20 21:36:16 +00:00
|
|
|
layout->free_divider = divider;
|
|
|
|
}
|
|
|
|
|
2016-03-02 16:18:10 +00:00
|
|
|
internal Panel_And_ID
|
|
|
|
layout_alloc_panel(Editing_Layout *layout){
|
|
|
|
Panel_And_ID result = {};
|
|
|
|
|
|
|
|
Assert(layout->panel_count < layout->panel_max_count);
|
|
|
|
++layout->panel_count;
|
|
|
|
|
|
|
|
result.panel = layout->free_sentinel.next;
|
|
|
|
dll_remove(result.panel);
|
|
|
|
dll_insert(&layout->used_sentinel, result.panel);
|
|
|
|
|
|
|
|
panel_init(result.panel);
|
|
|
|
|
|
|
|
result.id = (i32)(result.panel - layout->panels);
|
|
|
|
|
|
|
|
result.panel->ALLOCED = 1;
|
|
|
|
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
2016-02-20 21:36:16 +00:00
|
|
|
internal void
|
|
|
|
layout_free_panel(Editing_Layout *layout, Panel *panel){
|
2016-03-02 16:18:10 +00:00
|
|
|
dll_remove(panel);
|
|
|
|
dll_insert(&layout->free_sentinel, panel);
|
|
|
|
--layout->panel_count;
|
2016-03-01 03:57:55 +00:00
|
|
|
|
2016-03-02 16:18:10 +00:00
|
|
|
panel->ALLOCED = 0;
|
2016-02-20 21:36:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
internal Divider_And_ID
|
|
|
|
layout_calc_divider_id(Editing_Layout *layout, Panel_Divider *divider){
|
|
|
|
Divider_And_ID result;
|
|
|
|
result.divider = divider;
|
|
|
|
result.id = (i32)(divider - layout->dividers);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Split_Result{
|
|
|
|
Panel_Divider *divider;
|
|
|
|
Panel *panel;
|
|
|
|
};
|
|
|
|
|
|
|
|
internal Split_Result
|
2016-03-01 03:57:55 +00:00
|
|
|
layout_split_panel(Editing_Layout *layout, Panel *panel, b32 vertical){
|
|
|
|
Split_Result result = {};
|
|
|
|
Divider_And_ID div = {}, parent_div = {};
|
2016-03-02 16:18:10 +00:00
|
|
|
Panel_And_ID new_panel = {};
|
2016-03-01 03:57:55 +00:00
|
|
|
|
|
|
|
div = layout_alloc_divider(layout);
|
2016-02-20 21:36:16 +00:00
|
|
|
if (panel->parent != -1){
|
2016-03-01 03:57:55 +00:00
|
|
|
parent_div = layout_get_divider(layout, panel->parent);
|
2016-02-20 21:36:16 +00:00
|
|
|
if (panel->which_child == -1){
|
2016-03-01 03:57:55 +00:00
|
|
|
parent_div.divider->child1 = div.id;
|
2016-02-20 21:36:16 +00:00
|
|
|
}
|
|
|
|
else{
|
2016-03-01 03:57:55 +00:00
|
|
|
parent_div.divider->child2 = div.id;
|
2016-02-20 21:36:16 +00:00
|
|
|
}
|
|
|
|
}
|
2016-03-01 03:57:55 +00:00
|
|
|
|
2016-02-20 21:36:16 +00:00
|
|
|
div.divider->parent = panel->parent;
|
|
|
|
div.divider->which_child = panel->which_child;
|
|
|
|
if (vertical){
|
|
|
|
div.divider->v_divider = 1;
|
|
|
|
div.divider->pos = (panel->full.x0 + panel->full.x1) / 2;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
div.divider->v_divider = 0;
|
|
|
|
div.divider->pos = (panel->full.y0 + panel->full.y1) / 2;
|
|
|
|
}
|
|
|
|
|
2016-03-01 03:57:55 +00:00
|
|
|
new_panel = layout_alloc_panel(layout);
|
2016-02-20 21:36:16 +00:00
|
|
|
panel->parent = div.id;
|
|
|
|
panel->which_child = -1;
|
2016-03-02 16:18:10 +00:00
|
|
|
new_panel.panel->parent = div.id;
|
|
|
|
new_panel.panel->which_child = 1;
|
2016-02-20 21:36:16 +00:00
|
|
|
|
|
|
|
result.divider = div.divider;
|
2016-03-02 16:18:10 +00:00
|
|
|
result.panel = new_panel.panel;
|
|
|
|
|
2016-02-20 21:36:16 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
|
|
|
panel_fix_internal_area(Panel *panel){
|
2016-03-02 16:18:10 +00:00
|
|
|
panel->inner.x0 = panel->full.x0 + panel->l_margin;
|
|
|
|
panel->inner.x1 = panel->full.x1 - panel->r_margin;
|
|
|
|
panel->inner.y0 = panel->full.y0 + panel->t_margin;
|
|
|
|
panel->inner.y1 = panel->full.y1 - panel->b_margin;
|
2016-02-20 21:36:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
|
|
|
layout_fix_all_panels(Editing_Layout *layout){
|
2016-03-02 16:18:10 +00:00
|
|
|
Panel *panel;
|
|
|
|
Panel_Divider *dividers = layout->dividers;
|
|
|
|
i32 panel_count = layout->panel_count;
|
|
|
|
i32_Rect r;
|
|
|
|
i32 pos, which_child, action;
|
|
|
|
Divider_And_ID div;
|
|
|
|
|
|
|
|
if (panel_count > 1){
|
|
|
|
for (panel = layout->used_sentinel.next;
|
|
|
|
panel != &layout->used_sentinel;
|
|
|
|
panel = panel->next){
|
|
|
|
|
|
|
|
r.x0 = 0;
|
|
|
|
r.x1 = r.x0 + layout->full_width;
|
|
|
|
r.y0 = 0;
|
|
|
|
r.y1 = r.y0 + layout->full_height;
|
|
|
|
|
|
|
|
which_child = panel->which_child;
|
|
|
|
|
2016-02-20 21:36:16 +00:00
|
|
|
div.id = panel->parent;
|
2016-03-02 16:18:10 +00:00
|
|
|
|
2016-02-20 21:36:16 +00:00
|
|
|
for (;;){
|
2016-03-02 16:18:10 +00:00
|
|
|
Assert(div.id != -1);
|
2016-02-20 21:36:16 +00:00
|
|
|
div.divider = dividers + div.id;
|
|
|
|
pos = div.divider->pos;
|
2016-03-02 16:18:10 +00:00
|
|
|
|
|
|
|
action = (div.divider->v_divider << 1) | (which_child > 0);
|
2016-02-20 21:36:16 +00:00
|
|
|
switch (action){
|
|
|
|
case 0: // v_divider : 0, which_child : -1
|
2016-03-02 16:18:10 +00:00
|
|
|
if (pos < r.y1) r.y1 = pos;
|
2016-02-20 21:36:16 +00:00
|
|
|
break;
|
|
|
|
case 1: // v_divider : 0, which_child : 1
|
2016-03-02 16:18:10 +00:00
|
|
|
if (pos > r.y0) r.y0 = pos;
|
2016-02-20 21:36:16 +00:00
|
|
|
break;
|
|
|
|
case 2: // v_divider : 1, which_child : -1
|
2016-03-02 16:18:10 +00:00
|
|
|
if (pos < r.x1) r.x1 = pos;
|
2016-02-20 21:36:16 +00:00
|
|
|
break;
|
|
|
|
case 3: // v_divider : 1, which_child : 1
|
2016-03-02 16:18:10 +00:00
|
|
|
if (pos > r.x0) r.x0 = pos;
|
2016-02-20 21:36:16 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-03-02 16:18:10 +00:00
|
|
|
|
2016-02-20 21:36:16 +00:00
|
|
|
if (div.id != layout->root){
|
|
|
|
div.id = div.divider->parent;
|
|
|
|
which_child = div.divider->which_child;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-03-02 16:18:10 +00:00
|
|
|
|
|
|
|
panel->full = r;
|
2016-02-20 21:36:16 +00:00
|
|
|
panel_fix_internal_area(panel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else{
|
2016-03-02 16:18:10 +00:00
|
|
|
panel = layout->used_sentinel.next;
|
|
|
|
panel->full.x0 = 0;
|
|
|
|
panel->full.y0 = 0;
|
|
|
|
panel->full.x1 = layout->full_width;
|
|
|
|
panel->full.y1 = layout->full_height;
|
|
|
|
panel_fix_internal_area(panel);
|
2016-02-20 21:36:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
2016-03-01 03:57:55 +00:00
|
|
|
layout_refit(Editing_Layout *layout, i32 prev_width, i32 prev_height){
|
|
|
|
|
2016-02-20 21:36:16 +00:00
|
|
|
Panel_Divider *dividers = layout->dividers;
|
2016-03-01 03:57:55 +00:00
|
|
|
i32 max = layout->panel_max_count - 1;
|
|
|
|
|
|
|
|
f32 h_ratio, v_ratio;
|
2016-02-20 21:36:16 +00:00
|
|
|
|
2016-03-01 03:57:55 +00:00
|
|
|
Panel_Divider *divider = dividers;
|
|
|
|
i32 i;
|
2016-02-20 21:36:16 +00:00
|
|
|
|
2016-03-01 03:57:55 +00:00
|
|
|
if (layout->panel_count > 1){
|
|
|
|
Assert(prev_width != 0 && prev_height != 0);
|
2016-02-20 21:36:16 +00:00
|
|
|
|
2016-03-01 03:57:55 +00:00
|
|
|
h_ratio = ((f32)layout->full_width) / prev_width;
|
|
|
|
v_ratio = ((f32)layout->full_height) / prev_height;
|
|
|
|
|
|
|
|
for (i = 0; i < max; ++i, ++divider){
|
|
|
|
if (divider->v_divider){
|
|
|
|
divider->pos = ROUND32((divider->pos) * h_ratio);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
divider->pos = ROUND32((divider->pos) * v_ratio);
|
|
|
|
}
|
2016-02-20 21:36:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
layout_fix_all_panels(layout);
|
|
|
|
}
|
|
|
|
|
2016-03-02 16:18:10 +00:00
|
|
|
enum View_Message{
|
|
|
|
VMSG_STEP,
|
|
|
|
VMSG_DRAW,
|
|
|
|
VMSG_RESIZE,
|
|
|
|
VMSG_STYLE_CHANGE,
|
|
|
|
VMSG_FREE
|
|
|
|
};
|
|
|
|
|
|
|
|
struct View;
|
|
|
|
#define Do_View_Sig(name) \
|
|
|
|
i32 (name)(System_Functions *system, Exchange *exchange, \
|
|
|
|
View *view, i32_Rect rect, View *active, \
|
|
|
|
View_Message message, Render_Target *target, \
|
|
|
|
Input_Summary *user_input, Input_Summary *active_input)
|
|
|
|
|
|
|
|
typedef Do_View_Sig(Do_View_Function);
|
|
|
|
|
|
|
|
struct View{
|
|
|
|
View *next, *prev;
|
|
|
|
|
|
|
|
Panel *panel;
|
|
|
|
Command_Map *map;
|
|
|
|
Do_View_Function *do_view;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Live_Views{
|
|
|
|
void *views;
|
|
|
|
View free_sentinel;
|
|
|
|
i32 count, max;
|
|
|
|
i32 stride;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct View_And_ID{
|
|
|
|
View *view;
|
|
|
|
i32 id;
|
|
|
|
};
|
|
|
|
|
|
|
|
internal View*
|
|
|
|
live_set_get_view(Live_Views *live_set, i32 id){
|
|
|
|
void *result = ((char*)live_set->views + id);
|
|
|
|
return (View*)result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal View_And_ID
|
|
|
|
live_set_alloc_view(Live_Views *live_set, Mem_Options *mem){
|
|
|
|
View_And_ID result = {};
|
|
|
|
|
|
|
|
Assert(live_set->count < live_set->max);
|
|
|
|
++live_set->count;
|
|
|
|
|
|
|
|
result.view = live_set->free_sentinel.next;
|
|
|
|
result.id = (i32)((char*)result.view - (char*)live_set->views);
|
|
|
|
|
|
|
|
dll_remove(result.view);
|
|
|
|
memset(result.view, 0, live_set->stride);
|
|
|
|
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
live_set_free_view(System_Functions *system, Exchange *exchange, Live_Views *live_set, View *view){
|
|
|
|
Assert(live_set->count > 0);
|
|
|
|
--live_set->count;
|
|
|
|
view->do_view(system, exchange, view, {}, 0, VMSG_FREE, 0, {}, 0);
|
|
|
|
dll_insert(&live_set->free_sentinel, view);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
view_set_first(View *new_view, Panel *panel){
|
|
|
|
new_view->panel = panel;
|
|
|
|
panel->view = new_view;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline f32
|
2016-02-20 21:36:16 +00:00
|
|
|
view_base_compute_width(View *view){
|
|
|
|
Panel *panel = view->panel;
|
2016-03-02 16:18:10 +00:00
|
|
|
return (f32)(panel->inner.x1 - panel->inner.x0);
|
2016-02-20 21:36:16 +00:00
|
|
|
}
|
|
|
|
|
2016-03-02 16:18:10 +00:00
|
|
|
inline f32
|
2016-02-20 21:36:16 +00:00
|
|
|
view_base_compute_height(View *view){
|
|
|
|
Panel *panel = view->panel;
|
2016-03-02 16:18:10 +00:00
|
|
|
return (f32)(panel->inner.y1 - panel->inner.y0);
|
2016-02-20 21:36:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define view_compute_width(view) (view_base_compute_width(&(view)->view_base))
|
|
|
|
#define view_compute_height(view) (view_base_compute_height(&(view)->view_base))
|
|
|
|
|
2016-03-02 16:18:10 +00:00
|
|
|
struct Interactive_Style{
|
|
|
|
u32 bar_color;
|
|
|
|
u32 bar_active_color;
|
|
|
|
u32 base_color;
|
|
|
|
u32 pop1_color;
|
|
|
|
u32 pop2_color;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Interactive_Bar{
|
|
|
|
Interactive_Style style;
|
|
|
|
f32 pos_x, pos_y;
|
|
|
|
f32 text_shift_x, text_shift_y;
|
|
|
|
i32_Rect rect;
|
|
|
|
i16 font_id;
|
|
|
|
};
|
|
|
|
|
|
|
|
internal void
|
|
|
|
intbar_draw_string(Render_Target *target,
|
|
|
|
Interactive_Bar *bar, u8 *str, u32 char_color){
|
|
|
|
i16 font_id = bar->font_id;
|
|
|
|
|
|
|
|
draw_string(target, font_id, (char*)str,
|
|
|
|
(i32)(bar->pos_x + bar->text_shift_x),
|
|
|
|
(i32)(bar->pos_y + bar->text_shift_y),
|
|
|
|
char_color);
|
|
|
|
bar->pos_x += font_string_width(target, font_id, (char*)str);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
|
|
|
intbar_draw_string(Render_Target *target, Interactive_Bar *bar,
|
|
|
|
String str, u32 char_color){
|
|
|
|
i16 font_id = bar->font_id;
|
|
|
|
|
|
|
|
draw_string(target, font_id, str,
|
|
|
|
(i32)(bar->pos_x + bar->text_shift_x),
|
|
|
|
(i32)(bar->pos_y + bar->text_shift_y),
|
|
|
|
char_color);
|
|
|
|
bar->pos_x += font_string_width(target, font_id, str);
|
|
|
|
}
|
|
|
|
|
2016-02-20 21:36:16 +00:00
|
|
|
// BOTTOM
|
|
|
|
|