diff --git a/apps/Makefile b/apps/Makefile index 7561b2c76..e9b6d647a 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -2,6 +2,7 @@ include apps/graph/Makefile #include apps/picview/Makefile app_objs += $(addprefix apps/,\ + apps_container.o\ main.o\ ) diff --git a/apps/apps_container.cpp b/apps/apps_container.cpp new file mode 100644 index 000000000..d9845b3d2 --- /dev/null +++ b/apps/apps_container.cpp @@ -0,0 +1,34 @@ +#include "apps_container.h" + +AppsContainer::AppsContainer() : + Container() +{ +} + +bool AppsContainer::handleEvent(ion_event_t event) { + if (event == F1) { +#if USE_PIC_VIEW_APP + if (activeApp() == &m_picViewApp) { + Container::switchTo(&m_graphApp); + } else { + Container::switchTo(&m_picViewApp); + } +#endif + return true; + } + return false; +} + +void AppsContainer::switchTo(AppId appId) { + Container::switchTo(appWithId(appId)); +} + +App * AppsContainer::appWithId(AppId appId) { + App * apps[] = { + &m_graphApp +#if USE_PIC_VIEW_APP + , &m_picViewApp +#endif + }; + return apps[(int)appId]; +}; diff --git a/apps/apps_container.h b/apps/apps_container.h new file mode 100644 index 000000000..1591add00 --- /dev/null +++ b/apps/apps_container.h @@ -0,0 +1,27 @@ +#ifndef APPS_CONTAINER_H +#define APPS_CONTAINER_H + +#include "graph/graph_app.h" +#define USE_PIC_VIEW_APP 0 +#if USE_PIC_VIEW_APP +#include "picview/picview_app.h" +#endif + +class AppsContainer : public Container { +public: + AppsContainer(); + enum class AppId { + Graph = 0, + PicView = 1 + }; + void switchTo(AppId appId); + bool handleEvent(ion_event_t event) override; +private: + App * appWithId(AppId appId); + GraphApp m_graphApp; +#if USE_PIC_VIEW_APP + PicViewApp m_picViewApp; +#endif +}; + +#endif diff --git a/apps/main.cpp b/apps/main.cpp index f00a057ae..a253a4426 100644 --- a/apps/main.cpp +++ b/apps/main.cpp @@ -1,15 +1,7 @@ -#include "graph/graph_app.h" - -#define USE_PIC_VIEW_APP 0 -#if USE_PIC_VIEW_APP -#include "picview/picview_app.h" -#endif +#include "apps_container.h" void ion_app() { -#if USE_PIC_VIEW_APP - PicViewApp picViewApp = PicViewApp(); - picViewApp.run(); -#endif - GraphApp graphApp = GraphApp(); - graphApp.run(); + AppsContainer container; + container.switchTo(AppsContainer::AppId::Graph); + container.run(); } diff --git a/apps/picview/picview_app.cpp b/apps/picview/picview_app.cpp index 9b28543c2..7d7915a72 100644 --- a/apps/picview/picview_app.cpp +++ b/apps/picview/picview_app.cpp @@ -2,7 +2,7 @@ PicViewApp::PicViewApp() : App(), - m_picViewController(PicViewController()) + m_picViewController(PicViewController(this)) { } diff --git a/apps/picview/picview_controller.cpp b/apps/picview/picview_controller.cpp index 5da1dc835..19025e444 100644 --- a/apps/picview/picview_controller.cpp +++ b/apps/picview/picview_controller.cpp @@ -1,7 +1,7 @@ #include "picview_controller.h" -PicViewController::PicViewController() : - ViewController(), +PicViewController::PicViewController(Responder * parentResponder) : + ViewController(parentResponder), m_view(PicView()) { } diff --git a/apps/picview/picview_controller.h b/apps/picview/picview_controller.h index fb70d093f..846596aa2 100644 --- a/apps/picview/picview_controller.h +++ b/apps/picview/picview_controller.h @@ -6,7 +6,7 @@ class PicViewController : public ViewController { public: - PicViewController(); + PicViewController(Responder * parentResponder); View * view() override; private: PicView m_view; diff --git a/escher/Makefile b/escher/Makefile index 069d9e9b3..d9e1d1b2d 100644 --- a/escher/Makefile +++ b/escher/Makefile @@ -3,6 +3,7 @@ SFLAGS += -Iescher/include objs += $(addprefix escher/src/,\ app.o\ childless_view.o\ + container.o\ responder.o\ scroll_view.o\ scroll_view_indicator.o\ diff --git a/escher/include/escher.h b/escher/include/escher.h index b97e6f615..13cfda6cc 100644 --- a/escher/include/escher.h +++ b/escher/include/escher.h @@ -2,6 +2,7 @@ #define ESCHER_H #include +#include #include #include #include diff --git a/escher/include/escher/app.h b/escher/include/escher/app.h index 2c5e9a83a..eeb4055e8 100644 --- a/escher/include/escher/app.h +++ b/escher/include/escher/app.h @@ -4,26 +4,25 @@ #include #include +/* An app is fed events and outputs drawing calls. + * + * To achieve this, it uses a View hierarchy, and modifies it according to the + * events received. The View hierarchy keeps a memory of the area that needs to + * be redrawn depending on how it's been modified. + * + * Multiple App can exist at once. + * */ + class App : public Responder { public: App(); - void run(); + void setWindow(Window * window); void focus(Responder * responder); + void processEvent(ion_event_t event); protected: virtual ViewController * rootViewController() = 0; private: - void dispatchEvent(ion_event_t event); Responder * m_focusedResponder; }; -/* - -void handleEvent(event) { - // BACK: I want to do stuff! - 1/ Reset my text to what it was "before" - 2/ dismiss - dismiss = app->focus(parentResponder()); -} -*/ - #endif diff --git a/escher/include/escher/container.h b/escher/include/escher/container.h new file mode 100644 index 000000000..0127974bb --- /dev/null +++ b/escher/include/escher/container.h @@ -0,0 +1,32 @@ +#ifndef ESCHER_CONTAINER_H +#define ESCHER_CONTAINER_H + +/* Container is the entry point of a program using Escher. + * + * A container contains one or multiple App, and is responsible for running them + * together. Currently Container displays a single App fullscreen, but can + * switch to any other App. + * + * When writing an Escher program, you typically subclass Container, and your + * subclass owns one or more App. You then call "run()" on your container. */ + +#include +#include +extern "C" { +#include +} + +class Container { +public: + Container(); + void run(); + App * activeApp(); + virtual bool handleEvent(ion_event_t event); +protected: + void switchTo(App * app); +private: + App * m_activeApp; + Window m_window; +}; + +#endif diff --git a/escher/include/escher/tab_view_controller.h b/escher/include/escher/tab_view_controller.h index ca5683acd..2acd9ccb7 100644 --- a/escher/include/escher/tab_view_controller.h +++ b/escher/include/escher/tab_view_controller.h @@ -40,7 +40,7 @@ private: static constexpr uint8_t k_maxNumberOfChildren = 4; ViewController * m_children[k_maxNumberOfChildren]; uint8_t m_numberOfChildren; - uint8_t m_activeChildIndex; + int8_t m_activeChildIndex; }; #endif diff --git a/escher/src/app.cpp b/escher/src/app.cpp index 9cd5d4081..acaa38a4a 100644 --- a/escher/src/app.cpp +++ b/escher/src/app.cpp @@ -2,6 +2,7 @@ #include extern "C" { #include +#include } App::App() : @@ -10,26 +11,21 @@ App::App() : { } -void App::run() { - Window window; - window.setFrame(KDRect(0, 0, ION_SCREEN_WIDTH, ION_SCREEN_HEIGHT)); - View * rootView = rootViewController()->view(); - - focus(rootViewController()); - - window.setContentView(rootView); - rootView->setFrame(window.bounds()); - - window.redraw(); - - while (true) { - ion_event_t event = ion_get_event(); // This is a blocking call - dispatchEvent(event); - window.redraw(); +void App::setWindow(Window * window) { + ViewController * controller = rootViewController(); + View * view = controller->view(); + if (m_focusedResponder == nullptr) { + focus(controller); } + assert(controller->app() == this); + + window->setContentView(view); + view->setFrame(window->bounds()); + + window->redraw(); } -void App::dispatchEvent(ion_event_t event) { +void App::processEvent(ion_event_t event) { Responder * responder = m_focusedResponder; bool didHandleEvent = false; while (responder) { diff --git a/escher/src/container.cpp b/escher/src/container.cpp new file mode 100644 index 000000000..b2f31ba90 --- /dev/null +++ b/escher/src/container.cpp @@ -0,0 +1,37 @@ +#include +extern "C" { +#include +} + +Container::Container() : + m_activeApp(nullptr) +{ +} + +void Container::switchTo(App * app) { + m_activeApp = app; + m_activeApp->setWindow(&m_window); + m_window.redraw(); +} + +App * Container::activeApp() { + return m_activeApp; +} + +bool Container::handleEvent(ion_event_t event) { + return false; +} + +void Container::run() { + m_window.setFrame(KDRect(0, 0, ION_SCREEN_WIDTH, ION_SCREEN_HEIGHT)); + m_window.redraw(); + + while (true) { + ion_event_t event = ion_get_event(); // This is a blocking call + if (handleEvent(event)) { + continue; + } + m_activeApp->processEvent(event); + m_window.redraw(); + } +} diff --git a/escher/src/tab_view_controller.cpp b/escher/src/tab_view_controller.cpp index af029930c..b38752139 100644 --- a/escher/src/tab_view_controller.cpp +++ b/escher/src/tab_view_controller.cpp @@ -116,7 +116,9 @@ void TabViewController::setActiveTab(uint8_t i) { View * TabViewController::view() { // We're asked for a view! // Let's populate our tabview - setActiveTab(0); + if (m_activeChildIndex < 0) { + setActiveTab(0); + } return &m_view; }