#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"

# This example is a bit more complex application with many different
# widgets. It shows especially the use of the canvas widget.
# It's only ment as demonstration of the different widgets, not as
# example of good, ergonomic GUI design :-)

# FIXME: only scalable fonts allowed

load ../src/gnocl.so

# current colors as global variables 
set fillColor blue
set outlineColor blue

# other examples, which are sourced (and therfor executed)
proc exec-examples {} {
   set box [gnocl::box -orientation vertical -buttonType 1]
   set top [gnocl::window -title "Execute examples" -child $box -modal 0]

   $box add [gnocl::button -text "Simple example" \
         -command "source mini.tcl"]
   $box add [gnocl::button -text "different widgets" \
         -command "source widgets.tcl"]
   $box add [gnocl::button -text "text widget" \
         -command "source text.tcl"]
   $box add [gnocl::button -text "all stock items" \
         -command "source allstock.tcl"]
   $box add [gnocl::button -text "entry" \
         -command "source entry.tcl"]
   $box add [gnocl::button -text "dialog" \
         -command "source dialog.tcl"]
   $box add [gnocl::button -text "canvas lines" \
         -command "source canvasLines.tcl"]
   $box add [gnocl::button -text "canvas text" \
         -command "source canvasText.tcl"]
   $box add [gnocl::button -text "%#Close" \
         -command "$top delete"] 
}

# make menus
# File menu
set menu [gnocl::menu]
$menu add [gnocl::menuItem label -text "%#_New"]
$menu add [gnocl::menuItem separator]
$menu add [gnocl::menuItem label -text "%#_Quit" -command exit]
set file [gnocl::menuItem label -text "%__File" -submenu $menu]

# Edit menu
set menu [gnocl::menu]
foreach {el acc} {flash "<control>F" message "<alt>M" 
      warning "<shift><control>A" error "" } {
   $menu add [gnocl::menuItem label -text "%__$el" -command \
         "\$app $el \"$el text\"" -accelerator $acc]
}
$menu add [gnocl::menuItem label -text %__progess -command \
      {
         for { set k 0 } { $k < 100 } { set k [expr {$k+1}]} {
            $app progress $k; gnocl::update; after 10 
         }
         $app progress 0
      }]

set edit [gnocl::menuItem label -text "%__Edit" -submenu $menu]

# Help menu
set menu [gnocl::menu]
$menu add [gnocl::menuItem label -text "%#_About" -command {
      gnocl::about -title "Gnocl Test Application" \
      -authors {{P.G. Baum (peter@dr-baum.net)}} -version [gnocl::info version] \
      -copyright "(c) 2001 - 2002 P.G. Baum" \
      -comments "gtk version: [gnocl::info gtkVersion]" }]
set help [gnocl::menuItem label -text "%__Help" -submenu $menu]


# add all menus to main menu bar
set menubar [gnocl::menubar]
$menubar add [list $file $edit $help]

set statusbar [gnocl::appBar]

# main toolbar
set toolbar [gnocl::toolbar -style both]
$toolbar add item -text "Clear" -icon "%#Clear" -tooltip "Clear canvas" \
      -tooltip_private "Tooltip_private new" \
      -command {$canvas itemDelete all}
$toolbar add item -text "Exec" -icon "%#Exec" -tooltip "Execute examples" \
             -tooltip_private "Tooltip_private Exec" -command exec-examples
$toolbar addBegin space
$toolbar addBegin item -text "Quit" -icon "%#Quit" \
      -tooltip "Exit application" -command exit

# $toolbar add space
# $toolbar add item -text "Save" -icon "%#Save" -tooltip "Tooltip Save" \
#             -tooltip_private "Tooltip_private Save"

set box [gnocl::box -orientation vertical -homogeneous 0]
set app [gnocl::app testApp -title "Gnocl Test Application" \
      -menubar $menubar -statusbar $statusbar -toolbar $toolbar \
      -contents $box]

# second toolbar
proc fillTransparent { cpwidget transp } {
   $cpwidget configure -sensitive [expr {$transp?0:1}]
   set alpha [expr {$transp?0:65535}]
   set ::fillColor [lreplace [$cpwidget getColor] 3 3 $alpha]
}

set toolbar [gnocl::toolbar]
set colorPicker [gnocl::colorPicker -variable fillColor \
      -title "Select the fill color"]
$toolbar add widget [gnocl::label -text "%_f_ill color " \
      -bindUnderline $colorPicker]
$toolbar add widget [gnocl::checkButton -text "%_t_ransparent" \
      -command "fillTransparent $colorPicker %v"]
$toolbar add widget $colorPicker
$toolbar add space
set colorPicker [gnocl::colorPicker -variable outlineColor \
      -title "Select the outline color"]
$toolbar add widget [gnocl::label -text "%__outline color " \
      -bindUnderline $colorPicker]
$toolbar add widget $colorPicker
$toolbar add space
# font is automatically set to default font
set fontPicker [gnocl::fontPicker -variable font]
$toolbar add widget [gnocl::label -text "%_fo_nt " -bindUnderline $fontPicker]
$toolbar add widget $fontPicker
$app addToolbar $toolbar -name "Color and Font" -bandNum 2 

set hbox [gnocl::box -orientation horizontal -homogeneous 0]
$box add [list $hbox \
      [gnocl::label -text "Please click in the canvas below"]] -expand 0
set ::b2Action Move
set ::drawItem Line
set itemsWidget [gnocl::combo -variable drawItem -editable 0 \
      -strings {Line Rectangle Ellipse Text}]
set actionWidget [gnocl::combo -variable b2Action \
      -strings {Move Scale Rotate} -editable 0]
$hbox add [list \
      [gnocl::label -text "%_ B_1: " -bindUnderline $itemsWidget] \
      $itemsWidget \
      [gnocl::label -text "%_ B_2: " -bindUnderline $actionWidget] \
      $actionWidget] -expand 0 -fill 0

set canvas [gnocl::canvas -antialiased 1 -width 300 -height 200]
$box add $canvas

proc defaultCanvasBindings { } {
   # gnocl::bind $canvas "enter" [list puts "entering x: %x y: %y"]
   # gnocl::bind $canvas "leave" [list puts "leaving x: %x y: %y"]
   gnocl::bind $::canvas "button" [list canvasButton $::canvas %x %y %b]
   gnocl::bind $::canvas "motion" ""
   gnocl::bind $::canvas "buttonRelease" ""
}

defaultCanvasBindings

# different procs which are called if mouse point is over one item
# or mouse button is pressed
proc enterItem { item x y } {
   puts "enter: $item"
   $::canvas move $item {10 10}
   # $::canvas itemConfigure $item -fill red
}
proc leaveItem { item x y } {
   puts "leave $item"
   $::canvas itemConfigure $item -fill $::fillColor
}

proc configLine {win x y item } {
   foreach {x y} [$win windowToWorld [list $x $y]] break
   $win itemConfigure $item \
         -coords [lreplace $::lineCoords end-1 end $x $y]
}
proc lineAddPoint {win x y but item } {
   if { $but == 1 } {
      foreach {x y} [$win windowToWorld [list $x $y]] break
      set ::lineCoords [lreplace $::lineCoords end-1 end $x $y $x $y]
      $win itemConfigure $item -coords $::lineCoords
   } 
}
proc lineEndPoint {win but item } {
   if { $but != 1 } {
      if { [llength $::lineCoords] == 4 } {
         $win itemDelete $item
      } else {
         $win itemConfigure $item -coords [lrange $::lineCoords 0 end-2]
      }
      defaultCanvasBindings
   }
}

proc configRect {win x y item x0 y0 } {
   foreach {x y} [$win windowToWorld [list $x $y]] break
   set r [expr {sqrt(pow($x-$x0,2)+pow($y-$y0,2))}]
   $win itemConfigure $item -centerRadius 1 -coords \
         [list $x0 $y0 [expr {abs($x-$x0)}] [expr {abs($y-$y0)}]]
}
proc configEllipse {win x y item x0 y0 } {
   foreach {x y} [$win windowToWorld [list $x $y]] break
   set r [expr {sqrt(pow($x-$x0,2)+pow($y-$y0,2))}]
   $win itemConfigure $item -centerRadius 1 -coords [list $x0 $y0 $r]
}
proc moveItem {win x y item x0 y0 } {
   foreach {x y} [$win windowToWorld [list $x $y]] break
   $win move $item [list [expr {$x-$x0}] [expr {$y-$y0}]]
   gnocl::bind $win "motion" "moveItem $win %x %y $item $x $y"
}
proc scaleItem {win x y item x0 y0 {lastX 1.} {lastY 1.} } {
   foreach {x y} [$win windowToWorld [list $x $y]] break
   set sensitivity 10.
   set xscale [expr {exp(($x-$x0)/$sensitivity)}]
   set yscale [expr {exp(($y-$y0)/$sensitivity)}]
   $win scale $item \
         [list $x0 $y0 [expr {$xscale/$lastX}] [expr {$yscale/$lastY}]]
   gnocl::bind $win "motion" \
         "scaleItem $win %x %y $item $x0 $y0 $xscale $yscale"
}
proc printCoords { win item } {
   foreach {x1 y1 x2 y2} [$win getBounds $item] break
   set xm [expr {($x2+$x1)/2.}]
   set ym [expr {($y2+$y1)/2.}]
   puts "x1: $x1 y1: $y1 x2: $x2 y2: $y2 xm: $xm ym $ym"
}
proc rotateItem {win x y item x0 y0 {last 0} } {
   foreach {x y} [$win windowToWorld [list $x $y]] break
   foreach {x1 y1 x2 y2} [$win getBounds $item] break
   set xm [expr {($x2+$x1)/2.}]
   set ym [expr {($y2+$y1)/2.}]
   set w0 [expr {atan2($x0-$xm,$y0-$ym)}]
   set w [expr {atan2($x-$xm,$y-$ym)-$w0}]
   set ws [expr {-$w+$last}]
   $win rotate $item [list $xm $ym $ws]
   gnocl::bind $win "motion" \
         "rotateItem $win %x %y $item $x0 $y0 $w"
}

#   rotate with affine 
#   $win move $item [list [expr {-$xm}] [expr {-$ym}]]
#   set af [list [expr {cos($ws)}] [expr {sin($ws)}] \
#               [expr {-sin($ws)}] [expr {cos($ws)}] \
#               [expr {0}] [expr {0}]]
#   $win affine $item $af
#   $win move $item [list $xm $ym]

proc canvasButton {win x y but } {
   foreach {x y} [$win windowToWorld [list $x $y]] break
   if { $but == 1 } {
      switch -exact $::drawItem {
         Line        {  set ::lineCoords [list $x $y $x $y]
                        set item [$win create line $::lineCoords \
                              -fill $::fillColor -width 3 -arrow both \
                              -arrowShape {5 10 5} \
                              -capStyle but -joinStyle round]
                        gnocl::bind $win "motion" \
                              "configLine $win %x %y $item"
                        gnocl::bind $win "buttonPress" \
                              "lineAddPoint $win %x %y %b $item"
                        gnocl::bind $win "buttonRelease" \
                              "lineEndPoint $win %b $item"
                     }
         Ellipse     {  set item [$win create ellipse [list $x $y 1] \
                              -centerRadius 1 -fill $::fillColor \
                              -outline $::outlineColor -width 3]
                        gnocl::bind $win "motion" \
                              "configEllipse $win %x %y $item $x $y"
                        gnocl::bind $win "buttonRelease" \
                              defaultCanvasBindings
                     }
         Rectangle   {  set item [$win create rectangle [list $x $y 1] \
                              -centerRadius 1 -fill $::fillColor \
                              -outline $::outlineColor -width 3]
                        gnocl::bind $win "motion" \
                              "configRect $win %x %y $item $x $y"
                        gnocl::bind $win "buttonRelease" \
                              defaultCanvasBindings
                     }
         Text        {  set item [$win create text [list $x $y] \
                              -label "gnocl" -fill $::fillColor -font $::font]
                     }
      }
      # puts "new $item"
      gnocl::bind $item "enter" \
            [list $::app flash "entered $::drawItem $item @(%x,%y)"]
   } elseif { $but == 2 } {
      set item [$win findItemAt $x $y]
      if { $item != "" } {
         switch -exact $::b2Action {
            Move  { gnocl::bind $win "motion" \
                           "moveItem $win %x %y $item $x $y" }
            Scale { gnocl::bind $win "motion" \
                           "scaleItem $win %x %y $item $x $y" }
            Rotate { gnocl::bind $win "motion" \
                           "rotateItem $win %x %y $item $x $y" }
         }
         gnocl::bind $win "buttonRelease" defaultCanvasBindings
      }
   }
}

proc createEllipse {win x y but } {
   if { [catch {
      foreach {x y} [$win windowToWorld [list $x $y]] break
      switch -exact $but {
         1  { set item [$win create ellipse [list $x $y 10] \
                     -centerRadius 1 -fill $::fillColor \
                     -outline $::outlineColor] }
         2  { set item [$win create ellipse [list $x $y 25] \
                     -centerRadius 1 -fill $::fillColor \
                     -outline $::outlineColor -width 3] }
         3  { set item [$win create ellipse [list $x $y \
                     [expr {$x+5.}] [expr {$y+5.}]] ] }
      }
      # $::app flash "creating $item at $x $y"
      gnocl::bind $item "enter" [list $::app flash "enterItem $item %x %y"]
      # gnocl::bind $item "leave" "leaveItem $item %x %y"
   } erg] } {
      $::app error "in createEllipse:\n$erg"
   }
}
if { [info exists tk_patchLevel] } {
   wm withdraw .
} else {
   gnocl::mainLoop
}

