Z
zimba-tm
------=_Part_6032_7248194.1133577613783
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline
Hello,
I hate curses. Not that much, but it's really not that easy to build
ruby console applications using it.
Are there other libraries I could use instead of libcurses ?
My main complains are :
* you can't access the screen like a character matrix
* i want callbacks (onresize)
* you need to move the cursor where you want to write
* the "window"ing system is not cool
* it really feels like an old-skool C library in ruby
I started overriding the curses library to implement what I think is
nicer (which is subjective). Is anybody interested in this ? Also,
what is so special in the libcurse ? Is it because it supports VT100
that people are still using it ?
The joined file containes the modified curses class plus an class that
demonstrates how to use it (however it doesn't run)
--
Cheers,
zimba
http://zimba.oree.ch
------=_Part_6032_7248194.1133577613783
Content-Type: application/octet-stream; name=interface.rb
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="interface.rb"
require 'curses'
# curses sanitization
module Curses
@windows = Array.new
def self.windows
@windows
end
class Window
def init(buffer_size = 100, wrap = true)
@buffer = Array.new buffer_size, ''
@buffer_x = 0
@buffer_y = 0
@cursor_x = 0
@cursor_y = 0
@windows = Array.new
@line_wrap = wrap
Curses.windows.push self
end
def [](line_num)
@buffer[line_num]
end
def []=(line_num, line)
# TODO: check if data is in screen
@buffer[line_num] = line
old_setpos(line_num, 0)
if @line_wrap && line.length > maxx
addstr line[0..maxx] + "\n"
addstr line[maxx..line.length]
else
addstr line
end
# fill
addstr " " * (maxx - line.length)
old_setpos(line_num, line.length)
end
def puts(line)
# storage
if @cursor_x == @buffer.length-1
@buffer.pop
@buffer.push line
else
@cursor_x += 1
@buffer[@cursor_x] = line
end
# draw
if @line_wrap && line.length > maxx
addstr line[0..maxx] + "\n"
addstr line[maxx..line.length]
else
addstr line
end
end
alias :<<
uts
def putc(char, y=nil, x=nil)
if y == nil
y = @cursor_y
end
if x == nil
x = @cursor_x
end
diff = @buffer[x].length - y
if diff < 0
@buffer[y] += " " * diff
end
@buffer[y][x] << char
end
alias
utc :addch
alias :gets :getstr
alias :getc :getch
alias
ld_refresh :refresh
def refresh
old_refresh
end
alias
ld_clear :clear
def clear
setpos(0,0)
@buffer.fill('')
super
end
alias
ld_setpos :setpos
def setpos(y, x)
@cursor_y = y
@cursor_x = x
old_setpos y, x
end
alias
ld_move :move
def move(y, x)
setpos(@cursor_y + y, @cursor_x + x)
end
alias
ld_subwin :subwin
def subwin(height, width, top, left)
subwin = old_subwin height, width, top, left
subwin.init
@windows.push subwin
return subwin
end
alias
ld_close :close
def close
@windows.each do |window|
window.close
end
Curses.windows.delete self
Curses.close_screen if Curses.windows.length == 0
old_close
end
end
end
module Interface
class Cursed
def initialize(server)
@server = server
Signal.trap('INT') do
exit
end
end
def run
Curses::init_screen # binds curses to the current interface
Curses::raw # cbreak or raw, allows direct char handling
Curses::noecho # we will manage user output ourselves
# keypad(true) # allow handling of the keypad keys
Curses::nonl
lines = Curses::lines
cols = Curses::cols
# interface setup
@w = Curses::Window.new(lines, cols, 0, 0)
@w.init
@title = @w.subwin(1, cols, 0, 0)
@title[0] = "*** Welcome in zchat ***"
@title.refresh
@main = @w.subwin(lines-3, cols, 1, 0)
@main.scrollok(true)
@main.refresh
@status = @w.subwin(1, cols, lines-2, 0)
@status[0] = @server.hostname + ": " + @server.channel.keys.join(', ')
@status.refresh
@input = @w.subwin(1, cols, lines-1, 0)
@input[0] = ENV['USER']+'@'(e-mail address removed)+'/#test$ '
@input.refresh
@server.channel["#test"].on_read do |line|
@main.puts line
@main.refresh
@input.refresh
end
# keyboard input handling
t = Thread.new do
buffer = ''
line = @input[0]
while true
chr = @input.getc
case chr
when 13 # ?\n
case buffer
when /^ls/
$server['#test'].puts '/NAMES #test'
when /^echo\s/
command = buffer[5..buffer.length-1]
@server['#test'].puts command + "\n" if command.length > 0
when /^join\s/
command = buffer[5..buffer.length-1]
@server.puts '/j ' + command
when '\quit', ':q', 'exit', 'quit'
exit
else
@status[0] = "command not found..."
@status.refresh
end
buffer = ''
@input.setpos(0, 0)
when 279168 # Curses::KEY_LEFT
@input.move(0, -1)
when 279167 # Curses::KEY_RIGHT
@input.move(0, +1)
when ?\C-c
exit
when ?\C-? # Curses::KEY_BACKSPACE
if buffer.length > 1
buffer = buffer[0..buffer.length-2] if buffer.length > 1
@input.move(0, -1)
else
buffer = ''
@input.setpos(0, 0)
end
else
buffer << chr
end
@input[0] = line + buffer
@input.refresh
end
end
t.join
end
def exit
@w.close
puts "Exiting zchat..."
@server.exit
Kernel.exit
end
end
end
------=_Part_6032_7248194.1133577613783--
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline
Hello,
I hate curses. Not that much, but it's really not that easy to build
ruby console applications using it.
Are there other libraries I could use instead of libcurses ?
My main complains are :
* you can't access the screen like a character matrix
* i want callbacks (onresize)
* you need to move the cursor where you want to write
* the "window"ing system is not cool
* it really feels like an old-skool C library in ruby
I started overriding the curses library to implement what I think is
nicer (which is subjective). Is anybody interested in this ? Also,
what is so special in the libcurse ? Is it because it supports VT100
that people are still using it ?
The joined file containes the modified curses class plus an class that
demonstrates how to use it (however it doesn't run)
--
Cheers,
zimba
http://zimba.oree.ch
------=_Part_6032_7248194.1133577613783
Content-Type: application/octet-stream; name=interface.rb
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="interface.rb"
require 'curses'
# curses sanitization
module Curses
@windows = Array.new
def self.windows
@windows
end
class Window
def init(buffer_size = 100, wrap = true)
@buffer = Array.new buffer_size, ''
@buffer_x = 0
@buffer_y = 0
@cursor_x = 0
@cursor_y = 0
@windows = Array.new
@line_wrap = wrap
Curses.windows.push self
end
def [](line_num)
@buffer[line_num]
end
def []=(line_num, line)
# TODO: check if data is in screen
@buffer[line_num] = line
old_setpos(line_num, 0)
if @line_wrap && line.length > maxx
addstr line[0..maxx] + "\n"
addstr line[maxx..line.length]
else
addstr line
end
# fill
addstr " " * (maxx - line.length)
old_setpos(line_num, line.length)
end
def puts(line)
# storage
if @cursor_x == @buffer.length-1
@buffer.pop
@buffer.push line
else
@cursor_x += 1
@buffer[@cursor_x] = line
end
# draw
if @line_wrap && line.length > maxx
addstr line[0..maxx] + "\n"
addstr line[maxx..line.length]
else
addstr line
end
end
alias :<<
def putc(char, y=nil, x=nil)
if y == nil
y = @cursor_y
end
if x == nil
x = @cursor_x
end
diff = @buffer[x].length - y
if diff < 0
@buffer[y] += " " * diff
end
@buffer[y][x] << char
end
alias
alias :gets :getstr
alias :getc :getch
alias
def refresh
old_refresh
end
alias
def clear
setpos(0,0)
@buffer.fill('')
super
end
alias
def setpos(y, x)
@cursor_y = y
@cursor_x = x
old_setpos y, x
end
alias
def move(y, x)
setpos(@cursor_y + y, @cursor_x + x)
end
alias
def subwin(height, width, top, left)
subwin = old_subwin height, width, top, left
subwin.init
@windows.push subwin
return subwin
end
alias
def close
@windows.each do |window|
window.close
end
Curses.windows.delete self
Curses.close_screen if Curses.windows.length == 0
old_close
end
end
end
module Interface
class Cursed
def initialize(server)
@server = server
Signal.trap('INT') do
exit
end
end
def run
Curses::init_screen # binds curses to the current interface
Curses::raw # cbreak or raw, allows direct char handling
Curses::noecho # we will manage user output ourselves
# keypad(true) # allow handling of the keypad keys
Curses::nonl
lines = Curses::lines
cols = Curses::cols
# interface setup
@w = Curses::Window.new(lines, cols, 0, 0)
@w.init
@title = @w.subwin(1, cols, 0, 0)
@title[0] = "*** Welcome in zchat ***"
@title.refresh
@main = @w.subwin(lines-3, cols, 1, 0)
@main.scrollok(true)
@main.refresh
@status = @w.subwin(1, cols, lines-2, 0)
@status[0] = @server.hostname + ": " + @server.channel.keys.join(', ')
@status.refresh
@input = @w.subwin(1, cols, lines-1, 0)
@input[0] = ENV['USER']+'@'(e-mail address removed)+'/#test$ '
@input.refresh
@server.channel["#test"].on_read do |line|
@main.puts line
@main.refresh
@input.refresh
end
# keyboard input handling
t = Thread.new do
buffer = ''
line = @input[0]
while true
chr = @input.getc
case chr
when 13 # ?\n
case buffer
when /^ls/
$server['#test'].puts '/NAMES #test'
when /^echo\s/
command = buffer[5..buffer.length-1]
@server['#test'].puts command + "\n" if command.length > 0
when /^join\s/
command = buffer[5..buffer.length-1]
@server.puts '/j ' + command
when '\quit', ':q', 'exit', 'quit'
exit
else
@status[0] = "command not found..."
@status.refresh
end
buffer = ''
@input.setpos(0, 0)
when 279168 # Curses::KEY_LEFT
@input.move(0, -1)
when 279167 # Curses::KEY_RIGHT
@input.move(0, +1)
when ?\C-c
exit
when ?\C-? # Curses::KEY_BACKSPACE
if buffer.length > 1
buffer = buffer[0..buffer.length-2] if buffer.length > 1
@input.move(0, -1)
else
buffer = ''
@input.setpos(0, 0)
end
else
buffer << chr
end
@input[0] = line + buffer
@input.refresh
end
end
t.join
end
def exit
@w.close
puts "Exiting zchat..."
@server.exit
Kernel.exit
end
end
end
------=_Part_6032_7248194.1133577613783--