Class: RubyCurses::App

Inherits:
Object show all
Includes:
WidgetShortcuts
Defined in:
lib/rbcurse/core/util/app.rb

Overview

This is the Application class which does the job of setting up the environment, and closing it at the end.

Instance Attribute Summary collapse

methods to create widgets easily collapse

positioning of components collapse

Instance Method Summary collapse

Methods included from WidgetShortcuts

#_configure, #_position, #app_header, #blank, #box, def_widget, #dock, #flow, #line, #link, #listbox, #menubar, #menulink, #radio, #stack, #tabular_widget, #textarea, #textview, #tree, #vimsplit, #widget_shortcuts_init

Constructor Details

#initialize(config = {}, &block) ⇒ App

TODO: i should be able to pass window coords here in config :title



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/rbcurse/core/util/app.rb', line 82

def initialize config={}, &block
  #$log.debug " inside constructor of APP #{config}  "
  @config = config


  widget_shortcuts_init
  #@app_row = @app_col = 0
  #@stack = [] # stack's coordinates
  #@flowstack = []
  @variables = {}
  # if we are creating child objects then we will not use outer form. this object will manage
  @current_object = [] 
  @_system_commands = %w{ bind_global bind_component field_help_text }

  init_vars
  $log.debug "XXX APP CONFIG: #{@config}  " if $log.debug? 
  run &block
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



73
74
75
# File 'lib/rbcurse/core/util/app.rb', line 73

def config
  @config
end

#formObject (readonly)

Returns the value of attribute form.



74
75
76
# File 'lib/rbcurse/core/util/app.rb', line 74

def form
  @form
end

#quit_key=(value) ⇒ Object (writeonly)

Sets the attribute quit_key

Parameters:

  • value

    the value to set the attribute quit_key to.



76
77
78
# File 'lib/rbcurse/core/util/app.rb', line 76

def quit_key=(value)
  @quit_key = value
end

#windowObject (readonly)

Returns the value of attribute window.



75
76
77
# File 'lib/rbcurse/core/util/app.rb', line 75

def window
  @window
end

Instance Method Details

#bind_componentObject



362
363
364
365
366
367
368
369
# File 'lib/rbcurse/core/util/app.rb', line 362

def bind_component
  #rb_puts "Todo. ", :color_pair => get_color($promptcolor, :red, :black)
  print_error_message "Todo this. "
  # the idea here is to get the current component
  # and bind some keys to some methods.
  # however, how do we divine the methods we can map to
  # and also in some cases the components itself has multiple components
end

#bind_globalObject

bind a key to a method at global (form) level Note that individual component may be overriding this. FIXME: why are we using rawmessage and then getchar when ask would suffice



320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/rbcurse/core/util/app.rb', line 320

def bind_global
  opts = get_all_commands
  cmd = rb_gets("Select a command (<tab> for choices) : ", opts)
  if cmd.nil? || cmd == ""
    rb_puts "Aborted."
    return
  end
  key = []
  str = ""
  #raw_message "Enter one or 2 keys. Finish with ENTER. Enter first key:"
  #ch = @window.getchar()
  #raw_message_destroy
  #if [KEY_ENTER, 10, 13, ?\C-g.getbyte(0)].include? ch
    #say_with_pause "Aborted."
    #return
  #end
  # the next is fine but does not allow user to enter a control or alt or function character
  # since it uses Field. It is fine if you want to force alphanum input
  ch = rb_getchar("Enter one or two keys. Finish with <ENTER>. Enter first key:")
  unless ch
    rb_puts "Aborted. <Press a key>"
    return
  end
  key << ch
  str << keycode_tos(ch)
  ch = rb_getchar  "Got #{str}. Enter second key or hit return:"
  unless ch
    rb_puts "Aborted. <Press a key>"
    return
  end
  if ch == KEY_ENTER || ch == 13
  else
    key << ch
    str << keycode_tos(ch)
  end
  if !key.empty?
    rb_puts "Binding #{cmd} to #{str}. "
    key = key[0] if key.size == 1
    #@form.bind_key(key, cmd.to_sym) # not finding it, getting called by that comp
    @form.bind_key(key){ send(cmd.to_sym) }
  end
end

#closeObject



120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/rbcurse/core/util/app.rb', line 120

def close
  raw_message_destroy
  $log.debug " INSIDE CLOSE, #{@stop_ncurses_on_close} "
  @window.destroy if !@window.nil?
  $log.debug " INSIDE CLOSE, #{@stop_ncurses_on_close} "
  if @stop_ncurses_on_close
    $tt.destroy if $tt  # added on 2011-10-9 since we created a window, but only hid it after use
    VER::stop_ncurses
    $log.debug " CLOSING NCURSES"
  end
  #p $error_message.value unless $error_message.value.nil?
  $log.debug " CLOSING APP"
  #end
end

#edit_table(*args, &block) ⇒ Object

table widget

Examples:

data = [["Roger",16,"SWI"], ["Phillip",1, "DEU"]]
colnames = ["Name", "Wins", "Place"]
t = table :width => 40, :height => 10, :columns => colnames, :data => data, :estimate_widths => true
  other options are :column_widths => [12,4,12]
  :size_to_fit => true


663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
# File 'lib/rbcurse/core/util/app.rb', line 663

def edit_table *args, &block # earlier table
  require 'rbcurse/extras/widgets/rtable'
  config = {}
  # TODO confirm events many more
  events = [ :ENTER_ROW,  :LEAVE, :ENTER ]
  block_event = events[0]
  _process_args args, config, block_event, events
  # if user is leaving out width, then we don't want it in config
  # else Widget will put a value of 10 as default, overriding what we've calculated
  if config.has_key? :display_length
    config[:width] = config[:display_length] unless config.has_key? :width
  end
  ext = config.delete :extended_keys

  model = nil
  _position(config)
  # if no width given, expand to flows width
  config[:width] ||= @stack.last.width if @stack.last
  w = Table.new @form, config
  if ext
    require 'rbcurse/extras/include/tableextended' 
      # so we can increase and decrease column width using keys
    w.extend TableExtended
    w.bind_key(?w){ w.next_column }
    w.bind_key(?b){ w.previous_column }
    w.bind_key(?+) { w.increase_column }
    w.bind_key(?-) { w.decrease_column }
    w.bind_key([?d, ?d]) { w.table_model.delete_at w.current_index }
    w.bind_key(?u) { w.table_model.undo w.current_index}
  end
  if block
    w.bind(block_event, &block)
  end
  return w
end

#field_help_textObject

displays help_text associated with field. 2011-10-15



371
372
373
374
375
376
377
378
379
380
# File 'lib/rbcurse/core/util/app.rb', line 371

def field_help_text
  f = @form.get_current_field
  if f.respond_to?('help_text')
    h = f.help_text
    h = "No help text defined for this field.\nTry F1, or press '?' for key-bindings." unless h
    textdialog "#{h}", :title => "Widget Help Text"
  else
    alert "Could not get field #{f} or does not respond to helptext. Try F1 or '?'"
  end
end

#get_all_commandsObject



310
311
312
313
314
315
316
# File 'lib/rbcurse/core/util/app.rb', line 310

def get_all_commands
  opts = @_system_commands.dup
  if respond_to? :get_commands
    opts.push(*get_commands())
  end
  opts
end

#get_bindingObject

used only by LiveConsole, if enables in an app, usually only during testing.



273
274
275
# File 'lib/rbcurse/core/util/app.rb', line 273

def get_binding
  return binding()
end

#get_command_from_user(choices = ["quit","help", "suspend", "shell_output"]) ⇒ Object

prompts user for a command. we need to get this back to the calling app or have some block stuff TODO Actually, this is naive, you would want to pass some values in like current data value or lines ?? Also may want command completion, or help so all commands can be displayed NOTE: This is gonna change very soon - 2012-01-8



387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
# File 'lib/rbcurse/core/util/app.rb', line 387

def get_command_from_user choices=["quit","help", "suspend", "shell_output"]
  @_command_history ||= Array.new
  str = rb_gets("Cmd: ", choices) { |q| q.default = @_previous_command; q.history = @_command_history }
          @_command_history << str unless @_command_history.include? str
  # shell the command
  if str =~ /^!/
    str = str[1..-1]
    suspend(false) { 
      #system(str); 
      $log.debug "XXX STR #{str}  " if $log.debug? 

      output=`#{str}`
      system("echo ' ' ");
      $log.debug "XXX output #{output} " if $log.debug? 
      system("echo '#{output}' ");
      system("echo Press Enter to continue.");
      system("read"); 
    }
    return nil # i think
  else
    # TODO
    # here's where we can take internal commands
    #alert "[#{str}] string did not match :!"
    str = str.to_s #= str[1..-1]
    cmdline = str.split
    cmd = cmdline.shift #.to_sym
    return unless cmd # added 2011-09-11 FFI
    f = @form.get_current_field
    if respond_to?(cmd, true)
      if cmd == "close"
        throw :close # other seg faults in del_panel window.destroy executes 2x
      else
        res = send cmd, *cmdline
      end
    elsif f.respond_to?(cmd, true)
      res = f.send(cmd, *cmdline)
    else
      alert "App: #{self.class} does not respond to #{cmd} "
      ret = false
      # what is this execute_this: some kind of general routine for all apps ?
      ret = execute_this(cmd, *cmdline) if respond_to?(:execute_this, true)
      rb_puts("#{self.class} does not respond to #{cmd} ", :color_pair => $promptcolor) unless ret
      # should be able to say in red as error
    end
  end
end

#hline(config = {}) ⇒ Object

displays a horizontal line takes col (column to start from) from current stack take row from app_row

requires width to be passed in config, else defaults to 20

Examples:

hline :width => 55  


720
721
722
723
724
725
726
727
728
729
730
731
# File 'lib/rbcurse/core/util/app.rb', line 720

def hline config={}
  row = config[:row] || @app_row
  width = config[:width] || 20
  _position config
  col = config[:col] || 1
  @color_pair = config[:color_pair] || $datacolor
  @attrib = config[:attrib] || Ncurses::A_NORMAL
  @window.attron(Ncurses.COLOR_PAIR(@color_pair) | @attrib)
  @window.mvwhline( row, col, FFI::NCurses::ACS_HLINE, width)
  @window.attron(Ncurses.COLOR_PAIR(@color_pair) | @attrib)
  @app_row += 1
end

#init_varsObject



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/rbcurse/core/util/app.rb', line 100

def init_vars
  @quit_key ||= FFI::NCurses::KEY_F10
  # actually this should be maintained inside ncurses pack, so not loaded 2 times.
  # this way if we call an app from existing program, App won't start ncurses.
  unless $ncurses_started
    init_ncurses
  end
  $lastline = Ncurses.LINES - 1
  #@message_row = Ncurses.LINES-1
  #@prompt_row = @message_row # hope to use for ask etc # 2011-10-17 14:06:27
  unless $log
    path = File.join(ENV["LOGDIR"] || "./" ,"rbc13.log")
    file   = File.open(path, File::WRONLY|File::TRUNC|File::CREAT) 
    $log = Logger.new(path)
    $log.level = Logger::DEBUG # change to warn when you've tested your app.
    colors = Ncurses.COLORS
    $log.debug "START #{colors} colors  --------- #{$0} win: #{@window} "
  end
end

#keypress(&block) ⇒ Object

returns a symbol of the key pressed e.g. :C_c for Ctrl-C :Space, :bs, :M_d etc



205
206
207
# File 'lib/rbcurse/core/util/app.rb', line 205

def keypress &block
 @keyblock = block
end

#loggerObject



119
# File 'lib/rbcurse/core/util/app.rb', line 119

def logger; return $log; end

#loop(&block) ⇒ Object

not sure, but user shuld be able to trap keystrokes if he wants but do i still call handle_key if he does, or give him total control. But loop is already called by framework



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/rbcurse/core/util/app.rb', line 137

def loop &block
  @form.repaint
  @window.wrefresh
  Ncurses::Panel.update_panels
  @break_key = ?\C-q.getbyte(0)
  # added this extra loop since from some places we exit using throw :close
  # amd that was in a much higher place, and was getting us right out, with
  # no chance of user canceling quit. This extra loop allows us to remain
  # added on 2011-11-24 
  while true
    catch :close do
      while((ch = @window.getchar()) != 999 )
        #break if ch == @break_key
        if ch == @break_key || ch == @quit_key
          #stopping = @window.fire_close_handler
          #break if stopping.nil? || stopping
          break
        end

        if @keyblock
          str = keycode_tos ch
          @keyblock.call(str.gsub(/-/, "_").to_sym) # not used ever
        end

        yield ch if block # <<<----
        # this is what the user should have control ove. earlier we would put this in
        # a try catch block so user could do what he wanted with the error. Now we
        # need to get it to him somehow, perhaps through a block or on_error event
        begin
          @form.handle_key ch
        rescue => err
          $log.debug( "handle_key rescue reached ")
          $log.debug( err.to_s) 
          $log.debug(err.backtrace.join("\n")) 
          textdialog [err.to_s, *err.backtrace], :title => "Exception"
        end
        #@form.repaint # was this duplicate ?? handle calls repaint not needed
        @window.wrefresh
      end
    end # catch
    stopping = @window.fire_close_handler
    @window.wrefresh
    break if stopping.nil? || stopping
  end # while
end

#message(text) ⇒ Object

updates a global var with text. Calling app has to set up a Variable with that name and attach to a label so it can be printed.



210
211
212
213
# File 'lib/rbcurse/core/util/app.rb', line 210

def message text
  $status_message.value = text # trying out 2011-10-9 
  #@message.value = text # 2011-10-17 14:07:01
end

#message_immediate(text) ⇒ Object

Deprecated.

please use RubyCurses#status_line instead of a message label

during a process, when you wish to update status, since ordinarily the thread is busy and form does not get control back, so the window won’t refresh. This will only update on keystroke since it uses statusline



219
220
221
222
223
# File 'lib/rbcurse/core/util/app.rb', line 219

def message_immediate text
  $log.warn "DEPRECATED, use message(),  or rb_puts or use status_window"
  $status_message.value = text # trying out 2011-10-9 user needs to use in statusline command
  # 2011-10-17 knocking off label, should be printed on status_line
end

#OLDblank(rows = 1, config = {}) ⇒ Object

creates a blank row



710
711
712
# File 'lib/rbcurse/core/util/app.rb', line 710

def OLDblank rows=1, config={}
  @app_row += rows
end

#OLDbutton(*args, &block) ⇒ Object



476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
# File 'lib/rbcurse/core/util/app.rb', line 476

def OLDbutton *args, &block
  config = {}
  events = [ :PRESS,  :LEAVE, :ENTER ]
  block_event = :PRESS

  _process_args args, config, block_event, events
  config[:text] ||= config[:name]
  config.delete(:title)
  # flow gets precedence over stack
  _position(config)
  button = Button.new @form, config
  # shooz uses CHANGED, which is equivalent to our CHANGE. Our CHANGED means modified and exited
  if block
    button.bind(block_event, &block)
  end
  return button
end

#OLDcheck(*args, &block) ⇒ Object

check button



565
566
567
568
569
570
571
572
573
574
575
576
577
# File 'lib/rbcurse/core/util/app.rb', line 565

def OLDcheck *args, &block
  config = {}
  # TODO confirm events
  events = [ :PRESS,  :LEAVE, :ENTER ]
  block_event = :PRESS
  _process_args args, config, block_event, events
  _position(config)
  toggle = CheckBox.new @form, config
  if block
    toggle.bind(block_event, &block)
  end
  return toggle
end

#OLDcombo(*args, &block) ⇒ Object

creates a simple readonly table, that allows users to click on rows and also on the header. Header clicking is for column-sorting.



840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
# File 'lib/rbcurse/core/util/app.rb', line 840

def OLDcombo *args, &block
  require 'rbcurse/core/widgets/rcombo'
  config = {}
  events = [:PROPERTY_CHANGE, :LEAVE, :ENTER, :CHANGE, :ENTER_ROW, :PRESS ] # XXX
  block_event = nil
  _process_args args, config, block_event, events
  _position(config)
  # if no width given, expand to flows width
  config[:width] ||= @stack.last.width if @stack.last
  #config.delete :title
  useform = nil
  useform = @form if @current_object.empty?

  w = ComboBox.new useform, config # NO BLOCK GIVEN
  if block_given?
    @current_object << w
    yield_or_eval &block
    @current_object.pop
  end
  return w
end

#OLDdivider(*args, &block) ⇒ Object

divider used to resize neighbouring components TOTEST XXX



828
829
830
831
832
833
834
835
836
837
# File 'lib/rbcurse/core/util/app.rb', line 828

def OLDdivider *args, &block
  require 'rbcurse/core/widgets/divider'
  config = {}
  events = [:PROPERTY_CHANGE, :LEAVE, :ENTER, :DRAG_EVENT  ] # # none really at present
  block_event = nil
  _process_args args, config, block_event, events
  useform = nil
  useform = @form if @current_object.empty?
  sb = Divider.new useform, config
end

#OLDedit_list(*args, &block) ⇒ Object

create a list Since we are mouseless, one can traverse without selection. So we have a different way of selecting row/s and traversal. XXX this aspect of LB’s has always troubled me hugely.



497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
# File 'lib/rbcurse/core/util/app.rb', line 497

def OLDedit_list *args, &block  # earlier list_box
  config = {}
  # TODO confirm events
  # listdataevent has interval added and interval removed, due to multiple
  # selection, we have to make that simple for user here.
  events = [ :LEAVE, :ENTER, :ENTER_ROW, :LEAVE_ROW, :LIST_DATA_EVENT ]
  # TODO how to do this so he gets selected row easily
  block_event = :ENTER_ROW

  _process_args args, config, block_event, events
  # naive defaults, since list could be large or have very long items
  # usually user will provide
  if !config.has_key? :height
    ll = 0
    ll = config[:list].length + 2 if config.has_key? :list
    config[:height] ||= ll
    config[:height] = 15 if config[:height] > 20
  end
  if @current_object.empty?
    $log.debug "1 APP LB w: #{config[:width]} ,#{config[:name]} "
    config[:width] ||= @stack.last.width if @stack.last
    $log.debug "2 APP LB w: #{config[:width]} "
    config[:width] ||= longest_in_list(config[:list])+2
    $log.debug "3 APP LB w: #{config[:width]} "
  end
  # if no width given, expand to flows width XXX SHOULD BE NOT EXPAND ?
  #config[:width] ||= @stack.last.width if @stack.last
  #if config.has_key? :choose
  config[:default_values] = config.delete :choose
  # we make the default single unless specified
  config[:selection_mode] = :single unless config.has_key? :selection_mode
  if @current_object.empty?
  if @instack
    # most likely you won't have row and col. should we check or just go ahead
    col = @stack.last.margin
    config[:row] = @app_row
    config[:col] = col
    @app_row += config[:height] # this needs to take into account height of prev object
  end
  end
  useform = nil
  useform = @form if @current_object.empty?
  field = EditList.new useform, config # earlier ListBox
  # shooz uses CHANGED, which is equivalent to our CHANGE. Our CHANGED means modified and exited
  if block
    # this way you can't pass params to the block
    field.bind(block_event, &block)
  end
  return field
end

#OLDfield(*args, &block) ⇒ Object

process arguments based on datatype, perhaps making configuration of some components easier for caller avoiding too much boiler plate code

create a field



440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
# File 'lib/rbcurse/core/util/app.rb', line 440

def OLDfield *args, &block
  config = {}
  events = [ :CHANGED,  :LEAVE, :ENTER, :CHANGE ]
  block_event = :CHANGED # LEAVE, ENTER, CHANGE

  _process_args args, config, block_event, events
  config.delete(:title)
  _position config
  # hope next line doesn't bonk anything
  config[:display_length] ||= @stack.last.width if @stack.last # added here not sure 2010-11-17 18:43 
  field = Field.new @form, config
  # shooz uses CHANGED, which is equivalent to our CHANGE. Our CHANGED means modified and exited
  if block
    field.bind(block_event, &block)
  end
  return field
end

#OLDflow(config = {}, &block) ⇒ Object

keep adding to right of previous and when no more space move down and continue fitting in. Useful for button positioning. Currently, we can use a second flow to get another row. TODO: move down when row filled TODO: align right, center



897
898
899
900
901
902
903
904
905
906
907
908
# File 'lib/rbcurse/core/util/app.rb', line 897

def OLDflow config={}, &block
  @inflow = true
  mt =  config[:margin_top] || 0
  @app_row += mt
  col = @flowstack.last || @stack.last.margin || @app_col
  col += config[:margin] || 0
  @flowstack << col
  @flowcol = col
  yield_or_eval &block if block_given? 
  @flowstack.pop
  @inflow = false if @flowstack.empty?
end

#OLDlabel(*args) ⇒ Object

instance_eval &block if block_given? or colorlabel = Label.new @form, => “Select a color:”, “row” => row, “col” => col, “color”=>“cyan”, “mnemonic” => ‘S’ var = RubyCurses::Label.new @form, => $results, “row” => r, “col” => fc



463
464
465
466
467
468
469
470
471
472
473
474
# File 'lib/rbcurse/core/util/app.rb', line 463

def OLDlabel *args
  events = block_event = nil
  config = {}
  _process_args args, config, block_event, events
  config[:text] ||= config[:name]
  config[:height] ||= 1
  config.delete(:title)
  _position(config)
  label = Label.new @form, config
  # shooz uses CHANGED, which is equivalent to our CHANGE. Our CHANGED means modified and exited
  return label
end

#OLDlistbox(*args, &block) ⇒ Object

create a readonly list I don’t want to rename this to list, as that could lead to confusion, maybe rlist



761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
# File 'lib/rbcurse/core/util/app.rb', line 761

def OLDlistbox *args, &block # earlier basic_list
  require 'rbcurse/core/widgets/rlist'
  config = {}
  #TODO check these
  events = [ :LEAVE, :ENTER, :ENTER_ROW, :LEAVE_ROW, :LIST_DATA_EVENT ]
  # TODO how to do this so he gets selected row easily
  block_event = :ENTER_ROW
  _process_args args, config, block_event, events
  # some guesses at a sensible height for listbox
  if !config.has_key? :height
    ll = 0
    ll = config[:list].length + 2 if config.has_key? :list
    config[:height] ||= ll
    config[:height] = 15 if config[:height] > 20
  end
  _position(config)
  # if no width given, expand to flows width
  config[:width] ||= @stack.last.width if @stack.last
  config[:width] ||= longest_in_list(config[:list])+2
  #config.delete :title
  #config[:default_values] = config.delete :choose
  config[:selection_mode] = :single unless config.has_key? :selection_mode
  useform = nil
  useform = @form if @current_object.empty?

  w = List.new useform, config # NO BLOCK GIVEN
  if block_given?
    field.bind(block_event, &block)
  end
  return w
end

#OLDradio(*args, &block) ⇒ Object

radio button



579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
# File 'lib/rbcurse/core/util/app.rb', line 579

def OLDradio *args, &block
  config = {}
  # TODO confirm events
  events = [ :PRESS,  :LEAVE, :ENTER ]
  block_event = :PRESS
  _process_args args, config, block_event, events
  a = config[:group]
  # FIXME we should check if user has set a varialbe in :variable.
  # we should create a variable, so he can use it if he wants.
  if @variables.has_key? a
    v = @variables[a]
  else
    v = Variable.new
    @variables[a] = v
  end
  config[:variable] = v
  config.delete(:group)
  _position(config)
  radio = RadioButton.new @form, config
  if block
    radio.bind(block_event, &block)
  end
  return radio
end

#OLDscrollbar(*args, &block) ⇒ Object

scrollbar attached to the right of a parent object



816
817
818
819
820
821
822
823
824
825
826
# File 'lib/rbcurse/core/util/app.rb', line 816

def OLDscrollbar *args, &block
  require 'rbcurse/core/widgets/scrollbar'
  config = {}
  events = [:PROPERTY_CHANGE, :LEAVE, :ENTER  ] # # none really at present
  block_event = nil
  _process_args args, config, block_event, events
  raise "parent needed for scrollbar" if !config.has_key? :parent
  useform = nil
  useform = @form if @current_object.empty?
  sb = Scrollbar.new useform, config
end

#OLDstack(config = {}, &block) ⇒ Object

line up vertically whatever comes in, ignoring r and c margin_top to add to margin of existing stack (if embedded) such as extra spacing margin to add to margin of existing stack, or window (0) NOTE: since these coordins are calculated at start therefore if window resized i can’t recalculate. Stack = Struct.new(:margin_top, :margin, :width)



874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
# File 'lib/rbcurse/core/util/app.rb', line 874

def OLDstack config={}, &block
  @instack = true
  mt =  config[:margin_top] || 1
  mr =  config[:margin] || 0
  # must take into account margin
  defw = Ncurses.COLS - mr
  config[:width] = defw if config[:width] == :EXPAND
  w =   config[:width] || [50, defw].min
  s = Stack.new(mt, mr, w)
  @app_row += mt
  mr += @stack.last.margin if @stack.last
  @stack << s
  yield_or_eval &block if block_given?
  @stack.pop
  @instack = false if @stack.empty?
  @app_row = 0 if @stack.empty?
end

#OLDtextarea(*args, &block) ⇒ Object

editable text area



604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
# File 'lib/rbcurse/core/util/app.rb', line 604

def OLDtextarea *args, &block
  require 'rbcurse/core/widgets/rtextarea'
  config = {}
  # TODO confirm events many more
  events = [ :CHANGE,  :LEAVE, :ENTER ]
  block_event = events[0]
  _process_args args, config, block_event, events
  config[:width] = config[:display_length] unless config.has_key? :width
  _position(config)
  # if no width given, expand to flows width
  config[:width] ||= @stack.last.width if @stack.last
  useform = nil
  useform = @form if @current_object.empty?
  w = TextArea.new useform, config
  if block
    w.bind(block_event, &block)
  end
  return w
end

#OLDtoggle(*args, &block) ⇒ Object

toggle button



549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
# File 'lib/rbcurse/core/util/app.rb', line 549

def OLDtoggle *args, &block
  config = {}
  # TODO confirm events
  events = [ :PRESS,  :LEAVE, :ENTER ]
  block_event = :PRESS
  _process_args args, config, block_event, events
  config[:text] ||= longest_in_list2( [config[:onvalue], config[:offvalue]])
    #config[:onvalue] # needed for flow, we need a better way FIXME
  _position(config)
  toggle = ToggleButton.new @form, config
  if block
    toggle.bind(block_event, &block)
  end
  return toggle
end

#raw_message(text, config = {}, &blk) ⇒ Object

Deprecated.

Use say_with_pause or use rdialogs status_window, see test2.rb

Usage: application is inside a long processing loop and wishes to print ongoing status NOTE: if you use this, you must use raw_message_destroy at some stage, after processing or on_leave of object.



228
229
230
231
232
233
234
235
236
237
# File 'lib/rbcurse/core/util/app.rb', line 228

def raw_message text, config={}, &blk
  $raw_window ||= one_line_window last_line(), config, &blk
  width = $raw_window.width == 0 ? FFI::NCurses.COLS : $raw_window.width
  text = "%-*s" % [width, text]
  
  $raw_window.attron(Ncurses.COLOR_PAIR($normalcolor) )
  $raw_window.printstring 0,0,text, $normalcolor #, 'normal' if @title
  $raw_window.wrefresh
 
end

#raw_message_destroyObject



238
239
240
241
242
243
# File 'lib/rbcurse/core/util/app.rb', line 238

def raw_message_destroy
  if $raw_window
    $raw_window.destroy
    $raw_window = nil
  end
end

#raw_progress(arg) ⇒ Object

Deprecated.
  • don’t use stdscr at all, use rdialogs status_window (see test2.rb)

shows a simple progress bar on last row, using stdscr If Array of two numbers is given then also print part/total on left of bar

Parameters:

  • percentage, (Float, Array<Fixnum,Fixnum>)

    or part/total



248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/rbcurse/core/util/app.rb', line 248

def raw_progress arg
  $log.warning "WARNING: don't use this method as it uses stdscr"
  row = @message_label ? @message_label.row : Ncurses.LINES-1
  s = nil
  case arg
  when Array
    #calculate percentage
    pc = (arg[0]*1.0)/arg[1]
    # print items/total also
    s = "%-10s" % "(#{arg[0]}/#{arg[1]})"
  when
    Float
    pc = arg
  end
  scr = Ncurses.stdscr
  endcol = Ncurses.COLS-1
  startcol = endcol - 12
  stext = ("=" * (pc*10).to_i) 
  text = "[" + "%-10s" % stext + "]"
  Ncurses.mvprintw( row ,startcol-10, s) if s
  Ncurses.mvprintw row ,startcol, text
  #scr.refresh() # XXX FFI NW

end

#safe_loop(&block) ⇒ Object

if calling loop separately better to call this, since it will shut off ncurses and print error on screen.



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/rbcurse/core/util/app.rb', line 184

def safe_loop &block
  begin
    loop &block
  rescue => ex
    $log.debug( "APP.rb rescue reached ")
    $log.debug( ex) if ex
    $log.debug(ex.backtrace.join("\n")) if ex
  ensure
    close
    # putting it here allows it to be printed on screen, otherwise it was not showing at all.
    if ex
      puts "========== EXCEPTION =========="
      p ex 
      puts "==============================="
      puts(ex.backtrace.join("\n")) 
    end
  end
end

#subtitle(string, config = {}) ⇒ Object

print a sutitle on second row



704
705
706
# File 'lib/rbcurse/core/util/app.rb', line 704

def subtitle string, config={}
  @window.printstring 2, 30, string, $datacolor, 'normal'
end

#suspend(clear = true) ⇒ Object

suspends curses so you can play around on the shell or in cooked mode like Vim does. Expects a block to be passed. Purpose: you can print some stuff without creating a window, or just run shell commands without coming out. NOTE: if you pass clear as true, then the screen will be cleared and you can use puts or print to print. You may have to flush. However, with clear as false, the screen will not be cleared. You will have to print using printw, and if you expect user input you must do a “system /bin/stty sane” If you print stuff, you will have to put a getch() or system(“read”) to pause the screen.



288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/rbcurse/core/util/app.rb', line 288

def suspend clear=true
  return unless block_given?
  Ncurses.def_prog_mode
  if clear
    Ncurses.endwin 
    # NOTE: avoid false since screen remains half off
    # too many issues
  else
    system "/bin/stty sane"
  end
  yield if block_given?
  Ncurses.reset_prog_mode
  if !clear
    # Hope we don't screw your terminal up with this constantly.
    VER::stop_ncurses
    VER::start_ncurses  
    #@form.reset_all # not required
  end
  @form.repaint
  @window.wrefresh
  Ncurses::Panel.update_panels
end

#title(string, config = {}) ⇒ Object

print a title on first row



699
700
701
702
# File 'lib/rbcurse/core/util/app.rb', line 699

def title string, config={}
  ## TODO center it
  @window.printstring 1, 30, string, $normalcolor, 'reverse'
end

#TODOmaster_detail(*args, &block) ⇒ Object



793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
# File 'lib/rbcurse/core/util/app.rb', line 793

def TODOmaster_detail *args, &block
  require 'rbcurse/experimental/widgets/masterdetail'
  config = {}
  events = [:PROPERTY_CHANGE, :LEAVE, :ENTER ]
  block_event = nil
  _process_args args, config, block_event, events
  #config[:height] ||= 10
  _position(config)
  # if no width given, expand to flows width
  config[:width] ||= @stack.last.width if @stack.last
  #config.delete :title
  useform = nil
  useform = @form if @current_object.empty?

  w = MasterDetail.new useform, config # NO BLOCK GIVEN
  if block_given?
    @current_object << w
    yield_or_eval &block
    @current_object.pop
  end
  return w
end

#TODOmultisplit(*args, &block) ⇒ Object



733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
# File 'lib/rbcurse/core/util/app.rb', line 733

def TODOmultisplit *args, &block
  require 'rbcurse/extras/widgets/rmultisplit'
  config = {}
  events = [ :PROPERTY_CHANGE,  :LEAVE, :ENTER ]
  block_event = events[0]
  _process_args args, config, block_event, events
  _position(config)
  # if no width given, expand to flows width
  config[:width] ||= @stack.last.width if @stack.last
  config.delete :title
  useform = nil
  useform = @form if @current_object.empty?

  w = MultiSplit.new useform, config
  #if block
    #w.bind(block_event, w, &block)
  #end
  if block_given?
    @current_object << w
    #instance_eval &block if block_given?
    yield w
    @current_object.pop
  end
  return w
end