diff --git a/.build/.added_strings_w3.jai b/.build/.added_strings_w3.jai index bc14fd4..38c74d8 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.014, built on 24 May 2025"; - RELEASE_DATE :: "13 July 2025, 19:51:19"; + RELEASE_DATE :: "16 July 2025, 20:47:28"; GIT_BRANCH :: "main"; - GIT_REVISION :: "ad439a550931e9088715ccfbe161757bcead4a9a"; + GIT_REVISION :: "68096796dc50c0bfe4e9d687ce4e9563e0bbf4bb"; DEBUG :: true; diff --git a/.build/mexplore-debug_0_w3.obj b/.build/mexplore-debug_0_w3.obj index 997b6a1..38b681a 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 990b2ef..0b51b1a 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 57da458..a84bc1d 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 8f20830..aaf25f0 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 ce854f1..5524d62 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 269ea9d..17dc2d3 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 b410df5..323db38 100644 Binary files a/bin/mexplore-debug.rdi and b/bin/mexplore-debug.rdi differ diff --git a/src/stb_textedit.jai b/src/stb_textedit.jai index fe3c8a2..2a14336 100644 --- a/src/stb_textedit.jai +++ b/src/stb_textedit.jai @@ -283,7 +283,7 @@ STB_TEXTEDIT_STRINGLEN :: (obj: *STB_TEXTEDIT_STRING) -> s32 { } STB_TEXTEDIT_KEYTOTEXT :: (k: STB_TEXTEDIT_KEYTYPE) -> s32 #expand { - return ifx k >= 32 && k < 127 then k else -1; + return ifx k >= 32 then k else -1; } STB_TEXTEDIT_DELETECHARS :: (obj: *STB_TEXTEDIT_STRING, i: s32, n: s32) { @@ -339,11 +339,24 @@ STB_TEXTEDIT_LAYOUTROW :: (row: *StbTexteditRow, obj: *STB_TEXTEDIT_STRING, n: s //size, max_descent, read := SegmentText(obj.font, text_utf32.data, xx text_utf32.count); idx : s32; - while idx < obj.text.count && row.x1 < obj.max_size.x { - size, max_descent, read := next_word_size(obj.font, .{obj.text.count, obj.text.data}, n + idx, obj.max_size.x); + while word := n + idx < obj.text.count && row.x1 < obj.max_size.x { + size, max_descent, read := next_word_size(obj.font, obj.text, n + idx, obj.max_size.x); if row.x1 + size.x > obj.max_size.x { - break; + while grapheme := idx < obj.text.count { + size, max_descent, read := next_grapheme_size(obj.font, obj.text, n + idx, obj.max_size.x); + + if row.x1 + size.x > obj.max_size.x { + break word; + } + + 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; + idx += read; + } } row.x1 += size.x; diff --git a/src/text.jai b/src/text.jai index c510a1f..b9020e3 100644 --- a/src/text.jai +++ b/src/text.jai @@ -81,8 +81,11 @@ init_font :: (using font: *Font, filename: string, size: s32) { charcode : FT_ULong; gindex : FT_UInt; + i : int; + charcode = FT_Get_First_Char(face, *gindex); while gindex != 0 { + log("Reading index: % - Charcode: %", gindex, charcode); error = FT_Load_Glyph(face, gindex, FT_LOAD_RENDER); if error log("%", to_string(FT_Error_String(error))); @@ -108,6 +111,7 @@ init_font :: (using font: *Font, filename: string, size: s32) { table_set(*font.glyphs, glyph.index, glyph); charcode = FT_Get_Next_Char(face, charcode, *gindex); + i += 1; } // for 0..face.num_glyphs { @@ -275,6 +279,12 @@ render_text :: (font: *Font, text: []u32, pos: Vector2, size: Vector2, window_sp glyph : *Glyph = table_find_pointer(*font.glyphs, kglyph.Id); + if !glyph { + log("[Error] Panic! Didn't find the glyph!"); + for font.glyphs + log("%", it); + } + v0 : Vector2; v1 : Vector2; if count_descent { @@ -633,6 +643,250 @@ SegmentText :: (font: *Font, Codepoints: *u32, CodepointCount: u64) -> Vector2, // return 0; // } +next_grapheme_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)); + + // 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; + + + Cursor : kbts_cursor; + Direction : kbts_direction = .NONE; + Script : kbts_script = .DONT_KNOW; + RunStart : u64 = 0; + BreakState : kbts_break_state; + kbts_BeginBreak(*BreakState, .NONE, .NORMAL); + + // size : Vector2; + // max_descent : float; + + 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.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); + } + + if Break.Flags & .SCRIPT { + Script = Break.Script; + } + + if (Break.Position > RunStart) && (Break.Flags & .GRAPHEME) { + 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); + } + + // 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; + } + + return .{}, 0, 0; + + // 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_word_size :: (font: *Font, text: []u32, n: s32, max_width: float = 0.0) -> Vector2, float, s32 { textp : *u32 = text.data; diff --git a/src/ui.jai b/src/ui.jai index a672f27..c3b0187 100644 --- a/src/ui.jai +++ b/src/ui.jai @@ -984,19 +984,19 @@ ui_draw_text_input :: (using text_input: *TextInput) { if text_input.text.count > 0 { //midline : Vector2 = pos + Vector2.{cast(float, margin + border_size + padding), xx (size.y / 2.0)}; - row : StbTexteditRow; draw_pos : Vector2 = pos + v2(margin); i : s32; while i < text_input.text.count { + row : StbTexteditRow; STB_TEXTEDIT_LAYOUTROW(*row, text_input, 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, colour = font_colour); - draw_pos.y -= row.baseline_y_delta; + draw_pos.y -= font.face.size.metrics.height >> 6; i += xx row.num_chars; } @@ -1363,6 +1363,7 @@ ui_grow_roots :: () { if bottom_left.sizing_x == .GROW { bottom_left.size.x = xx window_width; + bottom_left.max_size.x = bottom_left.size.x; } } @@ -1376,6 +1377,7 @@ ui_grow_roots :: () { if top_left.sizing_x == .GROW { top_left.size.x = xx window_width; + top_left.max_size.x = top_left.size.x; } ui_grow_containers(top_left); @@ -1583,13 +1585,21 @@ ui_max_sizes :: () { if next.type == .CONTAINER ui_max_size_containers(next); + if next.type == .TEXTINPUT { + text_input := cast(*TextInput, next); + text_input.max_size.x = top_left.max_size.x; + + return; + } + next = next.next; } } } ui_max_size_containers :: (rect: *Rect) { - if rect.type != .CONTAINER return; + if rect.type != .CONTAINER + return; container := cast(*Container, rect); diff --git a/ui.rad b/ui.rad index 6e678d3..78ddb2c 100644 --- a/ui.rad +++ b/ui.rad @@ -1,15 +1,15 @@ // raddbg 0.9.20 project file -recent_file: path: "src/main.jai" +recent_file: path: "src/text.jai" recent_file: path: "src/ui.jai" +recent_file: path: "src/stb_textedit.jai" +recent_file: path: "../../../../jai/modules/runtime_support.jai" +recent_file: path: "modules/kb_text_shape/kb_text_shape.h" +recent_file: path: "src/main.jai" recent_file: path: "../../../../jai/modules/math/module.jai" recent_file: path: "../../../../jai/modules/basic/array.jai" -recent_file: path: "src/stb_textedit.jai" -recent_file: path: "src/text.jai" -recent_file: path: "modules/kb_text_shape/kb_text_shape.h" recent_file: path: "../../../../jai/modules/basic/module.jai" recent_file: path: "../../../../jai/modules/default_allocator/module.jai" -recent_file: path: "../../../../jai/modules/runtime_support.jai" target: { executable: "bin/mexplore-debug.exe" @@ -18,7 +18,24 @@ target: } breakpoint: { - source_location: "src/stb_textedit.jai:990:1" + source_location: "src/ui.jai:1588:1" hit_count: 0 enabled: 0 } +breakpoint: +{ + source_location: "src/ui.jai:262:1" + hit_count: 0 + enabled: 0 +} +breakpoint: +{ + source_location: "src/stb_textedit.jai:346:1" + hit_count: 0 + enabled: 0 +} +breakpoint: +{ + source_location: "src/text.jai:282:1" + hit_count: 8 +}