Improve Delegate Width Sizing

Create a cpp helper class to calculate the correct delegate width given it's parent width.

This is designed to be more robust and hopefully easier to understand than the current mass of javascript calcs.

BUG: 470167
This commit is contained in:
James Graham
2023-05-30 18:14:25 +00:00
parent f1be509d13
commit fa37f28c94
10 changed files with 492 additions and 23 deletions

153
src/delegatesizehelper.cpp Normal file
View File

@@ -0,0 +1,153 @@
// 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)
{
}
qreal DelegateSizeHelper::parentWidth() const
{
return m_parentWidth;
}
void DelegateSizeHelper::setParentWidth(qreal parentWidth)
{
if (parentWidth == m_parentWidth) {
return;
}
m_parentWidth = parentWidth;
Q_EMIT parentWidthChanged();
Q_EMIT currentPercentageWidthChanged();
Q_EMIT currentWidthChanged();
}
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
{
return m_maxWidth;
}
void DelegateSizeHelper::setMaxWidth(qreal maxWidth)
{
if (maxWidth == m_maxWidth) {
return;
}
m_maxWidth = maxWidth;
Q_EMIT maxWidthChanged();
}
int DelegateSizeHelper::calculateCurrentPercentageWidth() const
{
// Don't do anything if m_parentWidth hasn't been set yet.
if (m_parentWidth < 0) {
return -1;
}
// 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) {
qWarning() << "DelegateSizeHelper::calculateCurrentPercentageWidth() - m_startBreakpoint is equal to m_endBreakpoint this would lead to divide by "
"zero, aborting";
return -1;
}
// 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::ceil(m * m_parentWidth + c);
return std::clamp(calcPercentWidth, minPercentWidth, maxPercentWidth);
}
int DelegateSizeHelper::currentPercentageWidth() const
{
return calculateCurrentPercentageWidth();
}
qreal DelegateSizeHelper::currentWidth() const
{
if (m_parentWidth < 0) {
return 0.0;
}
int percentWidth = calculateCurrentPercentageWidth();
// - 1 means bad input values so don't try to calculate.
if (percentWidth == -1) {
return 0.0;
}
qreal absoluteWidth = m_parentWidth * percentWidth * 0.01;
if (m_maxWidth < 0.0) {
return std::ceil(absoluteWidth);
} else {
return std::ceil(std::min(absoluteWidth, m_maxWidth));
}
}