delegatesizehelper updates
Make `DelegateSizeHelper` take a `QQuickItem` rather than a width value and move `TimelineDelegate` to use it rather than duplicting the code. This requires the creation of `LibNeoChat` so that both the main and timeline modules can get access to the class. Note: ideally more stuff will go into `LibNeoChat` but it turns out our dependencies are kinda spaghetti like and so will take some untangling.
This commit is contained in:
19
src/libneochat/CMakeLists.txt
Normal file
19
src/libneochat/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
# SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_library(LibNeoChat STATIC)
|
||||
|
||||
target_sources(LibNeoChat PRIVATE
|
||||
delegatesizehelper.cpp
|
||||
)
|
||||
|
||||
ecm_add_qml_module(LibNeoChat GENERATE_PLUGIN_SOURCE
|
||||
URI org.kde.neochat.libneochat
|
||||
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat/libneochat
|
||||
)
|
||||
|
||||
generate_export_header(LibNeoChat BASE_NAME LibNeoChat)
|
||||
target_link_libraries(LibNeoChat PUBLIC
|
||||
Qt::Core
|
||||
Qt::Quick
|
||||
)
|
||||
191
src/libneochat/delegatesizehelper.cpp
Normal file
191
src/libneochat/delegatesizehelper.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#include "delegatesizehelper.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
DelegateSizeHelper::DelegateSizeHelper(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QQuickItem *DelegateSizeHelper::parentItem() const
|
||||
{
|
||||
return m_parentItem;
|
||||
}
|
||||
|
||||
void DelegateSizeHelper::setParentItem(QQuickItem *parentItem)
|
||||
{
|
||||
if (parentItem == m_parentItem) {
|
||||
return;
|
||||
}
|
||||
m_parentItem = parentItem;
|
||||
|
||||
if (m_parentItem) {
|
||||
connect(m_parentItem, &QQuickItem::widthChanged, this, [this]() {
|
||||
Q_EMIT availablePercentageWidthChanged();
|
||||
Q_EMIT availableWidthChanged();
|
||||
});
|
||||
}
|
||||
|
||||
Q_EMIT parentItemChanged();
|
||||
Q_EMIT availablePercentageWidthChanged();
|
||||
Q_EMIT availableWidthChanged();
|
||||
}
|
||||
|
||||
qreal DelegateSizeHelper::leftPadding() const
|
||||
{
|
||||
return m_leftPadding;
|
||||
}
|
||||
|
||||
void DelegateSizeHelper::setLeftPadding(qreal leftPadding)
|
||||
{
|
||||
if (qFuzzyCompare(leftPadding, m_leftPadding)) {
|
||||
return;
|
||||
}
|
||||
m_leftPadding = leftPadding;
|
||||
Q_EMIT leftPaddingChanged();
|
||||
Q_EMIT availablePercentageWidthChanged();
|
||||
Q_EMIT availableWidthChanged();
|
||||
}
|
||||
|
||||
qreal DelegateSizeHelper::rightPadding() const
|
||||
{
|
||||
return m_rightPadding;
|
||||
}
|
||||
|
||||
void DelegateSizeHelper::setRightPadding(qreal rightPadding)
|
||||
{
|
||||
if (qFuzzyCompare(rightPadding, m_rightPadding)) {
|
||||
return;
|
||||
}
|
||||
m_rightPadding = rightPadding;
|
||||
Q_EMIT rightPaddingChanged();
|
||||
Q_EMIT availablePercentageWidthChanged();
|
||||
Q_EMIT availableWidthChanged();
|
||||
}
|
||||
|
||||
qreal DelegateSizeHelper::startBreakpoint() const
|
||||
{
|
||||
return m_startBreakpoint;
|
||||
}
|
||||
|
||||
void DelegateSizeHelper::setStartBreakpoint(qreal startBreakpoint)
|
||||
{
|
||||
if (startBreakpoint == m_startBreakpoint) {
|
||||
return;
|
||||
}
|
||||
m_startBreakpoint = startBreakpoint;
|
||||
Q_EMIT startBreakpointChanged();
|
||||
}
|
||||
|
||||
qreal DelegateSizeHelper::endBreakpoint() const
|
||||
{
|
||||
return m_endBreakpoint;
|
||||
}
|
||||
|
||||
void DelegateSizeHelper::setEndBreakpoint(qreal endBreakpoint)
|
||||
{
|
||||
if (endBreakpoint == m_endBreakpoint) {
|
||||
return;
|
||||
}
|
||||
m_endBreakpoint = endBreakpoint;
|
||||
Q_EMIT endBreakpointChanged();
|
||||
}
|
||||
|
||||
int DelegateSizeHelper::startPercentWidth() const
|
||||
{
|
||||
return m_startPercentWidth;
|
||||
}
|
||||
|
||||
void DelegateSizeHelper::setStartPercentWidth(int startPercentWidth)
|
||||
{
|
||||
if (startPercentWidth == m_startPercentWidth) {
|
||||
return;
|
||||
}
|
||||
m_startPercentWidth = startPercentWidth;
|
||||
Q_EMIT startPercentWidthChanged();
|
||||
}
|
||||
|
||||
int DelegateSizeHelper::endPercentWidth() const
|
||||
{
|
||||
return m_endPercentWidth;
|
||||
}
|
||||
|
||||
void DelegateSizeHelper::setEndPercentWidth(int endPercentWidth)
|
||||
{
|
||||
if (endPercentWidth == m_endPercentWidth) {
|
||||
return;
|
||||
}
|
||||
m_endPercentWidth = endPercentWidth;
|
||||
Q_EMIT endPercentWidthChanged();
|
||||
}
|
||||
|
||||
qreal DelegateSizeHelper::maxWidth() const
|
||||
{
|
||||
if (m_maxWidth == std::nullopt) {
|
||||
if (m_parentItem) {
|
||||
return m_parentItem->width();
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return *m_maxWidth;
|
||||
}
|
||||
|
||||
void DelegateSizeHelper::setMaxWidth(qreal maxWidth)
|
||||
{
|
||||
if (maxWidth == m_maxWidth) {
|
||||
return;
|
||||
}
|
||||
m_maxWidth = maxWidth;
|
||||
Q_EMIT maxWidthChanged();
|
||||
}
|
||||
|
||||
qreal DelegateSizeHelper::maxAvailableWidth() const
|
||||
{
|
||||
if (!m_parentItem || qFuzzyCompare(m_parentItem->width(), 0)) {
|
||||
return 0;
|
||||
}
|
||||
return std::max(m_parentItem->width() - m_leftPadding - m_rightPadding, 0.0);
|
||||
}
|
||||
|
||||
int DelegateSizeHelper::calculateAvailablePercentageWidth() const
|
||||
{
|
||||
// Don't bother with calculations for a horizontal line.
|
||||
if (m_startPercentWidth == m_endPercentWidth) {
|
||||
return m_startPercentWidth;
|
||||
}
|
||||
// Dividing by zero is a bad idea.
|
||||
if (m_startBreakpoint == m_endBreakpoint || qFuzzyCompare(maxAvailableWidth(), 0)) {
|
||||
return 100;
|
||||
}
|
||||
|
||||
// Fit to y = mx + c
|
||||
qreal m = (m_endPercentWidth - m_startPercentWidth) / (m_endBreakpoint - m_startBreakpoint);
|
||||
qreal c = m_startPercentWidth - m * m_startBreakpoint;
|
||||
|
||||
// This allows us to clamp correctly if the start or end width is bigger.
|
||||
bool endPercentBigger = m_endPercentWidth > m_startPercentWidth;
|
||||
int maxPercentWidth = endPercentBigger ? m_endPercentWidth : m_startPercentWidth;
|
||||
int minPercentWidth = endPercentBigger ? m_startPercentWidth : m_endPercentWidth;
|
||||
|
||||
int calcPercentWidth = std::round(m * maxAvailableWidth() + c);
|
||||
return std::clamp(calcPercentWidth, minPercentWidth, maxPercentWidth);
|
||||
}
|
||||
|
||||
int DelegateSizeHelper::availablePercentageWidth() const
|
||||
{
|
||||
return calculateAvailablePercentageWidth();
|
||||
}
|
||||
|
||||
qreal DelegateSizeHelper::availableWidth() const
|
||||
{
|
||||
qreal absoluteWidth = maxAvailableWidth() * availablePercentageWidth() * 0.01;
|
||||
return std::round(std::min(absoluteWidth, maxWidth()));
|
||||
}
|
||||
|
||||
#include "moc_delegatesizehelper.cpp"
|
||||
152
src/libneochat/delegatesizehelper.h
Normal file
152
src/libneochat/delegatesizehelper.h
Normal file
@@ -0,0 +1,152 @@
|
||||
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QQmlEngine>
|
||||
#include <QQuickItem>
|
||||
|
||||
/**
|
||||
* @class DelegateSizeHelper
|
||||
*
|
||||
* A class to help calculate the current width of a chat delegate/bar.
|
||||
*
|
||||
* The aim is to support a dynamic sizing based upon the width of the page. There is
|
||||
* a built in curve that allows the width to transition between two percentages based
|
||||
* upon a start and finish break point. This is to provide better convergence where
|
||||
* generally the delegate will need to fill all or most the screen when thin but
|
||||
* should max out in size and only fill a lower percentage of the screen when wide.
|
||||
*
|
||||
* @note While the main intended usage is to start with a high percentage when the parentWidth
|
||||
* is small and transition to a lower one when large, the math is setup for the
|
||||
* general case so any combination of parameters works.
|
||||
*/
|
||||
class DelegateSizeHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
/**
|
||||
* @brief The parent item that defines the available content area.
|
||||
*/
|
||||
Q_PROPERTY(QQuickItem *parentItem READ parentItem WRITE setParentItem NOTIFY parentItemChanged)
|
||||
|
||||
/**
|
||||
* @brief The amount of padding to be removed from the left of the available content area.
|
||||
*
|
||||
* The padding is removed before calculating the available width, i.e. max available width
|
||||
* at 100% is equal to parent width minus padding.
|
||||
*/
|
||||
Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding NOTIFY leftPaddingChanged)
|
||||
|
||||
/**
|
||||
* @brief The amount of padding to be removed from the right of the available content area.
|
||||
*
|
||||
* The padding is removed before calculating the available width, i.e. max available width
|
||||
* at 100% is equal to parent width minus padding.
|
||||
*/
|
||||
Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding NOTIFY rightPaddingChanged)
|
||||
|
||||
/**
|
||||
* @brief The width (in px) when the width percentage should start to transition.
|
||||
*/
|
||||
Q_PROPERTY(qreal startBreakpoint READ startBreakpoint WRITE setStartBreakpoint NOTIFY startBreakpointChanged)
|
||||
|
||||
/**
|
||||
* @brief The width (in px) when the width percentage should finish transitioning.
|
||||
*/
|
||||
Q_PROPERTY(qreal endBreakpoint READ endBreakpoint WRITE setEndBreakpoint NOTIFY endBreakpointChanged)
|
||||
|
||||
/**
|
||||
* @brief The width (in %) of the component at or before the startBreakpoint.
|
||||
*
|
||||
* @sa startBreakpoint
|
||||
*/
|
||||
Q_PROPERTY(int startPercentWidth READ startPercentWidth WRITE setStartPercentWidth NOTIFY startPercentWidthChanged)
|
||||
|
||||
/**
|
||||
* @brief The width (in %) of the component at or after the endBreakpoint.
|
||||
*
|
||||
* @sa endBreakpoint
|
||||
*/
|
||||
Q_PROPERTY(int endPercentWidth READ endPercentWidth WRITE setEndPercentWidth NOTIFY endPercentWidthChanged)
|
||||
|
||||
/**
|
||||
* @brief The absolute maximum width (in px) the component can be.
|
||||
*/
|
||||
Q_PROPERTY(qreal maxWidth READ maxWidth WRITE setMaxWidth NOTIFY maxWidthChanged)
|
||||
|
||||
/**
|
||||
* @brief The width (in %) of the component at the current parentWidth.
|
||||
*
|
||||
* Will return -1 if no parentWidth is set or startBreakpoint == endBreakpoint.
|
||||
*
|
||||
* @sa parentWidth, startBreakpoint, endBreakpoint
|
||||
*/
|
||||
Q_PROPERTY(int availablePercentageWidth READ availablePercentageWidth NOTIFY availablePercentageWidthChanged)
|
||||
|
||||
/**
|
||||
* @brief The width (in px) of the component at the current parentWidth.
|
||||
*
|
||||
* Will return 0.0 if no parentWidth is set.
|
||||
*
|
||||
* @sa parentWidth
|
||||
*/
|
||||
Q_PROPERTY(qreal availableWidth READ availableWidth NOTIFY availableWidthChanged)
|
||||
|
||||
public:
|
||||
explicit DelegateSizeHelper(QObject *parent = nullptr);
|
||||
|
||||
QQuickItem *parentItem() const;
|
||||
void setParentItem(QQuickItem *parentItem);
|
||||
|
||||
qreal leftPadding() const;
|
||||
void setLeftPadding(qreal leftPadding);
|
||||
qreal rightPadding() const;
|
||||
void setRightPadding(qreal rightPadding);
|
||||
|
||||
qreal startBreakpoint() const;
|
||||
void setStartBreakpoint(qreal startBreakpoint);
|
||||
qreal endBreakpoint() const;
|
||||
void setEndBreakpoint(qreal endBreakpoint);
|
||||
|
||||
int startPercentWidth() const;
|
||||
void setStartPercentWidth(int startPercentWidth);
|
||||
int endPercentWidth() const;
|
||||
void setEndPercentWidth(int endPercentWidth);
|
||||
|
||||
qreal maxWidth() const;
|
||||
void setMaxWidth(qreal maxWidth);
|
||||
|
||||
qreal maxAvailableWidth() const;
|
||||
|
||||
int availablePercentageWidth() const;
|
||||
qreal availableWidth() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void parentItemChanged();
|
||||
void leftPaddingChanged();
|
||||
void rightPaddingChanged();
|
||||
void startBreakpointChanged();
|
||||
void endBreakpointChanged();
|
||||
void startPercentWidthChanged();
|
||||
void endPercentWidthChanged();
|
||||
void maxWidthChanged();
|
||||
void availablePercentageWidthChanged();
|
||||
void availableWidthChanged();
|
||||
|
||||
private:
|
||||
QPointer<QQuickItem> m_parentItem;
|
||||
|
||||
qreal m_leftPadding = 0.0;
|
||||
qreal m_rightPadding = 0.0;
|
||||
|
||||
qreal m_startBreakpoint = 0.0;
|
||||
qreal m_endBreakpoint = 0.0;
|
||||
int m_startPercentWidth = 100;
|
||||
int m_endPercentWidth = 85;
|
||||
std::optional<qreal> m_maxWidth = std::nullopt;
|
||||
|
||||
int calculateAvailablePercentageWidth() const;
|
||||
};
|
||||
Reference in New Issue
Block a user