timr 0.1.0 → 0.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 169f2bc1266172e38449b616494751f1675e3cf7
4
- data.tar.gz: b33d71090571dbcd6aa1e21a62a39f2b6fd8c484
3
+ metadata.gz: 8e2d97ef6133107ff6c5f10ec8d7469ceab22317
4
+ data.tar.gz: 0eb7ce0ac1b3946fe7c4022c243cdfdd790eb360
5
5
  SHA512:
6
- metadata.gz: 9425deec3cc7505b9672cbef8eb5a977521ef5374e28c22ba54f7accaa98aae794152e3495486c28dc0df3e04de4da61222a3a70771a4e614be2308586ffc4b8
7
- data.tar.gz: 72769b4c7417eecfac58f7a00c0e1e7f19d5b3eb024cf818431a24306bf6d0fc772667fdb544da2633c91651eff95e380980d65ff8a12e38e6f1d6cc3e9a6088
6
+ metadata.gz: e431719fdaa4d85555c6578e61f80fb81c12e21d49b2ffbe74db47e2d21f727da133766b4eb645fbc04d77881586a35fe26febfc6d3a6ad03c95123f06b96421
7
+ data.tar.gz: f5fd40d36d15e55298686229bfd61e6dda2571bd8c0d4f306f89c7625ffcc53af52751f6ca6fb4ecfef7d241661c94a28af9d0de72ca7af024ed22327f8284e0
@@ -9,6 +9,6 @@ charset = utf-8
9
9
  trim_trailing_whitespace = false
10
10
  insert_final_newline = true
11
11
 
12
- [*.yml]
12
+ [*.{yml,conf}]
13
13
  indent_style = space
14
14
  indent_size = 4
data/.gitignore CHANGED
@@ -1,6 +1,8 @@
1
1
  /.bundle/
2
2
  .setup
3
3
  /bin/dev
4
+ CHANGELOG-*.txt
5
+ Gemfile.lock
4
6
  /releases/
5
7
  README.html
6
8
  /tmp/
data/Makefile CHANGED
@@ -5,7 +5,7 @@ ALL_TARGETS_EXT = tmp
5
5
  include Makefile.common
6
6
 
7
7
  dev:
8
- RUBYOPT=-rbundler/setup ruby ./bin/timr
8
+ RUBYOPT=-rbundler/setup ruby --debug ./bin/timr -d tmp/timr -c tmp/timr.conf
9
9
 
10
10
  .PHONY: test
11
11
  test:
@@ -1,9 +1,9 @@
1
1
 
2
2
  # Ruby Common Big
3
- # 2016-04-09
3
+ # 2016-05-20
4
4
 
5
5
  MV = mv -nv
6
- RM = rm -rf
6
+ RM = rm -rfd
7
7
  MKDIR = mkdir -p
8
8
  CHMOD = chmod
9
9
  BUNDLER = bundle
@@ -36,9 +36,7 @@ update:
36
36
 
37
37
  .PHONY: clean
38
38
  clean:
39
- $(RM) .bundle
40
- $(RM) .setup
41
- $(RM) Gemfile.lock
39
+ $(RM) .bundle .setup Gemfile.lock
42
40
 
43
41
  .PHONY: release
44
42
  release: | releases
data/bin/timr CHANGED
@@ -7,6 +7,7 @@ require 'timr'
7
7
 
8
8
  @options = {
9
9
  :dir => nil,
10
+ :config_path => "#{Dir.home}/.timr/timr.conf",
10
11
  }
11
12
  opts = OptionParser.new do |o|
12
13
  o.banner = 'Usage: timr [options]'
@@ -16,11 +17,15 @@ opts = OptionParser.new do |o|
16
17
  @options[:dir] = path
17
18
  end
18
19
 
19
- o.on('-p', '--project <name>', 'Project Name: use ~/.timr/NAME as path.') do |name|
20
+ o.on('-p', '--project <name>', 'Project Name: use ~/.timr/projects/NAME as path.') do |name|
20
21
  @options[:dir] = File.expand_path(name, "#{Dir.home}/.timr/projects")
21
22
  end
22
23
 
23
- o.on_tail('-v', '--version', 'Show version.') do
24
+ o.on('-c', '--config <path>', 'Path to config file. Default: ~/.timr/timr.conf') do |path|
25
+ @options[:config_path] = File.expand_path(path)
26
+ end
27
+
28
+ o.on_tail('-V', '--version', 'Show version.') do
24
29
  puts "#{TheFox::Timr::NAME} #{TheFox::Timr::VERSION} (#{TheFox::Timr::DATE})"
25
30
  puts "#{TheFox::Timr::HOMEPAGE}"
26
31
  exit
@@ -35,6 +40,10 @@ end
35
40
  ARGV << '-h' if ARGV.count == 0
36
41
  opts.parse(ARGV)
37
42
 
38
- timr = TheFox::Timr::Timr.new(@options[:dir])
39
- timr.run
40
- timr.close
43
+ timr = TheFox::Timr::Timr.new(@options[:dir], @options[:config_path])
44
+ begin
45
+ timr.run
46
+ rescue Exception => e
47
+ timr.close
48
+ raise e
49
+ end
@@ -17,7 +17,7 @@ module TheFox
17
17
  !@task.nil?
18
18
  end
19
19
 
20
- def length
20
+ def size
21
21
  @tasks.length
22
22
  end
23
23
 
@@ -34,15 +34,22 @@ module TheFox
34
34
  if !old.nil?
35
35
  old.stop
36
36
  @task = @tasks.last
37
- @task.start if has_task?
37
+ @task.start if !@task.nil?
38
38
  true
39
39
  else
40
40
  false
41
41
  end
42
42
  end
43
43
 
44
- def pop_all(new_task = nil)
45
- if @task != new_task
44
+ def pop_all(new_task = nil, parent_track = nil)
45
+ if @task == new_task
46
+ #puts 'tasks =='
47
+ x = @task.start(parent_track)
48
+ #puts "return #{x}"
49
+ #puts
50
+ x
51
+ else
52
+ #puts 'stop all tasks'
46
53
  @tasks.each do |task|
47
54
  task.stop
48
55
  end
@@ -50,20 +57,18 @@ module TheFox
50
57
  @task = nil
51
58
 
52
59
  if !new_task.nil?
53
- push(new_task)
60
+ push(new_task, parent_track)
54
61
  end
55
62
  true
56
- else
57
- false
58
63
  end
59
64
  end
60
65
 
61
- def push(task)
66
+ def push(task, parent_track = nil)
62
67
  if !@tasks.include?(task)
63
- @task.stop if has_task?
68
+ @task.pause if has_task?
64
69
 
65
70
  @task = task
66
- @task.start
71
+ @task.start(parent_track)
67
72
  @tasks << @task
68
73
  true
69
74
  else
@@ -19,8 +19,8 @@ module TheFox
19
19
  'id' => UUID.new.generate,
20
20
  'name' => nil,
21
21
  'description' => nil,
22
- 'created' => Time.now.utc.strftime(TIME_FORMAT),
23
- 'modified' => Time.now.utc.strftime(TIME_FORMAT),
22
+ 'created' => Time.now.utc.strftime(TIME_FORMAT_FILE),
23
+ 'modified' => Time.now.utc.strftime(TIME_FORMAT_FILE),
24
24
  }
25
25
  @track = nil
26
26
  @timeline = []
@@ -48,7 +48,7 @@ module TheFox
48
48
  timeline_c = @timeline
49
49
  .map{ |track|
50
50
  h = track.to_h
51
- h['e'] = Time.now.utc.strftime(TIME_FORMAT) if !h.has_key?('e') || h['e'].nil?
51
+ h['e'] = Time.now.utc.strftime(TIME_FORMAT_FILE) if !h.has_key?('e') || h['e'].nil?
52
52
  h
53
53
  }
54
54
 
@@ -67,10 +67,16 @@ module TheFox
67
67
  @status == :running
68
68
  end
69
69
 
70
+ def paused?
71
+ @status == :paused
72
+ end
73
+
70
74
  def status
71
75
  case @status
72
76
  when :running
73
77
  ?>
78
+ when :paused
79
+ ?#
74
80
  when :stop
75
81
  ?|
76
82
  end
@@ -78,7 +84,7 @@ module TheFox
78
84
 
79
85
  def changed
80
86
  @changed = true
81
- @meta['modified'] = Time.now.utc.strftime(TIME_FORMAT)
87
+ @meta['modified'] = Time.now.utc.strftime(TIME_FORMAT_FILE)
82
88
  end
83
89
 
84
90
  def id
@@ -115,22 +121,61 @@ module TheFox
115
121
  @timeline
116
122
  end
117
123
 
118
- def start
119
- if !running?
120
- @changed = true
121
- @track = Track.new(self)
124
+ def start(parent_track = nil)
125
+ create_new_track = false
126
+
127
+ if running?
128
+ if !parent_track.nil?
129
+ if @track.description != parent_track.description
130
+ stop
131
+ create_new_track = true
132
+ end
133
+ end
134
+ elsif paused?
135
+ parent_track = @track
136
+ create_new_track = true
137
+ else
138
+ create_new_track = true
139
+ end
140
+
141
+ if create_new_track
142
+ @track = Track.new
143
+ if !parent_track.nil?
144
+ @track.parent = parent_track
145
+ @track.description = parent_track.description
146
+ end
147
+
148
+ @track.task = self
149
+ @track.begin_time = Time.now
122
150
  @timeline << @track
151
+
152
+ @changed = true
123
153
  end
154
+
124
155
  @status = :running
156
+
157
+ create_new_track
125
158
  end
126
159
 
127
- def stop
128
- if running? && !@track.nil?
160
+ def pause
161
+ if !@track.nil?
162
+ @status = :paused
129
163
  @changed = true
130
164
  @track.end_time = Time.now
165
+ end
166
+ end
167
+
168
+ def stop
169
+ if !@track.nil?
170
+ if running?
171
+ @changed = true
172
+ @track.end_time = Time.now
173
+ end
174
+
131
175
  @track = nil
132
176
  @timeline_diff_total = nil
133
177
  end
178
+
134
179
  @status = :stop
135
180
  end
136
181
 
@@ -143,7 +188,11 @@ module TheFox
143
188
  end
144
189
 
145
190
  def to_s
146
- name
191
+ track_description = ''
192
+ if has_track? && !@track.description.nil? && @track.description.to_s.length > 0
193
+ track_description = ": #{@track.description}"
194
+ end
195
+ '%s%s' % [name, track_description]
147
196
  end
148
197
 
149
198
  def to_list_s
@@ -2,6 +2,8 @@
2
2
  require 'curses'
3
3
  require 'time'
4
4
  require 'fileutils'
5
+ require 'yaml/store'
6
+ require 'thefox-ext'
5
7
 
6
8
  module TheFox
7
9
  module Timr
@@ -10,19 +12,31 @@ module TheFox
10
12
 
11
13
  #include Curses
12
14
 
13
- def initialize(path)
14
- @base_dir_path = File.expand_path(path)
15
+ def initialize(base_dir_path, config_path = nil)
16
+ @base_dir_path = File.expand_path(base_dir_path)
15
17
  @base_dir_name = File.basename(@base_dir_path)
16
18
  @data_dir_path = "#{@base_dir_path}/data"
19
+ @config_path = config_path
17
20
 
18
- puts "base: #{@base_dir_path}"
19
- puts "name: #{@base_dir_name}"
20
- puts "data: #{@data_dir_path}"
21
+ puts "base: #{@base_dir_path}"
22
+ puts "name: #{@base_dir_name}"
23
+ puts "data: #{@data_dir_path}"
24
+ puts "config: #{@config_path}"
21
25
 
22
26
  @stack = Stack.new
23
27
  @tasks = {}
24
28
  @last_write = nil
29
+ @config = {
30
+ 'clock' => {
31
+ 'default' => '%F %R',
32
+ 'large' => '%F %T',
33
+ 'short' => '%R',
34
+ },
35
+ }
36
+ #@ui_window_refresh_last = nil
37
+ #@ui_status_line_last = nil
25
38
 
39
+ config_read
26
40
  init_dirs
27
41
  tasks_load
28
42
 
@@ -37,6 +51,15 @@ module TheFox
37
51
  @window_timeline.tasks = @tasks
38
52
  end
39
53
 
54
+ def config_read(path = @config_path)
55
+ if !path.nil? && File.exist?(path)
56
+ content = YAML::load_file(path)
57
+ if content
58
+ @config.merge_recursive!(content)
59
+ end
60
+ end
61
+ end
62
+
40
63
  def init_dirs
41
64
  if !Dir.exist?(@base_dir_path)
42
65
  FileUtils.mkdir_p(@base_dir_path)
@@ -108,14 +131,17 @@ module TheFox
108
131
  end
109
132
  end
110
133
 
111
- def ui_status_text(text, attrn = Curses::A_NORMAL)
134
+ # This is the line on the bottom of the screen.
135
+ def ui_status_text(text = nil, attrn = Curses::A_NORMAL)
112
136
  line_nr = Curses.lines - 1
113
137
 
114
138
  Curses.setpos(line_nr, 0)
115
139
  Curses.clrtoeol
116
- Curses.setpos(line_nr, COL)
117
- Curses.attron(attrn) do
118
- Curses.addstr(text)
140
+ if !text.nil?
141
+ Curses.setpos(line_nr, COL)
142
+ Curses.attron(attrn) do
143
+ Curses.addstr(text)
144
+ end
119
145
  end
120
146
  Curses.refresh
121
147
  end
@@ -124,6 +150,7 @@ module TheFox
124
150
  ui_status_text(text, Curses.color_pair(Curses::COLOR_RED) | Curses::A_BOLD)
125
151
  end
126
152
 
153
+ # Use the Status Text line to get an input from user.
127
154
  def ui_status_input(text)
128
155
  Curses.echo
129
156
  Curses.timeout = -1
@@ -140,12 +167,17 @@ module TheFox
140
167
  abort = true
141
168
  break
142
169
  when Curses::Key::BACKSPACE
143
- Curses.stdscr.delch
144
- input = input[0..-2]
170
+ if input.length > 0
171
+ Curses.stdscr.delch
172
+ input = input[0..-2]
173
+ end
145
174
  when 10
146
175
  break
176
+ when nil
177
+ # Do nothing.
178
+ #sleep TIMEOUT.to_f / 1000
147
179
  else
148
- input += key_pressed
180
+ input += key_pressed.to_s
149
181
  end
150
182
  end
151
183
  if abort
@@ -159,9 +191,75 @@ module TheFox
159
191
  input
160
192
  end
161
193
 
194
+ # The second line from the bottom:
195
+ # Show current Track status, Track Time Difference, Task Time Total.
162
196
  def ui_status_line(init = false)
163
197
  line_nr = Curses.lines - 2
164
198
 
199
+ status_s = ''
200
+ track_begin_time_s = ''
201
+
202
+ run_time_track_str = ''
203
+ run_time_track_h = 0
204
+ run_time_track_m = 0
205
+ run_time_track_s = 0
206
+
207
+ run_time_total_str = ''
208
+ run_time_total_h = 0
209
+ run_time_total_m = 0
210
+ run_time_total_s = 0
211
+
212
+ time_s = ''
213
+
214
+ stack_has_task = @stack.has_task?.freeze
215
+ if stack_has_task
216
+ status_s = @stack.task.status
217
+
218
+ track_begin_time_s = '--:--'
219
+ if @stack.task.has_track?
220
+ track_begin_time_s = @stack.task.track.begin_time.strftime('%R')
221
+ end
222
+
223
+ run_time_track_h, run_time_track_m, run_time_track_s = @stack.task.run_time_track
224
+ run_time_total_h, run_time_total_m, run_time_total_s = @stack.task.run_time_total
225
+ else
226
+ status_s = TASK_NO_TASK_LOADED_CHAR
227
+ end
228
+
229
+ if Curses.cols > MIN_COLS
230
+ if stack_has_task
231
+ run_time_track_str = '%2d:%02d:%02d' % [run_time_track_h, run_time_track_m, run_time_track_s]
232
+ run_time_total_str = '%2d:%02d:%02d' % [run_time_total_h, run_time_total_m, run_time_total_s]
233
+ end
234
+
235
+ time_format = @config['clock']['default']
236
+ if Curses.cols <= 50
237
+ if stack_has_task
238
+ run_time_track_str = '%2d:%02d' % [run_time_track_h, run_time_track_m]
239
+ end
240
+ run_time_total_str = ''
241
+
242
+ time_format = nil
243
+ elsif Curses.cols <= 60
244
+ if stack_has_task
245
+ run_time_track_str = '%2d:%02d' % [run_time_track_h, run_time_track_m]
246
+ run_time_total_str = '%2d:%02d' % [run_time_total_h, run_time_total_m]
247
+ end
248
+
249
+ time_format = @config['clock']['short']
250
+ elsif Curses.cols > 80
251
+ time_format = @config['clock']['large']
252
+ end
253
+ if !time_format.nil?
254
+ time_s = Time.now.strftime(time_format)
255
+ end
256
+ end
257
+
258
+ line = "#{status_s} #{track_begin_time_s} #{run_time_track_str} #{run_time_total_str}"
259
+
260
+ rest = Curses.cols - COL - line.length - time_s.length - 1
261
+ line += ' ' * rest + time_s
262
+
165
263
  Curses.attron(Curses.color_pair(Curses::COLOR_GREEN) | Curses::A_NORMAL) do
166
264
  if init
167
265
  Curses.setpos(line_nr, 0)
@@ -170,37 +268,7 @@ module TheFox
170
268
  end
171
269
 
172
270
  Curses.setpos(line_nr, COL)
173
- if @stack.has_task?
174
- status = @stack.task.status
175
- track_begin_time_s = '--:--'
176
- if @stack.task.has_track?
177
- track_begin_time_s = @stack.task.track.begin_time.strftime('%R')
178
- end
179
- run_time_track = '%4d:%02d:%02d' % @stack.task.run_time_track
180
- run_time_total = '%4d:%02d:%02d' % @stack.task.run_time_total
181
-
182
- Curses.addstr("#{status} #{track_begin_time_s} #{run_time_track} #{run_time_total}")
183
- else
184
- Curses.addstr("#{TASK_NO_TASK_LOADED_C} --:-- ----:--:-- ----:--:--")
185
- end
186
-
187
- if Curses.cols > MIN_COLS
188
- time_format = '%F %R'
189
- if Curses.cols <= 30
190
- time_format = '%R'
191
- elsif Curses.cols <= 40
192
- time_format = '%m-%d %R'
193
- elsif Curses.cols <= 50
194
- time_format = '%y-%m-%d %R'
195
- elsif Curses.cols <= 60
196
- time_format = '%F %R'
197
- elsif Curses.cols > 80
198
- time_format = '%F %T'
199
- end
200
- time_str = Time.now.strftime(time_format)
201
- Curses.setpos(line_nr, Curses.cols - time_str.length - 1)
202
- Curses.addstr(time_str)
203
- end
271
+ Curses.addstr(line)
204
272
  end
205
273
 
206
274
  Curses.refresh
@@ -208,18 +276,47 @@ module TheFox
208
276
 
209
277
  def ui_window_show(window)
210
278
  @window = window
211
- ui_window_refresh
279
+ ui_window_refresh_all
212
280
  end
213
281
 
214
- def ui_window_refresh
215
- max_lines = ui_content_length
216
- (1..max_lines).each do |line_nr|
217
- Curses.setpos(line_nr, 0)
218
- Curses.clrtoeol
282
+ def ui_content_line(line_nr, text)
283
+ Curses.setpos(line_nr, 0)
284
+ Curses.clrtoeol
285
+
286
+ rest = Curses.cols - text.length - COL
287
+ if rest < 0
288
+ rest = 0
219
289
  end
290
+ out = ' ' * COL + text + ' ' * rest
220
291
 
292
+ if @window.has_cursor? && line_nr == @window.cursor
293
+ Curses.attron(Curses.color_pair(Curses::COLOR_BLUE) | Curses::A_BOLD) do
294
+ Curses.addstr(out)
295
+ end
296
+ else
297
+ Curses.addstr(out)
298
+ end
299
+ end
300
+
301
+ def ui_window_refresh(lines)
302
+ ui_window_refresh_all
303
+
304
+ # if !@window.nil?
305
+ # simple_refresh = @window.cursor_on_inner_range?
306
+
307
+ # if !simple_refresh || simple_refresh != @ui_window_refresh_last
308
+ # ui_window_refresh_all
309
+ # else
310
+ # ui_window_refresh_simple(lines)
311
+ # end
312
+
313
+ # @ui_window_refresh_last = simple_refresh
314
+ # end
315
+ end
316
+
317
+ def ui_window_refresh_all
221
318
  if !@window.nil?
222
- line_nr = 1
319
+ content_line_nr = 1
223
320
  @window.content_refresh
224
321
  max_line_len = Curses.cols - 2
225
322
  @window.page.each do |line_object|
@@ -231,36 +328,81 @@ module TheFox
231
328
  end
232
329
 
233
330
  if line_text.length > max_line_len
234
- cut = line_text.length - max_line_len + 4
235
- line_text = "#{line_text[0..-cut]}..."
331
+ range = 0..-(line_text.length - max_line_len + 4)
332
+ line_text = "#{line_text[range]}..."
236
333
  end
237
334
 
238
- rest = Curses.cols - line_text.length - COL
335
+ ui_content_line(content_line_nr, line_text)
239
336
 
240
- if @window.has_cursor?
241
- if line_nr == @window.cursor
242
- Curses.setpos(line_nr, 0)
243
- Curses.attron(Curses.color_pair(Curses::COLOR_BLUE) | Curses::A_BOLD) do
244
- Curses.addstr(' ' * COL + line_text + ' ' * rest)
245
- end
246
- else
247
- Curses.setpos(line_nr, COL)
248
- Curses.addstr(line_text)
249
- end
250
- else
251
- Curses.setpos(line_nr, COL)
252
- Curses.addstr(line_text)
253
- end
337
+ content_line_nr += 1
254
338
 
255
- line_nr += 1
339
+ # if $DEBUG
340
+ # Curses.refresh
341
+ # sleep 0.01
342
+ # end
343
+ end
344
+
345
+ window_page_length = @window.page_length
346
+ content_length = ui_content_length
347
+ if window_page_length < content_length
348
+ ((window_page_length + 1)..content_length).to_a.each do |rest_line_nr|
349
+ Curses.setpos(rest_line_nr, 0)
350
+ Curses.clrtoeol
351
+
352
+ # if $DEBUG
353
+ # Curses.addstr("-- CLEAR -- #{rest_line_nr} #{Time.now.strftime('%T')}")
354
+ # Curses.refresh
355
+ # sleep 0.01
356
+ # end
357
+ end
256
358
  end
257
359
  end
258
360
 
259
361
  Curses.refresh
260
362
  end
261
363
 
364
+ def ui_window_refresh_simple(lines)
365
+ max_line_len = Curses.cols - 2
366
+
367
+
368
+ old_cursor = @window.cursor + (lines * -1)
369
+ old_line_object = @window.page[old_cursor - 1]
370
+
371
+ old_line_text = ''
372
+ if old_line_object.is_a?(Task) || old_line_object.is_a?(Track)
373
+ old_line_text = old_line_object.to_list_s
374
+ else
375
+ old_line_text = old_line_object.to_s
376
+ end
377
+
378
+ if old_line_text.length > max_line_len
379
+ range = 0..-(line_text.length - max_line_len + 4)
380
+ old_line_text = "#{old_line_text[range]}..."
381
+ end
382
+
383
+
384
+ new_cursor = @window.cursor
385
+ new_line_object = @window.page[new_cursor - 1]
386
+
387
+ new_line_text = ''
388
+ if new_line_object.is_a?(Task) || new_line_object.is_a?(Track)
389
+ new_line_text = new_line_object.to_list_s
390
+ else
391
+ new_line_text = new_line_object.to_s
392
+ end
393
+
394
+ if new_line_text.length > max_line_len
395
+ range = 0..-(line_text.length - max_line_len + 4)
396
+ new_line_text = "#{new_line_text[range]}..."
397
+ end
398
+
399
+ ui_content_line(old_cursor, old_line_text)
400
+ ui_content_line(@window.cursor, new_line_text)
401
+ Curses.refresh
402
+ end
403
+
262
404
  def ui_content_length
263
- Curses.lines - RESERVED_LINES - @stack.length
405
+ Curses.lines - RESERVED_LINES - @stack.size
264
406
  end
265
407
 
266
408
  def update_content_length
@@ -272,20 +414,22 @@ module TheFox
272
414
  @window_timeline.content_length = cl
273
415
  end
274
416
 
275
- def ui_refresh
417
+ def ui_refresh_simple
276
418
  ui_stack_lines_refresh
277
- ui_window_refresh
419
+ ui_window_refresh_all
278
420
  end
279
421
 
280
422
  def ui_refresh_all
423
+ #@ui_window_refresh_last = nil
424
+
281
425
  update_content_length
282
426
  ui_title_line
283
427
  ui_status_line(true)
284
- ui_refresh
428
+ ui_refresh_simple
285
429
  end
286
430
 
287
431
  def ui_stack_lines_refresh
288
- line_nr = Curses.lines - (3 + (@stack.length - 1))
432
+ line_nr = Curses.lines - (3 + (@stack.size - 1))
289
433
 
290
434
  Curses.attron(Curses.color_pair(Curses::COLOR_BLUE)) do
291
435
  @stack.tasks_texts.reverse.each do |line_text|
@@ -302,41 +446,42 @@ module TheFox
302
446
  Curses.refresh
303
447
  end
304
448
 
305
- def task_apply(task = nil, push = false)
449
+ def task_apply(task = nil, parent_track = nil, push = false)
306
450
  if task.nil?
307
451
  @stack.pop_all
308
452
  else
309
453
  @tasks[task.id] = task
310
454
  if push
311
- @stack.push(task)
455
+ @stack.push(task, parent_track)
312
456
  else
313
- @stack.pop_all(task)
457
+ @stack.pop_all(task, parent_track)
314
458
  end
315
459
  end
316
460
 
317
461
  update_content_length
318
462
  window_content_changed
319
463
  ui_stack_lines_refresh
320
- ui_window_refresh
464
+ ui_window_refresh_all
321
465
  end
322
466
 
323
- def task_apply_replace_stack(task)
324
- task_apply(task, false)
467
+ def task_apply_replace_stack(task, parent_track = nil)
468
+ if !task.nil?
469
+ task_apply(task, parent_track, false)
470
+ end
325
471
  end
326
472
 
327
473
  def task_apply_stack_pop_all
328
- task_apply(nil, false)
474
+ task_apply(nil, nil, false)
329
475
  end
330
476
 
331
- def task_apply_push(task)
332
- task_apply(task, true)
477
+ def task_apply_push(task, parent_track = nil)
478
+ task_apply(task, parent_track, true)
333
479
  end
334
480
 
335
481
  def task_apply_pop
336
482
  if @stack.pop
337
483
  update_content_length
338
- #window_content_changed
339
- ui_refresh
484
+ ui_refresh_simple
340
485
  end
341
486
  end
342
487
 
@@ -350,6 +495,21 @@ module TheFox
350
495
  @window_timeline.content_changed
351
496
  end
352
497
 
498
+ def window_page_object
499
+ object = @window.page_object if !@window.nil?
500
+
501
+ task = nil
502
+ track = nil
503
+ if object.is_a?(Task)
504
+ task = object
505
+ elsif object.is_a?(Track)
506
+ task = object.task
507
+ track = object
508
+ end
509
+
510
+ [task, track]
511
+ end
512
+
353
513
  def write_all_data
354
514
  if @last_write.nil?
355
515
  @last_write = Time.now
@@ -373,32 +533,64 @@ module TheFox
373
533
  case key_pressed
374
534
  when Curses::Key::NPAGE
375
535
  @window.next_page if !@window.nil?
376
- ui_window_refresh
536
+
537
+ # if $DEBUG
538
+ # ui_status_text('DEBUG: %03d C=%03d L=%03d pr=%03d cr=%03d' % [@window.cursor, ui_content_length, @window.current_line, @window.page_refreshes, @window.content_refreshes])
539
+ # end
540
+
541
+ ui_window_refresh_all
377
542
  when Curses::Key::PPAGE
378
543
  @window.previous_page if !@window.nil?
379
- ui_window_refresh
544
+
545
+ # if $DEBUG
546
+ # ui_status_text('DEBUG: %03d C=%03d L=%03d pr=%03d cr=%03d' % [@window.cursor, ui_content_length, @window.current_line, @window.page_refreshes, @window.content_refreshes])
547
+ # end
548
+
549
+ ui_window_refresh_all
380
550
  when Curses::Key::DOWN
381
551
  if !@window.nil? && @window.has_cursor?
382
- @window.cursor_next_line
552
+ simple_refresh_b = @window.cursor_on_inner_range?
383
553
 
384
- #ui_status_text("Cursor: #{@window.cursor} c=#{ui_content_length} l=#{@window.current_line} pr=#{@window.page_refreshes} cr=#{@window.content_refreshes}")
554
+ @window.cursor_next_line
385
555
 
386
- ui_window_refresh
556
+ simple_refresh_a = @window.cursor_on_inner_range?
557
+
558
+ # if $DEBUG
559
+ # ui_status_text('DEBUG: %03d C=%03d L=%03d pr=%03d cr=%03d %02d %02d %s %s' % [@window.cursor, ui_content_length, @window.current_line, @window.page_refreshes, @window.content_refreshes, @window.cursor_border_top, @window.cursor_border_bottom, simple_refresh_b ? 'SIMPLE' : 'FULL', simple_refresh_a ? 'SIMPLE' : 'FULL'])
560
+ #end
561
+
562
+ ui_window_refresh(1)
387
563
  end
388
564
  when Curses::Key::UP
389
565
  if !@window.nil? && @window.has_cursor?
566
+ simple_refresh_b = @window.cursor_on_inner_range?
567
+
390
568
  @window.cursor_previous_line
391
569
 
392
- #ui_status_text("Cursor: #{@window.cursor} c=#{ui_content_length} l=#{@window.current_line} pr=#{@window.page_refreshes} cr=#{@window.content_refreshes}")
570
+ simple_refresh_a = @window.cursor_on_inner_range?
571
+
572
+ # if $DEBUG
573
+ # ui_status_text('DEBUG: %03d C=%03d L=%03d pr=%03d cr=%03d %02d %02d %s %s' % [@window.cursor, ui_content_length, @window.current_line, @window.page_refreshes, @window.content_refreshes, @window.cursor_border_top, @window.cursor_border_bottom, simple_refresh_b ? 'SIMPLE' : 'FULL', simple_refresh_a ? 'SIMPLE' : 'FULL'])
574
+ # end
393
575
 
394
- ui_window_refresh
576
+ ui_window_refresh(-1)
395
577
  end
396
578
  when Curses::Key::HOME
397
579
  @window.first_page if !@window.nil?
398
- ui_window_refresh
580
+
581
+ if $DEBUG
582
+ ui_status_text('DEBUG: %03d C=%03d L=%03d pr=%03d cr=%03d' % [@window.cursor, ui_content_length, @window.current_line, @window.page_refreshes, @window.content_refreshes])
583
+ end
584
+
585
+ ui_window_refresh_all
399
586
  when Curses::Key::END
400
587
  @window.last_page if !@window.nil?
401
- ui_window_refresh
588
+
589
+ # if $DEBUG
590
+ # ui_status_text('DEBUG: %03d C=%03d L=%03d pr=%03d cr=%03d' % [@window.cursor, ui_content_length, @window.current_line, @window.page_refreshes, @window.content_refreshes])
591
+ # end
592
+
593
+ ui_window_refresh_all
402
594
  when Curses::Key::RESIZE
403
595
  update_content_length
404
596
  ui_status_text("Window size: #{Curses.cols}x#{Curses.lines}")
@@ -408,36 +600,31 @@ module TheFox
408
600
  # comment this line.
409
601
  ui_refresh_all
410
602
  when 10
411
- object = @window.page_object if !@window.nil?
603
+ task, track = window_page_object
604
+ task_apply_replace_stack(task, track)
605
+ when '#'
606
+ task, * = window_page_object
412
607
 
413
- task = nil
414
- if object.is_a?(Task)
415
- task = object
416
- elsif object.is_a?(Track)
417
- task = object.task
418
- end
608
+ track_description = ui_status_input('Track Description: ')
609
+ ui_status_text("Description: '#{track_description}'")
419
610
 
420
- if !task.nil? # && @stack.task != task
421
- task_apply_replace_stack(task)
422
- end
423
- when 'b', 'p'
424
- object = @window.page_object if !@window.nil?
611
+ track = Track.new
612
+ track.task = task
613
+ track.description = track_description
425
614
 
426
- task = nil
427
- if object.is_a?(Task)
428
- task = object
429
- elsif object.is_a?(Track)
430
- task = object.task
431
- end
615
+ task_apply_replace_stack(task, track)
616
+ #ui_status_text('OK')
617
+ when 'b', 'p'
618
+ task, track = window_page_object
432
619
 
433
620
  if task.nil?
434
621
  ui_status_text("Unrecognized object: #{object.class}")
435
622
  else
436
- task_apply_push(task)
623
+ task_apply_push(task, track)
437
624
  end
438
625
  when 'r'
439
626
  ui_refresh_all
440
- ui_status_text('')
627
+ ui_status_text
441
628
  when 'n'
442
629
  task_name = ui_status_input('New task: ')
443
630
  if task_name.nil?
@@ -445,30 +632,50 @@ module TheFox
445
632
  else
446
633
  task = Task.new
447
634
  task.name = task_name
635
+ task.save_to_file(@data_dir_path)
636
+
448
637
  task_apply_replace_stack(task)
449
638
 
639
+ ui_status_text("Task '#{task_name}' created.")
640
+ end
641
+ when 't'
642
+ task_name = ui_status_input('New task: ')
643
+ if task_name.nil?
644
+ ui_status_text('Aborted.')
645
+ else
646
+ task = Task.new
647
+ task.name = task_name
648
+ task.save_to_file(@data_dir_path)
649
+
650
+ @tasks[task.id] = task
651
+
652
+ update_content_length
653
+ window_content_changed
654
+ ui_stack_lines_refresh
655
+ ui_window_refresh_all
656
+
450
657
  ui_status_text("Task '#{task_name}' created.")
451
658
  end
452
659
  when 'x'
453
660
  @stack.task.stop if @stack.has_task?
454
661
  window_content_changed
455
- ui_refresh
662
+ ui_refresh_simple
456
663
  when 'c'
457
664
  @stack.task.toggle if @stack.has_task?
458
665
  window_content_changed
459
- ui_refresh
666
+ ui_refresh_simple
460
667
  when 'v'
461
668
  task_apply_pop
462
669
  when 'f'
463
670
  task_apply_stack_pop_all
464
671
  when 'h', '?'
465
672
  ui_window_show(@window_help)
466
- when 't' # Test Windows
467
- ui_window_show(@window_test)
468
673
  when '1'
469
674
  ui_window_show(@window_timeline)
470
675
  when '2'
471
676
  ui_window_show(@window_tasks)
677
+ when '3' # Test Windows
678
+ ui_window_show(@window_test)
472
679
  when 'w'
473
680
  tasks_save(true)
474
681
  when 'q'