rbhex-core 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/CHANGELOG +2000 -0
- data/LICENSE +56 -0
- data/README.md +44 -0
- data/examples/abasiclist.rb +179 -0
- data/examples/alpmenu.rb +50 -0
- data/examples/app.sample +19 -0
- data/examples/atree.rb +100 -0
- data/examples/bline.rb +136 -0
- data/examples/common/file.rb +45 -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 +60 -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 +10 -0
- data/examples/data/todo.txt.bak +10 -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 +502 -0
- data/examples/dirtree.rb +94 -0
- data/examples/newtabbedwindow.rb +100 -0
- data/examples/newtesttabp.rb +92 -0
- data/examples/tabular.rb +146 -0
- data/examples/tasks.rb +178 -0
- data/examples/term2.rb +84 -0
- data/examples/testbuttons.rb +296 -0
- data/examples/testcombo.rb +102 -0
- data/examples/testfields.rb +195 -0
- data/examples/testkeypress.rb +72 -0
- data/examples/testlistbox.rb +170 -0
- data/examples/testmessagebox.rb +140 -0
- data/examples/testprogress.rb +116 -0
- data/examples/testree.rb +106 -0
- data/examples/testwsshortcuts.rb +66 -0
- data/examples/testwsshortcuts2.rb +128 -0
- data/lib/rbhex.rb +6 -0
- data/lib/rbhex/core/docs/index.txt +73 -0
- data/lib/rbhex/core/include/action.rb +80 -0
- data/lib/rbhex/core/include/actionmanager.rb +49 -0
- data/lib/rbhex/core/include/appmethods.rb +214 -0
- data/lib/rbhex/core/include/bordertitle.rb +48 -0
- data/lib/rbhex/core/include/chunk.rb +203 -0
- data/lib/rbhex/core/include/io.rb +553 -0
- data/lib/rbhex/core/include/listbindings.rb +74 -0
- data/lib/rbhex/core/include/listcellrenderer.rb +140 -0
- data/lib/rbhex/core/include/listeditable.rb +317 -0
- data/lib/rbhex/core/include/listscrollable.rb +663 -0
- data/lib/rbhex/core/include/listselectable.rb +271 -0
- data/lib/rbhex/core/include/multibuffer.rb +83 -0
- data/lib/rbhex/core/include/orderedhash.rb +77 -0
- data/lib/rbhex/core/include/ractionevent.rb +73 -0
- data/lib/rbhex/core/include/rchangeevent.rb +27 -0
- data/lib/rbhex/core/include/rhistory.rb +95 -0
- data/lib/rbhex/core/include/rinputdataevent.rb +47 -0
- data/lib/rbhex/core/include/vieditable.rb +172 -0
- data/lib/rbhex/core/include/widgetmenu.rb +66 -0
- data/lib/rbhex/core/system/colormap.rb +165 -0
- data/lib/rbhex/core/system/keyboard.rb +150 -0
- data/lib/rbhex/core/system/keydefs.rb +30 -0
- data/lib/rbhex/core/system/ncurses.rb +236 -0
- data/lib/rbhex/core/system/panel.rb +162 -0
- data/lib/rbhex/core/system/window.rb +913 -0
- data/lib/rbhex/core/util/ansiparser.rb +119 -0
- data/lib/rbhex/core/util/app.rb +1228 -0
- data/lib/rbhex/core/util/basestack.rb +410 -0
- data/lib/rbhex/core/util/bottomline.rb +1859 -0
- data/lib/rbhex/core/util/colorparser.rb +77 -0
- data/lib/rbhex/core/util/focusmanager.rb +31 -0
- data/lib/rbhex/core/util/padreader.rb +192 -0
- data/lib/rbhex/core/util/rcommandwindow.rb +604 -0
- data/lib/rbhex/core/util/rdialogs.rb +574 -0
- data/lib/rbhex/core/util/viewer.rb +149 -0
- data/lib/rbhex/core/util/widgetshortcuts.rb +506 -0
- data/lib/rbhex/core/version.rb +5 -0
- data/lib/rbhex/core/widgets/applicationheader.rb +103 -0
- data/lib/rbhex/core/widgets/box.rb +58 -0
- data/lib/rbhex/core/widgets/divider.rb +310 -0
- data/lib/rbhex/core/widgets/keylabelprinter.rb +194 -0
- data/lib/rbhex/core/widgets/rcombo.rb +253 -0
- data/lib/rbhex/core/widgets/rcontainer.rb +415 -0
- data/lib/rbhex/core/widgets/rlink.rb +30 -0
- data/lib/rbhex/core/widgets/rlist.rb +696 -0
- data/lib/rbhex/core/widgets/rmenu.rb +958 -0
- data/lib/rbhex/core/widgets/rmenulink.rb +22 -0
- data/lib/rbhex/core/widgets/rmessagebox.rb +387 -0
- data/lib/rbhex/core/widgets/rprogress.rb +118 -0
- data/lib/rbhex/core/widgets/rtabbedpane.rb +634 -0
- data/lib/rbhex/core/widgets/rtabbedwindow.rb +70 -0
- data/lib/rbhex/core/widgets/rtextarea.rb +960 -0
- data/lib/rbhex/core/widgets/rtextview.rb +739 -0
- data/lib/rbhex/core/widgets/rtree.rb +768 -0
- data/lib/rbhex/core/widgets/rwidget.rb +3277 -0
- data/lib/rbhex/core/widgets/scrollbar.rb +143 -0
- data/lib/rbhex/core/widgets/statusline.rb +113 -0
- data/lib/rbhex/core/widgets/tabular.rb +264 -0
- data/lib/rbhex/core/widgets/tabularwidget.rb +1142 -0
- data/lib/rbhex/core/widgets/textpad.rb +995 -0
- data/lib/rbhex/core/widgets/tree/treecellrenderer.rb +150 -0
- data/lib/rbhex/core/widgets/tree/treemodel.rb +428 -0
- data/rbhex-core.gemspec +32 -0
- metadata +172 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
require 'rbhex/core/widgets/rtextview'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
|
|
4
|
+
# NOTE: experimental, not yet firmed up
|
|
5
|
+
# If you use in application, please copy to some application folder in case i change this.
|
|
6
|
+
# Can be used for print_help_page
|
|
7
|
+
# TODO: add vi_keys here
|
|
8
|
+
# SUGGESTIONS WELCOME.
|
|
9
|
+
# @since 1.2.0
|
|
10
|
+
module RubyCurses
|
|
11
|
+
# a data viewer for viewing some text or filecontents
|
|
12
|
+
# view filename, :close_key => KEY_ENTER
|
|
13
|
+
# send data in an array
|
|
14
|
+
# view Array, :close_key => KEY_ENTER, :layout => [0,0,23,80]
|
|
15
|
+
# when passing layout reserve 4 rows for window and border. So for 2 lines of text
|
|
16
|
+
# give 6 rows.
|
|
17
|
+
class Viewer
|
|
18
|
+
# @param filename as string or content as array
|
|
19
|
+
# @yield textview object for further configuration before display
|
|
20
|
+
# NOTE: i am experimentally yielding textview object so i could supress borders
|
|
21
|
+
# just for kicks, but on can also bind_keys or events if one wanted.
|
|
22
|
+
def self.view what, config={} #:yield: textview
|
|
23
|
+
case what
|
|
24
|
+
when String # we have a path
|
|
25
|
+
content = _get_contents(what)
|
|
26
|
+
when Array
|
|
27
|
+
content = what
|
|
28
|
+
else
|
|
29
|
+
raise ArgumentError, "Viewer: Expecting Filename or Contents (array), but got #{what.class} "
|
|
30
|
+
end
|
|
31
|
+
wt = 0 # top margin
|
|
32
|
+
wl = 0 # left margin
|
|
33
|
+
wh = Ncurses.LINES-wt # height, goes to bottom of screen
|
|
34
|
+
ww = Ncurses.COLS-wl # width, goes to right end
|
|
35
|
+
wt, wl, wh, ww = config[:layout] if config.has_key? :layout
|
|
36
|
+
|
|
37
|
+
fp = config[:title] || ""
|
|
38
|
+
pf = config.fetch(:print_footer, true)
|
|
39
|
+
ta = config.fetch(:title_attrib, 'bold')
|
|
40
|
+
fa = config.fetch(:footer_attrib, 'bold')
|
|
41
|
+
type = config[:content_type]
|
|
42
|
+
|
|
43
|
+
layout = { :height => wh, :width => ww, :top => wt, :left => wl }
|
|
44
|
+
v_window = VER::Window.new(layout)
|
|
45
|
+
v_form = RubyCurses::Form.new v_window
|
|
46
|
+
colors = Ncurses.COLORS
|
|
47
|
+
back = :blue
|
|
48
|
+
back = 235 if colors >= 256
|
|
49
|
+
blue_white = get_color($datacolor, :white, back)
|
|
50
|
+
#blue_white = RubyCurses::Utils.get_color($datacolor, :white, 235)
|
|
51
|
+
textview = TextView.new v_form do
|
|
52
|
+
name "Viewer"
|
|
53
|
+
row 0
|
|
54
|
+
col 0
|
|
55
|
+
width ww
|
|
56
|
+
height wh-0 # earlier 2 but seems to be leaving space.
|
|
57
|
+
title fp
|
|
58
|
+
title_attrib ta
|
|
59
|
+
print_footer pf
|
|
60
|
+
footer_attrib fa
|
|
61
|
+
#border_attrib :reverse
|
|
62
|
+
border_color blue_white
|
|
63
|
+
end
|
|
64
|
+
require 'rbhex/core/include/multibuffer'
|
|
65
|
+
textview.extend(RubyCurses::MultiBuffers)
|
|
66
|
+
|
|
67
|
+
t = textview
|
|
68
|
+
t.bind_key('<', 'move window left'){ f = t.form.window; c = f.left - 1; f.hide; f.mvwin(f.top, c); f.show;
|
|
69
|
+
f.reset_layout([f.height, f.width, f.top, c]);
|
|
70
|
+
}
|
|
71
|
+
t.bind_key('>', 'move window right'){ f = t.form.window; c = f.left + 1; f.hide; f.mvwin(f.top, c);
|
|
72
|
+
f.reset_layout([f.height, f.width, f.top, c]); f.show;
|
|
73
|
+
}
|
|
74
|
+
t.bind_key('^', 'move window up'){ f = t.form.window; c = f.top - 1 ; f.hide; f.mvwin(c, f.left);
|
|
75
|
+
f.reset_layout([f.height, f.width, c, f.left]) ; f.show;
|
|
76
|
+
}
|
|
77
|
+
t.bind_key('V', 'move window down'){ f = t.form.window; c = f.top + 1 ; f.hide; f.mvwin(c, f.left);
|
|
78
|
+
f.reset_layout([f.height, f.width, c, f.left]); f.show;
|
|
79
|
+
}
|
|
80
|
+
# yielding textview so you may further configure or bind keys or events
|
|
81
|
+
begin
|
|
82
|
+
textview.set_content content, :content_type => type
|
|
83
|
+
textview.add_content content, :content_type => type
|
|
84
|
+
# the next can also be used to use formatted_text(text, :ansi)
|
|
85
|
+
yield textview if block_given?
|
|
86
|
+
v_form.repaint
|
|
87
|
+
v_window.wrefresh
|
|
88
|
+
Ncurses::Panel.update_panels
|
|
89
|
+
# allow closing using q and Ctrl-q in addition to any key specified
|
|
90
|
+
# user should not need to specify key, since that becomes inconsistent across usages
|
|
91
|
+
while((ch = v_window.getchar()) != ?\C-q.getbyte(0) )
|
|
92
|
+
break if ch == config[:close_key] || ch == ?q.ord || ch == 2727 # added double esc 2011-12-27
|
|
93
|
+
# if you've asked for ENTER then i also check for 10 and 13
|
|
94
|
+
break if (ch == 10 || ch == 13) && config[:close_key] == KEY_ENTER
|
|
95
|
+
v_form.handle_key ch
|
|
96
|
+
v_form.repaint
|
|
97
|
+
end
|
|
98
|
+
rescue => err
|
|
99
|
+
$log.error " VIEWER ERROR #{err} "
|
|
100
|
+
$log.debug(err.backtrace.join("\n"))
|
|
101
|
+
textdialog ["Error in viewer: #{err} ", *err.backtrace], :title => "Exception"
|
|
102
|
+
ensure
|
|
103
|
+
v_window.destroy if !v_window.nil?
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
private
|
|
107
|
+
def self._get_contents fp
|
|
108
|
+
return "File #{fp} not readable" unless File.readable? fp
|
|
109
|
+
return Dir.new(fp).entries if File.directory? fp
|
|
110
|
+
case File.extname(fp)
|
|
111
|
+
when '.tgz','.gz'
|
|
112
|
+
cmd = "tar -ztvf #{fp}"
|
|
113
|
+
content = %x[#{cmd}]
|
|
114
|
+
when '.zip'
|
|
115
|
+
cmd = "unzip -l #{fp}"
|
|
116
|
+
content = %x[#{cmd}]
|
|
117
|
+
when '.jar', '.gem'
|
|
118
|
+
cmd = "tar -tvf #{fp}"
|
|
119
|
+
content = %x[#{cmd}]
|
|
120
|
+
when '.png', '.out','.jpg', '.gif','.pdf'
|
|
121
|
+
content = "File #{fp} not displayable"
|
|
122
|
+
when '.sqlite'
|
|
123
|
+
cmd = "sqlite3 #{fp} 'select name from sqlite_master;'"
|
|
124
|
+
content = %x[#{cmd}]
|
|
125
|
+
else
|
|
126
|
+
content = File.open(fp,"r").readlines
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end # class
|
|
130
|
+
|
|
131
|
+
end # module
|
|
132
|
+
if __FILE__ == $PROGRAM_NAME
|
|
133
|
+
require 'rbhex/core/util/app'
|
|
134
|
+
|
|
135
|
+
App.new do
|
|
136
|
+
header = app_header "rbhex 1.2.0", :text_center => "Viewer Demo", :text_right =>"New Improved!", :color => :black, :bgcolor => :white, :attr => :bold
|
|
137
|
+
message "Press F1 to exit from here"
|
|
138
|
+
|
|
139
|
+
RubyCurses::Viewer.view(ARGV[0] || $0, :close_key => KEY_ENTER, :title => "Enter to close") do |t|
|
|
140
|
+
# you may configure textview further here.
|
|
141
|
+
#t.suppress_borders true
|
|
142
|
+
#t.color = :black
|
|
143
|
+
#t.bgcolor = :white
|
|
144
|
+
# or
|
|
145
|
+
#t.attr = :reverse
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
end # app
|
|
149
|
+
end
|
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
# ------------------------------------------------------------ #
|
|
2
|
+
# File: widgetshortcuts.rb
|
|
3
|
+
# Description: A common module for shortcuts to create widgets
|
|
4
|
+
# Also, stacks and flows objects
|
|
5
|
+
# Author: rkumar http://github.com/rkumar/rbcurse/
|
|
6
|
+
# Date: 05.11.11 - 15:13
|
|
7
|
+
# Last update: 2013-03-21 00:55
|
|
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 multirow comps like textview and textarea, list
|
|
16
|
+
# add blocks that make sense like in app
|
|
17
|
+
# - what if user does not want form attached - app uses useform ot
|
|
18
|
+
# to check for this, if current_object don't add form
|
|
19
|
+
#
|
|
20
|
+
# - usage of _position inside means these shortcuts cannot be reused
|
|
21
|
+
# with other positioning systems, we'll be cut-pasting forever
|
|
22
|
+
#
|
|
23
|
+
# == CHANGES
|
|
24
|
+
# ------------------------------------------------------------ #
|
|
25
|
+
#
|
|
26
|
+
|
|
27
|
+
# what is the real purpose of the shortcuts, is it to avoid putting nil
|
|
28
|
+
# for form there if not required.
|
|
29
|
+
# Or is it positioning, such as in a stack. or just a method ?
|
|
30
|
+
require 'rbhex/core/widgets/rlist'
|
|
31
|
+
require 'rbhex/core/widgets/rtextview'
|
|
32
|
+
module RubyCurses
|
|
33
|
+
module WidgetShortcuts
|
|
34
|
+
class Ws
|
|
35
|
+
attr_reader :config
|
|
36
|
+
def initialize config={}
|
|
37
|
+
@config = config
|
|
38
|
+
end
|
|
39
|
+
def [](sym)
|
|
40
|
+
@config[sym]
|
|
41
|
+
end
|
|
42
|
+
def []=(sym, val)
|
|
43
|
+
@config[sym] = val
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
class WsStack < Ws; end
|
|
47
|
+
class WsFlow < Ws; end
|
|
48
|
+
def widget_shortcuts_init
|
|
49
|
+
@_ws_app_row = @_ws_app_col = 0
|
|
50
|
+
#@_ws_active = []
|
|
51
|
+
@_ws_active = nil # so we can use shortcuts if no stack used
|
|
52
|
+
@_ws_components = []
|
|
53
|
+
@variables = {}
|
|
54
|
+
end
|
|
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 rbhex
|
|
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 "rbhex/core/widgets/rprogress", "Progress"
|
|
113
|
+
def_widget "rbhex/core/widgets/scrollbar", "Scrollbar"
|
|
114
|
+
def_widget nil, "Label"
|
|
115
|
+
def_widget nil, "Field"
|
|
116
|
+
def_widget nil, :CheckBox, 'check'
|
|
117
|
+
def_widget nil, :Button
|
|
118
|
+
def_widget nil, :ToggleButton, 'toggle'
|
|
119
|
+
def menubar &block
|
|
120
|
+
require 'rbhex/core/widgets/rmenu'
|
|
121
|
+
RubyCurses::MenuBar.new &block
|
|
122
|
+
end
|
|
123
|
+
def app_header title, config={}, &block
|
|
124
|
+
require 'rbhex/core/widgets/applicationheader'
|
|
125
|
+
header = ApplicationHeader.new @form, title, config, &block
|
|
126
|
+
end
|
|
127
|
+
# editable text area
|
|
128
|
+
def textarea config={}, &block
|
|
129
|
+
require 'rbhex/core/widgets/rtextarea'
|
|
130
|
+
# TODO confirm events many more
|
|
131
|
+
events = [ :CHANGE, :LEAVE, :ENTER ]
|
|
132
|
+
block_event = events[0]
|
|
133
|
+
#_process_args args, config, block_event, events
|
|
134
|
+
#config[:width] = config[:display_length] unless config.has_key? :width
|
|
135
|
+
# if no width given, expand to flows width
|
|
136
|
+
#config[:width] ||= @stack.last.width if @stack.last
|
|
137
|
+
useform = nil
|
|
138
|
+
#useform = @form if @current_object.empty?
|
|
139
|
+
w = TextArea.new useform, config
|
|
140
|
+
w.width = :expand unless w.width
|
|
141
|
+
w.height ||= :expand # TODO This has to come before other in stack next one will overwrite.
|
|
142
|
+
_position(w)
|
|
143
|
+
w.height ||= 8 # TODO
|
|
144
|
+
# need to expand to stack's width or flows itemwidth if given
|
|
145
|
+
if block
|
|
146
|
+
w.bind(block_event, &block)
|
|
147
|
+
end
|
|
148
|
+
return w
|
|
149
|
+
end
|
|
150
|
+
def textview config={}, &block
|
|
151
|
+
events = [ :LEAVE, :ENTER ]
|
|
152
|
+
block_event = events[0]
|
|
153
|
+
#_process_args args, config, block_event, events
|
|
154
|
+
#config[:width] = config[:display_length] unless config.has_key? :width
|
|
155
|
+
# if no width given, expand to flows width
|
|
156
|
+
#config[:width] ||= @stack.last.width if @stack.last
|
|
157
|
+
useform = nil
|
|
158
|
+
#useform = @form if @current_object.empty?
|
|
159
|
+
w = TextView.new useform, config
|
|
160
|
+
w.width = :expand unless w.width
|
|
161
|
+
w.height ||= :expand # TODO This has to come before other in stack next one will overwrite.
|
|
162
|
+
_position(w)
|
|
163
|
+
# need to expand to stack's width or flows itemwidth if given
|
|
164
|
+
if block
|
|
165
|
+
w.bind(block_event, &block)
|
|
166
|
+
end
|
|
167
|
+
return w
|
|
168
|
+
end
|
|
169
|
+
def listbox config={}, &block
|
|
170
|
+
events = [ :PRESS, :ENTER_ROW, :LEAVE, :ENTER ]
|
|
171
|
+
block_event = events[0]
|
|
172
|
+
#_process_args args, config, block_event, events
|
|
173
|
+
#config[:width] = config[:display_length] unless config.has_key? :width
|
|
174
|
+
# if no width given, expand to flows width
|
|
175
|
+
#config[:width] ||= @stack.last.width if @stack.last
|
|
176
|
+
useform = nil
|
|
177
|
+
#useform = @form if @current_object.empty?
|
|
178
|
+
w = List.new useform, config
|
|
179
|
+
w.width = :expand unless w.width
|
|
180
|
+
w.height ||= :expand # TODO We may need to push this before _position so it can be accounted for in stack
|
|
181
|
+
_position(w)
|
|
182
|
+
# need to expand to stack's width or flows itemwidth if given
|
|
183
|
+
if block
|
|
184
|
+
w.bind(block_event, &block)
|
|
185
|
+
end
|
|
186
|
+
return w
|
|
187
|
+
end
|
|
188
|
+
# prints pine-like key labels
|
|
189
|
+
def dock labels, config={}, &block
|
|
190
|
+
require 'rbhex/core/widgets/keylabelprinter'
|
|
191
|
+
klp = RubyCurses::KeyLabelPrinter.new @form, labels, config, &block
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def link config={}, &block
|
|
195
|
+
if config.is_a? String
|
|
196
|
+
_s = config
|
|
197
|
+
config = {}
|
|
198
|
+
config[:text] = _s
|
|
199
|
+
end
|
|
200
|
+
require 'rbhex/core/widgets/rlink'
|
|
201
|
+
events = [ :PRESS, :LEAVE, :ENTER ]
|
|
202
|
+
block_event = :PRESS
|
|
203
|
+
config[:highlight_foreground] = "yellow"
|
|
204
|
+
config[:highlight_background] = "red"
|
|
205
|
+
toggle = Link.new nil, config
|
|
206
|
+
_position(toggle)
|
|
207
|
+
if block
|
|
208
|
+
toggle.bind(block_event, toggle, &block)
|
|
209
|
+
end
|
|
210
|
+
return toggle
|
|
211
|
+
end
|
|
212
|
+
def menulink config={}, &block
|
|
213
|
+
if config.is_a? String
|
|
214
|
+
_s = config
|
|
215
|
+
config = {}
|
|
216
|
+
config[:text] = _s
|
|
217
|
+
end
|
|
218
|
+
require 'rbhex/core/widgets/rmenulink'
|
|
219
|
+
events = [ :PRESS, :LEAVE, :ENTER ]
|
|
220
|
+
block_event = :PRESS
|
|
221
|
+
config[:highlight_foreground] = "yellow"
|
|
222
|
+
config[:highlight_background] = "red"
|
|
223
|
+
#config[:hotkey] = true
|
|
224
|
+
w = MenuLink.new nil, config
|
|
225
|
+
_position(w)
|
|
226
|
+
if block
|
|
227
|
+
w.bind(block_event, w, &block)
|
|
228
|
+
end
|
|
229
|
+
return w
|
|
230
|
+
end
|
|
231
|
+
def tree config={}, &block
|
|
232
|
+
require 'rbhex/core/widgets/rtree'
|
|
233
|
+
events = [:TREE_WILL_EXPAND_EVENT, :TREE_EXPANDED_EVENT, :TREE_SELECTION_EVENT, :PROPERTY_CHANGE, :LEAVE, :ENTER ]
|
|
234
|
+
block_event = nil
|
|
235
|
+
#config[:height] ||= 10
|
|
236
|
+
# if no width given, expand to flows width
|
|
237
|
+
useform = nil
|
|
238
|
+
#useform = @form if @current_object.empty?
|
|
239
|
+
w = Tree.new useform, config, &block
|
|
240
|
+
w.width ||= :expand
|
|
241
|
+
w.height ||= :expand # TODO This has to come before other in stack next one will overwrite.
|
|
242
|
+
_position w
|
|
243
|
+
return w
|
|
244
|
+
end
|
|
245
|
+
# creates a simple readonly table, that allows users to click on rows
|
|
246
|
+
# and also on the header. Header clicking is for column-sorting.
|
|
247
|
+
def tabular_widget config={}, &block
|
|
248
|
+
require 'rbhex/core/widgets/tabularwidget'
|
|
249
|
+
events = [:PROPERTY_CHANGE, :LEAVE, :ENTER, :CHANGE, :ENTER_ROW, :PRESS ]
|
|
250
|
+
block_event = nil
|
|
251
|
+
# if no width given, expand to stack width
|
|
252
|
+
#config.delete :title
|
|
253
|
+
useform = nil
|
|
254
|
+
|
|
255
|
+
w = TabularWidget.new useform, config # NO BLOCK GIVEN
|
|
256
|
+
w.width ||= :expand
|
|
257
|
+
w.height ||= :expand # TODO This has to come before other in stack next one will overwrite.
|
|
258
|
+
_position(w)
|
|
259
|
+
if block_given?
|
|
260
|
+
#@current_object << w
|
|
261
|
+
yield_or_eval &block
|
|
262
|
+
#@current_object.pop
|
|
263
|
+
end
|
|
264
|
+
return w
|
|
265
|
+
end
|
|
266
|
+
alias :table :tabular_widget
|
|
267
|
+
# NOTE UNTESTED
|
|
268
|
+
def vimsplit config={}, &block
|
|
269
|
+
require 'rbhex/extras/widgets/rvimsplit'
|
|
270
|
+
#TODO check these
|
|
271
|
+
events = [:PROPERTY_CHANGE, :LEAVE, :ENTER ]
|
|
272
|
+
block_event = nil
|
|
273
|
+
config[:height] ||= 10
|
|
274
|
+
# if no width given, expand to flows width
|
|
275
|
+
#config.delete :title
|
|
276
|
+
useform = nil
|
|
277
|
+
|
|
278
|
+
w = VimSplit.new useform, config # NO BLOCK GIVEN
|
|
279
|
+
_position(w)
|
|
280
|
+
if block_given?
|
|
281
|
+
#@current_object << w
|
|
282
|
+
#instance_eval &block if block_given?
|
|
283
|
+
yield w
|
|
284
|
+
#@current_object.pop
|
|
285
|
+
end
|
|
286
|
+
return w
|
|
287
|
+
end
|
|
288
|
+
def _position w
|
|
289
|
+
if @_ws_active.nil? || @_ws_active.empty?
|
|
290
|
+
# no stack or flow, this is independent usage, or else we are outside stacks and flows
|
|
291
|
+
#
|
|
292
|
+
# this is outside any stack or flow, so we do the minimal
|
|
293
|
+
# user should specify row and col
|
|
294
|
+
w.row ||= 0
|
|
295
|
+
w.col ||= 0
|
|
296
|
+
#$log.debug "XXX: LABEL #{w.row} , #{w.col} "
|
|
297
|
+
w.set_form @form if @form # temporary,, only set if not inside an object FIXME
|
|
298
|
+
if w.width == :expand # calculate from current col, not 0 FIXME
|
|
299
|
+
w.width = FFI::NCurses.COLS-w.col # or take windows width since this could be in a message box
|
|
300
|
+
end
|
|
301
|
+
if w.height == :expand
|
|
302
|
+
# take from current row, and not zero FIXME
|
|
303
|
+
w.height = FFI::NCurses.LINES-w.row # or take windows width since this could be in a message box
|
|
304
|
+
end
|
|
305
|
+
return
|
|
306
|
+
|
|
307
|
+
end
|
|
308
|
+
# -------------------------- there is a stack or flow -------------------- #
|
|
309
|
+
#
|
|
310
|
+
cur = @_ws_active.last
|
|
311
|
+
unless cur
|
|
312
|
+
raise "This should have been handled previously.Somethings wrong, check/untested"
|
|
313
|
+
end
|
|
314
|
+
r = cur[:row] || 0
|
|
315
|
+
c = cur[:col] || 0
|
|
316
|
+
w.row = r
|
|
317
|
+
w.col = c
|
|
318
|
+
# if flow then take flows height, else use dummy value
|
|
319
|
+
if w.height_pc
|
|
320
|
+
w.height = ( (cur[:height] * w.height_pc.to_i)/100).floor
|
|
321
|
+
end
|
|
322
|
+
if w.height == :expand
|
|
323
|
+
if cur.is_a? WsFlow
|
|
324
|
+
w.height = cur[:height] || 8 #or raise "height not known for flow"
|
|
325
|
+
else
|
|
326
|
+
w.height = cur[:item_height] || 8 #or raise "height not known for flow"
|
|
327
|
+
end
|
|
328
|
+
#alert "setting ht to #{w.height}, #{cur[:height]} , for #{cur} "
|
|
329
|
+
end
|
|
330
|
+
if w.width == :expand
|
|
331
|
+
if cur.is_a? WsFlow
|
|
332
|
+
if cur[:item_width]
|
|
333
|
+
w.width = cur[:item_width] #or raise "item_Width not known for flow #{cur.class}, #{cur[:item_width]}, #{cur[:width]} , #{w.width_pc} "
|
|
334
|
+
elsif w.width_pc
|
|
335
|
+
#w.width = w.width_pc * cur[:width]
|
|
336
|
+
w.width = (cur[:width] * (w.width_pc.to_i * 0.01)).floor
|
|
337
|
+
else
|
|
338
|
+
w.width = cur[:width]
|
|
339
|
+
end
|
|
340
|
+
raise "width could not be calculated. i need flow width and item width_pc" if w.width == :expand
|
|
341
|
+
else
|
|
342
|
+
w.width = cur[:width] or raise "Width not known for stack #{cur.class}, #{cur[:width]} "
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
if cur.is_a? WsStack
|
|
346
|
+
r += w.height || 1 # NOTE, we need to have height for this purpose defined BEFORE calling for list/text
|
|
347
|
+
cur[:row] = r
|
|
348
|
+
else
|
|
349
|
+
wid = cur[:item_width] || w.width || 10
|
|
350
|
+
c += wid + 1
|
|
351
|
+
cur[:col] = c
|
|
352
|
+
end
|
|
353
|
+
#alert "set width to #{w.width} ,cur: #{cur[:width]} ,iw: #{cur[:item_width]} "
|
|
354
|
+
if cur.is_a? WsFlow
|
|
355
|
+
unless w.height
|
|
356
|
+
w.height = cur[:height] #or raise "Height not known for flow"
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
w.color ||= cur[:color]
|
|
360
|
+
w.bgcolor ||= cur[:bgcolor]
|
|
361
|
+
w.set_form @form if @form # temporary
|
|
362
|
+
@_ws_components << w
|
|
363
|
+
cur[:components] << w
|
|
364
|
+
end
|
|
365
|
+
# make it as simple as possible, don't try to be intelligent or
|
|
366
|
+
# clever, put as much on the user
|
|
367
|
+
def stack config={}, &block
|
|
368
|
+
s = WsStack.new config
|
|
369
|
+
@_ws_active ||= []
|
|
370
|
+
_configure s
|
|
371
|
+
@_ws_active << s
|
|
372
|
+
yield_or_eval &block if block_given?
|
|
373
|
+
@_ws_active.pop
|
|
374
|
+
|
|
375
|
+
# ---- stack is finished now
|
|
376
|
+
last = @_ws_active.last
|
|
377
|
+
if last
|
|
378
|
+
case last
|
|
379
|
+
when WsStack
|
|
380
|
+
when WsFlow
|
|
381
|
+
last[:col] += last[:item_width] || 0
|
|
382
|
+
# this tries to set height of outer flow based on highest row
|
|
383
|
+
# printed, however that does not account for height of object,
|
|
384
|
+
# so user should give a height to the flow.
|
|
385
|
+
last[:height] = s[:row] if s[:row] > (last[:height]||0)
|
|
386
|
+
$log.debug "XXX: STACK setting col to #{s[:col]} "
|
|
387
|
+
end
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
end
|
|
391
|
+
#
|
|
392
|
+
# item_width - width to use per item
|
|
393
|
+
# but the item width may apply to stacks inside not to items
|
|
394
|
+
def flow config={}, &block
|
|
395
|
+
s = WsFlow.new config
|
|
396
|
+
@_ws_active ||= []
|
|
397
|
+
_configure s
|
|
398
|
+
@_ws_active << s
|
|
399
|
+
yield_or_eval &block if block_given?
|
|
400
|
+
@_ws_active.pop
|
|
401
|
+
last = @_ws_active.last
|
|
402
|
+
if last
|
|
403
|
+
case last
|
|
404
|
+
when WsStack
|
|
405
|
+
if s[:height]
|
|
406
|
+
last[:row] += s[:height]
|
|
407
|
+
else
|
|
408
|
+
#last[:row] += last[:highest_row]
|
|
409
|
+
last[:row] += 1
|
|
410
|
+
end
|
|
411
|
+
when WsFlow
|
|
412
|
+
last[:col] += last[:item_width] || 0
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
end
|
|
416
|
+
# flow and stack could have a border option
|
|
417
|
+
# NOTE: box takes one row below too, so :expand overwrites that line
|
|
418
|
+
def box config={}, &block
|
|
419
|
+
require 'rbhex/core/widgets/box'
|
|
420
|
+
# take current stacks row and col
|
|
421
|
+
# advance row by one and col by one
|
|
422
|
+
# at end note row and advance by one
|
|
423
|
+
# draw a box around using these coordinates. width should be
|
|
424
|
+
# provided unless we have item width or something.
|
|
425
|
+
@_ws_active ||= []
|
|
426
|
+
last = @_ws_active.last
|
|
427
|
+
if last
|
|
428
|
+
r = last[:row]
|
|
429
|
+
c = last[:col]
|
|
430
|
+
config[:row] = r
|
|
431
|
+
config[:col] = c
|
|
432
|
+
last[:row] += config[:margin_top] || 1
|
|
433
|
+
last[:col] += config[:margin_left] || 1
|
|
434
|
+
_box = Box.new @form, config # needs to be created first or will overwrite area after others painted
|
|
435
|
+
yield_or_eval &block if block_given?
|
|
436
|
+
# FIXME last[height] needs to account for row
|
|
437
|
+
h = config[:height] || last[:height] || (last[:row] - r)
|
|
438
|
+
h = 2 if h < 2
|
|
439
|
+
w = config[:width] || last[:width] || 15 # tmp
|
|
440
|
+
case last
|
|
441
|
+
when WsFlow
|
|
442
|
+
w = last[:col]
|
|
443
|
+
when WsStack
|
|
444
|
+
#h += 1
|
|
445
|
+
end
|
|
446
|
+
config[:row] = r
|
|
447
|
+
config[:col] = c
|
|
448
|
+
config[:height] = h
|
|
449
|
+
config[:width] = w
|
|
450
|
+
_box.row r
|
|
451
|
+
_box.col c
|
|
452
|
+
_box.height h
|
|
453
|
+
_box.width w
|
|
454
|
+
last[:row] += 1
|
|
455
|
+
last[:col] += 1 # ??? XXX if flow we need to increment properly or not ?
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
# This configures a stack or flow not the objects inside
|
|
460
|
+
def _configure s
|
|
461
|
+
s[:row] ||= 0
|
|
462
|
+
s[:col] ||= 0
|
|
463
|
+
s[:row] += (s[:margin_top] || 0)
|
|
464
|
+
s[:col] += (s[:margin_left] || 0)
|
|
465
|
+
s[:width] = FFI::NCurses.COLS-s[:col] if s[:width] == :expand
|
|
466
|
+
s[:height] = FFI::NCurses.LINES-s[:row] if s[:height] == :expand # 2011-11-30
|
|
467
|
+
last = @_ws_active.last
|
|
468
|
+
if last
|
|
469
|
+
if s[:width_pc]
|
|
470
|
+
if last.is_a? WsStack
|
|
471
|
+
s[:width] = (last[:width] * (s[:width_pc].to_i * 0.01)).floor
|
|
472
|
+
else
|
|
473
|
+
# i think this width is picked up by next stack in this flow
|
|
474
|
+
last[:item_width] = (last[:width] * (s[:width_pc].to_i* 0.01)).floor
|
|
475
|
+
end
|
|
476
|
+
end
|
|
477
|
+
if s[:height_pc]
|
|
478
|
+
if last.is_a? WsFlow
|
|
479
|
+
s[:height] = ( (last[:height] * s[:height_pc].to_i)/100).floor
|
|
480
|
+
else
|
|
481
|
+
# this works only for flows within stacks not for an object unless
|
|
482
|
+
# you put a single object in a flow
|
|
483
|
+
s[:item_height] = ( (last[:height] * s[:height_pc].to_i)/100).floor
|
|
484
|
+
end
|
|
485
|
+
#alert "item height set as #{s[:height]} for #{s} "
|
|
486
|
+
end
|
|
487
|
+
if last.is_a? WsStack
|
|
488
|
+
s[:row] += (last[:row] || 0)
|
|
489
|
+
s[:col] += (last[:col] || 0)
|
|
490
|
+
else
|
|
491
|
+
s[:row] += (last[:row] || 0)
|
|
492
|
+
s[:col] += (last[:col] || 0) # we are updating with item_width as each st finishes
|
|
493
|
+
s[:width] ||= last[:item_width] #
|
|
494
|
+
end
|
|
495
|
+
else
|
|
496
|
+
# this should be outer most flow or stack, if nothing mentioned
|
|
497
|
+
# trying this out
|
|
498
|
+
s[:width] ||= :expand
|
|
499
|
+
s[:height] ||= :expand
|
|
500
|
+
s[:width] = FFI::NCurses.COLS-s[:col] if s[:width] == :expand
|
|
501
|
+
s[:height] = FFI::NCurses.LINES-s[:row] if s[:height] == :expand # 2011-11-30
|
|
502
|
+
end
|
|
503
|
+
s[:components] = []
|
|
504
|
+
end
|
|
505
|
+
end
|
|
506
|
+
end
|