Skip to content

add frame notification bounceyness #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Mar 3, 2021
Merged
80 changes: 79 additions & 1 deletion src/OLEDDisplayUi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ OLEDDisplayUi::OLEDDisplayUi(OLEDDisplay *display) {
indicatorDirection = LEFT_RIGHT;
activeSymbol = ANIMATION_activeSymbol;
inactiveSymbol = ANIMATION_inactiveSymbol;
notifyingFrameOffsetAmplitude = 10;
frameAnimationDirection = SLIDE_RIGHT;
lastTransitionDirection = 1;
frameCount = 0;
Expand All @@ -56,6 +57,7 @@ OLEDDisplayUi::OLEDDisplayUi(OLEDDisplay *display) {
updateInterval = 33;
state.lastUpdate = 0;
state.ticksSinceLastStateSwitch = 0;
state.ticks = 0;
state.frameState = FIXED;
state.currentFrame = 0;
state.frameTransitionDirection = 1;
Expand All @@ -66,6 +68,7 @@ OLEDDisplayUi::OLEDDisplayUi(OLEDDisplay *display) {
autoTransition = true;
setTimePerFrame(5000);
setTimePerTransition(500);
frameNotificationCallbackFunction = nullptr;
}

void OLEDDisplayUi::init() {
Expand Down Expand Up @@ -220,6 +223,54 @@ void OLEDDisplayUi::transitionToFrame(uint8_t frame) {
this->state.frameTransitionDirection = frame < this->state.currentFrame ? -1 : 1;
}

bool OLEDDisplayUi::addFrameToNotifications(uint32_t frameToAdd, bool force) {
switch (this->state.frameState) {
case IN_TRANSITION:
if(!force && this->state.transitionFrameTarget == frameToAdd)
// if we're in transition, and being asked to set the to-be-current frame
// as having a notifiction, just don't (unless we're forced)
return false;
break;
case FIXED:
if(!force && this->state.currentFrame == frameToAdd)
// if we're on a fixed frame, and being asked to set the current frame
// as having a notifiction, just don't (unless we're forced)
return false;
break;
}
// nothing is preventing us from setting the requested frame as having a notification, so
// do it.
this->state.notifyingFrames.push_back(frameToAdd);
return true;
}

bool OLEDDisplayUi::removeFrameFromNotifications(uint32_t frameToRemove) {
// We've been told that a frame no longer needs to be notifying

auto it = std::find(this->state.notifyingFrames.begin(), this->state.notifyingFrames.end(), frameToRemove);
if (it != this->state.notifyingFrames.end()) {
using std::swap;
// swap the one to be removed with the last element
// and remove the item at the end of the container
// to prevent moving all items after '5' by one
swap(*it, this->state.notifyingFrames.back());
this->state.notifyingFrames.pop_back();
return true;
}
return false;
}

void OLEDDisplayUi::setFrameNotificationCallback(FrameNotificationCallback* frameNotificationCallbackFunction) {
this->frameNotificationCallbackFunction = frameNotificationCallbackFunction;
}

uint32_t OLEDDisplayUi::getFirstNotifyingFrame() {
if (this->state.notifyingFrames.size() == 0){
return -1;
}
return this->state.notifyingFrames[0];
}


// -/----- State information -----\-
OLEDDisplayUiState* OLEDDisplayUi::getUiState(){
Expand Down Expand Up @@ -256,6 +307,7 @@ int16_t OLEDDisplayUi::update(){

void OLEDDisplayUi::tick() {
this->state.ticksSinceLastStateSwitch++;
this->state.ticks++;

switch (this->state.frameState) {
case IN_TRANSITION:
Expand Down Expand Up @@ -350,6 +402,10 @@ void OLEDDisplayUi::drawFrame(){
this->state.transitionFrameRelationship = INCOMING;
//Since we're IN_TRANSITION, draw the mew frame in a sliding-in position
(this->frameFunctions[this->getNextFrameNumber()])(this->display, &this->state, x1, y1);
// tell the consumer of this API that the frame that's coming into focus
// normally this would be to remove the notifications for this frame
if (frameNotificationCallbackFunction != nullptr)
(*frameNotificationCallbackFunction)(this->getNextFrameNumber(), this);

// Build up the indicatorDrawState
if (drawenCurrentFrame && !this->state.isIndicatorDrawen) {
Expand Down Expand Up @@ -377,6 +433,10 @@ void OLEDDisplayUi::drawFrame(){
this->state.transitionFrameRelationship = NONE;
//Since we're not transitioning, just draw the current frame at the origin
(this->frameFunctions[this->state.currentFrame])(this->display, &this->state, 0, 0);
// tell the consumer of this API that the frame that's coming into focus
// normally this would be to remove the notifications for this frame
if (frameNotificationCallbackFunction != nullptr)
(*frameNotificationCallbackFunction)(this->state.currentFrame, this);
break;
}
}
Expand Down Expand Up @@ -460,17 +520,35 @@ void OLEDDisplayUi::drawIndicator() {
image = this->inactiveSymbol;
}

if (this->state.notifyingFrames.size() > 0) {
for(uint8_t q=0;q<this->state.notifyingFrames.size();q++) {
// if the symbol for the frame we're currently drawing (i)
// is equal to the symbol in the array we're looking at (notff[q])
// then we should adjust `y` by the SIN function (actualOffset)
if (i == (this->state.notifyingFrames[q])) {
#define MILISECONDS_PER_BUBBLE_BOUNDS 5000
uint8_t actualOffset = abs((sin(this->state.ticks*PI/(MILISECONDS_PER_BUBBLE_BOUNDS/updateInterval)) * notifyingFrameOffsetAmplitude));
// is the indicator (symbol / dot) we're currently drawing one that's requesting notification
y = y - actualOffset;
//display->drawString(0,0,String(actualOffset));
//display->drawString(0,30,String(this->state.ticks));
}
}
}

this->display->drawFastImage(x, y, 8, 8, image);
}
}


void OLEDDisplayUi::drawOverlays() {
for (uint8_t i=0;i<this->overlayCount;i++){
(this->overlayFunctions[i])(this->display, &this->state);
}
}

uint8_t OLEDDisplayUi::getNextFrameNumber(){
if (this->nextFrameNumber != -1) return this->nextFrameNumber;
if (this->nextFrameNumber != -1)
return this->nextFrameNumber;
return (this->state.currentFrame + this->frameCount + this->state.frameTransitionDirection) % this->frameCount;
}
30 changes: 30 additions & 0 deletions src/OLEDDisplayUi.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,15 @@ const uint8_t ANIMATION_inactiveSymbol[] PROGMEM = {
struct OLEDDisplayUiState {
uint64_t lastUpdate;
uint16_t ticksSinceLastStateSwitch;
uint16_t ticks;


FrameState frameState;
uint8_t currentFrame;
uint8_t transitionFrameTarget;
TransitionRelationship transitionFrameRelationship;

std::vector<uint32_t> notifyingFrames;
bool isIndicatorDrawen;

// Normal = 1, Inverse = -1;
Expand All @@ -116,6 +119,7 @@ struct LoadingStage {
typedef void (*FrameCallback)(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
typedef void (*OverlayCallback)(OLEDDisplay *display, OLEDDisplayUiState* state);
typedef void (*LoadingDrawFunction)(OLEDDisplay *display, LoadingStage* stage, uint8_t progress);
typedef void (*FrameNotificationCallback)(uint32_t FrameNumber, void* UI);

class OLEDDisplayUi {
private:
Expand All @@ -141,7 +145,9 @@ class OLEDDisplayUi {
bool autoTransition;

FrameCallback* frameFunctions;
FrameNotificationCallback* frameNotificationCallbackFunction;
uint8_t frameCount;
uint8_t notifyingFrameOffsetAmplitude;

// Internally used to transition to a specific frame
int8_t nextFrameNumber;
Expand Down Expand Up @@ -264,6 +270,30 @@ class OLEDDisplayUi {
*/
void setInactiveSymbol(const uint8_t* symbol);

/**
* Adds a frame to the list of frames with active notifications
*/
bool addFrameToNotifications(uint32_t frameToAdd, bool force=false);

/**
* Removes a frame from the list of frames with active notifications
*/
bool removeFrameFromNotifications(uint32_t frameToRemove);

/**
* Sets a callback function to be called when a frame comes into focus
* Normally this function will remove the frame from the list of
* active notifications
*/

void setFrameNotificationCallback(FrameNotificationCallback* frameNotificationCallbackFunction);

/**
* Returns the number of the frist frame having notifications
* This is most likely to be used when attempting to "jump"
* to the oldest notification
*/
uint32_t getFirstNotifyingFrame();

// Frame settings

Expand Down