mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
refactor: About page (#5287)
This commit is contained in:
parent
694d53ad20
commit
905aa4e923
|
@ -52,6 +52,7 @@
|
||||||
- Minor: 7TV emotes now have a 4x image rather than a 3x image. (#5209)
|
- Minor: 7TV emotes now have a 4x image rather than a 3x image. (#5209)
|
||||||
- Minor: Add `reward.cost` `reward.id`, `reward.title` filter variables. (#5275)
|
- Minor: Add `reward.cost` `reward.id`, `reward.title` filter variables. (#5275)
|
||||||
- Minor: Change Lua `CompletionRequested` handler to use an event table. (#5280)
|
- Minor: Change Lua `CompletionRequested` handler to use an event table. (#5280)
|
||||||
|
- Minor: Changed the layout of the about page. (#5287)
|
||||||
- Bugfix: Fixed an issue where certain emojis did not send to Twitch chat correctly. (#4840)
|
- Bugfix: Fixed an issue where certain emojis did not send to Twitch chat correctly. (#4840)
|
||||||
- Bugfix: Fixed the `/shoutout` command not working with usernames starting with @'s (e.g. `/shoutout @forsen`). (#4800)
|
- Bugfix: Fixed the `/shoutout` command not working with usernames starting with @'s (e.g. `/shoutout @forsen`). (#4800)
|
||||||
- Bugfix: Fixed capitalized channel names in log inclusion list not being logged. (#4848)
|
- Bugfix: Fixed capitalized channel names in log inclusion list not being logged. (#4848)
|
||||||
|
|
BIN
resources/avatars/anon.png
Normal file
BIN
resources/avatars/anon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
|
@ -3,80 +3,89 @@
|
||||||
# TODO: Parse this into a CONTRIBUTORS.md too
|
# TODO: Parse this into a CONTRIBUTORS.md too
|
||||||
|
|
||||||
# Adding yourself? Copy and paste this template at the bottom of this file and fill in the fields in a PR!
|
# Adding yourself? Copy and paste this template at the bottom of this file and fill in the fields in a PR!
|
||||||
# Name | Link | Avatar (Loaded as a resource, avatars are not required) | Title (description of work done).
|
# Name | Link | Avatar (Loaded as a resource, avatars are not required).
|
||||||
|
|
||||||
# Avatar should be located in avatars/ directory. Its size should be 128x128 (get it from https://github.com/username.png?size=128).
|
# Avatar should be located in avatars/ directory. Its size should be 128x128 (get it from https://github.com/username.png?size=128).
|
||||||
# Make sure to reduce avatar's size as much as possible with tool like pngcrush or optipng (if the file is in png format).
|
# Make sure to reduce avatar's size as much as possible with tool like pngcrush or optipng (if the file is in png format).
|
||||||
# Contributor is what we use for someone who has contributed in general (like sent a programming-related PR).
|
# Contributor is what we use for someone who has contributed in general (like sent a programming-related PR).
|
||||||
|
|
||||||
fourtf | https://fourtf.com | :/avatars/fourtf.png | Author, main developer
|
@header Maintainers
|
||||||
pajlada | https://pajlada.se | :/avatars/pajlada.png | Collaborator, co-developer
|
|
||||||
zneix | https://github.com/zneix | :/avatars/zneix.png | Collaborator
|
|
||||||
Mm2PL | https://github.com/mm2pl | :/avatars/mm2pl.png | Collaborator
|
|
||||||
YungLPR | https://github.com/leon-richardt | | Collaborator
|
|
||||||
dnsge | https://github.com/dnsge | | Collaborator
|
|
||||||
Felanbird | https://github.com/Felanbird | | Collaborator
|
|
||||||
kornes | https://github.com/kornes | | Collaborator
|
|
||||||
|
|
||||||
Cranken | https://github.com/Cranken | | Contributor
|
fourtf | https://fourtf.com | :/avatars/fourtf.png
|
||||||
hemirt | https://github.com/hemirt | | Contributor
|
pajlada | https://pajlada.se | :/avatars/pajlada.png
|
||||||
LajamerrMittesdine | https://github.com/LajamerrMittesdine | | Contributor
|
|
||||||
coral | https://github.com/coral | | Contributor, design
|
@header Collaborators
|
||||||
apa420 | https://github.com/apa420 | | Contributor
|
|
||||||
DatGuy1 | https://github.com/DatGuy1 | | Contributor
|
zneix | https://github.com/zneix | :/avatars/zneix.png
|
||||||
Confuseh | https://github.com/Confuseh | | Contributor
|
Mm2PL | https://github.com/mm2pl | :/avatars/mm2pl.png
|
||||||
ch-ems | https://github.com/ch-ems | | Contributor
|
YungLPR | https://github.com/leon-richardt |
|
||||||
Bur0k | https://github.com/Bur0k | | Contributor
|
dnsge | https://github.com/dnsge |
|
||||||
nuuls | https://github.com/nuuls | | Contributor
|
Felanbird | https://github.com/Felanbird |
|
||||||
Chronophylos | https://github.com/Chronophylos | | Contributor
|
kornes | https://github.com/kornes |
|
||||||
Ckath | https://github.com/Ckath | | Contributor
|
|
||||||
matijakevic | https://github.com/matijakevic | | Contributor
|
@header Contributors
|
||||||
nforro | https://github.com/nforro | | Contributor
|
|
||||||
vanolpfan | https://github.com/vanolpfan | | Contributor
|
Cranken | https://github.com/Cranken |
|
||||||
23rd | https://github.com/23rd | | Contributor
|
hemirt | https://github.com/hemirt |
|
||||||
machgo | https://github.com/machgo | | Contributor
|
LajamerrMittesdine | https://github.com/LajamerrMittesdine |
|
||||||
TranRed | https://github.com/TranRed | | Contributor
|
coral | https://github.com/coral |
|
||||||
RAnders00 | https://github.com/RAnders00 | | Contributor
|
apa420 | https://github.com/apa420 |
|
||||||
gempir | https://github.com/gempir | | Contributor
|
DatGuy1 | https://github.com/DatGuy1 |
|
||||||
mfmarlow | https://github.com/mfmarlow | | Contributor
|
Confuseh | https://github.com/Confuseh |
|
||||||
y0dax | https://github.com/y0dax | | Contributor
|
ch-ems | https://github.com/ch-ems |
|
||||||
Iulian Onofrei | https://github.com/revolter | :/avatars/revolter.jpg | Contributor
|
Bur0k | https://github.com/Bur0k |
|
||||||
matthewde | https://github.com/m4tthewde | :/avatars/matthewde.jpg | Contributor
|
nuuls | https://github.com/nuuls |
|
||||||
Karar Al-Remahy | https://github.com/KararTY | :/avatars/kararty.png | Contributor
|
Chronophylos | https://github.com/Chronophylos |
|
||||||
Talen | https://github.com/talneoran | | Contributor
|
Ckath | https://github.com/Ckath |
|
||||||
SLCH | https://github.com/SLCH | :/avatars/slch.png | Contributor
|
matijakevic | https://github.com/matijakevic |
|
||||||
ALazyMeme | https://github.com/alazymeme | :/avatars/alazymeme.png | Contributor
|
nforro | https://github.com/nforro |
|
||||||
xHeaveny_ | https://github.com/xHeaveny | :/avatars/xheaveny.png | Contributor
|
vanolpfan | https://github.com/vanolpfan |
|
||||||
1xelerate | https://github.com/xel86 | :/avatars/_1xelerate.png | Contributor
|
23rd | https://github.com/23rd |
|
||||||
acdvs | https://github.com/acdvs | | Contributor
|
machgo | https://github.com/machgo |
|
||||||
karl-police | https://github.com/karl-police | :/avatars/karlpolice.png | Contributor
|
TranRed | https://github.com/TranRed |
|
||||||
brian6932 | https://github.com/brian6932 | :/avatars/brian6932.png | Contributor
|
RAnders00 | https://github.com/RAnders00 |
|
||||||
hicupalot | https://github.com/hicupalot | :/avatars/hicupalot.png | Contributor
|
gempir | https://github.com/gempir |
|
||||||
iProdigy | https://github.com/iProdigy | :/avatars/iprodigy.png | Contributor
|
mfmarlow | https://github.com/mfmarlow |
|
||||||
Jaxkey | https://github.com/Jaxkey | :/avatars/jaxkey.png | Contributor
|
y0dax | https://github.com/y0dax |
|
||||||
Explooosion | https://github.com/Explooosion-code | :/avatars/explooosion_code.png | Contributor
|
Iulian Onofrei | https://github.com/revolter | :/avatars/revolter.jpg
|
||||||
mohad12211 | https://github.com/mohad12211 | :/avatars/mohad12211.png | Contributor
|
matthewde | https://github.com/m4tthewde | :/avatars/matthewde.jpg
|
||||||
Wissididom | https://github.com/Wissididom | :/avatars/wissididom.png | Contributor
|
Karar Al-Remahy | https://github.com/KararTY | :/avatars/kararty.png
|
||||||
03y | https://github.com/03y | | Contributor
|
Talen | https://github.com/talneoran |
|
||||||
ScrubN | https://github.com/ScrubN | | Contributor
|
SLCH | https://github.com/SLCH | :/avatars/slch.png
|
||||||
Cyclone | https://github.com/PsycloneTM | :/avatars/cyclone.png | Contributor
|
ALazyMeme | https://github.com/alazymeme | :/avatars/alazymeme.png
|
||||||
2547techno | https://github.com/2547techno | :/avatars/techno.png | Contributor
|
xHeaveny_ | https://github.com/xHeaveny | :/avatars/xheaveny.png
|
||||||
ZonianMidian | https://github.com/ZonianMidian | :/avatars/zonianmidian.png | Contributor
|
1xelerate | https://github.com/xel86 | :/avatars/_1xelerate.png
|
||||||
olafyang | https://github.com/olafyang | | Contributor
|
acdvs | https://github.com/acdvs |
|
||||||
chrrs | https://github.com/chrrs | | Contributor
|
karl-police | https://github.com/karl-police | :/avatars/karlpolice.png
|
||||||
4rneee | https://github.com/4rneee | | Contributor
|
brian6932 | https://github.com/brian6932 | :/avatars/brian6932.png
|
||||||
crazysmc | https://github.com/crazysmc | :/avatars/crazysmc.png | Contributor
|
hicupalot | https://github.com/hicupalot | :/avatars/hicupalot.png
|
||||||
SputNikPlop | https://github.com/SputNikPlop | | Contributor
|
iProdigy | https://github.com/iProdigy | :/avatars/iprodigy.png
|
||||||
fraxx | https://github.com/fraxxio | :/avatars/fraxx.png | Contributor
|
Jaxkey | https://github.com/Jaxkey | :/avatars/jaxkey.png
|
||||||
KleberPF | https://github.com/KleberPF | | Contributor
|
Explooosion | https://github.com/Explooosion-code | :/avatars/explooosion_code.png
|
||||||
|
mohad12211 | https://github.com/mohad12211 | :/avatars/mohad12211.png
|
||||||
|
Wissididom | https://github.com/Wissididom | :/avatars/wissididom.png
|
||||||
|
03y | https://github.com/03y |
|
||||||
|
ScrubN | https://github.com/ScrubN |
|
||||||
|
Cyclone | https://github.com/PsycloneTM | :/avatars/cyclone.png
|
||||||
|
2547techno | https://github.com/2547techno | :/avatars/techno.png
|
||||||
|
ZonianMidian | https://github.com/ZonianMidian | :/avatars/zonianmidian.png
|
||||||
|
olafyang | https://github.com/olafyang |
|
||||||
|
chrrs | https://github.com/chrrs |
|
||||||
|
4rneee | https://github.com/4rneee |
|
||||||
|
crazysmc | https://github.com/crazysmc | :/avatars/crazysmc.png
|
||||||
|
SputNikPlop | https://github.com/SputNikPlop |
|
||||||
|
fraxx | https://github.com/fraxxio | :/avatars/fraxx.png
|
||||||
|
KleberPF | https://github.com/KleberPF |
|
||||||
|
|
||||||
# If you are a contributor add yourself above this line
|
# If you are a contributor add yourself above this line
|
||||||
|
|
||||||
Defman21 | https://github.com/Defman21 | | Documentation
|
@header Documentation
|
||||||
vilgotf | https://github.com/vilgotf | | Documentation
|
|
||||||
Ian321 | https://github.com/Ian321 | | Documentation
|
Defman21 | https://github.com/Defman21 |
|
||||||
Yardanico | https://github.com/Yardanico | | Documentation
|
vilgotf | https://github.com/vilgotf |
|
||||||
huti26 | https://github.com/huti26 | | Documentation
|
Ian321 | https://github.com/Ian321 |
|
||||||
chrisduerr | https://github.com/chrisduerr | | Documentation
|
Yardanico | https://github.com/Yardanico |
|
||||||
|
huti26 | https://github.com/huti26 |
|
||||||
|
chrisduerr | https://github.com/chrisduerr |
|
||||||
|
|
||||||
# Otherwise add yourself right above this one
|
# Otherwise add yourself right above this one
|
||||||
|
|
|
@ -656,6 +656,9 @@ set(SOURCE_FILES
|
||||||
widgets/helper/TitlebarButtons.cpp
|
widgets/helper/TitlebarButtons.cpp
|
||||||
widgets/helper/TitlebarButtons.hpp
|
widgets/helper/TitlebarButtons.hpp
|
||||||
|
|
||||||
|
widgets/layout/FlowLayout.cpp
|
||||||
|
widgets/layout/FlowLayout.hpp
|
||||||
|
|
||||||
widgets/listview/GenericItemDelegate.cpp
|
widgets/listview/GenericItemDelegate.cpp
|
||||||
widgets/listview/GenericItemDelegate.hpp
|
widgets/listview/GenericItemDelegate.hpp
|
||||||
widgets/listview/GenericListItem.cpp
|
widgets/listview/GenericListItem.cpp
|
||||||
|
|
252
src/widgets/layout/FlowLayout.cpp
Normal file
252
src/widgets/layout/FlowLayout.cpp
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
#include "widgets/layout/FlowLayout.hpp"
|
||||||
|
|
||||||
|
#include <QSizePolicy>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace chatterino;
|
||||||
|
|
||||||
|
class Linebreak : public QWidget
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
FlowLayout::FlowLayout(QWidget *parent, Options options)
|
||||||
|
: QLayout(parent)
|
||||||
|
, hSpace_(options.hSpacing)
|
||||||
|
, vSpace_(options.vSpacing)
|
||||||
|
{
|
||||||
|
if (options.margin >= 0)
|
||||||
|
{
|
||||||
|
this->setContentsMargins(options.margin, options.margin, options.margin,
|
||||||
|
options.margin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FlowLayout::FlowLayout(Options options)
|
||||||
|
: FlowLayout(nullptr, options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FlowLayout::~FlowLayout()
|
||||||
|
{
|
||||||
|
for (auto *item : this->itemList_)
|
||||||
|
{
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
this->itemList_ = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlowLayout::addItem(QLayoutItem *item)
|
||||||
|
{
|
||||||
|
this->itemList_.push_back(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlowLayout::addLinebreak(int height)
|
||||||
|
{
|
||||||
|
auto *linebreak = new Linebreak;
|
||||||
|
linebreak->setFixedHeight(height);
|
||||||
|
this->addWidget(linebreak);
|
||||||
|
}
|
||||||
|
|
||||||
|
int FlowLayout::horizontalSpacing() const
|
||||||
|
{
|
||||||
|
if (this->hSpace_ >= 0)
|
||||||
|
{
|
||||||
|
return this->hSpace_;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->defaultSpacing(QStyle::PM_LayoutHorizontalSpacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlowLayout::setHorizontalSpacing(int value)
|
||||||
|
{
|
||||||
|
if (this->hSpace_ == value)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->hSpace_ = value;
|
||||||
|
this->invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
int FlowLayout::verticalSpacing() const
|
||||||
|
{
|
||||||
|
if (this->vSpace_ >= 0)
|
||||||
|
{
|
||||||
|
return this->vSpace_;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->defaultSpacing(QStyle::PM_LayoutVerticalSpacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlowLayout::setVerticalSpacing(int value)
|
||||||
|
{
|
||||||
|
if (this->vSpace_ == value)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->vSpace_ = value;
|
||||||
|
this->invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
int FlowLayout::count() const
|
||||||
|
{
|
||||||
|
return static_cast<int>(this->itemList_.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
QLayoutItem *FlowLayout::itemAt(int index) const
|
||||||
|
{
|
||||||
|
if (index >= 0 && index < static_cast<int>(this->itemList_.size()))
|
||||||
|
{
|
||||||
|
return this->itemList_[static_cast<size_t>(index)];
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLayoutItem *FlowLayout::takeAt(int index)
|
||||||
|
{
|
||||||
|
if (index >= 0 && index < static_cast<int>(this->itemList_.size()))
|
||||||
|
{
|
||||||
|
auto *it = this->itemList_[static_cast<size_t>(index)];
|
||||||
|
this->itemList_.erase(this->itemList_.cbegin() +
|
||||||
|
static_cast<qsizetype>(index));
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::Orientations FlowLayout::expandingDirections() const
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FlowLayout::hasHeightForWidth() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FlowLayout::heightForWidth(int width) const
|
||||||
|
{
|
||||||
|
return this->doLayout({0, 0, width, 0}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlowLayout::setGeometry(const QRect &rect)
|
||||||
|
{
|
||||||
|
QLayout::setGeometry(rect);
|
||||||
|
this->doLayout(rect, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize FlowLayout::sizeHint() const
|
||||||
|
{
|
||||||
|
return this->minimumSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize FlowLayout::minimumSize() const
|
||||||
|
{
|
||||||
|
QSize size;
|
||||||
|
for (const auto *item : this->itemList_)
|
||||||
|
{
|
||||||
|
size = size.expandedTo(item->minimumSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
const QMargins margins = contentsMargins();
|
||||||
|
size += QSize(margins.left() + margins.right(),
|
||||||
|
margins.top() + margins.bottom());
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FlowLayout::doLayout(const QRect &rect, bool testOnly) const
|
||||||
|
{
|
||||||
|
auto margins = this->contentsMargins();
|
||||||
|
QRect effectiveRect = rect.adjusted(margins.left(), margins.top(),
|
||||||
|
-margins.right(), -margins.bottom());
|
||||||
|
int x = effectiveRect.x();
|
||||||
|
int y = effectiveRect.y();
|
||||||
|
int lineHeight = 0;
|
||||||
|
for (QLayoutItem *item : this->itemList_)
|
||||||
|
{
|
||||||
|
auto *linebreak = dynamic_cast<Linebreak *>(item->widget());
|
||||||
|
if (linebreak)
|
||||||
|
{
|
||||||
|
item->setGeometry({x, y, 0, linebreak->height()});
|
||||||
|
x = effectiveRect.x();
|
||||||
|
y = y + lineHeight + linebreak->height();
|
||||||
|
lineHeight = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto space = this->getSpacing(item);
|
||||||
|
int nextX = x + item->sizeHint().width() + space.width();
|
||||||
|
if (nextX - space.width() > effectiveRect.right() && lineHeight > 0)
|
||||||
|
{
|
||||||
|
x = effectiveRect.x();
|
||||||
|
y = y + lineHeight + space.height();
|
||||||
|
nextX = x + item->sizeHint().width() + space.width();
|
||||||
|
lineHeight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!testOnly)
|
||||||
|
{
|
||||||
|
item->setGeometry({QPoint{x, y}, item->sizeHint()});
|
||||||
|
}
|
||||||
|
|
||||||
|
x = nextX;
|
||||||
|
lineHeight = qMax(lineHeight, item->sizeHint().height());
|
||||||
|
}
|
||||||
|
|
||||||
|
return y + lineHeight - rect.y() + margins.bottom();
|
||||||
|
}
|
||||||
|
|
||||||
|
int FlowLayout::defaultSpacing(QStyle::PixelMetric pm) const
|
||||||
|
{
|
||||||
|
QObject *parent = this->parent();
|
||||||
|
if (!parent)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (auto *widget = dynamic_cast<QWidget *>(parent))
|
||||||
|
{
|
||||||
|
return widget->style()->pixelMetric(pm, nullptr, widget);
|
||||||
|
}
|
||||||
|
if (auto *layout = dynamic_cast<QLayout *>(parent))
|
||||||
|
{
|
||||||
|
return layout->spacing();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize FlowLayout::getSpacing(QLayoutItem *item) const
|
||||||
|
{
|
||||||
|
// called if there isn't any parent or the parent can't provide any spacing
|
||||||
|
auto fallbackSpacing = [&](auto dir) {
|
||||||
|
if (auto *widget = item->widget())
|
||||||
|
{
|
||||||
|
return widget->style()->layoutSpacing(QSizePolicy::PushButton,
|
||||||
|
QSizePolicy::PushButton, dir);
|
||||||
|
}
|
||||||
|
if (auto *layout = item->layout())
|
||||||
|
{
|
||||||
|
return layout->spacing();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
QSize spacing(this->horizontalSpacing(), this->verticalSpacing());
|
||||||
|
if (spacing.width() == -1)
|
||||||
|
{
|
||||||
|
spacing.rwidth() = fallbackSpacing(Qt::Horizontal);
|
||||||
|
}
|
||||||
|
if (spacing.height() == -1)
|
||||||
|
{
|
||||||
|
spacing.rheight() = fallbackSpacing(Qt::Vertical);
|
||||||
|
}
|
||||||
|
return spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace chatterino
|
104
src/widgets/layout/FlowLayout.hpp
Normal file
104
src/widgets/layout/FlowLayout.hpp
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QLayout>
|
||||||
|
#include <QStyle>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
|
/// @brief A QLayout wrapping items
|
||||||
|
///
|
||||||
|
/// Similar to a box layout that wraps its items. It's not super optimized.
|
||||||
|
/// Some computations in #doLayout() could be cached.
|
||||||
|
///
|
||||||
|
/// This is based on the Qt flow layout example:
|
||||||
|
/// https://doc.qt.io/qt-6/qtwidgets-layouts-flowlayout-example.html
|
||||||
|
class FlowLayout : public QLayout
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Options {
|
||||||
|
int margin = -1;
|
||||||
|
int hSpacing = -1;
|
||||||
|
int vSpacing = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit FlowLayout(QWidget *parent, Options options = {-1, -1, -1});
|
||||||
|
explicit FlowLayout(Options options = {-1, -1, -1});
|
||||||
|
|
||||||
|
~FlowLayout() override;
|
||||||
|
FlowLayout(const FlowLayout &) = delete;
|
||||||
|
FlowLayout(FlowLayout &&) = delete;
|
||||||
|
FlowLayout &operator=(const FlowLayout &) = delete;
|
||||||
|
FlowLayout &operator=(FlowLayout &&) = delete;
|
||||||
|
|
||||||
|
/// @brief Adds @a item to this layout
|
||||||
|
///
|
||||||
|
/// Ownership of @a item is transferred. This method isn't usually called
|
||||||
|
/// in application code (use addWidget/addLayout).
|
||||||
|
/// See QLayout::addItem for more information.
|
||||||
|
void addItem(QLayoutItem *item) override;
|
||||||
|
|
||||||
|
/// @brief Adds a linebreak to this layout
|
||||||
|
///
|
||||||
|
/// @param height Specifies the height of the linebreak
|
||||||
|
void addLinebreak(int height = 0);
|
||||||
|
|
||||||
|
/// @brief Spacing on the horizontal axis
|
||||||
|
///
|
||||||
|
/// -1 if the default spacing for an item will be used.
|
||||||
|
[[nodiscard]] int horizontalSpacing() const;
|
||||||
|
|
||||||
|
/// Setter for #horizontalSpacing(). -1 to use defaults.
|
||||||
|
void setHorizontalSpacing(int value);
|
||||||
|
|
||||||
|
/// @brief Spacing on the vertical axis
|
||||||
|
///
|
||||||
|
/// -1 if the default spacing for an item will be used.
|
||||||
|
[[nodiscard]] int verticalSpacing() const;
|
||||||
|
|
||||||
|
/// Setter for #verticalSpacing(). -1 to use defaults.
|
||||||
|
void setVerticalSpacing(int value);
|
||||||
|
|
||||||
|
/// From QLayout. This layout doesn't expand in any direction.
|
||||||
|
Qt::Orientations expandingDirections() const override;
|
||||||
|
bool hasHeightForWidth() const override;
|
||||||
|
int heightForWidth(int width) const override;
|
||||||
|
|
||||||
|
QSize minimumSize() const override;
|
||||||
|
QSize sizeHint() const override;
|
||||||
|
|
||||||
|
void setGeometry(const QRect &rect) override;
|
||||||
|
|
||||||
|
int count() const override;
|
||||||
|
QLayoutItem *itemAt(int index) const override;
|
||||||
|
|
||||||
|
/// From QLayout. Ownership is transferred to the caller
|
||||||
|
QLayoutItem *takeAt(int index) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// @brief Computes the layout
|
||||||
|
///
|
||||||
|
/// @param rect The area in which items can be layed out
|
||||||
|
/// @param testOnly If set, items won't be moved, only the total height
|
||||||
|
/// will be computed.
|
||||||
|
/// @returns The total height including margins.
|
||||||
|
int doLayout(const QRect &rect, bool testOnly) const;
|
||||||
|
|
||||||
|
/// @brief Computes the default spacing based for items on the parent
|
||||||
|
///
|
||||||
|
/// @param pm Either PM_LayoutHorizontalSpacing or PM_LayoutVerticalSpacing
|
||||||
|
/// for the respective direction.
|
||||||
|
/// @returns The spacing in dp, -1 if there isn't any parent
|
||||||
|
int defaultSpacing(QStyle::PixelMetric pm) const;
|
||||||
|
|
||||||
|
/// Computes the spacing for @a item
|
||||||
|
QSize getSpacing(QLayoutItem *item) const;
|
||||||
|
|
||||||
|
std::vector<QLayoutItem *> itemList_;
|
||||||
|
int hSpace_ = -1;
|
||||||
|
int vSpace_ = -1;
|
||||||
|
int lineSpacing_ = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace chatterino
|
|
@ -8,6 +8,7 @@
|
||||||
#include "util/RemoveScrollAreaBackground.hpp"
|
#include "util/RemoveScrollAreaBackground.hpp"
|
||||||
#include "widgets/BasePopup.hpp"
|
#include "widgets/BasePopup.hpp"
|
||||||
#include "widgets/helper/SignalLabel.hpp"
|
#include "widgets/helper/SignalLabel.hpp"
|
||||||
|
#include "widgets/layout/FlowLayout.hpp"
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFormLayout>
|
#include <QFormLayout>
|
||||||
|
@ -54,6 +55,7 @@ AboutPage::AboutPage()
|
||||||
|
|
||||||
auto label = vbox.emplace<QLabel>(version.buildString() + "<br>" +
|
auto label = vbox.emplace<QLabel>(version.buildString() + "<br>" +
|
||||||
version.runningString());
|
version.runningString());
|
||||||
|
label->setWordWrap(true);
|
||||||
label->setOpenExternalLinks(true);
|
label->setOpenExternalLinks(true);
|
||||||
label->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
label->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||||
}
|
}
|
||||||
|
@ -137,15 +139,15 @@ AboutPage::AboutPage()
|
||||||
l.emplace<QLabel>("Facebook emojis provided by <a href=\"https://facebook.com\">Facebook</a>")->setOpenExternalLinks(true);
|
l.emplace<QLabel>("Facebook emojis provided by <a href=\"https://facebook.com\">Facebook</a>")->setOpenExternalLinks(true);
|
||||||
l.emplace<QLabel>("Apple emojis provided by <a href=\"https://apple.com\">Apple</a>")->setOpenExternalLinks(true);
|
l.emplace<QLabel>("Apple emojis provided by <a href=\"https://apple.com\">Apple</a>")->setOpenExternalLinks(true);
|
||||||
l.emplace<QLabel>("Google emojis provided by <a href=\"https://google.com\">Google</a>")->setOpenExternalLinks(true);
|
l.emplace<QLabel>("Google emojis provided by <a href=\"https://google.com\">Google</a>")->setOpenExternalLinks(true);
|
||||||
l.emplace<QLabel>("Emoji datasource provided by <a href=\"https://www.iamcal.com/\">Cal Henderson</a>"
|
l.emplace<QLabel>("Emoji datasource provided by <a href=\"https://www.iamcal.com/\">Cal Henderson</a> "
|
||||||
"(<a href=\"https://github.com/iamcal/emoji-data/blob/master/LICENSE\">show license</a>)")->setOpenExternalLinks(true);
|
"(<a href=\"https://github.com/iamcal/emoji-data/blob/master/LICENSE\">show license</a>)")->setOpenExternalLinks(true);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
// Contributors
|
// Contributors
|
||||||
auto contributors = layout.emplace<QGroupBox>("Contributors");
|
auto contributors = layout.emplace<QGroupBox>("People");
|
||||||
{
|
{
|
||||||
auto l = contributors.emplace<QVBoxLayout>();
|
auto l = contributors.emplace<FlowLayout>();
|
||||||
|
|
||||||
QFile contributorsFile(":/contributors.txt");
|
QFile contributorsFile(":/contributors.txt");
|
||||||
contributorsFile.open(QFile::ReadOnly);
|
contributorsFile.open(QFile::ReadOnly);
|
||||||
|
@ -166,11 +168,24 @@ AboutPage::AboutPage()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (line.startsWith(u"@header"))
|
||||||
|
{
|
||||||
|
if (l->count() != 0)
|
||||||
|
{
|
||||||
|
l->addLinebreak(20);
|
||||||
|
}
|
||||||
|
auto *label = new QLabel(QStringLiteral("<h1>%1</h1>")
|
||||||
|
.arg(line.mid(8).trimmed()));
|
||||||
|
l->addWidget(label);
|
||||||
|
l->addLinebreak(8);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
QStringList contributorParts = line.split("|");
|
QStringList contributorParts = line.split("|");
|
||||||
|
|
||||||
if (contributorParts.size() != 4)
|
if (contributorParts.size() != 3)
|
||||||
{
|
{
|
||||||
qCDebug(chatterinoWidget)
|
qCWarning(chatterinoWidget)
|
||||||
<< "Missing parts in line" << line;
|
<< "Missing parts in line" << line;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -178,39 +193,42 @@ AboutPage::AboutPage()
|
||||||
QString username = contributorParts[0].trimmed();
|
QString username = contributorParts[0].trimmed();
|
||||||
QString url = contributorParts[1].trimmed();
|
QString url = contributorParts[1].trimmed();
|
||||||
QString avatarUrl = contributorParts[2].trimmed();
|
QString avatarUrl = contributorParts[2].trimmed();
|
||||||
QString role = contributorParts[3].trimmed();
|
|
||||||
|
|
||||||
auto *usernameLabel =
|
auto *usernameLabel =
|
||||||
new QLabel("<a href=\"" + url + "\">" + username + "</a>");
|
new QLabel("<a href=\"" + url + "\">" + username + "</a>");
|
||||||
usernameLabel->setOpenExternalLinks(true);
|
usernameLabel->setOpenExternalLinks(true);
|
||||||
auto *roleLabel = new QLabel(role);
|
usernameLabel->setToolTip(url);
|
||||||
|
|
||||||
auto contributorBox2 = l.emplace<QHBoxLayout>();
|
auto contributorBox2 = l.emplace<QVBoxLayout>();
|
||||||
|
|
||||||
const auto addAvatar = [&avatarUrl, &contributorBox2] {
|
const auto addAvatar = [&] {
|
||||||
if (!avatarUrl.isEmpty())
|
auto *avatar = new QLabel();
|
||||||
|
QPixmap avatarPixmap;
|
||||||
|
if (avatarUrl.isEmpty())
|
||||||
{
|
{
|
||||||
QPixmap avatarPixmap;
|
// TODO: or anon.png
|
||||||
avatarPixmap.load(avatarUrl);
|
avatarPixmap.load(":/avatars/anon.png");
|
||||||
|
|
||||||
auto avatar = contributorBox2.emplace<QLabel>();
|
|
||||||
avatar->setPixmap(avatarPixmap);
|
|
||||||
avatar->setFixedSize(64, 64);
|
|
||||||
avatar->setScaledContents(true);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
avatarPixmap.load(avatarUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
avatar->setPixmap(avatarPixmap);
|
||||||
|
avatar->setFixedSize(64, 64);
|
||||||
|
avatar->setScaledContents(true);
|
||||||
|
contributorBox2->addWidget(avatar, 0, Qt::AlignCenter);
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto addLabels = [&contributorBox2, &usernameLabel,
|
const auto addLabels = [&] {
|
||||||
&roleLabel] {
|
|
||||||
auto *labelBox = new QVBoxLayout();
|
auto *labelBox = new QVBoxLayout();
|
||||||
contributorBox2->addLayout(labelBox);
|
contributorBox2->addLayout(labelBox);
|
||||||
|
|
||||||
labelBox->addWidget(usernameLabel);
|
labelBox->addWidget(usernameLabel, 0, Qt::AlignCenter);
|
||||||
labelBox->addWidget(roleLabel);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
addLabels();
|
|
||||||
addAvatar();
|
addAvatar();
|
||||||
|
addLabels();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue