1801 lines
61 KiB
C++
1801 lines
61 KiB
C++
/*
|
|
* Mr. 4th Dimention - Allen Webster
|
|
*
|
|
* 20.08.2015
|
|
*
|
|
* Color customizing view for 4coder
|
|
*
|
|
*/
|
|
|
|
// TOP
|
|
|
|
enum Color_View_Mode{
|
|
CV_MODE_LIBRARY,
|
|
CV_MODE_IMPORT_FILE,
|
|
CV_MODE_EXPORT_FILE,
|
|
CV_MODE_IMPORT,
|
|
CV_MODE_EXPORT,
|
|
CV_MODE_ADJUSTING
|
|
};
|
|
|
|
struct Super_Color{
|
|
Vec4 hsla;
|
|
Vec4 rgba;
|
|
u32 *out;
|
|
};
|
|
|
|
internal Super_Color
|
|
super_color_create(u32 packed){
|
|
Super_Color result = {};
|
|
result.rgba = unpack_color4(packed);
|
|
result.hsla = rgba_to_hsla(result.rgba);
|
|
return result;
|
|
}
|
|
|
|
internal void
|
|
super_color_post_hsla(Super_Color *color, Vec4 hsla){
|
|
color->hsla = hsla;
|
|
if (hsla.h == 1.f)
|
|
hsla.h = 0.f;
|
|
color->rgba = hsla_to_rgba(hsla);
|
|
*color->out = pack_color4(color->rgba);
|
|
}
|
|
|
|
internal void
|
|
super_color_post_rgba(Super_Color *color, Vec4 rgba){
|
|
color->rgba = rgba;
|
|
color->hsla = rgba_to_hsla(rgba);
|
|
*color->out = pack_color4(rgba);
|
|
}
|
|
|
|
internal void
|
|
super_color_post_packed(Super_Color *color, u32 packed){
|
|
color->rgba = unpack_color4(packed);
|
|
color->hsla = rgba_to_hsla(color->rgba);
|
|
*color->out = packed;
|
|
}
|
|
|
|
u32 super_color_clear_masks[] = {0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00};
|
|
u32 super_color_shifts[] = {16, 8, 0};
|
|
|
|
internal u32
|
|
super_color_post_byte(Super_Color *color, i32 channel, u8 byte){
|
|
u32 packed = *color->out;
|
|
packed &= super_color_clear_masks[channel];
|
|
packed |= (byte << super_color_shifts[channel]);
|
|
super_color_post_packed(color, packed);
|
|
return packed;
|
|
}
|
|
|
|
struct Color_Highlight{
|
|
i32 ids[4];
|
|
};
|
|
|
|
struct Library_UI{
|
|
UI_State state;
|
|
UI_Layout layout;
|
|
|
|
Font_Set *fonts;
|
|
|
|
Style_Library *styles;
|
|
Hot_Directory *hot_directory;
|
|
};
|
|
|
|
struct Color_UI{
|
|
UI_State state;
|
|
UI_Layout layout;
|
|
|
|
Font_Set *fonts;
|
|
|
|
real32 hex_advance;
|
|
u32 *palette;
|
|
i32 palette_size;
|
|
|
|
Color_Highlight highlight;
|
|
Super_Color color;
|
|
|
|
bool32 has_hover_color;
|
|
Super_Color hover_color;
|
|
};
|
|
|
|
struct Color_View{
|
|
View view_base;
|
|
Hot_Directory *hot_directory;
|
|
Style *main_style;
|
|
Style_Library *styles;
|
|
File_View *hot_file_view;
|
|
Font_Set *fonts;
|
|
u32 *palette;
|
|
Working_Set *working_set;
|
|
i32 palette_size;
|
|
Color_View_Mode mode;
|
|
UI_State state;
|
|
Super_Color color;
|
|
Color_Highlight highlight;
|
|
bool32 p4c_only;
|
|
Style_Library inspecting_styles;
|
|
bool8 import_export_check[64];
|
|
};
|
|
|
|
inline Color_View*
|
|
view_to_color_view(View *view){
|
|
Assert(!view || view->type == VIEW_TYPE_COLOR);
|
|
return (Color_View*)view;
|
|
}
|
|
|
|
internal void
|
|
draw_gradient_slider(Render_Target *target, Vec4 base, i32 channel,
|
|
i32 steps, real32 top, real32_Rect slider, bool32 hsla){
|
|
Vec4 low, high;
|
|
real32 *lowv, *highv;
|
|
real32 x;
|
|
real32 next_x;
|
|
real32 x_step;
|
|
real32 v_step;
|
|
real32 m;
|
|
|
|
x = (real32)slider.x0;
|
|
x_step = (real32)(slider.x1 - slider.x0) / steps;
|
|
v_step = top / steps;
|
|
m = 1.f / top;
|
|
lowv = &low.v[channel];
|
|
highv = &high.v[channel];
|
|
|
|
if (hsla){
|
|
for (i32 i = 0; i < steps; ++i){
|
|
low = high = base;
|
|
*lowv = (i * v_step);
|
|
*highv = *lowv + v_step;
|
|
*lowv *= m;
|
|
*highv *= m;
|
|
low = hsla_to_rgba(low);
|
|
high = hsla_to_rgba(high);
|
|
|
|
next_x = x + x_step;
|
|
draw_gradient_2corner_clipped(
|
|
target, x, slider.y0, next_x, slider.y1,
|
|
low, high);
|
|
x = next_x;
|
|
}
|
|
}
|
|
else{
|
|
for (i32 i = 0; i < steps; ++i){
|
|
low = high = base;
|
|
*lowv = (i * v_step);
|
|
*highv = *lowv + v_step;
|
|
*lowv *= m;
|
|
*highv *= m;
|
|
|
|
next_x = x + x_step;
|
|
draw_gradient_2corner_clipped(
|
|
target, x, slider.y0, next_x, slider.y1,
|
|
low, high);
|
|
x = next_x;
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void
|
|
draw_hsl_slider(Render_Target *target, Vec4 base, i32 channel, i32 steps, real32 top,
|
|
real32_Rect slider){
|
|
draw_gradient_slider(target, base, channel, steps, top, slider, 1);
|
|
}
|
|
|
|
inline void
|
|
draw_rgb_slider(Render_Target *target, Vec4 base, i32 channel, i32 steps, real32 top,
|
|
real32_Rect slider){
|
|
draw_gradient_slider(target, base, channel, steps, top, slider, 0);
|
|
}
|
|
|
|
internal void
|
|
do_label(UI_State *state, UI_Layout *layout, char *text, real32 height = 2.f){
|
|
Style *style = state->style;
|
|
Font *font = style->font;
|
|
i32_Rect label = layout_rect(layout, FLOOR32(font->height * height));
|
|
|
|
if (!state->input_stage){
|
|
Render_Target *target = state->target;
|
|
u32 back = style->main.margin_color;
|
|
u32 fore = style->main.default_color;
|
|
draw_rectangle(target, label, back);
|
|
i32 height = label.y1 - label.y0;
|
|
draw_string(target, font, text, label.x0,
|
|
label.y0 + (height - font->height)/2, fore);
|
|
}
|
|
}
|
|
|
|
internal void
|
|
do_scroll_bar(UI_State *state, i32_Rect rect){
|
|
i32 id = 1;
|
|
i32 w = (rect.x1 - rect.x0);
|
|
i32 h = (rect.y1 - rect.y0);
|
|
|
|
i32_Rect top_arrow, bottom_arrow;
|
|
top_arrow.x0 = rect.x0;
|
|
top_arrow.x1 = rect.x1;
|
|
top_arrow.y0 = rect.y0;
|
|
top_arrow.y1 = top_arrow.y0 + w;
|
|
|
|
bottom_arrow.x0 = rect.x0;
|
|
bottom_arrow.x1 = rect.x1;
|
|
bottom_arrow.y1 = rect.y1;
|
|
bottom_arrow.y0 = bottom_arrow.y1 - w;
|
|
|
|
real32 space_h = (real32)(bottom_arrow.y0 - top_arrow.y1);
|
|
if (space_h <= w) return;
|
|
|
|
i32 slider_h = w;
|
|
|
|
real32 view_hmin = 0;
|
|
real32 view_hmax = state->height - h;
|
|
real32 L = unlerp(view_hmin, state->view_y, view_hmax);
|
|
|
|
real32 slider_hmin = (real32)top_arrow.y1;
|
|
real32 slider_hmax = (real32)bottom_arrow.y0 - slider_h;
|
|
real32 S = lerp(slider_hmin, L, slider_hmax);
|
|
|
|
i32_Rect slider;
|
|
slider.x0 = rect.x0;
|
|
slider.x1 = rect.x1;
|
|
slider.y0 = FLOOR32(S);
|
|
slider.y1 = slider.y0 + slider_h;
|
|
|
|
Widget_ID wid = make_id(state, id);
|
|
|
|
if (state->input_stage){
|
|
state->view_y =
|
|
ui_do_vscroll_input(state, top_arrow, bottom_arrow, slider,
|
|
wid, state->view_y, (real32)state->font->height,
|
|
slider_hmin, slider_hmax, view_hmin, view_hmax);
|
|
}
|
|
else{
|
|
Render_Target *target = state->target;
|
|
real32 x0, y0, x1, y1, x2, y2;
|
|
real32 w_1_2 = w*.5f;
|
|
real32 w_1_3 = w*.333333f;
|
|
real32 w_2_3 = w*.666667f;
|
|
|
|
|
|
UI_Style ui_style = get_ui_style(state->style);
|
|
u32 outline, back, fore;
|
|
|
|
outline = ui_style.bright;
|
|
|
|
wid.sub_id2 = 0;
|
|
|
|
x0 = (w_1_2 + top_arrow.x0);
|
|
x1 = (w_1_3 + top_arrow.x0);
|
|
x2 = (w_2_3 + top_arrow.x0);
|
|
|
|
++wid.sub_id2;
|
|
y0 = (w_1_3 + top_arrow.y0);
|
|
y1 = (w_2_3 + top_arrow.y0);
|
|
y2 = (w_2_3 + top_arrow.y0);
|
|
get_colors(state, &back, &fore, wid, ui_style);
|
|
draw_rectangle(target, top_arrow, back);
|
|
draw_rectangle_outline(target, top_arrow, outline);
|
|
draw_triangle_3corner(target, x0, y0, x1, y1, x2, y2, fore);
|
|
|
|
++wid.sub_id2;
|
|
y0 = (w_2_3 + bottom_arrow.y0);
|
|
y1 = (w_1_3 + bottom_arrow.y0);
|
|
y2 = (w_1_3 + bottom_arrow.y0);
|
|
get_colors(state, &back, &fore, wid, ui_style);
|
|
draw_rectangle(target, bottom_arrow, back);
|
|
draw_rectangle_outline(target, bottom_arrow, outline);
|
|
draw_triangle_3corner(target, x0, y0, x1, y1, x2, y2, fore);
|
|
|
|
++wid.sub_id2;
|
|
get_colors(state, &back, &fore, wid, ui_style);
|
|
draw_rectangle(target, slider, back);
|
|
draw_rectangle_outline(target, slider, outline);
|
|
|
|
draw_rectangle_outline(target, rect, outline);
|
|
}
|
|
}
|
|
|
|
internal void
|
|
do_single_slider(i32 sub_id, Color_UI *ui, i32 channel, bool32 is_rgba,
|
|
i32 grad_steps, real32 top, real32_Rect slider, real32 v_handle,
|
|
i32_Rect rect){
|
|
real32_Rect click_box = slider;
|
|
click_box.y0 -= v_handle;
|
|
|
|
if (ui->state.input_stage){
|
|
real32 v;
|
|
if (ui_do_slider_input(&ui->state, i32R(click_box), make_sub1(&ui->state, sub_id),
|
|
slider.x0, slider.x1, &v)){
|
|
Vec4 new_color;
|
|
if (is_rgba) new_color = ui->color.rgba;
|
|
else new_color = ui->color.hsla;
|
|
new_color.v[channel] = clamp(0.f, v, 1.f);
|
|
if (is_rgba) super_color_post_rgba(&ui->color, new_color);
|
|
else super_color_post_hsla(&ui->color, new_color);
|
|
}
|
|
}
|
|
else{
|
|
Render_Target *target = ui->state.target;
|
|
Vec4 color;
|
|
real32 x;
|
|
if (is_rgba){
|
|
color = ui->color.rgba;
|
|
draw_rgb_slider(target, V4(0,0,0,1.f), channel, 10, 100.f, slider);
|
|
}
|
|
else{
|
|
i32 steps;
|
|
real32 top;
|
|
if (channel == 0){
|
|
steps = 45;
|
|
top = 360.f;
|
|
}
|
|
else{
|
|
steps = 10;
|
|
top = 100.f;
|
|
}
|
|
color = ui->color.hsla;
|
|
draw_hsl_slider(target, color, channel, steps, top, slider);
|
|
}
|
|
|
|
x = lerp(slider.x0, color.v[channel], slider.x1);
|
|
draw_rectangle(
|
|
target, f32R(x, slider.y0, x + 1, slider.y1), 0xff000000);
|
|
|
|
draw_rectangle(
|
|
target, f32R(x-2, click_box.y0, x+3, slider.y0-4), 0xff777777);
|
|
}
|
|
}
|
|
|
|
internal void
|
|
do_hsl_sliders(Color_UI *ui, i32_Rect rect){
|
|
real32 bar_width = (real32)(rect.x1 - rect.x0 - 20);
|
|
if (bar_width > 45){
|
|
real32_Rect slider;
|
|
real32 y;
|
|
i32 sub_id;
|
|
|
|
real32 v_full_space = 30.f;
|
|
real32 v_half_space = 15.f;
|
|
real32 v_quarter_space = 12.f;
|
|
real32 v_handle = 9.f;
|
|
|
|
slider.x0 = rect.x0 + 10.f;
|
|
slider.x1 = slider.x0 + bar_width;
|
|
|
|
sub_id = 0;
|
|
|
|
i32 step_count[] = {45, 10, 10};
|
|
real32 tops[] = {360.f, 100.f, 100.f};
|
|
|
|
y = rect.y0 + v_quarter_space;
|
|
for (i32 i = 0; i < 3; ++i){
|
|
++sub_id;
|
|
slider.y0 = y;
|
|
slider.y1 = slider.y0 + v_half_space;
|
|
do_single_slider(sub_id, ui, i, 0, step_count[i], tops[i], slider, v_handle, rect);
|
|
y += v_full_space;
|
|
}
|
|
}
|
|
}
|
|
|
|
enum Channel_Field_Type{
|
|
CF_DEC,
|
|
CF_HEX
|
|
};
|
|
|
|
internal void
|
|
fill_buffer_color_channel(char *buffer, u8 x, Channel_Field_Type ftype){
|
|
if (ftype == CF_DEC){
|
|
u8 x0;
|
|
x0 = x / 10;
|
|
buffer[2] = (x - (10*x0)) + '0';
|
|
x = x0;
|
|
x0 = x / 10;
|
|
buffer[1] = (x - (10*x0)) + '0';
|
|
x = x0;
|
|
x0 = x / 10;
|
|
buffer[0] = (x - (10*x0)) + '0';
|
|
}
|
|
else{
|
|
u8 n;
|
|
n = x & 0xF;
|
|
buffer[1] = int_to_hexchar(n);
|
|
x >>= 4;
|
|
n = x & 0xF;
|
|
buffer[0] = int_to_hexchar(n);
|
|
}
|
|
}
|
|
|
|
internal bool32
|
|
do_channel_field(i32 sub_id, Color_UI *ui, u8 *channel, Channel_Field_Type ftype,
|
|
i32 y, u32 color, u32 back, i32 x0, i32 x1){
|
|
bool32 result = 0;
|
|
Render_Target *target = ui->state.target;
|
|
Font *font = ui->state.font;
|
|
|
|
i32_Rect hit_region;
|
|
hit_region.x0 = x0;
|
|
hit_region.x1 = x1;
|
|
hit_region.y0 = y;
|
|
hit_region.y1 = y + font->height;
|
|
|
|
i32 digit_count;
|
|
if (ftype == CF_DEC) digit_count = 3;
|
|
else digit_count = 2;
|
|
|
|
if (ui->state.input_stage){
|
|
i32 indx;
|
|
ui_do_subdivided_button_input(&ui->state, hit_region, digit_count,
|
|
make_sub1(&ui->state, sub_id), 1, &indx);
|
|
}
|
|
else{
|
|
if (ui->state.hover.sub_id1 == sub_id && ui->state.selected.sub_id1 != sub_id){
|
|
draw_rectangle(target, hit_region, back);
|
|
}
|
|
}
|
|
|
|
char string_buffer[4];
|
|
string_buffer[digit_count] = 0;
|
|
fill_buffer_color_channel(string_buffer, *channel, ftype);
|
|
|
|
if (ui->state.selected.sub_id1 == sub_id){
|
|
i32 indx = ui->state.selected.sub_id2;
|
|
if (ui->state.input_stage){
|
|
Key_Summary *keys = ui->state.keys;
|
|
Key_Codes *codes = ui->state.codes;
|
|
for (i32 key_i = 0; key_i < keys->count; ++key_i){
|
|
Key_Single key = get_single_key(keys, key_i);
|
|
|
|
if (key.key.keycode == codes->right){
|
|
++indx;
|
|
if (indx > digit_count-1) indx = 0;
|
|
}
|
|
if (key.key.keycode == codes->left){
|
|
--indx;
|
|
if (indx < 0) indx = digit_count-1;
|
|
}
|
|
|
|
i32 new_value = *channel;
|
|
if (key.key.keycode == codes->up || key.key.keycode == codes->down){
|
|
i32 place = digit_count-1-indx;
|
|
i32 base = (ftype == CF_DEC)?10:0x10;
|
|
i32 step_amount = 1;
|
|
while (place > 0){
|
|
step_amount *= base;
|
|
--place;
|
|
}
|
|
if (key.key.keycode == codes->down){
|
|
step_amount = 0 - step_amount;
|
|
}
|
|
new_value += step_amount;
|
|
}
|
|
|
|
u8 c = (u8)key.key.character;
|
|
bool32 is_good = (ftype == CF_DEC)?char_is_numeric(c):char_is_hex(c);
|
|
if (is_good){
|
|
string_buffer[indx] = c;
|
|
if (ftype == CF_DEC)
|
|
new_value = str_to_int(make_string(string_buffer, 3));
|
|
else
|
|
new_value = hexstr_to_int(make_string(string_buffer, 2));
|
|
++indx;
|
|
if (indx > digit_count-1) indx = 0;
|
|
}
|
|
|
|
if (c == '\n'){
|
|
switch (sub_id){
|
|
case 1: case 2:
|
|
case 4: case 5:
|
|
ui->state.sub_id1_change = sub_id + 3; break;
|
|
|
|
case 7: case 8:
|
|
ui->state.sub_id1_change = sub_id - 6; break;
|
|
}
|
|
}
|
|
|
|
if (new_value != *channel){
|
|
if (new_value > 255){
|
|
*channel = 255;
|
|
}
|
|
else if (new_value < 0){
|
|
*channel = 0;
|
|
}
|
|
else{
|
|
*channel = (u8)new_value;
|
|
}
|
|
fill_buffer_color_channel(string_buffer, *channel, ftype);
|
|
result = 1;
|
|
}
|
|
ui->state.selected.sub_id2 = indx;
|
|
}
|
|
}
|
|
else{
|
|
real32_Rect r = f32R(hit_region);
|
|
r.x0 += indx*ui->hex_advance+1;
|
|
r.x1 = r.x0+ui->hex_advance+1;
|
|
draw_rectangle(target, r, back);
|
|
}
|
|
}
|
|
|
|
if (!ui->state.input_stage)
|
|
draw_string_mono(target, font, string_buffer,
|
|
(real32)x0 + 1, (real32)y, ui->hex_advance,
|
|
color);
|
|
|
|
return result;
|
|
}
|
|
|
|
internal void
|
|
do_rgb_sliders(Color_UI *ui, i32_Rect rect){
|
|
i32 dec_x0, dec_x1;
|
|
dec_x0 = rect.x0 + 10;
|
|
dec_x1 = TRUNC32(dec_x0 + ui->hex_advance*3 + 2);
|
|
|
|
i32 hex_x0, hex_x1;
|
|
hex_x0 = dec_x1 + 10;
|
|
hex_x1 = TRUNC32(hex_x0 + ui->hex_advance*2 + 2);
|
|
|
|
rect.x0 = hex_x1;
|
|
real32 bar_width = (real32)(rect.x1 - rect.x0 - 20);
|
|
|
|
real32_Rect slider;
|
|
real32 y;
|
|
i32 sub_id;
|
|
u8 channel;
|
|
|
|
real32 v_full_space = 30.f;
|
|
real32 v_half_space = 15.f;
|
|
real32 v_quarter_space = 12.f;
|
|
real32 v_handle = 9.f;
|
|
|
|
u32 packed_color = *ui->color.out;
|
|
|
|
y = rect.y0 + v_quarter_space;
|
|
slider.x0 = rect.x0 + 10.f;
|
|
slider.x1 = slider.x0 + bar_width;
|
|
|
|
sub_id = 0;
|
|
|
|
persist i32 shifts[3] = { 16, 8, 0 };
|
|
persist u32 fore_colors[3] = { 0xFFFF0000, 0xFF00FF00, 0xFF1919FF };
|
|
persist u32 back_colors[3] = { 0xFF222222, 0xFF222222, 0xFF131313 };
|
|
|
|
for (i32 i = 0; i < 3; ++i){
|
|
i32 shift = shifts[i];
|
|
u32 fore = fore_colors[i];
|
|
u32 back = back_colors[i];
|
|
|
|
++sub_id;
|
|
channel = (packed_color >> shift) & 0xFF;
|
|
if (do_channel_field(sub_id, ui, &channel, CF_DEC,
|
|
(i32)y, fore, back, dec_x0, dec_x1))
|
|
super_color_post_byte(&ui->color, i, channel);
|
|
|
|
++sub_id;
|
|
channel = (packed_color >> shift) & 0xFF;
|
|
if (do_channel_field(sub_id, ui, &channel, CF_HEX,
|
|
(i32)y, fore, back, hex_x0, hex_x1))
|
|
super_color_post_byte(&ui->color, i, channel);
|
|
|
|
++sub_id;
|
|
slider.y0 = y;
|
|
slider.y1 = slider.y0 + v_half_space;
|
|
if (bar_width > 45.f)
|
|
do_single_slider(sub_id, ui, i, 1, 10, 100.f, slider, v_handle, rect);
|
|
y += v_full_space;
|
|
}
|
|
}
|
|
|
|
struct Blob_Layout{
|
|
i32_Rect rect;
|
|
i32 x, y;
|
|
i32 size, space;
|
|
};
|
|
|
|
internal void
|
|
begin_layout(Blob_Layout *layout, i32_Rect rect){
|
|
layout->rect = rect;
|
|
layout->x = rect.x0 + 10;
|
|
layout->y = rect.y0;
|
|
layout->size = 20;
|
|
layout->space = 5;
|
|
}
|
|
|
|
internal void
|
|
do_blob(Color_UI *ui, Blob_Layout *layout, u32 color, bool32 *set_me, i32 sub_id){
|
|
i32_Rect rect = layout->rect;
|
|
real32_Rect blob;
|
|
blob.x0 = (real32)layout->x;
|
|
blob.y0 = (real32)layout->y;
|
|
blob.x1 = blob.x0 + layout->size;
|
|
blob.y1 = blob.y0 + layout->size;
|
|
|
|
layout->y += layout->size + layout->space;
|
|
if (layout->y + layout->size + layout->space*2 > rect.y1){
|
|
layout->y = rect.y0;
|
|
layout->x += layout->size + layout->space;
|
|
}
|
|
|
|
if (ui->state.input_stage){
|
|
bool32 right = 0;
|
|
if (ui_do_button_input(&ui->state, i32R(blob), make_sub1(&ui->state, sub_id), 0, &right)){
|
|
super_color_post_packed(&ui->color, color);
|
|
}
|
|
else if (right) *set_me = 1;
|
|
}
|
|
else{
|
|
Render_Target *target = ui->state.target;
|
|
draw_rectangle(target, blob, color);
|
|
persist u32 silver = 0xFFa0a0a0;
|
|
draw_rectangle_outline(target, blob, silver);
|
|
}
|
|
}
|
|
|
|
inline void
|
|
do_blob(Color_UI *ui, Blob_Layout *layout, u32 *color, bool32 *set_me){
|
|
i32 sub_id = (i32)((char*)color - (char*)ui->state.style);
|
|
do_blob(ui, layout, *color, set_me, sub_id);
|
|
}
|
|
|
|
internal void
|
|
do_v_divide(Color_UI *ui, Blob_Layout *layout, i32 width){
|
|
i32_Rect rect = layout->rect;
|
|
if (layout->y > rect.y0){
|
|
layout->x += layout->size + layout->space;
|
|
}
|
|
layout->x += width;
|
|
layout->y = rect.y0;
|
|
}
|
|
|
|
internal void
|
|
do_palette(Color_UI *ui, i32_Rect rect){
|
|
Style *style = ui->state.style;
|
|
Blob_Layout layout;
|
|
begin_layout(&layout, rect);
|
|
bool32 set_me;
|
|
|
|
do_blob(ui, &layout, &style->main.back_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.margin_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.margin_active_color, &set_me);
|
|
|
|
do_blob(ui, &layout, &style->main.cursor_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.at_cursor_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.mark_color, &set_me);
|
|
|
|
do_blob(ui, &layout, &style->main.highlight_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.at_highlight_color, &set_me);
|
|
|
|
do_blob(ui, &layout, &style->main.default_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.comment_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.keyword_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.str_constant_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.char_constant_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.int_constant_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.float_constant_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.bool_constant_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.include_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.preproc_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.special_character_color, &set_me);
|
|
|
|
do_blob(ui, &layout, &style->main.highlight_junk_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.highlight_white_color, &set_me);
|
|
|
|
do_blob(ui, &layout, &style->main.paste_color, &set_me);
|
|
|
|
do_blob(ui, &layout, &style->main.file_info_style.bar_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.file_info_style.base_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.file_info_style.pop1_color, &set_me);
|
|
do_blob(ui, &layout, &style->main.file_info_style.pop2_color, &set_me);
|
|
|
|
do_v_divide(ui, &layout, 20);
|
|
|
|
if (!ui->state.input_stage){
|
|
Render_Target *target = ui->state.target;
|
|
Font *font = style->font;
|
|
draw_string(target, font, "Global Palette: right click to save color",
|
|
layout.x, layout.rect.y0, style->main.default_color);
|
|
}
|
|
|
|
layout.rect.y0 += layout.size + layout.space;
|
|
layout.y = layout.rect.y0;
|
|
i32 palette_size = ui->palette_size + 1000;
|
|
u32 *color = ui->palette;
|
|
for (i32 i = 1000; i < palette_size; ++i, ++color){
|
|
set_me = 0;
|
|
do_blob(ui, &layout, *color, &set_me, i);
|
|
if (set_me){
|
|
*color = *ui->color.out;
|
|
ui->state.redraw = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal void
|
|
do_sub_button(i32 id, Color_UI *ui, char *text){
|
|
Font *font = ui->state.font;
|
|
|
|
i32_Rect rect = layout_rect(&ui->layout, font->height + 2);
|
|
|
|
if (ui->state.input_stage){
|
|
ui_do_button_input(&ui->state, rect, make_sub0(&ui->state, id), 1);
|
|
}
|
|
else{
|
|
Render_Target *target = ui->state.target;
|
|
u32 back_color, text_color;
|
|
text_color = 0xFFDDDDDD;
|
|
if (ui->state.selected.sub_id0 == id){
|
|
back_color = 0xFF444444;
|
|
}
|
|
else if (ui->state.hover.sub_id0 == id){
|
|
back_color = 0xFF222222;
|
|
}
|
|
else{
|
|
back_color = 0xFF111111;
|
|
}
|
|
|
|
draw_rectangle(target, rect, back_color);
|
|
draw_string(target, font, text, rect.x0, rect.y0 + 1,
|
|
text_color);
|
|
}
|
|
}
|
|
|
|
internal void
|
|
do_color_adjuster(Color_UI *ui, u32 *color,
|
|
u32 text_color, u32 back_color, char *name){
|
|
i32 id = raw_ptr_dif(color, ui->state.style);
|
|
Render_Target *target = ui->state.target;
|
|
Font *font = ui->state.font;
|
|
i32 character_h = font->height;
|
|
u32 text = 0, back = 0;
|
|
|
|
i32_Rect bar = layout_rect(&ui->layout, character_h);
|
|
|
|
if (ui->state.input_stage){
|
|
if (ui_do_button_input(&ui->state, bar, make_id(&ui->state, id), 1)){
|
|
ui->has_hover_color = 1;
|
|
ui->hover_color = super_color_create(*color);
|
|
}
|
|
}
|
|
|
|
else{
|
|
u32 text_hover = 0xFF101010;
|
|
u32 back_hover = 0xFF999999;
|
|
if (ui->state.selected.id != id && ui->state.hover.id == id){
|
|
text = text_hover;
|
|
back = back_hover;
|
|
}
|
|
else{
|
|
text = text_color;
|
|
back = back_color;
|
|
}
|
|
|
|
draw_rectangle(target, bar, back);
|
|
i32 end_pos = draw_string(target, font, name, bar.x0, bar.y0, text);
|
|
|
|
real32 x_spacing = ui->hex_advance;
|
|
i32_Rect temp_rect = bar;
|
|
temp_rect.x0 = temp_rect.x1 - CEIL32(x_spacing * 9.f);
|
|
if (temp_rect.x0 >= end_pos + x_spacing){
|
|
u32 n = *color;
|
|
char full_hex_string[] = "0x000000";
|
|
for (i32 i = 7; i >= 2; --i){
|
|
i32 m = (n & 0xF);
|
|
n >>= 4;
|
|
full_hex_string[i] = int_to_hexchar(m);
|
|
}
|
|
draw_string_mono(target, font, full_hex_string,
|
|
(real32)temp_rect.x0, (real32)bar.y0,
|
|
x_spacing, text);
|
|
}
|
|
|
|
for (i32 i = 0; i < ArrayCount(ui->highlight.ids); ++i){
|
|
if (ui->highlight.ids[i] == id){
|
|
draw_rectangle_outline(target, f32R(bar), text_color);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ui->state.selected.id == id){
|
|
i32_Rect expanded = layout_rect(&ui->layout, 115 + (character_h + 2));
|
|
UI_Layout_Restore restore = begin_sub_layout(&ui->layout, expanded);
|
|
|
|
ui->color.out = color;
|
|
|
|
if (ui->state.input_stage){
|
|
if (ui->state.selected.sub_id0 == 0){
|
|
ui->state.selected.sub_id0 = 1;
|
|
}
|
|
}
|
|
else{
|
|
draw_rectangle(target, expanded, 0xff000000);
|
|
}
|
|
|
|
begin_row(&ui->layout, 3);
|
|
do_sub_button(1, ui, "HSL");
|
|
do_sub_button(2, ui, "RGB");
|
|
do_sub_button(3, ui, "Palette");
|
|
|
|
i32_Rect sub_rect;
|
|
sub_rect = expanded;
|
|
sub_rect.y0 += 10 + character_h;
|
|
|
|
switch (ui->state.selected.sub_id0){
|
|
case 1: do_hsl_sliders(ui, sub_rect); break;
|
|
case 2: do_rgb_sliders(ui, sub_rect); break;
|
|
case 3: do_palette(ui, sub_rect); break;
|
|
}
|
|
|
|
end_sub_layout(restore);
|
|
}
|
|
}
|
|
|
|
internal void
|
|
do_style_name(Color_UI *ui){
|
|
i32 id = -3;
|
|
Font *font = ui->state.font;
|
|
|
|
i32_Rect srect = layout_rect(&ui->layout, font->height);
|
|
|
|
Widget_ID wid = make_id(&ui->state, id);
|
|
bool32 selected = is_selected(&ui->state, wid);
|
|
|
|
if (ui->state.input_stage){
|
|
if (!selected){
|
|
ui_do_button_input(&ui->state, srect, wid, 1);
|
|
}
|
|
else{
|
|
Style *style = ui->state.style;
|
|
if (ui_do_text_field_input(&ui->state, &style->name)){
|
|
ui->state.selected = {};
|
|
}
|
|
}
|
|
}
|
|
else{
|
|
Render_Target *target = ui->state.target;
|
|
Style *style = ui->state.style;
|
|
u32 back, fore_text, fore_label;
|
|
if (selected){
|
|
back = 0xFF000000;
|
|
fore_label = 0xFF808080;
|
|
fore_text = 0xFFFFFFFF;
|
|
}
|
|
else if (is_hover(&ui->state, wid)){
|
|
back = 0xFF999999;
|
|
fore_text = fore_label = 0xFF101010;
|
|
}
|
|
else{
|
|
back = style->main.back_color;
|
|
fore_text = fore_label = style->main.default_color;
|
|
}
|
|
|
|
draw_rectangle(target, srect, back);
|
|
i32 x = srect.x0;
|
|
x = draw_string(target, font, "NAME: ",
|
|
x, srect.y0, fore_label);
|
|
x = draw_string(target, font, style->name.str,
|
|
x, srect.y0, fore_text);
|
|
}
|
|
}
|
|
|
|
internal bool32
|
|
do_font_option(Color_UI *ui, Font *font){
|
|
bool32 result = 0;
|
|
i32 sub_id = (i32)(font);
|
|
i32_Rect orect = layout_rect(&ui->layout, font->height);
|
|
|
|
Widget_ID wid = make_sub0(&ui->state, sub_id);
|
|
if (ui->state.input_stage){
|
|
if (ui_do_button_input(&ui->state, orect, wid, 0)){
|
|
result = 1;
|
|
}
|
|
}
|
|
else{
|
|
Render_Target *target = ui->state.target;
|
|
u32 back, fore;
|
|
if (is_hover(&ui->state, wid)){
|
|
back = 0xFF999999;
|
|
fore = 0xFF101010;
|
|
}
|
|
else{
|
|
back = 0xFF000000;
|
|
fore = 0xFFFFFFFF;
|
|
}
|
|
draw_rectangle(target, orect, back);
|
|
i32 x = orect.x0;
|
|
x = draw_string(target, font, "->",
|
|
x, orect.y0, fore);
|
|
x = draw_string(target, font, font->name.str,
|
|
x, orect.y0, fore);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
internal void
|
|
do_font_switch(Color_UI *ui){
|
|
i32 id = -2;
|
|
Render_Target *target = ui->state.target;
|
|
Font *font = ui->state.font;
|
|
i32 character_h = font->height;
|
|
|
|
i32_Rect srect = layout_rect(&ui->layout, character_h);
|
|
|
|
Widget_ID wid = make_id(&ui->state, id);
|
|
|
|
if (ui->state.input_stage){
|
|
ui_do_button_input(&ui->state, srect, wid, 1);
|
|
}
|
|
else{
|
|
Style *style = ui->state.style;
|
|
u32 back, fore;
|
|
if (is_hover(&ui->state, wid) && !is_selected(&ui->state, wid)){
|
|
back = 0xFF999999;
|
|
fore = 0xFF101010;
|
|
}
|
|
else{
|
|
back = style->main.back_color;
|
|
fore = style->main.default_color;
|
|
}
|
|
draw_rectangle(target, srect, back);
|
|
i32 x = srect.x0;
|
|
x = draw_string(target, font, "FONT: ",
|
|
x, srect.y0, fore);
|
|
x = draw_string(target, font, font->name.str,
|
|
x, srect.y0, fore);
|
|
}
|
|
|
|
if (is_selected(&ui->state, wid)){
|
|
Font_Set *fonts = ui->fonts;
|
|
Font *font_opt = fonts->fonts;
|
|
i32 count = fonts->count;
|
|
srect = layout_rect(&ui->layout, character_h/2);
|
|
if (!ui->state.input_stage)
|
|
draw_rectangle(target, srect, 0xFF000000);
|
|
|
|
for (i32 i = 0; i < count; ++i, ++font_opt){
|
|
if (font_opt == font) continue;
|
|
if (do_font_option(ui, font_opt)){
|
|
ui->state.style->font = font_opt;
|
|
ui->state.style->font_changed = 1;
|
|
}
|
|
}
|
|
|
|
srect = layout_rect(&ui->layout, character_h/2);
|
|
if (!ui->state.input_stage)
|
|
draw_rectangle(target, srect, 0xFF000000);
|
|
}
|
|
}
|
|
|
|
internal i32
|
|
step_draw_adjusting(Color_View *color_view, i32_Rect rect, View_Message message,
|
|
Render_Target *target, Input_Summary *user_input){
|
|
Style *style = color_view->main_style;
|
|
i32 result = 0;
|
|
|
|
if (message != VMSG_DRAW && message != VMSG_STEP) return result;
|
|
|
|
Color_UI ui;
|
|
ui.state = ui_state_init(&color_view->state, target, user_input,
|
|
style, color_view->working_set, (message == VMSG_STEP));
|
|
|
|
begin_layout(&ui.layout, rect);
|
|
|
|
ui.fonts = color_view->fonts;
|
|
ui.highlight = color_view->highlight;
|
|
ui.color = color_view->color;
|
|
ui.has_hover_color = 0;
|
|
ui.state.sub_id1_change = 0;
|
|
ui.hex_advance = font_get_max_width(ui.state.font, "0123456789abcdefx");
|
|
ui.palette = color_view->palette;
|
|
ui.palette_size = color_view->palette_size;
|
|
|
|
i32_Rect bar_rect = ui.layout.rect;
|
|
bar_rect.x0 = bar_rect.x1 - 20;
|
|
do_scroll_bar(&ui.state, bar_rect);
|
|
|
|
ui.layout.y -= FLOOR32(color_view->state.view_y);
|
|
ui.layout.rect.x1 -= 20;
|
|
|
|
if (!ui.state.input_stage) draw_push_clip(target, ui.layout.rect);
|
|
if (do_button(-1, &ui.state, &ui.layout, "Back to Library", 2)){
|
|
color_view->mode = CV_MODE_LIBRARY;
|
|
ui.state.view_y = 0;
|
|
}
|
|
|
|
do_style_name(&ui);
|
|
do_font_switch(&ui);
|
|
|
|
do_color_adjuster(&ui, &style->main.back_color,
|
|
style->main.default_color, style->main.back_color,
|
|
"Background");
|
|
do_color_adjuster(&ui, &style->main.margin_color,
|
|
style->main.default_color, style->main.margin_color,
|
|
"Margin");
|
|
do_color_adjuster(&ui, &style->main.margin_hover_color,
|
|
style->main.default_color, style->main.margin_hover_color,
|
|
"Margin Hover");
|
|
do_color_adjuster(&ui, &style->main.margin_active_color,
|
|
style->main.default_color, style->main.margin_active_color,
|
|
"Margin Active");
|
|
|
|
do_color_adjuster(&ui, &style->main.cursor_color,
|
|
style->main.at_cursor_color, style->main.cursor_color,
|
|
"Cursor");
|
|
do_color_adjuster(&ui, &style->main.at_cursor_color,
|
|
style->main.at_cursor_color, style->main.cursor_color,
|
|
"Text At Cursor");
|
|
do_color_adjuster(&ui, &style->main.mark_color,
|
|
style->main.mark_color, style->main.back_color,
|
|
"Mark");
|
|
|
|
do_color_adjuster(&ui, &style->main.highlight_color,
|
|
style->main.at_highlight_color, style->main.highlight_color,
|
|
"Highlight");
|
|
do_color_adjuster(&ui, &style->main.at_highlight_color,
|
|
style->main.at_highlight_color, style->main.highlight_color,
|
|
"Text At Highlight");
|
|
|
|
do_color_adjuster(&ui, &style->main.default_color,
|
|
style->main.default_color, style->main.back_color,
|
|
"Text Default");
|
|
do_color_adjuster(&ui, &style->main.comment_color,
|
|
style->main.comment_color, style->main.back_color,
|
|
"Comment");
|
|
do_color_adjuster(&ui, &style->main.keyword_color,
|
|
style->main.keyword_color, style->main.back_color,
|
|
"Keyword");
|
|
do_color_adjuster(&ui, &style->main.str_constant_color,
|
|
style->main.str_constant_color, style->main.back_color,
|
|
"String Constant");
|
|
do_color_adjuster(&ui, &style->main.char_constant_color,
|
|
style->main.char_constant_color, style->main.back_color,
|
|
"Character Constant");
|
|
do_color_adjuster(&ui, &style->main.int_constant_color,
|
|
style->main.int_constant_color, style->main.back_color,
|
|
"Integer Constant");
|
|
do_color_adjuster(&ui, &style->main.float_constant_color,
|
|
style->main.float_constant_color, style->main.back_color,
|
|
"Float Constant");
|
|
do_color_adjuster(&ui, &style->main.bool_constant_color,
|
|
style->main.bool_constant_color, style->main.back_color,
|
|
"Boolean Constant");
|
|
do_color_adjuster(&ui, &style->main.preproc_color,
|
|
style->main.preproc_color, style->main.back_color,
|
|
"Preprocessor");
|
|
do_color_adjuster(&ui, &style->main.include_color,
|
|
style->main.include_color, style->main.back_color,
|
|
"Include Constant");
|
|
do_color_adjuster(&ui, &style->main.special_character_color,
|
|
style->main.special_character_color, style->main.back_color,
|
|
"Special Character");
|
|
|
|
do_color_adjuster(&ui, &style->main.highlight_junk_color,
|
|
style->main.default_color, style->main.highlight_junk_color,
|
|
"Junk Highlight");
|
|
do_color_adjuster(&ui, &style->main.highlight_white_color,
|
|
style->main.default_color, style->main.highlight_white_color,
|
|
"Whitespace Highlight");
|
|
|
|
do_color_adjuster(&ui, &style->main.paste_color,
|
|
style->main.paste_color, style->main.back_color,
|
|
"Paste Color");
|
|
|
|
Interactive_Style *bar_style = &style->main.file_info_style;
|
|
do_color_adjuster(&ui, &bar_style->bar_color,
|
|
bar_style->base_color, bar_style->bar_color,
|
|
"Bar");
|
|
do_color_adjuster(&ui, &bar_style->base_color,
|
|
bar_style->base_color, bar_style->bar_color,
|
|
"Bar Text");
|
|
do_color_adjuster(&ui, &bar_style->pop1_color,
|
|
bar_style->pop1_color, bar_style->bar_color,
|
|
"Bar Pop 1");
|
|
do_color_adjuster(&ui, &bar_style->pop2_color,
|
|
bar_style->pop2_color, bar_style->bar_color,
|
|
"Bar Pop 2");
|
|
|
|
i32 did_activation = 0;
|
|
if (ui_finish_frame(&color_view->state, &ui.state, &ui.layout, rect, 1, &did_activation)){
|
|
result = 1;
|
|
}
|
|
if (did_activation){
|
|
if (ui.has_hover_color){
|
|
ui.color = ui.hover_color;
|
|
}
|
|
}
|
|
if (!ui.state.input_stage) draw_pop_clip(target);
|
|
color_view->color = ui.color;
|
|
|
|
return result;
|
|
}
|
|
|
|
internal void
|
|
update_highlighting(Color_View *color_view){
|
|
Style *style = color_view->main_style;
|
|
File_View *file_view = color_view->hot_file_view;
|
|
if (!file_view){
|
|
color_view->highlight = {};
|
|
return;
|
|
}
|
|
|
|
Editing_File *file = file_view->file;
|
|
i32 pos = view_get_cursor_pos(file_view);
|
|
char c = file->buffer.data[pos];
|
|
|
|
if (c == '\r'){
|
|
color_view->highlight.ids[0] =
|
|
raw_ptr_dif(&style->main.special_character_color, style);
|
|
}
|
|
|
|
else if (file->tokens_complete){
|
|
Cpp_Token_Stack *tokens = &file->token_stack;
|
|
Cpp_Get_Token_Result result = cpp_get_token(tokens, pos);
|
|
Cpp_Token token = tokens->tokens[result.token_index];
|
|
if (!result.in_whitespace){
|
|
u32 *color = style_get_color(style, token);
|
|
color_view->highlight.ids[0] = raw_ptr_dif(color, style);
|
|
if (token.type == CPP_TOKEN_JUNK){
|
|
color_view->highlight.ids[1] =
|
|
raw_ptr_dif(&style->main.highlight_junk_color, style);
|
|
}
|
|
else if (char_is_whitespace(c)){
|
|
color_view->highlight.ids[1] =
|
|
raw_ptr_dif(&style->main.highlight_white_color, style);
|
|
}
|
|
else{
|
|
color_view->highlight.ids[1] = 0;
|
|
}
|
|
}
|
|
else{
|
|
color_view->highlight.ids[0] = 0;
|
|
color_view->highlight.ids[1] =
|
|
raw_ptr_dif(&style->main.highlight_white_color, style);
|
|
}
|
|
}
|
|
|
|
else{
|
|
if (char_is_whitespace(c)){
|
|
color_view->highlight.ids[0] = 0;
|
|
color_view->highlight.ids[1] =
|
|
raw_ptr_dif(&style->main.highlight_white_color, style);
|
|
}
|
|
else{
|
|
color_view->highlight.ids[0] =
|
|
raw_ptr_dif(&style->main.default_color, style);
|
|
color_view->highlight.ids[1] = 0;
|
|
}
|
|
}
|
|
|
|
if (file_view->show_temp_highlight){
|
|
color_view->highlight.ids[2] =
|
|
raw_ptr_dif(&style->main.highlight_color, style);
|
|
color_view->highlight.ids[3] =
|
|
raw_ptr_dif(&style->main.at_highlight_color, style);
|
|
}
|
|
else if (file_view->paste_effect.tick_down > 0){
|
|
color_view->highlight.ids[2] =
|
|
raw_ptr_dif(&style->main.paste_color, style);
|
|
color_view->highlight.ids[3] = 0;
|
|
}
|
|
else{
|
|
color_view->highlight.ids[2] = 0;
|
|
color_view->highlight.ids[3] = 0;
|
|
}
|
|
}
|
|
|
|
internal bool32
|
|
do_style_preview(Library_UI *ui, Style *style, i32 toggle = -1){
|
|
bool32 result = 0;
|
|
Font *font = style->font;
|
|
i32 id;
|
|
if (style == ui->state.style) id = 2;
|
|
else id = raw_ptr_dif(style, ui->styles->styles) + 100;
|
|
|
|
i32_Rect prect = layout_rect(&ui->layout, font->height*3 + 6);
|
|
|
|
Widget_ID wid = make_id(&ui->state, id);
|
|
|
|
if (ui->state.input_stage){
|
|
if (ui_do_button_input(&ui->state, prect, wid, 0)){
|
|
result = 1;
|
|
}
|
|
}
|
|
else{
|
|
Render_Target *target = ui->state.target;
|
|
|
|
u32 margin_color = style->main.margin_color;
|
|
if (is_hover(&ui->state, wid)){
|
|
margin_color = style->main.margin_active_color;
|
|
}
|
|
|
|
i32_Rect inner;
|
|
if (toggle != -1){
|
|
i32_Rect toggle_box = prect;
|
|
toggle_box.x1 = toggle_box.x0 + font->height*2 + 6;
|
|
prect.x0 = toggle_box.x1;
|
|
|
|
inner = get_inner_rect(toggle_box, 3);
|
|
draw_margin(target, toggle_box, inner, margin_color);
|
|
draw_rectangle(target, inner, style->main.back_color);
|
|
|
|
i32 d;
|
|
d = font->height/2;
|
|
i32_Rect b;
|
|
b.x0 = (inner.x1 + inner.x0)/2 - d;
|
|
b.y0 = (inner.y1 + inner.y0)/2 - d;
|
|
b.x1 = b.x0 + font->height;
|
|
b.y1 = b.y0 + font->height;
|
|
if (toggle) draw_rectangle(target, b, margin_color);
|
|
else draw_rectangle_outline(target, b, margin_color);
|
|
}
|
|
|
|
inner = get_inner_rect(prect, 3);
|
|
draw_margin(target, prect, inner, margin_color);
|
|
draw_rectangle(target, inner, style->main.back_color);
|
|
|
|
i32 text_y = inner.y0;
|
|
i32 text_x = inner.x0;
|
|
text_x = draw_string(target, font, style->name.str,
|
|
text_x, text_y, style->main.default_color);
|
|
i32 font_x = (i32)(inner.x1 - font_string_width(font, font->name.str));
|
|
if (font_x > text_x + 10)
|
|
draw_string(target, font, font->name.str,
|
|
font_x, text_y, style->main.default_color);
|
|
|
|
text_x = inner.x0;
|
|
text_y += font->height;
|
|
text_x = draw_string(target, font, "if ", text_x, text_y,
|
|
style->main.keyword_color);
|
|
text_x = draw_string(target, font, "(x < ", text_x, text_y,
|
|
style->main.default_color);
|
|
text_x = draw_string(target, font, "0", text_x, text_y,
|
|
style->main.int_constant_color);
|
|
text_x = draw_string(target, font, ") { x = ", text_x, text_y,
|
|
style->main.default_color);
|
|
text_x = draw_string(target, font, "0", text_x, text_y,
|
|
style->main.int_constant_color);
|
|
text_x = draw_string(target, font, "; } ", text_x, text_y,
|
|
style->main.default_color);
|
|
text_x = draw_string(target, font, "// comment", text_x, text_y,
|
|
style->main.comment_color);
|
|
|
|
text_x = inner.x0;
|
|
text_y += font->height;
|
|
text_x = draw_string(target, font, "[] () {}; * -> +-/ <>= ! && || % ^",
|
|
text_x, text_y, style->main.default_color);
|
|
}
|
|
|
|
ui->layout.y = prect.y1;
|
|
return result;
|
|
}
|
|
|
|
internal bool32
|
|
do_main_file_box(UI_State *state, UI_Layout *layout, Hot_Directory *hot_directory, char *end = 0){
|
|
bool32 result = 0;
|
|
Style *style = state->style;
|
|
Font *font = style->font;
|
|
i32_Rect box = layout_rect(layout, font->height + 2);
|
|
String *string = &hot_directory->string;
|
|
|
|
if (state->input_stage){
|
|
if (ui_do_file_field_input(state, hot_directory)){
|
|
result = 1;
|
|
}
|
|
}
|
|
else{
|
|
Render_Target *target = state->target;
|
|
u32 back = style->main.margin_color;
|
|
u32 fore = style->main.default_color;
|
|
u32 special = style->main.special_character_color;
|
|
draw_rectangle(target, box, back);
|
|
i32 x = box.x0;
|
|
x = draw_string(target, font, string->str, x, box.y0, fore);
|
|
if (end) draw_string(target, font, end, x, box.y0, special);
|
|
}
|
|
|
|
layout->y = box.y1;
|
|
return result;
|
|
}
|
|
|
|
internal bool32
|
|
do_main_string_box(UI_State *state, UI_Layout *layout, String *string){
|
|
bool32 result = 0;
|
|
Style *style = state->style;
|
|
Font *font = style->font;
|
|
i32_Rect box = layout_rect(layout, font->height + 2);
|
|
|
|
if (state->input_stage){
|
|
if (ui_do_line_field_input(state, string)){
|
|
result = 1;
|
|
}
|
|
}
|
|
else{
|
|
Render_Target *target = state->target;
|
|
u32 back = style->main.margin_color;
|
|
u32 fore = style->main.default_color;
|
|
draw_rectangle(target, box, back);
|
|
i32 x = box.x0;
|
|
x = draw_string(target, font, string->str, x, box.y0, fore);
|
|
}
|
|
|
|
layout->y = box.y1;
|
|
return result;
|
|
}
|
|
|
|
internal bool32
|
|
do_list_option(i32 id, UI_State *state, UI_Layout *layout, String text){
|
|
bool32 result = 0;
|
|
Style *style = state->style;
|
|
Font *font = style->font;
|
|
i32 character_h = font->height;
|
|
|
|
i32_Rect box = layout_rect(layout, font->height*2);
|
|
Widget_ID wid = make_id(state, id);
|
|
|
|
if (state->input_stage){
|
|
if (ui_do_button_input(state, box, wid, 0)){
|
|
result = 1;
|
|
}
|
|
}
|
|
else{
|
|
Render_Target *target = state->target;
|
|
i32_Rect inner = get_inner_rect(box, 3);
|
|
u32 back, outline, fore, pop;
|
|
back = style->main.back_color;
|
|
fore = style->main.default_color;
|
|
pop = style->main.file_info_style.pop2_color;
|
|
if (is_hover(state, wid)) outline = style->main.margin_active_color;
|
|
else outline = style->main.margin_color;
|
|
|
|
draw_rectangle(target, inner, back);
|
|
i32 x = inner.x0, y = box.y0 + character_h/2;
|
|
x = draw_string(target, font, text, x, y, fore);
|
|
draw_margin(target, box, inner, outline);
|
|
}
|
|
|
|
layout->y = box.y1;
|
|
return result;
|
|
}
|
|
|
|
#define do_list_option_lit(id,state,layout,str) do_list_option(id, state, layout, make_lit_string(str))
|
|
|
|
internal bool32
|
|
do_file_option(i32 id, UI_State *state, UI_Layout *layout, String filename, bool32 is_folder, String extra){
|
|
bool32 result = 0;
|
|
Style *style = state->style;
|
|
Font *font = style->font;
|
|
i32 character_h = font->height;
|
|
|
|
i32_Rect box = layout_rect(layout, font->height*2);
|
|
Widget_ID wid = make_id(state, id);
|
|
|
|
if (state->input_stage){
|
|
if (ui_do_button_input(state, box, wid, 0)){
|
|
result = 1;
|
|
}
|
|
}
|
|
else{
|
|
Render_Target *target = state->target;
|
|
i32_Rect inner = get_inner_rect(box, 3);
|
|
u32 back, outline, fore, pop;
|
|
back = style->main.back_color;
|
|
fore = style->main.default_color;
|
|
pop = style->main.file_info_style.pop2_color;
|
|
if (is_hover(state, wid)) outline = style->main.margin_active_color;
|
|
else outline = style->main.margin_color;
|
|
|
|
draw_rectangle(target, inner, back);
|
|
i32 x = inner.x0, y = box.y0 + character_h/2;
|
|
x = draw_string(target, font, filename, x, y, fore);
|
|
if (is_folder) x = draw_string(target, font, "\\", x, y, fore);
|
|
draw_string(target, font, extra, x, y, pop);
|
|
draw_margin(target, box, inner, outline);
|
|
}
|
|
|
|
layout->y = box.y1;
|
|
return result;
|
|
}
|
|
|
|
internal bool32
|
|
do_file_list_box(UI_State *state, UI_Layout *layout, Hot_Directory *hot_dir, bool32 has_filter,
|
|
bool32 *new_dir, bool32 *selected, char *end){
|
|
bool32 result = 0;
|
|
File_List *files = &hot_dir->file_list;
|
|
|
|
if (do_main_file_box(state, layout, hot_dir, end)){
|
|
*selected = 1;
|
|
terminate_with_null(&hot_dir->string);
|
|
}
|
|
else{
|
|
persist String p4c_extension = make_lit_string("p4c");
|
|
persist String message_loaded = make_lit_string(" LOADED");
|
|
persist String message_unsaved = make_lit_string(" LOADED *");
|
|
persist String message_unsynced = make_lit_string(" LOADED BEHIND OS");
|
|
persist String message_nothing = {};
|
|
|
|
char front_name_space[256];
|
|
String front_name = make_fixed_width_string(front_name_space);
|
|
get_front_of_directory(&front_name, hot_dir->string);
|
|
|
|
Absolutes absolutes;
|
|
get_absolutes(front_name, &absolutes, 1, 1);
|
|
|
|
char full_path_[256];
|
|
String full_path = make_fixed_width_string(full_path_);
|
|
get_path_of_directory(&full_path, hot_dir->string);
|
|
i32 restore_size = full_path.size;
|
|
|
|
i32 i;
|
|
File_Info *info, *end;
|
|
end = files->infos + files->count;
|
|
for (info = files->infos, i = 0; info != end; ++info, ++i){
|
|
String filename = info->filename;
|
|
|
|
append(&full_path, filename);
|
|
terminate_with_null(&full_path);
|
|
Editing_File *file = working_set_contains(state->working_set, full_path);
|
|
full_path.size = restore_size;
|
|
|
|
bool8 is_folder = (info->folder != 0);
|
|
bool8 ext_match = (match(file_extension(filename), p4c_extension) != 0);
|
|
bool8 name_match = (filename_match(front_name, &absolutes, filename) != 0);
|
|
bool8 is_loaded = (file != 0);
|
|
|
|
String message = message_nothing;
|
|
if (is_loaded){
|
|
switch (buffer_get_sync(file)){
|
|
case SYNC_GOOD: message = message_loaded; break;
|
|
case SYNC_BEHIND_OS: message = message_unsynced; break;
|
|
case SYNC_UNSAVED: message = message_unsaved; break;
|
|
}
|
|
}
|
|
|
|
if ((is_folder || !has_filter || ext_match) && name_match){
|
|
if (do_file_option(100+i, state, layout, filename, is_folder, message)){
|
|
result = 1;
|
|
hot_directory_clean_end(hot_dir);
|
|
append(&hot_dir->string, filename);
|
|
if (is_folder){
|
|
*new_dir = 1;
|
|
append(&hot_dir->string, "\\");
|
|
}
|
|
else{
|
|
*selected = 1;
|
|
}
|
|
terminate_with_null(&hot_dir->string);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
internal bool32
|
|
do_live_file_list_box(UI_State *state, UI_Layout *layout, Working_Set *working_set,
|
|
String *string, bool32 *selected){
|
|
bool32 result = 0;
|
|
|
|
if (do_main_string_box(state, layout, string)){
|
|
*selected = 1;
|
|
terminate_with_null(string);
|
|
}
|
|
else{
|
|
persist String message_unsaved = make_lit_string(" *");
|
|
persist String message_unsynced = make_lit_string(" BEHIND OS");
|
|
persist String message_nothing = {};
|
|
|
|
Absolutes absolutes;
|
|
get_absolutes(*string, &absolutes, 1, 1);
|
|
|
|
i32 count = working_set->file_index_count;
|
|
Editing_File *files = working_set->files;
|
|
for (i32 i = 0; i < count; ++i){
|
|
Editing_File *file = files + i;
|
|
|
|
if (!file->is_dummy){
|
|
String message = message_nothing;
|
|
switch (buffer_get_sync(file)){
|
|
case SYNC_BEHIND_OS: message = message_unsynced; break;
|
|
case SYNC_UNSAVED: message = message_unsaved; break;
|
|
}
|
|
|
|
if (filename_match(*string, &absolutes, file->live_name)){
|
|
if (do_file_option(100+i, state, layout, file->live_name, 0, message)){
|
|
result = 1;
|
|
*selected = 1;
|
|
copy(string, file->live_name);
|
|
terminate_with_null(string);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
internal i32
|
|
step_draw_library(Color_View *color_view, i32_Rect rect, View_Message message,
|
|
Render_Target *target, Input_Summary *user_input){
|
|
i32 result = 0;
|
|
|
|
Library_UI ui;
|
|
ui.state = ui_state_init(&color_view->state, target, user_input,
|
|
color_view->main_style, color_view->working_set, (message == VMSG_STEP));
|
|
|
|
ui.fonts = color_view->fonts;
|
|
ui.hot_directory = color_view->hot_directory;
|
|
ui.styles = color_view->styles;
|
|
|
|
begin_layout(&ui.layout, rect);
|
|
|
|
Color_View_Mode mode = color_view->mode;
|
|
|
|
i32_Rect bar_rect = ui.layout.rect;
|
|
bar_rect.x0 = bar_rect.x1 - 20;
|
|
do_scroll_bar(&ui.state, bar_rect);
|
|
|
|
ui.layout.y -= FLOOR32(color_view->state.view_y);
|
|
ui.layout.rect.x1 -= 20;
|
|
|
|
if (!ui.state.input_stage) draw_push_clip(ui.state.target, ui.layout.rect);
|
|
switch (mode){
|
|
case CV_MODE_LIBRARY:
|
|
{
|
|
do_label(&ui.state, &ui.layout, "Current Theme - Click to Edit");
|
|
if (do_style_preview(&ui, color_view->main_style)){
|
|
color_view->mode = CV_MODE_ADJUSTING;
|
|
color_view->state.selected = {};
|
|
ui.state.view_y = 0;
|
|
result = 1;
|
|
}
|
|
|
|
begin_row(&ui.layout, 3);
|
|
if (ui.state.style->name.size >= 1){
|
|
if (do_button(-2, &ui.state, &ui.layout, "Save", 2)){
|
|
style_library_add(ui.styles, ui.state.style);
|
|
}
|
|
}
|
|
else{
|
|
do_button(-2, &ui.state, &ui.layout, "~Need's Name~", 2);
|
|
}
|
|
if (do_button(-3, &ui.state, &ui.layout, "Import", 2)){
|
|
color_view->mode = CV_MODE_IMPORT_FILE;
|
|
hot_directory_clean_end(color_view->hot_directory);
|
|
hot_directory_reload(color_view->hot_directory, color_view->working_set);
|
|
}
|
|
if (do_button(-4, &ui.state, &ui.layout, "Export", 2)){
|
|
color_view->mode = CV_MODE_EXPORT;
|
|
hot_directory_clean_end(color_view->hot_directory);
|
|
hot_directory_reload(color_view->hot_directory, color_view->working_set);
|
|
memset(color_view->import_export_check, 0, sizeof(color_view->import_export_check));
|
|
}
|
|
|
|
do_label(&ui.state, &ui.layout, "Theme Library - Click to Select");
|
|
|
|
i32 style_count = color_view->styles->count;
|
|
Style *style = color_view->styles->styles;
|
|
for (i32 i = 0; i < style_count; ++i, ++style){
|
|
if (do_style_preview(&ui, style)){
|
|
style_copy(color_view->main_style, style);
|
|
result = 1;
|
|
}
|
|
}
|
|
}break;
|
|
|
|
case CV_MODE_IMPORT_FILE:
|
|
{
|
|
do_label(&ui.state, &ui.layout, "Current Theme");
|
|
do_style_preview(&ui, color_view->main_style);
|
|
|
|
bool32 file_selected = 0;
|
|
|
|
do_label(&ui.state, &ui.layout, "Import Which File?");
|
|
begin_row(&ui.layout, 2);
|
|
if (do_button(-2, &ui.state, &ui.layout, "*.p4c only", 2, 1, color_view->p4c_only)){
|
|
color_view->p4c_only = !color_view->p4c_only;
|
|
}
|
|
if (do_button(-3, &ui.state, &ui.layout, "Cancel", 2)){
|
|
color_view->mode = CV_MODE_LIBRARY;
|
|
}
|
|
|
|
bool32 new_dir = 0;
|
|
if (do_file_list_box(&ui.state, &ui.layout, ui.hot_directory, color_view->p4c_only,
|
|
&new_dir, &file_selected, 0)){
|
|
result = 1;
|
|
}
|
|
|
|
if (new_dir){
|
|
hot_directory_reload(ui.hot_directory, ui.state.working_set);
|
|
}
|
|
if (file_selected){
|
|
memset(&color_view->inspecting_styles, 0, sizeof(Style_Library));
|
|
memset(color_view->import_export_check, 1, sizeof(color_view->import_export_check));
|
|
Style *styles = color_view->inspecting_styles.styles;
|
|
i32 count, max;
|
|
max = ArrayCount(color_view->inspecting_styles.styles);
|
|
if (style_library_import((u8*)color_view->hot_directory->string.str,
|
|
ui.fonts, styles, max, &count)){
|
|
color_view->mode = CV_MODE_IMPORT;
|
|
}
|
|
else{
|
|
color_view->mode = CV_MODE_LIBRARY;
|
|
}
|
|
color_view->inspecting_styles.count = count;
|
|
}
|
|
}break;
|
|
|
|
case CV_MODE_EXPORT_FILE:
|
|
{
|
|
do_label(&ui.state, &ui.layout, "Current Theme");
|
|
do_style_preview(&ui, color_view->main_style);
|
|
|
|
bool32 file_selected = 0;
|
|
|
|
do_label(&ui.state, &ui.layout, "Export File Name?");
|
|
begin_row(&ui.layout, 2);
|
|
if (do_button(-2, &ui.state, &ui.layout, "Finish Export", 2)){
|
|
file_selected = 1;
|
|
}
|
|
if (do_button(-3, &ui.state, &ui.layout, "Cancel", 2)){
|
|
color_view->mode = CV_MODE_LIBRARY;
|
|
}
|
|
|
|
bool32 new_dir = 0;
|
|
if (do_file_list_box(&ui.state, &ui.layout, ui.hot_directory, 1,
|
|
&new_dir, &file_selected, ".p4c")){
|
|
result = 1;
|
|
}
|
|
|
|
if (new_dir){
|
|
hot_directory_reload(ui.hot_directory, ui.state.working_set);
|
|
}
|
|
if (file_selected){
|
|
i32 count = ui.styles->count;
|
|
// TODO(allen): pass the transient memory in here
|
|
Style **styles = (Style**)
|
|
system_get_memory(sizeof(Style*)*count);
|
|
Style *style = ui.styles->styles;
|
|
bool8 *export_check = color_view->import_export_check;
|
|
i32 export_count = 0;
|
|
for (i32 i = 0; i < count; ++i, ++style){
|
|
if (export_check[i]){
|
|
styles[export_count++] = style;
|
|
}
|
|
}
|
|
char *mem = (char*)system_get_memory(ui.hot_directory->string.size + 5);
|
|
String str = make_string(mem, 0, ui.hot_directory->string.size + 5);
|
|
copy(&str, ui.hot_directory->string);
|
|
append(&str, make_lit_string(".p4c"));
|
|
style_library_export((u8*)str.str, styles, export_count);
|
|
system_free_memory(mem);
|
|
system_free_memory(styles);
|
|
color_view->mode = CV_MODE_LIBRARY;
|
|
}
|
|
}break;
|
|
|
|
case CV_MODE_IMPORT:
|
|
{
|
|
do_label(&ui.state, &ui.layout, "Current Theme");
|
|
do_style_preview(&ui, color_view->main_style);
|
|
|
|
i32 style_count = color_view->inspecting_styles.count;
|
|
Style *styles = color_view->inspecting_styles.styles;
|
|
bool8 *import_check = color_view->import_export_check;
|
|
|
|
do_label(&ui.state, &ui.layout, "Pack");
|
|
begin_row(&ui.layout, 2);
|
|
if (do_button(-2, &ui.state, &ui.layout, "Finish Import", 2)){
|
|
Style *style = styles;
|
|
for (i32 i = 0; i < style_count; ++i, ++style){
|
|
if (import_check[i]) style_library_add(ui.styles, style);
|
|
}
|
|
color_view->mode = CV_MODE_LIBRARY;
|
|
}
|
|
if (do_button(-3, &ui.state, &ui.layout, "Cancel", 2)){
|
|
color_view->mode = CV_MODE_LIBRARY;
|
|
}
|
|
|
|
Style *style = styles;
|
|
for (i32 i = 0; i < style_count; ++i, ++style){
|
|
if (do_style_preview(&ui, style, import_check[i])){
|
|
import_check[i] = !import_check[i];
|
|
result = 1;
|
|
}
|
|
}
|
|
}break;
|
|
|
|
case CV_MODE_EXPORT:
|
|
{
|
|
do_label(&ui.state, &ui.layout, "Current Theme");
|
|
do_style_preview(&ui, color_view->main_style);
|
|
|
|
do_label(&ui.state, &ui.layout, "Export Which Themes?");
|
|
begin_row(&ui.layout, 2);
|
|
if (do_button(-2, &ui.state, &ui.layout, "Export", 2)){
|
|
color_view->mode = CV_MODE_EXPORT_FILE;
|
|
}
|
|
if (do_button(-3, &ui.state, &ui.layout, "Cancel", 2)){
|
|
color_view->mode = CV_MODE_LIBRARY;
|
|
}
|
|
|
|
i32 style_count = color_view->styles->count;
|
|
Style *style = color_view->styles->styles;
|
|
bool8 *export_check = color_view->import_export_check;
|
|
for (i32 i = 0; i < style_count; ++i, ++style){
|
|
if (do_style_preview(&ui, style, export_check[i])){
|
|
export_check[i] = !export_check[i];
|
|
result = 1;
|
|
}
|
|
}
|
|
}break;
|
|
}
|
|
if (!ui.state.input_stage) draw_pop_clip(ui.state.target);
|
|
|
|
if (ui_finish_frame(&color_view->state, &ui.state, &ui.layout, rect, 1, 0)){
|
|
result = 1;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
internal
|
|
DO_VIEW_SIG(do_color_view){
|
|
view->mouse_cursor_type = APP_MOUSE_CURSOR_ARROW;
|
|
Color_View *color_view = (Color_View*)view;
|
|
i32 result = 0;
|
|
|
|
switch (color_view->mode){
|
|
case CV_MODE_LIBRARY:
|
|
case CV_MODE_IMPORT_FILE:
|
|
case CV_MODE_EXPORT_FILE:
|
|
case CV_MODE_IMPORT:
|
|
case CV_MODE_EXPORT:
|
|
switch (message){
|
|
case VMSG_STEP:
|
|
{
|
|
result = step_draw_library(color_view, rect, message, target, user_input);
|
|
}break;
|
|
case VMSG_DRAW:
|
|
{
|
|
step_draw_library(color_view, rect, message, target, user_input);
|
|
}break;
|
|
}break;
|
|
|
|
case CV_MODE_ADJUSTING:
|
|
switch (message){
|
|
case VMSG_STEP:
|
|
{
|
|
result = step_draw_adjusting(color_view, rect, message, target, user_input);
|
|
}break;
|
|
case VMSG_DRAW:
|
|
{
|
|
if (view != active){
|
|
File_View *file_view = view_to_file_view(active);
|
|
color_view->hot_file_view = file_view;
|
|
}
|
|
if (color_view->hot_file_view && !color_view->hot_file_view->view_base.is_active){
|
|
color_view->hot_file_view = 0;
|
|
}
|
|
update_highlighting(color_view);
|
|
step_draw_adjusting(color_view, rect, message, target, user_input);
|
|
}break;
|
|
}break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
internal Color_View*
|
|
color_view_init(View *view, Working_Set *working_set){
|
|
Color_View* result = (Color_View*)view;
|
|
view->type = VIEW_TYPE_COLOR;
|
|
view->do_view = do_color_view;
|
|
result->working_set = working_set;
|
|
return result;
|
|
}
|
|
|
|
// BOTTOM
|
|
|