2 * Copyright (C) 2011 Lukáš Karas <lukas.karas@centrum.cz>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 import QtQuick 1.1 // version 1.1 include PinchArea
23 import MyTools 1.0 // for WheelArea
31 signal sendWbMessage(string sessionId, string xmlContent);
32 signal messageSent(string content);
34 property int canvasWidth : 640;
35 property int canvasHeight: 480;
36 //property string uid : "demo@makneto.org"
39 console.log("II [BoardWidget.qml]: "+msg);
42 console.log("EE [BoardWidget.qml]: "+msg);
45 console.log("WW [BoardWidget.qml]: "+msg);
48 //signal foregroundColorChanged(variant color)
49 signal whiteboardMessageReceived(string data, string contact)
50 property bool whiteboardInitialiyed: false
51 property variant queue: undefined
52 property int animationLength : 200;
54 function onWhiteboardMessageReceived(data, contact){
55 if (whiteboardInitialiyed){
56 whiteboardMessageReceived.disconnect(onWhiteboardMessageReceived);
60 if (queue===undefined)
64 obj.contact = contact;
70 //log("whiteboard is not initialized... "+JSON.stringify(queue.length));
73 function hideWebView(b){
74 wbView.opacity = b? 0:1;
75 log("HACK: hide wbView? "+b);
85 source: "img/fullscreen.png"
88 AnchorChanges { target: board; anchors.top: board.parent.top; anchors.left: board.parent.left; }
95 source: "img/minimize.png"
98 AnchorChanges { target: board; anchors.right: board.parent.right; anchors.bottom: board.parent.bottom}
106 duration: animationLength
111 id: onHeightAnimation
112 duration: animationLength
115 Behavior on opacity {
116 NumberAnimation{duration: animationLength}
119 transitions: Transition {
120 // smoothly reanchor myRect and move into new position
121 AnchorAnimation { duration: animationLength }
124 Component.onCompleted: {
125 whiteboardMessageReceived.connect(onWhiteboardMessageReceived);
126 //toolbar.foregroundColorChanged.connect(board.foregroundColorChanged);
132 anchors{top:parent.top; right: toolbar.left; left: parent.left; bottom: parent.bottom}
134 property int previousWidth : canvasWidth+30
135 property int previousHeith : canvasHeight+30
140 PinchArea -> resizeAfterPinch -> onSnapshotTaken -> SVG resizing -> canvasResized
142 For faster and smooth zooming, we use PinchArea with combination WebView scale property.
143 After touch gesture release, we call resizeAfterPinch(). This take snaphost (graber component)
144 of current WebView content (scaled) and overlap WebView.
145 When snapshot is taken and shown (onSnapshotTaken), we invoke SVG scaling inside WebView.
146 This operation is long (up to seconds) and not smooth. After SVG resizing is caled canvasResized()
147 method. We currently change WebView size, return scale to 1 and remove old screenshot...
151 width: canvasWidth * 3
152 height: canvasHeight * 3
155 settings.pluginsEnabled: false
157 property bool whiteboardInitialized : false;
158 property real previousX: 0
159 property real previousY: 0
163 javaScriptWindowObjects: [QtObject {
164 WebView.windowObjectName: "connector"
165 function getUID(){ return board.parent.sessionId; }
167 wbView.whiteboardInitialized = true;
168 log("html part of whiteboard is initialized! lets make big stufs...");
169 // html part is loaded, init MaknetoWhiteboard...
170 wbView.evaluateJavaScript ( 'MaknetoWhiteboard.instance.init('+board.canvasWidth+', '+board.canvasHeight+')' );
172 //var zoom = Math.min( wbView.width / (wbView.contentsSize.width *0.3), wbView.height / (wbView.contentsSize.height *0.3) );
173 //wbView.evaluateJavaScript ( '$("#workArea").scrollLeft(640)');
174 //wbView.calculateZoom();
175 wbView.evaluateJavaScript ( 'MaknetoWhiteboard.instance.setZoom('+ wbView.width / (canvasWidth*3) +')' );
177 whiteboardMessageReceived.connect(onWhiteboardMessageReceived);
178 toolbar.foregroundColorChanged.connect(onForegroundColorChanged);
179 messageSent.connect(onMessageSent);
180 whiteboardInitialiyed = true;
181 while (queue !== undefined && queue.length !== 0){
183 var obj = tmp.shift(); // take first element (from array begin)
185 //log("queue message: "+obj.data);
186 onWhiteboardMessageReceived(obj.data, obj.contact);
189 function onForegroundColorChanged(c){
190 //log("onForegroundColorChanged "+c);
191 wbView.evaluateJavaScript ( 'MaknetoWhiteboard.instance.setForegroundColor("'+c+'")' );
193 function onWhiteboardMessageReceived(data, contact){
194 wbView.evaluateJavaScript ( 'MaknetoWhiteboard.instance.processXmlCommand('+JSON.stringify(data)+')' );
195 //log("on whiteboard msg received from "+contact+" "+JSON.stringify(data));
197 function onMessageSent(content){
198 wbView.evaluateJavaScript ( 'MaknetoWhiteboard.instance.messageSent('+JSON.stringify(content)+')' );
200 function sendMessage(xmlMessage){
202 sendWbMessage(board.parent.sessionId, xmlMessage);
205 function enableRendering(b){
206 wbView.renderingEnabled = b;
208 function canvasResized(){
209 var originalWidth = wbView.width;
210 var originalHeight = wbView.height;
211 wbView.width = wbView.width * wbView.scale;
212 wbView.height= wbView.height* wbView.scale;
214 // move to new center
215 wbView.x = wbView.x + (originalWidth - wbView.width)*.5;
216 wbView.y = wbView.y + (originalHeight - wbView.height)*.5;
217 wbView.previousX = wbView.x;
218 wbView.previousY = wbView.y;
220 log("resizeAfterPinch "+wbView.scale+" "+Math.floor(originalWidth)+"x"+Math.floor(originalHeight)+
221 " => "+Math.floor(wbView.width)+"x"+Math.floor(wbView.height)+" ..."+Math.floor(wbView.x) +""+Math.floor(wbView.y)+"");
223 pinchy.pinch.minimumX = Math.max( (wbView.width / (-2/3)) , -(wbView.width - wrapper.width));
224 pinchy.pinch.minimumY = Math.max( (wbView.height / (-2/3)) , -(wbView.height - wrapper.height));
225 pinchy.pinch.maximumX = 0;
226 pinchy.pinch.maximumY = 0;
228 var minWscale = wrapper.width / wbView.width;
229 var minHscale = wrapper.height / wbView.height;
230 pinchy.pinch.minimumScale = Math.max(minHscale, minWscale);
231 var maxWscale = (wrapper.width*15) / wbView.width;
232 var maxHscale = (wrapper.height*15) / wbView.height;
233 pinchy.pinch.maximumScale = Math.min(maxHscale, maxWscale);
235 graber.state = "hide";
236 //graberTimer.start();
240 WebView.windowObjectName: "console"
241 function log(msg) { console.log("II [Whiteboard]: " + msg); }
242 function debug(msg) { console.log("DD [Whiteboard]: " + msg); }
243 function warn(msg) { console.log("WW [Whiteboard]: " + msg); }
244 function error(msg) { console.log("EE [Whiteboard]: " + msg); }
248 function resizeAfterPinch(){
250 // TODO: SHOW waiting cursor while resizing SVG image
251 graber.takeSnapshot();
252 graber.state = "visible";
255 onContentsSizeChanged: {
259 Component.onCompleted: {
260 wbView.previousX = wbView.x +15
261 wbView.previousY = wbView.y +15
264 //html: "<html><head><script>console.log(\"This is in WebKit!\"); window.connector.qmlCall();</script></head><body><h1>Qt WebKit!</h1></body></html>"
265 url:"qrc:/whiteboard/main.html"
278 PropertyChanges { target: graber; opacity: 0 }
279 PropertyChanges { target: scalingOverlay; opacity: 0 }
283 PropertyChanges { target: graber; opacity: 1 }
284 PropertyChanges { target: scalingOverlay; opacity: 0.2 }
289 from: "hide"; to: "visible"
290 NumberAnimation { target: graber; properties: "opacity"; duration: 0 }
291 // when webkit scaling svg image, renderign thread is busy, so we cant draw this nice animation
292 //NumberAnimation { target: scalingOverlay; properties: "opacity"; duration: 500 }
295 from: "visible"; to: "hide"
296 NumberAnimation { target: graber; properties: "opacity"; duration: 100 }
297 NumberAnimation { target: scalingOverlay; properties: "opacity"; duration: 5000 } // opacity is multipied by parent's opacity
301 log("snapshot taken");
302 wbView.evaluateJavaScript ( 'MaknetoWhiteboard.instance.setZoom('+ wbView.width * wbView.scale / (canvasWidth*3) +')' );
313 anchors{horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter}
316 // discard all mouse operations while scaling
317 PinchArea{ anchors.fill: parent; enabled: true}
318 MouseArea{ anchors.fill: parent }
319 WheelArea{ anchors.fill: parent }
323 //Rectangle { id: rect; color: "transparent"; border.color: "yellow"; x: 150; y: 150; height: 250; width: 250 }
326 * I don't know better solution detect when resize animations stops...
329 id: animationNotifier
330 interval: 300; running: false; repeat: false
332 wrapper.onDimensionChanged(false);
336 // while animation we using QML scale for webView
337 function onDimensionChanged(fast){
338 if (wrapper.width < 10 || wrapper.height < 10)
342 var minWscale = wrapper.width / wbView.width;
343 var minHscale = wrapper.height / wbView.height;
344 pinchy.pinch.minimumScale = Math.max(minHscale, minWscale);
346 var wSc = wrapper.width / previousWidth;
347 var hSc = wrapper.height / previousHeith;
348 wbView.scale = Math.max(pinchy.pinch.minimumScale, Math.min(wSc, hSc)); // FIXME: it is good?
349 wbView.x = wbView.previousX + (wrapper.width - previousWidth) / 2
350 wbView.y = wbView.previousY + (wrapper.height - previousHeith) / 2
353 log("fast scale to "+wbView.scale+"");
354 log(" "+Math.floor( wbView.previousX)+" + ("+Math.floor(wrapper.width)+" - "+Math.floor(previousWidth)+") / 2) = "+Math.floor( wbView.x)+"");
355 log(" "+Math.floor( wbView.previousY)+" + ("+Math.floor(wrapper.height)+" - "+Math.floor(previousHeith)+") / 2) = "+Math.floor( wbView.y)+"");
358 animationNotifier.stop();
359 animationNotifier.start();
361 wbView.resizeAfterPinch();
362 previousWidth = wrapper.width;
363 previousHeith = wrapper.height
368 onDimensionChanged(true);
371 onDimensionChanged(true);
376 enabled: graber.state == "hide"
379 pinch.dragAxis: Pinch.XandYAxis
380 pinch.minimumScale: 1
381 pinch.maximumScale: 1
382 pinch.minimumX: -canvasWidth*2
384 pinch.minimumY: -canvasHeight*2
386 //pinch.minimumRotation: -150
387 //pinch.maximumRotation: 150
390 log("onPinchStarted");
392 wbView.evaluateJavaScript("MaknetoWhiteboard.instance.whiteboard.mouseUp2()");
397 wbView.resizeAfterPinch();
402 * delayed mouse down event is workaround for late detected gestures.
408 interval: 200; running: false; repeat: false
410 log("delayed mouseDown");
411 wbView.evaluateJavaScript("MaknetoWhiteboard.instance.whiteboard.mouseDown2("+(mouseX-wbView.x)+", "+(mouseY-wbView.y)+",0)");
417 acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
421 property int startWbX;
422 property int startWbY;
423 property variant pressed;
426 //log("mouseArea: onPressed");
427 //mouse.accepted = false;
432 pressed = mouse.button;
434 if (mouse.button == Qt.LeftButton){
436 pressDelay.mouseX = mouse.x;
437 pressDelay.mouseY = mouse.y;
439 //wbView.evaluateJavaScript("MaknetoWhiteboard.instance.whiteboard.mouseDown2("+(mouseX-wbView.x)+", "+(mouseY-wbView.y)+",0)");
445 //log("mouseArea: onDoubleClicked");
448 //log("mouseArea: onPositionChanged");
451 //log("mouseArea: onPressAndHold");
454 //log("mouseArea: onReleased");
456 wbView.evaluateJavaScript("MaknetoWhiteboard.instance.whiteboard.mouseUp2()");
458 onMousePositionChanged: {
460 //log("mouseArea: onMousePositionChanged");
461 if (pressed == Qt.LeftButton){
463 wbView.evaluateJavaScript("MaknetoWhiteboard.instance.whiteboard.mouseMove2("+(mouse.x-wbView.x)+", "+(mouse.y-wbView.y)+")");
467 if (pressed == Qt.RightButton || pressed == Qt.MiddleButton){
470 wbView.x = (mouse.x - startX) + startWbX;
471 wbView.y = (mouse.y - startY) + startWbY;
472 if (wbView.x < pinchy.pinch.minimumX)
473 wbView.x = pinchy.pinch.minimumX;
474 if (wbView.y < pinchy.pinch.minimumY)
475 wbView.y = pinchy.pinch.minimumY;
476 if (wbView.x > pinchy.pinch.maximumX)
477 wbView.x = pinchy.pinch.maximumX;
478 if (wbView.y > pinchy.pinch.maximumY)
479 wbView.y = pinchy.pinch.maximumY;
480 //log(" ... move "+wbView.x+" "+pinchy.pinch.minimumX);
485 // we use wheel for zooming on desktop...
489 //console.log("Vertical Wheel: " + delta)
490 var scaleRange = pinchy.pinch.maximumScale - pinchy.pinch.minimumScale;
492 wbView.scale += scaleRange * (delta / 5000);
493 if (wbView.scale > pinchy.pinch.maximumScale)
494 wbView.scale = pinchy.pinch.maximumScale;
495 if (wbView.scale < pinchy.pinch.minimumScale)
496 wbView.scale = pinchy.pinch.minimumScale;
497 // FIXME: adjust position when we zoom out
499 animationNotifier.stop();
500 animationNotifier.start();
503 //console.log("Horizontal Wheel: " + delta)
509 //color: parent.color
510 anchors{bottom: parent.bottom; right: parent.right; top: parent.top}
511 BorderImage { source: "img/lineedit.sci"; anchors.fill: parent }
516 wbView.renderingEnabled = false;
517 wbView.renderingEnabled = true;
520 wbView.renderingEnabled = false;
521 wbView.renderingEnabled = true;