forked from qt-creator/qt-creator
Android: parse image file names from manifest
Also scales splash images without stretching and reflects them to other orientations. Task-number: QTCREATORBUG-24149 Task-number: QTCREATORBUG-24150 Change-Id: Ie23a8ba5f75132971673d3232807e941dfd50f97 Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
@@ -35,9 +35,10 @@ namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
namespace {
|
||||
const QString highDpiIconPath = "/res/drawable-hdpi/icon.png";
|
||||
const QString mediumDpiIconPath = "/res/drawable-mdpi/icon.png";
|
||||
const QString lowDpiIconPath = "/res/drawable-ldpi/icon.png";
|
||||
const QString highDpiIconPath = QLatin1String("/res/drawable-hdpi/");
|
||||
const QString mediumDpiIconPath = QLatin1String("/res/drawable-mdpi/");
|
||||
const QString lowDpiIconPath = QLatin1String("/res/drawable-ldpi/");
|
||||
const QString imageSuffix = QLatin1String(".png");
|
||||
const QSize lowDpiIconSize{32, 32};
|
||||
const QSize mediumDpiIconSize{48, 48};
|
||||
const QSize highDpiIconSize{72, 72};
|
||||
@@ -63,11 +64,15 @@ AndroidManifestEditorIconContainerWidget::AndroidManifestEditorIconContainerWidg
|
||||
iconLayout->addWidget(line);
|
||||
iconLayout->addStretch(1);
|
||||
|
||||
QString iconFileName = m_iconFileName + imageSuffix;
|
||||
|
||||
auto lIconButton = new AndroidManifestEditorIconWidget(this,
|
||||
lowDpiIconSize,
|
||||
lowDpiIconSize,
|
||||
tr("Low DPI icon"), tr("Select low DPI icon"),
|
||||
textEditorWidget, lowDpiIconPath);
|
||||
textEditorWidget,
|
||||
lowDpiIconPath,
|
||||
iconFileName);
|
||||
iconLayout->addWidget(lIconButton);
|
||||
m_iconButtons.push_back(lIconButton);
|
||||
iconLayout->addStretch(1);
|
||||
@@ -76,7 +81,9 @@ AndroidManifestEditorIconContainerWidget::AndroidManifestEditorIconContainerWidg
|
||||
mediumDpiIconSize,
|
||||
mediumDpiIconSize,
|
||||
tr("Medium DPI icon"), tr("Select medium DPI icon"),
|
||||
textEditorWidget, mediumDpiIconPath);
|
||||
textEditorWidget,
|
||||
mediumDpiIconPath,
|
||||
iconFileName);
|
||||
iconLayout->addWidget(mIconButton);
|
||||
m_iconButtons.push_back(mIconButton);
|
||||
iconLayout->addStretch(1);
|
||||
@@ -85,7 +92,9 @@ AndroidManifestEditorIconContainerWidget::AndroidManifestEditorIconContainerWidg
|
||||
highDpiIconSize,
|
||||
highDpiIconSize,
|
||||
tr("High DPI icon"), tr("Select high DPI icon"),
|
||||
textEditorWidget, highDpiIconPath);
|
||||
textEditorWidget,
|
||||
highDpiIconPath,
|
||||
iconFileName);
|
||||
iconLayout->addWidget(hIconButton);
|
||||
m_iconButtons.push_back(hIconButton);
|
||||
iconLayout->addStretch(6);
|
||||
@@ -96,13 +105,25 @@ AndroidManifestEditorIconContainerWidget::AndroidManifestEditorIconContainerWidg
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidManifestEditorIconContainerWidget::loadIcons()
|
||||
void AndroidManifestEditorIconContainerWidget::setIconFileName(const QString &name)
|
||||
{
|
||||
for (auto &&iconButton : m_iconButtons)
|
||||
iconButton->loadIcon();
|
||||
m_iconFileName = name;
|
||||
}
|
||||
|
||||
bool AndroidManifestEditorIconContainerWidget::hasIcons()
|
||||
QString AndroidManifestEditorIconContainerWidget::iconFileName() const
|
||||
{
|
||||
return m_iconFileName;
|
||||
}
|
||||
|
||||
void AndroidManifestEditorIconContainerWidget::loadIcons()
|
||||
{
|
||||
for (auto &&iconButton : m_iconButtons) {
|
||||
iconButton->setTargetIconFileName(m_iconFileName + imageSuffix);
|
||||
iconButton->loadIcon();
|
||||
}
|
||||
}
|
||||
|
||||
bool AndroidManifestEditorIconContainerWidget::hasIcons() const
|
||||
{
|
||||
for (auto &&iconButton : m_iconButtons) {
|
||||
if (iconButton->hasIcon())
|
||||
|
@@ -25,6 +25,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <QWidget>
|
||||
|
||||
@@ -42,10 +43,13 @@ class AndroidManifestEditorIconContainerWidget : public QWidget
|
||||
public:
|
||||
explicit AndroidManifestEditorIconContainerWidget(QWidget *parent,
|
||||
TextEditor::TextEditorWidget *textEditorWidget);
|
||||
void setIconFileName(const QString &name);
|
||||
QString iconFileName() const;
|
||||
void loadIcons();
|
||||
bool hasIcons();
|
||||
bool hasIcons() const;
|
||||
private:
|
||||
QVector<AndroidManifestEditorIconWidget *> m_iconButtons;
|
||||
QString m_iconFileName = QLatin1String("icon");
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -34,6 +34,7 @@
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QLoggingCategory>
|
||||
#include <QPainter>
|
||||
#include <QToolButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
@@ -59,9 +60,11 @@ AndroidManifestEditorIconWidget::AndroidManifestEditorIconWidget(
|
||||
QWidget *parent, const QSize &iconSize, const QSize &buttonSize, const QString &title,
|
||||
const QString &tooltip,
|
||||
TextEditor::TextEditorWidget *textEditorWidget,
|
||||
const QString &targetIconPath)
|
||||
const QString &targetIconPath,
|
||||
const QString &targetIconFileName)
|
||||
: QWidget(parent), m_iconSize(iconSize), m_buttonSize(buttonSize),
|
||||
m_textEditorWidget(textEditorWidget), m_targetIconPath(targetIconPath)
|
||||
m_textEditorWidget(textEditorWidget),
|
||||
m_targetIconPath(targetIconPath), m_targetIconFileName(targetIconFileName)
|
||||
{
|
||||
auto iconLayout = new QVBoxLayout(this);
|
||||
auto iconTitle = new QLabel(title, this);
|
||||
@@ -108,12 +111,9 @@ AndroidManifestEditorIconWidget::AndroidManifestEditorIconWidget(
|
||||
this->setLayout(iconLayout);
|
||||
connect(m_button, &QAbstractButton::clicked,
|
||||
this, &AndroidManifestEditorIconWidget::selectIcon);
|
||||
if (clearButton) {
|
||||
if (clearButton)
|
||||
connect(clearButton, &QAbstractButton::clicked,
|
||||
this, &AndroidManifestEditorIconWidget::removeIcon);
|
||||
connect(clearButton, &QAbstractButton::clicked,
|
||||
this, &AndroidManifestEditorIconWidget::iconRemoved);
|
||||
}
|
||||
this, &AndroidManifestEditorIconWidget::clearIcon);
|
||||
m_iconSelectionText = tooltip;
|
||||
}
|
||||
|
||||
@@ -122,24 +122,27 @@ void AndroidManifestEditorIconWidget::setIcon(const QIcon &icon)
|
||||
m_button->setIcon(icon);
|
||||
}
|
||||
|
||||
void AndroidManifestEditorIconWidget::clearIcon()
|
||||
{
|
||||
removeIcon();
|
||||
iconRemoved();
|
||||
}
|
||||
|
||||
void AndroidManifestEditorIconWidget::loadIcon()
|
||||
{
|
||||
QString baseDir = manifestDir(m_textEditorWidget);
|
||||
QString iconFile = baseDir + m_targetIconPath;
|
||||
QString iconFile = baseDir + m_targetIconPath + m_targetIconFileName;
|
||||
setIconFromPath(iconFile);
|
||||
}
|
||||
|
||||
void AndroidManifestEditorIconWidget::setIconFromPath(const QString &iconPath)
|
||||
{
|
||||
iconSelected(iconPath);
|
||||
if (!m_textEditorWidget)
|
||||
return;
|
||||
m_iconPath = iconPath;
|
||||
QString baseDir = manifestDir(m_textEditorWidget);
|
||||
copyIcon();
|
||||
QString iconFile = baseDir + m_targetIconPath;
|
||||
if (!m_scaled) {
|
||||
QImage original(iconFile);
|
||||
QImage original(iconPath);
|
||||
if (!original.isNull() && m_scaledToOriginalAspectRatio) {
|
||||
if ((original.width() > original.height() && m_buttonSize.height() > m_buttonSize.width())
|
||||
|| (original.height() > original.width() && m_buttonSize.width() > m_buttonSize.height())) {
|
||||
auto width = m_buttonSize.height();
|
||||
@@ -148,9 +151,13 @@ void AndroidManifestEditorIconWidget::setIconFromPath(const QString &iconPath)
|
||||
m_button->setMinimumSize(m_buttonSize);
|
||||
m_button->setMaximumSize(m_buttonSize);
|
||||
m_button->setIconSize(m_buttonSize);
|
||||
auto targetWidth = m_iconSize.height();
|
||||
auto targetHeight = m_iconSize.width();
|
||||
m_iconSize = QSize(targetWidth, targetHeight);
|
||||
}
|
||||
|
||||
}
|
||||
copyIcon();
|
||||
QString iconFile = baseDir + m_targetIconPath + m_targetIconFileName;
|
||||
m_button->setIcon(QIcon(iconFile));
|
||||
}
|
||||
|
||||
@@ -161,12 +168,13 @@ void AndroidManifestEditorIconWidget::selectIcon()
|
||||
if (file.isEmpty())
|
||||
return;
|
||||
setIconFromPath(file);
|
||||
iconSelected(file, this);
|
||||
}
|
||||
|
||||
void AndroidManifestEditorIconWidget::removeIcon()
|
||||
{
|
||||
QString baseDir = manifestDir(m_textEditorWidget);
|
||||
const QString targetPath = baseDir + m_targetIconPath;
|
||||
const QString targetPath = baseDir + m_targetIconPath + m_targetIconFileName;
|
||||
if (targetPath.isEmpty()) {
|
||||
qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot remove icon.";
|
||||
return;
|
||||
@@ -178,14 +186,39 @@ void AndroidManifestEditorIconWidget::removeIcon()
|
||||
m_button->setIcon(QIcon());
|
||||
}
|
||||
|
||||
bool AndroidManifestEditorIconWidget::hasIcon()
|
||||
bool AndroidManifestEditorIconWidget::hasIcon() const
|
||||
{
|
||||
return !m_iconPath.isEmpty();
|
||||
}
|
||||
|
||||
void AndroidManifestEditorIconWidget::setScaled(bool scaled)
|
||||
void AndroidManifestEditorIconWidget::setScaledToOriginalAspectRatio(bool scaled)
|
||||
{
|
||||
m_scaled = scaled;
|
||||
m_scaledToOriginalAspectRatio = scaled;
|
||||
}
|
||||
|
||||
void AndroidManifestEditorIconWidget::setScaledWithoutStretching(bool scaled)
|
||||
{
|
||||
m_scaledWithoutStretching = scaled;
|
||||
}
|
||||
|
||||
void AndroidManifestEditorIconWidget::setTargetIconFileName(const QString &targetIconFileName)
|
||||
{
|
||||
m_targetIconFileName = targetIconFileName;
|
||||
}
|
||||
|
||||
void AndroidManifestEditorIconWidget::setTargetIconPath(const QString &targetIconPath)
|
||||
{
|
||||
m_targetIconPath = targetIconPath;
|
||||
}
|
||||
|
||||
QString AndroidManifestEditorIconWidget::targetIconFileName() const
|
||||
{
|
||||
return m_targetIconFileName;
|
||||
}
|
||||
|
||||
QString AndroidManifestEditorIconWidget::targetIconPath() const
|
||||
{
|
||||
return m_targetIconPath;
|
||||
}
|
||||
|
||||
void AndroidManifestEditorIconWidget::setScaleWarningLabelVisible(bool visible)
|
||||
@@ -194,17 +227,42 @@ void AndroidManifestEditorIconWidget::setScaleWarningLabelVisible(bool visible)
|
||||
m_scaleWarningLabel->setVisible(visible);
|
||||
}
|
||||
|
||||
static QImage scaleWithoutStretching(const QImage& original, const QSize& targetSize)
|
||||
{
|
||||
QImage ret(targetSize, QImage::Format_ARGB32);
|
||||
ret.fill(Qt::white);
|
||||
if (targetSize.height() > targetSize.width()) {
|
||||
// portrait target, scale to width and paint in the vertical middle
|
||||
QImage scaled = original.scaledToWidth(targetSize.width());
|
||||
int heightDiffHalf = (targetSize.height() - scaled.height()) / 2;
|
||||
QPainter painter(&ret);
|
||||
QRect targetRect(0, heightDiffHalf, targetSize.width(), scaled.height());
|
||||
QRect sourceRect(0, 0, scaled.width(), scaled.height());
|
||||
painter.drawImage(targetRect, scaled, sourceRect);
|
||||
} else if (targetSize.width() > targetSize.height()) {
|
||||
// landscape target, scale to height and paint in the horizontal middle
|
||||
QImage scaled = original.scaledToHeight(targetSize.height());
|
||||
int widthDiffHalf = (targetSize.width() - scaled.width()) / 2;
|
||||
QPainter painter(&ret);
|
||||
QRect targetRect(widthDiffHalf, 0, scaled.width(), targetSize.height());
|
||||
QRect sourceRect(0, 0, scaled.width(), scaled.height());
|
||||
painter.drawImage(targetRect, scaled, sourceRect);
|
||||
} else
|
||||
ret = original.scaled(targetSize.width(), targetSize.height(),
|
||||
Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AndroidManifestEditorIconWidget::copyIcon()
|
||||
{
|
||||
if (m_targetIconPath.isEmpty())
|
||||
return;
|
||||
QString baseDir = manifestDir(m_textEditorWidget);
|
||||
const QString targetPath = baseDir + m_targetIconPath;
|
||||
const QString targetPath = baseDir + m_targetIconPath + m_targetIconFileName;
|
||||
if (targetPath.isEmpty()) {
|
||||
qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot copy icon.";
|
||||
return;
|
||||
}
|
||||
QFileInfo targetFile(targetPath);
|
||||
QImage original(m_iconPath);
|
||||
if (m_iconPath != targetPath)
|
||||
removeIcon();
|
||||
@@ -221,15 +279,15 @@ void AndroidManifestEditorIconWidget::copyIcon()
|
||||
m_iconPath.clear();
|
||||
return;
|
||||
}
|
||||
QSize targetSize = m_iconSize;
|
||||
if (m_scaled) {
|
||||
QImage scaled = original.scaled(targetSize.width(), targetSize.height(),
|
||||
Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
setScaleWarningLabelVisible(scaled.width() > original.width() || scaled.height() > original.height());
|
||||
scaled.save(targetPath);
|
||||
} else
|
||||
original.save(targetPath);
|
||||
m_iconPath = m_targetIconPath;
|
||||
QImage scaled;
|
||||
if (!m_scaledWithoutStretching)
|
||||
scaled = original.scaled(m_iconSize.width(), m_iconSize.height(),
|
||||
Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
else
|
||||
scaled = scaleWithoutStretching(original, m_iconSize);
|
||||
setScaleWarningLabelVisible(scaled.width() > original.width() || scaled.height() > original.height());
|
||||
scaled.save(targetPath);
|
||||
m_iconPath = targetPath;
|
||||
} else {
|
||||
m_iconPath.clear();
|
||||
}
|
||||
|
@@ -50,14 +50,21 @@ public:
|
||||
const QString &title,
|
||||
const QString &tooltip,
|
||||
TextEditor::TextEditorWidget *textEditorWidget = nullptr,
|
||||
const QString &targetIconPath = {});
|
||||
const QString &targetIconPath = {},
|
||||
const QString &targetIconFileName = {});
|
||||
void setIcon(const QIcon &icon);
|
||||
void clearIcon();
|
||||
void loadIcon();
|
||||
void setIconFromPath(const QString &iconPath);
|
||||
bool hasIcon();
|
||||
void setScaled(bool scaled);
|
||||
bool hasIcon() const;
|
||||
void setScaledToOriginalAspectRatio(bool scaled);
|
||||
void setScaledWithoutStretching(bool scaled);
|
||||
void setTargetIconFileName(const QString &targetIconFileName);
|
||||
void setTargetIconPath(const QString &targetIconPath);
|
||||
QString targetIconFileName() const;
|
||||
QString targetIconPath() const;
|
||||
signals:
|
||||
void iconSelected(const QString &path);
|
||||
void iconSelected(const QString &path, AndroidManifestEditorIconWidget* iconWidget);
|
||||
void iconRemoved();
|
||||
|
||||
private:
|
||||
@@ -73,8 +80,10 @@ private:
|
||||
TextEditor::TextEditorWidget *m_textEditorWidget = nullptr;
|
||||
QString m_iconPath;
|
||||
QString m_targetIconPath;
|
||||
QString m_targetIconFileName;
|
||||
QString m_iconSelectionText;
|
||||
bool m_scaled = true;
|
||||
bool m_scaledToOriginalAspectRatio = false;
|
||||
bool m_scaledWithoutStretching = false;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -806,9 +806,20 @@ void AndroidManifestEditorWidget::syncToWidgets(const QDomDocument &doc)
|
||||
QDomElement activityElem = applicationElement.firstChildElement(QLatin1String("activity"));
|
||||
m_activityNameLineEdit->setText(activityElem.attribute(QLatin1String("android:label")));
|
||||
|
||||
QString appIconValue = applicationElement.attribute(QLatin1String("android:icon"));
|
||||
if (!appIconValue.isEmpty()) {
|
||||
QLatin1String drawable = QLatin1String("@drawable/");
|
||||
if (appIconValue.startsWith(drawable)) {
|
||||
QString appIconName = appIconValue.mid(drawable.size());
|
||||
m_iconButtons->setIconFileName(appIconName);
|
||||
}
|
||||
}
|
||||
|
||||
QDomElement metadataElem = activityElem.firstChildElement(QLatin1String("meta-data"));
|
||||
enum ActivityParseGuard {none = 0, libName = 1, styleExtract = 2, stickySplash = 4, done = 8};
|
||||
enum ActivityParseGuard {none = 0, libName = 1, styleExtract = 2, stickySplash = 4, splashImages = 8, done = 16};
|
||||
int activityParseGuard = ActivityParseGuard::none;
|
||||
enum SplashImageParseGuard {splashNone = 0, splash = 1, portraitSplash = 2, landscapeSplash = 4, splashDone = 8};
|
||||
int splashParseGuard = SplashImageParseGuard::splashNone;
|
||||
while (!metadataElem.isNull()) {
|
||||
if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.lib_name")
|
||||
&& !(activityParseGuard & ActivityParseGuard::libName)) {
|
||||
@@ -826,6 +837,29 @@ void AndroidManifestEditorWidget::syncToWidgets(const QDomDocument &doc)
|
||||
QString sticky = metadataElem.attribute(QLatin1String("android:value"));
|
||||
m_splashButtons->setSticky(sticky == QLatin1String("true"));
|
||||
activityParseGuard |= ActivityParseGuard::stickySplash;
|
||||
} else if (metadataElem.attribute(QLatin1String("android:name"))
|
||||
.startsWith(QLatin1String("android.app.splash_screen_drawable"))
|
||||
&& !(activityParseGuard & ActivityParseGuard::splashImages)
|
||||
&& !(splashParseGuard & SplashImageParseGuard::splashDone)) {
|
||||
QString attrName = metadataElem.attribute(QLatin1String("android:name"));
|
||||
QLatin1String drawable = QLatin1String("@drawable/");
|
||||
QString splashImageValue = metadataElem.attribute(QLatin1String("android:resource"));
|
||||
QString splashImageName;
|
||||
if (splashImageValue.startsWith(drawable)) {
|
||||
splashImageName = splashImageValue.mid(drawable.size());
|
||||
}
|
||||
if (attrName == QLatin1String("android.app.splash_screen_drawable")) {
|
||||
m_splashButtons->setImageFileName(splashImageName);
|
||||
splashParseGuard |= SplashImageParseGuard::splash;
|
||||
} else if (attrName == QLatin1String("android.app.splash_screen_drawable_portrait")) {
|
||||
m_splashButtons->setPortraitImageFileName(splashImageName);
|
||||
splashParseGuard |= SplashImageParseGuard::portraitSplash;
|
||||
} else if (attrName == QLatin1String("android.app.splash_screen_drawable_landscape")) {
|
||||
m_splashButtons->setLandscapeImageFileName(splashImageName);
|
||||
splashParseGuard |= SplashImageParseGuard::landscapeSplash;
|
||||
}
|
||||
if (splashParseGuard & SplashImageParseGuard::splashDone)
|
||||
activityParseGuard |= ActivityParseGuard::splashImages;
|
||||
}
|
||||
if (activityParseGuard == ActivityParseGuard::done)
|
||||
break;
|
||||
@@ -1066,7 +1100,7 @@ void AndroidManifestEditorWidget::parseApplication(QXmlStreamReader &reader, QXm
|
||||
bool ensureIconAttribute = m_iconButtons->hasIcons();
|
||||
if (ensureIconAttribute) {
|
||||
keys << QLatin1String("android:icon");
|
||||
values << QLatin1String("@drawable/icon");
|
||||
values << (QLatin1String("@drawable/") + m_iconButtons->iconFileName());
|
||||
} else
|
||||
remove << QLatin1String("android:icon");
|
||||
|
||||
@@ -1114,15 +1148,15 @@ void AndroidManifestEditorWidget::parseSplashScreen(QXmlStreamWriter &writer)
|
||||
{
|
||||
if (m_splashButtons->hasImages())
|
||||
writeMetadataElement("android.app.splash_screen_drawable",
|
||||
"android:resource", "@drawable/logo",
|
||||
"android:resource", QLatin1String("@drawable/") + m_splashButtons->imageFileName(),
|
||||
writer);
|
||||
if (m_splashButtons->hasPortraitImages())
|
||||
writeMetadataElement("android.app.splash_screen_drawable_portrait",
|
||||
"android:resource", "@drawable/logo_portrait",
|
||||
"android:resource", QLatin1String("@drawable/") + m_splashButtons->portraitImageFileName(),
|
||||
writer);
|
||||
if (m_splashButtons->hasLandscapeImages())
|
||||
writeMetadataElement("android.app.splash_screen_drawable_landscape",
|
||||
"android:resource", "@drawable/logo_landscape",
|
||||
"android:resource", QLatin1String("@drawable/") + m_splashButtons->landscapeImageFileName(),
|
||||
writer);
|
||||
if (m_splashButtons->isSticky())
|
||||
writeMetadataElement("android.app.splash_screen_sticky",
|
||||
|
@@ -26,25 +26,30 @@
|
||||
#include "splashiconcontainerwidget.h"
|
||||
#include "androidmanifesteditoriconwidget.h"
|
||||
|
||||
#include <texteditor/textdocument.h>
|
||||
#include <texteditor/texteditor.h>
|
||||
#include <utils/utilsicons.h>
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QFileInfo>
|
||||
#include <QTabWidget>
|
||||
#include <QToolButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
namespace {
|
||||
const QString highDpiImagePath = "/res/drawable-hdpi/logo.png";
|
||||
const QString mediumDpiImagePath = "/res/drawable-mdpi/logo.png";
|
||||
const QString lowDpiImagePath = "/res/drawable-ldpi/logo.png";
|
||||
const QString highDpiLandscapeImagePath = "/res/drawable-hdpi/logo_landscape.png";
|
||||
const QString mediumDpiLandscapeImagePath = "/res/drawable-mdpi/logo_landscape.png";
|
||||
const QString lowDpiLandscapeImagePath = "/res/drawable-ldpi/logo_landscape.png";
|
||||
const QString highDpiPortraitImagePath = "/res/drawable-hdpi/logo_portrait.png";
|
||||
const QString mediumDpiPortraitImagePath = "/res/drawable-mdpi/logo_portrait.png";
|
||||
const QString lowDpiPortraitImagePath = "/res/drawable-ldpi/logo_portrait.png";
|
||||
const QString highDpiImagePath = QLatin1String("/res/drawable-hdpi/");
|
||||
const QString mediumDpiImagePath = QLatin1String("/res/drawable-mdpi/");
|
||||
const QString lowDpiImagePath = QLatin1String("/res/drawable-ldpi/");
|
||||
const QString highDpiPortraitImagePath = QLatin1String("/res/drawable-port-hdpi/");
|
||||
const QString mediumDpiPortraitImagePath = QLatin1String("/res/drawable-port-mdpi/");
|
||||
const QString lowDpiPortraitImagePath = QLatin1String("/res/drawable-port-ldpi/");
|
||||
const QString highDpiLandscapeImagePath = QLatin1String("/res/drawable-land-hdpi/");
|
||||
const QString mediumDpiLandscapeImagePath = QLatin1String("/res/drawable-land-mdpi/");
|
||||
const QString lowDpiLandscapeImagePath = QLatin1String("/res/drawable-land-ldpi/");
|
||||
const QString imageSuffix = QLatin1String(".png");
|
||||
const QSize lowDpiImageSize{200, 320};
|
||||
const QSize mediumDpiImageSize{320, 480};
|
||||
const QSize highDpiImageSize{480, 720};
|
||||
@@ -53,6 +58,36 @@ const QSize mediumDpiLandscapeImageSize{480, 320};
|
||||
const QSize highDpiLandscapeImageSize{720, 480};
|
||||
const QSize displaySize{48, 72};
|
||||
const QSize landscapeDisplaySize{72, 48};
|
||||
QString manifestDir(TextEditor::TextEditorWidget *textEditorWidget)
|
||||
{
|
||||
// Get the manifest file's directory from its filepath.
|
||||
return textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
static AndroidManifestEditorIconWidget * addButtonToPage(QWidget *page,
|
||||
const QSize &splashSize, const QSize &splashDisplaySize,
|
||||
const QString &title, const QString &tooltip,
|
||||
TextEditor::TextEditorWidget *textEditorWidget,
|
||||
const QString &splashPath,
|
||||
const QString &splashFileName,
|
||||
QHBoxLayout *iconLayout,
|
||||
QVector<AndroidManifestEditorIconWidget *> &buttonContainer,
|
||||
bool scaledToOriginal,
|
||||
bool scaledWithoutStretching)
|
||||
{
|
||||
auto splashButton = new AndroidManifestEditorIconWidget(page,
|
||||
splashSize,
|
||||
splashDisplaySize,
|
||||
title,
|
||||
tooltip,
|
||||
textEditorWidget,
|
||||
splashPath, splashFileName);
|
||||
splashButton->setScaledToOriginalAspectRatio(scaledToOriginal);
|
||||
splashButton->setScaledWithoutStretching(scaledWithoutStretching);
|
||||
iconLayout->addWidget(splashButton);
|
||||
buttonContainer.push_back(splashButton);
|
||||
return splashButton;
|
||||
}
|
||||
|
||||
static QWidget *createPage(TextEditor::TextEditorWidget *textEditorWidget,
|
||||
@@ -62,45 +97,58 @@ static QWidget *createPage(TextEditor::TextEditorWidget *textEditorWidget,
|
||||
const QSize &splashSize,
|
||||
const QSize &portraitSplashSize,
|
||||
const QSize &landscapeSplashSize,
|
||||
const QString &splashSizeTooltip,
|
||||
const QString &portraitSplashSizeTooltip,
|
||||
const QString &landscapeSplashSizeTooltip,
|
||||
const QString &splashPath,
|
||||
const QString &splashFileName,
|
||||
const QString &portraitSplashPath,
|
||||
const QString &landscapeSplashPath)
|
||||
const QString &portraitSplashFileName,
|
||||
const QString &landscapeSplashPath,
|
||||
const QString &landscapeSplashFileName)
|
||||
{
|
||||
QWidget *page = new QWidget();
|
||||
auto iconLayout = new QHBoxLayout(page);
|
||||
auto splashButton = new AndroidManifestEditorIconWidget(page,
|
||||
splashSize,
|
||||
landscapeDisplaySize,
|
||||
SplashIconContainerWidget::tr("Splash screen"),
|
||||
SplashIconContainerWidget::tr("Select splash screen image"),
|
||||
textEditorWidget, splashPath);
|
||||
splashButton->setScaled(false);
|
||||
iconLayout->addWidget(splashButton);
|
||||
buttonContainer.push_back(splashButton);
|
||||
iconLayout->addStretch(1);
|
||||
auto splashButton= addButtonToPage(page, splashSize, landscapeDisplaySize,
|
||||
SplashIconContainerWidget::tr("Splash screen"),
|
||||
SplashIconContainerWidget::tr("Select splash screen image")
|
||||
+ splashSizeTooltip,
|
||||
textEditorWidget,
|
||||
splashPath, splashFileName + imageSuffix,
|
||||
iconLayout,
|
||||
buttonContainer,
|
||||
true, false);
|
||||
|
||||
auto portraitButton = new AndroidManifestEditorIconWidget(page,
|
||||
portraitSplashSize,
|
||||
displaySize,
|
||||
SplashIconContainerWidget::tr("Portrait splash screen"),
|
||||
SplashIconContainerWidget::tr("Select portrait splash screen image"),
|
||||
textEditorWidget, portraitSplashPath);
|
||||
iconLayout->addWidget(portraitButton);
|
||||
portraitButtonContainer.push_back(portraitButton);
|
||||
iconLayout->addStretch(1);
|
||||
auto portraitButton = addButtonToPage(page, portraitSplashSize, displaySize,
|
||||
SplashIconContainerWidget::tr("Portrait splash screen"),
|
||||
SplashIconContainerWidget::tr("Select portrait splash screen image")
|
||||
+ portraitSplashSizeTooltip,
|
||||
textEditorWidget,
|
||||
portraitSplashPath, portraitSplashFileName + imageSuffix,
|
||||
iconLayout,
|
||||
portraitButtonContainer,
|
||||
false, true);
|
||||
|
||||
auto landscapeButton = new AndroidManifestEditorIconWidget(page,
|
||||
landscapeSplashSize,
|
||||
landscapeDisplaySize,
|
||||
SplashIconContainerWidget::tr("Landscape splash screen"),
|
||||
SplashIconContainerWidget::tr("Select landscape splash screen image"),
|
||||
textEditorWidget, landscapeSplashPath);
|
||||
iconLayout->addWidget(landscapeButton);
|
||||
landscapeButtonContainer.push_back(landscapeButton);
|
||||
iconLayout->addStretch(1);
|
||||
|
||||
iconLayout->addStretch(6);
|
||||
auto landscapeButton = addButtonToPage(page, landscapeSplashSize, landscapeDisplaySize,
|
||||
SplashIconContainerWidget::tr("Landscape splash screen"),
|
||||
SplashIconContainerWidget::tr("Select landscape splash screen image")
|
||||
+ landscapeSplashSizeTooltip,
|
||||
textEditorWidget,
|
||||
landscapeSplashPath, landscapeSplashFileName + imageSuffix,
|
||||
iconLayout,
|
||||
landscapeButtonContainer,
|
||||
false, true);
|
||||
|
||||
auto clearButton = new QToolButton(page);
|
||||
clearButton->setText(SplashIconContainerWidget::tr("Clear all"));
|
||||
iconLayout->addWidget(clearButton);
|
||||
iconLayout->setAlignment(clearButton, Qt::AlignVCenter);
|
||||
SplashIconContainerWidget::connect(clearButton, &QAbstractButton::clicked,
|
||||
splashButton, &AndroidManifestEditorIconWidget::clearIcon);
|
||||
SplashIconContainerWidget::connect(clearButton, &QAbstractButton::clicked,
|
||||
portraitButton, &AndroidManifestEditorIconWidget::clearIcon);
|
||||
SplashIconContainerWidget::connect(clearButton, &QAbstractButton::clicked,
|
||||
landscapeButton, &AndroidManifestEditorIconWidget::clearIcon);
|
||||
return page;
|
||||
}
|
||||
|
||||
@@ -108,7 +156,7 @@ static QWidget *createPage(TextEditor::TextEditorWidget *textEditorWidget,
|
||||
SplashIconContainerWidget::SplashIconContainerWidget(
|
||||
QWidget *parent,
|
||||
TextEditor::TextEditorWidget *textEditorWidget)
|
||||
: QWidget(parent)
|
||||
: QWidget(parent), m_textEditorWidget(textEditorWidget)
|
||||
{
|
||||
auto layout = new QVBoxLayout(this);
|
||||
m_stickyCheck = new QCheckBox(tr("Sticky splash screen"), this);
|
||||
@@ -121,39 +169,55 @@ SplashIconContainerWidget::SplashIconContainerWidget(
|
||||
highDpiImageSize,
|
||||
highDpiImageSize,
|
||||
highDpiLandscapeImageSize,
|
||||
highDpiImagePath, highDpiPortraitImagePath, highDpiLandscapeImagePath);
|
||||
tr(" (480x720)"), tr(" (480x720)"), tr(" (720x480)"),
|
||||
highDpiImagePath, m_imageFileName,
|
||||
highDpiImagePath, m_portraitImageFileName,
|
||||
highDpiImagePath, m_landscapeImageFileName);
|
||||
tab->addTab(hdpiPage, tr("High DPI splash screen"));
|
||||
auto mdpiPage = createPage(textEditorWidget,
|
||||
m_imageButtons, m_portraitImageButtons, m_landscapeImageButtons,
|
||||
mediumDpiImageSize,
|
||||
mediumDpiImageSize,
|
||||
mediumDpiLandscapeImageSize,
|
||||
mediumDpiImagePath, mediumDpiPortraitImagePath, mediumDpiLandscapeImagePath);
|
||||
tr(" (320x480)"), tr(" (320x480)"), tr(" (320x480)"),
|
||||
mediumDpiImagePath, m_imageFileName,
|
||||
mediumDpiImagePath, m_portraitImageFileName,
|
||||
mediumDpiImagePath, m_landscapeImageFileName);
|
||||
tab->addTab(mdpiPage, tr("Medium DPI splash screen"));
|
||||
auto ldpiPage = createPage(textEditorWidget,
|
||||
m_imageButtons, m_portraitImageButtons, m_landscapeImageButtons,
|
||||
lowDpiImageSize,
|
||||
lowDpiImageSize,
|
||||
lowDpiLandscapeImageSize,
|
||||
lowDpiImagePath, lowDpiPortraitImagePath, lowDpiLandscapeImagePath);
|
||||
tr(" (200x320)"), tr(" (200x320)"), tr(" (320x200)"),
|
||||
lowDpiImagePath, m_imageFileName,
|
||||
lowDpiImagePath, m_portraitImageFileName,
|
||||
lowDpiImagePath, m_landscapeImageFileName);
|
||||
tab->addTab(ldpiPage, tr("Low DPI splash screen"));
|
||||
layout->addWidget(m_stickyCheck);
|
||||
layout->setAlignment(m_stickyCheck, Qt::AlignLeft);
|
||||
layout->addWidget(tab);
|
||||
for (auto &&imageButton : m_imageButtons)
|
||||
for (auto &&imageButton : m_imageButtons) {
|
||||
connect(imageButton, &AndroidManifestEditorIconWidget::iconSelected,
|
||||
this, &SplashIconContainerWidget::splashScreensModified);
|
||||
connect(imageButton, &AndroidManifestEditorIconWidget::iconSelected,
|
||||
this, &SplashIconContainerWidget::imageSelected);
|
||||
}
|
||||
for (auto &&imageButton : m_portraitImageButtons) {
|
||||
connect(imageButton, &AndroidManifestEditorIconWidget::iconSelected,
|
||||
this, &SplashIconContainerWidget::splashScreensModified);
|
||||
connect(imageButton, &AndroidManifestEditorIconWidget::iconRemoved,
|
||||
this, &SplashIconContainerWidget::splashScreensModified);
|
||||
connect(imageButton, &AndroidManifestEditorIconWidget::iconSelected,
|
||||
this, &SplashIconContainerWidget::imageSelected);
|
||||
}
|
||||
for (auto &&imageButton : m_landscapeImageButtons) {
|
||||
connect(imageButton, &AndroidManifestEditorIconWidget::iconSelected,
|
||||
this, &SplashIconContainerWidget::splashScreensModified);
|
||||
connect(imageButton, &AndroidManifestEditorIconWidget::iconRemoved,
|
||||
this, &SplashIconContainerWidget::splashScreensModified);
|
||||
connect(imageButton, &AndroidManifestEditorIconWidget::iconSelected,
|
||||
this, &SplashIconContainerWidget::imageSelected);
|
||||
}
|
||||
connect(m_stickyCheck, &QCheckBox::stateChanged, [this](int state) {
|
||||
bool old = m_splashScreenSticky;
|
||||
@@ -163,17 +227,48 @@ SplashIconContainerWidget::SplashIconContainerWidget(
|
||||
});
|
||||
}
|
||||
|
||||
void SplashIconContainerWidget::loadImages()
|
||||
static void maybeChangeImagePath(AndroidManifestEditorIconWidget *widget,
|
||||
TextEditor::TextEditorWidget *m_textEditorWidget,
|
||||
const QString &highDpiAlternativePath,
|
||||
const QString &mediumDpiAlternativePath,
|
||||
const QString &lowDpiAlternativePath)
|
||||
{
|
||||
for (auto &&imageButton : m_imageButtons)
|
||||
imageButton->loadIcon();
|
||||
for (auto &&imageButton : m_portraitImageButtons)
|
||||
imageButton->loadIcon();
|
||||
for (auto &&imageButton : m_landscapeImageButtons)
|
||||
imageButton->loadIcon();
|
||||
QString currentPath = widget->targetIconPath();
|
||||
QString alternativePath = currentPath;
|
||||
if (currentPath == highDpiImagePath)
|
||||
alternativePath = highDpiAlternativePath;
|
||||
else if (currentPath == mediumDpiImagePath)
|
||||
alternativePath = mediumDpiAlternativePath;
|
||||
else if (currentPath == lowDpiImagePath)
|
||||
alternativePath = lowDpiAlternativePath;
|
||||
QString baseDir = manifestDir(m_textEditorWidget);
|
||||
const QString targetPath = baseDir + alternativePath + widget->targetIconFileName();
|
||||
QFileInfo image(targetPath);
|
||||
if (image.exists())
|
||||
widget->setTargetIconPath(alternativePath);
|
||||
}
|
||||
|
||||
bool SplashIconContainerWidget::hasImages()
|
||||
void SplashIconContainerWidget::loadImages()
|
||||
{
|
||||
for (auto &&imageButton : m_imageButtons) {
|
||||
imageButton->setTargetIconFileName(m_imageFileName + imageSuffix);
|
||||
imageButton->loadIcon();
|
||||
}
|
||||
for (auto &&imageButton : m_portraitImageButtons) {
|
||||
imageButton->setTargetIconFileName(m_portraitImageFileName + imageSuffix);
|
||||
maybeChangeImagePath(imageButton, m_textEditorWidget,
|
||||
highDpiPortraitImagePath, mediumDpiPortraitImagePath, lowDpiPortraitImagePath);
|
||||
imageButton->loadIcon();
|
||||
}
|
||||
for (auto &&imageButton : m_landscapeImageButtons) {
|
||||
imageButton->setTargetIconFileName(m_landscapeImageFileName + imageSuffix);
|
||||
maybeChangeImagePath(imageButton, m_textEditorWidget,
|
||||
highDpiLandscapeImagePath, mediumDpiLandscapeImagePath, lowDpiLandscapeImagePath);
|
||||
imageButton->loadIcon();
|
||||
}
|
||||
}
|
||||
|
||||
bool SplashIconContainerWidget::hasImages() const
|
||||
{
|
||||
for (auto &&iconButton : m_imageButtons) {
|
||||
if (iconButton->hasIcon())
|
||||
@@ -182,7 +277,7 @@ bool SplashIconContainerWidget::hasImages()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SplashIconContainerWidget::hasPortraitImages()
|
||||
bool SplashIconContainerWidget::hasPortraitImages() const
|
||||
{
|
||||
for (auto &&iconButton : m_portraitImageButtons) {
|
||||
if (iconButton->hasIcon())
|
||||
@@ -191,7 +286,7 @@ bool SplashIconContainerWidget::hasPortraitImages()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SplashIconContainerWidget::hasLandscapeImages()
|
||||
bool SplashIconContainerWidget::hasLandscapeImages() const
|
||||
{
|
||||
for (auto &&iconButton : m_landscapeImageButtons) {
|
||||
if (iconButton->hasIcon())
|
||||
@@ -200,7 +295,7 @@ bool SplashIconContainerWidget::hasLandscapeImages()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SplashIconContainerWidget::isSticky()
|
||||
bool SplashIconContainerWidget::isSticky() const
|
||||
{
|
||||
return m_splashScreenSticky;
|
||||
}
|
||||
@@ -211,5 +306,72 @@ void SplashIconContainerWidget::setSticky(bool sticky)
|
||||
m_stickyCheck->setCheckState(m_splashScreenSticky ? Qt::Checked : Qt::Unchecked);
|
||||
}
|
||||
|
||||
QString SplashIconContainerWidget::imageFileName() const
|
||||
{
|
||||
return m_imageFileName;
|
||||
}
|
||||
|
||||
QString SplashIconContainerWidget::landscapeImageFileName() const
|
||||
{
|
||||
return m_landscapeImageFileName;
|
||||
}
|
||||
|
||||
QString SplashIconContainerWidget::portraitImageFileName() const
|
||||
{
|
||||
return m_portraitImageFileName;
|
||||
}
|
||||
|
||||
void SplashIconContainerWidget::setImageFileName(const QString &name)
|
||||
{
|
||||
m_imageFileName = name;
|
||||
}
|
||||
|
||||
void SplashIconContainerWidget::setLandscapeImageFileName(const QString &name)
|
||||
{
|
||||
m_landscapeImageFileName = name;
|
||||
}
|
||||
|
||||
void SplashIconContainerWidget::setPortraitImageFileName(const QString &name)
|
||||
{
|
||||
m_portraitImageFileName = name;
|
||||
}
|
||||
|
||||
static void reflectImage(const QString &path,
|
||||
AndroidManifestEditorIconWidget *iconWidget,
|
||||
const QVector<AndroidManifestEditorIconWidget *> &source,
|
||||
QVector<AndroidManifestEditorIconWidget *> *firstTarget,
|
||||
QVector<AndroidManifestEditorIconWidget *> *secondTarget = nullptr,
|
||||
Qt::Orientation *imageOrientation = nullptr)
|
||||
{
|
||||
for (int i = 0; i < source.size(); ++i)
|
||||
if (source[i] == iconWidget) {
|
||||
if (firstTarget && !(*firstTarget)[i]->hasIcon()
|
||||
&& (!imageOrientation || *imageOrientation == Qt::Horizontal))
|
||||
(*firstTarget)[i]->setIconFromPath(path);
|
||||
if (secondTarget && !(*secondTarget)[i]->hasIcon()
|
||||
&& (!imageOrientation || *imageOrientation == Qt::Vertical))
|
||||
(*secondTarget)[i]->setIconFromPath(path);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SplashIconContainerWidget::imageSelected(const QString &path, AndroidManifestEditorIconWidget *iconWidget)
|
||||
{
|
||||
QImage original(path);
|
||||
Qt::Orientation orientation = Qt::Horizontal;
|
||||
if (!original.isNull()) {
|
||||
if (original.width() > original.height()) {
|
||||
orientation = Qt::Horizontal;
|
||||
} else {
|
||||
orientation = Qt::Vertical;
|
||||
}
|
||||
}
|
||||
reflectImage(path, iconWidget,
|
||||
m_imageButtons, &m_portraitImageButtons, &m_landscapeImageButtons, &orientation);
|
||||
reflectImage(path, iconWidget, m_portraitImageButtons, &m_landscapeImageButtons);
|
||||
reflectImage(path, iconWidget, m_landscapeImageButtons, &m_portraitImageButtons);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Android
|
||||
|
@@ -46,21 +46,33 @@ class SplashIconContainerWidget : public QWidget
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SplashIconContainerWidget(QWidget *parent,
|
||||
TextEditor::TextEditorWidget *textEditorWidget);
|
||||
TextEditor::TextEditorWidget *textEditorWidget);
|
||||
void loadImages();
|
||||
bool hasImages();
|
||||
bool hasPortraitImages();
|
||||
bool hasLandscapeImages();
|
||||
bool isSticky();
|
||||
bool hasImages() const;
|
||||
bool hasPortraitImages() const;
|
||||
bool hasLandscapeImages() const;
|
||||
bool isSticky() const;
|
||||
void setSticky(bool sticky);
|
||||
QString imageFileName() const;
|
||||
QString landscapeImageFileName() const;
|
||||
QString portraitImageFileName() const;
|
||||
void setImageFileName(const QString &name);
|
||||
void setLandscapeImageFileName(const QString &name);
|
||||
void setPortraitImageFileName(const QString &name);
|
||||
signals:
|
||||
void splashScreensModified();
|
||||
private:
|
||||
void imageSelected(const QString &path, AndroidManifestEditorIconWidget *iconWidget);
|
||||
private:
|
||||
TextEditor::TextEditorWidget *m_textEditorWidget = nullptr;
|
||||
QVector<AndroidManifestEditorIconWidget *> m_imageButtons;
|
||||
QVector<AndroidManifestEditorIconWidget *> m_portraitImageButtons;
|
||||
QVector<AndroidManifestEditorIconWidget *> m_landscapeImageButtons;
|
||||
bool m_splashScreenSticky = false;
|
||||
QCheckBox *m_stickyCheck = nullptr;
|
||||
QString m_imageFileName = QLatin1String("logo");
|
||||
QString m_landscapeImageFileName = QLatin1String("logo_landscape");
|
||||
QString m_portraitImageFileName = QLatin1String("logo_portrait");
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
Reference in New Issue
Block a user