ncumbra 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca4311543d96466d546a976b01991af75abb649575d862cd6d9c9b94bd7a3833
4
- data.tar.gz: 6f56247dc1b5dfd77cb1d8fa0de95b275010ca276906c3ec88ac8119b6df134b
3
+ metadata.gz: 0f50282711c7933882897af2adccae541d0b52eec92487c4d2ce2dda917a0eee
4
+ data.tar.gz: fe8fd6c63aa1c4eb16f08b1ae4f6018aea8484429886139b6aebe3c930fbc05d
5
5
  SHA512:
6
- metadata.gz: 749b3f931e2fbf3fc32176711207edb52f0794082f579b037f942a7e2cb47bdbd3136035faceb395f3f55015a9ec212c6ac7995a0d0e10197932e04e0c1bc4b4
7
- data.tar.gz: c0e1e0e7bf83fa0a16f91b26495ffb93823ba614f6216438337beb3ab31958775e79b240aab1277fdab2d03cec6c2279c405a95b811dd2be2b1c527412079374
6
+ metadata.gz: eb0e57a9cca233e75a136189ad0a428dbc226f99d4c05ff59d92801cbb1cce0494aaad604816c1bc59ba291dab2afd08a7920d986a387a080ae6cdb5ba38a418
7
+ data.tar.gz: a47df4fad81e54ee99cf340fde0808e5805a1c4dceb214a35f271ab41ca7d3313410ac6be1f76adb979b8709927af0cec1448b470229bf80acb135f56e1ea94f
data/CHANGELOG CHANGED
@@ -1,3 +1,6 @@
1
+ 2018-06-11
2
+ - for 0.1.4
3
+ - Search in multiline widgets
1
4
  2018-06-03
2
5
  - for 0.1.3
3
6
  - YARD Documentation of attr_property
data/README.md CHANGED
@@ -11,9 +11,13 @@ This is a stripped version of `canis` gem (ncurses ruby).
11
11
  - should be able to use a file or widget from here (in another application) without having to copy too much
12
12
  - should be able to understand one file without having to understand entire library
13
13
  - should be easy for others to change as per their needs, or copy parts.
14
+ - many portions of `Widget` and `Form` have been rewritten and simplified.
15
+
16
+ Documentation is at: https://www.rubydoc.info/gems/ncumbra
14
17
 
15
18
 
16
19
  ## Gem name
20
+
17
21
  The name `umbra` was taken, so had to change the gem name to `ncumbra` but the packages and structure etc remain umbra.
18
22
 
19
23
  ## Motivation for yet another ncurses library
@@ -22,6 +26,7 @@ This is a stripped version of `canis` gem (ncurses ruby).
22
26
  keeping parts as independent as possible.
23
27
 
24
28
  ## Future versions
29
+
25
30
  - Ampersand in Label and Button to signify shortcut/mnemonic.
26
31
  - combo list
27
32
  - 256 colors
@@ -212,6 +217,11 @@ The simplest widget in `Umbra` is the Label. Labels are used for a single line o
212
217
  title = Label.new( :text => "Demo of Labels", :row => 0, :col => 0 , :width => FFI::NCurses.COLS-1,
213
218
  :justify => :center, :color_pair => 0)
214
219
 
220
+ The next example prints a label on the last line stretching from left to right. It will be used in later examples for printing a message when some event is triggered.
221
+
222
+ message_label = Label.new row: -1, col: 0, width: -1, color_pair: CP_CYAN, text: "Messages will come here..."
223
+
224
+
215
225
  A `mnemonic` and related widget may be associated with a label. This `mnemonic` is a shortcut or hotkey for jumping directly to another which is specified by `related_widget`. The `related_widget` must be a focusable object such as a `Field` or `Listbox`. The `mnemonic` is displayed with bold and underlined attribute since underline may not work on some terminals. The Alt-key is to be pressed to jump directly to the field.
216
226
 
217
227
  ```ruby
@@ -224,25 +234,28 @@ The `width` has been specified as the size of the current screen. You may use a
224
234
 
225
235
  Now change the `width` to `-1`. Run the program again and stretch the window's width. What happens ? Negative widths and heights are re-calculated at the time of printing, so a change in width of the screen will immediately reflect in the label's width. A negative value for width or height means that the object must stretch or extend to that row or column from the end. Negative widths are thus relative to the right end of the window. Positive widths are absolute.
226
236
 
227
- The important methods of `Label` are:
237
+ The important properties of `Label` are:
228
238
 
229
239
  - `text` - may be changed at any time, and will immediately reflect
230
240
  - `row` - vertical position on screen (0 to FFI::NCurses.LINES-1). Can be negative for relative position.
231
241
  - `col` - horizontal position on screen (0 to FFI::NCurses.COLS-1)
232
242
  - `width` - defaults to length of `text` but can be larger or smaller. Can be negative.
233
- - `color_pair` - see details for creating colors.
243
+ - `color_pair` - see details for creating colors. e.g. `CP_GREEN` `CP_CYAN` `CP_MAGENTA`, etc.
234
244
  - `attr` : maybe `BOLD` , `NORMAL` , `REVERSE` or `UNDERLINE`
235
245
  - `justify` - `:right`, `:left` or `:center`
236
246
  - `related_widget` - editable or focusable widget associated with this label.
237
247
  - `mnemonic` - short-cut used to shift access to `related_widget`
238
- - `print_label` - override the usual printing of a label. A label usually prints in one colour and attribute (or combination of attributes. However, for any customized printing of a label, one can override this method at the instance level.
248
+
249
+ Label also has the following method/s:
250
+
251
+ - `print_label` - override the usual printing of a label. A label usually prints in one colour and attribute (or combination of attributes). However, for any customized printing of a label, one can override this method at the instance level. For an example of customized printing, see examples/extab3.rb.
239
252
 
240
253
  ### Field
241
254
 
242
255
  This is an entry field. Text may be edited in a `Field`. Various validations are possible. Custom validations may be specified.
243
256
 
244
257
  ```ruby
245
- w = Field.new( :name => "name", :row => 1, :col => 1 , :width => 50)
258
+ w = Field.new( name: "name", row: 1, col: 1, width: 50)
246
259
  w.color_pair = CP_CYAN
247
260
  w.attr = FFI::NCurses::A_REVERSE
248
261
  w.highlight_color_pair = CP_YELLOW
@@ -253,7 +266,7 @@ This is an entry field. Text may be edited in a `Field`. Various validations are
253
266
  The above example shows creation of an editable field. The field has been further customized to have a different color when it is in focus (highlighted).
254
267
 
255
268
 
256
- Other customizations of field are as follows:
269
+ Other examples of customizations of field are as follows:
257
270
  ```ruby
258
271
  w.chars_allowed = /[\w\+\.\@]/
259
272
  email.valid_regex = /\w+\@\w+\.\w+/
@@ -411,10 +424,8 @@ It adds the following properties to ToggleButton.
411
424
  `value` may be used to set the initial value, or retrieve the value at any time.
412
425
 
413
426
  ```ruby
414
- row = 10
415
- col = 10
416
- check = Checkbox.new text: "No Frames", value: true, row: row+1, col: col, mnemonic: "N"
417
- check1 = Checkbox.new text: "Use https", value: false, row: row+2, col: col, mnemonic: "U"
427
+ check = Checkbox.new text: "No Frames", value: true, row: 11, col: 10, mnemonic: "N"
428
+ check1 = Checkbox.new text: "Use https", value: false, row: 12, col: 10, mnemonic: "U"
418
429
  ```
419
430
 
420
431
  A code block may be attached to the clicking of checkboxes either using `command` or binding to `:PRESS`.
@@ -440,8 +451,8 @@ The above is similar to:
440
451
 
441
452
  ### RadioButton
442
453
 
443
- A +ToggleButton+ button that may have an on or off value. Usually, several related radio buttons are created and only one may be +on+.
444
- Here, we create a +ButtonGroup+ and then `add` radio buttons to it.
454
+ A `ToggleButton` button that may have an on or off value. Usually, several related radio buttons are created and only one may be _on_.
455
+ Here, we create a `ButtonGroup` and then `add` radio buttons to it.
445
456
 
446
457
  ```ruby
447
458
  radio1 = RadioButton.new text: "Red", value: "R", row: 5, col: 20
@@ -470,13 +481,13 @@ A ButtonGroup is a collection of RadioButtons.
470
481
 
471
482
  Methods:
472
483
 
473
- - `add` - add a +RadioButton+ to the group.
484
+ - `add` - add a `RadioButton` to the group.
474
485
  - `selection` - return the button that is selected
475
486
  - `value` - get the value of the selected button
476
487
  - `select?` - ask if given button is selected
477
- - `select` - select the given button
478
488
  - `elements` - get an array of buttons added
479
489
  - `command` - supply a block to be called whenever a button in the group is clicked.
490
+ - `select` - select the given button (simulate keypress programmatically)
480
491
 
481
492
 
482
493
  ```ruby
@@ -530,8 +541,8 @@ The `:CHANGED` event is fired whenever an array is passed to the `list=` method.
530
541
 
531
542
  In addition to arrow keys, one may use "j" and "k" for down and up. Other keys are:
532
543
 
533
- - "g" - first row
534
- - "G" - last row
544
+ - g - first row
545
+ - G - last row
535
546
  - C-d - scroll down
536
547
  - C-u - scroll up
537
548
  - C-b - scroll backward
@@ -786,7 +797,7 @@ An object's `bind_event` is used to attach a code block to an event.
786
797
 
787
798
  ### Key Bindings
788
799
 
789
- For an object, or for the form, keys may be bound to a code block. All functionality in the system is bound to a code block, making it possible to override provided behavior, although that is not recommended. Tab, backtab and Escape may not be over-ridden.
800
+ For an object, or for the form, keys may be bound to a code block. All functionality in this library is bound to a code block, making it possible to override provided behavior, although that is not recommended. Tab, backtab and Escape may not be over-ridden.
790
801
 
791
802
  form.bind_key(KEY_F1, "Help") { help() }
792
803
 
@@ -794,11 +805,20 @@ For an object, or for the form, keys may be bound to a code block. All functiona
794
805
 
795
806
  list.bind_key(FFI::NCurses::KEY_CTRL_A, 'cursor home') { cursor_home }
796
807
 
808
+ One may bind Control, Alt, Function and Shifted-Function keys in Umbra. However, multiple keys as in vim or emacs may not be bound. If you require mapping key combinations such as "gg" or "Ctrl-x x" then you should look at the canis gem.
809
+ You may also map the first key to a method that takes a second key. In such cases, it is better to popup a menu so the user knows that a second key is pending.
810
+
811
+ (Note: TAB and BACKTAB are hardcoded in form.rb for traversal, ESCAPE is hardcoded in field.rb. If a widget does not consume the ARROW keys, they may also be used for traversal by form.rb)
797
812
 
798
813
  ## More examples
799
814
 
800
815
  See examples directory for code samples for all widgets. Be sure the run all the examples to see the capabilities of the library and the widgets.
801
816
 
817
+ ## Testing
818
+
819
+ I have not found a way of automated testing for ncurses applications. Suggestions are welcome.
820
+ My way is of manually testing which is cumbersome, and that discourages rewrites, refactoring, etc.
821
+
802
822
  ## Contributing
803
823
 
804
824
  Please go through the source, and suggest improvements to the design and code.
@@ -64,6 +64,26 @@ module Umbra
64
64
  m.run
65
65
  end
66
66
 
67
+ def get_string label, config={}
68
+ require 'umbra/messagebox'
69
+ config[:title] ||= "Entry"
70
+ config[:buttons] ||= ["Ok", "Cancel"]
71
+ fld = nil
72
+ mb = MessageBox.new config do
73
+ add Label.new text: label, row: 2, col: 2
74
+ fld = Field.new name: "field", row: 3, col: 2
75
+ add fld
76
+ end
77
+ index = mb.run
78
+ if index == 0
79
+ return fld.text
80
+ else
81
+ return nil
82
+ end
83
+ end
84
+
85
+
86
+
67
87
  ## create a logger instance given a path, return the logger
68
88
  ## NOTE: Ideally would like to set $log here to this, but what if user creates multiple.
69
89
  def create_logger path, config={}
@@ -4,15 +4,17 @@
4
4
  # Author: j kepler http://github.com/mare-imbrium/canis/
5
5
  # Date: 2018-04-07
6
6
  # License: MIT
7
- # Last update: 2018-06-02 19:01
7
+ # Last update: 2018-06-03 14:50
8
8
  # ----------------------------------------------------------------------------- #
9
9
  # box.rb Copyright (C) 2018 j kepler
10
10
  module Umbra
11
11
  ##
12
12
  # A box is a container around one, or more, widgets.
13
- # Properties include #visible, #justify and #title.
13
+ # Properties include `visible,` `justify` and `title.`
14
+ # It is not focusable, so no keys can be mapped to it.
15
+ #
14
16
  ## FIXME box needs to resize components if it's dimensions are changed.
15
- ## Or should components have a link to parent, so they can resize themselves ?
17
+ ## Or should components have a link to parent, so they can resize themselves ?
16
18
  #
17
19
  class Box < Widget
18
20
  # @param title [String] set and return title of box
@@ -127,9 +129,10 @@ module Umbra
127
129
  @widget = w
128
130
  end
129
131
 
130
- ## paint a horizontal line, as a separator between widgets
131
- ## param [Integer] row - row
132
- ## param [Integer] col - column
132
+ ## Paint a horizontal line, as a separator between widgets
133
+ ## Called by `repaint`.
134
+ ## @param row [Integer] row
135
+ ## @param col [Integer] column
133
136
  def hline row, col
134
137
  return if row >= self.row + self.height
135
138
  $log.debug " hline: #{row} ... #{@row} #{@height} "
@@ -5,7 +5,7 @@ require 'umbra/multiline'
5
5
  # Author: j kepler http://github.com/mare-imbrium/umbra
6
6
  # Date: 2018-03-19
7
7
  # License: MIT
8
- # Last update: 2018-06-03 10:39
8
+ # Last update: 2018-06-07 09:35
9
9
  # ----------------------------------------------------------------------------- #
10
10
  # listbox.rb Copyright (C) 2012-2018 j kepler
11
11
  # == TODO
@@ -46,6 +46,7 @@ module Umbra
46
46
  #register_events([:LIST_SELECTION_EVENT])
47
47
  register_events([:SELECT_ROW])
48
48
  super
49
+ @search_offset = 1 # search has offset of 1, due to added mark
49
50
  end
50
51
 
51
52
 
@@ -6,11 +6,10 @@ require 'umbra/widget'
6
6
  # Author: j kepler http://github.com/mare-imbrium/canis/
7
7
  # Date: 2018-05-08 - 11:54
8
8
  # License: MIT
9
- # Last update: 2018-06-01 14:36
9
+ # Last update: 2018-06-10 10:50
10
10
  # ----------------------------------------------------------------------------- #
11
11
  # multiline.rb Copyright (C) 2012-2018 j kepler
12
12
  #
13
- ## TODO search through text and put cursor on next result.
14
13
  ## TODO allow setting of current_index programmatically
15
14
  ## TODO is a row visible. visible? row. and make a row visible. programmatically
16
15
  ## TODO insert delete a row (if editable)
@@ -26,6 +25,9 @@ module Umbra
26
25
 
27
26
  attr_reader :list # array containing data (usually Strings)
28
27
  attr_reader :panned_cols ## How may columns has widget panned to right
28
+ ## adjustment for searching for a pattern in a line, if adding text to start of string.
29
+ ## Example, listbox adds one char to start. One may override and add two.
30
+ attr_accessor :search_offset
29
31
 
30
32
  # index of focussed row, starting 0, index into the list supplied
31
33
  attr_reader :current_index
@@ -35,6 +37,7 @@ module Umbra
35
37
  @editable = false
36
38
  @pstart = 0 # which row does printing start from
37
39
  @current_index = 0 # index of row on which cursor is
40
+ @search_offset = 0 # search has no offset
38
41
 
39
42
  ## PRESS event relates to pressing RETURN/ENTER (10)
40
43
  register_events([:LEAVE_ROW, :ENTER_ROW, :PRESS])
@@ -277,6 +280,8 @@ module Umbra
277
280
  ## C-h was not working, so trying C-j
278
281
  bind_key(FFI::NCurses::KEY_CTRL_J, 'scroll_left') { scroll_left }
279
282
  bind_key(FFI::NCurses::KEY_CTRL_L, 'scroll_right') { scroll_right }
283
+ bind_key(?/, 'ask search') { ask_search }
284
+ bind_key(?n, 'next match ') { find_more }
280
285
  @keys_mapped = true
281
286
  end
282
287
 
@@ -514,12 +519,103 @@ module Umbra
514
519
  @current_index = line
515
520
  ensure_visible line
516
521
  end
522
+ #def each_line
523
+ #@list.each_with_index do |line, ix|
524
+ #line = self.value_of_row( line, ix, :NONE)
525
+ #yield line
526
+ #end
527
+ #end
528
+
529
+ ## Ask user for a pattern to look for in lines.
530
+ ## Put cursor on first match.
531
+ def ask_search
532
+ str = get_string("Search:")
533
+ return unless str
534
+ ix = next_match str
535
+ if ix
536
+ @current_index, @curpos = ix
537
+ set_col_offset @curpos ## why do we need to do this also
538
+ $log.debug " ask_search ci: #{@current_index} , #{@curpos} "
539
+ @last_regex = str
540
+ else
541
+ alert "Pattern not found: #{str}"
542
+ end
543
+ end
544
+
545
+ ## find more occurrences of match. This is bound to 'n' key.
546
+ def find_more
547
+ return unless @last_regex
548
+ str = @last_regex
549
+ $log.debug " FIND MORE last_regex is : #{@last_regex} "
550
+ ix = next_match @last_regex
551
+ #return unless ix
552
+ if ix
553
+ @current_index, @curpos = ix
554
+ set_col_offset @curpos ## why do we need to do this also
555
+ else
556
+ alert "No more matches for: #{str}"
557
+ end
558
+ end
559
+
560
+ ## find the first or next occurrence of a pattern
561
+ ## @param str [String] pattern to match
562
+ ## @param startline [Integer] line to start search on
563
+ ## @param curpos [Integer] cursor position to start search on
564
+ ## @param endline [Integer] line to end search on
565
+ def next_match str, startline = nil, _curpos = nil, endline = nil
566
+ return unless str
567
+
568
+ ## check current line for more occurrences.
569
+ if !startline
570
+ startline = @current_index
571
+ _curpos ||= (@curpos + 1) # FIXME +1 should only happen if a search has already happened
572
+ #_pos = @list[startline].index(str, _curpos)
573
+ _pos = to_searchable(startline).index(str, _curpos)
574
+ return [startline, _pos + search_offset] if _pos
575
+ startline += 1
576
+ end
577
+ ## Check rest of file
578
+ ## loop through array, check after startline to eof
579
+ @list.each_with_index do | line, ix|
580
+ next if ix < startline
581
+ break if endline && ix > endline
582
+ #_found = line.index(str)
583
+ _found = to_searchable(ix).index(str)
584
+ #$log.debug " next_match: #{line}: #{_found} " if _found
585
+ return [ix, _found + search_offset] if _found
586
+ end
587
+ if startline > 0
588
+ # this can get called again since startline was made 1 in above block. FIXME
589
+ #return next_match str, 0, @current_index
590
+ end
591
+ return nil
592
+ end
593
+
594
+
595
+ ## This needs to be overridden in case of lists that contain something other than
596
+ ## `String` as their elements. In such a case, `search_offset` may need to be adjusted also.
597
+ ## @param index [Integer] offset of row in list
598
+ ## @return [String] searchable representation of list element at `index`
599
+ def to_searchable index
600
+ s = @list[index]
601
+ case s
602
+ when String
603
+ return s ## return the string as is.
604
+ when Array
605
+ ## may need to be overridden by caller
606
+ return s.join(" ")
607
+ else
608
+ raise "Don't know how to handle this datatype, please override to_searchable"
609
+ end
610
+ end
611
+
517
612
 
518
613
  ## UNTESTED
519
614
  def delete_at index
520
615
  return unless @list
521
616
  return unless @editable
522
- @repaint_all = true
617
+ #@repaint_all = true
618
+ @repaint_required = true
523
619
  @list.delete_at index
524
620
  end
525
621
 
@@ -527,7 +623,8 @@ module Umbra
527
623
  def insert index, line
528
624
  return unless @list
529
625
  return unless @editable
530
- @repaint_all = true
626
+ #@repaint_all = true
627
+ @repaint_required = true
531
628
  @list.insert index, line
532
629
  end
533
630
 
@@ -4,28 +4,29 @@
4
4
  # Author: j kepler http://github.com/mare-imbrium/umbra/
5
5
  # Date: 2018-05-06 - 09:56
6
6
  # License: MIT
7
- # Last update: 2018-05-22 14:46
7
+ # Last update: 2018-06-03 14:43
8
8
  # ----------------------------------------------------------------------------- #
9
9
  # table.rb Copyright (C) 2018 j kepler
10
10
 
11
- ##--------- Todo section ---------------
12
- ## DONE w - next column, b - previous column
13
- ## TODO paint lines as column separators. issue is panning.
14
- ## TODO starting visual column (required when scrolling)
15
- ## DONE change a value value_at(x,y, value) ; << ; delete_at
16
- ## TODO change column width interactively, hide column , move column
17
- ## TODO maybe even column_color(n, color_pair, attr)
18
- ## TODO sort on column/s.
19
- ## TODO selection will have to be added. maybe we should have extended listbox after all. Or made multiline selectable.
20
- ## DONE how to format the header
21
- ## DONE formatting rows
22
- ## DONE if we want to color specific columns based on values then I think we have to format (render) the row at the last
11
+ =begin
12
+ ## --------- Todo section ---------------
13
+ ## - TODO paint lines as column separators. issue is panning.
14
+ ## - TODO starting visual column (required when scrolling)
15
+ ## - DONE change a value value_at(x,y, value) ; << ; delete_at
16
+ ## - TODO change column width interactively, hide column , move column
17
+ ## - TODO maybe even column_color(n, color_pair, attr)
18
+ ## - TODO sort on column/s.
19
+ ## - TODO selection will have to be added. maybe we should have extended listbox after all. Or made multiline selectable.
20
+ ## - DONE how to format the header
21
+ ## - DONE formatting rows
22
+ ## - DONE if we want to color specific columns based on values then I think we have to format (render) the row at the last
23
23
  ## moment in print_row and not in advance
24
- ## NOTE: we are setting the data in tabular, not list. So calling list() will give nil until a render has happened.
24
+ ## - NOTE: we are setting the data in tabular, not list. So calling list() will give nil until a render has happened.
25
25
  ## callers will have to use data() instead of list() which is not consistent.
26
- ## NOTE: current_index in this object refers to index including header and separator. It is not the offset in the data array.
26
+ ## - NOTE: current_index in this object refers to index including header and separator. It is not the offset in the data array.
27
27
  ## For that we need to adjust with @data_offset.
28
- #
28
+ =end
29
+
29
30
  require 'forwardable'
30
31
  require 'umbra/tabular'
31
32
  require 'umbra/multiline'
@@ -1,3 +1,3 @@
1
1
  module Umbra
2
- VERSION = "0.1.3"
2
+ VERSION = "0.1.4"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ncumbra
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - kepler
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-06-03 00:00:00.000000000 Z
11
+ date: 2018-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -137,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
137
  version: '0'
138
138
  requirements: []
139
139
  rubyforge_project:
140
- rubygems_version: 2.7.6
140
+ rubygems_version: 2.7.7
141
141
  signing_key:
142
142
  specification_version: 4
143
143
  summary: tiny ncurses library for creating simple apps. Stripped version of Canis.