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