Ignore:
Timestamp:
May 17, 2010, 6:26:29 PM (14 years ago)
Author:
mmc
Message:

Fixed the image object to act more like a true input. If an image has a
label, it will show a thumbnail along with image info, and users can
right-click to get upload/download options. If there's no label, then
the image is shown full-size as before, so it acts like a decoration.

Changed binary string values to look like the image, with an icon representing
binary data and an info string showing info about the data type. This is
a little nicer than the hex dump we used to show for binary strings. String
size can be set to "binary" to force the string into the binary display
mode.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/gui/scripts/imageentry.tcl

    r1342 r1715  
    2727    public method tooltip {}
    2828
    29     private method _redraw {}
     29    protected method _redraw {}
     30    protected method _outline {imh color}
     31    protected method _uploadValue {args}
     32    protected method _downloadValue {}
    3033
    3134    private variable _owner ""    ;# thing managing this control
    3235    private variable _path ""     ;# path in XML to this image
     36    private variable _data ""     ;# current image data
    3337    private variable _imh ""      ;# image handle for current value
    3438    private variable _resize ""   ;# image for resize operations
     39
     40    private common _thumbsize 100 ;# std size for thumbnail images
    3541}
    3642
     
    5157    set _owner $owner
    5258    set _path $path
     59    set _resize [image create photo]
    5360
    5461    #
    5562    # Create the widget and configure it properly based on other
    56     # hints in the XML.
     63    # hints in the XML.  Two ways to display:  Old apps use images
     64    # without labels as decorations.  In that case, show the image
     65    # alone, probably full size.  Newer apps use images as inputs.
     66    # In that case, show a thumbnail of the image with some extra
     67    # facts about image type, file size, etc.
    5768    #
    5869    itk_component add image {
    5970        ::label $itk_interior.image -borderwidth 0
    6071    }
    61     pack $itk_component(image) -expand yes -fill both
    62     bind $itk_component(image) <Configure> [itcl::code $this _redraw]
     72
     73    itk_component add info {
     74        ::label $itk_interior.info -borderwidth 0 -width 5 \
     75            -anchor w -justify left
     76    }
     77
     78    itk_component add rmenu {
     79        menu $itk_interior.menu -tearoff 0
     80    } {
     81        usual
     82        ignore -tearoff
     83    }
     84    $itk_component(rmenu) add command \
     85        -label [Rappture::filexfer::label upload] \
     86        -command [itcl::code $this _uploadValue -start]
     87    $itk_component(rmenu) add command \
     88        -label [Rappture::filexfer::label download] \
     89        -command [itcl::code $this _downloadValue]
     90
     91
     92    if {[string length [label]] == 0} {
     93        # old mode -- big image
     94        pack $itk_component(image) -expand yes -fill both
     95        bind $itk_component(image) <Configure> [itcl::code $this _redraw]
     96    } else {
     97        # new mode -- thumbnail and details
     98        pack $itk_component(image) -side left
     99        pack $itk_component(info) -side left -expand yes -fill both -padx 4
     100
     101        bind $itk_component(image) <<PopupMenu>> \
     102            [list tk_popup $itk_component(rmenu) %X %Y]
     103        bind $itk_component(info) <<PopupMenu>> \
     104            [list tk_popup $itk_component(rmenu) %X %Y]
     105
     106        _redraw  ;# draw Empty image/info
     107    }
    63108
    64109    set str [$_owner xml get $path.current]
     
    114159        }
    115160        set _imh $imh
     161        set _data $newval
     162
    116163        _redraw
     164
    117165        return $newval
    118166
     
    124172    # Query the value and return.
    125173    #
    126     set data ""
    127     if {"" != $_imh} { set data [$_imh cget -data] }
    128     return $data
     174    set bytes $_data
     175    set fmt [$_owner xml get $_path.convert]
     176    if {"" != $fmt && "" != $_imh} {
     177        if {"pgm" == $fmt} { set fmt "ppm -grayscale" }
     178        set bytes [eval $_imh data -format $fmt]
     179        set bytes [Rappture::encoding::decode -as b64 $bytes]
     180    }
     181    return $bytes
    129182}
    130183
     
    164217itcl::body Rappture::ImageEntry::_redraw {} {
    165218    if {"" == $_imh} {
    166         $itk_component(image) configure -image ""
     219        # generate a big diagonal cross-hatch image
     220        set diag [Rappture::icon diag]
     221        set dw [image width $diag]
     222        set dh [image height $diag]
     223        $_resize configure -width $_thumbsize -height $_thumbsize
     224        for {set i 0} {$i < $_thumbsize/$dw+1} {incr i} {
     225            for {set j 0} {$j < $_thumbsize/$dh+1} {incr j} {
     226                set x [expr {$i*$dw}]
     227                set y [expr {$j*$dh}]
     228                $_resize copy $diag -to $x $y
     229            }
     230        }
     231        _outline $_resize black
     232        $itk_component(image) configure -image $_resize
     233        $itk_component(info) configure -text "Empty"
    167234        return
    168235    }
     
    172239    $itk_component(image) configure -image "" -width $iw -height $ih
    173240
     241    #
     242    # Build a description of the image if the info is showing.
     243    #
     244    set desc ""
     245    if {[string length [label]] != 0} {
     246        # if data is base64-encoded, try to decode it
     247        if {![regexp {^[a-zA-Z0-9+/=]+(\n[a-zA-Z0-9+/=]+)*$} $_data]
     248              || [catch {Rappture::encoding::decode -as b64 $_data} bytes]} {
     249            # oops! not base64 -- use data directly
     250            set bytes $_data
     251        }
     252        set desc [Rappture::utils::datatype $bytes]
     253        if {[string equal $desc "Binary data"]} {
     254            # generic description -- we can do a little better
     255            set iw [image width $_imh]
     256            set ih [image height $_imh]
     257            set desc "Image, ${iw} x ${ih}"
     258        }
     259        append desc "\n[Rappture::utils::binsize [string length $_data]]"
     260    }
     261    $itk_component(info) configure -text $desc
     262
     263    #
     264    # Put up the preview image, resizing if necessary.
     265    #
    174266    set str [string trim [$_owner xml get $_path.resize]]
    175267    if {"" == $str} {
     
    177269    }
    178270    switch -glob -- $str {
    179         auto {
    180             if {$_resize == ""} {
    181                 set _resize [image create photo]
    182             }
    183             set w [winfo width $itk_component(image)]
    184             set h [winfo height $itk_component(image)]
    185             if {$w/double($iw) < $h/double($ih)} {
    186                 set h [expr {round($w/double($iw)*$ih)}]
    187             } else {
    188                 set w [expr {round($h/double($ih)*$iw)}]
    189             }
    190             $_resize configure -width $w -height $h
    191             blt::winop resample $_imh $_resize
    192             $itk_component(image) configure -image $_resize
    193         }
    194271        width=* - height=* {
    195             if {$_resize == ""} {
    196                 set _resize [image create photo]
    197             }
    198272            if {[regexp {^width=([0-9]+)$} $str match size]} {
    199273                set w $size
    200274                set h [expr {round($w*$ih/double($iw))}]
    201275                $_resize configure -width $w -height $h
    202                 blt::winop resample $_imh $_resize
     276                $_resize blank
     277                blt::winop resample $_imh $_resize box
     278                _outline $_resize black
    203279                $itk_component(image) configure -image $_resize \
    204280                    -width $w -height $h
     
    207283                set w [expr {round($h*$iw/double($ih))}]
    208284                $_resize configure -width $w -height $h
    209                 blt::winop resample $_imh $_resize
     285                $_resize blank
     286                blt::winop resample $_imh $_resize box
     287                _outline $_resize black
    210288                $itk_component(image) configure -image $_resize \
    211289                    -width $w -height $h
     
    214292            }
    215293        }
     294        auto - none - default {
     295            if {[string length [label]] == 0} {
     296                # old mode -- big image with no label
     297                $itk_component(image) configure -image $_imh
     298            } else {
     299                # new mode -- thumbnail and image info
     300                set w $_thumbsize
     301                set h $_thumbsize
     302                $itk_component(image) configure -width $w -height $h
     303
     304                if {$iw <= $_thumbsize && $ih <= $_thumbsize} {
     305                    $_resize configure -width $iw -height $ih
     306                    $_resize copy $_imh
     307                    _outline $_resize black
     308                } else {
     309                    # large image -- scale it down
     310                    if {$iw > $ih} {
     311                        set h [expr {round($w/double($iw)*$ih)}]
     312                    } else {
     313                        set w [expr {round($h/double($ih)*$iw)}]
     314                    }
     315                    $_resize configure -width $w -height $h
     316                    $_resize blank
     317                    blt::winop resample $_imh $_resize box
     318                    _outline $_resize black
     319                }
     320                $itk_component(image) configure -image $_resize
     321            }
     322        }
     323    }
     324}
     325
     326# ----------------------------------------------------------------------
     327# USAGE: _outline <image> <color>
     328#
     329# Used internally to outline the given <image> with a single-pixel
     330# line of the specified <color>.  Updates the image in place.
     331# ----------------------------------------------------------------------
     332itcl::body Rappture::ImageEntry::_outline {im color} {
     333    if {"" != $im} {
     334        set w [image width $im]
     335        set h [image height $im]
     336        $im put $color -to 0 0 $w 1
     337        $im put $color -to 0 0 1 $h
     338        $im put $color -to 0 [expr {$h-1}] $w $h
     339        $im put $color -to [expr {$w-1}] 0 $w $h
     340    }
     341}
     342
     343# ----------------------------------------------------------------------
     344# USAGE: _uploadValue -start
     345# USAGE: _uploadValue -assign <key> <value> <key> <value> ...
     346#
     347# Used internally to initiate an upload operation.  Prompts the
     348# user to upload into the image area of this widget.
     349# ----------------------------------------------------------------------
     350itcl::body Rappture::ImageEntry::_uploadValue {args} {
     351    set opt [lindex $args 0]
     352    switch -- $opt {
     353        -start {
     354            set tool [Rappture::Tool::resources -appname]
     355            set cntls [list $_path [label] [tooltip]]
     356            Rappture::filexfer::upload \
     357                $tool $cntls [itcl::code $this _uploadValue -assign]
     358        }
     359        -assign {
     360            array set data [lrange $args 1 end] ;# skip option
     361            if {[info exists data(error)]} {
     362                Rappture::Tooltip::cue $itk_component(image) $data(error)
     363            }
     364            if {[info exists data(data)]} {
     365                Rappture::Tooltip::cue hide  ;# take down note about the popup
     366                if {[catch {value $data(data)} err]} {
     367                    Rappture::Tooltip::cue $itk_component(image) "Upload failed:\n$err"
     368                }
     369            }
     370        }
    216371        default {
    217             $itk_component(image) configure -image $_imh
    218         }
     372            error "bad option \"$opt\": should be -start or -assign"
     373        }
     374    }
     375}
     376
     377# ----------------------------------------------------------------------
     378# USAGE: _downloadValue
     379#
     380# Used internally to initiate a download operation.  Takes the current
     381# value and downloads it to the user in a new browser window.
     382# ----------------------------------------------------------------------
     383itcl::body Rappture::ImageEntry::_downloadValue {} {
     384    set bytes [Rappture::encoding::decode -as b64 [$_imh data -format png]]
     385    set mesg [Rappture::filexfer::download $bytes image.png]
     386
     387    if {"" != $mesg} {
     388        Rappture::Tooltip::cue $itk_component(image) $mesg
    219389    }
    220390}
Note: See TracChangeset for help on using the changeset viewer.