API started
							parent
							
								
									852a7fd71c
								
							
						
					
					
						commit
						c38d6ce47b
					
				|  | @ -2,113 +2,14 @@ | |||
|  * Example use of customization API | ||||
|  */ | ||||
| 
 | ||||
| // NOTE(allen): NEW THINGS TO LOOK FOR:
 | ||||
| // MAPID_USER_CUSTOM - define maps other than the built in GLOBAL/FILE maps
 | ||||
| // inherit_map
 | ||||
| // 
 | ||||
| // get_settings
 | ||||
| 
 | ||||
| #include "4coder_custom.h" | ||||
| 
 | ||||
| // NOTE(allen): All this helper stuff is here to make the new API
 | ||||
| // work a lot like the old API
 | ||||
| struct Bind_Helper{ | ||||
|     Binding_Unit *cursor, *start, *end; | ||||
|     Binding_Unit *header, *map; | ||||
|     int write_total; | ||||
|     int error; | ||||
| }; | ||||
| 
 | ||||
| #define BH_ERR_NONE 0 | ||||
| #define BH_ERR_MISSING_END_MAP 1 | ||||
| #define BH_ERR_MISSING_BEGIN_MAP 2 | ||||
| 
 | ||||
| inline Binding_Unit* | ||||
| write_unit(Bind_Helper *helper, Binding_Unit unit){ | ||||
|     Binding_Unit *p = 0; | ||||
|     helper->write_total += sizeof(Binding_Unit); | ||||
|     if (helper->error == 0 && helper->cursor != helper->end){ | ||||
|         p = helper->cursor++; | ||||
|         *p = unit; | ||||
|     } | ||||
|     return p; | ||||
| } | ||||
| 
 | ||||
| inline Bind_Helper | ||||
| begin_bind_helper(void *data, int size){ | ||||
|     Bind_Helper result; | ||||
|      | ||||
|     result.header = 0; | ||||
|     result.map = 0; | ||||
|     result.write_total = 0; | ||||
|     result.error = 0; | ||||
|      | ||||
|     result.cursor = (Binding_Unit*)data; | ||||
|     result.start = result.cursor; | ||||
|     result.end = result.start + size / sizeof(Binding_Unit); | ||||
|      | ||||
|     Binding_Unit unit; | ||||
|     unit.type = UNIT_HEADER; | ||||
|     unit.header.total_size = sizeof(Binding_Unit); | ||||
|     result.header = write_unit(&result, unit); | ||||
|      | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| begin_map(Bind_Helper *helper, int mapid){ | ||||
|     if (helper->map != 0 && helper->error == 0) helper->error = BH_ERR_MISSING_END_MAP; | ||||
|      | ||||
|     Binding_Unit unit; | ||||
|     unit.type = UNIT_MAP_BEGIN; | ||||
|     unit.map_begin.mapid = mapid; | ||||
|     helper->map = write_unit(helper, unit); | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| end_map(Bind_Helper *helper){ | ||||
|     if (helper->map == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN_MAP; | ||||
|      | ||||
|     helper->map = 0; | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| bind(Bind_Helper *helper, short code, unsigned char modifiers, int cmdid){ | ||||
|     if (helper->map == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN_MAP; | ||||
|      | ||||
|     Binding_Unit unit; | ||||
|     unit.type = UNIT_BINDING; | ||||
|     unit.binding.command_id = cmdid; | ||||
|     unit.binding.code = code; | ||||
|     unit.binding.modifiers = modifiers; | ||||
|      | ||||
|     write_unit(helper, unit); | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| bind_me(Bind_Helper *helper, short code, unsigned char modifiers, Custom_Command_Function *func){ | ||||
|     if (helper->map == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN_MAP; | ||||
|      | ||||
|     Binding_Unit unit; | ||||
|     unit.type = UNIT_CALLBACK; | ||||
|     unit.callback.func = func; | ||||
|     unit.callback.code = code; | ||||
|     unit.callback.modifiers = modifiers; | ||||
|      | ||||
|     write_unit(helper, unit); | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| bind_vanilla_keys(Bind_Helper *helper, int cmdid){ | ||||
|     bind(helper, 0, 0, cmdid); | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| bind_me_vanilla_keys(Bind_Helper *helper, Custom_Command_Function *func){ | ||||
|     bind_me(helper, 0, 0, func); | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| end_bind_helper(Bind_Helper *helper){ | ||||
|     if (helper->header){ | ||||
|         helper->header->header.total_size = (int)(helper->cursor - helper->start); | ||||
|         helper->header->header.error = helper->error; | ||||
|     } | ||||
| } | ||||
| #include "4coder_helper.h" | ||||
| 
 | ||||
| #define exec_command app.exec_command | ||||
| #define fulfill_interaction app.fulfill_interaction | ||||
|  | @ -123,37 +24,81 @@ CUSTOM_COMMAND_SIG(open_in_other){ | |||
|     exec_command(cmd_context, cmdid_interactive_open); | ||||
| } | ||||
| 
 | ||||
| extern "C" GET_BINDING_DATA(get_bindings){ | ||||
| extern "C" GET_BINDING_DATA(get_binding){ | ||||
|     Bind_Helper context_actual = begin_bind_helper(data, size); | ||||
|     Bind_Helper *context = &context_actual; | ||||
|      | ||||
|     begin_settings_group(context); | ||||
|      | ||||
|     use_when(context, when_default, 1); | ||||
|      | ||||
|     set(context, set_lex_as_cpp_file, 0); | ||||
|     set(context, set_wrap_lines, 1); | ||||
|     set(context, set_key_mapid, MAPID_FILE); | ||||
|      | ||||
|     // NOTE(allen): options include EOL_USE_CRLF, EOL_USE_CR_USE_LF, EOL_SHOW_CR_USE_LF
 | ||||
|     // EOL_USE_CRLF - treats a crlf and lf as newline markers, renders lone cr as special character "\r"
 | ||||
|     // EOL_USE_CR_USE_LF - treats both as separate newline markers
 | ||||
|     // EOL_SHOW_CR_USE_LF - treats lf as newline marker, renders cr as special character "\r"
 | ||||
|     set(context, set_end_line_mode, EOL_USE_CRLF); | ||||
|      | ||||
|     end_group(context); | ||||
|      | ||||
|      | ||||
|     begin_settings_group(context); | ||||
|      | ||||
|     use_when(context, when_extension, "cpp"); | ||||
|     use_when(context, when_extension, "hpp"); | ||||
|     use_when(context, when_extension, "c"); | ||||
|     use_when(context, when_extension, "h"); | ||||
|      | ||||
|     set(context, set_lex_as_cpp_file, 1); | ||||
|     set(context, set_key_mapid, MAPID_USER_CUSTOM + 0); | ||||
|      | ||||
|     begin_map(context, MAPID_GLOBAL); | ||||
|      | ||||
|     // NOTE(allen): Here put the contents of your set_global_bindings
 | ||||
|     bind(context, 'p', MDFR_CTRL, cmdid_open_panel_vsplit); | ||||
|     bind(context, '-', MDFR_CTRL, cmdid_open_panel_hsplit); | ||||
|     bind(context, 'P', MDFR_CTRL, cmdid_close_panel); | ||||
|     bind(context, 'n', MDFR_CTRL, cmdid_interactive_new); | ||||
|     bind(context, 'o', MDFR_CTRL, cmdid_interactive_open); | ||||
|     bind(context, ',', MDFR_CTRL, cmdid_change_active_panel); | ||||
|     bind(context, 'k', MDFR_CTRL, cmdid_interactive_kill_file); | ||||
|     bind(context, 'i', MDFR_CTRL, cmdid_interactive_switch_file); | ||||
|     bind(context, 'k', MDFR_CTRL, cmdid_interactive_kill_buffer); | ||||
|     bind(context, 'i', MDFR_CTRL, cmdid_interactive_switch_buffer); | ||||
|     bind(context, 'c', MDFR_ALT, cmdid_open_color_tweaker); | ||||
|     bind(context, 'x', MDFR_ALT, cmdid_open_menu); | ||||
|     bind_me(context, 'o', MDFR_ALT, open_in_other); | ||||
|      | ||||
|     end_map(context); | ||||
| 
 | ||||
|      | ||||
|     begin_map(context, MAPID_USER_CUSTOM + 0); | ||||
| 
 | ||||
|     // NOTE(allen): Set this map (MAPID_USER_CUSTOM + 0) to
 | ||||
|     // inherit from MAPID_FILE.  When searching if a key is bound
 | ||||
|     // in this map, if it is not found here it will then search MAPID_FILE.
 | ||||
|     //
 | ||||
|     // If this is not set, it defaults to MAPID_GLOBAL.
 | ||||
|     inherit_map(context, MAPID_FILE); | ||||
|      | ||||
|     bind(context, codes->right, MDFR_CTRL, cmdid_seek_alphanumeric_or_camel_right); | ||||
|     bind(context, codes->left, MDFR_CTRL, cmdid_seek_alphanumeric_or_camel_left); | ||||
|      | ||||
|     // NOTE(allen): Not currently functional
 | ||||
|     bind(context, '\t', MDFR_CTRL, cmdid_auto_tab); | ||||
|      | ||||
|     end_map(context); | ||||
| 
 | ||||
|      | ||||
|     begin_map(context, MAPID_FILE); | ||||
|      | ||||
|     // NOTE(allen): This is a new concept in the API. Binding this can be thought of as binding
 | ||||
|     // all combos which have an ascii code (shifted or not) and unmodified by CTRL or ALT.
 | ||||
|     // As of now, if this is used it cannot be overriden for particular combos; this overrides
 | ||||
|     // normal bindings.
 | ||||
|     // NOTE(allen): Binding this essentially binds all key combos that
 | ||||
|     // would normally insert a character into a buffer.
 | ||||
|     // Or apply this rule (which always works): if the code for the key
 | ||||
|     // is not in the codes struct, it is a vanilla key.
 | ||||
|     // It is possible to override this binding for individual keys.
 | ||||
|     bind_vanilla_keys(context, cmdid_write_character); | ||||
|      | ||||
|     // NOTE(allen): Here put the contents of your set_file_bindings
 | ||||
|     bind(context, codes->left, MDFR_NONE, cmdid_move_left); | ||||
|     bind(context, codes->right, MDFR_NONE, cmdid_move_right); | ||||
|     bind(context, codes->del, MDFR_NONE, cmdid_delete); | ||||
|  | @ -165,8 +110,8 @@ extern "C" GET_BINDING_DATA(get_bindings){ | |||
|     bind(context, codes->page_up, MDFR_NONE, cmdid_page_up); | ||||
|     bind(context, codes->page_down, MDFR_NONE, cmdid_page_down); | ||||
|      | ||||
|     bind(context, codes->right, MDFR_CTRL, cmdid_seek_alphanumeric_or_camel_right); | ||||
|     bind(context, codes->left, MDFR_CTRL, cmdid_seek_alphanumeric_or_camel_left); | ||||
|     bind(context, codes->right, MDFR_CTRL, cmdid_seek_whitespace_right); | ||||
|     bind(context, codes->left, MDFR_CTRL, cmdid_seek_whitespace_left); | ||||
|     bind(context, codes->up, MDFR_CTRL, cmdid_seek_whitespace_up); | ||||
|     bind(context, codes->down, MDFR_CTRL, cmdid_seek_whitespace_down); | ||||
|      | ||||
|  | @ -176,23 +121,26 @@ extern "C" GET_BINDING_DATA(get_bindings){ | |||
|     bind(context, 'x', MDFR_CTRL, cmdid_cut); | ||||
|     bind(context, 'v', MDFR_CTRL, cmdid_paste); | ||||
|     bind(context, 'V', MDFR_CTRL, cmdid_paste_next); | ||||
|     bind(context, 'z', MDFR_CTRL, cmdid_undo); | ||||
|     bind(context, 'y', MDFR_CTRL, cmdid_redo); | ||||
|     bind(context, 'd', MDFR_CTRL, cmdid_delete_chunk); | ||||
|     bind(context, 'l', MDFR_CTRL, cmdid_toggle_line_wrap); | ||||
|     bind(context, 'L', MDFR_CTRL, cmdid_toggle_endline_mode); | ||||
|     bind(context, 'u', MDFR_CTRL, cmdid_to_uppercase); | ||||
|     bind(context, 'j', MDFR_CTRL, cmdid_to_lowercase); | ||||
|     bind(context, '?', MDFR_CTRL, cmdid_toggle_show_whitespace); | ||||
| 
 | ||||
|     // NOTE(allen): These whitespace manipulators are not currently functional
 | ||||
|     bind(context, '`', MDFR_CTRL, cmdid_clean_line); | ||||
|     bind(context, '~', MDFR_CTRL, cmdid_clean_all_lines); | ||||
|     bind(context, '1', MDFR_CTRL, cmdid_eol_dosify); | ||||
|     bind(context, '!', MDFR_CTRL, cmdid_eol_nixify); | ||||
|      | ||||
|     bind(context, 'f', MDFR_CTRL, cmdid_search); | ||||
|     bind(context, 'r', MDFR_CTRL, cmdid_rsearch); | ||||
|     bind(context, 'g', MDFR_CTRL, cmdid_goto_line); | ||||
|      | ||||
|     bind(context, '\t', MDFR_CTRL, cmdid_auto_tab); | ||||
|      | ||||
|     bind(context, 'K', MDFR_CTRL, cmdid_kill_file); | ||||
|     bind(context, 'K', MDFR_CTRL, cmdid_kill_buffer); | ||||
|     bind(context, 'O', MDFR_CTRL, cmdid_reopen); | ||||
|     bind(context, 'w', MDFR_CTRL, cmdid_interactive_save_as); | ||||
|     bind(context, 's', MDFR_CTRL, cmdid_save); | ||||
|  |  | |||
|  | @ -70,15 +70,17 @@ enum Command_ID{ | |||
|     cmdid_paste, | ||||
|     cmdid_paste_next, | ||||
|     cmdid_delete_chunk, | ||||
|     cmdid_undo, | ||||
|     cmdid_redo, | ||||
|     cmdid_interactive_new, | ||||
|     cmdid_interactive_open, | ||||
|     cmdid_reopen, | ||||
|     cmdid_save, | ||||
|     cmdid_interactive_save_as, | ||||
|     cmdid_change_active_panel, | ||||
|     cmdid_interactive_switch_file, | ||||
|     cmdid_interactive_kill_file, | ||||
|     cmdid_kill_file, | ||||
|     cmdid_interactive_switch_buffer, | ||||
|     cmdid_interactive_kill_buffer, | ||||
|     cmdid_kill_buffer, | ||||
|     cmdid_toggle_line_wrap, | ||||
|     cmdid_toggle_endline_mode, | ||||
|     cmdid_to_uppercase, | ||||
|  | @ -141,36 +143,72 @@ struct Application_Links{ | |||
|     Fulfill_Interaction_Function *fulfill_interaction; | ||||
| }; | ||||
| 
 | ||||
| enum Settings_Unit_Type{ | ||||
|     SUNIT_HEADER, | ||||
|     SUNIT_GROUP, | ||||
|     SUNIT_USE_CLAUSE, | ||||
|     SUNIT_USE_CLAUSE_STRING, | ||||
|     SUNIT_SETTING | ||||
| }; | ||||
| 
 | ||||
| enum Setting_ID{ | ||||
|     set_lex_as_cpp_file, | ||||
|     set_wrap_lines, | ||||
|     set_key_mapid, | ||||
|     set_end_line_mode | ||||
| }; | ||||
| 
 | ||||
| enum Setting_When_Type{ | ||||
|     when_default, | ||||
|     when_extension | ||||
| }; | ||||
| 
 | ||||
| enum End_Of_Line_Options{ | ||||
|     EOL_USE_CRLF, | ||||
|     EOL_USE_CR_USE_LF, | ||||
|     EOL_SHOW_CR_USE_LF | ||||
| }; | ||||
| 
 | ||||
| enum Binding_Unit_Type{ | ||||
|     UNIT_HEADER, | ||||
|     UNIT_MAP_BEGIN, | ||||
|     UNIT_BINDING, | ||||
|     UNIT_CALLBACK | ||||
|     UNIT_CALLBACK, | ||||
|     UNIT_INHERIT, | ||||
|     UNIT_SETTINGS_BEGIN, | ||||
|     UNIT_USE_CLAUSE, | ||||
|     UNIT_USE_CLAUSE_STRING, | ||||
|     UNIT_SETTING | ||||
| }; | ||||
| 
 | ||||
| enum Map_ID{ | ||||
|     MAPID_GLOBAL, | ||||
|     MAPID_FILE | ||||
|     MAPID_FILE, | ||||
|     MAPID_USER_CUSTOM | ||||
| }; | ||||
| 
 | ||||
| struct Binding_Unit{ | ||||
|     Binding_Unit_Type type; | ||||
|     union{ | ||||
|         struct{ int total_size; int error; } header; | ||||
|          | ||||
|         struct{ int mapid; } map_begin; | ||||
|         struct{ int total_size; int map_count; int group_count; int error; } header; | ||||
|          | ||||
|         struct{ int mapid; int bind_count; } map_begin; | ||||
|         struct{ int mapid; } map_inherit; | ||||
|         struct{ | ||||
|             int command_id; | ||||
|             short code; | ||||
|             unsigned char modifiers; | ||||
|         } binding; | ||||
|          | ||||
|         struct{ | ||||
|             Custom_Command_Function *func; | ||||
|             short code; | ||||
|             unsigned char modifiers; | ||||
|         } callback; | ||||
|          | ||||
|         struct{ int clause_type; int value; } use_clause; | ||||
|         struct{ int clause_type; int len; char *value; } use_clause_string; | ||||
|         struct{ int setting_id; int value; } setting; | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,135 @@ | |||
| /*
 | ||||
|  * This is an example of how vim-keys might start | ||||
|  * to work in 4coder, through the customization API. | ||||
|  */ | ||||
| 
 | ||||
| #include "4coder_custom.h" | ||||
| #include "4coder_helper.h" | ||||
| 
 | ||||
| #define exec_command app.exec_command | ||||
| #define fulfill_interaction app.fulfill_interaction | ||||
| 
 | ||||
| extern "C" START_HOOK_SIG(start_hook){ | ||||
|     exec_command(cmd_context, cmdid_open_panel_vsplit); | ||||
|     exec_command(cmd_context, cmdid_change_active_panel); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| extern "C" GET_BINDING_DATA(get_binding){ | ||||
|     Bind_Helper context_actual = begin_bind_helper(data, size); | ||||
|     Bind_Helper *context = &context_actual; | ||||
|      | ||||
|     begin_settings_group(context); | ||||
|      | ||||
|     use_when(context, when_default, 1); | ||||
|      | ||||
|     set(context, set_lex_as_cpp_file, 0); | ||||
|     set(context, set_wrap_lines, 1); | ||||
|     set(context, set_key_mapid, MAPID_FILE); | ||||
|      | ||||
|     // NOTE(allen): options include EOL_USE_CRLF, EOL_USE_CR_USE_LF, EOL_SHOW_CR_USE_LF
 | ||||
|     // EOL_USE_CRLF - treats a crlf and lf as newline markers, renders lone cr as special character "\r"
 | ||||
|     // EOL_USE_CR_USE_LF - treats both as separate newline markers
 | ||||
|     // EOL_SHOW_CR_USE_LF - treats lf as newline marker, renders cr as special character "\r"
 | ||||
|     set(context, set_end_line_mode, EOL_USE_CRLF); | ||||
|      | ||||
|     end_group(context); | ||||
|      | ||||
|      | ||||
|     begin_settings_group(context); | ||||
|      | ||||
|     use_when(context, when_extension, "cpp"); | ||||
|     use_when(context, when_extension, "hpp"); | ||||
|     use_when(context, when_extension, "c"); | ||||
|     use_when(context, when_extension, "h"); | ||||
|      | ||||
|     set(context, set_lex_as_cpp_file, 1); | ||||
|     set(context, set_key_mapid, MAPID_USER_CUSTOM + 0); | ||||
|      | ||||
|     begin_map(context, MAPID_GLOBAL); | ||||
|      | ||||
|     bind(context, 'p', MDFR_CTRL, cmdid_open_panel_vsplit); | ||||
|     bind(context, '-', MDFR_CTRL, cmdid_open_panel_hsplit); | ||||
|     bind(context, 'P', MDFR_CTRL, cmdid_close_panel); | ||||
|     bind(context, 'n', MDFR_CTRL, cmdid_interactive_new); | ||||
|     bind(context, 'o', MDFR_CTRL, cmdid_interactive_open); | ||||
|     bind(context, ',', MDFR_CTRL, cmdid_change_active_panel); | ||||
|     bind(context, 'k', MDFR_CTRL, cmdid_interactive_kill_buffer); | ||||
|     bind(context, 'i', MDFR_CTRL, cmdid_interactive_switch_buffer); | ||||
|     bind(context, 'c', MDFR_ALT, cmdid_open_color_tweaker); | ||||
|     bind(context, 'x', MDFR_ALT, cmdid_open_menu); | ||||
|     bind_me(context, 'o', MDFR_ALT, open_in_other); | ||||
|      | ||||
|     end_map(context); | ||||
| 
 | ||||
|      | ||||
|     begin_map(context, MAPID_USER_CUSTOM + 0); | ||||
|     inherit_map(context, MAPID_FILE); | ||||
|     end_map(context); | ||||
| 
 | ||||
|     int sub_id; | ||||
|     begin_map(context, MAPID_FILE); | ||||
|      | ||||
|     sub_id = begin_sub_map(context); | ||||
|     { | ||||
|         bind_vanilla_keys(context, cmdid_write_character); | ||||
|          | ||||
|         bind(context, codes->left, MDFR_NONE, cmdid_move_left); | ||||
|         bind(context, codes->right, MDFR_NONE, cmdid_move_right); | ||||
|         bind(context, codes->del, MDFR_NONE, cmdid_delete); | ||||
|         bind(context, codes->back, MDFR_NONE, cmdid_backspace); | ||||
|         bind(context, codes->up, MDFR_NONE, cmdid_move_up); | ||||
|         bind(context, codes->down, MDFR_NONE, cmdid_move_down); | ||||
|         bind(context, codes->end, MDFR_NONE, cmdid_seek_end_of_line); | ||||
|         bind(context, codes->home, MDFR_NONE, cmdid_seek_beginning_of_line); | ||||
|         bind(context, codes->page_up, MDFR_NONE, cmdid_page_up); | ||||
|         bind(context, codes->page_down, MDFR_NONE, cmdid_page_down); | ||||
|     } | ||||
|     end_sub_map(context); | ||||
|      | ||||
|     bind_params(context, 'i', MDFR_NONE, cmdid_use_sub_map); | ||||
|     fill_param(context, "sub_id", sub_id); | ||||
|     end_params(context); | ||||
|      | ||||
|     bind_multi(context, 'a', MDFR_NONE); | ||||
|     { | ||||
|         bind(context, 'a', MDFR_NONE, cmdid_move_left); | ||||
|         bind_params(context, 'a', MDFR_NONE, cmdid_use_sub_map); | ||||
|         fill_param(context, "sub_id", sub_id); | ||||
|         end_params(context); | ||||
|     } | ||||
|     end_multi(context); | ||||
|      | ||||
|     bind(context, 'b', cmdid_seek_alphanumeric_left); | ||||
|     bind(context, 'w', cmdid_seek_alphanumeric_right); | ||||
|     bind(context, 'e', cmdid_seek_white_or_token_right); | ||||
| 
 | ||||
|     // ???? this seems a bit off
 | ||||
|     bind_compound(context, 'g'); | ||||
|     { | ||||
|         bind(context, 'e', cmdid_seek_white_or_token_left); | ||||
|     } | ||||
|     end_compound(context); | ||||
|      | ||||
|     end_map(context); | ||||
|     end_bind_helper(context); | ||||
|      | ||||
|     return context->write_total; | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| strset_(char *dst, char *src){ | ||||
|     do{ | ||||
|         *dst++ = *src++; | ||||
|     }while (*src); | ||||
| } | ||||
| 
 | ||||
| #define strset(d,s) if (sizeof(s) <= sizeof(d)) strset_(d,s) | ||||
| 
 | ||||
| extern "C" SET_EXTRA_FONT_SIG(set_extra_font){ | ||||
|     strset(font_out->file_name, "liberation-mono.ttf"); | ||||
|     strset(font_out->font_name, "BIG"); | ||||
|     font_out->size = 25; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -0,0 +1,228 @@ | |||
| /*
 | ||||
|  * Bind helper struct and functions | ||||
|  */ | ||||
| 
 | ||||
| struct Bind_Helper{ | ||||
|     Binding_Unit *cursor, *start, *end; | ||||
|     Binding_Unit *header, *group; | ||||
|     int write_total; | ||||
|     int error; | ||||
| }; | ||||
| 
 | ||||
| #define BH_ERR_NONE 0 | ||||
| #define BH_ERR_MISSING_END 1 | ||||
| #define BH_ERR_MISSING_BEGIN 2 | ||||
| #define BH_ERR_OUT_OF_MEMORY 3 | ||||
| 
 | ||||
| inline int | ||||
| seek_null(char *str){ | ||||
|     char *start = str; | ||||
|     while (*str) ++str; | ||||
|     return (int)(str - start); | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| copy(char *dest, char *src, int len){ | ||||
|     for (int i = 0; i < len; ++i){ | ||||
|         *dest++ = *src++; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| inline Binding_Unit* | ||||
| write_unit(Bind_Helper *helper, Binding_Unit unit){ | ||||
|     Binding_Unit *p = 0; | ||||
|     helper->write_total += sizeof(*p); | ||||
|     if (helper->error == 0 && helper->cursor != helper->end){ | ||||
|         p = helper->cursor++; | ||||
|         *p = unit; | ||||
|     } | ||||
|     return p; | ||||
| } | ||||
| 
 | ||||
| inline char* | ||||
| write_inline_string(Bind_Helper *helper, char *value, int len){ | ||||
|     char *dest = 0; | ||||
|     helper->write_total += len; | ||||
|     if (helper->error == 0){ | ||||
|         dest = (char*)helper->cursor; | ||||
|         int cursor_advance = len + sizeof(*helper->cursor) - 1; | ||||
|         cursor_advance /= sizeof(*helper->cursor); | ||||
|         cursor_advance *= sizeof(*helper->cursor); | ||||
|         helper->cursor += cursor_advance; | ||||
|         if (helper->cursor < helper->end){ | ||||
|             copy(dest, value, len); | ||||
|         } | ||||
|         else{ | ||||
|             helper->error = BH_ERR_OUT_OF_MEMORY; | ||||
|         } | ||||
|     } | ||||
|     return dest; | ||||
| } | ||||
| 
 | ||||
| inline Bind_Helper | ||||
| begin_bind_helper(void *data, int size){ | ||||
|     Bind_Helper result; | ||||
|      | ||||
|     result.header = 0; | ||||
|     result.group = 0; | ||||
|     result.write_total = 0; | ||||
|     result.error = 0; | ||||
|      | ||||
|     result.cursor = (Binding_Unit*)data; | ||||
|     result.start = result.cursor; | ||||
|     result.end = result.start + size / sizeof(*result.cursor); | ||||
|      | ||||
|     Binding_Unit unit; | ||||
|     unit.type = UNIT_HEADER; | ||||
|     unit.header.total_size = sizeof(*result.header); | ||||
|     result.header = write_unit(&result, unit); | ||||
|     result.header->header.map_count = 0; | ||||
|     result.header->header.group_count = 0; | ||||
|      | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| begin_map(Bind_Helper *helper, int mapid){ | ||||
|     if (helper->group != 0 && helper->error == 0) helper->error = BH_ERR_MISSING_END; | ||||
|     if (!helper->error) ++helper->header->header.map_count; | ||||
|      | ||||
|     Binding_Unit unit; | ||||
|     unit.type = UNIT_MAP_BEGIN; | ||||
|     unit.map_begin.mapid = mapid; | ||||
|     helper->group = write_unit(helper, unit); | ||||
|     helper->group->map_begin.bind_count = 0; | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| end_map(Bind_Helper *helper){ | ||||
|     if (helper->group == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN; | ||||
|     helper->group = 0; | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| bind(Bind_Helper *helper, short code, unsigned char modifiers, int cmdid){ | ||||
|     if (helper->group == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN; | ||||
|     if (!helper->error) ++helper->group->map_begin.bind_count; | ||||
|      | ||||
|     Binding_Unit unit; | ||||
|     unit.type = UNIT_BINDING; | ||||
|     unit.binding.command_id = cmdid; | ||||
|     unit.binding.code = code; | ||||
|     unit.binding.modifiers = modifiers; | ||||
|      | ||||
|     write_unit(helper, unit); | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| bind_me(Bind_Helper *helper, short code, unsigned char modifiers, Custom_Command_Function *func){ | ||||
|     if (helper->group == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN; | ||||
|     if (!helper->error) ++helper->group->map_begin.bind_count; | ||||
|      | ||||
|     Binding_Unit unit; | ||||
|     unit.type = UNIT_CALLBACK; | ||||
|     unit.callback.func = func; | ||||
|     unit.callback.code = code; | ||||
|     unit.callback.modifiers = modifiers; | ||||
|      | ||||
|     write_unit(helper, unit); | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| bind_vanilla_keys(Bind_Helper *helper, int cmdid){ | ||||
|     bind(helper, 0, 0, cmdid); | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| bind_me_vanilla_keys(Bind_Helper *helper, Custom_Command_Function *func){ | ||||
|     bind_me(helper, 0, 0, func); | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| inherit_map(Bind_Helper *helper, int mapid){ | ||||
|     if (helper->group == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN; | ||||
|      | ||||
|     Binding_Unit unit; | ||||
|     unit.type = UNIT_INHERIT; | ||||
|     unit.map_inherit.mapid = mapid; | ||||
|      | ||||
|     write_unit(helper, unit); | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| end_bind_helper(Bind_Helper *helper){ | ||||
|     if (helper->header){ | ||||
|         helper->header->header.total_size = (int)(helper->cursor - helper->start); | ||||
|         helper->header->header.error = helper->error; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| begin_settings_group(Bind_Helper *helper){ | ||||
|     if (helper->group != 0 && helper->error == 0) helper->error = BH_ERR_MISSING_END; | ||||
|     if (!helper->error) ++helper->header->header.group_count; | ||||
|      | ||||
|     Binding_Unit unit; | ||||
|     unit.type = UNIT_SETTINGS_BEGIN; | ||||
|     helper->group = write_unit(helper, unit); | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| end_group(Bind_Helper *helper){ | ||||
|     if (helper->group == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN; | ||||
|     helper->group = 0; | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| use_when(Bind_Helper *helper, int clause_type, int value){ | ||||
|     if (helper->group == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN; | ||||
| 
 | ||||
|     Binding_Unit unit; | ||||
|     unit.type = UNIT_USE_CLAUSE; | ||||
|     unit.use_clause.clause_type = clause_type; | ||||
|     unit.use_clause.value = value; | ||||
|     write_unit(helper, unit); | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| use_when(Bind_Helper *helper, int clause_type, char *value){ | ||||
|     if (helper->group == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN; | ||||
|      | ||||
|     Binding_Unit unit; | ||||
|     unit.type = UNIT_USE_CLAUSE; | ||||
|     unit.use_clause_string.clause_type = clause_type; | ||||
|     unit.use_clause_string.len = seek_null(value); | ||||
|     Binding_Unit *u = write_unit(helper, unit); | ||||
|     u->use_clause_string.value = write_inline_string(helper, value, unit.use_clause_string.len); | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| use_when(Bind_Helper *helper, int clause_type, char *value, int len){ | ||||
|     if (helper->group == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN; | ||||
|      | ||||
|     Binding_Unit unit; | ||||
|     unit.type = UNIT_USE_CLAUSE; | ||||
|     unit.use_clause_string.clause_type = clause_type; | ||||
|     unit.use_clause_string.len = len; | ||||
|     unit.use_clause_string.value = value; | ||||
|     write_unit(helper, unit); | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| set(Bind_Helper *helper, int setting_id, int value){ | ||||
|     if (helper->group == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN; | ||||
|      | ||||
|     Binding_Unit unit; | ||||
|     unit.type = UNIT_SETTING; | ||||
|     unit.setting.setting_id = setting_id; | ||||
|     unit.setting.value = value; | ||||
|     write_unit(helper, unit); | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| end_settings_helper(Bind_Helper *helper){ | ||||
|     if (helper->header){ | ||||
|         helper->header->header.error = helper->error; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -1661,10 +1661,10 @@ cpp_relex_nonalloc_main(Cpp_Relex_State *state, Cpp_Token_Stack *relex_stack, in | |||
|     for (;;){ | ||||
|         Cpp_Read_Result read = cpp_lex_step(state->file, &lex); | ||||
|         if (read.has_result){ | ||||
|             if (read.token.start == match_token.start && | ||||
|                 read.token.size == match_token.size && | ||||
|                 read.token.flags == match_token.flags && | ||||
|                 read.token.state_flags == match_token.state_flags){ | ||||
|             if (read.token.start == end_token.start && | ||||
|                 read.token.size == end_token.size && | ||||
|                 read.token.flags == end_token.flags && | ||||
|                 read.token.state_flags == end_token.state_flags){ | ||||
|                 break; | ||||
|             } | ||||
|             cpp_push_token_nonalloc(relex_stack, read.token); | ||||
|  |  | |||
|  | @ -111,13 +111,13 @@ FCPP_LINK int   hexchar_to_int(char c); | |||
| FCPP_LINK int   int_to_hexchar(char c); | ||||
| FCPP_LINK int   hexstr_to_int(String s); | ||||
| 
 | ||||
| FCPP_LINK void  copy_fast_unsafe(char *dest, char *src); | ||||
| FCPP_LINK int   copy_fast_unsafe(char *dest, char *src); | ||||
| FCPP_LINK void  copy_fast_unsafe(char *dest, String src); | ||||
| FCPP_LINK bool  copy_checked(String *dest, String src); | ||||
| FCPP_LINK bool  copy_partial(String *dest, char *src); | ||||
| FCPP_LINK bool  copy_partial(String *dest, String src); | ||||
| 
 | ||||
| inline    void  copy(char *dest, char *src) { copy_fast_unsafe(dest, src); } | ||||
| inline    int   copy(char *dest, char *src) { return copy_fast_unsafe(dest, src); } | ||||
| inline    void  copy(String *dest, String src) { copy_checked(dest, src); } | ||||
| inline    void  copy(String *dest, char *src) { copy_partial(dest, src); } | ||||
| 
 | ||||
|  | @ -671,14 +671,15 @@ hexstr_to_int(String str){ | |||
|     return x; | ||||
| } | ||||
| 
 | ||||
| FCPP_LINK void | ||||
| FCPP_LINK int | ||||
| copy_fast_unsafe(char *dest, char *src){ | ||||
|     int i = 0; | ||||
|     while (src[i] != 0){ | ||||
|         dest[i] = src[i]; | ||||
|         ++i; | ||||
|     char *start = dest; | ||||
|     while (*src != 0){ | ||||
|         *dest = *src; | ||||
|         ++dest; | ||||
|         ++src; | ||||
|     } | ||||
|     dest[i] = 0; | ||||
|     return (int)(dest - start); | ||||
| } | ||||
| 
 | ||||
| FCPP_LINK void | ||||
|  | @ -688,7 +689,6 @@ copy_fast_unsafe(char *dest, String src){ | |||
|         dest[i] = src.str[i]; | ||||
|         ++i; | ||||
|     } | ||||
|     dest[i] = 0; | ||||
| } | ||||
| 
 | ||||
| FCPP_LINK bool | ||||
|  |  | |||
|  | @ -71,66 +71,6 @@ struct Color_Highlight{ | |||
|     i32 ids[4]; | ||||
| }; | ||||
| 
 | ||||
| struct Widget_ID{ | ||||
|     i32 id; | ||||
|     i32 sub_id0; | ||||
|     i32 sub_id1; | ||||
|     i32 sub_id2; | ||||
| }; | ||||
| 
 | ||||
| inline bool32 | ||||
| widget_match(Widget_ID s1, Widget_ID s2){ | ||||
|     return (s1.id == s2.id && s1.sub_id0 == s2.sub_id0 && | ||||
|             s1.sub_id1 == s2.sub_id1 && s1.sub_id2 == s2.sub_id2); | ||||
| } | ||||
| 
 | ||||
| struct UI_State{ | ||||
|     Render_Target *target; | ||||
|     Style *style; | ||||
|     Font *font; | ||||
|     Mouse_Summary *mouse; | ||||
|     Key_Summary *keys; | ||||
|     Key_Codes *codes; | ||||
|     Working_Set *working_set; | ||||
|      | ||||
|     Widget_ID selected, hover, hot; | ||||
|     bool32 activate_me; | ||||
|     bool32 redraw; | ||||
|     bool32 input_stage; | ||||
|     i32 sub_id1_change; | ||||
|      | ||||
|     real32 height, view_y; | ||||
| }; | ||||
| 
 | ||||
| inline bool32 | ||||
| is_selected(UI_State *state, Widget_ID id){ | ||||
|     return widget_match(state->selected, id); | ||||
| } | ||||
| 
 | ||||
| inline bool32 | ||||
| is_hot(UI_State *state, Widget_ID id){ | ||||
|     return widget_match(state->hot, id); | ||||
| } | ||||
| 
 | ||||
| inline bool32 | ||||
| is_hover(UI_State *state, Widget_ID id){ | ||||
|     return widget_match(state->hover, id); | ||||
| } | ||||
| 
 | ||||
| struct UI_Layout{ | ||||
|     i32 row_count; | ||||
|     i32 row_item_width; | ||||
|     i32 row_max_item_height; | ||||
|      | ||||
|     i32_Rect rect; | ||||
|     i32 x, y;     | ||||
| }; | ||||
| 
 | ||||
| struct UI_Layout_Restore{ | ||||
|     UI_Layout layout; | ||||
|     UI_Layout *dest; | ||||
| }; | ||||
| 
 | ||||
| struct Library_UI{ | ||||
|     UI_State state; | ||||
|     UI_Layout layout; | ||||
|  | @ -183,58 +123,6 @@ view_to_color_view(View *view){ | |||
|     return (Color_View*)view; | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| begin_layout(UI_Layout *layout, i32_Rect rect){ | ||||
|     layout->rect = rect; | ||||
|     layout->x = rect.x0; | ||||
|     layout->y = rect.y0; | ||||
|     layout->row_count = 0; | ||||
|     layout->row_max_item_height = 0; | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| begin_row(UI_Layout *layout, i32 count){ | ||||
|     layout->row_count = count; | ||||
|     layout->row_item_width = (layout->rect.x1 - layout->x) / count;  | ||||
| } | ||||
| 
 | ||||
| inline i32_Rect | ||||
| layout_rect(UI_Layout *layout, i32 height){ | ||||
|     i32_Rect rect; | ||||
|     rect.x0 = layout->x; | ||||
|     rect.y0 = layout->y; | ||||
|     rect.x1 = rect.x0; | ||||
|     rect.y1 = rect.y0 + height; | ||||
|     if (layout->row_count > 0){ | ||||
|         --layout->row_count; | ||||
|         rect.x1 = rect.x0 + layout->row_item_width; | ||||
|         layout->x += layout->row_item_width; | ||||
|         layout->row_max_item_height = Max(height, layout->row_max_item_height); | ||||
|     } | ||||
|     if (layout->row_count == 0){ | ||||
|         rect.x1 = layout->rect.x1; | ||||
|         layout->row_max_item_height = Max(height, layout->row_max_item_height); | ||||
|         layout->y += layout->row_max_item_height; | ||||
|         layout->x = layout->rect.x0; | ||||
|         layout->row_max_item_height = 0; | ||||
|     } | ||||
|     return rect; | ||||
| } | ||||
| 
 | ||||
| inline UI_Layout_Restore | ||||
| begin_sub_layout(UI_Layout *layout, i32_Rect area){ | ||||
|     UI_Layout_Restore restore; | ||||
|     restore.layout = *layout; | ||||
|     restore.dest = layout; | ||||
|     begin_layout(layout, area); | ||||
|     return restore; | ||||
| } | ||||
| 
 | ||||
| inline void | ||||
| end_sub_layout(UI_Layout_Restore restore){ | ||||
|     *restore.dest = restore.layout; | ||||
| } | ||||
| 
 | ||||
| internal real32 | ||||
| font_string_width(Font *font, char *str){ | ||||
|     real32 x = 0; | ||||
|  | @ -308,203 +196,6 @@ draw_rgb_slider(Render_Target *target, Vec4 base, i32 channel, i32 steps, real32 | |||
|     draw_gradient_slider(target, base, channel, steps, top, slider, 0); | ||||
| } | ||||
| 
 | ||||
| inline Widget_ID | ||||
| make_id(UI_State *state, i32 id){ | ||||
|     Widget_ID r = state->selected; | ||||
|     r.id = id; | ||||
|     return r; | ||||
| } | ||||
| 
 | ||||
| inline Widget_ID | ||||
| make_sub0(UI_State *state, i32 id){ | ||||
|     Widget_ID r = state->selected; | ||||
|     r.sub_id0 = id; | ||||
|     return r; | ||||
| } | ||||
| 
 | ||||
| inline Widget_ID | ||||
| make_sub1(UI_State *state, i32 id){ | ||||
|     Widget_ID r = state->selected; | ||||
|     r.sub_id1 = id; | ||||
|     return r; | ||||
| } | ||||
| 
 | ||||
| inline Widget_ID | ||||
| make_sub2(UI_State *state, i32 id){ | ||||
|     Widget_ID r = state->selected; | ||||
|     r.sub_id2 = id; | ||||
|     return r; | ||||
| } | ||||
| 
 | ||||
| internal bool32 | ||||
| ui_do_button_input(UI_State *state, i32_Rect rect, Widget_ID id, bool32 activate, bool32 *right = 0){ | ||||
|     bool32 result = 0; | ||||
|     Mouse_Summary *mouse = state->mouse; | ||||
|     bool32 hover = hit_check(mouse->mx, mouse->my, rect); | ||||
|     if (hover){ | ||||
|         state->hover = id; | ||||
|         if (activate) state->activate_me = 1; | ||||
|         if (mouse->press_l || (mouse->press_r && right)) state->hot = id; | ||||
|         if (mouse->l && mouse->r) state->hot = {}; | ||||
|     } | ||||
|     bool32 is_match = widget_match(state->hot, id); | ||||
|     if (mouse->release_l && is_match){ | ||||
|         if (hover) result = 1; | ||||
|         state->redraw = 1; | ||||
|     } | ||||
|     if (right && mouse->release_r && is_match){ | ||||
|         if (hover) *right = 1; | ||||
|         state->redraw = 1; | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| internal bool32 | ||||
| ui_do_subdivided_button_input(UI_State *state, i32_Rect rect, i32 parts, Widget_ID id, bool32 activate, i32 *indx_out, bool32 *right = 0){ | ||||
|     bool32 result = 0; | ||||
|     real32 x0, x1; | ||||
|     i32_Rect sub_rect; | ||||
|     Widget_ID sub_widg = id; | ||||
|     real32 sub_width = (rect.x1 - rect.x0) / (real32)parts; | ||||
|     sub_rect.y0 = rect.y0; | ||||
|     sub_rect.y1 = rect.y1; | ||||
|     x1 = (real32)rect.x0; | ||||
|      | ||||
|     for (i32 i = 0; i < parts; ++i){ | ||||
|         x0 = x1; | ||||
|         x1 = x1 + sub_width; | ||||
|         sub_rect.x0 = TRUNC32(x0); | ||||
|         sub_rect.x1 = TRUNC32(x1); | ||||
|         sub_widg.sub_id2 = i; | ||||
|         if (ui_do_button_input(state, sub_rect, sub_widg, activate, right)){ | ||||
|             *indx_out = i; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| internal real32 | ||||
| ui_do_vscroll_input(UI_State *state, i32_Rect top, i32_Rect bottom, i32_Rect slider, | ||||
|                     Widget_ID id, real32 val, real32 step_amount, | ||||
|                     real32 smin, real32 smax, real32 vmin, real32 vmax){ | ||||
|     Mouse_Summary *mouse = state->mouse; | ||||
|     i32 mx = mouse->mx; | ||||
|     i32 my = mouse->my; | ||||
|     if (hit_check(mx, my, top)){ | ||||
|         state->hover = id; | ||||
|         state->hover.sub_id2 = 1; | ||||
|     } | ||||
|     if (hit_check(mx, my, bottom)){ | ||||
|         state->hover = id; | ||||
|         state->hover.sub_id2 = 2; | ||||
|     } | ||||
|     if (hit_check(mx, my, slider)){ | ||||
|         state->hover = id; | ||||
|         state->hover.sub_id2 = 3; | ||||
|     } | ||||
|     if (mouse->press_l) state->hot = state->hover; | ||||
|     if (id.id == state->hot.id){ | ||||
|         if (mouse->release_l){ | ||||
|             Widget_ID wid1, wid2; | ||||
|             wid1 = wid2 = id; | ||||
|             wid1.sub_id2 = 1; | ||||
|             wid2.sub_id2 = 2; | ||||
|             if (state->hot.sub_id2 == 1 && is_hover(state, wid1)) val -= step_amount; | ||||
|             if (state->hot.sub_id2 == 2 && is_hover(state, wid2)) val += step_amount; | ||||
|             state->redraw = 1; | ||||
|         } | ||||
|         if (state->hot.sub_id2 == 3){ | ||||
|             real32 S, L; | ||||
|             S = (real32)mouse->my - (slider.y1 - slider.y0) / 2; | ||||
|             if (S < smin) S = smin; | ||||
|             if (S > smax) S = smax; | ||||
|             L = unlerp(smin, S, smax); | ||||
|             val = lerp(vmin, L, vmax); | ||||
|             state->redraw = 1; | ||||
|         } | ||||
|     } | ||||
|     return val; | ||||
| } | ||||
| 
 | ||||
| internal bool32 | ||||
| ui_do_text_field_input(UI_State *state, String *str){ | ||||
|     bool32 result = 0; | ||||
|     Key_Summary *keys = state->keys; | ||||
|     for (i32 key_i = 0; key_i < keys->count; ++key_i){ | ||||
|         Key_Single key = get_single_key(keys, key_i); | ||||
|         char c = (char)key.key.character; | ||||
|         if (char_is_basic(c) && str->size < str->memory_size-1){ | ||||
|             str->str[str->size++] = c; | ||||
|             str->str[str->size] = 0; | ||||
|         } | ||||
|         else if (c == '\n'){ | ||||
|             result = 1; | ||||
|         } | ||||
|         else if (key.key.keycode == state->codes->back && str->size > 0){ | ||||
|             str->str[--str->size] = 0; | ||||
|         } | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| internal bool32 | ||||
| ui_do_file_field_input(UI_State *state, Hot_Directory *hot_dir){ | ||||
|     bool32 result = 0; | ||||
|     Key_Summary *keys = state->keys; | ||||
|     for (i32 key_i = 0; key_i < keys->count; ++key_i){ | ||||
|         Key_Single key = get_single_key(keys, key_i); | ||||
|         String *str = &hot_dir->string; | ||||
|         terminate_with_null(str); | ||||
|         Single_Line_Input_Step step = | ||||
|             app_single_file_input_step(state->codes, state->working_set, key, str, hot_dir, 1); | ||||
|         if (step.hit_newline || step.hit_ctrl_newline) result = 1; | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| internal bool32 | ||||
| ui_do_line_field_input(UI_State *state, String *string){ | ||||
|     bool32 result = 0; | ||||
|     Key_Summary *keys = state->keys; | ||||
|     for (i32 key_i = 0; key_i < keys->count; ++key_i){ | ||||
|         Key_Single key = get_single_key(keys, key_i); | ||||
|         terminate_with_null(string); | ||||
|         Single_Line_Input_Step step = | ||||
|             app_single_line_input_step(state->codes, key, string); | ||||
|         if (step.hit_newline || step.hit_ctrl_newline) result = 1; | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| internal bool32 | ||||
| ui_do_slider_input(UI_State *state, i32_Rect rect, Widget_ID wid, | ||||
|                    real32 min, real32 max, real32 *v){ | ||||
|     bool32 result = 0; | ||||
|     ui_do_button_input(state, rect, wid, 0); | ||||
|     Mouse_Summary *mouse = state->mouse; | ||||
|     if (is_hot(state, wid)){ | ||||
|         result = 1; | ||||
|         *v = unlerp(min, (real32)mouse->mx, max); | ||||
|         state->redraw = 1; | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| struct UI_Style{ | ||||
|     u32 dark, dim, bright; | ||||
| }; | ||||
| 
 | ||||
| internal UI_Style | ||||
| get_ui_style(Style *style){ | ||||
|     UI_Style ui_style; | ||||
|     ui_style.dark = style->main.back_color; | ||||
|     ui_style.dim = style->main.margin_color; | ||||
|     ui_style.bright = style->main.margin_active_color; | ||||
|     return ui_style; | ||||
| } | ||||
| 
 | ||||
| internal void | ||||
| do_label(UI_State *state, UI_Layout *layout, char *text, real32 height = 2.f){ | ||||
|     Style *style = state->style; | ||||
|  | @ -522,27 +213,6 @@ do_label(UI_State *state, UI_Layout *layout, char *text, real32 height = 2.f){ | |||
|     } | ||||
| } | ||||
| 
 | ||||
| internal void | ||||
| get_colors(UI_State *state, u32 *back, u32 *fore, Widget_ID wid, UI_Style style){ | ||||
|     bool32 hover = is_hover(state, wid); | ||||
|     bool32 hot = is_hot(state, wid); | ||||
|     i32 level = hot + hover; | ||||
|     switch (level){ | ||||
|     case 2: | ||||
|         *back = style.bright; | ||||
|         *fore = style.dark; | ||||
|         break; | ||||
|     case 1: | ||||
|         *back = style.dim; | ||||
|         *fore = style.bright; | ||||
|         break; | ||||
|     case 0: | ||||
|         *back = style.dark; | ||||
|         *fore = style.bright; | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| internal bool32 | ||||
| do_button(i32 id, UI_State *state, UI_Layout *layout, char *text, | ||||
|           bool32 is_toggle = 0, bool32 on = 0){ | ||||
|  | @ -550,7 +220,7 @@ do_button(i32 id, UI_State *state, UI_Layout *layout, char *text, | |||
|     Font *font = state->font; | ||||
|     i32 character_h = font->height; | ||||
|      | ||||
|     i32_Rect btn_rect = layout_rect(layout, font->height * 2); | ||||
|     i32_Rect btn_rect = layout_rect(layout, character_h * 2); | ||||
|     btn_rect = get_inner_rect(btn_rect, 2); | ||||
|      | ||||
|     Widget_ID wid = make_id(state, id); | ||||
|  | @ -1350,75 +1020,6 @@ do_font_switch(Color_UI *ui){ | |||
|     } | ||||
| } | ||||
| 
 | ||||
| internal UI_State | ||||
| ui_state_init(UI_State *state_in, Render_Target *target, Input_Summary *user_input, | ||||
|               Style *style, Working_Set *working_set, bool32 input_stage){ | ||||
|     UI_State state; | ||||
|     state.target = target; | ||||
|     state.style = style; | ||||
|     state.font = style->font; | ||||
|     state.working_set = working_set; | ||||
|     state.mouse = &user_input->mouse; | ||||
|     state.keys = &user_input->keys; | ||||
|     state.codes = user_input->codes; | ||||
|     state.selected = state_in->selected; | ||||
|     state.hot = state_in->hot; | ||||
|     if (input_stage) state.hover = {}; | ||||
|     else state.hover = state_in->hover; | ||||
|     state.redraw = 0; | ||||
|     state.activate_me = 0; | ||||
|     state.input_stage = input_stage; | ||||
|     state.height = state_in->height; | ||||
|     state.view_y = state_in->view_y; | ||||
|     return state; | ||||
| } | ||||
| 
 | ||||
| inline bool32 | ||||
| ui_state_match(UI_State a, UI_State b){ | ||||
|     return (widget_match(a.selected, b.selected) && | ||||
|             widget_match(a.hot, b.hot) && | ||||
|             widget_match(a.hover, b.hover)); | ||||
| } | ||||
| 
 | ||||
| internal bool32 | ||||
| ui_finish_frame(UI_State *persist_state, UI_State *state, UI_Layout *layout, i32_Rect rect, | ||||
|                 bool32 do_wheel, bool32 *did_activation){ | ||||
|     bool32 result = 0; | ||||
|     real32 h = layout->y + persist_state->view_y - rect.y0; | ||||
|     real32 max_y = h - (rect.y1 - rect.y0); | ||||
|      | ||||
|     persist_state->height = h; | ||||
|     persist_state->view_y = state->view_y; | ||||
|      | ||||
|     if (state->input_stage){ | ||||
|         Mouse_Summary *mouse = state->mouse; | ||||
|         if (mouse->wheel_used && do_wheel){ | ||||
|             persist_state->view_y += mouse->wheel_amount*state->font->height; | ||||
|             result = 1; | ||||
|         } | ||||
|         if (mouse->release_l && widget_match(state->hot, state->hover)){ | ||||
|             if (did_activation) *did_activation = 1; | ||||
|             if (state->activate_me){ | ||||
|                 state->selected = state->hot; | ||||
|             } | ||||
|         } | ||||
|         if (!mouse->l && !mouse->r){ | ||||
|             state->hot = {}; | ||||
|         } | ||||
|          | ||||
|         if (!ui_state_match(*persist_state, *state) || state->redraw){ | ||||
|             result = 1; | ||||
|         } | ||||
|          | ||||
|         *persist_state = *state; | ||||
|     } | ||||
|      | ||||
|     if (persist_state->view_y >= max_y) persist_state->view_y = max_y; | ||||
|     if (persist_state->view_y < 0) persist_state->view_y = 0; | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| internal i32 | ||||
| step_draw_adjusting(Color_View *color_view, i32_Rect rect, View_Message message, | ||||
|                     Render_Target *target, Input_Summary *user_input){ | ||||
|  | @ -1860,11 +1461,11 @@ do_file_list_box(UI_State *state, UI_Layout *layout, Hot_Directory *hot_dir, boo | |||
|         terminate_with_null(&hot_dir->string); | ||||
|     } | ||||
|     else{ | ||||
|         String p4c_extension = make_lit_string("p4c"); | ||||
|         String message_loaded = make_lit_string(" LOADED"); | ||||
|         String message_unsaved = make_lit_string(" LOADED *"); | ||||
|         String message_unsynced = make_lit_string(" LOADED BEHIND OS"); | ||||
|         String message_nothing = {}; | ||||
|         persist String p4c_extension = make_lit_string("p4c"); | ||||
|         persist String message_loaded = make_lit_string(" LOADED"); | ||||
|         persist String message_unsaved = make_lit_string(" LOADED *"); | ||||
|         persist String message_unsynced = make_lit_string(" LOADED BEHIND OS"); | ||||
|         persist String message_nothing = {}; | ||||
|          | ||||
|         char front_name_space[256]; | ||||
|         String front_name = make_fixed_width_string(front_name_space); | ||||
|  | @ -1896,14 +1497,10 @@ do_file_list_box(UI_State *state, UI_Layout *layout, Hot_Directory *hot_dir, boo | |||
|              | ||||
|             String message = message_nothing; | ||||
|             if (is_loaded){ | ||||
|                 if (file->last_4ed_write_time != file->last_sys_write_time){ | ||||
|                     message = message_unsynced; | ||||
|                 } | ||||
|                 else if (file->last_4ed_edit_time > file->last_sys_write_time){ | ||||
|                     message = message_unsaved; | ||||
|                 } | ||||
|                 else{ | ||||
|                     message = message_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; | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|  | @ -1938,6 +1535,10 @@ do_live_file_list_box(UI_State *state, UI_Layout *layout, Working_Set *working_s | |||
|         terminate_with_null(string); | ||||
|     } | ||||
|     else{ | ||||
|         persist String message_unsaved = make_lit_string(" *"); | ||||
|         persist String message_unsynced = make_lit_string(" BEHIND OS"); | ||||
|         persist String message_nothing = {}; | ||||
|          | ||||
|         Absolutes absolutes; | ||||
|         get_absolutes(*string, &absolutes, 1, 1); | ||||
|          | ||||
|  | @ -1947,8 +1548,14 @@ do_live_file_list_box(UI_State *state, UI_Layout *layout, Working_Set *working_s | |||
|             Editing_File *file = files + i; | ||||
|              | ||||
|             if (!file->is_dummy){ | ||||
|                 String message = message_nothing; | ||||
|                 switch (buffer_get_sync(file)){ | ||||
|                 case SYNC_BEHIND_OS: message = message_unsynced; break; | ||||
|                 case SYNC_UNSAVED: message = message_unsaved; break; | ||||
|                 } | ||||
|                  | ||||
|                 if (filename_match(*string, &absolutes, file->live_name)){ | ||||
|                     if (do_file_option(100+i, state, layout, file->live_name, 0, {})){ | ||||
|                     if (do_file_option(100+i, state, layout, file->live_name, 0, message)){ | ||||
|                         result = 1; | ||||
|                         *selected = 1; | ||||
|                         copy(string, file->live_name); | ||||
|  |  | |||
|  | @ -121,11 +121,11 @@ map_extract(Command_Map *map, Key_Single key){ | |||
|     if (alt) command |= MDFR_ALT; | ||||
|      | ||||
|     u16 code = key.key.character_no_caps_lock; | ||||
|     if (code != 0) map_get_vanilla_keyboard_default(map, command, &bind); | ||||
|     if (code == 0) code = key.key.keycode; | ||||
|     map_find(map, code, command, &bind); | ||||
|      | ||||
|     if (bind.function == 0){ | ||||
|         if (code == 0) code = key.key.keycode; | ||||
|         map_find(map, code, command, &bind); | ||||
|     if (bind.function == 0 && key.key.character_no_caps_lock != 0){ | ||||
|         map_get_vanilla_keyboard_default(map, command, &bind); | ||||
|     } | ||||
|      | ||||
|     return bind; | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ internal i32 | |||
| draw_general_memory(Debug_View *view, i32_Rect rect, Render_Target *target, i32 y){ | ||||
|     Font *font = view->font; | ||||
|     i32 y_advance = font->height; | ||||
|     Bubble *sentinel = &view->view_base.general->sentinel; | ||||
|     Bubble *sentinel = &view->view_base.mem->general.sentinel; | ||||
|      | ||||
|     for (Bubble *bubble = sentinel->next; | ||||
|          bubble != sentinel; | ||||
|  | @ -62,6 +62,8 @@ draw_general_memory(Debug_View *view, i32_Rect rect, Render_Target *target, i32 | |||
|             case BUBBLE_TOKENS: append(&s, "tokens"); break; | ||||
|             case BUBBLE_UNDO_STRING: append(&s, "undo string"); break; | ||||
|             case BUBBLE_UNDO: append(&s, "undo"); break; | ||||
|             case BUBBLE_HISTORY_STRING: append(&s, "history string"); break; | ||||
|             case BUBBLE_HISTORY: append(&s, "history"); break; | ||||
|             default: append(&s, "unknown"); break; | ||||
|             } | ||||
|         } | ||||
|  |  | |||
							
								
								
									
										2520
									
								
								4ed_file_view.cpp
								
								
								
								
							
							
						
						
									
										2520
									
								
								4ed_file_view.cpp
								
								
								
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -9,50 +9,19 @@ | |||
| 
 | ||||
| // TOP
 | ||||
| 
 | ||||
| enum Action_Type{ | ||||
|     DACT_OPEN, | ||||
|     DACT_SAVE_AS, | ||||
|     DACT_NEW, | ||||
|     DACT_SWITCH, | ||||
|     DACT_KILL, | ||||
|     DACT_CLOSE_MINOR, | ||||
|     DACT_CLOSE_MAJOR, | ||||
|     DACT_THEME_OPTIONS | ||||
| }; | ||||
| 
 | ||||
| struct Delayed_Action{ | ||||
|     Action_Type type; | ||||
|     String string; | ||||
|     Panel *panel; | ||||
| }; | ||||
| 
 | ||||
| struct Delay{ | ||||
|     Delayed_Action acts[8]; | ||||
|     i32 count, max; | ||||
| }; | ||||
| 
 | ||||
| inline void | ||||
| delayed_action(Delay *delay, Action_Type type, | ||||
|                String string, Panel *panel){ | ||||
|     Assert(delay->count < delay->max); | ||||
|     Delayed_Action action; | ||||
|     action.type = type; | ||||
|     action.string = string; | ||||
|     action.panel = panel; | ||||
|     delay->acts[delay->count++] = action; | ||||
| } | ||||
| 
 | ||||
| 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{ | ||||
|  | @ -64,10 +33,12 @@ struct Interactive_View{ | |||
|     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* | ||||
|  | @ -101,8 +72,26 @@ interactive_view_complete(Interactive_View *view){ | |||
|         break; | ||||
|          | ||||
|     case INTV_KILL: | ||||
|         delayed_action(view->delay, DACT_KILL, view->dest, panel); | ||||
|         delayed_action(view->delay, DACT_CLOSE_MINOR, {}, panel); | ||||
|         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; | ||||
|     } | ||||
| } | ||||
|  | @ -119,7 +108,7 @@ step_draw_int_view(Interactive_View *view, Render_Target *target, i32_Rect rect, | |||
|     begin_layout(&layout, rect); | ||||
|      | ||||
|     bool32 new_dir = 0; | ||||
|     bool32 file_selected = 0; | ||||
|     bool32 complete = 0; | ||||
| 
 | ||||
|     terminate_with_null(&view->query); | ||||
|     do_label(&state, &layout, view->query.str, 1.f); | ||||
|  | @ -127,7 +116,7 @@ step_draw_int_view(Interactive_View *view, Render_Target *target, i32_Rect rect, | |||
|     switch (view->interaction){ | ||||
|     case INTV_SYS_FILE_LIST: | ||||
|         if (do_file_list_box(&state, &layout, view->hot_directory, 0, | ||||
|                              &new_dir, &file_selected, 0)){ | ||||
|                              &new_dir, &complete, 0)){ | ||||
|             result = 1; | ||||
|         } | ||||
|         if (new_dir){ | ||||
|  | @ -136,13 +125,55 @@ step_draw_int_view(Interactive_View *view, Render_Target *target, i32_Rect rect, | |||
|         break; | ||||
|          | ||||
|     case INTV_LIVE_FILE_LIST: | ||||
|         if (do_live_file_list_box(&state, &layout, view->working_set, &view->dest, &file_selected)){ | ||||
|         if (do_live_file_list_box(&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.str, 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 (file_selected){ | ||||
|     if (complete){ | ||||
|         interactive_view_complete(view); | ||||
|     } | ||||
|      | ||||
|  | @ -156,6 +187,7 @@ step_draw_int_view(Interactive_View *view, Render_Target *target, i32_Rect rect, | |||
| 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: | ||||
|  |  | |||
|  | @ -69,7 +69,7 @@ struct View{ | |||
|     Command_Map *map; | ||||
|     Do_View_Function *do_view; | ||||
|     Handle_Command_Function *handle_command; | ||||
|     General_Memory *general; | ||||
|     Mem_Options *mem; | ||||
|     i32 type; | ||||
|     i32 block_size; | ||||
|     Application_Mouse_Cursor mouse_cursor_type; | ||||
|  | @ -173,7 +173,7 @@ live_set_get_view(Live_Views *live_set, i32 i){ | |||
| } | ||||
| 
 | ||||
| internal View* | ||||
| live_set_alloc_view(Live_Views *live_set, General_Memory *general){ | ||||
| live_set_alloc_view(Live_Views *live_set, Mem_Options *mem){ | ||||
|     Assert(live_set->count < live_set->max); | ||||
|     View *result = 0; | ||||
|     result = live_set->free_view; | ||||
|  | @ -181,7 +181,7 @@ live_set_alloc_view(Live_Views *live_set, General_Memory *general){ | |||
|     memset(result, 0, live_set->stride); | ||||
|     ++live_set->count; | ||||
|     result->is_active = 1; | ||||
|     result->general = general; | ||||
|     result->mem = mem; | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Allen Webster
						Allen Webster