From 71999392601828a069dfa0db919e6d4f83c5973d Mon Sep 17 00:00:00 2001 From: Mike Nolan Date: Thu, 3 Jul 2025 15:49:14 -0500 Subject: [PATCH] Switch to gitea --- CMakeLists.txt | 8 +- README.md | 5 +- examples/guikitchensink.cpp | 112 ++++- include/TessesFramework/Common.hpp | 1 + include/TessesFramework/SDL2/GUI.hpp | 104 +++- .../TessesFramework/SDL2/Views/ButtonView.hpp | 2 +- .../SDL2/Views/DropDownView.hpp | 23 + .../SDL2/Views/HScrollView.hpp | 24 + .../TessesFramework/SDL2/Views/HStackView.hpp | 27 ++ .../SDL2/Views/MultilineEditTextView.hpp | 27 ++ .../SDL2/Views/ScrollableTextListView.hpp | 21 + .../SDL2/Views/TextListView.hpp | 1 + .../SDL2/Views/VScrollView.hpp | 24 + .../TessesFramework/SDL2/Views/VStackView.hpp | 29 ++ src/SDL2/GUI.cpp | 65 ++- src/SDL2/GUIPopup.cpp | 105 +++++ src/SDL2/GUIWindow.cpp | 282 ++++++++++- src/SDL2/View.cpp | 8 +- src/SDL2/Views/ButtonView.cpp | 18 +- src/SDL2/Views/CheckView.cpp | 16 +- src/SDL2/Views/DropDownView.cpp | 113 +++++ src/SDL2/Views/EditTextView.cpp | 18 +- src/SDL2/Views/HScrollView.cpp | 329 +++++++++++++ src/SDL2/Views/HStackView.cpp | 273 +++++++++++ src/SDL2/Views/LabelView.cpp | 2 +- src/SDL2/Views/MultilineEditTextView.cpp | 178 +++++++ src/SDL2/Views/ProgressView.cpp | 8 +- src/SDL2/Views/ScrollableTextListView.cpp | 444 ++++++++++++++++++ src/SDL2/Views/TextListView.cpp | 20 +- src/SDL2/Views/VScrollView.cpp | 322 +++++++++++++ src/SDL2/Views/VStackView.cpp | 270 +++++++++++ src/TF_Init.cpp | 35 +- 32 files changed, 2820 insertions(+), 94 deletions(-) create mode 100644 include/TessesFramework/SDL2/Views/DropDownView.hpp create mode 100644 include/TessesFramework/SDL2/Views/HScrollView.hpp create mode 100644 include/TessesFramework/SDL2/Views/HStackView.hpp create mode 100644 include/TessesFramework/SDL2/Views/MultilineEditTextView.hpp create mode 100644 include/TessesFramework/SDL2/Views/ScrollableTextListView.hpp create mode 100644 include/TessesFramework/SDL2/Views/VScrollView.hpp create mode 100644 include/TessesFramework/SDL2/Views/VStackView.hpp create mode 100644 src/SDL2/GUIPopup.cpp create mode 100644 src/SDL2/Views/DropDownView.cpp create mode 100644 src/SDL2/Views/HScrollView.cpp create mode 100644 src/SDL2/Views/HStackView.cpp create mode 100644 src/SDL2/Views/MultilineEditTextView.cpp create mode 100644 src/SDL2/Views/ScrollableTextListView.cpp create mode 100644 src/SDL2/Views/VScrollView.cpp create mode 100644 src/SDL2/Views/VStackView.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 32dbf13..e9a1d06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,16 +55,22 @@ src/SDL2/FontCache.cpp src/SDL2/Stream.cpp src/SDL2/GUI.cpp src/SDL2/GUIWindow.cpp +src/SDL2/GUIPopup.cpp src/SDL2/View.cpp src/SDL2/Views/ButtonView.cpp src/SDL2/Views/AbsoluteView.cpp src/SDL2/Views/LabelView.cpp src/SDL2/Views/TextListView.cpp +src/SDL2/Views/ScrollableTextListView.cpp src/SDL2/Views/ProgressView.cpp src/SDL2/Views/CheckView.cpp src/SDL2/Views/EditTextView.cpp src/SDL2/Views/PictureView.cpp - +src/SDL2/Views/VScrollView.cpp +src/SDL2/Views/HScrollView.cpp +src/SDL2/Views/VStackView.cpp +src/SDL2/Views/HStackView.cpp +src/SDL2/Views/DropDownView.cpp ) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) diff --git a/README.md b/README.md index 3b53e04..306fb85 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,16 @@ Tesses Framework ================ +## If you are on onedev +We are switching to [gitea](https://git.tesseslanguage.com/tesses50/tesses-framework) + ## To Install - Install [mbedtls](https://github.com/Mbed-TLS/mbedtls) (use sudo apt install libmbedtls-dev on debian) for TessesFramework - Follow the commands bellow ## Run these commands to install tesses-framework ```bash -git clone https://onedev.site.tesses.net/tesses-framework +git clone https://git.tesseslanguage.com/tesses-framework cd tesses-framework mkdir build cd build diff --git a/examples/guikitchensink.cpp b/examples/guikitchensink.cpp index 79a5ddf..86e157f 100644 --- a/examples/guikitchensink.cpp +++ b/examples/guikitchensink.cpp @@ -2,22 +2,43 @@ #if defined(TESSESFRAMEWORK_ENABLE_SDL2) #define SDL_MAIN_HANDLED +#include "TessesFramework/Streams/MemoryStream.hpp" +#include "TessesFramework/Http/HttpClient.hpp" +#include "TessesFramework/SDL2/Stream.hpp" #include "TessesFramework/SDL2/GUI.hpp" #include "TessesFramework/SDL2/Views/ButtonView.hpp" #include "TessesFramework/SDL2/Views/AbsoluteView.hpp" #include "TessesFramework/SDL2/Views/LabelView.hpp" -#include "TessesFramework/SDL2/Views/TextListView.hpp" +#include "TessesFramework/SDL2/Views/ScrollableTextListView.hpp" #include "TessesFramework/Filesystem/LocalFS.hpp" #include "TessesFramework/SDL2/Views/ProgressView.hpp" #include "TessesFramework/SDL2/Views/CheckView.hpp" #include "TessesFramework/SDL2/Views/EditTextView.hpp" +#include "TessesFramework/SDL2/Views/PictureView.hpp" +#include "TessesFramework/SDL2/Views/VScrollView.hpp" +#include "TessesFramework/SDL2/Views/HScrollView.hpp" +#include "TessesFramework/SDL2/Views/VStackView.hpp" +#include "TessesFramework/SDL2/Views/HStackView.hpp" +#include "TessesFramework/SDL2/Views/DropDownView.hpp" +#include #include using namespace Tesses::Framework; using namespace Tesses::Framework::SDL2; + #endif - +void LoadImage(Views::PictureView& view) +{ + using namespace Tesses::Framework::Streams; + using namespace Tesses::Framework::Http; + MemoryStream strm(true); + + DownloadToStreamSimple("https://s.ytimg.com/vi/lItUxNQnzME/maxresdefault.jpg",strm); + strm.Seek(0L,SeekOrigin::Begin); + auto res = RwopsFromStream(&strm,false); + view.SetPicture(IMG_Load_RW(res,1),true); +} int main(int argc,char** argv) { @@ -25,6 +46,9 @@ int main(int argc,char** argv) TF_Init(); + //std::cout << GUI_EXPAND_N(argc) << std::endl; + + std::vector> colors={ std::pair({.r=255,.g=0,.b=128,.a=255},"Magenta"), std::pair({.r=255,.g=0,.b=0,.a=255}, "Red"), @@ -38,23 +62,36 @@ int main(int argc,char** argv) bool darkMode=true; size_t color_index=0; - GUIPalette pal0(darkMode,colors[color_index % colors.size()].first,20); + + GUIPalette pal0(darkMode,colors[color_index % colors.size()].first,20,2); TF_LOG("Create pallete"); - GUIWindow window("My Window Title",1280,720,SDL_WINDOW_RESIZABLE,pal0); + GUIWindow* window = new GUIWindow("My Window Title",1280,720,SDL_WINDOW_RESIZABLE,pal0); TF_LOG("Created GUIWindow success"); Views::LabelView lbl("A random label\nThat spans lines."); Views::ButtonView btn("Dark Mode"); Views::ButtonView btn2(colors[0].second); + Views::ButtonView btn3("Popup"); + Views::ButtonView btn4("Window"); Views::ProgressView progress(42.42); Views::CheckView cv(false,"Checkbox"); Views::CheckView cv2(false,"Another Checkbox"); Views::EditTextView edit("Enter some text"); + Views::DropDownView ddv; + ddv.GetItems()={ + "Al Gore", + "Demi Lovato", + "Steve Ballmer" + }; - Views::TextListView list; + Views::ScrollableTextListView list; + for(int i = 0; i < 100; i++) + { + list.items.push_back(std::to_string(i)); + } /*for(auto item : Tesses::Framework::Filesystem::LocalFS.EnumeratePaths((std::string)"/usr/bin")) { list.items.push_back(item.GetFileName()); @@ -63,7 +100,7 @@ int main(int argc,char** argv) //Views::LabelView labelView("My Sweet Label"); - + Views::AbsoluteView abs; abs.Add({.x=0,.y=0,.w=400,.h=64},&lbl,false); abs.Add({.x=32,.y=64,.w=200,.h=50},&btn,false); @@ -80,8 +117,49 @@ int main(int argc,char** argv) abs.Add({.x=32,.y=478,.w=300,.h=200},&edit,false); - window.SetView(&abs,false); - window.SDLEvent += std::make_shared>([&window,&lbl](View* sender, GUISDLEventEventArgs& e)->void { + Views::VScrollView vscroll(0,0,10); + Views::HScrollView hscroll(0,0,10); + + Views::LabelView lbl2("ScrollPos"); + + vscroll.ValueChanged += std::make_shared>( + [&](View* sender,GUIEventArgs& e)->void { + lbl2.SetText("ScrollPos: " + std::to_string(vscroll.value)); + } + ); + + Views::PictureView img; + LoadImage(img); + + abs.Add({.x=460,.y=32,.w=640,.h=480},&img,false); + + abs.Add({.x=1280-42,.y=2,.w=32,.h=720-20},&vscroll,false); + + abs.Add({.x=720,.y=720-100,.w=200,.h=100},&lbl2,false); + + + Views::VStackView vstack; + vstack.Add(GUI_MIN,&edit,false); + vstack.Add(GUI_MIN,&btn3,false); + vstack.Add(32,&ddv,false); + vstack.Add(GUI_MIN,&btn4,false); + + vstack.Add(GUI_EXPAND,&btn,false); + + + + vstack.Add(GUI_EXPAND_N(10),&list,false); + vstack.Add(GUI_EXPAND,&btn2,false); + + vstack.Add(GUI_MIN,&hscroll,false); + + Views::HStackView hstack; + hstack.Add(GUI_EXPAND,&vstack,false); + hstack.Add(GUI_MIN,&vscroll,false); + + window->SetView(&hstack,false); + //window.SetView(&abs,false); + window->SDLEvent += std::make_shared>([&window,&lbl](View* sender, GUISDLEventEventArgs& e)->void { std::string sdl2_event = "SDL_Event: " + std::to_string(e.event.type); TF_LOG(sdl2_event); if(e.event.type == SDL_EventType::SDL_WINDOWEVENT) @@ -98,7 +176,7 @@ int main(int argc,char** argv) darkMode = !darkMode; btn.SetText(darkMode ? "Light Mode" : "Dark Mode"); GUIPalette palette(darkMode,colors[color_index % colors.size()].first,20); - window.SetPalette(palette); + window->SetPalette(palette); }); //"A random label\nThat spans lines." @@ -107,9 +185,23 @@ int main(int argc,char** argv) btn2.SetText(colors[color_index % colors.size()].second); GUIPalette palette(darkMode,colors[color_index % colors.size()].first,20); - window.SetPalette(palette); + window->SetPalette(palette); }); + + Views::LabelView lbl3; + + GUIContainerPopup popup(42,42,300,200); + popup.SetView(&lbl3,false); + btn3.Click += std::make_shared>([&](View* sender, GUIEventArgs& e)->void{ + lbl3.SetText(edit.GetText()); + window->ShowPopup(popup); + }); + + //window("My Window Title",1280,720,SDL_WINDOW_RESIZABLE,pal0); + btn4.Click += std::make_shared>([&](View* sender, GUIEventArgs& e)->void{ + new GUIWindow("My Second Window",640,480,0,pal0); + }); TF_RunEventLoop(); diff --git a/include/TessesFramework/Common.hpp b/include/TessesFramework/Common.hpp index 1c75c38..1b0f0f7 100644 --- a/include/TessesFramework/Common.hpp +++ b/include/TessesFramework/Common.hpp @@ -112,6 +112,7 @@ namespace Tesses::Framework bool TF_GetConsoleEventsEnabled(); void TF_SetConsoleEventsEnabled(bool flag); void TF_InitConsole(); + void TF_Invoke(std::function cb); #if defined(TESSESFRAMEWORK_LOGTOFILE) void TF_Log(std::string dataToLog); diff --git a/include/TessesFramework/SDL2/GUI.hpp b/include/TessesFramework/SDL2/GUI.hpp index 657d64b..5e6ac17 100644 --- a/include/TessesFramework/SDL2/GUI.hpp +++ b/include/TessesFramework/SDL2/GUI.hpp @@ -12,15 +12,16 @@ namespace Tesses::Framework::SDL2 class GUIPalette { public: GUIPalette(); - GUIPalette(bool isDarkMode, SDL_Color accent,int fontSize=24); - GUIPalette(SDL_Color accent, SDL_Color background, SDL_Color border_color, SDL_Color border_hover, SDL_Color border_active, SDL_Color border_hover_active, int fontSize=24); + GUIPalette(bool isDarkMode, SDL_Color accent,int fontSize=24,int borderSize=2); + GUIPalette(SDL_Color accent, SDL_Color background, SDL_Color borderColor, SDL_Color borderHover, SDL_Color borderActive, SDL_Color borderHoverActive, int fontSize=24,int borderSize=2); SDL_Color accent; //color is used for font when not over accent background SDL_Color background; - SDL_Color border_color; //color is used for font when over accent background - SDL_Color border_hover; - SDL_Color border_active; - SDL_Color border_hover_active; + SDL_Color borderColor; //color is used for font when over accent background + SDL_Color borderHover; + SDL_Color borderActive; + SDL_Color borderHoverActive; int fontSize; + int borderSize; SDL_Color& GetBorderColor(bool isHovering, bool isActive, bool isMouseDown); }; @@ -32,6 +33,12 @@ namespace Tesses::Framework::SDL2 virtual ~GUIEventArgs(); }; class View; + class GUIWindowClosingEventArgs : public GUIEventArgs + { + public: + bool cancel; + std::string Type(); + }; class GUIMouseButtonEventArgs : public GUIEventArgs { public: @@ -62,6 +69,22 @@ namespace Tesses::Framework::SDL2 constexpr uint64_t VIEWFLAG_INTERCEPT_TAB=(uint64_t)1<<4; constexpr uint64_t VIEWFLAG_CHECKED=(uint64_t)1<<5; constexpr uint64_t VIEWFLAG_TOUCHED=(uint64_t)1<<6; + constexpr uint64_t VIEWFLAG_HOVER_B1STATE=(uint64_t)1<<7; //for scrollbar buttons + constexpr uint64_t VIEWFLAG_HOVER_B2STATE=(uint64_t)1<<8; //for scrollbar buttons + constexpr uint64_t VIEWFLAG_MOUSEDOWN_B1STATE=(uint64_t)1<<9; //for scrollbar buttons + constexpr uint64_t VIEWFLAG_MOUSEDOWN_B2STATE=(uint64_t)1<<10; //for scrollbar buttons + + constexpr int GUI_EXPAND = -1; + constexpr int GUI_MIN = 0; + + + constexpr int GUI_EXPAND_N(int n) + { + if(n < 0) return n; + return -n; + } + + class GUIPopup; class GUIWindow; class ContainerView; @@ -161,25 +184,71 @@ namespace Tesses::Framework::SDL2 Done }; class GUIPopup : public ContainerView { - View* child; - bool ownsChild; protected: - void OnDraw(SDL_Renderer* renderer, SDL_Rect& myRect); - bool OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds); - public: + bool closed=true; + virtual View* GetView()=0; - size_t ViewCount(); - View* GetViewAt(size_t index); + virtual void OnDraw(SDL_Renderer* renderer, SDL_Rect& myRect); + virtual bool OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds); + public: GUIPopup(); GUIPopup(SDL_Rect bounds); GUIPopup(int x, int y,int w, int h); SDL_Rect bounds; - - void SetView(View* view, bool owns=true); - ~GUIPopup(); + bool closeIfClickOutside=true; + + virtual void Close(); + virtual bool IsClosed(); + virtual ~GUIPopup(); + + size_t ViewCount(); + View* GetViewAt(size_t index); + + bool IsActive(); friend class GUIWindow; }; + class GUIContainerPopup : public GUIPopup + { + View* child; + bool ownsChild; + protected: + View* GetView(); + public: + GUIContainerPopup(); + GUIContainerPopup(SDL_Rect bounds); + GUIContainerPopup(int x, int y,int w, int h); + + void SetView(View* view, bool owns=true); + + ~GUIContainerPopup(); + }; + class GUIDialog : public GUIPopup { + protected: + virtual void OnDraw(SDL_Renderer* renderer, SDL_Rect& myRect); + virtual bool OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds); + public: + GUIDialog(); + GUIDialog(SDL_Rect bounds); + GUIDialog(int x,int y, int w, int h); + virtual ~GUIDialog(); + }; + class GUIContainerDialog : public GUIDialog + { + View* v; + bool owns=false; + protected: + View* GetView(); + public: + GUIContainerDialog(); + GUIContainerDialog(SDL_Rect bounds); + GUIContainerDialog(int x, int y,int w, int h); + void SetView(View* view, bool owns=true); + size_t ViewCount(); + View* GetViewAt(size_t index); + ~GUIContainerDialog(); + }; + class GUIWindow : public ContainerView { std::vector popups; @@ -198,6 +267,7 @@ namespace Tesses::Framework::SDL2 public: EventList JsonViewNotFound; + EventList Closing; size_t ViewCount(); View* GetViewAt(size_t index); FontCache* normal_font; @@ -228,6 +298,7 @@ namespace Tesses::Framework::SDL2 SDL_Renderer* GetSDLRenderer(); View* CreateViewFromJson(Tesses::Framework::Serialization::Json::JObject json); + operator bool(); }; @@ -235,6 +306,7 @@ namespace Tesses::Framework::SDL2 std::vector windows; public: void Update(); + void CloseWindows(); friend class GUIWindow; }; extern GUI gui; diff --git a/include/TessesFramework/SDL2/Views/ButtonView.hpp b/include/TessesFramework/SDL2/Views/ButtonView.hpp index a18914c..0e2b271 100644 --- a/include/TessesFramework/SDL2/Views/ButtonView.hpp +++ b/include/TessesFramework/SDL2/Views/ButtonView.hpp @@ -12,7 +12,7 @@ namespace Tesses::Framework::SDL2::Views public: ButtonView(); ButtonView(std::string text); - + virtual std::pair PreferedMinSize(); }; } #endif \ No newline at end of file diff --git a/include/TessesFramework/SDL2/Views/DropDownView.hpp b/include/TessesFramework/SDL2/Views/DropDownView.hpp new file mode 100644 index 0000000..03f69e2 --- /dev/null +++ b/include/TessesFramework/SDL2/Views/DropDownView.hpp @@ -0,0 +1,23 @@ +#pragma once +#if defined(TESSESFRAMEWORK_ENABLE_SDL2) +#include "../GUI.hpp" +#include "ScrollableTextListView.hpp" + +namespace Tesses::Framework::SDL2::Views +{ + class DropDownView : public View { + + GUIContainerPopup popup; + ScrollableTextListView listView; + bool hasSet=false; + protected: + virtual void OnDraw(SDL_Renderer* renderer, SDL_Rect& r); + virtual bool OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds); + public: + DropDownView(); + std::vector& GetItems(); + void SetIndex(int index); + int GetIndex(); + }; +} +#endif \ No newline at end of file diff --git a/include/TessesFramework/SDL2/Views/HScrollView.hpp b/include/TessesFramework/SDL2/Views/HScrollView.hpp new file mode 100644 index 0000000..1bbd045 --- /dev/null +++ b/include/TessesFramework/SDL2/Views/HScrollView.hpp @@ -0,0 +1,24 @@ +#pragma once +#if defined(TESSESFRAMEWORK_ENABLE_SDL2) +#include "../GUI.hpp" + +namespace Tesses::Framework::SDL2::Views +{ + class HScrollView : public View { + protected: + virtual void OnValueChanged(GUIEventArgs& e); + virtual void OnDraw(SDL_Renderer* renderer, SDL_Rect& r); + virtual bool OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds); + public: + HScrollView(); + HScrollView(uint64_t value, uint64_t min, uint64_t max,uint64_t step=1); + uint64_t value; + uint64_t min; + uint64_t max; + uint64_t step; + EventList ValueChanged; + + std::pair PreferedMinSize(); + }; +} +#endif \ No newline at end of file diff --git a/include/TessesFramework/SDL2/Views/HStackView.hpp b/include/TessesFramework/SDL2/Views/HStackView.hpp new file mode 100644 index 0000000..b498d06 --- /dev/null +++ b/include/TessesFramework/SDL2/Views/HStackView.hpp @@ -0,0 +1,27 @@ +#pragma once +#if defined(TESSESFRAMEWORK_ENABLE_SDL2) +#include "../GUI.hpp" + +namespace Tesses::Framework::SDL2::Views +{ + class HStackView : public ContainerView { + + std::vector>> items; + protected: + virtual void OnDraw(SDL_Renderer* renderer, SDL_Rect& r); + virtual bool OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds); + public: + HStackView(); + int spacing=0; + + void Add(int sz, View* view, bool owns=true); + void Remove(View* view); + void Clear(); + + virtual size_t ViewCount(); + virtual View* GetViewAt(size_t index); + + virtual ~HStackView(); + }; +} +#endif \ No newline at end of file diff --git a/include/TessesFramework/SDL2/Views/MultilineEditTextView.hpp b/include/TessesFramework/SDL2/Views/MultilineEditTextView.hpp new file mode 100644 index 0000000..b77797d --- /dev/null +++ b/include/TessesFramework/SDL2/Views/MultilineEditTextView.hpp @@ -0,0 +1,27 @@ +#pragma once +#if defined(TESSESFRAMEWORK_ENABLE_SDL2) +#include "../GUI.hpp" + +namespace Tesses::Framework::SDL2::Views +{ + class MultilineEditTextView : public View { + protected: + virtual void OnDraw(SDL_Renderer* renderer, SDL_Rect& r); + virtual bool OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds); + std::string hint; + std::vector lines; + SDL_Point topLeft={.x=0,.y=0}; + SDL_Point cursorPos={.x=0,.y=0}; + SDL_Point cursorEnd={.x=-1,.y=-1}; + public: + MultilineEditTextView(); + MultilineEditTextView(std::string hint); + virtual std::string GetHint(); + virtual void SetHint(std::string hint); + virtual std::string GetText(); + virtual void SetText(std::string text); + virtual void TypeText(std::string text); + virtual std::pair PreferedMinSize(); + }; +} +#endif \ No newline at end of file diff --git a/include/TessesFramework/SDL2/Views/ScrollableTextListView.hpp b/include/TessesFramework/SDL2/Views/ScrollableTextListView.hpp new file mode 100644 index 0000000..053a7ae --- /dev/null +++ b/include/TessesFramework/SDL2/Views/ScrollableTextListView.hpp @@ -0,0 +1,21 @@ +#pragma once +#if defined(TESSESFRAMEWORK_ENABLE_SDL2) +#include "../GUI.hpp" + +namespace Tesses::Framework::SDL2::Views +{ + class ScrollableTextListView : public View { + + protected: + virtual void OnDraw(SDL_Renderer* renderer, SDL_Rect& r); + virtual bool OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds); + public: + ScrollableTextListView(); + size_t firstIndex; + int selected; + std::vector items; + + EventList ValueChanged; + }; +} +#endif \ No newline at end of file diff --git a/include/TessesFramework/SDL2/Views/TextListView.hpp b/include/TessesFramework/SDL2/Views/TextListView.hpp index 9b62fae..c6a4316 100644 --- a/include/TessesFramework/SDL2/Views/TextListView.hpp +++ b/include/TessesFramework/SDL2/Views/TextListView.hpp @@ -15,6 +15,7 @@ namespace Tesses::Framework::SDL2::Views int selected; std::vector items; + EventList ValueChanged; }; } #endif \ No newline at end of file diff --git a/include/TessesFramework/SDL2/Views/VScrollView.hpp b/include/TessesFramework/SDL2/Views/VScrollView.hpp new file mode 100644 index 0000000..fbedaa5 --- /dev/null +++ b/include/TessesFramework/SDL2/Views/VScrollView.hpp @@ -0,0 +1,24 @@ +#pragma once +#if defined(TESSESFRAMEWORK_ENABLE_SDL2) +#include "../GUI.hpp" + +namespace Tesses::Framework::SDL2::Views +{ + class VScrollView : public View { + protected: + virtual void OnValueChanged(GUIEventArgs& e); + virtual void OnDraw(SDL_Renderer* renderer, SDL_Rect& r); + virtual bool OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds); + public: + VScrollView(); + VScrollView(uint64_t value, uint64_t min, uint64_t max,uint64_t step=1); + uint64_t value; + uint64_t min; + uint64_t max; + uint64_t step; + EventList ValueChanged; + + std::pair PreferedMinSize(); + }; +} +#endif \ No newline at end of file diff --git a/include/TessesFramework/SDL2/Views/VStackView.hpp b/include/TessesFramework/SDL2/Views/VStackView.hpp new file mode 100644 index 0000000..3ab1394 --- /dev/null +++ b/include/TessesFramework/SDL2/Views/VStackView.hpp @@ -0,0 +1,29 @@ +#pragma once +#if defined(TESSESFRAMEWORK_ENABLE_SDL2) +#include "../GUI.hpp" + +namespace Tesses::Framework::SDL2::Views +{ + class VStackView : public ContainerView { + + std::vector>> items; + protected: + virtual void OnDraw(SDL_Renderer* renderer, SDL_Rect& r); + virtual bool OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds); + public: + VStackView(); + int spacing=0; + + void Add(int sz, View* view, bool owns=true); + void Remove(View* view); + void Clear(); + + virtual size_t ViewCount(); + virtual View* GetViewAt(size_t index); + + virtual ~VStackView(); + + + }; +} +#endif \ No newline at end of file diff --git a/src/SDL2/GUI.cpp b/src/SDL2/GUI.cpp index af00c38..e518600 100644 --- a/src/SDL2/GUI.cpp +++ b/src/SDL2/GUI.cpp @@ -9,6 +9,12 @@ extern "C" { namespace Tesses::Framework::SDL2 { GUI gui; + void GUI::CloseWindows() + { + auto wins=this->windows; + for(auto win : wins) delete win; + this->windows.clear(); + } void GUI::Update() { if(this->windows.empty()) return; @@ -28,7 +34,8 @@ namespace Tesses::Framework::SDL2 SDL_Event event; while(SDL_PollEvent(&event)) { - for(auto win : this->windows) + auto windows = this->windows; + for(auto& win : windows) { if(win == nullptr) continue; auto id = SDL_GetWindowID(win->window); @@ -37,6 +44,18 @@ namespace Tesses::Framework::SDL2 case SDL_EventType::SDL_WINDOWEVENT: if(event.window.windowID == id) { + if(event.window.event == SDL_WINDOWEVENT_CLOSE) + { + GUIWindowClosingEventArgs e; + e.cancel=false; + win->Closing.Invoke(win,e); + if(!e.cancel) + { + delete win; + continue; + } + } + else win->Event(event); } break; @@ -168,28 +187,31 @@ namespace Tesses::Framework::SDL2 GUIPalette::GUIPalette() { this->fontSize=24; + this->borderSize = 2; } SDL_Color& GUIPalette::GetBorderColor(bool isHovering, bool isActive, bool isMouseDown) { bool isHovering2=isHovering ^ isMouseDown; if(isHovering2 && isActive) - return this->border_hover_active; + return this->borderHoverActive; if(isHovering2) - return this->border_hover; + return this->borderHover; if(isActive) - return this->border_active; - return this->border_color; + return this->borderActive; + return this->borderColor; } - GUIPalette::GUIPalette(SDL_Color accent, SDL_Color background, SDL_Color border_color, SDL_Color border_hover, SDL_Color border_active, SDL_Color border_hover_active, int fontSize) + GUIPalette::GUIPalette(SDL_Color accent, SDL_Color background, SDL_Color border_color, SDL_Color border_hover, SDL_Color border_active, SDL_Color border_hover_active, int fontSize,int borderSize) { + this->accent=accent; this->background = background; - this->border_color=border_color; - this->border_hover = border_hover; - this->border_active = border_active; - this->border_hover_active=border_hover_active; + this->borderColor=border_color; + this->borderHover = border_hover; + this->borderActive = border_active; + this->borderHoverActive=border_hover_active; this->fontSize = fontSize; + this->borderSize = borderSize; } std::string GUIEventArgs::Type() @@ -212,33 +234,38 @@ namespace Tesses::Framework::SDL2 { return "SDLEvent"; } + std::string GUIWindowClosingEventArgs::Type() + { + return "WindowClosing"; + } - GUIPalette::GUIPalette(bool isDarkMode, SDL_Color accent,int fontSize) + GUIPalette::GUIPalette(bool isDarkMode, SDL_Color accent,int fontSize,int borderSize) { this->accent = accent; this->fontSize = fontSize; + this->borderSize = borderSize; if(isDarkMode) { this->background = {.r = 42,.g=42,.b=42,.a=255}; - this->border_color = {.r=0,.g=0,.b=0,.a=255}; - this->border_hover = {.r=92,.g=92,.b=92,.a=255}; + this->borderColor = {.r=0,.g=0,.b=0,.a=255}; + this->borderHover = {.r=92,.g=92,.b=92,.a=255}; - this->border_active = {.r=200,.g=200,.b=200,.a=255}; - this->border_hover_active = {.r=(uint8_t)(255-accent.r),.g=(uint8_t)(255-accent.g),.b=(uint8_t)(255-accent.b),.a=255}; + this->borderActive = {.r=200,.g=200,.b=200,.a=255}; + this->borderHoverActive = {.r=(uint8_t)(255-accent.r),.g=(uint8_t)(255-accent.g),.b=(uint8_t)(255-accent.b),.a=255}; } else { this->background = {.r=239,.g=239,.b=239,.a=255}; - this->border_color = {.r=0,.g=0,.b=0,.a=255}; + this->borderColor = {.r=0,.g=0,.b=0,.a=255}; - this->border_active = {.r=92,.g=92,.b=92,.a=255}; + this->borderActive = {.r=92,.g=92,.b=92,.a=255}; - this->border_hover = {.r=200,.g=200,.b=200,.a=255}; + this->borderHover = {.r=200,.g=200,.b=200,.a=255}; - this->border_hover_active = {.r=(uint8_t)(255-accent.r),.g=(uint8_t)(255-accent.g),.b=(uint8_t)(255-accent.b),.a=255}; + this->borderHoverActive = {.r=(uint8_t)(255-accent.r),.g=(uint8_t)(255-accent.g),.b=(uint8_t)(255-accent.b),.a=255}; } } diff --git a/src/SDL2/GUIPopup.cpp b/src/SDL2/GUIPopup.cpp new file mode 100644 index 0000000..7b62a1c --- /dev/null +++ b/src/SDL2/GUIPopup.cpp @@ -0,0 +1,105 @@ +#if defined(TESSESFRAMEWORK_ENABLE_SDL2) +#include "TessesFramework/SDL2/GUI.hpp" + +namespace Tesses::Framework::SDL2 { +size_t GUIPopup::ViewCount() +{ + return this->GetView() != nullptr ? 1 : 0; +} +View* GUIPopup::GetViewAt(size_t index) +{ + if(index > 0) return nullptr; + return this->GetView(); +} +GUIPopup::GUIPopup() : GUIPopup(0,0,0,0) +{ + +} +GUIPopup::GUIPopup(SDL_Rect bounds) +{ + this->bounds = bounds; +} +GUIPopup::GUIPopup(int x, int y,int w, int h) +{ + this->bounds.x = x; + this->bounds.y = y; + this->bounds.w = w; + this->bounds.h = h; +} +View* GUIContainerPopup::GetView() +{ + return this->child; +} +GUIContainerPopup::GUIContainerPopup() : GUIPopup() +{ + +} +GUIContainerPopup::GUIContainerPopup(SDL_Rect bounds) : GUIPopup(bounds) +{ + +} +GUIContainerPopup::GUIContainerPopup(int x, int y,int w, int h) : GUIPopup(x,y,w,h) +{ + +} + + +void GUIContainerPopup::SetView(View* view, bool owns) +{ + if(this->ownsChild && this->child != view) + delete this->child; + this->child = view; + this->ownsChild=owns; + this->AssignChildParentToThis(view); +} +GUIContainerPopup::~GUIContainerPopup() +{ + if(this->ownsChild) + delete this->child; +} +GUIPopup::~GUIPopup() +{ + +} + +void GUIPopup::Close() +{ + + this->closed=true; +} +bool GUIPopup::IsClosed() +{ + return this->closed; +} + +void GUIPopup::OnDraw(SDL_Renderer* renderer, SDL_Rect& r) +{ + auto win = this->GetWindow(); + SDL_SetRenderDrawColor(renderer,win->palette.background.r,win->palette.background.g,win->palette.background.b,win->palette.background.a); + SDL_RenderFillRect(renderer,&r); + auto view = GetView(); + if(view != nullptr) + CallOnDraw(view,renderer,r); +} +bool GUIPopup::OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& myVisibleBounds) +{ + auto view = GetView(); + if(view != nullptr) + { + if(CallOnEvent(view,event,myBounds,myVisibleBounds)) return true; + } + + return View::OnEvent(event,myBounds,myVisibleBounds); +} + +bool GUIPopup::IsActive() +{ + auto win = this->GetWindow(); + if(win == nullptr) return false; + if(win->popups.empty()) return false; + + return win->popups.back() == this; +} + +} +#endif \ No newline at end of file diff --git a/src/SDL2/GUIWindow.cpp b/src/SDL2/GUIWindow.cpp index 3bf12c4..252e6c6 100644 --- a/src/SDL2/GUIWindow.cpp +++ b/src/SDL2/GUIWindow.cpp @@ -9,6 +9,12 @@ #include "TessesFramework/SDL2/Views/AbsoluteView.hpp" #include "TessesFramework/SDL2/Views/EditTextView.hpp" #include "TessesFramework/SDL2/Views/PictureView.hpp" +#include "TessesFramework/SDL2/Views/ScrollableTextListView.hpp" +#include "TessesFramework/SDL2/Views/HScrollView.hpp" +#include "TessesFramework/SDL2/Views/VScrollView.hpp" +#include "TessesFramework/SDL2/Views/HStackView.hpp" +#include "TessesFramework/SDL2/Views/VStackView.hpp" +#include "TessesFramework/SDL2/Views/DropDownView.hpp" #include "TessesFramework/SDL2/ParseColor.hpp" #if defined(__SWITCH__) @@ -19,11 +25,23 @@ extern "C" { namespace Tesses::Framework::SDL2 { + GUIWindow::operator bool() + { + if(this == nullptr) return false; + for(auto item : gui.windows) + if(item == this) return true; + return false; + } void GUIWindow::MakeActive(View* view) { if(!view->GetViewFlag(VIEWFLAG_TABSTOP)) return; if(view->GetViewFlag(VIEWFLAG_ISACTIVE)) return; + if(this->popups.empty()) DeactivateAll(this); + else + { + DeactivateAll(this->popups.back()); + } view->SetViewFlag(VIEWFLAG_ISACTIVE,true); } void GUIWindow::DeactivateAll(View* view) @@ -123,6 +141,7 @@ namespace Tesses::Framework::SDL2 } void GUIWindow::Event(SDL_Event& event) { + int w,h; SDL_GetWindowSize(window,&w,&h); SDL_Rect r={.x=0,.y=0,.w=w,.h=h}; @@ -135,6 +154,8 @@ namespace Tesses::Framework::SDL2 SDL_RenderClear(renderer); if(this->child != nullptr) this->child->OnDraw(renderer,r); + for(auto popup : this->popups) + popup->OnDraw(renderer,popup->bounds); SDL_RenderPresent(renderer); } bool GUIWindow::OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& myVisibleBounds) @@ -145,11 +166,75 @@ namespace Tesses::Framework::SDL2 GUISDLEventEventArgs sdle; sdle.event = event; this->SDLEvent.Invoke(this,sdle); - TabNext(); + if(this->popups.empty()) + TabNext(); + else + { + TabNextResult nr=TabNextResult::KeepGoing; + TabNext(this->popups.back(),nr); + if(nr != TabNextResult::Done) + { + nr = TabNextResult::TabNext; + TabNext(this->popups.back(),nr); + } + } return true; } - if(this->child != nullptr) { GUISDLEventEventArgs sdle; - sdle.event = event; this->SDLEvent.Invoke(this,sdle); return this->child->OnEvent(event,myBounds,myVisibleBounds);} + if(this->child != nullptr) { + GUISDLEventEventArgs sdle; + sdle.event = event; this->SDLEvent.Invoke(this,sdle); + retry: + if(this->popups.empty()) + return this->child->OnEvent(event,myBounds,myVisibleBounds); + else { + if(event.type == SDL_MOUSEBUTTONDOWN) + { + auto popup = this->popups.back(); + if(event.button.x >= popup->bounds.x && event.button.x < popup->bounds.x+popup->bounds.w && event.button.y >= popup->bounds.y && event.button.y < popup->bounds.y+popup->bounds.h) + { + return popup->OnEvent(event,popup->bounds,popup->bounds); + } + else if(popup->closeIfClickOutside) { + popup->closed=true; + this->popups.pop_back(); + goto retry; + } + return false; + } + else { + auto popup = this->popups.back(); + return popup->OnEvent(event,popup->bounds,popup->bounds); + + } + } + } + retry2: + if(!this->popups.empty()) + { + + if(event.type == SDL_MOUSEBUTTONDOWN) + { + auto popup = this->popups.back(); + if(event.button.x >= popup->bounds.x && event.button.x < popup->bounds.x+popup->bounds.w && event.button.y >= popup->bounds.y && event.button.y < popup->bounds.y+popup->bounds.h) + { + return popup->OnEvent(event,popup->bounds,popup->bounds); + } + else if(popup->closeIfClickOutside) + { + popup->closed=true; + this->popups.pop_back(); + goto retry2; + } + return false; + } + else + { + auto popup = this->popups.back(); + return popup->OnEvent(event,popup->bounds,popup->bounds); + + } + + } return View::OnEvent(event,myBounds,myVisibleBounds); } GUIWindow::GUIWindow(std::string title, int w, int h, Uint32 flags, const GUIPalette& palette) : ContainerView(title) @@ -245,6 +330,36 @@ namespace Tesses::Framework::SDL2 } } } + + void GUIWindow::ShowPopup(GUIPopup* popup) + { + popup->closed=false; + bool has = false; + for(auto item : this->popups) + if(item == popup) { has=true; break;} + if(!has) + this->popups.push_back(popup); + + + + AssignChildParentToThis(popup); + + auto v = popup->GetView(); + if(v != nullptr) this->MakeActive(v); + + while(!popup->IsClosed() && TF_IsRunning()) + { + TF_RunEventLoopItteration(); + } + if(!this->popups.empty() && this->popups.back() == popup) + this->popups.pop_back(); + popup->closed=true; + } + void GUIWindow::ShowPopup(GUIPopup& popup) + { + ShowPopup(&popup); + } + void GUIWindow::SetView(Tesses::Framework::Serialization::Json::JToken item) { Tesses::Framework::Serialization::Json::JObject dict; @@ -288,13 +403,13 @@ namespace Tesses::Framework::SDL2 if(pal0.TryGetValueAsType("Background",_str)) TryParseSDLColor(_str,pal.background); if(pal0.TryGetValueAsType("Border",_str)) - TryParseSDLColor(_str,pal.border_color); + TryParseSDLColor(_str,pal.borderColor); if(pal0.TryGetValueAsType("BorderActive",_str)) - TryParseSDLColor(_str,pal.border_active); + TryParseSDLColor(_str,pal.borderActive); if(pal0.TryGetValueAsType("BorderHover",_str)) - TryParseSDLColor(_str,pal.border_hover); + TryParseSDLColor(_str,pal.borderHover); if(pal0.TryGetValueAsType("BorderHoverActive",_str)) - TryParseSDLColor(_str,pal.border_hover_active); + TryParseSDLColor(_str,pal.borderHoverActive); this->SetPalette(pal); } if(dict.TryGetValueAsType("Title",title) || dict.TryGetValueAsType("Text",title)) @@ -312,7 +427,18 @@ namespace Tesses::Framework::SDL2 return this->renderer; } - + static int szStr2size(std::string sz) + { + if(sz.empty()) return GUI_MIN; + if(sz == "min") return GUI_MIN; + if(sz == "*") return GUI_EXPAND; + if(sz[0] == '*') { + return GUI_EXPAND_N(std::stoi(sz.substr(1))); + } + else { + return std::stoi(sz); + } + } View* GUIWindow::CreateViewFromJson(Tesses::Framework::Serialization::Json::JObject json) { @@ -382,6 +508,33 @@ namespace Tesses::Framework::SDL2 tlv->selected = (int)index; return tlv; } + else if(type == "ScrollableTextListView") + { + std::vector items; + Tesses::Framework::Serialization::Json::JArray arr; + if(json.TryGetValueAsType("Items",arr)) + { + std::string str; + for(auto item : arr) + { + if(Tesses::Framework::Serialization::Json::TryGetJToken(item,str)) items.push_back(str); + } + } + int64_t index=-1; + int64_t first=0; + json.TryGetValueAsType("SelectedIndex",index); + json.TryGetValueAsType("FirstIndex",first); + + auto tlv = new Views::ScrollableTextListView(); + + tlv->SetViewFlag(VIEWFLAG_ISACTIVE,active); + tlv->SetId(id); + tlv->items = items; + tlv->firstIndex = (size_t)first; + tlv->selected = (int)index; + return tlv; + } + else if(type == "AbsoluteView") { auto av = new Views::AbsoluteView(); @@ -432,6 +585,119 @@ namespace Tesses::Framework::SDL2 pv->SetId(id); return pv; } + else if(type == "DropDownView") + { + std::vector items; + Tesses::Framework::Serialization::Json::JArray arr; + if(json.TryGetValueAsType("Items",arr)) + { + std::string str; + for(auto item : arr) + { + if(Tesses::Framework::Serialization::Json::TryGetJToken(item,str)) items.push_back(str); + } + } + int64_t index=-1; + int64_t first=0; + json.TryGetValueAsType("SelectedIndex",index); + + auto tlv = new Views::DropDownView(); + + tlv->SetViewFlag(VIEWFLAG_ISACTIVE,active); + tlv->SetId(id); + tlv->GetItems() = items; + + tlv->SetIndex((int)index); + return tlv; + } + else if(type == "VScrollView") + { + int64_t value=0; + int64_t min = 0; + int64_t max = 10; + json.TryGetValueAsType("Value",value); + + json.TryGetValueAsType("Min",min); + + json.TryGetValueAsType("Max",max); + auto vscroll=new Views::VScrollView(); + vscroll->value = (uint64_t)value; + vscroll->min = (uint64_t)min; + vscroll->max = (uint64_t)max; + vscroll->SetId(id); + return vscroll; + } + else if(type == "HScrollView") + { + int64_t value=0; + int64_t min = 0; + int64_t max = 10; + json.TryGetValueAsType("Value",value); + + json.TryGetValueAsType("Min",min); + + json.TryGetValueAsType("Max",max); + auto hscroll=new Views::VScrollView(); + hscroll->value = (uint64_t)value; + hscroll->min = (uint64_t)min; + hscroll->max = (uint64_t)max; + hscroll->SetId(id); + return hscroll; + } + else if(type == "VStackView") + { + auto sv = new Views::VStackView(); + sv->SetId(id); + Tesses::Framework::Serialization::Json::JArray arr; + if(json.TryGetValueAsType("Items",arr)) + { + for(auto item : arr) + { + Tesses::Framework::Serialization::Json::JObject dict; + if(Tesses::Framework::Serialization::Json::TryGetJToken(item,dict)) + { + std::string n="min"; + + dict.TryGetValueAsType("Size",n); + + + auto myO = CreateViewFromJson(dict); + if(myO != nullptr) + { + sv->Add(szStr2size(n),myO); + } + } + } + } + return sv; + } + else if(type == "HStackView") + { + auto sv = new Views::HStackView(); + sv->SetId(id); + Tesses::Framework::Serialization::Json::JArray arr; + if(json.TryGetValueAsType("Items",arr)) + { + for(auto item : arr) + { + Tesses::Framework::Serialization::Json::JObject dict; + if(Tesses::Framework::Serialization::Json::TryGetJToken(item,dict)) + { + std::string n="min"; + + dict.TryGetValueAsType("Size",n); + + + auto myO = CreateViewFromJson(dict); + if(myO != nullptr) + { + sv->Add(szStr2size(n),myO); + } + } + } + } + return sv; + } else { GUIJsonViewNotFoundEventArgs e; e.destView == nullptr; diff --git a/src/SDL2/View.cpp b/src/SDL2/View.cpp index 40a32f4..f823994 100644 --- a/src/SDL2/View.cpp +++ b/src/SDL2/View.cpp @@ -98,8 +98,8 @@ namespace Tesses::Framework::SDL2 { GUIMouseButtonEventArgs cea; cea.button = (int)event.button.button; - cea.x = event.button.x - myVisibleBounds.x; - cea.y = event.button.y - myVisibleBounds.y; + cea.x = event.button.x - myBounds.x; + cea.y = event.button.y - myBounds.y; cea.which = event.button.which; this->SetViewFlag(VIEWFLAG_MOUSEDOWN_STATE,true); OnMouseDown(cea); @@ -112,8 +112,8 @@ namespace Tesses::Framework::SDL2 { GUIMouseButtonEventArgs cea; cea.button = (int)event.button.button; - cea.x = event.button.x - myVisibleBounds.x; - cea.y = event.button.y - myVisibleBounds.y; + cea.x = event.button.x - myBounds.x; + cea.y = event.button.y - myBounds.y; cea.which = event.button.which; this->SetViewFlag(VIEWFLAG_MOUSEDOWN_STATE,false); OnMouseUp(cea); diff --git a/src/SDL2/Views/ButtonView.cpp b/src/SDL2/Views/ButtonView.cpp index ebfd74f..071c274 100644 --- a/src/SDL2/Views/ButtonView.cpp +++ b/src/SDL2/Views/ButtonView.cpp @@ -10,6 +10,22 @@ namespace Tesses::Framework::SDL2::Views ButtonView::ButtonView(std::string text) : View(text) { + } + std::pair ButtonView::PreferedMinSize() + { + int w=-2; + int h=-2; + + auto win = GetWindow(); + if(win != nullptr) + { + win->normal_font->CalculateSize(text,w,h); + + w += win->palette.borderSize*3; + + h += win->palette.borderSize*3; + } + return std::pair(w,h); } bool ButtonView::OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& myVisibleBounds) { @@ -69,7 +85,7 @@ namespace Tesses::Framework::SDL2::Views SDL_SetRenderDrawColor(renderer,color.r,color.g,color.b,color.a); SDL_Rect r2={.x=r.x,.y=r.y,.w=r.w,.h=r.h}; - for(size_t i=0;i < 4; i++) + for(size_t i=0;i < win->palette.borderSize; i++) { SDL_RenderDrawRect(renderer,&r2); r2.x++; diff --git a/src/SDL2/Views/CheckView.cpp b/src/SDL2/Views/CheckView.cpp index 62f9279..7970ff9 100644 --- a/src/SDL2/Views/CheckView.cpp +++ b/src/SDL2/Views/CheckView.cpp @@ -21,7 +21,7 @@ namespace Tesses::Framework::SDL2::Views //we only need the y - int x = r.x+checkSz+8; + int x = r.x+checkSz+(win->palette.borderSize*2); int y = r.y+((r.h/2)-(textH/2)); win->normal_font->Render(renderer,x,y,text,win->palette.accent); @@ -34,15 +34,15 @@ namespace Tesses::Framework::SDL2::Views //x=0,y=0.5, x=0.5, y=1 - int x1=checkBoxRect.x+4; - int y1=checkBoxRect.y+4+((checkSz-8)/2); - int x2=checkBoxRect.x+4+((checkSz-8)/2); - int y2=checkBoxRect.y+4+(checkSz-8); + int x1=checkBoxRect.x+win->palette.borderSize; + int y1=checkBoxRect.y+win->palette.borderSize+((checkSz-(win->palette.borderSize*2))/2); + int x2=checkBoxRect.x+win->palette.borderSize+((checkSz-(win->palette.borderSize*2))/2); + int y2=checkBoxRect.y+win->palette.borderSize+(checkSz-(win->palette.borderSize*8)); - int x3=checkBoxRect.x+4+(checkSz-8); - int y3=checkBoxRect.y+4; + int x3=checkBoxRect.x+win->palette.borderSize+(checkSz-(win->palette.borderSize*2)); + int y3=checkBoxRect.y+win->palette.borderSize; - for(int i = 0; i < 4; i++) + for(int i = 0; i < win->palette.borderSize; i++) { SDL_RenderDrawLine(renderer,x1,y1-i,x2,y2-i); SDL_RenderDrawLine(renderer,x2-i,y2,x3-i,y3); diff --git a/src/SDL2/Views/DropDownView.cpp b/src/SDL2/Views/DropDownView.cpp new file mode 100644 index 0000000..b68c279 --- /dev/null +++ b/src/SDL2/Views/DropDownView.cpp @@ -0,0 +1,113 @@ + +#include "TessesFramework/SDL2/Views/DropDownView.hpp" + +namespace Tesses::Framework::SDL2::Views { + + void DropDownView::OnDraw(SDL_Renderer* renderer, SDL_Rect& r) + { + std::string text = this->text; + if(this->listView.selected > -1 && this->listView.selected < this->listView.items.size()) + { + text = this->listView.items[this->listView.selected]; + } + auto win = this->GetWindow(); + + int textW; + int textH; + win->normal_font->CalculateSize(text,textW,textH); + + int x=win->palette.borderSize*2; + int y=(r.h/2)-(textH/2); + x+=r.x; + y+=r.y; + + auto isHovering = this->GetViewFlag(VIEWFLAG_HOVER_STATE); + auto isActive = this->GetViewFlag(VIEWFLAG_ISACTIVE); + auto isMouseDown = this->GetViewFlag(VIEWFLAG_MOUSEDOWN_STATE); + + SDL_Color& color = win->palette.GetBorderColor(isHovering,isActive,isMouseDown); + + win->normal_font->Render(renderer,x,y,text,win->palette.accent); + SDL_SetRenderDrawColor(renderer,color.r,color.g,color.b,color.a); + + SDL_Rect r2={.x=r.x,.y=r.y,.w=r.w,.h=r.h}; + for(size_t i=0;i < win->palette.borderSize; i++) + { + SDL_RenderDrawRect(renderer,&r2); + r2.x++; + r2.y++; + r2.w-=2; + r2.h-=2; + } + + } + bool DropDownView::OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds) + { + auto win = this->GetWindow(); + if(event.type == SDL_MOUSEBUTTONUP) + { + if(event.button.x >= visibleBounds.x && event.button.x < visibleBounds.x+visibleBounds.w && event.button.y >= visibleBounds.y && event.button.y < visibleBounds.y+visibleBounds.h) + { + win->MakeActive(this); + this->popup.bounds.x = myBounds.x; + this->popup.bounds.y = myBounds.y+myBounds.h; + this->popup.bounds.w = myBounds.w; + this->popup.bounds.h = 150; + auto pu = &this->popup; + if(!this->hasSet) { + + this->listView.ValueChanged += std::make_shared>([pu](View* view,GUIEventArgs& args)->void { + pu->Close(); + }); + + this->popup.SetView(&this->listView,false); + this->hasSet=true; + } + win->ShowPopup(pu); + } + } + else if(event.type == SDL_KEYDOWN) + { + switch(event.key.keysym.sym) + { + case SDLK_UP: + { + this->listView.selected--; + if(this->listView.selected < 0 || this->listView.selected >= this->listView.items.size()) + { + this->listView.selected = (int)(this->listView.items.size()-1); + } + } + break; + case SDLK_DOWN: + { + this->listView.selected++; + if(this->listView.selected < -1 || this->listView.selected >= this->listView.items.size()) + { + this->listView.selected=0; + } + } + break; + } + } + return false; + } + DropDownView::DropDownView() : View("--PLEASE SELECT ONE--") + { + + + } + std::vector& DropDownView::GetItems() + { + return this->listView.items; + } + void DropDownView::SetIndex(int index) + { + this->listView.selected = index; + } + int DropDownView::GetIndex() + { + return this->listView.selected; + } + +} \ No newline at end of file diff --git a/src/SDL2/Views/EditTextView.cpp b/src/SDL2/Views/EditTextView.cpp index 6b4dce7..cabeff9 100644 --- a/src/SDL2/Views/EditTextView.cpp +++ b/src/SDL2/Views/EditTextView.cpp @@ -55,13 +55,13 @@ namespace Tesses::Framework::SDL2::Views } std::pair EditTextView::PreferedMinSize() { - int x=-2; - int y=-2; + int x=-1; + int y=-1; auto win = this->GetWindow(); if(win != nullptr) { x=-1; - y=win->monospaced_font->MaxHeight()+16; + y=win->monospaced_font->MaxHeight()+(win->palette.borderSize*4); } @@ -297,13 +297,13 @@ namespace Tesses::Framework::SDL2::Views int textW=win->monospaced_font->MaxWidth()+2; int textH=win->monospaced_font->MaxHeight(); - int noChars = (r.w-16) / textW; + int noChars = (r.w-(win->palette.borderSize*4)) / textW; int x=0; - int y=(r.h/2)-((textH+16)/2); - x+=r.x+8; - y+=r.y+8; + int y=(r.h/2)-((textH+(win->palette.borderSize*4))/2); + x+=r.x+(win->palette.borderSize*2); + y+=r.y+(win->palette.borderSize*2); auto isHovering = this->GetViewFlag(VIEWFLAG_HOVER_STATE); auto isActive = this->GetViewFlag(VIEWFLAG_ISACTIVE); @@ -367,8 +367,8 @@ namespace Tesses::Framework::SDL2::Views SDL_SetRenderDrawColor(renderer,color.r,color.g,color.b,color.a); - SDL_Rect r2={.x=r.x,.y=y-4,.w=r.w,.h=textH+16}; - for(size_t i=0;i < 4; i++) + SDL_Rect r2={.x=r.x,.y=y-(win->palette.borderSize*2),.w=r.w,.h=textH+16}; + for(size_t i=0;i < win->palette.borderSize; i++) { SDL_RenderDrawRect(renderer,&r2); r2.x++; diff --git a/src/SDL2/Views/HScrollView.cpp b/src/SDL2/Views/HScrollView.cpp new file mode 100644 index 0000000..aec64ec --- /dev/null +++ b/src/SDL2/Views/HScrollView.cpp @@ -0,0 +1,329 @@ +#if defined(TESSESFRAMEWORK_ENABLE_SDL2) + +#include "TessesFramework/SDL2/Views/HScrollView.hpp" + +namespace Tesses::Framework::SDL2::Views +{ + std::pair HScrollView::PreferedMinSize() + { + return std::pair(-1,32); + } + void HScrollView::OnValueChanged(GUIEventArgs& e) + { + + } + HScrollView::HScrollView() : HScrollView(0, 0, 100) + { + + } + HScrollView::HScrollView(uint64_t value, uint64_t min, uint64_t max,uint64_t step) : View() + { + this->value = value; + this->min = min; + this->max = max; + + this->step=step; + } + void HScrollView::OnDraw(SDL_Renderer* renderer, SDL_Rect& r) + { + auto win = this->GetWindow(); + auto leftIsHovering = this->GetViewFlag(VIEWFLAG_HOVER_B1STATE); + auto isActive = this->GetViewFlag(VIEWFLAG_ISACTIVE); + auto leftIsMouseDown = this->GetViewFlag(VIEWFLAG_MOUSEDOWN_B1STATE); + + auto middleIsHovering = this->GetViewFlag(VIEWFLAG_HOVER_STATE); + + auto middleIsMouseDown = this->GetViewFlag(VIEWFLAG_MOUSEDOWN_STATE); + + + auto rightIsHovering = this->GetViewFlag(VIEWFLAG_HOVER_B2STATE); + + auto rightIsMouseDown = this->GetViewFlag(VIEWFLAG_MOUSEDOWN_B2STATE); + + SDL_Color& leftColor = win->palette.GetBorderColor(leftIsHovering,isActive,leftIsMouseDown); + SDL_Color& leftMiddleColor = win->palette.GetBorderColor(leftIsHovering||middleIsHovering,isActive,leftIsMouseDown||middleIsMouseDown); + SDL_Color& middleColor = win->palette.GetBorderColor(middleIsHovering,isActive,middleIsMouseDown); + SDL_Color& rightMiddleColor = win->palette.GetBorderColor(rightIsHovering||middleIsHovering,isActive,rightIsMouseDown||middleIsMouseDown); + SDL_Color& rightColor = win->palette.GetBorderColor(rightIsHovering,isActive,rightIsMouseDown); + + SDL_SetRenderDrawColor(renderer,leftColor.r,leftColor.g,leftColor.b,leftColor.a); + + for(int i = 0; i < win->palette.borderSize; i++) + { + SDL_RenderDrawLine(renderer,r.x+i,r.y,r.x+i,r.y+r.h); //horizontal + + + SDL_RenderDrawLine(renderer,r.x,r.y+i,r.x+32,r.y+i); //horizontal + + SDL_RenderDrawLine(renderer,r.x,r.y+r.h-(1+i),r.x+32,r.y+r.h-(1+i)); //horizontal + } + SDL_SetRenderDrawColor(renderer,leftMiddleColor.r,leftMiddleColor.g,leftMiddleColor.b,leftMiddleColor.a); + for(int i = 0; i < win->palette.borderSize; i++) + { + SDL_RenderDrawLine(renderer,(r.x+32)-i,r.y,(r.x+32)-i,r.y+r.h); //horizontal + } + SDL_SetRenderDrawColor(renderer,middleColor.r,middleColor.g,middleColor.b,middleColor.a); + + for(int i = 0; i < win->palette.borderSize; i++) + { + SDL_RenderDrawLine(renderer,r.x+33,r.y+i,r.x+(r.w-33),r.y+i); //horizontal + SDL_RenderDrawLine(renderer,r.x+33,r.y+r.h-(1+i),r.x+(r.w-33),r.y+r.h-(1+i)); //horizontal + } + SDL_SetRenderDrawColor(renderer,rightColor.r,rightColor.g,rightColor.b,rightColor.a); + + for(int i = 0; i < win->palette.borderSize; i++) + { + SDL_RenderDrawLine(renderer,(r.x+r.w)-(i+1),r.y,(r.x+r.w)-(i+1),r.y+r.h); //horizontal + + SDL_RenderDrawLine(renderer,r.x+(r.w-32),r.y+i,r.x+r.w,r.y+i); //horizontal + SDL_RenderDrawLine(renderer,r.x+(r.w-32),r.y+r.h-(1+i),r.x+r.w,r.y+r.h-(1+i)); //horizonal + } + SDL_SetRenderDrawColor(renderer,rightMiddleColor.r,rightMiddleColor.g,rightMiddleColor.b,rightMiddleColor.a); + for(int i = 0; i < win->palette.borderSize; i++) + { + SDL_RenderDrawLine(renderer,(r.x+(r.w-32))+i,r.y,(r.x+(r.w-32))+i,r.y+r.h); //horizontal + } + + + + SDL_SetRenderDrawColor(renderer,win->palette.accent.r,win->palette.accent.g,win->palette.accent.b,win->palette.accent.a); + + for(int i = 0; i < 4; i++) + { + int y1 = 15; + int x1 = 8 + i; + + int y2 = 9; + int x2 = 18 + i; + + SDL_RenderDrawLine(renderer,x1+r.x,y1+r.y,x2+r.x,y2+r.y); + + int y3 = 31-y1; + int y4 = 31-y2; + + SDL_RenderDrawLine(renderer,x1+r.x,y3+r.y,x2+r.x,y4+r.y); + + int x3 = 31-x1; + int x4 = 31-x2; + + + SDL_RenderDrawLine(renderer,x3+r.x+(r.w-32),y1+r.y,x4+r.x+(r.w-32),y2+r.y); + + SDL_RenderDrawLine(renderer,x3+r.x+(r.w-32),y3+r.y,x4+r.x+(r.w-32),y4+r.y); + } + + uint64_t width = (uint64_t)r.w - 66; + uint64_t scrollSize = 4; + uint64_t dif = max-min; + if(dif > 0) + scrollSize = width / dif; + + if(scrollSize < 4) scrollSize=4; + + + double scroll = 0; + if(dif > 0) + scroll = (double)(value-min) / (double)dif; + + uint64_t scrollX = scroll * (width-scrollSize); + + + + if(scrollX > width-scrollSize) scrollX = width-scrollSize; + SDL_Rect r2={.x=(int)scrollX+r.x+32,.y=r.y+win->palette.borderSize,.w=(int)scrollSize,.h = r.h-(win->palette.borderSize*2)}; + SDL_RenderFillRect(renderer,&r2); + } + bool HScrollView::OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds) + { + if(event.type == SDL_MOUSEMOTION) + { + bool inside = event.motion.x >= visibleBounds.x && event.motion.x < visibleBounds.x+visibleBounds.w && event.motion.y >= visibleBounds.y && event.motion.y < visibleBounds.y+visibleBounds.h; + bool hoverFlag = this->GetViewFlag(VIEWFLAG_HOVER_STATE) || this->GetViewFlag(VIEWFLAG_HOVER_B1STATE) || this->GetViewFlag(VIEWFLAG_HOVER_B2STATE); + if(inside && !hoverFlag) + { + int x = event.motion.x - myBounds.x; + if(x <= 32) + { + //up btn + this->SetViewFlag(VIEWFLAG_HOVER_B1STATE,true); + this->SetViewFlag(VIEWFLAG_HOVER_B2STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_STATE,false); + } + else if(x >= myBounds.w-32) + { + //down btn + this->SetViewFlag(VIEWFLAG_HOVER_B1STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_B2STATE,true); + this->SetViewFlag(VIEWFLAG_HOVER_STATE,false); + } + else { + this->SetViewFlag(VIEWFLAG_HOVER_B1STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_B2STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_STATE,true); + } + + GUIEventArgs e; + this->OnEnter(e); + this->Enter.Invoke(this,e); + } + else if(!inside && hoverFlag) + { + this->SetViewFlag(VIEWFLAG_HOVER_STATE,false); + GUIEventArgs e; + this->OnLeave(e); + this->Leave.Invoke(this,e); + } else if(inside) { + int x = event.motion.x - myBounds.x; + if(x <= 32) + { + //up btn + this->SetViewFlag(VIEWFLAG_HOVER_B1STATE,true); + this->SetViewFlag(VIEWFLAG_HOVER_B2STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_STATE,false); + } + else if(x >= myBounds.w-32) + { + //down btn + this->SetViewFlag(VIEWFLAG_HOVER_B1STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_B2STATE,true); + this->SetViewFlag(VIEWFLAG_HOVER_STATE,false); + } + else { + this->SetViewFlag(VIEWFLAG_HOVER_B1STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_B2STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_STATE,true); + + + } + + } + + if(this->GetViewFlag(VIEWFLAG_MOUSEDOWN_STATE)) + { + int x = event.motion.x - myBounds.x; + if(x <= 32) + { + value = min; + } + else if(x >= myBounds.w-32) + { + value=max; + } + else { + uint64_t width = (uint64_t)myBounds.w - 66; + uint64_t x2 = x-33; + + double off = (double)x2 / (double)width; + + value = round((max-min)*off)+min; + GUIEventArgs cea2; + this->ValueChanged.Invoke(this,cea2); + } + + } + return false; + } + if(event.type == SDL_MOUSEBUTTONDOWN) + { + if(event.button.x >= visibleBounds.x && event.button.x < visibleBounds.x+visibleBounds.w && event.button.y >= visibleBounds.y && event.button.y < visibleBounds.y+visibleBounds.h) + { + GUIMouseButtonEventArgs cea; + cea.button = (int)event.button.button; + cea.x = event.button.x - myBounds.x; + cea.y = event.button.y - myBounds.y; + cea.which = event.button.which; + if(cea.x <= 32) + { + //up btn + this->SetViewFlag(VIEWFLAG_MOUSEDOWN_B1STATE,true); + } + else if(cea.x >= myBounds.w-32) + { + //down btn + this->SetViewFlag(VIEWFLAG_MOUSEDOWN_B2STATE,true); + } + else { + this->SetViewFlag(VIEWFLAG_MOUSEDOWN_STATE,true); + + uint64_t width = (uint64_t)myBounds.w - 66; + uint64_t x2 = cea.x-33; + + double off = (double)x2 / (double)width; + + value = round((max-min)*off)+min; + GUIEventArgs cea2; + this->ValueChanged.Invoke(this,cea2); + } + OnMouseDown(cea); + this->MouseDown.Invoke(this,cea); + + + + return false; + } + } + else if(event.type == SDL_MOUSEBUTTONUP) + { + if(this->GetViewFlag(VIEWFLAG_MOUSEDOWN_STATE)) + { + GUIMouseButtonEventArgs cea; + cea.button = (int)event.button.button; + cea.x = event.button.x - myBounds.x; + cea.y = event.button.y - myBounds.y; + cea.which = event.button.which; + this->SetViewFlag(VIEWFLAG_MOUSEDOWN_STATE,false); + OnMouseUp(cea); + this->MouseUp.Invoke(this,cea); + GUIEventArgs cea2; + OnClick(cea2); + this->Click.Invoke(this,cea2); + return true; + } + if(this->GetViewFlag(VIEWFLAG_MOUSEDOWN_B1STATE)) + { + GUIMouseButtonEventArgs cea; + cea.button = (int)event.button.button; + cea.x = event.button.x - myBounds.x; + cea.y = event.button.y - myBounds.y; + cea.which = event.button.which; + this->SetViewFlag(VIEWFLAG_MOUSEDOWN_B1STATE,false); + OnMouseUp(cea); + this->MouseUp.Invoke(this,cea); + GUIEventArgs cea2; + OnClick(cea2); + this->Click.Invoke(this,cea2); + this->value -= step; + if(this->value < min) this->value=min; + if(this->value >= max) this->value=min; + OnValueChanged(cea2); + this->ValueChanged.Invoke(this,cea2); + return true; + } + if(this->GetViewFlag(VIEWFLAG_MOUSEDOWN_B2STATE)) + { + GUIMouseButtonEventArgs cea; + cea.button = (int)event.button.button; + cea.x = event.button.x - myBounds.x; + cea.y = event.button.y - myBounds.y; + cea.which = event.button.which; + this->SetViewFlag(VIEWFLAG_MOUSEDOWN_B2STATE,false); + OnMouseUp(cea); + this->MouseUp.Invoke(this,cea); + GUIEventArgs cea2; + OnClick(cea2); + this->Click.Invoke(this,cea2); + this->value += step; + if(this->value > max) this->value=max; + OnValueChanged(cea2); + this->ValueChanged.Invoke(this,cea2); + return true; + } + + return false; + } + return View::OnEvent(event,myBounds,visibleBounds); + } + +} + +#endif \ No newline at end of file diff --git a/src/SDL2/Views/HStackView.cpp b/src/SDL2/Views/HStackView.cpp new file mode 100644 index 0000000..0f08ae6 --- /dev/null +++ b/src/SDL2/Views/HStackView.cpp @@ -0,0 +1,273 @@ + +#if defined(TESSESFRAMEWORK_ENABLE_SDL2) +#include "TessesFramework/SDL2/Views/HStackView.hpp" + +namespace Tesses::Framework::SDL2::Views +{ + void HStackView::OnDraw(SDL_Renderer* renderer, SDL_Rect& r) + { + int numberOfCells = 0; + int freeWidth = r.w; + std::vector sizes; + sizes.resize(this->items.size()); + + freeWidth -= (this->items.size() - 1) * this->spacing; + + for(size_t i = 0; i < this->items.size(); i++) + { + if(this->items[i].first > 0) + { + //static size + sizes[i] = this->items[i].first; + freeWidth-= this->items[i].first; + } + else if(this->items[i].first == 0) + { + auto prefered = this->items[i].second.first->PreferedMinSize(); + if(prefered.first > 0) + { + sizes[i] = prefered.first; + freeWidth -= prefered.first; + } + else { + sizes[i] = 0; + } + } + else { + numberOfCells -= this->items[i].first; + } + } + + + int cellSize = numberOfCells == 0 ? 0 : freeWidth / numberOfCells; + + + for(int i = 0; i < this->items.size();i++) + { + if(this->items[i].first < 0) + { + int myWidth =((-(this->items[i].first)) * cellSize); + + auto minSz = this->items[i].second.first->PreferedMinSize(); + if(minSz.first > myWidth) { + sizes[i] = minSz.first; + freeWidth-= minSz.first; + numberOfCells -= -(this->items[i].first); + } + } + } + cellSize = numberOfCells == 0 ? 0 : freeWidth/ numberOfCells; + int x = 0; + + + for(size_t i = 0; i < this->items.size(); i++) + { + if(i > 0) x += spacing; + + if(sizes[i] == 0) + { + int myWidth =((-(this->items[i].first)) * cellSize); + + + SDL_Rect theirBounds = { + .x =x, + .y=0, + .w=myWidth, + .h=r.h + }; + + + theirBounds.x += r.x; + theirBounds.y += r.y; + + + + CallOnDraw(this->items[i].second.first,renderer, theirBounds); + x+=myWidth; + } + else { + + SDL_Rect theirBounds = { + .x =x, + .y=0, + .w=sizes[i], + .h=r.h + }; + + + theirBounds.x += r.x; + theirBounds.y += r.y; + + + + CallOnDraw(this->items[i].second.first,renderer, theirBounds); + x+=sizes[i]; + } + + } + } + bool HStackView::OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds) + { + int numberOfCells = 0; + int freeWidth = myBounds.w; + std::vector sizes; + sizes.resize(this->items.size()); + + + freeWidth -= (this->items.size() - 1) * this->spacing; + for(size_t i = 0; i < this->items.size(); i++) + { + if(this->items[i].first > 0) + { + //static size + sizes[i] = this->items[i].first; + freeWidth-= this->items[i].first; + } + else if(this->items[i].first == 0) + { + auto prefered = this->items[i].second.first->PreferedMinSize(); + if(prefered.first > 0) + { + sizes[i] = prefered.first; + freeWidth -= prefered.first; + } + else { + sizes[i] = 0; + } + } + else { + numberOfCells -= this->items[i].first; + } + } + + + int cellSize = numberOfCells == 0 ? 0 : freeWidth/ numberOfCells; + + for(int i = 0; i < this->items.size();i++) + { + if(this->items[i].first < 0) + { + int myWidth =((-(this->items[i].first)) * cellSize); + + auto minSz = this->items[i].second.first->PreferedMinSize(); + if(minSz.first > myWidth) { + sizes[i] = minSz.first; + myWidth -= minSz.first; + numberOfCells -= -(this->items[i].first); + } + } + } + + + numberOfCells == 0 ? 0 : freeWidth/ numberOfCells; + int x = 0; + + + for(size_t i = 0; i < this->items.size(); i++) + { + if(i > 0) x += spacing; + if(sizes[i] == 0) + { + int myWidth =((-(this->items[i].first)) * cellSize); + + auto minSz = this->items[i].second.first->PreferedMinSize(); + if(minSz.first > myWidth) myWidth = minSz.first; + + SDL_Rect theirBounds = { + .x = x, + .y=0, + .w=myWidth, + .h=myBounds.h + }; + + SDL_Rect theirVisibleBounds = theirBounds; + theirVisibleBounds.x += visibleBounds.x; + theirVisibleBounds.y += visibleBounds.y; + + theirBounds.x += myBounds.x; + theirBounds.y += myBounds.y; + Clipper::ClipRect(theirVisibleBounds, visibleBounds); + + + + CallOnEvent(this->items[i].second.first,event,theirBounds,theirVisibleBounds); + + x+=myWidth; + } + else { + + SDL_Rect theirBounds = { + .x = x, + .y=0, + .w=sizes[i], + .h=myBounds.h + }; + + SDL_Rect theirVisibleBounds = theirBounds; + theirVisibleBounds.x += visibleBounds.x; + theirVisibleBounds.y += visibleBounds.y; + + theirBounds.x += myBounds.x; + theirBounds.y += myBounds.y; + Clipper::ClipRect(theirVisibleBounds, visibleBounds); + + + + CallOnEvent(this->items[i].second.first,event,theirBounds,theirVisibleBounds); + + x+=sizes[i]; + } + + } + return false; + } + HStackView::HStackView() : ContainerView() + { + + } + + void HStackView::Add(int sz, View* view, bool owns) + { + this->items.push_back(std::pair>(sz,std::pair(view,owns))); + this->AssignChildParentToThis(view); + } + void HStackView::Remove(View* view) + { + for(auto index = this->items.begin(); index < this->items.end(); index++) + { + if(index->second.first == view) + { + + if(index->second.first != nullptr && index->second.second) + delete view; + this->items.erase(index); + return; + } + } + } + void HStackView::Clear() + { + for(auto& item : this->items) + if(item.second.second && item.second.first != nullptr) delete item.second.first; + items = {}; + } + + size_t HStackView::ViewCount() + { + return this->items.size(); + } + View* HStackView::GetViewAt(size_t index) + { + return this->items.at(index).second.first; + } + + HStackView::~HStackView() + { + for(auto& item : this->items) + if(item.second.second && item.second.first != nullptr) delete item.second.first; + } + + + +} +#endif \ No newline at end of file diff --git a/src/SDL2/Views/LabelView.cpp b/src/SDL2/Views/LabelView.cpp index f4a760f..76d4f6a 100644 --- a/src/SDL2/Views/LabelView.cpp +++ b/src/SDL2/Views/LabelView.cpp @@ -5,7 +5,7 @@ namespace Tesses::Framework::SDL2::Views void LabelView::OnDraw(SDL_Renderer* renderer, SDL_Rect& r) { auto win =this->GetWindow(); - win->normal_font->Render(renderer,r.x+4,r.y+4,text,win->palette.accent); + win->normal_font->Render(renderer,r.x+win->palette.borderSize,r.y+win->palette.borderSize,text,win->palette.accent); } LabelView::LabelView() : View() diff --git a/src/SDL2/Views/MultilineEditTextView.cpp b/src/SDL2/Views/MultilineEditTextView.cpp new file mode 100644 index 0000000..99e4118 --- /dev/null +++ b/src/SDL2/Views/MultilineEditTextView.cpp @@ -0,0 +1,178 @@ +#if defined(TESSESFRAMEWORK_ENABLE_SDL2) +#include "TessesFramework/SDL2/Views/MultilineEditTextView.hpp" +#include "TessesFramework/Http/HttpUtils.hpp" + +namespace Tesses::Framework::SDL2::Views +{ + void MultilineEditTextView::OnDraw(SDL_Renderer* renderer, SDL_Rect& r) + { + //1 | + + // 9 | + //10 | + + + + + } + bool MultilineEditTextView::OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds) + { + + } + MultilineEditTextView::MultilineEditTextView() :MultilineEditTextView(std::string()) + { + + } + MultilineEditTextView::MultilineEditTextView(std::string hint) : View() + { + this->hint = hint; + } + std::string MultilineEditTextView::GetHint() + { + return this->hint; + } + void MultilineEditTextView::SetHint(std::string hint) + { + this->hint = hint; + } + std::string MultilineEditTextView::GetText() + { + if(this->lines.empty()) return {}; + std::string text = this->lines.front(); + for(size_t i = 1; i < this->lines.size(); i++) + { + text.push_back('\n'); + text.append(this->lines[i]); + } + return text; + } + void MultilineEditTextView::SetText(std::string text) + { + lines.clear(); + std::string line = ""; + for(auto c : text) + { + if(c == '\n') { + lines.push_back(line); + line = ""; + } + else { + line += c; + } + } + if(!line.empty()) lines.push_back(line); + + this->cursorPos.x=0; + this->cursorPos.y=0; + this->cursorEnd.x=-1; + this->cursorEnd.y=-1; + } + void MultilineEditTextView::TypeText(std::string text) + { + + SDL_Point cursorBegin = this->cursorPos; + SDL_Point cursorEnd = this->cursorEnd; + if(cursorBegin.y > cursorEnd.y || ((cursorBegin.y == cursorEnd.y) && (cursorBegin.x > cursorEnd.x))) + { + cursorBegin.y ^= cursorEnd.y; + cursorEnd.y ^= cursorBegin.y; + cursorBegin.y ^= cursorEnd.y; + + cursorBegin.x ^= cursorEnd.x; + cursorEnd.x ^= cursorBegin.x; + cursorBegin.x ^= cursorEnd.x; + } + /* + + if(cursorEnd != std::string::npos && cursorEnd <= this->text.size()) + { + this->text.erase(cursorBegin,cursorEnd-cursorBegin); + this->text.insert(cursorBegin,text); + } + else if(cursorBegin <= this->text.size()) { + this->text.insert(cursorBegin,text); + + } + + this->cursorPos = cursorBegin+text.size(); + this->cursorEnd = std::string::npos;*/ + + if(cursorEnd.y != -1 && cursorEnd.x != -1) + { + int line = cursorBegin.y; + for(int y = cursorBegin.y; y <= cursorEnd.y && y < lines.size(); y++) + { + if(y == cursorBegin.y && y == cursorEnd.y && cursorBegin.x == 0 && cursorEnd.x == this->lines[y].size()-1) + { + this->lines.erase(this->lines.begin()+line); + } + else if(y == cursorBegin.y && y == cursorEnd.y) + { + this->lines[line]=this->lines[line].substr(0,cursorBegin.x) + this->lines[line].substr(cursorEnd.x); + line++; + } + else if(y == cursorBegin.y && cursorBegin.x == 0) + { + this->lines.erase(this->lines.begin()+line); + } + else if(y == cursorBegin.y) + { + this->lines[line]=this->lines[line].substr(0,cursorBegin.x); + line++; + } + else if(y > cursorBegin.y && y < cursorEnd.y) + { + this->lines.erase(this->lines.begin()+line); + } + else if(y == cursorEnd.y && cursorEnd.x < this->lines[line].size()-1) + { + this->lines[line]=this->lines[line].substr(cursorBegin.x); + } + else { + this->lines.erase(this->lines.begin()+line); + } + } + } + + + + + auto mylines = Http::HttpUtils::SplitString(text,"\n"); + + if(!mylines.empty()) + { + if(cursorBegin.y < this->lines.size()) + { + + if(cursorBegin.x > 0) + { + mylines[0] = this->lines[cursorBegin.y].substr(0,cursorBegin.x) + mylines[0]; + } + + if(cursorBegin.x < this->lines[cursorBegin.y].size()) + { + mylines.back() += this->lines[cursorBegin.y].substr(cursorBegin.x); + } + + this->lines.erase(this->lines.begin()+cursorBegin.y); + } + + + + for(auto& item : mylines) + { + this->lines.insert(this->lines.begin()+cursorBegin.y,{item}); + } + + } + + + this->cursorPos = cursorBegin; + this->cursorEnd = {.x=-1,.y=-1}; + } + std::pair MultilineEditTextView::PreferedMinSize() + { + return std::pair(128,128); + } +} +#endif \ No newline at end of file diff --git a/src/SDL2/Views/ProgressView.cpp b/src/SDL2/Views/ProgressView.cpp index 472f2f4..63ac722 100644 --- a/src/SDL2/Views/ProgressView.cpp +++ b/src/SDL2/Views/ProgressView.cpp @@ -18,10 +18,10 @@ namespace Tesses::Framework::SDL2::Views auto win = this->GetWindow(); - SDL_SetRenderDrawColor(renderer,win->palette.border_color.r,win->palette.border_color.g,win->palette.border_color.b,win->palette.border_color.a); + SDL_SetRenderDrawColor(renderer,win->palette.borderColor.r,win->palette.borderColor.g,win->palette.borderColor.b,win->palette.borderColor.a); SDL_Rect r2={.x=rect.x,.y=rect.y,.w=rect.w,.h=rect.h}; - for(size_t i=0;i < 4; i++) + for(size_t i=0;i < win->palette.borderSize; i++) { SDL_RenderDrawRect(renderer,&r2); r2.x++; @@ -30,8 +30,8 @@ namespace Tesses::Framework::SDL2::Views r2.h-=2; } - auto res = (int)((rect.w-8)*(this->value/100.0)); - r2={.x=rect.x+4,.y=rect.y+4,.w=res,.h=rect.h-8}; + auto res = (int)((rect.w-(win->palette.borderSize*2))*(this->value/100.0)); + r2={.x=rect.x+win->palette.borderSize,.y=rect.y+win->palette.borderSize,.w=res,.h=rect.h-8}; SDL_SetRenderDrawColor(renderer,win->palette.accent.r,win->palette.accent.g,win->palette.accent.b,win->palette.accent.a); SDL_RenderFillRect(renderer,&r2); } diff --git a/src/SDL2/Views/ScrollableTextListView.cpp b/src/SDL2/Views/ScrollableTextListView.cpp new file mode 100644 index 0000000..5cdb3fa --- /dev/null +++ b/src/SDL2/Views/ScrollableTextListView.cpp @@ -0,0 +1,444 @@ +#if defined(TESSESFRAMEWORK_ENABLE_SDL2) + +#include "TessesFramework/SDL2/Views/ScrollableTextListView.hpp" + +namespace Tesses::Framework::SDL2::Views +{ + ScrollableTextListView::ScrollableTextListView() : View() + { + this->firstIndex=0; + this->selected=-1; + } + bool ScrollableTextListView::OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds) + { + auto win = this->GetWindow(); + auto item_height = win->normal_font->MaxHeight()+(win->palette.borderSize*2); + auto no_items = (myBounds.h-(win->palette.borderSize*2)) / item_height; + auto max_items = no_items; + + if(this->firstIndex + no_items > this->items.size()) + { + + no_items = this->items.size()-this->firstIndex; + } + + + if(event.type == SDL_KEYDOWN) + { + if(this->GetViewFlag(VIEWFLAG_ISACTIVE)) + { + switch(event.key.keysym.sym) + { + case SDLK_RETURN: + { + + GUIEventArgs e; + if(this->selected > -1) + this->ValueChanged.Invoke(this,e); + } + break; + case SDLK_HOME: + this->selected=0; + this->firstIndex=0; + break; + case SDLK_END: + this->selected = (int)(this->items.size()-1); + + this->firstIndex= this->selected-(this->selected % max_items); + + break; + case SDLK_DOWN: + this->selected++; + if(this->selected < -1 || this->selected >= this->items.size()) + { + this->selected=0; + } + this->firstIndex= this->selected-(this->selected % max_items); + + break; + case SDLK_UP: + this->selected--; + if(this->selected < 0 || this->selected >= this->items.size()) + { + this->selected = (int)(this->items.size()-1); + } + + this->firstIndex= this->selected-(this->selected % max_items); + + break; + } + } + } + + if(event.type == SDL_MOUSEMOTION) + { + bool inside = event.motion.x >= visibleBounds.x && event.motion.x < visibleBounds.x+visibleBounds.w && event.motion.y >= visibleBounds.y && event.motion.y < visibleBounds.y+visibleBounds.h; + bool hoverFlag = this->GetViewFlag(VIEWFLAG_HOVER_STATE) || this->GetViewFlag(VIEWFLAG_HOVER_B1STATE) || this->GetViewFlag(VIEWFLAG_HOVER_B2STATE); + if(inside && !hoverFlag) + { + int y = event.motion.y - myBounds.y; + if(y <= 32) + { + //up btn + this->SetViewFlag(VIEWFLAG_HOVER_B1STATE,true); + this->SetViewFlag(VIEWFLAG_HOVER_B2STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_STATE,false); + } + else if(y >= myBounds.h-32) + { + //down btn + this->SetViewFlag(VIEWFLAG_HOVER_B1STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_B2STATE,true); + this->SetViewFlag(VIEWFLAG_HOVER_STATE,false); + } + else { + this->SetViewFlag(VIEWFLAG_HOVER_B1STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_B2STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_STATE,true); + } + + GUIEventArgs e; + this->OnEnter(e); + this->Enter.Invoke(this,e); + } + else if(!inside && hoverFlag) + { + this->SetViewFlag(VIEWFLAG_HOVER_STATE,false); + GUIEventArgs e; + this->OnLeave(e); + this->Leave.Invoke(this,e); + } else if(inside) { + int y = event.motion.y - myBounds.y; + if(y <= 32) + { + //up btn + this->SetViewFlag(VIEWFLAG_HOVER_B1STATE,true); + this->SetViewFlag(VIEWFLAG_HOVER_B2STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_STATE,false); + } + else if(y >= myBounds.h-32) + { + //down btn + this->SetViewFlag(VIEWFLAG_HOVER_B1STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_B2STATE,true); + this->SetViewFlag(VIEWFLAG_HOVER_STATE,false); + } + else { + this->SetViewFlag(VIEWFLAG_HOVER_B1STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_B2STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_STATE,true); + + + } + + } + + if(this->GetViewFlag(VIEWFLAG_MOUSEDOWN_STATE)) + { + int y = event.motion.y - myBounds.y; + if(y <= 32) + { + this->firstIndex = 0; + } + else if(y >= myBounds.h-32) + { + uint64_t count = max_items == 0 ? 0 : this->items.size() / max_items; + + if((items.size() % max_items) == 0) count--; + + this->firstIndex = count*max_items; + } + else { + uint64_t height = (uint64_t)myBounds.h - 66; + uint64_t y2 = y-33; + + double off = (double)y2 / (double)height; + + + uint64_t count = max_items == 0 ? 0 : this->items.size() / max_items; + if((items.size() % max_items) == 0) count--; + + this->firstIndex = round(off*count) * max_items; + + } + + } + return false; + } + if(event.type == SDL_MOUSEBUTTONDOWN) + { + if(event.button.x >= visibleBounds.x && event.button.x < visibleBounds.x+visibleBounds.w && event.button.y >= visibleBounds.y && event.button.y < visibleBounds.y+visibleBounds.h) + { + int x= event.button.x - myBounds.x; + int y = event.button.y - myBounds.y; + + if(x >= myBounds.w-32) + { + + if(y <= 32) + { + //up btn + this->SetViewFlag(VIEWFLAG_MOUSEDOWN_B1STATE,true); + } + else if(y >= myBounds.h-32) + { + //down btn + this->SetViewFlag(VIEWFLAG_MOUSEDOWN_B2STATE,true); + } + else { + this->SetViewFlag(VIEWFLAG_MOUSEDOWN_STATE,true); + + uint64_t height = (uint64_t)myBounds.h - 66; + uint64_t y2 = y-33; + + double off = (double)y2 / (double)height; + + uint64_t count = max_items == 0 ? 0 : this->items.size() / max_items; + if((items.size() % max_items) == 0) count--; + + this->firstIndex = round(off*count) * max_items; + //value = round((max-min)*off)+min; + + } + } + + + return false; + } + } + else if(event.type == SDL_MOUSEBUTTONUP) + { + int x= event.button.x - myBounds.x; + if(x < myBounds.w-32 && event.button.x >= (visibleBounds.x+win->palette.borderSize) && event.button.y >= (visibleBounds.y+win->palette.borderSize) && event.button.y < (visibleBounds.y+visibleBounds.h)-(win->palette.borderSize*2)) + { + win->MakeActive(this); + auto myRealY=event.button.y - (myBounds.y+win->palette.borderSize); + auto yThing = myRealY / item_height; + + if(yThing < no_items) + { + auto high= yThing+this->firstIndex; + this->selected = (int)high; + GUIEventArgs e; + this->ValueChanged.Invoke(this,e); + } + + } + if(this->GetViewFlag(VIEWFLAG_MOUSEDOWN_STATE)) + { + + win->MakeActive(this); + this->SetViewFlag(VIEWFLAG_MOUSEDOWN_STATE,false); + + return true; + } + if(this->GetViewFlag(VIEWFLAG_MOUSEDOWN_B1STATE)) + { + + win->MakeActive(this); + this->SetViewFlag(VIEWFLAG_MOUSEDOWN_B1STATE,false); + + //this->value -= step; + //if(this->value < min) this->value=min; + //if(this->value >= max) this->value=min; + //OnValueChanged(cea2); + //this->ValueChanged.Invoke(this,cea2); + + uint64_t count = max_items == 0 ? 0 : this->items.size() / max_items; + + if((items.size() % max_items) == 0) count--; + + auto c = max_items == 0 ? 0 : (this->firstIndex / max_items); + c--; + if(c > count) c = 0; + this->firstIndex = c * max_items; + + return true; + } + if(this->GetViewFlag(VIEWFLAG_MOUSEDOWN_B2STATE)) + { + + win->MakeActive(this); + this->SetViewFlag(VIEWFLAG_MOUSEDOWN_B2STATE,false); + + uint64_t count = max_items == 0 ? 0 : this->items.size() / max_items; + + if((items.size() % max_items) == 0) count--; + + auto c = max_items == 0 ? 0 : (this->firstIndex / max_items); + c++; + if(c > count) c = count; + this->firstIndex = c * max_items; + //this->value += step; + //if(this->value > max) this->value=max; + //OnValueChanged(cea2); + //this->ValueChanged.Invoke(this,cea2); + return true; + } + return false; + } + + + + + + + + return View::OnEvent(event,myBounds,visibleBounds); + } + + void ScrollableTextListView::OnDraw(SDL_Renderer* renderer,SDL_Rect& rect) + { + auto win = this->GetWindow(); + auto item_height = win->normal_font->MaxHeight()+(win->palette.borderSize*2); + auto no_items = (rect.h-(win->palette.borderSize*2)) / item_height; + auto max_items = no_items; + auto isHovering = this->GetViewFlag(VIEWFLAG_HOVER_STATE); + auto isActive = this->GetViewFlag(VIEWFLAG_ISACTIVE); + auto isMouseDown = this->GetViewFlag(VIEWFLAG_MOUSEDOWN_STATE); + + SDL_Color& color = win->palette.GetBorderColor(isHovering,isActive,isMouseDown); + + SDL_SetRenderDrawColor(renderer,color.r,color.g,color.b,color.a); + + + + + + if(this->firstIndex + no_items > this->items.size()) + { + + no_items = this->items.size()-this->firstIndex; + } + + SDL_Rect _r2={.x=rect.x,.y=rect.y,.w=rect.w-32,.h=rect.h}; + for(size_t i=0;i < win->palette.borderSize; i++) + { + SDL_RenderDrawRect(renderer,&_r2); + _r2.x++; + _r2.y++; + _r2.w-=2; + _r2.h-=2; + } + + for(int i = 0; i < no_items; i++) + { + int realI = i+(int)firstIndex; + if(realI == this->selected) + { + SDL_SetRenderDrawColor(renderer,win->palette.accent.r,win->palette.accent.g,win->palette.accent.b,win->palette.accent.a); + SDL_Rect r2={.x=rect.x+win->palette.borderSize,.y=rect.y+win->palette.borderSize+(item_height*i),.w=rect.w-(win->palette.borderSize*2)-32,.h=item_height}; + SDL_RenderFillRect(renderer,&r2); + win->normal_font->Render(renderer,rect.x+(win->palette.borderSize*3),(rect.y+(win->palette.borderSize*3))+(item_height*i),this->items[realI],color); + } + else { + win->normal_font->Render(renderer,rect.x+(win->palette.borderSize*3),(rect.y+(win->palette.borderSize*3))+(item_height*i),this->items[realI],win->palette.accent); + } + } + + auto scrollX = (rect.w-32)+rect.x; + auto topIsHovering = this->GetViewFlag(VIEWFLAG_HOVER_B1STATE); + + auto topIsMouseDown = this->GetViewFlag(VIEWFLAG_MOUSEDOWN_B1STATE); + + auto middleIsHovering = this->GetViewFlag(VIEWFLAG_HOVER_STATE); + + auto middleIsMouseDown = this->GetViewFlag(VIEWFLAG_MOUSEDOWN_STATE); + + + auto bottomIsHovering = this->GetViewFlag(VIEWFLAG_HOVER_B2STATE); + + auto bottomIsMouseDown = this->GetViewFlag(VIEWFLAG_MOUSEDOWN_B2STATE); + + SDL_Color& topcolor = win->palette.GetBorderColor(topIsHovering,isActive,topIsMouseDown); + SDL_Color& topMiddleColor = win->palette.GetBorderColor(topIsHovering||middleIsHovering,isActive,topIsMouseDown||middleIsMouseDown); + SDL_Color& middleColor = win->palette.GetBorderColor(middleIsHovering,isActive,middleIsMouseDown); + SDL_Color& bottomMiddleColor = win->palette.GetBorderColor(bottomIsHovering||middleIsHovering,isActive,bottomIsMouseDown||middleIsMouseDown); + SDL_Color& bottomColor = win->palette.GetBorderColor(bottomIsHovering,isActive,bottomIsMouseDown); + + SDL_SetRenderDrawColor(renderer,topcolor.r,topcolor.g,topcolor.b,topcolor.a); + + for(int i = 0; i < win->palette.borderSize; i++) + { + SDL_RenderDrawLine(renderer,scrollX,rect.y+i,scrollX+32,rect.y+i); + SDL_RenderDrawLine(renderer,scrollX+i,rect.y,scrollX+i,rect.y+32); + SDL_RenderDrawLine(renderer,scrollX+32-(1+i),rect.y,scrollX+32-(1+i),rect.y+32); + } + SDL_SetRenderDrawColor(renderer,topMiddleColor.r,topMiddleColor.g,topMiddleColor.b,topMiddleColor.a); + for(int i = 0; i < win->palette.borderSize; i++) + { + SDL_RenderDrawLine(renderer,scrollX,(rect.y+32)-i,scrollX+32,(rect.y+32)-i); + } + SDL_SetRenderDrawColor(renderer,middleColor.r,middleColor.g,middleColor.b,middleColor.a); + + for(int i = 0; i < win->palette.borderSize; i++) + { + SDL_RenderDrawLine(renderer,scrollX+i,rect.y+33,scrollX+i,rect.y+(rect.h-33)); + SDL_RenderDrawLine(renderer,scrollX+32-(1+i),rect.y+33,scrollX+32-(1+i),rect.y+(rect.h-33)); + } + SDL_SetRenderDrawColor(renderer,bottomColor.r,bottomColor.g,bottomColor.b,bottomColor.a); + + for(int i = 0; i < win->palette.borderSize; i++) + { + SDL_RenderDrawLine(renderer,scrollX,(rect.y+rect.h)-(i+1),scrollX+32,(rect.y+rect.h)-(i+1)); + SDL_RenderDrawLine(renderer,scrollX+i,rect.y+(rect.h-32),scrollX+i,rect.y+rect.h); + SDL_RenderDrawLine(renderer,scrollX+32-(1+i),rect.y+(rect.h-32),scrollX+32-(1+i),rect.y+rect.h); + } + SDL_SetRenderDrawColor(renderer,bottomMiddleColor.r,bottomMiddleColor.g,bottomMiddleColor.b,bottomMiddleColor.a); + for(int i = 0; i < win->palette.borderSize; i++) + { + SDL_RenderDrawLine(renderer,scrollX,(rect.y+(rect.h-32))+i,scrollX+32,(rect.y+(rect.h-32))+i); + } + + + + SDL_SetRenderDrawColor(renderer,win->palette.accent.r,win->palette.accent.g,win->palette.accent.b,win->palette.accent.a); + + for(int i = 0; i < 4; i++) + { + int x1 = 15; + int y1 = 8 + i; + + int x2 = 9; + int y2 = 18 + i; + + SDL_RenderDrawLine(renderer,x1+scrollX,y1+rect.y,x2+scrollX,y2+rect.y); + + int x3 = 31-x1; + int x4 = 31-x2; + SDL_RenderDrawLine(renderer,x3+scrollX,y1+rect.y,x4+scrollX,y2+rect.y); + + int y3 = 31-y1; + int y4 = 31-y2; + + SDL_RenderDrawLine(renderer,x1+scrollX,y3+rect.y+(rect.h-32),x2+scrollX,y4+rect.y+(rect.h-32)); + SDL_RenderDrawLine(renderer,x3+scrollX,y3+rect.y+(rect.h-32),x4+scrollX,y4+rect.y+(rect.h-32)); + } + + uint64_t height = (uint64_t)rect.h - 66; + uint64_t scrollSize = 4; + uint64_t count = max_items == 0 ? 0 : this->items.size() / max_items; + + if((items.size() % max_items) == 0) count--; + + if(count > 0) + scrollSize = height / count; + + if(scrollSize < 4) scrollSize=4; + + + double scroll = 0; + if(count > 0 && max_items > 0) + scroll = (double)(this->firstIndex / max_items) / (double)count; + + uint64_t scrollY = scroll * (height-scrollSize); + + + + if(scrollY > height-scrollSize) scrollY = height-scrollSize; + SDL_Rect r2={.x=scrollX+win->palette.borderSize,.y=(int)scrollY+rect.y+32,.w = 32-(win->palette.borderSize*2),.h=(int)scrollSize}; + SDL_RenderFillRect(renderer,&r2); + + } +} +#endif \ No newline at end of file diff --git a/src/SDL2/Views/TextListView.cpp b/src/SDL2/Views/TextListView.cpp index cd2e961..fa15845 100644 --- a/src/SDL2/Views/TextListView.cpp +++ b/src/SDL2/Views/TextListView.cpp @@ -12,8 +12,8 @@ namespace Tesses::Framework::SDL2::Views bool TextListView::OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds) { auto win = this->GetWindow(); - auto item_height = win->normal_font->MaxHeight()+8; - auto no_items = (myBounds.h-8) / item_height; + auto item_height = win->normal_font->MaxHeight()+(win->palette.borderSize*2); + auto no_items = (myBounds.h-(win->palette.borderSize*2)) / item_height; if(this->items.size() > no_items) { @@ -65,10 +65,10 @@ namespace Tesses::Framework::SDL2::Views } } } - if(event.type == SDL_MOUSEBUTTONUP && event.button.x >= (visibleBounds.x+4) && event.button.x < (visibleBounds.x+visibleBounds.w)-8 && event.button.y >= (visibleBounds.y+4) && event.button.y < (visibleBounds.y+visibleBounds.h)-8) + if(event.type == SDL_MOUSEBUTTONUP && event.button.x >= (visibleBounds.x+win->palette.borderSize) && event.button.x < (visibleBounds.x+visibleBounds.w)-(win->palette.borderSize*2) && event.button.y >= (visibleBounds.y+win->palette.borderSize) && event.button.y < (visibleBounds.y+visibleBounds.h)-(win->palette.borderSize*2)) { win->MakeActive(this); - auto myRealY=event.button.y - (myBounds.y+4); + auto myRealY=event.button.y - (myBounds.y+win->palette.borderSize); auto yThing = myRealY / item_height; if(yThing < no_items) @@ -84,8 +84,8 @@ namespace Tesses::Framework::SDL2::Views void TextListView::OnDraw(SDL_Renderer* renderer,SDL_Rect& rect) { auto win = this->GetWindow(); - auto item_height = win->normal_font->MaxHeight()+8; - auto no_items = (rect.h-8) / item_height; + auto item_height = win->normal_font->MaxHeight()+(win->palette.borderSize*2); + auto no_items = (rect.h-(win->palette.borderSize*2)) / item_height; auto isHovering = this->GetViewFlag(VIEWFLAG_HOVER_STATE); auto isActive = this->GetViewFlag(VIEWFLAG_ISACTIVE); auto isMouseDown = this->GetViewFlag(VIEWFLAG_MOUSEDOWN_STATE); @@ -112,7 +112,7 @@ namespace Tesses::Framework::SDL2::Views } SDL_Rect r2={.x=rect.x,.y=rect.y,.w=rect.w,.h=rect.h}; - for(size_t i=0;i < 4; i++) + for(size_t i=0;i < win->palette.borderSize; i++) { SDL_RenderDrawRect(renderer,&r2); r2.x++; @@ -127,12 +127,12 @@ namespace Tesses::Framework::SDL2::Views if(realI == this->selected) { SDL_SetRenderDrawColor(renderer,win->palette.accent.r,win->palette.accent.g,win->palette.accent.b,win->palette.accent.a); - SDL_Rect r2={.x=rect.x+4,.y=rect.y+4+(item_height*i),.w=rect.w-8,.h=item_height}; + SDL_Rect r2={.x=rect.x+win->palette.borderSize,.y=rect.y+win->palette.borderSize+(item_height*i),.w=rect.w-(win->palette.borderSize*2),.h=item_height}; SDL_RenderFillRect(renderer,&r2); - win->normal_font->Render(renderer,rect.x+12,(rect.y+12)+(item_height*i),this->items[realI],color); + win->normal_font->Render(renderer,rect.x+(win->palette.borderSize*3),(rect.y+(win->palette.borderSize*3))+(item_height*i),this->items[realI],color); } else { - win->normal_font->Render(renderer,rect.x+12,(rect.y+12)+(item_height*i),this->items[realI],win->palette.accent); + win->normal_font->Render(renderer,rect.x+(win->palette.borderSize*3),(rect.y+(win->palette.borderSize*3))+(item_height*i),this->items[realI],win->palette.accent); } } } diff --git a/src/SDL2/Views/VScrollView.cpp b/src/SDL2/Views/VScrollView.cpp new file mode 100644 index 0000000..f54f50c --- /dev/null +++ b/src/SDL2/Views/VScrollView.cpp @@ -0,0 +1,322 @@ +#if defined(TESSESFRAMEWORK_ENABLE_SDL2) + +#include "TessesFramework/SDL2/Views/VScrollView.hpp" + +namespace Tesses::Framework::SDL2::Views +{ + std::pair VScrollView::PreferedMinSize() + { + return std::pair(32,-1); + } + void VScrollView::OnValueChanged(GUIEventArgs& e) + { + + } + VScrollView::VScrollView() : VScrollView(0, 0, 100) + { + + } + VScrollView::VScrollView(uint64_t value, uint64_t min, uint64_t max,uint64_t step) : View() + { + this->value = value; + this->min = min; + this->max = max; + + this->step=step; + } + void VScrollView::OnDraw(SDL_Renderer* renderer, SDL_Rect& r) + { + auto win = this->GetWindow(); + auto topIsHovering = this->GetViewFlag(VIEWFLAG_HOVER_B1STATE); + auto isActive = this->GetViewFlag(VIEWFLAG_ISACTIVE); + auto topIsMouseDown = this->GetViewFlag(VIEWFLAG_MOUSEDOWN_B1STATE); + + auto middleIsHovering = this->GetViewFlag(VIEWFLAG_HOVER_STATE); + + auto middleIsMouseDown = this->GetViewFlag(VIEWFLAG_MOUSEDOWN_STATE); + + + auto bottomIsHovering = this->GetViewFlag(VIEWFLAG_HOVER_B2STATE); + + auto bottomIsMouseDown = this->GetViewFlag(VIEWFLAG_MOUSEDOWN_B2STATE); + + SDL_Color& topcolor = win->palette.GetBorderColor(topIsHovering,isActive,topIsMouseDown); + SDL_Color& topMiddleColor = win->palette.GetBorderColor(topIsHovering||middleIsHovering,isActive,topIsMouseDown||middleIsMouseDown); + SDL_Color& middleColor = win->palette.GetBorderColor(middleIsHovering,isActive,middleIsMouseDown); + SDL_Color& bottomMiddleColor = win->palette.GetBorderColor(bottomIsHovering||middleIsHovering,isActive,bottomIsMouseDown||middleIsMouseDown); + SDL_Color& bottomColor = win->palette.GetBorderColor(bottomIsHovering,isActive,bottomIsMouseDown); + + SDL_SetRenderDrawColor(renderer,topcolor.r,topcolor.g,topcolor.b,topcolor.a); + + for(int i = 0; i < win->palette.borderSize; i++) + { + SDL_RenderDrawLine(renderer,r.x,r.y+i,r.x+r.w,r.y+i); + SDL_RenderDrawLine(renderer,r.x+i,r.y,r.x+i,r.y+32); + SDL_RenderDrawLine(renderer,r.x+r.w-(1+i),r.y,r.x+r.w-(1+i),r.y+32); + } + SDL_SetRenderDrawColor(renderer,topMiddleColor.r,topMiddleColor.g,topMiddleColor.b,topMiddleColor.a); + for(int i = 0; i < win->palette.borderSize; i++) + { + SDL_RenderDrawLine(renderer,r.x,(r.y+32)-i,r.x+r.w,(r.y+32)-i); + } + SDL_SetRenderDrawColor(renderer,middleColor.r,middleColor.g,middleColor.b,middleColor.a); + + for(int i = 0; i < win->palette.borderSize; i++) + { + SDL_RenderDrawLine(renderer,r.x+i,r.y+33,r.x+i,r.y+(r.h-33)); + SDL_RenderDrawLine(renderer,r.x+r.w-(1+i),r.y+33,r.x+r.w-(1+i),r.y+(r.h-33)); + } + SDL_SetRenderDrawColor(renderer,bottomColor.r,bottomColor.g,bottomColor.b,bottomColor.a); + + for(int i = 0; i < win->palette.borderSize; i++) + { + SDL_RenderDrawLine(renderer,r.x,(r.y+r.h)-(i+1),r.x+r.w,(r.y+r.h)-(i+1)); + SDL_RenderDrawLine(renderer,r.x+i,r.y+(r.h-32),r.x+i,r.y+r.h); + SDL_RenderDrawLine(renderer,r.x+r.w-(1+i),r.y+(r.h-32),r.x+r.w-(1+i),r.y+r.h); + } + SDL_SetRenderDrawColor(renderer,bottomMiddleColor.r,bottomMiddleColor.g,bottomMiddleColor.b,bottomMiddleColor.a); + for(int i = 0; i < win->palette.borderSize; i++) + { + SDL_RenderDrawLine(renderer,r.x,(r.y+(r.h-32))+i,r.x+r.w,(r.y+(r.h-32))+i); + } + + + + SDL_SetRenderDrawColor(renderer,win->palette.accent.r,win->palette.accent.g,win->palette.accent.b,win->palette.accent.a); + + for(int i = 0; i < 4; i++) + { + int x1 = 15; + int y1 = 8 + i; + + int x2 = 9; + int y2 = 18 + i; + + SDL_RenderDrawLine(renderer,x1+r.x,y1+r.y,x2+r.x,y2+r.y); + + int x3 = 31-x1; + int x4 = 31-x2; + SDL_RenderDrawLine(renderer,x3+r.x,y1+r.y,x4+r.x,y2+r.y); + + int y3 = 31-y1; + int y4 = 31-y2; + + SDL_RenderDrawLine(renderer,x1+r.x,y3+r.y+(r.h-32),x2+r.x,y4+r.y+(r.h-32)); + SDL_RenderDrawLine(renderer,x3+r.x,y3+r.y+(r.h-32),x4+r.x,y4+r.y+(r.h-32)); + } + + uint64_t height = (uint64_t)r.h - 66; + uint64_t scrollSize = 4; + uint64_t dif = max-min; + if(dif > 0) + scrollSize = height / dif; + + if(scrollSize < 4) scrollSize=4; + + + double scroll = 0; + if(dif > 0) + scroll = (double)(value-min) / (double)dif; + + uint64_t scrollY = scroll * (height-scrollSize); + + + + if(scrollY > height-scrollSize) scrollY = height-scrollSize; + SDL_Rect r2={.x=r.x+win->palette.borderSize,.y=(int)scrollY+r.y+32,.w = r.w-(win->palette.borderSize*2),.h=(int)scrollSize}; + SDL_RenderFillRect(renderer,&r2); + } + bool VScrollView::OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds) + { + if(event.type == SDL_MOUSEMOTION) + { + bool inside = event.motion.x >= visibleBounds.x && event.motion.x < visibleBounds.x+visibleBounds.w && event.motion.y >= visibleBounds.y && event.motion.y < visibleBounds.y+visibleBounds.h; + bool hoverFlag = this->GetViewFlag(VIEWFLAG_HOVER_STATE) || this->GetViewFlag(VIEWFLAG_HOVER_B1STATE) || this->GetViewFlag(VIEWFLAG_HOVER_B2STATE); + if(inside && !hoverFlag) + { + int y = event.motion.y - myBounds.y; + if(y <= 32) + { + //up btn + this->SetViewFlag(VIEWFLAG_HOVER_B1STATE,true); + this->SetViewFlag(VIEWFLAG_HOVER_B2STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_STATE,false); + } + else if(y >= myBounds.h-32) + { + //down btn + this->SetViewFlag(VIEWFLAG_HOVER_B1STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_B2STATE,true); + this->SetViewFlag(VIEWFLAG_HOVER_STATE,false); + } + else { + this->SetViewFlag(VIEWFLAG_HOVER_B1STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_B2STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_STATE,true); + } + + GUIEventArgs e; + this->OnEnter(e); + this->Enter.Invoke(this,e); + } + else if(!inside && hoverFlag) + { + this->SetViewFlag(VIEWFLAG_HOVER_STATE,false); + GUIEventArgs e; + this->OnLeave(e); + this->Leave.Invoke(this,e); + } else if(inside) { + int y = event.motion.y - myBounds.y; + if(y <= 32) + { + //up btn + this->SetViewFlag(VIEWFLAG_HOVER_B1STATE,true); + this->SetViewFlag(VIEWFLAG_HOVER_B2STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_STATE,false); + } + else if(y >= myBounds.h-32) + { + //down btn + this->SetViewFlag(VIEWFLAG_HOVER_B1STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_B2STATE,true); + this->SetViewFlag(VIEWFLAG_HOVER_STATE,false); + } + else { + this->SetViewFlag(VIEWFLAG_HOVER_B1STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_B2STATE,false); + this->SetViewFlag(VIEWFLAG_HOVER_STATE,true); + + + } + + } + + if(this->GetViewFlag(VIEWFLAG_MOUSEDOWN_STATE)) + { + int y = event.motion.y - myBounds.y; + if(y <= 32) + { + value = min; + } + else if(y >= myBounds.h-32) + { + value=max; + } + else { + uint64_t height = (uint64_t)myBounds.h - 66; + uint64_t y2 = y-33; + + double off = (double)y2 / (double)height; + + value = round((max-min)*off)+min; + GUIEventArgs cea2; + this->ValueChanged.Invoke(this,cea2); + } + + } + return false; + } + if(event.type == SDL_MOUSEBUTTONDOWN) + { + if(event.button.x >= visibleBounds.x && event.button.x < visibleBounds.x+visibleBounds.w && event.button.y >= visibleBounds.y && event.button.y < visibleBounds.y+visibleBounds.h) + { + GUIMouseButtonEventArgs cea; + cea.button = (int)event.button.button; + cea.x = event.button.x - myBounds.x; + cea.y = event.button.y - myBounds.y; + cea.which = event.button.which; + if(cea.y <= 32) + { + //up btn + this->SetViewFlag(VIEWFLAG_MOUSEDOWN_B1STATE,true); + } + else if(cea.y >= myBounds.h-32) + { + //down btn + this->SetViewFlag(VIEWFLAG_MOUSEDOWN_B2STATE,true); + } + else { + this->SetViewFlag(VIEWFLAG_MOUSEDOWN_STATE,true); + + uint64_t height = (uint64_t)myBounds.h - 66; + uint64_t y2 = cea.y-33; + + double off = (double)y2 / (double)height; + + value = round((max-min)*off)+min; + GUIEventArgs cea2; + this->ValueChanged.Invoke(this,cea2); + } + OnMouseDown(cea); + this->MouseDown.Invoke(this,cea); + + + + return false; + } + } + else if(event.type == SDL_MOUSEBUTTONUP) + { + if(this->GetViewFlag(VIEWFLAG_MOUSEDOWN_STATE)) + { + GUIMouseButtonEventArgs cea; + cea.button = (int)event.button.button; + cea.x = event.button.x - myBounds.x; + cea.y = event.button.y - myBounds.y; + cea.which = event.button.which; + this->SetViewFlag(VIEWFLAG_MOUSEDOWN_STATE,false); + OnMouseUp(cea); + this->MouseUp.Invoke(this,cea); + GUIEventArgs cea2; + OnClick(cea2); + this->Click.Invoke(this,cea2); + return true; + } + if(this->GetViewFlag(VIEWFLAG_MOUSEDOWN_B1STATE)) + { + GUIMouseButtonEventArgs cea; + cea.button = (int)event.button.button; + cea.x = event.button.x - myBounds.x; + cea.y = event.button.y - myBounds.y; + cea.which = event.button.which; + this->SetViewFlag(VIEWFLAG_MOUSEDOWN_B1STATE,false); + OnMouseUp(cea); + this->MouseUp.Invoke(this,cea); + GUIEventArgs cea2; + OnClick(cea2); + this->Click.Invoke(this,cea2); + this->value -= step; + if(this->value < min) this->value=min; + if(this->value >= max) this->value=min; + OnValueChanged(cea2); + this->ValueChanged.Invoke(this,cea2); + return true; + } + if(this->GetViewFlag(VIEWFLAG_MOUSEDOWN_B2STATE)) + { + GUIMouseButtonEventArgs cea; + cea.button = (int)event.button.button; + cea.x = event.button.x - myBounds.x; + cea.y = event.button.y - myBounds.y; + cea.which = event.button.which; + this->SetViewFlag(VIEWFLAG_MOUSEDOWN_B2STATE,false); + OnMouseUp(cea); + this->MouseUp.Invoke(this,cea); + GUIEventArgs cea2; + OnClick(cea2); + this->Click.Invoke(this,cea2); + this->value += step; + if(this->value > max) this->value=max; + OnValueChanged(cea2); + this->ValueChanged.Invoke(this,cea2); + return true; + } + + return false; + } + return View::OnEvent(event,myBounds,visibleBounds); + } + +} + +#endif \ No newline at end of file diff --git a/src/SDL2/Views/VStackView.cpp b/src/SDL2/Views/VStackView.cpp new file mode 100644 index 0000000..6308e33 --- /dev/null +++ b/src/SDL2/Views/VStackView.cpp @@ -0,0 +1,270 @@ + +#if defined(TESSESFRAMEWORK_ENABLE_SDL2) +#include "TessesFramework/SDL2/Views/VStackView.hpp" + +namespace Tesses::Framework::SDL2::Views +{ + void VStackView::OnDraw(SDL_Renderer* renderer, SDL_Rect& r) + { + int numberOfCells = 0; + int freeHeight = r.h; + std::vector sizes; + sizes.resize(this->items.size()); + + freeHeight -= (this->items.size() - 1) * this->spacing; + + for(size_t i = 0; i < this->items.size(); i++) + { + if(this->items[i].first > 0) + { + //static size + sizes[i] = this->items[i].first; + freeHeight-= this->items[i].first; + } + else if(this->items[i].first == 0) + { + auto prefered = this->items[i].second.first->PreferedMinSize(); + if(prefered.second > 0) + { + sizes[i] = prefered.second; + freeHeight -= prefered.second; + } + else { + sizes[i] = 0; + } + } + else { + numberOfCells -= this->items[i].first; + } + } + + + int cellSize = numberOfCells == 0 ? 0 : freeHeight / numberOfCells; + + + for(int i = 0; i < this->items.size();i++) + { + if(this->items[i].first < 0) + { + int myHeight =((-(this->items[i].first)) * cellSize); + + auto minSz = this->items[i].second.first->PreferedMinSize(); + if(minSz.second > myHeight) { + sizes[i] = minSz.second; + freeHeight -= minSz.second; + numberOfCells -= -(this->items[i].first); + } + } + } + cellSize = numberOfCells == 0 ? 0 : freeHeight / numberOfCells; + int y = 0; + + + for(size_t i = 0; i < this->items.size(); i++) + { + if(i > 0) y += spacing; + + if(sizes[i] == 0) + { + int myHeight =((-(this->items[i].first)) * cellSize); + + + SDL_Rect theirBounds = { + .x = 0, + .y=y, + .w=r.w, + .h=myHeight + }; + + + theirBounds.x += r.x; + theirBounds.y += r.y; + + + + CallOnDraw(this->items[i].second.first,renderer, theirBounds); + y+=myHeight; + } + else { + + SDL_Rect theirBounds = { + .x = 0, + .y=y, + .w=r.w, + .h=sizes[i] + }; + + + theirBounds.x += r.x; + theirBounds.y += r.y; + + + + CallOnDraw(this->items[i].second.first,renderer, theirBounds); + y+=sizes[i]; + } + + } + } + bool VStackView::OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds) + { + int numberOfCells = 0; + int freeHeight = myBounds.h; + std::vector sizes; + sizes.resize(this->items.size()); + + + freeHeight -= (this->items.size() - 1) * this->spacing; + for(size_t i = 0; i < this->items.size(); i++) + { + if(this->items[i].first > 0) + { + //static size + sizes[i] = this->items[i].first; + freeHeight-= this->items[i].first; + } + else if(this->items[i].first == 0) + { + auto prefered = this->items[i].second.first->PreferedMinSize(); + if(prefered.second > 0) + { + sizes[i] = prefered.second; + freeHeight -= prefered.second; + } + else { + sizes[i] = 0; + } + } + else { + numberOfCells -= this->items[i].first; + } + } + + + int cellSize = numberOfCells == 0 ? 0 : freeHeight / numberOfCells; + + for(int i = 0; i < this->items.size();i++) + { + if(this->items[i].first < 0) + { + int myHeight =((-(this->items[i].first)) * cellSize); + + auto minSz = this->items[i].second.first->PreferedMinSize(); + if(minSz.second > myHeight) { + sizes[i] = minSz.second; + freeHeight -= minSz.second; + numberOfCells -= -(this->items[i].first); + } + } + } + + + cellSize = numberOfCells == 0 ? 0 : freeHeight / numberOfCells; + int y = 0; + + + for(size_t i = 0; i < this->items.size(); i++) + { + if(i > 0) y += spacing; + if(sizes[i] == 0) + { + int myHeight =((-(this->items[i].first)) * cellSize); + + SDL_Rect theirBounds = { + .x = 0, + .y=y, + .w=myBounds.w, + .h=myHeight + }; + + SDL_Rect theirVisibleBounds = theirBounds; + theirVisibleBounds.x += visibleBounds.x; + theirVisibleBounds.y += visibleBounds.y; + + theirBounds.x += myBounds.x; + theirBounds.y += myBounds.y; + Clipper::ClipRect(theirVisibleBounds, visibleBounds); + + + + CallOnEvent(this->items[i].second.first,event,theirBounds,theirVisibleBounds); + + y+=myHeight; + } + else { + + SDL_Rect theirBounds = { + .x = 0, + .y=y, + .w=myBounds.w, + .h=sizes[i] + }; + + SDL_Rect theirVisibleBounds = theirBounds; + theirVisibleBounds.x += visibleBounds.x; + theirVisibleBounds.y += visibleBounds.y; + + theirBounds.x += myBounds.x; + theirBounds.y += myBounds.y; + Clipper::ClipRect(theirVisibleBounds, visibleBounds); + + + + CallOnEvent(this->items[i].second.first,event,theirBounds,theirVisibleBounds); + + y+=sizes[i]; + } + + } + return false; + } + VStackView::VStackView() : ContainerView() + { + + } + + void VStackView::Add(int sz, View* view, bool owns) + { + this->items.push_back(std::pair>(sz,std::pair(view,owns))); + this->AssignChildParentToThis(view); + } + void VStackView::Remove(View* view) + { + for(auto index = this->items.begin(); index < this->items.end(); index++) + { + if(index->second.first == view) + { + + if(index->second.first != nullptr && index->second.second) + delete view; + this->items.erase(index); + return; + } + } + } + void VStackView::Clear() + { + for(auto& item : this->items) + if(item.second.second && item.second.first != nullptr) delete item.second.first; + items = {}; + } + + size_t VStackView::ViewCount() + { + return this->items.size(); + } + View* VStackView::GetViewAt(size_t index) + { + return this->items.at(index).second.first; + } + + VStackView::~VStackView() + { + for(auto& item : this->items) + if(item.second.second && item.second.first != nullptr) delete item.second.first; + } + + + +} +#endif \ No newline at end of file diff --git a/src/TF_Init.cpp b/src/TF_Init.cpp index 1bab200..aaea897 100644 --- a/src/TF_Init.cpp +++ b/src/TF_Init.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #if defined(TESSESFRAMEWORK_ENABLE_SQLITE) extern "C" { @@ -67,6 +68,25 @@ namespace Tesses::Framework volatile static bool isRunningSig=true; volatile static std::atomic isRunning; volatile static std::atomic gaming_console_events=true; + + #if defined(TESSESFRAMEWORK_ENABLE_THREADING) + Threading::Mutex invokings_mtx; + + std::queue> invokings; + #endif + + + void TF_Invoke(std::function cb) + { + #if defined(TESSESFRAMEWORK_ENABLE_THREADING) + invokings_mtx.Lock(); + invokings.push(cb); + invokings_mtx.Unlock(); + #else + cb(); + #endif + } + void TF_ConnectToSelf(uint16_t port) { Tesses::Framework::Streams::NetworkStream ns("127.0.0.1",port,false,false,false); @@ -103,8 +123,19 @@ namespace Tesses::Framework OnItteraton.Invoke(ittr++); #if defined(TESSESFRAMEWORK_ENABLE_THREADING) && (defined(GEKKO) || defined(__SWITCH__)) Tesses::Framework::Threading::LookForFinishedThreads(); + + #endif + #if defined(TESSESFRAMEWORK_ENABLE_THREADING) + invokings_mtx.Lock(); + auto invokes = invokings; + invokings_mtx.Unlock(); + while(!invokes.empty()) + { + invokes.front()(); + invokes.pop(); + + } #endif - if(!isRunningSig) isRunning=false; #if defined(GEKKO) @@ -157,6 +188,8 @@ namespace Tesses::Framework #endif #if defined(TESSESFRAMEWORK_ENABLE_SDL2) SDL_Quit(); + Tesses::Framework::SDL2::gui.CloseWindows(); + #endif } void TF_Init()