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