mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-24 08:10:50 +01:00
[escher] Create dynamic view controller
Change-Id: Ic8fe6d095666aa7af76c8d328b0bf83342a09453
This commit is contained in:
@@ -8,6 +8,7 @@ objs += $(addprefix escher/src/,\
|
||||
button_row_controller.o\
|
||||
chevron_view.o\
|
||||
container.o\
|
||||
dynamic_view_controller.o\
|
||||
editable_text_cell.o\
|
||||
even_odd_cell.o\
|
||||
even_odd_buffer_text_cell.o\
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <escher/button_row_controller.h>
|
||||
#include <escher/chevron_view.h>
|
||||
#include <escher/container.h>
|
||||
#include <escher/dynamic_view_controller.h>
|
||||
#include <escher/editable_text_cell.h>
|
||||
#include <escher/even_odd_cell.h>
|
||||
#include <escher/even_odd_buffer_text_cell.h>
|
||||
|
||||
@@ -15,6 +15,8 @@ public:
|
||||
void didBecomeFirstResponder() override;
|
||||
void viewWillAppear() override;
|
||||
void viewDidDisappear() override;
|
||||
void loadView() override;
|
||||
void unloadView() override;
|
||||
private:
|
||||
class ContentView : public View {
|
||||
public:
|
||||
|
||||
@@ -28,6 +28,8 @@ public:
|
||||
bool setSelectedButton(int selectedButton);
|
||||
void viewWillAppear() override;
|
||||
void viewDidDisappear() override;
|
||||
void loadView() override;
|
||||
void unloadView() override;
|
||||
private:
|
||||
class ContentView : public View {
|
||||
public:
|
||||
@@ -64,6 +66,10 @@ public:
|
||||
virtual Button * buttonAtIndex(int index, ButtonRowController::Position position) const;
|
||||
ButtonRowController * header();
|
||||
ButtonRowController * footer();
|
||||
/* By default these two functions do not load anything. They should be
|
||||
* overrided if the delegate dynamically allocate the button views. */
|
||||
virtual void loadButtonView();
|
||||
virtual void unloadButtonView();
|
||||
private:
|
||||
ButtonRowController * m_header;
|
||||
ButtonRowController * m_footer;
|
||||
|
||||
21
escher/include/escher/dynamic_view_controller.h
Normal file
21
escher/include/escher/dynamic_view_controller.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef ESCHER_DYNAMIC_VIEW_CONTROLLER_H
|
||||
#define ESCHER_DYNAMIC_VIEW_CONTROLLER_H
|
||||
|
||||
#include <escher/view_controller.h>
|
||||
|
||||
/* Dynamic view controllers dynamically construct their views when appearring and
|
||||
* delete them when disappearing. */
|
||||
|
||||
class DynamicViewController : public ViewController {
|
||||
public:
|
||||
DynamicViewController(Responder * parentResponder);
|
||||
~DynamicViewController();
|
||||
View * view() override;
|
||||
virtual void loadView() override;
|
||||
virtual void unloadView() override;
|
||||
private:
|
||||
virtual View * createView() = 0;
|
||||
View * m_view;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -17,6 +17,8 @@ public:
|
||||
bool isDisplayingModal();
|
||||
void viewWillAppear() override;
|
||||
void viewDidDisappear() override;
|
||||
void loadView() override;
|
||||
void unloadView() override;
|
||||
private:
|
||||
class ContentView : public View {
|
||||
public:
|
||||
|
||||
@@ -23,6 +23,8 @@ public:
|
||||
void didBecomeFirstResponder() override;
|
||||
void viewWillAppear() override;
|
||||
void viewDidDisappear() override;
|
||||
void loadView() override;
|
||||
void unloadView() override;
|
||||
private:
|
||||
class ControllerView : public View {
|
||||
public:
|
||||
|
||||
@@ -16,9 +16,12 @@ public:
|
||||
const char * tabName(uint8_t index);
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
void didBecomeFirstResponder() override;
|
||||
void didEnterResponderChain(Responder * previousResponder) override;
|
||||
void willResignFirstResponder() override;
|
||||
void viewWillAppear() override;
|
||||
void viewDidDisappear() override;
|
||||
void loadView() override;
|
||||
void unloadView() override;
|
||||
private:
|
||||
class ContentView : public View {
|
||||
public:
|
||||
|
||||
@@ -25,6 +25,7 @@ class View {
|
||||
friend class Window;
|
||||
public:
|
||||
View();
|
||||
virtual ~View();
|
||||
|
||||
/* The drawRect method should be implemented by each View subclass. In a
|
||||
* typical drawRect implementation, a subclass will make drawing calls to the
|
||||
|
||||
@@ -32,6 +32,8 @@ public:
|
||||
ViewController(Responder * parentResponder);
|
||||
virtual const char * title();
|
||||
virtual View * view() = 0;
|
||||
virtual void loadView();
|
||||
virtual void unloadView();
|
||||
virtual void viewWillAppear();
|
||||
virtual void viewDidDisappear();
|
||||
};
|
||||
|
||||
@@ -86,3 +86,11 @@ void AlternateEmptyViewController::viewDidDisappear() {
|
||||
m_contentView.mainViewController()->viewDidDisappear();
|
||||
}
|
||||
}
|
||||
|
||||
void AlternateEmptyViewController::loadView() {
|
||||
m_contentView.mainViewController()->loadView();
|
||||
}
|
||||
|
||||
void AlternateEmptyViewController::unloadView() {
|
||||
m_contentView.mainViewController()->unloadView();
|
||||
}
|
||||
|
||||
@@ -91,13 +91,12 @@ const Container * App::container() const {
|
||||
}
|
||||
|
||||
void App::didBecomeActive(Window * window) {
|
||||
m_modalViewController.loadView();
|
||||
View * view = m_modalViewController.view();
|
||||
assert(m_modalViewController.app() == this);
|
||||
window->setContentView(view);
|
||||
m_modalViewController.viewWillAppear();
|
||||
if (m_firstResponder == nullptr) {
|
||||
setFirstResponder(&m_modalViewController);
|
||||
}
|
||||
setFirstResponder(&m_modalViewController);
|
||||
window->redraw();
|
||||
}
|
||||
|
||||
@@ -105,5 +104,7 @@ void App::willBecomeInactive() {
|
||||
if (m_modalViewController.isDisplayingModal()) {
|
||||
dismissModalViewController();
|
||||
}
|
||||
setFirstResponder(nullptr);
|
||||
m_modalViewController.viewDidDisappear();
|
||||
m_modalViewController.unloadView();
|
||||
}
|
||||
|
||||
@@ -26,6 +26,12 @@ ButtonRowController * ButtonRowDelegate::header() {
|
||||
return m_header;
|
||||
}
|
||||
|
||||
void ButtonRowDelegate::loadButtonView() {
|
||||
}
|
||||
|
||||
void ButtonRowDelegate::unloadButtonView() {
|
||||
}
|
||||
|
||||
ButtonRowController::ContentView::ContentView(ViewController * mainViewController, ButtonRowDelegate * delegate, Position position, Style style) :
|
||||
View(),
|
||||
m_mainViewController(mainViewController),
|
||||
@@ -231,3 +237,13 @@ void ButtonRowController::viewWillAppear() {
|
||||
void ButtonRowController::viewDidDisappear() {
|
||||
m_contentView.mainViewController()->viewDidDisappear();
|
||||
}
|
||||
|
||||
void ButtonRowController::loadView() {
|
||||
m_contentView.buttonRowDelegate()->loadButtonView();
|
||||
m_contentView.mainViewController()->loadView();
|
||||
}
|
||||
|
||||
void ButtonRowController::unloadView() {
|
||||
m_contentView.buttonRowDelegate()->unloadButtonView();
|
||||
m_contentView.mainViewController()->unloadView();
|
||||
}
|
||||
|
||||
32
escher/src/dynamic_view_controller.cpp
Normal file
32
escher/src/dynamic_view_controller.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#include <escher/dynamic_view_controller.h>
|
||||
#include <escher/app.h>
|
||||
#include <assert.h>
|
||||
|
||||
DynamicViewController::DynamicViewController(Responder * parentResponder) :
|
||||
ViewController(parentResponder),
|
||||
m_view(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
DynamicViewController::~DynamicViewController() {
|
||||
if (m_view) {
|
||||
delete m_view;
|
||||
m_view = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
View * DynamicViewController::view() {
|
||||
assert(m_view != nullptr);
|
||||
return m_view;
|
||||
}
|
||||
|
||||
void DynamicViewController::loadView() {
|
||||
assert(m_view == nullptr);
|
||||
m_view = createView();
|
||||
}
|
||||
|
||||
void DynamicViewController::unloadView() {
|
||||
assert(m_view != nullptr);
|
||||
delete m_view;
|
||||
m_view = nullptr;
|
||||
}
|
||||
@@ -17,7 +17,9 @@ ModalViewController::ContentView::ContentView() :
|
||||
}
|
||||
|
||||
void ModalViewController::ContentView::setMainView(View * regularView) {
|
||||
m_regularView = regularView;
|
||||
if (m_regularView != regularView) {
|
||||
m_regularView = regularView;
|
||||
}
|
||||
}
|
||||
|
||||
int ModalViewController::ContentView::numberOfSubviews() const {
|
||||
@@ -96,9 +98,6 @@ ModalViewController::ModalViewController(Responder * parentResponder, ViewContro
|
||||
}
|
||||
|
||||
View * ModalViewController::view() {
|
||||
if (m_contentView.subviewAtIndex(0) == nullptr) {
|
||||
m_contentView.setMainView(m_regularViewController->view());
|
||||
}
|
||||
return &m_contentView;
|
||||
}
|
||||
|
||||
@@ -112,6 +111,7 @@ void ModalViewController::displayModalViewController(ViewController * vc, float
|
||||
vc->setParentResponder(this);
|
||||
m_previousResponder = app()->firstResponder();
|
||||
m_regularViewController->viewDidDisappear();
|
||||
vc->loadView();
|
||||
m_contentView.presentModalView(vc->view(), verticalAlignment, horizontalAlignment, topMargin, leftMargin, bottomMargin, rightMargin);
|
||||
m_currentModalViewController->viewWillAppear();
|
||||
app()->setFirstResponder(vc);
|
||||
@@ -119,6 +119,7 @@ void ModalViewController::displayModalViewController(ViewController * vc, float
|
||||
|
||||
void ModalViewController::dismissModalViewController() {
|
||||
m_currentModalViewController->viewDidDisappear();
|
||||
m_currentModalViewController->unloadView();
|
||||
m_currentModalViewController = nullptr;
|
||||
m_regularViewController->viewWillAppear();
|
||||
app()->setFirstResponder(m_previousResponder);
|
||||
@@ -156,3 +157,19 @@ void ModalViewController::viewDidDisappear() {
|
||||
}
|
||||
m_regularViewController->viewDidDisappear();
|
||||
}
|
||||
|
||||
void ModalViewController::loadView() {
|
||||
if (m_contentView.isDisplayingModal()) {
|
||||
m_currentModalViewController->loadView();
|
||||
}
|
||||
m_regularViewController->loadView();
|
||||
m_contentView.setMainView(m_regularViewController->view());
|
||||
m_contentView.layoutSubviews();
|
||||
}
|
||||
|
||||
void ModalViewController::unloadView() {
|
||||
if (m_contentView.isDisplayingModal()) {
|
||||
m_currentModalViewController->unloadView();
|
||||
}
|
||||
m_regularViewController->unloadView();
|
||||
}
|
||||
|
||||
@@ -90,8 +90,9 @@ const char * StackViewController::title() {
|
||||
void StackViewController::push(ViewController * vc, KDColor textColor, KDColor backgroundColor, KDColor separatorColor) {
|
||||
m_view.pushStack(vc, textColor, backgroundColor, separatorColor);
|
||||
m_children[m_numberOfChildren++] = vc;
|
||||
if (m_numberOfChildren > 1) {
|
||||
if (m_numberOfChildren > 2) {
|
||||
m_children[m_numberOfChildren-2]->viewDidDisappear();
|
||||
m_children[m_numberOfChildren-2]->unloadView();
|
||||
}
|
||||
setupActiveViewController();
|
||||
}
|
||||
@@ -100,15 +101,19 @@ void StackViewController::pop() {
|
||||
m_view.popStack();
|
||||
assert(m_numberOfChildren > 0);
|
||||
ViewController * vc = m_children[m_numberOfChildren-1];
|
||||
vc->setParentResponder(nullptr);
|
||||
m_numberOfChildren--;
|
||||
vc->viewDidDisappear();
|
||||
setupActiveViewController();
|
||||
vc->setParentResponder(nullptr);
|
||||
vc->unloadView();
|
||||
}
|
||||
|
||||
void StackViewController::setupActiveViewController() {
|
||||
ViewController * vc = m_children[m_numberOfChildren-1];
|
||||
vc->setParentResponder(this);
|
||||
if (m_numberOfChildren > 1) {
|
||||
vc->loadView();
|
||||
}
|
||||
m_view.setContentView(vc->view());
|
||||
vc->viewWillAppear();
|
||||
app()->setFirstResponder(vc);
|
||||
@@ -133,7 +138,12 @@ View * StackViewController::view() {
|
||||
|
||||
void StackViewController::viewWillAppear() {
|
||||
if (m_rootViewController != nullptr) {
|
||||
push(m_rootViewController, m_textColor, m_backgroundColor, m_separatorColor);
|
||||
/* push the m_rootViewController without setting it as first responder
|
||||
* (which will be done in did become first responder */
|
||||
m_view.pushStack(m_rootViewController, m_textColor, m_backgroundColor, m_separatorColor);
|
||||
m_children[m_numberOfChildren++] = m_rootViewController;
|
||||
m_rootViewController->setParentResponder(this);
|
||||
m_view.setContentView(m_rootViewController->view());
|
||||
m_rootViewController = nullptr;
|
||||
}
|
||||
ViewController * vc = m_children[m_numberOfChildren-1];
|
||||
@@ -148,3 +158,21 @@ void StackViewController::viewDidDisappear() {
|
||||
vc->viewDidDisappear();
|
||||
}
|
||||
}
|
||||
|
||||
void StackViewController::loadView() {
|
||||
if (m_rootViewController) {
|
||||
m_rootViewController->loadView();
|
||||
} else {
|
||||
ViewController * vc = m_children[m_numberOfChildren-1];
|
||||
if (m_numberOfChildren > 0 && vc) {
|
||||
vc->loadView();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StackViewController::unloadView() {
|
||||
ViewController * vc = m_children[m_numberOfChildren-1];
|
||||
if (m_numberOfChildren > 0 && vc) {
|
||||
vc->unloadView();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,10 +111,14 @@ void TabViewController::setActiveTab(int8_t i, bool forceReactive) {
|
||||
ViewController * activeVC = m_children[i];
|
||||
if (i != m_activeChildIndex || forceReactive) {
|
||||
assert(i <= m_numberOfChildren);
|
||||
if (i != m_activeChildIndex) {
|
||||
activeVC->loadView();
|
||||
}
|
||||
m_view.setActiveView(activeVC->view());
|
||||
m_view.m_tabView.setActiveIndex(i);
|
||||
if (m_activeChildIndex >= 0) {
|
||||
if (m_activeChildIndex >= 0 && m_activeChildIndex != i) {
|
||||
m_children[m_activeChildIndex]->viewDidDisappear();
|
||||
m_children[m_activeChildIndex]->unloadView();
|
||||
}
|
||||
m_activeChildIndex = i;
|
||||
if (i >= 0) {
|
||||
@@ -132,6 +136,10 @@ void TabViewController::setSelectedTab(int8_t i) {
|
||||
m_selectedChildIndex = i;
|
||||
}
|
||||
|
||||
void TabViewController::didEnterResponderChain(Responder * previousResponder) {
|
||||
setActiveTab(m_activeChildIndex, true);
|
||||
}
|
||||
|
||||
void TabViewController::didBecomeFirstResponder() {
|
||||
setSelectedTab(m_activeChildIndex);
|
||||
}
|
||||
@@ -142,13 +150,6 @@ void TabViewController::willResignFirstResponder() {
|
||||
|
||||
|
||||
View * TabViewController::view() {
|
||||
// We're asked for a view!
|
||||
// Let's populate our tabview
|
||||
if (m_view.m_tabView.numberOfTabs() != m_numberOfChildren) {
|
||||
for (int i=0; i<m_numberOfChildren; i++) {
|
||||
m_view.m_tabView.addTab(m_children[i]);
|
||||
}
|
||||
}
|
||||
return &m_view;
|
||||
}
|
||||
|
||||
@@ -161,16 +162,26 @@ const char * TabViewController::tabName(uint8_t index) {
|
||||
}
|
||||
|
||||
void TabViewController::viewWillAppear() {
|
||||
if (m_activeChildIndex < 0) {
|
||||
setActiveTab(0, true);
|
||||
} else {
|
||||
setActiveTab(m_activeChildIndex, true);
|
||||
}
|
||||
ViewController * activeVC = m_children[m_activeChildIndex];
|
||||
activeVC->viewWillAppear();
|
||||
}
|
||||
|
||||
void TabViewController::viewDidDisappear() {
|
||||
ViewController * activeVC = m_children[m_activeChildIndex];
|
||||
activeVC->viewDidDisappear();
|
||||
}
|
||||
|
||||
void TabViewController::loadView() {
|
||||
if (m_view.m_tabView.numberOfTabs() != m_numberOfChildren) {
|
||||
for (int i=0; i<m_numberOfChildren; i++) {
|
||||
m_view.m_tabView.addTab(m_children[i]);
|
||||
}
|
||||
}
|
||||
if (m_activeChildIndex < 0) {
|
||||
m_activeChildIndex = 0;
|
||||
}
|
||||
m_children[m_activeChildIndex]->loadView();
|
||||
}
|
||||
|
||||
void TabViewController::unloadView() {
|
||||
ViewController * activeVC = m_children[m_activeChildIndex];
|
||||
activeVC->unloadView();
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@ View::View() :
|
||||
{
|
||||
}
|
||||
|
||||
View::~View() {
|
||||
}
|
||||
|
||||
void View::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
// By default, a view doesn't do anything
|
||||
// It's transparent!
|
||||
|
||||
@@ -14,3 +14,9 @@ void ViewController::viewWillAppear() {
|
||||
|
||||
void ViewController::viewDidDisappear() {
|
||||
}
|
||||
|
||||
void ViewController::loadView() {
|
||||
}
|
||||
|
||||
void ViewController::unloadView() {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user