Skip to content

Instantly share code, notes, and snippets.

@rc1
Last active December 18, 2015 09:19
Show Gist options
  • Select an option

  • Save rc1/5760667 to your computer and use it in GitHub Desktop.

Select an option

Save rc1/5760667 to your computer and use it in GitHub Desktop.
#pragma once
#include "ofMain.h"
class ScreenStack;
// Base Screen class for using with ScreenStack
class Screen {
friend class ScreenStack;
public:
Screen():
screenStack(0)
{};
virtual ~Screen() {}
// the stack that contains this screen
ScreenStack *getScreenStack() { return screenStack; }
/// App events
virtual void update() {};
virtual void draw() = 0;
virtual void exit() {};
/// Touch events
virtual void touchDown(ofTouchEventArgs & touch) {};
virtual void touchMoved(ofTouchEventArgs & touch) {};
virtual void touchUp(ofTouchEventArgs & touch) {};
virtual void touchDoubleTap(ofTouchEventArgs & touch) {};
virtual void touchCancelled(ofTouchEventArgs & touch) {}
/// Pop delegate methods (invoked by ScreenStack)
// Can return false to block a pop request. I.e. return false, do a *getting popped*
// animation, force a pop on the ScreenStack
virtual bool allowPop() { return true; }
virtual void willGetPopped() {};
virtual void didBecomeTopAfterPop() {};
/// Push delegate methods (invoked by ScreenStack)
// Can return false to block a screen being pushed on top. I.e. return false,
// do a *getting popped* animation, force a push on the ScreenStack with `otherScreenPtr`
virtual bool allowScreenToBePushedOnTop(ofPtr<Screen>otherScreenPtr) { return true; }
virtual void willGetScreenPushedOnTop(ofPtr<Screen>otherScreenPtr) {};
virtual void didGetPushedOnTop() {};
private:
ScreenStack *screenStack;
};
// Holds a stack of screens.
// The top most screen will be the reciever of calls to update, draw, exit, touch.
// The events can be auto subscribed via enableAppEvents, enableTouchEvents
class ScreenStack {
public:
ScreenStack():
_hasEnabledAppEvents(false),
_hasEnabledTouchEvents(false)
{};
virtual ~ScreenStack() {
if (_hasEnabledAppEvents) {
disableAppEvents();
}
if (_hasEnabledTouchEvents) {
disableTouchEvents();
}
};
/// Adding and removing screens
void pushScreen(ofPtr<Screen> screenPtr, bool force=false) {
if (screenPtr == 0) {
ofLogError() << "Invald screen pushed to ScreenStack";
return;
}
// either force the push or ask the top most screen if it allows the push
if ( force || screenPtrs.empty() || screenPtrs.top()->allowScreenToBePushedOnTop( screenPtr ) ) {
// tell the top most screen it is getting something push on top
if ( !screenPtrs.empty() ) {
screenPtrs.top()->willGetScreenPushedOnTop( screenPtr );
}
// give the screen a reference to its stack (this)
screenPtr->screenStack = this;
screenPtrs.push( screenPtr );
screenPtr->didGetPushedOnTop();
}
};
void popScreen(bool force=false) {
if ( force || screenPtrs.empty() || screenPtrs.top()->allowPop() ) {
if ( !screenPtrs.empty() ) {
screenPtrs.top()->willGetPopped();
}
screenPtrs.top()->screenStack = nil;
screenPtrs.pop();
if ( !screenPtrs.empty() ) {
screenPtrs.top()->didBecomeTopAfterPop();
}
}
};
/// Events
// Draw events
void update() {
if ( !screenPtrs.empty() ) {
screenPtrs.top()->update();
}
};
void draw() {
if ( !screenPtrs.empty() ) {
screenPtrs.top()->draw();
}
};
void exit() {
if ( !screenPtrs.empty() ) {
screenPtrs.top()->exit();
}
};
// Touch events
void touchDown(ofTouchEventArgs & touch) {
if ( !screenPtrs.empty() ) {
screenPtrs.top()->touchDown(touch);
}
};
void touchMoved(ofTouchEventArgs & touch) {
if ( !screenPtrs.empty() ) {
screenPtrs.top()->touchMoved(touch);
}
};
void touchUp(ofTouchEventArgs & touch) {
if ( !screenPtrs.empty() ) {
screenPtrs.top()->touchUp(touch);
}
};
void touchDoubleTap(ofTouchEventArgs & touch) {
if ( !screenPtrs.empty() ) {
screenPtrs.top()->touchDoubleTap(touch);
}
};
void touchCancelled(ofTouchEventArgs & touch) {
if ( !screenPtrs.empty() ) {
screenPtrs.top()->touchCancelled(touch);
}
};
/// Auto enable / disable events listeners
void enableAppEvents() {
ofAddListener(ofEvents().update, this, &ScreenStack::onUpdate);
ofAddListener(ofEvents().draw, this, &ScreenStack::onDraw);
ofAddListener(ofEvents().exit, this, &ScreenStack::onExit);
_hasEnabledAppEvents = true;
};
void disableAppEvents() {
ofRemoveListener(ofEvents().update, this, &ScreenStack::onUpdate);
ofRemoveListener(ofEvents().draw, this, &ScreenStack::onDraw);
ofRemoveListener(ofEvents().exit, this, &ScreenStack::onExit);
_hasEnabledAppEvents = false;
};
void onDraw(ofEventArgs &data) { draw(); }
void onUpdate(ofEventArgs &data) { update(); }
void onExit(ofEventArgs &data) { exit(); }
void enableTouchEvents() {
ofAddListener(ofEvents().touchDown, this, &ScreenStack::onTouchDown);
ofAddListener(ofEvents().touchMoved, this, &ScreenStack::onTouchMoved);
ofAddListener(ofEvents().touchUp, this, &ScreenStack::onTouchUp);
ofAddListener(ofEvents().touchDoubleTap, this, &ScreenStack::onTouchDoubleTap);
ofAddListener(ofEvents().touchCancelled, this, &ScreenStack::onTouchCancelled);
_hasEnabledAppEvents = true;
};
void disableTouchEvents() {
ofRemoveListener(ofEvents().touchDown, this, &ScreenStack::onTouchDown);
ofRemoveListener(ofEvents().touchMoved, this, &ScreenStack::onTouchMoved);
ofRemoveListener(ofEvents().touchUp, this, &ScreenStack::onTouchUp);
ofRemoveListener(ofEvents().touchDoubleTap, this, &ScreenStack::onTouchDoubleTap);
ofRemoveListener(ofEvents().touchCancelled, this, &ScreenStack::onTouchCancelled);
_hasEnabledAppEvents = false;
};
void onTouchDown(ofTouchEventArgs & touch) { touchDown(touch); }
void onTouchMoved(ofTouchEventArgs & touch) { touchMoved(touch); }
void onTouchUp(ofTouchEventArgs & touch) { touchUp(touch); }
void onTouchDoubleTap(ofTouchEventArgs & touch) { touchDoubleTap(touch); }
void onTouchCancelled(ofTouchEventArgs & touch) { touchCancelled(touch); }
private:
stack< ofPtr<Screen> > screenPtrs;
bool _hasEnabledAppEvents;
bool _hasEnabledTouchEvents;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment