xref: /haiku/src/kits/interface/StringView.cpp (revision 89d652d5e0defd9d095c778709cef82f5f10c357)
1 /*
2  * Copyright 2001-2008, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Frans van Nispen (xlr8@tref.nl)
7  *		Ingo Weinhold <ingo_weinhold@gmx.de>
8  *		Stephan Aßmus <superstippi@gmx.de>
9  */
10 
11 //!	BStringView draws a non-editable text string.
12 
13 
14 #include <StringView.h>
15 
16 #include <LayoutUtils.h>
17 #include <Message.h>
18 #include <View.h>
19 #include <Window.h>
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include <binary_compatibility/Interface.h>
26 
27 
28 BStringView::BStringView(BRect frame, const char* name, const char* text,
29 			uint32 resizeMask, uint32 flags)
30 	:	BView(frame, name, resizeMask, flags | B_FULL_UPDATE_ON_RESIZE),
31 		fText(text ? strdup(text) : NULL),
32 		fStringWidth(text ? StringWidth(text) : 0.0),
33 		fAlign(B_ALIGN_LEFT),
34 		fPreferredSize(-1, -1)
35 {
36 }
37 
38 
39 BStringView::BStringView(const char* name, const char* text, uint32 flags)
40 	:	BView(name, flags | B_FULL_UPDATE_ON_RESIZE),
41 		fText(text ? strdup(text) : NULL),
42 		fStringWidth(text ? StringWidth(text) : 0.0),
43 		fAlign(B_ALIGN_LEFT),
44 		fPreferredSize(-1, -1)
45 {
46 }
47 
48 
49 BStringView::BStringView(BMessage* data)
50 	:	BView(data),
51 		fText(NULL),
52 		fStringWidth(0.0),
53 		fPreferredSize(-1, -1)
54 {
55 	int32 align;
56 	if (data->FindInt32("_align", &align) == B_OK)
57 		fAlign = (alignment)align;
58 	else
59 		fAlign = B_ALIGN_LEFT;
60 
61 	const char* text;
62 	if (data->FindString("_text", &text) != B_OK)
63 		text = NULL;
64 
65 	SetText(text);
66 	SetFlags(Flags() | B_FULL_UPDATE_ON_RESIZE);
67 }
68 
69 
70 BStringView::~BStringView()
71 {
72 	free(fText);
73 }
74 
75 
76 BArchivable*
77 BStringView::Instantiate(BMessage* data)
78 {
79 	if (!validate_instantiation(data, "BStringView"))
80 		return NULL;
81 
82 	return new BStringView(data);
83 }
84 
85 
86 status_t
87 BStringView::Archive(BMessage* data, bool deep) const
88 {
89 	status_t err = BView::Archive(data, deep);
90 
91 	if (err == B_OK && fText)
92 		err = data->AddString("_text", fText);
93 
94 	if (err == B_OK)
95 		err = data->AddInt32("_align", fAlign);
96 
97 	return err;
98 }
99 
100 
101 // #pragma mark -
102 
103 
104 void
105 BStringView::AttachedToWindow()
106 {
107 	rgb_color color = B_TRANSPARENT_COLOR;
108 
109 	BView* parent = Parent();
110 	if (parent != NULL)
111 		color = parent->ViewColor();
112 
113 	if (color == B_TRANSPARENT_COLOR)
114 		color = ui_color(B_PANEL_BACKGROUND_COLOR);
115 
116 	SetViewColor(color);
117 }
118 
119 
120 void
121 BStringView::DetachedFromWindow()
122 {
123 	BView::DetachedFromWindow();
124 }
125 
126 
127 void
128 BStringView::AllAttached()
129 {
130 	BView::AllAttached();
131 }
132 
133 
134 void
135 BStringView::AllDetached()
136 {
137 	BView::AllDetached();
138 }
139 
140 
141 // #pragma mark -
142 
143 
144 void
145 BStringView::MakeFocus(bool state)
146 {
147 	BView::MakeFocus(state);
148 }
149 
150 
151 void
152 BStringView::GetPreferredSize(float* _width, float* _height)
153 {
154 	_ValidatePreferredSize();
155 
156 	if (_width)
157 		*_width = fPreferredSize.width;
158 
159 	if (_height)
160 		*_height = fPreferredSize.height;
161 }
162 
163 
164 BSize
165 BStringView::MinSize()
166 {
167 	return BLayoutUtils::ComposeSize(ExplicitMinSize(),
168 		_ValidatePreferredSize());
169 }
170 
171 
172 BSize
173 BStringView::MaxSize()
174 {
175 	return BLayoutUtils::ComposeSize(ExplicitMaxSize(),
176 		_ValidatePreferredSize());
177 }
178 
179 
180 BSize
181 BStringView::PreferredSize()
182 {
183 	return BLayoutUtils::ComposeSize(ExplicitPreferredSize(),
184 		_ValidatePreferredSize());
185 }
186 
187 
188 void
189 BStringView::InvalidateLayout(bool descendants)
190 {
191 	// invalidate cached preferred size
192 	fPreferredSize.Set(-1, -1);
193 
194 	BView::InvalidateLayout(descendants);
195 }
196 
197 
198 void
199 BStringView::ResizeToPreferred()
200 {
201 	float width, height;
202 	GetPreferredSize(&width, &height);
203 
204 	// Resize the width only for B_ALIGN_LEFT (if its large enough already, that is)
205 	if (Bounds().Width() > width && Alignment() != B_ALIGN_LEFT)
206 		width = Bounds().Width();
207 
208 	BView::ResizeTo(width, height);
209 }
210 
211 
212 void
213 BStringView::FrameMoved(BPoint newPosition)
214 {
215 	BView::FrameMoved(newPosition);
216 }
217 
218 
219 void
220 BStringView::FrameResized(float newWidth, float newHeight)
221 {
222 	BView::FrameResized(newWidth, newHeight);
223 }
224 
225 
226 // #pragma mark -
227 
228 
229 void
230 BStringView::Draw(BRect updateRect)
231 {
232 	if (!fText)
233 		return;
234 
235 	SetLowColor(ViewColor());
236 
237 	font_height fontHeight;
238 	GetFontHeight(&fontHeight);
239 
240 	BRect bounds = Bounds();
241 
242 	float y = (bounds.top + bounds.bottom - ceilf(fontHeight.ascent)
243 		- ceilf(fontHeight.descent)) / 2.0 + ceilf(fontHeight.ascent);
244 	float x;
245 	switch (fAlign) {
246 		case B_ALIGN_RIGHT:
247 			x = bounds.Width() - fStringWidth;
248 			break;
249 
250 		case B_ALIGN_CENTER:
251 			x = (bounds.Width() - fStringWidth) / 2.0;
252 			break;
253 
254 		default:
255 			x = 0.0;
256 			break;
257 	}
258 
259 	DrawString(fText, BPoint(x, y));
260 }
261 
262 
263 void
264 BStringView::MessageReceived(BMessage* message)
265 {
266 	BView::MessageReceived(message);
267 }
268 
269 
270 void
271 BStringView::MouseDown(BPoint point)
272 {
273 	BView::MouseDown(point);
274 }
275 
276 
277 void
278 BStringView::MouseUp(BPoint point)
279 {
280 	BView::MouseUp(point);
281 }
282 
283 
284 void
285 BStringView::MouseMoved(BPoint point, uint32 transit, const BMessage* msg)
286 {
287 	BView::MouseMoved(point, transit, msg);
288 }
289 
290 
291 // #pragma mark -
292 
293 
294 void
295 BStringView::SetText(const char* text)
296 {
297 	if ((text && fText && !strcmp(text, fText)) || (!text && !fText))
298 		return;
299 
300 	free(fText);
301 	fText = text ? strdup(text) : NULL;
302 
303 	float newStringWidth = StringWidth(fText);
304 	if (fStringWidth != newStringWidth) {
305 		fStringWidth = newStringWidth;
306 		InvalidateLayout();
307 	}
308 
309 	Invalidate();
310 }
311 
312 
313 const char*
314 BStringView::Text() const
315 {
316 	return fText;
317 }
318 
319 
320 void
321 BStringView::SetAlignment(alignment flag)
322 {
323 	fAlign = flag;
324 	Invalidate();
325 }
326 
327 
328 alignment
329 BStringView::Alignment() const
330 {
331 	return fAlign;
332 }
333 
334 
335 BHandler*
336 BStringView::ResolveSpecifier(BMessage* msg, int32 index,
337 	BMessage* specifier, int32 form, const char* property)
338 {
339 	return NULL;
340 }
341 
342 
343 status_t
344 BStringView::GetSupportedSuites(BMessage* message)
345 {
346 	return BView::GetSupportedSuites(message);
347 }
348 
349 
350 void
351 BStringView::SetFont(const BFont* font, uint32 mask)
352 {
353 	BView::SetFont(font, mask);
354 
355 	fStringWidth = StringWidth(fText);
356 
357 	Invalidate();
358 	InvalidateLayout();
359 }
360 
361 
362 // #pragma mark -
363 
364 
365 status_t
366 BStringView::Perform(perform_code code, void* _data)
367 {
368 	switch (code) {
369 		case PERFORM_CODE_MIN_SIZE:
370 			((perform_data_min_size*)_data)->return_value
371 				= BStringView::MinSize();
372 			return B_OK;
373 		case PERFORM_CODE_MAX_SIZE:
374 			((perform_data_max_size*)_data)->return_value
375 				= BStringView::MaxSize();
376 			return B_OK;
377 		case PERFORM_CODE_PREFERRED_SIZE:
378 			((perform_data_preferred_size*)_data)->return_value
379 				= BStringView::PreferredSize();
380 			return B_OK;
381 		case PERFORM_CODE_LAYOUT_ALIGNMENT:
382 			((perform_data_layout_alignment*)_data)->return_value
383 				= BStringView::LayoutAlignment();
384 			return B_OK;
385 		case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
386 			((perform_data_has_height_for_width*)_data)->return_value
387 				= BStringView::HasHeightForWidth();
388 			return B_OK;
389 		case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
390 		{
391 			perform_data_get_height_for_width* data
392 				= (perform_data_get_height_for_width*)_data;
393 			BStringView::GetHeightForWidth(data->width, &data->min, &data->max,
394 				&data->preferred);
395 			return B_OK;
396 		}
397 		case PERFORM_CODE_SET_LAYOUT:
398 		{
399 			perform_data_set_layout* data = (perform_data_set_layout*)_data;
400 			BStringView::SetLayout(data->layout);
401 			return B_OK;
402 		}
403 		case PERFORM_CODE_INVALIDATE_LAYOUT:
404 		{
405 			perform_data_invalidate_layout* data
406 				= (perform_data_invalidate_layout*)_data;
407 			BStringView::InvalidateLayout(data->descendants);
408 			return B_OK;
409 		}
410 		case PERFORM_CODE_DO_LAYOUT:
411 		{
412 			BStringView::DoLayout();
413 			return B_OK;
414 		}
415 	}
416 
417 	return BView::Perform(code, _data);
418 }
419 
420 
421 
422 void BStringView::_ReservedStringView1() {}
423 void BStringView::_ReservedStringView2() {}
424 void BStringView::_ReservedStringView3() {}
425 
426 
427 BStringView&
428 BStringView::operator=(const BStringView&)
429 {
430 	// Assignment not allowed (private)
431 	return *this;
432 }
433 
434 
435 // #pragma mark -
436 
437 
438 BSize
439 BStringView::_ValidatePreferredSize()
440 {
441 	if (fPreferredSize.width < 0) {
442 		// width
443 		fPreferredSize.width = ceilf(fStringWidth);
444 
445 		// height
446 		font_height fontHeight;
447 		GetFontHeight(&fontHeight);
448 
449 		fPreferredSize.height = ceilf(fontHeight.ascent + fontHeight.descent
450 			+ fontHeight.leading);
451 
452 		ResetLayoutInvalidation();
453 	}
454 
455 	return fPreferredSize;
456 }
457 
458