rbcurse 1.4.0 → 1.4.1.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. data/NOTES +68 -0
  2. data/README.markdown +73 -330
  3. data/TODO2.txt +2 -2
  4. data/VERSION +1 -1
  5. data/examples/abasiclist.rb +8 -2
  6. data/examples/alpmenu.rb +1 -1
  7. data/examples/app.rb +1 -24
  8. data/examples/appdirtree.rb +1 -1
  9. data/examples/appemail.rb +8 -14
  10. data/examples/appemaillb.rb +2 -2
  11. data/examples/appgcompose.rb +7 -5
  12. data/examples/common/file.rb +40 -0
  13. data/examples/{rmail.rb → common/rmail.rb} +0 -0
  14. data/examples/data/README.markdown +9 -0
  15. data/examples/data/brew.txt +38 -0
  16. data/examples/data/color.2 +37 -0
  17. data/examples/data/gemlist.txt +60 -0
  18. data/examples/data/lotr.txt +12 -0
  19. data/examples/data/ports.txt +136 -0
  20. data/examples/data/tasks.txt +27 -0
  21. data/examples/{todocsv.csv → data/todocsv.csv} +0 -0
  22. data/examples/data/unix1.txt +21 -0
  23. data/examples/data/unix2.txt +11 -0
  24. data/examples/dbdemo.rb +49 -14
  25. data/examples/{appgmail.rb → deprecated/appgmail.rb} +1 -1
  26. data/examples/{splitp.rb → deprecated/splitp.rb} +0 -0
  27. data/examples/{testscrolllb.rb → deprecated/testscrolllb.rb} +0 -0
  28. data/examples/{testscrollp.rb → deprecated/testscrollp.rb} +0 -0
  29. data/examples/{testscrollta.rb → deprecated/testscrollta.rb} +0 -0
  30. data/examples/{testscrolltable.rb → deprecated/testscrolltable.rb} +0 -0
  31. data/examples/{testsplit.rb → deprecated/testsplit.rb} +0 -0
  32. data/examples/{testsplit2.rb → deprecated/testsplit2.rb} +0 -0
  33. data/examples/{testsplit3.rb → deprecated/testsplit3.rb} +0 -0
  34. data/examples/{testsplit3_1.rb → deprecated/testsplit3_1.rb} +0 -0
  35. data/examples/{testsplit3a.rb → deprecated/testsplit3a.rb} +0 -0
  36. data/examples/{testsplit3b.rb → deprecated/testsplit3b.rb} +0 -0
  37. data/examples/{testsplitta.rb → deprecated/testsplitta.rb} +0 -0
  38. data/examples/{testsplittv.rb → deprecated/testsplittv.rb} +0 -0
  39. data/examples/{testsplittvv.rb → deprecated/testsplittvv.rb} +0 -0
  40. data/examples/{testtpane.rb → deprecated/testtpane.rb} +0 -0
  41. data/examples/{testtpane2.rb → deprecated/testtpane2.rb} +0 -0
  42. data/examples/{testtpanetable.rb → deprecated/testtpanetable.rb} +0 -0
  43. data/examples/dirtree.rb +17 -7
  44. data/examples/experimental/resultsetdemo.rb +280 -0
  45. data/examples/experimental/testmform.rb +35 -0
  46. data/examples/{testscroller.rb → experimental/testscroller.rb} +1 -19
  47. data/examples/experimental/teststackflow.rb +111 -0
  48. data/examples/menu1.rb +1 -0
  49. data/examples/multispl.rb +4 -4
  50. data/examples/newmessagebox.rb +130 -0
  51. data/examples/newtabbedwindow.rb +100 -0
  52. data/examples/newtesttabp.rb +0 -3
  53. data/examples/qdfilechooser.rb +0 -3
  54. data/examples/rfe.rb +134 -18
  55. data/examples/rfe_renderer.rb +48 -2
  56. data/examples/sqlc.rb +2 -1
  57. data/examples/sqlm.rb +0 -2
  58. data/examples/table1.rb +1 -7
  59. data/examples/term2.rb +4 -1
  60. data/examples/test1.rb +0 -5
  61. data/examples/test2.rb +42 -31
  62. data/examples/testapp2.rb +8 -1
  63. data/examples/testchars.rb +0 -4
  64. data/examples/testcombo.rb +5 -9
  65. data/examples/testkeypress.rb +0 -3
  66. data/examples/testmenu.rb +0 -4
  67. data/examples/testmulticomp.rb +3 -5
  68. data/examples/testmulticontainer.rb +94 -0
  69. data/examples/testtable.rb +0 -5
  70. data/examples/testtabp.rb +16 -18
  71. data/examples/testtodo.rb +1 -5
  72. data/examples/testwsshortcuts.rb +64 -0
  73. data/examples/testwsshortcuts2.rb +126 -0
  74. data/examples/viewtodo.rb +1 -4
  75. data/lib/rbcurse.rb +1 -1
  76. data/lib/rbcurse/app.rb +92 -69
  77. data/lib/rbcurse/applicationheader.rb +46 -6
  78. data/lib/rbcurse/celleditor.rb +1 -9
  79. data/lib/rbcurse/comboboxcellrenderer.rb +0 -4
  80. data/lib/rbcurse/common/ansiparser.rb +117 -0
  81. data/{examples → lib/rbcurse/common}/appmethods.rb +25 -0
  82. data/lib/rbcurse/common/basestack.rb +407 -0
  83. data/lib/rbcurse/common/bordertitle.rb +41 -0
  84. data/lib/rbcurse/common/chunk.rb +177 -0
  85. data/lib/rbcurse/common/colorparser.rb +71 -0
  86. data/lib/rbcurse/common/keydefs.rb +30 -0
  87. data/lib/rbcurse/common/widgetshortcuts.rb +302 -0
  88. data/lib/rbcurse/deprecated/README.markdown +12 -0
  89. data/lib/rbcurse/{rscrollpane.rb → deprecated/rscrollpane.rb} +0 -0
  90. data/lib/rbcurse/{rsplitpane.rb → deprecated/rsplitpane.rb} +0 -0
  91. data/lib/rbcurse/{rsplitpane2.rb → deprecated/rsplitpane2.rb} +0 -0
  92. data/lib/rbcurse/{rviewport.rb → deprecated/rviewport.rb} +0 -0
  93. data/lib/rbcurse/experimental/README.markdown +14 -0
  94. data/lib/rbcurse/experimental/resultsettextview.rb +585 -0
  95. data/lib/rbcurse/experimental/stackflow.rb +478 -0
  96. data/lib/rbcurse/extras/bottomline.rb +85 -16
  97. data/lib/rbcurse/extras/box.rb +58 -0
  98. data/lib/rbcurse/extras/directorylist.rb +1 -1
  99. data/lib/rbcurse/extras/horizlist.rb +203 -0
  100. data/lib/rbcurse/extras/listselectable.rb +8 -0
  101. data/lib/rbcurse/extras/multiform.rb +330 -0
  102. data/lib/rbcurse/extras/multilinelabel.rb +142 -0
  103. data/lib/rbcurse/extras/newmessagebox.rb +328 -0
  104. data/lib/rbcurse/extras/newtabbedpane.rb +612 -0
  105. data/lib/rbcurse/extras/newtabbedwindow.rb +68 -0
  106. data/lib/rbcurse/extras/padreader.rb +189 -0
  107. data/lib/rbcurse/extras/rcomboedit.rb +256 -0
  108. data/lib/rbcurse/extras/resultsetbrowser.rb +281 -0
  109. data/lib/rbcurse/extras/statusline.rb +44 -6
  110. data/lib/rbcurse/extras/tabularwidget.rb +141 -104
  111. data/lib/rbcurse/extras/textpad.rb +516 -0
  112. data/lib/rbcurse/extras/viewer.rb +2 -0
  113. data/lib/rbcurse/io.rb +120 -3
  114. data/lib/rbcurse/listcellrenderer.rb +2 -1
  115. data/lib/rbcurse/listkeys.rb +1 -1
  116. data/lib/rbcurse/listscrollable.rb +72 -7
  117. data/lib/rbcurse/rbasiclistbox.rb +64 -12
  118. data/lib/rbcurse/rchangeevent.rb +0 -1
  119. data/lib/rbcurse/rcombo.rb +54 -59
  120. data/lib/rbcurse/rcommandwindow.rb +46 -10
  121. data/lib/rbcurse/rcontainer.rb +415 -0
  122. data/lib/rbcurse/rdialogs.rb +242 -165
  123. data/lib/rbcurse/rinputdataevent.rb +0 -1
  124. data/lib/rbcurse/rlistbox.rb +19 -9
  125. data/lib/rbcurse/rmessagebox.rb +1 -5
  126. data/lib/rbcurse/rmulticontainer.rb +64 -61
  127. data/lib/rbcurse/rmultitextview.rb +0 -2
  128. data/lib/rbcurse/rpopupmenu.rb +0 -2
  129. data/lib/rbcurse/rscrollform.rb +61 -12
  130. data/lib/rbcurse/rtabbedpane.rb +89 -73
  131. data/lib/rbcurse/rtabbedwindow.rb +53 -211
  132. data/lib/rbcurse/rtable.rb +0 -2
  133. data/lib/rbcurse/rtextarea.rb +14 -14
  134. data/lib/rbcurse/rtextview.rb +165 -50
  135. data/lib/rbcurse/rvimsplit.rb +15 -12
  136. data/lib/rbcurse/rwidget.rb +404 -150
  137. data/lib/rbcurse/table/tablecellrenderer.rb +1 -4
  138. data/lib/rbcurse/table/tabledatecellrenderer.rb +0 -3
  139. data/lib/ver/ncurses.rb +1 -9
  140. data/lib/ver/rpad.rb +375 -0
  141. data/lib/ver/window.rb +262 -440
  142. metadata +73 -31
@@ -1,5 +1,21 @@
1
+ # ----------------------------------------------------------------------------- #
2
+ # File: applicationheader.rb
3
+ # Description: Prints a header on first row, with right, left and centered text
4
+ # NOTE: on some terminal such as xterm-256color spaces do not print
5
+ # so you will see black or empty spaces between text.
6
+ # This does not happen on screen and xterm-color.
7
+ # Author: rkumar http://github.com/rkumar/rbcurse/
8
+ # Date:
9
+ # License: Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
10
+ # Last update: 2011-11-16 - 00:07
11
+ #
12
+ # CHANGES:
13
+ # For some terminals, like xterm-256color which were not printing spaces
14
+ # I've changed to code so only text is printed where it has to with no
15
+ # padding. These terminals remove the padding color.
16
+ # ----------------------------------------------------------------------------- #
17
+ #
1
18
  require 'rbcurse/rwidget'
2
- #include Ncurses # FFI 2011-09-8
3
19
  include RubyCurses
4
20
  module RubyCurses
5
21
  class ApplicationHeader < Widget
@@ -39,20 +55,44 @@ module RubyCurses
39
55
  return unless @repaint_required
40
56
 
41
57
  #print_header(htext, posy = 0, posx = 0)
42
- print_header(@text1 + " %15s " % @text2 + " %20s" % @text_center , posy=0, posx=0)
58
+ att = get_attrib @attr
59
+ len = @window.width
60
+ len = Ncurses.COLS-0 if len == 0
61
+ # print a bar across the screen
62
+ @window.attron(Ncurses.COLOR_PAIR(@color_pair) | att)
63
+ @window.mvhline(@row, @col, 1, len)
64
+ @window.attroff(Ncurses.COLOR_PAIR(@color_pair) | att)
65
+ #print_header(@text1 + " %15s " % @text2 + " %20s" % @text_center , posy=0, posx=0)
66
+
67
+ # Now print the text in the correct positions with no padding, else some terminal
68
+ # will blacken the text out.
69
+ print_header("#{@text1} #{@text2}") # + " %20s" % @text_center , posy=0, posx=0)
70
+ print_center("#{@text_center}") # + " %20s" % @text_center , posy=0, posx=0)
43
71
  print_top_right(@text_right)
44
72
  @repaint_required = false
45
73
  end
46
74
  def print_header(htext, r = 0, c = 0)
47
- $log.debug " def print_header(#{htext}, posy = 0, posx = 0)"
75
+ #win = @window
76
+ #len = @window.width
77
+ #len = Ncurses.COLS-0 if len == 0
78
+ #
79
+ #@form.window.printstring r, c, "%-*s" % [len, htext], @color_pair, @attr
80
+ @form.window.printstring r, c, htext, @color_pair, @attr
81
+ end
82
+ def print_center(htext, r = 0, c = 0)
48
83
  win = @window
49
- len = Ncurses.COLS-0
50
- @form.window.printstring r, c, "%-*s" % [len, htext], @color_pair, @attr
84
+ len = win.width
85
+ len = Ncurses.COLS-0 if len == 0
86
+ #
87
+ #@form.window.printstring r, c, "%-*s" % [len, htext], @color_pair, @attr
88
+ win.printstring r, ((len-htext.length)/2).floor, htext, @color_pair, @attr
51
89
  end
52
90
  def print_top_right(htext)
53
91
  $log.debug " def print_top_right(#{htext})"
54
92
  hlen = htext.length
55
- len = Ncurses.COLS-1
93
+ len = Ncurses.COLS-0
94
+ len = @window.width
95
+ len = Ncurses.COLS-0 if len == 0
56
96
  @form.window.printstring 0, len-hlen, htext, @color_pair, @attr
57
97
  end
58
98
  ##
@@ -1,8 +1,3 @@
1
- require 'rubygems'
2
- #require 'ncurses'
3
- require 'logger'
4
- #require 'lib/rbcurse/rwidget'
5
-
6
1
 
7
2
  ##
8
3
  # This file gives us a mean of using a component as an editor in a list or later table.
@@ -23,7 +18,6 @@ module RubyCurses
23
18
  s = @component.class.to_s.downcase()
24
19
  s.slice!("rubycurses::")
25
20
  @_class = s.to_sym
26
- #$log.debug " CELL EIDOTR got #{@_class}"
27
21
  config_setup config # @config.each_pair { |k,v| variable_set(k,v) }
28
22
  instance_eval &block if block_given?
29
23
  end
@@ -75,7 +69,6 @@ module RubyCurses
75
69
  f = @component
76
70
  f.on_leave
77
71
  if f.respond_to? :editable and f.modified?
78
- $log.debug " Table about to fire CHANGED for #{f} "
79
72
  f.fire_handler(:CHANGED, f)
80
73
  end
81
74
  end
@@ -97,13 +90,12 @@ module RubyCurses
97
90
  widget.visible = true
98
91
  widget.form = parent.form
99
92
  #$log.debug " prepare editor value #{widget.display_length} displlen #{widget.maxlen}"
100
- $log.debug " prepare editor form: #{widget.form} "
93
+ #$log.debug " prepare editor form: #{widget.form} " # 2011-11-15 12:54:41
101
94
  #widget.display_length = widget.display_length -1
102
95
  widget.bgcolor = 'yellow'
103
96
  widget.color = 'black'
104
97
  widget.on_enter
105
98
  #widget.attr = Ncurses::A_REVERSE | Ncurses::A_BOLD
106
- #$log.debug " prepare editor value #{value} : fr:#{row}, fc:#{col}"
107
99
  end
108
100
  #This may not really be necessary since we paint the cell editor only if editing is on
109
101
  def cancel_editor
@@ -1,7 +1,3 @@
1
- require 'rubygems'
2
- #require 'ncurses'
3
- require 'logger'
4
- #require 'lib/rbcurse/rwidget'
5
1
  module RubyCurses
6
2
 
7
3
  ##
@@ -0,0 +1,117 @@
1
+ # ----------------------------------------------------------------------------- #
2
+ # File: colorparser.rb
3
+ # Description: Default parse for our tmux format
4
+ # The aim is to be able to specify parsers so different kinds
5
+ # of formatting or documents can be used, such as ANSI formatted
6
+ # manpages.
7
+ # Author: rkumar http://github.com/rkumar/rbcurse/
8
+ # Date: 07.11.11 - 13:17
9
+ # License: Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
10
+ # Last update: use ,,L
11
+ # ----------------------------------------------------------------------------- #
12
+ # == TODO
13
+ # - perhaps we can compile the regexp once and reuse
14
+ #
15
+
16
+ class AnsiParser
17
+
18
+ # NOTE: Experimental and minimal
19
+ # parses the formatted string and yields either an array of color, bgcolor and attrib
20
+ # or the text. This will be called by convert_to_chunk.
21
+ #
22
+ # Currently, assumes colors and attributes are correct. No error checking or fancy stuff.
23
+ # s="#[fg=green]hello there#[fg=yellow, bg=black, dim]"
24
+ # @since 1.4.1 2011-11-3 experimental, can change
25
+ # @return [nil] knows nothign about output format.
26
+
27
+ def parse_format s # yields attribs or text
28
+ ## set default colors
29
+ color = :white
30
+ bgcolor = :black
31
+ attrib = FFI::NCurses::A_NORMAL
32
+ text = ""
33
+
34
+ ## split #[...]
35
+ #a = s.split /(#\[[^\]]*\])/
36
+ a = s.split /(\x1b\[\d*(?:;\d+)*?[a-zA-Z])/
37
+ a.each { |e|
38
+ ## process color or attrib portion
39
+ #[ "", "\e[1m", "", "\e[34m", "", "\e[47m", "Showing all items...", "\e[0m", "", "\e[0m", "\n"]
40
+ if e[0] == "\x1b" && e[-1] == "m"
41
+
42
+ #e.each { |f| x=/^.\[(.*).$/.match(f)
43
+ $log.debug "XXX: ANSI e #{e} "
44
+ x=/^.\[(.*).$/.match(e)
45
+ color, bgcolor, attrib = nil, nil, nil
46
+ $log.debug "XXX: ANSI #{x} ..... #{x[1]} "
47
+ args = x[1].split ';'
48
+ ## first split on commas to separate fg, bg and attr
49
+ # http://ascii-table.com/ansi-escape-sequences.php
50
+ args.each { |att|
51
+ $log.debug "XXX: ANSI att: #{att} "
52
+ case att.to_i
53
+ when 0
54
+ color, bgcolor, attrib = nil, nil, nil
55
+ yield :reset # actually this resets all so we need an endall or clearall reset
56
+
57
+ when 1
58
+ attrib = 'bold'
59
+ when 2
60
+ attrib = 'dim'
61
+ when 4
62
+ attrib = 'underline'
63
+ when 5
64
+ attrib = 'blink'
65
+ when 7
66
+ attrib = 'reverse'
67
+ when 8
68
+ attrib = 'hidden' # XXX
69
+ when 30
70
+ color = 'black'
71
+ when 31
72
+ color = 'red'
73
+ when 32
74
+ color = 'green'
75
+ when 33
76
+ color = 'yellow'
77
+ when 34
78
+ color = 'blue'
79
+ when 35
80
+ color = 'magenta'
81
+ when 36
82
+ color = 'cyan'
83
+ when 37
84
+ color = 'white'
85
+
86
+ #Background colors
87
+ when 40
88
+ bgcolor = 'black'
89
+ when 41
90
+ bgcolor = 'red'
91
+ when 42
92
+ bgcolor = 'green'
93
+ when 43
94
+ bgcolor = 'yellow'
95
+ when 44
96
+ bgcolor = 'blue'
97
+ when 45
98
+ bgcolor = 'magenta'
99
+ when 46
100
+ bgcolor = 'cyan'
101
+ when 47
102
+ bgcolor = 'white'
103
+ else
104
+ $log.warn "XXX: WARN ANSI not used #{att} "
105
+ end
106
+ } # args.ea
107
+ #} # e.each
108
+ $log.debug "XXX: ANSI YIELDING #{color} , #{bgcolor} , #{attrib} "
109
+ yield [color,bgcolor,attrib] if block_given?
110
+ else
111
+ text = e
112
+ yield text if block_given?
113
+ end
114
+ } # a.each
115
+ end
116
+
117
+ end
@@ -1,5 +1,6 @@
1
1
  module RubyCurses
2
2
  module Utils
3
+ private
3
4
  def _suspend clear=true
4
5
  return unless block_given?
5
6
  Ncurses.def_prog_mode
@@ -22,6 +23,11 @@ module RubyCurses
22
23
  @window.wrefresh if @window
23
24
  Ncurses::Panel.update_panels
24
25
  end
26
+ #
27
+ # Suspends to shell so user can execute commands.
28
+ # Maybe not be able to get your prompt correctly.
29
+ #
30
+ public
25
31
  def suspend
26
32
  _suspend(false) do
27
33
  system("tput cup 26 0")
@@ -32,6 +38,10 @@ module RubyCurses
32
38
  end
33
39
  end
34
40
 
41
+ #
42
+ # Displays application help using either array provided
43
+ # or checking for :help_text method
44
+ # @param [Array] help text
35
45
  def display_app_help help_array= nil
36
46
  if help_array
37
47
  arr = help_array
@@ -64,12 +74,19 @@ module RubyCurses
64
74
  t.attr = :reverse
65
75
  end
66
76
  end
77
+ #
78
+ # prompts user for unix command and displays output in viewer
79
+ #
67
80
  def shell_output
68
81
  cmd = get_string("Enter shell command:", 50)
69
82
  if cmd && !cmd.empty?
70
83
  run_command cmd
71
84
  end
72
85
  end
86
+
87
+ #
88
+ # executes given command and displays in viewer
89
+ # @param [String] unix command, e.g., git -st
73
90
  def run_command cmd
74
91
  # http://whynotwiki.com/Ruby_/_Process_management#What_happens_to_standard_error_.28stderr.29.3F
75
92
  require 'rbcurse/extras/viewer'
@@ -82,6 +99,14 @@ module RubyCurses
82
99
  res.gsub!("\t"," ")
83
100
  RubyCurses::Viewer.view(res.split("\n"), :close_key => KEY_RETURN, :title => "<Enter> to close, M-l M-h to scroll")
84
101
  end
102
+ def shell_out command
103
+ @window.hide
104
+ Ncurses.endwin
105
+ system command
106
+ Ncurses.refresh
107
+ #Ncurses.curs_set 0 # why ?
108
+ @window.show
109
+ end
85
110
  end # utils
86
111
  end # module RubyC
87
112
  include RubyCurses::Utils
@@ -0,0 +1,407 @@
1
+ #
2
+ # Common stack flow functionality
3
+ # * Name: basestack.rb
4
+ # * Description: Classes that allow user to stack and flow components
5
+ #
6
+ # * Date: 30.10.11 - 12:57
7
+ # * Last update: 30.10.11 - 12:57
8
+ #
9
+ module RubyCurses
10
+ module ModStack
11
+ #
12
+ # Base class for stacks and flows.
13
+ # Will manage determining row col and width height of objects
14
+ # Stacks place objects one below another. Flows place objects to the
15
+ # right of the previous. Orientation can be reversed.
16
+ #
17
+ class BaseStack
18
+ attr_accessor :components
19
+ attr_reader :config
20
+ attr_accessor :form
21
+ def initialize config={}, components=[]
22
+ @config = config
23
+ config.each do |k, v|
24
+ instance_variable_set "@#{k}", v
25
+ end
26
+ @components = components
27
+ @calc_needed = true
28
+ end
29
+ # XXX if user sets later, we won't be checking the config
30
+ # We check the actual variables which config sets in init
31
+ %w[ parent_component width height weight row col orientation].each { |e|
32
+ eval(
33
+ "def #{e}
34
+ @config[:#{e}]
35
+ end
36
+ def #{e}=(val)
37
+ @config[:#{e}]=val
38
+ instance_variable_set \"@#{e}\", val
39
+ @calc_needed = true
40
+ end"
41
+ )
42
+ }
43
+ alias :parent :parent_component
44
+ #alias :parent= :parent_component
45
+ def repaint # stack
46
+ $log.debug "XXX: stack repaint recalc #{@calc_needed} "
47
+ @components.each { |e| e.form = @form unless e.form } #unless @calc_needed
48
+ recalc if @calc_needed
49
+ @components.each { |e| e.repaint }
50
+ end
51
+ def repaint_all x
52
+ @calc_needed = true
53
+ end
54
+ def override_graphic gr
55
+ @graphic = gr
56
+ end
57
+ def focusable; false; end
58
+ # Calculates row col and width height
59
+ # for each subc-omponent based on coords of Container
60
+ # This is to be called only when the container has got its coordinates (i.e
61
+ # Containers repaint). This should be in this objects repaint.
62
+ def recalc
63
+ @calc_needed = false
64
+ comp = self
65
+ if comp.is_a? BaseStack
66
+ check_coords comp
67
+ @margin_left ||= 0
68
+ @margin_right ||= 0
69
+ @margin_top ||= 0
70
+ @margin_bottom ||= 0
71
+ if comp.is_a? Stack
72
+ r = row + @margin_top
73
+ rem = 0
74
+ ht = height - (@margin_top + @margin_bottom)
75
+ if @orientation == :bottom
76
+ mult = -1
77
+ comps = @components.reverse
78
+ r = row + height - @margin_bottom
79
+
80
+ else
81
+ mult = 1
82
+ comps = @components
83
+
84
+ end
85
+ comps.each { |e|
86
+ # should only happen if expandable FIXME
87
+ e.height = 0.01 * e.weight * (ht - (e.margin_top + e.margin_bottom))
88
+ hround = e.height.floor
89
+ rem += e.height - hround
90
+ e.height = hround #- (@margin_top + @margin_bottom)
91
+ # rounding creates a problem, since 0.5 gets rounded up and we can exceed bound
92
+ # So i floor, and maintain the lost space, and add it back when it exceeds 1
93
+ # This way the last components gets stretched to meet the end, which is required
94
+ # when the height of the stack is odd and there's a left-over row
95
+ if rem >= 1
96
+ e.height += 1
97
+ rem = 0
98
+ end
99
+ # Item level margins have not been accounted for when calculating weightages, and
100
+ # should not be used on the weightage axis
101
+ r += e.margin_top
102
+ if @orientation == :bottom
103
+ r += e.height * mult
104
+ e.row = r
105
+ else
106
+ e.row = r
107
+ r += e.height + 0
108
+ end
109
+ e.width = width - (@margin_left + @margin_right + e.margin_left + e.margin_right)
110
+ e.col = col + @margin_left + e.margin_left # ??? XXX
111
+ $log.debug "XXX: recalc stack #{e.widget.class} r:#{e.row} c:#{e.col} h:#{e.height} = we:#{e.weight} * h:#{height} "
112
+ #e.col_offset = col_offset # ??? XXX
113
+ check_coords e
114
+ e.repaint_all(true)
115
+ e.recalc if e.is_a? BaseStack
116
+ }
117
+ elsif comp.is_a? Flow
118
+ c = col + @margin_left #+ col_offset
119
+ rem = 0
120
+ wd = width - (@margin_left + @margin_right)
121
+ # right_to_left orientation
122
+ if @orientation == :right
123
+ mult = -1
124
+ comps = @components.reverse
125
+ c = col + width - @margin_right
126
+ $log.debug "XXX: ORIENT1f recalc #{@orientation} "
127
+ else
128
+ mult = 1
129
+ comps = @components
130
+ $log.debug "XXX: ORIENT2f recalc #{@orientation} "
131
+ end
132
+ comps.each { |e|
133
+ e.width = e.weight * wd * 0.01
134
+ wround = e.width.floor
135
+ rem += e.width - wround
136
+ e.width = wround
137
+ # see comment in prev block regarding remaininder
138
+ if rem >= 1
139
+ e.width += 1
140
+ rem = 0
141
+ end
142
+ e.height = height - (@margin_top + @margin_bottom) #* weight * 0.01
143
+ #e.height = e.height.round
144
+ if @orientation == :right
145
+ c += e.width * mult # mult 1 or -1
146
+ e.col = c
147
+ else
148
+ e.col = c
149
+ c += e.width * mult # mult 1 or -1
150
+ end
151
+ e.row = row + @margin_top
152
+ check_coords e
153
+ $log.debug "XXX: recalc flow #{e.widget.class} r:#{e.row} c:#{e.col} h:#{e.height} = we:#{e.weight} * w:#{width} "
154
+ e.repaint_all(true) # why not happening when we change row, hieght etc
155
+ e.recalc if e.is_a? BaseStack
156
+ }
157
+ end
158
+ else
159
+ alert "in else recalc DOES NOT COME HERE "
160
+ comp.col = comp.parent.col
161
+ comp.row = comp.parent.row
162
+ comp.height = comp.parent.height
163
+ comp.width = comp.parent.width
164
+ $log.debug "XXX: recalc else #{comp.class} r #{comp.row} c #{comp.col} . h #{comp} height w #{comp.width} "
165
+ end
166
+ end
167
+ # Traverses the comopnent tree and calculates weightages for all components
168
+ # based on what has been specified by user
169
+ def check_coords e # stack
170
+ r = e.row
171
+ c = e.col
172
+ if r >= row + height
173
+ $log.warn "XXX: WARN e.class is out of bounds row #{r} "
174
+ e.visible = false
175
+ end
176
+ if c >= col + width
177
+ $log.warn "XXX: WARN e.class is out of bounds col #{c} "
178
+ e.visible = false
179
+ end
180
+ end
181
+ def increase c=@current_component
182
+ p = self #c.parent_component
183
+ ci = p.components.index(c)
184
+ ni = ci + 1
185
+ if p.components[ni].nil?
186
+ ni = nil
187
+ end
188
+ case p
189
+ when Flow
190
+ # increase width of current and reduce from neighbor
191
+ if ni
192
+ n = p.components[ni]
193
+ $log.debug "XXX: INC fl current #{ci}, total#{p.components.count}, next #{n} "
194
+
195
+ c.width += 1
196
+ n.width -= 1
197
+ n.col += 1
198
+ end
199
+
200
+ when Stack
201
+ if ni
202
+ n = p.components[ni]
203
+ $log.debug "XXX: INC fl current #{ci}, total#{p.components.count}, next #{n} "
204
+
205
+ c.height += 1
206
+ n.height -= 1
207
+ n.row += 1
208
+ end
209
+ $log.debug "XXX: INC st current #{ci}, total#{p.components.count} "
210
+ end
211
+
212
+ end
213
+ def decrease c=@current_component
214
+ p = self #c.parent_component
215
+ ci = p.components.index(c)
216
+ ni = ci + 1
217
+ if p.components[ni].nil?
218
+ ni = nil
219
+ end
220
+ case p
221
+ when Flow
222
+ # increase width of current and reduce from neighbor
223
+ if ni
224
+ n = p.components[ni]
225
+ $log.debug "XXX: INC fl current #{ci}, total#{p.components.count}, next #{n} "
226
+
227
+ c.width -= 1
228
+ n.width += 1
229
+ n.col -= 1
230
+ end
231
+
232
+ when Stack
233
+ if ni
234
+ n = p.components[ni]
235
+ $log.debug "XXX: INC fl current #{ci}, total#{p.components.count}, next #{n} "
236
+
237
+ c.height -= 1
238
+ n.height += 1
239
+ n.row -= 1
240
+ end
241
+ $log.debug "XXX: INC st current #{ci}, total#{p.components.count} "
242
+ end
243
+
244
+ end
245
+ def to_s
246
+ @components
247
+ end
248
+ end # class Base
249
+ # A stack positions objects one below the other
250
+ class Stack < BaseStack; end
251
+ # A flow positions objects in a left to right
252
+ class Flow < BaseStack; end
253
+ #
254
+ # A wrapper over widget mostly because it adds weight and margins
255
+ #
256
+ class Item
257
+ attr_reader :config, :widget
258
+ attr_reader :margin_top, :margin_left, :margin_bottom, :margin_right
259
+ def initialize config={}, widget
260
+ @config = config
261
+ config.each do |k, v|
262
+ instance_variable_set "@#{k}", v
263
+ end
264
+ @margin_left ||= 0
265
+ @margin_right ||= 0
266
+ @margin_top ||= 0
267
+ @margin_bottom ||= 0
268
+ @widget = widget
269
+ end
270
+ def weight; @config[:weight]||100; end
271
+ def weight=(val); @config[:weight]=val; end
272
+ def repaint; @widget.repaint; end
273
+ %w[ form parent parent_component width height row col row_offset col_offset focusable].each { |e|
274
+ eval(
275
+ "def #{e}
276
+ @widget.#{e}
277
+ end
278
+ def #{e}=(val)
279
+ @widget.#{e}=val
280
+ end"
281
+ )
282
+ }
283
+ def method_missing(sym, *args, &block)
284
+ @widget.send sym, *args, &block
285
+ end
286
+ end # class Item
287
+
288
+ # --------------------- module level ------------------------------#
289
+ # General routin to traverse components and their components
290
+ def traverse c, &block
291
+ if c.is_a? BaseStack
292
+ yield c
293
+ c.components.each { |e|
294
+ yield e
295
+ }
296
+ c.components.each { |e| traverse(e, &block) }
297
+ @ctr -= 1
298
+ else
299
+ end
300
+ end
301
+
302
+ # traverse the components and their children
303
+ #
304
+ def each &block
305
+ @components.each { |e| traverse e, &block }
306
+ end
307
+ # module level
308
+ private
309
+ def _stack type, config={}, &block
310
+ case type
311
+ when :stack
312
+ s = Stack.new(config)
313
+ when :flow
314
+ s = Flow.new(config)
315
+ end
316
+ _add s
317
+ @active << s
318
+ yield_or_eval &block if block_given?
319
+ @active.pop
320
+ # if active is empty then this is where we could calculate
321
+ # percentatges and do recalc, thus making it independent
322
+ end
323
+ # module level
324
+ private
325
+ private
326
+ def _add s
327
+ if @active.empty?
328
+ $log.debug "XXX: ADDING TO components #{s} "
329
+ unless s.is_a? BaseStack
330
+ raise "No stack or flow to add to. Results may not be what you want"
331
+ end
332
+ @components << s
333
+ else
334
+ @active.last.components << s
335
+ end
336
+ __add s
337
+ end
338
+
339
+ # module level
340
+ private
341
+ public
342
+ def stack config={}, &block
343
+ _stack :stack, config, &block
344
+ end
345
+ def flow config={}, &block
346
+ _stack :flow, config, &block
347
+ end
348
+ # module level
349
+ private
350
+ def add w, config={}
351
+ i = Item.new config, w
352
+ _add i
353
+ end
354
+ alias :add_widget :add
355
+ # module level
356
+ private
357
+ def calc_weightages2 components, parent
358
+ #puts " #{@ctr} --> #{c.type}, wt: #{c.config[:weight]} "
359
+ @ctr += 1
360
+ wt = 0
361
+ cnt = 0
362
+ sz = components.count
363
+ $log.debug "XXX: calc COMP COUNT #{sz} "
364
+ # calculate how much weightage has been given by user
365
+ # so we can allocate average to other components
366
+ components.each { |e|
367
+ if e.config[:weight]
368
+ wt += e.config[:weight]
369
+ cnt += 1
370
+ end
371
+ $log.debug "XXX: INC setting parent #{parent} to #{e} "
372
+ e.config[:parent] = parent
373
+ e.config[:level] = @ctr
374
+ }
375
+ used = sz - cnt
376
+ $log.debug "XXX: ADDING calc COMP COUNT #{sz} - #{cnt} "
377
+ if used > 0
378
+ avg = (100-wt)/used
379
+ # Allocate average to other components
380
+ components.each { |e| e.config[:weight] = avg unless e.config[:weight] }
381
+ end
382
+ components.each { |e| calc_weightages2(e.components, e) if e.respond_to? :components }
383
+ @ctr -= 1
384
+ end
385
+ # module level
386
+ private
387
+ # given an widget, return the item, so we can change weight or some other config
388
+ def item_for widget
389
+ each do |e|
390
+ if e.is_a? Item
391
+ if e.widget == widget
392
+ return e
393
+ end
394
+ end
395
+ end
396
+ return nil
397
+ end
398
+ # module level
399
+ # returns the parent (flow or stack) for a given widget
400
+ # allowing user to change configuration such as weight
401
+ def parent_of widget
402
+ f = item_for widget
403
+ return f.config[:parent] if f
404
+ return nil
405
+ end
406
+ end # mod modstack
407
+ end # mod