mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-18 21:30:38 +01:00
Escher: Add the App and Responder classes
Change-Id: Ia11d13132b3bd5aa085787556b8e198089bcb0fa
This commit is contained in:
@@ -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;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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\
|
||||
|
||||
@@ -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>
|
||||
|
||||
28
escher/include/escher/app.h
Normal file
28
escher/include/escher/app.h
Normal 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
|
||||
20
escher/include/escher/responder.h
Normal file
20
escher/include/escher/responder.h
Normal 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
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
43
escher/src/app.cpp
Normal 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
21
escher/src/responder.cpp
Normal 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) {
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <escher/view_controller.h>
|
||||
|
||||
ViewController::ViewController() {
|
||||
ViewController::ViewController() :
|
||||
Responder() {
|
||||
}
|
||||
|
||||
char * ViewController::title() {
|
||||
|
||||
Reference in New Issue
Block a user