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