home *** CD-ROM | disk | FTP | other *** search
/ PC World 2000 December / PCWorld_2000-12_cd.bin / Komunikace / Comanche / comanche.exe / lib / iwidgets3.0.0 / scripts / canvasprintbox.itk < prev    next >
Text File  |  1999-02-24  |  32KB  |  1,111 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. 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. 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. 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. 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. 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. 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.     _update_canvas
  240. }
  241.  
  242. #<
  243. # Determines the orientation of the output to the printer (or file).
  244. # It can take the value "portrait" or "landscape" (default). Changes
  245. # to this attribute will be reflected immediately in the "stamp".
  246. #>
  247. configbody iwidgets::Canvasprintbox::orient {
  248.     switch $itk_option(-orient) {
  249.         "portrait" - "landscape" {
  250.         $itk_component(orientom) select $itk_option(-orient)
  251.         _update_canvas
  252.  
  253.         }
  254.         default {
  255.         error "bad orient option \"$itk_option(-orient)\":\
  256.             should be portrait or landscape"
  257.         }
  258.     }
  259. }
  260.  
  261. #<
  262. # Determines if the output should be stretched to fill the
  263. # page (as defined by the attribute pagesize) as large as
  264. # possible. The aspect-ratio of the output will be retained
  265. # and the output will never fall outside of the boundaries
  266. # of the page.
  267. #>
  268. configbody iwidgets::Canvasprintbox::stretch {
  269.     if {$itk_option(-stretch) != 0 && $itk_option(-stretch) != 1} {
  270.         error {bad option "stretch": should be a boolean}
  271.     }
  272.     set _globVar($this,stretchcb) $itk_option(-stretch)
  273.     _update_attr
  274. }
  275.  
  276. #<
  277. # Indicates if posterizing is turned on or not. Posterizing
  278. # the output means that it is possible to distribute the
  279. # output over more than one page. This way it is possible to
  280. # print a canvas/region which is larger than the specified
  281. # pagesize without stretching. If used in combination with
  282. # stretching it can be used to "blow up" the contents of a
  283. # canvas to as large as size as you want (See attributes:
  284. # hpagecnt end vpagecnt). Any change to this attribute will
  285. # automatically update the "stamp".
  286. #>
  287. configbody iwidgets::Canvasprintbox::posterize {
  288.     if {$itk_option(-posterize) != "0" && $itk_option(-posterize) != "1"} {
  289.         error "expected boolean but got \"$itk_option(-posterize)\""
  290.     }
  291.     set _globVar($this,postercb) $itk_option(-posterize)
  292.     _update_canvas
  293. }
  294.  
  295. #<
  296. # Is used in combination with "posterize" to determine over
  297. # how many pages the output should be distributed. This
  298. # attribute specifies how many pages should be used horizontaly.
  299. # Any change to this attribute will automatically update the "stamp".
  300. #>
  301. configbody iwidgets::Canvasprintbox::hpagecnt {
  302.     set _globVar($this,hpc) $itk_option(-hpagecnt)
  303.     _update_canvas
  304. }
  305.  
  306. #<
  307. # Is used in combination with "posterize" to determine over
  308. # how many pages the output should be distributed. This
  309. # attribute specifies how many pages should be used verticaly.
  310. # Any change to this attribute will automatically update the "stamp".
  311. #>
  312. configbody iwidgets::Canvasprintbox::vpagecnt {
  313.     set _globVar($this,vpc) $itk_option(-vpagecnt)
  314.     _update_canvas
  315. }
  316.  
  317. # ------------------------------------------------------------------
  318. # CONSTRUCTOR
  319. # ------------------------------------------------------------------
  320. body iwidgets::Canvasprintbox::constructor {args} {
  321.     set _globVar($this,output) printer
  322.     set _globVar($this,printeref) ""
  323.     set _globVar($this,fileef) "canvas.ps"
  324.     set _globVar($this,hpc) 1
  325.     set _globVar($this,vpc) 1
  326.     set _globVar($this,postercb) 0
  327.     set _globVar($this,stretchcb) 0
  328.  
  329.     itk_component add canvasframe {
  330.         frame $itk_interior.f18 -bd 2
  331.     }
  332.  
  333.     itk_component add canvas {
  334.         canvas $itk_component(canvasframe).c1 \
  335.             -bd 2 -relief sunken \
  336.             -scrollregion {0c 0c 10c 10c} \
  337.             -width 250
  338.     }
  339.     pack $itk_component(canvas) -expand 1 -fill both
  340.  
  341.     itk_component add outputom {
  342.         iwidgets::Labeledframe $itk_interior.outputom \
  343.             -labelpos nw \
  344.             -labeltext "Output to"
  345.     }
  346.     set cs [$itk_component(outputom) childsite]
  347.  
  348.     itk_component add printerrb {
  349.         radiobutton $cs.printerrb \
  350.             -text Printer \
  351.             -variable [scope _globVar($this,output)] \
  352.             -anchor w \
  353.             -justify left \
  354.             -value printer \
  355.             -command [code $this _update_attr]
  356.     } { 
  357.         usual
  358.         rename -font -labelfont labelFont Font
  359.     }
  360.     itk_component add printeref {
  361.         iwidgets::entryfield $cs.printeref \
  362.             -labeltext "command:" \
  363.             -state normal \
  364.             -labelpos w \
  365.             -textvariable [scope _globVar($this,printeref)]
  366.     }
  367.  
  368.     itk_component add filerb {
  369.         radiobutton $cs.filerb \
  370.             -text File \
  371.             -justify left \
  372.             -anchor w \
  373.             -variable [scope _globVar($this,output)] \
  374.             -value file \
  375.             -command [code $this _update_attr]
  376.     } { 
  377.         usual
  378.         rename -font -labelfont labelFont Font
  379.     }
  380.     itk_component add fileef {
  381.         iwidgets::entryfield $cs.fileef \
  382.             -labeltext "filename:" \
  383.             -state disabled \
  384.             -labelpos w \
  385.             -textvariable [scope _globVar($this,fileef)]
  386.     }
  387.  
  388.     itk_component add propsframe {
  389.         iwidgets::Labeledframe $itk_interior.propsframe \
  390.             -labelpos nw \
  391.             -labeltext "Properties"
  392.     }
  393.     set cs [$itk_component(propsframe) childsite]
  394.  
  395.     itk_component add paperom {
  396.         iwidgets::optionmenu $cs.paperom \
  397.             -labelpos w -cyclicon 1 \
  398.             -labeltext "Paper size:" \
  399.             -command [code $this refresh]
  400.     } { 
  401.         usual
  402.         rename -font -labelfont labelFont Font
  403.     }
  404.     eval $itk_component(paperom) insert end [ezPaperInfo types]
  405.     $itk_component(paperom) select A4
  406.  
  407.     itk_component add orientom {
  408.         iwidgets::radiobox $itk_interior.orientom \
  409.             -labeltext "Orientation" -command [code $this refresh]
  410.     }
  411.     $itk_component(orientom) add landscape -text Landscape
  412.     $itk_component(orientom) add portrait -text Portrait
  413.     $itk_component(orientom) select 0
  414.  
  415.     itk_component add stretchcb {
  416.         checkbutton $cs.stretchcb \
  417.             -relief flat \
  418.             -text {Stretch to fit} \
  419.             -justify left \
  420.             -anchor w \
  421.             -variable [scope _globVar($this,stretchcb)] \
  422.             -command [code $this refresh]
  423.     } { 
  424.         usual
  425.         rename -font -labelfont labelFont Font
  426.     }
  427.  
  428.     itk_component add postercb {
  429.         checkbutton $cs.postercb \
  430.             -relief flat \
  431.             -text Posterize \
  432.             -justify left \
  433.             -anchor w \
  434.             -variable [scope _globVar($this,postercb)] \
  435.             -command [code $this refresh]
  436.     } { 
  437.         usual
  438.         rename -font -labelfont labelFont Font
  439.     }
  440.  
  441.     itk_component add hpcnt {
  442.         iwidgets::entryfield $cs.hpcnt \
  443.             -labeltext on \
  444.             -textvariable [scope _globVar($this,hpc)] \
  445.             -validate integer -width 3 \
  446.             -command [code $this refresh]
  447.     }
  448.  
  449.     itk_component add vpcnt {
  450.         iwidgets::entryfield $cs.vpcnt \
  451.             -labeltext by \
  452.             -textvariable [scope _globVar($this,vpc)] \
  453.             -validate integer -width 3 \
  454.             -command [code $this refresh]
  455.     }
  456.  
  457.     itk_component add pages {
  458.         label $cs.pages -text pages.
  459.     } { 
  460.         usual
  461.         rename -font -labelfont labelFont Font
  462.     }
  463.     
  464.     set init_opts $args
  465.     
  466.     grid $itk_component(canvasframe) -row 0 -column 0 -rowspan 4 -sticky nsew
  467.     grid $itk_component(propsframe)  -row 0 -column 1 -sticky nsew
  468.     grid $itk_component(outputom)    -row 1 -column 1 -sticky nsew
  469.     grid $itk_component(orientom)    -row 2 -column 1 -sticky nsew
  470.     grid columnconfigure $itk_interior 0 -weight 1
  471.     grid rowconfigure    $itk_interior 3 -weight 1
  472.  
  473.     grid $itk_component(printerrb) -row 0 -column 0 -sticky nsw
  474.     grid $itk_component(printeref) -row 0 -column 1 -sticky nsw
  475.     grid $itk_component(filerb)    -row 1 -column 0 -sticky nsw
  476.     grid $itk_component(fileef)    -row 1 -column 1 -sticky nsw
  477.     iwidgets::Labeledwidget::alignlabels $itk_component(printeref) $itk_component(fileef)
  478.     grid columnconfigure $itk_component(outputom) 1 -weight 1
  479.  
  480.     grid $itk_component(paperom)   -row 0 -column 0 -columnspan 2 -sticky nsw
  481.     grid $itk_component(stretchcb) -row 1 -column 0 -sticky nsw
  482.     grid $itk_component(postercb)  -row 2 -column 0 -sticky nsw
  483.     grid $itk_component(hpcnt)     -row 2 -column 1 -sticky nsw
  484.     grid $itk_component(vpcnt)     -row 2 -column 2 -sticky nsw
  485.     grid $itk_component(pages)     -row 2 -column 3 -sticky nsw
  486.     grid columnconfigure $itk_component(propsframe) 3 -weight 1
  487.  
  488.     eval itk_initialize $args
  489.  
  490.     bind $itk_component(pages) <Map> +[code $this _mapEventHandler]
  491.     bind $itk_component(canvas) <Configure> +[code $this refresh]
  492. }
  493.  
  494.  
  495. # ---------------------------------------------------------------
  496. # PUBLIC METHODS
  497. #----------------------------------------------------------------
  498.  
  499. #<
  500. # This is used to set the canvas that has to be printed.
  501. # A stamp-sized copy will automatically be drawn to show how the
  502. # output would look with the current settings.
  503. #
  504. # In:    canv - The canvas to be printed
  505. # Out:    canvas (attrib) - Holds the canvas to be printed
  506. #>    
  507. body iwidgets::Canvasprintbox::setcanvas {canv} {
  508.     set canvas $canv
  509.     _update_canvas
  510. }
  511.  
  512. #<
  513. # Returns the value of the -printercmd or -filename option
  514. # depending on the current setting of -output.
  515. #
  516. # In:    itk_option (attrib)
  517. # Out:    The value of -printercmd or -filename
  518. #>
  519. body iwidgets::Canvasprintbox::getoutput {} {
  520.     switch $_globVar($this,output) {
  521.       "file" {
  522.         return $_globVar($this,fileef)
  523.       }
  524.       "printer" {
  525.           return $_globVar($this,printeref)
  526.       }
  527.     }
  528.     return ""
  529. }
  530.  
  531. #<
  532. # Perfrom the actual printing of the canvas using the current settings of
  533. # all the attributes.
  534. #
  535. # In:    itk_option, rotate (attrib)
  536. # Out:    A boolean indicating wether printing was successful
  537. #>
  538. body iwidgets::Canvasprintbox::print {} {
  539.  
  540.     global env tcl_platform
  541.  
  542.     stop
  543.  
  544.     if {$itk_option(-output) == "file"} {
  545.         set nm $itk_option(-filename)
  546.         if {[string range $nm 0 1] == "~/"} {
  547.             set nm "$env(HOME)/[string range $nm 2 end]"
  548.         }
  549.     } else {
  550.         set nm "/tmp/xge[winfo id $canvas]"
  551.     }
  552.  
  553.     set pr [_calc_print_region]
  554.     set x1 [lindex $pr 0]
  555.     set y1 [lindex $pr 1]
  556.     set x2 [lindex $pr 2]
  557.     set y2 [lindex $pr 3]
  558.     set cx [expr int(($x2 + $x1) / 2)]
  559.     set cy [expr int(($y2 + $y1) / 2)]
  560.     if {!$itk_option(-stretch)} {
  561.         set ps [_calc_poster_size]
  562.         set pshw [expr int([lindex $ps 0] / 2)]
  563.         set pshh [expr int([lindex $ps 1] / 2)]
  564.         set x [expr $cx - $pshw]
  565.         set y [expr $cy - $pshh]
  566.         set w [ezPaperInfo $itk_option(-pagesize) pwidth $itk_option(-orient) $win]
  567.         set h [ezPaperInfo $itk_option(-pagesize) pheight $itk_option(-orient) $win]
  568.     } else {
  569.         set x $x1
  570.         set y $y1
  571.         set w [expr ($x2-$x1) / $_globVar($this,hpc)]
  572.         set h [expr ($y2-$y1) / $_globVar($this,vpc)]
  573.     }
  574.  
  575.     set i 0
  576.     set px $x
  577.     while {$i < $_globVar($this,hpc)} {
  578.         set j 0
  579.         set py $y
  580.         while {$j < $_globVar($this,vpc)} {
  581.             set nm2 [expr {$_globVar($this,hpc) > 1 || $_globVar($this,vpc) > 1 ? "$nm$i.$j" : $nm}]
  582.  
  583.             if {$itk_option(-stretch)} {
  584.                 $canvas postscript \
  585.                   -file $nm2 \
  586.                   -rotate $rotate \
  587.                   -x $px -y $py \
  588.                   -width $w \
  589.                   -height $h \
  590.                   -pagex [ezPaperInfo $itk_option(-pagesize) centerx] \
  591.                   -pagey [ezPaperInfo $itk_option(-pagesize) centery] \
  592.                   -pagewidth [ezPaperInfo $itk_option(-pagesize) pwidth $itk_option(-orient)] \
  593.                   -pageheight [ezPaperInfo $itk_option(-pagesize) pheight $itk_option(-orient)]
  594.             } else {
  595.                 $canvas postscript \
  596.                   -file $nm2 \
  597.                   -rotate $rotate \
  598.                   -x $px -y $py \
  599.                   -width $w \
  600.                   -height $h \
  601.                   -pagex [ezPaperInfo $itk_option(-pagesize) centerx] \
  602.                   -pagey [ezPaperInfo $itk_option(-pagesize) centery]
  603.             }
  604.  
  605.             if {$itk_option(-output) == "printer"} {
  606.                 set cmd "$itk_option(-printcmd) < $nm2"
  607.                 if {[catch {eval exec $cmd &}]} {
  608.                     return 0
  609.                 }
  610.             }
  611.  
  612.             set py [expr $py + $h]
  613.             incr j
  614.         }
  615.         set px [expr $px + $w]
  616.         incr i
  617.     }
  618.  
  619.     return 1
  620. }
  621.  
  622. #<
  623. # Retrieves the current value for all edit fields and updates
  624. # the stamp accordingly. Is useful for Apply-buttons.
  625. #>
  626. body iwidgets::Canvasprintbox::refresh {} {
  627.     stop
  628.     _update_canvas
  629.         return
  630. }
  631.  
  632. #<
  633. # Stops the drawing of the "stamp". I'm currently unable to detect
  634. # when a Canvasprintbox gets withdrawn. It's therefore advised
  635. # that you perform a stop before you do something like that.
  636. #>
  637. body iwidgets::Canvasprintbox::stop {} {
  638.  
  639.     if {$_reposition != ""} {
  640.         after cancel $_reposition
  641.         set _reposition ""
  642.     }
  643.  
  644.     if {$_update_attr_id != ""} {
  645.         after cancel $_update_attr_id
  646.         set _update_attr_id ""
  647.     }
  648.  
  649.         return
  650. }
  651.  
  652. # ---------------------------------------------------------------
  653. # PROTECTED METHODS
  654. #----------------------------------------------------------------
  655.  
  656. #
  657. # Calculate the total size the output would be with the current
  658. # settings for "pagesize" and "posterize" (and "hpagecnt" and
  659. # "vpagecnt"). This size will be the size of the printable area,
  660. # some space has been substracted to take into account that a
  661. # page should have borders because most printers can't print on
  662. # the very edge of the paper.
  663. #
  664. # In:    posterize, hpagecnt, vpagecnt, pagesize, orient (attrib)
  665. # Out:    A list of two numbers indicating the width and the height
  666. #    of the total paper area which will be used for printing
  667. #    in pixels.
  668. #
  669. body iwidgets::Canvasprintbox::_calc_poster_size {} {
  670.     set tpw [expr [ezPaperInfo $itk_option(-pagesize) \
  671.         pwidth $itk_option(-orient) $win]*$_globVar($this,hpc)]
  672.     set tph [expr [ezPaperInfo $itk_option(-pagesize) \
  673.         pheight $itk_option(-orient) $win]*$_globVar($this,vpc)]
  674.  
  675.     return "$tpw $tph"
  676. }
  677.  
  678. #
  679. # Determine which area of the "source" canvas will be printed.
  680. # If "printregion" was set by the "user" this will be used and
  681. # converted to pixel-coordinates. If the user didn't set it
  682. # the bounding box that contains all canvas-items will be used
  683. # instead.
  684. #
  685. # In:    printregion, canvas (attrib)
  686. # Out:    Four floats specifying the region to be printed in
  687. #    pixel-coordinates (topleft & bottomright).
  688. #
  689. body iwidgets::Canvasprintbox::_calc_print_region {} {
  690.     set printreg [expr {$itk_option(-printregion) != "" 
  691.         ? $itk_option(-printregion) : [$canvas bbox all]}]
  692.  
  693.     if {$printreg != ""} {
  694.         set prx1 [winfo fpixels $canvas [lindex $printreg 0]]
  695.         set pry1 [winfo fpixels $canvas [lindex $printreg 1]]
  696.         set prx2 [winfo fpixels $canvas [lindex $printreg 2]]
  697.         set pry2 [winfo fpixels $canvas [lindex $printreg 3]]
  698.  
  699.         set res "$prx1 $pry1 $prx2 $pry2"
  700.     } else {
  701.         set res "0 0 0 0"
  702.     }
  703.     
  704.     return $res
  705. }
  706.  
  707. #
  708. # Calculate the scaling factor needed if the output was
  709. # to be stretched to fit exactly on the page (or pages).
  710. # If stretching is turned off this will always return 1.0.
  711. #
  712. # In:    stretch (attrib)
  713. # Out:    A float specifying the scaling factor.
  714. #
  715. body iwidgets::Canvasprintbox::_calc_print_scale {} {
  716.     if {$itk_option(-stretch)} {
  717.         set pr [_calc_print_region]
  718.         set prw [expr [lindex $pr 2] - [lindex $pr 0]]
  719.         set prh [expr [lindex $pr 3] - [lindex $pr 1]]
  720.         set ps [_calc_poster_size]
  721.         set psw [lindex $ps 0]
  722.         set psh [lindex $ps 1]
  723.         set sfx [expr $psw / $prw]
  724.         set sfy [expr $psh / $prh]
  725.         set sf [expr {$sfx < $sfy ? $sfx : $sfy}]
  726.         return $sf
  727.     } else {
  728.         return 1.0
  729.     }
  730. }
  731.  
  732. #
  733. # Schedule the thread that makes a copy of the "source"
  734. # canvas to the "stamp".
  735. #
  736. # In:    win, canvas (attrib)
  737. # Out:    -
  738. #
  739. body iwidgets::Canvasprintbox::_update_canvas {{when later}} {
  740.     if {$win == "" || $canvas == "" || [$canvas find all] == ""} {
  741.         return
  742.     }
  743.     if {$when == "later"} {
  744.         if {$_reposition == ""} {
  745.             set _reposition [after idle [code $this _update_canvas now]]
  746.         }
  747.         return
  748.     }
  749.  
  750.     _update_attr now
  751.  
  752.     #
  753.     # Make a copy of the "source" canvas to the "stamp".
  754.     #
  755.     if {$_globVar($this,hpc) == [llength $vlines] &&
  756.         $_globVar($this,vpc) == [llength $hlines]} {
  757.         stop
  758.         return
  759.     }    
  760.  
  761.     $canvw delete all
  762.  
  763.     set width  [winfo width $canvw]
  764.     set height [winfo height $canvw]
  765.     set ps [_calc_poster_size]
  766.  
  767.     #
  768.     # Calculate the scaling factor that would be needed to fit the
  769.     # whole "source" into the "stamp". This takes into account the
  770.     # total amount of "paper" that would be needed to print the
  771.     # contents of the "source".
  772.     #
  773.     set xsf [expr $width/[lindex $ps 0]]
  774.     set ysf [expr $height/[lindex $ps 1]]
  775.     set sf [expr {$xsf < $ysf ? $xsf : $ysf}]
  776.     set w [expr [lindex $ps 0]*$sf]
  777.     set h [expr [lindex $ps 1]*$sf]
  778.     set x1 [expr ($width-$w)/2]
  779.     set y1 [expr ($height-$h)/2]
  780.     set x2 [expr $x1+$w]
  781.     set y2 [expr $y1+$h]
  782.     set cx [expr ($x2+$x1)/ 2]
  783.     set cy [expr ($y2+$y1)/ 2]
  784.  
  785.     set printreg [_calc_print_region]
  786.     set prx1 [lindex $printreg 0]
  787.     set pry1 [lindex $printreg 1]
  788.     set prx2 [lindex $printreg 2]
  789.     set pry2 [lindex $printreg 3]
  790.     set prcx [expr ($prx2+$prx1)/2]
  791.     set prcy [expr ($pry2+$pry1)/2]
  792.  
  793.     set psf [_calc_print_scale]
  794.  
  795.     #
  796.     # Copy all items from the "real" canvas to the canvas
  797.     # showing what we'll send to the printer. Bitmaps and
  798.     # texts are not copied because they can't be scaled,
  799.     # a rectangle will be created instead.
  800.     #
  801.     set tsf [expr $sf * $psf]
  802.     set dx [expr $cx-($prcx*$tsf)]
  803.     set dy [expr $cy-($prcy*$tsf)]
  804.     $canvw create rectangle \
  805.         [expr $x1+0] \
  806.         [expr $y1+0] \
  807.         [expr $x2-0] \
  808.         [expr $y2-0] -fill white
  809.     set items [eval "$canvas find overlapping $printreg"]
  810.  
  811.     set itemCount [llength $items]
  812.     for {set cnt 0} {$cnt < $itemCount} {incr cnt} {
  813.         #
  814.         # Determine the item's type and coordinates
  815.         #
  816.         set i [lindex $items $cnt]
  817.         set t [$canvas type $i]
  818.         set crds [$canvas coords $i]
  819.  
  820.         #
  821.         # Ask for the item's configuration settings and strip
  822.         # it to leave only a list of option names and values.
  823.         #
  824.         set cfg [$canvas itemconfigure $i]
  825.         set cfg2 ""
  826.         foreach c $cfg {
  827.             if {[llength $c] == 5} {
  828.                 lappend cfg2 [lindex $c 0] [lindex $c 4]
  829.             }
  830.         }
  831.  
  832.         #
  833.         # Handle texts and bitmaps differently: they will
  834.         # be represented as rectangles.
  835.         #
  836.         if {$t == "text" || $t == "bitmap" || $t == "window"} {
  837.             set t "rectangle"
  838.             set crds [$canvas bbox $i]
  839.             set cfg2 "-outline {} -fill gray"
  840.         }
  841.  
  842.         #
  843.         # Remove the arrows from a line item when the scale
  844.         # factor drops below 1/3rd of the original size.
  845.         # This to prevent the arrowheads from dominating the
  846.         # display.
  847.         #
  848.         if {$t == "line" && $tsf < 0.33} {
  849.             lappend cfg2 -arrow none
  850.         }
  851.         
  852.         #
  853.         # Create a copy of the item on the "printing" canvas.
  854.         #
  855.         set i2 [eval "$canvw create $t $crds $cfg2"]
  856.         $canvw scale $i2 0 0 $tsf $tsf
  857.         $canvw move $i2 $dx $dy
  858.  
  859.         if {[expr $cnt%25] == 0} {
  860.             update
  861.         }
  862.         if {$_reposition == ""} {
  863.             return
  864.         }
  865.     }
  866.  
  867.     set p $x1
  868.     set i 1
  869.     set vlines {}
  870.     while {$i < $_globVar($this,hpc)} {
  871.         set p [expr $p + ($w/$_globVar($this,hpc))]
  872.         set l [$canvw create line $p $y1 $p $y2]
  873.         lappend vlines $l
  874.         incr i
  875.     }
  876.  
  877.     set p $y1
  878.     set i 1
  879.     set vlines {}
  880.     while {$i < $_globVar($this,vpc)} {
  881.         set p [expr $p + ($h/$_globVar($this,vpc))]
  882.         set l [$canvw create line $x1 $p $x2 $p]
  883.         lappend vlines $l
  884.         incr i
  885.     }
  886.  
  887.     set _reposition ""
  888. }
  889.  
  890. #
  891. # Update the attributes to reflect changes made in the user-
  892. # interface.
  893. #
  894. # In:    itk_option (attrib) - the attributes to update
  895. #    itk_component (attrib) - the widgets
  896. #    _globVar (common) - the global var holding the state
  897. #        of all radiobuttons and checkboxes.
  898. # Out:    -
  899. #
  900. body iwidgets::Canvasprintbox::_update_attr {{when "later"}} {
  901.     if {$when != "now"} {
  902.         if {$_update_attr_id == ""} {
  903.             set _update_attr_id [after idle [code $this _update_attr now]]
  904.         }
  905.         return
  906.     }
  907.  
  908.         set itk_option(-printcmd)  $_globVar($this,printeref)
  909.         set itk_option(-filename)  $_globVar($this,fileef)
  910.         set itk_option(-output)    $_globVar($this,output)
  911.     set itk_option(-pagesize)  [string tolower [$itk_component(paperom) get]]
  912.     set itk_option(-stretch)   $_globVar($this,stretchcb)
  913.     set itk_option(-posterize) $_globVar($this,postercb)
  914.     set itk_option(-vpagecnt)  $_globVar($this,vpc)
  915.     set itk_option(-hpagecnt)  $_globVar($this,hpc)
  916.     set itk_option(-orient)    [$itk_component(orientom) get]
  917.     set rotate                 [expr {$itk_option(-orient) == "landscape"}]
  918.  
  919.     if {$_globVar($this,output) == "file"} {
  920.         $itk_component(fileef) configure \
  921.             -state normal -foreground $itk_option(-foreground)
  922.         $itk_component(printeref) configure \
  923.             -state disabled -foreground $itk_option(-disabledforeground)
  924.     } else {
  925.         $itk_component(fileef) configure \
  926.             -state disabled -foreground $itk_option(-disabledforeground)
  927.         $itk_component(printeref) configure \
  928.             -state normal -foreground $itk_option(-foreground)
  929.     }
  930.  
  931.     set fg [expr {$_globVar($this,postercb) \
  932.         ? $itk_option(-foreground) : $itk_option(-disabledforeground)}]
  933.  
  934.     $itk_component(vpcnt) configure -foreground $fg
  935.     $itk_component(hpcnt) configure -foreground $fg
  936.     $itk_component(pages) configure -foreground $fg
  937.  
  938.     #
  939.     # Update dependencies among widgets. (For example: disabling
  940.     # an entry-widget when its associated checkbox-button is used
  941.     # to turn of the option (the entry's value is not needed
  942.     # anymore and this should be reflected in the fact that it
  943.     # isn't possible to change it anymore).
  944.     #
  945.     # former method:_update_widgets/_update_UI
  946.     #
  947.     set state [expr {$itk_option(-posterize) ? "normal" : "disabled"}]
  948.     $itk_component(vpcnt) configure -state $state
  949.     $itk_component(hpcnt) configure -state $state
  950.     $itk_component(paperom) select "*[string range $itk_option(-pagesize) 1 end]"
  951.  
  952.     set _update_attr_id ""
  953. }
  954.  
  955. #
  956. # Gets called when the CanvasPrintBox-widget gets mapped.
  957. #
  958. body iwidgets::Canvasprintbox::_mapEventHandler {} {
  959.     set win $itk_interior
  960.     set canvw $itk_component(canvas)
  961.     if {$canvas != ""} {
  962.         setcanvas $canvas
  963.     }
  964.     _update_attr
  965. }
  966.  
  967. #
  968. # Destroy this object and its associated widgets.
  969. #
  970. body iwidgets::Canvasprintbox::destructor {} {
  971.     stop
  972. }
  973.  
  974. #
  975. # Hold the information about common paper sizes. A bit of a hack, but it
  976. # should be possible to add your own if you take a look at it.
  977. #
  978. body iwidgets::Canvasprintbox::ezPaperInfo {size {attr ""} \
  979.     {orient "portrait"} {window ""}} {
  980.     
  981.     set size [string tolower $size]
  982.     set attr [string tolower $attr]
  983.     set orient [string tolower $orient]
  984.     
  985.     case $size in {
  986.         types {
  987.             return "A5 A4 A3 A2 A1 Legal Letter"
  988.         }
  989.         a5 {
  990.             set paper(x1) "1.0c"
  991.             set paper(y1) "1.0c"
  992.             set paper(x2) "13.85c"
  993.             set paper(y2) "20.0c"
  994.             set paper(pheight) "19.0c"
  995.             set paper(pwidth) "12.85c"
  996.             set paper(height) "21.0c"
  997.             set paper(width) "14.85c"
  998.             set paper(centerx) "7.425c"
  999.             set paper(centery) "10.5c"
  1000.         }
  1001.         a4 {
  1002.             set paper(x1) "1.0c"
  1003.             set paper(y1) "1.0c"
  1004.             set paper(x2) "20.0c"
  1005.             set paper(y2) "28.7c"
  1006.             set paper(pheight) "27.7c"
  1007.             set paper(pwidth) "19.0c"
  1008.             set paper(height) "29.7c"
  1009.             set paper(width) "21.0c"
  1010.             set paper(centerx) "10.5c"
  1011.             set paper(centery) "14.85c"
  1012.         }
  1013.         a3 {
  1014.             set paper(x1) "1.0c"
  1015.             set paper(y1) "1.0c"
  1016.             set paper(x2) "28.7c"
  1017.             set paper(y2) "41.0c"
  1018.             set paper(pheight) "40.0c"
  1019.             set paper(pwidth) "27.7c"
  1020.             set paper(height) "42.0c"
  1021.             set paper(width) "29.7c"
  1022.             set paper(centerx) "14.85c"
  1023.             set paper(centery)  "21.0c"
  1024.         }
  1025.         a2 {
  1026.             set paper(x1) "1.0c"
  1027.             set paper(y1) "1.0c"
  1028.             set paper(x2) "41.0c"
  1029.             set paper(y2) "58.4c"
  1030.             set paper(pheight) "57.4c"
  1031.             set paper(pwidth) "40.0c"
  1032.             set paper(height) "59.4c"
  1033.             set paper(width) "42.0c"
  1034.             set paper(centerx) "21.0c"
  1035.             set paper(centery)  "29.7c"
  1036.         }
  1037.         a1 {
  1038.             set paper(x1) "1.0c"
  1039.             set paper(y1) "1.0c"
  1040.             set paper(x2) "58.4c"
  1041.             set paper(y2) "83.0c"
  1042.             set paper(pheight) "82.0c"
  1043.             set paper(pwidth) "57.4c"
  1044.             set paper(height) "84.0c"
  1045.             set paper(width) "59.4c"
  1046.             set paper(centerx) "29.7c"
  1047.             set paper(centery)  "42.0c"
  1048.         }
  1049.         legal {
  1050.             set paper(x1) "0.2i"
  1051.             set paper(y1) "0.2i"
  1052.             set paper(x2) "8.3i"
  1053.             set paper(y2) "13.8i"
  1054.             set paper(pheight) "13.6i"
  1055.             set paper(pwidth) "8.1i"
  1056.             set paper(height) "14.0i"
  1057.             set paper(width) "8.5i"
  1058.             set paper(centerx) "4.25i"
  1059.             set paper(centery) "7.0i"
  1060.         }
  1061.         letter {
  1062.             set paper(x1) "0.2i"
  1063.             set paper(y1) "0.2i"
  1064.             set paper(x2) "8.3i"
  1065.             set paper(y2) "10.8i"
  1066.             set paper(pheight) "10.6i"
  1067.             set paper(pwidth) "8.1i"
  1068.             set paper(height) "11.0i"
  1069.             set paper(width) "8.5i"
  1070.             set paper(centerx) "4.25i"
  1071.             set paper(centery) "5.5i"
  1072.         }
  1073.         default {
  1074.             error "ezPaperInfo: Unknown paper type ($type)"
  1075.         }
  1076.     }
  1077.     
  1078.     set inv(x1) "y1"
  1079.     set inv(x2) "y2"
  1080.     set inv(y1) "x1"
  1081.     set inv(y2) "x2"
  1082.     set inv(pwidth) "pheight"
  1083.     set inv(pheight) "pwidth"
  1084.     set inv(width) "height"
  1085.     set inv(height) "width"
  1086.     set inv(centerx) "centery"
  1087.     set inv(centery) "centerx"
  1088.     
  1089.     case $orient in {
  1090.         landscape {
  1091.             set res $paper($inv($attr))
  1092.         }
  1093.         portrait {
  1094.             set res $paper($attr)
  1095.         }
  1096.         default {
  1097.             error "ezPaperInfo: orientation should be\
  1098.                 portrait or landscape (not $orient)"
  1099.         }
  1100.     }
  1101.     
  1102.     if {$window != ""} {
  1103.         set res [winfo fpixels $window $res]
  1104.     }
  1105.     
  1106.     return $res
  1107.