2 * Copyright 2001-2015, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Stephan Aßmus <superstippi@gmx.de>
7 * Axel Dörfler, axeld@pinc-software.de
8 * Frans van Nispen (xlr8@tref.nl)
9 * Ingo Weinhold <ingo_weinhold@gmx.de>
13 //! BStringView draws a non-editable text string.
16 #include <StringView.h>
22 #include <LayoutUtils.h>
24 #include <PropertyInfo.h>
28 #include <binary_compatibility/Interface.h>
31 static property_info sPropertyList
[] = {
34 { B_GET_PROPERTY
, B_SET_PROPERTY
},
35 { B_DIRECT_SPECIFIER
},
41 { B_GET_PROPERTY
, B_SET_PROPERTY
},
42 { B_DIRECT_SPECIFIER
},
50 BStringView::BStringView(BRect frame
, const char* name
, const char* text
,
51 uint32 resizingMode
, uint32 flags
)
53 BView(frame
, name
, resizingMode
, flags
| B_FULL_UPDATE_ON_RESIZE
),
54 fText(text
? strdup(text
) : NULL
),
55 fTruncation(B_NO_TRUNCATION
),
57 fPreferredSize(text
? StringWidth(text
) : 0.0, -1)
62 BStringView::BStringView(const char* name
, const char* text
, uint32 flags
)
64 BView(name
, flags
| B_FULL_UPDATE_ON_RESIZE
),
65 fText(text
? strdup(text
) : NULL
),
66 fTruncation(B_NO_TRUNCATION
),
68 fPreferredSize(text
? StringWidth(text
) : 0.0, -1)
73 BStringView::BStringView(BMessage
* archive
)
77 fTruncation(B_NO_TRUNCATION
),
80 fAlign
= (alignment
)archive
->GetInt32("_align", B_ALIGN_LEFT
);
81 fTruncation
= (uint32
)archive
->GetInt32("_truncation", B_NO_TRUNCATION
);
83 const char* text
= archive
->GetString("_text", NULL
);
86 SetFlags(Flags() | B_FULL_UPDATE_ON_RESIZE
);
90 BStringView::~BStringView()
96 // #pragma mark - Archiving methods
100 BStringView::Instantiate(BMessage
* data
)
102 if (!validate_instantiation(data
, "BStringView"))
105 return new BStringView(data
);
110 BStringView::Archive(BMessage
* data
, bool deep
) const
112 status_t status
= BView::Archive(data
, deep
);
114 if (status
== B_OK
&& fText
)
115 status
= data
->AddString("_text", fText
);
116 if (status
== B_OK
&& fTruncation
!= B_NO_TRUNCATION
)
117 status
= data
->AddInt32("_truncation", fTruncation
);
119 status
= data
->AddInt32("_align", fAlign
);
125 // #pragma mark - Hook methods
129 BStringView::AttachedToWindow()
131 rgb_color color
= B_TRANSPARENT_COLOR
;
133 BView
* parent
= Parent();
135 color
= parent
->ViewColor();
137 if (color
== B_TRANSPARENT_COLOR
)
138 color
= ui_color(B_PANEL_BACKGROUND_COLOR
);
145 BStringView::DetachedFromWindow()
147 BView::DetachedFromWindow();
152 BStringView::AllAttached()
154 BView::AllAttached();
159 BStringView::AllDetached()
161 BView::AllDetached();
165 // #pragma mark - Layout methods
169 BStringView::MakeFocus(bool focus
)
171 BView::MakeFocus(focus
);
176 BStringView::GetPreferredSize(float* _width
, float* _height
)
178 _ValidatePreferredSize();
181 *_width
= fPreferredSize
.width
;
184 *_height
= fPreferredSize
.height
;
189 BStringView::MinSize()
191 return BLayoutUtils::ComposeSize(ExplicitMinSize(),
192 _ValidatePreferredSize());
197 BStringView::MaxSize()
199 return BLayoutUtils::ComposeSize(ExplicitMaxSize(),
200 _ValidatePreferredSize());
205 BStringView::PreferredSize()
207 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(),
208 _ValidatePreferredSize());
213 BStringView::ResizeToPreferred()
216 GetPreferredSize(&width
, &height
);
218 // Resize the width only for B_ALIGN_LEFT (if its large enough already, that is)
219 if (Bounds().Width() > width
&& Alignment() != B_ALIGN_LEFT
)
220 width
= Bounds().Width();
222 BView::ResizeTo(width
, height
);
227 BStringView::LayoutAlignment()
229 return BLayoutUtils::ComposeAlignment(ExplicitAlignment(),
230 BAlignment(fAlign
, B_ALIGN_MIDDLE
));
234 // #pragma mark - More hook methods
238 BStringView::FrameMoved(BPoint newPosition
)
240 BView::FrameMoved(newPosition
);
245 BStringView::FrameResized(float newWidth
, float newHeight
)
247 BView::FrameResized(newWidth
, newHeight
);
252 BStringView::Draw(BRect updateRect
)
257 SetLowColor(ViewColor());
259 font_height fontHeight
;
260 GetFontHeight(&fontHeight
);
262 BRect bounds
= Bounds();
264 const char* text
= fText
;
265 float width
= fPreferredSize
.width
;
267 if (fTruncation
!= B_NO_TRUNCATION
&& width
> bounds
.Width()) {
268 // The string needs to be truncated
269 // TODO: we should cache this
271 TruncateString(&truncated
, fTruncation
, bounds
.Width());
272 text
= truncated
.String();
273 width
= StringWidth(text
);
276 float y
= (bounds
.top
+ bounds
.bottom
- ceilf(fontHeight
.ascent
)
277 - ceilf(fontHeight
.descent
)) / 2.0 + ceilf(fontHeight
.ascent
);
281 x
= bounds
.Width() - width
;
285 x
= (bounds
.Width() - width
) / 2.0;
293 DrawString(text
, BPoint(x
, y
));
298 BStringView::MessageReceived(BMessage
* message
)
300 if (message
->what
== B_GET_PROPERTY
|| message
->what
== B_SET_PROPERTY
) {
304 const char* property
;
305 if (message
->GetCurrentSpecifier(&index
, &specifier
, &form
, &property
)
307 BView::MessageReceived(message
);
311 BMessage
reply(B_REPLY
);
312 bool handled
= false;
313 if (strcmp(property
, "Text") == 0) {
314 if (message
->what
== B_GET_PROPERTY
) {
315 reply
.AddString("result", fText
);
319 if (message
->FindString("data", &text
) == B_OK
) {
321 reply
.AddInt32("error", B_OK
);
325 } else if (strcmp(property
, "Alignment") == 0) {
326 if (message
->what
== B_GET_PROPERTY
) {
327 reply
.AddInt32("result", (int32
)fAlign
);
331 if (message
->FindInt32("data", &align
) == B_OK
) {
332 SetAlignment((alignment
)align
);
333 reply
.AddInt32("error", B_OK
);
340 message
->SendReply(&reply
);
345 BView::MessageReceived(message
);
350 BStringView::MouseDown(BPoint point
)
352 BView::MouseDown(point
);
357 BStringView::MouseUp(BPoint point
)
359 BView::MouseUp(point
);
364 BStringView::MouseMoved(BPoint point
, uint32 transit
, const BMessage
* msg
)
366 BView::MouseMoved(point
, transit
, msg
);
374 BStringView::SetText(const char* text
)
376 if ((text
&& fText
&& !strcmp(text
, fText
)) || (!text
&& !fText
))
380 fText
= text
? strdup(text
) : NULL
;
382 float newStringWidth
= StringWidth(fText
);
383 if (fPreferredSize
.width
!= newStringWidth
) {
384 fPreferredSize
.width
= newStringWidth
;
393 BStringView::Text() const
400 BStringView::SetAlignment(alignment flag
)
408 BStringView::Alignment() const
415 BStringView::SetTruncation(uint32 truncationMode
)
417 if (fTruncation
!= truncationMode
) {
418 fTruncation
= truncationMode
;
425 BStringView::Truncation() const
432 BStringView::ResolveSpecifier(BMessage
* message
, int32 index
,
433 BMessage
* specifier
, int32 form
, const char* property
)
435 BPropertyInfo
propInfo(sPropertyList
);
436 if (propInfo
.FindMatch(message
, 0, specifier
, form
, property
) >= B_OK
)
439 return BView::ResolveSpecifier(message
, index
, specifier
, form
, property
);
444 BStringView::GetSupportedSuites(BMessage
* data
)
449 status_t status
= data
->AddString("suites", "suite/vnd.Be-string-view");
453 BPropertyInfo
propertyInfo(sPropertyList
);
454 status
= data
->AddFlat("messages", &propertyInfo
);
458 return BView::GetSupportedSuites(data
);
463 BStringView::SetFont(const BFont
* font
, uint32 mask
)
465 BView::SetFont(font
, mask
);
467 fPreferredSize
.width
= StringWidth(fText
);
475 BStringView::LayoutInvalidated(bool descendants
)
477 // invalidate cached preferred size
478 fPreferredSize
.height
= -1;
482 // #pragma mark - Perform
486 BStringView::Perform(perform_code code
, void* _data
)
489 case PERFORM_CODE_MIN_SIZE
:
490 ((perform_data_min_size
*)_data
)->return_value
491 = BStringView::MinSize();
494 case PERFORM_CODE_MAX_SIZE
:
495 ((perform_data_max_size
*)_data
)->return_value
496 = BStringView::MaxSize();
499 case PERFORM_CODE_PREFERRED_SIZE
:
500 ((perform_data_preferred_size
*)_data
)->return_value
501 = BStringView::PreferredSize();
504 case PERFORM_CODE_LAYOUT_ALIGNMENT
:
505 ((perform_data_layout_alignment
*)_data
)->return_value
506 = BStringView::LayoutAlignment();
509 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH
:
510 ((perform_data_has_height_for_width
*)_data
)->return_value
511 = BStringView::HasHeightForWidth();
514 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH
:
516 perform_data_get_height_for_width
* data
517 = (perform_data_get_height_for_width
*)_data
;
518 BStringView::GetHeightForWidth(data
->width
, &data
->min
, &data
->max
,
523 case PERFORM_CODE_SET_LAYOUT
:
525 perform_data_set_layout
* data
= (perform_data_set_layout
*)_data
;
526 BStringView::SetLayout(data
->layout
);
530 case PERFORM_CODE_LAYOUT_INVALIDATED
:
532 perform_data_layout_invalidated
* data
533 = (perform_data_layout_invalidated
*)_data
;
534 BStringView::LayoutInvalidated(data
->descendants
);
538 case PERFORM_CODE_DO_LAYOUT
:
540 BStringView::DoLayout();
545 return BView::Perform(code
, _data
);
549 // #pragma mark - FBC padding methods
552 void BStringView::_ReservedStringView1() {}
553 void BStringView::_ReservedStringView2() {}
554 void BStringView::_ReservedStringView3() {}
557 // #pragma mark - Private methods
561 BStringView::operator=(const BStringView
&)
563 // Assignment not allowed (private)
569 BStringView::_ValidatePreferredSize()
571 if (fPreferredSize
.height
< 0) {
573 font_height fontHeight
;
574 GetFontHeight(&fontHeight
);
576 fPreferredSize
.height
= ceilf(fontHeight
.ascent
+ fontHeight
.descent
577 + fontHeight
.leading
);
579 ResetLayoutInvalidation();
582 return fPreferredSize
;
587 B_IF_GCC_2(InvalidateLayout__11BStringViewb
,
588 _ZN11BStringView16InvalidateLayoutEb
)(BView
* view
, bool descendants
)
590 perform_data_layout_invalidated data
;
591 data
.descendants
= descendants
;
593 view
->Perform(PERFORM_CODE_LAYOUT_INVALIDATED
, &data
);