source: trunk/tools/shared/deviceskin/deviceskin.cpp@ 1028

Last change on this file since 1028 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 26.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the tools applications of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "deviceskin.h"
43
44#include <QtCore/qnamespace.h>
45#include <QtGui/QApplication>
46#include <QtGui/QBitmap>
47#include <QtGui/QPixmap>
48#include <QtGui/QPainter>
49#include <QtCore/QTextStream>
50#include <QtCore/QFile>
51#include <QtCore/QFileInfo>
52#include <QtGui/QImage>
53#include <QtCore/QTimer>
54#include <QtCore/QDir>
55#include <QtCore/QRegExp>
56#include <QtGui/QMouseEvent>
57#include <QtCore/QDebug>
58
59#ifdef TEST_SKIN
60# include <QtGui/QMainWindow>
61# include <QtGui/QDialog>
62# include <QtGui/QDialogButtonBox>
63# include <QtGui/QHBoxLayout>
64#endif
65
66QT_BEGIN_NAMESPACE
67
68namespace {
69 enum { joydistance = 10, key_repeat_period = 50, key_repeat_delay = 500 };
70 enum { debugDeviceSkin = 0 };
71}
72
73static void parseRect(const QString &value, QRect *rect) {
74 const QStringList l = value.split(QLatin1Char(' '));
75 rect->setRect(l[0].toInt(), l[1].toInt(), l[2].toInt(), l[3].toInt());
76}
77
78static QString msgImageNotLoaded(const QString &f) {
79 return DeviceSkin::tr("The image file '%1' could not be loaded.").arg(f);
80}
81
82// ------------ DeviceSkinButtonArea
83DeviceSkinButtonArea::DeviceSkinButtonArea() :
84 keyCode(0),
85 activeWhenClosed(0)
86{
87}
88
89QDebug &operator<<(QDebug &str, const DeviceSkinButtonArea &a)
90{
91
92 str << "Area: " << a.name << " keyCode=" << a.keyCode << " area=" << a.area
93 << " text=" << a.text << " activeWhenClosed=" << a.activeWhenClosed;
94 return str;
95}
96
97// ------------ DeviceSkinParameters
98
99QDebug operator<<(QDebug str, const DeviceSkinParameters &p)
100{
101 str << "Images " << p.skinImageUpFileName << ','
102 << p.skinImageDownFileName<< ',' << p.skinImageClosedFileName
103 << ',' << p.skinCursorFileName <<"\nScreen: " << p.screenRect
104 << " back: " << p.backScreenRect << " closed: " << p.closedScreenRect
105 << " cursor: " << p.cursorHot << " Prefix: " << p.prefix
106 << " Joystick: " << p.joystick << " MouseHover" << p.hasMouseHover;
107 const int numAreas = p.buttonAreas.size();
108 for (int i = 0; i < numAreas; i++)
109 str << p.buttonAreas[i];
110 return str;
111}
112
113QSize DeviceSkinParameters::secondaryScreenSize() const
114{
115 return backScreenRect.isNull() ? closedScreenRect .size(): backScreenRect.size();
116}
117
118bool DeviceSkinParameters::hasSecondaryScreen() const
119{
120 return secondaryScreenSize() != QSize(0, 0);
121}
122
123bool DeviceSkinParameters::read(const QString &skinDirectory, ReadMode rm, QString *errorMessage)
124{
125 // Figure out the name. remove ending '/' if present
126 QString skinFile = skinDirectory;
127 if (skinFile.endsWith(QLatin1Char('/')))
128 skinFile.truncate(skinFile.length() - 1);
129
130 QFileInfo fi(skinFile);
131 QString fn;
132 if ( fi.isDir() ) {
133 prefix = skinFile;
134 prefix += QLatin1Char('/');
135 fn = prefix;
136 fn += fi.baseName();
137 fn += QLatin1String(".skin");
138 } else if (fi.isFile()){
139 fn = skinFile;
140 prefix = fi.path();
141 prefix += QLatin1Char('/');
142 } else {
143 *errorMessage = DeviceSkin::tr("The skin directory '%1' does not contain a configuration file.").arg(skinDirectory);
144 return false;
145 }
146 QFile f(fn);
147 if (!f.open(QIODevice::ReadOnly )) {
148 *errorMessage = DeviceSkin::tr("The skin configuration file '%1' could not be opened.").arg(fn);
149 return false;
150 }
151 QTextStream ts(&f);
152 const bool rc = read(ts, rm, errorMessage);
153 if (!rc)
154 *errorMessage = DeviceSkin::tr("The skin configuration file '%1' could not be read: %2").arg(fn).arg(*errorMessage);
155 return rc;
156}
157bool DeviceSkinParameters::read(QTextStream &ts, ReadMode rm, QString *errorMessage)
158{
159 QStringList closedAreas;
160 QStringList toggleAreas;
161 QStringList toggleActiveAreas;
162 int nareas = 0;
163 screenDepth = 0;
164 QString mark;
165 ts >> mark;
166 hasMouseHover = true; // historical default
167 if ( mark == QLatin1String("[SkinFile]") ) {
168 const QString UpKey = QLatin1String("Up");
169 const QString DownKey = QLatin1String("Down");
170 const QString ClosedKey = QLatin1String("Closed");
171 const QString ClosedAreasKey = QLatin1String("ClosedAreas");
172 const QString ScreenKey = QLatin1String("Screen");
173 const QString ScreenDepthKey = QLatin1String("ScreenDepth");
174 const QString BackScreenKey = QLatin1String("BackScreen");
175 const QString ClosedScreenKey = QLatin1String("ClosedScreen");
176 const QString CursorKey = QLatin1String("Cursor");
177 const QString AreasKey = QLatin1String("Areas");
178 const QString ToggleAreasKey = QLatin1String("ToggleAreas");
179 const QString ToggleActiveAreasKey = QLatin1String("ToggleActiveAreas");
180 const QString HasMouseHoverKey = QLatin1String("HasMouseHover");
181 // New
182 while (!nareas) {
183 QString line = ts.readLine();
184 if ( line.isNull() )
185 break;
186 if ( line[0] != QLatin1Char('#') && !line.isEmpty() ) {
187 int eq = line.indexOf(QLatin1Char('='));
188 if ( eq >= 0 ) {
189 const QString key = line.left(eq);
190 eq++;
191 while (eq<line.length()-1 && line[eq].isSpace())
192 eq++;
193 const QString value = line.mid(eq);
194 if ( key == UpKey ) {
195 skinImageUpFileName = value;
196 } else if ( key == DownKey ) {
197 skinImageDownFileName = value;
198 } else if ( key == ClosedKey ) {
199 skinImageClosedFileName = value;
200 } else if ( key == ClosedAreasKey ) {
201 closedAreas = value.split(QLatin1Char(' '));
202 } else if ( key == ScreenKey ) {
203 parseRect( value, &screenRect);
204 } else if ( key == ScreenDepthKey ) {
205 screenDepth = value.toInt();
206 } else if ( key == BackScreenKey ) {
207 parseRect(value, &backScreenRect);
208 } else if ( key == ClosedScreenKey ) {
209 parseRect( value, &closedScreenRect );
210 } else if ( key == CursorKey ) {
211 QStringList l = value.split(QLatin1Char(' '));
212 skinCursorFileName = l[0];
213 cursorHot = QPoint(l[1].toInt(),l[2].toInt());
214 } else if ( key == AreasKey ) {
215 nareas = value.toInt();
216 } else if ( key == ToggleAreasKey ) {
217 toggleAreas = value.split(QLatin1Char(' '));
218 } else if ( key == ToggleActiveAreasKey ) {
219 toggleActiveAreas = value.split(QLatin1Char(' '));
220 } else if ( key == HasMouseHoverKey ) {
221 hasMouseHover = value == QLatin1String("true") || value == QLatin1String("1");
222 }
223 } else {
224 *errorMessage = DeviceSkin::tr("Syntax error: %1").arg(line);
225 return false;
226 }
227 }
228 }
229 } else {
230 // Old
231 skinImageUpFileName = mark;
232 QString s;
233 int x,y,w,h,na;
234 ts >> s >> x >> y >> w >> h >> na;
235 skinImageDownFileName = s;
236 screenRect.setRect(x, y, w, h);
237 nareas = na;
238 }
239 // Done for short mode
240 if (rm == ReadSizeOnly)
241 return true;
242 // verify skin files exist
243 skinImageUpFileName.insert(0, prefix);
244 if (!QFile(skinImageUpFileName).exists()) {
245 *errorMessage = DeviceSkin::tr("The skin \"up\" image file '%1' does not exist.").arg(skinImageUpFileName);
246 return false;
247 }
248 if (!skinImageUp.load(skinImageUpFileName)) {
249 *errorMessage = msgImageNotLoaded(skinImageUpFileName);
250 return false;
251 }
252
253 skinImageDownFileName.insert(0, prefix);
254 if (!QFile(skinImageDownFileName).exists()) {
255 *errorMessage = DeviceSkin::tr("The skin \"down\" image file '%1' does not exist.").arg(skinImageDownFileName);
256 return false;
257 }
258 if (!skinImageDown.load(skinImageDownFileName)) {
259 *errorMessage = msgImageNotLoaded(skinImageDownFileName);
260 return false;
261 }
262
263 if (!skinImageClosedFileName.isEmpty()) {
264 skinImageClosedFileName.insert(0, prefix);
265 if (!QFile(skinImageClosedFileName).exists()) {
266 *errorMessage = DeviceSkin::tr("The skin \"closed\" image file '%1' does not exist.").arg(skinImageClosedFileName);
267 return false;
268 }
269 if (!skinImageClosed.load(skinImageClosedFileName)) {
270 *errorMessage = msgImageNotLoaded(skinImageClosedFileName);
271 return false;
272 }
273 }
274
275 if (!skinCursorFileName.isEmpty()) {
276 skinCursorFileName.insert(0, prefix);
277 if (!QFile(skinCursorFileName).exists()) {
278 *errorMessage = DeviceSkin::tr("The skin cursor image file '%1' does not exist.").arg(skinCursorFileName);
279 return false;
280 }
281 if (!skinCursor.load(skinCursorFileName)) {
282 *errorMessage = msgImageNotLoaded(skinCursorFileName);
283 return false;
284 }
285 }
286
287 // read areas
288 if (!nareas)
289 return true;
290 buttonAreas.reserve(nareas);
291
292 int i = 0;
293 ts.readLine(); // eol
294 joystick = -1;
295 const QString Joystick = QLatin1String("Joystick");
296 while (i < nareas && !ts.atEnd() ) {
297 buttonAreas.push_back(DeviceSkinButtonArea());
298 DeviceSkinButtonArea &area = buttonAreas.back();
299 const QString line = ts.readLine();
300 if ( !line.isEmpty() && line[0] != QLatin1Char('#') ) {
301 const QStringList tok = line.split(QRegExp(QLatin1String("[ \t][ \t]*")));
302 if ( tok.count()<6 ) {
303 *errorMessage = DeviceSkin::tr("Syntax error in area definition: %1").arg(line);
304 return false;
305 } else {
306 area.name = tok[0];
307 QString k = tok[1];
308 if ( k.left(2).toLower() == QLatin1String("0x")) {
309 area.keyCode = k.mid(2).toInt(0,16);
310 } else {
311 area.keyCode = k.toInt();
312 }
313
314 int p=0;
315 for (int j=2; j < tok.count() - 1; ) {
316 const int x = tok[j++].toInt();
317 const int y = tok[j++].toInt();
318 area.area.putPoints(p++,1,x,y);
319 }
320
321 const QChar doubleQuote = QLatin1Char('"');
322 if ( area.name[0] == doubleQuote && area.name.endsWith(doubleQuote)) {
323 area.name.truncate(area.name.size() - 1);
324 area.name.remove(0, 1);
325 }
326 if ( area.name.length() == 1 )
327 area.text = area.name;
328 if ( area.name == Joystick)
329 joystick = i;
330 area.activeWhenClosed = closedAreas.contains(area.name)
331 || area.keyCode == Qt::Key_Flip; // must be to work
332 area.toggleArea = toggleAreas.contains(area.name);
333 area.toggleActiveArea = toggleActiveAreas.contains(area.name);
334 if ( area.toggleArea )
335 toggleAreaList += i;
336 i++;
337 }
338 }
339 }
340 if (i != nareas) {
341 qWarning() << DeviceSkin::tr("Mismatch in number of areas, expected %1, got %2.")
342 .arg(nareas).arg(i);
343 }
344 if (debugDeviceSkin)
345 qDebug() << *this;
346 return true;
347}
348
349// --------- CursorWindow declaration
350
351namespace qvfb_internal {
352
353class CursorWindow : public QWidget
354{
355public:
356 explicit CursorWindow(const QImage &cursor, QPoint hot, QWidget *sk);
357
358 void setView(QWidget*);
359 void setPos(QPoint);
360 bool handleMouseEvent(QEvent *ev);
361
362protected:
363 bool event( QEvent *);
364 bool eventFilter( QObject*, QEvent *);
365
366private:
367 QWidget *mouseRecipient;
368 QWidget *m_view;
369 QWidget *skin;
370 QPoint hotspot;
371};
372}
373
374// --------- Skin
375
376DeviceSkin::DeviceSkin(const DeviceSkinParameters &parameters, QWidget *p ) :
377 QWidget(p),
378 m_parameters(parameters),
379 buttonRegions(parameters.buttonAreas.size(), QRegion()),
380 parent(p),
381 m_view(0),
382 m_secondaryView(0),
383 buttonPressed(false),
384 buttonIndex(0),
385 cursorw(0),
386 joydown(0),
387 t_skinkey(new QTimer(this)),
388 t_parentmove(new QTimer(this)),
389 flipped_open(true)
390{
391 Q_ASSERT(p);
392 setMouseTracking(true);
393 setAttribute(Qt::WA_NoSystemBackground);
394
395 setZoom(1.0);
396 connect( t_skinkey, SIGNAL(timeout()), this, SLOT(skinKeyRepeat()) );
397 t_parentmove->setSingleShot( true );
398 connect( t_parentmove, SIGNAL(timeout()), this, SLOT(moveParent()) );
399}
400
401void DeviceSkin::skinKeyRepeat()
402{
403 if ( m_view ) {
404 const DeviceSkinButtonArea &area = m_parameters.buttonAreas[buttonIndex];
405 emit skinKeyReleaseEvent( area.keyCode,area.text, true );
406 emit skinKeyPressEvent( area.keyCode, area.text, true );
407 t_skinkey->start(key_repeat_period);
408 }
409}
410
411void DeviceSkin::calcRegions()
412{
413 const int numAreas = m_parameters.buttonAreas.size();
414 for (int i=0; i<numAreas; i++) {
415 QPolygon xa(m_parameters.buttonAreas[i].area.count());
416 int n = m_parameters.buttonAreas[i].area.count();
417 for (int p=0; p<n; p++) {
418 xa.setPoint(p,transform.map(m_parameters.buttonAreas[i].area[p]));
419 }
420 if ( n == 2 ) {
421 buttonRegions[i] = QRegion(xa.boundingRect());
422 } else {
423 buttonRegions[i] = QRegion(xa);
424 }
425 }
426}
427
428void DeviceSkin::loadImages()
429{
430 QImage iup = m_parameters.skinImageUp;
431 QImage idown = m_parameters.skinImageDown;
432
433 QImage iclosed;
434 const bool hasClosedImage = !m_parameters.skinImageClosed.isNull();
435
436 if (hasClosedImage)
437 iclosed = m_parameters.skinImageClosed;
438 QImage icurs;
439 const bool hasCursorImage = !m_parameters.skinCursor.isNull();
440 if (hasCursorImage)
441 icurs = m_parameters.skinCursor;
442
443 if (!transform.isIdentity()) {
444 iup = iup.transformed(transform, Qt::SmoothTransformation);
445 idown = idown.transformed(transform, Qt::SmoothTransformation);
446 if (hasClosedImage)
447 iclosed = iclosed.transformed(transform, Qt::SmoothTransformation);
448 if (hasCursorImage)
449 icurs = icurs.transformed(transform, Qt::SmoothTransformation);
450 }
451 const Qt::ImageConversionFlags conv = Qt::ThresholdAlphaDither|Qt::AvoidDither;
452 skinImageUp = QPixmap::fromImage(iup);
453 skinImageDown = QPixmap::fromImage(idown, conv);
454 if (hasClosedImage)
455 skinImageClosed = QPixmap::fromImage(iclosed, conv);
456 if (hasCursorImage)
457 skinCursor = QPixmap::fromImage(icurs, conv);
458
459 setFixedSize( skinImageUp.size() );
460 if (!skinImageUp.mask())
461 skinImageUp.setMask(skinImageUp.createHeuristicMask());
462 if (!skinImageClosed.mask())
463 skinImageClosed.setMask(skinImageClosed.createHeuristicMask());
464
465 QWidget* parent = parentWidget();
466 parent->setMask( skinImageUp.mask() );
467 parent->setFixedSize( skinImageUp.size() );
468
469 delete cursorw;
470 cursorw = 0;
471 if (hasCursorImage) {
472 cursorw = new qvfb_internal::CursorWindow(m_parameters.skinCursor, m_parameters.cursorHot, this);
473 if ( m_view )
474 cursorw->setView(m_view);
475 }
476}
477
478DeviceSkin::~DeviceSkin( )
479{
480 delete cursorw;
481}
482
483void DeviceSkin::setTransform( const QMatrix& wm )
484{
485 transform = QImage::trueMatrix(wm,m_parameters.skinImageUp.width(),m_parameters.skinImageUp.height());
486 calcRegions();
487 loadImages();
488 if ( m_view ) {
489 QPoint p = transform.map(QPolygon(m_parameters.screenRect)).boundingRect().topLeft();
490 m_view->move(p);
491 }
492 updateSecondaryScreen();
493}
494
495void DeviceSkin::setZoom( double z )
496{
497 setTransform(QMatrix().scale(z,z));
498}
499
500void DeviceSkin::updateSecondaryScreen()
501{
502 if (!m_secondaryView)
503 return;
504 if (flipped_open) {
505 if (m_parameters.backScreenRect.isNull()) {
506 m_secondaryView->hide();
507 } else {
508 m_secondaryView->move(transform.map(QPolygon(m_parameters.backScreenRect)).boundingRect().topLeft());
509 m_secondaryView->show();
510 }
511 } else {
512 if (m_parameters.closedScreenRect.isNull()) {
513 m_secondaryView->hide();
514 } else {
515 m_secondaryView->move(transform.map(QPolygon(m_parameters.closedScreenRect)).boundingRect().topLeft());
516 m_secondaryView->show();
517 }
518 }
519}
520
521void DeviceSkin::setView( QWidget *v )
522{
523 m_view = v;
524 m_view->setFocus();
525 m_view->move(transform.map(QPolygon(m_parameters.screenRect)).boundingRect().topLeft());
526 if ( cursorw )
527 cursorw->setView(v);
528}
529
530void DeviceSkin::setSecondaryView( QWidget *v )
531{
532 m_secondaryView = v;
533 updateSecondaryScreen();
534}
535
536void DeviceSkin::paintEvent( QPaintEvent *)
537{
538 QPainter p( this );
539 if ( flipped_open ) {
540 p.drawPixmap( 0, 0, skinImageUp );
541 } else {
542 p.drawPixmap( 0, 0, skinImageClosed );
543 }
544 QList<int> toDraw;
545 if ( buttonPressed == true ) {
546 toDraw += buttonIndex;
547 }
548 foreach (int toggle, m_parameters.toggleAreaList) {
549 const DeviceSkinButtonArea &ba = m_parameters.buttonAreas[toggle];
550 if ( flipped_open || ba.activeWhenClosed ) {
551 if ( ba.toggleArea && ba.toggleActiveArea )
552 toDraw += toggle;
553 }
554 }
555 foreach (int button, toDraw ) {
556 const DeviceSkinButtonArea &ba = m_parameters.buttonAreas[button];
557 const QRect r = buttonRegions[button].boundingRect();
558 if ( ba.area.count() > 2 )
559 p.setClipRegion(buttonRegions[button]);
560 p.drawPixmap( r.topLeft(), skinImageDown, r);
561 }
562}
563
564void DeviceSkin::mousePressEvent( QMouseEvent *e )
565{
566 if (e->button() == Qt::RightButton) {
567 emit popupMenu();
568 } else {
569 buttonPressed = false;
570
571 onjoyrelease = -1;
572 const int numAreas = m_parameters.buttonAreas.size();
573 for (int i = 0; i < numAreas ; i++) {
574 const DeviceSkinButtonArea &ba = m_parameters.buttonAreas[i];
575 if ( buttonRegions[i].contains( e->pos() ) ) {
576 if ( flipped_open || ba.activeWhenClosed ) {
577 if ( m_parameters.joystick == i ) {
578 joydown = true;
579 } else {
580 if ( joydown )
581 onjoyrelease = i;
582 else
583 startPress(i);
584 break;
585 if (debugDeviceSkin)// Debug message to be sure we are clicking the right areas
586 qDebug()<< m_parameters.buttonAreas[i].name << " clicked";
587 }
588 }
589 }
590 }
591 clickPos = e->pos();
592// This is handy for finding the areas to define rectangles for new skins
593 if (debugDeviceSkin)
594 qDebug()<< "Clicked in " << e->pos().x() << ',' << e->pos().y();
595 clickPos = e->pos();
596 }
597}
598
599void DeviceSkin::flip(bool open)
600{
601 if ( flipped_open == open )
602 return;
603 if ( open ) {
604 parent->setMask( skinImageUp.mask() );
605 emit skinKeyReleaseEvent( Qt::Key(Qt::Key_Flip), QString(), false);
606 } else {
607 parent->setMask( skinImageClosed.mask() );
608 emit skinKeyPressEvent( Qt::Key(Qt::Key_Flip), QString(), false);
609 }
610 flipped_open = open;
611 updateSecondaryScreen();
612 repaint();
613}
614
615void DeviceSkin::startPress(int i)
616{
617 buttonPressed = true;
618 buttonIndex = i;
619 if (m_view) {
620 const DeviceSkinButtonArea &ba = m_parameters.buttonAreas[buttonIndex];
621 if ( ba.keyCode == Qt::Key_Flip ) {
622 flip(!flipped_open);
623 } else if ( ba.toggleArea ) {
624 bool active = !ba.toggleActiveArea;
625 const_cast<DeviceSkinButtonArea &>(ba).toggleActiveArea = active;
626 if ( active )
627 emit skinKeyPressEvent( ba.keyCode, ba.text, false);
628 else
629 emit skinKeyReleaseEvent( ba.keyCode, ba.text, false);
630 } else {
631 emit skinKeyPressEvent( ba.keyCode, ba.text, false);
632 t_skinkey->start(key_repeat_delay);
633 }
634 repaint( buttonRegions[buttonIndex].boundingRect() );
635 }
636}
637
638void DeviceSkin::endPress()
639{
640 const DeviceSkinButtonArea &ba = m_parameters.buttonAreas[buttonIndex];
641 if (m_view && ba.keyCode != Qt::Key_Flip && !ba.toggleArea )
642 emit skinKeyReleaseEvent(ba.keyCode, ba.text, false );
643 t_skinkey->stop();
644 buttonPressed = false;
645 repaint( buttonRegions[buttonIndex].boundingRect() );
646}
647
648void DeviceSkin::mouseMoveEvent( QMouseEvent *e )
649{
650 if ( e->buttons() & Qt::LeftButton ) {
651 const int joystick = m_parameters.joystick;
652 QPoint newpos = e->globalPos() - clickPos;
653 if ( joydown ) {
654 int k1=0, k2=0;
655 if ( newpos.x() < -joydistance ) {
656 k1 = joystick+1;
657 } else if ( newpos.x() > +joydistance ) {
658 k1 = joystick+3;
659 }
660 if ( newpos.y() < -joydistance ) {
661 k2 = joystick+2;
662 } else if ( newpos.y() > +joydistance ) {
663 k2 = joystick+4;
664 }
665 if ( k1 || k2 ) {
666 if ( !buttonPressed ) {
667 onjoyrelease = -1;
668 if ( k1 && k2 ) {
669 startPress(k2);
670 endPress();
671 }
672 startPress(k1 ? k1 : k2);
673 }
674 } else if ( buttonPressed ) {
675 endPress();
676 }
677 } else if ( buttonPressed == false ) {
678 parentpos = newpos;
679 if ( !t_parentmove->isActive() )
680 t_parentmove->start(50);
681 }
682 }
683 if ( cursorw )
684 cursorw->setPos(e->globalPos());
685}
686
687void DeviceSkin::moveParent()
688{
689 parent->move( parentpos );
690}
691
692void DeviceSkin::mouseReleaseEvent( QMouseEvent * )
693{
694 if ( buttonPressed )
695 endPress();
696 if ( joydown ) {
697 joydown = false;
698 if ( onjoyrelease >= 0 ) {
699 startPress(onjoyrelease);
700 endPress();
701 }
702 }
703}
704
705bool DeviceSkin::hasCursor() const
706{
707 return !skinCursor.isNull();
708}
709
710// ------------------ CursorWindow implementation
711
712namespace qvfb_internal {
713
714bool CursorWindow::eventFilter( QObject *, QEvent *ev)
715{
716 handleMouseEvent(ev);
717 return false;
718}
719
720bool CursorWindow::event( QEvent *ev )
721{
722 if (handleMouseEvent(ev))
723 return true;
724 return QWidget::event(ev);
725}
726
727bool CursorWindow::handleMouseEvent(QEvent *ev)
728{
729 bool handledEvent = false;
730 static int inhere=0;
731 if ( !inhere ) {
732 inhere++;
733 if ( m_view ) {
734 if ( ev->type() >= QEvent::MouseButtonPress && ev->type() <= QEvent::MouseMove ) {
735 QMouseEvent *e = (QMouseEvent*)ev;
736 QPoint gp = e->globalPos();
737 QPoint vp = m_view->mapFromGlobal(gp);
738 QPoint sp = skin->mapFromGlobal(gp);
739 if ( e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonDblClick ) {
740 if ( m_view->rect().contains(vp) )
741 mouseRecipient = m_view;
742 else if ( skin->parentWidget()->geometry().contains(gp) )
743 mouseRecipient = skin;
744 else
745 mouseRecipient = 0;
746 }
747 if ( mouseRecipient ) {
748 setPos(gp);
749 QMouseEvent me(e->type(),mouseRecipient==skin ? sp : vp,gp,e->button(),e->buttons(),e->modifiers());
750 QApplication::sendEvent(mouseRecipient, &me);
751 } else if ( !skin->parentWidget()->geometry().contains(gp) ) {
752 hide();
753 } else {
754 setPos(gp);
755 }
756 if ( e->type() == QEvent::MouseButtonRelease )
757 mouseRecipient = 0;
758 handledEvent = true;
759 }
760 }
761 inhere--;
762 }
763 return handledEvent;
764}
765
766void CursorWindow::setView(QWidget* v)
767{
768 if ( m_view ) {
769 m_view->removeEventFilter(this);
770 m_view->removeEventFilter(this);
771 }
772 m_view = v;
773 m_view->installEventFilter(this);
774 m_view->installEventFilter(this);
775 mouseRecipient = 0;
776}
777
778CursorWindow::CursorWindow(const QImage &img, QPoint hot, QWidget* sk)
779 :QWidget(0),
780 m_view(0), skin(sk),
781 hotspot(hot)
782{
783 setWindowFlags( Qt::FramelessWindowHint );
784 mouseRecipient = 0;
785 setMouseTracking(true);
786#ifndef QT_NO_CURSOR
787 setCursor(Qt::BlankCursor);
788#endif
789 QPixmap p;
790 p = QPixmap::fromImage(img);
791 if (!p.mask()) {
792 if ( img.hasAlphaChannel() ) {
793 QBitmap bm;
794 bm = QPixmap::fromImage(img.createAlphaMask());
795 p.setMask( bm );
796 } else {
797 QBitmap bm;
798 bm = QPixmap::fromImage(img.createHeuristicMask());
799 p.setMask( bm );
800 }
801 }
802 QPalette palette;
803 palette.setBrush(backgroundRole(), QBrush(p));
804 setPalette(palette);
805 setFixedSize( p.size() );
806 if ( !p.mask().isNull() )
807 setMask( p.mask() );
808}
809
810void CursorWindow::setPos(QPoint p)
811{
812 move(p-hotspot);
813 show();
814 raise();
815}
816}
817
818#ifdef TEST_SKIN
819
820int main(int argc,char *argv[])
821{
822 if (argc < 1)
823 return 1;
824 const QString skinFile = QString::fromUtf8(argv[1]);
825 QApplication app(argc,argv);
826 QMainWindow mw;
827
828 DeviceSkinParameters params;
829 QString errorMessage;
830 if (!params.read(skinFile, DeviceSkinParameters::ReadAll, &errorMessage)) {
831 qWarning() << errorMessage;
832 return 1;
833 }
834 DeviceSkin ds(params, &mw);
835 // View Dialog
836 QDialog *dialog = new QDialog();
837 QHBoxLayout *dialogLayout = new QHBoxLayout();
838 dialog->setLayout(dialogLayout);
839 QDialogButtonBox *dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
840 QObject::connect(dialogButtonBox, SIGNAL(rejected()), dialog, SLOT(reject()));
841 QObject::connect(dialogButtonBox, SIGNAL(accepted()), dialog, SLOT(accept()));
842 dialogLayout->addWidget(dialogButtonBox);
843 dialog->setFixedSize(params.screenSize());
844 dialog->setParent(&ds, Qt::SubWindow);
845 dialog->setAutoFillBackground(true);
846 ds.setView(dialog);
847
848 QObject::connect(&ds, SIGNAL(popupMenu()), &mw, SLOT(close()));
849 QObject::connect(&ds, SIGNAL(skinKeyPressEvent(int,QString,bool)), &mw, SLOT(close()));
850 mw.show();
851 return app.exec();
852}
853
854#endif
855
856QT_END_NAMESPACE
857
Note: See TracBrowser for help on using the repository browser.