From 44f5f66b9f17e49d6defed8ac74e1e38aac463b4 Mon Sep 17 00:00:00 2001 From: sixtenhugosson Date: Tue, 26 Dec 2023 09:11:41 +0100 Subject: [PATCH] Revamped the text editor. --- code/core/core_memory.cpp | 6 +- code/core/core_string.cpp | 160 +---- code/core/core_string.h | 14 - code/generated/vn_platform.meta.h | 2 +- code/vn.cpp | 33 +- code/vn_font.cpp | 36 +- code/vn_platform.h | 1 + code/vn_platform.md | 54 +- code/vn_scene.cpp | 35 +- code/vn_scene.h | 4 +- code/vn_text_op.h | 32 +- code/vn_ui_utils.cpp | 96 +-- code/vn_workspace.cpp | 138 ++-- code/vn_workspace.h | 9 - code/vn_workspace_text_editor.cpp | 1093 +++++++++++++++-------------- code/vn_workspace_text_editor.h | 86 +-- code/vn_workspace_view.cpp | 40 +- code/win32__main.rdbg | Bin 1073 -> 485 bytes code/win32_main.cpp | 34 +- config.vn | 2 +- 20 files changed, 875 insertions(+), 1000 deletions(-) diff --git a/code/core/core_memory.cpp b/code/core/core_memory.cpp index 85a91f3..499f599 100644 --- a/code/core/core_memory.cpp +++ b/code/core/core_memory.cpp @@ -89,13 +89,13 @@ static void ArenaRelease(arena *Arena) for(;Node != Arena;) { arena *Next = Node->Prev; - Platform.Deallocate(Node); + Platform.Deallocate(Node, Node->Size); Node = Next; } #if VN_ASAN_ENABLED ASAN_POISON_MEMORY_REGION(Arena, Arena->Size); #endif - Platform.Deallocate(Arena); + Platform.Deallocate(Arena, Arena->Size); } else { @@ -188,7 +188,7 @@ static void ArenaPopTo(arena *Arena, u64 Position) #if VN_ASAN_ENABLED ASAN_POISON_MEMORY_REGION(Node, Node->Size); #endif - Platform.Deallocate(Node); + Platform.Deallocate(Node, Node->Size); Node = Prev; } } diff --git a/code/core/core_string.cpp b/code/core/core_string.cpp index 8d45112..e2ed906 100644 --- a/code/core/core_string.cpp +++ b/code/core/core_string.cpp @@ -6,9 +6,9 @@ inline b32 IsWhitespace(char C) { b32 Result = ((C == ' ') || - (C == '\n') || - (C == '\t') || - (C == '\r')); + (C == '\n') || + (C == '\t') || + (C == '\r')); return(Result); } @@ -63,8 +63,8 @@ static b32 AreEqual(string A, string B) Result = true; for(s64 Index = 0; - Index < A.Count; - ++Index) + Index < A.Count; + ++Index) { if(A.Data[Index] != B.Data[Index]) { @@ -105,8 +105,8 @@ static u64 HashString(string String) { u64 Result = 5731; for(s64 Index = 0; - Index < String.Count; - ++Index) + Index < String.Count; + ++Index) { Result += String.Data[Index]; Result ^= Result << 13; @@ -123,8 +123,8 @@ static s64 FirstIndexOf(string String, char Char) { s64 Result = -1; for(s64 Index = 0; - Index < String.Count; - ++Index) + Index < String.Count; + ++Index) { if(String.Data[Index] == Char) { @@ -139,8 +139,8 @@ static s64 LastIndexOf(string String, char Char) { s64 Result = -1; for(s64 Index = String.Count-1; - Index >= 0; - --Index) + Index >= 0; + --Index) { if(String.Data[Index] == Char) { @@ -157,8 +157,8 @@ static s64 FirstIndexOf(string String, string Sub) if(String.Count >= Sub.Count) { for(s64 Index = 0; - Index < String.Count - Sub.Count; - ++Index) + Index < String.Count - Sub.Count; + ++Index) { string ToCheck = Substring(String, Range1S64(Index, Index + Sub.Count)); if(AreEqual(ToCheck, Sub)) @@ -178,8 +178,8 @@ static s64 LastIndexOf(string String, string Sub) if(String.Count >= Sub.Count) { for(s64 Index = String.Count - Sub.Count - 1; - Index >= 0; - --Index) + Index >= 0; + --Index) { string ToCheck = Substring(String, Range1S64(Index, Index + Sub.Count)); if(AreEqual(ToCheck, Sub)) @@ -287,8 +287,8 @@ static string ConvertS64ToString(arena *Arena, s64 Value) } for(s64 Index = 0; - Index < DigitCount; - ++Index) + Index < DigitCount; + ++Index) { String.Data[TotalBufferCount - 1 - Index] = '0' + (Value % 10); Value /= 10; @@ -395,13 +395,13 @@ static string JoinStringList(string_list *List, arena *Arena) s64 GlobalIndex = 0; for(string_node *Node = List->First; - Node != 0; - Node = Node->Next) + Node != 0; + Node = Node->Next) { string String = Node->String; for(s64 Index = 0; - Index < String.Count; - ++Index) + Index < String.Count; + ++Index) { Buffer[GlobalIndex++] = String.Data[Index]; } @@ -411,118 +411,6 @@ static string JoinStringList(string_list *List, arena *Arena) return(Result); } -///////////////////////////////////// -//~ sixten: String Chunk Functions -static string_chunk_list MakeStringChunkList(s64 ChunkSize) -{ - string_chunk_list Result = {}; - Result.ChunkSize = ChunkSize; - return(Result); -} - -static string JoinStringChunkList(arena *Arena, string_chunk_list *List) -{ - string Result = {}; - Result.Count = List->TotalCount; - Result.Data = PushArrayNoClear(Arena, u8, List->TotalCount + 1); - s64 Index = 0; - s64 CountRemaining = List->TotalCount; - for(string_node *Node = List->First; Node != 0; Node = Node->Next) - { - string String = Node->String; - Copy(Result.Data + Index, String.Data, Min(CountRemaining, List->ChunkSize)); - CountRemaining -= List->ChunkSize; - Index += String.Count; - } - return(Result); -} - -// sixten(TODO): Incomplete, remove maybe? -static void ReplaceRange(arena *Arena, string_chunk_list *List, string Text, range1_s64 Range) -{ - s64 NewTotalCount = Max(0ULL, List->TotalCount - DimOfRange(Range)) + Text.Count; - - //- sixten: do we need to allocate more chunks? - if(List->ChunkSize*List->ChunkCount < NewTotalCount) - { - s64 ChunksToAlloc = (NewTotalCount - List->ChunkSize*List->ChunkCount)/List->ChunkSize + 1; - for(s64 Index = 0; Index < ChunksToAlloc; Index += 1) - { - if(DLLIsEmpty(List->FirstFree)) - { - string_node *Node = PushStructNoClear(Arena, string_node); - Node->String.Count = 0; - Node->String.Data = PushArrayNoClear(Arena, u8, List->ChunkSize); - DLLInsertLast(List->First, List->Last, Node); - } - else - { - string_node *Node = List->FirstFree; - Node->String.Count = 0; - DLLRemove(List->FirstFree, List->LastFree, Node); - DLLInsertLast(List->First, List->Last, Node); - } - } - - List->ChunkCount += ChunksToAlloc; - } - - s64 CountDelta = NewTotalCount - List->TotalCount; - - // sixten: I cannot be bothered enough to figure out the correct implementation for this. However, if I do this - remember that you can rearrange - // the ordering of the linked list, instead of actually copying over the bytes for the majority of this. - Assert(AbsoluteValue(CountDelta) < List->ChunkSize); - - //- sixten: find the first and last affected nodes - s64 FirstAffectedNodeIndex = Range.Min/List->ChunkSize; - s64 LastAffectedNodeIndex = Range.Max/List->ChunkSize; - string_node *FirstAffectedNode = List->First; - for(s64 WalkIndex = 0; WalkIndex < FirstAffectedNodeIndex; WalkIndex += 1) - { - FirstAffectedNode = FirstAffectedNode->Next; - } - string_node *LastAffectedNode = FirstAffectedNode; - for(s64 WalkIndex = 0; WalkIndex < LastAffectedNodeIndex-FirstAffectedNodeIndex; WalkIndex += 1) - { - LastAffectedNode = LastAffectedNode->Next; - } - - if(CountDelta >= 0) - { - //- sixten: insertion - make room and the copy the data - s64 WriteOffset = Range.Min%List->ChunkSize; - for(string_node *Node = List->Last; Node != 0; Node = Node->Prev) - { - CopyReverse(Node->String.Data+CountDelta+WriteOffset, Node->String.Data+WriteOffset, List->ChunkSize-CountDelta-WriteOffset); - - if(Node == LastAffectedNode) - { - break; - } - else - { - Copy(Node->String.Data, Node->Prev->String.Data+List->ChunkSize-CountDelta, CountDelta); - } - } - s64 SourceOffset = 0; - for(string_node *Node = FirstAffectedNode; Node != 0; Node = Node->Next) - { - Copy(Node->String.Data+WriteOffset, Text.Data+SourceOffset, Min(List->ChunkSize-WriteOffset, Text.Count-SourceOffset)); - SourceOffset += List->ChunkSize; - if(Node == LastAffectedNode) - { - break; - } - } - } - else if(CountDelta < 0) - { - //- sixten: deletion - } - - List->TotalCount = NewTotalCount; -} - //~ sixten: Unicode @@ -621,7 +509,7 @@ static string_decode DecodeUTF16Codepoint(u16 *Data, s64 Count) else if(Count >= 2) { if(0xD800 <= Data[0] && Data[0] < 0xDC00 && - 0xDC00 <= Data[1] && Data[1] < 0xE000) + 0xDC00 <= Data[1] && Data[1] < 0xE000) { Result.Codepoint = ((Data[0] - 0xD800)<<10)|(Data[1]-0xDC00); Result.Size = 2; @@ -768,8 +656,8 @@ static text_point TextPointFromOffset(string String, s64 Offset) { text_point Point = {1, 1}; for(s64 Index = 0; - Index < String.Count && Index < Offset; - ++Index) + Index < String.Count && Index < Offset; + ++Index) { if(String.Data[Index] == '\n') { diff --git a/code/core/core_string.h b/code/core/core_string.h index 87246a1..ba74011 100644 --- a/code/core/core_string.h +++ b/code/core/core_string.h @@ -35,20 +35,6 @@ struct string_list s64 TotalCount; }; -///////////////////////////////////// -//~ sixten: String Chunk Types -struct string_chunk_list -{ - s64 ChunkSize; - s64 ChunkCount; - s64 TotalCount; - - string_node *First; - string_node *Last; - string_node *FirstFree; - string_node *LastFree; -}; - ///////////////////////////////////// //~ sixten: Char funcitons diff --git a/code/generated/vn_platform.meta.h b/code/generated/vn_platform.meta.h index ecec7f0..33926b8 100644 --- a/code/generated/vn_platform.meta.h +++ b/code/generated/vn_platform.meta.h @@ -3,7 +3,7 @@ #define PLATFORM_COMMIT(name) void name(void *Pointer, u64 Size) #define PLATFORM_DECOMMIT(name) void name(void *Pointer, u64 Size) #define PLATFORM_ALLOCATE(name) void * name(u64 Size) -#define PLATFORM_DEALLOCATE(name) void name(void *Pointer) +#define PLATFORM_DEALLOCATE(name) void name(void *Pointer, u64 Size) #define PLATFORM_OPEN_FILE(name) platform_file_handle name(string Path, platform_access_flags FileAccess) #define PLATFORM_CLOSE_FILE(name) void name(platform_file_handle Handle) #define PLATFORM_READ_FILE(name) void name(platform_file_handle Handle, void *Dest, u64 Offset, u64 Size) diff --git a/code/vn.cpp b/code/vn.cpp index b7ce884..e5783f0 100644 --- a/code/vn.cpp +++ b/code/vn.cpp @@ -98,7 +98,7 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender) arena *Arena = ArenaAlloc(Kilobytes(24), true); State = Memory->State = PushStruct(Arena, vn_state); State->Arena = Arena; - State->FrameArena = ArenaAlloc(Megabytes(1), true); + State->FrameArena = ArenaAlloc(Kilobytes(1), true); State->GlyphAtlas = CreateGlyphAtlas(RenderCommands); State->Config = CreateConfig(); @@ -193,8 +193,8 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender) //- sixten: consume all remaining evetns for(platform_event *Event = Input->EventList->First; - Event != 0; - Event = Event->Next) + Event != 0; + Event = Event->Next) { if(Event->Type == PlatformEvent_WindowClose) { @@ -212,19 +212,30 @@ VN_UPDATE_AND_RENDER(VN_UpdateAndRender) UI_RenderFrame(&Group, State->GlyphAtlas); -#if VN_INTERNAL +#if VN_INTERNAL + r32 DEBUGDisplayOffsetY = 20; if(DEBUG_DebugSettings->ListHotAndActive) { - PushText(&Group, State->GlyphAtlas, Font_Regular, V2(5, RenderCommands->RenderDim.y - 20), 15, Color_Grey, - PushFormat(State->UI.FrameArena, "Hot: %S:%llu", UI_BoxStringFromKey(UI_HotKey()), UI_HotKey())); - PushText(&Group, State->GlyphAtlas, Font_Regular, V2(5, RenderCommands->RenderDim.y - 40), 15, Color_Grey, - PushFormat(State->UI.FrameArena, "Active: %S:%llu", UI_BoxStringFromKey(UI_ActiveKey()), UI_ActiveKey())); + PushText(&Group, State->GlyphAtlas, Font_Regular, V2(5, RenderCommands->RenderDim.y - DEBUGDisplayOffsetY), 15, Color_Grey, + PushFormat(State->UI.FrameArena, "Hot: %S:%llu", UI_BoxStringFromKey(UI_HotKey()), UI_HotKey())); + DEBUGDisplayOffsetY += 20; + PushText(&Group, State->GlyphAtlas, Font_Regular, V2(5, RenderCommands->RenderDim.y - DEBUGDisplayOffsetY), 15, Color_Grey, + PushFormat(State->UI.FrameArena, "Active: %S:%llu", UI_BoxStringFromKey(UI_ActiveKey()), UI_ActiveKey())); + DEBUGDisplayOffsetY += 20; } + + if(DEBUG_DebugSettings->RenderFPSCounter) + { + PushText(&Group, State->GlyphAtlas, Font_Regular, V2(5, RenderCommands->RenderDim.y - DEBUGDisplayOffsetY), 15, Color_Grey, + PushFormat(State->UI.FrameArena, "FPS: %.2f", 1.0f/Input->dtForFrame)); + DEBUGDisplayOffsetY += 20; + + } #endif - + #if VN_INTERNAL - DI_EndFrame(); + DI_EndFrame(); #endif - + } } \ No newline at end of file diff --git a/code/vn_font.cpp b/code/vn_font.cpp index 7e95406..1396515 100644 --- a/code/vn_font.cpp +++ b/code/vn_font.cpp @@ -26,20 +26,20 @@ static void RasterizeGlyph(glyph_atlas *Atlas, font_id Font, glyph *Glyph, u32 C s32 GlyphsPerRow = Atlas->BitmapSize / Atlas->GlyphSize; v2_s32 BaseTextureOffset = V2S32((InternalIndex % GlyphsPerRow)*Atlas->GlyphSize, - (InternalIndex / GlyphsPerRow)*Atlas->GlyphSize); + (InternalIndex / GlyphsPerRow)*Atlas->GlyphSize); int GlyphIndex = stbtt_FindGlyphIndex(Info, Codepoint); stbtt_GetGlyphBitmapBoxSubpixel(Info, GlyphIndex, Scale, Scale, - (r32)Subpixel/GLYPH_SUBPIXEL_SEGMENTS, 0, - &Glyph->P0.x, &Glyph->P0.y, &Glyph->P1.x, &Glyph->P1.y); + (r32)Subpixel/GLYPH_SUBPIXEL_SEGMENTS, 0, + &Glyph->P0.x, &Glyph->P0.y, &Glyph->P1.x, &Glyph->P1.y); Fill(Atlas->BitmapBuffer, 0, Atlas->GlyphSize*Atlas->GlyphSize); stbtt_MakeGlyphBitmapSubpixel(Info, Atlas->BitmapBuffer, - Atlas->GlyphSize, Atlas->GlyphSize, Atlas->GlyphSize, - Scale, Scale, - (r32)Subpixel/GLYPH_SUBPIXEL_SEGMENTS, 0, - GlyphIndex); + Atlas->GlyphSize, Atlas->GlyphSize, Atlas->GlyphSize, + Scale, Scale, + (r32)Subpixel/GLYPH_SUBPIXEL_SEGMENTS, 0, + GlyphIndex); s32 Advance, LeftSideBearing; stbtt_GetGlyphHMetrics(Info, GlyphIndex, &Advance, &LeftSideBearing); @@ -54,8 +54,8 @@ static void RasterizeGlyph(glyph_atlas *Atlas, font_id Font, glyph *Glyph, u32 C Glyph->P1 = BaseTextureOffset + Dim + V2S32(2, 2); Atlas->RenderCommands->FillRegion(Atlas->Texture, - BaseTextureOffset, V2S32(Atlas->GlyphSize, Atlas->GlyphSize), - Atlas->BitmapBuffer); + BaseTextureOffset, V2S32(Atlas->GlyphSize, Atlas->GlyphSize), + Atlas->BitmapBuffer); } static glyph *GetGlyph(glyph_atlas *Atlas, font_id Font, u32 Codepoint, r32 Size, s32 Subpixel) @@ -63,8 +63,8 @@ static glyph *GetGlyph(glyph_atlas *Atlas, font_id Font, u32 Codepoint, r32 Size glyph *Glyph = 0; for(s32 GlyphIndex = 0; - GlyphIndex < Atlas->GlyphsUsed; - ++GlyphIndex) + GlyphIndex < Atlas->GlyphsUsed; + ++GlyphIndex) { glyph *At = Atlas->Glyphs + GlyphIndex; if((At->Font == Font) && (At->Codepoint == Codepoint) && (At->Size == Size) && (At->Subpixel == Subpixel)) @@ -125,13 +125,13 @@ static glyph_atlas *CreateGlyphAtlas(vn_render_commands *RenderCommands, Atlas->Fonts[Font_Icons].Data = Platform_ReadEntireFile(Atlas->Arena, StrLit("data/fonts/icons.ttf")); for(s32 FontIndex = 0; - FontIndex < Font_Count; - ++FontIndex) + FontIndex < Font_Count; + ++FontIndex) { loaded_font *Font = Atlas->Fonts + FontIndex; stbtt_InitFont(&Font->Info, - Font->Data.Data, - stbtt_GetFontOffsetForIndex(Font->Data.Data, 0)); + Font->Data.Data, + stbtt_GetFontOffsetForIndex(Font->Data.Data, 0)); stbtt_GetFontVMetrics(&Font->Info, &Font->Ascent, &Font->Descent, &Font->LineGap); } @@ -163,9 +163,9 @@ static r32 PushText(render_group *Group, glyph_atlas *Atlas, font_id Font, v2 Dim = RenderDim*(1.0 / Font_Oversample); PushTexturedQuad(Group, - Range2R32(GlyphP, GlyphP+Dim), - Range2R32(ConvertV2ToR32(Glyph->P0), ConvertV2ToR32(Glyph->P1)), - Color, Color, Color, Color, 0, 0, 0, Atlas->Texture); + Range2R32(GlyphP, GlyphP+Dim), + Range2R32(ConvertV2ToR32(Glyph->P0), ConvertV2ToR32(Glyph->P1)), + Color, Color, Color, Color, 0, 0, 0, Atlas->Texture); OffsetX += Glyph->Advance/Font_Oversample; } diff --git a/code/vn_platform.h b/code/vn_platform.h index 8e01c42..689a8e6 100644 --- a/code/vn_platform.h +++ b/code/vn_platform.h @@ -92,6 +92,7 @@ enum platform_key Key_PageUp, Key_PageDown, Key_Home, Key_End, + Key_Plus, Key_Minus, Key_Backspace, Key_Delete, diff --git a/code/vn_platform.md b/code/vn_platform.md index fc0a324..fdae7d5 100644 --- a/code/vn_platform.md +++ b/code/vn_platform.md @@ -1,46 +1,46 @@ @table(Name, NameLower, NameCaps, Type, Arguments) platform_functions: { - { Reserve reserve RESERVE `void *` `u64 Size` } - { Release release RELEASE `void` `void *Pointer` } - { Commit commit COMMIT `void` `void *Pointer, u64 Size` } - { Decommit decommit DECOMMIT `void` `void *Pointer, u64 Size` } - { Allocate allocate ALLOCATE `void *` `u64 Size` } - { Deallocate deallocate DEALLOCATE `void` `void *Pointer` } - { OpenFile open_file OPEN_FILE `platform_file_handle` `string Path, platform_access_flags FileAccess` } - { CloseFile close_file CLOSE_FILE `void` `platform_file_handle Handle` } - { ReadFile read_file READ_FILE `void` `platform_file_handle Handle, void *Dest, u64 Offset, u64 Size` } - { WriteFile write_file WRITE_FILE `void` `platform_file_handle Handle, void *Source, u64 Offset, u64 Size` } - { GetFileSize get_file_size GET_FILE_SIZE `u64` `platform_file_handle Handle` } - { SetCursor set_cursor SET_CURSOR `void` `platform_cursor Cursor` } - { ToggleFullscreen toggle_fullscreen TOGGLE_FULLSCREEN `void` `void` } - { ShowMessage show_message SHOW_MESSAGE `void` `string Message, platform_message_type Type` } - { BeginFileIter begin_file_iter BEGIN_FILE_ITER `platform_file_iter *` `arena *Arena, string Path` } - { AdvanceFileIter advance_file_iter ADVANCE_FILE_ITER `b32` `arena *Arena, platform_file_iter *Iter, platform_file_info *OutInfo` } - { EndFileIter end_file_iter END_FILE_ITER `void` `platform_file_iter *Iter` } - { SetClipboard set_clipboard SET_CLIPBOARD `void` `string String` } - { GetClipboard get_clipboard GET_CLIPBOARD `string` `arena *Arena` } + { Reserve reserve RESERVE `void *` `u64 Size` } + { Release release RELEASE `void` `void *Pointer` } + { Commit commit COMMIT `void` `void *Pointer, u64 Size` } + { Decommit decommit DECOMMIT `void` `void *Pointer, u64 Size` } + { Allocate allocate ALLOCATE `void *` `u64 Size` } + { Deallocate deallocate DEALLOCATE `void` `void *Pointer, u64 Size` } + { OpenFile open_file OPEN_FILE `platform_file_handle` `string Path, platform_access_flags FileAccess` } + { CloseFile close_file CLOSE_FILE `void` `platform_file_handle Handle` } + { ReadFile read_file READ_FILE `void` `platform_file_handle Handle, void *Dest, u64 Offset, u64 Size` } + { WriteFile write_file WRITE_FILE `void` `platform_file_handle Handle, void *Source, u64 Offset, u64 Size` } + { GetFileSize get_file_size GET_FILE_SIZE `u64` `platform_file_handle Handle` } + { SetCursor set_cursor SET_CURSOR `void` `platform_cursor Cursor` } + { ToggleFullscreen toggle_fullscreen TOGGLE_FULLSCREEN `void` `void` } + { ShowMessage show_message SHOW_MESSAGE `void` `string Message, platform_message_type Type` } + { BeginFileIter begin_file_iter BEGIN_FILE_ITER `platform_file_iter *` `arena *Arena, string Path` } + { AdvanceFileIter advance_file_iter ADVANCE_FILE_ITER `b32` `arena *Arena, platform_file_iter *Iter, platform_file_info *OutInfo` } + { EndFileIter end_file_iter END_FILE_ITER `void` `platform_file_iter *Iter` } + { SetClipboard set_clipboard SET_CLIPBOARD `void` `string String` } + { GetClipboard get_clipboard GET_CLIPBOARD `string` `arena *Arena` } } @table_gen { - @expand(platform_functions s) `#define PLATFORM_$(s.NameCaps)(name) $(s.Type) name($(s.Arguments))` + @expand(platform_functions s) `#define PLATFORM_$(s.NameCaps)(name) $(s.Type) name($(s.Arguments))` } @table_gen { - @expand(platform_functions s) `typedef PLATFORM_$(s.NameCaps)(platform_$(s.NameLower));` + @expand(platform_functions s) `typedef PLATFORM_$(s.NameCaps)(platform_$(s.NameLower));` } @table_gen { - `struct platform_api` - `{` - @expand(platform_functions s) `platform_$(s.NameLower) *$(s.Name); ` - `};` + `struct platform_api` + `{` + @expand(platform_functions s) `platform_$(s.NameLower) *$(s.Name); ` + `};` } @table_gen { - `#define RegisterPlatformFunctions(PlatformName)\\` - @expand(platform_functions s) `Platform.$(s.Name) = PlatformName##_$(s.Name);\\` + `#define RegisterPlatformFunctions(PlatformName)\\` + @expand(platform_functions s) `Platform.$(s.Name) = PlatformName##_$(s.Name);\\` } \ No newline at end of file diff --git a/code/vn_scene.cpp b/code/vn_scene.cpp index 4dc866c..32edf2e 100644 --- a/code/vn_scene.cpp +++ b/code/vn_scene.cpp @@ -91,22 +91,6 @@ static void S_PopEmissionTarget(scene_compiler *Compiler) Compiler->TargetStackIndex -= 1; } -static scene_bytecode_chunk *S_FindBytecodeChunkByName(scene_compiler *Compiler, string Name) -{ - scene_bytecode_chunk *Result = 0; - u64 Hash = HashString(Name); - scene_bytecode_bucket *Bucket = &Compiler->ProcBuckets[Hash%ArrayCount(Compiler->ProcBuckets)]; - for(scene_bytecode_chunk *Chunk = Bucket->First; Chunk != 0; Chunk = Chunk->Next) - { - if(AreEqual(Chunk->Name, Name)) - { - Result = Chunk; - break; - } - } - return(Result); -} - static void S_AdvanceCompiler(scene_compiler *Compiler) { Compiler->At += 1; @@ -143,17 +127,6 @@ static scene_parse_rule S_ParseRuleFromToken(scene_compiler *Compiler, token Tok return(Result); } -static b32 S_MatchToken(scene_compiler *Compiler, token Token, token_kind Kind) -{ - b32 Result = false; - string String = T_StringFromToken(Compiler->Text, Token); - if(Token.Kind == Kind) - { - Result = true; - } - return(Result); -} - static token S_ConsumeToken(scene_compiler *Compiler, token_kind Kind, char *Message) { token Token = Compiler->At[0]; @@ -1002,7 +975,7 @@ static void S_ResetRuntime(scene_runtime *Runtime) } } -static scene_runtime_result S_Run(scene_runtime *Runtime, arena *FrameArena, b32 AdvanceOnAwait) +static scene_runtime_result S_Run(scene_runtime *Runtime, arena *Arena, b32 AdvanceOnAwait) { scene_runtime_result Result = {}; compiled_scene *Compiled = &Runtime->Compiled; @@ -1194,7 +1167,7 @@ static scene_runtime_result S_Run(scene_runtime *Runtime, arena *FrameArena, b32 case S_Op_ClearDialog: { - scene_textbox_action *Action = PushStructNoClear(FrameArena, scene_textbox_action); + scene_textbox_action *Action = PushStructNoClear(Arena, scene_textbox_action); Action->Kind = S_TextboxActionKind_Set; Action->String = StrLit(""); QueuePush(Runtime->FirstTextboxAction, Runtime->LastTextboxAction, Action); @@ -1220,7 +1193,7 @@ static scene_runtime_result S_Run(scene_runtime *Runtime, arena *FrameArena, b32 } // sixten: create & apply character action - scene_character_action *Action = PushStruct(FrameArena, scene_character_action); + scene_character_action *Action = PushStruct(Arena, scene_character_action); Action->Target = Character; if(State.Kind == S_ValueKind_Nil) @@ -1236,7 +1209,7 @@ static scene_runtime_result S_Run(scene_runtime *Runtime, arena *FrameArena, b32 case S_Op_LineEntry: { - scene_textbox_action *Action = PushStructNoClear(FrameArena, scene_textbox_action); + scene_textbox_action *Action = PushStructNoClear(Arena, scene_textbox_action); Action->Kind = S_TextboxActionKind_Append; Runtime->IP += 1; diff --git a/code/vn_scene.h b/code/vn_scene.h index f266e7c..28cb2fc 100644 --- a/code/vn_scene.h +++ b/code/vn_scene.h @@ -393,7 +393,6 @@ static void S_EmitConstant(scene_compiler *Compiler, scene_value Value); static void S_SetEmissionTarget(scene_compiler *Compiler, scene_emission_target Target); static void S_PushEmissionTarget(scene_compiler *Compiler, scene_emission_target Target); static void S_PopEmissionTarget(scene_compiler *Compiler); -static scene_bytecode_chunk *S_FindBytecodeChunkByName(scene_compiler *Compiler, string Name); inline scene_emission_target S_RawEmissionTarget(arena *Arena, scene_bytecode_bucket *Bucket) { @@ -417,7 +416,6 @@ inline scene_emission_target S_NamedEmissionTarget(arena *Arena, scene_bytecode_ //- sixten: parsing helpers static void S_AdvanceCompiler(scene_compiler *Compiler); static scene_parse_rule S_ParseRuleFromToken(scene_compiler *Compiler, token Token); -static b32 S_MatchToken(scene_compiler *Compiler, token Token, token_kind Kind); static token S_ConsumeToken(scene_compiler *Compiler, token_kind Kind, char *Message); //- sixten: parsing @@ -455,6 +453,6 @@ static compiled_scene S_CopyCompiledScene(arena *Arena, compiled_scene *Compiled static scene_proc *S_FindProcByName(compiled_scene *Compiled, string Name); static scene_named_value *S_FindGlobalVariableByName(scene_runtime *Runtime, string Name, b32 AlwaysCreate = true); static void S_ResetRuntime(scene_runtime *Runtime); -static scene_runtime_result S_Run(scene_runtime *Runtime, arena *FrameArena, b32 AdvanceOnAwait); +static scene_runtime_result S_Run(scene_runtime *Runtime, arena *Arena, b32 AdvanceOnAwait); #endif //VN_SCENE_H diff --git a/code/vn_text_op.h b/code/vn_text_op.h index 1b668d6..96d2a45 100644 --- a/code/vn_text_op.h +++ b/code/vn_text_op.h @@ -482,26 +482,26 @@ static text_op TextOpFromAction(arena *Arena, string String, Op.NewCursor = Op.NewMark = Op.Range.Min; } - if(Action->Codepoint != 0) + //- sixten: handle insertions { - Op.ReplaceString = StringFromCodepoint(Arena, Action->Codepoint); + b32 InsertedSomething = false; + if(Action->Codepoint != 0) + { + Op.ReplaceString = StringFromCodepoint(Arena, Action->Codepoint); + InsertedSomething = true; + } + else if(Action->Flags & TextActionFlag_Paste) + { + Op.ReplaceString = RemoveAll(Arena, Platform.GetClipboard(Arena), '\r');; + InsertedSomething = true; + } - if(State->Cursor == State->Mark) + if(InsertedSomething) { - Op.NewCursor += Op.ReplaceString.Count; - Op.Range = Range1S64(State->Cursor, State->Cursor); + range1_s64 Selection = Range1S64(State->Cursor, State->Mark); + Op.Range = Selection; + Op.NewCursor = Op.NewMark = Selection.Min+Op.ReplaceString.Count; } - else - { - Op.NewCursor += Op.ReplaceString.Count; - Op.Range = Range1S64(State->Cursor, State->Mark); - } - } - else if(Action->Flags & TextActionFlag_Paste) - { - Op.ReplaceString = Platform.GetClipboard(Arena); - Op.Range = Range1S64(State->Cursor, State->Cursor); - Op.NewCursor += Op.ReplaceString.Count; } if(!(Action->Flags & TextActionFlag_KeepMark)) diff --git a/code/vn_ui_utils.cpp b/code/vn_ui_utils.cpp index 6afd2c1..00b5ec1 100644 --- a/code/vn_ui_utils.cpp +++ b/code/vn_ui_utils.cpp @@ -121,12 +121,12 @@ static ui_signal UI_Button(string String) { UI_SetNextHoverCursor(PlatformCursor_Hand); ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText| - UI_BoxFlag_DrawBackground| - UI_BoxFlag_DrawBorder| - UI_BoxFlag_HotAnimation| - UI_BoxFlag_ActiveAnimation| - UI_BoxFlag_Clickable, - String); + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_HotAnimation| + UI_BoxFlag_ActiveAnimation| + UI_BoxFlag_Clickable, + String); ui_signal Signal = UI_SignalFromBox(Box); return(Signal); } @@ -143,12 +143,12 @@ static ui_signal UI_ButtonF(char *Format, ...) va_end(Arguments); ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText| - UI_BoxFlag_DrawBackground| - UI_BoxFlag_DrawBorder| - UI_BoxFlag_HotAnimation| - UI_BoxFlag_ActiveAnimation| - UI_BoxFlag_Clickable, - String); + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_HotAnimation| + UI_BoxFlag_ActiveAnimation| + UI_BoxFlag_Clickable, + String); ui_signal Signal = UI_SignalFromBox(Box); ReleaseScratch(Scratch); @@ -200,24 +200,26 @@ static ui_signal UI_Scrollbar(axis2 Axis, string Name, r32 Size, r32 Offset) UI_SetNextFont(Font_Icons); UI_MakeBoxF(UI_BoxFlag_DrawText, "%U", Axis?FontIcon_UpDir:FontIcon_LeftDir); - UI_Spacer(UI_Pixels(Offset, 1)); - - UI_SetNextCornerRadius(4.0f); - UI_SetNextAxisSize(Axis, UI_Pixels(Size, 1)); - UI_SetNextAxisSize(Opposite(Axis), UI_Percent(1, 1)); - - Signal = UI_SignalFromBox(UI_MakeBox(UI_BoxFlag_DrawBorder | - UI_BoxFlag_DrawBackground | - UI_BoxFlag_Clickable | - UI_BoxFlag_HotAnimation | - UI_BoxFlag_ActiveAnimation, - StrLit("Slider"))); - - UI_Spacer(UI_Percent(1, 0)); - - UI_SetNextSize(UI_Em(1, 1), UI_Em(1, 1)); - UI_SetNextFont(Font_Icons); - UI_MakeBoxF(UI_BoxFlag_DrawText, "%U", Axis?FontIcon_DownDir:FontIcon_RightDir); + Offset = Clamp(Offset, 0, DimOfRange(UI_TopParent()->Rect).E[Axis]-Size-UI_TopFontSize()*2); + + UI_Spacer(UI_Pixels(Offset, 1)); + + UI_SetNextCornerRadius(4.0f); + UI_SetNextAxisSize(Axis, UI_Pixels(Size, 1)); + UI_SetNextAxisSize(Opposite(Axis), UI_Percent(1, 1)); + + Signal = UI_SignalFromBox(UI_MakeBox(UI_BoxFlag_DrawBorder | + UI_BoxFlag_DrawBackground | + UI_BoxFlag_Clickable | + UI_BoxFlag_HotAnimation | + UI_BoxFlag_ActiveAnimation, + StrLit("Slider"))); + + UI_Spacer(UI_Percent(1, 0)); + + UI_SetNextSize(UI_Em(1, 1), UI_Em(1, 1)); + UI_SetNextFont(Font_Icons); + UI_MakeBoxF(UI_BoxFlag_DrawText, "%U", Axis?FontIcon_DownDir:FontIcon_RightDir); } return(Signal); @@ -247,7 +249,7 @@ static void UI_ScrollBegin(r32 *X, r32 *Y, ui_box_flags Flags, string Name) } UI_SetNextSize(AllowOnX?UI_ChildrenSum(1, 1):UI_Percent(1, 0), - AllowOnY?UI_ChildrenSum(1, 1):UI_Percent(1, 0)); + AllowOnY?UI_ChildrenSum(1, 1):UI_Percent(1, 0)); ui_box *ScrollableBox = UI_MakeBox(ScrollFlags, StrLit("Scrollable Box")); @@ -300,8 +302,8 @@ static void UI_ScrollEnd(r32 *X, r32 *Y, ui_box_flags Flags, string Name) else { for(platform_event *Event = UI_EventList()->First; - Event != 0; - Event = Event->Next) + Event != 0; + Event = Event->Next) { if(Event->Type == PlatformEvent_MouseScroll && Event->Scroll.x != 0) { @@ -351,8 +353,8 @@ static void UI_ScrollEnd(r32 *X, r32 *Y, ui_box_flags Flags, string Name) else { for(platform_event *Event = UI_EventList()->First; - Event != 0; - Event = Event->Next) + Event != 0; + Event = Event->Next) { if(Event->Type == PlatformEvent_MouseScroll && Event->Scroll.y != 0) { @@ -394,12 +396,12 @@ static r32 UI_Slider(r32 Value, range1_r32 Range) UI_SetNextSize(UI_Em(1, 1), UI_Em(1, 1)); UI_SetNextFixedX((DimOfRange(Container->Rect).x-UI_TopFontSize())*(Value-Range.Min)/DimOfRange(Range)); ui_box *Box = UI_MakeBoxF(UI_BoxFlag_DrawBackground| - UI_BoxFlag_DrawBorder| - UI_BoxFlag_HotAnimation| - UI_BoxFlag_ActiveAnimation| - UI_BoxFlag_Clickable| - UI_BoxFlag_FloatingX| - 0, "Dragable"); + UI_BoxFlag_DrawBorder| + UI_BoxFlag_HotAnimation| + UI_BoxFlag_ActiveAnimation| + UI_BoxFlag_Clickable| + UI_BoxFlag_FloatingX| + 0, "Dragable"); ui_signal Signal = UI_SignalFromBox(Box); if(Signal.Dragging) { @@ -426,12 +428,12 @@ static void UI_TooltipLabel(string Label, v2 P) UI_CornerRadius(4); UI_SetNextFixedP(P+V2R32(15.0f, 0.0f)); UI_MakeBox(UI_BoxFlag_DrawBorder | - UI_BoxFlag_DrawBackground | - UI_BoxFlag_DrawText | - UI_BoxFlag_DrawDropShadow | - UI_BoxFlag_FloatingX | - UI_BoxFlag_FloatingY, - Label); + UI_BoxFlag_DrawBackground | + UI_BoxFlag_DrawText | + UI_BoxFlag_DrawDropShadow | + UI_BoxFlag_FloatingX | + UI_BoxFlag_FloatingY, + Label); } } diff --git a/code/vn_workspace.cpp b/code/vn_workspace.cpp index 41151c6..11399c6 100644 --- a/code/vn_workspace.cpp +++ b/code/vn_workspace.cpp @@ -80,14 +80,14 @@ static void W_ProcessKeyBinds() platform_event_list *EventList = Workspace->EventList; for(platform_event *Event = EventList->First; - Event != 0; - Event = Event->Next) + Event != 0; + Event = Event->Next) { if(Event->Type == PlatformEvent_Press) { for(s32 KeybindIndex = 0; - KeybindIndex < ArrayCount(Workspace_Keybinds); - ++KeybindIndex) + KeybindIndex < ArrayCount(Workspace_Keybinds); + ++KeybindIndex) { workspace_keybind *Keybind = Workspace_Keybinds + KeybindIndex; if((Event->Key == Keybind->Key) && (Event->Modifiers == Keybind->Modifiers)) @@ -111,12 +111,12 @@ static ui_signal W_BuildToolbarButton(char *Text, workspace_toolbar_menu Menu) UI_SetNextBackgroundColor(ColorFromHex(0x252728FF)); ui_box *Box = UI_MakeBoxF(UI_BoxFlag_DrawBackground | - UI_BoxFlag_DrawBorder | - UI_BoxFlag_DrawText | - UI_BoxFlag_HotAnimation | - UI_BoxFlag_ActiveAnimation | - UI_BoxFlag_Clickable, - Text); + UI_BoxFlag_DrawBorder | + UI_BoxFlag_DrawText | + UI_BoxFlag_HotAnimation | + UI_BoxFlag_ActiveAnimation | + UI_BoxFlag_Clickable, + Text); ui_signal Signal = UI_SignalFromBox(Box); @@ -153,11 +153,11 @@ static ui_signal W_BuildMenuItem(u32 Icon, char *Text, char *Shortcut) UI_SetNextHoverCursor(PlatformCursor_Hand); ui_box *Box = UI_MakeBoxF(UI_BoxFlag_DrawBackground | - UI_BoxFlag_DrawBorder | - UI_BoxFlag_HotAnimation | - UI_BoxFlag_ActiveAnimation | - UI_BoxFlag_Clickable, - "Menu Item %s", Text); + UI_BoxFlag_DrawBorder | + UI_BoxFlag_HotAnimation | + UI_BoxFlag_ActiveAnimation | + UI_BoxFlag_Clickable, + "Menu Item %s", Text); UI_Parent(Box) { @@ -184,7 +184,7 @@ static void W_BuildToolbar(void) UI_SetNextBackgroundColor(Theme_BackgroundColor); ui_box *ToolbarBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder, - "Workspace Toolbar"); + "Workspace Toolbar"); UI_Parent(ToolbarBox) { @@ -204,11 +204,11 @@ static void W_BuildToolbar(void) UI_SetNextWidth(UI_Pixels(250, 1)); UI_SetNextHeight(UI_ChildrenSum(MenuT, 1)); ui_box *Dropdown = UI_MakeBoxF(UI_BoxFlag_DrawBackground | - UI_BoxFlag_DrawDropShadow | - UI_BoxFlag_Clip | - UI_BoxFlag_FloatingX | - UI_BoxFlag_FloatingY, - "Workspace Dropdown"); + UI_BoxFlag_DrawDropShadow | + UI_BoxFlag_Clip | + UI_BoxFlag_FloatingX | + UI_BoxFlag_FloatingY, + "Workspace Dropdown"); UI_Parent(Dropdown) UI_BackgroundColor(V4(0.25, 0.25, 0.25, 1)) @@ -300,40 +300,6 @@ static void W_DeletePanel(workspace_panel *Panel) DLLInsertLast(Workspace->FirstFreePanel, Workspace->LastFreePanel, Panel); } -static void W_PanelViewPush(workspace_panel_view_list *List, workspace_panel_view *PanelView) -{ - DLLInsertLast(List->First, List->Last, PanelView); - List->Count += 1; -} - -static void W_PanelViewRemove(workspace_panel_view_list *List, workspace_panel_view *PanelView) -{ - DLLRemove(List->First, List->Last, PanelView); - List->Count -= 1; -} - -static workspace_panel_view *W_CreatePanelView(void) -{ - workspace *Workspace = W_GetState(); - workspace_panel_view *PanelView = Workspace->PanelViewFreeList.First; - if(PanelView) - { - W_PanelViewRemove(&Workspace->PanelViewFreeList, PanelView); - } - else - { - PanelView = PushStruct(Workspace->PanelViewArena, workspace_panel_view); - } - return(PanelView); -} - -static void W_DeletePanelView(workspace_panel_view *PanelView) -{ - workspace *Workspace = W_GetState(); - ZeroStruct(PanelView); - W_PanelViewPush(&Workspace->PanelViewFreeList, PanelView); -} - static void W_SplitPanel(workspace_panel *Panel, axis2 Axis) { workspace *Workspace = W_GetState(); @@ -357,8 +323,8 @@ static void W_SplitPanel(workspace_panel *Panel, axis2 Axis) // sixten: Update the parents of the children. for(workspace_view *Child = NewPanel->FirstView; - Child != 0; - Child = Child->Next) + Child != 0; + Child = Child->Next) { Child->Parent = NewPanel; } @@ -442,12 +408,12 @@ static void W_BuildTabItem(workspace_panel *Panel, workspace_view *View) UI_SetNextCornerRadius(0.0); ui_box *TabBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground | - UI_BoxFlag_DrawDropShadow | - UI_BoxFlag_HotAnimation | - UI_BoxFlag_ActiveAnimation | - UI_BoxFlag_Clip | - UI_BoxFlag_Clickable, - "Workspace Panel Tab Item %S#%p", Name, View); + UI_BoxFlag_DrawDropShadow | + UI_BoxFlag_HotAnimation | + UI_BoxFlag_ActiveAnimation | + UI_BoxFlag_Clip | + UI_BoxFlag_Clickable, + "Workspace Panel Tab Item %S#%p", Name, View); UI_Parent(TabBox) UI_Padding(UI_Pixels(5, 1)) { @@ -506,8 +472,8 @@ static void W_BuildPanelHeader(workspace_panel *Panel) UI_Parent(UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_Clip, "Workspace Panel Header")) { for(workspace_view *View = Panel->FirstView; - View != 0; - View = View->Next) + View != 0; + View = View->Next) { W_BuildTabItem(Panel, View); } @@ -523,10 +489,10 @@ static void W_BuildPanelHeader(workspace_panel *Panel) UI_SetNextHoverCursor(PlatformCursor_Hand); ui_box *CloseBox = UI_MakeBoxF(UI_BoxFlag_HotAnimation | - UI_BoxFlag_ActiveAnimation | - UI_BoxFlag_DrawText | - UI_BoxFlag_Clickable, - "%U", FontIcon_Cancel); + UI_BoxFlag_ActiveAnimation | + UI_BoxFlag_DrawText | + UI_BoxFlag_Clickable, + "%U", FontIcon_Cancel); ui_signal Signal = UI_SignalFromBox(CloseBox); if(Signal.Clicked) @@ -549,8 +515,8 @@ static void W_BuildPanel(workspace_panel *Panel) { r32 TotalOfParent = 0; for(workspace_panel *Child = Parent->First; - Child != 0; - Child = Child->Next) + Child != 0; + Child = Child->Next) { if(Child != Panel) { @@ -579,10 +545,10 @@ static void W_BuildPanel(workspace_panel *Panel) UI_SetNextBackgroundColor(Theme_BackgroundColor); ui_box *BodyBox = UI_MakeBoxF(UI_BoxFlag_DrawBorder | - UI_BoxFlag_DrawBackground | - UI_BoxFlag_Clip | - UI_BoxFlag_Clickable, - "Workspace Panel Body"); + UI_BoxFlag_DrawBackground | + UI_BoxFlag_Clip | + UI_BoxFlag_Clickable, + "Workspace Panel Body"); UI_Parent(BodyBox) { if(Panel->FirstView) @@ -622,7 +588,7 @@ static void W_BuildPanel(workspace_panel *Panel) b32 DragActive = W_GetDragPayload(&Payload); b32 OverlayActive = (DragActive && (Payload.View->Parent != Panel) && - InRange(BodyBox->Rect, UI_GetState()->MouseP)); + InRange(BodyBox->Rect, UI_GetState()->MouseP)); if(OverlayActive && Workspace->DragPayloadState == W_DragPayload_Released) { @@ -640,7 +606,7 @@ static void W_BuildPanel(workspace_panel *Panel) { workspace_panel *OldParent = View->Parent; b32 ViewWasCurrent = ((OldParent->CurrentView == View) && - (Workspace->CurrentPanel == OldParent)); + (Workspace->CurrentPanel == OldParent)); // sixten: Detatch view { @@ -673,9 +639,9 @@ static void W_BuildPanel(workspace_panel *Panel) UI_SetNextSize(UI_Percent(1, 1), UI_Percent(1, 1)); UI_MakeBoxF(UI_BoxFlag_DrawBackground | - UI_BoxFlag_FloatingX | - UI_BoxFlag_FloatingY, - "Workspace Panel Drag Hover"); + UI_BoxFlag_FloatingX | + UI_BoxFlag_FloatingY, + "Workspace Panel Drag Hover"); } } @@ -697,8 +663,8 @@ static void W_BuildPanel(workspace_panel *Panel) { s32 ChildCount = 0; for(workspace_panel *Child = Panel->First; - Child != 0; - Child = Child->Next) + Child != 0; + Child = Child->Next) { ++ChildCount; } @@ -711,8 +677,8 @@ static void W_BuildPanel(workspace_panel *Panel) r32 SizeScalar = 1.0 - PercentPaddedSpace; for(workspace_panel *Child = Panel->First; - Child != 0; - Child = Child->Next) + Child != 0; + Child = Child->Next) { UI_SetNextAxisSize(Panel->SplitAxis, UI_Percent(Child->PercentOfParent*SizeScalar, 0)); UI_SetNextAxisSize(Opposite(Panel->SplitAxis), UI_Percent(1, 0)); @@ -729,8 +695,8 @@ static void W_BuildPanel(workspace_panel *Panel) if(Signal.Hovering || Signal.Dragging) { Platform.SetCursor((Panel->SplitAxis == Axis2_X) ? - PlatformCursor_ArrowHorizontal : - PlatformCursor_ArrowVertical); + PlatformCursor_ArrowHorizontal : + PlatformCursor_ArrowVertical); } if(Signal.Dragging) diff --git a/code/vn_workspace.h b/code/vn_workspace.h index 9bb4732..dff9152 100644 --- a/code/vn_workspace.h +++ b/code/vn_workspace.h @@ -103,9 +103,6 @@ struct workspace workspace_drag_payload_state DragPayloadState; workspace_drag_payload DragPayload; - arena *PanelViewArena; - workspace_panel_view_list PanelViewFreeList; - workspace_toolbar_menu Menu; v2 MenuP; r32 MenuT; @@ -138,12 +135,6 @@ static void W_SplitPanel(workspace_panel *Panel, axis2 Axis); //- sixten: Views static b32 W_ViewIsDragged(workspace_view *View); -//- sixten: Panel Views -static void W_PanelViewPush(workspace_panel_view_list *List, workspace_panel_view *PanelView); -static void W_PanelViewRemove(workspace_panel_view_list *List, workspace_panel_view *PanelView); -static workspace_panel_view *W_CreatePanelView(void); -static void W_DeletePanelView(workspace_panel_view *PanelView); - //- sixten: Builder code static ui_signal W_BuildToolbarButton(char *Text, workspace_toolbar_menu Menu); static ui_signal W_BuildMenuItem(u32 Icon, char *Text, char *Shortcut); diff --git a/code/vn_workspace_text_editor.cpp b/code/vn_workspace_text_editor.cpp index aecc19a..34d3dcd 100644 --- a/code/vn_workspace_text_editor.cpp +++ b/code/vn_workspace_text_editor.cpp @@ -75,6 +75,7 @@ static workspace_text_data W_TextDataFromString(arena *Arena, string Text) //- sixten: gather all line ranges range1_s64_list Lines = {}; + s64 MaxLineCount = 0; { u8 *TextBegin = Text.Data; u8 *TextEnd = TextBegin + Text.Count; @@ -86,6 +87,10 @@ static workspace_text_data W_TextDataFromString(arena *Arena, string Text) //- sixten: push line range on newline and EOF if(Char == TextEnd || *Char == '\n') { + if(DimOfRange(Range) > MaxLineCount) + { + MaxLineCount = DimOfRange(Range); + } Range1S64ListPush(Scratch.Arena, &Lines, Range); Range = Range1S64(Range.Max, Range.Max); } @@ -97,6 +102,7 @@ static workspace_text_data W_TextDataFromString(arena *Arena, string Text) { Result.Tokens = Tokens; Result.Lines = Range1S64ArrayFromList(Arena, &Lines);; + Result.MaxLineCount = MaxLineCount; } ReleaseScratch(Scratch); return(Result); @@ -107,6 +113,7 @@ static void W_TextEditorApplyChanges(workspace_view_text_editor *Editor) workspace_text_data TextData = W_TextDataFromString(Editor->ProcessingArena, Editor->Text.String); Editor->Tokens = TextData.Tokens; Editor->Lines = TextData.Lines; + Editor->MaxLineCount = TextData.MaxLineCount; Editor->Compiled = S_ScriptFromText(Editor->ProcessingArena, Editor->Text.String); if(Editor->Compiled.IsValid) { @@ -136,247 +143,6 @@ static void W_SaveTextEditorToFile(workspace_view_text_editor *Editor) //////////////////////////////// //~ sixten: Workspace Text Editor Builder Functions -static UI_CUSTOM_DRAW_CALLBACK(W_TextEditorDrawCallback) -{ - temp Scratch = GetScratch(); - workspace_view_text_editor *Editor = (workspace_view_text_editor *)Data; - - //- sixten: get dimensions & scroll offset from container - ui_box *ContainerBox = Editor->ContainerBox; - range2_r32 ParentRect = ContainerBox->Rect; - v2 ParentDim = DimOfRange(ParentRect); - v2 Offset = Box->Parent->Offset; - - //- sixten: rendering properties - r32 FontSize = Editor->FontSize; - r32 LineHeight = FontSize + 4.0f; - - //- sixten: calculate the dimensions of the glyphs - glyph *Glyph = GetGlyph(Atlas, Font_Monospace, 'A', FontSize, 0); - r32 GlyphAdvance = Glyph->Advance; - - //- sixten: find the text point - text_point CursorTextP = TextPointFromOffset(Editor->Text.String, Editor->EditState.Cursor); - text_point MarkTextP = TextPointFromOffset(Editor->Text.String, Editor->EditState.Mark); - - //- sixten: get the line count - range1_s64_array *Lines = &Editor->Lines; - s64 LineCount = Lines->Count; - - //- sixten: calculate the text dim - Editor->TextDim = V2(1900, LineCount*LineHeight); - - //- sixten: calculate the line margin dim - s32 LineMarginDigitsRequired = 6; - v2_r32 LineMarginDim = V2((LineMarginDigitsRequired)*GlyphAdvance, ParentRect.Max.y - ParentRect.Min.y); - - //- sixten: tokenize text - tokenize_result TokenizeResult = T_TokenizeFromText(Scratch.Arena, Editor->Text.String); - token_array Tokens = TokenizeResult.Tokens; - token *TokensBegin = Tokens.Tokens; - token *TokensEnd = TokensBegin + Tokens.Count; - - //- sixten: find the first visible token - token *VisibleTokensBegin = TokensBegin; - s64 TopMostLine = Min((s64)Floor(-Offset.y / LineHeight), LineCount); - for(s64 LinesFound = 0; LinesFound < TopMostLine && VisibleTokensBegin < TokensEnd; VisibleTokensBegin += 1) - { - if(VisibleTokensBegin->Kind == TokenKind_Newline) - { - LinesFound += 1; - } - } - - //- sixten: find the last visible token - token *VisibleTokensEnd = VisibleTokensBegin; - s64 LinesOnScreen = Min((s64)Floor(ParentDim.y / LineHeight)+1, LineCount-TopMostLine); - for(s64 LinesFound = 0; LinesFound < LinesOnScreen && VisibleTokensEnd < TokensEnd; VisibleTokensEnd += 1) - { - if(VisibleTokensEnd->Kind == TokenKind_Newline) - { - LinesFound += 1; - } - } - - //- sixten: draw line numbers & line highlights - { - //- sixten: draw the background - v4 LineMarginColor = ColorFromHex(0x10203080); - range2_r32 LineMarginBox = Range2R32(ParentRect.Min, ParentRect.Min+LineMarginDim); - PushQuad(Group, LineMarginBox, LineMarginColor, LineMarginColor, LineMarginColor, LineMarginColor, 0, 0, 0); - - //- sixten: draw the numbers - v2_r32 LineOffset = Box->Rect.Min; - for(s64 LineIndex = TopMostLine; LineIndex < TopMostLine + LinesOnScreen; LineIndex += 1) - { - r32 LineY = LineOffset.y + LineIndex*LineHeight; - PushTextF(Group, Atlas, Font_Monospace, V2(0, LineY), FontSize, Color_Grey, "%*.i", LineMarginDigitsRequired, LineIndex+1); - - if(LineIndex + 1 == CursorTextP.Line) - { - v4_r32 LineHighlightColor = ColorFromHex(0x10204080); - range2_r32 LineHighlightBox = Range2R32(V2(LineMarginBox.Max.x, LineY), V2(Box->Rect.Max.x, LineY+LineHeight)); - PushQuad(Group, LineHighlightBox, LineHighlightColor, LineHighlightColor, LineHighlightColor, LineHighlightColor, 0, 0, 0); - } - } - } - - //- sixten: render tokens - v2 BaseTokenP = Box->Rect.Min+V2(LineMarginDim.x, TopMostLine*LineHeight); - v2 TokenP = BaseTokenP; - for(token *Token = VisibleTokensBegin; Token < VisibleTokensEnd; Token += 1) - { - string TokenString = T_StringFromToken(Editor->Text.String, *Token); - - //- sixten: get color & font from token - font_id Font = Font_Monospace; - v4 Color = Color_Magenta; - if(Token->Kind == TokenKind_Comment) { Color = Color_Grey; Font = Font_MonospaceOblique; } - else if(Token->Kind > TokenKind_SymbolsBegin && Token->Kind < TokenKind_SymbolsEnd) { Color = Color_Grey; } - else if(Token->Kind == TokenKind_StringLiteral) { Color = ColorFromHex(0xffa900ff); } - else if(Token->Kind == TokenKind_Numeric) { Color = ColorFromHex(0xffa900ff); } - else if(Token->Kind > TokenKind_KeywordsBegin && Token->Kind < TokenKind_KeywordsEnd) - { - if(Token->Kind == TokenKind_True || Token->Kind == TokenKind_False) - { - Color = ColorFromHex(0xffa900ff); - } - else - { - Color = ColorFromHex(0xf0c674ff); - } - } - else if(Token->Kind == TokenKind_Identifier) - { - Color = Theme_TextColor; - } - - //- sixten: check for errors - b32 ConsideredError = false; - for(scene_compile_error *Error = Editor->Compiled.Errors.First; Error != 0; Error = Error->Next) - { - if(Error->Token.Range.Min == Token->Range.Min && - Error->Token.Range.Max == Token->Range.Max) - { - ConsideredError = true; - break; - } - } - - //- sixten: render & advance by token - if(!(T_IsWhitespace(Token->Kind))) - { - if(Token->Kind == TokenKind_Comment) - { - //- sixten: advance to newline and push text - // sixten(TODO): proper multiline comment rendering. - u8 *TextBegin = TokenString.Data; - u8 *TextEnd = TextBegin+TokenString.Count; - u8 *Marker = TextBegin; - for(u8 *Byte = TextBegin; Byte <= TextEnd; Byte += 1) - { - if(*Byte == '\n' || Byte == TextEnd) - { - PushText(Group, Atlas, Font, TokenP, FontSize, Color, MakeString(Marker, Byte-Marker)); - Marker = Byte+1; - - if(*Byte == '\n' && Byte != TextEnd) - { - TokenP.x = BaseTokenP.x; - TokenP.y += LineHeight; - } - } - } - } - else - { - r32 TokenWidth = PushText(Group, Atlas, Font, TokenP, FontSize, Color, TokenString); - - //- sixten: render error highlight - if(ConsideredError) - { - range2_r32 Dest = Range2R32(TokenP+V2R32(0, LineHeight-3), TokenP+V2R32(TokenWidth, LineHeight)); - v4_r32 ErrorColor = V4R32(0.9f, 0.3f, 0.3f, 0.8f); - PushQuad(Group, Dest, ErrorColor, ErrorColor, ErrorColor, ErrorColor, 3, 0.4, 0); - } - TokenP.x += TokenWidth; - } - } - else - { - if(Token->Kind == TokenKind_Newline) - { - TokenP.x = BaseTokenP.x; - TokenP.y += LineHeight; - } - else - { - u8 *StringBegin = TokenString.Data; - u8 *StringEnd = StringBegin + TokenString.Count; - for(u8 *Char = StringBegin; Char < StringEnd; Char += 1) - { - if(*Char == ' ' || *Char == '\t') - { - TokenP.x += GlyphAdvance; - } - } - } - } - } - - //- sixten: render cursor - { - s64 LineIndex = CursorTextP.Line-1; - string Line = Substring(Editor->Text.String, Editor->Lines.Ranges[LineIndex]); - s64 ColumnIndex = CursorTextP.Column-1; - s64 ColumnOffset = UTF8OffsetFromIndex(Line, ColumnIndex); - - v2 TargetCursorP = Box->Rect.Min+V2(LineMarginDim.x+ColumnOffset*GlyphAdvance, LineIndex*LineHeight); - v2 CursorP = V2(AC_AnimateValueF(TargetCursorP.x, TargetCursorP.x, 0.1, "Workspace Text Editor Cursor X %p", Editor), - AC_AnimateValueF(TargetCursorP.y, TargetCursorP.y, 0.1, "Workspace Text Editor Cursor Y %p", Editor)); - v2 CursorDim = V2(2, LineHeight); - range2_r32 CursorRect = Range2R32(CursorP, CursorP+CursorDim); - v4 CursorColor = ColorFromHex(0x10FF20FF); - PushQuad(Group, CursorRect, CursorColor, CursorColor, CursorColor, CursorColor, 2, 0.4, 0); - } - - //- sixten: render the selection - { - text_range Selection = TextRange(CursorTextP, MarkTextP); - range1_s64 LineRange = Range1S64(Selection.Min.Line, Selection.Max.Line); - for(s64 LineIndex = TopMostLine; LineIndex < TopMostLine + LinesOnScreen; LineIndex += 1) - { - if(Contains(LineRange, LineIndex + 1)) - { - range1_s64 ColumnRange = Lines->Ranges[LineIndex]; - range1_s64 NormalizedColumnRange = Range1S64(0, DimOfRange(ColumnRange)); - if(LineIndex+1 == LineRange.Min && LineIndex+1 == LineRange.Max) - { - NormalizedColumnRange = Range1S64(Editor->EditState.Cursor - ColumnRange.Min, Editor->EditState.Mark - ColumnRange.Min); - } - else if(LineIndex+1 == LineRange.Min) - { - NormalizedColumnRange = Range1S64(Min(Editor->EditState.Mark, Editor->EditState.Cursor) - ColumnRange.Min, DimOfRange(ColumnRange)); - } - else if(LineIndex+1 == LineRange.Max) - { - NormalizedColumnRange = Range1S64(0, Max(Editor->EditState.Mark, Editor->EditState.Cursor) - ColumnRange.Min); - } - - string Line = Substring(Editor->Text.String, ColumnRange); - range1_s64 ColumnOffsetRange = Range1S64(UTF8OffsetFromIndex(Line, NormalizedColumnRange.Min), - UTF8OffsetFromIndex(Line, NormalizedColumnRange.Max)); - - r32 LineY = LineIndex*LineHeight; - v4_r32 LineHighlightColor = ColorFromHex(0x66B3CC4C); - range2_r32 LineHighlightBox = Range2R32(Box->Rect.Min+V2(LineMarginDim.x+ColumnOffsetRange.Min*GlyphAdvance, LineY), - Box->Rect.Min+V2(LineMarginDim.x+ColumnOffsetRange.Max*GlyphAdvance, LineY+LineHeight)); - PushQuad(Group, LineHighlightBox, LineHighlightColor, LineHighlightColor, LineHighlightColor, LineHighlightColor, 4, 1.4, 0); - } - } - } - ReleaseScratch(Scratch); -} static b32 W_ProcessTextEditorEvent(workspace_view_text_editor *Editor, platform_event *Event) { b32 CursorHasBeenModified = false; @@ -402,8 +168,8 @@ static b32 W_ProcessTextEditorEvent(workspace_view_text_editor *Editor, platform range1_s64 Selection = Range1S64(Editor->EditState.Cursor, Editor->EditState.Mark); AppendToHistory(Editor->HistoryArena, List, - HistoryEntry(Editor->HistoryArena, Op.ReplaceString, Op.Range), - HistoryEntry(Editor->HistoryArena, Substring(Editor->Text.String, Op.Range), Range1S64(Op.Range.Min, Op.Range.Min+Op.ReplaceString.Count))); + HistoryEntry(Editor->HistoryArena, Op.ReplaceString, Op.Range), + HistoryEntry(Editor->HistoryArena, Substring(Editor->Text.String, Op.Range), Range1S64(Op.Range.Min, Op.Range.Min+Op.ReplaceString.Count))); List->At = List->Sentinel.Prev; } @@ -435,303 +201,590 @@ static void W_BuildTextEditorInfoBar(workspace_view_text_editor *Editor) } } -static void W_BuildTextEditor(workspace_view *View) +static void W_BuildTextEditorErrorList(workspace_view_text_editor *Editor) { - workspace_view_text_editor *Editor = (workspace_view_text_editor *)View->Data; - - temp Scratch = GetScratch(); - + r32 TargetFooterHeightEm = 2.25f*Min(Editor->Compiled.Errors.Count, 10LL); + UI_Size(UI_Percent(1, 0), UI_Em(AC_AnimateValueF(TargetFooterHeightEm, TargetFooterHeightEm, 0.3, "Error Lister %p", Editor), 1)) UI_Column() UI_Height(UI_TextContent(0, 1)) + { + s64 Index = 0; + for(scene_compile_error *Error = Editor->Compiled.Errors.First; Error != 0; Error = Error->Next, Index += 1) + { + UI_SetNextHeight(UI_ChildrenSum(1, 1)); + UI_SetNextLayoutAxis(Axis2_X); + UI_Parent(UI_MakeBoxF(0, "Editor Error Lister Container %p", Error)) UI_Padding(UI_Em(1, 1)) UI_Height(UI_Em(1.75f, 1)) + { + UI_SetNextBackgroundColor(SetAlpha(Theme_BorderColor, 0.8f)); + UI_SetNextCornerRadius(4); + UI_SetNextLayoutAxis(Axis2_X); + UI_SetNextHoverCursor(PlatformCursor_Hand); + ui_box *ContainerBox = UI_MakeBoxF(UI_BoxFlag_Clickable|UI_BoxFlag_DrawDropShadow|UI_BoxFlag_DrawBorder, "Container Box"); + + UI_Parent(ContainerBox) UI_Padding(UI_Em(1, 1)) UI_Width(UI_TextContent(0, 1)) + { + UI_Font(Font_Icons) UI_LabelF("%U", FontIcon_Attention); + UI_Spacer(UI_Em(0.5f, 1)); + // sixten(TODO): this is dumb, slow and downright stupid. + text_point Point = TextPointFromOffset(Editor->Text.String, Error->Token.Range.Min); + UI_LabelF("%i:%i", Point.Line, Point.Column); + UI_Spacer(UI_Em(0.5f, 1)); + UI_Label(Error->Message); + UI_Spacer(UI_Percent(1, 0)); + } + + ui_signal Signal = UI_SignalFromBox(ContainerBox); + if(Signal.Hovering) + { + UI_TooltipLabel(StrLit("Goto in source"), UI_MouseP()); + } + } + UI_Spacer(UI_Em(0.5, 1)); + } + } +} + +UI_CUSTOM_DRAW_CALLBACK(W_TextEditorLinesBarDrawCallback) +{ + workspace_view_text_editor *Editor = (workspace_view_text_editor *)Data; + + //- sixten: calculate dimensions + ui_box *Parent = Box->Parent; + v2_r32 ParentDim = DimOfRange(Parent->Rect); + + r32 FontSize = Editor->FontSize; + r32 LineHeight = FontSize + 4.0f; + + s64 LineStart = Floor(-Parent->Offset.y/LineHeight); + s64 LineEnd = Min(Editor->Lines.Count, (s64)Floor((ParentDim.y-Parent->Offset.y)/LineHeight)+1); + + s64 LineNumberCount = (s64)(Log(Editor->Lines.Count)/Log(10))+1; + + for(s64 Line = LineStart; Line < LineEnd; Line += 1) + { + PushTextF(Group, Atlas, Font_Monospace, Box->Rect.Min+V2R32(0, Line*LineHeight), Editor->FontSize, Color_Grey, " %*i", LineNumberCount, Line+1); + } +} + +UI_CUSTOM_DRAW_CALLBACK(W_TextEditorDrawCallback) +{ + workspace_view_text_editor *Editor = (workspace_view_text_editor *)Data; + temp Scratch = GetScratch(); + + //- sixten: calculate dimensions + ui_box *Parent = Box->Parent; + v2_r32 ParentDim = DimOfRange(Parent->Rect); + //- sixten: rendering properties - r32 FontSize = Editor->FontSize = 13.0f; + r32 FontSize = Editor->FontSize; r32 LineHeight = FontSize + 4.0f; //- sixten: calculate the dimensions of the glyphs - glyph *Glyph = GetGlyph(UI_GlyphAtlas(), Font_Monospace, 'A', FontSize, 0); + glyph *Glyph = GetGlyph(Atlas, Font_Monospace, 'A', FontSize, 0); r32 GlyphAdvance = Glyph->Advance; - //- sixten: calculate the line margin dim - s32 LineMarginDigitsRequired = 6; - r32 LineMarginWidth = (LineMarginDigitsRequired)*GlyphAdvance; + //- sixten: find the text point + text_point CursorTextP = TextPointFromOffset(Editor->Text.String, Editor->EditState.Cursor); + text_point MarkTextP = TextPointFromOffset(Editor->Text.String, Editor->EditState.Mark); + s64 LineStart = Floor(-Parent->Offset.y/LineHeight); + s64 LineEnd = Min(Editor->Lines.Count, (s64)Floor((ParentDim.y-Parent->Offset.y)/LineHeight)+1); + + //- sixten: tokenize text + tokenize_result TokenizeResult = T_TokenizeFromText(Scratch.Arena, Editor->Text.String); + token_array Tokens = TokenizeResult.Tokens; + token *TokensBegin = Tokens.Tokens; + token *TokensEnd = TokensBegin + Tokens.Count; + v2_r32 StartTokenP = Box->Rect.Min; + + //- sixten: find the first visible token + token *VisibleTokensBegin = TokensBegin; + for(s64 LinesFound = 0; LinesFound < LineStart && VisibleTokensBegin < TokensEnd; VisibleTokensBegin += 1) { - //- sixten: build & handle the text editor - ui_box *EditorBox = 0; - UI_SetNextSize(UI_Percent(1, 1), UI_Percent(1, 0)); - UI_Scroll(0, &Editor->Offset.y) + if(VisibleTokensBegin->Kind == TokenKind_Newline) { - //- sixten: find the container box for the scrollable region - Editor->ContainerBox = UI_TopParent()->Parent->Parent; - - UI_SetNextSize(UI_Pixels(Editor->TextDim.x, 1), UI_Pixels(Editor->TextDim.y, 1)); - EditorBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_Clickable, "Workspace Text Editor %p", View); - UI_EquipBoxCustomDrawCallback(EditorBox, W_TextEditorDrawCallback, Editor); + LinesFound += 1; + StartTokenP.y += LineHeight; } - - //- sixten: build footer - W_BuildTextEditorInfoBar(Editor); - r32 TargetFooterHeightEm = 2.25f*Min(Editor->Compiled.Errors.Count, 10LL); - UI_Size(UI_Percent(1, 0), UI_Em(AC_AnimateValueF(TargetFooterHeightEm, TargetFooterHeightEm, 0.3, "Error Lister %p", Editor), 1)) UI_Column() UI_Height(UI_TextContent(0, 1)) + } + + //- sixten: find the last visible token + token *VisibleTokensEnd = VisibleTokensBegin; + for(s64 LinesFound = 0; LinesFound < LineEnd-LineStart && VisibleTokensEnd < TokensEnd; VisibleTokensEnd += 1) + { + if(VisibleTokensEnd->Kind == TokenKind_Newline) { - s64 Index = 0; - for(scene_compile_error *Error = Editor->Compiled.Errors.First; Error != 0; Error = Error->Next, Index += 1) - { - UI_SetNextHeight(UI_ChildrenSum(1, 1)); - UI_SetNextLayoutAxis(Axis2_X); - UI_Parent(UI_MakeBoxF(0, "Editor Error Lister Container %p", Error)) UI_Padding(UI_Em(1, 1)) UI_Height(UI_Em(1.75f, 1)) - { - UI_SetNextBackgroundColor(SetAlpha(Theme_BorderColor, 0.8f)); - UI_SetNextCornerRadius(4); - UI_SetNextLayoutAxis(Axis2_X); - UI_SetNextHoverCursor(PlatformCursor_Hand); - ui_box *ContainerBox = UI_MakeBoxF(UI_BoxFlag_Clickable|UI_BoxFlag_DrawDropShadow|UI_BoxFlag_DrawBorder, "Container Box"); - - UI_Parent(ContainerBox) UI_Padding(UI_Em(1, 1)) UI_Width(UI_TextContent(0, 1)) - { - UI_Font(Font_Icons) UI_LabelF("%U", FontIcon_Attention); - UI_Spacer(UI_Em(0.5f, 1)); - // sixten(TODO): this is dumb, slow and downright stupid. - text_point Point = TextPointFromOffset(Editor->Text.String, Error->Token.Range.Min); - UI_LabelF("%i:%i", Point.Line, Point.Column); - UI_Spacer(UI_Em(0.5f, 1)); - UI_Label(Error->Message); - UI_Spacer(UI_Percent(1, 0)); - } - - ui_signal Signal = UI_SignalFromBox(ContainerBox); - if(Signal.Hovering) - { - UI_TooltipLabel(StrLit("Goto in source"), UI_MouseP()); - } - } - UI_Spacer(UI_Em(0.5, 1)); - } + LinesFound += 1; } + } + + //- sixten: render tokens + v2_r32 TokenP = StartTokenP; + for(token *Token = VisibleTokensBegin; Token < VisibleTokensEnd; Token += 1) + { + string TokenString = T_StringFromToken(Editor->Text.String, *Token); - b32 CursorHasBeenModified = false; - - if(W_ViewIsCurrent(View)) + //- sixten: get color & font from token + font_id Font = Font_Monospace; + v4 Color = Color_Magenta; + if(Token->Kind == TokenKind_Comment) { Color = Color_Grey; Font = Font_MonospaceOblique; } + else if(Token->Kind > TokenKind_SymbolsBegin && Token->Kind < TokenKind_SymbolsEnd) { Color = Color_Grey; } + else if(Token->Kind == TokenKind_StringLiteral) { Color = ColorFromHex(0xffa900ff); } + else if(Token->Kind == TokenKind_Numeric) { Color = ColorFromHex(0xffa900ff); } + else if(Token->Kind > TokenKind_KeywordsBegin && Token->Kind < TokenKind_KeywordsEnd) { - //- sixten: handle history + if(Token->Kind == TokenKind_True || Token->Kind == TokenKind_False) { - history_list *List = &Editor->History; - - //- sixten: undo - if(Platform_KeyPress(UI_EventList(), Key_Z, PlatformModifier_Ctrl)) - { - history_node *Node = List->At; - if(Node != &List->Sentinel) - { - //- sixten: get entry & apply - history_entry Entry = Node->Backward; - MutableStringReplaceRange(&Editor->Text, Entry.ReplaceString, Entry.Range); - W_TextEditorApplyChanges(Editor); - Editor->EditState.Cursor = Editor->EditState.Mark = Entry.Range.Min+Entry.ReplaceString.Count; - CursorHasBeenModified = true; - - List->At = Node->Prev; - } - } - - //- sixten: redo - if(Platform_KeyPress(UI_EventList(), Key_Y, PlatformModifier_Ctrl)) - { - history_node *Node = List->At->Next; - if(Node != &List->Sentinel) - { - //- sixten: get entry & apply - history_entry Entry = Node->Forward; - MutableStringReplaceRange(&Editor->Text, Entry.ReplaceString, Entry.Range); - W_TextEditorApplyChanges(Editor); - Editor->EditState.Cursor = Editor->EditState.Mark = Entry.Range.Min+Entry.ReplaceString.Count; - CursorHasBeenModified = true; - - List->At = Node; - } - } - } - - //- sixten: save - if(Platform_KeyPress(UI_EventList(), Key_S, PlatformModifier_Ctrl)) - { - W_SaveTextEditorToFile(Editor); - } - - //- sixten: select all - if(Platform_KeyPress(UI_EventList(), Key_A, PlatformModifier_Ctrl)) - { - Editor->EditState.Mark = 0; - Editor->EditState.Cursor = Editor->Text.String.Count; - } - - //- sixten: keyboard input -> text op - for(platform_event *Event = UI_EventList()->First; - Event != 0; - Event = Event->Next) - { - if(Event->Type == PlatformEvent_Press || Event->Type == PlatformEvent_Text) - { - //- sixten: auto-indent - s64 Indent = 0; - if(Event->Codepoint == '\n') - { - string Line = Substring(Editor->Text.String, Editor->Lines.Ranges[Editor->LastTextPoint.Line-1]); - if(Line.Data[Line.Count-1] == '\n') - { - Line.Count -= 1; - } - - for(u8 *Data = Line.Data; *Data == '\t' && Data < Line.Data+Line.Count; Data += 1) - { - Indent += 1; - } - } - - //- sixten: auto close bracket - if(Event->Codepoint == '{') - { - platform_event FakeEvent = {}; - FakeEvent.Codepoint = '}'; - FakeEvent.Type = PlatformEvent_Text; - CursorHasBeenModified |= W_ProcessTextEditorEvent(Editor, &FakeEvent); - FakeEvent.Key = Key_Left;; - FakeEvent.Type = PlatformEvent_Press; - CursorHasBeenModified |= W_ProcessTextEditorEvent(Editor, &FakeEvent); - } - - //- sixten: auto close string literal - if(Event->Codepoint == '"') - { - platform_event FakeEvent = {}; - FakeEvent.Codepoint = '"'; - FakeEvent.Type = PlatformEvent_Text; - CursorHasBeenModified |= W_ProcessTextEditorEvent(Editor, &FakeEvent); - FakeEvent.Key = Key_Left;; - FakeEvent.Type = PlatformEvent_Press; - CursorHasBeenModified |= W_ProcessTextEditorEvent(Editor, &FakeEvent); - } - - CursorHasBeenModified |= W_ProcessTextEditorEvent(Editor, Event); - - //- sixten: apply indent - { - platform_event FakeTab = {}; - FakeTab.Codepoint = '\t'; - FakeTab.Type = PlatformEvent_Text; - - for(s64 IndentIndex = 0; IndentIndex < Indent; IndentIndex += 1) - { - CursorHasBeenModified |= W_ProcessTextEditorEvent(Editor, &FakeTab); - } - } - } - } - } - - //- sixten: right-click dropdown - { - if(Editor->DropdownActive) - { - UI_Tooltip - { - UI_SetNextFixedP(Editor->DropdownP); - UI_SetNextWidth(UI_Em(20, 1)); - UI_SetNextHeight(UI_ChildrenSum(AC_AnimateValueDirect(1, 0.2, &Editor->DropdownTransition), 1)); - UI_SetNextCornerRadius(4); - UI_Parent(UI_MakeBox(UI_BoxFlag_DrawBackground | - UI_BoxFlag_DrawDropShadow | - UI_BoxFlag_Clip | - UI_BoxFlag_FloatingX | - UI_BoxFlag_FloatingY, StrLit("Text Editor Dropdown"))) - UI_Width(UI_Percent(1, 1)) UI_Height(UI_Em(1.66, 1)) - UI_BackgroundColor(V4(0.25, 0.25, 0.25, 1)) - UI_BorderColor(V4(0.45, 0.45, 0.45, 1)) - UI_CornerRadius(2) - { - // sixten(TODO): MAKE THESE BUTTONS ACTUALLY DO STUFF!!! - if(W_BuildMenuItem(FontIcon_Gamepad, "Run in scene view", "").Clicked) - { - SV_SetCurrentSource(&Editor->Compiled); - Editor->DropdownActive = false; - } - if(Editor->EditState.Cursor != Editor->EditState.Mark) - { - if(W_BuildMenuItem(FontIcon_Document, "Copy", "Ctrl+C").Clicked) - { - Editor->DropdownActive = false; - } - if(W_BuildMenuItem(FontIcon_Cut, "Cut", "Ctrl+X").Clicked) - { - Editor->DropdownActive = false; - } - } - if(W_BuildMenuItem(FontIcon_Paste, "Paste", "Ctrl+V").Clicked) - { - Editor->DropdownActive = false; - } - if(W_BuildMenuItem(FontIcon_Floppy, "Save", "Ctrl+S").Clicked) - { - W_SaveTextEditorToFile(Editor); - Editor->DropdownActive = false; - } - } - } - } - } - - ui_signal Signal = UI_SignalFromBox(EditorBox); - - if(Signal.Pressed || (Signal.PressedRight && (Editor->EditState.Cursor == Editor->EditState.Mark))) - { - //- sixten: translate mouse position to text point - v2 MouseOffset = Signal.MouseP - EditorBox->Rect.Min - V2(LineMarginWidth, 0); - s64 LineIndex = Clamp((s64)(MouseOffset.y / LineHeight), 0, Editor->Lines.Count); - - string Line = Substring(Editor->Text.String, Editor->Lines.Ranges[LineIndex]); - s64 ColumnOffset = (s64)(MouseOffset.x / GlyphAdvance); - s64 ColumnIndex = UTF8IndexFromOffset(Line, ColumnOffset); - - text_point Point = {LineIndex + 1, ColumnIndex + 1}; - Editor->EditState.Cursor = Editor->EditState.Mark = OffsetFromTextPoint(Editor->Text.String, Editor->Lines, Point); - } - - if(Signal.Dragging) - { - //- sixten: translate mouse position to text point - v2 MouseOffset = Signal.MouseP - EditorBox->Rect.Min - V2(LineMarginWidth, 0); - s64 LineIndex = Clamp((s64)(MouseOffset.y / LineHeight), 0, Editor->Lines.Count); - string Line = Substring(Editor->Text.String, Editor->Lines.Ranges[LineIndex]); - s64 ColumnOffset = (s64)(MouseOffset.x / GlyphAdvance); - s64 ColumnIndex = UTF8IndexFromOffset(Line, ColumnOffset); - - text_point Point = {LineIndex + 1, ColumnIndex + 1}; - Editor->EditState.Cursor = OffsetFromTextPoint(Editor->Text.String, Editor->Lines, Point); - - CursorHasBeenModified = true; - - Editor->DropdownActive = false; - } - - if(Signal.PressedRight) - { - Editor->DropdownActive = true; - Editor->DropdownP = UI_MouseP(); - Editor->DropdownTransition = 0; - } - - //- sixten: update eventual text point extents - if(CursorHasBeenModified) - { - text_point Point = TextPointFromOffset(Editor->Text.String, Editor->EditState.Cursor); - if(Editor->LastTextPoint.Line == Point.Line) - { - Editor->LastTextPoint = Point; + Color = ColorFromHex(0xffa900ff); } else { - Editor->LastTextPoint.Line = Point.Line; - Editor->LastTextPoint.Column = Max(Editor->LastTextPoint.Column, Point.Column); + Color = ColorFromHex(0xf0c674ff); + } + } + else if(Token->Kind == TokenKind_Identifier) + { + Color = Theme_TextColor; + } + + //- sixten: check for errors + b32 ConsideredError = false; + for(scene_compile_error *Error = Editor->Compiled.Errors.First; Error != 0; Error = Error->Next) + { + if(Error->Token.Range.Min == Token->Range.Min && + Error->Token.Range.Max == Token->Range.Max) + { + ConsideredError = true; + break; + } + } + + //- sixten: render & advance by token + if(!(T_IsWhitespace(Token->Kind))) + { + if(Token->Kind == TokenKind_Comment) + { + //- sixten: advance to newline and push text + // sixten(TODO): proper multiline comment rendering. + u8 *TextBegin = TokenString.Data; + u8 *TextEnd = TextBegin+TokenString.Count; + u8 *Marker = TextBegin; + for(u8 *Byte = TextBegin; Byte <= TextEnd; Byte += 1) + { + if(*Byte == '\n' || Byte == TextEnd) + { + PushText(Group, Atlas, Font, TokenP, FontSize, Color, MakeString(Marker, Byte-Marker)); + Marker = Byte+1; + + if(*Byte == '\n' && Byte != TextEnd) + { + TokenP.x = StartTokenP.x; + TokenP.y += LineHeight; + } + } + } + } + else + { + r32 TokenWidth = PushText(Group, Atlas, Font, TokenP, FontSize, Color, TokenString); + + //- sixten: render error highlight + if(ConsideredError) + { + range2_r32 Dest = Range2R32(TokenP+V2R32(0, LineHeight-3), TokenP+V2R32(TokenWidth, LineHeight)); + v4_r32 ErrorColor = V4R32(0.9f, 0.3f, 0.3f, 0.8f); + PushQuad(Group, Dest, ErrorColor, ErrorColor, ErrorColor, ErrorColor, 3, 0.4, 0); + } + TokenP.x += TokenWidth; + } + } + else + { + if(Token->Kind == TokenKind_Newline) + { + TokenP.x = StartTokenP.x; + TokenP.y += LineHeight; + } + else + { + u8 *StringBegin = TokenString.Data; + u8 *StringEnd = StringBegin + TokenString.Count; + for(u8 *Char = StringBegin; Char < StringEnd; Char += 1) + { + if(*Char == ' ' || *Char == '\t') + { + TokenP.x += GlyphAdvance; + } + } } } } - ReleaseScratch(Scratch); + + //- sixten: render the selection + { + text_range Selection = TextRange(CursorTextP, MarkTextP); + range1_s64 LineRange = Range1S64(Selection.Min.Line, Selection.Max.Line); + for(s64 LineIndex = LineStart; LineIndex < LineEnd; LineIndex += 1) + { + if(Contains(LineRange, LineIndex + 1)) + { + range1_s64 ColumnRange = Editor->Lines.Ranges[LineIndex]; + range1_s64 NormalizedColumnRange = Range1S64(0, DimOfRange(ColumnRange)); + if(LineIndex+1 == LineRange.Min && LineIndex+1 == LineRange.Max) + { + NormalizedColumnRange = Range1S64(Editor->EditState.Cursor - ColumnRange.Min, Editor->EditState.Mark - ColumnRange.Min); + } + else if(LineIndex+1 == LineRange.Min) + { + NormalizedColumnRange = Range1S64(Min(Editor->EditState.Mark, Editor->EditState.Cursor) - ColumnRange.Min, DimOfRange(ColumnRange)); + } + else if(LineIndex+1 == LineRange.Max) + { + NormalizedColumnRange = Range1S64(0, Max(Editor->EditState.Mark, Editor->EditState.Cursor) - ColumnRange.Min); + } + + string Line = Substring(Editor->Text.String, ColumnRange); + range1_s64 ColumnOffsetRange = Range1S64(UTF8OffsetFromIndex(Line, NormalizedColumnRange.Min), + UTF8OffsetFromIndex(Line, NormalizedColumnRange.Max)); + + r32 LineY = LineIndex*LineHeight; + v4_r32 LineHighlightColor = ColorFromHex(0x66B3CC4C); + range2_r32 LineHighlightBox = Range2R32(Box->Rect.Min+V2(ColumnOffsetRange.Min*GlyphAdvance, LineY), + Box->Rect.Min+V2(ColumnOffsetRange.Max*GlyphAdvance, LineY+LineHeight)); + PushQuad(Group, LineHighlightBox, LineHighlightColor, LineHighlightColor, LineHighlightColor, LineHighlightColor, 4, 1.4, 0); + } + } + } + + //- sixten: render cursor + { + s64 LineIndex = CursorTextP.Line-1; + string Line = Substring(Editor->Text.String, Editor->Lines.Ranges[LineIndex]); + s64 ColumnIndex = CursorTextP.Column-1; + s64 ColumnOffset = UTF8OffsetFromIndex(Line, ColumnIndex); + + v2 TargetCursorP = Box->Rect.Min+V2(ColumnOffset*GlyphAdvance, LineIndex*LineHeight); + v2 CursorP = V2(AC_AnimateValueF(TargetCursorP.x, TargetCursorP.x, 0.1, "Workspace Text Editor Cursor X %p", Editor), + AC_AnimateValueF(TargetCursorP.y, TargetCursorP.y, 0.1, "Workspace Text Editor Cursor Y %p", Editor)); + v2 CursorDim = V2(2, LineHeight); + range2_r32 CursorRect = Range2R32(CursorP, CursorP+CursorDim); + v4 CursorColor = ColorFromHex(0x10FF20FF); + PushQuad(Group, CursorRect, CursorColor, CursorColor, CursorColor, CursorColor, 2, 0.4, 0); + } +} + +static void W_BuildTextEditor(workspace_view *View) +{ + workspace_view_text_editor *Editor = (workspace_view_text_editor *)View->Data; + + //- sixten: calculate dimensions + r32 FontSize = Editor->FontSize; + r32 LineHeight = FontSize + 4.0f; + + glyph *Glyph = GetGlyph(UI_GlyphAtlas(), Font_Monospace, 'A', FontSize, 0); + r32 GlyphAdvance = Glyph->Advance; + + s64 LineCount = Editor->Lines.Count; + s64 MaxLineCount = Editor->MaxLineCount; + + s64 LineNumberCount = (s64)(Log(Editor->Lines.Count)/Log(10))+1; + v2_r32 LinesBarDim = V2R32((LineNumberCount + 2)*GlyphAdvance, LineCount*LineHeight); + + v2_r32 TextEditorDim = V2R32((MaxLineCount+LineNumberCount+2)*GlyphAdvance, (LineCount+1)*LineHeight); + v2_r32 VisibleRegionDim; // sixten(NOTE): This is set further down + + b32 CursorHasBeenModified = false; + + //- sixten: layout editor + UI_WidthFill UI_HeightFill UI_Column() + { + //- sixten: line numbers, editor & scrollbar + UI_HeightFill UI_Row(UI_BoxFlag_DrawBorder) + { + UI_WidthFill UI_Column(0, StrLit("Scrollable & Scroll X")) + { + UI_Row(0, StrLit("Scroll Region")) // contains lines bar & text editor + { + v2_r32 ScrollRegionDim = DimOfRange(UI_TopParent()->Rect); + + v2_r32 AnimatedOffset = V2R32(AC_AnimateValueF(Editor->Offset.x, Editor->Offset.x, 0.3f, "%p Offset X", View), + AC_AnimateValueF(Editor->Offset.y, Editor->Offset.y, 0.3f, "%p Offset Y", View)); + + // sixten(NOTE): We put the lines bar & text editor in containers to be able to easily offset them. + UI_SetNextBackgroundColor(ColorFromHex(0x10203080)); + UI_SetNextOffsetY(-AnimatedOffset.y); + UI_Width(UI_ChildrenSum(1, 1)) UI_Parent(UI_MakeBox(UI_BoxFlag_Clip|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawDropShadow, StrLit("Lines Bar Container"))) + { + UI_SetNextSize(UI_Pixels(LinesBarDim.x, 1), UI_Pixels(LinesBarDim.y, 1)); + ui_box *LinesBarBox = UI_MakeBoxF(0, "Workspace View Text Editor Lines Bar"); + UI_EquipBoxCustomDrawCallback(LinesBarBox, W_TextEditorLinesBarDrawCallback, Editor); + } + + UI_SetNextOffset(-AnimatedOffset.x, -AnimatedOffset.y); + UI_WidthFill UI_Parent(UI_MakeBox(UI_BoxFlag_Clip|UI_BoxFlag_Clickable, StrLit("Text Editor Container"))) + { + ui_box *EditorContainerBox = UI_TopParent(); + VisibleRegionDim = DimOfRange(EditorContainerBox->Rect); + ui_signal EditorContainerSignal = UI_SignalFromBox(EditorContainerBox); + //- sixten: text editor scrolling + if(AreEqual(UI_HotKey(), EditorContainerBox->Key)) + { + for(platform_event *Event = UI_EventList()->First; + Event != 0; + Event = Event->Next) + { + if(Event->Type == PlatformEvent_MouseScroll && (Event->Modifiers != PlatformModifier_Ctrl) && Event->Scroll.y != 0) + { + Editor->Offset.y -= Event->Scroll.y*LineHeight*4; + Platform_ConsumeEvent(UI_EventList(), Event); + } + } + } + UI_SetNextSize(UI_Pixels(TextEditorDim.x, 1), UI_Pixels(TextEditorDim.y, 1)); + ui_box *TextEditorBox = UI_MakeBoxF(0, "Workspace View Text Editor"); + UI_EquipBoxCustomDrawCallback(TextEditorBox, W_TextEditorDrawCallback, Editor); + + if(EditorContainerSignal.Dragging) + { + //- sixten: translate mouse position to text point + v2 MouseOffset = EditorContainerSignal.MouseP - TextEditorBox->Rect.Min; + s64 LineIndex = Clamp((s64)(MouseOffset.y / LineHeight), 0, Editor->Lines.Count); + string Line = Substring(Editor->Text.String, Editor->Lines.Ranges[LineIndex]); + s64 ColumnOffset = (s64)(MouseOffset.x / GlyphAdvance); + s64 ColumnIndex = UTF8IndexFromOffset(Line, ColumnOffset); + + CursorHasBeenModified = true; + Editor->DropdownActive = false; + + text_point Point = {LineIndex + 1, ColumnIndex + 1}; + Editor->EditState.Cursor = OffsetFromTextPoint(Editor->Text.String, Editor->Lines, Point); + + if(EditorContainerSignal.Pressed) + { + Editor->EditState.Mark = Editor->EditState.Cursor; + } + } + } + } + + //- sixten: build scrollbar x + { + ui_box *ParentBox = UI_TopParent(); + v2_r32 ParentDim = DimOfRange(ParentBox->Rect); + r32 MaxScrollWidth = ParentDim.x-UI_TopFontSize()*2; + r32 ScrollScaleX = ParentDim.x/TextEditorDim.x; + if(ScrollScaleX > 1) + { + ScrollScaleX = 0; + } + ui_signal ScrollX = UI_Scrollbar(Axis2_X, StrLit("Workspace View Text Editor Scrollbar X"), MaxScrollWidth*ScrollScaleX, Editor->Offset.x/TextEditorDim.x*MaxScrollWidth); + if(ScrollX.Dragging) + { + if(ScrollX.Pressed) + { + UI_StoreDragR32(Editor->Offset.x); + } + Editor->Offset.x = UI_GetDragR32() + ScrollX.DragDelta.x/ScrollScaleX; + + } + Editor->Offset.x = Clamp(Editor->Offset.x, 0, Max(0.0f, TextEditorDim.x-ParentDim.x)); + } + } + + UI_Width(UI_ChildrenSum(1, 1)) UI_Column(0, StrLit("Scrollable & Scroll Y")) + { + //- sixten: build scrollbar y + { + ui_box *ParentBox = UI_TopParent(); + v2_r32 ParentDim = DimOfRange(ParentBox->Rect); + r32 MaxScrollHeight = ParentDim.y-UI_TopFontSize()*3; + r32 ScrollScaleY = ParentDim.y/TextEditorDim.y; + if(ScrollScaleY > 1) + { + MaxScrollHeight = 0; + } + ui_signal ScrollY = UI_Scrollbar(Axis2_Y, StrLit("Workspace View Text Editor Scrollbar Y"), MaxScrollHeight*ScrollScaleY, Editor->Offset.y/TextEditorDim.y*MaxScrollHeight); + if(ScrollY.Dragging) + { + if(ScrollY.Pressed) + { + UI_StoreDragR32(Editor->Offset.y); + } + Editor->Offset.y = UI_GetDragR32() + ScrollY.DragDelta.y/ScrollScaleY; + } + Editor->Offset.y = Clamp(Editor->Offset.y, 0, Max(0.0f, TextEditorDim.y-ParentDim.y)); + } + UI_Width(UI_Em(1, 1)) UI_Height(UI_Em(1, 1)) UI_MakeBox(UI_BoxFlag_DrawBorder, StrLit("")); + } + } + + //- sixten: info bar + W_BuildTextEditorInfoBar(Editor); + W_BuildTextEditorErrorList(Editor); + } + + //- sixten: process inputs + if(W_ViewIsCurrent(View)) + { + //- sixten: handle history + { + history_list *List = &Editor->History; + + //- sixten: undo + if(Platform_KeyPress(UI_EventList(), Key_Z, PlatformModifier_Ctrl)) + { + history_node *Node = List->At; + if(Node != &List->Sentinel) + { + //- sixten: get entry & apply + history_entry Entry = Node->Backward; + MutableStringReplaceRange(&Editor->Text, Entry.ReplaceString, Entry.Range); + W_TextEditorApplyChanges(Editor); + Editor->EditState.Cursor = Editor->EditState.Mark = Entry.Range.Min+Entry.ReplaceString.Count; + CursorHasBeenModified = true; + + List->At = Node->Prev; + } + } + + //- sixten: redo + if(Platform_KeyPress(UI_EventList(), Key_Y, PlatformModifier_Ctrl)) + { + history_node *Node = List->At->Next; + if(Node != &List->Sentinel) + { + //- sixten: get entry & apply + history_entry Entry = Node->Forward; + MutableStringReplaceRange(&Editor->Text, Entry.ReplaceString, Entry.Range); + W_TextEditorApplyChanges(Editor); + Editor->EditState.Cursor = Editor->EditState.Mark = Entry.Range.Min+Entry.ReplaceString.Count; + CursorHasBeenModified = true; + + List->At = Node; + } + } + } + + //- sixten: save + if(Platform_KeyPress(UI_EventList(), Key_S, PlatformModifier_Ctrl)) + { + W_SaveTextEditorToFile(Editor); + } + + //- sixten: select all + if(Platform_KeyPress(UI_EventList(), Key_A, PlatformModifier_Ctrl)) + { + Editor->EditState.Mark = 0; + Editor->EditState.Cursor = Editor->Text.String.Count; + } + + //- sixten: keyboard input -> text op + for(platform_event *Event = UI_EventList()->First; + Event != 0; + Event = Event->Next) + { + //- sixten: check for scaling + if(Event->Type == PlatformEvent_Press && Event->Modifiers == PlatformModifier_Ctrl && (Event->Key == Key_Plus || Event->Key == Key_Minus)) + { + Editor->FontSize += (Event->Key == Key_Plus ? 1 : -1); + continue; + } + if(Event->Type == PlatformEvent_MouseScroll && Event->Modifiers == PlatformModifier_Ctrl && (Event->Scroll.y != 0)) + { + Editor->FontSize += (Event->Scroll.y); + continue; + } + + if(Event->Type == PlatformEvent_Press || Event->Type == PlatformEvent_Text) + { + //- sixten: auto-indent + s64 Indent = 0; + if(Event->Codepoint == '\n') + { + string Line = Substring(Editor->Text.String, Editor->Lines.Ranges[Editor->LastTextPoint.Line-1]); + if(Line.Data[Line.Count-1] == '\n') + { + Line.Count -= 1; + } + + for(u8 *Data = Line.Data; *Data == '\t' && Data < Line.Data+Line.Count; Data += 1) + { + Indent += 1; + } + } + + //- sixten: auto close bracket + if(Event->Codepoint == '{') + { + platform_event FakeEvent = {}; + FakeEvent.Codepoint = '}'; + FakeEvent.Type = PlatformEvent_Text; + CursorHasBeenModified |= W_ProcessTextEditorEvent(Editor, &FakeEvent); + FakeEvent.Key = Key_Left;; + FakeEvent.Type = PlatformEvent_Press; + CursorHasBeenModified |= W_ProcessTextEditorEvent(Editor, &FakeEvent); + } + + //- sixten: auto close string literal + if(Event->Codepoint == '"') + { + platform_event FakeEvent = {}; + FakeEvent.Codepoint = '"'; + FakeEvent.Type = PlatformEvent_Text; + CursorHasBeenModified |= W_ProcessTextEditorEvent(Editor, &FakeEvent); + FakeEvent.Key = Key_Left;; + FakeEvent.Type = PlatformEvent_Press; + CursorHasBeenModified |= W_ProcessTextEditorEvent(Editor, &FakeEvent); + } + + //- sixten: default event + if(W_ProcessTextEditorEvent(Editor, Event)) + { + CursorHasBeenModified = true; + Platform_ConsumeEvent(UI_EventList(), Event); + } + + //- sixten: apply indent + { + platform_event FakeTab = {}; + FakeTab.Codepoint = '\t'; + FakeTab.Type = PlatformEvent_Text; + + for(s64 IndentIndex = 0; IndentIndex < Indent; IndentIndex += 1) + { + CursorHasBeenModified |= W_ProcessTextEditorEvent(Editor, &FakeTab); + } + } + } + } + + //- sixten: change last text point & adapt view to cursor + if(CursorHasBeenModified) + { + text_point Point = TextPointFromOffset(Editor->Text.String, Editor->EditState.Cursor); + s64 LineIndex = Point.Line-1; + string Line = Substring(Editor->Text.String, Editor->Lines.Ranges[LineIndex]); + s64 ColumnIndex = Point.Column-1; + s64 ColumnOffset = UTF8OffsetFromIndex(Line, ColumnIndex); + + v2 CursorP = V2(ColumnOffset*GlyphAdvance, LineIndex*LineHeight); + + if(CursorP.y < Editor->Offset.y) + { + Editor->Offset.y = CursorP.y; + } + if(CursorP.y > Editor->Offset.y + VisibleRegionDim.y - LineHeight) + { + Editor->Offset.y = CursorP.y - VisibleRegionDim.y + LineHeight; + } + + if(Editor->LastTextPoint.Line == Point.Line) + { + Editor->LastTextPoint = Point; + } + else + { + Editor->LastTextPoint.Line = Point.Line; + Editor->LastTextPoint.Column = Max(Editor->LastTextPoint.Column, Point.Column); + } + } + } } \ No newline at end of file diff --git a/code/vn_workspace_text_editor.h b/code/vn_workspace_text_editor.h index f22a3d2..e9cfe3f 100644 --- a/code/vn_workspace_text_editor.h +++ b/code/vn_workspace_text_editor.h @@ -8,8 +8,8 @@ struct mutable_string { - arena *Arena; - string String; + arena *Arena; + string String; }; //////////////////////////////// @@ -17,22 +17,22 @@ struct mutable_string struct history_entry { - range1_s64 Range; - string ReplaceString; + range1_s64 Range; + string ReplaceString; }; struct history_node { - history_node *Next; - history_node *Prev; - history_entry Forward; - history_entry Backward; + history_node *Next; + history_node *Prev; + history_entry Forward; + history_entry Backward; }; struct history_list { - history_node *At; - history_node Sentinel; + history_node *At; + history_node Sentinel; }; //////////////////////////////// @@ -40,42 +40,44 @@ struct history_list struct workspace_text_data { - token_array Tokens; - range1_s64_array Lines; + token_array Tokens; + range1_s64_array Lines; + s64 MaxLineCount; }; struct workspace_view_text_editor { - // sixten: processed text - arena *ProcessingArena; - token_array Tokens; - range1_s64_array Lines; - compiled_scene Compiled; - - // sixten: text being edited - string FileName; - string FilePath; - mutable_string Text; - - // sixten: text editing - text_edit_state EditState; - text_point LastTextPoint; - - // sixten: text rendering - r32 FontSize; - - // sixten: history - arena *HistoryArena; - history_list History; - history_node *SavePoint; - - // sixten: ui building & rendering - ui_box *ContainerBox; - v2 TextDim; - v2 Offset; - b32 DropdownActive; - v2 DropdownP; - r32 DropdownTransition; + // sixten: processed text + arena *ProcessingArena; + token_array Tokens; + range1_s64_array Lines; + s64 MaxLineCount; + compiled_scene Compiled; + + // sixten: text being edited + string FileName; + string FilePath; + mutable_string Text; + + // sixten: text editing + text_edit_state EditState; + text_point LastTextPoint; + + // sixten: text rendering + r32 FontSize; + + // sixten: history + arena *HistoryArena; + history_list History; + history_node *SavePoint; + + // sixten: ui building & rendering + ui_box *ContainerBox; + v2 TextDim; + v2 Offset; + b32 DropdownActive; + v2 DropdownP; + r32 DropdownTransition; }; //////////////////////////////// diff --git a/code/vn_workspace_view.cpp b/code/vn_workspace_view.cpp index e2dbc01..351daab 100644 --- a/code/vn_workspace_view.cpp +++ b/code/vn_workspace_view.cpp @@ -39,6 +39,8 @@ inline workspace_view *W_CreateNewView(workspace_view_kind Kind, workspace_panel workspace_text_data TextData = W_TextDataFromString(Editor->ProcessingArena, Editor->Text.String); Editor->Tokens = TextData.Tokens; Editor->Lines = TextData.Lines; + + Editor->FontSize = 13.0f; } break; case W_ViewKind_NavEditor: @@ -194,8 +196,8 @@ static void W_BuildSettingsTabButton(workspace_view_settings *Settings, char *Na UI_SetNextTextColor(Color); ui_box *Box = UI_MakeBoxF(UI_BoxFlag_DrawText | - UI_BoxFlag_Clickable, - Name); + UI_BoxFlag_Clickable, + Name); ui_signal Signal = UI_SignalFromBox(Box); if(Signal.Hovering) @@ -215,11 +217,11 @@ static b32 UI_DropdownSelection(char **Alternatives, s32 AlternativeCount, b32 * UI_SetNextLayoutAxis(Axis2_X); ui_box *DropdownBox = UI_MakeBoxF(UI_BoxFlag_DrawBackground | - UI_BoxFlag_DrawBorder | - UI_BoxFlag_HotAnimation | - UI_BoxFlag_ActiveAnimation | - UI_BoxFlag_Clickable, - "Dropdown"); + UI_BoxFlag_DrawBorder | + UI_BoxFlag_HotAnimation | + UI_BoxFlag_ActiveAnimation | + UI_BoxFlag_Clickable, + "Dropdown"); UI_Parent(DropdownBox) { UI_Width(UI_Percent(1, 0)) UI_LabelF(Alternatives[*Selected]); @@ -249,15 +251,15 @@ static b32 UI_DropdownSelection(char **Alternatives, s32 AlternativeCount, b32 * UI_SetNextWidth(UI_Pixels(200, 1)); UI_SetNextHeight(UI_ChildrenSum(OpenTransition, 1)); UI_Parent(UI_MakeBoxF(UI_BoxFlag_Clip | - UI_BoxFlag_DrawDropShadow | - UI_BoxFlag_FloatingX | - UI_BoxFlag_FloatingY, "Dropdown Contents %p%p", Alternatives, Open)) + UI_BoxFlag_DrawDropShadow | + UI_BoxFlag_FloatingX | + UI_BoxFlag_FloatingY, "Dropdown Contents %p%p", Alternatives, Open)) { UI_PushWidth(UI_Percent(1, 1)); for(s64 Index = 0; - Index < Round(AlternativeCount*OpenTransition); - ++Index) + Index < Round(AlternativeCount*OpenTransition); + ++Index) { ui_signal ButtonSignal = UI_ButtonF(Alternatives[Index]); if(AreEqual(UI_ActiveKey(), ButtonSignal.Box->Key)) @@ -316,8 +318,8 @@ static void W_BuildImageViewer(workspace_view *View) if(AreEqual(UI_HotKey(), ImageBox->Key)) { for(platform_event *Event = UI_EventList()->First; - Event != 0; - Event = Event->Next) + Event != 0; + Event = Event->Next) { if(Event->Type == PlatformEvent_MouseScroll && Event->Scroll.y != 0) { @@ -426,7 +428,7 @@ static void W_BuildSettings(workspace_view *View) UI_SetNextWidth(UI_Pixels(200, 1)); UI_SetNextCornerRadius(4); if(UI_DropdownSelection(Alternatives, ArrayCount(Alternatives), - &Settings->GeneralDropdownOpen, &DropdownSelected)) + &Settings->GeneralDropdownOpen, &DropdownSelected)) { Workspace->Input->RefreshRate = AlternativeMapping[DropdownSelected]; Settings->GeneralDropdownOpen = false; @@ -463,10 +465,10 @@ static void W_BuildView(workspace_view *View) UI_SetNextCornerRadius(3); ui_box *ViewBox = UI_MakeBoxF(UI_BoxFlag_Clickable | - UI_BoxFlag_DrawBackground | - UI_BoxFlag_DrawBorder | - UI_BoxFlag_Clip, - "Workspace View %p", View); + UI_BoxFlag_DrawBackground | + UI_BoxFlag_DrawBorder | + UI_BoxFlag_Clip, + "Workspace View %p", View); UI_Parent(ViewBox) UI_Size(UI_Percent(1, 0), UI_Percent(1, 0)) diff --git a/code/win32__main.rdbg b/code/win32__main.rdbg index 7f7234da6309ed259cdbda73e2947949f2714eef..fc9887638e0192bb77b2cb6d3193d96ab3c3346b 100644 GIT binary patch delta 178 zcmdnU@sxRjB?}t^1HEwn7A2OXro@!x#g}I4<))S->LqJWHe?c; zoX^O`m6uo+pPG_cl3z60mq~&bsHiv@s3pEEGqrr;8aYNepdn`EnR&)W@wthad3wnO z1wiu|n1PrRh=W0j!+>f*wuU4YrKgs#0$Gklsd{__9Yg*o&g*YawLmZ4GOal4kAZU+-P#>;_qd z1zM83PwsoUTt2%my-UyYI_;p)W)$Qq=#OO_28C2lk1XL*`7i+_yzM1yA6LyKOCWRz z7=TfrEad`xk*0SJ#zxYFEak>dgUt3>mKv$-z>h8*@IoRO?$ANxiiB<)9-$3jS_W8V zQDR8kse{9$2U=NjpS#@#R0xKEYX?y2B-}^Yfgg2qFV=k?e+kUi?{dpq*fYCmf1@`r zH|(L|-9}(Oj23@Z3PHsE!w$|~C04uK@Jw%}Tz2$WSzJ`3@jKnDOtmx8SZ9zx) && - (MonitorInfo.rcMonitor.top == NewPos->y) && - (MonWidth == NewPos->cx) && - (MonHeight == NewPos->cy)); + (MonitorInfo.rcMonitor.top == NewPos->y) && + (MonWidth == NewPos->cx) && + (MonHeight == NewPos->cy)); } DWORD OldStyle = GetWindowLong(Window, GWL_STYLE); @@ -573,6 +573,8 @@ static LRESULT Win32_WindowCallback(HWND Window, UINT Message, WPARAM WParam, LP else if(VKCode == VK_NEXT) { Key = Key_PageDown; } else if(VKCode == VK_HOME) { Key = Key_Home; } else if(VKCode == VK_END) { Key = Key_End; } + else if(VKCode == VK_OEM_PLUS) { Key = Key_Plus; } + else if(VKCode == VK_OEM_MINUS) { Key = Key_Minus; } else if(VKCode == VK_BACK) { Key = Key_Backspace; } else if(VKCode == VK_DELETE) { Key = Key_Delete; } else if(VKCode == VK_ESCAPE) { Key = Key_Escape; } @@ -776,12 +778,12 @@ int WinMain(HINSTANCE Instance, HINSTANCE PreviousInstance, LPSTR CommandLine, i if(RegisterClassA(&WindowClass)) { HWND Window = CreateWindowEx(0, - WindowClass.lpszClassName, - "vn - December 2023 Build", - WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - 0, 0, Instance, 0); + WindowClass.lpszClassName, + "vn - December 2023 Build", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + 0, 0, Instance, 0); if(Window) { Global_Win32State.Window = Window; diff --git a/config.vn b/config.vn index 28f3e01..05d0675 100644 --- a/config.vn +++ b/config.vn @@ -1,6 +1,6 @@ Platform { - RefreshRate = 0; + RefreshRate = 60; } Dev