Initial sloppy setup for customizable line layout
parent
af78a9966e
commit
187f91084a
|
@ -356,64 +356,84 @@ buffer_seek_character_class(Application_Links *app, Buffer_ID buffer, Character_
|
||||||
}
|
}
|
||||||
|
|
||||||
api(custom) function f32
|
api(custom) function f32
|
||||||
buffer_line_y_difference(Application_Links *app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 line_a, i64 line_b){
|
buffer_line_y_difference(Application_Links *app, Buffer_ID buffer_id,
|
||||||
|
f32 width, Face_ID face_id,
|
||||||
|
i64 line_a, i64 line_b){
|
||||||
Models *models = (Models*)app->cmd_context;
|
Models *models = (Models*)app->cmd_context;
|
||||||
Editing_File *file = imp_get_file(models, buffer_id);
|
Editing_File *file = imp_get_file(models, buffer_id);
|
||||||
f32 result = {};
|
f32 result = {};
|
||||||
if (api_check_buffer(file)){
|
if (api_check_buffer(file)){
|
||||||
Face *face = font_set_face_from_id(&models->font_set, face_id);
|
Face *face = font_set_face_from_id(&models->font_set, face_id);
|
||||||
if (face != 0){
|
if (face != 0){
|
||||||
result = file_line_y_difference(app->tctx, models, file, width, face, line_a, line_b);
|
Layout_Function *layout_func = models->layout_func;
|
||||||
|
result = file_line_y_difference(app->tctx, models, file,
|
||||||
|
layout_func, width, face,
|
||||||
|
line_a, line_b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
api(custom) function Line_Shift_Vertical
|
api(custom) function Line_Shift_Vertical
|
||||||
buffer_line_shift_y(Application_Links *app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 line, f32 y_shift){
|
buffer_line_shift_y(Application_Links *app, Buffer_ID buffer_id,
|
||||||
|
f32 width, Face_ID face_id,
|
||||||
|
i64 line, f32 y_shift){
|
||||||
Models *models = (Models*)app->cmd_context;
|
Models *models = (Models*)app->cmd_context;
|
||||||
Editing_File *file = imp_get_file(models, buffer_id);
|
Editing_File *file = imp_get_file(models, buffer_id);
|
||||||
Line_Shift_Vertical result = {};
|
Line_Shift_Vertical result = {};
|
||||||
if (api_check_buffer(file)){
|
if (api_check_buffer(file)){
|
||||||
Face *face = font_set_face_from_id(&models->font_set, face_id);
|
Face *face = font_set_face_from_id(&models->font_set, face_id);
|
||||||
if (face != 0){
|
if (face != 0){
|
||||||
result = file_line_shift_y(app->tctx, models, file, width, face, line, y_shift);
|
Layout_Function *layout_func = models->layout_func;
|
||||||
|
result = file_line_shift_y(app->tctx, models, file,
|
||||||
|
layout_func, width, face,
|
||||||
|
line, y_shift);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
api(custom) function i64
|
api(custom) function i64
|
||||||
buffer_pos_at_relative_xy(Application_Links *app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, Vec2_f32 relative_xy){
|
buffer_pos_at_relative_xy(Application_Links *app, Buffer_ID buffer_id,
|
||||||
|
f32 width, Face_ID face_id,
|
||||||
|
i64 base_line, Vec2_f32 relative_xy){
|
||||||
Models *models = (Models*)app->cmd_context;
|
Models *models = (Models*)app->cmd_context;
|
||||||
Editing_File *file = imp_get_file(models, buffer_id);
|
Editing_File *file = imp_get_file(models, buffer_id);
|
||||||
i64 result = -1;
|
i64 result = -1;
|
||||||
if (api_check_buffer(file)){
|
if (api_check_buffer(file)){
|
||||||
Face *face = font_set_face_from_id(&models->font_set, face_id);
|
Face *face = font_set_face_from_id(&models->font_set, face_id);
|
||||||
if (face != 0){
|
if (face != 0){
|
||||||
result = file_pos_at_relative_xy(app->tctx, models, file, width, face, base_line, relative_xy);
|
Layout_Function *layout_func = models->layout_func;
|
||||||
|
result = file_pos_at_relative_xy(app->tctx, models, file,
|
||||||
|
layout_func, width, face,
|
||||||
|
base_line, relative_xy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
api(custom) function Vec2_f32
|
api(custom) function Vec2_f32
|
||||||
buffer_relative_xy_of_pos(Application_Links *app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 pos)
|
buffer_relative_xy_of_pos(Application_Links *app, Buffer_ID buffer_id,
|
||||||
{
|
f32 width, Face_ID face_id,
|
||||||
|
i64 base_line, i64 pos){
|
||||||
Models *models = (Models*)app->cmd_context;
|
Models *models = (Models*)app->cmd_context;
|
||||||
Editing_File *file = imp_get_file(models, buffer_id);
|
Editing_File *file = imp_get_file(models, buffer_id);
|
||||||
Vec2_f32 result = {};
|
Vec2_f32 result = {};
|
||||||
if (api_check_buffer(file)){
|
if (api_check_buffer(file)){
|
||||||
Face *face = font_set_face_from_id(&models->font_set, face_id);
|
Face *face = font_set_face_from_id(&models->font_set, face_id);
|
||||||
if (face != 0){
|
if (face != 0){
|
||||||
result = file_relative_xy_of_pos(app->tctx, models, file, width, face, base_line, pos);
|
Layout_Function *layout_func = models->layout_func;
|
||||||
|
result = file_relative_xy_of_pos(app->tctx, models, file,
|
||||||
|
layout_func, width, face,
|
||||||
|
base_line, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
api(custom) function i64
|
api(custom) function i64
|
||||||
buffer_relative_character_from_pos(Application_Links *app, Buffer_ID buffer_id, f32 width, Face_ID face_id, i64 base_line, i64 pos)
|
buffer_relative_character_from_pos(Application_Links *app, Buffer_ID buffer_id,
|
||||||
|
f32 width, Face_ID face_id, i64 base_line, i64 pos)
|
||||||
{
|
{
|
||||||
Models *models = (Models*)app->cmd_context;
|
Models *models = (Models*)app->cmd_context;
|
||||||
Editing_File *file = imp_get_file(models, buffer_id);
|
Editing_File *file = imp_get_file(models, buffer_id);
|
||||||
|
@ -421,7 +441,10 @@ buffer_relative_character_from_pos(Application_Links *app, Buffer_ID buffer_id,
|
||||||
if (api_check_buffer(file)){
|
if (api_check_buffer(file)){
|
||||||
Face *face = font_set_face_from_id(&models->font_set, face_id);
|
Face *face = font_set_face_from_id(&models->font_set, face_id);
|
||||||
if (face != 0){
|
if (face != 0){
|
||||||
result = file_relative_character_from_pos(app->tctx, models, file, width, face, base_line, pos);
|
Layout_Function *layout_func = models->layout_func;
|
||||||
|
result = file_relative_character_from_pos(app->tctx, models, file,
|
||||||
|
layout_func, width, face,
|
||||||
|
base_line, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(result);
|
return(result);
|
||||||
|
@ -436,7 +459,10 @@ buffer_pos_from_relative_character(Application_Links *app, Buffer_ID buffer_id,
|
||||||
if (api_check_buffer(file)){
|
if (api_check_buffer(file)){
|
||||||
Face *face = font_set_face_from_id(&models->font_set, face_id);
|
Face *face = font_set_face_from_id(&models->font_set, face_id);
|
||||||
if (face != 0){
|
if (face != 0){
|
||||||
result = file_pos_from_relative_character(app->tctx, models, file, width, face, base_line, relative_character);
|
Layout_Function *layout_func = models->layout_func;
|
||||||
|
result = file_pos_from_relative_character(app->tctx, models, file,
|
||||||
|
layout_func, width, face,
|
||||||
|
base_line, relative_character);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(result);
|
return(result);
|
||||||
|
@ -1497,8 +1523,10 @@ view_set_buffer_scroll(Application_Links *app, View_ID view_id, Buffer_Scroll sc
|
||||||
scroll.target.pixel_shift.x = f32_round32(scroll.target.pixel_shift.x);
|
scroll.target.pixel_shift.x = f32_round32(scroll.target.pixel_shift.x);
|
||||||
scroll.target.pixel_shift.y = f32_round32(scroll.target.pixel_shift.y);
|
scroll.target.pixel_shift.y = f32_round32(scroll.target.pixel_shift.y);
|
||||||
scroll.target.pixel_shift.x = clamp_bot(0.f, scroll.target.pixel_shift.x);
|
scroll.target.pixel_shift.x = clamp_bot(0.f, scroll.target.pixel_shift.x);
|
||||||
Buffer_Layout_Item_List line = view_get_line_layout(tctx, models, view, scroll.target.line_number);
|
Layout_Item_List line = view_get_line_layout(tctx, models, view,
|
||||||
scroll.target.pixel_shift.y = clamp(0.f, scroll.target.pixel_shift.y, line.height);
|
scroll.target.line_number);
|
||||||
|
scroll.target.pixel_shift.y =
|
||||||
|
clamp(0.f, scroll.target.pixel_shift.y, line.height);
|
||||||
if (rule == SetBufferScroll_SnapCursorIntoView){
|
if (rule == SetBufferScroll_SnapCursorIntoView){
|
||||||
view_set_scroll(tctx, models, view, scroll);
|
view_set_scroll(tctx, models, view, scroll);
|
||||||
}
|
}
|
||||||
|
@ -2139,6 +2167,10 @@ set_custom_hook(Application_Links *app, Hook_ID hook_id, Void_Func *func_ptr){
|
||||||
{
|
{
|
||||||
models->buffer_region = (Buffer_Region_Function*)func_ptr;
|
models->buffer_region = (Buffer_Region_Function*)func_ptr;
|
||||||
}break;
|
}break;
|
||||||
|
case HookID_Layout:
|
||||||
|
{
|
||||||
|
models->layout_func = (Layout_Function*)func_ptr;
|
||||||
|
}break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2483,13 +2515,20 @@ get_face_metrics(Application_Links *app, Face_ID face_id){
|
||||||
if (face_id != 0){
|
if (face_id != 0){
|
||||||
Face *face = font_set_face_from_id(&models->font_set, face_id);
|
Face *face = font_set_face_from_id(&models->font_set, face_id);
|
||||||
if (face != 0){
|
if (face != 0){
|
||||||
result.text_height = face->text_height;
|
result = face->metrics;
|
||||||
result.line_height = face->line_height;
|
}
|
||||||
result.max_advance = face->max_advance;
|
}
|
||||||
result.normal_advance = face->typical_advance;
|
return(result);
|
||||||
result.space_advance = face->space_advance;
|
}
|
||||||
result.decimal_digit_advance = face->digit_advance;
|
|
||||||
result.hex_digit_advance = face->hex_advance;
|
api(custom) function Face_Advance_Map
|
||||||
|
get_face_advance_map(Application_Links *app, Face_ID face_id){
|
||||||
|
Models *models = (Models*)app->cmd_context;
|
||||||
|
Face_Advance_Map result = {};
|
||||||
|
if (face_id != 0){
|
||||||
|
Face *face = font_set_face_from_id(&models->font_set, face_id);
|
||||||
|
if (face != 0){
|
||||||
|
result = face->advance_map;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(result);
|
return(result);
|
||||||
|
@ -2717,6 +2756,8 @@ text_layout_create(Application_Links *app, Buffer_ID buffer_id, Rect_f32 rect, B
|
||||||
|
|
||||||
Gap_Buffer *buffer = &file->state.buffer;
|
Gap_Buffer *buffer = &file->state.buffer;
|
||||||
|
|
||||||
|
Layout_Function *layout_func = models->layout_func;
|
||||||
|
|
||||||
Vec2_f32 dim = rect_dim(rect);
|
Vec2_f32 dim = rect_dim(rect);
|
||||||
|
|
||||||
i64 line_count = buffer_line_count(buffer);
|
i64 line_count = buffer_line_count(buffer);
|
||||||
|
@ -2724,7 +2765,9 @@ text_layout_create(Application_Links *app, Buffer_ID buffer_id, Rect_f32 rect, B
|
||||||
f32 y = -buffer_point.pixel_shift.y;
|
f32 y = -buffer_point.pixel_shift.y;
|
||||||
for (;line_number <= line_count;
|
for (;line_number <= line_count;
|
||||||
line_number += 1){
|
line_number += 1){
|
||||||
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, dim.x, face, line_number);
|
Layout_Item_List line = file_get_line_layout(tctx, models, file,
|
||||||
|
layout_func, dim.x, face,
|
||||||
|
line_number);
|
||||||
f32 next_y = y + line.height;
|
f32 next_y = y + line.height;
|
||||||
if (next_y >= dim.y){
|
if (next_y >= dim.y){
|
||||||
break;
|
break;
|
||||||
|
@ -2743,7 +2786,8 @@ text_layout_create(Application_Links *app, Buffer_ID buffer_id, Rect_f32 rect, B
|
||||||
colors_array[i].id = Stag_Default;
|
colors_array[i].id = Stag_Default;
|
||||||
}
|
}
|
||||||
result = text_layout_new(&models->text_layouts, arena, buffer_id, buffer_point,
|
result = text_layout_new(&models->text_layouts, arena, buffer_id, buffer_point,
|
||||||
visible_range, visible_line_number_range, rect, colors_array);
|
visible_range, visible_line_number_range, rect, colors_array,
|
||||||
|
layout_func);
|
||||||
}
|
}
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
@ -2789,6 +2833,9 @@ text_layout_line_on_screen(Application_Links *app, Text_Layout_ID layout_id, i64
|
||||||
if (layout == 0){
|
if (layout == 0){
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Layout_Function *layout_func = layout->layout_func;
|
||||||
|
|
||||||
Rect_f32 rect = layout->rect;
|
Rect_f32 rect = layout->rect;
|
||||||
if (range_contains_inclusive(layout->visible_line_number_range, line_number)){
|
if (range_contains_inclusive(layout->visible_line_number_range, line_number)){
|
||||||
Editing_File *file = imp_get_file(models, layout->buffer_id);
|
Editing_File *file = imp_get_file(models, layout->buffer_id);
|
||||||
|
@ -2798,7 +2845,9 @@ text_layout_line_on_screen(Application_Links *app, Text_Layout_ID layout_id, i64
|
||||||
|
|
||||||
for (i64 line_number_it = layout->visible_line_number_range.first;;
|
for (i64 line_number_it = layout->visible_line_number_range.first;;
|
||||||
line_number_it += 1){
|
line_number_it += 1){
|
||||||
Buffer_Layout_Item_List line = file_get_line_layout(app->tctx, models, file, width, face, line_number_it);
|
Layout_Item_List line = file_get_line_layout(app->tctx, models, file,
|
||||||
|
layout_func, width, face,
|
||||||
|
line_number_it);
|
||||||
result.max += line.height;
|
result.max += line.height;
|
||||||
if (line_number_it == line_number){
|
if (line_number_it == line_number){
|
||||||
break;
|
break;
|
||||||
|
@ -2816,6 +2865,7 @@ text_layout_line_on_screen(Application_Links *app, Text_Layout_ID layout_id, i64
|
||||||
else if (line_number > layout->visible_line_number_range.max){
|
else if (line_number > layout->visible_line_number_range.max){
|
||||||
result = If32(rect.y1, rect.y1);
|
result = If32(rect.y1, rect.y1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2835,11 +2885,15 @@ text_layout_character_on_screen(Application_Links *app, Text_Layout_ID layout_id
|
||||||
f32 width = rect_width(rect);
|
f32 width = rect_width(rect);
|
||||||
Face *face = file_get_face(models, file);
|
Face *face = file_get_face(models, file);
|
||||||
|
|
||||||
|
Layout_Function *layout_func = layout->layout_func;
|
||||||
|
|
||||||
f32 y = 0.f;
|
f32 y = 0.f;
|
||||||
Buffer_Layout_Item_List line = {};
|
Layout_Item_List line = {};
|
||||||
for (i64 line_number_it = layout->visible_line_number_range.first;;
|
for (i64 line_number_it = layout->visible_line_number_range.first;;
|
||||||
line_number_it += 1){
|
line_number_it += 1){
|
||||||
line = file_get_line_layout(app->tctx, models, file, width, face, line_number_it);
|
line = file_get_line_layout(app->tctx, models, file,
|
||||||
|
layout_func, width, face,
|
||||||
|
line_number_it);
|
||||||
if (line_number_it == line_number){
|
if (line_number_it == line_number){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2851,10 +2905,10 @@ text_layout_character_on_screen(Application_Links *app, Text_Layout_ID layout_id
|
||||||
// Buffer_Layout_Item_List.
|
// Buffer_Layout_Item_List.
|
||||||
b32 is_first_item = true;
|
b32 is_first_item = true;
|
||||||
result = Rf32_negative_infinity;
|
result = Rf32_negative_infinity;
|
||||||
for (Buffer_Layout_Item_Block *block = line.first;
|
for (Layout_Item_Block *block = line.first;
|
||||||
block != 0;
|
block != 0;
|
||||||
block = block->next){
|
block = block->next){
|
||||||
Buffer_Layout_Item *item_ptr = block->items;
|
Layout_Item *item_ptr = block->items;
|
||||||
i64 count = block->count;
|
i64 count = block->count;
|
||||||
for (i32 i = 0; i < count; i += 1, item_ptr += 1){
|
for (i32 i = 0; i < count; i += 1, item_ptr += 1){
|
||||||
i64 index = item_ptr->index;
|
i64 index = item_ptr->index;
|
||||||
|
|
|
@ -62,6 +62,7 @@ struct Models{
|
||||||
Buffer_Hook_Function *save_file;
|
Buffer_Hook_Function *save_file;
|
||||||
Buffer_Edit_Range_Function *buffer_edit_range;
|
Buffer_Edit_Range_Function *buffer_edit_range;
|
||||||
Buffer_Region_Function *buffer_region;
|
Buffer_Region_Function *buffer_region;
|
||||||
|
Layout_Function *layout_func;
|
||||||
|
|
||||||
Color_Table fallback_color_table;
|
Color_Table fallback_color_table;
|
||||||
Color_Table color_table;
|
Color_Table color_table;
|
||||||
|
|
|
@ -74,6 +74,7 @@
|
||||||
#include "4coder_log.cpp"
|
#include "4coder_log.cpp"
|
||||||
#include "4coder_buffer_seek_constructors.cpp"
|
#include "4coder_buffer_seek_constructors.cpp"
|
||||||
#include "4coder_command_map.cpp"
|
#include "4coder_command_map.cpp"
|
||||||
|
#include "4coder_codepoint_map.cpp"
|
||||||
|
|
||||||
#include "generated/custom_api.cpp"
|
#include "generated/custom_api.cpp"
|
||||||
#define DYNAMIC_LINK_API
|
#define DYNAMIC_LINK_API
|
||||||
|
@ -87,7 +88,6 @@
|
||||||
#include "4ed_coroutine.cpp"
|
#include "4ed_coroutine.cpp"
|
||||||
#include "4ed_mem.cpp"
|
#include "4ed_mem.cpp"
|
||||||
#include "4ed_dynamic_variables.cpp"
|
#include "4ed_dynamic_variables.cpp"
|
||||||
#include "4ed_font_face.cpp"
|
|
||||||
#include "4ed_font_set.cpp"
|
#include "4ed_font_set.cpp"
|
||||||
#include "4ed_translation.cpp"
|
#include "4ed_translation.cpp"
|
||||||
#include "4ed_render_target.cpp"
|
#include "4ed_render_target.cpp"
|
||||||
|
|
232
4ed_buffer.cpp
232
4ed_buffer.cpp
|
@ -856,194 +856,8 @@ buffer_chunk_position_iterate(String_Const_u8_Array chunks, Buffer_Chunk_Positio
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
internal void
|
|
||||||
buffer_layout__write(Arena *arena, Buffer_Layout_Item_List *list, i64 index, u32 codepoint,
|
|
||||||
Buffer_Layout_Flag flags, Rect_f32 rect){
|
|
||||||
Temp_Memory restore_point = begin_temp(arena);
|
|
||||||
Buffer_Layout_Item *item = push_array(arena, Buffer_Layout_Item, 1);
|
|
||||||
|
|
||||||
Buffer_Layout_Item_Block *block = list->first;
|
|
||||||
if (block != 0){
|
|
||||||
if (block->items + block->count == item){
|
|
||||||
block->count += 1;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
block = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (block == 0){
|
|
||||||
end_temp(restore_point);
|
|
||||||
block = push_array(arena, Buffer_Layout_Item_Block, 1);
|
|
||||||
item = push_array(arena, Buffer_Layout_Item, 1);
|
|
||||||
sll_queue_push(list->first, list->last, block);
|
|
||||||
list->node_count += 1;
|
|
||||||
block->items = item;
|
|
||||||
block->count = 1;
|
|
||||||
}
|
|
||||||
list->total_count += 1;
|
|
||||||
|
|
||||||
if (index > list->index_range.max){
|
|
||||||
block->character_count += 1;
|
|
||||||
list->character_count += 1;
|
|
||||||
list->index_range.max = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
item->index = index;
|
|
||||||
item->codepoint = codepoint;
|
|
||||||
item->flags = flags;
|
|
||||||
item->rect = rect;
|
|
||||||
list->height = max(list->height, rect.y1);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Buffer_Layout_Item_List
|
|
||||||
buffer_layout(Thread_Context *tctx, Arena *arena, Gap_Buffer *buffer, Interval_i64 range, Face *face, f32 width){
|
|
||||||
Scratch_Block scratch(tctx);
|
|
||||||
|
|
||||||
Buffer_Layout_Item_List list = {};
|
|
||||||
list.index_range.first = range.first;
|
|
||||||
list.index_range.one_past_last = range.first - 1;
|
|
||||||
|
|
||||||
List_String_Const_u8 chunks = buffer_get_chunks(scratch, buffer);
|
|
||||||
buffer_chunks_clamp(&chunks, range);
|
|
||||||
|
|
||||||
f32 line_height = face->line_height;
|
|
||||||
f32 text_height = face->text_height;
|
|
||||||
f32 line_to_text_shift = text_height - line_height;
|
|
||||||
f32 space_advance = face->space_advance;
|
|
||||||
|
|
||||||
if (chunks.node_count == 0){
|
|
||||||
f32 next_x = space_advance;
|
|
||||||
buffer_layout__write(arena, &list, range.first, ' ', 0,
|
|
||||||
Rf32(V2(0.f, 0.f), V2f32(next_x, text_height)));
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
Vec2_f32 p = {};
|
|
||||||
f32 line_y = line_height;
|
|
||||||
f32 text_y = text_height;
|
|
||||||
|
|
||||||
String_Const_u8 text = {};
|
|
||||||
if (chunks.node_count == 1){
|
|
||||||
text = chunks.first->string;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
text = string_list_flatten(scratch, chunks);
|
|
||||||
}
|
|
||||||
|
|
||||||
i64 index = range.first;
|
|
||||||
b32 first_of_the_line = true;
|
|
||||||
|
|
||||||
b32 consuming_newline_characters = false;
|
|
||||||
i64 newline_character_index = -1;
|
|
||||||
|
|
||||||
b32 prev_did_emit_newline = false;
|
|
||||||
|
|
||||||
u8 *ptr = text.str;
|
|
||||||
u8 *end_ptr = ptr + text.size;
|
|
||||||
for (;ptr < end_ptr;){
|
|
||||||
Character_Consume_Result consume = utf8_consume(ptr, (umem)(end_ptr - ptr));
|
|
||||||
u32 render_codepoint = consume.codepoint;
|
|
||||||
b32 emit_newline = false;
|
|
||||||
switch (consume.codepoint){
|
|
||||||
case '\t':
|
|
||||||
{
|
|
||||||
render_codepoint = ' ';
|
|
||||||
}//fallthrough;
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
f32 advance = font_get_glyph_advance(face, consume.codepoint);
|
|
||||||
f32 next_x = p.x + advance;
|
|
||||||
if (!first_of_the_line && next_x >= width){
|
|
||||||
p.y = line_y;
|
|
||||||
p.x = 0.f;
|
|
||||||
line_y += line_height;
|
|
||||||
text_y = line_y + line_to_text_shift;
|
|
||||||
next_x = p.x + advance;
|
|
||||||
}
|
|
||||||
buffer_layout__write(arena, &list, index, render_codepoint, 0,
|
|
||||||
Rf32(p, V2f32(next_x, text_y)));
|
|
||||||
p.x = next_x;
|
|
||||||
ptr += consume.inc;
|
|
||||||
index += consume.inc;
|
|
||||||
first_of_the_line = false;
|
|
||||||
}break;
|
|
||||||
|
|
||||||
case '\r':
|
|
||||||
{
|
|
||||||
if (!consuming_newline_characters){
|
|
||||||
consuming_newline_characters = true;
|
|
||||||
newline_character_index = index;
|
|
||||||
}
|
|
||||||
ptr += 1;
|
|
||||||
index += 1;
|
|
||||||
}break;
|
|
||||||
|
|
||||||
case '\n':
|
|
||||||
{
|
|
||||||
if (!consuming_newline_characters){
|
|
||||||
consuming_newline_characters = true;
|
|
||||||
newline_character_index = index;
|
|
||||||
}
|
|
||||||
emit_newline = true;
|
|
||||||
ptr += 1;
|
|
||||||
index += 1;
|
|
||||||
}break;
|
|
||||||
|
|
||||||
case max_u32:
|
|
||||||
{
|
|
||||||
f32 next_x = p.x + face->byte_advance;
|
|
||||||
if (!first_of_the_line && next_x >= width){
|
|
||||||
p.y = line_y;
|
|
||||||
p.x = 0.f;
|
|
||||||
line_y += line_height;
|
|
||||||
text_y = line_y + line_to_text_shift;
|
|
||||||
next_x = p.x + face->byte_advance;
|
|
||||||
}
|
|
||||||
u32 v = *ptr;
|
|
||||||
u32 lo = v&0xF;
|
|
||||||
u32 hi = (v >> 4)&0xF;
|
|
||||||
f32 advance = face->byte_sub_advances[0];
|
|
||||||
buffer_layout__write(arena, &list, index, '\\', 0,
|
|
||||||
Rf32(p, V2f32(p.x + advance, text_y)));
|
|
||||||
p.x += advance;
|
|
||||||
advance = face->byte_sub_advances[1];
|
|
||||||
buffer_layout__write(arena, &list, index, integer_symbols[lo], 0,
|
|
||||||
Rf32(p, V2f32(p.x + advance, text_y)));
|
|
||||||
p.x += advance;
|
|
||||||
face->byte_sub_advances[2];
|
|
||||||
buffer_layout__write(arena, &list, index, integer_symbols[hi], 0,
|
|
||||||
Rf32(p, V2f32(p.x + advance, text_y)));
|
|
||||||
p.x = next_x;
|
|
||||||
ptr += 1;
|
|
||||||
index += 1;
|
|
||||||
first_of_the_line = false;
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
prev_did_emit_newline = false;
|
|
||||||
if (emit_newline){
|
|
||||||
f32 next_x = p.x + space_advance;
|
|
||||||
buffer_layout__write(arena, &list, newline_character_index, ' ', 0,
|
|
||||||
Rf32(p, V2f32(next_x, text_y)));
|
|
||||||
p.y = line_y;
|
|
||||||
p.x = 0.f;
|
|
||||||
line_y += line_height;
|
|
||||||
text_y = line_y + line_to_text_shift;
|
|
||||||
first_of_the_line = true;
|
|
||||||
prev_did_emit_newline = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!prev_did_emit_newline){
|
|
||||||
f32 next_x = p.x + space_advance;
|
|
||||||
buffer_layout__write(arena, &list, index, ' ', 0, Rf32(p, V2f32(next_x, text_y)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list.bottom_extension = -line_to_text_shift;
|
|
||||||
list.height += list.bottom_extension;
|
|
||||||
|
|
||||||
return(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal i64
|
internal i64
|
||||||
buffer_layout_nearest_pos_to_xy(Buffer_Layout_Item_List list, Vec2_f32 p){
|
buffer_layout_nearest_pos_to_xy(Layout_Item_List list, Vec2_f32 p){
|
||||||
i64 closest_match = 0;
|
i64 closest_match = 0;
|
||||||
if (p.y < 0.f){
|
if (p.y < 0.f){
|
||||||
closest_match = list.index_range.min;
|
closest_match = list.index_range.min;
|
||||||
|
@ -1055,11 +869,11 @@ buffer_layout_nearest_pos_to_xy(Buffer_Layout_Item_List list, Vec2_f32 p){
|
||||||
if (0.f < p.x && p.x < max_f32){
|
if (0.f < p.x && p.x < max_f32){
|
||||||
f32 bottom_extension = list.bottom_extension;
|
f32 bottom_extension = list.bottom_extension;
|
||||||
f32 closest_x = -max_f32;
|
f32 closest_x = -max_f32;
|
||||||
for (Buffer_Layout_Item_Block *block = list.first;
|
for (Layout_Item_Block *block = list.first;
|
||||||
block != 0;
|
block != 0;
|
||||||
block = block->next){
|
block = block->next){
|
||||||
i64 count = block->count;
|
i64 count = block->count;
|
||||||
Buffer_Layout_Item *item = block->items;
|
Layout_Item *item = block->items;
|
||||||
for (i32 i = 0; i < count; i += 1, item += 1){
|
for (i32 i = 0; i < count; i += 1, item += 1){
|
||||||
// NOTE(allen): This only works if we build layouts in y-sorted order.
|
// NOTE(allen): This only works if we build layouts in y-sorted order.
|
||||||
if (p.y < item->rect.y0){
|
if (p.y < item->rect.y0){
|
||||||
|
@ -1088,12 +902,12 @@ buffer_layout_nearest_pos_to_xy(Buffer_Layout_Item_List list, Vec2_f32 p){
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if (p.x == max_f32){
|
if (p.x == max_f32){
|
||||||
Buffer_Layout_Item *prev_item = 0;
|
Layout_Item *prev_item = 0;
|
||||||
for (Buffer_Layout_Item_Block *block = list.first;
|
for (Layout_Item_Block *block = list.first;
|
||||||
block != 0;
|
block != 0;
|
||||||
block = block->next){
|
block = block->next){
|
||||||
i64 count = block->count;
|
i64 count = block->count;
|
||||||
Buffer_Layout_Item *item = block->items;
|
Layout_Item *item = block->items;
|
||||||
for (i32 i = 0; i < count; i += 1, item += 1){
|
for (i32 i = 0; i < count; i += 1, item += 1){
|
||||||
if (p.y < item->rect.y0){
|
if (p.y < item->rect.y0){
|
||||||
goto double_break_2;
|
goto double_break_2;
|
||||||
|
@ -1113,12 +927,12 @@ buffer_layout_nearest_pos_to_xy(Buffer_Layout_Item_List list, Vec2_f32 p){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
Buffer_Layout_Item *closest_item = 0;
|
Layout_Item *closest_item = 0;
|
||||||
for (Buffer_Layout_Item_Block *block = list.first;
|
for (Layout_Item_Block *block = list.first;
|
||||||
block != 0;
|
block != 0;
|
||||||
block = block->next){
|
block = block->next){
|
||||||
i64 count = block->count;
|
i64 count = block->count;
|
||||||
Buffer_Layout_Item *item = block->items;
|
Layout_Item *item = block->items;
|
||||||
for (i32 i = 0; i < count; i += 1, item += 1){
|
for (i32 i = 0; i < count; i += 1, item += 1){
|
||||||
// NOTE(allen): This only works if we build layouts in y-sorted order.
|
// NOTE(allen): This only works if we build layouts in y-sorted order.
|
||||||
if (p.y < item->rect.y0){
|
if (p.y < item->rect.y0){
|
||||||
|
@ -1145,7 +959,7 @@ buffer_layout_nearest_pos_to_xy(Buffer_Layout_Item_List list, Vec2_f32 p){
|
||||||
}
|
}
|
||||||
|
|
||||||
internal i64
|
internal i64
|
||||||
buffer_layout_get_pos_at_character(Buffer_Layout_Item_List list, i64 character){
|
buffer_layout_get_pos_at_character(Layout_Item_List list, i64 character){
|
||||||
i64 result = 0;
|
i64 result = 0;
|
||||||
if (character <= 0){
|
if (character <= 0){
|
||||||
result = list.index_range.min;
|
result = list.index_range.min;
|
||||||
|
@ -1155,7 +969,7 @@ buffer_layout_get_pos_at_character(Buffer_Layout_Item_List list, i64 character){
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
i64 counter = 0;
|
i64 counter = 0;
|
||||||
for (Buffer_Layout_Item_Block *node = list.first;
|
for (Layout_Item_Block *node = list.first;
|
||||||
node != 0;
|
node != 0;
|
||||||
node = node->next){
|
node = node->next){
|
||||||
i64 next_counter = counter + node->character_count;
|
i64 next_counter = counter + node->character_count;
|
||||||
|
@ -1164,7 +978,7 @@ buffer_layout_get_pos_at_character(Buffer_Layout_Item_List list, i64 character){
|
||||||
i64 relative_character = character - counter;
|
i64 relative_character = character - counter;
|
||||||
i64 relative_character_counter = 0;
|
i64 relative_character_counter = 0;
|
||||||
i64 prev_index = -1;
|
i64 prev_index = -1;
|
||||||
Buffer_Layout_Item *item = node->items;
|
Layout_Item *item = node->items;
|
||||||
for (i64 i = 0; i < count; i += 1, item += 1){
|
for (i64 i = 0; i < count; i += 1, item += 1){
|
||||||
if (prev_index != item->index){
|
if (prev_index != item->index){
|
||||||
prev_index = item->index;
|
prev_index = item->index;
|
||||||
|
@ -1183,15 +997,15 @@ buffer_layout_get_pos_at_character(Buffer_Layout_Item_List list, i64 character){
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Buffer_Layout_Item*
|
internal Layout_Item*
|
||||||
buffer_layout_get_first_with_index(Buffer_Layout_Item_List list, i64 index){
|
buffer_layout_get_first_with_index(Layout_Item_List list, i64 index){
|
||||||
Buffer_Layout_Item *result = 0;
|
Layout_Item *result = 0;
|
||||||
Buffer_Layout_Item *prev = 0;
|
Layout_Item *prev = 0;
|
||||||
for (Buffer_Layout_Item_Block *block = list.first;
|
for (Layout_Item_Block *block = list.first;
|
||||||
block != 0;
|
block != 0;
|
||||||
block = block->next){
|
block = block->next){
|
||||||
i64 count = block->count;
|
i64 count = block->count;
|
||||||
Buffer_Layout_Item *item = block->items;
|
Layout_Item *item = block->items;
|
||||||
for (i32 i = 0; i < count; i += 1, item += 1){
|
for (i32 i = 0; i < count; i += 1, item += 1){
|
||||||
if (item->index > index){
|
if (item->index > index){
|
||||||
result = prev;
|
result = prev;
|
||||||
|
@ -1212,9 +1026,9 @@ buffer_layout_get_first_with_index(Buffer_Layout_Item_List list, i64 index){
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Vec2_f32
|
internal Vec2_f32
|
||||||
buffer_layout_xy_center_of_pos(Buffer_Layout_Item_List list, i64 index){
|
buffer_layout_xy_center_of_pos(Layout_Item_List list, i64 index){
|
||||||
Vec2_f32 result = {};
|
Vec2_f32 result = {};
|
||||||
Buffer_Layout_Item *item = buffer_layout_get_first_with_index(list, index);
|
Layout_Item *item = buffer_layout_get_first_with_index(list, index);
|
||||||
if (item != 0){
|
if (item != 0){
|
||||||
result = rect_center(item->rect);
|
result = rect_center(item->rect);
|
||||||
}
|
}
|
||||||
|
@ -1222,7 +1036,7 @@ buffer_layout_xy_center_of_pos(Buffer_Layout_Item_List list, i64 index){
|
||||||
}
|
}
|
||||||
|
|
||||||
internal i64
|
internal i64
|
||||||
buffer_layout_character_from_pos(Buffer_Layout_Item_List list, i64 index){
|
buffer_layout_character_from_pos(Layout_Item_List list, i64 index){
|
||||||
i64 result = 0;
|
i64 result = 0;
|
||||||
i64 character_count = 0;
|
i64 character_count = 0;
|
||||||
i64 prev_index = -1;
|
i64 prev_index = -1;
|
||||||
|
@ -1233,10 +1047,10 @@ buffer_layout_character_from_pos(Buffer_Layout_Item_List list, i64 index){
|
||||||
result = list.character_count - 1;
|
result = list.character_count - 1;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
for (Buffer_Layout_Item_Block *node = list.first;
|
for (Layout_Item_Block *node = list.first;
|
||||||
node != 0;
|
node != 0;
|
||||||
node = node->next){
|
node = node->next){
|
||||||
Buffer_Layout_Item *item = node->items;
|
Layout_Item *item = node->items;
|
||||||
i64 count = node->count;
|
i64 count = node->count;
|
||||||
for (i64 i = 0; i < count; i += 1, item += 1){
|
for (i64 i = 0; i < count; i += 1, item += 1){
|
||||||
if (item->index == index){
|
if (item->index == index){
|
||||||
|
|
38
4ed_buffer.h
38
4ed_buffer.h
|
@ -63,44 +63,6 @@ struct Line_Move{
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef u32 Buffer_Layout_Flag;
|
|
||||||
enum{
|
|
||||||
BRFlag_Special_Character = (1 << 0),
|
|
||||||
BRFlag_Ghost_Character = (1 << 1)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Buffer_Layout_Item{
|
|
||||||
i64 index;
|
|
||||||
u32 codepoint;
|
|
||||||
Buffer_Layout_Flag flags;
|
|
||||||
Rect_f32 rect;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Buffer_Layout_Item_Block{
|
|
||||||
Buffer_Layout_Item_Block *next;
|
|
||||||
Buffer_Layout_Item *items;
|
|
||||||
i64 count;
|
|
||||||
i64 character_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Buffer_Layout_Item_List{
|
|
||||||
Buffer_Layout_Item_Block *first;
|
|
||||||
Buffer_Layout_Item_Block *last;
|
|
||||||
i32 node_count;
|
|
||||||
i32 total_count;
|
|
||||||
f32 height;
|
|
||||||
f32 bottom_extension;
|
|
||||||
i64 character_count;
|
|
||||||
Interval_i64 index_range;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
struct Edit_Array{
|
|
||||||
Edit *vals;
|
|
||||||
i32 count;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// BOTTOM
|
// BOTTOM
|
||||||
|
|
120
4ed_file.cpp
120
4ed_file.cpp
|
@ -292,9 +292,10 @@ file_get_managed_scope(Editing_File *file){
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
internal Buffer_Layout_Item_List
|
internal Layout_Item_List
|
||||||
file_get_line_layout(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, i64 line_number){
|
file_get_line_layout(Thread_Context *tctx, Models *models, Editing_File *file,
|
||||||
Buffer_Layout_Item_List result = {};
|
Layout_Function *layout_func, f32 width, Face *face, i64 line_number){
|
||||||
|
Layout_Item_List result = {};
|
||||||
|
|
||||||
i64 line_count = buffer_line_count(&file->state.buffer);
|
i64 line_count = buffer_line_count(&file->state.buffer);
|
||||||
if (1 <= line_number && line_number <= line_count){
|
if (1 <= line_number && line_number <= line_count){
|
||||||
|
@ -306,19 +307,23 @@ file_get_line_layout(Thread_Context *tctx, Models *models, Editing_File *file, f
|
||||||
|
|
||||||
Data key_data = make_data_struct(&key);
|
Data key_data = make_data_struct(&key);
|
||||||
|
|
||||||
Buffer_Layout_Item_List *list = 0;
|
Layout_Item_List *list = 0;
|
||||||
|
|
||||||
Table_Lookup lookup = table_lookup(&file->state.line_layout_table, key_data);
|
Table_Lookup lookup = table_lookup(&file->state.line_layout_table, key_data);
|
||||||
if (lookup.found_match){
|
if (lookup.found_match){
|
||||||
u64 val = 0;
|
u64 val = 0;
|
||||||
table_read(&file->state.line_layout_table, lookup, &val);
|
table_read(&file->state.line_layout_table, lookup, &val);
|
||||||
list = (Buffer_Layout_Item_List*)IntAsPtr(val);
|
list = (Layout_Item_List*)IntAsPtr(val);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
list = push_array(&file->state.cached_layouts_arena, Buffer_Layout_Item_List, 1);
|
list = push_array(&file->state.cached_layouts_arena, Layout_Item_List, 1);
|
||||||
Interval_i64 line_range = buffer_get_pos_range_from_line_number(&file->state.buffer, line_number);
|
Range_i64 line_range = buffer_get_pos_range_from_line_number(&file->state.buffer, line_number);
|
||||||
*list = buffer_layout(tctx, &file->state.cached_layouts_arena,
|
|
||||||
&file->state.buffer, line_range, face, width);
|
Application_Links app = {};
|
||||||
|
app.tctx = tctx;
|
||||||
|
app.cmd_context = models;
|
||||||
|
*list = layout_func(&app, &file->state.cached_layouts_arena,
|
||||||
|
file->id, line_range, face->id, width);
|
||||||
key_data = push_data_copy(&file->state.cached_layouts_arena, key_data);
|
key_data = push_data_copy(&file->state.cached_layouts_arena, key_data);
|
||||||
table_insert(&file->state.line_layout_table, key_data, (u64)PtrAsInt(list));
|
table_insert(&file->state.line_layout_table, key_data, (u64)PtrAsInt(list));
|
||||||
}
|
}
|
||||||
|
@ -335,7 +340,9 @@ file_clear_layout_cache(Editing_File *file){
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Line_Shift_Vertical
|
internal Line_Shift_Vertical
|
||||||
file_line_shift_y(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, i64 line_number, f32 y_delta){
|
file_line_shift_y(Thread_Context *tctx, Models *models, Editing_File *file,
|
||||||
|
Layout_Function *layout_func, f32 width, Face *face,
|
||||||
|
i64 line_number, f32 y_delta){
|
||||||
Line_Shift_Vertical result = {};
|
Line_Shift_Vertical result = {};
|
||||||
|
|
||||||
f32 line_y = 0.f;
|
f32 line_y = 0.f;
|
||||||
|
@ -355,7 +362,8 @@ file_line_shift_y(Thread_Context *tctx, Models *models, Editing_File *file, f32
|
||||||
line_number = 1;
|
line_number = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, line_number);
|
Layout_Item_List line = file_get_line_layout(tctx, models, file, layout_func,
|
||||||
|
width, face, line_number);
|
||||||
line_y -= line.height;
|
line_y -= line.height;
|
||||||
}
|
}
|
||||||
if (!has_result){
|
if (!has_result){
|
||||||
|
@ -368,7 +376,8 @@ file_line_shift_y(Thread_Context *tctx, Models *models, Editing_File *file, f32
|
||||||
b32 has_result = false;
|
b32 has_result = false;
|
||||||
i64 line_count = buffer_line_count(&file->state.buffer);
|
i64 line_count = buffer_line_count(&file->state.buffer);
|
||||||
for (;;line_number += 1){
|
for (;;line_number += 1){
|
||||||
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, line_number);
|
Layout_Item_List line = file_get_line_layout(tctx, models, file, layout_func,
|
||||||
|
width, face, line_number);
|
||||||
f32 next_y = line_y + line.height;
|
f32 next_y = line_y + line.height;
|
||||||
if (y_delta < next_y){
|
if (y_delta < next_y){
|
||||||
has_result = true;
|
has_result = true;
|
||||||
|
@ -391,12 +400,15 @@ file_line_shift_y(Thread_Context *tctx, Models *models, Editing_File *file, f32
|
||||||
}
|
}
|
||||||
|
|
||||||
internal f32
|
internal f32
|
||||||
file_line_y_difference(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, i64 line_a, i64 line_b){
|
file_line_y_difference(Thread_Context *tctx, Models *models, Editing_File *file,
|
||||||
|
Layout_Function *layout_func, f32 width, Face *face,
|
||||||
|
i64 line_a, i64 line_b){
|
||||||
f32 result = 0.f;
|
f32 result = 0.f;
|
||||||
if (line_a != line_b){
|
if (line_a != line_b){
|
||||||
Interval_i64 line_range = Ii64(line_a, line_b);
|
Interval_i64 line_range = Ii64(line_a, line_b);
|
||||||
for (i64 i = line_range.min; i < line_range.max; i += 1){
|
for (i64 i = line_range.min; i < line_range.max; i += 1){
|
||||||
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, i);
|
Layout_Item_List line = file_get_line_layout(tctx, models, file, layout_func,
|
||||||
|
width, face, i);
|
||||||
result += line.height;
|
result += line.height;
|
||||||
}
|
}
|
||||||
if (line_a < line_b){
|
if (line_a < line_b){
|
||||||
|
@ -407,25 +419,40 @@ file_line_y_difference(Thread_Context *tctx, Models *models, Editing_File *file,
|
||||||
}
|
}
|
||||||
|
|
||||||
internal i64
|
internal i64
|
||||||
file_pos_at_relative_xy(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, i64 base_line, Vec2_f32 relative_xy){
|
file_pos_at_relative_xy(Thread_Context *tctx, Models *models, Editing_File *file,
|
||||||
Line_Shift_Vertical shift = file_line_shift_y(tctx, models, file, width, face, base_line, relative_xy.y);
|
Layout_Function *layout_func, f32 width, Face *face,
|
||||||
|
i64 base_line, Vec2_f32 relative_xy){
|
||||||
|
Line_Shift_Vertical shift = file_line_shift_y(tctx, models, file,
|
||||||
|
layout_func, width, face, base_line,
|
||||||
|
relative_xy.y);
|
||||||
relative_xy.y -= shift.y_delta;
|
relative_xy.y -= shift.y_delta;
|
||||||
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, shift.line);
|
Layout_Item_List line = file_get_line_layout(tctx, models, file,
|
||||||
|
layout_func, width, face,
|
||||||
|
shift.line);
|
||||||
return(buffer_layout_nearest_pos_to_xy(line, relative_xy));
|
return(buffer_layout_nearest_pos_to_xy(line, relative_xy));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Vec2_f32
|
internal Vec2_f32
|
||||||
file_relative_xy_of_pos(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, i64 base_line, i64 pos){
|
file_relative_xy_of_pos(Thread_Context *tctx, Models *models, Editing_File *file,
|
||||||
|
Layout_Function *layout_func, f32 width, Face *face,
|
||||||
|
i64 base_line, i64 pos){
|
||||||
i64 line_number = buffer_get_line_index(&file->state.buffer, pos) + 1;
|
i64 line_number = buffer_get_line_index(&file->state.buffer, pos) + 1;
|
||||||
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, line_number);
|
Layout_Item_List line = file_get_line_layout(tctx, models, file,
|
||||||
|
layout_func, width, face,
|
||||||
|
line_number);
|
||||||
Vec2_f32 result = buffer_layout_xy_center_of_pos(line, pos);
|
Vec2_f32 result = buffer_layout_xy_center_of_pos(line, pos);
|
||||||
result.y += file_line_y_difference(tctx, models, file, width, face, line_number, base_line);
|
result.y += file_line_y_difference(tctx, models, file,
|
||||||
|
layout_func, width, face, line_number, base_line);
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Buffer_Point
|
internal Buffer_Point
|
||||||
file_normalize_buffer_point(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, Buffer_Point point){
|
file_normalize_buffer_point(Thread_Context *tctx, Models *models, Editing_File *file,
|
||||||
Line_Shift_Vertical shift = file_line_shift_y(tctx, models, file, width, face, point.line_number, point.pixel_shift.y);
|
Layout_Function *layout_func, f32 width, Face *face,
|
||||||
|
Buffer_Point point){
|
||||||
|
Line_Shift_Vertical shift = file_line_shift_y(tctx, models, file,
|
||||||
|
layout_func, width, face, point.line_number,
|
||||||
|
point.pixel_shift.y);
|
||||||
point.line_number = shift.line;
|
point.line_number = shift.line;
|
||||||
point.pixel_shift.y -= shift.y_delta;
|
point.pixel_shift.y -= shift.y_delta;
|
||||||
point.pixel_shift.x = clamp_bot(0.f, point.pixel_shift.x);
|
point.pixel_shift.x = clamp_bot(0.f, point.pixel_shift.x);
|
||||||
|
@ -434,15 +461,21 @@ file_normalize_buffer_point(Thread_Context *tctx, Models *models, Editing_File *
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Vec2_f32
|
internal Vec2_f32
|
||||||
file_buffer_point_difference(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, Buffer_Point a, Buffer_Point b){
|
file_buffer_point_difference(Thread_Context *tctx, Models *models, Editing_File *file,
|
||||||
f32 y_difference = file_line_y_difference(tctx, models, file, width, face, a.line_number, b.line_number);
|
Layout_Function *layout_func, f32 width, Face *face,
|
||||||
|
Buffer_Point a, Buffer_Point b){
|
||||||
|
f32 y_difference = file_line_y_difference(tctx, models, file,
|
||||||
|
layout_func, width, face,
|
||||||
|
a.line_number, b.line_number);
|
||||||
Vec2_f32 result = a.pixel_shift - b.pixel_shift;
|
Vec2_f32 result = a.pixel_shift - b.pixel_shift;
|
||||||
result.y += y_difference;
|
result.y += y_difference;
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Line_Shift_Character
|
internal Line_Shift_Character
|
||||||
file_line_shift_characters(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, i64 line_number, i64 character_delta){
|
file_line_shift_characters(Thread_Context *tctx, Models *models, Editing_File *file,
|
||||||
|
Layout_Function *layout_func, f32 width, Face *face,
|
||||||
|
i64 line_number, i64 character_delta){
|
||||||
Line_Shift_Character result = {};
|
Line_Shift_Character result = {};
|
||||||
|
|
||||||
i64 line_character = 0;
|
i64 line_character = 0;
|
||||||
|
@ -462,7 +495,9 @@ file_line_shift_characters(Thread_Context *tctx, Models *models, Editing_File *f
|
||||||
line_number = 1;
|
line_number = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, line_number);
|
Layout_Item_List line = file_get_line_layout(tctx, models, file,
|
||||||
|
layout_func, width, face,
|
||||||
|
line_number);
|
||||||
line_character -= line.character_count;
|
line_character -= line.character_count;
|
||||||
}
|
}
|
||||||
if (!has_result){
|
if (!has_result){
|
||||||
|
@ -475,7 +510,9 @@ file_line_shift_characters(Thread_Context *tctx, Models *models, Editing_File *f
|
||||||
b32 has_result = false;
|
b32 has_result = false;
|
||||||
i64 line_count = buffer_line_count(&file->state.buffer);
|
i64 line_count = buffer_line_count(&file->state.buffer);
|
||||||
for (;;line_number += 1){
|
for (;;line_number += 1){
|
||||||
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, line_number);
|
Layout_Item_List line = file_get_line_layout(tctx, models, file,
|
||||||
|
layout_func, width, face,
|
||||||
|
line_number);
|
||||||
i64 next_character = line_character + line.character_count;
|
i64 next_character = line_character + line.character_count;
|
||||||
if (character_delta < next_character){
|
if (character_delta < next_character){
|
||||||
has_result = true;
|
has_result = true;
|
||||||
|
@ -498,12 +535,15 @@ file_line_shift_characters(Thread_Context *tctx, Models *models, Editing_File *f
|
||||||
}
|
}
|
||||||
|
|
||||||
internal i64
|
internal i64
|
||||||
file_line_character_difference(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, i64 line_a, i64 line_b){
|
file_line_character_difference(Thread_Context *tctx, Models *models, Editing_File *file,
|
||||||
|
Layout_Function *layout_func, f32 width, Face *face,
|
||||||
|
i64 line_a, i64 line_b){
|
||||||
i64 result = 0;
|
i64 result = 0;
|
||||||
if (line_a != line_b){
|
if (line_a != line_b){
|
||||||
Interval_i64 line_range = Ii64(line_a, line_b);
|
Interval_i64 line_range = Ii64(line_a, line_b);
|
||||||
for (i64 i = line_range.min; i < line_range.max; i += 1){
|
for (i64 i = line_range.min; i < line_range.max; i += 1){
|
||||||
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, i);
|
Layout_Item_List line = file_get_line_layout(tctx, models, file,
|
||||||
|
layout_func, width, face, i);
|
||||||
result += line.character_count;
|
result += line.character_count;
|
||||||
}
|
}
|
||||||
if (line_a < line_b){
|
if (line_a < line_b){
|
||||||
|
@ -514,19 +554,29 @@ file_line_character_difference(Thread_Context *tctx, Models *models, Editing_Fil
|
||||||
}
|
}
|
||||||
|
|
||||||
internal i64
|
internal i64
|
||||||
file_pos_from_relative_character(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, i64 base_line, i64 relative_character){
|
file_pos_from_relative_character(Thread_Context *tctx, Models *models, Editing_File *file,
|
||||||
Line_Shift_Character shift = file_line_shift_characters(tctx, models, file, width, face, base_line, relative_character);
|
Layout_Function *layout_func, f32 width, Face *face,
|
||||||
|
i64 base_line, i64 relative_character){
|
||||||
|
Line_Shift_Character shift = file_line_shift_characters(tctx, models, file,
|
||||||
|
layout_func, width, face,
|
||||||
|
base_line, relative_character);
|
||||||
relative_character -= shift.character_delta;
|
relative_character -= shift.character_delta;
|
||||||
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, shift.line);
|
Layout_Item_List line = file_get_line_layout(tctx, models, file,
|
||||||
|
layout_func, width, face,
|
||||||
|
shift.line);
|
||||||
return(buffer_layout_get_pos_at_character(line, relative_character));
|
return(buffer_layout_get_pos_at_character(line, relative_character));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal i64
|
internal i64
|
||||||
file_relative_character_from_pos(Thread_Context *tctx, Models *models, Editing_File *file, f32 width, Face *face, i64 base_line, i64 pos){
|
file_relative_character_from_pos(Thread_Context *tctx, Models *models, Editing_File *file, Layout_Function *layout_func, f32 width, Face *face,
|
||||||
|
i64 base_line, i64 pos){
|
||||||
i64 line_number = buffer_get_line_index(&file->state.buffer, pos) + 1;
|
i64 line_number = buffer_get_line_index(&file->state.buffer, pos) + 1;
|
||||||
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, line_number);
|
Layout_Item_List line = file_get_line_layout(tctx, models, file,
|
||||||
|
layout_func, width, face,
|
||||||
|
line_number);
|
||||||
i64 result = buffer_layout_character_from_pos(line, pos);
|
i64 result = buffer_layout_character_from_pos(line, pos);
|
||||||
result += file_line_character_difference(tctx, models, file, width, face, line_number, base_line);
|
result += file_line_character_difference(tctx, models, file,
|
||||||
|
layout_func, width, face, line_number, base_line);
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,43 +30,17 @@ struct Glyph_Bounds{
|
||||||
Rect_f32 xy_off;
|
Rect_f32 xy_off;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Codepoint_Index_Map{
|
|
||||||
b32 has_zero_index;
|
|
||||||
u16 zero_index;
|
|
||||||
u16 max_index;
|
|
||||||
Table_u32_u16 table;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Face{
|
struct Face{
|
||||||
Face_Description description;
|
Face_Description description;
|
||||||
Face_ID id;
|
Face_ID id;
|
||||||
i32 version_number;
|
i32 version_number;
|
||||||
|
|
||||||
// NOTE(allen): Metrics
|
// NOTE(allen): Metrics
|
||||||
f32 text_height;
|
Face_Metrics metrics;
|
||||||
f32 line_height;
|
|
||||||
f32 ascent;
|
|
||||||
f32 descent;
|
|
||||||
f32 line_skip;
|
|
||||||
f32 max_advance;
|
|
||||||
|
|
||||||
f32 underline_yoff1;
|
|
||||||
f32 underline_yoff2;
|
|
||||||
|
|
||||||
f32 space_advance;
|
|
||||||
f32 digit_advance;
|
|
||||||
f32 hex_advance;
|
|
||||||
f32 byte_advance;
|
|
||||||
f32 byte_sub_advances[3];
|
|
||||||
f32 typical_lowercase_advance;
|
|
||||||
f32 typical_uppercase_advance;
|
|
||||||
f32 typical_advance;
|
|
||||||
|
|
||||||
// NOTE(allen): Glyph data
|
// NOTE(allen): Glyph data
|
||||||
Codepoint_Index_Map codepoint_to_index_map;
|
Face_Advance_Map advance_map;
|
||||||
u16 index_count;
|
|
||||||
Glyph_Bounds *bounds;
|
Glyph_Bounds *bounds;
|
||||||
f32 *advance;
|
|
||||||
Glyph_Bounds white;
|
Glyph_Bounds white;
|
||||||
|
|
||||||
Texture_Kind texture_kind;
|
Texture_Kind texture_kind;
|
||||||
|
|
|
@ -194,31 +194,35 @@ ft__font_make_face(Arena *arena, Face_Description *description, f32 scale_factor
|
||||||
face->description = *description;
|
face->description = *description;
|
||||||
face->description.font.file_name = file_name;
|
face->description.font.file_name = file_name;
|
||||||
|
|
||||||
face->max_advance = f32_ceil32(ft_face->size->metrics.max_advance/64.f);
|
Face_Metrics *met = &face->metrics;
|
||||||
face->ascent = f32_ceil32(ft_face->size->metrics.ascender/64.f);
|
|
||||||
face->descent = f32_floor32(ft_face->size->metrics.descender/64.f);
|
met->max_advance = f32_ceil32(ft_face->size->metrics.max_advance/64.f);
|
||||||
face->text_height = f32_ceil32(ft_face->size->metrics.height/64.f);
|
met->ascent = f32_ceil32(ft_face->size->metrics.ascender/64.f);
|
||||||
face->line_skip = face->text_height - face->ascent + face->descent;
|
met->descent = f32_floor32(ft_face->size->metrics.descender/64.f);
|
||||||
face->line_skip = clamp_bot(1.f, face->line_skip);
|
met->text_height = f32_ceil32(ft_face->size->metrics.height/64.f);
|
||||||
face->line_height = face->text_height + face->line_skip;
|
met->line_skip = met->text_height - met->ascent + met->descent;
|
||||||
|
met->line_skip = clamp_bot(1.f, met->line_skip);
|
||||||
|
met->line_height = met->text_height + met->line_skip;
|
||||||
|
|
||||||
{
|
{
|
||||||
f32 real_over_notional = face->line_height/(f32)ft_face->height;
|
f32 real_over_notional = met->line_height/(f32)ft_face->height;
|
||||||
f32 relative_center = -1.f*real_over_notional*ft_face->underline_position;
|
f32 relative_center = -1.f*real_over_notional*ft_face->underline_position;
|
||||||
f32 relative_thickness = real_over_notional*ft_face->underline_thickness;
|
f32 relative_thickness = real_over_notional*ft_face->underline_thickness;
|
||||||
|
|
||||||
f32 center = f32_floor32(face->ascent + relative_center);
|
f32 center = f32_floor32(met->ascent + relative_center);
|
||||||
f32 thickness = clamp_bot(1.f, relative_thickness);
|
f32 thickness = clamp_bot(1.f, relative_thickness);
|
||||||
|
|
||||||
face->underline_yoff1 = center - thickness*0.5f;
|
met->underline_yoff1 = center - thickness*0.5f;
|
||||||
face->underline_yoff2 = center + thickness*0.5f;
|
met->underline_yoff2 = center + thickness*0.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
face->codepoint_to_index_map = ft__get_codepoint_index_map(arena->base_allocator, ft_face);
|
face->advance_map.codepoint_to_index =
|
||||||
u16 index_count = codepoint_index_map_count(&face->codepoint_to_index_map);
|
ft__get_codepoint_index_map(arena->base_allocator, ft_face);
|
||||||
face->index_count = index_count;
|
u16 index_count =
|
||||||
|
codepoint_index_map_count(&face->advance_map.codepoint_to_index);
|
||||||
|
face->advance_map.index_count = index_count;
|
||||||
|
face->advance_map.advance = push_array_zero(arena, f32, index_count);
|
||||||
face->bounds = push_array(arena, Glyph_Bounds, index_count);
|
face->bounds = push_array(arena, Glyph_Bounds, index_count);
|
||||||
face->advance = push_array_zero(arena, f32, index_count);
|
|
||||||
|
|
||||||
struct FT_Bitmap{
|
struct FT_Bitmap{
|
||||||
Vec2_i32 dim;
|
Vec2_i32 dim;
|
||||||
|
@ -238,7 +242,7 @@ ft__font_make_face(Arena *arena, Face_Description *description, f32 scale_factor
|
||||||
bitmap->data = push_array(arena, u8, dim.x*dim.y);
|
bitmap->data = push_array(arena, u8, dim.x*dim.y);
|
||||||
|
|
||||||
face->bounds[i].xy_off.x0 = (f32)(ft_face->glyph->bitmap_left);
|
face->bounds[i].xy_off.x0 = (f32)(ft_face->glyph->bitmap_left);
|
||||||
face->bounds[i].xy_off.y0 = (f32)(face->ascent - ft_face->glyph->bitmap_top);
|
face->bounds[i].xy_off.y0 = (f32)(met->ascent - ft_face->glyph->bitmap_top);
|
||||||
face->bounds[i].xy_off.x1 = (f32)(face->bounds[i].xy_off.x0 + dim.x);
|
face->bounds[i].xy_off.x1 = (f32)(face->bounds[i].xy_off.x0 + dim.x);
|
||||||
face->bounds[i].xy_off.y1 = (f32)(face->bounds[i].xy_off.y0 + dim.y);
|
face->bounds[i].xy_off.y1 = (f32)(face->bounds[i].xy_off.y0 + dim.y);
|
||||||
|
|
||||||
|
@ -272,7 +276,7 @@ ft__font_make_face(Arena *arena, Face_Description *description, f32 scale_factor
|
||||||
}break;
|
}break;
|
||||||
}
|
}
|
||||||
|
|
||||||
face->advance[i] = f32_ceil32(ft_glyph->advance.x/64.0f);
|
face->advance_map.advance[i] = f32_ceil32(ft_glyph->advance.x/64.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,22 +331,30 @@ ft__font_make_face(Arena *arena, Face_Description *description, f32 scale_factor
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
face->space_advance = font_get_glyph_advance(face, ' ');
|
Face_Advance_Map *advance_map = &face->advance_map;
|
||||||
face->digit_advance = font_get_max_glyph_advance_range(face, '0', '9');
|
|
||||||
face->hex_advance = font_get_max_glyph_advance_range(face, 'A', 'F');
|
met->space_advance = font_get_glyph_advance(advance_map, met, ' ');
|
||||||
face->hex_advance = Max(face->hex_advance, face->digit_advance);
|
met->decimal_digit_advance =
|
||||||
face->byte_sub_advances[0] = font_get_glyph_advance(face, '\\');
|
font_get_max_glyph_advance_range(advance_map, met, '0', '9');
|
||||||
face->byte_sub_advances[1] = face->hex_advance;
|
met->hex_digit_advance =
|
||||||
face->byte_sub_advances[2] = face->hex_advance;
|
font_get_max_glyph_advance_range(advance_map, met, 'A', 'F');
|
||||||
face->byte_advance =
|
met->hex_digit_advance =
|
||||||
face->byte_sub_advances[0] +
|
max(met->hex_digit_advance, met->decimal_digit_advance);
|
||||||
face->byte_sub_advances[1] +
|
met->byte_sub_advances[0] =
|
||||||
face->byte_sub_advances[2];
|
font_get_glyph_advance(advance_map, met, '\\');
|
||||||
face->typical_lowercase_advance = font_get_average_glyph_advance_range(face, 'a', 'z');
|
met->byte_sub_advances[1] = met->hex_digit_advance;
|
||||||
face->typical_uppercase_advance = font_get_average_glyph_advance_range(face, 'A', 'Z');
|
met->byte_sub_advances[2] = met->hex_digit_advance;
|
||||||
face->typical_advance = (26*face->typical_lowercase_advance +
|
met->byte_advance =
|
||||||
26*face->typical_uppercase_advance +
|
met->byte_sub_advances[0] +
|
||||||
10*face->digit_advance)/62.f;
|
met->byte_sub_advances[1] +
|
||||||
|
met->byte_sub_advances[2];
|
||||||
|
met->normal_lowercase_advance =
|
||||||
|
font_get_average_glyph_advance_range(advance_map, met, 'a', 'z');
|
||||||
|
met->normal_uppercase_advance =
|
||||||
|
font_get_average_glyph_advance_range(advance_map, met, 'A', 'Z');
|
||||||
|
met->normal_advance = (26*met->normal_lowercase_advance +
|
||||||
|
26*met->normal_uppercase_advance +
|
||||||
|
10*met->decimal_digit_advance)/62.f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -167,8 +167,8 @@ draw_font_glyph(Render_Target *target, Face *face, u32 codepoint, Vec2_f32 p,
|
||||||
draw__set_face_id(target, face->id);
|
draw__set_face_id(target, face->id);
|
||||||
|
|
||||||
u16 glyph_index = 0;
|
u16 glyph_index = 0;
|
||||||
if (!codepoint_index_map_read(&face->codepoint_to_index_map, codepoint,
|
if (!codepoint_index_map_read(&face->advance_map.codepoint_to_index,
|
||||||
&glyph_index)){
|
codepoint, &glyph_index)){
|
||||||
glyph_index = 0;
|
glyph_index = 0;
|
||||||
}
|
}
|
||||||
Glyph_Bounds bounds = face->bounds[glyph_index];
|
Glyph_Bounds bounds = face->bounds[glyph_index];
|
||||||
|
@ -230,8 +230,8 @@ draw_string(Render_Target *target, Face *face, String_Const_u8 string, Vec2_f32
|
||||||
if (face != 0){
|
if (face != 0){
|
||||||
point = floor32(point);
|
point = floor32(point);
|
||||||
|
|
||||||
f32 byte_advance = face->byte_advance;
|
f32 byte_advance = face->metrics.byte_advance;
|
||||||
f32 *byte_sub_advances = face->byte_sub_advances;
|
f32 *byte_sub_advances = face->metrics.byte_sub_advances;
|
||||||
|
|
||||||
u8 *str = (u8*)string.str;
|
u8 *str = (u8*)string.str;
|
||||||
u8 *str_end = str + string.size;
|
u8 *str_end = str + string.size;
|
||||||
|
@ -250,7 +250,9 @@ draw_string(Render_Target *target, Face *face, String_Const_u8 string, Vec2_f32
|
||||||
if (color != 0){
|
if (color != 0){
|
||||||
draw_font_glyph(target, face, codepoint, point, color, flags);
|
draw_font_glyph(target, face, codepoint, point, color, flags);
|
||||||
}
|
}
|
||||||
f32 d = font_get_glyph_advance(face, codepoint);
|
f32 d = font_get_glyph_advance(&face->advance_map,
|
||||||
|
&face->metrics,
|
||||||
|
codepoint);
|
||||||
point += d*delta;
|
point += d*delta;
|
||||||
total_delta += d;
|
total_delta += d;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,8 +37,8 @@ text_layout_release(Thread_Context *tctx, Models *models, Text_Layout_Container
|
||||||
internal Text_Layout_ID
|
internal Text_Layout_ID
|
||||||
text_layout_new(Text_Layout_Container *container, Arena *arena,
|
text_layout_new(Text_Layout_Container *container, Arena *arena,
|
||||||
Buffer_ID buffer_id, Buffer_Point point,
|
Buffer_ID buffer_id, Buffer_Point point,
|
||||||
Interval_i64 visible_range, Interval_i64 visible_line_number_range,
|
Range_i64 visible_range, Interval_i64 visible_line_number_range,
|
||||||
Rect_f32 rect, FColor *item_colors){
|
Rect_f32 rect, FColor *item_colors, Layout_Function *layout_func){
|
||||||
Text_Layout *new_layout_data = text_layout_new__alloc_layout(container);
|
Text_Layout *new_layout_data = text_layout_new__alloc_layout(container);
|
||||||
new_layout_data->arena = arena;
|
new_layout_data->arena = arena;
|
||||||
new_layout_data->buffer_id = buffer_id;
|
new_layout_data->buffer_id = buffer_id;
|
||||||
|
@ -47,6 +47,7 @@ text_layout_new(Text_Layout_Container *container, Arena *arena,
|
||||||
new_layout_data->visible_line_number_range = visible_line_number_range;
|
new_layout_data->visible_line_number_range = visible_line_number_range;
|
||||||
new_layout_data->rect = rect;
|
new_layout_data->rect = rect;
|
||||||
new_layout_data->item_colors = item_colors;
|
new_layout_data->item_colors = item_colors;
|
||||||
|
new_layout_data->layout_func = layout_func;
|
||||||
Text_Layout_ID new_id = ++container->id_counter;
|
Text_Layout_ID new_id = ++container->id_counter;
|
||||||
table_insert(&container->table, new_id, (u64)PtrAsInt(new_layout_data));
|
table_insert(&container->table, new_id, (u64)PtrAsInt(new_layout_data));
|
||||||
return(new_id);
|
return(new_id);
|
||||||
|
@ -97,21 +98,24 @@ text_layout_render(Thread_Context *tctx, Models *models, Text_Layout *layout){
|
||||||
i64 first_index = layout->visible_range.first;
|
i64 first_index = layout->visible_range.first;
|
||||||
i64 line_number = layout->visible_line_number_range.min;
|
i64 line_number = layout->visible_line_number_range.min;
|
||||||
i64 line_number_last = layout->visible_line_number_range.max;
|
i64 line_number_last = layout->visible_line_number_range.max;
|
||||||
|
Layout_Function *layout_func = layout->layout_func;
|
||||||
for (;line_number <= line_number_last; line_number += 1){
|
for (;line_number <= line_number_last; line_number += 1){
|
||||||
Buffer_Layout_Item_List line = file_get_line_layout(tctx, models, file, width, face, line_number);
|
Layout_Item_List line = file_get_line_layout(tctx, models, file,
|
||||||
for (Buffer_Layout_Item_Block *block = line.first;
|
layout_func, width, face,
|
||||||
|
line_number);
|
||||||
|
for (Layout_Item_Block *block = line.first;
|
||||||
block != 0;
|
block != 0;
|
||||||
block = block->next){
|
block = block->next){
|
||||||
Buffer_Layout_Item *item = block->items;
|
Layout_Item *item = block->items;
|
||||||
i64 count = block->count;
|
i64 count = block->count;
|
||||||
FColor *item_colors = layout->item_colors;
|
FColor *item_colors = layout->item_colors;
|
||||||
for (i32 i = 0; i < count; i += 1, item += 1){
|
for (i32 i = 0; i < count; i += 1, item += 1){
|
||||||
if (item->codepoint != 0){
|
if (item->codepoint != 0){
|
||||||
ARGB_Color color = 0;
|
ARGB_Color color = 0;
|
||||||
if (HasFlag(item->flags, BRFlag_Special_Character)){
|
if (HasFlag(item->flags, LayoutItemFlag_Special_Character)){
|
||||||
color = special_color;
|
color = special_color;
|
||||||
}
|
}
|
||||||
else if (HasFlag(item->flags, BRFlag_Ghost_Character)){
|
else if (HasFlag(item->flags, LayoutItemFlag_Ghost_Character)){
|
||||||
color = ghost_color;
|
color = ghost_color;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
|
|
@ -22,6 +22,7 @@ union Text_Layout{
|
||||||
Interval_i64 visible_line_number_range;
|
Interval_i64 visible_line_number_range;
|
||||||
Rect_f32 rect;
|
Rect_f32 rect;
|
||||||
FColor *item_colors;
|
FColor *item_colors;
|
||||||
|
Layout_Function *layout_func;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
111
4ed_view.cpp
111
4ed_view.cpp
|
@ -177,66 +177,91 @@ view_height(Thread_Context *tctx, Models *models, View *view){
|
||||||
return(rect_height(view_get_buffer_rect(tctx, models, view)));
|
return(rect_height(view_get_buffer_rect(tctx, models, view)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Layout_Function*
|
||||||
|
view_get_layout_func(View *view){
|
||||||
|
return(view->layout_func);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
internal Buffer_Layout_Item_List
|
internal Layout_Item_List
|
||||||
view_get_line_layout(Thread_Context *tctx, Models *models, View *view, i64 line_number){
|
view_get_line_layout(Thread_Context *tctx, Models *models, View *view, i64 line_number){
|
||||||
Editing_File *file = view->file;
|
Editing_File *file = view->file;
|
||||||
Face *face = file_get_face(models, file);
|
Face *face = file_get_face(models, file);
|
||||||
f32 width = view_width(tctx, models, view);
|
f32 width = view_width(tctx, models, view);
|
||||||
return(file_get_line_layout(tctx, models, file, width, face, line_number));
|
Layout_Function *layout_func = view_get_layout_func(view);
|
||||||
|
return(file_get_line_layout(tctx, models, file, layout_func, width, face, line_number));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Line_Shift_Vertical
|
internal Line_Shift_Vertical
|
||||||
view_line_shift_y(Thread_Context *tctx, Models *models, View *view, i64 line_number, f32 y_delta){
|
view_line_shift_y(Thread_Context *tctx, Models *models, View *view,
|
||||||
|
i64 line_number, f32 y_delta){
|
||||||
Editing_File *file = view->file;
|
Editing_File *file = view->file;
|
||||||
Face *face = file_get_face(models, file);
|
Face *face = file_get_face(models, file);
|
||||||
f32 width = view_width(tctx, models, view);
|
f32 width = view_width(tctx, models, view);
|
||||||
return(file_line_shift_y(tctx, models, file, width, face, line_number, y_delta));
|
Layout_Function *layout_func = view_get_layout_func(view);
|
||||||
|
return(file_line_shift_y(tctx, models, file, layout_func, width, face,
|
||||||
|
line_number, y_delta));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal f32
|
internal f32
|
||||||
view_line_y_difference(Thread_Context *tctx, Models *models, View *view, i64 line_a, i64 line_b){
|
view_line_y_difference(Thread_Context *tctx, Models *models, View *view,
|
||||||
|
i64 line_a, i64 line_b){
|
||||||
Editing_File *file = view->file;
|
Editing_File *file = view->file;
|
||||||
Face *face = file_get_face(models, file);
|
Face *face = file_get_face(models, file);
|
||||||
f32 width = view_width(tctx, models, view);
|
f32 width = view_width(tctx, models, view);
|
||||||
return(file_line_y_difference(tctx, models, file, width, face, line_a, line_b));
|
Layout_Function *layout_func = view_get_layout_func(view);
|
||||||
|
return(file_line_y_difference(tctx, models, file,
|
||||||
|
layout_func, width, face, line_a, line_b));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal i64
|
internal i64
|
||||||
view_pos_at_relative_xy(Thread_Context *tctx, Models *models, View *view, i64 base_line, Vec2_f32 relative_xy){
|
view_pos_at_relative_xy(Thread_Context *tctx, Models *models, View *view,
|
||||||
|
i64 base_line, Vec2_f32 relative_xy){
|
||||||
Editing_File *file = view->file;
|
Editing_File *file = view->file;
|
||||||
Face *face = file_get_face(models, file);
|
Face *face = file_get_face(models, file);
|
||||||
f32 width = view_width(tctx, models, view);
|
f32 width = view_width(tctx, models, view);
|
||||||
return(file_pos_at_relative_xy(tctx, models, file, width, face, base_line, relative_xy));
|
Layout_Function *layout_func = view_get_layout_func(view);
|
||||||
|
return(file_pos_at_relative_xy(tctx, models, file,
|
||||||
|
layout_func, width, face, base_line, relative_xy));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Vec2_f32
|
internal Vec2_f32
|
||||||
view_relative_xy_of_pos(Thread_Context *tctx, Models *models, View *view, i64 base_line, i64 pos){
|
view_relative_xy_of_pos(Thread_Context *tctx, Models *models, View *view,
|
||||||
|
i64 base_line, i64 pos){
|
||||||
Editing_File *file = view->file;
|
Editing_File *file = view->file;
|
||||||
Face *face = file_get_face(models, file);
|
Face *face = file_get_face(models, file);
|
||||||
f32 width = view_width(tctx, models, view);
|
f32 width = view_width(tctx, models, view);
|
||||||
return(file_relative_xy_of_pos(tctx, models, file, width, face, base_line, pos));
|
Layout_Function *layout_func = view_get_layout_func(view);
|
||||||
|
return(file_relative_xy_of_pos(tctx, models, file,
|
||||||
|
layout_func, width, face, base_line, pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Buffer_Point
|
internal Buffer_Point
|
||||||
view_normalize_buffer_point(Thread_Context *tctx, Models *models, View *view, Buffer_Point point){
|
view_normalize_buffer_point(Thread_Context *tctx, Models *models, View *view,
|
||||||
|
Buffer_Point point){
|
||||||
Editing_File *file = view->file;
|
Editing_File *file = view->file;
|
||||||
Face *face = file_get_face(models, file);
|
Face *face = file_get_face(models, file);
|
||||||
f32 width = view_width(tctx, models, view);
|
f32 width = view_width(tctx, models, view);
|
||||||
return(file_normalize_buffer_point(tctx, models, file, width, face, point));
|
Layout_Function *layout_func = view_get_layout_func(view);
|
||||||
|
return(file_normalize_buffer_point(tctx, models, file,
|
||||||
|
layout_func, width, face, point));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Vec2_f32
|
internal Vec2_f32
|
||||||
view_buffer_point_difference(Thread_Context *tctx, Models *models, View *view, Buffer_Point a, Buffer_Point b){
|
view_buffer_point_difference(Thread_Context *tctx, Models *models, View *view,
|
||||||
|
Buffer_Point a, Buffer_Point b){
|
||||||
Editing_File *file = view->file;
|
Editing_File *file = view->file;
|
||||||
Face *face = file_get_face(models, file);
|
Face *face = file_get_face(models, file);
|
||||||
f32 width = view_width(tctx, models, view);
|
f32 width = view_width(tctx, models, view);
|
||||||
return(file_buffer_point_difference(tctx, models, file, width, face, a, b));
|
Layout_Function *layout_func = view_get_layout_func(view);
|
||||||
|
return(file_buffer_point_difference(tctx, models, file,
|
||||||
|
layout_func, width, face, a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Buffer_Point
|
internal Buffer_Point
|
||||||
view_move_buffer_point(Thread_Context *tctx, Models *models, View *view, Buffer_Point buffer_point, Vec2_f32 delta){
|
view_move_buffer_point(Thread_Context *tctx, Models *models, View *view,
|
||||||
|
Buffer_Point buffer_point, Vec2_f32 delta){
|
||||||
delta += buffer_point.pixel_shift;
|
delta += buffer_point.pixel_shift;
|
||||||
Line_Shift_Vertical shift = view_line_shift_y(tctx, models, view, buffer_point.line_number, delta.y);
|
Line_Shift_Vertical shift = view_line_shift_y(tctx, models, view, buffer_point.line_number, delta.y);
|
||||||
buffer_point.line_number = shift.line;
|
buffer_point.line_number = shift.line;
|
||||||
|
@ -245,35 +270,47 @@ view_move_buffer_point(Thread_Context *tctx, Models *models, View *view, Buffer_
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Line_Shift_Character
|
internal Line_Shift_Character
|
||||||
view_line_shift_characters(Thread_Context *tctx, Models *models, View *view, i64 line_number, i64 character_delta){
|
view_line_shift_characters(Thread_Context *tctx, Models *models, View *view,
|
||||||
|
i64 line_number, i64 character_delta){
|
||||||
Editing_File *file = view->file;
|
Editing_File *file = view->file;
|
||||||
Face *face = file_get_face(models, file);
|
Face *face = file_get_face(models, file);
|
||||||
f32 width = view_width(tctx, models, view);
|
f32 width = view_width(tctx, models, view);
|
||||||
return(file_line_shift_characters(tctx, models, file, width, face, line_number, character_delta));
|
Layout_Function *layout_func = view_get_layout_func(view);
|
||||||
|
return(file_line_shift_characters(tctx, models, file,
|
||||||
|
layout_func, width, face, line_number, character_delta));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal i64
|
internal i64
|
||||||
view_line_character_difference(Thread_Context *tctx, Models *models, View *view, i64 line_a, i64 line_b){
|
view_line_character_difference(Thread_Context *tctx, Models *models, View *view,
|
||||||
|
i64 line_a, i64 line_b){
|
||||||
Editing_File *file = view->file;
|
Editing_File *file = view->file;
|
||||||
Face *face = file_get_face(models, file);
|
Face *face = file_get_face(models, file);
|
||||||
f32 width = view_width(tctx, models, view);
|
f32 width = view_width(tctx, models, view);
|
||||||
return(file_line_character_difference(tctx, models, file, width, face, line_a, line_b));
|
Layout_Function *layout_func = view_get_layout_func(view);
|
||||||
|
return(file_line_character_difference(tctx, models, file, layout_func, width, face,
|
||||||
|
line_a, line_b));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal i64
|
internal i64
|
||||||
view_pos_from_relative_character(Thread_Context *tctx, Models *models, View *view, i64 base_line, i64 relative_character){
|
view_pos_from_relative_character(Thread_Context *tctx, Models *models, View *view,
|
||||||
|
i64 base_line, i64 relative_character){
|
||||||
Editing_File *file = view->file;
|
Editing_File *file = view->file;
|
||||||
Face *face = file_get_face(models, file);
|
Face *face = file_get_face(models, file);
|
||||||
f32 width = view_width(tctx, models, view);
|
f32 width = view_width(tctx, models, view);
|
||||||
return(file_pos_from_relative_character(tctx, models, file, width, face, base_line, relative_character));
|
Layout_Function *layout_func = view_get_layout_func(view);
|
||||||
|
return(file_pos_from_relative_character(tctx, models, file, layout_func, width, face,
|
||||||
|
base_line, relative_character));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal i64
|
internal i64
|
||||||
view_relative_character_from_pos(Thread_Context *tctx, Models *models, View *view, i64 base_line, i64 pos){
|
view_relative_character_from_pos(Thread_Context *tctx, Models *models, View *view,
|
||||||
|
i64 base_line, i64 pos){
|
||||||
Editing_File *file = view->file;
|
Editing_File *file = view->file;
|
||||||
Face *face = file_get_face(models, file);
|
Face *face = file_get_face(models, file);
|
||||||
f32 width = view_width(tctx, models, view);
|
f32 width = view_width(tctx, models, view);
|
||||||
return(file_relative_character_from_pos(tctx, models, file, width, face, base_line, pos));
|
Layout_Function *layout_func = view_get_layout_func(view);
|
||||||
|
return(file_relative_character_from_pos(tctx, models, file,
|
||||||
|
layout_func, width, face, base_line, pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Buffer_Cursor
|
internal Buffer_Cursor
|
||||||
|
@ -291,13 +328,16 @@ view_move_view_to_cursor(Thread_Context *tctx, Models *models, View *view, Buffe
|
||||||
Rect_f32 rect = view_get_buffer_rect(tctx, models, view);
|
Rect_f32 rect = view_get_buffer_rect(tctx, models, view);
|
||||||
Vec2_f32 view_dim = rect_dim(rect);
|
Vec2_f32 view_dim = rect_dim(rect);
|
||||||
|
|
||||||
|
Layout_Function *layout_func = view_get_layout_func(view);
|
||||||
|
|
||||||
File_Edit_Positions edit_pos = view_get_edit_pos(view);
|
File_Edit_Positions edit_pos = view_get_edit_pos(view);
|
||||||
Vec2_f32 p = file_relative_xy_of_pos(tctx, models, file, view_dim.x, face, scroll->target.line_number,
|
Vec2_f32 p = file_relative_xy_of_pos(tctx, models, file,
|
||||||
edit_pos.cursor_pos);
|
layout_func, view_dim.x, face,
|
||||||
|
scroll->target.line_number, edit_pos.cursor_pos);
|
||||||
p -= scroll->target.pixel_shift;
|
p -= scroll->target.pixel_shift;
|
||||||
|
|
||||||
f32 line_height = face->line_height;
|
f32 line_height = face->metrics.line_height;
|
||||||
f32 typical_advance = face->typical_advance;
|
f32 normal_advance = face->metrics.normal_advance;
|
||||||
|
|
||||||
Vec2_f32 target_p_relative = {};
|
Vec2_f32 target_p_relative = {};
|
||||||
if (p.y < 0.f){
|
if (p.y < 0.f){
|
||||||
|
@ -307,10 +347,10 @@ view_move_view_to_cursor(Thread_Context *tctx, Models *models, View *view, Buffe
|
||||||
target_p_relative.y = (p.y + line_height*1.5f) - view_dim.y;
|
target_p_relative.y = (p.y + line_height*1.5f) - view_dim.y;
|
||||||
}
|
}
|
||||||
if (p.x < 0.f){
|
if (p.x < 0.f){
|
||||||
target_p_relative.x = p.x - typical_advance*1.5f;
|
target_p_relative.x = p.x - normal_advance*1.5f;
|
||||||
}
|
}
|
||||||
else if (p.x > view_dim.x){
|
else if (p.x > view_dim.x){
|
||||||
target_p_relative.x = (p.x + typical_advance*1.5f) - view_dim.x;
|
target_p_relative.x = (p.x + normal_advance*1.5f) - view_dim.x;
|
||||||
}
|
}
|
||||||
scroll->target.pixel_shift += target_p_relative;
|
scroll->target.pixel_shift += target_p_relative;
|
||||||
scroll->target = view_normalize_buffer_point(tctx, models, view, scroll->target);
|
scroll->target = view_normalize_buffer_point(tctx, models, view, scroll->target);
|
||||||
|
@ -327,10 +367,14 @@ view_move_cursor_to_view(Thread_Context *tctx, Models *models, View *view, Buffe
|
||||||
Rect_f32 rect = view_get_buffer_rect(tctx, models, view);
|
Rect_f32 rect = view_get_buffer_rect(tctx, models, view);
|
||||||
Vec2_f32 view_dim = rect_dim(rect);
|
Vec2_f32 view_dim = rect_dim(rect);
|
||||||
|
|
||||||
Vec2_f32 p = file_relative_xy_of_pos(tctx, models, file, view_dim.x, face, scroll.target.line_number, *pos_in_out);
|
Layout_Function *layout_func = view_get_layout_func(view);
|
||||||
|
|
||||||
|
Vec2_f32 p = file_relative_xy_of_pos(tctx, models, file,
|
||||||
|
layout_func, view_dim.x, face,
|
||||||
|
scroll.target.line_number, *pos_in_out);
|
||||||
p -= scroll.target.pixel_shift;
|
p -= scroll.target.pixel_shift;
|
||||||
|
|
||||||
f32 line_height = face->line_height;
|
f32 line_height = face->metrics.line_height;
|
||||||
|
|
||||||
b32 adjusted_y = true;
|
b32 adjusted_y = true;
|
||||||
if (p.y < 0.f){
|
if (p.y < 0.f){
|
||||||
|
@ -346,7 +390,9 @@ view_move_cursor_to_view(Thread_Context *tctx, Models *models, View *view, Buffe
|
||||||
b32 result = false;
|
b32 result = false;
|
||||||
if (adjusted_y){
|
if (adjusted_y){
|
||||||
p += scroll.target.pixel_shift;
|
p += scroll.target.pixel_shift;
|
||||||
*pos_in_out = file_pos_at_relative_xy(tctx, models, file, view_dim.x, face, scroll.target.line_number, p);
|
*pos_in_out = file_pos_at_relative_xy(tctx, models, file,
|
||||||
|
layout_func, view_dim.x, face,
|
||||||
|
scroll.target.line_number, p);
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,6 +561,7 @@ view_event_context_base__inner(Coroutine *coroutine){
|
||||||
function void
|
function void
|
||||||
view_init(Thread_Context *tctx, Models *models, View *view, Editing_File *initial_buffer,
|
view_init(Thread_Context *tctx, Models *models, View *view, Editing_File *initial_buffer,
|
||||||
Custom_Command_Function *event_context_base){
|
Custom_Command_Function *event_context_base){
|
||||||
|
view->layout_func = models->layout_func;
|
||||||
view_set_file(tctx, models, view, initial_buffer);
|
view_set_file(tctx, models, view, initial_buffer);
|
||||||
|
|
||||||
view->node_arena = reserve_arena(tctx);
|
view->node_arena = reserve_arena(tctx);
|
||||||
|
|
|
@ -75,6 +75,7 @@ struct View{
|
||||||
File_Edit_Positions edit_pos_;
|
File_Edit_Positions edit_pos_;
|
||||||
i64 mark;
|
i64 mark;
|
||||||
f32 preferred_x;
|
f32 preferred_x;
|
||||||
|
Layout_Function *layout_func;
|
||||||
|
|
||||||
b8 new_scroll_target;
|
b8 new_scroll_target;
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Mr. 4th Dimention - Allen Webster
|
4coder_codepoint_map.cpp - Codepoint map to index
|
||||||
*
|
|
||||||
* 23.07.2019
|
|
||||||
*
|
|
||||||
* Face basic operations.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TOP
|
// TOP
|
||||||
|
|
||||||
internal b32
|
function b32
|
||||||
codepoint_index_map_read(Codepoint_Index_Map *map, u32 codepoint, u16 *index_out){
|
codepoint_index_map_read(Codepoint_Index_Map *map, u32 codepoint, u16 *index_out){
|
||||||
b32 success = true;
|
b32 success = true;
|
||||||
if (codepoint == 0 && map->has_zero_index){
|
if (codepoint == 0 && map->has_zero_index){
|
||||||
|
@ -24,46 +19,48 @@ codepoint_index_map_read(Codepoint_Index_Map *map, u32 codepoint, u16 *index_out
|
||||||
return(success);
|
return(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal u16
|
function u16
|
||||||
codepoint_index_map_count(Codepoint_Index_Map *map){
|
codepoint_index_map_count(Codepoint_Index_Map *map){
|
||||||
return(map->max_index + 1);
|
return(map->max_index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal f32
|
function f32
|
||||||
font_get_glyph_advance(Face *face, u32 codepoint){
|
font_get_glyph_advance(Face_Advance_Map *map, Face_Metrics *metrics, u32 codepoint){
|
||||||
f32 result = 0.f;
|
f32 result = 0.f;
|
||||||
if (codepoint == '\t'){
|
if (codepoint == '\t'){
|
||||||
result = face->space_advance*4.f;
|
result = metrics->space_advance*4.f;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if (character_is_whitespace(codepoint)){
|
if (character_is_whitespace(codepoint)){
|
||||||
codepoint = ' ';
|
codepoint = ' ';
|
||||||
}
|
}
|
||||||
u16 index = 0;
|
u16 index = 0;
|
||||||
if (codepoint_index_map_read(&face->codepoint_to_index_map, codepoint, &index)){
|
if (codepoint_index_map_read(&map->codepoint_to_index, codepoint, &index)){
|
||||||
if (index < face->index_count){
|
if (index < map->index_count){
|
||||||
result = face->advance[index];
|
result = map->advance[index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal f32
|
function f32
|
||||||
font_get_max_glyph_advance_range(Face *face, u32 codepoint_first, u32 codepoint_last){
|
font_get_max_glyph_advance_range(Face_Advance_Map *map, Face_Metrics *metrics,
|
||||||
f32 result = font_get_glyph_advance(face, codepoint_first);
|
u32 codepoint_first, u32 codepoint_last){
|
||||||
|
f32 result = font_get_glyph_advance(map, metrics, codepoint_first);
|
||||||
for (u32 i = codepoint_first + 1; i <= codepoint_last; i += 1){
|
for (u32 i = codepoint_first + 1; i <= codepoint_last; i += 1){
|
||||||
f32 a = font_get_glyph_advance(face, i);
|
f32 a = font_get_glyph_advance(map, metrics, i);
|
||||||
result = Max(a, result);
|
result = Max(a, result);
|
||||||
}
|
}
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal f32
|
function f32
|
||||||
font_get_average_glyph_advance_range(Face *face, u32 codepoint_first, u32 codepoint_last){
|
font_get_average_glyph_advance_range(Face_Advance_Map *map, Face_Metrics *metrics,
|
||||||
|
u32 codepoint_first, u32 codepoint_last){
|
||||||
f32 result = 0.f;
|
f32 result = 0.f;
|
||||||
for (u32 i = codepoint_first; i <= codepoint_last; i += 1){
|
for (u32 i = codepoint_first; i <= codepoint_last; i += 1){
|
||||||
result += font_get_glyph_advance(face, i);
|
result += font_get_glyph_advance(map, metrics, i);
|
||||||
}
|
}
|
||||||
result /= (f32)(codepoint_last - codepoint_first + 1);
|
result /= (f32)(codepoint_last - codepoint_first + 1);
|
||||||
return(result);
|
return(result);
|
|
@ -281,6 +281,188 @@ default_buffer_region(Application_Links *app, View_ID view_id, Rect_f32 region){
|
||||||
return(region);
|
return(region);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
buffer_layout__write(Arena *arena, Layout_Item_List *list,
|
||||||
|
i64 index, u32 codepoint, Layout_Item_Flag flags, Rect_f32 rect){
|
||||||
|
Temp_Memory restore_point = begin_temp(arena);
|
||||||
|
Layout_Item *item = push_array(arena, Layout_Item, 1);
|
||||||
|
|
||||||
|
Layout_Item_Block *block = list->first;
|
||||||
|
if (block != 0){
|
||||||
|
if (block->items + block->count == item){
|
||||||
|
block->count += 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
block = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (block == 0){
|
||||||
|
end_temp(restore_point);
|
||||||
|
block = push_array(arena, Layout_Item_Block, 1);
|
||||||
|
item = push_array(arena, Layout_Item, 1);
|
||||||
|
sll_queue_push(list->first, list->last, block);
|
||||||
|
list->node_count += 1;
|
||||||
|
block->items = item;
|
||||||
|
block->count = 1;
|
||||||
|
}
|
||||||
|
list->total_count += 1;
|
||||||
|
|
||||||
|
if (index > list->index_range.max){
|
||||||
|
block->character_count += 1;
|
||||||
|
list->character_count += 1;
|
||||||
|
list->index_range.max = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
item->index = index;
|
||||||
|
item->codepoint = codepoint;
|
||||||
|
item->flags = flags;
|
||||||
|
item->rect = rect;
|
||||||
|
list->height = max(list->height, rect.y1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Layout_Item_List
|
||||||
|
default_buffer_layout(Application_Links *app, Arena *arena, Buffer_ID buffer, Range_i64 range,
|
||||||
|
Face_ID face, f32 width){
|
||||||
|
Scratch_Block scratch(app);
|
||||||
|
|
||||||
|
Layout_Item_List list = {};
|
||||||
|
list.index_range.first = range.first;
|
||||||
|
list.index_range.one_past_last = range.first - 1;
|
||||||
|
|
||||||
|
String_Const_u8 text = push_buffer_range(app, scratch, buffer, range);
|
||||||
|
|
||||||
|
Face_Metrics metrics = get_face_metrics(app, face);
|
||||||
|
f32 line_height = metrics.line_height;
|
||||||
|
f32 text_height = metrics.text_height;
|
||||||
|
f32 line_to_text_shift = text_height - line_height;
|
||||||
|
f32 space_advance = metrics.space_advance;
|
||||||
|
|
||||||
|
Face_Advance_Map advance_map = get_face_advance_map(app, face);
|
||||||
|
|
||||||
|
if (text.size == 0){
|
||||||
|
f32 next_x = space_advance;
|
||||||
|
buffer_layout__write(arena, &list, range.first, ' ', 0,
|
||||||
|
Rf32(V2(0.f, 0.f), V2f32(next_x, text_height)));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
Vec2_f32 p = {};
|
||||||
|
f32 line_y = line_height;
|
||||||
|
f32 text_y = text_height;
|
||||||
|
|
||||||
|
i64 index = range.first;
|
||||||
|
b32 first_of_the_line = true;
|
||||||
|
|
||||||
|
b32 consuming_newline_characters = false;
|
||||||
|
i64 newline_character_index = -1;
|
||||||
|
|
||||||
|
b32 prev_did_emit_newline = false;
|
||||||
|
|
||||||
|
u8 *ptr = text.str;
|
||||||
|
u8 *end_ptr = ptr + text.size;
|
||||||
|
for (;ptr < end_ptr;){
|
||||||
|
Character_Consume_Result consume = utf8_consume(ptr, (umem)(end_ptr - ptr));
|
||||||
|
u32 render_codepoint = consume.codepoint;
|
||||||
|
b32 emit_newline = false;
|
||||||
|
switch (consume.codepoint){
|
||||||
|
case '\t':
|
||||||
|
{
|
||||||
|
render_codepoint = ' ';
|
||||||
|
}//fallthrough;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
f32 advance = font_get_glyph_advance(&advance_map, &metrics,
|
||||||
|
consume.codepoint);
|
||||||
|
f32 next_x = p.x + advance;
|
||||||
|
if (!first_of_the_line && next_x >= width){
|
||||||
|
p.y = line_y;
|
||||||
|
p.x = 0.f;
|
||||||
|
line_y += line_height;
|
||||||
|
text_y = line_y + line_to_text_shift;
|
||||||
|
next_x = p.x + advance;
|
||||||
|
}
|
||||||
|
buffer_layout__write(arena, &list, index, render_codepoint, 0,
|
||||||
|
Rf32(p, V2f32(next_x, text_y)));
|
||||||
|
p.x = next_x;
|
||||||
|
ptr += consume.inc;
|
||||||
|
index += consume.inc;
|
||||||
|
first_of_the_line = false;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case '\r':
|
||||||
|
{
|
||||||
|
if (!consuming_newline_characters){
|
||||||
|
consuming_newline_characters = true;
|
||||||
|
newline_character_index = index;
|
||||||
|
}
|
||||||
|
ptr += 1;
|
||||||
|
index += 1;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case '\n':
|
||||||
|
{
|
||||||
|
if (!consuming_newline_characters){
|
||||||
|
consuming_newline_characters = true;
|
||||||
|
newline_character_index = index;
|
||||||
|
}
|
||||||
|
emit_newline = true;
|
||||||
|
ptr += 1;
|
||||||
|
index += 1;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case max_u32:
|
||||||
|
{
|
||||||
|
f32 next_x = p.x + metrics.byte_advance;
|
||||||
|
if (!first_of_the_line && next_x >= width){
|
||||||
|
p.y = line_y;
|
||||||
|
p.x = 0.f;
|
||||||
|
line_y += line_height;
|
||||||
|
text_y = line_y + line_to_text_shift;
|
||||||
|
next_x = p.x + metrics.byte_advance;
|
||||||
|
}
|
||||||
|
u32 v = *ptr;
|
||||||
|
u32 lo = v&0xF;
|
||||||
|
u32 hi = (v >> 4)&0xF;
|
||||||
|
f32 advance = metrics.byte_sub_advances[0];
|
||||||
|
buffer_layout__write(arena, &list, index, '\\', 0,
|
||||||
|
Rf32(p, V2f32(p.x + advance, text_y)));
|
||||||
|
p.x += advance;
|
||||||
|
advance = metrics.byte_sub_advances[1];
|
||||||
|
buffer_layout__write(arena, &list, index, integer_symbols[lo], 0,
|
||||||
|
Rf32(p, V2f32(p.x + advance, text_y)));
|
||||||
|
p.x += advance;
|
||||||
|
advance = metrics.byte_sub_advances[2];
|
||||||
|
buffer_layout__write(arena, &list, index, integer_symbols[hi], 0,
|
||||||
|
Rf32(p, V2f32(p.x + advance, text_y)));
|
||||||
|
p.x = next_x;
|
||||||
|
ptr += 1;
|
||||||
|
index += 1;
|
||||||
|
first_of_the_line = false;
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
prev_did_emit_newline = false;
|
||||||
|
if (emit_newline){
|
||||||
|
f32 next_x = p.x + space_advance;
|
||||||
|
buffer_layout__write(arena, &list, newline_character_index, ' ', 0,
|
||||||
|
Rf32(p, V2f32(next_x, text_y)));
|
||||||
|
p.y = line_y;
|
||||||
|
p.x = 0.f;
|
||||||
|
line_y += line_height;
|
||||||
|
text_y = line_y + line_to_text_shift;
|
||||||
|
first_of_the_line = true;
|
||||||
|
prev_did_emit_newline = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!prev_did_emit_newline){
|
||||||
|
f32 next_x = p.x + space_advance;
|
||||||
|
buffer_layout__write(arena, &list, index, ' ', 0, Rf32(p, V2f32(next_x, text_y)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list.bottom_extension = -line_to_text_shift;
|
||||||
|
list.height += list.bottom_extension;
|
||||||
|
|
||||||
|
return(list);
|
||||||
|
}
|
||||||
|
|
||||||
function void
|
function void
|
||||||
default_render_buffer(Application_Links *app, View_ID view_id, b32 is_active_view,
|
default_render_buffer(Application_Links *app, View_ID view_id, b32 is_active_view,
|
||||||
Buffer_ID buffer, Text_Layout_ID text_layout_id,
|
Buffer_ID buffer, Text_Layout_ID text_layout_id,
|
||||||
|
@ -931,6 +1113,7 @@ set_all_default_hooks(Application_Links *app){
|
||||||
set_custom_hook(app, HookID_SaveFile, default_file_save);
|
set_custom_hook(app, HookID_SaveFile, default_file_save);
|
||||||
set_custom_hook(app, HookID_BufferEditRange, default_buffer_edit_range);
|
set_custom_hook(app, HookID_BufferEditRange, default_buffer_edit_range);
|
||||||
set_custom_hook(app, HookID_BufferRegion, default_buffer_region);
|
set_custom_hook(app, HookID_BufferRegion, default_buffer_region);
|
||||||
|
set_custom_hook(app, HookID_Layout, default_buffer_layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
// BOTTOM
|
// BOTTOM
|
||||||
|
|
|
@ -64,6 +64,7 @@
|
||||||
#include "4coder_log.cpp"
|
#include "4coder_log.cpp"
|
||||||
#include "4coder_hash_functions.cpp"
|
#include "4coder_hash_functions.cpp"
|
||||||
#include "4coder_table.cpp"
|
#include "4coder_table.cpp"
|
||||||
|
#include "4coder_codepoint_map.cpp"
|
||||||
#include "4coder_async_tasks.cpp"
|
#include "4coder_async_tasks.cpp"
|
||||||
#include "4coder_string_match.cpp"
|
#include "4coder_string_match.cpp"
|
||||||
#include "4coder_buffer_seek_constructors.cpp"
|
#include "4coder_buffer_seek_constructors.cpp"
|
||||||
|
|
|
@ -448,11 +448,35 @@ struct Face_Description{
|
||||||
struct Face_Metrics{
|
struct Face_Metrics{
|
||||||
f32 text_height;
|
f32 text_height;
|
||||||
f32 line_height;
|
f32 line_height;
|
||||||
|
f32 ascent;
|
||||||
|
f32 descent;
|
||||||
|
f32 line_skip;
|
||||||
|
|
||||||
|
f32 underline_yoff1;
|
||||||
|
f32 underline_yoff2;
|
||||||
|
|
||||||
f32 max_advance;
|
f32 max_advance;
|
||||||
f32 normal_advance;
|
|
||||||
f32 space_advance;
|
f32 space_advance;
|
||||||
f32 decimal_digit_advance;
|
f32 decimal_digit_advance;
|
||||||
f32 hex_digit_advance;
|
f32 hex_digit_advance;
|
||||||
|
f32 byte_advance;
|
||||||
|
f32 byte_sub_advances[3];
|
||||||
|
f32 normal_lowercase_advance;
|
||||||
|
f32 normal_uppercase_advance;
|
||||||
|
f32 normal_advance;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Codepoint_Index_Map{
|
||||||
|
b32 has_zero_index;
|
||||||
|
u16 zero_index;
|
||||||
|
u16 max_index;
|
||||||
|
Table_u32_u16 table;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Face_Advance_Map{
|
||||||
|
Codepoint_Index_Map codepoint_to_index;
|
||||||
|
f32 *advance;
|
||||||
|
u16 index_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Edit{
|
struct Edit{
|
||||||
|
@ -542,6 +566,7 @@ enum{
|
||||||
HookID_SaveFile,
|
HookID_SaveFile,
|
||||||
HookID_BufferEditRange,
|
HookID_BufferEditRange,
|
||||||
HookID_BufferRegion,
|
HookID_BufferRegion,
|
||||||
|
HookID_Layout,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef i32 Hook_Function(Application_Links *app);
|
typedef i32 Hook_Function(Application_Links *app);
|
||||||
|
@ -584,6 +609,41 @@ typedef void Render_Caller_Function(Application_Links *app, Frame_Info frame_inf
|
||||||
#define RENDER_CALLER_SIG(name) \
|
#define RENDER_CALLER_SIG(name) \
|
||||||
void name(Application_Links *app, Frame_Info frame_info, View_ID view)
|
void name(Application_Links *app, Frame_Info frame_info, View_ID view)
|
||||||
|
|
||||||
|
typedef u32 Layout_Item_Flag;
|
||||||
|
enum{
|
||||||
|
LayoutItemFlag_Special_Character = (1 << 0),
|
||||||
|
LayoutItemFlag_Ghost_Character = (1 << 1)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Layout_Item{
|
||||||
|
i64 index;
|
||||||
|
u32 codepoint;
|
||||||
|
Layout_Item_Flag flags;
|
||||||
|
Rect_f32 rect;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Layout_Item_Block{
|
||||||
|
Layout_Item_Block *next;
|
||||||
|
Layout_Item *items;
|
||||||
|
i64 count;
|
||||||
|
i64 character_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Layout_Item_List{
|
||||||
|
Layout_Item_Block *first;
|
||||||
|
Layout_Item_Block *last;
|
||||||
|
i32 node_count;
|
||||||
|
i32 total_count;
|
||||||
|
f32 height;
|
||||||
|
f32 bottom_extension;
|
||||||
|
i64 character_count;
|
||||||
|
Interval_i64 index_range;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Layout_Item_List Layout_Function(Application_Links *app, Arena *arena,
|
||||||
|
Buffer_ID buffer, Range_i64 range,
|
||||||
|
Face_ID face, f32 width);
|
||||||
|
|
||||||
typedef i64 Command_Map_ID;
|
typedef i64 Command_Map_ID;
|
||||||
|
|
||||||
struct Command_Trigger{
|
struct Command_Trigger{
|
||||||
|
|
|
@ -143,6 +143,7 @@ vtable->global_history_edit_group_end = global_history_edit_group_end;
|
||||||
vtable->buffer_set_face = buffer_set_face;
|
vtable->buffer_set_face = buffer_set_face;
|
||||||
vtable->get_face_description = get_face_description;
|
vtable->get_face_description = get_face_description;
|
||||||
vtable->get_face_metrics = get_face_metrics;
|
vtable->get_face_metrics = get_face_metrics;
|
||||||
|
vtable->get_face_advance_map = get_face_advance_map;
|
||||||
vtable->get_face_id = get_face_id;
|
vtable->get_face_id = get_face_id;
|
||||||
vtable->try_create_new_face = try_create_new_face;
|
vtable->try_create_new_face = try_create_new_face;
|
||||||
vtable->try_modify_face = try_modify_face;
|
vtable->try_modify_face = try_modify_face;
|
||||||
|
@ -319,6 +320,7 @@ global_history_edit_group_end = vtable->global_history_edit_group_end;
|
||||||
buffer_set_face = vtable->buffer_set_face;
|
buffer_set_face = vtable->buffer_set_face;
|
||||||
get_face_description = vtable->get_face_description;
|
get_face_description = vtable->get_face_description;
|
||||||
get_face_metrics = vtable->get_face_metrics;
|
get_face_metrics = vtable->get_face_metrics;
|
||||||
|
get_face_advance_map = vtable->get_face_advance_map;
|
||||||
get_face_id = vtable->get_face_id;
|
get_face_id = vtable->get_face_id;
|
||||||
try_create_new_face = vtable->try_create_new_face;
|
try_create_new_face = vtable->try_create_new_face;
|
||||||
try_modify_face = vtable->try_modify_face;
|
try_modify_face = vtable->try_modify_face;
|
||||||
|
|
|
@ -141,6 +141,7 @@
|
||||||
#define custom_buffer_set_face_sig() b32 custom_buffer_set_face(Application_Links* app, Buffer_ID buffer_id, Face_ID id)
|
#define custom_buffer_set_face_sig() b32 custom_buffer_set_face(Application_Links* app, Buffer_ID buffer_id, Face_ID id)
|
||||||
#define custom_get_face_description_sig() Face_Description custom_get_face_description(Application_Links* app, Face_ID face_id)
|
#define custom_get_face_description_sig() Face_Description custom_get_face_description(Application_Links* app, Face_ID face_id)
|
||||||
#define custom_get_face_metrics_sig() Face_Metrics custom_get_face_metrics(Application_Links* app, Face_ID face_id)
|
#define custom_get_face_metrics_sig() Face_Metrics custom_get_face_metrics(Application_Links* app, Face_ID face_id)
|
||||||
|
#define custom_get_face_advance_map_sig() Face_Advance_Map custom_get_face_advance_map(Application_Links* app, Face_ID face_id)
|
||||||
#define custom_get_face_id_sig() Face_ID custom_get_face_id(Application_Links* app, Buffer_ID buffer_id)
|
#define custom_get_face_id_sig() Face_ID custom_get_face_id(Application_Links* app, Buffer_ID buffer_id)
|
||||||
#define custom_try_create_new_face_sig() Face_ID custom_try_create_new_face(Application_Links* app, Face_Description* description)
|
#define custom_try_create_new_face_sig() Face_ID custom_try_create_new_face(Application_Links* app, Face_Description* description)
|
||||||
#define custom_try_modify_face_sig() b32 custom_try_modify_face(Application_Links* app, Face_ID id, Face_Description* description)
|
#define custom_try_modify_face_sig() b32 custom_try_modify_face(Application_Links* app, Face_ID id, Face_Description* description)
|
||||||
|
@ -313,6 +314,7 @@ typedef void custom_global_history_edit_group_end_type(Application_Links* app);
|
||||||
typedef b32 custom_buffer_set_face_type(Application_Links* app, Buffer_ID buffer_id, Face_ID id);
|
typedef b32 custom_buffer_set_face_type(Application_Links* app, Buffer_ID buffer_id, Face_ID id);
|
||||||
typedef Face_Description custom_get_face_description_type(Application_Links* app, Face_ID face_id);
|
typedef Face_Description custom_get_face_description_type(Application_Links* app, Face_ID face_id);
|
||||||
typedef Face_Metrics custom_get_face_metrics_type(Application_Links* app, Face_ID face_id);
|
typedef Face_Metrics custom_get_face_metrics_type(Application_Links* app, Face_ID face_id);
|
||||||
|
typedef Face_Advance_Map custom_get_face_advance_map_type(Application_Links* app, Face_ID face_id);
|
||||||
typedef Face_ID custom_get_face_id_type(Application_Links* app, Buffer_ID buffer_id);
|
typedef Face_ID custom_get_face_id_type(Application_Links* app, Buffer_ID buffer_id);
|
||||||
typedef Face_ID custom_try_create_new_face_type(Application_Links* app, Face_Description* description);
|
typedef Face_ID custom_try_create_new_face_type(Application_Links* app, Face_Description* description);
|
||||||
typedef b32 custom_try_modify_face_type(Application_Links* app, Face_ID id, Face_Description* description);
|
typedef b32 custom_try_modify_face_type(Application_Links* app, Face_ID id, Face_Description* description);
|
||||||
|
@ -486,6 +488,7 @@ custom_global_history_edit_group_end_type *global_history_edit_group_end;
|
||||||
custom_buffer_set_face_type *buffer_set_face;
|
custom_buffer_set_face_type *buffer_set_face;
|
||||||
custom_get_face_description_type *get_face_description;
|
custom_get_face_description_type *get_face_description;
|
||||||
custom_get_face_metrics_type *get_face_metrics;
|
custom_get_face_metrics_type *get_face_metrics;
|
||||||
|
custom_get_face_advance_map_type *get_face_advance_map;
|
||||||
custom_get_face_id_type *get_face_id;
|
custom_get_face_id_type *get_face_id;
|
||||||
custom_try_create_new_face_type *try_create_new_face;
|
custom_try_create_new_face_type *try_create_new_face;
|
||||||
custom_try_modify_face_type *try_modify_face;
|
custom_try_modify_face_type *try_modify_face;
|
||||||
|
@ -660,6 +663,7 @@ internal void global_history_edit_group_end(Application_Links* app);
|
||||||
internal b32 buffer_set_face(Application_Links* app, Buffer_ID buffer_id, Face_ID id);
|
internal b32 buffer_set_face(Application_Links* app, Buffer_ID buffer_id, Face_ID id);
|
||||||
internal Face_Description get_face_description(Application_Links* app, Face_ID face_id);
|
internal Face_Description get_face_description(Application_Links* app, Face_ID face_id);
|
||||||
internal Face_Metrics get_face_metrics(Application_Links* app, Face_ID face_id);
|
internal Face_Metrics get_face_metrics(Application_Links* app, Face_ID face_id);
|
||||||
|
internal Face_Advance_Map get_face_advance_map(Application_Links* app, Face_ID face_id);
|
||||||
internal Face_ID get_face_id(Application_Links* app, Buffer_ID buffer_id);
|
internal Face_ID get_face_id(Application_Links* app, Buffer_ID buffer_id);
|
||||||
internal Face_ID try_create_new_face(Application_Links* app, Face_Description* description);
|
internal Face_ID try_create_new_face(Application_Links* app, Face_Description* description);
|
||||||
internal b32 try_modify_face(Application_Links* app, Face_ID id, Face_Description* description);
|
internal b32 try_modify_face(Application_Links* app, Face_ID id, Face_Description* description);
|
||||||
|
@ -834,6 +838,7 @@ global custom_global_history_edit_group_end_type *global_history_edit_group_end
|
||||||
global custom_buffer_set_face_type *buffer_set_face = 0;
|
global custom_buffer_set_face_type *buffer_set_face = 0;
|
||||||
global custom_get_face_description_type *get_face_description = 0;
|
global custom_get_face_description_type *get_face_description = 0;
|
||||||
global custom_get_face_metrics_type *get_face_metrics = 0;
|
global custom_get_face_metrics_type *get_face_metrics = 0;
|
||||||
|
global custom_get_face_advance_map_type *get_face_advance_map = 0;
|
||||||
global custom_get_face_id_type *get_face_id = 0;
|
global custom_get_face_id_type *get_face_id = 0;
|
||||||
global custom_try_create_new_face_type *try_create_new_face = 0;
|
global custom_try_create_new_face_type *try_create_new_face = 0;
|
||||||
global custom_try_modify_face_type *try_modify_face = 0;
|
global custom_try_modify_face_type *try_modify_face = 0;
|
||||||
|
|
|
@ -141,6 +141,7 @@ api(custom) function void global_history_edit_group_end(Application_Links* app);
|
||||||
api(custom) function b32 buffer_set_face(Application_Links* app, Buffer_ID buffer_id, Face_ID id);
|
api(custom) function b32 buffer_set_face(Application_Links* app, Buffer_ID buffer_id, Face_ID id);
|
||||||
api(custom) function Face_Description get_face_description(Application_Links* app, Face_ID face_id);
|
api(custom) function Face_Description get_face_description(Application_Links* app, Face_ID face_id);
|
||||||
api(custom) function Face_Metrics get_face_metrics(Application_Links* app, Face_ID face_id);
|
api(custom) function Face_Metrics get_face_metrics(Application_Links* app, Face_ID face_id);
|
||||||
|
api(custom) function Face_Advance_Map get_face_advance_map(Application_Links* app, Face_ID face_id);
|
||||||
api(custom) function Face_ID get_face_id(Application_Links* app, Buffer_ID buffer_id);
|
api(custom) function Face_ID get_face_id(Application_Links* app, Buffer_ID buffer_id);
|
||||||
api(custom) function Face_ID try_create_new_face(Application_Links* app, Face_Description* description);
|
api(custom) function Face_ID try_create_new_face(Application_Links* app, Face_Description* description);
|
||||||
api(custom) function b32 try_modify_face(Application_Links* app, Face_ID id, Face_Description* description);
|
api(custom) function b32 try_modify_face(Application_Links* app, Face_ID id, Face_Description* description);
|
||||||
|
|
|
@ -108,8 +108,8 @@ struct Win32_Input_Chunk{
|
||||||
|
|
||||||
#include "4coder_hash_functions.cpp"
|
#include "4coder_hash_functions.cpp"
|
||||||
#include "4coder_system_allocator.cpp"
|
#include "4coder_system_allocator.cpp"
|
||||||
|
#include "4coder_codepoint_map.cpp"
|
||||||
|
|
||||||
#include "4ed_font_face.cpp"
|
|
||||||
#include "4ed_mem.cpp"
|
#include "4ed_mem.cpp"
|
||||||
#include "4ed_font_set.cpp"
|
#include "4ed_font_set.cpp"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue