timr 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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'