Victory. Text editor working well. Docs being written.
This commit is contained in:
parent
406a8a3a71
commit
f18795ff79
@ -5,8 +5,8 @@
|
|||||||
//
|
//
|
||||||
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.018, built on 11 October 2025";
|
||||||
RELEASE_DATE :: "15 September 2025, 21:57:10";
|
RELEASE_DATE :: "21 October 2025, 23:02:07";
|
||||||
GIT_BRANCH :: "main";
|
GIT_BRANCH :: "main";
|
||||||
GIT_REVISION :: "7be01af7bf0025806f36ad7c938655e432d8b81e";
|
GIT_REVISION :: "406a8a3a7118b28edb568656315ea190c111c5ba";
|
||||||
DEBUG :: true;
|
DEBUG :: true;
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
136
README.md
Normal file
136
README.md
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
# UI
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This is a small Jai library to do some basic immediate mode UI. It has a variety of widgets
|
||||||
|
and writing new ones should be relatively easy, if you follow the existing ones.
|
||||||
|
|
||||||
|
As opposed to a UI library you might find on the Internet, like Dear ImGui, this library is
|
||||||
|
sadly not platform independent. It is relatively coupled with OpenGL, so you in order to
|
||||||
|
integrate it to a project, you will need to also provide a GL context with GLFW, RGFW, SDL,
|
||||||
|
or the like.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
The main concept behind this UI system is that as you call the ui_* functions like ui_begin/ui_end, etc.
|
||||||
|
You are implicitly building the tree that represents the UI hierarchy. That is the magic of an
|
||||||
|
immediate mode API. You take advantage of the fact that functions are called in a stack across time.
|
||||||
|
Which is implicitly a Tree. At the end of the frame you give this tree to the rendering function, which
|
||||||
|
recurses through it pre-order, drawing the panels, icons, text, etc., in the correct order.
|
||||||
|
|
||||||
|
Using this architecutre as the base places some undesirable constraints on the further design of the
|
||||||
|
system though. For example, the most useful part of this library is the auto-layout algorithm. It's not
|
||||||
|
super sophisticated, but it works. And in order to do this auto layout you need two basic pieces of
|
||||||
|
information. Where are the ui elements and how big are they. Properties that the layout algorithm can
|
||||||
|
itself change!
|
||||||
|
|
||||||
|
So, the easiest solution to this problem is to separate everything into distinct phases (or passes).
|
||||||
|
In the first pass you are declaring the tree structure of the UI as you go in a bottom up fashion,
|
||||||
|
recording the initial positions and sizes. Then after you're done you can traverse the tree from the
|
||||||
|
top down adjusting the layout. This is only possible because at this point in time you have all the
|
||||||
|
information including nodes' siblings, the size they are, they size they'd like to be, etc.
|
||||||
|
|
||||||
|
## Public API
|
||||||
|
|
||||||
|
Some functions have a begin/end pair, becuase you necesarily have to wait until things finish happening
|
||||||
|
inside of them to be able to calculate their initial size, etc. Other functions don't have this begin/end
|
||||||
|
pair, because they don't allow children, they're a leaf node, and they don't need further information to finish
|
||||||
|
their calculations.
|
||||||
|
|
||||||
|
```
|
||||||
|
ui_new_frame :: ()
|
||||||
|
```
|
||||||
|
|
||||||
|
This has to be called every frame, before calling any other UI function.
|
||||||
|
|
||||||
|
```
|
||||||
|
ui_begin :: (s: string)
|
||||||
|
```
|
||||||
|
|
||||||
|
This begins a panel, which other widgets can go inside of.
|
||||||
|
|
||||||
|
```
|
||||||
|
ui_end :: ()
|
||||||
|
```
|
||||||
|
|
||||||
|
Has to be called after a ui_begin to finish its UI Node.
|
||||||
|
|
||||||
|
```
|
||||||
|
ui_text_input :: (s: string, font_colour := Vector4.{1, 1, 1, 1})
|
||||||
|
```
|
||||||
|
|
||||||
|
This starts a text editor!
|
||||||
|
|
||||||
|
```
|
||||||
|
ui_begin_container :: (s: string, gradient := false, colour_left := Vector4.{}, colour_right := Vector4.{}, max_x: s32 = -1, max_y: s32 = -1, flags: ContainerFlags = 0)
|
||||||
|
```
|
||||||
|
|
||||||
|
Similar to a normal ui_begin, but you can have this one inside the main panel, recursively.
|
||||||
|
Very useful to change the layout direction (Left To Right vs Top to Bottom)
|
||||||
|
|
||||||
|
```
|
||||||
|
ui_end_container :: ()
|
||||||
|
```
|
||||||
|
|
||||||
|
Must be called after a ui_begin_container, to calculate sizing and finish the node in the UI Tree.
|
||||||
|
|
||||||
|
```
|
||||||
|
ui_icon :: (s: string, texture: *Texture, size: Vector2)
|
||||||
|
```
|
||||||
|
|
||||||
|
Renders an OpenGL texture.
|
||||||
|
|
||||||
|
```
|
||||||
|
ui_label :: (s: string = "", colour := Vector4.{1.0, 1.0, 1.0, 1.0})
|
||||||
|
```
|
||||||
|
|
||||||
|
Renders text.
|
||||||
|
|
||||||
|
```
|
||||||
|
ui_spacing :: (s: string)
|
||||||
|
```
|
||||||
|
|
||||||
|
Forces spacing between elements. The auto layout algorithm tries to maximize the space between
|
||||||
|
the node before the spacing and after the spacing, taking into account the max size of the parent
|
||||||
|
container.
|
||||||
|
|
||||||
|
```
|
||||||
|
ui_button :: (s: string = "", icon_texture: *Texture = null, font_colour := Vector4.{1, 1, 1, 1}, draw_frame := true) -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Renders a panel with optional text in it and an optional OpenGL texture. When clicked it returns true.
|
||||||
|
Very useful to run conditional code like:
|
||||||
|
|
||||||
|
if ui_button(...) {
|
||||||
|
do_something();
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
ui_font_icon :: (font: *Font, s: string, size: Vector2, colour: Vector4 = .{1, 1, 1, 1})
|
||||||
|
```
|
||||||
|
|
||||||
|
Renders an icon stored in a font. you have to figure out what the name of the glyph is and pray
|
||||||
|
FreeType can find it. You can look up the names using a tool like [FontDrop!](https://fontdrop.info/).
|
||||||
|
|
||||||
|
```
|
||||||
|
ui_progress_bar :: (s: string = "", progress: float, size: Vector2, background := Vector4.{1, 1, 1, 1}, foreground := Vector4.{1, 1, 1, 1})
|
||||||
|
```
|
||||||
|
|
||||||
|
Renders a progress bar.
|
||||||
|
|
||||||
|
```
|
||||||
|
ui_end_frame :: ()
|
||||||
|
```
|
||||||
|
|
||||||
|
Must be called after finishing the UI Tree. You must not call any UI Tree building functions (any of the previous ones)
|
||||||
|
after this call and before a new ui_begin_frame.
|
||||||
|
|
||||||
|
```
|
||||||
|
ui_render :: ()
|
||||||
|
```
|
||||||
|
|
||||||
|
Renders the UI with OpenGL.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Please look at main.jai for an example.
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,7 +1,7 @@
|
|||||||
// Workspace: Target Program
|
// Workspace: Target Program
|
||||||
|
|
||||||
//
|
//
|
||||||
// #insert text. Generated from /opt/jai/modules/Bindings_Generator/module.jai:326.
|
// #insert text. Generated from C:/jai/modules/Bindings_Generator/module.jai:337.
|
||||||
//
|
//
|
||||||
([2] string).[
|
([2] string).[
|
||||||
.["FLT_MIN", "FLOAT32_MIN"],
|
.["FLT_MIN", "FLOAT32_MIN"],
|
||||||
@ -44,8 +44,8 @@
|
|||||||
.["INT64_MIN", "S64_MIN"],
|
.["INT64_MIN", "S64_MIN"],
|
||||||
.["INT64_MAX", "S64_MAX"],
|
.["INT64_MAX", "S64_MAX"],
|
||||||
.["UINT64_MAX", "U64_MAX"],
|
.["UINT64_MAX", "U64_MAX"],
|
||||||
.["LONG_MIN", "S64_MIN"],
|
.["LONG_MIN", "S32_MIN"],
|
||||||
.["LONG_MAX", "S64_MAX"],
|
.["LONG_MAX", "S32_MAX"],
|
||||||
.["ULONG_MIN", "0"],
|
.["ULONG_MIN", "0"],
|
||||||
.["ULONG_MAX", "U64_MAX"],
|
.["ULONG_MAX", "U32_MAX"],
|
||||||
];
|
];
|
||||||
|
|||||||
@ -108,8 +108,8 @@ generate_bindings :: (args: [] string, minimum_os_version: type_of(Build_Options
|
|||||||
|
|
||||||
try_to_preserve_comments = false;
|
try_to_preserve_comments = false;
|
||||||
|
|
||||||
array_add(*libpaths, lib_directory);
|
array_add(*library_search_paths, lib_directory);
|
||||||
array_add(*libnames, LIB_BASE_NAME);
|
array_add(*libraries, .{ filename = LIB_BASE_NAME});
|
||||||
array_add(*source_files, tprint("%.h", LIB_BASE_NAME));
|
array_add(*source_files, tprint("%.h", LIB_BASE_NAME));
|
||||||
|
|
||||||
generate_library_declarations = false;
|
generate_library_declarations = false;
|
||||||
|
|||||||
@ -42,12 +42,45 @@
|
|||||||
API
|
API
|
||||||
Segmentation
|
Segmentation
|
||||||
kbts_BeginBreak()
|
kbts_BeginBreak()
|
||||||
kbts_BreakAddCodepoint() -- Feed a codepoint to the breaker, call kbts_Break() immediately after this to get results
|
kbts_BreakAddCodepoint() -- Feed a codepoint to the breaker.
|
||||||
|
You need to call Break() repeatedly after every call to BreakAddCodepoint().
|
||||||
|
Something like:
|
||||||
|
kbts_BreakAddCodepoint(&BreakState, ...);
|
||||||
|
kbts_break Break;
|
||||||
|
while(kbts_Break(&BreakState, &Break)) {...}
|
||||||
|
|
||||||
|
When you call Break(), We guarantee that breaks are returned in-order. On our side, this means
|
||||||
|
that they are buffered and reordered. On your side, it means that there is a delay of a few
|
||||||
|
characters between your current position and the Break.Position that you will see.
|
||||||
|
|
||||||
|
In some cases, our buffering might break. When that happens, we set
|
||||||
|
BREAK_STATE_FLAG_RAN_OUT_OF_REORDER_BUFFER_SPACE, and kbts_BreakStateIsValid() will return false.
|
||||||
|
This is a sticky error, so you can check it whenever you like.
|
||||||
|
To clear the error flag and start segmenting again, you will need to call BeginBreak(&BreakState),
|
||||||
|
which resets the entire state.
|
||||||
|
|
||||||
|
Note that the input configurations for which our buffering breaks should be, for all intents and
|
||||||
|
purposes, nonsensical. If you find legitimate text that we cannot segment without running out of
|
||||||
|
buffer space, then that is a bug.
|
||||||
|
|
||||||
|
The default buffer size is determined by the BREAK_REORDER_BUFFER_FLUSH_THRESHOLD. If you really
|
||||||
|
need a bigger buffer, then you might want to consider modifying this constant and recompiling
|
||||||
|
the library, although this should be viewed as an emergency solution and not a routine
|
||||||
|
configuration option.
|
||||||
kbts_BreakFlush()
|
kbts_BreakFlush()
|
||||||
kbts_Break() -- Call repeatedly to get breaks
|
kbts_Break() -- Call repeatedly to get breaks
|
||||||
kbts_BreakStateIsValid()
|
kbts_BreakStateIsValid()
|
||||||
Easy font loading
|
Easy font loading
|
||||||
kbts_FontFromFile() -- Open a font, byteswap it in place, and allocate auxiliary structures
|
kbts_FontFromFile() -- Open a font, byteswap it in place, and allocate auxiliary structures.
|
||||||
|
When you read a font with kb_text_shape, the library will byteswap its data in-place and perform
|
||||||
|
a bunch of other pre-computation passes to figure out memory limits and other useful information.
|
||||||
|
This means you cannot trivially pass our pointer to the font data to any other TTF library, since
|
||||||
|
they will expect the data to be in big endian format, which it won't be after we are done with it.
|
||||||
|
|
||||||
|
You can expect font reading to be pretty slow.
|
||||||
|
On the other hand, you can expect shaping to be pretty fast.
|
||||||
|
|
||||||
|
To open a font with your own IO and memory allocation, see "Manual Memory Management" below.
|
||||||
kbts_FreeFont()
|
kbts_FreeFont()
|
||||||
kbts_FontIsValid()
|
kbts_FontIsValid()
|
||||||
Shaping
|
Shaping
|
||||||
@ -56,7 +89,33 @@
|
|||||||
kbts_ShapeConfig() -- Bake a font/script-specific shaping configuration
|
kbts_ShapeConfig() -- Bake a font/script-specific shaping configuration
|
||||||
kbts_CodepointToGlyph()
|
kbts_CodepointToGlyph()
|
||||||
kbts_InferScript() -- Hacky script recognition for when no segmentation data is available
|
kbts_InferScript() -- Hacky script recognition for when no segmentation data is available
|
||||||
kbts_Shape() -- Returns 1 if more memory is needed, you should probably call this in a while()
|
kbts_Shape() -- Returns 1 if more memory is needed, you should probably call this in a while().
|
||||||
|
This is how you might call this in practice:
|
||||||
|
while(kbts_Shape(State, &Config, Direction, Direction, Glyphs, &GlyphCount, GlyphCapacity))
|
||||||
|
{
|
||||||
|
Glyphs = realloc(Glyphs, sizeof(kbts_glyph) * State->RequiredGlyphCapacity);
|
||||||
|
GlyphCapacity = State->RequiredGlyphCapacity;
|
||||||
|
}
|
||||||
|
Once Shape() returns 0, you are done shaping. Glyph indices are in the kbts_glyph.Id field.
|
||||||
|
Please note that, while the glyphs do also contain a Codepoint field, this field will mostly
|
||||||
|
be meaningless whenever complex shaping operations occur. This is because fonts exclusively
|
||||||
|
work on glyph indices, and a lot of ligatures are obviously a combination of several codepoints
|
||||||
|
and do not have a corresponding codepoint in the Unicode world.
|
||||||
|
The same is true when a single glyph is split into multiple glyphs. A font might decide to
|
||||||
|
decompose a letter-with-accent into a letter glyph + an accent glyph. In that case, we will
|
||||||
|
know what the accent glyph's index is, but we are not told what its codepoint is.
|
||||||
|
|
||||||
|
There is currently no way to track where in the source text each glyph originates from.
|
||||||
|
One thing we might try is to have a "void *UserData" member on each glyph, and flow it through
|
||||||
|
the different substitutions, but I personally have not needed this yet and I do not have good
|
||||||
|
test cases for it. If you are interested, let me know!
|
||||||
|
|
||||||
|
Final positions are in font units and can be extracted with Cursor() and PositionGlyph().
|
||||||
|
To convert font units to fractional pixels in FreeType:
|
||||||
|
(FontX * FtSizeMetrics.x_scale) >> 16
|
||||||
|
(FontY * FtSizeMetrics.y_scale) >> 16
|
||||||
|
This will give you 26.6 fractional pixel units.
|
||||||
|
See https://freetype.org/freetype2/docs/reference/ft2-sizing_and_scaling.html for more info.
|
||||||
kbts_ResetShapeState()
|
kbts_ResetShapeState()
|
||||||
Shaping - feature control
|
Shaping - feature control
|
||||||
kbts_FeatureOverride() -- Describe a manual override for a font feature
|
kbts_FeatureOverride() -- Describe a manual override for a font feature
|
||||||
@ -74,9 +133,24 @@
|
|||||||
Manual memory management
|
Manual memory management
|
||||||
kbts_SizeOfShapeState()
|
kbts_SizeOfShapeState()
|
||||||
kbts_PlaceShapeState()
|
kbts_PlaceShapeState()
|
||||||
kbts_ReadFontHeader() -- Read the top of the file and return how many bytes are needed to read the rest
|
kbts_ReadFontHeader() -- Read and byteswap the top of the file.
|
||||||
kbts_ReadFontData() -- Read and byteswap the rest
|
kbts_ReadFontData() -- Read and byteswap the rest.
|
||||||
kbts_PostReadFontInitialize() -- Initialize auxiliary structures
|
kbts_PostReadFontInitialize() -- Initialize auxiliary structures
|
||||||
|
Example code for reading a font file with this API looks like this:
|
||||||
|
size_t ScratchSize = kbts_ReadFontHeader(&Font, Data, Size);
|
||||||
|
size_t PermanentMemorySize = kbts_ReadFontData(&Font, malloc(ScratchSize), ScratchSize);
|
||||||
|
kbts_PostReadFontInitialize(&Font, malloc(PermanentMemorySize), PermanentMemorySize);
|
||||||
|
|
||||||
|
Please note that, AS SOON AS YOU CALL ReadFontHeader(), THE FONT DATA IS MODIFIED IN-PLACE.
|
||||||
|
AS SOON AS YOU CALL ReadFontHeader(), THE FONT DATA IS MODIFIED IN-PLACE.
|
||||||
|
AS SOON AS YOU CALL ReadFontHeader(), THE FONT DATA IS MODIFIED IN-PLACE.
|
||||||
|
AS SOON AS YOU CALL ReadFontHeader(), THE FONT DATA IS MODIFIED IN-PLACE!
|
||||||
|
If you need to open the same font with another library, you need to copy the data BEFORE
|
||||||
|
calling ReadFontHeader().
|
||||||
|
|
||||||
|
The buffer you pass to ReadFontData() is temporary and can be freed once the function returns.
|
||||||
|
The buffer you pass to PostReadFontInitialize() is persistent and can only be freed once you
|
||||||
|
are done with the font.
|
||||||
Utility, etc.
|
Utility, etc.
|
||||||
kbts_ShaperIsComplex()
|
kbts_ShaperIsComplex()
|
||||||
kbts_ScriptIsComplex()
|
kbts_ScriptIsComplex()
|
||||||
@ -98,7 +172,7 @@
|
|||||||
kbts_direction Direction = KBTS_DIRECTION_NONE;
|
kbts_direction Direction = KBTS_DIRECTION_NONE;
|
||||||
for(size_t StringAt = 0; StringAt < Length;)
|
for(size_t StringAt = 0; StringAt < Length;)
|
||||||
{
|
{
|
||||||
kbts_decode Decode = kbts_DecodeUtf8(String, Length - StringAt);
|
kbts_decode Decode = kbts_DecodeUtf8(String + StringAt, Length - StringAt);
|
||||||
StringAt += Decode.SourceCharactersConsumed;
|
StringAt += Decode.SourceCharactersConsumed;
|
||||||
if(Decode.Valid)
|
if(Decode.Valid)
|
||||||
{
|
{
|
||||||
@ -174,6 +248,7 @@
|
|||||||
|
|
||||||
Open a font with your own memory:
|
Open a font with your own memory:
|
||||||
kbts_font Font;
|
kbts_font Font;
|
||||||
|
// Be careful: ReadFontHeader() and ReadFontData() both byteswap font data in-place!
|
||||||
size_t ScratchSize = kbts_ReadFontHeader(&Font, Data, Size);
|
size_t ScratchSize = kbts_ReadFontHeader(&Font, Data, Size);
|
||||||
size_t PermanentMemorySize = kbts_ReadFontData(&Font, malloc(ScratchSize), ScratchSize);
|
size_t PermanentMemorySize = kbts_ReadFontData(&Font, malloc(ScratchSize), ScratchSize);
|
||||||
kbts_PostReadFontInitialize(&Font, malloc(PermanentMemorySize), PermanentMemorySize);
|
kbts_PostReadFontInitialize(&Font, malloc(PermanentMemorySize), PermanentMemorySize);
|
||||||
@ -3038,7 +3113,7 @@ static kbts_script_properties kbts_ScriptProperties[KBTS_SCRIPT_COUNT] = {
|
|||||||
KBTS_EXPORT kbts_script kbts_ScriptTagToScript(kbts_script_tag Tag)
|
KBTS_EXPORT kbts_script kbts_ScriptTagToScript(kbts_script_tag Tag)
|
||||||
{
|
{
|
||||||
kbts_script Result = 0;
|
kbts_script Result = 0;
|
||||||
switch(Result)
|
switch(Tag)
|
||||||
{
|
{
|
||||||
case KBTS_SCRIPT_TAG_DONT_KNOW: Result = KBTS_SCRIPT_DONT_KNOW; break;
|
case KBTS_SCRIPT_TAG_DONT_KNOW: Result = KBTS_SCRIPT_DONT_KNOW; break;
|
||||||
case KBTS_SCRIPT_TAG_ADLAM: Result = KBTS_SCRIPT_ADLAM; break;
|
case KBTS_SCRIPT_TAG_ADLAM: Result = KBTS_SCRIPT_ADLAM; break;
|
||||||
@ -15999,8 +16074,7 @@ KBTS_EXPORT kbts_glyph kbts_CodepointToGlyph(kbts_font *Font, kbts_u32 Codepoint
|
|||||||
{
|
{
|
||||||
Result.Id = Cmap0->GlyphIdArray[Codepoint];
|
Result.Id = Cmap0->GlyphIdArray[Codepoint];
|
||||||
}
|
}
|
||||||
}
|
} break;
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
@ -16041,8 +16115,7 @@ KBTS_EXPORT kbts_glyph kbts_CodepointToGlyph(kbts_font *Font, kbts_u32 Codepoint
|
|||||||
|
|
||||||
Result.Id = GlyphId;
|
Result.Id = GlyphId;
|
||||||
}
|
}
|
||||||
}
|
} break;
|
||||||
break;
|
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
{
|
{
|
||||||
@ -16052,31 +16125,36 @@ KBTS_EXPORT kbts_glyph kbts_CodepointToGlyph(kbts_font *Font, kbts_u32 Codepoint
|
|||||||
kbts_u16 *StartCodes = EndCodes + SegmentCount + 1;
|
kbts_u16 *StartCodes = EndCodes + SegmentCount + 1;
|
||||||
kbts_s16 *IdDeltas = (kbts_s16 *)(StartCodes + SegmentCount);
|
kbts_s16 *IdDeltas = (kbts_s16 *)(StartCodes + SegmentCount);
|
||||||
kbts_u16 *IdRangeOffsets = (kbts_u16 *)(IdDeltas + SegmentCount);
|
kbts_u16 *IdRangeOffsets = (kbts_u16 *)(IdDeltas + SegmentCount);
|
||||||
|
kbts_un SegmentIndexOffset = 0;
|
||||||
|
|
||||||
KBTS_FOR(SegmentIndex, 0, SegmentCount)
|
if(SegmentCount)
|
||||||
{
|
{
|
||||||
kbts_u16 Start = StartCodes[SegmentIndex];
|
while(SegmentCount > 1)
|
||||||
if((Codepoint >= Start) && (Codepoint <= EndCodes[SegmentIndex]))
|
|
||||||
{
|
{
|
||||||
kbts_s16 Delta = IdDeltas[SegmentIndex];
|
kbts_un HalfCount = SegmentCount / 2;
|
||||||
kbts_u16 RangeOffset = IdRangeOffsets[SegmentIndex];
|
SegmentIndexOffset = (EndCodes[SegmentIndexOffset + HalfCount - 1] < Codepoint) ? (SegmentIndexOffset + HalfCount) : SegmentIndexOffset;
|
||||||
|
SegmentCount -= HalfCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kbts_u16 Start = StartCodes[SegmentIndexOffset];
|
||||||
|
if((Codepoint >= Start) && (Codepoint <= EndCodes[SegmentIndexOffset]))
|
||||||
|
{
|
||||||
|
kbts_s16 Delta = IdDeltas[SegmentIndexOffset];
|
||||||
|
kbts_u16 RangeOffset = IdRangeOffsets[SegmentIndexOffset];
|
||||||
|
|
||||||
kbts_u16 GlyphId = (kbts_u16)Delta;
|
kbts_u16 GlyphId = (kbts_u16)Delta;
|
||||||
if(RangeOffset)
|
if(RangeOffset)
|
||||||
{
|
{
|
||||||
GlyphId += *(&IdRangeOffsets[SegmentIndex] + (Codepoint - Start) + RangeOffset / 2);
|
GlyphId += *(&IdRangeOffsets[SegmentIndexOffset] + (Codepoint - Start) + RangeOffset / 2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GlyphId += (kbts_u16)(Codepoint);
|
GlyphId += (kbts_u16)(Codepoint);
|
||||||
}
|
}
|
||||||
Result.Id = GlyphId;
|
Result.Id = GlyphId;
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
} break;
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 6:
|
case 6:
|
||||||
{
|
{
|
||||||
@ -16088,8 +16166,7 @@ KBTS_EXPORT kbts_glyph kbts_CodepointToGlyph(kbts_font *Font, kbts_u32 Codepoint
|
|||||||
{
|
{
|
||||||
Result.Id = GlyphIds[Offset];
|
Result.Id = GlyphIds[Offset];
|
||||||
}
|
}
|
||||||
}
|
} break;
|
||||||
break;
|
|
||||||
|
|
||||||
case 12:
|
case 12:
|
||||||
{
|
{
|
||||||
@ -16097,22 +16174,25 @@ KBTS_EXPORT kbts_glyph kbts_CodepointToGlyph(kbts_font *Font, kbts_u32 Codepoint
|
|||||||
kbts_sequential_map_group *Groups = KBTS_POINTER_AFTER(kbts_sequential_map_group, Cmap12);
|
kbts_sequential_map_group *Groups = KBTS_POINTER_AFTER(kbts_sequential_map_group, Cmap12);
|
||||||
|
|
||||||
kbts_un GlyphId = 0;
|
kbts_un GlyphId = 0;
|
||||||
KBTS_FOR(GroupIndex, 0, Cmap12->GroupCount)
|
kbts_un GroupCount = Cmap12->GroupCount;
|
||||||
|
if(GroupCount)
|
||||||
{
|
{
|
||||||
kbts_sequential_map_group *Group = &Groups[GroupIndex];
|
while(GroupCount > 1)
|
||||||
|
|
||||||
if((Codepoint >= Group->StartCharacterCode) && (Codepoint <= Group->EndCharacterCode))
|
|
||||||
{
|
{
|
||||||
kbts_un Offset = Codepoint - Group->StartCharacterCode;
|
kbts_un HalfCount = GroupCount / 2;
|
||||||
GlyphId = Group->StartGlyphId + Offset;
|
Groups = (Groups[HalfCount - 1].EndCharacterCode < Codepoint) ? (Groups + HalfCount) : Groups;
|
||||||
|
GroupCount -= HalfCount;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if((Codepoint >= Groups->StartCharacterCode) && (Codepoint <= Groups->EndCharacterCode))
|
||||||
|
{
|
||||||
|
kbts_un Offset = Codepoint - Groups->StartCharacterCode;
|
||||||
|
GlyphId = Groups->StartGlyphId + Offset;
|
||||||
|
}
|
||||||
|
|
||||||
Result.Id = (kbts_u16)GlyphId;
|
Result.Id = (kbts_u16)GlyphId;
|
||||||
}
|
} break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// This file was auto-generated using the following command:
|
// This file was auto-generated using the following command:
|
||||||
//
|
//
|
||||||
// jai generate.jai - -compile -debug
|
// jai generate.jai
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
@ -15,7 +15,8 @@ KBTS_MAX_SIMULTANEOUS_FEATURES :: 16;
|
|||||||
KBTS_BREAK_REORDER_BUFFER_FLUSH_THRESHOLD :: 4;
|
KBTS_BREAK_REORDER_BUFFER_FLUSH_THRESHOLD :: 4;
|
||||||
KBTS_BREAK_REORDER_BUFFER_SIZE :: KBTS_BREAK_REORDER_BUFFER_FLUSH_THRESHOLD * 2;
|
KBTS_BREAK_REORDER_BUFFER_SIZE :: KBTS_BREAK_REORDER_BUFFER_FLUSH_THRESHOLD * 2;
|
||||||
|
|
||||||
kbts_joining_feature :: enum u8 {
|
kbts_joining_feature :: u8;
|
||||||
|
kbts_joining_feature_enum :: enum s32 {
|
||||||
NONE :: 0;
|
NONE :: 0;
|
||||||
|
|
||||||
ISOL :: 1;
|
ISOL :: 1;
|
||||||
@ -41,7 +42,8 @@ kbts_joining_feature :: enum u8 {
|
|||||||
KBTS_JOINING_FEATURE_COUNT :: COUNT;
|
KBTS_JOINING_FEATURE_COUNT :: COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbts_reph_position :: enum u8 {
|
kbts_reph_position :: u8;
|
||||||
|
kbts_reph_position_enum :: enum s32 {
|
||||||
AFTER_POST :: 0;
|
AFTER_POST :: 0;
|
||||||
BEFORE_POST :: 1;
|
BEFORE_POST :: 1;
|
||||||
BEFORE_SUBJOINED :: 2;
|
BEFORE_SUBJOINED :: 2;
|
||||||
@ -59,7 +61,8 @@ kbts_reph_position :: enum u8 {
|
|||||||
KBTS_REPH_POSITION_COUNT :: COUNT;
|
KBTS_REPH_POSITION_COUNT :: COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbts_reph_encoding :: enum u8 {
|
kbts_reph_encoding :: u8;
|
||||||
|
kbts_reph_encoding_enum :: enum s32 {
|
||||||
IMPLICIT :: 0;
|
IMPLICIT :: 0;
|
||||||
EXPLICIT :: 1;
|
EXPLICIT :: 1;
|
||||||
LOGICAL_REPHA :: 2;
|
LOGICAL_REPHA :: 2;
|
||||||
@ -75,7 +78,8 @@ kbts_reph_encoding :: enum u8 {
|
|||||||
KBTS_REPH_ENCODING_COUNT :: COUNT;
|
KBTS_REPH_ENCODING_COUNT :: COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbts_syllabic_position :: enum u8 {
|
kbts_syllabic_position :: u8;
|
||||||
|
kbts_syllabic_position_enum :: enum s32 {
|
||||||
NONE :: 0;
|
NONE :: 0;
|
||||||
|
|
||||||
RA_TO_BECOME_REPH :: 1;
|
RA_TO_BECOME_REPH :: 1;
|
||||||
@ -1533,7 +1537,8 @@ kbts_break_flags :: enum u32 {
|
|||||||
KBTS_BREAK_FLAG_ANY :: ANY;
|
KBTS_BREAK_FLAG_ANY :: ANY;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbts_op_kind :: enum u8 {
|
kbts_op_kind :: u8;
|
||||||
|
kbts_op_kind_enum :: enum s32 {
|
||||||
END :: 0;
|
END :: 0;
|
||||||
|
|
||||||
PRE_NORMALIZE_DOTTED_CIRCLES :: 1;
|
PRE_NORMALIZE_DOTTED_CIRCLES :: 1;
|
||||||
@ -1569,7 +1574,8 @@ kbts_op_kind :: enum u8 {
|
|||||||
KBTS_OP_KIND_COUNT :: COUNT;
|
KBTS_OP_KIND_COUNT :: COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbts_glyph_flags :: enum u32 {
|
kbts_glyph_flags :: u32;
|
||||||
|
kbts_glyph_flags_enum :: enum s32 {
|
||||||
ISOL :: 1;
|
ISOL :: 1;
|
||||||
FINA :: 2;
|
FINA :: 2;
|
||||||
FIN2 :: 4;
|
FIN2 :: 4;
|
||||||
@ -1659,7 +1665,8 @@ kbts_japanese_line_break_style :: enum u8 {
|
|||||||
KBTS_JAPANESE_LINE_BREAK_STYLE_COUNT :: COUNT;
|
KBTS_JAPANESE_LINE_BREAK_STYLE_COUNT :: COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbts_orientation :: enum u32 {
|
kbts_orientation :: u32;
|
||||||
|
kbts_orientation_enum :: enum s32 {
|
||||||
HORIZONTAL :: 0;
|
HORIZONTAL :: 0;
|
||||||
VERTICAL :: 1;
|
VERTICAL :: 1;
|
||||||
|
|
||||||
@ -1685,7 +1692,8 @@ kbts_direction :: enum u32 {
|
|||||||
KBTS_DIRECTION_COUNT :: COUNT;
|
KBTS_DIRECTION_COUNT :: COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbts_unicode_joining_type :: enum u8 {
|
kbts_unicode_joining_type :: u8;
|
||||||
|
kbts_unicode_joining_type_enum :: enum s32 {
|
||||||
NONE :: 0;
|
NONE :: 0;
|
||||||
LEFT :: 1;
|
LEFT :: 1;
|
||||||
DUAL :: 2;
|
DUAL :: 2;
|
||||||
@ -1722,7 +1730,8 @@ kbts_unicode_flag_enum :: enum s32 {
|
|||||||
KBTS_UNICODE_FLAG_NON_SPACING_MARK :: NON_SPACING_MARK;
|
KBTS_UNICODE_FLAG_NON_SPACING_MARK :: NON_SPACING_MARK;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbts_unicode_bidirectional_class :: enum u8 {
|
kbts_unicode_bidirectional_class :: u8;
|
||||||
|
kbts_unicode_bidirectional_class_enum :: enum s32 {
|
||||||
NI :: 0;
|
NI :: 0;
|
||||||
L :: 1;
|
L :: 1;
|
||||||
R :: 2;
|
R :: 2;
|
||||||
@ -1748,7 +1757,8 @@ kbts_unicode_bidirectional_class :: enum u8 {
|
|||||||
KBTS_UNICODE_BIDIRECTIONAL_CLASS_COUNT :: COUNT;
|
KBTS_UNICODE_BIDIRECTIONAL_CLASS_COUNT :: COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbts_line_break_class :: enum u8 {
|
kbts_line_break_class :: u8;
|
||||||
|
kbts_line_break_class_enum :: enum s32 {
|
||||||
Onea :: 0;
|
Onea :: 0;
|
||||||
Oea :: 1;
|
Oea :: 1;
|
||||||
Ope :: 2;
|
Ope :: 2;
|
||||||
@ -1896,7 +1906,8 @@ kbts_line_break_class :: enum u8 {
|
|||||||
KBTS_LINE_BREAK_CLASS_EOT :: EOT;
|
KBTS_LINE_BREAK_CLASS_EOT :: EOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbts_word_break_class :: enum u8 {
|
kbts_word_break_class :: u8;
|
||||||
|
kbts_word_break_class_enum :: enum s32 {
|
||||||
Onep :: 0;
|
Onep :: 0;
|
||||||
Oep :: 1;
|
Oep :: 1;
|
||||||
CR :: 2;
|
CR :: 2;
|
||||||
@ -1946,7 +1957,8 @@ kbts_word_break_class :: enum u8 {
|
|||||||
KBTS_WORD_BREAK_CLASS_SOT :: SOT;
|
KBTS_WORD_BREAK_CLASS_SOT :: SOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbts_shaper :: enum u32 {
|
kbts_shaper :: u32;
|
||||||
|
kbts_shaper_enum :: enum s32 {
|
||||||
DEFAULT :: 0;
|
DEFAULT :: 0;
|
||||||
ARABIC :: 1;
|
ARABIC :: 1;
|
||||||
HANGUL :: 2;
|
HANGUL :: 2;
|
||||||
@ -1972,7 +1984,8 @@ kbts_shaper :: enum u32 {
|
|||||||
KBTS_SHAPER_COUNT :: COUNT;
|
KBTS_SHAPER_COUNT :: COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbts_script_tag :: enum u32 {
|
kbts_script_tag :: u32;
|
||||||
|
kbts_script_tag_enum :: enum s32 {
|
||||||
DONT_KNOW :: 538976288;
|
DONT_KNOW :: 538976288;
|
||||||
ADLAM :: 1835820129;
|
ADLAM :: 1835820129;
|
||||||
AHOM :: 1836017761;
|
AHOM :: 1836017761;
|
||||||
@ -2662,7 +2675,8 @@ kbts_script :: enum u32 {
|
|||||||
KBTS_SCRIPT_COUNT :: COUNT;
|
KBTS_SCRIPT_COUNT :: COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbts_feature_tag :: enum u32 {
|
kbts_feature_tag :: u32;
|
||||||
|
kbts_feature_tag_enum :: enum s32 {
|
||||||
UNREGISTERED :: 0;
|
UNREGISTERED :: 0;
|
||||||
isol :: 1819243369;
|
isol :: 1819243369;
|
||||||
fina :: 1634625894;
|
fina :: 1634625894;
|
||||||
@ -2693,7 +2707,7 @@ kbts_feature_tag :: enum u32 {
|
|||||||
blwm :: 1836543074;
|
blwm :: 1836543074;
|
||||||
blws :: 1937206370;
|
blws :: 1937206370;
|
||||||
calt :: 1953259875;
|
calt :: 1953259875;
|
||||||
case_ :: 1702060387;
|
_case :: 1702060387;
|
||||||
ccmp :: 1886217059;
|
ccmp :: 1886217059;
|
||||||
chws :: 1937205347;
|
chws :: 1937205347;
|
||||||
cjct :: 1952672355;
|
cjct :: 1952672355;
|
||||||
@ -2939,7 +2953,7 @@ kbts_feature_tag :: enum u32 {
|
|||||||
KBTS_FEATURE_TAG_blwm :: blwm;
|
KBTS_FEATURE_TAG_blwm :: blwm;
|
||||||
KBTS_FEATURE_TAG_blws :: blws;
|
KBTS_FEATURE_TAG_blws :: blws;
|
||||||
KBTS_FEATURE_TAG_calt :: calt;
|
KBTS_FEATURE_TAG_calt :: calt;
|
||||||
KBTS_FEATURE_TAG_case :: case_;
|
KBTS_FEATURE_TAG_case :: _case;
|
||||||
KBTS_FEATURE_TAG_ccmp :: ccmp;
|
KBTS_FEATURE_TAG_ccmp :: ccmp;
|
||||||
KBTS_FEATURE_TAG_chws :: chws;
|
KBTS_FEATURE_TAG_chws :: chws;
|
||||||
KBTS_FEATURE_TAG_cjct :: cjct;
|
KBTS_FEATURE_TAG_cjct :: cjct;
|
||||||
@ -3156,7 +3170,8 @@ kbts_feature_tag :: enum u32 {
|
|||||||
KBTS_FEATURE_TAG_zero :: zero;
|
KBTS_FEATURE_TAG_zero :: zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbts_feature_id :: enum u32 {
|
kbts_feature_id :: u32;
|
||||||
|
kbts_feature_id_enum :: enum s32 {
|
||||||
UNREGISTERED :: 0;
|
UNREGISTERED :: 0;
|
||||||
isol :: 1;
|
isol :: 1;
|
||||||
fina :: 2;
|
fina :: 2;
|
||||||
@ -3187,7 +3202,7 @@ kbts_feature_id :: enum u32 {
|
|||||||
blwm :: 27;
|
blwm :: 27;
|
||||||
blws :: 28;
|
blws :: 28;
|
||||||
calt :: 29;
|
calt :: 29;
|
||||||
case_ :: 30;
|
_case :: 30;
|
||||||
ccmp :: 31;
|
ccmp :: 31;
|
||||||
chws :: 32;
|
chws :: 32;
|
||||||
cjct :: 33;
|
cjct :: 33;
|
||||||
@ -3434,7 +3449,7 @@ kbts_feature_id :: enum u32 {
|
|||||||
KBTS_FEATURE_ID_blwm :: blwm;
|
KBTS_FEATURE_ID_blwm :: blwm;
|
||||||
KBTS_FEATURE_ID_blws :: blws;
|
KBTS_FEATURE_ID_blws :: blws;
|
||||||
KBTS_FEATURE_ID_calt :: calt;
|
KBTS_FEATURE_ID_calt :: calt;
|
||||||
KBTS_FEATURE_ID_case :: case_;
|
KBTS_FEATURE_ID_case :: _case;
|
||||||
KBTS_FEATURE_ID_ccmp :: ccmp;
|
KBTS_FEATURE_ID_ccmp :: ccmp;
|
||||||
KBTS_FEATURE_ID_chws :: chws;
|
KBTS_FEATURE_ID_chws :: chws;
|
||||||
KBTS_FEATURE_ID_cjct :: cjct;
|
KBTS_FEATURE_ID_cjct :: cjct;
|
||||||
@ -3652,7 +3667,8 @@ kbts_feature_id :: enum u32 {
|
|||||||
KBTS_FEATURE_ID_COUNT :: COUNT;
|
KBTS_FEATURE_ID_COUNT :: COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbts_shaping_table :: enum u8 {
|
kbts_shaping_table :: u8;
|
||||||
|
kbts_shaping_table_enum :: enum s32 {
|
||||||
GSUB :: 0;
|
GSUB :: 0;
|
||||||
GPOS :: 1;
|
GPOS :: 1;
|
||||||
COUNT :: 2;
|
COUNT :: 2;
|
||||||
@ -3932,7 +3948,8 @@ kbts_bracket :: struct {
|
|||||||
Script: u8;
|
Script: u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbts_break_state_flags :: enum u32 {
|
kbts_break_state_flags :: u32;
|
||||||
|
kbts_break_state_flags_enum :: enum s32 {
|
||||||
STARTED :: 1;
|
STARTED :: 1;
|
||||||
END :: 2;
|
END :: 2;
|
||||||
RAN_OUT_OF_REORDER_BUFFER_SPACE :: 4;
|
RAN_OUT_OF_REORDER_BUFFER_SPACE :: 4;
|
||||||
|
|||||||
6
src/.build/.added_strings_w2.jai
Normal file
6
src/.build/.added_strings_w2.jai
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// Workspace: Target Program
|
||||||
|
|
||||||
|
//
|
||||||
|
// String added via add_build_string() from C:/Users/vfs/Dev/Jails/bin/metaprogram/jails_diagnostics.jai:19.
|
||||||
|
//
|
||||||
|
JAILS_DIAGNOSTICS_BUILD :: true;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
#import "Basic";
|
#import "Basic";
|
||||||
#import "GL";
|
#import "GL";
|
||||||
#import "freetype-2.12.1";
|
#import "freetype";
|
||||||
#import "Hash_Table";
|
#import "Hash_Table";
|
||||||
#import "Math";
|
#import "Math";
|
||||||
#import "File";
|
#import "File";
|
||||||
|
|||||||
@ -278,6 +278,8 @@
|
|||||||
|
|
||||||
STB_TEXTEDIT_STRING :: TextInput;
|
STB_TEXTEDIT_STRING :: TextInput;
|
||||||
|
|
||||||
|
STB_TEXTEDIT_GETWIDTH_NEWLINE :: -1.0;
|
||||||
|
|
||||||
STB_TEXTEDIT_STRINGLEN :: (obj: *STB_TEXTEDIT_STRING) -> s32 {
|
STB_TEXTEDIT_STRINGLEN :: (obj: *STB_TEXTEDIT_STRING) -> s32 {
|
||||||
return xx obj.text.count;
|
return xx obj.text.count;
|
||||||
}
|
}
|
||||||
@ -306,6 +308,7 @@ STB_TEXTEDIT_INSERTCHARS :: (obj: *STB_TEXTEDIT_STRING, i: s32, c: *STB_TEXTEDIT
|
|||||||
|
|
||||||
len := obj.text.count;
|
len := obj.text.count;
|
||||||
|
|
||||||
|
// if the string is empty add an initial new line.
|
||||||
if n + len > obj.text.count {
|
if n + len > obj.text.count {
|
||||||
array_resize(*obj.text, n + len);
|
array_resize(*obj.text, n + len);
|
||||||
}
|
}
|
||||||
@ -324,12 +327,23 @@ STB_TEXTEDIT_INSERTCHARS :: (obj: *STB_TEXTEDIT_STRING, i: s32, c: *STB_TEXTEDIT
|
|||||||
|
|
||||||
STB_TEXTEDIT_LAYOUTROW :: (row: *StbTexteditRow, obj: *STB_TEXTEDIT_STRING, n: s32) {
|
STB_TEXTEDIT_LAYOUTROW :: (row: *StbTexteditRow, obj: *STB_TEXTEDIT_STRING, n: s32) {
|
||||||
idx : s32;
|
idx : s32;
|
||||||
if n + idx < obj.text.count && row.x1 < obj.max_size.x - (2 * obj.margin + 2 * obj.border_size + 2 * obj.padding) {
|
|
||||||
|
size, max_descent, read := next_line_size(obj.font, obj.text, n + idx, obj.max_size.x - (2 * obj.margin + 2 * obj.border_size + 2 * obj.padding));
|
||||||
|
row.x1 = size.x;
|
||||||
|
row.baseline_y_delta = size.y;
|
||||||
|
row.ymin = max_descent;
|
||||||
|
row.ymax = size.y - row.ymin;
|
||||||
|
row.num_chars = read;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
if n + idx < obj.text.count && row.x1 <= obj.max_size.x - (2 * obj.margin + 2 * obj.border_size + 2 * obj.padding) {
|
||||||
size, max_descent, read := next_line_size(obj.font, obj.text, n + idx, obj.max_size.x - (2 * obj.margin + 2 * obj.border_size + 2 * obj.padding));
|
size, max_descent, read := next_line_size(obj.font, obj.text, n + idx, obj.max_size.x - (2 * obj.margin + 2 * obj.border_size + 2 * obj.padding));
|
||||||
|
|
||||||
if row.x1 + size.x > obj.max_size.x - (2 * obj.margin + 2 * obj.border_size + 2 * obj.padding) {
|
if row.x1 + size.x > obj.max_size.x - (2 * obj.margin + 2 * obj.border_size + 2 * obj.padding) {
|
||||||
|
|
||||||
while word := n + idx < obj.text.count && row.x1 < obj.max_size.x - (2 * obj.margin + 2 * obj.border_size + 2 * obj.padding) {
|
while word := n + idx < obj.text.count && row.x1 <= obj.max_size.x - (2 * obj.margin + 2 * obj.border_size + 2 * obj.padding) {
|
||||||
size, max_descent, read := next_word_size(obj.font, obj.text, n + idx, obj.max_size.x - (2 * obj.margin + 2 * obj.border_size + 2 * obj.padding));
|
size, max_descent, read := next_word_size(obj.font, obj.text, n + idx, obj.max_size.x - (2 * obj.margin + 2 * obj.border_size + 2 * obj.padding));
|
||||||
|
|
||||||
if row.x1 + size.x > obj.max_size.x - (2 * obj.margin + 2 * obj.border_size + 2 * obj.padding) {
|
if row.x1 + size.x > obj.max_size.x - (2 * obj.margin + 2 * obj.border_size + 2 * obj.padding) {
|
||||||
@ -337,7 +351,6 @@ STB_TEXTEDIT_LAYOUTROW :: (row: *StbTexteditRow, obj: *STB_TEXTEDIT_STRING, n: s
|
|||||||
size, max_descent, read := next_grapheme_size(obj.font, obj.text, n + idx, obj.max_size.x - (2 * obj.margin + 2 * obj.border_size + 2 * obj.padding));
|
size, max_descent, read := next_grapheme_size(obj.font, obj.text, n + idx, obj.max_size.x - (2 * obj.margin + 2 * obj.border_size + 2 * obj.padding));
|
||||||
|
|
||||||
if row.x1 + size.x > obj.max_size.x - (2 * obj.margin + 2 * obj.border_size + 2 * obj.padding) {
|
if row.x1 + size.x > obj.max_size.x - (2 * obj.margin + 2 * obj.border_size + 2 * obj.padding) {
|
||||||
//break word;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,14 +370,13 @@ STB_TEXTEDIT_LAYOUTROW :: (row: *StbTexteditRow, obj: *STB_TEXTEDIT_STRING, n: s
|
|||||||
row.num_chars += read;
|
row.num_chars += read;
|
||||||
idx += read;
|
idx += read;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
row.x1 = size.x;
|
||||||
|
row.baseline_y_delta = size.y;
|
||||||
|
row.ymin = max_descent;
|
||||||
|
row.ymax = size.y - row.ymin;
|
||||||
|
row.num_chars = read;
|
||||||
}
|
}
|
||||||
|
|
||||||
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.x0 = 0.0;
|
row.x0 = 0.0;
|
||||||
@ -373,37 +385,54 @@ 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 {
|
||||||
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 - n);
|
||||||
|
|
||||||
Cursor : kbts_cursor;
|
Cursor : kbts_cursor;
|
||||||
Direction : kbts_direction = .NONE;
|
Direction : kbts_direction = .NONE;
|
||||||
Script : kbts_script = .DONT_KNOW;
|
Script : kbts_script = .DONT_KNOW;
|
||||||
RunStart : u64 = 0;
|
RunStart : u64 = 0;
|
||||||
|
|
||||||
BreakState : kbts_break_state;
|
BreakState : kbts_break_state;
|
||||||
kbts_BeginBreak(*BreakState, .NONE, .NORMAL);
|
kbts_BeginBreak(*BreakState, .NONE, .NORMAL);
|
||||||
|
|
||||||
width : float;
|
width : float;
|
||||||
|
|
||||||
CodepointIndex : u64;
|
CodepointIndex : s32 = 0;
|
||||||
while CodepointIndex <= xx i {
|
while CodepointIndex < xx CodepointCount {
|
||||||
kbts_BreakAddCodepoint(*BreakState, Codepoints[CodepointIndex], 1, xx ((CodepointIndex + 1) == xx CodepointCount));
|
kbts_BreakAddCodepoint(*BreakState, Codepoints[CodepointIndex], 1, xx ((CodepointIndex + 1) == xx CodepointCount));
|
||||||
Break : kbts_break;
|
Break : kbts_break;
|
||||||
while kbts_Break(*BreakState, *Break) {
|
while kbts_Break(*BreakState, *Break) {
|
||||||
|
// if (Break.Position > RunStart) && (Break.Flags & (KBTS_BREAK_FLAG_DIRECTION | KBTS_BREAK_FLAG_SCRIPT | KBTS_BREAK_FLAG_LINE_HARD)) {
|
||||||
if Break.Flags & .DIRECTION {
|
// RunLength : int = Break.Position - RunStart;
|
||||||
Direction = Break.Direction;
|
// ShapeText(*Cursor, Codepoints + RunStart, RunLength, BreakState.MainDirection, Direction, Script);
|
||||||
if(!Cursor.Direction) Cursor = kbts_Cursor(BreakState.MainDirection);
|
// RunStart = Break.Position;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if Break.Flags & .SCRIPT {
|
|
||||||
Script = Break.Script;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Break.Position > RunStart) && (Break.Flags & .GRAPHEME) {
|
if (Break.Position > RunStart) && (Break.Flags & .GRAPHEME) {
|
||||||
RunLength : u64 = Break.Position - RunStart;
|
RunLength : u64 = Break.Position - RunStart;
|
||||||
size, max_descent := ShapeText(obj.font, *Cursor, Codepoints + RunStart, RunLength, BreakState.MainDirection, Direction, Script);
|
size, max_descent := ShapeText(obj.font, *Cursor, Codepoints + RunStart, RunLength, BreakState.MainDirection, Direction, Script);
|
||||||
|
|
||||||
width = size.x;
|
width = size.x;
|
||||||
|
log("Grapheme: % Position: % Run Length: %, width: %", Codepoints[Break.Position - 1], Break.Position, RunLength, width);
|
||||||
|
if Break.Position == xx (i + 1) {
|
||||||
|
if Codepoints[Break.Position - 1] == STB_TEXTEDIT_NEWLINE {
|
||||||
|
width = STB_TEXTEDIT_GETWIDTH_NEWLINE;
|
||||||
|
return width;
|
||||||
|
} else {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RunStart = Break.Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
if Break.Flags & .DIRECTION {
|
||||||
|
Direction = Break.Direction;
|
||||||
|
|
||||||
|
if !Cursor.Direction Cursor = kbts_Cursor(BreakState.MainDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
if Break.Flags & .SCRIPT {
|
||||||
|
Script = Break.Script;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,6 +440,95 @@ STB_TEXTEDIT_GETWIDTH :: (obj: *STB_TEXTEDIT_STRING, n: s32, i: s32) -> float {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return width;
|
return width;
|
||||||
|
|
||||||
|
// Cursor : kbts_cursor;
|
||||||
|
// Direction : kbts_direction = .NONE;
|
||||||
|
// Script : kbts_script = .DONT_KNOW;
|
||||||
|
// RunStart : u64 = 0;
|
||||||
|
// BreakState : kbts_break_state;
|
||||||
|
// kbts_BeginBreak(*BreakState, .NONE, .NORMAL);
|
||||||
|
|
||||||
|
// width : float;
|
||||||
|
|
||||||
|
// CodepointIndex : u64;
|
||||||
|
// while CodepointIndex < 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.Flags & .GRAPHEME {
|
||||||
|
// RunLength : u64 = Break.Position - RunStart;
|
||||||
|
// if RunLength == 0 continue;
|
||||||
|
// size, max_descent := ShapeText(obj.font, *Cursor, Codepoints + RunStart, RunLength, BreakState.MainDirection, Direction, Script);
|
||||||
|
// width = size.x;
|
||||||
|
// if Break.Position == xx max(i, 1) {
|
||||||
|
// if Codepoints[Break.Position] == STB_TEXTEDIT_NEWLINE {
|
||||||
|
// width = STB_TEXTEDIT_GETWIDTH_NEWLINE;
|
||||||
|
// log("Grapheme: % Position: % Run Length: %, width: %", Codepoints[Break.Position], Break.Position, RunLength, width);
|
||||||
|
// return width;
|
||||||
|
// } else {
|
||||||
|
// log("Grapheme: % Position: % Run Length: %, width: %", Codepoints[Break.Position], Break.Position, RunLength, width);
|
||||||
|
// return width;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// RunStart = Break.Position;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if Break.Flags & .WORD {
|
||||||
|
// RunLength : u64 = Break.Position - RunStart;
|
||||||
|
// log("Word: Position: % Run Length: %", Break.Position, RunLength);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if Break.Flags & .LINE_SOFT {
|
||||||
|
// RunLength : u64 = Break.Position - RunStart;
|
||||||
|
// log("Line Soft: Position: % Run Length: %", Break.Position, RunLength);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if Break.Flags & .LINE_HARD {
|
||||||
|
// RunLength : u64 = Break.Position - RunStart;
|
||||||
|
// log("Line Hard: Position: % Run Length: %", Break.Position, RunLength);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // if (Break.Position >= RunStart) && (Break.Flags & .ANY) {
|
||||||
|
// // RunLength : u64 = Break.Position - RunStart;
|
||||||
|
// // if RunLength == 0 {
|
||||||
|
// // size, max_descent := ShapeText(obj.font, *Cursor, Codepoints + RunStart, RunLength, BreakState.MainDirection, Direction, Script);
|
||||||
|
|
||||||
|
// // if Codepoints[Break.Position] == STB_TEXTEDIT_NEWLINE {
|
||||||
|
// // width = STB_TEXTEDIT_GETWIDTH_NEWLINE;
|
||||||
|
// // return width;
|
||||||
|
// // } else {
|
||||||
|
// // width = size.x;
|
||||||
|
// // }
|
||||||
|
// // } else if RunLength > 0 {
|
||||||
|
// // size, max_descent := ShapeText(obj.font, *Cursor, Codepoints + RunStart, RunLength, BreakState.MainDirection, Direction, Script);
|
||||||
|
|
||||||
|
// // if Codepoints[Break.Position] == STB_TEXTEDIT_NEWLINE {
|
||||||
|
// // width = STB_TEXTEDIT_GETWIDTH_NEWLINE;
|
||||||
|
// // return width;
|
||||||
|
// // } else {
|
||||||
|
// // width = size.x;
|
||||||
|
// // return width;
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// CodepointIndex += 1;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
STB_TEXTEDIT_K_LEFT :: 0x200000; // keyboard input to move cursor left
|
STB_TEXTEDIT_K_LEFT :: 0x200000; // keyboard input to move cursor left
|
||||||
@ -558,6 +676,7 @@ stb_text_locate_coord :: (str: *STB_TEXTEDIT_STRING, x: float, y: float) -> s32
|
|||||||
|
|
||||||
// search rows to find one that straddles 'y'
|
// search rows to find one that straddles 'y'
|
||||||
while i < n {
|
while i < n {
|
||||||
|
r = .{};
|
||||||
STB_TEXTEDIT_LAYOUTROW(*r, str, i);
|
STB_TEXTEDIT_LAYOUTROW(*r, str, i);
|
||||||
if r.num_chars <= 0
|
if r.num_chars <= 0
|
||||||
return n;
|
return n;
|
||||||
@ -669,10 +788,11 @@ stb_textedit_find_charpos :: (find: *StbFindState, str: *STB_TEXTEDIT_STRING, n:
|
|||||||
i : s32 = 0;
|
i : s32 = 0;
|
||||||
first : s32;
|
first : s32;
|
||||||
|
|
||||||
if n == z {
|
if (str.text[str.text.count - 1] == STB_TEXTEDIT_NEWLINE && n == z - 1) || (n == z) {
|
||||||
// if it's at the end, then find the last line -- simpler than trying to
|
// if it's at the end, then find the last line -- simpler than trying to
|
||||||
// explicitly handle this case in the regular code
|
// explicitly handle this case in the regular code
|
||||||
if single_line {
|
if single_line {
|
||||||
|
r = .{};
|
||||||
STB_TEXTEDIT_LAYOUTROW(*r, str, 0);
|
STB_TEXTEDIT_LAYOUTROW(*r, str, 0);
|
||||||
find.y = 0;
|
find.y = 0;
|
||||||
find.first_char = 0;
|
find.first_char = 0;
|
||||||
@ -684,13 +804,27 @@ stb_textedit_find_charpos :: (find: *StbFindState, str: *STB_TEXTEDIT_STRING, n:
|
|||||||
find.x = 0;
|
find.x = 0;
|
||||||
find.height = 1;
|
find.height = 1;
|
||||||
while (i < z) {
|
while (i < z) {
|
||||||
|
r = .{};
|
||||||
STB_TEXTEDIT_LAYOUTROW(*r, str, i);
|
STB_TEXTEDIT_LAYOUTROW(*r, str, i);
|
||||||
|
if i + r.num_chars == z {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
prev_start = i;
|
prev_start = i;
|
||||||
i += r.num_chars;
|
i += r.num_chars;
|
||||||
}
|
}
|
||||||
find.first_char = i;
|
find.first_char = i;
|
||||||
find.length = 0;
|
find.length = r.num_chars;
|
||||||
find.prev_first = prev_start;
|
find.prev_first = prev_start;
|
||||||
|
|
||||||
|
// now scan to find xpos
|
||||||
|
find.x = r.x0;
|
||||||
|
i = 0;
|
||||||
|
while first + i < n {
|
||||||
|
find.x += STB_TEXTEDIT_GETWIDTH(str, first, i);
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -699,6 +833,7 @@ stb_textedit_find_charpos :: (find: *StbFindState, str: *STB_TEXTEDIT_STRING, n:
|
|||||||
find.y = 0;
|
find.y = 0;
|
||||||
|
|
||||||
while true {
|
while true {
|
||||||
|
r = .{};
|
||||||
STB_TEXTEDIT_LAYOUTROW(*r, str, i);
|
STB_TEXTEDIT_LAYOUTROW(*r, str, i);
|
||||||
if n < i + r.num_chars
|
if n < i + r.num_chars
|
||||||
break;
|
break;
|
||||||
@ -731,13 +866,25 @@ STB_TEXT_HAS_SELECTION :: (s: *STB_TexteditState) -> bool #expand {
|
|||||||
stb_textedit_clamp :: (str: *STB_TEXTEDIT_STRING, state: *STB_TexteditState) {
|
stb_textedit_clamp :: (str: *STB_TEXTEDIT_STRING, state: *STB_TexteditState) {
|
||||||
n : s32 = STB_TEXTEDIT_STRINGLEN(str);
|
n : s32 = STB_TEXTEDIT_STRINGLEN(str);
|
||||||
if STB_TEXT_HAS_SELECTION(state) {
|
if STB_TEXT_HAS_SELECTION(state) {
|
||||||
if (state.select_start > n) state.select_start = n;
|
if str.text[str.text.count - 1] == STB_TEXTEDIT_NEWLINE && state.select_start > n - 1 {
|
||||||
if (state.select_end > n) state.select_end = n;
|
state.select_start = n - 1;
|
||||||
|
} else if state.select_start > n
|
||||||
|
state.select_start = n;
|
||||||
|
|
||||||
|
if str.text[str.text.count - 1] == STB_TEXTEDIT_NEWLINE && state.select_end > n - 1 {
|
||||||
|
state.select_end = n - 1;
|
||||||
|
} else if state.select_end > n
|
||||||
|
state.select_end = n;
|
||||||
|
|
||||||
// if clamping forced them to be equal, move the cursor to match
|
// if clamping forced them to be equal, move the cursor to match
|
||||||
if (state.select_start == state.select_end)
|
if (state.select_start == state.select_end)
|
||||||
state.cursor = state.select_start;
|
state.cursor = state.select_start;
|
||||||
}
|
}
|
||||||
if (state.cursor > n) state.cursor = n;
|
if str.text[str.text.count - 1] == STB_TEXTEDIT_NEWLINE && state.cursor > n - 1 {
|
||||||
|
state.cursor = n - 1;
|
||||||
|
} else if state.cursor > n {
|
||||||
|
state.cursor = n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete characters while updating undo
|
// delete characters while updating undo
|
||||||
@ -880,8 +1027,12 @@ while retry := true {
|
|||||||
ch : STB_TEXTEDIT_CHARTYPE = cast(STB_TEXTEDIT_CHARTYPE, c);
|
ch : STB_TEXTEDIT_CHARTYPE = cast(STB_TEXTEDIT_CHARTYPE, c);
|
||||||
|
|
||||||
// can't add newline in single-line mode
|
// can't add newline in single-line mode
|
||||||
if c == #char "\n" && state.single_line
|
if c == #char "\n" && state.single_line {
|
||||||
break;
|
break;
|
||||||
|
} else if str.text.count == 0 {
|
||||||
|
new_line : u32 = #char "\n";
|
||||||
|
STB_TEXTEDIT_INSERTCHARS(str, state.cursor, *new_line, 1);
|
||||||
|
}
|
||||||
|
|
||||||
if state.insert_mode && !STB_TEXT_HAS_SELECTION(state) && state.cursor < STB_TEXTEDIT_STRINGLEN(str) {
|
if state.insert_mode && !STB_TEXT_HAS_SELECTION(state) && state.cursor < STB_TEXTEDIT_STRINGLEN(str) {
|
||||||
stb_text_makeundo_replace(str, state, state.cursor, 1, 1);
|
stb_text_makeundo_replace(str, state, state.cursor, 1, 1);
|
||||||
@ -1024,6 +1175,7 @@ while retry := true {
|
|||||||
|
|
||||||
// now find character position down a row
|
// now find character position down a row
|
||||||
state.cursor = start;
|
state.cursor = start;
|
||||||
|
row = .{};
|
||||||
STB_TEXTEDIT_LAYOUTROW(*row, str, state.cursor);
|
STB_TEXTEDIT_LAYOUTROW(*row, str, state.cursor);
|
||||||
x = row.x0;
|
x = row.x0;
|
||||||
for i : 0..row.num_chars - 1 {
|
for i : 0..row.num_chars - 1 {
|
||||||
@ -1090,6 +1242,7 @@ while retry := true {
|
|||||||
|
|
||||||
// now find character position up a row
|
// now find character position up a row
|
||||||
state.cursor = find.prev_first;
|
state.cursor = find.prev_first;
|
||||||
|
row = .{};
|
||||||
STB_TEXTEDIT_LAYOUTROW(*row, str, state.cursor);
|
STB_TEXTEDIT_LAYOUTROW(*row, str, state.cursor);
|
||||||
x = row.x0;
|
x = row.x0;
|
||||||
for i : 0..row.num_chars - 1 {
|
for i : 0..row.num_chars - 1 {
|
||||||
|
|||||||
189
src/text.jai
189
src/text.jai
@ -36,8 +36,6 @@ Font :: struct {
|
|||||||
|
|
||||||
glyphs : Table(u32, Glyph);
|
glyphs : Table(u32, Glyph);
|
||||||
|
|
||||||
//hb : *hb_font_t;
|
|
||||||
|
|
||||||
kb : kbts_font;
|
kb : kbts_font;
|
||||||
|
|
||||||
texture : Texture;
|
texture : Texture;
|
||||||
@ -61,7 +59,6 @@ init_font :: (using font: *Font, filename: string, size: s32) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//FT_Set_Pixel_Sizes(face, 0, size);
|
|
||||||
error = FT_Set_Char_Size(face, 0, size * 64, 0, 96);
|
error = FT_Set_Char_Size(face, 0, size * 64, 0, 96);
|
||||||
if error {
|
if error {
|
||||||
log("%", to_string(FT_Error_String(error)));
|
log("%", to_string(FT_Error_String(error)));
|
||||||
@ -113,34 +110,6 @@ init_font :: (using font: *Font, filename: string, size: s32) {
|
|||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for 0..face.num_glyphs {
|
|
||||||
// //for 65..90 {
|
|
||||||
// //index := FT_Get_Char_Index(face, xx it);
|
|
||||||
// error = FT_Load_Glyph(face, cast(u32) it, FT_LOAD_RENDER);
|
|
||||||
// if error
|
|
||||||
// logd("%", to_string(FT_Error_String(error)));
|
|
||||||
|
|
||||||
// array_add(*rects, stbrp_rect.{cast(s32) face.glyph.glyph_index, xx (face.glyph.bitmap.width + 2),
|
|
||||||
// xx (face.glyph.bitmap.rows + 2), 0, 0, 0});
|
|
||||||
|
|
||||||
// glyph : Glyph;
|
|
||||||
// glyph.utf32 = cast(u32) it;
|
|
||||||
// glyph.index = face.glyph.glyph_index;
|
|
||||||
// glyph.bearing_x = cast,trunc(s16) face.glyph.bitmap_left;
|
|
||||||
// glyph.bearing_y = cast,trunc(s16) face.glyph.bitmap_top;
|
|
||||||
// glyph.width = xx face.glyph.bitmap.width;
|
|
||||||
// glyph.height = xx face.glyph.bitmap.rows;
|
|
||||||
// glyph.rwidth = xx face.glyph.metrics.width >> 6;
|
|
||||||
// glyph.rheight = xx face.glyph.metrics.height >> 6;
|
|
||||||
// glyph.descent = xx (cast(float) face.glyph.bitmap.rows - cast(float) face.glyph.bitmap_top);
|
|
||||||
// glyph.ascent = xx (cast(float) face.glyph.bitmap.rows - glyph.descent);
|
|
||||||
// glyph.advance = cast(s16) face.glyph.advance.x >> 6;
|
|
||||||
// glyph.bitmap = alloc(glyph.height * glyph.width);
|
|
||||||
// memcpy(glyph.bitmap, face.glyph.bitmap.buffer, glyph.height * glyph.width);
|
|
||||||
|
|
||||||
// table_set(*font.glyphs, glyph.index, glyph);
|
|
||||||
// }
|
|
||||||
|
|
||||||
stbrp_pack_rects(*stbrpcontext, rects.data, cast(s32) rects.count);
|
stbrp_pack_rects(*stbrpcontext, rects.data, cast(s32) rects.count);
|
||||||
|
|
||||||
|
|
||||||
@ -182,32 +151,8 @@ init_font :: (using font: *Font, filename: string, size: s32) {
|
|||||||
|
|
||||||
flip(atlas);
|
flip(atlas);
|
||||||
|
|
||||||
// for rect : rects {
|
|
||||||
// glyph : *Glyph = table_find_pointer(*font.glyphs, cast(u32) rect.id);
|
|
||||||
// if (glyph.bitmap) {
|
|
||||||
// glyph.x = cast,trunc(s16) rect.x;
|
|
||||||
// glyph.y = ATLAS_SIZE - 1 - cast,trunc(s16) rect.y - xx glyph.height;
|
|
||||||
// glyph.st0 = .{cast(float, glyph.x) / ATLAS_SIZE, cast(float, glyph.y) / ATLAS_SIZE};
|
|
||||||
// glyph.st1 = glyph.st0 + .{cast(float, glyph.width) / ATLAS_SIZE, cast(float, glyph.height) / ATLAS_SIZE};
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
texture = make_texture_from_data(atlas, ATLAS_SIZE, ATLAS_SIZE);
|
texture = make_texture_from_data(atlas, ATLAS_SIZE, ATLAS_SIZE);
|
||||||
|
|
||||||
// blob : *hb_blob_t = hb_blob_create_or_fail(font_data.data, xx font_data.count, .HB_MEMORY_MODE_DUPLICATE, null, null);
|
|
||||||
// if blob == null {
|
|
||||||
// loge("Could not create the HarfBuzz blob.");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// hb_face : *hb_face_t = hb_face_create_or_fail(blob, 0);
|
|
||||||
// if hb_face == null {
|
|
||||||
// loge("Could not create the HarfBuzz face.");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// hb = hb_font_create(hb_face);
|
|
||||||
// hb_font_set_ppem(hb, xx pixel_size, xx pixel_size);
|
|
||||||
// hb_font_set_scale(hb, cast(s32) pixel_size * 64, cast(s32) pixel_size * 64);
|
|
||||||
|
|
||||||
ScratchSize : u64 = kbts_ReadFontHeader(*font.kb, font_data.data, xx font_data.count);
|
ScratchSize : u64 = kbts_ReadFontHeader(*font.kb, font_data.data, xx font_data.count);
|
||||||
PermanentMemorySize : u64 = kbts_ReadFontData(*font.kb, alloc(xx ScratchSize), ScratchSize);
|
PermanentMemorySize : u64 = kbts_ReadFontData(*font.kb, alloc(xx ScratchSize), ScratchSize);
|
||||||
kbts_PostReadFontInitialize(*font.kb, alloc(xx PermanentMemorySize), PermanentMemorySize);
|
kbts_PostReadFontInitialize(*font.kb, alloc(xx PermanentMemorySize), PermanentMemorySize);
|
||||||
@ -271,15 +216,9 @@ render_text :: (font: *Font, text: []u32, pos: Vector2, size: Vector2, window_sp
|
|||||||
X, Y : s32;
|
X, Y : s32;
|
||||||
kbts_PositionGlyph(*Cursor, kglyph, *X, *Y);
|
kbts_PositionGlyph(*Cursor, kglyph, *X, *Y);
|
||||||
|
|
||||||
// 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, kglyph.Id);
|
glyph : *Glyph = table_find_pointer(*font.glyphs, kglyph.Id);
|
||||||
|
|
||||||
if !glyph {
|
if !glyph {
|
||||||
//log("[Error] Panic! Didn't find the glyph!");
|
|
||||||
GlyphIndex += 1;
|
GlyphIndex += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -316,80 +255,11 @@ render_text :: (font: *Font, text: []u32, pos: Vector2, size: Vector2, window_sp
|
|||||||
array_add(*vertices, .{.{v0.x, v1.y}, .{t0.x, t1.y}, colour});
|
array_add(*vertices, .{.{v0.x, v1.y}, .{t0.x, t1.y}, colour});
|
||||||
array_add(*vertices, .{v1, t1, colour});
|
array_add(*vertices, .{v1, t1, colour});
|
||||||
|
|
||||||
//render_pos += Vector2.{x_advance / 64.0, y_advance / 64.0};
|
|
||||||
|
|
||||||
GlyphIndex += 1;
|
GlyphIndex += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(Glyphs);
|
free(Glyphs);
|
||||||
|
|
||||||
//size, max_descent := ShapeText(font, *Cursor, text_utf32.data, xx text_utf32.count, Direction, Direction, Script);
|
|
||||||
|
|
||||||
// buf : *hb_buffer_t = hb_buffer_create();
|
|
||||||
// hb_buffer_add_utf8(buf, text.data, xx text.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 : u32;
|
|
||||||
// glyph_info : *hb_glyph_info_t = hb_buffer_get_glyph_infos(buf, *glyph_count);
|
|
||||||
// glyph_pos : *hb_glyph_position_t = hb_buffer_get_glyph_positions(buf, *glyph_count);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// draw_size, max_ascent, max_descent := calculate_string_draw_size(font, text);
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// v0 : Vector2;
|
|
||||||
// v1 : Vector2;
|
|
||||||
// if count_descent {
|
|
||||||
// v0 = render_pos + .{cast(float) x_offset + glyph.bearing_x,
|
|
||||||
// cast(float) y_offset - glyph.bearing_y + draw_size.y - max_descent};
|
|
||||||
// } else {
|
|
||||||
// v0 = render_pos + .{cast(float) x_offset + glyph.bearing_x,
|
|
||||||
// cast(float) y_offset - (xx glyph.height - glyph.bearing_y)/* - glyph.height + draw_size.y*/};
|
|
||||||
// }
|
|
||||||
|
|
||||||
// v1 = v0 + Vector2.{cast(float) glyph.width, cast(float) glyph.height};
|
|
||||||
|
|
||||||
// // #if Y_IS_UP {
|
|
||||||
// // t0 := Vector2.{cast(float, glyph.x) / cast(float, ATLAS_SIZE), cast(float, glyph.y) / cast(float, ATLAS_SIZE)};
|
|
||||||
// // t1 := t0 + Vector2.{cast(float, glyph.width) / cast(float, ATLAS_SIZE), -cast(float, glyph.height) / cast(float, ATLAS_SIZE)};
|
|
||||||
// t0 := glyph.st0;
|
|
||||||
// t1 := glyph.st1;
|
|
||||||
// // } else {
|
|
||||||
// // t0 := Vector2.{cast(float, glyph.x / ATLAS_SIZE), cast(float, glyph.y / ATLAS_SIZE)};
|
|
||||||
// // t1 := t0 + .{cast(float, glyph.width / ATLAS_SIZE), cast(float, glyph.height / ATLAS_SIZE)};
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// array_add(*vertices, .{v0, t0, colour});
|
|
||||||
// array_add(*vertices, .{.{v0.x, v1.y}, .{t0.x, t1.y}, colour});
|
|
||||||
// array_add(*vertices, .{.{v1.x, v0.y}, .{t1.x, t0.y}, colour});
|
|
||||||
|
|
||||||
// array_add(*vertices, .{.{v1.x, v0.y}, .{t1.x, t0.y}, colour});
|
|
||||||
// array_add(*vertices, .{.{v0.x, v1.y}, .{t0.x, t1.y}, colour});
|
|
||||||
// array_add(*vertices, .{v1, t1, colour});
|
|
||||||
|
|
||||||
// render_pos += Vector2.{x_advance / 64.0, y_advance / 64.0};
|
|
||||||
// }
|
|
||||||
// hb_buffer_destroy(buf);
|
|
||||||
|
|
||||||
view := identity_of(Matrix4);
|
view := identity_of(Matrix4);
|
||||||
proj := window_proj;
|
proj := window_proj;
|
||||||
@ -400,58 +270,6 @@ render_text :: (font: *Font, text: []u32, pos: Vector2, size: Vector2, window_sp
|
|||||||
// restore_opengl_state(*opengl_state);
|
// restore_opengl_state(*opengl_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// string_size :: (font: *Font, Cursor: *kbts_cursor, text: string, MainDirection: kbts_direction, Direction: kbts_direction, Script: kbts_script) -> Vector2 {
|
|
||||||
// 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);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Glyphs : *kbts_glyph = cast(*kbts_glyph, alloc(size_of(kbts_glyph) * text_utf32.count));
|
|
||||||
|
|
||||||
// CodepointIndex: u64;
|
|
||||||
// while CodepointIndex < xx text_utf32.count {
|
|
||||||
// Glyphs[CodepointIndex] = kbts_CodepointToGlyph(*font.kb, text_utf32[CodepointIndex]);
|
|
||||||
|
|
||||||
// CodepointIndex += 1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// State : *kbts_shape_state = kbts_CreateShapeState(*font.kb);
|
|
||||||
// Config : kbts_shape_config = kbts_ShapeConfig(*font.kb, Script, xx kbts_language_enum.KBTS_LANGUAGE_DONT_KNOW);
|
|
||||||
|
|
||||||
// size : Vector2;
|
|
||||||
|
|
||||||
// GlyphCount : u32 = xx text_utf32.count;
|
|
||||||
// GlyphCapacity : u32 = GlyphCount;
|
|
||||||
// while kbts_Shape(State, *Config, MainDirection, Direction, Glyphs, *GlyphCount, GlyphCapacity) {
|
|
||||||
// Glyphs = cast(*kbts_glyph, realloc(Glyphs, size_of(kbts_glyph) * State.RequiredGlyphCapacity, size_of(kbts_glyph) * GlyphCapacity));
|
|
||||||
// GlyphCapacity = State.RequiredGlyphCapacity;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// GlyphIndex : u64;
|
|
||||||
// while GlyphIndex < GlyphCount {
|
|
||||||
// Glyph : *kbts_glyph = *Glyphs[GlyphIndex];
|
|
||||||
|
|
||||||
// X : s32;
|
|
||||||
// Y : s32;
|
|
||||||
// kbts_PositionGlyph(Cursor, Glyph, *X, *Y);
|
|
||||||
|
|
||||||
// //RenderGlyph(Glyph, X, Y);
|
|
||||||
|
|
||||||
// GlyphIndex += 1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// free(Glyphs);
|
|
||||||
|
|
||||||
// return size;
|
|
||||||
// }
|
|
||||||
|
|
||||||
ShapeText :: (font: *Font, Cursor: *kbts_cursor, Codepoints: *u32, CodepointCount: u64, MainDirection: kbts_direction, Direction: kbts_direction, Script: kbts_script) -> Vector2, float {
|
ShapeText :: (font: *Font, Cursor: *kbts_cursor, Codepoints: *u32, CodepointCount: u64, MainDirection: kbts_direction, Direction: kbts_direction, Script: kbts_script) -> Vector2, float {
|
||||||
kglyphs : *kbts_glyph = cast(*kbts_glyph, alloc(xx (size_of(kbts_glyph) * CodepointCount)));
|
kglyphs : *kbts_glyph = cast(*kbts_glyph, alloc(xx (size_of(kbts_glyph) * CodepointCount)));
|
||||||
|
|
||||||
@ -488,12 +306,8 @@ ShapeText :: (font: *Font, Cursor: *kbts_cursor, Codepoints: *u32, CodepointCoun
|
|||||||
size.y = max(size.y, xx glyph.height);
|
size.y = max(size.y, xx glyph.height);
|
||||||
size.x += xx (FT_MulFix(kglyph.AdvanceX, font.face.size.metrics.x_scale) >> 6);
|
size.x += xx (FT_MulFix(kglyph.AdvanceX, font.face.size.metrics.x_scale) >> 6);
|
||||||
max_descent = max(max_descent, xx glyph.descent);
|
max_descent = max(max_descent, xx glyph.descent);
|
||||||
//line.max_descent = max(line.max_descent, cast(float) glyph.descent);
|
|
||||||
//line.max_ascent = max(line.max_ascent, cast(float) glyph.ascent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//RenderGlyph(Glyph, X, Y);
|
|
||||||
|
|
||||||
GlyphIndex += 1;
|
GlyphIndex += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -555,9 +369,6 @@ next_word_size :: (font : *Font, text : []u32, n : s32, max_width : float = 0.0)
|
|||||||
BreakState : kbts_break_state;
|
BreakState : kbts_break_state;
|
||||||
kbts_BeginBreak(*BreakState, .NONE, .NORMAL);
|
kbts_BeginBreak(*BreakState, .NONE, .NORMAL);
|
||||||
|
|
||||||
// size : Vector2;
|
|
||||||
// max_descent : float;
|
|
||||||
|
|
||||||
CodepointIndex : u64;
|
CodepointIndex : u64;
|
||||||
while CodepointIndex < xx CodepointCount {
|
while CodepointIndex < xx CodepointCount {
|
||||||
kbts_BreakAddCodepoint(*BreakState, Codepoints[CodepointIndex], 1, xx ((CodepointIndex + 1) == xx CodepointCount));
|
kbts_BreakAddCodepoint(*BreakState, Codepoints[CodepointIndex], 1, xx ((CodepointIndex + 1) == xx CodepointCount));
|
||||||
|
|||||||
125
src/ui.jai
125
src/ui.jai
@ -78,7 +78,6 @@ UIContext :: struct {
|
|||||||
sizing_y : UISizing;
|
sizing_y : UISizing;
|
||||||
offaxis_layout : UIOffAxisLayout;
|
offaxis_layout : UIOffAxisLayout;
|
||||||
|
|
||||||
// font : *Simp.Dynamic_Font;
|
|
||||||
font : *Font;
|
font : *Font;
|
||||||
|
|
||||||
margin : s32 = 2;
|
margin : s32 = 2;
|
||||||
@ -159,7 +158,6 @@ Label :: struct {
|
|||||||
text : string;
|
text : string;
|
||||||
text_size : Vector2;
|
text_size : Vector2;
|
||||||
max_descent : float;
|
max_descent : float;
|
||||||
//lines : [..]Line;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Icon :: struct {
|
Icon :: struct {
|
||||||
@ -313,7 +311,7 @@ ui_render :: () {
|
|||||||
|
|
||||||
ui_begin :: (s: string) {
|
ui_begin :: (s: string) {
|
||||||
text, key := ui_decompose_and_generate_id(null, s);
|
text, key := ui_decompose_and_generate_id(null, s);
|
||||||
success, ptr := table_find_new(*ui_context.rects, key);
|
success, ptr := table_find(*ui_context.rects, key);
|
||||||
root : *Rect = xx ptr;
|
root : *Rect = xx ptr;
|
||||||
if !success {
|
if !success {
|
||||||
new_root := New(Rect);
|
new_root := New(Rect);
|
||||||
@ -382,7 +380,7 @@ global_max_width : float = 100.0;
|
|||||||
|
|
||||||
ui_label :: (s: string = "", colour := Vector4.{1.0, 1.0, 1.0, 1.0}) {
|
ui_label :: (s: string = "", colour := Vector4.{1.0, 1.0, 1.0, 1.0}) {
|
||||||
text, key := ui_decompose_and_generate_id(peek(ui_context.stack), s);
|
text, key := ui_decompose_and_generate_id(peek(ui_context.stack), s);
|
||||||
success, ptr := table_find_new(*ui_context.rects, key);
|
success, ptr := table_find(*ui_context.rects, key);
|
||||||
label : *Label = xx ptr;
|
label : *Label = xx ptr;
|
||||||
if !success {
|
if !success {
|
||||||
new_label := New(Label);
|
new_label := New(Label);
|
||||||
@ -534,7 +532,7 @@ ui_draw_label :: (using label: *Label) {
|
|||||||
|
|
||||||
ui_icon :: (s: string, texture: *Texture, size: Vector2) {
|
ui_icon :: (s: string, texture: *Texture, size: Vector2) {
|
||||||
text, key := ui_decompose_and_generate_id(peek(ui_context.stack), s);
|
text, key := ui_decompose_and_generate_id(peek(ui_context.stack), s);
|
||||||
success, ptr := table_find_new(*ui_context.rects, key);
|
success, ptr := table_find(*ui_context.rects, key);
|
||||||
icon : *Icon = xx ptr;
|
icon : *Icon = xx ptr;
|
||||||
if !success {
|
if !success {
|
||||||
new_icon := New(Icon);
|
new_icon := New(Icon);
|
||||||
@ -580,7 +578,7 @@ ui_draw_icon :: (using icon: *Icon) {
|
|||||||
|
|
||||||
ui_font_icon :: (font: *Font, s: string, size: Vector2, colour: Vector4 = .{1, 1, 1, 1}) {
|
ui_font_icon :: (font: *Font, s: string, size: Vector2, colour: Vector4 = .{1, 1, 1, 1}) {
|
||||||
text, key := ui_decompose_and_generate_id(peek(ui_context.stack), s);
|
text, key := ui_decompose_and_generate_id(peek(ui_context.stack), s);
|
||||||
success, ptr := table_find_new(*ui_context.rects, key);
|
success, ptr := table_find(*ui_context.rects, key);
|
||||||
icon : *FontIcon = xx ptr;
|
icon : *FontIcon = xx ptr;
|
||||||
if !success {
|
if !success {
|
||||||
new_icon := New(FontIcon);
|
new_icon := New(FontIcon);
|
||||||
@ -613,10 +611,6 @@ ui_font_icon :: (font: *Font, s: string, size: Vector2, colour: Vector4 = .{1, 1
|
|||||||
ui_draw_font_icon :: (using font_icon: *FontIcon) {
|
ui_draw_font_icon :: (using font_icon: *FontIcon) {
|
||||||
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)};
|
||||||
|
|
||||||
// label_size := Vector2.{xx Simp.prepare_icon(font, name), xx font.character_height};
|
|
||||||
|
|
||||||
// Simp.draw_prepared_text(font, xx midline.x, xx (midline.y - label_size.y / 2.0), colour);
|
|
||||||
|
|
||||||
// Backup GL state
|
// Backup GL state
|
||||||
// opengl_state : OpenGLState;
|
// opengl_state : OpenGLState;
|
||||||
// save_opengl_state(*opengl_state);
|
// save_opengl_state(*opengl_state);
|
||||||
@ -633,7 +627,7 @@ ui_draw_font_icon :: (using font_icon: *FontIcon) {
|
|||||||
|
|
||||||
ui_button :: (s: string = "", icon_texture: *Texture = null, font_colour := Vector4.{1, 1, 1, 1}, draw_frame := true) -> bool {
|
ui_button :: (s: string = "", icon_texture: *Texture = null, font_colour := Vector4.{1, 1, 1, 1}, draw_frame := true) -> bool {
|
||||||
text, key := ui_decompose_and_generate_id(peek(ui_context.stack), s);
|
text, key := ui_decompose_and_generate_id(peek(ui_context.stack), s);
|
||||||
success, ptr := table_find_new(*ui_context.rects, key);
|
success, ptr := table_find(*ui_context.rects, key);
|
||||||
button : *Button = xx ptr;
|
button : *Button = xx ptr;
|
||||||
if !success {
|
if !success {
|
||||||
new_button := New(Button);
|
new_button := New(Button);
|
||||||
@ -773,7 +767,7 @@ ui_draw_button :: (using button: *Button) {
|
|||||||
|
|
||||||
ui_scrollbar :: (s: string = "", icon_texture: *Texture = null, font_colour := Vector4.{1, 1, 1, 1}, draw_frame := true) -> bool {
|
ui_scrollbar :: (s: string = "", icon_texture: *Texture = null, font_colour := Vector4.{1, 1, 1, 1}, draw_frame := true) -> bool {
|
||||||
text, key := ui_decompose_and_generate_id(peek(ui_context.stack), s);
|
text, key := ui_decompose_and_generate_id(peek(ui_context.stack), s);
|
||||||
success, ptr := table_find_new(*ui_context.rects, key);
|
success, ptr := table_find(*ui_context.rects, key);
|
||||||
scrollbar : *ScrollBar = xx ptr;
|
scrollbar : *ScrollBar = xx ptr;
|
||||||
if !success {
|
if !success {
|
||||||
new_scrollbar := New(ScrollBar);
|
new_scrollbar := New(ScrollBar);
|
||||||
@ -884,7 +878,7 @@ ui_draw_scroll_bar :: (using scroll_bar: *ScrollBar) {
|
|||||||
|
|
||||||
ui_text_input :: (s: string, font_colour := Vector4.{1, 1, 1, 1}) {
|
ui_text_input :: (s: string, font_colour := Vector4.{1, 1, 1, 1}) {
|
||||||
text, key := ui_decompose_and_generate_id(peek(ui_context.stack), s);
|
text, key := ui_decompose_and_generate_id(peek(ui_context.stack), s);
|
||||||
success, ptr := table_find_new(*ui_context.rects, key);
|
success, ptr := table_find(*ui_context.rects, key);
|
||||||
text_input : *TextInput = xx ptr;
|
text_input : *TextInput = xx ptr;
|
||||||
if !success {
|
if !success {
|
||||||
new_text_input := New(TextInput);
|
new_text_input := New(TextInput);
|
||||||
@ -906,32 +900,22 @@ ui_text_input :: (s: string, font_colour := Vector4.{1, 1, 1, 1}) {
|
|||||||
ui_append_to_parent(text_input);
|
ui_append_to_parent(text_input);
|
||||||
|
|
||||||
text_size : Vector2;
|
text_size : Vector2;
|
||||||
//text_size.y = xx text_input.font.face.size.metrics.height >> 6;
|
|
||||||
//str := builder_to_string(*text_input.input_buffer, 0, false);
|
|
||||||
// if str.count > 0 {
|
|
||||||
// defer free(str);
|
|
||||||
// textsize = Vector2.{xx Simp.prepare_text(text_input.font, str), xx text_input.font.character_height};
|
|
||||||
// }
|
|
||||||
max_descent : float;
|
max_descent : float;
|
||||||
// idx : s32;
|
|
||||||
// while idx < text_input.text.count {
|
|
||||||
// word_size, word_descent, read := next_word_size(text_input.font, text_input.text, idx, 0.0);
|
|
||||||
|
|
||||||
// text_size.x += word_size.x;
|
|
||||||
// text_size.y = max(text_size.y, word_size.y);
|
|
||||||
// max_descent = max(max_descent, word_descent);
|
|
||||||
|
|
||||||
// idx += read;
|
|
||||||
// }
|
|
||||||
|
|
||||||
i : s32;
|
i : s32;
|
||||||
while i < text_input.text.count {
|
while i < text_input.text.count {
|
||||||
row : StbTexteditRow;
|
row : StbTexteditRow;
|
||||||
STB_TEXTEDIT_LAYOUTROW(*row, text_input, i);
|
STB_TEXTEDIT_LAYOUTROW(*row, text_input, i);
|
||||||
|
|
||||||
|
is_new_line : bool = text_input.text[i + row.num_chars - 1] == #char "\n";
|
||||||
|
|
||||||
text_size.x = max(text_size.x, row.x1);
|
text_size.x = max(text_size.x, row.x1);
|
||||||
text_size.y += text_input.font.face.size.metrics.height >> 6;
|
text_size.y += text_input.font.face.size.metrics.height >> 6;
|
||||||
|
|
||||||
|
// if is_new_line && text_input.text.count <= i + row.num_chars {
|
||||||
|
// text_size.y += text_input.font.face.size.metrics.height >> 6;
|
||||||
|
// }
|
||||||
|
|
||||||
i += xx row.num_chars;
|
i += xx row.num_chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1005,14 +989,20 @@ ui_draw_text_input :: (using text_input: *TextInput) {
|
|||||||
row : StbTexteditRow;
|
row : StbTexteditRow;
|
||||||
STB_TEXTEDIT_LAYOUTROW(*row, text_input, i);
|
STB_TEXTEDIT_LAYOUTROW(*row, text_input, i);
|
||||||
|
|
||||||
|
is_new_line : bool = text_input.text[i + row.num_chars - 1] == #char "\n";
|
||||||
|
|
||||||
select_rectangle : Rectangle;
|
select_rectangle : Rectangle;
|
||||||
|
|
||||||
if i + xx row.num_chars >= textedit_state.cursor {
|
log("Cursor: %", textedit_state.cursor);
|
||||||
|
|
||||||
|
if i + row.num_chars >= textedit_state.cursor && !(is_new_line && textedit_state.cursor == i + row.num_chars) {
|
||||||
|
|
||||||
j : s32;
|
j : s32;
|
||||||
while grapheme := i + j < textedit_state.cursor {
|
while grapheme := i + j < textedit_state.cursor {
|
||||||
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;
|
||||||
|
|
||||||
j += read;
|
j += read;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1020,8 +1010,7 @@ ui_draw_text_input :: (using text_input: *TextInput) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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}, text_input.size,
|
.{draw_pos.x, draw_pos.y + row.ymin}, text_input.size,colour = font_colour);
|
||||||
colour = font_colour);
|
|
||||||
|
|
||||||
if textedit_state.select_start < textedit_state.select_end {
|
if textedit_state.select_start < textedit_state.select_end {
|
||||||
|
|
||||||
@ -1087,6 +1076,72 @@ ui_draw_text_input :: (using text_input: *TextInput) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render_filled_rectangle(select_pos + v2(margin) + v2(border_size) + v2(padding), select_size, .{0.8, 0.2, 0.55, 0.4});
|
||||||
|
}
|
||||||
|
} else if textedit_state.select_start > textedit_state.select_end {
|
||||||
|
|
||||||
|
if textedit_state.select_start > i && textedit_state.select_end < i + row.num_chars {
|
||||||
|
|
||||||
|
select_size : Vector2 = .{0.0, xx font.face.size.metrics.height >> 6};
|
||||||
|
|
||||||
|
if textedit_state.select_end < i && textedit_state.select_start > i + row.num_chars {
|
||||||
|
select_pos.x = 0.0;
|
||||||
|
select_size.x = row.x1 - row.x0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if textedit_state.select_end >= i && textedit_state.select_start > i + row.num_chars {
|
||||||
|
j : s32;
|
||||||
|
while grapheme := i + j < textedit_state.select_end && i + j < i + row.num_chars {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select_size.x = row.x1 - select_pos.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if textedit_state.select_end < i && textedit_state.select_start <= i + row.num_chars {
|
||||||
|
select_pos.x = 0.0;
|
||||||
|
|
||||||
|
j : s32;
|
||||||
|
while grapheme := i + j < textedit_state.select_start && i + j < i + row.num_chars {
|
||||||
|
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 textedit_state.select_end >= i && textedit_state.select_start <= i + row.num_chars {
|
||||||
|
j : s32;
|
||||||
|
|
||||||
|
while grapheme := i + j < textedit_state.select_end && i + j < i + row.num_chars {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while grapheme := i + j < textedit_state.select_start && i + j < i + row.num_chars {
|
||||||
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render_filled_rectangle(select_pos + v2(margin) + v2(border_size) + v2(padding), select_size, .{0.8, 0.2, 0.55, 0.4});
|
render_filled_rectangle(select_pos + v2(margin) + v2(border_size) + v2(padding), select_size, .{0.8, 0.2, 0.55, 0.4});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1117,7 +1172,7 @@ ui_draw_text_input :: (using text_input: *TextInput) {
|
|||||||
|
|
||||||
ui_begin_container :: (s: string, gradient := false, colour_left := Vector4.{}, colour_right := Vector4.{}, max_x: s32 = -1, max_y: s32 = -1, flags: ContainerFlags = 0) -> bool {
|
ui_begin_container :: (s: string, gradient := false, colour_left := Vector4.{}, colour_right := Vector4.{}, max_x: s32 = -1, max_y: s32 = -1, flags: ContainerFlags = 0) -> bool {
|
||||||
text, key := ui_decompose_and_generate_id(peek(ui_context.stack), s);
|
text, key := ui_decompose_and_generate_id(peek(ui_context.stack), s);
|
||||||
success, ptr := table_find_new(*ui_context.rects, key);
|
success, ptr := table_find(*ui_context.rects, key);
|
||||||
container : *Container = xx ptr;
|
container : *Container = xx ptr;
|
||||||
if !success {
|
if !success {
|
||||||
new_container := New(Container);
|
new_container := New(Container);
|
||||||
@ -1219,7 +1274,7 @@ ui_draw_container :: (using container: *Container) {
|
|||||||
|
|
||||||
ui_spacing :: (s: string) {
|
ui_spacing :: (s: string) {
|
||||||
text, key := ui_decompose_and_generate_id(peek(ui_context.stack), s);
|
text, key := ui_decompose_and_generate_id(peek(ui_context.stack), s);
|
||||||
success, ptr := table_find_new(*ui_context.rects, key);
|
success, ptr := table_find(*ui_context.rects, key);
|
||||||
spacing : *Spacing = xx ptr;
|
spacing : *Spacing = xx ptr;
|
||||||
if !success {
|
if !success {
|
||||||
new_spacing := New(Spacing);
|
new_spacing := New(Spacing);
|
||||||
@ -1251,7 +1306,7 @@ ui_spacing :: (s: string) {
|
|||||||
|
|
||||||
ui_progress_bar :: (s: string = "", progress: float, size: Vector2, background := Vector4.{1, 1, 1, 1}, foreground := Vector4.{1, 1, 1, 1}) {
|
ui_progress_bar :: (s: string = "", progress: float, size: Vector2, background := Vector4.{1, 1, 1, 1}, foreground := Vector4.{1, 1, 1, 1}) {
|
||||||
text, key := ui_decompose_and_generate_id(peek(ui_context.stack), s);
|
text, key := ui_decompose_and_generate_id(peek(ui_context.stack), s);
|
||||||
success, ptr := table_find_new(*ui_context.rects, key);
|
success, ptr := table_find(*ui_context.rects, key);
|
||||||
bar : *ProgressBar = xx ptr;
|
bar : *ProgressBar = xx ptr;
|
||||||
if !success {
|
if !success {
|
||||||
new_bar := New(ProgressBar);
|
new_bar := New(ProgressBar);
|
||||||
|
|||||||
45
ui.rad
45
ui.rad
@ -1,45 +0,0 @@
|
|||||||
// raddbg 0.9.21 project file
|
|
||||||
|
|
||||||
recent_file: path: "src/stb_textedit.jai"
|
|
||||||
recent_file: path: "src/ui.jai"
|
|
||||||
recent_file: path: "../../../../jai/modules/runtime_support.jai"
|
|
||||||
recent_file: path: "src/main.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: "../../../../jai/modules/math/module.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/basic/module.jai"
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "bin/mexplore-debug.exe"
|
|
||||||
working_directory: bin
|
|
||||||
enabled: 1
|
|
||||||
}
|
|
||||||
breakpoint:
|
|
||||||
{
|
|
||||||
source_location: "src/ui.jai:1032:1"
|
|
||||||
hit_count: 0
|
|
||||||
enabled: 0
|
|
||||||
}
|
|
||||||
breakpoint:
|
|
||||||
{
|
|
||||||
source_location: "src/stb_textedit.jai:995:1"
|
|
||||||
hit_count: 0
|
|
||||||
enabled: 0
|
|
||||||
}
|
|
||||||
breakpoint:
|
|
||||||
{
|
|
||||||
source_location: "src/stb_textedit.jai:1016:1"
|
|
||||||
hit_count: 0
|
|
||||||
enabled: 0
|
|
||||||
}
|
|
||||||
breakpoint:
|
|
||||||
{
|
|
||||||
source_location: "src/stb_textedit.jai:1030:1"
|
|
||||||
enabled: 0
|
|
||||||
hit_count: 0
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user