VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/softkeyboard/UISoftKeyboard.cpp@ 102493

Last change on this file since 102493 was 101658, checked in by vboxsync, 11 months ago

FE/Qt: bugref:6143. Drawing soft keyboard's multimedia keys resolution aware.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 155.3 KB
Line 
1/* $Id: UISoftKeyboard.cpp 101658 2023-10-30 13:38:39Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UISoftKeyboard class implementation.
4 */
5
6/*
7 * Copyright (C) 2016-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* Qt includes: */
29#include <QApplication>
30#include <QCheckBox>
31#include <QColorDialog>
32#include <QComboBox>
33#include <QDir>
34#include <QFile>
35#include <QGroupBox>
36#include <QInputDialog>
37#include <QHeaderView>
38#include <QLabel>
39#include <QLineEdit>
40#include <QListWidget>
41#include <QPainter>
42#include <QPicture>
43#include <QPushButton>
44#include <QSplitter>
45#include <QStatusBar>
46#include <QStyle>
47#include <QStackedWidget>
48#include <QToolButton>
49#include <QXmlStreamReader>
50#include <QVBoxLayout>
51
52/* GUI includes: */
53#include "UIDesktopWidgetWatchdog.h"
54#include "UIExtraDataManager.h"
55#include "UIHelpBrowserDialog.h"
56#include "UIIconPool.h"
57#include "UIMachine.h"
58#include "UIMessageCenter.h"
59#include "UIModalWindowManager.h"
60#include "UISoftKeyboard.h"
61#include "UICommon.h"
62#ifdef VBOX_WS_MAC
63# include "VBoxUtils-darwin.h"
64#endif
65
66/* External includes: */
67# include <math.h>
68
69/* Forward declarations: */
70class UISoftKeyboardColorButton;
71class UISoftKeyboardLayout;
72class UISoftKeyboardRow;
73class UISoftKeyboardWidget;
74
75const int iMessageTimeout = 3000;
76/** Key position are used to identify respective keys. */
77const int iCapsLockPosition = 30;
78const int iNumLockPosition = 90;
79const int iScrollLockPosition = 125;
80
81/** Set a generous file size limit. */
82const qint64 iFileSizeLimit = _256K;
83const QString strSubDirectorName("keyboardLayouts");
84
85/** Name, background color, normal font color, hover color, edited button background color, pressed button font color. */
86const char* predefinedColorThemes[][6] = {{"Clear Night","#000000", "#ffffff", "#859900", "#9b6767", "#000000"},
87 {"Gobi Dark","#002b36", "#fdf6e3", "#859900", "#cb4b16", "#002b36"},
88 {"Gobi Light","#fdf6e3", "#002b36", "#2aa198", "#cb4b16", "#bf4040"},
89 {0, 0, 0, 0, 0, 0}};
90
91typedef QPair<QLabel*, UISoftKeyboardColorButton*> ColorSelectLabelButton;
92
93enum KeyState
94{
95 KeyState_NotPressed,
96 KeyState_Pressed,
97 KeyState_Locked,
98 KeyState_Max
99};
100
101enum KeyType
102{
103 /** Can be in KeyState_NotPressed and KeyState_Pressed states. */
104 KeyType_Ordinary,
105 /** e.g. CapsLock, NumLock. Can be only in KeyState_NotPressed, KeyState_Locked */
106 KeyType_Lock,
107 /** e.g. Shift Can be in all 3 states*/
108 KeyType_Modifier,
109 KeyType_Max
110};
111
112enum KeyboardColorType
113{
114 KeyboardColorType_Background = 0,
115 KeyboardColorType_Font,
116 KeyboardColorType_Hover,
117 KeyboardColorType_Edit,
118 KeyboardColorType_Pressed,
119 KeyboardColorType_Max
120};
121
122enum KeyboardRegion
123{
124 KeyboardRegion_Main = 0,
125 KeyboardRegion_NumPad,
126 KeyboardRegion_MultimediaKeys,
127 KeyboardRegion_Max
128};
129
130struct UIKeyCaptions
131{
132 UIKeyCaptions(const QString &strBase, const QString &strShift,
133 const QString &strAltGr, const QString &strShiftAltGr)
134 : m_strBase(strBase)
135 , m_strShift(strShift)
136 , m_strAltGr(strAltGr)
137 , m_strShiftAltGr(strShiftAltGr)
138 {
139 m_strBase.replace("\\n", "\n");
140 m_strShift.replace("\\n", "\n");
141 m_strAltGr.replace("\\n", "\n");
142 m_strShiftAltGr.replace("\\n", "\n");
143 }
144 UIKeyCaptions(){}
145 bool operator==(const UIKeyCaptions &other) const
146 {
147 return (m_strBase == other.m_strBase &&
148 m_strShift == other.m_strShift &&
149 m_strAltGr == other.m_strAltGr &&
150 m_strShiftAltGr == other.m_strShiftAltGr);
151 }
152 QString m_strBase;
153 QString m_strShift;
154 QString m_strAltGr;
155 QString m_strShiftAltGr;
156};
157
158/** Returns a QPointF which lies on the line [p0, p1] and with a distance @p fDistance to p0. */
159QPointF pointInBetween(qreal fDistance, const QPointF &p0, const QPointF &p1)
160{
161 QPointF vectorP0P1 = p1 - p0;
162 qreal length = sqrt(vectorP0P1.x() * vectorP0P1.x() + vectorP0P1.y() * vectorP0P1.y());
163 if (length == 0)
164 return QPointF();
165 /* Normalize the vector and add it to starting point: */
166 vectorP0P1 = (fDistance / length) * vectorP0P1 + p0;
167 return vectorP0P1;
168}
169
170
171/*********************************************************************************************************************************
172* UISoftKeyboardColorButton definition. *
173*********************************************************************************************************************************/
174
175class UISoftKeyboardColorButton : public QPushButton
176{
177 Q_OBJECT;
178
179public:
180
181 UISoftKeyboardColorButton(KeyboardColorType enmColorType, QWidget *pParent = 0);
182 KeyboardColorType colorType() const;
183
184public:
185
186 KeyboardColorType m_enmColorType;
187};
188
189
190/*********************************************************************************************************************************
191* UISoftKeyboardPhysicalLayout definition. *
192*********************************************************************************************************************************/
193
194/** This class is used to represent the physical layout of a keyboard (in contrast to UISoftKeyboardLayout).
195 * Physical layouts are read from an xml file where keys are placed in rows. Each UISoftKeyboardLayout must refer to a
196 * refer to a UISoftKeyboardPhysicalLayout instance. An example of an UISoftKeyboardPhysicalLayout instance is 103 key ISO layout.*/
197class UISoftKeyboardPhysicalLayout
198{
199
200public:
201 UISoftKeyboardPhysicalLayout();
202
203 void setName(const QString &strName);
204 const QString &name() const;
205
206 void setFileName(const QString &strName);
207 const QString &fileName() const;
208
209 void setUid(const QUuid &uid);
210 const QUuid &uid() const;
211
212 const QVector<UISoftKeyboardRow> &rows() const;
213 QVector<UISoftKeyboardRow> &rows();
214
215 void setLockKey(int iKeyPosition, UISoftKeyboardKey *pKey);
216 void updateLockKeyStates(bool fCapsLockState, bool fNumLockState, bool fScrollLockState);
217 void reset();
218
219 void setDefaultKeyWidth(int iDefaultKeyWidth);
220 int defaultKeyWidth() const;
221
222 /** Returns the sum totalHeight() of all rows(). */
223 int totalHeight() const;
224
225private:
226
227 void updateLockKeyState(bool fLockState, UISoftKeyboardKey *pKey);
228 QString m_strFileName;
229 QUuid m_uId;
230 QString m_strName;
231 QVector<UISoftKeyboardRow> m_rows;
232 int m_iDefaultKeyWidth;
233 /** Scroll, Num, and Caps Lock keys' states are updated thru some API events. Thus we keep their pointers in a containter. */
234 QMap<int, UISoftKeyboardKey*> m_lockKeys;
235};
236
237/*********************************************************************************************************************************
238* UIKeyboardLayoutEditor definition. *
239*********************************************************************************************************************************/
240
241/** A QWidget extension thru which we can edit key captions, the physical layout of the keyboard, name of the layout etc. */
242class UIKeyboardLayoutEditor : public QIWithRetranslateUI<QWidget>
243{
244 Q_OBJECT;
245
246signals:
247
248 void sigLayoutEdited();
249 void sigUIKeyCaptionsEdited(UISoftKeyboardKey* pKey);
250 void sigGoBackButton();
251
252public:
253
254 UIKeyboardLayoutEditor(QWidget *pParent = 0);
255 void setKey(UISoftKeyboardKey *pKey);
256 void setLayoutToEdit(UISoftKeyboardLayout *pLayout);
257 void setPhysicalLayoutList(const QVector<UISoftKeyboardPhysicalLayout> &physicalLayouts);
258 void reset();
259
260protected:
261
262 virtual void retranslateUi() RT_OVERRIDE;
263
264private slots:
265
266 void sltCaptionsUpdate();
267 void sltPhysicalLayoutChanged();
268 void sltLayoutNameChanged(const QString &strCaption);
269 void sltLayoutNativeNameChanged(const QString &strCaption);
270
271private:
272
273 void prepareObjects();
274 void prepareConnections();
275 QWidget *prepareKeyCaptionEditWidgets();
276 void resetKeyWidgets();
277 QGridLayout *m_pEditorLayout;
278 QToolButton *m_pGoBackButton;
279 QGroupBox *m_pSelectedKeyGroupBox;
280 QGroupBox *m_pCaptionEditGroupBox;
281 QComboBox *m_pPhysicalLayoutCombo;
282 QLabel *m_pTitleLabel;
283 QLabel *m_pPhysicalLayoutLabel;
284 QLabel *m_pLayoutNameLabel;
285 QLabel *m_pLayoutNativeNameLabel;
286 QLabel *m_pScanCodeLabel;
287 QLabel *m_pPositionLabel;
288 QLabel *m_pBaseCaptionLabel;
289 QLabel *m_pShiftCaptionLabel;
290 QLabel *m_pAltGrCaptionLabel;
291 QLabel *m_pShiftAltGrCaptionLabel;
292 QLineEdit *m_pLayoutNameEdit;
293 QLineEdit *m_pLayoutNativeNameEdit;
294 QLineEdit *m_pScanCodeEdit;
295 QLineEdit *m_pPositionEdit;
296 QLineEdit *m_pBaseCaptionEdit;
297 QLineEdit *m_pShiftCaptionEdit;
298 QLineEdit *m_pAltGrCaptionEdit;
299 QLineEdit *m_pShiftAltGrCaptionEdit;
300
301 /** The key which is being currently edited. Might be Null. */
302 UISoftKeyboardKey *m_pKey;
303 /** The layout which is being currently edited. */
304 UISoftKeyboardLayout *m_pLayout;
305};
306
307/*********************************************************************************************************************************
308* UILayoutSelector definition. *
309*********************************************************************************************************************************/
310
311class UILayoutSelector : public QIWithRetranslateUI<QWidget>
312{
313
314 Q_OBJECT;
315
316signals:
317
318 void sigSaveLayout();
319 void sigCopyLayout();
320 void sigDeleteLayout();
321 void sigLayoutSelectionChanged(const QUuid &strSelectedLayoutUid);
322 void sigShowLayoutEditor();
323 void sigCloseLayoutList();
324
325public:
326
327 UILayoutSelector(QWidget *pParent = 0);
328 void setLayoutList(const QStringList &layoutNames, QList<QUuid> layoutIdList);
329 void setCurrentLayout(const QUuid &layoutUid);
330 void setCurrentLayoutIsEditable(bool fEditable);
331
332protected:
333
334 virtual void retranslateUi() RT_OVERRIDE;
335
336private slots:
337
338 void sltCurrentItemChanged(QListWidgetItem *pCurrent, QListWidgetItem *pPrevious);
339
340private:
341
342 void prepareObjects();
343
344 QListWidget *m_pLayoutListWidget;
345 QToolButton *m_pApplyLayoutButton;
346 QToolButton *m_pEditLayoutButton;
347 QToolButton *m_pCopyLayoutButton;
348 QToolButton *m_pSaveLayoutButton;
349 QToolButton *m_pDeleteLayoutButton;
350 QLabel *m_pTitleLabel;
351 QToolButton *m_pCloseButton;
352};
353
354/*********************************************************************************************************************************
355* UISoftKeyboardRow definition. *
356*********************************************************************************************************************************/
357
358/** UISoftKeyboardRow represents a row in the physical keyboard. The rows are read from a physical layout file and contained
359 * keys are added to rows in the order they appear in that file.*/
360class UISoftKeyboardRow
361{
362
363public:
364
365 UISoftKeyboardRow();
366
367 void setDefaultWidth(int iWidth);
368 int defaultWidth() const;
369
370 void setDefaultHeight(int iHeight);
371 int defaultHeight() const;
372
373 /* Return the sum of the maximum key height and m_iSpaceHeightAfter */
374 int totalHeight() const;
375
376 QVector<UISoftKeyboardKey> &keys();
377 const QVector<UISoftKeyboardKey> &keys() const;
378
379 void setSpaceHeightAfter(int iSpace);
380 int spaceHeightAfter() const;
381
382 int leftMargin() const;
383 void setLeftMargin(int iMargin);
384
385private:
386
387 /** Default width and height might be inherited from the layout and overwritten in row settings. */
388 int m_iDefaultWidth;
389 int m_iDefaultHeight;
390
391 QVector<UISoftKeyboardKey> m_keys;
392 int m_iSpaceHeightAfter;
393 /* The width of the empty space before the 1st key. */
394 int m_iLeftMargin;
395};
396
397/*********************************************************************************************************************************
398* UISoftKeyboardKey definition. *
399*********************************************************************************************************************************/
400
401/** UISoftKeyboardKey is a place holder for a keyboard key. Graphical key represantations are drawn according to this class.
402 * The position of a key within the physical layout is read from the layout file. Note that UISoftKeyboardKey usually does not have
403 * caption field(s). Captions are kept by UISoftKeyboardLayout since same keys may (and usually do) have different captions in
404 * different layouts. So called static captions are exceptions. They are defined in physical layout files and kept as member of
405 * UISoftKeyboardKey. When a static caption exits captions (if any) from the keyboard layout files are ignored. */
406class UISoftKeyboardKey
407{
408public:
409
410 UISoftKeyboardKey();
411
412 const QRect keyGeometry() const;
413 void setKeyGeometry(const QRect &rect);
414
415 void setWidth(int iWidth);
416 int width() const;
417
418 void setHeight(int iHeight);
419 int height() const;
420
421 void setScanCode(LONG scanCode);
422 LONG scanCode() const;
423
424 void addScanCodePrefix(LONG scanCode);
425
426 void setUsageId(LONG usageId);
427 void setUsagePage(LONG usagePage);
428 QPair<LONG, LONG> usagePageIdPair() const;
429
430 void setSpaceWidthAfter(int iSpace);
431 int spaceWidthAfter() const;
432
433 void setPosition(int iPosition);
434 int position() const;
435
436 void setType(KeyType enmType);
437 KeyType type() const;
438
439 KeyboardRegion keyboardRegion() const;
440 void setKeyboardRegion(KeyboardRegion enmRegion);
441
442 void setCutout(int iCorner, int iWidth, int iHeight);
443
444 KeyState state() const;
445 void setState(KeyState state);
446
447 void setStaticCaption(const QString &strCaption);
448 const QString &staticCaption() const;
449
450 void setImageByName(const QString &strCaption);
451 QPixmap image() const;
452
453 void setParentWidget(UISoftKeyboardWidget* pParent);
454 QVector<LONG> scanCodeWithPrefix() const;
455
456 void setIsOSMenuKey(bool fFlag);
457 bool isOSMenuKey() const;
458
459 void release();
460 void press();
461
462 void setPoints(const QVector<QPointF> &points);
463 const QVector<QPointF> &points() const;
464 const QPainterPath &painterPath() const;
465
466
467 void setCornerRadius(float fCornerRadius);
468
469 QPolygonF polygonInGlobal() const;
470
471 int cutoutCorner() const;
472 int cutoutWidth() const;
473 int cutoutHeight() const;
474
475 void updateLockState(bool fLocked);
476 void reset();
477
478private:
479
480 void updateState(bool fPressed);
481 /** Creates a path out of points m_points with rounded corners. */
482 void computePainterPath();
483
484 QRect m_keyGeometry;
485 /** Stores the key points (vertices) in local coordinates. */
486 QVector<QPointF> m_points;
487 /** We cache the path since re-computing that at each draw is meaningless. */
488 QPainterPath m_painterPath;
489 KeyType m_enmType;
490 KeyState m_enmState;
491 /** Key width as it is read from the xml file. */
492 int m_iWidth;
493 /** Key height as it is read from the xml file. */
494 int m_iHeight;
495 int m_iSpaceWidthAfter;
496 LONG m_scanCode;
497 QVector<LONG> m_scanCodePrefix;
498
499 /** @name Cutouts are used to create non-rectangle keys polygons.
500 * @{ */
501 int m_iCutoutWidth;
502 int m_iCutoutHeight;
503 /** -1 is for no cutout. 0 is the topleft, 2 is the top right and so on. */
504 int m_iCutoutCorner;
505 /** @} */
506
507 /** Key's position in the layout. */
508 int m_iPosition;
509 UISoftKeyboardWidget *m_pParentWidget;
510 LONG m_iUsageId;
511 LONG m_iUsagePage;
512 KeyboardRegion m_enmKeyboardRegion;
513 /** This is used for multimedia keys, OS key etc where we want to have a non-modifiable
514 * caption (usually a single char). This caption is defined in the physical layout file
515 * and has precedence over the captions defined in keyboard layout files. */
516 QString m_strStaticCaption;
517 bool m_fIsOSMenuKey;
518 double m_fCornerRadius;
519 QIcon m_icon;
520};
521
522
523/*********************************************************************************************************************************
524* UISoftKeyboardLayout definition. *
525*********************************************************************************************************************************/
526/** UISoftKeyboardLayout represents mainly a set of captions for the keys. It refers to a phsical layout which defines the
527 * positioning and number of keys (alongside with scan codes etc.). UISoftKeyboardLayout instances are read from xml files. An
528 * example for UISoftKeyboardLayout instance is 'US International' keyboard layout. */
529class UISoftKeyboardLayout
530{
531
532public:
533
534 UISoftKeyboardLayout();
535
536 void setName(const QString &strName);
537 const QString &name() const;
538
539 void setNativeName(const QString &strLocaName);
540 const QString &nativeName() const;
541
542 /** Combines name and native name and returns the string. */
543 QString nameString() const;
544
545 void setSourceFilePath(const QString& strSourceFilePath);
546 const QString& sourceFilePath() const;
547
548 void setIsFromResources(bool fIsFromResources);
549 bool isFromResources() const;
550
551 void setEditable(bool fEditable);
552 bool editable() const;
553
554 void setPhysicalLayoutUuid(const QUuid &uuid);
555 const QUuid &physicalLayoutUuid() const;
556
557 void addOrUpdateUIKeyCaptions(int iKeyPosition, const UIKeyCaptions &keyCaptions);
558 UIKeyCaptions keyCaptions(int iKeyPosition) const;
559
560 bool operator==(const UISoftKeyboardLayout &otherLayout) const;
561
562 QString baseCaption(int iKeyPosition) const;
563 QString shiftCaption(int iKeyPosition) const;
564
565 QString altGrCaption(int iKeyPosition) const;
566 QString shiftAltGrCaption(int iKeyPosition) const;
567
568 void setEditedBuNotSaved(bool fEditedButNotsaved);
569 bool editedButNotSaved() const;
570
571 void setUid(const QUuid &uid);
572 QUuid uid() const;
573
574 void drawTextInRect(const UISoftKeyboardKey &key, QPainter &painter);
575 void drawKeyImageInRect(const UISoftKeyboardKey &key, QPainter &painter);
576
577private:
578
579 QMap<int, UIKeyCaptions> m_keyCaptionsMap;
580 /** Caching the font sizes we used for font rendering since it is not a very cheap process to compute these. */
581 QMap<int, int> m_keyCaptionsFontSizeMap;
582 /** The UUID of the physical layout used by this layout. */
583 QUuid m_physicalLayoutUuid;
584 /** This is the English name of the layout. */
585 QString m_strName;
586 QString m_strNativeName;
587 QString m_strSourceFilePath;
588 bool m_fEditable;
589 bool m_fIsFromResources;
590 bool m_fEditedButNotSaved;
591 QUuid m_uid;
592};
593
594/*********************************************************************************************************************************
595* UISoftKeyboardColorTheme definition. *
596*********************************************************************************************************************************/
597
598class UISoftKeyboardColorTheme
599{
600
601public:
602
603 UISoftKeyboardColorTheme();
604 UISoftKeyboardColorTheme(const QString &strName,
605 const QString &strBackgroundColor,
606 const QString &strNormalFontColor,
607 const QString &strHoverColor,
608 const QString &strEditedButtonBackgroundColor,
609 const QString &strPressedButtonFontColor);
610
611 void setColor(KeyboardColorType enmColorType, const QColor &color);
612 QColor color(KeyboardColorType enmColorType) const;
613 QStringList colorsToStringList() const;
614 void colorsFromStringList(const QStringList &colorStringList);
615
616 const QString &name() const;
617 void setName(const QString &strName);
618
619 bool isEditable() const;
620 void setIsEditable(bool fIsEditable);
621
622private:
623
624 QVector<QColor> m_colors;
625 QString m_strName;
626 bool m_fIsEditable;
627};
628
629/*********************************************************************************************************************************
630* UISoftKeyboardWidget definition. *
631*********************************************************************************************************************************/
632
633/** The container widget for keyboard keys. It also handles all the keyboard related events. paintEvent of this class
634 * handles drawing of the soft keyboard. */
635class UISoftKeyboardWidget : public QIWithRetranslateUI<QWidget>
636{
637 Q_OBJECT;
638
639 enum Mode
640 {
641 Mode_LayoutEdit,
642 Mode_Keyboard,
643 Mode_Max
644 };
645
646signals:
647
648 void sigStatusBarMessage(const QString &strMessage);
649 void sigPutKeyboardSequence(QVector<LONG> sequence);
650 void sigPutUsageCodesPress(QVector<QPair<LONG, LONG> > sequence);
651 void sigPutUsageCodesRelease(QVector<QPair<LONG, LONG> > sequence);
652 void sigCurrentLayoutChange();
653 void sigKeyToEdit(UISoftKeyboardKey* pKey);
654 void sigCurrentColorThemeChanged();
655 void sigOptionsChanged();
656
657public:
658
659 UISoftKeyboardWidget(QWidget *pParent = 0);
660
661 virtual QSize minimumSizeHint() const RT_OVERRIDE;
662 virtual QSize sizeHint() const RT_OVERRIDE;
663 void keyStateChange(UISoftKeyboardKey* pKey);
664 void loadLayouts();
665
666 void setCurrentLayout(const QUuid &layoutUid);
667 UISoftKeyboardLayout *currentLayout();
668
669 QStringList layoutNameList() const;
670 QList<QUuid> layoutUidList() const;
671 const QVector<UISoftKeyboardPhysicalLayout> &physicalLayouts() const;
672 void deleteCurrentLayout();
673 void toggleEditMode(bool fIsEditMode);
674
675 void saveCurentLayoutToFile();
676 void copyCurentLayout();
677 float layoutAspectRatio();
678
679 bool hideOSMenuKeys() const;
680 void setHideOSMenuKeys(bool fHide);
681
682 bool hideNumPad() const;
683 void setHideNumPad(bool fHide);
684
685 bool hideMultimediaKeys() const;
686 void setHideMultimediaKeys(bool fHide);
687
688 QColor color(KeyboardColorType enmColorType) const;
689 void setColor(KeyboardColorType ennmColorType, const QColor &color);
690
691 QStringList colorsToStringList(const QString &strColorThemeName);
692 void colorsFromStringList(const QString &strColorThemeName, const QStringList &colorStringList);
693
694 /** Unlike modifier and ordinary keys we update the state of the Lock keys thru event signals we receieve
695 * from the guest OS. Parameter f???State is true if the corresponding key is locked. */
696 void updateLockKeyStates(bool fCapsLockState, bool fNumLockState, bool fScrollLockState);
697 void reset();
698
699 QStringList colorThemeNames() const;
700 QString currentColorThemeName() const;
701 void setColorThemeByName(const QString &strColorThemeName);
702 void parentDialogDeactivated();
703 bool isColorThemeEditable() const;
704 /** Returns a list of layout names that have been edited but not yet saved to a file. */
705 QStringList unsavedLayoutsNameList() const;
706
707protected:
708
709 virtual void paintEvent(QPaintEvent *pEvent) RT_OVERRIDE;
710 virtual void mousePressEvent(QMouseEvent *pEvent) RT_OVERRIDE;
711 virtual void mouseReleaseEvent(QMouseEvent *pEvent) RT_OVERRIDE;
712 virtual void mouseMoveEvent(QMouseEvent *pEvent) RT_OVERRIDE;
713 virtual void retranslateUi() RT_OVERRIDE;
714
715private:
716
717 void addLayout(const UISoftKeyboardLayout &newLayout);
718 void setNewMinimumSize(const QSize &size);
719 void setInitialSize(int iWidth, int iHeight);
720 /** Searches for the key which contains the position of the @p pEvent and returns it if found. */
721 UISoftKeyboardKey *keyUnderMouse(QMouseEvent *pEvent);
722 UISoftKeyboardKey *keyUnderMouse(const QPoint &point);
723 void handleKeyPress(UISoftKeyboardKey *pKey);
724 void handleKeyRelease(UISoftKeyboardKey *pKey);
725 /** Sends usage id/page to API when a modifier key is right clicked. useful for testing and things like
726 * Window key press for start menu opening. This works orthogonal to left clicks.*/
727 void modifierKeyPressRelease(UISoftKeyboardKey *pKey, bool fRelease);
728 bool loadPhysicalLayout(const QString &strLayoutFileName, KeyboardRegion keyboardRegion = KeyboardRegion_Main);
729 bool loadKeyboardLayout(const QString &strLayoutName);
730 void prepareObjects();
731 void prepareColorThemes();
732 UISoftKeyboardPhysicalLayout *findPhysicalLayout(const QUuid &uuid);
733 /** Sets m_pKeyBeingEdited. */
734 void setKeyBeingEdited(UISoftKeyboardKey *pKey);
735 bool layoutByNameExists(const QString &strName) const;
736
737 /** Looks under the default keyboard layout folder and add the file names to the fileList. */
738 void lookAtDefaultLayoutFolder(QStringList &fileList);
739 UISoftKeyboardColorTheme *colorTheme(const QString &strColorThemeName);
740 void showKeyTooltip(UISoftKeyboardKey *pKey);
741
742 UISoftKeyboardKey *m_pKeyUnderMouse;
743 UISoftKeyboardKey *m_pKeyBeingEdited;
744
745 UISoftKeyboardKey *m_pKeyPressed;
746 UISoftKeyboardColorTheme *m_currentColorTheme;
747 QVector<UISoftKeyboardColorTheme> m_colorThemes;
748 QVector<UISoftKeyboardKey*> m_pressedModifiers;
749 QVector<UISoftKeyboardPhysicalLayout> m_physicalLayouts;
750 UISoftKeyboardPhysicalLayout m_numPadLayout;
751 UISoftKeyboardPhysicalLayout m_multiMediaKeysLayout;
752 QMap<QUuid, UISoftKeyboardLayout> m_layouts;
753 QUuid m_uCurrentLayoutId;
754 /** Key is the key position as read from the layout and value is the message we show as mouse hovers over the key. */
755 QMap<int, QString> m_keyTooltips;
756
757 QSize m_minimumSize;
758 float m_fScaleFactorX;
759 float m_fScaleFactorY;
760 int m_iInitialHeight;
761 /** This is the width of the keyboard including the numpad but without m_iInitialWidthNoNumPad */
762 int m_iInitialWidth;
763 int m_iInitialWidthNoNumPad;
764 /** This widt is added while drawing the keyboard not to key geometries. */
765 int m_iBeforeNumPadWidth;
766 int m_iXSpacing;
767 int m_iYSpacing;
768 int m_iLeftMargin;
769 int m_iTopMargin;
770 int m_iRightMargin;
771 int m_iBottomMargin;
772 Mode m_enmMode;
773 bool m_fHideOSMenuKeys;
774 bool m_fHideNumPad;
775 bool m_fHideMultimediaKeys;
776};
777
778/*********************************************************************************************************************************
779* UIPhysicalLayoutReader definition. *
780*********************************************************************************************************************************/
781
782class UIPhysicalLayoutReader
783{
784
785public:
786
787 bool parseXMLFile(const QString &strFileName, UISoftKeyboardPhysicalLayout &physicalLayout);
788 static QVector<QPointF> computeKeyVertices(const UISoftKeyboardKey &key);
789
790private:
791
792 void parseKey(UISoftKeyboardRow &row);
793 void parseRow(int iDefaultWidth, int iDefaultHeight, QVector<UISoftKeyboardRow> &rows);
794 /** Parses the horizontal space between keys. */
795 void parseKeySpace(UISoftKeyboardRow &row);
796 void parseCutout(UISoftKeyboardKey &key);
797
798 QXmlStreamReader m_xmlReader;
799};
800
801/*********************************************************************************************************************************
802* UIKeyboardLayoutReader definition. *
803*********************************************************************************************************************************/
804
805class UIKeyboardLayoutReader
806{
807
808public:
809
810 bool parseFile(const QString &strFileName, UISoftKeyboardLayout &layout);
811
812private:
813
814 void parseKey(UISoftKeyboardLayout &layout);
815 QXmlStreamReader m_xmlReader;
816 /** Map key is the key position and the value is the captions of the key. */
817};
818
819
820/*********************************************************************************************************************************
821* UISoftKeyboardStatusBarWidget definition. *
822*********************************************************************************************************************************/
823
824class UISoftKeyboardStatusBarWidget : public QIWithRetranslateUI<QWidget>
825{
826 Q_OBJECT;
827
828signals:
829
830 void sigShowHideSidePanel();
831 void sigShowSettingWidget();
832 void sigResetKeyboard();
833 void sigHelpButtonPressed();
834
835public:
836
837 UISoftKeyboardStatusBarWidget(QWidget *pParent = 0);
838 void updateLayoutNameInStatusBar(const QString &strMessage);
839
840protected:
841
842 virtual void retranslateUi() RT_OVERRIDE;
843
844private:
845
846 void prepareObjects();
847 QToolButton *m_pLayoutListButton;
848 QToolButton *m_pSettingsButton;
849 QToolButton *m_pResetButton;
850 QToolButton *m_pHelpButton;
851 QLabel *m_pMessageLabel;
852};
853
854
855/*********************************************************************************************************************************
856* UISoftKeyboardSettingsWidget definition. *
857*********************************************************************************************************************************/
858
859class UISoftKeyboardSettingsWidget : public QIWithRetranslateUI<QWidget>
860{
861 Q_OBJECT;
862
863signals:
864
865 void sigHideNumPad(bool fHide);
866 void sigHideOSMenuKeys(bool fHide);
867 void sigHideMultimediaKeys(bool fHide);
868 void sigColorCellClicked(int iColorRow);
869 void sigCloseSettingsWidget();
870 void sigColorThemeSelectionChanged(const QString &strColorThemeName);
871
872public:
873
874 UISoftKeyboardSettingsWidget(QWidget *pParent = 0);
875 void setHideOSMenuKeys(bool fHide);
876 void setHideNumPad(bool fHide);
877 void setHideMultimediaKeys(bool fHide);
878 void setColorSelectionButtonBackgroundAndTooltip(KeyboardColorType enmColorType, const QColor &color, bool fIsColorEditable);
879 void setColorThemeNames(const QStringList &colorThemeNames);
880 void setCurrentColorThemeName(const QString &strColorThemeName);
881
882protected:
883
884 virtual void retranslateUi() RT_OVERRIDE;
885
886private slots:
887
888 void sltColorSelectionButtonClicked();
889
890private:
891
892 void prepareObjects();
893
894 QCheckBox *m_pHideNumPadCheckBox;
895 QCheckBox *m_pShowOsMenuButtonsCheckBox;
896 QCheckBox *m_pHideMultimediaKeysCheckBox;
897 QGroupBox *m_pColorThemeGroupBox;
898 QComboBox *m_pColorThemeComboBox;
899 QLabel *m_pTitleLabel;
900 QToolButton *m_pCloseButton;
901 QVector<ColorSelectLabelButton> m_colorSelectLabelsButtons;
902};
903
904
905/*********************************************************************************************************************************
906* UISoftKeyboardColorButton implementation. *
907*********************************************************************************************************************************/
908
909
910UISoftKeyboardColorButton::UISoftKeyboardColorButton(KeyboardColorType enmColorType, QWidget *pParent /*= 0 */)
911 :QPushButton(pParent)
912 , m_enmColorType(enmColorType){}
913
914KeyboardColorType UISoftKeyboardColorButton::colorType() const
915{
916 return m_enmColorType;
917}
918
919
920/*********************************************************************************************************************************
921* UISoftKeyboardPhysicalLayout implementation. *
922*********************************************************************************************************************************/
923
924UISoftKeyboardPhysicalLayout::UISoftKeyboardPhysicalLayout()
925 :m_iDefaultKeyWidth(50)
926{
927}
928
929void UISoftKeyboardPhysicalLayout::setName(const QString &strName)
930{
931 m_strName = strName;
932}
933
934const QString &UISoftKeyboardPhysicalLayout::name() const
935{
936 return m_strName;
937}
938
939void UISoftKeyboardPhysicalLayout::setFileName(const QString &strName)
940{
941 m_strFileName = strName;
942}
943
944const QString &UISoftKeyboardPhysicalLayout::fileName() const
945{
946 return m_strFileName;
947}
948
949void UISoftKeyboardPhysicalLayout::setUid(const QUuid &uid)
950{
951 m_uId = uid;
952}
953
954const QUuid &UISoftKeyboardPhysicalLayout::uid() const
955{
956 return m_uId;
957}
958
959const QVector<UISoftKeyboardRow> &UISoftKeyboardPhysicalLayout::rows() const
960{
961 return m_rows;
962}
963
964QVector<UISoftKeyboardRow> &UISoftKeyboardPhysicalLayout::rows()
965{
966 return m_rows;
967}
968
969void UISoftKeyboardPhysicalLayout::setLockKey(int iKeyPosition, UISoftKeyboardKey *pKey)
970{
971 m_lockKeys[iKeyPosition] = pKey;
972}
973
974void UISoftKeyboardPhysicalLayout::updateLockKeyStates(bool fCapsLockState, bool fNumLockState, bool fScrollLockState)
975{
976 updateLockKeyState(fCapsLockState, m_lockKeys.value(iCapsLockPosition, 0));
977 updateLockKeyState(fNumLockState, m_lockKeys.value(iNumLockPosition, 0));
978 updateLockKeyState(fScrollLockState, m_lockKeys.value(iScrollLockPosition, 0));
979}
980
981void UISoftKeyboardPhysicalLayout::setDefaultKeyWidth(int iDefaultKeyWidth)
982{
983 m_iDefaultKeyWidth = iDefaultKeyWidth;
984}
985
986int UISoftKeyboardPhysicalLayout::defaultKeyWidth() const
987{
988 return m_iDefaultKeyWidth;
989}
990
991void UISoftKeyboardPhysicalLayout::reset()
992{
993 for (int i = 0; i < m_rows.size(); ++i)
994 {
995 for (int j = 0; j < m_rows[i].keys().size(); ++j)
996 {
997 m_rows[i].keys()[j].reset();
998 }
999 }
1000}
1001
1002int UISoftKeyboardPhysicalLayout::totalHeight() const
1003{
1004 int iHeight = 0;
1005 for (int i = 0; i < m_rows.size(); ++i)
1006 iHeight += m_rows[i].totalHeight();
1007 return iHeight;
1008}
1009
1010void UISoftKeyboardPhysicalLayout::updateLockKeyState(bool fLockState, UISoftKeyboardKey *pKey)
1011{
1012 if (!pKey)
1013 return;
1014 pKey->updateLockState(fLockState);
1015}
1016
1017/*********************************************************************************************************************************
1018* UIKeyboardLayoutEditor implementation. *
1019*********************************************************************************************************************************/
1020
1021UIKeyboardLayoutEditor::UIKeyboardLayoutEditor(QWidget *pParent /* = 0 */)
1022 :QIWithRetranslateUI<QWidget>(pParent)
1023 , m_pEditorLayout(0)
1024 , m_pGoBackButton(0)
1025 , m_pSelectedKeyGroupBox(0)
1026 , m_pCaptionEditGroupBox(0)
1027 , m_pPhysicalLayoutCombo(0)
1028 , m_pTitleLabel(0)
1029 , m_pPhysicalLayoutLabel(0)
1030 , m_pLayoutNameLabel(0)
1031 , m_pLayoutNativeNameLabel(0)
1032 , m_pScanCodeLabel(0)
1033 , m_pPositionLabel(0)
1034 , m_pBaseCaptionLabel(0)
1035 , m_pShiftCaptionLabel(0)
1036 , m_pAltGrCaptionLabel(0)
1037 , m_pShiftAltGrCaptionLabel(0)
1038 , m_pLayoutNameEdit(0)
1039 , m_pLayoutNativeNameEdit(0)
1040 , m_pScanCodeEdit(0)
1041 , m_pPositionEdit(0)
1042 , m_pBaseCaptionEdit(0)
1043 , m_pShiftCaptionEdit(0)
1044 , m_pAltGrCaptionEdit(0)
1045 , m_pShiftAltGrCaptionEdit(0)
1046 , m_pKey(0)
1047 , m_pLayout(0)
1048{
1049 setAutoFillBackground(true);
1050 prepareObjects();
1051}
1052
1053void UIKeyboardLayoutEditor::setKey(UISoftKeyboardKey *pKey)
1054{
1055 if (m_pKey == pKey || !m_pLayout)
1056 return;
1057 /* First apply the pending changes to the key that has been edited: */
1058 if (m_pKey)
1059 {
1060 UIKeyCaptions captions = m_pLayout->keyCaptions(m_pKey->position());
1061 if (captions.m_strBase != m_pBaseCaptionEdit->text() ||
1062 captions.m_strShift != m_pShiftCaptionEdit->text() ||
1063 captions.m_strAltGr != m_pAltGrCaptionEdit->text() ||
1064 captions.m_strShiftAltGr != m_pShiftAltGrCaptionEdit->text())
1065 m_pLayout->addOrUpdateUIKeyCaptions(m_pKey->position(),
1066 UIKeyCaptions(m_pBaseCaptionEdit->text(),
1067 m_pShiftCaptionEdit->text(),
1068 m_pAltGrCaptionEdit->text(),
1069 m_pShiftAltGrCaptionEdit->text()));
1070 }
1071 m_pKey = pKey;
1072 if (m_pSelectedKeyGroupBox)
1073 m_pSelectedKeyGroupBox->setEnabled(m_pKey);
1074 if (!m_pKey)
1075 {
1076 resetKeyWidgets();
1077 return;
1078 }
1079 if (m_pScanCodeEdit)
1080 m_pScanCodeEdit->setText(QString::number(m_pKey->scanCode(), 16));
1081 if (m_pPositionEdit)
1082 m_pPositionEdit->setText(QString::number(m_pKey->position()));
1083 UIKeyCaptions captions = m_pLayout->keyCaptions(m_pKey->position());
1084 if (m_pBaseCaptionEdit)
1085 m_pBaseCaptionEdit->setText(captions.m_strBase);
1086 if (m_pShiftCaptionEdit)
1087 m_pShiftCaptionEdit->setText(captions.m_strShift);
1088 if (m_pAltGrCaptionEdit)
1089 m_pAltGrCaptionEdit->setText(captions.m_strAltGr);
1090 if (m_pShiftAltGrCaptionEdit)
1091 m_pShiftAltGrCaptionEdit->setText(captions.m_strShiftAltGr);
1092 m_pBaseCaptionEdit->setFocus();
1093}
1094
1095void UIKeyboardLayoutEditor::setLayoutToEdit(UISoftKeyboardLayout *pLayout)
1096{
1097 if (m_pLayout == pLayout)
1098 return;
1099
1100 m_pLayout = pLayout;
1101 if (!m_pLayout)
1102 reset();
1103
1104 if (m_pLayoutNameEdit)
1105 m_pLayoutNameEdit->setText(m_pLayout ? m_pLayout->name() : QString());
1106
1107 if (m_pLayoutNativeNameEdit)
1108 m_pLayoutNativeNameEdit->setText(m_pLayout ? m_pLayout->nativeName() : QString());
1109
1110 if (m_pPhysicalLayoutCombo && m_pLayout)
1111 {
1112 int iIndex = m_pPhysicalLayoutCombo->findData(m_pLayout->physicalLayoutUuid());
1113 if (iIndex != -1)
1114 m_pPhysicalLayoutCombo->setCurrentIndex(iIndex);
1115 }
1116 update();
1117}
1118
1119void UIKeyboardLayoutEditor::setPhysicalLayoutList(const QVector<UISoftKeyboardPhysicalLayout> &physicalLayouts)
1120{
1121 if (!m_pPhysicalLayoutCombo)
1122 return;
1123 m_pPhysicalLayoutCombo->clear();
1124 foreach (const UISoftKeyboardPhysicalLayout &physicalLayout, physicalLayouts)
1125 m_pPhysicalLayoutCombo->addItem(physicalLayout.name(), physicalLayout.uid());
1126}
1127
1128void UIKeyboardLayoutEditor::retranslateUi()
1129{
1130 if (m_pTitleLabel)
1131 m_pTitleLabel->setText(UISoftKeyboard::tr("Layout Editor"));
1132 if (m_pGoBackButton)
1133 {
1134 m_pGoBackButton->setToolTip(UISoftKeyboard::tr("Return Back to Layout List"));
1135 m_pGoBackButton->setText(UISoftKeyboard::tr("Back to Layout List"));
1136 }
1137 if (m_pPhysicalLayoutLabel)
1138 m_pPhysicalLayoutLabel->setText(UISoftKeyboard::tr("Physical Layout"));
1139 if (m_pLayoutNameLabel)
1140 m_pLayoutNameLabel->setText(UISoftKeyboard::tr("English Name"));
1141 if (m_pLayoutNameEdit)
1142 m_pLayoutNameEdit->setToolTip(UISoftKeyboard::tr("Name of the Layout in English"));
1143 if (m_pLayoutNativeNameLabel)
1144 m_pLayoutNativeNameLabel->setText(UISoftKeyboard::tr("Native Language Name"));
1145 if (m_pLayoutNativeNameEdit)
1146 m_pLayoutNativeNameEdit->setToolTip(UISoftKeyboard::tr("Name of the Layout in the native Language"));
1147 if (m_pScanCodeLabel)
1148 m_pScanCodeLabel->setText(UISoftKeyboard::tr("Scan Code"));
1149 if (m_pScanCodeEdit)
1150 m_pScanCodeEdit->setToolTip(UISoftKeyboard::tr("The scan code the key produces. Not editable"));
1151 if (m_pPositionLabel)
1152 m_pPositionLabel->setText(UISoftKeyboard::tr("Position"));
1153 if (m_pPositionEdit)
1154 m_pPositionEdit->setToolTip(UISoftKeyboard::tr("The physical position of the key. Not editable"));
1155 if (m_pBaseCaptionLabel)
1156 m_pBaseCaptionLabel->setText(UISoftKeyboard::tr("Base"));
1157 if (m_pShiftCaptionLabel)
1158 m_pShiftCaptionLabel->setText(UISoftKeyboard::tr("Shift"));
1159 if (m_pAltGrCaptionLabel)
1160 m_pAltGrCaptionLabel->setText(UISoftKeyboard::tr("AltGr"));
1161 if (m_pShiftAltGrCaptionLabel)
1162 m_pShiftAltGrCaptionLabel->setText(UISoftKeyboard::tr("ShiftAltGr"));
1163 if (m_pCaptionEditGroupBox)
1164 m_pCaptionEditGroupBox->setTitle(UISoftKeyboard::tr("Captions"));
1165 if (m_pSelectedKeyGroupBox)
1166 m_pSelectedKeyGroupBox->setTitle(UISoftKeyboard::tr("Selected Key"));
1167}
1168
1169void UIKeyboardLayoutEditor::sltCaptionsUpdate()
1170{
1171 if (!m_pKey || !m_pLayout)
1172 return;
1173 m_pLayout->addOrUpdateUIKeyCaptions(m_pKey->position(),
1174 UIKeyCaptions(m_pBaseCaptionEdit->text(),
1175 m_pShiftCaptionEdit->text(),
1176 m_pAltGrCaptionEdit->text(),
1177 m_pShiftAltGrCaptionEdit->text()));
1178 emit sigUIKeyCaptionsEdited(m_pKey);
1179}
1180
1181void UIKeyboardLayoutEditor::sltPhysicalLayoutChanged()
1182{
1183 if (!m_pPhysicalLayoutCombo || !m_pLayout)
1184 return;
1185 QUuid currentData = m_pPhysicalLayoutCombo->currentData().toUuid();
1186 if (!currentData.isNull())
1187 m_pLayout->setPhysicalLayoutUuid(currentData);
1188 emit sigLayoutEdited();
1189}
1190
1191void UIKeyboardLayoutEditor::sltLayoutNameChanged(const QString &strName)
1192{
1193 if (!m_pLayout || m_pLayout->name() == strName)
1194 return;
1195 m_pLayout->setName(strName);
1196 emit sigLayoutEdited();
1197}
1198
1199void UIKeyboardLayoutEditor::sltLayoutNativeNameChanged(const QString &strNativeName)
1200{
1201 if (!m_pLayout || m_pLayout->nativeName() == strNativeName)
1202 return;
1203 m_pLayout->setNativeName(strNativeName);
1204 emit sigLayoutEdited();
1205}
1206
1207void UIKeyboardLayoutEditor::prepareObjects()
1208{
1209 m_pEditorLayout = new QGridLayout;
1210 if (!m_pEditorLayout)
1211 return;
1212 setLayout(m_pEditorLayout);
1213
1214 QHBoxLayout *pTitleLayout = new QHBoxLayout;
1215 m_pGoBackButton = new QToolButton;
1216 m_pGoBackButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
1217 m_pGoBackButton->setIcon(UIIconPool::defaultIcon(UIIconPool::UIDefaultIconType_ArrowBack));
1218 m_pGoBackButton->setAutoRaise(true);
1219 m_pEditorLayout->addWidget(m_pGoBackButton, 0, 0, 1, 1);
1220 connect(m_pGoBackButton, &QToolButton::clicked, this, &UIKeyboardLayoutEditor::sigGoBackButton);
1221 m_pTitleLabel = new QLabel;
1222 pTitleLayout->addWidget(m_pTitleLabel);
1223 pTitleLayout->addStretch(2);
1224 pTitleLayout->addWidget(m_pGoBackButton);
1225 m_pEditorLayout->addLayout(pTitleLayout, 0, 0, 1, 2);
1226
1227 m_pLayoutNativeNameLabel = new QLabel;
1228 m_pLayoutNativeNameEdit = new QLineEdit;
1229 m_pLayoutNativeNameLabel->setBuddy(m_pLayoutNativeNameEdit);
1230 m_pEditorLayout->addWidget(m_pLayoutNativeNameLabel, 2, 0, 1, 1);
1231 m_pEditorLayout->addWidget(m_pLayoutNativeNameEdit, 2, 1, 1, 1);
1232 connect(m_pLayoutNativeNameEdit, &QLineEdit::textChanged, this, &UIKeyboardLayoutEditor::sltLayoutNativeNameChanged);
1233
1234 m_pLayoutNameLabel = new QLabel;
1235 m_pLayoutNameEdit = new QLineEdit;
1236 m_pLayoutNameLabel->setBuddy(m_pLayoutNameEdit);
1237 m_pEditorLayout->addWidget(m_pLayoutNameLabel, 3, 0, 1, 1);
1238 m_pEditorLayout->addWidget(m_pLayoutNameEdit, 3, 1, 1, 1);
1239 connect(m_pLayoutNameEdit, &QLineEdit::textChanged, this, &UIKeyboardLayoutEditor::sltLayoutNameChanged);
1240
1241
1242 m_pPhysicalLayoutLabel = new QLabel;
1243 m_pPhysicalLayoutCombo = new QComboBox;
1244 m_pPhysicalLayoutLabel->setBuddy(m_pPhysicalLayoutCombo);
1245 m_pEditorLayout->addWidget(m_pPhysicalLayoutLabel, 4, 0, 1, 1);
1246 m_pEditorLayout->addWidget(m_pPhysicalLayoutCombo, 4, 1, 1, 1);
1247 connect(m_pPhysicalLayoutCombo, &QComboBox::currentIndexChanged, this, &UIKeyboardLayoutEditor::sltPhysicalLayoutChanged);
1248
1249 m_pSelectedKeyGroupBox = new QGroupBox;
1250 m_pSelectedKeyGroupBox->setEnabled(false);
1251
1252 m_pEditorLayout->addWidget(m_pSelectedKeyGroupBox, 5, 0, 1, 2);
1253 QGridLayout *pSelectedKeyLayout = new QGridLayout(m_pSelectedKeyGroupBox);
1254 pSelectedKeyLayout->setSpacing(0);
1255 pSelectedKeyLayout->setContentsMargins(0, 0, 0, 0);
1256
1257 m_pScanCodeLabel = new QLabel;
1258 m_pScanCodeEdit = new QLineEdit;
1259 m_pScanCodeLabel->setBuddy(m_pScanCodeEdit);
1260 m_pScanCodeEdit->setEnabled(false);
1261 pSelectedKeyLayout->addWidget(m_pScanCodeLabel, 0, 0);
1262 pSelectedKeyLayout->addWidget(m_pScanCodeEdit, 0, 1);
1263
1264 m_pPositionLabel= new QLabel;
1265 m_pPositionEdit = new QLineEdit;
1266 m_pPositionEdit->setEnabled(false);
1267 m_pPositionLabel->setBuddy(m_pPositionEdit);
1268 pSelectedKeyLayout->addWidget(m_pPositionLabel, 1, 0);
1269 pSelectedKeyLayout->addWidget(m_pPositionEdit, 1, 1);
1270
1271 QWidget *pCaptionEditor = prepareKeyCaptionEditWidgets();
1272 if (pCaptionEditor)
1273 pSelectedKeyLayout->addWidget(pCaptionEditor, 2, 0, 2, 2);
1274
1275 QSpacerItem *pSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding);
1276 if (pSpacer)
1277 pSelectedKeyLayout->addItem(pSpacer, 4, 1);
1278
1279 retranslateUi();
1280}
1281
1282QWidget *UIKeyboardLayoutEditor::prepareKeyCaptionEditWidgets()
1283{
1284 m_pCaptionEditGroupBox = new QGroupBox;
1285 if (!m_pCaptionEditGroupBox)
1286 return 0;
1287 m_pCaptionEditGroupBox->setFlat(false);
1288 QGridLayout *pCaptionEditorLayout = new QGridLayout(m_pCaptionEditGroupBox);
1289 pCaptionEditorLayout->setSpacing(0);
1290 pCaptionEditorLayout->setContentsMargins(0, 0, 0, 0);
1291
1292 if (!pCaptionEditorLayout)
1293 return 0;
1294
1295 m_pBaseCaptionLabel = new QLabel;
1296 m_pBaseCaptionEdit = new QLineEdit;
1297 m_pBaseCaptionLabel->setBuddy(m_pBaseCaptionEdit);
1298 pCaptionEditorLayout->addWidget(m_pBaseCaptionLabel, 0, 0);
1299 pCaptionEditorLayout->addWidget(m_pBaseCaptionEdit, 0, 1);
1300 connect(m_pBaseCaptionEdit, &QLineEdit::textChanged, this, &UIKeyboardLayoutEditor::sltCaptionsUpdate);
1301
1302 m_pShiftCaptionLabel = new QLabel;
1303 m_pShiftCaptionEdit = new QLineEdit;
1304 m_pShiftCaptionLabel->setBuddy(m_pShiftCaptionEdit);
1305 pCaptionEditorLayout->addWidget(m_pShiftCaptionLabel, 1, 0);
1306 pCaptionEditorLayout->addWidget(m_pShiftCaptionEdit, 1, 1);
1307 connect(m_pShiftCaptionEdit, &QLineEdit::textChanged, this, &UIKeyboardLayoutEditor::sltCaptionsUpdate);
1308
1309 m_pAltGrCaptionLabel = new QLabel;
1310 m_pAltGrCaptionEdit = new QLineEdit;
1311 m_pAltGrCaptionLabel->setBuddy(m_pAltGrCaptionEdit);
1312 pCaptionEditorLayout->addWidget(m_pAltGrCaptionLabel, 2, 0);
1313 pCaptionEditorLayout->addWidget(m_pAltGrCaptionEdit, 2, 1);
1314 connect(m_pAltGrCaptionEdit, &QLineEdit::textChanged, this, &UIKeyboardLayoutEditor::sltCaptionsUpdate);
1315
1316 m_pShiftAltGrCaptionLabel = new QLabel;
1317 m_pShiftAltGrCaptionEdit = new QLineEdit;
1318 m_pShiftAltGrCaptionLabel->setBuddy(m_pShiftAltGrCaptionEdit);
1319 pCaptionEditorLayout->addWidget(m_pShiftAltGrCaptionLabel, 3, 0);
1320 pCaptionEditorLayout->addWidget(m_pShiftAltGrCaptionEdit, 3, 1);
1321 connect(m_pShiftAltGrCaptionEdit, &QLineEdit::textChanged, this, &UIKeyboardLayoutEditor::sltCaptionsUpdate);
1322
1323 QSpacerItem *pSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding);
1324 if (pSpacer)
1325 pCaptionEditorLayout->addItem(pSpacer, 4, 1);
1326 return m_pCaptionEditGroupBox;
1327}
1328
1329void UIKeyboardLayoutEditor::reset()
1330{
1331 if (m_pLayoutNameEdit)
1332 m_pLayoutNameEdit->clear();
1333 resetKeyWidgets();
1334}
1335
1336void UIKeyboardLayoutEditor::resetKeyWidgets()
1337{
1338 if (m_pScanCodeEdit)
1339 m_pScanCodeEdit->clear();
1340 if (m_pPositionEdit)
1341 m_pPositionEdit->clear();
1342 if (m_pBaseCaptionEdit)
1343 m_pBaseCaptionEdit->clear();
1344 if (m_pShiftCaptionEdit)
1345 m_pShiftCaptionEdit->clear();
1346 if (m_pAltGrCaptionEdit)
1347 m_pAltGrCaptionEdit->clear();
1348 if (m_pShiftAltGrCaptionEdit)
1349 m_pShiftAltGrCaptionEdit->clear();
1350}
1351
1352/*********************************************************************************************************************************
1353* UILayoutSelector implementation. *
1354*********************************************************************************************************************************/
1355
1356UILayoutSelector::UILayoutSelector(QWidget *pParent /* = 0 */)
1357 :QIWithRetranslateUI<QWidget>(pParent)
1358 , m_pLayoutListWidget(0)
1359 , m_pApplyLayoutButton(0)
1360 , m_pEditLayoutButton(0)
1361 , m_pCopyLayoutButton(0)
1362 , m_pSaveLayoutButton(0)
1363 , m_pDeleteLayoutButton(0)
1364 , m_pTitleLabel(0)
1365 , m_pCloseButton(0)
1366{
1367 prepareObjects();
1368}
1369
1370void UILayoutSelector::setCurrentLayout(const QUuid &layoutUid)
1371{
1372 if (!m_pLayoutListWidget)
1373 return;
1374 if (layoutUid.isNull())
1375 {
1376 m_pLayoutListWidget->selectionModel()->clear();
1377 return;
1378 }
1379 QListWidgetItem *pFoundItem = 0;
1380 for (int i = 0; i < m_pLayoutListWidget->count() && !pFoundItem; ++i)
1381 {
1382 QListWidgetItem *pItem = m_pLayoutListWidget->item(i);
1383 if (!pItem)
1384 continue;
1385 if (pItem->data(Qt::UserRole).toUuid() == layoutUid)
1386 pFoundItem = pItem;
1387 }
1388 if (!pFoundItem)
1389 return;
1390 if (pFoundItem == m_pLayoutListWidget->currentItem())
1391 return;
1392 m_pLayoutListWidget->blockSignals(true);
1393 m_pLayoutListWidget->setCurrentItem(pFoundItem);
1394 m_pLayoutListWidget->blockSignals(false);
1395}
1396
1397void UILayoutSelector::setCurrentLayoutIsEditable(bool fEditable)
1398{
1399 if (m_pEditLayoutButton)
1400 m_pEditLayoutButton->setEnabled(fEditable);
1401 if (m_pSaveLayoutButton)
1402 m_pSaveLayoutButton->setEnabled(fEditable);
1403 if (m_pDeleteLayoutButton)
1404 m_pDeleteLayoutButton->setEnabled(fEditable);
1405}
1406
1407void UILayoutSelector::setLayoutList(const QStringList &layoutNames, QList<QUuid> layoutUidList)
1408{
1409 if (!m_pLayoutListWidget || layoutNames.size() != layoutUidList.size())
1410 return;
1411 QUuid currentItemUid;
1412 if (m_pLayoutListWidget->currentItem())
1413 currentItemUid = m_pLayoutListWidget->currentItem()->data(Qt::UserRole).toUuid();
1414 m_pLayoutListWidget->blockSignals(true);
1415 m_pLayoutListWidget->clear();
1416 for (int i = 0; i < layoutNames.size(); ++i)
1417 {
1418 QListWidgetItem *pItem = new QListWidgetItem(layoutNames[i], m_pLayoutListWidget);
1419 pItem->setData(Qt::UserRole, layoutUidList[i]);
1420 m_pLayoutListWidget->addItem(pItem);
1421 if (layoutUidList[i] == currentItemUid)
1422 m_pLayoutListWidget->setCurrentItem(pItem);
1423 }
1424 m_pLayoutListWidget->sortItems();
1425 m_pLayoutListWidget->blockSignals(false);
1426}
1427
1428void UILayoutSelector::retranslateUi()
1429{
1430 if (m_pApplyLayoutButton)
1431 m_pApplyLayoutButton->setToolTip(UISoftKeyboard::tr("Use the selected layout"));
1432 if (m_pEditLayoutButton)
1433 m_pEditLayoutButton->setToolTip(UISoftKeyboard::tr("Edit the selected layout"));
1434 if (m_pDeleteLayoutButton)
1435 m_pDeleteLayoutButton->setToolTip(UISoftKeyboard::tr("Delete the selected layout"));
1436 if (m_pCopyLayoutButton)
1437 m_pCopyLayoutButton->setToolTip(UISoftKeyboard::tr("Copy the selected layout"));
1438 if (m_pSaveLayoutButton)
1439 m_pSaveLayoutButton->setToolTip(UISoftKeyboard::tr("Save the selected layout into File"));
1440 if (m_pTitleLabel)
1441 m_pTitleLabel->setText(UISoftKeyboard::tr("Layout List"));
1442 if (m_pCloseButton)
1443 {
1444 m_pCloseButton->setToolTip(UISoftKeyboard::tr("Close the layout list"));
1445 m_pCloseButton->setText("Close");
1446 }
1447}
1448
1449void UILayoutSelector::prepareObjects()
1450{
1451 QVBoxLayout *pLayout = new QVBoxLayout;
1452 if (!pLayout)
1453 return;
1454 pLayout->setSpacing(0);
1455 setLayout(pLayout);
1456
1457 QHBoxLayout *pTitleLayout = new QHBoxLayout;
1458 m_pCloseButton = new QToolButton;
1459 m_pCloseButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
1460 m_pCloseButton->setIcon(UIIconPool::defaultIcon(UIIconPool::UIDefaultIconType_DialogCancel));
1461 m_pCloseButton->setAutoRaise(true);
1462 connect(m_pCloseButton, &QToolButton::clicked, this, &UILayoutSelector::sigCloseLayoutList);
1463 m_pTitleLabel = new QLabel;
1464 pTitleLayout->addWidget(m_pTitleLabel);
1465 pTitleLayout->addStretch(2);
1466 pTitleLayout->addWidget(m_pCloseButton);
1467 pLayout->addLayout(pTitleLayout);
1468
1469 m_pLayoutListWidget = new QListWidget;
1470 pLayout->addWidget(m_pLayoutListWidget);
1471 m_pLayoutListWidget->setSortingEnabled(true);
1472 connect(m_pLayoutListWidget, &QListWidget::currentItemChanged, this, &UILayoutSelector::sltCurrentItemChanged);
1473
1474 m_pLayoutListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
1475 QHBoxLayout *pButtonsLayout = new QHBoxLayout;
1476 pLayout->addLayout(pButtonsLayout);
1477
1478 m_pEditLayoutButton = new QToolButton;
1479 m_pEditLayoutButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_layout_edit_16px.png", ":/soft_keyboard_layout_edit_disabled_16px.png"));
1480 pButtonsLayout->addWidget(m_pEditLayoutButton);
1481 connect(m_pEditLayoutButton, &QToolButton::clicked, this, &UILayoutSelector::sigShowLayoutEditor);
1482
1483 m_pCopyLayoutButton = new QToolButton;
1484 m_pCopyLayoutButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_layout_copy_16px.png", ":/soft_keyboard_layout_copy_disabled_16px.png"));
1485 pButtonsLayout->addWidget(m_pCopyLayoutButton);
1486 connect(m_pCopyLayoutButton, &QToolButton::clicked, this, &UILayoutSelector::sigCopyLayout);
1487
1488 m_pSaveLayoutButton = new QToolButton;
1489 m_pSaveLayoutButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_layout_save_16px.png", ":/soft_keyboard_layout_save_disabled_16px.png"));
1490 pButtonsLayout->addWidget(m_pSaveLayoutButton);
1491 connect(m_pSaveLayoutButton, &QToolButton::clicked, this, &UILayoutSelector::sigSaveLayout);
1492
1493 m_pDeleteLayoutButton = new QToolButton;
1494 m_pDeleteLayoutButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_layout_remove_16px.png", ":/soft_keyboard_layout_remove_disabled_16px.png"));
1495 pButtonsLayout->addWidget(m_pDeleteLayoutButton);
1496 connect(m_pDeleteLayoutButton, &QToolButton::clicked, this, &UILayoutSelector::sigDeleteLayout);
1497
1498 pButtonsLayout->addStretch(2);
1499
1500 retranslateUi();
1501}
1502
1503void UILayoutSelector::sltCurrentItemChanged(QListWidgetItem *pCurrent, QListWidgetItem *pPrevious)
1504{
1505 Q_UNUSED(pPrevious);
1506 if (!pCurrent)
1507 return;
1508 emit sigLayoutSelectionChanged(pCurrent->data(Qt::UserRole).toUuid());
1509}
1510
1511/*********************************************************************************************************************************
1512* UISoftKeyboardRow implementation. *
1513*********************************************************************************************************************************/
1514
1515UISoftKeyboardRow::UISoftKeyboardRow()
1516 : m_iDefaultWidth(0)
1517 , m_iDefaultHeight(0)
1518 , m_iSpaceHeightAfter(0)
1519 , m_iLeftMargin(0)
1520{
1521}
1522
1523void UISoftKeyboardRow::setDefaultWidth(int iWidth)
1524{
1525 m_iDefaultWidth = iWidth;
1526}
1527
1528int UISoftKeyboardRow::defaultWidth() const
1529{
1530 return m_iDefaultWidth;
1531}
1532
1533int UISoftKeyboardRow::totalHeight() const
1534{
1535 int iMaxHeight = 0;
1536 for (int i = 0; i < m_keys.size(); ++i)
1537 iMaxHeight = qMax(iMaxHeight, m_keys[i].height());
1538 return iMaxHeight + m_iSpaceHeightAfter;
1539}
1540
1541void UISoftKeyboardRow::setDefaultHeight(int iHeight)
1542{
1543 m_iDefaultHeight = iHeight;
1544}
1545
1546int UISoftKeyboardRow::defaultHeight() const
1547{
1548 return m_iDefaultHeight;
1549}
1550
1551QVector<UISoftKeyboardKey> &UISoftKeyboardRow::keys()
1552{
1553 return m_keys;
1554}
1555
1556const QVector<UISoftKeyboardKey> &UISoftKeyboardRow::keys() const
1557{
1558 return m_keys;
1559}
1560
1561void UISoftKeyboardRow::setSpaceHeightAfter(int iSpace)
1562{
1563 m_iSpaceHeightAfter = iSpace;
1564}
1565
1566int UISoftKeyboardRow::spaceHeightAfter() const
1567{
1568 return m_iSpaceHeightAfter;
1569}
1570
1571int UISoftKeyboardRow::leftMargin() const
1572{
1573 return m_iLeftMargin;
1574}
1575
1576void UISoftKeyboardRow::setLeftMargin(int iMargin)
1577{
1578 m_iLeftMargin = iMargin;
1579}
1580
1581/*********************************************************************************************************************************
1582* UISoftKeyboardKey implementation. *
1583*********************************************************************************************************************************/
1584
1585UISoftKeyboardKey::UISoftKeyboardKey()
1586 : m_enmType(KeyType_Ordinary)
1587 , m_enmState(KeyState_NotPressed)
1588 , m_iWidth(0)
1589 , m_iHeight(0)
1590 , m_iSpaceWidthAfter(0)
1591 , m_scanCode(0)
1592 , m_iCutoutWidth(0)
1593 , m_iCutoutHeight(0)
1594 , m_iCutoutCorner(-1)
1595 , m_iPosition(0)
1596 , m_pParentWidget(0)
1597 , m_enmKeyboardRegion(KeyboardRegion_Main)
1598 , m_fIsOSMenuKey(false)
1599 , m_fCornerRadius(5.)
1600{
1601}
1602
1603const QRect UISoftKeyboardKey::keyGeometry() const
1604{
1605 return m_keyGeometry;
1606}
1607
1608void UISoftKeyboardKey::setKeyGeometry(const QRect &rect)
1609{
1610 m_keyGeometry = rect;
1611}
1612
1613
1614void UISoftKeyboardKey::setWidth(int iWidth)
1615{
1616 m_iWidth = iWidth;
1617}
1618
1619int UISoftKeyboardKey::width() const
1620{
1621 return m_iWidth;
1622}
1623
1624void UISoftKeyboardKey::setHeight(int iHeight)
1625{
1626 m_iHeight = iHeight;
1627}
1628
1629int UISoftKeyboardKey::height() const
1630{
1631 return m_iHeight;
1632}
1633
1634void UISoftKeyboardKey::setScanCode(LONG scanCode)
1635{
1636 m_scanCode = scanCode;
1637}
1638
1639LONG UISoftKeyboardKey::scanCode() const
1640{
1641 return m_scanCode;
1642}
1643
1644void UISoftKeyboardKey::addScanCodePrefix(LONG scanCodePrefix)
1645{
1646 m_scanCodePrefix << scanCodePrefix;
1647}
1648
1649void UISoftKeyboardKey::setSpaceWidthAfter(int iSpace)
1650{
1651 m_iSpaceWidthAfter = iSpace;
1652}
1653
1654int UISoftKeyboardKey::spaceWidthAfter() const
1655{
1656 return m_iSpaceWidthAfter;
1657}
1658
1659void UISoftKeyboardKey::setUsageId(LONG usageId)
1660{
1661 m_iUsageId = usageId;
1662}
1663
1664void UISoftKeyboardKey::setUsagePage(LONG usagePage)
1665{
1666 m_iUsagePage = usagePage;
1667}
1668
1669QPair<LONG, LONG> UISoftKeyboardKey::usagePageIdPair() const
1670{
1671 return QPair<LONG, LONG>(m_iUsageId, m_iUsagePage);
1672}
1673
1674void UISoftKeyboardKey::setPosition(int iPosition)
1675{
1676 m_iPosition = iPosition;
1677}
1678
1679int UISoftKeyboardKey::position() const
1680{
1681 return m_iPosition;
1682}
1683
1684void UISoftKeyboardKey::setType(KeyType enmType)
1685{
1686 m_enmType = enmType;
1687}
1688
1689KeyType UISoftKeyboardKey::type() const
1690{
1691 return m_enmType;
1692}
1693
1694KeyboardRegion UISoftKeyboardKey::keyboardRegion() const
1695{
1696 return m_enmKeyboardRegion;
1697}
1698
1699void UISoftKeyboardKey::setKeyboardRegion(KeyboardRegion enmRegion)
1700{
1701 m_enmKeyboardRegion = enmRegion;
1702}
1703
1704void UISoftKeyboardKey::setCutout(int iCorner, int iWidth, int iHeight)
1705{
1706 m_iCutoutCorner = iCorner;
1707 m_iCutoutWidth = iWidth;
1708 m_iCutoutHeight = iHeight;
1709}
1710
1711KeyState UISoftKeyboardKey::state() const
1712{
1713 return m_enmState;
1714}
1715
1716void UISoftKeyboardKey::setState(KeyState state)
1717{
1718 m_enmState = state;
1719}
1720
1721void UISoftKeyboardKey::setStaticCaption(const QString &strCaption)
1722{
1723 m_strStaticCaption = strCaption;
1724}
1725
1726const QString &UISoftKeyboardKey::staticCaption() const
1727{
1728 return m_strStaticCaption;
1729}
1730
1731void UISoftKeyboardKey::setImageByName(const QString &strImageFileName)
1732{
1733 if (strImageFileName.isEmpty())
1734 return;
1735 m_icon = UIIconPool::iconSet(QString(":/%1").arg(strImageFileName));
1736}
1737
1738QPixmap UISoftKeyboardKey::image() const
1739{
1740 QPixmap pixmap;
1741
1742 /* Check whether we have valid icon: */
1743 if (!m_icon.isNull())
1744 {
1745 /* Determine desired icon size: */
1746 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_LargeIconSize);
1747 const QSize iconSize = QSize(iIconMetric, iIconMetric);
1748 /* Get pixmap of requested size (take into account the DPI of the main shown window, if possible): */
1749 const qreal fDevicePixelRatio = windowManager().mainWindowShown() && windowManager().mainWindowShown()->windowHandle()
1750 ? windowManager().mainWindowShown()->windowHandle()->devicePixelRatio() : 1;
1751 pixmap = m_icon.pixmap(iconSize, fDevicePixelRatio);
1752 }
1753
1754 return pixmap;
1755}
1756
1757void UISoftKeyboardKey::setParentWidget(UISoftKeyboardWidget* pParent)
1758{
1759 m_pParentWidget = pParent;
1760}
1761
1762void UISoftKeyboardKey::setIsOSMenuKey(bool fFlag)
1763{
1764 m_fIsOSMenuKey = fFlag;
1765}
1766
1767bool UISoftKeyboardKey::isOSMenuKey() const
1768{
1769 return m_fIsOSMenuKey;
1770}
1771
1772void UISoftKeyboardKey::release()
1773{
1774 /* Lock key states are controlled by the event signals we get from the guest OS. See updateLockKeyState function: */
1775 if (m_enmType != KeyType_Lock)
1776 updateState(false);
1777}
1778
1779void UISoftKeyboardKey::press()
1780{
1781 /* Lock key states are controlled by the event signals we get from the guest OS. See updateLockKeyState function: */
1782 if (m_enmType != KeyType_Lock)
1783 updateState(true);
1784}
1785
1786void UISoftKeyboardKey::setPoints(const QVector<QPointF> &points)
1787{
1788 m_points = points;
1789 computePainterPath();
1790}
1791
1792const QVector<QPointF> &UISoftKeyboardKey::points() const
1793{
1794 return m_points;
1795}
1796
1797const QPainterPath &UISoftKeyboardKey::painterPath() const
1798{
1799 return m_painterPath;
1800}
1801
1802void UISoftKeyboardKey::computePainterPath()
1803{
1804 if (m_points.size() < 3)
1805 return;
1806
1807 m_painterPath = QPainterPath(pointInBetween(m_fCornerRadius, m_points[0], m_points[1]));
1808 for (int i = 0; i < m_points.size(); ++i)
1809 {
1810 QPointF p0 = pointInBetween(m_fCornerRadius, m_points[(i+1)%m_points.size()], m_points[i]);
1811 QPointF p1 = pointInBetween(m_fCornerRadius, m_points[(i+1)%m_points.size()], m_points[(i+2)%m_points.size()]);
1812 m_painterPath.lineTo(p0);
1813 m_painterPath.quadTo(m_points[(i+1)%m_points.size()], p1);
1814 }
1815}
1816
1817void UISoftKeyboardKey::setCornerRadius(float fCornerRadius)
1818{
1819 m_fCornerRadius = fCornerRadius;
1820}
1821
1822QPolygonF UISoftKeyboardKey::polygonInGlobal() const
1823{
1824 QPolygonF globalPolygon(m_points);
1825 globalPolygon.translate(m_keyGeometry.x(), m_keyGeometry.y());
1826 return globalPolygon;
1827}
1828
1829int UISoftKeyboardKey::cutoutCorner() const
1830{
1831 return m_iCutoutCorner;
1832}
1833
1834int UISoftKeyboardKey::cutoutWidth() const
1835{
1836 return m_iCutoutWidth;
1837}
1838
1839int UISoftKeyboardKey::cutoutHeight() const
1840{
1841 return m_iCutoutHeight;
1842}
1843
1844void UISoftKeyboardKey::updateState(bool fPressed)
1845{
1846 KeyState enmPreviousState = state();
1847 if (m_enmType == KeyType_Modifier)
1848 {
1849 if (fPressed)
1850 {
1851 if (m_enmState == KeyState_NotPressed)
1852 m_enmState = KeyState_Pressed;
1853 else if(m_enmState == KeyState_Pressed)
1854 m_enmState = KeyState_Locked;
1855 else
1856 m_enmState = KeyState_NotPressed;
1857 }
1858 else
1859 {
1860 if(m_enmState == KeyState_Pressed)
1861 m_enmState = KeyState_NotPressed;
1862 }
1863 }
1864 else if (m_enmType == KeyType_Lock)
1865 {
1866 m_enmState = fPressed ? KeyState_Locked : KeyState_NotPressed;
1867 }
1868 else if (m_enmType == KeyType_Ordinary)
1869 {
1870 if (m_enmState == KeyState_NotPressed)
1871 m_enmState = KeyState_Pressed;
1872 else
1873 m_enmState = KeyState_NotPressed;
1874 }
1875 if (enmPreviousState != state() && m_pParentWidget)
1876 m_pParentWidget->keyStateChange(this);
1877}
1878
1879void UISoftKeyboardKey::updateLockState(bool fLocked)
1880{
1881 if (m_enmType != KeyType_Lock)
1882 return;
1883 if (fLocked && m_enmState == KeyState_Locked)
1884 return;
1885 if (!fLocked && m_enmState == KeyState_NotPressed)
1886 return;
1887 updateState(fLocked);
1888}
1889
1890void UISoftKeyboardKey::reset()
1891{
1892 m_enmState = KeyState_NotPressed;
1893}
1894
1895
1896/*********************************************************************************************************************************
1897* UISoftKeyboardLayout implementation. *
1898*********************************************************************************************************************************/
1899
1900UISoftKeyboardLayout::UISoftKeyboardLayout()
1901 : m_fEditable(true)
1902 , m_fIsFromResources(false)
1903 , m_fEditedButNotSaved(false)
1904 , m_uid(QUuid::createUuid())
1905{
1906}
1907
1908QString UISoftKeyboardLayout::nameString() const
1909{
1910 QString strCombinedName;
1911 if (nativeName().isEmpty() && !name().isEmpty())
1912 strCombinedName = name();
1913 else if (!nativeName().isEmpty() && name().isEmpty())
1914 strCombinedName = nativeName();
1915 else
1916 strCombinedName = QString("%1 (%2)").arg(nativeName()).arg(name());
1917 return strCombinedName;
1918}
1919
1920void UISoftKeyboardLayout::setSourceFilePath(const QString& strSourceFilePath)
1921{
1922 m_strSourceFilePath = strSourceFilePath;
1923 setEditedBuNotSaved(true);
1924}
1925
1926const QString& UISoftKeyboardLayout::sourceFilePath() const
1927{
1928 return m_strSourceFilePath;
1929}
1930
1931void UISoftKeyboardLayout::setIsFromResources(bool fIsFromResources)
1932{
1933 m_fIsFromResources = fIsFromResources;
1934 setEditedBuNotSaved(true);
1935}
1936
1937bool UISoftKeyboardLayout::isFromResources() const
1938{
1939 return m_fIsFromResources;
1940}
1941
1942void UISoftKeyboardLayout::setName(const QString &strName)
1943{
1944 m_strName = strName;
1945 setEditedBuNotSaved(true);
1946}
1947
1948const QString &UISoftKeyboardLayout::name() const
1949{
1950 return m_strName;
1951}
1952
1953void UISoftKeyboardLayout::setNativeName(const QString &strNativeName)
1954{
1955 m_strNativeName = strNativeName;
1956 setEditedBuNotSaved(true);
1957}
1958
1959const QString &UISoftKeyboardLayout::nativeName() const
1960{
1961 return m_strNativeName;
1962}
1963
1964void UISoftKeyboardLayout::setEditable(bool fEditable)
1965{
1966 m_fEditable = fEditable;
1967 setEditedBuNotSaved(true);
1968}
1969
1970bool UISoftKeyboardLayout::editable() const
1971{
1972 return m_fEditable;
1973}
1974
1975void UISoftKeyboardLayout::setPhysicalLayoutUuid(const QUuid &uuid)
1976{
1977 m_physicalLayoutUuid = uuid;
1978 setEditedBuNotSaved(true);
1979}
1980
1981const QUuid &UISoftKeyboardLayout::physicalLayoutUuid() const
1982{
1983 return m_physicalLayoutUuid;
1984}
1985
1986void UISoftKeyboardLayout::addOrUpdateUIKeyCaptions(int iKeyPosition, const UIKeyCaptions &keyCaptions)
1987{
1988 if (m_keyCaptionsMap[iKeyPosition] == keyCaptions)
1989 return;
1990 m_keyCaptionsMap[iKeyPosition] = keyCaptions;
1991 /* Updating the captions invalidates the cached font size. We set it to 0, thereby forcing its recomputaion: */
1992 m_keyCaptionsFontSizeMap[iKeyPosition] = 0;
1993 setEditedBuNotSaved(true);
1994}
1995
1996UIKeyCaptions UISoftKeyboardLayout::keyCaptions(int iKeyPosition) const
1997{
1998 return m_keyCaptionsMap[iKeyPosition];
1999}
2000
2001bool UISoftKeyboardLayout::operator==(const UISoftKeyboardLayout &otherLayout) const
2002{
2003 if (m_strName != otherLayout.m_strName)
2004 return false;
2005 if (m_strNativeName != otherLayout.m_strNativeName)
2006 return false;
2007 if (m_physicalLayoutUuid != otherLayout.m_physicalLayoutUuid)
2008 return false;
2009 if (m_fEditable != otherLayout.m_fEditable)
2010 return false;
2011 if (m_strSourceFilePath != otherLayout.m_strSourceFilePath)
2012 return false;
2013 if (m_fIsFromResources != otherLayout.m_fIsFromResources)
2014 return false;
2015 return true;
2016}
2017
2018QString UISoftKeyboardLayout::baseCaption(int iKeyPosition) const
2019{
2020 return m_keyCaptionsMap.value(iKeyPosition, UIKeyCaptions()).m_strBase;
2021}
2022
2023QString UISoftKeyboardLayout::shiftCaption(int iKeyPosition) const
2024{
2025 if (!m_keyCaptionsMap.contains(iKeyPosition))
2026 return QString();
2027 return m_keyCaptionsMap[iKeyPosition].m_strShift;
2028}
2029
2030QString UISoftKeyboardLayout::altGrCaption(int iKeyPosition) const
2031{
2032 if (!m_keyCaptionsMap.contains(iKeyPosition))
2033 return QString();
2034 return m_keyCaptionsMap[iKeyPosition].m_strAltGr;
2035}
2036
2037QString UISoftKeyboardLayout::shiftAltGrCaption(int iKeyPosition) const
2038{
2039 if (!m_keyCaptionsMap.contains(iKeyPosition))
2040 return QString();
2041 return m_keyCaptionsMap[iKeyPosition].m_strShiftAltGr;
2042}
2043
2044void UISoftKeyboardLayout::setEditedBuNotSaved(bool fEditedButNotsaved)
2045{
2046 m_fEditedButNotSaved = fEditedButNotsaved;
2047}
2048
2049bool UISoftKeyboardLayout::editedButNotSaved() const
2050{
2051 return m_fEditedButNotSaved;
2052}
2053
2054void UISoftKeyboardLayout::setUid(const QUuid &uid)
2055{
2056 m_uid = uid;
2057 setEditedBuNotSaved(true);
2058}
2059
2060QUuid UISoftKeyboardLayout::uid() const
2061{
2062 return m_uid;
2063}
2064
2065void UISoftKeyboardLayout::drawTextInRect(const UISoftKeyboardKey &key, QPainter &painter)
2066{
2067 int iKeyPosition = key.position();
2068 const QRect &keyGeometry = key.keyGeometry();
2069 QFont painterFont(painter.font());
2070
2071 QString strBaseCaption;
2072 QString strShiftCaption;
2073 QString strShiftAltGrCaption;
2074 QString strAltGrCaption;
2075
2076 /* Static captions which are defined in the physical layout files have precedence over
2077 the one define in the keyboard layouts. In effect they stay the same for all the
2078 keyboard layouts sharing the same physical layout: */
2079
2080 if (key.staticCaption().isEmpty())
2081 {
2082 strBaseCaption = baseCaption(iKeyPosition);
2083 strShiftCaption = shiftCaption(iKeyPosition);
2084 strShiftAltGrCaption = shiftAltGrCaption(iKeyPosition);
2085 strAltGrCaption = altGrCaption(iKeyPosition);
2086 }
2087 else
2088 strBaseCaption = key.staticCaption();
2089
2090 const QString &strTopleftString = !strShiftCaption.isEmpty() ? strShiftCaption : strBaseCaption;
2091 const QString &strBottomleftString = !strShiftCaption.isEmpty() ? strBaseCaption : QString();
2092
2093 int iFontSize = 30;
2094 if (!m_keyCaptionsFontSizeMap.contains(iKeyPosition) || m_keyCaptionsFontSizeMap.value(iKeyPosition) == 0)
2095 {
2096 do
2097 {
2098 painterFont.setPixelSize(iFontSize);
2099 painterFont.setBold(true);
2100 painter.setFont(painterFont);
2101 QFontMetrics fontMetrics = painter.fontMetrics();
2102#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
2103 int iMargin = 0.25 * fontMetrics.horizontalAdvance('X');
2104#else
2105 int iMargin = 0.25 * fontMetrics.width('X');
2106#endif
2107
2108 int iTopWidth = 0;
2109 /* Some captions are multi line using \n as separator: */
2110 QStringList strList;
2111#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
2112 strList << strTopleftString.split("\n", Qt::SkipEmptyParts)
2113 << strShiftAltGrCaption.split("\n", Qt::SkipEmptyParts);
2114#else
2115 strList << strTopleftString.split("\n", QString::SkipEmptyParts)
2116 << strShiftAltGrCaption.split("\n", QString::SkipEmptyParts);
2117#endif
2118 foreach (const QString &strPart, strList)
2119#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
2120 iTopWidth = qMax(iTopWidth, fontMetrics.horizontalAdvance(strPart));
2121#else
2122 iTopWidth = qMax(iTopWidth, fontMetrics.width(strPart));
2123#endif
2124 strList.clear();
2125#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
2126 strList << strBottomleftString.split("\n", Qt::SkipEmptyParts)
2127 << strAltGrCaption.split("\n", Qt::SkipEmptyParts);
2128#else
2129 strList << strBottomleftString.split("\n", QString::SkipEmptyParts)
2130 << strAltGrCaption.split("\n", QString::SkipEmptyParts);
2131#endif
2132
2133 int iBottomWidth = 0;
2134 foreach (const QString &strPart, strList)
2135#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
2136 iBottomWidth = qMax(iBottomWidth, fontMetrics.horizontalAdvance(strPart));
2137#else
2138 iBottomWidth = qMax(iBottomWidth, fontMetrics.width(strPart));
2139#endif
2140 int iTextWidth = 2 * iMargin + qMax(iTopWidth, iBottomWidth);
2141 int iTextHeight = 0;
2142
2143 if (key.keyboardRegion() == KeyboardRegion_MultimediaKeys)
2144 iTextHeight = 2 * iMargin + fontMetrics.height();
2145 else
2146 iTextHeight = 2 * iMargin + 2 * fontMetrics.height();
2147
2148 if (iTextWidth >= keyGeometry.width() || iTextHeight >= keyGeometry.height())
2149 --iFontSize;
2150 else
2151 break;
2152
2153 }while(iFontSize > 1);
2154 m_keyCaptionsFontSizeMap[iKeyPosition] = iFontSize;
2155 }
2156 else
2157 {
2158 iFontSize = m_keyCaptionsFontSizeMap[iKeyPosition];
2159 painterFont.setPixelSize(iFontSize);
2160 painterFont.setBold(true);
2161 painter.setFont(painterFont);
2162 }
2163
2164 QFontMetrics fontMetrics = painter.fontMetrics();
2165#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
2166 int iMargin = 0.25 * fontMetrics.horizontalAdvance('X');
2167#else
2168 int iMargin = 0.25 * fontMetrics.width('X');
2169#endif
2170 QRect textRect;
2171 if (key.keyboardRegion() == KeyboardRegion_MultimediaKeys)
2172 textRect = QRect(2 * iMargin, iMargin,
2173 keyGeometry.width() - 2 * iMargin,
2174 keyGeometry.height() - 2 * iMargin);
2175 else
2176 textRect = QRect(iMargin, iMargin,
2177 keyGeometry.width() - 2 * iMargin,
2178 keyGeometry.height() - 2 * iMargin);
2179
2180 if (key.keyboardRegion() == KeyboardRegion_MultimediaKeys)
2181 {
2182 painter.drawText(QRect(0, 0, keyGeometry.width(), keyGeometry.height()),
2183 Qt::AlignHCenter | Qt::AlignVCenter, strTopleftString);
2184 }
2185 else
2186 {
2187 painter.drawText(textRect, Qt::AlignLeft | Qt::AlignTop, strTopleftString);
2188 painter.drawText(textRect, Qt::AlignLeft | Qt::AlignBottom, strBottomleftString);
2189 painter.drawText(textRect, Qt::AlignRight | Qt::AlignTop, strShiftAltGrCaption);
2190 painter.drawText(textRect, Qt::AlignRight | Qt::AlignBottom, strAltGrCaption);
2191 }
2192}
2193
2194void UISoftKeyboardLayout::drawKeyImageInRect(const UISoftKeyboardKey &key, QPainter &painter)
2195{
2196 if (key.image().isNull())
2197 return;
2198 const QRect &keyGeometry = key.keyGeometry();
2199 int iMargin = 0.1 * qMax(keyGeometry.width(), keyGeometry.height());
2200 int size = qMin(keyGeometry.width() - 2 * iMargin, keyGeometry.height() - 2 * iMargin);
2201 painter.drawPixmap(QRect(0.5 * (keyGeometry.width() - size), 0.5 * (keyGeometry.height() - size),
2202 size, size), key.image());
2203}
2204
2205
2206/*********************************************************************************************************************************
2207* UISoftKeyboardColorTheme implementation. *
2208*********************************************************************************************************************************/
2209
2210UISoftKeyboardColorTheme::UISoftKeyboardColorTheme()
2211 : m_colors(QVector<QColor>(KeyboardColorType_Max))
2212 , m_fIsEditable(false)
2213{
2214 m_colors[KeyboardColorType_Background].setNamedColor("#ff878787");
2215 m_colors[KeyboardColorType_Font].setNamedColor("#ff000000");
2216 m_colors[KeyboardColorType_Hover].setNamedColor("#ff676767");
2217 m_colors[KeyboardColorType_Edit].setNamedColor("#ff9b6767");
2218 m_colors[KeyboardColorType_Pressed].setNamedColor("#fffafafa");
2219}
2220
2221UISoftKeyboardColorTheme::UISoftKeyboardColorTheme(const QString &strName,
2222 const QString &strBackgroundColor,
2223 const QString &strNormalFontColor,
2224 const QString &strHoverColor,
2225 const QString &strEditedButtonBackgroundColor,
2226 const QString &strPressedButtonFontColor)
2227 :m_colors(QVector<QColor>(KeyboardColorType_Max))
2228 ,m_strName(strName)
2229 , m_fIsEditable(false)
2230{
2231 m_colors[KeyboardColorType_Background].setNamedColor(strBackgroundColor);
2232 m_colors[KeyboardColorType_Font].setNamedColor(strNormalFontColor);
2233 m_colors[KeyboardColorType_Hover].setNamedColor(strHoverColor);
2234 m_colors[KeyboardColorType_Edit].setNamedColor(strEditedButtonBackgroundColor);
2235 m_colors[KeyboardColorType_Pressed].setNamedColor(strPressedButtonFontColor);
2236}
2237
2238
2239void UISoftKeyboardColorTheme::setColor(KeyboardColorType enmColorType, const QColor &color)
2240{
2241 if ((int) enmColorType >= m_colors.size())
2242 return;
2243 m_colors[(int)enmColorType] = color;
2244}
2245
2246QColor UISoftKeyboardColorTheme::color(KeyboardColorType enmColorType) const
2247{
2248 if ((int) enmColorType >= m_colors.size())
2249 return QColor();
2250 return m_colors[(int)enmColorType];
2251}
2252
2253QStringList UISoftKeyboardColorTheme::colorsToStringList() const
2254{
2255 QStringList colorStringList;
2256 foreach (const QColor &color, m_colors)
2257 colorStringList << color.name(QColor::HexArgb);
2258 return colorStringList;
2259}
2260
2261void UISoftKeyboardColorTheme::colorsFromStringList(const QStringList &colorStringList)
2262{
2263 for (int i = 0; i < colorStringList.size() && i < m_colors.size(); ++i)
2264 {
2265 if (!QColor::isValidColor(colorStringList[i]))
2266 continue;
2267 m_colors[i].setNamedColor(colorStringList[i]);
2268 }
2269}
2270
2271const QString &UISoftKeyboardColorTheme::name() const
2272{
2273 return m_strName;
2274}
2275
2276void UISoftKeyboardColorTheme::setName(const QString &strName)
2277{
2278 m_strName = strName;
2279}
2280
2281bool UISoftKeyboardColorTheme::isEditable() const
2282{
2283 return m_fIsEditable;
2284}
2285
2286void UISoftKeyboardColorTheme::setIsEditable(bool fIsEditable)
2287{
2288 m_fIsEditable = fIsEditable;
2289}
2290
2291/*********************************************************************************************************************************
2292* UISoftKeyboardWidget implementation. *
2293*********************************************************************************************************************************/
2294
2295UISoftKeyboardWidget::UISoftKeyboardWidget(QWidget *pParent /* = 0 */)
2296 :QIWithRetranslateUI<QWidget>(pParent)
2297 , m_pKeyUnderMouse(0)
2298 , m_pKeyBeingEdited(0)
2299 , m_pKeyPressed(0)
2300 , m_currentColorTheme(0)
2301 , m_iInitialHeight(0)
2302 , m_iInitialWidth(0)
2303 , m_iInitialWidthNoNumPad(0)
2304 , m_iBeforeNumPadWidth(30)
2305 , m_iXSpacing(5)
2306 , m_iYSpacing(5)
2307 , m_iLeftMargin(10)
2308 , m_iTopMargin(10)
2309 , m_iRightMargin(10)
2310 , m_iBottomMargin(10)
2311 , m_enmMode(Mode_Keyboard)
2312 , m_fHideOSMenuKeys(false)
2313 , m_fHideNumPad(false)
2314 , m_fHideMultimediaKeys(false)
2315{
2316 prepareObjects();
2317 prepareColorThemes();
2318 retranslateUi();
2319}
2320
2321QSize UISoftKeyboardWidget::minimumSizeHint() const
2322{
2323 float fScale = 0.5f;
2324 return QSize(fScale * m_minimumSize.width(), fScale * m_minimumSize.height());
2325}
2326
2327QSize UISoftKeyboardWidget::sizeHint() const
2328{
2329 float fScale = 0.5f;
2330 return QSize(fScale * m_minimumSize.width(), fScale * m_minimumSize.height());
2331}
2332
2333void UISoftKeyboardWidget::paintEvent(QPaintEvent *pEvent) /* override */
2334{
2335 Q_UNUSED(pEvent);
2336 if (!m_layouts.contains(m_uCurrentLayoutId))
2337 return;
2338
2339 UISoftKeyboardLayout &currentLayout = m_layouts[m_uCurrentLayoutId];
2340
2341 if (m_iInitialWidth == 0 || m_iInitialWidthNoNumPad == 0 || m_iInitialHeight == 0)
2342 return;
2343
2344 if (!m_fHideNumPad)
2345 m_fScaleFactorX = width() / (float) (m_iInitialWidth + m_iBeforeNumPadWidth);
2346 else
2347 m_fScaleFactorX = width() / (float) m_iInitialWidthNoNumPad;
2348
2349 if (!m_fHideMultimediaKeys)
2350 m_fScaleFactorY = height() / (float) m_iInitialHeight;
2351 else
2352 m_fScaleFactorY = height() / (float)(m_iInitialHeight - m_multiMediaKeysLayout.totalHeight());
2353
2354 QPainter painter(this);
2355 QFont painterFont(font());
2356 painterFont.setPixelSize(15);
2357 painterFont.setBold(true);
2358 painter.setFont(painterFont);
2359 painter.setRenderHint(QPainter::Antialiasing);
2360 painter.setRenderHint(QPainter::SmoothPixmapTransform);
2361 painter.scale(m_fScaleFactorX, m_fScaleFactorY);
2362 int unitSize = qApp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin);
2363 float fLedRadius = 0.8 * unitSize;
2364 float fLedMargin = 5;//0.6 * unitSize;
2365
2366 UISoftKeyboardPhysicalLayout *pPhysicalLayout = findPhysicalLayout(currentLayout.physicalLayoutUuid());
2367 if (!pPhysicalLayout)
2368 return;
2369
2370 QVector<UISoftKeyboardRow> &rows = pPhysicalLayout->rows();
2371 for (int i = 0; i < rows.size(); ++i)
2372 {
2373 QVector<UISoftKeyboardKey> &keys = rows[i].keys();
2374 for (int j = 0; j < keys.size(); ++j)
2375 {
2376 UISoftKeyboardKey &key = keys[j];
2377
2378 if (m_fHideOSMenuKeys && key.isOSMenuKey())
2379 continue;
2380
2381 if (m_fHideNumPad && key.keyboardRegion() == KeyboardRegion_NumPad)
2382 continue;
2383
2384 if (m_fHideMultimediaKeys && key.keyboardRegion() == KeyboardRegion_MultimediaKeys)
2385 continue;
2386
2387 if (m_fHideMultimediaKeys)
2388 painter.translate(key.keyGeometry().x(), key.keyGeometry().y() - m_multiMediaKeysLayout.totalHeight());
2389 else
2390 painter.translate(key.keyGeometry().x(), key.keyGeometry().y());
2391
2392 if(&key == m_pKeyBeingEdited)
2393 painter.setBrush(QBrush(color(KeyboardColorType_Edit)));
2394 else if (&key == m_pKeyUnderMouse)
2395 painter.setBrush(QBrush(color(KeyboardColorType_Hover)));
2396 else
2397 painter.setBrush(QBrush(color(KeyboardColorType_Background)));
2398
2399 if (&key == m_pKeyPressed)
2400 painter.setPen(QPen(color(KeyboardColorType_Pressed), 2));
2401 else
2402 painter.setPen(QPen(color(KeyboardColorType_Font), 2));
2403
2404 /* Draw the key shape: */
2405 painter.drawPath(key.painterPath());
2406
2407 if (key.keyboardRegion() == KeyboardRegion_MultimediaKeys)
2408 currentLayout.drawKeyImageInRect(key, painter);
2409 else
2410 currentLayout.drawTextInRect(key, painter);
2411 /* Draw small LED like circles on the modifier/lock keys: */
2412 if (key.type() != KeyType_Ordinary)
2413 {
2414 QColor ledColor;
2415 if (key.type() == KeyType_Lock)
2416 {
2417 if (key.state() == KeyState_NotPressed)
2418 ledColor = color(KeyboardColorType_Font);
2419 else
2420 ledColor = QColor(0, 255, 0);
2421 }
2422 else
2423 {
2424 if (key.state() == KeyState_NotPressed)
2425 ledColor = color(KeyboardColorType_Font);
2426 else if (key.state() == KeyState_Pressed)
2427 ledColor = QColor(0, 191, 204);
2428 else
2429 ledColor = QColor(255, 50, 50);
2430 }
2431 if (m_enmMode == Mode_LayoutEdit)
2432 ledColor = color(KeyboardColorType_Font);
2433 painter.setBrush(ledColor);
2434 painter.setPen(ledColor);
2435 QRectF rectangle(key.keyGeometry().width() - 2 * fLedMargin, key.keyGeometry().height() - 2 * fLedMargin,
2436 fLedRadius, fLedRadius);
2437 painter.drawEllipse(rectangle);
2438 }
2439 if (m_fHideMultimediaKeys)
2440 painter.translate(-key.keyGeometry().x(), -key.keyGeometry().y() + m_multiMediaKeysLayout.totalHeight());
2441 else
2442 painter.translate(-key.keyGeometry().x(), -key.keyGeometry().y());
2443 }
2444 }
2445}
2446
2447void UISoftKeyboardWidget::mousePressEvent(QMouseEvent *pEvent)
2448{
2449 QWidget::mousePressEvent(pEvent);
2450 if (pEvent->button() != Qt::RightButton && pEvent->button() != Qt::LeftButton)
2451 return;
2452
2453 m_pKeyPressed = keyUnderMouse(pEvent);
2454 if (!m_pKeyPressed)
2455 return;
2456
2457 /* Handling the right button press: */
2458 if (pEvent->button() == Qt::RightButton)
2459 modifierKeyPressRelease(m_pKeyPressed, false);
2460 else
2461 {
2462 /* Handling the left button press: */
2463 if (m_enmMode == Mode_Keyboard)
2464 handleKeyPress(m_pKeyPressed);
2465 else if (m_enmMode == Mode_LayoutEdit)
2466 setKeyBeingEdited(m_pKeyUnderMouse);
2467 }
2468 update();
2469}
2470
2471void UISoftKeyboardWidget::mouseReleaseEvent(QMouseEvent *pEvent)
2472{
2473 QWidget::mouseReleaseEvent(pEvent);
2474
2475 if (pEvent->button() != Qt::RightButton && pEvent->button() != Qt::LeftButton)
2476 return;
2477
2478 if (!m_pKeyPressed)
2479 return;
2480 if (pEvent->button() == Qt::RightButton)
2481 modifierKeyPressRelease(m_pKeyPressed, true);
2482 else
2483 {
2484 if (m_enmMode == Mode_Keyboard)
2485 handleKeyRelease(m_pKeyPressed);
2486 }
2487 m_pKeyPressed = 0;
2488 update();
2489}
2490
2491void UISoftKeyboardWidget::mouseMoveEvent(QMouseEvent *pEvent)
2492{
2493 QWidget::mouseMoveEvent(pEvent);
2494 UISoftKeyboardKey *pPreviousKeyUnderMouse = m_pKeyUnderMouse;
2495 keyUnderMouse(pEvent);
2496 if (pPreviousKeyUnderMouse != m_pKeyUnderMouse)
2497 showKeyTooltip(m_pKeyUnderMouse);
2498}
2499
2500void UISoftKeyboardWidget::retranslateUi()
2501{
2502 m_keyTooltips[317] = UISoftKeyboard::tr("Power off");
2503 m_keyTooltips[300] = UISoftKeyboard::tr("Web browser go back");
2504 m_keyTooltips[301] = UISoftKeyboard::tr("Web browser go the home page");
2505 m_keyTooltips[302] = UISoftKeyboard::tr("Web browser go forward");
2506 m_keyTooltips[315] = UISoftKeyboard::tr("Web browser reload the current page");
2507 m_keyTooltips[314] = UISoftKeyboard::tr("Web browser stop loading the page");
2508 m_keyTooltips[313] = UISoftKeyboard::tr("Web browser search");
2509
2510 m_keyTooltips[307] = UISoftKeyboard::tr("Jump back to previous media track");
2511 m_keyTooltips[308] = UISoftKeyboard::tr("Jump to next media track");
2512 m_keyTooltips[309] = UISoftKeyboard::tr("Stop playing");
2513 m_keyTooltips[310] = UISoftKeyboard::tr("Play or pause playing");
2514
2515 m_keyTooltips[303] = UISoftKeyboard::tr("Start email application");
2516 m_keyTooltips[311] = UISoftKeyboard::tr("Start calculator");
2517 m_keyTooltips[312] = UISoftKeyboard::tr("Show 'My Computer'");
2518 m_keyTooltips[316] = UISoftKeyboard::tr("Show Media folder");
2519
2520 m_keyTooltips[304] = UISoftKeyboard::tr("Mute");
2521 m_keyTooltips[305] = UISoftKeyboard::tr("Volume down");
2522 m_keyTooltips[306] = UISoftKeyboard::tr("Volume up");
2523}
2524
2525void UISoftKeyboardWidget::saveCurentLayoutToFile()
2526{
2527 if (!m_layouts.contains(m_uCurrentLayoutId))
2528 return;
2529 UISoftKeyboardLayout &currentLayout = m_layouts[m_uCurrentLayoutId];
2530 QString strHomeFolder = uiCommon().homeFolder();
2531 QDir dir(strHomeFolder);
2532 if (!dir.exists(strSubDirectorName))
2533 {
2534 if (!dir.mkdir(strSubDirectorName))
2535 {
2536 sigStatusBarMessage(QString("%1 %2").arg(UISoftKeyboard::tr("Error! Could not create folder under").arg(strHomeFolder)));
2537 return;
2538 }
2539 }
2540
2541 strHomeFolder += QString(QDir::separator()) + strSubDirectorName;
2542 QInputDialog dialog(this);
2543 dialog.setInputMode(QInputDialog::TextInput);
2544 dialog.setWindowModality(Qt::WindowModal);
2545 dialog.setWindowTitle(UISoftKeyboard::tr("Provide a file name"));
2546 dialog.setTextValue(currentLayout.name());
2547 dialog.setLabelText(QString("%1 %2").arg(UISoftKeyboard::tr("The file will be saved under:<br>")).arg(strHomeFolder));
2548 if (dialog.exec() == QDialog::Rejected)
2549 return;
2550 QString strFileName(dialog.textValue());
2551 if (strFileName.isEmpty() || strFileName.contains("..") || strFileName.contains(QDir::separator()))
2552 {
2553 sigStatusBarMessage(QString("%1 %2").arg(strFileName).arg(UISoftKeyboard::tr(" is an invalid file name")));
2554 return;
2555 }
2556
2557 UISoftKeyboardPhysicalLayout *pPhysicalLayout = findPhysicalLayout(currentLayout.physicalLayoutUuid());
2558 if (!pPhysicalLayout)
2559 {
2560 sigStatusBarMessage("The layout file could not be saved");
2561 return;
2562 }
2563
2564 QFileInfo fileInfo(strFileName);
2565 if (fileInfo.suffix().compare("xml", Qt::CaseInsensitive) != 0)
2566 strFileName += ".xml";
2567 strFileName = strHomeFolder + QString(QDir::separator()) + strFileName;
2568 QFile xmlFile(strFileName);
2569 if (!xmlFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
2570 {
2571 sigStatusBarMessage("The layout file could not be saved");
2572 return;
2573 }
2574
2575 QXmlStreamWriter xmlWriter;
2576 xmlWriter.setDevice(&xmlFile);
2577
2578 xmlWriter.setAutoFormatting(true);
2579 xmlWriter.writeStartDocument("1.0");
2580 xmlWriter.writeStartElement("layout");
2581 xmlWriter.writeTextElement("name", currentLayout.name());
2582 xmlWriter.writeTextElement("nativename", currentLayout.nativeName());
2583 xmlWriter.writeTextElement("physicallayoutid", pPhysicalLayout->uid().toString());
2584 xmlWriter.writeTextElement("id", currentLayout.uid().toString());
2585
2586 QVector<UISoftKeyboardRow> &rows = pPhysicalLayout->rows();
2587 for (int i = 0; i < rows.size(); ++i)
2588 {
2589 QVector<UISoftKeyboardKey> &keys = rows[i].keys();
2590
2591 for (int j = 0; j < keys.size(); ++j)
2592 {
2593 xmlWriter.writeStartElement("key");
2594
2595 UISoftKeyboardKey &key = keys[j];
2596 xmlWriter.writeTextElement("position", QString::number(key.position()));
2597 xmlWriter.writeTextElement("basecaption", currentLayout.baseCaption(key.position()));
2598 xmlWriter.writeTextElement("shiftcaption", currentLayout.shiftCaption(key.position()));
2599 xmlWriter.writeTextElement("altgrcaption", currentLayout.altGrCaption(key.position()));
2600 xmlWriter.writeTextElement("shiftaltgrcaption", currentLayout.shiftAltGrCaption(key.position()));
2601 xmlWriter.writeEndElement();
2602 }
2603 }
2604 xmlWriter.writeEndElement();
2605 xmlWriter.writeEndDocument();
2606
2607 xmlFile.close();
2608 currentLayout.setSourceFilePath(strFileName);
2609 currentLayout.setEditedBuNotSaved(false);
2610 sigStatusBarMessage(QString("%1 %2").arg(strFileName).arg(UISoftKeyboard::tr(" is saved")));
2611}
2612
2613void UISoftKeyboardWidget::copyCurentLayout()
2614{
2615 UISoftKeyboardLayout newLayout(m_layouts[m_uCurrentLayoutId]);
2616
2617 QString strNewName = QString("%1-%2").arg(newLayout.name()).arg(UISoftKeyboard::tr("Copy"));
2618 int iCount = 1;
2619 while (layoutByNameExists(strNewName))
2620 {
2621 strNewName = QString("%1-%2-%3").arg(newLayout.name()).arg(UISoftKeyboard::tr("Copy")).arg(QString::number(iCount));
2622 ++iCount;
2623 }
2624
2625 newLayout.setName(strNewName);
2626 newLayout.setEditedBuNotSaved(true);
2627 newLayout.setEditable(true);
2628 newLayout.setIsFromResources(false);
2629 newLayout.setSourceFilePath(QString());
2630 newLayout.setUid(QUuid::createUuid());
2631 addLayout(newLayout);
2632}
2633
2634float UISoftKeyboardWidget::layoutAspectRatio()
2635{
2636 if (m_iInitialWidth == 0)
2637 return 1.f;
2638 return m_iInitialHeight / (float) m_iInitialWidth;
2639}
2640
2641bool UISoftKeyboardWidget::hideOSMenuKeys() const
2642{
2643 return m_fHideOSMenuKeys;
2644}
2645
2646void UISoftKeyboardWidget::setHideOSMenuKeys(bool fHide)
2647{
2648 if (m_fHideOSMenuKeys == fHide)
2649 return;
2650 m_fHideOSMenuKeys = fHide;
2651 update();
2652 emit sigOptionsChanged();
2653}
2654
2655bool UISoftKeyboardWidget::hideNumPad() const
2656{
2657 return m_fHideNumPad;
2658}
2659
2660void UISoftKeyboardWidget::setHideNumPad(bool fHide)
2661{
2662 if (m_fHideNumPad == fHide)
2663 return;
2664 m_fHideNumPad = fHide;
2665 update();
2666 emit sigOptionsChanged();
2667}
2668
2669bool UISoftKeyboardWidget::hideMultimediaKeys() const
2670{
2671 return m_fHideMultimediaKeys;
2672}
2673
2674void UISoftKeyboardWidget::setHideMultimediaKeys(bool fHide)
2675{
2676 if (m_fHideMultimediaKeys == fHide)
2677 return;
2678 m_fHideMultimediaKeys = fHide;
2679 update();
2680 emit sigOptionsChanged();
2681}
2682
2683QColor UISoftKeyboardWidget::color(KeyboardColorType enmColorType) const
2684{
2685 if (!m_currentColorTheme)
2686 return QColor();
2687 return m_currentColorTheme->color(enmColorType);
2688}
2689
2690void UISoftKeyboardWidget::setColor(KeyboardColorType enmColorType, const QColor &color)
2691{
2692 if (m_currentColorTheme)
2693 m_currentColorTheme->setColor(enmColorType, color);
2694 update();
2695}
2696
2697QStringList UISoftKeyboardWidget::colorsToStringList(const QString &strColorThemeName)
2698{
2699 UISoftKeyboardColorTheme *pTheme = colorTheme(strColorThemeName);
2700 if (!pTheme)
2701 return QStringList();
2702 return pTheme->colorsToStringList();
2703}
2704
2705void UISoftKeyboardWidget::colorsFromStringList(const QString &strColorThemeName, const QStringList &colorStringList)
2706{
2707 UISoftKeyboardColorTheme *pTheme = colorTheme(strColorThemeName);
2708 if (!pTheme)
2709 return;
2710 pTheme->colorsFromStringList(colorStringList);
2711}
2712
2713void UISoftKeyboardWidget::updateLockKeyStates(bool fCapsLockState, bool fNumLockState, bool fScrollLockState)
2714{
2715 for (int i = 0; i < m_physicalLayouts.size(); ++i)
2716 m_physicalLayouts[i].updateLockKeyStates(fCapsLockState, fNumLockState, fScrollLockState);
2717 update();
2718}
2719
2720QStringList UISoftKeyboardWidget::colorThemeNames() const
2721{
2722 QStringList nameList;
2723 foreach (const UISoftKeyboardColorTheme &theme, m_colorThemes)
2724 {
2725 nameList << theme.name();
2726 }
2727 return nameList;
2728}
2729
2730QString UISoftKeyboardWidget::currentColorThemeName() const
2731{
2732 if (!m_currentColorTheme)
2733 return QString();
2734 return m_currentColorTheme->name();
2735}
2736
2737void UISoftKeyboardWidget::setColorThemeByName(const QString &strColorThemeName)
2738{
2739 if (strColorThemeName.isEmpty())
2740 return;
2741 if (m_currentColorTheme && m_currentColorTheme->name() == strColorThemeName)
2742 return;
2743 for (int i = 0; i < m_colorThemes.size(); ++i)
2744 {
2745 if (m_colorThemes[i].name() == strColorThemeName)
2746 {
2747 m_currentColorTheme = &(m_colorThemes[i]);
2748 break;
2749 }
2750 }
2751 update();
2752 emit sigCurrentColorThemeChanged();
2753}
2754
2755void UISoftKeyboardWidget::parentDialogDeactivated()
2756{
2757 if (!underMouse())
2758 m_pKeyUnderMouse = 0;
2759 update();
2760}
2761
2762bool UISoftKeyboardWidget::isColorThemeEditable() const
2763{
2764 if (!m_currentColorTheme)
2765 return false;
2766 return m_currentColorTheme->isEditable();
2767}
2768
2769QStringList UISoftKeyboardWidget::unsavedLayoutsNameList() const
2770{
2771 QStringList nameList;
2772 foreach (const UISoftKeyboardLayout &layout, m_layouts)
2773 {
2774 if (layout.editedButNotSaved())
2775 nameList << layout.nameString();
2776 }
2777 return nameList;
2778}
2779
2780void UISoftKeyboardWidget::deleteCurrentLayout()
2781{
2782 if (!m_layouts.contains(m_uCurrentLayoutId))
2783 return;
2784
2785 /* Make sure we will have at least one layout remaining. */
2786 if (m_layouts.size() <= 1)
2787 return;
2788
2789 const UISoftKeyboardLayout &layout = m_layouts.value(m_uCurrentLayoutId);
2790 if (!layout.editable() || layout.isFromResources())
2791 return;
2792
2793 QDir fileToDelete;
2794 QString strFilePath(layout.sourceFilePath());
2795
2796 bool fFileExists = false;
2797 if (!strFilePath.isEmpty())
2798 fFileExists = fileToDelete.exists(strFilePath);
2799 /* It might be that the layout copied but not yet saved into a file: */
2800 if (fFileExists)
2801 {
2802 if (!msgCenter().questionBinary(this, MessageType_Question,
2803 QString(UISoftKeyboard::tr("This will delete the keyboard layout file as well. Proceed?")),
2804 0 /* auto-confirm id */,
2805 QString("Delete") /* ok button text */,
2806 QString() /* cancel button text */,
2807 false /* ok button by default? */))
2808 return;
2809
2810 if (fileToDelete.remove(strFilePath))
2811 sigStatusBarMessage(UISoftKeyboard::tr("The file %1 has been deleted").arg(strFilePath));
2812 else
2813 sigStatusBarMessage(UISoftKeyboard::tr("Deleting the file %1 has failed").arg(strFilePath));
2814 }
2815
2816 m_layouts.remove(m_uCurrentLayoutId);
2817 setCurrentLayout(m_layouts.firstKey());
2818}
2819
2820void UISoftKeyboardWidget::toggleEditMode(bool fIsEditMode)
2821{
2822 if (fIsEditMode)
2823 m_enmMode = Mode_LayoutEdit;
2824 else
2825 {
2826 m_enmMode = Mode_Keyboard;
2827 m_pKeyBeingEdited = 0;
2828 }
2829 update();
2830}
2831
2832void UISoftKeyboardWidget::addLayout(const UISoftKeyboardLayout &newLayout)
2833{
2834 if (m_layouts.contains(newLayout.uid()))
2835 return;
2836 m_layouts[newLayout.uid()] = newLayout;
2837}
2838
2839void UISoftKeyboardWidget::setNewMinimumSize(const QSize &size)
2840{
2841 m_minimumSize = size;
2842 updateGeometry();
2843}
2844
2845void UISoftKeyboardWidget::setInitialSize(int iWidth, int iHeight)
2846{
2847 m_iInitialWidth = iWidth;
2848 m_iInitialHeight = iHeight;
2849}
2850
2851UISoftKeyboardKey *UISoftKeyboardWidget::keyUnderMouse(QMouseEvent *pEvent)
2852{
2853 const QPoint lPos = pEvent->position().toPoint();
2854 QPoint eventPosition(lPos.x() / m_fScaleFactorX, lPos.y() / m_fScaleFactorY);
2855 if (m_fHideMultimediaKeys)
2856 eventPosition.setY(eventPosition.y() + m_multiMediaKeysLayout.totalHeight());
2857 return keyUnderMouse(eventPosition);
2858}
2859
2860UISoftKeyboardKey *UISoftKeyboardWidget::keyUnderMouse(const QPoint &eventPosition)
2861{
2862 const UISoftKeyboardLayout &currentLayout = m_layouts.value(m_uCurrentLayoutId);
2863
2864 UISoftKeyboardPhysicalLayout *pPhysicalLayout = findPhysicalLayout(currentLayout.physicalLayoutUuid());
2865 if (!pPhysicalLayout)
2866 return 0;
2867
2868 UISoftKeyboardKey *pKey = 0;
2869 QVector<UISoftKeyboardRow> &rows = pPhysicalLayout->rows();
2870 for (int i = 0; i < rows.size(); ++i)
2871 {
2872 QVector<UISoftKeyboardKey> &keys = rows[i].keys();
2873 for (int j = 0; j < keys.size(); ++j)
2874 {
2875 UISoftKeyboardKey &key = keys[j];
2876 if (key.polygonInGlobal().containsPoint(eventPosition, Qt::OddEvenFill))
2877 {
2878 pKey = &key;
2879 break;
2880 }
2881 }
2882 }
2883 if (m_pKeyUnderMouse != pKey)
2884 {
2885 m_pKeyUnderMouse = pKey;
2886 update();
2887 }
2888 return pKey;
2889}
2890
2891void UISoftKeyboardWidget::handleKeyRelease(UISoftKeyboardKey *pKey)
2892{
2893 if (!pKey)
2894 return;
2895 if (pKey->type() == KeyType_Ordinary)
2896 pKey->release();
2897 /* We only send the scan codes of Ordinary keys: */
2898 if (pKey->type() == KeyType_Modifier)
2899 return;
2900
2901#if 0
2902
2903 QVector<LONG> sequence;
2904 if (!pKey->scanCodePrefix().isEmpty())
2905 sequence << pKey->scanCodePrefix();
2906 sequence << (pKey->scanCode() | 0x80);
2907
2908 /* Add the pressed modifiers in the reverse order: */
2909 for (int i = m_pressedModifiers.size() - 1; i >= 0; --i)
2910 {
2911 UISoftKeyboardKey *pModifier = m_pressedModifiers[i];
2912 if (!pModifier->scanCodePrefix().isEmpty())
2913 sequence << pModifier->scanCodePrefix();
2914 sequence << (pModifier->scanCode() | 0x80);
2915 /* Release the pressed modifiers (if there are not locked): */
2916 pModifier->release();
2917 }
2918 emit sigPutKeyboardSequence(sequence);
2919
2920#else
2921
2922 QVector<QPair<LONG, LONG> > sequence;
2923 sequence << QPair<LONG, LONG>(pKey->usagePageIdPair());
2924 /* Add the pressed modifiers in the reverse order: */
2925 for (int i = m_pressedModifiers.size() - 1; i >= 0; --i)
2926 {
2927 UISoftKeyboardKey *pModifier = m_pressedModifiers[i];
2928 sequence << pModifier->usagePageIdPair();
2929 /* Release the pressed modifiers (if there are not locked): */
2930 pModifier->release();
2931 }
2932 emit sigPutUsageCodesRelease(sequence);
2933
2934#endif
2935}
2936
2937void UISoftKeyboardWidget::handleKeyPress(UISoftKeyboardKey *pKey)
2938{
2939 if (!pKey)
2940 return;
2941 pKey->press();
2942
2943 if (pKey->type() == KeyType_Modifier)
2944 return;
2945
2946#if 0
2947 QVector<LONG> sequence;
2948 /* Add the pressed modifiers first: */
2949 for (int i = 0; i < m_pressedModifiers.size(); ++i)
2950 {
2951 UISoftKeyboardKey *pModifier = m_pressedModifiers[i];
2952 if (!pModifier->scanCodePrefix().isEmpty())
2953 sequence << pModifier->scanCodePrefix();
2954 sequence << pModifier->scanCode();
2955 }
2956
2957 if (!pKey->scanCodePrefix().isEmpty())
2958 sequence << pKey->scanCodePrefix();
2959 sequence << pKey->scanCode();
2960 emit sigPutKeyboardSequence(sequence);
2961
2962#else
2963
2964 QVector<QPair<LONG, LONG> > sequence;
2965
2966 /* Add the pressed modifiers first: */
2967 for (int i = 0; i < m_pressedModifiers.size(); ++i)
2968 {
2969 UISoftKeyboardKey *pModifier = m_pressedModifiers[i];
2970 sequence << pModifier->usagePageIdPair();
2971 }
2972
2973 sequence << pKey->usagePageIdPair();
2974 emit sigPutUsageCodesPress(sequence);
2975
2976#endif
2977}
2978
2979void UISoftKeyboardWidget::modifierKeyPressRelease(UISoftKeyboardKey *pKey, bool fRelease)
2980{
2981 if (!pKey || pKey->type() != KeyType_Modifier)
2982 return;
2983
2984 pKey->setState(KeyState_NotPressed);
2985
2986 QVector<QPair<LONG, LONG> > sequence;
2987 sequence << pKey->usagePageIdPair();
2988 if (fRelease)
2989 emit sigPutUsageCodesRelease(sequence);
2990 else
2991 emit sigPutUsageCodesPress(sequence);
2992}
2993
2994void UISoftKeyboardWidget::keyStateChange(UISoftKeyboardKey* pKey)
2995{
2996 if (!pKey)
2997 return;
2998 if (pKey->type() == KeyType_Modifier)
2999 {
3000 if (pKey->state() == KeyState_NotPressed)
3001 m_pressedModifiers.removeOne(pKey);
3002 else
3003 if (!m_pressedModifiers.contains(pKey))
3004 m_pressedModifiers.append(pKey);
3005 }
3006}
3007
3008void UISoftKeyboardWidget::setCurrentLayout(const QUuid &layoutUid)
3009{
3010 if (m_uCurrentLayoutId == layoutUid || !m_layouts.contains(layoutUid))
3011 return;
3012
3013 UISoftKeyboardPhysicalLayout *pPhysicalLayout = findPhysicalLayout(m_layouts[layoutUid].physicalLayoutUuid());
3014 if (!pPhysicalLayout)
3015 return;
3016
3017 m_uCurrentLayoutId = layoutUid;
3018 emit sigCurrentLayoutChange();
3019 update();
3020}
3021
3022UISoftKeyboardLayout *UISoftKeyboardWidget::currentLayout()
3023{
3024 if (!m_layouts.contains(m_uCurrentLayoutId))
3025 return 0;
3026 return &(m_layouts[m_uCurrentLayoutId]);
3027}
3028
3029bool UISoftKeyboardWidget::loadPhysicalLayout(const QString &strLayoutFileName, KeyboardRegion keyboardRegion /* = KeyboardRegion_Main */)
3030{
3031 if (strLayoutFileName.isEmpty())
3032 return false;
3033 UIPhysicalLayoutReader reader;
3034 UISoftKeyboardPhysicalLayout *newPhysicalLayout = 0;
3035 if (keyboardRegion == KeyboardRegion_Main)
3036 {
3037 m_physicalLayouts.append(UISoftKeyboardPhysicalLayout());
3038 newPhysicalLayout = &(m_physicalLayouts.back());
3039 }
3040 else if (keyboardRegion == KeyboardRegion_NumPad)
3041 newPhysicalLayout = &(m_numPadLayout);
3042 else if (keyboardRegion == KeyboardRegion_MultimediaKeys)
3043 newPhysicalLayout = &(m_multiMediaKeysLayout);
3044 else
3045 return false;
3046
3047 if (!reader.parseXMLFile(strLayoutFileName, *newPhysicalLayout))
3048 {
3049 m_physicalLayouts.removeLast();
3050 return false;
3051 }
3052
3053 for (int i = 0; i < newPhysicalLayout->rows().size(); ++i)
3054 {
3055 UISoftKeyboardRow &row = newPhysicalLayout->rows()[i];
3056 for (int j = 0; j < row.keys().size(); ++j)
3057 row.keys()[j].setKeyboardRegion(keyboardRegion);
3058 }
3059
3060 if (keyboardRegion == KeyboardRegion_NumPad || keyboardRegion == KeyboardRegion_MultimediaKeys)
3061 return true;
3062
3063 /* Go thru all the keys row by row and construct their geometries: */
3064 int iY = m_iTopMargin;
3065 int iMaxWidth = 0;
3066 int iMaxWidthNoNumPad = 0;
3067 const QVector<UISoftKeyboardRow> &numPadRows = m_numPadLayout.rows();
3068 QVector<UISoftKeyboardRow> &rows = newPhysicalLayout->rows();
3069
3070 /* Prepend the multimedia rows to the layout */
3071 const QVector<UISoftKeyboardRow> &multimediaRows = m_multiMediaKeysLayout.rows();
3072 for (int i = multimediaRows.size() - 1; i >= 0; --i)
3073 rows.prepend(multimediaRows[i]);
3074
3075 for (int i = 0; i < rows.size(); ++i)
3076 {
3077 UISoftKeyboardRow &row = rows[i];
3078 /* Insert the numpad rows at the end of keyboard rows starting with appending 0th numpad row to the
3079 end of (1 + multimediaRows.size())th layout row: */
3080 if (i > multimediaRows.size())
3081 {
3082 int iNumPadRowIndex = i - (1 + multimediaRows.size());
3083 if (iNumPadRowIndex >= 0 && iNumPadRowIndex < numPadRows.size())
3084 {
3085 for (int m = 0; m < numPadRows[iNumPadRowIndex].keys().size(); ++m)
3086 row.keys().append(numPadRows[iNumPadRowIndex].keys()[m]);
3087 }
3088 }
3089
3090 int iX = m_iLeftMargin + row.leftMargin();
3091 int iXNoNumPad = m_iLeftMargin;
3092 int iRowHeight = row.defaultHeight();
3093 int iKeyWidth = 0;
3094 for (int j = 0; j < row.keys().size(); ++j)
3095 {
3096 UISoftKeyboardKey &key = (row.keys())[j];
3097 if (key.position() == iScrollLockPosition ||
3098 key.position() == iNumLockPosition ||
3099 key.position() == iCapsLockPosition)
3100 newPhysicalLayout->setLockKey(key.position(), &key);
3101
3102 if (key.keyboardRegion() == KeyboardRegion_NumPad)
3103 key.setKeyGeometry(QRect(iX + m_iBeforeNumPadWidth, iY, key.width(), key.height()));
3104 else
3105 key.setKeyGeometry(QRect(iX, iY, key.width(), key.height()));
3106
3107 key.setCornerRadius(0.1 * newPhysicalLayout->defaultKeyWidth());
3108 key.setPoints(UIPhysicalLayoutReader::computeKeyVertices(key));
3109 key.setParentWidget(this);
3110
3111 iKeyWidth = key.width();
3112 if (j < row.keys().size() - 1)
3113 iKeyWidth += m_iXSpacing;
3114 if (key.spaceWidthAfter() != 0 && j != row.keys().size() - 1)
3115 iKeyWidth += (m_iXSpacing + key.spaceWidthAfter());
3116
3117 iX += iKeyWidth;
3118 if (key.keyboardRegion() != KeyboardRegion_NumPad)
3119 iXNoNumPad += iKeyWidth;
3120 }
3121 if (row.spaceHeightAfter() != 0)
3122 iY += row.spaceHeightAfter() + m_iYSpacing;
3123 iMaxWidth = qMax(iMaxWidth, iX);
3124 iMaxWidthNoNumPad = qMax(iMaxWidthNoNumPad, iXNoNumPad);
3125
3126 iY += iRowHeight;
3127 if (i < rows.size() - 1)
3128 iY += m_iYSpacing;
3129 }
3130 int iInitialWidth = iMaxWidth + m_iRightMargin;
3131 int iInitialWidthNoNumPad = iMaxWidthNoNumPad + m_iRightMargin;
3132 int iInitialHeight = iY + m_iBottomMargin;
3133 m_iInitialWidth = qMax(m_iInitialWidth, iInitialWidth);
3134 m_iInitialWidthNoNumPad = qMax(m_iInitialWidthNoNumPad, iInitialWidthNoNumPad);
3135 m_iInitialHeight = qMax(m_iInitialHeight, iInitialHeight);
3136 return true;
3137}
3138
3139bool UISoftKeyboardWidget::loadKeyboardLayout(const QString &strLayoutFileName)
3140{
3141 if (strLayoutFileName.isEmpty())
3142 return false;
3143
3144 UIKeyboardLayoutReader keyboardLayoutReader;
3145
3146 UISoftKeyboardLayout newLayout;
3147 if (!keyboardLayoutReader.parseFile(strLayoutFileName, newLayout))
3148 return false;
3149
3150 UISoftKeyboardPhysicalLayout *pPhysicalLayout = findPhysicalLayout(newLayout.physicalLayoutUuid());
3151 /* If no pyhsical layout with the UUID the keyboard layout refers is found then cancel loading the keyboard layout: */
3152 if (!pPhysicalLayout)
3153 return false;
3154
3155 /* Make sure we have unique lay1out UUIDs: */
3156 int iCount = 0;
3157 foreach (const UISoftKeyboardLayout &layout, m_layouts)
3158 {
3159 if (layout.uid() == newLayout.uid())
3160 ++iCount;
3161 }
3162 if (iCount > 1)
3163 return false;
3164
3165 newLayout.setSourceFilePath(strLayoutFileName);
3166 addLayout(newLayout);
3167 return true;
3168}
3169
3170UISoftKeyboardPhysicalLayout *UISoftKeyboardWidget::findPhysicalLayout(const QUuid &uuid)
3171{
3172 for (int i = 0; i < m_physicalLayouts.size(); ++i)
3173 {
3174 if (m_physicalLayouts[i].uid() == uuid)
3175 return &(m_physicalLayouts[i]);
3176 }
3177 return 0;
3178}
3179
3180void UISoftKeyboardWidget::reset()
3181{
3182 m_pressedModifiers.clear();
3183 m_pKeyUnderMouse = 0;
3184 m_pKeyBeingEdited = 0;
3185 m_pKeyPressed = 0;
3186 m_enmMode = Mode_Keyboard;
3187
3188 for (int i = 0; i < m_physicalLayouts.size(); ++i)
3189 m_physicalLayouts[i].reset();
3190}
3191
3192void UISoftKeyboardWidget::loadLayouts()
3193{
3194 /* Load physical layouts from resources: Numpad and multimedia layout files should be read first
3195 since we insert these to other layouts: */
3196 loadPhysicalLayout(":/numpad.xml", KeyboardRegion_NumPad);
3197 loadPhysicalLayout(":/multimedia_keys.xml", KeyboardRegion_MultimediaKeys);
3198 QStringList physicalLayoutNames;
3199 physicalLayoutNames << ":/101_ansi.xml"
3200 << ":/102_iso.xml"
3201 << ":/106_japanese.xml"
3202 << ":/103_iso.xml"
3203 << ":/103_ansi.xml";
3204 foreach (const QString &strName, physicalLayoutNames)
3205 loadPhysicalLayout(strName);
3206
3207 setNewMinimumSize(QSize(m_iInitialWidth, m_iInitialHeight));
3208 setInitialSize(m_iInitialWidth, m_iInitialHeight);
3209
3210 /* Add keyboard layouts from resources: */
3211 QStringList keyboardLayoutNames;
3212 keyboardLayoutNames << ":/us_international.xml"
3213 << ":/german.xml"
3214 << ":/us.xml"
3215 << ":/greek.xml"
3216 << ":/japanese.xml"
3217 << ":/brazilian.xml"
3218 << ":/korean.xml";
3219
3220 foreach (const QString &strName, keyboardLayoutNames)
3221 loadKeyboardLayout(strName);
3222 /* Mark the layouts we load from the resources as non-editable: */
3223 for (QMap<QUuid, UISoftKeyboardLayout>::iterator iterator = m_layouts.begin(); iterator != m_layouts.end(); ++iterator)
3224 {
3225 iterator.value().setEditable(false);
3226 iterator.value().setIsFromResources(true);
3227 }
3228 keyboardLayoutNames.clear();
3229 /* Add keyboard layouts from the defalt keyboard layout folder: */
3230 lookAtDefaultLayoutFolder(keyboardLayoutNames);
3231 foreach (const QString &strName, keyboardLayoutNames)
3232 loadKeyboardLayout(strName);
3233
3234 if (m_layouts.isEmpty())
3235 return;
3236 for (QMap<QUuid, UISoftKeyboardLayout>::iterator iterator = m_layouts.begin(); iterator != m_layouts.end(); ++iterator)
3237 iterator.value().setEditedBuNotSaved(false);
3238 /* Block sigCurrentLayoutChange since it causes saving set layout to exra data: */
3239 blockSignals(true);
3240 setCurrentLayout(m_layouts.firstKey());
3241 blockSignals(false);
3242}
3243
3244void UISoftKeyboardWidget::prepareObjects()
3245{
3246 setMouseTracking(true);
3247}
3248
3249void UISoftKeyboardWidget::prepareColorThemes()
3250{
3251 int iIndex = 0;
3252 while (predefinedColorThemes[iIndex][0])
3253 {
3254 m_colorThemes << UISoftKeyboardColorTheme(predefinedColorThemes[iIndex][0],
3255 predefinedColorThemes[iIndex][1],
3256 predefinedColorThemes[iIndex][2],
3257 predefinedColorThemes[iIndex][3],
3258 predefinedColorThemes[iIndex][4],
3259 predefinedColorThemes[iIndex][5]);
3260 ++iIndex;
3261 }
3262
3263 UISoftKeyboardColorTheme customTheme;
3264 customTheme.setName("Custom");
3265 customTheme.setIsEditable(true);
3266 m_colorThemes.append(customTheme);
3267 m_currentColorTheme = &(m_colorThemes.back());
3268}
3269
3270void UISoftKeyboardWidget::setKeyBeingEdited(UISoftKeyboardKey* pKey)
3271{
3272 if (m_pKeyBeingEdited == pKey)
3273 return;
3274 m_pKeyBeingEdited = pKey;
3275 emit sigKeyToEdit(pKey);
3276}
3277
3278bool UISoftKeyboardWidget::layoutByNameExists(const QString &strName) const
3279{
3280 foreach (const UISoftKeyboardLayout &layout, m_layouts)
3281 {
3282 if (layout.name() == strName)
3283 return true;
3284 }
3285 return false;
3286}
3287
3288void UISoftKeyboardWidget::lookAtDefaultLayoutFolder(QStringList &fileList)
3289{
3290 QString strFolder = QString("%1%2%3").arg(uiCommon().homeFolder()).arg(QDir::separator()).arg(strSubDirectorName);
3291 QDir dir(strFolder);
3292 if (!dir.exists())
3293 return;
3294 QStringList filters;
3295 filters << "*.xml";
3296 dir.setNameFilters(filters);
3297 QFileInfoList fileInfoList = dir.entryInfoList();
3298 foreach (const QFileInfo &fileInfo, fileInfoList)
3299 fileList << fileInfo.absoluteFilePath();
3300}
3301
3302UISoftKeyboardColorTheme *UISoftKeyboardWidget::colorTheme(const QString &strColorThemeName)
3303{
3304 for (int i = 0; i < m_colorThemes.size(); ++i)
3305 {
3306 if (m_colorThemes[i].name() == strColorThemeName)
3307 return &(m_colorThemes[i]);
3308 }
3309 return 0;
3310}
3311
3312void UISoftKeyboardWidget::showKeyTooltip(UISoftKeyboardKey *pKey)
3313{
3314 if (pKey && m_keyTooltips.contains(pKey->position()))
3315 sigStatusBarMessage(m_keyTooltips[pKey->position()]);
3316 else
3317 sigStatusBarMessage(QString());
3318
3319}
3320
3321QStringList UISoftKeyboardWidget::layoutNameList() const
3322{
3323 QStringList layoutNames;
3324 foreach (const UISoftKeyboardLayout &layout, m_layouts)
3325 layoutNames << layout.nameString();
3326 return layoutNames;
3327}
3328
3329QList<QUuid> UISoftKeyboardWidget::layoutUidList() const
3330{
3331 QList<QUuid> layoutUids;
3332 foreach (const UISoftKeyboardLayout &layout, m_layouts)
3333 layoutUids << layout.uid();
3334 return layoutUids;
3335}
3336
3337const QVector<UISoftKeyboardPhysicalLayout> &UISoftKeyboardWidget::physicalLayouts() const
3338{
3339 return m_physicalLayouts;
3340}
3341
3342/*********************************************************************************************************************************
3343* UIPhysicalLayoutReader implementation. *
3344*********************************************************************************************************************************/
3345
3346bool UIPhysicalLayoutReader::parseXMLFile(const QString &strFileName, UISoftKeyboardPhysicalLayout &physicalLayout)
3347{
3348 QFile xmlFile(strFileName);
3349 if (!xmlFile.exists())
3350 return false;
3351
3352 if (xmlFile.size() >= iFileSizeLimit)
3353 return false;
3354
3355 if (!xmlFile.open(QIODevice::ReadOnly))
3356 return false;
3357
3358 m_xmlReader.setDevice(&xmlFile);
3359
3360 if (!m_xmlReader.readNextStartElement() || m_xmlReader.name() != QLatin1String("physicallayout"))
3361 return false;
3362 physicalLayout.setFileName(strFileName);
3363
3364 QXmlStreamAttributes attributes = m_xmlReader.attributes();
3365 int iDefaultWidth = attributes.value("defaultWidth").toInt();
3366 int iDefaultHeight = attributes.value("defaultHeight").toInt();
3367 QVector<UISoftKeyboardRow> &rows = physicalLayout.rows();
3368 physicalLayout.setDefaultKeyWidth(iDefaultWidth);
3369
3370 while (m_xmlReader.readNextStartElement())
3371 {
3372 if (m_xmlReader.name() == QLatin1String("row"))
3373 parseRow(iDefaultWidth, iDefaultHeight, rows);
3374 else if (m_xmlReader.name() == QLatin1String("name"))
3375 physicalLayout.setName(m_xmlReader.readElementText());
3376 else if (m_xmlReader.name() == QLatin1String("id"))
3377 physicalLayout.setUid(QUuid(m_xmlReader.readElementText()));
3378 else
3379 m_xmlReader.skipCurrentElement();
3380 }
3381
3382 return true;
3383}
3384
3385void UIPhysicalLayoutReader::parseRow(int iDefaultWidth, int iDefaultHeight, QVector<UISoftKeyboardRow> &rows)
3386{
3387 rows.append(UISoftKeyboardRow());
3388 UISoftKeyboardRow &row = rows.back();
3389
3390 row.setDefaultWidth(iDefaultWidth);
3391 row.setDefaultHeight(iDefaultHeight);
3392 row.setSpaceHeightAfter(0);
3393
3394 /* Override the layout attributes if the row also has them: */
3395 QXmlStreamAttributes attributes = m_xmlReader.attributes();
3396 if (attributes.hasAttribute("defaultWidth"))
3397 row.setDefaultWidth(attributes.value("defaultWidth").toInt());
3398 if (attributes.hasAttribute("defaultHeight"))
3399 row.setDefaultHeight(attributes.value("defaultHeight").toInt());
3400 while (m_xmlReader.readNextStartElement())
3401 {
3402 if (m_xmlReader.name() == QLatin1String("key"))
3403 parseKey(row);
3404 else if (m_xmlReader.name() == QLatin1String("space"))
3405 parseKeySpace(row);
3406 else
3407 m_xmlReader.skipCurrentElement();
3408 }
3409}
3410
3411void UIPhysicalLayoutReader::parseKey(UISoftKeyboardRow &row)
3412{
3413 row.keys().append(UISoftKeyboardKey());
3414 UISoftKeyboardKey &key = row.keys().back();
3415 key.setWidth(row.defaultWidth());
3416 key.setHeight(row.defaultHeight());
3417 QString strKeyCap;
3418 while (m_xmlReader.readNextStartElement())
3419 {
3420 if (m_xmlReader.name() == QLatin1String("width"))
3421 key.setWidth(m_xmlReader.readElementText().toInt());
3422 else if (m_xmlReader.name() == QLatin1String("height"))
3423 key.setHeight(m_xmlReader.readElementText().toInt());
3424 else if (m_xmlReader.name() == QLatin1String("scancode"))
3425 {
3426 QString strCode = m_xmlReader.readElementText();
3427 bool fOk = false;
3428 key.setScanCode(strCode.toInt(&fOk, 16));
3429 }
3430 else if (m_xmlReader.name() == QLatin1String("scancodeprefix"))
3431 {
3432 QString strCode = m_xmlReader.readElementText();
3433 QStringList strList;
3434#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
3435 strList << strCode.split('-', Qt::SkipEmptyParts);
3436#else
3437 strList << strCode.split('-', QString::SkipEmptyParts);
3438#endif
3439 foreach (const QString &strPrefix, strList)
3440 {
3441 bool fOk = false;
3442 LONG iCode = strPrefix.toInt(&fOk, 16);
3443 if (fOk)
3444 key.addScanCodePrefix(iCode);
3445 }
3446 }
3447 else if (m_xmlReader.name() == QLatin1String("usageid"))
3448 {
3449 QString strCode = m_xmlReader.readElementText();
3450 bool fOk = false;
3451 key.setUsageId(strCode.toInt(&fOk, 16));
3452 }
3453 else if (m_xmlReader.name() == QLatin1String("usagepage"))
3454 {
3455 QString strCode = m_xmlReader.readElementText();
3456 bool fOk = false;
3457 key.setUsagePage(strCode.toInt(&fOk, 16));
3458 }
3459 else if (m_xmlReader.name() == QLatin1String("cutout"))
3460 parseCutout(key);
3461 else if (m_xmlReader.name() == QLatin1String("position"))
3462 key.setPosition(m_xmlReader.readElementText().toInt());
3463 else if (m_xmlReader.name() == QLatin1String("type"))
3464 {
3465 QString strType = m_xmlReader.readElementText();
3466 if (strType == "modifier")
3467 key.setType(KeyType_Modifier);
3468 else if (strType == "lock")
3469 key.setType(KeyType_Lock);
3470 }
3471 else if (m_xmlReader.name() == QLatin1String("osmenukey"))
3472 {
3473 if (m_xmlReader.readElementText() == "true")
3474 key.setIsOSMenuKey(true);
3475 }
3476 else if (m_xmlReader.name() == QLatin1String("staticcaption"))
3477 key.setStaticCaption(m_xmlReader.readElementText());
3478 else if (m_xmlReader.name() == QLatin1String("image"))
3479 key.setImageByName(m_xmlReader.readElementText());
3480 else
3481 m_xmlReader.skipCurrentElement();
3482 }
3483}
3484
3485void UIPhysicalLayoutReader::parseKeySpace(UISoftKeyboardRow &row)
3486{
3487 int iWidth = row.defaultWidth();
3488 int iHeight = 0;
3489 while (m_xmlReader.readNextStartElement())
3490 {
3491 if (m_xmlReader.name() == QLatin1String("width"))
3492 iWidth = m_xmlReader.readElementText().toInt();
3493 else if (m_xmlReader.name() == QLatin1String("height"))
3494 iHeight = m_xmlReader.readElementText().toInt();
3495 else
3496 m_xmlReader.skipCurrentElement();
3497 }
3498 row.setSpaceHeightAfter(iHeight);
3499 /* If we have keys add the parsed space to the last key as the 'space after': */
3500 if (!row.keys().empty())
3501 row.keys().back().setSpaceWidthAfter(iWidth);
3502 /* If we have no keys than this is the initial space left to first key: */
3503 else
3504 row.setLeftMargin(iWidth);
3505}
3506
3507void UIPhysicalLayoutReader::parseCutout(UISoftKeyboardKey &key)
3508{
3509 int iWidth = 0;
3510 int iHeight = 0;
3511 int iCorner = 0;
3512 while (m_xmlReader.readNextStartElement())
3513 {
3514 if (m_xmlReader.name() == QLatin1String("width"))
3515 iWidth = m_xmlReader.readElementText().toInt();
3516 else if (m_xmlReader.name() == QLatin1String("height"))
3517 iHeight = m_xmlReader.readElementText().toInt();
3518 else if (m_xmlReader.name() == QLatin1String("corner"))
3519 {
3520 QString strCorner = m_xmlReader.readElementText();
3521 if (strCorner == "topLeft")
3522 iCorner = 0;
3523 else if(strCorner == "topRight")
3524 iCorner = 1;
3525 else if(strCorner == "bottomRight")
3526 iCorner = 2;
3527 else if(strCorner == "bottomLeft")
3528 iCorner = 3;
3529 }
3530 else
3531 m_xmlReader.skipCurrentElement();
3532 }
3533 key.setCutout(iCorner, iWidth, iHeight);
3534}
3535
3536QVector<QPointF> UIPhysicalLayoutReader::computeKeyVertices(const UISoftKeyboardKey &key)
3537{
3538 QVector<QPointF> vertices;
3539
3540 if (key.cutoutCorner() == -1 || key.width() <= key.cutoutWidth() || key.height() <= key.cutoutHeight())
3541 {
3542 vertices.append(QPoint(0, 0));
3543 vertices.append(QPoint(key.width(), 0));
3544 vertices.append(QPoint(key.width(), key.height()));
3545 vertices.append(QPoint(0, key.height()));
3546 return vertices;
3547 }
3548 if (key.cutoutCorner() == 0)
3549 {
3550 vertices.append(QPoint(key.cutoutWidth(), 0));
3551 vertices.append(QPoint(key.width(), 0));
3552 vertices.append(QPoint(key.width(), key.height()));
3553 vertices.append(QPoint(0, key.height()));
3554 vertices.append(QPoint(0, key.cutoutHeight()));
3555 vertices.append(QPoint(key.cutoutWidth(), key.cutoutHeight()));
3556 }
3557 else if (key.cutoutCorner() == 1)
3558 {
3559 vertices.append(QPoint(0, 0));
3560 vertices.append(QPoint(key.width() - key.cutoutWidth(), 0));
3561 vertices.append(QPoint(key.width() - key.cutoutWidth(), key.cutoutHeight()));
3562 vertices.append(QPoint(key.width(), key.cutoutHeight()));
3563 vertices.append(QPoint(key.width(), key.height()));
3564 vertices.append(QPoint(0, key.height()));
3565 }
3566 else if (key.cutoutCorner() == 2)
3567 {
3568 vertices.append(QPoint(0, 0));
3569 vertices.append(QPoint(key.width(), 0));
3570 vertices.append(QPoint(key.width(), key.cutoutHeight()));
3571 vertices.append(QPoint(key.width() - key.cutoutWidth(), key.cutoutHeight()));
3572 vertices.append(QPoint(key.width() - key.cutoutWidth(), key.height()));
3573 vertices.append(QPoint(0, key.height()));
3574 }
3575 else if (key.cutoutCorner() == 3)
3576 {
3577 vertices.append(QPoint(0, 0));
3578 vertices.append(QPoint(key.width(), 0));
3579 vertices.append(QPoint(key.width(), key.height()));
3580 vertices.append(QPoint(key.cutoutWidth(), key.height()));
3581 vertices.append(QPoint(key.cutoutWidth(), key.height() - key.cutoutHeight()));
3582 vertices.append(QPoint(0, key.height() - key.cutoutHeight()));
3583 }
3584 return vertices;
3585}
3586
3587
3588/*********************************************************************************************************************************
3589* UIKeyboardLayoutReader implementation. *
3590*********************************************************************************************************************************/
3591
3592bool UIKeyboardLayoutReader::parseFile(const QString &strFileName, UISoftKeyboardLayout &layout)
3593{
3594 QFile xmlFile(strFileName);
3595 if (!xmlFile.exists())
3596 return false;
3597
3598 if (xmlFile.size() >= iFileSizeLimit)
3599 return false;
3600
3601 if (!xmlFile.open(QIODevice::ReadOnly))
3602 return false;
3603
3604 m_xmlReader.setDevice(&xmlFile);
3605
3606 if (!m_xmlReader.readNextStartElement() || m_xmlReader.name() != QLatin1String("layout"))
3607 return false;
3608
3609 while (m_xmlReader.readNextStartElement())
3610 {
3611 if (m_xmlReader.name() == QLatin1String("key"))
3612 parseKey(layout);
3613 else if (m_xmlReader.name() == QLatin1String("name"))
3614 layout.setName(m_xmlReader.readElementText());
3615 else if (m_xmlReader.name() == QLatin1String("nativename"))
3616 layout.setNativeName(m_xmlReader.readElementText());
3617 else if (m_xmlReader.name() == QLatin1String("physicallayoutid"))
3618 layout.setPhysicalLayoutUuid(QUuid(m_xmlReader.readElementText()));
3619 else if (m_xmlReader.name() == QLatin1String("id"))
3620 layout.setUid(QUuid(m_xmlReader.readElementText()));
3621 else
3622 m_xmlReader.skipCurrentElement();
3623 }
3624 return true;
3625}
3626
3627void UIKeyboardLayoutReader::parseKey(UISoftKeyboardLayout &layout)
3628{
3629 UIKeyCaptions keyCaptions;
3630 int iKeyPosition = 0;
3631 while (m_xmlReader.readNextStartElement())
3632 {
3633 if (m_xmlReader.name() == QLatin1String("basecaption"))
3634 {
3635 keyCaptions.m_strBase = m_xmlReader.readElementText();
3636 keyCaptions.m_strBase.replace("\\n", "\n");
3637 }
3638 else if (m_xmlReader.name() == QLatin1String("shiftcaption"))
3639 {
3640 keyCaptions.m_strShift = m_xmlReader.readElementText();
3641 keyCaptions.m_strShift.replace("\\n", "\n");
3642 }
3643 else if (m_xmlReader.name() == QLatin1String("altgrcaption"))
3644 {
3645 keyCaptions.m_strAltGr = m_xmlReader.readElementText();
3646 keyCaptions.m_strAltGr.replace("\\n", "\n");
3647 }
3648 else if (m_xmlReader.name() == QLatin1String("shiftaltgrcaption"))
3649 {
3650 keyCaptions.m_strShiftAltGr = m_xmlReader.readElementText();
3651 keyCaptions.m_strShiftAltGr.replace("\\n", "\n");
3652 }
3653 else if (m_xmlReader.name() == QLatin1String("position"))
3654 iKeyPosition = m_xmlReader.readElementText().toInt();
3655 else
3656 m_xmlReader.skipCurrentElement();
3657 }
3658 layout.addOrUpdateUIKeyCaptions(iKeyPosition, keyCaptions);
3659}
3660
3661
3662/*********************************************************************************************************************************
3663* UISoftKeyboardStatusBarWidget implementation. *
3664*********************************************************************************************************************************/
3665
3666UISoftKeyboardStatusBarWidget::UISoftKeyboardStatusBarWidget(QWidget *pParent /* = 0*/ )
3667 : QIWithRetranslateUI<QWidget>(pParent)
3668 , m_pLayoutListButton(0)
3669 , m_pSettingsButton(0)
3670 , m_pResetButton(0)
3671 , m_pHelpButton(0)
3672 , m_pMessageLabel(0)
3673{
3674 prepareObjects();
3675}
3676
3677void UISoftKeyboardStatusBarWidget::retranslateUi()
3678{
3679 if (m_pLayoutListButton)
3680 m_pLayoutListButton->setToolTip(UISoftKeyboard::tr("Layout List"));
3681 if (m_pSettingsButton)
3682 m_pSettingsButton->setToolTip(UISoftKeyboard::tr("Settings"));
3683 if (m_pResetButton)
3684 m_pResetButton->setToolTip(UISoftKeyboard::tr("Reset the keyboard and release all keys"));
3685 if (m_pHelpButton)
3686 m_pHelpButton->setToolTip(UISoftKeyboard::tr("Help"));
3687}
3688
3689void UISoftKeyboardStatusBarWidget::prepareObjects()
3690{
3691 QHBoxLayout *pLayout = new QHBoxLayout;
3692 if (!pLayout)
3693 return;
3694 pLayout->setContentsMargins(0, 0, 0, 0);
3695 setLayout(pLayout);
3696
3697 m_pMessageLabel = new QLabel;
3698 pLayout->addWidget(m_pMessageLabel);
3699
3700 m_pLayoutListButton = new QToolButton;
3701 if (m_pLayoutListButton)
3702 {
3703 m_pLayoutListButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_layout_list_16px.png", ":/soft_keyboard_layout_list_disabled_16px.png"));
3704 m_pLayoutListButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
3705 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
3706 m_pLayoutListButton->resize(QSize(iIconMetric, iIconMetric));
3707 m_pLayoutListButton->setStyleSheet("QToolButton { border: 0px none black; margin: 0px 0px 0px 0px; } QToolButton::menu-indicator {image: none;}");
3708 connect(m_pLayoutListButton, &QToolButton::clicked, this, &UISoftKeyboardStatusBarWidget::sigShowHideSidePanel);
3709 pLayout->addWidget(m_pLayoutListButton);
3710 }
3711
3712 m_pSettingsButton = new QToolButton;
3713 if (m_pSettingsButton)
3714 {
3715 m_pSettingsButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_settings_16px.png", ":/soft_keyboard_settings_disabled_16px.png"));
3716 m_pSettingsButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
3717 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
3718 m_pSettingsButton->resize(QSize(iIconMetric, iIconMetric));
3719 m_pSettingsButton->setStyleSheet("QToolButton { border: 0px none black; margin: 0px 0px 0px 0px; } QToolButton::menu-indicator {image: none;}");
3720 connect(m_pSettingsButton, &QToolButton::clicked, this, &UISoftKeyboardStatusBarWidget::sigShowSettingWidget);
3721 pLayout->addWidget(m_pSettingsButton);
3722 }
3723
3724 m_pResetButton = new QToolButton;
3725 if (m_pResetButton)
3726 {
3727 m_pResetButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_reset_16px.png"));
3728 m_pResetButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
3729 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
3730 m_pResetButton->resize(QSize(iIconMetric, iIconMetric));
3731 m_pResetButton->setStyleSheet("QToolButton { border: 0px none black; margin: 0px 0px 0px 0px; } QToolButton::menu-indicator {image: none;}");
3732 connect(m_pResetButton, &QToolButton::clicked, this, &UISoftKeyboardStatusBarWidget::sigResetKeyboard);
3733 pLayout->addWidget(m_pResetButton);
3734 }
3735
3736 m_pHelpButton = new QToolButton;
3737 if (m_pHelpButton)
3738 {
3739 m_pHelpButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_help_16px.png"));
3740 m_pHelpButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
3741 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
3742 m_pHelpButton->resize(QSize(iIconMetric, iIconMetric));
3743 m_pHelpButton->setStyleSheet("QToolButton { border: 0px none black; margin: 0px 0px 0px 0px; } QToolButton::menu-indicator {image: none;}");
3744 connect(m_pHelpButton, &QToolButton::clicked, this, &UISoftKeyboardStatusBarWidget::sigHelpButtonPressed);
3745 pLayout->addWidget(m_pHelpButton);
3746 }
3747
3748 retranslateUi();
3749}
3750
3751void UISoftKeyboardStatusBarWidget::updateLayoutNameInStatusBar(const QString &strMessage)
3752{
3753 if (!m_pMessageLabel)
3754 return;
3755 m_pMessageLabel->setText(strMessage);
3756}
3757
3758
3759/*********************************************************************************************************************************
3760* UISoftKeyboardSettingsWidget implementation. *
3761*********************************************************************************************************************************/
3762
3763UISoftKeyboardSettingsWidget::UISoftKeyboardSettingsWidget(QWidget *pParent /* = 0 */)
3764 : QIWithRetranslateUI<QWidget>(pParent)
3765 , m_pHideNumPadCheckBox(0)
3766 , m_pShowOsMenuButtonsCheckBox(0)
3767 , m_pHideMultimediaKeysCheckBox(0)
3768 , m_pColorThemeGroupBox(0)
3769 , m_pColorThemeComboBox(0)
3770 , m_pTitleLabel(0)
3771 , m_pCloseButton(0)
3772
3773{
3774 prepareObjects();
3775}
3776
3777void UISoftKeyboardSettingsWidget::setHideOSMenuKeys(bool fHide)
3778{
3779 if (m_pShowOsMenuButtonsCheckBox)
3780 m_pShowOsMenuButtonsCheckBox->setChecked(fHide);
3781}
3782
3783void UISoftKeyboardSettingsWidget::setHideNumPad(bool fHide)
3784{
3785 if (m_pHideNumPadCheckBox)
3786 m_pHideNumPadCheckBox->setChecked(fHide);
3787}
3788
3789void UISoftKeyboardSettingsWidget::setHideMultimediaKeys(bool fHide)
3790{
3791 if (m_pHideMultimediaKeysCheckBox)
3792 m_pHideMultimediaKeysCheckBox->setChecked(fHide);
3793}
3794
3795void UISoftKeyboardSettingsWidget::setColorSelectionButtonBackgroundAndTooltip(KeyboardColorType enmColorType,
3796 const QColor &color, bool fIsColorEditable)
3797{
3798 if (m_colorSelectLabelsButtons.size() > enmColorType && m_colorSelectLabelsButtons[enmColorType].second)
3799 {
3800 UISoftKeyboardColorButton *pButton = m_colorSelectLabelsButtons[enmColorType].second;
3801 QPalette pal = pButton->palette();
3802 pal.setColor(QPalette::Button, color);
3803 pButton->setAutoFillBackground(true);
3804 pButton->setPalette(pal);
3805 pButton->setToolTip(fIsColorEditable ? UISoftKeyboard::tr("Click to change the color.") : UISoftKeyboard::tr("This color theme is not editable."));
3806 pButton->update();
3807 }
3808}
3809
3810void UISoftKeyboardSettingsWidget::setColorThemeNames(const QStringList &colorThemeNames)
3811{
3812 if (!m_pColorThemeComboBox)
3813 return;
3814 m_pColorThemeComboBox->blockSignals(true);
3815 m_pColorThemeComboBox->clear();
3816 foreach (const QString &strName, colorThemeNames)
3817 m_pColorThemeComboBox->addItem(strName);
3818 m_pColorThemeComboBox->blockSignals(false);
3819}
3820
3821void UISoftKeyboardSettingsWidget::setCurrentColorThemeName(const QString &strColorThemeName)
3822{
3823 if (!m_pColorThemeComboBox)
3824 return;
3825 int iItemIndex = m_pColorThemeComboBox->findText(strColorThemeName, Qt::MatchFixedString);
3826 if (iItemIndex == -1)
3827 return;
3828 m_pColorThemeComboBox->blockSignals(true);
3829 m_pColorThemeComboBox->setCurrentIndex(iItemIndex);
3830 m_pColorThemeComboBox->blockSignals(false);
3831}
3832
3833void UISoftKeyboardSettingsWidget::retranslateUi()
3834{
3835 if (m_pTitleLabel)
3836 m_pTitleLabel->setText(UISoftKeyboard::tr("Keyboard Settings"));
3837 if (m_pCloseButton)
3838 {
3839 m_pCloseButton->setToolTip(UISoftKeyboard::tr("Close the layout list"));
3840 m_pCloseButton->setText("Close");
3841 }
3842 if (m_pHideNumPadCheckBox)
3843 m_pHideNumPadCheckBox->setText(UISoftKeyboard::tr("Hide NumPad"));
3844 if (m_pShowOsMenuButtonsCheckBox)
3845 m_pShowOsMenuButtonsCheckBox->setText(UISoftKeyboard::tr("Hide OS/Menu Keys"));
3846 if (m_pHideMultimediaKeysCheckBox)
3847 m_pHideMultimediaKeysCheckBox->setText(UISoftKeyboard::tr("Hide Multimedia Keys"));
3848 if (m_pColorThemeGroupBox)
3849 m_pColorThemeGroupBox->setTitle(UISoftKeyboard::tr("Color Themes"));
3850
3851 if (m_colorSelectLabelsButtons.size() == KeyboardColorType_Max)
3852 {
3853 if (m_colorSelectLabelsButtons[KeyboardColorType_Background].first)
3854 m_colorSelectLabelsButtons[KeyboardColorType_Background].first->setText(UISoftKeyboard::tr("Button Background Color"));
3855 if (m_colorSelectLabelsButtons[KeyboardColorType_Font].first)
3856 m_colorSelectLabelsButtons[KeyboardColorType_Font].first->setText(UISoftKeyboard::tr("Button Font Color"));
3857 if (m_colorSelectLabelsButtons[KeyboardColorType_Hover].first)
3858 m_colorSelectLabelsButtons[KeyboardColorType_Hover].first->setText(UISoftKeyboard::tr("Button Hover Color"));
3859 if (m_colorSelectLabelsButtons[KeyboardColorType_Edit].first)
3860 m_colorSelectLabelsButtons[KeyboardColorType_Edit].first->setText(UISoftKeyboard::tr("Button Edit Color"));
3861 if (m_colorSelectLabelsButtons[KeyboardColorType_Pressed].first)
3862 m_colorSelectLabelsButtons[KeyboardColorType_Pressed].first->setText(UISoftKeyboard::tr("Pressed Button Font Color"));
3863 }
3864}
3865
3866void UISoftKeyboardSettingsWidget::prepareObjects()
3867{
3868 QGridLayout *pSettingsLayout = new QGridLayout;
3869 if (!pSettingsLayout)
3870 return;
3871
3872 QHBoxLayout *pTitleLayout = new QHBoxLayout;
3873 m_pCloseButton = new QToolButton;
3874 m_pCloseButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
3875 m_pCloseButton->setIcon(UIIconPool::defaultIcon(UIIconPool::UIDefaultIconType_DialogCancel));
3876 m_pCloseButton->setAutoRaise(true);
3877 connect(m_pCloseButton, &QToolButton::clicked, this, &UISoftKeyboardSettingsWidget::sigCloseSettingsWidget);
3878 m_pTitleLabel = new QLabel;
3879 pTitleLayout->addWidget(m_pTitleLabel);
3880 pTitleLayout->addStretch(2);
3881 pTitleLayout->addWidget(m_pCloseButton);
3882 pSettingsLayout->addLayout(pTitleLayout, 0, 0, 1, 2);
3883
3884 m_pHideNumPadCheckBox = new QCheckBox;
3885 m_pShowOsMenuButtonsCheckBox = new QCheckBox;
3886 m_pHideMultimediaKeysCheckBox = new QCheckBox;
3887 pSettingsLayout->addWidget(m_pHideNumPadCheckBox, 1, 0, 1, 1);
3888 pSettingsLayout->addWidget(m_pShowOsMenuButtonsCheckBox, 2, 0, 1, 1);
3889 pSettingsLayout->addWidget(m_pHideMultimediaKeysCheckBox, 3, 0, 1, 1);
3890 connect(m_pHideNumPadCheckBox, &QCheckBox::toggled, this, &UISoftKeyboardSettingsWidget::sigHideNumPad);
3891 connect(m_pShowOsMenuButtonsCheckBox, &QCheckBox::toggled, this, &UISoftKeyboardSettingsWidget::sigHideOSMenuKeys);
3892 connect(m_pHideMultimediaKeysCheckBox, &QCheckBox::toggled, this, &UISoftKeyboardSettingsWidget::sigHideMultimediaKeys);
3893
3894 /* A groupbox to host the color selection widgets: */
3895 m_pColorThemeGroupBox = new QGroupBox;
3896 QVBoxLayout *pGroupBoxLayout = new QVBoxLayout(m_pColorThemeGroupBox);
3897 pSettingsLayout->addWidget(m_pColorThemeGroupBox, 4, 0, 1, 1);
3898
3899 m_pColorThemeComboBox = new QComboBox;
3900 pGroupBoxLayout->addWidget(m_pColorThemeComboBox);
3901 connect(m_pColorThemeComboBox, &QComboBox::currentTextChanged, this, &UISoftKeyboardSettingsWidget::sigColorThemeSelectionChanged);
3902
3903 /* Creating and configuring the color selection buttons: */
3904 QGridLayout *pColorSelectionLayout = new QGridLayout;
3905 pColorSelectionLayout->setSpacing(1);
3906 pGroupBoxLayout->addLayout(pColorSelectionLayout);
3907 for (int i = KeyboardColorType_Background; i < KeyboardColorType_Max; ++i)
3908 {
3909 QLabel *pLabel = new QLabel;
3910 UISoftKeyboardColorButton *pButton = new UISoftKeyboardColorButton((KeyboardColorType)i);
3911 pButton->setFlat(true);
3912 pButton->setMaximumWidth(3 * qApp->style()->pixelMetric(QStyle::PM_LargeIconSize));
3913 pColorSelectionLayout->addWidget(pLabel, i, 0, 1, 1);
3914 pColorSelectionLayout->addWidget(pButton, i, 1, 1, 1);
3915 m_colorSelectLabelsButtons.append(ColorSelectLabelButton(pLabel, pButton));
3916 connect(pButton, &UISoftKeyboardColorButton::clicked, this, &UISoftKeyboardSettingsWidget::sltColorSelectionButtonClicked);
3917 }
3918
3919 QSpacerItem *pSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding);
3920 if (pSpacer)
3921 pSettingsLayout->addItem(pSpacer, 6, 0);
3922
3923 setLayout(pSettingsLayout);
3924 retranslateUi();
3925}
3926
3927void UISoftKeyboardSettingsWidget::sltColorSelectionButtonClicked()
3928{
3929 UISoftKeyboardColorButton *pButton = qobject_cast<UISoftKeyboardColorButton*>(sender());
3930 if (!pButton)
3931 return;
3932 emit sigColorCellClicked((int)pButton->colorType());
3933}
3934
3935
3936/*********************************************************************************************************************************
3937* UISoftKeyboard implementation. *
3938*********************************************************************************************************************************/
3939
3940UISoftKeyboard::UISoftKeyboard(QWidget *pParent, UIMachine *pMachine,
3941 QWidget *pCenterWidget, QString strMachineName /* = QString() */)
3942 : QMainWindowWithRestorableGeometryAndRetranslateUi(pParent)
3943 , m_pMachine(pMachine)
3944 , m_pCenterWidget(pCenterWidget)
3945 , m_pMainLayout(0)
3946 , m_strMachineName(strMachineName)
3947 , m_pSplitter(0)
3948 , m_pSidePanelWidget(0)
3949 , m_pKeyboardWidget(0)
3950 , m_pLayoutEditor(0)
3951 , m_pLayoutSelector(0)
3952 , m_pSettingsWidget(0)
3953 , m_pStatusBarWidget(0)
3954 , m_iGeometrySaveTimerId(-1)
3955{
3956 setWindowTitle(QString("%1 - %2").arg(m_strMachineName).arg(tr("Soft Keyboard")));
3957 prepareObjects();
3958 prepareConnections();
3959
3960 if (m_pKeyboardWidget)
3961 {
3962 m_pKeyboardWidget->loadLayouts();
3963 if (m_pLayoutEditor)
3964 m_pLayoutEditor->setPhysicalLayoutList(m_pKeyboardWidget->physicalLayouts());
3965 }
3966
3967 loadSettings();
3968 configure();
3969 retranslateUi();
3970 uiCommon().setHelpKeyword(this, "soft-keyb");
3971}
3972
3973void UISoftKeyboard::retranslateUi()
3974{
3975}
3976
3977bool UISoftKeyboard::shouldBeMaximized() const
3978{
3979 return gEDataManager->softKeyboardDialogShouldBeMaximized();
3980}
3981
3982void UISoftKeyboard::closeEvent(QCloseEvent *event)
3983{
3984 QStringList strNameList = m_pKeyboardWidget->unsavedLayoutsNameList();
3985 /* Show a warning dialog when there are not saved layouts: */
3986 if (m_pKeyboardWidget && !strNameList.empty())
3987 {
3988 QString strJoinedString = strNameList.join("<br/>");
3989 if (!msgCenter().questionBinary(this, MessageType_Warning,
3990 tr("<p>Following layouts are edited/copied but not saved:</p>%1"
3991 "<p>Closing this dialog will cause loosing the changes. Proceed?</p>").arg(strJoinedString),
3992 0 /* auto-confirm id */,
3993 "Ok", "Cancel"))
3994 {
3995 event->ignore();
3996 return;
3997 }
3998 }
3999 m_pMachine->releaseKeys();
4000 emit sigClose();
4001 event->ignore();
4002}
4003
4004bool UISoftKeyboard::event(QEvent *pEvent)
4005{
4006 if (pEvent->type() == QEvent::WindowDeactivate)
4007 {
4008 if (m_pKeyboardWidget)
4009 m_pKeyboardWidget->parentDialogDeactivated();
4010 }
4011 else if (pEvent->type() == QEvent::KeyPress)
4012 {
4013 QKeyEvent *pKeyEvent = dynamic_cast<QKeyEvent*>(pEvent);
4014 if (pKeyEvent)
4015 {
4016 if (QKeySequence(pKeyEvent->key()) == QKeySequence::HelpContents)
4017 sltHandleHelpRequest();
4018 }
4019 }
4020 else if (pEvent->type() == QEvent::Resize ||
4021 pEvent->type() == QEvent::Move)
4022 {
4023 if (m_iGeometrySaveTimerId != -1)
4024 killTimer(m_iGeometrySaveTimerId);
4025 m_iGeometrySaveTimerId = startTimer(300);
4026 }
4027 else if (pEvent->type() == QEvent::Timer)
4028 {
4029 QTimerEvent *pTimerEvent = static_cast<QTimerEvent*>(pEvent);
4030 if (pTimerEvent->timerId() == m_iGeometrySaveTimerId)
4031 {
4032 killTimer(m_iGeometrySaveTimerId);
4033 m_iGeometrySaveTimerId = -1;
4034 saveDialogGeometry();
4035 }
4036 }
4037
4038 return QMainWindowWithRestorableGeometryAndRetranslateUi::event(pEvent);
4039}
4040
4041void UISoftKeyboard::sltKeyboardLedsChange()
4042{
4043 bool fNumLockLed = m_pMachine->isNumLock();
4044 bool fCapsLockLed = m_pMachine->isCapsLock();
4045 bool fScrollLockLed = m_pMachine->isScrollLock();
4046 if (m_pKeyboardWidget)
4047 m_pKeyboardWidget->updateLockKeyStates(fCapsLockLed, fNumLockLed, fScrollLockLed);
4048}
4049
4050void UISoftKeyboard::sltPutKeyboardSequence(QVector<LONG> sequence)
4051{
4052 m_pMachine->putScancodes(sequence);
4053}
4054
4055void UISoftKeyboard::sltPutUsageCodesPress(QVector<QPair<LONG, LONG> > sequence)
4056{
4057 for (int i = 0; i < sequence.size(); ++i)
4058 m_pMachine->putUsageCode(sequence[i].first, sequence[i].second, false);
4059}
4060
4061void UISoftKeyboard::sltPutUsageCodesRelease(QVector<QPair<LONG, LONG> > sequence)
4062{
4063 for (int i = 0; i < sequence.size(); ++i)
4064 m_pMachine->putUsageCode(sequence[i].first, sequence[i].second, true);
4065}
4066
4067void UISoftKeyboard::sltLayoutSelectionChanged(const QUuid &layoutUid)
4068{
4069 if (!m_pKeyboardWidget)
4070 return;
4071 m_pKeyboardWidget->setCurrentLayout(layoutUid);
4072 if (m_pLayoutSelector && m_pKeyboardWidget->currentLayout())
4073 m_pLayoutSelector->setCurrentLayoutIsEditable(m_pKeyboardWidget->currentLayout()->editable());
4074}
4075
4076void UISoftKeyboard::sltCurentLayoutChanged()
4077{
4078 if (!m_pKeyboardWidget)
4079 return;
4080 UISoftKeyboardLayout *pCurrentLayout = m_pKeyboardWidget->currentLayout();
4081
4082 /* Update the status bar string: */
4083 if (!pCurrentLayout)
4084 return;
4085 updateStatusBarMessage(pCurrentLayout->nameString());
4086 saveCurrentLayout();
4087}
4088
4089void UISoftKeyboard::sltShowLayoutSelector()
4090{
4091 if (m_pSidePanelWidget && m_pLayoutSelector)
4092 m_pSidePanelWidget->setCurrentWidget(m_pLayoutSelector);
4093 if (m_pKeyboardWidget)
4094 m_pKeyboardWidget->toggleEditMode(false);
4095 if (m_pLayoutEditor)
4096 m_pLayoutEditor->setKey(0);
4097}
4098
4099void UISoftKeyboard::sltShowLayoutEditor()
4100{
4101 if (m_pSidePanelWidget && m_pLayoutEditor)
4102 {
4103 m_pLayoutEditor->setLayoutToEdit(m_pKeyboardWidget->currentLayout());
4104 m_pSidePanelWidget->setCurrentWidget(m_pLayoutEditor);
4105 }
4106 if (m_pKeyboardWidget)
4107 m_pKeyboardWidget->toggleEditMode(true);
4108}
4109
4110void UISoftKeyboard::sltKeyToEditChanged(UISoftKeyboardKey* pKey)
4111{
4112 if (m_pLayoutEditor)
4113 m_pLayoutEditor->setKey(pKey);
4114}
4115
4116void UISoftKeyboard::sltLayoutEdited()
4117{
4118 if (!m_pKeyboardWidget)
4119 return;
4120 m_pKeyboardWidget->update();
4121 updateLayoutSelectorList();
4122 UISoftKeyboardLayout *pCurrentLayout = m_pKeyboardWidget->currentLayout();
4123
4124 /* Update the status bar string: */
4125 QString strLayoutName = pCurrentLayout ? pCurrentLayout->name() : QString();
4126 updateStatusBarMessage(strLayoutName);
4127}
4128
4129void UISoftKeyboard::sltKeyCaptionsEdited(UISoftKeyboardKey* pKey)
4130{
4131 Q_UNUSED(pKey);
4132 if (m_pKeyboardWidget)
4133 m_pKeyboardWidget->update();
4134}
4135
4136void UISoftKeyboard::sltShowHideSidePanel()
4137{
4138 if (!m_pSidePanelWidget)
4139 return;
4140 m_pSidePanelWidget->setVisible(!m_pSidePanelWidget->isVisible());
4141
4142 if (m_pSidePanelWidget->isVisible() && m_pSettingsWidget->isVisible())
4143 m_pSettingsWidget->setVisible(false);
4144}
4145
4146void UISoftKeyboard::sltShowHideSettingsWidget()
4147{
4148 if (!m_pSettingsWidget)
4149 return;
4150 m_pSettingsWidget->setVisible(!m_pSettingsWidget->isVisible());
4151 if (m_pSidePanelWidget->isVisible() && m_pSettingsWidget->isVisible())
4152 m_pSidePanelWidget->setVisible(false);
4153}
4154
4155void UISoftKeyboard::sltHandleColorThemeListSelection(const QString &strColorThemeName)
4156{
4157 if (m_pKeyboardWidget)
4158 m_pKeyboardWidget->setColorThemeByName(strColorThemeName);
4159 saveSelectedColorThemeName();
4160}
4161
4162void UISoftKeyboard::sltHandleKeyboardWidgetColorThemeChange()
4163{
4164 for (int i = (int)KeyboardColorType_Background;
4165 i < (int)KeyboardColorType_Max; ++i)
4166 {
4167 KeyboardColorType enmType = (KeyboardColorType)i;
4168 m_pSettingsWidget->setColorSelectionButtonBackgroundAndTooltip(enmType,
4169 m_pKeyboardWidget->color(enmType),
4170 m_pKeyboardWidget->isColorThemeEditable());
4171 }
4172}
4173
4174void UISoftKeyboard::sltCopyLayout()
4175{
4176 if (!m_pKeyboardWidget)
4177 return;
4178 m_pKeyboardWidget->copyCurentLayout();
4179 updateLayoutSelectorList();
4180}
4181
4182void UISoftKeyboard::sltSaveLayout()
4183{
4184 if (m_pKeyboardWidget)
4185 m_pKeyboardWidget->saveCurentLayoutToFile();
4186}
4187
4188void UISoftKeyboard::sltDeleteLayout()
4189{
4190 if (m_pKeyboardWidget)
4191 m_pKeyboardWidget->deleteCurrentLayout();
4192 updateLayoutSelectorList();
4193 if (m_pKeyboardWidget && m_pKeyboardWidget->currentLayout() && m_pLayoutSelector)
4194 {
4195 m_pLayoutSelector->setCurrentLayout(m_pKeyboardWidget->currentLayout()->uid());
4196 m_pLayoutSelector->setCurrentLayoutIsEditable(m_pKeyboardWidget->currentLayout()->editable());
4197 }
4198}
4199
4200void UISoftKeyboard::sltStatusBarMessage(const QString &strMessage)
4201{
4202 statusBar()->showMessage(strMessage, iMessageTimeout);
4203}
4204
4205void UISoftKeyboard::sltShowHideOSMenuKeys(bool fHide)
4206{
4207 if (m_pKeyboardWidget)
4208 m_pKeyboardWidget->setHideOSMenuKeys(fHide);
4209}
4210
4211void UISoftKeyboard::sltShowHideNumPad(bool fHide)
4212{
4213 if (m_pKeyboardWidget)
4214 m_pKeyboardWidget->setHideNumPad(fHide);
4215}
4216
4217void UISoftKeyboard::sltShowHideMultimediaKeys(bool fHide)
4218{
4219 if (m_pKeyboardWidget)
4220 m_pKeyboardWidget->setHideMultimediaKeys(fHide);
4221}
4222
4223void UISoftKeyboard::sltHandleColorCellClick(int iColorRow)
4224{
4225 if (!m_pKeyboardWidget || iColorRow >= static_cast<int>(KeyboardColorType_Max))
4226 return;
4227
4228 if (!m_pKeyboardWidget->isColorThemeEditable())
4229 return;
4230 const QColor &currentColor = m_pKeyboardWidget->color(static_cast<KeyboardColorType>(iColorRow));
4231 QColorDialog colorDialog(currentColor, this);
4232
4233 if (colorDialog.exec() == QDialog::Rejected)
4234 return;
4235 QColor newColor = colorDialog.selectedColor();
4236 if (currentColor == newColor)
4237 return;
4238 m_pKeyboardWidget->setColor(static_cast<KeyboardColorType>(iColorRow), newColor);
4239 m_pSettingsWidget->setColorSelectionButtonBackgroundAndTooltip(static_cast<KeyboardColorType>(iColorRow),
4240 newColor, m_pKeyboardWidget->isColorThemeEditable());
4241 saveCustomColorTheme();
4242}
4243
4244void UISoftKeyboard::sltResetKeyboard()
4245{
4246 if (m_pKeyboardWidget)
4247 m_pKeyboardWidget->reset();
4248 if (m_pLayoutEditor)
4249 m_pLayoutEditor->reset();
4250 m_pMachine->releaseKeys();
4251 update();
4252}
4253
4254void UISoftKeyboard::sltHandleHelpRequest()
4255{
4256 UIHelpBrowserDialog::findManualFileAndShow(uiCommon().helpKeyword(this));
4257}
4258
4259void UISoftKeyboard::prepareObjects()
4260{
4261 m_pSplitter = new QSplitter;
4262 if (!m_pSplitter)
4263 return;
4264 setCentralWidget(m_pSplitter);
4265 m_pSidePanelWidget = new QStackedWidget;
4266 if (!m_pSidePanelWidget)
4267 return;
4268
4269 m_pSidePanelWidget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
4270 m_pSidePanelWidget->hide();
4271
4272 m_pLayoutSelector = new UILayoutSelector;
4273 if (m_pLayoutSelector)
4274 m_pSidePanelWidget->addWidget(m_pLayoutSelector);
4275
4276 m_pLayoutEditor = new UIKeyboardLayoutEditor;
4277 if (m_pLayoutEditor)
4278 m_pSidePanelWidget->addWidget(m_pLayoutEditor);
4279
4280 m_pSettingsWidget = new UISoftKeyboardSettingsWidget;
4281 if (m_pSettingsWidget)
4282 {
4283 m_pSettingsWidget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
4284 m_pSettingsWidget->hide();
4285 }
4286 m_pKeyboardWidget = new UISoftKeyboardWidget;
4287 if (!m_pKeyboardWidget)
4288 return;
4289 m_pKeyboardWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
4290 m_pKeyboardWidget->updateGeometry();
4291 m_pSplitter->addWidget(m_pKeyboardWidget);
4292 m_pSplitter->addWidget(m_pSidePanelWidget);
4293 m_pSplitter->addWidget(m_pSettingsWidget);
4294
4295 m_pSplitter->setCollapsible(0, false);
4296 m_pSplitter->setCollapsible(1, false);
4297 m_pSplitter->setCollapsible(2, false);
4298
4299 statusBar()->setStyleSheet( "QStatusBar::item { border: 0px}" );
4300 m_pStatusBarWidget = new UISoftKeyboardStatusBarWidget;
4301 statusBar()->addPermanentWidget(m_pStatusBarWidget);
4302
4303 retranslateUi();
4304}
4305
4306void UISoftKeyboard::prepareConnections()
4307{
4308 connect(m_pMachine, &UIMachine::sigKeyboardLedsChange, this, &UISoftKeyboard::sltKeyboardLedsChange);
4309 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigPutKeyboardSequence, this, &UISoftKeyboard::sltPutKeyboardSequence);
4310 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigPutUsageCodesPress, this, &UISoftKeyboard::sltPutUsageCodesPress);
4311 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigPutUsageCodesRelease, this, &UISoftKeyboard::sltPutUsageCodesRelease);
4312 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigCurrentLayoutChange, this, &UISoftKeyboard::sltCurentLayoutChanged);
4313 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigKeyToEdit, this, &UISoftKeyboard::sltKeyToEditChanged);
4314 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigStatusBarMessage, this, &UISoftKeyboard::sltStatusBarMessage);
4315 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigCurrentColorThemeChanged, this, &UISoftKeyboard::sltHandleKeyboardWidgetColorThemeChange);
4316 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigOptionsChanged, this, &UISoftKeyboard::sltSaveSettings);
4317
4318 connect(m_pLayoutSelector, &UILayoutSelector::sigLayoutSelectionChanged, this, &UISoftKeyboard::sltLayoutSelectionChanged);
4319 connect(m_pLayoutSelector, &UILayoutSelector::sigShowLayoutEditor, this, &UISoftKeyboard::sltShowLayoutEditor);
4320 connect(m_pLayoutSelector, &UILayoutSelector::sigCloseLayoutList, this, &UISoftKeyboard::sltShowHideSidePanel);
4321 connect(m_pLayoutSelector, &UILayoutSelector::sigSaveLayout, this, &UISoftKeyboard::sltSaveLayout);
4322 connect(m_pLayoutSelector, &UILayoutSelector::sigDeleteLayout, this, &UISoftKeyboard::sltDeleteLayout);
4323 connect(m_pLayoutSelector, &UILayoutSelector::sigCopyLayout, this, &UISoftKeyboard::sltCopyLayout);
4324 connect(m_pLayoutEditor, &UIKeyboardLayoutEditor::sigGoBackButton, this, &UISoftKeyboard::sltShowLayoutSelector);
4325 connect(m_pLayoutEditor, &UIKeyboardLayoutEditor::sigLayoutEdited, this, &UISoftKeyboard::sltLayoutEdited);
4326 connect(m_pLayoutEditor, &UIKeyboardLayoutEditor::sigUIKeyCaptionsEdited, this, &UISoftKeyboard::sltKeyCaptionsEdited);
4327
4328 connect(m_pStatusBarWidget, &UISoftKeyboardStatusBarWidget::sigShowHideSidePanel, this, &UISoftKeyboard::sltShowHideSidePanel);
4329 connect(m_pStatusBarWidget, &UISoftKeyboardStatusBarWidget::sigShowSettingWidget, this, &UISoftKeyboard::sltShowHideSettingsWidget);
4330 connect(m_pStatusBarWidget, &UISoftKeyboardStatusBarWidget::sigResetKeyboard, this, &UISoftKeyboard::sltResetKeyboard);
4331 connect(m_pStatusBarWidget, &UISoftKeyboardStatusBarWidget::sigHelpButtonPressed, this, &UISoftKeyboard::sltHandleHelpRequest);
4332
4333 connect(m_pSettingsWidget, &UISoftKeyboardSettingsWidget::sigHideOSMenuKeys, this, &UISoftKeyboard::sltShowHideOSMenuKeys);
4334 connect(m_pSettingsWidget, &UISoftKeyboardSettingsWidget::sigHideNumPad, this, &UISoftKeyboard::sltShowHideNumPad);
4335 connect(m_pSettingsWidget, &UISoftKeyboardSettingsWidget::sigHideMultimediaKeys, this, &UISoftKeyboard::sltShowHideMultimediaKeys);
4336 connect(m_pSettingsWidget, &UISoftKeyboardSettingsWidget::sigColorCellClicked, this, &UISoftKeyboard::sltHandleColorCellClick);
4337 connect(m_pSettingsWidget, &UISoftKeyboardSettingsWidget::sigCloseSettingsWidget, this, &UISoftKeyboard::sltShowHideSettingsWidget);
4338 connect(m_pSettingsWidget, &UISoftKeyboardSettingsWidget::sigColorThemeSelectionChanged, this, &UISoftKeyboard::sltHandleColorThemeListSelection);
4339
4340 connect(&uiCommon(), &UICommon::sigAskToCommitData, this, &UISoftKeyboard::sltReleaseKeys);
4341}
4342
4343void UISoftKeyboard::saveDialogGeometry()
4344{
4345 const QRect geo = currentGeometry();
4346 LogRel2(("GUI: UISoftKeyboard: Saving geometry as: Origin=%dx%d, Size=%dx%d\n",
4347 geo.x(), geo.y(), geo.width(), geo.height()));
4348 gEDataManager->setSoftKeyboardDialogGeometry(geo, isCurrentlyMaximized());
4349}
4350
4351void UISoftKeyboard::saveCustomColorTheme()
4352{
4353 if (!m_pKeyboardWidget)
4354 return;
4355 /* Save the changes to the 'Custom' color theme to extra data: */
4356 QStringList colors = m_pKeyboardWidget->colorsToStringList("Custom");
4357 colors.prepend("Custom");
4358 gEDataManager->setSoftKeyboardColorTheme(colors);
4359}
4360
4361void UISoftKeyboard::saveSelectedColorThemeName()
4362{
4363 if (!m_pKeyboardWidget)
4364 return;
4365 gEDataManager->setSoftKeyboardSelectedColorTheme(m_pKeyboardWidget->currentColorThemeName());
4366}
4367
4368void UISoftKeyboard::saveCurrentLayout()
4369{
4370 if (m_pKeyboardWidget && m_pKeyboardWidget->currentLayout())
4371 gEDataManager->setSoftKeyboardSelectedLayout(m_pKeyboardWidget->currentLayout()->uid());
4372}
4373
4374void UISoftKeyboard::sltSaveSettings()
4375{
4376 /* Save other settings: */
4377 if (m_pKeyboardWidget)
4378 {
4379 gEDataManager->setSoftKeyboardOptions(m_pKeyboardWidget->hideNumPad(),
4380 m_pKeyboardWidget->hideOSMenuKeys(),
4381 m_pKeyboardWidget->hideMultimediaKeys());
4382 }
4383}
4384
4385void UISoftKeyboard::sltReleaseKeys()
4386{
4387 m_pMachine->releaseKeys();
4388}
4389
4390void UISoftKeyboard::loadSettings()
4391{
4392 /* Invent default window geometry: */
4393 float fKeyboardAspectRatio = 1.0f;
4394 if (m_pKeyboardWidget)
4395 fKeyboardAspectRatio = m_pKeyboardWidget->layoutAspectRatio();
4396 const QRect availableGeo = gpDesktop->availableGeometry(this);
4397 const int iDefaultWidth = availableGeo.width() / 2;
4398 const int iDefaultHeight = iDefaultWidth * fKeyboardAspectRatio;
4399 QRect defaultGeo(0, 0, iDefaultWidth, iDefaultHeight);
4400
4401 /* Load geometry from extradata: */
4402 const QRect geo = gEDataManager->softKeyboardDialogGeometry(this, m_pCenterWidget, defaultGeo);
4403 LogRel2(("GUI: UISoftKeyboard: Restoring geometry to: Origin=%dx%d, Size=%dx%d\n",
4404 geo.x(), geo.y(), geo.width(), geo.height()));
4405 restoreGeometry(geo);
4406
4407 /* Load other settings: */
4408 if (m_pKeyboardWidget)
4409 {
4410 QStringList colorTheme = gEDataManager->softKeyboardColorTheme();
4411 if (!colorTheme.empty())
4412 {
4413 /* The fist item is the theme name and the rest are color codes: */
4414 QString strThemeName = colorTheme[0];
4415 colorTheme.removeFirst();
4416 m_pKeyboardWidget->colorsFromStringList(strThemeName, colorTheme);
4417 }
4418 m_pKeyboardWidget->setColorThemeByName(gEDataManager->softKeyboardSelectedColorTheme());
4419 m_pKeyboardWidget->setCurrentLayout(gEDataManager->softKeyboardSelectedLayout());
4420
4421 /* Load other options from exra data: */
4422 bool fHideNumPad = false;
4423 bool fHideOSMenuKeys = false;
4424 bool fHideMultimediaKeys = false;
4425 gEDataManager->softKeyboardOptions(fHideNumPad, fHideOSMenuKeys, fHideMultimediaKeys);
4426 m_pKeyboardWidget->setHideNumPad(fHideNumPad);
4427 m_pKeyboardWidget->setHideOSMenuKeys(fHideOSMenuKeys);
4428 m_pKeyboardWidget->setHideMultimediaKeys(fHideMultimediaKeys);
4429 }
4430}
4431
4432void UISoftKeyboard::configure()
4433{
4434#ifndef VBOX_WS_MAC
4435 /* Assign window icon: */
4436 setWindowIcon(UIIconPool::iconSetFull(":/soft_keyboard_32px.png", ":/soft_keyboard_16px.png"));
4437#endif
4438
4439 if (m_pKeyboardWidget && m_pSettingsWidget)
4440 {
4441 m_pSettingsWidget->setHideOSMenuKeys(m_pKeyboardWidget->hideOSMenuKeys());
4442 m_pSettingsWidget->setHideNumPad(m_pKeyboardWidget->hideNumPad());
4443 m_pSettingsWidget->setHideMultimediaKeys(m_pKeyboardWidget->hideMultimediaKeys());
4444
4445 m_pSettingsWidget->setColorThemeNames(m_pKeyboardWidget->colorThemeNames());
4446 m_pSettingsWidget->setCurrentColorThemeName(m_pKeyboardWidget->currentColorThemeName());
4447
4448 for (int i = (int)KeyboardColorType_Background;
4449 i < (int)KeyboardColorType_Max; ++i)
4450 {
4451 KeyboardColorType enmType = (KeyboardColorType)i;
4452 m_pSettingsWidget->setColorSelectionButtonBackgroundAndTooltip(enmType,
4453 m_pKeyboardWidget->color(enmType),
4454 m_pKeyboardWidget->isColorThemeEditable());
4455 }
4456 }
4457 updateLayoutSelectorList();
4458 if (m_pKeyboardWidget && m_pKeyboardWidget->currentLayout() && m_pLayoutSelector)
4459 {
4460 m_pLayoutSelector->setCurrentLayout(m_pKeyboardWidget->currentLayout()->uid());
4461 m_pLayoutSelector->setCurrentLayoutIsEditable(m_pKeyboardWidget->currentLayout()->editable());
4462 }
4463}
4464
4465void UISoftKeyboard::updateStatusBarMessage(const QString &strName)
4466{
4467 if (!m_pStatusBarWidget)
4468 return;
4469 QString strMessage;
4470 if (!strName.isEmpty())
4471 {
4472 strMessage += QString("%1: %2").arg(tr("Layout")).arg(strName);
4473 m_pStatusBarWidget->updateLayoutNameInStatusBar(strMessage);
4474 }
4475 else
4476 m_pStatusBarWidget->updateLayoutNameInStatusBar(QString());
4477}
4478
4479void UISoftKeyboard::updateLayoutSelectorList()
4480{
4481 if (!m_pKeyboardWidget || !m_pLayoutSelector)
4482 return;
4483 m_pLayoutSelector->setLayoutList(m_pKeyboardWidget->layoutNameList(), m_pKeyboardWidget->layoutUidList());
4484}
4485
4486#include "UISoftKeyboard.moc"
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette