2023-01-18 17:18:19 +00:00
|
|
|
/* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved
|
|
|
|
* See the LICENSE file for information about the license. */
|
|
|
|
|
|
|
|
#include "app.h"
|
|
|
|
|
|
|
|
/* =========================== Subview handling ================================
|
|
|
|
* Note that these are not the Flipper subviews, but the subview system
|
|
|
|
* implemented inside ProtoView.
|
|
|
|
* ========================================================================== */
|
|
|
|
|
|
|
|
/* Return the ID of the currently selected subview, of the current
|
|
|
|
* view. */
|
2023-01-18 19:25:39 +00:00
|
|
|
int get_current_subview(ProtoViewApp* app) {
|
2023-01-18 17:18:19 +00:00
|
|
|
return app->current_subview[app->current_view];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Called by view rendering callback that has subviews, to show small triangles
|
|
|
|
* facing down/up if there are other subviews the user can access with up
|
|
|
|
* and down. */
|
2023-01-18 19:25:39 +00:00
|
|
|
void show_available_subviews(Canvas* canvas, ProtoViewApp* app, int last_subview) {
|
2023-01-18 17:18:19 +00:00
|
|
|
int subview = get_current_subview(app);
|
2023-01-18 19:25:39 +00:00
|
|
|
if(subview != 0) canvas_draw_triangle(canvas, 120, 5, 8, 5, CanvasDirectionBottomToTop);
|
|
|
|
if(subview != last_subview - 1)
|
|
|
|
canvas_draw_triangle(canvas, 120, 59, 8, 5, CanvasDirectionTopToBottom);
|
2023-01-18 17:18:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle up/down keys when we are in a subview. If the function catched
|
|
|
|
* such keypress, it returns true, so that the actual view input callback
|
|
|
|
* knows it can just return ASAP without doing anything. */
|
2023-01-18 19:25:39 +00:00
|
|
|
bool process_subview_updown(ProtoViewApp* app, InputEvent input, int last_subview) {
|
2023-01-18 17:18:19 +00:00
|
|
|
int subview = get_current_subview(app);
|
2023-01-18 19:25:39 +00:00
|
|
|
if(input.type == InputTypePress) {
|
|
|
|
if(input.key == InputKeyUp) {
|
|
|
|
if(subview != 0) app->current_subview[app->current_view]--;
|
2023-01-18 17:18:19 +00:00
|
|
|
return true;
|
2023-01-18 19:25:39 +00:00
|
|
|
} else if(input.key == InputKeyDown) {
|
|
|
|
if(subview != last_subview - 1) app->current_subview[app->current_view]++;
|
2023-01-18 17:18:19 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ============================= Text input ====================================
|
|
|
|
* Normally we just use our own private UI widgets. However for the text input
|
|
|
|
* widget, that is quite complex, visualizes a keyboard and must be standardized
|
|
|
|
* for user coherent experience, we use the one provided by the Flipper
|
|
|
|
* framework. The following two functions allow to show the keyboard to get
|
|
|
|
* text and later dismiss it.
|
|
|
|
* ========================================================================== */
|
|
|
|
|
|
|
|
/* Show the keyboard, take the user input and store it into the specified
|
|
|
|
* 'buffer' of 'buflen' total bytes. When the user is done, the done_callback
|
|
|
|
* is called passing the application context to it. Such callback needs
|
|
|
|
* to do whatever it wants with the input buffer and dismissi the keyboard
|
|
|
|
* calling: dismiss_keyboard(app);
|
|
|
|
*
|
|
|
|
* Note: if the buffer is not a null-termined zero string, what it contains will
|
|
|
|
* be used as initial input for the user. */
|
2023-01-18 19:25:39 +00:00
|
|
|
void show_keyboard(ProtoViewApp* app, char* buffer, uint32_t buflen, void (*done_callback)(void*)) {
|
2023-01-18 17:18:19 +00:00
|
|
|
app->show_text_input = true;
|
|
|
|
app->text_input_buffer = buffer;
|
|
|
|
app->text_input_buffer_len = buflen;
|
|
|
|
app->text_input_done_callback = done_callback;
|
|
|
|
}
|
|
|
|
|
2023-01-18 19:25:39 +00:00
|
|
|
void dismiss_keyboard(ProtoViewApp* app) {
|
2023-01-18 17:18:19 +00:00
|
|
|
view_dispatcher_stop(app->view_dispatcher);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* =========================== Canvas extensions ============================ */
|
|
|
|
|
2023-01-18 19:25:39 +00:00
|
|
|
void canvas_draw_str_with_border(
|
|
|
|
Canvas* canvas,
|
|
|
|
uint8_t x,
|
|
|
|
uint8_t y,
|
|
|
|
const char* str,
|
|
|
|
Color text_color,
|
|
|
|
Color border_color) {
|
2023-01-18 17:18:19 +00:00
|
|
|
struct {
|
2023-01-18 19:25:39 +00:00
|
|
|
uint8_t x;
|
|
|
|
uint8_t y;
|
|
|
|
} dir[8] = {{-1, -1}, {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}};
|
2023-01-18 17:18:19 +00:00
|
|
|
|
|
|
|
/* Rotate in all the directions writing the same string to create a
|
|
|
|
* border, then write the actual string in the other color in the
|
|
|
|
* middle. */
|
|
|
|
canvas_set_color(canvas, border_color);
|
2023-01-18 19:25:39 +00:00
|
|
|
for(int j = 0; j < 8; j++) canvas_draw_str(canvas, x + dir[j].x, y + dir[j].y, str);
|
2023-01-18 17:18:19 +00:00
|
|
|
canvas_set_color(canvas, text_color);
|
2023-01-18 19:25:39 +00:00
|
|
|
canvas_draw_str(canvas, x, y, str);
|
2023-01-18 17:18:19 +00:00
|
|
|
canvas_set_color(canvas, ColorBlack);
|
|
|
|
}
|