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