Merge branch 'master' into git_is_pepega
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
// http://en.cppreference.com/w/cpp/algorithm/clamp
|
||||
|
||||
template <class T>
|
||||
constexpr const T &clamp(const T &v, const T &lo, const T &hi)
|
||||
{
|
||||
return assert(!(hi < lo)), (v < lo) ? lo : (hi < v) ? hi : v;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDir>
|
||||
#include <QString>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
// https://stackoverflow.com/a/13014491
|
||||
inline QString combinePath(const QString &a, const QString &b)
|
||||
{
|
||||
return QDir::cleanPath(a + QDir::separator() + b);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <QPointF>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
inline float distanceBetweenPoints(const QPointF &p1, const QPointF &p2)
|
||||
{
|
||||
QPointF tmp = p1 - p2;
|
||||
|
||||
float distance = 0.f;
|
||||
distance += tmp.x() * tmp.x();
|
||||
distance += tmp.y() * tmp.y();
|
||||
|
||||
return sqrt(distance);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "FunctionEventFilter.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
FunctionEventFilter::FunctionEventFilter(
|
||||
QObject *parent, std::function<bool(QObject *, QEvent *)> function)
|
||||
: QObject(parent)
|
||||
, function_(std::move(function))
|
||||
{
|
||||
}
|
||||
|
||||
bool FunctionEventFilter::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
return this->function_(watched, event);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <QEvent>
|
||||
#include <QObject>
|
||||
#include <functional>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class FunctionEventFilter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FunctionEventFilter(QObject *parent,
|
||||
std::function<bool(QObject *, QEvent *)> function);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
|
||||
private:
|
||||
std::function<bool(QObject *, QEvent *)> function_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,33 @@
|
||||
#include "FuzzyConvert.hpp"
|
||||
|
||||
#include <QRegularExpression>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
int fuzzyToInt(const QString &str, int default_)
|
||||
{
|
||||
static auto intFinder = QRegularExpression("[0-9]+");
|
||||
|
||||
auto match = intFinder.match(str);
|
||||
if (match.hasMatch())
|
||||
{
|
||||
return match.captured().toInt();
|
||||
}
|
||||
|
||||
return default_;
|
||||
}
|
||||
|
||||
float fuzzyToFloat(const QString &str, float default_)
|
||||
{
|
||||
static auto floatFinder = QRegularExpression("[0-9]+(\\.[0-9]+)?");
|
||||
|
||||
auto match = floatFinder.match(str);
|
||||
if (match.hasMatch())
|
||||
{
|
||||
return match.captured().toFloat();
|
||||
}
|
||||
|
||||
return default_;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
int fuzzyToInt(const QString &str, int default_);
|
||||
float fuzzyToFloat(const QString &str, float default_);
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "Helpers.hpp"
|
||||
|
||||
#include <QUuid>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
QString generateUuid()
|
||||
{
|
||||
auto uuid = QUuid::createUuid();
|
||||
return uuid.toString();
|
||||
}
|
||||
|
||||
QString formatRichLink(const QString &url, bool file)
|
||||
{
|
||||
return QString("<a href=\"") + (file ? "file:///" : "") + url + "\">" +
|
||||
url + "</a>";
|
||||
}
|
||||
|
||||
QString formatRichNamedLink(const QString &url, const QString &name, bool file)
|
||||
{
|
||||
return QString("<a href=\"") + (file ? "file:///" : "") + url + "\">" +
|
||||
name + "</a>";
|
||||
}
|
||||
|
||||
QString shortenString(const QString &str, unsigned maxWidth)
|
||||
{
|
||||
auto shortened = QString(str);
|
||||
|
||||
if (str.size() > int(maxWidth))
|
||||
{
|
||||
shortened.resize(int(maxWidth));
|
||||
shortened += "...";
|
||||
}
|
||||
|
||||
return shortened;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <QString>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
template <typename... Args>
|
||||
auto fS(Args &&... args)
|
||||
{
|
||||
return fmt::format(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
QString generateUuid();
|
||||
|
||||
QString formatRichLink(const QString &url, bool file = false);
|
||||
|
||||
QString formatRichNamedLink(const QString &url, const QString &name,
|
||||
bool file = false);
|
||||
|
||||
QString shortenString(const QString &str, unsigned maxWidth = 50);
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
namespace fmt {
|
||||
|
||||
// format_arg for QString
|
||||
inline void format_arg(BasicFormatter<char> &f, const char *&, const QString &v)
|
||||
{
|
||||
f.writer().write("{}", v.toStdString());
|
||||
}
|
||||
|
||||
} // namespace fmt
|
||||
@@ -22,14 +22,12 @@ void initUpdateButton(Button &button,
|
||||
dialog->buttonClicked.connect([&button](auto buttonType) {
|
||||
switch (buttonType)
|
||||
{
|
||||
case UpdateDialog::Dismiss:
|
||||
{
|
||||
case UpdateDialog::Dismiss: {
|
||||
button.hide();
|
||||
}
|
||||
break;
|
||||
case UpdateDialog::Install:
|
||||
{
|
||||
Updates::getInstance().installUpdates();
|
||||
case UpdateDialog::Install: {
|
||||
Updates::instance().installUpdates();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -41,18 +39,18 @@ void initUpdateButton(Button &button,
|
||||
|
||||
// update image when state changes
|
||||
auto updateChange = [&button](auto) {
|
||||
button.setVisible(Updates::getInstance().shouldShowUpdateButton());
|
||||
button.setVisible(Updates::instance().shouldShowUpdateButton());
|
||||
|
||||
auto imageUrl = Updates::getInstance().isError()
|
||||
auto imageUrl = Updates::instance().isError()
|
||||
? ":/buttons/updateError.png"
|
||||
: ":/buttons/update.png";
|
||||
button.setPixmap(QPixmap(imageUrl));
|
||||
};
|
||||
|
||||
updateChange(Updates::getInstance().getStatus());
|
||||
updateChange(Updates::instance().getStatus());
|
||||
|
||||
signalHolder.managedConnect(
|
||||
Updates::getInstance().statusUpdated,
|
||||
Updates::instance().statusUpdated,
|
||||
[updateChange](auto status) { updateChange(status); });
|
||||
}
|
||||
|
||||
|
||||
+6
-12
@@ -19,38 +19,32 @@ inline QString parseTagString(const QString &input)
|
||||
|
||||
switch (c.cell())
|
||||
{
|
||||
case 'n':
|
||||
{
|
||||
case 'n': {
|
||||
output.replace(i, 2, '\n');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
{
|
||||
case 'r': {
|
||||
output.replace(i, 2, '\r');
|
||||
}
|
||||
break;
|
||||
|
||||
case 's':
|
||||
{
|
||||
case 's': {
|
||||
output.replace(i, 2, ' ');
|
||||
}
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
{
|
||||
case '\\': {
|
||||
output.replace(i, 2, '\\');
|
||||
}
|
||||
break;
|
||||
|
||||
case ':':
|
||||
{
|
||||
case ':': {
|
||||
output.replace(i, 2, ';');
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
default: {
|
||||
output.remove(i, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <QLayout>
|
||||
#include <QWidget>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
using LayoutItem = boost::variant<QWidget *, QLayout *>;
|
||||
|
||||
template <typename T>
|
||||
T *makeLayout(std::initializer_list<LayoutItem> items)
|
||||
{
|
||||
auto t = new T;
|
||||
|
||||
for (auto &item : items)
|
||||
{
|
||||
switch (item.which())
|
||||
{
|
||||
case 0:
|
||||
t->addItem(new QWidgetItem(boost::get<QWidget *>(item)));
|
||||
break;
|
||||
case 1:
|
||||
t->addItem(boost::get<QLayout *>(item));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
template <typename T, typename With>
|
||||
T *makeWidget(With with)
|
||||
{
|
||||
auto t = new T;
|
||||
|
||||
with(t);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include <QRunnable>
|
||||
#include <QThreadPool>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#define async_exec(a) \
|
||||
QThreadPool::globalInstance()->start(new LambdaRunnable(a));
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class LambdaRunnable : public QRunnable
|
||||
{
|
||||
public:
|
||||
LambdaRunnable(std::function<void()> action)
|
||||
{
|
||||
this->action_ = action;
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
this->action_();
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void()> action_;
|
||||
};
|
||||
|
||||
// Taken from
|
||||
// https://stackoverflow.com/questions/21646467/how-to-execute-a-functor-or-a-lambda-in-a-given-thread-in-qt-gcd-style
|
||||
// Qt 5/4 - preferred, has least allocations
|
||||
template <typename F>
|
||||
static void postToThread(F &&fun, QObject *obj = qApp)
|
||||
{
|
||||
struct Event : public QEvent {
|
||||
using Fun = typename std::decay<F>::type;
|
||||
Fun fun;
|
||||
Event(Fun &&fun)
|
||||
: QEvent(QEvent::None)
|
||||
, fun(std::move(fun))
|
||||
{
|
||||
}
|
||||
Event(const Fun &fun)
|
||||
: QEvent(QEvent::None)
|
||||
, fun(fun)
|
||||
{
|
||||
}
|
||||
~Event() override
|
||||
{
|
||||
fun();
|
||||
}
|
||||
};
|
||||
QCoreApplication::postEvent(obj, new Event(std::forward<F>(fun)));
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -61,10 +61,10 @@ private:
|
||||
// new
|
||||
if (other)
|
||||
{
|
||||
this->conn_ =
|
||||
QObject::connect(other, &QObject::destroyed, qApp,
|
||||
[this](QObject *) { this->set(nullptr); },
|
||||
Qt::DirectConnection);
|
||||
this->conn_ = QObject::connect(
|
||||
other, &QObject::destroyed, qApp,
|
||||
[this](QObject *) { this->set(nullptr); },
|
||||
Qt::DirectConnection);
|
||||
}
|
||||
|
||||
this->t_ = other;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
namespace std {
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||
template <>
|
||||
struct hash<QString> {
|
||||
std::size_t operator()(const QString &s) const
|
||||
@@ -12,5 +13,6 @@ struct hash<QString> {
|
||||
return qHash(s);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace std
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <pajlada/serialize.hpp>
|
||||
|
||||
namespace pajlada {
|
||||
|
||||
template <>
|
||||
struct Serialize<QString> {
|
||||
static rapidjson::Value get(const QString &value,
|
||||
rapidjson::Document::AllocatorType &a)
|
||||
{
|
||||
return rapidjson::Value(value.toUtf8(), a);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Deserialize<QString> {
|
||||
static QString get(const rapidjson::Value &value, bool *error = nullptr)
|
||||
{
|
||||
if (!value.IsString())
|
||||
{
|
||||
PAJLADA_REPORT_ERROR(error)
|
||||
return QString{};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return QString::fromUtf8(value.GetString(),
|
||||
value.GetStringLength());
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
// int x = 5;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// int y = 5;
|
||||
}
|
||||
|
||||
return QString{};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace pajlada
|
||||
@@ -0,0 +1,174 @@
|
||||
#pragma once
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
QStringList getValidLinks()
|
||||
{
|
||||
return {
|
||||
R"(http://github.com/)",
|
||||
R"(https://github.com/)",
|
||||
R"(http://username@github.com/)",
|
||||
R"(https://username@github.com/)",
|
||||
R"(http://pajlada.github.io)",
|
||||
R"(https://pajlada.github.io)",
|
||||
R"(http://pajlada.github.io/)",
|
||||
R"(https://pajlada.github.io/)",
|
||||
R"(http://github.com/some/random/path)",
|
||||
R"(https://github.com/some/random/path)",
|
||||
R"(http://github.com?query=value)",
|
||||
R"(https://github.com?query=value)",
|
||||
R"(http://github.com?query=value&abc=123)",
|
||||
R"(https://github.com?query=value&abc=123)",
|
||||
R"(http://github.com/?query=value&abc=123&yhf=abc_def)",
|
||||
R"(http://github.com/?query=value&abc=123&yhf)",
|
||||
R"(http://github.com?query=value&abc=)",
|
||||
R"(http://github.com?query=value&abc=)",
|
||||
R"(http://github.com/#block)",
|
||||
R"(https://github.com/#anchor)",
|
||||
R"(http://github.com/path/?qs=true#block)",
|
||||
R"(https://github.com/path/?qs=true#anchor)",
|
||||
R"(github.com/)",
|
||||
R"(username@github.com/)",
|
||||
R"(pajlada.github.io)",
|
||||
R"(pajlada.github.io/)",
|
||||
R"(github.com/some/random/path)",
|
||||
R"(github.com?query=value)",
|
||||
R"(github.com?query=value&abc=123)",
|
||||
R"(github.com/?query=value&abc=123&yhf=abc_def)",
|
||||
R"(github.com/?query=value&abc=123&yhf)",
|
||||
R"(github.com?query=value&abc=)",
|
||||
R"(github.com?query=value&abc=)",
|
||||
R"(github.com/#block)",
|
||||
R"(github.com/path/?qs=true#block)",
|
||||
R"(HTTP://GITHUB.COM/)",
|
||||
R"(HTTPS://GITHUB.COM/)",
|
||||
R"(HTTP://USERNAME@GITHUB.COM/)",
|
||||
R"(HTTPS://USERNAME@GITHUB.COM/)",
|
||||
R"(HTTP://PAJLADA.GITHUB.IO)",
|
||||
R"(HTTPS://PAJLADA.GITHUB.IO)",
|
||||
R"(HTTP://PAJLADA.GITHUB.IO/)",
|
||||
R"(HTTPS://PAJLADA.GITHUB.IO/)",
|
||||
R"(HTTP://GITHUB.COM/SOME/RANDOM/PATH)",
|
||||
R"(HTTPS://GITHUB.COM/SOME/RANDOM/PATH)",
|
||||
R"(HTTP://GITHUB.COM?QUERY=VALUE)",
|
||||
R"(HTTPS://GITHUB.COM?QUERY=VALUE)",
|
||||
R"(HTTP://GITHUB.COM?QUERY=VALUE&ABC=123)",
|
||||
R"(HTTPS://GITHUB.COM?QUERY=VALUE&ABC=123)",
|
||||
R"(HTTP://GITHUB.COM/?QUERY=VALUE&ABC=123&YHF=ABC_DEF)",
|
||||
R"(HTTP://GITHUB.COM/?QUERY=VALUE&ABC=123&YHF)",
|
||||
R"(HTTP://GITHUB.COM?QUERY=VALUE&ABC=)",
|
||||
R"(HTTP://GITHUB.COM?QUERY=VALUE&ABC=)",
|
||||
R"(HTTP://GITHUB.COM/#BLOCK)",
|
||||
R"(HTTPS://GITHUB.COM/#ANCHOR)",
|
||||
R"(HTTP://GITHUB.COM/PATH/?QS=TRUE#BLOCK)",
|
||||
R"(HTTPS://GITHUB.COM/PATH/?QS=TRUE#ANCHOR)",
|
||||
R"(GITHUB.COM/)",
|
||||
R"(USERNAME@GITHUB.COM/)",
|
||||
R"(PAJLADA.GITHUB.IO)",
|
||||
R"(PAJLADA.GITHUB.IO/)",
|
||||
R"(GITHUB.COM/SOME/RANDOM/PATH)",
|
||||
R"(GITHUB.COM?QUERY=VALUE)",
|
||||
R"(GITHUB.COM?QUERY=VALUE&ABC=123)",
|
||||
R"(GITHUB.COM/?QUERY=VALUE&ABC=123&YHF=ABC_DEF)",
|
||||
R"(GITHUB.COM/?QUERY=VALUE&ABC=123&YHF)",
|
||||
R"(GITHUB.COM?QUERY=VALUE&ABC=)",
|
||||
R"(GITHUB.COM?QUERY=VALUE&ABC=)",
|
||||
R"(GITHUB.COM/#BLOCK)",
|
||||
R"(GITHUB.COM/PATH/?QS=TRUE#BLOCK)",
|
||||
R"(http://foo.com/blah_blah)",
|
||||
R"(http://foo.com/blah_blah/)",
|
||||
R"(http://foo.com/blah_blah_(wikipedia))",
|
||||
R"(http://foo.com/blah_blah_(wikipedia)_(again))",
|
||||
R"(http://www.example.com/wpstyle/?p=364)",
|
||||
R"(https://www.example.com/foo/?bar=baz&inga=42&quux)",
|
||||
R"(http://✪df.ws/123)",
|
||||
R"(http://userid@example.com)",
|
||||
R"(http://userid@example.com/)",
|
||||
R"(http://userid@example.com:8080)",
|
||||
R"(http://userid@example.com:8080/)",
|
||||
R"(http://142.42.1.1/)",
|
||||
R"(http://142.42.1.1:8080/)",
|
||||
R"(http://➡.ws/䨹)",
|
||||
R"(http://⌘.ws)",
|
||||
R"(http://⌘.ws/)",
|
||||
R"(http://foo.com/blah_(wikipedia)#cite-1)",
|
||||
R"(http://foo.com/blah_(wikipedia)_blah#cite-1)",
|
||||
R"(http://foo.com/unicode_(✪)_in_parens)",
|
||||
R"(http://foo.com/(something)?after=parens)",
|
||||
R"(http://☺.damowmow.com/)",
|
||||
R"(http://code.google.com/events/#&product=browser)",
|
||||
R"(http://j.mp)",
|
||||
R"(ftp://foo.bar/baz)",
|
||||
R"(http://foo.bar/?q=Test%20URL-encoded%20stuff)",
|
||||
R"(http://مثال.إختبار)",
|
||||
R"(http://例子.测试)",
|
||||
R"(http://उदाहरण.परीक्षा)",
|
||||
R"(http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com)",
|
||||
R"(http://1337.net)",
|
||||
R"(http://a.b-c.de)",
|
||||
R"(http://223.255.255.254)",
|
||||
};
|
||||
}
|
||||
|
||||
QStringList getValidButIgnoredLinks()
|
||||
{
|
||||
return {
|
||||
R"(http://username:password@github.com/)",
|
||||
R"(https://username:password@github.com/)",
|
||||
R"(http://userid:password@example.com)",
|
||||
R"(http://userid:password@example.com/)",
|
||||
R"(http://userid:password@example.com:8080)",
|
||||
R"(http://userid:password@example.com:8080/)",
|
||||
};
|
||||
}
|
||||
|
||||
QStringList getInvalidLinks()
|
||||
{
|
||||
return {
|
||||
R"(1.40)",
|
||||
R"(test..)",
|
||||
R"(test.)",
|
||||
R"(http://)",
|
||||
R"(http://.)",
|
||||
R"(http://..)",
|
||||
R"(http://../)",
|
||||
R"(http://?)",
|
||||
R"(http://??)",
|
||||
R"(http://??/)",
|
||||
R"(http://#)",
|
||||
R"(http://##)",
|
||||
R"(http://##/)",
|
||||
R"(http://foo.bar?q=Spaces should be encoded)",
|
||||
R"(//)",
|
||||
R"(//a)",
|
||||
R"(///a)",
|
||||
R"(///)",
|
||||
R"(http:///a)",
|
||||
R"(foo.com)",
|
||||
R"(rdar://1234)",
|
||||
R"(h://test)",
|
||||
R"(http:// shouldfail.com)",
|
||||
R"(:// should fail)",
|
||||
R"(http://foo.bar/foo(bar)baz quux)",
|
||||
R"(ftps://foo.bar/)",
|
||||
R"(http://-error-.invalid/)",
|
||||
R"(http://a.b--c.de/)",
|
||||
R"(http://-a.b.co)",
|
||||
R"(http://a.b-.co)",
|
||||
R"(http://0.0.0.0)",
|
||||
R"(http://10.1.1.0)",
|
||||
R"(http://10.1.1.255)",
|
||||
R"(http://224.1.1.1)",
|
||||
R"(http://1.1.1.1.1)",
|
||||
R"(http://123.123.123)",
|
||||
R"(http://3628126748)",
|
||||
R"(http://.www.foo.bar/)",
|
||||
R"(http://www.foo.bar./)",
|
||||
R"(http://.www.foo.bar./)",
|
||||
R"(http://10.1.1.1)",
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <QShortcut>
|
||||
#include <QWidget>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
template <typename WidgetType, typename Func>
|
||||
inline void createShortcut(WidgetType *w, const char *key, Func func)
|
||||
{
|
||||
auto s = new QShortcut(QKeySequence(key), w);
|
||||
s->setContext(Qt::WidgetWithChildrenShortcut);
|
||||
QObject::connect(s, &QShortcut::activated, w, func);
|
||||
}
|
||||
|
||||
template <typename WidgetType, typename Func>
|
||||
inline void createWindowShortcut(WidgetType *w, const char *key, Func func)
|
||||
{
|
||||
auto s = new QShortcut(QKeySequence(key), w);
|
||||
s->setContext(Qt::WindowShortcut);
|
||||
QObject::connect(s, &QShortcut::activated, w, func);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -199,7 +199,7 @@ void openStreamlinkForChannel(const QString &channel)
|
||||
{
|
||||
QString channelURL = "twitch.tv/" + channel;
|
||||
|
||||
QString preferredQuality = getSettings()->preferredQuality;
|
||||
QString preferredQuality = getSettings()->preferredQuality.getValue();
|
||||
preferredQuality = preferredQuality.toLower();
|
||||
|
||||
if (preferredQuality == "choose")
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
#include "WindowsHelper.hpp"
|
||||
|
||||
#include <QSettings>
|
||||
|
||||
#ifdef USEWINSDK
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
typedef enum MONITOR_DPI_TYPE {
|
||||
MDT_EFFECTIVE_DPI = 0,
|
||||
MDT_ANGULAR_DPI = 1,
|
||||
MDT_RAW_DPI = 2,
|
||||
MDT_DEFAULT = MDT_EFFECTIVE_DPI
|
||||
} MONITOR_DPI_TYPE;
|
||||
|
||||
typedef HRESULT(CALLBACK *GetDpiForMonitor_)(HMONITOR, MONITOR_DPI_TYPE, UINT *,
|
||||
UINT *);
|
||||
|
||||
boost::optional<UINT> getWindowDpi(HWND hwnd)
|
||||
{
|
||||
static HINSTANCE shcore = LoadLibrary(L"Shcore.dll");
|
||||
if (shcore != nullptr)
|
||||
{
|
||||
if (auto getDpiForMonitor =
|
||||
GetDpiForMonitor_(GetProcAddress(shcore, "GetDpiForMonitor")))
|
||||
{
|
||||
HMONITOR monitor =
|
||||
MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
|
||||
UINT xScale, yScale;
|
||||
|
||||
getDpiForMonitor(monitor, MDT_DEFAULT, &xScale, &yScale);
|
||||
|
||||
return xScale;
|
||||
}
|
||||
}
|
||||
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
typedef HRESULT(CALLBACK *OleFlushClipboard_)();
|
||||
|
||||
void flushClipboard()
|
||||
{
|
||||
static HINSTANCE ole32 = LoadLibrary(L"Ole32.dll");
|
||||
if (ole32 != nullptr)
|
||||
{
|
||||
if (auto oleFlushClipboard =
|
||||
OleFlushClipboard_(GetProcAddress(ole32, "OleFlushClipboard")))
|
||||
{
|
||||
oleFlushClipboard();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr const char *runKey =
|
||||
"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run";
|
||||
|
||||
bool isRegisteredForStartup()
|
||||
{
|
||||
QSettings settings(runKey, QSettings::NativeFormat);
|
||||
|
||||
return !settings.value("Chatterino").toString().isEmpty();
|
||||
}
|
||||
|
||||
void setRegisteredForStartup(bool isRegistered)
|
||||
{
|
||||
QSettings settings(runKey, QSettings::NativeFormat);
|
||||
|
||||
if (isRegistered)
|
||||
{
|
||||
auto exePath = QFileInfo(QCoreApplication::applicationFilePath())
|
||||
.absoluteFilePath()
|
||||
.replace('/', '\\');
|
||||
|
||||
settings.setValue("Chatterino", "\"" + exePath + "\" --autorun");
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.remove("Chatterino");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef USEWINSDK
|
||||
|
||||
# include <Windows.h>
|
||||
# include <boost/optional.hpp>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
boost::optional<UINT> getWindowDpi(HWND hwnd);
|
||||
void flushClipboard();
|
||||
|
||||
bool isRegisteredForStartup();
|
||||
void setRegisteredForStartup(bool isRegistered);
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user