source: tol/tolbase/lib/renderpane/renderpane.tcl @ 73aa767e

1941-docker-image-to-testdevel
Last change on this file since 73aa767e was a680983, checked in by Jorge Pérez <josp.jorge@…>, 15 years ago

refs #1347, hipertext widget extracted from Notebook App

git-svn-id: ​https://www.tol-project.org/svn/tolp/trunk@3878 be4846ae-f051-483a-831f-b64e7d08527f

  • Property mode set to 100644
File size: 30.7 KB
Line 
1package require Tk
2package require snit
3package require trycatch
4package require markupparser
5
6namespace import trycatch::*
7interp alias {} prefs {} ::Notebook::prefs
8
9#-----------------------------------------------------------------------
10# TITLE:
11#       renderpane.tcl
12#
13# AUTHOR:
14#       Will Duquette
15#
16# DESCRIPTION:
17#       A read-only text widget designed to render Notebook markup.
18#       From the standpoint of the caller, the "render" method replaces
19#       the "insert" and "delete" methods, which are effectively no-ops.
20#
21#       All necessary text widget commands are delegated down to the text
22#       widget.  This widget knows how to render and tag Notebook markup,
23#       but it doesn't provide any of the active behavior.
24#
25# LICENSE:
26#       Copyright (C) 2005 by William H. Duquette.  This file may
27#       be used subject to the terms in license.txt.
28#
29#-----------------------------------------------------------------------
30
31snit::widgetadaptor renderpane {
32    #-------------------------------------------------------------------
33    # Text Widget Adaptation
34
35    # Disable the insert and delete methods, to make this readonly.
36    method insert {args} {}
37    method delete {args} {}
38
39    # Pass all otherwise undefined methods and options to the real
40    # text widget, so that the remaining behavior is as expected.
41    delegate method * to hull
42    delegate option * to hull
43
44    #-------------------------------------------------------------------
45    # Widget options
46
47    # The command to use to query about a link's existence.  Must take
48    # a page name as argument and return 1 if it exists, and 0 otherwise.
49    option -querycommand {}
50
51    # The command to call when a page title is clicked.  Should take the
52    # title as its argument.
53    option -titlecommand {}
54
55    # The command to call when a page link is clicked.  Should take the
56    # name of the page to link to as its argument.
57    option -linkcommand {}
58
59    # The command to call when a magic button is clicked.  The command
60    # should take one argument, the script to execute.
61    option -buttoncommand {}
62
63    # The command to call when a macroerror is clicked.  The command
64    # should take one argument, the text of the macro.
65    option -macroerrorcommand {}
66
67    # The command to call to write a message to the message line
68    option -messagecommand {}
69
70    # The notebook file directory; used as the root for relative paths.
71    option -dbdir {}
72
73    # The missing image to show when [!image !] could not be resolved
74    option -missingimage ""
75
76    #-------------------------------------------------------------------
77    # Instance Variables
78   
79    # The code associated with a magic button, where the index is
80    # $button-$index.  $button is the displayed text for the button
81    # and $index is the index of the first character of the displayed text.
82    variable bcode
83
84    # Counter used to generate names for horizontal line elements in
85    # the text pane.
86    variable counter 0
87
88    # Escape character substitutions
89    # TBD: Some of this should probably be done as part of markup parsing.
90    variable escapeMapping \
91        "&lt; < &gt; > &lb; \[ &rb; \] &amp; &"
92
93    # Image List -- loaded images, for later destruction
94    variable imageList {}
95
96    # Image Data array: the index is the text widget index of the image,
97    # and the value is the text to display.
98    variable imageData
99
100    typevariable defaultMissingImage
101
102    # Type constructor: build resources
103    typeconstructor {
104      set defaultMissingImage [ image create photo -data {
105        R0lGODlhIAAgAIAAADNmmQUFBSwAAAAAIAAgAAACYIyPqZvgD6OcztCLn81c7g4C36Vwo8cE2Kml
106        B6lSb1VOLBS3iJx3NRoSNWy9zA/oG/JAR6RRuTTtntIZ9WldFYk3YpC5RXWdvOkVZtZis7D1GBeO
107        pNVfad1+p+fLrn6qAAA7q
108      } ]
109    }
110
111    #-----------------------------------------------------------------------
112    # Constructor and Destructor
113
114    constructor {args} {
115        set options(-querycommand) [codename DefaultQueryCmd]
116        set options(-missingimage) $defaultMissingImage
117
118        # Next, create the rotext pane.
119        installhull using text \
120            -insertwidth 0 \
121            -borderwidth 5 \
122            -relief flat \
123            -setgrid true \
124            -wrap word \
125            -cursor xterm
126
127        # At present, all delegated options are delegated to the
128        # hull component, so now we can configure.
129      $self configurelist $args
130
131        # Next, create the bullet icons
132        image create bitmap $win.bullet1 -data {
133            #define button_width 8
134            #define button_height 8
135            static unsigned char button_bits[] = {
136                0x00, 0x3c, 0x7e, 0x7e, 0x7e, 0x7e, 0x3c, 0x00};
137        }
138
139        image create bitmap $win.bullet2 -data {
140            #define bullet2_width 8
141            #define bullet2_height 8
142            static unsigned char bullet2_bits[] = {
143                0x00, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0x00};
144        }
145
146        image create bitmap $win.bullet3 -data {
147            #define bullet3_width 8
148            #define bullet3_height 8
149            static unsigned char bullet3_bits[] = {
150                0x00, 0x00, 0x00, 0x7e, 0x7e, 0x00, 0x00, 0x00};
151        }
152
153        # Next, add the markup tags, using the user preferences.
154        $self UsePreferences
155
156        # Next, copy the default Text bindings to the renderpane,
157        # and adjust the bindtags so that the Text bindings no longer
158        # matter.  This will allow us to override them.
159
160        foreach sym [bind Text] {
161            bind $win $sym [bind Text $sym]
162        }
163
164        set bt [bindtags $win]
165        set ndx [lsearch -exact $bt Text]
166        bindtags $win [lreplace $bt $ndx $ndx]
167
168        # Next, remove the <<Cut>> and <<Paste>> tags, etc., since renderpanes
169        # aren't editable.
170        bind $win <<Cut>> ""
171        bind $win <<Paste>> ""
172        bind $win <<Undo>> ""
173        bind $win <<Redo>> ""
174
175        # When over an active tag, the cursor should be a hand.
176        foreach tag {title link button macroerror} {
177            $hull tag bind $tag <Enter> \
178                [mymethod EnterHandler $tag %x %y]
179               
180            $hull tag bind $tag <Leave> \
181                [mymethod LeaveHandler $tag %x %y]
182        }
183
184        # While over images, display the -text and path.
185        $hull tag bind image <Enter> [mymethod EnterImage %x %y]
186        $hull tag bind image <Leave> [mymethod LeaveImage %x %y]
187
188        # Prepare to receive preferences events; unregister on
189        # destroy.
190        prefs register $selfns [mymethod UsePreferences]
191
192        # Add better navigation keys
193        bind $win <Key-Down>  [list $hull yview scroll  1 units]
194        bind $win <Key-Up>    [list $hull yview scroll -1 units]
195        bind $win <Key-Next>  [list $hull yview scroll  1 pages]
196        bind $win <Key-Prior> [list $hull yview scroll -1 pages]
197        bind $win <Key-Home>  [list $hull yview moveto 0]
198        bind $win <Key-End>   [list $hull yview moveto 1]
199
200        # Add mouse interactions
201        $hull tag bind title <1> \
202            [mymethod TitleHandler %x %y]
203
204        $hull tag bind link <1> \
205            [mymethod LinkHandler %x %y]
206
207        $hull tag bind button <ButtonRelease-1> \
208            [mymethod ButtonHandler %x %y]
209
210        $hull tag bind macroerror <ButtonRelease-1> \
211            [mymethod MacroErrorHandler %x %y]
212
213    }
214
215    destructor {
216        catch {prefs unregister $selfns}
217        catch {image delete $win.bullet1 $win.bullet2 $win.bullet3}
218        catch {$self FreeImages}
219    }
220
221    #-----------------------------------------------------------------------
222    # Public methods
223
224    # Render a page into the page.  Uses ::markupparser::parseWithHandler
225    # and ParseHandler to do the job.
226    method render {title text} {
227        variable sty
228
229        # FIRST, delete all text from the text widget.
230        $hull del 1.0 end
231
232        # NEXT, forget all images
233        $self FreeImages
234
235        # NEXT, forget about any magic buttons; we'll build a new set.
236        array unset bcode
237
238        # NEXT, render the title
239        if { $title ne "" } {
240          $hull insert end " $title\n" title
241          $hull insert end "\n"
242        }
243
244        # NEXT, enable the default text style and indent
245        set sty(para) ""
246        set sty(txt) ""
247        set indent 0
248
249        # NEXT, render the page's text
250        foreach {tag value} [::markupparser::parse $text] {
251            switch -exact -- $tag {
252                META { }
253                HASH {
254                    # FIRST, #--- is always displayed specially.
255                    if {[string match "#---*" $value]} {
256                        $self InsertHLine
257                        continue
258                    }
259
260                    # NEXT, if the prefs flag is set then all directives
261                    # are displayed.
262                    if {[prefs get displaydirectives]} {
263                        $hull insert end $value pre
264                        continue
265                    }
266
267                    # NEXT, display directives based on what they are.
268                    if {[string match "#pre*" $value]} {
269                        # Skip it.
270                    } elseif {[string match "#unpre*" $value]} {
271                        # Skip it.
272                    } elseif {[string match "#meta*" $value]} {
273                        # Skip it.
274                    } elseif {[string match "#rem*" $value]} {
275                        # Skip it.
276                    } elseif {[string match "#data*" $value]} {
277                        # Skip it
278                    } elseif {[string match "#undata*" $value]} {
279                        # Skip it
280                    } elseif {[string match "#Tcl*" $value]} {
281                        # Skip it
282                    } elseif {[string match "#unTcl*" $value]} {
283                        # Skip it
284                    } else {
285                        $hull insert end $value pre
286                    }
287                }
288                PRE {
289                    $hull insert end $value pre
290                }
291                TCL {
292                    $hull insert end $value tcl
293                }
294                DATA {
295                    array set fields $value
296                    $hull insert end $fields(data) pre
297                }
298                H {
299                    set lev [lindex $value 0]
300                    set htext [lindex $value 1]
301
302                    $hull insert end "$htext\n" header$lev
303                }
304                P {
305                    set ptype  [lindex $value 0]
306                    set indent [lindex $value 1]
307
308                    # FIRST, basic paragraph setup.
309                    set sty(bold) ""
310                    set sty(italic) ""
311                    set sty(mono) ""
312                    set sty(strike) ""
313                    set sty(small) ""
314                    set sty(header) ""
315                    set sty(para) ""
316                    set sty(txt) ""
317                    set sty(link) "link"
318                    set sty(button) "button"
319
320                    # NEXT, set up for bulleted and indented paragraphs
321
322                    if {$ptype eq "*"} {
323                        set sty(para) "indent$indent"
324                        set sty(txt) $sty(para)
325                        set sty(link) [concat $sty(txt) link]
326                        set sty(button) [concat $sty(txt) button]
327           
328                        set lead [string repeat "\t" [expr {$indent - 1}]]
329               
330                        switch $indent {
331                            1       {set image $win.bullet1}
332                            2       {set image $win.bullet2}
333                            default {set image $win.bullet3}
334                        }
335                   
336                        $hull insert end "$lead" $sty(para)
337                        $hull image create end -image $image -align center
338                        $hull insert end "\t" $sty(para)
339                    } elseif {$indent > 0} {
340                        set sty(para) "indent$indent"
341                        set sty(txt) $sty(para)
342                        set sty(link) [concat $sty(txt) link]
343                        set sty(button) [concat $sty(txt) button]
344                   
345                        $hull insert end [string repeat "\t" $indent] $sty(para)
346                    }
347                }
348                STY {
349                    switch -exact -- [lindex $value 0] {
350                        m1  {
351                            set sty(mono) "mono"
352                            set sty(header) ""
353                            set sty(small) ""}
354                        m0 {
355                            set sty(mono) ""
356                        }
357                        b1  {
358                            set sty(bold) "bold"
359                            set sty(header) ""
360                            set sty(small) ""
361                        }
362                        b0 {
363                            set sty(bold) ""
364                        }
365                        i1  {
366                            set sty(italic) "italic"
367                            set sty(header) ""
368                            set sty(small) ""
369                        }
370                        i0 {
371                            set sty(italic) ""
372                        }
373                        h1  {
374                            set sty(header) "header3"
375                            set sty(bold) ""
376                            set sty(italic) ""
377                            set sty(mono) ""
378                            set sty(small) ""
379                        }
380                        h0 {
381                            set sty(header) ""
382                        }
383                        s1  {
384                            set sty(small) "small"
385                            set sty(bold) ""
386                            set sty(italic) ""
387                            set sty(mono) ""
388                            set sty(header) ""
389                        }
390                        s0 {
391                            set sty(small) ""
392                        }
393                        x1  {
394                            set sty(strike) "strike"
395                        }
396                        x0 {
397                            set sty(strike) ""
398                        }
399                        default {error "Unknown style: [lindex $value 1]"}
400                    }
401
402                    # Build the style list
403                    if {$sty(header) ne ""} {
404                        set theFont $sty(header)
405                    }
406                   
407                    set sty(txt) "$sty(para) $sty(mono)$sty(bold)$sty(italic) $sty(strike) $sty(header) $sty(small)"
408                    set sty(link) [concat $sty(txt) link]
409                    set sty(button) [concat $sty(txt) button]
410                }
411                LINK {
412                    #set value [NormalizeSpace $value]
413
414                    if {![regexp {^([^|]+)\|(.*$)} $value dummy linktext name]} {
415                        set linktext $value
416                        set name $value
417                    }
418                    set linktext [NormalizeNewlines $linktext]
419                    set name [NormalizeSpace $name]
420
421                    # If it exists, show it normally; if not, show it differently.
422                    if {[$self QueryLink $name]} {
423                        set index [$hull index insert]
424                        $hull insert end $linktext $sty(link)
425                    } else {
426                        $hull insert end "\[" [concat $sty(txt) warning]
427                        set index [$hull index insert]
428                        $hull insert end $linktext $sty(link)
429                        $hull insert end "\]" [concat $sty(txt) warning]
430                    }
431
432                    # Save the page to link to in bcode.
433                    set bcode([string tolower $linktext]-$index) $name
434                }
435                BTN {
436                    if {[regexp {^([^|]+)\|(.*$)} $value dummy bname code]} {
437                        set bname [NormalizeNewlines $bname]
438                        set index [$hull index insert]
439                        set bcode([string tolower $bname]-$index) $code
440                        $hull insert end $bname $sty(button)
441                    } else {
442                        $hull insert end "\[%$value%\]" warningmono
443                    }
444                }
445                OBJECT {
446                    set obj [getobj $value]
447                    switch -exact [lindex $obj 0] {
448                        image {
449                            $self InsertImage $obj
450                        }
451                        error {
452                            $hull insert end "\[!$value!\]" warningmono
453                            $self Msg [lindex $obj 1]
454                        }
455                        default {
456                            $hull insert end "\[!$value!\]" warningmono
457                            $self Msg "Unrecognized object type: $value"
458                        }
459                    }
460                }
461                MACRO {
462                    # We should see this only if macro expansion failed for this
463                    # macro
464                    $hull insert end "\[@$value@\]" macroerror
465                }
466                TXT -
467                HTML {
468                    # Normalize normal text: replace the whitespace between lines
469                    # a single space.
470                    regsub -all {\s*\n\s*} $value " " value
471                    $hull insert end [string map $escapeMapping $value] $sty(txt)
472                }
473                BR {
474                    $hull insert end "\n" $sty(txt)
475                    $hull insert end [string repeat "\t" $indent] $sty(para)
476                }
477                /P -
478                NL {
479                    $hull insert end "\n" $sty(txt)
480                }
481                default {error "Unknown markup tag: $tag"}
482            }
483        }
484    }
485
486    # Tag text that matches the search text.
487    method searchfor {searchText} {
488        $hull tag remove search 1.0 end
489
490        set pattern [string trim $searchText]
491
492        if {$pattern eq ""} {
493            return
494        }
495
496        set done 0
497        set index 1.0
498        set count 0
499        while {1} {
500            set index [$hull search -nocase -count count -- $pattern $index end]
501
502            if {$index eq ""} {
503                return
504            }
505
506            set endIndex [$hull index "$index + $count chars"]
507
508            $hull tag add search $index $endIndex
509
510            set index $endIndex
511        }
512    }
513
514
515    #-----------------------------------------------------------------------
516    # Private Methods and Procs
517
518    # Given the name of a tag that's been clicked on, and the x,y pixel
519    # coordinates of the click, return the tagged text.
520    method GetTagText {tag x y} {
521        set range [$hull tag prevrange $tag "@$x,$y +1 chars"]
522
523        return [$hull get [lindex $range 0] [lindex $range 1]]
524    }
525
526    # Given the name of a tag that's been clicked on, and the x,y pixel
527    # coordinates of the click, return the range {startIndex endIndex}.
528    method GetTagRange {tag x y} {
529        return [$hull tag prevrange $tag "@$x,$y +1 chars"]
530    }
531
532    # Returns 1 if a link exists and 0 otherwise.  Uses the -querycommand.
533    method QueryLink {name} {
534        set command $options(-querycommand)
535        lappend command $name
536        return [uplevel \#0 $command]
537    }
538
539    # Default query; always returns true.
540    proc DefaultQueryCmd {args} {
541        return 1
542    }
543
544    # Called when a special tag is entered
545    method EnterHandler {tag x y} {
546        $hull configure -cursor hand2
547
548        if {$tag eq "link" || $tag eq "button"} {
549            set range [$self GetTagRange $tag $x $y]
550            set name  [$hull get [lindex $range 0] [lindex $range 1]]
551            set index [lindex $range 0]
552
553            set bcodeKey "[string tolower $name]-$index"
554           
555            # TBD: It would be better if there were a -hovercommand;
556            # it could be passed the relevant info, and the caller
557            # could decide how to use it.
558
559            $self Msg $bcode($bcodeKey)
560        }
561    }
562
563    # Called when a special tag is left
564    method LeaveHandler {tag x y} {
565        $hull configure -cursor xterm
566
567        if {$tag eq "link" || $tag eq "button"} {
568            $self Msg ""
569        }
570    }
571
572    # Called when an image is entered
573    method EnterImage {x y} {
574        set ndx [$hull index @$x,$y]
575        $self Msg $imageData($ndx)
576    }
577
578    # Called when an image is left
579    method LeaveImage {x y} {
580        $self Msg ""
581    }
582
583    # Called to write a message to the -messagecommand.
584    method Msg {text} {
585        if {$options(-messagecommand) eq ""} {
586            return
587        }
588
589        set cmd $options(-messagecommand)
590        lappend cmd $text
591        uplevel \#0 $cmd
592    }
593
594    # Called when the title is clicked.
595    method TitleHandler {x y} {
596        set command $options(-titlecommand)
597
598        if {$command eq ""} {
599            return
600        }
601
602        # As formatted, the title includes leading and trailing
603        # whitespace; delete it.
604        lappend command [string trim [$self GetTagText title $x $y]]
605        uplevel \#0 $command
606    }
607
608    # Called when a link is clicked.
609    method LinkHandler {x y} {
610        set command $options(-linkcommand)
611
612        if {$command eq ""} {
613            return
614        }
615
616        set range [$self GetTagRange link $x $y]
617        set name  [$hull get [lindex $range 0] [lindex $range 1]]
618        set index [lindex $range 0]
619
620        lappend command $bcode([string tolower $name]-$index)
621        uplevel \#0 $command
622    }
623
624    # Finds the button script and calls the button command
625    method ButtonHandler {x y} {
626        set command $options(-buttoncommand)
627
628        if {$command eq ""} {
629            return
630        }
631
632        set range [$self GetTagRange button $x $y]
633        set name  [$hull get [lindex $range 0] [lindex $range 1]]
634        set index [lindex $range 0]
635
636        lappend command $bcode([string tolower $name]-$index)
637        uplevel \#0 $command
638    }
639
640    # Finds the macroerror macro text and calls the macroerror command
641    method MacroErrorHandler {x y} {
642        set command $options(-macroerrorcommand)
643
644        if {$command eq ""} {
645            return
646        }
647
648        # The macro [@ @] brackets are included in the text; remove
649        # them.
650        set macro [string range [$self GetTagText macroerror $x $y] 2 end-2]
651
652        lappend command $macro
653        uplevel \#0 $command
654    }
655
656    # defines and updates style tags when preferences change.
657    method UsePreferences {} {
658        # TBD: Make this a preference setting.
659        set tabWidth 0.2
660
661        $win.bullet1 configure \
662            -foreground [prefs get normalfg] \
663            -background [prefs get normalbg] \
664
665        $win.bullet2 configure \
666            -foreground [prefs get normalfg] \
667            -background [prefs get normalbg] \
668
669        $win.bullet3 configure \
670            -foreground [prefs get normalfg] \
671            -background [prefs get normalbg] \
672
673        $hull configure \
674            -foreground [prefs get normalfg] \
675            -background [prefs get normalbg] \
676            -font [prefs get bodytext] \
677            -tabs [list ${tabWidth}i [expr $tabWidth*2]i]
678
679        $hull tag configure title \
680            -font [prefs get titletext] \
681            -foreground [prefs get titlefg] \
682            -background [prefs get titlebg]
683
684        $hull tag configure header1 \
685            -font [prefs get header1text]
686
687        $hull tag configure header2 \
688            -font [prefs get header2text]
689
690        $hull tag configure header3 \
691            -font [prefs get header3text]
692
693        $hull tag configure small \
694            -font [prefs get smalltext]
695
696        $hull tag configure bold \
697            -font [concat [prefs get bodytext] bold]
698
699        $hull tag configure italic \
700            -font [concat [prefs get bodytext] italic]
701
702        $hull tag configure bolditalic \
703            -font [concat [prefs get bodytext] [list bold italic]]
704
705        $hull tag configure mono \
706            -font [prefs get monotext]
707
708        $hull tag configure monobold \
709            -font [concat [prefs get monotext] bold]
710
711        $hull tag configure monoitalic \
712            -font [concat [prefs get monotext] italic]
713
714        $hull tag configure monobolditalic \
715            -font [concat [prefs get monotext] [list bold italic]]
716
717        $hull tag configure strike \
718            -overstrike 1
719
720        $hull tag configure link \
721            -foreground [prefs get linkfg] \
722            -background [prefs get linkbg]
723
724        $hull tag configure warning \
725            -foreground [prefs get warningfg] \
726            -background [prefs get warningbg]
727
728        $hull tag configure warningmono \
729            -font [prefs get monotext] \
730            -foreground [prefs get warningfg] \
731            -background [prefs get warningbg]
732
733        $hull tag configure button \
734            -foreground [prefs get buttonfg] \
735            -background [prefs get buttonbg]
736
737        $hull tag configure macroerror \
738            -font [prefs get monotext] \
739            -foreground [prefs get warningfg] \
740            -background [prefs get warningbg]
741
742        $hull tag configure pre \
743            -font [prefs get monotext] \
744            -foreground [prefs get prefg] \
745            -background [prefs get prebg]
746
747        $hull tag configure tcl \
748            -font [prefs get monotext] \
749            -foreground [prefs get tclfg] \
750            -background [prefs get tclbg]
751
752        $hull tag configure search \
753            -foreground [prefs get searchfg] \
754            -background [prefs get searchbg]
755
756        # Up to 9 levels of indent
757        for {set i 1} {$i <= 9} {incr i} {
758            $hull tag configure "indent$i" \
759                -lmargin2 [expr $i*$tabWidth]i
760        }
761
762        # Give highest priority to the selection to make it visible when some
763        # text with a non-default background is selected
764        $hull tag raise sel
765    }
766
767    # Inserts a horizontal line into the pane by creating a frame widget.
768    method InsertHLine {} {
769        # First, create the frame as a child of the pane.
770        incr counter
771        set f $win.h$counter
772
773        set width [expr {[winfo reqwidth $win] - 20}]
774
775        frame $f -height 4 -width $width -background white \
776            -borderwidth 2 -relief groove
777
778        # Next, insert it into the pane.
779        $hull window create end -window $f -align center -pady 3
780        $hull insert end "\n" pre
781    }
782
783    # Removes leading and trailing whitespace, and reduces internal whitespace
784    # sequences to one space.
785    proc NormalizeSpace {text} {
786        regsub -all {\n} $text " " text
787        regsub -all {\s+} $text " " text
788 
789        return [string trim $text]
790    }
791
792    # Reduces internal whitespace sequences which contain a newline
793    # to a single space.  Other whitespace is left alone.
794    proc NormalizeNewlines {text} {
795        regsub -all {\s*\n\s*} $text " " text
796 
797        return $text
798    }
799
800    # Parses an image request, and loads and inserts the image.
801    method InsertImage {arglist} {
802        set fileName [file join $options(-dbdir) [lindex $arglist 1]]
803
804        array set opts [lindex $arglist 2]
805
806        if {$opts(-text) ne ""} {
807            set disptext "$opts(-text): $fileName"
808        } else {
809            set disptext $fileName
810        }
811
812        try {
813            set images [LoadImage $fileName $opts(-width) $opts(-height)]
814        } catch -msg msg {
815            puts "Couldn't load '$fileName': $msg"
816          set images [ list $options(-missingimage) ]
817        }
818
819        # NEXT, insert it into the text window.  If there's only one
820        # image, just insert it normally; otherwise, insert the strips.
821        # If there's a list, insert them in sequence.
822        if {[llength $images] == 1} {
823            set imageIndex [$hull index insert]
824            set imageData($imageIndex) $disptext
825            $hull image create end -image [lindex $images 0] \
826                -padx $opts(-padwidth)
827
828            $hull tag add image $imageIndex
829        } else {
830            foreach img $images {
831                if {[$hull compare insert > "insert linestart"]} {
832                    $hull insert insert "\n"
833                }
834                set imageIndex [$hull index insert]
835                set imageData($imageIndex) $disptext
836                $hull image create end -image $img \
837                    -padx $opts(-padwidth)
838                $hull tag add image $imageIndex
839            }
840        }
841    }
842
843    # Destroys all loaded images
844    method FreeImages {} {
845        array unset imageData
846
847        foreach img $imageList {
848            image delete $img
849        }
850        set imageList {}
851    }
852
853    # Loads an image, subsampling down to the desired size.
854    # Pass 0 width, 0 height for the default size.
855    # If the image is "tall", it's broken into strips;
856    # this helps everything scroll better.
857    proc LoadImage {filename {width 0} {height 0}} {
858        puts "LoadImage $filename"
859        if { [ file readable $filename ] } {
860          # FIRST, load the image
861          set img [image create photo -file $filename]
862        } elseif { [ lsearch [ image names ] $filename ] != -1 } {
863          # It is a valid tk image
864          set img $filename
865        } else {
866          error "$filename does not reference a valid image"
867        }
868        # NEXT, if the width and height are both 0, scale it..
869        if {$width > 0 || $height > 0} {
870            # FIRST, figure out how to scale it.
871            set iwidth [image width $img]
872            set iheight [image height $img]
873
874            if {$width == 0} {
875                set width $iwidth
876            }
877
878            if {$height == 0} {
879                set height $iheight
880            }
881           
882            set scale 1
883           
884            while {$iheight/$scale > $height ||
885                   $iwidth/$scale > $width} {
886                incr scale
887            }
888
889            # NEXT, scale the image, and delete the original.
890            set iheight [expr {$iheight/$scale}]
891            set iwidth [expr {$iwidth/$scale}]
892            set dest [image create photo]
893            $dest copy $img -subsample $scale
894
895            image delete $img
896
897            set img $dest
898        }
899
900        # NEXT, if the image is tall, cut it into horizontal strips,
901        # and return a list of the strips.  This allows the text
902        # widget to scroll more nicely.
903        set iheight [image height $img]
904        set iwidth [image width $img]
905
906        set stripHeight 25
907       
908        if {1 || $iheight <= $stripHeight} {
909            lappend imageList $img
910
911            return [list $img]
912        }
913
914        set iy 0
915        set results {}
916        while {$iy < $iheight} {
917            if {$iy + $stripHeight > $iheight} {
918                set stripHeight [expr {$iheight - $iy}]
919            }
920
921            set strip [image create photo]
922            $strip copy $img -from 0 $iy $iwidth [incr iy $stripHeight]
923            lappend results $strip
924            lappend imageList $strip
925        }
926       
927        # NEXT, we no longer need the image from which we took the strips.
928        image delete $img
929
930        return $results
931    }
932}
933
934package provide renderpane 2.1.3
Note: See TracBrowser for help on using the repository browser.