Add main screen
This commit is contained in:
@@ -62,7 +62,7 @@ set(CROSSLANG_ENABLE_BINARIES OFF)
|
||||
|
||||
FetchContent_MakeAvailable(TessesCrossLang)
|
||||
|
||||
add_executable(${PROJECT_NAME} src/main.cpp src/bigscreenwindow.cpp src/bigscreenplayer.cpp src/button.cpp src/vgrid.cpp src/hgrid.cpp src/clipper.cpp src/font.cpp src/text.cpp)
|
||||
add_executable(${PROJECT_NAME} src/main.cpp src/bigscreenwindow.cpp src/bigscreenplayer.cpp src/button.cpp src/vgrid.cpp src/hgrid.cpp src/clipper.cpp src/font.cpp src/text.cpp src/textbox.cpp)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC crosslang_static)
|
||||
|
||||
|
||||
@@ -130,6 +130,8 @@ namespace Tesses::BigScreen {
|
||||
|
||||
int MinHeight();
|
||||
};
|
||||
|
||||
|
||||
class Button : public Widget, public std::enable_shared_from_this<Button>
|
||||
{
|
||||
private:
|
||||
@@ -192,7 +194,6 @@ namespace Tesses::BigScreen {
|
||||
SDL_Renderer* renderer;
|
||||
|
||||
std::shared_ptr<Widget> page;
|
||||
bool running=true;
|
||||
Widget* current = nullptr;
|
||||
std::shared_ptr<FontCache> fc;
|
||||
SDL_Color color=COLOR_BGLIGHT;
|
||||
@@ -209,13 +210,16 @@ namespace Tesses::BigScreen {
|
||||
|
||||
void Run();
|
||||
~BigScreenWindow();
|
||||
std::shared_ptr<Widget> GetWidget();
|
||||
void SetWidget(std::shared_ptr<Widget> widget);
|
||||
void DrawRectThick(SDL_Rect rect, int sz);
|
||||
std::shared_ptr<BigScreenWindow> GetRoot();
|
||||
|
||||
void SetBackColor(SDL_Color color);
|
||||
void SetBackColor(std::string color);
|
||||
|
||||
|
||||
void SetPage(std::string name, std::shared_ptr<Widget> widget);
|
||||
void Close();
|
||||
};
|
||||
|
||||
|
||||
@@ -230,15 +234,57 @@ namespace Tesses::BigScreen {
|
||||
|
||||
int tex_w = -1, tex_h = -1;
|
||||
|
||||
bool controls=false;
|
||||
bool paused = false;
|
||||
bool seeking=false;
|
||||
|
||||
public:
|
||||
mpv_handle* GetMPVHandle();
|
||||
VideoPlayerWidget();
|
||||
EventResult Event(SDL_Event& event,SDL_Rect& rect);
|
||||
void SetPrev(std::shared_ptr<Widget> w);
|
||||
std::shared_ptr<Widget> GetPrev();
|
||||
void Draw(SDL_Rect& rect);
|
||||
void LoadFile(std::string file);
|
||||
~VideoPlayerWidget();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class TextBox : public Widget, public std::enable_shared_from_this<TextBox>
|
||||
{
|
||||
private:
|
||||
std::string text;
|
||||
public:
|
||||
TextBox()=default;
|
||||
EventResult Event(SDL_Event& event,SDL_Rect& rect);
|
||||
void Draw(SDL_Rect& rect);
|
||||
std::string GetText();
|
||||
void SetText(std::string text);
|
||||
int MinWidth();
|
||||
int MinHeight();
|
||||
|
||||
class TextBoxDialog : public Widget {
|
||||
std::shared_ptr<TextBox> tb;
|
||||
std::shared_ptr<Widget> page;
|
||||
std::shared_ptr<VGrid> grid;
|
||||
size_t cursor;
|
||||
|
||||
bool shift=false;
|
||||
int x=0;
|
||||
int y=-1;
|
||||
|
||||
void Append(char c);
|
||||
void HandleKey();
|
||||
|
||||
public:
|
||||
TextBoxDialog(std::shared_ptr<TextBox> tb, std::shared_ptr<Widget> page);
|
||||
EventResult Event(SDL_Event& event,SDL_Rect& rect);
|
||||
void Draw(SDL_Rect& rect);
|
||||
~TextBoxDialog()=default;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
class Clipper {
|
||||
SDL_Rect theRect;
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Tesses::BigScreen {
|
||||
//"/home/mike/Music/dir/Vids/Chicken.mp4";
|
||||
mpv = mpv_create();
|
||||
mpv_set_option_string(mpv, "vo", "libmpv");
|
||||
|
||||
if (mpv_initialize(mpv) < 0)
|
||||
throw std::runtime_error("mpv init failed");
|
||||
|
||||
@@ -36,46 +37,108 @@ namespace Tesses::BigScreen {
|
||||
|
||||
|
||||
}
|
||||
const int CONTROLS_HEIGHT = 16;
|
||||
EventResult VideoPlayerWidget::Event(SDL_Event& event, SDL_Rect& rect)
|
||||
{
|
||||
auto window = this->GetRoot();
|
||||
if(window == nullptr) return EventResult::Ignored;
|
||||
|
||||
switch (event.type) {
|
||||
|
||||
case SDL_KEYDOWN:
|
||||
if(event.key.keysym.sym == SDLK_ESCAPE)
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
this->seeking=false;
|
||||
break;
|
||||
case SDL_MOUSEMOTION:
|
||||
{
|
||||
this->controls = (event.motion.x > rect.x && event.motion.y >= (rect.h - CONTROLS_HEIGHT) + rect.y && event.button.x < rect.x+rect.w && event.motion.y < rect.y+rect.h);
|
||||
|
||||
if(seeking && event.motion.x >= rect.x && event.motion.x < rect.x+rect.w && rect.w > 0)
|
||||
{
|
||||
window->SetWidget(nullptr);
|
||||
double pos = (double)(event.motion.x - rect.x) / (double)rect.w;
|
||||
double length = 0;
|
||||
mpv_get_property(mpv, "duration", mpv_format::MPV_FORMAT_DOUBLE, &length);
|
||||
|
||||
std::string seek = std::to_string(length*pos);
|
||||
|
||||
const char *cmd_seek[] = {"seek", seek.c_str(), "absolute",NULL};
|
||||
mpv_command_async(mpv, 0, cmd_seek);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
{
|
||||
if(event.button.x >= rect.x && event.button.y >= rect.y && event.button.x < rect.x+rect.w && event.button.y < rect.y+rect.h)
|
||||
{
|
||||
window->SetCurrent(this);
|
||||
if(event.button.y >= rect.y+(rect.h-CONTROLS_HEIGHT) && rect.w > 0)
|
||||
{
|
||||
this->seeking=true;
|
||||
double pos = (double)(event.button.x - rect.x) / (double)rect.w;
|
||||
double length = 0;
|
||||
mpv_get_property(mpv, "duration", mpv_format::MPV_FORMAT_DOUBLE, &length);
|
||||
|
||||
std::string seek = std::to_string(length*pos);
|
||||
|
||||
const char *cmd_seek[] = {"seek", seek.c_str(), "absolute",NULL};
|
||||
mpv_command_async(mpv, 0, cmd_seek);
|
||||
}
|
||||
else {
|
||||
const char *cmd_pause[] = {"cycle", "pause", NULL};
|
||||
mpv_command_async(mpv, 0, cmd_pause);
|
||||
}
|
||||
return EventResult::Handled;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
{
|
||||
if(!window->IsCurrent(this)) return EventResult::Ignored;
|
||||
|
||||
if(event.key.keysym.sym == SDLK_UP || event.key.keysym.sym == SDLK_DOWN)
|
||||
{
|
||||
return EventResult::ParentDo;
|
||||
}
|
||||
|
||||
if(event.key.keysym.sym == SDLK_LEFT)
|
||||
{
|
||||
const char *seek[] = {"seek", "-10", NULL};
|
||||
mpv_command_async(mpv, 0, seek);
|
||||
return EventResult::Handled;
|
||||
}
|
||||
if(event.key.keysym.sym == SDLK_RIGHT)
|
||||
{
|
||||
const char *seek[] = {"seek", "+10", NULL};
|
||||
mpv_command_async(mpv, 0, seek);
|
||||
|
||||
return EventResult::Handled;
|
||||
}
|
||||
if (event.key.keysym.sym == SDLK_SPACE) {
|
||||
const char *cmd_pause[] = {"cycle", "pause", NULL};
|
||||
mpv_command_async(mpv, 0, cmd_pause);
|
||||
|
||||
mpv_get_property(mpv, "pause", mpv_format::MPV_FORMAT_FLAG, &paused);
|
||||
|
||||
return EventResult::Handled;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return EventResult::Handled;
|
||||
return EventResult::Ignored;
|
||||
}
|
||||
|
||||
void VideoPlayerWidget::Draw(SDL_Rect& rect)
|
||||
{
|
||||
auto window = this->GetRoot();
|
||||
if(window == nullptr) return;
|
||||
|
||||
|
||||
mpv_get_property(mpv, "pause", mpv_format::MPV_FORMAT_FLAG, &paused);
|
||||
|
||||
|
||||
|
||||
int w=rect.w, h=rect.h;
|
||||
if (!tex || tex_w != w || tex_h != h) {
|
||||
SDL_DestroyTexture(tex);
|
||||
@@ -114,9 +177,45 @@ namespace Tesses::BigScreen {
|
||||
if(tex)
|
||||
SDL_RenderCopy(window->GetRenderer(), tex, NULL, &rect);
|
||||
|
||||
SDL_Rect controls = {
|
||||
.x = rect.x,
|
||||
.y = rect.y + (rect.h-CONTROLS_HEIGHT),
|
||||
.w = rect.w,
|
||||
.h = CONTROLS_HEIGHT
|
||||
};
|
||||
if(this->controls || this->paused)
|
||||
{
|
||||
SDL_SetRenderDrawColor(window->GetRenderer(), COLOR_HIGHLIGHT.r, COLOR_HIGHLIGHT.g, COLOR_HIGHLIGHT.b, COLOR_HIGHLIGHT.a);
|
||||
|
||||
SDL_RenderFillRect(window->GetRenderer(), &controls);
|
||||
double length = 0;
|
||||
double time_pos = 0;
|
||||
mpv_get_property(mpv, "duration", mpv_format::MPV_FORMAT_DOUBLE, &length);
|
||||
|
||||
SDL_RenderPresent(window->GetRenderer());
|
||||
mpv_get_property(mpv,"time-pos",mpv_format::MPV_FORMAT_DOUBLE, &time_pos);
|
||||
|
||||
|
||||
if(length > 0)
|
||||
{
|
||||
double offset = time_pos / length;
|
||||
if(offset < 0.0)
|
||||
offset = 0.0;
|
||||
if(offset > 1.0)
|
||||
offset = 1.0;
|
||||
|
||||
SDL_Rect r2 = {
|
||||
.x=controls.x,
|
||||
.y=controls.y,
|
||||
.w=offset*rect.w,
|
||||
.h=controls.h
|
||||
};
|
||||
SDL_SetRenderDrawColor(window->GetRenderer(), COLOR_PRIMARY.r, COLOR_PRIMARY.g, COLOR_PRIMARY.b, COLOR_PRIMARY.a);
|
||||
|
||||
SDL_RenderFillRect(window->GetRenderer(), &r2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void VideoPlayerWidget::LoadFile(std::string file)
|
||||
|
||||
@@ -30,16 +30,20 @@ namespace Tesses::BigScreen
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<Widget> BigScreenWindow::GetWidget()
|
||||
{
|
||||
return this->page;
|
||||
}
|
||||
|
||||
BigScreenWindow::BigScreenWindow()
|
||||
{
|
||||
|
||||
|
||||
window = SDL_CreateWindow("Tesses Big Screen", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_RESIZABLE);
|
||||
window = SDL_CreateWindow("Tesses Big Screen", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_RESIZABLE | SDL_WINDOW_FULLSCREEN);
|
||||
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
|
||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
||||
this->fc = std::make_shared<FontCache>(renderer, 36);
|
||||
|
||||
this->fc = std::make_shared<FontCache>(renderer, 24);
|
||||
|
||||
running=true;
|
||||
}
|
||||
std::shared_ptr<FontCache> BigScreenWindow::GetFont()
|
||||
{
|
||||
@@ -59,7 +63,7 @@ namespace Tesses::BigScreen
|
||||
|
||||
void BigScreenWindow::Run()
|
||||
{
|
||||
while(running)
|
||||
while(Tesses::Framework::TF_IsRunning())
|
||||
{
|
||||
SDL_Event event;
|
||||
|
||||
@@ -84,7 +88,7 @@ namespace Tesses::BigScreen
|
||||
|
||||
|
||||
|
||||
|
||||
Tesses::Framework::TF_Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,8 +135,7 @@ namespace Tesses::BigScreen
|
||||
{
|
||||
case SDL_QUIT:
|
||||
{
|
||||
|
||||
running=false;
|
||||
Tesses::Framework::TF_SetIsRunning(false);
|
||||
|
||||
return EventResult::Handled;
|
||||
}
|
||||
@@ -182,8 +185,10 @@ namespace Tesses::BigScreen
|
||||
|
||||
this->page = page;
|
||||
if(page)
|
||||
{
|
||||
page->parent = this->weak_from_this();
|
||||
|
||||
SetCurrent(page.get());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -214,4 +219,21 @@ namespace Tesses::BigScreen
|
||||
return mytype;
|
||||
return std::shared_ptr<BigScreenWindow>();
|
||||
}
|
||||
|
||||
void BigScreenWindow::SetPage(std::string name, std::shared_ptr<Widget> widget)
|
||||
{
|
||||
auto cur = this->GetWidget();
|
||||
|
||||
auto vgrid = std::make_shared<VGrid>();
|
||||
auto hgrid = std::make_shared<HGrid>();
|
||||
hgrid->AddChild(std::make_shared<Button>("<-",[cur](std::shared_ptr<Widget> w)->void {
|
||||
auto win = w->GetRoot();
|
||||
if(win)
|
||||
win->SetWidget(cur);
|
||||
}),0);
|
||||
hgrid->AddChild(std::make_shared<Text>(name),0);
|
||||
vgrid->AddChild(hgrid,0);
|
||||
vgrid->AddChild(widget,GRID_STRETCH);
|
||||
this->SetWidget(vgrid);
|
||||
}
|
||||
}
|
||||
@@ -87,9 +87,10 @@ namespace Tesses::BigScreen
|
||||
{
|
||||
if(event.button.x >= rect.x && event.button.y >= rect.y && event.button.x < rect.x+rect.w && event.button.y < rect.y+rect.h)
|
||||
{
|
||||
|
||||
window->SetCurrent(this);
|
||||
if(this->cb) this->cb(this->shared_from_this());
|
||||
|
||||
window->SetCurrent(this);
|
||||
return EventResult::Handled;
|
||||
}
|
||||
}
|
||||
@@ -145,7 +146,7 @@ namespace Tesses::BigScreen
|
||||
rect.w-=4;
|
||||
rect.h-=4;
|
||||
SDL_SetRenderDrawColor(window->GetRenderer(), COLOR_BORDER.r, COLOR_BORDER.g, COLOR_BORDER.b, COLOR_BORDER.a);
|
||||
window->DrawRectThick(rect, 2);
|
||||
window->DrawRectThick(rect, 3);
|
||||
rect.x-=2;
|
||||
rect.y-=2;
|
||||
rect.w+=4;
|
||||
@@ -188,7 +189,7 @@ namespace Tesses::BigScreen
|
||||
this->child->parent = weak_from_this();
|
||||
|
||||
if(this->child)
|
||||
return this->child->MinWidth() + 24;
|
||||
return this->child->MinWidth() + 16;
|
||||
return 128;
|
||||
}
|
||||
|
||||
@@ -198,7 +199,7 @@ namespace Tesses::BigScreen
|
||||
this->child->parent = weak_from_this();
|
||||
|
||||
if(this->child)
|
||||
return this->child->MinHeight() + 24;
|
||||
return this->child->MinHeight() + 16;
|
||||
return 32;
|
||||
}
|
||||
}
|
||||
@@ -161,7 +161,7 @@ bool TryParseSDLColor(std::string str, SDL_Color& col)
|
||||
{
|
||||
str = HU::Replace(str," ","");
|
||||
//rgba(255,255,255,1.0)
|
||||
//rgb(197, 30, 30)
|
||||
//rgb(197,30,30)
|
||||
//#rgb
|
||||
//#rgba
|
||||
//#rrggbb
|
||||
|
||||
291
src/main.cpp
291
src/main.cpp
@@ -1,57 +1,260 @@
|
||||
#include "bigscreen.hpp"
|
||||
|
||||
using namespace Tesses::BigScreen;
|
||||
|
||||
std::vector<std::string> pages = {
|
||||
"VIDEOS",
|
||||
"MUSIC",
|
||||
"PICTURES",
|
||||
"PLUGINS",
|
||||
"SETTINGS",
|
||||
"EXIT"
|
||||
};
|
||||
|
||||
const int PAGE_VIDEO = 0;
|
||||
const int PAGE_MUSIC = 1;
|
||||
const int PAGE_PICTURES = 2;
|
||||
const int PAGE_PLUGINS = 3;
|
||||
const int PAGE_SETTINGS = 4;
|
||||
const int PAGE_EXIT = 5;
|
||||
|
||||
class Home : public Widget, public std::enable_shared_from_this<Home> {
|
||||
size_t pageIdx = 0;
|
||||
public:
|
||||
bool Click(SDL_Rect& rect,int x, int y)
|
||||
{
|
||||
auto window = this->GetRoot();
|
||||
if(!window) return false;
|
||||
auto font = window->GetFont();
|
||||
|
||||
|
||||
auto charWidth = font->MaxWidth();
|
||||
auto charHeight = font->MaxHeight();
|
||||
|
||||
auto yButtons = (rect.h-(rect.h/3))+rect.y;
|
||||
|
||||
auto centerBtnWidth = (charWidth * 9)+16;
|
||||
|
||||
auto centerBtnX = ((rect.w/2) - (centerBtnWidth / 2))+rect.x;
|
||||
|
||||
auto sideBtnWidth = (charWidth * 2)+16;
|
||||
auto leftButtonX = centerBtnX - (sideBtnWidth+16);
|
||||
auto rightButtonX = centerBtnX + centerBtnWidth + 16;
|
||||
|
||||
|
||||
SDL_Rect rect2 = {
|
||||
.x = centerBtnX,
|
||||
.y=yButtons,
|
||||
.w = centerBtnWidth,
|
||||
.h=charHeight+16
|
||||
};
|
||||
|
||||
|
||||
if(x >= rect2.x && y >= rect2.y && x < rect2.x + rect2.w && y < rect2.y + rect2.h)
|
||||
{
|
||||
Select();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
rect2 = {
|
||||
.x = leftButtonX,
|
||||
.y=yButtons,
|
||||
.w = sideBtnWidth,
|
||||
.h=charHeight+16
|
||||
};
|
||||
|
||||
if(x >= rect2.x && y >= rect2.y && x < rect2.x + rect2.w && y < rect2.y + rect2.h)
|
||||
{
|
||||
if(pageIdx > 0) pageIdx--;
|
||||
return true;
|
||||
}
|
||||
|
||||
rect2 = {
|
||||
.x = rightButtonX,
|
||||
.y=yButtons,
|
||||
.w = sideBtnWidth,
|
||||
.h=charHeight+16
|
||||
};
|
||||
|
||||
if(x >= rect2.x && y >= rect2.y && x < rect2.x + rect2.w && y < rect2.y + rect2.h)
|
||||
{
|
||||
if(pageIdx+1 < pages.size()) pageIdx++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
void Select()
|
||||
{
|
||||
auto window=GetRoot();
|
||||
if(!window) return;
|
||||
|
||||
switch(pageIdx)
|
||||
{
|
||||
case PAGE_VIDEO:
|
||||
{
|
||||
window->SetPage("Videos", nullptr);
|
||||
}
|
||||
break;
|
||||
case PAGE_EXIT:
|
||||
Tesses::Framework::TF_SetIsRunning(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
EventResult Event(SDL_Event& event,SDL_Rect& rect)
|
||||
{
|
||||
auto window = this->GetRoot();
|
||||
if(!window) return EventResult::Ignored;
|
||||
switch(event.type)
|
||||
{
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
{
|
||||
return Click(rect,event.button.x,event.button.y) ? EventResult::Handled : EventResult::Ignored;
|
||||
}
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
{
|
||||
switch(event.key.keysym.scancode)
|
||||
{
|
||||
case SDL_SCANCODE_ESCAPE:
|
||||
{
|
||||
Tesses::Framework::TF_SetIsRunning(false);
|
||||
return EventResult::Handled;
|
||||
}
|
||||
break;
|
||||
case SDL_SCANCODE_LEFT:
|
||||
{
|
||||
if(pageIdx > 0) pageIdx--;
|
||||
return EventResult::Handled;
|
||||
}
|
||||
break;
|
||||
case SDL_SCANCODE_RIGHT:
|
||||
{
|
||||
if(pageIdx+1 < pages.size()) pageIdx++;
|
||||
return EventResult::Handled;
|
||||
}
|
||||
break;
|
||||
case SDL_SCANCODE_SPACE:
|
||||
{
|
||||
Select();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return EventResult::Ignored;
|
||||
}
|
||||
void Draw(SDL_Rect& rect)
|
||||
{
|
||||
auto window = this->GetRoot();
|
||||
if(!window) return;
|
||||
auto font = window->GetFont();
|
||||
|
||||
auto dt= Tesses::Framework::Date::DateTime::Now();
|
||||
|
||||
|
||||
std::string dateTime = dt.ToString(
|
||||
"%I:%M:%S %p%n%a, %b %d, %Y"
|
||||
);
|
||||
|
||||
int myW=0, myH=0;
|
||||
|
||||
font->CalculateSize(dateTime,myW,myH);
|
||||
|
||||
font->Render(window->GetRenderer(), (rect.x + rect.w - myW) - 24, rect.y+12,dateTime,COLOR_TEXT);
|
||||
|
||||
|
||||
font->CalculateSize("Tesses BigScreen",myW, myH);
|
||||
|
||||
myW = ((rect.w / 2) - (myW/2)) + rect.x;
|
||||
myH = (rect.h/4) + rect.y;
|
||||
|
||||
font->Render(window->GetRenderer(), myW,myH, "Tesses BigScreen", COLOR_TEXT);
|
||||
|
||||
auto charWidth = font->MaxWidth();
|
||||
auto charHeight = font->MaxHeight();
|
||||
|
||||
auto yButtons = (rect.h-(rect.h/3))+rect.y;
|
||||
|
||||
auto centerBtnWidth = (charWidth * 9)+16;
|
||||
|
||||
auto centerBtnX = ((rect.w/2) - (centerBtnWidth / 2))+rect.x;
|
||||
|
||||
auto sideBtnWidth = (charWidth * 2)+16;
|
||||
auto leftButtonX = centerBtnX - (sideBtnWidth+16);
|
||||
auto rightButtonX = centerBtnX + centerBtnWidth + 16;
|
||||
|
||||
|
||||
SDL_Rect rect2 = {
|
||||
.x = centerBtnX,
|
||||
.y=yButtons,
|
||||
.w = centerBtnWidth,
|
||||
.h=charHeight+16
|
||||
};
|
||||
|
||||
SDL_SetRenderDrawColor(window->GetRenderer(), COLOR_PRIMARY.r, COLOR_PRIMARY.g, COLOR_PRIMARY.b,COLOR_PRIMARY.a);
|
||||
SDL_RenderFillRect(window->GetRenderer(), &rect2);
|
||||
|
||||
font->CalculateSize(pages[this->pageIdx],myW,myH);
|
||||
|
||||
myW = ((rect2.w/2) - (myW/2))+rect2.x;
|
||||
|
||||
myH = ((rect2.h/2) - (myH/2))+rect2.y;
|
||||
|
||||
font->Render(window->GetRenderer(),myW,myH,pages[this->pageIdx],COLOR_TEXT);
|
||||
|
||||
|
||||
rect2 = {
|
||||
.x = leftButtonX,
|
||||
.y=yButtons,
|
||||
.w = sideBtnWidth,
|
||||
.h=charHeight+16
|
||||
};
|
||||
SDL_RenderFillRect(window->GetRenderer(), &rect2);
|
||||
font->CalculateSize("<-",myW,myH);
|
||||
|
||||
myW = ((rect2.w/2) - (myW/2))+rect2.x;
|
||||
|
||||
myH = ((rect2.h/2) - (myH/2))+rect2.y;
|
||||
|
||||
font->Render(window->GetRenderer(),myW,myH,"<-",COLOR_TEXT);
|
||||
|
||||
|
||||
|
||||
rect2 = {
|
||||
.x = rightButtonX,
|
||||
.y=yButtons,
|
||||
.w = sideBtnWidth,
|
||||
.h=charHeight+16
|
||||
};
|
||||
SDL_RenderFillRect(window->GetRenderer(), &rect2);
|
||||
|
||||
font->CalculateSize("->",myW,myH);
|
||||
|
||||
myW = ((rect2.w/2) - (myW/2))+rect2.x;
|
||||
|
||||
myH = ((rect2.h/2) - (myH/2))+rect2.y;
|
||||
|
||||
font->Render(window->GetRenderer(),myW,myH,"->",COLOR_TEXT);
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Tesses::Framework::TF_Init();
|
||||
TTF_Init();
|
||||
|
||||
SDL_Init(SDL_INIT_EVERYTHING);
|
||||
using namespace Tesses::BigScreen;
|
||||
auto window = std::make_shared<BigScreenWindow>();
|
||||
/*window->SetWidget(std::make_shared<Button>("My Button",[](std::shared_ptr<Tesses::BigScreen::Widget> w)->void{
|
||||
std::cout << "Hi" << std::endl;
|
||||
}));*/
|
||||
|
||||
|
||||
std::shared_ptr<VGrid> vgrid = std::make_shared<VGrid>();
|
||||
|
||||
vgrid->AddChild(std::make_shared<Text>("Label"),0);
|
||||
|
||||
vgrid->AddChild(std::make_shared<Button>("My Button",[](std::shared_ptr<Widget> w)->void{
|
||||
std::cout <<"My Button" <<std::endl;
|
||||
}), 0);
|
||||
vgrid->AddChild(std::make_shared<Text>("Label 2"),0);
|
||||
vgrid->AddChild(std::make_shared<Button>("My Button 2",[](std::shared_ptr<Widget> w)->void{
|
||||
std::cout <<"My Button 2" <<std::endl;
|
||||
}), 0);
|
||||
|
||||
auto hgrid = std::make_shared<HGrid>();
|
||||
|
||||
vgrid->AddChild(nullptr, GRID_STRETCH);
|
||||
auto win = std::make_shared<BigScreenWindow>();
|
||||
win->SetWidget(std::make_shared<Home>());
|
||||
win->Run();
|
||||
|
||||
hgrid->AddChild(nullptr,GRID_STRETCH);
|
||||
|
||||
hgrid->AddChild(std::make_shared<Button>("<-", [](std::shared_ptr<Widget> widget)->void {
|
||||
std::cout << "<-" << std::endl;
|
||||
}),0);
|
||||
hgrid->AddChild(nullptr,16);
|
||||
hgrid->AddChild(std::make_shared<Button>("OK", [](std::shared_ptr<Widget> widget)->void {
|
||||
std::cout << "OK" << std::endl;
|
||||
}),0);
|
||||
|
||||
hgrid->AddChild(nullptr,16);
|
||||
hgrid->AddChild(std::make_shared<Button>("Cancel", [](std::shared_ptr<Widget> widget)->void {
|
||||
std::cout << "Cancel" << std::endl;
|
||||
}),0);
|
||||
|
||||
|
||||
hgrid->AddChild(nullptr, 32);
|
||||
|
||||
vgrid->AddChild(hgrid, 0);
|
||||
|
||||
vgrid->AddChild(nullptr, 32);
|
||||
|
||||
window->SetWidget(vgrid);
|
||||
|
||||
window->Run();
|
||||
return 0;
|
||||
}
|
||||
438
src/textbox.cpp
Normal file
438
src/textbox.cpp
Normal file
@@ -0,0 +1,438 @@
|
||||
#include "bigscreen.hpp"
|
||||
|
||||
namespace Tesses::BigScreen
|
||||
{
|
||||
EventResult TextBox::Event(SDL_Event& event,SDL_Rect& rect)
|
||||
{
|
||||
auto window = this->GetRoot();
|
||||
if(!window) return EventResult::Ignored;
|
||||
|
||||
|
||||
switch(event.type)
|
||||
{
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
{
|
||||
if(event.button.x >= rect.x && event.button.y >= rect.y && event.button.x < rect.x+rect.w && event.button.y < rect.y+rect.h)
|
||||
{
|
||||
|
||||
std::shared_ptr<TextBoxDialog> dlg = std::make_shared<TextBoxDialog>(shared_from_this(),window->GetWidget());
|
||||
window->SetWidget(dlg);
|
||||
return EventResult::Handled;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
{
|
||||
switch(event.key.keysym.scancode)
|
||||
{
|
||||
case SDL_Scancode::SDL_SCANCODE_SPACE:
|
||||
{
|
||||
if(window->IsCurrent(this))
|
||||
{
|
||||
std::shared_ptr<TextBoxDialog> dlg = std::make_shared<TextBoxDialog>(shared_from_this(),window->GetWidget());
|
||||
window->SetWidget(dlg);
|
||||
|
||||
return EventResult::Handled;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_Scancode::SDL_SCANCODE_UP:
|
||||
case SDL_Scancode::SDL_SCANCODE_DOWN:
|
||||
case SDL_Scancode::SDL_SCANCODE_LEFT:
|
||||
case SDL_Scancode::SDL_SCANCODE_RIGHT:
|
||||
{
|
||||
if(window->IsCurrent(this))
|
||||
return EventResult::ParentDo;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return EventResult::Ignored;
|
||||
}
|
||||
std::string TextBox::GetText()
|
||||
{
|
||||
return this->text;
|
||||
}
|
||||
void TextBox::SetText(std::string text)
|
||||
{
|
||||
this->text = text;
|
||||
}
|
||||
void TextBox::Draw(SDL_Rect& rect)
|
||||
{
|
||||
auto window = this->GetRoot();
|
||||
if(!window) return;
|
||||
|
||||
Clipper clipper(window->GetRenderer(),rect);
|
||||
if(clipper.Clip(rect))
|
||||
{
|
||||
auto font = window->GetFont();
|
||||
auto height = (rect.h/2) - (font->MaxHeight()/2);
|
||||
|
||||
font->Render(window->GetRenderer(),rect.x+10,rect.y+height,text,COLOR_TEXT);
|
||||
}
|
||||
|
||||
SDL_SetRenderDrawColor(window->GetRenderer(), COLOR_PRIMARY.r, COLOR_PRIMARY.g, COLOR_PRIMARY.b, 255);
|
||||
|
||||
window->DrawRectThick(rect,6);
|
||||
if(window->IsCurrent(this))
|
||||
{
|
||||
rect.x+=2;
|
||||
rect.y+=2;
|
||||
rect.w-=4;
|
||||
rect.h-=4;
|
||||
SDL_SetRenderDrawColor(window->GetRenderer(), COLOR_BORDER.r, COLOR_BORDER.g, COLOR_BORDER.b, COLOR_BORDER.a);
|
||||
window->DrawRectThick(rect, 2);
|
||||
rect.x-=2;
|
||||
rect.y-=2;
|
||||
rect.w+=4;
|
||||
rect.h+=4;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
int TextBox::MinWidth()
|
||||
{
|
||||
auto window = this->GetRoot();
|
||||
if(!window) return 0;
|
||||
int x=0;
|
||||
int y=0;
|
||||
window->GetFont()->CalculateSize(text,x,y);
|
||||
|
||||
return x+16;
|
||||
}
|
||||
|
||||
int TextBox::MinHeight()
|
||||
{
|
||||
auto window = this->GetRoot();
|
||||
if(!window) return 0;
|
||||
int x=0;
|
||||
int y=0;
|
||||
window->GetFont()->CalculateSize(text,x,y);
|
||||
|
||||
return y+16;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const int KEYBOARD_WIDTH = 14;
|
||||
const int KEYBOARD_HEIGHT = 4;
|
||||
|
||||
const char* lower[KEYBOARD_HEIGHT][KEYBOARD_WIDTH]= {
|
||||
{
|
||||
"`","1","2","3","4","5","6","7","8","9","0","-","=","BS"
|
||||
},
|
||||
{
|
||||
"q","w","e","r","t","y","u","i","o","p","[","]","\\"," ",
|
||||
},
|
||||
{
|
||||
"a","s","d","f","g","h","i","j","k","l",";","'","<-","->"
|
||||
},
|
||||
{
|
||||
"SH","z","x","c","v","b","n","m",",",".","/","SH"," ","OK",
|
||||
}
|
||||
};
|
||||
|
||||
const char* upper[KEYBOARD_HEIGHT][KEYBOARD_WIDTH]= {
|
||||
{
|
||||
"~","!","@","#","$","%","^","&","*","(",")","_","+","BS"
|
||||
},
|
||||
{
|
||||
"Q","W","E","R","T","Y","U","I","O","P","{","}","|"," ",
|
||||
},
|
||||
{
|
||||
"A","S","D","F","G","H","I","J","K","L",":","\"","<-","->"
|
||||
},
|
||||
{
|
||||
"SH","Z","X","C","V","B","N","M","<",">","?","SH"," ","OK",
|
||||
}
|
||||
};
|
||||
|
||||
void TextBox::TextBoxDialog::Append(char c)
|
||||
{
|
||||
if(c == '\b')
|
||||
{
|
||||
auto& pos = this->cursor;
|
||||
if(pos >= this->tb->text.size())
|
||||
pos = this->tb->text.size();
|
||||
|
||||
if(pos > 0)
|
||||
{
|
||||
pos--;
|
||||
this->tb->text.erase(pos,1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto& pos = this->cursor;
|
||||
if(pos >= this->tb->text.size())
|
||||
pos = this->tb->text.size();
|
||||
|
||||
this->tb->text.insert(pos, {c});
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
TextBox::TextBoxDialog::TextBoxDialog(std::shared_ptr<TextBox> tb, std::shared_ptr<Widget> page): tb(tb), page(page)
|
||||
{
|
||||
this->cursor = tb->text.size();
|
||||
|
||||
}
|
||||
void TextBox::TextBoxDialog::HandleKey()
|
||||
{
|
||||
if(y == -1) return;
|
||||
if((x == 0 || x == 11) && y == 3) {
|
||||
shift=!shift;
|
||||
}
|
||||
else if(x==13 && y ==3) {
|
||||
auto window = this->GetRoot();
|
||||
if(!window) return;
|
||||
window->SetWidget(this->page);
|
||||
if(this->tb)
|
||||
window->SetCurrent(this->tb.get());
|
||||
}
|
||||
else if(x == 12 && y == 2)
|
||||
{
|
||||
this->cursor--;
|
||||
if(this->cursor >= this->tb->text.size())
|
||||
this->cursor=0;
|
||||
}
|
||||
else if(x == 13 && y == 2)
|
||||
{
|
||||
this->cursor++;
|
||||
if(this->cursor >= this->tb->text.size())
|
||||
this->cursor=this->tb->text.size();
|
||||
}
|
||||
else if(x == 13 && y == 0)
|
||||
{
|
||||
Append('\b');
|
||||
}
|
||||
else {
|
||||
if(x >= 0 && y >= 0 && x < KEYBOARD_WIDTH && y < KEYBOARD_HEIGHT)
|
||||
Append(((shift ? upper : lower)[y][x])[0]);
|
||||
|
||||
shift=false;
|
||||
}
|
||||
}
|
||||
EventResult TextBox::TextBoxDialog::Event(SDL_Event& event,SDL_Rect& rect)
|
||||
{
|
||||
auto window = this->GetRoot();
|
||||
if(!window) return EventResult::Ignored;
|
||||
|
||||
|
||||
switch(event.type)
|
||||
{
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
{
|
||||
int btnTextSzW=0;
|
||||
int btnTextSzH=0;
|
||||
window->GetFont()->CalculateSize("OO",btnTextSzW,btnTextSzH);
|
||||
int btnSzW = btnTextSzW+16;
|
||||
int btnSzH = btnTextSzW+16;
|
||||
|
||||
int keyboardHeight = (KEYBOARD_HEIGHT * btnSzH) + 16;
|
||||
int keyboardWidth = (KEYBOARD_WIDTH * btnSzW) + 16;
|
||||
|
||||
int keyboardX = ((rect.w/2) - (keyboardWidth/2))+rect.x;
|
||||
int keyboardY = rect.y+(rect.h-keyboardHeight);
|
||||
|
||||
for(int y = 0; y < KEYBOARD_HEIGHT; y++)
|
||||
{
|
||||
for(int x = 0; x < KEYBOARD_WIDTH; x++)
|
||||
{
|
||||
auto keyX = keyboardX + (x*btnSzW);
|
||||
auto keyY = keyboardY + (y*btnSzH);
|
||||
|
||||
if(event.button.x < keyX) continue;
|
||||
if(event.button.y < keyY) continue;
|
||||
if(event.button.x >= (keyX + btnSzW)) continue;
|
||||
if(event.button.y >= (keyY + btnSzH)) continue;
|
||||
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
|
||||
HandleKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_TEXTINPUT:
|
||||
{
|
||||
|
||||
if(event.text.text[0] != ' ') {
|
||||
Append(event.text.text[0]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
switch(event.key.keysym.scancode)
|
||||
{
|
||||
case SDL_SCANCODE_SPACE:
|
||||
{
|
||||
if(this->y == -1)
|
||||
{
|
||||
Append(' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleKey();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_SCANCODE_UP:
|
||||
{
|
||||
this->y--;
|
||||
if(this->y < -1) this->y=-1;
|
||||
}
|
||||
break;
|
||||
case SDL_SCANCODE_DOWN:
|
||||
{
|
||||
this->y++;
|
||||
if(this->y >= KEYBOARD_HEIGHT) this->y=KEYBOARD_HEIGHT-1;
|
||||
}
|
||||
break;
|
||||
case SDL_SCANCODE_LEFT:
|
||||
{
|
||||
if(this->y == -1)
|
||||
{
|
||||
this->cursor--;
|
||||
if(this->cursor >= this->tb->text.size())
|
||||
this->cursor=0;
|
||||
}
|
||||
else {
|
||||
this->x--;
|
||||
if(this->x < 0) this->x=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_SCANCODE_RIGHT:
|
||||
{
|
||||
if(this->y == -1)
|
||||
{
|
||||
this->cursor++;
|
||||
if(this->cursor >= this->tb->text.size())
|
||||
this->cursor=this->tb->text.size();
|
||||
}
|
||||
else {
|
||||
this->x++;
|
||||
if(this->x >= KEYBOARD_WIDTH) this->x=KEYBOARD_WIDTH-1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_SCANCODE_RETURN:
|
||||
case SDL_SCANCODE_RETURN2:
|
||||
case SDL_SCANCODE_ESCAPE:
|
||||
{
|
||||
window->SetWidget(this->page);
|
||||
if(this->tb)
|
||||
window->SetCurrent(this->tb.get());
|
||||
return EventResult::Handled;
|
||||
}
|
||||
break;
|
||||
case SDL_SCANCODE_BACKSPACE:
|
||||
{
|
||||
Append('\b');
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return EventResult::Ignored;
|
||||
}
|
||||
void TextBox::TextBoxDialog::Draw(SDL_Rect& rect)
|
||||
{
|
||||
auto window = this->GetRoot();
|
||||
if(!window) return;
|
||||
|
||||
if(this->page)
|
||||
this->page->Draw(rect);
|
||||
|
||||
int btnTextSzW=0;
|
||||
int btnTextSzH=0;
|
||||
|
||||
auto font = window->GetFont();
|
||||
font->CalculateSize("OO",btnTextSzW,btnTextSzH);
|
||||
auto textWidth = font->MaxWidth();
|
||||
int btnSzW = btnTextSzW+16;
|
||||
int btnSzH = btnTextSzW+16;
|
||||
|
||||
int keyboardHeight = (KEYBOARD_HEIGHT * btnSzH) + 16;
|
||||
int keyboardWidth = (KEYBOARD_WIDTH * btnSzW) + 16;
|
||||
|
||||
int keyboardX = ((rect.w/2) - (keyboardWidth/2))+8+rect.x;
|
||||
int keyboardY = rect.y+8+(rect.h-keyboardHeight);
|
||||
|
||||
|
||||
SDL_SetRenderDrawColor(window->GetRenderer(), 0,0,0,200);
|
||||
SDL_RenderFillRect(window->GetRenderer(), &rect);
|
||||
|
||||
|
||||
SDL_SetRenderDrawColor(window->GetRenderer(), COLOR_PRIMARY.r,COLOR_PRIMARY.g,COLOR_PRIMARY.b,COLOR_PRIMARY.a);
|
||||
|
||||
int height = font->MaxHeight()+16;
|
||||
|
||||
SDL_Rect r2 = {
|
||||
.x = rect.x,
|
||||
.y=((rect.h-keyboardHeight)/2) - (height/2),
|
||||
.w = rect.w,
|
||||
.h = height
|
||||
};
|
||||
|
||||
SDL_RenderFillRect(window->GetRenderer(), &r2);
|
||||
|
||||
auto maxChars = (rect.w-16) / textWidth;
|
||||
|
||||
|
||||
if(tb->text.size() <= maxChars)
|
||||
{
|
||||
font->Render(window->GetRenderer(), rect.x+8, ((rect.h-keyboardHeight)/2) - (height/2) + 8, tb->text, COLOR_TEXT);
|
||||
}
|
||||
else {
|
||||
auto page = this->cursor / maxChars;
|
||||
font->Render(window->GetRenderer(), rect.x+8,((rect.h-keyboardHeight)/2) - (height/2) + 8, tb->text.substr(page*maxChars,maxChars), COLOR_TEXT);
|
||||
}
|
||||
|
||||
int cur = (int)(this->cursor % maxChars);
|
||||
r2 = {.x=rect.x+8+(textWidth*cur),.y=((rect.h-keyboardHeight)/2) - (height/2)+ height-4,.w=textWidth,.h=4};
|
||||
SDL_SetRenderDrawColor(window->GetRenderer(), COLOR_HIGHLIGHT.r,COLOR_HIGHLIGHT.g,COLOR_HIGHLIGHT.b,COLOR_HIGHLIGHT.a);
|
||||
|
||||
SDL_RenderFillRect(window->GetRenderer(), &r2);
|
||||
|
||||
SDL_SetRenderDrawColor(window->GetRenderer(), COLOR_PRIMARY.r,COLOR_PRIMARY.g,COLOR_PRIMARY.b,COLOR_PRIMARY.a);
|
||||
|
||||
r2 = {
|
||||
.x = rect.x,
|
||||
.y=(rect.h-keyboardHeight)+rect.y,
|
||||
.w = rect.w,
|
||||
.h = keyboardHeight
|
||||
};
|
||||
|
||||
|
||||
|
||||
SDL_RenderFillRect(window->GetRenderer(), &r2);
|
||||
|
||||
|
||||
for(int y=0;y<KEYBOARD_HEIGHT; y++)
|
||||
{
|
||||
for(int x = 0; x < KEYBOARD_WIDTH; x++)
|
||||
{
|
||||
int textX = (x*btnSzW) + keyboardX;
|
||||
int textY = (y*btnSzH) + keyboardY;
|
||||
|
||||
font->Render(window->GetRenderer(), textX, textY, (shift ? upper : lower)[y][x], COLOR_TEXT);
|
||||
|
||||
if(this->x == x && this->y == y)
|
||||
{
|
||||
SDL_Rect r = {.x=textX-8,.y=textY-8,.w = btnSzW, .h=btnSzH};
|
||||
SDL_SetRenderDrawColor(window->GetRenderer(), COLOR_HIGHLIGHT.r, COLOR_HIGHLIGHT.g,COLOR_HIGHLIGHT.b,COLOR_HIGHLIGHT.a);
|
||||
window->DrawRectThick(r,6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user