accutronic 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,198 @@
1
+ #!/usr/bin/ruby
2
+ # encoding: utf-8
3
+
4
+ # Simple library which provides a simple
5
+ # command line "File Manager" interface.
6
+ #
7
+ #
8
+ # Author:: Luke Spangler
9
+ # Email:: m27frogy.roblox@gmail.com
10
+
11
+ require "abc"
12
+ require "accu-window"
13
+
14
+ # Primary module which contains
15
+ # the methods.
16
+ module FileLibrary
17
+
18
+ # Enables completion in the file
19
+ # manager by taking in a directory
20
+ # and input text and returning
21
+ # a matching file or the original
22
+ # text if no match is found.
23
+ def self.Completion(dir,text)
24
+ #--
25
+ result = text
26
+ range = (0)..(text.length-1)
27
+ Dir.foreach(dir) { |file|
28
+ #puts file.slice(range), text
29
+ if file.slice(range) == text then
30
+ result = file
31
+ break
32
+ end
33
+ }
34
+ return result
35
+ #++
36
+ end
37
+
38
+ # Selects a file using a simple command-line
39
+ # navigation system.
40
+ def self.SelectFile()
41
+ #--
42
+ origDir = Dir.pwd
43
+ currentDirectory = ""
44
+ selection = ""
45
+ request = ""
46
+ while selection == "" do
47
+ currentDirectory = Dir.pwd
48
+ puts "---------\nPWD: " + currentDirectory + "\n---------"
49
+ Dir.foreach(currentDirectory) { |file|
50
+ if File.directory? file then
51
+ puts "|" + file + "| - dir"
52
+ else
53
+ puts "|" + file + "| - file"
54
+ end
55
+ }
56
+ puts "---------"
57
+ request = gets
58
+ request.slice!(-1)
59
+ while not (File.exists? request) do
60
+ puts "Invalid: |" + request + "|"
61
+ puts "Please enter a valid file name or directory."
62
+ request = gets
63
+ request.slice!(-1)
64
+ if not File.exists? request then
65
+ request = self.Completion(currentDirectory,request)
66
+ if File.exists? request then
67
+ if not File.directory? request then
68
+ puts "Is this file correct: |" + request + "| |Y N| "
69
+ else
70
+ puts "Is this directory correct: |" + request + "| |Y N| "
71
+ end
72
+ if WindowTerminal.getchr.downcase != "y" then
73
+ request = ""
74
+ end
75
+ end
76
+ end
77
+ end
78
+ if File.directory? request then
79
+ Dir.chdir(request)
80
+ else
81
+ selection = request
82
+ end
83
+ end
84
+ selection = Dir.pwd + "/" + selection
85
+ puts "File selected: |" + selection + "|"
86
+ return selection
87
+ #++
88
+ end
89
+
90
+ # An implementation of SelectFile
91
+ # using WindowTerminal.
92
+ def self.SelectFile_With_Windows(manager=WindowTerminal::WindowManager.new)
93
+ #--
94
+ # Declarations
95
+ origDir = Dir.pwd
96
+ currentDirectory = ""
97
+ selection = ""
98
+ request = ""
99
+ # Define window.
100
+ window = WindowTerminal::Window.new(WindowTerminal::Orientation.new,"Browse for file.")
101
+ text = WindowTerminal::WrappedText.new(WindowTerminal::Orientation.new(-1,0),"",5,:preserve)
102
+ text2 = WindowTerminal::ColoredText.new(WindowTerminal::Orientation.new(1,0),"",5)
103
+ window.add_objects text2,text
104
+ num = manager.new_page window
105
+ manager.display_page num
106
+ # Standard loop.
107
+ while selection == "" do
108
+ text2.set_text ""
109
+ currentDirectory = Dir.pwd
110
+ string = ""
111
+ string << "---------\nPWD: " + currentDirectory + "\n---------\n"
112
+ Dir.foreach(currentDirectory) { |file|
113
+ if File.directory? file then
114
+ string << "|" + file + "| dir\n"
115
+ else
116
+ string << "|" + file + "| file\n"
117
+ end
118
+ }
119
+ string << "---------\n"
120
+ string = string.split("\n")
121
+ range = 0..(string.length-1)
122
+ text.set_text string[range].join("\n")
123
+ WindowTerminal.screen_render
124
+ char = WindowTerminal.getchr().downcase()
125
+ while (char == "w") or (char == "s") do
126
+ if char == "w" then
127
+ start = range.begin - 1
128
+ start = 0 if start < 0
129
+ ending = range.end
130
+ range = start..ending
131
+ else
132
+ start = range.begin + 1
133
+ start = range.end if start > range.end
134
+ ending = range.end
135
+ range = start..ending
136
+ end
137
+ text.set_text string[range].join("\n")
138
+ WindowTerminal.screen_render
139
+ char = WindowTerminal.getchr().downcase()
140
+ end
141
+ #puts string
142
+ text2.set_text "File: "
143
+ WindowTerminal.screen_render
144
+ request = ""
145
+ while not (File.exists? request) do
146
+ text2.set_text "Invalid: |" + request + "| Please enter a valid file name or directory." if request != ""
147
+ WindowTerminal.screen_render
148
+ request = WindowTerminal.getchrs { |char,full|
149
+ text2.set_text "File: " + full
150
+ #WindowTerminal.screen_render
151
+ }
152
+ if not File.exists? request then
153
+ request = self.Completion(currentDirectory,request)
154
+ if File.exists? request then
155
+ if not File.directory? request then
156
+ text2.set_text "Is this file correct: |" + request + "| |Y N| "
157
+ else
158
+ text2.set_text "Is this directory correct: |" + request + "| |Y N| "
159
+ end
160
+ WindowTerminal.screen_render
161
+ if WindowTerminal.getchr.downcase != "y" then
162
+ request = ""
163
+ end
164
+ end
165
+ end
166
+ end
167
+ if File.directory? request then
168
+ Dir.chdir(request)
169
+ else
170
+ selection = request
171
+ end
172
+ end
173
+ selection = Dir.pwd + "/" + selection
174
+ text2.set_text ""
175
+ text.set_text "File selected: |" + selection + "|"
176
+ WindowTerminal.screen_render
177
+ WindowTerminal.getchr()
178
+ # Cleanup window.
179
+ manager.remove_page num
180
+ # Return
181
+ return selection
182
+ #++
183
+ end
184
+ end
185
+
186
+ # Copyright 2014 Luke Spangler
187
+ #
188
+ # Licensed under the Apache License, Version 2.0 (the "License");
189
+ # you may not use this file except in compliance with the License.
190
+ # You may obtain a copy of the License at
191
+ #
192
+ # http://www.apache.org/licenses/LICENSE-2.0
193
+ #
194
+ # Unless required by applicable law or agreed to in writing, software
195
+ # distributed under the License is distributed on an "AS IS" BASIS,
196
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
197
+ # See the License for the specific language governing permissions and
198
+ # limitations under the License.
@@ -0,0 +1,756 @@
1
+ # This is a library which uses some hacky references
2
+ # together with lots of math and loops to split
3
+ # a terminal into windows, via the module WindowTerminal.
4
+ # There are also several smaller classes declared
5
+ # which include:
6
+ #
7
+ # Orientation:: A class for orienting objects.
8
+ # Text:: A class for printing text in a window, based on an Orientation object.
9
+ # ColoredText:: A subclass of Text which adds compatibility for colored text.
10
+ # WrappedText:: A subclass of Text which allows text to be wrapped into a window.
11
+ # ColoredWrappedText:: A subclass of WrappedText which adds support for colored text.
12
+ # Line:: A class which creates a horizontal line across a window.
13
+ # Window:: The main class which handles the rendering of basic windows and their objects in a terminal emulator.
14
+ # WindowManager:: A class which allows simple(r) handling and rendering of windows and their objects.
15
+ #
16
+ #
17
+ # Author:: Luke Spangler
18
+ # Email:: m27frogy.roblox@gmail.com
19
+
20
+ require "highline/import"
21
+
22
+ # The primary module in-which the majority
23
+ # of classes and methods are bundled.
24
+ module WindowTerminal
25
+ TIOCGNWINSZ = 0x5413
26
+ STDOUT_HANDLE = 0xFFFFFFF5
27
+ @@windows = []
28
+
29
+ # A class which stores the Orientation
30
+ # of an object.
31
+ class Orientation
32
+ attr_reader :x,:y
33
+
34
+ # Initializes an Orienation object.
35
+ def initialize(x=0,y=0)
36
+ if x != -1 and x != 0 and x != 1 then
37
+ x = 0
38
+ end
39
+ if y != -1 and y != 0 and y != 1 then
40
+ y = 0
41
+ end
42
+ @x = x
43
+ @y = y
44
+ end
45
+
46
+ # Makes the to_s return a more
47
+ # "bootiful" string.
48
+ def to_s
49
+ "#{@x}|#{@y}"
50
+ end
51
+ end
52
+
53
+ # Aclass for use with the Window object
54
+ # in rendering strings with Orientation.
55
+ class Text
56
+ attr_reader :orientation,:text, :y
57
+
58
+ # Initializes a Text object.
59
+ def initialize(orientation,text,y)
60
+ raise "Orientation must be passed!" if not orientation.is_a? Orientation
61
+ raise "String must be passed!" if not text.is_a? String
62
+ @orientation = orientation
63
+ @text = text
64
+ @y = y
65
+ end
66
+
67
+ # Allows the @text instance variable
68
+ # to be mutable.
69
+ def set_text(text)
70
+ @text = text
71
+ end
72
+
73
+ # Gets the length of the objects string
74
+ # while ignoring the character 27.
75
+ def get_length(text=@text)
76
+ #--
77
+ length = 0
78
+ text.each_char {|char|
79
+ if char.ord != 27 then
80
+ length += 1
81
+ end
82
+ }
83
+ #puts length
84
+ return length
85
+ #++
86
+ end
87
+
88
+ # Renders a line of text.
89
+ def render_line(line,width,*args)
90
+ #--
91
+ line = line.dup
92
+ if get_length() == @text.length and get_length.even? then
93
+ @text << " "
94
+ end
95
+ if args[0] == nil then
96
+ args[0] = 0
97
+ end
98
+ start = args[0]
99
+ if @orientation.x == 0 then
100
+ length = get_length()
101
+ real_length = @text.length
102
+ difference = (length - real_length).abs
103
+ # Calculate centering.
104
+ centered_width = (get_length() / 2).floor
105
+ centered_length = ((width - 1) / 2).floor
106
+
107
+ range = (centered_length-centered_width)..(centered_length+centered_width)
108
+ # Add stretch space for colored text.
109
+ if difference > 0 then
110
+ char_existing = line[range.begin]
111
+ append_string = ""
112
+ #puts length,real_length
113
+ (difference+(difference*2.5).ceil).times {|v|
114
+ append_string << char_existing
115
+ }
116
+ #puts line[(range.begin)..(real_length -1)]
117
+ line = line[0..range.begin] + append_string + line[(range.begin)..(width)]
118
+ range = (range.begin+difference)..(range.end+difference)
119
+ end
120
+ line[range] = @text
121
+ if get_length(line) > width then
122
+ #puts "wut"
123
+ # RAIG GLITCH AHX AHOGWHGOHWOGHWOGHGH
124
+ line[get_length(line)-start-1] = ""
125
+ end
126
+ elsif @orientation.x == -1 then
127
+ length = get_length()
128
+ real_length = @text.length
129
+ difference = (length - real_length).abs
130
+ #puts difference
131
+ range = (start)..(length+1)
132
+ #puts range
133
+ # Add stretch space for colored text.
134
+ if difference > 0 then
135
+ char_existing = line[range.begin]
136
+ append_string = ""
137
+ puts length,real_length
138
+ (difference+(difference*2.5).ceil).times {|v|
139
+ append_string << char_existing
140
+ }
141
+ #puts line[(range.begin)..(real_length -1)]
142
+ puts "|" + line[0..range.begin-1] + "|"
143
+ line = line[0..(range.begin-1)] + append_string + line[(range.begin)..(width)]
144
+ #range = (range.begin+difference)..(range.end+difference)
145
+ end
146
+ line[range] = @text
147
+ elsif @orientation.x == 1 then
148
+ length = get_length()
149
+ real_length = @text.length
150
+ max_length = width - start - 1
151
+ difference = (length - real_length).abs
152
+ #puts difference
153
+ range = (max_length - length + 1)..(max_length)
154
+ #puts range
155
+ # Add stretch space for colored text.
156
+ if difference > 0 then
157
+ char_existing = line[range.begin]
158
+ append_string = ""
159
+ puts length,real_length
160
+ (difference+(difference*3).ceil).times {|v|
161
+ append_string << char_existing
162
+ }
163
+ puts "|" + line[(range.end+1)..(range.end + start)] + "|"
164
+ #puts (length/2.5).ceil
165
+ line = line[0..(range.begin)] + append_string + line[(range.end-((length/2)-2).ceil)..(range.end + start)]
166
+ range = (range.begin+difference*3.5)..(range.end)
167
+ end
168
+ line[range] = @text
169
+ end
170
+ return line
171
+ #++
172
+ end
173
+ end
174
+
175
+ # A subclass of Text for colored window text.
176
+ class ColoredText < Text
177
+ #--
178
+ #say(%{Here's some <%= color('dark red text', RED) %>.})
179
+ #++
180
+
181
+ # Initializes a ColoredText object.
182
+ def initialize(orientation,text,y,color=:green)
183
+ if WindowTerminal.os == :linux then
184
+ if color == :green then
185
+ text = "\e[#{32}m#{text}\e[0m"
186
+ elsif color == :red then
187
+ text = "\e[#{31}m#{text}\e[0m"
188
+ elsif color == :yellow then
189
+ text = "\e[#{33}m#{text}\e[0m"
190
+ elsif color == :pink then
191
+ text = "\e[#{35}m#{text}\e[0m"
192
+ end
193
+ end
194
+ super(orientation,text,y)
195
+ end
196
+ end
197
+
198
+ # A subclass of Text which allows for
199
+ # wrapped text within a Window.
200
+ class WrappedText < Text
201
+ undef :render_line
202
+
203
+ # Initializes a WrappedText object.
204
+ def initialize(orientation,text,y,mode=:destroy)
205
+ @mode = mode
206
+ super(orientation,text,y)
207
+ end
208
+
209
+ # Renders the WrappedText object
210
+ # based on passed lines and
211
+ # returns the modified lines.
212
+ def render(lines,cols,rows,padding=2)
213
+ #--
214
+ lines = lines.dup
215
+ words = wrap(@text,rows-padding*2)
216
+ if words.length > (cols - @y) then
217
+ words.slice!((cols - @y + 1)..(words.length-1))
218
+ end
219
+ range = (@y - 1)..(cols-1)
220
+ sum = 0
221
+ ending = cols - padding - 1
222
+ lines.each_index { |index|
223
+ if (range === index and words[sum]) and index < ending then
224
+ #puts "|" + words[sum] + "|"
225
+ lines[index] = WindowTerminal::Text.new(orientation,words[sum],0).render_line(lines[index],rows,padding)
226
+ sum += 1
227
+ end
228
+ }
229
+ return lines
230
+ #++
231
+ end
232
+
233
+ private
234
+
235
+ # Wraps a string based on width.
236
+ # <i>Credit: RubyCookbook</i>
237
+ def wrap(s,width)
238
+ #--
239
+ if @mode == :destroy then
240
+ s = s.dup
241
+ s = s.split(/\s+/) if s.is_a? String
242
+ lines = []
243
+ line = ""
244
+ #puts s.length
245
+ s.each do |word|
246
+ if line.size + word.size >= width then
247
+ lines << line
248
+ line = word
249
+ elsif line.empty? then
250
+ line = word
251
+ else
252
+ line << " " << word
253
+ end
254
+ end
255
+
256
+ lines << line if line
257
+ #puts lines.length
258
+ return lines
259
+ else
260
+ string = s.gsub(/(.{1,#{width}})( |\Z)/, "\\1\n").split(/\n/)
261
+ #puts string
262
+ string
263
+ end
264
+ end
265
+ #++
266
+ end
267
+
268
+ # A subclass of WrappedText which adds compatibility for
269
+ # different colors.
270
+ class ColoredWrappedText < WrappedText
271
+
272
+ # Initializes a ColoredWrappedText object.
273
+ def initialize(orientation,text,y,color=:green,mode=:destroy)
274
+ @color = color
275
+ if WindowTerminal.os == :linux then
276
+ if @color == :green then
277
+ text = "\e[#{32}m#{text}\e[0m"
278
+ elsif @color == :red then
279
+ text = "\e[#{31}m#{text}\e[0m"
280
+ elsif @color == :yellow then
281
+ text = "\e[#{33}m#{text}\e[0m"
282
+ elsif @color == :pink then
283
+ text = "\e[#{35}m#{text}\e[0m"
284
+ end
285
+ end
286
+ super(orientation,text,y,mode)
287
+ end
288
+
289
+ end
290
+
291
+ # A class which renders a simple
292
+ # horizontal line on a Window.
293
+ class Line
294
+ attr_reader :y
295
+
296
+ # Initializes a Line object.
297
+ def initialize(y)
298
+ @y = y
299
+ end
300
+
301
+ # Renders on the passed line
302
+ # and returns the modified line.
303
+ def render_line(line,width,*args)
304
+ line.gsub(" ","-")
305
+ end
306
+ end
307
+
308
+ # The main class which handles each individual
309
+ # terminal window.
310
+ class Window
311
+ attr_reader :orientation,:name,:objects
312
+
313
+ # Initializes Window object.
314
+ def initialize(orientation,name)
315
+ raise "Orientation must be passed!" if not orientation.is_a? Orientation
316
+ @orientation = orientation
317
+ @name = name
318
+ @objects = []
319
+ add_object(WindowTerminal::ColoredText.new(WindowTerminal::Orientation.new,@name,0,:red))
320
+ add_object(WindowTerminal::Line.new(1))
321
+ end
322
+
323
+ # Makes the to_s method return
324
+ # something a bit more meaningful.
325
+ def to_s
326
+ "<Window: @orientation = #{@orientation.to_s}, @name = #{@name} >"
327
+ end
328
+
329
+ # Adds a single object to the Window's
330
+ # object list.
331
+ def add_object(object)
332
+ raise ArgumentError "Argument must be a renderable object." if not (object.respond_to?(:render_line) or object.respond_to?(:render))
333
+ @objects << object
334
+ end
335
+
336
+ # Adds all passed arguments to the
337
+ # Window's object list.
338
+ def add_objects(*items)
339
+ raise ArgumentError "Argument missing" if items.length == 0
340
+ items.each { |item|
341
+ add_object(item)
342
+ }
343
+ end
344
+
345
+ # Yields the passed block
346
+ # with each object.
347
+ def for_objects()
348
+ @objects.each {|object|
349
+ yield object
350
+ }
351
+ end
352
+
353
+ # Includes the Window in the
354
+ # WindowTerminal module screen_render.
355
+ def include_in_render(bool=true)
356
+ if bool and not WindowTerminal.get_windows().include? self then
357
+ WindowTerminal.add_window self
358
+ elsif not bool and WindowTerminal.get_windows().include? self then
359
+ WindowTerminal.remove_window self
360
+ end
361
+ end
362
+ end
363
+
364
+ # Makes handling and switching between
365
+ # Window objects simpler by creating
366
+ # an API that allows for objects
367
+ # to be assigned to pages,
368
+ # which can, in turn,
369
+ # be displayed, hidden, or deleted
370
+ # at leisure.
371
+ class WindowManager
372
+ attr_reader :pages
373
+
374
+ # Initializes a WindowManager object.
375
+ def initialize()
376
+ @pages = []
377
+ @displayed_page = nil
378
+ end
379
+
380
+ # Creates a new page with the passed
381
+ # arguments and returns the page
382
+ # number.
383
+ def new_page(*items)
384
+ @pages << []
385
+ items.each { |item|
386
+ if item.is_a? Window then
387
+ @pages[-1] << item
388
+ end
389
+ }
390
+ return @pages.length
391
+ end
392
+
393
+ # Displays the page at the number
394
+ # specified; defaults to one.
395
+ def display_page(num=1)
396
+ raise(ArgumentError, "Argument 1 must be a valid integer!") if not (num.is_a? Fixnum)
397
+ hide_page(@displayed_page)
398
+ @pages[num-1].each { |item|
399
+ WindowTerminal.add_window(item)
400
+ }
401
+ @displayed_page = num
402
+ end
403
+
404
+ # Alias for display_page.
405
+ def show(num=1)
406
+ display_page(num)
407
+ end
408
+
409
+ # Hides a page by a number,
410
+ # defaults to doing nothing.
411
+ def hide_page(num=nil)
412
+ if num then
413
+ raise(ArgumentError, "Argument 1 must be a valid integer!") if not (num.is_a? Fixnum)
414
+ if num == @displayed_page then
415
+ @pages[num-1].each { |item|
416
+ WindowTerminal.remove_window(item)
417
+ }
418
+ @displayed_page = nil
419
+ end
420
+ end
421
+ end
422
+
423
+ # An alias for hide_page which
424
+ # always passes the current
425
+ # displayed page number,
426
+ # if it exists.
427
+ def hide()
428
+ if @displayed_page then
429
+ hide_page(@displayed_page)
430
+ end
431
+ end
432
+
433
+ # Delete a page by page number.
434
+ def remove_page(num)
435
+ raise(ArgumentError, "Argument 1 must be a valid integer!") if not (num.is_a? Fixnum)
436
+ hide_page(num)
437
+ @pages.delete_at(num-1)
438
+ end
439
+
440
+ # Gets all Text and Text subclass
441
+ # objects on the page given and
442
+ # returns them all as an array.
443
+ def get_page_text(num)
444
+ raise(ArgumentError, "Argument 1 must be a valid integer!") if not (num.is_a? Fixnum)
445
+ array = []
446
+ @pages[num-1].each {|window|
447
+ array << window.objects.dup
448
+ array[-1].each {|item|
449
+ if not (item.respond_to? :set_text) then
450
+ array[-1].delete(item)
451
+ end
452
+ }
453
+ }
454
+ return array
455
+ end
456
+
457
+ # An alias for the WindowTerminal method
458
+ # screen_render.
459
+ def render()
460
+ WindowTerminal.screen_render
461
+ end
462
+ end
463
+
464
+ # Gets current terminal size based
465
+ # on the operating system and
466
+ # returns the result.
467
+ def self.terminal_size
468
+ if self.os == :windows then
469
+ m_GetStdHAndle = Win32Api.new("kernel32","GetStdHandle",["L"],"L")
470
+ m_GetConsoleScreenBufferInfo = Win32Api.new("kernel32","GetConsoleScreenBufferInfo",["L","P"],"L")
471
+
472
+ format = "SSSSSssssSS"
473
+ buf = ([0] * format.size).pack(format)
474
+ stdout_handle = m_GetStdHandle.call(STDOUT_HANDLE)
475
+
476
+ m_GetConsoleScreenBufferInfo.call(stdout_handle, buf)
477
+ (bufx, bufy, curx, cury, wattr, left, top, right, bottom, maxx, maxy) = buf.unpack(format)
478
+ return bottom - top + 1, right - left + 1
479
+ else
480
+ rows, cols = 25, 80
481
+ buf = [ 0, 0, 0, 0 ].pack("SSSS")
482
+ if STDOUT.ioctl(TIOCGNWINSZ, buf) >= 0 then
483
+ rows, cols, row_pixels, col_pixels = buf.unpack("SSSS")[0..1]
484
+ end
485
+ return rows,cols
486
+ end
487
+ end
488
+
489
+ # Adds a window to the render.
490
+ def self.add_window(win)
491
+ @@windows << win
492
+ end
493
+
494
+ # Remoes a window from the render.
495
+ def self.remove_window(win)
496
+ @@windows.delete(win)
497
+ end
498
+
499
+ # Returns the windows currently
500
+ # being rendered.
501
+ def self.get_windows()
502
+ @@windows
503
+ end
504
+
505
+ # Returns current operating system
506
+ # based on the return value of
507
+ # ENV["OS"].
508
+ def self.os
509
+ op = :blah
510
+ if ENV["OS"] == nil then
511
+ op = :linux
512
+ else
513
+ op = :windows
514
+ end
515
+ return op
516
+ end
517
+
518
+ # Renders the screen using
519
+ # current window objects.
520
+ def self.screen_render
521
+ #--
522
+ rows,cols = *WindowTerminal.terminal_size
523
+ line1 = ""
524
+ line2 = ""
525
+ cols.times {|num|
526
+ line1 << "#"
527
+ line2 << " "
528
+ }
529
+ line2[0] = "#"
530
+ line2[-1] = "#"
531
+ line1 << "\n"
532
+ line2 << "\n"
533
+ lines = ""
534
+ rows.times {|num|
535
+ if num != 0 and num != rows - 1 then
536
+ lines << line2
537
+ else
538
+ lines << line1
539
+ end
540
+ }
541
+ if @@windows.length == 1 then
542
+ window = @@windows[0]
543
+ # Add lines for window.
544
+ lines = lines.split("\n")
545
+ lines.each_index { |index|
546
+ #puts index
547
+ if index > 1 and index < rows - 2 then
548
+ lines[index][1] = "|"
549
+ lines[index][-2] = "|"
550
+ end
551
+ }
552
+ lines[1].gsub!(" ","-")
553
+ #lines[3].gsub!(" ","-")
554
+ lines[-2].gsub!(" ","-")
555
+ # Render window objects.
556
+ window.for_objects{ |object|
557
+ if object.respond_to? :render_line then
558
+ lines[object.y+2] = object.render_line(lines[object.y+2],cols,2)
559
+ elsif object.respond_to? :render then
560
+ lines = object.render(lines,rows,cols)
561
+ end
562
+ }
563
+ lines = lines.join("\n")
564
+ elsif @@windows.length == 2 then
565
+ window1,window2 = @@windows[0],@@windows[1]
566
+ if window1.orientation.x != window2.orientation.x then # Box-Box
567
+ if window1.orientation.x > window2.orientation.x then
568
+ left_window = window2
569
+ right_window = window1
570
+ else
571
+ left_window = window1
572
+ right_window = window2
573
+ end
574
+ lines = lines.split("\n")
575
+ lines_left = []
576
+ lines_right = []
577
+ width = (cols - 1)
578
+ left_dimension = (width / 2).ceil
579
+ right_dimension = width - left_dimension
580
+ lines.each_index {|index|
581
+ #puts "iteration"
582
+ lines_left[index] = lines[index].slice(0..left_dimension)
583
+ lines_right[index] = lines[index].slice(right_dimension..width)
584
+ }
585
+ [[left_window,lines_left],[right_window,lines_right]].each { |array|
586
+ window = array[0]
587
+ current_lines = array[1]
588
+ current_lines.each_index { |index|
589
+ if index > 1 and index < rows - 2 then
590
+ current_lines[index][0] = "#"
591
+ current_lines[index][-1] = "#"
592
+ current_lines[index][1] = "|"
593
+ current_lines[index][-2] = "|"
594
+ end
595
+ }
596
+ local_cols = current_lines[0].length
597
+ current_lines[1].gsub!(" ","-")
598
+ current_lines[-2].gsub!(" ","-")
599
+ window.for_objects{ |object|
600
+ if object.respond_to? :render_line then
601
+ current_lines[object.y+2] = object.render_line(current_lines[object.y+2],local_cols,2)
602
+ end
603
+ }
604
+ }
605
+ lines = []
606
+ lines_left.each_index { |index|
607
+ lines[index] = lines_left[index] + lines_right[index]
608
+ }
609
+ lines_left = []
610
+ lines_right = []
611
+ lines = lines.join("\n")
612
+ else # Box / Box
613
+ if window1.orientation.y > window2.orientation.y then
614
+ up_window = window2
615
+ down_window = window1
616
+ else
617
+ up_window = window1
618
+ down_window = window2
619
+ end
620
+ lines = lines.split("\n")
621
+ up_lines = []
622
+ down_lines = []
623
+ height = (rows - 1)
624
+ up_dimension = (height / 2).ceil
625
+ down_dimension = height - up_dimension
626
+ lines.each_index {|index|
627
+ #puts "iteration"
628
+ if index <= up_dimension then
629
+ up_lines << lines[index]
630
+ else
631
+ down_lines << lines[index]
632
+ end
633
+ }
634
+ [[up_window,up_lines],[down_window,down_lines]].each { |array|
635
+ window = array[0]
636
+ current_lines = array[1]
637
+ current_lines[1].gsub!(" ","-")
638
+ old = current_lines[-1].dup
639
+ current_lines[-1].gsub!(" ","-")
640
+ if current_lines[-1] == old then
641
+ current_lines[-2].gsub!(" ","-")
642
+ end
643
+ current_lines.each_index { |index|
644
+ if index == 0 or index == rows - 1 then
645
+ current_lines[index] = line1.dup.gsub("\n","")
646
+ # elsif index == 1 or index == rows - 2 then
647
+ # current_lines[index].gsub!(" ","-")
648
+ else
649
+ #current_lines[index][0] = "#"
650
+ #current_lines[index][-1] = "#"
651
+ if current_lines[index][1] != "#" then
652
+ current_lines[index][1] = "|"
653
+ current_lines[index][-2] = "|"
654
+ end
655
+ end
656
+ }
657
+ window.for_objects{ |object|
658
+ if object.respond_to? :render_line then
659
+ current_lines[object.y+2] = object.render_line(current_lines[object.y+2],cols,2)
660
+ end
661
+ }
662
+ }
663
+ lines = []
664
+ up_lines.each { |line|
665
+ lines << line
666
+ }
667
+ up_lines = []
668
+ down_lines.each {|line|
669
+ lines << line
670
+ }
671
+ down_lines = []
672
+ lines = lines.join("\n")
673
+ end
674
+ end
675
+ print lines
676
+ #++
677
+ end
678
+
679
+ # Gets a string from user using
680
+ # the highline library ask()
681
+ # set to no echo.
682
+ def self.ask_quietly()
683
+ string = ask("") { |q| q.echo = '' }
684
+ yield(string) if block_given?
685
+ self.screen_render
686
+ return string
687
+ end
688
+
689
+ # Gets a single character from
690
+ # the terminal emulator
691
+ # in linux, otherwise it
692
+ # returns an empty string.
693
+ #
694
+ # Also yields the character to
695
+ # a passed block before rendering.
696
+ def self.getchr()
697
+ if self.os == :linux then
698
+ string = ""
699
+ begin
700
+ system("stty raw -echo")
701
+ string = STDIN.getc
702
+ ensure
703
+ system("stty -raw echo")
704
+ end
705
+ yield string if block_given?
706
+ self.screen_render
707
+ return string
708
+ else
709
+ ""
710
+ end
711
+ end
712
+
713
+ # Similar to ask_quietly but
714
+ # renders the screen after
715
+ # each character is entered.
716
+ #
717
+ # A block may also be passed
718
+ # which will be executed
719
+ # just before a render with the
720
+ # current character and the full
721
+ # string thus far.
722
+ def self.getchrs()
723
+ if self.os == :linux then
724
+ full = ""
725
+ string = " "
726
+ string = self.getchr()
727
+ while (string.ord != 13) do
728
+ if string.ord == 127 and full.length > 0 then
729
+ full.slice!(full.length - 1)
730
+ else
731
+ full << string.ord
732
+ end
733
+ yield(string,full) if block_given?
734
+ self.screen_render
735
+ string = self.getchr()
736
+ end
737
+ return full
738
+ else
739
+ ""
740
+ end
741
+ end
742
+ end
743
+
744
+ # Copyright 2014 Luke Spangler
745
+ #
746
+ # Licensed under the Apache License, Version 2.0 (the "License");
747
+ # you may not use this file except in compliance with the License.
748
+ # You may obtain a copy of the License at
749
+ #
750
+ # http://www.apache.org/licenses/LICENSE-2.0
751
+ #
752
+ # Unless required by applicable law or agreed to in writing, software
753
+ # distributed under the License is distributed on an "AS IS" BASIS,
754
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
755
+ # See the License for the specific language governing permissions and
756
+ # limitations under the License.