#!/usr/bin/env ruby # widget -- # This script demonstrates the various widgets provided by Tk, # along with many of the features of the Tk toolkit. This file # only contains code to generate the main window for the # application, which invokes individual demonstrations. The # code for the actual demonstrations is contained in separate # ".rb" files is this directory, which are sourced by this script # as needed. require 'tk' unless /^8\.[1-9]/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK require 'tkencoding' end require 'tkafter' ### $DEBUG=1 ########## #---------------------------------------------------------------- # The code below create the main window, consisting of a menu bar # and a text widget that explains how to use the program, plus lists # all of the demos as hypertext items. #---------------------------------------------------------------- # widget demo directory $demo_dir = File.dirname($0) # root $root = TkRoot.new{title "Ruby/Tk Widget Demonstration"} # tk $tk_version = Tk::TK_VERSION # tcl_platform $tk_platform = TkVarAccess.new('tcl_platform') # $font = TkFont.new('-*-Helvetica-Medium-R-Normal--*-140-*-*-*-*-*-*', nil) # TkMenubar.new($root, [[['File', 0], ['About ... ', proc{aboutBox}, 0, ''], '---', ['Quit', proc{exit}, 0, 'Meta-Q'] ]]).pack('side'=>'top', 'fill'=>'x') $root.bind('F1', proc{aboutBox}) =begin TkFrame.new($root){|frame| TkMenubutton.new(frame){|button| m = TkMenu.new(button) { add 'command', 'label'=>'Quit', 'command'=>proc{exit}, 'underline'=>0 } menu m text 'File' underline 0 }.pack('side'=>'left') }.pack('side'=>'top', 'fill'=>'x') =end # if $tk_version =~ /^4\.[01]/ scr = TkScrollbar.new($root, 'orient'=>'vertical') txt = TkText.new($root) { wrap 'word' width 60 height 30 font $font setgrid 'yes' yscrollcommand proc{|first,last| scr.set first,last} } scr.command(proc{|*args| txt.yview(*args)}) scr.pack('side'=>'right', 'fill'=>'y') txt.pack('expand'=>'yes', 'fill'=>'both') else textFrame = TkFrame.new($root) scr = TkScrollbar.new($root, 'orient'=>'vertical', 'highlightthickness'=>0, 'takefocus'=>1) { pack('in'=>textFrame, 'side'=>'right', 'fill'=>'y', 'padx'=>1) } txt = TkText.new($root) { wrap 'word' width 60 height 30 font $font setgrid 'yes' highlightthickness 0 padx 4 pady 2 takefocus 0 yscrollcommand proc{|first,last| scr.set first,last} } scr.command(proc{|*args| txt.yview(*args)}) # txt.pack('in'=>textFrame, 'expand'=>'yes', 'fill'=>'both', 'padx'=>1) txt.pack('in'=>textFrame, 'expand'=>'yes', 'fill'=>'both') # textFrame.pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>2) textFrame.pack('expand'=>'yes', 'fill'=>'both') statusBar = TkFrame.new($root) {|f| $statusBarLabel = \ TkLabel.new(f, 'text'=>" ", 'relief'=>'sunken', 'bd'=>1, 'anchor'=>'w', 'font'=>'-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') \ .pack('side'=>'left', 'padx'=>2, 'expand'=>'yes', 'fill'=>'both') TkLabel.new(f, 'width'=>8, 'relief'=>'sunken', 'bd'=>1, 'anchor'=>'w', 'font'=>'-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') \ .pack('side'=>'left', 'padx'=>2) }.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>2) end # Create a bunch of tags to use in the text widget, such as those for # section titles and demo descriptions. Also define the bindings for # tags. tag_title = TkTextTag.new(txt, 'font'=>'-*-Helvetica-Bold-R-Normal--*-180-*-*-*-*-*-*') # We put some "space" characters to the left and right of each demo description # so that the descriptions are highlighted only when the mouse cursor # is right over them (but not when the cursor is to their left or right) tag_demospace = TkTextTag.new(txt, 'lmargin1'=>'1c', 'lmargin2'=>'1c') if TkWinfo.depth($root) == '1' tag_demo = TkTextTag.new(txt, 'lmargin1'=>'1c', 'lmargin2'=>'1c', 'underline'=>1) $tag_visited = TkTextTag.new(txt, 'lmargin1'=>'1c', 'lmargin2'=>'1c', 'underline'=>1) tag_hot = TkTextTag.new(txt, 'background'=>'black', 'foreground'=>'white') else tag_demo = TkTextTag.new(txt, 'lmargin1'=>'1c', 'lmargin2'=>'1c', 'foreground'=>'blue', 'underline'=>1) $tag_visited = TkTextTag.new(txt, 'lmargin1'=>'1c', 'lmargin2'=>'1c', 'foreground'=>'#303080', 'underline'=>1) # tag_hot = TkTextTag.new(txt, 'relief'=>'raised', 'borderwidth'=>1, # 'background'=>'SeaGreen3') tag_hot = TkTextTag.new(txt, 'borderwidth'=>1, 'foreground'=>'red') end #tag_demo.bind('Button-1', proc{invoke txt, txt.index('current')}) tag_demo.bind('ButtonRelease-1', proc{|x,y|invoke txt, txt.index("@#{x},#{y}")}, '%x %y') lastLine = TkVariable.new("") newLine = TkVariable.new("") tag_demo.bind('Enter', proc{|x,y| lastLine.value = txt.index("@#{x},#{y} linestart") tag_hot.add(lastLine.value, "#{lastLine.value} lineend") showStatus txt, txt.index("@#{x},#{y}") }, '%x %y') tag_demo.bind('Leave', proc{ tag_hot.remove('1.0','end') txt.configure('cursor','xterm') $statusBarLabel.configure('text'=>"") }) tag_demo.bind('Motion', proc{|x, y| newLine.value = txt.index("@#{x},#{y} linestart") if newLine.value != lastLine.value tag_hot.remove('1.0','end') lastLine.value = newLine.value if ( txt.tag_names("@#{x},#{y}").find{|t| t.kind_of?(String) && t =~ /^demo-/ } ) tag_hot.add(lastLine.value, "#{lastLine.value} lineend -1 chars") end end showStatus txt, txt.index("@#{x},#{y}") }, '%x %y') # Create the text for the text widget. txt.insert('end', "Ruby/Tk Widget Demonstrations\n\n", tag_title) txt.insert('end', <'top', 'fill'=>'x') len = 1 args.each{|vnam,vbody| len = vnam.to_s.length if vnam.to_s.length > len } args.each{|vnam,vbody| TkFrame.new(w){|f| #TkLabel.new(f, 'text'=>"#{vnam}: ").pack('side'=>'left') TkLabel.new(f, 'text'=>"#{vnam}: ",'width'=>len+2).pack('side'=>'left') TkLabel.new(f, 'textvariable'=>vbody, 'anchor'=>'w')\ .pack('side'=>'left', 'expand'=>'yes', 'fill'=>'x') }.pack('side'=>'top', 'anchor'=>'w', 'fill'=>'x') } TkButton.new(w) { text "OK" command proc{w.destroy} }.pack('side'=>'bottom', 'pady'=>2) } $showVarsWin[parent.path] = w end # invoke -- # This procedure is called when the user clicks on a demo description. # It is responsible for invoking the demonstration. # # Arguments: # index - The index of the character that the user clicked on. def invoke (txt, index) tag = txt.tag_names(index).find{|t| t.kind_of?(String) && t =~ /^demo-/} return unless tag cursor = txt.cget('cursor') txt.cursor('watch') Tk.update # eval `cat #{tag[5..-1]}.rb` eval `cat #{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb` Tk.update # txt.cursor('xterm') txt.cursor(cursor) $tag_visited.add("#{index} linestart +1 chars", "#{index} lineend +1 chars") end # showStatus -- # # Show the name of the demo program in the status bar. This procedure # is called when the user moves the cursor over a demo description. # def showStatus (txt, index) tag = txt.tag_names(index).find{|t| t.kind_of?(String) && t =~ /^demo-/} cursor = txt.cget('cursor') unless tag $statusBarLabel.configure('text', " ") newcursor = 'xterm' else demoname = tag[5..-1] $statusBarLabel.configure('text', "Run the \"#{demoname}\" sample program") newcursor = 'hand2' end txt.configure('cursor'=>newcursor) if cursor != newcursor end # showCode -- # This procedure creates a toplevel window that displays the code for # a demonstration and allows it to be edited and reinvoked. # # Arguments: # w - The name of the demonstration's window, which can be # used to derive the name of the file containing its code. def showCode (demo) file = "#{demo}.rb" $code_window = nil unless defined? $code_window if $code_window == nil || TkWinfo.exist?($code_window) == '0' $code_window = TkToplevel.new(nil) f = TkFrame.new($code_window) TkButton.new(f) { text "Dismiss" command proc{ $code_window.destroy $code_window = nil } }.pack('side'=>'left', 'expand'=>'yes', 'pady'=>2) TkButton.new(f) { text "Rerun Demo" command proc{eval($code_text.get('1.0','end'))} }.pack('side'=>'left', 'expand'=>'yes', 'pady'=>2) # f.pack('side'=>'bottom', 'expand'=>'yes', 'fill'=>'x') f.pack('side'=>'bottom', 'fill'=>'x') if $tk_version =~ /^4\.[01]/ s = TkScrollbar.new($code_window, 'orient'=>'vertical') $code_text = TkText.new($code_window) { height 40 setgrid 'yes' yscrollcommand proc{|first,last| s.set first,last} } s.command(proc{|*args| $code_text.yview(*args)}) s.pack('side'=>'right', 'fill'=>'y') $code_text.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'both') else TkFrame.new($code_window) {|f| pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1) hs = TkScrollbar.new($code_window, 'highlightthickness'=>0, 'orient'=>'horizontal') vs = TkScrollbar.new($code_window, 'highlightthickness'=>0, 'orient'=>'vertical') $code_text = TkText.new($code_window) {|t| height 40 wrap 'word' xscrollcommand proc{|first,last| hs.set first,last} yscrollcommand proc{|first,last| vs.set first,last} setgrid 'yes' highlightthickness 0 pady 2 padx 3 hs.command(proc{|*args| $code_text.xview(*args)}) vs.command(proc{|*args| $code_text.yview(*args)}) } $code_text.grid('in'=>f, 'padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') vs.grid('in'=>f, 'padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>1, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') # xs.grid('in'=>f, 'padx'=>1, 'pady'=>1, 'row'=>1, 'column'=>0, # 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') # JKC 2001-07-26: segfaults under 1.7.1 (2001-06-19) [i686-linux] TkGrid.rowconfigure(f, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure(f, 0, 'weight'=>1, 'minsize'=>0) } end else $code_window.deiconify $code_window.raise end $code_window.title("Demo code: #{file}") $code_window.iconname(file) # fid = open(file, 'r') fid = open([$demo_dir, file].join(File::Separator), 'r') $code_text.delete('1.0', 'end') #$code_text.insert('1.0', `cat #{file}`) $code_text.insert('1.0', fid.read) #$code_mark = TkTextMark.new($code_text, '1.0') #$code_text.set_insert('1.0') TkTextMarkInsert.new($code_text,'1.0') fid.close end # aboutBox # # Pops up a message box with an "about" message # def aboutBox Tk.messageBox('icon'=>'info', 'type'=>'ok', 'title'=>'About Widget Demo', 'message'=>"Ruby/Tk widget demonstration Ver.1.0.2\n\n( based on Tk 8.1 Copyright (c) 1996-1997 Sun Microsystems, Inc. )\n\nRunning Version :: Ruby#{VERSION}/Tk#{$tk_version}") end ################################ Tk.mainloop