Eclipse SUMO - Simulation of Urban MObility
MFXDynamicLabel.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 // Copyright (C) 2001-2024 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 /****************************************************************************/
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();
64 }
65 
66 
67 void
68 MFXDynamicLabel::position(FXint x, FXint y, FXint w, FXint h) {
69  FXLabel::position(x, y, w, h);
71 }
72 
73 
74 FXint
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
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
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 
FXDEFMAP(MFXDynamicLabel) MFXLabelMap[]
A list item which allows for custom coloring.
void reformatLineBreaks(const int curWidth)
MFXDynamicLabel()
fox needs this
void setText(const FXString &text)
overload text label updates to store the original string as backup for when width changes again
void position(FXint x, FXint y, FXint w, FXint h)
overload position to be informed when the parent has done the layout
long onUpdate(FXObject *sender, FXSelector, void *)
overload to be informed when the label text has to be reformatted due to width changes
std::string myOriginalString
std::string myIndentString
Definition: json.hpp:4471