mirror of
https://github.com/fergalmoran/flameshot.git
synced 2026-03-26 18:10:02 +00:00
* Merge CTB::ButtonType into CaptureTool::Type Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Remove configshortcuts.cpp which I forgot to do earlier Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Add activeButtonTool & activeButtonToolType in CaptureWidget Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Rename slots in CaptureTool for better mnemonics Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix move tool bug Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Refactor ShortcutsWidget::initButtons Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Move code from CaptureWidget to SelectionWidget: part 1 Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Move code from CaptureWidget to SelectionWidget: part 2 Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Move code from CaptureWidget to SelectionWidget: part 3 Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Move code from CaptureWidget to SelectionWidget: part 4 Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Add SelectionWidget::updateCursor Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Move code from CaptureWidget to SelectionWidget: part 5 Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Refactor mouse events in CaptureWidget Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Overlay message update Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Replace connect/disconnect with blockSignals Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * updateIcon on button animation finished Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Remove CaptureWidget::selectAll Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Move moveLeft and similar to SelectionWidget Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Mark update calls for removal Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Specialize CaptureWidget update to affected rects Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Tune update of tool objects Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Remove redundant CaptureTool requests Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Improve performance of update in CaptureWidget Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix failing builds Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix failing builds again Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix undo/redo update Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Undo/redo update workaround Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Extend capture tool update rects Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Fix circle count tool update bug Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Add 'Left Double-Click' tooltip to copy button Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com> * Improve ColorPicker performance Signed-off-by: Haris Gušić <harisgusic.dev@gmail.com>
415 lines
8.7 KiB
C++
415 lines
8.7 KiB
C++
#include "valuehandler.h"
|
|
#include "capturetool.h"
|
|
#include "confighandler.h"
|
|
#include <QColor>
|
|
#include <QFileInfo>
|
|
#include <QStandardPaths>
|
|
#include <QVariant>
|
|
|
|
// VALUE HANDLER
|
|
|
|
QVariant ValueHandler::value(const QVariant& val)
|
|
{
|
|
if (!val.isValid() || !check(val)) {
|
|
return fallback();
|
|
} else {
|
|
return process(val);
|
|
}
|
|
}
|
|
|
|
QVariant ValueHandler::fallback()
|
|
{
|
|
return QVariant();
|
|
}
|
|
|
|
QVariant ValueHandler::representation(const QVariant& val)
|
|
{
|
|
return val.toString();
|
|
}
|
|
|
|
QString ValueHandler::expected()
|
|
{
|
|
return {};
|
|
}
|
|
|
|
QVariant ValueHandler::process(const QVariant& val)
|
|
{
|
|
return val;
|
|
}
|
|
|
|
// BOOL
|
|
|
|
Bool::Bool(bool def)
|
|
: m_def(def)
|
|
{}
|
|
|
|
bool Bool::check(const QVariant& val)
|
|
{
|
|
QString str = val.toString();
|
|
if (str != "true" && str != "false") {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
QVariant Bool::fallback()
|
|
{
|
|
return m_def;
|
|
}
|
|
|
|
QString Bool::expected()
|
|
{
|
|
return QStringLiteral("true or false");
|
|
}
|
|
|
|
// STRING
|
|
|
|
String::String(const QString& def)
|
|
: m_def(def)
|
|
{}
|
|
|
|
bool String::check(const QVariant&)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
QVariant String::fallback()
|
|
{
|
|
return m_def;
|
|
}
|
|
|
|
QString String::expected()
|
|
{
|
|
return QStringLiteral("string");
|
|
}
|
|
|
|
// COLOR
|
|
|
|
Color::Color(const QColor& def)
|
|
: m_def(def)
|
|
{}
|
|
|
|
bool Color::check(const QVariant& val)
|
|
{
|
|
QString str = val.toString();
|
|
// Disable #RGB, #RRRGGGBBB and #RRRRGGGGBBBB formats that QColor supports
|
|
return QColor::isValidColor(str) &&
|
|
(str[0] != '#' ||
|
|
(str.length() != 4 && str.length() != 10 && str.length() != 13));
|
|
}
|
|
|
|
QVariant Color::process(const QVariant& val)
|
|
{
|
|
QString str = val.toString();
|
|
QColor color(str);
|
|
if (str.length() == 9 && str[0] == '#') {
|
|
// Convert #RRGGBBAA (flameshot) to #AARRGGBB (QColor)
|
|
int blue = color.blue();
|
|
color.setBlue(color.green());
|
|
color.setGreen(color.red());
|
|
color.setRed(color.alpha());
|
|
color.setAlpha(blue);
|
|
}
|
|
return color;
|
|
}
|
|
|
|
QVariant Color::fallback()
|
|
{
|
|
return m_def;
|
|
}
|
|
|
|
QVariant Color::representation(const QVariant& val)
|
|
{
|
|
QString str = val.toString();
|
|
QColor color(str);
|
|
if (str.length() == 9 && str[0] == '#') {
|
|
// Convert #AARRGGBB (QColor) to #RRGGBBAA (flameshot)
|
|
int alpha = color.alpha();
|
|
color.setAlpha(color.red());
|
|
color.setRed(color.green());
|
|
color.setGreen(color.blue());
|
|
color.setBlue(alpha);
|
|
}
|
|
return color.name();
|
|
}
|
|
|
|
QString Color::expected()
|
|
{
|
|
return QStringLiteral("color name or hex value");
|
|
}
|
|
|
|
// BOUNDED INT
|
|
|
|
BoundedInt::BoundedInt(int min, int max, int def)
|
|
: m_min(min)
|
|
, m_max(max)
|
|
, m_def(def)
|
|
{}
|
|
|
|
bool BoundedInt::check(const QVariant& val)
|
|
{
|
|
QString str = val.toString();
|
|
bool conversionOk;
|
|
int num = str.toInt(&conversionOk);
|
|
return conversionOk && (m_max < m_min || num <= m_max);
|
|
}
|
|
|
|
QVariant BoundedInt::fallback()
|
|
{
|
|
return m_def;
|
|
}
|
|
|
|
QString BoundedInt::expected()
|
|
{
|
|
return QStringLiteral("number between %1 and %2").arg(m_min).arg(m_max);
|
|
}
|
|
|
|
// LOWER BOUNDED INT
|
|
|
|
LowerBoundedInt::LowerBoundedInt(int min, int def)
|
|
: m_min(min)
|
|
, m_def(def)
|
|
{}
|
|
|
|
bool LowerBoundedInt::check(const QVariant& val)
|
|
{
|
|
QString str = val.toString();
|
|
bool conversionOk;
|
|
int num = str.toInt(&conversionOk);
|
|
return conversionOk && num >= m_min;
|
|
}
|
|
|
|
QVariant LowerBoundedInt::fallback()
|
|
{
|
|
return m_def;
|
|
}
|
|
|
|
QString LowerBoundedInt::expected()
|
|
{
|
|
return QStringLiteral("number >= %1").arg(m_min);
|
|
}
|
|
|
|
// KEY SEQUENCE
|
|
|
|
KeySequence::KeySequence(const QKeySequence& fallback)
|
|
: m_fallback(fallback)
|
|
{}
|
|
|
|
bool KeySequence::check(const QVariant& val)
|
|
{
|
|
QString str = val.toString();
|
|
if (!str.isEmpty() && QKeySequence(str).toString().isEmpty()) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
QVariant KeySequence::fallback()
|
|
{
|
|
return m_fallback;
|
|
}
|
|
|
|
QString KeySequence::expected()
|
|
{
|
|
return QStringLiteral("keyboard shortcut");
|
|
}
|
|
|
|
// EXISTING DIR
|
|
|
|
bool ExistingDir::check(const QVariant& val)
|
|
{
|
|
if (!val.canConvert(QVariant::String) || val.toString().isEmpty()) {
|
|
return false;
|
|
}
|
|
QFileInfo info(val.toString());
|
|
return info.isDir() && info.exists();
|
|
}
|
|
|
|
QVariant ExistingDir::fallback()
|
|
{
|
|
using SP = QStandardPaths;
|
|
for (auto location :
|
|
{ SP::PicturesLocation, SP::HomeLocation, SP::TempLocation }) {
|
|
QString path = SP::writableLocation(location);
|
|
if (QFileInfo(path).isDir()) {
|
|
return path;
|
|
}
|
|
}
|
|
return {};
|
|
}
|
|
|
|
QString ExistingDir::expected()
|
|
{
|
|
return QStringLiteral("existing directory");
|
|
}
|
|
|
|
// FILENAME PATTERN
|
|
|
|
bool FilenamePattern::check(const QVariant&)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
QVariant FilenamePattern::fallback()
|
|
{
|
|
return ConfigHandler().filenamePatternDefault();
|
|
}
|
|
|
|
QVariant FilenamePattern::process(const QVariant& val)
|
|
{
|
|
QString str = val.toString();
|
|
return !str.isEmpty() ? val : fallback();
|
|
}
|
|
|
|
QString FilenamePattern::expected()
|
|
{
|
|
return QStringLiteral("please edit using the GUI");
|
|
}
|
|
|
|
// BUTTON LIST
|
|
|
|
using BType = CaptureTool::Type;
|
|
using BList = QList<CaptureTool::Type>;
|
|
|
|
bool ButtonList::check(const QVariant& val)
|
|
{
|
|
// TODO stop using CTB
|
|
using CTB = CaptureToolButton;
|
|
auto allButtons = CTB::getIterableButtonTypes();
|
|
for (int btn : val.value<QList<int>>()) {
|
|
if (!allButtons.contains(static_cast<BType>(btn))) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Helper
|
|
void sortButtons(BList& buttons)
|
|
{
|
|
std::sort(buttons.begin(), buttons.end(), [](BType a, BType b) {
|
|
return CaptureToolButton::getPriorityByButton(a) <
|
|
CaptureToolButton::getPriorityByButton(b);
|
|
});
|
|
}
|
|
|
|
QVariant ButtonList::process(const QVariant& val)
|
|
{
|
|
QList<int> intButtons = val.value<QList<int>>();
|
|
auto buttons = ButtonList::fromIntList(intButtons);
|
|
sortButtons(buttons);
|
|
return QVariant::fromValue(buttons);
|
|
}
|
|
|
|
QVariant ButtonList::fallback()
|
|
{
|
|
auto buttons = CaptureToolButton::getIterableButtonTypes();
|
|
buttons.removeOne(CaptureTool::TYPE_SIZEDECREASE);
|
|
buttons.removeOne(CaptureTool::TYPE_SIZEINCREASE);
|
|
sortButtons(buttons);
|
|
return QVariant::fromValue(buttons);
|
|
}
|
|
|
|
QVariant ButtonList::representation(const QVariant& val)
|
|
{
|
|
auto intList = toIntList(val.value<BList>());
|
|
normalizeButtons(intList);
|
|
return QVariant::fromValue(intList);
|
|
}
|
|
|
|
QString ButtonList::expected()
|
|
{
|
|
return QStringLiteral("please don't edit by hand");
|
|
}
|
|
|
|
QList<CaptureTool::Type> ButtonList::fromIntList(const QList<int>& l)
|
|
{
|
|
QList<CaptureTool::Type> buttons;
|
|
buttons.reserve(l.size());
|
|
for (auto const i : l)
|
|
buttons << static_cast<CaptureTool::Type>(i);
|
|
return buttons;
|
|
}
|
|
|
|
QList<int> ButtonList::toIntList(const QList<CaptureTool::Type>& l)
|
|
{
|
|
QList<int> buttons;
|
|
buttons.reserve(l.size());
|
|
for (auto const i : l)
|
|
buttons << static_cast<int>(i);
|
|
return buttons;
|
|
}
|
|
|
|
bool ButtonList::normalizeButtons(QList<int>& buttons)
|
|
{
|
|
QList<int> listTypesInt =
|
|
toIntList(CaptureToolButton::getIterableButtonTypes());
|
|
|
|
bool hasChanged = false;
|
|
for (int i = 0; i < buttons.size(); i++) {
|
|
if (!listTypesInt.contains(buttons.at(i))) {
|
|
buttons.removeAt(i);
|
|
hasChanged = true;
|
|
}
|
|
}
|
|
return hasChanged;
|
|
}
|
|
|
|
// USER COLORS
|
|
|
|
bool UserColors::check(const QVariant& val)
|
|
{
|
|
if (!val.isValid()) {
|
|
return true;
|
|
}
|
|
if (!val.canConvert(QVariant::StringList)) {
|
|
return false;
|
|
}
|
|
for (const QString& str : val.toStringList()) {
|
|
if (!QColor::isValidColor(str) && str != "picker") {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
QVariant UserColors::process(const QVariant& val)
|
|
{
|
|
QStringList strColors = val.toStringList();
|
|
if (strColors.isEmpty()) {
|
|
return fallback();
|
|
}
|
|
|
|
QVector<QColor> colors;
|
|
colors.reserve(strColors.size());
|
|
|
|
for (const QString& str : strColors) {
|
|
if (str != "picker") {
|
|
colors.append(QColor(str));
|
|
} else {
|
|
colors.append(QColor());
|
|
}
|
|
}
|
|
|
|
return QVariant::fromValue(colors);
|
|
}
|
|
|
|
QVariant UserColors::fallback()
|
|
{
|
|
return QVariant::fromValue(QVector<QColor>{ Qt::darkRed,
|
|
Qt::red,
|
|
Qt::yellow,
|
|
Qt::green,
|
|
Qt::darkGreen,
|
|
Qt::cyan,
|
|
Qt::blue,
|
|
Qt::magenta,
|
|
Qt::darkMagenta,
|
|
QColor() });
|
|
}
|
|
|
|
QString UserColors::expected()
|
|
{
|
|
return QStringLiteral("list of colors separated by comma");
|
|
}
|