root/as3/gunyarapaint/trunk/gunyarapaint/src/gunyarapaint.as

リビジョン 3223, 19.2 kB (コミッタ: tasuku, コミット時期: 4 年 前)

* gunyarapaint: ロゴの埋め込みがうまくいっていなかった。修正。

Line 
1 private const DEBUG:Boolean = false;
2
3 import flash.display.InteractiveObject;
4 import flash.events.Event;
5 import flash.events.KeyboardEvent;
6 import flash.geom.Matrix;
7 import flash.geom.Point;
8 import flash.ui.Keyboard;
9 import flash.utils.ByteArray;
10
11 import mx.controls.Alert;
12 import mx.core.UIComponent;
13 import mx.core.UITextField;
14 import mx.events.FlexEvent;
15 import mx.events.ListEvent;
16 import mx.events.NumericStepperEvent;
17 import mx.events.ResizeEvent;
18 import mx.events.SliderEvent;
19 import mx.managers.PopUpManager;
20
21 import org.libspark.gunyarapaint.controls.GPPasswordWindowControl;
22 import org.libspark.gunyarapaint.entities.GPLogger;
23 import org.libspark.gunyarapaint.entities.GPPen;
24 import org.libspark.nicopedia.Com;
25
26 private var basex:uint, basey:uint, baseWidth:uint, baseHeight:uint;
27
28 private var oekakiId:uint;
29 private var redirectUrl:String;
30
31 private var _logger:GPLogger;
32
33 private const ALERT_TITLE:String = 'お絵カキコ';
34 private const MAX_CANVAS_WIDTH:uint = 500;
35 private const MAX_CANVAS_HEIGHT:uint = 500;
36 private const MIN_CANVAS_WIDTH:uint = 16;
37 private const MIN_CANVAS_HEIGHT:uint = 16;
38
39 // ポップアップの初期位置
40 private var initCanvasWindowPos:Point;
41 private var initPenDetailWindowPos:Point;
42 private var initGPLayerWindowPos:Point;
43 private var initCanvasWindowSize:Point;
44
45 public function init():void {
46   var width:uint, height:uint, undoBufferSize:uint;
47
48   if (DEBUG) {
49     versionLabel.text += 'debug';
50     /*
51     parameters['oekakiId'] = 23724;
52     parameters['baseImgUrl'] = 'http://dic.nicovideo.jp/oekaki_layers/23724';
53     parameters['baseImgInfoUrl'] = 'http://dic.nicovideo.jp/oekaki_info/23724';
54     */
55     parameters['postUrl'] = 'http://dic.dev.nicovideo.jp/';
56     parameters['cookie'] = 'cookie';
57     parameters['magic'] = 'magic';
58     parameters['redirectUrl'] = 'http://dic.dev.nicovideo.jp/';
59     parameters['undoBufferSize'] = 16;
60     parameters['canvasWidth'] = 417;
61     parameters['canvasHeight'] = 317;
62     // debug buttons
63     logPlayButton.addEventListener(FlexEvent.BUTTON_DOWN, playLogHandler);
64     logPlayButton.visible = true;
65     checkPngButton.visible = true;
66   }
67
68   this.enabled = false;
69   gpCanvasWindow.enabled = false;
70   penDetailWindow.enabled = false;
71   gpLayerWindow.enabled = false;
72
73   // リサイズ
74   this.addEventListener(ResizeEvent.RESIZE, appResizeHandler);
75
76   // キャンバス回転スライダ
77   canvasZoom.addEventListener(SliderEvent.CHANGE, canvasZoomHandler);
78   canvasZoom.addEventListener(SliderEvent.THUMB_DRAG, canvasZoomHandler);
79   canvasRotate.addEventListener(SliderEvent.CHANGE, canvasRotateHandler);
80   canvasRotate.addEventListener(SliderEvent.THUMB_DRAG, canvasRotateHandler);
81   zoomResetButton.addEventListener(FlexEvent.BUTTON_DOWN, zoomResetButtonHandler);
82   rotateResetButton.addEventListener(FlexEvent.BUTTON_DOWN, rotateResetButtonHandler);
83   horizontalMirrorButton.addEventListener(FlexEvent.BUTTON_DOWN, horizontalMirrorButtonHandler);
84   verticalMirrorButton.addEventListener(FlexEvent.BUTTON_DOWN, verticalMirrorButtonHandler);
85
86   // 20090905-haku2 ins start
87   // 数値入力によるスライダ補助
88   canvasZoomValue.addEventListener(FlexEvent.ENTER, canvasZoomValueHandler);
89   canvasRotateValue.addEventListener(FlexEvent.ENTER, canvasRotateValueHandler);
90   // 20090905-haku2 ins end
91  
92   // アンドゥ・リドゥ
93   undoButton.addEventListener(FlexEvent.BUTTON_DOWN, undoButtonHandler);
94   redoButton.addEventListener(FlexEvent.BUTTON_DOWN, redoButtonHandler);
95    
96   // 補助線
97   additionalNumberStepper.addEventListener(NumericStepperEvent.CHANGE, additionalNumberStepperHandler);
98   additionalBoxCheckBox.addEventListener(Event.CHANGE, additionalBoxCheckBoxHandler);
99   additionalSkewCheckBox.addEventListener(Event.CHANGE, additionalSkewCheckBoxHandler);
100   // 20090906-haku2 ins start
101   // 補助線モード選択コンボ初期化
102   additionalTypeComboBox.dataProvider = [
103     {label: '分割', data: 0},
104     {label: 'px単位', data: 1}];
105   additionalTypeComboBox.addEventListener(ListEvent.CHANGE, additionalTypeComboBoxHandler);
106   // 20090906-haku2 ins end
107  
108   // 投稿
109   postOekakiButton.addEventListener(FlexEvent.BUTTON_DOWN, postOekakiButtonHandler);
110
111   // window状態
112   windowsResetButton.addEventListener(FlexEvent.BUTTON_DOWN, windowsResetButtonHandler);
113   // ふっかつのじゅもん
114   passwordButton.addEventListener(FlexEvent.BUTTON_DOWN, passwordButtonHandler);
115
116   // ポップアップさせて、そいつらの初期位置を覚える
117
118   PopUpManager.addPopUp(gpCanvasWindow, this);
119   PopUpManager.addPopUp(penDetailWindow, this);
120   PopUpManager.addPopUp(gpLayerWindow, this);
121   initCanvasWindowPos = new Point(gpCanvasWindow.x, gpCanvasWindow.y);
122   initPenDetailWindowPos = new Point(penDetailWindow.x, penDetailWindow.y);
123   initGPLayerWindowPos = new Point(gpLayerWindow.x, gpLayerWindow.y);
124   initCanvasWindowSize = new Point(gpCanvasWindow.width, gpCanvasWindow.height);
125
126   if (parameters['postUrl'] && parameters['cookie'] && parameters['magic'] && parameters['redirectUrl']) {
127     postOekakiButton.enabled = true;
128     redirectUrl = parameters['redirectUrl'];
129   }
130   if (parameters['undoBufferSize']) {
131     undoBufferSize = int(parameters['undoBufferSize']);
132     if (undoBufferSize < 0) {
133       Alert.show('最大アンドゥ回数が少なすぎます。', ALERT_TITLE);     
134     }
135     if (undoBufferSize > 32) {
136       Alert.show('最大アンドゥ回数が多すぎます。', ALERT_TITLE);     
137     }
138   } else {
139     return;
140   }
141   if (parameters['oekakiId'] && parameters['baseImgUrl']) {
142     oekakiId = uint(parameters['oekakiId']);
143     new Com().loadURL(parameters['baseImgUrl'], getBaseImgHandler);
144   } else {
145     if (parameters['canvasWidth'] && parameters['canvasHeight']) {
146       width = int(parameters['canvasWidth']);
147       height = int(parameters['canvasHeight']);
148       if (width < MIN_CANVAS_WIDTH || height < MIN_CANVAS_HEIGHT) {
149         Alert.show('キャンバスサイズが小さすぎます。', ALERT_TITLE);
150         return;
151       }
152       if (width > MAX_CANVAS_WIDTH || height > MAX_CANVAS_HEIGHT) {
153         Alert.show('キャンバスサイズが大きすぎます。', ALERT_TITLE);
154         return;
155       }
156     } else {
157       return;
158     }
159     _logger = GPLogger.createForDraw(width, height, undoBufferSize, null, null);
160     relocateComponents();
161   }
162 }
163
164 // ウィンドウ全体のリサイズ
165 private function appResizeHandler(e:ResizeEvent):void {
166   relocateComponents();
167 }
168
169 // ふっかつのじゅもんからの復活
170
171 public function deserialize(s:String):void {
172   // TODO: 実装
173   // var log:GPLogger = GPLogger.deserialize(s);
174 }
175
176 private function windowsResetButtonHandler(evt:FlexEvent):void {
177   gpCanvasWindow.rotateCanvas(0);
178  
179   gpCanvasWindow.transform.matrix = new Matrix(1, 0, 0, 1, initCanvasWindowPos.x, initCanvasWindowPos.y);
180   penDetailWindow.move(initPenDetailWindowPos.x, initPenDetailWindowPos.y);
181   gpLayerWindow.move(initGPLayerWindowPos.x, initGPLayerWindowPos.y);
182   gpCanvasWindow.width = initCanvasWindowSize.x;
183   gpCanvasWindow.height = initCanvasWindowSize.y;
184  
185   setRotate(0);
186   setZoom(1);
187 }
188
189 private function passwordButtonHandler(evt:FlexEvent):void {
190   var w:GPPasswordWindowControl = new GPPasswordWindowControl();
191   mx.managers.PopUpManager.addPopUp(w, this, true);
192   // w.password = gpCanvas.logger.password;
193 }
194
195 private function appComplete():void {
196   stage.addEventListener(KeyboardEvent.KEY_DOWN, shortCutKeyDownHandler); 
197   stage.addEventListener(KeyboardEvent.KEY_UP, shortCutKeyUpHandler); 
198   stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
199   stage.addEventListener(MouseEvent.MOUSE_OUT, mouseUpHandler); // これを入れるとマズい。
200 }
201
202 // canvasでの外のmouseUpをcanvasに通知 
203 private function mouseUpHandler(evt:MouseEvent):void {
204   if (_logger) {
205     _logger.extMouseUp(evt);
206   }
207 }
208 private function set allEnabled(value:Boolean):void {
209   this.enabled = value;
210   gpCanvasWindow.enabled = value;
211   penDetailWindow.enabled = value;
212   gpLayerWindow.enabled = value;
213 }
214 private function relocateComponents():void {
215   toolCanvas.x = (this.width - toolCanvas.width) / 2;
216   allEnabled = true;
217 }
218
219 // TODO: もう本当に汚い… これのスコープを短くする。
220 private var baseImg:BitmapData;
221
222 private function getBaseImgHandler(com:Com):void {
223   baseImg = Bitmap(com.content).bitmapData;
224   if (parameters['baseImgInfoUrl']) {
225     new Com().sendGetUrlRequest(parameters['baseImgInfoUrl'], getBaseImgInfoHandler);
226   } else {
227     // 画像のサイズがそのままwidth/height
228     // このロジックは通らなくなっているはずだが、移行措置のため残してある。
229     // 消してもよい。
230     baseImgToCanvas(baseImg.width, baseImg.height, parameters['undoBufferSize'], null);
231   }
232 }
233
234 private function getBaseImgInfoHandler(com:Com):void {
235   var info:Object = com.jsonObject;
236   if (!info) {
237     info = {'width': baseImg.width, 'height': baseImg.height};
238   }
239   baseImgToCanvas(info['width'], info['height'], parameters['undoBufferSize'], info);
240 }
241
242 private function baseImgToCanvas(width:uint, height:uint, undoBufferSize:uint, baseInfo:Object):void {
243     _logger = GPLogger.createForDraw(width, height, undoBufferSize,
244                                      baseImg, baseInfo);
245     gpCanvasWindow.logger = _logger;
246     relocateComponents();
247     this.enabled = true; 
248 }
249
250 private function canvasZoomHandler(evt:SliderEvent):void {
251   // 20090905-haku2 ins start
252   // 拡大率をテキストボックスに反映
253   if (evt.value >= 1) {
254     canvasZoomValue.text = String(Math.round(evt.value * 10000)/100);
255   } else {
256     canvasZoomValue.text = String(Math.round((1.0 / (-evt.value + 2)) * 10000)/100);
257   }
258   // 20090905-haku2 ins end
259   gpCanvasWindow.zoomCanvas(evt.value);
260 }
261 // 20090909-haku2 upd start
262 // 数値入力で拡大率指定
263 private function canvasZoomValueHandler(evt:Event):void {
264   var rm:Number = Number(canvasZoomValue.text);
265   if (rm <= 0) {
266     rm = 1;
267   } else if (rm >= 100) {
268     rm /= 100;
269   } else {
270     rm = -(100 / rm) + 2;
271   }
272   canvasZoom.value = rm;
273   gpCanvasWindow.zoomCanvas(canvasZoom.value);
274 }
275 // 20090909-haku2 upd end
276
277 private function canvasRotateHandler(evt:SliderEvent):void {
278   canvasRotateValue.text = String(-evt.value); // 20090905-haku2 ins キャンバス回転角度をテキストボックスに反映
279   gpCanvasWindow.rotateCanvas(evt.value);
280 }
281 // 20090909-haku2 upd start
282 // 数値入力でキャンバス回転角度指定
283 private function canvasRotateValueHandler(evt:Event):void {
284   canvasRotate.value = Number(canvasRotateValue.text);
285   gpCanvasWindow.rotateCanvas(canvasRotate.value);
286 }
287 // 20090909-haku2 upd end
288
289 private function undoButtonHandler(evt:FlexEvent):void {
290   _logger.eventUndo();
291 }
292 private function redoButtonHandler(evt:FlexEvent):void {
293   _logger.eventRedo();
294 }
295 private function additionalNumberStepperHandler(evt:NumericStepperEvent):void {
296   _logger.eventSetAdditionalNumber(evt.value);
297 }
298 private function additionalBoxCheckBoxHandler(evt:Event):void {
299   _logger.eventSetAdditionalBox(evt.target.selected);
300 }
301 private function additionalSkewCheckBoxHandler(evt:Event):void {
302   _logger.eventSetAdditionalSkew(evt.target.selected);
303 }
304 // 20090906-haku2 ins start
305 // 補助線種類の変更
306 private function additionalTypeComboBoxHandler(evt:ListEvent):void {
307   var n:Number = additionalNumberStepper.value;
308   additionalNumberStepper.value = _logger.additionalNumBk;
309   _logger.additionalNumBk = n;
310   _logger.additionalType = additionalTypeComboBox.selectedIndex;
311   if (_logger.additionalType == 0) {
312     additionalNumberStepper.minimum = 2;
313     additionalNumberStepper.maximum = 16;
314   } else {
315     additionalNumberStepper.minimum = 4;
316     additionalNumberStepper.maximum = 80;
317   }
318   _logger.eventSetAdditionalNumber(additionalNumberStepper.value);
319 }
320 // 20090906-haku2 ins end
321 public function changeUndoRedoHandler(undoCount:uint, redoCount:uint):void {
322   if (undoCount > 0) {
323     undoButton.label = 'アンドゥ (' + undoCount + ')';
324     undoButton.enabled = true;
325   } else {
326     undoButton.label = 'アンドゥ';
327     undoButton.enabled = false;
328   }
329   if (redoCount > 0) {
330     redoButton.label = 'リドゥ (' + redoCount + ')';
331     redoButton.enabled = true;
332   } else {
333     redoButton.label = 'リドゥ';
334     redoButton.enabled = false;
335   }
336 }
337
338 private function commCompleteHandler(com:Com):void {
339   try {
340     if (com.errStr) {
341       // error
342       Alert.show(com.errStr, ALERT_TITLE);
343     } else if (com.data.toString() != '') {
344       Alert.show(com.data.toString(), ALERT_TITLE);
345     } else {
346       // redirect
347       Com.redirect(redirectUrl);
348       return;
349     }
350   } catch (e:Error) {
351     Alert.show('何かしらのエラーが起きました…再投稿お願いいたします。', ALERT_TITLE);
352   }
353   allEnabled = true;
354   extChangeAlertOnUnload(true);
355 }
356
357 private function postOekakiButtonHandler(evt:Event):void {
358   if (titleTextInput.text == '') {
359     Alert.show('絵のタイトルが空です。', ALERT_TITLE);
360     return;
361   }
362   if (messageTextArea.text == '') {
363     Alert.show('書き込みが空です。', ALERT_TITLE);
364     return;
365   }
366   if (_logger.logCount == 0) {
367     Alert.show('絵が描かれていません。お絵かきしてください。', ALERT_TITLE);
368     return;
369   }
370   try {
371     allEnabled = false;
372     extChangeAlertOnUnload(false);
373     var com:Com = new Com();
374     com.postOekaki(this,
375                    parameters['postUrl'],
376                    parameters['magic'],
377                    parameters['cookie'],
378                    fromTextInput.text,
379                    titleTextInput.text,
380                    messageTextArea.text,
381                    watchlistCheckBox.selected,
382                    oekakiId,
383                    _logger.dataForPost,
384                    commCompleteHandler
385                   );
386   } catch (e:Error) {
387     allEnabled = true;
388     extChangeAlertOnUnload(true);
389     Alert.show(e.message, ALERT_TITLE);
390   }
391 }
392
393 private function rotateResetButtonHandler(evt:Event):void {
394   setRotate(0);
395   canvasRotateValue.text = "0"; // 20090905-haku2 ins 数値入力をリセット
396 }
397
398 private function zoomResetButtonHandler(evt:Event):void {
399   setZoom(1);
400   canvasZoomValue.text = "100"; // 20090905-haku2 ins 数値入力をリセット
401 }
402
403 private function horizontalMirrorButtonHandler(evt:Event):void {
404   _logger.eventHorizontalMirror(0xff);
405 }
406
407 private function verticalMirrorButtonHandler(evt:Event):void {
408   _logger.eventVerticalMirror(0xff);
409 }
410
411 private function setRotate(v:Number):void {
412   canvasRotate.value = v;
413   canvasRotateValue.text = String(-canvasRotate.value); // 20090909-haku2 ins キャンバス回転角度をテキストボックスに反映
414   gpCanvasWindow.rotateCanvas(canvasRotate.value);
415 }
416
417 private function setZoom(v:Number):void {
418   canvasZoom.value = v;
419   gpCanvasWindow.zoomCanvas(canvasZoom.value); 
420   // 20090909-haku2 ins start
421   // 拡大率をテキストボックスに反映
422   if (canvasZoom.value >= 1) {
423     canvasZoomValue.text = String(Math.round(canvasZoom.value * 10000)/100);
424   } else {
425     canvasZoomValue.text = String(Math.round((1.0 / (-canvasZoom.value + 2)) * 10000)/100);
426   }
427   // 20090909-haku2 ins end
428 }
429
430 private function checkShortCutControl():Boolean {
431   var fo:InteractiveObject = stage.focus;
432   return (fo is mx.core.UITextField);
433 }
434
435
436 private function shortCutKeyDownHandler(evt:KeyboardEvent):void {
437   if (checkShortCutControl()) {
438     return;
439   }
440   switch (evt.keyCode) {
441   case Keyboard.CONTROL:
442     penDetailWindow.penDetail.setTool(GPPen.PEN_MODE_DROPPER, null, true);
443     break;
444   case Keyboard.SHIFT:
445     break;
446   case Keyboard.SPACE:
447     penDetailWindow.penDetail.setTool(GPPen.PEN_MODE_HANDTOOL, null, true);
448     break;
449   case 48: // 0
450   case 96: // ten-key 0
451     if (evt.shiftKey) {
452       setRotate(0);
453     } else {
454       setZoom(1);
455     }
456     break;
457   case 65: // a
458     // Aキーの状態 = 押下中
459     _logger.key_A = true;
460     break;
461   case 73: // i
462     this.windowsResetButtonHandler(null);
463     break;
464   case 77: // m
465     this.horizontalMirrorButtonHandler(null);
466     break;
467   case 81: // q
468     // Qキーの状態 = 押下中
469     _logger.key_Q = true;
470     break;
471   case 82: // r
472     // Rキーの状態 = 押下中
473     _logger.key_R = true;
474     break;
475   // 20090905-haku2 ins start
476   case 84: // t
477     // Tキーの状態 = 押下中
478     _logger.key_T = true;
479     break;
480   // 20090905-haku2 ins end
481   case 89: // y
482     _logger.eventRedo();
483     break;
484   case 90: // z
485     _logger.eventUndo();
486     break;
487   case 107: // ten key +
488     // +
489     setZoom(canvasZoom.value + 1);
490     break;
491   case 109: // ten key -
492     // -
493     setZoom(canvasZoom.value - 1);
494     break;
495   case 187:
496     if (evt.shiftKey) {
497       // +
498       setZoom(canvasZoom.value + 1);
499     }
500     break;
501   case 189:
502     // -
503     setZoom(canvasZoom.value - 1);
504     break;
505   case 49: // 1
506   case 50: // 2
507   case 51: // 3
508   case 52: // 4
509   case 53: // 5
510   case 54: // 6
511   case 55: // 7
512   case 56: // 8
513   case 57: // 9
514     if (!evt.shiftKey) { // 念のため SHIFTキー対応 (テンキーのほうは放置)
515       penDetailWindow.penDetail.setPenSize(evt.keyCode - 48);
516     }
517     break;
518   case 97: // ten-key 1
519   case 98: // ten-key 2
520   case 99: // ten-key 3
521   case 100: // ten-key 4
522   case 101: // ten-key 5
523   case 102: // ten-key 6
524   case 103: // ten-key 7
525   case 104: // ten-key 8
526   case 105: // ten-key 9
527     penDetailWindow.penDetail.setPenSize(evt.keyCode - 96);
528     break;
529   case 45: // INS
530     if (!evt.shiftKey) {
531       setRotate(0);
532     }
533     break;
534   default:
535     // Alert('' + evt.keyCode);
536     break;
537   }
538 }
539
540 private function shortCutKeyUpHandler(evt:KeyboardEvent):void {
541   if (checkShortCutControl()) {
542     return;
543   }
544   switch (evt.keyCode) {
545   case Keyboard.CONTROL:
546     penDetailWindow.penDetail.resetPenTool();
547     break;
548   case Keyboard.SPACE:
549     penDetailWindow.penDetail.resetPenTool();
550     break;
551   case 65: // a
552     // Aキーの状態 = 解放
553     _logger.key_A = false;
554     break;
555   case 81: // q
556     // Qキーの状態 = 解放
557     _logger.key_Q = false;
558     break;
559   case 82: // r
560     // Rキーの状態 = 解放
561     _logger.key_R = false;
562     break;
563   // 20090905-haku2 ins start
564   case 84: // t
565     // Tキーの状態 = 解放
566     _logger.key_T = false;
567     break;
568   // 20090905-haku2 ins end
569   return;
570   }
571 }
572
573 /* for debug */
574
575 private var _debugLogger:GPLogger;
576 private function playLogHandler(evt:FlexEvent):void {
577   var lb:ByteArray = _logger.compressedLog;
578   lb.uncompress();
579   _debugLogger = GPLogger.createFromByteArray(lb, false, null, null);
580
581   var tui:UIComponent = new UIComponent();
582   tui.graphics.beginFill(0xFFFFFF);
583   tui.graphics.drawRect(0, 0, _debugLogger.canvasWidth, _debugLogger.canvasHeight);
584   tui.addChild(_debugLogger.layerArray.view);
585   this.addChild(tui);
586
587   // this.rawChildren.addChild(_debugLogger.layerArray.view);
588   _debugLogger.play(1000, function ():void {});
589 }
590
591 private function extChangeAlertOnUnload(b:Boolean):void {
592   if (ExternalInterface.available) {
593     try {
594       ExternalInterface.call("changeAlertOnUnload", b);
595     } catch (e:SecurityError) {
596     } catch (e:Error) {
597     }
598   }
599 }
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。