moved BaseWindow and related files into appbase

This commit is contained in:
fourtf 2018-11-22 22:10:29 +01:00
parent 0f8a1a3ff8
commit 38b23d77ce
22 changed files with 6 additions and 6365 deletions

View file

@ -16,6 +16,8 @@ TARGET = chatterino
TEMPLATE = app
PRECOMPILED_HEADER = src/PrecompiledHeader.hpp
CONFIG += precompile_header
DEFINES += CHATTERINO
DEFINES += "AB_NAMESPACE=chatterino"
useBreakpad {
LIBS += -L$$PWD/lib/qBreakpad/handler/build
@ -39,7 +41,6 @@ macx {
# Submodules
include(lib/appbase.pri)
include(lib/humanize.pri)
include(lib/fmt.pri)
DEFINES += IRC_NAMESPACE=Communi
include(lib/libcommuni.pri)
include(lib/websocketpp.pri)
@ -114,11 +115,9 @@ SOURCES += \
src/util/DebugCount.cpp \
src/util/RapidjsonHelpers.cpp \
src/util/StreamLink.cpp \
src/util/WindowsHelper.cpp \
src/widgets/AccountSwitchPopupWidget.cpp \
src/widgets/AccountSwitchWidget.cpp \
src/widgets/AttachedWindow.cpp \
src/widgets/BaseWindow.cpp \
src/widgets/dialogs/EmotePopup.cpp \
src/widgets/dialogs/LastRunCrashDialog.cpp \
src/widgets/dialogs/LoginDialog.cpp \
@ -142,7 +141,6 @@ SOURCES += \
src/widgets/helper/SettingsDialogTab.cpp \
src/widgets/helper/SignalLabel.cpp \
src/widgets/helper/TitlebarButton.cpp \
src/widgets/Label.cpp \
src/widgets/Notebook.cpp \
src/widgets/Scrollbar.cpp \
src/widgets/settingspages/AboutPage.cpp \
@ -164,13 +162,11 @@ SOURCES += \
src/widgets/splits/SplitInput.cpp \
src/widgets/splits/SplitOverlay.cpp \
src/widgets/StreamView.cpp \
src/widgets/TooltipWidget.cpp \
src/widgets/Window.cpp \
src/common/LinkParser.cpp \
src/controllers/moderationactions/ModerationActions.cpp \
src/singletons/NativeMessaging.cpp \
src/singletons/Emotes.cpp \
src/singletons/Fonts.cpp \
src/singletons/Logging.cpp \
src/singletons/Paths.cpp \
src/singletons/Resources.cpp \
@ -204,7 +200,6 @@ SOURCES += \
src/controllers/notifications/NotificationModel.cpp \
src/singletons/Toasts.cpp \
src/common/DownloadManager.cpp \
src/widgets/helper/EffectLabel.cpp \
src/widgets/helper/Button.cpp \
src/messages/MessageContainer.cpp \
src/debug/Benchmark.cpp \
@ -233,7 +228,6 @@ HEADERS += \
src/common/NetworkWorker.hpp \
src/common/NullablePtr.hpp \
src/common/ProviderId.hpp \
src/util/RapidJsonSerializeQString.hpp \
src/common/SignalVectorModel.hpp \
src/common/Version.hpp \
src/controllers/accounts/Account.hpp \
@ -303,18 +297,15 @@ HEADERS += \
src/util/Helpers.hpp \
src/util/IrcHelpers.hpp \
src/util/LayoutCreator.hpp \
src/util/PostToThread.hpp \
src/util/QStringHash.hpp \
src/util/RapidjsonHelpers.hpp \
src/util/RemoveScrollAreaBackground.hpp \
src/util/SharedPtrElementLess.hpp \
src/util/StandardItemHelper.hpp \
src/util/StreamLink.hpp \
src/util/WindowsHelper.hpp \
src/widgets/AccountSwitchPopupWidget.hpp \
src/widgets/AccountSwitchWidget.hpp \
src/widgets/AttachedWindow.hpp \
src/widgets/BaseWindow.hpp \
src/widgets/dialogs/EmotePopup.hpp \
src/widgets/dialogs/LastRunCrashDialog.hpp \
src/widgets/dialogs/LoginDialog.hpp \
@ -337,10 +328,8 @@ HEADERS += \
src/widgets/helper/ScrollbarHighlight.hpp \
src/widgets/helper/SearchPopup.hpp \
src/widgets/helper/SettingsDialogTab.hpp \
src/widgets/helper/Shortcut.hpp \
src/widgets/helper/SignalLabel.hpp \
src/widgets/helper/TitlebarButton.hpp \
src/widgets/Label.hpp \
src/widgets/Notebook.hpp \
src/widgets/Scrollbar.hpp \
src/widgets/settingspages/AboutPage.hpp \
@ -362,14 +351,12 @@ HEADERS += \
src/widgets/splits/SplitInput.hpp \
src/widgets/splits/SplitOverlay.hpp \
src/widgets/StreamView.hpp \
src/widgets/TooltipWidget.hpp \
src/widgets/Window.hpp \
src/providers/twitch/TwitchCommon.hpp \
src/util/IsBigEndian.hpp \
src/common/LinkParser.hpp \
src/controllers/moderationactions/ModerationActions.hpp \
src/singletons/Emotes.hpp \
src/singletons/Fonts.hpp \
src/singletons/Logging.hpp \
src/singletons/Paths.hpp \
src/singletons/Resources.hpp \
@ -409,7 +396,6 @@ HEADERS += \
src/controllers/notifications/NotificationModel.hpp \
src/singletons/Toasts.hpp \
src/common/DownloadManager.hpp \
src/widgets/helper/EffectLabel.hpp \
src/util/LayoutHelper.hpp \
src/widgets/helper/Button.hpp \
src/messages/MessageContainer.hpp \

View file

@ -1,5 +1,3 @@
Third party libraries are stored here
Fetched via `git submodule update --init --recursive`
Using [fmtlib/fmt](https://github.com/fmtlib/fmt)

View file

@ -1,4 +0,0 @@
# fmt
SOURCES += $$PWD/../lib/fmt/fmt/format.cpp
INCLUDEPATH += $$PWD/../lib/fmt/

View file

@ -1,535 +0,0 @@
/*
Formatting library for C++
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "format.h"
#include <string.h>
#include <cctype>
#include <cerrno>
#include <climits>
#include <cmath>
#include <cstdarg>
#include <cstddef> // for std::ptrdiff_t
#if defined(_WIN32) && defined(__MINGW32__)
# include <cstring>
#endif
#if FMT_USE_WINDOWS_H
# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN)
# define WIN32_LEAN_AND_MEAN
# endif
# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
# include <windows.h>
# else
# define NOMINMAX
# include <windows.h>
# undef NOMINMAX
# endif
#endif
#if FMT_EXCEPTIONS
# define FMT_TRY try
# define FMT_CATCH(x) catch (x)
#else
# define FMT_TRY if (true)
# define FMT_CATCH(x) if (false)
#endif
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4127) // conditional expression is constant
# pragma warning(disable: 4702) // unreachable code
// Disable deprecation warning for strerror. The latter is not called but
// MSVC fails to detect it.
# pragma warning(disable: 4996)
#endif
// Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available.
static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
return fmt::internal::Null<>();
}
static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
return fmt::internal::Null<>();
}
namespace fmt {
FMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT {}
FMT_FUNC FormatError::~FormatError() FMT_DTOR_NOEXCEPT {}
FMT_FUNC SystemError::~SystemError() FMT_DTOR_NOEXCEPT {}
namespace {
#ifndef _MSC_VER
# define FMT_SNPRINTF snprintf
#else // _MSC_VER
inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
va_list args;
va_start(args, format);
int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
va_end(args);
return result;
}
# define FMT_SNPRINTF fmt_snprintf
#endif // _MSC_VER
#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
# define FMT_SWPRINTF snwprintf
#else
# define FMT_SWPRINTF swprintf
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
const char RESET_COLOR[] = "\x1b[0m";
typedef void (*FormatFunc)(Writer &, int, StringRef);
// Portable thread-safe version of strerror.
// Sets buffer to point to a string describing the error code.
// This can be either a pointer to a string stored in buffer,
// or a pointer to some static immutable string.
// Returns one of the following values:
// 0 - success
// ERANGE - buffer is not large enough to store the error message
// other - failure
// Buffer should be at least of size 1.
int safe_strerror(
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
class StrError {
private:
int error_code_;
char *&buffer_;
std::size_t buffer_size_;
// A noop assignment operator to avoid bogus warnings.
void operator=(const StrError &) {}
// Handle the result of XSI-compliant version of strerror_r.
int handle(int result) {
// glibc versions before 2.13 return result in errno.
return result == -1 ? errno : result;
}
// Handle the result of GNU-specific version of strerror_r.
int handle(char *message) {
// If the buffer is full then the message is probably truncated.
if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
return ERANGE;
buffer_ = message;
return 0;
}
// Handle the case when strerror_r is not available.
int handle(internal::Null<>) {
return fallback(strerror_s(buffer_, buffer_size_, error_code_));
}
// Fallback to strerror_s when strerror_r is not available.
int fallback(int result) {
// If the buffer is full then the message is probably truncated.
return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
ERANGE : result;
}
// Fallback to strerror if strerror_r and strerror_s are not available.
int fallback(internal::Null<>) {
errno = 0;
buffer_ = strerror(error_code_);
return errno;
}
public:
StrError(int err_code, char *&buf, std::size_t buf_size)
: error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
int run() {
// Suppress a warning about unused strerror_r.
strerror_r(0, FMT_NULL, "");
return handle(strerror_r(error_code_, buffer_, buffer_size_));
}
};
return StrError(error_code, buffer, buffer_size).run();
}
void format_error_code(Writer &out, int error_code,
StringRef message) FMT_NOEXCEPT {
// Report error code making sure that the output fits into
// INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
// bad_alloc.
out.clear();
static const char SEP[] = ": ";
static const char ERROR_STR[] = "error ";
// Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
typedef internal::IntTraits<int>::MainType MainType;
MainType abs_value = static_cast<MainType>(error_code);
if (internal::is_negative(error_code)) {
abs_value = 0 - abs_value;
++error_code_size;
}
error_code_size += internal::count_digits(abs_value);
if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size)
out << message << SEP;
out << ERROR_STR << error_code;
assert(out.size() <= internal::INLINE_BUFFER_SIZE);
}
void report_error(FormatFunc func, int error_code,
StringRef message) FMT_NOEXCEPT {
MemoryWriter full_message;
func(full_message, error_code, message);
// Use Writer::data instead of Writer::c_str to avoid potential memory
// allocation.
std::fwrite(full_message.data(), full_message.size(), 1, stderr);
std::fputc('\n', stderr);
}
} // namespace
FMT_FUNC void SystemError::init(
int err_code, CStringRef format_str, ArgList args) {
error_code_ = err_code;
MemoryWriter w;
format_system_error(w, err_code, format(format_str, args));
std::runtime_error &base = *this;
base = std::runtime_error(w.str());
}
template <typename T>
int internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, T value) {
if (width == 0) {
return precision < 0 ?
FMT_SNPRINTF(buffer, size, format, value) :
FMT_SNPRINTF(buffer, size, format, precision, value);
}
return precision < 0 ?
FMT_SNPRINTF(buffer, size, format, width, value) :
FMT_SNPRINTF(buffer, size, format, width, precision, value);
}
template <typename T>
int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, T value) {
if (width == 0) {
return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, value) :
FMT_SWPRINTF(buffer, size, format, precision, value);
}
return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, width, value) :
FMT_SWPRINTF(buffer, size, format, width, precision, value);
}
template <typename T>
const char internal::BasicData<T>::DIGITS[] =
"0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859"
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899";
#define FMT_POWERS_OF_10(factor) \
factor * 10, \
factor * 100, \
factor * 1000, \
factor * 10000, \
factor * 100000, \
factor * 1000000, \
factor * 10000000, \
factor * 100000000, \
factor * 1000000000
template <typename T>
const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = {
0, FMT_POWERS_OF_10(1)
};
template <typename T>
const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = {
0,
FMT_POWERS_OF_10(1),
FMT_POWERS_OF_10(ULongLong(1000000000)),
// Multiply several constants instead of using a single long long constant
// to avoid warnings about C++98 not supporting long long.
ULongLong(1000000000) * ULongLong(1000000000) * 10
};
FMT_FUNC void internal::report_unknown_type(char code, const char *type) {
(void)type;
if (std::isprint(static_cast<unsigned char>(code))) {
FMT_THROW(FormatError(
format("unknown format code '{}' for {}", code, type)));
}
FMT_THROW(FormatError(
format("unknown format code '\\x{:02x}' for {}",
static_cast<unsigned>(code), type)));
}
#if FMT_USE_WINDOWS_H
FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) {
static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
if (s.size() > INT_MAX)
FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
int s_size = static_cast<int>(s.size());
int length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
if (length == 0)
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
buffer_.resize(length + 1);
length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
if (length == 0)
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
buffer_[length] = 0;
}
FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) {
if (int error_code = convert(s)) {
FMT_THROW(WindowsError(error_code,
"cannot convert string from UTF-16 to UTF-8"));
}
}
FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) {
if (s.size() > INT_MAX)
return ERROR_INVALID_PARAMETER;
int s_size = static_cast<int>(s.size());
int length = WideCharToMultiByte(
CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
if (length == 0)
return GetLastError();
buffer_.resize(length + 1);
length = WideCharToMultiByte(
CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
if (length == 0)
return GetLastError();
buffer_[length] = 0;
return 0;
}
FMT_FUNC void WindowsError::init(
int err_code, CStringRef format_str, ArgList args) {
error_code_ = err_code;
MemoryWriter w;
internal::format_windows_error(w, err_code, format(format_str, args));
std::runtime_error &base = *this;
base = std::runtime_error(w.str());
}
FMT_FUNC void internal::format_windows_error(
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
FMT_TRY {
MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;
buffer.resize(INLINE_BUFFER_SIZE);
for (;;) {
wchar_t *system_message = &buffer[0];
int result = FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
system_message, static_cast<uint32_t>(buffer.size()), FMT_NULL);
if (result != 0) {
UTF16ToUTF8 utf8_message;
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
out << message << ": " << utf8_message;
return;
}
break;
}
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
break; // Can't get error message, report error code instead.
buffer.resize(buffer.size() * 2);
}
} FMT_CATCH(...) {}
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
}
#endif // FMT_USE_WINDOWS_H
FMT_FUNC void format_system_error(
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
FMT_TRY {
internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer;
buffer.resize(internal::INLINE_BUFFER_SIZE);
for (;;) {
char *system_message = &buffer[0];
int result = safe_strerror(error_code, system_message, buffer.size());
if (result == 0) {
out << message << ": " << system_message;
return;
}
if (result != ERANGE)
break; // Can't get error message, report error code instead.
buffer.resize(buffer.size() * 2);
}
} FMT_CATCH(...) {}
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
}
template <typename Char>
void internal::ArgMap<Char>::init(const ArgList &args) {
if (!map_.empty())
return;
typedef internal::NamedArg<Char> NamedArg;
const NamedArg *named_arg = FMT_NULL;
bool use_values =
args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
if (use_values) {
for (unsigned i = 0;/*nothing*/; ++i) {
internal::Arg::Type arg_type = args.type(i);
switch (arg_type) {
case internal::Arg::NONE:
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
}
}
return;
}
for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
internal::Arg::Type arg_type = args.type(i);
if (arg_type == internal::Arg::NAMED_ARG) {
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
}
}
for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
switch (args.args_[i].type) {
case internal::Arg::NONE:
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
}
}
}
template <typename Char>
void internal::FixedBuffer<Char>::grow(std::size_t) {
FMT_THROW(std::runtime_error("buffer overflow"));
}
FMT_FUNC internal::Arg internal::FormatterBase::do_get_arg(
unsigned arg_index, const char *&error) {
internal::Arg arg = args_[arg_index];
switch (arg.type) {
case internal::Arg::NONE:
error = "argument index out of range";
break;
case internal::Arg::NAMED_ARG:
arg = *static_cast<const internal::Arg*>(arg.pointer);
break;
default:
/*nothing*/;
}
return arg;
}
FMT_FUNC void report_system_error(
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
// 'fmt::' is for bcc32.
report_error(format_system_error, error_code, message);
}
#if FMT_USE_WINDOWS_H
FMT_FUNC void report_windows_error(
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
// 'fmt::' is for bcc32.
report_error(internal::format_windows_error, error_code, message);
}
#endif
FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) {
MemoryWriter w;
w.write(format_str, args);
std::fwrite(w.data(), 1, w.size(), f);
}
FMT_FUNC void print(CStringRef format_str, ArgList args) {
print(stdout, format_str, args);
}
FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) {
char escape[] = "\x1b[30m";
escape[3] = static_cast<char>('0' + c);
std::fputs(escape, stdout);
print(format, args);
std::fputs(RESET_COLOR, stdout);
}
#ifndef FMT_HEADER_ONLY
template struct internal::BasicData<void>;
// Explicit instantiations for char.
template void internal::FixedBuffer<char>::grow(std::size_t);
template void internal::ArgMap<char>::init(const ArgList &args);
template FMT_API int internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, double value);
template FMT_API int internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, long double value);
// Explicit instantiations for wchar_t.
template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
template void internal::ArgMap<wchar_t>::init(const ArgList &args);
template FMT_API int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, double value);
template FMT_API int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, long double value);
#endif // FMT_HEADER_ONLY
} // namespace fmt
#ifdef _MSC_VER
# pragma warning(pop)
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,154 +0,0 @@
#include "singletons/Fonts.hpp"
#include "Application.hpp"
#include "debug/AssertInGuiThread.hpp"
#include "singletons/Settings.hpp"
#include "singletons/WindowManager.hpp"
#include <QDebug>
#include <QtGlobal>
#ifdef Q_OS_WIN32
# define DEFAULT_FONT_FAMILY "Segoe UI"
# define DEFAULT_FONT_SIZE 10
#else
# ifdef Q_OS_MACOS
# define DEFAULT_FONT_FAMILY "Helvetica Neue"
# define DEFAULT_FONT_SIZE 12
# else
# define DEFAULT_FONT_FAMILY "Arial"
# define DEFAULT_FONT_SIZE 11
# endif
#endif
namespace chatterino {
Fonts::Fonts()
: chatFontFamily("/appearance/currentFontFamily", DEFAULT_FONT_FAMILY)
, chatFontSize("/appearance/currentFontSize", DEFAULT_FONT_SIZE)
{
this->fontsByType_.resize(size_t(FontStyle::EndType));
}
void Fonts::initialize(Settings &, Paths &)
{
this->chatFontFamily.connect(
[this]() {
assertInGuiThread();
for (auto &map : this->fontsByType_)
{
map.clear();
}
this->fontChanged.invoke();
},
false);
this->chatFontSize.connect(
[this]() {
assertInGuiThread();
for (auto &map : this->fontsByType_)
{
map.clear();
}
this->fontChanged.invoke();
},
false);
getSettings()->boldScale.connect(
[this]() {
assertInGuiThread();
getApp()->windows->incGeneration();
for (auto &map : this->fontsByType_)
{
map.clear();
}
this->fontChanged.invoke();
},
false);
}
QFont Fonts::getFont(FontStyle type, float scale)
{
return this->getOrCreateFontData(type, scale).font;
}
QFontMetrics Fonts::getFontMetrics(FontStyle type, float scale)
{
return this->getOrCreateFontData(type, scale).metrics;
}
Fonts::FontData &Fonts::getOrCreateFontData(FontStyle type, float scale)
{
assertInGuiThread();
assert(type < FontStyle::EndType);
auto &map = this->fontsByType_[size_t(type)];
// find element
auto it = map.find(scale);
if (it != map.end())
{
// return if found
return it->second;
}
// emplace new element
auto result = map.emplace(scale, this->createFontData(type, scale));
assert(result.second);
return result.first->second;
}
Fonts::FontData Fonts::createFontData(FontStyle type, float scale)
{
// check if it's a chat (scale the setting)
if (type >= FontStyle::ChatStart && type <= FontStyle::ChatEnd)
{
static std::unordered_map<FontStyle, ChatFontData> sizeScale{
{FontStyle::ChatSmall, {0.6f, false, QFont::Normal}},
{FontStyle::ChatMediumSmall, {0.8f, false, QFont::Normal}},
{FontStyle::ChatMedium, {1, false, QFont::Normal}},
{FontStyle::ChatMediumBold,
{1, false, QFont::Weight(getSettings()->boldScale.getValue())}},
{FontStyle::ChatMediumItalic, {1, true, QFont::Normal}},
{FontStyle::ChatLarge, {1.2f, false, QFont::Normal}},
{FontStyle::ChatVeryLarge, {1.4f, false, QFont::Normal}},
};
sizeScale[FontStyle::ChatMediumBold] = {
1, false, QFont::Weight(getSettings()->boldScale.getValue())};
auto data = sizeScale[type];
return FontData(
QFont(this->chatFontFamily.getValue(),
int(this->chatFontSize.getValue() * data.scale * scale),
data.weight, data.italic));
}
// normal Ui font (use pt size)
{
#ifdef Q_OS_MAC
constexpr float multiplier = 0.8f;
#else
constexpr float multiplier = 1.f;
#endif
static std::unordered_map<FontStyle, UiFontData> defaultSize{
{FontStyle::Tiny, {8, "Monospace", false, QFont::Normal}},
{FontStyle::UiMedium,
{int(9 * multiplier), DEFAULT_FONT_FAMILY, false, QFont::Normal}},
{FontStyle::UiTabs,
{int(9 * multiplier), DEFAULT_FONT_FAMILY, false, QFont::Normal}},
};
UiFontData &data = defaultSize[type];
QFont font(data.name, int(data.size * scale), data.weight, data.italic);
return FontData(font);
}
}
} // namespace chatterino

View file

@ -1,89 +0,0 @@
#pragma once
#include "common/ChatterinoSetting.hpp"
#include "common/Singleton.hpp"
#include <QFont>
#include <QFontDatabase>
#include <QFontMetrics>
#include <boost/noncopyable.hpp>
#include <pajlada/signals/signal.hpp>
#include <array>
#include <unordered_map>
namespace chatterino {
class Settings;
class Paths;
enum class FontStyle : uint8_t {
Tiny,
ChatSmall,
ChatMediumSmall,
ChatMedium,
ChatMediumBold,
ChatMediumItalic,
ChatLarge,
ChatVeryLarge,
UiMedium,
UiTabs,
// don't remove this value
EndType,
// make sure to update these values accordingly!
ChatStart = ChatSmall,
ChatEnd = ChatVeryLarge,
};
class Fonts final : public Singleton
{
public:
Fonts();
virtual void initialize(Settings &settings, Paths &paths) override;
// font data gets set in createFontData(...)
QFont getFont(FontStyle type, float scale);
QFontMetrics getFontMetrics(FontStyle type, float scale);
QStringSetting chatFontFamily;
IntSetting chatFontSize;
pajlada::Signals::NoArgSignal fontChanged;
private:
struct FontData {
FontData(const QFont &_font)
: font(_font)
, metrics(_font)
{
}
const QFont font;
const QFontMetrics metrics;
};
struct ChatFontData {
float scale;
bool italic;
QFont::Weight weight;
};
struct UiFontData {
float size;
const char *name;
bool italic;
QFont::Weight weight;
};
FontData &getOrCreateFontData(FontStyle type, float scale);
FontData createFontData(FontStyle type, float scale);
std::vector<std::unordered_map<float, FontData>> fontsByType_;
};
} // namespace chatterino

View file

@ -17,7 +17,7 @@ class Theme final : public Singleton
public:
Theme();
inline bool isLightTheme() const
bool isLightTheme() const
{
return this->isLight_;
}

View file

@ -1,59 +0,0 @@
#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

View file

@ -1,45 +0,0 @@
#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

View file

@ -1,56 +0,0 @@
#include "WindowsHelper.hpp"
#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();
}
}
}
} // namespace chatterino
#endif

View file

@ -1,15 +0,0 @@
#pragma once
#ifdef USEWINSDK
# include <Windows.h>
# include <boost/optional.hpp>
namespace chatterino {
boost::optional<UINT> getWindowDpi(HWND hwnd);
void flushClipboard();
} // namespace chatterino
#endif

View file

@ -1,895 +0,0 @@
#include "BaseWindow.hpp"
#include "Application.hpp"
#include "boost/algorithm/algorithm.hpp"
#include "debug/Log.hpp"
#include "singletons/Settings.hpp"
#include "singletons/Theme.hpp"
#include "singletons/WindowManager.hpp"
#include "util/PostToThread.hpp"
#include "util/WindowsHelper.hpp"
#include "widgets/Label.hpp"
#include "widgets/TooltipWidget.hpp"
#include "widgets/helper/EffectLabel.hpp"
#include "widgets/helper/Shortcut.hpp"
#include <QApplication>
#include <QDebug>
#include <QDesktopWidget>
#include <QIcon>
#include <functional>
#ifdef USEWINSDK
# include <ObjIdl.h>
# include <VersionHelpers.h>
# include <Windows.h>
# include <dwmapi.h>
# include <gdiplus.h>
# include <windowsx.h>
//#include <ShellScalingApi.h>
# pragma comment(lib, "Dwmapi.lib")
# include <QHBoxLayout>
# include <QVBoxLayout>
# define WM_DPICHANGED 0x02E0
#endif
#include "widgets/helper/TitlebarButton.hpp"
namespace chatterino {
BaseWindow::BaseWindow(QWidget *parent, Flags _flags)
: BaseWidget(parent,
Qt::Window | ((_flags & TopMost) ? Qt::WindowStaysOnTopHint
: Qt::WindowFlags()))
, enableCustomFrame_(_flags & EnableCustomFrame)
, frameless_(_flags & Frameless)
, flags_(_flags)
{
if (this->frameless_)
{
this->enableCustomFrame_ = false;
this->setWindowFlag(Qt::FramelessWindowHint);
}
this->init();
getSettings()->uiScale.connect(
[this]() { postToThread([this] { this->updateScale(); }); },
this->connections_);
this->updateScale();
createWindowShortcut(this, "CTRL+0",
[] { getSettings()->uiScale.setValue(0); });
// QTimer::this->scaleChangedEvent(this->getScale());
}
float BaseWindow::scale() const
{
return this->overrideScale().value_or(this->scale_);
}
BaseWindow::Flags BaseWindow::getFlags()
{
return this->flags_;
}
void BaseWindow::init()
{
this->setWindowIcon(QIcon(":/images/icon.png"));
#ifdef USEWINSDK
if (this->hasCustomWindowFrame())
{
// CUSTOM WINDOW FRAME
QVBoxLayout *layout = new QVBoxLayout();
this->ui_.windowLayout = layout;
layout->setContentsMargins(0, 1, 0, 0);
layout->setSpacing(0);
this->setLayout(layout);
{
if (!this->frameless_)
{
QHBoxLayout *buttonLayout = this->ui_.titlebarBox =
new QHBoxLayout();
buttonLayout->setMargin(0);
layout->addLayout(buttonLayout);
// title
Label *title = new Label("Chatterino");
QObject::connect(
this, &QWidget::windowTitleChanged,
[title](const QString &text) { title->setText(text); });
QSizePolicy policy(QSizePolicy::Ignored,
QSizePolicy::Preferred);
policy.setHorizontalStretch(1);
title->setSizePolicy(policy);
buttonLayout->addWidget(title);
this->ui_.titleLabel = title;
// buttons
TitleBarButton *_minButton = new TitleBarButton;
_minButton->setButtonStyle(TitleBarButtonStyle::Minimize);
TitleBarButton *_maxButton = new TitleBarButton;
_maxButton->setButtonStyle(TitleBarButtonStyle::Maximize);
TitleBarButton *_exitButton = new TitleBarButton;
_exitButton->setButtonStyle(TitleBarButtonStyle::Close);
QObject::connect(_minButton, &TitleBarButton::leftClicked, this,
[this] {
this->setWindowState(Qt::WindowMinimized |
this->windowState());
});
QObject::connect(_maxButton, &TitleBarButton::leftClicked, this,
[this, _maxButton] {
this->setWindowState(
_maxButton->getButtonStyle() !=
TitleBarButtonStyle::Maximize
? Qt::WindowActive
: Qt::WindowMaximized);
});
QObject::connect(_exitButton, &TitleBarButton::leftClicked,
this, [this] { this->close(); });
this->ui_.minButton = _minButton;
this->ui_.maxButton = _maxButton;
this->ui_.exitButton = _exitButton;
this->ui_.buttons.push_back(_minButton);
this->ui_.buttons.push_back(_maxButton);
this->ui_.buttons.push_back(_exitButton);
// buttonLayout->addStretch(1);
buttonLayout->addWidget(_minButton);
buttonLayout->addWidget(_maxButton);
buttonLayout->addWidget(_exitButton);
buttonLayout->setSpacing(0);
}
}
this->ui_.layoutBase = new BaseWidget(this);
layout->addWidget(this->ui_.layoutBase);
}
// DPI
// auto dpi = getWindowDpi(this->winId());
// if (dpi) {
// this->scale = dpi.value() / 96.f;
// }
#endif
#ifdef USEWINSDK
// fourtf: don't ask me why we need to delay this
if (!(this->flags_ & Flags::TopMost))
{
QTimer::singleShot(1, this, [this] {
getSettings()->windowTopMost.connect(
[this](bool topMost, auto) {
::SetWindowPos(HWND(this->winId()),
topMost ? HWND_TOPMOST : HWND_NOTOPMOST, 0,
0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
},
this->managedConnections_);
});
}
#else
// if (getSettings()->windowTopMost.getValue()) {
// this->setWindowFlag(Qt::WindowStaysOnTopHint);
// }
#endif
}
void BaseWindow::setStayInScreenRect(bool value)
{
this->stayInScreenRect_ = value;
this->moveIntoDesktopRect(this);
}
bool BaseWindow::getStayInScreenRect() const
{
return this->stayInScreenRect_;
}
void BaseWindow::setActionOnFocusLoss(ActionOnFocusLoss value)
{
this->actionOnFocusLoss_ = value;
}
BaseWindow::ActionOnFocusLoss BaseWindow::getActionOnFocusLoss() const
{
return this->actionOnFocusLoss_;
}
QWidget *BaseWindow::getLayoutContainer()
{
if (this->hasCustomWindowFrame())
{
return this->ui_.layoutBase;
}
else
{
return this;
}
}
bool BaseWindow::hasCustomWindowFrame()
{
#ifdef USEWINSDK
static bool isWin8 = IsWindows8OrGreater();
return isWin8 && this->enableCustomFrame_;
#else
return false;
#endif
}
void BaseWindow::themeChangedEvent()
{
if (this->hasCustomWindowFrame())
{
QPalette palette;
palette.setColor(QPalette::Background, QColor(0, 0, 0, 0));
palette.setColor(QPalette::Foreground, this->theme->window.text);
this->setPalette(palette);
if (this->ui_.titleLabel)
{
QPalette palette_title;
palette_title.setColor(
QPalette::Foreground,
this->theme->isLightTheme() ? "#333" : "#ccc");
this->ui_.titleLabel->setPalette(palette_title);
}
for (Button *button : this->ui_.buttons)
{
button->setMouseEffectColor(this->theme->window.text);
}
}
else
{
QPalette palette;
palette.setColor(QPalette::Background, this->theme->window.background);
palette.setColor(QPalette::Foreground, this->theme->window.text);
this->setPalette(palette);
}
}
bool BaseWindow::event(QEvent *event)
{
if (event->type() ==
QEvent::WindowDeactivate /*|| event->type() == QEvent::FocusOut*/)
{
this->onFocusLost();
}
return QWidget::event(event);
}
void BaseWindow::wheelEvent(QWheelEvent *event)
{
if (event->orientation() != Qt::Vertical)
{
return;
}
if (event->modifiers() & Qt::ControlModifier)
{
if (event->delta() > 0)
{
getSettings()->uiScale.setValue(WindowManager::clampUiScale(
getSettings()->uiScale.getValue() + 1));
}
else
{
getSettings()->uiScale.setValue(WindowManager::clampUiScale(
getSettings()->uiScale.getValue() - 1));
}
}
}
void BaseWindow::onFocusLost()
{
switch (this->getActionOnFocusLoss())
{
case Delete:
{
this->deleteLater();
}
break;
case Close:
{
this->close();
}
break;
case Hide:
{
this->hide();
}
break;
default:;
}
}
void BaseWindow::mousePressEvent(QMouseEvent *event)
{
#ifndef Q_OS_WIN
if (this->flags_ & FramelessDraggable)
{
this->movingRelativePos = event->localPos();
if (auto widget =
this->childAt(event->localPos().x(), event->localPos().y()))
{
std::function<bool(QWidget *)> recursiveCheckMouseTracking;
recursiveCheckMouseTracking = [&](QWidget *widget) {
if (widget == nullptr)
{
return false;
}
if (widget->hasMouseTracking())
{
return true;
}
return recursiveCheckMouseTracking(widget->parentWidget());
};
if (!recursiveCheckMouseTracking(widget))
{
log("Start moving");
this->moving = true;
}
}
}
#endif
BaseWidget::mousePressEvent(event);
}
void BaseWindow::mouseReleaseEvent(QMouseEvent *event)
{
#ifndef Q_OS_WIN
if (this->flags_ & FramelessDraggable)
{
if (this->moving)
{
log("Stop moving");
this->moving = false;
}
}
#endif
BaseWidget::mouseReleaseEvent(event);
}
void BaseWindow::mouseMoveEvent(QMouseEvent *event)
{
#ifndef Q_OS_WIN
if (this->flags_ & FramelessDraggable)
{
if (this->moving)
{
const auto &newPos = event->screenPos() - this->movingRelativePos;
this->move(newPos.x(), newPos.y());
}
}
#endif
BaseWidget::mouseMoveEvent(event);
}
TitleBarButton *BaseWindow::addTitleBarButton(const TitleBarButtonStyle &style,
std::function<void()> onClicked)
{
TitleBarButton *button = new TitleBarButton;
button->setScaleIndependantSize(30, 30);
this->ui_.buttons.push_back(button);
this->ui_.titlebarBox->insertWidget(1, button);
button->setButtonStyle(style);
QObject::connect(button, &TitleBarButton::leftClicked, this,
[onClicked] { onClicked(); });
return button;
}
EffectLabel *BaseWindow::addTitleBarLabel(std::function<void()> onClicked)
{
EffectLabel *button = new EffectLabel;
button->setScaleIndependantHeight(30);
this->ui_.buttons.push_back(button);
this->ui_.titlebarBox->insertWidget(1, button);
QObject::connect(button, &EffectLabel::leftClicked, this,
[onClicked] { onClicked(); });
return button;
}
void BaseWindow::changeEvent(QEvent *)
{
TooltipWidget::getInstance()->hide();
#ifdef USEWINSDK
if (this->ui_.maxButton)
{
this->ui_.maxButton->setButtonStyle(
this->windowState() & Qt::WindowMaximized
? TitleBarButtonStyle::Unmaximize
: TitleBarButtonStyle::Maximize);
}
#endif
#ifndef Q_OS_WIN
this->update();
#endif
}
void BaseWindow::leaveEvent(QEvent *)
{
TooltipWidget::getInstance()->hide();
}
void BaseWindow::moveTo(QWidget *parent, QPoint point, bool offset)
{
if (offset)
{
point.rx() += 16;
point.ry() += 16;
}
this->move(point);
this->moveIntoDesktopRect(parent);
}
void BaseWindow::resizeEvent(QResizeEvent *)
{
// Queue up save because: Window resized
getApp()->windows->queueSave();
this->moveIntoDesktopRect(this);
this->calcButtonsSizes();
}
void BaseWindow::moveEvent(QMoveEvent *event)
{
// Queue up save because: Window position changed
getApp()->windows->queueSave();
BaseWidget::moveEvent(event);
}
void BaseWindow::closeEvent(QCloseEvent *)
{
this->closing.invoke();
}
void BaseWindow::moveIntoDesktopRect(QWidget *parent)
{
if (!this->stayInScreenRect_)
return;
// move the widget into the screen geometry if it's not already in there
QDesktopWidget *desktop = QApplication::desktop();
QRect s = desktop->availableGeometry(parent);
QPoint p = this->pos();
if (p.x() < s.left())
{
p.setX(s.left());
}
if (p.y() < s.top())
{
p.setY(s.top());
}
if (p.x() + this->width() > s.right())
{
p.setX(s.right() - this->width());
}
if (p.y() + this->height() > s.bottom())
{
p.setY(s.bottom() - this->height());
}
if (p != this->pos())
this->move(p);
}
bool BaseWindow::nativeEvent(const QByteArray &eventType, void *message,
long *result)
{
#ifdef USEWINSDK
# if (QT_VERSION == QT_VERSION_CHECK(5, 11, 1))
MSG *msg = *reinterpret_cast<MSG **>(message);
# else
MSG *msg = reinterpret_cast<MSG *>(message);
# endif
bool returnValue = false;
switch (msg->message)
{
case WM_DPICHANGED:
returnValue = handleDPICHANGED(msg);
break;
case WM_SHOWWINDOW:
returnValue = this->handleSHOWWINDOW(msg);
break;
case WM_NCCALCSIZE:
returnValue = this->handleNCCALCSIZE(msg, result);
break;
case WM_SIZE:
returnValue = this->handleSIZE(msg);
break;
case WM_NCHITTEST:
returnValue = this->handleNCHITTEST(msg, result);
break;
default:
return QWidget::nativeEvent(eventType, message, result);
}
QWidget::nativeEvent(eventType, message, result);
return returnValue;
#else
return QWidget::nativeEvent(eventType, message, result);
#endif
}
void BaseWindow::scaleChangedEvent(float)
{
#ifdef USEWINSDK
this->calcButtonsSizes();
#endif
}
void BaseWindow::paintEvent(QPaintEvent *)
{
QPainter painter(this);
if (this->frameless_)
{
painter.setPen(QColor("#999"));
painter.drawRect(0, 0, this->width() - 1, this->height() - 1);
}
this->drawCustomWindowFrame(painter);
}
void BaseWindow::updateScale()
{
auto scale =
this->nativeScale_ * (this->flags_ & DisableCustomScaling
? 1
: getApp()->windows->getUiScaleValue());
this->setScale(scale);
for (auto child : this->findChildren<BaseWidget *>())
{
child->setScale(scale);
}
}
void BaseWindow::calcButtonsSizes()
{
if (!this->shown_)
{
return;
}
if ((this->width() / this->scale()) < 300)
{
if (this->ui_.minButton)
this->ui_.minButton->setScaleIndependantSize(30, 30);
if (this->ui_.maxButton)
this->ui_.maxButton->setScaleIndependantSize(30, 30);
if (this->ui_.exitButton)
this->ui_.exitButton->setScaleIndependantSize(30, 30);
}
else
{
if (this->ui_.minButton)
this->ui_.minButton->setScaleIndependantSize(46, 30);
if (this->ui_.maxButton)
this->ui_.maxButton->setScaleIndependantSize(46, 30);
if (this->ui_.exitButton)
this->ui_.exitButton->setScaleIndependantSize(46, 30);
}
}
void BaseWindow::drawCustomWindowFrame(QPainter &painter)
{
#ifdef USEWINSDK
if (this->hasCustomWindowFrame())
{
QPainter painter(this);
QColor bg = this->overrideBackgroundColor_.value_or(
this->theme->window.background);
painter.fillRect(QRect(0, 1, this->width() - 0, this->height() - 0),
bg);
}
#endif
}
bool BaseWindow::handleDPICHANGED(MSG *msg)
{
#ifdef USEWINSDK
int dpi = HIWORD(msg->wParam);
float _scale = dpi / 96.f;
static bool firstResize = true;
if (!firstResize)
{
auto *prcNewWindow = reinterpret_cast<RECT *>(msg->lParam);
SetWindowPos(msg->hwnd, nullptr, prcNewWindow->left, prcNewWindow->top,
prcNewWindow->right - prcNewWindow->left,
prcNewWindow->bottom - prcNewWindow->top,
SWP_NOZORDER | SWP_NOACTIVATE);
}
firstResize = false;
this->nativeScale_ = _scale;
this->updateScale();
return true;
#else
return false;
#endif
}
bool BaseWindow::handleSHOWWINDOW(MSG *msg)
{
#ifdef USEWINSDK
if (auto dpi = getWindowDpi(msg->hwnd))
{
this->nativeScale_ = dpi.get() / 96.f;
this->updateScale();
}
if (!this->shown_ && this->isVisible() && this->hasCustomWindowFrame())
{
this->shown_ = true;
const MARGINS shadow = {8, 8, 8, 8};
DwmExtendFrameIntoClientArea(HWND(this->winId()), &shadow);
}
this->calcButtonsSizes();
return true;
#else
return false;
#endif
}
bool BaseWindow::handleNCCALCSIZE(MSG *msg, long *result)
{
#ifdef USEWINSDK
if (this->hasCustomWindowFrame())
{
// int cx = GetSystemMetrics(SM_CXSIZEFRAME);
// int cy = GetSystemMetrics(SM_CYSIZEFRAME);
if (msg->wParam == TRUE)
{
NCCALCSIZE_PARAMS *ncp =
(reinterpret_cast<NCCALCSIZE_PARAMS *>(msg->lParam));
ncp->lppos->flags |= SWP_NOREDRAW;
RECT *clientRect = &ncp->rgrc[0];
clientRect->left += 1;
clientRect->top += 0;
clientRect->right -= 1;
clientRect->bottom -= 1;
}
*result = 0;
return true;
}
return false;
#else
return false;
#endif
}
bool BaseWindow::handleSIZE(MSG *msg)
{
#ifdef USEWINSDK
if (this->ui_.windowLayout)
{
if (this->frameless_)
{
//
}
else if (this->hasCustomWindowFrame())
{
if (msg->wParam == SIZE_MAXIMIZED)
{
auto offset = int(this->scale() * 8);
this->ui_.windowLayout->setContentsMargins(offset, offset,
offset, offset);
}
else
{
this->ui_.windowLayout->setContentsMargins(0, 1, 0, 0);
}
}
}
return false;
#else
return false;
#endif
}
bool BaseWindow::handleNCHITTEST(MSG *msg, long *result)
{
#ifdef USEWINSDK
const LONG border_width = 8; // in pixels
RECT winrect;
GetWindowRect(HWND(winId()), &winrect);
long x = GET_X_LPARAM(msg->lParam);
long y = GET_Y_LPARAM(msg->lParam);
QPoint point(x - winrect.left, y - winrect.top);
if (this->hasCustomWindowFrame())
{
*result = 0;
bool resizeWidth = minimumWidth() != maximumWidth();
bool resizeHeight = minimumHeight() != maximumHeight();
if (resizeWidth)
{
// left border
if (x < winrect.left + border_width)
{
*result = HTLEFT;
}
// right border
if (x >= winrect.right - border_width)
{
*result = HTRIGHT;
}
}
if (resizeHeight)
{
// bottom border
if (y >= winrect.bottom - border_width)
{
*result = HTBOTTOM;
}
// top border
if (y < winrect.top + border_width)
{
*result = HTTOP;
}
}
if (resizeWidth && resizeHeight)
{
// bottom left corner
if (x >= winrect.left && x < winrect.left + border_width &&
y < winrect.bottom && y >= winrect.bottom - border_width)
{
*result = HTBOTTOMLEFT;
}
// bottom right corner
if (x < winrect.right && x >= winrect.right - border_width &&
y < winrect.bottom && y >= winrect.bottom - border_width)
{
*result = HTBOTTOMRIGHT;
}
// top left corner
if (x >= winrect.left && x < winrect.left + border_width &&
y >= winrect.top && y < winrect.top + border_width)
{
*result = HTTOPLEFT;
}
// top right corner
if (x < winrect.right && x >= winrect.right - border_width &&
y >= winrect.top && y < winrect.top + border_width)
{
*result = HTTOPRIGHT;
}
}
if (*result == 0)
{
bool client = false;
for (QWidget *widget : this->ui_.buttons)
{
if (widget->geometry().contains(point))
{
client = true;
}
}
if (this->ui_.layoutBase->geometry().contains(point))
{
client = true;
}
if (client)
{
*result = HTCLIENT;
}
else
{
*result = HTCAPTION;
}
}
return true;
}
else if (this->flags_ & FramelessDraggable)
{
*result = 0;
bool client = false;
if (auto widget = this->childAt(point))
{
std::function<bool(QWidget *)> recursiveCheckMouseTracking;
recursiveCheckMouseTracking = [&](QWidget *widget) {
if (widget == nullptr)
{
return false;
}
if (widget->hasMouseTracking())
{
return true;
}
return recursiveCheckMouseTracking(widget->parentWidget());
};
if (recursiveCheckMouseTracking(widget))
{
client = true;
}
}
if (client)
{
*result = HTCLIENT;
}
else
{
*result = HTCAPTION;
}
return true;
}
#else
return false;
#endif
}
} // namespace chatterino

View file

@ -1,120 +0,0 @@
#pragma once
#include "widgets/BaseWidget.hpp"
#include <functional>
#include <pajlada/signals/signalholder.hpp>
class QHBoxLayout;
struct tagMSG;
typedef struct tagMSG MSG;
namespace chatterino {
class Button;
class EffectLabel;
class TitleBarButton;
enum class TitleBarButtonStyle;
class BaseWindow : public BaseWidget
{
Q_OBJECT
public:
enum Flags {
None = 0,
EnableCustomFrame = 1,
Frameless = 2,
TopMost = 4,
DisableCustomScaling = 8,
FramelessDraggable = 16,
};
enum ActionOnFocusLoss { Nothing, Delete, Close, Hide };
explicit BaseWindow(QWidget *parent = nullptr, Flags flags_ = None);
QWidget *getLayoutContainer();
bool hasCustomWindowFrame();
TitleBarButton *addTitleBarButton(const TitleBarButtonStyle &style,
std::function<void()> onClicked);
EffectLabel *addTitleBarLabel(std::function<void()> onClicked);
void setStayInScreenRect(bool value);
bool getStayInScreenRect() const;
void setActionOnFocusLoss(ActionOnFocusLoss value);
ActionOnFocusLoss getActionOnFocusLoss() const;
void moveTo(QWidget *widget, QPoint point, bool offset = true);
virtual float scale() const override;
Flags getFlags();
pajlada::Signals::NoArgSignal closing;
protected:
virtual bool nativeEvent(const QByteArray &eventType, void *message,
long *result) override;
virtual void scaleChangedEvent(float) override;
virtual void paintEvent(QPaintEvent *) override;
virtual void changeEvent(QEvent *) override;
virtual void leaveEvent(QEvent *) override;
virtual void resizeEvent(QResizeEvent *) override;
virtual void moveEvent(QMoveEvent *) override;
virtual void closeEvent(QCloseEvent *) override;
virtual void themeChangedEvent() override;
virtual bool event(QEvent *event) override;
virtual void wheelEvent(QWheelEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
QPointF movingRelativePos;
bool moving{};
void updateScale();
boost::optional<QColor> overrideBackgroundColor_;
private:
void init();
void moveIntoDesktopRect(QWidget *parent);
void calcButtonsSizes();
void drawCustomWindowFrame(QPainter &painter);
void onFocusLost();
bool handleDPICHANGED(MSG *msg);
bool handleSHOWWINDOW(MSG *msg);
bool handleNCCALCSIZE(MSG *msg, long *result);
bool handleSIZE(MSG *msg);
bool handleNCHITTEST(MSG *msg, long *result);
bool enableCustomFrame_;
ActionOnFocusLoss actionOnFocusLoss_ = Nothing;
bool frameless_;
bool stayInScreenRect_ = false;
bool shown_ = false;
Flags flags_;
float nativeScale_ = 1;
struct {
QLayout *windowLayout = nullptr;
QHBoxLayout *titlebarBox = nullptr;
QWidget *titleLabel = nullptr;
TitleBarButton *minButton = nullptr;
TitleBarButton *maxButton = nullptr;
TitleBarButton *exitButton = nullptr;
QWidget *layoutBase = nullptr;
std::vector<Button *> buttons;
} ui_;
pajlada::Signals::SignalHolder connections_;
std::vector<pajlada::Signals::ScopedConnection> managedConnections_;
}; // namespace chatterino
} // namespace chatterino

View file

@ -1,138 +0,0 @@
#include "Label.hpp"
#include "Application.hpp"
#include <QPainter>
namespace chatterino {
Label::Label(QString text, FontStyle style)
: Label(nullptr, text, style)
{
}
Label::Label(BaseWidget *parent, QString text, FontStyle style)
: BaseWidget(parent)
, text_(text)
, fontStyle_(style)
{
auto app = getApp();
this->connections_.managedConnect(app->fonts->fontChanged,
[this] { this->updateSize(); });
}
const QString &Label::getText() const
{
return this->text_;
}
void Label::setText(const QString &text)
{
if (this->text_ != text)
{
this->text_ = text;
this->updateSize();
this->update();
}
}
FontStyle Label::getFontStyle() const
{
return this->fontStyle_;
}
bool Label::getCentered() const
{
return this->centered_;
}
void Label::setCentered(bool centered)
{
this->centered_ = centered;
this->updateSize();
}
bool Label::getHasOffset() const
{
return this->hasOffset_;
}
void Label::setHasOffset(bool hasOffset)
{
this->hasOffset_ = hasOffset;
this->updateSize();
}
void Label::setFontStyle(FontStyle style)
{
this->fontStyle_ = style;
this->updateSize();
}
void Label::scaleChangedEvent(float scale)
{
this->updateSize();
}
QSize Label::sizeHint() const
{
return this->preferedSize_;
}
QSize Label::minimumSizeHint() const
{
return this->preferedSize_;
}
void Label::paintEvent(QPaintEvent *)
{
auto app = getApp();
QPainter painter(this);
QFontMetrics metrics = app->fonts->getFontMetrics(
this->getFontStyle(), this->scale() * 96.f / this->logicalDpiX() *
this->devicePixelRatioF());
painter.setFont(app->fonts->getFont(
this->getFontStyle(), this->scale() * 96.f / this->logicalDpiX() *
this->devicePixelRatioF()));
int offset = this->getOffset();
// draw text
QRect textRect(offset, 0, this->width() - offset - offset, this->height());
int width = metrics.width(this->text_);
Qt::Alignment alignment = !this->centered_ || width > textRect.width()
? Qt::AlignLeft | Qt::AlignVCenter
: Qt::AlignCenter;
QTextOption option(alignment);
option.setWrapMode(QTextOption::NoWrap);
painter.drawText(textRect, this->text_, option);
#if 0
painter.setPen(QColor(255, 0, 0));
painter.drawRect(0, 0, this->width() - 1, this->height() - 1);
#endif
}
void Label::updateSize()
{
auto app = getApp();
QFontMetrics metrics =
app->fonts->getFontMetrics(this->fontStyle_, this->scale());
int width = metrics.width(this->text_) + (2 * this->getOffset());
int height = metrics.height();
this->preferedSize_ = QSize(width, height);
this->updateGeometry();
}
int Label::getOffset()
{
return this->hasOffset_ ? int(8 * this->scale()) : 0;
}
} // namespace chatterino

View file

@ -1,50 +0,0 @@
#pragma once
#include "singletons/Fonts.hpp"
#include "widgets/BaseWidget.hpp"
#include <pajlada/signals/signalholder.hpp>
namespace chatterino {
class Label : public BaseWidget
{
public:
explicit Label(QString text = QString(),
FontStyle style = FontStyle::UiMedium);
explicit Label(BaseWidget *parent, QString text = QString(),
FontStyle style = FontStyle::UiMedium);
const QString &getText() const;
void setText(const QString &text);
FontStyle getFontStyle() const;
void setFontStyle(FontStyle style);
bool getCentered() const;
void setCentered(bool centered);
bool getHasOffset() const;
void setHasOffset(bool hasOffset);
protected:
virtual void scaleChangedEvent(float scale_) override;
virtual void paintEvent(QPaintEvent *) override;
virtual QSize sizeHint() const override;
virtual QSize minimumSizeHint() const override;
private:
void updateSize();
int getOffset();
QString text_;
FontStyle fontStyle_;
QSize preferedSize_;
bool centered_ = false;
bool hasOffset_ = true;
pajlada::Signals::SignalHolder connections_;
};
} // namespace chatterino

View file

@ -10,7 +10,7 @@
#include "widgets/dialogs/SettingsDialog.hpp"
#include "widgets/helper/NotebookButton.hpp"
#include "widgets/helper/NotebookTab.hpp"
#include "widgets/helper/Shortcut.hpp"
#include "util/Shortcut.hpp"
#include "widgets/splits/Split.hpp"
#include "widgets/splits/SplitContainer.hpp"

View file

@ -1,106 +0,0 @@
#include "TooltipWidget.hpp"
#include "Application.hpp"
#include "singletons/Fonts.hpp"
#include "singletons/Theme.hpp"
#include <QDebug>
#include <QDesktopWidget>
#include <QStyle>
#include <QVBoxLayout>
#ifdef USEWINSDK
# include <Windows.h>
#endif
namespace chatterino {
TooltipWidget *TooltipWidget::getInstance()
{
static TooltipWidget *tooltipWidget = nullptr;
if (tooltipWidget == nullptr)
{
tooltipWidget = new TooltipWidget();
}
return tooltipWidget;
}
TooltipWidget::TooltipWidget(BaseWidget *parent)
: BaseWindow(parent, BaseWindow::TopMost)
, displayText_(new QLabel())
{
auto app = getApp();
this->setStyleSheet("color: #fff; background: #000");
this->setWindowOpacity(0.8);
this->updateFont();
this->setStayInScreenRect(true);
this->setAttribute(Qt::WA_ShowWithoutActivating);
this->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint |
Qt::X11BypassWindowManagerHint |
Qt::BypassWindowManagerHint);
displayText_->setAlignment(Qt::AlignHCenter);
displayText_->setText("tooltip text");
auto layout = new QVBoxLayout();
layout->setContentsMargins(10, 5, 10, 5);
layout->addWidget(displayText_);
this->setLayout(layout);
this->fontChangedConnection_ =
app->fonts->fontChanged.connect([this] { this->updateFont(); });
}
TooltipWidget::~TooltipWidget()
{
this->fontChangedConnection_.disconnect();
}
#ifdef USEWINSDK
void TooltipWidget::raise()
{
::SetWindowPos(HWND(this->winId()), HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
#endif
void TooltipWidget::themeChangedEvent()
{
this->setStyleSheet("color: #fff; background: #000");
}
void TooltipWidget::scaleChangedEvent(float)
{
this->updateFont();
}
void TooltipWidget::updateFont()
{
auto app = getApp();
this->setFont(
app->fonts->getFont(FontStyle::ChatMediumSmall, this->scale()));
}
void TooltipWidget::setText(QString text)
{
this->displayText_->setText(text);
}
void TooltipWidget::setWordWrap(bool wrap)
{
this->displayText_->setWordWrap(wrap);
}
void TooltipWidget::changeEvent(QEvent *)
{
// clear parents event
}
void TooltipWidget::leaveEvent(QEvent *)
{
// clear parents event
}
} // namespace chatterino

View file

@ -1,41 +0,0 @@
#pragma once
#include "widgets/BaseWindow.hpp"
#include <QLabel>
#include <QWidget>
#include <pajlada/signals/signal.hpp>
namespace chatterino {
class TooltipWidget : public BaseWindow
{
Q_OBJECT
public:
static TooltipWidget *getInstance();
TooltipWidget(BaseWidget *parent = nullptr);
virtual ~TooltipWidget() override;
void setText(QString text);
void setWordWrap(bool wrap);
#ifdef USEWINSDK
void raise();
#endif
protected:
void changeEvent(QEvent *) override;
void leaveEvent(QEvent *) override;
void themeChangedEvent() override;
void scaleChangedEvent(float) override;
private:
void updateFont();
QLabel *displayText_;
pajlada::Signals::Connection fontChangedConnection_;
};
} // namespace chatterino

View file

@ -16,7 +16,7 @@
#include "widgets/dialogs/WelcomeDialog.hpp"
#include "widgets/helper/EffectLabel.hpp"
#include "widgets/helper/NotebookTab.hpp"
#include "widgets/helper/Shortcut.hpp"
#include "util/Shortcut.hpp"
#include "widgets/helper/TitlebarButton.hpp"
#include "widgets/splits/ClosedSplits.hpp"
#include "widgets/splits/Split.hpp"

View file

@ -1,24 +0,0 @@
#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

View file

@ -23,7 +23,7 @@
#include "widgets/helper/NotebookTab.hpp"
#include "widgets/helper/ResizingTextEdit.hpp"
#include "widgets/helper/SearchPopup.hpp"
#include "widgets/helper/Shortcut.hpp"
#include "util/Shortcut.hpp"
#include "widgets/splits/ClosedSplits.hpp"
#include "widgets/splits/SplitContainer.hpp"
#include "widgets/splits/SplitHeader.hpp"