QtBase  v6.3.1
qandroidplatformtheme.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "androidjnimain.h"
41 #include "androidjnimenu.h"
42 #include "qandroidplatformtheme.h"
44 #include "qandroidplatformmenu.h"
48 
49 #include <QCoreApplication>
50 #include <QDebug>
51 #include <QFileInfo>
52 #include <QJsonDocument>
53 #include <QVariant>
54 
55 #include <private/qguiapplication_p.h>
56 #include <private/qhighdpiscaling_p.h>
58 
60 
61 namespace {
62  const int textStyle_bold = 1;
63  const int textStyle_italic = 2;
64 
65  const int typeface_sans = 1;
66  const int typeface_serif = 2;
67  const int typeface_monospace = 3;
68 }
69 
70 static int fontType(const QString &androidControl)
71 {
72  if (androidControl == QLatin1String("defaultStyle"))
74  if (androidControl == QLatin1String("textViewStyle"))
76  else if (androidControl == QLatin1String("buttonStyle"))
78  else if (androidControl == QLatin1String("checkboxStyle"))
80  else if (androidControl == QLatin1String("radioButtonStyle"))
82  else if (androidControl == QLatin1String("simple_list_item_single_choice"))
84  else if (androidControl == QLatin1String("simple_spinner_dropdown_item"))
86  else if (androidControl == QLatin1String("spinnerStyle"))
88  else if (androidControl == QLatin1String("simple_list_item"))
90  return -1;
91 }
92 
93 static int paletteType(const QString &androidControl)
94 {
95  if (androidControl == QLatin1String("defaultStyle"))
97  if (androidControl == QLatin1String("textViewStyle"))
99  else if (androidControl == QLatin1String("buttonStyle"))
101  else if (androidControl == QLatin1String("checkboxStyle"))
103  else if (androidControl == QLatin1String("radioButtonStyle"))
105  else if (androidControl == QLatin1String("simple_list_item_single_choice"))
107  else if (androidControl == QLatin1String("editTextStyle"))
109  else if (androidControl == QLatin1String("spinnerStyle"))
111  return -1;
112 }
113 
114 static void setPaletteColor(const QVariantMap &object,
115  QPalette &palette,
116  QPalette::ColorRole role)
117 {
118  // QPalette::Active -> ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET
119  palette.setColor(QPalette::Active,
120  role,
121  QRgb(object.value(QLatin1String("ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET")).toInt()));
122 
123  // QPalette::Inactive -> ENABLED_STATE_SET
124  palette.setColor(QPalette::Inactive,
125  role,
126  QRgb(object.value(QLatin1String("ENABLED_STATE_SET")).toInt()));
127 
128  // QPalette::Disabled -> EMPTY_STATE_SET
129  palette.setColor(QPalette::Disabled,
130  role,
131  QRgb(object.value(QLatin1String("EMPTY_STATE_SET")).toInt()));
132 
133  palette.setColor(QPalette::Current, role, palette.color(QPalette::Active, role));
134 
135  if (role == QPalette::WindowText) {
136  // QPalette::BrightText -> PRESSED
137  // QPalette::Active -> PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET
138  palette.setColor(QPalette::Active,
140  QRgb(object.value(QLatin1String("PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET")).toInt()));
141 
142  // QPalette::Inactive -> PRESSED_ENABLED_STATE_SET
143  palette.setColor(QPalette::Inactive,
145  QRgb(object.value(QLatin1String("PRESSED_ENABLED_STATE_SET")).toInt()));
146 
147  // QPalette::Disabled -> PRESSED_STATE_SET
148  palette.setColor(QPalette::Disabled,
150  QRgb(object.value(QLatin1String("PRESSED_STATE_SET")).toInt()));
151 
153 
154  // QPalette::HighlightedText -> SELECTED
155  // QPalette::Active -> ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET
156  palette.setColor(QPalette::Active,
158  QRgb(object.value(QLatin1String("ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET")).toInt()));
159 
160  // QPalette::Inactive -> ENABLED_SELECTED_STATE_SET
161  palette.setColor(QPalette::Inactive,
163  QRgb(object.value(QLatin1String("ENABLED_SELECTED_STATE_SET")).toInt()));
164 
165  // QPalette::Disabled -> SELECTED_STATE_SET
166  palette.setColor(QPalette::Disabled,
168  QRgb(object.value(QLatin1String("SELECTED_STATE_SET")).toInt()));
169 
170  palette.setColor(QPalette::Current,
173 
174  // Same colors for Text
179 
180  // And for ButtonText
185  }
186 }
187 
189 {
190  QString stylePath(QLatin1String(qgetenv("ANDROID_STYLE_PATH")));
191  const QLatin1Char slashChar('/');
192  if (!stylePath.isEmpty() && !stylePath.endsWith(slashChar))
193  stylePath += slashChar;
194 
195  Q_ASSERT(!stylePath.isEmpty());
196 
197  QString androidTheme = QLatin1String(qgetenv("QT_ANDROID_THEME"));
198  if (!androidTheme.isEmpty() && !androidTheme.endsWith(slashChar))
199  androidTheme += slashChar;
200 
201  if (!androidTheme.isEmpty() && QFileInfo::exists(stylePath + androidTheme + QLatin1String("style.json")))
202  stylePath += androidTheme;
203 
204  QFile f(stylePath + QLatin1String("style.json"));
205  if (!f.open(QIODevice::ReadOnly))
206  return QJsonObject();
207 
210  if (Q_UNLIKELY(document.isNull())) {
211  qCritical() << error.errorString();
212  return QJsonObject();
213  }
214 
215  if (Q_UNLIKELY(!document.isObject())) {
216  qCritical("Style.json does not contain a valid style.");
217  return QJsonObject();
218  }
219  return document.object();
220 }
221 
222 static std::shared_ptr<AndroidStyle> loadAndroidStyle(QPalette *defaultPalette)
223 {
225  std::shared_ptr<AndroidStyle> style = std::make_shared<AndroidStyle>();
226  style->m_styleData = AndroidStyle::loadStyleData();
227  if (style->m_styleData.isEmpty())
228  return std::shared_ptr<AndroidStyle>();
229 
230  {
231  QFont font(QLatin1String("Droid Sans Mono"), 14.0 * 100 / 72);
232  style->m_fonts.insert(QPlatformTheme::FixedFont, font);
233  }
234 
235  for (QJsonObject::const_iterator objectIterator = style->m_styleData.constBegin();
236  objectIterator != style->m_styleData.constEnd();
237  ++objectIterator) {
238  QString key = objectIterator.key();
239  QJsonValue value = objectIterator.value();
240  if (!value.isObject()) {
241  qWarning("Style.json structure is unrecognized.");
242  continue;
243  }
244  QJsonObject item = value.toObject();
245  QJsonObject::const_iterator attributeIterator = item.find(QLatin1String("qtClass"));
246  QByteArray qtClassName;
247  if (attributeIterator != item.constEnd()) {
248  // The item has palette and font information for a specific Qt Class (e.g. QWidget, QPushButton, etc.)
249  qtClassName = attributeIterator.value().toString().toLatin1();
250  }
251  const int ft = fontType(key);
252  if (ft > -1 || !qtClassName.isEmpty()) {
253  // Extract font information
254  QFont font;
255 
256  // Font size (in pixels)
257  attributeIterator = item.find(QLatin1String("TextAppearance_textSize"));
258  if (attributeIterator != item.constEnd())
259  font.setPixelSize(int(attributeIterator.value().toDouble() / pixelDensity));
260 
261  // Font style
262  attributeIterator = item.find(QLatin1String("TextAppearance_textStyle"));
263  if (attributeIterator != item.constEnd()) {
264  const int style = int(attributeIterator.value().toDouble());
267  }
268 
269  // Font typeface
270  attributeIterator = item.find(QLatin1String("TextAppearance_typeface"));
271  if (attributeIterator != item.constEnd()) {
272  QFont::StyleHint styleHint = QFont::AnyStyle;
273  switch (int(attributeIterator.value().toDouble())) {
274  case typeface_sans:
275  styleHint = QFont::SansSerif;
276  break;
277  case typeface_serif:
278  styleHint = QFont::Serif;
279  break;
280  case typeface_monospace:
281  styleHint = QFont::Monospace;
282  break;
283  }
285  }
286  if (!qtClassName.isEmpty())
287  style->m_QWidgetsFonts.insert(qtClassName, font);
288 
289  if (ft > -1) {
290  style->m_fonts.insert(ft, font);
291  if (ft == QPlatformTheme::SystemFont)
293  }
294  // Extract font information
295  }
296 
297  const int pt = paletteType(key);
298  if (pt > -1 || !qtClassName.isEmpty()) {
299  // Extract palette information
300  QPalette palette = *defaultPalette;
301 
302  attributeIterator = item.find(QLatin1String("defaultTextColorPrimary"));
303  if (attributeIterator != item.constEnd())
304  palette.setColor(QPalette::WindowText, QRgb(int(attributeIterator.value().toDouble())));
305 
306  attributeIterator = item.find(QLatin1String("defaultBackgroundColor"));
307  if (attributeIterator != item.constEnd())
308  palette.setColor(QPalette::Window, QRgb(int(attributeIterator.value().toDouble())));
309 
310  attributeIterator = item.find(QLatin1String("TextAppearance_textColor"));
311  if (attributeIterator != item.constEnd())
312  setPaletteColor(attributeIterator.value().toObject().toVariantMap(), palette, QPalette::WindowText);
313 
314  attributeIterator = item.find(QLatin1String("TextAppearance_textColorLink"));
315  if (attributeIterator != item.constEnd())
316  setPaletteColor(attributeIterator.value().toObject().toVariantMap(), palette, QPalette::Link);
317 
318  attributeIterator = item.find(QLatin1String("TextAppearance_textColorHighlight"));
319  if (attributeIterator != item.constEnd())
320  palette.setColor(QPalette::Highlight, QRgb(int(attributeIterator.value().toDouble())));
321 
323  *defaultPalette = style->m_standardPalette = palette;
324 
325  if (pt > -1)
326  style->m_palettes.insert(pt, palette);
327  // Extract palette information
328  }
329  }
330  return style;
331 }
332 
334 {
335  QColor background(229, 229, 229);
336  QColor light = background.lighter(150);
337  QColor mid(background.darker(130));
338  QColor midLight = mid.lighter(110);
339  QColor base(249, 249, 249);
340  QColor disabledBase(background);
341  QColor dark = background.darker(150);
342  QColor darkDisabled = dark.darker(110);
344  QColor highlightedText = Qt::black;
345  QColor disabledText = QColor(190, 190, 190);
346  QColor button(241, 241, 241);
347  QColor shadow(201, 201, 201);
348  QColor highlight(148, 210, 231);
349  QColor disabledShadow = shadow.lighter(150);
350 
351  m_defaultPalette = QPalette(Qt::black,background,light,dark,mid,text,base);
352  m_defaultPalette.setBrush(QPalette::Midlight, midLight);
353  m_defaultPalette.setBrush(QPalette::Button, button);
354  m_defaultPalette.setBrush(QPalette::Shadow, shadow);
355  m_defaultPalette.setBrush(QPalette::HighlightedText, highlightedText);
356 
357  m_defaultPalette.setBrush(QPalette::Disabled, QPalette::Text, disabledText);
358  m_defaultPalette.setBrush(QPalette::Disabled, QPalette::WindowText, disabledText);
359  m_defaultPalette.setBrush(QPalette::Disabled, QPalette::ButtonText, disabledText);
360  m_defaultPalette.setBrush(QPalette::Disabled, QPalette::Base, disabledBase);
361  m_defaultPalette.setBrush(QPalette::Disabled, QPalette::Dark, darkDisabled);
362  m_defaultPalette.setBrush(QPalette::Disabled, QPalette::Shadow, disabledShadow);
363 
364  m_defaultPalette.setBrush(QPalette::Active, QPalette::Highlight, highlight);
365  m_defaultPalette.setBrush(QPalette::Inactive, QPalette::Highlight, highlight);
366  m_defaultPalette.setBrush(QPalette::Disabled, QPalette::Highlight, highlight.lighter(150));
367  m_androidStyleData = loadAndroidStyle(&m_defaultPalette);
368  QGuiApplication::setPalette(m_defaultPalette);
369  androidPlatformNativeInterface->m_androidStyle = m_androidStyleData;
370 
371  // default in case the style has not set a font
372  m_systemFont = QFont(QLatin1String("Roboto"), 14.0 * 100 / 72); // keep default size the same after changing from 100 dpi to 72 dpi
373 }
374 
376 {
377  return new QAndroidPlatformMenuBar;
378 }
379 
381 {
382  return new QAndroidPlatformMenu;
383 }
384 
386 {
387  return new QAndroidPlatformMenuItem;
388 }
389 
391 {
393 }
394 
395 static inline int paletteType(QPlatformTheme::Palette type)
396 {
397  switch (type) {
401 
404 
407 
410 
414 
417 
418  default:
420  }
421 }
422 
424 {
425  if (m_androidStyleData) {
426  auto it = m_androidStyleData->m_palettes.find(paletteType(type));
427  if (it != m_androidStyleData->m_palettes.end())
428  return &(it.value());
429  }
430  return &m_defaultPalette;
431 }
432 
433 static inline int fontType(QPlatformTheme::Font type)
434 {
435  switch (type) {
438 
441 
442  default:
443  return type;
444  }
445 }
446 
448 {
449  if (m_androidStyleData) {
450  auto it = m_androidStyleData->m_fonts.find(fontType(type));
451  if (it != m_androidStyleData->m_fonts.end())
452  return &(it.value());
453  }
454 
456  return &m_systemFont;
457  return 0;
458 }
459 
461 {
462  switch (hint) {
463  case StyleNames:
464  if (qEnvironmentVariableIntValue("QT_USE_ANDROID_NATIVE_STYLE")
465  && m_androidStyleData) {
466  return QStringList(QLatin1String("android"));
467  }
468  return QStringList(QLatin1String("Fusion"));
472  {
473  int minimumDistance = qEnvironmentVariableIntValue("QT_ANDROID_MINIMUM_MOUSE_DOUBLE_CLICK_DISTANCE");
474  int ret = minimumDistance;
475 
476  QAndroidPlatformIntegration *platformIntegration
478  QAndroidPlatformScreen *platformScreen = platformIntegration->screen();
479  if (platformScreen != 0) {
480  QScreen *screen = platformScreen->screen();
481  qreal dotsPerInch = screen->physicalDotsPerInch();
482 
483  // Allow 15% of an inch between clicks when double clicking
484  int distance = qRound(dotsPerInch * 0.15);
485  if (distance > minimumDistance)
486  ret = distance;
487  }
488 
489  if (ret > 0)
490  return ret;
491 
492  Q_FALLTHROUGH();
493  }
494  default:
495  return QPlatformTheme::themeHint(hint);
496  }
497 }
498 
500 {
501  switch (button) {
503  return QCoreApplication::translate("QAndroidPlatformTheme", "Yes");
505  return QCoreApplication::translate("QAndroidPlatformTheme", "Yes to All");
507  return QCoreApplication::translate("QAndroidPlatformTheme", "No");
509  return QCoreApplication::translate("QAndroidPlatformTheme", "No to All");
510  }
512 }
513 
515 {
516  if (type == MessageDialog)
517  return qEnvironmentVariableIntValue("QT_USE_ANDROID_NATIVE_DIALOGS") == 1;
518  if (type == FileDialog)
519  return true;
520  return false;
521 }
522 
524 {
525  switch (type) {
526  case MessageDialog:
528  case FileDialog:
530  default:
531  return 0;
532  }
533 }
534 
Arabic default style
Definition: afstyles.h:94
#define value
[5]
FT_Error error
Definition: cffdrivr.c:657
QAndroidPlatformScreen * screen()
std::shared_ptr< AndroidStyle > m_androidStyle
const QPalette * palette(Palette type=SystemPalette) const override
QVariant themeHint(ThemeHint hint) const override
QAndroidPlatformTheme(QAndroidPlatformNativeInterface *androidPlatformNativeInterface)
QPlatformMenu * createPlatformMenu() const override
QString standardButtonText(int button) const override
QPlatformDialogHelper * createPlatformDialogHelper(DialogType type) const override
const QFont * font(Font type=SystemFont) const override
bool usePlatformNativeDialog(DialogType type) const override
QPlatformMenuItem * createPlatformMenuItem() const override
QPlatformMenuBar * createPlatformMenuBar() const override
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
bool isEmpty() const noexcept
Definition: qbytearray.h:129
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition: qcolor.h:67
QColor darker(int f=200) const noexcept
Definition: qcolor.cpp:2854
QRgb
Definition: qrgb.h:49
QColor lighter(int f=150) const noexcept
Definition: qcolor.cpp:2809
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
bool isNull() const
Definition: qdom.cpp:2124
The QFile class provides an interface for reading from and writing to files.
Definition: qfile.h:94
bool exists() const
Definition: qfileinfo.cpp:697
The QFont class specifies a query for a font used for drawing text.
Definition: qfont.h:56
StyleHint
Definition: qfont.h:59
@ AnyStyle
Definition: qfont.h:65
@ Monospace
Definition: qfont.h:67
@ Serif
Definition: qfont.h:61
@ SansSerif
Definition: qfont.h:60
void setPixelSize(int)
Definition: qfont.cpp:1069
void setBold(bool)
Definition: qfont.h:335
void setItalic(bool b)
Definition: qfont.h:343
void setStyleHint(StyleHint, StyleStrategy=PreferDefault)
Definition: qfont.cpp:1517
@ PreferMatch
Definition: qfont.h:78
static void setFont(const QFont &)
static void setPalette(const QPalette &pal)
static QPlatformIntegration * platformIntegration()
static bool isActive()
The QJsonDocument class provides a way to read and write JSON documents.
Definition: qjsondocument.h:83
static QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error=nullptr)
The QJsonObject::const_iterator class provides an STL-style const iterator for QJsonObject.
Definition: qjsonobject.h:185
QJsonValueRef value() const
Definition: qjsonobject.h:211
The QJsonObject class encapsulates a JSON object.
Definition: qjsonobject.h:56
QVariantMap toVariantMap() const
The QJsonValue class encapsulates a value in JSON.
Definition: qjsonvalue.h:60
QJsonObject toObject() const
Definition: qjsonvalue.cpp:947
QString toString(const QString &defaultValue={}) const
Definition: qjsonvalue.h:181
double toDouble(double defaultValue=0) const
Definition: qjsonvalue.h:180
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
The QPalette class contains color groups for each widget state.
Definition: qpalette.h:55
void setBrush(ColorRole cr, const QBrush &brush)
Definition: qpalette.h:184
@ Current
Definition: qpalette.h:84
@ Inactive
Definition: qpalette.h:84
@ Active
Definition: qpalette.h:84
@ Disabled
Definition: qpalette.h:84
@ HighlightedText
Definition: qpalette.h:88
@ Button
Definition: qpalette.h:86
@ Link
Definition: qpalette.h:89
@ BrightText
Definition: qpalette.h:87
@ Window
Definition: qpalette.h:87
@ Shadow
Definition: qpalette.h:87
@ Base
Definition: qpalette.h:87
@ Text
Definition: qpalette.h:87
@ ButtonText
Definition: qpalette.h:87
@ WindowText
Definition: qpalette.h:86
@ Highlight
Definition: qpalette.h:88
@ Dark
Definition: qpalette.h:86
@ Midlight
Definition: qpalette.h:86
QScreen * screen() const
virtual QVariant themeHint(ThemeHint hint) const
virtual QString standardButtonText(int button) const
The QScreen class is used to query screen properties. \inmodule QtGui.
Definition: qscreen.h:68
qreal physicalDotsPerInch
the number of physical dots or pixels per inch
Definition: qscreen.h:91
The QString class provides a Unicode character string.
Definition: qstring.h:388
QByteArray toLatin1() const &
Definition: qstring.h:745
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:5143
bool isEmpty() const
Definition: qstring.h:1216
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:95
Definition: base.h:37
QDomDocument document
[0]
QPushButton * button
[2]
palette
double pixelDensity()
void openOptionsMenu()
@ black
Definition: qnamespace.h:61
#define Q_FALLTHROUGH()
#define Q_UNLIKELY(x)
QList< QString > QStringList
Definition: qcontainerfwd.h:64
EGLOutputLayerEXT EGLint EGLAttrib value
int qRound(qfloat16 d) noexcept
Definition: qfloat16.h:227
QT_END_INCLUDE_NAMESPACE typedef double qreal
Definition: qglobal.h:341
@ text
#define qCritical
Definition: qlogging.h:180
#define qWarning
Definition: qlogging.h:179
GLenum type
Definition: qopengl.h:270
GLuint64 key
GLfloat GLfloat f
GLsizei GLsizei GLfloat distance
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
QScreen * screen
[1]
Definition: main.cpp:76
QString base
QGraphicsItem * item
QStringList::Iterator it
static QJsonObject loadStyleData()
The QJsonParseError class is used to report errors during JSON parsing.
Definition: qjsondocument.h:56
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:53
void light()