-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
940 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
#include "combo.h" | ||
#include "utils/combo/core/aggregator.h" | ||
#include "utils/combo/one_button.h" | ||
#include "utils/combo/one_hold_down_button.h" | ||
#include "utils/combo/sequence_buttons.h" | ||
#include "utils/combo/concurrent_buttons.h" | ||
|
||
#define SECONDS_FOR_EXIT 3 | ||
|
||
using lilka::Alignment; | ||
using lilka::Button; | ||
|
||
uint8_t leftSecondsForExit = SECONDS_FOR_EXIT; | ||
bool exitApp = false; | ||
uint8_t currentScene = 0; | ||
|
||
void exit_process_handler(const Button button, const ButtonStage stage, uint16_t leftTimeToComplete) { | ||
leftSecondsForExit = leftTimeToComplete / 1000; | ||
} | ||
|
||
void exit_reset_handler() { | ||
leftSecondsForExit = SECONDS_FOR_EXIT; | ||
} | ||
|
||
void exit_completed_handler() { | ||
exitApp = true; | ||
} | ||
|
||
void completed_handler() { | ||
currentScene++; | ||
} | ||
|
||
ComboApp::ComboApp() : App("Combo") { | ||
leftSecondsForExit = SECONDS_FOR_EXIT; | ||
exitApp = false; | ||
currentScene = 0; | ||
} | ||
|
||
void ComboApp::run() { | ||
ComboAggregator comboAggregator; | ||
lilka::Canvas buffer(canvas->width(), canvas->height()); | ||
|
||
ComboOneHoldDownButton comboExit(Button::SELECT, SECONDS_FOR_EXIT * 1000); | ||
comboExit.setAutoReset(false); | ||
comboExit.setCompletedEventHandler(exit_completed_handler); | ||
comboExit.setResetEventHandler(exit_reset_handler); | ||
comboExit.setProgressEventHandler(exit_process_handler); | ||
comboAggregator.add(&comboExit); | ||
|
||
ComboOneButton comboContinue(Button::START); | ||
comboContinue.setAutoStart(false); | ||
comboContinue.setAutoReset(false); | ||
comboContinue.setCompletedEventHandler(completed_handler); | ||
comboAggregator.add(&comboContinue); | ||
|
||
ComboOneButton comboScene1PressA(Button::A); | ||
comboScene1PressA.setAutoStart(false); | ||
comboScene1PressA.setAutoReset(false); | ||
comboScene1PressA.setCompletedEventHandler(completed_handler); | ||
comboAggregator.add(&comboScene1PressA); | ||
|
||
ComboOneHoldDownButton comboScene2HoldAny(Button::ANY, 1000); | ||
comboScene2HoldAny.setAutoStart(false); | ||
comboScene2HoldAny.setAutoReset(false); | ||
comboScene2HoldAny.setCompletedEventHandler(completed_handler); | ||
comboAggregator.add(&comboScene2HoldAny); | ||
|
||
ComboConcurrentButtons comboScene3UpB({Button::UP, Button::B}); | ||
comboScene3UpB.setAutoStart(false); | ||
comboScene3UpB.setAutoReset(false); | ||
comboScene3UpB.setCompletedEventHandler(completed_handler); | ||
comboAggregator.add(&comboScene3UpB); | ||
|
||
ComboButtonSequence comboSequenceLast( | ||
{Button::DOWN, Button::UP, Button::UP, Button::DOWN, Button::A, Button::B, Button::B, Button::A} | ||
); | ||
comboSequenceLast.setAutoStart(false); | ||
comboSequenceLast.setAutoReset(false); | ||
comboSequenceLast.setCompletedEventHandler(completed_handler); | ||
comboAggregator.add(&comboSequenceLast); | ||
|
||
while (!exitApp) { | ||
lilka::State st = lilka::controller.getState(); | ||
comboAggregator.loop(st); | ||
|
||
buffer.fillScreen(lilka::colors::Black); | ||
mainUI(buffer, st); | ||
|
||
switch (currentScene) { | ||
case 0: | ||
comboContinue.start(); | ||
scene_0(buffer, st); | ||
break; | ||
case 1: | ||
comboScene1PressA.start(); | ||
scene_1(buffer, st); | ||
break; | ||
case 2: | ||
comboScene2HoldAny.start(); | ||
scene_2(buffer, st); | ||
break; | ||
case 3: | ||
comboScene3UpB.start(); | ||
scene_3(buffer, st); | ||
break; | ||
case 4: | ||
comboSequenceLast.setTimeout(750); | ||
comboSequenceLast.start(); | ||
scene_4(buffer, st, 750); | ||
break; | ||
case 5: | ||
comboSequenceLast.setTimeout(500); | ||
if (comboSequenceLast.isCompleted()) { | ||
comboSequenceLast.reset(); | ||
} | ||
comboSequenceLast.start(); | ||
scene_4(buffer, st, 500); | ||
break; | ||
case 6: | ||
comboSequenceLast.setTimeout(250); | ||
if (comboSequenceLast.isCompleted()) { | ||
comboSequenceLast.reset(); | ||
} | ||
comboSequenceLast.start(); | ||
scene_4(buffer, st, 250); | ||
break; | ||
case 7: | ||
scene_final(buffer, st); | ||
break; | ||
default: | ||
break; | ||
} | ||
canvas->drawCanvas(&buffer); | ||
queueDraw(); | ||
vTaskDelay(1 / portTICK_PERIOD_MS); | ||
} | ||
} | ||
|
||
void ComboApp::mainUI(lilka::Canvas& buffer, lilka::State& st) { | ||
uint16_t hor_center = canvas->width() / 2; | ||
lilka::display.setFont(FONT_10x20_MONO); | ||
buffer.drawTextAligned("Demo Combo", hor_center, 20, Alignment::ALIGN_CENTER, Alignment::ALIGN_START); | ||
lilka::display.setFont(FONT_8x13_MONO); | ||
buffer.drawTextAligned( | ||
"Для виходу затисніть", | ||
hor_center, | ||
canvas->height() - 40, | ||
lilka::Alignment::ALIGN_CENTER, | ||
lilka::Alignment::ALIGN_START | ||
); | ||
|
||
const char* pressByExitMessage = "[SELECT] на %d сек"; | ||
char pressByExit[strlen(pressByExitMessage)]; | ||
sprintf(pressByExit, pressByExitMessage, leftSecondsForExit); | ||
buffer.drawTextAligned( | ||
pressByExit, hor_center, canvas->height() - 20, Alignment::ALIGN_CENTER, Alignment::ALIGN_START | ||
); | ||
} | ||
|
||
void ComboApp::scene_0(lilka::Canvas& buffer, lilka::State& st) { | ||
uint16_t hor_center = canvas->width() / 2; | ||
lilka::display.setFont(FONT_8x13_MONO); | ||
buffer.drawTextAligned("Натисніть [START]", hor_center, 90, Alignment::ALIGN_CENTER, Alignment::ALIGN_START); | ||
|
||
buffer.drawTextAligned("для продовження", hor_center, 110, Alignment::ALIGN_CENTER, Alignment::ALIGN_START); | ||
} | ||
|
||
void ComboApp::scene_1(lilka::Canvas& buffer, lilka::State& st) { | ||
uint16_t hor_center = canvas->width() / 2; | ||
lilka::display.setFont(FONT_8x13_MONO); | ||
buffer.drawTextAligned("Натисніть", hor_center, 90, Alignment::ALIGN_CENTER, Alignment::ALIGN_START); | ||
|
||
buffer.drawTextAligned("[A]", hor_center, 110, Alignment::ALIGN_CENTER, Alignment::ALIGN_START); | ||
} | ||
|
||
void ComboApp::scene_2(lilka::Canvas& buffer, lilka::State& st) { | ||
uint16_t hor_center = canvas->width() / 2; | ||
lilka::display.setFont(FONT_8x13_MONO); | ||
buffer.drawTextAligned("Затисніть будь-яку", hor_center, 90, Alignment::ALIGN_CENTER, Alignment::ALIGN_START); | ||
|
||
buffer.drawTextAligned("кнопку на 1 сек", hor_center, 110, Alignment::ALIGN_CENTER, Alignment::ALIGN_START); | ||
} | ||
|
||
void ComboApp::scene_3(lilka::Canvas& buffer, lilka::State& st) { | ||
uint16_t hor_center = canvas->width() / 2; | ||
lilka::display.setFont(FONT_8x13_MONO); | ||
buffer.drawTextAligned("Натисніть разом", hor_center, 90, Alignment::ALIGN_CENTER, Alignment::ALIGN_START); | ||
|
||
buffer.drawTextAligned("[UP] + [B]", hor_center, 110, Alignment::ALIGN_CENTER, Alignment::ALIGN_START); | ||
} | ||
|
||
void ComboApp::scene_4(lilka::Canvas& buffer, lilka::State& st, int timeout) { | ||
uint16_t hor_center = canvas->width() / 2; | ||
lilka::display.setFont(FONT_8x13_MONO); | ||
buffer.drawTextAligned("DOWN,UP,UP,DOWN,A,B,B,A", hor_center, 90, Alignment::ALIGN_CENTER, Alignment::ALIGN_START); | ||
|
||
const char* txt = "Таймаут %d мс"; | ||
char bf[100]; | ||
sprintf(bf, txt, timeout); | ||
buffer.drawTextAligned(bf, hor_center, 110, Alignment::ALIGN_CENTER, Alignment::ALIGN_START); | ||
} | ||
|
||
void ComboApp::scene_final(lilka::Canvas& buffer, lilka::State& st) { | ||
uint16_t hor_center = canvas->width() / 2; | ||
lilka::display.setFont(FONT_8x13_MONO); | ||
buffer.drawTextAligned("Кінець!", hor_center, 90, Alignment::ALIGN_CENTER, Alignment::ALIGN_START); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#pragma once | ||
|
||
#include "app.h" | ||
|
||
class ComboApp : public App { | ||
public: | ||
ComboApp(); | ||
|
||
private: | ||
void run() override; | ||
|
||
void mainUI(lilka::Canvas& buffer, lilka::State& st); | ||
void scene_0(lilka::Canvas& buffer, lilka::State& st); | ||
void scene_1(lilka::Canvas& buffer, lilka::State& st); | ||
void scene_2(lilka::Canvas& buffer, lilka::State& st); | ||
void scene_3(lilka::Canvas& buffer, lilka::State& st); | ||
void scene_4(lilka::Canvas& buffer, lilka::State& st, int timeout); | ||
void scene_final(lilka::Canvas& buffer, lilka::State& st); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
#include "concurrent_buttons.h" | ||
|
||
ComboConcurrentButtons::ComboConcurrentButtons(std::initializer_list<Button> buttonList) : | ||
ComboBase(), | ||
NUM_BUTTONS(buttonList.size() ? buttonList.size() : 1), | ||
buttons(new Button[NUM_BUTTONS]), | ||
progressEventHandler(nullptr) { | ||
initButtons(buttonList); | ||
} | ||
|
||
ComboConcurrentButtons::~ComboConcurrentButtons() { | ||
buttons.reset(); | ||
progressEventHandler = nullptr; | ||
} | ||
|
||
void ComboConcurrentButtons::initButtons(std::initializer_list<Button> buttonList) { | ||
if (buttonList.size()) { | ||
auto it = buttonList.begin(); | ||
for (size_t i = 0; i < NUM_BUTTONS && it != buttonList.end(); ++i, ++it) { | ||
buttons[i] = *it; | ||
} | ||
} else { | ||
buttons[0] = Button::ANY; | ||
} | ||
buttonStage.changeButtonAndReset(Button::ANY); | ||
} | ||
|
||
void ComboConcurrentButtons::onProgress() { | ||
if (!progressEventHandler) { | ||
return; | ||
} | ||
progressEventHandler(NUM_BUTTONS, buttons.get(), buttonStage.getStage()); | ||
} | ||
|
||
void ComboConcurrentButtons::loopAction(State& state) { | ||
if (buttonStage.isReleased()) { | ||
return; | ||
} | ||
_StateButtons& buttonStates = *reinterpret_cast<_StateButtons*>(&state); | ||
switch (buttonStage.getStage()) { | ||
case WAITING: | ||
checkAllButtonsPressed(buttonStates); | ||
break; | ||
case PRESSED: | ||
checkAllButtonsReleased(buttonStates); | ||
break; | ||
case RELEASED: | ||
default: | ||
break; | ||
} | ||
} | ||
|
||
void ComboConcurrentButtons::resetAction() { | ||
buttonStage.reset(); | ||
} | ||
|
||
bool ComboConcurrentButtons::isTargetButton(size_t buttonIndex) { | ||
for (size_t i = 0; i < NUM_BUTTONS; i++) { | ||
if (buttons[i] == Button::ANY || buttonIndex == buttons[i]) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
bool ComboConcurrentButtons::isNonTargetButtonsPressed(_StateButtons& buttonStates) { | ||
if(!buttonStates[Button::ANY].pressed) { | ||
return false; | ||
} | ||
size_t size = Button::COUNT - 1; // exclude ANY button | ||
for (size_t i = 0; i < size; i++) { | ||
if (buttonStates[i].pressed && !isTargetButton(i)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
void ComboConcurrentButtons::checkAllButtonsPressed(_StateButtons& buttonStates) { | ||
if (isNonTargetButtonsPressed(buttonStates)) { | ||
return; | ||
} | ||
bool allButtonsPressed = true; | ||
bool anyButtonJustPressed = false; | ||
for (size_t i = 0; i < NUM_BUTTONS; i++) { | ||
ButtonState& bs = buttonStates[buttons[i]]; | ||
if (!bs.pressed) { | ||
allButtonsPressed = false; | ||
break; | ||
} | ||
if (bs.justPressed) { | ||
anyButtonJustPressed = true; | ||
} | ||
} | ||
if (allButtonsPressed && anyButtonJustPressed) { | ||
buttonStage.setStage(PRESSED); | ||
onProgress(); | ||
complete(); | ||
} | ||
} | ||
|
||
void ComboConcurrentButtons::checkAllButtonsReleased(_StateButtons& buttonStates) { | ||
bool allButtonsReleased = true; | ||
bool anyButtonJustReleased = false; | ||
for (size_t i = 0; i < NUM_BUTTONS; i++) { | ||
ButtonState& bs = buttonStates[buttons[i]]; | ||
if (bs.pressed) { | ||
allButtonsReleased = false; | ||
break; | ||
} | ||
if (bs.justReleased) { | ||
anyButtonJustReleased = true; | ||
} | ||
} | ||
if (allButtonsReleased && anyButtonJustReleased) { | ||
buttonStage.setStage(RELEASED); | ||
onProgress(); | ||
checkAutoReset(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
#pragma once | ||
|
||
#include "core/core.h" | ||
#include "core/stage.h" | ||
|
||
using ComboConcurrentButtonsProgressEventHandler = | ||
void (*)(const size_t numOfButtons, const Button buttons[], const ButtonStage stage); | ||
|
||
class ComboConcurrentButtons : public ComboBase { | ||
public: | ||
ComboConcurrentButtons(std::initializer_list<Button> buttonList); | ||
~ComboConcurrentButtons(); | ||
|
||
void setProgressEventHandler(ComboConcurrentButtonsProgressEventHandler handler) { | ||
progressEventHandler = handler; | ||
} | ||
|
||
private: | ||
const size_t NUM_BUTTONS; | ||
std::unique_ptr<Button[]> buttons; | ||
ComboButtonStage buttonStage; | ||
ComboConcurrentButtonsProgressEventHandler progressEventHandler; | ||
|
||
void initButtons(std::initializer_list<Button> buttonList); | ||
bool isTargetButton(size_t buttonIndex); | ||
bool isNonTargetButtonsPressed(_StateButtons& buttonStates); | ||
void checkAllButtonsPressed(_StateButtons& buttonStates); | ||
void checkAllButtonsReleased(_StateButtons& buttonStates); | ||
void onProgress(); | ||
void loopAction(State& state) override; | ||
void resetAction() override; | ||
}; |
Oops, something went wrong.