SR Technology WTK Repo
Check-in [04e9c7f911]
Not logged in

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

Overview
Comment:Add logging methods.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:04e9c7f911db3eda6687b5b39156f79c54537fe3
User & Date: gerald 2013-02-05 02:15:26
Context
2013-02-12
15:13
Ported code to TclOO. Demos all work. Integrated the Odie package to extend TclOO and add extra keywords and to make TclOO more snitlike. check-in: 833107b47e user: seandeelywoods tags: trunk
14:57
Merging in changes from trunk check-in: 1cf1e20494 user: seandeelywoods tags: hypnotoad
2013-02-05
02:15
Add logging methods. check-in: 04e9c7f911 user: gerald tags: trunk
2013-01-22
18:31
Corrected mime type for CSS. check-in: bd8435682a user: gerald tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to lib/wtk-base.tcl.

4
5
6
7
8
9
10

11
12
13
14
15
16
17
..
32
33
34
35
36
37
38



39






40
41
42
43
44
45
46
# are interpreted and used to update internal widget state here, which often triggers
# callbacks or other event bindings.
#
# Communication with the client is solely via the "fromclient" and "toclient" routines
# (the latter of which is setup in the wtk::init call).

package require snit


namespace eval ::wtk {
    variable widgets
    variable wobj
    variable _nextid -1
    variable _sender ""

................................................................................
        GridState _reset
        init $_sender
        return ""
    }

    proc toclient {cmd} {uplevel #0 $wtk::_sender [list $cmd]}




    proc fromclient {cmd} {if {[lindex $cmd 0]=="EVENT"} {[getwidget [lindex $cmd 1]] _event {*}[lrange $cmd 2 end]}}








    # 'Generic' widget object, which handles routines common to all widgets like
    # assigning it an id, keeping track of whether or not its been created, etc.
    # Purely for convenience, we also include some code here that manages widgets
    # that use -text or -textvariable, though not every widget will do so.








>







 







>
>
>
|
>
>
>
>
>
>







4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
..
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# are interpreted and used to update internal widget state here, which often triggers
# callbacks or other event bindings.
#
# Communication with the client is solely via the "fromclient" and "toclient" routines
# (the latter of which is setup in the wtk::init call).

package require snit
package require log

namespace eval ::wtk {
    variable widgets
    variable wobj
    variable _nextid -1
    variable _sender ""

................................................................................
        GridState _reset
        init $_sender
        return ""
    }

    proc toclient {cmd} {uplevel #0 $wtk::_sender [list $cmd]}

    proc fromclient {cmd} {
        switch -exact -- [lindex $cmd 0] {
            "EVENT" {
                [getwidget [lindex $cmd 1]] _event {*}[lrange $cmd 2 end]
            }
            "LOG" {
                ::log::log [lindex $cmd 1] [lrange $cmd 2 end]
            }
        }
    }


    # 'Generic' widget object, which handles routines common to all widgets like
    # assigning it an id, keeping track of whether or not its been created, etc.
    # Purely for convenience, we also include some code here that manages widgets
    # that use -text or -textvariable, though not every widget will do so.

Changes to widgets/wtk.js.

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
..
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
..
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
...
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
...
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
var wtk = {
    
    widgets : new Array(),
    objs : new Array(),

		pause : function(ms) {
			ms += new Date().getTime();
			while (new Date() < ms){}
		},
  
    /*
     *   Initialize, and manage two AJAX connections to the server; one is used to send
     *   messages, and the other polling connection is used to receive messages.  These
     *   correspond to the routines in server.tcl, and could be equally well replaced by
     *   a different and/or more reliable communications channel.
     */
    init : function(sessionid) {
        wtk.sessionid = sessionid;
				wtk.conntype = "init";
        wtk.widgets['obj0'] = document.getElementById('obj0');
        

				if ('WebSocket' in window){
			 		/* WebSocket is supported. Proceed with server connection*/

					//create the uri to the ws controller on server
					var loc = window.location, ws_uri;
					if (loc.protocol === "https:") {
................................................................................
					console.log('Browser doesnt support WebSockets, using AJAX instead');
					wtk.poller;
				};


    },






    poller : function() {$.ajax({type:'GET', url:'wtkpoll.html?sessionid='+wtk.sessionid, dataType:'script', 
                                complete: function() {setTimeout(wtk.poller,100);},
                                error: function(jqXHR, textStatus, errorThrown) {
																	//alert("AJAX server connection interrupted\nPress OK to reconnect.");
																	console.log('AJAX server connecton interrupted '+textStatus+' '+errorThrown);
																	setTimeout(location.reload(1),200);}
                               });
												 },

    sendto : function(msg) { 
      if (wtk.conntype != "websocket") {
				$.get('wtkcb.html?sessionid='+wtk.sessionid, {cmd : msg});
			} else {
				wtk.connection.send(msg);
			}
		},

................................................................................
    CreateWidget : function(id,type,txt,attr) {
        var w = document.createElement(type);
        w.id = id;
        if(txt!='') {if (attr=='innerHTML') {w.innerHTML=txt;} else {w.value=txt;};}
        wtk.widgets[id] = w;
        return w;
    },
    
    /*
     * Buttons, labels and entries, oh my!
     */

  
		createMisc   : function(id, type, txt, attr) { 
			wtk.CreateWidget(id, type, txt, attr).onclick = function() {wtk.miscClicked(id);}; 
			},
		miscClicked : function(id) { wtk.sendto('EVENT '+id+' pressed'+' value '+wtk.widgets[id].value); },

    createButton  : function(id,txt) { wtk.CreateWidget(id,'button',txt,'innerHTML').onclick = function() {wtk.buttonClicked(id);}; },
    buttonClicked : function(id) { wtk.sendto('EVENT '+id+' pressed'); },

    createCombobox  : function(id,txt) { 
    	  wtk.CreateWidget(id,'select',txt,'value').onchange = function() {wtk.comboboxClicked(id);}; 
    },
    comboboxClicked : function(id) { wtk.sendto('EVENT '+id+' value '+wtk.widgets[id].value); },

    createLabel   : function(id, txt) { wtk.CreateWidget(id, 'span', txt,'innerHTML'); },

    createEntry   : function(id, txt) { wtk.CreateWidget(id, 'input', txt,'value').onkeyup = function() {wtk.entryChanged(id);}; },
    entryChanged  : function(id) { wtk.sendto('EVENT '+id+' value '+wtk.widgets[id].value); },

    createText   : function(id, txt) { wtk.CreateWidget(id, 'textarea', txt,'value').onkeyup = function() {wtk.textChanged(id);}; },
    textChanged  : function(id) { wtk.sendto('EVENT '+id+' value '+wtk.widgets[id].value); },
        
    createFrame   : function(id) { wtk.CreateWidget(id, 'div', '', '');},
    


    createCheckButton : function(id,txt) {
        var w = wtk.CreateWidget(id,'span', '', ''); 
        var c = w.appendChild(document.createElement('input'));
        var l = w.appendChild(document.createElement('span'));
        c.type = 'checkbox';
        c.onclick = function() {wtk.checkButtonClicked(id);};
        l.innerHTML = txt;
    },
    checkButtonClicked : function(id) { var ev; if (wtk.widgets[id].childNodes[0].checked==true) {ev='checked';} else {ev='unchecked';}; wtk.sendto('EVENT ' + id + ' ' + ev);},
    
    /*
     * Grid .
     */
    
    newGrid : function(parent,id) {
        var w = document.createElement('table');
        w.id = id;
        wtk.widgets[parent].appendChild(w);
    },
    
    /*
     * Canvas
     */
    
    Canvas : function(w,id) {
        var self = this;
        this.w = w;
        this.id = id;
        this.ctx = null;
        this.items = [];
        this.context = w.getContext("2d");
................................................................................
        this.drawtimer = null;
        this.ghostcanvas = null;
        this.gctx = null;
        w.width = 100; w.height = 100; w.style.width = '100px'; w.style.height = '100px';
        w.style.background = '#ffffff';
        w.style.position = 'relative';
        w.style.cursor = 'default';
        
        w.onmousedown = function(ev) {self.handleMouse(ev, 'mousedown');}
        w.onmousemove = function(ev) {self.handleMouse(ev, 'mousemove');}
        w.onmouseup = function(ev) {self.handleMouse(ev, 'mouseup');}
        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;
            ctx.clearRect(0,0,this.w.width,this.w.height);
            ctx.beginPath();
            $.each(this.items, function(idx,i) {self.drawItem(ctx,i)});
        }
        
        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;
            }
            if (this.gctx==null) {this.gctx = this.ghostcanvas.getContext("2d");}
................................................................................
                var imageData = this.gctx.getImageData(x,y,1,1);
                if (imageData.data[3]>0) {
                    return this.items[i].cid;
                }
            }
            return '';
        }
      
        this.handleMouse = function(ev, action) {
            var itemhit = '';
            var x = ev.pageX-this.w.offsetLeft;
            var y = ev.pageY-this.w.offsetTop;
            if (action=="mousedown") {itemhit = this.itemAt(x,y);}
            wtk.sendto('EVENT '+this.id+' '+action+' '+x+' '+y+' '+ev.button+' '+itemhit);
        }
        
    },
        
    createCanvas : function(id) {
        var w = wtk.CreateWidget(id,'canvas', '', '');
        wtk.objs[id] = new wtk.Canvas(w,id);
    },
};


|







|










|







 







>
>
>

<
|








|







 







|




|
|
|






|
|










|

|



|







|



|





|



|







 







|




|





|

|








|






|


|







 







|







|

|





<
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
..
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
..
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
...
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236

var wtk = {

    widgets : new Array(),
    objs : new Array(),

		pause : function(ms) {
			ms += new Date().getTime();
			while (new Date() < ms){}
		},

    /*
     *   Initialize, and manage two AJAX connections to the server; one is used to send
     *   messages, and the other polling connection is used to receive messages.  These
     *   correspond to the routines in server.tcl, and could be equally well replaced by
     *   a different and/or more reliable communications channel.
     */
    init : function(sessionid) {
        wtk.sessionid = sessionid;
				wtk.conntype = "init";
        wtk.widgets['obj0'] = document.getElementById('obj0');


				if ('WebSocket' in window){
			 		/* WebSocket is supported. Proceed with server connection*/

					//create the uri to the ws controller on server
					var loc = window.location, ws_uri;
					if (loc.protocol === "https:") {
................................................................................
					console.log('Browser doesnt support WebSockets, using AJAX instead');
					wtk.poller;
				};


    },

    server_log :function(logLevel,msg) {
        wtk.sendto('LOG '+logLevel+' '+wtk.sessionid+' '+msg);
    },


    poller : function() {$.ajax({type:'GET', url:'wtkpoll.html?sessionid='+wtk.sessionid, dataType:'script',
                                complete: function() {setTimeout(wtk.poller,100);},
                                error: function(jqXHR, textStatus, errorThrown) {
																	//alert("AJAX server connection interrupted\nPress OK to reconnect.");
																	console.log('AJAX server connecton interrupted '+textStatus+' '+errorThrown);
																	setTimeout(location.reload(1),200);}
                               });
												 },

    sendto : function(msg) {
      if (wtk.conntype != "websocket") {
				$.get('wtkcb.html?sessionid='+wtk.sessionid, {cmd : msg});
			} else {
				wtk.connection.send(msg);
			}
		},

................................................................................
    CreateWidget : function(id,type,txt,attr) {
        var w = document.createElement(type);
        w.id = id;
        if(txt!='') {if (attr=='innerHTML') {w.innerHTML=txt;} else {w.value=txt;};}
        wtk.widgets[id] = w;
        return w;
    },

    /*
     * Buttons, labels and entries, oh my!
     */


		createMisc   : function(id, type, txt, attr) {
			wtk.CreateWidget(id, type, txt, attr).onclick = function() {wtk.miscClicked(id);};
			},
		miscClicked : function(id) { wtk.sendto('EVENT '+id+' pressed'+' value '+wtk.widgets[id].value); },

    createButton  : function(id,txt) { wtk.CreateWidget(id,'button',txt,'innerHTML').onclick = function() {wtk.buttonClicked(id);}; },
    buttonClicked : function(id) { wtk.sendto('EVENT '+id+' pressed'); },

    createCombobox  : function(id,txt) {
    	  wtk.CreateWidget(id,'select',txt,'value').onchange = function() {wtk.comboboxClicked(id);};
    },
    comboboxClicked : function(id) { wtk.sendto('EVENT '+id+' value '+wtk.widgets[id].value); },

    createLabel   : function(id, txt) { wtk.CreateWidget(id, 'span', txt,'innerHTML'); },

    createEntry   : function(id, txt) { wtk.CreateWidget(id, 'input', txt,'value').onkeyup = function() {wtk.entryChanged(id);}; },
    entryChanged  : function(id) { wtk.sendto('EVENT '+id+' value '+wtk.widgets[id].value); },

    createText   : function(id, txt) { wtk.CreateWidget(id, 'textarea', txt,'value').onkeyup = function() {wtk.textChanged(id);}; },
    textChanged  : function(id) { wtk.sendto('EVENT '+id+' value '+wtk.widgets[id].value); },

    createFrame   : function(id) { wtk.CreateWidget(id, 'div', '', '');},



    createCheckButton : function(id,txt) {
        var w = wtk.CreateWidget(id,'span', '', '');
        var c = w.appendChild(document.createElement('input'));
        var l = w.appendChild(document.createElement('span'));
        c.type = 'checkbox';
        c.onclick = function() {wtk.checkButtonClicked(id);};
        l.innerHTML = txt;
    },
    checkButtonClicked : function(id) { var ev; if (wtk.widgets[id].childNodes[0].checked==true) {ev='checked';} else {ev='unchecked';}; wtk.sendto('EVENT ' + id + ' ' + ev);},

    /*
     * Grid .
     */

    newGrid : function(parent,id) {
        var w = document.createElement('table');
        w.id = id;
        wtk.widgets[parent].appendChild(w);
    },

    /*
     * Canvas
     */

    Canvas : function(w,id) {
        var self = this;
        this.w = w;
        this.id = id;
        this.ctx = null;
        this.items = [];
        this.context = w.getContext("2d");
................................................................................
        this.drawtimer = null;
        this.ghostcanvas = null;
        this.gctx = null;
        w.width = 100; w.height = 100; w.style.width = '100px'; w.style.height = '100px';
        w.style.background = '#ffffff';
        w.style.position = 'relative';
        w.style.cursor = 'default';

        w.onmousedown = function(ev) {self.handleMouse(ev, 'mousedown');}
        w.onmousemove = function(ev) {self.handleMouse(ev, 'mousemove');}
        w.onmouseup = function(ev) {self.handleMouse(ev, 'mouseup');}
        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;
            ctx.clearRect(0,0,this.w.width,this.w.height);
            ctx.beginPath();
            $.each(this.items, function(idx,i) {self.drawItem(ctx,i)});
        }

        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;
            }
            if (this.gctx==null) {this.gctx = this.ghostcanvas.getContext("2d");}
................................................................................
                var imageData = this.gctx.getImageData(x,y,1,1);
                if (imageData.data[3]>0) {
                    return this.items[i].cid;
                }
            }
            return '';
        }

        this.handleMouse = function(ev, action) {
            var itemhit = '';
            var x = ev.pageX-this.w.offsetLeft;
            var y = ev.pageY-this.w.offsetTop;
            if (action=="mousedown") {itemhit = this.itemAt(x,y);}
            wtk.sendto('EVENT '+this.id+' '+action+' '+x+' '+y+' '+ev.button+' '+itemhit);
        }

    },

    createCanvas : function(id) {
        var w = wtk.CreateWidget(id,'canvas', '', '');
        wtk.objs[id] = new wtk.Canvas(w,id);
    },
};