[Escher] Add a Container that lets us run multiple apps

Change-Id: I674348ed0ff48934eb248dc48735f4ba13c34692
This commit is contained in:
Romain Goyet
2016-08-12 15:15:28 +02:00
parent 09ac89a47c
commit 7789123913
15 changed files with 169 additions and 47 deletions

View File

@@ -2,6 +2,7 @@ include apps/graph/Makefile
#include apps/picview/Makefile
app_objs += $(addprefix apps/,\
apps_container.o\
main.o\
)

34
apps/apps_container.cpp Normal file
View File

@@ -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];
};

27
apps/apps_container.h Normal file
View File

@@ -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

View File

@@ -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();
}

View File

@@ -2,7 +2,7 @@
PicViewApp::PicViewApp() :
App(),
m_picViewController(PicViewController())
m_picViewController(PicViewController(this))
{
}

View File

@@ -1,7 +1,7 @@
#include "picview_controller.h"
PicViewController::PicViewController() :
ViewController(),
PicViewController::PicViewController(Responder * parentResponder) :
ViewController(parentResponder),
m_view(PicView())
{
}

View File

@@ -6,7 +6,7 @@
class PicViewController : public ViewController {
public:
PicViewController();
PicViewController(Responder * parentResponder);
View * view() override;
private:
PicView m_view;

View File

@@ -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\

View File

@@ -2,6 +2,7 @@
#define ESCHER_H
#include <escher/app.h>
#include <escher/container.h>
#include <escher/responder.h>
#include <escher/scroll_view.h>
#include <escher/scroll_view_indicator.h>

View File

@@ -4,26 +4,25 @@
#include <escher/responder.h>
#include <escher/view_controller.h>
/* 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

View File

@@ -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 <escher/app.h>
#include <escher/window.h>
extern "C" {
#include <ion.h>
}
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

View File

@@ -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

View File

@@ -2,6 +2,7 @@
#include <escher/window.h>
extern "C" {
#include <ion.h>
#include <assert.h>
}
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) {

37
escher/src/container.cpp Normal file
View File

@@ -0,0 +1,37 @@
#include <escher/container.h>
extern "C" {
#include <ion.h>
}
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();
}
}

View File

@@ -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;
}