From 37131dbe12277daccd3c73d05ce391dd055670c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Thu, 1 Apr 2021 15:03:02 +0300 Subject: [PATCH] [FL-1092] Make View reusable outside of dispatcher (#396) * View: replace direct View to ViewDispatcher link with callback. ViewDispatcher: update View usage. ViewHandler: update View usage, handle update signal. --- applications/gui/view.c | 21 +++++++++++--------- applications/gui/view.h | 25 ++++++++++++++++++++++-- applications/gui/view_dispatcher.c | 16 +++++++++++---- applications/gui/view_dispatcher_i.h | 4 ++-- applications/gui/view_i.h | 10 +++++----- applications/sd-filesystem/view_holder.c | 20 +++++++++++++++++++ applications/sd-filesystem/view_holder.h | 6 ++++++ 7 files changed, 80 insertions(+), 22 deletions(-) diff --git a/applications/gui/view.c b/applications/gui/view.c index d2838ba3..8987ecfd 100644 --- a/applications/gui/view.c +++ b/applications/gui/view.c @@ -11,13 +11,6 @@ void view_free(View* view) { free(view); } -void view_set_dispatcher(View* view, ViewDispatcher* view_dispatcher) { - furi_assert(view); - furi_assert(view_dispatcher); - furi_assert(view->dispatcher == NULL); - view->dispatcher = view_dispatcher; -} - void view_set_draw_callback(View* view, ViewDrawCallback callback) { furi_assert(view); furi_assert(view->draw_callback == NULL); @@ -50,6 +43,16 @@ void view_set_exit_callback(View* view, ViewCallback callback) { view->exit_callback = callback; } +void view_set_update_callback(View* view, ViewUpdateCallback callback) { + furi_assert(view); + view->update_callback = callback; +} + +void view_set_update_callback_context(View* view, void* context) { + furi_assert(view); + view->update_callback_context = context; +} + void view_set_context(View* view, void* context) { furi_assert(view); furi_assert(context); @@ -105,8 +108,8 @@ void* view_get_model(View* view) { void view_commit_model(View* view, bool update) { furi_assert(view); view_unlock_model(view); - if(update && view->dispatcher) { - view_dispatcher_update(view->dispatcher, view); + if(update && view->update_callback) { + view->update_callback(view, view->update_callback_context); } } diff --git a/applications/gui/view.h b/applications/gui/view.h index ef864325..489d4cc1 100644 --- a/applications/gui/view.h +++ b/applications/gui/view.h @@ -20,6 +20,9 @@ extern "C" { */ #define VIEW_DESTROY 0xFFFFFFFA +/* View, anonymous type */ +typedef struct View View; + /* View Draw callback * @param canvas, pointer to canvas * @param view_model, pointer to context @@ -48,6 +51,14 @@ typedef uint32_t (*ViewNavigationCallback)(void* context); */ typedef void (*ViewCallback)(void* context); +/* View Update Callback + * Called upon model change, need to be propagated to GUI throw ViewPort update + * @param view, pointer to view + * @param context, pointer to context + * @warning called from GUI thread + */ +typedef void (*ViewUpdateCallback)(View* view, void* context); + /* View model types */ typedef enum { /* Model is not allocated */ @@ -62,8 +73,6 @@ typedef enum { ViewModelTypeLocking, } ViewModelType; -typedef struct View View; - /* Allocate and init View * @return pointer to View */ @@ -110,6 +119,18 @@ void view_set_enter_callback(View* view, ViewCallback callback); */ void view_set_exit_callback(View* view, ViewCallback callback); +/* Set Update callback + * @param view, pointer to View + * @param callback, callback + */ +void view_set_update_callback(View* view, ViewUpdateCallback callback); + +/* Set View Draw callback + * @param view, pointer to View + * @param context, context for callbacks + */ +void view_set_update_callback_context(View* view, void* context); + /* Set View Draw callback * @param view, pointer to View * @param context, context for callbacks diff --git a/applications/gui/view_dispatcher.c b/applications/gui/view_dispatcher.c index 52d455b3..5f6fbdb0 100644 --- a/applications/gui/view_dispatcher.c +++ b/applications/gui/view_dispatcher.c @@ -48,7 +48,8 @@ void view_dispatcher_add_view(ViewDispatcher* view_dispatcher, uint32_t view_id, } ViewDict_set_at(view_dispatcher->views, view_id, view); - view_set_dispatcher(view, view_dispatcher); + view_set_update_callback(view, view_dispatcher_update); + view_set_update_callback_context(view, view_dispatcher); // Unlock gui if(view_dispatcher->gui) { @@ -63,14 +64,19 @@ void view_dispatcher_remove_view(ViewDispatcher* view_dispatcher, uint32_t view_ if(view_dispatcher->gui) { gui_lock(view_dispatcher->gui); } + // Get View by ID + View* view = *ViewDict_get(view_dispatcher->views, view_id); // Disable the view if it is active - if(view_dispatcher->current_view == *ViewDict_get(view_dispatcher->views, view_id)) { + if(view_dispatcher->current_view == view) { view_dispatcher_set_current_view(view_dispatcher, NULL); } // Remove view ViewDict_erase(view_dispatcher->views, view_id); + view_set_update_callback(view, NULL); + view_set_update_callback_context(view, NULL); + // Unlock gui if(view_dispatcher->gui) { gui_unlock(view_dispatcher->gui); @@ -153,9 +159,11 @@ void view_dispatcher_set_current_view(ViewDispatcher* view_dispatcher, View* vie } } -void view_dispatcher_update(ViewDispatcher* view_dispatcher, View* view) { - furi_assert(view_dispatcher); +void view_dispatcher_update(View* view, void* context) { furi_assert(view); + furi_assert(context); + + ViewDispatcher* view_dispatcher = context; if(view_dispatcher->current_view == view) { view_port_update(view_dispatcher->view_port); diff --git a/applications/gui/view_dispatcher_i.h b/applications/gui/view_dispatcher_i.h index 6539609d..1d17a81c 100644 --- a/applications/gui/view_dispatcher_i.h +++ b/applications/gui/view_dispatcher_i.h @@ -23,5 +23,5 @@ void view_dispatcher_input_callback(InputEvent* event, void* context); /* Set current view, dispatches view enter and exit */ void view_dispatcher_set_current_view(ViewDispatcher* view_dispatcher, View* view); -/* View to ViewDispatcher update event */ -void view_dispatcher_update(ViewDispatcher* view_dispatcher, View* view); +/* ViewDispatcher update event */ +void view_dispatcher_update(View* view, void* context); diff --git a/applications/gui/view_i.h b/applications/gui/view_i.h index b4c4c7c9..34bf3815 100644 --- a/applications/gui/view_i.h +++ b/applications/gui/view_i.h @@ -1,7 +1,6 @@ #pragma once #include "view.h" -#include "view_dispatcher_i.h" #include typedef struct { @@ -10,21 +9,22 @@ typedef struct { } ViewModelLocking; struct View { - ViewDispatcher* dispatcher; ViewDrawCallback draw_callback; ViewInputCallback input_callback; + ViewModelType model_type; ViewNavigationCallback previous_callback; ViewNavigationCallback next_callback; ViewCallback enter_callback; ViewCallback exit_callback; + + ViewUpdateCallback update_callback; + void* update_callback_context; + void* model; void* context; }; -/* Set View dispatcher */ -void view_set_dispatcher(View* view, ViewDispatcher* view_dispatcher); - /* Unlock model */ void view_unlock_model(View* view); diff --git a/applications/sd-filesystem/view_holder.c b/applications/sd-filesystem/view_holder.c index b84ee178..a7f82d79 100644 --- a/applications/sd-filesystem/view_holder.c +++ b/applications/sd-filesystem/view_holder.c @@ -45,7 +45,17 @@ void view_holder_free(ViewHolder* view_holder) { void view_holder_set_view(ViewHolder* view_holder, View* view) { furi_assert(view_holder); + if(view_holder->view) { + view_set_update_callback(view_holder->view, NULL); + view_set_update_callback_context(view_holder->view, NULL); + } + view_holder->view = view; + + if(view_holder->view) { + view_set_update_callback(view_holder->view, view_holder_update); + view_set_update_callback_context(view_holder->view, view_holder); + } } void view_holder_set_free_callback( @@ -85,6 +95,16 @@ void view_holder_stop(ViewHolder* view_holder) { view_port_enabled_set(view_holder->view_port, false); } +void view_holder_update(View* view, void* context) { + furi_assert(view); + furi_assert(context); + + ViewHolder* view_holder = context; + if(view == view_holder->view) { + view_port_update(view_holder->view_port); + } +} + static void view_holder_draw_callback(Canvas* canvas, void* context) { ViewHolder* view_holder = context; if(view_holder->view) { diff --git a/applications/sd-filesystem/view_holder.h b/applications/sd-filesystem/view_holder.h index 4c1d1f67..785ad20a 100644 --- a/applications/sd-filesystem/view_holder.h +++ b/applications/sd-filesystem/view_holder.h @@ -87,6 +87,12 @@ void view_holder_start(ViewHolder* view_holder); */ void view_holder_stop(ViewHolder* view_holder); +/** View Update Handler + * @param view, View Instance + * @param context, ViewHolder instance + */ +void view_holder_update(View* view, void* context); + #ifdef __cplusplus } #endif \ No newline at end of file