最近在玩oled,目前网上大多数的oled产品都用到了OLEDDisplayUI这个库,这个库包括三个方面,加载动画、指示器动画、帧切换动画。一定程序上丰富了oled的可玩性。但在玩的过程中我也只是拿出来用,至于怎么实现的之前也没考虑,我想很多人都是这样。玩了一段时间感觉不满足,想自己折腾一下,做其他其他的动画,更好玩一点。但这个库的资料一点没找到,我只能把原库的英文部分翻译一下,有些函数能懂的写一点注释,自己的C++水平太菜,暂时还不能写出很好的文档。先给大家看一下吧,我想可能有人用的到,自己也算做个笔记。
//file:OLEDDisplayUI.h
/**
* The MIT License (MIT)
*
* Copyright (c) 2016 by Daniel Eichhorn
* Copyright (c) 2016 by Fabrice Weinberg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
//上面是软件协议
#ifndef OLEDDISPLAYUI_h
#define OLEDDISPLAYUI_h
#include <Arduino.h>
#include "OLEDDisplay.h"
//#define DEBUG_OLEDDISPLAYUI(...) Serial.printf( __VA_ARGS__ )
//定义串口输出调试
#ifndef DEBUG_OLEDDISPLAYUI
#define DEBUG_OLEDDISPLAYUI(...)
#endif
//显示动画方向 (向上、向下、向左、向右)
enum AnimationDirection {
SLIDE_UP,
SLIDE_DOWN,
SLIDE_LEFT,
SLIDE_RIGHT
};
//指示器位置(上面、右面、下面、左面)
enum IndicatorPosition {
TOP,
RIGHT,
BOTTOM,
LEFT
};
//指示器移动方向(左右、右左)
enum IndicatorDirection {
LEFT_RIGHT,
RIGHT_LEFT
};
//帧状态(移动中、固定)
enum FrameState {
IN_TRANSITION,
FIXED
};
//指示器内活动标志
const char ANIMATION_activeSymbol[] PROGMEM = {
0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00
};
//指示器内不活动标志
const char ANIMATION_inactiveSymbol[] PROGMEM = {
0x00, 0x0, 0x0, 0x18, 0x18, 0x0, 0x0, 0x00
};
// Structure of the UiState
//UI状态结构体
struct OLEDDisplayUiState {
uint64_t lastUpdate = 0;
uint16_t ticksSinceLastStateSwitch = 0;
FrameState frameState = FIXED;
uint8_t currentFrame = 0;
bool isIndicatorDrawen = true;
// Normal = 1, Inverse = -1;
int8_t frameTransitionDirection = 1;
bool manuelControll = false;
// Custom data that can be used by the user
void* userData = NULL;
};
//加载进度条结构体
struct LoadingStage {
const char* process;
void(*callback)();
};
//FramaeCallbac\OverlayCallback\LoadingDrawFunction函数声明
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);
//定义OLEDDisplayUi类
class OLEDDisplayUi {
private:
OLEDDisplay *display;
// Symbols for the Indicator
//定义指示器位置及移动方向
IndicatorPosition indicatorPosition = BOTTOM;
IndicatorDirection indicatorDirection = LEFT_RIGHT;
const char* activeSymbol = ANIMATION_activeSymbol;
const char* inactiveSymbol = ANIMATION_inactiveSymbol;
bool shouldDrawIndicators = true;
// Values for the Frames
//帧值
AnimationDirection frameAnimationDirection = SLIDE_RIGHT;
int8_t lastTransitionDirection = 1;
uint16_t ticksPerFrame = 151; // ~ 5000ms at 30 FPS(5000毫秒30帧)
uint16_t ticksPerTransition = 15; // ~ 500ms at 30 FPS (500毫秒30帧)
bool autoTransition = true;
FrameCallback* frameFunctions;
uint8_t frameCount = 0;
// Internally used to transition to a specific frame
//内部用于转换到特定帧(这个不知道啥意思,字面翻译)
int8_t nextFrameNumber = -1;
// Values for Overlays
//Overlays值
OverlayCallback* overlayFunctions;
uint8_t overlayCount = 0;
// Will the Indicator be drawen (指示器是否被绘出)
// 3 Not drawn in both frames (3,不绘出)
// 2 Drawn this frame but not next (2,此帧绘出,下一帧不绘)
// 1 Not drown this frame but next (1,此帧不会出,下一帧绘出)
// 0 Not known yet (0,不知道)
uint8_t indicatorDrawState = 1;
// Loading screen
//屏幕加载
//实例化LoadingDrawFunction
LoadingDrawFunction loadingDrawFunction = [](OLEDDisplay *display, LoadingStage* stage, uint8_t progress) {
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_10);
display->drawString(64, 18, stage->process);
display->drawProgressBar(4, 32, 120, 8, progress);
};
// UI State
//UI状态
OLEDDisplayUiState state;
// Bookeeping for update
//更新状态记录
uint8_t updateInterval = 33;
uint8_t getNextFrameNumber();
void drawIndicator();
void drawFrame();
void drawOverlays();
void tick();
void resetState();
public:
OLEDDisplayUi(OLEDDisplay *display);
/**
* Initialise the display
*/
//初始化显示
void init();
/**
* Configure the internal used target FPS
*/
//设置内部目标帧率
void setTargetFPS(uint8_t fps);
// Automatic Controll(自动控制)
/**
* Enable automatic transition to next frame after the some time can be configured with `setTimePerFrame` and `setTimePerTransition`.
*/
//可通过设置`setTimePerFrame` 和 `setTimePerTransition`值,定时自动切换到下一帧。
void enableAutoTransition();
/**
* Disable automatic transition to next frame.
*/
//禁用自动切换下一帧
void disableAutoTransition();
/**
* Set the direction if the automatic transitioning
*/
//设置自动切换方向
void setAutoTransitionForwards();
void setAutoTransitionBackwards();
/**
* Set the approx. time a frame is displayed
*/
//设置每帧显示时间
void setTimePerFrame(uint16_t time);
/**
* Set the approx. time a transition will take
*/
//设置切换时间
void setTimePerTransition(uint16_t time);
// Customize indicator position and style
//自定义指示器位置和风格
/**
* Draw the indicator.
* This is the defaut state for all frames if
* the indicator was hidden on the previous frame
* it will be slided in.
*/
//如果前一帧的指示器是隐藏的,此帧显示指示器。
void enableIndicator();
/**
* Don't draw the indicator.
* This will slide out the indicator
* when transitioning to the next frame.
*/
//当显示下一帧的时候指示器将隐藏。
void disableIndicator();
/**
* Enable drawing of indicators
*/
//显示指示器
void enableAllIndicators();
/**
* Disable draw of indicators.
*/
//不显示指示器
void disableAllIndicators();
/**
* Set the position of the indicator bar.
*/
//指示器位置
void setIndicatorPosition(IndicatorPosition pos);
/**
* Set the direction of the indicator bar. Defining the order of frames ASCENDING / DESCENDING
*/
//指示器方向。帧升序\帧降序
void setIndicatorDirection(IndicatorDirection dir);
/**
* Set the symbol to indicate an active frame in the indicator bar.
*/
//设置指示器内活动帧标志
void setActiveSymbol(const char* symbol);
/**
* Set the symbol to indicate an inactive frame in the indicator bar.
*/
//设置指示器内不活动帧标志
void setInactiveSymbol(const char* symbol);
// Frame settings
//帧设置
/**
* Configure what animation is used to transition from one frame to another
*/
//设置帧切换动画
void setFrameAnimation(AnimationDirection dir);
/**
* Add frame drawing functions
*/
//帧绘制功能
void setFrames(FrameCallback* frameFunctions, uint8_t frameCount);
// Overlay
/**
* Add overlays drawing functions that are draw independent of the Frames
*/
//层覆盖功能
void setOverlays(OverlayCallback* overlayFunctions, uint8_t overlayCount);
// Loading animation
//加载动画
/**
* Set the function that will draw each step
* in the loading animation
*/
//加载动画时详细设置
void setLoadingDrawFunction(LoadingDrawFunction loadingFunction);
/**
* Run the loading process
*/
//加载进度
void runLoadingProcess(LoadingStage* stages, uint8_t stagesCount);
// Manual Control
//手动控制
void nextFrame();
void previousFrame();
/**
* Switch without transition to frame `frame`.
*/
//切换到哪一帧
void switchToFrame(uint8_t frame);
/**
* Transition to frame `frame`, when the `frame` number is bigger than the current
* frame the forward animation will be used, otherwise the backwards animation is used.
*/
//如果下一帧号大于当前帧,向前绘制动画,否则向后绘制动画。
void transitionToFrame(uint8_t frame);
// State Info
//获取UI状态
OLEDDisplayUiState* getUiState();
int8_t update();
};
#endif
//file:OLEDDisplayUI.cpp
/**
* The MIT License (MIT)
*
* Copyright (c) 2018 by ThingPulse, Daniel Eichhorn
* Copyright (c) 2018 by Fabrice Weinberg
* Copyright (c) 2019 by Helmut Tschemernjak - www.radioshuttle.de
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* ThingPulse invests considerable time and money to develop these open source libraries.
* Please support us by buying our products (and not the clones) from
* https://thingpulse.com
*
*/
//上面是共享软件协议
#include "OLEDDisplayUi.h"
void LoadingDrawDefault(OLEDDisplay *display, LoadingStage* stage, uint8_t progress) {
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(ArialMT_Plain_10);
display->drawString(64, 18, stage->process);
display->drawProgressBar(4, 32, 120, 8, progress);
};
OLEDDisplayUi::OLEDDisplayUi(OLEDDisplay *display) {
this->display = display;
indicatorPosition = BOTTOM;
indicatorDirection = LEFT_RIGHT;
activeSymbol = ANIMATION_activeSymbol;
inactiveSymbol = ANIMATION_inactiveSymbol;
frameAnimationDirection = SLIDE_RIGHT;
lastTransitionDirection = 1;
ticksPerFrame = 151; // ~ 5000ms at 30 FPS
ticksPerTransition = 15; // ~ 500ms at 30 FPS
frameCount = 0;
nextFrameNumber = -1;
overlayCount = 0;
indicatorDrawState = 1;
loadingDrawFunction = LoadingDrawDefault;
updateInterval = 33;
state.lastUpdate = 0;
state.ticksSinceLastStateSwitch = 0;
state.frameState = FIXED;
state.currentFrame = 0;
state.frameTransitionDirection = 1;
state.isIndicatorDrawen = true;
state.manuelControll = false;
state.userData = NULL;
shouldDrawIndicators = true;
autoTransition = true;
}
void OLEDDisplayUi::init() {
this->display->init();
}
void OLEDDisplayUi::setTargetFPS(uint8_t fps){
float oldInterval = this->updateInterval;
this->updateInterval = ((float) 1.0 / (float) fps) * 1000;
// Calculate new ticksPerFrame
float changeRatio = oldInterval / (float) this->updateInterval;
this->ticksPerFrame *= changeRatio;
this->ticksPerTransition *= changeRatio;
}
// -/------ Automatic controll ------\-
//自动控制
void OLEDDisplayUi::enableAutoTransition(){
this->autoTransition = true;
}
void OLEDDisplayUi::disableAutoTransition(){
this->autoTransition = false;
}
void OLEDDisplayUi::setAutoTransitionForwards(){
this->state.frameTransitionDirection = 1;
this->lastTransitionDirection = 1;
}
void OLEDDisplayUi::setAutoTransitionBackwards(){
this->state.frameTransitionDirection = -1;
this->lastTransitionDirection = -1;
}
void OLEDDisplayUi::setTimePerFrame(uint16_t time){
this->ticksPerFrame = (uint16_t) ( (float) time / (float) updateInterval);
}
void OLEDDisplayUi::setTimePerTransition(uint16_t time){
this->ticksPerTransition = (uint16_t) ( (float) time / (float) updateInterval);
}
// -/------ Customize indicator position and style -------\-
//自定义指示器位置和风格
void OLEDDisplayUi::enableIndicator(){
this->state.isIndicatorDrawen = true;
}
void OLEDDisplayUi::disableIndicator(){
this->state.isIndicatorDrawen = false;
}
void OLEDDisplayUi::enableAllIndicators(){
this->shouldDrawIndicators = true;
}
void OLEDDisplayUi::disableAllIndicators(){
this->shouldDrawIndicators = false;
}
void OLEDDisplayUi::setIndicatorPosition(IndicatorPosition pos) {
this->indicatorPosition = pos;
}
void OLEDDisplayUi::setIndicatorDirection(IndicatorDirection dir) {
this->indicatorDirection = dir;
}
void OLEDDisplayUi::setActiveSymbol(const uint8_t* symbol) {
this->activeSymbol = symbol;
}
void OLEDDisplayUi::setInactiveSymbol(const uint8_t* symbol) {
this->inactiveSymbol = symbol;
}
// -/----- Frame settings -----\-
//帧设定
void OLEDDisplayUi::setFrameAnimation(AnimationDirection dir) {
this->frameAnimationDirection = dir;
}
void OLEDDisplayUi::setFrames(FrameCallback* frameFunctions, uint8_t frameCount) {
this->frameFunctions = frameFunctions;
this->frameCount = frameCount;
this->resetState();
}
// -/----- Overlays ------\-
void OLEDDisplayUi::setOverlays(OverlayCallback* overlayFunctions, uint8_t overlayCount){
this->overlayFunctions = overlayFunctions;
this->overlayCount = overlayCount;
}
// -/----- Loading Process -----\-
//加载进程/
void OLEDDisplayUi::setLoadingDrawFunction(LoadingDrawFunction loadingDrawFunction) {
this->loadingDrawFunction = loadingDrawFunction;
}
void OLEDDisplayUi::runLoadingProcess(LoadingStage* stages, uint8_t stagesCount) {
uint8_t progress = 0;
uint8_t increment = 100 / stagesCount;
for (uint8_t i = 0; i < stagesCount; i++) {
display->clear();
this->loadingDrawFunction(this->display, &stages[i], progress);
display->display();
stages[i].callback();
progress += increment;
yield();
}
display->clear();
this->loadingDrawFunction(this->display, &stages[stagesCount-1], progress);
display->display();
delay(150);
}
// -/----- Manuel control -----\-
//手动控制
void OLEDDisplayUi::nextFrame() {
if (this->state.frameState != IN_TRANSITION) {
this->state.manuelControll = true;
this->state.frameState = IN_TRANSITION;
this->state.ticksSinceLastStateSwitch = 0;
this->lastTransitionDirection = this->state.frameTransitionDirection;
this->state.frameTransitionDirection = 1;
}
}
void OLEDDisplayUi::previousFrame() {
if (this->state.frameState != IN_TRANSITION) {
this->state.manuelControll = true;
this->state.frameState = IN_TRANSITION;
this->state.ticksSinceLastStateSwitch = 0;
this->lastTransitionDirection = this->state.frameTransitionDirection;
this->state.frameTransitionDirection = -1;
}
}
void OLEDDisplayUi::switchToFrame(uint8_t frame) {
if (frame >= this->frameCount) return;
this->state.ticksSinceLastStateSwitch = 0;
if (frame == this->state.currentFrame) return;
this->state.frameState = FIXED;
this->state.currentFrame = frame;
this->state.isIndicatorDrawen = true;
}
void OLEDDisplayUi::transitionToFrame(uint8_t frame) {
if (frame >= this->frameCount) return;
this->state.ticksSinceLastStateSwitch = 0;
if (frame == this->state.currentFrame) return;
this->nextFrameNumber = frame;
this->lastTransitionDirection = this->state.frameTransitionDirection;
this->state.manuelControll = true;
this->state.frameState = IN_TRANSITION;
this->state.frameTransitionDirection = frame < this->state.currentFrame ? -1 : 1;
}
// -/----- State information -----\-
//UI状态信息
OLEDDisplayUiState* OLEDDisplayUi::getUiState(){
return &this->state;
}
int16_t OLEDDisplayUi::update(){
#ifdef ARDUINO
unsigned long frameStart = millis();
#elif __MBED__
Timer t;
t.start();
unsigned long frameStart = t.read_ms();
#else
#error "Unkown operating system"
#endif
int16_t timeBudget = this->updateInterval - (frameStart - this->state.lastUpdate);
if ( timeBudget <= 0) {
// Implement frame skipping to ensure time budget is keept
if (this->autoTransition && this->state.lastUpdate != 0) this->state.ticksSinceLastStateSwitch += ceil((double)-timeBudget / (double)this->updateInterval);
this->state.lastUpdate = frameStart;
this->tick();
}
#ifdef ARDUINO
return this->updateInterval - (millis() - frameStart);
#elif __MBED__
return this->updateInterval - (t.read_ms() - frameStart);
#else
#error "Unkown operating system"
#endif
}
void OLEDDisplayUi::tick() {
this->state.ticksSinceLastStateSwitch++;
switch (this->state.frameState) {
case IN_TRANSITION:
if (this->state.ticksSinceLastStateSwitch >= this->ticksPerTransition){
this->state.frameState = FIXED;
this->state.currentFrame = getNextFrameNumber();
this->state.ticksSinceLastStateSwitch = 0;
this->nextFrameNumber = -1;
}
break;
case FIXED:
// Revert manuelControll
if (this->state.manuelControll) {
this->state.frameTransitionDirection = this->lastTransitionDirection;
this->state.manuelControll = false;
}
if (this->state.ticksSinceLastStateSwitch >= this->ticksPerFrame){
if (this->autoTransition){
this->state.frameState = IN_TRANSITION;
}
this->state.ticksSinceLastStateSwitch = 0;
}
break;
}
this->display->clear();
this->drawFrame();
if (shouldDrawIndicators) {
this->drawIndicator();
}
this->drawOverlays();
this->display->display();
}
void OLEDDisplayUi::resetState() {
this->state.lastUpdate = 0;
this->state.ticksSinceLastStateSwitch = 0;
this->state.frameState = FIXED;
this->state.currentFrame = 0;
this->state.isIndicatorDrawen = true;
}
void OLEDDisplayUi::drawFrame(){
switch (this->state.frameState){
case IN_TRANSITION: {
float progress = (float) this->state.ticksSinceLastStateSwitch / (float) this->ticksPerTransition;
int16_t x = 0, y = 0, x1 = 0, y1 = 0;
switch(this->frameAnimationDirection){
case SLIDE_LEFT:
x = -this->display->width() * progress;
y = 0;
x1 = x + this->display->width();
y1 = 0;
break;
case SLIDE_RIGHT:
x = this->display->width() * progress;
y = 0;
x1 = x - this->display->width();
y1 = 0;
break;
case SLIDE_UP:
x = 0;
y = -this->display->height() * progress;
x1 = 0;
y1 = y + this->display->height();
break;
case SLIDE_DOWN:
default:
x = 0;
y = this->display->height() * progress;
x1 = 0;
y1 = y - this->display->height();
break;
}
// Invert animation if direction is reversed.
//如果方向调换则动画方向调换
int8_t dir = this->state.frameTransitionDirection >= 0 ? 1 : -1;
x *= dir; y *= dir; x1 *= dir; y1 *= dir;
bool drawenCurrentFrame;
// Prope each frameFunction for the indicator Drawen state
this->enableIndicator();
(this->frameFunctions[this->state.currentFrame])(this->display, &this->state, x, y);
drawenCurrentFrame = this->state.isIndicatorDrawen;
this->enableIndicator();
(this->frameFunctions[this->getNextFrameNumber()])(this->display, &this->state, x1, y1);
// Build up the indicatorDrawState
//指示器绘制状态
if (drawenCurrentFrame && !this->state.isIndicatorDrawen) {
// Drawen now but not next
//本帧显示下帧不显示
this->indicatorDrawState = 2;
} else if (!drawenCurrentFrame && this->state.isIndicatorDrawen) {
// Not drawen now but next
//本帧不显示下帧显示
this->indicatorDrawState = 1;
} else if (!drawenCurrentFrame && !this->state.isIndicatorDrawen) {
// Not drawen in both frames
//都不显示
this->indicatorDrawState = 3;
}
// If the indicator isn't draw in the current frame
// reflect it in state.isIndicatorDrawen
//如果本帧不显示,指示器是否显示。
if (!drawenCurrentFrame) this->state.isIndicatorDrawen = false;
break;
}
case FIXED:
// Always assume that the indicator is drawn!
// And set indicatorDrawState to "not known yet"
//如果指示器已绘制,indicatorDrawState设置为0,0的值是“不知道”,见.h文件。
this->indicatorDrawState = 0;
this->enableIndicator();
(this->frameFunctions[this->state.currentFrame])(this->display, &this->state, 0, 0);
break;
}
}
void OLEDDisplayUi::drawIndicator() {
// Only draw if the indicator is invisible
// for both frames or
// the indiactor is shown and we are IN_TRANSITION
//如果指示器不可见或指示器已显示但是IN_TRANSITION状态,绘制指示器。
if (this->indicatorDrawState == 3 || (!this->state.isIndicatorDrawen && this->state.frameState != IN_TRANSITION)) {
return;
}
uint8_t posOfHighlightFrame = 0;
float indicatorFadeProgress = 0;
// if the indicator needs to be slided in we want to
// highlight the next frame in the transition
//如果指示器需要显示出来,亮光显示下一帧
uint8_t frameToHighlight = this->indicatorDrawState == 1 ? this->getNextFrameNumber() : this->state.currentFrame;
// Calculate the frame that needs to be highlighted
// based on the Direction the indiactor is drawn
//基于指示器绘制的方向计算需要高亮显示的帧
//
switch (this->indicatorDirection){
case LEFT_RIGHT:
posOfHighlightFrame = frameToHighlight;
break;
case RIGHT_LEFT:
default:
posOfHighlightFrame = this->frameCount - frameToHighlight;
break;
}
switch (this->indicatorDrawState) {
case 1: // Indicator was not drawn in this frame but will be in next
// Slide IN
indicatorFadeProgress = 1 - ((float) this->state.ticksSinceLastStateSwitch / (float) this->ticksPerTransition);
break;
case 2: // Indicator was drawn in this frame but not in next
// Slide OUT
indicatorFadeProgress = ((float) this->state.ticksSinceLastStateSwitch / (float) this->ticksPerTransition);
break;
}
//Space between indicators - reduce for small screen sizes
uint16_t indicatorSpacing = 12;
if (this->display->getHeight() < 64 && (this->indicatorPosition == RIGHT || this->indicatorPosition == LEFT)) {
indicatorSpacing = 6;
}
uint16_t frameStartPos = (indicatorSpacing * frameCount / 2);
const uint8_t *image;
uint16_t x = 0,y = 0;
for (uint8_t i = 0; i < this->frameCount; i++) {
switch (this->indicatorPosition){
case TOP:
y = 0 - (8 * indicatorFadeProgress);
x = (this->display->width() / 2) - frameStartPos + 12 * i;
break;
case BOTTOM:
y = (this->display->height() - 8) + (8 * indicatorFadeProgress);
x = (this->display->width() / 2) - frameStartPos + 12 * i;
break;
case RIGHT:
x = (this->display->width() - 8) + (8 * indicatorFadeProgress);
y = (this->display->height() / 2) - frameStartPos + 2 + 12 * i;
break;
case LEFT:
default:
x = 0 - (8 * indicatorFadeProgress);
y = (this->display->height() / 2) - frameStartPos + 2 + indicatorSpacing * i;
break;
}
if (posOfHighlightFrame == i) {
image = this->activeSymbol;
} else {
image = this->inactiveSymbol;
}
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;
return (this->state.currentFrame + this->frameCount + this->state.frameTransitionDirection) % this->frameCount;
}