Change indentation to 4 spaces

This commit is contained in:
Nicolas Werner 2021-09-18 00:22:33 +02:00
parent e118f3882d
commit cfca7157b9
No known key found for this signature in database
GPG key ID: C8D75E610773F2D9
165 changed files with 23146 additions and 23975 deletions

View file

@ -9,214 +9,214 @@
Badge::Badge(QWidget *parent)
: OverlayWidget(parent)
{
init();
init();
}
Badge::Badge(const QIcon &icon, QWidget *parent)
: OverlayWidget(parent)
{
init();
setIcon(icon);
init();
setIcon(icon);
}
Badge::Badge(const QString &text, QWidget *parent)
: OverlayWidget(parent)
{
init();
setText(text);
init();
setText(text);
}
void
Badge::init()
{
x_ = 0;
y_ = 0;
// TODO: Make padding configurable.
padding_ = 5;
diameter_ = 24;
x_ = 0;
y_ = 0;
// TODO: Make padding configurable.
padding_ = 5;
diameter_ = 24;
setAttribute(Qt::WA_TransparentForMouseEvents);
setAttribute(Qt::WA_TransparentForMouseEvents);
QFont _font(font());
_font.setPointSizeF(7.5);
_font.setStyleName("Bold");
QFont _font(font());
_font.setPointSizeF(7.5);
_font.setStyleName("Bold");
setFont(_font);
setText("");
setFont(_font);
setText("");
}
QString
Badge::text() const
{
return text_;
return text_;
}
QIcon
Badge::icon() const
{
return icon_;
return icon_;
}
QSize
Badge::sizeHint() const
{
const int d = diameter();
return QSize(d + 4, d + 4);
const int d = diameter();
return QSize(d + 4, d + 4);
}
qreal
Badge::relativeYPosition() const
{
return y_;
return y_;
}
qreal
Badge::relativeXPosition() const
{
return x_;
return x_;
}
QPointF
Badge::relativePosition() const
{
return QPointF(x_, y_);
return QPointF(x_, y_);
}
QColor
Badge::backgroundColor() const
{
if (!background_color_.isValid())
return QColor("black");
if (!background_color_.isValid())
return QColor("black");
return background_color_;
return background_color_;
}
QColor
Badge::textColor() const
{
if (!text_color_.isValid())
return QColor("white");
if (!text_color_.isValid())
return QColor("white");
return text_color_;
return text_color_;
}
void
Badge::setTextColor(const QColor &color)
{
text_color_ = color;
text_color_ = color;
}
void
Badge::setBackgroundColor(const QColor &color)
{
background_color_ = color;
background_color_ = color;
}
void
Badge::setRelativePosition(const QPointF &pos)
{
setRelativePosition(pos.x(), pos.y());
setRelativePosition(pos.x(), pos.y());
}
void
Badge::setRelativePosition(qreal x, qreal y)
{
x_ = x;
y_ = y;
update();
x_ = x;
y_ = y;
update();
}
void
Badge::setRelativeXPosition(qreal x)
{
x_ = x;
update();
x_ = x;
update();
}
void
Badge::setRelativeYPosition(qreal y)
{
y_ = y;
update();
y_ = y;
update();
}
void
Badge::setIcon(const QIcon &icon)
{
icon_ = icon;
update();
icon_ = icon;
update();
}
void
Badge::setText(const QString &text)
{
text_ = text;
text_ = text;
if (!icon_.isNull())
icon_ = QIcon();
if (!icon_.isNull())
icon_ = QIcon();
size_ = fontMetrics().size(Qt::TextShowMnemonic, text);
size_ = fontMetrics().size(Qt::TextShowMnemonic, text);
update();
update();
}
void
Badge::setDiameter(int diameter)
{
if (diameter > 0) {
diameter_ = diameter;
update();
}
if (diameter > 0) {
diameter_ = diameter;
update();
}
}
void
Badge::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.translate(x_, y_);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.translate(x_, y_);
QBrush brush;
brush.setStyle(Qt::SolidPattern);
QBrush brush;
brush.setStyle(Qt::SolidPattern);
painter.setBrush(brush);
painter.setPen(Qt::NoPen);
painter.setBrush(brush);
painter.setPen(Qt::NoPen);
const int d = diameter();
const int d = diameter();
QRectF r(0, 0, d, d);
r.translate(QPointF((width() - d), (height() - d)) / 2);
QRectF r(0, 0, d, d);
r.translate(QPointF((width() - d), (height() - d)) / 2);
if (icon_.isNull()) {
QPen pen;
// TODO: Make badge width configurable.
pen.setWidth(1);
pen.setColor(textColor());
if (icon_.isNull()) {
QPen pen;
// TODO: Make badge width configurable.
pen.setWidth(1);
pen.setColor(textColor());
painter.setPen(pen);
painter.drawEllipse(r);
painter.setPen(pen);
painter.drawEllipse(r);
painter.setPen(textColor());
painter.setBrush(Qt::NoBrush);
painter.drawText(r.translated(0, -0.5), Qt::AlignCenter, text_);
} else {
painter.drawEllipse(r);
QRectF q(0, 0, 16, 16);
q.moveCenter(r.center());
QPixmap pixmap = icon().pixmap(16, 16);
QPainter icon(&pixmap);
icon.setCompositionMode(QPainter::CompositionMode_SourceIn);
icon.fillRect(pixmap.rect(), textColor());
painter.drawPixmap(q.toRect(), pixmap);
}
painter.setPen(textColor());
painter.setBrush(Qt::NoBrush);
painter.drawText(r.translated(0, -0.5), Qt::AlignCenter, text_);
} else {
painter.drawEllipse(r);
QRectF q(0, 0, 16, 16);
q.moveCenter(r.center());
QPixmap pixmap = icon().pixmap(16, 16);
QPainter icon(&pixmap);
icon.setCompositionMode(QPainter::CompositionMode_SourceIn);
icon.fillRect(pixmap.rect(), textColor());
painter.drawPixmap(q.toRect(), pixmap);
}
}
int
Badge::diameter() const
{
if (icon_.isNull()) {
return qMax(size_.width(), size_.height()) + padding_;
}
if (icon_.isNull()) {
return qMax(size_.width(), size_.height()) + padding_;
}
return diameter_;
return diameter_;
}

View file

@ -13,54 +13,54 @@
class Badge : public OverlayWidget
{
Q_OBJECT
Q_OBJECT
Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor)
Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor)
Q_PROPERTY(QPointF relativePosition WRITE setRelativePosition READ relativePosition)
Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor)
Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor)
Q_PROPERTY(QPointF relativePosition WRITE setRelativePosition READ relativePosition)
public:
explicit Badge(QWidget *parent = nullptr);
explicit Badge(const QIcon &icon, QWidget *parent = nullptr);
explicit Badge(const QString &text, QWidget *parent = nullptr);
explicit Badge(QWidget *parent = nullptr);
explicit Badge(const QIcon &icon, QWidget *parent = nullptr);
explicit Badge(const QString &text, QWidget *parent = nullptr);
void setBackgroundColor(const QColor &color);
void setTextColor(const QColor &color);
void setIcon(const QIcon &icon);
void setRelativePosition(const QPointF &pos);
void setRelativePosition(qreal x, qreal y);
void setRelativeXPosition(qreal x);
void setRelativeYPosition(qreal y);
void setText(const QString &text);
void setDiameter(int diameter);
void setBackgroundColor(const QColor &color);
void setTextColor(const QColor &color);
void setIcon(const QIcon &icon);
void setRelativePosition(const QPointF &pos);
void setRelativePosition(qreal x, qreal y);
void setRelativeXPosition(qreal x);
void setRelativeYPosition(qreal y);
void setText(const QString &text);
void setDiameter(int diameter);
QIcon icon() const;
QString text() const;
QColor backgroundColor() const;
QColor textColor() const;
QPointF relativePosition() const;
QSize sizeHint() const override;
qreal relativeXPosition() const;
qreal relativeYPosition() const;
QIcon icon() const;
QString text() const;
QColor backgroundColor() const;
QColor textColor() const;
QPointF relativePosition() const;
QSize sizeHint() const override;
qreal relativeXPosition() const;
qreal relativeYPosition() const;
int diameter() const;
int diameter() const;
protected:
void paintEvent(QPaintEvent *event) override;
void paintEvent(QPaintEvent *event) override;
private:
void init();
void init();
QColor background_color_;
QColor text_color_;
QColor background_color_;
QColor text_color_;
QIcon icon_;
QSize size_;
QString text_;
QIcon icon_;
QSize size_;
QString text_;
int padding_;
int diameter_;
int padding_;
int diameter_;
qreal x_;
qreal y_;
qreal x_;
qreal y_;
};

View file

@ -19,94 +19,89 @@ DropShadow::draw(QPainter &painter,
qreal width,
qreal height)
{
painter.setPen(Qt::NoPen);
painter.setPen(Qt::NoPen);
QLinearGradient gradient;
gradient.setColorAt(startPosition, start);
gradient.setColorAt(endPosition0, end);
QLinearGradient gradient;
gradient.setColorAt(startPosition, start);
gradient.setColorAt(endPosition0, end);
// Right
QPointF right0(width - margin, height / 2);
QPointF right1(width, height / 2);
gradient.setStart(right0);
gradient.setFinalStop(right1);
painter.setBrush(QBrush(gradient));
// Deprecated in 5.13: painter.drawRoundRect(
// QRectF(QPointF(width - margin * radius, margin), QPointF(width, height -
// margin)), 0.0, 0.0);
painter.drawRoundedRect(
QRectF(QPointF(width - margin * radius, margin), QPointF(width, height - margin)),
0.0,
0.0);
// Right
QPointF right0(width - margin, height / 2);
QPointF right1(width, height / 2);
gradient.setStart(right0);
gradient.setFinalStop(right1);
painter.setBrush(QBrush(gradient));
// Deprecated in 5.13: painter.drawRoundRect(
// QRectF(QPointF(width - margin * radius, margin), QPointF(width, height -
// margin)), 0.0, 0.0);
painter.drawRoundedRect(
QRectF(QPointF(width - margin * radius, margin), QPointF(width, height - margin)), 0.0, 0.0);
// Left
QPointF left0(margin, height / 2);
QPointF left1(0, height / 2);
gradient.setStart(left0);
gradient.setFinalStop(left1);
painter.setBrush(QBrush(gradient));
painter.drawRoundedRect(
QRectF(QPointF(margin * radius, margin), QPointF(0, height - margin)), 0.0, 0.0);
// Left
QPointF left0(margin, height / 2);
QPointF left1(0, height / 2);
gradient.setStart(left0);
gradient.setFinalStop(left1);
painter.setBrush(QBrush(gradient));
painter.drawRoundedRect(
QRectF(QPointF(margin * radius, margin), QPointF(0, height - margin)), 0.0, 0.0);
// Top
QPointF top0(width / 2, margin);
QPointF top1(width / 2, 0);
gradient.setStart(top0);
gradient.setFinalStop(top1);
painter.setBrush(QBrush(gradient));
painter.drawRoundedRect(
QRectF(QPointF(width - margin, 0), QPointF(margin, margin)), 0.0, 0.0);
// Top
QPointF top0(width / 2, margin);
QPointF top1(width / 2, 0);
gradient.setStart(top0);
gradient.setFinalStop(top1);
painter.setBrush(QBrush(gradient));
painter.drawRoundedRect(QRectF(QPointF(width - margin, 0), QPointF(margin, margin)), 0.0, 0.0);
// Bottom
QPointF bottom0(width / 2, height - margin);
QPointF bottom1(width / 2, height);
gradient.setStart(bottom0);
gradient.setFinalStop(bottom1);
painter.setBrush(QBrush(gradient));
painter.drawRoundedRect(
QRectF(QPointF(margin, height - margin), QPointF(width - margin, height)), 0.0, 0.0);
// Bottom
QPointF bottom0(width / 2, height - margin);
QPointF bottom1(width / 2, height);
gradient.setStart(bottom0);
gradient.setFinalStop(bottom1);
painter.setBrush(QBrush(gradient));
painter.drawRoundedRect(
QRectF(QPointF(margin, height - margin), QPointF(width - margin, height)), 0.0, 0.0);
// BottomRight
QPointF bottomright0(width - margin, height - margin);
QPointF bottomright1(width, height);
gradient.setStart(bottomright0);
gradient.setFinalStop(bottomright1);
gradient.setColorAt(endPosition1, end);
painter.setBrush(QBrush(gradient));
painter.drawRoundedRect(QRectF(bottomright0, bottomright1), 0.0, 0.0);
// BottomRight
QPointF bottomright0(width - margin, height - margin);
QPointF bottomright1(width, height);
gradient.setStart(bottomright0);
gradient.setFinalStop(bottomright1);
gradient.setColorAt(endPosition1, end);
painter.setBrush(QBrush(gradient));
painter.drawRoundedRect(QRectF(bottomright0, bottomright1), 0.0, 0.0);
// BottomLeft
QPointF bottomleft0(margin, height - margin);
QPointF bottomleft1(0, height);
gradient.setStart(bottomleft0);
gradient.setFinalStop(bottomleft1);
gradient.setColorAt(endPosition1, end);
painter.setBrush(QBrush(gradient));
painter.drawRoundedRect(QRectF(bottomleft0, bottomleft1), 0.0, 0.0);
// BottomLeft
QPointF bottomleft0(margin, height - margin);
QPointF bottomleft1(0, height);
gradient.setStart(bottomleft0);
gradient.setFinalStop(bottomleft1);
gradient.setColorAt(endPosition1, end);
painter.setBrush(QBrush(gradient));
painter.drawRoundedRect(QRectF(bottomleft0, bottomleft1), 0.0, 0.0);
// TopLeft
QPointF topleft0(margin, margin);
QPointF topleft1(0, 0);
gradient.setStart(topleft0);
gradient.setFinalStop(topleft1);
gradient.setColorAt(endPosition1, end);
painter.setBrush(QBrush(gradient));
painter.drawRoundedRect(QRectF(topleft0, topleft1), 0.0, 0.0);
// TopLeft
QPointF topleft0(margin, margin);
QPointF topleft1(0, 0);
gradient.setStart(topleft0);
gradient.setFinalStop(topleft1);
gradient.setColorAt(endPosition1, end);
painter.setBrush(QBrush(gradient));
painter.drawRoundedRect(QRectF(topleft0, topleft1), 0.0, 0.0);
// TopRight
QPointF topright0(width - margin, margin);
QPointF topright1(width, 0);
gradient.setStart(topright0);
gradient.setFinalStop(topright1);
gradient.setColorAt(endPosition1, end);
painter.setBrush(QBrush(gradient));
painter.drawRoundedRect(QRectF(topright0, topright1), 0.0, 0.0);
// TopRight
QPointF topright0(width - margin, margin);
QPointF topright1(width, 0);
gradient.setStart(topright0);
gradient.setFinalStop(topright1);
gradient.setColorAt(endPosition1, end);
painter.setBrush(QBrush(gradient));
painter.drawRoundedRect(QRectF(topright0, topright1), 0.0, 0.0);
// Widget
painter.setBrush(QBrush("#FFFFFF"));
painter.setRenderHint(QPainter::Antialiasing);
painter.drawRoundedRect(
QRectF(QPointF(margin, margin), QPointF(width - margin, height - margin)),
radius,
radius);
// Widget
painter.setBrush(QBrush("#FFFFFF"));
painter.setRenderHint(QPainter::Antialiasing);
painter.drawRoundedRect(
QRectF(QPointF(margin, margin), QPointF(width - margin, height - margin)), radius, radius);
}

View file

@ -11,14 +11,14 @@ class QPainter;
class DropShadow
{
public:
static void draw(QPainter &painter,
qint16 margin,
qreal radius,
QColor start,
QColor end,
qreal startPosition,
qreal endPosition0,
qreal endPosition1,
qreal width,
qreal height);
static void draw(QPainter &painter,
qint16 margin,
qreal radius,
QColor start,
QColor end,
qreal startPosition,
qreal endPosition0,
qreal endPosition1,
qreal width,
qreal height);
};

File diff suppressed because it is too large Load diff

View file

@ -14,174 +14,171 @@ class FlatButton;
class FlatButtonStateMachine : public QStateMachine
{
Q_OBJECT
Q_OBJECT
Q_PROPERTY(qreal overlayOpacity WRITE setOverlayOpacity READ overlayOpacity)
Q_PROPERTY(
qreal checkedOverlayProgress WRITE setCheckedOverlayProgress READ checkedOverlayProgress)
Q_PROPERTY(qreal overlayOpacity WRITE setOverlayOpacity READ overlayOpacity)
Q_PROPERTY(
qreal checkedOverlayProgress WRITE setCheckedOverlayProgress READ checkedOverlayProgress)
public:
explicit FlatButtonStateMachine(FlatButton *parent);
~FlatButtonStateMachine() override;
explicit FlatButtonStateMachine(FlatButton *parent);
~FlatButtonStateMachine() override;
void setOverlayOpacity(qreal opacity);
void setCheckedOverlayProgress(qreal opacity);
void setOverlayOpacity(qreal opacity);
void setCheckedOverlayProgress(qreal opacity);
inline qreal overlayOpacity() const;
inline qreal checkedOverlayProgress() const;
inline qreal overlayOpacity() const;
inline qreal checkedOverlayProgress() const;
void startAnimations();
void setupProperties();
void updateCheckedStatus();
void startAnimations();
void setupProperties();
void updateCheckedStatus();
signals:
void buttonPressed();
void buttonChecked();
void buttonUnchecked();
void buttonPressed();
void buttonChecked();
void buttonUnchecked();
protected:
bool eventFilter(QObject *watched, QEvent *event) override;
bool eventFilter(QObject *watched, QEvent *event) override;
private:
void addTransition(QObject *object, const char *signal, QState *fromState, QState *toState);
void addTransition(QObject *object,
QEvent::Type eventType,
QState *fromState,
QState *toState);
void addTransition(QAbstractTransition *transition, QState *fromState, QState *toState);
void addTransition(QObject *object, const char *signal, QState *fromState, QState *toState);
void addTransition(QObject *object, QEvent::Type eventType, QState *fromState, QState *toState);
void addTransition(QAbstractTransition *transition, QState *fromState, QState *toState);
FlatButton *const button_;
FlatButton *const button_;
QState *const top_level_state_;
QState *const config_state_;
QState *const checkable_state_;
QState *const checked_state_;
QState *const unchecked_state_;
QState *const neutral_state_;
QState *const neutral_focused_state_;
QState *const hovered_state_;
QState *const hovered_focused_state_;
QState *const pressed_state_;
QState *const top_level_state_;
QState *const config_state_;
QState *const checkable_state_;
QState *const checked_state_;
QState *const unchecked_state_;
QState *const neutral_state_;
QState *const neutral_focused_state_;
QState *const hovered_state_;
QState *const hovered_focused_state_;
QState *const pressed_state_;
qreal overlay_opacity_;
qreal checked_overlay_progress_;
qreal overlay_opacity_;
qreal checked_overlay_progress_;
bool was_checked_;
bool was_checked_;
};
inline qreal
FlatButtonStateMachine::overlayOpacity() const
{
return overlay_opacity_;
return overlay_opacity_;
}
inline qreal
FlatButtonStateMachine::checkedOverlayProgress() const
{
return checked_overlay_progress_;
return checked_overlay_progress_;
}
class FlatButton : public QPushButton
{
Q_OBJECT
Q_OBJECT
Q_PROPERTY(QColor foregroundColor WRITE setForegroundColor READ foregroundColor)
Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor)
Q_PROPERTY(QColor overlayColor WRITE setOverlayColor READ overlayColor)
Q_PROPERTY(QColor disabledForegroundColor WRITE setDisabledForegroundColor READ
disabledForegroundColor)
Q_PROPERTY(QColor disabledBackgroundColor WRITE setDisabledBackgroundColor READ
disabledBackgroundColor)
Q_PROPERTY(qreal fontSize WRITE setFontSize READ fontSize)
Q_PROPERTY(QColor foregroundColor WRITE setForegroundColor READ foregroundColor)
Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor)
Q_PROPERTY(QColor overlayColor WRITE setOverlayColor READ overlayColor)
Q_PROPERTY(
QColor disabledForegroundColor WRITE setDisabledForegroundColor READ disabledForegroundColor)
Q_PROPERTY(
QColor disabledBackgroundColor WRITE setDisabledBackgroundColor READ disabledBackgroundColor)
Q_PROPERTY(qreal fontSize WRITE setFontSize READ fontSize)
public:
explicit FlatButton(QWidget *parent = nullptr,
ui::ButtonPreset preset = ui::ButtonPreset::FlatPreset);
explicit FlatButton(const QString &text,
QWidget *parent = nullptr,
ui::ButtonPreset preset = ui::ButtonPreset::FlatPreset);
FlatButton(const QString &text,
ui::Role role,
QWidget *parent = nullptr,
ui::ButtonPreset preset = ui::ButtonPreset::FlatPreset);
~FlatButton() override;
explicit FlatButton(QWidget *parent = nullptr,
ui::ButtonPreset preset = ui::ButtonPreset::FlatPreset);
explicit FlatButton(const QString &text,
QWidget *parent = nullptr,
ui::ButtonPreset preset = ui::ButtonPreset::FlatPreset);
FlatButton(const QString &text,
ui::Role role,
QWidget *parent = nullptr,
ui::ButtonPreset preset = ui::ButtonPreset::FlatPreset);
~FlatButton() override;
void applyPreset(ui::ButtonPreset preset);
void applyPreset(ui::ButtonPreset preset);
void setBackgroundColor(const QColor &color);
void setBackgroundMode(Qt::BGMode mode);
void setBaseOpacity(qreal opacity);
void setCheckable(bool value);
void setCornerRadius(qreal radius);
void setDisabledBackgroundColor(const QColor &color);
void setDisabledForegroundColor(const QColor &color);
void setFixedRippleRadius(qreal radius);
void setFontSize(qreal size);
void setForegroundColor(const QColor &color);
void setHasFixedRippleRadius(bool value);
void setIconPlacement(ui::ButtonIconPlacement placement);
void setOverlayColor(const QColor &color);
void setOverlayStyle(ui::OverlayStyle style);
void setRippleStyle(ui::RippleStyle style);
void setRole(ui::Role role);
void setBackgroundColor(const QColor &color);
void setBackgroundMode(Qt::BGMode mode);
void setBaseOpacity(qreal opacity);
void setCheckable(bool value);
void setCornerRadius(qreal radius);
void setDisabledBackgroundColor(const QColor &color);
void setDisabledForegroundColor(const QColor &color);
void setFixedRippleRadius(qreal radius);
void setFontSize(qreal size);
void setForegroundColor(const QColor &color);
void setHasFixedRippleRadius(bool value);
void setIconPlacement(ui::ButtonIconPlacement placement);
void setOverlayColor(const QColor &color);
void setOverlayStyle(ui::OverlayStyle style);
void setRippleStyle(ui::RippleStyle style);
void setRole(ui::Role role);
QColor foregroundColor() const;
QColor backgroundColor() const;
QColor overlayColor() const;
QColor disabledForegroundColor() const;
QColor disabledBackgroundColor() const;
QColor foregroundColor() const;
QColor backgroundColor() const;
QColor overlayColor() const;
QColor disabledForegroundColor() const;
QColor disabledBackgroundColor() const;
qreal fontSize() const;
qreal cornerRadius() const;
qreal baseOpacity() const;
qreal fontSize() const;
qreal cornerRadius() const;
qreal baseOpacity() const;
bool hasFixedRippleRadius() const;
bool hasFixedRippleRadius() const;
ui::Role role() const;
ui::OverlayStyle overlayStyle() const;
ui::RippleStyle rippleStyle() const;
ui::ButtonIconPlacement iconPlacement() const;
ui::Role role() const;
ui::OverlayStyle overlayStyle() const;
ui::RippleStyle rippleStyle() const;
ui::ButtonIconPlacement iconPlacement() const;
Qt::BGMode backgroundMode() const;
Qt::BGMode backgroundMode() const;
QSize sizeHint() const override;
QSize sizeHint() const override;
protected:
int IconPadding = 0;
int IconPadding = 0;
void checkStateSet() override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
void paintEvent(QPaintEvent *event) override;
void checkStateSet() override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
void paintEvent(QPaintEvent *event) override;
virtual void paintBackground(QPainter *painter);
virtual void paintForeground(QPainter *painter);
virtual void updateClipPath();
virtual void paintBackground(QPainter *painter);
virtual void paintForeground(QPainter *painter);
virtual void updateClipPath();
void init();
void init();
private:
RippleOverlay *ripple_overlay_;
FlatButtonStateMachine *state_machine_;
RippleOverlay *ripple_overlay_;
FlatButtonStateMachine *state_machine_;
ui::Role role_;
ui::RippleStyle ripple_style_;
ui::ButtonIconPlacement icon_placement_;
ui::OverlayStyle overlay_style_;
ui::Role role_;
ui::RippleStyle ripple_style_;
ui::ButtonIconPlacement icon_placement_;
ui::OverlayStyle overlay_style_;
Qt::BGMode bg_mode_;
Qt::BGMode bg_mode_;
QColor background_color_;
QColor foreground_color_;
QColor overlay_color_;
QColor disabled_color_;
QColor disabled_background_color_;
QColor background_color_;
QColor foreground_color_;
QColor overlay_color_;
QColor disabled_color_;
QColor disabled_background_color_;
qreal fixed_ripple_radius_;
qreal corner_radius_;
qreal base_opacity_;
qreal font_size_;
qreal fixed_ripple_radius_;
qreal corner_radius_;
qreal base_opacity_;
qreal font_size_;
bool use_fixed_ripple_radius_;
bool use_fixed_ripple_radius_;
};

View file

@ -10,91 +10,91 @@
FloatingButton::FloatingButton(const QIcon &icon, QWidget *parent)
: RaisedButton(parent)
{
setFixedSize(DIAMETER, DIAMETER);
setGeometry(buttonGeometry());
setFixedSize(DIAMETER, DIAMETER);
setGeometry(buttonGeometry());
if (parentWidget())
parentWidget()->installEventFilter(this);
if (parentWidget())
parentWidget()->installEventFilter(this);
setFixedRippleRadius(50);
setIcon(icon);
raise();
setFixedRippleRadius(50);
setIcon(icon);
raise();
}
QRect
FloatingButton::buttonGeometry() const
{
QWidget *parent = parentWidget();
QWidget *parent = parentWidget();
if (!parent)
return QRect();
if (!parent)
return QRect();
return QRect(parent->width() - (OFFSET_X + DIAMETER),
parent->height() - (OFFSET_Y + DIAMETER),
DIAMETER,
DIAMETER);
return QRect(parent->width() - (OFFSET_X + DIAMETER),
parent->height() - (OFFSET_Y + DIAMETER),
DIAMETER,
DIAMETER);
}
bool
FloatingButton::event(QEvent *event)
{
if (!parent())
return RaisedButton::event(event);
switch (event->type()) {
case QEvent::ParentChange: {
parent()->installEventFilter(this);
setGeometry(buttonGeometry());
break;
}
case QEvent::ParentAboutToChange: {
parent()->installEventFilter(this);
break;
}
default:
break;
}
if (!parent())
return RaisedButton::event(event);
switch (event->type()) {
case QEvent::ParentChange: {
parent()->installEventFilter(this);
setGeometry(buttonGeometry());
break;
}
case QEvent::ParentAboutToChange: {
parent()->installEventFilter(this);
break;
}
default:
break;
}
return RaisedButton::event(event);
}
bool
FloatingButton::eventFilter(QObject *obj, QEvent *event)
{
const QEvent::Type type = event->type();
const QEvent::Type type = event->type();
if (QEvent::Move == type || QEvent::Resize == type)
setGeometry(buttonGeometry());
if (QEvent::Move == type || QEvent::Resize == type)
setGeometry(buttonGeometry());
return RaisedButton::eventFilter(obj, event);
return RaisedButton::eventFilter(obj, event);
}
void
FloatingButton::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
Q_UNUSED(event);
QRect square = QRect(0, 0, DIAMETER, DIAMETER);
square.moveCenter(rect().center());
QRect square = QRect(0, 0, DIAMETER, DIAMETER);
square.moveCenter(rect().center());
QPainter p(this);
p.setRenderHints(QPainter::Antialiasing);
QPainter p(this);
p.setRenderHints(QPainter::Antialiasing);
QBrush brush;
brush.setStyle(Qt::SolidPattern);
brush.setColor(backgroundColor());
QBrush brush;
brush.setStyle(Qt::SolidPattern);
brush.setColor(backgroundColor());
p.setBrush(brush);
p.setPen(Qt::NoPen);
p.drawEllipse(square);
p.setBrush(brush);
p.setPen(Qt::NoPen);
p.drawEllipse(square);
QRect iconGeometry(0, 0, ICON_SIZE, ICON_SIZE);
iconGeometry.moveCenter(square.center());
QRect iconGeometry(0, 0, ICON_SIZE, ICON_SIZE);
iconGeometry.moveCenter(square.center());
QPixmap pixmap = icon().pixmap(QSize(ICON_SIZE, ICON_SIZE));
QPainter icon(&pixmap);
icon.setCompositionMode(QPainter::CompositionMode_SourceIn);
icon.fillRect(pixmap.rect(), foregroundColor());
QPixmap pixmap = icon().pixmap(QSize(ICON_SIZE, ICON_SIZE));
QPainter icon(&pixmap);
icon.setCompositionMode(QPainter::CompositionMode_SourceIn);
icon.fillRect(pixmap.rect(), foregroundColor());
p.drawPixmap(iconGeometry, pixmap);
p.drawPixmap(iconGeometry, pixmap);
}

View file

@ -14,17 +14,17 @@ constexpr int OFFSET_Y = 20;
class FloatingButton : public RaisedButton
{
Q_OBJECT
Q_OBJECT
public:
FloatingButton(const QIcon &icon, QWidget *parent = nullptr);
FloatingButton(const QIcon &icon, QWidget *parent = nullptr);
QSize sizeHint() const override { return QSize(DIAMETER, DIAMETER); };
QRect buttonGeometry() const;
QSize sizeHint() const override { return QSize(DIAMETER, DIAMETER); };
QRect buttonGeometry() const;
protected:
bool event(QEvent *event) override;
bool eventFilter(QObject *obj, QEvent *event) override;
bool event(QEvent *event) override;
bool eventFilter(QObject *obj, QEvent *event) override;
void paintEvent(QPaintEvent *event) override;
void paintEvent(QPaintEvent *event) override;
};

View file

@ -19,60 +19,60 @@ constexpr int HMargin = 20;
InfoMessage::InfoMessage(QWidget *parent)
: QWidget{parent}
{
initFont();
initFont();
}
InfoMessage::InfoMessage(QString msg, QWidget *parent)
: QWidget{parent}
, msg_{msg}
{
initFont();
initFont();
QFontMetrics fm{font()};
width_ = fm.horizontalAdvance(msg_) + HPadding * 2;
height_ = fm.ascent() + 2 * VPadding;
QFontMetrics fm{font()};
width_ = fm.horizontalAdvance(msg_) + HPadding * 2;
height_ = fm.ascent() + 2 * VPadding;
setFixedHeight(height_ + 2 * HMargin);
setFixedHeight(height_ + 2 * HMargin);
}
void
InfoMessage::paintEvent(QPaintEvent *)
{
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
p.setFont(font());
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
p.setFont(font());
// Center the box horizontally & vertically.
auto textRegion = QRectF(width() / 2 - width_ / 2, HMargin, width_, height_);
// Center the box horizontally & vertically.
auto textRegion = QRectF(width() / 2 - width_ / 2, HMargin, width_, height_);
QPainterPath ppath;
ppath.addRoundedRect(textRegion, height_ / 2, height_ / 2);
QPainterPath ppath;
ppath.addRoundedRect(textRegion, height_ / 2, height_ / 2);
p.setPen(Qt::NoPen);
p.fillPath(ppath, boxColor());
p.drawPath(ppath);
p.setPen(Qt::NoPen);
p.fillPath(ppath, boxColor());
p.drawPath(ppath);
p.setPen(QPen(textColor()));
p.drawText(textRegion, Qt::AlignCenter, msg_);
p.setPen(QPen(textColor()));
p.drawText(textRegion, Qt::AlignCenter, msg_);
}
DateSeparator::DateSeparator(QDateTime datetime, QWidget *parent)
: InfoMessage{parent}
{
auto now = QDateTime::currentDateTime();
auto now = QDateTime::currentDateTime();
QString fmt = QLocale::system().dateFormat(QLocale::LongFormat);
QString fmt = QLocale::system().dateFormat(QLocale::LongFormat);
if (now.date().year() == datetime.date().year()) {
QRegularExpression rx("[^a-zA-Z]*y+[^a-zA-Z]*");
fmt = fmt.remove(rx);
}
if (now.date().year() == datetime.date().year()) {
QRegularExpression rx("[^a-zA-Z]*y+[^a-zA-Z]*");
fmt = fmt.remove(rx);
}
msg_ = datetime.date().toString(fmt);
msg_ = datetime.date().toString(fmt);
QFontMetrics fm{font()};
width_ = fm.horizontalAdvance(msg_) + HPadding * 2;
height_ = fm.ascent() + 2 * VPadding;
QFontMetrics fm{font()};
width_ = fm.horizontalAdvance(msg_) + HPadding * 2;
height_ = fm.ascent() + 2 * VPadding;
setFixedHeight(height_ + 2 * HMargin);
setFixedHeight(height_ + 2 * HMargin);
}

View file

@ -10,47 +10,47 @@
class InfoMessage : public QWidget
{
Q_OBJECT
Q_OBJECT
Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor)
Q_PROPERTY(QColor boxColor WRITE setBoxColor READ boxColor)
Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor)
Q_PROPERTY(QColor boxColor WRITE setBoxColor READ boxColor)
public:
explicit InfoMessage(QWidget *parent = nullptr);
InfoMessage(QString msg, QWidget *parent = nullptr);
explicit InfoMessage(QWidget *parent = nullptr);
InfoMessage(QString msg, QWidget *parent = nullptr);
void setTextColor(QColor color) { textColor_ = color; }
void setBoxColor(QColor color) { boxColor_ = color; }
void saveDatetime(QDateTime datetime) { datetime_ = datetime; }
void setTextColor(QColor color) { textColor_ = color; }
void setBoxColor(QColor color) { boxColor_ = color; }
void saveDatetime(QDateTime datetime) { datetime_ = datetime; }
QColor textColor() const { return textColor_; }
QColor boxColor() const { return boxColor_; }
QDateTime datetime() const { return datetime_; }
QColor textColor() const { return textColor_; }
QColor boxColor() const { return boxColor_; }
QDateTime datetime() const { return datetime_; }
protected:
void paintEvent(QPaintEvent *event) override;
void initFont()
{
QFont f;
f.setWeight(QFont::Medium);
setFont(f);
}
void paintEvent(QPaintEvent *event) override;
void initFont()
{
QFont f;
f.setWeight(QFont::Medium);
setFont(f);
}
int width_;
int height_;
int width_;
int height_;
QString msg_;
QString msg_;
QDateTime datetime_;
QDateTime datetime_;
QColor textColor_ = QColor("black");
QColor boxColor_ = QColor("white");
QColor textColor_ = QColor("black");
QColor boxColor_ = QColor("white");
};
class DateSeparator : public InfoMessage
{
Q_OBJECT
Q_OBJECT
public:
DateSeparator(QDateTime datetime, QWidget *parent = nullptr);
DateSeparator(QDateTime datetime, QWidget *parent = nullptr);
};

View file

@ -17,16 +17,16 @@ Label::Label(const QString &text, QWidget *parent, Qt::WindowFlags f)
void
Label::mousePressEvent(QMouseEvent *e)
{
pressPosition_ = e->pos();
emit pressed(e);
QLabel::mousePressEvent(e);
pressPosition_ = e->pos();
emit pressed(e);
QLabel::mousePressEvent(e);
}
void
Label::mouseReleaseEvent(QMouseEvent *e)
{
emit released(e);
if (pressPosition_ == e->pos())
emit clicked(e);
QLabel::mouseReleaseEvent(e);
emit released(e);
if (pressPosition_ == e->pos())
emit clicked(e);
QLabel::mouseReleaseEvent(e);
}

View file

@ -8,22 +8,22 @@
class Label : public QLabel
{
Q_OBJECT
Q_OBJECT
public:
explicit Label(QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
explicit Label(const QString &text,
QWidget *parent = Q_NULLPTR,
Qt::WindowFlags f = Qt::WindowFlags());
explicit Label(QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
explicit Label(const QString &text,
QWidget *parent = Q_NULLPTR,
Qt::WindowFlags f = Qt::WindowFlags());
signals:
void clicked(QMouseEvent *e);
void pressed(QMouseEvent *e);
void released(QMouseEvent *e);
void clicked(QMouseEvent *e);
void pressed(QMouseEvent *e);
void released(QMouseEvent *e);
protected:
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
QPoint pressPosition_;
QPoint pressPosition_;
};

View file

@ -14,70 +14,70 @@ LoadingIndicator::LoadingIndicator(QWidget *parent)
, angle_(0)
, color_(Qt::black)
{
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
setFocusPolicy(Qt::NoFocus);
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
setFocusPolicy(Qt::NoFocus);
timer_ = new QTimer(this);
connect(timer_, SIGNAL(timeout()), this, SLOT(onTimeout()));
timer_ = new QTimer(this);
connect(timer_, SIGNAL(timeout()), this, SLOT(onTimeout()));
}
void
LoadingIndicator::paintEvent(QPaintEvent *e)
{
Q_UNUSED(e)
Q_UNUSED(e)
if (!timer_->isActive())
return;
if (!timer_->isActive())
return;
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
int width = qMin(this->width(), this->height());
int width = qMin(this->width(), this->height());
int outerRadius = (width - 4) * 0.5f;
int innerRadius = outerRadius * 0.78f;
int outerRadius = (width - 4) * 0.5f;
int innerRadius = outerRadius * 0.78f;
int capsuleRadius = (outerRadius - innerRadius) / 2;
int capsuleRadius = (outerRadius - innerRadius) / 2;
for (int i = 0; i < 8; ++i) {
QColor color = color_;
for (int i = 0; i < 8; ++i) {
QColor color = color_;
color.setAlphaF(1.0f - (i / 8.0f));
color.setAlphaF(1.0f - (i / 8.0f));
painter.setPen(Qt::NoPen);
painter.setBrush(color);
painter.setPen(Qt::NoPen);
painter.setBrush(color);
qreal radius = capsuleRadius * (1.0f - (i / 16.0f));
qreal radius = capsuleRadius * (1.0f - (i / 16.0f));
painter.save();
painter.save();
painter.translate(rect().center());
painter.rotate(angle_ - i * 45.0f);
painter.translate(rect().center());
painter.rotate(angle_ - i * 45.0f);
QPointF center = QPointF(-capsuleRadius, -innerRadius);
painter.drawEllipse(center, radius * 2, radius * 2);
QPointF center = QPointF(-capsuleRadius, -innerRadius);
painter.drawEllipse(center, radius * 2, radius * 2);
painter.restore();
}
painter.restore();
}
}
void
LoadingIndicator::start()
{
timer_->start(interval_);
show();
timer_->start(interval_);
show();
}
void
LoadingIndicator::stop()
{
timer_->stop();
hide();
timer_->stop();
hide();
}
void
LoadingIndicator::onTimeout()
{
angle_ = (angle_ + 45) % 360;
repaint();
angle_ = (angle_ + 45) % 360;
repaint();
}

View file

@ -12,30 +12,30 @@ class QTimer;
class QPaintEvent;
class LoadingIndicator : public QWidget
{
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor)
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor)
public:
LoadingIndicator(QWidget *parent = nullptr);
LoadingIndicator(QWidget *parent = nullptr);
void paintEvent(QPaintEvent *e) override;
void paintEvent(QPaintEvent *e) override;
void start();
void stop();
void start();
void stop();
QColor color() { return color_; }
void setColor(QColor color) { color_ = color; }
QColor color() { return color_; }
void setColor(QColor color) { color_ = color; }
int interval() { return interval_; }
void setInterval(int interval) { interval_ = interval; }
int interval() { return interval_; }
void setInterval(int interval) { interval_ = interval; }
private slots:
void onTimeout();
void onTimeout();
private:
int interval_;
int angle_;
int interval_;
int angle_;
QColor color_;
QTimer *timer_;
QColor color_;
QTimer *timer_;
};

View file

@ -10,16 +10,16 @@
class Menu : public QMenu
{
Q_OBJECT
Q_OBJECT
public:
Menu(QWidget *parent = nullptr)
: QMenu(parent){};
Menu(QWidget *parent = nullptr)
: QMenu(parent){};
protected:
void leaveEvent(QEvent *e) override
{
hide();
void leaveEvent(QEvent *e) override
{
hide();
QMenu::leaveEvent(e);
}
QMenu::leaveEvent(e);
}
};

View file

@ -19,160 +19,157 @@
void
MxcAnimatedImage::startDownload()
{
if (!room_)
return;
if (eventId_.isEmpty())
return;
if (!room_)
return;
if (eventId_.isEmpty())
return;
auto event = room_->eventById(eventId_);
if (!event) {
nhlog::ui()->error("Failed to load media for event {}, event not found.",
eventId_.toStdString());
return;
auto event = room_->eventById(eventId_);
if (!event) {
nhlog::ui()->error("Failed to load media for event {}, event not found.",
eventId_.toStdString());
return;
}
QByteArray mimeType = QString::fromStdString(mtx::accessors::mimetype(*event)).toUtf8();
animatable_ = QMovie::supportedFormats().contains(mimeType.split('/').back());
animatableChanged();
if (!animatable_)
return;
QString mxcUrl = QString::fromStdString(mtx::accessors::url(*event));
QString originalFilename = QString::fromStdString(mtx::accessors::filename(*event));
auto encryptionInfo = mtx::accessors::file(*event);
// If the message is a link to a non mxcUrl, don't download it
if (!mxcUrl.startsWith("mxc://")) {
return;
}
QString suffix = QMimeDatabase().mimeTypeForName(mimeType).preferredSuffix();
const auto url = mxcUrl.toStdString();
const auto name = QString(mxcUrl).remove("mxc://");
QFileInfo filename(QString("%1/media_cache/media/%2.%3")
.arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation))
.arg(name)
.arg(suffix));
if (QDir::cleanPath(name) != name) {
nhlog::net()->warn("mxcUrl '{}' is not safe, not downloading file", url);
return;
}
QDir().mkpath(filename.path());
QPointer<MxcAnimatedImage> self = this;
auto processBuffer = [this, mimeType, encryptionInfo, self](QIODevice &device) {
if (!self)
return;
if (buffer.isOpen()) {
movie.stop();
movie.setDevice(nullptr);
buffer.close();
}
QByteArray mimeType = QString::fromStdString(mtx::accessors::mimetype(*event)).toUtf8();
animatable_ = QMovie::supportedFormats().contains(mimeType.split('/').back());
animatableChanged();
if (!animatable_)
return;
QString mxcUrl = QString::fromStdString(mtx::accessors::url(*event));
QString originalFilename = QString::fromStdString(mtx::accessors::filename(*event));
auto encryptionInfo = mtx::accessors::file(*event);
// If the message is a link to a non mxcUrl, don't download it
if (!mxcUrl.startsWith("mxc://")) {
return;
if (encryptionInfo) {
QByteArray ba = device.readAll();
std::string temp(ba.constData(), ba.size());
temp = mtx::crypto::to_string(mtx::crypto::decrypt_file(temp, encryptionInfo.value()));
buffer.setData(temp.data(), temp.size());
} else {
buffer.setData(device.readAll());
}
buffer.open(QIODevice::ReadOnly);
buffer.reset();
QString suffix = QMimeDatabase().mimeTypeForName(mimeType).preferredSuffix();
QTimer::singleShot(0, this, [this, mimeType] {
nhlog::ui()->info(
"Playing movie with size: {}, {}", buffer.bytesAvailable(), buffer.isOpen());
movie.setFormat(mimeType);
movie.setDevice(&buffer);
if (play_)
movie.start();
else
movie.jumpToFrame(0);
emit loadedChanged();
update();
});
};
const auto url = mxcUrl.toStdString();
const auto name = QString(mxcUrl).remove("mxc://");
QFileInfo filename(QString("%1/media_cache/media/%2.%3")
.arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation))
.arg(name)
.arg(suffix));
if (QDir::cleanPath(name) != name) {
nhlog::net()->warn("mxcUrl '{}' is not safe, not downloading file", url);
return;
if (filename.isReadable()) {
QFile f(filename.filePath());
if (f.open(QIODevice::ReadOnly)) {
processBuffer(f);
return;
}
}
QDir().mkpath(filename.path());
http::client()->download(url,
[filename, url, processBuffer](const std::string &data,
const std::string &,
const std::string &,
mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to retrieve media {}: {} {}",
url,
err->matrix_error.error,
static_cast<int>(err->status_code));
return;
}
QPointer<MxcAnimatedImage> self = this;
try {
QFile file(filename.filePath());
auto processBuffer = [this, mimeType, encryptionInfo, self](QIODevice &device) {
if (!self)
return;
if (!file.open(QIODevice::WriteOnly))
return;
if (buffer.isOpen()) {
movie.stop();
movie.setDevice(nullptr);
buffer.close();
}
QByteArray ba(data.data(), (int)data.size());
file.write(ba);
file.close();
if (encryptionInfo) {
QByteArray ba = device.readAll();
std::string temp(ba.constData(), ba.size());
temp = mtx::crypto::to_string(
mtx::crypto::decrypt_file(temp, encryptionInfo.value()));
buffer.setData(temp.data(), temp.size());
} else {
buffer.setData(device.readAll());
}
buffer.open(QIODevice::ReadOnly);
buffer.reset();
QTimer::singleShot(0, this, [this, mimeType] {
nhlog::ui()->info("Playing movie with size: {}, {}",
buffer.bytesAvailable(),
buffer.isOpen());
movie.setFormat(mimeType);
movie.setDevice(&buffer);
if (play_)
movie.start();
else
movie.jumpToFrame(0);
emit loadedChanged();
update();
});
};
if (filename.isReadable()) {
QFile f(filename.filePath());
if (f.open(QIODevice::ReadOnly)) {
processBuffer(f);
return;
}
}
http::client()->download(
url,
[filename, url, processBuffer](const std::string &data,
const std::string &,
const std::string &,
mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to retrieve media {}: {} {}",
url,
err->matrix_error.error,
static_cast<int>(err->status_code));
return;
}
try {
QFile file(filename.filePath());
if (!file.open(QIODevice::WriteOnly))
return;
QByteArray ba(data.data(), (int)data.size());
file.write(ba);
file.close();
QBuffer buf(&ba);
buf.open(QBuffer::ReadOnly);
processBuffer(buf);
} catch (const std::exception &e) {
nhlog::ui()->warn("Error while saving file to: {}", e.what());
}
});
QBuffer buf(&ba);
buf.open(QBuffer::ReadOnly);
processBuffer(buf);
} catch (const std::exception &e) {
nhlog::ui()->warn("Error while saving file to: {}", e.what());
}
});
}
QSGNode *
MxcAnimatedImage::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
{
if (!imageDirty)
return oldNode;
if (!imageDirty)
return oldNode;
imageDirty = false;
QSGImageNode *n = static_cast<QSGImageNode *>(oldNode);
if (!n) {
n = window()->createImageNode();
n->setOwnsTexture(true);
// n->setFlags(QSGNode::OwnedByParent | QSGNode::OwnsGeometry |
// GSGNode::OwnsMaterial);
n->setFlags(QSGNode::OwnedByParent);
}
imageDirty = false;
QSGImageNode *n = static_cast<QSGImageNode *>(oldNode);
if (!n) {
n = window()->createImageNode();
n->setOwnsTexture(true);
// n->setFlags(QSGNode::OwnedByParent | QSGNode::OwnsGeometry |
// GSGNode::OwnsMaterial);
n->setFlags(QSGNode::OwnedByParent);
}
// n->setTexture(nullptr);
auto img = movie.currentImage();
if (!img.isNull())
n->setTexture(window()->createTextureFromImage(img));
else {
delete n;
return nullptr;
}
// n->setTexture(nullptr);
auto img = movie.currentImage();
if (!img.isNull())
n->setTexture(window()->createTextureFromImage(img));
else {
delete n;
return nullptr;
}
n->setSourceRect(img.rect());
n->setRect(QRect(0, 0, width(), height()));
n->setFiltering(QSGTexture::Linear);
n->setMipmapFiltering(QSGTexture::Linear);
n->setSourceRect(img.rect());
n->setRect(QRect(0, 0, width(), height()));
n->setFiltering(QSGTexture::Linear);
n->setMipmapFiltering(QSGTexture::Linear);
return n;
return n;
}

View file

@ -14,78 +14,78 @@ class TimelineModel;
// This is an AnimatedImage, that can draw encrypted images
class MxcAnimatedImage : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(TimelineModel *roomm READ room WRITE setRoom NOTIFY roomChanged REQUIRED)
Q_PROPERTY(QString eventId READ eventId WRITE setEventId NOTIFY eventIdChanged)
Q_PROPERTY(bool animatable READ animatable NOTIFY animatableChanged)
Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged)
Q_PROPERTY(bool play READ play WRITE setPlay NOTIFY playChanged)
Q_OBJECT
Q_PROPERTY(TimelineModel *roomm READ room WRITE setRoom NOTIFY roomChanged REQUIRED)
Q_PROPERTY(QString eventId READ eventId WRITE setEventId NOTIFY eventIdChanged)
Q_PROPERTY(bool animatable READ animatable NOTIFY animatableChanged)
Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged)
Q_PROPERTY(bool play READ play WRITE setPlay NOTIFY playChanged)
public:
MxcAnimatedImage(QQuickItem *parent = nullptr)
: QQuickItem(parent)
{
connect(this, &MxcAnimatedImage::eventIdChanged, &MxcAnimatedImage::startDownload);
connect(this, &MxcAnimatedImage::roomChanged, &MxcAnimatedImage::startDownload);
connect(&movie, &QMovie::frameChanged, this, &MxcAnimatedImage::newFrame);
setFlag(QQuickItem::ItemHasContents);
// setAcceptHoverEvents(true);
}
MxcAnimatedImage(QQuickItem *parent = nullptr)
: QQuickItem(parent)
{
connect(this, &MxcAnimatedImage::eventIdChanged, &MxcAnimatedImage::startDownload);
connect(this, &MxcAnimatedImage::roomChanged, &MxcAnimatedImage::startDownload);
connect(&movie, &QMovie::frameChanged, this, &MxcAnimatedImage::newFrame);
setFlag(QQuickItem::ItemHasContents);
// setAcceptHoverEvents(true);
}
bool animatable() const { return animatable_; }
bool loaded() const { return buffer.size() > 0; }
bool play() const { return play_; }
QString eventId() const { return eventId_; }
TimelineModel *room() const { return room_; }
void setEventId(QString newEventId)
{
if (eventId_ != newEventId) {
eventId_ = newEventId;
emit eventIdChanged();
}
bool animatable() const { return animatable_; }
bool loaded() const { return buffer.size() > 0; }
bool play() const { return play_; }
QString eventId() const { return eventId_; }
TimelineModel *room() const { return room_; }
void setEventId(QString newEventId)
{
if (eventId_ != newEventId) {
eventId_ = newEventId;
emit eventIdChanged();
}
void setRoom(TimelineModel *room)
{
if (room_ != room) {
room_ = room;
emit roomChanged();
}
}
void setRoom(TimelineModel *room)
{
if (room_ != room) {
room_ = room;
emit roomChanged();
}
void setPlay(bool newPlay)
{
if (play_ != newPlay) {
play_ = newPlay;
movie.setPaused(!play_);
emit playChanged();
}
}
void setPlay(bool newPlay)
{
if (play_ != newPlay) {
play_ = newPlay;
movie.setPaused(!play_);
emit playChanged();
}
}
QSGNode *updatePaintNode(QSGNode *oldNode,
QQuickItem::UpdatePaintNodeData *updatePaintNodeData) override;
QSGNode *updatePaintNode(QSGNode *oldNode,
QQuickItem::UpdatePaintNodeData *updatePaintNodeData) override;
signals:
void roomChanged();
void eventIdChanged();
void animatableChanged();
void loadedChanged();
void playChanged();
void roomChanged();
void eventIdChanged();
void animatableChanged();
void loadedChanged();
void playChanged();
private slots:
void startDownload();
void newFrame(int frame)
{
currentFrame = frame;
imageDirty = true;
update();
}
void startDownload();
void newFrame(int frame)
{
currentFrame = frame;
imageDirty = true;
update();
}
private:
TimelineModel *room_ = nullptr;
QString eventId_;
QString filename_;
bool animatable_ = false;
QBuffer buffer;
QMovie movie;
int currentFrame = 0;
bool imageDirty = true;
bool play_ = true;
TimelineModel *room_ = nullptr;
QString eventId_;
QString filename_;
bool animatable_ = false;
QBuffer buffer;
QMovie movie;
int currentFrame = 0;
bool imageDirty = true;
bool play_ = true;
};

View file

@ -21,122 +21,119 @@
void
MxcMediaProxy::setVideoSurface(QAbstractVideoSurface *surface)
{
qDebug() << "Changing surface";
m_surface = surface;
setVideoOutput(m_surface);
qDebug() << "Changing surface";
m_surface = surface;
setVideoOutput(m_surface);
}
QAbstractVideoSurface *
MxcMediaProxy::getVideoSurface()
{
return m_surface;
return m_surface;
}
void
MxcMediaProxy::startDownload()
{
if (!room_)
return;
if (eventId_.isEmpty())
return;
if (!room_)
return;
if (eventId_.isEmpty())
return;
auto event = room_->eventById(eventId_);
if (!event) {
nhlog::ui()->error("Failed to load media for event {}, event not found.",
eventId_.toStdString());
return;
auto event = room_->eventById(eventId_);
if (!event) {
nhlog::ui()->error("Failed to load media for event {}, event not found.",
eventId_.toStdString());
return;
}
QString mxcUrl = QString::fromStdString(mtx::accessors::url(*event));
QString originalFilename = QString::fromStdString(mtx::accessors::filename(*event));
QString mimeType = QString::fromStdString(mtx::accessors::mimetype(*event));
auto encryptionInfo = mtx::accessors::file(*event);
// If the message is a link to a non mxcUrl, don't download it
if (!mxcUrl.startsWith("mxc://")) {
return;
}
QString suffix = QMimeDatabase().mimeTypeForName(mimeType).preferredSuffix();
const auto url = mxcUrl.toStdString();
const auto name = QString(mxcUrl).remove("mxc://");
QFileInfo filename(QString("%1/media_cache/media/%2.%3")
.arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation))
.arg(name)
.arg(suffix));
if (QDir::cleanPath(name) != name) {
nhlog::net()->warn("mxcUrl '{}' is not safe, not downloading file", url);
return;
}
QDir().mkpath(filename.path());
QPointer<MxcMediaProxy> self = this;
auto processBuffer = [this, encryptionInfo, filename, self](QIODevice &device) {
if (!self)
return;
if (encryptionInfo) {
QByteArray ba = device.readAll();
std::string temp(ba.constData(), ba.size());
temp = mtx::crypto::to_string(mtx::crypto::decrypt_file(temp, encryptionInfo.value()));
buffer.setData(temp.data(), temp.size());
} else {
buffer.setData(device.readAll());
}
buffer.open(QIODevice::ReadOnly);
buffer.reset();
QString mxcUrl = QString::fromStdString(mtx::accessors::url(*event));
QString originalFilename = QString::fromStdString(mtx::accessors::filename(*event));
QString mimeType = QString::fromStdString(mtx::accessors::mimetype(*event));
QTimer::singleShot(0, this, [this, filename] {
nhlog::ui()->info(
"Playing buffer with size: {}, {}", buffer.bytesAvailable(), buffer.isOpen());
this->setMedia(QMediaContent(filename.fileName()), &buffer);
emit loadedChanged();
});
};
auto encryptionInfo = mtx::accessors::file(*event);
// If the message is a link to a non mxcUrl, don't download it
if (!mxcUrl.startsWith("mxc://")) {
return;
if (filename.isReadable()) {
QFile f(filename.filePath());
if (f.open(QIODevice::ReadOnly)) {
processBuffer(f);
return;
}
}
QString suffix = QMimeDatabase().mimeTypeForName(mimeType).preferredSuffix();
http::client()->download(url,
[filename, url, processBuffer](const std::string &data,
const std::string &,
const std::string &,
mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to retrieve media {}: {} {}",
url,
err->matrix_error.error,
static_cast<int>(err->status_code));
return;
}
const auto url = mxcUrl.toStdString();
const auto name = QString(mxcUrl).remove("mxc://");
QFileInfo filename(QString("%1/media_cache/media/%2.%3")
.arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation))
.arg(name)
.arg(suffix));
if (QDir::cleanPath(name) != name) {
nhlog::net()->warn("mxcUrl '{}' is not safe, not downloading file", url);
return;
}
try {
QFile file(filename.filePath());
QDir().mkpath(filename.path());
if (!file.open(QIODevice::WriteOnly))
return;
QPointer<MxcMediaProxy> self = this;
QByteArray ba(data.data(), (int)data.size());
file.write(ba);
file.close();
auto processBuffer = [this, encryptionInfo, filename, self](QIODevice &device) {
if (!self)
return;
if (encryptionInfo) {
QByteArray ba = device.readAll();
std::string temp(ba.constData(), ba.size());
temp = mtx::crypto::to_string(
mtx::crypto::decrypt_file(temp, encryptionInfo.value()));
buffer.setData(temp.data(), temp.size());
} else {
buffer.setData(device.readAll());
}
buffer.open(QIODevice::ReadOnly);
buffer.reset();
QTimer::singleShot(0, this, [this, filename] {
nhlog::ui()->info("Playing buffer with size: {}, {}",
buffer.bytesAvailable(),
buffer.isOpen());
this->setMedia(QMediaContent(filename.fileName()), &buffer);
emit loadedChanged();
});
};
if (filename.isReadable()) {
QFile f(filename.filePath());
if (f.open(QIODevice::ReadOnly)) {
processBuffer(f);
return;
}
}
http::client()->download(
url,
[filename, url, processBuffer](const std::string &data,
const std::string &,
const std::string &,
mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to retrieve media {}: {} {}",
url,
err->matrix_error.error,
static_cast<int>(err->status_code));
return;
}
try {
QFile file(filename.filePath());
if (!file.open(QIODevice::WriteOnly))
return;
QByteArray ba(data.data(), (int)data.size());
file.write(ba);
file.close();
QBuffer buf(&ba);
buf.open(QBuffer::ReadOnly);
processBuffer(buf);
} catch (const std::exception &e) {
nhlog::ui()->warn("Error while saving file to: {}", e.what());
}
});
QBuffer buf(&ba);
buf.open(QBuffer::ReadOnly);
processBuffer(buf);
} catch (const std::exception &e) {
nhlog::ui()->warn("Error while saving file to: {}", e.what());
}
});
}

View file

@ -20,61 +20,58 @@ class TimelineModel;
// need the videoSurface property, so that part is really easy!
class MxcMediaProxy : public QMediaPlayer
{
Q_OBJECT
Q_PROPERTY(TimelineModel *roomm READ room WRITE setRoom NOTIFY roomChanged REQUIRED)
Q_PROPERTY(QString eventId READ eventId WRITE setEventId NOTIFY eventIdChanged)
Q_PROPERTY(QAbstractVideoSurface *videoSurface READ getVideoSurface WRITE setVideoSurface)
Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged)
Q_OBJECT
Q_PROPERTY(TimelineModel *roomm READ room WRITE setRoom NOTIFY roomChanged REQUIRED)
Q_PROPERTY(QString eventId READ eventId WRITE setEventId NOTIFY eventIdChanged)
Q_PROPERTY(QAbstractVideoSurface *videoSurface READ getVideoSurface WRITE setVideoSurface)
Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged)
public:
MxcMediaProxy(QObject *parent = nullptr)
: QMediaPlayer(parent)
{
connect(this, &MxcMediaProxy::eventIdChanged, &MxcMediaProxy::startDownload);
connect(this, &MxcMediaProxy::roomChanged, &MxcMediaProxy::startDownload);
connect(this,
qOverload<QMediaPlayer::Error>(&MxcMediaProxy::error),
[this](QMediaPlayer::Error error) {
nhlog::ui()->info("Media player error {} and errorStr {}",
error,
this->errorString().toStdString());
});
connect(this,
&MxcMediaProxy::mediaStatusChanged,
[this](QMediaPlayer::MediaStatus status) {
nhlog::ui()->info(
"Media player status {} and error {}", status, this->error());
});
}
MxcMediaProxy(QObject *parent = nullptr)
: QMediaPlayer(parent)
{
connect(this, &MxcMediaProxy::eventIdChanged, &MxcMediaProxy::startDownload);
connect(this, &MxcMediaProxy::roomChanged, &MxcMediaProxy::startDownload);
connect(this,
qOverload<QMediaPlayer::Error>(&MxcMediaProxy::error),
[this](QMediaPlayer::Error error) {
nhlog::ui()->info("Media player error {} and errorStr {}",
error,
this->errorString().toStdString());
});
connect(this, &MxcMediaProxy::mediaStatusChanged, [this](QMediaPlayer::MediaStatus status) {
nhlog::ui()->info("Media player status {} and error {}", status, this->error());
});
}
bool loaded() const { return buffer.size() > 0; }
QString eventId() const { return eventId_; }
TimelineModel *room() const { return room_; }
void setEventId(QString newEventId)
{
eventId_ = newEventId;
emit eventIdChanged();
}
void setRoom(TimelineModel *room)
{
room_ = room;
emit roomChanged();
}
void setVideoSurface(QAbstractVideoSurface *surface);
QAbstractVideoSurface *getVideoSurface();
bool loaded() const { return buffer.size() > 0; }
QString eventId() const { return eventId_; }
TimelineModel *room() const { return room_; }
void setEventId(QString newEventId)
{
eventId_ = newEventId;
emit eventIdChanged();
}
void setRoom(TimelineModel *room)
{
room_ = room;
emit roomChanged();
}
void setVideoSurface(QAbstractVideoSurface *surface);
QAbstractVideoSurface *getVideoSurface();
signals:
void roomChanged();
void eventIdChanged();
void loadedChanged();
void newBuffer(QMediaContent, QIODevice *buf);
void roomChanged();
void eventIdChanged();
void loadedChanged();
void newBuffer(QMediaContent, QIODevice *buf);
private slots:
void startDownload();
void startDownload();
private:
TimelineModel *room_ = nullptr;
QString eventId_;
QString filename_;
QBuffer buffer;
QAbstractVideoSurface *m_surface = nullptr;
TimelineModel *room_ = nullptr;
QString eventId_;
QString filename_;
QBuffer buffer;
QAbstractVideoSurface *m_surface = nullptr;
};

View file

@ -14,16 +14,16 @@ NhekoCursorShape::NhekoCursorShape(QQuickItem *parent)
Qt::CursorShape
NhekoCursorShape::cursorShape() const
{
return cursor().shape();
return cursor().shape();
}
void
NhekoCursorShape::setCursorShape(Qt::CursorShape cursorShape)
{
if (currentShape_ == cursorShape)
return;
if (currentShape_ == cursorShape)
return;
currentShape_ = cursorShape;
setCursor(cursorShape);
emit cursorShapeChanged();
currentShape_ = cursorShape;
setCursor(cursorShape);
emit cursorShapeChanged();
}

View file

@ -11,20 +11,20 @@
class NhekoCursorShape : public QQuickItem
{
Q_OBJECT
Q_OBJECT
Q_PROPERTY(Qt::CursorShape cursorShape READ cursorShape WRITE setCursorShape NOTIFY
cursorShapeChanged)
Q_PROPERTY(
Qt::CursorShape cursorShape READ cursorShape WRITE setCursorShape NOTIFY cursorShapeChanged)
public:
explicit NhekoCursorShape(QQuickItem *parent = 0);
explicit NhekoCursorShape(QQuickItem *parent = 0);
private:
Qt::CursorShape cursorShape() const;
void setCursorShape(Qt::CursorShape cursorShape);
Qt::CursorShape cursorShape() const;
void setCursorShape(Qt::CursorShape cursorShape);
Qt::CursorShape currentShape_;
Qt::CursorShape currentShape_;
signals:
void cursorShapeChanged();
void cursorShapeChanged();
};

View file

@ -16,28 +16,28 @@
NhekoDropArea::NhekoDropArea(QQuickItem *parent)
: QQuickItem(parent)
{
setFlags(ItemAcceptsDrops);
setFlags(ItemAcceptsDrops);
}
void
NhekoDropArea::dragEnterEvent(QDragEnterEvent *event)
{
event->acceptProposedAction();
event->acceptProposedAction();
}
void
NhekoDropArea::dragMoveEvent(QDragMoveEvent *event)
{
event->acceptProposedAction();
event->acceptProposedAction();
}
void
NhekoDropArea::dropEvent(QDropEvent *event)
{
if (event) {
auto model = ChatPage::instance()->timelineManager()->rooms()->getRoomById(roomid_);
if (model) {
model->input()->insertMimeData(event->mimeData());
}
if (event) {
auto model = ChatPage::instance()->timelineManager()->rooms()->getRoomById(roomid_);
if (model) {
model->input()->insertMimeData(event->mimeData());
}
}
}

View file

@ -6,29 +6,29 @@
class NhekoDropArea : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(QString roomid READ roomid WRITE setRoomid NOTIFY roomidChanged)
Q_OBJECT
Q_PROPERTY(QString roomid READ roomid WRITE setRoomid NOTIFY roomidChanged)
public:
NhekoDropArea(QQuickItem *parent = nullptr);
NhekoDropArea(QQuickItem *parent = nullptr);
signals:
void roomidChanged(QString roomid);
void roomidChanged(QString roomid);
public slots:
void setRoomid(QString roomid)
{
if (roomid_ != roomid) {
roomid_ = roomid;
emit roomidChanged(roomid);
}
void setRoomid(QString roomid)
{
if (roomid_ != roomid) {
roomid_ = roomid;
emit roomidChanged(roomid);
}
QString roomid() const { return roomid_; }
}
QString roomid() const { return roomid_; }
protected:
void dragEnterEvent(QDragEnterEvent *event) override;
void dragMoveEvent(QDragMoveEvent *event) override;
void dropEvent(QDropEvent *event) override;
void dragEnterEvent(QDragEnterEvent *event) override;
void dragMoveEvent(QDragMoveEvent *event) override;
void dropEvent(QDropEvent *event) override;
private:
QString roomid_;
QString roomid_;
};

View file

@ -17,93 +17,93 @@
Nheko::Nheko()
{
connect(
UserSettings::instance().get(), &UserSettings::themeChanged, this, &Nheko::colorsChanged);
connect(ChatPage::instance(), &ChatPage::contentLoaded, this, &Nheko::updateUserProfile);
connect(
UserSettings::instance().get(), &UserSettings::themeChanged, this, &Nheko::colorsChanged);
connect(ChatPage::instance(), &ChatPage::contentLoaded, this, &Nheko::updateUserProfile);
}
void
Nheko::updateUserProfile()
{
if (cache::client() && cache::client()->isInitialized())
currentUser_.reset(
new UserProfile("", utils::localUser(), ChatPage::instance()->timelineManager()));
else
currentUser_.reset();
emit profileChanged();
if (cache::client() && cache::client()->isInitialized())
currentUser_.reset(
new UserProfile("", utils::localUser(), ChatPage::instance()->timelineManager()));
else
currentUser_.reset();
emit profileChanged();
}
QPalette
Nheko::colors() const
{
return Theme::paletteFromTheme(UserSettings::instance()->theme().toStdString());
return Theme::paletteFromTheme(UserSettings::instance()->theme().toStdString());
}
QPalette
Nheko::inactiveColors() const
{
auto p = colors();
p.setCurrentColorGroup(QPalette::ColorGroup::Inactive);
return p;
auto p = colors();
p.setCurrentColorGroup(QPalette::ColorGroup::Inactive);
return p;
}
Theme
Nheko::theme() const
{
return Theme(UserSettings::instance()->theme().toStdString());
return Theme(UserSettings::instance()->theme().toStdString());
}
void
Nheko::openLink(QString link) const
{
QUrl url(link);
// Open externally if we couldn't handle it internally
if (!ChatPage::instance()->handleMatrixUri(url)) {
QDesktopServices::openUrl(url);
}
QUrl url(link);
// Open externally if we couldn't handle it internally
if (!ChatPage::instance()->handleMatrixUri(url)) {
QDesktopServices::openUrl(url);
}
}
void
Nheko::setStatusMessage(QString msg) const
{
ChatPage::instance()->setStatus(msg);
ChatPage::instance()->setStatus(msg);
}
UserProfile *
Nheko::currentUser() const
{
nhlog::ui()->debug("Profile requested");
nhlog::ui()->debug("Profile requested");
return currentUser_.get();
return currentUser_.get();
}
void
Nheko::showUserSettingsPage() const
{
ChatPage::instance()->showUserSettingsPage();
ChatPage::instance()->showUserSettingsPage();
}
void
Nheko::openLogoutDialog() const
{
MainWindow::instance()->openLogoutDialog();
MainWindow::instance()->openLogoutDialog();
}
void
Nheko::openCreateRoomDialog() const
{
MainWindow::instance()->openCreateRoomDialog(
[](const mtx::requests::CreateRoom &req) { ChatPage::instance()->createRoom(req); });
MainWindow::instance()->openCreateRoomDialog(
[](const mtx::requests::CreateRoom &req) { ChatPage::instance()->createRoom(req); });
}
void
Nheko::openJoinRoomDialog() const
{
MainWindow::instance()->openJoinRoomDialog(
[](const QString &room_id) { ChatPage::instance()->joinRoom(room_id); });
MainWindow::instance()->openJoinRoomDialog(
[](const QString &room_id) { ChatPage::instance()->joinRoom(room_id); });
}
void
Nheko::reparent(QWindow *win) const
{
win->setTransientParent(MainWindow::instance()->windowHandle());
win->setTransientParent(MainWindow::instance()->windowHandle());
}

View file

@ -15,51 +15,51 @@ class QWindow;
class Nheko : public QObject
{
Q_OBJECT
Q_OBJECT
Q_PROPERTY(QPalette colors READ colors NOTIFY colorsChanged)
Q_PROPERTY(QPalette inactiveColors READ inactiveColors NOTIFY colorsChanged)
Q_PROPERTY(Theme theme READ theme NOTIFY colorsChanged)
Q_PROPERTY(int avatarSize READ avatarSize CONSTANT)
Q_PROPERTY(int paddingSmall READ paddingSmall CONSTANT)
Q_PROPERTY(int paddingMedium READ paddingMedium CONSTANT)
Q_PROPERTY(int paddingLarge READ paddingLarge CONSTANT)
Q_PROPERTY(QPalette colors READ colors NOTIFY colorsChanged)
Q_PROPERTY(QPalette inactiveColors READ inactiveColors NOTIFY colorsChanged)
Q_PROPERTY(Theme theme READ theme NOTIFY colorsChanged)
Q_PROPERTY(int avatarSize READ avatarSize CONSTANT)
Q_PROPERTY(int paddingSmall READ paddingSmall CONSTANT)
Q_PROPERTY(int paddingMedium READ paddingMedium CONSTANT)
Q_PROPERTY(int paddingLarge READ paddingLarge CONSTANT)
Q_PROPERTY(UserProfile *currentUser READ currentUser NOTIFY profileChanged)
Q_PROPERTY(UserProfile *currentUser READ currentUser NOTIFY profileChanged)
public:
Nheko();
Nheko();
QPalette colors() const;
QPalette inactiveColors() const;
Theme theme() const;
QPalette colors() const;
QPalette inactiveColors() const;
Theme theme() const;
int avatarSize() const { return 40; }
int avatarSize() const { return 40; }
int paddingSmall() const { return 4; }
int paddingMedium() const { return 8; }
int paddingLarge() const { return 20; }
UserProfile *currentUser() const;
int paddingSmall() const { return 4; }
int paddingMedium() const { return 8; }
int paddingLarge() const { return 20; }
UserProfile *currentUser() const;
Q_INVOKABLE QFont monospaceFont() const
{
return QFontDatabase::systemFont(QFontDatabase::FixedFont);
}
Q_INVOKABLE void openLink(QString link) const;
Q_INVOKABLE void setStatusMessage(QString msg) const;
Q_INVOKABLE void showUserSettingsPage() const;
Q_INVOKABLE void openLogoutDialog() const;
Q_INVOKABLE void openCreateRoomDialog() const;
Q_INVOKABLE void openJoinRoomDialog() const;
Q_INVOKABLE void reparent(QWindow *win) const;
Q_INVOKABLE QFont monospaceFont() const
{
return QFontDatabase::systemFont(QFontDatabase::FixedFont);
}
Q_INVOKABLE void openLink(QString link) const;
Q_INVOKABLE void setStatusMessage(QString msg) const;
Q_INVOKABLE void showUserSettingsPage() const;
Q_INVOKABLE void openLogoutDialog() const;
Q_INVOKABLE void openCreateRoomDialog() const;
Q_INVOKABLE void openJoinRoomDialog() const;
Q_INVOKABLE void reparent(QWindow *win) const;
public slots:
void updateUserProfile();
void updateUserProfile();
signals:
void colorsChanged();
void profileChanged();
void colorsChanged();
void profileChanged();
private:
QScopedPointer<UserProfile> currentUser_;
QScopedPointer<UserProfile> currentUser_;
};

View file

@ -12,50 +12,50 @@ OverlayModal::OverlayModal(QWidget *parent)
: OverlayWidget(parent)
, color_{QColor(30, 30, 30, 170)}
{
layout_ = new QVBoxLayout(this);
layout_->setSpacing(0);
layout_->setContentsMargins(10, 40, 10, 20);
setContentAlignment(Qt::AlignCenter);
layout_ = new QVBoxLayout(this);
layout_->setSpacing(0);
layout_->setContentsMargins(10, 40, 10, 20);
setContentAlignment(Qt::AlignCenter);
}
void
OverlayModal::setWidget(QWidget *widget)
{
// Delete the previous widget
if (layout_->count() > 0) {
QLayoutItem *item;
while ((item = layout_->takeAt(0)) != nullptr) {
delete item->widget();
delete item;
}
// Delete the previous widget
if (layout_->count() > 0) {
QLayoutItem *item;
while ((item = layout_->takeAt(0)) != nullptr) {
delete item->widget();
delete item;
}
}
layout_->addWidget(widget);
content_ = widget;
content_->setFocus();
layout_->addWidget(widget);
content_ = widget;
content_->setFocus();
}
void
OverlayModal::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
Q_UNUSED(event);
QPainter painter(this);
painter.fillRect(rect(), color_);
QPainter painter(this);
painter.fillRect(rect(), color_);
}
void
OverlayModal::mousePressEvent(QMouseEvent *e)
{
if (isDismissible_ && content_ && !content_->geometry().contains(e->pos()))
hide();
if (isDismissible_ && content_ && !content_->geometry().contains(e->pos()))
hide();
}
void
OverlayModal::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Escape) {
event->accept();
hide();
}
if (event->key() == Qt::Key_Escape) {
event->accept();
hide();
}
}

View file

@ -15,25 +15,25 @@
class OverlayModal : public OverlayWidget
{
public:
OverlayModal(QWidget *parent);
OverlayModal(QWidget *parent);
void setColor(QColor color) { color_ = color; }
void setDismissible(bool state) { isDismissible_ = state; }
void setColor(QColor color) { color_ = color; }
void setDismissible(bool state) { isDismissible_ = state; }
void setContentAlignment(QFlags<Qt::AlignmentFlag> flag) { layout_->setAlignment(flag); }
void setWidget(QWidget *widget);
void setContentAlignment(QFlags<Qt::AlignmentFlag> flag) { layout_->setAlignment(flag); }
void setWidget(QWidget *widget);
protected:
void paintEvent(QPaintEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void paintEvent(QPaintEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
private:
QWidget *content_;
QVBoxLayout *layout_;
QWidget *content_;
QVBoxLayout *layout_;
QColor color_;
QColor color_;
//! Decides whether or not the modal can be removed by clicking into it.
bool isDismissible_ = true;
//! Decides whether or not the modal can be removed by clicking into it.
bool isDismissible_ = true;
};

View file

@ -10,69 +10,69 @@
OverlayWidget::OverlayWidget(QWidget *parent)
: QWidget(parent)
{
if (parent) {
parent->installEventFilter(this);
setGeometry(overlayGeometry());
raise();
}
if (parent) {
parent->installEventFilter(this);
setGeometry(overlayGeometry());
raise();
}
}
bool
OverlayWidget::event(QEvent *event)
{
if (!parent())
return QWidget::event(event);
switch (event->type()) {
case QEvent::ParentChange: {
parent()->installEventFilter(this);
setGeometry(overlayGeometry());
break;
}
case QEvent::ParentAboutToChange: {
parent()->removeEventFilter(this);
break;
}
default:
break;
}
if (!parent())
return QWidget::event(event);
switch (event->type()) {
case QEvent::ParentChange: {
parent()->installEventFilter(this);
setGeometry(overlayGeometry());
break;
}
case QEvent::ParentAboutToChange: {
parent()->removeEventFilter(this);
break;
}
default:
break;
}
return QWidget::event(event);
}
bool
OverlayWidget::eventFilter(QObject *obj, QEvent *event)
{
switch (event->type()) {
case QEvent::Move:
case QEvent::Resize:
setGeometry(overlayGeometry());
break;
default:
break;
}
switch (event->type()) {
case QEvent::Move:
case QEvent::Resize:
setGeometry(overlayGeometry());
break;
default:
break;
}
return QWidget::eventFilter(obj, event);
return QWidget::eventFilter(obj, event);
}
QRect
OverlayWidget::overlayGeometry() const
{
QWidget *widget = parentWidget();
QWidget *widget = parentWidget();
if (!widget)
return QRect();
if (!widget)
return QRect();
return widget->rect();
return widget->rect();
}
void
OverlayWidget::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
Q_UNUSED(event);
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

View file

@ -11,15 +11,15 @@ class QPainter;
class OverlayWidget : public QWidget
{
Q_OBJECT
Q_OBJECT
public:
explicit OverlayWidget(QWidget *parent = nullptr);
explicit OverlayWidget(QWidget *parent = nullptr);
protected:
bool event(QEvent *event) override;
bool eventFilter(QObject *obj, QEvent *event) override;
bool event(QEvent *event) override;
bool eventFilter(QObject *obj, QEvent *event) override;
QRect overlayGeometry() const;
void paintEvent(QPaintEvent *event) override;
QRect overlayGeometry() const;
void paintEvent(QPaintEvent *event) override;
};

View file

@ -13,147 +13,141 @@
class Painter : public QPainter
{
public:
explicit Painter(QPaintDevice *device)
: QPainter(device)
{}
explicit Painter(QPaintDevice *device)
: QPainter(device)
{}
void drawTextLeft(int x, int y, const QString &text)
{
QFontMetrics m(fontMetrics());
drawText(x, y + m.ascent(), text);
void drawTextLeft(int x, int y, const QString &text)
{
QFontMetrics m(fontMetrics());
drawText(x, y + m.ascent(), text);
}
void drawTextRight(int x, int y, int outerw, const QString &text, int textWidth = -1)
{
QFontMetrics m(fontMetrics());
if (textWidth < 0) {
textWidth = m.horizontalAdvance(text);
}
drawText((outerw - x - textWidth), y + m.ascent(), text);
}
void drawTextRight(int x, int y, int outerw, const QString &text, int textWidth = -1)
{
QFontMetrics m(fontMetrics());
if (textWidth < 0) {
textWidth = m.horizontalAdvance(text);
}
drawText((outerw - x - textWidth), y + m.ascent(), text);
}
void drawPixmapLeft(int x, int y, const QPixmap &pix, const QRect &from)
{
drawPixmap(QPoint(x, y), pix, from);
}
void drawPixmapLeft(int x, int y, const QPixmap &pix, const QRect &from)
{
drawPixmap(QPoint(x, y), pix, from);
}
void drawPixmapLeft(const QPoint &p, const QPixmap &pix, const QRect &from)
{
return drawPixmapLeft(p.x(), p.y(), pix, from);
}
void drawPixmapLeft(const QPoint &p, const QPixmap &pix, const QRect &from)
{
return drawPixmapLeft(p.x(), p.y(), pix, from);
}
void drawPixmapLeft(int x, int y, int w, int h, const QPixmap &pix, const QRect &from)
{
drawPixmap(QRect(x, y, w, h), pix, from);
}
void drawPixmapLeft(int x, int y, int w, int h, const QPixmap &pix, const QRect &from)
{
drawPixmap(QRect(x, y, w, h), pix, from);
}
void drawPixmapLeft(const QRect &r, const QPixmap &pix, const QRect &from)
{
return drawPixmapLeft(r.x(), r.y(), r.width(), r.height(), pix, from);
}
void drawPixmapLeft(const QRect &r, const QPixmap &pix, const QRect &from)
{
return drawPixmapLeft(r.x(), r.y(), r.width(), r.height(), pix, from);
}
void drawPixmapLeft(int x, int y, int outerw, const QPixmap &pix)
{
Q_UNUSED(outerw);
drawPixmap(QPoint(x, y), pix);
}
void drawPixmapLeft(int x, int y, int outerw, const QPixmap &pix)
{
Q_UNUSED(outerw);
drawPixmap(QPoint(x, y), pix);
}
void drawPixmapLeft(const QPoint &p, int outerw, const QPixmap &pix)
{
return drawPixmapLeft(p.x(), p.y(), outerw, pix);
}
void drawPixmapLeft(const QPoint &p, int outerw, const QPixmap &pix)
{
return drawPixmapLeft(p.x(), p.y(), outerw, pix);
}
void drawPixmapRight(int x, int y, int outerw, const QPixmap &pix, const QRect &from)
{
drawPixmap(QPoint((outerw - x - (from.width() / pix.devicePixelRatio())), y), pix, from);
}
void drawPixmapRight(int x, int y, int outerw, const QPixmap &pix, const QRect &from)
{
drawPixmap(
QPoint((outerw - x - (from.width() / pix.devicePixelRatio())), y), pix, from);
}
void drawPixmapRight(const QPoint &p, int outerw, const QPixmap &pix, const QRect &from)
{
return drawPixmapRight(p.x(), p.y(), outerw, pix, from);
}
void
drawPixmapRight(int x, int y, int w, int h, int outerw, const QPixmap &pix, const QRect &from)
{
drawPixmap(QRect((outerw - x - w), y, w, h), pix, from);
}
void drawPixmapRight(const QPoint &p, int outerw, const QPixmap &pix, const QRect &from)
{
return drawPixmapRight(p.x(), p.y(), outerw, pix, from);
}
void drawPixmapRight(int x,
int y,
int w,
int h,
int outerw,
const QPixmap &pix,
const QRect &from)
{
drawPixmap(QRect((outerw - x - w), y, w, h), pix, from);
}
void drawPixmapRight(const QRect &r, int outerw, const QPixmap &pix, const QRect &from)
{
return drawPixmapRight(r.x(), r.y(), r.width(), r.height(), outerw, pix, from);
}
void drawPixmapRight(const QRect &r, int outerw, const QPixmap &pix, const QRect &from)
{
return drawPixmapRight(r.x(), r.y(), r.width(), r.height(), outerw, pix, from);
}
void drawPixmapRight(int x, int y, int outerw, const QPixmap &pix)
{
drawPixmap(QPoint((outerw - x - (pix.width() / pix.devicePixelRatio())), y), pix);
}
void drawPixmapRight(int x, int y, int outerw, const QPixmap &pix)
{
drawPixmap(QPoint((outerw - x - (pix.width() / pix.devicePixelRatio())), y), pix);
}
void drawPixmapRight(const QPoint &p, int outerw, const QPixmap &pix)
{
return drawPixmapRight(p.x(), p.y(), outerw, pix);
}
void drawPixmapRight(const QPoint &p, int outerw, const QPixmap &pix)
{
return drawPixmapRight(p.x(), p.y(), outerw, pix);
}
void drawAvatar(const QPixmap &pix, int w, int h, int d)
{
QPainterPath pp;
pp.addEllipse((w - d) / 2, (h - d) / 2, d, d);
void drawAvatar(const QPixmap &pix, int w, int h, int d)
{
QPainterPath pp;
pp.addEllipse((w - d) / 2, (h - d) / 2, d, d);
QRect region((w - d) / 2, (h - d) / 2, d, d);
QRect region((w - d) / 2, (h - d) / 2, d, d);
setClipPath(pp);
drawPixmap(region, pix);
}
setClipPath(pp);
drawPixmap(region, pix);
}
void drawLetterAvatar(const QString &c,
const QColor &penColor,
const QColor &brushColor,
int w,
int h,
int d)
{
QRect region((w - d) / 2, (h - d) / 2, d, d);
void drawLetterAvatar(const QString &c,
const QColor &penColor,
const QColor &brushColor,
int w,
int h,
int d)
{
QRect region((w - d) / 2, (h - d) / 2, d, d);
setPen(Qt::NoPen);
setBrush(brushColor);
setPen(Qt::NoPen);
setBrush(brushColor);
drawEllipse(region.center(), d / 2, d / 2);
drawEllipse(region.center(), d / 2, d / 2);
setBrush(Qt::NoBrush);
drawEllipse(region.center(), d / 2, d / 2);
setBrush(Qt::NoBrush);
drawEllipse(region.center(), d / 2, d / 2);
setPen(penColor);
drawText(region.translated(0, -1), Qt::AlignCenter, c);
}
setPen(penColor);
drawText(region.translated(0, -1), Qt::AlignCenter, c);
}
};
class PainterHighQualityEnabler
{
public:
PainterHighQualityEnabler(Painter &p)
: _painter(p)
{
hints_ = QPainter::Antialiasing | QPainter::SmoothPixmapTransform |
QPainter::TextAntialiasing;
PainterHighQualityEnabler(Painter &p)
: _painter(p)
{
hints_ =
QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing;
_painter.setRenderHints(hints_);
}
_painter.setRenderHints(hints_);
}
~PainterHighQualityEnabler()
{
if (hints_)
_painter.setRenderHints(hints_, false);
}
~PainterHighQualityEnabler()
{
if (hints_)
_painter.setRenderHints(hints_, false);
}
PainterHighQualityEnabler(const PainterHighQualityEnabler &other) = delete;
PainterHighQualityEnabler &operator=(const PainterHighQualityEnabler &other) = delete;
PainterHighQualityEnabler(const PainterHighQualityEnabler &other) = delete;
PainterHighQualityEnabler &operator=(const PainterHighQualityEnabler &other) = delete;
private:
Painter &_painter;
QPainter::RenderHints hints_ = {};
Painter &_painter;
QPainter::RenderHints hints_ = {};
};

View file

@ -10,68 +10,68 @@
void
RaisedButton::init()
{
shadow_state_machine_ = new QStateMachine(this);
normal_state_ = new QState;
pressed_state_ = new QState;
effect_ = new QGraphicsDropShadowEffect;
shadow_state_machine_ = new QStateMachine(this);
normal_state_ = new QState;
pressed_state_ = new QState;
effect_ = new QGraphicsDropShadowEffect;
effect_->setBlurRadius(7);
effect_->setOffset(QPointF(0, 2));
effect_->setColor(QColor(0, 0, 0, 75));
effect_->setBlurRadius(7);
effect_->setOffset(QPointF(0, 2));
effect_->setColor(QColor(0, 0, 0, 75));
setBackgroundMode(Qt::OpaqueMode);
setMinimumHeight(42);
setGraphicsEffect(effect_);
setBaseOpacity(0.3);
setBackgroundMode(Qt::OpaqueMode);
setMinimumHeight(42);
setGraphicsEffect(effect_);
setBaseOpacity(0.3);
shadow_state_machine_->addState(normal_state_);
shadow_state_machine_->addState(pressed_state_);
shadow_state_machine_->addState(normal_state_);
shadow_state_machine_->addState(pressed_state_);
normal_state_->assignProperty(effect_, "offset", QPointF(0, 2));
normal_state_->assignProperty(effect_, "blurRadius", 7);
normal_state_->assignProperty(effect_, "offset", QPointF(0, 2));
normal_state_->assignProperty(effect_, "blurRadius", 7);
pressed_state_->assignProperty(effect_, "offset", QPointF(0, 5));
pressed_state_->assignProperty(effect_, "blurRadius", 29);
pressed_state_->assignProperty(effect_, "offset", QPointF(0, 5));
pressed_state_->assignProperty(effect_, "blurRadius", 29);
QAbstractTransition *transition;
QAbstractTransition *transition;
transition = new QEventTransition(this, QEvent::MouseButtonPress);
transition->setTargetState(pressed_state_);
normal_state_->addTransition(transition);
transition = new QEventTransition(this, QEvent::MouseButtonPress);
transition->setTargetState(pressed_state_);
normal_state_->addTransition(transition);
transition = new QEventTransition(this, QEvent::MouseButtonDblClick);
transition->setTargetState(pressed_state_);
normal_state_->addTransition(transition);
transition = new QEventTransition(this, QEvent::MouseButtonDblClick);
transition->setTargetState(pressed_state_);
normal_state_->addTransition(transition);
transition = new QEventTransition(this, QEvent::MouseButtonRelease);
transition->setTargetState(normal_state_);
pressed_state_->addTransition(transition);
transition = new QEventTransition(this, QEvent::MouseButtonRelease);
transition->setTargetState(normal_state_);
pressed_state_->addTransition(transition);
QPropertyAnimation *animation;
QPropertyAnimation *animation;
animation = new QPropertyAnimation(effect_, "offset", this);
animation->setDuration(100);
shadow_state_machine_->addDefaultAnimation(animation);
animation = new QPropertyAnimation(effect_, "offset", this);
animation->setDuration(100);
shadow_state_machine_->addDefaultAnimation(animation);
animation = new QPropertyAnimation(effect_, "blurRadius", this);
animation->setDuration(100);
shadow_state_machine_->addDefaultAnimation(animation);
animation = new QPropertyAnimation(effect_, "blurRadius", this);
animation->setDuration(100);
shadow_state_machine_->addDefaultAnimation(animation);
shadow_state_machine_->setInitialState(normal_state_);
shadow_state_machine_->start();
shadow_state_machine_->setInitialState(normal_state_);
shadow_state_machine_->start();
}
RaisedButton::RaisedButton(QWidget *parent)
: FlatButton(parent)
{
init();
init();
}
RaisedButton::RaisedButton(const QString &text, QWidget *parent)
: FlatButton(parent)
{
init();
setText(text);
init();
setText(text);
}
RaisedButton::~RaisedButton() {}
@ -79,15 +79,15 @@ RaisedButton::~RaisedButton() {}
bool
RaisedButton::event(QEvent *event)
{
if (QEvent::EnabledChange == event->type()) {
if (isEnabled()) {
shadow_state_machine_->start();
effect_->setEnabled(true);
} else {
shadow_state_machine_->stop();
effect_->setEnabled(false);
}
if (QEvent::EnabledChange == event->type()) {
if (isEnabled()) {
shadow_state_machine_->start();
effect_->setEnabled(true);
} else {
shadow_state_machine_->stop();
effect_->setEnabled(false);
}
}
return FlatButton::event(event);
return FlatButton::event(event);
}

View file

@ -12,21 +12,21 @@
class RaisedButton : public FlatButton
{
Q_OBJECT
Q_OBJECT
public:
explicit RaisedButton(QWidget *parent = nullptr);
explicit RaisedButton(const QString &text, QWidget *parent = nullptr);
~RaisedButton() override;
explicit RaisedButton(QWidget *parent = nullptr);
explicit RaisedButton(const QString &text, QWidget *parent = nullptr);
~RaisedButton() override;
protected:
bool event(QEvent *event) override;
bool event(QEvent *event) override;
private:
void init();
void init();
QStateMachine *shadow_state_machine_;
QState *normal_state_;
QState *pressed_state_;
QGraphicsDropShadowEffect *effect_;
QStateMachine *shadow_state_machine_;
QState *normal_state_;
QState *pressed_state_;
QGraphicsDropShadowEffect *effect_;
};

View file

@ -14,7 +14,7 @@ Ripple::Ripple(const QPoint &center, QObject *parent)
, opacity_(0)
, center_(center)
{
init();
init();
}
Ripple::Ripple(const QPoint &center, RippleOverlay *overlay, QObject *parent)
@ -26,86 +26,86 @@ Ripple::Ripple(const QPoint &center, RippleOverlay *overlay, QObject *parent)
, opacity_(0)
, center_(center)
{
init();
init();
}
void
Ripple::setRadius(qreal radius)
{
Q_ASSERT(overlay_);
Q_ASSERT(overlay_);
if (radius_ == radius)
return;
if (radius_ == radius)
return;
radius_ = radius;
overlay_->update();
radius_ = radius;
overlay_->update();
}
void
Ripple::setOpacity(qreal opacity)
{
Q_ASSERT(overlay_);
Q_ASSERT(overlay_);
if (opacity_ == opacity)
return;
if (opacity_ == opacity)
return;
opacity_ = opacity;
overlay_->update();
opacity_ = opacity;
overlay_->update();
}
void
Ripple::setColor(const QColor &color)
{
if (brush_.color() == color)
return;
if (brush_.color() == color)
return;
brush_.setColor(color);
brush_.setColor(color);
if (overlay_)
overlay_->update();
if (overlay_)
overlay_->update();
}
void
Ripple::setBrush(const QBrush &brush)
{
brush_ = brush;
brush_ = brush;
if (overlay_)
overlay_->update();
if (overlay_)
overlay_->update();
}
void
Ripple::destroy()
{
Q_ASSERT(overlay_);
Q_ASSERT(overlay_);
overlay_->removeRipple(this);
overlay_->removeRipple(this);
}
QPropertyAnimation *
Ripple::animate(const QByteArray &property, const QEasingCurve &easing, int duration)
{
QPropertyAnimation *animation = new QPropertyAnimation;
animation->setTargetObject(this);
animation->setPropertyName(property);
animation->setEasingCurve(easing);
animation->setDuration(duration);
QPropertyAnimation *animation = new QPropertyAnimation;
animation->setTargetObject(this);
animation->setPropertyName(property);
animation->setEasingCurve(easing);
animation->setDuration(duration);
addAnimation(animation);
addAnimation(animation);
return animation;
return animation;
}
void
Ripple::init()
{
setOpacityStartValue(0.5);
setOpacityEndValue(0);
setRadiusStartValue(0);
setRadiusEndValue(300);
setOpacityStartValue(0.5);
setOpacityEndValue(0);
setRadiusStartValue(0);
setRadiusEndValue(300);
brush_.setColor(Qt::black);
brush_.setStyle(Qt::SolidPattern);
brush_.setColor(Qt::black);
brush_.setStyle(Qt::SolidPattern);
connect(this, SIGNAL(finished()), this, SLOT(destroy()));
connect(this, SIGNAL(finished()), this, SLOT(destroy()));
}

View file

@ -14,136 +14,136 @@ class RippleOverlay;
class Ripple : public QParallelAnimationGroup
{
Q_OBJECT
Q_OBJECT
Q_PROPERTY(qreal radius WRITE setRadius READ radius)
Q_PROPERTY(qreal opacity WRITE setOpacity READ opacity)
Q_PROPERTY(qreal radius WRITE setRadius READ radius)
Q_PROPERTY(qreal opacity WRITE setOpacity READ opacity)
public:
explicit Ripple(const QPoint &center, QObject *parent = nullptr);
Ripple(const QPoint &center, RippleOverlay *overlay, QObject *parent = nullptr);
explicit Ripple(const QPoint &center, QObject *parent = nullptr);
Ripple(const QPoint &center, RippleOverlay *overlay, QObject *parent = nullptr);
inline void setOverlay(RippleOverlay *overlay);
inline void setOverlay(RippleOverlay *overlay);
void setRadius(qreal radius);
void setOpacity(qreal opacity);
void setColor(const QColor &color);
void setBrush(const QBrush &brush);
void setRadius(qreal radius);
void setOpacity(qreal opacity);
void setColor(const QColor &color);
void setBrush(const QBrush &brush);
inline qreal radius() const;
inline qreal opacity() const;
inline QColor color() const;
inline QBrush brush() const;
inline QPoint center() const;
inline qreal radius() const;
inline qreal opacity() const;
inline QColor color() const;
inline QBrush brush() const;
inline QPoint center() const;
inline QPropertyAnimation *radiusAnimation() const;
inline QPropertyAnimation *opacityAnimation() const;
inline QPropertyAnimation *radiusAnimation() const;
inline QPropertyAnimation *opacityAnimation() const;
inline void setOpacityStartValue(qreal value);
inline void setOpacityEndValue(qreal value);
inline void setRadiusStartValue(qreal value);
inline void setRadiusEndValue(qreal value);
inline void setDuration(int msecs);
inline void setOpacityStartValue(qreal value);
inline void setOpacityEndValue(qreal value);
inline void setRadiusStartValue(qreal value);
inline void setRadiusEndValue(qreal value);
inline void setDuration(int msecs);
protected slots:
void destroy();
void destroy();
private:
Q_DISABLE_COPY(Ripple)
Q_DISABLE_COPY(Ripple)
QPropertyAnimation *animate(const QByteArray &property,
const QEasingCurve &easing = QEasingCurve::OutQuad,
int duration = 800);
QPropertyAnimation *animate(const QByteArray &property,
const QEasingCurve &easing = QEasingCurve::OutQuad,
int duration = 800);
void init();
void init();
RippleOverlay *overlay_;
RippleOverlay *overlay_;
QPropertyAnimation *const radius_anim_;
QPropertyAnimation *const opacity_anim_;
QPropertyAnimation *const radius_anim_;
QPropertyAnimation *const opacity_anim_;
qreal radius_;
qreal opacity_;
qreal radius_;
qreal opacity_;
QPoint center_;
QBrush brush_;
QPoint center_;
QBrush brush_;
};
inline void
Ripple::setOverlay(RippleOverlay *overlay)
{
overlay_ = overlay;
overlay_ = overlay;
}
inline qreal
Ripple::radius() const
{
return radius_;
return radius_;
}
inline qreal
Ripple::opacity() const
{
return opacity_;
return opacity_;
}
inline QColor
Ripple::color() const
{
return brush_.color();
return brush_.color();
}
inline QBrush
Ripple::brush() const
{
return brush_;
return brush_;
}
inline QPoint
Ripple::center() const
{
return center_;
return center_;
}
inline QPropertyAnimation *
Ripple::radiusAnimation() const
{
return radius_anim_;
return radius_anim_;
}
inline QPropertyAnimation *
Ripple::opacityAnimation() const
{
return opacity_anim_;
return opacity_anim_;
}
inline void
Ripple::setOpacityStartValue(qreal value)
{
opacity_anim_->setStartValue(value);
opacity_anim_->setStartValue(value);
}
inline void
Ripple::setOpacityEndValue(qreal value)
{
opacity_anim_->setEndValue(value);
opacity_anim_->setEndValue(value);
}
inline void
Ripple::setRadiusStartValue(qreal value)
{
radius_anim_->setStartValue(value);
radius_anim_->setStartValue(value);
}
inline void
Ripple::setRadiusEndValue(qreal value)
{
radius_anim_->setEndValue(value);
radius_anim_->setEndValue(value);
}
inline void
Ripple::setDuration(int msecs)
{
radius_anim_->setDuration(msecs);
opacity_anim_->setDuration(msecs);
radius_anim_->setDuration(msecs);
opacity_anim_->setDuration(msecs);
}

View file

@ -11,56 +11,56 @@ RippleOverlay::RippleOverlay(QWidget *parent)
: OverlayWidget(parent)
, use_clip_(false)
{
setAttribute(Qt::WA_TransparentForMouseEvents);
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_TransparentForMouseEvents);
setAttribute(Qt::WA_NoSystemBackground);
}
void
RippleOverlay::addRipple(Ripple *ripple)
{
ripple->setOverlay(this);
ripples_.push_back(ripple);
ripple->start();
ripple->setOverlay(this);
ripples_.push_back(ripple);
ripple->start();
}
void
RippleOverlay::addRipple(const QPoint &position, qreal radius)
{
Ripple *ripple = new Ripple(position);
ripple->setRadiusEndValue(radius);
addRipple(ripple);
Ripple *ripple = new Ripple(position);
ripple->setRadiusEndValue(radius);
addRipple(ripple);
}
void
RippleOverlay::removeRipple(Ripple *ripple)
{
if (ripples_.removeOne(ripple))
delete ripple;
if (ripples_.removeOne(ripple))
delete ripple;
}
void
RippleOverlay::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
Q_UNUSED(event)
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::NoPen);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::NoPen);
if (use_clip_)
painter.setClipPath(clip_path_);
if (use_clip_)
painter.setClipPath(clip_path_);
for (auto it = ripples_.constBegin(); it != ripples_.constEnd(); ++it)
paintRipple(&painter, *it);
for (auto it = ripples_.constBegin(); it != ripples_.constEnd(); ++it)
paintRipple(&painter, *it);
}
void
RippleOverlay::paintRipple(QPainter *painter, Ripple *ripple)
{
const qreal radius = ripple->radius();
const QPointF center = ripple->center();
const qreal radius = ripple->radius();
const QPointF center = ripple->center();
painter->setOpacity(ripple->opacity());
painter->setBrush(ripple->brush());
painter->drawEllipse(center, radius, radius);
painter->setOpacity(ripple->opacity());
painter->setBrush(ripple->brush());
painter->drawEllipse(center, radius, radius);
}

View file

@ -12,50 +12,50 @@ class Ripple;
class RippleOverlay : public OverlayWidget
{
Q_OBJECT
Q_OBJECT
public:
explicit RippleOverlay(QWidget *parent = nullptr);
explicit RippleOverlay(QWidget *parent = nullptr);
void addRipple(Ripple *ripple);
void addRipple(const QPoint &position, qreal radius = 300);
void addRipple(Ripple *ripple);
void addRipple(const QPoint &position, qreal radius = 300);
void removeRipple(Ripple *ripple);
void removeRipple(Ripple *ripple);
inline void setClipping(bool enable);
inline bool hasClipping() const;
inline void setClipping(bool enable);
inline bool hasClipping() const;
inline void setClipPath(const QPainterPath &path);
inline void setClipPath(const QPainterPath &path);
protected:
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
private:
Q_DISABLE_COPY(RippleOverlay)
Q_DISABLE_COPY(RippleOverlay)
void paintRipple(QPainter *painter, Ripple *ripple);
void paintRipple(QPainter *painter, Ripple *ripple);
QList<Ripple *> ripples_;
QPainterPath clip_path_;
bool use_clip_;
QList<Ripple *> ripples_;
QPainterPath clip_path_;
bool use_clip_;
};
inline void
RippleOverlay::setClipping(bool enable)
{
use_clip_ = enable;
update();
use_clip_ = enable;
update();
}
inline bool
RippleOverlay::hasClipping() const
{
return use_clip_;
return use_clip_;
}
inline void
RippleOverlay::setClipPath(const QPainterPath &path)
{
clip_path_ = path;
update();
clip_path_ = path;
update();
}

File diff suppressed because it is too large Load diff

View file

@ -19,121 +19,121 @@ class TextField;
/// outside of main with the UI code.
class ThreadProxy : public QObject
{
Q_OBJECT
Q_OBJECT
signals:
void error(const QString &msg);
void nameEventSent(const QString &);
void topicEventSent(const QString &);
void stopLoading();
void error(const QString &msg);
void nameEventSent(const QString &);
void topicEventSent(const QString &);
void stopLoading();
};
class EditModal : public QWidget
{
Q_OBJECT
Q_OBJECT
public:
EditModal(const QString &roomId, QWidget *parent = nullptr);
EditModal(const QString &roomId, QWidget *parent = nullptr);
void setFields(const QString &roomName, const QString &roomTopic);
void setFields(const QString &roomName, const QString &roomTopic);
signals:
void nameChanged(const QString &roomName);
void topicChanged(const QString &topic);
void nameChanged(const QString &roomName);
void topicChanged(const QString &topic);
private slots:
void topicEventSent(const QString &topic);
void nameEventSent(const QString &name);
void error(const QString &msg);
void topicEventSent(const QString &topic);
void nameEventSent(const QString &name);
void error(const QString &msg);
void applyClicked();
void applyClicked();
private:
QString roomId_;
QString initialName_;
QString initialTopic_;
QString roomId_;
QString initialName_;
QString initialTopic_;
QLabel *errorField_;
QLabel *errorField_;
TextField *nameInput_;
TextField *topicInput_;
TextField *nameInput_;
TextField *topicInput_;
QPushButton *applyBtn_;
QPushButton *cancelBtn_;
QPushButton *applyBtn_;
QPushButton *cancelBtn_;
};
class RoomSettings : public QObject
{
Q_OBJECT
Q_PROPERTY(QString roomId READ roomId CONSTANT)
Q_PROPERTY(QString roomVersion READ roomVersion CONSTANT)
Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged)
Q_PROPERTY(QString roomTopic READ roomTopic NOTIFY roomTopicChanged)
Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl NOTIFY avatarUrlChanged)
Q_PROPERTY(int memberCount READ memberCount CONSTANT)
Q_PROPERTY(int notifications READ notifications NOTIFY notificationsChanged)
Q_PROPERTY(int accessJoinRules READ accessJoinRules NOTIFY accessJoinRulesChanged)
Q_PROPERTY(bool isLoading READ isLoading NOTIFY loadingChanged)
Q_PROPERTY(bool canChangeAvatar READ canChangeAvatar CONSTANT)
Q_PROPERTY(bool canChangeJoinRules READ canChangeJoinRules CONSTANT)
Q_PROPERTY(bool canChangeNameAndTopic READ canChangeNameAndTopic CONSTANT)
Q_PROPERTY(bool isEncryptionEnabled READ isEncryptionEnabled NOTIFY encryptionChanged)
Q_PROPERTY(bool supportsKnocking READ supportsKnocking CONSTANT)
Q_PROPERTY(bool supportsRestricted READ supportsRestricted CONSTANT)
Q_OBJECT
Q_PROPERTY(QString roomId READ roomId CONSTANT)
Q_PROPERTY(QString roomVersion READ roomVersion CONSTANT)
Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged)
Q_PROPERTY(QString roomTopic READ roomTopic NOTIFY roomTopicChanged)
Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl NOTIFY avatarUrlChanged)
Q_PROPERTY(int memberCount READ memberCount CONSTANT)
Q_PROPERTY(int notifications READ notifications NOTIFY notificationsChanged)
Q_PROPERTY(int accessJoinRules READ accessJoinRules NOTIFY accessJoinRulesChanged)
Q_PROPERTY(bool isLoading READ isLoading NOTIFY loadingChanged)
Q_PROPERTY(bool canChangeAvatar READ canChangeAvatar CONSTANT)
Q_PROPERTY(bool canChangeJoinRules READ canChangeJoinRules CONSTANT)
Q_PROPERTY(bool canChangeNameAndTopic READ canChangeNameAndTopic CONSTANT)
Q_PROPERTY(bool isEncryptionEnabled READ isEncryptionEnabled NOTIFY encryptionChanged)
Q_PROPERTY(bool supportsKnocking READ supportsKnocking CONSTANT)
Q_PROPERTY(bool supportsRestricted READ supportsRestricted CONSTANT)
public:
RoomSettings(QString roomid, QObject *parent = nullptr);
RoomSettings(QString roomid, QObject *parent = nullptr);
QString roomId() const;
QString roomName() const;
QString roomTopic() const;
QString roomVersion() const;
QString roomAvatarUrl();
int memberCount() const;
int notifications();
int accessJoinRules();
bool isLoading() const;
//! Whether the user has enough power level to send m.room.join_rules events.
bool canChangeJoinRules() const;
//! Whether the user has enough power level to send m.room.name & m.room.topic events.
bool canChangeNameAndTopic() const;
//! Whether the user has enough power level to send m.room.avatar event.
bool canChangeAvatar() const;
bool isEncryptionEnabled() const;
bool supportsKnocking() const;
bool supportsRestricted() const;
QString roomId() const;
QString roomName() const;
QString roomTopic() const;
QString roomVersion() const;
QString roomAvatarUrl();
int memberCount() const;
int notifications();
int accessJoinRules();
bool isLoading() const;
//! Whether the user has enough power level to send m.room.join_rules events.
bool canChangeJoinRules() const;
//! Whether the user has enough power level to send m.room.name & m.room.topic events.
bool canChangeNameAndTopic() const;
//! Whether the user has enough power level to send m.room.avatar event.
bool canChangeAvatar() const;
bool isEncryptionEnabled() const;
bool supportsKnocking() const;
bool supportsRestricted() const;
Q_INVOKABLE void enableEncryption();
Q_INVOKABLE void updateAvatar();
Q_INVOKABLE void openEditModal();
Q_INVOKABLE void changeAccessRules(int index);
Q_INVOKABLE void changeNotifications(int currentIndex);
Q_INVOKABLE void enableEncryption();
Q_INVOKABLE void updateAvatar();
Q_INVOKABLE void openEditModal();
Q_INVOKABLE void changeAccessRules(int index);
Q_INVOKABLE void changeNotifications(int currentIndex);
signals:
void loadingChanged();
void roomNameChanged();
void roomTopicChanged();
void avatarUrlChanged();
void encryptionChanged();
void notificationsChanged();
void accessJoinRulesChanged();
void displayError(const QString &errorMessage);
void loadingChanged();
void roomNameChanged();
void roomTopicChanged();
void avatarUrlChanged();
void encryptionChanged();
void notificationsChanged();
void accessJoinRulesChanged();
void displayError(const QString &errorMessage);
public slots:
void stopLoading();
void avatarChanged();
void stopLoading();
void avatarChanged();
private:
void retrieveRoomInfo();
void updateAccessRules(const std::string &room_id,
const mtx::events::state::JoinRules &,
const mtx::events::state::GuestAccess &);
void retrieveRoomInfo();
void updateAccessRules(const std::string &room_id,
const mtx::events::state::JoinRules &,
const mtx::events::state::GuestAccess &);
private:
QString roomid_;
bool usesEncryption_ = false;
bool isLoading_ = false;
RoomInfo info_;
int notifications_ = 0;
int accessRules_ = 0;
QString roomid_;
bool usesEncryption_ = false;
bool isLoading_ = false;
RoomInfo info_;
int notifications_ = 0;
int accessRules_ = 0;
};

View file

@ -15,121 +15,121 @@ SnackBar::SnackBar(QWidget *parent)
: OverlayWidget(parent)
, offset_anim(this, "offset", this)
{
QFont font;
font.setPointSizeF(font.pointSizeF() * 1.2);
font.setWeight(50);
setFont(font);
QFont font;
font.setPointSizeF(font.pointSizeF() * 1.2);
font.setWeight(50);
setFont(font);
boxHeight_ = QFontMetrics(font).height() * 2;
offset_ = STARTING_OFFSET;
position_ = SnackBarPosition::Top;
boxHeight_ = QFontMetrics(font).height() * 2;
offset_ = STARTING_OFFSET;
position_ = SnackBarPosition::Top;
hideTimer_.setSingleShot(true);
hideTimer_.setSingleShot(true);
offset_anim.setStartValue(1.0);
offset_anim.setEndValue(0.0);
offset_anim.setDuration(100);
offset_anim.setEasingCurve(QEasingCurve::OutCubic);
offset_anim.setStartValue(1.0);
offset_anim.setEndValue(0.0);
offset_anim.setDuration(100);
offset_anim.setEasingCurve(QEasingCurve::OutCubic);
connect(this, &SnackBar::offsetChanged, this, [this]() mutable { repaint(); });
connect(
&offset_anim, &QPropertyAnimation::finished, this, [this]() { hideTimer_.start(10000); });
connect(this, &SnackBar::offsetChanged, this, [this]() mutable { repaint(); });
connect(
&offset_anim, &QPropertyAnimation::finished, this, [this]() { hideTimer_.start(10000); });
connect(&hideTimer_, SIGNAL(timeout()), this, SLOT(hideMessage()));
connect(&hideTimer_, SIGNAL(timeout()), this, SLOT(hideMessage()));
hide();
hide();
}
void
SnackBar::start()
{
if (messages_.empty())
return;
if (messages_.empty())
return;
show();
raise();
show();
raise();
offset_anim.start();
offset_anim.start();
}
void
SnackBar::hideMessage()
{
stopTimers();
hide();
stopTimers();
hide();
if (!messages_.empty())
// Moving on to the next message.
messages_.pop_front();
if (!messages_.empty())
// Moving on to the next message.
messages_.pop_front();
// Resetting the starting position of the widget.
offset_ = STARTING_OFFSET;
// Resetting the starting position of the widget.
offset_ = STARTING_OFFSET;
if (!messages_.empty())
start();
if (!messages_.empty())
start();
}
void
SnackBar::stopTimers()
{
hideTimer_.stop();
hideTimer_.stop();
}
void
SnackBar::showMessage(const QString &msg)
{
messages_.push_back(msg);
messages_.push_back(msg);
// There is already an active message.
if (isVisible())
return;
// There is already an active message.
if (isVisible())
return;
start();
start();
}
void
SnackBar::mousePressEvent(QMouseEvent *)
{
hideMessage();
hideMessage();
}
void
SnackBar::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
Q_UNUSED(event)
if (messages_.empty())
return;
if (messages_.empty())
return;
auto message_ = messages_.front();
auto message_ = messages_.front();
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
QBrush brush;
brush.setStyle(Qt::SolidPattern);
brush.setColor(bgColor_);
p.setBrush(brush);
QBrush brush;
brush.setStyle(Qt::SolidPattern);
brush.setColor(bgColor_);
p.setBrush(brush);
QRect r(0, 0, std::max(MIN_WIDTH, width() * MIN_WIDTH_PERCENTAGE), boxHeight_);
QRect r(0, 0, std::max(MIN_WIDTH, width() * MIN_WIDTH_PERCENTAGE), boxHeight_);
p.setPen(Qt::white);
QRect br = p.boundingRect(r, Qt::AlignHCenter | Qt::AlignTop | Qt::TextWordWrap, message_);
p.setPen(Qt::white);
QRect br = p.boundingRect(r, Qt::AlignHCenter | Qt::AlignTop | Qt::TextWordWrap, message_);
p.setPen(Qt::NoPen);
r = br.united(r).adjusted(-BOX_PADDING, -BOX_PADDING, BOX_PADDING, BOX_PADDING);
p.setPen(Qt::NoPen);
r = br.united(r).adjusted(-BOX_PADDING, -BOX_PADDING, BOX_PADDING, BOX_PADDING);
const qreal s = 1 - offset_;
const qreal s = 1 - offset_;
if (position_ == SnackBarPosition::Bottom)
p.translate((width() - (r.width() - 2 * BOX_PADDING)) / 2,
height() - BOX_PADDING - s * (r.height()));
else
p.translate((width() - (r.width() - 2 * BOX_PADDING)) / 2,
s * (r.height()) - 2 * BOX_PADDING);
if (position_ == SnackBarPosition::Bottom)
p.translate((width() - (r.width() - 2 * BOX_PADDING)) / 2,
height() - BOX_PADDING - s * (r.height()));
else
p.translate((width() - (r.width() - 2 * BOX_PADDING)) / 2,
s * (r.height()) - 2 * BOX_PADDING);
br.moveCenter(r.center());
p.drawRoundedRect(r.adjusted(0, 0, 0, 4), 4, 4);
p.setPen(textColor_);
p.drawText(br, Qt::AlignHCenter | Qt::AlignTop | Qt::TextWordWrap, message_);
br.moveCenter(r.center());
p.drawRoundedRect(r.adjusted(0, 0, 0, 4), 4, 4);
p.setPen(textColor_);
p.drawText(br, Qt::AlignHCenter | Qt::AlignTop | Qt::TextWordWrap, message_);
}

View file

@ -14,79 +14,79 @@
enum class SnackBarPosition
{
Bottom,
Top,
Bottom,
Top,
};
class SnackBar : public OverlayWidget
{
Q_OBJECT
Q_OBJECT
Q_PROPERTY(QColor bgColor READ backgroundColor WRITE setBackgroundColor)
Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor)
Q_PROPERTY(double offset READ offset WRITE setOffset NOTIFY offsetChanged)
Q_PROPERTY(QColor bgColor READ backgroundColor WRITE setBackgroundColor)
Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor)
Q_PROPERTY(double offset READ offset WRITE setOffset NOTIFY offsetChanged)
public:
explicit SnackBar(QWidget *parent);
explicit SnackBar(QWidget *parent);
QColor backgroundColor() const { return bgColor_; }
void setBackgroundColor(const QColor &color)
{
bgColor_ = color;
update();
}
QColor backgroundColor() const { return bgColor_; }
void setBackgroundColor(const QColor &color)
{
bgColor_ = color;
update();
}
QColor textColor() const { return textColor_; }
void setTextColor(const QColor &color)
{
textColor_ = color;
update();
}
void setPosition(SnackBarPosition pos)
{
position_ = pos;
update();
}
QColor textColor() const { return textColor_; }
void setTextColor(const QColor &color)
{
textColor_ = color;
update();
}
void setPosition(SnackBarPosition pos)
{
position_ = pos;
update();
}
double offset() { return offset_; }
void setOffset(double offset)
{
if (offset != offset_) {
offset_ = offset;
emit offsetChanged();
}
double offset() { return offset_; }
void setOffset(double offset)
{
if (offset != offset_) {
offset_ = offset;
emit offsetChanged();
}
}
public slots:
void showMessage(const QString &msg);
void showMessage(const QString &msg);
signals:
void offsetChanged();
void offsetChanged();
protected:
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
private slots:
void hideMessage();
void hideMessage();
private:
void stopTimers();
void start();
void stopTimers();
void start();
QColor bgColor_;
QColor textColor_;
QColor bgColor_;
QColor textColor_;
qreal bgOpacity_;
qreal offset_;
qreal bgOpacity_;
qreal offset_;
std::deque<QString> messages_;
std::deque<QString> messages_;
QTimer hideTimer_;
QTimer hideTimer_;
double boxHeight_;
double boxHeight_;
QPropertyAnimation offset_anim;
QPropertyAnimation offset_anim;
SnackBarPosition position_;
SnackBarPosition position_;
};

View file

@ -15,363 +15,363 @@
TextField::TextField(QWidget *parent)
: QLineEdit(parent)
{
// Get rid of the focus border on macOS.
setAttribute(Qt::WA_MacShowFocusRect, 0);
// Get rid of the focus border on macOS.
setAttribute(Qt::WA_MacShowFocusRect, 0);
QPalette pal;
QPalette pal;
state_machine_ = new TextFieldStateMachine(this);
label_ = nullptr;
label_font_size_ = 15;
show_label_ = false;
background_color_ = pal.color(QPalette::Window);
is_valid_ = true;
state_machine_ = new TextFieldStateMachine(this);
label_ = nullptr;
label_font_size_ = 15;
show_label_ = false;
background_color_ = pal.color(QPalette::Window);
is_valid_ = true;
setFrame(false);
setAttribute(Qt::WA_Hover);
setMouseTracking(true);
setTextMargins(0, 4, 0, 6);
setFrame(false);
setAttribute(Qt::WA_Hover);
setMouseTracking(true);
setTextMargins(0, 4, 0, 6);
state_machine_->start();
QCoreApplication::processEvents();
state_machine_->start();
QCoreApplication::processEvents();
}
void
TextField::setBackgroundColor(const QColor &color)
{
background_color_ = color;
background_color_ = color;
}
QColor
TextField::backgroundColor() const
{
return background_color_;
return background_color_;
}
void
TextField::setShowLabel(bool value)
{
if (show_label_ == value) {
return;
}
if (show_label_ == value) {
return;
}
show_label_ = value;
show_label_ = value;
if (!label_ && value) {
label_ = new TextFieldLabel(this);
state_machine_->setLabel(label_);
}
if (!label_ && value) {
label_ = new TextFieldLabel(this);
state_machine_->setLabel(label_);
}
if (value) {
setContentsMargins(0, 23, 0, 0);
} else {
setContentsMargins(0, 0, 0, 0);
}
if (value) {
setContentsMargins(0, 23, 0, 0);
} else {
setContentsMargins(0, 0, 0, 0);
}
}
bool
TextField::hasLabel() const
{
return show_label_;
return show_label_;
}
void
TextField::setValid(bool valid)
{
is_valid_ = valid;
is_valid_ = valid;
}
bool
TextField::isValid() const
{
QString s = text();
int pos = 0;
if (regexp_.pattern().isEmpty()) {
return is_valid_;
}
QRegularExpressionValidator v(QRegularExpression(regexp_), 0);
return v.validate(s, pos) == QValidator::Acceptable;
QString s = text();
int pos = 0;
if (regexp_.pattern().isEmpty()) {
return is_valid_;
}
QRegularExpressionValidator v(QRegularExpression(regexp_), 0);
return v.validate(s, pos) == QValidator::Acceptable;
}
void
TextField::setLabelFontSize(qreal size)
{
label_font_size_ = size;
label_font_size_ = size;
if (label_) {
QFont font(label_->font());
font.setPointSizeF(size);
label_->setFont(font);
label_->update();
}
if (label_) {
QFont font(label_->font());
font.setPointSizeF(size);
label_->setFont(font);
label_->update();
}
}
qreal
TextField::labelFontSize() const
{
return label_font_size_;
return label_font_size_;
}
void
TextField::setLabel(const QString &label)
{
label_text_ = label;
setShowLabel(true);
label_->update();
label_text_ = label;
setShowLabel(true);
label_->update();
}
QString
TextField::label() const
{
return label_text_;
return label_text_;
}
void
TextField::setLabelColor(const QColor &color)
{
label_color_ = color;
update();
label_color_ = color;
update();
}
QColor
TextField::labelColor() const
{
if (!label_color_.isValid()) {
return QPalette().color(QPalette::Text);
}
if (!label_color_.isValid()) {
return QPalette().color(QPalette::Text);
}
return label_color_;
return label_color_;
}
void
TextField::setInkColor(const QColor &color)
{
ink_color_ = color;
update();
ink_color_ = color;
update();
}
QColor
TextField::inkColor() const
{
if (!ink_color_.isValid()) {
return QPalette().color(QPalette::Text);
}
if (!ink_color_.isValid()) {
return QPalette().color(QPalette::Text);
}
return ink_color_;
return ink_color_;
}
void
TextField::setUnderlineColor(const QColor &color)
{
underline_color_ = color;
update();
underline_color_ = color;
update();
}
void
TextField::setRegexp(const QRegularExpression &regexp)
{
regexp_ = regexp;
regexp_ = regexp;
}
QColor
TextField::underlineColor() const
{
if (!underline_color_.isValid()) {
if ((hasAcceptableInput() && isValid()) || !isModified())
return QPalette().color(QPalette::Highlight);
else
return Qt::red;
}
if (!underline_color_.isValid()) {
if ((hasAcceptableInput() && isValid()) || !isModified())
return QPalette().color(QPalette::Highlight);
else
return Qt::red;
}
return underline_color_;
return underline_color_;
}
bool
TextField::event(QEvent *event)
{
switch (event->type()) {
case QEvent::Resize:
case QEvent::Move: {
if (label_)
label_->setGeometry(rect());
break;
}
default:
break;
}
switch (event->type()) {
case QEvent::Resize:
case QEvent::Move: {
if (label_)
label_->setGeometry(rect());
break;
}
default:
break;
}
return QLineEdit::event(event);
return QLineEdit::event(event);
}
void
TextField::paintEvent(QPaintEvent *event)
{
QLineEdit::paintEvent(event);
QLineEdit::paintEvent(event);
QPainter painter(this);
QPainter painter(this);
if (text().isEmpty()) {
painter.setOpacity(1 - state_machine_->progress());
painter.fillRect(rect(), backgroundColor());
}
if (text().isEmpty()) {
painter.setOpacity(1 - state_machine_->progress());
painter.fillRect(rect(), backgroundColor());
}
const int y = height() - 1;
const int wd = width() - 5;
const int y = height() - 1;
const int wd = width() - 5;
QPen pen;
pen.setWidth(1);
pen.setColor(underlineColor());
painter.setPen(pen);
painter.setOpacity(1);
painter.drawLine(2, y, wd, y);
QPen pen;
pen.setWidth(1);
pen.setColor(underlineColor());
painter.setPen(pen);
painter.setOpacity(1);
painter.drawLine(2, y, wd, y);
QBrush brush;
brush.setStyle(Qt::SolidPattern);
brush.setColor(inkColor());
QBrush brush;
brush.setStyle(Qt::SolidPattern);
brush.setColor(inkColor());
const qreal progress = state_machine_->progress();
const qreal progress = state_machine_->progress();
if (progress > 0) {
painter.setPen(Qt::NoPen);
painter.setBrush(brush);
const int w = (1 - progress) * static_cast<qreal>(wd / 2);
painter.drawRect(w + 2.5, height() - 2, wd - 2 * w, 2);
}
if (progress > 0) {
painter.setPen(Qt::NoPen);
painter.setBrush(brush);
const int w = (1 - progress) * static_cast<qreal>(wd / 2);
painter.drawRect(w + 2.5, height() - 2, wd - 2 * w, 2);
}
}
TextFieldStateMachine::TextFieldStateMachine(TextField *parent)
: QStateMachine(parent)
, text_field_(parent)
{
normal_state_ = new QState;
focused_state_ = new QState;
normal_state_ = new QState;
focused_state_ = new QState;
label_ = nullptr;
offset_anim_ = nullptr;
color_anim_ = nullptr;
progress_ = 0.0;
label_ = nullptr;
offset_anim_ = nullptr;
color_anim_ = nullptr;
progress_ = 0.0;
addState(normal_state_);
addState(focused_state_);
addState(normal_state_);
addState(focused_state_);
setInitialState(normal_state_);
setInitialState(normal_state_);
QEventTransition *transition;
QPropertyAnimation *animation;
QEventTransition *transition;
QPropertyAnimation *animation;
transition = new QEventTransition(parent, QEvent::FocusIn);
transition->setTargetState(focused_state_);
normal_state_->addTransition(transition);
transition = new QEventTransition(parent, QEvent::FocusIn);
transition->setTargetState(focused_state_);
normal_state_->addTransition(transition);
animation = new QPropertyAnimation(this, "progress", this);
animation->setEasingCurve(QEasingCurve::InCubic);
animation->setDuration(310);
transition->addAnimation(animation);
animation = new QPropertyAnimation(this, "progress", this);
animation->setEasingCurve(QEasingCurve::InCubic);
animation->setDuration(310);
transition->addAnimation(animation);
transition = new QEventTransition(parent, QEvent::FocusOut);
transition->setTargetState(normal_state_);
focused_state_->addTransition(transition);
transition = new QEventTransition(parent, QEvent::FocusOut);
transition->setTargetState(normal_state_);
focused_state_->addTransition(transition);
animation = new QPropertyAnimation(this, "progress", this);
animation->setEasingCurve(QEasingCurve::OutCubic);
animation->setDuration(310);
transition->addAnimation(animation);
animation = new QPropertyAnimation(this, "progress", this);
animation->setEasingCurve(QEasingCurve::OutCubic);
animation->setDuration(310);
transition->addAnimation(animation);
normal_state_->assignProperty(this, "progress", 0);
focused_state_->assignProperty(this, "progress", 1);
normal_state_->assignProperty(this, "progress", 0);
focused_state_->assignProperty(this, "progress", 1);
setupProperties();
setupProperties();
connect(text_field_, SIGNAL(textChanged(QString)), this, SLOT(setupProperties()));
connect(text_field_, SIGNAL(textChanged(QString)), this, SLOT(setupProperties()));
}
void
TextFieldStateMachine::setLabel(TextFieldLabel *label)
{
if (label_) {
delete label_;
}
if (label_) {
delete label_;
}
if (offset_anim_) {
removeDefaultAnimation(offset_anim_);
delete offset_anim_;
}
if (offset_anim_) {
removeDefaultAnimation(offset_anim_);
delete offset_anim_;
}
if (color_anim_) {
removeDefaultAnimation(color_anim_);
delete color_anim_;
}
if (color_anim_) {
removeDefaultAnimation(color_anim_);
delete color_anim_;
}
label_ = label;
label_ = label;
if (label_) {
offset_anim_ = new QPropertyAnimation(label_, "offset", this);
offset_anim_->setDuration(210);
offset_anim_->setEasingCurve(QEasingCurve::OutCubic);
addDefaultAnimation(offset_anim_);
if (label_) {
offset_anim_ = new QPropertyAnimation(label_, "offset", this);
offset_anim_->setDuration(210);
offset_anim_->setEasingCurve(QEasingCurve::OutCubic);
addDefaultAnimation(offset_anim_);
color_anim_ = new QPropertyAnimation(label_, "color", this);
color_anim_->setDuration(210);
addDefaultAnimation(color_anim_);
}
color_anim_ = new QPropertyAnimation(label_, "color", this);
color_anim_->setDuration(210);
addDefaultAnimation(color_anim_);
}
setupProperties();
setupProperties();
}
void
TextFieldStateMachine::setupProperties()
{
if (label_) {
const int m = text_field_->textMargins().top();
if (label_) {
const int m = text_field_->textMargins().top();
if (text_field_->text().isEmpty()) {
normal_state_->assignProperty(label_, "offset", QPointF(0, 26));
} else {
normal_state_->assignProperty(label_, "offset", QPointF(0, 0 - m));
}
focused_state_->assignProperty(label_, "offset", QPointF(0, 0 - m));
focused_state_->assignProperty(label_, "color", text_field_->inkColor());
normal_state_->assignProperty(label_, "color", text_field_->labelColor());
if (0 != label_->offset().y() && !text_field_->text().isEmpty()) {
label_->setOffset(QPointF(0, 0 - m));
} else if (!text_field_->hasFocus() && label_->offset().y() <= 0 &&
text_field_->text().isEmpty()) {
label_->setOffset(QPointF(0, 26));
}
if (text_field_->text().isEmpty()) {
normal_state_->assignProperty(label_, "offset", QPointF(0, 26));
} else {
normal_state_->assignProperty(label_, "offset", QPointF(0, 0 - m));
}
text_field_->update();
focused_state_->assignProperty(label_, "offset", QPointF(0, 0 - m));
focused_state_->assignProperty(label_, "color", text_field_->inkColor());
normal_state_->assignProperty(label_, "color", text_field_->labelColor());
if (0 != label_->offset().y() && !text_field_->text().isEmpty()) {
label_->setOffset(QPointF(0, 0 - m));
} else if (!text_field_->hasFocus() && label_->offset().y() <= 0 &&
text_field_->text().isEmpty()) {
label_->setOffset(QPointF(0, 26));
}
}
text_field_->update();
}
TextFieldLabel::TextFieldLabel(TextField *parent)
: QWidget(parent)
, text_field_(parent)
{
x_ = 0;
y_ = 26;
scale_ = 1;
color_ = parent->labelColor();
x_ = 0;
y_ = 26;
scale_ = 1;
color_ = parent->labelColor();
QFont font;
font.setWeight(60);
font.setLetterSpacing(QFont::PercentageSpacing, 102);
setFont(font);
QFont font;
font.setWeight(60);
font.setLetterSpacing(QFont::PercentageSpacing, 102);
setFont(font);
}
void
TextFieldLabel::paintEvent(QPaintEvent *)
{
if (!text_field_->hasLabel())
return;
if (!text_field_->hasLabel())
return;
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.scale(scale_, scale_);
painter.setPen(color_);
painter.setOpacity(1);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.scale(scale_, scale_);
painter.setPen(color_);
painter.setOpacity(1);
QPointF pos(2 + x_, height() - 36 + y_);
painter.drawText(pos.x(), pos.y(), text_field_->label());
QPointF pos(2 + x_, height() - 36 + y_);
painter.drawText(pos.x(), pos.y(), text_field_->label());
}

View file

@ -18,163 +18,163 @@ class TextFieldStateMachine;
class TextField : public QLineEdit
{
Q_OBJECT
Q_OBJECT
Q_PROPERTY(QColor inkColor WRITE setInkColor READ inkColor)
Q_PROPERTY(QColor labelColor WRITE setLabelColor READ labelColor)
Q_PROPERTY(QColor underlineColor WRITE setUnderlineColor READ underlineColor)
Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor)
Q_PROPERTY(QColor inkColor WRITE setInkColor READ inkColor)
Q_PROPERTY(QColor labelColor WRITE setLabelColor READ labelColor)
Q_PROPERTY(QColor underlineColor WRITE setUnderlineColor READ underlineColor)
Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor)
public:
explicit TextField(QWidget *parent = nullptr);
explicit TextField(QWidget *parent = nullptr);
void setInkColor(const QColor &color);
void setBackgroundColor(const QColor &color);
void setLabel(const QString &label);
void setLabelColor(const QColor &color);
void setLabelFontSize(qreal size);
void setShowLabel(bool value);
void setUnderlineColor(const QColor &color);
void setRegexp(const QRegularExpression &regexp);
void setValid(bool valid);
void setInkColor(const QColor &color);
void setBackgroundColor(const QColor &color);
void setLabel(const QString &label);
void setLabelColor(const QColor &color);
void setLabelFontSize(qreal size);
void setShowLabel(bool value);
void setUnderlineColor(const QColor &color);
void setRegexp(const QRegularExpression &regexp);
void setValid(bool valid);
QColor inkColor() const;
QColor labelColor() const;
QColor underlineColor() const;
QColor backgroundColor() const;
QString label() const;
bool hasLabel() const;
bool isValid() const;
qreal labelFontSize() const;
QColor inkColor() const;
QColor labelColor() const;
QColor underlineColor() const;
QColor backgroundColor() const;
QString label() const;
bool hasLabel() const;
bool isValid() const;
qreal labelFontSize() const;
protected:
bool event(QEvent *event) override;
void paintEvent(QPaintEvent *event) override;
bool event(QEvent *event) override;
void paintEvent(QPaintEvent *event) override;
private:
void init();
void init();
QColor ink_color_;
QColor background_color_;
QColor label_color_;
QColor underline_color_;
QString label_text_;
TextFieldLabel *label_;
TextFieldStateMachine *state_machine_;
bool show_label_;
QRegularExpression regexp_;
bool is_valid_;
qreal label_font_size_;
QColor ink_color_;
QColor background_color_;
QColor label_color_;
QColor underline_color_;
QString label_text_;
TextFieldLabel *label_;
TextFieldStateMachine *state_machine_;
bool show_label_;
QRegularExpression regexp_;
bool is_valid_;
qreal label_font_size_;
};
class TextFieldLabel : public QWidget
{
Q_OBJECT
Q_OBJECT
Q_PROPERTY(qreal scale WRITE setScale READ scale)
Q_PROPERTY(QPointF offset WRITE setOffset READ offset)
Q_PROPERTY(QColor color WRITE setColor READ color)
Q_PROPERTY(qreal scale WRITE setScale READ scale)
Q_PROPERTY(QPointF offset WRITE setOffset READ offset)
Q_PROPERTY(QColor color WRITE setColor READ color)
public:
TextFieldLabel(TextField *parent);
TextFieldLabel(TextField *parent);
inline void setColor(const QColor &color);
inline void setOffset(const QPointF &pos);
inline void setScale(qreal scale);
inline void setColor(const QColor &color);
inline void setOffset(const QPointF &pos);
inline void setScale(qreal scale);
inline QColor color() const;
inline QPointF offset() const;
inline qreal scale() const;
inline QColor color() const;
inline QPointF offset() const;
inline qreal scale() const;
protected:
void paintEvent(QPaintEvent *event) override;
void paintEvent(QPaintEvent *event) override;
private:
TextField *const text_field_;
TextField *const text_field_;
QColor color_;
qreal scale_;
qreal x_;
qreal y_;
QColor color_;
qreal scale_;
qreal x_;
qreal y_;
};
inline void
TextFieldLabel::setColor(const QColor &color)
{
color_ = color;
update();
color_ = color;
update();
}
inline void
TextFieldLabel::setOffset(const QPointF &pos)
{
x_ = pos.x();
y_ = pos.y();
update();
x_ = pos.x();
y_ = pos.y();
update();
}
inline void
TextFieldLabel::setScale(qreal scale)
{
scale_ = scale;
update();
scale_ = scale;
update();
}
inline QPointF
TextFieldLabel::offset() const
{
return QPointF(x_, y_);
return QPointF(x_, y_);
}
inline qreal
TextFieldLabel::scale() const
{
return scale_;
return scale_;
}
inline QColor
TextFieldLabel::color() const
{
return color_;
return color_;
}
class TextFieldStateMachine : public QStateMachine
{
Q_OBJECT
Q_OBJECT
Q_PROPERTY(qreal progress WRITE setProgress READ progress)
Q_PROPERTY(qreal progress WRITE setProgress READ progress)
public:
TextFieldStateMachine(TextField *parent);
TextFieldStateMachine(TextField *parent);
inline void setProgress(qreal progress);
void setLabel(TextFieldLabel *label);
inline void setProgress(qreal progress);
void setLabel(TextFieldLabel *label);
inline qreal progress() const;
inline qreal progress() const;
public slots:
void setupProperties();
void setupProperties();
private:
QPropertyAnimation *color_anim_;
QPropertyAnimation *offset_anim_;
QPropertyAnimation *color_anim_;
QPropertyAnimation *offset_anim_;
QState *focused_state_;
QState *normal_state_;
QState *focused_state_;
QState *normal_state_;
TextField *text_field_;
TextFieldLabel *label_;
TextField *text_field_;
TextFieldLabel *label_;
qreal progress_;
qreal progress_;
};
inline void
TextFieldStateMachine::setProgress(qreal progress)
{
progress_ = progress;
text_field_->update();
progress_ = progress;
text_field_->update();
}
inline qreal
TextFieldStateMachine::progress() const
{
return progress_;
return progress_;
}

View file

@ -14,12 +14,12 @@
bool
ContextMenuFilter::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::MouseButtonPress) {
emit contextMenuIsOpening();
return true;
}
if (event->type() == QEvent::MouseButtonPress) {
emit contextMenuIsOpening();
return true;
}
return QObject::eventFilter(obj, event);
return QObject::eventFilter(obj, event);
}
TextLabel::TextLabel(QWidget *parent)
@ -29,94 +29,94 @@ TextLabel::TextLabel(QWidget *parent)
TextLabel::TextLabel(const QString &text, QWidget *parent)
: QTextBrowser(parent)
{
document()->setDefaultStyleSheet(QString("a {color: %1; }").arg(utils::linkColor()));
document()->setDefaultStyleSheet(QString("a {color: %1; }").arg(utils::linkColor()));
setText(text);
setOpenExternalLinks(true);
setText(text);
setOpenExternalLinks(true);
// Make it look and feel like an ordinary label.
setReadOnly(true);
setFrameStyle(QFrame::NoFrame);
QPalette pal = palette();
pal.setColor(QPalette::Base, Qt::transparent);
setPalette(pal);
// Make it look and feel like an ordinary label.
setReadOnly(true);
setFrameStyle(QFrame::NoFrame);
QPalette pal = palette();
pal.setColor(QPalette::Base, Qt::transparent);
setPalette(pal);
// Wrap anywhere but prefer words, adjust minimum height on the fly.
setLineWrapMode(QTextEdit::WidgetWidth);
setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
connect(document()->documentLayout(),
&QAbstractTextDocumentLayout::documentSizeChanged,
this,
&TextLabel::adjustHeight);
document()->setDocumentMargin(0);
// Wrap anywhere but prefer words, adjust minimum height on the fly.
setLineWrapMode(QTextEdit::WidgetWidth);
setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
connect(document()->documentLayout(),
&QAbstractTextDocumentLayout::documentSizeChanged,
this,
&TextLabel::adjustHeight);
document()->setDocumentMargin(0);
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
setFixedHeight(0);
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
setFixedHeight(0);
connect(this, &TextLabel::linkActivated, this, &TextLabel::handleLinkActivation);
connect(this, &TextLabel::linkActivated, this, &TextLabel::handleLinkActivation);
auto filter = new ContextMenuFilter(this);
installEventFilter(filter);
connect(filter, &ContextMenuFilter::contextMenuIsOpening, this, [this]() {
contextMenuRequested_ = true;
});
auto filter = new ContextMenuFilter(this);
installEventFilter(filter);
connect(filter, &ContextMenuFilter::contextMenuIsOpening, this, [this]() {
contextMenuRequested_ = true;
});
}
void
TextLabel::focusOutEvent(QFocusEvent *e)
{
QTextBrowser::focusOutEvent(e);
QTextBrowser::focusOutEvent(e);
// We keep the selection available for the context menu.
if (contextMenuRequested_) {
contextMenuRequested_ = false;
return;
}
// We keep the selection available for the context menu.
if (contextMenuRequested_) {
contextMenuRequested_ = false;
return;
}
QTextCursor cursor = textCursor();
cursor.clearSelection();
setTextCursor(cursor);
QTextCursor cursor = textCursor();
cursor.clearSelection();
setTextCursor(cursor);
}
void
TextLabel::mousePressEvent(QMouseEvent *e)
{
link_ = (e->button() & Qt::LeftButton) ? anchorAt(e->pos()) : QString();
QTextBrowser::mousePressEvent(e);
link_ = (e->button() & Qt::LeftButton) ? anchorAt(e->pos()) : QString();
QTextBrowser::mousePressEvent(e);
}
void
TextLabel::mouseReleaseEvent(QMouseEvent *e)
{
if (e->button() & Qt::LeftButton && !link_.isEmpty() && anchorAt(e->pos()) == link_) {
emit linkActivated(link_);
return;
}
if (e->button() & Qt::LeftButton && !link_.isEmpty() && anchorAt(e->pos()) == link_) {
emit linkActivated(link_);
return;
}
QTextBrowser::mouseReleaseEvent(e);
QTextBrowser::mouseReleaseEvent(e);
}
void
TextLabel::wheelEvent(QWheelEvent *event)
{
event->ignore();
event->ignore();
}
void
TextLabel::handleLinkActivation(const QUrl &url)
{
auto parts = url.toString().split('/');
auto defaultHandler = [](const QUrl &url) { QDesktopServices::openUrl(url); };
auto parts = url.toString().split('/');
auto defaultHandler = [](const QUrl &url) { QDesktopServices::openUrl(url); };
if (url.host() != "matrix.to" || parts.isEmpty())
return defaultHandler(url);
if (url.host() != "matrix.to" || parts.isEmpty())
return defaultHandler(url);
try {
using namespace mtx::identifiers;
parse<User>(parts.last().toStdString());
} catch (const std::exception &) {
return defaultHandler(url);
}
try {
using namespace mtx::identifiers;
parse<User>(parts.last().toStdString());
} catch (const std::exception &) {
return defaultHandler(url);
}
emit userProfileTriggered(parts.last());
emit userProfileTriggered(parts.last());
}

View file

@ -15,45 +15,45 @@ class QWheelEvent;
class ContextMenuFilter : public QObject
{
Q_OBJECT
Q_OBJECT
public:
explicit ContextMenuFilter(QWidget *parent)
: QObject(parent)
{}
explicit ContextMenuFilter(QWidget *parent)
: QObject(parent)
{}
signals:
void contextMenuIsOpening();
void contextMenuIsOpening();
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
bool eventFilter(QObject *obj, QEvent *event) override;
};
class TextLabel : public QTextBrowser
{
Q_OBJECT
Q_OBJECT
public:
TextLabel(const QString &text, QWidget *parent = nullptr);
TextLabel(QWidget *parent = nullptr);
TextLabel(const QString &text, QWidget *parent = nullptr);
TextLabel(QWidget *parent = nullptr);
void wheelEvent(QWheelEvent *event) override;
void clearLinks() { link_.clear(); }
void wheelEvent(QWheelEvent *event) override;
void clearLinks() { link_.clear(); }
protected:
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void focusOutEvent(QFocusEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void focusOutEvent(QFocusEvent *e) override;
private slots:
void adjustHeight(const QSizeF &size) { setFixedHeight(size.height()); }
void handleLinkActivation(const QUrl &link);
void adjustHeight(const QSizeF &size) { setFixedHeight(size.height()); }
void handleLinkActivation(const QUrl &link);
signals:
void userProfileTriggered(const QString &user_id);
void linkActivated(const QUrl &link);
void userProfileTriggered(const QString &user_id);
void linkActivated(const QUrl &link);
private:
QString link_;
bool contextMenuRequested_ = false;
QString link_;
bool contextMenuRequested_ = false;
};

View file

@ -9,66 +9,66 @@ Q_DECLARE_METATYPE(Theme)
QPalette
Theme::paletteFromTheme(std::string_view theme)
{
[[maybe_unused]] static auto meta = qRegisterMetaType<Theme>("Theme");
static QPalette original;
if (theme == "light") {
QPalette lightActive(
/*windowText*/ QColor("#333"),
/*button*/ QColor("white"),
/*light*/ QColor(0xef, 0xef, 0xef),
/*dark*/ QColor(70, 77, 93),
/*mid*/ QColor(220, 220, 220),
/*text*/ QColor("#333"),
/*bright_text*/ QColor("#f2f5f8"),
/*base*/ QColor("#fff"),
/*window*/ QColor("white"));
lightActive.setColor(QPalette::AlternateBase, QColor("#eee"));
lightActive.setColor(QPalette::Highlight, QColor("#38a3d8"));
lightActive.setColor(QPalette::HighlightedText, QColor("#f4f4f5"));
lightActive.setColor(QPalette::ToolTipBase, lightActive.base().color());
lightActive.setColor(QPalette::ToolTipText, lightActive.text().color());
lightActive.setColor(QPalette::Link, QColor("#0077b5"));
lightActive.setColor(QPalette::ButtonText, QColor("#555459"));
return lightActive;
} else if (theme == "dark") {
QPalette darkActive(
/*windowText*/ QColor("#caccd1"),
/*button*/ QColor(0xff, 0xff, 0xff),
/*light*/ QColor("#caccd1"),
/*dark*/ QColor(60, 70, 77),
/*mid*/ QColor("#202228"),
/*text*/ QColor("#caccd1"),
/*bright_text*/ QColor("#f4f5f8"),
/*base*/ QColor("#202228"),
/*window*/ QColor("#2d3139"));
darkActive.setColor(QPalette::AlternateBase, QColor("#2d3139"));
darkActive.setColor(QPalette::Highlight, QColor("#38a3d8"));
darkActive.setColor(QPalette::HighlightedText, QColor("#f4f5f8"));
darkActive.setColor(QPalette::ToolTipBase, darkActive.base().color());
darkActive.setColor(QPalette::ToolTipText, darkActive.text().color());
darkActive.setColor(QPalette::Link, QColor("#38a3d8"));
darkActive.setColor(QPalette::ButtonText, "#828284");
return darkActive;
} else {
return original;
}
[[maybe_unused]] static auto meta = qRegisterMetaType<Theme>("Theme");
static QPalette original;
if (theme == "light") {
QPalette lightActive(
/*windowText*/ QColor("#333"),
/*button*/ QColor("white"),
/*light*/ QColor(0xef, 0xef, 0xef),
/*dark*/ QColor(70, 77, 93),
/*mid*/ QColor(220, 220, 220),
/*text*/ QColor("#333"),
/*bright_text*/ QColor("#f2f5f8"),
/*base*/ QColor("#fff"),
/*window*/ QColor("white"));
lightActive.setColor(QPalette::AlternateBase, QColor("#eee"));
lightActive.setColor(QPalette::Highlight, QColor("#38a3d8"));
lightActive.setColor(QPalette::HighlightedText, QColor("#f4f4f5"));
lightActive.setColor(QPalette::ToolTipBase, lightActive.base().color());
lightActive.setColor(QPalette::ToolTipText, lightActive.text().color());
lightActive.setColor(QPalette::Link, QColor("#0077b5"));
lightActive.setColor(QPalette::ButtonText, QColor("#555459"));
return lightActive;
} else if (theme == "dark") {
QPalette darkActive(
/*windowText*/ QColor("#caccd1"),
/*button*/ QColor(0xff, 0xff, 0xff),
/*light*/ QColor("#caccd1"),
/*dark*/ QColor(60, 70, 77),
/*mid*/ QColor("#202228"),
/*text*/ QColor("#caccd1"),
/*bright_text*/ QColor("#f4f5f8"),
/*base*/ QColor("#202228"),
/*window*/ QColor("#2d3139"));
darkActive.setColor(QPalette::AlternateBase, QColor("#2d3139"));
darkActive.setColor(QPalette::Highlight, QColor("#38a3d8"));
darkActive.setColor(QPalette::HighlightedText, QColor("#f4f5f8"));
darkActive.setColor(QPalette::ToolTipBase, darkActive.base().color());
darkActive.setColor(QPalette::ToolTipText, darkActive.text().color());
darkActive.setColor(QPalette::Link, QColor("#38a3d8"));
darkActive.setColor(QPalette::ButtonText, "#828284");
return darkActive;
} else {
return original;
}
}
Theme::Theme(std::string_view theme)
{
auto p = paletteFromTheme(theme);
separator_ = p.mid().color();
if (theme == "light") {
sidebarBackground_ = QColor("#233649");
alternateButton_ = QColor("#ccc");
red_ = QColor("#a82353");
} else if (theme == "dark") {
sidebarBackground_ = QColor("#2d3139");
alternateButton_ = QColor("#414A59");
red_ = QColor("#a82353");
} else {
sidebarBackground_ = p.window().color();
alternateButton_ = p.dark().color();
red_ = QColor("red");
}
auto p = paletteFromTheme(theme);
separator_ = p.mid().color();
if (theme == "light") {
sidebarBackground_ = QColor("#233649");
alternateButton_ = QColor("#ccc");
red_ = QColor("#a82353");
} else if (theme == "dark") {
sidebarBackground_ = QColor("#2d3139");
alternateButton_ = QColor("#414A59");
red_ = QColor("#a82353");
} else {
sidebarBackground_ = p.window().color();
alternateButton_ = p.dark().color();
red_ = QColor("red");
}
}

View file

@ -16,62 +16,62 @@ const int AvatarSize = 40;
enum class ButtonPreset
{
FlatPreset,
CheckablePreset
FlatPreset,
CheckablePreset
};
enum class RippleStyle
{
CenteredRipple,
PositionedRipple,
NoRipple
CenteredRipple,
PositionedRipple,
NoRipple
};
enum class OverlayStyle
{
NoOverlay,
TintedOverlay,
GrayOverlay
NoOverlay,
TintedOverlay,
GrayOverlay
};
enum class Role
{
Default,
Primary,
Secondary
Default,
Primary,
Secondary
};
enum class ButtonIconPlacement
{
LeftIcon,
RightIcon
LeftIcon,
RightIcon
};
enum class ProgressType
{
DeterminateProgress,
IndeterminateProgress
DeterminateProgress,
IndeterminateProgress
};
} // namespace ui
class Theme : public QPalette
{
Q_GADGET
Q_PROPERTY(QColor sidebarBackground READ sidebarBackground CONSTANT)
Q_PROPERTY(QColor alternateButton READ alternateButton CONSTANT)
Q_PROPERTY(QColor separator READ separator CONSTANT)
Q_PROPERTY(QColor red READ red CONSTANT)
Q_GADGET
Q_PROPERTY(QColor sidebarBackground READ sidebarBackground CONSTANT)
Q_PROPERTY(QColor alternateButton READ alternateButton CONSTANT)
Q_PROPERTY(QColor separator READ separator CONSTANT)
Q_PROPERTY(QColor red READ red CONSTANT)
public:
Theme() {}
explicit Theme(std::string_view theme);
static QPalette paletteFromTheme(std::string_view theme);
Theme() {}
explicit Theme(std::string_view theme);
static QPalette paletteFromTheme(std::string_view theme);
QColor sidebarBackground() const { return sidebarBackground_; }
QColor alternateButton() const { return alternateButton_; }
QColor separator() const { return separator_; }
QColor red() const { return red_; }
QColor sidebarBackground() const { return sidebarBackground_; }
QColor alternateButton() const { return alternateButton_; }
QColor separator() const { return separator_; }
QColor red() const { return red_; }
private:
QColor sidebarBackground_, separator_, red_, alternateButton_;
QColor sidebarBackground_, separator_, red_, alternateButton_;
};

View file

@ -11,32 +11,32 @@ ThemeManager::ThemeManager() {}
QColor
ThemeManager::themeColor(const QString &key) const
{
if (key == "Black")
return QColor("#171919");
if (key == "Black")
return QColor("#171919");
else if (key == "BrightWhite")
return QColor("#EBEBEB");
else if (key == "FadedWhite")
return QColor("#C9C9C9");
else if (key == "MediumWhite")
return QColor("#929292");
else if (key == "BrightWhite")
return QColor("#EBEBEB");
else if (key == "FadedWhite")
return QColor("#C9C9C9");
else if (key == "MediumWhite")
return QColor("#929292");
else if (key == "BrightGreen")
return QColor("#1C3133");
else if (key == "DarkGreen")
return QColor("#577275");
else if (key == "LightGreen")
return QColor("#46A451");
else if (key == "BrightGreen")
return QColor("#1C3133");
else if (key == "DarkGreen")
return QColor("#577275");
else if (key == "LightGreen")
return QColor("#46A451");
else if (key == "Gray")
return QColor("#5D6565");
else if (key == "Red")
return QColor("#E22826");
else if (key == "Blue")
return QColor("#81B3A9");
else if (key == "Gray")
return QColor("#5D6565");
else if (key == "Red")
return QColor("#E22826");
else if (key == "Blue")
return QColor("#81B3A9");
else if (key == "Transparent")
return QColor(0, 0, 0, 0);
else if (key == "Transparent")
return QColor(0, 0, 0, 0);
return (QColor(0, 0, 0, 0));
return (QColor(0, 0, 0, 0));
}

View file

@ -8,23 +8,23 @@
class ThemeManager : public QCommonStyle
{
Q_OBJECT
Q_OBJECT
public:
inline static ThemeManager &instance();
inline static ThemeManager &instance();
QColor themeColor(const QString &key) const;
QColor themeColor(const QString &key) const;
private:
ThemeManager();
ThemeManager();
ThemeManager(ThemeManager const &);
void operator=(ThemeManager const &);
ThemeManager(ThemeManager const &);
void operator=(ThemeManager const &);
};
inline ThemeManager &
ThemeManager::instance()
{
static ThemeManager instance;
return instance;
static ThemeManager instance;
return instance;
}

View file

@ -12,84 +12,84 @@
void
Toggle::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
Q_UNUSED(event);
}
Toggle::Toggle(QWidget *parent)
: QAbstractButton{parent}
{
init();
init();
connect(this, &QAbstractButton::toggled, this, &Toggle::setState);
connect(this, &QAbstractButton::toggled, this, &Toggle::setState);
}
void
Toggle::setState(bool isEnabled)
{
setChecked(isEnabled);
thumb_->setShift(isEnabled ? Position::Left : Position::Right);
setupProperties();
setChecked(isEnabled);
thumb_->setShift(isEnabled ? Position::Left : Position::Right);
setupProperties();
}
void
Toggle::init()
{
track_ = new ToggleTrack(this);
thumb_ = new ToggleThumb(this);
track_ = new ToggleTrack(this);
thumb_ = new ToggleThumb(this);
setCursor(QCursor(Qt::PointingHandCursor));
setCheckable(true);
setChecked(false);
setCursor(QCursor(Qt::PointingHandCursor));
setCheckable(true);
setChecked(false);
setState(false);
setupProperties();
setState(false);
setupProperties();
QCoreApplication::processEvents();
QCoreApplication::processEvents();
}
void
Toggle::setupProperties()
{
if (isEnabled()) {
Position position = thumb_->shift();
if (isEnabled()) {
Position position = thumb_->shift();
thumb_->setThumbColor(trackColor());
thumb_->setThumbColor(trackColor());
if (position == Position::Left)
track_->setTrackColor(activeColor());
else if (position == Position::Right)
track_->setTrackColor(inactiveColor());
}
if (position == Position::Left)
track_->setTrackColor(activeColor());
else if (position == Position::Right)
track_->setTrackColor(inactiveColor());
}
update();
update();
}
void
Toggle::setDisabledColor(const QColor &color)
{
disabledColor_ = color;
setupProperties();
disabledColor_ = color;
setupProperties();
}
void
Toggle::setActiveColor(const QColor &color)
{
activeColor_ = color;
setupProperties();
activeColor_ = color;
setupProperties();
}
void
Toggle::setInactiveColor(const QColor &color)
{
inactiveColor_ = color;
setupProperties();
inactiveColor_ = color;
setupProperties();
}
void
Toggle::setTrackColor(const QColor &color)
{
trackColor_ = color;
setupProperties();
trackColor_ = color;
setupProperties();
}
ToggleThumb::ToggleThumb(Toggle *parent)
@ -98,119 +98,119 @@ ToggleThumb::ToggleThumb(Toggle *parent)
, position_{Position::Right}
, offset_{0}
{
parent->installEventFilter(this);
parent->installEventFilter(this);
}
void
ToggleThumb::setShift(Position position)
{
if (position_ != position) {
position_ = position;
updateOffset();
}
if (position_ != position) {
position_ = position;
updateOffset();
}
}
bool
ToggleThumb::eventFilter(QObject *obj, QEvent *event)
{
const QEvent::Type type = event->type();
const QEvent::Type type = event->type();
if (QEvent::Resize == type || QEvent::Move == type) {
setGeometry(toggle_->rect().adjusted(8, 8, -8, -8));
updateOffset();
}
if (QEvent::Resize == type || QEvent::Move == type) {
setGeometry(toggle_->rect().adjusted(8, 8, -8, -8));
updateOffset();
}
return QWidget::eventFilter(obj, event);
return QWidget::eventFilter(obj, event);
}
void
ToggleThumb::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
Q_UNUSED(event)
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QBrush brush;
brush.setStyle(Qt::SolidPattern);
brush.setColor(toggle_->isEnabled() ? thumbColor_ : Qt::white);
QBrush brush;
brush.setStyle(Qt::SolidPattern);
brush.setColor(toggle_->isEnabled() ? thumbColor_ : Qt::white);
painter.setBrush(brush);
painter.setPen(Qt::NoPen);
int s;
QRectF r;
s = height() - 10;
r = QRectF(5 + offset_, 5, s, s);
painter.drawEllipse(r);
if (!toggle_->isEnabled()) {
brush.setColor(toggle_->disabledColor());
painter.setBrush(brush);
painter.setPen(Qt::NoPen);
int s;
QRectF r;
s = height() - 10;
r = QRectF(5 + offset_, 5, s, s);
painter.drawEllipse(r);
if (!toggle_->isEnabled()) {
brush.setColor(toggle_->disabledColor());
painter.setBrush(brush);
painter.drawEllipse(r);
}
}
}
void
ToggleThumb::updateOffset()
{
const QSize s(size());
offset_ = position_ == Position::Left ? static_cast<qreal>(s.width() - s.height()) : 0;
update();
const QSize s(size());
offset_ = position_ == Position::Left ? static_cast<qreal>(s.width() - s.height()) : 0;
update();
}
ToggleTrack::ToggleTrack(Toggle *parent)
: QWidget{parent}
, toggle_{parent}
{
Q_ASSERT(parent);
Q_ASSERT(parent);
parent->installEventFilter(this);
parent->installEventFilter(this);
}
void
ToggleTrack::setTrackColor(const QColor &color)
{
trackColor_ = color;
update();
trackColor_ = color;
update();
}
bool
ToggleTrack::eventFilter(QObject *obj, QEvent *event)
{
const QEvent::Type type = event->type();
const QEvent::Type type = event->type();
if (QEvent::Resize == type || QEvent::Move == type) {
setGeometry(toggle_->rect());
}
if (QEvent::Resize == type || QEvent::Move == type) {
setGeometry(toggle_->rect());
}
return QWidget::eventFilter(obj, event);
return QWidget::eventFilter(obj, event);
}
void
ToggleTrack::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
Q_UNUSED(event)
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QBrush brush;
if (toggle_->isEnabled()) {
brush.setColor(trackColor_);
painter.setOpacity(0.8);
} else {
brush.setColor(toggle_->disabledColor());
painter.setOpacity(0.6);
}
QBrush brush;
if (toggle_->isEnabled()) {
brush.setColor(trackColor_);
painter.setOpacity(0.8);
} else {
brush.setColor(toggle_->disabledColor());
painter.setOpacity(0.6);
}
brush.setStyle(Qt::SolidPattern);
painter.setBrush(brush);
painter.setPen(Qt::NoPen);
brush.setStyle(Qt::SolidPattern);
painter.setBrush(brush);
painter.setPen(Qt::NoPen);
const int h = height() / 2;
const QRect r(0, h / 2, width(), h);
painter.drawRoundedRect(r.adjusted(14, 4, -14, -4), h / 2 - 4, h / 2 - 4);
const int h = height() / 2;
const QRect r(0, h / 2, width(), h);
painter.drawRoundedRect(r.adjusted(14, 4, -14, -4), h / 2 - 4, h / 2 - 4);
}

View file

@ -12,103 +12,103 @@ class ToggleThumb;
enum class Position
{
Left,
Right
Left,
Right
};
class Toggle : public QAbstractButton
{
Q_OBJECT
Q_OBJECT
Q_PROPERTY(QColor activeColor WRITE setActiveColor READ activeColor)
Q_PROPERTY(QColor disabledColor WRITE setDisabledColor READ disabledColor)
Q_PROPERTY(QColor inactiveColor WRITE setInactiveColor READ inactiveColor)
Q_PROPERTY(QColor trackColor WRITE setTrackColor READ trackColor)
Q_PROPERTY(QColor activeColor WRITE setActiveColor READ activeColor)
Q_PROPERTY(QColor disabledColor WRITE setDisabledColor READ disabledColor)
Q_PROPERTY(QColor inactiveColor WRITE setInactiveColor READ inactiveColor)
Q_PROPERTY(QColor trackColor WRITE setTrackColor READ trackColor)
public:
Toggle(QWidget *parent = nullptr);
Toggle(QWidget *parent = nullptr);
void setState(bool isEnabled);
void setState(bool isEnabled);
void setActiveColor(const QColor &color);
void setDisabledColor(const QColor &color);
void setInactiveColor(const QColor &color);
void setTrackColor(const QColor &color);
void setActiveColor(const QColor &color);
void setDisabledColor(const QColor &color);
void setInactiveColor(const QColor &color);
void setTrackColor(const QColor &color);
QColor activeColor() const { return activeColor_; };
QColor disabledColor() const { return disabledColor_; };
QColor inactiveColor() const { return inactiveColor_; };
QColor trackColor() const { return trackColor_.isValid() ? trackColor_ : QColor("#eee"); };
QColor activeColor() const { return activeColor_; };
QColor disabledColor() const { return disabledColor_; };
QColor inactiveColor() const { return inactiveColor_; };
QColor trackColor() const { return trackColor_.isValid() ? trackColor_ : QColor("#eee"); };
QSize sizeHint() const override { return QSize(64, 48); };
QSize sizeHint() const override { return QSize(64, 48); };
protected:
void paintEvent(QPaintEvent *event) override;
void paintEvent(QPaintEvent *event) override;
private:
void init();
void setupProperties();
void init();
void setupProperties();
ToggleTrack *track_;
ToggleThumb *thumb_;
ToggleTrack *track_;
ToggleThumb *thumb_;
QColor disabledColor_;
QColor activeColor_;
QColor inactiveColor_;
QColor trackColor_;
QColor disabledColor_;
QColor activeColor_;
QColor inactiveColor_;
QColor trackColor_;
};
class ToggleThumb : public QWidget
{
Q_OBJECT
Q_OBJECT
Q_PROPERTY(QColor thumbColor WRITE setThumbColor READ thumbColor)
Q_PROPERTY(QColor thumbColor WRITE setThumbColor READ thumbColor)
public:
ToggleThumb(Toggle *parent);
ToggleThumb(Toggle *parent);
Position shift() const { return position_; };
qreal offset() const { return offset_; };
QColor thumbColor() const { return thumbColor_; };
Position shift() const { return position_; };
qreal offset() const { return offset_; };
QColor thumbColor() const { return thumbColor_; };
void setShift(Position position);
void setThumbColor(const QColor &color)
{
thumbColor_ = color;
update();
};
void setShift(Position position);
void setThumbColor(const QColor &color)
{
thumbColor_ = color;
update();
};
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
void paintEvent(QPaintEvent *event) override;
bool eventFilter(QObject *obj, QEvent *event) override;
void paintEvent(QPaintEvent *event) override;
private:
void updateOffset();
void updateOffset();
Toggle *const toggle_;
QColor thumbColor_;
Toggle *const toggle_;
QColor thumbColor_;
Position position_;
qreal offset_;
Position position_;
qreal offset_;
};
class ToggleTrack : public QWidget
{
Q_OBJECT
Q_OBJECT
Q_PROPERTY(QColor trackColor WRITE setTrackColor READ trackColor)
Q_PROPERTY(QColor trackColor WRITE setTrackColor READ trackColor)
public:
ToggleTrack(Toggle *parent);
ToggleTrack(Toggle *parent);
void setTrackColor(const QColor &color);
QColor trackColor() const { return trackColor_; };
void setTrackColor(const QColor &color);
QColor trackColor() const { return trackColor_; };
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
void paintEvent(QPaintEvent *event) override;
bool eventFilter(QObject *obj, QEvent *event) override;
void paintEvent(QPaintEvent *event) override;
private:
Toggle *const toggle_;
QColor trackColor_;
Toggle *const toggle_;
QColor trackColor_;
};

View file

@ -27,210 +27,200 @@ UserProfile::UserProfile(QString roomid,
, manager(manager_)
, model(parent)
{
globalAvatarUrl = "";
globalAvatarUrl = "";
connect(this,
&UserProfile::globalUsernameRetrieved,
this,
&UserProfile::setGlobalUsername,
Qt::QueuedConnection);
connect(this,
&UserProfile::globalUsernameRetrieved,
this,
&UserProfile::setGlobalUsername,
Qt::QueuedConnection);
if (isGlobalUserProfile()) {
getGlobalProfileData();
}
if (isGlobalUserProfile()) {
getGlobalProfileData();
}
if (!cache::client() || !cache::client()->isDatabaseReady() ||
!ChatPage::instance()->timelineManager())
return;
if (!cache::client() || !cache::client()->isDatabaseReady() ||
!ChatPage::instance()->timelineManager())
return;
connect(cache::client(),
&Cache::verificationStatusChanged,
this,
[this](const std::string &user_id) {
if (user_id != this->userid_.toStdString())
return;
connect(
cache::client(), &Cache::verificationStatusChanged, this, [this](const std::string &user_id) {
if (user_id != this->userid_.toStdString())
return;
auto status = cache::verificationStatus(user_id);
if (!status)
return;
this->isUserVerified = status->user_verified;
emit userStatusChanged();
auto status = cache::verificationStatus(user_id);
if (!status)
return;
this->isUserVerified = status->user_verified;
emit userStatusChanged();
for (auto &deviceInfo : deviceList_.deviceList_) {
deviceInfo.verification_status =
std::find(status->verified_devices.begin(),
status->verified_devices.end(),
deviceInfo.device_id.toStdString()) ==
status->verified_devices.end()
? verification::UNVERIFIED
: verification::VERIFIED;
}
deviceList_.reset(deviceList_.deviceList_);
emit devicesChanged();
});
fetchDeviceList(this->userid_);
for (auto &deviceInfo : deviceList_.deviceList_) {
deviceInfo.verification_status =
std::find(status->verified_devices.begin(),
status->verified_devices.end(),
deviceInfo.device_id.toStdString()) == status->verified_devices.end()
? verification::UNVERIFIED
: verification::VERIFIED;
}
deviceList_.reset(deviceList_.deviceList_);
emit devicesChanged();
});
fetchDeviceList(this->userid_);
}
QHash<int, QByteArray>
DeviceInfoModel::roleNames() const
{
return {
{DeviceId, "deviceId"},
{DeviceName, "deviceName"},
{VerificationStatus, "verificationStatus"},
};
return {
{DeviceId, "deviceId"},
{DeviceName, "deviceName"},
{VerificationStatus, "verificationStatus"},
};
}
QVariant
DeviceInfoModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() >= (int)deviceList_.size() || index.row() < 0)
return {};
if (!index.isValid() || index.row() >= (int)deviceList_.size() || index.row() < 0)
return {};
switch (role) {
case DeviceId:
return deviceList_[index.row()].device_id;
case DeviceName:
return deviceList_[index.row()].display_name;
case VerificationStatus:
return QVariant::fromValue(deviceList_[index.row()].verification_status);
default:
return {};
}
switch (role) {
case DeviceId:
return deviceList_[index.row()].device_id;
case DeviceName:
return deviceList_[index.row()].display_name;
case VerificationStatus:
return QVariant::fromValue(deviceList_[index.row()].verification_status);
default:
return {};
}
}
void
DeviceInfoModel::reset(const std::vector<DeviceInfo> &deviceList)
{
beginResetModel();
this->deviceList_ = std::move(deviceList);
endResetModel();
beginResetModel();
this->deviceList_ = std::move(deviceList);
endResetModel();
}
DeviceInfoModel *
UserProfile::deviceList()
{
return &this->deviceList_;
return &this->deviceList_;
}
QString
UserProfile::userid()
{
return this->userid_;
return this->userid_;
}
QString
UserProfile::displayName()
{
return isGlobalUserProfile() ? globalUsername : cache::displayName(roomid_, userid_);
return isGlobalUserProfile() ? globalUsername : cache::displayName(roomid_, userid_);
}
QString
UserProfile::avatarUrl()
{
return isGlobalUserProfile() ? globalAvatarUrl : cache::avatarUrl(roomid_, userid_);
return isGlobalUserProfile() ? globalAvatarUrl : cache::avatarUrl(roomid_, userid_);
}
bool
UserProfile::isGlobalUserProfile() const
{
return roomid_ == "";
return roomid_ == "";
}
crypto::Trust
UserProfile::getUserStatus()
{
return isUserVerified;
return isUserVerified;
}
bool
UserProfile::userVerificationEnabled() const
{
return hasMasterKey;
return hasMasterKey;
}
bool
UserProfile::isSelf() const
{
return this->userid_ == utils::localUser();
return this->userid_ == utils::localUser();
}
void
UserProfile::fetchDeviceList(const QString &userID)
{
auto localUser = utils::localUser();
auto localUser = utils::localUser();
if (!cache::client() || !cache::client()->isDatabaseReady())
return;
if (!cache::client() || !cache::client()->isDatabaseReady())
return;
cache::client()->query_keys(
userID.toStdString(),
[other_user_id = userID.toStdString(), this](const UserKeyCache &other_user_keys,
mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to query device keys: {},{}",
mtx::errors::to_string(err->matrix_error.errcode),
static_cast<int>(err->status_code));
return;
}
cache::client()->query_keys(
userID.toStdString(),
[other_user_id = userID.toStdString(), this](const UserKeyCache &other_user_keys,
mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to query device keys: {},{}",
mtx::errors::to_string(err->matrix_error.errcode),
static_cast<int>(err->status_code));
return;
}
// Ensure local key cache is up to date
cache::client()->query_keys(
utils::localUser().toStdString(),
[other_user_id, other_user_keys, this](const UserKeyCache &,
mtx::http::RequestErr err) {
using namespace mtx;
std::string local_user_id = utils::localUser().toStdString();
// Ensure local key cache is up to date
cache::client()->query_keys(
utils::localUser().toStdString(),
[other_user_id, other_user_keys, this](const UserKeyCache &,
mtx::http::RequestErr err) {
using namespace mtx;
std::string local_user_id = utils::localUser().toStdString();
if (err) {
nhlog::net()->warn(
"failed to query device keys: {},{}",
mtx::errors::to_string(err->matrix_error.errcode),
static_cast<int>(err->status_code));
return;
}
if (err) {
nhlog::net()->warn("failed to query device keys: {},{}",
mtx::errors::to_string(err->matrix_error.errcode),
static_cast<int>(err->status_code));
return;
}
this->hasMasterKey = !other_user_keys.master_keys.keys.empty();
this->hasMasterKey = !other_user_keys.master_keys.keys.empty();
std::vector<DeviceInfo> deviceInfo;
auto devices = other_user_keys.device_keys;
auto verificationStatus =
cache::client()->verificationStatus(other_user_id);
std::vector<DeviceInfo> deviceInfo;
auto devices = other_user_keys.device_keys;
auto verificationStatus = cache::client()->verificationStatus(other_user_id);
isUserVerified = verificationStatus.user_verified;
emit userStatusChanged();
isUserVerified = verificationStatus.user_verified;
emit userStatusChanged();
for (const auto &d : devices) {
auto device = d.second;
verification::Status verified =
verification::Status::UNVERIFIED;
for (const auto &d : devices) {
auto device = d.second;
verification::Status verified = verification::Status::UNVERIFIED;
if (std::find(verificationStatus.verified_devices.begin(),
verificationStatus.verified_devices.end(),
device.device_id) !=
verificationStatus.verified_devices.end() &&
mtx::crypto::verify_identity_signature(
device,
DeviceId(device.device_id),
UserId(other_user_id)))
verified = verification::Status::VERIFIED;
if (std::find(verificationStatus.verified_devices.begin(),
verificationStatus.verified_devices.end(),
device.device_id) != verificationStatus.verified_devices.end() &&
mtx::crypto::verify_identity_signature(
device, DeviceId(device.device_id), UserId(other_user_id)))
verified = verification::Status::VERIFIED;
deviceInfo.push_back(
{QString::fromStdString(d.first),
QString::fromStdString(
device.unsigned_info.device_display_name),
verified});
}
deviceInfo.push_back(
{QString::fromStdString(d.first),
QString::fromStdString(device.unsigned_info.device_display_name),
verified});
}
this->deviceList_.queueReset(std::move(deviceInfo));
emit devicesChanged();
});
});
this->deviceList_.queueReset(std::move(deviceInfo));
emit devicesChanged();
});
});
}
void
UserProfile::banUser()
{
ChatPage::instance()->banUser(this->userid_, "");
ChatPage::instance()->banUser(this->userid_, "");
}
// void ignoreUser(){
@ -240,188 +230,180 @@ UserProfile::banUser()
void
UserProfile::kickUser()
{
ChatPage::instance()->kickUser(this->userid_, "");
ChatPage::instance()->kickUser(this->userid_, "");
}
void
UserProfile::startChat()
{
ChatPage::instance()->startChat(this->userid_);
ChatPage::instance()->startChat(this->userid_);
}
void
UserProfile::changeUsername(QString username)
{
if (isGlobalUserProfile()) {
// change global
http::client()->set_displayname(
username.toStdString(), [](mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("could not change username");
return;
}
});
} else {
// change room username
mtx::events::state::Member member;
member.display_name = username.toStdString();
member.avatar_url =
cache::avatarUrl(roomid_,
QString::fromStdString(http::client()->user_id().to_string()))
.toStdString();
member.membership = mtx::events::state::Membership::Join;
if (isGlobalUserProfile()) {
// change global
http::client()->set_displayname(username.toStdString(), [](mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("could not change username");
return;
}
});
} else {
// change room username
mtx::events::state::Member member;
member.display_name = username.toStdString();
member.avatar_url =
cache::avatarUrl(roomid_, QString::fromStdString(http::client()->user_id().to_string()))
.toStdString();
member.membership = mtx::events::state::Membership::Join;
updateRoomMemberState(std::move(member));
}
updateRoomMemberState(std::move(member));
}
}
void
UserProfile::verify(QString device)
{
if (!device.isEmpty())
manager->verifyDevice(userid_, device);
else {
manager->verifyUser(userid_);
}
if (!device.isEmpty())
manager->verifyDevice(userid_, device);
else {
manager->verifyUser(userid_);
}
}
void
UserProfile::unverify(QString device)
{
cache::markDeviceUnverified(userid_.toStdString(), device.toStdString());
cache::markDeviceUnverified(userid_.toStdString(), device.toStdString());
}
void
UserProfile::setGlobalUsername(const QString &globalUser)
{
globalUsername = globalUser;
emit displayNameChanged();
globalUsername = globalUser;
emit displayNameChanged();
}
void
UserProfile::changeAvatar()
{
const QString picturesFolder =
QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
const QString fileName = QFileDialog::getOpenFileName(
nullptr, tr("Select an avatar"), picturesFolder, tr("All Files (*)"));
const QString picturesFolder =
QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
const QString fileName = QFileDialog::getOpenFileName(
nullptr, tr("Select an avatar"), picturesFolder, tr("All Files (*)"));
if (fileName.isEmpty())
return;
if (fileName.isEmpty())
return;
QMimeDatabase db;
QMimeType mime = db.mimeTypeForFile(fileName, QMimeDatabase::MatchContent);
QMimeDatabase db;
QMimeType mime = db.mimeTypeForFile(fileName, QMimeDatabase::MatchContent);
const auto format = mime.name().split("/")[0];
const auto format = mime.name().split("/")[0];
QFile file{fileName, this};
if (format != "image") {
emit displayError(tr("The selected file is not an image"));
return;
}
QFile file{fileName, this};
if (format != "image") {
emit displayError(tr("The selected file is not an image"));
return;
}
if (!file.open(QIODevice::ReadOnly)) {
emit displayError(tr("Error while reading file: %1").arg(file.errorString()));
return;
}
if (!file.open(QIODevice::ReadOnly)) {
emit displayError(tr("Error while reading file: %1").arg(file.errorString()));
return;
}
const auto bin = file.peek(file.size());
const auto payload = std::string(bin.data(), bin.size());
const auto bin = file.peek(file.size());
const auto payload = std::string(bin.data(), bin.size());
isLoading_ = true;
emit loadingChanged();
isLoading_ = true;
emit loadingChanged();
// First we need to create a new mxc URI
// (i.e upload media to the Matrix content repository) for the new avatar.
http::client()->upload(
payload,
mime.name().toStdString(),
QFileInfo(fileName).fileName().toStdString(),
[this,
payload,
mimetype = mime.name().toStdString(),
size = payload.size(),
room_id = roomid_.toStdString(),
content = std::move(bin)](const mtx::responses::ContentURI &res,
mtx::http::RequestErr err) {
// First we need to create a new mxc URI
// (i.e upload media to the Matrix content repository) for the new avatar.
http::client()->upload(
payload,
mime.name().toStdString(),
QFileInfo(fileName).fileName().toStdString(),
[this,
payload,
mimetype = mime.name().toStdString(),
size = payload.size(),
room_id = roomid_.toStdString(),
content = std::move(bin)](const mtx::responses::ContentURI &res, mtx::http::RequestErr err) {
if (err) {
nhlog::ui()->error("Failed to upload image", err->matrix_error.error);
return;
}
if (isGlobalUserProfile()) {
http::client()->set_avatar_url(res.content_uri, [this](mtx::http::RequestErr err) {
if (err) {
nhlog::ui()->error("Failed to upload image", err->matrix_error.error);
return;
nhlog::ui()->error("Failed to set user avatar url", err->matrix_error.error);
}
if (isGlobalUserProfile()) {
http::client()->set_avatar_url(
res.content_uri, [this](mtx::http::RequestErr err) {
if (err) {
nhlog::ui()->error("Failed to set user avatar url",
err->matrix_error.error);
}
isLoading_ = false;
emit loadingChanged();
getGlobalProfileData();
});
} else {
// change room username
mtx::events::state::Member member;
member.display_name = cache::displayName(roomid_, userid_).toStdString();
member.avatar_url = res.content_uri;
member.membership = mtx::events::state::Membership::Join;
isLoading_ = false;
emit loadingChanged();
getGlobalProfileData();
});
} else {
// change room username
mtx::events::state::Member member;
member.display_name = cache::displayName(roomid_, userid_).toStdString();
member.avatar_url = res.content_uri;
member.membership = mtx::events::state::Membership::Join;
updateRoomMemberState(std::move(member));
}
});
updateRoomMemberState(std::move(member));
}
});
}
void
UserProfile::updateRoomMemberState(mtx::events::state::Member member)
{
http::client()->send_state_event(roomid_.toStdString(),
http::client()->user_id().to_string(),
member,
[](mtx::responses::EventId, mtx::http::RequestErr err) {
if (err)
nhlog::net()->error(
"Failed to update room member state : ",
err->matrix_error.error);
});
http::client()->send_state_event(
roomid_.toStdString(),
http::client()->user_id().to_string(),
member,
[](mtx::responses::EventId, mtx::http::RequestErr err) {
if (err)
nhlog::net()->error("Failed to update room member state : ", err->matrix_error.error);
});
}
void
UserProfile::updateAvatarUrl()
{
isLoading_ = false;
emit loadingChanged();
isLoading_ = false;
emit loadingChanged();
emit avatarUrlChanged();
emit avatarUrlChanged();
}
bool
UserProfile::isLoading() const
{
return isLoading_;
return isLoading_;
}
void
UserProfile::getGlobalProfileData()
{
http::client()->get_profile(
userid_.toStdString(),
[this](const mtx::responses::Profile &res, mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to retrieve profile info for {}",
userid_.toStdString());
return;
}
http::client()->get_profile(
userid_.toStdString(), [this](const mtx::responses::Profile &res, mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to retrieve profile info for {}", userid_.toStdString());
return;
}
emit globalUsernameRetrieved(QString::fromStdString(res.display_name));
globalAvatarUrl = QString::fromStdString(res.avatar_url);
emit avatarUrlChanged();
});
emit globalUsernameRetrieved(QString::fromStdString(res.display_name));
globalAvatarUrl = QString::fromStdString(res.avatar_url);
emit avatarUrlChanged();
});
}
void
UserProfile::openGlobalProfile()
{
emit manager->openGlobalUserProfile(userid_);
emit manager->openGlobalUserProfile(userid_);
}

View file

@ -18,9 +18,9 @@ Q_NAMESPACE
enum Status
{
VERIFIED,
UNVERIFIED,
BLOCKED
VERIFIED,
UNVERIFIED,
BLOCKED
};
Q_ENUM_NS(Status)
}
@ -32,128 +32,127 @@ class TimelineViewManager;
class DeviceInfo
{
public:
DeviceInfo(const QString deviceID,
const QString displayName,
verification::Status verification_status_)
: device_id(deviceID)
, display_name(displayName)
, verification_status(verification_status_)
{}
DeviceInfo()
: verification_status(verification::UNVERIFIED)
{}
DeviceInfo(const QString deviceID,
const QString displayName,
verification::Status verification_status_)
: device_id(deviceID)
, display_name(displayName)
, verification_status(verification_status_)
{}
DeviceInfo()
: verification_status(verification::UNVERIFIED)
{}
QString device_id;
QString display_name;
QString device_id;
QString display_name;
verification::Status verification_status;
verification::Status verification_status;
};
class DeviceInfoModel : public QAbstractListModel
{
Q_OBJECT
Q_OBJECT
public:
enum Roles
{
DeviceId,
DeviceName,
VerificationStatus,
};
enum Roles
{
DeviceId,
DeviceName,
VerificationStatus,
};
explicit DeviceInfoModel(QObject *parent = nullptr)
{
(void)parent;
connect(this, &DeviceInfoModel::queueReset, this, &DeviceInfoModel::reset);
};
QHash<int, QByteArray> roleNames() const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override
{
(void)parent;
return (int)deviceList_.size();
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
explicit DeviceInfoModel(QObject *parent = nullptr)
{
(void)parent;
connect(this, &DeviceInfoModel::queueReset, this, &DeviceInfoModel::reset);
};
QHash<int, QByteArray> roleNames() const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override
{
(void)parent;
return (int)deviceList_.size();
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
signals:
void queueReset(const std::vector<DeviceInfo> &deviceList);
void queueReset(const std::vector<DeviceInfo> &deviceList);
public slots:
void reset(const std::vector<DeviceInfo> &deviceList);
void reset(const std::vector<DeviceInfo> &deviceList);
private:
std::vector<DeviceInfo> deviceList_;
std::vector<DeviceInfo> deviceList_;
friend class UserProfile;
friend class UserProfile;
};
class UserProfile : public QObject
{
Q_OBJECT
Q_PROPERTY(QString displayName READ displayName NOTIFY displayNameChanged)
Q_PROPERTY(QString userid READ userid CONSTANT)
Q_PROPERTY(QString avatarUrl READ avatarUrl NOTIFY avatarUrlChanged)
Q_PROPERTY(DeviceInfoModel *deviceList READ deviceList NOTIFY devicesChanged)
Q_PROPERTY(bool isGlobalUserProfile READ isGlobalUserProfile CONSTANT)
Q_PROPERTY(int userVerified READ getUserStatus NOTIFY userStatusChanged)
Q_PROPERTY(bool isLoading READ isLoading NOTIFY loadingChanged)
Q_PROPERTY(
bool userVerificationEnabled READ userVerificationEnabled NOTIFY userStatusChanged)
Q_PROPERTY(bool isSelf READ isSelf CONSTANT)
Q_PROPERTY(TimelineModel *room READ room CONSTANT)
Q_OBJECT
Q_PROPERTY(QString displayName READ displayName NOTIFY displayNameChanged)
Q_PROPERTY(QString userid READ userid CONSTANT)
Q_PROPERTY(QString avatarUrl READ avatarUrl NOTIFY avatarUrlChanged)
Q_PROPERTY(DeviceInfoModel *deviceList READ deviceList NOTIFY devicesChanged)
Q_PROPERTY(bool isGlobalUserProfile READ isGlobalUserProfile CONSTANT)
Q_PROPERTY(int userVerified READ getUserStatus NOTIFY userStatusChanged)
Q_PROPERTY(bool isLoading READ isLoading NOTIFY loadingChanged)
Q_PROPERTY(bool userVerificationEnabled READ userVerificationEnabled NOTIFY userStatusChanged)
Q_PROPERTY(bool isSelf READ isSelf CONSTANT)
Q_PROPERTY(TimelineModel *room READ room CONSTANT)
public:
UserProfile(QString roomid,
QString userid,
TimelineViewManager *manager_,
TimelineModel *parent = nullptr);
UserProfile(QString roomid,
QString userid,
TimelineViewManager *manager_,
TimelineModel *parent = nullptr);
DeviceInfoModel *deviceList();
DeviceInfoModel *deviceList();
QString userid();
QString displayName();
QString avatarUrl();
bool isGlobalUserProfile() const;
crypto::Trust getUserStatus();
bool userVerificationEnabled() const;
bool isSelf() const;
bool isLoading() const;
TimelineModel *room() const { return model; }
QString userid();
QString displayName();
QString avatarUrl();
bool isGlobalUserProfile() const;
crypto::Trust getUserStatus();
bool userVerificationEnabled() const;
bool isSelf() const;
bool isLoading() const;
TimelineModel *room() const { return model; }
Q_INVOKABLE void verify(QString device = "");
Q_INVOKABLE void unverify(QString device = "");
Q_INVOKABLE void fetchDeviceList(const QString &userID);
Q_INVOKABLE void banUser();
// Q_INVOKABLE void ignoreUser();
Q_INVOKABLE void kickUser();
Q_INVOKABLE void startChat();
Q_INVOKABLE void changeUsername(QString username);
Q_INVOKABLE void changeAvatar();
Q_INVOKABLE void openGlobalProfile();
Q_INVOKABLE void verify(QString device = "");
Q_INVOKABLE void unverify(QString device = "");
Q_INVOKABLE void fetchDeviceList(const QString &userID);
Q_INVOKABLE void banUser();
// Q_INVOKABLE void ignoreUser();
Q_INVOKABLE void kickUser();
Q_INVOKABLE void startChat();
Q_INVOKABLE void changeUsername(QString username);
Q_INVOKABLE void changeAvatar();
Q_INVOKABLE void openGlobalProfile();
signals:
void userStatusChanged();
void loadingChanged();
void displayNameChanged();
void avatarUrlChanged();
void displayError(const QString &errorMessage);
void globalUsernameRetrieved(const QString &globalUser);
void devicesChanged();
void userStatusChanged();
void loadingChanged();
void displayNameChanged();
void avatarUrlChanged();
void displayError(const QString &errorMessage);
void globalUsernameRetrieved(const QString &globalUser);
void devicesChanged();
public slots:
void updateAvatarUrl();
void updateAvatarUrl();
protected slots:
void setGlobalUsername(const QString &globalUser);
void setGlobalUsername(const QString &globalUser);
private:
void updateRoomMemberState(mtx::events::state::Member member);
void getGlobalProfileData();
void updateRoomMemberState(mtx::events::state::Member member);
void getGlobalProfileData();
private:
QString roomid_, userid_;
QString globalUsername;
QString globalAvatarUrl;
DeviceInfoModel deviceList_;
crypto::Trust isUserVerified = crypto::Trust::Unverified;
bool hasMasterKey = false;
bool isLoading_ = false;
TimelineViewManager *manager;
TimelineModel *model;
QString roomid_, userid_;
QString globalUsername;
QString globalAvatarUrl;
DeviceInfoModel deviceList_;
crypto::Trust isUserVerified = crypto::Trust::Unverified;
bool hasMasterKey = false;
bool isLoading_ = false;
TimelineViewManager *manager;
TimelineModel *model;
};