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,129 @@
|
|
|
1
|
+
require "ffi-ncurses"
|
|
2
|
+
module Ncurses # changed on 2011-09-8
|
|
3
|
+
# making minimal changes as per ffi-ncurses 0.4.0 which implements panels
|
|
4
|
+
#module Canis # too many places call Ncurses::Panel
|
|
5
|
+
class Panel #< Struct.new(:pointer)
|
|
6
|
+
|
|
7
|
+
def initialize(window)
|
|
8
|
+
if window.respond_to?(:pointer)
|
|
9
|
+
@pointer = FFI::NCurses.new_panel(window.pointer)
|
|
10
|
+
else
|
|
11
|
+
@pointer = FFI::NCurses.new_panel(window)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
def pointer
|
|
15
|
+
@pointer
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Puts panel below all other panels.
|
|
19
|
+
def bottom_panel
|
|
20
|
+
FFI::NCurses.bottom_panel(@pointer)
|
|
21
|
+
end
|
|
22
|
+
alias bottom bottom_panel
|
|
23
|
+
|
|
24
|
+
# Put the visible panel on top of all other panels in the stack.
|
|
25
|
+
#
|
|
26
|
+
# To ensure compatibility across platforms, use this method instead of
|
|
27
|
+
# {show_panel} when the panel is shown.
|
|
28
|
+
def top_panel
|
|
29
|
+
FFI::NCurses.top_panel(@pointer)
|
|
30
|
+
end
|
|
31
|
+
alias top top_panel
|
|
32
|
+
|
|
33
|
+
# Makes hidden panel visible by placing it on the top of the stack.
|
|
34
|
+
#
|
|
35
|
+
# To ensure compatibility across platforms, use this method instead of
|
|
36
|
+
# {top_panel} when the panel is hidden.
|
|
37
|
+
def show_panel
|
|
38
|
+
FFI::NCurses.show_panel(@pointer)
|
|
39
|
+
end
|
|
40
|
+
alias show show_panel
|
|
41
|
+
|
|
42
|
+
# Removes the given panel from the panel stack and thus hides it from
|
|
43
|
+
# view.
|
|
44
|
+
# The PANEL structure is not lost, merely removed from the stack.
|
|
45
|
+
def hide_panel
|
|
46
|
+
FFI::NCurses.hide_panel(@pointer)
|
|
47
|
+
end
|
|
48
|
+
alias hide hide_panel
|
|
49
|
+
|
|
50
|
+
# Returns a pointer to the window of the given panel.
|
|
51
|
+
def panel_window
|
|
52
|
+
FFI::NCurses.panel_window(@pointer)
|
|
53
|
+
end
|
|
54
|
+
alias window panel_window
|
|
55
|
+
|
|
56
|
+
# Replace the window of the panel with the given window.
|
|
57
|
+
# Useful, for example, if you want to resize a panel.
|
|
58
|
+
# You can call {replace_panel} on the output of {wresize}.
|
|
59
|
+
# It does not change the position of the panel in the stack.
|
|
60
|
+
def replace_panel(window)
|
|
61
|
+
FFI::NCurses.replace_panel(@pointer, window)
|
|
62
|
+
end
|
|
63
|
+
alias replace replace_panel
|
|
64
|
+
|
|
65
|
+
# Move the panel window so that its upper-left corner is at
|
|
66
|
+
# (+starty+,+startx+).
|
|
67
|
+
# It does not change the position of the panel in the stack.
|
|
68
|
+
# Be sure to use this method instead of {mvwin}, to move a panel window.
|
|
69
|
+
def move_panel(starty = 0, startx = 0)
|
|
70
|
+
FFI::NCurses.move_panel(@pointer, starty, startx)
|
|
71
|
+
end
|
|
72
|
+
alias move move_panel
|
|
73
|
+
|
|
74
|
+
# Returns true if the panel is in the panel stack, false if not.
|
|
75
|
+
# Returns ERR if the panel pointer is a null pointer.
|
|
76
|
+
def panel_hidden
|
|
77
|
+
FFI::NCurses.panel_hidden(@pointer) == 0
|
|
78
|
+
end
|
|
79
|
+
alias hidden? panel_hidden
|
|
80
|
+
|
|
81
|
+
# Returns pointer to the panel above.
|
|
82
|
+
def panel_above
|
|
83
|
+
FFI::NCurses.panel_above(@pointer)
|
|
84
|
+
end
|
|
85
|
+
alias above panel_above
|
|
86
|
+
|
|
87
|
+
# Return a pointer to the panel just below panel.
|
|
88
|
+
# If the panel argument is a pointer to 0, it returns a pointer to the
|
|
89
|
+
# top panel in the stack.
|
|
90
|
+
def panel_below
|
|
91
|
+
FFI::NCurses.panel_below(@pointer)
|
|
92
|
+
end
|
|
93
|
+
alias below panel_below
|
|
94
|
+
|
|
95
|
+
# Returns the user pointer for a given panel.
|
|
96
|
+
def panel_userptr
|
|
97
|
+
FFI::NCurses.panel_userptr(@pointer)
|
|
98
|
+
end
|
|
99
|
+
alias userptr panel_userptr
|
|
100
|
+
|
|
101
|
+
# sets the panel's user pointer.
|
|
102
|
+
def set_panel_userptr(user_pointer)
|
|
103
|
+
FFI::NCurses.set_panel_userptr(@pointer, user_pointer)
|
|
104
|
+
end
|
|
105
|
+
alias userptr= set_panel_userptr
|
|
106
|
+
|
|
107
|
+
# Remove the panel from the stack and deallocate the PANEL structure.
|
|
108
|
+
# Doesn't remove the associated window.
|
|
109
|
+
def del_panel
|
|
110
|
+
FFI::NCurses.del_panel(@pointer)
|
|
111
|
+
end
|
|
112
|
+
alias del del_panel
|
|
113
|
+
alias delete del_panel
|
|
114
|
+
|
|
115
|
+
class << self
|
|
116
|
+
# these will be used when you say Ncurses::Panel.del_panel(@panel.pointer)
|
|
117
|
+
# You could directly say FFI:NCurses or even @panel.del_panel.
|
|
118
|
+
def update_panels
|
|
119
|
+
FFI::NCurses.update_panels
|
|
120
|
+
end
|
|
121
|
+
def method_missing(name, *args)
|
|
122
|
+
if (FFI::NCurses.respond_to?(name))
|
|
123
|
+
return FFI::NCurses.send(name, *args)
|
|
124
|
+
end
|
|
125
|
+
raise "Panel did not respond_to #{name} "
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -0,0 +1,1081 @@
|
|
|
1
|
+
# ----------------------------------------------------------------------------- #
|
|
2
|
+
# File: window.rb
|
|
3
|
+
# Description: A wrapper over window
|
|
4
|
+
# Author: jkepler http://github.com/mare-imbrium/canis/
|
|
5
|
+
# Date: Around for a long time
|
|
6
|
+
# License: Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
|
|
7
|
+
# Last update: 2014-07-10 00:13
|
|
8
|
+
#
|
|
9
|
+
# == CHANGED
|
|
10
|
+
# removed dead or redudant code - 2014-04-22 - 12:53
|
|
11
|
+
# - replaced getchar with new simpler one - 2014-05-04
|
|
12
|
+
# - introduced key_tos to replace keycode_tos, moved to Util in rwidget.rb
|
|
13
|
+
# - reintroduced nedelay and reduced escdelay
|
|
14
|
+
#
|
|
15
|
+
# == TODO
|
|
16
|
+
# strip and remove cruft. Several methods marked as deprecated.
|
|
17
|
+
# ----------------------------------------------------------------------------- #
|
|
18
|
+
#
|
|
19
|
+
require 'canis/core/system/ncurses'
|
|
20
|
+
require 'canis/core/system/panel'
|
|
21
|
+
# this is since often windows are declared with 0 height or width and this causes
|
|
22
|
+
# crashes in the most unlikely places. This prevceents me from having to write ternary
|
|
23
|
+
# e.g.
|
|
24
|
+
# @layout[:width].ifzero(FFI::NCurses::LINES-2)
|
|
25
|
+
class Fixnum
|
|
26
|
+
def ifzero v
|
|
27
|
+
return self if self != 0
|
|
28
|
+
return v
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
# This class is to be extended so that it can be called by anyone wanting to implement
|
|
32
|
+
# chunks ot text with color and attributes. Chunkline consists of multiple chunks of colored text
|
|
33
|
+
# and should implement a +each_with_color+.
|
|
34
|
+
# The purpose of adding this is so that +chunk.rb+ does not need to be required if colored text
|
|
35
|
+
# is not being used by an application.
|
|
36
|
+
class AbstractChunkLine; end
|
|
37
|
+
|
|
38
|
+
module Canis
|
|
39
|
+
class Window
|
|
40
|
+
attr_reader :width, :height, :top, :left
|
|
41
|
+
attr_accessor :layout # hash containing hwtl
|
|
42
|
+
attr_reader :panel # reader requires so he can del it in end
|
|
43
|
+
attr_accessor :name # more for debugging log files. 2010-02-02 19:58
|
|
44
|
+
#attr_accessor :modified # has it been modified and may need a refresh 2014-04-22 - 10:23 CLEANUP
|
|
45
|
+
# for root windows we need to know the form so we can ask it to update when
|
|
46
|
+
# there are overlapping windows.
|
|
47
|
+
attr_accessor :form
|
|
48
|
+
|
|
49
|
+
# creation and layout related {{{
|
|
50
|
+
# @param [Array, Hash] window coordinates (ht, w, top, left)
|
|
51
|
+
# or
|
|
52
|
+
# @param [int, int, int, int] window coordinates (ht, w, top, left)
|
|
53
|
+
# 2011-09-21 allowing array, or 4 ints, in addition to hash @since 1.3.1
|
|
54
|
+
def initialize(*args)
|
|
55
|
+
|
|
56
|
+
case args.size
|
|
57
|
+
when 1
|
|
58
|
+
case args[0]
|
|
59
|
+
when Array, Hash
|
|
60
|
+
layout = args[0]
|
|
61
|
+
else
|
|
62
|
+
raise ArgumentError, "Window expects 4 ints, array of 4 ints, or Hash in constructor"
|
|
63
|
+
end
|
|
64
|
+
when 4
|
|
65
|
+
layout = { :height => args[0], :width => args[1], :top => args[2], :left => args[3] }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
@visible = true
|
|
69
|
+
set_layout(layout)
|
|
70
|
+
|
|
71
|
+
#$log.debug "XXX:WINDOW got h #{@height}, w #{@width}, t #{@top}, l #{@left} "
|
|
72
|
+
|
|
73
|
+
@height = FFI::NCurses.LINES if @height == 0 # 2011-11-14 added since tired of checking for zero
|
|
74
|
+
@width = FFI::NCurses.COLS if @width == 0
|
|
75
|
+
|
|
76
|
+
@window = FFI::NCurses.newwin(@height, @width, @top, @left) # added FFI 2011-09-6
|
|
77
|
+
# trying out refreshing underlying window.
|
|
78
|
+
$global_windows ||= []
|
|
79
|
+
# this causes issues padrefresh failing when display_list does a resize.
|
|
80
|
+
#$global_windows << self
|
|
81
|
+
@panel = Ncurses::Panel.new(@window) # added FFI 2011-09-6
|
|
82
|
+
#$error_message_row = $status_message_row = Ncurses.LINES-1
|
|
83
|
+
$error_message_row ||= Ncurses.LINES-1
|
|
84
|
+
$error_message_col ||= 1 # ask (bottomline) uses 0 as default so you can have mismatch. XXX
|
|
85
|
+
$status_message ||= Canis::Variable.new # in case not an App
|
|
86
|
+
|
|
87
|
+
# 2014-05-07 - 12:29 CANIS earlier this was called $key_map but that suggests a map.
|
|
88
|
+
$key_map_type ||= :vim
|
|
89
|
+
$esc_esc = true; # gove me double esc as 2727 so i can map it.
|
|
90
|
+
init_vars
|
|
91
|
+
|
|
92
|
+
unless @key_reader
|
|
93
|
+
create_default_key_reader
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
end
|
|
98
|
+
def init_vars
|
|
99
|
+
Ncurses::keypad(@window, true)
|
|
100
|
+
# Added this so we can get Esc, and also C-c pressed in succession does not crash system
|
|
101
|
+
# 2011-12-20 half-delay crashes system as does cbreak
|
|
102
|
+
#This causes us to be unable to process gg qq since getch won't wait.
|
|
103
|
+
#FFI::NCurses::nodelay(@window, bf = true)
|
|
104
|
+
# wtimeout was causing RESIZE sigwinch to only happen after pressing a key
|
|
105
|
+
#Ncurses::wtimeout(@window, $ncurses_timeout || 500) # will wait a second on wgetch so we can get gg and qq
|
|
106
|
+
#@stack = [] # since we have moved to handler 2014-04-20 - 11:15
|
|
107
|
+
@name ||="#{self}"
|
|
108
|
+
@modified = true
|
|
109
|
+
$catch_alt_digits ||= false # is this where is should put globals ? 2010-03-14 14:00 XXX
|
|
110
|
+
end
|
|
111
|
+
##
|
|
112
|
+
# this is an alternative constructor
|
|
113
|
+
def self.root_window(layout = { :height => 0, :width => 0, :top => 0, :left => 0 })
|
|
114
|
+
|
|
115
|
+
@layout = layout
|
|
116
|
+
@window = Window.new(@layout)
|
|
117
|
+
@window.name = "Window::ROOTW:#{$global_windows.count}"
|
|
118
|
+
@window.wrefresh
|
|
119
|
+
Ncurses::Panel.update_panels
|
|
120
|
+
# earlier we only put root window, now we may need to do all (bline - numbered menu - alert)
|
|
121
|
+
$global_windows << @window unless $global_windows.include? @window
|
|
122
|
+
return @window
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# This refreshes the root window whenever overlapping windows are
|
|
126
|
+
# destroyed or moved.
|
|
127
|
+
# This works by asking the root window's form to repaint all its objects.
|
|
128
|
+
# This is now being called whenever a window is destroyed (and also resized).
|
|
129
|
+
# However, it must
|
|
130
|
+
# manually be called if you move a window.
|
|
131
|
+
# NOTE : if there are too many root windows, this could get expensive since we are updating all.
|
|
132
|
+
# We may need to have a way to specify which window to repaint.
|
|
133
|
+
# If there are non-root windows above, we may have manually refresh only the previous one.
|
|
134
|
+
#
|
|
135
|
+
def self.refresh_all current_win=nil
|
|
136
|
+
#Ncurses.touchwin(FFI::NCurses.stdscr)
|
|
137
|
+
# above blanks out entire screen
|
|
138
|
+
# in case of multiple root windows lets just do last otherwise too much refreshing.
|
|
139
|
+
gw = $global_windows
|
|
140
|
+
if current_win
|
|
141
|
+
gw = $global_windows.select {|e| e != current_win }
|
|
142
|
+
end
|
|
143
|
+
return unless gw.last
|
|
144
|
+
wins = [ gw.last ]
|
|
145
|
+
wins.each_with_index do |w,i|
|
|
146
|
+
$log.debug " REFRESH_ALL on #{w.name} (#{i}) sending 1000"
|
|
147
|
+
# NOTE 2014-05-01 - 20:25 although we have reached the root window from any level
|
|
148
|
+
# however, this is sending the hack to whoever is trapping the key, which in our current
|
|
149
|
+
# case happends to be Viewer, *not* the root form. We need to send to root form.
|
|
150
|
+
f = w.form
|
|
151
|
+
if f
|
|
152
|
+
# send hack to root windows form if passed.
|
|
153
|
+
f.handle_key 1000
|
|
154
|
+
end
|
|
155
|
+
#w.ungetch(1000)
|
|
156
|
+
# below blanks out entire screen too
|
|
157
|
+
#FFI::NCurses.touchwin(w.get_window)
|
|
158
|
+
#$log.debug "XXX: refreshall diong window "
|
|
159
|
+
#w.hide
|
|
160
|
+
#w.show
|
|
161
|
+
#Ncurses.refresh
|
|
162
|
+
#w.wrefresh
|
|
163
|
+
end
|
|
164
|
+
#Ncurses::Panel.update_panels
|
|
165
|
+
end
|
|
166
|
+
# 2009-10-13 12:24
|
|
167
|
+
# not used as yet
|
|
168
|
+
# this is an alternative constructor
|
|
169
|
+
# created if you don't want to create a hash first
|
|
170
|
+
# 2011-09-21 V1.3.1 You can now send an array to Window constructor
|
|
171
|
+
def self.create_window(h=0, w=0, t=0, l=0)
|
|
172
|
+
layout = { :height => h, :width => w, :top => t, :left => l }
|
|
173
|
+
@window = Window.new(layout)
|
|
174
|
+
return @window
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def resize_with(layout)
|
|
178
|
+
#$log.debug " DARN ! This awready duz a resize!! if h or w or even top or left changed!!! XXX"
|
|
179
|
+
set_layout(layout)
|
|
180
|
+
$log.debug " resize after set_layout: #{@height} , #{@width} , #{@top} , #{@left}, "
|
|
181
|
+
wresize(height, width)
|
|
182
|
+
mvwin(top, left)
|
|
183
|
+
Window.refresh_all self
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
%w[width height top left].each do |side|
|
|
187
|
+
eval(
|
|
188
|
+
"def #{side}=(n)
|
|
189
|
+
return if n == #{side}
|
|
190
|
+
@layout[:#{side}] = n
|
|
191
|
+
resize_with @layout
|
|
192
|
+
end"
|
|
193
|
+
)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
##
|
|
197
|
+
# Creating variables case of array, we still create the hash
|
|
198
|
+
# @param array or hash containing h w t and l
|
|
199
|
+
def set_layout(layout)
|
|
200
|
+
case layout
|
|
201
|
+
when Array
|
|
202
|
+
$log.error "NIL in window constructor" if layout.include? nil
|
|
203
|
+
raise ArgumentError, "Nil in window constructor" if layout.include? nil
|
|
204
|
+
# NOTE this is just setting, and not replacing zero with max values
|
|
205
|
+
@height, @width, @top, @left = *layout
|
|
206
|
+
raise ArgumentError, "Nil in window constructor" if @top.nil? || @left.nil?
|
|
207
|
+
|
|
208
|
+
@layout = { :height => @height, :width => @width, :top => @top, :left => @left }
|
|
209
|
+
when Hash
|
|
210
|
+
@layout = layout
|
|
211
|
+
|
|
212
|
+
[:height, :width, :top, :left].each do |name|
|
|
213
|
+
instance_variable_set("@#{name}", @layout[name])
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
# --- layout and creation related }}}
|
|
218
|
+
|
|
219
|
+
# ADDED DUE TO FFI
|
|
220
|
+
def wrefresh
|
|
221
|
+
Ncurses.wrefresh(@window)
|
|
222
|
+
end
|
|
223
|
+
def delwin # 2011-09-7
|
|
224
|
+
Ncurses.delwin(@window)
|
|
225
|
+
end
|
|
226
|
+
def attron *args
|
|
227
|
+
FFI::NCurses.wattron @window, *args
|
|
228
|
+
end
|
|
229
|
+
def attroff *args
|
|
230
|
+
FFI::NCurses.wattroff @window, *args
|
|
231
|
+
end
|
|
232
|
+
#
|
|
233
|
+
# ## END FFI
|
|
234
|
+
|
|
235
|
+
def resize
|
|
236
|
+
resize_with(@layout)
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Ncurses
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def x=(n) move(y, n) end
|
|
243
|
+
def y=(n) move(n, x) end
|
|
244
|
+
|
|
245
|
+
#def move(y, x)
|
|
246
|
+
#return unless @visible
|
|
247
|
+
## Log.debug([y, x] => caller[0,4])
|
|
248
|
+
##@window.wmove(y, x) # bombing since ffi-ncurses 0.4.0 (maybe it was never called
|
|
249
|
+
##earlier. was crashing in appemail.rb testchoose.
|
|
250
|
+
#wmove y,x # can alias it
|
|
251
|
+
#end
|
|
252
|
+
# since include FFI is taking over, i need to force it here. not going into
|
|
253
|
+
# method_missing
|
|
254
|
+
def wmove y,x
|
|
255
|
+
#Ncurses.wmove @window, y, x
|
|
256
|
+
FFI::NCurses.wmove @window, y, x
|
|
257
|
+
end
|
|
258
|
+
alias :move :wmove
|
|
259
|
+
|
|
260
|
+
def method_missing(name, *args)
|
|
261
|
+
name = name.to_s
|
|
262
|
+
if (name[0,2] == "mv")
|
|
263
|
+
test_name = name.dup
|
|
264
|
+
test_name[2,0] = "w" # insert "w" after"mv"
|
|
265
|
+
if (FFI::NCurses.respond_to?(test_name))
|
|
266
|
+
return FFI::NCurses.send(test_name, @window, *args)
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
test_name = "w" + name
|
|
270
|
+
if (FFI::NCurses.respond_to?(test_name))
|
|
271
|
+
return FFI::NCurses.send(test_name, @window, *args)
|
|
272
|
+
end
|
|
273
|
+
FFI::NCurses.send(name, @window, *args)
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def respond_to?(name)
|
|
277
|
+
name = name.to_s
|
|
278
|
+
if (name[0,2] == "mv" && FFI::NCurses.respond_to?("mvw" + name[2..-1]))
|
|
279
|
+
return true
|
|
280
|
+
end
|
|
281
|
+
FFI::NCurses.respond_to?("w" + name) || FFI::NCurses.respond_to?(name)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
#--
|
|
285
|
+
# removing some methods that not used or used once
|
|
286
|
+
# leaving here so we not what to do to print in these cases
|
|
287
|
+
def print(string, width = width)
|
|
288
|
+
w = width == 0? Ncurses.COLS : width
|
|
289
|
+
waddnstr(string.to_s, w) # changed 2011 dts
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
#def print_yx(string, y = 0, x = 0)
|
|
293
|
+
#w = width == 0? Ncurses.COLS : width
|
|
294
|
+
#mvwaddnstr(y, x, string, w) # changed 2011 dts
|
|
295
|
+
#end
|
|
296
|
+
#++
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
# return the character to the keyboard buffer to be read again.
|
|
300
|
+
def ungetch(ch)
|
|
301
|
+
Ncurses.ungetch(ch)
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
# reads a character from keyboard and returns
|
|
305
|
+
# NOTE:
|
|
306
|
+
# if a function key is pressed, multiple such ints will be returned one after the other
|
|
307
|
+
# so the caller must decipher the same. See +getchar()+
|
|
308
|
+
#
|
|
309
|
+
# @return int
|
|
310
|
+
# @return -1 if no char read
|
|
311
|
+
# ORIGINALLY After esc there was a timeout, but after others there was notimeout, so it would wait
|
|
312
|
+
# indefinitely for a key
|
|
313
|
+
# NOTE : caller may set a timeout prior to calling, but not change setting after since this method
|
|
314
|
+
# maintains the default state in +ensure+. e.g. +widget.rb+ does a blocking get in +_process_key+
|
|
315
|
+
# Curses sets a timeout when ESCAPE is pressed, it is called ESCDELAY and is 1000 milliseconds.
|
|
316
|
+
# You may reduce it if you are not on some old slow telnet session. This returns faster from an esc
|
|
317
|
+
# although there are still some issues. ESC-ESC becomes an issue, but if i press ESC-ESC-1 then esc-esc comes
|
|
318
|
+
# together. otherwise there is a -1 between each esc.
|
|
319
|
+
#
|
|
320
|
+
def getch
|
|
321
|
+
#c = @window.getch
|
|
322
|
+
#FFI::NCurses::nodelay(@window, true)
|
|
323
|
+
#FFI::NCurses::wtimeout(@window, 0)
|
|
324
|
+
#$log.debug " #{Time.now.to_f} inside MAIN before getch "
|
|
325
|
+
c = FFI::NCurses.wgetch(@window)
|
|
326
|
+
# the only reason i am doing this is so ESC can be returned if no key is pressed
|
|
327
|
+
# after that, not sure how this effects everything. most likely I should just
|
|
328
|
+
# go back to using a wtimeout, and not worry about resize requiring a keystroke
|
|
329
|
+
if c == 27
|
|
330
|
+
$escstart = Time.now.to_f
|
|
331
|
+
# if ESC pressed don't wait too long for next key
|
|
332
|
+
Ncurses::wtimeout(@window, $ncurses_timeout || 500) # will wait n millisecond on wgetch so that we can return if no
|
|
333
|
+
else
|
|
334
|
+
FFI::NCurses.set_escdelay(100)
|
|
335
|
+
# this means keep waiting for a key.
|
|
336
|
+
Ncurses::nowtimeout(@window, true)
|
|
337
|
+
end
|
|
338
|
+
c
|
|
339
|
+
|
|
340
|
+
rescue SystemExit, Interrupt
|
|
341
|
+
#FFI::NCurses.flushinp
|
|
342
|
+
3 # is C-c
|
|
343
|
+
rescue StandardError
|
|
344
|
+
-1 # is C-c
|
|
345
|
+
ensure
|
|
346
|
+
# whatever the default is, is to be set here in case caller changed it.
|
|
347
|
+
#FFI::NCurses::nodelay(@window, true)
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
# Earlier this was handled by window itself. Now we delegate to a reader
|
|
351
|
+
# @return int keycode, can be function key or meta or arrow key.
|
|
352
|
+
#
|
|
353
|
+
# NOTE:
|
|
354
|
+
# This is called by user programs in a loop.
|
|
355
|
+
# We are now moving from returning an int to returning a string similar to what
|
|
356
|
+
# user would get on commandline using C-v
|
|
357
|
+
#
|
|
358
|
+
def getchar
|
|
359
|
+
@key_reader.getchar
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
# setup and reset
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
# Ncurses panel
|
|
368
|
+
|
|
369
|
+
def hide
|
|
370
|
+
#return unless visible? # added 2011-10-14 these 2 are not behaving properly
|
|
371
|
+
Ncurses::Panel.hide_panel @panel.pointer
|
|
372
|
+
#Ncurses.refresh # wnoutrefresh
|
|
373
|
+
Ncurses::Panel.update_panels # added so below window does not need to do this 2011-10-1
|
|
374
|
+
@visible = false
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def show
|
|
378
|
+
#return if visible? # added 2011-10-14 these 2 are not behaving properly
|
|
379
|
+
Ncurses::Panel.show_panel @panel.pointer
|
|
380
|
+
#Ncurses.refresh # wnoutrefresh
|
|
381
|
+
Ncurses::Panel.update_panels # added so below window does not need to do this 2011-10-1
|
|
382
|
+
@visible = true
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def visible?
|
|
387
|
+
@visible
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
##
|
|
391
|
+
# destroy window, panel and any pads that were requested
|
|
392
|
+
#
|
|
393
|
+
def destroy
|
|
394
|
+
# typically the ensure block should have this
|
|
395
|
+
|
|
396
|
+
#$log.debug "win destroy start"
|
|
397
|
+
|
|
398
|
+
$global_windows.delete self
|
|
399
|
+
Ncurses::Panel.del_panel(@panel.pointer) if @panel
|
|
400
|
+
delwin() if @window
|
|
401
|
+
Ncurses::Panel.update_panels # added so below window does not need to do this 2011-10-1
|
|
402
|
+
|
|
403
|
+
# destroy any pads that were created by widgets using get_pad
|
|
404
|
+
@pads.each { |pad|
|
|
405
|
+
FFI::NCurses.delwin(pad) if pad
|
|
406
|
+
pad = nil
|
|
407
|
+
} if @pads
|
|
408
|
+
# added here to hopefully take care of this issue once and for all.
|
|
409
|
+
# Whenever any window is destroyed, the root window is repainted.
|
|
410
|
+
#
|
|
411
|
+
Window.refresh_all
|
|
412
|
+
#$log.debug "win destroy end"
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
#
|
|
416
|
+
# 2011-11-13 since 1.4.1
|
|
417
|
+
# Widgets can get window to create a pad for them. This way when the window
|
|
418
|
+
# is destroyed, it will delete all the pads. A widget wold not be able to do this.
|
|
419
|
+
# The destroy method of the widget will be called.
|
|
420
|
+
def get_pad content_rows, content_cols
|
|
421
|
+
pad = FFI::NCurses.newpad(content_rows, content_cols)
|
|
422
|
+
@pads ||= []
|
|
423
|
+
@pads << pad
|
|
424
|
+
## added 2013-03-05 - 19:21 without next line how was pad being returned
|
|
425
|
+
return pad
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
# print and chunk related --- {{{
|
|
429
|
+
#
|
|
430
|
+
# Allows user to send data as normal string or chunks for printing
|
|
431
|
+
# An array is assumed to be a chunk containing color and attrib info
|
|
432
|
+
#
|
|
433
|
+
def printstring_or_chunks(r,c,content, color, att = Ncurses::A_NORMAL)
|
|
434
|
+
if content.is_a? String
|
|
435
|
+
printstring(r,c,content, color, att)
|
|
436
|
+
elsif content.is_a? AbstractChunkLine
|
|
437
|
+
#$log.debug "XXX: using chunkline" # 2011-12-10 12:40:13
|
|
438
|
+
wmove r, c
|
|
439
|
+
a = get_attrib att
|
|
440
|
+
# please add width to avoid overflow
|
|
441
|
+
show_colored_chunks content, color, a
|
|
442
|
+
elsif content.is_a? Array
|
|
443
|
+
# several chunks in one row - NOTE Very experimental may change
|
|
444
|
+
if content[0].is_a? Array
|
|
445
|
+
$log.warn "XXX: WARNING outdated should send in a chunkline"
|
|
446
|
+
wmove r, c
|
|
447
|
+
a = get_attrib att
|
|
448
|
+
# please add width to avoid overflow
|
|
449
|
+
show_colored_chunks content, color, a
|
|
450
|
+
else
|
|
451
|
+
# a single row chunk - NOTE Very experimental may change
|
|
452
|
+
text = content[1].dup
|
|
453
|
+
printstring r, c, text, content[0] || color, content[2] || att
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
#
|
|
458
|
+
# prints a string formatted in our new experimental coloring format
|
|
459
|
+
# taken from tmux. Currently, since i have chunks workings, i convert
|
|
460
|
+
# to chunks and use the existing print function. This could change.
|
|
461
|
+
# An example of a formatted string is:
|
|
462
|
+
# s="#[fg=green]testing chunks #[fg=yellow, bg=red, bold]yellow #[reverse] reverseme \
|
|
463
|
+
# #[normal]normal#[bg = black]just yellow#[fg=blue],blue now #[underline] underlined text"
|
|
464
|
+
# Ideally I should push and pop colors which the shell does not do with ansi terminal sequences.
|
|
465
|
+
# That way i can have a line in red,
|
|
466
|
+
# with some word in yellow, and then the line continues in red.
|
|
467
|
+
#
|
|
468
|
+
def printstring_formatted(r,c,content, color, att = Ncurses::A_NORMAL)
|
|
469
|
+
att = get_attrib att unless att.is_a? Fixnum
|
|
470
|
+
chunkline = convert_to_chunk(content, color, att)
|
|
471
|
+
printstring_or_chunks r,c, chunkline, color, att
|
|
472
|
+
end # print
|
|
473
|
+
#
|
|
474
|
+
# print a formatted line right aligned
|
|
475
|
+
# c (col) is ignored and calculated based on width and unformatted string length
|
|
476
|
+
#
|
|
477
|
+
def printstring_formatted_right(r,c,content, color, att = Ncurses::A_NORMAL)
|
|
478
|
+
clean = content.gsub /#\[[^\]]*\]/,'' # clean out all markup
|
|
479
|
+
#c = actual_width() - clean.length # actual width not working if resize
|
|
480
|
+
c = getmaxx() - clean.length
|
|
481
|
+
printstring_formatted(r,c,content, color, att )
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
private
|
|
485
|
+
def get_default_color_parser
|
|
486
|
+
require 'canis/core/util/defaultcolorparser'
|
|
487
|
+
@color_parser || DefaultColorParser.new
|
|
488
|
+
end
|
|
489
|
+
# supply with a color parser, if you supplied formatted text
|
|
490
|
+
public
|
|
491
|
+
def color_parser f
|
|
492
|
+
$log.debug "XXX: color_parser setting in window to #{f} "
|
|
493
|
+
require 'canis/core/include/colorparser'
|
|
494
|
+
if f == :tmux
|
|
495
|
+
@color_parser = get_default_color_parser()
|
|
496
|
+
else
|
|
497
|
+
@color_parser = f
|
|
498
|
+
end
|
|
499
|
+
end
|
|
500
|
+
#
|
|
501
|
+
# Takes a formatted string and converts the parsed parts to chunks.
|
|
502
|
+
#
|
|
503
|
+
# @param [String] takes the entire line or string and breaks into an array of chunks
|
|
504
|
+
# @yield chunk if block
|
|
505
|
+
# @return [ChunkLine] # [Array] array of chunks
|
|
506
|
+
public
|
|
507
|
+
def convert_to_chunk s, colorp=$datacolor, att=FFI::NCurses::A_NORMAL
|
|
508
|
+
unless @color_parser
|
|
509
|
+
require 'canis/core/include/colorparser'
|
|
510
|
+
@color_parser = get_default_color_parser()
|
|
511
|
+
@converter = Chunks::ColorParser.new @color_parser
|
|
512
|
+
# we need to know set the parent in colorparser. 2014-05-26 - 14:49
|
|
513
|
+
@converter.form = self.form
|
|
514
|
+
end
|
|
515
|
+
@converter.convert_to_chunk s, colorp, att
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
##
|
|
519
|
+
# prints a string at row, col, with given color and attribute
|
|
520
|
+
# added by rk 2008-11-29 19:01
|
|
521
|
+
# I usually use this, not the others ones here
|
|
522
|
+
# @param r - row
|
|
523
|
+
# @param c - col
|
|
524
|
+
# @param string - text to print
|
|
525
|
+
# @param color - color pair
|
|
526
|
+
# @ param att - ncurses attribute: normal, bold, reverse, blink,
|
|
527
|
+
# underline
|
|
528
|
+
public
|
|
529
|
+
def printstring(r,c,string, color, att = Ncurses::A_NORMAL)
|
|
530
|
+
|
|
531
|
+
raise "printstring recvd nil row #{r} or col #{c} " if r.nil? || c.nil?
|
|
532
|
+
#$log.debug " #{@name} inside window printstring r #{r} c #{c} #{string} "
|
|
533
|
+
if att.nil?
|
|
534
|
+
att = Ncurses::A_NORMAL
|
|
535
|
+
else
|
|
536
|
+
att = get_attrib att
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
wattron(Ncurses.COLOR_PAIR(color) | att)
|
|
540
|
+
mvwprintw(r, c, "%s", :string, string);
|
|
541
|
+
wattroff(Ncurses.COLOR_PAIR(color) | att)
|
|
542
|
+
end
|
|
543
|
+
##
|
|
544
|
+
# prints the border for message boxes
|
|
545
|
+
#
|
|
546
|
+
# NOTE : FOR MESSAGEBOXES ONLY !!!! Then why not move to messagebox FIXME
|
|
547
|
+
def print_border_mb row, col, height, width, color, attr
|
|
548
|
+
# the next is for xterm-256
|
|
549
|
+
att = get_attrib attr
|
|
550
|
+
len = width
|
|
551
|
+
len = Ncurses.COLS-0 if len == 0
|
|
552
|
+
# print a bar across the screen
|
|
553
|
+
#attron(Ncurses.COLOR_PAIR(color) | att)
|
|
554
|
+
# this works for newmessagebox but not for old one.
|
|
555
|
+
# Even now in some cases some black shows through, if the widget is printing spaces
|
|
556
|
+
# such as field or textview on a messagebox.
|
|
557
|
+
(row-1).upto(row+height-1) do |r|
|
|
558
|
+
mvwhline(r, col, 1, len)
|
|
559
|
+
end
|
|
560
|
+
#attroff(Ncurses.COLOR_PAIR(color) | att)
|
|
561
|
+
|
|
562
|
+
mvwaddch row, col, Ncurses::ACS_ULCORNER
|
|
563
|
+
mvwhline( row, col+1, Ncurses::ACS_HLINE, width-6)
|
|
564
|
+
mvwaddch row, col+width-5, Ncurses::ACS_URCORNER
|
|
565
|
+
mvwvline( row+1, col, Ncurses::ACS_VLINE, height-4)
|
|
566
|
+
|
|
567
|
+
mvwaddch row+height-3, col, Ncurses::ACS_LLCORNER
|
|
568
|
+
mvwhline(row+height-3, col+1, Ncurses::ACS_HLINE, width-6)
|
|
569
|
+
mvwaddch row+height-3, col+width-5, Ncurses::ACS_LRCORNER
|
|
570
|
+
mvwvline( row+1, col+width-5, Ncurses::ACS_VLINE, height-4)
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
##
|
|
574
|
+
# prints a border around a widget, CLEARING the area.
|
|
575
|
+
# If calling with a pad, you would typically use 0,0, h-1, w-1.
|
|
576
|
+
# FIXME can this be moved to module Bordertitle ?
|
|
577
|
+
def print_border row, col, height, width, color, att=Ncurses::A_NORMAL
|
|
578
|
+
raise "height needs to be supplied." if height.nil?
|
|
579
|
+
raise "width needs to be supplied." if width.nil?
|
|
580
|
+
att ||= Ncurses::A_NORMAL
|
|
581
|
+
|
|
582
|
+
#$log.debug " inside window print_border r #{row} c #{col} h #{height} w #{width} "
|
|
583
|
+
|
|
584
|
+
# 2009-11-02 00:45 made att nil for blanking out
|
|
585
|
+
# FIXME - in tabbedpanes this clears one previous line ??? XXX when using a textarea/view
|
|
586
|
+
# when using a pad this calls pads printstring which again reduces top and left !!! 2010-01-26 23:53
|
|
587
|
+
ww=width-2
|
|
588
|
+
clr = " "*ww
|
|
589
|
+
(row+1).upto(row+height-1) do |r|
|
|
590
|
+
printstring( r, col+1, clr, color, att)
|
|
591
|
+
end
|
|
592
|
+
print_border_only row, col, height, width, color, att
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
## print just the border, no cleanup
|
|
597
|
+
#+ Earlier, we would clean up. Now in some cases, i'd like
|
|
598
|
+
#+ to print border over what's been done.
|
|
599
|
+
# XXX this reduces 1 from width but not height !!! FIXME
|
|
600
|
+
# FIXME can this be moved to module Bordertitle ?
|
|
601
|
+
def print_border_only row, col, height, width, color, att=Ncurses::A_NORMAL
|
|
602
|
+
if att.nil?
|
|
603
|
+
att = Ncurses::A_NORMAL
|
|
604
|
+
else
|
|
605
|
+
att = get_attrib att
|
|
606
|
+
end
|
|
607
|
+
wattron(Ncurses.COLOR_PAIR(color) | att)
|
|
608
|
+
mvwaddch row, col, Ncurses::ACS_ULCORNER
|
|
609
|
+
mvwhline( row, col+1, Ncurses::ACS_HLINE, width-2)
|
|
610
|
+
mvwaddch row, col+width-1, Ncurses::ACS_URCORNER
|
|
611
|
+
mvwvline( row+1, col, Ncurses::ACS_VLINE, height-1)
|
|
612
|
+
|
|
613
|
+
mvwaddch row+height-0, col, Ncurses::ACS_LLCORNER
|
|
614
|
+
mvwhline(row+height-0, col+1, Ncurses::ACS_HLINE, width-2)
|
|
615
|
+
mvwaddch row+height-0, col+width-1, Ncurses::ACS_LRCORNER
|
|
616
|
+
mvwvline( row+1, col+width-1, Ncurses::ACS_VLINE, height-1)
|
|
617
|
+
wattroff(Ncurses.COLOR_PAIR(color) | att)
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
# Previously this printed a chunk as a full line, I've modified it to print on
|
|
621
|
+
# one line. This can be used for running text.
|
|
622
|
+
# NOTE 2013-03-08 - 17:02 added width so we don't overflow
|
|
623
|
+
# NOTE 2014-05-11 - textpad has its own version, so does not call this.
|
|
624
|
+
def show_colored_chunks(chunks, defcolor = nil, defattr = nil, wid = 999, pcol = 0)
|
|
625
|
+
return unless visible?
|
|
626
|
+
ww = 0
|
|
627
|
+
chunks.each_with_color do |text, color, attrib|
|
|
628
|
+
|
|
629
|
+
## 2013-03-08 - 19:11 take care of scrolling by means of pcol
|
|
630
|
+
if pcol > 0
|
|
631
|
+
if pcol > text.length
|
|
632
|
+
# ignore entire chunk and reduce pcol
|
|
633
|
+
pcol -= text.length
|
|
634
|
+
next
|
|
635
|
+
else
|
|
636
|
+
# print portion of chunk and zero pcol
|
|
637
|
+
text = text[pcol..-1]
|
|
638
|
+
pcol = 0
|
|
639
|
+
end
|
|
640
|
+
end
|
|
641
|
+
oldw = ww
|
|
642
|
+
ww += text.length
|
|
643
|
+
if ww > wid
|
|
644
|
+
# if we are exceeding the width then by howmuch
|
|
645
|
+
rem = wid - oldw
|
|
646
|
+
if rem > 0
|
|
647
|
+
# take only as much as we are allowed
|
|
648
|
+
text = text[0,rem]
|
|
649
|
+
else
|
|
650
|
+
break
|
|
651
|
+
end
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
color ||= defcolor
|
|
655
|
+
attrib ||= defattr
|
|
656
|
+
|
|
657
|
+
cc, bg = ColorMap.get_colors_for_pair color
|
|
658
|
+
#$log.debug "XXX: CHUNK window #{text}, cp #{color} , attrib #{attrib}. #{cc}, #{bg} "
|
|
659
|
+
color_set(color,nil) if color
|
|
660
|
+
wattron(attrib) if attrib
|
|
661
|
+
#print(text)
|
|
662
|
+
waddnstr(text.to_s, @width) # changed 2014-04-22 - 11:59 to reduce a function
|
|
663
|
+
wattroff(attrib) if attrib
|
|
664
|
+
end
|
|
665
|
+
end
|
|
666
|
+
# ----- }}}
|
|
667
|
+
|
|
668
|
+
# This used to return an Ncurses window object, and you could call methods on it
|
|
669
|
+
# Now it returns a FFI::NCurses.window pointer which you cannot call methods on.
|
|
670
|
+
# You have to pass it to FFI::NCurses.<method>
|
|
671
|
+
def get_window; @window; end
|
|
672
|
+
|
|
673
|
+
# returns name of window or self (mostly for debugging)
|
|
674
|
+
def to_s; @name || self; end
|
|
675
|
+
|
|
676
|
+
# actions to perform when window closed.
|
|
677
|
+
# == Example
|
|
678
|
+
# @window.close_command do
|
|
679
|
+
# if confirm("Save tasks?", :default_button => 0)
|
|
680
|
+
# take some actions
|
|
681
|
+
# end
|
|
682
|
+
# end
|
|
683
|
+
def close_command *args, &block
|
|
684
|
+
@close_command ||= []
|
|
685
|
+
@close_args ||= []
|
|
686
|
+
@close_command << block
|
|
687
|
+
@close_args << args
|
|
688
|
+
end
|
|
689
|
+
alias :command :close_command
|
|
690
|
+
|
|
691
|
+
# set a single command to confirm whether window shoud close or not
|
|
692
|
+
# Block should return true or false for closing or not
|
|
693
|
+
# == Examples
|
|
694
|
+
#
|
|
695
|
+
# @window.confirm_close_command do
|
|
696
|
+
# confirm "Sure you wanna quit?", :default_button => 1
|
|
697
|
+
# end
|
|
698
|
+
#
|
|
699
|
+
def confirm_close_command *args, &block
|
|
700
|
+
@confirm_close_command = block
|
|
701
|
+
@confirm_close_args = args
|
|
702
|
+
end
|
|
703
|
+
|
|
704
|
+
# Called when window close is requested by user.
|
|
705
|
+
# Executes confirm_close block and if it succeeds then executes close commands
|
|
706
|
+
# called by util/app.rb
|
|
707
|
+
def fire_close_handler
|
|
708
|
+
if @confirm_close_command
|
|
709
|
+
comm = @confirm_close_command
|
|
710
|
+
ret = comm.call(self, *@confirm_close_args)
|
|
711
|
+
return ret unless ret # only return if false returned
|
|
712
|
+
end
|
|
713
|
+
if @close_command
|
|
714
|
+
@close_command.each_with_index do |comm, ix|
|
|
715
|
+
comm.call(self, *@close_args[ix]) if comm
|
|
716
|
+
end
|
|
717
|
+
end
|
|
718
|
+
@close_command = nil
|
|
719
|
+
@close_args = nil
|
|
720
|
+
return true
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
# creates a key reader unless overridden by application which should be rare.
|
|
724
|
+
def create_default_key_reader
|
|
725
|
+
@key_reader = DefaultKeyReader.new self
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
end # window
|
|
730
|
+
|
|
731
|
+
# created on 2014-04-20 - 00:19 so that user can install own handler
|
|
732
|
+
#
|
|
733
|
+
#
|
|
734
|
+
# A class that reads keys and handles function, shifted function, control, alt, and other
|
|
735
|
+
# extended keys.
|
|
736
|
+
# THis essentially consists of a method getchar which will be called by the application
|
|
737
|
+
# to get keys in a loop. Application may also call getchar to get one key in some situations.
|
|
738
|
+
#
|
|
739
|
+
# Originally, rbcurse returned an int, but we are movign to a string, so that user can use the exact
|
|
740
|
+
# control codes he gets on the terminal using C-v and map them here.
|
|
741
|
+
#
|
|
742
|
+
#
|
|
743
|
+
class DefaultKeyReader # --- {{{
|
|
744
|
+
def initialize win
|
|
745
|
+
@window = win
|
|
746
|
+
@stack = []
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
# return an int for the key read. this is just a single int, and is not interpreted
|
|
750
|
+
# for control or function keys. it also will return -1 when no action.
|
|
751
|
+
# You may re-implenent it or call the original one.
|
|
752
|
+
#
|
|
753
|
+
def getch
|
|
754
|
+
@window.getch
|
|
755
|
+
end
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
# A map of int keycodes associated with a string name which is defined in $kh
|
|
759
|
+
$kh_int ||= Hash.new {|hash, key| hash[key] = key.hash }
|
|
760
|
+
# these 4 for xterm-color which does not send 265 on F1
|
|
761
|
+
$kh_int["F1"] = 265
|
|
762
|
+
$kh_int["F2"] = 266
|
|
763
|
+
$kh_int["F3"] = 267
|
|
764
|
+
$kh_int["F4"] = 268
|
|
765
|
+
# testing out shift+Function. these are the codes my kb generates
|
|
766
|
+
if File.exists? File.expand_path("~/ncurses-keys.yml")
|
|
767
|
+
# a sample of this file should be available with this
|
|
768
|
+
# the file is a hash or mapping, but should not contrain control characters.
|
|
769
|
+
# Usually delete the control character and insert a "\e" in its place.
|
|
770
|
+
# "\e[1;3C": C-RIGHT
|
|
771
|
+
require 'yaml'
|
|
772
|
+
$kh = YAML::load( File.open( File.expand_path("~/ncurses-keys.yml" ) ))
|
|
773
|
+
else
|
|
774
|
+
# if we could not find any mappings then use some dummy ones that work on my laptop.
|
|
775
|
+
$kh=Hash.new
|
|
776
|
+
KEY_S_F1='[1;2P'
|
|
777
|
+
$kh[KEY_S_F1]="S-F1"
|
|
778
|
+
$kh['[1;2Q']="S-F2"
|
|
779
|
+
$kh['[1;2R']="S-F3"
|
|
780
|
+
$kh['[1;2S']="S-F4"
|
|
781
|
+
$kh['[15;2~']="S-F5"
|
|
782
|
+
|
|
783
|
+
end
|
|
784
|
+
# this is for xterm-color which does not send 265 on F1
|
|
785
|
+
$kh['OP']="F1"
|
|
786
|
+
$kh['OQ']="F2"
|
|
787
|
+
$kh['OR']="F3"
|
|
788
|
+
$kh['OS']="F4"
|
|
789
|
+
|
|
790
|
+
# NOTE: This is a reworked and much simpler version of the original getchar which was taken from manveru's
|
|
791
|
+
# codebase. This also currently returns the keycode as int while placing the char version in a
|
|
792
|
+
# global $key_chr. Until we are ready to return a char, we use this.
|
|
793
|
+
#
|
|
794
|
+
# FIXME : I have tried very hard to revert to nodelay but it does not seem to have an effect when ESC is pressed.
|
|
795
|
+
# Somewhere, there is a delay when ESC is pressed. I not longer wish to provide the feature of pressing ESC
|
|
796
|
+
# and then a key to be evaluated as Meta-key. This slows down when a user just presses ESC.
|
|
797
|
+
#
|
|
798
|
+
# Read a char from the window (from user) and returns int code.
|
|
799
|
+
# In some cases, such as codes entered in the $kh hash, we do not yet have a keycode defined
|
|
800
|
+
# so we return 9999 and the user can access $key_chr.
|
|
801
|
+
#
|
|
802
|
+
# NOTE: Do not convert to string, that is doing two things. Allow user to convert if required using
|
|
803
|
+
# `key_tos`
|
|
804
|
+
def getchar
|
|
805
|
+
$key_chr = nil
|
|
806
|
+
c = nil
|
|
807
|
+
while true
|
|
808
|
+
c = self.getch
|
|
809
|
+
break if c != -1
|
|
810
|
+
end
|
|
811
|
+
|
|
812
|
+
cn = c
|
|
813
|
+
$key_int = c
|
|
814
|
+
# handle control codes 0 to 127 but not escape
|
|
815
|
+
if cn >= 0 && cn < 128 && cn != 27
|
|
816
|
+
#$key_chr = key_tos(c)
|
|
817
|
+
return c
|
|
818
|
+
end
|
|
819
|
+
|
|
820
|
+
# if escape then get into a loop and keep checking till -1 or another escape
|
|
821
|
+
#
|
|
822
|
+
if c == 27
|
|
823
|
+
buff=c.chr
|
|
824
|
+
# if there is another escape coming through then 2 keys were pressed so
|
|
825
|
+
# evaluate upon hitting an escape
|
|
826
|
+
# NOTE : i think only if ESc is followed by [ should be keep collectig
|
|
827
|
+
# otherwise the next char should evaluate. cases like F1 are already being sent in as high integer codes
|
|
828
|
+
while true
|
|
829
|
+
#$log.debug " #{Time.now.to_f} inside LOOP before getch "
|
|
830
|
+
# This getch seems to take enough time not to return a -1 for almost a second
|
|
831
|
+
# even if nodelay is true ??? XXX
|
|
832
|
+
FFI::NCurses.set_escdelay(5)
|
|
833
|
+
k = self.getch
|
|
834
|
+
#$log.debug "elapsed #{elapsed} millis inside LOOP AFTER getch #{k} (#{elapsed1})"
|
|
835
|
+
$log.debug "inside LOOP AFTER getch #{k} "
|
|
836
|
+
|
|
837
|
+
if k == 27
|
|
838
|
+
# seems like two Meta keys pressed in quick succession without chance for -1 to kick in
|
|
839
|
+
# but this still does not catch meta char followed by single char. M-za , it does.
|
|
840
|
+
if $esc_esc
|
|
841
|
+
if buff == 27.chr
|
|
842
|
+
$key_chr = "<ESC-ESC>"
|
|
843
|
+
return 2727
|
|
844
|
+
else
|
|
845
|
+
alert "buff is #{buff}"
|
|
846
|
+
end
|
|
847
|
+
end
|
|
848
|
+
$log.debug " 1251 before evaluate "
|
|
849
|
+
x = _evaluate_buff buff
|
|
850
|
+
# return ESC so it can be interpreted again.
|
|
851
|
+
@window.ungetch k
|
|
852
|
+
$key_chr = x if x
|
|
853
|
+
return $key_int if x
|
|
854
|
+
$log.warn "getchar: window.rb 1200 Found no mapping for #{buff} "
|
|
855
|
+
$key_chr = buff
|
|
856
|
+
return $key_int
|
|
857
|
+
#return buff # otherwise caught in loop ???
|
|
858
|
+
elsif k > -1
|
|
859
|
+
# FIXME next lne crashes if M-C-h pressed which gives 263
|
|
860
|
+
if k > 255
|
|
861
|
+
$log.warn "getchar: window.rb 1247 Found no mapping for #{buff} #{k} "
|
|
862
|
+
$key_int = k + 128
|
|
863
|
+
return $key_int
|
|
864
|
+
# this contains ESc followed by a high number
|
|
865
|
+
=begin
|
|
866
|
+
ka = key_tos(k)
|
|
867
|
+
if ka
|
|
868
|
+
$key_chr = "<M-" + ka[1..-1]
|
|
869
|
+
$key_int = k + 128
|
|
870
|
+
return $key_int
|
|
871
|
+
else
|
|
872
|
+
$key_chr = "UNKNOWN: Meta + #{k}"
|
|
873
|
+
return 9999
|
|
874
|
+
end
|
|
875
|
+
=end
|
|
876
|
+
end
|
|
877
|
+
|
|
878
|
+
buff += k.chr
|
|
879
|
+
# this is an alt/meta code. All other complex codes seem to have a [ after the escape
|
|
880
|
+
# so we will keep accumulating them.
|
|
881
|
+
# NOTE this still means that user can press Alt-[ and some letter in quick succession
|
|
882
|
+
# and it will accumulate rather than be interpreted as M-[.
|
|
883
|
+
#
|
|
884
|
+
if buff.length == 2 and k == 79
|
|
885
|
+
# this is Alt-O and can be a F key in some terms like xterm-color
|
|
886
|
+
elsif buff.length == 2 and k.chr != '['
|
|
887
|
+
x = _evaluate_buff buff
|
|
888
|
+
|
|
889
|
+
$key_chr = x
|
|
890
|
+
return $key_int if x
|
|
891
|
+
end
|
|
892
|
+
#$log.debug "XXX: getchar adding #{k}, #{k.chr} to buff #{buff} "
|
|
893
|
+
else
|
|
894
|
+
#$log.debug " GOT -1 in escape "
|
|
895
|
+
# it is -1 so evaluate
|
|
896
|
+
x = _evaluate_buff buff
|
|
897
|
+
$key_chr = x if x
|
|
898
|
+
return $key_int if x
|
|
899
|
+
$log.warn "getchar: window.rb 1256 Found no mapping for #{buff} "
|
|
900
|
+
$key_chr = buff
|
|
901
|
+
return $key_int
|
|
902
|
+
end
|
|
903
|
+
end
|
|
904
|
+
end
|
|
905
|
+
|
|
906
|
+
# what if keyname does not return anything
|
|
907
|
+
if c > 127
|
|
908
|
+
#$log.info "xxxgetchar: window.rb sending #{c} "
|
|
909
|
+
=begin
|
|
910
|
+
ch = FFI::NCurses::keyname(c)
|
|
911
|
+
# remove those ugly brackets around function keys
|
|
912
|
+
if ch && ch[-1]==')'
|
|
913
|
+
ch = ch.gsub(/[()]/,'')
|
|
914
|
+
end
|
|
915
|
+
if ch && ch.index("KEY_")
|
|
916
|
+
ch = ch.gsub(/KEY_/,'')
|
|
917
|
+
end
|
|
918
|
+
ch = "<#{ch}>" if ch
|
|
919
|
+
#return ch if ch
|
|
920
|
+
$key_chr = ch if ch
|
|
921
|
+
$key_chr = "UNKNOWN:#{c}" unless ch
|
|
922
|
+
$log.warn "getchar: window.rb 1234 Found no mapping for #{c} " unless ch
|
|
923
|
+
=end
|
|
924
|
+
#$key_chr = key_tos(ch)
|
|
925
|
+
return c
|
|
926
|
+
end
|
|
927
|
+
if c
|
|
928
|
+
#$key_chr = c.chr
|
|
929
|
+
return c
|
|
930
|
+
end
|
|
931
|
+
end
|
|
932
|
+
|
|
933
|
+
|
|
934
|
+
def getchar_as_char
|
|
935
|
+
$key_int = getchar
|
|
936
|
+
$key_chr = key_tos( $key_int )
|
|
937
|
+
return $key_chr
|
|
938
|
+
end
|
|
939
|
+
|
|
940
|
+
|
|
941
|
+
=begin
|
|
942
|
+
# NOTE I cannot use this since we are not ready to take a string, that is a big decision that
|
|
943
|
+
# requries a lot of work, and some decisions. We may bind using "<CR>" or "<C-d>" so
|
|
944
|
+
# maybe that's how we may need to send back
|
|
945
|
+
## get a character from user and return as a string
|
|
946
|
+
# Adapted from:
|
|
947
|
+
#http://stackoverflow.com/questions/174933/how-to-get-a-single-character-without-pressing-enter/8274275#8274275
|
|
948
|
+
# Need to take complex keys and matc against a hash.
|
|
949
|
+
# We cannot use the cetus example as is since here $stdin.ready? does not work and more importantly
|
|
950
|
+
# we have keyboard set to true so function keys and arrow keys are not returned as multiple values but as
|
|
951
|
+
# one int in the 255 and above range. so that must be interpreted separately.
|
|
952
|
+
#
|
|
953
|
+
# If we wait for -1 then quick M-a can get concatenated. we need to take care
|
|
954
|
+
# a ESC means the previous one should be evaluated and not contactenated
|
|
955
|
+
# FIXME = ESCESC 2727 - can't do this as will clash with Esc, M-(n).
|
|
956
|
+
# this is a rework of the above but returns an int so that the existing programs can keep working.
|
|
957
|
+
# We will store the char codes/ in a global string so user can get esp if unknown.
|
|
958
|
+
# UNUSED since we are still using int codes.
|
|
959
|
+
def getchar_as_char # -- {{{
|
|
960
|
+
c = nil
|
|
961
|
+
while true
|
|
962
|
+
c = self.getch
|
|
963
|
+
break if c != -1
|
|
964
|
+
end
|
|
965
|
+
|
|
966
|
+
cn = c
|
|
967
|
+
#return FFI::NCurses::keyname(c) if [10,13,127,0,32,8].include? c
|
|
968
|
+
$key_int = c
|
|
969
|
+
if cn >= 0 && cn < 128 && cn != 27
|
|
970
|
+
$key_chr = key_tos(c)
|
|
971
|
+
return $key_chr
|
|
972
|
+
end
|
|
973
|
+
|
|
974
|
+
# if escape then get into a loop and keep checking till -1 or another escape
|
|
975
|
+
#
|
|
976
|
+
if c == 27
|
|
977
|
+
buff=c.chr
|
|
978
|
+
# if there is another escape coming through then 2 keys were pressed so
|
|
979
|
+
# evaluate upon hitting an escape
|
|
980
|
+
# NOTE : i think only if ESc is followed by [ should be keep collectig
|
|
981
|
+
# otherwise the next char should evaluate. cases like F1 are already being sent in as high integer codes
|
|
982
|
+
while true
|
|
983
|
+
|
|
984
|
+
k = self.getch
|
|
985
|
+
|
|
986
|
+
if k == 27
|
|
987
|
+
# seems like two Meta keys pressed in quick succession without chance for -1 to kick in
|
|
988
|
+
# but this still does not catch meta char followed by single char. M-za
|
|
989
|
+
x = _evaluate_buff buff
|
|
990
|
+
# return ESC so it can be interpreted again.
|
|
991
|
+
@window.ungetch k
|
|
992
|
+
return x if x
|
|
993
|
+
$log.warn "getchar: window.rb 1200 Found no mapping for #{buff} "
|
|
994
|
+
return buff # otherwise caught in loop ???
|
|
995
|
+
elsif k > -1
|
|
996
|
+
buff += k.chr
|
|
997
|
+
# this is an alt/meta code. All other complex codes seem to have a [ after the escape
|
|
998
|
+
# so we will keep accumulating them.
|
|
999
|
+
# NOTE this still means that user can press Alt-[ and some letter in quick succession
|
|
1000
|
+
# and it will accumulate rather than be interpreted as M-[.
|
|
1001
|
+
#
|
|
1002
|
+
if buff.length == 2 and k.chr != '['
|
|
1003
|
+
x = _evaluate_buff buff
|
|
1004
|
+
return x if x
|
|
1005
|
+
end
|
|
1006
|
+
#$log.debug "XXX: getchar adding #{k}, #{k.chr} to buff #{buff} "
|
|
1007
|
+
else
|
|
1008
|
+
# it is -1 so evaluate
|
|
1009
|
+
x = _evaluate_buff buff
|
|
1010
|
+
return x if x
|
|
1011
|
+
return buff
|
|
1012
|
+
end
|
|
1013
|
+
end
|
|
1014
|
+
end
|
|
1015
|
+
|
|
1016
|
+
# what if keyname does not return anything
|
|
1017
|
+
if c > 127
|
|
1018
|
+
#$log.info "xxxgetchar: window.rb sending #{c} "
|
|
1019
|
+
ch = FFI::NCurses::keyname(c)
|
|
1020
|
+
# remove those ugly brackets around function keys
|
|
1021
|
+
if ch && ch[-1]==')'
|
|
1022
|
+
ch = ch.gsub(/[()]/,'')
|
|
1023
|
+
end
|
|
1024
|
+
return ch if ch
|
|
1025
|
+
$log.warn "getchar: window.rb 1234 Found no mapping for #{c} "
|
|
1026
|
+
return c
|
|
1027
|
+
end
|
|
1028
|
+
return c.chr if c
|
|
1029
|
+
end # -- }}}
|
|
1030
|
+
=end
|
|
1031
|
+
|
|
1032
|
+
# Generate and return an int for a newkey which user has specified in yml file.
|
|
1033
|
+
# We use hash, which won't allow me to derive key string
|
|
1034
|
+
# in case loop user can do:
|
|
1035
|
+
# when KEY_ENTER
|
|
1036
|
+
# when 32
|
|
1037
|
+
# when $kh_int["S-F2"]
|
|
1038
|
+
def _get_int_for_newkey x
|
|
1039
|
+
# FIXME put the declaration somewhere else maybe in window cons ???
|
|
1040
|
+
y = $kh_int[x]
|
|
1041
|
+
# when i give user the hash, he can get the string back ???
|
|
1042
|
+
$kh_int[y] = x unless $kh_int.key? y
|
|
1043
|
+
return y
|
|
1044
|
+
end
|
|
1045
|
+
# check buffer if some key mapped in global kh for this
|
|
1046
|
+
# Otherwise if it is 2 keys then it is a Meta key
|
|
1047
|
+
# Can return nil if no mapping
|
|
1048
|
+
# @return [String] string code for key (since it is mostly from $kh. Also sets, $key_int
|
|
1049
|
+
private
|
|
1050
|
+
def _evaluate_buff buff
|
|
1051
|
+
if buff == 27.chr
|
|
1052
|
+
$key_int = 27
|
|
1053
|
+
#$escend = Time.now.to_f
|
|
1054
|
+
#elapsed = ($escend - $escstart)*1000
|
|
1055
|
+
#$log.debug " #{elapsed} evaluated to ESC"
|
|
1056
|
+
$key_chr = "<ESC>"
|
|
1057
|
+
return $key_chr
|
|
1058
|
+
end
|
|
1059
|
+
x=$kh[buff]
|
|
1060
|
+
if x
|
|
1061
|
+
$key_int = 9999
|
|
1062
|
+
$key_int = _get_int_for_newkey(x)
|
|
1063
|
+
$key_cache[$key_int] = x unless $key_cache.key? $key_int
|
|
1064
|
+
# FIXME currently 9999 signifies unknown key, but since this is derived from a user list
|
|
1065
|
+
# we could have some dummy number being passed or set by user too.
|
|
1066
|
+
return "<#{x}>"
|
|
1067
|
+
end
|
|
1068
|
+
#$log.debug "XXX: getchar returning with #{buff}"
|
|
1069
|
+
if buff.size == 2
|
|
1070
|
+
## possibly a meta/alt char
|
|
1071
|
+
k = buff[-1]
|
|
1072
|
+
$key_int = 128 + k.ord
|
|
1073
|
+
return key_tos( $key_int )
|
|
1074
|
+
end
|
|
1075
|
+
$key_int = 99999
|
|
1076
|
+
nil
|
|
1077
|
+
end
|
|
1078
|
+
|
|
1079
|
+
end # class DefaultKeyReader -- }}}
|
|
1080
|
+
|
|
1081
|
+
end
|