VirtualBox

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

Last change on this file since 103977 was 103920, checked in by vboxsync, 9 months ago

FE/Qt. bugref:10622. Using new UITranslationEventListener in soft keyboard classes.

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