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