VirtualBox

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

Last change on this file since 100347 was 100344, checked in by vboxsync, 19 months ago

FE/Qt: bugref:10450: Qt6 compatibility bits for QMouseEvent; Replacing QMouseEvent::pos with QSinglePointEvent::position; S.a. r157776.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 154.7 KB
Line 
1/* $Id: UISoftKeyboard.cpp 100344 2023-07-03 10:09:28Z 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 exections. 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 const QImage &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 QImage m_image;
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, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
1248 this, &UIKeyboardLayoutEditor::sltPhysicalLayoutChanged);
1249
1250 m_pSelectedKeyGroupBox = new QGroupBox;
1251 m_pSelectedKeyGroupBox->setEnabled(false);
1252
1253 m_pEditorLayout->addWidget(m_pSelectedKeyGroupBox, 5, 0, 1, 2);
1254 QGridLayout *pSelectedKeyLayout = new QGridLayout(m_pSelectedKeyGroupBox);
1255 pSelectedKeyLayout->setSpacing(0);
1256 pSelectedKeyLayout->setContentsMargins(0, 0, 0, 0);
1257
1258 m_pScanCodeLabel = new QLabel;
1259 m_pScanCodeEdit = new QLineEdit;
1260 m_pScanCodeLabel->setBuddy(m_pScanCodeEdit);
1261 m_pScanCodeEdit->setEnabled(false);
1262 pSelectedKeyLayout->addWidget(m_pScanCodeLabel, 0, 0);
1263 pSelectedKeyLayout->addWidget(m_pScanCodeEdit, 0, 1);
1264
1265 m_pPositionLabel= new QLabel;
1266 m_pPositionEdit = new QLineEdit;
1267 m_pPositionEdit->setEnabled(false);
1268 m_pPositionLabel->setBuddy(m_pPositionEdit);
1269 pSelectedKeyLayout->addWidget(m_pPositionLabel, 1, 0);
1270 pSelectedKeyLayout->addWidget(m_pPositionEdit, 1, 1);
1271
1272 QWidget *pCaptionEditor = prepareKeyCaptionEditWidgets();
1273 if (pCaptionEditor)
1274 pSelectedKeyLayout->addWidget(pCaptionEditor, 2, 0, 2, 2);
1275
1276 QSpacerItem *pSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding);
1277 if (pSpacer)
1278 pSelectedKeyLayout->addItem(pSpacer, 4, 1);
1279
1280 retranslateUi();
1281}
1282
1283QWidget *UIKeyboardLayoutEditor::prepareKeyCaptionEditWidgets()
1284{
1285 m_pCaptionEditGroupBox = new QGroupBox;
1286 if (!m_pCaptionEditGroupBox)
1287 return 0;
1288 m_pCaptionEditGroupBox->setFlat(false);
1289 QGridLayout *pCaptionEditorLayout = new QGridLayout(m_pCaptionEditGroupBox);
1290 pCaptionEditorLayout->setSpacing(0);
1291 pCaptionEditorLayout->setContentsMargins(0, 0, 0, 0);
1292
1293 if (!pCaptionEditorLayout)
1294 return 0;
1295
1296 m_pBaseCaptionLabel = new QLabel;
1297 m_pBaseCaptionEdit = new QLineEdit;
1298 m_pBaseCaptionLabel->setBuddy(m_pBaseCaptionEdit);
1299 pCaptionEditorLayout->addWidget(m_pBaseCaptionLabel, 0, 0);
1300 pCaptionEditorLayout->addWidget(m_pBaseCaptionEdit, 0, 1);
1301 connect(m_pBaseCaptionEdit, &QLineEdit::textChanged, this, &UIKeyboardLayoutEditor::sltCaptionsUpdate);
1302
1303 m_pShiftCaptionLabel = new QLabel;
1304 m_pShiftCaptionEdit = new QLineEdit;
1305 m_pShiftCaptionLabel->setBuddy(m_pShiftCaptionEdit);
1306 pCaptionEditorLayout->addWidget(m_pShiftCaptionLabel, 1, 0);
1307 pCaptionEditorLayout->addWidget(m_pShiftCaptionEdit, 1, 1);
1308 connect(m_pShiftCaptionEdit, &QLineEdit::textChanged, this, &UIKeyboardLayoutEditor::sltCaptionsUpdate);
1309
1310 m_pAltGrCaptionLabel = new QLabel;
1311 m_pAltGrCaptionEdit = new QLineEdit;
1312 m_pAltGrCaptionLabel->setBuddy(m_pAltGrCaptionEdit);
1313 pCaptionEditorLayout->addWidget(m_pAltGrCaptionLabel, 2, 0);
1314 pCaptionEditorLayout->addWidget(m_pAltGrCaptionEdit, 2, 1);
1315 connect(m_pAltGrCaptionEdit, &QLineEdit::textChanged, this, &UIKeyboardLayoutEditor::sltCaptionsUpdate);
1316
1317 m_pShiftAltGrCaptionLabel = new QLabel;
1318 m_pShiftAltGrCaptionEdit = new QLineEdit;
1319 m_pShiftAltGrCaptionLabel->setBuddy(m_pShiftAltGrCaptionEdit);
1320 pCaptionEditorLayout->addWidget(m_pShiftAltGrCaptionLabel, 3, 0);
1321 pCaptionEditorLayout->addWidget(m_pShiftAltGrCaptionEdit, 3, 1);
1322 connect(m_pShiftAltGrCaptionEdit, &QLineEdit::textChanged, this, &UIKeyboardLayoutEditor::sltCaptionsUpdate);
1323
1324 QSpacerItem *pSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding);
1325 if (pSpacer)
1326 pCaptionEditorLayout->addItem(pSpacer, 4, 1);
1327 return m_pCaptionEditGroupBox;
1328}
1329
1330void UIKeyboardLayoutEditor::reset()
1331{
1332 if (m_pLayoutNameEdit)
1333 m_pLayoutNameEdit->clear();
1334 resetKeyWidgets();
1335}
1336
1337void UIKeyboardLayoutEditor::resetKeyWidgets()
1338{
1339 if (m_pScanCodeEdit)
1340 m_pScanCodeEdit->clear();
1341 if (m_pPositionEdit)
1342 m_pPositionEdit->clear();
1343 if (m_pBaseCaptionEdit)
1344 m_pBaseCaptionEdit->clear();
1345 if (m_pShiftCaptionEdit)
1346 m_pShiftCaptionEdit->clear();
1347 if (m_pAltGrCaptionEdit)
1348 m_pAltGrCaptionEdit->clear();
1349 if (m_pShiftAltGrCaptionEdit)
1350 m_pShiftAltGrCaptionEdit->clear();
1351}
1352
1353/*********************************************************************************************************************************
1354* UILayoutSelector implementation. *
1355*********************************************************************************************************************************/
1356
1357UILayoutSelector::UILayoutSelector(QWidget *pParent /* = 0 */)
1358 :QIWithRetranslateUI<QWidget>(pParent)
1359 , m_pLayoutListWidget(0)
1360 , m_pApplyLayoutButton(0)
1361 , m_pEditLayoutButton(0)
1362 , m_pCopyLayoutButton(0)
1363 , m_pSaveLayoutButton(0)
1364 , m_pDeleteLayoutButton(0)
1365 , m_pTitleLabel(0)
1366 , m_pCloseButton(0)
1367{
1368 prepareObjects();
1369}
1370
1371void UILayoutSelector::setCurrentLayout(const QUuid &layoutUid)
1372{
1373 if (!m_pLayoutListWidget)
1374 return;
1375 if (layoutUid.isNull())
1376 {
1377 m_pLayoutListWidget->selectionModel()->clear();
1378 return;
1379 }
1380 QListWidgetItem *pFoundItem = 0;
1381 for (int i = 0; i < m_pLayoutListWidget->count() && !pFoundItem; ++i)
1382 {
1383 QListWidgetItem *pItem = m_pLayoutListWidget->item(i);
1384 if (!pItem)
1385 continue;
1386 if (pItem->data(Qt::UserRole).toUuid() == layoutUid)
1387 pFoundItem = pItem;
1388 }
1389 if (!pFoundItem)
1390 return;
1391 if (pFoundItem == m_pLayoutListWidget->currentItem())
1392 return;
1393 m_pLayoutListWidget->blockSignals(true);
1394 m_pLayoutListWidget->setCurrentItem(pFoundItem);
1395 m_pLayoutListWidget->blockSignals(false);
1396}
1397
1398void UILayoutSelector::setCurrentLayoutIsEditable(bool fEditable)
1399{
1400 if (m_pEditLayoutButton)
1401 m_pEditLayoutButton->setEnabled(fEditable);
1402 if (m_pSaveLayoutButton)
1403 m_pSaveLayoutButton->setEnabled(fEditable);
1404 if (m_pDeleteLayoutButton)
1405 m_pDeleteLayoutButton->setEnabled(fEditable);
1406}
1407
1408void UILayoutSelector::setLayoutList(const QStringList &layoutNames, QList<QUuid> layoutUidList)
1409{
1410 if (!m_pLayoutListWidget || layoutNames.size() != layoutUidList.size())
1411 return;
1412 QUuid currentItemUid;
1413 if (m_pLayoutListWidget->currentItem())
1414 currentItemUid = m_pLayoutListWidget->currentItem()->data(Qt::UserRole).toUuid();
1415 m_pLayoutListWidget->blockSignals(true);
1416 m_pLayoutListWidget->clear();
1417 for (int i = 0; i < layoutNames.size(); ++i)
1418 {
1419 QListWidgetItem *pItem = new QListWidgetItem(layoutNames[i], m_pLayoutListWidget);
1420 pItem->setData(Qt::UserRole, layoutUidList[i]);
1421 m_pLayoutListWidget->addItem(pItem);
1422 if (layoutUidList[i] == currentItemUid)
1423 m_pLayoutListWidget->setCurrentItem(pItem);
1424 }
1425 m_pLayoutListWidget->sortItems();
1426 m_pLayoutListWidget->blockSignals(false);
1427}
1428
1429void UILayoutSelector::retranslateUi()
1430{
1431 if (m_pApplyLayoutButton)
1432 m_pApplyLayoutButton->setToolTip(UISoftKeyboard::tr("Use the selected layout"));
1433 if (m_pEditLayoutButton)
1434 m_pEditLayoutButton->setToolTip(UISoftKeyboard::tr("Edit the selected layout"));
1435 if (m_pDeleteLayoutButton)
1436 m_pDeleteLayoutButton->setToolTip(UISoftKeyboard::tr("Delete the selected layout"));
1437 if (m_pCopyLayoutButton)
1438 m_pCopyLayoutButton->setToolTip(UISoftKeyboard::tr("Copy the selected layout"));
1439 if (m_pSaveLayoutButton)
1440 m_pSaveLayoutButton->setToolTip(UISoftKeyboard::tr("Save the selected layout into File"));
1441 if (m_pTitleLabel)
1442 m_pTitleLabel->setText(UISoftKeyboard::tr("Layout List"));
1443 if (m_pCloseButton)
1444 {
1445 m_pCloseButton->setToolTip(UISoftKeyboard::tr("Close the layout list"));
1446 m_pCloseButton->setText("Close");
1447 }
1448}
1449
1450void UILayoutSelector::prepareObjects()
1451{
1452 QVBoxLayout *pLayout = new QVBoxLayout;
1453 if (!pLayout)
1454 return;
1455 pLayout->setSpacing(0);
1456 setLayout(pLayout);
1457
1458 QHBoxLayout *pTitleLayout = new QHBoxLayout;
1459 m_pCloseButton = new QToolButton;
1460 m_pCloseButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
1461 m_pCloseButton->setIcon(UIIconPool::defaultIcon(UIIconPool::UIDefaultIconType_DialogCancel));
1462 m_pCloseButton->setAutoRaise(true);
1463 connect(m_pCloseButton, &QToolButton::clicked, this, &UILayoutSelector::sigCloseLayoutList);
1464 m_pTitleLabel = new QLabel;
1465 pTitleLayout->addWidget(m_pTitleLabel);
1466 pTitleLayout->addStretch(2);
1467 pTitleLayout->addWidget(m_pCloseButton);
1468 pLayout->addLayout(pTitleLayout);
1469
1470 m_pLayoutListWidget = new QListWidget;
1471 pLayout->addWidget(m_pLayoutListWidget);
1472 m_pLayoutListWidget->setSortingEnabled(true);
1473 connect(m_pLayoutListWidget, &QListWidget::currentItemChanged, this, &UILayoutSelector::sltCurrentItemChanged);
1474
1475 m_pLayoutListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
1476 QHBoxLayout *pButtonsLayout = new QHBoxLayout;
1477 pLayout->addLayout(pButtonsLayout);
1478
1479 m_pEditLayoutButton = new QToolButton;
1480 m_pEditLayoutButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_layout_edit_16px.png", ":/soft_keyboard_layout_edit_disabled_16px.png"));
1481 pButtonsLayout->addWidget(m_pEditLayoutButton);
1482 connect(m_pEditLayoutButton, &QToolButton::clicked, this, &UILayoutSelector::sigShowLayoutEditor);
1483
1484 m_pCopyLayoutButton = new QToolButton;
1485 m_pCopyLayoutButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_layout_copy_16px.png", ":/soft_keyboard_layout_copy_disabled_16px.png"));
1486 pButtonsLayout->addWidget(m_pCopyLayoutButton);
1487 connect(m_pCopyLayoutButton, &QToolButton::clicked, this, &UILayoutSelector::sigCopyLayout);
1488
1489 m_pSaveLayoutButton = new QToolButton;
1490 m_pSaveLayoutButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_layout_save_16px.png", ":/soft_keyboard_layout_save_disabled_16px.png"));
1491 pButtonsLayout->addWidget(m_pSaveLayoutButton);
1492 connect(m_pSaveLayoutButton, &QToolButton::clicked, this, &UILayoutSelector::sigSaveLayout);
1493
1494 m_pDeleteLayoutButton = new QToolButton;
1495 m_pDeleteLayoutButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_layout_remove_16px.png", ":/soft_keyboard_layout_remove_disabled_16px.png"));
1496 pButtonsLayout->addWidget(m_pDeleteLayoutButton);
1497 connect(m_pDeleteLayoutButton, &QToolButton::clicked, this, &UILayoutSelector::sigDeleteLayout);
1498
1499 pButtonsLayout->addStretch(2);
1500
1501 retranslateUi();
1502}
1503
1504void UILayoutSelector::sltCurrentItemChanged(QListWidgetItem *pCurrent, QListWidgetItem *pPrevious)
1505{
1506 Q_UNUSED(pPrevious);
1507 if (!pCurrent)
1508 return;
1509 emit sigLayoutSelectionChanged(pCurrent->data(Qt::UserRole).toUuid());
1510}
1511
1512/*********************************************************************************************************************************
1513* UISoftKeyboardRow implementation. *
1514*********************************************************************************************************************************/
1515
1516UISoftKeyboardRow::UISoftKeyboardRow()
1517 : m_iDefaultWidth(0)
1518 , m_iDefaultHeight(0)
1519 , m_iSpaceHeightAfter(0)
1520 , m_iLeftMargin(0)
1521{
1522}
1523
1524void UISoftKeyboardRow::setDefaultWidth(int iWidth)
1525{
1526 m_iDefaultWidth = iWidth;
1527}
1528
1529int UISoftKeyboardRow::defaultWidth() const
1530{
1531 return m_iDefaultWidth;
1532}
1533
1534int UISoftKeyboardRow::totalHeight() const
1535{
1536 int iMaxHeight = 0;
1537 for (int i = 0; i < m_keys.size(); ++i)
1538 iMaxHeight = qMax(iMaxHeight, m_keys[i].height());
1539 return iMaxHeight + m_iSpaceHeightAfter;
1540}
1541
1542void UISoftKeyboardRow::setDefaultHeight(int iHeight)
1543{
1544 m_iDefaultHeight = iHeight;
1545}
1546
1547int UISoftKeyboardRow::defaultHeight() const
1548{
1549 return m_iDefaultHeight;
1550}
1551
1552QVector<UISoftKeyboardKey> &UISoftKeyboardRow::keys()
1553{
1554 return m_keys;
1555}
1556
1557const QVector<UISoftKeyboardKey> &UISoftKeyboardRow::keys() const
1558{
1559 return m_keys;
1560}
1561
1562void UISoftKeyboardRow::setSpaceHeightAfter(int iSpace)
1563{
1564 m_iSpaceHeightAfter = iSpace;
1565}
1566
1567int UISoftKeyboardRow::spaceHeightAfter() const
1568{
1569 return m_iSpaceHeightAfter;
1570}
1571
1572int UISoftKeyboardRow::leftMargin() const
1573{
1574 return m_iLeftMargin;
1575}
1576
1577void UISoftKeyboardRow::setLeftMargin(int iMargin)
1578{
1579 m_iLeftMargin = iMargin;
1580}
1581
1582/*********************************************************************************************************************************
1583* UISoftKeyboardKey implementation. *
1584*********************************************************************************************************************************/
1585
1586UISoftKeyboardKey::UISoftKeyboardKey()
1587 : m_enmType(KeyType_Ordinary)
1588 , m_enmState(KeyState_NotPressed)
1589 , m_iWidth(0)
1590 , m_iHeight(0)
1591 , m_iSpaceWidthAfter(0)
1592 , m_scanCode(0)
1593 , m_iCutoutWidth(0)
1594 , m_iCutoutHeight(0)
1595 , m_iCutoutCorner(-1)
1596 , m_iPosition(0)
1597 , m_pParentWidget(0)
1598 , m_enmKeyboardRegion(KeyboardRegion_Main)
1599 , m_fIsOSMenuKey(false)
1600 , m_fCornerRadius(5.)
1601{
1602}
1603
1604const QRect UISoftKeyboardKey::keyGeometry() const
1605{
1606 return m_keyGeometry;
1607}
1608
1609void UISoftKeyboardKey::setKeyGeometry(const QRect &rect)
1610{
1611 m_keyGeometry = rect;
1612}
1613
1614
1615void UISoftKeyboardKey::setWidth(int iWidth)
1616{
1617 m_iWidth = iWidth;
1618}
1619
1620int UISoftKeyboardKey::width() const
1621{
1622 return m_iWidth;
1623}
1624
1625void UISoftKeyboardKey::setHeight(int iHeight)
1626{
1627 m_iHeight = iHeight;
1628}
1629
1630int UISoftKeyboardKey::height() const
1631{
1632 return m_iHeight;
1633}
1634
1635void UISoftKeyboardKey::setScanCode(LONG scanCode)
1636{
1637 m_scanCode = scanCode;
1638}
1639
1640LONG UISoftKeyboardKey::scanCode() const
1641{
1642 return m_scanCode;
1643}
1644
1645void UISoftKeyboardKey::addScanCodePrefix(LONG scanCodePrefix)
1646{
1647 m_scanCodePrefix << scanCodePrefix;
1648}
1649
1650void UISoftKeyboardKey::setSpaceWidthAfter(int iSpace)
1651{
1652 m_iSpaceWidthAfter = iSpace;
1653}
1654
1655int UISoftKeyboardKey::spaceWidthAfter() const
1656{
1657 return m_iSpaceWidthAfter;
1658}
1659
1660void UISoftKeyboardKey::setUsageId(LONG usageId)
1661{
1662 m_iUsageId = usageId;
1663}
1664
1665void UISoftKeyboardKey::setUsagePage(LONG usagePage)
1666{
1667 m_iUsagePage = usagePage;
1668}
1669
1670QPair<LONG, LONG> UISoftKeyboardKey::usagePageIdPair() const
1671{
1672 return QPair<LONG, LONG>(m_iUsageId, m_iUsagePage);
1673}
1674
1675void UISoftKeyboardKey::setPosition(int iPosition)
1676{
1677 m_iPosition = iPosition;
1678}
1679
1680int UISoftKeyboardKey::position() const
1681{
1682 return m_iPosition;
1683}
1684
1685void UISoftKeyboardKey::setType(KeyType enmType)
1686{
1687 m_enmType = enmType;
1688}
1689
1690KeyType UISoftKeyboardKey::type() const
1691{
1692 return m_enmType;
1693}
1694
1695KeyboardRegion UISoftKeyboardKey::keyboardRegion() const
1696{
1697 return m_enmKeyboardRegion;
1698}
1699
1700void UISoftKeyboardKey::setKeyboardRegion(KeyboardRegion enmRegion)
1701{
1702 m_enmKeyboardRegion = enmRegion;
1703}
1704
1705void UISoftKeyboardKey::setCutout(int iCorner, int iWidth, int iHeight)
1706{
1707 m_iCutoutCorner = iCorner;
1708 m_iCutoutWidth = iWidth;
1709 m_iCutoutHeight = iHeight;
1710}
1711
1712KeyState UISoftKeyboardKey::state() const
1713{
1714 return m_enmState;
1715}
1716
1717void UISoftKeyboardKey::setState(KeyState state)
1718{
1719 m_enmState = state;
1720}
1721
1722void UISoftKeyboardKey::setStaticCaption(const QString &strCaption)
1723{
1724 m_strStaticCaption = strCaption;
1725}
1726
1727const QString &UISoftKeyboardKey::staticCaption() const
1728{
1729 return m_strStaticCaption;
1730}
1731
1732void UISoftKeyboardKey::setImageByName(const QString &strImageFileName)
1733{
1734 if (strImageFileName.isEmpty())
1735 return;
1736 m_image = QImage(QString(":/%1").arg(strImageFileName));
1737}
1738
1739const QImage &UISoftKeyboardKey::image() const
1740{
1741 return m_image;
1742}
1743
1744void UISoftKeyboardKey::setParentWidget(UISoftKeyboardWidget* pParent)
1745{
1746 m_pParentWidget = pParent;
1747}
1748
1749void UISoftKeyboardKey::setIsOSMenuKey(bool fFlag)
1750{
1751 m_fIsOSMenuKey = fFlag;
1752}
1753
1754bool UISoftKeyboardKey::isOSMenuKey() const
1755{
1756 return m_fIsOSMenuKey;
1757}
1758
1759void UISoftKeyboardKey::release()
1760{
1761 /* Lock key states are controlled by the event signals we get from the guest OS. See updateLockKeyState function: */
1762 if (m_enmType != KeyType_Lock)
1763 updateState(false);
1764}
1765
1766void UISoftKeyboardKey::press()
1767{
1768 /* Lock key states are controlled by the event signals we get from the guest OS. See updateLockKeyState function: */
1769 if (m_enmType != KeyType_Lock)
1770 updateState(true);
1771}
1772
1773void UISoftKeyboardKey::setPoints(const QVector<QPointF> &points)
1774{
1775 m_points = points;
1776 computePainterPath();
1777}
1778
1779const QVector<QPointF> &UISoftKeyboardKey::points() const
1780{
1781 return m_points;
1782}
1783
1784const QPainterPath &UISoftKeyboardKey::painterPath() const
1785{
1786 return m_painterPath;
1787}
1788
1789void UISoftKeyboardKey::computePainterPath()
1790{
1791 if (m_points.size() < 3)
1792 return;
1793
1794 m_painterPath = QPainterPath(pointInBetween(m_fCornerRadius, m_points[0], m_points[1]));
1795 for (int i = 0; i < m_points.size(); ++i)
1796 {
1797 QPointF p0 = pointInBetween(m_fCornerRadius, m_points[(i+1)%m_points.size()], m_points[i]);
1798 QPointF p1 = pointInBetween(m_fCornerRadius, m_points[(i+1)%m_points.size()], m_points[(i+2)%m_points.size()]);
1799 m_painterPath.lineTo(p0);
1800 m_painterPath.quadTo(m_points[(i+1)%m_points.size()], p1);
1801 }
1802}
1803
1804void UISoftKeyboardKey::setCornerRadius(float fCornerRadius)
1805{
1806 m_fCornerRadius = fCornerRadius;
1807}
1808
1809QPolygonF UISoftKeyboardKey::polygonInGlobal() const
1810{
1811 QPolygonF globalPolygon(m_points);
1812 globalPolygon.translate(m_keyGeometry.x(), m_keyGeometry.y());
1813 return globalPolygon;
1814}
1815
1816int UISoftKeyboardKey::cutoutCorner() const
1817{
1818 return m_iCutoutCorner;
1819}
1820
1821int UISoftKeyboardKey::cutoutWidth() const
1822{
1823 return m_iCutoutWidth;
1824}
1825
1826int UISoftKeyboardKey::cutoutHeight() const
1827{
1828 return m_iCutoutHeight;
1829}
1830
1831void UISoftKeyboardKey::updateState(bool fPressed)
1832{
1833 KeyState enmPreviousState = state();
1834 if (m_enmType == KeyType_Modifier)
1835 {
1836 if (fPressed)
1837 {
1838 if (m_enmState == KeyState_NotPressed)
1839 m_enmState = KeyState_Pressed;
1840 else if(m_enmState == KeyState_Pressed)
1841 m_enmState = KeyState_Locked;
1842 else
1843 m_enmState = KeyState_NotPressed;
1844 }
1845 else
1846 {
1847 if(m_enmState == KeyState_Pressed)
1848 m_enmState = KeyState_NotPressed;
1849 }
1850 }
1851 else if (m_enmType == KeyType_Lock)
1852 {
1853 m_enmState = fPressed ? KeyState_Locked : KeyState_NotPressed;
1854 }
1855 else if (m_enmType == KeyType_Ordinary)
1856 {
1857 if (m_enmState == KeyState_NotPressed)
1858 m_enmState = KeyState_Pressed;
1859 else
1860 m_enmState = KeyState_NotPressed;
1861 }
1862 if (enmPreviousState != state() && m_pParentWidget)
1863 m_pParentWidget->keyStateChange(this);
1864}
1865
1866void UISoftKeyboardKey::updateLockState(bool fLocked)
1867{
1868 if (m_enmType != KeyType_Lock)
1869 return;
1870 if (fLocked && m_enmState == KeyState_Locked)
1871 return;
1872 if (!fLocked && m_enmState == KeyState_NotPressed)
1873 return;
1874 updateState(fLocked);
1875}
1876
1877void UISoftKeyboardKey::reset()
1878{
1879 m_enmState = KeyState_NotPressed;
1880}
1881
1882
1883/*********************************************************************************************************************************
1884* UISoftKeyboardLayout implementation. *
1885*********************************************************************************************************************************/
1886
1887UISoftKeyboardLayout::UISoftKeyboardLayout()
1888 : m_fEditable(true)
1889 , m_fIsFromResources(false)
1890 , m_fEditedButNotSaved(false)
1891 , m_uid(QUuid::createUuid())
1892{
1893}
1894
1895QString UISoftKeyboardLayout::nameString() const
1896{
1897 QString strCombinedName;
1898 if (nativeName().isEmpty() && !name().isEmpty())
1899 strCombinedName = name();
1900 else if (!nativeName().isEmpty() && name().isEmpty())
1901 strCombinedName = nativeName();
1902 else
1903 strCombinedName = QString("%1 (%2)").arg(nativeName()).arg(name());
1904 return strCombinedName;
1905}
1906
1907void UISoftKeyboardLayout::setSourceFilePath(const QString& strSourceFilePath)
1908{
1909 m_strSourceFilePath = strSourceFilePath;
1910 setEditedBuNotSaved(true);
1911}
1912
1913const QString& UISoftKeyboardLayout::sourceFilePath() const
1914{
1915 return m_strSourceFilePath;
1916}
1917
1918void UISoftKeyboardLayout::setIsFromResources(bool fIsFromResources)
1919{
1920 m_fIsFromResources = fIsFromResources;
1921 setEditedBuNotSaved(true);
1922}
1923
1924bool UISoftKeyboardLayout::isFromResources() const
1925{
1926 return m_fIsFromResources;
1927}
1928
1929void UISoftKeyboardLayout::setName(const QString &strName)
1930{
1931 m_strName = strName;
1932 setEditedBuNotSaved(true);
1933}
1934
1935const QString &UISoftKeyboardLayout::name() const
1936{
1937 return m_strName;
1938}
1939
1940void UISoftKeyboardLayout::setNativeName(const QString &strNativeName)
1941{
1942 m_strNativeName = strNativeName;
1943 setEditedBuNotSaved(true);
1944}
1945
1946const QString &UISoftKeyboardLayout::nativeName() const
1947{
1948 return m_strNativeName;
1949}
1950
1951void UISoftKeyboardLayout::setEditable(bool fEditable)
1952{
1953 m_fEditable = fEditable;
1954 setEditedBuNotSaved(true);
1955}
1956
1957bool UISoftKeyboardLayout::editable() const
1958{
1959 return m_fEditable;
1960}
1961
1962void UISoftKeyboardLayout::setPhysicalLayoutUuid(const QUuid &uuid)
1963{
1964 m_physicalLayoutUuid = uuid;
1965 setEditedBuNotSaved(true);
1966}
1967
1968const QUuid &UISoftKeyboardLayout::physicalLayoutUuid() const
1969{
1970 return m_physicalLayoutUuid;
1971}
1972
1973void UISoftKeyboardLayout::addOrUpdateUIKeyCaptions(int iKeyPosition, const UIKeyCaptions &keyCaptions)
1974{
1975 if (m_keyCaptionsMap[iKeyPosition] == keyCaptions)
1976 return;
1977 m_keyCaptionsMap[iKeyPosition] = keyCaptions;
1978 /* Updating the captions invalidates the cached font size. We set it to 0, thereby forcing its recomputaion: */
1979 m_keyCaptionsFontSizeMap[iKeyPosition] = 0;
1980 setEditedBuNotSaved(true);
1981}
1982
1983UIKeyCaptions UISoftKeyboardLayout::keyCaptions(int iKeyPosition) const
1984{
1985 return m_keyCaptionsMap[iKeyPosition];
1986}
1987
1988bool UISoftKeyboardLayout::operator==(const UISoftKeyboardLayout &otherLayout) const
1989{
1990 if (m_strName != otherLayout.m_strName)
1991 return false;
1992 if (m_strNativeName != otherLayout.m_strNativeName)
1993 return false;
1994 if (m_physicalLayoutUuid != otherLayout.m_physicalLayoutUuid)
1995 return false;
1996 if (m_fEditable != otherLayout.m_fEditable)
1997 return false;
1998 if (m_strSourceFilePath != otherLayout.m_strSourceFilePath)
1999 return false;
2000 if (m_fIsFromResources != otherLayout.m_fIsFromResources)
2001 return false;
2002 return true;
2003}
2004
2005QString UISoftKeyboardLayout::baseCaption(int iKeyPosition) const
2006{
2007 return m_keyCaptionsMap.value(iKeyPosition, UIKeyCaptions()).m_strBase;
2008}
2009
2010QString UISoftKeyboardLayout::shiftCaption(int iKeyPosition) const
2011{
2012 if (!m_keyCaptionsMap.contains(iKeyPosition))
2013 return QString();
2014 return m_keyCaptionsMap[iKeyPosition].m_strShift;
2015}
2016
2017QString UISoftKeyboardLayout::altGrCaption(int iKeyPosition) const
2018{
2019 if (!m_keyCaptionsMap.contains(iKeyPosition))
2020 return QString();
2021 return m_keyCaptionsMap[iKeyPosition].m_strAltGr;
2022}
2023
2024QString UISoftKeyboardLayout::shiftAltGrCaption(int iKeyPosition) const
2025{
2026 if (!m_keyCaptionsMap.contains(iKeyPosition))
2027 return QString();
2028 return m_keyCaptionsMap[iKeyPosition].m_strShiftAltGr;
2029}
2030
2031void UISoftKeyboardLayout::setEditedBuNotSaved(bool fEditedButNotsaved)
2032{
2033 m_fEditedButNotSaved = fEditedButNotsaved;
2034}
2035
2036bool UISoftKeyboardLayout::editedButNotSaved() const
2037{
2038 return m_fEditedButNotSaved;
2039}
2040
2041void UISoftKeyboardLayout::setUid(const QUuid &uid)
2042{
2043 m_uid = uid;
2044 setEditedBuNotSaved(true);
2045}
2046
2047QUuid UISoftKeyboardLayout::uid() const
2048{
2049 return m_uid;
2050}
2051
2052void UISoftKeyboardLayout::drawTextInRect(const UISoftKeyboardKey &key, QPainter &painter)
2053{
2054 int iKeyPosition = key.position();
2055 const QRect &keyGeometry = key.keyGeometry();
2056 QFont painterFont(painter.font());
2057
2058 QString strBaseCaption;
2059 QString strShiftCaption;
2060 QString strShiftAltGrCaption;
2061 QString strAltGrCaption;
2062
2063 /* Static captions which are defined in the physical layout files have precedence over
2064 the one define in the keyboard layouts. In effect they stay the same for all the
2065 keyboard layouts sharing the same physical layout: */
2066
2067 if (key.staticCaption().isEmpty())
2068 {
2069 strBaseCaption = baseCaption(iKeyPosition);
2070 strShiftCaption = shiftCaption(iKeyPosition);
2071 strShiftAltGrCaption = shiftAltGrCaption(iKeyPosition);
2072 strAltGrCaption = altGrCaption(iKeyPosition);
2073 }
2074 else
2075 strBaseCaption = key.staticCaption();
2076
2077 const QString &strTopleftString = !strShiftCaption.isEmpty() ? strShiftCaption : strBaseCaption;
2078 const QString &strBottomleftString = !strShiftCaption.isEmpty() ? strBaseCaption : QString();
2079
2080 int iFontSize = 30;
2081 if (!m_keyCaptionsFontSizeMap.contains(iKeyPosition) || m_keyCaptionsFontSizeMap.value(iKeyPosition) == 0)
2082 {
2083 do
2084 {
2085 painterFont.setPixelSize(iFontSize);
2086 painterFont.setBold(true);
2087 painter.setFont(painterFont);
2088 QFontMetrics fontMetrics = painter.fontMetrics();
2089#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
2090 int iMargin = 0.25 * fontMetrics.horizontalAdvance('X');
2091#else
2092 int iMargin = 0.25 * fontMetrics.width('X');
2093#endif
2094
2095 int iTopWidth = 0;
2096 /* Some captions are multi line using \n as separator: */
2097 QStringList strList;
2098#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
2099 strList << strTopleftString.split("\n", Qt::SkipEmptyParts)
2100 << strShiftAltGrCaption.split("\n", Qt::SkipEmptyParts);
2101#else
2102 strList << strTopleftString.split("\n", QString::SkipEmptyParts)
2103 << strShiftAltGrCaption.split("\n", QString::SkipEmptyParts);
2104#endif
2105 foreach (const QString &strPart, strList)
2106#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
2107 iTopWidth = qMax(iTopWidth, fontMetrics.horizontalAdvance(strPart));
2108#else
2109 iTopWidth = qMax(iTopWidth, fontMetrics.width(strPart));
2110#endif
2111 strList.clear();
2112#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
2113 strList << strBottomleftString.split("\n", Qt::SkipEmptyParts)
2114 << strAltGrCaption.split("\n", Qt::SkipEmptyParts);
2115#else
2116 strList << strBottomleftString.split("\n", QString::SkipEmptyParts)
2117 << strAltGrCaption.split("\n", QString::SkipEmptyParts);
2118#endif
2119
2120 int iBottomWidth = 0;
2121 foreach (const QString &strPart, strList)
2122#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
2123 iBottomWidth = qMax(iBottomWidth, fontMetrics.horizontalAdvance(strPart));
2124#else
2125 iBottomWidth = qMax(iBottomWidth, fontMetrics.width(strPart));
2126#endif
2127 int iTextWidth = 2 * iMargin + qMax(iTopWidth, iBottomWidth);
2128 int iTextHeight = 0;
2129
2130 if (key.keyboardRegion() == KeyboardRegion_MultimediaKeys)
2131 iTextHeight = 2 * iMargin + fontMetrics.height();
2132 else
2133 iTextHeight = 2 * iMargin + 2 * fontMetrics.height();
2134
2135 if (iTextWidth >= keyGeometry.width() || iTextHeight >= keyGeometry.height())
2136 --iFontSize;
2137 else
2138 break;
2139
2140 }while(iFontSize > 1);
2141 m_keyCaptionsFontSizeMap[iKeyPosition] = iFontSize;
2142 }
2143 else
2144 {
2145 iFontSize = m_keyCaptionsFontSizeMap[iKeyPosition];
2146 painterFont.setPixelSize(iFontSize);
2147 painterFont.setBold(true);
2148 painter.setFont(painterFont);
2149 }
2150
2151 QFontMetrics fontMetrics = painter.fontMetrics();
2152#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
2153 int iMargin = 0.25 * fontMetrics.horizontalAdvance('X');
2154#else
2155 int iMargin = 0.25 * fontMetrics.width('X');
2156#endif
2157 QRect textRect;
2158 if (key.keyboardRegion() == KeyboardRegion_MultimediaKeys)
2159 textRect = QRect(2 * iMargin, iMargin,
2160 keyGeometry.width() - 2 * iMargin,
2161 keyGeometry.height() - 2 * iMargin);
2162 else
2163 textRect = QRect(iMargin, iMargin,
2164 keyGeometry.width() - 2 * iMargin,
2165 keyGeometry.height() - 2 * iMargin);
2166
2167 if (key.keyboardRegion() == KeyboardRegion_MultimediaKeys)
2168 {
2169 painter.drawText(QRect(0, 0, keyGeometry.width(), keyGeometry.height()),
2170 Qt::AlignHCenter | Qt::AlignVCenter, strTopleftString);
2171 }
2172 else
2173 {
2174 painter.drawText(textRect, Qt::AlignLeft | Qt::AlignTop, strTopleftString);
2175 painter.drawText(textRect, Qt::AlignLeft | Qt::AlignBottom, strBottomleftString);
2176 painter.drawText(textRect, Qt::AlignRight | Qt::AlignTop, strShiftAltGrCaption);
2177 painter.drawText(textRect, Qt::AlignRight | Qt::AlignBottom, strAltGrCaption);
2178 }
2179}
2180
2181void UISoftKeyboardLayout::drawKeyImageInRect(const UISoftKeyboardKey &key, QPainter &painter)
2182{
2183 if (key.image().isNull())
2184 return;
2185 const QRect &keyGeometry = key.keyGeometry();
2186 int iMargin = 0.1 * qMax(keyGeometry.width(), keyGeometry.height());
2187 int size = qMin(keyGeometry.width() - 2 * iMargin, keyGeometry.height() - 2 * iMargin);
2188 painter.drawImage(QRect(0.5 * (keyGeometry.width() - size), 0.5 * (keyGeometry.height() - size),
2189 size, size), key.image());
2190}
2191
2192
2193/*********************************************************************************************************************************
2194* UISoftKeyboardColorTheme implementation. *
2195*********************************************************************************************************************************/
2196
2197UISoftKeyboardColorTheme::UISoftKeyboardColorTheme()
2198 : m_colors(QVector<QColor>(KeyboardColorType_Max))
2199 , m_fIsEditable(false)
2200{
2201 m_colors[KeyboardColorType_Background].setNamedColor("#ff878787");
2202 m_colors[KeyboardColorType_Font].setNamedColor("#ff000000");
2203 m_colors[KeyboardColorType_Hover].setNamedColor("#ff676767");
2204 m_colors[KeyboardColorType_Edit].setNamedColor("#ff9b6767");
2205 m_colors[KeyboardColorType_Pressed].setNamedColor("#fffafafa");
2206}
2207
2208UISoftKeyboardColorTheme::UISoftKeyboardColorTheme(const QString &strName,
2209 const QString &strBackgroundColor,
2210 const QString &strNormalFontColor,
2211 const QString &strHoverColor,
2212 const QString &strEditedButtonBackgroundColor,
2213 const QString &strPressedButtonFontColor)
2214 :m_colors(QVector<QColor>(KeyboardColorType_Max))
2215 ,m_strName(strName)
2216 , m_fIsEditable(false)
2217{
2218 m_colors[KeyboardColorType_Background].setNamedColor(strBackgroundColor);
2219 m_colors[KeyboardColorType_Font].setNamedColor(strNormalFontColor);
2220 m_colors[KeyboardColorType_Hover].setNamedColor(strHoverColor);
2221 m_colors[KeyboardColorType_Edit].setNamedColor(strEditedButtonBackgroundColor);
2222 m_colors[KeyboardColorType_Pressed].setNamedColor(strPressedButtonFontColor);
2223}
2224
2225
2226void UISoftKeyboardColorTheme::setColor(KeyboardColorType enmColorType, const QColor &color)
2227{
2228 if ((int) enmColorType >= m_colors.size())
2229 return;
2230 m_colors[(int)enmColorType] = color;
2231}
2232
2233QColor UISoftKeyboardColorTheme::color(KeyboardColorType enmColorType) const
2234{
2235 if ((int) enmColorType >= m_colors.size())
2236 return QColor();
2237 return m_colors[(int)enmColorType];
2238}
2239
2240QStringList UISoftKeyboardColorTheme::colorsToStringList() const
2241{
2242 QStringList colorStringList;
2243 foreach (const QColor &color, m_colors)
2244 colorStringList << color.name(QColor::HexArgb);
2245 return colorStringList;
2246}
2247
2248void UISoftKeyboardColorTheme::colorsFromStringList(const QStringList &colorStringList)
2249{
2250 for (int i = 0; i < colorStringList.size() && i < m_colors.size(); ++i)
2251 {
2252 if (!QColor::isValidColor(colorStringList[i]))
2253 continue;
2254 m_colors[i].setNamedColor(colorStringList[i]);
2255 }
2256}
2257
2258const QString &UISoftKeyboardColorTheme::name() const
2259{
2260 return m_strName;
2261}
2262
2263void UISoftKeyboardColorTheme::setName(const QString &strName)
2264{
2265 m_strName = strName;
2266}
2267
2268bool UISoftKeyboardColorTheme::isEditable() const
2269{
2270 return m_fIsEditable;
2271}
2272
2273void UISoftKeyboardColorTheme::setIsEditable(bool fIsEditable)
2274{
2275 m_fIsEditable = fIsEditable;
2276}
2277
2278/*********************************************************************************************************************************
2279* UISoftKeyboardWidget implementation. *
2280*********************************************************************************************************************************/
2281
2282UISoftKeyboardWidget::UISoftKeyboardWidget(QWidget *pParent /* = 0 */)
2283 :QIWithRetranslateUI<QWidget>(pParent)
2284 , m_pKeyUnderMouse(0)
2285 , m_pKeyBeingEdited(0)
2286 , m_pKeyPressed(0)
2287 , m_currentColorTheme(0)
2288 , m_iInitialHeight(0)
2289 , m_iInitialWidth(0)
2290 , m_iInitialWidthNoNumPad(0)
2291 , m_iBeforeNumPadWidth(30)
2292 , m_iXSpacing(5)
2293 , m_iYSpacing(5)
2294 , m_iLeftMargin(10)
2295 , m_iTopMargin(10)
2296 , m_iRightMargin(10)
2297 , m_iBottomMargin(10)
2298 , m_enmMode(Mode_Keyboard)
2299 , m_fHideOSMenuKeys(false)
2300 , m_fHideNumPad(false)
2301 , m_fHideMultimediaKeys(false)
2302{
2303 prepareObjects();
2304 prepareColorThemes();
2305 retranslateUi();
2306}
2307
2308QSize UISoftKeyboardWidget::minimumSizeHint() const
2309{
2310 float fScale = 0.5f;
2311 return QSize(fScale * m_minimumSize.width(), fScale * m_minimumSize.height());
2312}
2313
2314QSize UISoftKeyboardWidget::sizeHint() const
2315{
2316 float fScale = 0.5f;
2317 return QSize(fScale * m_minimumSize.width(), fScale * m_minimumSize.height());
2318}
2319
2320void UISoftKeyboardWidget::paintEvent(QPaintEvent *pEvent) /* override */
2321{
2322 Q_UNUSED(pEvent);
2323 if (!m_layouts.contains(m_uCurrentLayoutId))
2324 return;
2325
2326 UISoftKeyboardLayout &currentLayout = m_layouts[m_uCurrentLayoutId];
2327
2328 if (m_iInitialWidth == 0 || m_iInitialWidthNoNumPad == 0 || m_iInitialHeight == 0)
2329 return;
2330
2331 if (!m_fHideNumPad)
2332 m_fScaleFactorX = width() / (float) (m_iInitialWidth + m_iBeforeNumPadWidth);
2333 else
2334 m_fScaleFactorX = width() / (float) m_iInitialWidthNoNumPad;
2335
2336 if (!m_fHideMultimediaKeys)
2337 m_fScaleFactorY = height() / (float) m_iInitialHeight;
2338 else
2339 m_fScaleFactorY = height() / (float)(m_iInitialHeight - m_multiMediaKeysLayout.totalHeight());
2340
2341 QPainter painter(this);
2342 QFont painterFont(font());
2343 painterFont.setPixelSize(15);
2344 painterFont.setBold(true);
2345 painter.setFont(painterFont);
2346 painter.setRenderHint(QPainter::Antialiasing);
2347 painter.setRenderHint(QPainter::SmoothPixmapTransform);
2348 painter.scale(m_fScaleFactorX, m_fScaleFactorY);
2349 int unitSize = qApp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin);
2350 float fLedRadius = 0.8 * unitSize;
2351 float fLedMargin = 5;//0.6 * unitSize;
2352
2353 UISoftKeyboardPhysicalLayout *pPhysicalLayout = findPhysicalLayout(currentLayout.physicalLayoutUuid());
2354 if (!pPhysicalLayout)
2355 return;
2356
2357 QVector<UISoftKeyboardRow> &rows = pPhysicalLayout->rows();
2358 for (int i = 0; i < rows.size(); ++i)
2359 {
2360 QVector<UISoftKeyboardKey> &keys = rows[i].keys();
2361 for (int j = 0; j < keys.size(); ++j)
2362 {
2363 UISoftKeyboardKey &key = keys[j];
2364
2365 if (m_fHideOSMenuKeys && key.isOSMenuKey())
2366 continue;
2367
2368 if (m_fHideNumPad && key.keyboardRegion() == KeyboardRegion_NumPad)
2369 continue;
2370
2371 if (m_fHideMultimediaKeys && key.keyboardRegion() == KeyboardRegion_MultimediaKeys)
2372 continue;
2373
2374 if (m_fHideMultimediaKeys)
2375 painter.translate(key.keyGeometry().x(), key.keyGeometry().y() - m_multiMediaKeysLayout.totalHeight());
2376 else
2377 painter.translate(key.keyGeometry().x(), key.keyGeometry().y());
2378
2379 if(&key == m_pKeyBeingEdited)
2380 painter.setBrush(QBrush(color(KeyboardColorType_Edit)));
2381 else if (&key == m_pKeyUnderMouse)
2382 painter.setBrush(QBrush(color(KeyboardColorType_Hover)));
2383 else
2384 painter.setBrush(QBrush(color(KeyboardColorType_Background)));
2385
2386 if (&key == m_pKeyPressed)
2387 painter.setPen(QPen(color(KeyboardColorType_Pressed), 2));
2388 else
2389 painter.setPen(QPen(color(KeyboardColorType_Font), 2));
2390
2391 /* Draw the key shape: */
2392 painter.drawPath(key.painterPath());
2393
2394 if (key.keyboardRegion() == KeyboardRegion_MultimediaKeys)
2395 currentLayout.drawKeyImageInRect(key, painter);
2396 else
2397 currentLayout.drawTextInRect(key, painter);
2398 /* Draw small LED like circles on the modifier/lock keys: */
2399 if (key.type() != KeyType_Ordinary)
2400 {
2401 QColor ledColor;
2402 if (key.type() == KeyType_Lock)
2403 {
2404 if (key.state() == KeyState_NotPressed)
2405 ledColor = color(KeyboardColorType_Font);
2406 else
2407 ledColor = QColor(0, 255, 0);
2408 }
2409 else
2410 {
2411 if (key.state() == KeyState_NotPressed)
2412 ledColor = color(KeyboardColorType_Font);
2413 else if (key.state() == KeyState_Pressed)
2414 ledColor = QColor(0, 191, 204);
2415 else
2416 ledColor = QColor(255, 50, 50);
2417 }
2418 if (m_enmMode == Mode_LayoutEdit)
2419 ledColor = color(KeyboardColorType_Font);
2420 painter.setBrush(ledColor);
2421 painter.setPen(ledColor);
2422 QRectF rectangle(key.keyGeometry().width() - 2 * fLedMargin, key.keyGeometry().height() - 2 * fLedMargin,
2423 fLedRadius, fLedRadius);
2424 painter.drawEllipse(rectangle);
2425 }
2426 if (m_fHideMultimediaKeys)
2427 painter.translate(-key.keyGeometry().x(), -key.keyGeometry().y() + m_multiMediaKeysLayout.totalHeight());
2428 else
2429 painter.translate(-key.keyGeometry().x(), -key.keyGeometry().y());
2430 }
2431 }
2432}
2433
2434void UISoftKeyboardWidget::mousePressEvent(QMouseEvent *pEvent)
2435{
2436 QWidget::mousePressEvent(pEvent);
2437 if (pEvent->button() != Qt::RightButton && pEvent->button() != Qt::LeftButton)
2438 return;
2439
2440 m_pKeyPressed = keyUnderMouse(pEvent);
2441 if (!m_pKeyPressed)
2442 return;
2443
2444 /* Handling the right button press: */
2445 if (pEvent->button() == Qt::RightButton)
2446 modifierKeyPressRelease(m_pKeyPressed, false);
2447 else
2448 {
2449 /* Handling the left button press: */
2450 if (m_enmMode == Mode_Keyboard)
2451 handleKeyPress(m_pKeyPressed);
2452 else if (m_enmMode == Mode_LayoutEdit)
2453 setKeyBeingEdited(m_pKeyUnderMouse);
2454 }
2455 update();
2456}
2457
2458void UISoftKeyboardWidget::mouseReleaseEvent(QMouseEvent *pEvent)
2459{
2460 QWidget::mouseReleaseEvent(pEvent);
2461
2462 if (pEvent->button() != Qt::RightButton && pEvent->button() != Qt::LeftButton)
2463 return;
2464
2465 if (!m_pKeyPressed)
2466 return;
2467 if (pEvent->button() == Qt::RightButton)
2468 modifierKeyPressRelease(m_pKeyPressed, true);
2469 else
2470 {
2471 if (m_enmMode == Mode_Keyboard)
2472 handleKeyRelease(m_pKeyPressed);
2473 }
2474 m_pKeyPressed = 0;
2475 update();
2476}
2477
2478void UISoftKeyboardWidget::mouseMoveEvent(QMouseEvent *pEvent)
2479{
2480 QWidget::mouseMoveEvent(pEvent);
2481 UISoftKeyboardKey *pPreviousKeyUnderMouse = m_pKeyUnderMouse;
2482 keyUnderMouse(pEvent);
2483 if (pPreviousKeyUnderMouse != m_pKeyUnderMouse)
2484 showKeyTooltip(m_pKeyUnderMouse);
2485}
2486
2487void UISoftKeyboardWidget::retranslateUi()
2488{
2489 m_keyTooltips[317] = UISoftKeyboard::tr("Power off");
2490 m_keyTooltips[300] = UISoftKeyboard::tr("Web browser go back");
2491 m_keyTooltips[301] = UISoftKeyboard::tr("Web browser go the home page");
2492 m_keyTooltips[302] = UISoftKeyboard::tr("Web browser go forward");
2493 m_keyTooltips[315] = UISoftKeyboard::tr("Web browser reload the current page");
2494 m_keyTooltips[314] = UISoftKeyboard::tr("Web browser stop loading the page");
2495 m_keyTooltips[313] = UISoftKeyboard::tr("Web browser search");
2496
2497 m_keyTooltips[307] = UISoftKeyboard::tr("Jump back to previous media track");
2498 m_keyTooltips[308] = UISoftKeyboard::tr("Jump to next media track");
2499 m_keyTooltips[309] = UISoftKeyboard::tr("Stop playing");
2500 m_keyTooltips[310] = UISoftKeyboard::tr("Play or pause playing");
2501
2502 m_keyTooltips[303] = UISoftKeyboard::tr("Start email application");
2503 m_keyTooltips[311] = UISoftKeyboard::tr("Start calculator");
2504 m_keyTooltips[312] = UISoftKeyboard::tr("Show 'My Computer'");
2505 m_keyTooltips[316] = UISoftKeyboard::tr("Show Media folder");
2506
2507 m_keyTooltips[304] = UISoftKeyboard::tr("Mute");
2508 m_keyTooltips[305] = UISoftKeyboard::tr("Volume down");
2509 m_keyTooltips[306] = UISoftKeyboard::tr("Volume up");
2510}
2511
2512void UISoftKeyboardWidget::saveCurentLayoutToFile()
2513{
2514 if (!m_layouts.contains(m_uCurrentLayoutId))
2515 return;
2516 UISoftKeyboardLayout &currentLayout = m_layouts[m_uCurrentLayoutId];
2517 QString strHomeFolder = uiCommon().homeFolder();
2518 QDir dir(strHomeFolder);
2519 if (!dir.exists(strSubDirectorName))
2520 {
2521 if (!dir.mkdir(strSubDirectorName))
2522 {
2523 sigStatusBarMessage(QString("%1 %2").arg(UISoftKeyboard::tr("Error! Could not create folder under").arg(strHomeFolder)));
2524 return;
2525 }
2526 }
2527
2528 strHomeFolder += QString(QDir::separator()) + strSubDirectorName;
2529 QInputDialog dialog(this);
2530 dialog.setInputMode(QInputDialog::TextInput);
2531 dialog.setWindowModality(Qt::WindowModal);
2532 dialog.setWindowTitle(UISoftKeyboard::tr("Provide a file name"));
2533 dialog.setTextValue(currentLayout.name());
2534 dialog.setLabelText(QString("%1 %2").arg(UISoftKeyboard::tr("The file will be saved under:<br>")).arg(strHomeFolder));
2535 if (dialog.exec() == QDialog::Rejected)
2536 return;
2537 QString strFileName(dialog.textValue());
2538 if (strFileName.isEmpty() || strFileName.contains("..") || strFileName.contains(QDir::separator()))
2539 {
2540 sigStatusBarMessage(QString("%1 %2").arg(strFileName).arg(UISoftKeyboard::tr(" is an invalid file name")));
2541 return;
2542 }
2543
2544 UISoftKeyboardPhysicalLayout *pPhysicalLayout = findPhysicalLayout(currentLayout.physicalLayoutUuid());
2545 if (!pPhysicalLayout)
2546 {
2547 sigStatusBarMessage("The layout file could not be saved");
2548 return;
2549 }
2550
2551 QFileInfo fileInfo(strFileName);
2552 if (fileInfo.suffix().compare("xml", Qt::CaseInsensitive) != 0)
2553 strFileName += ".xml";
2554 strFileName = strHomeFolder + QString(QDir::separator()) + strFileName;
2555 QFile xmlFile(strFileName);
2556 if (!xmlFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
2557 {
2558 sigStatusBarMessage("The layout file could not be saved");
2559 return;
2560 }
2561
2562 QXmlStreamWriter xmlWriter;
2563 xmlWriter.setDevice(&xmlFile);
2564
2565 xmlWriter.setAutoFormatting(true);
2566 xmlWriter.writeStartDocument("1.0");
2567 xmlWriter.writeStartElement("layout");
2568 xmlWriter.writeTextElement("name", currentLayout.name());
2569 xmlWriter.writeTextElement("nativename", currentLayout.nativeName());
2570 xmlWriter.writeTextElement("physicallayoutid", pPhysicalLayout->uid().toString());
2571 xmlWriter.writeTextElement("id", currentLayout.uid().toString());
2572
2573 QVector<UISoftKeyboardRow> &rows = pPhysicalLayout->rows();
2574 for (int i = 0; i < rows.size(); ++i)
2575 {
2576 QVector<UISoftKeyboardKey> &keys = rows[i].keys();
2577
2578 for (int j = 0; j < keys.size(); ++j)
2579 {
2580 xmlWriter.writeStartElement("key");
2581
2582 UISoftKeyboardKey &key = keys[j];
2583 xmlWriter.writeTextElement("position", QString::number(key.position()));
2584 xmlWriter.writeTextElement("basecaption", currentLayout.baseCaption(key.position()));
2585 xmlWriter.writeTextElement("shiftcaption", currentLayout.shiftCaption(key.position()));
2586 xmlWriter.writeTextElement("altgrcaption", currentLayout.altGrCaption(key.position()));
2587 xmlWriter.writeTextElement("shiftaltgrcaption", currentLayout.shiftAltGrCaption(key.position()));
2588 xmlWriter.writeEndElement();
2589 }
2590 }
2591 xmlWriter.writeEndElement();
2592 xmlWriter.writeEndDocument();
2593
2594 xmlFile.close();
2595 currentLayout.setSourceFilePath(strFileName);
2596 currentLayout.setEditedBuNotSaved(false);
2597 sigStatusBarMessage(QString("%1 %2").arg(strFileName).arg(UISoftKeyboard::tr(" is saved")));
2598}
2599
2600void UISoftKeyboardWidget::copyCurentLayout()
2601{
2602 UISoftKeyboardLayout newLayout(m_layouts[m_uCurrentLayoutId]);
2603
2604 QString strNewName = QString("%1-%2").arg(newLayout.name()).arg(UISoftKeyboard::tr("Copy"));
2605 int iCount = 1;
2606 while (layoutByNameExists(strNewName))
2607 {
2608 strNewName = QString("%1-%2-%3").arg(newLayout.name()).arg(UISoftKeyboard::tr("Copy")).arg(QString::number(iCount));
2609 ++iCount;
2610 }
2611
2612 newLayout.setName(strNewName);
2613 newLayout.setEditedBuNotSaved(true);
2614 newLayout.setEditable(true);
2615 newLayout.setIsFromResources(false);
2616 newLayout.setSourceFilePath(QString());
2617 newLayout.setUid(QUuid::createUuid());
2618 addLayout(newLayout);
2619}
2620
2621float UISoftKeyboardWidget::layoutAspectRatio()
2622{
2623 if (m_iInitialWidth == 0)
2624 return 1.f;
2625 return m_iInitialHeight / (float) m_iInitialWidth;
2626}
2627
2628bool UISoftKeyboardWidget::hideOSMenuKeys() const
2629{
2630 return m_fHideOSMenuKeys;
2631}
2632
2633void UISoftKeyboardWidget::setHideOSMenuKeys(bool fHide)
2634{
2635 if (m_fHideOSMenuKeys == fHide)
2636 return;
2637 m_fHideOSMenuKeys = fHide;
2638 update();
2639 emit sigOptionsChanged();
2640}
2641
2642bool UISoftKeyboardWidget::hideNumPad() const
2643{
2644 return m_fHideNumPad;
2645}
2646
2647void UISoftKeyboardWidget::setHideNumPad(bool fHide)
2648{
2649 if (m_fHideNumPad == fHide)
2650 return;
2651 m_fHideNumPad = fHide;
2652 update();
2653 emit sigOptionsChanged();
2654}
2655
2656bool UISoftKeyboardWidget::hideMultimediaKeys() const
2657{
2658 return m_fHideMultimediaKeys;
2659}
2660
2661void UISoftKeyboardWidget::setHideMultimediaKeys(bool fHide)
2662{
2663 if (m_fHideMultimediaKeys == fHide)
2664 return;
2665 m_fHideMultimediaKeys = fHide;
2666 update();
2667 emit sigOptionsChanged();
2668}
2669
2670QColor UISoftKeyboardWidget::color(KeyboardColorType enmColorType) const
2671{
2672 if (!m_currentColorTheme)
2673 return QColor();
2674 return m_currentColorTheme->color(enmColorType);
2675}
2676
2677void UISoftKeyboardWidget::setColor(KeyboardColorType enmColorType, const QColor &color)
2678{
2679 if (m_currentColorTheme)
2680 m_currentColorTheme->setColor(enmColorType, color);
2681 update();
2682}
2683
2684QStringList UISoftKeyboardWidget::colorsToStringList(const QString &strColorThemeName)
2685{
2686 UISoftKeyboardColorTheme *pTheme = colorTheme(strColorThemeName);
2687 if (!pTheme)
2688 return QStringList();
2689 return pTheme->colorsToStringList();
2690}
2691
2692void UISoftKeyboardWidget::colorsFromStringList(const QString &strColorThemeName, const QStringList &colorStringList)
2693{
2694 UISoftKeyboardColorTheme *pTheme = colorTheme(strColorThemeName);
2695 if (!pTheme)
2696 return;
2697 pTheme->colorsFromStringList(colorStringList);
2698}
2699
2700void UISoftKeyboardWidget::updateLockKeyStates(bool fCapsLockState, bool fNumLockState, bool fScrollLockState)
2701{
2702 for (int i = 0; i < m_physicalLayouts.size(); ++i)
2703 m_physicalLayouts[i].updateLockKeyStates(fCapsLockState, fNumLockState, fScrollLockState);
2704 update();
2705}
2706
2707QStringList UISoftKeyboardWidget::colorThemeNames() const
2708{
2709 QStringList nameList;
2710 foreach (const UISoftKeyboardColorTheme &theme, m_colorThemes)
2711 {
2712 nameList << theme.name();
2713 }
2714 return nameList;
2715}
2716
2717QString UISoftKeyboardWidget::currentColorThemeName() const
2718{
2719 if (!m_currentColorTheme)
2720 return QString();
2721 return m_currentColorTheme->name();
2722}
2723
2724void UISoftKeyboardWidget::setColorThemeByName(const QString &strColorThemeName)
2725{
2726 if (strColorThemeName.isEmpty())
2727 return;
2728 if (m_currentColorTheme && m_currentColorTheme->name() == strColorThemeName)
2729 return;
2730 for (int i = 0; i < m_colorThemes.size(); ++i)
2731 {
2732 if (m_colorThemes[i].name() == strColorThemeName)
2733 {
2734 m_currentColorTheme = &(m_colorThemes[i]);
2735 break;
2736 }
2737 }
2738 update();
2739 emit sigCurrentColorThemeChanged();
2740}
2741
2742void UISoftKeyboardWidget::parentDialogDeactivated()
2743{
2744 if (!underMouse())
2745 m_pKeyUnderMouse = 0;
2746 update();
2747}
2748
2749bool UISoftKeyboardWidget::isColorThemeEditable() const
2750{
2751 if (!m_currentColorTheme)
2752 return false;
2753 return m_currentColorTheme->isEditable();
2754}
2755
2756QStringList UISoftKeyboardWidget::unsavedLayoutsNameList() const
2757{
2758 QStringList nameList;
2759 foreach (const UISoftKeyboardLayout &layout, m_layouts)
2760 {
2761 if (layout.editedButNotSaved())
2762 nameList << layout.nameString();
2763 }
2764 return nameList;
2765}
2766
2767void UISoftKeyboardWidget::deleteCurrentLayout()
2768{
2769 if (!m_layouts.contains(m_uCurrentLayoutId))
2770 return;
2771
2772 /* Make sure we will have at least one layout remaining. */
2773 if (m_layouts.size() <= 1)
2774 return;
2775
2776 const UISoftKeyboardLayout &layout = m_layouts.value(m_uCurrentLayoutId);
2777 if (!layout.editable() || layout.isFromResources())
2778 return;
2779
2780 QDir fileToDelete;
2781 QString strFilePath(layout.sourceFilePath());
2782
2783 bool fFileExists = false;
2784 if (!strFilePath.isEmpty())
2785 fFileExists = fileToDelete.exists(strFilePath);
2786 /* It might be that the layout copied but not yet saved into a file: */
2787 if (fFileExists)
2788 {
2789 if (!msgCenter().questionBinary(this, MessageType_Question,
2790 QString(UISoftKeyboard::tr("This will delete the keyboard layout file as well. Proceed?")),
2791 0 /* auto-confirm id */,
2792 QString("Delete") /* ok button text */,
2793 QString() /* cancel button text */,
2794 false /* ok button by default? */))
2795 return;
2796
2797 if (fileToDelete.remove(strFilePath))
2798 sigStatusBarMessage(UISoftKeyboard::tr("The file %1 has been deleted").arg(strFilePath));
2799 else
2800 sigStatusBarMessage(UISoftKeyboard::tr("Deleting the file %1 has failed").arg(strFilePath));
2801 }
2802
2803 m_layouts.remove(m_uCurrentLayoutId);
2804 setCurrentLayout(m_layouts.firstKey());
2805}
2806
2807void UISoftKeyboardWidget::toggleEditMode(bool fIsEditMode)
2808{
2809 if (fIsEditMode)
2810 m_enmMode = Mode_LayoutEdit;
2811 else
2812 {
2813 m_enmMode = Mode_Keyboard;
2814 m_pKeyBeingEdited = 0;
2815 }
2816 update();
2817}
2818
2819void UISoftKeyboardWidget::addLayout(const UISoftKeyboardLayout &newLayout)
2820{
2821 if (m_layouts.contains(newLayout.uid()))
2822 return;
2823 m_layouts[newLayout.uid()] = newLayout;
2824}
2825
2826void UISoftKeyboardWidget::setNewMinimumSize(const QSize &size)
2827{
2828 m_minimumSize = size;
2829 updateGeometry();
2830}
2831
2832void UISoftKeyboardWidget::setInitialSize(int iWidth, int iHeight)
2833{
2834 m_iInitialWidth = iWidth;
2835 m_iInitialHeight = iHeight;
2836}
2837
2838UISoftKeyboardKey *UISoftKeyboardWidget::keyUnderMouse(QMouseEvent *pEvent)
2839{
2840#ifndef VBOX_IS_QT6_OR_LATER /* QMouseEvent::pos was replaced with QSinglePointEvent::position in Qt6 */
2841 const QPoint lPos = pEvent->pos();
2842#else
2843 const QPoint lPos = pEvent->position().toPoint();
2844#endif
2845 QPoint eventPosition(lPos.x() / m_fScaleFactorX, lPos.y() / m_fScaleFactorY);
2846 if (m_fHideMultimediaKeys)
2847 eventPosition.setY(eventPosition.y() + m_multiMediaKeysLayout.totalHeight());
2848 return keyUnderMouse(eventPosition);
2849}
2850
2851UISoftKeyboardKey *UISoftKeyboardWidget::keyUnderMouse(const QPoint &eventPosition)
2852{
2853 const UISoftKeyboardLayout &currentLayout = m_layouts.value(m_uCurrentLayoutId);
2854
2855 UISoftKeyboardPhysicalLayout *pPhysicalLayout = findPhysicalLayout(currentLayout.physicalLayoutUuid());
2856 if (!pPhysicalLayout)
2857 return 0;
2858
2859 UISoftKeyboardKey *pKey = 0;
2860 QVector<UISoftKeyboardRow> &rows = pPhysicalLayout->rows();
2861 for (int i = 0; i < rows.size(); ++i)
2862 {
2863 QVector<UISoftKeyboardKey> &keys = rows[i].keys();
2864 for (int j = 0; j < keys.size(); ++j)
2865 {
2866 UISoftKeyboardKey &key = keys[j];
2867 if (key.polygonInGlobal().containsPoint(eventPosition, Qt::OddEvenFill))
2868 {
2869 pKey = &key;
2870 break;
2871 }
2872 }
2873 }
2874 if (m_pKeyUnderMouse != pKey)
2875 {
2876 m_pKeyUnderMouse = pKey;
2877 update();
2878 }
2879 return pKey;
2880}
2881
2882void UISoftKeyboardWidget::handleKeyRelease(UISoftKeyboardKey *pKey)
2883{
2884 if (!pKey)
2885 return;
2886 if (pKey->type() == KeyType_Ordinary)
2887 pKey->release();
2888 /* We only send the scan codes of Ordinary keys: */
2889 if (pKey->type() == KeyType_Modifier)
2890 return;
2891
2892#if 0
2893
2894 QVector<LONG> sequence;
2895 if (!pKey->scanCodePrefix().isEmpty())
2896 sequence << pKey->scanCodePrefix();
2897 sequence << (pKey->scanCode() | 0x80);
2898
2899 /* Add the pressed modifiers in the reverse order: */
2900 for (int i = m_pressedModifiers.size() - 1; i >= 0; --i)
2901 {
2902 UISoftKeyboardKey *pModifier = m_pressedModifiers[i];
2903 if (!pModifier->scanCodePrefix().isEmpty())
2904 sequence << pModifier->scanCodePrefix();
2905 sequence << (pModifier->scanCode() | 0x80);
2906 /* Release the pressed modifiers (if there are not locked): */
2907 pModifier->release();
2908 }
2909 emit sigPutKeyboardSequence(sequence);
2910
2911#else
2912
2913 QVector<QPair<LONG, LONG> > sequence;
2914 sequence << QPair<LONG, LONG>(pKey->usagePageIdPair());
2915 /* Add the pressed modifiers in the reverse order: */
2916 for (int i = m_pressedModifiers.size() - 1; i >= 0; --i)
2917 {
2918 UISoftKeyboardKey *pModifier = m_pressedModifiers[i];
2919 sequence << pModifier->usagePageIdPair();
2920 /* Release the pressed modifiers (if there are not locked): */
2921 pModifier->release();
2922 }
2923 emit sigPutUsageCodesRelease(sequence);
2924
2925#endif
2926}
2927
2928void UISoftKeyboardWidget::handleKeyPress(UISoftKeyboardKey *pKey)
2929{
2930 if (!pKey)
2931 return;
2932 pKey->press();
2933
2934 if (pKey->type() == KeyType_Modifier)
2935 return;
2936
2937#if 0
2938 QVector<LONG> sequence;
2939 /* Add the pressed modifiers first: */
2940 for (int i = 0; i < m_pressedModifiers.size(); ++i)
2941 {
2942 UISoftKeyboardKey *pModifier = m_pressedModifiers[i];
2943 if (!pModifier->scanCodePrefix().isEmpty())
2944 sequence << pModifier->scanCodePrefix();
2945 sequence << pModifier->scanCode();
2946 }
2947
2948 if (!pKey->scanCodePrefix().isEmpty())
2949 sequence << pKey->scanCodePrefix();
2950 sequence << pKey->scanCode();
2951 emit sigPutKeyboardSequence(sequence);
2952
2953#else
2954
2955 QVector<QPair<LONG, LONG> > sequence;
2956
2957 /* Add the pressed modifiers first: */
2958 for (int i = 0; i < m_pressedModifiers.size(); ++i)
2959 {
2960 UISoftKeyboardKey *pModifier = m_pressedModifiers[i];
2961 sequence << pModifier->usagePageIdPair();
2962 }
2963
2964 sequence << pKey->usagePageIdPair();
2965 emit sigPutUsageCodesPress(sequence);
2966
2967#endif
2968}
2969
2970void UISoftKeyboardWidget::modifierKeyPressRelease(UISoftKeyboardKey *pKey, bool fRelease)
2971{
2972 if (!pKey || pKey->type() != KeyType_Modifier)
2973 return;
2974
2975 pKey->setState(KeyState_NotPressed);
2976
2977 QVector<QPair<LONG, LONG> > sequence;
2978 sequence << pKey->usagePageIdPair();
2979 if (fRelease)
2980 emit sigPutUsageCodesRelease(sequence);
2981 else
2982 emit sigPutUsageCodesPress(sequence);
2983}
2984
2985void UISoftKeyboardWidget::keyStateChange(UISoftKeyboardKey* pKey)
2986{
2987 if (!pKey)
2988 return;
2989 if (pKey->type() == KeyType_Modifier)
2990 {
2991 if (pKey->state() == KeyState_NotPressed)
2992 m_pressedModifiers.removeOne(pKey);
2993 else
2994 if (!m_pressedModifiers.contains(pKey))
2995 m_pressedModifiers.append(pKey);
2996 }
2997}
2998
2999void UISoftKeyboardWidget::setCurrentLayout(const QUuid &layoutUid)
3000{
3001 if (m_uCurrentLayoutId == layoutUid || !m_layouts.contains(layoutUid))
3002 return;
3003
3004 UISoftKeyboardPhysicalLayout *pPhysicalLayout = findPhysicalLayout(m_layouts[layoutUid].physicalLayoutUuid());
3005 if (!pPhysicalLayout)
3006 return;
3007
3008 m_uCurrentLayoutId = layoutUid;
3009 emit sigCurrentLayoutChange();
3010 update();
3011}
3012
3013UISoftKeyboardLayout *UISoftKeyboardWidget::currentLayout()
3014{
3015 if (!m_layouts.contains(m_uCurrentLayoutId))
3016 return 0;
3017 return &(m_layouts[m_uCurrentLayoutId]);
3018}
3019
3020bool UISoftKeyboardWidget::loadPhysicalLayout(const QString &strLayoutFileName, KeyboardRegion keyboardRegion /* = KeyboardRegion_Main */)
3021{
3022 if (strLayoutFileName.isEmpty())
3023 return false;
3024 UIPhysicalLayoutReader reader;
3025 UISoftKeyboardPhysicalLayout *newPhysicalLayout = 0;
3026 if (keyboardRegion == KeyboardRegion_Main)
3027 {
3028 m_physicalLayouts.append(UISoftKeyboardPhysicalLayout());
3029 newPhysicalLayout = &(m_physicalLayouts.back());
3030 }
3031 else if (keyboardRegion == KeyboardRegion_NumPad)
3032 newPhysicalLayout = &(m_numPadLayout);
3033 else if (keyboardRegion == KeyboardRegion_MultimediaKeys)
3034 newPhysicalLayout = &(m_multiMediaKeysLayout);
3035 else
3036 return false;
3037
3038 if (!reader.parseXMLFile(strLayoutFileName, *newPhysicalLayout))
3039 {
3040 m_physicalLayouts.removeLast();
3041 return false;
3042 }
3043
3044 for (int i = 0; i < newPhysicalLayout->rows().size(); ++i)
3045 {
3046 UISoftKeyboardRow &row = newPhysicalLayout->rows()[i];
3047 for (int j = 0; j < row.keys().size(); ++j)
3048 row.keys()[j].setKeyboardRegion(keyboardRegion);
3049 }
3050
3051 if (keyboardRegion == KeyboardRegion_NumPad || keyboardRegion == KeyboardRegion_MultimediaKeys)
3052 return true;
3053
3054 /* Go thru all the keys row by row and construct their geometries: */
3055 int iY = m_iTopMargin;
3056 int iMaxWidth = 0;
3057 int iMaxWidthNoNumPad = 0;
3058 const QVector<UISoftKeyboardRow> &numPadRows = m_numPadLayout.rows();
3059 QVector<UISoftKeyboardRow> &rows = newPhysicalLayout->rows();
3060
3061 /* Prepend the multimedia rows to the layout */
3062 const QVector<UISoftKeyboardRow> &multimediaRows = m_multiMediaKeysLayout.rows();
3063 for (int i = multimediaRows.size() - 1; i >= 0; --i)
3064 rows.prepend(multimediaRows[i]);
3065
3066 for (int i = 0; i < rows.size(); ++i)
3067 {
3068 UISoftKeyboardRow &row = rows[i];
3069 /* Insert the numpad rows at the end of keyboard rows starting with appending 0th numpad row to the
3070 end of (1 + multimediaRows.size())th layout row: */
3071 if (i > multimediaRows.size())
3072 {
3073 int iNumPadRowIndex = i - (1 + multimediaRows.size());
3074 if (iNumPadRowIndex >= 0 && iNumPadRowIndex < numPadRows.size())
3075 {
3076 for (int m = 0; m < numPadRows[iNumPadRowIndex].keys().size(); ++m)
3077 row.keys().append(numPadRows[iNumPadRowIndex].keys()[m]);
3078 }
3079 }
3080
3081 int iX = m_iLeftMargin + row.leftMargin();
3082 int iXNoNumPad = m_iLeftMargin;
3083 int iRowHeight = row.defaultHeight();
3084 int iKeyWidth = 0;
3085 for (int j = 0; j < row.keys().size(); ++j)
3086 {
3087 UISoftKeyboardKey &key = (row.keys())[j];
3088 if (key.position() == iScrollLockPosition ||
3089 key.position() == iNumLockPosition ||
3090 key.position() == iCapsLockPosition)
3091 newPhysicalLayout->setLockKey(key.position(), &key);
3092
3093 if (key.keyboardRegion() == KeyboardRegion_NumPad)
3094 key.setKeyGeometry(QRect(iX + m_iBeforeNumPadWidth, iY, key.width(), key.height()));
3095 else
3096 key.setKeyGeometry(QRect(iX, iY, key.width(), key.height()));
3097
3098 key.setCornerRadius(0.1 * newPhysicalLayout->defaultKeyWidth());
3099 key.setPoints(UIPhysicalLayoutReader::computeKeyVertices(key));
3100 key.setParentWidget(this);
3101
3102 iKeyWidth = key.width();
3103 if (j < row.keys().size() - 1)
3104 iKeyWidth += m_iXSpacing;
3105 if (key.spaceWidthAfter() != 0 && j != row.keys().size() - 1)
3106 iKeyWidth += (m_iXSpacing + key.spaceWidthAfter());
3107
3108 iX += iKeyWidth;
3109 if (key.keyboardRegion() != KeyboardRegion_NumPad)
3110 iXNoNumPad += iKeyWidth;
3111 }
3112 if (row.spaceHeightAfter() != 0)
3113 iY += row.spaceHeightAfter() + m_iYSpacing;
3114 iMaxWidth = qMax(iMaxWidth, iX);
3115 iMaxWidthNoNumPad = qMax(iMaxWidthNoNumPad, iXNoNumPad);
3116
3117 iY += iRowHeight;
3118 if (i < rows.size() - 1)
3119 iY += m_iYSpacing;
3120 }
3121 int iInitialWidth = iMaxWidth + m_iRightMargin;
3122 int iInitialWidthNoNumPad = iMaxWidthNoNumPad + m_iRightMargin;
3123 int iInitialHeight = iY + m_iBottomMargin;
3124 m_iInitialWidth = qMax(m_iInitialWidth, iInitialWidth);
3125 m_iInitialWidthNoNumPad = qMax(m_iInitialWidthNoNumPad, iInitialWidthNoNumPad);
3126 m_iInitialHeight = qMax(m_iInitialHeight, iInitialHeight);
3127 return true;
3128}
3129
3130bool UISoftKeyboardWidget::loadKeyboardLayout(const QString &strLayoutFileName)
3131{
3132 if (strLayoutFileName.isEmpty())
3133 return false;
3134
3135 UIKeyboardLayoutReader keyboardLayoutReader;
3136
3137 UISoftKeyboardLayout newLayout;
3138 if (!keyboardLayoutReader.parseFile(strLayoutFileName, newLayout))
3139 return false;
3140
3141 UISoftKeyboardPhysicalLayout *pPhysicalLayout = findPhysicalLayout(newLayout.physicalLayoutUuid());
3142 /* If no pyhsical layout with the UUID the keyboard layout refers is found then cancel loading the keyboard layout: */
3143 if (!pPhysicalLayout)
3144 return false;
3145
3146 /* Make sure we have unique lay1out UUIDs: */
3147 int iCount = 0;
3148 foreach (const UISoftKeyboardLayout &layout, m_layouts)
3149 {
3150 if (layout.uid() == newLayout.uid())
3151 ++iCount;
3152 }
3153 if (iCount > 1)
3154 return false;
3155
3156 newLayout.setSourceFilePath(strLayoutFileName);
3157 addLayout(newLayout);
3158 return true;
3159}
3160
3161UISoftKeyboardPhysicalLayout *UISoftKeyboardWidget::findPhysicalLayout(const QUuid &uuid)
3162{
3163 for (int i = 0; i < m_physicalLayouts.size(); ++i)
3164 {
3165 if (m_physicalLayouts[i].uid() == uuid)
3166 return &(m_physicalLayouts[i]);
3167 }
3168 return 0;
3169}
3170
3171void UISoftKeyboardWidget::reset()
3172{
3173 m_pressedModifiers.clear();
3174 m_pKeyUnderMouse = 0;
3175 m_pKeyBeingEdited = 0;
3176 m_pKeyPressed = 0;
3177 m_enmMode = Mode_Keyboard;
3178
3179 for (int i = 0; i < m_physicalLayouts.size(); ++i)
3180 m_physicalLayouts[i].reset();
3181}
3182
3183void UISoftKeyboardWidget::loadLayouts()
3184{
3185 /* Load physical layouts from resources: Numpad and multimedia layout files should be read first
3186 since we insert these to other layouts: */
3187 loadPhysicalLayout(":/numpad.xml", KeyboardRegion_NumPad);
3188 loadPhysicalLayout(":/multimedia_keys.xml", KeyboardRegion_MultimediaKeys);
3189 QStringList physicalLayoutNames;
3190 physicalLayoutNames << ":/101_ansi.xml"
3191 << ":/102_iso.xml"
3192 << ":/106_japanese.xml"
3193 << ":/103_iso.xml"
3194 << ":/103_ansi.xml";
3195 foreach (const QString &strName, physicalLayoutNames)
3196 loadPhysicalLayout(strName);
3197
3198 setNewMinimumSize(QSize(m_iInitialWidth, m_iInitialHeight));
3199 setInitialSize(m_iInitialWidth, m_iInitialHeight);
3200
3201 /* Add keyboard layouts from resources: */
3202 QStringList keyboardLayoutNames;
3203 keyboardLayoutNames << ":/us_international.xml"
3204 << ":/german.xml"
3205 << ":/us.xml"
3206 << ":/greek.xml"
3207 << ":/japanese.xml"
3208 << ":/brazilian.xml"
3209 << ":/korean.xml";
3210
3211 foreach (const QString &strName, keyboardLayoutNames)
3212 loadKeyboardLayout(strName);
3213 /* Mark the layouts we load from the resources as non-editable: */
3214 for (QMap<QUuid, UISoftKeyboardLayout>::iterator iterator = m_layouts.begin(); iterator != m_layouts.end(); ++iterator)
3215 {
3216 iterator.value().setEditable(false);
3217 iterator.value().setIsFromResources(true);
3218 }
3219 keyboardLayoutNames.clear();
3220 /* Add keyboard layouts from the defalt keyboard layout folder: */
3221 lookAtDefaultLayoutFolder(keyboardLayoutNames);
3222 foreach (const QString &strName, keyboardLayoutNames)
3223 loadKeyboardLayout(strName);
3224
3225 if (m_layouts.isEmpty())
3226 return;
3227 for (QMap<QUuid, UISoftKeyboardLayout>::iterator iterator = m_layouts.begin(); iterator != m_layouts.end(); ++iterator)
3228 iterator.value().setEditedBuNotSaved(false);
3229 /* Block sigCurrentLayoutChange since it causes saving set layout to exra data: */
3230 blockSignals(true);
3231 setCurrentLayout(m_layouts.firstKey());
3232 blockSignals(false);
3233}
3234
3235void UISoftKeyboardWidget::prepareObjects()
3236{
3237 setMouseTracking(true);
3238}
3239
3240void UISoftKeyboardWidget::prepareColorThemes()
3241{
3242 int iIndex = 0;
3243 while (predefinedColorThemes[iIndex][0])
3244 {
3245 m_colorThemes << UISoftKeyboardColorTheme(predefinedColorThemes[iIndex][0],
3246 predefinedColorThemes[iIndex][1],
3247 predefinedColorThemes[iIndex][2],
3248 predefinedColorThemes[iIndex][3],
3249 predefinedColorThemes[iIndex][4],
3250 predefinedColorThemes[iIndex][5]);
3251 ++iIndex;
3252 }
3253
3254 UISoftKeyboardColorTheme customTheme;
3255 customTheme.setName("Custom");
3256 customTheme.setIsEditable(true);
3257 m_colorThemes.append(customTheme);
3258 m_currentColorTheme = &(m_colorThemes.back());
3259}
3260
3261void UISoftKeyboardWidget::setKeyBeingEdited(UISoftKeyboardKey* pKey)
3262{
3263 if (m_pKeyBeingEdited == pKey)
3264 return;
3265 m_pKeyBeingEdited = pKey;
3266 emit sigKeyToEdit(pKey);
3267}
3268
3269bool UISoftKeyboardWidget::layoutByNameExists(const QString &strName) const
3270{
3271 foreach (const UISoftKeyboardLayout &layout, m_layouts)
3272 {
3273 if (layout.name() == strName)
3274 return true;
3275 }
3276 return false;
3277}
3278
3279void UISoftKeyboardWidget::lookAtDefaultLayoutFolder(QStringList &fileList)
3280{
3281 QString strFolder = QString("%1%2%3").arg(uiCommon().homeFolder()).arg(QDir::separator()).arg(strSubDirectorName);
3282 QDir dir(strFolder);
3283 if (!dir.exists())
3284 return;
3285 QStringList filters;
3286 filters << "*.xml";
3287 dir.setNameFilters(filters);
3288 QFileInfoList fileInfoList = dir.entryInfoList();
3289 foreach (const QFileInfo &fileInfo, fileInfoList)
3290 fileList << fileInfo.absoluteFilePath();
3291}
3292
3293UISoftKeyboardColorTheme *UISoftKeyboardWidget::colorTheme(const QString &strColorThemeName)
3294{
3295 for (int i = 0; i < m_colorThemes.size(); ++i)
3296 {
3297 if (m_colorThemes[i].name() == strColorThemeName)
3298 return &(m_colorThemes[i]);
3299 }
3300 return 0;
3301}
3302
3303void UISoftKeyboardWidget::showKeyTooltip(UISoftKeyboardKey *pKey)
3304{
3305 if (pKey && m_keyTooltips.contains(pKey->position()))
3306 sigStatusBarMessage(m_keyTooltips[pKey->position()]);
3307 else
3308 sigStatusBarMessage(QString());
3309
3310}
3311
3312QStringList UISoftKeyboardWidget::layoutNameList() const
3313{
3314 QStringList layoutNames;
3315 foreach (const UISoftKeyboardLayout &layout, m_layouts)
3316 layoutNames << layout.nameString();
3317 return layoutNames;
3318}
3319
3320QList<QUuid> UISoftKeyboardWidget::layoutUidList() const
3321{
3322 QList<QUuid> layoutUids;
3323 foreach (const UISoftKeyboardLayout &layout, m_layouts)
3324 layoutUids << layout.uid();
3325 return layoutUids;
3326}
3327
3328const QVector<UISoftKeyboardPhysicalLayout> &UISoftKeyboardWidget::physicalLayouts() const
3329{
3330 return m_physicalLayouts;
3331}
3332
3333/*********************************************************************************************************************************
3334* UIPhysicalLayoutReader implementation. *
3335*********************************************************************************************************************************/
3336
3337bool UIPhysicalLayoutReader::parseXMLFile(const QString &strFileName, UISoftKeyboardPhysicalLayout &physicalLayout)
3338{
3339 QFile xmlFile(strFileName);
3340 if (!xmlFile.exists())
3341 return false;
3342
3343 if (xmlFile.size() >= iFileSizeLimit)
3344 return false;
3345
3346 if (!xmlFile.open(QIODevice::ReadOnly))
3347 return false;
3348
3349 m_xmlReader.setDevice(&xmlFile);
3350
3351 if (!m_xmlReader.readNextStartElement() || m_xmlReader.name() != QLatin1String("physicallayout"))
3352 return false;
3353 physicalLayout.setFileName(strFileName);
3354
3355 QXmlStreamAttributes attributes = m_xmlReader.attributes();
3356 int iDefaultWidth = attributes.value("defaultWidth").toInt();
3357 int iDefaultHeight = attributes.value("defaultHeight").toInt();
3358 QVector<UISoftKeyboardRow> &rows = physicalLayout.rows();
3359 physicalLayout.setDefaultKeyWidth(iDefaultWidth);
3360
3361 while (m_xmlReader.readNextStartElement())
3362 {
3363 if (m_xmlReader.name() == QLatin1String("row"))
3364 parseRow(iDefaultWidth, iDefaultHeight, rows);
3365 else if (m_xmlReader.name() == QLatin1String("name"))
3366 physicalLayout.setName(m_xmlReader.readElementText());
3367 else if (m_xmlReader.name() == QLatin1String("id"))
3368 physicalLayout.setUid(QUuid(m_xmlReader.readElementText()));
3369 else
3370 m_xmlReader.skipCurrentElement();
3371 }
3372
3373 return true;
3374}
3375
3376void UIPhysicalLayoutReader::parseRow(int iDefaultWidth, int iDefaultHeight, QVector<UISoftKeyboardRow> &rows)
3377{
3378 rows.append(UISoftKeyboardRow());
3379 UISoftKeyboardRow &row = rows.back();
3380
3381 row.setDefaultWidth(iDefaultWidth);
3382 row.setDefaultHeight(iDefaultHeight);
3383 row.setSpaceHeightAfter(0);
3384
3385 /* Override the layout attributes if the row also has them: */
3386 QXmlStreamAttributes attributes = m_xmlReader.attributes();
3387 if (attributes.hasAttribute("defaultWidth"))
3388 row.setDefaultWidth(attributes.value("defaultWidth").toInt());
3389 if (attributes.hasAttribute("defaultHeight"))
3390 row.setDefaultHeight(attributes.value("defaultHeight").toInt());
3391 while (m_xmlReader.readNextStartElement())
3392 {
3393 if (m_xmlReader.name() == QLatin1String("key"))
3394 parseKey(row);
3395 else if (m_xmlReader.name() == QLatin1String("space"))
3396 parseKeySpace(row);
3397 else
3398 m_xmlReader.skipCurrentElement();
3399 }
3400}
3401
3402void UIPhysicalLayoutReader::parseKey(UISoftKeyboardRow &row)
3403{
3404 row.keys().append(UISoftKeyboardKey());
3405 UISoftKeyboardKey &key = row.keys().back();
3406 key.setWidth(row.defaultWidth());
3407 key.setHeight(row.defaultHeight());
3408 QString strKeyCap;
3409 while (m_xmlReader.readNextStartElement())
3410 {
3411 if (m_xmlReader.name() == QLatin1String("width"))
3412 key.setWidth(m_xmlReader.readElementText().toInt());
3413 else if (m_xmlReader.name() == QLatin1String("height"))
3414 key.setHeight(m_xmlReader.readElementText().toInt());
3415 else if (m_xmlReader.name() == QLatin1String("scancode"))
3416 {
3417 QString strCode = m_xmlReader.readElementText();
3418 bool fOk = false;
3419 key.setScanCode(strCode.toInt(&fOk, 16));
3420 }
3421 else if (m_xmlReader.name() == QLatin1String("scancodeprefix"))
3422 {
3423 QString strCode = m_xmlReader.readElementText();
3424 QStringList strList;
3425#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
3426 strList << strCode.split('-', Qt::SkipEmptyParts);
3427#else
3428 strList << strCode.split('-', QString::SkipEmptyParts);
3429#endif
3430 foreach (const QString &strPrefix, strList)
3431 {
3432 bool fOk = false;
3433 LONG iCode = strPrefix.toInt(&fOk, 16);
3434 if (fOk)
3435 key.addScanCodePrefix(iCode);
3436 }
3437 }
3438 else if (m_xmlReader.name() == QLatin1String("usageid"))
3439 {
3440 QString strCode = m_xmlReader.readElementText();
3441 bool fOk = false;
3442 key.setUsageId(strCode.toInt(&fOk, 16));
3443 }
3444 else if (m_xmlReader.name() == QLatin1String("usagepage"))
3445 {
3446 QString strCode = m_xmlReader.readElementText();
3447 bool fOk = false;
3448 key.setUsagePage(strCode.toInt(&fOk, 16));
3449 }
3450 else if (m_xmlReader.name() == QLatin1String("cutout"))
3451 parseCutout(key);
3452 else if (m_xmlReader.name() == QLatin1String("position"))
3453 key.setPosition(m_xmlReader.readElementText().toInt());
3454 else if (m_xmlReader.name() == QLatin1String("type"))
3455 {
3456 QString strType = m_xmlReader.readElementText();
3457 if (strType == "modifier")
3458 key.setType(KeyType_Modifier);
3459 else if (strType == "lock")
3460 key.setType(KeyType_Lock);
3461 }
3462 else if (m_xmlReader.name() == QLatin1String("osmenukey"))
3463 {
3464 if (m_xmlReader.readElementText() == "true")
3465 key.setIsOSMenuKey(true);
3466 }
3467 else if (m_xmlReader.name() == QLatin1String("staticcaption"))
3468 key.setStaticCaption(m_xmlReader.readElementText());
3469 else if (m_xmlReader.name() == QLatin1String("image"))
3470 key.setImageByName(m_xmlReader.readElementText());
3471 else
3472 m_xmlReader.skipCurrentElement();
3473 }
3474}
3475
3476void UIPhysicalLayoutReader::parseKeySpace(UISoftKeyboardRow &row)
3477{
3478 int iWidth = row.defaultWidth();
3479 int iHeight = 0;
3480 while (m_xmlReader.readNextStartElement())
3481 {
3482 if (m_xmlReader.name() == QLatin1String("width"))
3483 iWidth = m_xmlReader.readElementText().toInt();
3484 else if (m_xmlReader.name() == QLatin1String("height"))
3485 iHeight = m_xmlReader.readElementText().toInt();
3486 else
3487 m_xmlReader.skipCurrentElement();
3488 }
3489 row.setSpaceHeightAfter(iHeight);
3490 /* If we have keys add the parsed space to the last key as the 'space after': */
3491 if (!row.keys().empty())
3492 row.keys().back().setSpaceWidthAfter(iWidth);
3493 /* If we have no keys than this is the initial space left to first key: */
3494 else
3495 row.setLeftMargin(iWidth);
3496}
3497
3498void UIPhysicalLayoutReader::parseCutout(UISoftKeyboardKey &key)
3499{
3500 int iWidth = 0;
3501 int iHeight = 0;
3502 int iCorner = 0;
3503 while (m_xmlReader.readNextStartElement())
3504 {
3505 if (m_xmlReader.name() == QLatin1String("width"))
3506 iWidth = m_xmlReader.readElementText().toInt();
3507 else if (m_xmlReader.name() == QLatin1String("height"))
3508 iHeight = m_xmlReader.readElementText().toInt();
3509 else if (m_xmlReader.name() == QLatin1String("corner"))
3510 {
3511 QString strCorner = m_xmlReader.readElementText();
3512 if (strCorner == "topLeft")
3513 iCorner = 0;
3514 else if(strCorner == "topRight")
3515 iCorner = 1;
3516 else if(strCorner == "bottomRight")
3517 iCorner = 2;
3518 else if(strCorner == "bottomLeft")
3519 iCorner = 3;
3520 }
3521 else
3522 m_xmlReader.skipCurrentElement();
3523 }
3524 key.setCutout(iCorner, iWidth, iHeight);
3525}
3526
3527QVector<QPointF> UIPhysicalLayoutReader::computeKeyVertices(const UISoftKeyboardKey &key)
3528{
3529 QVector<QPointF> vertices;
3530
3531 if (key.cutoutCorner() == -1 || key.width() <= key.cutoutWidth() || key.height() <= key.cutoutHeight())
3532 {
3533 vertices.append(QPoint(0, 0));
3534 vertices.append(QPoint(key.width(), 0));
3535 vertices.append(QPoint(key.width(), key.height()));
3536 vertices.append(QPoint(0, key.height()));
3537 return vertices;
3538 }
3539 if (key.cutoutCorner() == 0)
3540 {
3541 vertices.append(QPoint(key.cutoutWidth(), 0));
3542 vertices.append(QPoint(key.width(), 0));
3543 vertices.append(QPoint(key.width(), key.height()));
3544 vertices.append(QPoint(0, key.height()));
3545 vertices.append(QPoint(0, key.cutoutHeight()));
3546 vertices.append(QPoint(key.cutoutWidth(), key.cutoutHeight()));
3547 }
3548 else if (key.cutoutCorner() == 1)
3549 {
3550 vertices.append(QPoint(0, 0));
3551 vertices.append(QPoint(key.width() - key.cutoutWidth(), 0));
3552 vertices.append(QPoint(key.width() - key.cutoutWidth(), key.cutoutHeight()));
3553 vertices.append(QPoint(key.width(), key.cutoutHeight()));
3554 vertices.append(QPoint(key.width(), key.height()));
3555 vertices.append(QPoint(0, key.height()));
3556 }
3557 else if (key.cutoutCorner() == 2)
3558 {
3559 vertices.append(QPoint(0, 0));
3560 vertices.append(QPoint(key.width(), 0));
3561 vertices.append(QPoint(key.width(), key.cutoutHeight()));
3562 vertices.append(QPoint(key.width() - key.cutoutWidth(), key.cutoutHeight()));
3563 vertices.append(QPoint(key.width() - key.cutoutWidth(), key.height()));
3564 vertices.append(QPoint(0, key.height()));
3565 }
3566 else if (key.cutoutCorner() == 3)
3567 {
3568 vertices.append(QPoint(0, 0));
3569 vertices.append(QPoint(key.width(), 0));
3570 vertices.append(QPoint(key.width(), key.height()));
3571 vertices.append(QPoint(key.cutoutWidth(), key.height()));
3572 vertices.append(QPoint(key.cutoutWidth(), key.height() - key.cutoutHeight()));
3573 vertices.append(QPoint(0, key.height() - key.cutoutHeight()));
3574 }
3575 return vertices;
3576}
3577
3578
3579/*********************************************************************************************************************************
3580* UIKeyboardLayoutReader implementation. *
3581*********************************************************************************************************************************/
3582
3583bool UIKeyboardLayoutReader::parseFile(const QString &strFileName, UISoftKeyboardLayout &layout)
3584{
3585 QFile xmlFile(strFileName);
3586 if (!xmlFile.exists())
3587 return false;
3588
3589 if (xmlFile.size() >= iFileSizeLimit)
3590 return false;
3591
3592 if (!xmlFile.open(QIODevice::ReadOnly))
3593 return false;
3594
3595 m_xmlReader.setDevice(&xmlFile);
3596
3597 if (!m_xmlReader.readNextStartElement() || m_xmlReader.name() != QLatin1String("layout"))
3598 return false;
3599
3600 while (m_xmlReader.readNextStartElement())
3601 {
3602 if (m_xmlReader.name() == QLatin1String("key"))
3603 parseKey(layout);
3604 else if (m_xmlReader.name() == QLatin1String("name"))
3605 layout.setName(m_xmlReader.readElementText());
3606 else if (m_xmlReader.name() == QLatin1String("nativename"))
3607 layout.setNativeName(m_xmlReader.readElementText());
3608 else if (m_xmlReader.name() == QLatin1String("physicallayoutid"))
3609 layout.setPhysicalLayoutUuid(QUuid(m_xmlReader.readElementText()));
3610 else if (m_xmlReader.name() == QLatin1String("id"))
3611 layout.setUid(QUuid(m_xmlReader.readElementText()));
3612 else
3613 m_xmlReader.skipCurrentElement();
3614 }
3615 return true;
3616}
3617
3618void UIKeyboardLayoutReader::parseKey(UISoftKeyboardLayout &layout)
3619{
3620 UIKeyCaptions keyCaptions;
3621 int iKeyPosition = 0;
3622 while (m_xmlReader.readNextStartElement())
3623 {
3624 if (m_xmlReader.name() == QLatin1String("basecaption"))
3625 {
3626 keyCaptions.m_strBase = m_xmlReader.readElementText();
3627 keyCaptions.m_strBase.replace("\\n", "\n");
3628 }
3629 else if (m_xmlReader.name() == QLatin1String("shiftcaption"))
3630 {
3631 keyCaptions.m_strShift = m_xmlReader.readElementText();
3632 keyCaptions.m_strShift.replace("\\n", "\n");
3633 }
3634 else if (m_xmlReader.name() == QLatin1String("altgrcaption"))
3635 {
3636 keyCaptions.m_strAltGr = m_xmlReader.readElementText();
3637 keyCaptions.m_strAltGr.replace("\\n", "\n");
3638 }
3639 else if (m_xmlReader.name() == QLatin1String("shiftaltgrcaption"))
3640 {
3641 keyCaptions.m_strShiftAltGr = m_xmlReader.readElementText();
3642 keyCaptions.m_strShiftAltGr.replace("\\n", "\n");
3643 }
3644 else if (m_xmlReader.name() == QLatin1String("position"))
3645 iKeyPosition = m_xmlReader.readElementText().toInt();
3646 else
3647 m_xmlReader.skipCurrentElement();
3648 }
3649 layout.addOrUpdateUIKeyCaptions(iKeyPosition, keyCaptions);
3650}
3651
3652
3653/*********************************************************************************************************************************
3654* UISoftKeyboardStatusBarWidget implementation. *
3655*********************************************************************************************************************************/
3656
3657UISoftKeyboardStatusBarWidget::UISoftKeyboardStatusBarWidget(QWidget *pParent /* = 0*/ )
3658 : QIWithRetranslateUI<QWidget>(pParent)
3659 , m_pLayoutListButton(0)
3660 , m_pSettingsButton(0)
3661 , m_pResetButton(0)
3662 , m_pHelpButton(0)
3663 , m_pMessageLabel(0)
3664{
3665 prepareObjects();
3666}
3667
3668void UISoftKeyboardStatusBarWidget::retranslateUi()
3669{
3670 if (m_pLayoutListButton)
3671 m_pLayoutListButton->setToolTip(UISoftKeyboard::tr("Layout List"));
3672 if (m_pSettingsButton)
3673 m_pSettingsButton->setToolTip(UISoftKeyboard::tr("Settings"));
3674 if (m_pResetButton)
3675 m_pResetButton->setToolTip(UISoftKeyboard::tr("Reset the keyboard and release all keys"));
3676 if (m_pHelpButton)
3677 m_pHelpButton->setToolTip(UISoftKeyboard::tr("Help"));
3678}
3679
3680void UISoftKeyboardStatusBarWidget::prepareObjects()
3681{
3682 QHBoxLayout *pLayout = new QHBoxLayout;
3683 if (!pLayout)
3684 return;
3685 pLayout->setContentsMargins(0, 0, 0, 0);
3686 setLayout(pLayout);
3687
3688 m_pMessageLabel = new QLabel;
3689 pLayout->addWidget(m_pMessageLabel);
3690
3691 m_pLayoutListButton = new QToolButton;
3692 if (m_pLayoutListButton)
3693 {
3694 m_pLayoutListButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_layout_list_16px.png", ":/soft_keyboard_layout_list_disabled_16px.png"));
3695 m_pLayoutListButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
3696 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
3697 m_pLayoutListButton->resize(QSize(iIconMetric, iIconMetric));
3698 m_pLayoutListButton->setStyleSheet("QToolButton { border: 0px none black; margin: 0px 0px 0px 0px; } QToolButton::menu-indicator {image: none;}");
3699 connect(m_pLayoutListButton, &QToolButton::clicked, this, &UISoftKeyboardStatusBarWidget::sigShowHideSidePanel);
3700 pLayout->addWidget(m_pLayoutListButton);
3701 }
3702
3703 m_pSettingsButton = new QToolButton;
3704 if (m_pSettingsButton)
3705 {
3706 m_pSettingsButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_settings_16px.png", ":/soft_keyboard_settings_disabled_16px.png"));
3707 m_pSettingsButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
3708 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
3709 m_pSettingsButton->resize(QSize(iIconMetric, iIconMetric));
3710 m_pSettingsButton->setStyleSheet("QToolButton { border: 0px none black; margin: 0px 0px 0px 0px; } QToolButton::menu-indicator {image: none;}");
3711 connect(m_pSettingsButton, &QToolButton::clicked, this, &UISoftKeyboardStatusBarWidget::sigShowSettingWidget);
3712 pLayout->addWidget(m_pSettingsButton);
3713 }
3714
3715 m_pResetButton = new QToolButton;
3716 if (m_pResetButton)
3717 {
3718 m_pResetButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_reset_16px.png"));
3719 m_pResetButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
3720 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
3721 m_pResetButton->resize(QSize(iIconMetric, iIconMetric));
3722 m_pResetButton->setStyleSheet("QToolButton { border: 0px none black; margin: 0px 0px 0px 0px; } QToolButton::menu-indicator {image: none;}");
3723 connect(m_pResetButton, &QToolButton::clicked, this, &UISoftKeyboardStatusBarWidget::sigResetKeyboard);
3724 pLayout->addWidget(m_pResetButton);
3725 }
3726
3727 m_pHelpButton = new QToolButton;
3728 if (m_pHelpButton)
3729 {
3730 m_pHelpButton->setIcon(UIIconPool::iconSet(":/soft_keyboard_help_16px.png"));
3731 m_pHelpButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
3732 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
3733 m_pHelpButton->resize(QSize(iIconMetric, iIconMetric));
3734 m_pHelpButton->setStyleSheet("QToolButton { border: 0px none black; margin: 0px 0px 0px 0px; } QToolButton::menu-indicator {image: none;}");
3735 connect(m_pHelpButton, &QToolButton::clicked, this, &UISoftKeyboardStatusBarWidget::sigHelpButtonPressed);
3736 pLayout->addWidget(m_pHelpButton);
3737 }
3738
3739 retranslateUi();
3740}
3741
3742void UISoftKeyboardStatusBarWidget::updateLayoutNameInStatusBar(const QString &strMessage)
3743{
3744 if (!m_pMessageLabel)
3745 return;
3746 m_pMessageLabel->setText(strMessage);
3747}
3748
3749
3750/*********************************************************************************************************************************
3751* UISoftKeyboardSettingsWidget implementation. *
3752*********************************************************************************************************************************/
3753
3754UISoftKeyboardSettingsWidget::UISoftKeyboardSettingsWidget(QWidget *pParent /* = 0 */)
3755 : QIWithRetranslateUI<QWidget>(pParent)
3756 , m_pHideNumPadCheckBox(0)
3757 , m_pShowOsMenuButtonsCheckBox(0)
3758 , m_pHideMultimediaKeysCheckBox(0)
3759 , m_pColorThemeGroupBox(0)
3760 , m_pColorThemeComboBox(0)
3761 , m_pTitleLabel(0)
3762 , m_pCloseButton(0)
3763
3764{
3765 prepareObjects();
3766}
3767
3768void UISoftKeyboardSettingsWidget::setHideOSMenuKeys(bool fHide)
3769{
3770 if (m_pShowOsMenuButtonsCheckBox)
3771 m_pShowOsMenuButtonsCheckBox->setChecked(fHide);
3772}
3773
3774void UISoftKeyboardSettingsWidget::setHideNumPad(bool fHide)
3775{
3776 if (m_pHideNumPadCheckBox)
3777 m_pHideNumPadCheckBox->setChecked(fHide);
3778}
3779
3780void UISoftKeyboardSettingsWidget::setHideMultimediaKeys(bool fHide)
3781{
3782 if (m_pHideMultimediaKeysCheckBox)
3783 m_pHideMultimediaKeysCheckBox->setChecked(fHide);
3784}
3785
3786void UISoftKeyboardSettingsWidget::setColorSelectionButtonBackgroundAndTooltip(KeyboardColorType enmColorType,
3787 const QColor &color, bool fIsColorEditable)
3788{
3789 if (m_colorSelectLabelsButtons.size() > enmColorType && m_colorSelectLabelsButtons[enmColorType].second)
3790 {
3791 UISoftKeyboardColorButton *pButton = m_colorSelectLabelsButtons[enmColorType].second;
3792 QPalette pal = pButton->palette();
3793 pal.setColor(QPalette::Button, color);
3794 pButton->setAutoFillBackground(true);
3795 pButton->setPalette(pal);
3796 pButton->setToolTip(fIsColorEditable ? UISoftKeyboard::tr("Click to change the color.") : UISoftKeyboard::tr("This color theme is not editable."));
3797 pButton->update();
3798 }
3799}
3800
3801void UISoftKeyboardSettingsWidget::setColorThemeNames(const QStringList &colorThemeNames)
3802{
3803 if (!m_pColorThemeComboBox)
3804 return;
3805 m_pColorThemeComboBox->blockSignals(true);
3806 m_pColorThemeComboBox->clear();
3807 foreach (const QString &strName, colorThemeNames)
3808 m_pColorThemeComboBox->addItem(strName);
3809 m_pColorThemeComboBox->blockSignals(false);
3810}
3811
3812void UISoftKeyboardSettingsWidget::setCurrentColorThemeName(const QString &strColorThemeName)
3813{
3814 if (!m_pColorThemeComboBox)
3815 return;
3816 int iItemIndex = m_pColorThemeComboBox->findText(strColorThemeName, Qt::MatchFixedString);
3817 if (iItemIndex == -1)
3818 return;
3819 m_pColorThemeComboBox->blockSignals(true);
3820 m_pColorThemeComboBox->setCurrentIndex(iItemIndex);
3821 m_pColorThemeComboBox->blockSignals(false);
3822}
3823
3824void UISoftKeyboardSettingsWidget::retranslateUi()
3825{
3826 if (m_pTitleLabel)
3827 m_pTitleLabel->setText(UISoftKeyboard::tr("Keyboard Settings"));
3828 if (m_pCloseButton)
3829 {
3830 m_pCloseButton->setToolTip(UISoftKeyboard::tr("Close the layout list"));
3831 m_pCloseButton->setText("Close");
3832 }
3833 if (m_pHideNumPadCheckBox)
3834 m_pHideNumPadCheckBox->setText(UISoftKeyboard::tr("Hide NumPad"));
3835 if (m_pShowOsMenuButtonsCheckBox)
3836 m_pShowOsMenuButtonsCheckBox->setText(UISoftKeyboard::tr("Hide OS/Menu Keys"));
3837 if (m_pHideMultimediaKeysCheckBox)
3838 m_pHideMultimediaKeysCheckBox->setText(UISoftKeyboard::tr("Hide Multimedia Keys"));
3839 if (m_pColorThemeGroupBox)
3840 m_pColorThemeGroupBox->setTitle(UISoftKeyboard::tr("Color Themes"));
3841
3842 if (m_colorSelectLabelsButtons.size() == KeyboardColorType_Max)
3843 {
3844 if (m_colorSelectLabelsButtons[KeyboardColorType_Background].first)
3845 m_colorSelectLabelsButtons[KeyboardColorType_Background].first->setText(UISoftKeyboard::tr("Button Background Color"));
3846 if (m_colorSelectLabelsButtons[KeyboardColorType_Font].first)
3847 m_colorSelectLabelsButtons[KeyboardColorType_Font].first->setText(UISoftKeyboard::tr("Button Font Color"));
3848 if (m_colorSelectLabelsButtons[KeyboardColorType_Hover].first)
3849 m_colorSelectLabelsButtons[KeyboardColorType_Hover].first->setText(UISoftKeyboard::tr("Button Hover Color"));
3850 if (m_colorSelectLabelsButtons[KeyboardColorType_Edit].first)
3851 m_colorSelectLabelsButtons[KeyboardColorType_Edit].first->setText(UISoftKeyboard::tr("Button Edit Color"));
3852 if (m_colorSelectLabelsButtons[KeyboardColorType_Pressed].first)
3853 m_colorSelectLabelsButtons[KeyboardColorType_Pressed].first->setText(UISoftKeyboard::tr("Pressed Button Font Color"));
3854 }
3855}
3856
3857void UISoftKeyboardSettingsWidget::prepareObjects()
3858{
3859 QGridLayout *pSettingsLayout = new QGridLayout;
3860 if (!pSettingsLayout)
3861 return;
3862
3863 QHBoxLayout *pTitleLayout = new QHBoxLayout;
3864 m_pCloseButton = new QToolButton;
3865 m_pCloseButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
3866 m_pCloseButton->setIcon(UIIconPool::defaultIcon(UIIconPool::UIDefaultIconType_DialogCancel));
3867 m_pCloseButton->setAutoRaise(true);
3868 connect(m_pCloseButton, &QToolButton::clicked, this, &UISoftKeyboardSettingsWidget::sigCloseSettingsWidget);
3869 m_pTitleLabel = new QLabel;
3870 pTitleLayout->addWidget(m_pTitleLabel);
3871 pTitleLayout->addStretch(2);
3872 pTitleLayout->addWidget(m_pCloseButton);
3873 pSettingsLayout->addLayout(pTitleLayout, 0, 0, 1, 2);
3874
3875 m_pHideNumPadCheckBox = new QCheckBox;
3876 m_pShowOsMenuButtonsCheckBox = new QCheckBox;
3877 m_pHideMultimediaKeysCheckBox = new QCheckBox;
3878 pSettingsLayout->addWidget(m_pHideNumPadCheckBox, 1, 0, 1, 1);
3879 pSettingsLayout->addWidget(m_pShowOsMenuButtonsCheckBox, 2, 0, 1, 1);
3880 pSettingsLayout->addWidget(m_pHideMultimediaKeysCheckBox, 3, 0, 1, 1);
3881 connect(m_pHideNumPadCheckBox, &QCheckBox::toggled, this, &UISoftKeyboardSettingsWidget::sigHideNumPad);
3882 connect(m_pShowOsMenuButtonsCheckBox, &QCheckBox::toggled, this, &UISoftKeyboardSettingsWidget::sigHideOSMenuKeys);
3883 connect(m_pHideMultimediaKeysCheckBox, &QCheckBox::toggled, this, &UISoftKeyboardSettingsWidget::sigHideMultimediaKeys);
3884
3885 /* A groupbox to host the color selection widgets: */
3886 m_pColorThemeGroupBox = new QGroupBox;
3887 QVBoxLayout *pGroupBoxLayout = new QVBoxLayout(m_pColorThemeGroupBox);
3888 pSettingsLayout->addWidget(m_pColorThemeGroupBox, 4, 0, 1, 1);
3889
3890 m_pColorThemeComboBox = new QComboBox;
3891 pGroupBoxLayout->addWidget(m_pColorThemeComboBox);
3892 connect(m_pColorThemeComboBox, &QComboBox::currentTextChanged, this, &UISoftKeyboardSettingsWidget::sigColorThemeSelectionChanged);
3893
3894 /* Creating and configuring the color selection buttons: */
3895 QGridLayout *pColorSelectionLayout = new QGridLayout;
3896 pColorSelectionLayout->setSpacing(1);
3897 pGroupBoxLayout->addLayout(pColorSelectionLayout);
3898 for (int i = KeyboardColorType_Background; i < KeyboardColorType_Max; ++i)
3899 {
3900 QLabel *pLabel = new QLabel;
3901 UISoftKeyboardColorButton *pButton = new UISoftKeyboardColorButton((KeyboardColorType)i);
3902 pButton->setFlat(true);
3903 pButton->setMaximumWidth(3 * qApp->style()->pixelMetric(QStyle::PM_LargeIconSize));
3904 pColorSelectionLayout->addWidget(pLabel, i, 0, 1, 1);
3905 pColorSelectionLayout->addWidget(pButton, i, 1, 1, 1);
3906 m_colorSelectLabelsButtons.append(ColorSelectLabelButton(pLabel, pButton));
3907 connect(pButton, &UISoftKeyboardColorButton::clicked, this, &UISoftKeyboardSettingsWidget::sltColorSelectionButtonClicked);
3908 }
3909
3910 QSpacerItem *pSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding);
3911 if (pSpacer)
3912 pSettingsLayout->addItem(pSpacer, 6, 0);
3913
3914 setLayout(pSettingsLayout);
3915 retranslateUi();
3916}
3917
3918void UISoftKeyboardSettingsWidget::sltColorSelectionButtonClicked()
3919{
3920 UISoftKeyboardColorButton *pButton = qobject_cast<UISoftKeyboardColorButton*>(sender());
3921 if (!pButton)
3922 return;
3923 emit sigColorCellClicked((int)pButton->colorType());
3924}
3925
3926
3927/*********************************************************************************************************************************
3928* UISoftKeyboard implementation. *
3929*********************************************************************************************************************************/
3930
3931UISoftKeyboard::UISoftKeyboard(QWidget *pParent, UIMachine *pMachine,
3932 QWidget *pCenterWidget, QString strMachineName /* = QString() */)
3933 : QMainWindowWithRestorableGeometryAndRetranslateUi(pParent)
3934 , m_pMachine(pMachine)
3935 , m_pCenterWidget(pCenterWidget)
3936 , m_pMainLayout(0)
3937 , m_strMachineName(strMachineName)
3938 , m_pSplitter(0)
3939 , m_pSidePanelWidget(0)
3940 , m_pKeyboardWidget(0)
3941 , m_pLayoutEditor(0)
3942 , m_pLayoutSelector(0)
3943 , m_pSettingsWidget(0)
3944 , m_pStatusBarWidget(0)
3945 , m_iGeometrySaveTimerId(-1)
3946{
3947 setWindowTitle(QString("%1 - %2").arg(m_strMachineName).arg(tr("Soft Keyboard")));
3948 prepareObjects();
3949 prepareConnections();
3950
3951 if (m_pKeyboardWidget)
3952 {
3953 m_pKeyboardWidget->loadLayouts();
3954 if (m_pLayoutEditor)
3955 m_pLayoutEditor->setPhysicalLayoutList(m_pKeyboardWidget->physicalLayouts());
3956 }
3957
3958 loadSettings();
3959 configure();
3960 retranslateUi();
3961 uiCommon().setHelpKeyword(this, "soft-keyb");
3962}
3963
3964void UISoftKeyboard::retranslateUi()
3965{
3966}
3967
3968bool UISoftKeyboard::shouldBeMaximized() const
3969{
3970 return gEDataManager->softKeyboardDialogShouldBeMaximized();
3971}
3972
3973void UISoftKeyboard::closeEvent(QCloseEvent *event)
3974{
3975 QStringList strNameList = m_pKeyboardWidget->unsavedLayoutsNameList();
3976 /* Show a warning dialog when there are not saved layouts: */
3977 if (m_pKeyboardWidget && !strNameList.empty())
3978 {
3979 QString strJoinedString = strNameList.join("<br/>");
3980 if (!msgCenter().questionBinary(this, MessageType_Warning,
3981 tr("<p>Following layouts are edited/copied but not saved:</p>%1"
3982 "<p>Closing this dialog will cause loosing the changes. Proceed?</p>").arg(strJoinedString),
3983 0 /* auto-confirm id */,
3984 "Ok", "Cancel"))
3985 {
3986 event->ignore();
3987 return;
3988 }
3989 }
3990 m_pMachine->releaseKeys();
3991 emit sigClose();
3992 event->ignore();
3993}
3994
3995bool UISoftKeyboard::event(QEvent *pEvent)
3996{
3997 if (pEvent->type() == QEvent::WindowDeactivate)
3998 {
3999 if (m_pKeyboardWidget)
4000 m_pKeyboardWidget->parentDialogDeactivated();
4001 }
4002 else if (pEvent->type() == QEvent::KeyPress)
4003 {
4004 QKeyEvent *pKeyEvent = dynamic_cast<QKeyEvent*>(pEvent);
4005 if (pKeyEvent)
4006 {
4007 if (QKeySequence(pKeyEvent->key()) == QKeySequence::HelpContents)
4008 sltHandleHelpRequest();
4009 }
4010 }
4011 else if (pEvent->type() == QEvent::Resize ||
4012 pEvent->type() == QEvent::Move)
4013 {
4014 if (m_iGeometrySaveTimerId != -1)
4015 killTimer(m_iGeometrySaveTimerId);
4016 m_iGeometrySaveTimerId = startTimer(300);
4017 }
4018 else if (pEvent->type() == QEvent::Timer)
4019 {
4020 QTimerEvent *pTimerEvent = static_cast<QTimerEvent*>(pEvent);
4021 if (pTimerEvent->timerId() == m_iGeometrySaveTimerId)
4022 {
4023 killTimer(m_iGeometrySaveTimerId);
4024 m_iGeometrySaveTimerId = -1;
4025 saveDialogGeometry();
4026 }
4027 }
4028
4029 return QMainWindowWithRestorableGeometryAndRetranslateUi::event(pEvent);
4030}
4031
4032void UISoftKeyboard::sltKeyboardLedsChange()
4033{
4034 bool fNumLockLed = m_pMachine->isNumLock();
4035 bool fCapsLockLed = m_pMachine->isCapsLock();
4036 bool fScrollLockLed = m_pMachine->isScrollLock();
4037 if (m_pKeyboardWidget)
4038 m_pKeyboardWidget->updateLockKeyStates(fCapsLockLed, fNumLockLed, fScrollLockLed);
4039}
4040
4041void UISoftKeyboard::sltPutKeyboardSequence(QVector<LONG> sequence)
4042{
4043 m_pMachine->putScancodes(sequence);
4044}
4045
4046void UISoftKeyboard::sltPutUsageCodesPress(QVector<QPair<LONG, LONG> > sequence)
4047{
4048 for (int i = 0; i < sequence.size(); ++i)
4049 m_pMachine->putUsageCode(sequence[i].first, sequence[i].second, false);
4050}
4051
4052void UISoftKeyboard::sltPutUsageCodesRelease(QVector<QPair<LONG, LONG> > sequence)
4053{
4054 for (int i = 0; i < sequence.size(); ++i)
4055 m_pMachine->putUsageCode(sequence[i].first, sequence[i].second, true);
4056}
4057
4058void UISoftKeyboard::sltLayoutSelectionChanged(const QUuid &layoutUid)
4059{
4060 if (!m_pKeyboardWidget)
4061 return;
4062 m_pKeyboardWidget->setCurrentLayout(layoutUid);
4063 if (m_pLayoutSelector && m_pKeyboardWidget->currentLayout())
4064 m_pLayoutSelector->setCurrentLayoutIsEditable(m_pKeyboardWidget->currentLayout()->editable());
4065}
4066
4067void UISoftKeyboard::sltCurentLayoutChanged()
4068{
4069 if (!m_pKeyboardWidget)
4070 return;
4071 UISoftKeyboardLayout *pCurrentLayout = m_pKeyboardWidget->currentLayout();
4072
4073 /* Update the status bar string: */
4074 if (!pCurrentLayout)
4075 return;
4076 updateStatusBarMessage(pCurrentLayout->nameString());
4077 saveCurrentLayout();
4078}
4079
4080void UISoftKeyboard::sltShowLayoutSelector()
4081{
4082 if (m_pSidePanelWidget && m_pLayoutSelector)
4083 m_pSidePanelWidget->setCurrentWidget(m_pLayoutSelector);
4084 if (m_pKeyboardWidget)
4085 m_pKeyboardWidget->toggleEditMode(false);
4086 if (m_pLayoutEditor)
4087 m_pLayoutEditor->setKey(0);
4088}
4089
4090void UISoftKeyboard::sltShowLayoutEditor()
4091{
4092 if (m_pSidePanelWidget && m_pLayoutEditor)
4093 {
4094 m_pLayoutEditor->setLayoutToEdit(m_pKeyboardWidget->currentLayout());
4095 m_pSidePanelWidget->setCurrentWidget(m_pLayoutEditor);
4096 }
4097 if (m_pKeyboardWidget)
4098 m_pKeyboardWidget->toggleEditMode(true);
4099}
4100
4101void UISoftKeyboard::sltKeyToEditChanged(UISoftKeyboardKey* pKey)
4102{
4103 if (m_pLayoutEditor)
4104 m_pLayoutEditor->setKey(pKey);
4105}
4106
4107void UISoftKeyboard::sltLayoutEdited()
4108{
4109 if (!m_pKeyboardWidget)
4110 return;
4111 m_pKeyboardWidget->update();
4112 updateLayoutSelectorList();
4113 UISoftKeyboardLayout *pCurrentLayout = m_pKeyboardWidget->currentLayout();
4114
4115 /* Update the status bar string: */
4116 QString strLayoutName = pCurrentLayout ? pCurrentLayout->name() : QString();
4117 updateStatusBarMessage(strLayoutName);
4118}
4119
4120void UISoftKeyboard::sltKeyCaptionsEdited(UISoftKeyboardKey* pKey)
4121{
4122 Q_UNUSED(pKey);
4123 if (m_pKeyboardWidget)
4124 m_pKeyboardWidget->update();
4125}
4126
4127void UISoftKeyboard::sltShowHideSidePanel()
4128{
4129 if (!m_pSidePanelWidget)
4130 return;
4131 m_pSidePanelWidget->setVisible(!m_pSidePanelWidget->isVisible());
4132
4133 if (m_pSidePanelWidget->isVisible() && m_pSettingsWidget->isVisible())
4134 m_pSettingsWidget->setVisible(false);
4135}
4136
4137void UISoftKeyboard::sltShowHideSettingsWidget()
4138{
4139 if (!m_pSettingsWidget)
4140 return;
4141 m_pSettingsWidget->setVisible(!m_pSettingsWidget->isVisible());
4142 if (m_pSidePanelWidget->isVisible() && m_pSettingsWidget->isVisible())
4143 m_pSidePanelWidget->setVisible(false);
4144}
4145
4146void UISoftKeyboard::sltHandleColorThemeListSelection(const QString &strColorThemeName)
4147{
4148 if (m_pKeyboardWidget)
4149 m_pKeyboardWidget->setColorThemeByName(strColorThemeName);
4150 saveSelectedColorThemeName();
4151}
4152
4153void UISoftKeyboard::sltHandleKeyboardWidgetColorThemeChange()
4154{
4155 for (int i = (int)KeyboardColorType_Background;
4156 i < (int)KeyboardColorType_Max; ++i)
4157 {
4158 KeyboardColorType enmType = (KeyboardColorType)i;
4159 m_pSettingsWidget->setColorSelectionButtonBackgroundAndTooltip(enmType,
4160 m_pKeyboardWidget->color(enmType),
4161 m_pKeyboardWidget->isColorThemeEditable());
4162 }
4163}
4164
4165void UISoftKeyboard::sltCopyLayout()
4166{
4167 if (!m_pKeyboardWidget)
4168 return;
4169 m_pKeyboardWidget->copyCurentLayout();
4170 updateLayoutSelectorList();
4171}
4172
4173void UISoftKeyboard::sltSaveLayout()
4174{
4175 if (m_pKeyboardWidget)
4176 m_pKeyboardWidget->saveCurentLayoutToFile();
4177}
4178
4179void UISoftKeyboard::sltDeleteLayout()
4180{
4181 if (m_pKeyboardWidget)
4182 m_pKeyboardWidget->deleteCurrentLayout();
4183 updateLayoutSelectorList();
4184 if (m_pKeyboardWidget && m_pKeyboardWidget->currentLayout() && m_pLayoutSelector)
4185 {
4186 m_pLayoutSelector->setCurrentLayout(m_pKeyboardWidget->currentLayout()->uid());
4187 m_pLayoutSelector->setCurrentLayoutIsEditable(m_pKeyboardWidget->currentLayout()->editable());
4188 }
4189}
4190
4191void UISoftKeyboard::sltStatusBarMessage(const QString &strMessage)
4192{
4193 statusBar()->showMessage(strMessage, iMessageTimeout);
4194}
4195
4196void UISoftKeyboard::sltShowHideOSMenuKeys(bool fHide)
4197{
4198 if (m_pKeyboardWidget)
4199 m_pKeyboardWidget->setHideOSMenuKeys(fHide);
4200}
4201
4202void UISoftKeyboard::sltShowHideNumPad(bool fHide)
4203{
4204 if (m_pKeyboardWidget)
4205 m_pKeyboardWidget->setHideNumPad(fHide);
4206}
4207
4208void UISoftKeyboard::sltShowHideMultimediaKeys(bool fHide)
4209{
4210 if (m_pKeyboardWidget)
4211 m_pKeyboardWidget->setHideMultimediaKeys(fHide);
4212}
4213
4214void UISoftKeyboard::sltHandleColorCellClick(int iColorRow)
4215{
4216 if (!m_pKeyboardWidget || iColorRow >= static_cast<int>(KeyboardColorType_Max))
4217 return;
4218
4219 if (!m_pKeyboardWidget->isColorThemeEditable())
4220 return;
4221 const QColor &currentColor = m_pKeyboardWidget->color(static_cast<KeyboardColorType>(iColorRow));
4222 QColorDialog colorDialog(currentColor, this);
4223
4224 if (colorDialog.exec() == QDialog::Rejected)
4225 return;
4226 QColor newColor = colorDialog.selectedColor();
4227 if (currentColor == newColor)
4228 return;
4229 m_pKeyboardWidget->setColor(static_cast<KeyboardColorType>(iColorRow), newColor);
4230 m_pSettingsWidget->setColorSelectionButtonBackgroundAndTooltip(static_cast<KeyboardColorType>(iColorRow),
4231 newColor, m_pKeyboardWidget->isColorThemeEditable());
4232 saveCustomColorTheme();
4233}
4234
4235void UISoftKeyboard::sltResetKeyboard()
4236{
4237 if (m_pKeyboardWidget)
4238 m_pKeyboardWidget->reset();
4239 if (m_pLayoutEditor)
4240 m_pLayoutEditor->reset();
4241 m_pMachine->releaseKeys();
4242 update();
4243}
4244
4245void UISoftKeyboard::sltHandleHelpRequest()
4246{
4247 UIHelpBrowserDialog::findManualFileAndShow(uiCommon().helpKeyword(this));
4248}
4249
4250void UISoftKeyboard::prepareObjects()
4251{
4252 m_pSplitter = new QSplitter;
4253 if (!m_pSplitter)
4254 return;
4255 setCentralWidget(m_pSplitter);
4256 m_pSidePanelWidget = new QStackedWidget;
4257 if (!m_pSidePanelWidget)
4258 return;
4259
4260 m_pSidePanelWidget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
4261 m_pSidePanelWidget->hide();
4262
4263 m_pLayoutSelector = new UILayoutSelector;
4264 if (m_pLayoutSelector)
4265 m_pSidePanelWidget->addWidget(m_pLayoutSelector);
4266
4267 m_pLayoutEditor = new UIKeyboardLayoutEditor;
4268 if (m_pLayoutEditor)
4269 m_pSidePanelWidget->addWidget(m_pLayoutEditor);
4270
4271 m_pSettingsWidget = new UISoftKeyboardSettingsWidget;
4272 if (m_pSettingsWidget)
4273 {
4274 m_pSettingsWidget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
4275 m_pSettingsWidget->hide();
4276 }
4277 m_pKeyboardWidget = new UISoftKeyboardWidget;
4278 if (!m_pKeyboardWidget)
4279 return;
4280 m_pKeyboardWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
4281 m_pKeyboardWidget->updateGeometry();
4282 m_pSplitter->addWidget(m_pKeyboardWidget);
4283 m_pSplitter->addWidget(m_pSidePanelWidget);
4284 m_pSplitter->addWidget(m_pSettingsWidget);
4285
4286 m_pSplitter->setCollapsible(0, false);
4287 m_pSplitter->setCollapsible(1, false);
4288 m_pSplitter->setCollapsible(2, false);
4289
4290 statusBar()->setStyleSheet( "QStatusBar::item { border: 0px}" );
4291 m_pStatusBarWidget = new UISoftKeyboardStatusBarWidget;
4292 statusBar()->addPermanentWidget(m_pStatusBarWidget);
4293
4294 retranslateUi();
4295}
4296
4297void UISoftKeyboard::prepareConnections()
4298{
4299 connect(m_pMachine, &UIMachine::sigKeyboardLedsChange, this, &UISoftKeyboard::sltKeyboardLedsChange);
4300 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigPutKeyboardSequence, this, &UISoftKeyboard::sltPutKeyboardSequence);
4301 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigPutUsageCodesPress, this, &UISoftKeyboard::sltPutUsageCodesPress);
4302 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigPutUsageCodesRelease, this, &UISoftKeyboard::sltPutUsageCodesRelease);
4303 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigCurrentLayoutChange, this, &UISoftKeyboard::sltCurentLayoutChanged);
4304 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigKeyToEdit, this, &UISoftKeyboard::sltKeyToEditChanged);
4305 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigStatusBarMessage, this, &UISoftKeyboard::sltStatusBarMessage);
4306 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigCurrentColorThemeChanged, this, &UISoftKeyboard::sltHandleKeyboardWidgetColorThemeChange);
4307 connect(m_pKeyboardWidget, &UISoftKeyboardWidget::sigOptionsChanged, this, &UISoftKeyboard::sltSaveSettings);
4308
4309 connect(m_pLayoutSelector, &UILayoutSelector::sigLayoutSelectionChanged, this, &UISoftKeyboard::sltLayoutSelectionChanged);
4310 connect(m_pLayoutSelector, &UILayoutSelector::sigShowLayoutEditor, this, &UISoftKeyboard::sltShowLayoutEditor);
4311 connect(m_pLayoutSelector, &UILayoutSelector::sigCloseLayoutList, this, &UISoftKeyboard::sltShowHideSidePanel);
4312 connect(m_pLayoutSelector, &UILayoutSelector::sigSaveLayout, this, &UISoftKeyboard::sltSaveLayout);
4313 connect(m_pLayoutSelector, &UILayoutSelector::sigDeleteLayout, this, &UISoftKeyboard::sltDeleteLayout);
4314 connect(m_pLayoutSelector, &UILayoutSelector::sigCopyLayout, this, &UISoftKeyboard::sltCopyLayout);
4315 connect(m_pLayoutEditor, &UIKeyboardLayoutEditor::sigGoBackButton, this, &UISoftKeyboard::sltShowLayoutSelector);
4316 connect(m_pLayoutEditor, &UIKeyboardLayoutEditor::sigLayoutEdited, this, &UISoftKeyboard::sltLayoutEdited);
4317 connect(m_pLayoutEditor, &UIKeyboardLayoutEditor::sigUIKeyCaptionsEdited, this, &UISoftKeyboard::sltKeyCaptionsEdited);
4318
4319 connect(m_pStatusBarWidget, &UISoftKeyboardStatusBarWidget::sigShowHideSidePanel, this, &UISoftKeyboard::sltShowHideSidePanel);
4320 connect(m_pStatusBarWidget, &UISoftKeyboardStatusBarWidget::sigShowSettingWidget, this, &UISoftKeyboard::sltShowHideSettingsWidget);
4321 connect(m_pStatusBarWidget, &UISoftKeyboardStatusBarWidget::sigResetKeyboard, this, &UISoftKeyboard::sltResetKeyboard);
4322 connect(m_pStatusBarWidget, &UISoftKeyboardStatusBarWidget::sigHelpButtonPressed, this, &UISoftKeyboard::sltHandleHelpRequest);
4323
4324 connect(m_pSettingsWidget, &UISoftKeyboardSettingsWidget::sigHideOSMenuKeys, this, &UISoftKeyboard::sltShowHideOSMenuKeys);
4325 connect(m_pSettingsWidget, &UISoftKeyboardSettingsWidget::sigHideNumPad, this, &UISoftKeyboard::sltShowHideNumPad);
4326 connect(m_pSettingsWidget, &UISoftKeyboardSettingsWidget::sigHideMultimediaKeys, this, &UISoftKeyboard::sltShowHideMultimediaKeys);
4327 connect(m_pSettingsWidget, &UISoftKeyboardSettingsWidget::sigColorCellClicked, this, &UISoftKeyboard::sltHandleColorCellClick);
4328 connect(m_pSettingsWidget, &UISoftKeyboardSettingsWidget::sigCloseSettingsWidget, this, &UISoftKeyboard::sltShowHideSettingsWidget);
4329 connect(m_pSettingsWidget, &UISoftKeyboardSettingsWidget::sigColorThemeSelectionChanged, this, &UISoftKeyboard::sltHandleColorThemeListSelection);
4330
4331 connect(&uiCommon(), &UICommon::sigAskToCommitData, this, &UISoftKeyboard::sltReleaseKeys);
4332}
4333
4334void UISoftKeyboard::saveDialogGeometry()
4335{
4336 const QRect geo = currentGeometry();
4337 LogRel2(("GUI: UISoftKeyboard: Saving geometry as: Origin=%dx%d, Size=%dx%d\n",
4338 geo.x(), geo.y(), geo.width(), geo.height()));
4339 gEDataManager->setSoftKeyboardDialogGeometry(geo, isCurrentlyMaximized());
4340}
4341
4342void UISoftKeyboard::saveCustomColorTheme()
4343{
4344 if (!m_pKeyboardWidget)
4345 return;
4346 /* Save the changes to the 'Custom' color theme to extra data: */
4347 QStringList colors = m_pKeyboardWidget->colorsToStringList("Custom");
4348 colors.prepend("Custom");
4349 gEDataManager->setSoftKeyboardColorTheme(colors);
4350}
4351
4352void UISoftKeyboard::saveSelectedColorThemeName()
4353{
4354 if (!m_pKeyboardWidget)
4355 return;
4356 gEDataManager->setSoftKeyboardSelectedColorTheme(m_pKeyboardWidget->currentColorThemeName());
4357}
4358
4359void UISoftKeyboard::saveCurrentLayout()
4360{
4361 if (m_pKeyboardWidget && m_pKeyboardWidget->currentLayout())
4362 gEDataManager->setSoftKeyboardSelectedLayout(m_pKeyboardWidget->currentLayout()->uid());
4363}
4364
4365void UISoftKeyboard::sltSaveSettings()
4366{
4367 /* Save other settings: */
4368 if (m_pKeyboardWidget)
4369 {
4370 gEDataManager->setSoftKeyboardOptions(m_pKeyboardWidget->hideNumPad(),
4371 m_pKeyboardWidget->hideOSMenuKeys(),
4372 m_pKeyboardWidget->hideMultimediaKeys());
4373 }
4374}
4375
4376void UISoftKeyboard::sltReleaseKeys()
4377{
4378 m_pMachine->releaseKeys();
4379}
4380
4381void UISoftKeyboard::loadSettings()
4382{
4383 /* Invent default window geometry: */
4384 float fKeyboardAspectRatio = 1.0f;
4385 if (m_pKeyboardWidget)
4386 fKeyboardAspectRatio = m_pKeyboardWidget->layoutAspectRatio();
4387 const QRect availableGeo = gpDesktop->availableGeometry(this);
4388 const int iDefaultWidth = availableGeo.width() / 2;
4389 const int iDefaultHeight = iDefaultWidth * fKeyboardAspectRatio;
4390 QRect defaultGeo(0, 0, iDefaultWidth, iDefaultHeight);
4391
4392 /* Load geometry from extradata: */
4393 const QRect geo = gEDataManager->softKeyboardDialogGeometry(this, m_pCenterWidget, defaultGeo);
4394 LogRel2(("GUI: UISoftKeyboard: Restoring geometry to: Origin=%dx%d, Size=%dx%d\n",
4395 geo.x(), geo.y(), geo.width(), geo.height()));
4396 restoreGeometry(geo);
4397
4398 /* Load other settings: */
4399 if (m_pKeyboardWidget)
4400 {
4401 QStringList colorTheme = gEDataManager->softKeyboardColorTheme();
4402 if (!colorTheme.empty())
4403 {
4404 /* The fist item is the theme name and the rest are color codes: */
4405 QString strThemeName = colorTheme[0];
4406 colorTheme.removeFirst();
4407 m_pKeyboardWidget->colorsFromStringList(strThemeName, colorTheme);
4408 }
4409 m_pKeyboardWidget->setColorThemeByName(gEDataManager->softKeyboardSelectedColorTheme());
4410 m_pKeyboardWidget->setCurrentLayout(gEDataManager->softKeyboardSelectedLayout());
4411
4412 /* Load other options from exra data: */
4413 bool fHideNumPad = false;
4414 bool fHideOSMenuKeys = false;
4415 bool fHideMultimediaKeys = false;
4416 gEDataManager->softKeyboardOptions(fHideNumPad, fHideOSMenuKeys, fHideMultimediaKeys);
4417 m_pKeyboardWidget->setHideNumPad(fHideNumPad);
4418 m_pKeyboardWidget->setHideOSMenuKeys(fHideOSMenuKeys);
4419 m_pKeyboardWidget->setHideMultimediaKeys(fHideMultimediaKeys);
4420 }
4421}
4422
4423void UISoftKeyboard::configure()
4424{
4425 setWindowIcon(UIIconPool::iconSet(":/soft_keyboard_16px.png"));
4426 if (m_pKeyboardWidget && m_pSettingsWidget)
4427 {
4428 m_pSettingsWidget->setHideOSMenuKeys(m_pKeyboardWidget->hideOSMenuKeys());
4429 m_pSettingsWidget->setHideNumPad(m_pKeyboardWidget->hideNumPad());
4430 m_pSettingsWidget->setHideMultimediaKeys(m_pKeyboardWidget->hideMultimediaKeys());
4431
4432 m_pSettingsWidget->setColorThemeNames(m_pKeyboardWidget->colorThemeNames());
4433 m_pSettingsWidget->setCurrentColorThemeName(m_pKeyboardWidget->currentColorThemeName());
4434
4435 for (int i = (int)KeyboardColorType_Background;
4436 i < (int)KeyboardColorType_Max; ++i)
4437 {
4438 KeyboardColorType enmType = (KeyboardColorType)i;
4439 m_pSettingsWidget->setColorSelectionButtonBackgroundAndTooltip(enmType,
4440 m_pKeyboardWidget->color(enmType),
4441 m_pKeyboardWidget->isColorThemeEditable());
4442 }
4443 }
4444 updateLayoutSelectorList();
4445 if (m_pKeyboardWidget && m_pKeyboardWidget->currentLayout() && m_pLayoutSelector)
4446 {
4447 m_pLayoutSelector->setCurrentLayout(m_pKeyboardWidget->currentLayout()->uid());
4448 m_pLayoutSelector->setCurrentLayoutIsEditable(m_pKeyboardWidget->currentLayout()->editable());
4449 }
4450}
4451
4452void UISoftKeyboard::updateStatusBarMessage(const QString &strName)
4453{
4454 if (!m_pStatusBarWidget)
4455 return;
4456 QString strMessage;
4457 if (!strName.isEmpty())
4458 {
4459 strMessage += QString("%1: %2").arg(tr("Layout")).arg(strName);
4460 m_pStatusBarWidget->updateLayoutNameInStatusBar(strMessage);
4461 }
4462 else
4463 m_pStatusBarWidget->updateLayoutNameInStatusBar(QString());
4464}
4465
4466void UISoftKeyboard::updateLayoutSelectorList()
4467{
4468 if (!m_pKeyboardWidget || !m_pLayoutSelector)
4469 return;
4470 m_pLayoutSelector->setLayoutList(m_pKeyboardWidget->layoutNameList(), m_pKeyboardWidget->layoutUidList());
4471}
4472
4473#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