#include <QtWidgets>
#include "iconpreviewarea.h"
#include "iconsizespinbox.h"
#include "imagedelegate.h"
#include "mainwindow.h"
enum { OtherSize = QStyle::PM_CustomBase };
MainWindow::MainWindow()
{
QWidget *centralWidget = new QWidget(this);
setCentralWidget(centralWidget);
createActions();
QGridLayout *mainLayout = new QGridLayout(centralWidget);
QGroupBox *previewGroupBox = new QGroupBox(tr("Preview"));
previewArea = new IconPreviewArea(previewGroupBox);
QVBoxLayout *previewLayout = new QVBoxLayout(previewGroupBox);
previewLayout->addWidget(previewArea);
mainLayout->addWidget(previewGroupBox, 0, 0, 1, 2);
mainLayout->addWidget(createImagesGroupBox(), 1, 0);
QVBoxLayout *vBox = new QVBoxLayout;
vBox->addWidget(createIconSizeGroupBox());
vBox->addWidget(createHighDpiIconSizeGroupBox());
vBox->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding));
mainLayout->addLayout(vBox, 1, 1);
createContextMenu();
setWindowTitle(tr("Icons"));
checkCurrentStyle();
sizeButtonGroup->button(OtherSize)->click();
}
void MainWindow::show()
{
QMainWindow::show();
connect(windowHandle(), &QWindow::screenChanged, this, &MainWindow::screenChanged);
screenChanged();
}
void MainWindow::about()
{
QMessageBox::about(this, tr("About Icons"),
tr("The <b>Icons</b> example illustrates how Qt renders an icon in "
"different modes (active, normal, disabled, and selected) and "
"states (on and off) based on a set of images."));
}
void MainWindow::changeStyle(bool checked)
{
if (!checked)
return;
const QAction *action = qobject_cast<QAction *>(sender());
QStyle *style = QStyleFactory::create(action->data().toString());
Q_ASSERT(style);
QApplication::setStyle(style);
foreach (QAbstractButton *button, sizeButtonGroup->buttons()) {
const QStyle::PixelMetric metric = static_cast<QStyle::PixelMetric>(sizeButtonGroup->id(button));
const int value = style->pixelMetric(metric);
switch (metric) {
case QStyle::PM_SmallIconSize:
button->setText(tr("Small (%1 x %1)").arg(value));
break;
case QStyle::PM_LargeIconSize:
button->setText(tr("Large (%1 x %1)").arg(value));
break;
case QStyle::PM_ToolBarIconSize:
button->setText(tr("Toolbars (%1 x %1)").arg(value));
break;
case QStyle::PM_ListViewIconSize:
button->setText(tr("List views (%1 x %1)").arg(value));
break;
case QStyle::PM_IconViewIconSize:
button->setText(tr("Icon views (%1 x %1)").arg(value));
break;
case QStyle::PM_TabBarIconSize:
button->setText(tr("Tab bars (%1 x %1)").arg(value));
break;
default:
break;
}
}
triggerChangeSize();
}
void MainWindow::changeSize(int id, bool checked)
{
if (!checked)
return;
const bool other = id == int(OtherSize);
const int extent = other
? otherSpinBox->value()
: QApplication::style()->pixelMetric(static_cast<QStyle::PixelMetric>(id));
previewArea->setSize(QSize(extent, extent));
otherSpinBox->setEnabled(other);
}
void MainWindow::triggerChangeSize()
{
changeSize(sizeButtonGroup->checkedId(), true);
}
void MainWindow::changeIcon()
{
QIcon icon;
for (int row = 0; row < imagesTable->rowCount(); ++row) {
const QTableWidgetItem *fileItem = imagesTable->item(row, 0);
const QTableWidgetItem *modeItem = imagesTable->item(row, 1);
const QTableWidgetItem *stateItem = imagesTable->item(row, 2);
if (fileItem->checkState() == Qt::Checked) {
const int modeIndex = IconPreviewArea::iconModeNames().indexOf(modeItem->text());
Q_ASSERT(modeIndex >= 0);
const int stateIndex = IconPreviewArea::iconStateNames().indexOf(stateItem->text());
Q_ASSERT(stateIndex >= 0);
const QIcon::Mode mode = IconPreviewArea::iconModes().at(modeIndex);
const QIcon::State state = IconPreviewArea::iconStates().at(stateIndex);
const QString fileName = fileItem->data(Qt::UserRole).toString();
QImage image(fileName);
if (!image.isNull())
icon.addPixmap(QPixmap::fromImage(image), mode, state);
}
}
previewArea->setIcon(icon);
}
void MainWindow::addSampleImages()
{
addImages(QLatin1String(SRCDIR) + QLatin1String("/images"));
}
void MainWindow::addOtherImages()
{
static bool firstInvocation = true;
QString directory;
if (firstInvocation) {
firstInvocation = false;
directory = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).value(0, QString());
}
addImages(directory);
}
void MainWindow::addImages(const QString &directory)
{
QFileDialog fileDialog(this, tr("Open Images"), directory);
QStringList mimeTypeFilters;
foreach (const QByteArray &mimeTypeName, QImageReader::supportedMimeTypes())
mimeTypeFilters.append(mimeTypeName);
mimeTypeFilters.sort();
fileDialog.setMimeTypeFilters(mimeTypeFilters);
fileDialog.selectMimeTypeFilter(QLatin1String("image/png"));
fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
fileDialog.setFileMode(QFileDialog::ExistingFiles);
if (!nativeFileDialogAct->isChecked())
fileDialog.setOption(QFileDialog::DontUseNativeDialog);
if (fileDialog.exec() == QDialog::Accepted)
loadImages(fileDialog.selectedFiles());
}
void MainWindow::loadImages(const QStringList &fileNames)
{
foreach (const QString &fileName, fileNames) {
const int row = imagesTable->rowCount();
imagesTable->setRowCount(row + 1);
const QFileInfo fileInfo(fileName);
const QString imageName = fileInfo.baseName();
const QString fileName2x = fileInfo.absolutePath()
+ QLatin1Char('/') + imageName + QLatin1String("@2x.") + fileInfo.suffix();
const QFileInfo fileInfo2x(fileName2x);
const QImage image(fileName);
const QString toolTip =
tr("Directory: %1\nFile: %2\nFile@2x: %3\nSize: %4x%5")
.arg(QDir::toNativeSeparators(fileInfo.absolutePath()), fileInfo.fileName())
.arg(fileInfo2x.exists() ? fileInfo2x.fileName() : tr("<None>"))
.arg(image.width()).arg(image.height());
QTableWidgetItem *fileItem = new QTableWidgetItem(imageName);
fileItem->setData(Qt::UserRole, fileName);
fileItem->setIcon(QPixmap::fromImage(image));
fileItem->setFlags((fileItem->flags() | Qt::ItemIsUserCheckable) & ~Qt::ItemIsEditable);
fileItem->setToolTip(toolTip);
QIcon::Mode mode = QIcon::Normal;
QIcon::State state = QIcon::Off;
if (guessModeStateAct->isChecked()) {
if (imageName.contains(QLatin1String("_act"), Qt::CaseInsensitive))
mode = QIcon::Active;
else if (imageName.contains(QLatin1String("_dis"), Qt::CaseInsensitive))
mode = QIcon::Disabled;
else if (imageName.contains(QLatin1String("_sel"), Qt::CaseInsensitive))
mode = QIcon::Selected;
if (imageName.contains(QLatin1String("_on"), Qt::CaseInsensitive))
state = QIcon::On;
}
imagesTable->setItem(row, 0, fileItem);
QTableWidgetItem *modeItem =
new QTableWidgetItem(IconPreviewArea::iconModeNames().at(IconPreviewArea::iconModes().indexOf(mode)));
modeItem->setToolTip(toolTip);
imagesTable->setItem(row, 1, modeItem);
QTableWidgetItem *stateItem =
new QTableWidgetItem(IconPreviewArea::iconStateNames().at(IconPreviewArea::iconStates().indexOf(state)));
stateItem->setToolTip(toolTip);
imagesTable->setItem(row, 2, stateItem);
imagesTable->openPersistentEditor(modeItem);
imagesTable->openPersistentEditor(stateItem);
fileItem->setCheckState(Qt::Checked);
}
}
void MainWindow::useHighDpiPixmapsChanged(int checkState)
{
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, checkState == Qt::Checked);
changeIcon();
}
void MainWindow::removeAllImages()
{
imagesTable->setRowCount(0);
changeIcon();
}
QWidget *MainWindow::createImagesGroupBox()
{
QGroupBox *imagesGroupBox = new QGroupBox(tr("Images"));
imagesTable = new QTableWidget;
imagesTable->setSelectionMode(QAbstractItemView::NoSelection);
imagesTable->setItemDelegate(new ImageDelegate(this));
QStringList labels;
labels << tr("Image") << tr("Mode") << tr("State");
imagesTable->horizontalHeader()->setDefaultSectionSize(90);
imagesTable->setColumnCount(3);
imagesTable->setHorizontalHeaderLabels(labels);
imagesTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
imagesTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed);
imagesTable->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed);
imagesTable->verticalHeader()->hide();
connect(imagesTable, &QTableWidget::itemChanged,
this, &MainWindow::changeIcon);
QVBoxLayout *layout = new QVBoxLayout(imagesGroupBox);
layout->addWidget(imagesTable);
return imagesGroupBox;
}
QWidget *MainWindow::createIconSizeGroupBox()
{
QGroupBox *iconSizeGroupBox = new QGroupBox(tr("Icon Size"));
sizeButtonGroup = new QButtonGroup(this);
sizeButtonGroup->setExclusive(true);
connect(sizeButtonGroup, QOverload<int, bool>::of(&QButtonGroup::buttonToggled),
this, &MainWindow::changeSize);
QRadioButton *smallRadioButton = new QRadioButton;
sizeButtonGroup->addButton(smallRadioButton, QStyle::PM_SmallIconSize);
QRadioButton *largeRadioButton = new QRadioButton;
sizeButtonGroup->addButton(largeRadioButton, QStyle::PM_LargeIconSize);
QRadioButton *toolBarRadioButton = new QRadioButton;
sizeButtonGroup->addButton(toolBarRadioButton, QStyle::PM_ToolBarIconSize);
QRadioButton *listViewRadioButton = new QRadioButton;
sizeButtonGroup->addButton(listViewRadioButton, QStyle::PM_ListViewIconSize);
QRadioButton *iconViewRadioButton = new QRadioButton;
sizeButtonGroup->addButton(iconViewRadioButton, QStyle::PM_IconViewIconSize);
QRadioButton *tabBarRadioButton = new QRadioButton;
sizeButtonGroup->addButton(tabBarRadioButton, QStyle::PM_TabBarIconSize);
QRadioButton *otherRadioButton = new QRadioButton(tr("Other:"));
sizeButtonGroup->addButton(otherRadioButton, OtherSize);
otherSpinBox = new IconSizeSpinBox;
otherSpinBox->setRange(8, 256);
const QString spinBoxToolTip =
tr("Enter a custom size within %1..%2")
.arg(otherSpinBox->minimum()).arg(otherSpinBox->maximum());
otherSpinBox->setValue(64);
otherSpinBox->setToolTip(spinBoxToolTip);
otherRadioButton->setToolTip(spinBoxToolTip);
connect(otherSpinBox, QOverload<int>::of(&QSpinBox::valueChanged),
this, &MainWindow::triggerChangeSize);
QHBoxLayout *otherSizeLayout = new QHBoxLayout;
otherSizeLayout->addWidget(otherRadioButton);
otherSizeLayout->addWidget(otherSpinBox);
otherSizeLayout->addStretch();
QGridLayout *layout = new QGridLayout(iconSizeGroupBox);
layout->addWidget(smallRadioButton, 0, 0);
layout->addWidget(largeRadioButton, 1, 0);
layout->addWidget(toolBarRadioButton, 2, 0);
layout->addWidget(listViewRadioButton, 0, 1);
layout->addWidget(iconViewRadioButton, 1, 1);
layout->addWidget(tabBarRadioButton, 2, 1);
layout->addLayout(otherSizeLayout, 3, 0, 1, 2);
layout->setRowStretch(4, 1);
return iconSizeGroupBox;
}
void MainWindow::screenChanged()
{
devicePixelRatioLabel->setText(QString::number(devicePixelRatioF()));
if (const QWindow *window = windowHandle()) {
const QScreen *screen = window->screen();
const QString screenDescription =
tr("\"%1\" (%2x%3)").arg(screen->name())
.arg(screen->geometry().width()).arg(screen->geometry().height());
screenNameLabel->setText(screenDescription);
}
changeIcon();
}
QWidget *MainWindow::createHighDpiIconSizeGroupBox()
{
QGroupBox *highDpiGroupBox = new QGroupBox(tr("High DPI Scaling"));
QFormLayout *layout = new QFormLayout(highDpiGroupBox);
devicePixelRatioLabel = new QLabel(highDpiGroupBox);
screenNameLabel = new QLabel(highDpiGroupBox);
layout->addRow(tr("Screen:"), screenNameLabel);
layout->addRow(tr("Device pixel ratio:"), devicePixelRatioLabel);
QCheckBox *highDpiPixmapsCheckBox = new QCheckBox(QLatin1String("Qt::AA_UseHighDpiPixmaps"));
highDpiPixmapsCheckBox->setChecked(QCoreApplication::testAttribute(Qt::AA_UseHighDpiPixmaps));
connect(highDpiPixmapsCheckBox, &QCheckBox::stateChanged, this, &MainWindow::useHighDpiPixmapsChanged);
layout->addRow(highDpiPixmapsCheckBox);
return highDpiGroupBox;
}
void MainWindow::createActions()
{
QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
addSampleImagesAct = new QAction(tr("Add &Sample Images..."), this);
addSampleImagesAct->setShortcut(tr("Ctrl+A"));
connect(addSampleImagesAct, &QAction::triggered, this, &MainWindow::addSampleImages);
fileMenu->addAction(addSampleImagesAct);
addOtherImagesAct = new QAction(tr("&Add Images..."), this);
addOtherImagesAct->setShortcut(QKeySequence::Open);
connect(addOtherImagesAct, &QAction::triggered, this, &MainWindow::addOtherImages);
fileMenu->addAction(addOtherImagesAct);
removeAllImagesAct = new QAction(tr("&Remove All Images"), this);
removeAllImagesAct->setShortcut(tr("Ctrl+R"));
connect(removeAllImagesAct, &QAction::triggered,
this, &MainWindow::removeAllImages);
fileMenu->addAction(removeAllImagesAct);
fileMenu->addSeparator();
QAction *exitAct = fileMenu->addAction(tr("&Quit"), this, &QWidget::close);
exitAct->setShortcuts(QKeySequence::Quit);
QMenu *viewMenu = menuBar()->addMenu(tr("&View"));
styleActionGroup = new QActionGroup(this);
foreach (const QString &styleName, QStyleFactory::keys()) {
QAction *action = new QAction(tr("%1 Style").arg(styleName), styleActionGroup);
action->setData(styleName);
action->setCheckable(true);
connect(action, &QAction::triggered, this, &MainWindow::changeStyle);
viewMenu->addAction(action);
}
QMenu *settingsMenu = menuBar()->addMenu(tr("&Settings"));
guessModeStateAct = new QAction(tr("&Guess Image Mode/State"), this);
guessModeStateAct->setCheckable(true);
guessModeStateAct->setChecked(true);
settingsMenu->addAction(guessModeStateAct);
nativeFileDialogAct = new QAction(tr("&Use Native File Dialog"), this);
nativeFileDialogAct->setCheckable(true);
nativeFileDialogAct->setChecked(true);
settingsMenu->addAction(nativeFileDialogAct);
QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(tr("&About"), this, &MainWindow::about);
helpMenu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt);
}
void MainWindow::createContextMenu()
{
imagesTable->setContextMenuPolicy(Qt::ActionsContextMenu);
imagesTable->addAction(addSampleImagesAct);
imagesTable->addAction(addOtherImagesAct);
imagesTable->addAction(removeAllImagesAct);
}
void MainWindow::checkCurrentStyle()
{
foreach (QAction *action, styleActionGroup->actions()) {
QString styleName = action->data().toString();
QScopedPointer<QStyle> candidate(QStyleFactory::create(styleName));
Q_ASSERT(!candidate.isNull());
if (candidate->metaObject()->className()
== QApplication::style()->metaObject()->className()) {
action->trigger();
return;
}
}
}