Add GUI Support
This commit is contained in:
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
75
apps/guilayouttester.cpp
Normal 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
94
apps/tanonydrop.cpp
Normal 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;
|
||||
}
|
||||
@ -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
8
font/Mono/README.md
Normal 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
|
||||
BIN
font/Mono/aardvark-fixed-regular.ttf
Normal file
BIN
font/Mono/aardvark-fixed-regular.ttf
Normal file
Binary file not shown.
95
font/NonMono/License-OFL.txt
Normal file
95
font/NonMono/License-OFL.txt
Normal 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.
|
||||
BIN
font/NonMono/TanoheSans-Regular.ttf
Normal file
BIN
font/NonMono/TanoheSans-Regular.ttf
Normal file
Binary file not shown.
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
244
include/TessesFramework/SDL2/GUI.hpp
Normal file
244
include/TessesFramework/SDL2/GUI.hpp
Normal 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
|
||||
12
include/TessesFramework/SDL2/ParseColor.hpp
Normal file
12
include/TessesFramework/SDL2/ParseColor.hpp
Normal 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
|
||||
9
include/TessesFramework/SDL2/Stream.hpp
Normal file
9
include/TessesFramework/SDL2/Stream.hpp
Normal 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
|
||||
33
include/TessesFramework/SDL2/Views/AbsoluteView.hpp
Normal file
33
include/TessesFramework/SDL2/Views/AbsoluteView.hpp
Normal 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
|
||||
18
include/TessesFramework/SDL2/Views/ButtonView.hpp
Normal file
18
include/TessesFramework/SDL2/Views/ButtonView.hpp
Normal 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
|
||||
25
include/TessesFramework/SDL2/Views/CheckView.hpp
Normal file
25
include/TessesFramework/SDL2/Views/CheckView.hpp
Normal 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
|
||||
15
include/TessesFramework/SDL2/Views/LabelView.hpp
Normal file
15
include/TessesFramework/SDL2/Views/LabelView.hpp
Normal 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
|
||||
17
include/TessesFramework/SDL2/Views/ProgressView.hpp
Normal file
17
include/TessesFramework/SDL2/Views/ProgressView.hpp
Normal 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
|
||||
20
include/TessesFramework/SDL2/Views/TextListView.hpp
Normal file
20
include/TessesFramework/SDL2/Views/TextListView.hpp
Normal 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
|
||||
@ -17,18 +17,6 @@ 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
|
||||
{
|
||||
std::vector<JToken> items;
|
||||
@ -46,13 +34,34 @@ 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>
|
||||
bool TryGetJToken(JToken json, T& item)
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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);
|
||||
|
||||
29
include/TessesFramework/Streams/PtyStream.hpp
Normal file
29
include/TessesFramework/Streams/PtyStream.hpp
Normal 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();
|
||||
};
|
||||
}
|
||||
@ -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"
|
||||
13
include/TessesFramework/TextStreams/StdIOReader.hpp
Normal file
13
include/TessesFramework/TextStreams/StdIOReader.hpp
Normal 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();
|
||||
}
|
||||
15
include/TessesFramework/TextStreams/StdIOWriter.hpp
Normal file
15
include/TessesFramework/TextStreams/StdIOWriter.hpp
Normal 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();
|
||||
}
|
||||
@ -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();
|
||||
};
|
||||
}
|
||||
15
include/TessesFramework/TextStreams/StringReader.hpp
Normal file
15
include/TessesFramework/TextStreams/StringReader.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
15
include/TessesFramework/TextStreams/StringWriter.hpp
Normal file
15
include/TessesFramework/TextStreams/StringWriter.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@ -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);
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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 = {};
|
||||
|
||||
@ -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
231
src/SDL2/GUI.cpp
Normal 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
367
src/SDL2/GUIWindow.cpp
Normal 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
77
src/SDL2/Stream.cpp
Normal 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
173
src/SDL2/View.cpp
Normal 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
|
||||
109
src/SDL2/Views/AbsoluteView.cpp
Normal file
109
src/SDL2/Views/AbsoluteView.cpp
Normal 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
|
||||
77
src/SDL2/Views/ButtonView.cpp
Normal file
77
src/SDL2/Views/ButtonView.cpp
Normal 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
|
||||
122
src/SDL2/Views/CheckView.cpp
Normal file
122
src/SDL2/Views/CheckView.cpp
Normal 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
|
||||
20
src/SDL2/Views/LabelView.cpp
Normal file
20
src/SDL2/Views/LabelView.cpp
Normal 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
|
||||
39
src/SDL2/Views/ProgressView.cpp
Normal file
39
src/SDL2/Views/ProgressView.cpp
Normal 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
|
||||
140
src/SDL2/Views/TextListView.cpp
Normal file
140
src/SDL2/Views/TextListView.cpp
Normal 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
|
||||
@ -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)
|
||||
{
|
||||
#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
|
||||
switch(type)
|
||||
{
|
||||
case SocketType::ST_IPv4_TCP:
|
||||
#if defined(AF_INET)
|
||||
this->sock = NETWORK_SOCKET(AF_INET, datagram ? SOCK_DGRAM : SOCK_STREAM, 0);
|
||||
if(this->sock >= 0) this->success=true;
|
||||
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
132
src/Streams/PtyStream.cpp
Normal 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
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
|
||||
36
src/TextStreams/StdIOReader.cpp
Normal file
36
src/TextStreams/StdIOReader.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
42
src/TextStreams/StdIOWriter.cpp
Normal file
42
src/TextStreams/StdIOWriter.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
@ -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()
|
||||
{
|
||||
|
||||
38
src/TextStreams/StringReader.cpp
Normal file
38
src/TextStreams/StringReader.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
21
src/TextStreams/StringWriter.cpp
Normal file
21
src/TextStreams/StringWriter.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,10 @@
|
||||
|
||||
namespace Tesses::Framework::TextStreams
|
||||
{
|
||||
bool TextReader::Rewind()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int32_t TextReader::ReadChar()
|
||||
{
|
||||
std::string txt;
|
||||
|
||||
@ -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)
|
||||
|
||||
Reference in New Issue
Block a user