Add GUI Support

This commit is contained in:
2025-06-12 15:43:58 -05:00
parent dd4527645e
commit 71a2c83e5a
59 changed files with 3114 additions and 103 deletions

View File

@ -16,7 +16,7 @@ jobs:
commands: |
mkdir build
cd build
cmake -S .. -B . -DTESSESFRAMEWORK_FETCHCONTENT=OFF
cmake -S .. -B . -DTESSESFRAMEWORK_FETCHCONTENT=OFF -DTESSESFRAMEWORK_ENABLE_SDL2=ON
make -j12
make install DESTDIR=out
useTTY: true

View File

@ -24,10 +24,15 @@ src/Streams/Stream.cpp
src/Streams/BufferedStream.cpp
src/Streams/ByteReader.cpp
src/Streams/ByteWriter.cpp
src/Streams/PtyStream.cpp
src/TextStreams/StreamReader.cpp
src/TextStreams/StreamWriter.cpp
src/TextStreams/TextReader.cpp
src/TextStreams/TextWriter.cpp
src/TextStreams/StdIOReader.cpp
src/TextStreams/StdIOWriter.cpp
src/TextStreams/StringReader.cpp
src/TextStreams/StringWriter.cpp
src/Threading/Thread.cpp
src/Threading/Mutex.cpp
src/Filesystem/VFS.cpp
@ -42,6 +47,16 @@ src/TF_Init.cpp
src/wrapper.cpp
src/HiddenField.cpp
src/SDL2/FontCache.cpp
src/SDL2/Stream.cpp
src/SDL2/GUI.cpp
src/SDL2/GUIWindow.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/ProgressView.cpp
src/SDL2/Views/CheckView.cpp
)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
@ -69,21 +84,31 @@ endif()
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include)
include(cmake/bin2h.cmake)
if(TESSESFRAMEWORK_ENABLE_SDL2)
find_package(SDL2 REQUIRED)
find_package(SDL2_ttf REQUIRED)
find_package(SDL2_image REQUIRED)
endif()
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/include/TessesFramework/TanoheSans-Regular.h" "#pragma once\n")
bin2h(SOURCE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/font/NonMono/TanoheSans-Regular.ttf" HEADER_FILE "${CMAKE_CURRENT_BINARY_DIR}/include/TessesFramework/TanoheSans-Regular.h" VARIABLE_NAME TanoheSansRegular APPEND NULL_TERMINATE)
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/include/TessesFramework/TanoheSans-Regular.h" "\n")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/include/TessesFramework/aardvark-fixed-regular.h" "#pragma once\n")
bin2h(SOURCE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/font/Mono/aardvark-fixed-regular.ttf" HEADER_FILE "${CMAKE_CURRENT_BINARY_DIR}/include/TessesFramework/aardvark-fixed-regular.h" VARIABLE_NAME AardvarkFixedRegular APPEND NULL_TERMINATE)
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/include/TessesFramework/aardvark-fixed-regular.h" "\n")
endif()
if(TESSESFRAMEWORK_ENABLE_MBED)
if(TESSESFRAMEWORK_EMBED_CERT_BUNDLE)
include(cmake/bin2h.cmake)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/include/TessesFramework/CertificateChain.h "#pragma once\n")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/include/TessesFramework/CertificateChain.h" "#pragma once\n")
#target_compile_definitions(TessesFramework PUBLIC TESSESFRAMEWORK_EMBED_CERT_BUNDLE)
bin2h(SOURCE_FILE ${TESSESFRAMEWORK_CERT_BUNDLE_FILE} HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/include/TessesFramework/CertificateChain.h VARIABLE_NAME CertificateChain APPEND NULL_TERMINATE)
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/include/TessesFramework/CertificateChain.h "\n")
bin2h(SOURCE_FILE "${TESSESFRAMEWORK_CERT_BUNDLE_FILE}" HEADER_FILE "${CMAKE_CURRENT_BINARY_DIR}/include/TessesFramework/CertificateChain.h" VARIABLE_NAME CertificateChain APPEND NULL_TERMINATE)
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/include/TessesFramework/CertificateChain.h" "\n")
else()
target_compile_definitions(TessesFramework PUBLIC TESSESFRAMEWORK_CERT_BUNDLE_FILE=${TESSESFRAMEWORK_CERT_BUNDLE_FILE})
@ -164,7 +189,7 @@ target_link_libraries(${TessesFramework_TARGET} PUBLIC ws2_32)
endif()
if(NOT ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "NintendoWii" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "NintendoGameCube"))
if(NOT("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows" OR PLATFORM_PS2 OR "${CMAKE_SYSTEM_NAME}" STREQUAL "NintendoWii" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "NintendoGameCube"))
if(TESSESFRAMEWORK_ENABLE_THREADING)
set(THREADS_PREFER_PTHREAD_FLAG ON)
@ -176,6 +201,10 @@ if(TESSESFRAMEWORK_ENABLE_SETDATE)
target_compile_definitions(${TessesFramework_TARGET} PUBLIC TESSESFRAMEWORK_ENABLE_SETDATE)
endif()
target_compile_definitions(${TessesFramework_TARGET} PUBLIC _FILE_OFFSET_BITS=64)
if(PLATFORM_PS2)
target_link_libraries(${TessesFramework_TARGET} PUBLIC -ldebug)
endif()
endfunction()
include(GNUInstallDirs)
@ -281,6 +310,14 @@ if(TESSESFRAMEWORK_ENABLE_EXAMPLES)
endif()
if(TESSESFRAMEWORK_ENABLE_APPS)
if(TESSESFRAMEWORK_ENABLE_SDL2)
add_executable(tguilayouttester apps/guilayouttester.cpp)
target_link_libraries(tguilayouttester PUBLIC tessesframework)
install(TARGETS tguilayouttester DESTINATION bin)
endif()
add_executable(tanonydrop apps/tanonydrop.cpp)
target_link_libraries(tanonydrop PUBLIC tessesframework)
install(TARGETS tanonydrop DESTINATION bin)
add_executable(tfetch apps/tfetch.cpp)
target_link_libraries(tfetch PUBLIC tessesframework)
install(TARGETS tfetch DESTINATION bin)

View File

@ -24,3 +24,7 @@ sudo make install
## Code used from other peoples projects
- [Multipart parser (rewriten in C++ was C# in dejuric/simplehttp)](https://github.com/dajuric/simple-http)
## Resources used from others
- [ca-certificate.crt (from ubuntu)](ca-certificate.crt)
- [TanoheSans-Regular.ttf (license OFL)](font/License-OFL.txt)

75
apps/guilayouttester.cpp Normal file
View File

@ -0,0 +1,75 @@
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#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/Filesystem/LocalFS.hpp"
#include "TessesFramework/SDL2/Views/ProgressView.hpp"
#include "TessesFramework/SDL2/Views/CheckView.hpp"
#include "TessesFramework/TextStreams/StreamReader.hpp"
#include "TessesFramework/Streams/FileStream.hpp"
#include <iostream>
using namespace Tesses::Framework;
using namespace Tesses::Framework::SDL2;
using namespace Tesses::Framework::Streams;
using namespace Tesses::Framework::TextStreams;
using namespace Tesses::Framework::Serialization::Json;
void Load(GUIWindow& window, std::string jsonFile)
{
FILE* f = fopen(jsonFile.c_str(),"rb");
if(f != NULL)
{
FileStream strm(f,true,"rb");
StreamReader r(&strm,false);
auto text = r.ReadToEnd();
try {
auto obj = Json::Decode(text);
window.SetView(obj);
} catch(...)
{
}
}
}
#endif
int main(int argc,char** argv)
{
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
if(argc < 2)
{
std::cout << "USAGE: " << argv[0] << " layout.json" << std::endl;
return 0;
}
std::string jsonFile = argv[1];
TF_Init();
GUIPalette pal0(true,(SDL_Color){.r=255,.g=0,.b=0,.a=255},20);
GUIWindow window("Press ALT+R to Reload",640,480,SDL_WINDOW_RESIZABLE,pal0);
window.SDLEvent += std::make_shared<FunctionalEvent<View*,GUISDLEventEventArgs&>>([&window,jsonFile](View* sender, GUISDLEventEventArgs& e)->void{
if(e.event.type == SDL_KEYUP && (uint64_t)(e.event.key.keysym.mod & SDL_Keymod::KMOD_ALT) != 0 && e.event.key.keysym.sym == SDLK_r)
{
Load(window,jsonFile);
}
});
Load(window,jsonFile);
TF_RunEventLoop();
TF_Quit();
#endif
return 0;
}

94
apps/tanonydrop.cpp Normal file
View File

@ -0,0 +1,94 @@
#include "TessesFramework/TessesFramework.hpp"
#include <iostream>
using namespace Tesses::Framework;
using namespace Tesses::Framework::Streams;
using namespace Tesses::Framework::Http;
using namespace Tesses::Framework::Filesystem;
VFS* vfs;
int main(int argc, char** argv)
{
TF_InitWithConsole();
vfs = new SubdirFilesystem(&LocalFS,Tesses::Framework::Filesystem::VFSPath::GetAbsoluteCurrentDirectory(),false);
CallbackServer cb([](ServerContext& ctx)->bool{
if(ctx.path == "/")
{
ctx.WithMimeType("text/html")
.SendText(
"<!DOCTYPE html>"
"<html>"
"<head><meta charset=\"UTF-8\"><title>AnonyDump</title></head>"
"<body>"
"<h1>AnonyDump</h1>"
"<a href=\"./files/\">Files</a>"
"<form action=\"./upload\" method=\"post\" enctype=\"multipart/form-data\" accept-charset=\"UTF-8\">"
"<input type=\"file\" name=\"file\" multiple>"
"<input type=\"submit\" value=\"Upload\">"
"</form>"
"</body>"
"</html>"
);
return true;
}
else if(ctx.path == "/upload")
{
if(ctx.NeedToParseFormData())
{
ctx.ParseFormData([](std::string mime, std::string filename,std::string name)->Stream* {
if(name != "file") return nullptr;
VFSPath path("/"+filename);
auto strm = vfs->OpenFile(path,"wb");
return strm;
});
ctx.WithMimeType("text/html")
.SendText(
"<!DOCTYPE html>"
"<html>"
"<head><title>AnonyDump - Uploaded successfully</title>"
"<body>"
"<h1>Uploaded successfully</h1>"
"<a href=\"./\">Back</a>"
"</form>"
"</body>"
"</html>"
);
return true;
}
else {
ctx.statusCode= Tesses::Framework::Http::BadRequest;
ctx.WithMimeType("text/html")
.SendText(
"<!DOCTYPE html>"
"<html>"
"<head><title>AnonyDump - Error: Must contain multipart and POST</title>"
"<body>"
"<h1>Error: Must contain multipart and POST</h1>"
"<a href=\"./\">Back</a>"
"</form>"
"</body>"
"</html>"
);
}
}
return false;
});
Tesses::Framework::Http::MountableServer mountable(cb);
mountable.Mount("/files/",new FileServer(vfs,true,true,false),true);
HttpServer srv(4985,mountable);
srv.StartAccepting();
TF_RunEventLoop();
TF_Quit();
return 0;
}

View File

@ -1,28 +1,101 @@
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include <SDL2/SDL.h>
#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/Filesystem/LocalFS.hpp"
#include "TessesFramework/SDL2/Views/ProgressView.hpp"
#include "TessesFramework/SDL2/Views/CheckView.hpp"
#include <iostream>
using namespace Tesses::Framework;
using namespace Tesses::Framework::SDL2;
#endif
int main(int argc,char** argv)
{
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
SDL_Init(SDL_INIT_EVERYTHING);
TF_Init();
SDL_Window* window = SDL_CreateWindow("My SDL Window",0,0,320,240,0);
std::vector<std::pair<SDL_Color,std::string>> colors={
std::pair<SDL_Color,std::string>({.r=255,.g=0,.b=128,.a=255},"Magenta"),
std::pair<SDL_Color,std::string>({.r=255,.g=0,.b=0,.a=255}, "Red"),
std::pair<SDL_Color,std::string>({.r=0,.g=255,.b=0,.a=255}, "Green"),
std::pair<SDL_Color,std::string>({.r=0,.g=0,.b=255,.a=255}, "Blue"),
std::pair<SDL_Color,std::string>({.r=255,.g=255,.b=0,.a=255}, "Yellow"),
std::pair<SDL_Color,std::string>({.r=143, .g=188, .b=143,.a=255},"Dark sea Green"),
std::pair<SDL_Color,std::string>({.r=63, .g=253, .b=170,.a=255},"Aqua")
};
SDL_Renderer* renderer=SDL_CreateRenderer(window,-1,SDL_RENDERER_ACCELERATED);
while(true)
bool darkMode=true;
size_t color_index=0;
GUIPalette pal0(darkMode,colors[color_index % colors.size()].first,20);
GUIWindow window("My Window Title",640,480,SDL_WINDOW_RESIZABLE,pal0);
Views::LabelView lbl("A random label\nThat spans lines.");
Views::ButtonView btn("Dark Mode");
Views::ButtonView btn2(colors[0].second);
Views::ProgressView progress(42.42);
Views::CheckView cv(false,"Checkbox");
Views::CheckView cv2(false,"Another Checkbox");
Views::TextListView list;
for(auto item : Tesses::Framework::Filesystem::LocalFS.EnumeratePaths((std::string)"/usr/bin"))
{
SDL_Event event;
if(SDL_PollEvent(&event) && event.type == SDL_QUIT) break;
SDL_SetRenderDrawColor(renderer,255,0,0,255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
list.items.push_back(item.GetFileName());
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
//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);
abs.Add({.x=248,.y=64,.w=200,.h=50},&cv,false);
abs.Add({.x=32,.y=134,.w=200,.h=50},&btn2,false);
abs.Add({.x=248,.y=134,.w=200,.h=50},&cv2,false);
abs.Add({.x=32,.y=190,.w=200,.h=30},&progress,false);
abs.Add({.x=32,.y=230,.w=320,.h=240},&list,false);
window.SetView(&abs,false);
btn.Click += std::make_shared<FunctionalEvent<View*,GUIEventArgs&>>([&window,&darkMode,&color_index,&colors,&btn](View* sender, GUIEventArgs& e)->void{
darkMode = !darkMode;
btn.SetText(darkMode ? "Light Mode" : "Dark Mode");
GUIPalette palette(darkMode,colors[color_index % colors.size()].first,20);
window.SetPalette(palette);
});
btn2.Click += std::make_shared<FunctionalEvent<View*,GUIEventArgs&>>([&window,&darkMode,&color_index,&colors,&btn2](View* sender, GUIEventArgs& e)->void{
color_index++;
btn2.SetText(colors[color_index % colors.size()].second);
GUIPalette palette(darkMode,colors[color_index % colors.size()].first,20);
window.SetPalette(palette);
});
TF_RunEventLoop();
TF_Quit();
#endif
return 0;
}

8
font/Mono/README.md Normal file
View File

@ -0,0 +1,8 @@
Font Attribution
================
- [Licensed under OFL (SIL Open Font License)](http://scripts.sil.org/OFL)
- [Get the font](https://fontlibrary.org/en/font/aardvark-sans)
- [Made by Belleve Invis](https://fontlibrary.org/en/font/aardvark-sans)
I didn't see a LICENSE file in the font ZIP

Binary file not shown.

View File

@ -0,0 +1,95 @@
Copyright (c) 2014, Cooper Hewitt Smithsonian Design Museum
(cooperhewitt.org), with Reserved Font Name COOPER HEWITT.
Copyright (c) 2019-2020 by Cristiano Sobral (cssobral2013@gmail.com).
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

View File

@ -87,6 +87,17 @@ namespace Tesses::Framework
}
mtx.Unlock();
}
void Remove(std::function<bool(std::shared_ptr<Event<TArgs...>>)> cb)
{
for(auto index = this->items.begin(); index != this->items.end(); index++)
{
if(cb(*index))
{
this->items.erase(index);
index--;
}
}
}
};
extern EventList<uint64_t> OnItteraton;

View File

@ -147,6 +147,7 @@ struct CaseInsensitiveLess {
static std::string UrlPathDecode(std::string v);
static std::string UrlPathEncode(std::string v, bool ignoreSpace=false);
static std::string HtmlEncode(std::string v);
static std::string HtmlDecodeOnlyEntityNumber(std::string v);
static std::vector<std::string> SplitString(std::string text, std::string delimiter,std::size_t maxCnt = std::string::npos);
static std::string Replace(std::string str, std::string find, std::string replace);
static std::string StatusCodeString(StatusCode code);

View File

@ -1,4 +1,5 @@
#pragma once
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include <array>
#include <SDL2/SDL.h>
@ -11,17 +12,20 @@ class FontCache
{
std::array<SDL_Texture*,96> font_chrs;
int mw,mh,ps;
void Load(SDL_Renderer* renderer,TTF_Font* font,const SDL_Color& color);
void Load(SDL_Renderer* renderer,TTF_Font* font);
public:
FontCache(SDL_Renderer* renderer,TTF_Font* font,const SDL_Color& color);
FontCache(SDL_Renderer* renderer,std::string font,int sz,const SDL_Color& color);
FontCache(SDL_Renderer* renderer,const uint8_t* mem,size_t cnt,int sz,const SDL_Color& color);
FontCache(SDL_Renderer* renderer,const std::vector<uint8_t>& v,int sz,const SDL_Color& color);
FontCache(SDL_Renderer* renderer,TTF_Font* font);
FontCache(SDL_Renderer* renderer,std::string font,int sz);
FontCache(SDL_Renderer* renderer,const uint8_t* mem,size_t cnt,int sz);
FontCache(SDL_Renderer* renderer,const std::vector<uint8_t>& v,int sz);
FontCache(SDL_Renderer* renderer,int sz);
SDL_Texture* operator[](char c);
SDL_Texture* GetCharOfColor(char c, const SDL_Color& color);
int MaxWidth();
int MaxHeight();
int PointSize();
void CalculateSize(std::string text, int& x,int& y);
void Render(SDL_Renderer* renderer,int x,int y, std::string text, const SDL_Color& color);
~FontCache();
};
}

View File

@ -0,0 +1,244 @@
#pragma once
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include <SDL2/SDL.h>
#include "FontCache.hpp"
#include "../Filesystem/VFSFix.hpp"
#include "../Filesystem/VFS.hpp"
#include "../Common.hpp"
#include "../Serialization/Json.hpp"
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);
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;
int fontSize;
SDL_Color& GetBorderColor(bool isHovering, bool isActive, bool isMouseDown);
};
class GUIEventArgs
{
public:
virtual std::string Type();
virtual ~GUIEventArgs();
};
class View;
class GUIMouseButtonEventArgs : public GUIEventArgs
{
public:
Uint32 which;
int x;
int y;
Uint8 button;
std::string Type();
};
class GUIJsonViewNotFoundEventArgs : public GUIEventArgs
{
public:
std::string Type();
View* destView;
Tesses::Framework::Serialization::Json::JObject jsonObject;
std::string typeString;
};
class GUISDLEventEventArgs : public GUIEventArgs
{
public:
std::string Type();
SDL_Event event;
};
constexpr uint64_t VIEWFLAG_HOVER_STATE=(uint64_t)1 << 0;
constexpr uint64_t VIEWFLAG_MOUSEDOWN_STATE =(uint64_t)1<<1;
constexpr uint64_t VIEWFLAG_ISACTIVE=(uint64_t)1<<2;
constexpr uint64_t VIEWFLAG_TABSTOP=(uint64_t)1<<3;
constexpr uint64_t VIEWFLAG_INTERCEPT_TAB=(uint64_t)1<<4;
constexpr uint64_t VIEWFLAG_CHECKED=(uint64_t)1<<5;
class GUIPopup;
class GUIWindow;
class ContainerView;
class View {
protected:
std::string text;
std::string id;
uint64_t flags;
protected:
View();
View(std::string text);
virtual void OnDraw(SDL_Renderer* renderer, SDL_Rect& r);
virtual void OnDragDropFile(Tesses::Framework::Filesystem::VFSPath filePath,SDL_Rect myRect, SDL_Point dropLoc);
virtual void OnDragDropText(std::string text,SDL_Rect myRect, SDL_Point dropLoc);
virtual void OnEnter(GUIEventArgs& evt);
virtual void OnLeave(GUIEventArgs& evt);
virtual void OnMouseDown(GUIMouseButtonEventArgs& evt);
virtual void OnMouseUp(GUIMouseButtonEventArgs& evt);
virtual void OnClick(GUIEventArgs& evt);
virtual bool OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds);
virtual void OnSetParent(View* v);
void CallOnDraw(View* view, SDL_Renderer* renderer, SDL_Rect& myRect)
{
view->OnDraw(renderer,myRect);
}
bool CallOnEvent(View* view,SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds)
{
return view->OnEvent(event,myBounds,visibleBounds);
}
ContainerView* parent;
public:
bool GetViewFlag(uint64_t flag)
{
return (this->flags & flag) != 0;
}
void SetViewFlag(uint64_t flag, bool value)
{
if(value)
this->flags |= flag;
else
this->flags &= ~flag;
}
EventList<View*,GUIMouseButtonEventArgs&> MouseUp;
EventList<View*,GUIMouseButtonEventArgs&> MouseDown;
EventList<View*,GUIEventArgs&> Click;
EventList<View*,GUIEventArgs&> Enter;
EventList<View*,GUIEventArgs&> Leave;
EventList<View*,GUISDLEventEventArgs&> SDLEvent;
virtual ~View();
friend class GUIWindow;
virtual GUIWindow* GetWindow();
virtual std::string GetText();
virtual void SetText(std::string text);
virtual void SetId(std::string id);
virtual std::string GetId();
virtual View* FindViewById(std::string id);
friend class ContainerView;
};
class ContainerView : public View {
public:
virtual size_t ViewCount()=0;
virtual View* GetViewAt(size_t index)=0;
virtual View* FindViewById(std::string id);
protected:
ContainerView();
ContainerView(std::string text);
void AssignChildParentToThis(View* view)
{
if(view != nullptr)
{
view->parent = this;
view->OnSetParent(this);
}
}
};
enum class TabNextResult {
KeepGoing,
TabNext,
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:
size_t ViewCount();
View* GetViewAt(size_t index);
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();
friend class GUIWindow;
};
class GUIWindow : public ContainerView
{
std::vector<GUIPopup*> popups;
View* child;
bool ownsChild;
SDL_Window* window;
SDL_Renderer* renderer;
void Event(SDL_Event& event);
void Draw();
void DeactivateAll(View* view);
void TabNext(View* view,TabNextResult& nr);
protected:
void OnDraw(SDL_Renderer* renderer, SDL_Rect& myRect);
bool OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds);
public:
EventList<View*,GUIJsonViewNotFoundEventArgs&> JsonViewNotFound;
size_t ViewCount();
View* GetViewAt(size_t index);
FontCache* normal_font;
FontCache* monospaced_font;
GUIPalette palette;
GUIWindow(std::string title, int w, int h, Uint32 flags, const GUIPalette& palette);
void SetPalette(const GUIPalette& palette);
void SetView(View* view,bool owns=true);
void ShowPopup(GUIPopup* popup);
void ShowPopup(GUIPopup& popup);
void MakeActive(View* view);
void TabNext();
GUIWindow* GetWindow();
~GUIWindow();
friend class GUI;
friend class GUIPopup;
void SetText(std::string text);
void SetView(Tesses::Framework::Serialization::Json::JToken json);
View* CreateViewFromJson(Tesses::Framework::Serialization::Json::JObject json);
};
class GUI {
std::vector<GUIWindow*> windows;
public:
void Update();
friend class GUIWindow;
};
extern GUI gui;
class Clipper {
SDL_Rect theRect;
SDL_Renderer* renderer;
bool isClipped;
public:
Clipper(SDL_Renderer* renderer, SDL_Rect& myRect);
bool Clip(SDL_Rect rect);
~Clipper();
static void ClipRect(SDL_Rect& child, SDL_Rect& parent);
};
}
#endif

View File

@ -0,0 +1,12 @@
#pragma once
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include <SDL2/SDL.h>
#include <string>
namespace Tesses::Framework::SDL2
{
bool TryParseSDLColor(std::string str, SDL_Color& col);
}
#endif

View File

@ -0,0 +1,9 @@
#pragma once
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include "../Streams/Stream.hpp"
#include <SDL2/SDL_rwops.h>
namespace Tesses::Framework::SDL2
{
SDL_RWops* RwopsFromStream(Tesses::Framework::Streams::Stream* strm, bool owns=true);
}
#endif

View File

@ -0,0 +1,33 @@
#pragma once
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include "../GUI.hpp"
namespace Tesses::Framework::SDL2::Views
{
class AbsoluteView : public ContainerView {
std::vector<std::pair<std::pair<View*,bool>,SDL_Rect>> views;
protected:
void OnDraw(SDL_Renderer* renderer, SDL_Rect& myRect);
bool OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds);
public:
size_t ViewCount();
View* GetViewAt(size_t index);
AbsoluteView();
void Add(SDL_Rect rect, View* view, bool owns=true);
void Set(View* view, SDL_Rect rect);
void Remove(View* view);
~AbsoluteView();
};
/* class AbsoluteContainer : public View {
std::vector<std::pair<std::pair<View*,bool>,SDL_Rect>> views;
public:
void Add(SDL_Rect rect, View* view, bool owns=true);
void Set(View* view, SDL_Rect rect);
void Remove(View* view);
~AbsoluteContainer();
};*/
}
#endif

View File

@ -0,0 +1,18 @@
#pragma once
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include "../GUI.hpp"
namespace Tesses::Framework::SDL2::Views
{
class ButtonView : 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:
ButtonView();
ButtonView(std::string text);
};
}
#endif

View File

@ -0,0 +1,25 @@
#pragma once
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include "../GUI.hpp"
namespace Tesses::Framework::SDL2::Views
{
class CheckView : public View {
protected:
virtual void OnCheckChanged(GUIEventArgs& event);
virtual void OnDraw(SDL_Renderer* renderer, SDL_Rect& r);
virtual bool OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds);
public:
CheckView(bool checked, std::string label);
CheckView();
virtual bool GetChecked();
virtual void SetChecked(bool value);
EventList<View*,GUIEventArgs&> CheckChanged;
};
}
#endif

View File

@ -0,0 +1,15 @@
#pragma once
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include "../GUI.hpp"
namespace Tesses::Framework::SDL2::Views
{
class LabelView : public View {
protected:
virtual void OnDraw(SDL_Renderer* renderer, SDL_Rect& r);
public:
LabelView();
LabelView(std::string text);
};
}
#endif

View File

@ -0,0 +1,17 @@
#pragma once
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include "../GUI.hpp"
namespace Tesses::Framework::SDL2::Views
{
class ProgressView : public View
{
protected:
virtual void OnDraw(SDL_Renderer* renderer, SDL_Rect& r);
public:
ProgressView();
ProgressView(double value);
double value;
};
};
#endif

View File

@ -0,0 +1,20 @@
#pragma once
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include "../GUI.hpp"
namespace Tesses::Framework::SDL2::Views
{
class TextListView : 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:
TextListView();
size_t firstIndex;
int selected;
std::vector<std::string> items;
};
}
#endif

View File

@ -17,19 +17,7 @@ namespace Tesses::Framework::Serialization::Json
class JOItem;
class JObject {
std::map<std::string,JToken> map;
public:
JObject();
JObject(std::initializer_list<JOItem> items);
void SetValue(std::string key, JToken item);
JToken GetValue(std::string key);
void Remove(std::string key);
std::map<std::string,JToken>& GetMap();
std::map<std::string,JToken>::iterator begin();
std::map<std::string,JToken>::iterator end();
};
class JArray
class JArray
{
std::vector<JToken> items;
public:
@ -46,15 +34,36 @@ namespace Tesses::Framework::Serialization::Json
std::vector<JToken>::iterator begin();
std::vector<JToken>::iterator end();
};
class JOItem {
public:
JOItem();
JOItem(std::string key, JToken value);
std::string key;
JToken value;
class JObject {
std::map<std::string,JToken> map;
public:
JObject();
JObject(std::initializer_list<JOItem> items);
void SetValue(std::string key, JToken item);
template<typename T>
bool TryGetValueAsType(std::string key, T& value)
{
auto obj = GetValue(key);
if(std::holds_alternative<T>(obj))
{
value = std::get<T>(obj);
return true;
}
return false;
}
JToken GetValue(std::string key);
void Remove(std::string key);
std::map<std::string,JToken>& GetMap();
std::map<std::string,JToken>::iterator begin();
std::map<std::string,JToken>::iterator end();
};
template<typename T>
template<typename T>
bool TryGetJToken(JToken json, T& item)
{
if(std::holds_alternative<T>(json))
@ -64,6 +73,16 @@ namespace Tesses::Framework::Serialization::Json
}
return false;
}
class JOItem {
public:
JOItem();
JOItem(std::string key, JToken value);
std::string key;
JToken value;
};
class Json
{

View File

@ -21,6 +21,13 @@ namespace Tesses::Framework::Streams
bool IsValid();
void Close();
};
enum class SocketType {
ST_IPv4_TCP,
ST_IPv4_UDP,
ST_IPv6_TCP,
ST_IPv6_UDP,
ST_UNIX
};
class NetworkStream : public Stream {
int32_t sock;
bool owns;
@ -30,7 +37,7 @@ namespace Tesses::Framework::Streams
bool EndOfStream();
bool CanRead();
bool CanWrite();
NetworkStream(bool ipV6,bool datagram);
NetworkStream(SocketType type);
NetworkStream(std::string unixPath,bool isServer);
NetworkStream(std::string ipOrFqdn, uint16_t port, bool datagram,bool broadcast,bool supportIPv6);
NetworkStream(int32_t sock, bool owns);

View File

@ -0,0 +1,29 @@
#pragma once
#include "Stream.hpp"
namespace Tesses::Framework::Streams
{
struct WindowSize {
uint16_t Width;
uint16_t Height;
uint16_t Columns;
uint16_t Rows;
};
class PtyStream : public Stream
{
int socket;
int64_t pid;
bool eos;
WindowSize wS;
public:
PtyStream(WindowSize sz,std::string filename, std::vector<std::string> args,std::vector<std::string> env);
bool EndOfStream();
bool CanRead();
bool CanWrite();
size_t Read(uint8_t* buff, size_t sz);
size_t Write(const uint8_t* buff, size_t sz);
void Resize(WindowSize sz);
WindowSize GetWindowSize();
~PtyStream();
};
}

View File

@ -14,6 +14,10 @@
#include "Streams/ByteWriter.hpp"
#include "TextStreams/StreamReader.hpp"
#include "TextStreams/StreamWriter.hpp"
#include "TextStreams/StdIOReader.hpp"
#include "TextStreams/StdIOWriter.hpp"
#include "TextStreams/StringReader.hpp"
#include "TextStreams/StringWriter.hpp"
#include "Threading/Thread.hpp"
#include "Threading/Mutex.hpp"
#include "Threading/ThreadPool.hpp"
@ -29,3 +33,5 @@
#include "HiddenField.hpp"
#include "Serialization/Json.hpp"
#include "SDL2/FontCache.hpp"
#include "SDL2/Stream.hpp"
#include "SDL2/GUI.hpp"

View File

@ -0,0 +1,13 @@
#include "TextReader.hpp"
namespace Tesses::Framework::TextStreams
{
class ConsoleReader : public TextReader {
public:
ConsoleReader();
bool ReadBlock(std::string& str,size_t sz);
};
ConsoleReader StdIn();
}

View File

@ -0,0 +1,15 @@
#include "TextWriter.hpp"
namespace Tesses::Framework::TextStreams
{
class ConsoleWriter : public TextWriter {
bool isError;
public:
ConsoleWriter(bool isError=false);
void WriteData(const char* text, size_t len);
};
ConsoleWriter StdOut();
ConsoleWriter StdErr();
}

View File

@ -14,6 +14,7 @@ namespace Tesses::Framework::TextStreams
StreamReader(Tesses::Framework::Streams::Stream* strm, bool owns);
StreamReader(std::filesystem::path filename);
bool ReadBlock(std::string& str,size_t sz);
bool Rewind();
~StreamReader();
};
}

View File

@ -0,0 +1,15 @@
#include "TextReader.hpp"
namespace Tesses::Framework::TextStreams {
class StringReader : public TextReader {
std::string str;
size_t offset;
public:
StringReader();
StringReader(std::string str);
size_t& GetOffset();
std::string& GetString();
bool Rewind();
bool ReadBlock(std::string& str,size_t sz);
};
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "TextWriter.hpp"
namespace Tesses::Framework::TextStreams
{
class StringWriter : public TextWriter {
private:
std::string text;
public:
std::string& GetString();
StringWriter();
StringWriter(std::string str);
void WriteData(const char* text, size_t len);
};
}

View File

@ -6,6 +6,7 @@ namespace Tesses::Framework::TextStreams
class TextReader
{
public:
virtual bool Rewind();
virtual bool ReadBlock(std::string& str,size_t sz)=0;
int32_t ReadChar();
std::string ReadLine();

View File

@ -3,14 +3,73 @@
namespace Tesses::Framework::TextStreams
{
class NewLine {}; //dummy class
class TextWriter {
public:
TextWriter();
std::string newline;
virtual void WriteData(const char* text, size_t len)=0;
void Write(std::string txt);
void Write(int64_t n);
void Write(uint64_t n);
void Write(const void* ptr);
void Write(const char* ptr);
void Write(char c);
void Write(double d);
void Write(std::string text);
inline TextWriter& operator<<(int64_t n)
{
Write(n);
return *this;
}
inline TextWriter& operator<<(uint64_t n)
{
Write(n);
return *this;
}
inline TextWriter& operator<<(const void* n)
{
Write(n);
return *this;
}
inline TextWriter& operator<<(const char* n)
{
Write(n);
return *this;
}
inline TextWriter& operator<<(char n)
{
Write(n);
return *this;
}
inline TextWriter& operator<<(double n)
{
Write(n);
return *this;
}
inline TextWriter& operator<<(std::string n)
{
Write(n);
return *this;
}
inline TextWriter& operator<<(NewLine nl)
{
WriteLine();
return *this;
}
void WriteLine(std::string txt);
void WriteLine(int64_t n);
void WriteLine(uint64_t n);
void WriteLine(const void* ptr);
void WriteLine(const char* ptr);
void WriteLine(char c);
void WriteLine(double d);
void WriteLine();
virtual ~TextWriter();
};
}

View File

@ -10,7 +10,7 @@ namespace Tesses::Framework::Date
{
int GetTimeZone()
{
#if defined(__SWITCH__) || defined(_WIN32) || defined(GEKKO)
#if defined(__SWITCH__) || defined(_WIN32) || defined(GEKKO) || defined(__PS2__)
return (int)(-_timezone);
#else
return (int)(-timezone);
@ -18,7 +18,7 @@ namespace Tesses::Framework::Date
}
bool TimeZoneSupportDST()
{
#if defined(__SWITCH__) || defined(_WIN32) || defined(GEKKO)
#if defined(__SWITCH__) || defined(_WIN32) || defined(GEKKO) || defined(__PS2__)
return _daylight == 1;
#else
return daylight == 1;
@ -56,9 +56,9 @@ namespace Tesses::Framework::Date
secs /= 60;
hour = secs % 24;
day = (int)(uint32_t)ymd.day();
month = (int)(uint32_t)ymd.month();
year = (int32_t)ymd.year();
day = (int)(unsigned)ymd.day();
month = (int)(unsigned)ymd.month();
year = (int)ymd.year();
}
DateTime::DateTime(int64_t epoch)
{
@ -141,7 +141,7 @@ namespace Tesses::Framework::Date
date::year_month_day ymd(epoch);
auto month = (uint32_t)ymd.month();
auto month = (unsigned)ymd.month();
if(month > 3 && month < 11)
{
@ -149,7 +149,7 @@ namespace Tesses::Framework::Date
}
else if(month == 3)
{
auto day = (uint32_t)ymd.day();
auto day = (unsigned)ymd.day();
if(day > 14) isDST=true;
else if(day >= 8 && day <= 14)
{
@ -172,7 +172,7 @@ namespace Tesses::Framework::Date
}
else if(month == 11)
{
auto day = (uint32_t)ymd.day();
auto day = (unsigned)ymd.day();
if(day >= 1 && day <= 7)
{
date::year_month_weekday ymw(epoch);
@ -220,7 +220,7 @@ namespace Tesses::Framework::Date
date::year_month_day ymd(epoch);
auto month = (uint32_t)ymd.month();
auto month = (unsigned)ymd.month();
if(month > 3 && month < 11)
{
@ -228,7 +228,7 @@ namespace Tesses::Framework::Date
}
else if(month == 3)
{
auto day = (uint32_t)ymd.day();
auto day = (unsigned)ymd.day();
if(day > 14) isDST=true;
else if(day >= 8 && day <= 14)
{
@ -251,7 +251,7 @@ namespace Tesses::Framework::Date
}
else if(month == 11)
{
auto day = (uint32_t)ymd.day();
auto day = (unsigned)ymd.day();
if(day >= 1 && day <= 7)
{
date::year_month_weekday ymw(epoch);
@ -357,7 +357,7 @@ namespace Tesses::Framework::Date
date::year_month_day ymd(epoch);
auto month = (uint32_t)ymd.month();
auto month = (unsigned)ymd.month();
if(month > 3 && month < 11)
{
@ -365,7 +365,7 @@ namespace Tesses::Framework::Date
}
else if(month == 3)
{
auto day = (uint32_t)ymd.day();
auto day = (unsigned)ymd.day();
if(day > 14) isDST=true;
else if(day >= 8 && day <= 14)
{
@ -388,7 +388,7 @@ namespace Tesses::Framework::Date
}
else if(month == 11)
{
auto day = (uint32_t)ymd.day();
auto day = (unsigned)ymd.day();
if(day >= 1 && day <= 7)
{
date::year_month_weekday ymw(epoch);

View File

@ -36,7 +36,11 @@ namespace Tesses::Framework::Http
p = p.substr(1, p.size()-2);
}
p = HttpUtils::UrlPathDecode(p);
cd.filename = p;
}
else if(res2[0] == "name")

View File

@ -75,7 +75,7 @@ namespace Tesses::Framework::Http
if(this->allowListing)
{
std::string p = HttpUtils::HtmlEncode(ctx.originalPath);
std::string html = "<!DOCTYPE html><html><head><title>Index of ";
std::string html = "<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><title>Index of ";
html.append(p);
html.append("</title></head><body><h1>Index of ");
html.append(p);

View File

@ -9,19 +9,18 @@
#include "TessesFramework/Crypto/MbedHelpers.hpp"
#include "TessesFramework/Threading/Mutex.hpp"
#include "TessesFramework/Common.hpp"
#include "TessesFramework/TextStreams/StdIOWriter.hpp"
#include <iostream>
using FileStream = Tesses::Framework::Streams::FileStream;
using Stream = Tesses::Framework::Streams::Stream;
using SeekOrigin = Tesses::Framework::Streams::SeekOrigin;
using MemoryStream = Tesses::Framework::Streams::MemoryStream;
using StreamReader = Tesses::Framework::TextStreams::StreamReader;
using StreamWriter = Tesses::Framework::TextStreams::StreamWriter;
using TcpServer = Tesses::Framework::Streams::TcpServer;
using NetworkStream = Tesses::Framework::Streams::NetworkStream;
using BufferedStream = Tesses::Framework::Streams::BufferedStream;
using namespace Tesses::Framework::TextStreams;
namespace Tesses::Framework::Http
{
@ -503,6 +502,7 @@ namespace Tesses::Framework::Http
else
{
auto strm = cb(ct, cd1.filename, cd1.fieldName);
if(strm == nullptr) strm = new Stream();
bool retVal = parseUntillBoundaryEnd(&ctx->GetStream(),strm,boundary);
delete strm;
return retVal;
@ -635,13 +635,13 @@ namespace Tesses::Framework::Http
{
TF_LOG("Before printing interfaces");
std::cout << "\x1B[34mInterfaces:\n";
StdOut() << "\x1B[34mInterfaces:" << NewLine();
for(auto _ip : NetworkStream::GetIPs())
{
std::cout << "\x1B[32m";
std::cout << _ip.first << ": ";
std::cout << "\x1B[35mhttp://";
std::cout << _ip.second << ":" << std::to_string(this->GetPort()) << "/\n";
StdOut() << "\x1B[32m"
<< _ip.first << ": "
<< "\x1B[35mhttp://"
<< _ip.second << ":" << (uint64_t)this->GetPort() << "/" << NewLine();
}
@ -649,7 +649,7 @@ namespace Tesses::Framework::Http
if(this->showARTL)
{
if(!svr->IsValid()) std::cout << "\x1B[31mError, we failed to bind or something\x1B[39m\n" << std::endl;
std::cout << "\x1B[31mAlmost Ready to Listen\x1B[39m\n";
StdOut() << "\x1B[31mAlmost Ready to Listen\x1B[39m" << NewLine();
}
TF_LOG("After printing interfaces");

View File

@ -516,6 +516,68 @@ namespace Tesses::Framework::Http {
}
return strs;
}
std::string HttpUtils::HtmlDecodeOnlyEntityNumber(std::string v)
{
std::string buff={};
int state = 0;
uint64_t n=0;
for(auto item : v)
{
switch(state)
{
case 0:
if(item == '&') state=1;
else buff.push_back(item);
break;
case 1:
if(item == '#') {state = 2; n=0;}
else {state=0; buff.push_back('&'); buff.push_back(item); }
break;
case 2:
if(item == ';') {
state = 0;
if(n <= 0x7F)
{
buff.push_back((char)n);
}
else if(n >= 0x80 && n <= 0x7FF)
{
uint8_t high = 0b11000000 | ((uint8_t)(n >> 6) & 0b00011111);
uint8_t low = 0b10000000 | ((uint8_t)(n) & 0b00111111);
buff.push_back((char)high);
buff.push_back((char)low);
}
else if(n >= 0x800 && n <= 0xFFFF)
{
uint8_t high = 0b11100000 | ((uint8_t)(n >> 12) & 0b00001111);
uint8_t low = 0b10000000 | ((uint8_t)(n >> 6) & 0b00111111);
uint8_t lowest = 0b10000000 | ((uint8_t)(n) & 0b00111111);
buff.push_back((char)high);
buff.push_back((char)low);
buff.push_back((char)lowest);
}
else if(n >= 0x010000 && n <= 0x10FFFF)
{
uint8_t highest = 0b11110000 | ((uint8_t)(n >> 18) & 0b00000111);
uint8_t high = 0b10000000 | ((uint8_t)(n >> 12) & 0b00111111);
uint8_t low = 0b10000000 | ((uint8_t)(n >> 6) & 0b00111111);
uint8_t lowest = 0b10000000 | ((uint8_t)(n) & 0b00111111);
buff.push_back((char)highest);
buff.push_back((char)high);
buff.push_back((char)low);
buff.push_back((char)lowest);
}
}
else if(item >= '0' && item <= '9')
{
n *= 10;
n += item - '0';
}
}
}
return buff;
}
std::string HttpUtils::HtmlEncode(std::string html)
{
std::string myHtml = {};

View File

@ -1,7 +1,10 @@
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include "TessesFramework/SDL2/FontCache.hpp"
#include "TessesFramework/Http/HttpUtils.hpp"
#include "TessesFramework/TanoheSans-Regular.h"
using HU= Tesses::Framework::Http::HttpUtils;
namespace Tesses::Framework::SDL2 {
void FontCache::Load(SDL_Renderer* renderer,TTF_Font* font,const SDL_Color& color)
void FontCache::Load(SDL_Renderer* renderer,TTF_Font* font)
{
this->mw=0;
this->mh=0;
@ -9,7 +12,7 @@ void FontCache::Load(SDL_Renderer* renderer,TTF_Font* font,const SDL_Color& colo
for(size_t i = 0; i < this->font_chrs.size();i++)
{
SDL_Surface* surf = TTF_RenderGlyph_Blended(font,(Uint16)(i+32),color);
SDL_Surface* surf = TTF_RenderGlyph_Blended(font,(Uint16)(i+32),{.r=255,.g=255,.b=255,.a=255});
if(surf->w > this->mw) mw = surf->w;
if(surf->h > this->mh) mh = surf->h;
this->font_chrs[i] = SDL_CreateTextureFromSurface(renderer,surf);
@ -17,35 +20,123 @@ void FontCache::Load(SDL_Renderer* renderer,TTF_Font* font,const SDL_Color& colo
}
}
FontCache::FontCache(SDL_Renderer* renderer,std::string font,int sz,const SDL_Color& color)
FontCache::FontCache(SDL_Renderer* renderer,std::string font,int sz)
{
TTF_Font* f = TTF_OpenFont(font.c_str(),sz);
Load(renderer,f,color);
Load(renderer,f);
TTF_CloseFont(f);
}
FontCache::FontCache(SDL_Renderer* renderer,const uint8_t* mem,size_t cnt,int sz,const SDL_Color& color)
FontCache::FontCache(SDL_Renderer* renderer,const uint8_t* mem,size_t cnt,int sz)
{
TTF_Font* f = TTF_OpenFontRW(SDL_RWFromConstMem(mem,cnt),1,sz);
Load(renderer,f,color);
Load(renderer,f);
TTF_CloseFont(f);
}
FontCache::FontCache(SDL_Renderer* renderer,const std::vector<uint8_t>& v,int sz,const SDL_Color& color) : FontCache(renderer,v.data(),v.size(),sz,color)
FontCache::FontCache(SDL_Renderer* renderer,const std::vector<uint8_t>& v,int sz) : FontCache(renderer,v.data(),v.size(),sz)
{
}
FontCache::FontCache(SDL_Renderer* renderer,TTF_Font* font,const SDL_Color& color)
FontCache::FontCache(SDL_Renderer* renderer,TTF_Font* font)
{
this->Load(renderer,font,color);
this->Load(renderer,font);
}
FontCache::FontCache(SDL_Renderer* renderer,int sz) : FontCache(renderer,TANOHESANSREGULAR,TANOHESANSREGULAR_SIZE,sz)
{
}
void FontCache::CalculateSize(std::string text, int& x,int& y)
{
int myX = 0;
x=0;
y=0;
int maxH = MaxHeight();
y=maxH;
for(auto c : text)
{
switch(c)
{
case '\n':
{
y += maxH;
if(myX > x) x = myX;
myX = 0;
}
break;
case '\t':
{
auto tex = operator[](' ');
int wi;
SDL_QueryTexture(tex,NULL,NULL,&wi,NULL);
myX += wi * 4;
}
break;
default:
{
auto tex = operator[](c);
int wi;
int he;
SDL_QueryTexture(tex,NULL,NULL,&wi,&he);
myX += wi;
}
break;
}
}
if(myX > x) x = myX;
}
void FontCache::Render(SDL_Renderer* renderer,int x,int y, std::string text,const SDL_Color& color)
{
int myX = x;
int maxH = MaxHeight();
for(auto c : text)
{
switch(c)
{
case '\n':
{
y += maxH;
myX = x;
}
break;
case '\t':
{
auto tex = GetCharOfColor(' ',color);
int wi;
SDL_QueryTexture(tex,NULL,NULL,&wi,NULL);
myX += wi * 4;
}
break;
default:
{
auto tex = GetCharOfColor(c,color);
int wi;
int he;
SDL_QueryTexture(tex,NULL,NULL,&wi,&he);
SDL_Rect src={.x=0,.y=0,.w=wi,.h=he};
SDL_Rect dest={.x=myX,.y=y,.w=wi,.h=he};
myX += wi;
SDL_RenderCopy(renderer,tex,&src,&dest);
}
break;
}
}
}
SDL_Texture* FontCache::GetCharOfColor(char c, const SDL_Color& color)
{
auto res = (c >= 32 && c <= 126) ? this->font_chrs[c-32] : this->font_chrs[95];
SDL_SetTextureColorMod(res,color.r,color.g,color.b);
return res;
}
SDL_Texture* FontCache::operator[](char c)
{
if(c >= 32 && c <= 126)
{
return this->font_chrs[c-32];
}
return this->font_chrs[95];
return GetCharOfColor(c,{.r=255,.g=255,.b=255,.a=255});
}
FontCache::~FontCache()
{
@ -65,5 +156,121 @@ int FontCache::PointSize()
{
return this->ps;
}
bool TryParseSDLColor(std::string str, SDL_Color& col)
{
str = HU::Replace(str," ","");
//rgba(255,255,255,1.0)
//rgb(197, 30, 30)
//#rgb
//#rgba
//#rrggbb
//#rrggbbaa
if(str.size() >= 4 && str[0] == '#')
{
if(str.size() == 4)
{
auto r = HU::HexToNibble(str[1]);
r |= r << 4;
auto g = HU::HexToNibble(str[2]);
g |= g << 4;
auto b = HU::HexToNibble(str[3]);
b |= b << 4;
col.r = r;
col.g = g;
col.b = b;
col.a = 255;
return true;
}
else if(str.size() == 5)
{
auto r = HU::HexToNibble(str[1]);
r |= r << 4;
auto g = HU::HexToNibble(str[2]);
g |= g << 4;
auto b = HU::HexToNibble(str[3]);
b |= b << 4;
auto a = HU::HexToNibble(str[4]);
a |= a << 4;
col.r = r;
col.g = g;
col.b = b;
col.a = a;
return true;
}
else if(str.size() == 7) {
auto r = HU::HexToNibble(str[1]);
r |= HU::HexToNibble(str[2]) << 4;
auto g = HU::HexToNibble(str[3]);
g |= HU::HexToNibble(str[4]) << 4;
auto b = HU::HexToNibble(str[5]);
b |= HU::HexToNibble(str[6]) << 4;
col.r = r;
col.g = g;
col.b = b;
col.a = 255;
return true;
}
else if(str.size() == 9)
{
auto r = HU::HexToNibble(str[1]);
r |= HU::HexToNibble(str[2]) << 4;
auto g = HU::HexToNibble(str[3]);
g |= HU::HexToNibble(str[4]) << 4;
auto b = HU::HexToNibble(str[5]);
b |= HU::HexToNibble(str[6]) << 4;
auto a = HU::HexToNibble(str[7]);
a |= HU::HexToNibble(str[8]) << 4;
col.r = r;
col.g = g;
col.b = b;
col.a = a;
return true;
}
}
else if(str.size() > 4 && strncmp(str.c_str(),"rgb(",4) == 0 && str[str.size()-1] == ')')
{
str = HU::Replace(str.substr(4),")","");
auto parts = HU::SplitString(str,",");
if(parts.size() != 3) return false;
try{
auto r = std::stoul(parts[0]);
auto g = std::stoul(parts[1]);
auto b = std::stoul(parts[2]);
col.r = (Uint8)r;
col.g = (Uint8)g;
col.b = (Uint8)b;
col.a = 255;
} catch(...) {
return false;
}
return true;
}
else if(str.size() > 5 && strncmp(str.c_str(),"rgba(",5) == 0 && str[str.size()-1] == ')')
{
str = HU::Replace(str.substr(5),")","");
auto parts = HU::SplitString(str,",");
if(parts.size() != 4) return false;
try{
auto r = std::stoul(parts[0]);
auto g = std::stoul(parts[1]);
auto b = std::stoul(parts[2]);
double a= std::stod(parts[3]);
col.r = (Uint8)r;
col.g = (Uint8)g;
col.b = (Uint8)b;
col.a = (Uint8)(a * 255);
} catch(...) {
return false;
}
return true;
}
return false;
}
}
#endif

231
src/SDL2/GUI.cpp Normal file
View File

@ -0,0 +1,231 @@
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include "TessesFramework/SDL2/GUI.hpp"
#include <iostream>
namespace Tesses::Framework::SDL2
{
GUI gui;
void GUI::Update()
{
if(this->windows.empty()) return;
for(auto index = this->windows.begin(); index != this->windows.end(); index++)
{
if(*index == nullptr)
{
this->windows.erase(index);
index--;
}
}
if(this->windows.empty()) return;
SDL_Event event;
while(SDL_PollEvent(&event))
{
for(auto win : this->windows)
{
if(win == nullptr) continue;
auto id = SDL_GetWindowID(win->window);
switch(event.type)
{
case SDL_EventType::SDL_WINDOWEVENT:
if(event.window.windowID == id)
{
win->Event(event);
}
break;
case SDL_EventType::SDL_MOUSEBUTTONDOWN:
case SDL_EventType::SDL_MOUSEBUTTONUP:
if(event.button.windowID == id)
{
win->Event(event);
}
break;
case SDL_EventType::SDL_MOUSEMOTION:
if(event.motion.windowID == id)
{
win->Event(event);
}
break;
case SDL_EventType::SDL_MOUSEWHEEL:
if(event.wheel.windowID == id)
{
win->Event(event);
}
break;
case SDL_EventType::SDL_KEYUP:
case SDL_EventType::SDL_KEYDOWN:
if(event.key.windowID == id)
{
win->Event(event);
}
break;
case SDL_EventType::SDL_TEXTEDITING:
if(event.edit.windowID == id)
{
win->Event(event);
}
break;
case SDL_EventType::SDL_TEXTEDITING_EXT:
if(event.editExt.windowID == id)
{
win->Event(event);
}
break;
case SDL_EventType::SDL_TEXTINPUT:
if(event.text.windowID == id)
{
win->Event(event);
}
break;
case SDL_EventType::SDL_DROPBEGIN:
case SDL_EventType::SDL_DROPCOMPLETE:
case SDL_EventType::SDL_DROPFILE:
case SDL_EventType::SDL_DROPTEXT:
if(event.drop.windowID == id)
{
win->Event(event);
}
break;
default:
win->Event(event);
break;
}
}
if(event.type == SDL_QUIT)
{
TF_SetIsRunning(false);
break;
}
}
for(auto item : this->windows)
{
if(item != nullptr)
item->Draw();
}
}
Clipper::Clipper(SDL_Renderer* renderer, SDL_Rect& myRect)
{
this->isClipped=SDL_RenderIsClipEnabled(renderer);
SDL_RenderGetClipRect(renderer,&this->theRect);
if(!this->isClipped) this->theRect = myRect;
this->renderer = renderer;
}
void Clipper::ClipRect(SDL_Rect& child, SDL_Rect& parent)
{
if(child.x < parent.x)
{
int rem = parent.x- child.x;
child.x += rem;
child.w -= rem;
}
if(child.y < parent.y)
{
int rem = parent.y- child.y;
child.y += rem;
child.h -= rem;
}
if((child.x + child.w) > (parent.x + parent.w))
child.w = (parent.x + parent.w) - child.x;
if((child.y + child.h) > (parent.y + parent.h))
child.h = (parent.y + parent.h) - child.y;
}
bool Clipper::Clip(SDL_Rect rect)
{
ClipRect(rect,this->theRect);
if(rect.w <= 0 || rect.h <= 0) return false;
SDL_RenderSetClipRect(renderer, &rect);
return true;
}
Clipper::~Clipper()
{
if(isClipped) SDL_RenderSetClipRect(renderer, &this->theRect);
else SDL_RenderSetClipRect(renderer, nullptr);
}
GUIPalette::GUIPalette()
{
this->fontSize=24;
}
SDL_Color& GUIPalette::GetBorderColor(bool isHovering, bool isActive, bool isMouseDown)
{
bool isHovering2=isHovering ^ isMouseDown;
if(isHovering2 && isActive)
return this->border_hover_active;
if(isHovering2)
return this->border_hover;
if(isActive)
return this->border_active;
return this->border_color;
}
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)
{
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->fontSize = fontSize;
}
std::string GUIEventArgs::Type()
{
return "Base";
}
GUIEventArgs::~GUIEventArgs()
{
}
std::string GUIMouseButtonEventArgs::Type()
{
return "MouseButton";
}
std::string GUIJsonViewNotFoundEventArgs::Type()
{
return "JsonViewNotFound";
}
std::string GUISDLEventEventArgs::Type()
{
return "SDLEvent";
}
GUIPalette::GUIPalette(bool isDarkMode, SDL_Color accent,int fontSize)
{
this->accent = accent;
this->fontSize = fontSize;
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->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};
}
else
{
this->background = {.r=239,.g=239,.b=239,.a=255};
this->border_color = {.r=0,.g=0,.b=0,.a=255};
this->border_active = {.r=92,.g=92,.b=92,.a=255};
this->border_hover = {.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};
}
}
}
#endif

367
src/SDL2/GUIWindow.cpp Normal file
View File

@ -0,0 +1,367 @@
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include "TessesFramework/SDL2/GUI.hpp"
#include "TessesFramework/aardvark-fixed-regular.h"
#include "TessesFramework/SDL2/Views/ButtonView.hpp"
#include "TessesFramework/SDL2/Views/LabelView.hpp"
#include "TessesFramework/SDL2/Views/CheckView.hpp"
#include "TessesFramework/SDL2/Views/ProgressView.hpp"
#include "TessesFramework/SDL2/Views/TextListView.hpp"
#include "TessesFramework/SDL2/Views/AbsoluteView.hpp"
#include "TessesFramework/SDL2/ParseColor.hpp"
namespace Tesses::Framework::SDL2
{
void GUIWindow::MakeActive(View* view)
{
if(!view->GetViewFlag(VIEWFLAG_TABSTOP)) return;
if(view->GetViewFlag(VIEWFLAG_ISACTIVE)) return;
DeactivateAll(this);
view->SetViewFlag(VIEWFLAG_ISACTIVE,true);
}
void GUIWindow::DeactivateAll(View* view)
{
view->SetViewFlag(VIEWFLAG_ISACTIVE,false);
auto cv = dynamic_cast<ContainerView*>(view);
if(cv != nullptr)
{
for(size_t i = 0; i < cv->ViewCount();i++)
{
DeactivateAll(cv->GetViewAt(i));
}
}
}
void GUIWindow::TabNext(View* view,TabNextResult& nr)
{
if(nr == TabNextResult::Done)
return;
auto cv = dynamic_cast<ContainerView*>(view);
if(cv != nullptr)
{
for(size_t i = 0; i < cv->ViewCount();i++)
{
TabNext(cv->GetViewAt(i),nr);
if(nr == TabNextResult::Done)
return;
}
}
else
{
if(view->GetViewFlag(VIEWFLAG_ISACTIVE))
{
if(view->GetViewFlag(VIEWFLAG_INTERCEPT_TAB))
{
SDL_Rect r;
r.x=0;
r.y=0;
r.w=0;
r.h=0;
SDL_Event event;
event.type = SDL_KEYDOWN;
event.key.keysym.mod = SDL_Keymod::KMOD_NONE;
event.key.keysym.scancode = SDL_SCANCODE_TAB;
event.key.keysym.sym = SDL_KeyCode::SDLK_TAB;
view->CallOnEvent(view,event,r,r);
nr = TabNextResult::Done;
}
view->SetViewFlag(VIEWFLAG_ISACTIVE,false);
nr= TabNextResult::TabNext;
}
else if(view->GetViewFlag(VIEWFLAG_TABSTOP) && nr == TabNextResult::TabNext)
{
view->SetViewFlag(VIEWFLAG_ISACTIVE,true);
nr = TabNextResult::Done;
}
}
}
void GUIWindow::TabNext()
{
TabNextResult nr=TabNextResult::KeepGoing;
TabNext(this,nr);
if(nr != TabNextResult::Done)
{
nr = TabNextResult::TabNext;
TabNext(this,nr);
}
}
void GUIWindow::SetView(View* view,bool owns)
{
if(this->ownsChild && this->child != view)
delete this->child;
this->child = view;
this->ownsChild = owns;
if(view != nullptr)
view->parent = this;
}
GUIWindow* GUIWindow::GetWindow()
{
return this;
}
size_t GUIWindow::ViewCount()
{
return this->child != nullptr ? 1 : 0;
}
View* GUIWindow::GetViewAt(size_t index)
{
if(index > 0) return nullptr;
return this->child;
}
void GUIWindow::Draw()
{
int w,h;
SDL_GetWindowSize(window,&w,&h);
SDL_Rect r={.x=0,.y=0,.w=w,.h=h};
OnDraw(renderer,r);
}
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};
OnEvent(event,r,r);
}
void GUIWindow::OnDraw(SDL_Renderer* renderer, SDL_Rect& r)
{
SDL_SetRenderDrawColor(renderer,this->palette.background.r,this->palette.background.g,this->palette.background.b,this->palette.background.a);
SDL_RenderClear(renderer);
if(this->child != nullptr)
this->child->OnDraw(renderer,r);
SDL_RenderPresent(renderer);
}
bool GUIWindow::OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& myVisibleBounds)
{
if(event.type == SDL_EventType::SDL_KEYDOWN && event.key.keysym.sym ==SDL_KeyCode::SDLK_TAB)
{
GUISDLEventEventArgs sdle;
sdle.event = event;
this->SDLEvent.Invoke(this,sdle);
TabNext();
return true;
}
if(this->child != nullptr) { GUISDLEventEventArgs sdle;
sdle.event = event; this->SDLEvent.Invoke(this,sdle); return this->child->OnEvent(event,myBounds,myVisibleBounds);}
return View::OnEvent(event,myBounds,myVisibleBounds);
}
GUIWindow::GUIWindow(std::string title, int w, int h, Uint32 flags, const GUIPalette& palette) : ContainerView(title)
{
this->window = SDL_CreateWindow(title.c_str(),SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,w,h,flags);
this->renderer = SDL_CreateRenderer(this->window,-1,SDL_RENDERER_ACCELERATED);
SDL_SetRenderDrawBlendMode(renderer,SDL_BlendMode::SDL_BLENDMODE_BLEND);
this->child=nullptr;
this->parent=nullptr;
this->ownsChild=false;
this->normal_font=nullptr;
this->monospaced_font=nullptr;
gui.windows.push_back(this);
this->SetPalette(palette);
}
void GUIWindow::SetText(std::string text)
{
this->text = text;
SDL_SetWindowTitle(this->window,text.c_str());
}
void GUIWindow::SetPalette(const GUIPalette& palette)
{
this->palette = palette;
if(this->normal_font != nullptr)
delete this->normal_font;
if(this->monospaced_font != nullptr)
delete this->monospaced_font;
this->normal_font = new FontCache(this->renderer,this->palette.fontSize);
this->monospaced_font = new FontCache(this->renderer,AARDVARKFIXEDREGULAR,AARDVARKFIXEDREGULAR_SIZE,this->palette.fontSize);
}
GUIWindow::~GUIWindow()
{
if(this->ownsChild)
delete this->child;
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
for(auto index = gui.windows.begin(); index < gui.windows.end(); index++)
{
if(*index == this)
{
*index = nullptr;
break;
}
}
}
void GUIWindow::SetView(Tesses::Framework::Serialization::Json::JToken item)
{
Tesses::Framework::Serialization::Json::JObject dict;
if(Tesses::Framework::Serialization::Json::TryGetJToken(item,dict))
{
Tesses::Framework::Serialization::Json::JObject o;
Tesses::Framework::Serialization::Json::JObject sz;
Tesses::Framework::Serialization::Json::JObject pal0;
std::string title;
if(dict.TryGetValueAsType("Child",o))
{
this->SetView(CreateViewFromJson(o));
}
if(dict.TryGetValueAsType("Size",sz))
{
int w0,h0;
SDL_GetWindowSize(this->window,&w0,&h0);
int64_t w=w0;
int64_t h=h0;
sz.TryGetValueAsType("Width",w);
sz.TryGetValueAsType("Height",h);
SDL_SetWindowSize(this->window,(int)w,(int)h);
}
if(dict.TryGetValueAsType("Palette",pal0))
{
bool darkMode=true;
SDL_Color accent={.r=255,.g=0,.b=0,.a=255};
std::string _str;
int64_t fontSize=20;
pal0.TryGetValueAsType("IsDarkMode",darkMode);
pal0.TryGetValueAsType("FontSize",fontSize);
if(pal0.TryGetValueAsType("Accent",_str))
TryParseSDLColor(_str,accent);
GUIPalette pal(darkMode,accent,fontSize);
if(pal0.TryGetValueAsType("Background",_str))
TryParseSDLColor(_str,pal.background);
if(pal0.TryGetValueAsType("Border",_str))
TryParseSDLColor(_str,pal.border_color);
if(pal0.TryGetValueAsType("BorderActive",_str))
TryParseSDLColor(_str,pal.border_active);
if(pal0.TryGetValueAsType("BorderHover",_str))
TryParseSDLColor(_str,pal.border_hover);
if(pal0.TryGetValueAsType("BorderHoverActive",_str))
TryParseSDLColor(_str,pal.border_hover_active);
this->SetPalette(pal);
}
if(dict.TryGetValueAsType("Title",title) || dict.TryGetValueAsType("Text",title))
{
this->SetText(title);
}
}
}
View* GUIWindow::CreateViewFromJson(Tesses::Framework::Serialization::Json::JObject json)
{
std::string type;
if(json.TryGetValueAsType("Type",type))
{
std::string id={};
std::string text={};
bool active=false;
json.TryGetValueAsType("Id",id);
json.TryGetValueAsType("Text",text);
json.TryGetValueAsType("Active",active);
if(type == "ButtonView")
{
auto btn = new Views::ButtonView(text);
btn->SetId(id);
btn->SetViewFlag(VIEWFLAG_ISACTIVE,active);
return btn;
}
else if(type == "CheckView")
{
bool checked;
json.TryGetValueAsType("Checked",checked);
auto cv = new Views::CheckView(checked,text);
cv->SetId(id);
cv->SetViewFlag(VIEWFLAG_ISACTIVE,active);
return cv;
}
else if(type == "LabelView")
{
auto lv = new Views::LabelView(text);
lv->SetId(id);
return lv;
}
else if(type == "ProgressView")
{
double v=0;
json.TryGetValueAsType("Value",v);
auto pv = new Views::ProgressView(v);
pv->SetId(id);
return pv;
}
else if(type == "TextListView")
{
std::vector<std::string> 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::TextListView();
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();
av->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))
{
Tesses::Framework::Serialization::Json::JObject boundsDict;
SDL_Rect r={.x=0,.y=0,.w=200,.h=200};
if(dict.TryGetValueAsType("Bounds",boundsDict))
{
int64_t n;
if(boundsDict.TryGetValueAsType("X",n)) r.x = (int)n;
if(boundsDict.TryGetValueAsType("Y",n)) r.y = (int)n;
if(boundsDict.TryGetValueAsType("Width",n)) r.w = (int)n;
if(boundsDict.TryGetValueAsType("Height",n)) r.h = (int)n;
}
auto myO = CreateViewFromJson(dict);
if(myO != nullptr)
{
av->Add(r,myO);
}
}
}
}
return av;
}
else {
GUIJsonViewNotFoundEventArgs e;
e.destView == nullptr;
e.jsonObject = json;
e.typeString = type;
JsonViewNotFound.Invoke(this,e);
return e.destView;
}
}
return nullptr;
}
}
#endif

77
src/SDL2/Stream.cpp Normal file
View File

@ -0,0 +1,77 @@
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include "TessesFramework/SDL2/Stream.hpp"
namespace Tesses::Framework::SDL2 {
static SDLCALL size_t rwops_stream_read(struct SDL_RWops * context, void *ptr,
size_t size, size_t maxnum)
{
if(context->hidden.unknown.data1 == nullptr) return 0;
auto ctx = static_cast<Tesses::Framework::Streams::Stream*>(context->hidden.unknown.data1);
if(ctx->CanRead())
return ctx->Read((uint8_t*)ptr,size*maxnum) / size;
return 0;
}
static SDLCALL size_t rwops_stream_write(struct SDL_RWops * context, const void *ptr,
size_t size, size_t maxnum)
{
if(context->hidden.unknown.data1 == nullptr) return 0;
auto ctx = static_cast<Tesses::Framework::Streams::Stream*>(context->hidden.unknown.data1);
if(ctx->CanWrite())
return ctx->Write((const uint8_t*)ptr,size*maxnum) / size;
return 0;
}
static SDLCALL Sint64 rwops_stream_seek(struct SDL_RWops * context, Sint64 offset,
int whence)
{
if(context->hidden.unknown.data1 == nullptr) return -1;
auto ctx = static_cast<Tesses::Framework::Streams::Stream*>(context->hidden.unknown.data1);
if(!ctx->CanSeek()) return -1;
switch(whence)
{
case RW_SEEK_SET:
ctx->Seek(offset,Tesses::Framework::Streams::SeekOrigin::Begin);
break;
case RW_SEEK_CUR:
ctx->Seek(offset,Tesses::Framework::Streams::SeekOrigin::Current);
break;
case RW_SEEK_END:
ctx->Seek(offset,Tesses::Framework::Streams::SeekOrigin::End);
break;
}
return ctx->GetPosition();
}
static SDLCALL Sint64 rwops_stream_size(struct SDL_RWops * context)
{
if(context->hidden.unknown.data1 == nullptr) return -1;
auto ctx = static_cast<Tesses::Framework::Streams::Stream*>(context->hidden.unknown.data1);
return ctx->GetLength();
}
static SDLCALL int rwops_stream_close(struct SDL_RWops* context)
{
if(context->hidden.unknown.data2 == nullptr) return 0;
delete static_cast<Tesses::Framework::Streams::Stream*>(context->hidden.unknown.data1);
return 0;
}
SDL_RWops* RwopsFromStream(Tesses::Framework::Streams::Stream* strm, bool owns)
{
auto rw=SDL_AllocRW();
rw->type = SDL_RWOPS_UNKNOWN;
rw->hidden.unknown.data1 = static_cast<void*>(strm);
rw->hidden.unknown.data2 = (void*)(uintptr_t)(owns?1:0);
rw->read = rwops_stream_read;
rw->write = rwops_stream_write;
rw->seek = rwops_stream_seek;
rw->size = rwops_stream_size;
rw->close = rwops_stream_close;
return rw;
}
}
#endif

173
src/SDL2/View.cpp Normal file
View File

@ -0,0 +1,173 @@
#include "TessesFramework/SDL2/GUI.hpp"
using namespace Tesses::Framework::Serialization::Json;
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include "TessesFramework/SDL2/Views/ButtonView.hpp"
#include "TessesFramework/SDL2/Views/CheckView.hpp"
#include "TessesFramework/SDL2/Views/LabelView.hpp"
namespace Tesses::Framework::SDL2
{
ContainerView::ContainerView() : View()
{
this->flags = 0;
}
ContainerView::ContainerView(std::string text) : View(text)
{
this->flags = 0;
}
View::View() : View((std::string){})
{
}
View::View(std::string text)
{
this->text = text;
this->flags=VIEWFLAG_TABSTOP;
}
void View::SetText(std::string text)
{
this->text=text;
}
std::string View::GetText()
{
return this->text;
}
void View::OnMouseUp(GUIMouseButtonEventArgs& click)
{
}
void View::OnMouseDown(GUIMouseButtonEventArgs& click)
{
}
void View::OnClick(GUIEventArgs& click)
{
}
GUIWindow* View::GetWindow()
{
if(this->parent ==nullptr) return nullptr;
return this->parent->GetWindow();
}
void View::OnDragDropFile(Tesses::Framework::Filesystem::VFSPath filePath,SDL_Rect myRect, SDL_Point dropLoc)
{
}
void View::OnDragDropText(std::string text,SDL_Rect myRect, SDL_Point dropLoc)
{
}
void View::OnEnter(GUIEventArgs& evt)
{
}
void View::OnLeave(GUIEventArgs& evt)
{
}
void View::OnDraw(SDL_Renderer* renderer, SDL_Rect& myRect)
{
}
void View::OnSetParent(View* v)
{
}
bool View::OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& myVisibleBounds)
{
GUISDLEventEventArgs sdle;
sdle.event = event;
this->SDLEvent.Invoke(this,sdle);
if(event.type == SDL_MOUSEBUTTONDOWN)
{
if(event.button.x >= myVisibleBounds.x && event.button.x < myVisibleBounds.x+myVisibleBounds.w && event.button.y >= myVisibleBounds.y && event.button.y < myVisibleBounds.y+myVisibleBounds.h)
{
GUIMouseButtonEventArgs cea;
cea.button = (int)event.button.button;
cea.x = event.button.x - myVisibleBounds.x;
cea.y = event.button.y - myVisibleBounds.y;
cea.which = event.button.which;
this->SetViewFlag(VIEWFLAG_MOUSEDOWN_STATE,true);
OnMouseDown(cea);
this->MouseDown.Invoke(this,cea);
}
}
if(event.type == SDL_MOUSEBUTTONUP)
{
if(this->GetViewFlag(VIEWFLAG_MOUSEDOWN_STATE))
{
GUIMouseButtonEventArgs cea;
cea.button = (int)event.button.button;
cea.x = event.button.x - myVisibleBounds.x;
cea.y = event.button.y - myVisibleBounds.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,cea);
return true;
}
}
else if(event.type == SDL_MOUSEMOTION)
{
bool inside = event.motion.x >= myVisibleBounds.x && event.motion.x < myVisibleBounds.x+myVisibleBounds.w && event.motion.y >= myVisibleBounds.y && event.motion.y < myVisibleBounds.y+myVisibleBounds.h;
bool hoverFlag = this->GetViewFlag(VIEWFLAG_HOVER_STATE);
if(inside && !hoverFlag)
{
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);
}
}
return false;
}
std::string View::GetId()
{
return this->id;
}
void View::SetId(std::string id)
{
this->id = id;
}
View* View::FindViewById(std::string id)
{
if(this->GetId() == id) return this;
return nullptr;
}
View* ContainerView::FindViewById(std::string id)
{
if(this->GetId() == id) return this;
for(size_t i = 0; i <this->ViewCount(); i++)
{
auto v = this->GetViewAt(i);
auto v2 = v->FindViewById(id);
if(v2 != nullptr) return v2;
}
return nullptr;
}
View::~View()
{
}
}
#endif

View File

@ -0,0 +1,109 @@
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include "TessesFramework/SDL2/Views/AbsoluteView.hpp"
namespace Tesses::Framework::SDL2::Views
{
void AbsoluteView::OnDraw(SDL_Renderer* renderer, SDL_Rect& myRect)
{
Clipper clipper(renderer,myRect);
SDL_Rect oldClip;
bool isClipped=SDL_RenderIsClipEnabled(renderer);
SDL_RenderGetClipRect(renderer,&oldClip);
if(!isClipped) oldClip = myRect;
for(auto& ctrl : this->views)
{
SDL_Rect childRect = ctrl.second;
childRect.x += oldClip.x;
childRect.y += oldClip.y;
if(clipper.Clip(childRect))
CallOnDraw(ctrl.first.first,renderer,childRect);
}
}
bool AbsoluteView::OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds)
{
bool handled=false;
for(auto& item : this->views)
{
SDL_Rect theirBounds = item.second;
theirBounds.x += myBounds.x;
theirBounds.y += myBounds.y;
SDL_Rect theirVisibleBounds = item.second;
theirVisibleBounds.x += visibleBounds.x;
theirVisibleBounds.y += visibleBounds.y;
Clipper::ClipRect(theirVisibleBounds, visibleBounds);
if(CallOnEvent(item.first.first,event,theirBounds, theirVisibleBounds))
handled=true;
if(handled && event.type != SDL_MOUSEBUTTONUP && event.type != SDL_MOUSEMOTION)
{
GUISDLEventEventArgs sdle;
sdle.event = event; this->SDLEvent.Invoke(this,sdle);
return true;
}
}
if(handled) {GUISDLEventEventArgs sdle;
sdle.event = event; this->SDLEvent.Invoke(this,sdle);return true;}
return View::OnEvent(event,myBounds,visibleBounds);
}
size_t AbsoluteView::ViewCount()
{
return this->views.size();
}
View* AbsoluteView::GetViewAt(size_t index)
{
return this->views.at(index).first.first;
}
AbsoluteView::AbsoluteView() : ContainerView()
{
}
void AbsoluteView::Add(SDL_Rect rect, View* view, bool owns)
{
for(auto& item : this->views)
{
if(item.first.first == view) return;
}
this->AssignChildParentToThis(view);
this->views.push_back(std::pair<std::pair<View*,bool>,SDL_Rect>(std::pair<View*,bool>(view,owns),rect));
}
void AbsoluteView::Set(View* view, SDL_Rect rect)
{
for(auto& item : this->views)
{
if(item.first.first == view)
{
item.second = rect;
return;
}
}
}
void AbsoluteView::Remove(View* view)
{
for(auto index = this->views.begin(); index != this->views.end(); index++)
{
if(index->first.first == view)
{
if(index->first.second) delete index->first.first;
this->views.erase(index);
return;
}
}
}
AbsoluteView::~AbsoluteView()
{
for(auto& item : this->views)
{
if(item.first.second) delete item.first.first;
}
}
}
#endif

View File

@ -0,0 +1,77 @@
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include "TessesFramework/SDL2/Views/ButtonView.hpp"
namespace Tesses::Framework::SDL2::Views
{
ButtonView::ButtonView() : View()
{
}
ButtonView::ButtonView(std::string text) : View(text)
{
}
bool ButtonView::OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& myVisibleBounds)
{
if(this->GetViewFlag(VIEWFLAG_ISACTIVE))
{
if(event.type == SDL_KEYUP)
{
switch(event.key.keysym.sym)
{
case SDL_KeyCode::SDLK_SPACE:
{
GUIEventArgs e;
this->OnClick(e);
this->Click.Invoke(this,e);
} break;
}
}
}
if(event.type == SDL_MOUSEBUTTONUP)
{
if(event.button.x >= myVisibleBounds.x && event.button.x < myVisibleBounds.x+myVisibleBounds.w && event.button.y >= myVisibleBounds.y && event.button.y < myVisibleBounds.y+myVisibleBounds.h)
{
this->GetWindow()->MakeActive(this);
}
}
return View::OnEvent(event,myBounds,myVisibleBounds);
}
void ButtonView::OnDraw(SDL_Renderer* renderer, SDL_Rect& r)
{
auto win = this->GetWindow();
SDL_SetRenderDrawColor(renderer,win->palette.accent.r,win->palette.accent.g,win->palette.accent.b,win->palette.accent.a);
SDL_RenderFillRect(renderer,&r);
int textW;
int textH;
win->normal_font->CalculateSize(this->text,textW,textH);
int x=(r.w/2)-(textW/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,this->text,color);
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++)
{
SDL_RenderDrawRect(renderer,&r2);
r2.x++;
r2.y++;
r2.w-=2;
r2.h-=2;
}
}
}
#endif

View File

@ -0,0 +1,122 @@
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include "TessesFramework/SDL2/Views/CheckView.hpp"
namespace Tesses::Framework::SDL2::Views
{
void CheckView::OnCheckChanged(GUIEventArgs& event)
{
}
void CheckView::OnDraw(SDL_Renderer* renderer, SDL_Rect& r)
{
auto win = this->GetWindow();
const int checkSz=32;
SDL_Rect checkBoxRect={.x=r.x,.y=r.y+((r.h/2)-(checkSz/2)),.w=checkSz,.h=checkSz};
int textW;
int textH;
win->normal_font->CalculateSize(this->text,textW,textH);
//we only need the y
int x = r.x+checkSz+8;
int y = r.y+((r.h/2)-(textH/2));
win->normal_font->Render(renderer,x,y,text,win->palette.accent);
if(this->GetViewFlag(VIEWFLAG_CHECKED))
{
SDL_SetRenderDrawColor(renderer,win->palette.accent.r,win->palette.accent.g,win->palette.accent.b,win->palette.accent.a);
//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 x3=checkBoxRect.x+4+(checkSz-8);
int y3=checkBoxRect.y+4;
for(int i = 0; i < 4; i++)
{
SDL_RenderDrawLine(renderer,x1,y1-i,x2,y2-i);
SDL_RenderDrawLine(renderer,x2-i,y2,x3-i,y3);
}
}
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);
for(int i = 0; i < 4; i++)
{
SDL_RenderDrawRect(renderer,&checkBoxRect);
checkBoxRect.x++;
checkBoxRect.y++;
checkBoxRect.w-=2;
checkBoxRect.h-=2;
}
}
bool CheckView::OnEvent(SDL_Event& event, SDL_Rect& myBounds, SDL_Rect& visibleBounds)
{
if(this->GetViewFlag(VIEWFLAG_ISACTIVE))
{
if(event.type == SDL_KEYUP)
{
switch(event.key.keysym.sym)
{
case SDL_KeyCode::SDLK_SPACE:
{
GUIEventArgs e;
this->SetViewFlag(VIEWFLAG_CHECKED,!this->GetViewFlag(VIEWFLAG_CHECKED));
this->OnClick(e);
this->Click.Invoke(this,e);
this->OnCheckChanged(e);
this->CheckChanged.Invoke(this,e);
} break;
}
}
}
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)
{
this->GetWindow()->MakeActive(this);
this->SetViewFlag(VIEWFLAG_CHECKED,!this->GetViewFlag(VIEWFLAG_CHECKED));
GUIEventArgs e;
this->OnCheckChanged(e);
this->CheckChanged.Invoke(this,e);
}
}
return View::OnEvent(event,myBounds,visibleBounds);
}
CheckView::CheckView(bool checked, std::string label) : View(label)
{
this->SetViewFlag(VIEWFLAG_CHECKED,checked);
}
CheckView::CheckView() : View()
{
this->SetViewFlag(VIEWFLAG_CHECKED,false);
}
bool CheckView::GetChecked()
{
return this->GetViewFlag(VIEWFLAG_CHECKED);
}
void CheckView::SetChecked(bool value)
{
this->SetViewFlag(VIEWFLAG_CHECKED,true);
}
}
#endif

View File

@ -0,0 +1,20 @@
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include "TessesFramework/SDL2/Views/LabelView.hpp"
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);
}
LabelView::LabelView() : View()
{
this->flags &= ~VIEWFLAG_TABSTOP;
}
LabelView::LabelView(std::string text) : View(text)
{
this->flags &= ~VIEWFLAG_TABSTOP;
}
}
#endif

View File

@ -0,0 +1,39 @@
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include "TessesFramework/SDL2/Views/ProgressView.hpp"
namespace Tesses::Framework::SDL2::Views
{
ProgressView::ProgressView() : ProgressView(0.0)
{
}
ProgressView::ProgressView(double v) : View()
{
this->value = v;
this->SetViewFlag(VIEWFLAG_TABSTOP,false);
}
void ProgressView::OnDraw(SDL_Renderer* renderer, SDL_Rect& rect)
{
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_Rect r2={.x=rect.x,.y=rect.y,.w=rect.w,.h=rect.h};
for(size_t i=0;i < 4; i++)
{
SDL_RenderDrawRect(renderer,&r2);
r2.x++;
r2.y++;
r2.w-=2;
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};
SDL_SetRenderDrawColor(renderer,win->palette.accent.r,win->palette.accent.g,win->palette.accent.b,win->palette.accent.a);
SDL_RenderFillRect(renderer,&r2);
}
}
#endif

View File

@ -0,0 +1,140 @@
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include "TessesFramework/SDL2/Views/TextListView.hpp"
namespace Tesses::Framework::SDL2::Views
{
TextListView::TextListView() : View()
{
this->firstIndex=0;
this->selected=-1;
}
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;
if(this->items.size() > no_items)
{
if(this->items.size() - this->firstIndex < no_items)
{
this->firstIndex = this->items.size() - no_items;
}
}
else {
this->firstIndex=0;
no_items = (int)this->items.size();
}
if(event.type == SDL_KEYDOWN)
{
if(this->GetViewFlag(VIEWFLAG_ISACTIVE))
{
switch(event.key.keysym.sym)
{
case SDLK_HOME:
this->selected=0;
this->firstIndex=0;
break;
case SDLK_END:
this->selected = (int)(this->items.size()-1);
this->firstIndex = (this->selected/no_items) * no_items;
break;
case SDLK_DOWN:
this->selected++;
if(this->selected < -1 || this->selected >= this->items.size())
{
this->selected=0;
}
this->firstIndex = (this->selected/no_items) * no_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/no_items) * no_items;
break;
}
}
}
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)
{
win->MakeActive(this);
auto myRealY=event.button.y - (myBounds.y+4);
auto yThing = myRealY / item_height;
if(yThing < no_items)
{
auto high= yThing+this->firstIndex;
this->selected = (int)high;
}
}
return View::OnEvent(event,myBounds,visibleBounds);
}
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 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->items.size() > no_items)
{
if(this->items.size() - this->firstIndex < no_items)
{
this->firstIndex = this->items.size() - no_items;
}
}
else {
this->firstIndex=0;
no_items = (int)this->items.size();
}
SDL_Rect r2={.x=rect.x,.y=rect.y,.w=rect.w,.h=rect.h};
for(size_t i=0;i < 4; 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+4,.y=rect.y+4+(item_height*i),.w=rect.w-8,.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);
}
else {
win->normal_font->Render(renderer,rect.x+12,(rect.y+12)+(item_height*i),this->items[realI],win->palette.accent);
}
}
}
}
#endif

View File

@ -43,7 +43,7 @@ extern "C" {
#if defined(GEKKO)
extern "C" uint32_t if_config( char *local_ip, char *netmask, char *gateway,bool use_dhcp, int max_retries);
#elif !defined(_WIN32) && !defined(__ANDROID__) && !defined(__SWITCH__)
#elif !defined(_WIN32) && !defined(__ANDROID__) && !defined(__SWITCH__) && !defined(__PS2__)
#include <ifaddrs.h>
#endif
@ -117,7 +117,7 @@ namespace Tesses::Framework::Streams {
free(addresses);
#elif defined(__ANDROID__) || defined(__SWITCH__)
#elif defined(__ANDROID__) || defined(__SWITCH__) || defined(__PS2__)
#else
struct ifaddrs *ifAddrStruct = NULL;
@ -181,7 +181,12 @@ namespace Tesses::Framework::Streams {
{
memset(addr,0,sizeof(struct sockaddr_storage));
uint8_t ip[16];
#if defined(__PS2__)
if(inet_aton(str.c_str(),ip) == 1)
#else
if(inet_pton(AF_INET,str.c_str(),ip)==1)
#endif
{
struct sockaddr_in* inAddr = (struct sockaddr_in*)addr;
inAddr->sin_family = AF_INET;
@ -521,25 +526,46 @@ namespace Tesses::Framework::Streams {
{
return this->success;
}
NetworkStream::NetworkStream(bool ipV6,bool datagram)
NetworkStream::NetworkStream(SocketType type)
{
this->endOfStream=false;
this->owns = true;
this->success=false;
if(ipV6)
switch(type)
{
#if defined(AF_INET6)
this->sock = NETWORK_SOCKET(AF_INET6, datagram ? SOCK_DGRAM : SOCK_STREAM, 0);
if(this->sock >= 0) this->success=true;
#endif
}
else
{
#if defined(AF_INET)
this->sock = NETWORK_SOCKET(AF_INET, datagram ? SOCK_DGRAM : SOCK_STREAM, 0);
if(this->sock >= 0) this->success=true;
case SocketType::ST_IPv4_TCP:
#if defined(AF_INET)
this->sock = NETWORK_SOCKET(AF_INET,SOCK_STREAM, 0);
#endif
break;
case SocketType::ST_IPv4_UDP:
#if defined(AF_INET)
this->sock = NETWORK_SOCKET(AF_INET,SOCK_DGRAM, 0);
#endif
break;
case SocketType::ST_IPv6_TCP:
#if defined(AF_INET6)
this->sock = NETWORK_SOCKET(AF_INET6,SOCK_STREAM, 0);
#endif
break;
case SocketType::ST_IPv6_UDP:
#if defined(AF_INET6)
this->sock = NETWORK_SOCKET(AF_INET6,SOCK_DGRAM, 0);
#endif
break;
case SocketType::ST_UNIX:
#if defined(AF_UNIX)
this->sock = NETWORK_SOCKET(AF_UNIX,SOCK_DGRAM, 0);
#endif
break;
}
if(this->sock >= 0) this->success=true;
}
NetworkStream::NetworkStream(std::string ipOrFqdn, uint16_t port, bool datagram, bool broadcast, bool supportIPv6)
{
@ -672,7 +698,7 @@ namespace Tesses::Framework::Streams {
ip = StringifyIP((struct sockaddr*)&storage);
port = getPort((struct sockaddr*)&storage);
return new NetworkStream(s,true);
return new NetworkStream((int32_t)s,(bool)true);
}
size_t NetworkStream::Read(uint8_t* buff, size_t sz)
{
@ -797,7 +823,7 @@ bool NetworkStream::CanWrite() {
return false;
}
NetworkStream::NetworkStream(bool ipV6,bool datagram)
NetworkStream::NetworkStream(SocketType type)
{
}

132
src/Streams/PtyStream.cpp Normal file
View File

@ -0,0 +1,132 @@
#include "TessesFramework/Streams/PtyStream.hpp"
#if !defined(GEKKO) && !defined(__PS2__) && !defined(_WIN32)
#include <pty.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#endif
namespace Tesses::Framework::Streams {
PtyStream::PtyStream(WindowSize windowSize,std::string filename, std::vector<std::string> args, std::vector<std::string> env)
{
#if !defined(GEKKO) && !defined(__PS2__) && !defined(_WIN32)
this->wS = windowSize;
this->eos=false;
winsize sz;
sz.ws_col =(unsigned short)windowSize.Columns;
sz.ws_row = (unsigned short)windowSize.Rows;
sz.ws_xpixel = (unsigned short)windowSize.Width;
sz.ws_ypixel = (unsigned short)windowSize.Height;
termios ios;
cfmakeraw(&ios);
pid= forkpty(&this->socket,NULL,&ios,&sz);
if(pid == -1)
{
this->eos=true;
}
if(pid == 0)
{
char** argv = new char*[args.size()+1];
argv[args.size()]=NULL;
char** envp = new char*[env.size()+1];
envp[env.size()]=NULL;
for(size_t i = 0; i < args.size();i++)
{
argv[i] = (char*)args[i].c_str();
}
for(size_t i = 0; i < env.size();i++)
{
envp[i] = (char*)env[i].c_str();
}
if(execve(filename.c_str(),argv,envp) == -1)
{
perror("execve returned -1");
exit(1);
}
}
int flags = fcntl(this->socket, F_GETFL, 0);
if(flags == -1) {
perror("fcntl F_GETFL");
this->eos=true;
return;
}
flags |= O_NONBLOCK;
flags=fcntl(this->socket,F_SETFL,flags);
if(flags == -1) {
perror("fcntl F_SETFL");
this->eos=true;
return;
}
#endif
}
bool PtyStream::EndOfStream()
{
return this->eos;
}
bool PtyStream::CanRead()
{
return true;
}
bool PtyStream::CanWrite()
{
return true;
}
size_t PtyStream::Read(uint8_t* buff, size_t sz)
{
if(this->eos) return 0;
#if !defined(GEKKO) && !defined(__PS2__) && !defined(_WIN32)
auto res = read(this->socket, buff,sz);
if(res == -1)
{
if(errno != EAGAIN && errno != EWOULDBLOCK)
this->eos=true;
return 0;
}
return (size_t)res;
#else
return 0;
#endif
}
size_t PtyStream::Write(const uint8_t* buff, size_t sz)
{
#if !defined(GEKKO) && !defined(__PS2__) && !defined(_WIN32)
auto res = write(this->socket, buff,sz);
return res;
#else
return 0;
#endif
}
WindowSize PtyStream::GetWindowSize()
{
return this->wS;
}
void PtyStream::Resize(WindowSize windowSize)
{
#if !defined(GEKKO) && !defined(__PS2__) && !defined(_WIN32)
this->wS = windowSize;
winsize sz;
sz.ws_col =(unsigned short)windowSize.Columns;
sz.ws_row = (unsigned short)windowSize.Rows;
sz.ws_xpixel = (unsigned short)windowSize.Width;
sz.ws_ypixel = (unsigned short)windowSize.Height;
ioctl(this->socket,TIOCSWINSZ,&sz);
#endif
}
PtyStream::~PtyStream()
{
this->eos=true;
#if !defined(GEKKO) && !defined(__PS2__) && !defined(_WIN32)
close(this->socket);
kill((pid_t)this->pid,SIGHUP);
#endif
}
}

View File

@ -2,6 +2,7 @@
#include "TessesFramework/Streams/NetworkStream.hpp"
#include <atomic>
#include <csignal>
#include <iostream>
#if defined(_WIN32)
#include <windows.h>
#undef min
@ -35,6 +36,9 @@ static GXRModeObj *rmode = NULL;
#endif
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <SDL2/SDL_image.h>
#include "TessesFramework/SDL2/GUI.hpp"
#endif
namespace Tesses::Framework
@ -88,6 +92,7 @@ namespace Tesses::Framework
Tesses::Framework::Threading::LookForFinishedThreads();
#endif
if(!isRunningSig) isRunning=false;
#if defined(GEKKO)
if(gaming_console_events)
@ -115,6 +120,9 @@ namespace Tesses::Framework
}
#endif
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
Tesses::Framework::SDL2::gui.Update();
#endif
}
void TF_SetIsRunning(bool _isRunning)
{
@ -135,6 +143,14 @@ namespace Tesses::Framework
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
//SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS,"1");
SDL_Init(SDL_INIT_EVERYTHING);
TTF_Init();
int r = IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_TIF | IMG_INIT_WEBP | IMG_INIT_JXL |IMG_INIT_AVIF;
if(IMG_Init(
r
) != r)
{
std::cout << "IMG_Init: " << IMG_GetError() << std::endl;
}
#endif
tzset();

View File

@ -0,0 +1,36 @@
#include "TessesFramework/TextStreams/StdIOReader.hpp"
namespace Tesses::Framework::TextStreams
{
ConsoleReader::ConsoleReader()
{
}
bool ConsoleReader::ReadBlock(std::string& str,size_t len)
{
#if defined(_WIN32)
uint8_t* buff = new uint8_t[len];
#else
uint8_t buff[len];
#endif
size_t read=0;
size_t readTotal=0;
uint8_t* buffOff=buff;
do {
read=fread(buffOff,1,len,stdin);
if(read != 0) {readTotal+= read;len-=read; buffOff+=read;}
} while(read != 0);
if(readTotal == 0) return false;
str.append((const char*)buff, readTotal);
#if defined(_WIN32)
delete buff;
#endif
return true;
}
ConsoleReader StdIn()
{
return ConsoleReader();
}
}

View File

@ -0,0 +1,42 @@
#include "TessesFramework/TextStreams/StdIOWriter.hpp"
#if defined(__PS2__)
#include <debug.h>
#else
#include <cstdio>
#endif
namespace Tesses::Framework::TextStreams
{
ConsoleWriter::ConsoleWriter(bool isError) : TextWriter()
{
this->isError=isError;
}
void ConsoleWriter::WriteData(const char* text, size_t len)
{
#if defined(__PS2__)
char lenThing[10];//%.2048s
while(len > 0) {
int b = std::min((int)2047,(int)len);
snprintf(lenThing,18,"%%.%is",b);
scr_printf(lenThing,text);
len -= b;
text += b;
}
#else
if(isError)
fwrite(text,1,len,stderr);
else
fwrite(text,1,len,stdout);
#endif
}
ConsoleWriter StdOut()
{
return ConsoleWriter(false);
}
ConsoleWriter StdErr()
{
return ConsoleWriter(true);
}
}

View File

@ -11,6 +11,15 @@ namespace Tesses::Framework::TextStreams {
StreamReader::StreamReader(std::filesystem::path path) : StreamReader(new FileStream(path,"rb"),true)
{
}
bool StreamReader::Rewind()
{
if(this->strm->CanSeek())
{
this->strm->Seek((int64_t)0,Tesses::Framework::Streams::SeekOrigin::Begin);
return true;
}
return false;
}
StreamReader::StreamReader(Stream* strm, bool owns) : TextReader()
{

View File

@ -0,0 +1,38 @@
#include "TessesFramework/TextStreams/StringReader.hpp"
namespace Tesses::Framework::TextStreams {
StringReader::StringReader()
{
this->offset=0;
this->str="";
}
StringReader::StringReader(std::string str)
{
this->offset=0;
this->str=str;
}
size_t& StringReader::GetOffset()
{
return this->offset;
}
std::string& StringReader::GetString()
{
return this->str;
}
bool StringReader::Rewind()
{
this->offset=0;
return true;
}
bool StringReader::ReadBlock(std::string& str,size_t sz)
{
if(this->offset < this->str.size())
{
size_t len = std::min(sz,this->str.size()-this->offset);
str.insert(str.size(),this->str.data()+this->offset,len);
offset+=len;
return true;
}
return false;
}
}

View File

@ -0,0 +1,21 @@
#include "TessesFramework/TextStreams/StringWriter.hpp"
namespace Tesses::Framework::TextStreams
{
std::string& StringWriter::GetString()
{
return this->text;
}
StringWriter::StringWriter() : TextWriter()
{
}
StringWriter::StringWriter(std::string str) : TextWriter()
{
this->text = str;
}
void StringWriter::WriteData(const char* text, size_t len)
{
this->text.append(text,len);
}
}

View File

@ -2,6 +2,10 @@
namespace Tesses::Framework::TextStreams
{
bool TextReader::Rewind()
{
return false;
}
int32_t TextReader::ReadChar()
{
std::string txt;

View File

@ -1,7 +1,91 @@
#include "TessesFramework/TextStreams/TextWriter.hpp"
#include "TessesFramework/Http/HttpUtils.hpp"
namespace Tesses::Framework::TextStreams
{
void TextWriter::Write(int64_t n)
{
std::string text = std::to_string(n);
WriteData(text.c_str(),text.size());
}
void TextWriter::Write(uint64_t n)
{
std::string text = std::to_string(n);
WriteData(text.c_str(),text.size());
}
void TextWriter::Write(const void* ptr)
{
std::string text = "0x";
uintptr_t ptr2 = (uintptr_t)ptr;
for(size_t i = 1; i <= sizeof(ptr); i++)
{
uint8_t v = (uint8_t)(ptr2 >> (int)((sizeof(ptr) - i) * 8));
text.push_back(Tesses::Framework::Http::HttpUtils::NibbleToHex(v >> 4));
text.push_back(Tesses::Framework::Http::HttpUtils::NibbleToHex(v));
}
WriteData(text.c_str(),text.size());
}
void TextWriter::Write(const char* ptr)
{
WriteData(ptr,strlen(ptr));
}
void TextWriter::Write(char c)
{
WriteData(&c,1);
}
void TextWriter::Write(double d)
{
std::string text = std::to_string(d);
WriteData(text.c_str(),text.size());
}
void TextWriter::WriteLine(int64_t n)
{
std::string text = std::to_string(n);
text.append(newline);
WriteData(text.c_str(),text.size());
}
void TextWriter::WriteLine(uint64_t n)
{
std::string text = std::to_string(n);
text.append(newline);
WriteData(text.c_str(),text.size());
}
void TextWriter::WriteLine(const void* ptr)
{
std::string text = "0x";
uintptr_t ptr2 = (uintptr_t)ptr;
for(size_t i = 1; i <= sizeof(ptr); i++)
{
uint8_t v = (uint8_t)(ptr2 >> (int)((sizeof(ptr) - i) * 8));
text.push_back(Tesses::Framework::Http::HttpUtils::NibbleToHex(v >> 4));
text.push_back(Tesses::Framework::Http::HttpUtils::NibbleToHex(v));
}
text.append(newline);
WriteData(text.c_str(),text.size());
}
void TextWriter::WriteLine(const char* ptr)
{
std::string text = ptr;
text.append(newline);
WriteData(text.c_str(),text.size());
}
void TextWriter::WriteLine(char c)
{
std::string text = {c};
text.append(newline);
WriteData(text.c_str(),text.size());
}
void TextWriter::WriteLine(double d)
{
std::string text = std::to_string(d);
text.append(newline);
WriteData(text.c_str(),text.size());
}
TextWriter::TextWriter()
{
#if defined(WIN32) || defined(_WIN32)