From ea7871f0b6ac18381d4338dbfcfcdd61e26f801e Mon Sep 17 00:00:00 2001 From: Kai Pastor Date: Sat, 25 Aug 2018 09:13:14 +0200 Subject: [PATCH] SymbolPropertiesWidget: Add icon settings tab --- src/CMakeLists.txt | 1 + src/gui/symbols/icon_properties_widget.cpp | 255 +++++++++++++++++++ src/gui/symbols/icon_properties_widget.h | 87 +++++++ src/gui/symbols/symbol_properties_widget.cpp | 9 + src/gui/symbols/symbol_properties_widget.h | 3 + 5 files changed, 355 insertions(+) create mode 100644 src/gui/symbols/icon_properties_widget.cpp create mode 100644 src/gui/symbols/icon_properties_widget.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dff87ce29..147887839 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -121,6 +121,7 @@ set(Mapper_Common_SRCS gui/symbols/area_symbol_settings.cpp gui/symbols/combined_symbol_settings.cpp + gui/symbols/icon_properties_widget.cpp gui/symbols/line_symbol_settings.cpp gui/symbols/point_symbol_editor_widget.cpp gui/symbols/point_symbol_settings.cpp diff --git a/src/gui/symbols/icon_properties_widget.cpp b/src/gui/symbols/icon_properties_widget.cpp new file mode 100644 index 000000000..a2e847ed1 --- /dev/null +++ b/src/gui/symbols/icon_properties_widget.cpp @@ -0,0 +1,255 @@ +/* + * Copyright 2018 Kai Pastor + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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 3 of the License, or + * (at your option) any later version. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + + +#include "icon_properties_widget.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core/symbols/symbol.h" +#include "gui/file_dialog.h" +#include "gui/util_gui.h" +#include "gui/symbols/symbol_setting_dialog.h" +#include "util/backports.h" + +namespace OpenOrienteering { + +namespace { + +QString pngFileFilter() +{ + static const QString filter_template(QLatin1String("%1 (%2)")); + QStringList filters = { + filter_template.arg(::OpenOrienteering::IconPropertiesWidget::tr("PNG"), QLatin1String("*.png")), + ::OpenOrienteering::IconPropertiesWidget::tr("All files (*.*)") + }; + return filters.join(QLatin1String(";;")); +} + + +} // namespace + + + +IconPropertiesWidget::IconPropertiesWidget(Symbol* symbol, SymbolSettingDialog* dialog) +: QWidget(dialog) +, dialog(dialog) +, symbol(symbol) +{ + auto layout = new QFormLayout(); + setLayout(layout); + + layout->addRow(Util::Headline::create(tr("Default icon"))); + + default_icon_size_edit = Util::SpinBox::create(22, 256, tr("px")); + layout->addRow(tr("Preview width:"), default_icon_size_edit); + + layout->addItem(Util::SpacerItem::create(this)); + + auto default_icon_layout = new QHBoxLayout(); + default_icon_display = new QLabel(); + default_icon_display->setFrameStyle(QFrame::Panel); + default_icon_display->setFrameShadow(QFrame::Sunken); + default_icon_display->setLineWidth(2); + default_icon_layout->addWidget(default_icon_display); + default_icon_layout->addStretch(1); + layout->addRow(default_icon_layout); + + layout->addItem(Util::SpacerItem::create(this)); + + auto buttons_layer = new QHBoxLayout(); + save_default_button = new QPushButton(tr("Save...")); + buttons_layer->addWidget(save_default_button); + copy_default_button = new QPushButton(tr("Copy to custom icon")); + buttons_layer->addWidget(copy_default_button); + buttons_layer->addStretch(1); + + layout->addRow(buttons_layer); + + + layout->addItem(Util::SpacerItem::create(this)); + + + layout->addRow(Util::Headline::create(tr("Custom icon"))); + + custom_icon_size_edit = new QLineEdit(); + custom_icon_size_edit->setDisabled(true); + layout->addRow(tr("Width:"), custom_icon_size_edit); + + layout->addItem(Util::SpacerItem::create(this)); + + auto custom_icon_layout = new QHBoxLayout(); + custom_icon_display = new QLabel(); + custom_icon_display->setFrameStyle(QFrame::Panel); + custom_icon_display->setFrameShadow(QFrame::Sunken); + custom_icon_display->setLineWidth(2); + custom_icon_layout->addWidget(custom_icon_display); + custom_icon_layout->addStretch(1); + layout->addRow(custom_icon_layout); + + layout->addItem(Util::SpacerItem::create(this)); + + buttons_layer = new QHBoxLayout(); + save_button = new QPushButton(tr("Save...")); + buttons_layer->addWidget(save_button); + load_button = new QPushButton(tr("Load...")); + buttons_layer->addWidget(load_button); + clear_button = new QPushButton(tr("Clear")); + buttons_layer->addWidget(clear_button); + buttons_layer->addStretch(1); + + layout->addRow(buttons_layer); + + + connect(default_icon_size_edit, QOverload::of(&QSpinBox::valueChanged), this, &IconPropertiesWidget::sizeEdited, Qt::QueuedConnection); + connect(save_default_button, &QAbstractButton::clicked, this, &IconPropertiesWidget::saveClicked); + connect(copy_default_button, &QAbstractButton::clicked, this, &IconPropertiesWidget::copyClicked); + connect(save_button, &QAbstractButton::clicked, this, &IconPropertiesWidget::saveClicked); + connect(load_button, &QAbstractButton::clicked, this, &IconPropertiesWidget::loadClicked); + connect(clear_button, &QAbstractButton::clicked, this, &IconPropertiesWidget::clearClicked); + + updateWidgets(); +} + + +IconPropertiesWidget::~IconPropertiesWidget() = default; + + +void IconPropertiesWidget::reset(Symbol* symbol) +{ + Q_ASSERT(symbol); + this->symbol = symbol; + updateWidgets(); +} + + +void IconPropertiesWidget::updateWidgets() +{ + auto custom_icon = symbol->getCustomIcon(); + symbol->setCustomIcon({}); + auto default_icon = symbol->getIcon(dialog->getSourceMap()); + + default_icon_display->setPixmap(QPixmap::fromImage(default_icon)); + default_icon_size_edit->setValue(default_icon.width()); + + custom_icon_display->setPixmap(QPixmap::fromImage(custom_icon)); + if (custom_icon.isNull()) + { + custom_icon_size_edit->setText(QLatin1String("-")); + save_button->setEnabled(false); + clear_button->setEnabled(false); + } + else + { + custom_icon_size_edit->setText(tr("%1 px").arg(custom_icon.width())); + save_button->setEnabled(true); + clear_button->setEnabled(true); + } + + symbol->setCustomIcon(custom_icon); +} + + +void IconPropertiesWidget::sizeEdited(int size) +{ + if (default_icon_display->pixmap()->width() != size + && dialog->getSourceMap()) + { + auto icon = symbol->createIcon(*dialog->getSourceMap(), size); + default_icon_display->setPixmap(QPixmap::fromImage(icon)); + } +} + + +void IconPropertiesWidget::copyClicked() +{ + auto icon = default_icon_display->pixmap()->toImage(); + if (symbol->getCustomIcon() != icon) + { + symbol->setCustomIcon(icon); + updateWidgets(); + emit iconModified(); + } +} + + +void IconPropertiesWidget::saveClicked() +{ + auto path = FileDialog::getSaveFileName(this, tr("Save symbol icon ..."), {}, pngFileFilter()); + if (path.isEmpty()) + return; + + if (!path.endsWith(QLatin1String(".png", Qt::CaseInsensitive))) + path.append(QLatin1String(".png")); + + auto icon = symbol->getCustomIcon(); + if (icon.isNull() || sender() == save_default_button) + icon = default_icon_display->pixmap()->toImage(); + + QImageWriter writer{path}; + if (!writer.write(icon)) + { + QMessageBox::warning(this, tr("Error"), + tr("Failed to save the image:\n%1") + .arg(writer.errorString()) ); + } +} + + +void IconPropertiesWidget::loadClicked() +{ + auto path = FileDialog::getOpenFileName(this, tr("Load symbol icon ..."), {}, pngFileFilter()); + if (path.isEmpty()) + return; + + QImageReader reader{path}; + auto icon = reader.read(); + if (icon.isNull()) + { + QMessageBox::warning(this, tr("Error"), + tr("Cannot open file:\n%1\n\n%2"). + arg(path, reader.errorString()) ); + return; + } + + symbol->setCustomIcon(icon); + updateWidgets(); + emit iconModified(); +} + + +void IconPropertiesWidget::clearClicked() +{ + symbol->setCustomIcon({}); + updateWidgets(); + emit iconModified(); +} + + + +} // namespace OpenOrienteering diff --git a/src/gui/symbols/icon_properties_widget.h b/src/gui/symbols/icon_properties_widget.h new file mode 100644 index 000000000..0d9b3005e --- /dev/null +++ b/src/gui/symbols/icon_properties_widget.h @@ -0,0 +1,87 @@ +/* + * Copyright 2018 Kai Pastor + * + * This file is part of OpenOrienteering. + * + * OpenOrienteering 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 3 of the License, or + * (at your option) any later version. + * + * OpenOrienteering 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 OpenOrienteering. If not, see . + */ + + +#ifndef OPENORIENTEERING_ICON_PROPERTIES_WIDGET_H +#define OPENORIENTEERING_ICON_PROPERTIES_WIDGET_H + +#include + +#include "gui/symbols/symbol_properties_widget.h" + +class QAbstractButton; +class QLabel; +class QSpinBox; +class QLineEdit; + +namespace OpenOrienteering { + +class Map; +class Symbol; + + +/** + * A widget for modifying symbol icons. + */ +class IconPropertiesWidget : public QWidget +{ + Q_OBJECT + +public: + explicit IconPropertiesWidget(Symbol* symbol, SymbolSettingDialog* dialog = nullptr); + + ~IconPropertiesWidget() override; + + void reset(Symbol* symbol); + +signals: + void iconModified(); + +protected: + void updateWidgets(); + + void sizeEdited(int size); + + void copyClicked(); + + void saveClicked(); + + void loadClicked(); + + void clearClicked(); + +private: + SymbolSettingDialog* const dialog; + Symbol* symbol; + + QLabel* default_icon_display; + QSpinBox* default_icon_size_edit; + QLabel* custom_icon_display; + QLineEdit* custom_icon_size_edit; + QAbstractButton* save_default_button; + QAbstractButton* copy_default_button; + QAbstractButton* save_button; + QAbstractButton* load_button; + QAbstractButton* clear_button; +}; + + +} // namespace OpenOrienteering + +#endif // OPENORIENTEERING_ICON_PROPERTIES_WIDGET_H diff --git a/src/gui/symbols/symbol_properties_widget.cpp b/src/gui/symbols/symbol_properties_widget.cpp index cb63727ad..fbe08c613 100644 --- a/src/gui/symbols/symbol_properties_widget.cpp +++ b/src/gui/symbols/symbol_properties_widget.cpp @@ -41,6 +41,7 @@ #include "core/map.h" #include "core/symbols/symbol.h" +#include "gui/symbols/icon_properties_widget.h" #include "gui/symbols/symbol_setting_dialog.h" #include "util/translation_util.h" #include "util/backports.h" @@ -77,6 +78,9 @@ SymbolPropertiesWidget::SymbolPropertiesWidget(Symbol* symbol, SymbolSettingDial auto description_label = new QLabel(tr("Description:")); description_edit = new QTextEdit(); helper_symbol_check = new QCheckBox(tr("Helper symbol (not shown in finished map)")); + + icon_widget = new IconPropertiesWidget(symbol, dialog); // before reset() + SymbolPropertiesWidget::reset(symbol); for (auto editor : number_editors) @@ -124,6 +128,9 @@ SymbolPropertiesWidget::SymbolPropertiesWidget(Symbol* symbol, SymbolSettingDial layout->addWidget(helper_symbol_check, row, col, 1, num_col); addPropertiesGroup(tr("General"), generalTab); + + connect(icon_widget, &IconPropertiesWidget::iconModified, this, &SymbolPropertiesWidget::propertiesModified); + addPropertiesGroup(tr("Icon"), icon_widget); } @@ -337,6 +344,8 @@ void SymbolPropertiesWidget::reset(Symbol* symbol) } updateTextEdits(); helper_symbol_check->setChecked(symbol->isHelperSymbol()); + + icon_widget->reset(symbol); } diff --git a/src/gui/symbols/symbol_properties_widget.h b/src/gui/symbols/symbol_properties_widget.h index bd39351da..e12c1258d 100644 --- a/src/gui/symbols/symbol_properties_widget.h +++ b/src/gui/symbols/symbol_properties_widget.h @@ -38,6 +38,7 @@ class QWidget; namespace OpenOrienteering { +class IconPropertiesWidget; class Symbol; class SymbolSettingDialog; @@ -105,6 +106,8 @@ protected slots: QLineEdit* name_edit; QTextEdit* description_edit; QCheckBox* helper_symbol_check; + + IconPropertiesWidget* icon_widget; };