Project

General

Profile

1811q_strokes_2.txt

Sergey Ivanovskiy, 08/20/2015 10:42 AM

Download (39.4 KB)

 
1
=== modified file 'src/com/goldencode/p2j/ui/client/driver/web/WebClientMessageTypes.java'
2
--- src/com/goldencode/p2j/ui/client/driver/web/WebClientMessageTypes.java	2015-08-20 14:07:03 +0000
3
+++ src/com/goldencode/p2j/ui/client/driver/web/WebClientMessageTypes.java	2015-08-20 14:14:14 +0000
4
@@ -126,4 +126,7 @@
5
    
6
    /** Restack the z-order of all windows. */
7
    public static final byte MSG_RESTACK_WINDOWS     = (byte) 0x95;
8
+   
9
+   /** Set the stroke style for a window. */
10
+   public static final byte MSG_SET_STROKE_STYLE    = (byte) 0x96;
11
 }
12

    
13
=== modified file 'src/com/goldencode/p2j/ui/client/driver/web/index.html'
14
--- src/com/goldencode/p2j/ui/client/driver/web/index.html	2015-08-12 17:42:50 +0000
15
+++ src/com/goldencode/p2j/ui/client/driver/web/index.html	2015-08-20 12:40:07 +0000
16
@@ -9,6 +9,7 @@
17
             
18
       <script type="text/javascript" src="/common/p2j.js"></script>
19
       <script type="text/javascript" src="/common/p2j.sound.js"></script>
20
+      <script type="text/javascript" src="/client/p2j.strokes.js"></script>
21
       <script type="text/javascript" src="/client/p2j.screen.js"></script>
22
       <script type="text/javascript" src="/common/p2j.socket.js"></script>
23
       <script type="text/javascript" src="/common/p2j.keymap.js"></script>
24

    
25
=== modified file 'src/com/goldencode/p2j/ui/client/driver/web/res/p2j.socket.js'
26
--- src/com/goldencode/p2j/ui/client/driver/web/res/p2j.socket.js	2015-08-20 14:07:03 +0000
27
+++ src/com/goldencode/p2j/ui/client/driver/web/res/p2j.socket.js	2015-08-20 14:15:40 +0000
28
@@ -24,7 +24,7 @@
29
 **                  requests.
30
 ** 010 GES 20150818 Added more GUI message support including fonts, cursors and z-order.
31
 **                  Once the web socket has connected, notify the Java side, so that it can start
32
-**                  sending requests.
33
+**                  sending requests, added line strokes.
34
 */
35
 
36
 "use strict";
37
@@ -534,6 +534,13 @@
38
                      }
39
                      p2j.screen.restackZOrderEntries(winids);
40
                      break;
41
+                  case 0x96:
42
+                     // set line stroke
43
+                     var strokeStyle = me.readInt32BinaryMessage(message, 1);
44
+                     var strokeWidth = me.readInt32BinaryMessage(message, 5);
45
+                     var wid = me.readInt32BinaryMessage(message, 9);
46
+                     p2j.screen.setLineStroke(strokeStyle, strokeWidth, wid);
47
+                     break;
48
                };
49
             }
50
             else
51

    
52
=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebEmulatedWindow.java'
53
--- src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebEmulatedWindow.java	2015-08-18 19:50:34 +0000
54
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebEmulatedWindow.java	2015-08-20 10:02:03 +0000
55
@@ -17,7 +17,7 @@
56
 **                  font creation/selection.
57
 ** 005 GES 20150817 Removed isOnTop() since it is unnecessary. The saveFocusListeners(),
58
 **                  restoreFocusListeners() and moveToTop() are only needed for Swing usage and
59
-**                  have been removed from this class.
60
+**                  have been removed from this class, added line strokes.
61
 */
62
 
63
 package com.goldencode.p2j.ui.client.gui.driver.web;
64
@@ -362,6 +362,7 @@
65
             websock.setColor(ps.color.getRed(), ps.color.getGreen(), ps.color.getBlue());
66
             break;
67
          case SET_LINE_STROKE:
68
+            websock.setLineStroke(ps.stroke.ordinal(), Math.round(ps.strokeWidth), getWindowId());
69
             break;
70
          case SET_FONT:
71
             websock.setFont(ps.font.font);
72

    
73
=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java'
74
--- src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java	2015-08-20 14:07:03 +0000
75
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java	2015-08-20 14:17:12 +0000
76
@@ -12,8 +12,8 @@
77
 ** 001 GES 20150331 First version which is a placeholder using the common parent code as ChUI.
78
 ** 002 GES 20150701 Added messages for a first pass at GUI support,
79
 **                  implemented an images drawing operation.
80
-** 003 CA  20150810 Added operations for font, metrics and string drawing.  Added z-order
81
-**                  support.
82
+** 003 CA  20150810 Added operations for font, metrics and string drawing.  Added z-order,
83
+**                  line strokes.
84
 ** 004 CA  20150820 Moved the message receiving APIs to parent class.
85
 */
86
 
87
@@ -1231,6 +1231,31 @@
88
    }
89
 
90
    /**
91
+    * Sends MSG_SET_STROKE_STYLE to order the current window stroke to be changed
92
+    * on the client side. It sends a window its stroke style and line width. All possible stroke
93
+    * styles are listed by LineStroke enumeration. 
94
+    * 
95
+    * @param    strokeStyle
96
+    *           The known stroke style id.
97
+    * @param    width
98
+    *           The stroke line width.
99
+    * @param    wid
100
+    *           The window id.
101
+    */
102
+   public void setLineStroke(int strokeStyle, int width, int wid)
103
+   {
104
+      byte[] message = new byte[13];
105
+
106
+      message[0] = WebClientMessageTypes.MSG_SET_STROKE_STYLE;
107
+
108
+      writeMessageInt32(message, 1, strokeStyle);
109
+      writeMessageInt32(message, 5, width);
110
+      writeMessageInt32(message, 9, wid);
111
+
112
+      sendBinaryMessage(message);
113
+   }
114
+
115
+   /**
116
     * Draw a string at the specified location.
117
     * 
118
     * @param    text
119

    
120
=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.screen.js'
121
--- src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.screen.js	2015-08-19 20:05:05 +0000
122
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.screen.js	2015-08-20 14:22:24 +0000
123
@@ -84,6 +84,8 @@
124
       SET_TITLE            : 29
125
    };
126
 
127
+   var strokesManager = new LineStrokes();
128
+   
129
    /**
130
     * Constructor for a Window class that represents a Progress 4GL window instance.
131
     *
132
@@ -138,12 +140,17 @@
133
       // eliminate anti-aliasing of images
134
       this.ctx.imageSmoothingEnabled = false;
135
       
136
+      // the current window stroke style
137
+      this.strokeStyle = strokesManager.getDefaultStrokeStyle();
138
+      // the current window stroke width
139
+      this.strokeWidth = 1;
140
+      
141
       // force all drawing to be inside pixel "cells" instead of "stradling" between two cells
142
       // which is the default; this eliminates much of the worst of the anti-aliasing and
143
       // positioning problems inherent in canvas operations; this will also save off the
144
       // current state of the graphics context so that it can be restored later 
145
       this.translate(0.5, 0.5);
146
-   }
147
+   };
148
    
149
    /**
150
     * Cleanup any resources, including any linkages to the window from an owning window.
151
@@ -353,7 +360,7 @@
152
             this.ctx.rect(x, y, width, height);
153
             this.ctx.clip();
154
          }
155
-      }      
156
+      }
157
    };
158
    
159
    /**
160
@@ -430,7 +437,7 @@
161
    Window.prototype.resize = function(width, height)
162
    {
163
       // save off the previously drawn content
164
-      var oldPixels = ctx.getImageData(0, 0, canvas.width, canvas.height);
165
+      var oldPixels = this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height);
166
       
167
       // this is expensive, but we really do need to change the overall size of the canvas 
168
       this.canvas.width  = width;
169
@@ -441,7 +448,7 @@
170
       this.replay();
171
       
172
       // re-blit the previously drawn content
173
-      ctx.putImageData(oldPixels, 0, 0);
174
+      this.ctx.putImageData(oldPixels, 0, 0);
175
    };   
176
 
177
    /**
178
@@ -454,6 +461,42 @@
179
    {
180
       this.canvas.style.cursor = style;
181
    };
182
+   
183
+   /**
184
+    * Sets the stroke style.
185
+    * 
186
+    * @param    {Number} strokeStyle
187
+    *           The predefined stroke style.
188
+    */
189
+   Window.prototype.setStrokeStyle = function(strokeStyle)
190
+   {
191
+      this.strokeStyle = strokeStyle;
192
+   };
193
+   
194
+   /**
195
+    * Sets the stroke line width.
196
+    * 
197
+    * @param    {Number} width
198
+    *           The stroke line width.
199
+    */
200
+   Window.prototype.setStrokeWidth = function(width)
201
+   {
202
+      this.strokeWidth = width;
203
+   };
204
+
205
+   /**
206
+    * Sets the line stroke.
207
+    * 
208
+    * @param    {Number} strokeStyle
209
+    *           The predefined stroke style.
210
+    * @param    {Number} width
211
+    *           The stroke line width.
212
+    */
213
+   Window.prototype.setLineStroke = function(strokeStyle, width)
214
+   {
215
+      this.setStrokeStyle(strokeStyle);
216
+      this.setStrokeWidth(width);
217
+   };
218
 
219
    /**
220
     * Draw the given list of operations in the canvas.
221
@@ -521,11 +564,11 @@
222
                   // in this case, the "y" is the height in which it needs to be vertically centered
223
                   y = y / 2;
224
                   
225
-                  ctx.textBaseline = 'middle';
226
+                  this.ctx.textBaseline = 'middle';
227
                }
228
                else
229
                {
230
-                  ctx.textBaseline = 'top';
231
+                  this.ctx.textBaseline = 'top';
232
                }
233
 
234
                this.ctx.fillText(text, x, y);
235
@@ -554,16 +597,16 @@
236
                var lheight = p2j.socket.readInt32BinaryMessage(message, idx + offset);
237
                offset = offset + 4;
238
                
239
-               var textWidth = p2j.fonts.getTextWidth(this.currentFont, text);
240
-               var textHeight = p2j.fonts.getTextHeight(this.currentFont, text);
241
+               var textWidth = p2j.fonts.getTextWidth(currentFont, text);
242
+               var textHeight = p2j.fonts.getTextHeight(currentFont, text);
243
                
244
                var widthScale = lwidth / textWidth;
245
                var heightScale = lheight / textHeight;
246
                
247
                // scale drawing context to computed width
248
                // this scales the desired structure.x as well so it needs adjusting
249
-               ctx.save();
250
-               ctx.scale(widthScale, heightScale);
251
+               this.ctx.save();
252
+               this.ctx.scale(widthScale, heightScale);
253
                
254
                var scaleBackWidth = 1 / widthScale;
255
                var scaleBackHeight = 1 / heightScale;
256
@@ -573,15 +616,15 @@
257
                   // in this case, the "y" is the height in which it needs to be vertically centered
258
                   y = y / 2;
259
 
260
-                  ctx.textBaseline = 'middle';
261
+                  this.ctx.textBaseline = 'middle';
262
                }
263
                else
264
                {
265
-                  ctx.textBaseline = 'top';
266
+                  this.ctx.textBaseline = 'top';
267
                }
268
 
269
-               ctx.fillText(text, x * scaleBackWidth, y * scaleBackHeight);
270
-               ctx.restore();
271
+               this.ctx.fillText(text, x * scaleBackWidth, y * scaleBackHeight);
272
+               this.ctx.restore();
273
                
274
                break;
275
             case ops.DRAW_PARAGRAPH:
276
@@ -605,7 +648,7 @@
277
                width = p2j.socket.readInt32BinaryMessage(message, idx + offset);
278
                offset = offset + 4;
279
 
280
-               ctx.textBaseline = 'top';
281
+               this.ctx.textBaseline = 'top';
282
 
283
                me.layoutParagraphWorker(text, fontId, x, y, width, true);
284
 
285
@@ -615,7 +658,9 @@
286
                var y1 =  p2j.socket.readInt32BinaryMessage(message, idx + 5);
287
                var x2 =  p2j.socket.readInt32BinaryMessage(message, idx + 9);
288
                var y2 =  p2j.socket.readInt32BinaryMessage(message, idx + 13);
289
-               drawLine(this.ctx, x1, y1, x2, y2, this.rawColor);
290
+               strokesManager.applyStrokeToPath(this.ctx,
291
+                     this.strokeStyle, this.strokeWidth, this.rawColor,
292
+                     drawLine(this.ctx, x1, y1, x2, y2, this.rawColor));
293
                this.ctx.stroke();
294
                break;
295
             case ops.DRAW_RECT:
296
@@ -623,7 +668,9 @@
297
                y      = p2j.socket.readInt32BinaryMessage(message, idx + 5);
298
                width  = p2j.socket.readInt32BinaryMessage(message, idx + 9);
299
                height = p2j.socket.readInt32BinaryMessage(message, idx + 13);
300
-               drawRect(this.ctx, x, y, width, height, this.rawColor, false);
301
+               strokesManager.applyStrokeToPath(this.ctx,
302
+                     this.strokeStyle, this.strokeWidth, this.rawColor,
303
+                     drawRect(this.ctx, x, y, width, height, this.rawColor, false));
304
                break;
305
             case ops.DRAW_ROUND_RECT:
306
                x        = p2j.socket.readInt32BinaryMessage(message, idx + 1);
307
@@ -658,7 +705,7 @@
308
                   imgDataOffset = idx + 22;
309
                   loadedImages.set(key, message.subarray(imgDataOffset, imgDataOffset + pixelsInBytes));
310
                }
311
-               drawImage(x, y, width, height, imgData, imgDataOffset);
312
+               drawImage(this.ctx, x, y, width, height, imgData, imgDataOffset);
313
                break;
314
             case ops.FILL_RECT:
315
                x      = p2j.socket.readInt32BinaryMessage(message, idx + 1);
316
@@ -673,7 +720,7 @@
317
                width    = p2j.socket.readInt32BinaryMessage(message, idx + 9);
318
                height   = p2j.socket.readInt32BinaryMessage(message, idx + 13);
319
                diameter = p2j.socket.readInt32BinaryMessage(message, idx + 17);
320
-               drawRoundRect(ctx, x, y, width, height, diameter, this.rawColor, true);
321
+               drawRoundRect(this.ctx, x, y, width, height, diameter, this.rawColor, true);
322
                break;
323
             case ops.FILL_POLYGON:
324
                idx += 1;
325
@@ -719,14 +766,14 @@
326
             case ops.SET_FONT:
327
                fontId = p2j.socket.readInt32BinaryMessage(message, idx + 1);
328
 
329
-               this.setFont(fontId);
330
+               this.setFont(this.ctx, fontId);
331
                break;
332
             case ops.SET_FONT_STYLE:
333
                var style = p2j.socket.readInt32BinaryMessage(message, idx + 1);
334
                
335
-               if (p2j.fonts.setFontStyle(this.currentFont, style))
336
+               if (p2j.fonts.setFontStyle(currentFont, style))
337
                {
338
-                  fname = p2j.fonts.getFontName(this.currentFont);
339
+                  fname = p2j.fonts.getFontName(currentFont);
340
 
341
                   this.ctx.font = fname;
342
                }
343
@@ -792,7 +839,7 @@
344
    function isValidWindowId(wid)
345
    {
346
       return (typeof wid === 'number') && (wid % 1 === 0) && wid > 0;
347
-   }
348
+   };
349
    
350
    /**
351
     * Checks if the given value already exists as a window id.
352
@@ -805,8 +852,8 @@
353
    function isExistingWindowId(wid)
354
    {
355
       return winlist[wid] instanceof Window;
356
-   }
357
-   
358
+   };
359
+
360
    /**
361
     * Obtain the specified window.
362
     *
363
@@ -819,8 +866,8 @@
364
    function getWindow(wid)
365
    {
366
       return winlist[wid] instanceof Window ? winlist[wid] : null;
367
-   }
368
-            
369
+   };
370
+
371
    /**
372
     * Find the index of the given window in the z-order list.
373
     *
374
@@ -855,8 +902,8 @@
375
       }
376
       
377
       return found;
378
-   }
379
-   
380
+   };
381
+
382
    /**
383
     * Adds the given window to the end of the z-order list, setting the z-order value as needed.
384
     *
385
@@ -875,7 +922,7 @@
386
       
387
       // assign the z-order
388
       win.canvas.style.zIndex = zidx;
389
-   }
390
+   };
391
    
392
    /**
393
     * Removes the given window from the z-order list and resets the z-order values of all
394
@@ -898,7 +945,7 @@
395
       }
396
       
397
       return removeZOrderEntryWorker(found);
398
-   }
399
+   };
400
       
401
    /**
402
     * Removes the given element from the z-order list and resets the z-order values of all
403
@@ -924,7 +971,7 @@
404
       }
405
       
406
       return removed;
407
-   }
408
+   };
409
    
410
    /**
411
     * Moves the given window to the top of the z-order list and resets the z-order values of all
412
@@ -945,7 +992,7 @@
413
          
414
          addZOrderEntry(entry.id, entry.win);
415
       }
416
-   }
417
+   };
418
    
419
    /**
420
     * Directly draw the specified pixel in the given color.
421
@@ -959,14 +1006,14 @@
422
     * @param    {Number[]} color
423
     *           Array of 3 integer values between 0 and 255 inclusive, representing an RGB color.
424
     */
425
-   function drawPixel(ctx, x, y, color)
426
+   Window.prototype.drawPixel = function(ctx, x, y, color)
427
    {
428
-      pixData[0] = color[0];
429
-      pixData[1] = color[1];
430
-      pixData[2] = color[2];
431
+      this.pixData[0] = color[0];
432
+      this.pixData[1] = color[1];
433
+      this.pixData[2] = color[2];
434
       
435
-      ctx.putImageData(pixel, x, y);
436
-   }
437
+      this.ctx.putImageData(pixel, x, y);
438
+   };
439
    
440
    /**
441
     * Draw a line in the given color from (x1, y1) to (x2, y2) inclusive, using direct drawing.
442
@@ -985,9 +1032,14 @@
443
     *           Y coordinate of the ending pixel to be drawn.
444
     * @param    {Number[]} color
445
     *           Array of 3 integer values between 0 and 255 inclusive, representing an RGB color.
446
+    * 
447
+    * @return   {Array} path
448
+    *           The {x:.,y:.} point per a pixel array that represents the rectangle outerline.
449
     */
450
-   function drawLine(ctx, x1, y1, x2, y2, color)
451
+   Window.prototype.drawLine = function(ctx, x1, y1, x2, y2, color)
452
    {
453
+      // holds the line pixels to draw
454
+      var path = [];
455
       var dx = Math.abs(x2 - x1);
456
       var dy = Math.abs(y2 - y1);
457
       
458
@@ -1004,7 +1056,11 @@
459
       
460
       while (true)
461
       {
462
-         drawPixel(ctx, x, y, color);
463
+         if (strokesManager.isDirectDrawingStrokeStyle(this.strokeStyle))
464
+         {
465
+            drawPixel(ctx, x, y, color);
466
+         }
467
+         path.push({x : x, y : y});
468
          
469
          if (x == x2 && y == y2)
470
             break;
471
@@ -1023,7 +1079,9 @@
472
             y   += yIncr;
473
          }
474
       }
475
-   }
476
+      
477
+      return path;
478
+   };
479
    
480
    /**
481
     * Fill or stroke the current path on the given context, first using the current path as a
482
@@ -1052,8 +1110,8 @@
483
       }
484
       
485
       ctx.restore();
486
-   }
487
-         
488
+   };
489
+
490
    /**
491
     * Draw a rectangle in the given color and dimensions with the line drawing being overwritten
492
     * using direct drawing to eliminate the negative/unwanted effects of alni-aliasing.
493
@@ -1073,8 +1131,11 @@
494
     *           This will be used for the border lines and when in fill mode, also the interior.
495
     * @param    {Boolean} fill
496
     *           <code>true</code> to fill the drawn rectangle with the given color.
497
+    * 
498
+    * @return   {Array} path
499
+    *           The {x:.,y:.} point per a pixel array that represents the rectangle outerline.
500
     */
501
-   function drawRect(ctx, x, y, width, height, color, fill)
502
+   Window.prototype.drawRect = function(ctx, x, y, width, height, color, fill)
503
    {
504
       // use vector operations for the interior of the rectangle
505
       if (fill)
506
@@ -1085,15 +1146,20 @@
507
       }
508
       
509
       // now overdraw the stroked portion to eliminate anit-aliasing
510
-      drawLine(ctx, x, y, x + width, y, color);
511
-      drawLine(ctx, x, y + 1, x, y + height, color);
512
-      drawLine(ctx, x + width, y + 1, x + width, y + height, color);
513
-      drawLine(ctx, x + 1, y + height, x + width - 1, y + height, color);
514
-   }                         
515
+      // to draw rectangle following a clockwise direction
516
+      var path = drawLine(ctx, x, y, x + width, y, color);
517
+      Array.prototype.push.apply(path, drawLine(ctx, x + width, y + 1, x + width, y + height, color));
518
+      Array.prototype.push.apply(path, drawLine(ctx, x + width - 1, y + height, x + 1, y + height, color));
519
+      Array.prototype.push.apply(path, drawLine(ctx, x, y + height, x, y + 1, color));// close the path
520
+      
521
+      return path;
522
+   };
523
    
524
    /**
525
     * It draws an image on the canvas.
526
     * 
527
+    * @param    {CanvasRenderingContext2D} ctx
528
+    *           The canvas 2D graphics context on which to draw.
529
     * @param    {Number} x
530
     *           X coordinate of the top left corner.
531
     * @param    {Number} y
532
@@ -1107,7 +1173,7 @@
533
     * @param    {Number} imgDataOffset
534
     *           The offset of the encoded image data.
535
     */
536
-   function drawImage(x, y, width, height, imgData, imgDataOffset)
537
+   Window.prototype.drawImage = function(ctx, x, y, width, height, imgData, imgDataOffset)
538
    {
539
       var img = ctx.createImageData(width, height);
540
       var data = img.data;
541
@@ -1121,7 +1187,7 @@
542
          data[i + 3] = imgData[j + 3];
543
      }
544
      ctx.putImageData(img, x, y);
545
-   }
546
+   };
547
    
548
    /**
549
     * Convert a standard fillStyle or strokeStyle color into an array of [ R, G, B ] values.
550
@@ -1162,7 +1228,7 @@
551
       }
552
       
553
       return [ r, g, b ];
554
-   }
555
+   };
556
    
557
    /**
558
     * Test if the given argument is an array of 3 integer values.
559
@@ -1199,7 +1265,7 @@
560
       }
561
       
562
       return true;
563
-   }
564
+   };
565
    
566
    /**
567
     * Convert the given array of 3 integer values into an HTML color string.
568
@@ -1219,7 +1285,7 @@
569
       return "rgb(" + color[0].toString() + ", "
570
                     + color[1].toString() + ", "
571
                     + color[2].toString() + ")";
572
-   }
573
+   };
574
    
575
    /**
576
     * Convert the given array of RGB values into a lighter color in a manner that is compatible 
577
@@ -1254,7 +1320,7 @@
578
       var b = Math.min(Math.floor(bIn / SCALE_FACTOR), 255);
579
       
580
       return [ r, g, b ];
581
-   }
582
+   };
583
    
584
    /**
585
     * Convert the given array of RGB values into a darker color in a manner that is compatible 
586
@@ -1277,7 +1343,7 @@
587
       var b = Math.max(0, Math.floor(color[2] * SCALE_FACTOR));
588
       
589
       return [ r, g, b ];
590
-   }
591
+   };
592
          
593
    /**
594
     * Draw a rounded rectangle with the given context, dimensions and fill.
595
@@ -1302,7 +1368,7 @@
596
     *           <code>true</code> to fill the rectangle with the current color, otherwise just
597
     *           stroke the rectangle.
598
     */
599
-   function drawRoundRect(ctx, x, y, width, height, diameter, color, fill)
600
+   Window.prototype.drawRoundRect = function(ctx, x, y, width, height, diameter, color, fill)
601
    {
602
       var radius = diameter / 2;
603
       
604
@@ -1352,7 +1418,7 @@
605
       drawLine(ctx, rightUpX, rightUpY, rightDownX, rightDownY, color);
606
       drawLine(ctx, bottomLeftX, bottomLeftY, bottomRightX, bottomRightY, color);
607
       drawLine(ctx, leftUpX, leftUpY, leftDownX, leftDownY, color);
608
-   }
609
+   };
610
    
611
    /**
612
     * Draw a slightly shaded "3D" rectangle with the given context, dimensions and fill. In
613
@@ -1380,7 +1446,7 @@
614
     * @param    {Boolean} raise
615
     *           <code>true</code> to draw in raised mode.
616
     */
617
-   function draw3DRect(ctx, x, y, width, height, color, fill, raised)
618
+   Window.prototype.draw3DRect = function(ctx, x, y, width, height, color, fill, raised)
619
    {
620
       // save off our colors
621
       var oriFillColor   = ctx.fillStyle;
622
@@ -1422,8 +1488,8 @@
623
       // restore our colors
624
       ctx.fillStyle   = oriFillColor;
625
       ctx.strokeStyle = oriStrokeColor;
626
-   }                         
627
-         
628
+   };
629
+
630
    /**
631
     * Draw a closed polygon with the given context, vertices and fill.
632
     *
633
@@ -1441,7 +1507,7 @@
634
     *           <code>true</code> to fill the rectangle with the current color, otherwise just
635
     *           stroke the rectangle.
636
     */
637
-   function drawPolygon(ctx, xPoints, yPoints, num, color, fill)
638
+   Window.prototype.drawPolygon = function(ctx, xPoints, yPoints, num, color, fill)
639
    {
640
       var i;
641
    
642
@@ -1462,26 +1528,28 @@
643
       {
644
          drawLine(ctx, xPoints[i], yPoints[i], xPoints[i + 1], yPoints[i + 1], color);
645
       }
646
-   }
647
+   };
648
    
649
    /**
650
     * Set the font in the current context.  If the current font does not get changed, then this
651
     * will be a no-op.
652
     *
653
+    * @param    {CanvasRenderingContext2D} ctx
654
+    *           The canvas 2D graphics context on which to draw.
655
     * @param    {Number}  fontId
656
     *           The font identifier.
657
     */
658
-   function setFont(fontId)
659
+   function setFont(ctx, fontId)
660
    {
661
-      if (fontId != this.currentFont)
662
+      if (fontId != currentFont)
663
       {
664
          var fname = p2j.fonts.getFontName(fontId);
665
       
666
-         this.ctx.font = fname;
667
+         ctx.font = fname;
668
       
669
-         this.currentFont = fontId;
670
+         currentFont = fontId;
671
       }
672
-   }
673
+   };
674
 
675
    /**
676
     * Find the next split position, so that the sub-text fits the given width.
677
@@ -1535,7 +1603,7 @@
678
       while (end < txt.length);
679
 
680
       return end;
681
-   }
682
+   };
683
 
684
    /**
685
     * Split the word starting on the given index so that it fits the specified width.
686
@@ -1568,7 +1636,7 @@
687
       }
688
 
689
       return end;
690
-   }
691
+   };
692
 
693
    /**
694
     * Find the next occurrence of the character given by the specified regex, starting from the
695
@@ -1587,7 +1655,7 @@
696
    {
697
       var indexOf = txt.substring(start).search(regex);
698
       return (indexOf >= 0) ? (indexOf + start) : indexOf;
699
-   }
700
+   };
701
    
702
    /**
703
     * Create a new top-level window (and the canvas that backs it).
704
@@ -1770,13 +1838,16 @@
705
    /**
706
     * Draw text on canvas.
707
     * 
708
-    * @param {number} x      x coordinate
709
-    * @param {number} y      y coordinate
710
-    * @param {string} text   text to draw
711
-    * @param {number} a      attribute
712
-    * @param {object} v      color pairs
713
+    * @param    {CanvasRenderingContext2D} ctx
714
+    *           The canvas 2D graphics context on which to draw.
715
+    * @param    {Number} x
716
+    *           The x coordinate.
717
+    * @param    {Number} y
718
+    *           The y coordinate.
719
+    * @param    {String} text
720
+    *           The text to draw
721
     */
722
-   var drawText = function(ctx, x, y, text)
723
+   Window.prototype.drawText = function(ctx, x, y, text)
724
    {
725
       // TODO calc width and height
726
       var width;
727
@@ -1902,6 +1973,25 @@
728
    };
729
 
730
    /**
731
+    * Sets the line stroke for a window with the given id.
732
+    * 
733
+    * @param    {Number} strokeStyle
734
+    *           The predefined stroke style.
735
+    * @param    {Number} width
736
+    *           The stroke line width.
737
+    * @param    {Number} wid
738
+    *           Denotes the active window id.
739
+    */
740
+   me.setLineStroke = function(strokeStyle, width, wid)
741
+   {
742
+      var win = getWindow(wid);
743
+      if (win)
744
+      {
745
+         win.setLineStroke(strokeStyle, width);
746
+      }
747
+   };
748
+
749
+   /**
750
     * Clear the screen.
751
     */
752
    me.clear = function()
753
@@ -1941,6 +2031,8 @@
754
     * The method performs a layout operation on the supplied text and returns the resulting 
755
     * paragraph height while maintaining the supplied maximum width.
756
     *
757
+    * @param    {CanvasRenderingContext2D} ctx
758
+    *           The canvas 2D graphics context on which to draw.
759
     * @param    {String} txt
760
     *           The paragraph text.
761
     * @param    {Number} font
762
@@ -1957,7 +2049,7 @@
763
     * 
764
     * @return   {Number} The paragraph height.
765
     */
766
-   me.layoutParagraphWorker = function(txt, font, x, y, width, draw)
767
+   me.layoutParagraphWorker = function(ctx, txt, font, x, y, width, draw)
768
    {
769
       var newLine = true;
770
       var i = 0;
771
@@ -1965,9 +2057,9 @@
772
       if (draw)
773
       {
774
          // unless we are drawing, there is no need in changing the context font
775
-         this.ctx.save();
776
+         ctx.save();
777
       
778
-         this.setFont(font);
779
+         this.setFont(ctx, font);
780
       }
781
       
782
       var height = 0;
783
@@ -1992,7 +2084,7 @@
784
       
785
       if (draw)
786
       {
787
-         this.ctx.restore();
788
+         ctx.restore();
789
       }
790
       
791
       return height;
792

    
793
=== added file 'src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.strokes.js'
794
--- src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.strokes.js	1970-01-01 00:00:00 +0000
795
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/res/p2j.strokes.js	2015-08-20 09:36:41 +0000
796
@@ -0,0 +1,398 @@
797
+/*
798
+** Module   : p2j.strokes.js
799
+** Abstract : GUI-specific screen management
800
+**
801
+** Copyright (c) 2014-2015, Golden Code Development Corporation.
802
+** ALL RIGHTS RESERVED. Use is subject to license terms.
803
+**
804
+**         Golden Code Development Corporation
805
+**                 CONFIDENTIAL
806
+**
807
+** -#- -I- --Date-- ------------------------------Description----------------------------------
808
+** 001 SBI 20150819 The first version defines LineStrokes class as a strokes manager.
809
+*/
810
+
811
+"use strict";
812
+
813
+/**
814
+ * Defines the known stroke styles and methods to draw styled outer lines.
815
+ */
816
+function LineStrokes()
817
+{
818
+   /**
819
+    * Joins path segments by extending their outside edges until
820
+    * they meet.
821
+    */
822
+   var JOIN_MITER = 0;
823
+
824
+   /**
825
+    * Joins path segments by rounding off the corner at a radius
826
+    * of half the line width.
827
+    */
828
+   var JOIN_ROUND = 1;
829
+
830
+   /**
831
+    * Joins path segments by connecting the outer corners of their
832
+    * wide outlines with a straight segment.
833
+    */
834
+   var JOIN_BEVEL = 2;
835
+
836
+   /**
837
+    * Ends unclosed subpaths and dash segments with no added
838
+    * decoration.
839
+    */
840
+   var CAP_BUTT = 0;
841
+
842
+   /**
843
+    * Ends unclosed subpaths and dash segments with a round
844
+    * decoration that has a radius equal to half of the width
845
+    * of the pen.
846
+    */
847
+   var CAP_ROUND = 1;
848
+
849
+   /**
850
+    * Ends unclosed subpaths and dash segments with a square
851
+    * projection that extends beyond the end of the segment
852
+    * to a distance equal to half of the line width.
853
+    */
854
+   var CAP_SQUARE = 2;
855
+   
856
+   /**
857
+    * This is the list of all possible line stoke types.
858
+    */
859
+   var LineStrokeEnum = 
860
+   {
861
+      DEFAULT           : 0,
862
+      SPECIFIED_WIDTH   : 1,
863
+      DOTTED            : 2,
864
+      DOTTED_SMALL      : 3,
865
+      DOTTED_SMALL_THIN : 4
866
+   };
867
+
868
+   var LineStroke =
869
+   {
870
+      /** Dotted line specific parameter. */
871
+      DOT_STEP            : 2.0,
872
+      
873
+      /** Dotted line specific parameter. */
874
+      DOT_STEP_SMALL      : 1.0,
875
+      
876
+      /** Dotted line width. */
877
+      DOT_LINE_WIDTH      : 1.0,
878
+      
879
+      /** Dotted thin line width. */
880
+      DOT_LINE_THIN_WIDTH : 0.5
881
+   };
882
+   
883
+   var dotStroke = new BasicStroke(LineStroke.DOT_LINE_WIDTH, CAP_BUTT, JOIN_BEVEL, 0.0,
884
+         [LineStroke.DOT_STEP, LineStroke.DOT_STEP], LineStroke.DOT_STEP);
885
+
886
+   var dotSmallStroke  = new BasicStroke(LineStroke.DOT_LINE_WIDTH, CAP_BUTT, JOIN_BEVEL, 0.0,
887
+         [LineStroke.DOT_STEP_SMALL, LineStroke.DOT_STEP_SMALL], LineStroke.DOT_STEP_SMALL);
888
+
889
+   var dotSmallThinStroke = new BasicStroke(LineStroke.DOT_LINE_THIN_WIDTH, CAP_BUTT,
890
+         JOIN_BEVEL, 0.0, [LineStroke.DOT_STEP_SMALL, LineStroke.DOT_STEP_SMALL],
891
+         LineStroke.DOT_STEP_SMALL);
892
+
893
+   var defaultStroke = new BasicStroke(1.0, CAP_SQUARE, JOIN_MITER, 10.0, null, 0.0);
894
+   
895
+   /** Holds all java script styles of how the ends of lines are drawn. */
896
+   var caps = [ "butt", "round", "square"];
897
+   
898
+   /**
899
+    *   Holds all java script styles of how two connecting segments with non-zero lengths
900
+    *   in a shape are joined together.
901
+    */
902
+   var joins = [ "miter", "round", "bevel"];
903
+   
904
+   /**
905
+    * Holds properties for line drawing styles.
906
+    * 
907
+    * @param    width
908
+    *           The width of lines to draw.
909
+    * @param    cap
910
+    *           The decoration of the line ends.
911
+    * @param    join
912
+    *           The decoration applied where path segments meet.
913
+    * @param    miterlimit
914
+    *           The limit to trim the miter join.
915
+    * @param    dash
916
+    *           The array representing the dashing pattern.
917
+    * @param    dash_phase
918
+    *           The offset to start the dashing pattern.
919
+    */
920
+   function BasicStroke(width, cap, join, miterLimit, dash, dash_phase)
921
+   {
922
+      this.getWidth = function() { return width; };
923
+      this.getCap   = function() { return caps[cap]; };
924
+      
925
+      this.getJoin        = function() { return joins[join]; };
926
+      this.getMiterLimit  = function() { return miterLimit; };
927
+      
928
+      this.getDash       = function() { return dash; };
929
+      this.getDashPhase  = function() { return dash_phase; };
930
+   };
931
+
932
+   /**
933
+    * Returns the stroke style object.
934
+    * 
935
+    * @param    {Number} strokeStyle
936
+    *           The stroke style id according to the LineStroke enumeration.
937
+    * @param    {Number} width
938
+    *           The line width.
939
+    * 
940
+    * @return   The basic line stroke object.
941
+    */
942
+   function getLineStroke(strokeStyle, width)
943
+   {
944
+      switch(strokeStyle)
945
+      {
946
+         case LineStrokeEnum.SPECIFIED_WIDTH:
947
+            return new BasicStroke(width, CAP_SQUARE, JOIN_MITER, 10.0, null, 0.0);
948
+         case LineStrokeEnum.DOTTED:
949
+            return dotStroke;
950
+         case LineStrokeEnum.DOTTED_SMALL:
951
+            return dotSmallStroke;
952
+         case LineStrokeEnum.DOTTED_SMALL_THIN:
953
+            return dotSmallThinStroke;
954
+         default:
955
+            return defaultStroke;
956
+      }
957
+   };
958
+   
959
+   /**
960
+    * Returns the stroke path renderer.
961
+    * 
962
+    * @param    {CanvasRenderingContext2D} context
963
+    *           The canvas renderer.
964
+    * @param    {Number} strokeStyle
965
+    *           The stroke style id according to the LineStroke enumeration.
966
+    * @param    {Number} width
967
+    *           The line width.
968
+    * @param    {Number[]} strokeColor
969
+    *           The array of 3 integer values between 0 and 255 inclusive, representing
970
+    *           a stroke color.
971
+    * 
972
+    * @return   The stroke path renderer.
973
+    */
974
+   function getStrokePathRenderer(context, strokeStyle, width, strokeColor)
975
+   {
976
+      var basicStroke = getLineStroke(strokeStyle, width);
977
+      switch(strokeStyle)
978
+      {
979
+         case LineStrokeEnum.SPECIFIED_WIDTH:
980
+            return new WidenPathRenderer(context, basicStroke, strokeColor);
981
+         case LineStrokeEnum.DOTTED:
982
+         case LineStrokeEnum.DOTTED_SMALL:
983
+         case LineStrokeEnum.DOTTED_SMALL_THIN:
984
+            return new DotsPathRenderer(context, basicStroke, strokeColor);
985
+         default:
986
+            return { applyStroke : function (path) {} };
987
+      }
988
+   };
989
+   
990
+   /**
991
+    * Apply the given stroke style to the JS native canvas renderer.
992
+    * 
993
+    * @param    {CanvasRenderingContext2D} context
994
+    *           The canvas renderer.
995
+    * @param    {Number} strokeStyle
996
+    *           The stroke style id.
997
+    * @param    {Number} width
998
+    *           The line width.
999
+    */
1000
+   this.apply = function(context, strokeStyle, width)
1001
+   {
1002
+      if (context instanceof CanvasRenderingContext2D)
1003
+      {
1004
+         var basicStroke = getLineStroke(strokeStyle, width);
1005
+         context.lineWidth = basicStroke.getWidth();
1006
+         
1007
+         context.lineCap = basicStroke.getCap();
1008
+         
1009
+         context.lineJoin = basicStroke.getJoin();
1010
+         
1011
+         context.miterLimit = basicStroke.getMiterLimit();
1012
+         if (basicStroke.getDash())
1013
+         {
1014
+            context.setLineDash(basicStroke.getDash());
1015
+         }
1016
+         else
1017
+         {
1018
+            context.setLineDash([]);
1019
+         }
1020
+         context.lineDashOffset = basicStroke.getDashPhase();
1021
+      }
1022
+   }
1023
+
1024
+   /**
1025
+    * Apply the given stroke style to the area outer bounds.
1026
+    * 
1027
+    * @param    {CanvasRenderingContext2D} context
1028
+    *           The canvas renderer.
1029
+    * @param    {Number} strokeStyle
1030
+    *           The stroke style id.
1031
+    * @param    {Number} width
1032
+    *           The line width.
1033
+    * @param    {Number[]} strokeColor
1034
+    *           The array of 3 integer values between 0 and 255 inclusive, representing
1035
+    *           a stroke color.
1036
+    * @param    {Array} path
1037
+    *           The array of points that forms the outline of the target area.
1038
+    */
1039
+   this.applyStrokeToPath = function(context, strokeStyle, width, strokeColor, path)
1040
+   {
1041
+      if (context instanceof CanvasRenderingContext2D)
1042
+      {
1043
+         var renderer = getStrokePathRenderer(context, strokeStyle, width, strokeColor);
1044
+         renderer.applyStroke(path);
1045
+      }
1046
+   }
1047
+   
1048
+   
1049
+   this.isDirectDrawingStrokeStyle = function(strokeStyle)
1050
+   {
1051
+      return LineStrokeEnum.DEFAULT == strokeStyle;
1052
+   }
1053
+   
1054
+   this.getDefaultStrokeStyle = function()
1055
+   {
1056
+      return LineStrokeEnum.DEFAULT;
1057
+   }
1058
+   
1059
+   /**
1060
+    * Used to draw dash patterns on lines of pixels.
1061
+    * 
1062
+    * @param    {CanvasRenderingContext2D} context
1063
+    *           The canvas renderer.
1064
+    * @param    {Object} basicStroke
1065
+    *           The stroke style object.
1066
+    * @param    {Number[]} strokeColor
1067
+    *           The array of 3 integer values between 0 and 255 inclusive, representing
1068
+    *           a stroke color.
1069
+    */
1070
+   function DotsPathRenderer(ctx, basicStroke, strokeColor)
1071
+   {
1072
+      var pixel = ctx.createImageData(1, 1);
1073
+      var pixelData = pixel.data;
1074
+      pixelData[3] = 0xFF;
1075
+
1076
+      /**
1077
+       * Normalizes a dash offset distance according to the given dash pattern.
1078
+       * A normalized dash offset distance is a distance that is cut the corresponding segment
1079
+       * from the dash pattern that is extended periodically in order to cover the target dash
1080
+       * offset.
1081
+       * 
1082
+       * @param    {Array} dash
1083
+       *           The dash array that specifies the number of units to be drawn followed
1084
+       *           by the number of units to be skipped.
1085
+       * @param    {Number} dashOffset
1086
+       *           The offset distance from the first pattern point to the point which becomes
1087
+       *           a start point of the dash pattern.
1088
+       * 
1089
+       * @return   The container {startPhase : phase, startDashOn : dashOn, startIdx : idx},
1090
+       *           where the startPhase field holds a normalized dash offset, startDashOn defines
1091
+       *           to draw or to skip, the value of startIdx is the current dash pattern index.
1092
+       */
1093
+      function normalize(dash, dashOffset)
1094
+      {
1095
+         var phase = dashOffset;
1096
+         var idx = 0;
1097
+         var dashOn = true;
1098
+         var d;
1099
+         while (phase >= (d = dash[idx]))
1100
+         {
1101
+             phase -= d;
1102
+             idx = (idx + 1) % dash.length;
1103
+             dashOn = !dashOn;
1104
+         }
1105
+
1106
+         return {startPhase : phase, startDashOn : dashOn, startIdx : idx};
1107
+      }
1108
+      
1109
+      /**
1110
+       * Apply the given stroke to the line of pixels called a path.
1111
+       * 
1112
+       * @param    {Array} path
1113
+       *           The array of points that forms the outline of the target area.
1114
+       */
1115
+      this.applyStroke = function (path)
1116
+      {
1117
+         var dash = basicStroke.getDash();
1118
+         if (!dash || dash.length == 0)
1119
+         {
1120
+            return;
1121
+         }
1122
+         var dashOffset = basicStroke.getDashPhase();
1123
+         var len = dash.length;
1124
+         
1125
+         var patternObj = normalize(dash, dashOffset);
1126
+         
1127
+         var dashOn = patternObj.startDashOn;
1128
+         var phase  = patternObj.startPhase;
1129
+         var idx    = patternObj.startIdx;
1130
+         var rest = dash[idx] - phase;
1131
+         for (var i = 0; i < path.length; i++)
1132
+         {
1133
+            var point = path[i];
1134
+            if (rest < 1)
1135
+            {
1136
+               idx = (idx + 1) % len;
1137
+               rest = dash[idx];
1138
+               dashOn = !dashOn;
1139
+            }
1140
+            rest -= 1;
1141
+
1142
+            if (dashOn)
1143
+            {
1144
+               pixelData[0] = strokeColor[0];
1145
+               pixelData[1] = strokeColor[1];
1146
+               pixelData[2] = strokeColor[2];
1147
+               ctx.putImageData(pixel, point.x, point.y);
1148
+            }
1149
+         }
1150
+
1151
+      }
1152
+   }
1153
+   
1154
+   /**
1155
+    * Used to widen lines of pixels.
1156
+    * 
1157
+    * @param    {CanvasRenderingContext2D} context
1158
+    *           The canvas renderer.
1159
+    * @param    {Object} basicStroke
1160
+    *           The stroke style object.
1161
+    * @param    {Number[]} strokeColor
1162
+    *           The array of 3 integer values between 0 and 255 inclusive, representing
1163
+    *           a stroke color.
1164
+    */
1165
+   function WidenPathRenderer(ctx, basicStroke, strokeColor)
1166
+   {
1167
+      var width = basicStroke.getWidth();
1168
+      var image = ctx.createImageData(width, width);
1169
+      var imageData = image.data;
1170
+      
1171
+      for (var i = 0; i < 4 * width * width; i += 4)
1172
+      {
1173
+         imageData[i] = strokeColor[0];
1174
+         imageData[i + 1] = strokeColor[1];
1175
+         imageData[i + 2] = strokeColor[2];
1176
+         imageData[i + 3] = 0xFF;
1177
+      }
1178
+
1179
+      /**
1180
+       * To widen the line of pixels called a path according to the stroke style.
1181
+       * 
1182
+       * @param    {Array} path
1183
+       *           The array of points that forms the outline of the target area.
1184
+       */
1185
+      this.applyStroke = function (path)
1186
+      {
1187
+         for (var i = 0; i < path.length; i++)
1188
+         {
1189
+            var point = path[i];
1190
+            ctx.putImageData(image, point.x - (width >> 1), point.y - (width >> 1));
1191
+         }
1192
+      }
1193
+   }
1194
+}
1195
\ No newline at end of file
1196