1
2
3
4
5
6 using System;
7 using System.Collections;
8
9 namespace System.Windows
10 {
11 public Color DefaultToolTipTextColor()
12 {
13 return Color.Black();
14 }
15
16 public Color DefaultToolTipFrameColor()
17 {
18 return Color.Black();
19 }
20
21 public string DefaultToolTipFontFamilyName()
22 {
23 return "Segoe UI";
24 }
25
26 public float DefaultToolTipFontSize()
27 {
28 return 9.000000f;
29 }
30
31 public ControlCreateParams& ToolTipControlCreateParams(ControlCreateParams& controlCreateParams)
32 {
33 return controlCreateParams.SetWindowClassName("System.Windows.ToolTip").SetWindowStyle(HiddenChildWindowStyle()).
34 SetWindowClassBackgroundColor(SystemColor.COLOR_WINDOW).SetBackgroundColor(Color.FloralWhite()).SetSize(Size(0, 0));
35 }
36
37 public class ToolTipCreateParams
38 {
39 public ToolTipCreateParams(ControlCreateParams& controlCreateParams_) :
40 controlCreateParams(controlCreateParams_),
41 textColor(DefaultToolTipTextColor()),
42 frameColor(DefaultToolTipFrameColor()),
43 fontFamilyName(DefaultToolTipFontFamilyName()),
44 fontSize(DefaultToolTipFontSize())
45 {
46 }
47 public ToolTipCreateParams& Defaults()
48 {
49 return *this;
50 }
51 public ToolTipCreateParams& SetTextColor(const Color& textColor_)
52 {
53 textColor = textColor_;
54 return *this;
55 }
56 public ToolTipCreateParams& SetFrameColor(const Color& frameColor_)
57 {
58 frameColor = frameColor_;
59 return *this;
60 }
61 public ToolTipCreateParams& SetFontFamilyName(const string& fontFamilyName_)
62 {
63 fontFamilyName = fontFamilyName_;
64 return *this;
65 }
66 public ToolTipCreateParams& SetFontSize(float fontSize_)
67 {
68 fontSize = fontSize_;
69 return *this;
70 }
71 public ControlCreateParams& controlCreateParams;
72 public Color textColor;
73 public Color frameColor;
74 public string fontFamilyName;
75 public float fontSize;
76 }
77
78 public class ToolTip : Control
79 {
80 private enum Flags : sbyte
81 {
82 none = 0, changed = 1 << 0
83 }
84 public ToolTip(const Color& backgroundColor, const Color& textColor, const Color& frameColor, const string& text_, const Point& location_,
85 const Font& font_) :
86 base("System.Windows.ToolTip", DefaultWindowClassStyle(), HiddenChildWindowStyle(), DefaultExtendedWindowStyle(), backgroundColor,
87 text_, location_, Size(0, 0), Dock.none, Anchors.none), framePen(frameColor), font(font_), textBrush(textColor),
88 format(StringAlignment.near, StringAlignment.near), textHeight(0)
89 {
90 SetChanged();
91 }
92 public ToolTip(const Color& backgroundColor) :
93 this(backgroundColor, Color.Black(), Color.Black(), "", Point(0, 0), Font(FontFamily("Segoe UI"), 9.000000f))
94 {
95 }
96 public ToolTip() : this(Color.FloralWhite())
97 {
98 }
99 public ToolTip(ToolTipCreateParams& createParams) :
100 base(createParams.controlCreateParams),
101 framePen(createParams.frameColor),
102 font(FontFamily(createParams.fontFamilyName), createParams.fontSize),
103 textBrush(createParams.textColor),
104 format(StringAlignment.near, StringAlignment.near), textHeight(0)
105 {
106 SetChanged();
107 }
108 [nodiscard]
109 public Result<bool> SetTextColor(const Color& textColor)
110 {
111 textBrush = SolidBrush(textColor);
112 auto result = Invalidate();
113 if (result.Error()) return result;
114 return Result<bool>(true);
115 }
116 [nodiscard]
117 public Result<bool> SetFrameColor(const Color& frameColor)
118 {
119 framePen = Pen(frameColor);
120 auto result = Invalidate();
121 if (result.Error()) return result;
122 return Result<bool>(true);
123 }
124 [nodiscard]
125 public Result<bool> SetFont(const Font& font_)
126 {
127 font = font_;
128 SetChanged();
129 auto result = Invalidate();
130 if (result.Error()) return result;
131 return Result<bool>(true);
132 }
133 [nodiscard]
134 public Result<bool> MeasureExtent()
135 {
136 auto graphicsResult = Graphics.FromWindowHandle(Handle());
137 if (graphicsResult.Error())
138 {
139 return Result<bool>(ErrorId(graphicsResult.GetErrorId()));
140 }
141 Graphics& graphics = graphicsResult.Value();
142 auto measureResult = Measure(graphics);
143 if (measureResult.Error())
144 {
145 return Result<bool>(ErrorId(measureResult.GetErrorId()));
146 }
147 return Result<bool>(true);
148 }
149 [nodiscard]
150 protected override Result<bool> OnTextChanged()
151 {
152 auto result = base->OnTextChanged();
153 if (result.Error()) return result;
154 lines = SplitIntoLines(Text());
155 SetChanged();
156 result = Invalidate();
157 if (result.Error()) return result;
158 return Result<bool>(true);
159 }
160 [nodiscard]
161 protected override Result<bool> OnPaint(PaintEventArgs& args)
162 {
163 if (Changed())
164 {
165 ResetChanged();
166 auto measureResult = Measure(args.graphics);
167 if (measureResult.Error())
168 {
169 return Result<bool>(ErrorId(measureResult.GetErrorId()));
170 }
171 }
172 Rect r(Point(), GetSize());
173 r.size.w = r.size.w - 1;
174 r.size.h = r.size.h - 1;
175 auto clearResult = args.graphics.Clear(BackgroundColor());
176 if (clearResult.Error())
177 {
178 return Result<bool>(ErrorId(clearResult.GetErrorId()));
179 }
180 auto drawResult = args.graphics.DrawRectangle(framePen, r);
181 if (drawResult.Error())
182 {
183 return Result<bool>(ErrorId(drawResult.GetErrorId()));
184 }
185 PointF pt(1, 1);
186 for (const string& line : lines)
187 {
188 auto drawStringResult = args.graphics.DrawString(line, font, pt, textBrush);
189 if (drawResult.Error())
190 {
191 return Result<bool>(ErrorId(drawResult.GetErrorId()));
192 }
193 pt.y = pt.y + textHeight;
194 }
195 return base->OnPaint(args);
196 }
197 private Result<bool> Measure(Graphics& graphics)
198 {
199 Size size;
200 for (const string& line : lines)
201 {
202 auto measureStringResult = graphics.MeasureStringRectF(line, font, PointF(0, 0), format);
203 if (measureStringResult.Error())
204 {
205 return Result<bool>(ErrorId(measureStringResult.GetErrorId()));
206 }
207 RectF textRect = measureStringResult.Value();
208 textHeight = Max(textHeight, cast<int>(textRect.size.h));
209 size.w = Max(size.w, cast<int>(textRect.size.w));
210 }
211 size.h = cast<int>(lines.Count()) * textHeight;
212 size.w = size.w + 1;
213 size.h = size.h + 1;
214 auto result = SetSize(size);
215 if (result.Error()) return result;
216 return Result<bool>(true);
217 }
218 private inline bool Changed() const
219 {
220 return (flags & Flags.changed) != Flags.none;
221 }
222 private inline void SetChanged()
223 {
224 flags = cast<Flags>(flags | Flags.changed);
225 }
226 private inline void ResetChanged()
227 {
228 flags = cast<Flags>(flags & ~Flags.changed);
229 }
230 private Flags flags;
231 private Pen framePen;
232 private Font font;
233 private SolidBrush textBrush;
234 private StringFormat format;
235 private List<string> lines;
236 private int textHeight;
237 }
238
239 public List<string> SplitIntoLines(const string& text)
240 {
241 List<string> lines;
242 string line;
243 int state = 0;
244 for (char c : text)
245 {
246 switch (state)
247 {
248 case 0:
249 {
250 switch (c)
251 {
252 case '\n':
253 {
254 lines.Add(line);
255 line.Clear();
256 break;
257 }
258 case '\r':
259 {
260 state = 1;
261 break;
262 }
263 default:
264 {
265 line.Append(c);
266 break;
267 }
268 }
269 break;
270 }
271 case 1:
272 {
273 switch (c)
274 {
275 case '\n':
276 {
277 lines.Add(line);
278 line.Clear();
279 state = 0;
280 break;
281 }
282 }
283 break;
284 }
285 }
286 }
287 if (!line.IsEmpty())
288 {
289 lines.Add(line);
290 }
291 return lines;
292 }