home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World 2000 December
/
PCWorld_2000-12_cd.bin
/
Komunikace
/
Comanche
/
comanche.exe
/
lib
/
iwidgets2.2.0
/
scripts
/
canvasprintbox.itk
< prev
next >
Wrap
Text File
|
1999-02-24
|
36KB
|
1,291 lines
#
# CanvasPrintBox v1.5
# ----------------------------------------------------------------------
# Implements a print box for printing the contents of a canvas widget
# to a printer or a file. It is possible to specify page orientation, the
# number of pages to print the image on and if the output should be
# stretched to fit the page.
#
# CanvasPrintBox is a "super-widget" that can be used as an
# element in ones own GUIs. It is used to print the contents
# of a canvas (called the source hereafter) to a printer or a
# file. Possible settings include: portrait and landscape orientation
# of the output, stretching the output to fit the page while maintaining
# a proper aspect-ratio and posterizing to enlarge the output to fit on
# multiple pages. A stamp-sized copy of the source will be shown (called
# the stamp hereafter) at all times to reflect the effect of changing
# the settings will have on the output.
#
# ----------------------------------------------------------------------
# AUTHOR: Tako Schotanus EMAIL: Tako.Schotanus@bouw.tno.nl
# ----------------------------------------------------------------------
# Copyright (c) 1995 Tako Schotanus
# ======================================================================
# Permission is hereby granted, without written agreement and without
# license or royalty fees, to use, copy, modify, and distribute this
# software and its documentation for any purpose, provided that the
# above copyright notice and the following two paragraphs appear in
# all copies of this software.
#
# IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
# IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
# DAMAGE.
#
# THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
# ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
# ======================================================================
#
# Default resources.
#
option add *Canvasprintbox.filename "canvas.ps" widgetDefault
option add *Canvasprintbox.hPageCnt 1 widgetDefault
option add *Canvasprintbox.orient landscape widgetDefault
option add *Canvasprintbox.output printer widgetDefault
option add *Canvasprintbox.pageSize A4 widgetDefault
option add *Canvasprintbox.posterize 0 widgetDefault
option add *Canvasprintbox.printCmd lpr widgetDefault
option add *Canvasprintbox.printRegion "" widgetDefault
option add *Canvasprintbox.vPageCnt 1 widgetDefault
#
# Usual options.
#
itk::usual Canvasprintbox {
keep -background -cursor -textbackground
}
#<
#
# CanvasPrintBox is a "super-widget" that can be used as an
# element in ones own GUIs. It is used to print the contents
# of a canvas (called the source hereafter) to a printer or a
# file. Possible settings include: portrait and landscape orientation
# of the output, stretching the output to fit the page while maintaining
# a proper aspect-ratio and posterizing to enlarge the output to fit on
# multiple pages. A stamp-sized copy of the source will be shown (called
# the stamp hereafter) at all times to reflect the effect of changing
# the settings will have on the output.
#
#>
class iwidgets::Canvasprintbox {
inherit itk::Widget
#
# Just holds the names of some widgets/objects. "win" is used to
# determine if the object is fully constructed and initialized.
#
protected variable win ""
protected variable canvw ""
#
# The canvas we want to print.
#
protected variable canvas ""
#
# Boolean indicating if the attribute "orient" is set
# to landscape or not.
#
protected variable rotate 1
#
# Holds the configure options that were used to create this object.
#
protected variable init_opts ""
#
# The following attributes hold a list of lines that are
# currently drawn on the "stamp" to show how the page(s) is/are
# oriented. The first holds the vertical dividing lines and the
# second the horizontal ones.
#
protected variable hlines ""
protected variable vlines ""
#
# Updating is set when the thumbnail is being drawn. Settings
# this to 0 while drawing is still busy will terminate the
# proces.
# Restart_update can be set to 1 when the thumbnail is being
# drawn to force a redraw.
#
protected variable updating 0
protected variable restart_update 0
#
# Holds the current state for all check- and radiobuttons.
#
private common prtcanvglob
itk_option define -filename filename FileName ""
itk_option define -hpagecnt hPageCnt PageCnt 1
itk_option define -orient orient Orient "landscape"
itk_option define -output output Output "printer"
itk_option define -pagesize pageSize PageSize "A4"
itk_option define -posterize posterize Posterize 0
itk_option define -printcmd printCmd PrintCmd ""
itk_option define -printregion printRegion PrintRegion ""
itk_option define -stretch stretch Stretch 0
itk_option define -vpagecnt vPageCnt PageCnt 1
constructor {args} {}
destructor {}
# ---------------------------------------------------------------
# PUBLIC METHODS
#----------------------------------------------------------------
method getoutput {}
method print {}
method refresh {}
method setcanvas {canv}
method stop {}
# ---------------------------------------------------------------
# PROTECTED METHODS
#----------------------------------------------------------------
protected method _calc_poster_size {}
protected method _calc_print_region {}
protected method _calc_print_scale {}
protected method _calc_stamp_scale {}
protected method _config_optimum {}
protected method _mapEventHandler {}
protected method _update_UI {}
protected method _update_attr {}
protected method _update_canvas {}
protected method _update_canvas_thread {}
protected method _update_prtfile {}
protected method _update_widgets {}
# ---------------------------------------------------------------
# PUBLIC CLASS METHODS
#----------------------------------------------------------------
public proc ezPaperInfo {size {attr ""} \
{orient "portrait"} {window ""}} {}
}
#
# Provide a lowercased access method for the Canvasprintbox class.
#
proc ::iwidgets::canvasprintbox {args} {
uplevel ::iwidgets::Canvasprintbox $args
}
# ------------------------------------------------------------------
# OPTIONS
# ------------------------------------------------------------------
#<
# A list of four coordinates specifying which part of the canvas to print.
# An empty list means that the canvas' entire scrollregion should be
# printed. Any change to this attribute will automatically update the "stamp".
# Defaults to an empty list.
#>
configbody iwidgets::Canvasprintbox::printregion {
if {$itk_option(-printregion) != ""
&& [llength $itk_option(-printregion)] != 4} {
error {bad option "printregion": should contain 4 coordinates}
}
_update_canvas
}
#<
# Specifies where the postscript output should go: to the printer
# or to a file. Can take on the values "printer" or "file".
# The corresponding entry-widget will reflect the contents of
# either the printcmd attribute or the filename attribute.
#>
configbody iwidgets::Canvasprintbox::output {
case $itk_option(-output) {
file {
}
printer {
}
default {
error {bad output option \"$itk_option(-output)\":\
should be file or printer}
}
}
_update_UI
}
#<
# The command to execute when printing the postscript output.
# The command will get the postscript directed to its standard
# input. (Only when output is set to "printer")
#>
configbody iwidgets::Canvasprintbox::printcmd {
if {$win != ""} {
set itk_option(-output) "printer"
}
_update_UI
}
#<
# The file to write the postscript output to (Only when output
# is set to "file"). If posterizing is turned on and hpagecnt
# and/or vpagecnt is more than 1, x.y is appended to the filename
# where x is the horizontal page number and y the vertical page number.
#>
configbody iwidgets::Canvasprintbox::filename {
if {$win != ""} {
set itk_option(-output) "file"
}
_update_UI
}
#<
# The pagesize the printer supports. Changes to this attribute
# will be reflected immediately in the "stamp".
#>
configbody iwidgets::Canvasprintbox::pagesize {
set opt [string tolower $itk_option(-pagesize)]
set lst [string tolower [ezPaperInfo types]]
if {[lsearch $lst $opt] == -1} {
error "bad option \"pagesize\": should be one of: [ezPaperInfo types]"
}
_update_UI
_update_canvas
}
#<
# Determines the orientation of the output to the printer (or file).
# It can take the value "portrait" or "landscape" (default). Changes
# to this attribute will be reflected immediately in the "stamp".
#>
configbody iwidgets::Canvasprintbox::orient {
case $itk_option(-orient) {
portrait {
}
landscape {
}
default {
error {bad orient option \"$itk_option(-orient)\":\
should be portrait or landscape}
}
}
_update_UI
_update_canvas
}
#<
# Determines if the output should be stretched to fill the
# page (as defined by the attribute pagesize) as large as
# possible. The aspect-ratio of the output will be retained
# and the output will never fall outside of the boundaries
# of the page.
#>
configbody iwidgets::Canvasprintbox::stretch {
if {$itk_option(-stretch) != 0 && $itk_option(-stretch) != 1} {
error {bad option "stretch": should be a boolean}
}
_update_UI
}
#<
# Indicates if posterizing is turned on or not. Posterizing
# the output means that it is possible to distribute the
# output over more than one page. This way it is possible to
# print a canvas/region which is larger than the specified
# pagesize without stretching. If used in combination with
# stretching it can be used to "blow up" the contents of a
# canvas to as large as size as you want (See attributes:
# hpagecnt end vpagecnt). Any change to this attribute will
# automatically update the "stamp".
#>
configbody iwidgets::Canvasprintbox::posterize {
if {$itk_option(-posterize) != 0 && $itk_option(-posterize) != 1} {
error {bad option "posterize": should be a boolean}
}
_update_UI
_update_canvas
}
#<
# Is used in combination with "posterize" to determine over
# how many pages the output should be distributed. This
# attribute specifies how many pages should be used horizontaly.
# Any change to this attribute will automatically update the "stamp".
#>
configbody iwidgets::Canvasprintbox::hpagecnt {
_update_UI
_update_canvas
}
#<
# Is used in combination with "posterize" to determine over
# how many pages the output should be distributed. This
# attribute specifies how many pages should be used verticaly.
# Any change to this attribute will automatically update the "stamp".
#>
configbody iwidgets::Canvasprintbox::vpagecnt {
_update_UI
_update_canvas
}
# ------------------------------------------------------------------
# CONSTRUCTOR
# ------------------------------------------------------------------
body iwidgets::Canvasprintbox::constructor {args} {
itk_component add outputom {
iwidgets::optionmenu $itk_interior.outputom \
-labelmargin 5 -labelpos w -cyclicon 1\
-labeltext "Output to :" \
-items {Printer File} \
-command [code $this _update_attr]
} {
keep -cursor -background
}
$itk_component(outputom) select Printer
pack $itk_component(outputom) \
-anchor center -expand 0 -fill x -ipadx 0 -ipady 0 \
-padx 0 -pady 0 -side top
itk_component add prtflentry {
iwidgets::entryfield $itk_interior.prtflentry \
-labeltext {Printer command :} \
-command [code $this _update_prtfile]
} {
keep -background -cursor -textbackground
}
pack $itk_component(prtflentry) \
-anchor center -expand 0 -fill x -ipadx 0 -ipady 0 \
-padx 0 -pady 0 -side top
itk_component add paperom {
iwidgets::optionmenu $itk_interior.paperom \
-labelmargin 5 -labelpos w -cyclicon 1\
-labeltext "Paper size :" \
-command [code $this refresh]
} {
keep -cursor -background
}
$itk_component(paperom) configure -items [ezPaperInfo types]
$itk_component(paperom) select A4
pack $itk_component(paperom) \
-anchor center -expand 0 -fill x -ipadx 0 -ipady 0 \
-padx 0 -pady 0 -side top
itk_component add canvasframe {
frame $itk_interior.f18 -borderwidth 2 -relief ridge
} {
keep -background -cursor
}
pack $itk_component(canvasframe) \
-anchor center -expand 1 -fill both -ipadx 0 -ipady 0 \
-padx 2 -pady 2 -side top
itk_component add canvas {
canvas $itk_component(canvasframe).c1 \
-borderwidth 2 -relief sunken \
-scrollregion {0c 0c 10c 10c} \
-width 100 -height 100
} {
keep -background -cursor
}
pack $itk_component(canvas) \
-anchor center -expand 1 -fill both -ipadx 0 -ipady 0 \
-padx 0 -pady 9 -side top
itk_component add optionsframe {
frame $itk_interior.f26 -borderwidth 2
} {
keep -background -cursor
}
pack $itk_component(optionsframe) \
-anchor center -expand 0 -fill x -ipadx 0 -ipady 0 \
-padx 2 -pady 4 -side top
itk_component add orientom {
iwidgets::optionmenu $itk_component(optionsframe).orientom \
-labelmargin 5 -labelpos w -cyclicon 1\
-labeltext "Orientation :" \
-items {Portrait Landscape} \
-command [code $this refresh]
} {
keep -cursor -background
}
$itk_component(orientom) select Landscape
pack $itk_component(orientom) \
-anchor center -expand 0 -fill x -ipadx 0 -ipady 0 \
-padx 0 -pady 0 -side top
itk_component add stretchframe {
frame $itk_component(optionsframe).f14 -borderwidth 2
} {
keep -background -cursor
}
pack $itk_component(stretchframe) \
-anchor center -expand 0 -fill x -ipadx 0 -ipady 0 \
-padx 0 -pady 0 -side top
set prtcanvglob($this,stretchcb) 0
itk_component add stretchcb {
checkbutton $itk_component(stretchframe).cb1 \
-relief flat -text {Stretch to fit} \
-variable [scope prtcanvglob($this,stretchcb)] \
-command [code $this refresh]
} {
keep -background -cursor
}
pack $itk_component(stretchcb) \
-anchor center -expand 0 -fill none -ipadx 0 -ipady 0 \
-padx 0 -pady 0 -side left
itk_component add posterframe {
frame $itk_component(optionsframe).f15 -borderwidth 2
} {
keep -background -cursor
}
pack $itk_component(posterframe) \
-anchor center -expand 0 -fill x -ipadx 0 -ipady 0 \
-padx 0 -pady 0 -side top
set prtcanvglob($this,postercb) 0
itk_component add postercb {
checkbutton $itk_component(posterframe).cb1 \
-relief flat -text {Posterize on} \
-variable [scope prtcanvglob($this,postercb)] \
-command [code $this refresh]
} {
keep -background -cursor
}
pack $itk_component(postercb) \
-anchor center -expand 0 -fill none -ipadx 0 -ipady 0 \
-padx 0 -pady 0 -side left
itk_component add hpcnt {
iwidgets::entryfield $itk_component(posterframe).e1 \
-validate integer -width 3 \
-command [code $this refresh]
} {
keep -cursor -background -textbackground
}
pack $itk_component(hpcnt) \
-anchor center -expand 0 -fill x -ipadx 0 -ipady 0 \
-padx 0 -pady 0 -side left
itk_component add posterlbl1 {
label $itk_component(posterframe).l1 -text by
} {
keep -background -cursor
}
pack $itk_component(posterlbl1) \
-anchor center -expand 0 -fill none -ipadx 0 -ipady 0 \
-padx 0 -pady 0 -side left
itk_component add vpcnt {
iwidgets::entryfield $itk_component(posterframe).e2 \
-validate integer -width 3 \
-command [code $this refresh]
} {
keep -cursor -background -textbackground
}
pack $itk_component(vpcnt) \
-anchor center -expand 0 -fill none -ipadx 0 -ipady 0 \
-padx 0 -pady 0 -side left
itk_component add posterlbl2 {
label $itk_component(posterframe).l2 -text pages.
} {
keep -background -cursor
}
pack $itk_component(posterlbl2) \
-anchor center -expand 0 -fill none -ipadx 0 -ipady 0 \
-padx 0 -pady 0 -side left
bind $itk_component(canvas) <Map> [code $this _mapEventHandler]
bind $itk_component(canvas) <Configure> [code $this refresh]
set init_opts $args
eval itk_initialize $args
}
# ---------------------------------------------------------------
# PUBLIC METHODS
#----------------------------------------------------------------
#<
# This is used to set the canvas that has to be printed.
# A stamp-sized copy will automatically be drawn to show how the
# output would look with the current settings.
#
# In: canv - The canvas to be printed
# Out: canvas (attrib) - Holds the canvas to be printed
#>
body iwidgets::Canvasprintbox::setcanvas {canv} {
set canvas $canv
if {$win != ""} {
_config_optimum
_update_canvas
}
}
#<
# Returns the value of the -printercmd or -filename option
# depending on the current setting of -output.
#
# In: itk_option (attrib)
# Out: The value of -printercmd or -filename
#>
body iwidgets::Canvasprintbox::getoutput {} {
case $itk_option(-output) in {
file {
return $itk_option(-filename)
}
printer {
return $itk_option(-printcmd)
}
}
}
#<
# Perfrom the actual printing of the canvas using the current settings of
# all the attributes.
#
# In: itk_option, rotate (attrib)
# Out: A boolean indicating wether printing was successful
#>
body iwidgets::Canvasprintbox::print {} {
global env
if {$updating} {
set updating 0
}
_update_prtfile
_update_attr
if {$itk_option(-output) == "file"} {
set nm $itk_option(-filename)
if {[string range $nm 0 1] == "~/"} {
set nm [file join $env(HOME) [string range $nm 2 end]]
}
} else {
if {$tcl_platform(platform) == "macintosh"} {
error "can't print to LPR on a Mac.\nTry printing to a file, and passing that to LaserWriter 8"
}
set nm "/tmp/xge[winfo id $canvas]"
}
if {$itk_option(-posterize)} {
set vpc $itk_option(-vpagecnt)
set hpc $itk_option(-hpagecnt)
} else {
set vpc 1
set hpc 1
}
set pr [_calc_print_region]
set x1 [lindex $pr 0]
set y1 [lindex $pr 1]
set x2 [lindex $pr 2]
set y2 [lindex $pr 3]
set cx [expr int(($x2 + $x1) / 2)]
set cy [expr int(($y2 + $y1) / 2)]
if {!$itk_option(-stretch)} {
set ps [_calc_poster_size]
set pshw [expr int([lindex $ps 0] / 2)]
set pshh [expr int([lindex $ps 1] / 2)]
set x [expr $cx - $pshw]
set y [expr $cy - $pshh]
set w [ezPaperInfo $itk_option(-pagesize) pwidth $itk_option(-orient) $win]
set h [ezPaperInfo $itk_option(-pagesize) pheight $itk_option(-orient) $win]
} else {
set x $x1
set y $y1
set w [expr ($x2 - $x1) / $hpc]
set h [expr ($y2 - $y1) / $vpc]
}
set i 0
set px $x
while {$i < $hpc} {
set j 0
set py $y
while {$j < $vpc} {
if {$hpc > 1 || $vpc > 1} {
set nm2 "$nm$i.$j"
} else {
set nm2 $nm
}
if {$itk_option(-stretch)} {
$canvas postscript \
-file $nm2 \
-rotate $rotate \
-x $px -y $py \
-width $w \
-height $h \
-pagex [ezPaperInfo $itk_option(-pagesize) centerx] \
-pagey [ezPaperInfo $itk_option(-pagesize) centery] \
-pagewidth [ezPaperInfo $itk_option(-pagesize) pwidth $itk_option(-orient)] \
-pageheight [ezPaperInfo $itk_option(-pagesize) pheight $itk_option(-orient)]
} else {
$canvas postscript \
-file $nm2 \
-rotate $rotate \
-x $px -y $py \
-width $w \
-height $h \
-pagex [ezPaperInfo $itk_option(-pagesize) centerx] \
-pagey [ezPaperInfo $itk_option(-pagesize) centery]
}
if {$itk_option(-output) != "file"} {
set cmd "cat $nm2 | $itk_option(-printcmd)"
if {[catch {eval "exec $cmd"}]} {
return 0
}
catch {exec rm $nm2}
}
set py [expr $py + $h]
incr j
}
set px [expr $px + $w]
incr i
}
return 1
}
#<
# Retrieves the current value for all edit fields and updates
# the stamp accordingly. Is useful for Apply-buttons.
#>
body iwidgets::Canvasprintbox::refresh {} {
_update_attr
_update_canvas
}
#<
# Stops the drawing of the "stamp". I'm currently unable to detect
# when a Canvasprintbox gets withdrawn. It's therefore advised
# that you perform a stop before you do something like that.
#>
body iwidgets::Canvasprintbox::stop {} {
if {$updating} {
set updating 0
}
}
# ---------------------------------------------------------------
# PROTECTED METHODS
#----------------------------------------------------------------
#
# Calculate the total size the output would be with the current
# settings for "pagesize" and "posterize" (and "hpagecnt" and
# "vpagecnt"). This size will be the size of the printable area,
# some space has been substracted to take into account that a
# page should have borders because most printers can't print on
# the very edge of the paper.
#
# In: posterize, hpagecnt, vpagecnt, pagesize, orient (attrib)
# Out: A list of two numbers indicating the width and the height
# of the total paper area which will be used for printing
# in pixels.
#
body iwidgets::Canvasprintbox::_calc_poster_size {} {
if {$itk_option(-posterize)} {
set vpc $itk_option(-vpagecnt)
set hpc $itk_option(-hpagecnt)
} else {
set vpc 1
set hpc 1
}
set tpw [expr [ezPaperInfo $itk_option(-pagesize) pwidth $itk_option(-orient) $win] * $hpc]
set tph [expr [ezPaperInfo $itk_option(-pagesize) pheight $itk_option(-orient) $win] * $vpc]
return "$tpw $tph"
}
#
# Calculate the scaling factor that would be needed to fit the
# whole "source" into the "stamp". This takes into account the
# total amount of "paper" that would be needed to print the
# contents of the "source".
#
# In: -
# Out: A float specifying the scaling factor
#
body iwidgets::Canvasprintbox::_calc_stamp_scale {} {
set width [winfo width $canvw]
set height [winfo height $canvw]
set ps [_calc_poster_size]
set xsf [expr $width / [lindex $ps 0]]
set ysf [expr $height / [lindex $ps 1]]
if {$xsf < $ysf} {
set sf $xsf
} else {
set sf $ysf
}
return $sf
}
#
# Determine which area of the "source" canvas will be printed.
# If "printregion" was set by the "user" this will be used and
# converted to pixel-coordinates. If the user didn't set it
# the bounding box that contains all canvas-items will be used
# instead.
#
# In: printregion, canvas (attrib)
# Out: Four floats specifying the region to be printed in
# pixel-coordinates (topleft & bottomright).
#
body iwidgets::Canvasprintbox::_calc_print_region {} {
if {$itk_option(-printregion) != ""} {
set printreg $itk_option(-printregion)
} else {
set printreg [$canvas bbox all]
}
if {$printreg != ""} {
set prx1 [winfo fpixels $canvas [lindex $printreg 0]]
set pry1 [winfo fpixels $canvas [lindex $printreg 1]]
set prx2 [winfo fpixels $canvas [lindex $printreg 2]]
set pry2 [winfo fpixels $canvas [lindex $printreg 3]]
set res "$prx1 $pry1 $prx2 $pry2"
} else {
set res "0 0 0 0"
}
return $res
}
#
# Calculate the scaling factor needed if the output was
# to be stretched to fit exactly on the page (or pages).
# If stretching is turned off this will always return 1.0.
#
# In: stretch (attrib)
# Out: A float specifying the scaling factor.
#
body iwidgets::Canvasprintbox::_calc_print_scale {} {
if {$itk_option(-stretch)} {
set pr [_calc_print_region]
set prw [expr [lindex $pr 2] - [lindex $pr 0]]
set prh [expr [lindex $pr 3] - [lindex $pr 1]]
set ps [_calc_poster_size]
set psw [lindex $ps 0]
set psh [lindex $ps 1]
set sfx [expr $psw / $prw]
set sfy [expr $psh / $prh]
if {$sfx < $sfy} {
set sf $sfx
} else {
set sf $sfy
}
return $sf
} else {
return 1.0
}
}
#
# Change the configuration options in such a way that the
# "source" canvas will fit the page in the best possible
# way. This might mean changing the orientation of the
# output and/or stretching the output to fit the page.
# If either of these options was set by the "user" the
# option won't be changed, this might result on a less than
# perfect fit.
#
# In: canvas, orientset, orient, stretchset, stretch (attrib)
# Out: -
#
body iwidgets::Canvasprintbox::_config_optimum {} {
if {$canvas != ""} {
set pr [_calc_print_region]
set w [expr [lindex $pr 2] - [lindex $pr 0]]
set h [expr [lindex $pr 3] - [lindex $pr 1]]
if {[lsearch $init_opts -orient] == -1} {
if {$w > $h} {
set itk_option(-orient) "landscape"
} else {
set itk_option(-orient) "portrait"
}
}
if {[lsearch $init_opts -stretch] == -1} {
set ps [_calc_poster_size]
if {[lindex $ps 0] < $w || [lindex $ps 1] < $h} {
set itk_option(-stretch) 1
}
}
}
}
#
# Schedule the thread that makes a copy of the "source"
# canvas to the "stamp".
#
# In: win, canvas (attrib)
# Out: -
#
body iwidgets::Canvasprintbox::_update_canvas {} {
if {$win == "" || $canvas == "" || [$canvas find all] == ""} {
return
}
if {$updating} {
set restart_update 1
} else {
set restart_update 0
set updating 1
after idle [code $this _update_canvas_thread]
}
}
#
# Make a copy of the "source" canvas to the "stamp".
#
# In: win, canvas, posterize, hpagecnt, vpagecnt,
# vlines, hlines (attrib)
# Out: -
#
body iwidgets::Canvasprintbox::_update_canvas_thread {} {
if {$itk_option(-posterize)} {
set vpc $itk_option(-vpagecnt)
set hpc $itk_option(-hpagecnt)
} else {
set vpc 1
set hpc 1
}
if {$hpc == [llength $vlines] && $vpc == [llength $hlines]} {
set updating 0
return
}
$canvw delete all
set ps [_calc_poster_size]
set sf [_calc_stamp_scale]
set w [expr [lindex $ps 0] * $sf]
set h [expr [lindex $ps 1] * $sf]
set width [winfo width $canvw]
set height [winfo height $canvw]
set x1 [expr ($width - $w) / 2]
set y1 [expr ($height - $h) / 2]
set x2 [expr $x1 + $w]
set y2 [expr $y1 + $h]
set cx [expr ($x2 + $x1) / 2]
set cy [expr ($y2 + $y1) / 2]
set printreg [_calc_print_region]
set prx1 [lindex $printreg 0]
set pry1 [lindex $printreg 1]
set prx2 [lindex $printreg 2]
set pry2 [lindex $printreg 3]
set prcx [expr ($prx2 + $prx1) / 2]
set prcy [expr ($pry2 + $pry1) / 2]
set psf [_calc_print_scale]
#
# Copy all items from the "real" canvas to the canvas
# showing what we'll send to the printer. Bitmaps and
# texts are not copied because they can't be scaled,
# a rectangle will be created instead.
#
update
set cnt 0
set tsf [expr $sf * $psf]
set dx [expr $cx - ($prcx * $tsf)]
set dy [expr $cy - ($prcy * $tsf)]
$canvw create rectangle $x1 $y1 $x2 $y2 -fill white
set items [eval "$canvas find overlapping $printreg"]
foreach i $items {
#
# Determine the item's type and coordinates
#
set t [$canvas type $i]
set crds [$canvas coords $i]
#
# Ask for the item's configuration settings and strip
# it to leave only a list of option names and values.
#
set cfg [$canvas itemconfigure $i]
set cfg2 ""
foreach c $cfg {
if {[llength $c] == 5} {
lappend cfg2 [lindex $c 0] [lindex $c 4]
}
}
#
# Handle texts and bitmaps differently: they will
# be represented as rectangles.
#
if {$t == "text" || $t == "bitmap" || $t == "window"} {
set t "rectangle"
set crds [$canvas bbox $i]
set cfg2 "-outline {} -fill gray"
}
#
# Remove the arrows from a line item when the scale
# factor drops below 1/3rd of the original size.
# This to prevent the arrowheads from dominating the
# display.
#
if {$t == "line" && $tsf < 0.33} {
lappend cfg2 -arrow none
}
#
# Create a copy of the item on the "printing" canvas.
#
set i2 [eval "$canvw create $t $crds $cfg2"]
$canvw scale $i2 0 0 $tsf $tsf
$canvw move $i2 $dx $dy
incr cnt
if {[expr $cnt % 25] == 0} {
update
if {!$updating} {
return
}
if {$restart_update} {
set updating 0
after idle [code $this _update_canvas]
}
}
}
set p $x1
set i 1
set vlines ""
while {$i < $hpc} {
set p [expr $p + ($w / $hpc)]
set l [$canvw create line $p $y1 $p $y2]
lappend vlines $l
incr i
}
set p $y1
set i 1
set vlines ""
while {$i < $vpc} {
set p [expr $p + ($h / $vpc)]
set l [$canvw create line $x1 $p $x2 $p]
lappend vlines $l
incr i
}
set updating 0
}
#
# Update dependencies among widgets. (For example: disabling
# an entry-widget when its associated checkbox-button is used
# to turn of the option (the entry's value is not needed
# anymore and this should be reflected in the fact that it
# isn't possible to change it anymore).
#
# In: itk_option, rotate (attrib) - the widget settings
# itk_component (attrib) - the widgets
# Out: -
#
body iwidgets::Canvasprintbox::_update_widgets {} {
if {$itk_option(-posterize)} {
$itk_component(vpcnt) configure -state normal
$itk_component(hpcnt) configure -state normal
} else {
$itk_component(vpcnt) configure -state disabled
$itk_component(hpcnt) configure -state disabled
}
case $itk_option(-output) in {
printer {
$itk_component(prtflentry) configure -labeltext "Printer command :"
$itk_component(prtflentry) clear
$itk_component(prtflentry) insert 0 $itk_option(-printcmd)
}
file {
$itk_component(prtflentry) configure -labeltext "Filename :"
$itk_component(prtflentry) clear
$itk_component(prtflentry) insert 0 $itk_option(-filename)
}
}
case $itk_option(-orient) in {
landscape {
set rotate 1
}
portrait {
set rotate 0
}
}
}
#
# Updates the user-interface whenever one of the attributes
# is changes by the "user".
#
# In: itk_component (attrib) - the widgets to update
# prtcanvglob (common) - global variables for the radio-
# buttons and checkboxes.
# Out: -
#
body iwidgets::Canvasprintbox::_update_UI {} {
if {$win != ""} {
$itk_component(outputom) select \
"*[string range $itk_option(-output) 1 end]"
$itk_component(paperom) select \
"*[string range $itk_option(-pagesize) 1 end]"
$itk_component(orientom) select \
"*[string range $itk_option(-orient) 1 end]"
set prtcanvglob($this,stretchcb) $itk_option(-stretch)
set prtcanvglob($this,postercb) $itk_option(-posterize)
$itk_component(vpcnt) delete 0 end
$itk_component(vpcnt) insert 0 $itk_option(-vpagecnt)
$itk_component(hpcnt) delete 0 end
$itk_component(hpcnt) insert 0 $itk_option(-hpagecnt)
_update_widgets
}
}
#
# Update the attributes to reflect changes made in the user-
# interface.
#
# In: itk_option (attrib) - the attributes to update
# itk_component (attrib) - the widgets
# prtcanvglob (common) - the global var holding the state
# of all radiobuttons and checkboxes.
# Out: -
#
body iwidgets::Canvasprintbox::_update_attr {} {
if {$win != ""} {
set outp [$itk_component(outputom) get]
if {$outp != $itk_option(-output)} {
case $itk_option(-output) in {
printer {
set itk_option(-printcmd) [$itk_component(prtflentry) get]
}
file {
set itk_option(-filename) [$itk_component(prtflentry) get]
}
}
}
set itk_option(-output) [string tolower $outp]
set itk_option(-pagesize) \
[string tolower [$itk_component(paperom) get]]
set itk_option(-orient) \
[string tolower [$itk_component(orientom) get]]
set itk_option(-stretch) $prtcanvglob($this,stretchcb)
set itk_option(-posterize) $prtcanvglob($this,postercb)
set vpc [$itk_component(vpcnt) get]
if {$vpc >= 1} {
set itk_option(-vpagecnt) $vpc
} else {
$itk_component(vpcnt) delete 0 end
$itk_component(vpcnt) insert 0 $itk_option(-vpagecnt)
}
set hpc [$itk_component(hpcnt) get]
if {$hpc >= 1} {
set itk_option(-hpagecnt) [$itk_component(hpcnt) get]
} else {
$itk_component(hpcnt) delete 0 end
$itk_component(hpcnt) insert 0 $itk_option(-hpagecnt)
}
_update_widgets
}
}
#
# Updates the values for the attributes "printcmd" and "filename"
# every time the corresponding setting of the "To printer" and
# "To file" radiobuttons is changed.
#
# In: itk_option, itk_component (atrib)
# Out:
#
body iwidgets::Canvasprintbox::_update_prtfile {} {
case $itk_option(-output) in {
printer {
set itk_option(-printcmd) [$itk_component(prtflentry) get]
}
file {
set itk_option(-filename) [$itk_component(prtflentry) get]
}
}
}
#
# Gets called when the CanvasPrintBox-widget gets mapped.
#
body iwidgets::Canvasprintbox::_mapEventHandler {} {
set win $itk_interior
set canvw $itk_component(canvas)
if {$canvas != ""} {
setcanvas $canvas
}
_update_UI
}
#
# Destroy this object and its associated widgets.
#
body iwidgets::Canvasprintbox::destructor {} {
if {$updating} {
set updating 0
}
}
#
# Hold the information about common paper sizes. A bit of a hack, but it
# should be possible to add your own if you take a look at it.
#
body iwidgets::Canvasprintbox::ezPaperInfo {size {attr ""} \
{orient "portrait"} {window ""}} {
set size [string tolower $size]
set attr [string tolower $attr]
set orient [string tolower $orient]
case $size in {
types {
return "A5 A4 A3 A2 A1 Legal Letter"
}
a5 {
set paper(x1) "1.0c"
set paper(y1) "1.0c"
set paper(x2) "13.85c"
set paper(y2) "20.0c"
set paper(pheight) "19.0c"
set paper(pwidth) "12.85c"
set paper(height) "21.0c"
set paper(width) "14.85c"
set paper(centerx) "7.425c"
set paper(centery) "10.5c"
}
a4 {
set paper(x1) "1.0c"
set paper(y1) "1.0c"
set paper(x2) "20.0c"
set paper(y2) "28.7c"
set paper(pheight) "27.7c"
set paper(pwidth) "19.0c"
set paper(height) "29.7c"
set paper(width) "21.0c"
set paper(centerx) "10.5c"
set paper(centery) "14.85c"
}
a3 {
set paper(x1) "1.0c"
set paper(y1) "1.0c"
set paper(x2) "28.7c"
set paper(y2) "41.0c"
set paper(pheight) "40.0c"
set paper(pwidth) "27.7c"
set paper(height) "42.0c"
set paper(width) "29.7c"
set paper(centerx) "14.85c"
set paper(centery) "21.0c"
}
a2 {
set paper(x1) "1.0c"
set paper(y1) "1.0c"
set paper(x2) "41.0c"
set paper(y2) "58.4c"
set paper(pheight) "57.4c"
set paper(pwidth) "40.0c"
set paper(height) "59.4c"
set paper(width) "42.0c"
set paper(centerx) "21.0c"
set paper(centery) "29.7c"
}
a1 {
set paper(x1) "1.0c"
set paper(y1) "1.0c"
set paper(x2) "58.4c"
set paper(y2) "83.0c"
set paper(pheight) "82.0c"
set paper(pwidth) "57.4c"
set paper(height) "84.0c"
set paper(width) "59.4c"
set paper(centerx) "29.7c"
set paper(centery) "42.0c"
}
legal {
set paper(x1) "0.2i"
set paper(y1) "0.2i"
set paper(x2) "8.3i"
set paper(y2) "13.8i"
set paper(pheight) "13.6i"
set paper(pwidth) "8.1i"
set paper(height) "14.0i"
set paper(width) "8.5i"
set paper(centerx) "4.25i"
set paper(centery) "7.0i"
}
letter {
set paper(x1) "0.2i"
set paper(y1) "0.2i"
set paper(x2) "8.3i"
set paper(y2) "10.8i"
set paper(pheight) "10.6i"
set paper(pwidth) "8.1i"
set paper(height) "11.0i"
set paper(width) "8.5i"
set paper(centerx) "4.25i"
set paper(centery) "5.5i"
}
default {
error "ezPaperInfo: Unknown paper type ($type)"
}
}
set inv(x1) "y1"
set inv(x2) "y2"
set inv(y1) "x1"
set inv(y2) "x2"
set inv(pwidth) "pheight"
set inv(pheight) "pwidth"
set inv(width) "height"
set inv(height) "width"
set inv(centerx) "centery"
set inv(centery) "centerx"
case $orient in {
landscape {
set res $paper($inv($attr))
}
portrait {
set res $paper($attr)
}
default {
error "ezPaperInfo: orientation should be\
portrait or landscape (not $orient)"
}
}
if {$window != ""} {
set res [winfo fpixels $window $res]
}
return $res
}