diff --git a/applications/services/gui/modules/date_time_input.c b/applications/services/gui/modules/date_time_input.c index 63f648edb..abcb16887 100644 --- a/applications/services/gui/modules/date_time_input.c +++ b/applications/services/gui/modules/date_time_input.c @@ -2,12 +2,12 @@ #include #include -#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); +} diff --git a/applications/services/gui/modules/date_time_input.h b/applications/services/gui/modules/date_time_input.h index 3efc6c7a1..2969994fd 100644 --- a/applications/services/gui/modules/date_time_input.h +++ b/applications/services/gui/modules/date_time_input.h @@ -65,6 +65,25 @@ void date_time_input_set_result_callback( */ void date_time_input_set_header_text(DateTimeInput* date_time_input, const char* text); +/** Set date/time fields which can be edited + * + * @param date_time_input date/time input instance + * @param year whether to allow editing the year + * @param month whether to allow editing the month + * @param day whether to allow editing the day + * @param hour whether to allow editing the hour + * @param minute whether to allow editing the minute + * @param second whether to allow editing the second + */ +void date_time_input_set_editable_fields( + DateTimeInput* date_time_input, + bool year, + bool month, + bool day, + bool hour, + bool minute, + bool second); + #ifdef __cplusplus } #endif diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 1ea105e00..fcf8388f1 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -929,6 +929,7 @@ Function,-,cuserid,char*,char* Function,+,date_time_input_alloc,DateTimeInput*, Function,+,date_time_input_free,void,DateTimeInput* Function,+,date_time_input_get_view,View*,DateTimeInput* +Function,+,date_time_input_set_editable_fields,void,"DateTimeInput*, _Bool, _Bool, _Bool, _Bool, _Bool, _Bool" Function,+,date_time_input_set_header_text,void,"DateTimeInput*, const char*" Function,+,date_time_input_set_result_callback,void,"DateTimeInput*, DateTimeChangedCallback, DateTimeDoneCallback, void*, DateTime*" Function,+,datetime_datetime_to_timestamp,uint32_t,DateTime*