New Apps - Lot 1 (#27)
* New Apps - Lot 1 Trying to mix it up a little with some fun, useful and just weird. Adds more new apps... Brainfuck Breakout Magic 8 Ball Todo List Also re-organised the app name part of main.yml * Fix build? * fixes * and some more * Update Brainfuck.cpp * i heard you like fixes with your fixes * no hard coded paths
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
if (DEFINED ENV{TACTILITY_SDK_PATH})
|
||||
set(TACTILITY_SDK_PATH $ENV{TACTILITY_SDK_PATH})
|
||||
else()
|
||||
set(TACTILITY_SDK_PATH "../../release/TactilitySDK")
|
||||
message(WARNING "TACTILITY_SDK_PATH environment variable is not set, defaulting to ${TACTILITY_SDK_PATH}")
|
||||
endif()
|
||||
|
||||
include("${TACTILITY_SDK_PATH}/TactilitySDK.cmake")
|
||||
set(EXTRA_COMPONENT_DIRS ${TACTILITY_SDK_PATH})
|
||||
|
||||
project(Magic8Ball)
|
||||
tactility_project(Magic8Ball)
|
||||
@@ -0,0 +1,30 @@
|
||||
# Magic 8-Ball
|
||||
|
||||
A digital fortune-telling toy for Tactility.
|
||||
|
||||
## Overview
|
||||
|
||||
Ask a yes/no question, then shake the ball (tap or press a key) to receive one of 20 classic Magic 8-Ball responses. Responses span affirmative, non-committal, and negative categories.
|
||||
|
||||
## Features
|
||||
|
||||
- 20 classic Magic 8-Ball responses
|
||||
- Three response categories: Affirmative (10), Non-committal (5), Negative (5)
|
||||
- Prevents consecutive duplicate answers
|
||||
- Animated ball interface
|
||||
|
||||
## Controls
|
||||
|
||||
- **Touch**: Tap the ball to get a response
|
||||
- **Keyboard**: Enter or Space
|
||||
|
||||
## Responses
|
||||
|
||||
- **Affirmative**: "It is certain", "Without a doubt", "Yes definitely", "Most likely", and more
|
||||
- **Non-committal**: "Reply hazy, try again", "Ask again later", "Better not tell you now", and more
|
||||
- **Negative**: "Don't count on it", "My reply is no", "Very doubtful", and more
|
||||
|
||||
## Requirements
|
||||
|
||||
- Tactility
|
||||
- Input: Touchscreen and/or keyboard
|
||||
@@ -0,0 +1,11 @@
|
||||
file(GLOB_RECURSE SOURCE_FILES
|
||||
Source/*.c*
|
||||
)
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${SOURCE_FILES}
|
||||
# Library headers must be included directly,
|
||||
# because all regular dependencies get stripped by elf_loader's cmake script
|
||||
INCLUDE_DIRS ../../../Libraries/TactilityCpp/Include
|
||||
REQUIRES TactilitySDK
|
||||
)
|
||||
@@ -0,0 +1,144 @@
|
||||
#include "Magic8Ball.h"
|
||||
#include <tt_lvgl_toolbar.h>
|
||||
#include <tt_lvgl_keyboard.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
/* ── Responses ─────────────────────────────────────────────────────── */
|
||||
|
||||
static const char* responses[] = {
|
||||
/* Affirmative (10) */
|
||||
"It is certain.",
|
||||
"It is decidedly so.",
|
||||
"Without a doubt.",
|
||||
"Yes, definitely.",
|
||||
"You may rely on it.",
|
||||
"As I see it, yes.",
|
||||
"Most likely.",
|
||||
"Outlook good.",
|
||||
"Yes.",
|
||||
"Signs point to yes.",
|
||||
/* Non-committal (5) */
|
||||
"Reply hazy, try again.",
|
||||
"Ask again later.",
|
||||
"Better not tell you now.",
|
||||
"Cannot predict now.",
|
||||
"Concentrate and ask again.",
|
||||
/* Negative (5) */
|
||||
"Don't count on it.",
|
||||
"My reply is no.",
|
||||
"My sources say no.",
|
||||
"Outlook not so good.",
|
||||
"Very doubtful.",
|
||||
};
|
||||
|
||||
#define NUM_RESPONSES (sizeof(responses) / sizeof(responses[0]))
|
||||
|
||||
static const char* getInputHint() {
|
||||
if (tt_lvgl_hardware_keyboard_is_available()) {
|
||||
return "Touch or press Space to ask";
|
||||
}
|
||||
return "Touch the ball to ask";
|
||||
}
|
||||
|
||||
/* ── Methods ──────────────────────────────────────────────────────── */
|
||||
|
||||
void Magic8Ball::revealAnswer() {
|
||||
if (!seeded) {
|
||||
srand((unsigned)time(NULL));
|
||||
seeded = true;
|
||||
}
|
||||
|
||||
int idx;
|
||||
do {
|
||||
idx = rand() % NUM_RESPONSES;
|
||||
} while (idx == lastIdx && NUM_RESPONSES > 1);
|
||||
lastIdx = idx;
|
||||
|
||||
lv_label_set_text(answerLabel, responses[idx]);
|
||||
lv_label_set_text(hintLabel, getInputHint());
|
||||
}
|
||||
|
||||
void Magic8Ball::onBallClick(lv_event_t* e) {
|
||||
auto* self = (Magic8Ball*)lv_event_get_user_data(e);
|
||||
self->revealAnswer();
|
||||
}
|
||||
|
||||
void Magic8Ball::onKey(lv_event_t* e) {
|
||||
auto* self = (Magic8Ball*)lv_event_get_user_data(e);
|
||||
uint32_t key = lv_event_get_key(e);
|
||||
if (key == LV_KEY_ENTER || key == ' ') {
|
||||
self->revealAnswer();
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Lifecycle ────────────────────────────────────────────────────── */
|
||||
|
||||
void Magic8Ball::onShow(AppHandle app, lv_obj_t* parent) {
|
||||
lv_obj_remove_flag(parent, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
|
||||
/* Toolbar */
|
||||
lv_obj_t* toolbar = tt_lvgl_toolbar_create_for_app(parent, app);
|
||||
lv_obj_align(toolbar, LV_ALIGN_TOP_MID, 0, 0);
|
||||
|
||||
/* Main container */
|
||||
lv_obj_t* cont = lv_obj_create(parent);
|
||||
lv_obj_set_width(cont, LV_PCT(100));
|
||||
lv_obj_set_flex_grow(cont, 1);
|
||||
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(cont, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_align_to(cont, toolbar, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
|
||||
lv_obj_set_style_pad_all(cont, 2, 0);
|
||||
lv_obj_remove_flag(cont, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_set_style_border_width(cont, 0, 0);
|
||||
lv_obj_set_style_bg_color(cont, lv_color_hex(0x000000), 0);
|
||||
lv_obj_set_style_bg_opa(cont, LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_radius(cont, 0, 0);
|
||||
|
||||
/* "8" ball circle */
|
||||
ballObj = lv_obj_create(cont);
|
||||
lv_obj_set_size(ballObj, 120, 120);
|
||||
lv_obj_set_style_radius(ballObj, LV_RADIUS_CIRCLE, 0);
|
||||
lv_obj_set_style_bg_color(ballObj, lv_color_make(0x10, 0x10, 0x30), 0);
|
||||
lv_obj_set_style_bg_opa(ballObj, LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_border_color(ballObj, lv_color_make(0x40, 0x40, 0x80), 0);
|
||||
lv_obj_set_style_border_width(ballObj, 3, 0);
|
||||
lv_obj_remove_flag(ballObj, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_set_flex_flow(ballObj, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(ballObj, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
|
||||
/* Answer text inside the ball */
|
||||
answerLabel = lv_label_create(ballObj);
|
||||
lv_label_set_text(answerLabel, "8");
|
||||
lv_obj_set_style_text_color(answerLabel, lv_color_hex(0xFFFFFF), 0);
|
||||
lv_obj_set_style_text_font(answerLabel, lv_font_get_default(), 0);
|
||||
lv_obj_set_style_text_align(answerLabel, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_set_width(answerLabel, 100);
|
||||
lv_label_set_long_mode(answerLabel, LV_LABEL_LONG_WRAP);
|
||||
|
||||
/* Hint text below the ball */
|
||||
hintLabel = lv_label_create(cont);
|
||||
lv_label_set_text(hintLabel, getInputHint());
|
||||
lv_obj_set_style_text_color(hintLabel, lv_color_make(0x88, 0x88, 0x88), 0);
|
||||
lv_obj_set_style_text_font(hintLabel, lv_font_get_default(), 0);
|
||||
|
||||
/* Make the ball tappable / also space */
|
||||
lv_obj_add_flag(ballObj, LV_OBJ_FLAG_CLICKABLE);
|
||||
lv_obj_add_event_cb(ballObj, onBallClick, LV_EVENT_CLICKED, this);
|
||||
|
||||
/* Keyboard support */
|
||||
lv_group_t* grp = lv_group_get_default();
|
||||
if (grp) lv_group_add_obj(grp, ballObj);
|
||||
lv_obj_add_event_cb(ballObj, onKey, LV_EVENT_KEY, this);
|
||||
}
|
||||
|
||||
void Magic8Ball::onHide(AppHandle app) {
|
||||
lv_group_t* grp = lv_group_get_default();
|
||||
if (grp && ballObj) {
|
||||
lv_group_remove_obj(ballObj);
|
||||
}
|
||||
answerLabel = nullptr;
|
||||
hintLabel = nullptr;
|
||||
ballObj = nullptr;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <lvgl.h>
|
||||
#include <TactilityCpp/App.h>
|
||||
|
||||
class Magic8Ball final : public App {
|
||||
|
||||
private:
|
||||
// UI pointers (nulled in onHide)
|
||||
lv_obj_t* answerLabel = nullptr;
|
||||
lv_obj_t* hintLabel = nullptr;
|
||||
lv_obj_t* ballObj = nullptr;
|
||||
|
||||
// State
|
||||
int lastIdx = -1;
|
||||
bool seeded = false;
|
||||
|
||||
void revealAnswer();
|
||||
|
||||
static void onBallClick(lv_event_t* e);
|
||||
static void onKey(lv_event_t* e);
|
||||
|
||||
public:
|
||||
void onShow(AppHandle context, lv_obj_t* parent) override;
|
||||
void onHide(AppHandle context) override;
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
#include "Magic8Ball.h"
|
||||
#include <TactilityCpp/App.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
registerApp<Magic8Ball>();
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
[manifest]
|
||||
version=0.1
|
||||
[target]
|
||||
sdk=0.7.0-dev
|
||||
platforms=esp32,esp32s3,esp32c6,esp32p4
|
||||
[app]
|
||||
id=one.tactility.magic8ball
|
||||
versionName=0.1.0
|
||||
versionCode=1
|
||||
name=Magic 8-Ball
|
||||
Reference in New Issue
Block a user