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