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