mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-08-13 10:04:13 +02:00
Merge branch 'master' into master-modernize-signal-slot
This commit is contained in:
@@ -993,20 +993,47 @@ void TitleBlockTemplateView::updateDisplayedMinMaxWidth()
|
||||
int max_width = tbtemplate_ -> maximumWidth();
|
||||
|
||||
QString min_max_width_sentence;
|
||||
if (max_width != -1) {
|
||||
min_max_width_sentence = QString(
|
||||
tr(
|
||||
"Longueur minimale : %1px\nLongueur maximale : %2px\n",
|
||||
"tooltip showing the minimum and/or maximum width of the edited template"
|
||||
)
|
||||
).arg(min_width).arg(max_width);
|
||||
} else {
|
||||
min_max_width_sentence = QString(
|
||||
tr(
|
||||
"Longueur minimale : %1px\n",
|
||||
"tooltip showing the minimum width of the edited template"
|
||||
)
|
||||
).arg(min_width);
|
||||
|
||||
switch (static_cast<TitleBlockTemplate::WidthConstraintCase>(min_width)) {
|
||||
case TitleBlockTemplate::WidthConstraintCase::RelativeWidthExceeds100Percent:
|
||||
// minimumWidth() and maximumWidth() both check infeasibility
|
||||
// first, identically, so max_width reports the same case
|
||||
// here -- no need to check it separately.
|
||||
min_max_width_sentence = tr(
|
||||
"Attention : la somme des largeurs relatives dépasse 100%% de la largeur totale, ce modèle de cartouche ne peut être satisfait par aucune largeur.\n",
|
||||
"tooltip warning shown when a template's relative-to-total-length columns alone already exceed 100%% of the total width"
|
||||
);
|
||||
break;
|
||||
case TitleBlockTemplate::WidthConstraintCase::AbsoluteColumnsExceedRemainingWidth:
|
||||
min_max_width_sentence = tr(
|
||||
"Attention : les colonnes de largeur fixe ne peuvent pas tenir dans la largeur restante, ce modèle de cartouche ne peut être satisfait par aucune largeur.\n",
|
||||
"tooltip warning shown when a template's relative-to-total-length columns already consume all available width, leaving no room for its fixed-width columns"
|
||||
);
|
||||
break;
|
||||
default:
|
||||
if (min_width != static_cast<int>(TitleBlockTemplate::WidthConstraintCase::Unconstrained)) {
|
||||
min_max_width_sentence += QString(
|
||||
tr(
|
||||
"Longueur minimale : %1px\n",
|
||||
"tooltip showing the minimum width of the edited template"
|
||||
)
|
||||
).arg(min_width);
|
||||
}
|
||||
if (max_width != static_cast<int>(TitleBlockTemplate::WidthConstraintCase::Unconstrained)) {
|
||||
min_max_width_sentence += QString(
|
||||
tr(
|
||||
"Longueur maximale : %1px\n",
|
||||
"tooltip showing the maximum width of the edited template"
|
||||
)
|
||||
).arg(max_width);
|
||||
}
|
||||
if (min_max_width_sentence.isEmpty()) {
|
||||
min_max_width_sentence = tr(
|
||||
"Longueur non contrainte.\n",
|
||||
"tooltip shown when the edited template has neither a minimum nor a maximum width constraint"
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// the tooltip may also display the split label for readability purpose
|
||||
|
||||
+110
-22
@@ -960,42 +960,130 @@ int TitleBlockTemplate::columnTypeTotal(QET::TitleBlockColumnLength type) {
|
||||
}
|
||||
|
||||
/**
|
||||
@return the minimum width for this template
|
||||
@brief TitleBlockTemplate::classifyWidthConstraint
|
||||
Classifies this template's absolute-width (ABS) and
|
||||
relative-to-total-length (RTT) columns, independently of whether a
|
||||
minimum or a maximum width is being computed.
|
||||
|
||||
The classification is derived from the same inequality
|
||||
minimumWidth() solves for a minimum width:
|
||||
@code
|
||||
TOT >= ((sum(RTT)/100)*TOT) + sum(ABS)
|
||||
@endcode
|
||||
Regardless of TOT, the RTT term above scales linearly with TOT. If
|
||||
sum(RTT) alone already accounts for 100% or more of TOT, no choice
|
||||
of TOT -- however large -- can make room for it (and for any ABS
|
||||
columns on top of it): making the template wider grows the RTT
|
||||
columns' pixel footprint by the same proportion, so the shortfall
|
||||
never resolves. This function exists so both minimumWidth() and
|
||||
maximumWidth() report that consistently, instead of maximumWidth()
|
||||
incorrectly treating a misconfigured template as "no upper bound".
|
||||
|
||||
@param[out] abs_total set to columnTypeTotal(QET::Absolute).
|
||||
@param[out] remaining_width_fraction set to the fraction of the
|
||||
total template width left over once the RTT columns have taken
|
||||
their share: (100.0 - sum(RTT)) / 100.0. Zero means the RTT
|
||||
columns claim the entire width, leaving nothing for ABS columns;
|
||||
negative means they claim more than the entire width, which is
|
||||
unsatisfiable regardless of any ABS columns. Only meaningful when
|
||||
this function returns std::nullopt.
|
||||
@return WidthConstraintCase::RelativeWidthExceeds100Percent if
|
||||
sum(RTT) exceeds 100% (unsatisfiable at any width, with or without
|
||||
ABS columns), WidthConstraintCase::AbsoluteColumnsExceedRemainingWidth
|
||||
if sum(RTT) equals exactly 100% and at least one ABS column is also
|
||||
present (unsatisfiable at any width, since the RTT columns leave no
|
||||
room for it), WidthConstraintCase::Unconstrained if sum(RTT) equals
|
||||
exactly 100% with no ABS columns (every term vanishes, any width
|
||||
holds -- an ordinary, valid template), or std::nullopt if this
|
||||
template's columns admit a genuine finite width.
|
||||
*/
|
||||
std::optional<TitleBlockTemplate::WidthConstraintCase> TitleBlockTemplate::classifyWidthConstraint(int &abs_total, qreal &remaining_width_fraction)
|
||||
{
|
||||
abs_total = columnTypeTotal(QET::Absolute);
|
||||
remaining_width_fraction = (100.0 - columnTypeTotal(QET::RelativeToTotalLength)) / 100.0;
|
||||
|
||||
if (remaining_width_fraction < 0.0) {
|
||||
return WidthConstraintCase::RelativeWidthExceeds100Percent;
|
||||
}
|
||||
if (remaining_width_fraction == 0.0) {
|
||||
return abs_total == 0
|
||||
? WidthConstraintCase::Unconstrained
|
||||
: WidthConstraintCase::AbsoluteColumnsExceedRemainingWidth;
|
||||
}
|
||||
return std::nullopt; // a finite width exists: remaining_width_fraction > 0
|
||||
}
|
||||
|
||||
/**
|
||||
@brief TitleBlockTemplate::minimumWidth
|
||||
@return the minimum width, in pixels, required for this template's
|
||||
absolute-width (ABS) and relative-to-total-length (RTT) columns to
|
||||
all fit.
|
||||
|
||||
Derivation: writing TOT for the (variable) total template width,
|
||||
the minimum size enforced by the ABS and RTT columns is:
|
||||
@code
|
||||
TOT >= ((sum(RTT)/100)*TOT) + sum(ABS)
|
||||
=> (1 - (sum(RTT)/100))*TOT >= sum(ABS)
|
||||
=> TOT >= sum(ABS) / (1 - (sum(RTT)/100))
|
||||
=> TOT >= sum(ABS) / ((100 - sum(RTT))/100)
|
||||
@endcode
|
||||
relative-to-remaining-length (RTR) columns do not constrain the
|
||||
minimum width, since by definition they only ever claim a share of
|
||||
whatever space is left over after the ABS and RTT columns are laid
|
||||
out.
|
||||
|
||||
If no finite minimum width applies, returns one of
|
||||
WidthConstraintCase::Unconstrained,
|
||||
WidthConstraintCase::RelativeWidthExceeds100Percent, or
|
||||
WidthConstraintCase::AbsoluteColumnsExceedRemainingWidth (cast to
|
||||
int) instead -- see classifyWidthConstraint() and that enum's
|
||||
documentation for when each case applies.
|
||||
*/
|
||||
int TitleBlockTemplate::minimumWidth()
|
||||
{
|
||||
// Abbreviations: ABS: absolute, RTT: relative to total, RTR:
|
||||
// relative to remaining,
|
||||
// TOT: total diagram/TBT width (variable).
|
||||
|
||||
// Minimum size may be enforced by ABS and RTT widths:
|
||||
// TOT >= ((sum(REL)/100)*TOT)+sum(ABS)
|
||||
// => (1 - (sum(REL)/100))TOT >= sum(ABS)
|
||||
// => TOT >= sum(ABS) / (1 - (sum(REL)/100))
|
||||
// => TOT >= sum(ABS) / ((100 - sum(REL))/100))
|
||||
return(
|
||||
qRound(
|
||||
columnTypeTotal(QET::Absolute)
|
||||
/
|
||||
((100.0 - columnTypeTotal(QET::RelativeToTotalLength))
|
||||
/ 100.0)
|
||||
)
|
||||
);
|
||||
int abs_total;
|
||||
qreal remaining_width_fraction;
|
||||
if (auto width_case = classifyWidthConstraint(abs_total, remaining_width_fraction)) {
|
||||
return static_cast<int>(*width_case);
|
||||
}
|
||||
return qRound(abs_total / remaining_width_fraction);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief TitleBlockTemplate::maximumWidth
|
||||
@return the maximum width for this template,
|
||||
or -1 if it does not have any.
|
||||
@return the maximum width, in pixels, this template may be
|
||||
rendered at.
|
||||
|
||||
If this template is composed entirely of absolute-width (ABS)
|
||||
columns, the maximum is fixed: the template cannot extend beyond
|
||||
their sum, since nothing in it scales with the template's total
|
||||
width. Otherwise, at least one column scales with the total width
|
||||
(relative-to-total-length or relative-to-remaining-length), so
|
||||
there is ordinarily no upper bound: returns
|
||||
WidthConstraintCase::Unconstrained (cast to int) -- the common case
|
||||
for most templates.
|
||||
|
||||
The exception is when this template's columns cannot be satisfied
|
||||
by any width at all (see classifyWidthConstraint()) -- in that case
|
||||
there is no width, however large, that works, and this returns
|
||||
WidthConstraintCase::RelativeWidthExceeds100Percent or
|
||||
WidthConstraintCase::AbsoluteColumnsExceedRemainingWidth (cast to
|
||||
int) instead of Unconstrained, matching minimumWidth()'s handling
|
||||
of the same cases.
|
||||
*/
|
||||
int TitleBlockTemplate::maximumWidth()
|
||||
{
|
||||
int abs_total;
|
||||
qreal remaining_width_fraction;
|
||||
if (auto width_case = classifyWidthConstraint(abs_total, remaining_width_fraction)) {
|
||||
return static_cast<int>(*width_case);
|
||||
}
|
||||
if (columnTypeCount(QET::Absolute) == columns_width_.count()) {
|
||||
// The template is composed of absolute widths only,
|
||||
// therefore it may not extend beyond their sum.
|
||||
return(columnTypeTotal(QET::Absolute));
|
||||
return abs_total; // already computed by classifyWidthConstraint()
|
||||
}
|
||||
return(-1);
|
||||
return static_cast<int>(WidthConstraintCase::Unconstrained);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <QtSvg>
|
||||
#include <QtXml>
|
||||
#include <optional>
|
||||
|
||||
/**
|
||||
@brief The TitleBlockTemplate class
|
||||
@@ -36,9 +37,73 @@
|
||||
*/
|
||||
class TitleBlockTemplate : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
@brief The TitleBlockTemplate::WidthConstraintCase enum Distinguishes
|
||||
the possible outcomes of minimumWidth() or maximumWidth() for a
|
||||
template's column layout: either a genuine finite pixel width, or one
|
||||
of the cases below where no single finite width applies -- some of which are
|
||||
perfectly ordinary (Unconstrained), and some of which indicate the
|
||||
template's columns cannot be laid out at any width.
|
||||
|
||||
Both functions return one of the non-Bounded* cases below,
|
||||
cast to int, in place of a genuine width whenever no finite
|
||||
width applies. (*minimumWidth()/maximumWidth() never return
|
||||
a literal "Bounded" value -- when a finite width exists,
|
||||
they return that width directly. Bounded only appears as a
|
||||
concept in classifyWidthConstraint()'s std::nullopt return.)
|
||||
The int-based encoding exists because this project
|
||||
currently targets C++17.
|
||||
|
||||
@todo Once this project's minimum supported C++ standard
|
||||
reaches C++23, migrate minimumWidth() and maximumWidth() to
|
||||
return std::expected<int, WidthConstraintCase> instead of
|
||||
encoding these cases as negative int sentinels. That removes
|
||||
the possibility of a caller silently misinterpreting a
|
||||
sentinel as a real pixel width -- something the current
|
||||
int-based encoding cannot prevent at compile time.
|
||||
*/
|
||||
enum class WidthConstraintCase : int {
|
||||
/**
|
||||
There is no finite width constraint in this direction:
|
||||
any width is valid. This is a perfectly ordinary case,
|
||||
not a problem with the template -- for minimumWidth(),
|
||||
it happens when the relative-to-total-length (RTT)
|
||||
columns account for exactly 100% of the total width and
|
||||
there are no absolute-width (ABS) columns competing for
|
||||
space -- every term in the minimum-width inequality
|
||||
vanishes (0 >= 0), which holds for any width. For
|
||||
maximumWidth(), it happens whenever at least one column
|
||||
scales with the total width, so nothing caps how wide
|
||||
the template may grow -- the common case for most
|
||||
templates.
|
||||
*/
|
||||
Unconstrained = -1,
|
||||
|
||||
/**
|
||||
The RTT columns alone already exceed 100% of the total
|
||||
width (sum(RTT) > 100), independently of whether any ABS
|
||||
columns exist. The minimum-width inequality then only
|
||||
holds for a non-positive width, which cannot represent a
|
||||
real template: this indicates a genuinely misconfigured
|
||||
template that cannot be laid out at any width.
|
||||
*/
|
||||
RelativeWidthExceeds100Percent = -2,
|
||||
|
||||
/**
|
||||
The RTT columns account for exactly 100% of the total
|
||||
width, but at least one ABS column also needs a nonzero,
|
||||
fixed amount of space on top of that. The minimum-width
|
||||
inequality reduces to "0 >= (a positive number)", which
|
||||
never holds: this also indicates a genuinely
|
||||
misconfigured template that cannot be laid out at any
|
||||
width.
|
||||
*/
|
||||
AbsoluteColumnsExceedRemainingWidth = -3
|
||||
};
|
||||
|
||||
// constructors, destructor
|
||||
public:
|
||||
TitleBlockTemplate(QObject * = nullptr);
|
||||
~TitleBlockTemplate() override;
|
||||
private:
|
||||
@@ -146,6 +211,20 @@ class TitleBlockTemplate : public QObject {
|
||||
bool checkCell(const QDomElement &, TitleBlockCell ** = nullptr);
|
||||
void flushCells();
|
||||
void initCells();
|
||||
/**
|
||||
@brief TitleBlockTemplate::classifyWidthConstraint Classifies this template's absolute-width (ABS) and
|
||||
relative-to-total-length (RTT) columns, independently of whether a minimum or a maximum width is being computed -- see
|
||||
minimumWidth() for the derivation this is based on.
|
||||
@param[out] abs_total set to columnTypeTotal(QET::Absolute).
|
||||
@param[out] remaining_width_fraction set to the fraction of the total template width left over once the RTT columns have taken
|
||||
their share: (100.0 - sum(RTT)) / 100.0. Zero means the RTT columns claim the entire width, leaving nothing for ABS
|
||||
columns; negative means they claim more than the entire width, which is unsatisfiable regardless of any ABS columns. Only
|
||||
meaningful when this function returns std::nullopt.
|
||||
@return WidthConstraintCase::RelativeWidthExceeds100Percent, WidthConstraintCase::AbsoluteColumnsExceedRemainingWidth, or
|
||||
WidthConstraintCase::Unconstrained if no finite width exists for this template's columns, or std::nullopt if a finite width
|
||||
does exist (computable as qRound(abs_total / remaining_width_fraction)).
|
||||
*/
|
||||
std::optional<WidthConstraintCase> classifyWidthConstraint(int &abs_total, qreal &remaining_width_fraction);
|
||||
int lengthRange(int, int, const QList<int> &) const;
|
||||
QString finalTextForCell(
|
||||
const TitleBlockCell &,
|
||||
|
||||
Reference in New Issue
Block a user