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