[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>
This commit is contained in:
		
							parent
							
								
									be500993a3
								
							
						
					
					
						commit
						07036cc0f5
					
				| @ -1,4 +1,5 @@ | ||||
| #include "elements.h" | ||||
| #include "m-core.h" | ||||
| #include <assets_icons.h> | ||||
| #include "furi_hal_resources.h" | ||||
| #include <furi_hal.h> | ||||
| @ -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) { | ||||
|  | ||||
| @ -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()}, | ||||
|  | ||||
| @ -89,6 +89,13 @@ private: | ||||
|     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 { | ||||
| public: | ||||
|     void on_enter(IrdaApp* app) final; | ||||
|  | ||||
							
								
								
									
										71
									
								
								applications/irda/scene/irda_app_scene_ask_back.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								applications/irda/scene/irda_app_scene_ask_back.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -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) { | ||||
| } | ||||
| @ -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"); | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
| @ -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(); | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Albert Kharisov
						Albert Kharisov