MicroPythonBitmapTool/MainWindow.cpp

304 wiersze
9.9 KiB
C++

//
// (c)2021 by Lucky Resistor. https://luckyresistor.me/
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
//
#include "MainWindow.hpp"
#include "BitmapPanel.hpp"
#include "ConverterFramebufMonoVLSB.hpp"
#include "ConverterFramebufMonoHLSB.hpp"
#include "ConverterFramebufMonoHMSB.hpp"
#include <QtCore/QSettings>
#include <QtGui/QAction>
#include <QtGui/QClipboard>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QFrame>
#include <QtWidgets/QLabel>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QApplication>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QPlainTextEdit>
#include <QtWidgets/QScrollArea>
#include <QtWidgets/QSplitter>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
initializeConverterList();
initializeUi();
initializeMenu();
loadSettings();
}
MainWindow::~MainWindow()
{
}
void MainWindow::initializeConverterList()
{
_converterList.append(new ConverterFramebufMonoVLSB());
_converterList.append(new ConverterFramebufMonoHMSB());
_converterList.append(new ConverterFramebufMonoHLSB());
}
void MainWindow::initializeUi()
{
setMinimumSize(800, 600);
setWindowTitle(tr("Micropython Bitmap Tool by Lucky Resistor"));
auto centralWidget = new QWidget();
centralWidget->setObjectName("CentralWidget");
setCentralWidget(centralWidget);
auto mainLayout = new QHBoxLayout(centralWidget);
mainLayout->setContentsMargins(0, 0, 0, 0);
auto settingsPanel = new QFrame();
settingsPanel->setObjectName("SettingsPanel");
mainLayout->addWidget(settingsPanel);
auto settingsLayout = new QVBoxLayout(settingsPanel);
settingsLayout->setSpacing(4);
auto logo = new QLabel();
logo->setFixedSize(300, 250);
logo->setPixmap(QPixmap(":/images/AppLogo.png"));
settingsLayout->addWidget(logo);
auto versionLabel = new QLabel(tr("<b>Version %1</b>").arg(qApp->applicationVersion()));
versionLabel->setAlignment(Qt::AlignCenter);
settingsLayout->addWidget(versionLabel);
settingsLayout->addSpacing(16);
settingsLayout->addWidget(new QLabel(tr("Generated Format:")));
_formatSelector = new QComboBox();
for (auto converter : _converterList) {
_formatSelector->addItem(converter->displayName());
}
_formatSelector->setCurrentIndex(0);
settingsLayout->addWidget(_formatSelector);
settingsLayout->addStretch();
settingsLayout->addWidget(new QLabel(tr("<b>Loaded Bitmap Info:</b>")));
_bitmapInfo = new QLabel(tr("No Bitmap Loaded"));
_bitmapInfo->setObjectName("BitmapInfo");
_bitmapInfo->setMinimumHeight(200);
_bitmapInfo->setAlignment(Qt::AlignTop|Qt::AlignLeft);
settingsLayout->addWidget(_bitmapInfo);
auto loadButton = new QPushButton();
loadButton->setText(tr("Load Bitmap"));
settingsLayout->addWidget(loadButton);
connect(loadButton, &QPushButton::clicked, this, &MainWindow::onLoadBitmap);
auto previewSplittter = new QSplitter(Qt::Vertical);
previewSplittter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
previewSplittter->setChildrenCollapsible(false);
mainLayout->addWidget(previewSplittter);
_bitmapPanel = new BitmapPanel();
previewSplittter->addWidget(_bitmapPanel);
auto codePanel = new QWidget();
codePanel->setMinimumHeight(200);
auto codeLayout = new QVBoxLayout(codePanel);
codeLayout->setContentsMargins(16, 4, 16, 16);
codeLayout->setSpacing(4);
codeLayout->addWidget(new QLabel(tr("Generated Code:")));
_codePreview = new QPlainTextEdit();
_codePreview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
_codePreview->setReadOnly(true);
_codePreview->setWordWrapMode(QTextOption::NoWrap);
codeLayout->addWidget(_codePreview);
#ifdef Q_OS_WIN32
_codePreview->setFont(QFont("Consolas", 12));
#else
#ifdef Q_OS_MAC
_codePreview->setFont(QFont("Menlo", 12));
#else
_codePreview->setFont(QFont("Lucida Console", 12));
#endif
#endif
auto codeActions = new QFrame();
auto codeActionsLayout = new QHBoxLayout(codeActions);
codeActionsLayout->setContentsMargins(0, 0, 0, 0);
codeActionsLayout->setSpacing(4);
codeActionsLayout->addStretch();
auto copyCodeButton = new QPushButton();
copyCodeButton->setText(tr("Copy Code"));
codeActionsLayout->addWidget(copyCodeButton);
connect(copyCodeButton, &QPushButton::clicked, [=]{
qApp->clipboard()->setText(_codePreview->toPlainText());
});
codeLayout->addWidget(codeActions);
previewSplittter->addWidget(codePanel);
previewSplittter->setStretchFactor(0, 4);
previewSplittter->setStretchFactor(1, 1);
connect(_formatSelector, &QComboBox::currentIndexChanged, [=]{
_bitmapPanel->setConverter(selectedConverter());
updateBitmapInfo();
updateCode();
});
}
void MainWindow::initializeMenu()
{
auto menuFile = menuBar()->addMenu(tr("File"));
auto actionLoadBitmap = menuFile->addAction(tr("Load Bitmap..."));
actionLoadBitmap->setShortcut(QKeySequence("Ctrl+O"));
connect(actionLoadBitmap, &QAction::triggered, this, &MainWindow::onLoadBitmap);
auto actionQuit = menuFile->addAction(tr("Quit"));
connect(actionQuit, &QAction::triggered, [=]{
qApp->quit();
});
auto menuHelp = menuBar()->addMenu(tr("Help"));
auto actionAbout = menuHelp->addAction(tr("About..."));
connect(actionAbout, &QAction::triggered, [=]{
QMessageBox::about(this, tr("Micropython Bitmap Tool by Lucky Resistor"),
tr("<h1>Micropython Bitmap Tool</h1><p>(c)2021 by Lucky Resistor</p>"
"<p><b>Version %1</b></p>").arg(qApp->applicationVersion()));
});
auto actionAboutQt = menuHelp->addAction(tr("Information About Qt..."));
connect(actionAboutQt, &QAction::triggered, [=]{
QMessageBox::aboutQt(this);
});
}
void MainWindow::loadSettings()
{
QSettings settings;
restoreGeometry(settings.value("mainWindow.geometry").toByteArray());
restoreState(settings.value("mainWindow.state").toByteArray());
_formatSelector->setCurrentIndex(settings.value("format.index").toInt(0));
}
void MainWindow::saveSettings()
{
QSettings settings;
settings.setValue("mainWindow.geometry", saveGeometry());
settings.setValue("mainWindow.state", saveState());
settings.setValue("format.index", _formatSelector->currentIndex());
}
Converter *MainWindow::selectedConverter() const
{
auto converter = _converterList.value(_formatSelector->currentIndex());
if (converter == nullptr) {
converter = _converterList.first();
}
return converter;
}
void MainWindow::updateBitmapInfo()
{
QString text;
QTextStream ts(&text);
ts << "<p>";
ts << "Bitmap Size: " << _currentImage.width() << "x" << _currentImage.height() << "<br>";
ts << "Bit Depth: " << _currentImage.depth() << "<br>";
ts << "Color Format: ";
switch (_currentImage.pixelFormat().colorModel()) {
case QPixelFormat::RGB: ts << "RGB"; break;
case QPixelFormat::BGR: ts << "BGR"; break;
case QPixelFormat::Indexed: ts << "Indexed"; break;
case QPixelFormat::Grayscale: ts << "Grayscale"; break;
case QPixelFormat::CMYK: ts << "CMYK"; break;
case QPixelFormat::HSL: ts << "HSL"; break;
case QPixelFormat::HSV: ts << "HSV"; break;
case QPixelFormat::YUV: ts << "YUV"; break;
case QPixelFormat::Alpha: ts << "Alpha"; break;
}
ts << "<br>";
const auto gs = selectedConverter()->generatedSize(_currentImage.size());
ts << "Generated Size: " << gs.width() << "x" << gs.height() << "</p>";
_bitmapInfo->setText(text);
}
void MainWindow::updateCode()
{
QString code;
if (!_currentImage.isNull()) {
code = selectedConverter()->generateCode(_currentImage, QVariantMap());
}
_codePreview->setPlainText(code);
}
void MainWindow::onLoadBitmap()
{
QSettings settings;
auto lastDir = settings.value("bitmap.lastDir").toString();
auto fileName = QFileDialog::getOpenFileName(
this,
tr("Open Bitmap"),
lastDir,
tr("Images (*.png *.jpg *.jpeg *.gif *.pbm *.pgm *.ppm *.xbm *.xpm *.bpm)"));
if (fileName.isEmpty()) {
return;
}
QFileInfo fileInfo(fileName);
settings.setValue("bitmap.lastDir", fileInfo.absoluteDir().path());
QImage newImage;
if (!newImage.load(fileName)) {
QMessageBox::warning(this, tr("Loading Image Failed"),
tr("<h1>Failed to load the image</h1>"
"<p>Could not load the specified image file. "
"Make sure the image is in a supported format.</p>"));
return;
}
if (newImage.width() > 0x100 || newImage.height() > 0x100) {
QMessageBox::warning(this, tr("Image is Too Large"),
tr("<h1>Image is Too Large</h1>"
"<p>One dimension of the loaded image is larger than "
"256 pixel. This software is designed for small bitmaps.</p>"));
return;
}
_currentImage = newImage;
_bitmapPanel->setImage(newImage);
_bitmapPanel->setConverter(selectedConverter());
updateBitmapInfo();
updateCode();
}
void MainWindow::closeEvent(QCloseEvent *event)
{
saveSettings();
QMainWindow::closeEvent(event);
}