diff --git a/4ed.cpp b/4ed.cpp index 2afc6993..83a5f504 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -789,6 +789,7 @@ app_open_file_background(App_Vars *vars, Exchange *exchange, Working_Set *workin if (file_id){ result.is_new = 1; result.file = file.file; + file_init_strings(result.file); file_set_name(result.file, filename.str); file_set_to_loading(result.file); table_add(&working_set->table, result.file->name.source_path, file.index); @@ -923,16 +924,17 @@ COMMAND_DECL(save){ ProfileMomentFunction(); REQ_FILE_VIEW(view); REQ_FILE(file, view); - USE_VARS(vars); - USE_MEM(mem); - USE_EXCHANGE(exchange); - USE_WORKING_SET(working_set); + USE_DELAY(delay); + USE_PANEL(panel); + delayed_action(delay, DACT_SAVE, file->name.source_path, panel); +#if 0 String *file_path = &file->name.source_path; if (file_path->size > 0){ i32 sys_id = file_save(system, exchange, mem, file, file_path->str); app_push_file_binding(vars, sys_id, get_file_id(working_set, file)); } +#endif } COMMAND_DECL(interactive_save_as){ @@ -1678,6 +1680,7 @@ build(System_Functions *system, Mem_Options *mem, Font_Set *font_set, Style *style, Live_Views *live_set, Exchange *exchange, Panel *panel, Command_Data *command, + String hot_directory, char *buffer_name, i32 buffer_name_len, char *path, i32 path_len, char *script, i32 script_len, @@ -1725,7 +1728,7 @@ build(System_Functions *system, Mem_Options *mem, if (file){ file_create_super_locked(system, mem, file, buffer_name, font_set, style->font_id); file->settings.unimportant = 1; - table_add(&working_set->table, file->name.live_name, index); + table_add(&working_set->table, file->name.source_path, index); if (bind_to_new_view){ View *new_view = live_set_alloc_view(live_set, mem); @@ -1735,7 +1738,6 @@ build(System_Functions *system, Mem_Options *mem, view_set_file(system, file_view, file, font_set, style, vars->hooks[hook_open_file], command, &app_links); new_view->map = app_get_map(vars, file->settings.base_map_id); - } i32 i = vars->cli_processes.count++; @@ -1830,6 +1832,7 @@ COMMAND_DECL(build){ build(system, mem, vars, working_set, font_set, style, live_set, exchange, panel, command, + vars->hot_directory.string, buffer_name, buffer_name_len, path, path_len, script, script_len, @@ -1877,6 +1880,7 @@ COMMAND_DECL(build_here){ build(system, mem, vars, working_set, font_set, style, live_set, exchange, panel, command, + vars->hot_directory.string, buffer_name, buffer_name_len, path.str, path.size, dir.str, dir.size, @@ -3461,7 +3465,8 @@ App_Step_Sig(app_step){ if (fview){ Editing_File *file = fview->file; if (file && !file->state.is_dummy){ - file_save_and_set_names(system, exchange, mem, file, string->str); + i32 sys_id = file_save_and_set_names(system, exchange, mem, file, string->str); + app_push_file_binding(vars, sys_id, get_file_id(working_set, file)); } } }break; @@ -3470,7 +3475,8 @@ App_Step_Sig(app_step){ { Editing_File *file = working_set_lookup_file(working_set, *string); if (!file->state.is_dummy){ - file_save(system, exchange, mem, file, file->name.source_path.str); + i32 sys_id = file_save(system, exchange, mem, file, file->name.source_path.str); + app_push_file_binding(vars, sys_id, get_file_id(working_set, file)); } }break; diff --git a/4ed_color_view.cpp b/4ed_color_view.cpp index 4d9599b6..a6385e54 100644 --- a/4ed_color_view.cpp +++ b/4ed_color_view.cpp @@ -1,1903 +1,1903 @@ -/* - * 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_IMPORT_WAIT, - 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 *font_set; - u32 *palette; - Working_Set *working_set; - i32 palette_size; - Color_View_Mode mode; - UI_State state; - Super_Color color; - Color_Highlight highlight; - b32 p4c_only; - Style_Library inspecting_styles; - b8 import_export_check[64]; - i32 import_file_id; -}; - -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, f32 top, f32_Rect slider, b32 hsla){ - Vec4 low, high; - f32 *lowv, *highv; - f32 x; - f32 next_x; - f32 x_step; - f32 v_step; - f32 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, f32_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, f32 top, f32_Rect slider){ - draw_gradient_slider(target, base, channel, steps, top, slider, 0); -} - -internal void -do_label(UI_State *state, UI_Layout *layout, char *text, int text_size, f32 height = 2.f){ - Style *style = state->style; - i16 font_id = style->font_id; - i32 line_height = get_font_info(state->font_set, font_id)->height; - i32_Rect label = layout_rect(layout, FLOOR32(line_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; - - String textstr = make_string(text, text_size); - draw_string(target, font_id, textstr, label.x0, - label.y0 + (height - line_height)/2, fore); - } -} - -inline void -do_label(UI_State *state, UI_Layout *layout, String text, f32 height = 2.f){ - do_label(state, layout, text.str, text.size, height); -} - -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; - - f32 space_h = (f32)(bottom_arrow.y0 - top_arrow.y1); - if (space_h <= w) return; - - i32 slider_h = w; - - f32 view_hmin = 0; - f32 view_hmax = state->height - h; - f32 L = unlerp(view_hmin, state->view_y, view_hmax); - - f32 slider_hmin = (f32)top_arrow.y1; - f32 slider_hmax = (f32)bottom_arrow.y0 - slider_h; - f32 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, - (f32)(get_font_info(state->font_set, state->font_id)->height), - slider_hmin, slider_hmax, view_hmin, view_hmax); - } - else{ - Render_Target *target = state->target; - - f32 x0, y0, x1, y1, x2, y2; - f32 w_1_2 = w*.5f; - f32 w_1_3 = w*.333333f; - f32 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); - - ++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); - - ++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, b32 is_rgba, - i32 grad_steps, f32 top, f32_Rect slider, f32 v_handle, - i32_Rect rect){ - f32_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){ - f32_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 b32 -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){ - b32 result = 0; - - i16 font_id = ui->state.font_id; - i32 line_height = get_font_info(ui->state.font_set, font_id)->height; - i32_Rect hit_region; - hit_region.x0 = x0; - hit_region.x1 = x1; - hit_region.y0 = y; - hit_region.y1 = y + line_height; - - i32 digit_count; - if (ftype == CF_DEC) digit_count = 3; - else digit_count = 2; - - Render_Target *target = ui->state.target; - - 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_Event_Data key = get_single_key(keys, key_i); - - if (key.keycode == codes->right){ - ++indx; - if (indx > digit_count-1) indx = 0; - } - if (key.keycode == codes->left){ - --indx; - if (indx < 0) indx = digit_count-1; - } - - i32 new_value = *channel; - if (key.keycode == codes->up || 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.keycode == codes->down){ - step_amount = 0 - step_amount; - } - new_value += step_amount; - } - - u8 c = (u8)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{ - f32_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_id, 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); - - f32_Rect slider; - f32 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; - f32_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; - draw_string(target, style->font_id, "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){ - i16 font_id = ui->state.font_id; - i32 line_height = get_font_info(ui->state.font_set, font_id)->height; - i32_Rect rect = layout_rect(&ui->layout, line_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_id, 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); - i16 font_id = ui->state.font_id; - i32 character_h = get_font_info(ui->state.font_set, font_id)->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{ - Render_Target *target = ui->state.target; - 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_id, 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_id, full_hex_string, - (f32)temp_rect.x0, (f32)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){ - Render_Target *target = ui->state.target; - 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; - - i16 font_id = ui->state.font_id; - i32 line_height = get_font_info(ui->state.font_set, font_id)->height; - - i32_Rect srect = layout_rect(&ui->layout, line_height); - - Widget_ID wid = make_id(&ui->state, id); - b32 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_id, "NAME: ", - x, srect.y0, fore_label); - x = draw_string(target, font_id, style->name.str, - x, srect.y0, fore_text); - } -} - -internal b32 -do_font_option(Color_UI *ui, i16 font_id){ - b32 result = 0; - Font_Info *info = get_font_info(ui->state.font_set, font_id); - - i32 sub_id = (i32)(info); - i32_Rect orect = layout_rect(&ui->layout, info->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_id, "->", x, orect.y0, fore); - draw_string(target, font_id, info->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_Set *font_set = ui->state.font_set; - - i16 font_id = ui->state.font_id; - Font_Info *info = get_font_info(font_set, font_id); - i32 character_h = info->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_id, "FONT: ", - x, srect.y0, fore); - x = draw_string(target, font_id, info->name.str, - x, srect.y0, fore); - } - - if (is_selected(&ui->state, wid)){ - srect = layout_rect(&ui->layout, character_h/2); - if (!ui->state.input_stage) - draw_rectangle(target, srect, 0xFF000000); - - i32 count = font_set->count + 1; - - for (i16 i = 1; i < count; ++i){ - if (i == font_id) continue; - if (do_font_option(ui, i)){ - ui->state.style->font_id = i; - 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->font_set, color_view->working_set, - (message == VMSG_STEP)); - - begin_layout(&ui.layout, rect); - - ui.fonts = color_view->font_set; - 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.fonts, ui.state.font_id, "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){ - File_View *file_view = color_view->hot_file_view; - if (!file_view){ - color_view->highlight = {}; - return; - } - -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - Style *style = color_view->main_style; - Editing_File *file = file_view->file; - i32 pos = view_get_cursor_pos(file_view); - char c = file->state.buffer.data[pos]; - - if (c == '\r'){ - color_view->highlight.ids[0] = - raw_ptr_dif(&style->main.special_character_color, style); - } - - else if (file->state.tokens_complete){ - Cpp_Token_Stack *tokens = &file->state.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->state.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; - } -#endif -} - -internal b32 -do_style_preview(Library_UI *ui, Style *style, i32 toggle = -1){ - b32 result = 0; - i32 id; - if (style == ui->state.style) id = 2; - else id = raw_ptr_dif(style, ui->styles->styles) + 100; - - i16 font_id = style->font_id; - Font_Info *info = get_font_info(ui->state.font_set, font_id); - - i32_Rect prect = layout_rect(&ui->layout, info->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 + info->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 = info->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 + info->height; - b.y1 = b.y0 + info->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_id, style->name.str, - text_x, text_y, style->main.default_color); - i32 font_x = (i32)(inner.x1 - font_string_width(target, font_id, info->name.str)); - if (font_x > text_x + 10) - draw_string(target, font_id, info->name.str, - font_x, text_y, style->main.default_color); - - text_x = inner.x0; - text_y += info->height; - text_x = draw_string(target, font_id, "if ", text_x, text_y, - style->main.keyword_color); - text_x = draw_string(target, font_id, "(x < ", text_x, text_y, - style->main.default_color); - text_x = draw_string(target, font_id, "0", text_x, text_y, - style->main.int_constant_color); - text_x = draw_string(target, font_id, ") { x = ", text_x, text_y, - style->main.default_color); - text_x = draw_string(target, font_id, "0", text_x, text_y, - style->main.int_constant_color); - text_x = draw_string(target, font_id, "; } ", text_x, text_y, - style->main.default_color); - text_x = draw_string(target, font_id, "// comment", text_x, text_y, - style->main.comment_color); - - text_x = inner.x0; - text_y += info->height; - text_x = draw_string(target, font_id, "[] () {}; * -> +-/ <>= ! && || % ^", - text_x, text_y, style->main.default_color); - } - - ui->layout.y = prect.y1; - return result; -} - -internal b32 -do_main_file_box(System_Functions *system, UI_State *state, UI_Layout *layout, - Hot_Directory *hot_directory, b32 try_to_match, b32 case_sensitive, char *end){ - b32 result = 0; - Style *style = state->style; - String *string = &hot_directory->string; - - i16 font_id = style->font_id; - i32 line_height = get_font_info(state->font_set, font_id)->height; - i32_Rect box = layout_rect(layout, line_height + 2); - - if (state->input_stage){ - if (ui_do_file_field_input(system, state, hot_directory, try_to_match, case_sensitive)){ - 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_id, string->str, x, box.y0, fore); - if (end) draw_string(target, font_id, end, x, box.y0, special); - } - - layout->y = box.y1; - return result; -} - -internal b32 -do_main_string_box(System_Functions *system, UI_State *state, UI_Layout *layout, String *string){ - b32 result = 0; - Style *style = state->style; - - i16 font_id = style->font_id; - i32 line_height = get_font_info(state->font_set, font_id)->height; - i32_Rect box = layout_rect(layout, line_height + 2); - - if (state->input_stage){ - if (ui_do_line_field_input(system, 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_id, string->str, x, box.y0, fore); - } - - layout->y = box.y1; - return result; -} - -internal b32 -do_list_option(i32 id, UI_State *state, UI_Layout *layout, String text){ - b32 result = 0; - Style *style = state->style; - - i16 font_id = style->font_id; - i32 character_h = get_font_info(state->font_set, font_id)->height; - - i32_Rect box = layout_rect(layout, character_h*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_id, text, x, y, fore); - draw_margin(target, box, inner, outline); - } - - layout->y = box.y1; - return result; -} - -internal b32 -do_checkbox_list_option(i32 id, UI_State *state, UI_Layout *layout, String text, b32 is_on){ - b32 result = 0; - Style *style = state->style; - - i16 font_id = style->font_id; - i32 character_h = get_font_info(state->font_set, font_id)->height; - - i32_Rect box = layout_rect(layout, character_h*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, box_color; - 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; - box_color = style->main.margin_active_color; - - draw_rectangle(target, inner, back); - - i32_Rect square; - square = get_inner_rect(inner, character_h/3); - square.x1 = square.x0 + (square.y1 - square.y0); - if (is_on) draw_rectangle(target, square, box_color); - else draw_margin(target, square, 1, box_color); - - i32 x = square.x1 + 3; - i32 y = box.y0 + character_h/2; - x = draw_string(target, font_id, text, x, y, fore); - draw_margin(target, box, inner, outline); - } - - layout->y = box.y1; - return result; -} - - -internal b32 -do_file_option(i32 id, UI_State *state, UI_Layout *layout, String filename, b32 is_folder, String extra){ - b32 result = 0; - Style *style = state->style; - i16 font_id = style->font_id; - i32 character_h = get_font_info(state->font_set, font_id)->height; - - i32_Rect box = layout_rect(layout, character_h*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_id, filename, x, y, fore); - if (is_folder) x = draw_string(target, font_id, "\\", x, y, fore); - draw_string(target, font_id, extra, x, y, pop); - draw_margin(target, box, inner, outline); - } - - layout->y = box.y1; - return result; -} - -internal b32 -do_file_list_box(System_Functions *system, UI_State *state, UI_Layout *layout, - Hot_Directory *hot_dir, b32 has_filter, b32 try_to_match, b32 case_sensitive, - b32 *new_dir, b32 *selected, char *end){ - b32 result = 0; - File_List *files = &hot_dir->file_list; - - if (do_main_file_box(system, state, layout, hot_dir, try_to_match, case_sensitive, 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 !"); - 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; - - b8 is_folder = (info->folder != 0); - b8 ext_match = (match(file_extension(filename), p4c_extension) != 0); - b8 name_match = (filename_match(front_name, &absolutes, filename, case_sensitive) != 0); - b8 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 b32 -do_live_file_list_box(System_Functions *system, UI_State *state, UI_Layout *layout, - Working_Set *working_set, String *string, b32 *selected){ - b32 result = 0; - - if (do_main_string_box(system, state, layout, string)){ - *selected = 1; - terminate_with_null(string); - } - else{ - persist String message_unsaved = make_lit_string(" *"); - persist String message_unsynced = make_lit_string(" !"); - 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->state.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->name.live_name, 1)){ - if (do_file_option(100+i, state, layout, file->name.live_name, 0, message)){ - result = 1; - *selected = 1; - copy(string, file->name.live_name); - terminate_with_null(string); - } - } - } - } - } - - return result; -} - -internal i32 -step_draw_library(System_Functions *system, Exchange *exchange, Mem_Options *mem, - 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->font_set, - color_view->working_set, (message == VMSG_STEP)); - - ui.fonts = color_view->font_set; - 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; - - b32 case_sensitive = 0; - - 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, literal("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(system, 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(system, 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, literal("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, literal("Current Theme")); - do_style_preview(&ui, color_view->main_style); - - b32 file_selected = 0; - - do_label(&ui.state, &ui.layout, literal("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; - } - - b32 new_dir = 0; - if (do_file_list_box(system, &ui.state, &ui.layout, - ui.hot_directory, color_view->p4c_only, 1, case_sensitive, - &new_dir, &file_selected, 0)){ - result = 1; - } - - if (new_dir){ - hot_directory_reload(system, 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)); - - color_view->import_file_id = - exchange_request_file(exchange, - color_view->hot_directory->string.str, - color_view->hot_directory->string.size); - color_view->mode = CV_MODE_IMPORT_WAIT; - - } - }break; - - case CV_MODE_IMPORT_WAIT: - { - Style *styles = color_view->inspecting_styles.styles; - Data file; - i32 file_max; - - i32 count, max; - max = ArrayCount(color_view->inspecting_styles.styles); - - if (exchange_file_ready(exchange, color_view->import_file_id, - &file.data, &file.size, &file_max)){ - if (file.data){ - if (style_library_import(file, ui.fonts, styles, max, &count)) - color_view->mode = CV_MODE_IMPORT; - else color_view->mode = CV_MODE_LIBRARY; - color_view->inspecting_styles.count = count; - } - else{ - Assert(!"this shouldn't happen!"); - } - - exchange_free_file(exchange, color_view->import_file_id); - } - }break; - - case CV_MODE_EXPORT_FILE: - { - do_label(&ui.state, &ui.layout, literal("Current Theme")); - do_style_preview(&ui, color_view->main_style); - - b32 file_selected = 0; - - do_label(&ui.state, &ui.layout, literal("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; - } - - b32 new_dir = 0; - if (do_file_list_box(system, &ui.state, &ui.layout, - ui.hot_directory, 1, 1, case_sensitive, - &new_dir, &file_selected, ".p4c")){ - result = 1; - } - - if (new_dir){ - hot_directory_reload(system, - ui.hot_directory, ui.state.working_set); - } - if (file_selected){ - i32 count = ui.styles->count; - Temp_Memory temp = begin_temp_memory(&mem->part); - Style **styles = push_array(&mem->part, Style*, 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 *data = push_array(&mem->part, char, ui.hot_directory->string.size + 5); - String str = make_string(data, 0, ui.hot_directory->string.size + 5); - copy(&str, ui.hot_directory->string); - append(&str, make_lit_string(".p4c")); - style_library_export(system, exchange, mem, &target->font_set, str.str, styles, export_count); - - end_temp_memory(temp); - color_view->mode = CV_MODE_LIBRARY; - } - }break; - - case CV_MODE_IMPORT: - { - do_label(&ui.state, &ui.layout, literal("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, literal("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, literal("Current Theme")); - do_style_preview(&ui, color_view->main_style); - - do_label(&ui.state, &ui.layout, literal("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: - case CV_MODE_IMPORT_WAIT: - switch (message){ - case VMSG_STEP: - { - result = step_draw_library(system, exchange, view->mem, - color_view, rect, message, target, user_input); - }break; - case VMSG_DRAW: - { - step_draw_library(system, exchange, view->mem, - 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 - +/* + * 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_IMPORT_WAIT, + 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 *font_set; + u32 *palette; + Working_Set *working_set; + i32 palette_size; + Color_View_Mode mode; + UI_State state; + Super_Color color; + Color_Highlight highlight; + b32 p4c_only; + Style_Library inspecting_styles; + b8 import_export_check[64]; + i32 import_file_id; +}; + +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, f32 top, f32_Rect slider, b32 hsla){ + Vec4 low, high; + f32 *lowv, *highv; + f32 x; + f32 next_x; + f32 x_step; + f32 v_step; + f32 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, f32_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, f32 top, f32_Rect slider){ + draw_gradient_slider(target, base, channel, steps, top, slider, 0); +} + +internal void +do_label(UI_State *state, UI_Layout *layout, char *text, int text_size, f32 height = 2.f){ + Style *style = state->style; + i16 font_id = style->font_id; + i32 line_height = get_font_info(state->font_set, font_id)->height; + i32_Rect label = layout_rect(layout, FLOOR32(line_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; + + String textstr = make_string(text, text_size); + draw_string(target, font_id, textstr, label.x0, + label.y0 + (height - line_height)/2, fore); + } +} + +inline void +do_label(UI_State *state, UI_Layout *layout, String text, f32 height = 2.f){ + do_label(state, layout, text.str, text.size, height); +} + +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; + + f32 space_h = (f32)(bottom_arrow.y0 - top_arrow.y1); + if (space_h <= w) return; + + i32 slider_h = w; + + f32 view_hmin = 0; + f32 view_hmax = state->height - h; + f32 L = unlerp(view_hmin, state->view_y, view_hmax); + + f32 slider_hmin = (f32)top_arrow.y1; + f32 slider_hmax = (f32)bottom_arrow.y0 - slider_h; + f32 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, + (f32)(get_font_info(state->font_set, state->font_id)->height), + slider_hmin, slider_hmax, view_hmin, view_hmax); + } + else{ + Render_Target *target = state->target; + + f32 x0, y0, x1, y1, x2, y2; + f32 w_1_2 = w*.5f; + f32 w_1_3 = w*.333333f; + f32 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); + + ++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); + + ++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, b32 is_rgba, + i32 grad_steps, f32 top, f32_Rect slider, f32 v_handle, + i32_Rect rect){ + f32_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){ + f32_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 b32 +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){ + b32 result = 0; + + i16 font_id = ui->state.font_id; + i32 line_height = get_font_info(ui->state.font_set, font_id)->height; + i32_Rect hit_region; + hit_region.x0 = x0; + hit_region.x1 = x1; + hit_region.y0 = y; + hit_region.y1 = y + line_height; + + i32 digit_count; + if (ftype == CF_DEC) digit_count = 3; + else digit_count = 2; + + Render_Target *target = ui->state.target; + + 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_Event_Data key = get_single_key(keys, key_i); + + if (key.keycode == codes->right){ + ++indx; + if (indx > digit_count-1) indx = 0; + } + if (key.keycode == codes->left){ + --indx; + if (indx < 0) indx = digit_count-1; + } + + i32 new_value = *channel; + if (key.keycode == codes->up || 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.keycode == codes->down){ + step_amount = 0 - step_amount; + } + new_value += step_amount; + } + + u8 c = (u8)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{ + f32_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_id, 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); + + f32_Rect slider; + f32 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; + f32_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; + draw_string(target, style->font_id, "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){ + i16 font_id = ui->state.font_id; + i32 line_height = get_font_info(ui->state.font_set, font_id)->height; + i32_Rect rect = layout_rect(&ui->layout, line_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_id, 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); + i16 font_id = ui->state.font_id; + i32 character_h = get_font_info(ui->state.font_set, font_id)->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{ + Render_Target *target = ui->state.target; + 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_id, 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_id, full_hex_string, + (f32)temp_rect.x0, (f32)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){ + Render_Target *target = ui->state.target; + 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; + + i16 font_id = ui->state.font_id; + i32 line_height = get_font_info(ui->state.font_set, font_id)->height; + + i32_Rect srect = layout_rect(&ui->layout, line_height); + + Widget_ID wid = make_id(&ui->state, id); + b32 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_id, "NAME: ", + x, srect.y0, fore_label); + x = draw_string(target, font_id, style->name.str, + x, srect.y0, fore_text); + } +} + +internal b32 +do_font_option(Color_UI *ui, i16 font_id){ + b32 result = 0; + Font_Info *info = get_font_info(ui->state.font_set, font_id); + + i32 sub_id = (i32)(info); + i32_Rect orect = layout_rect(&ui->layout, info->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_id, "->", x, orect.y0, fore); + draw_string(target, font_id, info->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_Set *font_set = ui->state.font_set; + + i16 font_id = ui->state.font_id; + Font_Info *info = get_font_info(font_set, font_id); + i32 character_h = info->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_id, "FONT: ", + x, srect.y0, fore); + x = draw_string(target, font_id, info->name.str, + x, srect.y0, fore); + } + + if (is_selected(&ui->state, wid)){ + srect = layout_rect(&ui->layout, character_h/2); + if (!ui->state.input_stage) + draw_rectangle(target, srect, 0xFF000000); + + i32 count = font_set->count + 1; + + for (i16 i = 1; i < count; ++i){ + if (i == font_id) continue; + if (do_font_option(ui, i)){ + ui->state.style->font_id = i; + 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->font_set, color_view->working_set, + (message == VMSG_STEP)); + + begin_layout(&ui.layout, rect); + + ui.fonts = color_view->font_set; + 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.fonts, ui.state.font_id, "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){ + File_View *file_view = color_view->hot_file_view; + if (!file_view){ + color_view->highlight = {}; + return; + } + +#if BUFFER_EXPERIMENT_SCALPEL <= 0 + Style *style = color_view->main_style; + Editing_File *file = file_view->file; + i32 pos = view_get_cursor_pos(file_view); + char c = file->state.buffer.data[pos]; + + if (c == '\r'){ + color_view->highlight.ids[0] = + raw_ptr_dif(&style->main.special_character_color, style); + } + + else if (file->state.tokens_complete){ + Cpp_Token_Stack *tokens = &file->state.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->state.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; + } +#endif +} + +internal b32 +do_style_preview(Library_UI *ui, Style *style, i32 toggle = -1){ + b32 result = 0; + i32 id; + if (style == ui->state.style) id = 2; + else id = raw_ptr_dif(style, ui->styles->styles) + 100; + + i16 font_id = style->font_id; + Font_Info *info = get_font_info(ui->state.font_set, font_id); + + i32_Rect prect = layout_rect(&ui->layout, info->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 + info->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 = info->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 + info->height; + b.y1 = b.y0 + info->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_id, style->name.str, + text_x, text_y, style->main.default_color); + i32 font_x = (i32)(inner.x1 - font_string_width(target, font_id, info->name.str)); + if (font_x > text_x + 10) + draw_string(target, font_id, info->name.str, + font_x, text_y, style->main.default_color); + + text_x = inner.x0; + text_y += info->height; + text_x = draw_string(target, font_id, "if ", text_x, text_y, + style->main.keyword_color); + text_x = draw_string(target, font_id, "(x < ", text_x, text_y, + style->main.default_color); + text_x = draw_string(target, font_id, "0", text_x, text_y, + style->main.int_constant_color); + text_x = draw_string(target, font_id, ") { x = ", text_x, text_y, + style->main.default_color); + text_x = draw_string(target, font_id, "0", text_x, text_y, + style->main.int_constant_color); + text_x = draw_string(target, font_id, "; } ", text_x, text_y, + style->main.default_color); + text_x = draw_string(target, font_id, "// comment", text_x, text_y, + style->main.comment_color); + + text_x = inner.x0; + text_y += info->height; + text_x = draw_string(target, font_id, "[] () {}; * -> +-/ <>= ! && || % ^", + text_x, text_y, style->main.default_color); + } + + ui->layout.y = prect.y1; + return result; +} + +internal b32 +do_main_file_box(System_Functions *system, UI_State *state, UI_Layout *layout, + Hot_Directory *hot_directory, b32 try_to_match, b32 case_sensitive, char *end){ + b32 result = 0; + Style *style = state->style; + String *string = &hot_directory->string; + + i16 font_id = style->font_id; + i32 line_height = get_font_info(state->font_set, font_id)->height; + i32_Rect box = layout_rect(layout, line_height + 2); + + if (state->input_stage){ + if (ui_do_file_field_input(system, state, hot_directory, try_to_match, case_sensitive)){ + 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_id, string->str, x, box.y0, fore); + if (end) draw_string(target, font_id, end, x, box.y0, special); + } + + layout->y = box.y1; + return result; +} + +internal b32 +do_main_string_box(System_Functions *system, UI_State *state, UI_Layout *layout, String *string){ + b32 result = 0; + Style *style = state->style; + + i16 font_id = style->font_id; + i32 line_height = get_font_info(state->font_set, font_id)->height; + i32_Rect box = layout_rect(layout, line_height + 2); + + if (state->input_stage){ + if (ui_do_line_field_input(system, 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_id, string->str, x, box.y0, fore); + } + + layout->y = box.y1; + return result; +} + +internal b32 +do_list_option(i32 id, UI_State *state, UI_Layout *layout, String text){ + b32 result = 0; + Style *style = state->style; + + i16 font_id = style->font_id; + i32 character_h = get_font_info(state->font_set, font_id)->height; + + i32_Rect box = layout_rect(layout, character_h*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_id, text, x, y, fore); + draw_margin(target, box, inner, outline); + } + + layout->y = box.y1; + return result; +} + +internal b32 +do_checkbox_list_option(i32 id, UI_State *state, UI_Layout *layout, String text, b32 is_on){ + b32 result = 0; + Style *style = state->style; + + i16 font_id = style->font_id; + i32 character_h = get_font_info(state->font_set, font_id)->height; + + i32_Rect box = layout_rect(layout, character_h*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, box_color; + 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; + box_color = style->main.margin_active_color; + + draw_rectangle(target, inner, back); + + i32_Rect square; + square = get_inner_rect(inner, character_h/3); + square.x1 = square.x0 + (square.y1 - square.y0); + if (is_on) draw_rectangle(target, square, box_color); + else draw_margin(target, square, 1, box_color); + + i32 x = square.x1 + 3; + i32 y = box.y0 + character_h/2; + x = draw_string(target, font_id, text, x, y, fore); + draw_margin(target, box, inner, outline); + } + + layout->y = box.y1; + return result; +} + + +internal b32 +do_file_option(i32 id, UI_State *state, UI_Layout *layout, String filename, b32 is_folder, String extra){ + b32 result = 0; + Style *style = state->style; + i16 font_id = style->font_id; + i32 character_h = get_font_info(state->font_set, font_id)->height; + + i32_Rect box = layout_rect(layout, character_h*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_id, filename, x, y, fore); + if (is_folder) x = draw_string(target, font_id, "\\", x, y, fore); + draw_string(target, font_id, extra, x, y, pop); + draw_margin(target, box, inner, outline); + } + + layout->y = box.y1; + return result; +} + +internal b32 +do_file_list_box(System_Functions *system, UI_State *state, UI_Layout *layout, + Hot_Directory *hot_dir, b32 has_filter, b32 try_to_match, b32 case_sensitive, + b32 *new_dir, b32 *selected, char *end){ + b32 result = 0; + File_List *files = &hot_dir->file_list; + + if (do_main_file_box(system, state, layout, hot_dir, try_to_match, case_sensitive, 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 !"); + 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; + + b8 is_folder = (info->folder != 0); + b8 ext_match = (match(file_extension(filename), p4c_extension) != 0); + b8 name_match = (filename_match(front_name, &absolutes, filename, case_sensitive) != 0); + b8 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 b32 +do_live_file_list_box(System_Functions *system, UI_State *state, UI_Layout *layout, + Working_Set *working_set, String *string, b32 *selected){ + b32 result = 0; + + if (do_main_string_box(system, state, layout, string)){ + *selected = 1; + terminate_with_null(string); + } + else{ + persist String message_unsaved = make_lit_string(" *"); + persist String message_unsynced = make_lit_string(" !"); + 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->state.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->name.live_name, 1)){ + if (do_file_option(100+i, state, layout, file->name.live_name, 0, message)){ + result = 1; + *selected = 1; + copy(string, file->name.source_path); + terminate_with_null(string); + } + } + } + } + } + + return result; +} + +internal i32 +step_draw_library(System_Functions *system, Exchange *exchange, Mem_Options *mem, + 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->font_set, + color_view->working_set, (message == VMSG_STEP)); + + ui.fonts = color_view->font_set; + 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; + + b32 case_sensitive = 0; + + 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, literal("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(system, 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(system, 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, literal("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, literal("Current Theme")); + do_style_preview(&ui, color_view->main_style); + + b32 file_selected = 0; + + do_label(&ui.state, &ui.layout, literal("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; + } + + b32 new_dir = 0; + if (do_file_list_box(system, &ui.state, &ui.layout, + ui.hot_directory, color_view->p4c_only, 1, case_sensitive, + &new_dir, &file_selected, 0)){ + result = 1; + } + + if (new_dir){ + hot_directory_reload(system, 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)); + + color_view->import_file_id = + exchange_request_file(exchange, + color_view->hot_directory->string.str, + color_view->hot_directory->string.size); + color_view->mode = CV_MODE_IMPORT_WAIT; + + } + }break; + + case CV_MODE_IMPORT_WAIT: + { + Style *styles = color_view->inspecting_styles.styles; + Data file; + i32 file_max; + + i32 count, max; + max = ArrayCount(color_view->inspecting_styles.styles); + + if (exchange_file_ready(exchange, color_view->import_file_id, + &file.data, &file.size, &file_max)){ + if (file.data){ + if (style_library_import(file, ui.fonts, styles, max, &count)) + color_view->mode = CV_MODE_IMPORT; + else color_view->mode = CV_MODE_LIBRARY; + color_view->inspecting_styles.count = count; + } + else{ + Assert(!"this shouldn't happen!"); + } + + exchange_free_file(exchange, color_view->import_file_id); + } + }break; + + case CV_MODE_EXPORT_FILE: + { + do_label(&ui.state, &ui.layout, literal("Current Theme")); + do_style_preview(&ui, color_view->main_style); + + b32 file_selected = 0; + + do_label(&ui.state, &ui.layout, literal("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; + } + + b32 new_dir = 0; + if (do_file_list_box(system, &ui.state, &ui.layout, + ui.hot_directory, 1, 1, case_sensitive, + &new_dir, &file_selected, ".p4c")){ + result = 1; + } + + if (new_dir){ + hot_directory_reload(system, + ui.hot_directory, ui.state.working_set); + } + if (file_selected){ + i32 count = ui.styles->count; + Temp_Memory temp = begin_temp_memory(&mem->part); + Style **styles = push_array(&mem->part, Style*, 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 *data = push_array(&mem->part, char, ui.hot_directory->string.size + 5); + String str = make_string(data, 0, ui.hot_directory->string.size + 5); + copy(&str, ui.hot_directory->string); + append(&str, make_lit_string(".p4c")); + style_library_export(system, exchange, mem, &target->font_set, str.str, styles, export_count); + + end_temp_memory(temp); + color_view->mode = CV_MODE_LIBRARY; + } + }break; + + case CV_MODE_IMPORT: + { + do_label(&ui.state, &ui.layout, literal("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, literal("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, literal("Current Theme")); + do_style_preview(&ui, color_view->main_style); + + do_label(&ui.state, &ui.layout, literal("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: + case CV_MODE_IMPORT_WAIT: + switch (message){ + case VMSG_STEP: + { + result = step_draw_library(system, exchange, view->mem, + color_view, rect, message, target, user_input); + }break; + case VMSG_DRAW: + { + step_draw_library(system, exchange, view->mem, + 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 + diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index e05a10d4..6ff91341 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -1205,15 +1205,18 @@ file_init_strings(Editing_File *file){ inline void file_set_name(Editing_File *file, char *filename){ - if (file->name.live_name.str == 0) file_init_strings(file); - if (filename[0] == '*'){ - copy(&file->name.live_name, filename); + String f, ext; + + Assert(file->name.live_name.str != 0); + + f = make_string_slowly(filename); + copy_checked(&file->name.source_path, f); + file->name.live_name.size = 0; + get_front_of_directory(&file->name.live_name, f); + if (file->name.source_path.size == file->name.live_name.size){ + file->name.extension.size = 0; } else{ - String f, ext; - f = make_string_slowly(filename); - copy_checked(&file->name.source_path, f); - get_front_of_directory(&file->name.live_name, f); ext = file_extension(f); copy(&file->name.extension, ext); } @@ -1270,8 +1273,8 @@ inline b32 file_save_and_set_names(System_Functions *system, Exchange *exchange, Mem_Options *mem, Editing_File *file, char *filename){ b32 result = 0; - if (file_save(system, exchange, mem, file, filename)){ - result = 1; + result = file_save(system, exchange, mem, file, filename); + if (result){ file_set_name(file, filename); } return result; @@ -2223,7 +2226,7 @@ view_compute_cursor_from_unwrapped_xy(File_View *view, f32 seek_x, f32 seek_y, #endif } -inline Full_Cursor +internal Full_Cursor view_compute_cursor_from_wrapped_xy(File_View *view, f32 seek_x, f32 seek_y, b32 round_down = 0){ #if BUFFER_EXPERIMENT_SCALPEL <= 3 @@ -2246,7 +2249,7 @@ view_compute_cursor_from_wrapped_xy(File_View *view, f32 seek_x, f32 seek_y, #endif } -inline Full_Cursor +internal Full_Cursor view_compute_cursor_from_line_pos(File_View *view, i32 line, i32 pos){ #if BUFFER_EXPERIMENT_SCALPEL <= 3 Editing_File *file = view->file; @@ -2726,20 +2729,22 @@ file_edit_cursor_fix(System_Functions *system, Editing_File *file, Editing_Layout *layout, Cursor_Fix_Descriptor desc){ Full_Cursor temp_cursor; + File_View *current_view; Temp_Memory cursor_temp = begin_temp_memory(part); i32 cursor_max = layout->panel_max_count * 2; Cursor_With_Index *cursors = push_array(part, Cursor_With_Index, cursor_max); + f32 y_offset = 0, y_position = 0; i32 cursor_count = 0; i32 panel_count = layout->panel_count; Panel *current_panel = layout->panels; for (i32 i = 0; i < panel_count; ++i, ++current_panel){ - File_View *current_view = view_to_file_view(current_panel->view); + current_view = view_to_file_view(current_panel->view); if (current_view && current_view->file == file){ view_measure_wraps(system, general, current_view); write_cursor_with_index(cursors, &cursor_count, current_view->cursor.pos); write_cursor_with_index(cursors, &cursor_count, current_view->mark); - write_cursor_with_index(cursors, &cursor_count, current_view->scroll_i); + write_cursor_with_index(cursors, &cursor_count, current_view->scroll_i - 1); } } @@ -2760,21 +2765,25 @@ file_edit_cursor_fix(System_Functions *system, cursor_count = 0; current_panel = layout->panels; for (i32 i = 0; i < panel_count; ++i, ++current_panel){ - File_View *current_view = view_to_file_view(current_panel->view); + current_view = view_to_file_view(current_panel->view); if (current_view && current_view->file == file){ view_cursor_move(current_view, cursors[cursor_count++].pos); current_view->preferred_x = view_get_cursor_x(current_view); current_view->mark = cursors[cursor_count++].pos; - current_view->scroll_i = cursors[cursor_count++].pos; + current_view->scroll_i = cursors[cursor_count++].pos + 1; temp_cursor = view_compute_cursor_from_pos(current_view, current_view->scroll_i); + y_offset = MOD(current_view->scroll_y, current_view->font_height); + if (current_view->unwrapped_lines){ - current_view->target_y += (temp_cursor.unwrapped_y - current_view->scroll_y); - current_view->scroll_y = temp_cursor.unwrapped_y; + y_position = temp_cursor.unwrapped_y + y_offset; + current_view->target_y += (y_position - current_view->scroll_y); + current_view->scroll_y = y_position; } else{ - current_view->target_y += (temp_cursor.wrapped_y - current_view->scroll_y); - current_view->scroll_y = temp_cursor.wrapped_y; + y_position = temp_cursor.wrapped_y + y_offset; + current_view->target_y += (y_position - current_view->scroll_y); + current_view->scroll_y = y_position; } } } @@ -4189,19 +4198,19 @@ draw_file_bar(File_View *view, Interactive_Bar *bar, Render_Target *target){ intbar_draw_string(target, bar, line_number, base_color); - if (file){ + if (!file->settings.unimportant){ switch (buffer_get_sync(file)){ - case SYNC_BEHIND_OS: - { - persist String out_of_sync = make_lit_string(" !"); - intbar_draw_string(target, bar, out_of_sync, pop2_color); - }break; - - case SYNC_UNSAVED: - { - persist String out_of_sync = make_lit_string(" *"); - intbar_draw_string(target, bar, out_of_sync, pop2_color); - }break; + case SYNC_BEHIND_OS: + { + persist String out_of_sync = make_lit_string(" !"); + intbar_draw_string(target, bar, out_of_sync, pop2_color); + }break; + + case SYNC_UNSAVED: + { + persist String out_of_sync = make_lit_string(" *"); + intbar_draw_string(target, bar, out_of_sync, pop2_color); + }break; } } } diff --git a/4ed_interactive_view.cpp b/4ed_interactive_view.cpp index 014f274e..3cdfcde4 100644 --- a/4ed_interactive_view.cpp +++ b/4ed_interactive_view.cpp @@ -1,230 +1,230 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 19.09.2015 - * - * File editing view for 4coder - * - */ - -// TOP - -enum Interactive_View_Action{ - INTV_OPEN, - INTV_SAVE_AS, - INTV_NEW, - INTV_SWITCH, - INTV_KILL, - INTV_SURE_TO_KILL -}; - -enum Interactive_View_Interaction{ - INTV_SYS_FILE_LIST, - INTV_LIVE_FILE_LIST, - INTV_SURE_TO_KILL_INTER -}; - -struct Interactive_View{ - View view_base; - Hot_Directory *hot_directory; - Style *style; - Working_Set *working_set; - Delay *delay; - Font_Set *font_set; - UI_State state; - Interactive_View_Interaction interaction; - Interactive_View_Action action; - - char query_[256]; - String query; - char dest_[256]; - String dest; - i32 user_action; -}; - -inline Interactive_View* -view_to_interactive_view(View *view){ - Interactive_View *result = 0; - if (view->type == VIEW_TYPE_INTERACTIVE) - result = (Interactive_View*)view; - return result; -} - -internal void -interactive_view_complete(Interactive_View *view){ - Panel *panel = view->view_base.panel; - switch (view->action){ - case INTV_OPEN: - delayed_action(view->delay, DACT_OPEN, - view->hot_directory->string, panel); - break; - - case INTV_SAVE_AS: - delayed_action(view->delay, DACT_SAVE_AS, view->hot_directory->string, panel); - delayed_action(view->delay, DACT_CLOSE_MINOR, {}, panel); - break; - - case INTV_NEW: - delayed_action(view->delay, DACT_NEW, view->hot_directory->string, panel); - break; - - case INTV_SWITCH: - delayed_action(view->delay, DACT_SWITCH, view->dest, panel); - break; - - case INTV_KILL: - delayed_action(view->delay, DACT_TRY_KILL, view->dest, panel); - break; - - case INTV_SURE_TO_KILL: - switch (view->user_action){ - case 0: - delayed_action(view->delay, DACT_KILL, view->dest, panel); - delayed_action(view->delay, DACT_CLOSE_MINOR, {}, panel); - break; - - case 1: - delayed_action(view->delay, DACT_CLOSE_MINOR, {}, panel); - break; - - case 2: - delayed_action(view->delay, DACT_SAVE, view->dest, panel); - delayed_action(view->delay, DACT_KILL, view->dest, panel); - delayed_action(view->delay, DACT_CLOSE_MINOR, {}, panel); - break; - } - break; - } -} - -internal i32 -step_draw_int_view(System_Functions *system, Interactive_View *view, - Render_Target *target, i32_Rect rect, - Input_Summary *user_input, b32 input_stage){ - i32 result = 0; - - UI_State state = - ui_state_init(&view->state, target, user_input, - view->style, view->font_set, view->working_set, input_stage); - - UI_Layout layout; - begin_layout(&layout, rect); - - b32 new_dir = 0; - b32 complete = 0; - - do_label(&state, &layout, view->query, 1.f); - - b32 case_sensitive = 0; - - switch (view->interaction){ - case INTV_SYS_FILE_LIST: - { - b32 is_new = (view->action == INTV_NEW); - - if (do_file_list_box(system, &state, - &layout, view->hot_directory, 0, !is_new, case_sensitive, - &new_dir, &complete, 0)){ - result = 1; - } - if (new_dir){ - hot_directory_reload(system, - view->hot_directory, view->working_set); - } - }break; - - case INTV_LIVE_FILE_LIST: - if (do_live_file_list_box(system, &state, &layout, view->working_set, &view->dest, &complete)){ - result = 1; - } - break; - - case INTV_SURE_TO_KILL_INTER: - { - i32 action = -1; - char s_[256]; - String s = make_fixed_width_string(s_); - append(&s, view->dest); - append(&s, " has unsaved changes, kill it?"); - do_label(&state, &layout, s, 1.f); - - i32 id = 0; - if (do_list_option(++id, &state, &layout, make_lit_string("(Y)es"))){ - action = 0; - } - - if (do_list_option(++id, &state, &layout, make_lit_string("(N)o"))){ - action = 1; - } - - if (do_list_option(++id, &state, &layout, make_lit_string("(S)ave and kill"))){ - action = 2; - } - - if (action == -1 && input_stage){ - i32 key_count = user_input->keys.count; - for (i32 i = 0; i < key_count; ++i){ - Key_Event_Data key = user_input->keys.keys[i]; - switch (key.character){ - case 'y': case 'Y': action = 0; break; - case 'n': case 'N': action = 1; break; - case 's': case 'S': action = 2; break; - } - if (action == -1 && key.keycode == state.codes->esc) action = 1; - if (action != -1) break; - } - } - - if (action != -1){ - complete = 1; - view->user_action = action; - } - }break; - } - - if (complete){ - interactive_view_complete(view); - } - - if (ui_finish_frame(&view->state, &state, &layout, rect, 0, 0)){ - result = 1; - } - - return result; -} - -Do_View_Sig(do_interactive_view){ - i32 result = 0; - - view->mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; - Interactive_View *int_view = (Interactive_View*)view; - switch (message){ - case VMSG_STEP: case VMSG_DRAW: - result = step_draw_int_view(system, int_view, target, rect, user_input, (message == VMSG_STEP)); - break; - } - - return result; -} - -internal Interactive_View* -interactive_view_init(System_Functions *system, View *view, - Hot_Directory *hot_dir, Style *style, - Working_Set *working_set, Font_Set *font_set, Delay *delay){ - Interactive_View *result = (Interactive_View*)view; - view->type = VIEW_TYPE_INTERACTIVE; - view->do_view = do_interactive_view; - result->hot_directory = hot_dir; - hot_directory_clean_end(hot_dir); - hot_directory_reload(system, hot_dir, working_set); - result->query = make_fixed_width_string(result->query_); - result->dest = make_fixed_width_string(result->dest_); - result->style = style; - result->working_set = working_set; - result->font_set = font_set; - result->delay = delay; - return result; -} - -// BOTTOM - +/* + * Mr. 4th Dimention - Allen Webster + * + * 19.09.2015 + * + * File editing view for 4coder + * + */ + +// TOP + +enum Interactive_View_Action{ + INTV_OPEN, + INTV_SAVE_AS, + INTV_NEW, + INTV_SWITCH, + INTV_KILL, + INTV_SURE_TO_KILL +}; + +enum Interactive_View_Interaction{ + INTV_SYS_FILE_LIST, + INTV_LIVE_FILE_LIST, + INTV_SURE_TO_KILL_INTER +}; + +struct Interactive_View{ + View view_base; + Hot_Directory *hot_directory; + Style *style; + Working_Set *working_set; + Delay *delay; + Font_Set *font_set; + UI_State state; + Interactive_View_Interaction interaction; + Interactive_View_Action action; + + char query_[256]; + String query; + char dest_[256]; + String dest; + i32 user_action; +}; + +inline Interactive_View* +view_to_interactive_view(View *view){ + Interactive_View *result = 0; + if (view->type == VIEW_TYPE_INTERACTIVE) + result = (Interactive_View*)view; + return result; +} + +internal void +interactive_view_complete(Interactive_View *view){ + Panel *panel = view->view_base.panel; + switch (view->action){ + case INTV_OPEN: + delayed_action(view->delay, DACT_OPEN, + view->hot_directory->string, panel); + break; + + case INTV_SAVE_AS: + delayed_action(view->delay, DACT_SAVE_AS, view->hot_directory->string, panel); + delayed_action(view->delay, DACT_CLOSE_MINOR, {}, panel); + break; + + case INTV_NEW: + delayed_action(view->delay, DACT_NEW, view->hot_directory->string, panel); + break; + + case INTV_SWITCH: + delayed_action(view->delay, DACT_SWITCH, view->dest, panel); + break; + + case INTV_KILL: + delayed_action(view->delay, DACT_TRY_KILL, view->dest, panel); + break; + + case INTV_SURE_TO_KILL: + switch (view->user_action){ + case 0: + delayed_action(view->delay, DACT_KILL, view->dest, panel); + delayed_action(view->delay, DACT_CLOSE_MINOR, {}, panel); + break; + + case 1: + delayed_action(view->delay, DACT_CLOSE_MINOR, {}, panel); + break; + + case 2: + delayed_action(view->delay, DACT_SAVE, view->dest, panel); + delayed_action(view->delay, DACT_KILL, view->dest, panel); + delayed_action(view->delay, DACT_CLOSE_MINOR, {}, panel); + break; + } + break; + } +} + +internal i32 +step_draw_int_view(System_Functions *system, Interactive_View *view, + Render_Target *target, i32_Rect rect, + Input_Summary *user_input, b32 input_stage){ + i32 result = 0; + + UI_State state = + ui_state_init(&view->state, target, user_input, + view->style, view->font_set, view->working_set, input_stage); + + UI_Layout layout; + begin_layout(&layout, rect); + + b32 new_dir = 0; + b32 complete = 0; + + do_label(&state, &layout, view->query, 1.f); + + b32 case_sensitive = 0; + + switch (view->interaction){ + case INTV_SYS_FILE_LIST: + { + b32 is_new = (view->action == INTV_NEW); + + if (do_file_list_box(system, &state, + &layout, view->hot_directory, 0, !is_new, case_sensitive, + &new_dir, &complete, 0)){ + result = 1; + } + if (new_dir){ + hot_directory_reload(system, + view->hot_directory, view->working_set); + } + }break; + + case INTV_LIVE_FILE_LIST: + if (do_live_file_list_box(system, &state, &layout, view->working_set, &view->dest, &complete)){ + result = 1; + } + break; + + case INTV_SURE_TO_KILL_INTER: + { + i32 action = -1; + char s_[256]; + String s = make_fixed_width_string(s_); + append(&s, view->dest); + append(&s, " has unsaved changes, kill it?"); + do_label(&state, &layout, s, 1.f); + + i32 id = 0; + if (do_list_option(++id, &state, &layout, make_lit_string("(Y)es"))){ + action = 0; + } + + if (do_list_option(++id, &state, &layout, make_lit_string("(N)o"))){ + action = 1; + } + + if (do_list_option(++id, &state, &layout, make_lit_string("(S)ave and kill"))){ + action = 2; + } + + if (action == -1 && input_stage){ + i32 key_count = user_input->keys.count; + for (i32 i = 0; i < key_count; ++i){ + Key_Event_Data key = user_input->keys.keys[i]; + switch (key.character){ + case 'y': case 'Y': action = 0; break; + case 'n': case 'N': action = 1; break; + case 's': case 'S': action = 2; break; + } + if (action == -1 && key.keycode == state.codes->esc) action = 1; + if (action != -1) break; + } + } + + if (action != -1){ + complete = 1; + view->user_action = action; + } + }break; + } + + if (complete){ + interactive_view_complete(view); + } + + if (ui_finish_frame(&view->state, &state, &layout, rect, 0, 0)){ + result = 1; + } + + return result; +} + +Do_View_Sig(do_interactive_view){ + i32 result = 0; + + view->mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; + Interactive_View *int_view = (Interactive_View*)view; + switch (message){ + case VMSG_STEP: case VMSG_DRAW: + result = step_draw_int_view(system, int_view, target, rect, user_input, (message == VMSG_STEP)); + break; + } + + return result; +} + +internal Interactive_View* +interactive_view_init(System_Functions *system, View *view, + Hot_Directory *hot_dir, Style *style, + Working_Set *working_set, Font_Set *font_set, Delay *delay){ + Interactive_View *result = (Interactive_View*)view; + view->type = VIEW_TYPE_INTERACTIVE; + view->do_view = do_interactive_view; + result->hot_directory = hot_dir; + hot_directory_clean_end(hot_dir); + hot_directory_reload(system, hot_dir, working_set); + result->query = make_fixed_width_string(result->query_); + result->dest = make_fixed_width_string(result->dest_); + result->style = style; + result->working_set = working_set; + result->font_set = font_set; + result->delay = delay; + return result; +} + +// BOTTOM + diff --git a/4ed_math.cpp b/4ed_math.cpp index c82c5c44..6892e94a 100644 --- a/4ed_math.cpp +++ b/4ed_math.cpp @@ -1,774 +1,774 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 15.05.2015 - * - * Math functions for 4coder - * - */ - -// TOP - -/* - * Scalar operators - */ - -#define C_MATH 1 - -#define DEG_TO_RAD 0.0174533f - -#if C_MATH -#include -#endif - -inline real32 -ABS(real32 x){ - if (x < 0) x = -x; - return x; -} - -inline real32 -MOD(real32 x, i32 m){ -#if C_MATH - real32 whole, frac; - frac = modff(x, &whole); - return ((i32)(whole) % m) + frac; -#endif -} - -inline real32 -SQRT(real32 x){ -#if C_MATH - return sqrt(x); -#endif -} - -inline real32 -SIN(real32 x_degrees){ -#if C_MATH - return sinf(x_degrees * DEG_TO_RAD); -#endif -} - -inline real32 -COS(real32 x_degrees){ -#if C_MATH - return cosf(x_degrees * DEG_TO_RAD); -#endif -} - -/* - * Rounding - */ - -inline i32 -TRUNC32(real32 x) { return (i32)x; } - -inline i32 -FLOOR32(real32 x) { return (i32)(x)-((x!=(i32)(x) && x<0)?1:0); } - -inline i32 -CEIL32(real32 x) { return (i32)(x)+((x!=(i32)(x) && x>0)?1:0); } - -inline i32 -ROUND32(real32 x) { return FLOOR32(x + .5f); } - -inline i32 -DIVCEIL32(i32 n, i32 d) { - i32 q = (n/d); - return q + (q*d < n); -} - -inline real32 -FRACPART32(real32 x) { return x - (i32)x; } - -inline u32 -ROUNDPOT32(u32 v){ - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - return v; -} - -/* - * Rectangles - */ - -struct i32_Rect{ - i32 x0, y0; - i32 x1, y1; -}; - -struct f32_Rect{ - f32 x0, y0; - f32 x1, y1; -}; - -inline i32_Rect -i32R(i32 l, i32 t, i32 r, i32 b){ - i32_Rect rect; - rect.x0 = l; rect.y0 = t; - rect.x1 = r; rect.y1 = b; - return rect; -} - -inline i32_Rect -i32R(f32_Rect r){ - i32_Rect rect; - rect.x0 = (i32)r.x0; - rect.y0 = (i32)r.y0; - rect.x1 = (i32)r.x1; - rect.y1 = (i32)r.y1; - return rect; -} - -inline i32_Rect -i32XYWH(i32 x, i32 y, i32 w, i32 h){ - i32_Rect rect; - rect.x0 = x; rect.y0 = y; - rect.x1 = x+w; rect.y1 = y+h; - return rect; -} - -inline f32_Rect -f32R(f32 l, f32 t, f32 r, f32 b){ - f32_Rect rect; - rect.x0 = l; rect.y0 = t; - rect.x1 = r; rect.y1 = b; - return rect; -} - -inline f32_Rect -f32R(i32_Rect r){ - f32_Rect rect; - rect.x0 = (f32)r.x0; - rect.y0 = (f32)r.y0; - rect.x1 = (f32)r.x1; - rect.y1 = (f32)r.y1; - return rect; -} - -inline f32_Rect -f32XYWH(f32 x, f32 y, f32 w, f32 h){ - f32_Rect rect; - rect.x0 = x; rect.y0 = y; - rect.x1 = x+w; rect.y1 = y+h; - return rect; -} - -inline b32 -hit_check(i32 x, i32 y, i32 x0, i32 y0, i32 x1, i32 y1){ - return (x >= x0 && x < x1 && y >= y0 && y < y1); -} - -inline b32 -hit_check(i32 x, i32 y, i32_Rect rect){ - return (hit_check(x, y, rect.x0, rect.y0, rect.x1, rect.y1)); -} - -inline b32 -hit_check(i32 x, i32 y, f32 x0, f32 y0, f32 x1, f32 y1){ - return (x >= x0 && x < x1 && y >= y0 && y < y1); -} - -inline b32 -hit_check(i32 x, i32 y, f32_Rect rect){ - return (hit_check(x, y, rect.x0, rect.y0, rect.x1, rect.y1)); -} - -inline b32 -positive_area(i32_Rect rect){ - return (rect.x0 < rect.x1 && rect.y0 < rect.y1); -} - -inline i32_Rect -get_inner_rect(i32_Rect outer, i32 margin){ - i32_Rect r; - r.x0 = outer.x0 + margin; - r.y0 = outer.y0 + margin; - r.x1 = outer.x1 - margin; - r.y1 = outer.y1 - margin; - return r; -} - -inline b32 -fits_inside(i32_Rect rect, i32_Rect outer){ - return (rect.x0 >= outer.x0 && rect.x1 <= outer.x1 && - rect.y0 >= outer.y0 && rect.y1 <= outer.y1); -} - -inline i32_Rect -rect_clamp_to_rect(i32_Rect rect, i32_Rect clamp_box){ - if (rect.x0 < clamp_box.x0) rect.x0 = clamp_box.x0; - if (rect.y0 < clamp_box.y0) rect.y0 = clamp_box.y0; - if (rect.x1 > clamp_box.x1) rect.x1 = clamp_box.x1; - if (rect.y1 > clamp_box.y1) rect.y1 = clamp_box.y1; - return rect; -} - -inline i32_Rect -rect_clamp_to_rect(i32 left, i32 top, i32 right, i32 bottom, i32_Rect clamp_box){ - return rect_clamp_to_rect(i32R(left, top, right, bottom), clamp_box); -} - -/* - * Vectors - */ - -struct Vec2{ - union{ - struct{ - real32 x, y; - }; - struct{ - real32 v[2]; - }; - }; -}; - -struct Vec3{ - union{ - struct{ - real32 x, y, z; - }; - struct{ - real32 r, g, b; - }; - struct{ - Vec2 xy; - real32 _z; - }; - struct{ - real32 _x; - Vec2 yz; - }; - struct{ - real32 v[3]; - }; - }; -}; - -struct Vec4{ - union{ - struct{ - real32 r, g, b, a; - }; - - struct{ - real32 h, s, l, __a; - }; - struct{ - real32 x, y, z, w; - }; - struct{ - Vec3 rgb; - real32 _a; - }; - struct{ - Vec3 xyz; - real32 _w; - }; - struct{ - real32 _x; - Vec3 yzw; - }; - struct{ - real32 v[4]; - }; - }; -}; - -inline internal Vec2 -V2(real32 x, real32 y){ - Vec2 result; - result.x = x; - result.y = y; - return result; -} - -inline internal Vec3 -V3(real32 x, real32 y, real32 z){ - Vec3 result; - result.x = x; - result.y = y; - result.z = z; - return result; -} - -inline internal Vec4 -V4(real32 x, real32 y, real32 z, real32 w){ - Vec4 result; - result.x = x; - result.y = y; - result.z = z; - result.w = w; - return result; -} - -inline internal Vec2 -operator+(Vec2 a, Vec2 b){ - Vec2 result; - result.x = a.x + b.x; - result.y = a.y + b.y; - return result; -} - -inline internal Vec3 -operator+(Vec3 a, Vec3 b){ - Vec3 result; - result.x = a.x + b.x; - result.y = a.y + b.y; - result.z = a.z + b.z; - return result; -} - -inline internal Vec4 -operator+(Vec4 a, Vec4 b){ - Vec4 result; - result.x = a.x + b.x; - result.y = a.y + b.y; - result.z = a.z + b.z; - result.w = a.w + b.w; - return result; -} - -inline internal Vec2 -operator-(Vec2 a, Vec2 b){ - Vec2 result; - result.x = a.x - b.x; - result.y = a.y - b.y; - return result; -} - -inline internal Vec3 -operator-(Vec3 a, Vec3 b){ - Vec3 result; - result.x = a.x - b.x; - result.y = a.y - b.y; - result.z = a.z - b.z; - return result; -} - -inline internal Vec4 -operator-(Vec4 a, Vec4 b){ - Vec4 result; - result.x = a.x - b.x; - result.y = a.y - b.y; - result.z = a.z - b.z; - result.w = a.w - b.w; - return result; -} - -inline internal Vec2 -operator*(Vec2 a, real32 k){ - Vec2 result; - result.x = a.x * k; - result.y = a.y * k; - return result; -} - -inline internal Vec3 -operator*(Vec3 a, real32 k){ - Vec3 result; - result.x = a.x * k; - result.y = a.y * k; - result.z = a.z * k; - return result; -} - -inline internal Vec4 -operator*(Vec4 a, real32 k){ - Vec4 result; - result.x = a.x * k; - result.y = a.y * k; - result.z = a.z * k; - result.w = a.w * k; - return result; -} - -inline internal Vec2 -operator*(real32 k, Vec2 a){ - Vec2 result; - result.x = a.x * k; - result.y = a.y * k; - return result; -} - -inline internal Vec3 -operator*(real32 k, Vec3 a){ - Vec3 result; - result.x = a.x * k; - result.y = a.y * k; - result.z = a.z * k; - return result; -} - -inline internal Vec4 -operator*(real32 k, Vec4 a){ - Vec4 result; - result.x = a.x * k; - result.y = a.y * k; - result.z = a.z * k; - result.w = a.w * k; - return result; -} - -inline internal Vec2& -operator+=(Vec2 &a, Vec2 b){ - a = (a + b); - return a; -} - -inline internal Vec3& -operator+=(Vec3 &a, Vec3 b){ - a = (a + b); - return a; -} - -inline internal Vec4& -operator+=(Vec4 &a, Vec4 b){ - a = (a + b); - return a; -} - -inline internal Vec2& -operator-=(Vec2 &a, Vec2 b){ - a = (a - b); - return a; -} - -inline internal Vec3& -operator-=(Vec3 &a, Vec3 b){ - a = (a - b); - return a; -} - -inline internal Vec4& -operator-=(Vec4 &a, Vec4 b){ - a = (a - b); - return a; -} - -inline internal Vec2& -operator*=(Vec2 &a, real32 k){ - a = (a * k); - return a; -} - -inline internal Vec3& -operator*=(Vec3 &a, real32 k){ - a = (a * k); - return a; -} - -inline internal Vec4& -operator*=(Vec4 &a, real32 k){ - a = (a * k); - return a; -} - -inline internal real32 -dot(Vec2 a, Vec2 b){ - real32 result; - result = a.x*b.x + a.y*b.y; - return result; -} - -inline internal real32 -dot(Vec3 a, Vec3 b){ - real32 result; - result = a.x*b.x + a.y*b.y + a.z*b.z; - return result; -} - -inline internal real32 -dot(Vec4 a, Vec4 b){ - real32 result; - result = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; - return result; -} - -inline internal Vec3 -cross(Vec3 a, Vec3 b){ - Vec3 result; - result.x = a.y*b.z - b.y*a.z; - result.y = a.z*b.x - b.z*a.x; - result.z = a.x*b.y - b.x*a.y; - return result; -} - -inline internal Vec2 -hadamard(Vec2 a, Vec2 b){ - Vec2 result; - result.x = a.x*b.x; - result.y = a.y*b.y; - return result; -} - -inline internal Vec3 -hadamard(Vec3 a, Vec3 b){ - Vec3 result; - result.x = a.x*b.x; - result.y = a.y*b.y; - result.z = a.z*b.z; - return result; -} - -inline internal Vec4 -hadamard(Vec4 a, Vec4 b){ - Vec4 result; - result.x = a.x*b.x; - result.y = a.y*b.y; - result.z = a.z*b.z; - result.w = a.w*b.w; - return result; -} - -inline internal Vec2 -perp(Vec2 v){ - Vec2 result; - result.x = -v.y; - result.y = v.x; - return result; -} - -inline Vec2 -polar_to_cartesian(real32 theta_degrees, real32 length){ - Vec2 result; - result.x = COS(theta_degrees)*length; - result.y = SIN(theta_degrees)*length; - return result; -} - -inline Vec2 -rotate(Vec2 v, real32 theta_degrees){ - Vec2 result; - real32 c, s; - c = COS(theta_degrees); - s = SIN(theta_degrees); - result.x = v.x*c - v.y*s; - result.y = v.x*s + v.y*c; - return result; -} - -/* - * Coordinates - */ - -struct Matrix2{ - Vec2 x_axis; - Vec2 y_axis; -}; - -internal Matrix2 -invert(Vec2 x_axis, Vec2 y_axis){ - Matrix2 result = {}; - real32 det = 1.f / (x_axis.x*y_axis.y - x_axis.y*y_axis.x); - result.x_axis.x = y_axis.y*det; - result.y_axis.x = -y_axis.x*det; - result.x_axis.y = -x_axis.y*det; - result.y_axis.y = x_axis.x*det; - return result; -} - -internal Matrix2 -invert(Matrix2 m){ - Matrix2 result = {}; - real32 det = 1.f / (m.x_axis.x*m.y_axis.y - m.x_axis.y*m.y_axis.x); - result.x_axis.x = m.y_axis.y*det; - result.y_axis.x = -m.y_axis.x*det; - result.x_axis.y = -m.x_axis.y*det; - result.y_axis.y = m.x_axis.x*det; - return result; -} - -/* - * Lerps, Clamps, Thresholds, Etc - */ - -inline real32 -lerp(real32 a, real32 t, real32 b){ - return a + (b-a)*t; -} - -inline Vec2 -lerp(Vec2 a, real32 t, Vec2 b){ - return a + (b-a)*t; -} - -inline Vec3 -lerp(Vec3 a, real32 t, Vec3 b){ - return a + (b-a)*t; -} - -inline Vec4 -lerp(Vec4 a, real32 t, Vec4 b){ - return a + (b-a)*t; -} - -inline real32 -unlerp(real32 a, real32 x, real32 b){ - return (x - a) / (b - a); -} - -inline real32 -clamp(real32 a, real32 n, real32 z){ - return (nz)?(z):n); -} - -/* - * Color - */ - -// TODO(allen): Convert colors to Vec4 -inline internal u32 -color_blend(u32 a, real32 t, u32 b){ - union{ - u8 byte[4]; - u32 comp; - } A, B, R; - - A.comp = a; - B.comp = b; - - R.byte[0] = (u8)lerp(A.byte[0], t, B.byte[0]); - R.byte[1] = (u8)lerp(A.byte[1], t, B.byte[1]); - R.byte[2] = (u8)lerp(A.byte[2], t, B.byte[2]); - R.byte[3] = (u8)lerp(A.byte[3], t, B.byte[3]); - - return R.comp; -} - -internal Vec3 -unpack_color3(u32 color){ - Vec3 result; - result.r = ((color >> 16) & 0xFF) / 255.f; - result.g = ((color >> 8) & 0xFF) / 255.f; - result.b = ((color >> 0) & 0xFF) / 255.f; - return result; -} - -internal Vec4 -unpack_color4(u32 color){ - Vec4 result; - result.a = ((color >> 24) & 0xFF) / 255.f; - result.r = ((color >> 16) & 0xFF) / 255.f; - result.g = ((color >> 8) & 0xFF) / 255.f; - result.b = ((color >> 0) & 0xFF) / 255.f; - return result; -} - -internal u32 -pack_color4(Vec4 color){ - u32 result = - ((u8)(color.a * 255) << 24) | - ((u8)(color.r * 255) << 16) | - ((u8)(color.g * 255) << 8) | - ((u8)(color.b * 255) << 0); - return result; -} - -internal Vec4 -rgba_to_hsla(Vec4 rgba){ - Vec4 hsla = {}; - real32 max, min, delta; - i32 maxc; - hsla.a = rgba.a; - max = rgba.r; min = rgba.r; - maxc = 0; - if (rgba.r < rgba.g){ - max = rgba.g; - maxc = 1; - } - if (rgba.b > max){ - max = rgba.b; - maxc = 2; - } - if (rgba.r > rgba.g){ - min = rgba.g; - } - if (rgba.b < min){ - min = rgba.b; - } - delta = max - min; - - hsla.z = (max + min) * .5f; - if (delta == 0){ - hsla.x = 0.f; - hsla.y = 0.f; - } - else{ - switch (maxc){ - case 0: - { - hsla.x = (rgba.g - rgba.b) / delta; - hsla.x += (rgba.g < rgba.b) * 6.f; - }break; - - case 1: - { - hsla.x = (rgba.b - rgba.r) / delta; - hsla.x += 2.f; - }break; - - case 2: - { - hsla.x = (rgba.r - rgba.g) / delta; - hsla.x += 4.f; - }break; - } - hsla.x *= (1/6.f); // * 60 / 360 - hsla.y = delta / (1.f - ABS(2.f*hsla.z - 1.f)); - } - - return hsla; -} - -internal Vec4 -hsla_to_rgba(Vec4 hsla){ - if (hsla.h >= 1.f) hsla.h = 0.f; - Vec4 rgba = {}; - real32 C, X, m; - i32 H; - rgba.a = hsla.a; - C = (1.f - ABS(2*hsla.z - 1.f)) * hsla.y; - X = C * (1.f-ABS(MOD(hsla.x*6.f, 2)-1.f)); - m = hsla.z - C*.5f; - H = FLOOR32(hsla.x * 6.f); - switch (H){ - case 0: - rgba.r = C; rgba.g = X; rgba.b = 0; - break; - - case 1: - rgba.r = X; rgba.g = C; rgba.b = 0; - break; - - case 2: - rgba.r = 0; rgba.g = C; rgba.b = X; - break; - - case 3: - rgba.r = 0; rgba.g = X; rgba.b = C; - break; - - case 4: - rgba.r = X; rgba.g = 0; rgba.b = C; - break; - - case 5: - rgba.r = C; rgba.g = 0; rgba.b = X; - break; - } - rgba.r += m; - rgba.g += m; - rgba.b += m; - return rgba; -} - -// BOTTOM - +/* + * Mr. 4th Dimention - Allen Webster + * + * 15.05.2015 + * + * Math functions for 4coder + * + */ + +// TOP + +/* + * Scalar operators + */ + +#define C_MATH 1 + +#define DEG_TO_RAD 0.0174533f + +#if C_MATH +#include +#endif + +inline f32 +ABS(f32 x){ + if (x < 0) x = -x; + return x; +} + +inline f32 +MOD(f32 x, i32 m){ +#if C_MATH + f32 whole, frac; + frac = modff(x, &whole); + return ((i32)(whole) % m) + frac; +#endif +} + +inline f32 +SQRT(f32 x){ +#if C_MATH + return sqrt(x); +#endif +} + +inline f32 +SIN(f32 x_degrees){ +#if C_MATH + return sinf(x_degrees * DEG_TO_RAD); +#endif +} + +inline f32 +COS(f32 x_degrees){ +#if C_MATH + return cosf(x_degrees * DEG_TO_RAD); +#endif +} + +/* + * Rounding + */ + +inline i32 +TRUNC32(real32 x) { return (i32)x; } + +inline i32 +FLOOR32(real32 x) { return (i32)(x)-((x!=(i32)(x) && x<0)?1:0); } + +inline i32 +CEIL32(real32 x) { return (i32)(x)+((x!=(i32)(x) && x>0)?1:0); } + +inline i32 +ROUND32(real32 x) { return FLOOR32(x + .5f); } + +inline i32 +DIVCEIL32(i32 n, i32 d) { + i32 q = (n/d); + return q + (q*d < n); +} + +inline real32 +FRACPART32(real32 x) { return x - (i32)x; } + +inline u32 +ROUNDPOT32(u32 v){ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + +/* + * Rectangles + */ + +struct i32_Rect{ + i32 x0, y0; + i32 x1, y1; +}; + +struct f32_Rect{ + f32 x0, y0; + f32 x1, y1; +}; + +inline i32_Rect +i32R(i32 l, i32 t, i32 r, i32 b){ + i32_Rect rect; + rect.x0 = l; rect.y0 = t; + rect.x1 = r; rect.y1 = b; + return rect; +} + +inline i32_Rect +i32R(f32_Rect r){ + i32_Rect rect; + rect.x0 = (i32)r.x0; + rect.y0 = (i32)r.y0; + rect.x1 = (i32)r.x1; + rect.y1 = (i32)r.y1; + return rect; +} + +inline i32_Rect +i32XYWH(i32 x, i32 y, i32 w, i32 h){ + i32_Rect rect; + rect.x0 = x; rect.y0 = y; + rect.x1 = x+w; rect.y1 = y+h; + return rect; +} + +inline f32_Rect +f32R(f32 l, f32 t, f32 r, f32 b){ + f32_Rect rect; + rect.x0 = l; rect.y0 = t; + rect.x1 = r; rect.y1 = b; + return rect; +} + +inline f32_Rect +f32R(i32_Rect r){ + f32_Rect rect; + rect.x0 = (f32)r.x0; + rect.y0 = (f32)r.y0; + rect.x1 = (f32)r.x1; + rect.y1 = (f32)r.y1; + return rect; +} + +inline f32_Rect +f32XYWH(f32 x, f32 y, f32 w, f32 h){ + f32_Rect rect; + rect.x0 = x; rect.y0 = y; + rect.x1 = x+w; rect.y1 = y+h; + return rect; +} + +inline b32 +hit_check(i32 x, i32 y, i32 x0, i32 y0, i32 x1, i32 y1){ + return (x >= x0 && x < x1 && y >= y0 && y < y1); +} + +inline b32 +hit_check(i32 x, i32 y, i32_Rect rect){ + return (hit_check(x, y, rect.x0, rect.y0, rect.x1, rect.y1)); +} + +inline b32 +hit_check(i32 x, i32 y, f32 x0, f32 y0, f32 x1, f32 y1){ + return (x >= x0 && x < x1 && y >= y0 && y < y1); +} + +inline b32 +hit_check(i32 x, i32 y, f32_Rect rect){ + return (hit_check(x, y, rect.x0, rect.y0, rect.x1, rect.y1)); +} + +inline b32 +positive_area(i32_Rect rect){ + return (rect.x0 < rect.x1 && rect.y0 < rect.y1); +} + +inline i32_Rect +get_inner_rect(i32_Rect outer, i32 margin){ + i32_Rect r; + r.x0 = outer.x0 + margin; + r.y0 = outer.y0 + margin; + r.x1 = outer.x1 - margin; + r.y1 = outer.y1 - margin; + return r; +} + +inline b32 +fits_inside(i32_Rect rect, i32_Rect outer){ + return (rect.x0 >= outer.x0 && rect.x1 <= outer.x1 && + rect.y0 >= outer.y0 && rect.y1 <= outer.y1); +} + +inline i32_Rect +rect_clamp_to_rect(i32_Rect rect, i32_Rect clamp_box){ + if (rect.x0 < clamp_box.x0) rect.x0 = clamp_box.x0; + if (rect.y0 < clamp_box.y0) rect.y0 = clamp_box.y0; + if (rect.x1 > clamp_box.x1) rect.x1 = clamp_box.x1; + if (rect.y1 > clamp_box.y1) rect.y1 = clamp_box.y1; + return rect; +} + +inline i32_Rect +rect_clamp_to_rect(i32 left, i32 top, i32 right, i32 bottom, i32_Rect clamp_box){ + return rect_clamp_to_rect(i32R(left, top, right, bottom), clamp_box); +} + +/* + * Vectors + */ + +struct Vec2{ + union{ + struct{ + real32 x, y; + }; + struct{ + real32 v[2]; + }; + }; +}; + +struct Vec3{ + union{ + struct{ + real32 x, y, z; + }; + struct{ + real32 r, g, b; + }; + struct{ + Vec2 xy; + real32 _z; + }; + struct{ + real32 _x; + Vec2 yz; + }; + struct{ + real32 v[3]; + }; + }; +}; + +struct Vec4{ + union{ + struct{ + real32 r, g, b, a; + }; + + struct{ + real32 h, s, l, __a; + }; + struct{ + real32 x, y, z, w; + }; + struct{ + Vec3 rgb; + real32 _a; + }; + struct{ + Vec3 xyz; + real32 _w; + }; + struct{ + real32 _x; + Vec3 yzw; + }; + struct{ + real32 v[4]; + }; + }; +}; + +inline internal Vec2 +V2(real32 x, real32 y){ + Vec2 result; + result.x = x; + result.y = y; + return result; +} + +inline internal Vec3 +V3(real32 x, real32 y, real32 z){ + Vec3 result; + result.x = x; + result.y = y; + result.z = z; + return result; +} + +inline internal Vec4 +V4(real32 x, real32 y, real32 z, real32 w){ + Vec4 result; + result.x = x; + result.y = y; + result.z = z; + result.w = w; + return result; +} + +inline internal Vec2 +operator+(Vec2 a, Vec2 b){ + Vec2 result; + result.x = a.x + b.x; + result.y = a.y + b.y; + return result; +} + +inline internal Vec3 +operator+(Vec3 a, Vec3 b){ + Vec3 result; + result.x = a.x + b.x; + result.y = a.y + b.y; + result.z = a.z + b.z; + return result; +} + +inline internal Vec4 +operator+(Vec4 a, Vec4 b){ + Vec4 result; + result.x = a.x + b.x; + result.y = a.y + b.y; + result.z = a.z + b.z; + result.w = a.w + b.w; + return result; +} + +inline internal Vec2 +operator-(Vec2 a, Vec2 b){ + Vec2 result; + result.x = a.x - b.x; + result.y = a.y - b.y; + return result; +} + +inline internal Vec3 +operator-(Vec3 a, Vec3 b){ + Vec3 result; + result.x = a.x - b.x; + result.y = a.y - b.y; + result.z = a.z - b.z; + return result; +} + +inline internal Vec4 +operator-(Vec4 a, Vec4 b){ + Vec4 result; + result.x = a.x - b.x; + result.y = a.y - b.y; + result.z = a.z - b.z; + result.w = a.w - b.w; + return result; +} + +inline internal Vec2 +operator*(Vec2 a, real32 k){ + Vec2 result; + result.x = a.x * k; + result.y = a.y * k; + return result; +} + +inline internal Vec3 +operator*(Vec3 a, real32 k){ + Vec3 result; + result.x = a.x * k; + result.y = a.y * k; + result.z = a.z * k; + return result; +} + +inline internal Vec4 +operator*(Vec4 a, real32 k){ + Vec4 result; + result.x = a.x * k; + result.y = a.y * k; + result.z = a.z * k; + result.w = a.w * k; + return result; +} + +inline internal Vec2 +operator*(real32 k, Vec2 a){ + Vec2 result; + result.x = a.x * k; + result.y = a.y * k; + return result; +} + +inline internal Vec3 +operator*(real32 k, Vec3 a){ + Vec3 result; + result.x = a.x * k; + result.y = a.y * k; + result.z = a.z * k; + return result; +} + +inline internal Vec4 +operator*(real32 k, Vec4 a){ + Vec4 result; + result.x = a.x * k; + result.y = a.y * k; + result.z = a.z * k; + result.w = a.w * k; + return result; +} + +inline internal Vec2& +operator+=(Vec2 &a, Vec2 b){ + a = (a + b); + return a; +} + +inline internal Vec3& +operator+=(Vec3 &a, Vec3 b){ + a = (a + b); + return a; +} + +inline internal Vec4& +operator+=(Vec4 &a, Vec4 b){ + a = (a + b); + return a; +} + +inline internal Vec2& +operator-=(Vec2 &a, Vec2 b){ + a = (a - b); + return a; +} + +inline internal Vec3& +operator-=(Vec3 &a, Vec3 b){ + a = (a - b); + return a; +} + +inline internal Vec4& +operator-=(Vec4 &a, Vec4 b){ + a = (a - b); + return a; +} + +inline internal Vec2& +operator*=(Vec2 &a, real32 k){ + a = (a * k); + return a; +} + +inline internal Vec3& +operator*=(Vec3 &a, real32 k){ + a = (a * k); + return a; +} + +inline internal Vec4& +operator*=(Vec4 &a, real32 k){ + a = (a * k); + return a; +} + +inline internal real32 +dot(Vec2 a, Vec2 b){ + real32 result; + result = a.x*b.x + a.y*b.y; + return result; +} + +inline internal real32 +dot(Vec3 a, Vec3 b){ + real32 result; + result = a.x*b.x + a.y*b.y + a.z*b.z; + return result; +} + +inline internal real32 +dot(Vec4 a, Vec4 b){ + real32 result; + result = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; + return result; +} + +inline internal Vec3 +cross(Vec3 a, Vec3 b){ + Vec3 result; + result.x = a.y*b.z - b.y*a.z; + result.y = a.z*b.x - b.z*a.x; + result.z = a.x*b.y - b.x*a.y; + return result; +} + +inline internal Vec2 +hadamard(Vec2 a, Vec2 b){ + Vec2 result; + result.x = a.x*b.x; + result.y = a.y*b.y; + return result; +} + +inline internal Vec3 +hadamard(Vec3 a, Vec3 b){ + Vec3 result; + result.x = a.x*b.x; + result.y = a.y*b.y; + result.z = a.z*b.z; + return result; +} + +inline internal Vec4 +hadamard(Vec4 a, Vec4 b){ + Vec4 result; + result.x = a.x*b.x; + result.y = a.y*b.y; + result.z = a.z*b.z; + result.w = a.w*b.w; + return result; +} + +inline internal Vec2 +perp(Vec2 v){ + Vec2 result; + result.x = -v.y; + result.y = v.x; + return result; +} + +inline Vec2 +polar_to_cartesian(real32 theta_degrees, real32 length){ + Vec2 result; + result.x = COS(theta_degrees)*length; + result.y = SIN(theta_degrees)*length; + return result; +} + +inline Vec2 +rotate(Vec2 v, real32 theta_degrees){ + Vec2 result; + real32 c, s; + c = COS(theta_degrees); + s = SIN(theta_degrees); + result.x = v.x*c - v.y*s; + result.y = v.x*s + v.y*c; + return result; +} + +/* + * Coordinates + */ + +struct Matrix2{ + Vec2 x_axis; + Vec2 y_axis; +}; + +internal Matrix2 +invert(Vec2 x_axis, Vec2 y_axis){ + Matrix2 result = {}; + real32 det = 1.f / (x_axis.x*y_axis.y - x_axis.y*y_axis.x); + result.x_axis.x = y_axis.y*det; + result.y_axis.x = -y_axis.x*det; + result.x_axis.y = -x_axis.y*det; + result.y_axis.y = x_axis.x*det; + return result; +} + +internal Matrix2 +invert(Matrix2 m){ + Matrix2 result = {}; + real32 det = 1.f / (m.x_axis.x*m.y_axis.y - m.x_axis.y*m.y_axis.x); + result.x_axis.x = m.y_axis.y*det; + result.y_axis.x = -m.y_axis.x*det; + result.x_axis.y = -m.x_axis.y*det; + result.y_axis.y = m.x_axis.x*det; + return result; +} + +/* + * Lerps, Clamps, Thresholds, Etc + */ + +inline real32 +lerp(real32 a, real32 t, real32 b){ + return a + (b-a)*t; +} + +inline Vec2 +lerp(Vec2 a, real32 t, Vec2 b){ + return a + (b-a)*t; +} + +inline Vec3 +lerp(Vec3 a, real32 t, Vec3 b){ + return a + (b-a)*t; +} + +inline Vec4 +lerp(Vec4 a, real32 t, Vec4 b){ + return a + (b-a)*t; +} + +inline real32 +unlerp(real32 a, real32 x, real32 b){ + return (x - a) / (b - a); +} + +inline real32 +clamp(real32 a, real32 n, real32 z){ + return (nz)?(z):n); +} + +/* + * Color + */ + +// TODO(allen): Convert colors to Vec4 +inline internal u32 +color_blend(u32 a, real32 t, u32 b){ + union{ + u8 byte[4]; + u32 comp; + } A, B, R; + + A.comp = a; + B.comp = b; + + R.byte[0] = (u8)lerp(A.byte[0], t, B.byte[0]); + R.byte[1] = (u8)lerp(A.byte[1], t, B.byte[1]); + R.byte[2] = (u8)lerp(A.byte[2], t, B.byte[2]); + R.byte[3] = (u8)lerp(A.byte[3], t, B.byte[3]); + + return R.comp; +} + +internal Vec3 +unpack_color3(u32 color){ + Vec3 result; + result.r = ((color >> 16) & 0xFF) / 255.f; + result.g = ((color >> 8) & 0xFF) / 255.f; + result.b = ((color >> 0) & 0xFF) / 255.f; + return result; +} + +internal Vec4 +unpack_color4(u32 color){ + Vec4 result; + result.a = ((color >> 24) & 0xFF) / 255.f; + result.r = ((color >> 16) & 0xFF) / 255.f; + result.g = ((color >> 8) & 0xFF) / 255.f; + result.b = ((color >> 0) & 0xFF) / 255.f; + return result; +} + +internal u32 +pack_color4(Vec4 color){ + u32 result = + ((u8)(color.a * 255) << 24) | + ((u8)(color.r * 255) << 16) | + ((u8)(color.g * 255) << 8) | + ((u8)(color.b * 255) << 0); + return result; +} + +internal Vec4 +rgba_to_hsla(Vec4 rgba){ + Vec4 hsla = {}; + real32 max, min, delta; + i32 maxc; + hsla.a = rgba.a; + max = rgba.r; min = rgba.r; + maxc = 0; + if (rgba.r < rgba.g){ + max = rgba.g; + maxc = 1; + } + if (rgba.b > max){ + max = rgba.b; + maxc = 2; + } + if (rgba.r > rgba.g){ + min = rgba.g; + } + if (rgba.b < min){ + min = rgba.b; + } + delta = max - min; + + hsla.z = (max + min) * .5f; + if (delta == 0){ + hsla.x = 0.f; + hsla.y = 0.f; + } + else{ + switch (maxc){ + case 0: + { + hsla.x = (rgba.g - rgba.b) / delta; + hsla.x += (rgba.g < rgba.b) * 6.f; + }break; + + case 1: + { + hsla.x = (rgba.b - rgba.r) / delta; + hsla.x += 2.f; + }break; + + case 2: + { + hsla.x = (rgba.r - rgba.g) / delta; + hsla.x += 4.f; + }break; + } + hsla.x *= (1/6.f); // * 60 / 360 + hsla.y = delta / (1.f - ABS(2.f*hsla.z - 1.f)); + } + + return hsla; +} + +internal Vec4 +hsla_to_rgba(Vec4 hsla){ + if (hsla.h >= 1.f) hsla.h = 0.f; + Vec4 rgba = {}; + real32 C, X, m; + i32 H; + rgba.a = hsla.a; + C = (1.f - ABS(2*hsla.z - 1.f)) * hsla.y; + X = C * (1.f-ABS(MOD(hsla.x*6.f, 2)-1.f)); + m = hsla.z - C*.5f; + H = FLOOR32(hsla.x * 6.f); + switch (H){ + case 0: + rgba.r = C; rgba.g = X; rgba.b = 0; + break; + + case 1: + rgba.r = X; rgba.g = C; rgba.b = 0; + break; + + case 2: + rgba.r = 0; rgba.g = C; rgba.b = X; + break; + + case 3: + rgba.r = 0; rgba.g = X; rgba.b = C; + break; + + case 4: + rgba.r = X; rgba.g = 0; rgba.b = C; + break; + + case 5: + rgba.r = C; rgba.g = 0; rgba.b = X; + break; + } + rgba.r += m; + rgba.g += m; + rgba.b += m; + return rgba; +} + +// BOTTOM + diff --git a/4ed_system.h b/4ed_system.h index 8044d23a..35a48980 100644 --- a/4ed_system.h +++ b/4ed_system.h @@ -1,191 +1,191 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 21.01.2014 - * - * System functions for project codename "4ed" - * - */ - -// TOP - -struct Plat_Handle{ - u32 d[4]; -}; - -struct File_Info{ - String filename; - b32 folder; -}; - -struct File_List{ - void *block; - File_Info *infos; - i32 count, block_size; -}; - -#define Sys_File_Time_Stamp_Sig(name) u64 name(char *filename) -typedef Sys_File_Time_Stamp_Sig(System_File_Time_Stamp); - -// TODO(allen): make directory a char* to signal that it must be null terminated -#define Sys_Set_File_List_Sig(name) void name(File_List *file_list, String directory) -typedef Sys_Set_File_List_Sig(System_Set_File_List); - -#define Sys_Post_Clipboard_Sig(name) void name(String str) -typedef Sys_Post_Clipboard_Sig(System_Post_Clipboard); - -#define Sys_Time_Sig(name) u64 name() -typedef Sys_Time_Sig(System_Time); - -// cli -struct CLI_Handles{ - Plat_Handle proc; - Plat_Handle out_read; - Plat_Handle out_write; - u32 scratch_space[4]; - i32 exit; -}; - -#define Sys_CLI_Call_Sig(name) b32 name(char *path, char *script_name, CLI_Handles *cli_out) -typedef Sys_CLI_Call_Sig(System_CLI_Call); - -#define Sys_CLI_Begin_Update_Sig(name) void name(CLI_Handles *cli) -typedef Sys_CLI_Begin_Update_Sig(System_CLI_Begin_Update); - -#define Sys_CLI_Update_Step_Sig(name) b32 name(CLI_Handles *cli, char *dest, u32 max, u32 *amount) -typedef Sys_CLI_Update_Step_Sig(System_CLI_Update_Step); - -#define Sys_CLI_End_Update_Sig(name) b32 name(CLI_Handles *cli) -typedef Sys_CLI_End_Update_Sig(System_CLI_End_Update); - -// thread -struct Thread_Context; - -enum Lock_ID{ - FRAME_LOCK, - INPUT_LOCK, - FONT_LOCK, - RENDER_LOCK, - CANCEL_LOCK0, - CANCEL_LOCK1, - CANCEL_LOCK2, - CANCEL_LOCK3, - CANCEL_LOCK4, - CANCEL_LOCK5, - CANCEL_LOCK6, - CANCEL_LOCK7, - LOCK_COUNT -}; - -enum Thread_Group_ID{ - BACKGROUND_THREADS, - THREAD_GROUP_COUNT -}; - -struct Thread_Memory{ - void *data; - i32 size; - i32 id; -}; - -struct Thread_Exchange; -struct System_Functions; - -#define Job_Callback_Sig(name) void name( \ - System_Functions *system, Thread_Context *thread, Thread_Memory *memory, \ - Thread_Exchange *exchange, void *data[2]) -typedef Job_Callback_Sig(Job_Callback); - -struct Job_Data{ - Job_Callback *callback; - void *data[2]; - i32 memory_request; -}; - -struct Full_Job_Data{ - Job_Data job; - - u32 job_memory_index; - u32 running_thread; - b32 finished; - u32 id; -}; - -struct Work_Queue{ - Full_Job_Data jobs[256]; - Plat_Handle semaphore; - volatile u32 write_position; - volatile u32 read_position; -}; - -#define THREAD_NOT_ASSIGNED 0xFFFFFFFF - -#define JOB_ID_WRAP (ArrayCount(queue->jobs) * 4) -#define QUEUE_WRAP (ArrayCount(queue->jobs)) - -struct Thread_Exchange{ - Work_Queue queues[THREAD_GROUP_COUNT]; - volatile u32 force_redraw; -}; - -#define Sys_Post_Job_Sig(name) u32 name(Thread_Group_ID group_id, Job_Data job) -typedef Sys_Post_Job_Sig(System_Post_Job); - -#define Sys_Cancel_Job_Sig(name) void name(Thread_Group_ID group_id, u32 job_id) -typedef Sys_Cancel_Job_Sig(System_Cancel_Job); - -#define Sys_Grow_Thread_Memory_Sig(name) void name(Thread_Memory *memory) -typedef Sys_Grow_Thread_Memory_Sig(System_Grow_Thread_Memory); - -#define Sys_Acquire_Lock_Sig(name) void name(i32 id) -typedef Sys_Acquire_Lock_Sig(System_Acquire_Lock); - -#define Sys_Release_Lock_Sig(name) void name(i32 id) -typedef Sys_Release_Lock_Sig(System_Release_Lock); - -// debug -#define INTERNAL_Sys_Sentinel_Sig(name) Bubble* name() -typedef INTERNAL_Sys_Sentinel_Sig(INTERNAL_System_Sentinel); - -#define INTERNAL_Sys_Get_Thread_States_Sig(name) void name(Thread_Group_ID id, b8 *running, i32 *pending) -typedef INTERNAL_Sys_Get_Thread_States_Sig(INTERNAL_System_Get_Thread_States); - -#define INTERNAL_Sys_Debug_Message_Sig(name) void name(char *message) -typedef INTERNAL_Sys_Debug_Message_Sig(INTERNAL_System_Debug_Message); - -struct System_Functions{ - // files: 2 - System_File_Time_Stamp *file_time_stamp; - System_Set_File_List *set_file_list; - - // file system navigation (4coder_custom.h): 2 - Directory_Has_File *directory_has_file; - Directory_CD *directory_cd; - - // clipboard: 1 - System_Post_Clipboard *post_clipboard; - - // time: 1 - System_Time *time; - - // cli: 4 - System_CLI_Call *cli_call; - System_CLI_Begin_Update *cli_begin_update; - System_CLI_Update_Step *cli_update_step; - System_CLI_End_Update *cli_end_update; - - // threads: 5 - System_Post_Job *post_job; - System_Cancel_Job *cancel_job; - System_Grow_Thread_Memory *grow_thread_memory; - System_Acquire_Lock *acquire_lock; - System_Release_Lock *release_lock; - - // debug: 3 - INTERNAL_System_Sentinel *internal_sentinel; - INTERNAL_System_Get_Thread_States *internal_get_thread_states; - INTERNAL_System_Debug_Message *internal_debug_message; -}; - -// BOTTOM - +/* + * Mr. 4th Dimention - Allen Webster + * + * 21.01.2014 + * + * System functions for project codename "4ed" + * + */ + +// TOP + +struct Plat_Handle{ + u32 d[4]; +}; + +struct File_Info{ + String filename; + b32 folder; +}; + +struct File_List{ + void *block; + File_Info *infos; + i32 count, block_size; +}; + +#define Sys_File_Time_Stamp_Sig(name) u64 name(char *filename) +typedef Sys_File_Time_Stamp_Sig(System_File_Time_Stamp); + +// TODO(allen): make directory a char* to signal that it must be null terminated +#define Sys_Set_File_List_Sig(name) void name(File_List *file_list, String directory) +typedef Sys_Set_File_List_Sig(System_Set_File_List); + +#define Sys_Post_Clipboard_Sig(name) void name(String str) +typedef Sys_Post_Clipboard_Sig(System_Post_Clipboard); + +#define Sys_Time_Sig(name) u64 name() +typedef Sys_Time_Sig(System_Time); + +// cli +struct CLI_Handles{ + Plat_Handle proc; + Plat_Handle out_read; + Plat_Handle out_write; + u32 scratch_space[4]; + i32 exit; +}; + +#define Sys_CLI_Call_Sig(name) b32 name(char *path, char *script_name, CLI_Handles *cli_out) +typedef Sys_CLI_Call_Sig(System_CLI_Call); + +#define Sys_CLI_Begin_Update_Sig(name) void name(CLI_Handles *cli) +typedef Sys_CLI_Begin_Update_Sig(System_CLI_Begin_Update); + +#define Sys_CLI_Update_Step_Sig(name) b32 name(CLI_Handles *cli, char *dest, u32 max, u32 *amount) +typedef Sys_CLI_Update_Step_Sig(System_CLI_Update_Step); + +#define Sys_CLI_End_Update_Sig(name) b32 name(CLI_Handles *cli) +typedef Sys_CLI_End_Update_Sig(System_CLI_End_Update); + +// thread +struct Thread_Context; + +enum Lock_ID{ + FRAME_LOCK, + INPUT_LOCK, + FONT_LOCK, + RENDER_LOCK, + CANCEL_LOCK0, + CANCEL_LOCK1, + CANCEL_LOCK2, + CANCEL_LOCK3, + CANCEL_LOCK4, + CANCEL_LOCK5, + CANCEL_LOCK6, + CANCEL_LOCK7, + LOCK_COUNT +}; + +enum Thread_Group_ID{ + BACKGROUND_THREADS, + THREAD_GROUP_COUNT +}; + +struct Thread_Memory{ + void *data; + i32 size; + i32 id; +}; + +struct Thread_Exchange; +struct System_Functions; + +#define Job_Callback_Sig(name) void name( \ + System_Functions *system, Thread_Context *thread, Thread_Memory *memory, \ + Thread_Exchange *exchange, void *data[2]) +typedef Job_Callback_Sig(Job_Callback); + +struct Job_Data{ + Job_Callback *callback; + void *data[2]; + i32 memory_request; +}; + +struct Full_Job_Data{ + Job_Data job; + + u32 job_memory_index; + u32 running_thread; + b32 finished; + u32 id; +}; + +struct Work_Queue{ + Full_Job_Data jobs[256]; + Plat_Handle semaphore; + volatile u32 write_position; + volatile u32 read_position; +}; + +#define THREAD_NOT_ASSIGNED 0xFFFFFFFF + +#define JOB_ID_WRAP (ArrayCount(queue->jobs) * 4) +#define QUEUE_WRAP (ArrayCount(queue->jobs)) + +struct Thread_Exchange{ + Work_Queue queues[THREAD_GROUP_COUNT]; + volatile u32 force_redraw; +}; + +#define Sys_Post_Job_Sig(name) u32 name(Thread_Group_ID group_id, Job_Data job) +typedef Sys_Post_Job_Sig(System_Post_Job); + +#define Sys_Cancel_Job_Sig(name) void name(Thread_Group_ID group_id, u32 job_id) +typedef Sys_Cancel_Job_Sig(System_Cancel_Job); + +#define Sys_Grow_Thread_Memory_Sig(name) void name(Thread_Memory *memory) +typedef Sys_Grow_Thread_Memory_Sig(System_Grow_Thread_Memory); + +#define Sys_Acquire_Lock_Sig(name) void name(i32 id) +typedef Sys_Acquire_Lock_Sig(System_Acquire_Lock); + +#define Sys_Release_Lock_Sig(name) void name(i32 id) +typedef Sys_Release_Lock_Sig(System_Release_Lock); + +// debug +#define INTERNAL_Sys_Sentinel_Sig(name) Bubble* name() +typedef INTERNAL_Sys_Sentinel_Sig(INTERNAL_System_Sentinel); + +#define INTERNAL_Sys_Get_Thread_States_Sig(name) void name(Thread_Group_ID id, b8 *running, i32 *pending) +typedef INTERNAL_Sys_Get_Thread_States_Sig(INTERNAL_System_Get_Thread_States); + +#define INTERNAL_Sys_Debug_Message_Sig(name) void name(char *message) +typedef INTERNAL_Sys_Debug_Message_Sig(INTERNAL_System_Debug_Message); + +struct System_Functions{ + // files: 2 + System_File_Time_Stamp *file_time_stamp; + System_Set_File_List *set_file_list; + + // file system navigation (4coder_custom.h): 2 + Directory_Has_File *directory_has_file; + Directory_CD *directory_cd; + + // clipboard: 1 + System_Post_Clipboard *post_clipboard; + + // time: 1 + System_Time *time; + + // cli: 4 + System_CLI_Call *cli_call; + System_CLI_Begin_Update *cli_begin_update; + System_CLI_Update_Step *cli_update_step; + System_CLI_End_Update *cli_end_update; + + // threads: 5 + System_Post_Job *post_job; + System_Cancel_Job *cancel_job; + System_Grow_Thread_Memory *grow_thread_memory; + System_Acquire_Lock *acquire_lock; + System_Release_Lock *release_lock; + + // debug: 3 + INTERNAL_System_Sentinel *internal_sentinel; + INTERNAL_System_Get_Thread_States *internal_get_thread_states; + INTERNAL_System_Debug_Message *internal_debug_message; +}; + +// BOTTOM + diff --git a/vc120.pdb b/vc120.pdb index ab801a0d..dfa67a6e 100644 Binary files a/vc120.pdb and b/vc120.pdb differ diff --git a/win32_4ed.cpp b/win32_4ed.cpp index d9781cff..c0602d6e 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -75,6 +75,8 @@ struct Win32_Input_Chunk_Transient{ b8 mouse_r_press, mouse_r_release; b32 out_of_window; i16 mouse_wheel; + + b32 redraw; }; struct Win32_Input_Chunk_Persistent{ @@ -411,7 +413,6 @@ Sys_Set_File_List_Sig(system_set_file_list){ info->folder = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; info->filename.str = name; - char *name_base = name; i32 i = 0; for(;find_data.cFileName[i];++i) *name++ = find_data.cFileName[i]; info->filename.size = i; @@ -1247,6 +1248,7 @@ Win32Callback(HWND hwnd, UINT uMsg, i32 new_height = HIWORD(lParam); Win32Resize(new_width, new_height); + win32vars.input_chunk.trans.redraw = 1; } }break; @@ -1378,7 +1380,9 @@ UpdateLoop(LPVOID param){ u32 redraw = exchange_vars.thread.force_redraw; if (redraw) exchange_vars.thread.force_redraw = 0; - + redraw = redraw || input_chunk.trans.redraw; + + Key_Input_Data input_data; Mouse_State mouse; Application_Step_Result result;