Przeglądaj źródła

[FL-2222] IR fixes (#994)

* Fix elements_multiline_text_aligned
* IR: fix delete menu
* IR: bold text on delete/saved
* IR: add safe back screen
* IR: don't clear text on rename
* Nfc,Infrared: update DialogEx usage

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
Albert Kharisov 3 lat temu
rodzic
commit
07036cc0f5

+ 69 - 50
applications/gui/elements.c

@@ -1,4 +1,5 @@
 #include "elements.h"
 #include "elements.h"
+#include "m-core.h"
 #include <assets_icons.h>
 #include <assets_icons.h>
 #include "furi_hal_resources.h"
 #include "furi_hal_resources.h"
 #include <furi_hal.h>
 #include <furi_hal.h>
@@ -202,6 +203,48 @@ void elements_button_center(Canvas* canvas, const char* str) {
     canvas_invert_color(canvas);
     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(
 void elements_multiline_text_aligned(
     Canvas* canvas,
     Canvas* canvas,
     uint8_t x,
     uint8_t x,
@@ -212,64 +255,40 @@ void elements_multiline_text_aligned(
     furi_assert(canvas);
     furi_assert(canvas);
     furi_assert(text);
     furi_assert(text);
 
 
+    uint8_t lines_count = 0;
     uint8_t font_height = canvas_current_font_height(canvas);
     uint8_t font_height = canvas_current_font_height(canvas);
-    string_t str;
-    string_init(str);
-    const char* start = text;
-    char* end;
+    string_t line;
+
+    /* 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;
+    }
 
 
-    // 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;
+    if(vertical == AlignBottom) {
+        y -= font_height * (lines_count - 1);
+    } else if(vertical == AlignCenter) {
+        y -= (font_height * (lines_count - 1)) / 2;
     }
     }
 
 
-    do {
-        end = strchr(start, '\n');
+    /* 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(end) {
-            string_set_strn(str, start, end - start);
+        if((start[chars_fit] == '\n') || (start[chars_fit] == 0)) {
+            string_init_printf(line, "%.*s", chars_fit, start);
         } else {
         } else {
-            string_set_str(str, 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;
+            string_init_printf(line, "%.*s-\n", chars_fit, start);
         }
         }
-
-        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;
         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) {
 void elements_multiline_text(Canvas* canvas, uint8_t x, uint8_t y, const char* text) {

+ 2 - 0
applications/irda/irda_app.h

@@ -33,6 +33,7 @@ public:
         LearnSuccess,
         LearnSuccess,
         LearnEnterName,
         LearnEnterName,
         LearnDone,
         LearnDone,
+        AskBack,
         Remote,
         Remote,
         RemoteList,
         RemoteList,
         Edit,
         Edit,
@@ -123,6 +124,7 @@ private:
         {Scene::LearnSuccess, new IrdaAppSceneLearnSuccess()},
         {Scene::LearnSuccess, new IrdaAppSceneLearnSuccess()},
         {Scene::LearnEnterName, new IrdaAppSceneLearnEnterName()},
         {Scene::LearnEnterName, new IrdaAppSceneLearnEnterName()},
         {Scene::LearnDone, new IrdaAppSceneLearnDone()},
         {Scene::LearnDone, new IrdaAppSceneLearnDone()},
+        {Scene::AskBack, new IrdaAppSceneAskBack()},
         {Scene::Remote, new IrdaAppSceneRemote()},
         {Scene::Remote, new IrdaAppSceneRemote()},
         {Scene::RemoteList, new IrdaAppSceneRemoteList()},
         {Scene::RemoteList, new IrdaAppSceneRemoteList()},
         {Scene::Edit, new IrdaAppSceneEdit()},
         {Scene::Edit, new IrdaAppSceneEdit()},

+ 7 - 0
applications/irda/scene/irda_app_scene.h

@@ -89,6 +89,13 @@ private:
     std::vector<std::string> remote_names;
     std::vector<std::string> 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 {
 class IrdaAppSceneEdit : public IrdaAppScene {
 public:
 public:
     void on_enter(IrdaApp* app) final;
     void on_enter(IrdaApp* app) final;

+ 71 - 0
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 <string>
+
+static void dialog_result_callback(DialogExResult result, void* context) {
+    auto app = static_cast<IrdaApp*>(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) {
+}

+ 3 - 3
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) {
     if(app->get_edit_element() == IrdaApp::EditElement::Button) {
         auto signal = remote_manager->get_button_data(app->get_current_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()) {
         if(!signal.is_raw()) {
             auto message = &signal.get_message();
             auto message = &signal.get_message();
             app->set_text_store(
             app->set_text_store(
@@ -41,7 +41,7 @@ void IrdaAppSceneEditDelete::on_enter(IrdaApp* app) {
                 signal.get_raw_signal().timings_cnt);
                 signal.get_raw_signal().timings_cnt);
         }
         }
     } else {
     } 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(
         app->set_text_store(
             0,
             0,
             "%s\n with %lu buttons",
             "%s\n with %lu buttons",
@@ -49,7 +49,7 @@ void IrdaAppSceneEditDelete::on_enter(IrdaApp* app) {
             remote_manager->get_number_of_buttons());
             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_icon(dialog_ex, 0, 0, NULL);
     dialog_ex_set_left_button_text(dialog_ex, "Back");
     dialog_ex_set_left_button_text(dialog_ex, "Back");
     dialog_ex_set_right_button_text(dialog_ex, "Delete");
     dialog_ex_set_right_button_text(dialog_ex, "Delete");

+ 4 - 1
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* popup = view_manager->get_popup();
 
 
     popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62);
     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_callback(popup, IrdaApp::popup_callback);
     popup_set_context(popup, app);
     popup_set_context(popup, app);
@@ -32,4 +32,7 @@ bool IrdaAppSceneEditDeleteDone::on_event(IrdaApp* app, IrdaAppEvent* event) {
 }
 }
 
 
 void IrdaAppSceneEditDeleteDone::on_exit(IrdaApp* app) {
 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);
 }
 }

+ 1 - 1
applications/irda/scene/irda_app_scene_edit_rename.cpp

@@ -32,7 +32,7 @@ void IrdaAppSceneEditRename::on_enter(IrdaApp* app) {
         app,
         app,
         app->get_text_store(0),
         app->get_text_store(0),
         enter_name_length,
         enter_name_length,
-        true);
+        false);
 
 
     view_manager->switch_to(IrdaAppViewManager::ViewType::TextInput);
     view_manager->switch_to(IrdaAppViewManager::ViewType::TextInput);
 }
 }

+ 3 - 0
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) {
 void IrdaAppSceneLearn::on_exit(IrdaApp* app) {
     irda_worker_rx_stop(app->get_irda_worker());
     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);
 }
 }

+ 5 - 2
applications/irda/scene/irda_app_scene_learn_done.cpp

@@ -9,9 +9,9 @@ void IrdaAppSceneLearnDone::on_enter(IrdaApp* app) {
     DOLPHIN_DEED(DolphinDeedIrSave);
     DOLPHIN_DEED(DolphinDeedIrSave);
 
 
     if(app->get_learn_new_remote()) {
     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 {
     } 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);
     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) {
 void IrdaAppSceneLearnDone::on_exit(IrdaApp* app) {
     app->set_learn_new_remote(false);
     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);
 }
 }

+ 6 - 1
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;
     return consumed;
 }
 }
 
 
 void IrdaAppSceneLearnSuccess::on_exit(IrdaApp* app) {
 void IrdaAppSceneLearnSuccess::on_exit(IrdaApp* app) {
     IrdaAppViewManager* view_manager = app->get_view_manager();
     IrdaAppViewManager* view_manager = app->get_view_manager();
     DialogEx* dialog_ex = view_manager->get_dialog_ex();
     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();
     app->notify_green_off();
 }
 }

+ 1 - 8
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) {
     if(nfc->dev->format == NfcDeviceSaveFormatUid) {
         // Clear Dialog
         // Clear Dialog
         DialogEx* dialog_ex = nfc->dialog_ex;
         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) {
     } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
         // Clear TextBox
         // Clear TextBox
         text_box_reset(nfc->text_box);
         text_box_reset(nfc->text_box);

+ 1 - 8
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
     // Clean dialog
     DialogEx* dialog_ex = nfc->dialog_ex;
     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
     // Clean TextBox
     TextBox* text_box = nfc->text_box;
     TextBox* text_box = nfc->text_box;