| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- #include <furi.h>
- #include <furi_hal.h>
- #include <gui/gui.h>
- #include <gui/elements.h>
- #include <gui/icon.h>
- #include <input/input.h>
- #include <notification/notification.h>
- #include <notification/notification_messages.h>
- #include <stdbool.h> // Header-file for boolean data-type.
- #include <stdio.h>
- #include <string.h>
- #include "etch_icons.h"
- #include <assets_icons.h>
- #define WIDTH 64
- #define HEIGHT 32
- const int brush_size = 2;
- typedef struct selected_position {
- int x;
- int y;
- } selected_position;
- typedef struct {
- FuriMutex* mutex;
- selected_position selected;
- bool board[64][32];
- bool isDrawing;
- bool showWelcome;
- } EtchData;
- // Sequence to indicate that drawing is enabled.
- const NotificationSequence sequence_begin_draw = {
- &message_display_backlight_on,
- // Vibrate to indicate that drawing is enabled.
- &message_vibro_on,
- &message_note_g5,
- &message_delay_50,
- &message_note_c6,
- &message_delay_50,
- &message_note_e5,
- &message_vibro_off,
- &message_sound_off,
- NULL,
- };
- // sequence to indicate that drawing is disabled
- const NotificationSequence sequence_end_draw = {
- &message_red_0,
- // Indicate that drawing is disabled.
- &message_vibro_on,
- &message_note_g5,
- &message_delay_50,
- &message_note_e5,
- &message_delay_50,
- &message_vibro_off,
- &message_sound_off,
- &message_do_not_reset,
- NULL,
- };
- // Indicate that drawing is enabled.
- const NotificationSequence sequence_draw_enabled = {
- &message_red_255,
- &message_do_not_reset,
- NULL,
- };
- // Indicate that drawing is disabled.
- const NotificationSequence sequence_draw_disabled = {
- &message_red_0,
- &message_do_not_reset,
- NULL,
- };
- const NotificationSequence sequence_cleanup = {
- &message_red_0,
- &message_green_0,
- &message_blue_0,
- &message_sound_off,
- &message_vibro_off,
- NULL,
- };
- void etch_draw_callback(Canvas* canvas, void* ctx) {
- furi_assert(ctx);
- const EtchData* etch_state = ctx;
- furi_mutex_acquire(etch_state->mutex, FuriWaitForever);
- canvas_clear(canvas);
- // Show Welcome Message
- if(etch_state->showWelcome) {
- // Draw Etch A Sketch frame
- canvas_draw_frame(canvas, 5, 3, 119, 55); // Border
- canvas_draw_icon(canvas, 8, 50, &I_Ok_btn_pressed_13x13); // Left Knob
- canvas_draw_icon(canvas, 107, 50, &I_Ok_btn_pressed_13x13); // Right Knob
- // Draw Etch A Sketch text banner
- canvas_set_font(canvas, FontSecondary);
- canvas_draw_str(canvas, 36, 15, "Etch A Sketch");
- // Draw Etch A Sketch instructions "Hold Back to clear"
- canvas_set_font(canvas, FontSecondary);
- canvas_draw_str(canvas, 31, 26, "* Hold ");
- canvas_draw_icon(canvas, 59, 18, &I_Pin_back_arrow_10x8);
- canvas_set_font(canvas, FontSecondary);
- canvas_draw_str(canvas, 72, 26, "to clear");
- // Draw Etch A Sketch instructions "Hold OK button to draw"
- canvas_set_font(canvas, FontSecondary);
- canvas_draw_str(canvas, 31, 37, "* Hold");
- canvas_draw_icon(canvas, 61, 30, &I_ButtonCenter_7x7);
- canvas_set_font(canvas, FontSecondary);
- canvas_draw_str(canvas, 72, 37, "to draw");
- }
- canvas_set_color(canvas, ColorBlack);
- //draw the canvas(64x32) on screen(144x64) using brush_size*brush_size tiles
- for(int y = 0; y < 32; y++) {
- for(int x = 0; x < 64; x++) {
- if(etch_state->board[x][y]) {
- canvas_draw_box(canvas, x * brush_size, y * brush_size, 2, 2);
- }
- }
- }
- //draw cursor as a brush_size by brush_size black box
- canvas_set_color(canvas, ColorBlack);
- canvas_draw_box(
- canvas,
- etch_state->selected.x * brush_size,
- etch_state->selected.y * brush_size,
- brush_size,
- brush_size);
- //release the mutex
- furi_mutex_release(etch_state->mutex);
- }
- void etch_input_callback(InputEvent* input_event, void* ctx) {
- furi_assert(ctx);
- FuriMessageQueue* event_queue = ctx;
- furi_message_queue_put(event_queue, input_event, FuriWaitForever);
- }
- int32_t etch_a_sketch_app(void* p) {
- UNUSED(p);
- FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
- EtchData* etch_state = malloc(sizeof(EtchData));
- etch_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
- if(!etch_state->mutex) {
- FURI_LOG_E("etch", "cannot create mutex\r\n");
- free(etch_state);
- return -1;
- }
- // Configure view port
- ViewPort* view_port = view_port_alloc();
- view_port_draw_callback_set(view_port, etch_draw_callback, etch_state);
- view_port_input_callback_set(view_port, etch_input_callback, event_queue);
- // Register view port in GUI
- Gui* gui = furi_record_open(RECORD_GUI);
- gui_add_view_port(gui, view_port, GuiLayerFullscreen);
- NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
- InputEvent event;
- // Show Welcome Banner
- etch_state->showWelcome = true;
- while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) {
- //break out of the loop if the back key is pressed
- if(event.key == InputKeyBack && event.type == InputTypeShort) {
- break;
- }
- // Clear
- // TODO: Do animation of shaking board
- if(event.key == InputKeyBack && event.type == InputTypeLong) {
- etch_state->showWelcome = false;
- etch_state->board[1][1] = true;
- for(int y = 0; y < 32; y++) {
- for(int x = 0; x < 64; x++) {
- etch_state->board[x][y] = false;
- }
- }
- view_port_update(view_port);
- }
- // Keep LED on while drawing
- if(etch_state->isDrawing) {
- notification_message(notification, &sequence_draw_enabled);
- } else {
- notification_message(notification, &sequence_draw_disabled);
- }
- // Single Dot Select
- if(event.key == InputKeyOk && event.type == InputTypeShort) {
- etch_state->board[etch_state->selected.x][etch_state->selected.y] =
- !etch_state->board[etch_state->selected.x][etch_state->selected.y];
- }
- // Start Drawing
- if(event.key == InputKeyOk && event.type == InputTypeLong) {
- // notification_message(furi_record_open(RECORD_NOTIFICATION), &sequence_begin_draw);
- notification_message(notification, &sequence_begin_draw);
- if(etch_state->isDrawing) {
- // We're ending the drawing
- notification_message(notification, &sequence_end_draw);
- }
- etch_state->isDrawing = !etch_state->isDrawing;
- etch_state->board[etch_state->selected.x][etch_state->selected.y] = true;
- view_port_update(view_port);
- }
- //check the key pressed and change x and y accordingly
- if(event.type == InputTypeShort || event.type == InputTypeRepeat ||
- event.type == InputTypeLong) {
- switch(event.key) {
- case InputKeyUp:
- etch_state->selected.y -= 1;
- break;
- case InputKeyDown:
- etch_state->selected.y += 1;
- break;
- case InputKeyLeft:
- etch_state->selected.x -= 1;
- break;
- case InputKeyRight:
- etch_state->selected.x += 1;
- break;
- default:
- break;
- }
- //check if cursor position is out of bounds and reset it to the closest position
- if(etch_state->selected.x < 0) {
- etch_state->selected.x = 0;
- }
- if(etch_state->selected.x > 61) {
- etch_state->selected.x = 61;
- }
- if(etch_state->selected.y < 0) {
- etch_state->selected.y = 0;
- }
- if(etch_state->selected.y > 31) {
- etch_state->selected.y = 31;
- }
- if(etch_state->isDrawing == true) {
- etch_state->board[etch_state->selected.x][etch_state->selected.y] = true;
- }
- view_port_update(view_port);
- }
- }
- notification_message(notification, &sequence_cleanup);
- gui_remove_view_port(gui, view_port);
- view_port_free(view_port);
- furi_mutex_free(etch_state->mutex);
- furi_message_queue_free(event_queue);
- furi_record_close(RECORD_NOTIFICATION);
- furi_record_close(RECORD_GUI);
- free(etch_state);
- return 0;
- }
|