Version 0 of create triangle image

Updated 2010-11-25 17:20:13 by oehhar

Create triangle image dynamically

On a image create photo, a triangle of various dimensions may be painted on demand. The aim is to replace the BWidget ArrowButton by a ttk::button and a dynamically generated image.

The triangle is painted with the given foreground color on transparent background.

Example

image create photo i -width 30 -height 30
arrowimage i up
pack [ttk::button .l -image i -style Toolbutton]

created triangle image sample

Invocation

arrowimage

photoCmdThe command name of an image, as given to the image create photo command
dirDirection of the arrow. One of top,right, bottom or left
ipadxEmpty pixels around the image on the left and right of the image
ipadyEmpty pixels around the image on the top and bottom of the image
cleanSame as BWidget Arrowbutton clean parameter
foregroundThe foreground color of the arrow

Code

proc arrowimage { photoCmd dir {ipadx 0} {ipady 0} {clean 0} {foreground black} } {
    
    set width [$photoCmd cget -width]
    set height [$photoCmd cget -height]
    # w and h are max width and max height of arrow
    set w [expr {$width  - 2*$ipadx}]
    set h [expr {$height - 2*$ipady}]

    if { $w < 2 } {set w 2}
    if { $h < 2 } {set h 2}

    if { $clean > 0 } {
        # arrange for base to be odd
        if { [string equal $dir "top"] || [string equal $dir "bottom"] } {
            if { !($w % 2) } {
                incr w -1
            }
            if { $clean == 2 } {
                # arrange for h = (w+1)/2
                set h2 [expr {($w+1)/2}]
                if { $h2 > $h } {
                    set w [expr {2*$h-1}]
                } else {
                    set h $h2
                }
            }
        } else {
            if { !($h % 2) } {
                incr h -1
            }
            if { $clean == 2 } {
                # arrange for w = (h+1)/2
                set w2 [expr {($h+1)/2}]
                if { $w2 > $w } {
                    set h [expr {2*$w-1}]
                } else {
                    set w $w2
                }
            }
        }
    }

    set x0 [expr {($width-$w)/2}]
    set y0 [expr {($height-$h)/2}]
    set x1 [expr {$x0+$w-1}]
    set y1 [expr {$y0+$h-1}]
    # > Make the frame transparent and the inside with a square
    for {set y 0} {$y < $y0} {incr y} {
        for {set x 0} {$x < $height} {incr x} {
            $photoCmd transparency set $x $y 1
        }
    }
    for {set y [expr {$y1+1}]} {$y < $height} {incr y} {
        for {set x 0} {$x < $height} {incr x} {
            $photoCmd transparency set $x $y 1
        }
    }
    for {set y $y0} {$y <= $y1} {incr y} {
        for {set x 0} {$x < $x0} {incr x} {
            $photoCmd transparency set $x $y 1
        }
    }
    for {set y $y0} {$y <= $y1} {incr y} {
        for {set x [expr {$x1+1}]} {$x < $width} {incr x} {
            $photoCmd transparency set $x $y 1
        }
    }
    $photoCmd put $foreground -to $x0 $y0 [expr {$x1+1}] [expr {$y1+1}]
    # > Paint triangles as transparency
    switch $dir {
        top - bottom {
            set h0 $x0
            set h1 $x1
            set v0 $y0
            set v1 $y1
            # > On even size move right limit one to right
            set e1 [expr {($w % 2 == 0)?1:0}]
            set fHorX 1
        }
        default {
            set h0 $y0
            set h1 $y1
            set v0 $x0
            set v1 $x1
            # > On even size move right limit one to right
            set e1 [expr {($h % 2 == 0)?1:0}]
            set fHorX 0
        }
    }
    switch $dir {
        top - left {
            set corVert $v0
            set DCorVert 1
        }
        default {
            set corVert $v1
            set DCorVert -1
        }
    }
    set m [expr {($h0+$h1)/2}]
    set DHor [expr {$h1 - $m}]
    set DVert [expr {$v1 - $v0}]
    set d 0
    set r 0
    for {set vertLoop 0} {$vertLoop < $DVert} {incr vertLoop} {
        set limitHor [expr {$m - $d}]
        for {set horLoop 0} {$horLoop < $limitHor} {incr horLoop} {
            $photoCmd transparency set\
                    [expr {$fHorX?$horLoop:$corVert}]\
                    [expr {$fHorX?$corVert:$horLoop}] 1
        }
        set limitHor [expr {$m + $d + 1 + $e1}]
        for {set horLoop $limitHor} {$horLoop <= $h1} {incr horLoop} {
            $photoCmd transparency set\
                    [expr {$fHorX?$horLoop:$corVert}]\
                    [expr {$fHorX?$corVert:$horLoop}] 1
        }
        incr corVert $DCorVert
        incr r $DHor
        incr d [expr { $r / $DVert } ]
        set r [expr { $r % $DVert}]
    }
}