Store task UI geometry in project file
Updates various parts of the task subsystem in order to save and restore the UI node positions when projects are written and read in.
Merge request reports
Activity
assigned to @john.tourtellott
added 1 commit
- 72bd4616 - Add #define option to rate-limit nodeMoved signals
@dcthomp the current logic is functional but there are issues. We should discuss when you have time.
- Klugey: The logic to support multiple UI options includes a "uiLabel" that is stored in the task manager to identify which option is currently in use. Maybe there is a better way to do this?
- Serialization: There is an intermittent problem that occurs when saving/reloading the task manager that causes the task dependencies to get scrambled. I don't have a way to reliably repeat the symptom, it just shows up out of the blue sometimes. I don't think the new code in this branch creates the problem, instead it shows up now because I am reading/changing/writing the task manager contents for the first time.
- Rate limiting: There is a
#define LIMIT_MOVE_SIGNALS
item in qtTaskNode that can be used to limit the rate thatnodeMoved
signals emitted by qtTaskNode. It is current set to the off state because it creates a lag in the corresponding arc updates. It might make sense to have separate signals for (i) updating args at full speed and (ii) updating the project at rate-limited speed.
88 /// Store geometry changes from UI components 89 void setUiLabel(const std::string& label) { m_uiLabel = label; } 90 std::string uiLabel() const { return m_uiLabel; } 91 void uiGeometryChanged(smtk::string::Token taskId, const nlohmann::json& data); 92 void setUiConfig(const std::string& label, smtk::string::Token taskId, const nlohmann::json& j); 93 nlohmann::json uiConfig(smtk::string::Token taskId) const; 94 void dumpUiConfig() const; 95 86 96 private: 87 97 TaskInstances m_taskInstances; 88 98 AdaptorInstances m_adaptorInstances; 89 99 Active m_active; 90 100 std::weak_ptr<smtk::common::Managers> m_managers; 91 101 nlohmann::json m_styles; 102 std::string m_uiLabel; // for storing geometry objects 103 std::map<std::string, std::map<smtk::string::Token, nlohmann::json>> m_uiConfigs; - Comment on lines +88 to +103
Instead of adding lots of API to the
task::Manager
, add a single class that manages UI state.class Manager { // ... const UIState& uiState() const { return *m_uiState; } UIState& uiState() { return *m_uiState; } protected: std::shared_ptr<UIState> m_uiState; }; class UIState { std::unordered_map<smtk::string::Token, std::unordered_map<smtk::string::Token, nlohmann::json>> m_data; };
As an alternative to tracking node state with every move, consider holding a set of functors that can generate state when it comes time to save tasks:
class UIStateGenerator { /// Fetch state not tied to a particular task (e.g. background color). virtual nlohmann::json globalState() const = 0; /// Fetch state attached to a particular \a task. virtual nlohmann::json taskState (const smtk::task::Task& task) const = 0; } class UIState { std::unordered_map<smtk::string::Token, std::shared_ptr<UIStateGenerator>> m_data; };
Then qtTaskEditor can pass the task-manager's
UIState
object a custom functor to fetch node positions only when the project is written to disk.class TaskEditorState : UIStateGenerator { TaskEditorState(qtTaskEditor* editor) : m_editor(editor) { } nlohmann::json globalState() const override { return nlohmann::json(); } nlohmann::json taskState(const smtk::task::Task& task) const override { return m_editor->uiStateForTask(task); } protected: qtTaskEditor* m_editor{ nullptr }; }
Edited by David Thompson changed this line in version 4 of the diff
33 33 #include <QVBoxLayout> 34 34 #include <QWidget> 35 35 36 #include <string> 37 38 namespace 39 { 40 // String constant used to designate UI features in serialized task manager. 41 const std::string JSON_LABEL = "qtTaskEditor"; changed this line in version 4 of the diff
83 100 } 84 101 85 void computeNodeLayout() 102 // Returns true if UI configuration was modified 103 bool computeNodeLayout() 86 104 { 105 if (m_taskIndex.empty()) 106 { 107 return false; 108 } 109 110 // Check if taskManager has UI config objects first 111 bool configured = false; 112 auto* firstTask = m_taskIndex.begin()->first; 113 auto* taskManager = firstTask->manager(); 114 taskManager->setUiLabel(JSON_LABEL); changed this line in version 4 of the diff
Mostly fyi I started down the second approach (
TaskEditorState
) but will be switching to the first one (encapsulating UIState in smtk::task).I didn't think about this beforehand, but in terms of reducing the API impact to smtk::task::Manaager, I ran into a chicken & egg problem using the
TaskEditorState
approach. In brief, I can't instantiate a TaskEditorState until the qtTaskEditor is created, which doesn't occur until after the project has been loaded. So I need some object to store the UI state when the project is read in in order to provide that to the task editor when it is ready.added 4 commits
Toggle commit list@dcthomp This "later & greater" version is functional, though I should do more testing this afternoon.
- I'm also going to review the code this afternoon, but wanted to get this online asap.
- UIState class has separate maps for (i) data read from file and (ii) generators for writing current geometry to file.
- Had a problem with the code always marking a project modified when loaded, whether or not code did automatic layout. I presume it has to do with when the nodeModified signals get issued on first placement of each node. Resolved in
qtTaskEditor::onNodeGeometryChanged()
by comparing current geom with original geom loaded from file (if any). - I'm also still seeing the intermittent problem on file read that seems to mess up dependencies. Still cannot reproduce reliably. (so beware :)
Edited by John Tourtellottmentioned in commit 119f3395