SR Technology WTK Repo
Check-in [bb947dbc82]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Added oval, circle, and arc types to the canvas/wtk.js Modified the "graft" keyword such that calling the method of a graft with no arguments returns the object The wtk widget classes now fall back to the traditional unknown handler if the first argument does not look like a tkpath
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:bb947dbc8225e786946e847ceb8fb403baeb1891
User & Date: seandeelywoods 2013-02-12 20:29:02
Context
2013-02-12
20:55
Further fixes for the canvas Added different shapes to the sketch demo check-in: 0b61c414a1 user: seandeelywoods tags: trunk
20:29
Added oval, circle, and arc types to the canvas/wtk.js Modified the "graft" keyword such that calling the method of a graft with no arguments returns the object The wtk widget classes now fall back to the traditional unknown handler if the first argument does not look like a tkpath check-in: bb947dbc82 user: seandeelywoods tags: trunk
15:35
Removed several debugging puts statements Fixed some snitizisms I had missed in the canvas implementation. Rather than use delegation to re-use the "event_fire" method, I've simply created an object_event_fire method for the canvas to distinguish between widget bindings and canvas object bindings check-in: b88021946e user: seandeelywoods tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to lib/wtk-base.tcl.

94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
        

        class_method unknown {objname args} {
          if {[string index $objname 0] eq "."} {
            my create ::$objname $objname {*}$args
            return $objname
          }
          error "Unknown method $objname. Valid: [info class methods [info object class [self]]]"
        }

        class_method option args {
          puts "Option $args"
        }

        method property_set {propertyKey value} {







|







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
        

        class_method unknown {objname args} {
          if {[string index $objname 0] eq "."} {
            my create ::$objname $objname {*}$args
            return $objname
          }
          next $objname {*}$args
        }

        class_method option args {
          puts "Option $args"
        }

        method property_set {propertyKey value} {

Changes to odie/moac.tcl.

245
246
247
248
249
250
251



252







253
254
255
256
257
258
259
260
  # topic: e1c1cccb-5201-997d-e0c5-4e04394b61e2
  ###
  method graft args {
    my variable organs
    foreach {stub object} $args {
      set stub [string trimleft $stub /]
      logicset add organs $stub



      my put [list $stub $object]







      my forward ${stub} $object
      # Provide a more standard "/->object" stub
      #my forward /${stub} $object
    }
  }

  ###
  # topic: df00845e-dcbf-6f93-65b9-ee824513102a







>
>
>

>
>
>
>
>
>
>
|







245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
  # topic: e1c1cccb-5201-997d-e0c5-4e04394b61e2
  ###
  method graft args {
    my variable organs
    foreach {stub object} $args {
      set stub [string trimleft $stub /]
      logicset add organs $stub
      ###
      # For backward compadibility
      ###
      my put [list $stub $object]
      set body [string map [list %OBJECT% $object] {
        if {[llength $args]==0} {
          return %OBJECT%
        }
        return [%OBJECT% {*}$args]
      }]
      oo::objdefine [self] method $stub args $body 
      #my forward ${stub} $object
      # Provide a more standard "/->object" stub
      #my forward /${stub} $object
    }
  }

  ###
  # topic: df00845e-dcbf-6f93-65b9-ee824513102a

Changes to widgets/canvas.tcl.

1
2
3
4
5
6

7
8

9

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33



34













35
36




37
38
39
40
41
42
43
..
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

# Canvas
odie::class ::wtk::canvas {
  superclass wtk::Widget

  property itemtypes "line rectangle"

  property opts.line {-fill strokeStyle -width lineWidth}
  property opts.rectangle {-fill fillStyle -width lineWidth -outline strokeStyle}



  _wtkoption -width 100 {$JS.width=$V;$JS.style.width='${V}px';}
  _wtkoption -height 100 {$JS.height=$V;$JS.style.height='${V}px';}
  _wtkoption -background "#ffffff" {$JS.style.background='$V';}

  variable mousedown 0
  variable nextid 1
  variable items
  
  constructor args {
    set path [next {*}$args]
    my variable nextid mousedown items
    set nextid 1
    set mousedown 0
    
    return $path
  }
  
  method do_createjs {} {return "wtk.createCanvas('[my id]');"}
  
  method create {itemtype args} {
    my variable nextid
    if {$itemtype ni [my property itemtypes]} {error "bad item type"}
    lassign [my _parseCoordsAndOptions $args [my property opts.$itemtype]] coords opts
    set cid $nextid



    incr nextid













    set items($cid) [list type $itemtype coords $coords]
    ::wtk::toclient "wtk.objs\['[my id]'\].createItem($cid,'$itemtype',\[[join $coords ,]\],$opts);"




    return $cid
  }
  
  method wtk_event {which args} {
      # todo - make generic
      my variable mousedown
      if {$which=="mousedown"} {
................................................................................
        my event_fire $ev [list %x [lindex $args 0] %y [lindex $args 1]]
      }
      if {$which=="mouseup"} {
        set mousedown 0
        my event_fire "<B1-Release>" [list %x [lindex $args 0] %y [lindex $args 1]]
      }
  }
  
  method _parseCoordsAndOptions {s optmap} {
      set coords ""; set inopts 0; set opts ""
      foreach {x y} [split $s] {
          if {!$inopts && [string is integer $x]} {
              if {![string is integer $y]} {error "odd number of coordinates"}
              lappend coords $x $y
          } else {
              set inopts 1
              if {![dict exists $optmap $x]} {error "bad option"}
              lappend opts "[dict get $optmap $x]:\"$y\""
          }
      }
      return [list $coords "\{[join $opts ,]\}"]
  }

  variable bindings
  
  method bind {id ev script} {set bindings(${id},$ev) $script}
  
  method object_event_fire {id ev subs} {
    if {[info exists bindings(${id},$ev)]} {
      uplevel #0 [string map $subs $bindings(${id},$ev)]
    }
  }
}






|
>
|
|
>
|
>











|

<





|

|
|
|
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
>
>
>
>







 







|
<
<
<
<
<
<
<
<
<
<
<
<
<
<












1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

54
55
56
57
58
59
60
61
62
63
64
..
78
79
80
81
82
83
84
85














86
87
88
89
90
91
92
93
94
95
96
97

# Canvas
odie::class ::wtk::canvas {
  superclass wtk::Widget

  property itemtypes {
    circle    {-fill fillStyle -width lineWidth -outline strokeStyle}
    line      {-fill strokeStyle -width lineWidth}
    rectangle {-fill fillStyle -width lineWidth -outline strokeStyle}
    oval      {-fill fillStyle -width lineWidth -outline strokeStyle} 
  }
  
  _wtkoption -width 100 {$JS.width=$V;$JS.style.width='${V}px';}
  _wtkoption -height 100 {$JS.height=$V;$JS.style.height='${V}px';}
  _wtkoption -background "#ffffff" {$JS.style.background='$V';}

  variable mousedown 0
  variable nextid 1
  variable items
  
  constructor args {
    set path [next {*}$args]
    my variable nextid mousedown items
    set nextid 0
    set mousedown 0

    return $path
  }
  
  method do_createjs {} {return "wtk.createCanvas('[my id]');"}
  
  method create {itemtype coords args} {
    my variable nextid
    set itemtypes [my property itemtypes]
    if {![dict exists $itemtypes $itemtype]} {
      error "bad item type: $itemtype. Valid: [dict keys $itemtypes]"
    }
    if [catch {
    set optmap [dict get $itemtypes $itemtype]
    set cid [incr nextid]
    if {[llength $coords]==1} {
      set idx -1
      while {[string is double [lindex $args [incr idx]]]} {
        lappend coords [lindex $args $idx]
      }
      set args [lrange $args $idx end]
    }
    foreach {var val} $args {
      if {![dict exists $optmap $var]} {error "bad option $var"}
      lappend opts "[dict get $optmap $var]:\"$val\""
    }
    set create_js "wtk.objs\['[my id]'\].createItem($cid,'$itemtype',\[[join $coords ,]\],\{[join $opts ,]\});"
    wtk::toclient $create_js
    set items($cid) [list type $itemtype coords $coords options $opts]

    } err] {
       puts $err
       puts $::errorInfo
    }
    return $cid
  }
  
  method wtk_event {which args} {
      # todo - make generic
      my variable mousedown
      if {$which=="mousedown"} {
................................................................................
        my event_fire $ev [list %x [lindex $args 0] %y [lindex $args 1]]
      }
      if {$which=="mouseup"} {
        set mousedown 0
        my event_fire "<B1-Release>" [list %x [lindex $args 0] %y [lindex $args 1]]
      }
  }
















  variable bindings
  
  method bind {id ev script} {set bindings(${id},$ev) $script}
  
  method object_event_fire {id ev subs} {
    if {[info exists bindings(${id},$ev)]} {
      uplevel #0 [string map $subs $bindings(${id},$ev)]
    }
  }
}

Changes to widgets/wtk.js.

175
176
177
178
179
180
181


182
183
184
185
186
187
188
...
193
194
195
196
197
198
199


200





201













































202
203
204
205
206
207
208
        w.ondrag = function(ev) {self.handleMouse(ev, 'drag');}

        this.createItem = function(cid, type, coords, opts) {
            var o = {'cid':cid,'type':type,'coords':coords,'opts':opts};
            this.items.push(o);
            this.scheduleDraw();
        }



        this.scheduleDraw = function() {if (this.drawtimer==null) {var self=this;this.drawtimer = setTimeout(function() {self.draw()}, 100)}}

        this.draw = function() {
            var self = this;
            this.drawtimer = null;
            var ctx = this.context;
................................................................................

        this.drawItem = function(ctx,i,color) {
            ctx.beginPath();
            ctx.strokeStyle='#000000'; if ('strokeStyle' in i.opts && color!='black') {ctx.strokeStyle = i.opts['strokeStyle'];}
            ctx.fillStyle='#000000'; if ('fillStyle' in i.opts && color!='black') {ctx.fillStyle = i.opts['fillStyle'];}
            ctx.lineWidth = 3; if ('lineWidth' in i.opts) {ctx.lineWidth = i.opts['lineWidth'];}
            ctx.lineCap = 'round';


            if (i.type=="line") {ctx.moveTo(i.coords[0],i.coords[1]); for (var j=2;j<i.coords.length;j+=2) {ctx.lineTo(i.coords[j],i.coords[j+1]);};ctx.stroke();}





            if (i.type=="rectangle") {ctx.fillRect(i.coords[0],i.coords[1],i.coords[2]-i.coords[0],i.coords[3]-i.coords[1]);}













































        }

        this.itemAt = function(x,y) {
            /* use a 'ghost canvas' - see http://simonsarris.com/blog/140-canvas-moving-selectable-shapes */
            if (this.ghostcanvas==null) {this.ghostcanvas = document.createElement('canvas');this.gctx = null;}
            if (this.ghostcanvas.width!=this.w.width || this.ghostcanvas.height!=this.w.height) {
                this.ghostcanvas.width = this.w.width; this.ghostcanvas.height = this.w.height; this.gctx = null;







>
>







 







>
>
|
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
        w.ondrag = function(ev) {self.handleMouse(ev, 'drag');}

        this.createItem = function(cid, type, coords, opts) {
            var o = {'cid':cid,'type':type,'coords':coords,'opts':opts};
            this.items.push(o);
            this.scheduleDraw();
        }



        this.scheduleDraw = function() {if (this.drawtimer==null) {var self=this;this.drawtimer = setTimeout(function() {self.draw()}, 100)}}

        this.draw = function() {
            var self = this;
            this.drawtimer = null;
            var ctx = this.context;
................................................................................

        this.drawItem = function(ctx,i,color) {
            ctx.beginPath();
            ctx.strokeStyle='#000000'; if ('strokeStyle' in i.opts && color!='black') {ctx.strokeStyle = i.opts['strokeStyle'];}
            ctx.fillStyle='#000000'; if ('fillStyle' in i.opts && color!='black') {ctx.fillStyle = i.opts['fillStyle'];}
            ctx.lineWidth = 3; if ('lineWidth' in i.opts) {ctx.lineWidth = i.opts['lineWidth'];}
            ctx.lineCap = 'round';
            if (i.type=="line") {
              ctx.moveTo(i.coords[0],i.coords[1]);
              for (var j=2;j<i.coords.length;j+=2) {
                ctx.lineTo(i.coords[j],i.coords[j+1]);
              };
              ctx.stroke();
            }
            if (i.type=="rectangle") {
              ctx.fillRect(i.coords[0],i.coords[1],i.coords[2]-i.coords[0],i.coords[3]-i.coords[1]);
              ctx.stroke();
            }
            if (i.type=="circle") {
              var x=i.coords[0];
              var y=i.coords[1];
              var r=i.coords[2];
              ctx.arc(x,y,r,0,Math.PI*2,false);
              ctx.fill();
              ctx.stroke();
            }
            if (i.type=="arc") {
              ctx.arc(i.coords[0],i.coords[1],i.coords[2],i.coords[3],i.coords[4],false);
              ctx.fill();
              ctx.stroke();
            }
            if (i.type=="oval") {       
              var x=i.coords[0];
              var y=i.coords[1];
              var w=(i.coords[2]-i.coords[0]);
              var h=(i.coords[3]-i.coords[1]);
              var xm=w/2.0+i.coords[0];
              var ym=h/2.0+i.coords[1];
              if ( w==h ) {
                /* Render a circle as a circle */
                ctx.arc(xm,ym,w/2,Math.PI*2,false);
              } else {
                var kappa = .5522848;
                ox = (w / 2) * kappa, // control point offset horizontal
                oy = (h / 2) * kappa, // control point offset vertical
                xe = x + w,           // x-end
                ye = y + h,           // y-end
                xm = x + w / 2,       // x-middle
                ym = y + h / 2;       // y-middle
  
                ctx.beginPath();
                ctx.moveTo(x, ym);
                ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
                ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
                ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
                ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
                ctx.closePath();
              }
              ctx.fill();
              ctx.stroke();
            }
        }

        this.itemAt = function(x,y) {
            /* use a 'ghost canvas' - see http://simonsarris.com/blog/140-canvas-moving-selectable-shapes */
            if (this.ghostcanvas==null) {this.ghostcanvas = document.createElement('canvas');this.gctx = null;}
            if (this.ghostcanvas.width!=this.w.width || this.ghostcanvas.height!=this.w.height) {
                this.ghostcanvas.width = this.w.width; this.ghostcanvas.height = this.w.height; this.gctx = null;