diff --git a/.build/.added_strings_w3.jai b/.build/.added_strings_w3.jai index f2eb681..9ca03fa 100644 --- a/.build/.added_strings_w3.jai +++ b/.build/.added_strings_w3.jai @@ -6,7 +6,7 @@ NAME :: "mexplore"; VERSION :: "0.1"; 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_REVISION :: "4744f67e2e182828d1a3de921c4a5b6194a2a24d"; + GIT_REVISION :: "0f5d7d612591fbcf39e818c9076d28dc422ca635"; DEBUG :: true; diff --git a/.build/mexplore-debug.exp b/.build/mexplore-debug.exp index 643a05c..5fcc3f8 100644 Binary files a/.build/mexplore-debug.exp and b/.build/mexplore-debug.exp differ diff --git a/.build/mexplore-debug.lib b/.build/mexplore-debug.lib index 954e25b..8069cf8 100644 Binary files a/.build/mexplore-debug.lib and b/.build/mexplore-debug.lib differ diff --git a/.build/mexplore-debug_0_w3.obj b/.build/mexplore-debug_0_w3.obj index 7e35138..8565602 100644 Binary files a/.build/mexplore-debug_0_w3.obj and b/.build/mexplore-debug_0_w3.obj differ diff --git a/.build/mexplore-debug_1_w3.obj b/.build/mexplore-debug_1_w3.obj index d0df3c8..ad3bcab 100644 Binary files a/.build/mexplore-debug_1_w3.obj and b/.build/mexplore-debug_1_w3.obj differ diff --git a/.build/mexplore-debug_2_w3.obj b/.build/mexplore-debug_2_w3.obj index ac7d8f9..24bbc48 100644 Binary files a/.build/mexplore-debug_2_w3.obj and b/.build/mexplore-debug_2_w3.obj differ diff --git a/.build/mexplore-debug_3_w3.obj b/.build/mexplore-debug_3_w3.obj index 16a15ef..9b028d3 100644 Binary files a/.build/mexplore-debug_3_w3.obj and b/.build/mexplore-debug_3_w3.obj differ diff --git a/bin/mexplore-debug.exe b/bin/mexplore-debug.exe index afc2649..346771d 100644 Binary files a/bin/mexplore-debug.exe and b/bin/mexplore-debug.exe differ diff --git a/bin/mexplore-debug.pdb b/bin/mexplore-debug.pdb index 3a45e7c..209ed56 100644 Binary files a/bin/mexplore-debug.pdb and b/bin/mexplore-debug.pdb differ diff --git a/bin/mexplore-debug.rdi b/bin/mexplore-debug.rdi index 1e3e116..8d9590e 100644 Binary files a/bin/mexplore-debug.rdi and b/bin/mexplore-debug.rdi differ diff --git a/src/main.jai b/src/main.jai index 126caef..1c8e474 100644 --- a/src/main.jai +++ b/src/main.jai @@ -89,12 +89,39 @@ main :: () { if event.key.key == { case SDLK_ESCAPE; 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; transition.left_arrow_down = true; if event.key.mod == SDL_KMOD_LCTRL { log("Moving word to the left!"); 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 { log("Moving to the left"); transition.char = STB_TEXTEDIT_K_LEFT; @@ -105,6 +132,8 @@ main :: () { if event.key.mod == SDL_KMOD_LCTRL { log("Moving word to the right!"); 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 { log("Moving to the right"); transition.char = STB_TEXTEDIT_K_RIGHT; @@ -112,9 +141,8 @@ main :: () { case SDLK_BACKSPACE; transition.backspace = true; - if event.key.mod == SDL_KMOD_LCTRL { - // log("Moving word to the right!"); - // transition.char = STB_TEXTEDIT_K_WORDRIGHT; + if event.key.mod == SDL_KMOD_LSHIFT { + transition.char = STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT; } else { transition.char = STB_TEXTEDIT_K_BACKSPACE; } diff --git a/src/stb_textedit.jai b/src/stb_textedit.jai index 747a976..c8e21b1 100644 --- a/src/stb_textedit.jai +++ b/src/stb_textedit.jai @@ -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 { - 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; Codepoints : *u32 = textp + n; CodepointCount : u64 = xx (obj.text.count - (Codepoints - textp)); @@ -941,42 +939,42 @@ while retry := true { state.cursor = state.select_end; state.has_preferred_x = 0; -// #if #exists(STB_TEXTEDIT_MOVEWORDLEFT) { -// case STB_TEXTEDIT_K_WORDLEFT; -// if (STB_TEXT_HAS_SELECTION(state)) -// stb_textedit_move_to_first(state); -// else { -// state.cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state.cursor); -// stb_textedit_clamp( str, state ); -// } +//#if #exists(STB_TEXTEDIT_MOVEWORDLEFT) { + case STB_TEXTEDIT_K_WORDLEFT; + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_first(state); + else { + state.cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state.cursor); + stb_textedit_clamp( str, state ); + } -// case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT; -// if !STB_TEXT_HAS_SELECTION( state ) -// stb_textedit_prep_selection_at_cursor(state); + case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT; + if !STB_TEXT_HAS_SELECTION( state ) + stb_textedit_prep_selection_at_cursor(state); -// state.cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state.cursor); -// state.select_end = state.cursor; + state.cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state.cursor); + state.select_end = state.cursor; -// stb_textedit_clamp( str, state ); -// } + stb_textedit_clamp( str, state ); +//} // #if #exists(STB_TEXTEDIT_MOVEWORDRIGHT) { -// case STB_TEXTEDIT_K_WORDRIGHT; -// if (STB_TEXT_HAS_SELECTION(state)) { -// stb_textedit_move_to_last(str, state); -// } else { -// state.cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state.cursor); -// stb_textedit_clamp(str, state); -// } + case STB_TEXTEDIT_K_WORDRIGHT; + if (STB_TEXT_HAS_SELECTION(state)) { + stb_textedit_move_to_last(str, state); + } else { + state.cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state.cursor); + stb_textedit_clamp(str, state); + } -// case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT; -// if !STB_TEXT_HAS_SELECTION(state) -// stb_textedit_prep_selection_at_cursor(state); + case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT; + if !STB_TEXT_HAS_SELECTION(state) + stb_textedit_prep_selection_at_cursor(state); -// state.cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state.cursor); -// state.select_end = state.cursor; + state.cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, 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; diff --git a/src/text.jai b/src/text.jai index 5e3c6b8..6a69b85 100644 --- a/src/text.jai +++ b/src/text.jai @@ -502,7 +502,52 @@ ShapeText :: (font: *Font, Cursor: *kbts_cursor, Codepoints: *u32, CodepointCoun 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; Direction : kbts_direction = .NONE; Script : kbts_script = .DONT_KNOW; @@ -519,20 +564,6 @@ SegmentText :: (font: *Font, Codepoints: *u32, CodepointCount: u64) -> Vector2, Break : kbts_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 { Direction = Break.Direction; 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; 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; - //} - - // size.x += word_size.x; - // size.y = max(word_size.y); - - // max_descent = max(max_descent, word_max_descent); + return size, max_descent, xx Break.Position; } - - // 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; @@ -569,81 +587,6 @@ SegmentText :: (font: *Font, Codepoints: *u32, CodepointCount: u64) -> Vector2, 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 { 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; } -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 { - textp : *u32 = text.data; Codepoints : *u32 = textp + n; CodepointCount : u64 = xx (text.count - (Codepoints - textp)); diff --git a/src/ui.jai b/src/ui.jai index 654f320..75c486a 100644 --- a/src/ui.jai +++ b/src/ui.jai @@ -985,7 +985,17 @@ ui_draw_text_input :: (using text_input: *TextInput) { // Restore modified GL 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 { //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); 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; - } + } } else { 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}, .{draw_pos.x, draw_pos.y + row.ymin /*+ line.max_descent*/}, text_input.size, colour = font_colour); @@ -1023,11 +1070,14 @@ ui_draw_text_input :: (using text_input: *TextInput) { i += xx row.num_chars; } + } - // whil - // label_size, max_ascent, max_descent, lines := calculate_string_draw_size(label.font, label.text, true, max_width); - - // draw_pos.y -= line.size.y; + if textedit_state.select_end != textedit_state.select_start { + if textedit_state.select_end > textedit_state.select_start { + for select_rectangles { + 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 { @@ -2323,7 +2373,7 @@ render_rectangle :: (pos: Vector2, size: Vector2, window_space: bool = true) { 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.[ .{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_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); diff --git a/ui.rad b/ui.rad index b9947b0..b7ace89 100644 --- a/ui.rad +++ b/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: "../../../../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/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: "src/text.jai" 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/video/windows/SDL_windowsevents.c" recent_file: path: "src/math/math.jai" -recent_file: path: "../../../../jai/modules/runtime_support.jai" recent_file: path: "../../../../jai/modules/basic/module.jai" +breakpoint: +{ + source_location: "src/ui.jai:1024:1" + hit_count: 0 + enabled: 0 +} target: { executable: "bin/mexplore-debug.exe" - working_directory: bin + working_directory: "bin/" 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 -}