cleanup around single vs. multiline text mutation controls

This commit is contained in:
Ryan Fleury
2026-07-27 14:47:32 -07:00
parent 315e0672d3
commit c8dae72968
7 changed files with 173 additions and 225 deletions
+3 -3
View File
@@ -2726,10 +2726,10 @@ rd_view_ui(Rng2F32 rect)
RD_WatchPt pt = {row->block->key, row->key, rd_id_from_watch_cell(cell)}; RD_WatchPt pt = {row->block->key, row->key, rd_id_from_watch_cell(cell)};
RD_WatchViewTextEditState *edit_state = rd_watch_view_text_edit_state_from_pt(ewv, pt); RD_WatchViewTextEditState *edit_state = rd_watch_view_text_edit_state_from_pt(ewv, pt);
String8 string = str8(edit_state->input_buffer, edit_state->input_size); String8 string = str8(edit_state->input_buffer, edit_state->input_size);
UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, evt, string, edit_state->cursor, edit_state->mark); UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, evt, string, r1u64(0, string.size), edit_state->cursor, edit_state->mark);
// rjf: copy // rjf: copy
if(op.flags & UI_TxtOpFlag_Copy && selection_tbl.min.x == selection_tbl.max.x && selection_tbl.min.y == selection_tbl.max.y) if(evt->flags & UI_EventFlag_Copy && selection_tbl.min.x == selection_tbl.max.x && selection_tbl.min.y == selection_tbl.max.y)
{ {
wm_set_clipboard_text(op.copy); wm_set_clipboard_text(op.copy);
} }
@@ -2747,7 +2747,7 @@ rd_view_ui(Rng2F32 rect)
edit_state->input_size = new_string.size; edit_state->input_size = new_string.size;
edit_state->cursor = edit_state->mark = autocomp_cursor_info->replaced_range.min+autocomplete_string.size; edit_state->cursor = edit_state->mark = autocomp_cursor_info->replaced_range.min+autocomplete_string.size;
string = str8(edit_state->input_buffer, edit_state->input_size); string = str8(edit_state->input_buffer, edit_state->input_size);
op = ui_single_line_txt_op_from_event(scratch.arena, evt, string, edit_state->cursor, edit_state->mark); op = ui_single_line_txt_op_from_event(scratch.arena, evt, string, r1u64(0, string.size), edit_state->cursor, edit_state->mark);
} }
// rjf: cancel? -> revert to initial string // rjf: cancel? -> revert to initial string
+150 -164
View File
@@ -134,7 +134,6 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
U64 *cursor = &rd_regs()->cursor; U64 *cursor = &rd_regs()->cursor;
U64 *mark = &rd_regs()->mark; U64 *mark = &rd_regs()->mark;
S64 *preferred_column = &cv->preferred_column; S64 *preferred_column = &cv->preferred_column;
B32 change = 0;
for(UI_Event *evt = 0; ui_next_event(&evt);) for(UI_Event *evt = 0; ui_next_event(&evt);)
{ {
if(evt->kind != UI_EventKind_Navigate && evt->kind != UI_EventKind_Edit && evt->kind != UI_EventKind_Text) if(evt->kind != UI_EventKind_Navigate && evt->kind != UI_EventKind_Edit && evt->kind != UI_EventKind_Text)
@@ -142,6 +141,9 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
continue; continue;
} }
B32 taken = 0; B32 taken = 0;
U64 start_cursor = *cursor;
Vec2S32 delta = evt->delta_2s32;
U64 line_count = text_patched.line_map.total_line_count;
U64 line_num = txt_line_num_from_off(&text_patched.line_map, *cursor); U64 line_num = txt_line_num_from_off(&text_patched.line_map, *cursor);
Rng1U64 line_range = txt_range_from_line_num(&text_patched.line_map, line_num); Rng1U64 line_range = txt_range_from_line_num(&text_patched.line_map, line_num);
String8 line = {0}; String8 line = {0};
@@ -149,196 +151,180 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla
line.str = push_array(scratch.arena, U8, line.size); line.str = push_array(scratch.arena, U8, line.size);
memory_map_read(&text_patched.memory_map, line_range, line.str); memory_map_read(&text_patched.memory_map, line_range, line.str);
//- rjf: try to treat event as single-line operation; map into multi-line space //- rjf: interpret event as single-line text op
U64 line_cursor = *cursor - line_range.min; UI_TxtOp single_line_op = ui_single_line_txt_op_from_event(scratch.arena, evt, line, line_range, *cursor, *mark);
U64 line_mark = *mark - line_range.min;
UI_TxtOp single_line_op = ui_single_line_txt_op_from_event(scratch.arena, evt, line, line_cursor, line_mark);
single_line_op.range = shift_1u64(single_line_op.range, line_range.min);
single_line_op.cursor += line_range.min;
single_line_op.mark += line_range.min;
//- rjf: invalid single-line op or endpoint units => try multiline //- rjf: apply single-line navigations
if(evt->delta_unit == UI_EventDeltaUnit_Whole || single_line_op.flags & UI_TxtOpFlag_Invalid) *cursor = single_line_op.cursor;
*mark = single_line_op.mark;
//- rjf: wrap lines right
if(evt->delta_unit != UI_EventDeltaUnit_Whole && delta.x > 0 && start_cursor == line_range.max && line_num+1 <= line_count)
{ {
U64 start_cursor = *cursor; Rng1U64 next_line_range = txt_range_from_line_num(&text_patched.line_map, line_num+1);
U64 line_count = text_patched.line_map.total_line_count; *cursor = next_line_range.min;
Vec2S32 delta = evt->delta_2s32; *preferred_column = 1;
}
//- rjf: wrap lines right //- rjf: wrap lines left
if(evt->delta_unit != UI_EventDeltaUnit_Whole && delta.x > 0 && *cursor == line_range.max && line_num+1 <= line_count) if(evt->delta_unit != UI_EventDeltaUnit_Whole && delta.x < 0 && start_cursor == line_range.min && line_num-1 >= 1)
{ {
Rng1U64 next_line_range = txt_range_from_line_num(&text_patched.line_map, line_num+1); Rng1U64 prev_line_range = txt_range_from_line_num(&text_patched.line_map, line_num-1);
*cursor = next_line_range.min; *cursor = prev_line_range.max;
*preferred_column = 1; *preferred_column = (S64)dim_1u64(prev_line_range)+1;
change = 1; }
taken = 1;
}
//- rjf: wrap lines left //- rjf: movement down (plain)
if(evt->delta_unit != UI_EventDeltaUnit_Whole && delta.x < 0 && *cursor == line_range.min && line_num-1 >= 1) if(evt->delta_unit == UI_EventDeltaUnit_Char && delta.y > 0 && line_num+1 <= line_count)
{ {
Rng1U64 prev_line_range = txt_range_from_line_num(&text_patched.line_map, line_num-1); Rng1U64 next_line_range = txt_range_from_line_num(&text_patched.line_map, line_num+1);
*cursor = prev_line_range.max; *cursor = next_line_range.min + *preferred_column;
*preferred_column = (S64)dim_1u64(prev_line_range)+1; *cursor = clamp_1u64(next_line_range, *cursor);
change = 1; }
taken = 1;
}
//- rjf: movement down (plain) //- rjf: movement up (plain)
if(evt->delta_unit == UI_EventDeltaUnit_Char && delta.y > 0 && line_num+1 <= line_count) if(evt->delta_unit == UI_EventDeltaUnit_Char && delta.y < 0 && line_num > 1)
{ {
Rng1U64 next_line_range = txt_range_from_line_num(&text_patched.line_map, line_num+1); Rng1U64 prev_line_range = txt_range_from_line_num(&text_patched.line_map, line_num-1);
*cursor = next_line_range.min + *preferred_column; *cursor = prev_line_range.min + *preferred_column;
*cursor = clamp_1u64(next_line_range, *cursor); *cursor = clamp_1u64(prev_line_range, *cursor);
change = 1; }
taken = 1;
}
//- rjf: movement up (plain) //- rjf: movement down (chunk)
if(evt->delta_unit == UI_EventDeltaUnit_Char && delta.y < 0 && line_num > 1) if(evt->delta_unit == UI_EventDeltaUnit_Word && delta.y > 0 && line_num+1 <= line_count)
{
for(U64 scan_line_num = line_num+1; scan_line_num <= line_count; scan_line_num += 1)
{ {
Rng1U64 prev_line_range = txt_range_from_line_num(&text_patched.line_map, line_num-1); Temp scratch = scratch_begin(&arena, 1);
*cursor = prev_line_range.min + *preferred_column; Rng1U64 line_range = txt_range_from_line_num(&text_patched.line_map, scan_line_num);
*cursor = clamp_1u64(prev_line_range, *cursor); String8 line = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, line_range);
change = 1; String8 line_without_whitespace = str8_skip_chop_whitespace(line);
taken = 1; if(line_without_whitespace.size == 0)
}
//- rjf: movement down (chunk)
if(evt->delta_unit == UI_EventDeltaUnit_Word && delta.y > 0 && line_num+1 <= line_count)
{
for(U64 scan_line_num = line_num+1; scan_line_num <= line_count; scan_line_num += 1)
{ {
Temp scratch = scratch_begin(&arena, 1); *cursor = line_range.min + (U64)(line_without_whitespace.str - line.str);
Rng1U64 line_range = txt_range_from_line_num(&text_patched.line_map, scan_line_num);
String8 line = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, line_range);
String8 line_without_whitespace = str8_skip_chop_whitespace(line);
if(line_without_whitespace.size == 0)
{
*cursor = line_range.min + (U64)(line_without_whitespace.str - line.str);
}
else if(scan_line_num == line_count)
{
*cursor = text_patched.size;
}
scratch_end(scratch);
} }
change = 1; else if(scan_line_num == line_count)
taken = 1;
}
//- rjf: movement up (chunk)
if(evt->delta_unit == UI_EventDeltaUnit_Word && delta.y < 0 && line_num > 1)
{
for(U64 scan_line_num = line_num-1; scan_line_num > 0; scan_line_num -= 1)
{ {
Temp scratch = scratch_begin(&arena, 1); *cursor = text_patched.size;
Rng1U64 line_range = txt_range_from_line_num(&text_patched.line_map, scan_line_num);
String8 line = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, line_range);
String8 line_without_whitespace = str8_skip_chop_whitespace(line);
if(line_without_whitespace.size == 0)
{
*cursor = line_range.min + (U64)(line_without_whitespace.str - line.str);
}
else if(scan_line_num == 1)
{
*cursor = 0;
}
scratch_end(scratch);
} }
change = 1; scratch_end(scratch);
taken = 1;
}
//- rjf: movement down (page)
if(evt->delta_unit == UI_EventDeltaUnit_Page && delta.y > 0)
{
U64 advance = line_count_per_page;
U64 next_line = line_num + advance;
U64 next_line_clamped = Clamp(1, next_line, text_patched.line_map.total_line_count);
Rng1U64 next_line_range = txt_range_from_line_num(&text_patched.line_map, next_line_clamped);
*cursor = next_line_range.min;
change = 1;
taken = 1;
}
//- rjf: movement up (page)
if(evt->delta_unit == UI_EventDeltaUnit_Page && delta.y < 0)
{
S64 advance = -line_count_per_page;
if(line_num < line_count_per_page)
{
advance = -(line_num - 1);
}
U64 next_line = (U64)((S64)line_num + line_count_per_page);
U64 next_line_clamped = Clamp(1, next_line, text_patched.line_map.total_line_count);
Rng1U64 next_line_range = txt_range_from_line_num(&text_patched.line_map, next_line_clamped);
*cursor = next_line_range.min;
change = 1;
taken = 1;
}
//- rjf: movement to endpoint (+)
if(evt->delta_unit == UI_EventDeltaUnit_Whole && (delta.y > 0 || delta.x > 0))
{
*cursor = text_patched.size;
change = 1;
taken = 1;
}
//- rjf: movement to endpoint (-)
if(evt->delta_unit == UI_EventDeltaUnit_Whole && (delta.y < 0 || delta.x < 0))
{
*cursor = 0;
change = 1;
taken = 1;
}
//- rjf: stick mark to cursor, when we don't want to keep it in the same spot
if(!(evt->flags & UI_EventFlag_KeepMark))
{
*mark = *cursor;
}
//- rjf: push patch if we have one
if(evt->flags & UI_EventFlag_Delete)
{
Rng1U64 range = r1u64(start_cursor, *cursor);
txt_patch_list_push_new(cv->patch_arena, &cv->patches, range, single_line_op.replace);
text_patched = txt_patched_from_info_data_patches(scratch.arena, text_info, text_data, &cv->patches);
*cursor = *mark = range.min;
} }
} }
//- rjf: valid single-line op => do single-line op //- rjf: movement up (chunk)
else if(evt->delta_unit == UI_EventDeltaUnit_Word && delta.y < 0 && line_num > 1)
{ {
if(single_line_op.range.min != single_line_op.range.max || single_line_op.replace.size != 0) for(U64 scan_line_num = line_num-1; scan_line_num > 0; scan_line_num -= 1)
{ {
txt_patch_list_push_new(cv->patch_arena, &cv->patches, single_line_op.range, single_line_op.replace); Temp scratch = scratch_begin(&arena, 1);
text_patched = txt_patched_from_info_data_patches(scratch.arena, text_info, text_data, &cv->patches); Rng1U64 line_range = txt_range_from_line_num(&text_patched.line_map, scan_line_num);
String8 line = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, line_range);
String8 line_without_whitespace = str8_skip_chop_whitespace(line);
if(line_without_whitespace.size == 0)
{
*cursor = line_range.min + (U64)(line_without_whitespace.str - line.str);
}
else if(scan_line_num == 1)
{
*cursor = 0;
}
scratch_end(scratch);
} }
*cursor = single_line_op.cursor;
*mark = single_line_op.mark;
U64 line_num = txt_line_num_from_off(&text_patched.line_map, *cursor);
Rng1U64 line_range = txt_range_from_line_num(&text_patched.line_map, line_num);
*preferred_column = (*cursor - line_range.min);
change = 1;
taken = 1;
} }
//- rjf: copy //- rjf: movement down (page)
if(evt->delta_unit == UI_EventDeltaUnit_Page && delta.y > 0)
{
U64 advance = line_count_per_page;
U64 next_line = line_num + advance;
U64 next_line_clamped = Clamp(1, next_line, text_patched.line_map.total_line_count);
Rng1U64 next_line_range = txt_range_from_line_num(&text_patched.line_map, next_line_clamped);
*cursor = next_line_range.min;
}
//- rjf: movement up (page)
if(evt->delta_unit == UI_EventDeltaUnit_Page && delta.y < 0)
{
S64 advance = -line_count_per_page;
if(line_num < line_count_per_page)
{
advance = -(line_num - 1);
}
U64 next_line = (U64)((S64)line_num + line_count_per_page);
U64 next_line_clamped = Clamp(1, next_line, text_patched.line_map.total_line_count);
Rng1U64 next_line_range = txt_range_from_line_num(&text_patched.line_map, next_line_clamped);
*cursor = next_line_range.min;
}
//- rjf: movement to endpoint (+)
if(evt->delta_unit == UI_EventDeltaUnit_Whole && (delta.y > 0 || delta.x > 0))
{
*cursor = text_patched.size;
}
//- rjf: movement to endpoint (-)
if(evt->delta_unit == UI_EventDeltaUnit_Whole && (delta.y < 0 || delta.x < 0))
{
*cursor = 0;
}
//- rjf: get replaced-range; adjust based on multi-line logic
Rng1U64 replaced_range = single_line_op.range;
if(*cursor != single_line_op.cursor && (evt->flags & UI_EventFlag_Delete || evt->string.size != 0))
{
replaced_range = r1u64(*mark, *cursor);
}
//- rjf: in some cases, we want to pick a selection side based on the delta
if(*cursor != *mark && evt->flags & UI_EventFlag_PickSelectSide)
{
if(delta.x < 0 || delta.y < 0)
{
*cursor = *mark = Min(*cursor, *mark);
}
else if(delta.x > 0 || delta.y > 0)
{
*cursor = *mark = Max(*cursor, *mark);
}
}
//- rjf: do copy if needed
if(evt->flags & UI_EventFlag_Copy) if(evt->flags & UI_EventFlag_Copy)
{ {
String8 text = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, r1u64(*cursor, *mark)); String8 text = memory_map_data_from_range(scratch.arena, &text_patched.memory_map, r1u64(*cursor, *mark));
wm_set_clipboard_text(text); wm_set_clipboard_text(text);
taken = 1; }
//- rjf: stick mark to cursor, when we don't want to keep it in the same spot
if(!(evt->flags & UI_EventFlag_KeepMark))
{
*mark = *cursor;
}
//- rjf: push patch if we have one
if(replaced_range.max != replaced_range.min || single_line_op.replace.size != 0)
{
txt_patch_list_push_new(cv->patch_arena, &cv->patches, replaced_range, single_line_op.replace);
text_patched = txt_patched_from_info_data_patches(scratch.arena, text_info, text_data, &cv->patches);
*cursor = *mark = replaced_range.min + single_line_op.replace.size;
U64 line_num = txt_line_num_from_off(&text_patched.line_map, *cursor);
Rng1U64 line_range = txt_range_from_line_num(&text_patched.line_map, line_num);
*preferred_column = (*cursor - line_range.min);
} }
//- rjf: consume //- rjf: consume
if(taken) ui_eat_event(evt);
//- rjf: changed cursor -> snap in X
if(*cursor != start_cursor)
{ {
ui_eat_event(evt); snap[Axis2_X] = 1;
}
//- rjf: changed cursor line -> snap in Y
if(*cursor < line_range.min || line_range.max < *cursor)
{
snap[Axis2_Y] = 1;
} }
} }
} }
+4 -4
View File
@@ -2860,7 +2860,7 @@ rd_code_slice(RD_CodeSliceParams *params, U64 *cursor, U64 *mark, S64 *preferred
if(line_range.min <= *cursor && *cursor <= line_range.max) if(line_range.min <= *cursor && *cursor <= line_range.max)
{ {
Vec2F32 advance = fnt_dim_from_tag_size_string(line_box->font, line_box->font_size, 0, params->tab_size, str8_prefix(line_string, *cursor - line_range.min)); Vec2F32 advance = fnt_dim_from_tag_size_string(line_box->font, line_box->font_size, 0, params->tab_size, str8_prefix(line_string, *cursor - line_range.min));
F32 cursor_y = line_box->rect.y0-params->font_size*0.125f; F32 cursor_y = text_container_box->rect.y0 + line_idx*params->line_height_px - params->font_size*0.125f;
F32 cursor_y__animated = ui_anim(ui_key_from_stringf(text_container_box->key, "cursor_y_px"), cursor_y); F32 cursor_y__animated = ui_anim(ui_key_from_stringf(text_container_box->key, "cursor_y_px"), cursor_y);
F32 cursor_off_pixels = advance.x; F32 cursor_off_pixels = advance.x;
F32 cursor_off_pixels__animated = ui_anim(ui_key_from_stringf(text_container_box->key, "cursor_off_px"), cursor_off_pixels); F32 cursor_off_pixels__animated = ui_anim(ui_key_from_stringf(text_container_box->key, "cursor_off_px"), cursor_off_pixels);
@@ -3885,7 +3885,7 @@ rd_cell(RD_CellParams *params, String8 string)
} }
// rjf: map this action to an op // rjf: map this action to an op
UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, evt, edit_string, params->cursor[0], params->mark[0]); UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, evt, edit_string, r1u64(0, edit_string.size), params->cursor[0], params->mark[0]);
// rjf: any valid *additive* op & autocomplete hint? -> perform autocomplete first, then re-compute op // rjf: any valid *additive* op & autocomplete hint? -> perform autocomplete first, then re-compute op
if(!(evt->flags & UI_EventFlag_Delete) && autocomplete_hint_string.size != 0) if(!(evt->flags & UI_EventFlag_Delete) && autocomplete_hint_string.size != 0)
@@ -3899,7 +3899,7 @@ rd_cell(RD_CellParams *params, String8 string)
params->edit_string_size_out[0] = new_string.size; params->edit_string_size_out[0] = new_string.size;
params->cursor[0] = params->mark[0] = autocomp_cursor_info->replaced_range.min+autocomplete_hint_string.size; params->cursor[0] = params->mark[0] = autocomp_cursor_info->replaced_range.min+autocomplete_hint_string.size;
edit_string = str8(params->edit_buffer, params->edit_string_size_out[0]); edit_string = str8(params->edit_buffer, params->edit_string_size_out[0]);
op = ui_single_line_txt_op_from_event(scratch.arena, evt, edit_string, params->cursor[0], params->mark[0]); op = ui_single_line_txt_op_from_event(scratch.arena, evt, edit_string, r1u64(0, edit_string.size), params->cursor[0], params->mark[0]);
MemoryZeroStruct(&autocomplete_hint_string); MemoryZeroStruct(&autocomplete_hint_string);
} }
@@ -3913,7 +3913,7 @@ rd_cell(RD_CellParams *params, String8 string)
} }
// rjf: perform copy // rjf: perform copy
if(op.flags & UI_TxtOpFlag_Copy) if(evt->flags & UI_EventFlag_Copy)
{ {
wm_set_clipboard_text(op.copy); wm_set_clipboard_text(op.copy);
} }
+2 -2
View File
@@ -238,7 +238,7 @@ ui_line_edit(U64 *cursor, U64 *mark, U8 *edit_buffer, U64 edit_buffer_size, U64
} }
// rjf: map this action to an op // rjf: map this action to an op
UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, evt, edit_string, *cursor, *mark); UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, evt, edit_string, r1u64(0, edit_string.size), *cursor, *mark);
// rjf: perform replace range // rjf: perform replace range
if(op.range.min != op.range.max || op.replace.size != 0) if(op.range.min != op.range.max || op.replace.size != 0)
@@ -250,7 +250,7 @@ ui_line_edit(U64 *cursor, U64 *mark, U8 *edit_buffer, U64 edit_buffer_size, U64
} }
// rjf: perform copy // rjf: perform copy
if(op.flags & UI_TxtOpFlag_Copy) if(evt->flags & UI_EventFlag_Copy)
{ {
wm_set_clipboard_text(op.copy); wm_set_clipboard_text(op.copy);
} }
+8 -38
View File
@@ -142,14 +142,13 @@ ui_scanned_column_from_column(String8 string, S64 start_column, Side side)
} }
internal UI_TxtOp internal UI_TxtOp
ui_single_line_txt_op_from_event(Arena *arena, UI_Event *event, String8 string, U64 cursor, U64 mark) ui_single_line_txt_op_from_event(Arena *arena, UI_Event *event, String8 string, Rng1U64 cursor_range, U64 cursor, U64 mark)
{ {
U64 next_cursor = cursor; U64 next_cursor = cursor;
U64 next_mark = mark; U64 next_mark = mark;
Rng1U64 range = {0}; Rng1U64 range = {0};
String8 replace = {0}; String8 replace = {0};
String8 copy = {0}; String8 copy = {0};
UI_TxtOpFlags flags = 0;
Vec2S32 delta = event->delta_2s32; Vec2S32 delta = event->delta_2s32;
Vec2S32 original_delta = delta; Vec2S32 original_delta = delta;
@@ -164,7 +163,7 @@ ui_single_line_txt_op_from_event(Arena *arena, UI_Event *event, String8 string,
}break; }break;
case UI_EventDeltaUnit_Word: case UI_EventDeltaUnit_Word:
{ {
delta.x = (S32)(ui_scanned_column_from_column(string, (S64)cursor+1, delta.x > 0 ? Side_Max : Side_Min)-1 - (S64)cursor); delta.x = (S32)(ui_scanned_column_from_column(string, (S64)(cursor - cursor_range.min)+1, delta.x > 0 ? Side_Max : Side_Min)-1 - (S64)(cursor - cursor_range.min));
}break; }break;
case UI_EventDeltaUnit_Line: case UI_EventDeltaUnit_Line:
case UI_EventDeltaUnit_Whole: case UI_EventDeltaUnit_Whole:
@@ -179,8 +178,8 @@ ui_single_line_txt_op_from_event(Arena *arena, UI_Event *event, String8 string,
break; break;
} }
} }
U64 home_dest_off = (cursor == first_nonwhitespace_off) ? 0 : first_nonwhitespace_off; U64 home_dest_off = (cursor - cursor_range.min == first_nonwhitespace_off) ? 0 : first_nonwhitespace_off;
delta.x = (delta.x > 0) ? ((S64)string.size - (S64)cursor) : ((S64)home_dest_off - (S64)cursor); delta.x = (delta.x > 0) ? ((S64)string.size - (S64)(cursor - cursor_range.min)) : ((S64)home_dest_off - (S64)(cursor - cursor_range.min));
}break; }break;
} }
@@ -191,26 +190,17 @@ ui_single_line_txt_op_from_event(Arena *arena, UI_Event *event, String8 string,
} }
//- rjf: form next cursor //- rjf: form next cursor
B32 cursor_out_of_bounds = 0;
if(cursor == mark || !(event->flags & UI_EventFlag_ZeroDeltaOnSelect)) if(cursor == mark || !(event->flags & UI_EventFlag_ZeroDeltaOnSelect))
{ {
if(delta.x < -(S32)next_cursor) delta.x = Max(delta.x, -(S32)(next_cursor - cursor_range.min));
{ delta.x = Min(delta.x, +(S32)(cursor_range.max - next_cursor));
delta.x = -(S32)next_cursor;
cursor_out_of_bounds = 1;
}
if(cursor + delta.x > string.size)
{
delta.x = (S32)((S64)string.size - (S64)cursor);
cursor_out_of_bounds = 1;
}
next_cursor += delta.x; next_cursor += delta.x;
} }
//- rjf: cap at line //- rjf: cap at line
if(event->flags & UI_EventFlag_CapAtLine) if(event->flags & UI_EventFlag_CapAtLine)
{ {
next_cursor = Clamp(0, next_cursor, string.size); next_cursor = Clamp(cursor_range.min, next_cursor, cursor_range.max+1);
} }
//- rjf: in some cases, we want to pick a selection side based on the delta //- rjf: in some cases, we want to pick a selection side based on the delta
@@ -229,16 +219,7 @@ ui_single_line_txt_op_from_event(Arena *arena, UI_Event *event, String8 string,
//- rjf: copying //- rjf: copying
if(event->flags & UI_EventFlag_Copy) if(event->flags & UI_EventFlag_Copy)
{ {
copy = str8_substr(string, r1u64(cursor, mark)); copy = str8_substr(string, r1u64(cursor - cursor_range.min, mark - cursor_range.min));
flags |= UI_TxtOpFlag_Copy;
}
//- rjf: pasting
if(event->flags & UI_EventFlag_Paste)
{
range = r1u64(cursor, mark);
replace = wm_get_clipboard_text(arena);
next_cursor = next_mark = cursor + replace.size;
} }
//- rjf: deletion //- rjf: deletion
@@ -264,20 +245,9 @@ ui_single_line_txt_op_from_event(Arena *arena, UI_Event *event, String8 string,
next_cursor = next_mark = range.min + event->string.size; next_cursor = next_mark = range.min + event->string.size;
} }
//- rjf: determine if this event should be taken, based on bounds of cursor
{
if(next_cursor > string.size+replace.size || event->delta_2s32.y != 0 || cursor_out_of_bounds)
{
flags |= UI_TxtOpFlag_Invalid;
}
next_cursor = Clamp(0, next_cursor, string.size+replace.size);
next_mark = Clamp(0, next_mark, string.size+replace.size);
}
//- rjf: build+fill //- rjf: build+fill
UI_TxtOp op = {0}; UI_TxtOp op = {0};
{ {
op.flags = flags;
op.replace = replace; op.replace = replace;
op.copy = copy; op.copy = copy;
op.range = range; op.range = range;
+1 -9
View File
@@ -171,17 +171,9 @@ struct UI_EventList
//////////////////////////////// ////////////////////////////////
//~ rjf: Textual Operations //~ rjf: Textual Operations
typedef U32 UI_TxtOpFlags;
enum
{
UI_TxtOpFlag_Invalid = (1<<0),
UI_TxtOpFlag_Copy = (1<<1),
};
typedef struct UI_TxtOp UI_TxtOp; typedef struct UI_TxtOp UI_TxtOp;
struct UI_TxtOp struct UI_TxtOp
{ {
UI_TxtOpFlags flags;
String8 replace; String8 replace;
String8 copy; String8 copy;
Rng1U64 range; Rng1U64 range;
@@ -776,7 +768,7 @@ internal void ui_eat_event_node(UI_EventList *list, UI_EventNode *node);
internal B32 ui_char_is_scan_boundary(U8 c); internal B32 ui_char_is_scan_boundary(U8 c);
internal S64 ui_scanned_column_from_column(String8 string, S64 start_column, Side side); internal S64 ui_scanned_column_from_column(String8 string, S64 start_column, Side side);
internal UI_TxtOp ui_single_line_txt_op_from_event(Arena *arena, UI_Event *event, String8 string, U64 cursor, U64 mark); internal UI_TxtOp ui_single_line_txt_op_from_event(Arena *arena, UI_Event *event, String8 string, Rng1U64 cursor_range, U64 cursor, U64 mark);
internal String8 ui_push_string_replace_range(Arena *arena, String8 string, Rng1U64 range, String8 replace); internal String8 ui_push_string_replace_range(Arena *arena, String8 string, Rng1U64 range, String8 replace);
//////////////////////////////// ////////////////////////////////
@@ -506,7 +506,7 @@ w32_wm_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case WM_CHAR: case WM_CHAR:
{ {
U32 character = wParam; U32 character = wParam;
if(character >= 10 && character != 127) if((character >= 32 && character != 127) || character == '\n' || character == '\r')
{ {
WM_Event *event = w32_wm_push_event(WM_EventKind_Text, window); WM_Event *event = w32_wm_push_event(WM_EventKind_Text, window);
if(lParam & bit29) if(lParam & bit29)