# ListBox - A GTK Listbox
#--
###################################################################################
#
# ListBox - A GTK Listbox
# Copyright (C) 2007 Lake Information Works
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
# Contact: alan.lake AT lakeinfoworks DOT com
# Lake Information Works
# Kalervonkatu 13 A 2
# 20400 Jyväskylä
# Finland
#
###################################################################################
#++
=begin rdoc
Sample usage
Gtk.init
@main_window = Gtk::Window.new
@main_window.set_default_size 500,300
lb_left = ListBox.new
lb_left.header = 'Ad Groups'
lb_left.append('ulkomaanpuhelut')
lb_left.append('kaukopuhelut')
lb_left.append('suuntanumerot')
lb_right = ListBox.new
lb_right.header = 'State Nicknames'
lb_right.fill(['Empire','Golden','Silver','Sooner','Hoosier','Razorback','Buckeye','Lone Star'])
box = Gtk::HBox.new
@main_window.add(box)
box.pack_start(lb_left,true)
box.pack_start(lb_right,true)
@main_window.show_all
@main_window.signal_connect("destroy") { Gtk.main_quit }
lb_left.signal_connect('button_release_event') do |widget,event|
puts lb_left.button_release(widget,event)
end
lb_left.signal_connect('key-release-event') do |widget,event|
selection = lb_left.key_release(widget,event)
puts "#{selection}" if selection.class == String
end
# Note that no signal_connect code has been written for lb_right, so a selection cannot be made.
Gtk.main
=end
=begin rdoc
Purpose:
1. Document how to create a GTK widget in Ruby.
2. Create a general purpose listbox.
Credit:
Mathieu Blondel responded to my post on the Ruby Forum to teach me how to
create a valid widget. http://www.ruby-forum.com/topic/126951
Assumptions:
This document doesn't attempt to teach Ruby or GTK programming (or the
combination. Therefore, we assume that the reader knows how to create a
Ruby Class.
What's a widget?
http://www.webopedia.com/TERM/W/widget.html defines a widget. The listbox shown
here provides a way for the user to interface with an application by using the
mouse or keyboard to select an item in the list, whereupon the listbox
communicates the selection to the application.
What is provided here:
The following is in two parts: The class that creates the listbox widget and a
piece of code that illustrates the use of it. I will include comments in the
code that shows what needs to be done to make a class into a widget, but will
not completely comment the code. I am commenting the parts involved with
inheritance because it is the inheritance that makes ListBox a widget.
This listbox is extremely basic. The minimalistic design meets my need for a
listbox and makes it easier to highlight what it is that makes it a widget.
Furthermore, the fact that it is basic will allow me or another programmer to
easily modify it to include more sophisticated features.
=end
=begin rdoc
ListBox inherits Gtk::ScrolledWindow. ScrolledWindow was chosen because
(1) ScrolledWindow is a widget. This fact can be shown with interactive ruby
(irb) by doing (a) or (b):
(a)
[alan@erie ~]$ irb
irb(main):001:0> require 'gtk2'
=> true
irb(main):002:0> sw = Gtk::ScrolledWindow.new
=> #
irb(main):003:0> sw.is_a? Gtk::Widget
=> true
(b)
[alan@erie ~]$ irb
irb(main):001:0> require 'gtk2'
=> true
irb(main):002:0> Gtk::ScrolledWindow.ancestors
=> [Gtk::ScrolledWindow, Gtk::Bin, Gtk::Container, Gtk::Widget, Atk::Implementor, GLib::Interface, GLib::MetaInterface, Gtk::Object, GLib::InitiallyUnowned, GLib::Object, GLib::Instantiatable, Object, Kernel]
Note that Gtk::Widget is among ScrolledWindow's ancestors.
(2) the scrolled window part of this widget is the part that the user adds
to the GUI application.
=end
class ListBox < Gtk::ScrolledWindow
=begin rdoc
"super()" is needed because the Listbox class is inherited.
"self" refers to the ListBox, but because ListBox inherits ScrolledWindow, references to this scrolled window are also made with "self".
=end
def initialize
super()
tbl = Gtk::Table.new(2,2,false) # 2 rows, 2 columns, not homogeneous
self.hscrollbar_policy = Gtk::PolicyType::AUTOMATIC
self.vscrollbar_policy = Gtk::PolicyType::AUTOMATIC
self.shadow_type = Gtk::ShadowType::NONE
self.window_placement= Gtk::CornerType::TOP_LEFT
@renderer=Gtk::CellRendererText.new
@renderer.set_property( 'background', 'lavender' )
@renderer.set_property( 'foreground', 'black' )
@list_store = Gtk::ListStore.new(String)
@tree_view = Gtk::TreeView.new(@list_store)
col_hdr = ''
@tree_view_col1 = Gtk::TreeViewColumn.new(col_hdr, @renderer, {:text => 0})
@tree_view_col1.sizing = Gtk::TreeViewColumn::AUTOSIZE
@text_col = 0
@tree_view.append_column(@tree_view_col1)
@tree_view.headers_visible = false
@tree_view.selection.mode = Gtk::SELECTION_SINGLE
tbl.attach_defaults(@tree_view,0,2,0,2) # widget, left, right, top, bottom
self.add_with_viewport(tbl)
end # def initialize
=begin rdoc
Appends a string to ListBox's list.
=end
def append(str)
iter = @list_store.append
iter.set_value(0, str)
end
=begin rdoc
This is a significant part of the widget, providing communication from it to the application.
Called by a signal connect mouse button_release_event:
lb_left.signal_connect('button_release_event') do |widget,event|
puts lb_left.button_release(widget,event)
end
Returns: The string that is selected.
=end
def button_release(widget,event,type='text')
path, column, cell_x, cell_y = @tree_view.get_path_at_pos(event.x, event.y)
return path if type == 'line_nbr'
@tree_view.selection.selected[@tree_view.columns.index(column)] if type == 'text'
end
=begin rdoc
Clears the ListBox's list
=end
def clear
@list_store.clear
end
=begin rdoc
Fills the ListBox's list from the array of "items".
=end
def fill(items)
items.each { |item| self.append(item) }
end
=begin rdoc
Provides a header for the list.
=end
def header=(hdr)
@tree_view.headers_visible = true unless @tree_view.headers_visible?
@tree_view_col1.title = hdr
end
=begin rdoc
This is a significant part of the widget, providing communication from it to the application.
Called by a signal connect key_release_event, which occurs when the user uses keys to navigate:
lb_left.signal_connect('key-release-event') do |widget,event|
selection = lb_left.key_release(widget,event)
puts "#{selection}" if selection.class == String
end
Returns: Selected string if the Enter or Return key is pressed; nil if any other key is pressed. The up and down keys navigate the list.
=end
def key_release(widget,event)
return nil unless event.keyval == 65293 # Enter
column = @tree_view.get_column(0)
@tree_view.selection.selected[@tree_view.columns.index(column)]
end
=begin rdoc
Select the item in the list that is equal to text
=end
def select(text)
iter = @list_store.iter_first
begin
if iter[@text_col] == text
@tree_view.selection.select_iter(iter)
return true
end
end while iter.next!
return false
end
=begin rdoc
Synonym for the header=(hdr) method.
=end
def set_header(hdr)
self.header = hdr
end
=begin rdoc
Returns the text of line .
=end
def text_at_line(nbr)
iter = @list_store.iter_first
line_nbr = 0
begin
return iter.get_value(@text_col) if line_nbr == nbr
line_nbr += 1
end while iter.next!
return []
end
end