canis 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +45 -0
- data/CHANGES +52 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +24 -0
- data/Rakefile +2 -0
- data/canis.gemspec +25 -0
- data/examples/alpmenu.rb +46 -0
- data/examples/app.sample +19 -0
- data/examples/appemail.rb +191 -0
- data/examples/atree.rb +105 -0
- data/examples/bline.rb +181 -0
- data/examples/common/devel.rb +319 -0
- data/examples/common/file.rb +93 -0
- data/examples/data/README.markdown +9 -0
- data/examples/data/brew.txt +38 -0
- data/examples/data/color.2 +37 -0
- data/examples/data/gemlist.txt +59 -0
- data/examples/data/lotr.txt +12 -0
- data/examples/data/ports.txt +136 -0
- data/examples/data/table.txt +37 -0
- data/examples/data/tasks.csv +88 -0
- data/examples/data/tasks.txt +27 -0
- data/examples/data/todo.txt +16 -0
- data/examples/data/todocsv.csv +28 -0
- data/examples/data/unix1.txt +21 -0
- data/examples/data/unix2.txt +11 -0
- data/examples/dbdemo.rb +506 -0
- data/examples/dirtree.rb +177 -0
- data/examples/newtabbedwindow.rb +100 -0
- data/examples/newtesttabp.rb +92 -0
- data/examples/tabular.rb +212 -0
- data/examples/tasks.rb +179 -0
- data/examples/term2.rb +88 -0
- data/examples/testbuttons.rb +307 -0
- data/examples/testcombo.rb +102 -0
- data/examples/testdb.rb +182 -0
- data/examples/testfields.rb +208 -0
- data/examples/testflowlayout.rb +43 -0
- data/examples/testkeypress.rb +98 -0
- data/examples/testlistbox.rb +187 -0
- data/examples/testlistbox1.rb +199 -0
- data/examples/testmessagebox.rb +144 -0
- data/examples/testprogress.rb +116 -0
- data/examples/testree.rb +107 -0
- data/examples/testsplitlayout.rb +53 -0
- data/examples/testsplitlayout1.rb +49 -0
- data/examples/teststacklayout.rb +48 -0
- data/examples/testwsshortcuts.rb +68 -0
- data/examples/testwsshortcuts2.rb +129 -0
- data/lib/canis.rb +16 -0
- data/lib/canis/core/docs/index.txt +104 -0
- data/lib/canis/core/docs/list.txt +16 -0
- data/lib/canis/core/docs/style_help.yml +34 -0
- data/lib/canis/core/docs/tabbedpane.txt +15 -0
- data/lib/canis/core/docs/table.txt +31 -0
- data/lib/canis/core/docs/textpad.txt +48 -0
- data/lib/canis/core/docs/tree.txt +23 -0
- data/lib/canis/core/include/.DS_Store +0 -0
- data/lib/canis/core/include/action.rb +83 -0
- data/lib/canis/core/include/actionmanager.rb +49 -0
- data/lib/canis/core/include/appmethods.rb +179 -0
- data/lib/canis/core/include/bordertitle.rb +49 -0
- data/lib/canis/core/include/canisparser.rb +100 -0
- data/lib/canis/core/include/colorparser.rb +437 -0
- data/lib/canis/core/include/defaultfilerenderer.rb +64 -0
- data/lib/canis/core/include/io.rb +320 -0
- data/lib/canis/core/include/layouts/SplitLayout.rb +161 -0
- data/lib/canis/core/include/layouts/abstractlayout.rb +213 -0
- data/lib/canis/core/include/layouts/flowlayout.rb +104 -0
- data/lib/canis/core/include/layouts/stacklayout.rb +109 -0
- data/lib/canis/core/include/listbindings.rb +89 -0
- data/lib/canis/core/include/listeditable.rb +319 -0
- data/lib/canis/core/include/listoperations.rb +61 -0
- data/lib/canis/core/include/listselectionmodel.rb +388 -0
- data/lib/canis/core/include/multibuffer.rb +173 -0
- data/lib/canis/core/include/ractionevent.rb +73 -0
- data/lib/canis/core/include/rchangeevent.rb +27 -0
- data/lib/canis/core/include/rhistory.rb +95 -0
- data/lib/canis/core/include/rinputdataevent.rb +47 -0
- data/lib/canis/core/include/textdocument.rb +111 -0
- data/lib/canis/core/include/vieditable.rb +175 -0
- data/lib/canis/core/include/widgetmenu.rb +66 -0
- data/lib/canis/core/system/colormap.rb +165 -0
- data/lib/canis/core/system/keydefs.rb +32 -0
- data/lib/canis/core/system/ncurses.rb +237 -0
- data/lib/canis/core/system/panel.rb +129 -0
- data/lib/canis/core/system/window.rb +1081 -0
- data/lib/canis/core/util/ansiparser.rb +119 -0
- data/lib/canis/core/util/app.rb +696 -0
- data/lib/canis/core/util/basestack.rb +412 -0
- data/lib/canis/core/util/defaultcolorparser.rb +84 -0
- data/lib/canis/core/util/extras/README +5 -0
- data/lib/canis/core/util/extras/bottomline.rb +1815 -0
- data/lib/canis/core/util/extras/padreader.rb +192 -0
- data/lib/canis/core/util/focusmanager.rb +31 -0
- data/lib/canis/core/util/helpmanager.rb +160 -0
- data/lib/canis/core/util/oldwidgetshortcuts.rb +304 -0
- data/lib/canis/core/util/promptmenu.rb +235 -0
- data/lib/canis/core/util/rcommandwindow.rb +933 -0
- data/lib/canis/core/util/rdialogs.rb +520 -0
- data/lib/canis/core/util/textutils.rb +74 -0
- data/lib/canis/core/util/viewer.rb +238 -0
- data/lib/canis/core/util/widgetshortcuts.rb +508 -0
- data/lib/canis/core/widgets/applicationheader.rb +103 -0
- data/lib/canis/core/widgets/box.rb +58 -0
- data/lib/canis/core/widgets/divider.rb +310 -0
- data/lib/canis/core/widgets/extras/README.md +12 -0
- data/lib/canis/core/widgets/extras/rtextarea.rb +960 -0
- data/lib/canis/core/widgets/extras/stackflow.rb +474 -0
- data/lib/canis/core/widgets/keylabelprinter.rb +194 -0
- data/lib/canis/core/widgets/listbox.rb +326 -0
- data/lib/canis/core/widgets/listfooter.rb +86 -0
- data/lib/canis/core/widgets/rcombo.rb +210 -0
- data/lib/canis/core/widgets/rcontainer.rb +415 -0
- data/lib/canis/core/widgets/rlink.rb +30 -0
- data/lib/canis/core/widgets/rmenu.rb +970 -0
- data/lib/canis/core/widgets/rmenulink.rb +30 -0
- data/lib/canis/core/widgets/rmessagebox.rb +400 -0
- data/lib/canis/core/widgets/rprogress.rb +118 -0
- data/lib/canis/core/widgets/rtabbedpane.rb +631 -0
- data/lib/canis/core/widgets/rtabbedwindow.rb +70 -0
- data/lib/canis/core/widgets/rwidget.rb +3634 -0
- data/lib/canis/core/widgets/scrollbar.rb +147 -0
- data/lib/canis/core/widgets/statusline.rb +113 -0
- data/lib/canis/core/widgets/table.rb +1072 -0
- data/lib/canis/core/widgets/tabular.rb +264 -0
- data/lib/canis/core/widgets/textpad.rb +1674 -0
- data/lib/canis/core/widgets/tree.rb +690 -0
- data/lib/canis/core/widgets/tree/treecellrenderer.rb +150 -0
- data/lib/canis/core/widgets/tree/treemodel.rb +432 -0
- data/lib/canis/version.rb +3 -0
- metadata +229 -0
@@ -0,0 +1,74 @@
|
|
1
|
+
# ----------------------------------------------------------------------------- #
|
2
|
+
# File: textutils.rb
|
3
|
+
# Description: contains some common string or Array<String> utilities
|
4
|
+
# that may be required by various parts of application.
|
5
|
+
# Author: j kepler http://github.com/mare-imbrium/canis/
|
6
|
+
# Date: 2014-05-22 - 11:11
|
7
|
+
# License: MIT
|
8
|
+
# Last update: 2014-05-26 19:40
|
9
|
+
# ----------------------------------------------------------------------------- #
|
10
|
+
# textutils.rb Copyright (C) 2012-2014 j kepler
|
11
|
+
|
12
|
+
module Canis
|
13
|
+
module TextUtils
|
14
|
+
# Convert an array of Strings that has help markup into tmux style
|
15
|
+
# which can then by parsed into native format by the tmux parser
|
16
|
+
# 'help' markup is very much like markdown, but a very restricted
|
17
|
+
# subset.
|
18
|
+
# Currently called only by help_manager in rwidgets.rb
|
19
|
+
# Some of these need to be fixed since they may not allow some
|
20
|
+
# characters, maybe too restrictive, or may match within a word. FIXME
|
21
|
+
def self.help2tmux arr
|
22
|
+
arr.each do |e|
|
23
|
+
# double sq brackets are like wiki links, to internal documents in same location
|
24
|
+
e.gsub! /\[\[(\S+)\]\]/, '#[style=link][\1]#[/end]'
|
25
|
+
# double asterisk needs to be more permissive and take a space FIXME
|
26
|
+
e.gsub! /\*\*(\S.*?\S)\*\*/, '#[style=strong]\1#[/end]'
|
27
|
+
# the next is wrong and could match two asteriks also
|
28
|
+
#e.gsub! /\*(\S[^\*]+\S)\*/, '#[style=em]\1#[/end]'
|
29
|
+
e.gsub! /\*(?!\s)([^\*]+)(?<!\s)\*/, '#[style=em]\1#[/end]'
|
30
|
+
e.gsub! /\|([^\|]+)\|/, '#[style=ul]\1#[/end]'
|
31
|
+
#e.gsub! /__(\w+)__/, '#[style=em]\1#[/end]'
|
32
|
+
#e.gsub! /_(\w+)_/, '#[style=em]\1#[/end]'
|
33
|
+
# next one is a bit too restrictive, but did not want a line
|
34
|
+
# full of underlines to get selected.
|
35
|
+
# __(?!_)(.+?)(?<!_)__/
|
36
|
+
#e.gsub! /__([a-zA-Z]+)__/, '#[style=strong]\1#[/end]'
|
37
|
+
# also avoid if a space or _ is after starting __ and before
|
38
|
+
# ending __
|
39
|
+
e.gsub! /__(?![_\s])(.+?)(?<![_\s])__/, '#[style=strong]\1#[/end]'
|
40
|
+
# make sure this does not match inside a word or code
|
41
|
+
# will not accept an underscore inside
|
42
|
+
e.gsub! /\b_([^_]+)_\b/, '#[style=em]\1#[/end]'
|
43
|
+
e.gsub! /`([^`]+)`/, '#[style=code]\1#[/end]'
|
44
|
+
# keys are mentioned with "<" and ">" surrounding
|
45
|
+
e.gsub! /(\<\S+\>)/, '#[style=key]\1#[/end]'
|
46
|
+
# headers start with "#"
|
47
|
+
e.sub! /^###\s*(.*)$/, '#[style=h3]\1#[/end]'
|
48
|
+
e.sub! /^## (.*)$/, '#[style=h2]\1#[/end]'
|
49
|
+
e.sub! /^# (.*)$/, '#[style=h1]\1#[/end]'
|
50
|
+
# line starting with "">" starts a white bold block as in vim's help. "<" ends block.
|
51
|
+
e.sub! /^\>$/, '#[style=wb]'
|
52
|
+
e.sub! /^\<$/, '#[/end]'
|
53
|
+
end
|
54
|
+
return arr
|
55
|
+
end
|
56
|
+
##
|
57
|
+
# wraps text given max length, puts newlines in it.
|
58
|
+
# it does not take into account existing newlines
|
59
|
+
# Some classes have @maxlen or display_length which may be passed as the second parameter
|
60
|
+
def self.wrap_text(txt, max )
|
61
|
+
txt.gsub(/(.{1,#{max}})( +|$\n?)|(.{1,#{max}})/,
|
62
|
+
"\\1\\3\n")
|
63
|
+
end
|
64
|
+
|
65
|
+
# remove tabs, newlines and non-print chars from a string since these
|
66
|
+
# can mess display
|
67
|
+
def self.clean_string! content
|
68
|
+
content.chomp! # don't display newline
|
69
|
+
content.gsub!(/[\t\n]/, ' ') # don't display tab
|
70
|
+
content.gsub!(/[^[:print:]]/, '') # don't display non print characters
|
71
|
+
content
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,238 @@
|
|
1
|
+
require 'canis/core/widgets/textpad'
|
2
|
+
require 'canis/core/widgets/applicationheader'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
# A file or array viewer.
|
6
|
+
#
|
7
|
+
# CHANGES
|
8
|
+
# - 2014-04-09 - 00:58 changed textview to textpad
|
9
|
+
# Can be used for print_help_page
|
10
|
+
# SUGGESTIONS WELCOME.
|
11
|
+
# NOTE: since this is not a proper class / object, it is being hacked to pieces
|
12
|
+
# We need to either make this a proper class, or else make another one with a class,
|
13
|
+
# and use this for simple purposes only.
|
14
|
+
|
15
|
+
module Canis
|
16
|
+
# a data viewer for viewing some text or filecontents
|
17
|
+
# view filename, :close_key => KEY_ENTER
|
18
|
+
# send data in an array
|
19
|
+
# view Array, :close_key => KEY_ENTER, :layout => [23,80,0,0] (ht, wid, top, left)
|
20
|
+
# when passing layout reserve 4 rows for window and border. So for 2 lines of text
|
21
|
+
# give 6 rows.
|
22
|
+
class Viewer
|
23
|
+
# @param filename as string or content as array
|
24
|
+
# @yield textview object for further configuration before display
|
25
|
+
def self.view what, config={}, &block #:yield: textview
|
26
|
+
case what
|
27
|
+
when String # we have a path
|
28
|
+
content = _get_contents(what)
|
29
|
+
when Array
|
30
|
+
content = what
|
31
|
+
when TextDocument
|
32
|
+
$log.debug " setting content to textdocument #{what.options.keys} "
|
33
|
+
content = what
|
34
|
+
#content = what.text
|
35
|
+
#config[:content_type] = what.content_type
|
36
|
+
else
|
37
|
+
raise ArgumentError, "Viewer: Expecting Filename or Contents (array), but got #{what.class} "
|
38
|
+
end
|
39
|
+
wt = 0 # top margin
|
40
|
+
wl = 0 # left margin
|
41
|
+
wh = Ncurses.LINES-wt # height, goes to bottom of screen
|
42
|
+
ww = Ncurses.COLS-wl # width, goes to right end
|
43
|
+
layout = { :height => wh, :width => ww, :top => wt, :left => wl }
|
44
|
+
if config.has_key? :layout
|
45
|
+
layout = config[:layout]
|
46
|
+
case layout
|
47
|
+
when Array
|
48
|
+
#wt, wl, wh, ww = layout
|
49
|
+
# 2014-04-27 - 11:22 changed to the same order as window, otherwise confusion and errors
|
50
|
+
wh, ww, wt, wl = layout
|
51
|
+
layout = { :height => wh, :width => ww, :top => wt, :left => wl }
|
52
|
+
when Hash
|
53
|
+
# okay
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
fp = config[:title] || ""
|
58
|
+
pf = config.fetch(:print_footer, true)
|
59
|
+
ta = config.fetch(:title_attrib, 'bold')
|
60
|
+
fa = config.fetch(:footer_attrib, 'bold')
|
61
|
+
wbg = config.fetch(:window_bgcolor, nil)
|
62
|
+
b_ah = config[:app_header]
|
63
|
+
type = config[:content_type]
|
64
|
+
|
65
|
+
v_window = Canis::Window.new(layout)
|
66
|
+
v_form = Canis::Form.new v_window
|
67
|
+
v_window.name = "Viewer"
|
68
|
+
if wbg
|
69
|
+
v_window.wbkgd(Ncurses.COLOR_PAIR(wbg)); # does not work on xterm-256color
|
70
|
+
end
|
71
|
+
# I am placing this in globals since an alert on top will refresh the lower windows and this is quite large.
|
72
|
+
$global_windows << v_window
|
73
|
+
colors = Ncurses.COLORS
|
74
|
+
back = :blue
|
75
|
+
back = 235 if colors >= 256
|
76
|
+
blue_white = get_color($datacolor, :white, back)
|
77
|
+
|
78
|
+
tprow = 0
|
79
|
+
ah = nil
|
80
|
+
if b_ah
|
81
|
+
ah = ApplicationHeader.new v_form, "", :text_center => fp
|
82
|
+
tprow += 1
|
83
|
+
end
|
84
|
+
|
85
|
+
#blue_white = Canis::Utils.get_color($datacolor, :white, 235)
|
86
|
+
textview = TextPad.new v_form do
|
87
|
+
name "Viewer"
|
88
|
+
row tprow
|
89
|
+
col 0
|
90
|
+
width ww
|
91
|
+
height wh-tprow # earlier 2 but seems to be leaving space.
|
92
|
+
title fp
|
93
|
+
title_attrib ta
|
94
|
+
print_footer pf
|
95
|
+
footer_attrib fa
|
96
|
+
#border_attrib :reverse
|
97
|
+
border_color blue_white
|
98
|
+
end
|
99
|
+
# why multibuffers -- since used in help
|
100
|
+
require 'canis/core/include/multibuffer'
|
101
|
+
textview.extend(Canis::MultiBuffers)
|
102
|
+
|
103
|
+
t = textview
|
104
|
+
t.bind_key(Ncurses::KEY_F5, 'maximize window '){ f = t.form.window;
|
105
|
+
f.resize_with([FFI::NCurses.LINES-0, Ncurses.COLS, 0,0]);
|
106
|
+
#f.resize_with([0,0, 0,0]);
|
107
|
+
t.height = Ncurses.LINES - t.row - 0
|
108
|
+
}
|
109
|
+
t.bind_key(Ncurses::KEY_F6, 'restore window ', layout){ |l,m, n|
|
110
|
+
# l was DefaultKeyHandler, m was string, n was Hash
|
111
|
+
f = t.form.window;
|
112
|
+
#$log.debug " F6 ARG is #{m}, #{n}"
|
113
|
+
f.hide; # need to hide since earlier window was larger.
|
114
|
+
f.resize_with(n);
|
115
|
+
#f.resize_with([0,0, 0,0]);
|
116
|
+
t.height = f.height - t.row - 0
|
117
|
+
f.show
|
118
|
+
}
|
119
|
+
t.bind_key(?\C-\], "open file under cursor") {
|
120
|
+
eve = t.text_action_event
|
121
|
+
file = eve.word_under_cursor.strip
|
122
|
+
if File.exists? file
|
123
|
+
t.add_content file
|
124
|
+
t.buffer_last
|
125
|
+
end
|
126
|
+
}
|
127
|
+
|
128
|
+
=begin
|
129
|
+
# just for fun -- seeing how we can move window around
|
130
|
+
# these are working, but can cause a padrefresh error. we should check for bounds or something.
|
131
|
+
#
|
132
|
+
t.bind_key('<', 'move window left'){ f = t.form.window; c = f.left - 1; f.hide; f.mvwin(f.top, c); f.show;
|
133
|
+
f.set_layout([f.height, f.width, f.top, c]);
|
134
|
+
}
|
135
|
+
t.bind_key('>', 'move window right'){ f = t.form.window; c = f.left + 1; f.hide; f.mvwin(f.top, c);
|
136
|
+
f.set_layout([f.height, f.width, f.top, c]); f.show;
|
137
|
+
}
|
138
|
+
t.bind_key('^', 'move window up'){ f = t.form.window; c = f.top - 1 ; f.hide; f.mvwin(c, f.left);
|
139
|
+
f.set_layout([f.height, f.width, c, f.left]) ; f.show;
|
140
|
+
}
|
141
|
+
t.bind_key('V', 'move window down'){ f = t.form.window; c = f.top + 1 ; f.hide; f.mvwin(c, f.left);
|
142
|
+
f.set_layout([f.height, f.width, c, f.left]); f.show;
|
143
|
+
}
|
144
|
+
=end
|
145
|
+
items = {:header => ah}
|
146
|
+
close_keys = [ config[:close_key] , 3 , ?q.getbyte(0), 27 , 2727 ]
|
147
|
+
begin
|
148
|
+
# the next can also be used to use formatted_text(text, :ansi)
|
149
|
+
# yielding textview so you may further configure or bind keys or events
|
150
|
+
if block_given?
|
151
|
+
if block.arity > 0
|
152
|
+
yield textview, items
|
153
|
+
else
|
154
|
+
textview.instance_eval(&block)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
# multibuffer requires add_co after set_co
|
158
|
+
# We are using in help, therefore we need multibuffers.
|
159
|
+
#textview.set_content content, :content_type => type #, :stylesheet => t.stylesheet
|
160
|
+
# i need to do this so it is available when moving around
|
161
|
+
# buffers
|
162
|
+
# but this means that pressing next will again show the same
|
163
|
+
# buffer.
|
164
|
+
textview.add_content content, :content_type => type #, :stylesheet => t.stylesheet
|
165
|
+
textview.buffer_last
|
166
|
+
#yield textview if block_given?
|
167
|
+
v_form.repaint
|
168
|
+
v_window.wrefresh
|
169
|
+
Ncurses::Panel.update_panels
|
170
|
+
retval = ""
|
171
|
+
# allow closing using q and Ctrl-q in addition to any key specified
|
172
|
+
# user should not need to specify key, since that becomes inconsistent across usages
|
173
|
+
# NOTE: 2727 is no longer operational, so putting just ESC
|
174
|
+
while((ch = v_window.getchar()) != ?\C-q.getbyte(0) )
|
175
|
+
$log.debug " VIEWER got key #{ch} , close key is #{config[:close_key]} "
|
176
|
+
retval = textview.current_value() if ch == config[:close_key]
|
177
|
+
break if close_keys.include? ch
|
178
|
+
# if you've asked for ENTER then i also check for 10 and 13
|
179
|
+
retval = textview.current_value() if (ch == 10 || ch == 13) && config[:close_key] == KEY_ENTER
|
180
|
+
break if (ch == 10 || ch == 13) && config[:close_key] == KEY_ENTER
|
181
|
+
$log.debug " 1 VIEWER got key #{ch} "
|
182
|
+
v_form.handle_key ch
|
183
|
+
v_form.repaint
|
184
|
+
end
|
185
|
+
rescue => err
|
186
|
+
$log.error " VIEWER ERROR #{err} "
|
187
|
+
$log.debug(err.backtrace.join("\n"))
|
188
|
+
alert "#{err}"
|
189
|
+
#textdialog ["Error in viewer: #{err} ", *err.backtrace], :title => "Exception"
|
190
|
+
ensure
|
191
|
+
v_window.destroy if !v_window.nil?
|
192
|
+
end
|
193
|
+
return retval
|
194
|
+
end
|
195
|
+
private
|
196
|
+
def self._get_contents fp
|
197
|
+
raise "File #{fp} not readable" unless File.readable? fp
|
198
|
+
return Dir.new(fp).entries if File.directory? fp
|
199
|
+
case File.extname(fp)
|
200
|
+
when '.tgz','.gz'
|
201
|
+
cmd = "tar -ztvf #{fp}"
|
202
|
+
content = %x[#{cmd}]
|
203
|
+
when '.zip'
|
204
|
+
cmd = "unzip -l #{fp}"
|
205
|
+
content = %x[#{cmd}]
|
206
|
+
when '.jar', '.gem'
|
207
|
+
cmd = "tar -tvf #{fp}"
|
208
|
+
content = %x[#{cmd}]
|
209
|
+
when '.png', '.out','.jpg', '.gif','.pdf'
|
210
|
+
content = "File #{fp} not displayable"
|
211
|
+
when '.sqlite'
|
212
|
+
cmd = "sqlite3 #{fp} 'select name from sqlite_master;'"
|
213
|
+
content = %x[#{cmd}]
|
214
|
+
else
|
215
|
+
content = File.open(fp,"r").readlines
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end # class
|
219
|
+
|
220
|
+
end # module
|
221
|
+
if __FILE__ == $PROGRAM_NAME
|
222
|
+
require 'canis/core/util/app'
|
223
|
+
|
224
|
+
App.new do
|
225
|
+
header = app_header "canis 1.2.0", :text_center => "Viewer Demo", :text_right =>"New Improved!", :color => :black, :bgcolor => :white, :attr => :bold
|
226
|
+
message "Press F1 to exit from here"
|
227
|
+
|
228
|
+
Canis::Viewer.view(ARGV[0] || $0, :close_key => KEY_ENTER, :title => "Enter to close") do |t|
|
229
|
+
# you may configure textview further here.
|
230
|
+
#t.suppress_borders true
|
231
|
+
#t.color = :black
|
232
|
+
#t.bgcolor = :white
|
233
|
+
# or
|
234
|
+
#t.attr = :reverse
|
235
|
+
end
|
236
|
+
|
237
|
+
end # app
|
238
|
+
end
|
@@ -0,0 +1,508 @@
|
|
1
|
+
# ------------------------------------------------------------ #
|
2
|
+
# File: widgetshortcuts.rb
|
3
|
+
# Description: A common module for shortcuts to create widgets
|
4
|
+
# Also, stacks and flows objects
|
5
|
+
# Author: jkepler http://github.com/mare-imbrium/canis/
|
6
|
+
# Date: 05.11.11 - 15:13
|
7
|
+
# Last update: 2014-07-10 00:40
|
8
|
+
#
|
9
|
+
# I hope this slowly does not become an unmaintainable maze like vimsplit
|
10
|
+
#
|
11
|
+
# "Simplicity hinges as much on cutting nonessential features as on adding helpful ones."
|
12
|
+
# - Walter Bender
|
13
|
+
#
|
14
|
+
# == TODO
|
15
|
+
# add blocks that make sense like in app
|
16
|
+
# - what if user does not want form attached - app uses useform ot
|
17
|
+
# to check for this, if current_object don't add form
|
18
|
+
#
|
19
|
+
# - usage of _position inside means these shortcuts cannot be reused
|
20
|
+
# with other positioning systems, we'll be cut-pasting forever
|
21
|
+
#
|
22
|
+
# == CHANGES
|
23
|
+
# ------------------------------------------------------------ #
|
24
|
+
#
|
25
|
+
|
26
|
+
# what is the real purpose of the shortcuts, is it to avoid putting nil
|
27
|
+
# for form there if not required.
|
28
|
+
# Or is it positioning, such as in a stack. or just a method ?
|
29
|
+
#require 'canis/core/widgets/rlist'
|
30
|
+
## trying out new list based on textpad 2014-04-07 - 00:02 CANIS
|
31
|
+
module Canis
|
32
|
+
module WidgetShortcuts
|
33
|
+
class Ws
|
34
|
+
attr_reader :config
|
35
|
+
def initialize config={}
|
36
|
+
@config = config
|
37
|
+
end
|
38
|
+
def [](sym)
|
39
|
+
@config[sym]
|
40
|
+
end
|
41
|
+
def []=(sym, val)
|
42
|
+
@config[sym] = val
|
43
|
+
end
|
44
|
+
end
|
45
|
+
class WsStack < Ws; end
|
46
|
+
class WsFlow < Ws; end
|
47
|
+
def widget_shortcuts_init
|
48
|
+
@_ws_app_row = @_ws_app_col = 0
|
49
|
+
#@_ws_active = []
|
50
|
+
@_ws_active = nil # so we can use shortcuts if no stack used
|
51
|
+
@_ws_components = []
|
52
|
+
@variables = {}
|
53
|
+
end
|
54
|
+
# --- shortcuts {{{
|
55
|
+
def blank
|
56
|
+
label :text => ""
|
57
|
+
end
|
58
|
+
def line config={}
|
59
|
+
#horizontal line TODO
|
60
|
+
#row = config[:row] || @app_row
|
61
|
+
#width = config[:width] || 20
|
62
|
+
#_position config
|
63
|
+
#col = config[:col] || 1
|
64
|
+
#@color_pair = config[:color_pair] || $datacolor
|
65
|
+
#@attrib = config[:attrib] || Ncurses::A_NORMAL
|
66
|
+
#@window.attron(Ncurses.COLOR_PAIR(@color_pair) | @attrib)
|
67
|
+
#@window.mvwhline( row, col, FFI::NCurses::ACS_HLINE, width)
|
68
|
+
#@window.attron(Ncurses.COLOR_PAIR(@color_pair) | @attrib)
|
69
|
+
end
|
70
|
+
def radio config={}, &block
|
71
|
+
a = config[:group]
|
72
|
+
# should we not check for a nil
|
73
|
+
if @variables.has_key? a
|
74
|
+
v = @variables[a]
|
75
|
+
else
|
76
|
+
v = Variable.new
|
77
|
+
@variables[a] = v
|
78
|
+
end
|
79
|
+
config[:variable] = v
|
80
|
+
config.delete(:group)
|
81
|
+
w = RadioButton.new nil, config #, &block
|
82
|
+
_position w
|
83
|
+
if block
|
84
|
+
w.bind(:PRESS, &block)
|
85
|
+
end
|
86
|
+
return w
|
87
|
+
end
|
88
|
+
# create a shortcut for a class
|
89
|
+
# path is path of file to use in require starting with canis
|
90
|
+
# klass is name of class to instantiate
|
91
|
+
def self.def_widget(path, klass, short=nil)
|
92
|
+
p=""
|
93
|
+
if path
|
94
|
+
p="require \"#{path}\""
|
95
|
+
end
|
96
|
+
short ||= klass.to_s.downcase
|
97
|
+
eval %{
|
98
|
+
def #{short}(config={}, &block)
|
99
|
+
if config.is_a? String
|
100
|
+
_s = config
|
101
|
+
config = {}
|
102
|
+
config[:text] = _s
|
103
|
+
end
|
104
|
+
#{p}
|
105
|
+
w = #{klass}.new nil, config
|
106
|
+
_position w
|
107
|
+
w.command &block if block_given?
|
108
|
+
return w
|
109
|
+
end
|
110
|
+
}
|
111
|
+
end
|
112
|
+
def_widget "canis/core/widgets/rprogress", "Progress"
|
113
|
+
def_widget "canis/core/widgets/scrollbar", "Scrollbar"
|
114
|
+
def_widget nil, "Label"
|
115
|
+
#def_widget nil, "Field"
|
116
|
+
def_widget nil, "LabeledField", 'field'
|
117
|
+
def_widget nil, :CheckBox, 'check'
|
118
|
+
def_widget nil, :Button
|
119
|
+
def_widget nil, :ToggleButton, 'toggle'
|
120
|
+
def menubar &block
|
121
|
+
require 'canis/core/widgets/rmenu'
|
122
|
+
Canis::MenuBar.new &block
|
123
|
+
end
|
124
|
+
# add a standard application header
|
125
|
+
# == Example
|
126
|
+
# header = app_header "canis ", :text_center => "Browser Demo", :text_right =>"New Improved!",
|
127
|
+
# :color => :black, :bgcolor => :white, :attr => :bold
|
128
|
+
def app_header title, config={}, &block
|
129
|
+
require 'canis/core/widgets/applicationheader'
|
130
|
+
header = ApplicationHeader.new @form, title, config, &block
|
131
|
+
end
|
132
|
+
# editable text area
|
133
|
+
# use only for simple cases, since this is not fully tested
|
134
|
+
def textarea config={}, &block
|
135
|
+
require 'canis/core/widgets/extras/rtextarea'
|
136
|
+
# TODO confirm events many more
|
137
|
+
events = [ :CHANGE, :LEAVE, :ENTER ]
|
138
|
+
block_event = events[0]
|
139
|
+
#_process_args args, config, block_event, events
|
140
|
+
#config[:width] = config[:display_length] unless config.has_key? :width
|
141
|
+
# if no width given, expand to flows width
|
142
|
+
#config[:width] ||= @stack.last.width if @stack.last
|
143
|
+
useform = nil
|
144
|
+
#useform = @form if @current_object.empty?
|
145
|
+
w = TextArea.new useform, config
|
146
|
+
w.width = :expand unless w.width
|
147
|
+
w.height ||= :expand # TODO This has to come before other in stack next one will overwrite.
|
148
|
+
_position(w)
|
149
|
+
w.height ||= 8 # TODO
|
150
|
+
# need to expand to stack's width or flows itemwidth if given
|
151
|
+
if block
|
152
|
+
w.bind(block_event, &block)
|
153
|
+
end
|
154
|
+
return w
|
155
|
+
end
|
156
|
+
def textpad config={}, &block
|
157
|
+
events = [ :LEAVE, :ENTER ]
|
158
|
+
block_event = events[0]
|
159
|
+
#_process_args args, config, block_event, events
|
160
|
+
#config[:width] = config[:display_length] unless config.has_key? :width
|
161
|
+
# if no width given, expand to flows width
|
162
|
+
#config[:width] ||= @stack.last.width if @stack.last
|
163
|
+
useform = nil
|
164
|
+
#useform = @form if @current_object.empty?
|
165
|
+
#w = TextView.new useform, config
|
166
|
+
w = TextPad.new useform, config
|
167
|
+
w.width = :expand unless w.width
|
168
|
+
w.height ||= :expand # TODO This has to come before other in stack next one will overwrite.
|
169
|
+
_position(w)
|
170
|
+
# need to expand to stack's width or flows itemwidth if given
|
171
|
+
if block
|
172
|
+
w.bind(block_event, &block)
|
173
|
+
end
|
174
|
+
return w
|
175
|
+
end
|
176
|
+
# deprecate and move textview soon TODO
|
177
|
+
alias :textview :textpad
|
178
|
+
def listbox config={}, &block
|
179
|
+
require 'canis/core/widgets/listbox'
|
180
|
+
events = [ :PRESS, :ENTER_ROW, :LEAVE, :ENTER ]
|
181
|
+
block_event = events[0]
|
182
|
+
#_process_args args, config, block_event, events
|
183
|
+
#config[:width] = config[:display_length] unless config.has_key? :width
|
184
|
+
# if no width given, expand to flows width
|
185
|
+
#config[:width] ||= @stack.last.width if @stack.last
|
186
|
+
useform = nil
|
187
|
+
#useform = @form if @current_object.empty?
|
188
|
+
#w = List.new useform, config
|
189
|
+
w = Listbox.new useform, config
|
190
|
+
w.width = :expand unless w.width
|
191
|
+
w.height ||= :expand # TODO We may need to push this before _position so it can be accounted for in stack
|
192
|
+
_position(w)
|
193
|
+
# need to expand to stack's width or flows itemwidth if given
|
194
|
+
if block
|
195
|
+
w.bind(block_event, &block)
|
196
|
+
end
|
197
|
+
return w
|
198
|
+
end
|
199
|
+
# prints pine-like key labels
|
200
|
+
def dock labels, config={}, &block
|
201
|
+
require 'canis/core/widgets/keylabelprinter'
|
202
|
+
klp = Canis::KeyLabelPrinter.new @form, labels, config, &block
|
203
|
+
end
|
204
|
+
|
205
|
+
#
|
206
|
+
# prints a status line at bottom where mode's statuses et can be reflected
|
207
|
+
def status_line config={}, &block
|
208
|
+
require 'canis/core/widgets/statusline'
|
209
|
+
sl = Canis::StatusLine.new @form, config, &block
|
210
|
+
end
|
211
|
+
|
212
|
+
def link config={}, &block
|
213
|
+
if config.is_a? String
|
214
|
+
_s = config
|
215
|
+
config = {}
|
216
|
+
config[:text] = _s
|
217
|
+
end
|
218
|
+
require 'canis/core/widgets/rlink'
|
219
|
+
events = [ :PRESS, :LEAVE, :ENTER ]
|
220
|
+
block_event = :PRESS
|
221
|
+
config[:highlight_color] = "yellow"
|
222
|
+
config[:highlight_bgcolor] = "red"
|
223
|
+
toggle = Link.new nil, config
|
224
|
+
_position(toggle)
|
225
|
+
if block
|
226
|
+
toggle.bind(block_event, toggle, &block)
|
227
|
+
end
|
228
|
+
return toggle
|
229
|
+
end
|
230
|
+
def menulink config={}, &block
|
231
|
+
if config.is_a? String
|
232
|
+
_s = config
|
233
|
+
config = {}
|
234
|
+
config[:text] = _s
|
235
|
+
end
|
236
|
+
require 'canis/core/widgets/rmenulink'
|
237
|
+
events = [ :PRESS, :LEAVE, :ENTER ]
|
238
|
+
block_event = :PRESS
|
239
|
+
config[:highlight_color] = "yellow"
|
240
|
+
config[:highlight_bgcolor] = "red"
|
241
|
+
#config[:hotkey] = true
|
242
|
+
w = MenuLink.new nil, config
|
243
|
+
_position(w)
|
244
|
+
if block
|
245
|
+
w.bind(block_event, w, &block)
|
246
|
+
end
|
247
|
+
return w
|
248
|
+
end
|
249
|
+
def tree config={}, &block
|
250
|
+
#require 'canis/core/widgets/rtree'
|
251
|
+
require 'canis/core/widgets/tree'
|
252
|
+
events = [:TREE_WILL_EXPAND_EVENT, :TREE_EXPANDED_EVENT, :TREE_SELECTION_EVENT, :PROPERTY_CHANGE, :LEAVE, :ENTER , :ENTER_ROW, :TREE_COLLAPSED_EVENT, :TREE_WILL_EXPAND_EVENT]
|
253
|
+
block_event = :TREE_WILL_EXPAND_EVENT
|
254
|
+
#config[:height] ||= 10
|
255
|
+
# if no width given, expand to flows width
|
256
|
+
useform = nil
|
257
|
+
#useform = @form if @current_object.empty?
|
258
|
+
w = Tree.new useform, config, &block
|
259
|
+
w.width ||= :expand
|
260
|
+
w.height ||= :expand # TODO This has to come before other in stack next one will overwrite.
|
261
|
+
_position w
|
262
|
+
# calling the block here was causing a problem since a tree may define root etc in the block
|
263
|
+
# containers like to define elements in a block and not have an event called by default
|
264
|
+
return w
|
265
|
+
end
|
266
|
+
# creates a simple readonly table, that allows users to click on rows
|
267
|
+
# and also on the header. Header clicking is for column-sorting.
|
268
|
+
def table config={}, &block
|
269
|
+
#def tabular_widget config={}, &block
|
270
|
+
require 'canis/core/widgets/table'
|
271
|
+
events = [:PROPERTY_CHANGE, :LEAVE, :ENTER, :CHANGE, :ENTER_ROW, :PRESS ]
|
272
|
+
block_event = nil
|
273
|
+
# if no width given, expand to stack width
|
274
|
+
#config.delete :title
|
275
|
+
useform = nil
|
276
|
+
|
277
|
+
w = Table.new useform, config # NO BLOCK GIVEN
|
278
|
+
w.width ||= :expand
|
279
|
+
w.height ||= :expand # TODO This has to come before other in stack next one will overwrite.
|
280
|
+
_position(w)
|
281
|
+
if block_given?
|
282
|
+
#@current_object << w
|
283
|
+
yield_or_eval &block
|
284
|
+
#@current_object.pop
|
285
|
+
end
|
286
|
+
return w
|
287
|
+
end
|
288
|
+
|
289
|
+
# --- }}}
|
290
|
+
def _position w
|
291
|
+
if @_ws_active.nil? || @_ws_active.empty?
|
292
|
+
# no stack or flow, this is independent usage, or else we are outside stacks and flows
|
293
|
+
#
|
294
|
+
# this is outside any stack or flow, so we do the minimal
|
295
|
+
# user should specify row and col
|
296
|
+
w.row ||= 0
|
297
|
+
w.col ||= 0
|
298
|
+
#$log.debug "XXX: LABEL #{w.row} , #{w.col} "
|
299
|
+
w.set_form @form if @form # temporary,, only set if not inside an object FIXME
|
300
|
+
if w.width == :expand # calculate from current col, not 0 FIXME
|
301
|
+
w.width = FFI::NCurses.COLS-w.col # or take windows width since this could be in a message box
|
302
|
+
end
|
303
|
+
if w.height == :expand
|
304
|
+
# take from current row, and not zero FIXME
|
305
|
+
w.height = FFI::NCurses.LINES-w.row # or take windows width since this could be in a message box
|
306
|
+
end
|
307
|
+
return
|
308
|
+
|
309
|
+
end
|
310
|
+
# -------------------------- there is a stack or flow -------------------- #
|
311
|
+
#
|
312
|
+
cur = @_ws_active.last
|
313
|
+
unless cur
|
314
|
+
raise "This should have been handled previously.Somethings wrong, check/untested"
|
315
|
+
end
|
316
|
+
r = cur[:row] || 0
|
317
|
+
c = cur[:col] || 0
|
318
|
+
w.row = r
|
319
|
+
w.col = c
|
320
|
+
# if flow then take flows height, else use dummy value
|
321
|
+
if w.height_pc
|
322
|
+
w.height = ( (cur[:height] * w.height_pc.to_i)/100).floor
|
323
|
+
end
|
324
|
+
if w.height == :expand
|
325
|
+
if cur.is_a? WsFlow
|
326
|
+
w.height = cur[:height] || 8 #or raise "height not known for flow"
|
327
|
+
else
|
328
|
+
w.height = cur[:item_height] || 8 #or raise "height not known for flow"
|
329
|
+
end
|
330
|
+
#alert "setting ht to #{w.height}, #{cur[:height]} , for #{cur} "
|
331
|
+
end
|
332
|
+
if w.width == :expand
|
333
|
+
if cur.is_a? WsFlow
|
334
|
+
if cur[:item_width]
|
335
|
+
w.width = cur[:item_width] #or raise "item_Width not known for flow #{cur.class}, #{cur[:item_width]}, #{cur[:width]} , #{w.width_pc} "
|
336
|
+
elsif w.width_pc
|
337
|
+
#w.width = w.width_pc * cur[:width]
|
338
|
+
w.width = (cur[:width] * (w.width_pc.to_i * 0.01)).floor
|
339
|
+
else
|
340
|
+
w.width = cur[:width]
|
341
|
+
end
|
342
|
+
raise "width could not be calculated. i need flow width and item width_pc" if w.width == :expand
|
343
|
+
else
|
344
|
+
w.width = cur[:width] or raise "Width not known for stack #{cur.class}, #{cur[:width]} "
|
345
|
+
end
|
346
|
+
end
|
347
|
+
if cur.is_a? WsStack
|
348
|
+
r += w.height || 1 # NOTE, we need to have height for this purpose defined BEFORE calling for list/text
|
349
|
+
cur[:row] = r
|
350
|
+
else
|
351
|
+
wid = cur[:item_width] || w.width || 10
|
352
|
+
c += wid + 1
|
353
|
+
cur[:col] = c
|
354
|
+
end
|
355
|
+
#alert "set width to #{w.width} ,cur: #{cur[:width]} ,iw: #{cur[:item_width]} "
|
356
|
+
if cur.is_a? WsFlow
|
357
|
+
unless w.height
|
358
|
+
w.height = cur[:height] #or raise "Height not known for flow"
|
359
|
+
end
|
360
|
+
end
|
361
|
+
w.color ||= cur[:color]
|
362
|
+
w.bgcolor ||= cur[:bgcolor]
|
363
|
+
w.set_form @form if @form # temporary
|
364
|
+
@_ws_components << w
|
365
|
+
cur[:components] << w
|
366
|
+
end
|
367
|
+
# make it as simple as possible, don't try to be intelligent or
|
368
|
+
# clever, put as much on the user
|
369
|
+
def stack config={}, &block
|
370
|
+
s = WsStack.new config
|
371
|
+
@_ws_active ||= []
|
372
|
+
_configure s
|
373
|
+
@_ws_active << s
|
374
|
+
yield_or_eval &block if block_given?
|
375
|
+
@_ws_active.pop
|
376
|
+
|
377
|
+
# ---- stack is finished now
|
378
|
+
last = @_ws_active.last
|
379
|
+
if last
|
380
|
+
case last
|
381
|
+
when WsStack
|
382
|
+
when WsFlow
|
383
|
+
last[:col] += last[:item_width] || 0
|
384
|
+
# this tries to set height of outer flow based on highest row
|
385
|
+
# printed, however that does not account for height of object,
|
386
|
+
# so user should give a height to the flow.
|
387
|
+
last[:height] = s[:row] if s[:row] > (last[:height]||0)
|
388
|
+
$log.debug "XXX: STACK setting col to #{s[:col]} "
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
end
|
393
|
+
#
|
394
|
+
# item_width - width to use per item
|
395
|
+
# but the item width may apply to stacks inside not to items
|
396
|
+
def flow config={}, &block
|
397
|
+
s = WsFlow.new config
|
398
|
+
@_ws_active ||= []
|
399
|
+
_configure s
|
400
|
+
@_ws_active << s
|
401
|
+
yield_or_eval &block if block_given?
|
402
|
+
@_ws_active.pop
|
403
|
+
last = @_ws_active.last
|
404
|
+
if last
|
405
|
+
case last
|
406
|
+
when WsStack
|
407
|
+
if s[:height]
|
408
|
+
last[:row] += s[:height]
|
409
|
+
else
|
410
|
+
#last[:row] += last[:highest_row]
|
411
|
+
last[:row] += 1
|
412
|
+
end
|
413
|
+
when WsFlow
|
414
|
+
last[:col] += last[:item_width] || 0
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|
418
|
+
# flow and stack could have a border option
|
419
|
+
# NOTE: box takes one row below too, so :expand overwrites that line
|
420
|
+
def box config={}, &block
|
421
|
+
require 'canis/core/widgets/box'
|
422
|
+
# take current stacks row and col
|
423
|
+
# advance row by one and col by one
|
424
|
+
# at end note row and advance by one
|
425
|
+
# draw a box around using these coordinates. width should be
|
426
|
+
# provided unless we have item width or something.
|
427
|
+
@_ws_active ||= []
|
428
|
+
last = @_ws_active.last
|
429
|
+
if last
|
430
|
+
r = last[:row]
|
431
|
+
c = last[:col]
|
432
|
+
config[:row] = r
|
433
|
+
config[:col] = c
|
434
|
+
last[:row] += config[:margin_top] || 1
|
435
|
+
last[:col] += config[:margin_left] || 1
|
436
|
+
_box = Box.new @form, config # needs to be created first or will overwrite area after others painted
|
437
|
+
yield_or_eval &block if block_given?
|
438
|
+
# FIXME last[height] needs to account for row
|
439
|
+
h = config[:height] || last[:height] || (last[:row] - r)
|
440
|
+
h = 2 if h < 2
|
441
|
+
w = config[:width] || last[:width] || 15 # tmp
|
442
|
+
case last
|
443
|
+
when WsFlow
|
444
|
+
w = last[:col]
|
445
|
+
when WsStack
|
446
|
+
#h += 1
|
447
|
+
end
|
448
|
+
config[:row] = r
|
449
|
+
config[:col] = c
|
450
|
+
config[:height] = h
|
451
|
+
config[:width] = w
|
452
|
+
_box.row r
|
453
|
+
_box.col c
|
454
|
+
_box.height h
|
455
|
+
_box.width w
|
456
|
+
last[:row] += 1
|
457
|
+
last[:col] += 1 # ??? XXX if flow we need to increment properly or not ?
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
# This configures a stack or flow not the objects inside
|
462
|
+
def _configure s
|
463
|
+
s[:row] ||= 0
|
464
|
+
s[:col] ||= 0
|
465
|
+
s[:row] += (s[:margin_top] || 0)
|
466
|
+
s[:col] += (s[:margin_left] || 0)
|
467
|
+
s[:width] = FFI::NCurses.COLS-s[:col] if s[:width] == :expand
|
468
|
+
s[:height] = FFI::NCurses.LINES-s[:row] if s[:height] == :expand # 2011-11-30
|
469
|
+
last = @_ws_active.last
|
470
|
+
if last
|
471
|
+
if s[:width_pc]
|
472
|
+
if last.is_a? WsStack
|
473
|
+
s[:width] = (last[:width] * (s[:width_pc].to_i * 0.01)).floor
|
474
|
+
else
|
475
|
+
# i think this width is picked up by next stack in this flow
|
476
|
+
last[:item_width] = (last[:width] * (s[:width_pc].to_i* 0.01)).floor
|
477
|
+
end
|
478
|
+
end
|
479
|
+
if s[:height_pc]
|
480
|
+
if last.is_a? WsFlow
|
481
|
+
s[:height] = ( (last[:height] * s[:height_pc].to_i)/100).floor
|
482
|
+
else
|
483
|
+
# this works only for flows within stacks not for an object unless
|
484
|
+
# you put a single object in a flow
|
485
|
+
s[:item_height] = ( (last[:height] * s[:height_pc].to_i)/100).floor
|
486
|
+
end
|
487
|
+
#alert "item height set as #{s[:height]} for #{s} "
|
488
|
+
end
|
489
|
+
if last.is_a? WsStack
|
490
|
+
s[:row] += (last[:row] || 0)
|
491
|
+
s[:col] += (last[:col] || 0)
|
492
|
+
else
|
493
|
+
s[:row] += (last[:row] || 0)
|
494
|
+
s[:col] += (last[:col] || 0) # we are updating with item_width as each st finishes
|
495
|
+
s[:width] ||= last[:item_width] #
|
496
|
+
end
|
497
|
+
else
|
498
|
+
# this should be outer most flow or stack, if nothing mentioned
|
499
|
+
# trying this out
|
500
|
+
s[:width] ||= :expand
|
501
|
+
s[:height] ||= :expand
|
502
|
+
s[:width] = FFI::NCurses.COLS-s[:col] if s[:width] == :expand
|
503
|
+
s[:height] = FFI::NCurses.LINES-s[:row] if s[:height] == :expand # 2011-11-30
|
504
|
+
end
|
505
|
+
s[:components] = []
|
506
|
+
end
|
507
|
+
end
|
508
|
+
end
|