Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/foxtools/MFXDynamicLabel.cpp
169678 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file MFXDynamicLabel.cpp
15
/// @author Mirko Barthauer
16
/// @date 31.03.2023
17
///
18
// Text label with dynamic multi-line text (inserts line line breaks on the fly)
19
/****************************************************************************/
20
#include <config.h>
21
#include "MFXDynamicLabel.h"
22
23
// ===========================================================================
24
// FOX callback mapping
25
// ===========================================================================
26
27
FXDEFMAP(MFXDynamicLabel) MFXLabelMap[] = {
28
FXMAPFUNC(SEL_UPDATE, 0, MFXDynamicLabel::onUpdate),
29
};
30
31
// Object implementation
32
FXIMPLEMENT(MFXDynamicLabel, FXLabel, MFXLabelMap, ARRAYNUMBER(MFXLabelMap))
33
34
// ===========================================================================
35
// method definitions
36
// ===========================================================================
37
38
// ---------------------------------------------------------------------------
39
// MFXLabel - public methods
40
// ---------------------------------------------------------------------------
41
42
MFXDynamicLabel::MFXDynamicLabel(FXComposite* p, const FXString& text, FXIcon* ic, FXuint opts, FXint x, FXint y, FXint w, FXint h, FXint pl, FXint pr, FXint pt, FXint pb, std::string indent):
43
FXLabel(p, text, ic, opts, x, y, w, h, pl, pr, pt, pb), myOriginalString(text.text()), myIndentString(indent), myPreviousWidth(0) {
44
computeIndentation();
45
}
46
47
48
long
49
MFXDynamicLabel::onUpdate(FXObject* sender, FXSelector sel, void* ptr) {
50
const int curWidth = getWidth();
51
if (myPreviousWidth - curWidth != 0 && curWidth > 1) {
52
reformatLineBreaks(curWidth);
53
myPreviousWidth = curWidth;
54
}
55
return FXLabel::onUpdate(sender, sel, ptr);
56
}
57
58
59
void
60
MFXDynamicLabel::setText(const FXString& text) {
61
FXLabel::setText(text);
62
myOriginalString = text.text();
63
computeIndentation();
64
}
65
66
67
void
68
MFXDynamicLabel::position(FXint x, FXint y, FXint w, FXint h) {
69
FXLabel::position(x, y, w, h);
70
reformatLineBreaks(w);
71
}
72
73
74
FXint
75
MFXDynamicLabel::getDefaultHeight() {
76
int pWidth = getParent()->getWidth();
77
if (pWidth > 1) { // sign that it has been initialised
78
FXFrame* frame = dynamic_cast<FXFrame*>(getParent());
79
int padding = 0;
80
if (frame != nullptr) {
81
padding = frame->getPadLeft() + frame->getPadRight();
82
}
83
reformatLineBreaks(pWidth - padding);
84
}
85
return FXLabel::getDefaultHeight();
86
}
87
88
89
void
90
MFXDynamicLabel::computeIndentation() {
91
if (myOriginalString.find(myIndentString) == 0 || myOriginalString.find("\n" + myIndentString) != std::string::npos) {
92
myIndent = (int)myIndentString.size();
93
} else {
94
myIndent = 0;
95
}
96
}
97
98
99
void
100
MFXDynamicLabel::reformatLineBreaks(const int curWidth) {
101
const int preferredWidth = curWidth - getPadLeft() - getPadRight();
102
const int textWidth = getApp()->getNormalFont()->getTextWidth(label);
103
if (textWidth <= preferredWidth || preferredWidth < 1) {
104
return;
105
}
106
std::string newLine = "\n" + std::string(myIndent, ' ');
107
const int newLineOffset = (int)newLine.size();
108
std::string msg = myOriginalString;
109
int pos = 0;
110
int finalPos = (int)msg.size() - 1;
111
std::string::size_type nextLineBreak;
112
while (pos < finalPos) {
113
nextLineBreak = msg.find('\n', pos);
114
int subPos = (nextLineBreak != std::string::npos) ? (int)nextLineBreak : finalPos;
115
if (getApp()->getNormalFont()->getTextWidth(msg.substr(pos, subPos - pos).c_str()) <= preferredWidth) {
116
pos = subPos + 1;
117
continue;
118
}
119
if (myIndent > 0 && msg.substr(pos, myIndent) == myIndentString) {
120
pos += myIndent;
121
}
122
// select position for next line break
123
const int endPos = (nextLineBreak != std::string::npos) ? (int)nextLineBreak - 1 : finalPos;
124
std::string::size_type nextSpace = std::string::npos;
125
int lastSpacePos = -1;
126
int pos2 = pos;
127
while (pos2 < endPos) {
128
nextSpace = msg.find(' ', pos2);
129
if (nextSpace != std::string::npos && (int)nextSpace <= pos + myIndent) {
130
nextSpace = std::string::npos;
131
pos2 += myIndent + 1;
132
} else if (nextSpace != std::string::npos && (int)nextSpace < endPos) {
133
std::string testString = msg.substr(pos, nextSpace - pos);
134
if (getApp()->getNormalFont()->getTextWidth(msg.substr(pos, nextSpace - pos).c_str()) > preferredWidth) {
135
if (lastSpacePos > 0) {
136
msg.replace(lastSpacePos, 1, newLine);
137
pos2 = lastSpacePos + newLineOffset;
138
finalPos += newLineOffset;
139
} else {
140
msg.replace(nextSpace, 1, newLine);
141
pos2 = (int)nextSpace + newLineOffset;
142
finalPos += newLineOffset;
143
}
144
break;
145
} else {
146
pos2 = (int)nextSpace + 1;
147
if (msg.find(' ', pos2) == std::string::npos && lastSpacePos > 0) { // string end condition
148
msg.replace(lastSpacePos, 1, newLine);
149
pos2 += newLineOffset;
150
break;
151
}
152
}
153
lastSpacePos = (int)nextSpace;
154
} else {
155
pos2 = endPos + 2;
156
}
157
}
158
pos = pos2;
159
}
160
label = msg.c_str();
161
}
162
163
164
MFXDynamicLabel::MFXDynamicLabel() {}
165
166