Adding a framework to generate code for fonts.
- Work in progress to add a framework generating bitmap fonts.main
rodzic
3c46483bcb
commit
0018e4e9db
|
@ -0,0 +1,67 @@
|
|||
//
|
||||
// (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 "ApplicationController.hpp"
|
||||
|
||||
|
||||
ApplicationController *ApplicationController::_instance = nullptr;
|
||||
|
||||
|
||||
ApplicationController::ApplicationController(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
_instance = this;
|
||||
|
||||
// Start as soon the main loop is running.
|
||||
QMetaObject::invokeMethod(this, &ApplicationController::start, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
|
||||
QFont ApplicationController::monospaceFont() const
|
||||
{
|
||||
QFont monospaceFont;
|
||||
#ifdef Q_OS_WIN32
|
||||
monospaceFont = QFont("Consolas", 12);
|
||||
#else
|
||||
#ifdef Q_OS_MAC
|
||||
monospaceFont = QFont("Menlo", 12);
|
||||
#else
|
||||
monospaceFont = QFont("Lucida Console", 12);
|
||||
#endif
|
||||
#endif
|
||||
return monospaceFont;
|
||||
}
|
||||
|
||||
|
||||
void ApplicationController::start()
|
||||
{
|
||||
_mainWindow = new MainWindow();
|
||||
_mainWindow->show();
|
||||
}
|
||||
|
||||
|
||||
ApplicationController *ApplicationController::instance()
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
|
||||
|
||||
ApplicationController* gApp()
|
||||
{
|
||||
return ApplicationController::instance();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// (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/>.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "MainWindow.hpp"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
|
||||
/// The application controller
|
||||
///
|
||||
class ApplicationController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/// ctor
|
||||
///
|
||||
explicit ApplicationController(QObject *parent = nullptr);
|
||||
|
||||
public:
|
||||
/// Get the default monospaced font.
|
||||
///
|
||||
QFont monospaceFont() const;
|
||||
|
||||
public:
|
||||
/// Get the global instance.
|
||||
///
|
||||
static ApplicationController* instance();
|
||||
|
||||
private:
|
||||
/// Start the application.
|
||||
///
|
||||
Q_SLOT void start();
|
||||
|
||||
private:
|
||||
static ApplicationController *_instance; ///< The controller instance.
|
||||
MainWindow *_mainWindow; ///< The main window.
|
||||
};
|
||||
|
||||
|
||||
ApplicationController* gApp();
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// (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 "BitmapConverter.hpp"
|
||||
|
||||
|
||||
BitmapConverter::BitmapConverter(const QString &displayName)
|
||||
: Converter(displayName)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Converter::Mode BitmapConverter::mode() const
|
||||
{
|
||||
return Mode::Bitmap;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// (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/>.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "Converter.hpp"
|
||||
|
||||
|
||||
/// The base class for all bitmap converters.
|
||||
///
|
||||
class BitmapConverter : public Converter
|
||||
{
|
||||
public:
|
||||
/// ctor
|
||||
///
|
||||
BitmapConverter(const QString &displayName);
|
||||
|
||||
public: // implement Converter
|
||||
Mode mode() const override;
|
||||
|
||||
public:
|
||||
/// Generate the code from the given image.
|
||||
///
|
||||
/// @param image The image to convert.
|
||||
/// @param parameter A map with parameters passed to this converter.
|
||||
/// @return The generated code.
|
||||
///
|
||||
virtual QString generateCode(const QImage &image, const QVariantMap ¶meter) const = 0;
|
||||
};
|
||||
|
||||
|
|
@ -17,16 +17,19 @@
|
|||
#include "BitmapPanel.hpp"
|
||||
|
||||
|
||||
#include "ApplicationController.hpp"
|
||||
#include "Converter.hpp"
|
||||
#include "BitmapPreview.hpp"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QLabel>
|
||||
#include <QScrollArea>
|
||||
#include <QVBoxLayout>
|
||||
#include <QtWidgets/QComboBox>
|
||||
#include <QtWidgets/QLabel>
|
||||
#include <QtWidgets/QScrollArea>
|
||||
#include <QtWidgets/QVBoxLayout>
|
||||
#include <QtWidgets/QPushButton>
|
||||
|
||||
|
||||
BitmapPanel::BitmapPanel(QWidget *parent) : QWidget(parent)
|
||||
BitmapPanel::BitmapPanel(QWidget *parent)
|
||||
: QWidget(parent), _converter(nullptr)
|
||||
{
|
||||
initializeUi();
|
||||
}
|
||||
|
@ -35,16 +38,49 @@ BitmapPanel::BitmapPanel(QWidget *parent) : QWidget(parent)
|
|||
void BitmapPanel::setImage(const QImage &image)
|
||||
{
|
||||
_bitmapPreview->setImage(image);
|
||||
_bitmapPreview->setFixedSize(_bitmapPreview->sizeHint());
|
||||
}
|
||||
|
||||
|
||||
void BitmapPanel::setConverter(const Converter *converter)
|
||||
{
|
||||
_bitmapPreview->setConverter(converter);
|
||||
if (_converter != converter) {
|
||||
_converter = converter;
|
||||
_bitmapPreview->setConverter(converter);
|
||||
_bitmapPreview->setFixedSize(_bitmapPreview->sizeHint());
|
||||
_characterSelector->setVisible(_converter->mode() == Converter::Mode::Font);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BitmapPanel::setCharacters(const QString &characters)
|
||||
{
|
||||
if (_characters != characters) {
|
||||
_characters = characters;
|
||||
_characterSelector->clear();
|
||||
for (int i = 0; i < characters.size(); ++i) {
|
||||
const auto c = _characters.at(i);
|
||||
_characterSelector->addItem(QString("%1: %2 0x%3").arg(i, 3, 10, QChar('0'))
|
||||
.arg(QString(c)).arg(c.unicode(), 4, 16, QChar('0')), c);
|
||||
}
|
||||
_characterSelector->setCurrentIndex(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BitmapPanel::setParameter(const QVariantMap ¶meter)
|
||||
{
|
||||
_bitmapPreview->setParameter(parameter);
|
||||
_bitmapPreview->setFixedSize(_bitmapPreview->sizeHint());
|
||||
}
|
||||
|
||||
|
||||
QChar BitmapPanel::selectedCharacter() const
|
||||
{
|
||||
return _characterSelector->currentData().toChar();
|
||||
}
|
||||
|
||||
|
||||
void BitmapPanel::initializeUi()
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
|
@ -72,6 +108,35 @@ void BitmapPanel::initializeUi()
|
|||
auto previewSettingsLayout = new QHBoxLayout(previewSettingsPanel);
|
||||
previewSettingsLayout->setContentsMargins(0, 0, 0, 0);
|
||||
previewSettingsLayout->setSpacing(4);
|
||||
|
||||
_fontConversionTools = new QFrame();
|
||||
auto fontConversionLayout = new QHBoxLayout(_fontConversionTools);
|
||||
fontConversionLayout->setContentsMargins(0, 0, 0, 0);
|
||||
fontConversionLayout->setSpacing(2);
|
||||
previewSettingsLayout->addWidget(_fontConversionTools);
|
||||
|
||||
auto previousCharButton = new QPushButton("<");
|
||||
fontConversionLayout->addWidget(previousCharButton);
|
||||
_characterSelector = new QComboBox();
|
||||
_characterSelector->setFont(gApp()->monospaceFont());
|
||||
fontConversionLayout->addWidget(_characterSelector);
|
||||
auto nextCharButton = new QPushButton(">");
|
||||
fontConversionLayout->addWidget(nextCharButton);
|
||||
connect(_characterSelector, &QComboBox::currentIndexChanged, [=]{
|
||||
Q_EMIT selectedCharacterChanged(_characterSelector->currentData().toChar());
|
||||
});
|
||||
connect(previousCharButton, &QPushButton::clicked, [=]{
|
||||
auto currentIndex = _characterSelector->currentIndex();
|
||||
if (currentIndex > 0) {
|
||||
_characterSelector->setCurrentIndex(currentIndex - 1);
|
||||
}
|
||||
});
|
||||
connect(nextCharButton, &QPushButton::clicked, [=]{
|
||||
auto currentIndex = _characterSelector->currentIndex();
|
||||
if (currentIndex < (_characterSelector->count()-1)) {
|
||||
_characterSelector->setCurrentIndex(currentIndex + 1);
|
||||
}
|
||||
});
|
||||
previewSettingsLayout->addStretch();
|
||||
previewSettingsLayout->addWidget(new QLabel(tr("Overlay Mode:")));
|
||||
_overlaySelector = new QComboBox();
|
||||
|
|
|
@ -23,13 +23,18 @@
|
|||
class BitmapPreview;
|
||||
class Converter;
|
||||
class QComboBox;
|
||||
class QFrame;
|
||||
|
||||
|
||||
/// A panel with the scrollable bitmap preview.
|
||||
///
|
||||
class BitmapPanel : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/// Create the panel.
|
||||
///
|
||||
explicit BitmapPanel(QWidget *parent = nullptr);
|
||||
|
||||
public:
|
||||
|
@ -41,11 +46,34 @@ public:
|
|||
///
|
||||
void setConverter(const Converter *converter);
|
||||
|
||||
private:
|
||||
void initializeUi();
|
||||
/// Set the current character set.
|
||||
///
|
||||
void setCharacters(const QString &characters);
|
||||
|
||||
/// Set the current parameter.
|
||||
///
|
||||
void setParameter(const QVariantMap ¶meter);
|
||||
|
||||
/// Get the current selected character
|
||||
///
|
||||
QChar selectedCharacter() const;
|
||||
|
||||
private:
|
||||
/// Initialize all UI elements.
|
||||
///
|
||||
void initializeUi();
|
||||
|
||||
Q_SIGNALS:
|
||||
/// Emitted if the selected character changes.
|
||||
///
|
||||
void selectedCharacterChanged(QChar c);
|
||||
|
||||
private:
|
||||
const Converter *_converter; ///< The current converter.
|
||||
QString _characters; ///< The list of characters to convert.
|
||||
BitmapPreview *_bitmapPreview; ///< The bitmap preview;
|
||||
QFrame *_fontConversionTools; ///< The area with tools for font conversion.
|
||||
QComboBox *_characterSelector; ///< The selector for a single character.
|
||||
QComboBox *_overlaySelector; ///< The selector for the overlays.
|
||||
};
|
||||
|
||||
|
|
|
@ -48,9 +48,7 @@ void BitmapPreview::setImage(const QImage &image)
|
|||
if (_image != image) {
|
||||
_image = image;
|
||||
_pixmap = QPixmap::fromImage(image);
|
||||
if (_converter != nullptr) {
|
||||
setGeneratedSize(_converter->generatedSize(_image.size()));
|
||||
}
|
||||
updateGeneratedSize();
|
||||
recalculate();
|
||||
update();
|
||||
}
|
||||
|
@ -80,9 +78,18 @@ void BitmapPreview::setConverter(const Converter *converter)
|
|||
{
|
||||
if (_converter != converter) {
|
||||
_converter = converter;
|
||||
if (_converter != nullptr) {
|
||||
setGeneratedSize(_converter->generatedSize(_image.size()));
|
||||
}
|
||||
updateGeneratedSize();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BitmapPreview::setParameter(const QVariantMap ¶meter)
|
||||
{
|
||||
if (_parameter != parameter) {
|
||||
_parameter = parameter;
|
||||
updateGeneratedSize();
|
||||
recalculate();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
@ -118,7 +125,7 @@ void BitmapPreview::paintEvent(QPaintEvent *pe)
|
|||
p.setOpacity(1.0);
|
||||
p.translate(x, y);
|
||||
OverlayPainter op(&p, pe->rect(), _displayFactor, _pixmap.size(), _generatedSize);
|
||||
_converter->paintOverlay(op, _overlayMode, _image);
|
||||
_converter->paintOverlay(op, _overlayMode, _image, _parameter);
|
||||
}
|
||||
} else {
|
||||
p.setPen(Qt::white);
|
||||
|
@ -134,6 +141,16 @@ void BitmapPreview::resizeEvent(QResizeEvent *e)
|
|||
}
|
||||
|
||||
|
||||
void BitmapPreview::updateGeneratedSize()
|
||||
{
|
||||
if (_converter != nullptr && _converter->mode() == Converter::Mode::Bitmap) {
|
||||
setGeneratedSize(_converter->generatedSize(_image.size(), _parameter));
|
||||
} else {
|
||||
setGeneratedSize(_image.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BitmapPreview::recalculate()
|
||||
{
|
||||
if (_pixmap.isNull()) {
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <QtWidgets/QWidget>
|
||||
#include <QtGui/QImage>
|
||||
#include <QtGui/QPixmap>
|
||||
#include <QtCore/QVariantMap>
|
||||
|
||||
|
||||
class Converter;
|
||||
|
@ -49,6 +50,10 @@ public:
|
|||
///
|
||||
void setConverter(const Converter *converter);
|
||||
|
||||
/// Set the current parameter.
|
||||
///
|
||||
void setParameter(const QVariantMap ¶meter);
|
||||
|
||||
public:
|
||||
QSize sizeHint() const override;
|
||||
QSize minimumSizeHint() const override;
|
||||
|
@ -58,6 +63,10 @@ protected: // QWidget interface
|
|||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
/// update the generated size
|
||||
///
|
||||
void updateGeneratedSize();
|
||||
|
||||
/// Recalculate all sizes
|
||||
///
|
||||
void recalculate();
|
||||
|
@ -74,5 +83,6 @@ private:
|
|||
QSize _minimumSize; ///< The preferred size of this widget.
|
||||
OverlayMode _overlayMode; ///< The overlay mode.
|
||||
const Converter *_converter; ///< The current converter.
|
||||
QVariantMap _parameter; ///< The current set of parameter.
|
||||
};
|
||||
|
||||
|
|
|
@ -29,12 +29,18 @@ QString Converter::displayName() const
|
|||
}
|
||||
|
||||
|
||||
QSize Converter::generatedSize(const QSize &imageSize) const
|
||||
QSize Converter::generatedSize(const QSize &imageSize, const QVariantMap&) const
|
||||
{
|
||||
return imageSize;
|
||||
}
|
||||
|
||||
|
||||
ParameterDefinitionPtr Converter::createParameterDefinition() const
|
||||
{
|
||||
return ParameterDefinition::create();
|
||||
}
|
||||
|
||||
|
||||
LegendDataPtr Converter::legendData(OverlayMode) const
|
||||
{
|
||||
auto ld = LegendData::create();
|
||||
|
@ -43,7 +49,7 @@ LegendDataPtr Converter::legendData(OverlayMode) const
|
|||
}
|
||||
|
||||
|
||||
void Converter::paintOverlay(OverlayPainter &op, OverlayMode, const QImage&) const
|
||||
void Converter::paintOverlay(OverlayPainter &op, OverlayMode, const QImage&, const QVariantMap&) const
|
||||
{
|
||||
op.drawPixelOutline(op.imageRect(), colorBitmapSizeOriginal, 1, 2);
|
||||
if (op.generatedSize().isValid() && !op.generatedSize().isEmpty()) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "LegendData.hpp"
|
||||
#include "OverlayPainter.hpp"
|
||||
#include "OverlayMode.hpp"
|
||||
#include "ParameterDefinition.hpp"
|
||||
|
||||
#include <QtGui/QImage>
|
||||
#include <QtCore/QObject>
|
||||
|
@ -30,10 +31,17 @@
|
|||
///
|
||||
class Converter
|
||||
{
|
||||
public:
|
||||
enum class Mode {
|
||||
Bitmap,
|
||||
Font
|
||||
};
|
||||
|
||||
public:
|
||||
/// Create a new converter.
|
||||
///
|
||||
/// @param displayName The name displayed in the UI for this coonverter.
|
||||
/// @param mode The converter mode.
|
||||
///
|
||||
Converter(const QString &displayName);
|
||||
|
||||
|
@ -46,21 +54,21 @@ public:
|
|||
///
|
||||
QString displayName() const;
|
||||
|
||||
/// Get the mode for this converter.
|
||||
///
|
||||
virtual Mode mode() const = 0;
|
||||
|
||||
public:
|
||||
/// Return the size of the generated bitmap data.
|
||||
///
|
||||
/// @param imageSize The size of the image.
|
||||
/// @return The size of the generated bitmap data.
|
||||
///
|
||||
virtual QSize generatedSize(const QSize &imageSize) const;
|
||||
virtual QSize generatedSize(const QSize &imageSize, const QVariantMap ¶meter) const;
|
||||
|
||||
/// Generate the code from the given image.
|
||||
/// Create the parameter definition for the converter.
|
||||
///
|
||||
/// @param image The image to convert.
|
||||
/// @param parameter A map with parameters passed to this converter.
|
||||
/// @return The generated code.
|
||||
///
|
||||
virtual QString generateCode(const QImage &image, const QVariantMap ¶meter) const = 0;
|
||||
virtual ParameterDefinitionPtr createParameterDefinition() const;
|
||||
|
||||
/// Return a legend for the bitmap preview.
|
||||
///
|
||||
|
@ -71,8 +79,9 @@ public:
|
|||
/// @param p The painter.
|
||||
/// @param mode The overlay mode (never `None`).
|
||||
/// @param image The image.
|
||||
/// @param parameter The current set of parameter.
|
||||
///
|
||||
virtual void paintOverlay(OverlayPainter &p, OverlayMode mode, const QImage &image) const;
|
||||
virtual void paintOverlay(OverlayPainter &p, OverlayMode mode, const QImage &image, const QVariantMap ¶meter) const;
|
||||
|
||||
protected:
|
||||
/// The color for the image frame.
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
|
||||
ConverterFramebuf::ConverterFramebuf(const QString &displayName)
|
||||
: Converter(displayName)
|
||||
: BitmapConverter(displayName)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -17,12 +17,12 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
#include "Converter.hpp"
|
||||
#include "BitmapConverter.hpp"
|
||||
|
||||
|
||||
/// Base class of framebuf converters.
|
||||
///
|
||||
class ConverterFramebuf : public Converter
|
||||
class ConverterFramebuf : public BitmapConverter
|
||||
{
|
||||
public:
|
||||
ConverterFramebuf(const QString &displayName);
|
||||
|
|
|
@ -25,124 +25,29 @@ ConverterFramebufMono::ConverterFramebufMono(
|
|||
int unitSize)
|
||||
:
|
||||
ConverterFramebuf(displayName),
|
||||
_unitOrientation(unitOrientation),
|
||||
_bitDirection(bitDirection),
|
||||
_unitSize(unitSize)
|
||||
MonoTools(unitOrientation, bitDirection, unitSize)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
QSize ConverterFramebufMono::generatedSize(const QSize &imageSize) const
|
||||
QSize ConverterFramebufMono::generatedSize(const QSize &imageSize, const QVariantMap ¶meter) const
|
||||
{
|
||||
if (_unitOrientation == UnitOrientation::Vertical) {
|
||||
if ((imageSize.height() % _unitSize) != 0) {
|
||||
return QSize(imageSize.width(), ((imageSize.height()/_unitSize)+1)*_unitSize);
|
||||
} else {
|
||||
return imageSize;
|
||||
}
|
||||
} else {
|
||||
if ((imageSize.width() % _unitSize) != 0) {
|
||||
return QSize(((imageSize.width()/_unitSize)+1)*_unitSize, imageSize.height());
|
||||
} else {
|
||||
return imageSize;
|
||||
}
|
||||
}
|
||||
return monoGeneratedSize(imageSize, parameter);
|
||||
}
|
||||
|
||||
|
||||
LegendDataPtr ConverterFramebufMono::legendData(OverlayMode mode) const
|
||||
{
|
||||
auto data = ConverterFramebuf::legendData(mode);
|
||||
if (mode == OverlayMode::BitAssigments) {
|
||||
data->addEntry(colorBitAssignment1, colorBitAssignment2, QObject::tr("Bit Assignment"));
|
||||
} else {
|
||||
data->addEntry(colorPixelInterpretation, QObject::tr("Pixel Interpretation"));
|
||||
}
|
||||
addMonoLegendData(data, mode);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
void ConverterFramebufMono::paintOverlay(OverlayPainter &p, OverlayMode mode, const QImage &image) const
|
||||
void ConverterFramebufMono::paintOverlay(OverlayPainter &p, OverlayMode mode, const QImage &image, const QVariantMap ¶meter) const
|
||||
{
|
||||
ConverterFramebuf::paintOverlay(p, mode, image);
|
||||
if (mode == OverlayMode::BitAssigments) {
|
||||
const auto bitL = (_bitDirection == BitDirection::LSB ? "0" : QString::number(_unitSize-1));
|
||||
const auto bitH = (_bitDirection == BitDirection::LSB ? QString::number(_unitSize-1) : "0");
|
||||
bool colorFlag = false;
|
||||
if (_unitOrientation == UnitOrientation::Vertical) {
|
||||
for (int y = 0; y < p.imageSize().height(); y += _unitSize) {
|
||||
for (int x = 0; x < p.imageSize().width(); ++x) {
|
||||
QRect rect(x, y, 1, _unitSize);
|
||||
if (p.arePixelUpdated(rect)) {
|
||||
const auto color = colorFlag ? colorBitAssignment1 : colorBitAssignment2;
|
||||
p.drawPixelOutline(rect, color, 1);
|
||||
p.drawPixelText(QRect(x, y, 1, 1), color, bitL);
|
||||
p.drawPixelText(QRect(x, y+_unitSize-1, 1, 1), color, bitH);
|
||||
}
|
||||
colorFlag = !colorFlag;
|
||||
}
|
||||
if (p.imageSize().width() % 2 == 0) {
|
||||
colorFlag = !colorFlag;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int y = 0; y < p.imageSize().height(); ++y) {
|
||||
for (int x = 0; x < p.imageSize().width(); x += _unitSize) {
|
||||
QRect rect(x, y, _unitSize, 1);
|
||||
if (p.arePixelUpdated(rect)) {
|
||||
const auto color = colorFlag ? colorBitAssignment1 : colorBitAssignment2;
|
||||
p.drawPixelOutline(rect, color, 1);
|
||||
p.drawPixelText(QRect(x, y, 1, 1), color, bitH);
|
||||
p.drawPixelText(QRect(x+_unitSize-1, y, 1, 1), color, bitL);
|
||||
}
|
||||
colorFlag = !colorFlag;
|
||||
}
|
||||
if ((p.imageSize().width()/_unitSize) % 2 == 0) {
|
||||
colorFlag = !colorFlag;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (mode == OverlayMode::PixelInterpretation) {
|
||||
for (int y = 0; y < p.generatedSize().height(); ++y) {
|
||||
for (int x = 0; x < p.generatedSize().width(); ++x) {
|
||||
auto text = (getPixel(x, y, image) ? "1" : "0");
|
||||
const QRect rect(x, y, 1, 1);
|
||||
if (p.arePixelUpdated(rect)) {
|
||||
p.drawPixelText(rect, colorPixelInterpretation, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ConverterFramebufMono::getPixel(int x, int y, const QImage &image)
|
||||
{
|
||||
if (x < 0 || y < 0 || x >= image.width() || y >= image.height()) {
|
||||
return false;
|
||||
}
|
||||
auto color = image.pixelColor(x, y);
|
||||
float h, s, l, a;
|
||||
color.getHslF(&h, &s, &l, &a);
|
||||
if (a < 0.5) {
|
||||
return false;
|
||||
}
|
||||
return l < 0.5;
|
||||
}
|
||||
|
||||
|
||||
uint32_t ConverterFramebufMono::readUnit(int x, int y, int dx, int dy, int count, const QImage &image)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
result <<= 1;
|
||||
if (getPixel(x, y, image)) {
|
||||
result |= 0b1;
|
||||
}
|
||||
x += dx;
|
||||
y += dy;
|
||||
}
|
||||
return result;
|
||||
ConverterFramebuf::paintOverlay(p, mode, image, parameter);
|
||||
monoPaintOverlay(p, mode, image, parameter);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -17,24 +17,14 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
#include "MonoTools.hpp"
|
||||
#include "ConverterFramebuf.hpp"
|
||||
|
||||
|
||||
/// The base class of all mono converters
|
||||
///
|
||||
class ConverterFramebufMono : public ConverterFramebuf
|
||||
class ConverterFramebufMono : public ConverterFramebuf, public MonoTools
|
||||
{
|
||||
protected:
|
||||
enum class UnitOrientation {
|
||||
Horizontal,
|
||||
Vertical
|
||||
};
|
||||
|
||||
enum class BitDirection {
|
||||
LSB,
|
||||
MSB
|
||||
};
|
||||
|
||||
public:
|
||||
/// Create a new mono converter.
|
||||
///
|
||||
|
@ -49,30 +39,8 @@ public:
|
|||
int unitSize);
|
||||
|
||||
public: // Converter interface
|
||||
QSize generatedSize(const QSize &imageSize) const override;
|
||||
QSize generatedSize(const QSize &imageSize, const QVariantMap ¶meter) const override;
|
||||
LegendDataPtr legendData(OverlayMode mode) const override;
|
||||
void paintOverlay(OverlayPainter &p, OverlayMode mode, const QImage &image) const override;
|
||||
|
||||
protected:
|
||||
/// Interpret a single pixel.
|
||||
///
|
||||
/// Returns `false` if the pixel is out of bounds.
|
||||
///
|
||||
static bool getPixel(int x, int y, const QImage &image);
|
||||
|
||||
/// Read a single unit.
|
||||
///
|
||||
static uint32_t readUnit(int x, int y, int dx, int dy, int count, const QImage &image);
|
||||
|
||||
/// The colors for the bit assignments
|
||||
///
|
||||
static constexpr QColor colorBitAssignment1 = QColor(240, 40, 40);
|
||||
static constexpr QColor colorBitAssignment2 = QColor(240, 80, 80);
|
||||
static constexpr QColor colorPixelInterpretation = QColor(240, 240, 40);
|
||||
|
||||
protected:
|
||||
UnitOrientation _unitOrientation; ///< The unit orientatioon.
|
||||
BitDirection _bitDirection; ///< The bit direction.
|
||||
int _unitSize; ///< The number of bits per unit.
|
||||
void paintOverlay(OverlayPainter &p, OverlayMode mode, const QImage &image, const QVariantMap ¶meter) const override;
|
||||
};
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ ConverterFramebufMonoHLSB::ConverterFramebufMonoHLSB()
|
|||
}
|
||||
|
||||
|
||||
QString ConverterFramebufMonoHLSB::generateCode(const QImage &image, const QVariantMap&) const
|
||||
QString ConverterFramebufMonoHLSB::generateCode(const QImage &image, const QVariantMap ¶meter) const
|
||||
{
|
||||
QByteArray data;
|
||||
for (int y = 0; y < image.height(); ++y) {
|
||||
|
@ -34,5 +34,5 @@ QString ConverterFramebufMonoHLSB::generateCode(const QImage &image, const QVari
|
|||
data.append(static_cast<uint8_t>(readUnit(x, y, 1, 0, 8, image)));
|
||||
}
|
||||
}
|
||||
return createCode(data, generatedSize(image.size()), "MONO_HLSB");
|
||||
return createCode(data, generatedSize(image.size(), parameter), "MONO_HLSB");
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ ConverterFramebufMonoHMSB::ConverterFramebufMonoHMSB()
|
|||
}
|
||||
|
||||
|
||||
QString ConverterFramebufMonoHMSB::generateCode(const QImage &image, const QVariantMap&) const
|
||||
QString ConverterFramebufMonoHMSB::generateCode(const QImage &image, const QVariantMap ¶meter) const
|
||||
{
|
||||
QByteArray data;
|
||||
for (int y = 0; y < image.height(); ++y) {
|
||||
|
@ -31,6 +31,6 @@ QString ConverterFramebufMonoHMSB::generateCode(const QImage &image, const QVari
|
|||
data.append(static_cast<uint8_t>(readUnit(x+7, y, -1, 0, 8, image)));
|
||||
}
|
||||
}
|
||||
return createCode(data, generatedSize(image.size()), "MONO_HMSB");
|
||||
return createCode(data, generatedSize(image.size(), parameter), "MONO_HMSB");
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ ConverterFramebufMonoVLSB::ConverterFramebufMonoVLSB()
|
|||
}
|
||||
|
||||
|
||||
QString ConverterFramebufMonoVLSB::generateCode(const QImage &image, const QVariantMap&) const
|
||||
QString ConverterFramebufMonoVLSB::generateCode(const QImage &image, const QVariantMap ¶meter) const
|
||||
{
|
||||
QByteArray data;
|
||||
for (int y = 0; y < image.height(); y += 8) {
|
||||
|
@ -31,6 +31,6 @@ QString ConverterFramebufMonoVLSB::generateCode(const QImage &image, const QVari
|
|||
data.append(static_cast<uint8_t>(readUnit(x, y+7, 0, -1, 8, image)));
|
||||
}
|
||||
}
|
||||
return createCode(data, generatedSize(image.size()), "MONO_VLSB");
|
||||
return createCode(data, generatedSize(image.size(), parameter), "MONO_VLSB");
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
//
|
||||
// (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 "FontConverter.hpp"
|
||||
|
||||
|
||||
FontConverter::FontConverter(const QString &displayName)
|
||||
: Converter(displayName)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Converter::Mode FontConverter::mode() const
|
||||
{
|
||||
return Mode::Font;
|
||||
}
|
||||
|
||||
|
||||
ParameterDefinitionPtr FontConverter::createParameterDefinition() const
|
||||
{
|
||||
auto pd = Converter::createParameterDefinition();
|
||||
pd->addIntegerSize("maximumSize", QObject::tr("Maximum Size"),
|
||||
QSize(12, 16), QSize(8, 8), QSize(256, 256));
|
||||
pd->addIntegerPosition("charOffset", QObject::tr("Char Offset"),
|
||||
QPoint(0, 0), QPoint(-256, -256), QPoint(256, 256));
|
||||
pd->addCheckbox("convertMono", QObject::tr("Convert to Mono"), false);
|
||||
pd->addInteger("convertMonoThreshold", QObject::tr("Conversion Threshold"), 128, 0, 255);
|
||||
pd->addCheckbox("preferBitmapFont", QObject::tr("Prefer Bitmap Font"), false);
|
||||
pd->addCheckbox("noAntialiasFont", QObject::tr("No Antialias Font"), false);
|
||||
pd->addCheckbox("trimLeft", QObject::tr("Trim Left Side"), true);
|
||||
pd->addCheckbox("trimRight", QObject::tr("Trim Right Side"), true);
|
||||
pd->addCheckbox("invertFont", QObject::tr("Invert the Font"), false);
|
||||
return pd;
|
||||
}
|
||||
|
||||
|
||||
QImage FontConverter::generateImage(const QFont &font, QChar c, const QVariantMap ¶meter) const
|
||||
{
|
||||
auto maximumSize = parameter["maximumSize"].toSize();
|
||||
if (!maximumSize.isValid() || maximumSize.isNull()) {
|
||||
maximumSize = QSize(8, 8);
|
||||
}
|
||||
const auto charOffset = parameter["charOffset"].toPoint();
|
||||
QImage result(maximumSize, QImage::Format_ARGB32_Premultiplied);
|
||||
result.setDevicePixelRatio(1.0);
|
||||
QPainter p;
|
||||
p.begin(&result);
|
||||
p.fillRect(result.rect(), Qt::white);
|
||||
p.setRenderHint(QPainter::TextAntialiasing, false);
|
||||
auto fontForDrawing = font;
|
||||
int fontStyleStrategy = 0;
|
||||
if (parameter["preferBitmapFont"].toBool()) {
|
||||
fontStyleStrategy |= QFont::PreferBitmap;
|
||||
}
|
||||
if (parameter["noAntialiasFont"].toBool()) {
|
||||
fontStyleStrategy |= QFont::NoAntialias;
|
||||
}
|
||||
fontStyleStrategy |= QFont::NoSubpixelAntialias;
|
||||
fontForDrawing.setStyleStrategy(static_cast<QFont::StyleStrategy>(fontStyleStrategy));
|
||||
QFontMetrics fontMetrics(fontForDrawing);
|
||||
auto charBoundingRect = fontMetrics.boundingRect(c);
|
||||
// Make sure the first pixel is in the bitmap, draw baseline at ascent.
|
||||
QPoint targetPoint(-charBoundingRect.left(), fontMetrics.ascent());
|
||||
targetPoint += charOffset;
|
||||
p.setFont(fontForDrawing);
|
||||
p.drawText(targetPoint, QString(c));
|
||||
p.end();
|
||||
// Postprocess the font.
|
||||
const auto threshold = static_cast<unsigned int>(parameter["convertMonoThreshold"].toInt());
|
||||
if (parameter["convertMono"].toBool()) {
|
||||
for (int x = 0; x < result.width(); ++x) {
|
||||
for (int y = 0; y < result.height(); ++y) {
|
||||
const auto pixel = result.pixel(x, y);
|
||||
if ((pixel & 0xff) <= threshold) {
|
||||
result.setPixel(x, y, qRgb(0, 0, 0));
|
||||
} else {
|
||||
result.setPixel(x, y, qRgb(255, 255, 255));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Trim the font.
|
||||
const auto trimLeft = parameter["trimLeft"].toBool();
|
||||
const auto trimRight = parameter["trimRight"].toBool();
|
||||
if (trimLeft || trimRight) {
|
||||
auto resultRect = result.rect();
|
||||
int leftTrim = 0;
|
||||
int rightTrim = 0;
|
||||
if (trimLeft) {
|
||||
for (int x = 0; x < result.width(); ++x) {
|
||||
bool hasPixelSet = false;
|
||||
for (int y = 0; y < result.height(); ++y) {
|
||||
const auto pixel = result.pixel(x, y);
|
||||
if ((pixel & 0xff) <= threshold) {
|
||||
hasPixelSet = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasPixelSet) {
|
||||
break;
|
||||
}
|
||||
leftTrim += 1;
|
||||
}
|
||||
}
|
||||
if (trimRight) {
|
||||
for (int x = result.width()-1; x >= 0; --x) {
|
||||
bool hasPixelSet = false;
|
||||
for (int y = 0; y < result.width(); ++y) {
|
||||
const auto pixel = result.pixel(x, y);
|
||||
if ((pixel & 0xff) <= threshold) {
|
||||
hasPixelSet = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasPixelSet) {
|
||||
break;
|
||||
}
|
||||
rightTrim += 1;
|
||||
}
|
||||
}
|
||||
if ((resultRect.width() - leftTrim - rightTrim) <= 0) {
|
||||
// The font image is empty, use one pixel line.
|
||||
resultRect.setWidth(1);
|
||||
} else {
|
||||
resultRect = resultRect.marginsRemoved(QMargins(leftTrim, 0, rightTrim, 0));
|
||||
}
|
||||
if (resultRect != result.rect()) {
|
||||
result = result.copy(resultRect);
|
||||
}
|
||||
}
|
||||
// Invert the font.
|
||||
if (parameter["invertFont"].toBool()) {
|
||||
result.invertPixels();
|
||||
}
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
//
|
||||
// (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/>.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "Converter.hpp"
|
||||
|
||||
|
||||
/// The base class for all font converters.
|
||||
///
|
||||
class FontConverter : public Converter
|
||||
{
|
||||
public:
|
||||
/// ctor
|
||||
///
|
||||
FontConverter(const QString &displayName);
|
||||
|
||||
public: // implement Converter
|
||||
Mode mode() const override;
|
||||
ParameterDefinitionPtr createParameterDefinition() const override;
|
||||
|
||||
public:
|
||||
/// Create a bitmap for a given character.
|
||||
///
|
||||
/// This method should return the given character in exact the size and format it will
|
||||
/// be converted as bitmap.
|
||||
///
|
||||
/// @param font The font for the character.
|
||||
/// @param c The character to convert.
|
||||
/// @param parameter The current map of parameters.
|
||||
///
|
||||
virtual QImage generateImage(const QFont &font, QChar c, const QVariantMap ¶meter) const;
|
||||
|
||||
/// Generate the code from the given font.
|
||||
///
|
||||
/// The string with all characters to convert is passed as parameter 'characters'.
|
||||
///
|
||||
/// @param font The font to convert.
|
||||
/// @param parameter A map with parameters passed to this converter.
|
||||
/// @return The generated code.
|
||||
///
|
||||
virtual QString generateCode(const QFont &font, const QVariantMap ¶meter) const = 0;
|
||||
};
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
//
|
||||
// (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 "FontConverterFramebufMono.hpp"
|
||||
|
||||
|
||||
FontConverterFramebufMono::FontConverterFramebufMono()
|
||||
:
|
||||
FontConverter("MicroPython Font Mono VLSB"),
|
||||
MonoTools(UnitOrientation::Vertical, BitDirection::LSB, 8)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
QSize FontConverterFramebufMono::generatedSize(const QSize &imageSize, const QVariantMap ¶meter) const
|
||||
{
|
||||
return monoGeneratedSize(imageSize, parameter);
|
||||
}
|
||||
|
||||
|
||||
QString FontConverterFramebufMono::generateCode(const QFont&, const QVariantMap&) const
|
||||
{
|
||||
return "The generated format is not decided yet.";
|
||||
}
|
||||
|
||||
|
||||
LegendDataPtr FontConverterFramebufMono::legendData(OverlayMode mode) const
|
||||
{
|
||||
auto data = FontConverter::legendData(mode);
|
||||
addMonoLegendData(data, mode);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
void FontConverterFramebufMono::paintOverlay(OverlayPainter &p, OverlayMode mode, const QImage &image, const QVariantMap ¶meter) const
|
||||
{
|
||||
FontConverter::paintOverlay(p, mode, image, parameter);
|
||||
monoPaintOverlay(p, mode, image, parameter);
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// (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/>.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "FontConverter.hpp"
|
||||
#include "MonoTools.hpp"
|
||||
|
||||
|
||||
/// A simple converter to create mono bitmap fonts.
|
||||
///
|
||||
class FontConverterFramebufMono : public FontConverter, public MonoTools
|
||||
{
|
||||
public:
|
||||
/// ctor
|
||||
///
|
||||
FontConverterFramebufMono();
|
||||
|
||||
public: // implement FontConverter
|
||||
QSize generatedSize(const QSize &imageSize, const QVariantMap ¶meter) const override;
|
||||
QString generateCode(const QFont &font, const QVariantMap ¶meter) const override;
|
||||
LegendDataPtr legendData(OverlayMode mode) const override;
|
||||
void paintOverlay(OverlayPainter &p, OverlayMode mode, const QImage &image, const QVariantMap ¶meter) const override;
|
||||
};
|
||||
|
334
MainWindow.cpp
334
MainWindow.cpp
|
@ -17,10 +17,12 @@
|
|||
#include "MainWindow.hpp"
|
||||
|
||||
|
||||
#include "ApplicationController.hpp"
|
||||
#include "BitmapPanel.hpp"
|
||||
#include "ConverterFramebufMonoVLSB.hpp"
|
||||
#include "ConverterFramebufMonoHLSB.hpp"
|
||||
#include "ConverterFramebufMonoHMSB.hpp"
|
||||
#include "FontConverterFramebufMono.hpp"
|
||||
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtGui/QAction>
|
||||
|
@ -37,6 +39,11 @@
|
|||
#include <QtWidgets/QPlainTextEdit>
|
||||
#include <QtWidgets/QScrollArea>
|
||||
#include <QtWidgets/QSplitter>
|
||||
#include <QtWidgets/QFontComboBox>
|
||||
#include <QtWidgets/QLineEdit>
|
||||
#include <QtWidgets/QFormLayout>
|
||||
#include <QtWidgets/QSpinBox>
|
||||
#include <QtWidgets/QHBoxLayout>
|
||||
#include <QtGui/QDesktopServices>
|
||||
|
||||
|
||||
|
@ -47,6 +54,9 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
initializeUi();
|
||||
initializeMenu();
|
||||
loadSettings();
|
||||
onFormatChanged();
|
||||
onFontChanged();
|
||||
onCharactersChanged();
|
||||
}
|
||||
|
||||
|
||||
|
@ -60,13 +70,16 @@ void MainWindow::initializeConverterList()
|
|||
_converterList.append(new ConverterFramebufMonoVLSB());
|
||||
_converterList.append(new ConverterFramebufMonoHMSB());
|
||||
_converterList.append(new ConverterFramebufMonoHLSB());
|
||||
_converterList.append(new FontConverterFramebufMono());
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::initializeUi()
|
||||
{
|
||||
const int cFixedWidth = 400;
|
||||
|
||||
setMinimumSize(800, 600);
|
||||
setWindowTitle(tr("Micropython Bitmap Tool - V%1 - Lucky Resistor").arg(qApp->applicationVersion()));
|
||||
setWindowTitle(tr("MicroPython Bitmap Tool - V%1 - Lucky Resistor").arg(qApp->applicationVersion()));
|
||||
|
||||
auto centralWidget = new QWidget();
|
||||
centralWidget->setObjectName("CentralWidget");
|
||||
|
@ -83,15 +96,16 @@ void MainWindow::initializeUi()
|
|||
settingsLayout->setSpacing(4);
|
||||
|
||||
auto logo = new QLabel();
|
||||
logo->setFixedSize(300, 250);
|
||||
logo->setFixedSize(cFixedWidth, 100);
|
||||
logo->setPixmap(QPixmap(":/images/AppLogo.png"));
|
||||
logo->setAlignment(Qt::AlignCenter);
|
||||
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:")));
|
||||
settingsLayout->addWidget(new QLabel(tr("<b>Generated Format:</b>")));
|
||||
_formatSelector = new QComboBox();
|
||||
for (auto converter : _converterList) {
|
||||
_formatSelector->addItem(converter->displayName());
|
||||
|
@ -99,20 +113,96 @@ void MainWindow::initializeUi()
|
|||
_formatSelector->setCurrentIndex(0);
|
||||
settingsLayout->addWidget(_formatSelector);
|
||||
|
||||
settingsLayout->addStretch();
|
||||
settingsLayout->addWidget(new QLabel(tr("<b>Parameters:</b>")));
|
||||
|
||||
settingsLayout->addWidget(new QLabel(tr("<b>Loaded Bitmap Info:</b>")));
|
||||
auto parameterScroll = new QScrollArea();
|
||||
parameterScroll->setObjectName("ParameterScrollArea");
|
||||
_parameterFrame = new QFrame();
|
||||
_parameterFrame->setObjectName("ParameterFrame");
|
||||
_parameterFrame->setFixedWidth(cFixedWidth);
|
||||
_parameterLayout = new QFormLayout(_parameterFrame);
|
||||
_parameterLayout->setContentsMargins(8, 8, 8, 8);
|
||||
parameterScroll->setWidget(_parameterFrame);
|
||||
parameterScroll->setWidgetResizable(true);
|
||||
parameterScroll->setFixedWidth(cFixedWidth);
|
||||
parameterScroll->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||
//parameterScroll->setBackgroundRole(QPalette::Window);
|
||||
settingsLayout->addWidget(parameterScroll);
|
||||
|
||||
_bitmapConverterFrame = new QFrame();
|
||||
auto bitmapConverterLayout = new QVBoxLayout(_bitmapConverterFrame);
|
||||
bitmapConverterLayout->setContentsMargins(0, 0, 0, 0);
|
||||
bitmapConverterLayout->setSpacing(4);
|
||||
settingsLayout->addWidget(_bitmapConverterFrame);
|
||||
|
||||
bitmapConverterLayout->addWidget(new QLabel(tr("<b>Loaded Bitmap Info:</b>")));
|
||||
_bitmapInfo = new QLabel(tr("No Bitmap Loaded"));
|
||||
_bitmapInfo->setObjectName("BitmapInfo");
|
||||
_bitmapInfo->setMinimumHeight(200);
|
||||
_bitmapInfo->setMinimumHeight(100);
|
||||
_bitmapInfo->setAlignment(Qt::AlignTop|Qt::AlignLeft);
|
||||
settingsLayout->addWidget(_bitmapInfo);
|
||||
bitmapConverterLayout->addWidget(_bitmapInfo);
|
||||
|
||||
auto loadButton = new QPushButton();
|
||||
loadButton->setText(tr("Load Bitmap"));
|
||||
settingsLayout->addWidget(loadButton);
|
||||
bitmapConverterLayout->addWidget(loadButton);
|
||||
connect(loadButton, &QPushButton::clicked, this, &MainWindow::onLoadBitmap);
|
||||
|
||||
_fontConverterFrame = new QFrame();
|
||||
auto fontConverterLayout = new QVBoxLayout(_fontConverterFrame);
|
||||
fontConverterLayout->setContentsMargins(0, 0, 0, 0);
|
||||
fontConverterLayout->setSpacing(4);
|
||||
settingsLayout->addWidget(_fontConverterFrame);
|
||||
|
||||
fontConverterLayout->addWidget(new QLabel(tr("<b>Selected Font Info:</b>")));
|
||||
_fontInfo = new QLabel(tr("No Font Seleccted"));
|
||||
_fontInfo->setObjectName("FontInfo");
|
||||
_fontInfo->setMinimumHeight(100);
|
||||
_fontInfo->setAlignment(Qt::AlignTop|Qt::AlignLeft);
|
||||
fontConverterLayout->addWidget(_fontInfo);
|
||||
|
||||
fontConverterLayout->addWidget(new QLabel(tr("<b>Selected Font:</b>")));
|
||||
_fontSelector = new QFontComboBox();
|
||||
fontConverterLayout->addWidget(_fontSelector);
|
||||
auto fontDetailsLayout = new QHBoxLayout();
|
||||
fontDetailsLayout->setContentsMargins(0, 0, 0, 0);
|
||||
fontDetailsLayout->setSpacing(4);
|
||||
fontConverterLayout->addLayout(fontDetailsLayout);
|
||||
_fontWeightSelector = new QComboBox();
|
||||
_fontWeightSelector->addItem(tr("Thin"), static_cast<int>(QFont::Thin));
|
||||
_fontWeightSelector->addItem(tr("Extra Light"), static_cast<int>(QFont::ExtraLight));
|
||||
_fontWeightSelector->addItem(tr("Light"), static_cast<int>(QFont::Light));
|
||||
_fontWeightSelector->addItem(tr("Normal"), static_cast<int>(QFont::Normal));
|
||||
_fontWeightSelector->addItem(tr("Medium"), static_cast<int>(QFont::Medium));
|
||||
_fontWeightSelector->addItem(tr("Demi Bold"), static_cast<int>(QFont::DemiBold));
|
||||
_fontWeightSelector->addItem(tr("Bold"), static_cast<int>(QFont::Bold));
|
||||
_fontWeightSelector->addItem(tr("Extra Bold"), static_cast<int>(QFont::ExtraBold));
|
||||
_fontWeightSelector->addItem(tr("Black"), static_cast<int>(QFont::Black));
|
||||
_fontWeightSelector->setCurrentIndex(3);
|
||||
_fontSizeSelector = new QSpinBox();
|
||||
_fontSizeSelector->setRange(4, 200);
|
||||
_fontSizeSelector->setValue(12);
|
||||
_fontHinting = new QComboBox();
|
||||
_fontHinting->addItem(tr("Default"), static_cast<int>(QFont::PreferDefaultHinting));
|
||||
_fontHinting->addItem(tr("None"), static_cast<int>(QFont::PreferNoHinting));
|
||||
_fontHinting->addItem(tr("Vertical"), static_cast<int>(QFont::PreferVerticalHinting));
|
||||
_fontHinting->addItem(tr("Full"), static_cast<int>(QFont::PreferFullHinting));
|
||||
_fontHinting->setCurrentIndex(0);
|
||||
fontDetailsLayout->addWidget(new QLabel(tr("Size:")));
|
||||
fontDetailsLayout->addWidget(_fontSizeSelector);
|
||||
fontDetailsLayout->addWidget(new QLabel(tr("Weight:")));
|
||||
fontDetailsLayout->addWidget(_fontWeightSelector);
|
||||
fontDetailsLayout->addWidget(new QLabel(tr("Hinting:")));
|
||||
fontDetailsLayout->addWidget(_fontHinting);
|
||||
fontConverterLayout->addWidget(new QLabel(tr("Characters to convert:")));
|
||||
_fontCharacters = new QPlainTextEdit();
|
||||
_fontCharacters->setFixedHeight(100);
|
||||
_fontCharacters->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
|
||||
_fontCharacters->setWordWrapMode(QTextOption::WrapAnywhere);
|
||||
_fontCharacters->setPlainText("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,:;!?()+-=\"'<>");
|
||||
_fontCharacters->setReadOnly(true);
|
||||
fontConverterLayout->addWidget(_fontCharacters);
|
||||
connect(_fontCharacters, &QPlainTextEdit::textChanged, this, &MainWindow::onCharactersChanged);
|
||||
|
||||
auto previewSplittter = new QSplitter(Qt::Vertical);
|
||||
previewSplittter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
previewSplittter->setChildrenCollapsible(false);
|
||||
|
@ -133,15 +223,9 @@ void MainWindow::initializeUi()
|
|||
_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
|
||||
const auto monospaceFont = gApp()->monospaceFont();
|
||||
_codePreview->setFont(monospaceFont);
|
||||
_fontCharacters->setFont(monospaceFont);
|
||||
|
||||
auto codeActions = new QFrame();
|
||||
auto codeActionsLayout = new QHBoxLayout(codeActions);
|
||||
|
@ -161,11 +245,12 @@ void MainWindow::initializeUi()
|
|||
previewSplittter->setStretchFactor(0, 4);
|
||||
previewSplittter->setStretchFactor(1, 1);
|
||||
|
||||
connect(_formatSelector, &QComboBox::currentIndexChanged, [=]{
|
||||
_bitmapPanel->setConverter(selectedConverter());
|
||||
updateBitmapInfo();
|
||||
updateCode();
|
||||
});
|
||||
connect(_formatSelector, &QComboBox::currentIndexChanged, this, &MainWindow::onFormatChanged);
|
||||
connect(_fontSelector, &QFontComboBox::currentFontChanged, this, &MainWindow::onFontChanged);
|
||||
connect(_fontSizeSelector, &QSpinBox::valueChanged, this, &MainWindow::onFontChanged);
|
||||
connect(_fontWeightSelector, &QComboBox::currentIndexChanged, this, &MainWindow::onFontChanged);
|
||||
connect(_fontHinting, &QComboBox::currentIndexChanged, this, &MainWindow::onFontChanged);
|
||||
connect(_bitmapPanel, &BitmapPanel::selectedCharacterChanged, this, &MainWindow::onSelectedCharacterChanged);
|
||||
}
|
||||
|
||||
|
||||
|
@ -229,6 +314,18 @@ void MainWindow::loadSettings()
|
|||
restoreGeometry(settings.value("mainWindow.geometry").toByteArray());
|
||||
restoreState(settings.value("mainWindow.state").toByteArray());
|
||||
_formatSelector->setCurrentIndex(settings.value("format.index").toInt(0));
|
||||
_currentFont = QFont(settings.value("font.family", "Arial").toString());
|
||||
_currentFont.setPixelSize(settings.value("font.size", 12).toInt());
|
||||
_currentFont.setWeight(static_cast<QFont::Weight>(settings.value("font.weight", 500).toInt()));
|
||||
_fontSelector->setCurrentFont(_currentFont);
|
||||
_fontSizeSelector->setValue(_currentFont.pixelSize());
|
||||
const int index = _fontWeightSelector->findData(static_cast<int>(_currentFont.weight()));
|
||||
if (index >= 0) {
|
||||
_fontWeightSelector->setCurrentIndex(index);
|
||||
} else {
|
||||
_fontWeightSelector->setCurrentIndex(3); // normal
|
||||
}
|
||||
_fontHinting->setCurrentIndex(settings.value("font.hinting", 0).toInt());
|
||||
}
|
||||
|
||||
|
||||
|
@ -238,6 +335,10 @@ void MainWindow::saveSettings()
|
|||
settings.setValue("mainWindow.geometry", saveGeometry());
|
||||
settings.setValue("mainWindow.state", saveState());
|
||||
settings.setValue("format.index", _formatSelector->currentIndex());
|
||||
settings.setValue("font.family", _currentFont.family());
|
||||
settings.setValue("font.size", _currentFont.pixelSize());
|
||||
settings.setValue("font.weight", static_cast<int>(_currentFont.weight()));
|
||||
settings.setValue("font.hinting", _fontHinting->currentIndex());
|
||||
}
|
||||
|
||||
|
||||
|
@ -251,42 +352,120 @@ Converter *MainWindow::selectedConverter() const
|
|||
}
|
||||
|
||||
|
||||
void MainWindow::updateBitmapInfo()
|
||||
void MainWindow::updateInfoBox()
|
||||
{
|
||||
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;
|
||||
if (selectedConverter()->mode() == Converter::Mode::Bitmap) {
|
||||
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(), createParameterMap());
|
||||
ts << "Generated Size: " << gs.width() << "x" << gs.height() << "</p>";
|
||||
_bitmapInfo->setText(text);
|
||||
} else {
|
||||
ts << "<p>";
|
||||
ts << "Family: " << _currentFont.family() << "<br>";
|
||||
ts << "Weight: ";
|
||||
switch (_currentFont.weight()) {
|
||||
case QFont::Thin: ts << tr("Thin"); break;
|
||||
case QFont::ExtraLight: ts << tr("Extra Light"); break;
|
||||
case QFont::Light: ts << tr("Light"); break;
|
||||
case QFont::Normal: ts << tr("Normal"); break;
|
||||
case QFont::Medium: ts << tr("Medium"); break;
|
||||
case QFont::DemiBold: ts << tr("Demi Bold"); break;
|
||||
case QFont::Bold: ts << tr("Bold"); break;
|
||||
case QFont::ExtraBold: ts << tr("Extra Bold"); break;
|
||||
case QFont::Black: ts << tr("Black"); break;
|
||||
}
|
||||
ts << "<br>";
|
||||
ts << "Pixel Size: " << _currentFont.pixelSize() << "<br>";
|
||||
ts << "</p>";
|
||||
_fontInfo->setText(text);
|
||||
}
|
||||
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());
|
||||
if (selectedConverter()->mode() == Converter::Mode::Bitmap) {
|
||||
auto bitmapConverter = static_cast<BitmapConverter*>(selectedConverter());
|
||||
if (!_currentImage.isNull()) {
|
||||
code = bitmapConverter->generateCode(_currentImage, QVariantMap());
|
||||
}
|
||||
} else {
|
||||
auto fontConverter = static_cast<FontConverter*>(selectedConverter());
|
||||
code = fontConverter->generateCode(_currentFont, createParameterMap());
|
||||
}
|
||||
_codePreview->setPlainText(code);
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::updateParameters()
|
||||
{
|
||||
auto converter = selectedConverter();
|
||||
if (converter == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Replace the current parameter definition.
|
||||
_displayedParameters = converter->createParameterDefinition();
|
||||
// Remove the previous UI
|
||||
while (_parameterLayout->count() > 0) {
|
||||
auto item = _parameterLayout->takeAt(0);
|
||||
delete item;
|
||||
}
|
||||
for (auto w : _parameterFrame->findChildren<QWidget*>()) {
|
||||
w->deleteLater();
|
||||
}
|
||||
// Build the new parameter UI.
|
||||
if (_displayedParameters->parameterList().isEmpty()) {
|
||||
auto label = new QLabel();
|
||||
label->setText(tr("No Parameters"));
|
||||
_parameterLayout->addWidget(label);
|
||||
} else {
|
||||
for (const auto ¶meter : _displayedParameters->parameterList()) {
|
||||
auto pw = parameterFactory.createWidget(parameter);
|
||||
pw->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
pw->setObjectName(parameter->identifier());
|
||||
_parameterLayout->addRow(parameter->label() + ":", pw);
|
||||
connect(pw, &ParameterWidget::valueChanged, this, &MainWindow::onParameterChanged);
|
||||
}
|
||||
}
|
||||
auto stretchItem = new QWidget();
|
||||
stretchItem->setFixedWidth(10);
|
||||
stretchItem->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||
_parameterLayout->addRow(stretchItem);
|
||||
}
|
||||
|
||||
|
||||
QVariantMap MainWindow::createParameterMap() const
|
||||
{
|
||||
QVariantMap result;
|
||||
result["characters"] = _fontCharacters->toPlainText();
|
||||
result["font"] = _currentFont;
|
||||
result["char"] = _bitmapPanel->selectedCharacter();
|
||||
for (auto pw : _parameterFrame->findChildren<ParameterWidget*>()) {
|
||||
result[pw->objectName()] = pw->value();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::onLoadBitmap()
|
||||
{
|
||||
QSettings settings;
|
||||
|
@ -320,11 +499,78 @@ void MainWindow::onLoadBitmap()
|
|||
_currentImage = newImage;
|
||||
_bitmapPanel->setImage(newImage);
|
||||
_bitmapPanel->setConverter(selectedConverter());
|
||||
updateBitmapInfo();
|
||||
updateInfoBox();
|
||||
updateCode();
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::onFormatChanged()
|
||||
{
|
||||
const auto converter = selectedConverter();
|
||||
_bitmapPanel->setConverter(converter);
|
||||
if (converter->mode() == Converter::Mode::Bitmap) {
|
||||
_bitmapConverterFrame->setVisible(true);
|
||||
_fontConverterFrame->setVisible(false);
|
||||
} else {
|
||||
_bitmapConverterFrame->setVisible(false);
|
||||
_fontConverterFrame->setVisible(true);
|
||||
}
|
||||
updateParameters();
|
||||
updateInfoBox();
|
||||
updateCode();
|
||||
_bitmapPanel->setParameter(createParameterMap());
|
||||
onSelectedCharacterChanged(_bitmapPanel->selectedCharacter());
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::onFontChanged()
|
||||
{
|
||||
_currentFont = _fontSelector->currentFont();
|
||||
_currentFont.setWeight(static_cast<QFont::Weight>(_fontWeightSelector->currentData().toInt()));
|
||||
_currentFont.setPixelSize(_fontSizeSelector->value());
|
||||
const auto hintingPreferences = static_cast<QFont::HintingPreference>(_fontHinting->currentData().toInt());
|
||||
_currentFont.setHintingPreference(hintingPreferences);
|
||||
updateInfoBox();
|
||||
updateCode();
|
||||
_bitmapPanel->setParameter(createParameterMap());
|
||||
onSelectedCharacterChanged(_bitmapPanel->selectedCharacter());
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::onCharactersChanged()
|
||||
{
|
||||
auto characters = _fontCharacters->toPlainText();
|
||||
_bitmapPanel->setCharacters(characters);
|
||||
_bitmapPanel->setConverter(selectedConverter());
|
||||
_bitmapPanel->setParameter(createParameterMap());
|
||||
onSelectedCharacterChanged(_bitmapPanel->selectedCharacter());
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::onSelectedCharacterChanged(QChar c)
|
||||
{
|
||||
auto converter = selectedConverter();
|
||||
if (converter == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (converter->mode() == Converter::Mode::Font) {
|
||||
auto fontConverter = static_cast<const FontConverter*>(converter);
|
||||
auto newImage = fontConverter->generateImage(_currentFont, c, createParameterMap());
|
||||
_currentImage = newImage;
|
||||
_bitmapPanel->setImage(newImage);
|
||||
_bitmapPanel->setConverter(selectedConverter());
|
||||
_bitmapPanel->setParameter(createParameterMap());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::onParameterChanged()
|
||||
{
|
||||
_bitmapPanel->setParameter(createParameterMap());
|
||||
onSelectedCharacterChanged(_bitmapPanel->selectedCharacter());
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
saveSettings();
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
#include "ParameterDefinition.hpp"
|
||||
#include "ParameterFactory.hpp"
|
||||
|
||||
#include <QtCore/QVariantMap>
|
||||
#include <QtWidgets/QMainWindow>
|
||||
|
||||
|
||||
|
@ -25,6 +29,11 @@ class QPlainTextEdit;
|
|||
class QComboBox;
|
||||
class QLabel;
|
||||
class BitmapPanel;
|
||||
class QFrame;
|
||||
class QFontComboBox;
|
||||
class QLineEdit;
|
||||
class QSpinBox;
|
||||
class QFormLayout;
|
||||
|
||||
|
||||
/// The main widnow
|
||||
|
@ -64,26 +73,73 @@ private:
|
|||
|
||||
/// Update the bitmap info.
|
||||
///
|
||||
void updateBitmapInfo();
|
||||
void updateInfoBox();
|
||||
|
||||
/// Update the code.
|
||||
///
|
||||
void updateCode();
|
||||
|
||||
/// Update the parameter frame for the current converter.
|
||||
///
|
||||
void updateParameters();
|
||||
|
||||
/// Get the current parameters
|
||||
///
|
||||
QVariantMap createParameterMap() const;
|
||||
|
||||
private Q_SLOTS:
|
||||
/// Load a bitmap.
|
||||
///
|
||||
void onLoadBitmap();
|
||||
|
||||
/// After a new converter is selected.
|
||||
///
|
||||
void onFormatChanged();
|
||||
|
||||
/// After a new font is selected.
|
||||
///
|
||||
void onFontChanged();
|
||||
|
||||
/// After the character list has changed
|
||||
///
|
||||
void onCharactersChanged();
|
||||
|
||||
/// If the selected character changed
|
||||
///
|
||||
void onSelectedCharacterChanged(QChar c);
|
||||
|
||||
/// After a parameter has changed.
|
||||
///
|
||||
void onParameterChanged();
|
||||
|
||||
protected: // Implement QWidget
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
|
||||
private:
|
||||
ParameterFactory parameterFactory; ///< The parameter factory.
|
||||
|
||||
QComboBox *_formatSelector; ///< The format selector.
|
||||
QPlainTextEdit *_codePreview; ///< The generated code.
|
||||
BitmapPanel *_bitmapPanel; ///< The bitmap panel.
|
||||
QImage _currentImage; ///< The current loaded image
|
||||
|
||||
QFrame *_parameterFrame; ///< The frame with the parameters.
|
||||
QFormLayout *_parameterLayout; ///< The parameter layout.
|
||||
ParameterDefinitionPtr _displayedParameters; ///< The currently displayed parameters.
|
||||
|
||||
QImage _currentImage; ///< The current loaded image for bitmap converters.
|
||||
QFont _currentFont; ///< The currently selected font for font converters.
|
||||
|
||||
QFrame *_bitmapConverterFrame; ///< The frame for bitmap converters.
|
||||
QLabel *_bitmapInfo; ///< The label with the image info.
|
||||
|
||||
QFrame *_fontConverterFrame; ///< The frame for font converters.
|
||||
QLabel *_fontInfo; ///< The label with the font info.
|
||||
QFontComboBox *_fontSelector; ///< The combo box to select a new font.
|
||||
QComboBox *_fontWeightSelector; ///< The selector for the font weight.
|
||||
QSpinBox *_fontSizeSelector; ///< The selector for the used font size.
|
||||
QComboBox *_fontHinting; ///< The hinting settings for the font.
|
||||
QPlainTextEdit *_fontCharacters; ///< The characters of the font to be converted.
|
||||
|
||||
QList<Converter*> _converterList; ///< A list of available converters.
|
||||
};
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ QT += core gui
|
|||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
CONFIG += c++17
|
||||
CONFIG += sdk_no_version_check
|
||||
|
||||
TARGET = "MicroPythonBitmapTool"
|
||||
|
||||
|
@ -11,6 +12,8 @@ TARGET = "MicroPythonBitmapTool"
|
|||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
SOURCES += \
|
||||
ApplicationController.cpp \
|
||||
BitmapConverter.cpp \
|
||||
BitmapPanel.cpp \
|
||||
BitmapPreview.cpp \
|
||||
Converter.cpp \
|
||||
|
@ -19,13 +22,22 @@ SOURCES += \
|
|||
ConverterFramebufMonoHLSB.cpp \
|
||||
ConverterFramebufMonoHMSB.cpp \
|
||||
ConverterFramebufMonoVLSB.cpp \
|
||||
FontConverter.cpp \
|
||||
FontConverterFramebufMono.cpp \
|
||||
LegendData.cpp \
|
||||
LegendEntry.cpp \
|
||||
MonoTools.cpp \
|
||||
OverlayPainter.cpp \
|
||||
ParameterDefinition.cpp \
|
||||
ParameterEntry.cpp \
|
||||
ParameterFactory.cpp \
|
||||
ParameterWidget.cpp \
|
||||
main.cpp \
|
||||
MainWindow.cpp
|
||||
|
||||
HEADERS += \
|
||||
ApplicationController.hpp \
|
||||
BitmapConverter.hpp \
|
||||
BitmapPanel.hpp \
|
||||
BitmapPreview.hpp \
|
||||
Converter.hpp \
|
||||
|
@ -34,11 +46,19 @@ HEADERS += \
|
|||
ConverterFramebufMonoHLSB.hpp \
|
||||
ConverterFramebufMonoHMSB.hpp \
|
||||
ConverterFramebufMonoVLSB.hpp \
|
||||
FontConverter.hpp \
|
||||
FontConverterFramebufMono.hpp \
|
||||
LegendData.hpp \
|
||||
LegendEntry.hpp \
|
||||
MainWindow.hpp \
|
||||
MonoTools.hpp \
|
||||
OverlayMode.hpp \
|
||||
OverlayPainter.hpp
|
||||
OverlayPainter.hpp \
|
||||
ParameterDefinition.hpp \
|
||||
ParameterEntry.hpp \
|
||||
ParameterFactory.hpp \
|
||||
ParameterType.hpp \
|
||||
ParameterWidget.hpp
|
||||
|
||||
RESOURCES += \
|
||||
data/data.qrc
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
//
|
||||
// (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 "MonoTools.hpp"
|
||||
|
||||
|
||||
MonoTools::MonoTools(MonoTools::UnitOrientation unitOrientation, MonoTools::BitDirection bitDirection, int unitSize)
|
||||
: _unitOrientation(unitOrientation), _bitDirection(bitDirection), _unitSize(unitSize)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void MonoTools::addMonoLegendData(LegendDataPtr data, OverlayMode mode) const
|
||||
{
|
||||
if (mode == OverlayMode::BitAssigments) {
|
||||
data->addEntry(colorBitAssignment1, colorBitAssignment2, QObject::tr("Bit Assignment"));
|
||||
} else {
|
||||
data->addEntry(colorPixelInterpretation, QObject::tr("Pixel Interpretation"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QSize MonoTools::monoGeneratedSize(const QSize &imageSize, const QVariantMap&) const
|
||||
{
|
||||
if (_unitOrientation == UnitOrientation::Vertical) {
|
||||
if ((imageSize.height() % _unitSize) != 0) {
|
||||
return QSize(imageSize.width(), ((imageSize.height()/_unitSize)+1)*_unitSize);
|
||||
} else {
|
||||
return imageSize;
|
||||
}
|
||||
} else {
|
||||
if ((imageSize.width() % _unitSize) != 0) {
|
||||
return QSize(((imageSize.width()/_unitSize)+1)*_unitSize, imageSize.height());
|
||||
} else {
|
||||
return imageSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MonoTools::monoPaintOverlay(OverlayPainter &p, OverlayMode mode, const QImage &image, const QVariantMap&) const
|
||||
{
|
||||
if (mode == OverlayMode::BitAssigments) {
|
||||
const auto bitL = (_bitDirection == BitDirection::LSB ? "0" : QString::number(_unitSize-1));
|
||||
const auto bitH = (_bitDirection == BitDirection::LSB ? QString::number(_unitSize-1) : "0");
|
||||
bool colorFlag = false;
|
||||
if (_unitOrientation == UnitOrientation::Vertical) {
|
||||
for (int y = 0; y < p.imageSize().height(); y += _unitSize) {
|
||||
for (int x = 0; x < p.imageSize().width(); ++x) {
|
||||
QRect rect(x, y, 1, _unitSize);
|
||||
if (p.arePixelUpdated(rect)) {
|
||||
const auto color = colorFlag ? colorBitAssignment1 : colorBitAssignment2;
|
||||
p.drawPixelOutline(rect, color, 1);
|
||||
p.drawPixelText(QRect(x, y, 1, 1), color, bitL);
|
||||
p.drawPixelText(QRect(x, y+_unitSize-1, 1, 1), color, bitH);
|
||||
}
|
||||
colorFlag = !colorFlag;
|
||||
}
|
||||
if (p.imageSize().width() % 2 == 0) {
|
||||
colorFlag = !colorFlag;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int y = 0; y < p.imageSize().height(); ++y) {
|
||||
for (int x = 0; x < p.imageSize().width(); x += _unitSize) {
|
||||
QRect rect(x, y, _unitSize, 1);
|
||||
if (p.arePixelUpdated(rect)) {
|
||||
const auto color = colorFlag ? colorBitAssignment1 : colorBitAssignment2;
|
||||
p.drawPixelOutline(rect, color, 1);
|
||||
p.drawPixelText(QRect(x, y, 1, 1), color, bitH);
|
||||
p.drawPixelText(QRect(x+_unitSize-1, y, 1, 1), color, bitL);
|
||||
}
|
||||
colorFlag = !colorFlag;
|
||||
}
|
||||
if ((p.imageSize().width()/_unitSize) % 2 == 0) {
|
||||
colorFlag = !colorFlag;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (mode == OverlayMode::PixelInterpretation) {
|
||||
for (int y = 0; y < p.generatedSize().height(); ++y) {
|
||||
for (int x = 0; x < p.generatedSize().width(); ++x) {
|
||||
auto text = (getPixel(x, y, image) ? "1" : "0");
|
||||
const QRect rect(x, y, 1, 1);
|
||||
if (p.arePixelUpdated(rect)) {
|
||||
p.drawPixelText(rect, colorPixelInterpretation, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool MonoTools::getPixel(int x, int y, const QImage &image)
|
||||
{
|
||||
if (x < 0 || y < 0 || x >= image.width() || y >= image.height()) {
|
||||
return false;
|
||||
}
|
||||
auto color = image.pixelColor(x, y);
|
||||
float h, s, l, a;
|
||||
color.getHslF(&h, &s, &l, &a);
|
||||
if (a < 0.5) {
|
||||
return false;
|
||||
}
|
||||
return l < 0.5;
|
||||
}
|
||||
|
||||
|
||||
uint32_t MonoTools::readUnit(int x, int y, int dx, int dy, int count, const QImage &image)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
result <<= 1;
|
||||
if (getPixel(x, y, image)) {
|
||||
result |= 0b1;
|
||||
}
|
||||
x += dx;
|
||||
y += dy;
|
||||
}
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
//
|
||||
// (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/>.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "LegendData.hpp"
|
||||
#include "OverlayPainter.hpp"
|
||||
#include "OverlayMode.hpp"
|
||||
#include "ParameterDefinition.hpp"
|
||||
|
||||
#include <QtGui/QColor>
|
||||
#include <QtGui/QImage>
|
||||
|
||||
|
||||
class MonoTools
|
||||
{
|
||||
public:
|
||||
enum class UnitOrientation {
|
||||
Horizontal,
|
||||
Vertical
|
||||
};
|
||||
|
||||
enum class BitDirection {
|
||||
LSB,
|
||||
MSB
|
||||
};
|
||||
|
||||
public:
|
||||
/// ctor
|
||||
///
|
||||
MonoTools(UnitOrientation unitOrientation,
|
||||
BitDirection bitDirection,
|
||||
int unitSize);
|
||||
|
||||
/// Legend data for mono conversion
|
||||
///
|
||||
void addMonoLegendData(LegendDataPtr data, OverlayMode mode) const;
|
||||
|
||||
/// The generated size for mono conversion.
|
||||
///
|
||||
QSize monoGeneratedSize(const QSize &imageSize, const QVariantMap ¶meter) const;
|
||||
|
||||
/// Paint overlay for mono data.
|
||||
///
|
||||
void monoPaintOverlay(OverlayPainter &p, OverlayMode mode, const QImage &image, const QVariantMap ¶meter) const;
|
||||
|
||||
/// Interpret a single pixel.
|
||||
///
|
||||
/// Returns `false` if the pixel is out of bounds.
|
||||
///
|
||||
static bool getPixel(int x, int y, const QImage &image);
|
||||
|
||||
/// Read a single unit.
|
||||
///
|
||||
static uint32_t readUnit(int x, int y, int dx, int dy, int count, const QImage &image);
|
||||
|
||||
public:
|
||||
/// The colors for the bit assignments
|
||||
///
|
||||
static constexpr QColor colorBitAssignment1 = QColor(240, 40, 40);
|
||||
static constexpr QColor colorBitAssignment2 = QColor(240, 80, 80);
|
||||
static constexpr QColor colorPixelInterpretation = QColor(240, 240, 40);
|
||||
|
||||
protected:
|
||||
UnitOrientation _unitOrientation; ///< The unit orientatioon.
|
||||
BitDirection _bitDirection; ///< The bit direction.
|
||||
int _unitSize; ///< The number of bits per unit.
|
||||
};
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
//
|
||||
// (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 "ParameterDefinition.hpp"
|
||||
|
||||
|
||||
ParameterDefinitionPtr ParameterDefinition::create()
|
||||
{
|
||||
return ParameterDefinitionPtr(new ParameterDefinition());
|
||||
}
|
||||
|
||||
|
||||
void ParameterDefinition::addCheckbox(
|
||||
const QString &identifier,
|
||||
const QString &label,
|
||||
bool defaultValue)
|
||||
{
|
||||
QVariantMap settings;
|
||||
settings["default"] = defaultValue;
|
||||
_parameterList.append(ParameterEntry::create(
|
||||
ParameterType::Checkbox, identifier, label, settings));
|
||||
}
|
||||
|
||||
|
||||
void ParameterDefinition::addInteger(
|
||||
const QString &identifier,
|
||||
const QString &label,
|
||||
int defaultValue,
|
||||
int minimum,
|
||||
int maximum)
|
||||
{
|
||||
QVariantMap settings;
|
||||
settings["default"] = defaultValue;
|
||||
settings["minimum"] = minimum;
|
||||
settings["maximum"] = maximum;
|
||||
_parameterList.append(ParameterEntry::create(ParameterType::IntegerValue, identifier, label, settings));
|
||||
}
|
||||
|
||||
|
||||
void ParameterDefinition::addIntegerSize(const QString &identifier, const QString &label, QSize defaultValue, QSize minimum, QSize maximum)
|
||||
{
|
||||
QVariantMap settings;
|
||||
settings["default"] = defaultValue;
|
||||
settings["minimum"] = minimum;
|
||||
settings["maximum"] = maximum;
|
||||
_parameterList.append(ParameterEntry::create(ParameterType::IntegerSize, identifier, label, settings));
|
||||
}
|
||||
|
||||
|
||||
void ParameterDefinition::addIntegerPosition(const QString &identifier, const QString &label, QPoint defaultValue, QPoint minimum, QPoint maximum)
|
||||
{
|
||||
QVariantMap settings;
|
||||
settings["default"] = defaultValue;
|
||||
settings["minimum"] = minimum;
|
||||
settings["maximum"] = maximum;
|
||||
_parameterList.append(ParameterEntry::create(ParameterType::IntegerPosition, identifier, label, settings));
|
||||
}
|
||||
|
||||
|
||||
const ParameterDefinition::ParameterList &ParameterDefinition::parameterList() const
|
||||
{
|
||||
return _parameterList;
|
||||
}
|
||||
|
||||
|
||||
ParameterDefinition::ParameterDefinition()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
//
|
||||
// (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/>.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "ParameterEntry.hpp"
|
||||
|
||||
#include <QtCore/QSharedPointer>
|
||||
#include <QtCore/QSize>
|
||||
#include <QtCore/QPoint>
|
||||
|
||||
|
||||
class ParameterDefinition;
|
||||
using ParameterDefinitionPtr = QSharedPointer<ParameterDefinition>;
|
||||
using ParameterDefinitionPtrConst = QSharedPointer<const ParameterDefinition>;
|
||||
|
||||
|
||||
/// The definition of parameters, returned by a converter.
|
||||
///
|
||||
class ParameterDefinition
|
||||
{
|
||||
public:
|
||||
/// A parameter list.
|
||||
///
|
||||
using ParameterList = QList<ParameterEntryPtr>;
|
||||
|
||||
public:
|
||||
/// Create a new parameter definition.
|
||||
///
|
||||
static ParameterDefinitionPtr create();
|
||||
|
||||
public:
|
||||
/// Add a checkbox parameter.
|
||||
///
|
||||
void addCheckbox(const QString &identifier, const QString &label, bool defaultValue);
|
||||
|
||||
/// Add an integer parameter.
|
||||
///
|
||||
void addInteger(const QString &identifier, const QString &label, int defaultValue, int minimum, int maximum);
|
||||
|
||||
/// Add an integer size parameter.
|
||||
///
|
||||
void addIntegerSize(const QString &identifier, const QString &label, QSize defaultValue, QSize minimum, QSize maximum);
|
||||
|
||||
/// Add an integer position parameter.
|
||||
///
|
||||
void addIntegerPosition(const QString &identifier, const QString &label, QPoint defaultValue, QPoint minimum, QPoint maximum);
|
||||
|
||||
/// Get the parameter list.
|
||||
///
|
||||
const ParameterList& parameterList() const;
|
||||
|
||||
private:
|
||||
ParameterDefinition();
|
||||
|
||||
private:
|
||||
ParameterList _parameterList; ///< The list with all parameters.
|
||||
};
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
//
|
||||
// (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 "ParameterEntry.hpp"
|
||||
|
||||
|
||||
ParameterEntryPtr ParameterEntry::create(
|
||||
ParameterType type,
|
||||
const QString &identifier,
|
||||
const QString &label,
|
||||
const QVariantMap &settings)
|
||||
{
|
||||
return ParameterEntryPtr(new ParameterEntry(type, identifier, label, settings));
|
||||
}
|
||||
|
||||
|
||||
ParameterType ParameterEntry::type() const
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
|
||||
QString ParameterEntry::identifier() const
|
||||
{
|
||||
return _identifier;
|
||||
}
|
||||
|
||||
|
||||
QString ParameterEntry::label() const
|
||||
{
|
||||
return _label;
|
||||
}
|
||||
|
||||
|
||||
QVariantMap ParameterEntry::settings() const
|
||||
{
|
||||
return _settings;
|
||||
}
|
||||
|
||||
|
||||
ParameterEntry::ParameterEntry(
|
||||
ParameterType type,
|
||||
const QString &identifier,
|
||||
const QString &label,
|
||||
const QVariantMap &settings)
|
||||
:
|
||||
_type(type),
|
||||
_identifier(identifier),
|
||||
_label(label),
|
||||
_settings(settings)
|
||||
{
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// (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/>.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "ParameterType.hpp"
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QVariantMap>
|
||||
#include <QtCore/QSharedPointer>
|
||||
|
||||
|
||||
class ParameterEntry;
|
||||
using ParameterEntryPtr = QSharedPointer<ParameterEntry>;
|
||||
|
||||
|
||||
/// One entry in the parameter definition.
|
||||
///
|
||||
class ParameterEntry
|
||||
{
|
||||
public:
|
||||
static ParameterEntryPtr create(
|
||||
ParameterType type,
|
||||
const QString &identifier,
|
||||
const QString &label,
|
||||
const QVariantMap &settings);
|
||||
|
||||
public:
|
||||
/// The parameter type.
|
||||
///
|
||||
ParameterType type() const;
|
||||
|
||||
/// The identifier of the parameter.
|
||||
///
|
||||
QString identifier() const;
|
||||
|
||||
/// The label for the parameter.
|
||||
///
|
||||
QString label() const;
|
||||
|
||||
/// Settings for the parameter.
|
||||
///
|
||||
QVariantMap settings() const;
|
||||
|
||||
private:
|
||||
/// Create a new raw paremeter entry.
|
||||
///
|
||||
ParameterEntry(
|
||||
ParameterType type,
|
||||
const QString &identifier,
|
||||
const QString &label,
|
||||
const QVariantMap &settings);
|
||||
|
||||
private:
|
||||
ParameterType _type;
|
||||
QString _identifier;
|
||||
QString _label;
|
||||
QVariantMap _settings;
|
||||
};
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// (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 "ParameterFactory.hpp"
|
||||
|
||||
|
||||
ParameterFactory::ParameterFactory()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ParameterWidget *ParameterFactory::createWidget(const ParameterEntryPtr ¶meter) const
|
||||
{
|
||||
switch (parameter->type()) {
|
||||
case ParameterType::Checkbox:
|
||||
return new CheckBoxParameter(parameter);
|
||||
case ParameterType::IntegerValue:
|
||||
return new IntegerParameter(parameter);
|
||||
case ParameterType::IntegerSize:
|
||||
return new IntegerSizeParameter(parameter);
|
||||
case ParameterType::IntegerPosition:
|
||||
return new IntegerPositionParameter(parameter);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// (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/>.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "ParameterWidget.hpp"
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
|
||||
/// A factory to handle the generic parameters.
|
||||
///
|
||||
class ParameterFactory
|
||||
{
|
||||
public:
|
||||
ParameterFactory();
|
||||
|
||||
public:
|
||||
/// Create the widget for to edit a parameter.
|
||||
///
|
||||
ParameterWidget *createWidget(const ParameterEntryPtr ¶meter) const;
|
||||
};
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// (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/>.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
|
||||
/// The parameter type.
|
||||
///
|
||||
enum class ParameterType {
|
||||
Checkbox, ///< A boolean parameter
|
||||
IntegerValue, ///< An integer value.
|
||||
IntegerSize, ///< A size value
|
||||
IntegerPosition, ///< A position value.
|
||||
};
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
//
|
||||
// (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 "ParameterWidget.hpp"
|
||||
|
||||
|
||||
#include <QtWidgets/QHBoxLayout>
|
||||
#include <QtWidgets/QSpinBox>
|
||||
#include <QtWidgets/QCheckBox>
|
||||
#include <QtWidgets/QLabel>
|
||||
|
||||
|
||||
ParameterWidget::ParameterWidget(const ParameterEntryPtr ¶meter, QWidget *parent)
|
||||
: QWidget(parent), _currentValue(parameter->settings()["default"])
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CheckBoxParameter::CheckBoxParameter(const ParameterEntryPtr ¶meter, QWidget *parent)
|
||||
: ParameterWidget(parameter, parent)
|
||||
{
|
||||
auto mainLayout = new QHBoxLayout(this);
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mainLayout->setSpacing(2);
|
||||
_value = new QCheckBox();
|
||||
mainLayout->addWidget(_value);
|
||||
_value->setChecked(_currentValue.toBool());
|
||||
connect(_value, &QCheckBox::toggled, this, &CheckBoxParameter::valueChanged);
|
||||
}
|
||||
|
||||
|
||||
QVariant CheckBoxParameter::value() const
|
||||
{
|
||||
return static_cast<bool>(_value->isChecked());
|
||||
}
|
||||
|
||||
|
||||
void CheckBoxParameter::setValue(const QVariant &value)
|
||||
{
|
||||
if (value != _currentValue) {
|
||||
_currentValue = value;
|
||||
_value->setChecked(value.toBool());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
IntegerParameter::IntegerParameter(const ParameterEntryPtr ¶meter, QWidget *parent)
|
||||
: ParameterWidget(parameter, parent)
|
||||
{
|
||||
auto mainLayout = new QHBoxLayout(this);
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mainLayout->setSpacing(2);
|
||||
_value = new QSpinBox();
|
||||
_value->setRange(
|
||||
parameter->settings()["minimum"].toInt(),
|
||||
parameter->settings()["maximum"].toInt()
|
||||
);
|
||||
mainLayout->addWidget(_value);
|
||||
_value->setValue(_currentValue.toInt());
|
||||
connect(_value, &QSpinBox::valueChanged, this, &CheckBoxParameter::valueChanged);
|
||||
}
|
||||
|
||||
|
||||
QVariant IntegerParameter::value() const
|
||||
{
|
||||
return _value->value();
|
||||
}
|
||||
|
||||
|
||||
void IntegerParameter::setValue(const QVariant &value)
|
||||
{
|
||||
if (value != _currentValue) {
|
||||
_value->setValue(value.toInt());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
IntegerSizeParameter::IntegerSizeParameter(const ParameterEntryPtr ¶meter, QWidget *parent)
|
||||
: ParameterWidget(parameter, parent)
|
||||
{
|
||||
auto mainLayout = new QHBoxLayout(this);
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mainLayout->setSpacing(2);
|
||||
mainLayout->addWidget(new QLabel(tr("W:")));
|
||||
_a = new QSpinBox();
|
||||
_a->setRange(
|
||||
parameter->settings()["minimum"].toSize().width(),
|
||||
parameter->settings()["maximum"].toSize().width()
|
||||
);
|
||||
mainLayout->addWidget(_a);
|
||||
_a->setValue(_currentValue.toSize().width());
|
||||
connect(_a, &QSpinBox::valueChanged, this, &CheckBoxParameter::valueChanged);
|
||||
mainLayout->addWidget(new QLabel(tr("H:")));
|
||||
_b = new QSpinBox();
|
||||
_b->setRange(
|
||||
parameter->settings()["minimum"].toSize().height(),
|
||||
parameter->settings()["maximum"].toSize().height()
|
||||
);
|
||||
mainLayout->addWidget(_b);
|
||||
_b->setValue(_currentValue.toSize().height());
|
||||
connect(_b, &QSpinBox::valueChanged, this, &CheckBoxParameter::valueChanged);
|
||||
}
|
||||
|
||||
|
||||
QVariant IntegerSizeParameter::value() const
|
||||
{
|
||||
return QSize(_a->value(), _b->value());
|
||||
}
|
||||
|
||||
|
||||
void IntegerSizeParameter::setValue(const QVariant &value)
|
||||
{
|
||||
if (_currentValue != value) {
|
||||
_a->setValue(value.toSize().width());
|
||||
_b->setValue(value.toSize().height());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
IntegerPositionParameter::IntegerPositionParameter(const ParameterEntryPtr ¶meter, QWidget *parent)
|
||||
: ParameterWidget(parameter, parent)
|
||||
{
|
||||
auto mainLayout = new QHBoxLayout(this);
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mainLayout->setSpacing(2);
|
||||
mainLayout->addWidget(new QLabel(tr("X:")));
|
||||
_a = new QSpinBox();
|
||||
_a->setRange(
|
||||
parameter->settings()["minimum"].toPoint().x(),
|
||||
parameter->settings()["maximum"].toPoint().x()
|
||||
);
|
||||
mainLayout->addWidget(_a);
|
||||
_a->setValue(_currentValue.toPoint().x());
|
||||
connect(_a, &QSpinBox::valueChanged, this, &CheckBoxParameter::valueChanged);
|
||||
mainLayout->addWidget(new QLabel(tr("Y:")));
|
||||
_b = new QSpinBox();
|
||||
_b->setRange(
|
||||
parameter->settings()["minimum"].toPoint().y(),
|
||||
parameter->settings()["maximum"].toPoint().y()
|
||||
);
|
||||
mainLayout->addWidget(_b);
|
||||
_b->setValue(_currentValue.toPoint().y());
|
||||
connect(_b, &QSpinBox::valueChanged, this, &CheckBoxParameter::valueChanged);
|
||||
}
|
||||
|
||||
|
||||
QVariant IntegerPositionParameter::value() const
|
||||
{
|
||||
return QPoint(_a->value(), _b->value());
|
||||
}
|
||||
|
||||
|
||||
void IntegerPositionParameter::setValue(const QVariant &value)
|
||||
{
|
||||
if (_currentValue != value) {
|
||||
_a->setValue(value.toPoint().x());
|
||||
_b->setValue(value.toPoint().y());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
//
|
||||
// (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/>.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "ParameterEntry.hpp"
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
|
||||
class QCheckBox;
|
||||
class QSpinBox;
|
||||
|
||||
|
||||
/// The base class of all parameter widgets.
|
||||
///
|
||||
class ParameterWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/// Create the widget.
|
||||
///
|
||||
ParameterWidget(const ParameterEntryPtr ¶meter, QWidget *parent = nullptr);
|
||||
|
||||
/// Get the current value for the widget.
|
||||
///
|
||||
virtual QVariant value() const = 0;
|
||||
|
||||
/// Set the value for this widget.
|
||||
///
|
||||
virtual void setValue(const QVariant &value) = 0;
|
||||
|
||||
signals:
|
||||
/// Emitted if the value for this parameter changes.
|
||||
///
|
||||
void valueChanged();
|
||||
|
||||
protected:
|
||||
QVariant _currentValue; ///< Buffer to limit signals.
|
||||
};
|
||||
|
||||
|
||||
class CheckBoxParameter : public ParameterWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CheckBoxParameter(const ParameterEntryPtr ¶meter, QWidget *parent = nullptr);
|
||||
QVariant value() const override;
|
||||
void setValue(const QVariant &value) override;
|
||||
|
||||
private:
|
||||
QCheckBox *_value;
|
||||
};
|
||||
|
||||
|
||||
class IntegerParameter : public ParameterWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntegerParameter(const ParameterEntryPtr ¶meter, QWidget *parent = nullptr);
|
||||
QVariant value() const override;
|
||||
void setValue(const QVariant &value) override;
|
||||
|
||||
private:
|
||||
QSpinBox *_value;
|
||||
};
|
||||
|
||||
|
||||
class IntegerSizeParameter : public ParameterWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntegerSizeParameter(const ParameterEntryPtr ¶meter, QWidget *parent = nullptr);
|
||||
QVariant value() const override;
|
||||
void setValue(const QVariant &value) override;
|
||||
|
||||
private:
|
||||
QSpinBox *_a;
|
||||
QSpinBox *_b;
|
||||
};
|
||||
|
||||
|
||||
class IntegerPositionParameter : public ParameterWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntegerPositionParameter(const ParameterEntryPtr ¶meter, QWidget *parent = nullptr);
|
||||
QVariant value() const override;
|
||||
void setValue(const QVariant &value) override;
|
||||
|
||||
private:
|
||||
QSpinBox *_a;
|
||||
QSpinBox *_b;
|
||||
};
|
||||
|
BIN
data/AppLogo.png
BIN
data/AppLogo.png
Plik binarny nie jest wyświetlany.
Przed Szerokość: | Wysokość: | Rozmiar: 8.6 KiB Po Szerokość: | Wysokość: | Rozmiar: 4.8 KiB |
Plik binarny nie jest wyświetlany.
Przed Szerokość: | Wysokość: | Rozmiar: 19 KiB Po Szerokość: | Wysokość: | Rozmiar: 9.5 KiB |
Plik binarny nie jest wyświetlany.
Przed Szerokość: | Wysokość: | Rozmiar: 30 KiB Po Szerokość: | Wysokość: | Rozmiar: 14 KiB |
|
@ -14,8 +14,16 @@
|
|||
color: #f8f8f8;
|
||||
}
|
||||
|
||||
#BitmapInfo {
|
||||
#BitmapInfo, #FontInfo {
|
||||
border: 1px solid rgba(0,0,0,0.25);
|
||||
padding: 8px;
|
||||
margin: 0px 0px 16px 0px;
|
||||
}
|
||||
|
||||
#ParameterScrollArea {
|
||||
border: none;
|
||||
}
|
||||
|
||||
#ParameterFrame {
|
||||
background-color: #616875;
|
||||
}
|
||||
|
|
10
main.cpp
10
main.cpp
|
@ -14,16 +14,19 @@
|
|||
// 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 "ApplicationController.hpp"
|
||||
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtCore/QFile>
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
a.setApplicationName("MicroPython Bitmap Tool");
|
||||
a.setApplicationVersion("1.0.1");
|
||||
a.setApplicationVersion("1.2.0");
|
||||
a.setApplicationDisplayName("MicroPython Bitmap Tool");
|
||||
a.setOrganizationDomain("luckyresistor.me");
|
||||
a.setOrganizationName("Lucky Resistoor");
|
||||
|
@ -32,7 +35,6 @@ int main(int argc, char *argv[])
|
|||
a.setStyleSheet(QString::fromUtf8(styleSheet.readAll()));
|
||||
styleSheet.close();
|
||||
|
||||
MainWindow w;
|
||||
w.show();
|
||||
ApplicationController app;
|
||||
return a.exec();
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue