From 46ea31a1181d73c84fdb9b30a3fcedd25e843d50 Mon Sep 17 00:00:00 2001 From: Booklordofthedings Date: Thu, 10 Oct 2024 14:53:21 +0200 Subject: [PATCH] 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