canis 0.0.4
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 +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
|