home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 June / PCWorld_2005-06_cd.bin / software / vyzkuste / firewally / firewally.exe / framework-2.3.exe / canvasprintbox.itk < prev    next >
Text File  |  2003-09-01  |  32KB  |  1,112 lines

  1. #
  2. # CanvasPrintBox v1.5
  3. # ----------------------------------------------------------------------
  4. # Implements a print box for printing the contents of a canvas widget
  5. # to a printer or a file. It is possible to specify page orientation, the
  6. # number of pages to print the image on and if the output should be
  7. # stretched to fit the page.
  8. # CanvasPrintBox is a "super-widget" that can be used as an
  9. # element in ones own GUIs. It is used to print the contents
  10. # of a canvas (called the source hereafter) to a printer or a
  11. # file. Possible settings include: portrait and landscape orientation
  12. # of the output, stretching the output to fit the page while maintaining
  13. # a proper aspect-ratio and posterizing to enlarge the output to fit on
  14. # multiple pages. A stamp-sized copy of the source will be shown (called
  15. # the stamp hereafter) at all times to reflect the effect of changing
  16. # the settings will have on the output.
  17. #
  18. # ----------------------------------------------------------------------
  19. # AUTHOR: Tako Schotanus               EMAIL: Tako.Schotanus@bouw.tno.nl
  20. # ----------------------------------------------------------------------
  21. #                Copyright (c) 1995  Tako Schotanus
  22. # ======================================================================
  23. # Permission is hereby granted, without written agreement and without
  24. # license or royalty fees, to use, copy, modify, and distribute this
  25. # software and its documentation for any purpose, provided that the
  26. # above copyright notice and the following two paragraphs appear in
  27. # all copies of this software.
  28. # IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
  29. # DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 
  30. # ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 
  31. # IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 
  32. # DAMAGE.
  33. #
  34. # THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 
  35. # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
  36. # FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  37. # ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  38. # PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  39. # ======================================================================
  40.  
  41. #
  42. # Default resources.
  43. #
  44. option add *Canvasprintbox.filename    "canvas.ps"    widgetDefault
  45. option add *Canvasprintbox.hPageCnt    1        widgetDefault
  46. option add *Canvasprintbox.orient    landscape    widgetDefault
  47. option add *Canvasprintbox.output    printer        widgetDefault
  48. option add *Canvasprintbox.pageSize    A4        widgetDefault
  49. option add *Canvasprintbox.posterize    0        widgetDefault
  50. option add *Canvasprintbox.printCmd    lpr        widgetDefault
  51. option add *Canvasprintbox.printRegion    ""        widgetDefault
  52. option add *Canvasprintbox.vPageCnt    1        widgetDefault
  53.  
  54. #
  55. # Usual options.
  56. #
  57. itk::usual Canvasprintbox {
  58.     keep -background -cursor -textbackground -foreground
  59. }
  60.  
  61. #<
  62. #
  63. # CanvasPrintBox is a "super-widget" that can be used as an
  64. # element in ones own GUIs. It is used to print the contents
  65. # of a canvas (called the source hereafter) to a printer or a
  66. # file. Possible settings include: portrait and landscape orientation
  67. # of the output, stretching the output to fit the page while maintaining
  68. # a proper aspect-ratio and posterizing to enlarge the output to fit on
  69. # multiple pages. A stamp-sized copy of the source will be shown (called
  70. # the stamp hereafter) at all times to reflect the effect of changing
  71. # the settings will have on the output.
  72. #
  73. #>
  74. itcl::class iwidgets::Canvasprintbox {
  75.     inherit itk::Widget
  76.  
  77.     #
  78.     # Holds the current state for all check- and radiobuttons.
  79.     #
  80.     itk_option define -filename filename FileName "canvas.ps"
  81.     itk_option define -hpagecnt hPageCnt PageCnt 1
  82.     itk_option define -orient orient Orient "landscape"
  83.     itk_option define -output output Output "printer"
  84.     itk_option define -pagesize pageSize PageSize "A4"
  85.     itk_option define -posterize posterize Posterize 0
  86.     itk_option define -printcmd printCmd PrintCmd ""
  87.     itk_option define -printregion printRegion PrintRegion ""
  88.     itk_option define -stretch stretch Stretch 0
  89.     itk_option define -vpagecnt vPageCnt PageCnt 1
  90.     
  91.     constructor {args} {}
  92.     destructor {}
  93.  
  94.     # ---------------------------------------------------------------
  95.     # PUBLIC
  96.     #----------------------------------------------------------------
  97.     public {
  98.       method getoutput {}
  99.       method print {}
  100.       method refresh {}
  101.       method setcanvas {canv}
  102.       method stop {}
  103.     }
  104.  
  105.     # ---------------------------------------------------------------
  106.     # PROTECTED
  107.     #----------------------------------------------------------------
  108.     protected {
  109.       #
  110.       # Just holds the names of some widgets/objects. "win" is used to
  111.       # determine if the object is fully constructed and initialized.
  112.       #
  113.       variable win ""
  114.       variable canvw ""
  115.     
  116.       #
  117.       # The canvas we want to print. 
  118.       #
  119.       variable canvas ""
  120.     
  121.       #
  122.       # Boolean indicating if the attribute "orient" is set
  123.       # to landscape or not.
  124.       #
  125.       variable rotate 1
  126.     
  127.       #
  128.       # Holds the configure options that were used to create this object.
  129.       #
  130.       variable init_opts ""
  131.     
  132.       #
  133.       # The following attributes hold a list of lines that are
  134.       # currently drawn on the "stamp" to show how the page(s) is/are
  135.       # oriented. The first holds the vertical dividing lines and the
  136.       # second the horizontal ones.
  137.       #
  138.       variable hlines ""
  139.       variable vlines ""
  140.  
  141.       #
  142.       # Updating is set when the thumbnail is being drawn. Settings
  143.       # this to 0 while drawing is still busy will terminate the
  144.       # proces.
  145.       # Restart_update can be set to 1 when the thumbnail is being
  146.       # drawn to force a redraw.
  147.       #
  148.       variable _reposition ""
  149.       variable _update_attr_id ""
  150.  
  151.       method _calc_poster_size {}
  152.       method _calc_print_region {}
  153.       method _calc_print_scale {}
  154.       method _mapEventHandler {}
  155.       method _update_attr {{when later}}
  156.       method _update_canvas {{when later}}
  157.  
  158.       common _globVar
  159.  
  160.       proc ezPaperInfo {size {attr ""} \
  161.         {orient "portrait"} {window ""}} {}
  162.     }
  163. }
  164.  
  165. #
  166. # Provide a lowercased access method for the Canvasprintbox class.
  167. proc ::iwidgets::canvasprintbox {args} {
  168.     uplevel ::iwidgets::Canvasprintbox $args
  169. }
  170.  
  171. # ------------------------------------------------------------------
  172. #                             OPTIONS
  173. # ------------------------------------------------------------------
  174.  
  175. #<
  176. # A list of four coordinates specifying which part of the canvas to print.
  177. # An empty list means that the canvas' entire scrollregion should be
  178. # printed. Any change to this attribute will automatically update the "stamp".
  179. # Defaults to an empty list.
  180. #>
  181. itcl::configbody iwidgets::Canvasprintbox::printregion {
  182.     if {$itk_option(-printregion) != ""
  183.     && [llength $itk_option(-printregion)] != 4} {
  184.         error {bad option "printregion": should contain 4 coordinates}
  185.     }
  186.     _update_canvas
  187. }
  188.  
  189. #<
  190. # Specifies where the postscript output should go: to the printer
  191. # or to a file. Can take on the values "printer" or "file".
  192. # The corresponding entry-widget will reflect the contents of
  193. # either the printcmd attribute or the filename attribute.
  194. #>
  195. itcl::configbody iwidgets::Canvasprintbox::output {
  196.     switch $itk_option(-output) {
  197.         file - printer {
  198.         set _globVar($this,output) $itk_option(-output)
  199.         }
  200.         default {
  201.         error {bad output option \"$itk_option(-output)\":\
  202.             should be file or printer}
  203.         }
  204.     }
  205.     _update_attr
  206. }
  207.  
  208. #<
  209. # The command to execute when printing the postscript output.
  210. # The command will get the postscript directed to its standard
  211. # input. (Only when output is set to "printer")
  212. #>
  213. itcl::configbody iwidgets::Canvasprintbox::printcmd {
  214.     set _globVar($this,printeref) $itk_option(-printcmd)
  215.     _update_attr
  216. }
  217.  
  218. #<
  219. # The file to write the postscript output to (Only when output
  220. # is set to "file"). If posterizing is turned on and hpagecnt
  221. # and/or vpagecnt is more than 1, x.y is appended to the filename
  222. # where x is the horizontal page number and y the vertical page number.
  223. #>
  224. itcl::configbody iwidgets::Canvasprintbox::filename {
  225.     set _globVar($this,fileef) $itk_option(-filename)
  226.     _update_attr
  227. }
  228.  
  229. #<
  230. # The pagesize the printer supports. Changes to this attribute
  231. # will be reflected immediately in the "stamp".
  232. #>
  233. itcl::configbody iwidgets::Canvasprintbox::pagesize {
  234.     set opt [string tolower $itk_option(-pagesize)]
  235.     set lst [string tolower [ezPaperInfo types]]
  236.     if {[lsearch $lst $opt] == -1} {
  237.         error "bad option \"pagesize\": should be one of: [ezPaperInfo types]"
  238.     }
  239.     $itk_component(paperom) select "*[string range $opt 1 end]"
  240.     _update_canvas
  241. }
  242.  
  243. #<
  244. # Determines the orientation of the output to the printer (or file).
  245. # It can take the value "portrait" or "landscape" (default). Changes
  246. # to this attribute will be reflected immediately in the "stamp".
  247. #>
  248. itcl::configbody iwidgets::Canvasprintbox::orient {
  249.     switch $itk_option(-orient) {
  250.         "portrait" - "landscape" {
  251.         $itk_component(orientom) select $itk_option(-orient)
  252.         _update_canvas
  253.  
  254.         }
  255.         default {
  256.         error "bad orient option \"$itk_option(-orient)\":\
  257.             should be portrait or landscape"
  258.         }
  259.     }
  260. }
  261.  
  262. #<
  263. # Determines if the output should be stretched to fill the
  264. # page (as defined by the attribute pagesize) as large as
  265. # possible. The aspect-ratio of the output will be retained
  266. # and the output will never fall outside of the boundaries
  267. # of the page.
  268. #>
  269. itcl::configbody iwidgets::Canvasprintbox::stretch {
  270.     if {$itk_option(-stretch) != 0 && $itk_option(-stretch) != 1} {
  271.         error {bad option "stretch": should be a boolean}
  272.     }
  273.     set _globVar($this,stretchcb) $itk_option(-stretch)
  274.     _update_attr
  275. }
  276.  
  277. #<
  278. # Indicates if posterizing is turned on or not. Posterizing
  279. # the output means that it is possible to distribute the
  280. # output over more than one page. This way it is possible to
  281. # print a canvas/region which is larger than the specified
  282. # pagesize without stretching. If used in combination with
  283. # stretching it can be used to "blow up" the contents of a
  284. # canvas to as large as size as you want (See attributes:
  285. # hpagecnt end vpagecnt). Any change to this attribute will
  286. # automatically update the "stamp".
  287. #>
  288. itcl::configbody iwidgets::Canvasprintbox::posterize {
  289.     if {$itk_option(-posterize) != "0" && $itk_option(-posterize) != "1"} {
  290.         error "expected boolean but got \"$itk_option(-posterize)\""
  291.     }
  292.     set _globVar($this,postercb) $itk_option(-posterize)
  293.     _update_canvas
  294. }
  295.  
  296. #<
  297. # Is used in combination with "posterize" to determine over
  298. # how many pages the output should be distributed. This
  299. # attribute specifies how many pages should be used horizontaly.
  300. # Any change to this attribute will automatically update the "stamp".
  301. #>
  302. itcl::configbody iwidgets::Canvasprintbox::hpagecnt {
  303.     set _globVar($this,hpc) $itk_option(-hpagecnt)
  304.     _update_canvas
  305. }
  306.  
  307. #<
  308. # Is used in combination with "posterize" to determine over
  309. # how many pages the output should be distributed. This
  310. # attribute specifies how many pages should be used verticaly.
  311. # Any change to this attribute will automatically update the "stamp".
  312. #>
  313. itcl::configbody iwidgets::Canvasprintbox::vpagecnt {
  314.     set _globVar($this,vpc) $itk_option(-vpagecnt)
  315.     _update_canvas
  316. }
  317.  
  318. # ------------------------------------------------------------------
  319. # CONSTRUCTOR
  320. # ------------------------------------------------------------------
  321. itcl::body iwidgets::Canvasprintbox::constructor {args} {
  322.     set _globVar($this,output) printer
  323.     set _globVar($this,printeref) ""
  324.     set _globVar($this,fileef) "canvas.ps"
  325.     set _globVar($this,hpc) 1
  326.     set _globVar($this,vpc) 1
  327.     set _globVar($this,postercb) 0
  328.     set _globVar($this,stretchcb) 0
  329.  
  330.     itk_component add canvasframe {
  331.         frame $itk_interior.f18 -bd 2
  332.     }
  333.  
  334.     itk_component add canvas {
  335.         canvas $itk_component(canvasframe).c1 \
  336.             -bd 2 -relief sunken \
  337.             -scrollregion {0c 0c 10c 10c} \
  338.             -width 250
  339.     }
  340.     pack $itk_component(canvas) -expand 1 -fill both
  341.  
  342.     itk_component add outputom {
  343.         iwidgets::Labeledframe $itk_interior.outputom \
  344.             -labelpos nw \
  345.             -labeltext "Output to"
  346.     }
  347.     set cs [$itk_component(outputom) childsite]
  348.  
  349.     itk_component add printerrb {
  350.         radiobutton $cs.printerrb \
  351.             -text Printer \
  352.             -variable [itcl::scope _globVar($this,output)] \
  353.             -anchor w \
  354.             -justify left \
  355.             -value printer \
  356.             -command [itcl::code $this _update_attr]
  357.     } { 
  358.         usual
  359.         rename -font -labelfont labelFont Font
  360.     }
  361.     itk_component add printeref {
  362.         iwidgets::entryfield $cs.printeref \
  363.             -labeltext "command:" \
  364.             -state normal \
  365.             -labelpos w \
  366.             -textvariable [itcl::scope _globVar($this,printeref)]
  367.     }
  368.  
  369.     itk_component add filerb {
  370.         radiobutton $cs.filerb \
  371.             -text File \
  372.             -justify left \
  373.             -anchor w \
  374.             -variable [itcl::scope _globVar($this,output)] \
  375.             -value file \
  376.             -command [itcl::code $this _update_attr]
  377.     } { 
  378.         usual
  379.         rename -font -labelfont labelFont Font
  380.     }
  381.     itk_component add fileef {
  382.         iwidgets::entryfield $cs.fileef \
  383.             -labeltext "filename:" \
  384.             -state disabled \
  385.             -labelpos w \
  386.             -textvariable [itcl::scope _globVar($this,fileef)]
  387.     }
  388.  
  389.     itk_component add propsframe {
  390.         iwidgets::Labeledframe $itk_interior.propsframe \
  391.             -labelpos nw \
  392.             -labeltext "Properties"
  393.     }
  394.     set cs [$itk_component(propsframe) childsite]
  395.  
  396.     itk_component add paperom {
  397.         iwidgets::optionmenu $cs.paperom \
  398.             -labelpos w -cyclicon 1 \
  399.             -labeltext "Paper size:" \
  400.             -command [itcl::code $this refresh]
  401.     } { 
  402.         usual
  403.         rename -font -labelfont labelFont Font
  404.     }
  405.     eval $itk_component(paperom) insert end [ezPaperInfo types]
  406.     $itk_component(paperom) select A4
  407.  
  408.     itk_component add orientom {
  409.         iwidgets::radiobox $itk_interior.orientom \
  410.             -labeltext "Orientation" -command [itcl::code $this refresh]
  411.     }
  412.     $itk_component(orientom) add landscape -text Landscape
  413.     $itk_component(orientom) add portrait -text Portrait
  414.     $itk_component(orientom) select 0
  415.  
  416.     itk_component add stretchcb {
  417.         checkbutton $cs.stretchcb \
  418.             -relief flat \
  419.             -text {Stretch to fit} \
  420.             -justify left \
  421.             -anchor w \
  422.             -variable [itcl::scope _globVar($this,stretchcb)] \
  423.             -command [itcl::code $this refresh]
  424.     } { 
  425.         usual
  426.         rename -font -labelfont labelFont Font
  427.     }
  428.  
  429.     itk_component add postercb {
  430.         checkbutton $cs.postercb \
  431.             -relief flat \
  432.             -text Posterize \
  433.             -justify left \
  434.             -anchor w \
  435.             -variable [itcl::scope _globVar($this,postercb)] \
  436.             -command [itcl::code $this refresh]
  437.     } { 
  438.         usual
  439.         rename -font -labelfont labelFont Font
  440.     }
  441.  
  442.     itk_component add hpcnt {
  443.         iwidgets::entryfield $cs.hpcnt \
  444.             -labeltext on \
  445.             -textvariable [itcl::scope _globVar($this,hpc)] \
  446.             -validate integer -width 3 \
  447.             -command [itcl::code $this refresh]
  448.     }
  449.  
  450.     itk_component add vpcnt {
  451.         iwidgets::entryfield $cs.vpcnt \
  452.             -labeltext by \
  453.             -textvariable [itcl::scope _globVar($this,vpc)] \
  454.             -validate integer -width 3 \
  455.             -command [itcl::code $this refresh]
  456.     }
  457.  
  458.     itk_component add pages {
  459.         label $cs.pages -text pages.
  460.     } { 
  461.         usual
  462.         rename -font -labelfont labelFont Font
  463.     }
  464.     
  465.     set init_opts $args
  466.     
  467.     grid $itk_component(canvasframe) -row 0 -column 0 -rowspan 4 -sticky nsew
  468.     grid $itk_component(propsframe)  -row 0 -column 1 -sticky nsew
  469.     grid $itk_component(outputom)    -row 1 -column 1 -sticky nsew
  470.     grid $itk_component(orientom)    -row 2 -column 1 -sticky nsew
  471.     grid columnconfigure $itk_interior 0 -weight 1
  472.     grid rowconfigure    $itk_interior 3 -weight 1
  473.  
  474.     grid $itk_component(printerrb) -row 0 -column 0 -sticky nsw
  475.     grid $itk_component(printeref) -row 0 -column 1 -sticky nsw
  476.     grid $itk_component(filerb)    -row 1 -column 0 -sticky nsw
  477.     grid $itk_component(fileef)    -row 1 -column 1 -sticky nsw
  478.     iwidgets::Labeledwidget::alignlabels $itk_component(printeref) $itk_component(fileef)
  479.     grid columnconfigure $itk_component(outputom) 1 -weight 1
  480.  
  481.     grid $itk_component(paperom)   -row 0 -column 0 -columnspan 2 -sticky nsw
  482.     grid $itk_component(stretchcb) -row 1 -column 0 -sticky nsw
  483.     grid $itk_component(postercb)  -row 2 -column 0 -sticky nsw
  484.     grid $itk_component(hpcnt)     -row 2 -column 1 -sticky nsw
  485.     grid $itk_component(vpcnt)     -row 2 -column 2 -sticky nsw
  486.     grid $itk_component(pages)     -row 2 -column 3 -sticky nsw
  487.     grid columnconfigure $itk_component(propsframe) 3 -weight 1
  488.  
  489.     eval itk_initialize $args
  490.  
  491.     bind $itk_component(pages) <Map> +[itcl::code $this _mapEventHandler]
  492.     bind $itk_component(canvas) <Configure> +[itcl::code $this refresh]
  493. }
  494.  
  495.  
  496. # ---------------------------------------------------------------
  497. # PUBLIC METHODS
  498. #----------------------------------------------------------------
  499.  
  500. #<
  501. # This is used to set the canvas that has to be printed.
  502. # A stamp-sized copy will automatically be drawn to show how the
  503. # output would look with the current settings.
  504. #
  505. # In:    canv - The canvas to be printed
  506. # Out:    canvas (attrib) - Holds the canvas to be printed
  507. #>    
  508. itcl::body iwidgets::Canvasprintbox::setcanvas {canv} {
  509.     set canvas $canv
  510.     _update_canvas
  511. }
  512.  
  513. #<
  514. # Returns the value of the -printercmd or -filename option
  515. # depending on the current setting of -output.
  516. #
  517. # In:    itk_option (attrib)
  518. # Out:    The value of -printercmd or -filename
  519. #>
  520. itcl::body iwidgets::Canvasprintbox::getoutput {} {
  521.     switch $_globVar($this,output) {
  522.       "file" {
  523.         return $_globVar($this,fileef)
  524.       }
  525.       "printer" {
  526.           return $_globVar($this,printeref)
  527.       }
  528.     }
  529.     return ""
  530. }
  531.  
  532. #<
  533. # Perfrom the actual printing of the canvas using the current settings of
  534. # all the attributes.
  535. #
  536. # In:    itk_option, rotate (attrib)
  537. # Out:    A boolean indicating wether printing was successful
  538. #>
  539. itcl::body iwidgets::Canvasprintbox::print {} {
  540.  
  541.     global env tcl_platform
  542.  
  543.     stop
  544.  
  545.     if {$itk_option(-output) == "file"} {
  546.         set nm $_globVar($this,fileef)
  547.         if {[string range $nm 0 1] == "~/"} {
  548.             set nm "$env(HOME)/[string range $nm 2 end]"
  549.         }
  550.     } else {
  551.         set nm "/tmp/xge[winfo id $canvas]"
  552.     }
  553.  
  554.     set pr [_calc_print_region]
  555.     set x1 [lindex $pr 0]
  556.     set y1 [lindex $pr 1]
  557.     set x2 [lindex $pr 2]
  558.     set y2 [lindex $pr 3]
  559.     set cx [expr {int(($x2 + $x1) / 2)}]
  560.     set cy [expr {int(($y2 + $y1) / 2)}]
  561.     if {!$itk_option(-stretch)} {
  562.         set ps [_calc_poster_size]
  563.         set pshw [expr {int([lindex $ps 0] / 2)}]
  564.         set pshh [expr {int([lindex $ps 1] / 2)}]
  565.         set x [expr {$cx - $pshw}]
  566.         set y [expr {$cy - $pshh}]
  567.         set w [ezPaperInfo $itk_option(-pagesize) pwidth $itk_option(-orient) $win]
  568.         set h [ezPaperInfo $itk_option(-pagesize) pheight $itk_option(-orient) $win]
  569.     } else {
  570.         set x $x1
  571.         set y $y1
  572.         set w [expr {($x2-$x1) / $_globVar($this,hpc)}]
  573.         set h [expr {($y2-$y1) / $_globVar($this,vpc)}]
  574.     }
  575.  
  576.     set i 0
  577.     set px $x
  578.     while {$i < $_globVar($this,hpc)} {
  579.         set j 0
  580.         set py $y
  581.         while {$j < $_globVar($this,vpc)} {
  582.             set nm2 [expr {$_globVar($this,hpc) > 1 || $_globVar($this,vpc) > 1 ? "$nm$i.$j" : $nm}]
  583.  
  584.             if {$itk_option(-stretch)} {
  585.                 $canvas postscript \
  586.                   -file $nm2 \
  587.                   -rotate $rotate \
  588.                   -x $px -y $py \
  589.                   -width $w \
  590.                   -height $h \
  591.                   -pagex [ezPaperInfo $itk_option(-pagesize) centerx] \
  592.                   -pagey [ezPaperInfo $itk_option(-pagesize) centery] \
  593.                   -pagewidth [ezPaperInfo $itk_option(-pagesize) pwidth $itk_option(-orient)] \
  594.                   -pageheight [ezPaperInfo $itk_option(-pagesize) pheight $itk_option(-orient)]
  595.             } else {
  596.                 $canvas postscript \
  597.                   -file $nm2 \
  598.                   -rotate $rotate \
  599.                   -x $px -y $py \
  600.                   -width $w \
  601.                   -height $h \
  602.                   -pagex [ezPaperInfo $itk_option(-pagesize) centerx] \
  603.                   -pagey [ezPaperInfo $itk_option(-pagesize) centery]
  604.             }
  605.  
  606.             if {$itk_option(-output) == "printer"} {
  607.                 set cmd "$itk_option(-printcmd) < $nm2"
  608.                 if {[catch {eval exec $cmd &}]} {
  609.                     return 0
  610.                 }
  611.             }
  612.  
  613.             set py [expr {$py + $h}]
  614.             incr j
  615.         }
  616.         set px [expr {$px + $w}]
  617.         incr i
  618.     }
  619.  
  620.     return 1
  621. }
  622.  
  623. #<
  624. # Retrieves the current value for all edit fields and updates
  625. # the stamp accordingly. Is useful for Apply-buttons.
  626. #>
  627. itcl::body iwidgets::Canvasprintbox::refresh {} {
  628.     stop
  629.     _update_canvas
  630.         return
  631. }
  632.  
  633. #<
  634. # Stops the drawing of the "stamp". I'm currently unable to detect
  635. # when a Canvasprintbox gets withdrawn. It's therefore advised
  636. # that you perform a stop before you do something like that.
  637. #>
  638. itcl::body iwidgets::Canvasprintbox::stop {} {
  639.  
  640.     if {$_reposition != ""} {
  641.         after cancel $_reposition
  642.         set _reposition ""
  643.     }
  644.  
  645.     if {$_update_attr_id != ""} {
  646.         after cancel $_update_attr_id
  647.         set _update_attr_id ""
  648.     }
  649.  
  650.         return
  651. }
  652.  
  653. # ---------------------------------------------------------------
  654. # PROTECTED METHODS
  655. #----------------------------------------------------------------
  656.  
  657. #
  658. # Calculate the total size the output would be with the current
  659. # settings for "pagesize" and "posterize" (and "hpagecnt" and
  660. # "vpagecnt"). This size will be the size of the printable area,
  661. # some space has been substracted to take into account that a
  662. # page should have borders because most printers can't print on
  663. # the very edge of the paper.
  664. #
  665. # In:    posterize, hpagecnt, vpagecnt, pagesize, orient (attrib)
  666. # Out:    A list of two numbers indicating the width and the height
  667. #    of the total paper area which will be used for printing
  668. #    in pixels.
  669. #
  670. itcl::body iwidgets::Canvasprintbox::_calc_poster_size {} {
  671.     set tpw [expr {[ezPaperInfo $itk_option(-pagesize) \
  672.         pwidth $itk_option(-orient) $win]*$_globVar($this,hpc)}]
  673.     set tph [expr {[ezPaperInfo $itk_option(-pagesize) \
  674.         pheight $itk_option(-orient) $win]*$_globVar($this,vpc)}]
  675.  
  676.     return "$tpw $tph"
  677. }
  678.  
  679. #
  680. # Determine which area of the "source" canvas will be printed.
  681. # If "printregion" was set by the "user" this will be used and
  682. # converted to pixel-coordinates. If the user didn't set it
  683. # the bounding box that contains all canvas-items will be used
  684. # instead.
  685. #
  686. # In:    printregion, canvas (attrib)
  687. # Out:    Four floats specifying the region to be printed in
  688. #    pixel-coordinates (topleft & bottomright).
  689. #
  690. itcl::body iwidgets::Canvasprintbox::_calc_print_region {} {
  691.     set printreg [expr {$itk_option(-printregion) != "" 
  692.         ? $itk_option(-printregion) : [$canvas bbox all]}]
  693.  
  694.     if {$printreg != ""} {
  695.         set prx1 [winfo fpixels $canvas [lindex $printreg 0]]
  696.         set pry1 [winfo fpixels $canvas [lindex $printreg 1]]
  697.         set prx2 [winfo fpixels $canvas [lindex $printreg 2]]
  698.         set pry2 [winfo fpixels $canvas [lindex $printreg 3]]
  699.  
  700.         set res "$prx1 $pry1 $prx2 $pry2"
  701.     } else {
  702.         set res "0 0 0 0"
  703.     }
  704.     
  705.     return $res
  706. }
  707.  
  708. #
  709. # Calculate the scaling factor needed if the output was
  710. # to be stretched to fit exactly on the page (or pages).
  711. # If stretching is turned off this will always return 1.0.
  712. #
  713. # In:    stretch (attrib)
  714. # Out:    A float specifying the scaling factor.
  715. #
  716. itcl::body iwidgets::Canvasprintbox::_calc_print_scale {} {
  717.     if {$itk_option(-stretch)} {
  718.         set pr [_calc_print_region]
  719.         set prw [expr {[lindex $pr 2] - [lindex $pr 0]}]
  720.         set prh [expr {[lindex $pr 3] - [lindex $pr 1]}]
  721.         set ps [_calc_poster_size]
  722.         set psw [lindex $ps 0]
  723.         set psh [lindex $ps 1]
  724.         set sfx [expr {$psw / $prw}]
  725.         set sfy [expr {$psh / $prh}]
  726.         set sf [expr {$sfx < $sfy ? $sfx : $sfy}]
  727.         return $sf
  728.     } else {
  729.         return 1.0
  730.     }
  731. }
  732.  
  733. #
  734. # Schedule the thread that makes a copy of the "source"
  735. # canvas to the "stamp".
  736. #
  737. # In:    win, canvas (attrib)
  738. # Out:    -
  739. #
  740. itcl::body iwidgets::Canvasprintbox::_update_canvas {{when later}} {
  741.     if {$win == "" || $canvas == "" || [$canvas find all] == ""} {
  742.         return
  743.     }
  744.     if {$when == "later"} {
  745.         if {$_reposition == ""} {
  746.             set _reposition [after idle [itcl::code $this _update_canvas now]]
  747.         }
  748.         return
  749.     }
  750.  
  751.     _update_attr now
  752.  
  753.     #
  754.     # Make a copy of the "source" canvas to the "stamp".
  755.     #
  756.     if {$_globVar($this,hpc) == [llength $vlines] &&
  757.         $_globVar($this,vpc) == [llength $hlines]} {
  758.         stop
  759.         return
  760.     }    
  761.  
  762.     $canvw delete all
  763.  
  764.     set width  [winfo width $canvw]
  765.     set height [winfo height $canvw]
  766.     set ps [_calc_poster_size]
  767.  
  768.     #
  769.     # Calculate the scaling factor that would be needed to fit the
  770.     # whole "source" into the "stamp". This takes into account the
  771.     # total amount of "paper" that would be needed to print the
  772.     # contents of the "source".
  773.     #
  774.     set xsf [expr {$width/[lindex $ps 0]}]
  775.     set ysf [expr {$height/[lindex $ps 1]}]
  776.     set sf [expr {$xsf < $ysf ? $xsf : $ysf}]
  777.     set w [expr {[lindex $ps 0]*$sf}]
  778.     set h [expr {[lindex $ps 1]*$sf}]
  779.     set x1 [expr {($width-$w)/2}]
  780.     set y1 [expr {($height-$h)/2}]
  781.     set x2 [expr {$x1+$w}]
  782.     set y2 [expr {$y1+$h}]
  783.     set cx [expr {($x2+$x1)/ 2}]
  784.     set cy [expr {($y2+$y1)/ 2}]
  785.  
  786.     set printreg [_calc_print_region]
  787.     set prx1 [lindex $printreg 0]
  788.     set pry1 [lindex $printreg 1]
  789.     set prx2 [lindex $printreg 2]
  790.     set pry2 [lindex $printreg 3]
  791.     set prcx [expr {($prx2+$prx1)/2}]
  792.     set prcy [expr {($pry2+$pry1)/2}]
  793.  
  794.     set psf [_calc_print_scale]
  795.  
  796.     #
  797.     # Copy all items from the "real" canvas to the canvas
  798.     # showing what we'll send to the printer. Bitmaps and
  799.     # texts are not copied because they can't be scaled,
  800.     # a rectangle will be created instead.
  801.     #
  802.     set tsf [expr {$sf * $psf}]
  803.     set dx [expr {$cx-($prcx*$tsf)}]
  804.     set dy [expr {$cy-($prcy*$tsf)}]
  805.     $canvw create rectangle \
  806.         [expr {$x1+0}] \
  807.         [expr {$y1+0}] \
  808.         [expr {$x2-0}] \
  809.         [expr {$y2-0}] -fill white
  810.     set items [eval "$canvas find overlapping $printreg"]
  811.  
  812.     set itemCount [llength $items]
  813.     for {set cnt 0} {$cnt < $itemCount} {incr cnt} {
  814.         #
  815.         # Determine the item's type and coordinates
  816.         #
  817.         set i [lindex $items $cnt]
  818.         set t [$canvas type $i]
  819.         set crds [$canvas coords $i]
  820.  
  821.         #
  822.         # Ask for the item's configuration settings and strip
  823.         # it to leave only a list of option names and values.
  824.         #
  825.         set cfg [$canvas itemconfigure $i]
  826.         set cfg2 ""
  827.         foreach c $cfg {
  828.             if {[llength $c] == 5} {
  829.                 lappend cfg2 [lindex $c 0] [lindex $c 4]
  830.             }
  831.         }
  832.  
  833.         #
  834.         # Handle texts and bitmaps differently: they will
  835.         # be represented as rectangles.
  836.         #
  837.         if {$t == "text" || $t == "bitmap" || $t == "window"} {
  838.             set t "rectangle"
  839.             set crds [$canvas bbox $i]
  840.             set cfg2 "-outline {} -fill gray"
  841.         }
  842.  
  843.         #
  844.         # Remove the arrows from a line item when the scale
  845.         # factor drops below 1/3rd of the original size.
  846.         # This to prevent the arrowheads from dominating the
  847.         # display.
  848.         #
  849.         if {$t == "line" && $tsf < 0.33} {
  850.             lappend cfg2 -arrow none
  851.         }
  852.         
  853.         #
  854.         # Create a copy of the item on the "printing" canvas.
  855.         #
  856.         set i2 [eval "$canvw create $t $crds $cfg2"]
  857.         $canvw scale $i2 0 0 $tsf $tsf
  858.         $canvw move $i2 $dx $dy
  859.  
  860.         if {($cnt%25) == 0} {
  861.             update
  862.         }
  863.         if {$_reposition == ""} {
  864.             return
  865.         }
  866.     }
  867.  
  868.     set p $x1
  869.     set i 1
  870.     set vlines {}
  871.     while {$i < $_globVar($this,hpc)} {
  872.         set p [expr {$p + ($w/$_globVar($this,hpc))}]
  873.         set l [$canvw create line $p $y1 $p $y2]
  874.         lappend vlines $l
  875.         incr i
  876.     }
  877.  
  878.     set p $y1
  879.     set i 1
  880.     set vlines {}
  881.     while {$i < $_globVar($this,vpc)} {
  882.         set p [expr {$p + ($h/$_globVar($this,vpc))}]
  883.         set l [$canvw create line $x1 $p $x2 $p]
  884.         lappend vlines $l
  885.         incr i
  886.     }
  887.  
  888.     set _reposition ""
  889. }
  890.  
  891. #
  892. # Update the attributes to reflect changes made in the user-
  893. # interface.
  894. #
  895. # In:    itk_option (attrib) - the attributes to update
  896. #    itk_component (attrib) - the widgets
  897. #    _globVar (common) - the global var holding the state
  898. #        of all radiobuttons and checkboxes.
  899. # Out:    -
  900. #
  901. itcl::body iwidgets::Canvasprintbox::_update_attr {{when "later"}} {
  902.     if {$when != "now"} {
  903.         if {$_update_attr_id == ""} {
  904.             set _update_attr_id [after idle [itcl::code $this _update_attr now]]
  905.         }
  906.         return
  907.     }
  908.  
  909.         set itk_option(-printcmd)  $_globVar($this,printeref)
  910.         set itk_option(-filename)  $_globVar($this,fileef)
  911.         set itk_option(-output)    $_globVar($this,output)
  912.     set itk_option(-pagesize)  [string tolower [$itk_component(paperom) get]]
  913.     set itk_option(-stretch)   $_globVar($this,stretchcb)
  914.     set itk_option(-posterize) $_globVar($this,postercb)
  915.     set itk_option(-vpagecnt)  $_globVar($this,vpc)
  916.     set itk_option(-hpagecnt)  $_globVar($this,hpc)
  917.     set itk_option(-orient)    [$itk_component(orientom) get]
  918.     set rotate                 [expr {$itk_option(-orient) == "landscape"}]
  919.  
  920.     if {$_globVar($this,output) == "file"} {
  921.         $itk_component(fileef) configure \
  922.             -state normal -foreground $itk_option(-foreground)
  923.         $itk_component(printeref) configure \
  924.             -state disabled -foreground $itk_option(-disabledforeground)
  925.     } else {
  926.         $itk_component(fileef) configure \
  927.             -state disabled -foreground $itk_option(-disabledforeground)
  928.         $itk_component(printeref) configure \
  929.             -state normal -foreground $itk_option(-foreground)
  930.     }
  931.  
  932.     set fg [expr {$_globVar($this,postercb) \
  933.         ? $itk_option(-foreground) : $itk_option(-disabledforeground)}]
  934.  
  935.     $itk_component(vpcnt) configure -foreground $fg
  936.     $itk_component(hpcnt) configure -foreground $fg
  937.     $itk_component(pages) configure -foreground $fg
  938.  
  939.     #
  940.     # Update dependencies among widgets. (For example: disabling
  941.     # an entry-widget when its associated checkbox-button is used
  942.     # to turn of the option (the entry's value is not needed
  943.     # anymore and this should be reflected in the fact that it
  944.     # isn't possible to change it anymore).
  945.     #
  946.     # former method:_update_widgets/_update_UI
  947.     #
  948.     set state [expr {$itk_option(-posterize) ? "normal" : "disabled"}]
  949.     $itk_component(vpcnt) configure -state $state
  950.     $itk_component(hpcnt) configure -state $state
  951.     $itk_component(paperom) select "*[string range $itk_option(-pagesize) 1 end]"
  952.  
  953.     set _update_attr_id ""
  954. }
  955.  
  956. #
  957. # Gets called when the CanvasPrintBox-widget gets mapped.
  958. #
  959. itcl::body iwidgets::Canvasprintbox::_mapEventHandler {} {
  960.     set win $itk_interior
  961.     set canvw $itk_component(canvas)
  962.     if {$canvas != ""} {
  963.         setcanvas $canvas
  964.     }
  965.     _update_attr
  966. }
  967.  
  968. #
  969. # Destroy this object and its associated widgets.
  970. #
  971. itcl::body iwidgets::Canvasprintbox::destructor {} {
  972.     stop
  973. }
  974.  
  975. #
  976. # Hold the information about common paper sizes. A bit of a hack, but it
  977. # should be possible to add your own if you take a look at it.
  978. #
  979. itcl::body iwidgets::Canvasprintbox::ezPaperInfo {size {attr ""} \
  980.     {orient "portrait"} {window ""}} {
  981.     
  982.     set size [string tolower $size]
  983.     set attr [string tolower $attr]
  984.     set orient [string tolower $orient]
  985.     
  986.     case $size in {
  987.         types {
  988.             return "A5 A4 A3 A2 A1 Legal Letter"
  989.         }
  990.         a5 {
  991.             set paper(x1) "1.0c"
  992.             set paper(y1) "1.0c"
  993.             set paper(x2) "13.85c"
  994.             set paper(y2) "20.0c"
  995.             set paper(pheight) "19.0c"
  996.             set paper(pwidth) "12.85c"
  997.             set paper(height) "21.0c"
  998.             set paper(width) "14.85c"
  999.             set paper(centerx) "7.425c"
  1000.             set paper(centery) "10.5c"
  1001.         }
  1002.         a4 {
  1003.             set paper(x1) "1.0c"
  1004.             set paper(y1) "1.0c"
  1005.             set paper(x2) "20.0c"
  1006.             set paper(y2) "28.7c"
  1007.             set paper(pheight) "27.7c"
  1008.             set paper(pwidth) "19.0c"
  1009.             set paper(height) "29.7c"
  1010.             set paper(width) "21.0c"
  1011.             set paper(centerx) "10.5c"
  1012.             set paper(centery) "14.85c"
  1013.         }
  1014.         a3 {
  1015.             set paper(x1) "1.0c"
  1016.             set paper(y1) "1.0c"
  1017.             set paper(x2) "28.7c"
  1018.             set paper(y2) "41.0c"
  1019.             set paper(pheight) "40.0c"
  1020.             set paper(pwidth) "27.7c"
  1021.             set paper(height) "42.0c"
  1022.             set paper(width) "29.7c"
  1023.             set paper(centerx) "14.85c"
  1024.             set paper(centery)  "21.0c"
  1025.         }
  1026.         a2 {
  1027.             set paper(x1) "1.0c"
  1028.             set paper(y1) "1.0c"
  1029.             set paper(x2) "41.0c"
  1030.             set paper(y2) "58.4c"
  1031.             set paper(pheight) "57.4c"
  1032.             set paper(pwidth) "40.0c"
  1033.             set paper(height) "59.4c"
  1034.             set paper(width) "42.0c"
  1035.             set paper(centerx) "21.0c"
  1036.             set paper(centery)  "29.7c"
  1037.         }
  1038.         a1 {
  1039.             set paper(x1) "1.0c"
  1040.             set paper(y1) "1.0c"
  1041.             set paper(x2) "58.4c"
  1042.             set paper(y2) "83.0c"
  1043.             set paper(pheight) "82.0c"
  1044.             set paper(pwidth) "57.4c"
  1045.             set paper(height) "84.0c"
  1046.             set paper(width) "59.4c"
  1047.             set paper(centerx) "29.7c"
  1048.             set paper(centery)  "42.0c"
  1049.         }
  1050.         legal {
  1051.             set paper(x1) "0.2i"
  1052.             set paper(y1) "0.2i"
  1053.             set paper(x2) "8.3i"
  1054.             set paper(y2) "13.8i"
  1055.             set paper(pheight) "13.6i"
  1056.             set paper(pwidth) "8.1i"
  1057.             set paper(height) "14.0i"
  1058.             set paper(width) "8.5i"
  1059.             set paper(centerx) "4.25i"
  1060.             set paper(centery) "7.0i"
  1061.         }
  1062.         letter {
  1063.             set paper(x1) "0.2i"
  1064.             set paper(y1) "0.2i"
  1065.             set paper(x2) "8.3i"
  1066.             set paper(y2) "10.8i"
  1067.             set paper(pheight) "10.6i"
  1068.             set paper(pwidth) "8.1i"
  1069.             set paper(height) "11.0i"
  1070.             set paper(width) "8.5i"
  1071.             set paper(centerx) "4.25i"
  1072.             set paper(centery) "5.5i"
  1073.         }
  1074.         default {
  1075.             error "ezPaperInfo: Unknown paper type ($type)"
  1076.         }
  1077.     }
  1078.     
  1079.     set inv(x1) "y1"
  1080.     set inv(x2) "y2"
  1081.     set inv(y1) "x1"
  1082.     set inv(y2) "x2"
  1083.     set inv(pwidth) "pheight"
  1084.     set inv(pheight) "pwidth"
  1085.     set inv(width) "height"
  1086.     set inv(height) "width"
  1087.     set inv(centerx) "centery"
  1088.     set inv(centery) "centerx"
  1089.     
  1090.     case $orient in {
  1091.         landscape {
  1092.             set res $paper($inv($attr))
  1093.         }
  1094.         portrait {
  1095.             set res $paper($attr)
  1096.         }
  1097.         default {
  1098.             error "ezPaperInfo: orientation should be\
  1099.                 portrait or landscape (not $orient)"
  1100.         }
  1101.     }
  1102.     
  1103.     if {$window != ""} {
  1104.         set res [winfo fpixels $window $res]
  1105.     }
  1106.     
  1107.     return $res
  1108.