vertical movement and undo/redo
This commit is contained in:
parent
0f5d7d6125
commit
7be01af7bf
@ -6,7 +6,7 @@
|
|||||||
NAME :: "mexplore";
|
NAME :: "mexplore";
|
||||||
VERSION :: "0.1";
|
VERSION :: "0.1";
|
||||||
JAI_VERSION :: "beta 0.2.016, built on 19 July 2025";
|
JAI_VERSION :: "beta 0.2.016, built on 19 July 2025";
|
||||||
RELEASE_DATE :: "6 August 2025, 21:33:37";
|
RELEASE_DATE :: "30 August 2025, 17:16:50";
|
||||||
GIT_BRANCH :: "main";
|
GIT_BRANCH :: "main";
|
||||||
GIT_REVISION :: "4744f67e2e182828d1a3de921c4a5b6194a2a24d";
|
GIT_REVISION :: "0f5d7d612591fbcf39e818c9076d28dc422ca635";
|
||||||
DEBUG :: true;
|
DEBUG :: true;
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
34
src/main.jai
34
src/main.jai
@ -89,12 +89,39 @@ main :: () {
|
|||||||
if event.key.key == {
|
if event.key.key == {
|
||||||
case SDLK_ESCAPE;
|
case SDLK_ESCAPE;
|
||||||
running = false;
|
running = false;
|
||||||
|
|
||||||
|
case SDLK_Z;
|
||||||
|
if event.key.mod == SDL_KMOD_LCTRL | SDL_KMOD_LSHIFT {
|
||||||
|
log("REDO!");
|
||||||
|
transition.char = STB_TEXTEDIT_K_REDO;
|
||||||
|
} else if event.key.mod == SDL_KMOD_LCTRL {
|
||||||
|
log("UNDO!");
|
||||||
|
transition.char = STB_TEXTEDIT_K_UNDO;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDLK_UP;
|
||||||
|
if event.key.mod == SDL_KMOD_LSHIFT {
|
||||||
|
transition.char = STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT;
|
||||||
|
} else {
|
||||||
|
log("Moving up");
|
||||||
|
transition.char = STB_TEXTEDIT_K_UP;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDLK_DOWN;
|
||||||
|
if event.key.mod == SDL_KMOD_LSHIFT {
|
||||||
|
transition.char = STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT;
|
||||||
|
} else {
|
||||||
|
log("Moving down");
|
||||||
|
transition.char = STB_TEXTEDIT_K_DOWN;
|
||||||
|
}
|
||||||
|
|
||||||
case SDLK_LEFT;
|
case SDLK_LEFT;
|
||||||
transition.left_arrow_down = true;
|
transition.left_arrow_down = true;
|
||||||
if event.key.mod == SDL_KMOD_LCTRL {
|
if event.key.mod == SDL_KMOD_LCTRL {
|
||||||
log("Moving word to the left!");
|
log("Moving word to the left!");
|
||||||
transition.char = STB_TEXTEDIT_K_WORDLEFT;
|
transition.char = STB_TEXTEDIT_K_WORDLEFT;
|
||||||
|
} else if event.key.mod == SDL_KMOD_LSHIFT {
|
||||||
|
transition.char = STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT;
|
||||||
} else {
|
} else {
|
||||||
log("Moving to the left");
|
log("Moving to the left");
|
||||||
transition.char = STB_TEXTEDIT_K_LEFT;
|
transition.char = STB_TEXTEDIT_K_LEFT;
|
||||||
@ -105,6 +132,8 @@ main :: () {
|
|||||||
if event.key.mod == SDL_KMOD_LCTRL {
|
if event.key.mod == SDL_KMOD_LCTRL {
|
||||||
log("Moving word to the right!");
|
log("Moving word to the right!");
|
||||||
transition.char = STB_TEXTEDIT_K_WORDRIGHT;
|
transition.char = STB_TEXTEDIT_K_WORDRIGHT;
|
||||||
|
} else if event.key.mod == SDL_KMOD_LSHIFT {
|
||||||
|
transition.char = STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT;
|
||||||
} else {
|
} else {
|
||||||
log("Moving to the right");
|
log("Moving to the right");
|
||||||
transition.char = STB_TEXTEDIT_K_RIGHT;
|
transition.char = STB_TEXTEDIT_K_RIGHT;
|
||||||
@ -112,9 +141,8 @@ main :: () {
|
|||||||
|
|
||||||
case SDLK_BACKSPACE;
|
case SDLK_BACKSPACE;
|
||||||
transition.backspace = true;
|
transition.backspace = true;
|
||||||
if event.key.mod == SDL_KMOD_LCTRL {
|
if event.key.mod == SDL_KMOD_LSHIFT {
|
||||||
// log("Moving word to the right!");
|
transition.char = STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT;
|
||||||
// transition.char = STB_TEXTEDIT_K_WORDRIGHT;
|
|
||||||
} else {
|
} else {
|
||||||
transition.char = STB_TEXTEDIT_K_BACKSPACE;
|
transition.char = STB_TEXTEDIT_K_BACKSPACE;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -371,8 +371,6 @@ STB_TEXTEDIT_LAYOUTROW :: (row: *StbTexteditRow, obj: *STB_TEXTEDIT_STRING, n: s
|
|||||||
}
|
}
|
||||||
|
|
||||||
STB_TEXTEDIT_GETWIDTH :: (obj: *STB_TEXTEDIT_STRING, n: s32, i: s32) -> float {
|
STB_TEXTEDIT_GETWIDTH :: (obj: *STB_TEXTEDIT_STRING, n: s32, i: s32) -> float {
|
||||||
assert(i >= n, "n is where the line starts, and i the character we want to size. So i must be >= n");
|
|
||||||
|
|
||||||
textp : *u32 = obj.text.data;
|
textp : *u32 = obj.text.data;
|
||||||
Codepoints : *u32 = textp + n;
|
Codepoints : *u32 = textp + n;
|
||||||
CodepointCount : u64 = xx (obj.text.count - (Codepoints - textp));
|
CodepointCount : u64 = xx (obj.text.count - (Codepoints - textp));
|
||||||
@ -941,42 +939,42 @@ while retry := true {
|
|||||||
state.cursor = state.select_end;
|
state.cursor = state.select_end;
|
||||||
state.has_preferred_x = 0;
|
state.has_preferred_x = 0;
|
||||||
|
|
||||||
// #if #exists(STB_TEXTEDIT_MOVEWORDLEFT) {
|
//#if #exists(STB_TEXTEDIT_MOVEWORDLEFT) {
|
||||||
// case STB_TEXTEDIT_K_WORDLEFT;
|
case STB_TEXTEDIT_K_WORDLEFT;
|
||||||
// if (STB_TEXT_HAS_SELECTION(state))
|
if (STB_TEXT_HAS_SELECTION(state))
|
||||||
// stb_textedit_move_to_first(state);
|
stb_textedit_move_to_first(state);
|
||||||
// else {
|
else {
|
||||||
// state.cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state.cursor);
|
state.cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state.cursor);
|
||||||
// stb_textedit_clamp( str, state );
|
stb_textedit_clamp( str, state );
|
||||||
// }
|
}
|
||||||
|
|
||||||
// case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT;
|
case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT;
|
||||||
// if !STB_TEXT_HAS_SELECTION( state )
|
if !STB_TEXT_HAS_SELECTION( state )
|
||||||
// stb_textedit_prep_selection_at_cursor(state);
|
stb_textedit_prep_selection_at_cursor(state);
|
||||||
|
|
||||||
// state.cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state.cursor);
|
state.cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state.cursor);
|
||||||
// state.select_end = state.cursor;
|
state.select_end = state.cursor;
|
||||||
|
|
||||||
// stb_textedit_clamp( str, state );
|
stb_textedit_clamp( str, state );
|
||||||
// }
|
//}
|
||||||
|
|
||||||
// #if #exists(STB_TEXTEDIT_MOVEWORDRIGHT) {
|
// #if #exists(STB_TEXTEDIT_MOVEWORDRIGHT) {
|
||||||
// case STB_TEXTEDIT_K_WORDRIGHT;
|
case STB_TEXTEDIT_K_WORDRIGHT;
|
||||||
// if (STB_TEXT_HAS_SELECTION(state)) {
|
if (STB_TEXT_HAS_SELECTION(state)) {
|
||||||
// stb_textedit_move_to_last(str, state);
|
stb_textedit_move_to_last(str, state);
|
||||||
// } else {
|
} else {
|
||||||
// state.cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state.cursor);
|
state.cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state.cursor);
|
||||||
// stb_textedit_clamp(str, state);
|
stb_textedit_clamp(str, state);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT;
|
case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT;
|
||||||
// if !STB_TEXT_HAS_SELECTION(state)
|
if !STB_TEXT_HAS_SELECTION(state)
|
||||||
// stb_textedit_prep_selection_at_cursor(state);
|
stb_textedit_prep_selection_at_cursor(state);
|
||||||
|
|
||||||
// state.cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state.cursor);
|
state.cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state.cursor);
|
||||||
// state.select_end = state.cursor;
|
state.select_end = state.cursor;
|
||||||
|
|
||||||
// stb_textedit_clamp( str, state );
|
stb_textedit_clamp( str, state );
|
||||||
// }
|
// }
|
||||||
|
|
||||||
case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT;
|
case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT;
|
||||||
|
|||||||
330
src/text.jai
330
src/text.jai
@ -502,7 +502,52 @@ ShapeText :: (font: *Font, Cursor: *kbts_cursor, Codepoints: *u32, CodepointCoun
|
|||||||
return size, max_descent;
|
return size, max_descent;
|
||||||
}
|
}
|
||||||
|
|
||||||
SegmentText :: (font: *Font, Codepoints: *u32, CodepointCount: u64) -> Vector2, float, s32 {
|
next_segment_size :: (font : *Font, text : []u32, n : s32, max_width : float = 0.0, segment_type : kbts_break_flags) -> Vector2, float, s32, kbts_break_flags {
|
||||||
|
textp : *u32 = text.data;
|
||||||
|
Codepoints : *u32 = textp + n;
|
||||||
|
CodepointCount : u64 = xx (text.count - (Codepoints - textp));
|
||||||
|
|
||||||
|
Cursor : kbts_cursor;
|
||||||
|
Direction : kbts_direction = .NONE;
|
||||||
|
Script : kbts_script = .DONT_KNOW;
|
||||||
|
RunStart : u64 = 0;
|
||||||
|
BreakState : kbts_break_state;
|
||||||
|
kbts_BeginBreak(*BreakState, .NONE, .NORMAL);
|
||||||
|
|
||||||
|
CodepointIndex : u64;
|
||||||
|
while CodepointIndex < xx CodepointCount {
|
||||||
|
kbts_BreakAddCodepoint(*BreakState, Codepoints[CodepointIndex], 1, xx ((CodepointIndex + 1) == xx CodepointCount));
|
||||||
|
Break : kbts_break;
|
||||||
|
while kbts_Break(*BreakState, *Break) {
|
||||||
|
|
||||||
|
if Break.Flags & .DIRECTION {
|
||||||
|
Direction = Break.Direction;
|
||||||
|
if(!Cursor.Direction) Cursor = kbts_Cursor(BreakState.MainDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
if Break.Flags & .SCRIPT {
|
||||||
|
Script = Break.Script;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Break.Position > RunStart) && (Break.Flags & segment_type) {
|
||||||
|
RunLength : u64 = Break.Position - RunStart;
|
||||||
|
size, max_descent := ShapeText(font, *Cursor, Codepoints + RunStart, RunLength, BreakState.MainDirection, Direction, Script);
|
||||||
|
|
||||||
|
return size, max_descent, xx Break.Position, Break.Flags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CodepointIndex += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{}, 0, 0, xx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
next_word_size :: (font : *Font, text : []u32, n : s32, max_width : float = 0.0) -> Vector2, float, s32 {
|
||||||
|
textp : *u32 = text.data;
|
||||||
|
Codepoints : *u32 = textp + n;
|
||||||
|
CodepointCount : u64 = xx (text.count - (Codepoints - textp));
|
||||||
|
|
||||||
Cursor : kbts_cursor;
|
Cursor : kbts_cursor;
|
||||||
Direction : kbts_direction = .NONE;
|
Direction : kbts_direction = .NONE;
|
||||||
Script : kbts_script = .DONT_KNOW;
|
Script : kbts_script = .DONT_KNOW;
|
||||||
@ -519,20 +564,6 @@ SegmentText :: (font: *Font, Codepoints: *u32, CodepointCount: u64) -> Vector2,
|
|||||||
Break : kbts_break;
|
Break : kbts_break;
|
||||||
while kbts_Break(*BreakState, *Break) {
|
while kbts_Break(*BreakState, *Break) {
|
||||||
|
|
||||||
// if (Break.Position > RunStart) && (Break.Flags & (.DIRECTION | .SCRIPT | .LINE_HARD)) {
|
|
||||||
// RunLength : u64 = Break.Position - RunStart;
|
|
||||||
// size, max_descent := ShapeText(font, *Cursor, Codepoints + RunStart, RunLength, BreakState.MainDirection, Direction, Script);
|
|
||||||
|
|
||||||
// return size, max_descent, Break.Position;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (Break.Position > RunStart) && (Break.Flags & (.DIRECTION | .SCRIPT | .LINE_HARD)) {
|
|
||||||
// RunLength : u64 = Break.Position - RunStart;
|
|
||||||
// size, max_descent := ShapeText(font, *Cursor, Codepoints + RunStart, RunLength, BreakState.MainDirection, Direction, Script);
|
|
||||||
|
|
||||||
// return size, max_descent, xx CodepointIndex;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if Break.Flags & .DIRECTION {
|
if Break.Flags & .DIRECTION {
|
||||||
Direction = Break.Direction;
|
Direction = Break.Direction;
|
||||||
if(!Cursor.Direction) Cursor = kbts_Cursor(BreakState.MainDirection);
|
if(!Cursor.Direction) Cursor = kbts_Cursor(BreakState.MainDirection);
|
||||||
@ -546,21 +577,8 @@ SegmentText :: (font: *Font, Codepoints: *u32, CodepointCount: u64) -> Vector2,
|
|||||||
RunLength : u64 = Break.Position - RunStart;
|
RunLength : u64 = Break.Position - RunStart;
|
||||||
size, max_descent := ShapeText(font, *Cursor, Codepoints + RunStart, RunLength, BreakState.MainDirection, Direction, Script);
|
size, max_descent := ShapeText(font, *Cursor, Codepoints + RunStart, RunLength, BreakState.MainDirection, Direction, Script);
|
||||||
|
|
||||||
//if max_width > 0.0 && size.x + word_size.x > max_width {
|
return size, max_descent, xx Break.Position;
|
||||||
return size, max_descent, xx Break.Position;
|
|
||||||
//}
|
|
||||||
|
|
||||||
// size.x += word_size.x;
|
|
||||||
// size.y = max(word_size.y);
|
|
||||||
|
|
||||||
// max_descent = max(max_descent, word_max_descent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (Break.Position > RunStart) && Break.Flags & .LINE_HARD {
|
|
||||||
// RunLength : u64 = Break.Position - RunStart;
|
|
||||||
// word_size, word_max_descent := ShapeText(font, *Cursor, Codepoints + RunStart, RunLength, BreakState.MainDirection, Direction, Script);
|
|
||||||
// return size, max_descent, Break.Position;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CodepointIndex += 1;
|
CodepointIndex += 1;
|
||||||
@ -569,81 +587,6 @@ SegmentText :: (font: *Font, Codepoints: *u32, CodepointCount: u64) -> Vector2,
|
|||||||
return .{}, 0, 0;
|
return .{}, 0, 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get_next_row :: (font: *Font, max_width: float, text: string, index: s32, length: s32) -> s32 {
|
|
||||||
// Cursor : kbts_cursor;
|
|
||||||
// Direction : kbts_direction = xx kbts_direction_enum.KBTS_DIRECTION_NONE;
|
|
||||||
// Script : kbts_script = xx kbts_script_enum.KBTS_SCRIPT_DONT_KNOW;
|
|
||||||
// RunStart : u64;
|
|
||||||
// BreakState : kbts_break_state;
|
|
||||||
// kbts_BeginBreak(*BreakState, xx kbts_direction_enum.KBTS_DIRECTION_NONE, xx kbts_japanese_line_break_style_enum.KBTS_JAPANESE_LINE_BREAK_STYLE_NORMAL);
|
|
||||||
|
|
||||||
// text_utf32 : [..]u32;
|
|
||||||
// defer array_free(text_utf32);
|
|
||||||
|
|
||||||
// StringAt : u64;
|
|
||||||
// while StringAt < xx text.count {
|
|
||||||
// Decode : kbts_decode = kbts_DecodeUtf8(text.data, xx text.count - StringAt);
|
|
||||||
// StringAt += Decode.SourceCharactersConsumed;
|
|
||||||
// if Decode.Valid {
|
|
||||||
// array_add(*text_utf32, Decode.Codepoint);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// width : float;
|
|
||||||
|
|
||||||
// CodepointIndex : u64;
|
|
||||||
// while CodepointIndex < xx text_utf32.count {
|
|
||||||
|
|
||||||
// kbts_BreakAddCodepoint(*BreakState, text_utf32[CodepointIndex], 1, xx ((CodepointIndex + 1) == xx text_utf32.count));
|
|
||||||
// Break : kbts_break;
|
|
||||||
// while kbts_Break(*BreakState, *Break) {
|
|
||||||
// if (Break.Position > RunStart) && (Break.Flags & xx kbts_break_flags_enum.KBTS_BREAK_FLAG_DIRECTION | xx kbts_break_flags_enum.KBTS_BREAK_FLAG_SCRIPT | xx kbts_break_flags_enum.KBTS_BREAK_FLAG_LINE_HARD | xx kbts_break_flags_enum.KBTS_BREAK_FLAG_GRAPHEME) {
|
|
||||||
// RunLength : u64 = Break.Position - RunStart;
|
|
||||||
|
|
||||||
// // Glyph : kbts_glyph = kbts_CodepointToGlyph(*font.kb, Decode.Codepoint);
|
|
||||||
|
|
||||||
// // // Shape
|
|
||||||
// // GlyphCapacity : u32 = Length;
|
|
||||||
// // kbts_shape_state *State = kbts_CreateShapeState(*font.kb);
|
|
||||||
// // // A shape_config is immutable once created. You can freely share/hash it, etc.
|
|
||||||
// // Config : kbts_shape_config = kbts_ShapeConfig(*font.kb, Script, xx kbts_language_enum.KBTS_LANGUAGE_DONT_KNOW);
|
|
||||||
|
|
||||||
// // while kbts_Shape(State, *Config, Direction, Direction, Glyphs, *GlyphCount, GlyphCapacity) {
|
|
||||||
// // Glyphs = realloc(Glyphs, sizeof(kbts_glyph) * State.RequiredGlyphCapacity);
|
|
||||||
// // GlyphCapacity = State.RequiredGlyphCapacity;
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // // Get final positions
|
|
||||||
// // Cursor : kbts_cursor = kbts_Cursor(Direction);
|
|
||||||
// // GlyphIndex : u64;
|
|
||||||
|
|
||||||
// // while GlyphIndex < GlyphCount {
|
|
||||||
// // X : s32;
|
|
||||||
// // Y : s32;
|
|
||||||
// // kbts_PositionGlyph(*Cursor, *Glyphs[GlyphIndex], *X, *Y);
|
|
||||||
// // GlyphIndex += 1;
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// //width +=
|
|
||||||
// //ShapeText(&Cursor, Codepoints + RunStart, RunLength, BreakState.MainDirection, Direction, Script);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if Break.Flags & xx kbts_break_flags_enum.KBTS_BREAK_FLAG_DIRECTION {
|
|
||||||
// Direction = Break.Direction;
|
|
||||||
// if(!Cursor.Direction) Cursor = kbts_Cursor(BreakState.MainDirection);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if Break.Flags & xx kbts_break_flags_enum.KBTS_BREAK_FLAG_SCRIPT {
|
|
||||||
// Script = Break.Script;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// CodepointIndex += 1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
next_grapheme_size :: (font: *Font, text: []u32, n: s32, max_width: float = 0.0) -> Vector2, float, s32 {
|
next_grapheme_size :: (font: *Font, text: []u32, n: s32, max_width: float = 0.0) -> Vector2, float, s32 {
|
||||||
|
|
||||||
textp : *u32 = text.data;
|
textp : *u32 = text.data;
|
||||||
@ -686,186 +629,7 @@ next_grapheme_size :: (font: *Font, text: []u32, n: s32, max_width: float = 0.0)
|
|||||||
return .{}, 0, 0;
|
return .{}, 0, 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
next_word_size :: (font: *Font, text: []u32, n: s32, max_width: float = 0.0) -> Vector2, float, s32 {
|
|
||||||
|
|
||||||
textp : *u32 = text.data;
|
|
||||||
line_start : *u32 = textp + n;
|
|
||||||
len : u64 = xx (text.count - (line_start - textp));
|
|
||||||
|
|
||||||
// text_utf32 : [..]u32;
|
|
||||||
// defer array_free(text_utf32);
|
|
||||||
|
|
||||||
// StringAt : u64;
|
|
||||||
// while StringAt < xx len {
|
|
||||||
// Decode : kbts_decode = kbts_DecodeUtf8(line_start + StringAt, xx len - StringAt);
|
|
||||||
// StringAt += Decode.SourceCharactersConsumed;
|
|
||||||
// if Decode.Valid {
|
|
||||||
// array_add(*text_utf32, Decode.Codepoint);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
size, max_descent, read := SegmentText(font, line_start, len);
|
|
||||||
|
|
||||||
return size, max_descent, read;
|
|
||||||
|
|
||||||
// words := split(text, " ");
|
|
||||||
|
|
||||||
// for *word : words {
|
|
||||||
// if word.* != "" && word.data - text.data + word.count < text.count {
|
|
||||||
// if text[word.data - text.data + word.count] == " " {
|
|
||||||
// word.count += 1;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
//total_size : Vector2;
|
|
||||||
// lines : [..]Line;
|
|
||||||
|
|
||||||
// if !text {
|
|
||||||
// return .{}, 0.0, 0.0, lines;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if words.count == 0 {
|
|
||||||
// return .{}, 0.0, 0.0, lines;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// text_utf32 : [..]u32;
|
|
||||||
// defer array_free(text_utf32);
|
|
||||||
|
|
||||||
// StringAt : u64;
|
|
||||||
// while StringAt < text.count {
|
|
||||||
// Decode : kbts_decode = kbts_DecodeUtf8(text.data, text.count - StringAt);
|
|
||||||
// StringAt += Decode.SourceCharactersConsumed;
|
|
||||||
// if Decode.Valid {
|
|
||||||
// array_add(*text_utf32, Decode.Codepoint);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// String : *u8 = text_utf32.data;
|
|
||||||
// Length : u64 = text_utf32.count;
|
|
||||||
|
|
||||||
// // Make some glyphs
|
|
||||||
// kbts_glyph *Glyphs = cast(*kbts_glyph, alloc(size_of(kbts_glyph) * Length));
|
|
||||||
// GlyphCount : u32 = 0;
|
|
||||||
// Script : kbts_script = KBTS_SCRIPT_DONT_KNOW;
|
|
||||||
// Direction : kbts_direction = KBTS_DIRECTION_NONE;
|
|
||||||
// StringAt : u64;
|
|
||||||
// while StringAt < Length {
|
|
||||||
// Decode : kbts_decode = kbts_DecodeUtf8(String, Length - StringAt);
|
|
||||||
// StringAt += Decode.SourceCharactersConsumed;
|
|
||||||
// if(Decode.Valid) {
|
|
||||||
// Glyph : kbts_glyph = kbts_CodepointToGlyph(*Font, Decode.Codepoint);
|
|
||||||
// // Easy script inference for simple cases. (This is similar to hb_buffer_guess_segment_properties.)
|
|
||||||
// // If you have already segmented String with our API, you already have a script!
|
|
||||||
// // So no need to pass it in that case.
|
|
||||||
// // Only use this as a shorthand, when you are pretty sure String is a single
|
|
||||||
// // script.
|
|
||||||
// kbts_InferScript(*Direction, *Script, Glyph.Script);
|
|
||||||
// Glyphs[GlyphCount] = Glyph;
|
|
||||||
// GlyphCount += 1;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// void SegmentText(uint32_t *Codepoints, size_t CodepointCount)
|
|
||||||
|
|
||||||
// line : Line;
|
|
||||||
|
|
||||||
// for word : words {
|
|
||||||
// started_a_line : bool;
|
|
||||||
// if line.text.count == 0 {
|
|
||||||
// line.text.data = word.data;
|
|
||||||
// line.text.count = word.count;
|
|
||||||
// started_a_line = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// buf : *hb_buffer_t = hb_buffer_create();
|
|
||||||
// hb_buffer_add_utf8(buf, word.data, xx word.count, 0, -1);
|
|
||||||
|
|
||||||
// hb_buffer_set_direction(buf, hb_direction_t.LTR);
|
|
||||||
// hb_buffer_set_script(buf, hb_script_t.HB_SCRIPT_LATIN);
|
|
||||||
// hb_buffer_set_language(buf, hb_language_from_string("en", -1));
|
|
||||||
|
|
||||||
// features : [1]hb_feature_t;
|
|
||||||
// features[0].tag = HB_TAG(#char "c", #char "a", #char "l", #char "t");
|
|
||||||
// features[0].value = 1;
|
|
||||||
// features[0].start = HB_FEATURE_GLOBAL_START;
|
|
||||||
// features[0].end = HB_FEATURE_GLOBAL_END;
|
|
||||||
|
|
||||||
// hb_shape(font.hb, buf, features.data, features.count);
|
|
||||||
// glyph_count_u : u32;
|
|
||||||
// glyph_info : *hb_glyph_info_t = hb_buffer_get_glyph_infos(buf, *glyph_count_u);
|
|
||||||
// glyph_pos : *hb_glyph_position_t = hb_buffer_get_glyph_positions(buf, *glyph_count_u);
|
|
||||||
|
|
||||||
// glyph_count : s32 = xx glyph_count_u;
|
|
||||||
|
|
||||||
// word_size : Vector2;
|
|
||||||
|
|
||||||
// for i : 0..glyph_count - 1 {
|
|
||||||
// glyphid : hb_codepoint_t = glyph_info[i].codepoint;
|
|
||||||
// x_offset : hb_position_t = glyph_pos[i].x_offset;
|
|
||||||
// y_offset : hb_position_t = glyph_pos[i].y_offset;
|
|
||||||
// x_advance : hb_position_t = glyph_pos[i].x_advance;
|
|
||||||
// y_advance : hb_position_t = glyph_pos[i].y_advance;
|
|
||||||
|
|
||||||
// glyph : *Glyph = table_find_pointer(*font.glyphs, glyphid);
|
|
||||||
|
|
||||||
// if glyph {
|
|
||||||
// word_size.y = max(word_size.y, xx (glyph.height + glyph.descent));
|
|
||||||
// word_size.x += x_advance / 64.0;
|
|
||||||
// line.max_descent = max(line.max_descent, cast(float) glyph.descent);
|
|
||||||
// line.max_ascent = max(line.max_ascent, cast(float) glyph.ascent);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if !started_a_line {
|
|
||||||
// line.text.count += word.count;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if max_width > 0.0 {
|
|
||||||
// if line.size.x + word_size.x > max_width {
|
|
||||||
// line.size.x = max_width;
|
|
||||||
// line.size.y = max(line.size.y, word_size.y);
|
|
||||||
// line.size.y = max(line.size.y, line.max_ascent + line.max_descent);
|
|
||||||
// array_add(*lines, line);
|
|
||||||
// line = .{};
|
|
||||||
// } else {
|
|
||||||
// line.size.y = max(total_size.y, word_size.y);
|
|
||||||
// line.size.y = max(line.size.y, line.max_ascent + line.max_descent);
|
|
||||||
// line.size.x += word_size.x;
|
|
||||||
// // } else {
|
|
||||||
// // line.text.data = word.data;
|
|
||||||
// // line.text.count = word.count;
|
|
||||||
// // }
|
|
||||||
// }
|
|
||||||
// } else if max_width == 0.0 {
|
|
||||||
// line.size.y = max(total_size.y, word_size.y);
|
|
||||||
// line.size.y = max(line.size.y, line.max_ascent + line.max_descent);
|
|
||||||
// line.size.x += word_size.x;
|
|
||||||
// // if include_descent
|
|
||||||
// // size.y = max_ascent + max_descent;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// hb_buffer_destroy(buf);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if line.text.count > 0 {
|
|
||||||
// line.size.y = max(line.size.y, line.max_ascent + line.max_descent);
|
|
||||||
// array_add(*lines, line);
|
|
||||||
// line = .{};
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for line : lines {
|
|
||||||
// total_size.x = max(total_size.x, line.size.x);
|
|
||||||
// total_size.y += line.size.y;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
//return total_size, 0, 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
next_line_size :: (font: *Font, text: []u32, n: s32, max_width: float = 0.0) -> Vector2, float, s32 {
|
next_line_size :: (font: *Font, text: []u32, n: s32, max_width: float = 0.0) -> Vector2, float, s32 {
|
||||||
|
|
||||||
textp : *u32 = text.data;
|
textp : *u32 = text.data;
|
||||||
Codepoints : *u32 = textp + n;
|
Codepoints : *u32 = textp + n;
|
||||||
CodepointCount : u64 = xx (text.count - (Codepoints - textp));
|
CodepointCount : u64 = xx (text.count - (Codepoints - textp));
|
||||||
|
|||||||
76
src/ui.jai
76
src/ui.jai
@ -985,7 +985,17 @@ ui_draw_text_input :: (using text_input: *TextInput) {
|
|||||||
// Restore modified GL state
|
// Restore modified GL state
|
||||||
// restore_opengl_state(*opengl_state);
|
// restore_opengl_state(*opengl_state);
|
||||||
|
|
||||||
cursor_pos : Vector2 = pos + .{0.0, size.y - font.face.size.metrics.height >> 6 - 2 *(margin + border_size + padding)};
|
cursor_pos : Vector2 = pos + .{0.0, size.y - font.face.size.metrics.height >> 6 - 2 * (margin + border_size + padding)};
|
||||||
|
|
||||||
|
Rectangle :: struct {
|
||||||
|
pos : Vector2;
|
||||||
|
size : Vector2;
|
||||||
|
}
|
||||||
|
select_rectangles : [..]Rectangle;
|
||||||
|
defer array_free(select_rectangles);
|
||||||
|
|
||||||
|
select_pos : Vector2 = pos + .{0.0, size.y - font.face.size.metrics.height >> 6 - 2 * (margin + border_size + padding)};
|
||||||
|
select_size : Vector2 = .{0.0, xx font.face.size.metrics.height >> 6};
|
||||||
|
|
||||||
if text_input.text.count > 0 {
|
if text_input.text.count > 0 {
|
||||||
//midline : Vector2 = pos + Vector2.{cast(float, margin + border_size + padding), xx (size.y / 2.0)};
|
//midline : Vector2 = pos + Vector2.{cast(float, margin + border_size + padding), xx (size.y / 2.0)};
|
||||||
@ -1004,17 +1014,54 @@ ui_draw_text_input :: (using text_input: *TextInput) {
|
|||||||
size, max_descent, read := next_grapheme_size(font, text, i + j, 0.0);
|
size, max_descent, read := next_grapheme_size(font, text, i + j, 0.0);
|
||||||
|
|
||||||
cursor_pos.x += size.x;
|
cursor_pos.x += size.x;
|
||||||
// row.x1 += size.x;
|
|
||||||
// row.baseline_y_delta = max(row.baseline_y_delta, size.y);
|
|
||||||
// row.ymin = max(row.ymin, max_descent);
|
|
||||||
// row.ymax = max(row.ymax, size.y - row.ymin);
|
|
||||||
// row.num_chars += read;
|
|
||||||
j += read;
|
j += read;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cursor_pos.y -= font.face.size.metrics.height >> 6;
|
cursor_pos.y -= font.face.size.metrics.height >> 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if textedit_state.select_start < textedit_state.select_end {
|
||||||
|
if i + xx row.num_chars >= textedit_state.select_start {
|
||||||
|
j : s32;
|
||||||
|
while grapheme := i + j < textedit_state.select_start {
|
||||||
|
size, max_descent, read, segment_type := next_segment_size(font, text, i + j, 0.0, .GRAPHEME | .LINE_HARD);
|
||||||
|
|
||||||
|
if segment_type & .GRAPHEME {
|
||||||
|
select_pos.x += size.x;
|
||||||
|
j += read;
|
||||||
|
} else {
|
||||||
|
select_pos.y -= font.face.size.metrics.height >> 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while grapheme := i + j < textedit_state.select_end {
|
||||||
|
if i + j < row.num_chars {
|
||||||
|
array_add(*select_rectangles, .{select_pos, select_size});
|
||||||
|
select_pos.y -= font.face.size.metrics.height >> 6;
|
||||||
|
select_pos.x = pos.x;
|
||||||
|
select_size = .{0.0, 0.0};
|
||||||
|
}
|
||||||
|
size, max_descent, read, segment_type := next_segment_size(font, text, i + j, 0.0, .GRAPHEME | .LINE_HARD);
|
||||||
|
|
||||||
|
if segment_type & .GRAPHEME {
|
||||||
|
select_size.x += size.x;
|
||||||
|
j += read;
|
||||||
|
|
||||||
|
if i + j >= textedit_state.select_end {
|
||||||
|
array_add(*select_rectangles, .{select_pos, select_size});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
array_add(*select_rectangles, .{select_pos, select_size});
|
||||||
|
select_pos.y -= font.face.size.metrics.height >> 6;
|
||||||
|
select_pos.x = pos.x;
|
||||||
|
select_size = .{0.0, 0.0};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
select_pos.y -= font.face.size.metrics.height >> 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render_text(font, .{row.num_chars, text_input.text.data + i},
|
render_text(font, .{row.num_chars, text_input.text.data + i},
|
||||||
.{draw_pos.x, draw_pos.y + row.ymin /*+ line.max_descent*/}, text_input.size,
|
.{draw_pos.x, draw_pos.y + row.ymin /*+ line.max_descent*/}, text_input.size,
|
||||||
colour = font_colour);
|
colour = font_colour);
|
||||||
@ -1023,11 +1070,14 @@ ui_draw_text_input :: (using text_input: *TextInput) {
|
|||||||
|
|
||||||
i += xx row.num_chars;
|
i += xx row.num_chars;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// whil
|
if textedit_state.select_end != textedit_state.select_start {
|
||||||
// label_size, max_ascent, max_descent, lines := calculate_string_draw_size(label.font, label.text, true, max_width);
|
if textedit_state.select_end > textedit_state.select_start {
|
||||||
|
for select_rectangles {
|
||||||
// draw_pos.y -= line.size.y;
|
render_filled_rectangle(it.pos + v2(margin) + v2(border_size) + v2(padding), it.size, .{0.8, 0.2, 0.55, 0.4});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cursor_time < 0.5 {
|
if cursor_time < 0.5 {
|
||||||
@ -2323,7 +2373,7 @@ render_rectangle :: (pos: Vector2, size: Vector2, window_space: bool = true) {
|
|||||||
glDeleteVertexArrays(1, *vao);
|
glDeleteVertexArrays(1, *vao);
|
||||||
}
|
}
|
||||||
|
|
||||||
render_filled_rectangle :: (pos: Vector2, size: Vector2, window_space: bool = true) {
|
render_filled_rectangle :: (pos: Vector2, size: Vector2, colour := Vector4.{1, 1, 1, 1}, window_space: bool = true) {
|
||||||
|
|
||||||
positions: [4]Vector2 = Vector2.[
|
positions: [4]Vector2 = Vector2.[
|
||||||
.{pos.x + size.x, pos.y},
|
.{pos.x + size.x, pos.y},
|
||||||
@ -2355,7 +2405,7 @@ render_filled_rectangle :: (pos: Vector2, size: Vector2, window_space: bool = tr
|
|||||||
glUniformMatrix4fv(glGetUniformLocation(line_shader.id, "uni_view"), 1, GL_TRUE, cast(*float) *view);
|
glUniformMatrix4fv(glGetUniformLocation(line_shader.id, "uni_view"), 1, GL_TRUE, cast(*float) *view);
|
||||||
glUniformMatrix4fv(glGetUniformLocation(line_shader.id, "uni_proj"), 1, GL_TRUE, cast(*float) *proj);
|
glUniformMatrix4fv(glGetUniformLocation(line_shader.id, "uni_proj"), 1, GL_TRUE, cast(*float) *proj);
|
||||||
|
|
||||||
glUniform4f(glGetUniformLocation(line_shader.id, "uni_colour"), 1, 1, 1, 1);
|
glUniform4f(glGetUniformLocation(line_shader.id, "uni_colour"), colour.x, colour.y, colour.z, colour.w);
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, xx positions.count);
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, xx positions.count);
|
||||||
|
|
||||||
|
|||||||
30
ui.rad
30
ui.rad
@ -1,33 +1,27 @@
|
|||||||
// raddbg 0.9.20 project file
|
// raddbg 0.9.21 project file
|
||||||
|
|
||||||
recent_file: path: "src/stb_textedit.jai"
|
recent_file: path: "src/stb_textedit.jai"
|
||||||
|
recent_file: path: "../../../../jai/modules/runtime_support.jai"
|
||||||
|
recent_file: path: "src/main.jai"
|
||||||
|
recent_file: path: "src/ui.jai"
|
||||||
|
recent_file: path: "src/text.jai"
|
||||||
recent_file: path: "../../../../jai/modules/basic/array.jai"
|
recent_file: path: "../../../../jai/modules/basic/array.jai"
|
||||||
recent_file: path: "../../../../jai/modules/default_allocator/module.jai"
|
recent_file: path: "../../../../jai/modules/default_allocator/module.jai"
|
||||||
recent_file: path: "src/ui.jai"
|
|
||||||
recent_file: path: "src/main.jai"
|
|
||||||
recent_file: path: "../../../../jai/modules/math/module.jai"
|
recent_file: path: "../../../../jai/modules/math/module.jai"
|
||||||
recent_file: path: "src/text.jai"
|
|
||||||
recent_file: path: "modules/kb_text_shape/kb_text_shape.h"
|
recent_file: path: "modules/kb_text_shape/kb_text_shape.h"
|
||||||
recent_file: path: "modules/SDL3/src/SDL-release-3.2.16/src/events/sdl_keyboard.c"
|
recent_file: path: "modules/SDL3/src/SDL-release-3.2.16/src/events/sdl_keyboard.c"
|
||||||
recent_file: path: "modules/SDL3/src/SDL-release-3.2.16/src/video/windows/SDL_windowsevents.c"
|
recent_file: path: "modules/SDL3/src/SDL-release-3.2.16/src/video/windows/SDL_windowsevents.c"
|
||||||
recent_file: path: "src/math/math.jai"
|
recent_file: path: "src/math/math.jai"
|
||||||
recent_file: path: "../../../../jai/modules/runtime_support.jai"
|
|
||||||
recent_file: path: "../../../../jai/modules/basic/module.jai"
|
recent_file: path: "../../../../jai/modules/basic/module.jai"
|
||||||
|
breakpoint:
|
||||||
|
{
|
||||||
|
source_location: "src/ui.jai:1024:1"
|
||||||
|
hit_count: 0
|
||||||
|
enabled: 0
|
||||||
|
}
|
||||||
target:
|
target:
|
||||||
{
|
{
|
||||||
executable: "bin/mexplore-debug.exe"
|
executable: "bin/mexplore-debug.exe"
|
||||||
working_directory: bin
|
working_directory: "bin/"
|
||||||
enabled: 1
|
enabled: 1
|
||||||
}
|
}
|
||||||
breakpoint:
|
|
||||||
{
|
|
||||||
source_location: "src/stb_textedit.jai:1140:1"
|
|
||||||
hit_count: 0
|
|
||||||
enabled: 0
|
|
||||||
}
|
|
||||||
breakpoint:
|
|
||||||
{
|
|
||||||
source_location: "src/stb_textedit.jai:305:1"
|
|
||||||
hit_count: 0
|
|
||||||
enabled: 0
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user