Skip to content

Commit 431c957

Browse files
committed
add legendTitleEntry() method to Plot for legend titles
1 parent b0805f5 commit 431c957

13 files changed

Lines changed: 110 additions & 18 deletions

QtSLiM/QtSLiMGraphView.cpp

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -856,15 +856,23 @@ int QtSLiMGraphView::lineCountForLegend(QtSLiMLegendSpec &legend)
856856

857857
for (const QtSLiMLegendEntry &legendEntry : legend)
858858
{
859-
QString labelString = legendEntry.label;
860-
auto existingEntry = displayedLabels.find(labelString);
861-
862-
if (existingEntry == displayedLabels.end())
859+
if (legendEntry.entry_type == QtSLiM_LegendEntryType::kTitle)
863860
{
864-
// not a duplicate
865-
displayedLabels.insert(labelString, 0);
861+
// title items do not participate in the duplicate process; they always stand alone
866862
lineCount++;
867863
}
864+
else
865+
{
866+
QString labelString = legendEntry.label;
867+
auto existingEntry = displayedLabels.find(labelString);
868+
869+
if (existingEntry == displayedLabels.end())
870+
{
871+
// not a duplicate
872+
displayedLabels.insert(labelString, 0);
873+
lineCount++;
874+
}
875+
}
868876
}
869877

870878
return lineCount;
@@ -922,7 +930,11 @@ QSizeF QtSLiMGraphView::legendSize(QPainter &painter)
922930

923931
// incorporate the width of the label into the width of the legend
924932
QRectF labelBoundingBox = painter.boundingRect(QRect(), Qt::TextDontClip | Qt::TextSingleLine, labelString);
925-
double labelWidth = legendGraphicsWidth + legendInteriorMargin + labelBoundingBox.width();
933+
double labelWidth = labelBoundingBox.width();
934+
935+
// items other than title entries have a graphics box and an interior margin as well
936+
if (legendEntry.entry_type != QtSLiM_LegendEntryType::kTitle)
937+
labelWidth += legendGraphicsWidth + legendInteriorMargin;
926938

927939
labelWidth = SLIM_SCREEN_ROUND(labelWidth);
928940

@@ -983,18 +995,29 @@ void QtSLiMGraphView::drawLegend(QPainter &painter, QRectF legendRect)
983995

984996
// check for duplicate labels, which get uniqued into a single line
985997
int positionIndex;
986-
auto existingEntry = displayedLabels.find(labelString);
998+
bool isDuplicate = false;
987999

988-
if (existingEntry == displayedLabels.end())
1000+
if (legendEntry.entry_type == QtSLiM_LegendEntryType::kTitle)
9891001
{
990-
// not a duplicate
1002+
// title items do not participate in the duplicate process; they always stand alone
9911003
positionIndex = (nextLinePosition--);
992-
displayedLabels.insert(labelString, positionIndex);
9931004
}
9941005
else
9951006
{
996-
// duplicate; use the previously determined position
997-
positionIndex = existingEntry.value();
1007+
auto existingEntry = displayedLabels.find(labelString);
1008+
1009+
if (existingEntry == displayedLabels.end())
1010+
{
1011+
// not a duplicate
1012+
positionIndex = (nextLinePosition--);
1013+
displayedLabels.insert(labelString, positionIndex);
1014+
}
1015+
else
1016+
{
1017+
// duplicate; use the previously determined position
1018+
positionIndex = existingEntry.value();
1019+
isDuplicate = true;
1020+
}
9981021
}
9991022

10001023
QRectF entryBox(legendRect.x(), legendRect.y() + positionIndex * (legendLineHeight + legendInteriorMargin), legendRect.width(), legendLineHeight);
@@ -1007,6 +1030,12 @@ void QtSLiMGraphView::drawLegend(QPainter &painter, QRectF legendRect)
10071030
// draw the graphics in graphicsBox
10081031
switch (legendEntry.entry_type)
10091032
{
1033+
case QtSLiM_LegendEntryType::kTitle:
1034+
{
1035+
// use the full entry box for title items
1036+
labelBox = entryBox;
1037+
break;
1038+
}
10101039
case QtSLiM_LegendEntryType::kSwatch:
10111040
{
10121041
QRectF swatchBox = graphicsBox;
@@ -1058,7 +1087,7 @@ void QtSLiMGraphView::drawLegend(QPainter &painter, QRectF legendRect)
10581087
}
10591088

10601089
// if the entry is not a duplicate, draw the text label
1061-
if (existingEntry == displayedLabels.end())
1090+
if (!isDuplicate)
10621091
{
10631092
double labelX = labelBox.x();
10641093
double labelY = labelBox.y() + labelVerticalAdjust;

QtSLiM/QtSLiMGraphView.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ class QPushButton;
4343
// Legend support
4444
enum class QtSLiM_LegendEntryType : int {
4545
kUninitialized = -1,
46-
kSwatch = 0,
46+
kTitle = 0,
47+
kSwatch,
4748
kLine,
4849
kPoint
4950
};
@@ -81,6 +82,10 @@ class QtSLiMLegendEntry {
8182
// constructor for an entry that shows a point symbol
8283
QtSLiMLegendEntry(QString p_label, int p_point_symbol, QColor p_point_color, QColor p_point_border, double p_point_lwd, double p_point_size) :
8384
label(p_label), entry_type(QtSLiM_LegendEntryType::kPoint), point_symbol(p_point_symbol), point_color(p_point_color), point_border(p_point_border), point_lwd(p_point_lwd), point_size(p_point_size) {};
85+
86+
// constructor for an entry that shows a title
87+
QtSLiMLegendEntry(QString p_label) :
88+
label(p_label), entry_type(QtSLiM_LegendEntryType::kTitle) {};
8489
};
8590

8691
typedef std::vector<QtSLiMLegendEntry> QtSLiMLegendSpec;

QtSLiM/QtSLiMGraphView_CustomPlot.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,12 @@ void QtSLiMGraphView_CustomPlot::addLegendSwatchEntry(QString label, QColor colo
489489
update();
490490
}
491491

492+
void QtSLiMGraphView_CustomPlot::addLegendTitleEntry(QString label)
493+
{
494+
legend_entries_.emplace_back(label);
495+
update();
496+
}
497+
492498
QString QtSLiMGraphView_CustomPlot::graphTitle(void)
493499
{
494500
return title_;

QtSLiM/QtSLiMGraphView_CustomPlot.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class QtSLiMGraphView_CustomPlot : public QtSLiMGraphView
8181
void addLegendLineEntry(QString label, QColor color, double lwd);
8282
void addLegendPointEntry(QString label, int symbol, QColor color, QColor border, double lwd, double size);
8383
void addLegendSwatchEntry(QString label, QColor color);
84+
void addLegendTitleEntry(QString label);
8485

8586
virtual QString graphTitle(void) override;
8687
virtual QString aboutString(void) override;

QtSLiM/QtSLiM_Plot.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ EidosValue_SP Plot::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const
104104
case gID_axis: return ExecuteMethod_axis(p_method_id, p_arguments, p_interpreter);
105105
case gID_legendLineEntry: return ExecuteMethod_legendLineEntry(p_method_id, p_arguments, p_interpreter);
106106
case gID_legendPointEntry: return ExecuteMethod_legendPointEntry(p_method_id, p_arguments, p_interpreter);
107-
case gID_legendSwatchEntry: return ExecuteMethod_legendSwatchEntry(p_method_id, p_arguments, p_interpreter);
107+
case gID_legendSwatchEntry: return ExecuteMethod_legendSwatchEntry(p_method_id, p_arguments, p_interpreter);
108+
case gID_legendTitleEntry: return ExecuteMethod_legendTitleEntry(p_method_id, p_arguments, p_interpreter);
108109
case gID_lines: return ExecuteMethod_lines(p_method_id, p_arguments, p_interpreter);
109110
case gID_points: return ExecuteMethod_points(p_method_id, p_arguments, p_interpreter);
110111
case gID_text: return ExecuteMethod_text(p_method_id, p_arguments, p_interpreter);
@@ -534,7 +535,7 @@ EidosValue_SP Plot::ExecuteMethod_legendPointEntry(EidosGlobalStringID p_method_
534535
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_legendPointEntry): legendPointEntry() requires the elements of size to be in (0, 1000]." << EidosTerminate(nullptr);
535536

536537
if (!plotview_->legendAdded())
537-
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_legendLineEntry): addLegend() must be called before adding legend entries." << EidosTerminate(nullptr);
538+
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_legendPointEntry): addLegend() must be called before adding legend entries." << EidosTerminate(nullptr);
538539

539540
plotview_->addLegendPointEntry(label, symbol, color, border, lwd, size);
540541

@@ -564,13 +565,31 @@ EidosValue_SP Plot::ExecuteMethod_legendSwatchEntry(EidosGlobalStringID p_method
564565
QColor color(colorR, colorG, colorB, 255);
565566

566567
if (!plotview_->legendAdded())
567-
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_legendLineEntry): addLegend() must be called before adding legend entries." << EidosTerminate(nullptr);
568+
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_legendSwatchEntry): addLegend() must be called before adding legend entries." << EidosTerminate(nullptr);
568569

569570
plotview_->addLegendSwatchEntry(label, color);
570571

571572
return gStaticEidosValueVOID;
572573
}
573574

575+
// ********************* – (void)legendTitleEntry(string$ label)
576+
//
577+
EidosValue_SP Plot::ExecuteMethod_legendTitleEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)
578+
{
579+
#pragma unused (p_method_id, p_arguments, p_interpreter)
580+
EidosValue *label_value = p_arguments[0].get();
581+
582+
// label
583+
QString label = QString::fromStdString(label_value->StringAtIndex_NOCAST(0, nullptr));
584+
585+
if (!plotview_->legendAdded())
586+
EIDOS_TERMINATION << "ERROR (Plot::ExecuteMethod_legendTitleEntry): addLegend() must be called before adding legend entries." << EidosTerminate(nullptr);
587+
588+
plotview_->addLegendTitleEntry(label);
589+
590+
return gStaticEidosValueVOID;
591+
}
592+
574593
// ********************* – (void)lines(numeric x, numeric y, [string$ color = "red"], [numeric$ lwd = 1.0], [float$ alpha = 1.0])
575594
//
576595
EidosValue_SP Plot::ExecuteMethod_lines(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)
@@ -1017,6 +1036,8 @@ const std::vector<EidosMethodSignature_CSP> *Plot_Class::Methods(void) const
10171036
->AddNumeric_OS("lwd", gStaticEidosValue_Float1)->AddNumeric_OS("size", gStaticEidosValue_Float1)));
10181037
methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_legendSwatchEntry, kEidosValueMaskVOID))
10191038
->AddString_S("label")->AddString_OS("color", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String("red")))));
1039+
methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_legendTitleEntry, kEidosValueMaskVOID))
1040+
->AddString_S("label")));
10201041
methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_lines, kEidosValueMaskVOID))
10211042
->AddNumeric("x")->AddNumeric("y")->AddString_OS("color", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String("red")))
10221043
->AddNumeric_OS("lwd", gStaticEidosValue_Float1)->AddFloat_OS("alpha", gStaticEidosValue_Float1)));

QtSLiM/QtSLiM_Plot.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class Plot : public EidosDictionaryUnretained
6969
EidosValue_SP ExecuteMethod_legendLineEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
7070
EidosValue_SP ExecuteMethod_legendPointEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
7171
EidosValue_SP ExecuteMethod_legendSwatchEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
72+
EidosValue_SP ExecuteMethod_legendTitleEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
7273
EidosValue_SP ExecuteMethod_lines(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
7374
EidosValue_SP ExecuteMethod_points(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
7475
EidosValue_SP ExecuteMethod_text(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);

QtSLiM/help/SLiMHelpClasses.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,8 @@
772772
<p class="p6">Adds a legend entry with text <span class="s1">label</span> to the plot.<span class="Apple-converted-space">  </span>The entry will be displayed as a point symbol specified by <span class="s1">symbol</span>, <span class="s1">color</span>, <span class="s1">border</span>, <span class="s1">lwd</span>, and <span class="s1">size</span>, mirroring the appearance produced by <span class="s1">points()</span> for the same parameters; see <span class="s1">points()</span> for further details.<span class="Apple-converted-space">  </span>If one or more other legend entries already exist with the same label, the new entry will be drawn on top of the previously set entries for that label (allowing legend entries that display both a line and a point, for example).</p>
773773
<p class="p5">– (void)legendSwatchEntry(string$ label, [string$ color = "red"])</p>
774774
<p class="p6">Adds a legend entry with text <span class="s1">label</span> to the plot.<span class="Apple-converted-space">  </span>The entry will be displayed as a swatch drawn in color <span class="s1">color</span>.<span class="Apple-converted-space">  </span>If one or more other legend entries already exist with the same label, the new entry will be drawn on top of the previously set entries for that label (allowing legend entries that display both a line and a point, for example).</p>
775+
<p class="p5">– (void)legendTitleEntry(string$ label)</p>
776+
<p class="p6">Adds a legend entry with text <span class="s1">label</span> to the plot.<span class="Apple-converted-space">  </span>The entry will be displayed as a title, left-aligned with no graphical representation (no line, point, or swatch).<span class="Apple-converted-space">  </span>A label of <span class="s1">""</span>, the empty string, is allowed and will produce a blank line in the legend (for spacing).<span class="Apple-converted-space">  </span>Note that title entries always produce their own separate line in the legend; they do not participate in the overdrawing scheme used for other types of legend entries.</p>
775777
<p class="p5">– (void)lines(numeric x, numeric y, [string$ color = "red"], [numeric$ lwd = 1.0], [float$ alpha = 1.0])</p>
776778
<p class="p6">Adds line data given by <span class="s1">x</span> and <span class="s1">y</span> to the plot.<span class="Apple-converted-space">  </span>The data will be plotted as a series of connected line segments, following the (<i>x</i>, <i>y</i>) positions given; note that the <span class="s1">x</span> and <span class="s1">y</span> vectors must be the same length.<span class="Apple-converted-space">  </span>The new line data will be plotted on top of any previously added data.</p>
777779
<p class="p6">The lines will be drawn in color <span class="s1">color</span>, using line width <span class="s1">lwd</span>, with opacity <span class="s1">alpha</span>.<span class="Apple-converted-space">  </span>Alpha values must be in [<span class="s1">0.0</span>, <span class="s1">1.0</span>], where <span class="s1">0.0</span> is fully transparent and <span class="s1">1.0</span> is fully opaque.<span class="Apple-converted-space">  </span>Unlike <span class="s1">points()</span> and <span class="s1">text()</span>, the parameters <span class="s1">color</span>, <span class="s1">lwd</span>, and <span class="s1">alpha</span> must be singletons, since each point (except the two ends) is shared by two line segments; if you wish to vary the color/width/opacity for each line segment, separate calls to <span class="s1">lines()</span> are necessary. <span class="Apple-converted-space">  </span>See also <span class="s1">abline()</span>.</p>

SLiMgui/SLiMHelpClasses.rtf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6826,6 +6826,16 @@ The
68266826
\f4\fs20 . If one or more other legend entries already exist with the same label, the new entry will be drawn on top of the previously set entries for that label (allowing legend entries that display both a line and a point, for example).\
68276827
\pard\pardeftab397\li720\fi-446\ri720\sb180\sa60\partightenfactor0
68286828

6829+
\f3\fs18 \cf2 \'96\'a0(void)legendTitleEntry(string$\'a0label)\
6830+
\pard\pardeftab720\li547\ri720\sb60\sa60\partightenfactor0
6831+
6832+
\f4\fs20 \cf2 Adds a legend entry with text
6833+
\f3\fs18 label
6834+
\f4\fs20 to the plot. The entry will be displayed as a title, left-aligned with no graphical representation (no line, point, or swatch). A label of
6835+
\f3\fs18 ""
6836+
\f4\fs20 , the empty string, is allowed and will produce a blank line in the legend (for spacing). Note that title entries always produce their own separate line in the legend; they do not participate in the overdrawing scheme used for other types of legend entries.\
6837+
\pard\pardeftab397\li720\fi-446\ri720\sb180\sa60\partightenfactor0
6838+
68296839
\f3\fs18 \cf2 \'96\'a0(void)lines(numeric\'a0x, numeric\'a0y, [string$\'a0color\'a0=\'a0"red"], [numeric$\'a0lwd\'a0=\'a01.0], [float$\'a0alpha\'a0=\'a01.0])\
68306840
\pard\pardeftab720\li547\ri720\sb60\sa60\partightenfactor0
68316841

SLiMgui/plot.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class Plot : public EidosDictionaryUnretained
7171
EidosValue_SP ExecuteMethod_legendLineEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
7272
EidosValue_SP ExecuteMethod_legendPointEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
7373
EidosValue_SP ExecuteMethod_legendSwatchEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
74+
EidosValue_SP ExecuteMethod_legendTitleEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
7475
EidosValue_SP ExecuteMethod_lines(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
7576
EidosValue_SP ExecuteMethod_points(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);
7677
EidosValue_SP ExecuteMethod_text(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);

SLiMgui/plot.mm

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
case gID_legendLineEntry: return ExecuteMethod_legendLineEntry(p_method_id, p_arguments, p_interpreter);
101101
case gID_legendPointEntry: return ExecuteMethod_legendPointEntry(p_method_id, p_arguments, p_interpreter);
102102
case gID_legendSwatchEntry: return ExecuteMethod_legendSwatchEntry(p_method_id, p_arguments, p_interpreter);
103+
case gID_legendTitleEntry: return ExecuteMethod_legendTitleEntry(p_method_id, p_arguments, p_interpreter);
103104
case gID_lines: return ExecuteMethod_lines(p_method_id, p_arguments, p_interpreter);
104105
case gID_points: return ExecuteMethod_points(p_method_id, p_arguments, p_interpreter);
105106
case gID_text: return ExecuteMethod_text(p_method_id, p_arguments, p_interpreter);
@@ -162,6 +163,15 @@
162163
return gStaticEidosValueVOID;
163164
}
164165

166+
// ********************* – (void)legendTitleEntry(...)
167+
//
168+
EidosValue_SP Plot::ExecuteMethod_legendTitleEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)
169+
{
170+
#pragma unused (p_method_id, p_arguments, p_interpreter)
171+
// The user has no way to call this method in SLiMguiLegacy, since createPlot() does not return a Plot object.
172+
return gStaticEidosValueVOID;
173+
}
174+
165175
// ********************* – (void)lines(...)
166176
//
167177
EidosValue_SP Plot::ExecuteMethod_lines(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)
@@ -256,6 +266,8 @@
256266
->AddNumeric_OS("lwd", gStaticEidosValue_Float1)->AddNumeric_OS("size", gStaticEidosValue_Float1));
257267
methods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_legendSwatchEntry, kEidosValueMaskVOID))
258268
->AddString_S("label")->AddString_OS("color", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String("red"))));
269+
methods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_legendTitleEntry, kEidosValueMaskVOID))
270+
->AddString_S("label"));
259271
methods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_lines, kEidosValueMaskVOID))
260272
->AddNumeric("x")->AddNumeric("y")->AddString_OS("color", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String("red")))->AddNumeric_OS("lwd", gStaticEidosValue_Float1)->AddFloat_OS("alpha", gStaticEidosValue_Float1));
261273
methods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_points, kEidosValueMaskVOID))

0 commit comments

Comments
 (0)