Class: Umbra::Window

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

Overview

Window class

Creates and manages the underlying window in which we write or place a form and fields.
The two important methods here are the constructor, and +destroy()+.
+pointer+ is important for making further direct calls to FFI::NCurses.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(h = 0, w = 0, top = 0, left = 0) ⇒ Window

creates a window with given height, width, top and left. If no args given, creates a root window (i.e. full size).

Parameters:

  • height (Integer)
  • width (Integer)
  • top (Integer) (defaults to: 0)
  • left (Integer) (defaults to: 0)


129
130
131
132
133
134
135
136
137
138
139
# File 'lib/umbra/window.rb', line 129

def initialize h=0, w=0, top=0, left=0
  @height, @width, @top, @left = h, w, top, left

  @height = FFI::NCurses.LINES if @height == 0   # 2011-11-14 added since tired of checking for zero
  @width = FFI::NCurses.COLS   if @width == 0
  @pointer = FFI::NCurses.newwin(@height, @width, @top, @left) # added FFI 2011-09-6 

  @panel = FFI::NCurses.new_panel(@pointer)
  FFI::NCurses.keypad(@pointer, true)
  return @pointer
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object

route other methods to ffi. {{{ This should preferable NOT be used. Better to use the direct call itself. It attempts to route other calls to FFI::NCurses by trying to add w to the name and passing the pointer. I would like to remove this at some time.



271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/umbra/window.rb', line 271

def method_missing(name, *args)
  name = name.to_s
  if (name[0,2] == "mv")
    test_name = name.dup
    test_name[2,0] = "w" # insert "w" after"mv"
    if (FFI::NCurses.respond_to?(test_name))
      return FFI::NCurses.send(test_name, @pointer, *args)
    end
  end
  test_name = "w" + name
  if (FFI::NCurses.respond_to?(test_name))
    return FFI::NCurses.send(test_name, @pointer, *args)
  end
  FFI::NCurses.send(name, @pointer, *args)
end

Instance Attribute Details

#heightObject (readonly)

Returns the value of attribute height.



121
122
123
# File 'lib/umbra/window.rb', line 121

def height
  @height
end

#leftObject (readonly)

Returns the value of attribute left.



121
122
123
# File 'lib/umbra/window.rb', line 121

def left
  @left
end

#panelObject (readonly)

panel associated with window



120
121
122
# File 'lib/umbra/window.rb', line 120

def panel
  @panel
end

#pointerObject (readonly)

pointer to FFI routines, use when calling FFI directly.



119
120
121
# File 'lib/umbra/window.rb', line 119

def pointer
  @pointer
end

#topObject (readonly)

Returns the value of attribute top.



121
122
123
# File 'lib/umbra/window.rb', line 121

def top
  @top
end

#widthObject (readonly)

Returns the value of attribute width.



121
122
123
# File 'lib/umbra/window.rb', line 121

def width
  @width
end

Class Method Details

.create(h = 0, w = 0, top = 0, left = 0) ⇒ Object

create a window and return window, or yield window to block



142
143
144
145
146
147
148
149
150
151
152
# File 'lib/umbra/window.rb', line 142

def self.create h=0, w=0, top=0, left=0
  win = Window.new h, w, top, left
  return win unless block_given?

  begin
    yield win
  ensure
    win.destroy
  end

end

Instance Method Details

#boxObject

make a box around the window. Just a wrapper



287
288
289
290
# File 'lib/umbra/window.rb', line 287

def box
  @box = true
  FFI::NCurses.box(@pointer, 0, 0)
end

#destroyObject

destroy the window and the panel. This is important. It should be placed in the ensure block of caller application, so it happens.



262
263
264
265
266
# File 'lib/umbra/window.rb', line 262

def destroy
  FFI::NCurses.del_panel(@panel) if @panel
  FFI::NCurses.delwin(@pointer)   if @pointer
  @panel = @pointer = nil # prevent call twice
end

#getchInteger Also known as: getkey

Get a key from the standard input.

This will get control keys and function keys but not Alt keys. This is usually called in a loop by the main program. It returns the ascii code (integer). 1 is Ctrl-a .… 27 is Esc FFI already has constants declared for function keys and control keys for checkin against. Can return a 3 or -1 if user pressed Control-C.

NOTE: For ALT keys we need to check for 27/Esc and if so, then do another read with a timeout. If we get a key, then resolve. Otherwise, it is just ESC NOTE: this was working fine with nodelay. However, that would not allow an app to continuously

update the screen, as the getch was blocked. wtimeout allows screen to update without a key
being pressed. 2018-04-07

Returns:

  • (Integer)

    ascii code of key. For undefined keys, returns a String representation.



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/umbra/window.rb', line 197

def getch
  FFI::NCurses.wtimeout(@pointer, $ncurses_timeout || 1000)
  c = FFI::NCurses.wgetch(@pointer)
  if c == 27    ## {{{

    # don't wait for another key
    FFI::NCurses.nodelay(@pointer, true)
    k = FFI::NCurses.wgetch(@pointer)
    if k == -1
      # wait for key
      #FFI::NCurses.nodelay(@pointer, false)
      return 27
    else
      buf = ""
      loop do
        n = FFI::NCurses.wgetch(@pointer)
        break if n == -1
        buf += n.chr
      end
      # wait for next key
      #FFI::NCurses.nodelay(@pointer, false)

      # this works for all alt-keys but it messes with shift-function keys
      # shift-function keys start with M-[ (91) and then have more keys
      if buf == ""
        return k + 128
      end
      #$log.debug "  getch buf is #{k.chr}#{buf} "
      # returning a string key here which is for Shift-Function keys or other undefined keys.
      key = 27.chr + k.chr + buf
      return key

    end
  end   ## }}}
  #FFI::NCurses.nodelay(@pointer, false) # this works but trying out for continueous updates
  c
rescue SystemExit, Interrupt 
  3      # is C-c
rescue StandardError
  -1     # is C-c
end

#getcharObject

Convenience method for a waiting getch



240
241
242
243
# File 'lib/umbra/window.rb', line 240

def getchar
  $ncurses_timeout = -1
  return self.getch
end

#OLDgetchObject

this works fine for basic, control and function keys



246
247
248
249
250
251
252
# File 'lib/umbra/window.rb', line 246

def OLDgetch
  c = FFI::NCurses.wgetch(@pointer)
rescue SystemExit, Interrupt 
  3      # is C-c
rescue StandardError
  -1     # is C-c
end

#printstr(str, x = 0, y = 0) ⇒ Object

Deprecated.

print string at x, y coordinates. replace this with the original one below



156
157
158
159
160
# File 'lib/umbra/window.rb', line 156

def printstr(str, x=0,y=0)
  win = @pointer
  FFI::NCurses.wmove(win, x, y)
  FFI::NCurses.waddstr win, str
end

#printstring(r, c, string, color = 0, att = FFI::NCurses::A_NORMAL) ⇒ Object

2018-03-08 - taken from canis reduced print given string at row, col with given color and attributes

Parameters:

  • row (Integer)

    row to print on

  • col (Integer)

    column to print on

  • color (Integer) (defaults to: 0)

    color_pair created earlier

  • attr (Integer)

    any of the four FFI attributes, e.g. A_BOLD, A_REVERSE



168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/umbra/window.rb', line 168

def printstring(r,c,string, color=0, att = FFI::NCurses::A_NORMAL)

  #$log.debug "printstring recvd nil row #{r} or col #{c}, color:#{color},att:#{att}."  if $log
  raise "printstring recvd nil row #{r} or col #{c}, color:#{color},att:#{att} " if r.nil? || c.nil?
  att ||= FFI::NCurses::A_NORMAL
  color ||= 0
  raise "color is nil " unless color
  raise "att is nil " unless att

  FFI::NCurses.wattron(@pointer, FFI::NCurses.COLOR_PAIR(color) | att)
  FFI::NCurses.mvwprintw(@pointer, r, c, "%s", :string, string);
  FFI::NCurses.wattroff(@pointer, FFI::NCurses.COLOR_PAIR(color) | att)
end

#repaintObject

repaints windows objects like title and box. To be called from form on pressing redraw, and SIGWINCH



307
308
309
310
311
312
313
314
315
316
# File 'lib/umbra/window.rb', line 307

def repaint
  curses.wclear(@pointer)
  if @box
    self.box
  end
  if @title_data
    str, color, att = @title_data
    self.title str, color, att
  end
end

#title(str, color = 0, att = BOLD) ⇒ Object

Print a centered title on top of window. NOTE : the string is not stored, so it can be overwritten. This should be called after box, or else box will erase the title

Parameters:

  • str (String)

    title to print

  • color (Integer) (defaults to: 0)

    color_pair

  • att (Integer) (defaults to: BOLD)

    attribute constant



297
298
299
300
301
302
303
# File 'lib/umbra/window.rb', line 297

def title str, color=0, att=BOLD
  ## save so we can repaint if required
  @title_data = [str, color, att]
  strl = str.length
  col = (@width - strl)/2
  printstring(0,col, str, color, att)
end

#wrefreshObject

refresh the window (wrapper) To be called after printing on a window.



257
258
259
# File 'lib/umbra/window.rb', line 257

def wrefresh
  FFI::NCurses.wrefresh(@pointer)
end