|
|
|
|
@@ -2,12 +2,12 @@
|
|
|
|
|
#include <furi.h>
|
|
|
|
|
#include <assets_icons.h>
|
|
|
|
|
|
|
|
|
|
#define get_state(m, r, c) \
|
|
|
|
|
((m)->row == (r) && (m)->column == (c) ? \
|
|
|
|
|
((m)->editing ? EditStateActiveEditing : EditStateActive) : \
|
|
|
|
|
EditStateNone)
|
|
|
|
|
|
|
|
|
|
#define ROW_0_Y (10)
|
|
|
|
|
#define get_state(m, r, c, f) \
|
|
|
|
|
((m)->editable.f ? ((m)->row == (r) && (m)->column == (c) ? \
|
|
|
|
|
((m)->editing ? EditStateActiveEditing : EditStateActive) : \
|
|
|
|
|
EditStateNone) : \
|
|
|
|
|
EditStateDisabled)
|
|
|
|
|
#define ROW_0_Y (9)
|
|
|
|
|
#define ROW_0_H (20)
|
|
|
|
|
|
|
|
|
|
#define ROW_1_Y (40)
|
|
|
|
|
@@ -28,6 +28,15 @@ typedef struct {
|
|
|
|
|
uint8_t column;
|
|
|
|
|
bool editing;
|
|
|
|
|
|
|
|
|
|
struct {
|
|
|
|
|
bool year;
|
|
|
|
|
bool month;
|
|
|
|
|
bool day;
|
|
|
|
|
bool hour;
|
|
|
|
|
bool minute;
|
|
|
|
|
bool second;
|
|
|
|
|
} editable;
|
|
|
|
|
|
|
|
|
|
DateTimeChangedCallback changed_callback;
|
|
|
|
|
DateTimeDoneCallback done_callback;
|
|
|
|
|
void* callback_context;
|
|
|
|
|
@@ -37,6 +46,7 @@ typedef enum {
|
|
|
|
|
EditStateNone,
|
|
|
|
|
EditStateActive,
|
|
|
|
|
EditStateActiveEditing,
|
|
|
|
|
EditStateDisabled
|
|
|
|
|
} EditState;
|
|
|
|
|
|
|
|
|
|
static inline void date_time_input_cleanup_date(DateTime* dt) {
|
|
|
|
|
@@ -59,15 +69,17 @@ static inline void date_time_input_draw_block(
|
|
|
|
|
furi_assert(text);
|
|
|
|
|
|
|
|
|
|
canvas_set_color(canvas, ColorBlack);
|
|
|
|
|
if(state != EditStateNone) {
|
|
|
|
|
if(state == EditStateActiveEditing) {
|
|
|
|
|
canvas_draw_icon(canvas, x + w / 2 - 2, y - 1 - 3, &I_SmallArrowUp_3x5);
|
|
|
|
|
canvas_draw_icon(canvas, x + w / 2 - 2, y + h + 1, &I_SmallArrowDown_3x5);
|
|
|
|
|
if(state != EditStateDisabled) {
|
|
|
|
|
if(state != EditStateNone) {
|
|
|
|
|
if(state == EditStateActiveEditing) {
|
|
|
|
|
canvas_draw_icon(canvas, x + w / 2 - 2, y - 1 - 3, &I_SmallArrowUp_3x5);
|
|
|
|
|
canvas_draw_icon(canvas, x + w / 2 - 2, y + h + 1, &I_SmallArrowDown_3x5);
|
|
|
|
|
}
|
|
|
|
|
canvas_draw_rbox(canvas, x, y, w, h, 1);
|
|
|
|
|
canvas_set_color(canvas, ColorWhite);
|
|
|
|
|
} else {
|
|
|
|
|
canvas_draw_rframe(canvas, x, y, w, h, 1);
|
|
|
|
|
}
|
|
|
|
|
canvas_draw_rbox(canvas, x, y, w, h, 1);
|
|
|
|
|
canvas_set_color(canvas, ColorWhite);
|
|
|
|
|
} else {
|
|
|
|
|
canvas_draw_rframe(canvas, x, y, w, h, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
canvas_set_font(canvas, font);
|
|
|
|
|
@@ -88,19 +100,19 @@ static void date_time_input_draw_time_callback(Canvas* canvas, DateTimeInputMode
|
|
|
|
|
|
|
|
|
|
snprintf(buffer, sizeof(buffer), "%02u", model->datetime->hour);
|
|
|
|
|
date_time_input_draw_block(
|
|
|
|
|
canvas, 30, ROW_1_Y, 28, ROW_1_H, FontBigNumbers, get_state(model, 1, 0), buffer);
|
|
|
|
|
canvas, 30, ROW_1_Y, 28, ROW_1_H, FontBigNumbers, get_state(model, 1, 0, hour), buffer);
|
|
|
|
|
canvas_draw_box(canvas, 60, ROW_1_Y + ROW_1_H - 7, 2, 2);
|
|
|
|
|
canvas_draw_box(canvas, 60, ROW_1_Y + ROW_1_H - 7 - 6, 2, 2);
|
|
|
|
|
|
|
|
|
|
snprintf(buffer, sizeof(buffer), "%02u", model->datetime->minute);
|
|
|
|
|
date_time_input_draw_block(
|
|
|
|
|
canvas, 64, ROW_1_Y, 28, ROW_1_H, FontBigNumbers, get_state(model, 1, 1), buffer);
|
|
|
|
|
canvas, 64, ROW_1_Y, 28, ROW_1_H, FontBigNumbers, get_state(model, 1, 1, minute), buffer);
|
|
|
|
|
canvas_draw_box(canvas, 94, ROW_1_Y + ROW_1_H - 7, 2, 2);
|
|
|
|
|
canvas_draw_box(canvas, 94, ROW_1_Y + ROW_1_H - 7 - 6, 2, 2);
|
|
|
|
|
|
|
|
|
|
snprintf(buffer, sizeof(buffer), "%02u", model->datetime->second);
|
|
|
|
|
date_time_input_draw_block(
|
|
|
|
|
canvas, 98, ROW_1_Y, 28, ROW_1_H, FontBigNumbers, get_state(model, 1, 2), buffer);
|
|
|
|
|
canvas, 98, ROW_1_Y, 28, ROW_1_H, FontBigNumbers, get_state(model, 1, 2, second), buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void date_time_input_draw_date_callback(Canvas* canvas, DateTimeInputModel* model) {
|
|
|
|
|
@@ -113,14 +125,14 @@ static void date_time_input_draw_date_callback(Canvas* canvas, DateTimeInputMode
|
|
|
|
|
canvas_set_font(canvas, FontPrimary);
|
|
|
|
|
snprintf(buffer, sizeof(buffer), "%04u", model->datetime->year);
|
|
|
|
|
date_time_input_draw_block(
|
|
|
|
|
canvas, 2, ROW_0_Y, 56, ROW_0_H, FontBigNumbers, get_state(model, 0, 0), buffer);
|
|
|
|
|
canvas, 2, ROW_0_Y, 56, ROW_0_H, FontBigNumbers, get_state(model, 0, 0, year), buffer);
|
|
|
|
|
snprintf(buffer, sizeof(buffer), "%02u", model->datetime->month);
|
|
|
|
|
date_time_input_draw_block(
|
|
|
|
|
canvas, 64, ROW_0_Y, 28, ROW_0_H, FontBigNumbers, get_state(model, 0, 1), buffer);
|
|
|
|
|
canvas, 64, ROW_0_Y, 28, ROW_0_H, FontBigNumbers, get_state(model, 0, 1, month), buffer);
|
|
|
|
|
canvas_draw_box(canvas, 64 - 5, ROW_0_Y + (ROW_0_H / 2), 4, 2);
|
|
|
|
|
snprintf(buffer, sizeof(buffer), "%02u", model->datetime->day);
|
|
|
|
|
date_time_input_draw_block(
|
|
|
|
|
canvas, 98, ROW_0_Y, 28, ROW_0_H, FontBigNumbers, get_state(model, 0, 2), buffer);
|
|
|
|
|
canvas, 98, ROW_0_Y, 28, ROW_0_H, FontBigNumbers, get_state(model, 0, 2, day), buffer);
|
|
|
|
|
canvas_draw_box(canvas, 98 - 5, ROW_0_Y + (ROW_0_H / 2), 4, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -131,17 +143,36 @@ static void date_time_input_view_draw_callback(Canvas* canvas, void* _model) {
|
|
|
|
|
date_time_input_draw_date_callback(canvas, model);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline bool is_allowed_to_edit(DateTimeInputModel* model) {
|
|
|
|
|
return (model->row == 0 && ((model->column == 0 && model->editable.year) |
|
|
|
|
|
(model->column == 1 && model->editable.month) |
|
|
|
|
|
(model->column == 2 && model->editable.day))) ||
|
|
|
|
|
((model->row == 1) && ((model->column == 0 && model->editable.hour) |
|
|
|
|
|
(model->column == 1 && model->editable.minute) |
|
|
|
|
|
(model->column == 2 && model->editable.second)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool date_time_input_navigation_callback(InputEvent* event, DateTimeInputModel* model) {
|
|
|
|
|
if(event->key == InputKeyUp) {
|
|
|
|
|
if(model->row > 0) model->row--;
|
|
|
|
|
if(!is_allowed_to_edit(model)) model->row++;
|
|
|
|
|
} else if(event->key == InputKeyDown) {
|
|
|
|
|
if(model->row < ROW_COUNT - 1) model->row++;
|
|
|
|
|
if(!is_allowed_to_edit(model)) model->row--;
|
|
|
|
|
} else if(event->key == InputKeyOk) {
|
|
|
|
|
model->editing = !model->editing;
|
|
|
|
|
} else if(event->key == InputKeyRight) {
|
|
|
|
|
if(model->column < COLUMN_COUNT - 1) model->column++;
|
|
|
|
|
while(model->column < COLUMN_COUNT - 1 && !is_allowed_to_edit(model))
|
|
|
|
|
model->column++;
|
|
|
|
|
while(model->column > 0 && !is_allowed_to_edit(model))
|
|
|
|
|
model->column--;
|
|
|
|
|
} else if(event->key == InputKeyLeft) {
|
|
|
|
|
if(model->column > 0) model->column--;
|
|
|
|
|
while(model->column > 0 && !is_allowed_to_edit(model))
|
|
|
|
|
model->column--;
|
|
|
|
|
while(model->column < COLUMN_COUNT - 1 && !is_allowed_to_edit(model))
|
|
|
|
|
model->column++;
|
|
|
|
|
} else if(event->key == InputKeyBack && model->editing) {
|
|
|
|
|
model->editing = false;
|
|
|
|
|
} else if(event->key == InputKeyBack && model->done_callback) {
|
|
|
|
|
@@ -283,6 +314,13 @@ static void date_time_input_reset_model_input_data(DateTimeInputModel* model) {
|
|
|
|
|
model->column = 0;
|
|
|
|
|
|
|
|
|
|
model->datetime = NULL;
|
|
|
|
|
|
|
|
|
|
model->editable.year = true;
|
|
|
|
|
model->editable.month = true;
|
|
|
|
|
model->editable.day = true;
|
|
|
|
|
model->editable.hour = true;
|
|
|
|
|
model->editable.minute = true;
|
|
|
|
|
model->editable.second = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DateTimeInput* date_time_input_alloc(void) {
|
|
|
|
|
@@ -345,3 +383,39 @@ void date_time_input_set_header_text(DateTimeInput* date_time_input, const char*
|
|
|
|
|
with_view_model(
|
|
|
|
|
date_time_input->view, DateTimeInputModel * model, { model->header = text; }, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void date_time_input_set_editable_fields(
|
|
|
|
|
DateTimeInput* date_time_input,
|
|
|
|
|
bool year,
|
|
|
|
|
bool month,
|
|
|
|
|
bool day,
|
|
|
|
|
bool hour,
|
|
|
|
|
bool minute,
|
|
|
|
|
bool second) {
|
|
|
|
|
furi_check(date_time_input);
|
|
|
|
|
|
|
|
|
|
with_view_model(
|
|
|
|
|
date_time_input->view,
|
|
|
|
|
DateTimeInputModel * model,
|
|
|
|
|
{
|
|
|
|
|
model->editable.year = year;
|
|
|
|
|
model->editable.month = month;
|
|
|
|
|
model->editable.day = day;
|
|
|
|
|
model->editable.hour = hour;
|
|
|
|
|
model->editable.minute = minute;
|
|
|
|
|
model->editable.second = second;
|
|
|
|
|
|
|
|
|
|
// Select first editable field
|
|
|
|
|
model->row = 0;
|
|
|
|
|
model->column = 0;
|
|
|
|
|
while(!is_allowed_to_edit(model)) {
|
|
|
|
|
// Cycle to next column and wrap around at end
|
|
|
|
|
model->column = (model->column + 1) % COLUMN_COUNT;
|
|
|
|
|
// If the column is 0, we wrapped, so go to next row
|
|
|
|
|
if(model->column == 0) model->row++;
|
|
|
|
|
// If we passed the last row, give up
|
|
|
|
|
if(model->row >= ROW_COUNT) break;
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
true);
|
|
|
|
|
}
|
|
|
|
|
|