diff --git a/applications/gui/elements.c b/applications/gui/elements.c index 2b874ec1..703bf74b 100644 --- a/applications/gui/elements.c +++ b/applications/gui/elements.c @@ -1,4 +1,5 @@ #include "elements.h" +#include "m-core.h" #include #include "furi_hal_resources.h" #include @@ -202,6 +203,48 @@ void elements_button_center(Canvas* canvas, const char* str) { canvas_invert_color(canvas); } +static size_t + elements_get_max_chars_to_fit(Canvas* canvas, Align horizontal, const char* text, uint8_t x) { + const char* end = strchr(text, '\n'); + if(end == NULL) { + end = text + strlen(text); + } + size_t text_size = end - text; + string_t str; + string_init_set_str(str, text); + string_left(str, text_size); + size_t result = 0; + + uint16_t len_px = canvas_string_width(canvas, string_get_cstr(str)); + uint8_t px_left = 0; + if(horizontal == AlignCenter) { + px_left = canvas_width(canvas) - (x - len_px / 2); + } else if(horizontal == AlignLeft) { + px_left = canvas_width(canvas) - x; + } else if(horizontal == AlignRight) { + px_left = x; + } else { + furi_assert(0); + } + + if(len_px > px_left) { + uint8_t excess_symbols_approximately = + ((float)len_px - px_left) / ((float)len_px / text_size); + // reduce to 5 to be sure dash fit, and next line will be at least 5 symbols long + excess_symbols_approximately = MAX(excess_symbols_approximately, 5); + if(text_size > (excess_symbols_approximately + 5)) { + result = text_size - excess_symbols_approximately - 5; + } else { + result = text_size - 1; + } + } else { + result = text_size; + } + + string_clear(str); + return result; +} + void elements_multiline_text_aligned( Canvas* canvas, uint8_t x, @@ -212,64 +255,40 @@ void elements_multiline_text_aligned( furi_assert(canvas); furi_assert(text); + uint8_t lines_count = 0; uint8_t font_height = canvas_current_font_height(canvas); - string_t str; - string_init(str); - const char* start = text; - char* end; + string_t line; - // get lines count - uint8_t i, lines_count; - for(i = 0, lines_count = 0; text[i]; i++) lines_count += (text[i] == '\n'); - - switch(vertical) { - case AlignBottom: - y -= font_height * lines_count; - break; - case AlignCenter: - y -= (font_height * lines_count) / 2; - break; - case AlignTop: - default: - break; + /* go through text line by line and count lines */ + for(const char* start = text; start[0];) { + size_t chars_fit = elements_get_max_chars_to_fit(canvas, horizontal, start, x); + ++lines_count; + start += chars_fit; + start += start[0] == '\n' ? 1 : 0; } - do { - end = strchr(start, '\n'); + if(vertical == AlignBottom) { + y -= font_height * (lines_count - 1); + } else if(vertical == AlignCenter) { + y -= (font_height * (lines_count - 1)) / 2; + } - if(end) { - string_set_strn(str, start, end - start); + /* go through text line by line and print them */ + for(const char* start = text; start[0];) { + size_t chars_fit = elements_get_max_chars_to_fit(canvas, horizontal, start, x); + + if((start[chars_fit] == '\n') || (start[chars_fit] == 0)) { + string_init_printf(line, "%.*s", chars_fit, start); } else { - string_set_str(str, start); + string_init_printf(line, "%.*s-\n", chars_fit, start); } - - uint16_t len_px = canvas_string_width(canvas, string_get_cstr(str)); - uint8_t px_left = - canvas_width(canvas) - (x - (horizontal == AlignCenter ? len_px / 2 : 0)); - - // hacky - if(len_px > px_left) { - string_t buff; - string_init_set(buff, str); - size_t s_len = string_size(str); - uint8_t end_pos = s_len - ((len_px - px_left) / (len_px / s_len) + 5); - - string_left(buff, end_pos); - string_cat(buff, "-"); - string_right(str, end_pos); - - canvas_draw_str_aligned(canvas, x, y, horizontal, vertical, string_get_cstr(buff)); - string_clear(buff); - - start = end + 1; - y += font_height; - } - - canvas_draw_str_aligned(canvas, x, y, horizontal, vertical, string_get_cstr(str)); - start = end + 1; + canvas_draw_str_aligned(canvas, x, y, horizontal, vertical, string_get_cstr(line)); + string_clear(line); y += font_height; - } while(end); - string_clear(str); + + start += chars_fit; + start += start[0] == '\n' ? 1 : 0; + } } void elements_multiline_text(Canvas* canvas, uint8_t x, uint8_t y, const char* text) { diff --git a/applications/irda/irda_app.h b/applications/irda/irda_app.h index 5d660824..e8de29bb 100644 --- a/applications/irda/irda_app.h +++ b/applications/irda/irda_app.h @@ -33,6 +33,7 @@ public: LearnSuccess, LearnEnterName, LearnDone, + AskBack, Remote, RemoteList, Edit, @@ -123,6 +124,7 @@ private: {Scene::LearnSuccess, new IrdaAppSceneLearnSuccess()}, {Scene::LearnEnterName, new IrdaAppSceneLearnEnterName()}, {Scene::LearnDone, new IrdaAppSceneLearnDone()}, + {Scene::AskBack, new IrdaAppSceneAskBack()}, {Scene::Remote, new IrdaAppSceneRemote()}, {Scene::RemoteList, new IrdaAppSceneRemoteList()}, {Scene::Edit, new IrdaAppSceneEdit()}, diff --git a/applications/irda/scene/irda_app_scene.h b/applications/irda/scene/irda_app_scene.h index 9de48e18..f687d405 100644 --- a/applications/irda/scene/irda_app_scene.h +++ b/applications/irda/scene/irda_app_scene.h @@ -89,6 +89,13 @@ private: std::vector remote_names; }; +class IrdaAppSceneAskBack : public IrdaAppScene { +public: + void on_enter(IrdaApp* app) final; + bool on_event(IrdaApp* app, IrdaAppEvent* event) final; + void on_exit(IrdaApp* app) final; +}; + class IrdaAppSceneEdit : public IrdaAppScene { public: void on_enter(IrdaApp* app) final; diff --git a/applications/irda/scene/irda_app_scene_ask_back.cpp b/applications/irda/scene/irda_app_scene_ask_back.cpp new file mode 100644 index 00000000..34c8b61f --- /dev/null +++ b/applications/irda/scene/irda_app_scene_ask_back.cpp @@ -0,0 +1,71 @@ +#include "../irda_app.h" +#include "gui/modules/dialog_ex.h" +#include "irda.h" +#include "irda/scene/irda_app_scene.h" +#include + +static void dialog_result_callback(DialogExResult result, void* context) { + auto app = static_cast(context); + IrdaAppEvent event; + + event.type = IrdaAppEvent::Type::DialogExSelected; + event.payload.dialog_ex_result = result; + + app->get_view_manager()->send_event(&event); +} + +void IrdaAppSceneAskBack::on_enter(IrdaApp* app) { + IrdaAppViewManager* view_manager = app->get_view_manager(); + DialogEx* dialog_ex = view_manager->get_dialog_ex(); + + if(app->get_learn_new_remote()) { + dialog_ex_set_header(dialog_ex, "Exit to Infrared menu?", 64, 0, AlignCenter, AlignTop); + } else { + dialog_ex_set_header(dialog_ex, "Exit to remote menu?", 64, 0, AlignCenter, AlignTop); + } + + dialog_ex_set_text( + dialog_ex, "All unsaved data\nwill be lost", 64, 31, AlignCenter, AlignCenter); + dialog_ex_set_icon(dialog_ex, 0, 0, NULL); + dialog_ex_set_left_button_text(dialog_ex, "Exit"); + dialog_ex_set_center_button_text(dialog_ex, nullptr); + dialog_ex_set_right_button_text(dialog_ex, "Stay"); + dialog_ex_set_result_callback(dialog_ex, dialog_result_callback); + dialog_ex_set_context(dialog_ex, app); + + view_manager->switch_to(IrdaAppViewManager::ViewType::DialogEx); +} + +bool IrdaAppSceneAskBack::on_event(IrdaApp* app, IrdaAppEvent* event) { + bool consumed = false; + + if(event->type == IrdaAppEvent::Type::DialogExSelected) { + switch(event->payload.dialog_ex_result) { + case DialogExResultLeft: + consumed = true; + if(app->get_learn_new_remote()) { + app->search_and_switch_to_previous_scene({IrdaApp::Scene::Start}); + } else { + app->search_and_switch_to_previous_scene( + {IrdaApp::Scene::Edit, IrdaApp::Scene::Remote}); + } + break; + case DialogExResultCenter: + furi_assert(0); + break; + case DialogExResultRight: + app->switch_to_previous_scene(); + consumed = true; + break; + } + } + + if(event->type == IrdaAppEvent::Type::Back) { + consumed = true; + } + + return consumed; +} + +void IrdaAppSceneAskBack::on_exit(IrdaApp* app) { +} diff --git a/applications/irda/scene/irda_app_scene_edit_delete.cpp b/applications/irda/scene/irda_app_scene_edit_delete.cpp index 511ffd4b..36dcbd01 100644 --- a/applications/irda/scene/irda_app_scene_edit_delete.cpp +++ b/applications/irda/scene/irda_app_scene_edit_delete.cpp @@ -21,7 +21,7 @@ void IrdaAppSceneEditDelete::on_enter(IrdaApp* app) { if(app->get_edit_element() == IrdaApp::EditElement::Button) { auto signal = remote_manager->get_button_data(app->get_current_button()); - dialog_ex_set_header(dialog_ex, "Delete button?", 64, 6, AlignCenter, AlignCenter); + dialog_ex_set_header(dialog_ex, "Delete button?", 64, 0, AlignCenter, AlignTop); if(!signal.is_raw()) { auto message = &signal.get_message(); app->set_text_store( @@ -41,7 +41,7 @@ void IrdaAppSceneEditDelete::on_enter(IrdaApp* app) { signal.get_raw_signal().timings_cnt); } } else { - dialog_ex_set_header(dialog_ex, "Delete remote?", 64, 6, AlignCenter, AlignCenter); + dialog_ex_set_header(dialog_ex, "Delete remote?", 64, 0, AlignCenter, AlignTop); app->set_text_store( 0, "%s\n with %lu buttons", @@ -49,7 +49,7 @@ void IrdaAppSceneEditDelete::on_enter(IrdaApp* app) { remote_manager->get_number_of_buttons()); } - dialog_ex_set_text(dialog_ex, app->get_text_store(0), 64, 32, AlignCenter, AlignCenter); + dialog_ex_set_text(dialog_ex, app->get_text_store(0), 64, 31, AlignCenter, AlignCenter); dialog_ex_set_icon(dialog_ex, 0, 0, NULL); dialog_ex_set_left_button_text(dialog_ex, "Back"); dialog_ex_set_right_button_text(dialog_ex, "Delete"); diff --git a/applications/irda/scene/irda_app_scene_edit_delete_done.cpp b/applications/irda/scene/irda_app_scene_edit_delete_done.cpp index 4b817206..e429e72d 100644 --- a/applications/irda/scene/irda_app_scene_edit_delete_done.cpp +++ b/applications/irda/scene/irda_app_scene_edit_delete_done.cpp @@ -5,7 +5,7 @@ void IrdaAppSceneEditDeleteDone::on_enter(IrdaApp* app) { Popup* popup = view_manager->get_popup(); popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); - popup_set_text(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); + popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom); popup_set_callback(popup, IrdaApp::popup_callback); popup_set_context(popup, app); @@ -32,4 +32,7 @@ bool IrdaAppSceneEditDeleteDone::on_event(IrdaApp* app, IrdaAppEvent* event) { } void IrdaAppSceneEditDeleteDone::on_exit(IrdaApp* app) { + IrdaAppViewManager* view_manager = app->get_view_manager(); + Popup* popup = view_manager->get_popup(); + popup_set_header(popup, nullptr, 0, 0, AlignLeft, AlignTop); } diff --git a/applications/irda/scene/irda_app_scene_edit_rename.cpp b/applications/irda/scene/irda_app_scene_edit_rename.cpp index db6b8e4d..28c13456 100644 --- a/applications/irda/scene/irda_app_scene_edit_rename.cpp +++ b/applications/irda/scene/irda_app_scene_edit_rename.cpp @@ -32,7 +32,7 @@ void IrdaAppSceneEditRename::on_enter(IrdaApp* app) { app, app->get_text_store(0), enter_name_length, - true); + false); view_manager->switch_to(IrdaAppViewManager::ViewType::TextInput); } diff --git a/applications/irda/scene/irda_app_scene_learn.cpp b/applications/irda/scene/irda_app_scene_learn.cpp index 10cc4f33..7075f0f8 100644 --- a/applications/irda/scene/irda_app_scene_learn.cpp +++ b/applications/irda/scene/irda_app_scene_learn.cpp @@ -69,4 +69,7 @@ bool IrdaAppSceneLearn::on_event(IrdaApp* app, IrdaAppEvent* event) { void IrdaAppSceneLearn::on_exit(IrdaApp* app) { irda_worker_rx_stop(app->get_irda_worker()); + auto view_manager = app->get_view_manager(); + auto popup = view_manager->get_popup(); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignCenter); } diff --git a/applications/irda/scene/irda_app_scene_learn_done.cpp b/applications/irda/scene/irda_app_scene_learn_done.cpp index c659b5ce..f2669baa 100644 --- a/applications/irda/scene/irda_app_scene_learn_done.cpp +++ b/applications/irda/scene/irda_app_scene_learn_done.cpp @@ -9,9 +9,9 @@ void IrdaAppSceneLearnDone::on_enter(IrdaApp* app) { DOLPHIN_DEED(DolphinDeedIrSave); if(app->get_learn_new_remote()) { - popup_set_text(popup, "New remote\ncreated!", 5, 7, AlignLeft, AlignTop); + popup_set_header(popup, "New remote\ncreated!", 0, 0, AlignLeft, AlignTop); } else { - popup_set_text(popup, "Saved!", 5, 7, AlignLeft, AlignTop); + popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop); } popup_set_callback(popup, IrdaApp::popup_callback); @@ -35,4 +35,7 @@ bool IrdaAppSceneLearnDone::on_event(IrdaApp* app, IrdaAppEvent* event) { void IrdaAppSceneLearnDone::on_exit(IrdaApp* app) { app->set_learn_new_remote(false); + IrdaAppViewManager* view_manager = app->get_view_manager(); + Popup* popup = view_manager->get_popup(); + popup_set_header(popup, nullptr, 0, 0, AlignLeft, AlignTop); } diff --git a/applications/irda/scene/irda_app_scene_learn_success.cpp b/applications/irda/scene/irda_app_scene_learn_success.cpp index d7bd85d2..3ca828d2 100644 --- a/applications/irda/scene/irda_app_scene_learn_success.cpp +++ b/applications/irda/scene/irda_app_scene_learn_success.cpp @@ -91,12 +91,17 @@ bool IrdaAppSceneLearnSuccess::on_event(IrdaApp* app, IrdaAppEvent* event) { } } + if(event->type == IrdaAppEvent::Type::Back) { + app->switch_to_next_scene(IrdaApp::Scene::AskBack); + consumed = true; + } + return consumed; } void IrdaAppSceneLearnSuccess::on_exit(IrdaApp* app) { IrdaAppViewManager* view_manager = app->get_view_manager(); DialogEx* dialog_ex = view_manager->get_dialog_ex(); - dialog_ex_set_center_button_text(dialog_ex, nullptr); + dialog_ex_reset(dialog_ex); app->notify_green_off(); } diff --git a/applications/nfc/scenes/nfc_scene_device_info.c b/applications/nfc/scenes/nfc_scene_device_info.c index e9d5bfda..f0f326f6 100755 --- a/applications/nfc/scenes/nfc_scene_device_info.c +++ b/applications/nfc/scenes/nfc_scene_device_info.c @@ -189,14 +189,7 @@ void nfc_scene_device_info_on_exit(void* context) { if(nfc->dev->format == NfcDeviceSaveFormatUid) { // Clear Dialog DialogEx* dialog_ex = nfc->dialog_ex; - dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); - dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop); - dialog_ex_set_icon(dialog_ex, 0, 0, NULL); - dialog_ex_set_left_button_text(dialog_ex, NULL); - dialog_ex_set_right_button_text(dialog_ex, NULL); - dialog_ex_set_center_button_text(dialog_ex, NULL); - dialog_ex_set_result_callback(dialog_ex, NULL); - dialog_ex_set_context(dialog_ex, NULL); + dialog_ex_reset(dialog_ex); } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { // Clear TextBox text_box_reset(nfc->text_box); diff --git a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c index b396fae1..603ad54a 100755 --- a/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c +++ b/applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c @@ -103,14 +103,7 @@ void nfc_scene_read_mifare_ul_success_on_exit(void* context) { // Clean dialog DialogEx* dialog_ex = nfc->dialog_ex; - dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter); - dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop); - dialog_ex_set_icon(dialog_ex, 0, 0, NULL); - dialog_ex_set_left_button_text(dialog_ex, NULL); - dialog_ex_set_right_button_text(dialog_ex, NULL); - dialog_ex_set_center_button_text(dialog_ex, NULL); - dialog_ex_set_result_callback(dialog_ex, NULL); - dialog_ex_set_context(dialog_ex, NULL); + dialog_ex_reset(dialog_ex); // Clean TextBox TextBox* text_box = nfc->text_box;