#!/apacs/bin/wish -f # # layout canvas items in rows and columns with optional lines # # Version 1.1 # Last Modified: Fri Jan 6 09:27:36 1995 by Bryan M. Kramer # # Author: Bryan M. Kramer ([email protected]) # # Modifications and suggestions due to: # Brian Grossman <[email protected]> # # To Do List: # 1) straddle # # # # This has been implemented and tested using tcl7.3 and tk3.6. # It probably works with tk4.0. # # Copyright (c) 1995 University of Toronto # ====================================================================== # Permission to use, copy, modify, and distribute this software and its # documentation for any non-commercial purpose is hereby granted, # provided that the above copyright notice appear in all copies and that # both that the copyright notice and warranty disclaimer appear in # supporting documentation, and that the names of the University of Toronto # and Bryan M. Kramer not be used in advertising or publicity pertaining to # distribution of the software without specific, written prior permission. # # The University of Toronto and Bryan M. Kramer disclaim all warranties with # regard to this software, including all implied warranties of merchantability # and fitness. In no event shall the University of Toronto or Bryan M. Kramer # be liable for any special, indirect or consequential # damages or any damages whatsoever resulting from loss of use, data or # profits, whether in an action of contract, negligence or other # tortuous action, arising out of or in connection with the use or # performance of this software. # # # # USAGE example: # # set table [new_table] # pack $table # set canvas [table_canvas $table] # # table_col_defaults $table 5 1 5 grey # table_row_defaults $table 5 1 5 grey # table_col_info $table 1 5 3 5 black right # table_row_info $table 1 5 3 5 black # # set i [$canvas create text 10 10 -text "item 1 1"] # table_add $table $i 1 1 # set i [$canvas create text 10 10 -text "item 2 1"] # table_add $table $i 2 1 # set i [$canvas create text 10 10 -text "item 2 2"] # table_add $table $i 2 2 # # table_layout $table # # NOTE: # since canvases can take window items, this can be used to create # scrolling tables of buttons, entries etc.! # # # # # new_table [parent [-noscroll]] # - returns a frame containing a canvas and # vertical and horizontal scrollbars # - the returned name is the 'table' identifier # for the other table functions # - -noscroll skips making scrollbars and makes the # canvas big enough to show everything in it and make # table_fix_scroll will recalculate the canvas size # instead of recalculating the scrollregion. # # table_canvas table - return the canvas on which the table is to be drawn # USE this canvas for creating objects # # USER CAN REDEFINE the ABOVE two functions if other window arrangements are # desired # THE ONLY CONSTRAINT IS THAT [table_canvas table_id] return a canvas # containing # all the items that are to be layed out # # table_add table item row col - add an item to the table in position row,col # - ROW AND COL MUST BE >= 1 # - item is an integer identifying an object in # the canvas # # table_col_defaults table # [margin1 [rule_width [margin2 [rule_colour [alignment]]]]] # table_row_defaults table # [margin1 [rule_width [margin2 [rule_colour [alignment]]]]] # # - set up default row and column information # - between columns we have <space1, line, space2> # where space1 is margin1 pixels, the line has width # rule_width and space2 is margin2 pixels # - the line is drawn in rule_colour # - alignment specifies how objects are placed into cells # that are bigger than the space they need # - column alignments are one of left, right, or center # - row alignments are one of top, bottom, or center # # table_col_info table col # [margin1 [rule_width [margin2 [rule_colour [alignment]]]]] # table_row_info table row # [margin1 [rule_width [margin2 [rule_colour [alignment]]]]] # # - same as defaults except specifies a specific row or # column # - the rule information is for the line AFTER then nth # row or column # - use 0 to specify the rule_width and margin2 for the # leftmost or topmost line # # table_layout table - move the objects in the canvas so that rows and # columns accomodate the largest elements, aligning # the rest according to the alignment information # given for the table # - NOTE: can call this at any time, i.e. add new # items and redo layout is no problem # # table_fix_scroll table - change the scroll region of the canvas to # accomodate all objects on the canvas # # proc table_add {table item row col} { upvar \#0 tables$table x set x($row,$col) $item } proc table_sizes {table rn rowvector cn colvector} { upvar \#0 tables$table a upvar $rowvector row_h $rn rows upvar $colvector col_w $cn cols set rows 0 set cols 0 set cv [table_canvas $table] foreach key [array names a] { set l [split $key ,] set x [lindex $l 0] if {$x >= $rows} {set rows [expr $x + 1]} set y [lindex $l 1] if {$y >= $cols} {set cols [expr $y + 1]} set box [$cv bbox $a($key)] if {$box == ""} {continue} set width [expr [lindex $box 2] - [lindex $box 0]] set height [expr [lindex $box 3] - [lindex $box 1]] if [info exists row_h($x)] { if {$row_h($x) < $height} { set row_h($x) $height } } else { set row_h($x) $height } if [info exists col_w($y)] { if {$col_w($y) < $width} { set col_w($y) $width } } else { set col_w($y) $width } } } if {! [info exists table_num]} { set table_num 101 } proc new_table {{parent "."} args} { global table_num global table_SB set table_SB 1 foreach f $args { switch -- $f { -noscroll { set table_SB 0 } } } if {$parent == "."} { set fm ".table$table_num" } else { set fm "$parent.table$table_num" } incr table_num frame $fm frame $fm.inside set cv [canvas $fm.inside.c] pack $cv -side top -expand on -fill both if $table_SB { $cv configure -yscroll "$fm.scrolly set" $cv configure -xscroll "$fm.inside.scrollx set" scrollbar $fm.scrolly -command "$cv yview" bind $fm.scrolly <FocusIn> { tk_focusContinue %W } scrollbar $fm.inside.scrollx -command "$cv xview" -orient horiz bind $fm.inside.scrollx <FocusIn> { tk_focusContinue %W } pack $fm.inside.scrollx -side bottom -fill x pack $fm.scrolly -side right -fill y } pack $fm.inside -side left -expand on -fill both return $fm } proc table_canvas {table} { return "$table.inside.c" } proc table_fix_scroll {table} { set cv [table_canvas $table] $cv configure -scrollregion [$cv bbox all] global table_SB if {!$table_SB} { set box [$cv bbox all] if {$box == ""} {puts stderr "bbox error in table_fix_scroll" } $cv configure -height [expr [lindex $box 3] - [lindex $box 1]] $cv configure -width [expr [lindex $box 2] - [lindex $box 0]] } } proc table_margin1 {i infov defv} { upvar \#0 $infov info if {$i == 0} { return 0 } if [info exists info($i,m1)] { return $info($i,m1) } upvar \#0 $defv info if [info exists info(m1)] { return $info(m1) } return 0 } proc table_margin2 {i infov defv} { upvar \#0 $infov info if [info exists info($i,m2)] { return $info($i,m2) } upvar \#0 $defv info if [info exists info(m2)] { return $info(m2) } return 0 } proc table_rule {i infov defv} { upvar \#0 $infov info if [info exists info($i,rule)] { return $info($i,rule) } upvar \#0 $defv info if [info exists info(rule)] { return $info(rule) } return 0 } proc table_fill {i infov defv} { upvar \#0 $infov info if [info exists info($i,fill)] { return $info($i,fill) } upvar \#0 $defv info if [info exists info(fill)] { return $info(fill) } return black } proc table_just {i infov defv} { upvar \#0 $infov info if [info exists info($i,just)] { return $info($i,just) } upvar \#0 $defv info if [info exists info(just)] { return $info(just) } return left } proc table_margin_width {i info def} { return [expr [table_margin1 $i $info $def] + [table_margin2 $i $info $def] + [table_rule $i $info $def]] } proc table_col_info {table i {m1 0} {rule 0} {m2 0} {fill black} {just left}} { upvar \#0 table_col$table col_info set col_info($i,m1) $m1 set col_info($i,m2) $m2 set col_info($i,rule) $rule set col_info($i,fill) $fill set col_info($i,just) $just } proc table_row_info {table i {m1 0} {rule 0} {m2 0} {fill black} {just top}} { upvar \#0 table_row$table row_info set row_info($i,m1) $m1 set row_info($i,m2) $m2 set row_info($i,rule) $rule set row_info($i,fill) $fill set row_info($i,just) $just } proc table_col_defaults {table {m1 0} {rule 0} {m2 0} {fill black} {just left}} { upvar \#0 table_col_def$table col_info set col_info(m1) $m1 set col_info(m2) $m2 set col_info(rule) $rule set col_info(fill) $fill set col_info(just) $just } proc table_row_defaults {table {m1 0} {rule 0} {m2 0} {fill black} {just top}} { upvar \#0 table_row_def$table row_info set row_info(m1) $m1 set row_info(m2) $m2 set row_info(rule) $rule set row_info(fill) $fill set row_info(just) $just } proc table_draw_rules {table maxx maxy rows rowv cols colv row_info row_defaults col_info col_defaults} { upvar $rowv row_h $colv col_w set cv [table_canvas $table] $cv delete table_rules set maxx [expr $maxx - [table_margin2 [expr $rows - 1] $row_info $row_defaults]] set maxy [expr $maxy - [table_margin2 [expr $cols - 1] $col_info $col_defaults]] set x 0 for {set j 0} {$j < $cols} {} { set x [expr $x + [table_margin1 $j $col_info $col_defaults]] set w [table_rule $j $col_info $col_defaults] if {$w == 1} { set fill [table_fill $j $col_info $col_defaults] $cv create line $x 0 $x $maxy -tags table_rules -fill $fill -width $w } elseif {$w > 0} { set fill [table_fill $j $col_info $col_defaults] $cv create rectangle $x 0 [expr $x + $w - 1] $maxy -tags table_rules -fill $fill -outline $fill } set x [expr $x + $w + [table_margin2 $j $col_info $col_defaults]] incr j if [info exists col_w($j)] { set x [expr $x + $col_w($j)] } } set y 0 for {set j 0} {$j < $rows} {} { set y [expr $y + [table_margin1 $j $row_info $row_defaults]] set h [table_rule $j $row_info $row_defaults] if {$h == 1} { set fill [table_fill $j $row_info $row_defaults] $cv create line 0 $y $maxx $y -tags table_rules -fill $fill -width $h } elseif {$h > 0} { set fill [table_fill $j $row_info $row_defaults] $cv create rectangle 0 $y $maxx [expr $y + $h - 1] -tags table_rules -fill $fill -outline $fill } set y [expr $y + $h + [table_margin2 $j $row_info $row_defaults]] incr j if [info exists row_h($j)] { set y [expr $y + $row_h($j)] } } } proc table_just_x {box j colw col_info col_defaults} { set just [table_just $j $col_info $col_defaults] if {$just == "left"} { return 0 } elseif {$just == "right"} { set w [expr [lindex $box 2] - [lindex $box 0]] # must be greater than 0 by construction of column widths return [expr $colw - $w] } else { set w [expr [lindex $box 2] - [lindex $box 0]] return [expr ($colw -$w) / 2.0] } } proc table_just_y {box j rowh row_info row_defaults} { set just [table_just $j $row_info $row_defaults] if {$just == "top" || $just == "left"} { return 0 } elseif {$just == "bottom" || $just == "right"} { set w [expr [lindex $box 3] - [lindex $box 1]] # must be greater than 0 by construction of rowumn widths return [expr $rowh - $w] } else { set w [expr [lindex $box 3] - [lindex $box 1]] return [expr ($rowh -$w) / 2.0] } } proc table_layout {table} { upvar \#0 tables$table a set row_info "table_row$table" set col_info "table_col$table" set row_defaults "table_row_def$table" set col_defaults "table_col_def$table" table_sizes $table rows row_h cols col_w set cv [table_canvas $table] set x [table_margin_width 0 $col_info $col_defaults] for {set j 1} {$j < $cols} {incr j} { set y [table_margin_width 0 $row_info $row_defaults] if [info exists col_w($j)] { set w $col_w($j) } else { set w 0 } for {set i 1} {$i < $rows} {incr i} { if [info exists a($i,$j)] { set item $a($i,$j) set h $row_h($i) set box [$cv bbox $item] set xx [expr $x + [table_just_x $box $j $w $col_info $col_defaults]] set yy [expr $y + [table_just_y $box $i $h $row_info $row_defaults]] $cv move $item [expr $xx - [lindex $box 0]] [expr $yy - [lindex $box 1]] } if [info exists row_h($i)] { set y [expr $y + $row_h($i)] } set y [expr $y + [table_margin_width $i $row_info $row_defaults]] } if [info exists col_w($j)] { set x [expr $x + $col_w($j)] } set x [expr $x + [table_margin_width $j $col_info $col_defaults]] } table_draw_rules $table $x $y $rows row_h $cols col_w $row_info $row_defaults $col_info $col_defaults } #Local Variables: #mode: tcl #End: