Class: Umbra::MessageBox

Inherits:
Object
  • Object
show all
Defined in:
lib/umbra/messagebox.rb

Overview

Class: MessageBox

Description: A configurable dialog box. Creates a window which allows caller to add

widgets such as fields and buttons to it. Returns the offset of the button pressed
so the caller knows if Ok or Cancel etc was pressed.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

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

dsl_accessor :message you can also set button_orientation : :right, :left, :center



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/umbra/messagebox.rb', line 48

def initialize config={}, &block

  h = config.fetch(:height, nil)
  w = config.fetch(:width, nil)
  t = config.fetch(:row, nil)
  l = config.fetch(:col, nil)
  if h && w && t && l
    #@window = Window.new :height => h, :width => w, :top => t, :left => l
    @window = Window.new  h, w, t, l
    # else window will be created in repaint, and form will pass it to widgets before their first
    # repaint
  end
  @form = Form.new @window
  @buttons = ["Ok", "Cancel"]                          ## default button, can be overridden

  config.each_pair { |k,v| instance_variable_set("@#{k}",v) }
  @config = config
  @row = 0
  @col = 0
  @row_offset = 1
  @col_offset = 2
  
  @color_pair  = CP_BLACK

  @maxrow = 3

  instance_eval &block if block_given?
  #yield_or_eval &block if block_given? TODO

end

Instance Attribute Details

#buttonsObject

button labels. e.g. [Ok, Cancel]



38
39
40
# File 'lib/umbra/messagebox.rb', line 38

def buttons
  @buttons
end

#formObject (readonly)

Returns the value of attribute form.



35
36
37
# File 'lib/umbra/messagebox.rb', line 35

def form
  @form
end

#titleObject

Returns the value of attribute title.



37
38
39
# File 'lib/umbra/messagebox.rb', line 37

def title
  @title
end

#windowObject (readonly)

Returns the value of attribute window.



36
37
38
# File 'lib/umbra/messagebox.rb', line 36

def window
  @window
end

Instance Method Details

#_create_windowObject



319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
# File 'lib/umbra/messagebox.rb', line 319

def _create_window

  $log.debug "  MESSAGEBOX _create_window h:#{@height} w:#{@width} r:#{@row} c:#{@col} "
  $log.debug "  MESSAGEBOX _create_window h:#{@suggested_h} w:#{@suggested_w} "
  @width ||= @suggested_w || 60
  @height = @suggested_h || 10
  $log.debug "  MESSAGEBOX _create_window h:#{@height} w:#{@width} r:#{@row} c:#{@col} "
  if @suggested_row
    @row = @suggested_row
  else
    @row = ((FFI::NCurses.LINES-@height)/2).floor
  end
  if @suggested_col
    @col = @suggested_col
  else
    w = @width
    @col = ((FFI::NCurses.COLS-w)/2).floor
  end
  #@window = Window.new :height => @height, :width => @width, :top => @row, :left => @col
  $log.debug "  MESSAGEBOX _create_window h:#{@height} w:#{@width} r:#{@row} c:#{@col} "
  @window = Window.new  @height,  @width,  @row,  @col
  @graphic = @window
  @form.window = @window
  # in umbra, the widgets would not be having a window, if window was created after the widgets were added
end

#create_action_buttons(*labels) ⇒ Object

creates the buttons (INTERNAL)



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/umbra/messagebox.rb', line 188

def create_action_buttons *labels
  @action_buttons = []
  _row = @height-3
  _col = (@width-(labels.count*8))/2
  _col = 5 if _col < 1

  labels.each_with_index do |l, ix|
    b = Button.new text: l, row: _row, col: _col
    _col += l.length+5
    @action_buttons << b
    @form.add_widget b
    b.command do
      @selected_index = ix
      throw(:close, ix)
    end
  end
  ## 2018-05-17 - associate RETURN ENTER key with first button (FIXME) should be Ok or Okay or user 
  ##    should have some say in this. Same for associating ESC with Cancel or Quit.
  @form.bind_key(10, "Fire Ok button") { @action_buttons.first.fire }
end

#handle_keysObject

in umbra, the widgets would not be having a window, if window was created after the widgets were added



344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'lib/umbra/messagebox.rb', line 344

def handle_keys
  buttonindex = catch(:close) do 
    while((ch = @window.getch()) != FFI::NCurses::KEY_F10 )
      break if ch == ?\C-q.getbyte(0) || ch == 2727 # added double esc
      begin
        # trying out repaint of window also if repaint all asked for. 18 is C-r
        if ch == 1000 or ch == 18
          repaint_all_widgets
        end
        @form.handle_key(ch)
        @window.wrefresh
      rescue => err
        if $log
          $log.debug( err) if err
          $log.debug(err.backtrace.join("\n")) if err
        end
        textdialog ["Error in Messagebox: #{err} ", *err.backtrace], :title => "Exception" 
        @window.refresh # otherwise the window keeps showing (new FFI-ncurses issue)
      ensure
      end

    end # while loop
  end # close
  $log.debug "MESSAGEBOX: CALLING PROGRAM BEING RETURNED: #{buttonindex} "
  @window.destroy    ## 2018-05-17 - this should come in ensure block ???
  # added 2014-05-01 - 18:10 hopefully to refresh root_window.
  #Window.refresh_all
  return buttonindex 
end

#item(widget) ⇒ Object Also known as: add

Add a widget to the messagebox

Example: item( field )

or add ( field )

If row is not specified, then each call will add 1 to the row If height of the messagebox is not specified, then it will be computed

from the row of the last widget.


93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/umbra/messagebox.rb', line 93

def item widget
  # # normalcolor gives a white on black stark title like links and elinks
  # You can also do 'acolor' to give you a sober title that does not take attention away, like mc
  # remove from existing form if set, problem with this is mnemonics -- rare situation.
  @maxrow ||= 3
  @form.add_widget widget
  widget.row ||= 0
  widget.col ||= 0

  ## if caller does not specify row, then keep incrementing
  if widget.row == 0
    widget.row = [@maxrow+1, 3].max
  else
    widget.row += @row_offset       ## add one to row if stated by user
  end

  if widget.col == 0
    widget.col = 5
  else
    # i don't know button_offset as yet
    widget.col += @col_offset 
  end

  @maxrow = widget.row if widget.row > @maxrow
  @suggested_h = @height || @maxrow+6

  ## check that window does not exceed LINES else program will hang
  lines = FFI::NCurses.LINES
  @suggested_h = lines if @suggested_h > lines
  if widget.row > lines
    $log.warning "MESSAGEBOX placing widget at row (#{widget.row} > #{lines}. You are placing too many items."
  end

  @suggested_w ||= 0
  ww = widget.width || 5  # some widgets do no set a default width, and could be null
  _w = [ww + 5, 15].max
  @suggested_w = widget.col + _w if widget.col > @suggested_w
  if ww >= @suggested_w
    @suggested_w = ww + widget.col + 10
  end
  #$log.debug "  MESSAGEBOX add suggested_w #{@suggested_w} , suggested_h : #{@suggested_h}, maxrow #{@maxrow}, LINES= #{FFI::NCurses.LINES}  "
  # if w's given col is > width then add to suggested_w or text.length
end

#longest_in_list(list) ⇒ Object

returns length of longest



310
311
312
313
314
315
# File 'lib/umbra/messagebox.rb', line 310

def longest_in_list list  #:nodoc:
  longest = list.inject(0) do |memo,word|
    memo >= word.length ? memo : word.length
  end    
  longest
end

#message(message) {|message_label| ... } ⇒ Object Also known as: message=

yield label or field being used for display for further customization

Yields:

  • (message_label)


222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/umbra/messagebox.rb', line 222

def message message # yield label or field being used for display for further customization
  @suggested_h = @height || 10
  message = message.gsub(/[\n\r\t]/,' ') rescue message
  message_col = 5
  $log.debug "  MESSAGE w: #{@width}, size: #{message.size} "
  _pad = 5
  @suggested_w = @width || [message.size + _pad + message_col , FFI::NCurses.COLS-2].min
  r = 3
  len = message.length
  #@suggested_w = len + _pad + message_col if len < @suggested_w - _pad - message_col

  display_length = @suggested_w-_pad
  display_length -= message_col
  message_height = 2

  color_pair = CP_WHITE
  # trying this out. sometimes very long labels get truncated, so i give a field in wchich user
  # can use arrow key or C-a and C-e
  if message.size > display_length
    message_label = Field.new({:text => message, :name=>"message_label",
      :row => r, :col => message_col, :width => display_length,  
      :color_pair => color_pair, :editable => false})
  else
    message_label = Label.new({:text => message, :name=>"message_label",
      :row => r, :col => message_col, :width => display_length,
      :height => message_height, :color_pair => color_pair})
  end
  @form.add_widget message_label
  @maxrow = 3
  yield message_label if block_given?
end

#repaintObject

paints the messagebox and creates the buttons (INTERNAL)



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/umbra/messagebox.rb', line 162

def repaint
  _create_window unless @window
  #acolor = get_color $reverscolor, @color, @bgcolor 
  acolor = 0 # ??? FIXME
  $log.debug " MESSAGE BOX bg:#{@bgcolor} , co:#{@color} , colorpair:#{acolor}"
  @window.wbkgd(FFI::NCurses.COLOR_PAIR(acolor) | REVERSE); 

  @color_pair ||= CP_BLACK
  bordercolor = @border_color || CP_BLACK
  borderatt = @border_attrib || NORMAL
  @window.wattron(FFI::NCurses.COLOR_PAIR(bordercolor) | (borderatt || FFI::NCurses::A_NORMAL))
  print_border_mb @window, 1,2, @height, @width, nil, nil
  @window.wattroff(FFI::NCurses.COLOR_PAIR(bordercolor) | (borderatt || FFI::NCurses::A_NORMAL))
  @title ||= "+-+"
  @title_color ||= CP_CYAN
  @title_attr ||= REVERSE
  title = " "+@title+" "
  # normalcolor gives a white on black stark title like links and elinks
  # You can also do 'acolor' to give you a sober title that does not take attention away, like mc
  @window.printstring(@row=1,@col=(@width-title.length)/2,title, color=@title_color, @title_attr)
  #print_message if @message
  create_action_buttons(*@buttons) unless @action_buttons
end

#runObject

Call this after instantiating the window



152
153
154
155
156
157
158
159
# File 'lib/umbra/messagebox.rb', line 152

def run
  repaint
  @form.pack # needs window
  @form.repaint
  @form.select_first_field      ## otherwise on_enter of first won't fire
  @window.wrefresh
  return handle_keys
end

#text(message) {|message_label| ... } ⇒ Object Also known as: text=

This is for larger messages, or messages where the size is not known. A textview object is created and yielded.

Yields:

  • (message_label)


258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# File 'lib/umbra/messagebox.rb', line 258

def text message
  @suggested_w = @width || (FFI::NCurses.COLS * 0.80).floor
  @suggested_h = @height || (FFI::NCurses.LINES * 0.80).floor

  message_col = 3
  r = 2
  display_length = @suggested_w-4
  display_length -= message_col
  #clr = @color || :white
  #bgclr = @bgcolor || :black
  color_pair = CP_WHITE

  if message.is_a? Array
    l = longest_in_list message
    if l > @suggested_w 
      if l < FFI::NCurses.COLS
        #@suggested_w = l
        @suggested_w = FFI::NCurses.COLS-2 
      else
        @suggested_w = FFI::NCurses.COLS-2 
      end
      display_length = @suggested_w-6
    end
    # reduce width and height if you can based on array contents
  else
    message = wrap_text(message, display_length).split("\n")
  end
  # now that we have moved to textpad that +8 was causing black lines to remain after the text
  message_height = message.size #+ 8
  # reduce if possible if its not required.
  #
  r1 = (FFI::NCurses.LINES-@suggested_h)/2
  r1 = r1.floor
  w = @suggested_w
  c1 = (FFI::NCurses.COLS-w)/2
  c1 = c1.floor
  @suggested_row = r1
  @suggested_col = c1
  brow = @button_row || @suggested_h-4
  available_ht = brow - r + 1
  message_height = [message_height, available_ht].min
  # replaced 2014-04-14 - 23:51 
  message_label = Textbox.new({:name=>"message_label", :list => message,
    :row => r, :col => message_col, :width => display_length,
    :height => message_height, :color_pair => color_pair})
  #message_label.set_content message
  @form.add_widget message_label
  yield message_label if block_given?

end

#wrap_text(s, width = 78) ⇒ Object

{{{



316
317
318
# File 'lib/umbra/messagebox.rb', line 316

def wrap_text(s, width=78)    # {{{
  s.gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n").split("\n")
end