ppcurses 0.0.25 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.rdoc +50 -11
- data/lib/ppcurses/Screen.rb +128 -15
- data/lib/ppcurses/actions/BaseAction.rb +1 -2
- data/lib/ppcurses/actions/GetBooleanAction.rb +6 -6
- data/lib/ppcurses/actions/GetDataAction.rb +4 -4
- data/lib/ppcurses/actions/GetEnumeratedStringAction.rb +6 -6
- data/lib/ppcurses/actions/GetIntegerAction.rb +2 -2
- data/lib/ppcurses/actions/GetStringAction.rb +2 -0
- data/lib/ppcurses/actions/PromptAction.rb +2 -2
- data/lib/ppcurses/application.rb +219 -0
- data/lib/ppcurses/date/meta_month.rb +139 -0
- data/lib/ppcurses/form/button.rb +120 -0
- data/lib/ppcurses/form/combo_box.rb +93 -0
- data/lib/ppcurses/form/date_picker.rb +86 -0
- data/lib/ppcurses/form/form.rb +96 -0
- data/lib/ppcurses/form/input_element.rb +189 -0
- data/lib/ppcurses/form/radio_button_group.rb +56 -0
- data/lib/ppcurses/geometry.rb +23 -0
- data/lib/ppcurses/menu/BaseMenu.rb +8 -14
- data/lib/ppcurses/menu/Menu.rb +5 -8
- data/lib/ppcurses/menu/RadioMenu.rb +2 -5
- data/lib/ppcurses/menu/choice_menu.rb +33 -0
- data/lib/ppcurses/menu/date_menu.rb +97 -0
- data/lib/ppcurses/menu_bar.rb +102 -0
- data/lib/ppcurses/table_view.rb +58 -0
- data/lib/ppcurses/view.rb +45 -0
- data/lib/ppcurses/window/pp_window.rb +42 -0
- data/lib/ppcurses.rb +57 -3
- data/test/application/create_application.rb +23 -0
- data/test/date/printMetaMonth.rb +30 -0
- data/test/form/menu_opens_form.rb +15 -0
- data/test/form/simple_form.rb +48 -0
- data/test/form/test_combo.rb +20 -0
- data/test/form/test_date_picker.rb +19 -0
- data/test/getBooleanAction.rb +1 -1
- data/test/getDataAction.rb +6 -6
- data/test/getEnumStringAction.rb +4 -4
- data/test/getIntegerAction.rb +4 -4
- data/test/menu/changeMenuBorder.rb +1 -1
- data/test/menu/compositeMenu.rb +2 -2
- data/test/menu/displayMenu.rb +1 -1
- data/test/raw_screen/display_colours.rb +69 -0
- data/test/raw_screen/press_a_key.rb +18 -0
- data/test/table_view/testTableView.rb +16 -0
- data/test/threads/block_test.rb +63 -0
- data/test/threads/handle_resize.rb +43 -0
- metadata +37 -12
- data/lib/ppcurses/Constants.rb +0 -8
@@ -0,0 +1,139 @@
|
|
1
|
+
|
2
|
+
def group(xs, n)
|
3
|
+
(0..xs.size / n - 1).collect { |i| xs[i * n, n] } # / This comment fixes a Visual Studio Code highlighting bug
|
4
|
+
end
|
5
|
+
|
6
|
+
# --------------------------------------------------------------------------
|
7
|
+
# This algorithm is based on ref/cal.rb by Tadayoshi Funaba
|
8
|
+
#
|
9
|
+
# Differences:
|
10
|
+
# - Only supports a monthly calendar type; no yearly calendar.
|
11
|
+
#
|
12
|
+
# - Returns a secondary day position array that specifies the row
|
13
|
+
# and column for each day of the month. Useful for highlighting a
|
14
|
+
# specific day.
|
15
|
+
#
|
16
|
+
# Example day position array for May 2015. The 1st of February
|
17
|
+
# occurs in the second row and the 16th column of the returned
|
18
|
+
# string calendar array
|
19
|
+
#
|
20
|
+
# day_pos = [ nil, [2,16], [2,19],
|
21
|
+
# [3,1], [3,4], [3,7], [3,10], [3,13], [3,16], [3,19],
|
22
|
+
# [4,0], [4,3], [4,6], [4,9], [4,12], [4,15], [4,18],
|
23
|
+
# [5,0], [5,3], [5,6], [5,9], [5,12], [5,15], [5,18],
|
24
|
+
# [6,0], [6,3], [6,6], [6,9], [6,12], [6,15], [6,18],
|
25
|
+
# [7,0] ]
|
26
|
+
#
|
27
|
+
#
|
28
|
+
# - Takes a Date object as initial parameter
|
29
|
+
#
|
30
|
+
# - K variable eliminated
|
31
|
+
#
|
32
|
+
# - Does not support the transformation option
|
33
|
+
#
|
34
|
+
#
|
35
|
+
def pict(day)
|
36
|
+
|
37
|
+
year = day.year
|
38
|
+
month = day.month
|
39
|
+
|
40
|
+
dw = 2 # Day width
|
41
|
+
mw = (dw + 1) * 7 - 1 # Month width
|
42
|
+
day_pos = [ nil ] # Create an array indexed by 1 by putting nil in slot zero.
|
43
|
+
|
44
|
+
# First day of the month e.g. 2015-05-01
|
45
|
+
fi = Date.new(year, month, 1, Date::GREGORIAN)
|
46
|
+
# Go backwards to the earliest closest day divisible by 7 date, e.g. 2015-04-26,
|
47
|
+
# using the Julian day number and modulus.
|
48
|
+
fi -= (fi.jd + 1) % 7
|
49
|
+
|
50
|
+
ve = (fi..fi + 6).collect{ |cu|
|
51
|
+
%w(S M Tu W Th F S)[cu.wday]
|
52
|
+
}
|
53
|
+
|
54
|
+
row = 1
|
55
|
+
pos = -1
|
56
|
+
# Creates an array of values ["S", " M", ... "31"]
|
57
|
+
ve += (fi..fi + 41).collect{ |cu| # of type Date
|
58
|
+
|
59
|
+
pos += 1 # Needed for meta info
|
60
|
+
if (cu.jd + 1) % 7 == 0 then
|
61
|
+
row += 1
|
62
|
+
pos = 0
|
63
|
+
end
|
64
|
+
|
65
|
+
if cu.mon == month then
|
66
|
+
|
67
|
+
# -------- Save meta information in day_pos array
|
68
|
+
i = pos * 3
|
69
|
+
if cu.mday < 10 then i += 1 end
|
70
|
+
|
71
|
+
day_pos.push [row, i]
|
72
|
+
# --------- End Meta info ------------------
|
73
|
+
|
74
|
+
cu.mday
|
75
|
+
end.to_s
|
76
|
+
|
77
|
+
}
|
78
|
+
|
79
|
+
# adds padding based on day width "1" --> " 1"
|
80
|
+
ve = ve.collect{|e| e.rjust(dw)}
|
81
|
+
|
82
|
+
# Creates an array of arrays. 7 for the days in the week
|
83
|
+
gr = group(ve, 7)
|
84
|
+
|
85
|
+
# Converts inner arrays to strings
|
86
|
+
ta = gr.collect{|xs| xs.join(' ')}
|
87
|
+
|
88
|
+
# Adds month/year header to top
|
89
|
+
ca = %w(January February March April May June July
|
90
|
+
August September October November December)[month - 1]
|
91
|
+
ca = ca + ' ' + year.to_s
|
92
|
+
ca = ca.center(mw)
|
93
|
+
ta.unshift(ca)
|
94
|
+
|
95
|
+
return ta, day_pos
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
module PPCurses
|
101
|
+
|
102
|
+
|
103
|
+
# A container object that holds:
|
104
|
+
#
|
105
|
+
# - A date object
|
106
|
+
# - The month the day belongs to in string array format
|
107
|
+
# - The row and column position of the date in the string array
|
108
|
+
#
|
109
|
+
# This container is used for displaying dates in the datepicker.
|
110
|
+
# The row and column position are necessary so that the day
|
111
|
+
# selected can be highlighted.
|
112
|
+
#
|
113
|
+
class MetaMonth
|
114
|
+
|
115
|
+
attr_accessor :day
|
116
|
+
attr_accessor :month_str_array
|
117
|
+
attr_accessor :day_pos
|
118
|
+
|
119
|
+
def initialize(day=Date.today)
|
120
|
+
self.day = day
|
121
|
+
end
|
122
|
+
|
123
|
+
def day=(new_day)
|
124
|
+
@day = new_day
|
125
|
+
@month_str_array, @day_pos = pict(@day)
|
126
|
+
end
|
127
|
+
|
128
|
+
def day_row
|
129
|
+
@day_pos[ @day.day ][0]
|
130
|
+
end
|
131
|
+
|
132
|
+
def day_col
|
133
|
+
@day_pos[ @day.day ][1]
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module PPCurses
|
2
|
+
|
3
|
+
class Button < View
|
4
|
+
|
5
|
+
attr_accessor :label
|
6
|
+
attr_accessor :selected
|
7
|
+
attr_accessor :pushed
|
8
|
+
|
9
|
+
attr_accessor :action
|
10
|
+
|
11
|
+
def initialize(label)
|
12
|
+
@label = label
|
13
|
+
@selected = false
|
14
|
+
@pushed = false
|
15
|
+
end
|
16
|
+
|
17
|
+
#
|
18
|
+
# Screen should be of type Curses::Window
|
19
|
+
#
|
20
|
+
def show(screen)
|
21
|
+
screen.attron(Curses::A_REVERSE) if @selected
|
22
|
+
screen.addstr("< #{@label} >")
|
23
|
+
screen.attroff(Curses::A_REVERSE) if @selected
|
24
|
+
end
|
25
|
+
|
26
|
+
def width
|
27
|
+
@label.length + 4
|
28
|
+
end
|
29
|
+
|
30
|
+
def height
|
31
|
+
1
|
32
|
+
end
|
33
|
+
|
34
|
+
def set_curs_pos(screen)
|
35
|
+
Curses.curs_set(INVISIBLE)
|
36
|
+
end
|
37
|
+
|
38
|
+
def key_down( key )
|
39
|
+
|
40
|
+
if key == ENTER
|
41
|
+
@action.call unless action.nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
# For grouping two buttons together, i.e. SUBMIT/CANCEL
|
52
|
+
class ButtonPair < View
|
53
|
+
|
54
|
+
attr_accessor :selected
|
55
|
+
attr_accessor :selected_element
|
56
|
+
|
57
|
+
attr_reader :button1
|
58
|
+
attr_reader :button2
|
59
|
+
|
60
|
+
def initialize(button1_label, button2_label)
|
61
|
+
@button1 = Button.new(button1_label)
|
62
|
+
@button2 = Button.new(button2_label)
|
63
|
+
|
64
|
+
@selected_button = @button1
|
65
|
+
|
66
|
+
@selected = false
|
67
|
+
end
|
68
|
+
|
69
|
+
def selected=(val)
|
70
|
+
@selected_button.selected = val
|
71
|
+
@selected=val
|
72
|
+
end
|
73
|
+
|
74
|
+
def height
|
75
|
+
1
|
76
|
+
end
|
77
|
+
|
78
|
+
def set_curs_pos(screen)
|
79
|
+
Curses.curs_set(INVISIBLE)
|
80
|
+
end
|
81
|
+
|
82
|
+
def key_down( key )
|
83
|
+
if key == KEY_RIGHT or key == KEY_LEFT
|
84
|
+
@selected_button.selected=false
|
85
|
+
|
86
|
+
if @selected_button == @button1
|
87
|
+
@selected_button = @button2
|
88
|
+
else
|
89
|
+
@selected_button = @button1
|
90
|
+
end
|
91
|
+
|
92
|
+
@selected_button.selected=true
|
93
|
+
return
|
94
|
+
end
|
95
|
+
|
96
|
+
@selected_button.key_down(key)
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
def show(screen)
|
101
|
+
|
102
|
+
p = screen.cur_point
|
103
|
+
p.y+=1
|
104
|
+
screen.set_pos_by_point(p)
|
105
|
+
|
106
|
+
|
107
|
+
@button1.show(screen)
|
108
|
+
|
109
|
+
p.x += @button1.width + 2
|
110
|
+
screen.set_pos_by_point(p)
|
111
|
+
|
112
|
+
@button2.show(screen)
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
|
120
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
module PPCurses
|
4
|
+
|
5
|
+
class ComboBox < View
|
6
|
+
|
7
|
+
DOWN_ARROW = '∇'
|
8
|
+
|
9
|
+
# Does the element have focus in the form?
|
10
|
+
attr_accessor :selected
|
11
|
+
|
12
|
+
|
13
|
+
def initialize(label, options)
|
14
|
+
@label = label
|
15
|
+
@options = options
|
16
|
+
|
17
|
+
@display_width = 13
|
18
|
+
@choice_made = false
|
19
|
+
|
20
|
+
@options.each do |option|
|
21
|
+
if option.length > @display_width
|
22
|
+
@display_width = option.length
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def show(screen)
|
29
|
+
screen.attron(A_REVERSE) if @selected
|
30
|
+
screen.addstr("#{@label}:")
|
31
|
+
|
32
|
+
@combo_display_point = screen.cur_point
|
33
|
+
|
34
|
+
screen.attroff(A_REVERSE) if @selected
|
35
|
+
|
36
|
+
screen.addstr(display_string)
|
37
|
+
end
|
38
|
+
|
39
|
+
def height
|
40
|
+
1
|
41
|
+
end
|
42
|
+
|
43
|
+
def set_curs_pos(screen)
|
44
|
+
screen.curs_set(INVISIBLE)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Return Value
|
48
|
+
# The object in the receiver's internal item list corresponding to the last item selected
|
49
|
+
# from the pop-up list, or nil if no item is selected.
|
50
|
+
def object_value_of_selected_item
|
51
|
+
if @options_menu.nil?
|
52
|
+
return nil
|
53
|
+
end
|
54
|
+
|
55
|
+
@options[@options_menu.selection]
|
56
|
+
end
|
57
|
+
|
58
|
+
def key_down(key)
|
59
|
+
|
60
|
+
if key == ENTER
|
61
|
+
|
62
|
+
if @options_menu.nil?
|
63
|
+
@options_menu = PPCurses::ChoiceMenu.new( @options )
|
64
|
+
end
|
65
|
+
|
66
|
+
@options_menu.set_origin(@combo_display_point)
|
67
|
+
|
68
|
+
@options_menu.show
|
69
|
+
@options_menu.menu_selection
|
70
|
+
|
71
|
+
if @options_menu.pressed_enter
|
72
|
+
@choice_made = true
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
#------------------------------------------------
|
80
|
+
protected
|
81
|
+
def display_string
|
82
|
+
if @choice_made
|
83
|
+
return ' '+ "#{@options[@options_menu.selection].center(@display_width,'-')} #{DOWN_ARROW}"
|
84
|
+
end
|
85
|
+
|
86
|
+
' ' + ' select '.center(@display_width,'-') + " #{DOWN_ARROW}"
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
module PPCurses
|
4
|
+
|
5
|
+
|
6
|
+
# Ruby date objects are immutable
|
7
|
+
# ---------------------------------
|
8
|
+
# 09-15-1950
|
9
|
+
# 05-04-2015 = May 4th 2015
|
10
|
+
class DatePicker < View
|
11
|
+
|
12
|
+
DOWN_ARROW = '∇'
|
13
|
+
|
14
|
+
# Does the element have focus in the form?
|
15
|
+
attr_accessor :selected
|
16
|
+
|
17
|
+
|
18
|
+
def initialize(label, initial_date = Date.today)
|
19
|
+
@label = label
|
20
|
+
@display_width = 13
|
21
|
+
@date = initial_date
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def show(screen)
|
26
|
+
screen.attron(A_REVERSE) if @selected
|
27
|
+
screen.addstr("#{@label}:")
|
28
|
+
|
29
|
+
@combo_display_point = screen.cur_point
|
30
|
+
|
31
|
+
screen.attroff(A_REVERSE) if @selected
|
32
|
+
|
33
|
+
screen.addstr(display_string)
|
34
|
+
end
|
35
|
+
|
36
|
+
def height
|
37
|
+
1
|
38
|
+
end
|
39
|
+
|
40
|
+
def set_curs_pos(screen)
|
41
|
+
screen.curs_set(INVISIBLE)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Return Value
|
45
|
+
# The object in the receiver's internal item list corresponding to the last item selected
|
46
|
+
# from the pop-up list, or nil if no item is selected.
|
47
|
+
def object_value_of_selected_item
|
48
|
+
if @options_menu.nil?
|
49
|
+
return nil
|
50
|
+
end
|
51
|
+
|
52
|
+
@options[@options_menu.selection]
|
53
|
+
end
|
54
|
+
|
55
|
+
def key_down(key)
|
56
|
+
|
57
|
+
if key == ENTER
|
58
|
+
|
59
|
+
if @date_menu.nil?
|
60
|
+
@date_menu = PPCurses::DateMenu.new(@date)
|
61
|
+
end
|
62
|
+
|
63
|
+
@date_menu.set_origin(@combo_display_point)
|
64
|
+
|
65
|
+
@date_menu.show
|
66
|
+
@date_menu.menu_selection
|
67
|
+
|
68
|
+
if @date_menu.pressed_enter
|
69
|
+
@date = @date_menu.day
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
#------------------------------------------------
|
77
|
+
protected
|
78
|
+
def display_string
|
79
|
+
" #{@date.month}-#{@date.day}-#{@date.year} #{DOWN_ARROW}"
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module PPCurses
|
2
|
+
|
3
|
+
class Form < View
|
4
|
+
|
5
|
+
attr_accessor :selected_element
|
6
|
+
|
7
|
+
#
|
8
|
+
# Screen should be of type Curses::Window
|
9
|
+
#
|
10
|
+
def initialize
|
11
|
+
@elements = []
|
12
|
+
end
|
13
|
+
|
14
|
+
# Formal protocol required
|
15
|
+
# Adds an element to the form. Elements are rendered in the order they are added.
|
16
|
+
#
|
17
|
+
# An element must implement the following protocol:
|
18
|
+
#
|
19
|
+
# - def show(screen)
|
20
|
+
# - def height
|
21
|
+
# - def set_curs_pos(screen)
|
22
|
+
# - def key_down(key)
|
23
|
+
# - def selected=
|
24
|
+
#
|
25
|
+
def add (element)
|
26
|
+
PPCurses.implements_protocol( element, %w(show height set_curs_pos key_down selected=))
|
27
|
+
@elements.push(element)
|
28
|
+
|
29
|
+
if @selected_element.nil?
|
30
|
+
set_selected_element(@elements[0])
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def submitted?
|
37
|
+
@button_pair.button1.pushed
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def key_down( key )
|
42
|
+
|
43
|
+
if key == KEY_UP or key == KEY_DOWN or key == TAB
|
44
|
+
selected_index = @elements.index(@selected_element)
|
45
|
+
n_choices = @elements.length
|
46
|
+
|
47
|
+
if key == KEY_DOWN or key == TAB
|
48
|
+
(selected_index == n_choices-1) ? next_selection = 0 : next_selection = selected_index + 1
|
49
|
+
else
|
50
|
+
(selected_index == 0) ? next_selection = n_choices - 1 : next_selection = selected_index - 1
|
51
|
+
end
|
52
|
+
|
53
|
+
set_selected_element(@elements[next_selection])
|
54
|
+
return
|
55
|
+
end
|
56
|
+
|
57
|
+
@selected_element.key_down(key)
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
# TODO -- call display of subview???
|
63
|
+
def display(screen)
|
64
|
+
y = 1
|
65
|
+
x = 1
|
66
|
+
|
67
|
+
for i in 0..@elements.length - 1
|
68
|
+
element = @elements[i]
|
69
|
+
screen.setpos(y, x)
|
70
|
+
element.show(screen)
|
71
|
+
y += element.height
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
@selected_element.set_curs_pos(screen) unless @selected_element.nil?
|
76
|
+
end
|
77
|
+
|
78
|
+
# --------------------------------------------------------------------------------
|
79
|
+
protected
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
def set_selected_element(new_element)
|
84
|
+
|
85
|
+
unless @selected_element.nil?
|
86
|
+
@selected_element.selected=false
|
87
|
+
end
|
88
|
+
|
89
|
+
@selected_element = new_element
|
90
|
+
@selected_element.selected=true
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
module PPCurses
|
2
|
+
|
3
|
+
class InputElement < View
|
4
|
+
|
5
|
+
attr_accessor :label
|
6
|
+
attr_accessor :value
|
7
|
+
attr_accessor :size
|
8
|
+
attr_accessor :selected
|
9
|
+
|
10
|
+
attr_accessor :filter
|
11
|
+
|
12
|
+
attr_accessor :value_start_point
|
13
|
+
|
14
|
+
|
15
|
+
# Stores the X location of the cursor relative to the
|
16
|
+
# value being displayed. If the cursor is in
|
17
|
+
# the middle of the string then subsequent keys
|
18
|
+
# will be added from this location, etc.
|
19
|
+
attr_accessor :cursor_location
|
20
|
+
|
21
|
+
|
22
|
+
def initialize(label, size )
|
23
|
+
@label = label
|
24
|
+
@size = size
|
25
|
+
@selected = false
|
26
|
+
@value = ''
|
27
|
+
@cursor_location = 0
|
28
|
+
@filter = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
# Creates an InputElement that only allows integer input
|
32
|
+
#
|
33
|
+
def InputElement.new_integer_only( label, size)
|
34
|
+
i_only = PPCurses::InputElement.new(label, size)
|
35
|
+
i_only.filter =PPCurses::NumberFilter.new
|
36
|
+
i_only
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def show(screen)
|
41
|
+
print_label( screen )
|
42
|
+
|
43
|
+
@value_start_point = screen.cur_point
|
44
|
+
|
45
|
+
print_value( screen )
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
def key_down( key )
|
51
|
+
if key == DELETE
|
52
|
+
handle_delete
|
53
|
+
return
|
54
|
+
end
|
55
|
+
|
56
|
+
if key == KEY_LEFT
|
57
|
+
@cursor_location -= 1 unless @cursor_location == 0
|
58
|
+
return
|
59
|
+
end
|
60
|
+
|
61
|
+
if key == KEY_RIGHT
|
62
|
+
@cursor_location += 1 unless @cursor_location == @value.length
|
63
|
+
return
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
# Ignore control characters
|
68
|
+
if key.is_a?(Fixnum)
|
69
|
+
return
|
70
|
+
end
|
71
|
+
|
72
|
+
# Adding new characters to the string
|
73
|
+
|
74
|
+
# Check size of string before adding another character
|
75
|
+
if @value.length >= @size
|
76
|
+
# Ignore input
|
77
|
+
return
|
78
|
+
end
|
79
|
+
|
80
|
+
unless passes_filter(key)
|
81
|
+
return
|
82
|
+
end
|
83
|
+
|
84
|
+
add_character(key)
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def passes_filter( key )
|
90
|
+
if @filter.nil?
|
91
|
+
return true
|
92
|
+
end
|
93
|
+
|
94
|
+
@filter.passes_filter( key )
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
def set_curs_pos(screen)
|
99
|
+
Curses.curs_set(VISIBLE)
|
100
|
+
x = @value_start_point.x + @cursor_location
|
101
|
+
|
102
|
+
screen.setpos( @value_start_point.y, x )
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
def height
|
107
|
+
1
|
108
|
+
end
|
109
|
+
|
110
|
+
# --------------------------------------------------------------------------------
|
111
|
+
protected
|
112
|
+
|
113
|
+
|
114
|
+
def print_label( screen )
|
115
|
+
screen.attron(Curses::A_REVERSE) if @selected
|
116
|
+
screen.addstr("#{@label}:")
|
117
|
+
screen.attroff(Curses::A_REVERSE) if @selected
|
118
|
+
screen.addstr(' ')
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
def print_value( screen )
|
123
|
+
screen.attron(Curses::A_UNDERLINE)
|
124
|
+
screen.addstr(@value.ljust(@size))
|
125
|
+
screen.attroff(Curses::A_UNDERLINE)
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
def handle_delete
|
130
|
+
# Cursor is at the front of the string, nothing in
|
131
|
+
# front of it to delete, or there is nothing to delete
|
132
|
+
if @cursor_location == 0 or @value.length == 0
|
133
|
+
return
|
134
|
+
end
|
135
|
+
|
136
|
+
if @value.length == 1
|
137
|
+
@value = ''
|
138
|
+
@cursor_location = 0
|
139
|
+
return
|
140
|
+
end
|
141
|
+
|
142
|
+
# Cursor is at the end of the string, remove the last character
|
143
|
+
if @cursor_location == @value.length
|
144
|
+
@value = @value.slice(0..@cursor_location-2)
|
145
|
+
elsif @cursor_location == 1
|
146
|
+
# cursor is right after the first character
|
147
|
+
@value = @value.slice(1..@value.length-1)
|
148
|
+
else
|
149
|
+
# Cursor is in the middle of the string, remove the character at the cursor location
|
150
|
+
# Example:
|
151
|
+
#
|
152
|
+
# abcdefg
|
153
|
+
# 1234567
|
154
|
+
# ^ -> cursor-location = 3
|
155
|
+
#
|
156
|
+
@value = @value.slice(0..@cursor_location-2) + @value.slice(@cursor_location..@value.length-1)
|
157
|
+
end
|
158
|
+
|
159
|
+
@cursor_location -= 1
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
def add_character ( char )
|
164
|
+
if @cursor_location == @value.length
|
165
|
+
@value += char
|
166
|
+
else
|
167
|
+
@value = @value.slice(0..@cursor_location-1) + char + @value.slice(@cursor_location..@value.length-1)
|
168
|
+
end
|
169
|
+
|
170
|
+
@cursor_location += 1
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
|
177
|
+
class NumberFilter
|
178
|
+
|
179
|
+
def passes_filter( key )
|
180
|
+
if key =~ /^\d+$/
|
181
|
+
return true
|
182
|
+
end
|
183
|
+
|
184
|
+
false
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|