Escher: Add the App and Responder classes

Change-Id: Ia11d13132b3bd5aa085787556b8e198089bcb0fa
This commit is contained in:
Romain Goyet
2016-05-30 13:27:17 +02:00
parent 97be08027f
commit 4ed72f60df
11 changed files with 220 additions and 14 deletions

View File

@@ -1,9 +1,9 @@
extern "C" {
#include <assert.h>
#include <escher.h>
#include <stdlib.h>
#include <ion.h>
}
#include <escher.h>
/*
class App {
@@ -66,6 +66,37 @@ void MyTextView::drawRect(KDRect frame) {
}
*/
class GraphView : public ChildlessView {
public:
void drawRect(KDRect rect) const override;
};
void GraphView::drawRect(KDRect rect) const {
KDColor bg = 0x99;
KDFillRect(rect, bg);
for (KDCoordinate x=rect.x; x<rect.x+rect.width; x++) {
KDSetPixel((KDPoint){x, (KDCoordinate)(x*x/rect.width)}, 0x00);
}
}
class GraphViewController : public ViewController {
public:
using ViewController::ViewController;
View * view() override;
char * title() override;
private:
GraphView m_view;
};
View * GraphViewController::view() {
return &m_view;
}
char * GraphViewController::title() {
return "Graph";
}
class DemoViewController : public ViewController {
public:
DemoViewController(KDColor c);
@@ -88,6 +119,28 @@ char * DemoViewController::title() {
return "HELLO";
}
class MyTestApp : public App {
public:
MyTestApp();
protected:
ViewController * rootViewController() override;
private:
DemoViewController m_demoViewController;
GraphViewController m_graphViewController;
TabViewController m_tabViewController;
};
MyTestApp::MyTestApp() :
m_demoViewController(DemoViewController(0x55)),
m_graphViewController(GraphViewController()),
m_tabViewController(&m_demoViewController, &m_graphViewController)
{
}
ViewController * MyTestApp::rootViewController() {
return &m_tabViewController;
}
void ion_app() {
//KDDrawString("Hello", {0,0}, 0);
@@ -95,25 +148,23 @@ void ion_app() {
//KDFillRect({0,0,100,100}, 0x55);
//KDFillRect({100,100,100,100}, 0x99);
Window window;
DemoViewController v1 = DemoViewController(0x55);
DemoViewController v2 = DemoViewController(0x99);
ViewController * tabs[]= { &v1, &v2};
TabViewController tabVC = TabViewController(tabs, 2);
window.setFrame({{0,0}, {200, 200}});
window.setSubview(tabVC.view(), 0);
tabVC.view()->setFrame(window.bounds());
MyTestApp myApp = MyTestApp();
myApp.run();
/*
int i = 0;
while(true) {
#if ESCHER_VIEW_LOGGING
std::cout << window << std::endl;
#endif
tabVC.setActiveTab(i);
ion_event_t event = ion_get_event();
tabVC.handleKeyEvent(event);
i = (i+1)%2;
}
*/

View File

@@ -1,7 +1,9 @@
SFLAGS += -Iescher/include
objs += $(addprefix escher/src/,\
app.o\
childless_view.o\
responder.o\
solid_color_view.o\
tab_view.o\
tab_view_cell.o\

View File

@@ -1,6 +1,8 @@
#ifndef ESCHER_H
#define ESCHER_H
#include <escher/app.h>
#include <escher/responder.h>
#include <escher/solid_color_view.h>
#include <escher/text_view.h>
#include <escher/tab_view_controller.h>

View File

@@ -0,0 +1,28 @@
#ifndef ESCHER_APP_H
#define ESCHER_APP_H
#include <escher/responder.h>
#include <escher/view_controller.h>
class App {
public:
void run();
void focus(Responder * responder);
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,20 @@
#ifndef ESCHER_RESPONDER_H
#define ESCHER_RESPONDER_H
extern "C" {
#include <ion.h>
}
class Responder {
public:
Responder();
virtual bool handleEvent(ion_event_t event); // Default implementation does nothing
virtual void setFocused(bool focused); // Default implementation does nothing. Used by subclasses to know when active or not
Responder * parentResponder();
protected:
void setParentResponder(Responder * responder);
private:
Responder * m_parentResponder;
};
#endif

View File

@@ -6,7 +6,8 @@
class TabViewController : public ViewController {
public:
TabViewController(ViewController ** children, uint8_t numberOfChildren);
TabViewController(ViewController * one, ViewController * two);
//TabViewController(ViewController ** children, uint8_t numberOfChildren);
View * view() override;
void handleKeyEvent(int key) override;
@@ -14,6 +15,7 @@ public:
uint8_t numberOfTabs();
const char * tabName(uint8_t index);
bool handleEvent(ion_event_t event) override;
private:
class ContentView : public View {
public:
@@ -36,7 +38,8 @@ private:
ContentView m_view;
ViewController ** m_children;
static constexpr uint8_t k_maxNumberOfChildren = 4;
ViewController * m_children[k_maxNumberOfChildren];
uint8_t m_numberOfChildren;
uint8_t m_activeChildIndex;
};

View File

@@ -12,8 +12,9 @@ extern "C" {
*/
#include <escher/view.h>
#include <escher/responder.h>
class ViewController {
class ViewController : public Responder {
public:
ViewController();
virtual char * title();

43
escher/src/app.cpp Normal file
View File

@@ -0,0 +1,43 @@
#include <escher/app.h>
#include <escher/window.h>
extern "C" {
#include <ion.h>
}
void App::run() {
Window window;
window.setFrame({{0,0}, {200, 200}});
View * rootView = rootViewController()->view();
focus(rootViewController());
window.setSubview(rootView, 0);
rootView->setFrame(window.bounds());
while (true) {
ion_event_t event = ion_get_event(); // This is a blocking call
dispatchEvent(event);
}
}
void App::dispatchEvent(ion_event_t event) {
Responder * responder = m_focusedResponder;
bool didHandleEvent = false;
while (responder) {
didHandleEvent = responder->handleEvent(event);
if (didHandleEvent) {
break;
}
responder = responder->parentResponder();
}
}
void App::focus(Responder * responder) {
if (m_focusedResponder) {
m_focusedResponder->setFocused(false);
}
m_focusedResponder = responder;
if (m_focusedResponder) {
m_focusedResponder->setFocused(true);
}
}

21
escher/src/responder.cpp Normal file
View File

@@ -0,0 +1,21 @@
#include <escher/responder.h>
Responder::Responder() :
m_parentResponder(nullptr)
{
}
Responder * Responder::parentResponder() {
return m_parentResponder;
}
void Responder::setParentResponder(Responder * responder) {
m_parentResponder = responder;
}
bool Responder::handleEvent(ion_event_t event) {
return false;
}
void Responder::setFocused(bool focused) {
}

View File

@@ -58,6 +58,39 @@ const char * TabViewController::ContentView::className() const {
}
#endif
TabViewController::TabViewController(ViewController * one, ViewController * two) :
ViewController(),
m_numberOfChildren(2),
m_activeChildIndex(-1)
{
m_children[0] = one;
m_children[1] = two;
// TODO: This should be lazy loaded!
// So this code should live in view()
for (int i=0; i<m_numberOfChildren; i++) {
m_view.m_tabView.addTabNamed(m_children[i]->title());
}
}
bool TabViewController::handleEvent(ion_event_t event) {
switch(event) {
case LEFT_ARROW:
if (m_activeChildIndex > 0) {
setActiveTab(m_activeChildIndex-1);
}
return true;
case RIGHT_ARROW:
if (m_activeChildIndex < m_numberOfChildren-1) {
setActiveTab(m_activeChildIndex+1);
}
return true;
default:
return false;
}
}
/*
TabViewController::TabViewController(ViewController ** children, uint8_t numberOfChildren) :
m_children(children),
m_numberOfChildren(numberOfChildren),
@@ -67,6 +100,7 @@ TabViewController::TabViewController(ViewController ** children, uint8_t numberO
m_view.m_tabView.addTabNamed(children[i]->title());
}
}
*/
void TabViewController::setActiveTab(uint8_t i) {
if (i == m_activeChildIndex) {

View File

@@ -1,6 +1,7 @@
#include <escher/view_controller.h>
ViewController::ViewController() {
ViewController::ViewController() :
Responder() {
}
char * ViewController::title() {