VirtualBox

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

Last change on this file was 104358, checked in by vboxsync, 5 weeks ago

FE/Qt. bugref:10622. More refactoring around the retranslation functionality.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use