xref: /haiku/src/kits/interface/StringView.cpp (revision 1b6bc2675fe3691538c8764ab016593f3b06ca53)
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::ResizeToPreferred()
190 {
191 	float width, height;
192 	GetPreferredSize(&width, &height);
193 
194 	// Resize the width only for B_ALIGN_LEFT (if its large enough already, that is)
195 	if (Bounds().Width() > width && Alignment() != B_ALIGN_LEFT)
196 		width = Bounds().Width();
197 
198 	BView::ResizeTo(width, height);
199 }
200 
201 
202 void
203 BStringView::FrameMoved(BPoint newPosition)
204 {
205 	BView::FrameMoved(newPosition);
206 }
207 
208 
209 void
210 BStringView::FrameResized(float newWidth, float newHeight)
211 {
212 	BView::FrameResized(newWidth, newHeight);
213 }
214 
215 
216 // #pragma mark -
217 
218 
219 void
220 BStringView::Draw(BRect updateRect)
221 {
222 	if (!fText)
223 		return;
224 
225 	SetLowColor(ViewColor());
226 
227 	font_height fontHeight;
228 	GetFontHeight(&fontHeight);
229 
230 	BRect bounds = Bounds();
231 
232 	float y = (bounds.top + bounds.bottom - ceilf(fontHeight.ascent)
233 		- ceilf(fontHeight.descent)) / 2.0 + ceilf(fontHeight.ascent);
234 	float x;
235 	switch (fAlign) {
236 		case B_ALIGN_RIGHT:
237 			x = bounds.Width() - fStringWidth;
238 			break;
239 
240 		case B_ALIGN_CENTER:
241 			x = (bounds.Width() - fStringWidth) / 2.0;
242 			break;
243 
244 		default:
245 			x = 0.0;
246 			break;
247 	}
248 
249 	DrawString(fText, BPoint(x, y));
250 }
251 
252 
253 void
254 BStringView::MessageReceived(BMessage* message)
255 {
256 	BView::MessageReceived(message);
257 }
258 
259 
260 void
261 BStringView::MouseDown(BPoint point)
262 {
263 	BView::MouseDown(point);
264 }
265 
266 
267 void
268 BStringView::MouseUp(BPoint point)
269 {
270 	BView::MouseUp(point);
271 }
272 
273 
274 void
275 BStringView::MouseMoved(BPoint point, uint32 transit, const BMessage* msg)
276 {
277 	BView::MouseMoved(point, transit, msg);
278 }
279 
280 
281 // #pragma mark -
282 
283 
284 void
285 BStringView::SetText(const char* text)
286 {
287 	if ((text && fText && !strcmp(text, fText)) || (!text && !fText))
288 		return;
289 
290 	free(fText);
291 	fText = text ? strdup(text) : NULL;
292 
293 	float newStringWidth = StringWidth(fText);
294 	if (fStringWidth != newStringWidth) {
295 		fStringWidth = newStringWidth;
296 		InvalidateLayout();
297 	}
298 
299 	Invalidate();
300 }
301 
302 
303 const char*
304 BStringView::Text() const
305 {
306 	return fText;
307 }
308 
309 
310 void
311 BStringView::SetAlignment(alignment flag)
312 {
313 	fAlign = flag;
314 	Invalidate();
315 }
316 
317 
318 alignment
319 BStringView::Alignment() const
320 {
321 	return fAlign;
322 }
323 
324 
325 BHandler*
326 BStringView::ResolveSpecifier(BMessage* msg, int32 index,
327 	BMessage* specifier, int32 form, const char* property)
328 {
329 	return NULL;
330 }
331 
332 
333 status_t
334 BStringView::GetSupportedSuites(BMessage* message)
335 {
336 	return BView::GetSupportedSuites(message);
337 }
338 
339 
340 void
341 BStringView::SetFont(const BFont* font, uint32 mask)
342 {
343 	BView::SetFont(font, mask);
344 
345 	fStringWidth = StringWidth(fText);
346 
347 	Invalidate();
348 	InvalidateLayout();
349 }
350 
351 
352 void
353 BStringView::LayoutInvalidated(bool descendants)
354 {
355 	// invalidate cached preferred size
356 	fPreferredSize.Set(-1, -1);
357 }
358 
359 
360 // #pragma mark -
361 
362 
363 status_t
364 BStringView::Perform(perform_code code, void* _data)
365 {
366 	switch (code) {
367 		case PERFORM_CODE_MIN_SIZE:
368 			((perform_data_min_size*)_data)->return_value
369 				= BStringView::MinSize();
370 			return B_OK;
371 		case PERFORM_CODE_MAX_SIZE:
372 			((perform_data_max_size*)_data)->return_value
373 				= BStringView::MaxSize();
374 			return B_OK;
375 		case PERFORM_CODE_PREFERRED_SIZE:
376 			((perform_data_preferred_size*)_data)->return_value
377 				= BStringView::PreferredSize();
378 			return B_OK;
379 		case PERFORM_CODE_LAYOUT_ALIGNMENT:
380 			((perform_data_layout_alignment*)_data)->return_value
381 				= BStringView::LayoutAlignment();
382 			return B_OK;
383 		case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
384 			((perform_data_has_height_for_width*)_data)->return_value
385 				= BStringView::HasHeightForWidth();
386 			return B_OK;
387 		case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
388 		{
389 			perform_data_get_height_for_width* data
390 				= (perform_data_get_height_for_width*)_data;
391 			BStringView::GetHeightForWidth(data->width, &data->min, &data->max,
392 				&data->preferred);
393 			return B_OK;
394 		}
395 		case PERFORM_CODE_SET_LAYOUT:
396 		{
397 			perform_data_set_layout* data = (perform_data_set_layout*)_data;
398 			BStringView::SetLayout(data->layout);
399 			return B_OK;
400 		}
401 		case PERFORM_CODE_LAYOUT_INVALIDATED:
402 		{
403 			perform_data_layout_invalidated* data
404 				= (perform_data_layout_invalidated*)_data;
405 			BStringView::LayoutInvalidated(data->descendants);
406 			return B_OK;
407 		}
408 		case PERFORM_CODE_DO_LAYOUT:
409 		{
410 			BStringView::DoLayout();
411 			return B_OK;
412 		}
413 	}
414 
415 	return BView::Perform(code, _data);
416 }
417 
418 
419 
420 void BStringView::_ReservedStringView1() {}
421 void BStringView::_ReservedStringView2() {}
422 void BStringView::_ReservedStringView3() {}
423 
424 
425 BStringView&
426 BStringView::operator=(const BStringView&)
427 {
428 	// Assignment not allowed (private)
429 	return *this;
430 }
431 
432 
433 // #pragma mark -
434 
435 
436 BSize
437 BStringView::_ValidatePreferredSize()
438 {
439 	if (fPreferredSize.width < 0) {
440 		// width
441 		fPreferredSize.width = ceilf(fStringWidth);
442 
443 		// height
444 		font_height fontHeight;
445 		GetFontHeight(&fontHeight);
446 
447 		fPreferredSize.height = ceilf(fontHeight.ascent + fontHeight.descent
448 			+ fontHeight.leading);
449 
450 		ResetLayoutInvalidation();
451 	}
452 
453 	return fPreferredSize;
454 }
455 
456 
457 #if __GNUC__ == 2
458 
459 
460 extern "C" void
461 InvalidateLayout__11BStringViewb(BView* view, bool descendants)
462 {
463 	perform_data_layout_invalidated data;
464 	data.descendants = descendants;
465 
466 	view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data);
467 }
468 
469 
470 #endif
471