1
0
Fork 0

Launcher: convert most icons to masked.

Still need to add SVG support, but this improves feedback (eg hover)
for many icons in the launcher. Will remove the redundant PNGs in
another commit once other pieces are done.
This commit is contained in:
James Turner 2021-03-29 15:13:27 +01:00
parent 0b905470d4
commit cec9ab5039
52 changed files with 213 additions and 36 deletions

View file

@ -217,6 +217,8 @@ if (HAVE_QT)
TipBackgroundBox.hxx
GettingStartedScope.hxx
GettingStartedScope.cxx
QmlColoredImageProvider.hxx
QmlColoredImageProvider.cxx
${QQUI_SOURCES}
)

View file

@ -87,8 +87,6 @@ LauncherController::LauncherController(QObject *parent, QWindow* window) :
connect(m_location, &LocationController::descriptionChanged,
this, &LauncherController::summaryChanged);
initQML();
m_aircraftModel = new AircraftItemModel(this);
m_installedAircraftModel = new AircraftProxyModel(this, m_aircraftModel);
m_installedAircraftModel->setInstalledFilterEnabled(true);
@ -158,7 +156,7 @@ LauncherController::LauncherController(QObject *parent, QWindow* window) :
QTimer::singleShot(2000, this, &LauncherController::checkForOldDownloadDir);
}
void LauncherController::initQML()
void LauncherController::initQML(int& styleTypeId)
{
qmlRegisterUncreatableType<LauncherController>("FlightGear.Launcher", 1, 0, "LauncherController", "no");
qmlRegisterUncreatableType<LocationController>("FlightGear.Launcher", 1, 0, "LocationController", "no");
@ -203,6 +201,7 @@ void LauncherController::initQML()
qmlRegisterType<ModelDataExtractor>("FlightGear", 1, 0, "ModelDataExtractor");
qmlRegisterSingletonType(QUrl("qrc:/qml/OverlayShared.qml"), "FlightGear", 1, 0, "OverlayShared");
styleTypeId = qmlRegisterSingletonType(QUrl("qrc:/qml/Style.qml"), "FlightGear", 1, 0, "Style");
qmlRegisterType<GettingStartedScope>("FlightGear", 1, 0, "GettingStartedScope");
qmlRegisterType<GettingStartedTipsController>("FlightGear", 1, 0, "GettingStartedController");

View file

@ -101,7 +101,7 @@ class LauncherController : public QObject
public:
explicit LauncherController(QObject *parent, QWindow* win);
void initQML();
void initQML(int& styleTypeId);
Q_INVOKABLE bool validateMetarString(QString metar);

View file

@ -21,15 +21,16 @@
#include "AddOnsController.hxx"
#include "AircraftItemModel.hxx"
#include "DefaultAircraftLocator.hxx"
#include "GettingStartedTip.hxx"
#include "LaunchConfig.hxx"
#include "LauncherController.hxx"
#include "LauncherNotificationsController.hxx"
#include "LauncherPackageDelegate.hxx"
#include "LocalAircraftCache.hxx"
#include "LocationController.hxx"
#include "QmlColoredImageProvider.hxx"
#include "QtLauncher.hxx"
#include "UpdateChecker.hxx"
#include "GettingStartedTip.hxx"
#include <Main/sentryIntegration.hxx>
@ -40,7 +41,9 @@ LauncherMainWindow::LauncherMainWindow(bool inSimMode) : QQuickView()
setTitle("FlightGear " FLIGHTGEAR_VERSION);
m_controller = new LauncherController(this, this);
m_controller->initQML();
int styleTypeId = 0;
m_controller->initQML(styleTypeId);
// use a direct connection to be notified synchronously when the render thread
// starts OpenGL. We use this to log the OpenGL information from the
@ -49,6 +52,9 @@ LauncherMainWindow::LauncherMainWindow(bool inSimMode) : QQuickView()
this, &LauncherMainWindow::renderTheadSceneGraphInitialized,
Qt::DirectConnection);
m_coloredIconProvider = new QmlColoredImageProvider;
engine()->addImageProvider("colored-icon", m_coloredIconProvider);
if (!inSimMode) {
#if defined(Q_OS_MAC)
QMenuBar* mb = new QMenuBar();
@ -100,6 +106,8 @@ LauncherMainWindow::LauncherMainWindow(bool inSimMode) : QQuickView()
"On Ubuntu/Debian systems, the package is called 'qml-module-qtquick-controls2'"));
}
m_coloredIconProvider->loadStyleColors(engine(), styleTypeId);
connect(this, &QQuickView::statusChanged, this, &LauncherMainWindow::onQuickStatusChanged);
m_controller->initialRestoreSettings();

View file

@ -35,6 +35,7 @@ class LaunchConfig;
class ViewCommandLinePage;
class QQuickItem;
class LauncherController;
class QmlColoredImageProvider;
class LauncherMainWindow : public QQuickView
{
@ -57,6 +58,7 @@ private:
bool checkQQC2Availability();
LauncherController* m_controller;
QmlColoredImageProvider* m_coloredIconProvider;
};
#endif // of LAUNCHER_MAIN_WINDOW_HXX

View file

@ -0,0 +1,96 @@
// Copyright (C) 2021 James Turner <james@flightgear.org>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "QmlColoredImageProvider.hxx"
#include <QDebug>
#include <QQmlComponent>
#include <QQmlEngine>
QmlColoredImageProvider::QmlColoredImageProvider() : QQuickImageProvider(QQmlImageProviderBase::Image)
{
}
void QmlColoredImageProvider::loadStyleColors(QQmlEngine* engine, int styleTypeId)
{
QJSValue styleObject = engine->singletonInstance<QJSValue>(styleTypeId);
if (styleObject.isNull() || !styleObject.isQObject()) {
qWarning() << "Unable to load Style object";
return;
}
_themeColor = QColor{styleObject.property("themeColor").toString()};
_textColor = QColor{styleObject.property("baseTextColor").toString()};
_themeContrastColor = QColor{styleObject.property("themeContrastTextColor").toString()};
_activeColor = QColor{styleObject.property("activeColor").toString()};
_destructiveColor = QColor{styleObject.property("destructiveActionColor").toString()};
}
QImage QmlColoredImageProvider::requestImage(const QString& id, QSize* size, const QSize& requestedSize)
{
QString path = ":/icon/" + id;
QColor c = _themeColor;
auto queryPos = id.indexOf('?');
if (queryPos >= 0) {
path = ":/icon/" + id.left(queryPos); // without the query part
const QString q = id.mid(queryPos + 1);
if (q == "text") {
c = _textColor;
} else if (q == "themeContrast") {
c = _themeContrastColor;
} else if (q == "active") {
c = _activeColor;
} else if (q == "destructive") {
c = _destructiveColor;
} else if (q == "theme") {
// default already
} else {
qWarning() << Q_FUNC_INFO << "Unrecognized color specification:" << id;
}
}
QImage originalImage = QImage{path};
if (originalImage.isNull()) {
qWarning() << Q_FUNC_INFO << "Failed to load image:" << path;
return {};
}
if (!originalImage.isGrayscale()) {
qWarning() << Q_FUNC_INFO << "Source image is not a greyscale mask:" << path;
}
const int baseRed = c.red();
const int baseGreen = c.green();
const int baseBlue = c.blue();
*size = originalImage.size();
// colorize it
QImage colored{originalImage.size(), QImage::Format_ARGB32_Premultiplied};
const int width = size->width();
const int height = size->height();
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
// this is 0..255 ranged alpha/intensity value
const int alpha = originalImage.pixel(x, y);
colored.setPixel(x, y, qPremultiply(qRgba(baseRed, baseGreen, baseBlue, alpha)));
}
}
return colored;
}

View file

@ -0,0 +1,41 @@
// Copyright (C) 2021 James Turner <james@flightgear.org>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#pragma once
#include <QColor>
#include <QQuickImageProvider>
class QQmlEngine;
/**
* @brief Heper image provider to allow re-colorizing
* images based on the active style
*
*/
class QmlColoredImageProvider : public QQuickImageProvider
{
public:
QmlColoredImageProvider();
QImage requestImage(const QString& id, QSize* size, const QSize& requestedSize) override;
void loadStyleColors(QQmlEngine* engine, int styleTypeId);
private:
QColor _themeColor, _textColor, _themeContrastColor, _activeColor;
QColor _destructiveColor;
};

BIN
src/GUI/assets/mask-add.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 769 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 749 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 901 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,005 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 B

View file

@ -1,5 +1,5 @@
import QtQuick 2.4
import "."
import FlightGear 1.0
Rectangle {
id: root
@ -16,7 +16,8 @@ Rectangle {
Text {
id: label
text: qsTr("Add")
color: "white"
color: Style.backgroundColor
anchors {
left: parent.left
leftMargin: Style.margin
@ -28,7 +29,8 @@ Rectangle {
Image {
id: icon
anchors.right: parent.right
source: "qrc:///add-icon"
source: mouse.containsMouse ? "image:///colored-icon/add?active"
: "image:///colored-icon/add?text"
}
MouseArea {

View file

@ -40,7 +40,7 @@ Item {
Image {
id: gearIcon
source: "qrc:///settings-gear-white"
source: "image://colored-icon/settings?themeContrast"
height: root.height - 2
fillMode: Image.PreserveAspectFit
anchors.right: parent.right

View file

@ -62,7 +62,7 @@ Rectangle {
Image {
id: upDownIcon
source: "qrc:///up-down-arrow"
source: headingMouseArea.containsMouse ? "image://colored-icon/up-down?theme" : "image://colored-icon/up-down?text"
// x: root.centerX + Math.min(title.implicitWidth * 0.5, title.width * 0.5)
anchors.verticalCenter: parent.verticalCenter
visible: __enabled

View file

@ -12,7 +12,7 @@ Item {
Image {
id: image
anchors.centerIn: parent
source: "qrc:///back-icon"
source: mouse.containsMouse ? "image://colored-icon/back?active" : "image://colored-icon/back"
}
MouseArea {

View file

@ -154,7 +154,7 @@ FocusScope {
Rectangle {
id: upDownArea
color: "white"
color: Style.backgroundColor
anchors.left: input.right
anchors.verticalCenter: input.verticalCenter
height: upDownIcon.implicitHeight
@ -164,7 +164,7 @@ FocusScope {
Image {
id: upDownIcon
// show up/down arrows
source: "qrc:///up-down-arrow"
source: "image://colored-icon/up-down?text"
}
MouseArea {

View file

@ -183,7 +183,7 @@ FocusScope {
Image {
id: upDownIcon
// show up/down arrows
source: "qrc:///up-down-arrow"
source: "image://colored-icon/up-down?text"
}
MouseArea {

View file

@ -16,7 +16,8 @@ Item {
id: icon
x: 0
y: 0
source: "qrc:///reorder-list-icon-small"
source: promptText.visible ? "image://colored-icon/reorder-small?active"
: "image://colored-icon/reorder-small?text"
}
@ -44,6 +45,7 @@ Item {
}
Text {
id: promptText
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.left
anchors.rightMargin: Style.margin

View file

@ -15,7 +15,7 @@ Item {
id: icon
source: {
var b = mouse.containsMouse ? !root.checked : root.checked;
return b ? "qrc:///favourite-icon-filled" : "qrc:///favourite-icon-outline";
return b ? "image://colored-icon/star-filled?theme" : "image://colored-icon/star-outline?text";
}
anchors.centerIn: parent

View file

@ -8,7 +8,7 @@ Rectangle {
border.color: Style.themeColor
width: height
height: Style.baseFontPixelSize + Style.margin * 2
color: mouse.containsMouse ? Style.minorFrameColor : "white"
color: mouse.containsMouse ? Style.minorFrameColor : Style.backgroundColor
property bool gridMode: false

View file

@ -27,7 +27,7 @@ Item {
Image {
id: icon
source: "qrc:///history-icon"
source: "image://colored-icon/history?themeContrast"
anchors.centerIn: parent
}

View file

@ -8,7 +8,7 @@ Rectangle {
border.color: Style.themeColor
width: height
height: Style.baseFontPixelSize + Style.margin * 2
color: mouse.containsMouse ? Style.minorFrameColor : "white"
color: mouse.containsMouse ? Style.minorFrameColor : Style.backgroundColor
property alias icon: icon.source

View file

@ -181,7 +181,7 @@ FocusScope {
Image {
id: upDownIcon
// show up/down arrows
source: "qrc:///up-down-arrow"
source: "image://colored-icon/up-down?text"
}
MouseArea {

View file

@ -229,17 +229,10 @@ Item {
anchors.top: headerText.bottom
anchors.right: parent.right
anchors.margins: Style.margin
icon: "qrc:///svg/icon-carrier"
icon: root.showCarriers ? "image://colored-icon/carrier2?text"
: "image://colored-icon/airport?text"
onClicked: {
root.showCarriers = ! root.showCarriers;
if (root.showCarriers) {
this.icon = "qrc:///svg/icon-airport"
} else {
this.icon = "qrc:///svg/icon-carrier"
}
}
onClicked: root.showCarriers = ! root.showCarriers;
GettingStartedTip {
tipId: "locationCarriersList"

View file

@ -276,7 +276,7 @@ FocusScope {
Image {
id: upDownIcon
// show up/down arrows
source: "qrc:///up-down-arrow"
source: "image://colored-icon/up-down?text"
}
MouseArea {

View file

@ -87,7 +87,7 @@ Item {
Image {
id: upDownIcon
visible: root.enabled
source: "qrc:///up-down-arrow"
source: mouseArea.containsMouse ? "image://colored-icon/up-down?theme" : "image://colored-icon/up-down?text"
anchors.right: parent.right
anchors.rightMargin: Style.margin
anchors.verticalCenter: parent.verticalCenter

View file

@ -86,7 +86,11 @@ FocusScope
Image {
id: searchIcon
source: root.canClear ? "qrc:///clear-text-icon" :"qrc:///search-icon-small"
// give hover feedback when showing the clear icon
source: clearButtonMouse.containsMouse ? "image://colored-icon/clear?destructive"
: root.canClear ? "image://colored-icon/clear?text" : "image://colored-icon/search?text"
anchors.right: parent.right
anchors.rightMargin: Style.margin
anchors.verticalCenter: parent.verticalCenter

View file

@ -74,7 +74,7 @@ Item {
Text {
id: headerTitle
color: "white"
color: Style.themeContrastTextColor
anchors.verticalCenter: parent.verticalCenter
font.bold: true
font.pixelSize: Style.subHeadingFontPixelSize

View file

@ -43,7 +43,7 @@ Rectangle {
Image {
id: menuIconImage
anchors.centerIn: parent
source: "qrc:///ellipsis-icon"
source: "image://colored-icon/ellipsis?themeContrast"
}
MouseArea {

View file

@ -12,6 +12,7 @@ QtObject
readonly property string frameColor: "#68A6E1"
readonly property string minorFrameColor: "#9f9f9f"
readonly property string backgroundColor: "#ffffff"
readonly property string themeColor: "#1b7ad3"
readonly property string destructiveActionColor: "#c62703"

View file

@ -172,4 +172,31 @@
<file alias="icon-airport">assets/icons8-airport-50.png</file>
<file alias="aircraft-carrier">assets/aircraft-carrier-icon.svg</file>
</qresource>
<qresource prefix="/icon">
<file alias="scroll-down">assets/mask-scroll-down.png</file>
<file alias="history">assets/mask-history.png</file>
<file alias="settings">assets/mask-settings-gear.png</file>
<file alias="search">assets/mask-search.png</file>
<file alias="carrier">assets/mask-aircraft-carrier.png</file>
<file alias="carrier2">assets/mask-carrier2.png</file>
<file alias="map-airplane">assets/mask-airplane.png</file>
<file alias="airport">assets/mask-airport.png</file>
<file alias="arrow-left">assets/mask-arrow-left.png</file>
<file alias="arrow-right">assets/mask-arrow-right.png</file>
<file alias="clear">assets/mask-clear.png</file>
<file alias="cross">assets/mask-cross.png</file>
<file alias="hide">assets/mask-hide.png</file>
<file alias="preview">assets/mask-preview.png</file>
<file alias="up-down">assets/mask-up-down.png</file>
<file alias="star-filled">assets/mask-star-filled.png</file>
<file alias="star-outline">assets/mask-star-outline.png</file>
<file alias="back">assets/mask-back.png</file>
<file alias="cancel-small">assets/mask-cancel-small.png</file>
<file alias="reorder-list">assets/mask-reorder-list.png</file>
<file alias="reorder-small">assets/mask-reorder-small.png</file>
<file alias="cancel">assets/mask-cancel.png</file>
<file alias="add">assets/mask-add.png</file>
<file alias="toolbox-help">assets/mask-toolbox-help.png</file>
<file alias="ellipsis">assets/mask-ellipsis.png</file>
</qresource>
</RCC>