qtimetrap 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +48 -0
- data/README.md +3 -4
- data/app/components/entries/branch_hierarchy_helpers.rb +4 -4
- data/app/components/entries/entry_row_render_helpers.rb +196 -0
- data/app/components/entries/leaf_archive_helpers.rb +6 -6
- data/app/components/entries/leaf_note_helpers.rb +18 -12
- data/app/components/entries/leaf_task_display_helpers.rb +15 -0
- data/app/components/entries/leaf_task_editor_state_helpers.rb +68 -0
- data/app/components/entries/leaf_task_helpers.rb +130 -46
- data/app/components/entries/leaf_time_helpers.rb +9 -9
- data/app/components/entries/list_component.rb +302 -15
- data/app/components/entries/list_host_helpers.rb +6 -3
- data/app/components/entries/list_state_helpers.rb +77 -4
- data/app/components/entries/list_task_editor_helpers.rb +31 -0
- data/app/components/entries/render_helpers.rb +2 -2
- data/app/components/entries/tree_helpers.rb +9 -7
- data/app/components/entries/tree_toolbar_helpers.rb +12 -12
- data/app/components/project_sidebar/archive_toggle_helpers.rb +6 -6
- data/app/components/project_sidebar/component.rb +18 -7
- data/app/components/project_sidebar/logo_helpers.rb +14 -14
- data/app/components/project_sidebar/project_button_helpers.rb +7 -7
- data/app/components/project_sidebar/task_helpers.rb +11 -11
- data/app/components/qt_ui_helpers.rb +9 -9
- data/app/components/tracker_controls/component.rb +19 -8
- data/app/components/tracker_controls/layout_builder.rb +35 -15
- data/app/components/tracker_controls/layout_helpers.rb +7 -6
- data/app/services/archived_entries_store.rb +11 -6
- data/app/styles/themes/dark/entries_list.qss +12 -4
- data/app/styles/themes/light/entries_list.qss +12 -4
- data/app/view_models/main_view_model.rb +4 -0
- data/app/views/main_window.rb +2 -3
- data/app/views/main_window_layout_builder.rb +6 -6
- data/app/views/main_window_runtime.rb +14 -8
- data/app/views/main_window_runtime_archive_helpers.rb +7 -1
- data/app/views/main_window_runtime_key_helpers.rb +24 -5
- data/app/views/main_window_runtime_render_helpers.rb +2 -1
- data/app/views/main_window_splitter_toggle_bootstrap_helpers.rb +1 -1
- data/app/views/main_window_splitter_toggle_helpers.rb +10 -10
- data/app/views/main_window_splitter_toggle_hover_helpers.rb +2 -2
- data/app/views/main_window_ui_helpers.rb +31 -3
- data/app/views/window_icon_loader.rb +1 -1
- data/lib/qtimetrap/version.rb +1 -1
- data/lib/rubocop/cop/qt/prefer_ruby_style_setter.rb +50 -0
- metadata +11 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '018f44eb75f1594bcb9a78ac9f9cf8663901e2c3bf34d76f324f6e5a955da4d1'
|
|
4
|
+
data.tar.gz: b0c0f032ae783bb94d12061186c8430596ae7c5dbcef6497337113517bebc6b5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 10055a894a818debb7f33541ca4146fe65eb46e0bb364f10d0d7d0cc8bee9d3ee0421658fd9848d186a264d4fa2bd9c1830c166c5e11cdf990ed39bdc5cb4bf7
|
|
7
|
+
data.tar.gz: c1b33688d08191603e914254c48a1405393dc21482041e8a9f7a5587dd104a012bd8e0ff3b0c5093be0a2743e0a2dd8982e9c0f32570fb599806ad454ee45e20
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.1.3] - 2026-11-10
|
|
6
|
+
|
|
7
|
+
### Performance
|
|
8
|
+
- Cache archived-entry IDs during refresh.
|
|
9
|
+
- Render the entry list incrementally and filter existing widgets instead of rebuilding the tree.
|
|
10
|
+
- Create task editors only when activated to reduce initial widget construction.
|
|
11
|
+
- Add a startup and interaction profiling script.
|
|
12
|
+
|
|
13
|
+
## [0.1.2] - 2026-03-17
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- Editable task reassignment for individual entries.
|
|
17
|
+
- Archive mode with archive/restore flow for entry rows.
|
|
18
|
+
- Multi-select project filtering in the sidebar with recent-activity ordering for projects and tasks.
|
|
19
|
+
- Date/time range filtering for rendered entry nodes.
|
|
20
|
+
- Custom RuboCop enforcement for Ruby-style Qt setter usage in `app/**`.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- Switched project license to BSD-2-Clause.
|
|
24
|
+
- Moved specs under `spec/qtimetrap/**` and removed the RuboCop todo file.
|
|
25
|
+
- Improved README, packaging metadata, and release preparation.
|
|
26
|
+
- Tracker inputs now take focus on direct click when editing is allowed.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
- Preserved running tracker inputs when selecting sidebar tasks.
|
|
30
|
+
- Closed inline editors on outside click without relying on application-level hit-testing workarounds.
|
|
31
|
+
- Restored entry task editor styling and display-field behavior.
|
|
32
|
+
- Reduced UI regressions around inline task editing, scrolling, and blur handling.
|
|
33
|
+
|
|
34
|
+
## [0.1.1] - 2026-03-14
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
- Fedora/COPR packaging, desktop entry installation, and application icons.
|
|
38
|
+
- Sidebar task filtering, multi-project filtering, and archive support groundwork.
|
|
39
|
+
- Editable note and time updates for entry leaves.
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
- Updated runtime dependency to newer `qt` releases in the 0.1 series.
|
|
43
|
+
|
|
44
|
+
## [0.1.0] - 2026-03-05
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
- Initial release of QTimetrap as a Ruby gem with a Qt desktop UI.
|
|
48
|
+
- MVVM application structure with Zeitwerk autoloading, themed QSS styling, and Timetrap integration.
|
data/README.md
CHANGED
|
@@ -19,7 +19,7 @@ QTimetrap follows an MVVM-style architecture with `Zeitwerk` autoloading and a R
|
|
|
19
19
|
## Requirements
|
|
20
20
|
|
|
21
21
|
- Ruby `>= 3.2`
|
|
22
|
-
- Qt bridge gem: `qt >= 0.1.
|
|
22
|
+
- Qt bridge gem: `qt >= 0.1.7`
|
|
23
23
|
- `timetrap` CLI available as `t` (or configured via env)
|
|
24
24
|
|
|
25
25
|
## Install
|
|
@@ -38,9 +38,8 @@ Install required system libraries first:
|
|
|
38
38
|
### Fedora COPR
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
sudo dnf copr enable cyjimmy264/ruby-qt
|
|
42
|
-
sudo dnf
|
|
43
|
-
sudo dnf install ruby-qt ruby-qtimetrap
|
|
41
|
+
sudo dnf copr enable cyjimmy264/ruby-qt-stack
|
|
42
|
+
sudo dnf install ruby-qtimetrap
|
|
44
43
|
gem install timetrap
|
|
45
44
|
qtimetrap
|
|
46
45
|
```
|
|
@@ -8,10 +8,10 @@ module QTimetrap
|
|
|
8
8
|
|
|
9
9
|
def build_children_container(parent_widget)
|
|
10
10
|
container = QWidget.new(parent_widget)
|
|
11
|
-
container.
|
|
11
|
+
container.object_name = 'entry_node_children'
|
|
12
12
|
layout = QVBoxLayout.new(container)
|
|
13
13
|
layout.set_contents_margins(0, 0, 0, 0)
|
|
14
|
-
layout.
|
|
14
|
+
layout.spacing = 2
|
|
15
15
|
[container, layout]
|
|
16
16
|
end
|
|
17
17
|
|
|
@@ -32,9 +32,9 @@ module QTimetrap
|
|
|
32
32
|
binding = branch_bindings[node_id]
|
|
33
33
|
return unless binding
|
|
34
34
|
|
|
35
|
-
binding.fetch(:children_container).
|
|
35
|
+
binding.fetch(:children_container).visible = visible
|
|
36
36
|
text = branch_button_text(binding.fetch(:level), binding.fetch(:label), visible)
|
|
37
|
-
binding.fetch(:button).
|
|
37
|
+
binding.fetch(:button).text = text
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
end
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module QTimetrap
|
|
4
|
+
module Entries
|
|
5
|
+
# Builds editable entry rows in small GUI-thread steps.
|
|
6
|
+
module EntryRowRenderHelpers
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def start_entry_row_render(node, level, layout:, parent_widget:)
|
|
10
|
+
row = build_entry_row(parent_widget)
|
|
11
|
+
apply_entry_widget_styles(row, ListComponent::ENTRY_ROW_STYLE_IDS)
|
|
12
|
+
row_layout = build_entry_row_layout(row)
|
|
13
|
+
layout.add_widget(row)
|
|
14
|
+
entry_rows << row
|
|
15
|
+
entry_id = node.fetch(:entry_id, node.fetch(:id))
|
|
16
|
+
entry_rows_by_id[entry_id] = row
|
|
17
|
+
project_branch_id = container_branch_ids[parent_widget.handle.address]
|
|
18
|
+
entry_row_parent_branches[entry_id] = project_branch_id
|
|
19
|
+
project_branch_entry_ids[project_branch_id] << entry_id if project_branch_id
|
|
20
|
+
row_visible = visible_entry_ids.nil? || visible_entry_ids.key?(entry_id)
|
|
21
|
+
row_filter_state[entry_id] = row_visible
|
|
22
|
+
row.visible = row_visible
|
|
23
|
+
|
|
24
|
+
context = {
|
|
25
|
+
node: node,
|
|
26
|
+
level: level,
|
|
27
|
+
row: row,
|
|
28
|
+
row_layout: row_layout,
|
|
29
|
+
parent_layout: layout,
|
|
30
|
+
parent_widget: parent_widget
|
|
31
|
+
}
|
|
32
|
+
enqueue_entry_row_stage(context, :time_group)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def enqueue_entry_row_stage(context, stage, index = nil)
|
|
36
|
+
render_queue << [:entry_stage, stage, context, index]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def process_entry_row_stage(context, stage, index)
|
|
40
|
+
case stage
|
|
41
|
+
when :time_group then create_entry_time_group(context)
|
|
42
|
+
when :start_time then create_entry_start_time(context)
|
|
43
|
+
when :time_separator then create_entry_time_separator(context)
|
|
44
|
+
when :end_time then create_entry_end_time(context)
|
|
45
|
+
when :bind_start_time then bind_entry_start_time(context)
|
|
46
|
+
when :bind_end_time then bind_entry_end_time(context)
|
|
47
|
+
when :prefix then create_entry_prefix(context)
|
|
48
|
+
when :task_container then create_task_container(context)
|
|
49
|
+
when :task_display then create_task_display(context)
|
|
50
|
+
when :note_input then create_entry_note(context)
|
|
51
|
+
when :note_bind_mouse then bind_entry_note_mouse(context)
|
|
52
|
+
when :note_bind_key then bind_entry_note_key(context)
|
|
53
|
+
when :note_bind_return then bind_entry_note_return(context)
|
|
54
|
+
when :note_bind_focus then bind_entry_note_focus(context)
|
|
55
|
+
when :archive_button then create_entry_archive_button(context)
|
|
56
|
+
when :finish then finish_entry_row(context)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def create_entry_time_group(context)
|
|
61
|
+
group = QWidget.new(context.fetch(:row))
|
|
62
|
+
group.object_name = 'entry_node_entry_time_group'
|
|
63
|
+
layout = QHBoxLayout.new(group)
|
|
64
|
+
layout.set_contents_margins(0, 0, 0, 0)
|
|
65
|
+
layout.spacing = 4
|
|
66
|
+
context[:time_group] = group
|
|
67
|
+
context[:time_layout] = layout
|
|
68
|
+
context.fetch(:row_layout).add_widget(group)
|
|
69
|
+
enqueue_entry_row_stage(context, :start_time)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def create_entry_start_time(context)
|
|
73
|
+
node = context.fetch(:node)
|
|
74
|
+
input = build_entry_time_input(
|
|
75
|
+
context.fetch(:row),
|
|
76
|
+
object_name: 'entry_node_entry_start',
|
|
77
|
+
value: node.fetch(:start_label, '--:--'),
|
|
78
|
+
placeholder: '--:--'
|
|
79
|
+
)
|
|
80
|
+
context[:start_input] = input
|
|
81
|
+
context.fetch(:time_layout).add_widget(input)
|
|
82
|
+
enqueue_entry_row_stage(context, :time_separator)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def create_entry_time_separator(context)
|
|
86
|
+
separator = build_entry_time_separator(context.fetch(:time_group))
|
|
87
|
+
context[:time_layout].add_widget(separator)
|
|
88
|
+
enqueue_entry_row_stage(context, :end_time)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def create_entry_end_time(context)
|
|
92
|
+
node = context.fetch(:node)
|
|
93
|
+
input = build_entry_time_input(
|
|
94
|
+
context.fetch(:row),
|
|
95
|
+
object_name: 'entry_node_entry_end',
|
|
96
|
+
value: node.fetch(:end_label, 'running'),
|
|
97
|
+
placeholder: 'running'
|
|
98
|
+
)
|
|
99
|
+
context[:end_input] = input
|
|
100
|
+
context.fetch(:time_layout).add_widget(input)
|
|
101
|
+
enqueue_entry_row_stage(context, :bind_start_time)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def bind_entry_start_time(context)
|
|
105
|
+
bind_single_time_input(
|
|
106
|
+
context.fetch(:start_input),
|
|
107
|
+
resolve_entry_id(context.fetch(:node)),
|
|
108
|
+
context.fetch(:start_input),
|
|
109
|
+
context.fetch(:end_input)
|
|
110
|
+
)
|
|
111
|
+
enqueue_entry_row_stage(context, :bind_end_time)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def bind_entry_end_time(context)
|
|
115
|
+
bind_single_time_input(
|
|
116
|
+
context.fetch(:end_input),
|
|
117
|
+
resolve_entry_id(context.fetch(:node)),
|
|
118
|
+
context.fetch(:start_input),
|
|
119
|
+
context.fetch(:end_input)
|
|
120
|
+
)
|
|
121
|
+
enqueue_entry_row_stage(context, :prefix)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def create_entry_prefix(context)
|
|
125
|
+
label = build_entry_prefix_label(context.fetch(:row), context.fetch(:node), context.fetch(:level))
|
|
126
|
+
context.fetch(:row_layout).add_widget(label)
|
|
127
|
+
enqueue_entry_row_stage(context, :task_container)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def create_task_container(context)
|
|
131
|
+
container = QWidget.new(context.fetch(:row))
|
|
132
|
+
container.object_name = 'entry_node_entry_task_container'
|
|
133
|
+
build_entry_task_layout(container)
|
|
134
|
+
context[:task_container] = container
|
|
135
|
+
context.fetch(:row_layout).add_widget(container)
|
|
136
|
+
enqueue_entry_row_stage(context, :task_display)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def create_task_display(context)
|
|
140
|
+
node = context.fetch(:node)
|
|
141
|
+
task_name = node.fetch(:task_name, '').to_s
|
|
142
|
+
display = build_entry_task_display(context.fetch(:task_container), task_name)
|
|
143
|
+
context[:task_name] = task_name
|
|
144
|
+
context[:task_display] = display
|
|
145
|
+
task_container = context.fetch(:task_container)
|
|
146
|
+
register_task_widgets(task_container, display, nil, nil)
|
|
147
|
+
register_task_editor_config(task_container, node: context.fetch(:node), task_name: task_name)
|
|
148
|
+
display.on(:mouse_button_press) { |_| activate_entry_task_input(task_container) }
|
|
149
|
+
enqueue_entry_row_stage(context, :note_input)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def create_entry_note(context)
|
|
153
|
+
input = build_entry_note_input_widget(context.fetch(:row), context.fetch(:node))
|
|
154
|
+
context[:note_input] = input
|
|
155
|
+
context.fetch(:row_layout).add_widget(input)
|
|
156
|
+
enqueue_entry_row_stage(context, :note_bind_mouse)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def bind_entry_note_mouse(context)
|
|
160
|
+
input = context.fetch(:note_input)
|
|
161
|
+
input.on(:mouse_button_press) { |_| activate_entry_note_input(input) }
|
|
162
|
+
enqueue_entry_row_stage(context, :note_bind_key)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def bind_entry_note_key(context)
|
|
166
|
+
input = context.fetch(:note_input)
|
|
167
|
+
entry_id = resolve_entry_id(context.fetch(:node))
|
|
168
|
+
input.on(:key_press) { |event| handle_entry_note_key_press(input, entry_id, event) }
|
|
169
|
+
enqueue_entry_row_stage(context, :note_bind_return)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def bind_entry_note_return(context)
|
|
173
|
+
input = context.fetch(:note_input)
|
|
174
|
+
entry_id = resolve_entry_id(context.fetch(:node))
|
|
175
|
+
input.connect('returnPressed') { |_| handle_entry_note_commit(input, entry_id) }
|
|
176
|
+
enqueue_entry_row_stage(context, :note_bind_focus)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def bind_entry_note_focus(context)
|
|
180
|
+
context.fetch(:note_input).on(:focus_out) { |_| handle_entry_note_focus_out(context.fetch(:note_input)) }
|
|
181
|
+
enqueue_entry_row_stage(context, :archive_button)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def create_entry_archive_button(context)
|
|
185
|
+
button = build_entry_archive_button(context.fetch(:row), context.fetch(:node))
|
|
186
|
+
context.fetch(:row_layout).add_widget(button)
|
|
187
|
+
enqueue_entry_row_stage(context, :finish)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def finish_entry_row(context)
|
|
191
|
+
context.fetch(:row_layout).set_stretch(2, 1)
|
|
192
|
+
context.fetch(:row_layout).set_stretch(3, 2)
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
@@ -8,12 +8,12 @@ module QTimetrap
|
|
|
8
8
|
|
|
9
9
|
def build_entry_archive_button(row, node)
|
|
10
10
|
QPushButton.new(row).tap do |button|
|
|
11
|
-
button.
|
|
12
|
-
button.
|
|
13
|
-
button.
|
|
14
|
-
button.
|
|
15
|
-
button.
|
|
16
|
-
button.
|
|
11
|
+
button.object_name = 'entry_node_entry_archive'
|
|
12
|
+
button.text = '🗃'
|
|
13
|
+
button.tool_tip = 'Toggle archive state'
|
|
14
|
+
button.focus_policy = Qt::NoFocus
|
|
15
|
+
button.fixed_width = 28
|
|
16
|
+
button.fixed_height = 24
|
|
17
17
|
entry_id = resolve_entry_id(node)
|
|
18
18
|
button.connect('clicked') { |_| on_entry_archive&.call(entry_id) }
|
|
19
19
|
end
|
|
@@ -8,6 +8,7 @@ module QTimetrap
|
|
|
8
8
|
|
|
9
9
|
def render_entry_leaf_node(node, level, layout:, parent_widget:)
|
|
10
10
|
row = build_entry_row(parent_widget)
|
|
11
|
+
apply_entry_widget_styles(row, ListComponent::ENTRY_ROW_STYLE_IDS)
|
|
11
12
|
row_layout = build_entry_row_layout(row)
|
|
12
13
|
start_input, end_input = add_entry_time_widgets(row_layout, row, node)
|
|
13
14
|
add_entry_row_widgets(row_layout, row, node, level)
|
|
@@ -31,33 +32,38 @@ module QTimetrap
|
|
|
31
32
|
|
|
32
33
|
def build_entry_row(parent_widget)
|
|
33
34
|
QWidget.new(parent_widget).tap do |row|
|
|
34
|
-
row.
|
|
35
|
-
row.
|
|
36
|
-
row.
|
|
35
|
+
row.object_name = 'entry_node_entry_row'
|
|
36
|
+
row.fixed_width = branch_button_width
|
|
37
|
+
row.fixed_height = 32
|
|
37
38
|
end
|
|
38
39
|
end
|
|
39
40
|
|
|
40
41
|
def build_entry_row_layout(row)
|
|
41
42
|
QHBoxLayout.new(row).tap do |layout|
|
|
42
43
|
layout.set_contents_margins(8, 0, 8, 0)
|
|
43
|
-
layout.
|
|
44
|
+
layout.spacing = 6
|
|
44
45
|
end
|
|
45
46
|
end
|
|
46
47
|
|
|
47
48
|
def build_entry_prefix_label(row, node, level)
|
|
48
49
|
QLabel.new(row).tap do |prefix_label|
|
|
49
|
-
prefix_label.
|
|
50
|
-
prefix_label.
|
|
50
|
+
prefix_label.object_name = 'entry_node_entry_prefix'
|
|
51
|
+
prefix_label.text = "#{indent(level)}#{node.fetch(:prefix, node.fetch(:label))}"
|
|
51
52
|
end
|
|
52
53
|
end
|
|
53
54
|
|
|
54
55
|
def build_entry_note_input(row, node)
|
|
56
|
+
build_entry_note_input_widget(row, node).tap do |note_input|
|
|
57
|
+
bind_entry_note_input_events(note_input, resolve_entry_id(node))
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def build_entry_note_input_widget(row, node)
|
|
55
62
|
QLineEdit.new(row).tap do |note_input|
|
|
56
|
-
note_input.
|
|
63
|
+
note_input.object_name = 'entry_node_entry_note'
|
|
57
64
|
note_input.text = node.fetch(:note, '')
|
|
58
|
-
note_input.
|
|
59
|
-
note_input.
|
|
60
|
-
bind_entry_note_input_events(note_input, resolve_entry_id(node))
|
|
65
|
+
note_input.placeholder_text = '(no note)'
|
|
66
|
+
note_input.read_only = true
|
|
61
67
|
end
|
|
62
68
|
end
|
|
63
69
|
|
|
@@ -83,12 +89,12 @@ module QTimetrap
|
|
|
83
89
|
end
|
|
84
90
|
|
|
85
91
|
def activate_entry_note_input(note_input)
|
|
86
|
-
note_input.
|
|
92
|
+
note_input.read_only = false
|
|
87
93
|
note_input.set_focus
|
|
88
94
|
end
|
|
89
95
|
|
|
90
96
|
def deactivate_entry_note_input(note_input)
|
|
91
|
-
note_input.
|
|
97
|
+
note_input.read_only = true
|
|
92
98
|
note_input.clear_focus
|
|
93
99
|
end
|
|
94
100
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module QTimetrap
|
|
4
|
+
module Entries
|
|
5
|
+
# Display-field helpers for entry task controls.
|
|
6
|
+
module LeafTaskDisplayHelpers
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def sync_task_display_field(task_input, task_name)
|
|
10
|
+
task_input.text = task_name
|
|
11
|
+
task_input.tool_tip = task_name
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module QTimetrap
|
|
4
|
+
module Entries
|
|
5
|
+
# State transitions for entry task display/editor widgets.
|
|
6
|
+
module LeafTaskEditorStateHelpers
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def activate_entry_task_input(task_container)
|
|
10
|
+
close_previous_task_editor(task_container)
|
|
11
|
+
editor, editor_input = ensure_entry_task_editor(task_container)
|
|
12
|
+
show_entry_task_editor(task_container)
|
|
13
|
+
self.active_task_container = task_container
|
|
14
|
+
editor_input.read_only = false
|
|
15
|
+
editor.set_focus
|
|
16
|
+
editor_input.set_focus
|
|
17
|
+
editor.show_popup
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def deactivate_entry_task_input(task_container)
|
|
21
|
+
editor = entry_task_editor(task_container)
|
|
22
|
+
editor_input = entry_task_editor_line_edit(editor)
|
|
23
|
+
editor_input.read_only = true
|
|
24
|
+
editor.hide_popup
|
|
25
|
+
editor.clear_focus
|
|
26
|
+
show_entry_task_display(task_container)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def handle_entry_task_focus_out(task_container)
|
|
30
|
+
return unless task_container
|
|
31
|
+
|
|
32
|
+
reset_entry_task_editor(task_container)
|
|
33
|
+
deactivate_entry_task_input(task_container)
|
|
34
|
+
return unless active_task_container
|
|
35
|
+
return unless task_container_matches?(active_task_container, task_container)
|
|
36
|
+
|
|
37
|
+
self.active_task_container = nil
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def close_previous_task_editor(task_container)
|
|
41
|
+
return unless active_task_container
|
|
42
|
+
return if task_container_matches?(active_task_container, task_container)
|
|
43
|
+
|
|
44
|
+
handle_entry_task_focus_out(active_task_container)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def reset_entry_task_editor(task_container)
|
|
48
|
+
entry_task_editor(task_container).current_text = entry_task_display_input(task_container).text.to_s
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def show_entry_task_editor(task_container)
|
|
52
|
+
entry_task_display_input(task_container).hide
|
|
53
|
+
entry_task_editor(task_container).show
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def show_entry_task_display(task_container)
|
|
57
|
+
entry_task_editor(task_container).hide
|
|
58
|
+
entry_task_display_input(task_container).show
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def sync_entry_task_display(task_container, task_name)
|
|
62
|
+
sync_task_display_field(entry_task_display_input(task_container), task_name)
|
|
63
|
+
entry_task_editor(task_container).current_text = task_name
|
|
64
|
+
entry_task_editor(task_container).tool_tip = task_name
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|