mirror of
https://github.com/xenia-project/elemental-forms.git
synced 2024-11-23 03:29:43 +00:00
Refactorized demo platform integration to better suit game loops.
Makes it easier to reuse the demo platform glue for other projects. Especially game loops or platforms where rendering is set up in a different order. TB API change: Removed language file path from tb_core_init. g_tb_lng->Load should be called manually after tb_core_init instead.
This commit is contained in:
parent
3e6464d1db
commit
2f51f25369
@ -12,19 +12,21 @@
|
||||
|
||||
using namespace tb;
|
||||
|
||||
class DemoApplication : public Application
|
||||
class DemoApplication : public App
|
||||
{
|
||||
public:
|
||||
DemoApplication() : Application() {}
|
||||
DemoApplication() : App(1280, 700) {}
|
||||
|
||||
virtual const char *GetTitle() const { return "Demo"; }
|
||||
virtual void OnBackendAttached(AppBackend *backend, int width, int height);
|
||||
virtual bool Init();
|
||||
virtual void RenderFrame(int window_w, int window_h);
|
||||
virtual void RenderFrame();
|
||||
};
|
||||
|
||||
class DemoWindow : public TBWindow
|
||||
{
|
||||
public:
|
||||
DemoWindow();
|
||||
DemoWindow(TBWidget *root);
|
||||
bool LoadResourceFile(const char *filename);
|
||||
void LoadResourceData(const char *data);
|
||||
void LoadResource(TBNode &node);
|
||||
@ -35,7 +37,7 @@ public:
|
||||
class MainWindow : public DemoWindow, public TBMessageHandler
|
||||
{
|
||||
public:
|
||||
MainWindow();
|
||||
MainWindow(TBWidget *root);
|
||||
virtual bool OnEvent(const TBWidgetEvent &ev);
|
||||
|
||||
// Implement TBMessageHandler
|
||||
@ -45,14 +47,14 @@ public:
|
||||
class ImageWindow : public DemoWindow
|
||||
{
|
||||
public:
|
||||
ImageWindow();
|
||||
ImageWindow(TBWidget *root);
|
||||
virtual bool OnEvent(const TBWidgetEvent &ev);
|
||||
};
|
||||
|
||||
class PageWindow : public DemoWindow, public TBScrollerSnapListener
|
||||
{
|
||||
public:
|
||||
PageWindow();
|
||||
PageWindow(TBWidget *root);
|
||||
virtual bool OnEvent(const TBWidgetEvent &ev);
|
||||
virtual void OnScrollSnap(TBWidget *target_widget, int &target_x, int &target_y);
|
||||
};
|
||||
@ -60,7 +62,7 @@ public:
|
||||
class AnimationsWindow : public DemoWindow
|
||||
{
|
||||
public:
|
||||
AnimationsWindow();
|
||||
AnimationsWindow(TBWidget *root);
|
||||
void Animate();
|
||||
virtual bool OnEvent(const TBWidgetEvent &ev);
|
||||
};
|
||||
@ -68,28 +70,28 @@ public:
|
||||
class LayoutWindow : public DemoWindow
|
||||
{
|
||||
public:
|
||||
LayoutWindow(const char *filename);
|
||||
LayoutWindow(TBWidget *root, const char *filename);
|
||||
virtual bool OnEvent(const TBWidgetEvent &ev);
|
||||
};
|
||||
|
||||
class TabContainerWindow : public DemoWindow
|
||||
{
|
||||
public:
|
||||
TabContainerWindow();
|
||||
TabContainerWindow(TBWidget *root);
|
||||
virtual bool OnEvent(const TBWidgetEvent &ev);
|
||||
};
|
||||
|
||||
class ConnectionWindow : public DemoWindow
|
||||
{
|
||||
public:
|
||||
ConnectionWindow();
|
||||
ConnectionWindow(TBWidget *root);
|
||||
virtual bool OnEvent(const TBWidgetEvent &ev);
|
||||
};
|
||||
|
||||
class ScrollContainerWindow : public DemoWindow, public TBMessageHandler
|
||||
{
|
||||
public:
|
||||
ScrollContainerWindow();
|
||||
ScrollContainerWindow(TBWidget *root);
|
||||
virtual bool OnEvent(const TBWidgetEvent &ev);
|
||||
|
||||
// Implement TBMessageHandler
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <stdarg.h>
|
||||
#include "tests/tb_test.h"
|
||||
#include "tb_system.h"
|
||||
#include "tb_language.h"
|
||||
#include "tb_inline_select.h"
|
||||
#include "tb_select.h"
|
||||
#include "tb_menu_window.h"
|
||||
@ -18,8 +19,6 @@
|
||||
#include "image/tb_image_manager.h"
|
||||
#include "utf8/utf8.h"
|
||||
|
||||
static Application *application;
|
||||
|
||||
AdvancedItemSource advanced_source;
|
||||
TBGenericStringItemSource name_source;
|
||||
TBGenericStringItemSource popup_menu_source;
|
||||
@ -48,9 +47,9 @@ void const_expr_test()
|
||||
|
||||
// == DemoWindow ==============================================================
|
||||
|
||||
DemoWindow::DemoWindow()
|
||||
DemoWindow::DemoWindow(TBWidget *root)
|
||||
{
|
||||
application->GetRoot()->AddChild(this);
|
||||
root->AddChild(this);
|
||||
}
|
||||
|
||||
bool DemoWindow::LoadResourceFile(const char *filename)
|
||||
@ -132,7 +131,7 @@ bool DemoWindow::OnEvent(const TBWidgetEvent &ev)
|
||||
class EditWindow : public DemoWindow
|
||||
{
|
||||
public:
|
||||
EditWindow()
|
||||
EditWindow(TBWidget *root) : DemoWindow(root)
|
||||
{
|
||||
LoadResourceFile("Demo/demo01/ui_resources/test_textwindow.tb.txt");
|
||||
}
|
||||
@ -259,7 +258,7 @@ public:
|
||||
|
||||
// == LayoutWindow ============================================================
|
||||
|
||||
LayoutWindow::LayoutWindow(const char *filename)
|
||||
LayoutWindow::LayoutWindow(TBWidget *root, const char *filename) : DemoWindow(root)
|
||||
{
|
||||
LoadResourceFile(filename);
|
||||
}
|
||||
@ -293,7 +292,7 @@ bool LayoutWindow::OnEvent(const TBWidgetEvent &ev)
|
||||
|
||||
// == TabContainerWindow ============================================================
|
||||
|
||||
TabContainerWindow::TabContainerWindow()
|
||||
TabContainerWindow::TabContainerWindow(TBWidget *root) : DemoWindow(root)
|
||||
{
|
||||
LoadResourceFile("Demo/demo01/ui_resources/test_tabcontainer01.tb.txt");
|
||||
}
|
||||
@ -335,7 +334,7 @@ bool TabContainerWindow::OnEvent(const TBWidgetEvent &ev)
|
||||
|
||||
// == ConnectionWindow =========================================================
|
||||
|
||||
ConnectionWindow::ConnectionWindow()
|
||||
ConnectionWindow::ConnectionWindow(TBWidget *root) : DemoWindow(root)
|
||||
{
|
||||
LoadResourceFile("Demo/demo01/ui_resources/test_connections.tb.txt");
|
||||
}
|
||||
@ -357,7 +356,7 @@ bool ConnectionWindow::OnEvent(const TBWidgetEvent &ev)
|
||||
|
||||
// == ScrollContainerWindow ===================================================
|
||||
|
||||
ScrollContainerWindow::ScrollContainerWindow()
|
||||
ScrollContainerWindow::ScrollContainerWindow(TBWidget *root) : DemoWindow(root)
|
||||
{
|
||||
LoadResourceFile("Demo/demo01/ui_resources/test_scrollcontainer.tb.txt");
|
||||
|
||||
@ -446,7 +445,7 @@ void ScrollContainerWindow::OnMessageReceived(TBMessage *msg)
|
||||
|
||||
// == ImageWindow =============================================================
|
||||
|
||||
ImageWindow::ImageWindow()
|
||||
ImageWindow::ImageWindow(TBWidget *root) : DemoWindow(root)
|
||||
{
|
||||
LoadResourceFile("Demo/demo01/ui_resources/test_image_widget.tb.txt");
|
||||
}
|
||||
@ -465,7 +464,7 @@ bool ImageWindow::OnEvent(const TBWidgetEvent &ev)
|
||||
|
||||
// == PageWindow =============================================================
|
||||
|
||||
PageWindow::PageWindow()
|
||||
PageWindow::PageWindow(TBWidget *root) : DemoWindow(root)
|
||||
{
|
||||
LoadResourceFile("Demo/demo01/ui_resources/test_scroller_snap.tb.txt");
|
||||
|
||||
@ -488,7 +487,7 @@ void PageWindow::OnScrollSnap(TBWidget *target_widget, int &target_x, int &targe
|
||||
|
||||
// == AnimationsWindow ========================================================
|
||||
|
||||
AnimationsWindow::AnimationsWindow()
|
||||
AnimationsWindow::AnimationsWindow(TBWidget *root) : DemoWindow(root)
|
||||
{
|
||||
LoadResourceFile("Demo/demo01/ui_resources/test_animations.tb.txt");
|
||||
Animate();
|
||||
@ -530,7 +529,7 @@ bool AnimationsWindow::OnEvent(const TBWidgetEvent &ev)
|
||||
|
||||
// == MainWindow ==============================================================
|
||||
|
||||
MainWindow::MainWindow()
|
||||
MainWindow::MainWindow(TBWidget *root) : DemoWindow(root)
|
||||
{
|
||||
LoadResourceFile("Demo/demo01/ui_resources/test_ui.tb.txt");
|
||||
|
||||
@ -566,7 +565,7 @@ bool MainWindow::OnEvent(const TBWidgetEvent &ev)
|
||||
{
|
||||
if (ev.target->GetID() == TBIDC("new"))
|
||||
{
|
||||
new MainWindow();
|
||||
new MainWindow(GetParentRoot());
|
||||
return true;
|
||||
}
|
||||
if (ev.target->GetID() == TBIDC("msg"))
|
||||
@ -647,43 +646,43 @@ bool MainWindow::OnEvent(const TBWidgetEvent &ev)
|
||||
{
|
||||
TBStr resource_file("Demo/demo01/ui_resources/");
|
||||
resource_file.Append(ev.target->data.GetString());
|
||||
new LayoutWindow(resource_file);
|
||||
new LayoutWindow(GetParentRoot(), resource_file);
|
||||
return true;
|
||||
}
|
||||
else if (ev.target->GetID() == TBIDC("test-connections"))
|
||||
{
|
||||
new ConnectionWindow();
|
||||
new ConnectionWindow(GetParentRoot());
|
||||
return true;
|
||||
}
|
||||
else if (ev.target->GetID() == TBIDC("test-list"))
|
||||
{
|
||||
new AdvancedListWindow(&advanced_source);
|
||||
new AdvancedListWindow(GetParentRoot(), &advanced_source);
|
||||
return true;
|
||||
}
|
||||
else if (ev.target->GetID() == TBIDC("test-image"))
|
||||
{
|
||||
new ImageWindow();
|
||||
new ImageWindow(GetParentRoot());
|
||||
return true;
|
||||
}
|
||||
else if (ev.target->GetID() == TBIDC("test-page"))
|
||||
{
|
||||
new PageWindow();
|
||||
new PageWindow(GetParentRoot());
|
||||
return true;
|
||||
}
|
||||
else if (ev.target->GetID() == TBIDC("test-animations"))
|
||||
{
|
||||
new AnimationsWindow();
|
||||
new AnimationsWindow(GetParentRoot());
|
||||
return true;
|
||||
}
|
||||
else if (ev.target->GetID() == TBIDC("test-scroll-container"))
|
||||
{
|
||||
new ScrollContainerWindow();
|
||||
new ScrollContainerWindow(GetParentRoot());
|
||||
return true;
|
||||
}
|
||||
else if (ev.target->GetID() == TBIDC("test-skin-conditions"))
|
||||
{
|
||||
(new DemoWindow())->LoadResourceFile("Demo/demo01/ui_resources/test_skin_conditions01.tb.txt");
|
||||
(new DemoWindow())->LoadResourceFile("Demo/demo01/ui_resources/test_skin_conditions02.tb.txt");
|
||||
(new DemoWindow(GetParentRoot()))->LoadResourceFile("Demo/demo01/ui_resources/test_skin_conditions01.tb.txt");
|
||||
(new DemoWindow(GetParentRoot()))->LoadResourceFile("Demo/demo01/ui_resources/test_skin_conditions02.tb.txt");
|
||||
return true;
|
||||
}
|
||||
else if (ev.target->GetID() == TBIDC("test-resource-edit"))
|
||||
@ -737,7 +736,7 @@ const char *boy_names[] = {
|
||||
|
||||
bool DemoApplication::Init()
|
||||
{
|
||||
if (!Application::Init())
|
||||
if (!App::Init())
|
||||
return false;
|
||||
|
||||
// Block new animations during Init.
|
||||
@ -771,15 +770,15 @@ bool DemoApplication::Init()
|
||||
// Give the first item a skin image
|
||||
popup_menu_source.GetItem(0)->SetSkinImage(TBIDC("Icon16"));
|
||||
|
||||
new MainWindow();
|
||||
new MainWindow(&m_root);
|
||||
|
||||
new EditWindow;
|
||||
new EditWindow(&m_root);
|
||||
|
||||
new ListWindow(&name_source);
|
||||
new ListWindow(&m_root, &name_source);
|
||||
|
||||
new AdvancedListWindow(&advanced_source);
|
||||
new AdvancedListWindow(&m_root, &advanced_source);
|
||||
|
||||
new TabContainerWindow();
|
||||
new TabContainerWindow(&m_root);
|
||||
|
||||
if (num_failed_tests)
|
||||
{
|
||||
@ -791,15 +790,15 @@ bool DemoApplication::Init()
|
||||
return true;
|
||||
}
|
||||
|
||||
void DemoApplication::RenderFrame(int window_w, int window_h)
|
||||
void DemoApplication::RenderFrame()
|
||||
{
|
||||
// Override RenderFrame without calling super, since we want
|
||||
// to inject code between BeginPaint/EndPaint.
|
||||
// Application::RenderFrame(window_w, window_h);
|
||||
// Application::RenderFrame();
|
||||
|
||||
// Render
|
||||
g_renderer->BeginPaint(window_w, window_h);
|
||||
GetRoot()->InvokePaint(TBWidget::PaintProps());
|
||||
g_renderer->BeginPaint(m_root.GetRect().w, m_root.GetRect().h);
|
||||
m_root.InvokePaint(TBWidget::PaintProps());
|
||||
|
||||
#if defined(TB_RUNTIME_DEBUG_INFO) && defined(TB_IMAGE)
|
||||
// Enable to debug image manager fragments
|
||||
@ -827,24 +826,21 @@ void DemoApplication::RenderFrame(int window_w, int window_h)
|
||||
str.SetFormatted("FPS: %d Frame %d", fps, frame_counter_total);
|
||||
else
|
||||
str.SetFormatted("Frame %d", frame_counter_total);
|
||||
GetRoot()->GetFont()->DrawString(5, 5, TBColor(255, 255, 255), str);
|
||||
m_root.GetFont()->DrawString(5, 5, TBColor(255, 255, 255), str);
|
||||
|
||||
g_renderer->EndPaint();
|
||||
|
||||
// If we want continous updates or got animations running, reinvalidate immediately
|
||||
if (continuous_repaint || TBAnimationManager::HasAnimationsRunning())
|
||||
GetRoot()->Invalidate();
|
||||
m_root.Invalidate();
|
||||
}
|
||||
|
||||
int app_main()
|
||||
void DemoApplication::OnBackendAttached(AppBackend *backend, int width, int height)
|
||||
{
|
||||
application = new DemoApplication();
|
||||
App::OnBackendAttached(backend, width, height);
|
||||
|
||||
ApplicationBackend *application_backend = ApplicationBackend::Create(application, 1280, 700, "Demo");
|
||||
if (!application_backend)
|
||||
return 1;
|
||||
|
||||
tb_core_init(application_backend->GetRenderer(), "resources/language/lng_en.tb.txt");
|
||||
// Load language file
|
||||
g_tb_lng->Load("resources/language/lng_en.tb.txt");
|
||||
|
||||
// Load the default skin, and override skin that contains the graphics specific to the demo.
|
||||
g_tb_skin->Load("resources/default_skin/skin.tb.txt", "Demo/demo01/skin/skin.tb.txt");
|
||||
@ -893,13 +889,9 @@ int app_main()
|
||||
font->RenderGlyphs(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~•·åäöÅÄÖ");
|
||||
|
||||
// Give the root widget a background skin
|
||||
application->GetRoot()->SetSkinBg(TBIDC("background"));
|
||||
|
||||
application->Init();
|
||||
application->Run();
|
||||
application->ShutDown();
|
||||
|
||||
delete application;
|
||||
|
||||
return 0;
|
||||
m_root.SetSkinBg(TBIDC("background"));
|
||||
}
|
||||
|
||||
App *app_create() {
|
||||
return new DemoApplication();
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ TBWidget *AdvancedItemSource::CreateItemWidget(int index, TBSelectItemViewer *vi
|
||||
|
||||
// == ListWindow ==============================================================
|
||||
|
||||
ListWindow::ListWindow(TBSelectItemSource *source)
|
||||
ListWindow::ListWindow(TBWidget *root, TBSelectItemSource *source) : DemoWindow(root)
|
||||
{
|
||||
LoadResourceFile("Demo/demo01/ui_resources/test_select.tb.txt");
|
||||
if (TBSelectList *select = GetWidgetByIDAndType<TBSelectList>("list"))
|
||||
@ -85,8 +85,9 @@ bool ListWindow::OnEvent(const TBWidgetEvent &ev)
|
||||
|
||||
// == AdvancedListWindow ==============================================================
|
||||
|
||||
AdvancedListWindow::AdvancedListWindow(AdvancedItemSource *source)
|
||||
: m_source(source)
|
||||
AdvancedListWindow::AdvancedListWindow(TBWidget *root, AdvancedItemSource *source)
|
||||
: DemoWindow(root)
|
||||
, m_source(source)
|
||||
{
|
||||
LoadResourceFile("Demo/demo01/ui_resources/test_select_advanced.tb.txt");
|
||||
if (TBSelectList *select = GetWidgetByIDAndType<TBSelectList>("list"))
|
||||
|
@ -10,7 +10,7 @@ class AdvancedItemSource;
|
||||
class ListWindow : public DemoWindow
|
||||
{
|
||||
public:
|
||||
ListWindow(TBSelectItemSource *source);
|
||||
ListWindow(TBWidget *root, TBSelectItemSource *source);
|
||||
virtual bool OnEvent(const TBWidgetEvent &ev);
|
||||
};
|
||||
|
||||
@ -18,7 +18,7 @@ public:
|
||||
class AdvancedListWindow : public DemoWindow
|
||||
{
|
||||
public:
|
||||
AdvancedListWindow(AdvancedItemSource *source);
|
||||
AdvancedListWindow(TBWidget *root, AdvancedItemSource *source);
|
||||
virtual bool OnEvent(const TBWidgetEvent &ev);
|
||||
private:
|
||||
AdvancedItemSource *m_source;
|
||||
|
@ -3,35 +3,57 @@
|
||||
|
||||
using namespace tb;
|
||||
|
||||
void Application::Run()
|
||||
// == AppRootWidget ===============================================================================
|
||||
|
||||
void AppRootWidget::OnInvalid()
|
||||
{
|
||||
m_backend->Run();
|
||||
if (m_app->GetBackend())
|
||||
m_app->GetBackend()->OnAppEvent(AppBackend::EVENT_PAINT_REQUEST);
|
||||
}
|
||||
|
||||
bool Application::Init()
|
||||
// == App =========================================================================================
|
||||
|
||||
App::App(int width, int height)
|
||||
: m_backend(nullptr)
|
||||
, m_root(this)
|
||||
{
|
||||
// Set initial size which suggest to the backend which size we want the window to be.
|
||||
m_root.SetRect(TBRect(0, 0, width, height));
|
||||
}
|
||||
|
||||
void App::OnBackendAttached(AppBackend *backend, int width, int height)
|
||||
{
|
||||
m_backend = backend;
|
||||
OnResized(width, height);
|
||||
}
|
||||
|
||||
void App::OnResized(int width, int height)
|
||||
{
|
||||
m_root.SetRect(TBRect(0, 0, width, height));
|
||||
}
|
||||
|
||||
bool App::Init()
|
||||
{
|
||||
TBWidgetsAnimationManager::Init();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Application::ShutDown()
|
||||
void App::ShutDown()
|
||||
{
|
||||
TBWidgetsAnimationManager::Shutdown();
|
||||
delete m_backend;
|
||||
m_backend = nullptr;
|
||||
}
|
||||
|
||||
void Application::Process()
|
||||
void App::Process()
|
||||
{
|
||||
TBAnimationManager::Update();
|
||||
GetRoot()->InvokeProcessStates();
|
||||
GetRoot()->InvokeProcess();
|
||||
m_root.InvokeProcessStates();
|
||||
m_root.InvokeProcess();
|
||||
}
|
||||
|
||||
void Application::RenderFrame(int window_w, int window_h)
|
||||
void App::RenderFrame()
|
||||
{
|
||||
g_renderer->BeginPaint(window_w, window_h);
|
||||
GetRoot()->InvokePaint(TBWidget::PaintProps());
|
||||
g_renderer->BeginPaint(m_root.GetRect().w, m_root.GetRect().h);
|
||||
m_root.InvokePaint(TBWidget::PaintProps());
|
||||
g_renderer->EndPaint();
|
||||
|
||||
// If animations are running, reinvalidate immediately
|
||||
|
@ -1,43 +1,72 @@
|
||||
#ifndef APPLICATION_H
|
||||
#define APPLICATION_H
|
||||
|
||||
/** Called from the platform main function. */
|
||||
int app_main();
|
||||
#include "tb_widgets.h"
|
||||
|
||||
class Application;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This file contains some platform glue that is optional. It may help you set up a TB UI
|
||||
// for a game or application quicker or just function as a sample of how it can be done.
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
/** Backend interface that handles platform window & creating the renderer. */
|
||||
class ApplicationBackend
|
||||
class App;
|
||||
class AppBackend;
|
||||
|
||||
/** The root of widgets in a platform backend. */
|
||||
class AppRootWidget : public tb::TBWidget
|
||||
{
|
||||
public:
|
||||
static ApplicationBackend *Create(Application *app, int width, int height, const char *title);
|
||||
virtual ~ApplicationBackend() {}
|
||||
virtual void Run() = 0;
|
||||
virtual tb::TBWidget *GetRoot() = 0;
|
||||
virtual tb::TBRenderer *GetRenderer() = 0;
|
||||
// For safe typecasting
|
||||
TBOBJECT_SUBCLASS(AppRootWidget, tb::TBWidget);
|
||||
|
||||
AppRootWidget(App *app) : m_app(app) {}
|
||||
virtual void OnInvalid();
|
||||
|
||||
App *GetApp() { return m_app; }
|
||||
private:
|
||||
App *m_app;
|
||||
};
|
||||
|
||||
/** Backend interface that handles platform window & creating the renderer. */
|
||||
class AppBackend
|
||||
{
|
||||
public:
|
||||
enum EVENT {
|
||||
EVENT_PAINT_REQUEST,
|
||||
EVENT_QUIT_REQUEST,
|
||||
EVENT_TITLE_CHANGED
|
||||
};
|
||||
virtual ~AppBackend() {}
|
||||
virtual void OnAppEvent(const EVENT &ev) = 0;
|
||||
};
|
||||
|
||||
/** Application interface, for setting up the application using turbo badger. */
|
||||
class Application
|
||||
class App
|
||||
{
|
||||
public:
|
||||
Application() {}
|
||||
virtual ~Application() {}
|
||||
App(int width, int height);
|
||||
virtual ~App() {}
|
||||
|
||||
tb::TBWidget *GetRoot() { return m_backend->GetRoot(); }
|
||||
virtual const char *GetTitle() const { return ""; }
|
||||
int GetWidth() const { return m_root.GetRect().w; }
|
||||
int GetHeight() const { return m_root.GetRect().h; }
|
||||
|
||||
/** Run the message loop. */
|
||||
void Run();
|
||||
tb::TBWidget *GetRoot() { return &m_root; }
|
||||
AppBackend *GetBackend() { return m_backend; }
|
||||
|
||||
virtual void OnBackendAttached(ApplicationBackend *backend) { m_backend = backend; }
|
||||
virtual void OnBackendAttached(AppBackend *backend, int width, int height);
|
||||
virtual void OnBackendDetached() { m_backend = nullptr; }
|
||||
virtual void OnResized(int width, int height);
|
||||
|
||||
virtual bool Init();
|
||||
virtual void ShutDown();
|
||||
virtual void Process();
|
||||
virtual void RenderFrame(int window_w, int window_h);
|
||||
virtual void RenderFrame();
|
||||
protected:
|
||||
ApplicationBackend *m_backend;
|
||||
AppBackend *m_backend;
|
||||
AppRootWidget m_root;
|
||||
};
|
||||
|
||||
/** Should return new instance of App. */
|
||||
App *app_create();
|
||||
|
||||
#endif // APPLICATION_H
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <string.h>
|
||||
#include "tb_skin.h"
|
||||
#include "tb_system.h"
|
||||
#include "tb_widgets.h"
|
||||
#include "tb_msg.h"
|
||||
#include "renderers/tb_renderer_gl.h"
|
||||
#include "tb_font_renderer.h"
|
||||
@ -25,62 +24,42 @@ bool key_ctrl = false;
|
||||
bool key_shift = false;
|
||||
bool key_super = false;
|
||||
|
||||
class ApplicationBackendGLFW;
|
||||
class AppBackendGLFW;
|
||||
|
||||
void SetBackend(GLFWwindow *window, ApplicationBackendGLFW *backend)
|
||||
void SetBackend(GLFWwindow *window, AppBackendGLFW *backend)
|
||||
{
|
||||
glfwSetWindowUserPointer(window, backend);
|
||||
}
|
||||
|
||||
ApplicationBackendGLFW *GetBackend(GLFWwindow *window)
|
||||
AppBackendGLFW *GetBackend(GLFWwindow *window)
|
||||
{
|
||||
return static_cast<ApplicationBackendGLFW*>(glfwGetWindowUserPointer(window));
|
||||
return static_cast<AppBackendGLFW*>(glfwGetWindowUserPointer(window));
|
||||
}
|
||||
|
||||
// The root of all widgets in a GLFW window.
|
||||
class RootWidget : public TBWidget
|
||||
class AppBackendGLFW : public AppBackend
|
||||
{
|
||||
public:
|
||||
RootWidget(ApplicationBackendGLFW *backend) : m_backend(backend) {}
|
||||
virtual void OnInvalid();
|
||||
private:
|
||||
ApplicationBackendGLFW *m_backend;
|
||||
};
|
||||
bool Init(App *app);
|
||||
AppBackendGLFW() : m_app(nullptr)
|
||||
, m_renderer(nullptr)
|
||||
, mainWindow(0)
|
||||
, m_has_pending_update(false)
|
||||
, m_quit_requested(false) {}
|
||||
~AppBackendGLFW();
|
||||
|
||||
class ApplicationBackendGLFW : public ApplicationBackend
|
||||
{
|
||||
public:
|
||||
bool Init(Application *app, int width, int height, const char *title);
|
||||
ApplicationBackendGLFW() : m_application(nullptr),
|
||||
m_renderer(nullptr),
|
||||
m_root(this),
|
||||
mainWindow(0),
|
||||
has_pending_update(false) {}
|
||||
~ApplicationBackendGLFW();
|
||||
virtual void OnAppEvent(const EVENT &ev);
|
||||
|
||||
virtual void Run();
|
||||
virtual TBWidget *GetRoot() { return &m_root; }
|
||||
virtual TBRenderer *GetRenderer() { return m_renderer; }
|
||||
TBWidget *GetRoot() const { return m_app->GetRoot(); }
|
||||
int GetWidth() const { return m_app->GetWidth(); }
|
||||
int GetHeight() const { return m_app->GetHeight(); }
|
||||
|
||||
int GetWidth() const { return m_root.GetRect().w; }
|
||||
int GetHeight() const { return m_root.GetRect().h; }
|
||||
|
||||
Application *m_application;
|
||||
App *m_app;
|
||||
TBRendererGL *m_renderer;
|
||||
RootWidget m_root;
|
||||
GLFWwindow *mainWindow;
|
||||
bool has_pending_update;
|
||||
bool m_has_pending_update;
|
||||
bool m_quit_requested;
|
||||
};
|
||||
|
||||
void RootWidget::OnInvalid()
|
||||
{
|
||||
if (!m_backend->has_pending_update)
|
||||
{
|
||||
m_backend->has_pending_update = true;
|
||||
glfwWakeUpMsgLoop(m_backend->mainWindow);
|
||||
}
|
||||
}
|
||||
|
||||
MODIFIER_KEYS GetModifierKeys()
|
||||
{
|
||||
MODIFIER_KEYS code = TB_MODIFIER_NONE;
|
||||
@ -359,33 +338,32 @@ void TBSystem::RescheduleTimer(double fire_time)
|
||||
|
||||
static void window_refresh_callback(GLFWwindow *window)
|
||||
{
|
||||
ApplicationBackendGLFW *backend = GetBackend(window);
|
||||
AppBackendGLFW *backend = GetBackend(window);
|
||||
|
||||
backend->m_application->Process();
|
||||
|
||||
backend->has_pending_update = false;
|
||||
backend->m_app->Process();
|
||||
|
||||
backend->m_has_pending_update = false;
|
||||
// Bail out if we get here with invalid dimensions.
|
||||
// This may happen when minimizing windows (GLFW 3.0.4, Windows 8.1).
|
||||
if (backend->GetWidth() == 0 || backend->GetHeight() == 0)
|
||||
return;
|
||||
|
||||
backend->m_application->RenderFrame(backend->GetWidth(), backend->GetHeight());
|
||||
backend->m_app->RenderFrame();
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
}
|
||||
|
||||
static void window_size_callback(GLFWwindow *window, int w, int h)
|
||||
{
|
||||
ApplicationBackendGLFW *backend = GetBackend(window);
|
||||
if (backend->GetRoot())
|
||||
backend->GetRoot()->SetRect(TBRect(0, 0, w, h));
|
||||
AppBackendGLFW *backend = GetBackend(window);
|
||||
if (backend->m_app)
|
||||
backend->m_app->OnResized(w, h);
|
||||
}
|
||||
|
||||
#if (GLFW_VERSION_MAJOR >= 3 && GLFW_VERSION_MINOR >= 1)
|
||||
static void drop_callback(GLFWwindow *window, int count, const char **files_utf8)
|
||||
{
|
||||
ApplicationBackendGLFW *backend = GetBackend(window);
|
||||
AppBackendGLFW *backend = GetBackend(window);
|
||||
TBWidget *target = TBWidget::hovered_widget;
|
||||
if (!target)
|
||||
target = TBWidget::focused_widget;
|
||||
@ -401,21 +379,13 @@ static void drop_callback(GLFWwindow *window, int count, const char **files_utf8
|
||||
}
|
||||
#endif
|
||||
|
||||
//static
|
||||
ApplicationBackend *ApplicationBackend::Create(Application *app, int width, int height, const char *title)
|
||||
{
|
||||
ApplicationBackendGLFW *backend = new ApplicationBackendGLFW();
|
||||
if (backend && backend->Init(app, width, height, title))
|
||||
return backend;
|
||||
delete backend;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ApplicationBackendGLFW::Init(Application *app, int width, int height, const char *title)
|
||||
bool AppBackendGLFW::Init(App *app)
|
||||
{
|
||||
if (!glfwInit())
|
||||
return false;
|
||||
mainWindow = glfwCreateWindow(width, height, title, NULL, NULL);
|
||||
const int width = app->GetWidth() > 0 ? app->GetWidth() : 1920;
|
||||
const int height = app->GetHeight() > 0 ? app->GetHeight() : 1080;
|
||||
mainWindow = glfwCreateWindow(width, height, app->GetTitle(), NULL, NULL);
|
||||
if (!mainWindow)
|
||||
{
|
||||
glfwTerminate();
|
||||
@ -442,13 +412,6 @@ bool ApplicationBackendGLFW::Init(Application *app, int width, int height, const
|
||||
glfwSetDropCallback(mainWindow, drop_callback);
|
||||
#endif
|
||||
|
||||
m_renderer = new TBRendererGL();
|
||||
m_root.SetRect(TBRect(0, 0, width, height));
|
||||
|
||||
// Create the application object for our demo
|
||||
m_application = app;
|
||||
m_application->OnBackendAttached(this);
|
||||
|
||||
#ifdef TB_TARGET_MACOSX
|
||||
// Put is in the root of the repository so the demo resources are found.
|
||||
char exec_path[2048];
|
||||
@ -461,13 +424,20 @@ bool ApplicationBackendGLFW::Init(Application *app, int width, int height, const
|
||||
}
|
||||
#endif
|
||||
|
||||
m_renderer = new TBRendererGL();
|
||||
tb_core_init(m_renderer);
|
||||
|
||||
// Create the App object for our demo
|
||||
m_app = app;
|
||||
m_app->OnBackendAttached(this, width, height);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ApplicationBackendGLFW::~ApplicationBackendGLFW()
|
||||
AppBackendGLFW::~AppBackendGLFW()
|
||||
{
|
||||
m_application->OnBackendDetached();
|
||||
m_application = nullptr;
|
||||
m_app->OnBackendDetached();
|
||||
m_app = nullptr;
|
||||
|
||||
tb_core_shutdown();
|
||||
|
||||
@ -476,14 +446,54 @@ ApplicationBackendGLFW::~ApplicationBackendGLFW()
|
||||
delete m_renderer;
|
||||
}
|
||||
|
||||
void ApplicationBackendGLFW::Run()
|
||||
void AppBackendGLFW::OnAppEvent(const EVENT &ev)
|
||||
{
|
||||
do
|
||||
switch (ev)
|
||||
{
|
||||
if (has_pending_update)
|
||||
window_refresh_callback(mainWindow);
|
||||
glfwWaitMsgLoop(mainWindow);
|
||||
} while (!glfwWindowShouldClose(mainWindow));
|
||||
case EVENT_PAINT_REQUEST:
|
||||
if (!m_has_pending_update)
|
||||
{
|
||||
m_has_pending_update = true;
|
||||
glfwWakeUpMsgLoop(mainWindow);
|
||||
}
|
||||
break;
|
||||
case EVENT_QUIT_REQUEST:
|
||||
m_quit_requested = true;
|
||||
glfwWakeUpMsgLoop(mainWindow);
|
||||
break;
|
||||
case EVENT_TITLE_CHANGED:
|
||||
glfwSetWindowTitle(mainWindow, m_app->GetTitle());
|
||||
break;
|
||||
default:
|
||||
assert(!"Unhandled app event!");
|
||||
}
|
||||
}
|
||||
|
||||
bool port_main() {
|
||||
App *app = app_create();
|
||||
|
||||
AppBackendGLFW *backend = new AppBackendGLFW();
|
||||
if (!backend || !backend->Init(app))
|
||||
return false;
|
||||
|
||||
bool success = app->Init();
|
||||
if (success) {
|
||||
// Main loop
|
||||
do
|
||||
{
|
||||
if (backend->m_has_pending_update)
|
||||
window_refresh_callback(backend->mainWindow);
|
||||
glfwWaitMsgLoop(backend->mainWindow);
|
||||
} while (!backend->m_quit_requested && !glfwWindowShouldClose(backend->mainWindow));
|
||||
|
||||
app->ShutDown();
|
||||
}
|
||||
|
||||
delete backend;
|
||||
|
||||
delete app;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
#ifdef TB_TARGET_WINDOWS
|
||||
@ -500,16 +510,16 @@ int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
|
||||
// Crank up windows timer resolution (it's awfully low res normally). Note: This affects battery time!
|
||||
timeBeginPeriod(1);
|
||||
int ret = app_main();
|
||||
bool success = port_main();
|
||||
timeEndPeriod(1);
|
||||
return ret;
|
||||
return success ? 0 : 1;
|
||||
}
|
||||
|
||||
#else // TB_TARGET_WINDOWS
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
return app_main();
|
||||
return port_main() ? 0 : 1;
|
||||
}
|
||||
|
||||
#endif // !TB_TARGET_WINDOWS
|
||||
|
@ -21,12 +21,11 @@ TBWidgetsReader *g_widgets_reader = nullptr;
|
||||
TBLanguage *g_tb_lng = nullptr;
|
||||
TBFontManager *g_font_manager = nullptr;
|
||||
|
||||
bool tb_core_init(TBRenderer *renderer, const char *lng_file)
|
||||
bool tb_core_init(TBRenderer *renderer)
|
||||
{
|
||||
TBDebugPrint("Initiating Turbo Badger - version %s\n", TB_VERSION_STR);
|
||||
g_renderer = renderer;
|
||||
g_tb_lng = new TBLanguage;
|
||||
g_tb_lng->Load(lng_file);
|
||||
g_font_manager = new TBFontManager();
|
||||
g_tb_skin = new TBSkin();
|
||||
g_widgets_reader = TBWidgetsReader::Create();
|
||||
|
@ -52,7 +52,7 @@ extern TBLanguage *g_tb_lng;
|
||||
extern TBFontManager *g_font_manager;
|
||||
|
||||
/** Initialize turbo badger. Call this before using any turbo badger API. */
|
||||
bool tb_core_init(TBRenderer *renderer, const char *lng_file);
|
||||
bool tb_core_init(TBRenderer *renderer);
|
||||
|
||||
/** Shutdown turbo badger. Call this after deleting the last widget, to free turbo badger internals. */
|
||||
void tb_core_shutdown();
|
||||
|
Loading…
Reference in New Issue
Block a user