From c0e0c30eb86ec7daff171936a08b070fb0424bd4 Mon Sep 17 00:00:00 2001 From: Booklordofthedings Date: Tue, 1 Oct 2024 14:20:16 +0200 Subject: [PATCH 1/6] added pkkg --- .gitignore | 1 + BeefProj.toml | 2 +- BeefSpace.toml | 5 +++++ pkkg | 20 ++++++++++++++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 BeefSpace.toml create mode 100644 pkkg diff --git a/.gitignore b/.gitignore index 33a38ac..01e2ab1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # ---> Beef **/build **/recovery +**/deps BeefSpace_User.toml diff --git a/BeefProj.toml b/BeefProj.toml index 58f3911..36c7ff3 100644 --- a/BeefProj.toml +++ b/BeefProj.toml @@ -1,5 +1,5 @@ FileVersion = 1 -Dependencies = {corlib = "*", corlib = "*", raylib-beef = "*"} +Dependencies = {corlib = "*", corlib = "*"} [Project] Name = "TheaterGui" diff --git a/BeefSpace.toml b/BeefSpace.toml new file mode 100644 index 0000000..95e8183 --- /dev/null +++ b/BeefSpace.toml @@ -0,0 +1,5 @@ +FileVersion = 1 +Projects = {TheaterGui = {Path = "."}, examples = {Path = "examples"}} + +[Workspace] +StartupProject = "examples" diff --git a/pkkg b/pkkg new file mode 100644 index 0000000..4a942dc --- /dev/null +++ b/pkkg @@ -0,0 +1,20 @@ +#This is the pkkg template file +l Name TheaterGui + +t Desc A simple retained mode gui library + +l Url https://code.booklordofthe.dev/Theater/TheaterGui + +a Authors + o Book + l Name Booklordofthedings + l Url https://Boooklordofthe.dev + +a Dependencies + o Bofa + l Name Bofa + l Url https://code.booklordofthe.dev/Booklordofthedings/Bofa.git + l Tag 1.1.0 + o Raylib + l Name Raylib + l Url https://code.booklordofthe.dev/Extern/raylib-beef.git \ No newline at end of file From c0dd04127c958718d6c6fd7fc6de92289136ec29 Mon Sep 17 00:00:00 2001 From: Booklordofthedings Date: Sun, 6 Oct 2024 22:23:40 +0200 Subject: [PATCH 2/6] further changes, lazy loading, new modular backend system --- BeefProj.toml | 2 +- BeefSpace.toml | 2 +- examples/BeefProj.toml | 2 +- examples/src/Box.bf | 15 - examples/src/Buttons.bf | 45 --- examples/src/Checkb.bf | 18 -- examples/src/ExampleToolbar.bf | 37 --- examples/src/HorSlider.bf | 25 -- examples/src/MainScreen.bf | 48 ---- examples/src/OpenButton.bf | 21 -- examples/src/Program.bf | 27 +- examples/src/Radios.bf | 19 -- examples/src/VertSlider.bf | 20 -- raylib-backend/BeefProj.toml | 7 + raylib-backend/src/Platform_Raylib.bf | 45 +++ .../src/Platform_Raylib/Conversion.bf | 31 ++ raylib-backend/src/Platform_Raylib/Drawing.bf | 95 ++++++ raylib-backend/src/Platform_Raylib/Input.bf | 31 ++ raylib-backend/src/Platform_Raylib/Text.bf | 42 +++ .../src/TextureManager.bf | 36 +-- src/App.bf | 270 ++---------------- src/Components/Button.bf | 72 +++-- src/Components/Checkbox.bf | 49 ---- src/Components/Component.bf | 108 +------ src/Components/Container.bf | 229 ++++----------- src/Components/Dropdown.bf | 57 ---- src/Components/DropdownPopup.bf | 109 ------- src/Components/HSlider.bf | 11 - src/Components/IconButton.bf | 30 -- src/Components/InputField.bf | 72 ----- src/Components/Label.bf | 25 -- src/Components/LargeButton.bf | 24 -- src/Components/NButton.bf | 56 ---- src/Components/NHSlider.bf | 78 ----- src/Components/NVSlider.bf | 78 ----- src/Components/Placeholder.bf | 13 - src/Components/Popup.bf | 12 - src/Components/RadioButton.bf | 62 ---- src/Components/RightClickPopup.bf | 115 -------- src/Components/Screen.bf | 18 -- src/Components/ScrollableContainer.bf | 193 ------------- src/Components/Toolbar.bf | 144 ---------- src/Components/ToolbarPopup.bf | 116 -------- src/Components/VSlider.bf | 11 - src/Core/Layout.bf | 64 +++++ src/Core/Structs/color.bf | 38 +++ src/Core/Structs/colorScheme.bf | 16 ++ src/Core/Structs/rect.bf | 23 ++ src/Core/Structs/theme.bf | 25 ++ src/Core/TGRuntime.api.bf | 40 +++ src/Core/TGRuntime.core.bf | 67 +++++ src/Extensions.bf | 53 ---- src/Generators/ButtonGenerator.bf | 48 ---- src/Generators/CheckboxGenerator.bf | 48 ---- src/Generators/ContainerGenerator.bf | 37 --- src/Generators/DropdownGenerator.bf | 54 ---- src/Generators/IconButtonGenerator.bf | 49 ---- src/Generators/LargeButtonGenerator.bf | 48 ---- src/Generators/NButtonGenerator.bf | 48 ---- src/Generators/RadioButtonGenerator.bf | 48 ---- src/Generators/ScreenGenerator.bf | 36 --- src/Generators/SliderGenerator.bf | 57 ---- src/Generators/ToolbarGenerator.bf | 44 --- src/IPlatformLayer.bf | 43 +++ src/Input.bf | 122 -------- src/PlatformLayer.bf | 21 -- src/Theme.bf | 41 --- src/WASM.bf | 10 + 68 files changed, 735 insertions(+), 2865 deletions(-) delete mode 100644 examples/src/Box.bf delete mode 100644 examples/src/Buttons.bf delete mode 100644 examples/src/Checkb.bf delete mode 100644 examples/src/ExampleToolbar.bf delete mode 100644 examples/src/HorSlider.bf delete mode 100644 examples/src/MainScreen.bf delete mode 100644 examples/src/OpenButton.bf delete mode 100644 examples/src/Radios.bf delete mode 100644 examples/src/VertSlider.bf create mode 100644 raylib-backend/BeefProj.toml create mode 100644 raylib-backend/src/Platform_Raylib.bf create mode 100644 raylib-backend/src/Platform_Raylib/Conversion.bf create mode 100644 raylib-backend/src/Platform_Raylib/Drawing.bf create mode 100644 raylib-backend/src/Platform_Raylib/Input.bf create mode 100644 raylib-backend/src/Platform_Raylib/Text.bf rename src/Textures.bf => raylib-backend/src/TextureManager.bf (76%) delete mode 100644 src/Components/Checkbox.bf delete mode 100644 src/Components/Dropdown.bf delete mode 100644 src/Components/DropdownPopup.bf delete mode 100644 src/Components/HSlider.bf delete mode 100644 src/Components/IconButton.bf delete mode 100644 src/Components/InputField.bf delete mode 100644 src/Components/Label.bf delete mode 100644 src/Components/LargeButton.bf delete mode 100644 src/Components/NButton.bf delete mode 100644 src/Components/NHSlider.bf delete mode 100644 src/Components/NVSlider.bf delete mode 100644 src/Components/Placeholder.bf delete mode 100644 src/Components/Popup.bf delete mode 100644 src/Components/RadioButton.bf delete mode 100644 src/Components/RightClickPopup.bf delete mode 100644 src/Components/Screen.bf delete mode 100644 src/Components/ScrollableContainer.bf delete mode 100644 src/Components/Toolbar.bf delete mode 100644 src/Components/ToolbarPopup.bf delete mode 100644 src/Components/VSlider.bf create mode 100644 src/Core/Layout.bf create mode 100644 src/Core/Structs/color.bf create mode 100644 src/Core/Structs/colorScheme.bf create mode 100644 src/Core/Structs/rect.bf create mode 100644 src/Core/Structs/theme.bf create mode 100644 src/Core/TGRuntime.api.bf create mode 100644 src/Core/TGRuntime.core.bf delete mode 100644 src/Extensions.bf delete mode 100644 src/Generators/ButtonGenerator.bf delete mode 100644 src/Generators/CheckboxGenerator.bf delete mode 100644 src/Generators/ContainerGenerator.bf delete mode 100644 src/Generators/DropdownGenerator.bf delete mode 100644 src/Generators/IconButtonGenerator.bf delete mode 100644 src/Generators/LargeButtonGenerator.bf delete mode 100644 src/Generators/NButtonGenerator.bf delete mode 100644 src/Generators/RadioButtonGenerator.bf delete mode 100644 src/Generators/ScreenGenerator.bf delete mode 100644 src/Generators/SliderGenerator.bf delete mode 100644 src/Generators/ToolbarGenerator.bf create mode 100644 src/IPlatformLayer.bf delete mode 100644 src/Input.bf delete mode 100644 src/PlatformLayer.bf delete mode 100644 src/Theme.bf create mode 100644 src/WASM.bf diff --git a/BeefProj.toml b/BeefProj.toml index 36c7ff3..15726c0 100644 --- a/BeefProj.toml +++ b/BeefProj.toml @@ -1,5 +1,5 @@ FileVersion = 1 -Dependencies = {corlib = "*", corlib = "*"} +Dependencies = {corlib = "*", corlib = "*", Bofa = "*", raylib-beef = "*"} [Project] Name = "TheaterGui" diff --git a/BeefSpace.toml b/BeefSpace.toml index 95e8183..8c33a2f 100644 --- a/BeefSpace.toml +++ b/BeefSpace.toml @@ -1,5 +1,5 @@ FileVersion = 1 -Projects = {TheaterGui = {Path = "."}, examples = {Path = "examples"}} +Projects = {TheaterGui = {Path = "."}, examples = {Path = "examples"}, Bofa = {Path = "deps/Bofa"}, raylib-beef = {Path = "deps/Raylib/raylib-beef"}, raylib-backend = {Path = "raylib-backend"}} [Workspace] StartupProject = "examples" diff --git a/examples/BeefProj.toml b/examples/BeefProj.toml index 4185c75..276bc1d 100644 --- a/examples/BeefProj.toml +++ b/examples/BeefProj.toml @@ -1,5 +1,5 @@ FileVersion = 1 -Dependencies = {corlib = "*", TheaterGui = "*"} +Dependencies = {corlib = "*", TheaterGui = "*", raylib-backend = "*"} [Project] Name = "examples" diff --git a/examples/src/Box.bf b/examples/src/Box.bf deleted file mode 100644 index e9e4331..0000000 --- a/examples/src/Box.bf +++ /dev/null @@ -1,15 +0,0 @@ -namespace examples; - -using TheaterGui.Components; - -class Box : Container -{ - public this() : base("Box") - { - //Add ui items here via AddChild() and terminate the row via EndRow() - Margin = 5; - - AddChild(new Checkb()); - AddChild(new Radios()); - } -} \ No newline at end of file diff --git a/examples/src/Buttons.bf b/examples/src/Buttons.bf deleted file mode 100644 index 396a91f..0000000 --- a/examples/src/Buttons.bf +++ /dev/null @@ -1,45 +0,0 @@ -namespace examples; - -using TheaterGui.Components; - -class StandartButton : Button -{ - public this() : base("Basic Button") - { - Margin = 5; - } - - //What happens when the button is clicked - public override void ClickAction() - { - - } -} - -class LButton : LargeButton -{ - public this() : base("Large Button") - { - Margin = 5; - } - - //What happens when the button is clicked - public override void ClickAction() - { - - } -} - -class CButton : NButton -{ - public this() : base(400, 50, "Custom sized button") - { - Margin = 5; - } - - //What happens when the button is clicked - public override void ClickAction() - { - - } -} \ No newline at end of file diff --git a/examples/src/Checkb.bf b/examples/src/Checkb.bf deleted file mode 100644 index 075de89..0000000 --- a/examples/src/Checkb.bf +++ /dev/null @@ -1,18 +0,0 @@ -namespace examples; - -using TheaterGui.Components; - -class Checkb : Checkbox -{ - public this() : base("Check me!") - { - Checked = true; - Description = "Beef is awesome"; - } - - //What happens when the button is clicked - public override void OnCheck(bool checkValue) - { - - } -} \ No newline at end of file diff --git a/examples/src/ExampleToolbar.bf b/examples/src/ExampleToolbar.bf deleted file mode 100644 index bae38b9..0000000 --- a/examples/src/ExampleToolbar.bf +++ /dev/null @@ -1,37 +0,0 @@ -namespace examples; - -using TheaterGui.Components; - -class ExampleToolbar : Toolbar -{ - public this() : base("Toolbar") - { - AddToolbarCategories( - new .("Help", - new .("Version", new => PrintVersion) - ), - - new .("About", - new .("TheaterGui", new => PrintAbout), - new .("Booklordofthedings", new => PrintAbout) - ) - ); - } - - public void PrintVersion() - { -#if !BF_PLATFORM_WASM - System.Console.WriteLine("1.0"); -#endif - } - - public void PrintAbout() - { -#if !BF_PLATFORM_WASM - System.Console.WriteLine(""" - TheaterGui by Booklordofthedings - A simple easy to use gui library for tools - """); -#endif - } -} \ No newline at end of file diff --git a/examples/src/HorSlider.bf b/examples/src/HorSlider.bf deleted file mode 100644 index 7fca7b9..0000000 --- a/examples/src/HorSlider.bf +++ /dev/null @@ -1,25 +0,0 @@ -namespace examples; - -using TheaterGui.Components; - -class HorSlider : HSlider -{ - public this() : base("HorSlider") - { - //Use the thing above to set the length of the bar - Min = 0; - Max = 100; - Value = 50; - ReactToValueChange = true; //This indicates wether OnValueChange gets actually called - Description = "A default horizontal slider"; - - MarginTop = 50; - } - - public override void OnValueChange(float newVal) - { -#if !BF_PLATFORM_WASM - System.Console.WriteLine(Value); -#endif - } -} \ No newline at end of file diff --git a/examples/src/MainScreen.bf b/examples/src/MainScreen.bf deleted file mode 100644 index fd4d5e0..0000000 --- a/examples/src/MainScreen.bf +++ /dev/null @@ -1,48 +0,0 @@ -namespace examples; - -using TheaterGui.Components; - -class MainScreen : Screen -{ - public this() : base("MainScreen") - { - //Add ui items here via AddChild() and terminate the row via EndRow() - AddChild(new ExampleToolbar()); - - AddChild(new Label("Changing the width allows you to see these buttons reordered")); - EndRow(); - - AddChild(new OpenButton()); - AddChild(new OpenButton()); - AddChild(new OpenButton()); - AddChild(new OpenButton()); - AddChild(new OpenButton()); - AddChild(new OpenButton()); - AddChild(new OpenButton()); - AddChild(new OpenButton()); - AddChild(new OpenButton()); - AddChild(new OpenButton()); - AddChild(new OpenButton()); - AddChild(new OpenButton()); - AddChild(new OpenButton()); - AddChild(new OpenButton()); - AddChild(new OpenButton()); - AddChild(new OpenButton()); - AddChild(new OpenButton()); - AddChild(new OpenButton()); - EndRow(); - - AddChild(new StandartButton()); - AddChild(new LButton()); - AddChild(new CButton()); - EndRow(); - - AddChild(new HorSlider()); - AddChild(new VertSlider()); - EndRow(); - - - AddChild(new Box()); - AddChild(new Box()); - } -} \ No newline at end of file diff --git a/examples/src/OpenButton.bf b/examples/src/OpenButton.bf deleted file mode 100644 index a0dad75..0000000 --- a/examples/src/OpenButton.bf +++ /dev/null @@ -1,21 +0,0 @@ -namespace examples; - -using TheaterGui.Components; - -class OpenButton : IconButton -{ - public this() : base("OpenButton") - { - Icon = .Icon_Folder; //Use this to set the icon sprite - Margin = 5; - MarginTop = 40; - MarginBottom = 40; - Description = "Open a file dialogue"; - } - - //What happens when the button is clicked - public override void ClickAction() - { - - } -} \ No newline at end of file diff --git a/examples/src/Program.bf b/examples/src/Program.bf index 406a9a3..8cc6767 100644 --- a/examples/src/Program.bf +++ b/examples/src/Program.bf @@ -1,11 +1,34 @@ namespace examples; using TheaterGui; +using TheaterGui.Core; +using TheaterGui.Components; class Program { public static void Main() { - App.Run("Example Gui",1920,1080); + scope App() + ..SetName("TheaterGui Application") + ..SetStartingSize(1280, 720) + ..SetPlatformLayer(new raylib_backend.PlatformRaylib()) + .Run(new MainScreen()); } -} \ No newline at end of file +} + +class MainScreen : Container +{ + public this() + { + AddChild("Main Button", new Button()); + AddChild("Other Button", new Button()); + + + Layout = new (val, width) => + { + val.Component("Main Button", 5); + val.Component("Other Button", 10); + }; + } +} + diff --git a/examples/src/Radios.bf b/examples/src/Radios.bf deleted file mode 100644 index 501c580..0000000 --- a/examples/src/Radios.bf +++ /dev/null @@ -1,19 +0,0 @@ -namespace examples; - -using TheaterGui.Components; - -class Radios : RadioButton -{ - public this() : base("Radios") - { - - Description = ""; - //Use SetBoxes(int, params StringView) to set the elements of the radio buttons - SetBoxes(3, "Windows", "Linux", "Mac", "Web"); - } - - //React to the check event, or use the Checked field to get the value directly - public override void OnCheck(int32 value) - { - } -} \ No newline at end of file diff --git a/examples/src/VertSlider.bf b/examples/src/VertSlider.bf deleted file mode 100644 index fd2eb66..0000000 --- a/examples/src/VertSlider.bf +++ /dev/null @@ -1,20 +0,0 @@ -namespace examples; - -using TheaterGui.Components; - -class VertSlider : VSlider -{ - public this() : base("VertSlider") - { - //Use the thing above to set the length of the bar - Min = 0; - Max = 100; - Value = 50; - ReactToValueChange = true; //This indicates wether OnValueChange gets actually called - } - - public override void OnValueChange(float newVal) - { - - } -} \ No newline at end of file diff --git a/raylib-backend/BeefProj.toml b/raylib-backend/BeefProj.toml new file mode 100644 index 0000000..374a7ab --- /dev/null +++ b/raylib-backend/BeefProj.toml @@ -0,0 +1,7 @@ +FileVersion = 1 +Dependencies = {corlib = "*", raylib-beef = "*", TheaterGui = "*"} + +[Project] +Name = "raylib-backend" +TargetType = "BeefLib" +StartupObject = "raylib_backend.Program" diff --git a/raylib-backend/src/Platform_Raylib.bf b/raylib-backend/src/Platform_Raylib.bf new file mode 100644 index 0000000..5d76c00 --- /dev/null +++ b/raylib-backend/src/Platform_Raylib.bf @@ -0,0 +1,45 @@ +namespace raylib_backend; + +using TheaterGui; +using TheaterGui.Core; +using TheaterGui.Core.Structs; + +using System; +using System.Collections; + +using RaylibBeef; + +class PlatformRaylib : IPlatformLayer +{ + private RenderTexture2D _ScreenTexture; + private TextureManager _TextureManager; + private Color _BackgroundColor = Raylib.WHITE; + private Dictionary _LoadedFonts = new .() ~ DeleteDictionaryAndKeys!(_); + private static uint8[?] _Texture_WindowIcon = Compiler.ReadBinary("../assets/64.png"); + + + public void Initialize(StringView pWindowTitle, int32 pWidth, int32 pHeight) + { + Raylib.SetConfigFlags((.)(ConfigFlags.FLAG_WINDOW_RESIZABLE | ConfigFlags.FLAG_WINDOW_HIGHDPI)); + String title = scope .(pWindowTitle); + Raylib.InitWindow(pWidth, pHeight, title); + Raylib.SetExitKey(0); + Raylib.SetWindowMinSize(640, 360); + Raylib.SetTargetFPS(40); + + var icon = Raylib.LoadImageFromMemory(".png", (.)&_Texture_WindowIcon, _Texture_WindowIcon.Count); + Raylib.SetWindowIcon(icon); + Raylib.UnloadImage(icon); + + _ScreenTexture = Raylib.LoadRenderTexture(Raylib.GetRenderWidth(), Raylib.GetRenderHeight()); + _TextureManager = new .(); + } + + public void Deinitialize() + { + for(var i in _LoadedFonts) + Raylib.UnloadFont(i.value); + Raylib.UnloadRenderTexture(_ScreenTexture); + delete _TextureManager; + } +} diff --git a/raylib-backend/src/Platform_Raylib/Conversion.bf b/raylib-backend/src/Platform_Raylib/Conversion.bf new file mode 100644 index 0000000..9c186b5 --- /dev/null +++ b/raylib-backend/src/Platform_Raylib/Conversion.bf @@ -0,0 +1,31 @@ +namespace raylib_backend; + +using RaylibBeef; + +using TheaterGui.Core; +using TheaterGui.Core.Structs; + +extension PlatformRaylib +{ + ///Converts a TGColor into a raylib compatible color + private Color Convert(color pColor) + { + return .(pColor.Red, pColor.Green, pColor.Blue, pColor.Alpha); + } + + ///Convert a TGRect into a raylib compatible rectangle + private Rectangle Convert(rect pRect) + { + return .(pRect.x, pRect.y, pRect.width, pRect.height); + } + + private float[2] Convert(Vector2 pVector) + { + return .(pVector.x, pVector.y); + } + + private Vector2 Convert(int32[2] pValues) + { + return .(pValues[0], pValues[1]); + } +} \ No newline at end of file diff --git a/raylib-backend/src/Platform_Raylib/Drawing.bf b/raylib-backend/src/Platform_Raylib/Drawing.bf new file mode 100644 index 0000000..8dede2b --- /dev/null +++ b/raylib-backend/src/Platform_Raylib/Drawing.bf @@ -0,0 +1,95 @@ +namespace raylib_backend; + +using TheaterGui.Core.Structs; + +using System; +using System.Collections; + +using RaylibBeef; + +extension PlatformRaylib +{ + public void StartDrawing() + { + Raylib.BeginDrawing(); + Raylib.ClearBackground(_BackgroundColor); + Raylib.BeginTextureMode(_ScreenTexture); + Raylib.ClearBackground(_BackgroundColor); + } + + public void StopDrawing() + { + Raylib.EndTextureMode(); + Raylib.DrawTexturePro( + _ScreenTexture.texture, + .(0, 0, _ScreenTexture.texture.width, -_ScreenTexture.texture.height), + .(0, 0, Raylib.GetScreenWidth(), Raylib.GetScreenHeight()), + .(0, 0), + 0, + Raylib.WHITE + ); + Raylib.EndDrawing(); + } + + public void RedrawLastFrame() + { + Raylib.BeginDrawing(); + Raylib.ClearBackground(_BackgroundColor); + Raylib.DrawTexturePro( + _ScreenTexture.texture, + .(0, 0, _ScreenTexture.texture.width, -_ScreenTexture.texture.height), + .(0, 0, Raylib.GetScreenWidth(), Raylib.GetScreenHeight()), + .(0, 0), + 0, + Raylib.WHITE + ); + Raylib.EndDrawing(); + } + + public void ChangeBackgroundColor(color pTint) + { + _BackgroundColor = Convert(pTint); + } + + public void LoadTexture(Span pData, StringView pName) + { + _TextureManager.[Friend]LoadAsset(pData, pName); + } + + public void DrawTexture(StringView pName, rect pTarget, color pTints) + { + if(_TextureManager.GetAsset(pName) case .Ok(let val)) + { + Raylib.DrawTexturePro( + *val.Source, + val.SourceRect, + Convert(pTarget), + .(0,0), 0, + Convert(pTints) + ); + } + else + Raylib.DrawRectangle(pTarget.x, pTarget.y, pTarget.width, pTarget.height, Raylib.PINK); + } + + public int32[2] MeasureTextureSize(StringView pName) + { + if(_TextureManager.GetAsset(pName) case .Ok(let val)) + { + return .(val.Width, val.Height); + } + return .(0,0); + } + + public void DrawColorRect(rect pTarget, color pTint) + { + Raylib.DrawRectangleRec(Convert(pTarget), Convert(pTint)); + } + + public void DrawColorRectOutlined(rect pTarget, color pTint, color pOutlineTint) + { + Raylib.DrawRectangleRec(Convert(pTarget), Convert(pTint)); + Raylib.DrawRectangleLinesEx(Convert(pTarget), 1, Convert(pOutlineTint)); + } + +} \ No newline at end of file diff --git a/raylib-backend/src/Platform_Raylib/Input.bf b/raylib-backend/src/Platform_Raylib/Input.bf new file mode 100644 index 0000000..ab7d259 --- /dev/null +++ b/raylib-backend/src/Platform_Raylib/Input.bf @@ -0,0 +1,31 @@ +namespace raylib_backend; + +using RaylibBeef; + +extension PlatformRaylib +{ + public bool ShouldClose() => Raylib.WindowShouldClose(); + public float[2] MousePosition() => Convert(Raylib.GetMousePosition()); + public float[2] MouseDelta() => Convert(Raylib.GetMouseDelta()); + public bool MouseLeftClick() => Raylib.IsMouseButtonDown(0); + public bool MouseRightClick() => Raylib.IsMouseButtonDown(1); + public float MouseWheel() => Raylib.GetMouseWheelMoveV().y; + + public int32[2] ScreenSize() + { + int32[2] ScreenSize = .(); + ScreenSize[0] = Raylib.GetScreenWidth(); + ScreenSize[1] = Raylib.GetScreenHeight(); + + //The size of the render texture is also automatically changed to always fit + if(ScreenSize[0] != _ScreenTexture.texture.width || ScreenSize[1] != _ScreenTexture.texture.height) + { + Raylib.UnloadRenderTexture(_ScreenTexture); + _ScreenTexture = Raylib.LoadRenderTexture(ScreenSize[0], ScreenSize[1]); + } + + return ScreenSize; + } + + +} \ No newline at end of file diff --git a/raylib-backend/src/Platform_Raylib/Text.bf b/raylib-backend/src/Platform_Raylib/Text.bf new file mode 100644 index 0000000..6bbb312 --- /dev/null +++ b/raylib-backend/src/Platform_Raylib/Text.bf @@ -0,0 +1,42 @@ +namespace raylib_backend; + +using TheaterGui.Core.Structs; + +using System; + +using RaylibBeef; + +extension PlatformRaylib +{ + + public void LoadFont(Span pData, StringView pName, uint8 pFontSize) + { + var font = Raylib.LoadFontFromMemory(".ttf", (.)pData.Ptr, (.)pData.Length, pFontSize, null, 256); + if(_LoadedFonts.ContainsKeyAlt(pName)) + { + Raylib.UnloadFont(_LoadedFonts[scope .(pName)]); + _LoadedFonts[scope .(pName)] = font; + } + else + _LoadedFonts.Add(new .(pName), font); + } + + public void DrawText(StringView pText, StringView pFont, int32[2] pPosition, color pTint) + { + if(_LoadedFonts.GetValue(scope .(pFont)) case .Ok(let val)) + Raylib.DrawTextEx(val, scope String(pText), Convert(pPosition), val.baseSize, 1, Convert(pTint)); + else + Raylib.DrawText(scope String(pText), pPosition[0], pPosition[1], 10, Raylib.PINK); + } + + public int32[2] MeasureTextSize(StringView pText, StringView pFont) + { + if(_LoadedFonts.GetValue(scope .(pFont)) case .Ok(let val)) + { + var res = Raylib.MeasureTextEx(val, scope String(pText), val.baseSize, 1); + return .((.)res.x, (.)res.y); + } + else + return .(Raylib.MeasureText(scope String(pText), 10), 10); + } +} \ No newline at end of file diff --git a/src/Textures.bf b/raylib-backend/src/TextureManager.bf similarity index 76% rename from src/Textures.bf rename to raylib-backend/src/TextureManager.bf index b2f7ab8..514ef0b 100644 --- a/src/Textures.bf +++ b/raylib-backend/src/TextureManager.bf @@ -1,40 +1,14 @@ -namespace TheaterGui; +namespace raylib_backend; using System; using System.Collections; + using RaylibBeef; -class Textures +class TextureManager { private List _Containers = new .() ~ DeleteContainerAndItems!(_); private List _Textures = new .() ~ delete _; - - public this() - { - Theme.Font = Raylib.LoadFontFromMemory(".ttf", (.)&Theme.Din, Theme.Din.Count, Theme.FontSize, null, 256); - Theme.FontSmall = Raylib.LoadFontFromMemory(".ttf", (.)&Theme.Din, Theme.Din.Count, Theme.FontSizeSmall, null, 256); - Theme.FontLarge = Raylib.LoadFontFromMemory(".ttf", (.)&Theme.Din, Theme.Din.Count, Theme.FontSizeLarge, null, 256); - - LoadAsset(Theme.Texture_Button, "button"); - LoadAsset(Theme.Texture_NButton, "n_button"); - LoadAsset(Theme.Texture_SquareButton, "square_button"); - LoadAsset(Theme.Texture_LargeButton, "large_button"); - LoadAsset(Theme.Texture_Checkbox, "checkbox"); - LoadAsset(Theme.Texture_Checkbox_Checked, "checkbox_checked"); - LoadAsset(Theme.Horizontal_Patch, "horizontal_patch"); - LoadAsset(Theme.Dropdown, "dropdown"); - - - - LoadAsset(Theme.Texture_TheaterIcon, "theater_icon"); - LoadAsset(Theme.Texture_FolderIcon, "folder_icon"); - sprite.Icon_Folder = GetAsset("folder_icon"); - sprite.Icon_Theater = GetAsset("theater_icon"); - - - - } - private Dictionary _TileMap = new .() ~ DeleteDictionaryAndKeys!(_); ///Attempt to get a existing asset by StringView @@ -164,10 +138,6 @@ struct sprite public int32 Height = 0; public float Rotation = 0; - public static sprite Icon_Folder; - public static sprite Icon_Theater; - - public void Render(float x, float y, Color color = Raylib.WHITE) { Raylib.DrawTexturePro(*Source, SourceRect, Rectangle(x + Width / 2, y + Height / 2, Width, Height), Vector2(Width / 2, Height / 2), Rotation, color); diff --git a/src/App.bf b/src/App.bf index 139b48d..8aae9d8 100644 --- a/src/App.bf +++ b/src/App.bf @@ -1,263 +1,53 @@ namespace TheaterGui; +using TheaterGui.Core; +using TheaterGui.Core.Structs; +using TheaterGui.Components; using System; -using System.Collections; - -using RaylibBeef; - -using internal TheaterGui; -using TheaterGui.Components; class App { - /* - There are two ways to run TheaterGui. - Either full, by using the Run function or by manually calling the functions in Run. - This way you can integrate TheaterGui into other raylib applications of your choice. + private String _Name = new .("TheaterGui Program") ~ delete _; + private int32[2] _StartingSize = .(1280, 720); + private IPlatformLayer _Platform = null ~ delete _; + private colorScheme _Scheme = .DefaultScheme; + private theme _Theme = .(); - Components are supposed to be created via inheritance for each individual component, except some very simple exeptions (Labels, Placeholders) - */ - - -#region Fields - //For hover items - private static List _Popups = new .() ~ DeleteContainerAndItems!(_); - private static Vector2 _OldPos = .(0, 0); - private static double _MovTime = 0; - private static String _HoverText = new .() ~ delete _; - private static Vector2 _OldSize = .(0, 0); - - - public static Textures Textures ~ delete _; //All loaded textures - public static Component Selected; //Currently selected component - public static bool AllowReorder = true; - - - private static Screen _CurrentScreen = null ~ delete _; - public static Screen CurrentScreen + public Result Run(Container pScreen) { - get => _CurrentScreen; - set - { - if (_CurrentScreen != null) - delete _CurrentScreen; - _CurrentScreen = value; - _CurrentScreen.Reorder(Width); - } - }; + if(_Platform == null) + return .Err; + + var runtime = new TGRuntime(); + runtime.[Friend]Launch(_Platform, pScreen, _Name, _StartingSize[0], _StartingSize[1], _Scheme, _Theme); + delete runtime; - ///Window width - public static int32 Width - { - get => Raylib.GetRenderWidth(); - set => Raylib.SetWindowSize(value, Raylib.GetRenderHeight()); + return .Ok; } - - ///Window height - public static int32 Height + public void SetName(StringView pName) { - get => Raylib.GetRenderHeight(); - set => Raylib.SetWindowSize(Raylib.GetRenderWidth(), value); + _Name.Clear(); + _Name.Append(pName); } - - ///Mouse position - public static Vector2 Mouse + public void SetStartingSize(int32 pWidth, int32 pHeight) { - get => Raylib.GetMousePosition(); + if(pWidth > 0 || pHeight > 0) + return; + _StartingSize[0] = pWidth; + _StartingSize[1] = pHeight; } - - //Mouse wheel offset - public static float Wheel + public void SetPlatformLayer(IPlatformLayer pPlatformLayer) { - get; - set; - } - - - private static bool _ShouldClose; - public static bool ShouldClose - { - public get - { - return _ShouldClose || Raylib.WindowShouldClose(); - } - public set => _ShouldClose = value; - } -#endregion - - - - - - ///Run TheaterGui (Use for fully independent programs) - ///@param pName Name of the window - ///@param pWidth Width of the window - ///@param pHeight Height of the window - ///@param pStartScreen The starting Screen of the application - public static void Run(StringView pName, int32 pWidth, int32 pHeight) where T : Screen - { - InitializeRaylib(pName, pWidth, pHeight); - InitializeGui(); - -#if BF_PLATFORM_WASM - WebAssembly.emscripten_set_main_loop(=> ProcessDrawFrame, 40, 1); - ///Afaik the infinite loop means, that the deinitialization functionality will not be called, - ///but that should be fine for wasm since it fully cleans up when you exit the page. - ///If we dont do it calls the deinitialization directly afterwards -#else - while (!App.ShouldClose) - ProcessDrawFrame(); -#endif - - DeinitializeGui(); - DeinitializeRaylib(); - } - - - ///Initializes the raylib enviroment - ///@param pName Name of the window - ///@param pWidth Width of the window - ///@param pHeight Height of the window - public static void InitializeRaylib(StringView pName, int32 pWidth, int32 pHeight) - { - //Default raylib settings - Raylib.SetConfigFlags((.)(ConfigFlags.FLAG_WINDOW_RESIZABLE | ConfigFlags.FLAG_WINDOW_HIGHDPI)); - Raylib.InitWindow(pWidth, pHeight, scope String(pName)); - Raylib.SetExitKey(0); -#if !BF_PLATFORM_WASM ///Otherwise raylib sleeps and delays browser responsiveness - Raylib.SetTargetFPS(40); //Should be a resonable framerate for gui apps -#endif - Raylib.SetWindowMinSize(640, 360); - - ///Set the default window icon - var icon = Raylib.LoadImageFromMemory(".png", (.)&Theme.Texture_WindowIcon, Theme.Texture_WindowIcon.Count); - Raylib.SetWindowIcon(icon); - Raylib.UnloadImage(icon); - } - - - ///Initialize the gui enviroment - public static void InitializeGui() where T : Screen - { - Textures = new .(); - CurrentScreen = new T(); - } - - - ///Cleanup the gui enviroment - public static void DeinitializeGui() => void(); - - - ///Cleanup the raylib enviroment - public static void DeinitializeRaylib() => void(); - - - ///To be called by emscripten - private static void ProcessDrawFrame() - { - ProcessFrame(); - Raylib.BeginDrawing(); - Raylib.ClearBackground(Theme.Background); - DrawFrame(); - Raylib.EndDrawing(); - } - - - ///Process the logic for a single frame of the application - public static void ProcessFrame() - { - - Vector2 newSize = .(Width, Height); - if (_OldSize != newSize) - { - CurrentScreen.Reorder((.)newSize.x); - _OldSize = newSize; - } - - Input.HandleScrolling(Raylib.GetMouseWheelMove()); - - if (Raylib.IsMouseButtonPressed(0)) - Input.HandleLeftClick(); - else if (Raylib.IsMouseButtonDown(0)) - Input.HandleLeftDown(); - else if (Raylib.IsMouseButtonPressed(1)) - Input.HandleRightClick(); - else - Input.HandleHover(); - - if(Selected != null) - Selected.WhileSelected(); - } - - - ///Draw the current state of the application - public static void DrawFrame() - { - //Drawing logic - CurrentScreen.Render((.)Wheel); - - for (var i in _Popups) - i.Render((.)Wheel); - - if (!_HoverText.IsEmpty) - { - RenderHoverText(); - _HoverText.Clear(); - } - } - - private static void RenderHoverText() - { - int32 yOffset = 0; - int32 xOffset = 0; - - var measure = Raylib.MeasureTextEx(Theme.FontSmall, _HoverText, Theme.FontSizeSmall, 0); - - if (Mouse.x < Width / 2) //Render the textbox to the right of the cursor - xOffset = 15; - else //Render the textbox to the left of the cursor - xOffset = (.)(-1 * measure.x) - 15; - if (Mouse.y < Height / 2) //Render the textbox at the y location of the cursor - yOffset = 0; - else //Render the textbox offset so, that the textbox y ends at the y location of the cursor - yOffset = (.)(-1 * measure.y); - - //BoxShadow - //Box - //BoxBorder - //BoxContent - Raylib.DrawRectangle((.)Mouse.x - 3 + xOffset + 3, (.)Mouse.y - 3 + yOffset + 3, (.)measure.x + 6, (.)measure.y + 3, Color(0, 0, 0, 70)); - Raylib.DrawRectangle((.)Mouse.x - 3 + xOffset, (.)Mouse.y - 3 + yOffset, (.)measure.x + 6, (.)measure.y + 3, Color(218, 211, 176, 255)); - Raylib.DrawRectangleLines((.)Mouse.x - 3 + xOffset, (.)Mouse.y - 3 + yOffset, (.)measure.x + 6, (.)measure.y + 3, Raylib.BLACK); - Raylib.DrawTextEx(Theme.FontSmall, _HoverText, Raymath.Vector2Add(Mouse, Vector2(xOffset, yOffset)), Theme.FontSizeSmall, 0, Raylib.BLACK); + delete _Platform; + _Platform = pPlatformLayer; } + public void SetColorScheme(colorScheme pScheme) => _Scheme = pScheme; + public void SetUITheme(theme pTheme) => _Theme = pTheme; - - - public static void ForceReorder() - { - if (AllowReorder && CurrentScreen != null) - CurrentScreen.Reorder(Width); - } - - - public static void OpenPopup(Popup popup) - { - _Popups.Add(popup); - } - - public static Result GetTopmostPopup() - { - if(_Popups.Count < 1) - return .Err; - return .Ok(_Popups[^1]); - } -} - - +} \ No newline at end of file diff --git a/src/Components/Button.bf b/src/Components/Button.bf index f81e89a..45fc5d2 100644 --- a/src/Components/Button.bf +++ b/src/Components/Button.bf @@ -1,55 +1,51 @@ namespace TheaterGui.Components; +using TheaterGui.Core; +using TheaterGui.Core.Structs; using System; -using RaylibBeef; -abstract class Button : Component +class Button : Component { - public this(StringView pLabel, StringView pComponentName = "Button") : base(pComponentName, pLabel) + private bool _Hovered = false; + private bool _AlreadyHovered = false; + + public String Label ~ delete _; + + public this(StringView pName = "Button") { - Sprite = App.Textures.GetAsset("button"); - Width = Sprite.Width; - Height = Sprite.Height; + Label = new .(pName); } - public abstract void ClickAction(); //What happends when its clicked - - - protected bool _IsHovered = false; - public override Component OnHover(int32 x, int32 y) + public override void Update(TheaterGui.Core.TGRuntime rt) { - _IsHovered = true; - return this; + if(_Hovered != _AlreadyHovered) + { + _Hovered = _AlreadyHovered; + rt.Dirty(); + } + _AlreadyHovered = false; } - public override bool OnClick(int32 x, int32 y) + public override void Draw(TGRuntime rt, rect rect) { - if(Rectangle(X, Y, Width, Height).Overlaps(x, y)) - { - if(Enabled) - { - ClickAction(); - return true; - } - return false; - } - return false; + rt.Platform.DrawTexture("Button", rect, rt.Scheme.PrimaryColor); + if(_Hovered) + rt.Platform.DrawTexture("Button", rect, rt.Scheme.HoverColor); + + var tsize = rt.Platform.MeasureTextSize(Label, "Font_Normal"); + rt.Platform.DrawText(Label, "Font_Normal", + .((.)(rect.x + 0.5*rect.width - tsize[0]*0.5), + (.)(rect.y + 0.5*rect.height - tsize[1]*0.5)) + ,rt.Scheme.TextColor); } - public override void Render(int32 soy) + public override int32[2] Resize(TheaterGui.Core.TGRuntime rt, int32 width) { - Sprite.Render(X,Y + soy, Tint); - var measure = Raylib.MeasureTextEx(Theme.Font, Label.ToScopeCStr!(), Theme.FontSize, 0); - Raylib.DrawTextEx(Theme.Font, Label.ToScopeCStr!(), Vector2(X+Width/2-measure.x/2,Y+Height/2-measure.y/2 + soy), Theme.FontSize, 0, Theme.Text); - if(!Enabled) - { - Sprite.Render(X,Y + soy, Theme.DisabledTint); - } - else - { - if(_IsHovered) - Sprite.Render(X,Y + soy, HoverTint); - } - _IsHovered = false; + return rt.Platform.MeasureTextureSize("Button"); + } + public override bool OnHover(TGRuntime rt, int32[2] mPos) + { + _AlreadyHovered = true; + return true; } } \ No newline at end of file diff --git a/src/Components/Checkbox.bf b/src/Components/Checkbox.bf deleted file mode 100644 index ac5f849..0000000 --- a/src/Components/Checkbox.bf +++ /dev/null @@ -1,49 +0,0 @@ -namespace TheaterGui.Components; - -using System; -using RaylibBeef; - -abstract class Checkbox : Component -{ - public sprite SpriteChecked; - - public bool Checked = false; - - public abstract void OnCheck(bool checkValue); - - public this(StringView pName) : base("Checkbox", pName) - { - Sprite = App.Textures.GetAsset("checkbox"); - SpriteChecked = App.Textures.GetAsset("checkbox_checked"); - var measure = Raylib.MeasureTextEx(Theme.Font, Label.Ptr, Theme.FontSize, 0); - Width = Sprite.Width + (.)measure.x + 2; - Height = measure.y > Sprite.Height ? (.)measure.y : Sprite.Height; - } - - protected bool _IsHovered = false; - public override Component OnHover(int32 x, int32 y) - { - _IsHovered = true; - return this; - } - - public override bool OnClick(int32 x, int32 y) - { - Checked = !Checked; - OnCheck(Checked); - return true; - } - - public override void Render(int32 soy) - { - if(!Checked) - Sprite.Render(X,Y + soy,Tint); - else - SpriteChecked.Render(X,Y + soy,Tint); - var measure = Raylib.MeasureTextEx(Theme.Font, Label.ToScopeCStr!(), Theme.FontSize, 0); - Raylib.DrawTextEx(Theme.Font, Label.ToScopeCStr!(), Vector2(X + Sprite.Width + 2, (.)(Y + Sprite.Height/2 - 0.5*measure.y) + soy), Theme.FontSize, 0, Theme.Text); - if(_IsHovered) - Sprite.Render(X,Y + soy, HoverTint); - _IsHovered = false; - } -} \ No newline at end of file diff --git a/src/Components/Component.bf b/src/Components/Component.bf index a3618d8..e829bc8 100644 --- a/src/Components/Component.bf +++ b/src/Components/Component.bf @@ -1,107 +1,11 @@ namespace TheaterGui.Components; - -using System; -using RaylibBeef; +using TheaterGui.Core; +using TheaterGui.Core.Structs; abstract class Component { - public this(StringView pComponentName, StringView pLabel) - { - ComponentType = pComponentName; - Label = pLabel; - } - - /// - /// Fields - /// - public Container Parent; - public bool Enabled = true; - - public Color Tint = Theme.Tint; - public Color HoverTint = Theme.HoverTint; - public sprite Sprite; - - public int32 MarginTop = 0; - public int32 MarginBottom = 0; - public int32 MarginLeft = 0; - public int32 MarginRight = 0; - - /// - /// Properties - /// - public bool Selected - { //When something is selected its allowed to update every frame - get; - set - { - Selected = value; - App.Selected = this; - } - } - - public int32 Margin - { - //There seems to be no reasonable way to implement a getter here - set - { - MarginTop = value; - MarginBottom = value; - MarginLeft = value; - MarginRight = value; - } - } - - private int32 _X = 0; - public int32 X - { - get => _X; - private set - { - _X = value; - } //You may set this, but it might fuck up layouting - }; - - private int32 _Y = 0; - public int32 Y - { - get => _Y; - private set - { - _Y = value; - } //You may set this, but it might fuck up layouting - }; - - public int32 Width - { - public get; - protected set; //Please do not - } - - public int32 Height - { - public get; - protected set; //Please do not - } - - [DynamicString] //What this type of component is called - private String _ComponentType = new .() ~ delete _; - [DynamicString] //What the component says on it when rendered - private String _Label = null ~ delete _; - [DynamicString] //Usually only used by the OnHover tooltip - private String _Description = null ~ delete _; - - - /// - /// Functions - /// - public abstract void Render(int32 soy); - - public virtual bool OnClick(int32 x, int32 y) => false; - public virtual void OnRightClick(int32 x, int32 y, Toolbar.ToolbarCategory items) {} - public virtual bool HandleScrollEvent(float scroll, int32 x, int32 y) {return false;}; - public virtual bool OnDown(int32 x, int32 y) => false; - public abstract Component OnHover(int32 x, int32 y); - - public virtual void WhileSelected() { } - + public abstract void Update(TGRuntime rt); + public abstract void Draw(TGRuntime rt, rect rect); + public abstract int32[2] Resize(TGRuntime rt, int32 width); + public abstract bool OnHover(TGRuntime rt, int32[2] mPos); } \ No newline at end of file diff --git a/src/Components/Container.bf b/src/Components/Container.bf index 04d51ff..15bd64d 100644 --- a/src/Components/Container.bf +++ b/src/Components/Container.bf @@ -1,195 +1,80 @@ namespace TheaterGui.Components; +using TheaterGui.Core; +using TheaterGui.Core.Structs; using System; using System.Collections; -class Container : Component +abstract class Container : Component { - public this(StringView pName, StringView pComponentName = "Container") : base(pName, pComponentName) - { + protected Dictionary _Children = new .() ~ DeleteDictionaryAndKeysAndValues!(_); + protected List _Drawings = new .() ~ delete _; + public delegate void(Layout, int32 width) Layout = null ~ delete _; + + public override void Update(TGRuntime rt) + { + for(var i in _Children) + i.value.Update(rt); } - private List _LayoutData = new .() ~ delete _; - - public List Children = new .() ~ DeleteContainerAndItems!(_); - - - - ///Recalculate the layout of all entries - public virtual void Reorder(int32 w) + public override void Draw(TGRuntime rt, rect rect) { - /* - List {Entry, Entry, Entry, RB, Entry, Entry, RB, Entry, RB} - null is a rowbreak while non null isnt a rowbreak - - Algorithm - if the current entry is a rowbreak, reset the cursor to x = 0, y = y + height - - try to fit the current entry after the cursor - if it fits add it, - if it doesnt fit break - */ - - int32 maxWidth = 0; //The highest width line - int32 rowHeight = 0; //How high the current row is - int32 x = 0; - int32 y = 0; - - for(var e in _LayoutData) + for(var i in _Drawings) { - if(e == null) - { //Manual row break - x = 0; - y = y + rowHeight; - rowHeight = 0; - continue; - } + if(_Children.ContainsKeyAlt(i.name)) + _Children[scope .(i.name)].Draw(rt, i + rect); + } + } - if(e is Container) + public override int32[2] Resize(TGRuntime rt, int32 width) + { + _Drawings.Clear(); + + Layout l = scope .(); + l.[Friend]_RT = rt; + l.[Friend]_Children = _Children; + l.[Friend]_Drawings = _Drawings; + l.[Friend]_MaxWidth = width; + + Layout.Invoke(l, width); + + int32[2] max = .(0,0); + for(var i in _Drawings) + { + if(i.width+i.x > max[0]) + max[0] = i.width+i.x; + if(i.height+i.y > max[1]) + max[1] = i.height+i.y; + } + return max; + } + + public override bool OnHover(TGRuntime rt, int32[2] mPos) + { + for(var i in _Drawings) + { + if(_Children.GetValue(scope .(i.name)) case .Ok(let component)) { - ((Container)e).Reorder(w); - if(x+e.Width+e.MarginLeft > w-MarginLeft) //Change both instances of padding to 2*Padding to ensure proper padding on the leftmost side of the screen - { //Automatic row break - x = 0; - y = y + rowHeight; - rowHeight = 0; + if(mPos[0] >= i.x && mPos[0] <= i.x + i.width + && mPos[1] >= i.y && mPos[1] <= i.y + i.height) + { + if(component.OnHover(rt, .(mPos[0]-i.x, mPos[1]-i.y))) + return true; + else + return false; } - MoveChildrenRecursive((Container)e, x, y); } - - - if(e is Toolbar) - e.Width = App.Width; - - if(x+e.Width+e.MarginLeft > w-MarginLeft) //Change both instances of padding to 2*Padding to ensure proper padding on the leftmost side of the screen - { //Automatic row break - x = 0; - y = y + rowHeight; - rowHeight = 0; - } - - e.[Friend]X = x + e.MarginLeft; - x = x + e.Width + e.MarginLeft + e.MarginRight; - e.[Friend]Y = y + e.MarginTop; - if(x > maxWidth) - maxWidth = x; - - if(rowHeight < e.Height+e.MarginTop+e.MarginBottom) - rowHeight = e.Height+e.MarginTop+e.MarginBottom; } - - Width = maxWidth + MarginLeft + MarginRight; - Height = y + rowHeight + MarginTop + MarginBottom; - } - private void MoveChildrenRecursive(Container c, int32 x, int32 y) - { - for(var i in c.Children) - { - i.[Friend]X += x + MarginLeft + c.MarginLeft; - i.[Friend]Y += y + MarginTop + c.MarginTop; - if(i is Container) - MoveChildrenRecursive((Container)i, x, y); - } - } - - ///Add a new item to the list of items - public void AddChild(Component pToAdd) - { - _LayoutData.Add(pToAdd); - Children.Add(pToAdd); - pToAdd.Parent = this; - } - - public virtual void InsertBefore(Component pToAdd, Component Position, bool pReorder = true) - { - var idx = _LayoutData.IndexOf(Position); - if(idx < 0) - { - delete pToAdd; //Avoid memory leaks - return; - } - _LayoutData.Insert(idx, pToAdd); - Children.Add(pToAdd); - pToAdd.Parent = this; - - if(pReorder) - App.ForceReorder(); - } - - public virtual void InsertAfter(Component pToAdd, Component Position, bool pReorder = true) - { - var idx = _LayoutData.IndexOf(Position); - idx++; - if(idx < 0) - { - delete pToAdd; //Avoid memory leaks - return; - } - _LayoutData.Insert(idx, pToAdd); - Children.Add(pToAdd); - pToAdd.Parent = this; - - if(pReorder) - App.ForceReorder(); - } - - ///Forcefully terminates the current row - public void EndRow() => _LayoutData.Add(null); - - public override void Render(int32 soy) - { - for(var i in Children) - i.Render(soy); - } - - public override bool OnClick(int32 x, int32 y) - { - for(var e in Children) - { - if(RaylibBeef.Rectangle(e.X, e.Y, e.Width, e.Height).Overlaps(x, y)) - return e.OnClick(x, y); - } return false; } - public override bool OnDown(int32 x, int32 y) + public Result AddChild(StringView pName, Component pComponent) { - for(var e in Children) - { - if(RaylibBeef.Rectangle(e.X, e.Y, e.Width, e.Height).Overlaps(x, y)) - return e.OnDown(x, y); - } - return false; - } - - public override Component OnHover(int32 x, int32 y) - { - for(var e in Children) - { - if(RaylibBeef.Rectangle(e.X, e.Y, e.Width, e.Height).Overlaps(x, y)) - return e.OnHover(x, y); - } - return null; - } - - public override bool HandleScrollEvent(float scroll, int32 x, int32 y) - { - for(var e in Children) - { - if(RaylibBeef.Rectangle(e.X, e.Y, e.Width, e.Height).Overlaps(x, y)) - return e.HandleScrollEvent(scroll, x, y); - } - return false; - } - - public override void OnRightClick(int32 x, int32 y, Toolbar.ToolbarCategory items) - { - for(var e in Children) - { - if(RaylibBeef.Rectangle(e.X, e.Y, e.Width, e.Height).Overlaps(x, y)) - e.OnRightClick(x, y, items); - } + if(_Children.ContainsKeyAlt(pName)) + return .Err; + _Children.Add(new .(pName), pComponent); + return .Ok; } } \ No newline at end of file diff --git a/src/Components/Dropdown.bf b/src/Components/Dropdown.bf deleted file mode 100644 index 76e99de..0000000 --- a/src/Components/Dropdown.bf +++ /dev/null @@ -1,57 +0,0 @@ -namespace TheaterGui.Components; - -using System; -using System.Collections; -using RaylibBeef; - -abstract class Dropdown : Component -{ - public List Entries = new .() ~ DeleteContainerAndItems!(_); - public uint32 SelectedEntry = 0; - - public this() : base("Dropdown", "Label") - { - Margin = 20; - Sprite = App.Textures.GetAsset("dropdown"); - Width = Sprite.Width; - Height = Sprite.Height; - } - - public override void Render(int32 soy) - { - Sprite.Render(X,Y + soy, Tint); - var measure = Raylib.MeasureTextEx(Theme.Font, Entries[(.)SelectedEntry], Theme.FontSize, 0); - Raylib.DrawTextEx(Theme.Font, Entries[(.)SelectedEntry], Vector2(X+Width/2-measure.x/2,Y+Height/2-measure.y/2 + soy), Theme.FontSize, 0, Theme.Text); - if(!Enabled) - { - Sprite.Render(X,Y + soy, Theme.DisabledTint); - } - else - { - if(_IsHovered) - Sprite.Render(X,Y + soy, HoverTint); - } - _IsHovered = false; - } - - public override bool OnClick(int32 x, int32 y) - { - var list = new List(Entries.Count); - defer delete list; - for(var i in Entries) - list.Add(i); - var popup = new DropdownPopup(X, Y + Height, Width, list); - popup.Owner = this; - App.OpenPopup(popup); - return true; - } - - public abstract void ClickAction(String pNewVal); - - protected bool _IsHovered = false; - public override Component OnHover(int32 x, int32 y) - { - _IsHovered = true; - return this; - } -} \ No newline at end of file diff --git a/src/Components/DropdownPopup.bf b/src/Components/DropdownPopup.bf deleted file mode 100644 index c986c52..0000000 --- a/src/Components/DropdownPopup.bf +++ /dev/null @@ -1,109 +0,0 @@ -namespace TheaterGui.Components; - -using System; -using System.Collections; -using RaylibBeef; - -class DropdownPopup : Popup -{ - public NPatchInfo PatchInfo; - public int32 SelectedItem = -1; - public Dropdown Owner = null; - public List Options = new .() ~ DeleteContainerAndItems!(_); - - public this(int32 x, int32 y, int32 w, params Span options) : base("DropdownPopup", "DropdownPopup") - { - this.[Friend]X = x; - this.[Friend]Y = y-1; - Sprite = App.Textures.GetAsset("horizontal_patch"); - PatchInfo =.(Sprite.SourceRect, 2,2,2,2,(.)NPatchLayout.NPATCH_NINE_PATCH); - for(var i in options) - Options.Add(new .(i)); - Width = w; - Height = ((.)Options.Count * (Theme.FontSize+10))-5; - } - - public this(int32 x, int32 y, int32 w, List options) : base("DropdownPopup", "DropdownPopup") - { - this.[Friend]X = x; - this.[Friend]Y = y-1; - Sprite = App.Textures.GetAsset("horizontal_patch"); - PatchInfo =.(Sprite.SourceRect, 2,2,2,2,(.)NPatchLayout.NPATCH_NINE_PATCH); - for(var i in options) - Options.Add(new .(i)); - Width = w; - Height = ((.)Options.Count * (Theme.FontSize+10))-5; - } - - public override void Render(int32 soy) - { - Raylib.DrawTextureNPatch( - *Sprite.Source, - PatchInfo, - Rectangle(X, Y + soy, Width, Height), - Vector2(0,0), - 0, - Tint); - int32 y = 5; - for(var i in Options) - { - Raylib.DrawTextEx(Theme.Font, scope String(i), Vector2(X + 5, Y + y + soy), Theme.FontSize, 0, Theme.Text); - if(@i.Index == SelectedItem) - { - Raylib.DrawTextureNPatch( - *Sprite.Source, - PatchInfo, - Rectangle(X, Y + y - 4 + soy, Width, Theme.FontSize+10), - Vector2(0,0), - 0, - HoverTint); - } - - y += (.)Theme.FontSize+5; - } - } - - public override bool OnClick(int32 x, int32 y) - { - if(!(x >= X && x <= X + Width)) - return false; - - int32 pos = 5 + Y; - for(var i in Options) - { - if(y >= pos && y <= pos + (.)Theme.FontSize+5) - { - if(Owner != null) - { - Owner.SelectedEntry = (.)@i.Index; - Owner.ClickAction(i); - } - return false; - } - pos += (.)Theme.FontSize+5; - - } - - return false; - } - - public override Component OnHover(int32 x, int32 y) - { - int32 pos = 5 + Y; - for(var i in Options) - { - if(y >= pos && y <= pos + (.)Theme.FontSize+5) - { - SelectedItem = (.)@i.Index; - return this; - } - pos += (.)Theme.FontSize+5; - } - SelectedItem = -1; - return null; - } - - public override void OnClose() - { - } -} \ No newline at end of file diff --git a/src/Components/HSlider.bf b/src/Components/HSlider.bf deleted file mode 100644 index 900ffa2..0000000 --- a/src/Components/HSlider.bf +++ /dev/null @@ -1,11 +0,0 @@ -namespace TheaterGui.Components; - -using System; - -abstract class HSlider : NHSlider -{ - public this(StringView pLabel) : base(32 * 6, pLabel, "HSlider") - { - - } -} \ No newline at end of file diff --git a/src/Components/IconButton.bf b/src/Components/IconButton.bf deleted file mode 100644 index ad7b08e..0000000 --- a/src/Components/IconButton.bf +++ /dev/null @@ -1,30 +0,0 @@ -namespace TheaterGui.Components; - -using System; - -abstract class IconButton : Button -{ - public sprite Icon = App.Textures.GetAsset("folder_icon"); - - - public this(StringView pName) : base(pName, "SquareButton") - { - Sprite = App.Textures.GetAsset("square_button"); - Width = Sprite.Width; - Height = Sprite.Height; - } - - - - public override void Render(int32 soy) - { - - Sprite.Render(X,Y + soy, Tint); - Icon.Render(X+Width/2-Icon.Width/2+2,Y+Height/2-Icon.Height/2+2 + soy, .(0,0,0,125)); - Icon.Render(X+Width/2-Icon.Width/2,Y+Height/2-Icon.Height/2 + soy); - if(_IsHovered) - Sprite.Render(X,Y + soy, HoverTint); - _IsHovered = false; - - } -} \ No newline at end of file diff --git a/src/Components/InputField.bf b/src/Components/InputField.bf deleted file mode 100644 index 8900f78..0000000 --- a/src/Components/InputField.bf +++ /dev/null @@ -1,72 +0,0 @@ -namespace TheaterGui.Components; - -using System; - -using RaylibBeef; - -class InputField : Component -{ - public NPatchInfo PatchInfo; - public String InputContent = new .() ~ delete _; - - - String text = new .() ~ delete _; - public this(StringView pLabel) : base("InputField", pLabel) - { - Label = "Test Data"; - Sprite = App.Textures.GetAsset("n_button"); - Width = 128 * 2; - Height = 32; - Margin = 10; - Tint = Theme.Background; - PatchInfo = .(Sprite.SourceRect, 7, 7, 7, 7, (.)NPatchLayout.NPATCH_NINE_PATCH); - } - public override void Render(int32 soy) - { - Raylib.DrawTextureNPatch( - *Sprite.Source, - PatchInfo, - Rectangle(X, Y + soy, Width, Height), - Vector2(0, 0), - 0, - Tint); - - if (_IsHovered || App.Selected == this) - Raylib.DrawTextureNPatch(*Sprite.Source, PatchInfo, Rectangle(X, Y + soy, Width, Height), Vector2(0, 0), 0, Theme.Tint.SetAlpha(120)); - _IsHovered = false; - - var measure = Raylib.MeasureTextEx(Theme.Font, text, Theme.FontSize, 0); - Raylib.DrawTextEx(Theme.Font, text, Vector2(X + 7, Y + Height / 2 - measure.y / 2 + soy), Theme.FontSize, 0, Theme.Text); - } - - protected bool _IsHovered = false; - public override Component OnHover(int32 x, int32 y) - { - _IsHovered = true; - return this; - } - - public override bool OnClick(int32 x, int32 y) - { - App.Selected = this; - return true; - } - - public override void WhileSelected() - { - int key = Raylib.GetCharPressed(); - while (key > 0) - { - // NOTE: Only allow keys in range [32..125] - if ((key >= 32) && (key <= 125) && (text.Length < 100)) - text.Append((char8)key); - - key = Raylib.GetCharPressed(); // Check next character in the queue - } - - if (Raylib.IsKeyPressed((.)KeyboardKey.KEY_BACKSPACE)) - text.RemoveFromEnd(1); - if(Raylib.IsKeyPressed((.)KeyboardKey.KEY_ESCAPE)) - App.Selected = null; - } -} \ No newline at end of file diff --git a/src/Components/Label.bf b/src/Components/Label.bf deleted file mode 100644 index 529641c..0000000 --- a/src/Components/Label.bf +++ /dev/null @@ -1,25 +0,0 @@ -namespace TheaterGui.Components; - -using System; -using RaylibBeef; - -class Label : Component -{ - private Vector2 _Measure; - public this(StringView pName) : base(Label, pName) - { - Label = pName; - Margin = 3; - _Measure = Raylib.MeasureTextEx(Theme.FontLarge, Label.Ptr, Theme.FontSizeLarge, 0); - Height = (.)_Measure.y; - Width = (.)_Measure.x; - } - - public override Component OnHover(int32 x, int32 y) => null; - - public override void Render(int32 soy) - { - Raylib.DrawTextEx(Theme.FontLarge, Label.Ptr, Vector2(X,Y + soy), Theme.FontSizeLarge, 0, Theme.Text); - Raylib.DrawLine(X,Y + (.)_Measure.y + soy,X + (.)_Measure.x, Y + (.)_Measure.y + soy, Theme.Text); - } -} \ No newline at end of file diff --git a/src/Components/LargeButton.bf b/src/Components/LargeButton.bf deleted file mode 100644 index c3ec88f..0000000 --- a/src/Components/LargeButton.bf +++ /dev/null @@ -1,24 +0,0 @@ -namespace TheaterGui.Components; - -using System; -using RaylibBeef; - -abstract class LargeButton : Button -{ - public this(StringView pName) : base(pName, "LargeButton") - { - Sprite = App.Textures.GetAsset("large_button"); - Width = Sprite.Width; - Height = Sprite.Height; - } - - public override void Render(int32 soy) - { - Sprite.Render(X,Y + soy, Tint); - var measure = Raylib.MeasureTextEx(Theme.Font, Label.Ptr, Theme.FontSize, 0); - Raylib.DrawTextEx(Theme.Font, Label.Ptr, Vector2(X+Width/2-measure.x/2,Y+Height/2-measure.y/2 + soy), Theme.FontSize, 0, Theme.Text); - if(_IsHovered) - Sprite.Render(X,Y + soy, HoverTint); - _IsHovered = false; - } -} \ No newline at end of file diff --git a/src/Components/NButton.bf b/src/Components/NButton.bf deleted file mode 100644 index ede9234..0000000 --- a/src/Components/NButton.bf +++ /dev/null @@ -1,56 +0,0 @@ -namespace TheaterGui.Components; - -using System; -using RaylibBeef; - -abstract class NButton : Button -{ - public NPatchInfo PatchInfo; - - public this(int32 w, int32 h, StringView pName) : base(pName, "NButton") - { - Sprite = App.Textures.GetAsset("n_button"); - Width = w; - Height = h; - - PatchInfo =.(Sprite.SourceRect, 7,7,7,7,(.)NPatchLayout.NPATCH_NINE_PATCH); - - } - - public override void Render(int32 soy) - { - Raylib.DrawTextureNPatch( - *Sprite.Source, - PatchInfo, - Rectangle(X, Y + soy, Width, Height), - Vector2(0,0), - 0, - Tint); - - var measure = Raylib.MeasureTextEx(Theme.Font, Label.ToScopeCStr!(), Theme.FontSize, 0); - Raylib.DrawTextEx(Theme.Font, Label.ToScopeCStr!(), Vector2(X+Width/2-measure.x/2,Y+Height/2-measure.y/2 + soy), Theme.FontSize, 0, Theme.Text); - - if(!Enabled) - { - Raylib.DrawTextureNPatch( - *Sprite.Source, - PatchInfo, - Rectangle(X, Y + soy, Width, Height), - Vector2(0,0), - 0, - Theme.DisabledTint); - } - else - { - if(_IsHovered) - Raylib.DrawTextureNPatch( - *Sprite.Source, - PatchInfo, - Rectangle(X, Y + soy, Width, Height), - Vector2(0,0), - 0, - HoverTint); - } - _IsHovered = false; - } -} \ No newline at end of file diff --git a/src/Components/NHSlider.bf b/src/Components/NHSlider.bf deleted file mode 100644 index 5836af7..0000000 --- a/src/Components/NHSlider.bf +++ /dev/null @@ -1,78 +0,0 @@ -namespace TheaterGui.Components; - -using System; -using RaylibBeef; - -//This slider may be any size -abstract class NHSlider : Component -{ - private bool _CurrentlyDragged = false; //Used to stop accidental hovers - public int32 BarWidth = 0; - public float Percentage = 0; - public float Min = 0; - public float Max = 0; - public float Value - { - get => Min + Percentage * (Max-Min); - set => Percentage = (value - Min)/(Max-Min); //This should be mathematically fine, no clue if its actually fine though - } - - public bool ReactToValueChange = false; //Calling on value change too frequently might not be good so we clear here - public virtual void OnValueChange(float newVal) - { - - } - - public this(int32 width, StringView pLabel, StringView pTypename = "NHSlider") : base(pTypename, pLabel) - { - Sprite = App.Textures.GetAsset("checkbox"); - Width = width + Sprite.Width; - BarWidth = width; - Height = Sprite.Height; - } - - - public override void Render(int32 soy) - { - Raylib.DrawRectangle(X + Sprite.Width/2, Y + Sprite.Height/2 - 4 + soy, BarWidth, 8, Raylib.BLACK); - Sprite.Render((.)(X+ Percentage * BarWidth), Y + soy, Tint); - if(_IsHovered) - Sprite.Render((.)(X +Percentage * BarWidth), Y + soy, HoverTint); - _IsHovered = false; - - if(!Raylib.IsMouseButtonDown(0)) - _CurrentlyDragged = false; - } - - public override bool OnClick(int32 x, int32 y) - { - _CurrentlyDragged = true; - return true; - } - - public override bool OnDown(int32 x, int32 y) - { - if(_CurrentlyDragged) - { - float np = 0; - np = x - X; - np = Math.Clamp(np, Sprite.Width/2, Width - Sprite.Width/2); //Not rly clamp - np -= Sprite.Width/2; - np = np / (BarWidth); //I fucking hate that this works - - float oldp = Percentage; - Percentage = np; - if(ReactToValueChange && oldp != Percentage) - OnValueChange(Min + np * (Max-Min)); - return true; - } - return false; - } - - protected bool _IsHovered = false; - public override Component OnHover(int32 x, int32 y) - { - _IsHovered = true; - return this; - } -} \ No newline at end of file diff --git a/src/Components/NVSlider.bf b/src/Components/NVSlider.bf deleted file mode 100644 index a1297f0..0000000 --- a/src/Components/NVSlider.bf +++ /dev/null @@ -1,78 +0,0 @@ -namespace TheaterGui.Components; - -using System; -using RaylibBeef; - -//This slider may be any size -abstract class NVSlider : Component -{ - private bool _CurrentlyDragged = false; //Used to stop accidental hovers - public int32 BarHeight = 0; - public float Percentage = 0; - public float Min = 0; - public float Max = 0; - public float Value - { - get => Min + Percentage * (Max-Min); - set => Percentage = (value - Min)/(Max-Min); //This should be mathematically fine, no clue if its actually fine though - } - - public bool ReactToValueChange = false; //Calling on value change too frequently might not be good so we clear here - public virtual void OnValueChange(float newVal) - { - - } - - public this(int32 height, StringView pLabel, StringView pTypeName = "NVSlider") : base(pTypeName, pLabel) - { - Sprite = App.Textures.GetAsset("checkbox"); - Width = Sprite.Width; - BarHeight = height; - Height = Sprite.Height + height; - } - - - public override void Render(int32 soy) - { - Raylib.DrawRectangle(X + Sprite.Width/2 - 4, Y + Sprite.Height/2 + soy, 8, BarHeight, Raylib.BLACK); - Sprite.Render(X, Y + soy + Percentage * BarHeight, Tint); - if(_IsHovered) - Sprite.Render(X, Y + soy + Percentage * BarHeight, HoverTint); - _IsHovered = false; - - if(!Raylib.IsMouseButtonDown(0)) - _CurrentlyDragged = false; - } - - public override bool OnClick(int32 x, int32 y) - { - _CurrentlyDragged = true; - return true; - } - - public override bool OnDown(int32 x, int32 y) - { - if(_CurrentlyDragged) - { - float np = 0; - np = y - Y; - np = Math.Clamp(np, Sprite.Height/2, Height - Sprite.Height/2); //Not rly clamp - np -= Sprite.Height/2; - np = np / (BarHeight); //I fucking hate that this works - - float oldp = Percentage; - Percentage = np; - if(ReactToValueChange && oldp != Percentage) - OnValueChange(Min + np * (Max-Min)); - return true; - } - return false; - } - - protected bool _IsHovered = false; - public override Component OnHover(int32 x, int32 y) - { - _IsHovered = true; - return this; - } -} \ No newline at end of file diff --git a/src/Components/Placeholder.bf b/src/Components/Placeholder.bf deleted file mode 100644 index c635b3a..0000000 --- a/src/Components/Placeholder.bf +++ /dev/null @@ -1,13 +0,0 @@ -namespace TheaterGui.Components; - -class Placeholder : Component -{ - public this(int32 w, int32 h) : base("Placeholder", "Placeholder") - { - Width = w; - Height = h; - } - - public override Component OnHover(int32 x, int32 y) => null; - public override void Render(int32 soy) {} -} \ No newline at end of file diff --git a/src/Components/Popup.bf b/src/Components/Popup.bf deleted file mode 100644 index b574802..0000000 --- a/src/Components/Popup.bf +++ /dev/null @@ -1,12 +0,0 @@ -namespace TheaterGui.Components; - -abstract class Popup : Component -{ - public this(System.StringView pComponentName, System.StringView pLabel) : base(pComponentName, pLabel) - { - - } - - ///When something force closes the popup - public abstract void OnClose(); -} \ No newline at end of file diff --git a/src/Components/RadioButton.bf b/src/Components/RadioButton.bf deleted file mode 100644 index 448ca7e..0000000 --- a/src/Components/RadioButton.bf +++ /dev/null @@ -1,62 +0,0 @@ -namespace TheaterGui.Components; - -using System; - -abstract class RadioButton : Container -{ - public int32 Checked = -1; - - public this(StringView pName) : base(pName, "RadioButtons") - { - Description = pName; - } - - public virtual void OnCheck(int32 value) - { - - } - - ///Set all of the fields to be used as checkboxes - public void SetBoxes(int32 selectedIndex, params Span args) - { - Checked = selectedIndex; - //Clear out old ones - this.[Friend]_LayoutData.ClearAndDeleteItems(); - Children.Clear(); - - for(var i in args) - { - var toAdd = new RadioCheckbox(i); - toAdd.Description = Description; - if(@i.Index == selectedIndex) - toAdd.Checked = true; - AddChild(toAdd); - EndRow(); - } - } - - private void SelectButton(RadioCheckbox toSelect) - { - for(var i in Children) - if(i == toSelect) - { - ((RadioCheckbox)i).Checked = true; - Checked = (.)@i.Index; - OnCheck((.)@i.Index); - } - else - ((RadioCheckbox)i).Checked = false; - } - - private class RadioCheckbox : Checkbox - { - public this(StringView pName) : base(pName) - { - Margin = 2; - } - public override void OnCheck(bool checkValue) - { - ((RadioButton)Parent).SelectButton(this); - } - } -} \ No newline at end of file diff --git a/src/Components/RightClickPopup.bf b/src/Components/RightClickPopup.bf deleted file mode 100644 index ee2e752..0000000 --- a/src/Components/RightClickPopup.bf +++ /dev/null @@ -1,115 +0,0 @@ -namespace TheaterGui.Components; - -using System; -using RaylibBeef; -using System.Collections; - -class RightClickPopup : Popup -{ - public NPatchInfo PatchInfo; - public Toolbar.ToolbarCategory.ToolbarItem SelectedItem = null; - - private Toolbar.ToolbarCategory _Category = null ~ delete _; - public Toolbar.ToolbarCategory Category - { - get => _Category; - set - { - _Category = value; - int32 maxWidth = 0; - for(var i in _Category.Items) - if(maxWidth <= i.NameMeasurement.x) - maxWidth = (.)i.NameMeasurement.x; - - Width = maxWidth + 10 + 20; - Height = (.)(5 +((_Category.NameMeasurement.y + 5) * _Category.Items.Count)); - } - } - - public this(int32 x, int32 y, Toolbar.ToolbarCategory category) : base("ToolbarPopup", category.Name) - { - this.[Friend]X = x; - this.[Friend]Y = y-1; - Sprite = App.Textures.GetAsset("horizontal_patch"); - PatchInfo =.(Sprite.SourceRect, 2,2,2,2,(.)NPatchLayout.NPATCH_NINE_PATCH); - Category = category; - if(x+Width > App.Width) - this.[Friend]X -= Width; - if(y+Height > App.Height) - this.[Friend]Y -= Height; - } - - public override void Render(int32 soy) - { - Raylib.DrawTextureNPatch( - *Sprite.Source, - PatchInfo, - Rectangle(X, Y + soy, Width, Height), - Vector2(0,0), - 0, - Tint); - int32 y = 5; - for(var i in Category.Items) - { - Raylib.DrawTextEx(Theme.Font, scope String(i.Name), Vector2(X + 5, Y + y + soy), Theme.FontSize, 0, Theme.Text); - if(SelectedItem == i) - { - Raylib.DrawTextureNPatch( - *Sprite.Source, - PatchInfo, - Rectangle(X, Y + y - 5 + soy, Width, i.NameMeasurement.y+10), - Vector2(0,0), - 0, - HoverTint); - } - - y += (.)i.NameMeasurement.y+5; - } - } - - public override Component OnHover(int32 x, int32 y) - { - if(!(x >= X && x <= X + Width)) - { - SelectedItem = null; - return null; - } - - int32 pos = 5 + Y; - for(var i in Category.Items) - { - if(y >= pos && y <= pos + (.)i.NameMeasurement.y+5) - { - SelectedItem = i; - return this; - } - pos += (.)i.NameMeasurement.y+5; - } - SelectedItem = null; - return null; - } - - public override bool OnClick(int32 x, int32 y) - { - if(!(x >= X && x <= X + Width)) - return false; - - int32 pos = 5 + Y; - for(var i in Category.Items) - { - if(y >= pos && y <= pos + (.)i.NameMeasurement.y+5) - { - if(i.ClickAction != null) - i.ClickAction(); - return false; - } - pos += (.)i.NameMeasurement.y+5; - } - - return false; - } - - public override void OnClose() - { - } -} \ No newline at end of file diff --git a/src/Components/Screen.bf b/src/Components/Screen.bf deleted file mode 100644 index b1df64a..0000000 --- a/src/Components/Screen.bf +++ /dev/null @@ -1,18 +0,0 @@ -namespace TheaterGui.Components; -using TheaterGui; - -using System; -using System.Collections; -using RaylibBeef; - -/* - While containers are sized depending on their parent, screens are sized depending on the user -*/ -class Screen : Container -{ - public this(StringView pName) : base(pName, "Screen") - { - this.Width = Raylib.GetRenderWidth(); - this.Height = Raylib.GetRenderHeight(); - } -} \ No newline at end of file diff --git a/src/Components/ScrollableContainer.bf b/src/Components/ScrollableContainer.bf deleted file mode 100644 index 8dfe0e4..0000000 --- a/src/Components/ScrollableContainer.bf +++ /dev/null @@ -1,193 +0,0 @@ -namespace TheaterGui.Components; - -using System; -using System.Collections; -using RaylibBeef; - -class ScrollableContainer : Container -{ - public int32 ContainerHeight = 0; - public float Scroll = 0; - - public this(StringView pName, StringView pComponentName = "Container") : base(pName, pComponentName) - { - - } - - private List _LayoutData = new .() ~ delete _; - ///Recalculate the layout of all entries - public override void Reorder(int32 w) - { - /* - List {Entry, Entry, Entry, RB, Entry, Entry, RB, Entry, RB} - null is a rowbreak while non null isnt a rowbreak - - Algorithm - if the current entry is a rowbreak, reset the cursor to x = 0, y = y + height - - try to fit the current entry after the cursor - if it fits add it, - if it doesnt fit break - */ - - int32 maxWidth = 0; //The highest width line - int32 rowHeight = 0; //How high the current row is - int32 x = 0; - int32 y = 0; - - for(var e in _LayoutData) - { - if(e == null) - { //Manual row break - x = 0; - y = y + rowHeight; - rowHeight = 0; - continue; - } - - if(e is Container) - { - ((Container)e).Reorder(w); - MoveChildrenRecursive((Container)e, x, y); - } - - if(e is Toolbar) - e.Width = App.Width; - - if(x+e.Width+e.MarginLeft > w-MarginLeft) //Change both instances of padding to 2*Padding to ensure proper padding on the leftmost side of the screen - { //Automatic row break - x = 0; - y = y + rowHeight; - rowHeight = 0; - } - e.[Friend]X = x + e.MarginLeft; - x = x + e.Width + e.MarginLeft + e.MarginRight; - e.[Friend]Y = y + e.MarginTop; - if(x > maxWidth) - maxWidth = x; - - if(rowHeight < e.Height+e.MarginTop+e.MarginBottom) - rowHeight = e.Height+e.MarginTop+e.MarginBottom; - - } - - Width = maxWidth + MarginLeft + MarginRight; - Height = y + rowHeight + MarginTop + MarginBottom; - } - - private void MoveChildrenRecursive(Container c, int32 x, int32 y) - { - for(var i in c.Children) - { - i.[Friend]X += x + MarginLeft + c.MarginLeft; - i.[Friend]Y += y + MarginTop + c.MarginTop; - if(i is Container) - MoveChildrenRecursive((Container)i, x, y); - } - } - - ///Add a new item to the list of items - public new void AddChild(Component pToAdd) - { - _LayoutData.Add(pToAdd); - Children.Add(pToAdd); - pToAdd.Parent = this; - } - - public override void InsertBefore(Component pToAdd, Component Position, bool pReorder = true) - { - var idx = _LayoutData.IndexOf(Position); - if(idx < 0) - { - delete pToAdd; //Avoid memory leaks - return; - } - _LayoutData.Insert(idx, pToAdd); - Children.Add(pToAdd); - pToAdd.Parent = this; - - if(pReorder) - App.ForceReorder(); - } - - public override void InsertAfter(Component pToAdd, Component Position, bool pReorder = true) - { - var idx = _LayoutData.IndexOf(Position); - idx++; - if(idx < 0) - { - delete pToAdd; //Avoid memory leaks - return; - } - _LayoutData.Insert(idx, pToAdd); - Children.Add(pToAdd); - pToAdd.Parent = this; - - if(pReorder) - App.ForceReorder(); - } - - ///Forcefully terminates the current row - public new void EndRow() => _LayoutData.Add(null); - - public override void Render(int32 soy) - { - Raylib.BeginScissorMode(X, Y + soy, Width, Height); - for(var i in Children) - i.Render((.)(soy + Scroll)); - Raylib.EndScissorMode(); - } - - public override bool OnClick(int32 x, int32 y) - { - for(var e in Children) - { - if(RaylibBeef.Rectangle(e.X, e.Y, e.Width, e.Height).Overlaps(x, (.)(y - Scroll))) - return e.OnClick(x, (.)(y - Scroll)); - } - return false; - } - - public override bool OnDown(int32 x, int32 y) - { - for(var e in Children) - { - if(RaylibBeef.Rectangle(e.X, e.Y, e.Width, e.Height).Overlaps(x, (.)(y - Scroll))) - return e.OnDown(x, (.)(y - Scroll)); - } - return false; - } - - public override Component OnHover(int32 x, int32 y) - { - for(var e in Children) - { - if(RaylibBeef.Rectangle(e.X, e.Y, e.Width, e.Height).Overlaps(x, (.)(y - Scroll))) - return e.OnHover(x, (.)(y - Scroll)); - } - return null; - } - - public override void OnRightClick(int32 x, int32 y, Toolbar.ToolbarCategory items) - { - for(var e in Children) - { - if(RaylibBeef.Rectangle(e.X, e.Y, e.Width, e.Height).Overlaps(x, (.)(y - Scroll))) - e.OnRightClick(x, (.)(y - Scroll), items); - } - } - - public override bool HandleScrollEvent(float scroll, int32 x, int32 y) - { - for(var e in Children) - { - if(RaylibBeef.Rectangle(e.X, e.Y, e.Width, e.Height).Overlaps(x, (.)(y - Scroll))) - if(e.HandleScrollEvent(scroll, x, (.)(y - Scroll))) - return true; - } - - Scroll += scroll; - Scroll = Math.Clamp(Scroll,-(Height-ContainerHeight),0); - return true; - } -} \ No newline at end of file diff --git a/src/Components/Toolbar.bf b/src/Components/Toolbar.bf deleted file mode 100644 index 355fd65..0000000 --- a/src/Components/Toolbar.bf +++ /dev/null @@ -1,144 +0,0 @@ -namespace TheaterGui.Components; - -using System; -using System.Collections; -using RaylibBeef; - -abstract class Toolbar : Component -{ - public NPatchInfo PatchInfo; - public List Categories = new .() ~ DeleteContainerAndItems!(_); - private ToolbarPopup _CurrentPopup = null; - private ToolbarCategory _SelectedPopup = null; - - public this(StringView pLabel) : base("Toolbar", pLabel) - { - Height = 24; - Sprite = App.Textures.GetAsset("horizontal_patch"); - PatchInfo =.(Sprite.SourceRect, 2,2,2,2,(.)NPatchLayout.NPATCH_NINE_PATCH); - } - - public override void Render(int32 soy) - { - Raylib.DrawTextureNPatch( - *Sprite.Source, - PatchInfo, - Rectangle(X, Y + soy, Width, Height), - Vector2(0,0), - 0, - Tint); - int32 x = 5; - for(var i in Categories) - { - Raylib.DrawTextEx(Theme.Font, scope String(scope $"{i.Name}"), Vector2(X + x, Y + Height/2 - i.NameMeasurement.y/2 + soy), Theme.FontSize, 0, Theme.Text); - if(i == _SelectedPopup) - { - //5 padding in every direction - Raylib.DrawTextureNPatch( - *Sprite.Source, - PatchInfo, - Rectangle(X + x-5, Y + soy, i.NameMeasurement.x+10, Height), - Vector2(0,0), - 0, - HoverTint); - } - - x += (.)i.NameMeasurement.x + 10; - } - } - - public override bool OnClick(int32 x, int32 y) - { - int32 hor = 10; - for(var i in Categories) - { - if(x >= hor && x <= hor + i.NameMeasurement.x) - { - var popup = new ToolbarPopup(hor-10,Height + Y, i); - popup.Owner = this; - App.OpenPopup(popup); - _CurrentPopup = popup; - return true; - } - hor += (.)i.NameMeasurement.x + 10; - } - return false; - } - - public override Component OnHover(int32 x, int32 y) - { - int32 hor = 10; - for(var i in Categories) - { - if(x >= hor && x <= hor + i.NameMeasurement.x) - { - _SelectedPopup = i; - - if(_CurrentPopup != null && _CurrentPopup.Category != i) - { - _CurrentPopup.Category = i; - _CurrentPopup.[Friend]X = hor-10; - } - return this; - } - hor += (.)i.NameMeasurement.x + 10; - } - _SelectedPopup = null; - - return null; - } - - public void AddToolbarCategories(params Span pCategories) - { - for(var i in pCategories) - Categories.Add(i); - } - - ///Toolbar data is stored in here - public class ToolbarCategory - { - private String _Name = null ~ delete _; - public Vector2 NameMeasurement = .(0,0); - public StringView Name - { - public get => (_Name != null) ? _Name : default; - public set - { - String.NewOrSet!(_Name, value); - NameMeasurement = Raylib.MeasureTextEx(Theme.Font, _Name, Theme.FontSize, 0); - } - } - - public this(StringView pName, params Span pItems) - { - Name = pName; - for(var i in pItems) - Items.Add(i); - } - - public class ToolbarItem - { - private String _Name = null ~ delete _; - public Vector2 NameMeasurement = .(0,0); - public StringView Name - { - public get => (_Name != null) ? _Name : default; - public set - { - String.NewOrSet!(_Name, value); - NameMeasurement = Raylib.MeasureTextEx(Theme.Font, _Name, Theme.FontSize, 0); - } - } - - public this(StringView pName, delegate void() pClickAction) - { - Name = pName; - ClickAction = pClickAction; - } - - public delegate void() ClickAction = null ~ delete _; - } - - public List Items = new .() ~ DeleteContainerAndItems!(_); - } -} \ No newline at end of file diff --git a/src/Components/ToolbarPopup.bf b/src/Components/ToolbarPopup.bf deleted file mode 100644 index 35e9a75..0000000 --- a/src/Components/ToolbarPopup.bf +++ /dev/null @@ -1,116 +0,0 @@ -namespace TheaterGui.Components; - -using System; -using RaylibBeef; - -class ToolbarPopup : Popup -{ - public NPatchInfo PatchInfo; - public Toolbar Owner = null; - public Toolbar.ToolbarCategory.ToolbarItem SelectedItem = null; - - private Toolbar.ToolbarCategory _Category = null; - public Toolbar.ToolbarCategory Category - { - get => _Category; - set - { - _Category = value; - int32 maxWidth = 0; - for(var i in _Category.Items) - if(maxWidth <= i.NameMeasurement.x) - maxWidth = (.)i.NameMeasurement.x; - - Width = maxWidth + 10 + 32; - Height = (.)(5 +((_Category.NameMeasurement.y + 5) * _Category.Items.Count)); - } - } - - public this(int32 x, int32 y, Toolbar.ToolbarCategory category) : base("ToolbarPopup", category.Name) - { - this.[Friend]X = x; - this.[Friend]Y = y-1; - Sprite = App.Textures.GetAsset("horizontal_patch"); - PatchInfo =.(Sprite.SourceRect, 2,2,2,2,(.)NPatchLayout.NPATCH_NINE_PATCH); - Category = category; - } - - public override void Render(int32 soy) - { - Raylib.DrawTextureNPatch( - *Sprite.Source, - PatchInfo, - Rectangle(X, Y + soy, Width, Height), - Vector2(0,0), - 0, - Tint); - int32 y = 5; - for(var i in Category.Items) - { - Raylib.DrawTextEx(Theme.Font, scope String(i.Name), Vector2(X + 5 + 32, Y + y + soy), Theme.FontSize, 0, Theme.Text); - if(SelectedItem == i) - { - Raylib.DrawTextureNPatch( - *Sprite.Source, - PatchInfo, - Rectangle(X, Y + y - 5 + soy, Width, i.NameMeasurement.y+10), - Vector2(0,0), - 0, - HoverTint); - } - - y += (.)i.NameMeasurement.y+5; - } - } - - public override Component OnHover(int32 x, int32 y) - { - if(!(x >= X && x <= X + Width)) - { - SelectedItem = null; - return null; - } - - int32 pos = 5 + Y; - for(var i in Category.Items) - { - if(y >= pos && y <= pos + (.)i.NameMeasurement.y+5) - { - SelectedItem = i; - return this; - } - pos += (.)i.NameMeasurement.y+5; - } - SelectedItem = null; - return null; - } - - public override bool OnClick(int32 x, int32 y) - { - if(!(x >= X && x <= X + Width)) - return false; - - int32 pos = 5 + Y; - for(var i in Category.Items) - { - if(y >= pos && y <= pos + (.)i.NameMeasurement.y+5) - { - if(i.ClickAction != null) - i.ClickAction(); - return false; - } - pos += (.)i.NameMeasurement.y+5; - } - - return false; - } - - public override void OnClose() - { - if(Owner != null) - { - Owner.[Friend]_CurrentPopup = null; - Owner.[Friend]_SelectedPopup = null; - } - } -} \ No newline at end of file diff --git a/src/Components/VSlider.bf b/src/Components/VSlider.bf deleted file mode 100644 index 467f1b5..0000000 --- a/src/Components/VSlider.bf +++ /dev/null @@ -1,11 +0,0 @@ -namespace TheaterGui.Components; - -using System; - -abstract class VSlider : NVSlider -{ - public this(StringView pLabel) : base(32 * 6, pLabel, "VSlider") - { - - } -} \ No newline at end of file diff --git a/src/Core/Layout.bf b/src/Core/Layout.bf new file mode 100644 index 0000000..17b062f --- /dev/null +++ b/src/Core/Layout.bf @@ -0,0 +1,64 @@ +namespace TheaterGui.Core; +using TheaterGui.Components; +using TheaterGui.Core.Structs; + +using System; +using System.Collections; + +class Layout +{ + private TGRuntime _RT; + private Dictionary _Children; + private List _Drawings; + + private int32 _X = 0; + private int32 _Y = 0; + private int32 _LineHeight = 0; + + private int32 _MaxWidth = 0; + + public void Linebreak(int32 padding = 0) + { + _X = 0; + _Y += _LineHeight + padding; + _LineHeight = 0; + } + + public void Placeholder(int32 width, int32 height) + { + if(height > _LineHeight) + _LineHeight = height; + if(!(_X + width > _MaxWidth)) + _X += width; + } + + public void Component(StringView name, int32 padding) => Component(name, padding, padding, padding, padding); + public void Component(StringView name, int32 padding_top = 0, int32 padding_bottom = 0, int32 padding_left = 0, int32 padding_right = 0) + { + if(_Children.ContainsKeyAlt(name)) + { + var item = _Children[scope .(name)]; + var size = item.Resize(_RT, _MaxWidth); + + if(_X + size[0] + padding_left + padding_right > _MaxWidth) + { + _X = 0; + _Y += _LineHeight; + _LineHeight = 0; + } + + rect toAdd = .(); + toAdd.name = name; + toAdd.width = size[0]; + toAdd.height = size[1]; + toAdd.x = _X + padding_left; + toAdd.y = _Y + padding_top; + _Drawings.Add(toAdd); + + _X += size[0] + padding_left + padding_right; + if(size[1] + padding_top + padding_bottom > _LineHeight) + _LineHeight = size[1] + padding_top + padding_bottom; + + } + } +} \ No newline at end of file diff --git a/src/Core/Structs/color.bf b/src/Core/Structs/color.bf new file mode 100644 index 0000000..6094c69 --- /dev/null +++ b/src/Core/Structs/color.bf @@ -0,0 +1,38 @@ +namespace TheaterGui.Core.Structs; + + +struct color +{ + public uint8 Red = 0; + public uint8 Green = 0; + public uint8 Blue = 0; + public uint8 Alpha = 255; + + public this() + { + + } + + public this(uint8 red, uint8 green, uint8 blue, uint8 alpha = 255) + { + Red = red; + Green = green; + Blue = blue; + Alpha = alpha; + } + + public this(uint8[3] data) + { + Red = data[0]; + Green = data[1]; + Blue = data[2]; + } + + public this(uint8[4] data) + { + Red = data[0]; + Green = data[1]; + Blue = data[2]; + Alpha = data[3]; + } +} \ No newline at end of file diff --git a/src/Core/Structs/colorScheme.bf b/src/Core/Structs/colorScheme.bf new file mode 100644 index 0000000..4d3b808 --- /dev/null +++ b/src/Core/Structs/colorScheme.bf @@ -0,0 +1,16 @@ +namespace TheaterGui.Core.Structs; + +struct colorScheme +{ + public color TextColor = .(216, 197, 215); + public color BackgroundColor = .(45, 45, 49); + public color PrimaryColor = .(153, 36, 72); + public color AcceptColor = .(); + public color WarningColor = .(); + public color ErrorColor = .(); + public color DisabledColor = .(90, 90, 90, 125); + public color HoverColor = .(255, 255, 255, 50); + + + public static colorScheme DefaultScheme = .(); +} \ No newline at end of file diff --git a/src/Core/Structs/rect.bf b/src/Core/Structs/rect.bf new file mode 100644 index 0000000..de68f27 --- /dev/null +++ b/src/Core/Structs/rect.bf @@ -0,0 +1,23 @@ +namespace TheaterGui.Core.Structs; + +using System; + +struct rect +{ + public StringView name; + public int32 x = 0; + public int32 y = 0; + public int32 width; + public int32 height; + + public static rect operator+(rect lhs, rect rhs) + { + rect toReturn = .(); + toReturn.name = lhs.name; + toReturn.x = rhs.x + lhs.x; + toReturn.y = rhs.y + lhs.y; + toReturn.width = lhs.width; + toReturn.height = lhs.height; + return toReturn; + } +} \ No newline at end of file diff --git a/src/Core/Structs/theme.bf b/src/Core/Structs/theme.bf new file mode 100644 index 0000000..6e00e8d --- /dev/null +++ b/src/Core/Structs/theme.bf @@ -0,0 +1,25 @@ +namespace TheaterGui.Core.Structs; + +using System; + +struct theme +{ + private static uint8[?] _Theme_Font = Compiler.ReadBinary("assets/Din.ttf"); + private static uint8[?] _Theme_Button = Compiler.ReadBinary("assets/button.png"); + + /* + private static uint8[?] Texture_SquareButton = Compiler.ReadBinary("assets/square_button.png"); + private static uint8[?] Texture_LargeButton = Compiler.ReadBinary("assets/large_button.png"); + private static uint8[?] Texture_NButton = Compiler.ReadBinary("assets/n_button.png"); + private static uint8[?] Texture_Checkbox = Compiler.ReadBinary("assets/checkbox.png"); + private static uint8[?] Texture_Checkbox_Checked = Compiler.ReadBinary("assets/checkbox_checked.png"); + private static uint8[?] Horizontal_Patch = Compiler.ReadBinary("assets/horizontal_patch.png"); + private static uint8[?] Dropdown = Compiler.ReadBinary("assets/dropdown.png"); + */ + + public (Span, uint8) Font_Normal = ( + .(&_Theme_Font, _Theme_Font.Count), + 16 + ); + public Span Button = .(&_Theme_Button, _Theme_Button.Count); +} \ No newline at end of file diff --git a/src/Core/TGRuntime.api.bf b/src/Core/TGRuntime.api.bf new file mode 100644 index 0000000..d3e19b3 --- /dev/null +++ b/src/Core/TGRuntime.api.bf @@ -0,0 +1,40 @@ +namespace TheaterGui.Core; +using TheaterGui.Components; +using TheaterGui.Core.Structs; + +using System; +using System.Collections; + +extension TGRuntime +{ + public theme Theme; + public colorScheme Scheme;; + + private List _Screens = new .() ~ DeleteContainerAndItems!(_); + + private bool _ShouldClose = false; + public bool ShouldClose + { + get => _ShouldClose; + set + { + if(value) + _ShouldClose = value; + } + } + + public IPlatformLayer Platform + { + get; + private set; + } + + private bool _Dirty = true; + public void Dirty() => _Dirty = true; + + public int32[2] ScreenSize + { + get; + private set; + } +} \ No newline at end of file diff --git a/src/Core/TGRuntime.core.bf b/src/Core/TGRuntime.core.bf new file mode 100644 index 0000000..8da4a31 --- /dev/null +++ b/src/Core/TGRuntime.core.bf @@ -0,0 +1,67 @@ +namespace TheaterGui.Core; +using TheaterGui.Core.Structs; +using TheaterGui.Components; + +using System; + +class TGRuntime +{ + private void Launch(IPlatformLayer platform, Container screen, StringView name, int32 width, int32 height, colorScheme scheme, theme theme) + { + Platform = platform; + Platform.Initialize(name, width, height); + LoadTextures(theme, scheme); + Theme = theme; + Scheme = scheme; + + _Screens.Add(screen); + for(var i in _Screens) + i.Resize(this, width); +#if BF_PLATFORM_WASM + WebAssembly.emscripten_set_main_loop(=> ProcessFrame, 60, 1); +#else + while (!ShouldClose) + ProcessFrame(); +#endif + platform.Deinitialize(); + } + + private void ProcessFrame() + { + //Meta + ShouldClose = Platform.ShouldClose(); + var ss = Platform.ScreenSize(); + if(ss != ScreenSize) + { //Resultion update + Dirty(); + for(var i in _Screens) + i.Resize(this, ss[0]); + ScreenSize = ss; + } + var mPos = Platform.MousePosition(); + _Screens[0].OnHover(this, .((.)mPos[0], (.)mPos[1])); + + + //Logic + for(var screen in _Screens) + screen.Update(this); + //Drawing + if(_Dirty) + { + Platform.StartDrawing(); + for(var screen in _Screens) + screen.Draw(this, .() {width = ScreenSize[0], height = ScreenSize[1] }); + Platform.StopDrawing(); + _Dirty = false; + } + else + Platform.RedrawLastFrame(); + } + + private void LoadTextures(theme pStartingTheme, colorScheme pScheme) + { + Platform.ChangeBackgroundColor(pScheme.BackgroundColor); + Platform.LoadFont(pStartingTheme.Font_Normal.0, "Font_Normal", pStartingTheme.Font_Normal.1); + Platform.LoadTexture(pStartingTheme.Button, "Button"); + } +} \ No newline at end of file diff --git a/src/Extensions.bf b/src/Extensions.bf deleted file mode 100644 index 67fd0fc..0000000 --- a/src/Extensions.bf +++ /dev/null @@ -1,53 +0,0 @@ -namespace RaylibBeef -{ - extension Rectangle - { - public bool Overlaps(int32 x, int32 y) - { - if (x >= this.x && x <= this.x + this.width) - if (y >= this.y && y <= this.y + this.height) - return true; - return false; - } - } - - extension Color - { - public Color SetRed(uint8 red) => .(red, g, b, a); - public Color SetGreen(uint8 green) => .(r, green, b, a); - public Color SetBlue(uint8 blue) => .(r, g, blue, a); - public Color SetAlpha(uint8 alpha) => .(r, g, b, alpha); - } -} - -namespace System -{ - using System.Reflection; - - [AttributeUsage(.Field)] - struct DynamicStringAttribute : Attribute, IOnFieldInit - { - [Comptime] - public void OnFieldInit(FieldInfo fieldInfo, Self* prev) - { - Compiler.EmitTypeBody(fieldInfo.DeclaringType, scope $""" - public StringView {fieldInfo.Name.Substring(1)} - {{ - public get => {fieldInfo.Name} == null ? "" : {fieldInfo.Name}..EnsureNullTerminator(); - public set => String.NewOrSet!({fieldInfo.Name}, value); - }}; - """); - } - } -} - -namespace System -{ -#if BF_PLATFORM_WASM - extension WebAssembly - { - [CLink, CallingConvention(.Stdcall)] - public static extern void emscripten_set_main_loop(function void() func, int32 fps, int32 simulateInfinteLoop); - } -#endif -} \ No newline at end of file diff --git a/src/Generators/ButtonGenerator.bf b/src/Generators/ButtonGenerator.bf deleted file mode 100644 index a4e7541..0000000 --- a/src/Generators/ButtonGenerator.bf +++ /dev/null @@ -1,48 +0,0 @@ -namespace TheaterGui.Generators; - -using System; - -class ButtonGenerator : Compiler.Generator -{ - public override String Name => "TheaterGui -> Button" - - public override void InitUI() - { - AddEdit("name", "Button Name", ""); - AddCheckbox("enabled", "Enabled", true); - AddEdit("description", "Description", ""); - } - - public override void Generate(String outFileName, String outText, ref Flags generateFlags) - { - var name = mParams["name"]; - if (name.EndsWith(".bf", .OrdinalIgnoreCase)) - name.RemoveFromEnd(3); - - var enabled = bool.Parse(mParams["enabled"]); - var description = mParams["description"]; - - outFileName.Append(scope $"{name}"); - - outText.Append(scope $""" - namespace {Namespace}; - - using TheaterGui.Components; - - class {name} : Button - {{ - public this() : base("{name}") - {{ - {!enabled ? "Enabled = false;" : ""} - Description = "{description}"; - }} - - //What happens when the button is clicked - public override void ClickAction() - {{ - - }} - }} - """); - } -} \ No newline at end of file diff --git a/src/Generators/CheckboxGenerator.bf b/src/Generators/CheckboxGenerator.bf deleted file mode 100644 index 92c173b..0000000 --- a/src/Generators/CheckboxGenerator.bf +++ /dev/null @@ -1,48 +0,0 @@ -namespace TheaterGui.Generators; - -using System; - -class CheckboxGenerator : Compiler.Generator -{ - public override String Name => "TheaterGui -> Checkbox" - - public override void InitUI() - { - AddEdit("name", "Checkbox Name", ""); - AddCheckbox("enabled", "Enabled", true); - AddEdit("description", "Description", ""); - } - - public override void Generate(String outFileName, String outText, ref Flags generateFlags) - { - var name = mParams["name"]; - if (name.EndsWith(".bf", .OrdinalIgnoreCase)) - name.RemoveFromEnd(3); - - var enabled = bool.Parse(mParams["enabled"]); - var description = mParams["description"]; - - outFileName.Append(scope $"{name}"); - - outText.Append(scope $""" - namespace {Namespace}; - - using TheaterGui.Components; - - class {name} : Checkbox - {{ - public this() : base("{name}") - {{ - {!enabled ? "Enabled = false;" : ""} - Description = "{description}"; - }} - - //What happens when the button is clicked - public override void OnCheck(bool checkValue) - {{ - - }} - }} - """); - } -} \ No newline at end of file diff --git a/src/Generators/ContainerGenerator.bf b/src/Generators/ContainerGenerator.bf deleted file mode 100644 index f62d444..0000000 --- a/src/Generators/ContainerGenerator.bf +++ /dev/null @@ -1,37 +0,0 @@ -namespace TheaterGui.Generators; - -using System; - -class ContainerGenerator : Compiler.Generator -{ - public override String Name => "TheaterGui -> Container" - - public override void InitUI() - { - AddEdit("name", "Container Name", ""); - } - - public override void Generate(String outFileName, String outText, ref Flags generateFlags) - { - var name = mParams["name"]; - if (name.EndsWith(".bf", .OrdinalIgnoreCase)) - name.RemoveFromEnd(3); - - outFileName.Append(scope $"{name}"); - - outText.Append(scope $""" - namespace {Namespace}; - - using TheaterGui.Components; - - class {name} : Container - {{ - public this() : base("{name}") - {{ - //Add ui items here via AddChild() and terminate the row via EndRow() - Margin = 5; - }} - }} - """); - } -} \ No newline at end of file diff --git a/src/Generators/DropdownGenerator.bf b/src/Generators/DropdownGenerator.bf deleted file mode 100644 index 5d88842..0000000 --- a/src/Generators/DropdownGenerator.bf +++ /dev/null @@ -1,54 +0,0 @@ -namespace TheaterGui.Generators; - -using System; - -class DropdownGenerator : Compiler.Generator -{ - public override String Name => "TheaterGui -> Dropdown" - - public override void InitUI() - { - AddEdit("name", "Button Name", ""); - AddEdit("description", "Description", ""); - AddEdit("content", "Entries", "Seperate entries via ';'"); - } - - public override void Generate(String outFileName, String outText, ref Flags generateFlags) - { - var name = mParams["name"]; - if (name.EndsWith(".bf", .OrdinalIgnoreCase)) - name.RemoveFromEnd(3); - - var description = mParams["description"]; - var entries = mParams["content"]; - - - outFileName.Append(scope $"{name}"); - - outText.Append(scope $""" - namespace {Namespace}; - - using TheaterGui.Components; - using System; - - class TG{name} : Dropdown - {{ - public this() : base() - {{ - Description = "{description}"; - """); - var split = entries.Split(';'); - for(var i in split) - outText.Append(scope $"\t\tEntries.Add(new .(\"{i}\"));\n"); - outText.Append(scope $""" - }} - - //What happens when the button is clicked - public override void ClickAction(String newValue) - {{ - - }} - }} - """); - } -} \ No newline at end of file diff --git a/src/Generators/IconButtonGenerator.bf b/src/Generators/IconButtonGenerator.bf deleted file mode 100644 index 2219c07..0000000 --- a/src/Generators/IconButtonGenerator.bf +++ /dev/null @@ -1,49 +0,0 @@ -namespace TheaterGui.Generators; - -using System; - -class IconButtonGenerator : Compiler.Generator -{ - public override String Name => "TheaterGui -> Icon Button" - - public override void InitUI() - { - AddEdit("name", "Button Name", ""); - AddCheckbox("enabled", "Enabled", true); - AddEdit("description", "Description", ""); - } - - public override void Generate(String outFileName, String outText, ref Flags generateFlags) - { - var name = mParams["name"]; - if (name.EndsWith(".bf", .OrdinalIgnoreCase)) - name.RemoveFromEnd(3); - - var enabled = bool.Parse(mParams["enabled"]); - var description = mParams["description"]; - - outFileName.Append(scope $"{name}"); - - outText.Append(scope $""" - namespace {Namespace}; - - using TheaterGui.Components; - - class {name} : IconButton - {{ - public this() : base("{name}") - {{ - Icon = .Icon_Folder; //Use this to set the icon sprite - {!enabled ? "Enabled = false;" : ""} - Description = "{description}"; - }} - - //What happens when the button is clicked - public override void ClickAction() - {{ - - }} - }} - """); - } -} \ No newline at end of file diff --git a/src/Generators/LargeButtonGenerator.bf b/src/Generators/LargeButtonGenerator.bf deleted file mode 100644 index 29b4c6b..0000000 --- a/src/Generators/LargeButtonGenerator.bf +++ /dev/null @@ -1,48 +0,0 @@ -namespace TheaterGui.Generators; - -using System; - -class LargeButtonGenerator : Compiler.Generator -{ - public override String Name => "TheaterGui -> Large Button" - - public override void InitUI() - { - AddEdit("name", "Button Name", ""); - AddCheckbox("enabled", "Enabled", true); - AddEdit("description", "Description", ""); - } - - public override void Generate(String outFileName, String outText, ref Flags generateFlags) - { - var name = mParams["name"]; - if (name.EndsWith(".bf", .OrdinalIgnoreCase)) - name.RemoveFromEnd(3); - - var enabled = bool.Parse(mParams["enabled"]); - var description = mParams["description"]; - - outFileName.Append(scope $"{name}"); - - outText.Append(scope $""" - namespace {Namespace}; - - using TheaterGui.Components; - - class {name} : LargeButton - {{ - public this() : base("{name}") - {{ - {!enabled ? "Enabled = false;" : ""} - Description = "{description}"; - }} - - //What happens when the button is clicked - public override void ClickAction() - {{ - - }} - }} - """); - } -} \ No newline at end of file diff --git a/src/Generators/NButtonGenerator.bf b/src/Generators/NButtonGenerator.bf deleted file mode 100644 index d1e0141..0000000 --- a/src/Generators/NButtonGenerator.bf +++ /dev/null @@ -1,48 +0,0 @@ -namespace TheaterGui.Generators; - -using System; - -class NButtonGenerator : Compiler.Generator -{ - public override String Name => "TheaterGui -> NButton" - - public override void InitUI() - { - AddEdit("name", "Button Name", ""); - AddCheckbox("enabled", "Enabled", true); - AddEdit("description", "Description", ""); - } - - public override void Generate(String outFileName, String outText, ref Flags generateFlags) - { - var name = mParams["name"]; - if (name.EndsWith(".bf", .OrdinalIgnoreCase)) - name.RemoveFromEnd(3); - - var enabled = bool.Parse(mParams["enabled"]); - var description = mParams["description"]; - - outFileName.Append(scope $"{name}"); - - outText.Append(scope $""" - namespace {Namespace}; - - using TheaterGui.Components; - - class {name} : NButton - {{ - public this() : base("{name}") - {{ - {!enabled ? "Enabled = false;" : ""} - Description = "{description}"; - }} - - //What happens when the button is clicked - public override void ClickAction() - {{ - - }} - }} - """); - } -} \ No newline at end of file diff --git a/src/Generators/RadioButtonGenerator.bf b/src/Generators/RadioButtonGenerator.bf deleted file mode 100644 index ab19139..0000000 --- a/src/Generators/RadioButtonGenerator.bf +++ /dev/null @@ -1,48 +0,0 @@ -namespace TheaterGui.Generators; - -using System; - -class RadioButtonGenerator : Compiler.Generator -{ - public override String Name => "TheaterGui -> Radio Button" - - public override void InitUI() - { - AddEdit("name", "Component Name", ""); - AddCheckbox("enabled", "Enabled", true); - AddEdit("description", "Description", ""); - } - - public override void Generate(String outFileName, String outText, ref Flags generateFlags) - { - var name = mParams["name"]; - if (name.EndsWith(".bf", .OrdinalIgnoreCase)) - name.RemoveFromEnd(3); - - var enabled = bool.Parse(mParams["enabled"]); - var description = mParams["description"]; - - outFileName.Append(scope $"{name}"); - - outText.Append(scope $""" - namespace {Namespace}; - - using TheaterGui.Components; - - class {name} : RadioButton - {{ - public this() : base("{name}") - {{ - {!enabled ? "Enabled = false;" : ""} - Description = "{description}"; - //Use SetBoxes(int, params StringView) to set the elements of the radio buttons - }} - - //React to the check event, or use the Checked field to get the value directly - public override void OnCheck(int32 value) - {{ - }} - }} - """); - } -} \ No newline at end of file diff --git a/src/Generators/ScreenGenerator.bf b/src/Generators/ScreenGenerator.bf deleted file mode 100644 index 9c9c4c3..0000000 --- a/src/Generators/ScreenGenerator.bf +++ /dev/null @@ -1,36 +0,0 @@ -namespace TheaterGui.Generators; - -using System; - -class ScreenGenerator : Compiler.Generator -{ - public override String Name => "TheaterGui -> Screen" - - public override void InitUI() - { - AddEdit("name", "Screen Name", ""); - } - - public override void Generate(String outFileName, String outText, ref Flags generateFlags) - { - var name = mParams["name"]; - if (name.EndsWith(".bf", .OrdinalIgnoreCase)) - name.RemoveFromEnd(3); - - outFileName.Append(scope $"{name}"); - - outText.Append(scope $""" - namespace {Namespace}; - - using TheaterGui.Components; - - class {name} : Screen - {{ - public this() : base("{name}") - {{ - //Add UI items here via AddChild() and terminate the row via EndRow() - }} - }} - """); - } -} \ No newline at end of file diff --git a/src/Generators/SliderGenerator.bf b/src/Generators/SliderGenerator.bf deleted file mode 100644 index 1ab378b..0000000 --- a/src/Generators/SliderGenerator.bf +++ /dev/null @@ -1,57 +0,0 @@ -namespace TheaterGui.Generators; - -using System; - -class SliderGenerator : Compiler.Generator -{ - public override String Name => "TheaterGui -> Slider" - - public override void InitUI() - { - AddEdit("name", "Slider Name", ""); - AddCombo("orientation", "Orientation", "Horizontal", .(scope StringView[]("Horizontal", "Vertical"))); - AddCheckbox("length", "Fixed Length", true); - AddEdit("min", "Minimal Value", "0"); - AddEdit("max", "Maximal Value", "100"); - AddEdit("dfault", "Starting Value", "50"); - } - - public override void Generate(String outFileName, String outText, ref Flags generateFlags) - { - var name = mParams["name"]; - if (name.EndsWith(".bf", .OrdinalIgnoreCase)) - name.RemoveFromEnd(3); - - var orientation = mParams["orientation"]; - var fixedLength = mParams["length"]; - var min = mParams["min"]; - var max = mParams["max"]; - var dfault = mParams["dfault"]; - - - outFileName.Append(scope $"{name}"); - - outText.Append(scope $""" - namespace {Namespace}; - - using TheaterGui.Components; - - class {name} : {(fixedLength == "True") ? "" : "N" }{(orientation == "Horizontal") ? "H" : "V"}Slider - {{ - public this() : base({(fixedLength == "True") ? "" : "64, "}"{name}") - {{ - //Use the thing above to set the length of the bar - Min = {min}; - Max = {max}; - Value = {dfault}; - ReactToValueChange = true; //This indicates wether OnValueChange gets actually called - }} - - public override void OnValueChange(float newVal) - {{ - - }} - }} - """); - } -} \ No newline at end of file diff --git a/src/Generators/ToolbarGenerator.bf b/src/Generators/ToolbarGenerator.bf deleted file mode 100644 index d0c2906..0000000 --- a/src/Generators/ToolbarGenerator.bf +++ /dev/null @@ -1,44 +0,0 @@ -namespace TheaterGui.Generators; - -using System; - -class ToolbarGenerator : Compiler.Generator -{ - public override String Name => "TheaterGui -> Toolbar" - - public override void InitUI() - { - AddEdit("name", "Toolbar Name", ""); - } - - public override void Generate(String outFileName, String outText, ref Flags generateFlags) - { - var name = mParams["name"]; - if (name.EndsWith(".bf", .OrdinalIgnoreCase)) - name.RemoveFromEnd(3); - - - outFileName.Append(scope $"{name}"); - - outText.Append(scope $""" - namespace {Namespace}; - - using TheaterGui.Components; - - class {name} : Toolbar - {{ - public this() : base("{name}") - {{ - - /* - AddToolbarCategories( - new .("File", - new .("Open Recent", null) - ) - ); - */ - }} - }} - """); - } -} \ No newline at end of file diff --git a/src/IPlatformLayer.bf b/src/IPlatformLayer.bf new file mode 100644 index 0000000..31eb5ff --- /dev/null +++ b/src/IPlatformLayer.bf @@ -0,0 +1,43 @@ +namespace TheaterGui; +using TheaterGui.Core.Structs; + +using System; + +interface IPlatformLayer +{ + public void Initialize(StringView pWindowTitle, int32 pWidth, int32 pHeight); + public void Deinitialize(); + + + //Drawing + public void StartDrawing(); + public void StopDrawing(); + public void RedrawLastFrame(); + + public void ChangeBackgroundColor(color pTint); + + public void LoadTexture(Span pData, StringView pName); + public void DrawTexture(StringView pName, rect pTarget, color pTint); + public int32[2] MeasureTextureSize(StringView pName); + + public void DrawColorRect(rect pTarget, color pTint); + public void DrawColorRectOutlined(rect pTarget, color pTint, color pOutlineTint); + + + ///Text + public void LoadFont(Span pData, StringView pName, uint8 pFontSize); + public void DrawText(StringView pText, StringView pFont, int32[2] pPosition, color pTint); + public int32[2] MeasureTextSize(StringView pText, StringView pFont); + + + ///Input + public bool ShouldClose(); + + public int32[2] ScreenSize(); + + public float[2] MousePosition(); + public float[2] MouseDelta(); + public bool MouseLeftClick(); + public bool MouseRightClick(); + public float MouseWheel(); +} \ No newline at end of file diff --git a/src/Input.bf b/src/Input.bf deleted file mode 100644 index ceed82f..0000000 --- a/src/Input.bf +++ /dev/null @@ -1,122 +0,0 @@ -namespace TheaterGui; - -using System; - -using RaylibBeef; - -using TheaterGui.Components; - -class Input -{ - internal static void HandleScrolling(float pWheelMove) - { - var w = pWheelMove * pWheelMove * pWheelMove; - - if (!App.CurrentScreen.HandleScrollEvent(w, (.)App.Mouse.x, (.)(App.Mouse.y - App.Wheel)) && App.CurrentScreen.Height - App.Height > 0) - { - App.Wheel += w; - App.Wheel = Math.Clamp(App.Wheel, -1 * (App.CurrentScreen.Height - App.Height), 0); - } - } - - internal static void HandleLeftClick() - { - var mouse = App.Mouse; - - if (App.GetTopmostPopup() case .Ok(let top)) - { - if (Rectangle(top.X, top.Y, top.Width, top.Height).Overlaps((.)mouse.x, (.)(mouse.y - App.Wheel))) - { - if (top.OnClick((.)mouse.x, (.)mouse.y)) - return; - - - App.[Friend]_Popups.Remove(top); - top.OnClose(); //Any last words ? - delete top; - } - else - { - bool a = top is DropdownPopup; //TODO: Make this less horrible - - App.[Friend]_Popups.Remove(top); - top.OnClose(); //Any last words ? - delete top; - if(!a) - App.CurrentScreen.OnClick((.)mouse.x, (.)(mouse.y - App.Wheel)); //So that we dont eat any inputs - } - } - else - App.CurrentScreen.OnClick((.)mouse.x, (.)(mouse.y - App.Wheel)); - } - - internal static void HandleRightClick() - { - //We dont stack up rightclicks - if (App.GetTopmostPopup() case .Ok(let top)) - if (top is RightClickPopup) - delete App.[Friend]_Popups.GetAndRemove(top).Value; - - Toolbar.ToolbarCategory popupCat = new .("Items"); - App.CurrentScreen.OnRightClick((.)App.Mouse.x, (.)App.Mouse.y, popupCat); - if (popupCat.Items.Count > 0) - App.[Friend]_Popups.Add(new RightClickPopup((.)App.Mouse.x, (.)App.Mouse.y, popupCat)); - else - delete popupCat; - } - - internal static bool HandleLeftDown() - { - //Topmost first - for (var i in App.[Friend]_Popups.Reversed) - { - var hoverResult = i.OnDown(Raylib.GetMouseX(), Raylib.GetMouseY() - (.)App.Wheel); - if (hoverResult == false) - continue; - return hoverResult; - } - return App.CurrentScreen.OnDown(Raylib.GetMouseX(), (.)(Raylib.GetMouseY() - App.Wheel)); - } - - internal static void HandleHover() - { - Component hoverRes = HandleHoverPopups(); - if (hoverRes == null) - hoverRes = HandleHoverScreen(); - - if (hoverRes == null) - Raylib.SetMouseCursor((.)MouseCursor.MOUSE_CURSOR_DEFAULT); - else - { - if (hoverRes.Enabled) - Raylib.SetMouseCursor((.)MouseCursor.MOUSE_CURSOR_POINTING_HAND); - - if (App.[Friend]_OldPos != App.Mouse) - App.[Friend]_MovTime = Raylib.GetTime(); - if (Raylib.GetTime() - App.[Friend]_MovTime >= 0.5) - App.[Friend]_HoverText.Append(hoverRes.Description); - App.[Friend]_OldPos = App.Mouse; - } - } - - ///Handle the hover effect for all screen objects - private static Component HandleHoverScreen() - { - return App.CurrentScreen.OnHover(Raylib.GetMouseX(), (.)(Raylib.GetMouseY() - App.Wheel)); - } - - - ///Checks if any popup catches the hover - private static Component HandleHoverPopups() - { - //Topmost first - for (var i in App.[Friend]_Popups.Reversed) - { - var hoverResult = i.OnHover(Raylib.GetMouseX(), Raylib.GetMouseY() - (.)App.Wheel); - if (hoverResult == null) - continue; - return hoverResult; - } - return null; - } -} \ No newline at end of file diff --git a/src/PlatformLayer.bf b/src/PlatformLayer.bf deleted file mode 100644 index 9680f25..0000000 --- a/src/PlatformLayer.bf +++ /dev/null @@ -1,21 +0,0 @@ -namespace TheaterGui; - -//Which backend does theatergui use -#define BACKEND_RAYLIB - - - -#if BACKEND_RAYLIB -using RaylibBeef; -#endif - -class PlatformLayer -{ - /// - public static void DrawSprite() - { - - } -} - -//TODO: Actually implement this \ No newline at end of file diff --git a/src/Theme.bf b/src/Theme.bf deleted file mode 100644 index efe7e37..0000000 --- a/src/Theme.bf +++ /dev/null @@ -1,41 +0,0 @@ -namespace TheaterGui; - -using System; -using RaylibBeef; - -public class Theme -{ - public static Font Font ~ Raylib.UnloadFont(_); - public static Font FontSmall ~ Raylib.UnloadFont(_); - public static Font FontLarge ~ Raylib.UnloadFont(_); - - public static int32 FontSize = 16; - public static int32 FontSizeLarge = 20; - public static int32 FontSizeSmall = 12; - - public static Color Background = .(45, 45, 49, 255); - public static Color Tint = .(153, 36, 72, 255); - public static Color HoverTint = .(255,255,255,50); //Color overlay when an object is hovered over - public static Color DisabledTint = .(90,90,90,125); - public static Color Text = .(216, 197, 215, 255); - - //Font data - public static uint8[?] Din = Compiler.ReadBinary("assets/Din.ttf"); - - public static uint8[?] Texture_WindowIcon = Compiler.ReadBinary("assets/64.png"); - //Icons - public static uint8[?] Texture_TheaterIcon = Compiler.ReadBinary("assets/icon_theater.png"); - public static uint8[?] Texture_FolderIcon = Compiler.ReadBinary("assets/icon_folder.png"); - - //Controls - public static uint8[?] Texture_SquareButton = Compiler.ReadBinary("assets/square_button.png"); - public static uint8[?] Texture_LargeButton = Compiler.ReadBinary("assets/large_button.png"); - public static uint8[?] Texture_NButton = Compiler.ReadBinary("assets/n_button.png"); - public static uint8[?] Texture_Button = Compiler.ReadBinary("assets/button.png"); - public static uint8[?] Texture_Checkbox = Compiler.ReadBinary("assets/checkbox.png"); - public static uint8[?] Texture_Checkbox_Checked = Compiler.ReadBinary("assets/checkbox_checked.png"); - public static uint8[?] Horizontal_Patch = Compiler.ReadBinary("assets/horizontal_patch.png"); - public static uint8[?] Dropdown = Compiler.ReadBinary("assets/dropdown.png"); - -} - diff --git a/src/WASM.bf b/src/WASM.bf new file mode 100644 index 0000000..aa9a813 --- /dev/null +++ b/src/WASM.bf @@ -0,0 +1,10 @@ +namespace System +{ +#if BF_PLATFORM_WASM + extension WebAssembly + { + [CLink, CallingConvention(.Stdcall)] + public static extern void emscripten_set_main_loop(function void() func, int32 fps, int32 simulateInfinteLoop); + } +#endif +} \ No newline at end of file From 46ea31a1181d73c84fdb9b30a3fcedd25e843d50 Mon Sep 17 00:00:00 2001 From: Booklordofthedings Date: Thu, 10 Oct 2024 14:53:21 +0200 Subject: [PATCH 3/6] Fixed some stuff, added basic popups and more --- BeefSpace.toml | 3 + examples/src/Program.bf | 80 ++++++++- raylib-backend/src/Platform_Raylib/Drawing.bf | 39 +++++ src/App.bf | 2 +- src/Components/Button.bf | 19 ++- src/Components/Component.bf | 6 + src/Components/Container.bf | 43 +++++ src/Components/Internal/ClickableText.bf | 90 ++++++++++ src/Components/Popup.bf | 154 ++++++++++++++++++ src/Components/Screen.bf | 64 ++++++++ src/Components/Toolbar.bf | 141 ++++++++++++++++ src/Core/Layout.bf | 2 +- src/Core/TGRuntime.api.bf | 28 +++- src/Core/TGRuntime.core.bf | 103 ++++++++++-- 14 files changed, 750 insertions(+), 24 deletions(-) create mode 100644 src/Components/Internal/ClickableText.bf create mode 100644 src/Components/Popup.bf create mode 100644 src/Components/Screen.bf create mode 100644 src/Components/Toolbar.bf diff --git a/BeefSpace.toml b/BeefSpace.toml index 8c33a2f..f5589ee 100644 --- a/BeefSpace.toml +++ b/BeefSpace.toml @@ -3,3 +3,6 @@ Projects = {TheaterGui = {Path = "."}, examples = {Path = "examples"}, Bofa = {P [Workspace] StartupProject = "examples" + +[Configs.Debug.Win64] +ConfigSelections = {raylib-beef = {Config = "StaticDebug"}} diff --git a/examples/src/Program.bf b/examples/src/Program.bf index 8cc6767..7b9bb81 100644 --- a/examples/src/Program.bf +++ b/examples/src/Program.bf @@ -1,8 +1,11 @@ namespace examples; +using System; + using TheaterGui; using TheaterGui.Core; using TheaterGui.Components; +using TheaterGui.Components.Internal; class Program { @@ -16,18 +19,83 @@ class Program } } -class MainScreen : Container +class MainScreen : Screen { public this() { - AddChild("Main Button", new Button()); - AddChild("Other Button", new Button()); + Toolbar toAdd = new .(); + toAdd.AddEntry("File", "Open File", new (rt) => {Console.WriteLine("Open file");}); + toAdd.AddEntry("Edit", "Go back", new (rt) => {Console.WriteLine("Go back");}); + toAdd.AddEntry("Edit", "Open File", new (rt) => {Console.WriteLine("Open File");}); + toAdd.AddEntry("Window", "Open File", new (rt) => {Console.WriteLine("Open File");}); + + + + + AddChild("Toolbar", toAdd); + AddChild("Button", new Button(new (val) => {Console.WriteLine("Hellau :)");})); + - Layout = new (val, width) => { - val.Component("Main Button", 5); - val.Component("Other Button", 10); + val.Component("Toolbar"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + val.Component("Button"); + + }; } } diff --git a/raylib-backend/src/Platform_Raylib/Drawing.bf b/raylib-backend/src/Platform_Raylib/Drawing.bf index 8dede2b..b633a7e 100644 --- a/raylib-backend/src/Platform_Raylib/Drawing.bf +++ b/raylib-backend/src/Platform_Raylib/Drawing.bf @@ -11,6 +11,23 @@ extension PlatformRaylib { public void StartDrawing() { + if(Raylib.GetMouseDelta().x + Raylib.GetMouseDelta().y != 0) + { + if(targetFps != 40) + { + Raylib.SetTargetFPS(40); + targetFps = 40; + } + } + else + { + if(targetFps != 20) + { + Raylib.SetTargetFPS(20); + targetFps = 20; + } + } + Raylib.BeginDrawing(); Raylib.ClearBackground(_BackgroundColor); Raylib.BeginTextureMode(_ScreenTexture); @@ -31,8 +48,27 @@ extension PlatformRaylib Raylib.EndDrawing(); } + private int32 targetFps = 40; + public void RedrawLastFrame() { + if(Raylib.GetMouseDelta().x + Raylib.GetMouseDelta().y != 0) + { + if(targetFps != 40) + { + Raylib.SetTargetFPS(40); + targetFps = 40; + } + } + else + { + if(targetFps != 20) + { + Raylib.SetTargetFPS(20); + targetFps = 20; + } + } + Raylib.BeginDrawing(); Raylib.ClearBackground(_BackgroundColor); Raylib.DrawTexturePro( @@ -43,6 +79,9 @@ extension PlatformRaylib 0, Raylib.WHITE ); +#if DEBUG + Raylib.DrawRectangle(0,0,5,5, Raylib.PINK); +#endif Raylib.EndDrawing(); } diff --git a/src/App.bf b/src/App.bf index 8aae9d8..b80487e 100644 --- a/src/App.bf +++ b/src/App.bf @@ -13,7 +13,7 @@ class App private colorScheme _Scheme = .DefaultScheme; private theme _Theme = .(); - public Result Run(Container pScreen) + public Result Run(Screen pScreen) { if(_Platform == null) return .Err; diff --git a/src/Components/Button.bf b/src/Components/Button.bf index 45fc5d2..4dc5622 100644 --- a/src/Components/Button.bf +++ b/src/Components/Button.bf @@ -10,9 +10,11 @@ class Button : Component private bool _AlreadyHovered = false; public String Label ~ delete _; + delegate void(TGRuntime rt) Action ~ delete _; - public this(StringView pName = "Button") + public this(delegate void(TGRuntime rt) pToCall, StringView pName = "Button") { + Action = pToCall; Label = new .(pName); } @@ -43,9 +45,24 @@ class Button : Component { return rt.Platform.MeasureTextureSize("Button"); } + public override bool OnHover(TGRuntime rt, int32[2] mPos) { _AlreadyHovered = true; return true; } + + public override bool OnLeftClick(TGRuntime rt, int32[2] mPos) + { + Action.Invoke(rt); + return true; + } + + public override bool OnScroll(TGRuntime rt, float pOffset) => false; + + public override bool OnRightClick(TGRuntime rt, int32[2] mPos, System.Collections.List<(String, delegate void(TGRuntime))> pList) + { + pList.Add((.)(new String(scope $"Click {Label}"), new (rt) => {this.Action.Invoke(rt);})); + return true; + } } \ No newline at end of file diff --git a/src/Components/Component.bf b/src/Components/Component.bf index e829bc8..fcfc555 100644 --- a/src/Components/Component.bf +++ b/src/Components/Component.bf @@ -2,10 +2,16 @@ namespace TheaterGui.Components; using TheaterGui.Core; using TheaterGui.Core.Structs; +using System; +using System.Collections; + abstract class Component { public abstract void Update(TGRuntime rt); public abstract void Draw(TGRuntime rt, rect rect); public abstract int32[2] Resize(TGRuntime rt, int32 width); public abstract bool OnHover(TGRuntime rt, int32[2] mPos); + public abstract bool OnLeftClick(TGRuntime rt, int32[2] mPos); + public abstract bool OnScroll(TGRuntime rt, float pOffset); + public abstract bool OnRightClick(TGRuntime rt, int32[2] mPos, List<(String, delegate void(TGRuntime))> pList); } \ No newline at end of file diff --git a/src/Components/Container.bf b/src/Components/Container.bf index 15bd64d..9b7d847 100644 --- a/src/Components/Container.bf +++ b/src/Components/Container.bf @@ -70,6 +70,49 @@ abstract class Container : Component return false; } + public override bool OnRightClick(TGRuntime rt, int32[2] mPos, System.Collections.List<(String, delegate void(TGRuntime))> pList) + { + for(var i in _Drawings) + { + if(_Children.GetValue(scope .(i.name)) case .Ok(let component)) + { + if(mPos[0] >= i.x && mPos[0] <= i.x + i.width + && mPos[1] >= i.y && mPos[1] <= i.y + i.height) + { + component.OnRightClick(rt, .(mPos[0]-i.x, mPos[1]-i.y), pList); + return true; + } + } + } + return false; + } + + + public override bool OnLeftClick(TGRuntime rt, int32[2] mPos) + { + for(var i in _Drawings) + { + if(_Children.GetValue(scope .(i.name)) case .Ok(let component)) + { + if(mPos[0] >= i.x && mPos[0] <= i.x + i.width + && mPos[1] >= i.y && mPos[1] <= i.y + i.height) + { + if(component.OnLeftClick(rt, .(mPos[0]-i.x, mPos[1]-i.y))) + return true; + else + return true; + } + } + } + + return false; + } + + public override bool OnScroll(TGRuntime rt, float pOffset) + { + return false; + } + public Result AddChild(StringView pName, Component pComponent) { if(_Children.ContainsKeyAlt(pName)) diff --git a/src/Components/Internal/ClickableText.bf b/src/Components/Internal/ClickableText.bf new file mode 100644 index 0000000..6b198bf --- /dev/null +++ b/src/Components/Internal/ClickableText.bf @@ -0,0 +1,90 @@ +namespace TheaterGui.Components.Internal; +using TheaterGui.Components; +using TheaterGui.Core; +using TheaterGui.Core.Structs; + +using System; + +//The clickable text for things like the right click menu and the top toolbar +class ClickableText : Component +{ + private bool _Hovered = false; + private bool _AlreadyHovered = false; + + public String Label ~ delete _; + public delegate void(TGRuntime rt) Action ~ delete _; + public int32[2] Padding = .(50, 4); + public Alignment TextAlign = .LeftAligned; + + public enum Alignment + { + LeftAligned, + Center, + RightAligned + } + + public this(delegate void(TGRuntime rt) pToCall, StringView pName = "Button") + { + Action = pToCall; + Label = new .(pName); + } + + public override void Update(TheaterGui.Core.TGRuntime rt) + { + if(_Hovered != _AlreadyHovered) + { + _Hovered = _AlreadyHovered; + rt.Dirty(); + } + _AlreadyHovered = false; + } + + public override void Draw(TGRuntime rt, rect rect) + { + if(_Hovered) + rt.Platform.DrawColorRect(rect , rt.Scheme.HoverColor); + + var tsize = rt.Platform.MeasureTextSize(Label, "Font_Normal"); + int32 p = 0; + switch(TextAlign) + { + case .LeftAligned: + p = rect.x; + p += 2; + case .Center: + p = (.)(rect.x + 0.5*rect.width - tsize[0]*0.5); + case .RightAligned: + p = (.)(rect.x + rect.width - tsize[0]); + p -= 2; + } + rt.Platform.DrawText(Label, "Font_Normal", + .(p, + (.)(rect.y + 0.5*rect.height - tsize[1]*0.5)) + ,rt.Scheme.TextColor); + } + + public override int32[2] Resize(TheaterGui.Core.TGRuntime rt, int32 width) + { + var ts = rt.Platform.MeasureTextSize(Label, "Font_Normal"); + return .(ts[0] + Padding[0], ts[1] + Padding[1]); + } + + public override bool OnHover(TGRuntime rt, int32[2] mPos) + { + _AlreadyHovered = true; + return true; + } + + public override bool OnLeftClick(TGRuntime rt, int32[2] mPos) + { + Action.Invoke(rt); + return true; + } + + public override bool OnScroll(TGRuntime rt, float pOffset) + { + return false; + } + + public override bool OnRightClick(TGRuntime rt, int32[2] mPos, System.Collections.List<(String, delegate void(TGRuntime))> pList) => true; +} \ No newline at end of file diff --git a/src/Components/Popup.bf b/src/Components/Popup.bf new file mode 100644 index 0000000..cc55f52 --- /dev/null +++ b/src/Components/Popup.bf @@ -0,0 +1,154 @@ +namespace TheaterGui.Components; +using TheaterGui.Core.Structs; +using TheaterGui.Core; + +using System; +using System.Collections; + +///Unscrollable popup window that has a list of available items, clicking on anything but popup windows with the same tag will close it +class Popup : Container +{ + private rect _Container = .(); + private List<(String, delegate void(TGRuntime))> _ToDelete = null; + + public int32[2] Position = .(); + public int32 Padding = 0; + public bool DoHeightCheck = true; + + public this(int32[2] pPosition) + { + Position = pPosition; + } + + public ~this() + { + if(_ToDelete != null) + { + for(var i in _ToDelete) + { + delete i.0; + delete i.1; + } + delete _ToDelete; + } + } + + public override void Draw(TheaterGui.Core.TGRuntime rt, rect rect) + { + _Container = rect; + rect offset = .(); + int32[2] whLimit = .(0, 0); + for(var i in _Drawings) + { + if(whLimit[0] < i.x + i.width) + whLimit[0] = i.x + i.width; + if(whLimit[1] < i.y + i.height) + whLimit[1] = i.y + i.height; + } + offset.width = whLimit[0]; + offset.height = whLimit[1]; + + if(Position[0] < rt.ScreenSize[0]/2) + offset.x = Position[0]; + else + offset.x = Position[0]-offset.width; + + if(Position[1] < rt.ScreenSize[1]/2) + offset.y = Position[1]; + else + offset.y = Position[1]-offset.height; + + rt.Platform.DrawColorRectOutlined( + .() {x = offset.x - Padding, y = offset.y - Padding, width = offset.width + 2*Padding, height = offset.height + 2*Padding} + , rt.Scheme.PrimaryColor, rt.Scheme.AcceptColor); + rt.Platform.DrawColorRect( + .() {x = offset.x - Padding, y = offset.y - Padding, width = offset.width + 2*Padding+4, height = offset.height + 2*Padding+4} + , .(0x00, 0x00, 0x00, 40)); + base.Draw(rt, offset); + } + + + public override bool OnHover(TheaterGui.Core.TGRuntime rt, int32[2] mPos) + { + rect offset = .(); + int32[2] whLimit = .(0, 0); + for(var i in _Drawings) + { + if(whLimit[0] < i.x + i.width) + whLimit[0] = i.x + i.width; + if(whLimit[1] < i.y + i.height) + whLimit[1] = i.y + i.height; + } + offset.width = whLimit[0]; + offset.height = whLimit[1]; + + if(Position[0] < rt.ScreenSize[0]/2) + offset.x = Position[0]; + else + offset.x = Position[0]-offset.width; + + if(Position[1] < rt.ScreenSize[1]/2) + offset.y = Position[1]; + else + offset.y = Position[1]-offset.height; + + return base.OnHover(rt, .(mPos[0] - offset.x, mPos[1] - offset.y)); + } + + public override bool OnLeftClick(TheaterGui.Core.TGRuntime rt, int32[2] mPos) + { + rect offset = .(); + int32[2] whLimit = .(0, 0); + for(var i in _Drawings) + { + if(whLimit[0] < i.x + i.width) + whLimit[0] = i.x + i.width; + if(whLimit[1] < i.y + i.height) + whLimit[1] = i.y + i.height; + } + offset.width = whLimit[0]; + offset.height = whLimit[1]; + + if(Position[0] < rt.ScreenSize[0]/2) + offset.x = Position[0]; + else + offset.x = Position[0]-offset.width; + + if(Position[1] < rt.ScreenSize[1]/2) + offset.y = Position[1]; + else + offset.y = Position[1]-offset.height; + return base.OnLeftClick(rt, .(mPos[0] - offset.x, mPos[1] - offset.y)); + } + + public override bool OnScroll(TheaterGui.Core.TGRuntime rt, float pOffset) + { + return false; //Popups dont scroll + } + + public override int32[2] Resize(TheaterGui.Core.TGRuntime rt, int32 width) + { + _Drawings.Clear(); + + Layout l = scope .(); + l.[Friend]_RT = rt; + l.[Friend]_Children = _Children; + l.[Friend]_Drawings = _Drawings; + l.[Friend]_MaxWidth = width; + + Layout.Invoke(l, width); + + int32[2] max = .(0,0); + for(var i in _Drawings) + { + if(i.width+i.x > max[0]) + max[0] = i.width+i.x; + if(i.height+i.y > max[1]) + max[1] = i.height+i.y; + } + + for(var i in ref _Drawings) + i.width = max[0]; + return max; + } +} \ No newline at end of file diff --git a/src/Components/Screen.bf b/src/Components/Screen.bf new file mode 100644 index 0000000..9190609 --- /dev/null +++ b/src/Components/Screen.bf @@ -0,0 +1,64 @@ +namespace TheaterGui.Components; +using TheaterGui.Core; + +using System; + +class Screen : Container +{ + /* + Represents a physical view of a screen. It takes up the full window and there can only ever be one screen at a time + */ + + private float _ScrollValue = 0; + + public override bool OnHover(TheaterGui.Core.TGRuntime rt, int32[2] mPos) + { + return base.OnHover(rt, .(mPos[0], (.)(mPos[1] + _ScrollValue))); + } + + public override bool OnLeftClick(TGRuntime rt, int32[2] mPos) + { + for(var i in _Drawings) + { + if(_Children.GetValue(scope .(i.name)) case .Ok(let component)) + { + if(mPos[0] >= i.x && mPos[0] <= i.x + i.width + && mPos[1] >= i.y - _ScrollValue && mPos[1] <= i.y + i.height - _ScrollValue) + { + if(component.OnLeftClick(rt, .(mPos[0]-i.x, mPos[1]-i.y))) + return true; + else + return false; + } + } + } + + return false; + } + + public override void Draw(TheaterGui.Core.TGRuntime rt, TheaterGui.Core.Structs.rect rect) + { + base.Draw(rt, rect + .() {y = -(.)_ScrollValue}); + } + + public override int32[2] Resize(TheaterGui.Core.TGRuntime rt, int32 width) + { + return base.Resize(rt, width); + } + + public override bool OnScroll(TheaterGui.Core.TGRuntime rt, float pOffset) + { + int32 lowest = 0; + for(var i in _Drawings) + if(i.y + i.height > lowest) + lowest = i.y + i.height; + if(lowest > rt.Platform.ScreenSize()[1]) + { + _ScrollValue += pOffset; + _ScrollValue = Math.Clamp(_ScrollValue, 0, lowest - rt.Platform.ScreenSize()[1]); + return true; + } + else + return false; //Unable to scroll + } +} \ No newline at end of file diff --git a/src/Components/Toolbar.bf b/src/Components/Toolbar.bf new file mode 100644 index 0000000..3e96222 --- /dev/null +++ b/src/Components/Toolbar.bf @@ -0,0 +1,141 @@ +namespace TheaterGui.Components; +using TheaterGui.Components.Internal; +using TheaterGui.Core; + +using System; +using System.Collections; + +class Toolbar : Component +{ + private Dictionary> _Items = new .() ~ delete _; + private StringView _Hovered = ""; + private StringView _AlreadyHovered = ""; + private int32 _Offset = 0; + + public ~this() + { + for(var i in _Items) + { + delete i.key; + for(var j in i.value) + { + delete j.0; + delete j.1; + } + delete i.value; + } + } + + public override void Update(TGRuntime rt) + { + if(_Hovered != _AlreadyHovered) + { + _Hovered = _AlreadyHovered; + rt.Dirty(); + } + _AlreadyHovered = ""; + } + + public override void Draw(TGRuntime rt, TheaterGui.Core.Structs.rect rect) + { + _Offset = rect.x; + rt.Platform.DrawColorRectOutlined(rect, rt.Scheme.PrimaryColor, rt.Scheme.AcceptColor); + int32 xOffset = 0; + for(var i in _Items) + { + var tsize = rt.Platform.MeasureTextSize(i.key, "Font_Normal"); + + + if(_Hovered == i.key) + rt.Platform.DrawColorRect(.() {x = rect.x + xOffset, y = rect.y, width = 10 + tsize[0], height = rect.height}, rt.Scheme.HoverColor); + + xOffset += 5; + rt.Platform.DrawText(i.key, "Font_Normal", + .(xOffset+(rect.x), + (.)(rect.y + 0.5*rect.height - tsize[1]*0.5)+1) + ,rt.Scheme.TextColor); + xOffset += tsize[0]; + xOffset += 5; + } + + } + + public override int32[2] Resize(TGRuntime rt, int32 width) + { + return .(width, rt.Platform.MeasureTextSize("I", "Font_Normal")[1] + 6); + } + + public override bool OnHover(TGRuntime rt, int32[2] mPos) + { + int32 xOffset = 0; + for(var i in _Items) + { + var tsize = rt.Platform.MeasureTextSize(i.key, "Font_Normal"); + if(mPos[0] > xOffset && mPos[0] <= xOffset + tsize[0] + 10) + { + _AlreadyHovered = i.key; + if(rt.[Friend]_PopupsName == "Toolbar") + { + rt.ClearPopups(); + OpenPopup(rt, .(xOffset, rt.Platform.MeasureTextSize("I", "Font_Normal")[1] + 4), i.key); + } + } + xOffset += tsize[0] + 10; + } + return true; + } + + public override bool OnLeftClick(TGRuntime rt, int32[2] mPos) + { + if(_Hovered == "") + return false; + + int32 xOffset = 0; + for(var i in _Items) + { + if(i.key == _Hovered) + { + OpenPopup(rt, .(xOffset + _Offset,rt.Platform.MeasureTextSize("I", "Font_Normal")[1]+4), i.key); + return true; + } + + var tsize = rt.Platform.MeasureTextSize(i.key, "Font_Normal"); + xOffset += tsize[0] + 10; + } + return false; + } + + public override bool OnScroll(TGRuntime rt, float pOffset) => false; + + + private void OpenPopup(TGRuntime rt, int32[2] pos, StringView pName) + { + Popup toPopup = new .(pos); + if(_Items.GetValue(scope String(pName)) case .Ok(let vals)) + { + for(var i in vals) + toPopup.AddChild(i.0, new ClickableText(new (rt) => {i.1.Invoke(rt);},i.0)); + + toPopup.Layout = new [&] (val, width) => { + for(var i in vals) + { + val.Component(i.0); + val.Linebreak(); + } + }; + + } + rt.OpenPopup(toPopup, "Toolbar"); + } + + public void AddEntry(StringView pSection, StringView pName, delegate void(TGRuntime) pToRun) + { + if(!_Items.ContainsKeyAlt(pSection)) + _Items.Add(new .(pSection), new .()); + if(_Items.GetValue(scope .(pSection)) case .Ok(let val)) + val.Add((new .(pName), pToRun)); + } + + public override bool OnRightClick(TGRuntime rt, int32[2] mPos, System.Collections.List<(String, delegate void(TGRuntime))> pList) => true; + +} \ No newline at end of file diff --git a/src/Core/Layout.bf b/src/Core/Layout.bf index 17b062f..137665f 100644 --- a/src/Core/Layout.bf +++ b/src/Core/Layout.bf @@ -38,7 +38,7 @@ class Layout if(_Children.ContainsKeyAlt(name)) { var item = _Children[scope .(name)]; - var size = item.Resize(_RT, _MaxWidth); + var size = item.Resize(_RT, _MaxWidth-_X); if(_X + size[0] + padding_left + padding_right > _MaxWidth) { diff --git a/src/Core/TGRuntime.api.bf b/src/Core/TGRuntime.api.bf index d3e19b3..54e2ddb 100644 --- a/src/Core/TGRuntime.api.bf +++ b/src/Core/TGRuntime.api.bf @@ -10,7 +10,7 @@ extension TGRuntime public theme Theme; public colorScheme Scheme;; - private List _Screens = new .() ~ DeleteContainerAndItems!(_); + private Screen _CurrentScreen ~ delete _; private bool _ShouldClose = false; public bool ShouldClose @@ -37,4 +37,30 @@ extension TGRuntime get; private set; } + + private List _Popups = new .() ~ DeleteContainerAndItems!(_); + private String _PopupsName = new .("") ~ delete _; + public void OpenPopup(Popup pPopup, StringView pName) + { + if(pPopup == null) + { + ClearPopups(); + return; + } + else if(pName != _PopupsName) + { + ClearPopups(); + _PopupsName.Append(pName); + } + pPopup.Resize(this, ScreenSize[0]); + _Popups.Add(pPopup); + } + + public void ClearPopups() + { + Dirty(); + _PopupsName..Clear() + .Append(""); + ClearAndDeleteItems(_Popups); + } } \ No newline at end of file diff --git a/src/Core/TGRuntime.core.bf b/src/Core/TGRuntime.core.bf index 8da4a31..7f00cd5 100644 --- a/src/Core/TGRuntime.core.bf +++ b/src/Core/TGRuntime.core.bf @@ -1,12 +1,14 @@ namespace TheaterGui.Core; using TheaterGui.Core.Structs; using TheaterGui.Components; +using TheaterGui.Components.Internal; using System; +using System.Collections; class TGRuntime { - private void Launch(IPlatformLayer platform, Container screen, StringView name, int32 width, int32 height, colorScheme scheme, theme theme) + private void Launch(IPlatformLayer platform, Screen screen, StringView name, int32 width, int32 height, colorScheme scheme, theme theme) { Platform = platform; Platform.Initialize(name, width, height); @@ -14,9 +16,10 @@ class TGRuntime Theme = theme; Scheme = scheme; - _Screens.Add(screen); - for(var i in _Screens) - i.Resize(this, width); + _CurrentScreen = screen; + _CurrentScreen.Resize(this, width); + ScreenSize = Platform.ScreenSize(); + #if BF_PLATFORM_WASM WebAssembly.emscripten_set_main_loop(=> ProcessFrame, 60, 1); #else @@ -26,31 +29,84 @@ class TGRuntime platform.Deinitialize(); } + + bool _MBDownLastFrame = false; + bool _MBRightDownLastFrame = false; private void ProcessFrame() { //Meta ShouldClose = Platform.ShouldClose(); var ss = Platform.ScreenSize(); - if(ss != ScreenSize) + if (ss != ScreenSize) { //Resultion update Dirty(); - for(var i in _Screens) - i.Resize(this, ss[0]); + ClearPopups(); + _CurrentScreen.Resize(this, ss[0]); ScreenSize = ss; } + + if (Platform.MouseWheel() != 0) + if (_CurrentScreen.OnScroll(this, -5 * Platform.MouseWheel())) + { + Dirty(); + ClearPopups(); + } + var mPos = Platform.MousePosition(); - _Screens[0].OnHover(this, .((.)mPos[0], (.)mPos[1])); - + bool hasHovered = false; + for (var i in _Popups) + if (i.OnHover(this, .((.)mPos[0], (.)mPos[1]))) + hasHovered = true; + if (!hasHovered) + _CurrentScreen.OnHover(this, .((.)mPos[0], (.)mPos[1])); + + if (_MBDownLastFrame && !Platform.MouseLeftClick()) + { + bool hasLClicked = false; + for (var i in _Popups) + if (i.OnLeftClick(this, .((.)mPos[0], (.)mPos[1]))) + hasLClicked = true; + if (!hasLClicked) + { + ClearPopups(); + _CurrentScreen.OnLeftClick(this, .((.)mPos[0], (.)mPos[1])); + } + } + _MBDownLastFrame = Platform.MouseLeftClick(); + + if (_MBRightDownLastFrame && !Platform.MouseRightClick()) + { + bool hasLClicked = false; + List<(String, delegate void(TGRuntime))> data = new .(); + for (var i in _Popups) + if (i.OnRightClick(this, .((.)mPos[0], (.)mPos[1]), data)) + { + hasLClicked = true; + } + if (!hasLClicked) + { + ClearPopups(); + _CurrentScreen.OnRightClick(this, .((.)mPos[0], (.)mPos[1]), data); + } + if(data.Count > 0) + OpenRightClickPopup(this, .((.)mPos[0], (.)mPos[1]), data); + else + delete data; + } + _MBRightDownLastFrame = Platform.MouseRightClick(); + //Logic - for(var screen in _Screens) - screen.Update(this); + for (var i in _Popups) + i.Update(this); + _CurrentScreen.Update(this); //Drawing - if(_Dirty) + if (_Dirty) { Platform.StartDrawing(); - for(var screen in _Screens) - screen.Draw(this, .() {width = ScreenSize[0], height = ScreenSize[1] }); + _CurrentScreen.Draw(this, .() { width = ScreenSize[0], height = ScreenSize[1] }); + for (var i in _Popups) + i.Draw(this, .() { width = ScreenSize[0], height = ScreenSize[1] }); Platform.StopDrawing(); _Dirty = false; } @@ -64,4 +120,23 @@ class TGRuntime Platform.LoadFont(pStartingTheme.Font_Normal.0, "Font_Normal", pStartingTheme.Font_Normal.1); Platform.LoadTexture(pStartingTheme.Button, "Button"); } + + private void OpenRightClickPopup(TGRuntime rt, int32[2] pos, List<(String, delegate void(TGRuntime))> data) + { + Popup toPopup = new .(pos); + toPopup.Padding = 5; + toPopup.[Friend]_ToDelete = data; + for (var i in data) + toPopup.AddChild(i.0, new ClickableText(new (rt) => { i.1.Invoke(rt); }, i.0)); + + toPopup.Layout = new [&] (val, width) => + { + for (var i in data) + { + val.Component(i.0); + val.Linebreak(); + } + }; + OpenPopup(toPopup, "Rightclick"); + } } \ No newline at end of file From 9e7330d47c0d4bf268ec2652249dfe764f339c5b Mon Sep 17 00:00:00 2001 From: Booklordofthedings Date: Wed, 16 Oct 2024 12:08:01 +0200 Subject: [PATCH 4/6] added radio button --- examples/src/Program.bf | 68 ++++------------------ src/Components/Checkbox.bf | 73 ++++++++++++++++++++++++ src/Components/Label.bf | 40 +++++++++++++ src/Components/RadioButton.bf | 103 ++++++++++++++++++++++++++++++++++ src/Core/EventSystem.bf | 59 +++++++++++++++++++ src/Core/Structs/theme.bf | 12 ++-- src/Core/TGRuntime.api.bf | 2 + src/Core/TGRuntime.core.bf | 3 + src/TODO | 18 ++++++ 9 files changed, 316 insertions(+), 62 deletions(-) create mode 100644 src/Components/Checkbox.bf create mode 100644 src/Components/Label.bf create mode 100644 src/Components/RadioButton.bf create mode 100644 src/Core/EventSystem.bf create mode 100644 src/TODO diff --git a/examples/src/Program.bf b/examples/src/Program.bf index 7b9bb81..2f15680 100644 --- a/examples/src/Program.bf +++ b/examples/src/Program.bf @@ -34,68 +34,24 @@ class MainScreen : Screen AddChild("Toolbar", toAdd); AddChild("Button", new Button(new (val) => {Console.WriteLine("Hellau :)");})); + AddChild("Label", new Label("LMAO")); + AddChild("CBox", new Checkbox("Box")); + RadioButton r = new .(); + r.Label.Add(new .("One")); + r.Label.Add(new .("Two")); + r.Label.Add(new .("Three")); + AddChild("radio", r); Layout = new (val, width) => { val.Component("Toolbar"); + val.Component("Label", 10); + val.Linebreak(); val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - val.Component("Button"); - - + val.Component("CBox", 5); + val.Linebreak(); + val.Component("radio"); }; } } diff --git a/src/Components/Checkbox.bf b/src/Components/Checkbox.bf new file mode 100644 index 0000000..59a3fb5 --- /dev/null +++ b/src/Components/Checkbox.bf @@ -0,0 +1,73 @@ +namespace TheaterGui.Components; +using TheaterGui.Core; +using TheaterGui.Core.Structs; + +using System; +using System.Collections; + +class Checkbox : Component +{ + private bool _Hovered = false; + private bool _AlreadyHovered = false; + + public String Label ~ delete _; + public bool Checked = false; + + public this(StringView pName) + { + Label = new .(pName); + } + + public override void Update(TGRuntime rt) + { + if(_Hovered != _AlreadyHovered) + { + _Hovered = _AlreadyHovered; + rt.Dirty(); + } + _AlreadyHovered = false; + } + + public override void Draw(TGRuntime rt, rect rect) + { + var textureSize = rt.Platform.MeasureTextureSize("Checkbox"); + if(!Checked) + rt.Platform.DrawTexture("Checkbox", .() {x = rect.x, y = rect.y, width = textureSize[0], height = textureSize[1]}, rt.Scheme.PrimaryColor); + else + rt.Platform.DrawTexture("Checkbox_Checked", .() {x = rect.x, y = rect.y, width = textureSize[0], height = textureSize[1]}, rt.Scheme.PrimaryColor); + + if(_Hovered) + rt.Platform.DrawTexture("Checkbox", .() {x = rect.x, y = rect.y, width = textureSize[0], height = textureSize[1]}, rt.Scheme.HoverColor); + + var tsize = rt.Platform.MeasureTextSize(Label, "Font_Normal"); + rt.Platform.DrawText(Label, "Font_Normal", + .(rect.x + textureSize[0] + 5 + ,(.)(rect.y + 0.5*rect.height - tsize[1]*0.5)) + ,rt.Scheme.TextColor); + } + + public override int32[2] Resize(TGRuntime rt, int32 width) + { + var textureSize = rt.Platform.MeasureTextureSize("Checkbox"); + var tsize = rt.Platform.MeasureTextSize(Label, "Font_Normal"); + textureSize[0] += 5 + tsize[0]; + if(tsize[1] > textureSize[1]) + textureSize[1] = tsize[1]; + return textureSize; + } + + public override bool OnHover(TGRuntime rt, int32[2] mPos) + { + _AlreadyHovered = true; + return true; + } + + public override bool OnLeftClick(TGRuntime rt, int32[2] mPos) + { + Checked = !Checked; + return true; + } + + public override bool OnScroll(TGRuntime rt, float pOffset) => false; + public override bool OnRightClick(TGRuntime rt, int32[2] mPos, System.Collections.List<(String, delegate void(TGRuntime))> pList) => false; +} \ No newline at end of file diff --git a/src/Components/Label.bf b/src/Components/Label.bf new file mode 100644 index 0000000..d9b95dd --- /dev/null +++ b/src/Components/Label.bf @@ -0,0 +1,40 @@ +namespace TheaterGui.Components; +using TheaterGui.Core; +using TheaterGui.Core.Structs; + +using System; +using System.Collections; + +class Label : Component +{ + public String Label = null ~ delete _; + + public this(StringView pLabel) + { + Label = new .(pLabel); + } + + public override void Update(TGRuntime rt) + { + + } + + public override void Draw(TGRuntime rt, rect rect) + { + rt.Platform.DrawText(Label, "Font_Normal", .(rect.x, rect.y), rt.Scheme.TextColor); + } + + public override int32[2] Resize(TGRuntime rt, int32 width) + { + var s = rt.Platform.MeasureTextSize(Label, "Font_Normal"); + return .(s[0], s[1]); + } + + public override bool OnHover(TGRuntime rt, int32[2] mPos) => false; + + public override bool OnLeftClick(TGRuntime rt, int32[2] mPos) => false; + + public override bool OnScroll(TGRuntime rt, float pOffset) => false; + + public override bool OnRightClick(TGRuntime rt, int32[2] mPos, List<(String, delegate void(TGRuntime))> pList) => true; +} \ No newline at end of file diff --git a/src/Components/RadioButton.bf b/src/Components/RadioButton.bf new file mode 100644 index 0000000..a1327a4 --- /dev/null +++ b/src/Components/RadioButton.bf @@ -0,0 +1,103 @@ +namespace TheaterGui.Components; +using TheaterGui.Core; +using TheaterGui.Core.Structs; + +using System; +using System.Collections; + +class RadioButton : Component +{ + private int32 _Checked = 0; + private int32 _Hovered = -1; + private int32 _AlreadyHovered = -1; + + public List Label = new .() ~ DeleteContainerAndItems!(_); + + public this() + { + } + + public override void Update(TGRuntime rt) + { + if(_Hovered != _AlreadyHovered) + { + _Hovered = _AlreadyHovered; + rt.Dirty(); + } + _AlreadyHovered = -1; + } + + public override void Draw(TGRuntime rt, rect rect) + { + int32 startingY = 0; + var textureSize = rt.Platform.MeasureTextureSize("Checkbox"); + for(var i in Label) + { + if(!(_Checked == (.)@i.Index)) + rt.Platform.DrawTexture("Checkbox", .() {x = rect.x, y = rect.y + startingY, width = textureSize[0], height = textureSize[1]}, rt.Scheme.PrimaryColor); + else + rt.Platform.DrawTexture("Checkbox_Checked", .() {x = rect.x, y = rect.y + startingY, width = textureSize[0], height = textureSize[1]}, rt.Scheme.PrimaryColor); + + if(_Hovered == @i.Index) + rt.Platform.DrawTexture("Checkbox", .() {x = rect.x, y = rect.y + startingY, width = textureSize[0], height = textureSize[1]}, rt.Scheme.HoverColor); + + var tsize = rt.Platform.MeasureTextSize(i, "Font_Normal"); + rt.Platform.DrawText(i, "Font_Normal", + .(rect.x + textureSize[0] + 5 + ,(.)(rect.y + 0.5*textureSize[1] - tsize[1]*0.5 + startingY)) + ,rt.Scheme.TextColor); + + startingY += textureSize[1]; + } + } + + + public override int32[2] Resize(TGRuntime rt, int32 width) + { + var textureSize = rt.Platform.MeasureTextureSize("Checkbox"); + int32 xAddition = 0; + for(var label in Label) + { + var tsize = rt.Platform.MeasureTextSize(label, "Font_Normal"); + if(tsize[0] + 5 < xAddition) + xAddition = tsize[0] + 5; + textureSize[1] += rt.Platform.MeasureTextureSize("Checkbox")[1]; + } + + textureSize[0] += xAddition; + return textureSize; + } + + private int32 GetSelectedItem(TGRuntime rt, int32[2] mPos) + { + int32 startingY = 0; + int32 itemHeight = rt.Platform.MeasureTextureSize("Checkbox")[1]; + for(var i in Label) + { + if(mPos[1] >= startingY && mPos[1] < startingY + itemHeight) + { + var textSize = rt.Platform.MeasureTextSize(i, "Font_Normal"); + if(mPos[0] <= rt.Platform.MeasureTextureSize("Checkbox")[0] + 5 + textSize[0]) + return (.)@i.Index; + } + startingY += itemHeight; + } + + return -1; + } + + public override bool OnHover(TGRuntime rt, int32[2] mPos) + { + _AlreadyHovered = GetSelectedItem(rt, mPos); + return true; + } + + public override bool OnLeftClick(TGRuntime rt, int32[2] mPos) + { + _Checked = GetSelectedItem(rt, mPos); + return true; + } + + public override bool OnScroll(TGRuntime rt, float pOffset) => false; + public override bool OnRightClick(TGRuntime rt, int32[2] mPos, System.Collections.List<(String, delegate void(TGRuntime))> pList) => false; +} diff --git a/src/Core/EventSystem.bf b/src/Core/EventSystem.bf new file mode 100644 index 0000000..3942da1 --- /dev/null +++ b/src/Core/EventSystem.bf @@ -0,0 +1,59 @@ +namespace TheaterGui.Core; + +using System; +using System.Collections; + +class EventSystem +{ + private Dictionary> _Events = new .() ~ delete _; + private uint64 _Id = 0; + + public ~this() + { + for(var i in _Events) + { + delete i.key; + for(var j in i.value) + delete j.1; + delete i.value; + } + } + + ///Invoke a event, conditionally pass in a event object, and return the amount of events called + public int32 Invoke(StringView name, void* obj) + { + if(!_Events.ContainsKeyAlt(name)) + return -1; + int32 toReturn = 0; + for(var i in _Events[scope .(name)]) + { + i.1(obj); + toReturn++; + } + return toReturn; + } + + ///Returns the deregistration id to be used when deregistering + public uint64 Register(StringView name, delegate void(void*) func) + { + if(!_Events.ContainsKeyAlt(name)) + _Events.Add(new .(name), new .()); + _Events[scope .(name)].Add((_Id+1, func)); + _Id++; + return _Id; + } + + public void DeRegister(StringView name, uint64 id) + { + if(!_Events.ContainsKeyAlt(name)) + return; + for(var i in _Events[scope .(name)]) + { + if(i.0 == id) + { + delete i.1; + @i.Remove(); + } + } + } +} \ No newline at end of file diff --git a/src/Core/Structs/theme.bf b/src/Core/Structs/theme.bf index 6e00e8d..ae45916 100644 --- a/src/Core/Structs/theme.bf +++ b/src/Core/Structs/theme.bf @@ -6,20 +6,20 @@ struct theme { private static uint8[?] _Theme_Font = Compiler.ReadBinary("assets/Din.ttf"); private static uint8[?] _Theme_Button = Compiler.ReadBinary("assets/button.png"); + private static uint8[?] _Theme_Checkbox = Compiler.ReadBinary("assets/checkbox.png"); + private static uint8[?] _Theme_Checkbox_Checked = Compiler.ReadBinary("assets/checkbox_checked.png"); /* private static uint8[?] Texture_SquareButton = Compiler.ReadBinary("assets/square_button.png"); private static uint8[?] Texture_LargeButton = Compiler.ReadBinary("assets/large_button.png"); private static uint8[?] Texture_NButton = Compiler.ReadBinary("assets/n_button.png"); - private static uint8[?] Texture_Checkbox = Compiler.ReadBinary("assets/checkbox.png"); - private static uint8[?] Texture_Checkbox_Checked = Compiler.ReadBinary("assets/checkbox_checked.png"); + private static uint8[?] Horizontal_Patch = Compiler.ReadBinary("assets/horizontal_patch.png"); private static uint8[?] Dropdown = Compiler.ReadBinary("assets/dropdown.png"); */ - public (Span, uint8) Font_Normal = ( - .(&_Theme_Font, _Theme_Font.Count), - 16 - ); + public (Span, uint8) Font_Normal = (.(&_Theme_Font, _Theme_Font.Count),16); public Span Button = .(&_Theme_Button, _Theme_Button.Count); + public Span Checkbox = .(&_Theme_Checkbox, _Theme_Checkbox.Count); + public Span Checkbox_Checked = .(&_Theme_Checkbox_Checked, _Theme_Checkbox_Checked.Count); } \ No newline at end of file diff --git a/src/Core/TGRuntime.api.bf b/src/Core/TGRuntime.api.bf index 54e2ddb..df19cfb 100644 --- a/src/Core/TGRuntime.api.bf +++ b/src/Core/TGRuntime.api.bf @@ -7,6 +7,8 @@ using System.Collections; extension TGRuntime { + public EventSystem Events = new .() ~ delete _; + public theme Theme; public colorScheme Scheme;; diff --git a/src/Core/TGRuntime.core.bf b/src/Core/TGRuntime.core.bf index 7f00cd5..2a2a081 100644 --- a/src/Core/TGRuntime.core.bf +++ b/src/Core/TGRuntime.core.bf @@ -119,6 +119,9 @@ class TGRuntime Platform.ChangeBackgroundColor(pScheme.BackgroundColor); Platform.LoadFont(pStartingTheme.Font_Normal.0, "Font_Normal", pStartingTheme.Font_Normal.1); Platform.LoadTexture(pStartingTheme.Button, "Button"); + Platform.LoadTexture(pStartingTheme.Checkbox, "Checkbox"); + Platform.LoadTexture(pStartingTheme.Checkbox_Checked, "Checkbox_Checked"); + } private void OpenRightClickPopup(TGRuntime rt, int32[2] pos, List<(String, delegate void(TGRuntime))> data) diff --git a/src/TODO b/src/TODO new file mode 100644 index 0000000..bb05c1c --- /dev/null +++ b/src/TODO @@ -0,0 +1,18 @@ +TODO: +TabbedContainers +Fixed size containers +Collapseables +Dropdown +Textfields +Textboxes +TextDisplays +Icon buttons +Horizontal sliders +Vertical sliders +Code cleanup + + +Being Worked on: + +Done +Radio Buttons \ No newline at end of file From f6c0049e781e8c08facdee6f148e7e0e23751c85 Mon Sep 17 00:00:00 2001 From: Booklordofthedings Date: Wed, 16 Oct 2024 13:58:58 +0200 Subject: [PATCH 5/6] Started dropdown and added sliders --- examples/src/Program.bf | 10 ++++- src/Components/Button.bf | 6 +-- src/Components/Dropdown.bf | 68 +++++++++++++++++++++++++++++++ src/Components/HSlider.bf | 75 ++++++++++++++++++++++++++++++++++ src/Components/RadioButton.bf | 6 +-- src/Components/VSlider.bf | 76 +++++++++++++++++++++++++++++++++++ src/Core/Structs/theme.bf | 4 +- src/Core/TGRuntime.core.bf | 1 + src/TODO | 10 ++--- 9 files changed, 243 insertions(+), 13 deletions(-) create mode 100644 src/Components/Dropdown.bf create mode 100644 src/Components/HSlider.bf create mode 100644 src/Components/VSlider.bf diff --git a/examples/src/Program.bf b/examples/src/Program.bf index 2f15680..ee2f6a8 100644 --- a/examples/src/Program.bf +++ b/examples/src/Program.bf @@ -34,6 +34,7 @@ class MainScreen : Screen AddChild("Toolbar", toAdd); AddChild("Button", new Button(new (val) => {Console.WriteLine("Hellau :)");})); + AddChild("dd", new Dropdown(new (val) => {Console.WriteLine("Hellau :)");})); AddChild("Label", new Label("LMAO")); AddChild("CBox", new Checkbox("Box")); @@ -42,6 +43,9 @@ class MainScreen : Screen r.Label.Add(new .("Two")); r.Label.Add(new .("Three")); AddChild("radio", r); + AddChild("hslider", new HSlider()); + AddChild("vslider", new VSlider()); + Layout = new (val, width) => { @@ -51,7 +55,11 @@ class MainScreen : Screen val.Component("Button"); val.Component("CBox", 5); val.Linebreak(); - val.Component("radio"); + val.Component("radio", 5); + val.Component("hslider"); + val.Component("vslider"); + val.Linebreak(); + val.Component("dd", 5); }; } } diff --git a/src/Components/Button.bf b/src/Components/Button.bf index 4dc5622..dcae7b0 100644 --- a/src/Components/Button.bf +++ b/src/Components/Button.bf @@ -12,10 +12,10 @@ class Button : Component public String Label ~ delete _; delegate void(TGRuntime rt) Action ~ delete _; - public this(delegate void(TGRuntime rt) pToCall, StringView pName = "Button") + public this(delegate void(TGRuntime rt) pAction, StringView pLabel = "Button") { - Action = pToCall; - Label = new .(pName); + Label = new .(pLabel); + Action = pAction; } public override void Update(TheaterGui.Core.TGRuntime rt) diff --git a/src/Components/Dropdown.bf b/src/Components/Dropdown.bf new file mode 100644 index 0000000..1000f61 --- /dev/null +++ b/src/Components/Dropdown.bf @@ -0,0 +1,68 @@ +namespace TheaterGui.Components; +using TheaterGui.Core; +using TheaterGui.Core.Structs; + +using System; + +class Dropdown : Component +{ + private bool _Hovered = false; + private bool _AlreadyHovered = false; + + public String Label ~ delete _; + delegate void(TGRuntime rt) Action ~ delete _; + + public this(delegate void(TGRuntime rt) pAction, StringView pLabel = "Button") + { + Label = new .(pLabel); + Action = pAction; + } + + public override void Update(TheaterGui.Core.TGRuntime rt) + { + if(_Hovered != _AlreadyHovered) + { + _Hovered = _AlreadyHovered; + rt.Dirty(); + } + _AlreadyHovered = false; + } + + public override void Draw(TGRuntime rt, rect rect) + { + rt.Platform.DrawTexture("Dropdown", rect, rt.Scheme.PrimaryColor); + if(_Hovered) + rt.Platform.DrawTexture("Dropdown", rect, rt.Scheme.HoverColor); + + var tsize = rt.Platform.MeasureTextSize(Label, "Font_Normal"); + rt.Platform.DrawText(Label, "Font_Normal", + .((.)(rect.x + 0.5*rect.width - tsize[0]*0.5), + (.)(rect.y + 0.5*rect.height - tsize[1]*0.5)) + ,rt.Scheme.TextColor); + } + + public override int32[2] Resize(TheaterGui.Core.TGRuntime rt, int32 width) + { + return rt.Platform.MeasureTextureSize("Dropdown"); + } + + public override bool OnHover(TGRuntime rt, int32[2] mPos) + { + _AlreadyHovered = true; + return true; + } + + public override bool OnLeftClick(TGRuntime rt, int32[2] mPos) + { + Action.Invoke(rt); + return true; + } + + public override bool OnScroll(TGRuntime rt, float pOffset) => false; + + public override bool OnRightClick(TGRuntime rt, int32[2] mPos, System.Collections.List<(String, delegate void(TGRuntime))> pList) + { + pList.Add((.)(new String(scope $"Click {Label}"), new (rt) => {this.Action.Invoke(rt);})); + return true; + } +} \ No newline at end of file diff --git a/src/Components/HSlider.bf b/src/Components/HSlider.bf new file mode 100644 index 0000000..c74e19d --- /dev/null +++ b/src/Components/HSlider.bf @@ -0,0 +1,75 @@ +namespace TheaterGui.Components; +using TheaterGui.Core; +using TheaterGui.Core.Structs; + +using System; + +class HSlider : Component +{ + private bool _Hovered = false; + private bool _AlreadyHovered = false; + + public float Value = 0; + + public this() + { + } + + public override void Update(TheaterGui.Core.TGRuntime rt) + { + if (_Hovered != _AlreadyHovered) + { + _Hovered = _AlreadyHovered; + rt.Dirty(); + } + _AlreadyHovered = false; + } + + public override void Draw(TGRuntime rt, rect rect) + { + var ts = rt.Platform.MeasureTextureSize("Checkbox"); + + rt.Platform.DrawColorRect(.() { x = rect.x + ts[0], width = rect.width-2*ts[0], y = rect.y + ts[1] / 2 - 4, height = 8 }, rt.Scheme.AcceptColor); + rt.Platform.DrawTexture("Checkbox", .() { x = (.)(rect.x + ts[0] + Value * 10*ts[0]-ts[0]/2), y = rect.y, width = ts[0], height = ts[1] }, rt.Scheme.PrimaryColor); + if (_Hovered) + rt.Platform.DrawTexture("Checkbox", .() { x = (.)(rect.x + ts[0] + Value * 10*ts[0]-ts[0]/2), y = rect.y, width = ts[0], height = ts[1] }, rt.Scheme.HoverColor); + } + + public override int32[2] Resize(TheaterGui.Core.TGRuntime rt, int32 width) + { + var ts = rt.Platform.MeasureTextureSize("Checkbox"); + return .(ts[0] * 12, ts[1]); + } + + public override bool OnHover(TGRuntime rt, int32[2] mPos) + { + _AlreadyHovered = true; + if(rt.Platform.MouseLeftClick()) + { + float oldVal = Value; + OnLeftClick(rt, mPos); + if(Value != oldVal) + rt.Dirty(); + } + return true; + } + + public override bool OnLeftClick(TGRuntime rt, int32[2] mPos) + { + var ts = rt.Platform.MeasureTextureSize("Checkbox"); + if(mPos[0] <= ts[0]) + Value = 0; + else if(mPos[0] >= ts[0] * 11) + Value = 1; + else + { + float ofst = mPos[0] - ts[0]; + Value = Math.Clamp(ofst / (ts[0]*10) + ,0,1); + } + return true; + } + + public override bool OnScroll(TGRuntime rt, float pOffset) => false; + public override bool OnRightClick(TGRuntime rt, int32[2] mPos, System.Collections.List<(String, delegate void(TGRuntime))> pList) => false; +} \ No newline at end of file diff --git a/src/Components/RadioButton.bf b/src/Components/RadioButton.bf index a1327a4..f0ed98d 100644 --- a/src/Components/RadioButton.bf +++ b/src/Components/RadioButton.bf @@ -59,12 +59,12 @@ class RadioButton : Component for(var label in Label) { var tsize = rt.Platform.MeasureTextSize(label, "Font_Normal"); - if(tsize[0] + 5 < xAddition) + if(tsize[0] + 5 > xAddition) xAddition = tsize[0] + 5; - textureSize[1] += rt.Platform.MeasureTextureSize("Checkbox")[1]; } - textureSize[0] += xAddition; + textureSize[0] = textureSize[0] + xAddition; + textureSize[1] = (.)(textureSize[1] * Label.Count); return textureSize; } diff --git a/src/Components/VSlider.bf b/src/Components/VSlider.bf new file mode 100644 index 0000000..de0be46 --- /dev/null +++ b/src/Components/VSlider.bf @@ -0,0 +1,76 @@ +namespace TheaterGui.Components; +using TheaterGui.Core; +using TheaterGui.Core.Structs; + +using System; + +class VSlider : Component +{ + private bool _Hovered = false; + private bool _AlreadyHovered = false; + + public float Value = 0; + + public this() + { + } + + public override void Update(TheaterGui.Core.TGRuntime rt) + { + if (_Hovered != _AlreadyHovered) + { + _Hovered = _AlreadyHovered; + rt.Dirty(); + } + _AlreadyHovered = false; + } + + public override void Draw(TGRuntime rt, rect rect) + { + var ts = rt.Platform.MeasureTextureSize("Checkbox"); + + rt.Platform.DrawColorRect(.() { x = rect.x + ts[0] / 2 - 4, width = 8, y = rect.y + ts[1], height = rect.height-2*ts[1] }, rt.Scheme.AcceptColor); + + rt.Platform.DrawTexture("Checkbox", .() { y = (.)(rect.y + ts[1] + Value * 10*ts[1]-ts[1]/2), x = rect.x, height = ts[1], width = ts[0] }, rt.Scheme.PrimaryColor); + if (_Hovered) + rt.Platform.DrawTexture("Checkbox", .() { y = (.)(rect.y + ts[1] + Value * 10*ts[1]-ts[1]/2), x = rect.x, height = ts[1], width = ts[0] }, rt.Scheme.HoverColor); + } + + public override int32[2] Resize(TheaterGui.Core.TGRuntime rt, int32 width) + { + var ts = rt.Platform.MeasureTextureSize("Checkbox"); + return .(ts[0], ts[1] * 12); + } + + public override bool OnHover(TGRuntime rt, int32[2] mPos) + { + _AlreadyHovered = true; + if(rt.Platform.MouseLeftClick()) + { + float oldVal = Value; + OnLeftClick(rt, mPos); + if(Value != oldVal) + rt.Dirty(); + } + return true; + } + + public override bool OnLeftClick(TGRuntime rt, int32[2] mPos) + { + var ts = rt.Platform.MeasureTextureSize("Checkbox"); + if(mPos[1] <= ts[1]) + Value = 0; + else if(mPos[1] >= ts[1] * 11) + Value = 1; + else + { + float ofst = mPos[1] - ts[1]; + Value = Math.Clamp(ofst / (ts[1]*10) + ,0,1); + } + return true; + } + + public override bool OnScroll(TGRuntime rt, float pOffset) => false; + public override bool OnRightClick(TGRuntime rt, int32[2] mPos, System.Collections.List<(String, delegate void(TGRuntime))> pList) => false; +} \ No newline at end of file diff --git a/src/Core/Structs/theme.bf b/src/Core/Structs/theme.bf index ae45916..38116f5 100644 --- a/src/Core/Structs/theme.bf +++ b/src/Core/Structs/theme.bf @@ -8,6 +8,7 @@ struct theme private static uint8[?] _Theme_Button = Compiler.ReadBinary("assets/button.png"); private static uint8[?] _Theme_Checkbox = Compiler.ReadBinary("assets/checkbox.png"); private static uint8[?] _Theme_Checkbox_Checked = Compiler.ReadBinary("assets/checkbox_checked.png"); + private static uint8[?] _Theme_Dropdown = Compiler.ReadBinary("assets/dropdown.png"); /* private static uint8[?] Texture_SquareButton = Compiler.ReadBinary("assets/square_button.png"); @@ -15,11 +16,12 @@ struct theme private static uint8[?] Texture_NButton = Compiler.ReadBinary("assets/n_button.png"); private static uint8[?] Horizontal_Patch = Compiler.ReadBinary("assets/horizontal_patch.png"); - private static uint8[?] Dropdown = Compiler.ReadBinary("assets/dropdown.png"); */ public (Span, uint8) Font_Normal = (.(&_Theme_Font, _Theme_Font.Count),16); public Span Button = .(&_Theme_Button, _Theme_Button.Count); public Span Checkbox = .(&_Theme_Checkbox, _Theme_Checkbox.Count); public Span Checkbox_Checked = .(&_Theme_Checkbox_Checked, _Theme_Checkbox_Checked.Count); + public Span Dropdown = .(&_Theme_Dropdown, _Theme_Dropdown.Count); + } \ No newline at end of file diff --git a/src/Core/TGRuntime.core.bf b/src/Core/TGRuntime.core.bf index 2a2a081..e0358dd 100644 --- a/src/Core/TGRuntime.core.bf +++ b/src/Core/TGRuntime.core.bf @@ -120,6 +120,7 @@ class TGRuntime Platform.LoadFont(pStartingTheme.Font_Normal.0, "Font_Normal", pStartingTheme.Font_Normal.1); Platform.LoadTexture(pStartingTheme.Button, "Button"); Platform.LoadTexture(pStartingTheme.Checkbox, "Checkbox"); + Platform.LoadTexture(pStartingTheme.Dropdown, "Dropdown"); Platform.LoadTexture(pStartingTheme.Checkbox_Checked, "Checkbox_Checked"); } diff --git a/src/TODO b/src/TODO index bb05c1c..3670021 100644 --- a/src/TODO +++ b/src/TODO @@ -2,17 +2,17 @@ TODO: TabbedContainers Fixed size containers Collapseables -Dropdown Textfields Textboxes TextDisplays Icon buttons -Horizontal sliders -Vertical sliders Code cleanup Being Worked on: +Dropdown -Done -Radio Buttons \ No newline at end of file +Done: +Radio Buttons +Horizontal sliders +Vertical sliders \ No newline at end of file From 0f12f4359c2271c6fa35375ce824fc2d5da78a4f Mon Sep 17 00:00:00 2001 From: Booklordofthedings Date: Thu, 17 Oct 2024 12:37:30 +0200 Subject: [PATCH 6/6] Dropdown works --- examples/src/Program.bf | 10 +- src/Components/Dropdown.bf | 31 +++--- src/Components/Internal/DropdownPopup.bf | 117 +++++++++++++++++++++++ src/TODO | 13 ++- 4 files changed, 149 insertions(+), 22 deletions(-) create mode 100644 src/Components/Internal/DropdownPopup.bf diff --git a/examples/src/Program.bf b/examples/src/Program.bf index ee2f6a8..d54d5b3 100644 --- a/examples/src/Program.bf +++ b/examples/src/Program.bf @@ -34,7 +34,7 @@ class MainScreen : Screen AddChild("Toolbar", toAdd); AddChild("Button", new Button(new (val) => {Console.WriteLine("Hellau :)");})); - AddChild("dd", new Dropdown(new (val) => {Console.WriteLine("Hellau :)");})); + AddChild("dd", new Dropdown("One", "Two", "Three")); AddChild("Label", new Label("LMAO")); AddChild("CBox", new Checkbox("Box")); @@ -45,6 +45,13 @@ class MainScreen : Screen AddChild("radio", r); AddChild("hslider", new HSlider()); AddChild("vslider", new VSlider()); + AddChild("lb", new Label(""" + Labels can also be used to + contain some larger text since this also + works fine + and without any + issues + """)); Layout = new (val, width) => @@ -58,6 +65,7 @@ class MainScreen : Screen val.Component("radio", 5); val.Component("hslider"); val.Component("vslider"); + val.Component("lb"); val.Linebreak(); val.Component("dd", 5); }; diff --git a/src/Components/Dropdown.bf b/src/Components/Dropdown.bf index 1000f61..0b46663 100644 --- a/src/Components/Dropdown.bf +++ b/src/Components/Dropdown.bf @@ -1,21 +1,24 @@ namespace TheaterGui.Components; +using TheaterGui.Components.Internal; using TheaterGui.Core; using TheaterGui.Core.Structs; using System; +using System.Collections; class Dropdown : Component { private bool _Hovered = false; private bool _AlreadyHovered = false; + private int32[2] _Pos = .(); - public String Label ~ delete _; - delegate void(TGRuntime rt) Action ~ delete _; + public List Options = new .() ~ DeleteContainerAndItems!(_); + public int32 Selected = 0; - public this(delegate void(TGRuntime rt) pAction, StringView pLabel = "Button") + public this(params Span args) { - Label = new .(pLabel); - Action = pAction; + for(var i in args) + Options.Add(new .(i)); } public override void Update(TheaterGui.Core.TGRuntime rt) @@ -30,12 +33,13 @@ class Dropdown : Component public override void Draw(TGRuntime rt, rect rect) { + _Pos = .(rect.x, rect.y + rect.height); rt.Platform.DrawTexture("Dropdown", rect, rt.Scheme.PrimaryColor); if(_Hovered) rt.Platform.DrawTexture("Dropdown", rect, rt.Scheme.HoverColor); - var tsize = rt.Platform.MeasureTextSize(Label, "Font_Normal"); - rt.Platform.DrawText(Label, "Font_Normal", + var tsize = rt.Platform.MeasureTextSize(Options[Selected], "Font_Normal"); + rt.Platform.DrawText(Options[Selected], "Font_Normal", .((.)(rect.x + 0.5*rect.width - tsize[0]*0.5), (.)(rect.y + 0.5*rect.height - tsize[1]*0.5)) ,rt.Scheme.TextColor); @@ -54,15 +58,14 @@ class Dropdown : Component public override bool OnLeftClick(TGRuntime rt, int32[2] mPos) { - Action.Invoke(rt); + var p = new DropdownPopup(Options) {Position = _Pos}; + p.[Friend]_Click = new [&] (val) => { + this.Selected = val; + }; + rt.OpenPopup(p, "Dropdown"); return true; } public override bool OnScroll(TGRuntime rt, float pOffset) => false; - - public override bool OnRightClick(TGRuntime rt, int32[2] mPos, System.Collections.List<(String, delegate void(TGRuntime))> pList) - { - pList.Add((.)(new String(scope $"Click {Label}"), new (rt) => {this.Action.Invoke(rt);})); - return true; - } + public override bool OnRightClick(TGRuntime rt, int32[2] mPos, System.Collections.List<(String, delegate void(TGRuntime))> pList) => false; } \ No newline at end of file diff --git a/src/Components/Internal/DropdownPopup.bf b/src/Components/Internal/DropdownPopup.bf new file mode 100644 index 0000000..c7ec168 --- /dev/null +++ b/src/Components/Internal/DropdownPopup.bf @@ -0,0 +1,117 @@ +namespace TheaterGui.Components.Internal; +using TheaterGui.Components; +using TheaterGui.Core; +using TheaterGui.Core.Structs; + +using System; +using System.Collections; + +class DropdownPopup : Popup +{ + private int32 _Hovered = -1; + private int32 _AlreadyHovered = -1; + private int32[2] _Size = .(); + private delegate void(int32) _Click ~ delete _; + + public List Options = new .() ~ DeleteContainerAndItems!(_); + public int32 Selected = 0; + + public this(List args) : this() + { + for(var i in args) + Options.Add(new .(i)); + } + + public override void Update(TGRuntime rt) + { + if(_Hovered != _AlreadyHovered) + { + _Hovered = _AlreadyHovered; + rt.Dirty(); + } + _AlreadyHovered = -1; + } + + public override void Draw(TGRuntime rt, rect rect) + { + rt.Platform.DrawColorRectOutlined( + .() {x = Position[0], y = Position[1], width = _Size[0], height = _Size[1]} + ,rt.Scheme.PrimaryColor, rt.Scheme.AcceptColor); + int32 offsetY = 2; + for(var i in Options) + { + rt.Platform.DrawText(i, "Font_Normal", .(Position[0] + 2, Position[1] + offsetY), rt.Scheme.TextColor); + var size = rt.Platform.MeasureTextSize(i, "Font_Normal"); + + if(_Hovered == (.)@i.Index) + { + rt.Platform.DrawColorRect( + .() {x = Position[0], y = Position[1] + offsetY - 2, width = _Size[0], height = 4 + size[1]}, + rt.Scheme.HoverColor); + } + + offsetY += 4 + size[1]; + + } + } + + public override int32[2] Resize(TGRuntime rt, int32 width) + { + int32[2] size = .(); + for(var i in Options) + { + size[0] = rt.Platform.MeasureTextureSize("Dropdown")[0]; + var tsize = rt.Platform.MeasureTextSize(i, "Font_Normal"); + size[1] += tsize[1] + 4; //4 is the padding + + } + _Size = size; + return size; + } + + public override bool OnHover(TGRuntime rt, int32[2] mPos) + { + if(mPos[0] >= Position[0] && mPos[0] < Position[0] + _Size[0]) + { + if(mPos[1] >= Position[1] && mPos[1] < Position[1] + _Size[1]) + { + int32[2] offset = .(mPos[0] - Position[0], mPos[1] - Position[1]); + int32 offsetY = 0; + for(var i in Options) + { + var tsize = rt.Platform.MeasureTextSize(i, "Font_Normal"); + if(offset[1] >= offsetY && offset[1] < offsetY + tsize[1] + 4) + { + _AlreadyHovered = (.)@i.Index; + return true; + } + offsetY += tsize[1] + 4; + } + } + } + return false; + } + + public override bool OnLeftClick(TGRuntime rt, int32[2] mPos) + { + if(mPos[0] >= Position[0] && mPos[0] < Position[0] + _Size[0]) + { + if(mPos[1] >= Position[1] && mPos[1] < Position[1] + _Size[1]) + { + int32[2] offset = .(mPos[0] - Position[0], mPos[1] - Position[1]); + int32 offsetY = 0; + for(var i in Options) + { + var tsize = rt.Platform.MeasureTextSize(i, "Font_Normal"); + if(offset[1] >= offsetY && offset[1] < offsetY + tsize[1] + 4) + { + _Click.Invoke((.)@i.Index); + return false; + } + offsetY += tsize[1] + 4; + } + } + } + return false; + } +} \ No newline at end of file diff --git a/src/TODO b/src/TODO index 3670021..c52b5b4 100644 --- a/src/TODO +++ b/src/TODO @@ -1,18 +1,17 @@ TODO: TabbedContainers Fixed size containers -Collapseables -Textfields -Textboxes -TextDisplays -Icon buttons +Collapseable Code cleanup +Dropdowns render offscreen Being Worked on: -Dropdown +Textfields +Textboxes Done: Radio Buttons Horizontal sliders -Vertical sliders \ No newline at end of file +Vertical sliders +Dropdown \ No newline at end of file