1 /* 2 * Copyright 2001-2019 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus, superstippi@gmx.de 7 * Axel Dörfler, axeld@pinc-software.de 8 * Adrian Oanca, adioanca@cotty.iren.ro 9 * Ingo Weinhold. ingo_weinhold@gmx.de 10 * Julian Harnath, julian.harnath@rwth-aachen.de 11 * Joseph Groover, looncraz@looncraz.net 12 */ 13 14 15 #include <View.h> 16 17 #include <algorithm> 18 #include <new> 19 20 #include <math.h> 21 #include <stdio.h> 22 23 #include <Application.h> 24 #include <Bitmap.h> 25 #include <Button.h> 26 #include <Cursor.h> 27 #include <File.h> 28 #include <GradientLinear.h> 29 #include <GradientRadial.h> 30 #include <GradientRadialFocus.h> 31 #include <GradientDiamond.h> 32 #include <GradientConic.h> 33 #include <InterfaceDefs.h> 34 #include <Layout.h> 35 #include <LayoutContext.h> 36 #include <LayoutUtils.h> 37 #include <MenuBar.h> 38 #include <Message.h> 39 #include <MessageQueue.h> 40 #include <ObjectList.h> 41 #include <Picture.h> 42 #include <Point.h> 43 #include <Polygon.h> 44 #include <PropertyInfo.h> 45 #include <Region.h> 46 #include <ScrollBar.h> 47 #include <Shape.h> 48 #include <Shelf.h> 49 #include <String.h> 50 #include <Window.h> 51 52 #include <AppMisc.h> 53 #include <AppServerLink.h> 54 #include <binary_compatibility/Interface.h> 55 #include <binary_compatibility/Support.h> 56 #include <MessagePrivate.h> 57 #include <MessageUtils.h> 58 #include <PortLink.h> 59 #include <ServerProtocol.h> 60 #include <ServerProtocolStructs.h> 61 #include <ShapePrivate.h> 62 #include <ToolTip.h> 63 #include <ToolTipManager.h> 64 #include <TokenSpace.h> 65 #include <ViewPrivate.h> 66 67 using std::nothrow; 68 69 //#define DEBUG_BVIEW 70 #ifdef DEBUG_BVIEW 71 # include <stdio.h> 72 # define STRACE(x) printf x 73 # define BVTRACE _PrintToStream() 74 #else 75 # define STRACE(x) ; 76 # define BVTRACE ; 77 #endif 78 79 80 static property_info sViewPropInfo[] = { 81 { "Frame", { B_GET_PROPERTY, B_SET_PROPERTY }, 82 { B_DIRECT_SPECIFIER, 0 }, "The view's frame rectangle.", 0, 83 { B_RECT_TYPE } 84 }, 85 { "Hidden", { B_GET_PROPERTY, B_SET_PROPERTY }, 86 { B_DIRECT_SPECIFIER, 0 }, "Whether or not the view is hidden.", 87 0, { B_BOOL_TYPE } 88 }, 89 { "Shelf", { 0 }, 90 { B_DIRECT_SPECIFIER, 0 }, "Directs the scripting message to the " 91 "shelf.", 0 92 }, 93 { "View", { B_COUNT_PROPERTIES, 0 }, 94 { B_DIRECT_SPECIFIER, 0 }, "Returns the number of child views.", 0, 95 { B_INT32_TYPE } 96 }, 97 { "View", { 0 }, 98 { B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, B_NAME_SPECIFIER, 0 }, 99 "Directs the scripting message to the specified view.", 0 100 }, 101 102 { 0 } 103 }; 104 105 106 // #pragma mark - 107 108 109 static inline uint32 110 get_uint32_color(rgb_color color) 111 { 112 return B_BENDIAN_TO_HOST_INT32(*(uint32*)&color); 113 // rgb_color is always in rgba format, no matter what endian; 114 // we always return the int32 value in host endian. 115 } 116 117 118 static inline rgb_color 119 get_rgb_color(uint32 value) 120 { 121 value = B_HOST_TO_BENDIAN_INT32(value); 122 return *(rgb_color*)&value; 123 } 124 125 126 // #pragma mark - 127 128 129 namespace BPrivate { 130 131 ViewState::ViewState() 132 { 133 pen_location.Set(0, 0); 134 pen_size = 1.0; 135 136 // NOTE: the clipping_region is empty 137 // on construction but it is not used yet, 138 // we avoid having to keep track of it via 139 // this flag 140 clipping_region_used = false; 141 142 high_color = (rgb_color){ 0, 0, 0, 255 }; 143 low_color = (rgb_color){ 255, 255, 255, 255 }; 144 view_color = low_color; 145 which_view_color = B_NO_COLOR; 146 which_view_color_tint = B_NO_TINT; 147 148 which_high_color = B_NO_COLOR; 149 which_high_color_tint = B_NO_TINT; 150 151 which_low_color = B_NO_COLOR; 152 which_low_color_tint = B_NO_TINT; 153 154 pattern = B_SOLID_HIGH; 155 drawing_mode = B_OP_COPY; 156 157 origin.Set(0, 0); 158 159 line_join = B_MITER_JOIN; 160 line_cap = B_BUTT_CAP; 161 miter_limit = B_DEFAULT_MITER_LIMIT; 162 fill_rule = B_NONZERO; 163 164 alpha_source_mode = B_PIXEL_ALPHA; 165 alpha_function_mode = B_ALPHA_OVERLAY; 166 167 scale = 1.0; 168 169 font = *be_plain_font; 170 font_flags = font.Flags(); 171 font_aliasing = false; 172 173 // We only keep the B_VIEW_CLIP_REGION_BIT flag invalidated, 174 // because we should get the clipping region from app_server. 175 // The other flags do not need to be included because the data they 176 // represent is already in sync with app_server - app_server uses the 177 // same init (default) values. 178 valid_flags = ~B_VIEW_CLIP_REGION_BIT; 179 180 archiving_flags = B_VIEW_FRAME_BIT | B_VIEW_RESIZE_BIT; 181 } 182 183 184 void 185 ViewState::UpdateServerFontState(BPrivate::PortLink &link) 186 { 187 link.StartMessage(AS_VIEW_SET_FONT_STATE); 188 link.Attach<uint16>(font_flags); 189 // always present 190 191 if (font_flags & B_FONT_FAMILY_AND_STYLE) 192 link.Attach<uint32>(font.FamilyAndStyle()); 193 194 if (font_flags & B_FONT_SIZE) 195 link.Attach<float>(font.Size()); 196 197 if (font_flags & B_FONT_SHEAR) 198 link.Attach<float>(font.Shear()); 199 200 if (font_flags & B_FONT_ROTATION) 201 link.Attach<float>(font.Rotation()); 202 203 if (font_flags & B_FONT_FALSE_BOLD_WIDTH) 204 link.Attach<float>(font.FalseBoldWidth()); 205 206 if (font_flags & B_FONT_SPACING) 207 link.Attach<uint8>(font.Spacing()); 208 209 if (font_flags & B_FONT_ENCODING) 210 link.Attach<uint8>(font.Encoding()); 211 212 if (font_flags & B_FONT_FACE) 213 link.Attach<uint16>(font.Face()); 214 215 if (font_flags & B_FONT_FLAGS) 216 link.Attach<uint32>(font.Flags()); 217 } 218 219 220 void 221 ViewState::UpdateServerState(BPrivate::PortLink &link) 222 { 223 UpdateServerFontState(link); 224 225 link.StartMessage(AS_VIEW_SET_STATE); 226 227 ViewSetStateInfo info; 228 info.penLocation = pen_location; 229 info.penSize = pen_size; 230 info.highColor = high_color; 231 info.lowColor = low_color; 232 info.whichHighColor = which_high_color; 233 info.whichLowColor = which_low_color; 234 info.whichHighColorTint = which_high_color_tint; 235 info.whichLowColorTint = which_low_color_tint; 236 info.pattern = pattern; 237 info.drawingMode = drawing_mode; 238 info.origin = origin; 239 info.scale = scale; 240 info.lineJoin = line_join; 241 info.lineCap = line_cap; 242 info.miterLimit = miter_limit; 243 info.fillRule = fill_rule; 244 info.alphaSourceMode = alpha_source_mode; 245 info.alphaFunctionMode = alpha_function_mode; 246 info.fontAntialiasing = font_aliasing; 247 link.Attach<ViewSetStateInfo>(info); 248 249 // BAffineTransform is transmitted as a double array 250 double _transform[6]; 251 if (transform.Flatten(_transform, sizeof(_transform)) != B_OK) 252 return; 253 link.Attach<double[6]>(_transform); 254 255 // we send the 'local' clipping region... if we have one... 256 // TODO: Could be optimized, but is low prio, since most views won't 257 // have a custom clipping region. 258 if (clipping_region_used) { 259 int32 count = clipping_region.CountRects(); 260 link.Attach<int32>(count); 261 for (int32 i = 0; i < count; i++) 262 link.Attach<BRect>(clipping_region.RectAt(i)); 263 } else { 264 // no clipping region 265 link.Attach<int32>(-1); 266 } 267 268 // Although we might have a 'local' clipping region, when we call 269 // BView::GetClippingRegion() we ask for the 'global' one and it 270 // is kept on server, so we must invalidate B_VIEW_CLIP_REGION_BIT flag 271 272 valid_flags = ~B_VIEW_CLIP_REGION_BIT; 273 } 274 275 276 void 277 ViewState::UpdateFrom(BPrivate::PortLink &link) 278 { 279 link.StartMessage(AS_VIEW_GET_STATE); 280 281 int32 code; 282 if (link.FlushWithReply(code) != B_OK 283 || code != B_OK) 284 return; 285 286 ViewGetStateInfo info; 287 link.Read<ViewGetStateInfo>(&info); 288 289 // set view's font state 290 font_flags = B_FONT_ALL; 291 font.SetFamilyAndStyle(info.fontID); 292 font.SetSize(info.fontSize); 293 font.SetShear(info.fontShear); 294 font.SetRotation(info.fontRotation); 295 font.SetFalseBoldWidth(info.fontFalseBoldWidth); 296 font.SetSpacing(info.fontSpacing); 297 font.SetEncoding(info.fontEncoding); 298 font.SetFace(info.fontFace); 299 font.SetFlags(info.fontFlags); 300 301 // set view's state 302 pen_location = info.viewStateInfo.penLocation; 303 pen_size = info.viewStateInfo.penSize; 304 high_color = info.viewStateInfo.highColor; 305 low_color = info.viewStateInfo.lowColor; 306 pattern = info.viewStateInfo.pattern; 307 drawing_mode = info.viewStateInfo.drawingMode; 308 origin = info.viewStateInfo.origin; 309 scale = info.viewStateInfo.scale; 310 line_join = info.viewStateInfo.lineJoin; 311 line_cap = info.viewStateInfo.lineCap; 312 miter_limit = info.viewStateInfo.miterLimit; 313 fill_rule = info.viewStateInfo.fillRule; 314 alpha_source_mode = info.viewStateInfo.alphaSourceMode; 315 alpha_function_mode = info.viewStateInfo.alphaFunctionMode; 316 font_aliasing = info.viewStateInfo.fontAntialiasing; 317 318 // BAffineTransform is transmitted as a double array 319 double _transform[6]; 320 link.Read<double[6]>(&_transform); 321 if (transform.Unflatten(B_AFFINE_TRANSFORM_TYPE, _transform, 322 sizeof(_transform)) != B_OK) { 323 return; 324 } 325 326 // read the user clipping 327 // (that's NOT the current View visible clipping but the additional 328 // user specified clipping!) 329 int32 clippingRectCount; 330 link.Read<int32>(&clippingRectCount); 331 if (clippingRectCount >= 0) { 332 clipping_region.MakeEmpty(); 333 for (int32 i = 0; i < clippingRectCount; i++) { 334 BRect rect; 335 link.Read<BRect>(&rect); 336 clipping_region.Include(rect); 337 } 338 } else { 339 // no user clipping used 340 clipping_region_used = false; 341 } 342 343 valid_flags = ~B_VIEW_CLIP_REGION_BIT; 344 } 345 346 } // namespace BPrivate 347 348 349 // #pragma mark - 350 351 352 // archiving constants 353 namespace { 354 const char* const kSizesField = "BView:sizes"; 355 // kSizesField = {min, max, pref} 356 const char* const kAlignmentField = "BView:alignment"; 357 const char* const kLayoutField = "BView:layout"; 358 } 359 360 361 struct BView::LayoutData { 362 LayoutData() 363 : 364 fMinSize(), 365 fMaxSize(), 366 fPreferredSize(), 367 fAlignment(), 368 fLayoutInvalidationDisabled(0), 369 fLayout(NULL), 370 fLayoutContext(NULL), 371 fLayoutItems(5, false), 372 fLayoutValid(true), // TODO: Rethink these initial values! 373 fMinMaxValid(true), // 374 fLayoutInProgress(false), 375 fNeedsRelayout(true) 376 { 377 } 378 379 status_t 380 AddDataToArchive(BMessage* archive) 381 { 382 status_t err = archive->AddSize(kSizesField, fMinSize); 383 384 if (err == B_OK) 385 err = archive->AddSize(kSizesField, fMaxSize); 386 387 if (err == B_OK) 388 err = archive->AddSize(kSizesField, fPreferredSize); 389 390 if (err == B_OK) 391 err = archive->AddAlignment(kAlignmentField, fAlignment); 392 393 return err; 394 } 395 396 void 397 PopulateFromArchive(BMessage* archive) 398 { 399 archive->FindSize(kSizesField, 0, &fMinSize); 400 archive->FindSize(kSizesField, 1, &fMaxSize); 401 archive->FindSize(kSizesField, 2, &fPreferredSize); 402 archive->FindAlignment(kAlignmentField, &fAlignment); 403 } 404 405 BSize fMinSize; 406 BSize fMaxSize; 407 BSize fPreferredSize; 408 BAlignment fAlignment; 409 int fLayoutInvalidationDisabled; 410 BLayout* fLayout; 411 BLayoutContext* fLayoutContext; 412 BObjectList<BLayoutItem> fLayoutItems; 413 bool fLayoutValid; 414 bool fMinMaxValid; 415 bool fLayoutInProgress; 416 bool fNeedsRelayout; 417 }; 418 419 420 BView::BView(const char* name, uint32 flags, BLayout* layout) 421 : 422 BHandler(name) 423 { 424 _InitData(BRect(0, 0, -1, -1), name, B_FOLLOW_NONE, 425 flags | B_SUPPORTS_LAYOUT); 426 SetLayout(layout); 427 } 428 429 430 BView::BView(BRect frame, const char* name, uint32 resizingMode, uint32 flags) 431 : 432 BHandler(name) 433 { 434 _InitData(frame, name, resizingMode, flags); 435 } 436 437 438 BView::BView(BMessage* archive) 439 : 440 BHandler(BUnarchiver::PrepareArchive(archive)) 441 { 442 BUnarchiver unarchiver(archive); 443 if (!archive) 444 debugger("BView cannot be constructed from a NULL archive."); 445 446 BRect frame; 447 archive->FindRect("_frame", &frame); 448 449 uint32 resizingMode; 450 if (archive->FindInt32("_resize_mode", (int32*)&resizingMode) != B_OK) 451 resizingMode = 0; 452 453 uint32 flags; 454 if (archive->FindInt32("_flags", (int32*)&flags) != B_OK) 455 flags = 0; 456 457 _InitData(frame, Name(), resizingMode, flags); 458 459 font_family family; 460 font_style style; 461 if (archive->FindString("_fname", 0, (const char**)&family) == B_OK 462 && archive->FindString("_fname", 1, (const char**)&style) == B_OK) { 463 BFont font; 464 font.SetFamilyAndStyle(family, style); 465 466 float size; 467 if (archive->FindFloat("_fflt", 0, &size) == B_OK) 468 font.SetSize(size); 469 470 float shear; 471 if (archive->FindFloat("_fflt", 1, &shear) == B_OK 472 && shear >= 45.0 && shear <= 135.0) 473 font.SetShear(shear); 474 475 float rotation; 476 if (archive->FindFloat("_fflt", 2, &rotation) == B_OK 477 && rotation >=0 && rotation <= 360) 478 font.SetRotation(rotation); 479 480 SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE 481 | B_FONT_SHEAR | B_FONT_ROTATION); 482 } 483 484 int32 color = 0; 485 if (archive->FindInt32("_color", 0, &color) == B_OK) 486 SetHighColor(get_rgb_color(color)); 487 if (archive->FindInt32("_color", 1, &color) == B_OK) 488 SetLowColor(get_rgb_color(color)); 489 if (archive->FindInt32("_color", 2, &color) == B_OK) 490 SetViewColor(get_rgb_color(color)); 491 492 float tint = B_NO_TINT; 493 if (archive->FindInt32("_uicolor", 0, &color) == B_OK 494 && color != B_NO_COLOR) { 495 if (archive->FindFloat("_uitint", 0, &tint) != B_OK) 496 tint = B_NO_TINT; 497 498 SetHighUIColor((color_which)color, tint); 499 } 500 if (archive->FindInt32("_uicolor", 1, &color) == B_OK 501 && color != B_NO_COLOR) { 502 if (archive->FindFloat("_uitint", 1, &tint) != B_OK) 503 tint = B_NO_TINT; 504 505 SetLowUIColor((color_which)color, tint); 506 } 507 if (archive->FindInt32("_uicolor", 2, &color) == B_OK 508 && color != B_NO_COLOR) { 509 if (archive->FindFloat("_uitint", 2, &tint) != B_OK) 510 tint = B_NO_TINT; 511 512 SetViewUIColor((color_which)color, tint); 513 } 514 515 uint32 evMask; 516 uint32 options; 517 if (archive->FindInt32("_evmask", 0, (int32*)&evMask) == B_OK 518 && archive->FindInt32("_evmask", 1, (int32*)&options) == B_OK) 519 SetEventMask(evMask, options); 520 521 BPoint origin; 522 if (archive->FindPoint("_origin", &origin) == B_OK) 523 SetOrigin(origin); 524 525 float scale; 526 if (archive->FindFloat("_scale", &scale) == B_OK) 527 SetScale(scale); 528 529 BAffineTransform transform; 530 if (archive->FindFlat("_transform", &transform) == B_OK) 531 SetTransform(transform); 532 533 float penSize; 534 if (archive->FindFloat("_psize", &penSize) == B_OK) 535 SetPenSize(penSize); 536 537 BPoint penLocation; 538 if (archive->FindPoint("_ploc", &penLocation) == B_OK) 539 MovePenTo(penLocation); 540 541 int16 lineCap; 542 int16 lineJoin; 543 float lineMiter; 544 if (archive->FindInt16("_lmcapjoin", 0, &lineCap) == B_OK 545 && archive->FindInt16("_lmcapjoin", 1, &lineJoin) == B_OK 546 && archive->FindFloat("_lmmiter", &lineMiter) == B_OK) 547 SetLineMode((cap_mode)lineCap, (join_mode)lineJoin, lineMiter); 548 549 int16 fillRule; 550 if (archive->FindInt16("_fillrule", &fillRule) == B_OK) 551 SetFillRule(fillRule); 552 553 int16 alphaBlend; 554 int16 modeBlend; 555 if (archive->FindInt16("_blend", 0, &alphaBlend) == B_OK 556 && archive->FindInt16("_blend", 1, &modeBlend) == B_OK) 557 SetBlendingMode( (source_alpha)alphaBlend, (alpha_function)modeBlend); 558 559 uint32 drawingMode; 560 if (archive->FindInt32("_dmod", (int32*)&drawingMode) == B_OK) 561 SetDrawingMode((drawing_mode)drawingMode); 562 563 fLayoutData->PopulateFromArchive(archive); 564 565 if (archive->FindInt16("_show", &fShowLevel) != B_OK) 566 fShowLevel = 0; 567 568 if (BUnarchiver::IsArchiveManaged(archive)) { 569 int32 i = 0; 570 while (unarchiver.EnsureUnarchived("_views", i++) == B_OK) 571 ; 572 unarchiver.EnsureUnarchived(kLayoutField); 573 574 } else { 575 BMessage msg; 576 for (int32 i = 0; archive->FindMessage("_views", i, &msg) == B_OK; 577 i++) { 578 BArchivable* object = instantiate_object(&msg); 579 if (BView* child = dynamic_cast<BView*>(object)) 580 AddChild(child); 581 } 582 } 583 } 584 585 586 BArchivable* 587 BView::Instantiate(BMessage* data) 588 { 589 if (!validate_instantiation(data , "BView")) 590 return NULL; 591 592 return new(std::nothrow) BView(data); 593 } 594 595 596 status_t 597 BView::Archive(BMessage* data, bool deep) const 598 { 599 BArchiver archiver(data); 600 status_t ret = BHandler::Archive(data, deep); 601 602 if (ret != B_OK) 603 return ret; 604 605 if ((fState->archiving_flags & B_VIEW_FRAME_BIT) != 0) 606 ret = data->AddRect("_frame", Bounds().OffsetToCopy(fParentOffset)); 607 608 if (ret == B_OK) 609 ret = data->AddInt32("_resize_mode", ResizingMode()); 610 611 if (ret == B_OK) 612 ret = data->AddInt32("_flags", Flags()); 613 614 if (ret == B_OK && (fState->archiving_flags & B_VIEW_EVENT_MASK_BIT) != 0) { 615 ret = data->AddInt32("_evmask", fEventMask); 616 if (ret == B_OK) 617 ret = data->AddInt32("_evmask", fEventOptions); 618 } 619 620 if (ret == B_OK && (fState->archiving_flags & B_VIEW_FONT_BIT) != 0) { 621 BFont font; 622 GetFont(&font); 623 624 font_family family; 625 font_style style; 626 font.GetFamilyAndStyle(&family, &style); 627 ret = data->AddString("_fname", family); 628 if (ret == B_OK) 629 ret = data->AddString("_fname", style); 630 if (ret == B_OK) 631 ret = data->AddFloat("_fflt", font.Size()); 632 if (ret == B_OK) 633 ret = data->AddFloat("_fflt", font.Shear()); 634 if (ret == B_OK) 635 ret = data->AddFloat("_fflt", font.Rotation()); 636 } 637 638 // colors 639 if (ret == B_OK) 640 ret = data->AddInt32("_color", get_uint32_color(HighColor())); 641 if (ret == B_OK) 642 ret = data->AddInt32("_color", get_uint32_color(LowColor())); 643 if (ret == B_OK) 644 ret = data->AddInt32("_color", get_uint32_color(ViewColor())); 645 646 if (ret == B_OK) 647 ret = data->AddInt32("_uicolor", (int32)HighUIColor()); 648 if (ret == B_OK) 649 ret = data->AddInt32("_uicolor", (int32)LowUIColor()); 650 if (ret == B_OK) 651 ret = data->AddInt32("_uicolor", (int32)ViewUIColor()); 652 653 if (ret == B_OK) 654 ret = data->AddFloat("_uitint", fState->which_high_color_tint); 655 if (ret == B_OK) 656 ret = data->AddFloat("_uitint", fState->which_low_color_tint); 657 if (ret == B_OK) 658 ret = data->AddFloat("_uitint", fState->which_view_color_tint); 659 660 // NOTE: we do not use this flag any more 661 // if ( 1 ){ 662 // ret = data->AddInt32("_dbuf", 1); 663 // } 664 665 if (ret == B_OK && (fState->archiving_flags & B_VIEW_ORIGIN_BIT) != 0) 666 ret = data->AddPoint("_origin", Origin()); 667 668 if (ret == B_OK && (fState->archiving_flags & B_VIEW_SCALE_BIT) != 0) 669 ret = data->AddFloat("_scale", Scale()); 670 671 if (ret == B_OK && (fState->archiving_flags & B_VIEW_TRANSFORM_BIT) != 0) { 672 BAffineTransform transform = Transform(); 673 ret = data->AddFlat("_transform", &transform); 674 } 675 676 if (ret == B_OK && (fState->archiving_flags & B_VIEW_PEN_SIZE_BIT) != 0) 677 ret = data->AddFloat("_psize", PenSize()); 678 679 if (ret == B_OK && (fState->archiving_flags & B_VIEW_PEN_LOCATION_BIT) != 0) 680 ret = data->AddPoint("_ploc", PenLocation()); 681 682 if (ret == B_OK && (fState->archiving_flags & B_VIEW_LINE_MODES_BIT) != 0) { 683 ret = data->AddInt16("_lmcapjoin", (int16)LineCapMode()); 684 if (ret == B_OK) 685 ret = data->AddInt16("_lmcapjoin", (int16)LineJoinMode()); 686 if (ret == B_OK) 687 ret = data->AddFloat("_lmmiter", LineMiterLimit()); 688 } 689 690 if (ret == B_OK && (fState->archiving_flags & B_VIEW_FILL_RULE_BIT) != 0) 691 ret = data->AddInt16("_fillrule", (int16)FillRule()); 692 693 if (ret == B_OK && (fState->archiving_flags & B_VIEW_BLENDING_BIT) != 0) { 694 source_alpha alphaSourceMode; 695 alpha_function alphaFunctionMode; 696 GetBlendingMode(&alphaSourceMode, &alphaFunctionMode); 697 698 ret = data->AddInt16("_blend", (int16)alphaSourceMode); 699 if (ret == B_OK) 700 ret = data->AddInt16("_blend", (int16)alphaFunctionMode); 701 } 702 703 if (ret == B_OK && (fState->archiving_flags & B_VIEW_DRAWING_MODE_BIT) != 0) 704 ret = data->AddInt32("_dmod", DrawingMode()); 705 706 if (ret == B_OK) 707 ret = fLayoutData->AddDataToArchive(data); 708 709 if (ret == B_OK) 710 ret = data->AddInt16("_show", fShowLevel); 711 712 if (deep && ret == B_OK) { 713 for (BView* child = fFirstChild; child != NULL && ret == B_OK; 714 child = child->fNextSibling) 715 ret = archiver.AddArchivable("_views", child, deep); 716 717 if (ret == B_OK) 718 ret = archiver.AddArchivable(kLayoutField, GetLayout(), deep); 719 } 720 721 return archiver.Finish(ret); 722 } 723 724 725 status_t 726 BView::AllUnarchived(const BMessage* from) 727 { 728 BUnarchiver unarchiver(from); 729 status_t err = B_OK; 730 731 int32 count; 732 from->GetInfo("_views", NULL, &count); 733 734 for (int32 i = 0; err == B_OK && i < count; i++) { 735 BView* child; 736 err = unarchiver.FindObject<BView>("_views", i, child); 737 if (err == B_OK) 738 err = _AddChild(child, NULL) ? B_OK : B_ERROR; 739 } 740 741 if (err == B_OK) { 742 BLayout*& layout = fLayoutData->fLayout; 743 err = unarchiver.FindObject(kLayoutField, layout); 744 if (err == B_OK && layout) { 745 fFlags |= B_SUPPORTS_LAYOUT; 746 fLayoutData->fLayout->SetOwner(this); 747 } 748 } 749 750 return err; 751 } 752 753 754 status_t 755 BView::AllArchived(BMessage* into) const 756 { 757 return BHandler::AllArchived(into); 758 } 759 760 761 BView::~BView() 762 { 763 STRACE(("BView(%s)::~BView()\n", this->Name())); 764 765 if (fOwner != NULL) { 766 debugger("Trying to delete a view that belongs to a window. " 767 "Call RemoveSelf first."); 768 } 769 770 // we also delete all our children 771 772 BView* child = fFirstChild; 773 while (child) { 774 BView* nextChild = child->fNextSibling; 775 776 delete child; 777 child = nextChild; 778 } 779 780 SetLayout(NULL); 781 _RemoveLayoutItemsFromLayout(true); 782 783 delete fLayoutData; 784 785 _RemoveSelf(); 786 787 if (fToolTip != NULL) 788 fToolTip->ReleaseReference(); 789 790 if (fVerScroller != NULL) 791 fVerScroller->SetTarget((BView*)NULL); 792 if (fHorScroller != NULL) 793 fHorScroller->SetTarget((BView*)NULL); 794 795 SetName(NULL); 796 797 _RemoveCommArray(); 798 delete fState; 799 } 800 801 802 BRect 803 BView::Bounds() const 804 { 805 _CheckLock(); 806 807 if (fIsPrinting) 808 return fState->print_rect; 809 810 return fBounds; 811 } 812 813 814 void 815 BView::_ConvertToParent(BPoint* point, bool checkLock) const 816 { 817 if (!fParent) 818 return; 819 820 if (checkLock) 821 _CheckLock(); 822 823 // - our scrolling offset 824 // + our bounds location within the parent 825 point->x += -fBounds.left + fParentOffset.x; 826 point->y += -fBounds.top + fParentOffset.y; 827 } 828 829 830 void 831 BView::ConvertToParent(BPoint* point) const 832 { 833 _ConvertToParent(point, true); 834 } 835 836 837 BPoint 838 BView::ConvertToParent(BPoint point) const 839 { 840 ConvertToParent(&point); 841 842 return point; 843 } 844 845 846 void 847 BView::_ConvertFromParent(BPoint* point, bool checkLock) const 848 { 849 if (!fParent) 850 return; 851 852 if (checkLock) 853 _CheckLock(); 854 855 // - our bounds location within the parent 856 // + our scrolling offset 857 point->x += -fParentOffset.x + fBounds.left; 858 point->y += -fParentOffset.y + fBounds.top; 859 } 860 861 862 void 863 BView::ConvertFromParent(BPoint* point) const 864 { 865 _ConvertFromParent(point, true); 866 } 867 868 869 BPoint 870 BView::ConvertFromParent(BPoint point) const 871 { 872 ConvertFromParent(&point); 873 874 return point; 875 } 876 877 878 void 879 BView::ConvertToParent(BRect* rect) const 880 { 881 if (!fParent) 882 return; 883 884 _CheckLock(); 885 886 // - our scrolling offset 887 // + our bounds location within the parent 888 rect->OffsetBy(-fBounds.left + fParentOffset.x, 889 -fBounds.top + fParentOffset.y); 890 } 891 892 893 BRect 894 BView::ConvertToParent(BRect rect) const 895 { 896 ConvertToParent(&rect); 897 898 return rect; 899 } 900 901 902 void 903 BView::ConvertFromParent(BRect* rect) const 904 { 905 if (!fParent) 906 return; 907 908 _CheckLock(); 909 910 // - our bounds location within the parent 911 // + our scrolling offset 912 rect->OffsetBy(-fParentOffset.x + fBounds.left, 913 -fParentOffset.y + fBounds.top); 914 } 915 916 917 BRect 918 BView::ConvertFromParent(BRect rect) const 919 { 920 ConvertFromParent(&rect); 921 922 return rect; 923 } 924 925 926 void 927 BView::_ConvertToScreen(BPoint* point, bool checkLock) const 928 { 929 if (!fParent) { 930 if (fOwner) 931 fOwner->ConvertToScreen(point); 932 933 return; 934 } 935 936 if (checkLock) 937 _CheckOwnerLock(); 938 939 _ConvertToParent(point, false); 940 fParent->_ConvertToScreen(point, false); 941 } 942 943 944 void 945 BView::ConvertToScreen(BPoint* point) const 946 { 947 _ConvertToScreen(point, true); 948 } 949 950 951 BPoint 952 BView::ConvertToScreen(BPoint point) const 953 { 954 ConvertToScreen(&point); 955 956 return point; 957 } 958 959 960 void 961 BView::_ConvertFromScreen(BPoint* point, bool checkLock) const 962 { 963 if (!fParent) { 964 if (fOwner) 965 fOwner->ConvertFromScreen(point); 966 967 return; 968 } 969 970 if (checkLock) 971 _CheckOwnerLock(); 972 973 _ConvertFromParent(point, false); 974 fParent->_ConvertFromScreen(point, false); 975 } 976 977 978 void 979 BView::ConvertFromScreen(BPoint* point) const 980 { 981 _ConvertFromScreen(point, true); 982 } 983 984 985 BPoint 986 BView::ConvertFromScreen(BPoint point) const 987 { 988 ConvertFromScreen(&point); 989 990 return point; 991 } 992 993 994 void 995 BView::ConvertToScreen(BRect* rect) const 996 { 997 BPoint offset(0.0, 0.0); 998 ConvertToScreen(&offset); 999 rect->OffsetBy(offset); 1000 } 1001 1002 1003 BRect 1004 BView::ConvertToScreen(BRect rect) const 1005 { 1006 ConvertToScreen(&rect); 1007 1008 return rect; 1009 } 1010 1011 1012 void 1013 BView::ConvertFromScreen(BRect* rect) const 1014 { 1015 BPoint offset(0.0, 0.0); 1016 ConvertFromScreen(&offset); 1017 rect->OffsetBy(offset); 1018 } 1019 1020 1021 BRect 1022 BView::ConvertFromScreen(BRect rect) const 1023 { 1024 ConvertFromScreen(&rect); 1025 1026 return rect; 1027 } 1028 1029 1030 uint32 1031 BView::Flags() const 1032 { 1033 _CheckLock(); 1034 return fFlags & ~_RESIZE_MASK_; 1035 } 1036 1037 1038 void 1039 BView::SetFlags(uint32 flags) 1040 { 1041 if (Flags() == flags) 1042 return; 1043 1044 if (fOwner) { 1045 if (flags & B_PULSE_NEEDED) { 1046 _CheckLock(); 1047 if (fOwner->fPulseRunner == NULL) 1048 fOwner->SetPulseRate(fOwner->PulseRate()); 1049 } 1050 1051 uint32 changesFlags = flags ^ fFlags; 1052 if (changesFlags & (B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE 1053 | B_FRAME_EVENTS | B_SUBPIXEL_PRECISE 1054 | B_TRANSPARENT_BACKGROUND)) { 1055 _CheckLockAndSwitchCurrent(); 1056 1057 fOwner->fLink->StartMessage(AS_VIEW_SET_FLAGS); 1058 fOwner->fLink->Attach<uint32>(flags); 1059 fOwner->fLink->Flush(); 1060 } 1061 } 1062 1063 /* Some useful info: 1064 fFlags is a unsigned long (32 bits) 1065 * bits 1-16 are used for BView's flags 1066 * bits 17-32 are used for BView' resize mask 1067 * _RESIZE_MASK_ is used for that. Look into View.h to see how 1068 it's defined 1069 */ 1070 fFlags = (flags & ~_RESIZE_MASK_) | (fFlags & _RESIZE_MASK_); 1071 1072 fState->archiving_flags |= B_VIEW_FLAGS_BIT; 1073 } 1074 1075 1076 BRect 1077 BView::Frame() const 1078 { 1079 return Bounds().OffsetToCopy(fParentOffset.x, fParentOffset.y); 1080 } 1081 1082 1083 void 1084 BView::Hide() 1085 { 1086 if (fOwner && fShowLevel == 0) { 1087 _CheckLockAndSwitchCurrent(); 1088 fOwner->fLink->StartMessage(AS_VIEW_HIDE); 1089 fOwner->fLink->Flush(); 1090 } 1091 fShowLevel++; 1092 1093 if (fShowLevel == 1) 1094 _InvalidateParentLayout(); 1095 } 1096 1097 1098 void 1099 BView::Show() 1100 { 1101 fShowLevel--; 1102 if (fOwner && fShowLevel == 0) { 1103 _CheckLockAndSwitchCurrent(); 1104 fOwner->fLink->StartMessage(AS_VIEW_SHOW); 1105 fOwner->fLink->Flush(); 1106 } 1107 1108 if (fShowLevel == 0) 1109 _InvalidateParentLayout(); 1110 } 1111 1112 1113 bool 1114 BView::IsFocus() const 1115 { 1116 if (fOwner) { 1117 _CheckLock(); 1118 return fOwner->CurrentFocus() == this; 1119 } else 1120 return false; 1121 } 1122 1123 1124 bool 1125 BView::IsHidden(const BView* lookingFrom) const 1126 { 1127 if (fShowLevel > 0) 1128 return true; 1129 1130 // may we be egocentric? 1131 if (lookingFrom == this) 1132 return false; 1133 1134 // we have the same visibility state as our 1135 // parent, if there is one 1136 if (fParent) 1137 return fParent->IsHidden(lookingFrom); 1138 1139 // if we're the top view, and we're interested 1140 // in the "global" view, we're inheriting the 1141 // state of the window's visibility 1142 if (fOwner && lookingFrom == NULL) 1143 return fOwner->IsHidden(); 1144 1145 return false; 1146 } 1147 1148 1149 bool 1150 BView::IsHidden() const 1151 { 1152 return IsHidden(NULL); 1153 } 1154 1155 1156 bool 1157 BView::IsPrinting() const 1158 { 1159 return fIsPrinting; 1160 } 1161 1162 1163 BPoint 1164 BView::LeftTop() const 1165 { 1166 return Bounds().LeftTop(); 1167 } 1168 1169 1170 void 1171 BView::SetResizingMode(uint32 mode) 1172 { 1173 if (fOwner) { 1174 _CheckLockAndSwitchCurrent(); 1175 1176 fOwner->fLink->StartMessage(AS_VIEW_RESIZE_MODE); 1177 fOwner->fLink->Attach<uint32>(mode); 1178 } 1179 1180 // look at SetFlags() for more info on the below line 1181 fFlags = (fFlags & ~_RESIZE_MASK_) | (mode & _RESIZE_MASK_); 1182 } 1183 1184 1185 uint32 1186 BView::ResizingMode() const 1187 { 1188 return fFlags & _RESIZE_MASK_; 1189 } 1190 1191 1192 void 1193 BView::SetViewCursor(const BCursor* cursor, bool sync) 1194 { 1195 if (cursor == NULL || fOwner == NULL) 1196 return; 1197 1198 _CheckLock(); 1199 1200 ViewSetViewCursorInfo info; 1201 info.cursorToken = cursor->fServerToken; 1202 info.viewToken = _get_object_token_(this); 1203 info.sync = sync; 1204 1205 BPrivate::AppServerLink link; 1206 link.StartMessage(AS_SET_VIEW_CURSOR); 1207 link.Attach<ViewSetViewCursorInfo>(info); 1208 1209 if (sync) { 1210 // Make sure the server has processed the message. 1211 int32 code; 1212 link.FlushWithReply(code); 1213 } 1214 } 1215 1216 1217 void 1218 BView::Flush() const 1219 { 1220 if (fOwner) 1221 fOwner->Flush(); 1222 } 1223 1224 1225 void 1226 BView::Sync() const 1227 { 1228 _CheckOwnerLock(); 1229 if (fOwner) 1230 fOwner->Sync(); 1231 } 1232 1233 1234 BWindow* 1235 BView::Window() const 1236 { 1237 return fOwner; 1238 } 1239 1240 1241 // #pragma mark - Hook Functions 1242 1243 1244 void 1245 BView::AttachedToWindow() 1246 { 1247 // Hook function 1248 STRACE(("\tHOOK: BView(%s)::AttachedToWindow()\n", Name())); 1249 } 1250 1251 1252 void 1253 BView::AllAttached() 1254 { 1255 // Hook function 1256 STRACE(("\tHOOK: BView(%s)::AllAttached()\n", Name())); 1257 } 1258 1259 1260 void 1261 BView::DetachedFromWindow() 1262 { 1263 // Hook function 1264 STRACE(("\tHOOK: BView(%s)::DetachedFromWindow()\n", Name())); 1265 } 1266 1267 1268 void 1269 BView::AllDetached() 1270 { 1271 // Hook function 1272 STRACE(("\tHOOK: BView(%s)::AllDetached()\n", Name())); 1273 } 1274 1275 1276 void 1277 BView::Draw(BRect updateRect) 1278 { 1279 // Hook function 1280 STRACE(("\tHOOK: BView(%s)::Draw()\n", Name())); 1281 } 1282 1283 1284 void 1285 BView::DrawAfterChildren(BRect updateRect) 1286 { 1287 // Hook function 1288 STRACE(("\tHOOK: BView(%s)::DrawAfterChildren()\n", Name())); 1289 } 1290 1291 1292 void 1293 BView::FrameMoved(BPoint newPosition) 1294 { 1295 // Hook function 1296 STRACE(("\tHOOK: BView(%s)::FrameMoved()\n", Name())); 1297 } 1298 1299 1300 void 1301 BView::FrameResized(float newWidth, float newHeight) 1302 { 1303 // Hook function 1304 STRACE(("\tHOOK: BView(%s)::FrameResized()\n", Name())); 1305 } 1306 1307 1308 void 1309 BView::GetPreferredSize(float* _width, float* _height) 1310 { 1311 STRACE(("\tHOOK: BView(%s)::GetPreferredSize()\n", Name())); 1312 1313 if (_width != NULL) 1314 *_width = fBounds.Width(); 1315 if (_height != NULL) 1316 *_height = fBounds.Height(); 1317 } 1318 1319 1320 void 1321 BView::ResizeToPreferred() 1322 { 1323 STRACE(("\tHOOK: BView(%s)::ResizeToPreferred()\n", Name())); 1324 1325 float width; 1326 float height; 1327 GetPreferredSize(&width, &height); 1328 1329 ResizeTo(width, height); 1330 } 1331 1332 1333 void 1334 BView::KeyDown(const char* bytes, int32 numBytes) 1335 { 1336 // Hook function 1337 STRACE(("\tHOOK: BView(%s)::KeyDown()\n", Name())); 1338 1339 if (Window()) 1340 Window()->_KeyboardNavigation(); 1341 } 1342 1343 1344 void 1345 BView::KeyUp(const char* bytes, int32 numBytes) 1346 { 1347 // Hook function 1348 STRACE(("\tHOOK: BView(%s)::KeyUp()\n", Name())); 1349 } 1350 1351 1352 void 1353 BView::MouseDown(BPoint where) 1354 { 1355 // Hook function 1356 STRACE(("\tHOOK: BView(%s)::MouseDown()\n", Name())); 1357 } 1358 1359 1360 void 1361 BView::MouseUp(BPoint where) 1362 { 1363 // Hook function 1364 STRACE(("\tHOOK: BView(%s)::MouseUp()\n", Name())); 1365 } 1366 1367 1368 void 1369 BView::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage) 1370 { 1371 // Hook function 1372 STRACE(("\tHOOK: BView(%s)::MouseMoved()\n", Name())); 1373 } 1374 1375 1376 void 1377 BView::Pulse() 1378 { 1379 // Hook function 1380 STRACE(("\tHOOK: BView(%s)::Pulse()\n", Name())); 1381 } 1382 1383 1384 void 1385 BView::TargetedByScrollView(BScrollView* scroll_view) 1386 { 1387 // Hook function 1388 STRACE(("\tHOOK: BView(%s)::TargetedByScrollView()\n", Name())); 1389 } 1390 1391 1392 void 1393 BView::WindowActivated(bool active) 1394 { 1395 // Hook function 1396 STRACE(("\tHOOK: BView(%s)::WindowActivated()\n", Name())); 1397 } 1398 1399 1400 // #pragma mark - Input Functions 1401 1402 1403 void 1404 BView::BeginRectTracking(BRect startRect, uint32 style) 1405 { 1406 if (_CheckOwnerLockAndSwitchCurrent()) { 1407 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_RECT_TRACK); 1408 fOwner->fLink->Attach<BRect>(startRect); 1409 fOwner->fLink->Attach<uint32>(style); 1410 fOwner->fLink->Flush(); 1411 } 1412 } 1413 1414 1415 void 1416 BView::EndRectTracking() 1417 { 1418 if (_CheckOwnerLockAndSwitchCurrent()) { 1419 fOwner->fLink->StartMessage(AS_VIEW_END_RECT_TRACK); 1420 fOwner->fLink->Flush(); 1421 } 1422 } 1423 1424 1425 void 1426 BView::DragMessage(BMessage* message, BRect dragRect, BHandler* replyTo) 1427 { 1428 if (!message) 1429 return; 1430 1431 _CheckOwnerLock(); 1432 1433 // calculate the offset 1434 BPoint offset; 1435 uint32 buttons; 1436 BMessage* current = fOwner->CurrentMessage(); 1437 if (!current || current->FindPoint("be:view_where", &offset) != B_OK) 1438 GetMouse(&offset, &buttons, false); 1439 offset -= dragRect.LeftTop(); 1440 1441 if (!dragRect.IsValid()) { 1442 DragMessage(message, NULL, B_OP_BLEND, offset, replyTo); 1443 return; 1444 } 1445 1446 // TODO: that's not really what should happen - the app_server should take 1447 // the chance *NOT* to need to drag a whole bitmap around but just a frame. 1448 1449 // create a drag bitmap for the rect 1450 BBitmap* bitmap = new(std::nothrow) BBitmap(dragRect, B_RGBA32); 1451 if (bitmap == NULL) 1452 return; 1453 1454 uint32* bits = (uint32*)bitmap->Bits(); 1455 uint32 bytesPerRow = bitmap->BytesPerRow(); 1456 uint32 width = dragRect.IntegerWidth() + 1; 1457 uint32 height = dragRect.IntegerHeight() + 1; 1458 uint32 lastRow = (height - 1) * width; 1459 1460 memset(bits, 0x00, height * bytesPerRow); 1461 1462 // top 1463 for (uint32 i = 0; i < width; i += 2) 1464 bits[i] = 0xff000000; 1465 1466 // bottom 1467 for (uint32 i = (height % 2 == 0 ? 1 : 0); i < width; i += 2) 1468 bits[lastRow + i] = 0xff000000; 1469 1470 // left 1471 for (uint32 i = 0; i < lastRow; i += width * 2) 1472 bits[i] = 0xff000000; 1473 1474 // right 1475 for (uint32 i = (width % 2 == 0 ? width : 0); i < lastRow; i += width * 2) 1476 bits[width - 1 + i] = 0xff000000; 1477 1478 DragMessage(message, bitmap, B_OP_BLEND, offset, replyTo); 1479 } 1480 1481 1482 void 1483 BView::DragMessage(BMessage* message, BBitmap* image, BPoint offset, 1484 BHandler* replyTo) 1485 { 1486 DragMessage(message, image, B_OP_COPY, offset, replyTo); 1487 } 1488 1489 1490 void 1491 BView::DragMessage(BMessage* message, BBitmap* image, 1492 drawing_mode dragMode, BPoint offset, BHandler* replyTo) 1493 { 1494 if (message == NULL) 1495 return; 1496 1497 if (image == NULL) { 1498 // TODO: workaround for drags without a bitmap - should not be necessary if 1499 // we move the rectangle dragging into the app_server 1500 image = new(std::nothrow) BBitmap(BRect(0, 0, 0, 0), B_RGBA32); 1501 if (image == NULL) 1502 return; 1503 } 1504 1505 if (replyTo == NULL) 1506 replyTo = this; 1507 1508 if (replyTo->Looper() == NULL) 1509 debugger("DragMessage: warning - the Handler needs a looper"); 1510 1511 _CheckOwnerLock(); 1512 1513 if (!message->HasInt32("buttons")) { 1514 BMessage* msg = fOwner->CurrentMessage(); 1515 uint32 buttons; 1516 1517 if (msg == NULL 1518 || msg->FindInt32("buttons", (int32*)&buttons) != B_OK) { 1519 BPoint point; 1520 GetMouse(&point, &buttons, false); 1521 } 1522 1523 message->AddInt32("buttons", buttons); 1524 } 1525 1526 BMessage::Private privateMessage(message); 1527 privateMessage.SetReply(BMessenger(replyTo, replyTo->Looper())); 1528 1529 int32 bufferSize = message->FlattenedSize(); 1530 char* buffer = new(std::nothrow) char[bufferSize]; 1531 if (buffer != NULL) { 1532 message->Flatten(buffer, bufferSize); 1533 1534 fOwner->fLink->StartMessage(AS_VIEW_DRAG_IMAGE); 1535 fOwner->fLink->Attach<int32>(image->_ServerToken()); 1536 fOwner->fLink->Attach<int32>((int32)dragMode); 1537 fOwner->fLink->Attach<BPoint>(offset); 1538 fOwner->fLink->Attach<int32>(bufferSize); 1539 fOwner->fLink->Attach(buffer, bufferSize); 1540 1541 // we need to wait for the server 1542 // to actually process this message 1543 // before we can delete the bitmap 1544 int32 code; 1545 fOwner->fLink->FlushWithReply(code); 1546 1547 delete [] buffer; 1548 } else { 1549 fprintf(stderr, "BView::DragMessage() - no memory to flatten drag " 1550 "message\n"); 1551 } 1552 1553 delete image; 1554 } 1555 1556 1557 void 1558 BView::GetMouse(BPoint* _location, uint32* _buttons, bool checkMessageQueue) 1559 { 1560 if (_location == NULL && _buttons == NULL) 1561 return; 1562 1563 _CheckOwnerLockAndSwitchCurrent(); 1564 1565 uint32 eventOptions = fEventOptions | fMouseEventOptions; 1566 bool noHistory = eventOptions & B_NO_POINTER_HISTORY; 1567 bool fullHistory = eventOptions & B_FULL_POINTER_HISTORY; 1568 1569 if (checkMessageQueue && !noHistory) { 1570 Window()->UpdateIfNeeded(); 1571 BMessageQueue* queue = Window()->MessageQueue(); 1572 queue->Lock(); 1573 1574 // Look out for mouse update messages 1575 1576 BMessage* message; 1577 for (int32 i = 0; (message = queue->FindMessage(i)) != NULL; i++) { 1578 switch (message->what) { 1579 case B_MOUSE_MOVED: 1580 case B_MOUSE_UP: 1581 case B_MOUSE_DOWN: 1582 bool deleteMessage; 1583 if (!Window()->_StealMouseMessage(message, deleteMessage)) 1584 continue; 1585 1586 if (!fullHistory && message->what == B_MOUSE_MOVED) { 1587 // Check if the message is too old. Some applications 1588 // check the message queue in such a way that mouse 1589 // messages *must* pile up. This check makes them work 1590 // as intended, although these applications could simply 1591 // use the version of BView::GetMouse() that does not 1592 // check the history. Also note that it isn't a problem 1593 // to delete the message in case there is not a newer 1594 // one. If we don't find a message in the queue, we will 1595 // just fall back to asking the app_sever directly. So 1596 // the imposed delay will not be a problem on slower 1597 // computers. This check also prevents another problem, 1598 // when the message that we use is *not* removed from 1599 // the queue. Subsequent calls to GetMouse() would find 1600 // this message over and over! 1601 bigtime_t eventTime; 1602 if (message->FindInt64("when", &eventTime) == B_OK 1603 && system_time() - eventTime > 10000) { 1604 // just discard the message 1605 if (deleteMessage) 1606 delete message; 1607 continue; 1608 } 1609 } 1610 if (_location != NULL) 1611 message->FindPoint("screen_where", _location); 1612 if (_buttons != NULL) 1613 message->FindInt32("buttons", (int32*)_buttons); 1614 queue->Unlock(); 1615 // we need to hold the queue lock until here, because 1616 // the message might still be used for something else 1617 1618 if (_location != NULL) 1619 ConvertFromScreen(_location); 1620 1621 if (deleteMessage) 1622 delete message; 1623 1624 return; 1625 } 1626 } 1627 queue->Unlock(); 1628 } 1629 1630 // If no mouse update message has been found in the message queue, 1631 // we get the current mouse location and buttons from the app_server 1632 1633 fOwner->fLink->StartMessage(AS_GET_MOUSE); 1634 1635 int32 code; 1636 if (fOwner->fLink->FlushWithReply(code) == B_OK 1637 && code == B_OK) { 1638 BPoint location; 1639 uint32 buttons; 1640 fOwner->fLink->Read<BPoint>(&location); 1641 fOwner->fLink->Read<uint32>(&buttons); 1642 // TODO: ServerWindow replies with an int32 here 1643 1644 ConvertFromScreen(&location); 1645 // TODO: in beos R5, location is already converted to the view 1646 // local coordinate system, so if an app checks the window message 1647 // queue by itself, it might not find what it expects. 1648 // NOTE: the fact that we have mouse coords in screen space in our 1649 // queue avoids the problem that messages already in the queue will 1650 // be outdated as soon as a window or even the view moves. The 1651 // second situation being quite common actually, also with regards 1652 // to scrolling. An app reading these messages would have to know 1653 // the locations of the window and view for each message... 1654 // otherwise it is potentially broken anyways. 1655 if (_location != NULL) 1656 *_location = location; 1657 if (_buttons != NULL) 1658 *_buttons = buttons; 1659 } else { 1660 if (_location != NULL) 1661 _location->Set(0, 0); 1662 if (_buttons != NULL) 1663 *_buttons = 0; 1664 } 1665 } 1666 1667 1668 void 1669 BView::MakeFocus(bool focus) 1670 { 1671 if (fOwner == NULL) 1672 return; 1673 1674 // TODO: If this view has focus and focus == false, 1675 // will there really be no other view with focus? No 1676 // cycling to the next one? 1677 BView* focusView = fOwner->CurrentFocus(); 1678 if (focus) { 1679 // Unfocus a previous focus view 1680 if (focusView != NULL && focusView != this) 1681 focusView->MakeFocus(false); 1682 1683 // if we want to make this view the current focus view 1684 fOwner->_SetFocus(this, true); 1685 } else { 1686 // we want to unfocus this view, but only if it actually has focus 1687 if (focusView == this) 1688 fOwner->_SetFocus(NULL, true); 1689 } 1690 } 1691 1692 1693 BScrollBar* 1694 BView::ScrollBar(orientation direction) const 1695 { 1696 switch (direction) { 1697 case B_VERTICAL: 1698 return fVerScroller; 1699 1700 case B_HORIZONTAL: 1701 return fHorScroller; 1702 1703 default: 1704 return NULL; 1705 } 1706 } 1707 1708 1709 void 1710 BView::ScrollBy(float deltaX, float deltaY) 1711 { 1712 ScrollTo(BPoint(fBounds.left + deltaX, fBounds.top + deltaY)); 1713 } 1714 1715 1716 void 1717 BView::ScrollTo(BPoint where) 1718 { 1719 // scrolling by fractional values is not supported 1720 where.x = roundf(where.x); 1721 where.y = roundf(where.y); 1722 1723 // no reason to process this further if no scroll is intended. 1724 if (where.x == fBounds.left && where.y == fBounds.top) 1725 return; 1726 1727 // make sure scrolling is within valid bounds 1728 if (fHorScroller) { 1729 float min, max; 1730 fHorScroller->GetRange(&min, &max); 1731 1732 if (where.x < min) 1733 where.x = min; 1734 else if (where.x > max) 1735 where.x = max; 1736 } 1737 if (fVerScroller) { 1738 float min, max; 1739 fVerScroller->GetRange(&min, &max); 1740 1741 if (where.y < min) 1742 where.y = min; 1743 else if (where.y > max) 1744 where.y = max; 1745 } 1746 1747 _CheckLockAndSwitchCurrent(); 1748 1749 float xDiff = where.x - fBounds.left; 1750 float yDiff = where.y - fBounds.top; 1751 1752 // if we're attached to a window tell app_server about this change 1753 if (fOwner) { 1754 fOwner->fLink->StartMessage(AS_VIEW_SCROLL); 1755 fOwner->fLink->Attach<float>(xDiff); 1756 fOwner->fLink->Attach<float>(yDiff); 1757 1758 fOwner->fLink->Flush(); 1759 1760 // fState->valid_flags &= ~B_VIEW_FRAME_BIT; 1761 } 1762 1763 // we modify our bounds rectangle by deltaX/deltaY coord units hor/ver. 1764 fBounds.OffsetTo(where.x, where.y); 1765 1766 // then set the new values of the scrollbars 1767 if (fHorScroller && xDiff != 0.0) 1768 fHorScroller->SetValue(fBounds.left); 1769 if (fVerScroller && yDiff != 0.0) 1770 fVerScroller->SetValue(fBounds.top); 1771 1772 } 1773 1774 1775 status_t 1776 BView::SetEventMask(uint32 mask, uint32 options) 1777 { 1778 if (fEventMask == mask && fEventOptions == options) 1779 return B_OK; 1780 1781 // don't change the mask if it's zero and we've got options 1782 if (mask != 0 || options == 0) 1783 fEventMask = mask | (fEventMask & 0xffff0000); 1784 fEventOptions = options; 1785 1786 fState->archiving_flags |= B_VIEW_EVENT_MASK_BIT; 1787 1788 if (fOwner) { 1789 _CheckLockAndSwitchCurrent(); 1790 1791 fOwner->fLink->StartMessage(AS_VIEW_SET_EVENT_MASK); 1792 fOwner->fLink->Attach<uint32>(mask); 1793 fOwner->fLink->Attach<uint32>(options); 1794 fOwner->fLink->Flush(); 1795 } 1796 1797 return B_OK; 1798 } 1799 1800 1801 uint32 1802 BView::EventMask() 1803 { 1804 return fEventMask; 1805 } 1806 1807 1808 status_t 1809 BView::SetMouseEventMask(uint32 mask, uint32 options) 1810 { 1811 // Just don't do anything if the view is not yet attached 1812 // or we were called outside of BView::MouseDown() 1813 if (fOwner != NULL 1814 && fOwner->CurrentMessage() != NULL 1815 && fOwner->CurrentMessage()->what == B_MOUSE_DOWN) { 1816 _CheckLockAndSwitchCurrent(); 1817 fMouseEventOptions = options; 1818 1819 fOwner->fLink->StartMessage(AS_VIEW_SET_MOUSE_EVENT_MASK); 1820 fOwner->fLink->Attach<uint32>(mask); 1821 fOwner->fLink->Attach<uint32>(options); 1822 fOwner->fLink->Flush(); 1823 return B_OK; 1824 } 1825 1826 return B_ERROR; 1827 } 1828 1829 1830 // #pragma mark - Graphic State Functions 1831 1832 1833 void 1834 BView::PushState() 1835 { 1836 _CheckOwnerLockAndSwitchCurrent(); 1837 1838 fOwner->fLink->StartMessage(AS_VIEW_PUSH_STATE); 1839 1840 // initialize origin, scale and transform, new states start "clean". 1841 fState->valid_flags |= B_VIEW_SCALE_BIT | B_VIEW_ORIGIN_BIT 1842 | B_VIEW_TRANSFORM_BIT; 1843 fState->scale = 1.0f; 1844 fState->origin.Set(0, 0); 1845 fState->transform.Reset(); 1846 } 1847 1848 1849 void 1850 BView::PopState() 1851 { 1852 _CheckOwnerLockAndSwitchCurrent(); 1853 1854 fOwner->fLink->StartMessage(AS_VIEW_POP_STATE); 1855 _FlushIfNotInTransaction(); 1856 1857 // invalidate all flags (except those that are not part of pop/push) 1858 fState->valid_flags = B_VIEW_VIEW_COLOR_BIT; 1859 } 1860 1861 1862 void 1863 BView::SetOrigin(BPoint where) 1864 { 1865 SetOrigin(where.x, where.y); 1866 } 1867 1868 1869 void 1870 BView::SetOrigin(float x, float y) 1871 { 1872 if (fState->IsValid(B_VIEW_ORIGIN_BIT) 1873 && x == fState->origin.x && y == fState->origin.y) 1874 return; 1875 1876 fState->origin.x = x; 1877 fState->origin.y = y; 1878 1879 if (_CheckOwnerLockAndSwitchCurrent()) { 1880 fOwner->fLink->StartMessage(AS_VIEW_SET_ORIGIN); 1881 fOwner->fLink->Attach<float>(x); 1882 fOwner->fLink->Attach<float>(y); 1883 1884 fState->valid_flags |= B_VIEW_ORIGIN_BIT; 1885 } 1886 1887 // our local coord system origin has changed, so when archiving we'll add 1888 // this too 1889 fState->archiving_flags |= B_VIEW_ORIGIN_BIT; 1890 } 1891 1892 1893 BPoint 1894 BView::Origin() const 1895 { 1896 if (!fState->IsValid(B_VIEW_ORIGIN_BIT)) { 1897 // we don't keep graphics state information, therefor 1898 // we need to ask the server for the origin after PopState() 1899 _CheckOwnerLockAndSwitchCurrent(); 1900 1901 fOwner->fLink->StartMessage(AS_VIEW_GET_ORIGIN); 1902 1903 int32 code; 1904 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) 1905 fOwner->fLink->Read<BPoint>(&fState->origin); 1906 1907 fState->valid_flags |= B_VIEW_ORIGIN_BIT; 1908 } 1909 1910 return fState->origin; 1911 } 1912 1913 1914 void 1915 BView::SetScale(float scale) const 1916 { 1917 if (fState->IsValid(B_VIEW_SCALE_BIT) && scale == fState->scale) 1918 return; 1919 1920 if (fOwner) { 1921 _CheckLockAndSwitchCurrent(); 1922 1923 fOwner->fLink->StartMessage(AS_VIEW_SET_SCALE); 1924 fOwner->fLink->Attach<float>(scale); 1925 1926 fState->valid_flags |= B_VIEW_SCALE_BIT; 1927 } 1928 1929 fState->scale = scale; 1930 fState->archiving_flags |= B_VIEW_SCALE_BIT; 1931 } 1932 1933 1934 float 1935 BView::Scale() const 1936 { 1937 if (!fState->IsValid(B_VIEW_SCALE_BIT) && fOwner) { 1938 _CheckLockAndSwitchCurrent(); 1939 1940 fOwner->fLink->StartMessage(AS_VIEW_GET_SCALE); 1941 1942 int32 code; 1943 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) 1944 fOwner->fLink->Read<float>(&fState->scale); 1945 1946 fState->valid_flags |= B_VIEW_SCALE_BIT; 1947 } 1948 1949 return fState->scale; 1950 } 1951 1952 1953 void 1954 BView::SetTransform(BAffineTransform transform) 1955 { 1956 if (fState->IsValid(B_VIEW_TRANSFORM_BIT) && transform == fState->transform) 1957 return; 1958 1959 if (fOwner != NULL) { 1960 _CheckLockAndSwitchCurrent(); 1961 1962 fOwner->fLink->StartMessage(AS_VIEW_SET_TRANSFORM); 1963 fOwner->fLink->Attach<BAffineTransform>(transform); 1964 1965 fState->valid_flags |= B_VIEW_TRANSFORM_BIT; 1966 } 1967 1968 fState->transform = transform; 1969 fState->archiving_flags |= B_VIEW_TRANSFORM_BIT; 1970 } 1971 1972 1973 BAffineTransform 1974 BView::Transform() const 1975 { 1976 if (!fState->IsValid(B_VIEW_TRANSFORM_BIT) && fOwner != NULL) { 1977 _CheckLockAndSwitchCurrent(); 1978 1979 fOwner->fLink->StartMessage(AS_VIEW_GET_TRANSFORM); 1980 1981 int32 code; 1982 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) 1983 fOwner->fLink->Read<BAffineTransform>(&fState->transform); 1984 1985 fState->valid_flags |= B_VIEW_TRANSFORM_BIT; 1986 } 1987 1988 return fState->transform; 1989 } 1990 1991 1992 void 1993 BView::TranslateBy(double x, double y) 1994 { 1995 if (fOwner != NULL) { 1996 _CheckLockAndSwitchCurrent(); 1997 1998 fOwner->fLink->StartMessage(AS_VIEW_AFFINE_TRANSLATE); 1999 fOwner->fLink->Attach<double>(x); 2000 fOwner->fLink->Attach<double>(y); 2001 2002 fState->valid_flags &= ~B_VIEW_TRANSFORM_BIT; 2003 } 2004 2005 fState->archiving_flags |= B_VIEW_TRANSFORM_BIT; 2006 } 2007 2008 2009 void 2010 BView::ScaleBy(double x, double y) 2011 { 2012 if (fOwner != NULL) { 2013 _CheckLockAndSwitchCurrent(); 2014 2015 fOwner->fLink->StartMessage(AS_VIEW_AFFINE_SCALE); 2016 fOwner->fLink->Attach<double>(x); 2017 fOwner->fLink->Attach<double>(y); 2018 2019 fState->valid_flags &= ~B_VIEW_TRANSFORM_BIT; 2020 } 2021 2022 fState->archiving_flags |= B_VIEW_TRANSFORM_BIT; 2023 } 2024 2025 2026 void 2027 BView::RotateBy(double angleRadians) 2028 { 2029 if (fOwner != NULL) { 2030 _CheckLockAndSwitchCurrent(); 2031 2032 fOwner->fLink->StartMessage(AS_VIEW_AFFINE_ROTATE); 2033 fOwner->fLink->Attach<double>(angleRadians); 2034 2035 fState->valid_flags &= ~B_VIEW_TRANSFORM_BIT; 2036 } 2037 2038 fState->archiving_flags |= B_VIEW_TRANSFORM_BIT; 2039 } 2040 2041 2042 void 2043 BView::SetLineMode(cap_mode lineCap, join_mode lineJoin, float miterLimit) 2044 { 2045 if (fState->IsValid(B_VIEW_LINE_MODES_BIT) 2046 && lineCap == fState->line_cap && lineJoin == fState->line_join 2047 && miterLimit == fState->miter_limit) 2048 return; 2049 2050 if (fOwner) { 2051 _CheckLockAndSwitchCurrent(); 2052 2053 ViewSetLineModeInfo info; 2054 info.lineJoin = lineJoin; 2055 info.lineCap = lineCap; 2056 info.miterLimit = miterLimit; 2057 2058 fOwner->fLink->StartMessage(AS_VIEW_SET_LINE_MODE); 2059 fOwner->fLink->Attach<ViewSetLineModeInfo>(info); 2060 2061 fState->valid_flags |= B_VIEW_LINE_MODES_BIT; 2062 } 2063 2064 fState->line_cap = lineCap; 2065 fState->line_join = lineJoin; 2066 fState->miter_limit = miterLimit; 2067 2068 fState->archiving_flags |= B_VIEW_LINE_MODES_BIT; 2069 } 2070 2071 2072 join_mode 2073 BView::LineJoinMode() const 2074 { 2075 // This will update the current state, if necessary 2076 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT)) 2077 LineMiterLimit(); 2078 2079 return fState->line_join; 2080 } 2081 2082 2083 cap_mode 2084 BView::LineCapMode() const 2085 { 2086 // This will update the current state, if necessary 2087 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT)) 2088 LineMiterLimit(); 2089 2090 return fState->line_cap; 2091 } 2092 2093 2094 float 2095 BView::LineMiterLimit() const 2096 { 2097 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT) && fOwner) { 2098 _CheckLockAndSwitchCurrent(); 2099 2100 fOwner->fLink->StartMessage(AS_VIEW_GET_LINE_MODE); 2101 2102 int32 code; 2103 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) { 2104 2105 ViewSetLineModeInfo info; 2106 fOwner->fLink->Read<ViewSetLineModeInfo>(&info); 2107 2108 fState->line_cap = info.lineCap; 2109 fState->line_join = info.lineJoin; 2110 fState->miter_limit = info.miterLimit; 2111 } 2112 2113 fState->valid_flags |= B_VIEW_LINE_MODES_BIT; 2114 } 2115 2116 return fState->miter_limit; 2117 } 2118 2119 2120 void 2121 BView::SetFillRule(int32 fillRule) 2122 { 2123 if (fState->IsValid(B_VIEW_FILL_RULE_BIT) && fillRule == fState->fill_rule) 2124 return; 2125 2126 if (fOwner) { 2127 _CheckLockAndSwitchCurrent(); 2128 2129 fOwner->fLink->StartMessage(AS_VIEW_SET_FILL_RULE); 2130 fOwner->fLink->Attach<int32>(fillRule); 2131 2132 fState->valid_flags |= B_VIEW_FILL_RULE_BIT; 2133 } 2134 2135 fState->fill_rule = fillRule; 2136 2137 fState->archiving_flags |= B_VIEW_FILL_RULE_BIT; 2138 } 2139 2140 2141 int32 2142 BView::FillRule() const 2143 { 2144 if (!fState->IsValid(B_VIEW_FILL_RULE_BIT) && fOwner) { 2145 _CheckLockAndSwitchCurrent(); 2146 2147 fOwner->fLink->StartMessage(AS_VIEW_GET_FILL_RULE); 2148 2149 int32 code; 2150 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) { 2151 2152 int32 fillRule; 2153 fOwner->fLink->Read<int32>(&fillRule); 2154 2155 fState->fill_rule = fillRule; 2156 } 2157 2158 fState->valid_flags |= B_VIEW_FILL_RULE_BIT; 2159 } 2160 2161 return fState->fill_rule; 2162 } 2163 2164 2165 void 2166 BView::SetDrawingMode(drawing_mode mode) 2167 { 2168 if (fState->IsValid(B_VIEW_DRAWING_MODE_BIT) 2169 && mode == fState->drawing_mode) 2170 return; 2171 2172 if (fOwner) { 2173 _CheckLockAndSwitchCurrent(); 2174 2175 fOwner->fLink->StartMessage(AS_VIEW_SET_DRAWING_MODE); 2176 fOwner->fLink->Attach<int8>((int8)mode); 2177 2178 fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT; 2179 } 2180 2181 fState->drawing_mode = mode; 2182 fState->archiving_flags |= B_VIEW_DRAWING_MODE_BIT; 2183 } 2184 2185 2186 drawing_mode 2187 BView::DrawingMode() const 2188 { 2189 if (!fState->IsValid(B_VIEW_DRAWING_MODE_BIT) && fOwner) { 2190 _CheckLockAndSwitchCurrent(); 2191 2192 fOwner->fLink->StartMessage(AS_VIEW_GET_DRAWING_MODE); 2193 2194 int32 code; 2195 if (fOwner->fLink->FlushWithReply(code) == B_OK 2196 && code == B_OK) { 2197 int8 drawingMode; 2198 fOwner->fLink->Read<int8>(&drawingMode); 2199 2200 fState->drawing_mode = (drawing_mode)drawingMode; 2201 fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT; 2202 } 2203 } 2204 2205 return fState->drawing_mode; 2206 } 2207 2208 2209 void 2210 BView::SetBlendingMode(source_alpha sourceAlpha, alpha_function alphaFunction) 2211 { 2212 if (fState->IsValid(B_VIEW_BLENDING_BIT) 2213 && sourceAlpha == fState->alpha_source_mode 2214 && alphaFunction == fState->alpha_function_mode) 2215 return; 2216 2217 if (fOwner) { 2218 _CheckLockAndSwitchCurrent(); 2219 2220 ViewBlendingModeInfo info; 2221 info.sourceAlpha = sourceAlpha; 2222 info.alphaFunction = alphaFunction; 2223 2224 fOwner->fLink->StartMessage(AS_VIEW_SET_BLENDING_MODE); 2225 fOwner->fLink->Attach<ViewBlendingModeInfo>(info); 2226 2227 fState->valid_flags |= B_VIEW_BLENDING_BIT; 2228 } 2229 2230 fState->alpha_source_mode = sourceAlpha; 2231 fState->alpha_function_mode = alphaFunction; 2232 2233 fState->archiving_flags |= B_VIEW_BLENDING_BIT; 2234 } 2235 2236 2237 void 2238 BView::GetBlendingMode(source_alpha* _sourceAlpha, 2239 alpha_function* _alphaFunction) const 2240 { 2241 if (!fState->IsValid(B_VIEW_BLENDING_BIT) && fOwner) { 2242 _CheckLockAndSwitchCurrent(); 2243 2244 fOwner->fLink->StartMessage(AS_VIEW_GET_BLENDING_MODE); 2245 2246 int32 code; 2247 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) { 2248 ViewBlendingModeInfo info; 2249 fOwner->fLink->Read<ViewBlendingModeInfo>(&info); 2250 2251 fState->alpha_source_mode = info.sourceAlpha; 2252 fState->alpha_function_mode = info.alphaFunction; 2253 2254 fState->valid_flags |= B_VIEW_BLENDING_BIT; 2255 } 2256 } 2257 2258 if (_sourceAlpha) 2259 *_sourceAlpha = fState->alpha_source_mode; 2260 2261 if (_alphaFunction) 2262 *_alphaFunction = fState->alpha_function_mode; 2263 } 2264 2265 2266 void 2267 BView::MovePenTo(BPoint point) 2268 { 2269 MovePenTo(point.x, point.y); 2270 } 2271 2272 2273 void 2274 BView::MovePenTo(float x, float y) 2275 { 2276 if (fState->IsValid(B_VIEW_PEN_LOCATION_BIT) 2277 && x == fState->pen_location.x && y == fState->pen_location.y) 2278 return; 2279 2280 if (fOwner) { 2281 _CheckLockAndSwitchCurrent(); 2282 2283 fOwner->fLink->StartMessage(AS_VIEW_SET_PEN_LOC); 2284 fOwner->fLink->Attach<BPoint>(BPoint(x, y)); 2285 2286 fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT; 2287 } 2288 2289 fState->pen_location.x = x; 2290 fState->pen_location.y = y; 2291 2292 fState->archiving_flags |= B_VIEW_PEN_LOCATION_BIT; 2293 } 2294 2295 2296 void 2297 BView::MovePenBy(float x, float y) 2298 { 2299 // this will update the pen location if necessary 2300 if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT)) 2301 PenLocation(); 2302 2303 MovePenTo(fState->pen_location.x + x, fState->pen_location.y + y); 2304 } 2305 2306 2307 BPoint 2308 BView::PenLocation() const 2309 { 2310 if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT) && fOwner) { 2311 _CheckLockAndSwitchCurrent(); 2312 2313 fOwner->fLink->StartMessage(AS_VIEW_GET_PEN_LOC); 2314 2315 int32 code; 2316 if (fOwner->fLink->FlushWithReply(code) == B_OK 2317 && code == B_OK) { 2318 fOwner->fLink->Read<BPoint>(&fState->pen_location); 2319 2320 fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT; 2321 } 2322 } 2323 2324 return fState->pen_location; 2325 } 2326 2327 2328 void 2329 BView::SetPenSize(float size) 2330 { 2331 if (fState->IsValid(B_VIEW_PEN_SIZE_BIT) && size == fState->pen_size) 2332 return; 2333 2334 if (fOwner) { 2335 _CheckLockAndSwitchCurrent(); 2336 2337 fOwner->fLink->StartMessage(AS_VIEW_SET_PEN_SIZE); 2338 fOwner->fLink->Attach<float>(size); 2339 2340 fState->valid_flags |= B_VIEW_PEN_SIZE_BIT; 2341 } 2342 2343 fState->pen_size = size; 2344 fState->archiving_flags |= B_VIEW_PEN_SIZE_BIT; 2345 } 2346 2347 2348 float 2349 BView::PenSize() const 2350 { 2351 if (!fState->IsValid(B_VIEW_PEN_SIZE_BIT) && fOwner) { 2352 _CheckLockAndSwitchCurrent(); 2353 2354 fOwner->fLink->StartMessage(AS_VIEW_GET_PEN_SIZE); 2355 2356 int32 code; 2357 if (fOwner->fLink->FlushWithReply(code) == B_OK 2358 && code == B_OK) { 2359 fOwner->fLink->Read<float>(&fState->pen_size); 2360 2361 fState->valid_flags |= B_VIEW_PEN_SIZE_BIT; 2362 } 2363 } 2364 2365 return fState->pen_size; 2366 } 2367 2368 2369 void 2370 BView::SetHighColor(rgb_color color) 2371 { 2372 SetHighUIColor(B_NO_COLOR); 2373 2374 // are we up-to-date already? 2375 if (fState->IsValid(B_VIEW_HIGH_COLOR_BIT) 2376 && fState->high_color == color) 2377 return; 2378 2379 if (fOwner) { 2380 _CheckLockAndSwitchCurrent(); 2381 2382 fOwner->fLink->StartMessage(AS_VIEW_SET_HIGH_COLOR); 2383 fOwner->fLink->Attach<rgb_color>(color); 2384 2385 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT; 2386 } 2387 2388 fState->high_color = color; 2389 2390 fState->archiving_flags |= B_VIEW_HIGH_COLOR_BIT; 2391 } 2392 2393 2394 rgb_color 2395 BView::HighColor() const 2396 { 2397 if (!fState->IsValid(B_VIEW_HIGH_COLOR_BIT) && fOwner) { 2398 _CheckLockAndSwitchCurrent(); 2399 2400 fOwner->fLink->StartMessage(AS_VIEW_GET_HIGH_COLOR); 2401 2402 int32 code; 2403 if (fOwner->fLink->FlushWithReply(code) == B_OK 2404 && code == B_OK) { 2405 fOwner->fLink->Read<rgb_color>(&fState->high_color); 2406 2407 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT; 2408 } 2409 } 2410 2411 return fState->high_color; 2412 } 2413 2414 2415 void 2416 BView::SetHighUIColor(color_which which, float tint) 2417 { 2418 if (fState->IsValid(B_VIEW_WHICH_HIGH_COLOR_BIT) 2419 && fState->which_high_color == which 2420 && fState->which_high_color_tint == tint) 2421 return; 2422 2423 if (fOwner != NULL) { 2424 _CheckLockAndSwitchCurrent(); 2425 2426 fOwner->fLink->StartMessage(AS_VIEW_SET_HIGH_UI_COLOR); 2427 fOwner->fLink->Attach<color_which>(which); 2428 fOwner->fLink->Attach<float>(tint); 2429 2430 fState->valid_flags |= B_VIEW_WHICH_HIGH_COLOR_BIT; 2431 } 2432 2433 fState->which_high_color = which; 2434 fState->which_high_color_tint = tint; 2435 2436 if (which != B_NO_COLOR) { 2437 fState->archiving_flags |= B_VIEW_WHICH_HIGH_COLOR_BIT; 2438 fState->archiving_flags &= ~B_VIEW_HIGH_COLOR_BIT; 2439 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT; 2440 2441 fState->high_color = tint_color(ui_color(which), tint); 2442 } else { 2443 fState->valid_flags &= ~B_VIEW_HIGH_COLOR_BIT; 2444 fState->archiving_flags &= ~B_VIEW_WHICH_HIGH_COLOR_BIT; 2445 } 2446 } 2447 2448 2449 color_which 2450 BView::HighUIColor(float* tint) const 2451 { 2452 if (!fState->IsValid(B_VIEW_WHICH_HIGH_COLOR_BIT) 2453 && fOwner != NULL) { 2454 _CheckLockAndSwitchCurrent(); 2455 2456 fOwner->fLink->StartMessage(AS_VIEW_GET_HIGH_UI_COLOR); 2457 2458 int32 code; 2459 if (fOwner->fLink->FlushWithReply(code) == B_OK 2460 && code == B_OK) { 2461 fOwner->fLink->Read<color_which>(&fState->which_high_color); 2462 fOwner->fLink->Read<float>(&fState->which_high_color_tint); 2463 fOwner->fLink->Read<rgb_color>(&fState->high_color); 2464 2465 fState->valid_flags |= B_VIEW_WHICH_HIGH_COLOR_BIT; 2466 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT; 2467 } 2468 } 2469 2470 if (tint != NULL) 2471 *tint = fState->which_high_color_tint; 2472 2473 return fState->which_high_color; 2474 } 2475 2476 2477 void 2478 BView::SetLowColor(rgb_color color) 2479 { 2480 SetLowUIColor(B_NO_COLOR); 2481 2482 if (fState->IsValid(B_VIEW_LOW_COLOR_BIT) 2483 && fState->low_color == color) 2484 return; 2485 2486 if (fOwner) { 2487 _CheckLockAndSwitchCurrent(); 2488 2489 fOwner->fLink->StartMessage(AS_VIEW_SET_LOW_COLOR); 2490 fOwner->fLink->Attach<rgb_color>(color); 2491 2492 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT; 2493 } 2494 2495 fState->low_color = color; 2496 2497 fState->archiving_flags |= B_VIEW_LOW_COLOR_BIT; 2498 } 2499 2500 2501 rgb_color 2502 BView::LowColor() const 2503 { 2504 if (!fState->IsValid(B_VIEW_LOW_COLOR_BIT) && fOwner) { 2505 _CheckLockAndSwitchCurrent(); 2506 2507 fOwner->fLink->StartMessage(AS_VIEW_GET_LOW_COLOR); 2508 2509 int32 code; 2510 if (fOwner->fLink->FlushWithReply(code) == B_OK 2511 && code == B_OK) { 2512 fOwner->fLink->Read<rgb_color>(&fState->low_color); 2513 2514 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT; 2515 } 2516 } 2517 2518 return fState->low_color; 2519 } 2520 2521 2522 void 2523 BView::SetLowUIColor(color_which which, float tint) 2524 { 2525 if (fState->IsValid(B_VIEW_WHICH_LOW_COLOR_BIT) 2526 && fState->which_low_color == which 2527 && fState->which_low_color_tint == tint) 2528 return; 2529 2530 if (fOwner != NULL) { 2531 _CheckLockAndSwitchCurrent(); 2532 2533 fOwner->fLink->StartMessage(AS_VIEW_SET_LOW_UI_COLOR); 2534 fOwner->fLink->Attach<color_which>(which); 2535 fOwner->fLink->Attach<float>(tint); 2536 2537 fState->valid_flags |= B_VIEW_WHICH_LOW_COLOR_BIT; 2538 } 2539 2540 fState->which_low_color = which; 2541 fState->which_low_color_tint = tint; 2542 2543 if (which != B_NO_COLOR) { 2544 fState->archiving_flags |= B_VIEW_WHICH_LOW_COLOR_BIT; 2545 fState->archiving_flags &= ~B_VIEW_LOW_COLOR_BIT; 2546 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT; 2547 2548 fState->low_color = tint_color(ui_color(which), tint); 2549 } else { 2550 fState->valid_flags &= ~B_VIEW_LOW_COLOR_BIT; 2551 fState->archiving_flags &= ~B_VIEW_WHICH_LOW_COLOR_BIT; 2552 } 2553 } 2554 2555 2556 color_which 2557 BView::LowUIColor(float* tint) const 2558 { 2559 if (!fState->IsValid(B_VIEW_WHICH_LOW_COLOR_BIT) 2560 && fOwner != NULL) { 2561 _CheckLockAndSwitchCurrent(); 2562 2563 fOwner->fLink->StartMessage(AS_VIEW_GET_LOW_UI_COLOR); 2564 2565 int32 code; 2566 if (fOwner->fLink->FlushWithReply(code) == B_OK 2567 && code == B_OK) { 2568 fOwner->fLink->Read<color_which>(&fState->which_low_color); 2569 fOwner->fLink->Read<float>(&fState->which_low_color_tint); 2570 fOwner->fLink->Read<rgb_color>(&fState->low_color); 2571 2572 fState->valid_flags |= B_VIEW_WHICH_LOW_COLOR_BIT; 2573 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT; 2574 } 2575 } 2576 2577 if (tint != NULL) 2578 *tint = fState->which_low_color_tint; 2579 2580 return fState->which_low_color; 2581 } 2582 2583 2584 bool 2585 BView::HasDefaultColors() const 2586 { 2587 // If we don't have any of these flags, then we have default colors 2588 uint32 testMask = B_VIEW_VIEW_COLOR_BIT | B_VIEW_HIGH_COLOR_BIT 2589 | B_VIEW_LOW_COLOR_BIT | B_VIEW_WHICH_VIEW_COLOR_BIT 2590 | B_VIEW_WHICH_HIGH_COLOR_BIT | B_VIEW_WHICH_LOW_COLOR_BIT; 2591 2592 return (fState->archiving_flags & testMask) == 0; 2593 } 2594 2595 2596 bool 2597 BView::HasSystemColors() const 2598 { 2599 return fState->which_view_color == B_PANEL_BACKGROUND_COLOR 2600 && fState->which_high_color == B_PANEL_TEXT_COLOR 2601 && fState->which_low_color == B_PANEL_BACKGROUND_COLOR 2602 && fState->which_view_color_tint == B_NO_TINT 2603 && fState->which_high_color_tint == B_NO_TINT 2604 && fState->which_low_color_tint == B_NO_TINT; 2605 } 2606 2607 2608 void 2609 BView::AdoptParentColors() 2610 { 2611 AdoptViewColors(Parent()); 2612 } 2613 2614 2615 void 2616 BView::AdoptSystemColors() 2617 { 2618 SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 2619 SetLowUIColor(B_PANEL_BACKGROUND_COLOR); 2620 SetHighUIColor(B_PANEL_TEXT_COLOR); 2621 } 2622 2623 2624 void 2625 BView::AdoptViewColors(BView* view) 2626 { 2627 if (view == NULL || (view->Window() != NULL && !view->LockLooper())) 2628 return; 2629 2630 float tint = B_NO_TINT; 2631 float viewTint = tint; 2632 color_which viewWhich = view->ViewUIColor(&viewTint); 2633 2634 // View color 2635 if (viewWhich != B_NO_COLOR) 2636 SetViewUIColor(viewWhich, viewTint); 2637 else 2638 SetViewColor(view->ViewColor()); 2639 2640 // Low color 2641 color_which which = view->LowUIColor(&tint); 2642 if (which != B_NO_COLOR) 2643 SetLowUIColor(which, tint); 2644 else if (viewWhich != B_NO_COLOR) 2645 SetLowUIColor(viewWhich, viewTint); 2646 else 2647 SetLowColor(view->LowColor()); 2648 2649 // High color 2650 which = view->HighUIColor(&tint); 2651 if (which != B_NO_COLOR) 2652 SetHighUIColor(which, tint); 2653 else 2654 SetHighColor(view->HighColor()); 2655 2656 if (view->Window() != NULL) 2657 view->UnlockLooper(); 2658 } 2659 2660 2661 void 2662 BView::SetViewColor(rgb_color color) 2663 { 2664 SetViewUIColor(B_NO_COLOR); 2665 2666 if (fState->IsValid(B_VIEW_VIEW_COLOR_BIT) 2667 && fState->view_color == color) 2668 return; 2669 2670 if (fOwner) { 2671 _CheckLockAndSwitchCurrent(); 2672 2673 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_COLOR); 2674 fOwner->fLink->Attach<rgb_color>(color); 2675 fOwner->fLink->Flush(); 2676 2677 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT; 2678 } 2679 2680 fState->view_color = color; 2681 2682 fState->archiving_flags |= B_VIEW_VIEW_COLOR_BIT; 2683 } 2684 2685 2686 rgb_color 2687 BView::ViewColor() const 2688 { 2689 if (!fState->IsValid(B_VIEW_VIEW_COLOR_BIT) && fOwner) { 2690 _CheckLockAndSwitchCurrent(); 2691 2692 fOwner->fLink->StartMessage(AS_VIEW_GET_VIEW_COLOR); 2693 2694 int32 code; 2695 if (fOwner->fLink->FlushWithReply(code) == B_OK 2696 && code == B_OK) { 2697 fOwner->fLink->Read<rgb_color>(&fState->view_color); 2698 2699 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT; 2700 } 2701 } 2702 2703 return fState->view_color; 2704 } 2705 2706 2707 void 2708 BView::SetViewUIColor(color_which which, float tint) 2709 { 2710 if (fState->IsValid(B_VIEW_WHICH_VIEW_COLOR_BIT) 2711 && fState->which_view_color == which 2712 && fState->which_view_color_tint == tint) 2713 return; 2714 2715 if (fOwner != NULL) { 2716 _CheckLockAndSwitchCurrent(); 2717 2718 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_UI_COLOR); 2719 fOwner->fLink->Attach<color_which>(which); 2720 fOwner->fLink->Attach<float>(tint); 2721 2722 fState->valid_flags |= B_VIEW_WHICH_VIEW_COLOR_BIT; 2723 } 2724 2725 fState->which_view_color = which; 2726 fState->which_view_color_tint = tint; 2727 2728 if (which != B_NO_COLOR) { 2729 fState->archiving_flags |= B_VIEW_WHICH_VIEW_COLOR_BIT; 2730 fState->archiving_flags &= ~B_VIEW_VIEW_COLOR_BIT; 2731 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT; 2732 2733 fState->view_color = tint_color(ui_color(which), tint); 2734 } else { 2735 fState->valid_flags &= ~B_VIEW_VIEW_COLOR_BIT; 2736 fState->archiving_flags &= ~B_VIEW_WHICH_VIEW_COLOR_BIT; 2737 } 2738 2739 if (!fState->IsValid(B_VIEW_WHICH_LOW_COLOR_BIT)) 2740 SetLowUIColor(which, tint); 2741 } 2742 2743 2744 color_which 2745 BView::ViewUIColor(float* tint) const 2746 { 2747 if (!fState->IsValid(B_VIEW_WHICH_VIEW_COLOR_BIT) 2748 && fOwner != NULL) { 2749 _CheckLockAndSwitchCurrent(); 2750 2751 fOwner->fLink->StartMessage(AS_VIEW_GET_VIEW_UI_COLOR); 2752 2753 int32 code; 2754 if (fOwner->fLink->FlushWithReply(code) == B_OK 2755 && code == B_OK) { 2756 fOwner->fLink->Read<color_which>(&fState->which_view_color); 2757 fOwner->fLink->Read<float>(&fState->which_view_color_tint); 2758 fOwner->fLink->Read<rgb_color>(&fState->view_color); 2759 2760 fState->valid_flags |= B_VIEW_WHICH_VIEW_COLOR_BIT; 2761 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT; 2762 } 2763 } 2764 2765 if (tint != NULL) 2766 *tint = fState->which_view_color_tint; 2767 2768 return fState->which_view_color; 2769 } 2770 2771 2772 void 2773 BView::ForceFontAliasing(bool enable) 2774 { 2775 if (fState->IsValid(B_VIEW_FONT_ALIASING_BIT) 2776 && enable == fState->font_aliasing) 2777 return; 2778 2779 if (fOwner) { 2780 _CheckLockAndSwitchCurrent(); 2781 2782 fOwner->fLink->StartMessage(AS_VIEW_PRINT_ALIASING); 2783 fOwner->fLink->Attach<bool>(enable); 2784 2785 fState->valid_flags |= B_VIEW_FONT_ALIASING_BIT; 2786 } 2787 2788 fState->font_aliasing = enable; 2789 fState->archiving_flags |= B_VIEW_FONT_ALIASING_BIT; 2790 } 2791 2792 2793 void 2794 BView::SetFont(const BFont* font, uint32 mask) 2795 { 2796 if (!font || mask == 0) 2797 return; 2798 2799 if (mask == B_FONT_ALL) { 2800 fState->font = *font; 2801 } else { 2802 // TODO: move this into a BFont method 2803 if (mask & B_FONT_FAMILY_AND_STYLE) 2804 fState->font.SetFamilyAndStyle(font->FamilyAndStyle()); 2805 2806 if (mask & B_FONT_SIZE) 2807 fState->font.SetSize(font->Size()); 2808 2809 if (mask & B_FONT_SHEAR) 2810 fState->font.SetShear(font->Shear()); 2811 2812 if (mask & B_FONT_ROTATION) 2813 fState->font.SetRotation(font->Rotation()); 2814 2815 if (mask & B_FONT_FALSE_BOLD_WIDTH) 2816 fState->font.SetFalseBoldWidth(font->FalseBoldWidth()); 2817 2818 if (mask & B_FONT_SPACING) 2819 fState->font.SetSpacing(font->Spacing()); 2820 2821 if (mask & B_FONT_ENCODING) 2822 fState->font.SetEncoding(font->Encoding()); 2823 2824 if (mask & B_FONT_FACE) 2825 fState->font.SetFace(font->Face()); 2826 2827 if (mask & B_FONT_FLAGS) 2828 fState->font.SetFlags(font->Flags()); 2829 } 2830 2831 fState->font_flags |= mask; 2832 2833 if (fOwner) { 2834 _CheckLockAndSwitchCurrent(); 2835 2836 fState->UpdateServerFontState(*fOwner->fLink); 2837 fState->valid_flags |= B_VIEW_FONT_BIT; 2838 } 2839 2840 fState->archiving_flags |= B_VIEW_FONT_BIT; 2841 // TODO: InvalidateLayout() here for convenience? 2842 } 2843 2844 2845 void 2846 BView::GetFont(BFont* font) const 2847 { 2848 if (!fState->IsValid(B_VIEW_FONT_BIT)) { 2849 // we don't keep graphics state information, therefor 2850 // we need to ask the server for the origin after PopState() 2851 _CheckOwnerLockAndSwitchCurrent(); 2852 2853 // TODO: add a font getter! 2854 fState->UpdateFrom(*fOwner->fLink); 2855 } 2856 2857 *font = fState->font; 2858 } 2859 2860 2861 void 2862 BView::GetFontHeight(font_height* height) const 2863 { 2864 fState->font.GetHeight(height); 2865 } 2866 2867 2868 void 2869 BView::SetFontSize(float size) 2870 { 2871 BFont font; 2872 font.SetSize(size); 2873 2874 SetFont(&font, B_FONT_SIZE); 2875 } 2876 2877 2878 float 2879 BView::StringWidth(const char* string) const 2880 { 2881 return fState->font.StringWidth(string); 2882 } 2883 2884 2885 float 2886 BView::StringWidth(const char* string, int32 length) const 2887 { 2888 return fState->font.StringWidth(string, length); 2889 } 2890 2891 2892 void 2893 BView::GetStringWidths(char* stringArray[], int32 lengthArray[], 2894 int32 numStrings, float widthArray[]) const 2895 { 2896 fState->font.GetStringWidths(const_cast<const char**>(stringArray), 2897 const_cast<const int32*>(lengthArray), numStrings, widthArray); 2898 } 2899 2900 2901 void 2902 BView::TruncateString(BString* string, uint32 mode, float width) const 2903 { 2904 fState->font.TruncateString(string, mode, width); 2905 } 2906 2907 2908 void 2909 BView::ClipToPicture(BPicture* picture, BPoint where, bool sync) 2910 { 2911 _ClipToPicture(picture, where, false, sync); 2912 } 2913 2914 2915 void 2916 BView::ClipToInversePicture(BPicture* picture, BPoint where, bool sync) 2917 { 2918 _ClipToPicture(picture, where, true, sync); 2919 } 2920 2921 2922 void 2923 BView::GetClippingRegion(BRegion* region) const 2924 { 2925 if (!region) 2926 return; 2927 2928 // NOTE: the client has no idea when the clipping in the server 2929 // changed, so it is always read from the server 2930 region->MakeEmpty(); 2931 2932 2933 if (fOwner) { 2934 if (fIsPrinting && _CheckOwnerLock()) { 2935 region->Set(fState->print_rect); 2936 return; 2937 } 2938 2939 _CheckLockAndSwitchCurrent(); 2940 fOwner->fLink->StartMessage(AS_VIEW_GET_CLIP_REGION); 2941 2942 int32 code; 2943 if (fOwner->fLink->FlushWithReply(code) == B_OK 2944 && code == B_OK) { 2945 fOwner->fLink->ReadRegion(region); 2946 fState->valid_flags |= B_VIEW_CLIP_REGION_BIT; 2947 } 2948 } 2949 } 2950 2951 2952 void 2953 BView::ConstrainClippingRegion(BRegion* region) 2954 { 2955 if (_CheckOwnerLockAndSwitchCurrent()) { 2956 fOwner->fLink->StartMessage(AS_VIEW_SET_CLIP_REGION); 2957 2958 if (region) { 2959 int32 count = region->CountRects(); 2960 fOwner->fLink->Attach<int32>(count); 2961 if (count > 0) 2962 fOwner->fLink->AttachRegion(*region); 2963 } else { 2964 fOwner->fLink->Attach<int32>(-1); 2965 // '-1' means that in the app_server, there won't be any 'local' 2966 // clipping region (it will be NULL) 2967 } 2968 2969 _FlushIfNotInTransaction(); 2970 2971 fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT; 2972 fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT; 2973 } 2974 } 2975 2976 2977 void 2978 BView::ClipToRect(BRect rect) 2979 { 2980 _ClipToRect(rect, false); 2981 } 2982 2983 2984 void 2985 BView::ClipToInverseRect(BRect rect) 2986 { 2987 _ClipToRect(rect, true); 2988 } 2989 2990 2991 void 2992 BView::ClipToShape(BShape* shape) 2993 { 2994 _ClipToShape(shape, false); 2995 } 2996 2997 2998 void 2999 BView::ClipToInverseShape(BShape* shape) 3000 { 3001 _ClipToShape(shape, true); 3002 } 3003 3004 3005 // #pragma mark - Drawing Functions 3006 3007 3008 void 3009 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect, 3010 uint32 options) 3011 { 3012 if (bitmap == NULL || fOwner == NULL 3013 || !bitmapRect.IsValid() || !viewRect.IsValid()) 3014 return; 3015 3016 _CheckLockAndSwitchCurrent(); 3017 3018 ViewDrawBitmapInfo info; 3019 info.bitmapToken = bitmap->_ServerToken(); 3020 info.options = options; 3021 info.viewRect = viewRect; 3022 info.bitmapRect = bitmapRect; 3023 3024 fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP); 3025 fOwner->fLink->Attach<ViewDrawBitmapInfo>(info); 3026 3027 _FlushIfNotInTransaction(); 3028 } 3029 3030 3031 void 3032 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect) 3033 { 3034 DrawBitmapAsync(bitmap, bitmapRect, viewRect, 0); 3035 } 3036 3037 3038 void 3039 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect viewRect) 3040 { 3041 if (bitmap && fOwner) { 3042 DrawBitmapAsync(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN), 3043 viewRect, 0); 3044 } 3045 } 3046 3047 3048 void 3049 BView::DrawBitmapAsync(const BBitmap* bitmap, BPoint where) 3050 { 3051 if (bitmap == NULL || fOwner == NULL) 3052 return; 3053 3054 _CheckLockAndSwitchCurrent(); 3055 3056 ViewDrawBitmapInfo info; 3057 info.bitmapToken = bitmap->_ServerToken(); 3058 info.options = 0; 3059 info.bitmapRect = bitmap->Bounds().OffsetToCopy(B_ORIGIN); 3060 info.viewRect = info.bitmapRect.OffsetToCopy(where); 3061 3062 fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP); 3063 fOwner->fLink->Attach<ViewDrawBitmapInfo>(info); 3064 3065 _FlushIfNotInTransaction(); 3066 } 3067 3068 3069 void 3070 BView::DrawBitmapAsync(const BBitmap* bitmap) 3071 { 3072 DrawBitmapAsync(bitmap, PenLocation()); 3073 } 3074 3075 3076 void 3077 BView::DrawBitmap(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect, 3078 uint32 options) 3079 { 3080 if (fOwner) { 3081 DrawBitmapAsync(bitmap, bitmapRect, viewRect, options); 3082 Sync(); 3083 } 3084 } 3085 3086 3087 void 3088 BView::DrawBitmap(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect) 3089 { 3090 if (fOwner) { 3091 DrawBitmapAsync(bitmap, bitmapRect, viewRect, 0); 3092 Sync(); 3093 } 3094 } 3095 3096 3097 void 3098 BView::DrawBitmap(const BBitmap* bitmap, BRect viewRect) 3099 { 3100 if (bitmap && fOwner) { 3101 DrawBitmap(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN), viewRect, 3102 0); 3103 } 3104 } 3105 3106 3107 void 3108 BView::DrawBitmap(const BBitmap* bitmap, BPoint where) 3109 { 3110 if (fOwner) { 3111 DrawBitmapAsync(bitmap, where); 3112 Sync(); 3113 } 3114 } 3115 3116 3117 void 3118 BView::DrawBitmap(const BBitmap* bitmap) 3119 { 3120 DrawBitmap(bitmap, PenLocation()); 3121 } 3122 3123 3124 void 3125 BView::DrawTiledBitmapAsync(const BBitmap* bitmap, BRect viewRect, 3126 BPoint phase) 3127 { 3128 if (bitmap == NULL || fOwner == NULL || !viewRect.IsValid()) 3129 return; 3130 3131 _CheckLockAndSwitchCurrent(); 3132 3133 ViewDrawBitmapInfo info; 3134 info.bitmapToken = bitmap->_ServerToken(); 3135 info.options = B_TILE_BITMAP; 3136 info.viewRect = viewRect; 3137 info.bitmapRect = bitmap->Bounds().OffsetToCopy(phase); 3138 3139 fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP); 3140 fOwner->fLink->Attach<ViewDrawBitmapInfo>(info); 3141 3142 _FlushIfNotInTransaction(); 3143 } 3144 3145 3146 void 3147 BView::DrawTiledBitmap(const BBitmap* bitmap, BRect viewRect, BPoint phase) 3148 { 3149 if (fOwner) { 3150 DrawTiledBitmapAsync(bitmap, viewRect, phase); 3151 Sync(); 3152 } 3153 } 3154 3155 3156 void 3157 BView::DrawChar(char c) 3158 { 3159 DrawString(&c, 1, PenLocation()); 3160 } 3161 3162 3163 void 3164 BView::DrawChar(char c, BPoint location) 3165 { 3166 DrawString(&c, 1, location); 3167 } 3168 3169 3170 void 3171 BView::DrawString(const char* string, escapement_delta* delta) 3172 { 3173 if (string == NULL) 3174 return; 3175 3176 DrawString(string, strlen(string), PenLocation(), delta); 3177 } 3178 3179 3180 void 3181 BView::DrawString(const char* string, BPoint location, escapement_delta* delta) 3182 { 3183 if (string == NULL) 3184 return; 3185 3186 DrawString(string, strlen(string), location, delta); 3187 } 3188 3189 3190 void 3191 BView::DrawString(const char* string, int32 length, escapement_delta* delta) 3192 { 3193 DrawString(string, length, PenLocation(), delta); 3194 } 3195 3196 3197 void 3198 BView::DrawString(const char* string, int32 length, BPoint location, 3199 escapement_delta* delta) 3200 { 3201 if (fOwner == NULL || string == NULL || length < 1) 3202 return; 3203 3204 _CheckLockAndSwitchCurrent(); 3205 3206 ViewDrawStringInfo info; 3207 info.stringLength = length; 3208 info.location = location; 3209 if (delta != NULL) 3210 info.delta = *delta; 3211 3212 // quite often delta will be NULL 3213 if (delta) 3214 fOwner->fLink->StartMessage(AS_DRAW_STRING_WITH_DELTA); 3215 else 3216 fOwner->fLink->StartMessage(AS_DRAW_STRING); 3217 3218 fOwner->fLink->Attach<ViewDrawStringInfo>(info); 3219 fOwner->fLink->Attach(string, length); 3220 3221 _FlushIfNotInTransaction(); 3222 3223 // this modifies our pen location, so we invalidate the flag. 3224 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT; 3225 } 3226 3227 3228 void 3229 BView::DrawString(const char* string, const BPoint* locations, 3230 int32 locationCount) 3231 { 3232 if (string == NULL) 3233 return; 3234 3235 DrawString(string, strlen(string), locations, locationCount); 3236 } 3237 3238 3239 void 3240 BView::DrawString(const char* string, int32 length, const BPoint* locations, 3241 int32 locationCount) 3242 { 3243 if (fOwner == NULL || string == NULL || length < 1 || locations == NULL) 3244 return; 3245 3246 _CheckLockAndSwitchCurrent(); 3247 3248 fOwner->fLink->StartMessage(AS_DRAW_STRING_WITH_OFFSETS); 3249 3250 fOwner->fLink->Attach<int32>(length); 3251 fOwner->fLink->Attach<int32>(locationCount); 3252 fOwner->fLink->Attach(string, length); 3253 fOwner->fLink->Attach(locations, locationCount * sizeof(BPoint)); 3254 3255 _FlushIfNotInTransaction(); 3256 3257 // this modifies our pen location, so we invalidate the flag. 3258 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT; 3259 } 3260 3261 3262 void 3263 BView::StrokeEllipse(BPoint center, float xRadius, float yRadius, 3264 ::pattern pattern) 3265 { 3266 StrokeEllipse(BRect(center.x - xRadius, center.y - yRadius, 3267 center.x + xRadius, center.y + yRadius), pattern); 3268 } 3269 3270 3271 void 3272 BView::StrokeEllipse(BRect rect, ::pattern pattern) 3273 { 3274 if (fOwner == NULL) 3275 return; 3276 3277 _CheckLockAndSwitchCurrent(); 3278 _UpdatePattern(pattern); 3279 3280 fOwner->fLink->StartMessage(AS_STROKE_ELLIPSE); 3281 fOwner->fLink->Attach<BRect>(rect); 3282 3283 _FlushIfNotInTransaction(); 3284 } 3285 3286 3287 void 3288 BView::FillEllipse(BPoint center, float xRadius, float yRadius, 3289 ::pattern pattern) 3290 { 3291 FillEllipse(BRect(center.x - xRadius, center.y - yRadius, 3292 center.x + xRadius, center.y + yRadius), pattern); 3293 } 3294 3295 3296 void 3297 BView::FillEllipse(BPoint center, float xRadius, float yRadius, 3298 const BGradient& gradient) 3299 { 3300 FillEllipse(BRect(center.x - xRadius, center.y - yRadius, 3301 center.x + xRadius, center.y + yRadius), gradient); 3302 } 3303 3304 3305 void 3306 BView::FillEllipse(BRect rect, ::pattern pattern) 3307 { 3308 if (fOwner == NULL) 3309 return; 3310 3311 _CheckLockAndSwitchCurrent(); 3312 _UpdatePattern(pattern); 3313 3314 fOwner->fLink->StartMessage(AS_FILL_ELLIPSE); 3315 fOwner->fLink->Attach<BRect>(rect); 3316 3317 _FlushIfNotInTransaction(); 3318 } 3319 3320 3321 void 3322 BView::FillEllipse(BRect rect, const BGradient& gradient) 3323 { 3324 if (fOwner == NULL) 3325 return; 3326 3327 _CheckLockAndSwitchCurrent(); 3328 3329 fOwner->fLink->StartMessage(AS_FILL_ELLIPSE_GRADIENT); 3330 fOwner->fLink->Attach<BRect>(rect); 3331 fOwner->fLink->AttachGradient(gradient); 3332 3333 _FlushIfNotInTransaction(); 3334 } 3335 3336 3337 void 3338 BView::StrokeArc(BPoint center, float xRadius, float yRadius, float startAngle, 3339 float arcAngle, ::pattern pattern) 3340 { 3341 StrokeArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius, 3342 center.y + yRadius), startAngle, arcAngle, pattern); 3343 } 3344 3345 3346 void 3347 BView::StrokeArc(BRect rect, float startAngle, float arcAngle, 3348 ::pattern pattern) 3349 { 3350 if (fOwner == NULL) 3351 return; 3352 3353 _CheckLockAndSwitchCurrent(); 3354 _UpdatePattern(pattern); 3355 3356 fOwner->fLink->StartMessage(AS_STROKE_ARC); 3357 fOwner->fLink->Attach<BRect>(rect); 3358 fOwner->fLink->Attach<float>(startAngle); 3359 fOwner->fLink->Attach<float>(arcAngle); 3360 3361 _FlushIfNotInTransaction(); 3362 } 3363 3364 3365 void 3366 BView::FillArc(BPoint center,float xRadius, float yRadius, float startAngle, 3367 float arcAngle, ::pattern pattern) 3368 { 3369 FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius, 3370 center.y + yRadius), startAngle, arcAngle, pattern); 3371 } 3372 3373 3374 void 3375 BView::FillArc(BPoint center,float xRadius, float yRadius, float startAngle, 3376 float arcAngle, const BGradient& gradient) 3377 { 3378 FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius, 3379 center.y + yRadius), startAngle, arcAngle, gradient); 3380 } 3381 3382 3383 void 3384 BView::FillArc(BRect rect, float startAngle, float arcAngle, 3385 ::pattern pattern) 3386 { 3387 if (fOwner == NULL) 3388 return; 3389 3390 _CheckLockAndSwitchCurrent(); 3391 _UpdatePattern(pattern); 3392 3393 fOwner->fLink->StartMessage(AS_FILL_ARC); 3394 fOwner->fLink->Attach<BRect>(rect); 3395 fOwner->fLink->Attach<float>(startAngle); 3396 fOwner->fLink->Attach<float>(arcAngle); 3397 3398 _FlushIfNotInTransaction(); 3399 } 3400 3401 3402 void 3403 BView::FillArc(BRect rect, float startAngle, float arcAngle, 3404 const BGradient& gradient) 3405 { 3406 if (fOwner == NULL) 3407 return; 3408 3409 _CheckLockAndSwitchCurrent(); 3410 3411 fOwner->fLink->StartMessage(AS_FILL_ARC_GRADIENT); 3412 fOwner->fLink->Attach<BRect>(rect); 3413 fOwner->fLink->Attach<float>(startAngle); 3414 fOwner->fLink->Attach<float>(arcAngle); 3415 fOwner->fLink->AttachGradient(gradient); 3416 3417 _FlushIfNotInTransaction(); 3418 } 3419 3420 3421 void 3422 BView::StrokeBezier(BPoint* controlPoints, ::pattern pattern) 3423 { 3424 if (fOwner == NULL) 3425 return; 3426 3427 _CheckLockAndSwitchCurrent(); 3428 _UpdatePattern(pattern); 3429 3430 fOwner->fLink->StartMessage(AS_STROKE_BEZIER); 3431 fOwner->fLink->Attach<BPoint>(controlPoints[0]); 3432 fOwner->fLink->Attach<BPoint>(controlPoints[1]); 3433 fOwner->fLink->Attach<BPoint>(controlPoints[2]); 3434 fOwner->fLink->Attach<BPoint>(controlPoints[3]); 3435 3436 _FlushIfNotInTransaction(); 3437 } 3438 3439 3440 void 3441 BView::FillBezier(BPoint* controlPoints, ::pattern pattern) 3442 { 3443 if (fOwner == NULL) 3444 return; 3445 3446 _CheckLockAndSwitchCurrent(); 3447 _UpdatePattern(pattern); 3448 3449 fOwner->fLink->StartMessage(AS_FILL_BEZIER); 3450 fOwner->fLink->Attach<BPoint>(controlPoints[0]); 3451 fOwner->fLink->Attach<BPoint>(controlPoints[1]); 3452 fOwner->fLink->Attach<BPoint>(controlPoints[2]); 3453 fOwner->fLink->Attach<BPoint>(controlPoints[3]); 3454 3455 _FlushIfNotInTransaction(); 3456 } 3457 3458 3459 void 3460 BView::FillBezier(BPoint* controlPoints, const BGradient& gradient) 3461 { 3462 if (fOwner == NULL) 3463 return; 3464 3465 _CheckLockAndSwitchCurrent(); 3466 3467 fOwner->fLink->StartMessage(AS_FILL_BEZIER_GRADIENT); 3468 fOwner->fLink->Attach<BPoint>(controlPoints[0]); 3469 fOwner->fLink->Attach<BPoint>(controlPoints[1]); 3470 fOwner->fLink->Attach<BPoint>(controlPoints[2]); 3471 fOwner->fLink->Attach<BPoint>(controlPoints[3]); 3472 fOwner->fLink->AttachGradient(gradient); 3473 3474 _FlushIfNotInTransaction(); 3475 } 3476 3477 3478 void 3479 BView::StrokePolygon(const BPolygon* polygon, bool closed, ::pattern pattern) 3480 { 3481 if (polygon == NULL) 3482 return; 3483 3484 StrokePolygon(polygon->fPoints, polygon->fCount, polygon->Frame(), closed, 3485 pattern); 3486 } 3487 3488 3489 void 3490 BView::StrokePolygon(const BPoint* pointArray, int32 numPoints, bool closed, 3491 ::pattern pattern) 3492 { 3493 BPolygon polygon(pointArray, numPoints); 3494 3495 StrokePolygon(polygon.fPoints, polygon.fCount, polygon.Frame(), closed, 3496 pattern); 3497 } 3498 3499 3500 void 3501 BView::StrokePolygon(const BPoint* pointArray, int32 numPoints, BRect bounds, 3502 bool closed, ::pattern pattern) 3503 { 3504 if (pointArray == NULL 3505 || numPoints <= 1 3506 || fOwner == NULL) 3507 return; 3508 3509 _CheckLockAndSwitchCurrent(); 3510 _UpdatePattern(pattern); 3511 3512 BPolygon polygon(pointArray, numPoints); 3513 polygon.MapTo(polygon.Frame(), bounds); 3514 3515 if (fOwner->fLink->StartMessage(AS_STROKE_POLYGON, 3516 polygon.fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(bool) 3517 + sizeof(int32)) == B_OK) { 3518 fOwner->fLink->Attach<BRect>(polygon.Frame()); 3519 fOwner->fLink->Attach<bool>(closed); 3520 fOwner->fLink->Attach<int32>(polygon.fCount); 3521 fOwner->fLink->Attach(polygon.fPoints, polygon.fCount * sizeof(BPoint)); 3522 3523 _FlushIfNotInTransaction(); 3524 } else { 3525 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n"); 3526 } 3527 } 3528 3529 3530 void 3531 BView::FillPolygon(const BPolygon* polygon, ::pattern pattern) 3532 { 3533 if (polygon == NULL 3534 || polygon->fCount <= 2 3535 || fOwner == NULL) 3536 return; 3537 3538 _CheckLockAndSwitchCurrent(); 3539 _UpdatePattern(pattern); 3540 3541 if (fOwner->fLink->StartMessage(AS_FILL_POLYGON, 3542 polygon->fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(int32)) 3543 == B_OK) { 3544 fOwner->fLink->Attach<BRect>(polygon->Frame()); 3545 fOwner->fLink->Attach<int32>(polygon->fCount); 3546 fOwner->fLink->Attach(polygon->fPoints, 3547 polygon->fCount * sizeof(BPoint)); 3548 3549 _FlushIfNotInTransaction(); 3550 } else { 3551 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n"); 3552 } 3553 } 3554 3555 3556 void 3557 BView::FillPolygon(const BPolygon* polygon, const BGradient& gradient) 3558 { 3559 if (polygon == NULL 3560 || polygon->fCount <= 2 3561 || fOwner == NULL) 3562 return; 3563 3564 _CheckLockAndSwitchCurrent(); 3565 3566 if (fOwner->fLink->StartMessage(AS_FILL_POLYGON_GRADIENT, 3567 polygon->fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(int32)) 3568 == B_OK) { 3569 fOwner->fLink->Attach<BRect>(polygon->Frame()); 3570 fOwner->fLink->Attach<int32>(polygon->fCount); 3571 fOwner->fLink->Attach(polygon->fPoints, 3572 polygon->fCount * sizeof(BPoint)); 3573 fOwner->fLink->AttachGradient(gradient); 3574 3575 _FlushIfNotInTransaction(); 3576 } else { 3577 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n"); 3578 } 3579 } 3580 3581 3582 void 3583 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, ::pattern pattern) 3584 { 3585 if (pointArray == NULL) 3586 return; 3587 3588 BPolygon polygon(pointArray, numPoints); 3589 FillPolygon(&polygon, pattern); 3590 } 3591 3592 3593 void 3594 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, 3595 const BGradient& gradient) 3596 { 3597 if (pointArray == NULL) 3598 return; 3599 3600 BPolygon polygon(pointArray, numPoints); 3601 FillPolygon(&polygon, gradient); 3602 } 3603 3604 3605 void 3606 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, BRect bounds, 3607 ::pattern pattern) 3608 { 3609 if (pointArray == NULL) 3610 return; 3611 3612 BPolygon polygon(pointArray, numPoints); 3613 3614 polygon.MapTo(polygon.Frame(), bounds); 3615 FillPolygon(&polygon, pattern); 3616 } 3617 3618 3619 void 3620 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, BRect bounds, 3621 const BGradient& gradient) 3622 { 3623 if (pointArray == NULL) 3624 return; 3625 3626 BPolygon polygon(pointArray, numPoints); 3627 3628 polygon.MapTo(polygon.Frame(), bounds); 3629 FillPolygon(&polygon, gradient); 3630 } 3631 3632 3633 void 3634 BView::StrokeRect(BRect rect, ::pattern pattern) 3635 { 3636 if (fOwner == NULL) 3637 return; 3638 3639 _CheckLockAndSwitchCurrent(); 3640 _UpdatePattern(pattern); 3641 3642 fOwner->fLink->StartMessage(AS_STROKE_RECT); 3643 fOwner->fLink->Attach<BRect>(rect); 3644 3645 _FlushIfNotInTransaction(); 3646 } 3647 3648 3649 void 3650 BView::FillRect(BRect rect, ::pattern pattern) 3651 { 3652 if (fOwner == NULL) 3653 return; 3654 3655 // NOTE: ensuring compatibility with R5, 3656 // invalid rects are not filled, they are stroked though! 3657 if (!rect.IsValid()) 3658 return; 3659 3660 _CheckLockAndSwitchCurrent(); 3661 _UpdatePattern(pattern); 3662 3663 fOwner->fLink->StartMessage(AS_FILL_RECT); 3664 fOwner->fLink->Attach<BRect>(rect); 3665 3666 _FlushIfNotInTransaction(); 3667 } 3668 3669 3670 void 3671 BView::FillRect(BRect rect, const BGradient& gradient) 3672 { 3673 if (fOwner == NULL) 3674 return; 3675 3676 // NOTE: ensuring compatibility with R5, 3677 // invalid rects are not filled, they are stroked though! 3678 if (!rect.IsValid()) 3679 return; 3680 3681 _CheckLockAndSwitchCurrent(); 3682 3683 fOwner->fLink->StartMessage(AS_FILL_RECT_GRADIENT); 3684 fOwner->fLink->Attach<BRect>(rect); 3685 fOwner->fLink->AttachGradient(gradient); 3686 3687 _FlushIfNotInTransaction(); 3688 } 3689 3690 3691 void 3692 BView::StrokeRoundRect(BRect rect, float xRadius, float yRadius, 3693 ::pattern pattern) 3694 { 3695 if (fOwner == NULL) 3696 return; 3697 3698 _CheckLockAndSwitchCurrent(); 3699 _UpdatePattern(pattern); 3700 3701 fOwner->fLink->StartMessage(AS_STROKE_ROUNDRECT); 3702 fOwner->fLink->Attach<BRect>(rect); 3703 fOwner->fLink->Attach<float>(xRadius); 3704 fOwner->fLink->Attach<float>(yRadius); 3705 3706 _FlushIfNotInTransaction(); 3707 } 3708 3709 3710 void 3711 BView::FillRoundRect(BRect rect, float xRadius, float yRadius, 3712 ::pattern pattern) 3713 { 3714 if (fOwner == NULL) 3715 return; 3716 3717 _CheckLockAndSwitchCurrent(); 3718 3719 _UpdatePattern(pattern); 3720 3721 fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT); 3722 fOwner->fLink->Attach<BRect>(rect); 3723 fOwner->fLink->Attach<float>(xRadius); 3724 fOwner->fLink->Attach<float>(yRadius); 3725 3726 _FlushIfNotInTransaction(); 3727 } 3728 3729 3730 void 3731 BView::FillRoundRect(BRect rect, float xRadius, float yRadius, 3732 const BGradient& gradient) 3733 { 3734 if (fOwner == NULL) 3735 return; 3736 3737 _CheckLockAndSwitchCurrent(); 3738 3739 fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT_GRADIENT); 3740 fOwner->fLink->Attach<BRect>(rect); 3741 fOwner->fLink->Attach<float>(xRadius); 3742 fOwner->fLink->Attach<float>(yRadius); 3743 fOwner->fLink->AttachGradient(gradient); 3744 3745 _FlushIfNotInTransaction(); 3746 } 3747 3748 3749 void 3750 BView::FillRegion(BRegion* region, ::pattern pattern) 3751 { 3752 if (region == NULL || fOwner == NULL) 3753 return; 3754 3755 _CheckLockAndSwitchCurrent(); 3756 3757 _UpdatePattern(pattern); 3758 3759 fOwner->fLink->StartMessage(AS_FILL_REGION); 3760 fOwner->fLink->AttachRegion(*region); 3761 3762 _FlushIfNotInTransaction(); 3763 } 3764 3765 3766 void 3767 BView::FillRegion(BRegion* region, const BGradient& gradient) 3768 { 3769 if (region == NULL || fOwner == NULL) 3770 return; 3771 3772 _CheckLockAndSwitchCurrent(); 3773 3774 fOwner->fLink->StartMessage(AS_FILL_REGION_GRADIENT); 3775 fOwner->fLink->AttachRegion(*region); 3776 fOwner->fLink->AttachGradient(gradient); 3777 3778 _FlushIfNotInTransaction(); 3779 } 3780 3781 3782 void 3783 BView::StrokeTriangle(BPoint point1, BPoint point2, BPoint point3, BRect bounds, 3784 ::pattern pattern) 3785 { 3786 if (fOwner == NULL) 3787 return; 3788 3789 _CheckLockAndSwitchCurrent(); 3790 3791 _UpdatePattern(pattern); 3792 3793 fOwner->fLink->StartMessage(AS_STROKE_TRIANGLE); 3794 fOwner->fLink->Attach<BPoint>(point1); 3795 fOwner->fLink->Attach<BPoint>(point2); 3796 fOwner->fLink->Attach<BPoint>(point3); 3797 fOwner->fLink->Attach<BRect>(bounds); 3798 3799 _FlushIfNotInTransaction(); 3800 } 3801 3802 3803 void 3804 BView::StrokeTriangle(BPoint point1, BPoint point2, BPoint point3, 3805 ::pattern pattern) 3806 { 3807 if (fOwner) { 3808 // we construct the smallest rectangle that contains the 3 points 3809 // for the 1st point 3810 BRect bounds(point1, point1); 3811 3812 // for the 2nd point 3813 if (point2.x < bounds.left) 3814 bounds.left = point2.x; 3815 3816 if (point2.y < bounds.top) 3817 bounds.top = point2.y; 3818 3819 if (point2.x > bounds.right) 3820 bounds.right = point2.x; 3821 3822 if (point2.y > bounds.bottom) 3823 bounds.bottom = point2.y; 3824 3825 // for the 3rd point 3826 if (point3.x < bounds.left) 3827 bounds.left = point3.x; 3828 3829 if (point3.y < bounds.top) 3830 bounds.top = point3.y; 3831 3832 if (point3.x > bounds.right) 3833 bounds.right = point3.x; 3834 3835 if (point3.y > bounds.bottom) 3836 bounds.bottom = point3.y; 3837 3838 StrokeTriangle(point1, point2, point3, bounds, pattern); 3839 } 3840 } 3841 3842 3843 void 3844 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3, 3845 ::pattern pattern) 3846 { 3847 if (fOwner) { 3848 // we construct the smallest rectangle that contains the 3 points 3849 // for the 1st point 3850 BRect bounds(point1, point1); 3851 3852 // for the 2nd point 3853 if (point2.x < bounds.left) 3854 bounds.left = point2.x; 3855 3856 if (point2.y < bounds.top) 3857 bounds.top = point2.y; 3858 3859 if (point2.x > bounds.right) 3860 bounds.right = point2.x; 3861 3862 if (point2.y > bounds.bottom) 3863 bounds.bottom = point2.y; 3864 3865 // for the 3rd point 3866 if (point3.x < bounds.left) 3867 bounds.left = point3.x; 3868 3869 if (point3.y < bounds.top) 3870 bounds.top = point3.y; 3871 3872 if (point3.x > bounds.right) 3873 bounds.right = point3.x; 3874 3875 if (point3.y > bounds.bottom) 3876 bounds.bottom = point3.y; 3877 3878 FillTriangle(point1, point2, point3, bounds, pattern); 3879 } 3880 } 3881 3882 3883 void 3884 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3, 3885 const BGradient& gradient) 3886 { 3887 if (fOwner) { 3888 // we construct the smallest rectangle that contains the 3 points 3889 // for the 1st point 3890 BRect bounds(point1, point1); 3891 3892 // for the 2nd point 3893 if (point2.x < bounds.left) 3894 bounds.left = point2.x; 3895 3896 if (point2.y < bounds.top) 3897 bounds.top = point2.y; 3898 3899 if (point2.x > bounds.right) 3900 bounds.right = point2.x; 3901 3902 if (point2.y > bounds.bottom) 3903 bounds.bottom = point2.y; 3904 3905 // for the 3rd point 3906 if (point3.x < bounds.left) 3907 bounds.left = point3.x; 3908 3909 if (point3.y < bounds.top) 3910 bounds.top = point3.y; 3911 3912 if (point3.x > bounds.right) 3913 bounds.right = point3.x; 3914 3915 if (point3.y > bounds.bottom) 3916 bounds.bottom = point3.y; 3917 3918 FillTriangle(point1, point2, point3, bounds, gradient); 3919 } 3920 } 3921 3922 3923 void 3924 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3, 3925 BRect bounds, ::pattern pattern) 3926 { 3927 if (fOwner == NULL) 3928 return; 3929 3930 _CheckLockAndSwitchCurrent(); 3931 _UpdatePattern(pattern); 3932 3933 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE); 3934 fOwner->fLink->Attach<BPoint>(point1); 3935 fOwner->fLink->Attach<BPoint>(point2); 3936 fOwner->fLink->Attach<BPoint>(point3); 3937 fOwner->fLink->Attach<BRect>(bounds); 3938 3939 _FlushIfNotInTransaction(); 3940 } 3941 3942 3943 void 3944 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3, BRect bounds, 3945 const BGradient& gradient) 3946 { 3947 if (fOwner == NULL) 3948 return; 3949 3950 _CheckLockAndSwitchCurrent(); 3951 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE_GRADIENT); 3952 fOwner->fLink->Attach<BPoint>(point1); 3953 fOwner->fLink->Attach<BPoint>(point2); 3954 fOwner->fLink->Attach<BPoint>(point3); 3955 fOwner->fLink->Attach<BRect>(bounds); 3956 fOwner->fLink->AttachGradient(gradient); 3957 3958 _FlushIfNotInTransaction(); 3959 } 3960 3961 3962 void 3963 BView::StrokeLine(BPoint toPoint, ::pattern pattern) 3964 { 3965 StrokeLine(PenLocation(), toPoint, pattern); 3966 } 3967 3968 3969 void 3970 BView::StrokeLine(BPoint start, BPoint end, ::pattern pattern) 3971 { 3972 if (fOwner == NULL) 3973 return; 3974 3975 _CheckLockAndSwitchCurrent(); 3976 _UpdatePattern(pattern); 3977 3978 ViewStrokeLineInfo info; 3979 info.startPoint = start; 3980 info.endPoint = end; 3981 3982 fOwner->fLink->StartMessage(AS_STROKE_LINE); 3983 fOwner->fLink->Attach<ViewStrokeLineInfo>(info); 3984 3985 _FlushIfNotInTransaction(); 3986 3987 // this modifies our pen location, so we invalidate the flag. 3988 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT; 3989 } 3990 3991 3992 void 3993 BView::StrokeShape(BShape* shape, ::pattern pattern) 3994 { 3995 if (shape == NULL || fOwner == NULL) 3996 return; 3997 3998 shape_data* sd = (shape_data*)shape->fPrivateData; 3999 if (sd->opCount == 0 || sd->ptCount == 0) 4000 return; 4001 4002 _CheckLockAndSwitchCurrent(); 4003 _UpdatePattern(pattern); 4004 4005 fOwner->fLink->StartMessage(AS_STROKE_SHAPE); 4006 fOwner->fLink->Attach<BRect>(shape->Bounds()); 4007 fOwner->fLink->Attach<int32>(sd->opCount); 4008 fOwner->fLink->Attach<int32>(sd->ptCount); 4009 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(uint32)); 4010 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 4011 4012 _FlushIfNotInTransaction(); 4013 } 4014 4015 4016 void 4017 BView::FillShape(BShape* shape, ::pattern pattern) 4018 { 4019 if (shape == NULL || fOwner == NULL) 4020 return; 4021 4022 shape_data* sd = (shape_data*)(shape->fPrivateData); 4023 if (sd->opCount == 0 || sd->ptCount == 0) 4024 return; 4025 4026 _CheckLockAndSwitchCurrent(); 4027 _UpdatePattern(pattern); 4028 4029 fOwner->fLink->StartMessage(AS_FILL_SHAPE); 4030 fOwner->fLink->Attach<BRect>(shape->Bounds()); 4031 fOwner->fLink->Attach<int32>(sd->opCount); 4032 fOwner->fLink->Attach<int32>(sd->ptCount); 4033 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32)); 4034 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 4035 4036 _FlushIfNotInTransaction(); 4037 } 4038 4039 4040 void 4041 BView::FillShape(BShape* shape, const BGradient& gradient) 4042 { 4043 if (shape == NULL || fOwner == NULL) 4044 return; 4045 4046 shape_data* sd = (shape_data*)(shape->fPrivateData); 4047 if (sd->opCount == 0 || sd->ptCount == 0) 4048 return; 4049 4050 _CheckLockAndSwitchCurrent(); 4051 4052 fOwner->fLink->StartMessage(AS_FILL_SHAPE_GRADIENT); 4053 fOwner->fLink->Attach<BRect>(shape->Bounds()); 4054 fOwner->fLink->Attach<int32>(sd->opCount); 4055 fOwner->fLink->Attach<int32>(sd->ptCount); 4056 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32)); 4057 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 4058 fOwner->fLink->AttachGradient(gradient); 4059 4060 _FlushIfNotInTransaction(); 4061 } 4062 4063 4064 void 4065 BView::BeginLineArray(int32 count) 4066 { 4067 if (fOwner == NULL) 4068 return; 4069 4070 if (count <= 0) 4071 debugger("Calling BeginLineArray with a count <= 0"); 4072 4073 _CheckLock(); 4074 4075 if (fCommArray) { 4076 debugger("Can't nest BeginLineArray calls"); 4077 // not fatal, but it helps during 4078 // development of your app and is in 4079 // line with R5... 4080 delete[] fCommArray->array; 4081 delete fCommArray; 4082 } 4083 4084 // TODO: since this method cannot return failure, and further AddLine() 4085 // calls with a NULL fCommArray would drop into the debugger anyway, 4086 // we allow the possible std::bad_alloc exceptions here... 4087 fCommArray = new _array_data_; 4088 fCommArray->count = 0; 4089 4090 // Make sure the fCommArray is initialized to reasonable values in cases of 4091 // bad_alloc. At least the exception can be caught and EndLineArray won't 4092 // crash. 4093 fCommArray->array = NULL; 4094 fCommArray->maxCount = 0; 4095 4096 fCommArray->array = new ViewLineArrayInfo[count]; 4097 fCommArray->maxCount = count; 4098 } 4099 4100 4101 void 4102 BView::AddLine(BPoint start, BPoint end, rgb_color color) 4103 { 4104 if (fOwner == NULL) 4105 return; 4106 4107 if (!fCommArray) 4108 debugger("BeginLineArray must be called before using AddLine"); 4109 4110 _CheckLock(); 4111 4112 const uint32 &arrayCount = fCommArray->count; 4113 if (arrayCount < fCommArray->maxCount) { 4114 fCommArray->array[arrayCount].startPoint = start; 4115 fCommArray->array[arrayCount].endPoint = end; 4116 fCommArray->array[arrayCount].color = color; 4117 4118 fCommArray->count++; 4119 } 4120 } 4121 4122 4123 void 4124 BView::EndLineArray() 4125 { 4126 if (fOwner == NULL) 4127 return; 4128 4129 if (fCommArray == NULL) 4130 debugger("Can't call EndLineArray before BeginLineArray"); 4131 4132 _CheckLockAndSwitchCurrent(); 4133 4134 fOwner->fLink->StartMessage(AS_STROKE_LINEARRAY); 4135 fOwner->fLink->Attach<int32>(fCommArray->count); 4136 fOwner->fLink->Attach(fCommArray->array, 4137 fCommArray->count * sizeof(ViewLineArrayInfo)); 4138 4139 _FlushIfNotInTransaction(); 4140 4141 _RemoveCommArray(); 4142 } 4143 4144 4145 void 4146 BView::SetDiskMode(char* filename, long offset) 4147 { 4148 // TODO: implement 4149 // One BeBook version has this to say about SetDiskMode(): 4150 // 4151 // "Begins recording a picture to the file with the given filename 4152 // at the given offset. Subsequent drawing commands sent to the view 4153 // will be written to the file until EndPicture() is called. The 4154 // stored commands may be played from the file with DrawPicture()." 4155 } 4156 4157 4158 void 4159 BView::BeginPicture(BPicture* picture) 4160 { 4161 if (_CheckOwnerLockAndSwitchCurrent() 4162 && picture && picture->fUsurped == NULL) { 4163 picture->Usurp(fCurrentPicture); 4164 fCurrentPicture = picture; 4165 4166 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_PICTURE); 4167 } 4168 } 4169 4170 4171 void 4172 BView::AppendToPicture(BPicture* picture) 4173 { 4174 _CheckLockAndSwitchCurrent(); 4175 4176 if (picture && picture->fUsurped == NULL) { 4177 int32 token = picture->Token(); 4178 4179 if (token == -1) { 4180 BeginPicture(picture); 4181 } else { 4182 picture->SetToken(-1); 4183 picture->Usurp(fCurrentPicture); 4184 fCurrentPicture = picture; 4185 fOwner->fLink->StartMessage(AS_VIEW_APPEND_TO_PICTURE); 4186 fOwner->fLink->Attach<int32>(token); 4187 } 4188 } 4189 } 4190 4191 4192 BPicture* 4193 BView::EndPicture() 4194 { 4195 if (_CheckOwnerLockAndSwitchCurrent() && fCurrentPicture) { 4196 int32 token; 4197 4198 fOwner->fLink->StartMessage(AS_VIEW_END_PICTURE); 4199 4200 int32 code; 4201 if (fOwner->fLink->FlushWithReply(code) == B_OK 4202 && code == B_OK 4203 && fOwner->fLink->Read<int32>(&token) == B_OK) { 4204 BPicture* picture = fCurrentPicture; 4205 fCurrentPicture = picture->StepDown(); 4206 picture->SetToken(token); 4207 4208 // TODO do this more efficient e.g. use a shared area and let the 4209 // client write into it 4210 picture->_Download(); 4211 return picture; 4212 } 4213 } 4214 4215 return NULL; 4216 } 4217 4218 4219 void 4220 BView::SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect, 4221 uint32 followFlags, uint32 options) 4222 { 4223 _SetViewBitmap(bitmap, srcRect, dstRect, followFlags, options); 4224 } 4225 4226 4227 void 4228 BView::SetViewBitmap(const BBitmap* bitmap, uint32 followFlags, uint32 options) 4229 { 4230 BRect rect; 4231 if (bitmap) 4232 rect = bitmap->Bounds(); 4233 4234 rect.OffsetTo(B_ORIGIN); 4235 4236 _SetViewBitmap(bitmap, rect, rect, followFlags, options); 4237 } 4238 4239 4240 void 4241 BView::ClearViewBitmap() 4242 { 4243 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0); 4244 } 4245 4246 4247 status_t 4248 BView::SetViewOverlay(const BBitmap* overlay, BRect srcRect, BRect dstRect, 4249 rgb_color* colorKey, uint32 followFlags, uint32 options) 4250 { 4251 if (overlay == NULL || (overlay->fFlags & B_BITMAP_WILL_OVERLAY) == 0) 4252 return B_BAD_VALUE; 4253 4254 status_t status = _SetViewBitmap(overlay, srcRect, dstRect, followFlags, 4255 options | AS_REQUEST_COLOR_KEY); 4256 if (status == B_OK) { 4257 // read the color that will be treated as transparent 4258 fOwner->fLink->Read<rgb_color>(colorKey); 4259 } 4260 4261 return status; 4262 } 4263 4264 4265 status_t 4266 BView::SetViewOverlay(const BBitmap* overlay, rgb_color* colorKey, 4267 uint32 followFlags, uint32 options) 4268 { 4269 if (overlay == NULL) 4270 return B_BAD_VALUE; 4271 4272 BRect rect = overlay->Bounds(); 4273 rect.OffsetTo(B_ORIGIN); 4274 4275 return SetViewOverlay(overlay, rect, rect, colorKey, followFlags, options); 4276 } 4277 4278 4279 void 4280 BView::ClearViewOverlay() 4281 { 4282 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0); 4283 } 4284 4285 4286 void 4287 BView::CopyBits(BRect src, BRect dst) 4288 { 4289 if (fOwner == NULL) 4290 return; 4291 4292 if (!src.IsValid() || !dst.IsValid()) 4293 return; 4294 4295 _CheckLockAndSwitchCurrent(); 4296 4297 fOwner->fLink->StartMessage(AS_VIEW_COPY_BITS); 4298 fOwner->fLink->Attach<BRect>(src); 4299 fOwner->fLink->Attach<BRect>(dst); 4300 4301 _FlushIfNotInTransaction(); 4302 } 4303 4304 4305 void 4306 BView::DrawPicture(const BPicture* picture) 4307 { 4308 if (picture == NULL) 4309 return; 4310 4311 DrawPictureAsync(picture, PenLocation()); 4312 Sync(); 4313 } 4314 4315 4316 void 4317 BView::DrawPicture(const BPicture* picture, BPoint where) 4318 { 4319 if (picture == NULL) 4320 return; 4321 4322 DrawPictureAsync(picture, where); 4323 Sync(); 4324 } 4325 4326 4327 void 4328 BView::DrawPicture(const char* filename, long offset, BPoint where) 4329 { 4330 if (!filename) 4331 return; 4332 4333 DrawPictureAsync(filename, offset, where); 4334 Sync(); 4335 } 4336 4337 4338 void 4339 BView::DrawPictureAsync(const BPicture* picture) 4340 { 4341 if (picture == NULL) 4342 return; 4343 4344 DrawPictureAsync(picture, PenLocation()); 4345 } 4346 4347 4348 void 4349 BView::DrawPictureAsync(const BPicture* picture, BPoint where) 4350 { 4351 if (picture == NULL) 4352 return; 4353 4354 if (_CheckOwnerLockAndSwitchCurrent() && picture->Token() > 0) { 4355 fOwner->fLink->StartMessage(AS_VIEW_DRAW_PICTURE); 4356 fOwner->fLink->Attach<int32>(picture->Token()); 4357 fOwner->fLink->Attach<BPoint>(where); 4358 4359 _FlushIfNotInTransaction(); 4360 } 4361 } 4362 4363 4364 void 4365 BView::DrawPictureAsync(const char* filename, long offset, BPoint where) 4366 { 4367 if (!filename) 4368 return; 4369 4370 // TODO: Test 4371 BFile file(filename, B_READ_ONLY); 4372 if (file.InitCheck() < B_OK) 4373 return; 4374 4375 file.Seek(offset, SEEK_SET); 4376 4377 BPicture picture; 4378 if (picture.Unflatten(&file) < B_OK) 4379 return; 4380 4381 DrawPictureAsync(&picture, where); 4382 } 4383 4384 4385 void 4386 BView::BeginLayer(uint8 opacity) 4387 { 4388 if (_CheckOwnerLockAndSwitchCurrent()) { 4389 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_LAYER); 4390 fOwner->fLink->Attach<uint8>(opacity); 4391 _FlushIfNotInTransaction(); 4392 } 4393 } 4394 4395 4396 void 4397 BView::EndLayer() 4398 { 4399 if (_CheckOwnerLockAndSwitchCurrent()) { 4400 fOwner->fLink->StartMessage(AS_VIEW_END_LAYER); 4401 _FlushIfNotInTransaction(); 4402 } 4403 } 4404 4405 4406 void 4407 BView::Invalidate(BRect invalRect) 4408 { 4409 if (fOwner == NULL) 4410 return; 4411 4412 // NOTE: This rounding of the invalid rect is to stay compatible with BeOS. 4413 // On the server side, the invalid rect will be converted to a BRegion, 4414 // which rounds in a different manner, so that it really includes the 4415 // fractional coordinates of a BRect (ie ceilf(rect.right) & 4416 // ceilf(rect.bottom)), which is also what BeOS does. So we have to do the 4417 // different rounding here to stay compatible in both ways. 4418 invalRect.left = (int)invalRect.left; 4419 invalRect.top = (int)invalRect.top; 4420 invalRect.right = (int)invalRect.right; 4421 invalRect.bottom = (int)invalRect.bottom; 4422 if (!invalRect.IsValid()) 4423 return; 4424 4425 _CheckLockAndSwitchCurrent(); 4426 4427 fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_RECT); 4428 fOwner->fLink->Attach<BRect>(invalRect); 4429 4430 // TODO: determine why this check isn't working correctly. 4431 #if 0 4432 if (!fOwner->fUpdateRequested) { 4433 fOwner->fLink->Flush(); 4434 fOwner->fUpdateRequested = true; 4435 } 4436 #else 4437 fOwner->fLink->Flush(); 4438 #endif 4439 } 4440 4441 4442 void 4443 BView::Invalidate(const BRegion* region) 4444 { 4445 if (region == NULL || fOwner == NULL) 4446 return; 4447 4448 _CheckLockAndSwitchCurrent(); 4449 4450 fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_REGION); 4451 fOwner->fLink->AttachRegion(*region); 4452 4453 // TODO: See above. 4454 #if 0 4455 if (!fOwner->fUpdateRequested) { 4456 fOwner->fLink->Flush(); 4457 fOwner->fUpdateRequested = true; 4458 } 4459 #else 4460 fOwner->fLink->Flush(); 4461 #endif 4462 } 4463 4464 4465 void 4466 BView::Invalidate() 4467 { 4468 Invalidate(Bounds()); 4469 } 4470 4471 4472 void 4473 BView::DelayedInvalidate(bigtime_t delay) 4474 { 4475 DelayedInvalidate(delay, Bounds()); 4476 } 4477 4478 4479 void 4480 BView::DelayedInvalidate(bigtime_t delay, BRect invalRect) 4481 { 4482 if (fOwner == NULL) 4483 return; 4484 4485 invalRect.left = (int)invalRect.left; 4486 invalRect.top = (int)invalRect.top; 4487 invalRect.right = (int)invalRect.right; 4488 invalRect.bottom = (int)invalRect.bottom; 4489 if (!invalRect.IsValid()) 4490 return; 4491 4492 _CheckLockAndSwitchCurrent(); 4493 4494 fOwner->fLink->StartMessage(AS_VIEW_DELAYED_INVALIDATE_RECT); 4495 fOwner->fLink->Attach<bigtime_t>(system_time() + delay); 4496 fOwner->fLink->Attach<BRect>(invalRect); 4497 fOwner->fLink->Flush(); 4498 } 4499 4500 4501 void 4502 BView::InvertRect(BRect rect) 4503 { 4504 if (fOwner) { 4505 _CheckLockAndSwitchCurrent(); 4506 4507 fOwner->fLink->StartMessage(AS_VIEW_INVERT_RECT); 4508 fOwner->fLink->Attach<BRect>(rect); 4509 4510 _FlushIfNotInTransaction(); 4511 } 4512 } 4513 4514 4515 // #pragma mark - View Hierarchy Functions 4516 4517 4518 void 4519 BView::AddChild(BView* child, BView* before) 4520 { 4521 STRACE(("BView(%s)::AddChild(child '%s', before '%s')\n", 4522 this->Name(), 4523 child != NULL && child->Name() ? child->Name() : "NULL", 4524 before != NULL && before->Name() ? before->Name() : "NULL")); 4525 4526 if (!_AddChild(child, before)) 4527 return; 4528 4529 if (fLayoutData->fLayout) 4530 fLayoutData->fLayout->AddView(child); 4531 } 4532 4533 4534 bool 4535 BView::AddChild(BLayoutItem* child) 4536 { 4537 if (!fLayoutData->fLayout) 4538 return false; 4539 return fLayoutData->fLayout->AddItem(child); 4540 } 4541 4542 4543 bool 4544 BView::_AddChild(BView* child, BView* before) 4545 { 4546 if (!child) 4547 return false; 4548 4549 if (child->fParent != NULL) { 4550 debugger("AddChild failed - the view already has a parent."); 4551 return false; 4552 } 4553 4554 if (child == this) { 4555 debugger("AddChild failed - cannot add a view to itself."); 4556 return false; 4557 } 4558 4559 bool lockedOwner = false; 4560 if (fOwner && !fOwner->IsLocked()) { 4561 fOwner->Lock(); 4562 lockedOwner = true; 4563 } 4564 4565 if (!_AddChildToList(child, before)) { 4566 debugger("AddChild failed!"); 4567 if (lockedOwner) 4568 fOwner->Unlock(); 4569 return false; 4570 } 4571 4572 if (fOwner) { 4573 _CheckLockAndSwitchCurrent(); 4574 4575 child->_SetOwner(fOwner); 4576 child->_CreateSelf(); 4577 child->_Attach(); 4578 4579 if (lockedOwner) 4580 fOwner->Unlock(); 4581 } 4582 4583 InvalidateLayout(); 4584 4585 return true; 4586 } 4587 4588 4589 bool 4590 BView::RemoveChild(BView* child) 4591 { 4592 STRACE(("BView(%s)::RemoveChild(%s)\n", Name(), child->Name())); 4593 4594 if (!child) 4595 return false; 4596 4597 if (child->fParent != this) 4598 return false; 4599 4600 return child->RemoveSelf(); 4601 } 4602 4603 4604 int32 4605 BView::CountChildren() const 4606 { 4607 _CheckLock(); 4608 4609 uint32 count = 0; 4610 BView* child = fFirstChild; 4611 4612 while (child != NULL) { 4613 count++; 4614 child = child->fNextSibling; 4615 } 4616 4617 return count; 4618 } 4619 4620 4621 BView* 4622 BView::ChildAt(int32 index) const 4623 { 4624 _CheckLock(); 4625 4626 BView* child = fFirstChild; 4627 while (child != NULL && index-- > 0) { 4628 child = child->fNextSibling; 4629 } 4630 4631 return child; 4632 } 4633 4634 4635 BView* 4636 BView::NextSibling() const 4637 { 4638 return fNextSibling; 4639 } 4640 4641 4642 BView* 4643 BView::PreviousSibling() const 4644 { 4645 return fPreviousSibling; 4646 } 4647 4648 4649 bool 4650 BView::RemoveSelf() 4651 { 4652 _RemoveLayoutItemsFromLayout(false); 4653 4654 return _RemoveSelf(); 4655 } 4656 4657 4658 bool 4659 BView::_RemoveSelf() 4660 { 4661 STRACE(("BView(%s)::_RemoveSelf()\n", Name())); 4662 4663 // Remove this child from its parent 4664 4665 BWindow* owner = fOwner; 4666 _CheckLock(); 4667 4668 if (owner != NULL) { 4669 _UpdateStateForRemove(); 4670 _Detach(); 4671 } 4672 4673 BView* parent = fParent; 4674 if (!parent || !parent->_RemoveChildFromList(this)) 4675 return false; 4676 4677 if (owner != NULL && !fTopLevelView) { 4678 // the top level view is deleted by the app_server automatically 4679 owner->fLink->StartMessage(AS_VIEW_DELETE); 4680 owner->fLink->Attach<int32>(_get_object_token_(this)); 4681 } 4682 4683 parent->InvalidateLayout(); 4684 4685 STRACE(("DONE: BView(%s)::_RemoveSelf()\n", Name())); 4686 4687 return true; 4688 } 4689 4690 4691 void 4692 BView::_RemoveLayoutItemsFromLayout(bool deleteItems) 4693 { 4694 if (fParent == NULL || fParent->fLayoutData->fLayout == NULL) 4695 return; 4696 4697 int32 index = fLayoutData->fLayoutItems.CountItems(); 4698 while (index-- > 0) { 4699 BLayoutItem* item = fLayoutData->fLayoutItems.ItemAt(index); 4700 item->RemoveSelf(); 4701 // Removes item from fLayoutItems list 4702 if (deleteItems) 4703 delete item; 4704 } 4705 } 4706 4707 4708 BView* 4709 BView::Parent() const 4710 { 4711 if (fParent && fParent->fTopLevelView) 4712 return NULL; 4713 4714 return fParent; 4715 } 4716 4717 4718 BView* 4719 BView::FindView(const char* name) const 4720 { 4721 if (name == NULL) 4722 return NULL; 4723 4724 if (Name() != NULL && !strcmp(Name(), name)) 4725 return const_cast<BView*>(this); 4726 4727 BView* child = fFirstChild; 4728 while (child != NULL) { 4729 BView* view = child->FindView(name); 4730 if (view != NULL) 4731 return view; 4732 4733 child = child->fNextSibling; 4734 } 4735 4736 return NULL; 4737 } 4738 4739 4740 void 4741 BView::MoveBy(float deltaX, float deltaY) 4742 { 4743 MoveTo(fParentOffset.x + roundf(deltaX), fParentOffset.y + roundf(deltaY)); 4744 } 4745 4746 4747 void 4748 BView::MoveTo(BPoint where) 4749 { 4750 MoveTo(where.x, where.y); 4751 } 4752 4753 4754 void 4755 BView::MoveTo(float x, float y) 4756 { 4757 if (x == fParentOffset.x && y == fParentOffset.y) 4758 return; 4759 4760 // BeBook says we should do this. And it makes sense. 4761 x = roundf(x); 4762 y = roundf(y); 4763 4764 if (fOwner) { 4765 _CheckLockAndSwitchCurrent(); 4766 fOwner->fLink->StartMessage(AS_VIEW_MOVE_TO); 4767 fOwner->fLink->Attach<float>(x); 4768 fOwner->fLink->Attach<float>(y); 4769 4770 // fState->valid_flags |= B_VIEW_FRAME_BIT; 4771 4772 _FlushIfNotInTransaction(); 4773 } 4774 4775 _MoveTo((int32)x, (int32)y); 4776 } 4777 4778 4779 void 4780 BView::ResizeBy(float deltaWidth, float deltaHeight) 4781 { 4782 // BeBook says we should do this. And it makes sense. 4783 deltaWidth = roundf(deltaWidth); 4784 deltaHeight = roundf(deltaHeight); 4785 4786 if (deltaWidth == 0 && deltaHeight == 0) 4787 return; 4788 4789 if (fOwner) { 4790 _CheckLockAndSwitchCurrent(); 4791 fOwner->fLink->StartMessage(AS_VIEW_RESIZE_TO); 4792 4793 fOwner->fLink->Attach<float>(fBounds.Width() + deltaWidth); 4794 fOwner->fLink->Attach<float>(fBounds.Height() + deltaHeight); 4795 4796 // fState->valid_flags |= B_VIEW_FRAME_BIT; 4797 4798 _FlushIfNotInTransaction(); 4799 } 4800 4801 _ResizeBy((int32)deltaWidth, (int32)deltaHeight); 4802 } 4803 4804 4805 void 4806 BView::ResizeTo(float width, float height) 4807 { 4808 ResizeBy(width - fBounds.Width(), height - fBounds.Height()); 4809 } 4810 4811 4812 void 4813 BView::ResizeTo(BSize size) 4814 { 4815 ResizeBy(size.width - fBounds.Width(), size.height - fBounds.Height()); 4816 } 4817 4818 4819 // #pragma mark - Inherited Methods (from BHandler) 4820 4821 4822 status_t 4823 BView::GetSupportedSuites(BMessage* data) 4824 { 4825 if (data == NULL) 4826 return B_BAD_VALUE; 4827 4828 status_t status = data->AddString("suites", "suite/vnd.Be-view"); 4829 BPropertyInfo propertyInfo(sViewPropInfo); 4830 if (status == B_OK) 4831 status = data->AddFlat("messages", &propertyInfo); 4832 if (status == B_OK) 4833 return BHandler::GetSupportedSuites(data); 4834 return status; 4835 } 4836 4837 4838 BHandler* 4839 BView::ResolveSpecifier(BMessage* message, int32 index, BMessage* specifier, 4840 int32 what, const char* property) 4841 { 4842 if (message->what == B_WINDOW_MOVE_BY 4843 || message->what == B_WINDOW_MOVE_TO) { 4844 return this; 4845 } 4846 4847 BPropertyInfo propertyInfo(sViewPropInfo); 4848 status_t err = B_BAD_SCRIPT_SYNTAX; 4849 BMessage replyMsg(B_REPLY); 4850 4851 switch (propertyInfo.FindMatch(message, index, specifier, what, property)) { 4852 case 0: 4853 case 1: 4854 case 3: 4855 return this; 4856 4857 case 2: 4858 if (fShelf) { 4859 message->PopSpecifier(); 4860 return fShelf; 4861 } 4862 4863 err = B_NAME_NOT_FOUND; 4864 replyMsg.AddString("message", "This window doesn't have a shelf"); 4865 break; 4866 4867 case 4: 4868 { 4869 if (!fFirstChild) { 4870 err = B_NAME_NOT_FOUND; 4871 replyMsg.AddString("message", "This window doesn't have " 4872 "children."); 4873 break; 4874 } 4875 BView* child = NULL; 4876 switch (what) { 4877 case B_INDEX_SPECIFIER: 4878 { 4879 int32 index; 4880 err = specifier->FindInt32("index", &index); 4881 if (err == B_OK) 4882 child = ChildAt(index); 4883 break; 4884 } 4885 case B_REVERSE_INDEX_SPECIFIER: 4886 { 4887 int32 rindex; 4888 err = specifier->FindInt32("index", &rindex); 4889 if (err == B_OK) 4890 child = ChildAt(CountChildren() - rindex); 4891 break; 4892 } 4893 case B_NAME_SPECIFIER: 4894 { 4895 const char* name; 4896 err = specifier->FindString("name", &name); 4897 if (err == B_OK) 4898 child = FindView(name); 4899 break; 4900 } 4901 } 4902 4903 if (child != NULL) { 4904 message->PopSpecifier(); 4905 return child; 4906 } 4907 4908 if (err == B_OK) 4909 err = B_BAD_INDEX; 4910 4911 replyMsg.AddString("message", 4912 "Cannot find view at/with specified index/name."); 4913 break; 4914 } 4915 4916 default: 4917 return BHandler::ResolveSpecifier(message, index, specifier, what, 4918 property); 4919 } 4920 4921 if (err < B_OK) { 4922 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD; 4923 4924 if (err == B_BAD_SCRIPT_SYNTAX) 4925 replyMsg.AddString("message", "Didn't understand the specifier(s)"); 4926 else 4927 replyMsg.AddString("message", strerror(err)); 4928 } 4929 4930 replyMsg.AddInt32("error", err); 4931 message->SendReply(&replyMsg); 4932 return NULL; 4933 } 4934 4935 4936 void 4937 BView::MessageReceived(BMessage* message) 4938 { 4939 if (!message->HasSpecifiers()) { 4940 switch (message->what) { 4941 case B_INVALIDATE: 4942 { 4943 BRect rect; 4944 if (message->FindRect("be:area", &rect) == B_OK) 4945 Invalidate(rect); 4946 else 4947 Invalidate(); 4948 break; 4949 } 4950 4951 case B_KEY_DOWN: 4952 { 4953 // TODO: cannot use "string" here if we support having different 4954 // font encoding per view (it's supposed to be converted by 4955 // BWindow::_HandleKeyDown() one day) 4956 const char* string; 4957 ssize_t bytes; 4958 if (message->FindData("bytes", B_STRING_TYPE, 4959 (const void**)&string, &bytes) == B_OK) 4960 KeyDown(string, bytes - 1); 4961 break; 4962 } 4963 4964 case B_KEY_UP: 4965 { 4966 // TODO: same as above 4967 const char* string; 4968 ssize_t bytes; 4969 if (message->FindData("bytes", B_STRING_TYPE, 4970 (const void**)&string, &bytes) == B_OK) 4971 KeyUp(string, bytes - 1); 4972 break; 4973 } 4974 4975 case B_VIEW_RESIZED: 4976 FrameResized(message->GetInt32("width", 0), 4977 message->GetInt32("height", 0)); 4978 break; 4979 4980 case B_VIEW_MOVED: 4981 FrameMoved(fParentOffset); 4982 break; 4983 4984 case B_MOUSE_DOWN: 4985 { 4986 BPoint where; 4987 message->FindPoint("be:view_where", &where); 4988 MouseDown(where); 4989 break; 4990 } 4991 4992 case B_MOUSE_IDLE: 4993 { 4994 BPoint where; 4995 if (message->FindPoint("be:view_where", &where) != B_OK) 4996 break; 4997 4998 BToolTip* tip; 4999 if (GetToolTipAt(where, &tip)) 5000 ShowToolTip(tip); 5001 else 5002 BHandler::MessageReceived(message); 5003 break; 5004 } 5005 5006 case B_MOUSE_MOVED: 5007 { 5008 uint32 eventOptions = fEventOptions | fMouseEventOptions; 5009 bool noHistory = eventOptions & B_NO_POINTER_HISTORY; 5010 bool dropIfLate = !(eventOptions & B_FULL_POINTER_HISTORY); 5011 5012 bigtime_t eventTime; 5013 if (message->FindInt64("when", (int64*)&eventTime) < B_OK) 5014 eventTime = system_time(); 5015 5016 uint32 transit; 5017 message->FindInt32("be:transit", (int32*)&transit); 5018 // don't drop late messages with these important transit values 5019 if (transit == B_ENTERED_VIEW || transit == B_EXITED_VIEW) 5020 dropIfLate = false; 5021 5022 // TODO: The dropping code may have the following problem: On 5023 // slower computers, 20ms may just be to abitious a delay. 5024 // There, we might constantly check the message queue for a 5025 // newer message, not find any, and still use the only but later 5026 // than 20ms message, which of course makes the whole thing 5027 // later than need be. An adaptive delay would be kind of neat, 5028 // but would probably use additional BWindow members to count 5029 // the successful versus fruitless queue searches and the delay 5030 // value itself or something similar. 5031 if (noHistory 5032 || (dropIfLate && (system_time() - eventTime > 20000))) { 5033 // filter out older mouse moved messages in the queue 5034 BWindow* window = Window(); 5035 window->_DequeueAll(); 5036 BMessageQueue* queue = window->MessageQueue(); 5037 queue->Lock(); 5038 5039 BMessage* moved; 5040 for (int32 i = 0; (moved = queue->FindMessage(i)) != NULL; 5041 i++) { 5042 if (moved != message && moved->what == B_MOUSE_MOVED) { 5043 // there is a newer mouse moved message in the 5044 // queue, just ignore the current one, the newer one 5045 // will be handled here eventually 5046 queue->Unlock(); 5047 return; 5048 } 5049 } 5050 queue->Unlock(); 5051 } 5052 5053 BPoint where; 5054 uint32 buttons; 5055 message->FindPoint("be:view_where", &where); 5056 message->FindInt32("buttons", (int32*)&buttons); 5057 5058 if (transit == B_EXITED_VIEW || transit == B_OUTSIDE_VIEW) 5059 HideToolTip(); 5060 5061 BMessage* dragMessage = NULL; 5062 if (message->HasMessage("be:drag_message")) { 5063 dragMessage = new BMessage(); 5064 if (message->FindMessage("be:drag_message", dragMessage) 5065 != B_OK) { 5066 delete dragMessage; 5067 dragMessage = NULL; 5068 } 5069 } 5070 5071 MouseMoved(where, transit, dragMessage); 5072 delete dragMessage; 5073 break; 5074 } 5075 5076 case B_MOUSE_UP: 5077 { 5078 BPoint where; 5079 message->FindPoint("be:view_where", &where); 5080 fMouseEventOptions = 0; 5081 MouseUp(where); 5082 break; 5083 } 5084 5085 case B_MOUSE_WHEEL_CHANGED: 5086 { 5087 BScrollBar* horizontal = ScrollBar(B_HORIZONTAL); 5088 BScrollBar* vertical = ScrollBar(B_VERTICAL); 5089 if (horizontal == NULL && vertical == NULL) { 5090 // Pass the message to the next handler 5091 BHandler::MessageReceived(message); 5092 break; 5093 } 5094 5095 float deltaX = 0.0f; 5096 float deltaY = 0.0f; 5097 5098 if (horizontal != NULL) 5099 message->FindFloat("be:wheel_delta_x", &deltaX); 5100 5101 if (vertical != NULL) 5102 message->FindFloat("be:wheel_delta_y", &deltaY); 5103 5104 if (deltaX == 0.0f && deltaY == 0.0f) 5105 break; 5106 5107 if ((modifiers() & B_CONTROL_KEY) != 0) 5108 std::swap(horizontal, vertical); 5109 5110 if (horizontal != NULL && deltaX != 0.0f) 5111 ScrollWithMouseWheelDelta(horizontal, deltaX); 5112 5113 if (vertical != NULL && deltaY != 0.0f) 5114 ScrollWithMouseWheelDelta(vertical, deltaY); 5115 5116 break; 5117 } 5118 5119 // prevent message repeats 5120 case B_COLORS_UPDATED: 5121 case B_FONTS_UPDATED: 5122 break; 5123 5124 case B_SCREEN_CHANGED: 5125 case B_WORKSPACE_ACTIVATED: 5126 case B_WORKSPACES_CHANGED: 5127 { 5128 BWindow* window = Window(); 5129 if (window == NULL) 5130 break; 5131 5132 // propagate message to child views 5133 int32 childCount = CountChildren(); 5134 for (int32 i = 0; i < childCount; i++) { 5135 BView* view = ChildAt(i); 5136 if (view != NULL) 5137 window->PostMessage(message, view); 5138 } 5139 break; 5140 } 5141 5142 default: 5143 BHandler::MessageReceived(message); 5144 break; 5145 } 5146 5147 return; 5148 } 5149 5150 // Scripting message 5151 5152 BMessage replyMsg(B_REPLY); 5153 status_t err = B_BAD_SCRIPT_SYNTAX; 5154 int32 index; 5155 BMessage specifier; 5156 int32 what; 5157 const char* property; 5158 5159 if (message->GetCurrentSpecifier(&index, &specifier, &what, &property) 5160 != B_OK) { 5161 return BHandler::MessageReceived(message); 5162 } 5163 5164 BPropertyInfo propertyInfo(sViewPropInfo); 5165 switch (propertyInfo.FindMatch(message, index, &specifier, what, 5166 property)) { 5167 case 0: 5168 if (message->what == B_GET_PROPERTY) { 5169 err = replyMsg.AddRect("result", Frame()); 5170 } else if (message->what == B_SET_PROPERTY) { 5171 BRect newFrame; 5172 err = message->FindRect("data", &newFrame); 5173 if (err == B_OK) { 5174 MoveTo(newFrame.LeftTop()); 5175 ResizeTo(newFrame.Width(), newFrame.Height()); 5176 } 5177 } 5178 break; 5179 case 1: 5180 if (message->what == B_GET_PROPERTY) { 5181 err = replyMsg.AddBool("result", IsHidden()); 5182 } else if (message->what == B_SET_PROPERTY) { 5183 bool newHiddenState; 5184 err = message->FindBool("data", &newHiddenState); 5185 if (err == B_OK) { 5186 if (newHiddenState == true) 5187 Hide(); 5188 else 5189 Show(); 5190 } 5191 } 5192 break; 5193 case 3: 5194 err = replyMsg.AddInt32("result", CountChildren()); 5195 break; 5196 default: 5197 return BHandler::MessageReceived(message); 5198 } 5199 5200 if (err != B_OK) { 5201 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD; 5202 5203 if (err == B_BAD_SCRIPT_SYNTAX) 5204 replyMsg.AddString("message", "Didn't understand the specifier(s)"); 5205 else 5206 replyMsg.AddString("message", strerror(err)); 5207 5208 replyMsg.AddInt32("error", err); 5209 } 5210 5211 message->SendReply(&replyMsg); 5212 } 5213 5214 5215 status_t 5216 BView::Perform(perform_code code, void* _data) 5217 { 5218 switch (code) { 5219 case PERFORM_CODE_MIN_SIZE: 5220 ((perform_data_min_size*)_data)->return_value 5221 = BView::MinSize(); 5222 return B_OK; 5223 case PERFORM_CODE_MAX_SIZE: 5224 ((perform_data_max_size*)_data)->return_value 5225 = BView::MaxSize(); 5226 return B_OK; 5227 case PERFORM_CODE_PREFERRED_SIZE: 5228 ((perform_data_preferred_size*)_data)->return_value 5229 = BView::PreferredSize(); 5230 return B_OK; 5231 case PERFORM_CODE_LAYOUT_ALIGNMENT: 5232 ((perform_data_layout_alignment*)_data)->return_value 5233 = BView::LayoutAlignment(); 5234 return B_OK; 5235 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH: 5236 ((perform_data_has_height_for_width*)_data)->return_value 5237 = BView::HasHeightForWidth(); 5238 return B_OK; 5239 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH: 5240 { 5241 perform_data_get_height_for_width* data 5242 = (perform_data_get_height_for_width*)_data; 5243 BView::GetHeightForWidth(data->width, &data->min, &data->max, 5244 &data->preferred); 5245 return B_OK; 5246 } 5247 case PERFORM_CODE_SET_LAYOUT: 5248 { 5249 perform_data_set_layout* data = (perform_data_set_layout*)_data; 5250 BView::SetLayout(data->layout); 5251 return B_OK; 5252 } 5253 case PERFORM_CODE_LAYOUT_INVALIDATED: 5254 { 5255 perform_data_layout_invalidated* data 5256 = (perform_data_layout_invalidated*)_data; 5257 BView::LayoutInvalidated(data->descendants); 5258 return B_OK; 5259 } 5260 case PERFORM_CODE_DO_LAYOUT: 5261 { 5262 BView::DoLayout(); 5263 return B_OK; 5264 } 5265 case PERFORM_CODE_LAYOUT_CHANGED: 5266 { 5267 BView::LayoutChanged(); 5268 return B_OK; 5269 } 5270 case PERFORM_CODE_GET_TOOL_TIP_AT: 5271 { 5272 perform_data_get_tool_tip_at* data 5273 = (perform_data_get_tool_tip_at*)_data; 5274 data->return_value 5275 = BView::GetToolTipAt(data->point, data->tool_tip); 5276 return B_OK; 5277 } 5278 case PERFORM_CODE_ALL_UNARCHIVED: 5279 { 5280 perform_data_all_unarchived* data = 5281 (perform_data_all_unarchived*)_data; 5282 5283 data->return_value = BView::AllUnarchived(data->archive); 5284 return B_OK; 5285 } 5286 case PERFORM_CODE_ALL_ARCHIVED: 5287 { 5288 perform_data_all_archived* data = 5289 (perform_data_all_archived*)_data; 5290 5291 data->return_value = BView::AllArchived(data->archive); 5292 return B_OK; 5293 } 5294 } 5295 5296 return BHandler::Perform(code, _data); 5297 } 5298 5299 5300 // #pragma mark - Layout Functions 5301 5302 5303 BSize 5304 BView::MinSize() 5305 { 5306 // TODO: make sure this works correctly when some methods are overridden 5307 float width, height; 5308 GetPreferredSize(&width, &height); 5309 5310 return BLayoutUtils::ComposeSize(fLayoutData->fMinSize, 5311 (fLayoutData->fLayout ? fLayoutData->fLayout->MinSize() 5312 : BSize(width, height))); 5313 } 5314 5315 5316 BSize 5317 BView::MaxSize() 5318 { 5319 return BLayoutUtils::ComposeSize(fLayoutData->fMaxSize, 5320 (fLayoutData->fLayout ? fLayoutData->fLayout->MaxSize() 5321 : BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED))); 5322 } 5323 5324 5325 BSize 5326 BView::PreferredSize() 5327 { 5328 // TODO: make sure this works correctly when some methods are overridden 5329 float width, height; 5330 GetPreferredSize(&width, &height); 5331 5332 return BLayoutUtils::ComposeSize(fLayoutData->fPreferredSize, 5333 (fLayoutData->fLayout ? fLayoutData->fLayout->PreferredSize() 5334 : BSize(width, height))); 5335 } 5336 5337 5338 BAlignment 5339 BView::LayoutAlignment() 5340 { 5341 return BLayoutUtils::ComposeAlignment(fLayoutData->fAlignment, 5342 (fLayoutData->fLayout ? fLayoutData->fLayout->Alignment() 5343 : BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER))); 5344 } 5345 5346 5347 void 5348 BView::SetExplicitMinSize(BSize size) 5349 { 5350 fLayoutData->fMinSize = size; 5351 InvalidateLayout(); 5352 } 5353 5354 5355 void 5356 BView::SetExplicitMaxSize(BSize size) 5357 { 5358 fLayoutData->fMaxSize = size; 5359 InvalidateLayout(); 5360 } 5361 5362 5363 void 5364 BView::SetExplicitPreferredSize(BSize size) 5365 { 5366 fLayoutData->fPreferredSize = size; 5367 InvalidateLayout(); 5368 } 5369 5370 5371 void 5372 BView::SetExplicitSize(BSize size) 5373 { 5374 fLayoutData->fMinSize = size; 5375 fLayoutData->fMaxSize = size; 5376 fLayoutData->fPreferredSize = size; 5377 InvalidateLayout(); 5378 } 5379 5380 5381 void 5382 BView::SetExplicitAlignment(BAlignment alignment) 5383 { 5384 fLayoutData->fAlignment = alignment; 5385 InvalidateLayout(); 5386 } 5387 5388 5389 BSize 5390 BView::ExplicitMinSize() const 5391 { 5392 return fLayoutData->fMinSize; 5393 } 5394 5395 5396 BSize 5397 BView::ExplicitMaxSize() const 5398 { 5399 return fLayoutData->fMaxSize; 5400 } 5401 5402 5403 BSize 5404 BView::ExplicitPreferredSize() const 5405 { 5406 return fLayoutData->fPreferredSize; 5407 } 5408 5409 5410 BAlignment 5411 BView::ExplicitAlignment() const 5412 { 5413 return fLayoutData->fAlignment; 5414 } 5415 5416 5417 bool 5418 BView::HasHeightForWidth() 5419 { 5420 return (fLayoutData->fLayout 5421 ? fLayoutData->fLayout->HasHeightForWidth() : false); 5422 } 5423 5424 5425 void 5426 BView::GetHeightForWidth(float width, float* min, float* max, float* preferred) 5427 { 5428 if (fLayoutData->fLayout) 5429 fLayoutData->fLayout->GetHeightForWidth(width, min, max, preferred); 5430 } 5431 5432 5433 void 5434 BView::SetLayout(BLayout* layout) 5435 { 5436 if (layout == fLayoutData->fLayout) 5437 return; 5438 5439 if (layout && layout->Layout()) 5440 debugger("BView::SetLayout() failed, layout is already in use."); 5441 5442 fFlags |= B_SUPPORTS_LAYOUT; 5443 5444 // unset and delete the old layout 5445 if (fLayoutData->fLayout) { 5446 fLayoutData->fLayout->RemoveSelf(); 5447 fLayoutData->fLayout->SetOwner(NULL); 5448 delete fLayoutData->fLayout; 5449 } 5450 5451 fLayoutData->fLayout = layout; 5452 5453 if (fLayoutData->fLayout) { 5454 fLayoutData->fLayout->SetOwner(this); 5455 5456 // add all children 5457 int count = CountChildren(); 5458 for (int i = 0; i < count; i++) 5459 fLayoutData->fLayout->AddView(ChildAt(i)); 5460 } 5461 5462 InvalidateLayout(); 5463 } 5464 5465 5466 BLayout* 5467 BView::GetLayout() const 5468 { 5469 return fLayoutData->fLayout; 5470 } 5471 5472 5473 void 5474 BView::InvalidateLayout(bool descendants) 5475 { 5476 // printf("BView(%p)::InvalidateLayout(%i), valid: %i, inProgress: %i\n", 5477 // this, descendants, fLayoutData->fLayoutValid, 5478 // fLayoutData->fLayoutInProgress); 5479 5480 if (!fLayoutData->fMinMaxValid || fLayoutData->fLayoutInProgress 5481 || fLayoutData->fLayoutInvalidationDisabled > 0) { 5482 return; 5483 } 5484 fLayoutData->fLayoutValid = false; 5485 fLayoutData->fMinMaxValid = false; 5486 LayoutInvalidated(descendants); 5487 5488 if (descendants) { 5489 for (BView* child = fFirstChild; 5490 child; child = child->fNextSibling) { 5491 child->InvalidateLayout(descendants); 5492 } 5493 } 5494 5495 if (fLayoutData->fLayout) 5496 fLayoutData->fLayout->InvalidateLayout(descendants); 5497 else 5498 _InvalidateParentLayout(); 5499 5500 if (fTopLevelView 5501 && fOwner != NULL) 5502 fOwner->PostMessage(B_LAYOUT_WINDOW); 5503 } 5504 5505 5506 void 5507 BView::EnableLayoutInvalidation() 5508 { 5509 if (fLayoutData->fLayoutInvalidationDisabled > 0) 5510 fLayoutData->fLayoutInvalidationDisabled--; 5511 } 5512 5513 5514 void 5515 BView::DisableLayoutInvalidation() 5516 { 5517 fLayoutData->fLayoutInvalidationDisabled++; 5518 } 5519 5520 5521 bool 5522 BView::IsLayoutInvalidationDisabled() 5523 { 5524 if (fLayoutData->fLayoutInvalidationDisabled > 0) 5525 return true; 5526 return false; 5527 } 5528 5529 5530 bool 5531 BView::IsLayoutValid() const 5532 { 5533 return fLayoutData->fLayoutValid; 5534 } 5535 5536 5537 void 5538 BView::ResetLayoutInvalidation() 5539 { 5540 fLayoutData->fMinMaxValid = true; 5541 } 5542 5543 5544 BLayoutContext* 5545 BView::LayoutContext() const 5546 { 5547 return fLayoutData->fLayoutContext; 5548 } 5549 5550 5551 void 5552 BView::Layout(bool force) 5553 { 5554 BLayoutContext context; 5555 _Layout(force, &context); 5556 } 5557 5558 5559 void 5560 BView::Relayout() 5561 { 5562 if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) { 5563 fLayoutData->fNeedsRelayout = true; 5564 if (fLayoutData->fLayout) 5565 fLayoutData->fLayout->RequireLayout(); 5566 5567 // Layout() is recursive, that is if the parent view is currently laid 5568 // out, we don't call layout() on this view, but wait for the parent's 5569 // Layout() to do that for us. 5570 if (!fParent || !fParent->fLayoutData->fLayoutInProgress) 5571 Layout(false); 5572 } 5573 } 5574 5575 5576 void 5577 BView::LayoutInvalidated(bool descendants) 5578 { 5579 // hook method 5580 } 5581 5582 5583 void 5584 BView::DoLayout() 5585 { 5586 if (fLayoutData->fLayout) 5587 fLayoutData->fLayout->_LayoutWithinContext(false, LayoutContext()); 5588 } 5589 5590 5591 void 5592 BView::SetToolTip(const char* text) 5593 { 5594 if (text == NULL || text[0] == '\0') { 5595 SetToolTip((BToolTip*)NULL); 5596 return; 5597 } 5598 5599 if (BTextToolTip* tip = dynamic_cast<BTextToolTip*>(fToolTip)) 5600 tip->SetText(text); 5601 else 5602 SetToolTip(new BTextToolTip(text)); 5603 } 5604 5605 5606 void 5607 BView::SetToolTip(BToolTip* tip) 5608 { 5609 if (fToolTip == tip) 5610 return; 5611 else if (tip == NULL) 5612 HideToolTip(); 5613 5614 if (fToolTip != NULL) 5615 fToolTip->ReleaseReference(); 5616 5617 fToolTip = tip; 5618 5619 if (fToolTip != NULL) 5620 fToolTip->AcquireReference(); 5621 } 5622 5623 5624 BToolTip* 5625 BView::ToolTip() const 5626 { 5627 return fToolTip; 5628 } 5629 5630 5631 void 5632 BView::ShowToolTip(BToolTip* tip) 5633 { 5634 if (tip == NULL) 5635 return; 5636 5637 BPoint where; 5638 GetMouse(&where, NULL, false); 5639 5640 BToolTipManager::Manager()->ShowTip(tip, ConvertToScreen(where), this); 5641 } 5642 5643 5644 void 5645 BView::HideToolTip() 5646 { 5647 BToolTipManager::Manager()->HideTip(); 5648 } 5649 5650 5651 bool 5652 BView::GetToolTipAt(BPoint point, BToolTip** _tip) 5653 { 5654 if (fToolTip != NULL) { 5655 *_tip = fToolTip; 5656 return true; 5657 } 5658 5659 *_tip = NULL; 5660 return false; 5661 } 5662 5663 5664 void 5665 BView::LayoutChanged() 5666 { 5667 // hook method 5668 } 5669 5670 5671 void 5672 BView::_Layout(bool force, BLayoutContext* context) 5673 { 5674 //printf("%p->BView::_Layout(%d, %p)\n", this, force, context); 5675 //printf(" fNeedsRelayout: %d, fLayoutValid: %d, fLayoutInProgress: %d\n", 5676 //fLayoutData->fNeedsRelayout, fLayoutData->fLayoutValid, 5677 //fLayoutData->fLayoutInProgress); 5678 if (fLayoutData->fNeedsRelayout || !fLayoutData->fLayoutValid || force) { 5679 fLayoutData->fLayoutValid = false; 5680 5681 if (fLayoutData->fLayoutInProgress) 5682 return; 5683 5684 BLayoutContext* oldContext = fLayoutData->fLayoutContext; 5685 fLayoutData->fLayoutContext = context; 5686 5687 fLayoutData->fLayoutInProgress = true; 5688 DoLayout(); 5689 fLayoutData->fLayoutInProgress = false; 5690 5691 fLayoutData->fLayoutValid = true; 5692 fLayoutData->fMinMaxValid = true; 5693 fLayoutData->fNeedsRelayout = false; 5694 5695 // layout children 5696 for(BView* child = fFirstChild; child; child = child->fNextSibling) { 5697 if (!child->IsHidden(child)) 5698 child->_Layout(force, context); 5699 } 5700 5701 LayoutChanged(); 5702 5703 fLayoutData->fLayoutContext = oldContext; 5704 5705 // invalidate the drawn content, if requested 5706 if (fFlags & B_INVALIDATE_AFTER_LAYOUT) 5707 Invalidate(); 5708 } 5709 } 5710 5711 5712 void 5713 BView::_LayoutLeft(BLayout* deleted) 5714 { 5715 // If our layout is added to another layout (via BLayout::AddItem()) 5716 // then we share ownership of our layout. In the event that our layout gets 5717 // deleted by the layout it has been added to, this method is called so 5718 // that we don't double-delete our layout. 5719 if (fLayoutData->fLayout == deleted) 5720 fLayoutData->fLayout = NULL; 5721 InvalidateLayout(); 5722 } 5723 5724 5725 void 5726 BView::_InvalidateParentLayout() 5727 { 5728 if (!fParent) 5729 return; 5730 5731 BLayout* layout = fLayoutData->fLayout; 5732 BLayout* layoutParent = layout ? layout->Layout() : NULL; 5733 if (layoutParent) { 5734 layoutParent->InvalidateLayout(); 5735 } else if (fLayoutData->fLayoutItems.CountItems() > 0) { 5736 int32 count = fLayoutData->fLayoutItems.CountItems(); 5737 for (int32 i = 0; i < count; i++) { 5738 fLayoutData->fLayoutItems.ItemAt(i)->Layout()->InvalidateLayout(); 5739 } 5740 } else { 5741 fParent->InvalidateLayout(); 5742 } 5743 } 5744 5745 5746 // #pragma mark - Private Functions 5747 5748 5749 void 5750 BView::_InitData(BRect frame, const char* name, uint32 resizingMode, 5751 uint32 flags) 5752 { 5753 // Info: The name of the view is set by BHandler constructor 5754 5755 STRACE(("BView::_InitData: enter\n")); 5756 5757 // initialize members 5758 if ((resizingMode & ~_RESIZE_MASK_) || (flags & _RESIZE_MASK_)) 5759 printf("%s BView::_InitData(): resizing mode or flags swapped\n", name); 5760 5761 // There are applications that swap the resize mask and the flags in the 5762 // BView constructor. This does not cause problems under BeOS as it just 5763 // ors the two fields to one 32bit flag. 5764 // For now we do the same but print the above warning message. 5765 // TODO: this should be removed at some point and the original 5766 // version restored: 5767 // fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_); 5768 fFlags = resizingMode | flags; 5769 5770 // handle rounding 5771 frame.left = roundf(frame.left); 5772 frame.top = roundf(frame.top); 5773 frame.right = roundf(frame.right); 5774 frame.bottom = roundf(frame.bottom); 5775 5776 fParentOffset.Set(frame.left, frame.top); 5777 5778 fOwner = NULL; 5779 fParent = NULL; 5780 fNextSibling = NULL; 5781 fPreviousSibling = NULL; 5782 fFirstChild = NULL; 5783 5784 fShowLevel = 0; 5785 fTopLevelView = false; 5786 5787 fCurrentPicture = NULL; 5788 fCommArray = NULL; 5789 5790 fVerScroller = NULL; 5791 fHorScroller = NULL; 5792 5793 fIsPrinting = false; 5794 fAttached = false; 5795 5796 // TODO: Since we cannot communicate failure, we don't use std::nothrow here 5797 // TODO: Maybe we could auto-delete those views on AddChild() instead? 5798 fState = new BPrivate::ViewState; 5799 5800 fBounds = frame.OffsetToCopy(B_ORIGIN); 5801 fShelf = NULL; 5802 5803 fEventMask = 0; 5804 fEventOptions = 0; 5805 fMouseEventOptions = 0; 5806 5807 fLayoutData = new LayoutData; 5808 5809 fToolTip = NULL; 5810 5811 if ((flags & B_SUPPORTS_LAYOUT) != 0) { 5812 SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 5813 SetLowUIColor(ViewUIColor()); 5814 SetHighUIColor(B_PANEL_TEXT_COLOR); 5815 } 5816 } 5817 5818 5819 void 5820 BView::_RemoveCommArray() 5821 { 5822 if (fCommArray) { 5823 delete [] fCommArray->array; 5824 delete fCommArray; 5825 fCommArray = NULL; 5826 } 5827 } 5828 5829 5830 void 5831 BView::_SetOwner(BWindow* newOwner) 5832 { 5833 if (!newOwner) 5834 _RemoveCommArray(); 5835 5836 if (fOwner != newOwner && fOwner) { 5837 if (fOwner->fFocus == this) 5838 MakeFocus(false); 5839 5840 if (fOwner->fLastMouseMovedView == this) 5841 fOwner->fLastMouseMovedView = NULL; 5842 5843 fOwner->RemoveHandler(this); 5844 if (fShelf) 5845 fOwner->RemoveHandler(fShelf); 5846 } 5847 5848 if (newOwner && newOwner != fOwner) { 5849 newOwner->AddHandler(this); 5850 if (fShelf) 5851 newOwner->AddHandler(fShelf); 5852 5853 if (fTopLevelView) 5854 SetNextHandler(newOwner); 5855 else 5856 SetNextHandler(fParent); 5857 } 5858 5859 fOwner = newOwner; 5860 5861 for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling) 5862 child->_SetOwner(newOwner); 5863 } 5864 5865 5866 void 5867 BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync) 5868 { 5869 if (!_CheckOwnerLockAndSwitchCurrent()) 5870 return; 5871 5872 if (picture == NULL) { 5873 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE); 5874 fOwner->fLink->Attach<int32>(-1); 5875 5876 // NOTE: No need to sync here, since the -1 token cannot 5877 // become invalid on the server. 5878 } else { 5879 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE); 5880 fOwner->fLink->Attach<int32>(picture->Token()); 5881 fOwner->fLink->Attach<BPoint>(where); 5882 fOwner->fLink->Attach<bool>(invert); 5883 5884 // NOTE: "sync" defaults to true in public methods. If you know what 5885 // you are doing, i.e. if you know your BPicture stays valid, you 5886 // can avoid the performance impact of syncing. In a use-case where 5887 // the client creates BPictures on the stack, these BPictures may 5888 // have issued a AS_DELETE_PICTURE command to the ServerApp when Draw() 5889 // goes out of scope, and the command is processed earlier in the 5890 // ServerApp thread than the AS_VIEW_CLIP_TO_PICTURE command in the 5891 // ServerWindow thread, which will then have the result that no 5892 // ServerPicture is found of the token. 5893 if (sync) 5894 Sync(); 5895 } 5896 } 5897 5898 5899 void 5900 BView::_ClipToRect(BRect rect, bool inverse) 5901 { 5902 if (_CheckOwnerLockAndSwitchCurrent()) { 5903 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_RECT); 5904 fOwner->fLink->Attach<bool>(inverse); 5905 fOwner->fLink->Attach<BRect>(rect); 5906 _FlushIfNotInTransaction(); 5907 } 5908 } 5909 5910 5911 void 5912 BView::_ClipToShape(BShape* shape, bool inverse) 5913 { 5914 if (shape == NULL) 5915 return; 5916 5917 shape_data* sd = (shape_data*)shape->fPrivateData; 5918 if (sd->opCount == 0 || sd->ptCount == 0) 5919 return; 5920 5921 if (_CheckOwnerLockAndSwitchCurrent()) { 5922 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_SHAPE); 5923 fOwner->fLink->Attach<bool>(inverse); 5924 fOwner->fLink->Attach<int32>(sd->opCount); 5925 fOwner->fLink->Attach<int32>(sd->ptCount); 5926 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(uint32)); 5927 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 5928 _FlushIfNotInTransaction(); 5929 } 5930 } 5931 5932 5933 bool 5934 BView::_RemoveChildFromList(BView* child) 5935 { 5936 if (child->fParent != this) 5937 return false; 5938 5939 if (fFirstChild == child) { 5940 // it's the first view in the list 5941 fFirstChild = child->fNextSibling; 5942 } else { 5943 // there must be a previous sibling 5944 child->fPreviousSibling->fNextSibling = child->fNextSibling; 5945 } 5946 5947 if (child->fNextSibling) 5948 child->fNextSibling->fPreviousSibling = child->fPreviousSibling; 5949 5950 child->fParent = NULL; 5951 child->fNextSibling = NULL; 5952 child->fPreviousSibling = NULL; 5953 5954 return true; 5955 } 5956 5957 5958 bool 5959 BView::_AddChildToList(BView* child, BView* before) 5960 { 5961 if (!child) 5962 return false; 5963 if (child->fParent != NULL) { 5964 debugger("View already belongs to someone else"); 5965 return false; 5966 } 5967 if (before != NULL && before->fParent != this) { 5968 debugger("Invalid before view"); 5969 return false; 5970 } 5971 5972 if (before != NULL) { 5973 // add view before this one 5974 child->fNextSibling = before; 5975 child->fPreviousSibling = before->fPreviousSibling; 5976 if (child->fPreviousSibling != NULL) 5977 child->fPreviousSibling->fNextSibling = child; 5978 5979 before->fPreviousSibling = child; 5980 if (fFirstChild == before) 5981 fFirstChild = child; 5982 } else { 5983 // add view to the end of the list 5984 BView* last = fFirstChild; 5985 while (last != NULL && last->fNextSibling != NULL) { 5986 last = last->fNextSibling; 5987 } 5988 5989 if (last != NULL) { 5990 last->fNextSibling = child; 5991 child->fPreviousSibling = last; 5992 } else { 5993 fFirstChild = child; 5994 child->fPreviousSibling = NULL; 5995 } 5996 5997 child->fNextSibling = NULL; 5998 } 5999 6000 child->fParent = this; 6001 return true; 6002 } 6003 6004 6005 /*! \brief Creates the server counterpart of this view. 6006 This is only done for views that are part of the view hierarchy, ie. when 6007 they are attached to a window. 6008 RemoveSelf() deletes the server object again. 6009 */ 6010 bool 6011 BView::_CreateSelf() 6012 { 6013 // AS_VIEW_CREATE & AS_VIEW_CREATE_ROOT do not use the 6014 // current view mechanism via _CheckLockAndSwitchCurrent() - the token 6015 // of the view and its parent are both send to the server. 6016 6017 if (fTopLevelView) 6018 fOwner->fLink->StartMessage(AS_VIEW_CREATE_ROOT); 6019 else 6020 fOwner->fLink->StartMessage(AS_VIEW_CREATE); 6021 6022 fOwner->fLink->Attach<int32>(_get_object_token_(this)); 6023 fOwner->fLink->AttachString(Name()); 6024 fOwner->fLink->Attach<BRect>(Frame()); 6025 fOwner->fLink->Attach<BPoint>(LeftTop()); 6026 fOwner->fLink->Attach<uint32>(ResizingMode()); 6027 fOwner->fLink->Attach<uint32>(fEventMask); 6028 fOwner->fLink->Attach<uint32>(fEventOptions); 6029 fOwner->fLink->Attach<uint32>(Flags()); 6030 fOwner->fLink->Attach<bool>(IsHidden(this)); 6031 fOwner->fLink->Attach<rgb_color>(fState->view_color); 6032 if (fTopLevelView) 6033 fOwner->fLink->Attach<int32>(B_NULL_TOKEN); 6034 else 6035 fOwner->fLink->Attach<int32>(_get_object_token_(fParent)); 6036 fOwner->fLink->Flush(); 6037 6038 _CheckOwnerLockAndSwitchCurrent(); 6039 fState->UpdateServerState(*fOwner->fLink); 6040 6041 // we create all its children, too 6042 6043 for (BView* child = fFirstChild; child != NULL; 6044 child = child->fNextSibling) { 6045 child->_CreateSelf(); 6046 } 6047 6048 fOwner->fLink->Flush(); 6049 return true; 6050 } 6051 6052 6053 /*! Sets the new view position. 6054 It doesn't contact the server, though - the only case where this 6055 is called outside of MoveTo() is as reaction of moving a view 6056 in the server (a.k.a. B_WINDOW_RESIZED). 6057 It also calls the BView's FrameMoved() hook. 6058 */ 6059 void 6060 BView::_MoveTo(int32 x, int32 y) 6061 { 6062 fParentOffset.Set(x, y); 6063 6064 if (Window() != NULL && fFlags & B_FRAME_EVENTS) { 6065 BMessage moved(B_VIEW_MOVED); 6066 moved.AddInt64("when", system_time()); 6067 moved.AddPoint("where", BPoint(x, y)); 6068 6069 BMessenger target(this); 6070 target.SendMessage(&moved); 6071 } 6072 } 6073 6074 6075 /*! Computes the actual new frame size and recalculates the size of 6076 the children as well. 6077 It doesn't contact the server, though - the only case where this 6078 is called outside of ResizeBy() is as reaction of resizing a view 6079 in the server (a.k.a. B_WINDOW_RESIZED). 6080 It also calls the BView's FrameResized() hook. 6081 */ 6082 void 6083 BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight) 6084 { 6085 fBounds.right += deltaWidth; 6086 fBounds.bottom += deltaHeight; 6087 6088 if (Window() == NULL) { 6089 // we're not supposed to exercise the resizing code in case 6090 // we haven't been attached to a window yet 6091 return; 6092 } 6093 6094 // layout the children 6095 if ((fFlags & B_SUPPORTS_LAYOUT) != 0) { 6096 Relayout(); 6097 } else { 6098 for (BView* child = fFirstChild; child; child = child->fNextSibling) 6099 child->_ParentResizedBy(deltaWidth, deltaHeight); 6100 } 6101 6102 if (fFlags & B_FRAME_EVENTS) { 6103 BMessage resized(B_VIEW_RESIZED); 6104 resized.AddInt64("when", system_time()); 6105 resized.AddInt32("width", fBounds.IntegerWidth()); 6106 resized.AddInt32("height", fBounds.IntegerHeight()); 6107 6108 BMessenger target(this); 6109 target.SendMessage(&resized); 6110 } 6111 } 6112 6113 6114 /*! Relayouts the view according to its resizing mode. */ 6115 void 6116 BView::_ParentResizedBy(int32 x, int32 y) 6117 { 6118 uint32 resizingMode = fFlags & _RESIZE_MASK_; 6119 BRect newFrame = Frame(); 6120 6121 // follow with left side 6122 if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8) 6123 newFrame.left += x; 6124 else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8) 6125 newFrame.left += x / 2; 6126 6127 // follow with right side 6128 if ((resizingMode & 0x000FU) == _VIEW_RIGHT_) 6129 newFrame.right += x; 6130 else if ((resizingMode & 0x000FU) == _VIEW_CENTER_) 6131 newFrame.right += x / 2; 6132 6133 // follow with top side 6134 if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12) 6135 newFrame.top += y; 6136 else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12) 6137 newFrame.top += y / 2; 6138 6139 // follow with bottom side 6140 if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4) 6141 newFrame.bottom += y; 6142 else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4) 6143 newFrame.bottom += y / 2; 6144 6145 if (newFrame.LeftTop() != fParentOffset) { 6146 // move view 6147 _MoveTo((int32)roundf(newFrame.left), (int32)roundf(newFrame.top)); 6148 } 6149 6150 if (newFrame != Frame()) { 6151 // resize view 6152 int32 widthDiff = (int32)(newFrame.Width() - fBounds.Width()); 6153 int32 heightDiff = (int32)(newFrame.Height() - fBounds.Height()); 6154 _ResizeBy(widthDiff, heightDiff); 6155 } 6156 } 6157 6158 6159 void 6160 BView::_Activate(bool active) 6161 { 6162 WindowActivated(active); 6163 6164 for (BView* child = fFirstChild; child != NULL; 6165 child = child->fNextSibling) { 6166 child->_Activate(active); 6167 } 6168 } 6169 6170 6171 void 6172 BView::_Attach() 6173 { 6174 if (fOwner != NULL) { 6175 // unmask state flags to force [re]syncing with the app_server 6176 fState->valid_flags &= ~(B_VIEW_WHICH_VIEW_COLOR_BIT 6177 | B_VIEW_WHICH_LOW_COLOR_BIT | B_VIEW_WHICH_HIGH_COLOR_BIT); 6178 6179 if (fState->which_view_color != B_NO_COLOR) 6180 SetViewUIColor(fState->which_view_color, 6181 fState->which_view_color_tint); 6182 6183 if (fState->which_high_color != B_NO_COLOR) 6184 SetHighUIColor(fState->which_high_color, 6185 fState->which_high_color_tint); 6186 6187 if (fState->which_low_color != B_NO_COLOR) 6188 SetLowUIColor(fState->which_low_color, 6189 fState->which_low_color_tint); 6190 } 6191 6192 AttachedToWindow(); 6193 6194 fAttached = true; 6195 6196 // after giving the view a chance to do this itself, 6197 // check for the B_PULSE_NEEDED flag and make sure the 6198 // window set's up the pulse messaging 6199 if (fOwner) { 6200 if (fFlags & B_PULSE_NEEDED) { 6201 _CheckLock(); 6202 if (fOwner->fPulseRunner == NULL) 6203 fOwner->SetPulseRate(fOwner->PulseRate()); 6204 } 6205 6206 if (!fOwner->IsHidden()) 6207 Invalidate(); 6208 } 6209 6210 for (BView* child = fFirstChild; child != NULL; 6211 child = child->fNextSibling) { 6212 // we need to check for fAttached as new views could have been 6213 // added in AttachedToWindow() - and those are already attached 6214 if (!child->fAttached) 6215 child->_Attach(); 6216 } 6217 6218 AllAttached(); 6219 } 6220 6221 6222 void 6223 BView::_ColorsUpdated(BMessage* message) 6224 { 6225 if (fTopLevelView 6226 && fLayoutData->fLayout != NULL 6227 && !fState->IsValid(B_VIEW_WHICH_VIEW_COLOR_BIT)) { 6228 SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 6229 SetHighUIColor(B_PANEL_TEXT_COLOR); 6230 } 6231 6232 rgb_color color; 6233 6234 const char* colorName = ui_color_name(fState->which_view_color); 6235 if (colorName != NULL && message->FindColor(colorName, &color) == B_OK) { 6236 fState->view_color = tint_color(color, fState->which_view_color_tint); 6237 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT; 6238 } 6239 6240 colorName = ui_color_name(fState->which_low_color); 6241 if (colorName != NULL && message->FindColor(colorName, &color) == B_OK) { 6242 fState->low_color = tint_color(color, fState->which_low_color_tint); 6243 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT; 6244 } 6245 6246 colorName = ui_color_name(fState->which_high_color); 6247 if (colorName != NULL && message->FindColor(colorName, &color) == B_OK) { 6248 fState->high_color = tint_color(color, fState->which_high_color_tint); 6249 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT; 6250 } 6251 6252 MessageReceived(message); 6253 6254 for (BView* child = fFirstChild; child != NULL; 6255 child = child->fNextSibling) 6256 child->_ColorsUpdated(message); 6257 6258 Invalidate(); 6259 } 6260 6261 6262 void 6263 BView::_Detach() 6264 { 6265 DetachedFromWindow(); 6266 fAttached = false; 6267 6268 for (BView* child = fFirstChild; child != NULL; 6269 child = child->fNextSibling) { 6270 child->_Detach(); 6271 } 6272 6273 AllDetached(); 6274 6275 if (fOwner) { 6276 _CheckLock(); 6277 6278 if (!fOwner->IsHidden()) 6279 Invalidate(); 6280 6281 // make sure our owner doesn't need us anymore 6282 6283 if (fOwner->CurrentFocus() == this) { 6284 MakeFocus(false); 6285 // MakeFocus() is virtual and might not be 6286 // passing through to the BView version, 6287 // but we need to make sure at this point 6288 // that we are not the focus view anymore. 6289 if (fOwner->CurrentFocus() == this) 6290 fOwner->_SetFocus(NULL, true); 6291 } 6292 6293 if (fOwner->fDefaultButton == this) 6294 fOwner->SetDefaultButton(NULL); 6295 6296 if (fOwner->fKeyMenuBar == this) 6297 fOwner->fKeyMenuBar = NULL; 6298 6299 if (fOwner->fLastMouseMovedView == this) 6300 fOwner->fLastMouseMovedView = NULL; 6301 6302 if (fOwner->fLastViewToken == _get_object_token_(this)) 6303 fOwner->fLastViewToken = B_NULL_TOKEN; 6304 6305 _SetOwner(NULL); 6306 } 6307 } 6308 6309 6310 void 6311 BView::_Draw(BRect updateRect) 6312 { 6313 if (IsHidden(this) || !(Flags() & B_WILL_DRAW)) 6314 return; 6315 6316 // NOTE: if ViewColor() == B_TRANSPARENT_COLOR and no B_WILL_DRAW 6317 // -> View is simply not drawn at all 6318 6319 _SwitchServerCurrentView(); 6320 6321 ConvertFromScreen(&updateRect); 6322 6323 // TODO: make states robust (the hook implementation could 6324 // mess things up if it uses non-matching Push- and PopState(), 6325 // we would not be guaranteed to still have the same state on 6326 // the stack after having called Draw()) 6327 PushState(); 6328 Draw(updateRect); 6329 PopState(); 6330 Flush(); 6331 } 6332 6333 6334 void 6335 BView::_DrawAfterChildren(BRect updateRect) 6336 { 6337 if (IsHidden(this) || !(Flags() & B_WILL_DRAW) 6338 || !(Flags() & B_DRAW_ON_CHILDREN)) 6339 return; 6340 6341 _SwitchServerCurrentView(); 6342 6343 ConvertFromScreen(&updateRect); 6344 6345 // TODO: make states robust (see above) 6346 PushState(); 6347 DrawAfterChildren(updateRect); 6348 PopState(); 6349 Flush(); 6350 } 6351 6352 6353 void 6354 BView::_FontsUpdated(BMessage* message) 6355 { 6356 MessageReceived(message); 6357 6358 for (BView* child = fFirstChild; child != NULL; 6359 child = child->fNextSibling) { 6360 child->_FontsUpdated(message); 6361 } 6362 } 6363 6364 6365 void 6366 BView::_Pulse() 6367 { 6368 if ((Flags() & B_PULSE_NEEDED) != 0) 6369 Pulse(); 6370 6371 for (BView* child = fFirstChild; child != NULL; 6372 child = child->fNextSibling) { 6373 child->_Pulse(); 6374 } 6375 } 6376 6377 6378 void 6379 BView::_UpdateStateForRemove() 6380 { 6381 // TODO: _CheckLockAndSwitchCurrent() would be good enough, no? 6382 if (!_CheckOwnerLockAndSwitchCurrent()) 6383 return; 6384 6385 fState->UpdateFrom(*fOwner->fLink); 6386 // if (!fState->IsValid(B_VIEW_FRAME_BIT)) { 6387 // fOwner->fLink->StartMessage(AS_VIEW_GET_COORD); 6388 // 6389 // status_t code; 6390 // if (fOwner->fLink->FlushWithReply(code) == B_OK 6391 // && code == B_OK) { 6392 // fOwner->fLink->Read<BPoint>(&fParentOffset); 6393 // fOwner->fLink->Read<BRect>(&fBounds); 6394 // fState->valid_flags |= B_VIEW_FRAME_BIT; 6395 // } 6396 // } 6397 6398 // update children as well 6399 6400 for (BView* child = fFirstChild; child != NULL; 6401 child = child->fNextSibling) { 6402 if (child->fOwner) 6403 child->_UpdateStateForRemove(); 6404 } 6405 } 6406 6407 6408 inline void 6409 BView::_UpdatePattern(::pattern pattern) 6410 { 6411 if (fState->IsValid(B_VIEW_PATTERN_BIT) && pattern == fState->pattern) 6412 return; 6413 6414 if (fOwner) { 6415 _CheckLockAndSwitchCurrent(); 6416 6417 fOwner->fLink->StartMessage(AS_VIEW_SET_PATTERN); 6418 fOwner->fLink->Attach< ::pattern>(pattern); 6419 6420 fState->valid_flags |= B_VIEW_PATTERN_BIT; 6421 } 6422 6423 fState->pattern = pattern; 6424 } 6425 6426 6427 void 6428 BView::_FlushIfNotInTransaction() 6429 { 6430 if (!fOwner->fInTransaction) { 6431 fOwner->Flush(); 6432 } 6433 } 6434 6435 6436 BShelf* 6437 BView::_Shelf() const 6438 { 6439 return fShelf; 6440 } 6441 6442 6443 void 6444 BView::_SetShelf(BShelf* shelf) 6445 { 6446 if (fShelf != NULL && fOwner != NULL) 6447 fOwner->RemoveHandler(fShelf); 6448 6449 fShelf = shelf; 6450 6451 if (fShelf != NULL && fOwner != NULL) 6452 fOwner->AddHandler(fShelf); 6453 } 6454 6455 6456 status_t 6457 BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect, 6458 uint32 followFlags, uint32 options) 6459 { 6460 if (!_CheckOwnerLockAndSwitchCurrent()) 6461 return B_ERROR; 6462 6463 int32 serverToken = bitmap ? bitmap->_ServerToken() : -1; 6464 6465 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_BITMAP); 6466 fOwner->fLink->Attach<int32>(serverToken); 6467 fOwner->fLink->Attach<BRect>(srcRect); 6468 fOwner->fLink->Attach<BRect>(dstRect); 6469 fOwner->fLink->Attach<int32>(followFlags); 6470 fOwner->fLink->Attach<int32>(options); 6471 6472 status_t status = B_ERROR; 6473 fOwner->fLink->FlushWithReply(status); 6474 6475 return status; 6476 } 6477 6478 6479 bool 6480 BView::_CheckOwnerLockAndSwitchCurrent() const 6481 { 6482 STRACE(("BView(%s)::_CheckOwnerLockAndSwitchCurrent()\n", Name())); 6483 6484 if (fOwner == NULL) { 6485 debugger("View method requires owner and doesn't have one."); 6486 return false; 6487 } 6488 6489 _CheckLockAndSwitchCurrent(); 6490 6491 return true; 6492 } 6493 6494 6495 bool 6496 BView::_CheckOwnerLock() const 6497 { 6498 if (fOwner) { 6499 fOwner->check_lock(); 6500 return true; 6501 } else { 6502 debugger("View method requires owner and doesn't have one."); 6503 return false; 6504 } 6505 } 6506 6507 6508 void 6509 BView::_CheckLockAndSwitchCurrent() const 6510 { 6511 STRACE(("BView(%s)::_CheckLockAndSwitchCurrent()\n", Name())); 6512 6513 if (!fOwner) 6514 return; 6515 6516 fOwner->check_lock(); 6517 6518 _SwitchServerCurrentView(); 6519 } 6520 6521 6522 void 6523 BView::_CheckLock() const 6524 { 6525 if (fOwner) 6526 fOwner->check_lock(); 6527 } 6528 6529 6530 void 6531 BView::_SwitchServerCurrentView() const 6532 { 6533 int32 serverToken = _get_object_token_(this); 6534 6535 if (fOwner->fLastViewToken != serverToken) { 6536 STRACE(("contacting app_server... sending token: %" B_PRId32 "\n", 6537 serverToken)); 6538 fOwner->fLink->StartMessage(AS_SET_CURRENT_VIEW); 6539 fOwner->fLink->Attach<int32>(serverToken); 6540 6541 fOwner->fLastViewToken = serverToken; 6542 } 6543 } 6544 6545 6546 status_t 6547 BView::ScrollWithMouseWheelDelta(BScrollBar* scrollBar, float delta) 6548 { 6549 if (scrollBar == NULL || delta == 0.0f) 6550 return B_BAD_VALUE; 6551 6552 float smallStep; 6553 float largeStep; 6554 scrollBar->GetSteps(&smallStep, &largeStep); 6555 6556 // pressing the shift key scrolls faster (following the pseudo-standard set 6557 // by other desktop environments). 6558 if ((modifiers() & B_SHIFT_KEY) != 0) 6559 delta *= largeStep; 6560 else 6561 delta *= smallStep * 3; 6562 6563 scrollBar->SetValue(scrollBar->Value() + delta); 6564 6565 return B_OK; 6566 } 6567 6568 6569 #if __GNUC__ == 2 6570 6571 6572 extern "C" void 6573 _ReservedView1__5BView(BView* view, BRect rect) 6574 { 6575 view->BView::DrawAfterChildren(rect); 6576 } 6577 6578 6579 extern "C" void 6580 _ReservedView2__5BView(BView* view) 6581 { 6582 // MinSize() 6583 perform_data_min_size data; 6584 view->Perform(PERFORM_CODE_MIN_SIZE, &data); 6585 } 6586 6587 6588 extern "C" void 6589 _ReservedView3__5BView(BView* view) 6590 { 6591 // MaxSize() 6592 perform_data_max_size data; 6593 view->Perform(PERFORM_CODE_MAX_SIZE, &data); 6594 } 6595 6596 6597 extern "C" BSize 6598 _ReservedView4__5BView(BView* view) 6599 { 6600 // PreferredSize() 6601 perform_data_preferred_size data; 6602 view->Perform(PERFORM_CODE_PREFERRED_SIZE, &data); 6603 return data.return_value; 6604 } 6605 6606 6607 extern "C" BAlignment 6608 _ReservedView5__5BView(BView* view) 6609 { 6610 // LayoutAlignment() 6611 perform_data_layout_alignment data; 6612 view->Perform(PERFORM_CODE_LAYOUT_ALIGNMENT, &data); 6613 return data.return_value; 6614 } 6615 6616 6617 extern "C" bool 6618 _ReservedView6__5BView(BView* view) 6619 { 6620 // HasHeightForWidth() 6621 perform_data_has_height_for_width data; 6622 view->Perform(PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH, &data); 6623 return data.return_value; 6624 } 6625 6626 6627 extern "C" void 6628 _ReservedView7__5BView(BView* view, float width, float* min, float* max, 6629 float* preferred) 6630 { 6631 // GetHeightForWidth() 6632 perform_data_get_height_for_width data; 6633 data.width = width; 6634 view->Perform(PERFORM_CODE_GET_HEIGHT_FOR_WIDTH, &data); 6635 if (min != NULL) 6636 *min = data.min; 6637 if (max != NULL) 6638 *max = data.max; 6639 if (preferred != NULL) 6640 *preferred = data.preferred; 6641 } 6642 6643 6644 extern "C" void 6645 _ReservedView8__5BView(BView* view, BLayout* layout) 6646 { 6647 // SetLayout() 6648 perform_data_set_layout data; 6649 data.layout = layout; 6650 view->Perform(PERFORM_CODE_SET_LAYOUT, &data); 6651 } 6652 6653 6654 extern "C" void 6655 _ReservedView9__5BView(BView* view, bool descendants) 6656 { 6657 // LayoutInvalidated() 6658 perform_data_layout_invalidated data; 6659 data.descendants = descendants; 6660 view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data); 6661 } 6662 6663 6664 extern "C" void 6665 _ReservedView10__5BView(BView* view) 6666 { 6667 // DoLayout() 6668 view->Perform(PERFORM_CODE_DO_LAYOUT, NULL); 6669 } 6670 6671 6672 #endif // __GNUC__ == 2 6673 6674 6675 extern "C" bool 6676 B_IF_GCC_2(_ReservedView11__5BView, _ZN5BView15_ReservedView11Ev)( 6677 BView* view, BPoint point, BToolTip** _toolTip) 6678 { 6679 // GetToolTipAt() 6680 perform_data_get_tool_tip_at data; 6681 data.point = point; 6682 data.tool_tip = _toolTip; 6683 view->Perform(PERFORM_CODE_GET_TOOL_TIP_AT, &data); 6684 return data.return_value; 6685 } 6686 6687 6688 extern "C" void 6689 B_IF_GCC_2(_ReservedView12__5BView, _ZN5BView15_ReservedView12Ev)( 6690 BView* view) 6691 { 6692 // LayoutChanged(); 6693 view->Perform(PERFORM_CODE_LAYOUT_CHANGED, NULL); 6694 } 6695 6696 6697 void BView::_ReservedView13() {} 6698 void BView::_ReservedView14() {} 6699 void BView::_ReservedView15() {} 6700 void BView::_ReservedView16() {} 6701 6702 6703 BView::BView(const BView& other) 6704 : 6705 BHandler() 6706 { 6707 // this is private and not functional, but exported 6708 } 6709 6710 6711 BView& 6712 BView::operator=(const BView& other) 6713 { 6714 // this is private and not functional, but exported 6715 return *this; 6716 } 6717 6718 6719 void 6720 BView::_PrintToStream() 6721 { 6722 printf("BView::_PrintToStream()\n"); 6723 printf("\tName: %s\n" 6724 "\tParent: %s\n" 6725 "\tFirstChild: %s\n" 6726 "\tNextSibling: %s\n" 6727 "\tPrevSibling: %s\n" 6728 "\tOwner(Window): %s\n" 6729 "\tToken: %" B_PRId32 "\n" 6730 "\tFlags: %" B_PRId32 "\n" 6731 "\tView origin: (%f,%f)\n" 6732 "\tView Bounds rectangle: (%f,%f,%f,%f)\n" 6733 "\tShow level: %d\n" 6734 "\tTopView?: %s\n" 6735 "\tBPicture: %s\n" 6736 "\tVertical Scrollbar %s\n" 6737 "\tHorizontal Scrollbar %s\n" 6738 "\tIs Printing?: %s\n" 6739 "\tShelf?: %s\n" 6740 "\tEventMask: %" B_PRId32 "\n" 6741 "\tEventOptions: %" B_PRId32 "\n", 6742 Name(), 6743 fParent ? fParent->Name() : "NULL", 6744 fFirstChild ? fFirstChild->Name() : "NULL", 6745 fNextSibling ? fNextSibling->Name() : "NULL", 6746 fPreviousSibling ? fPreviousSibling->Name() : "NULL", 6747 fOwner ? fOwner->Name() : "NULL", 6748 _get_object_token_(this), 6749 fFlags, 6750 fParentOffset.x, fParentOffset.y, 6751 fBounds.left, fBounds.top, fBounds.right, fBounds.bottom, 6752 fShowLevel, 6753 fTopLevelView ? "YES" : "NO", 6754 fCurrentPicture? "YES" : "NULL", 6755 fVerScroller? "YES" : "NULL", 6756 fHorScroller? "YES" : "NULL", 6757 fIsPrinting? "YES" : "NO", 6758 fShelf? "YES" : "NO", 6759 fEventMask, 6760 fEventOptions); 6761 6762 printf("\tState status:\n" 6763 "\t\tLocalCoordianteSystem: (%f,%f)\n" 6764 "\t\tPenLocation: (%f,%f)\n" 6765 "\t\tPenSize: %f\n" 6766 "\t\tHighColor: [%d,%d,%d,%d]\n" 6767 "\t\tLowColor: [%d,%d,%d,%d]\n" 6768 "\t\tViewColor: [%d,%d,%d,%d]\n" 6769 "\t\tPattern: %" B_PRIx64 "\n" 6770 "\t\tDrawingMode: %d\n" 6771 "\t\tLineJoinMode: %d\n" 6772 "\t\tLineCapMode: %d\n" 6773 "\t\tMiterLimit: %f\n" 6774 "\t\tAlphaSource: %d\n" 6775 "\t\tAlphaFuntion: %d\n" 6776 "\t\tScale: %f\n" 6777 "\t\t(Print)FontAliasing: %s\n" 6778 "\t\tFont Info:\n", 6779 fState->origin.x, fState->origin.y, 6780 fState->pen_location.x, fState->pen_location.y, 6781 fState->pen_size, 6782 fState->high_color.red, fState->high_color.blue, fState->high_color.green, fState->high_color.alpha, 6783 fState->low_color.red, fState->low_color.blue, fState->low_color.green, fState->low_color.alpha, 6784 fState->view_color.red, fState->view_color.blue, fState->view_color.green, fState->view_color.alpha, 6785 *((uint64*)&(fState->pattern)), 6786 fState->drawing_mode, 6787 fState->line_join, 6788 fState->line_cap, 6789 fState->miter_limit, 6790 fState->alpha_source_mode, 6791 fState->alpha_function_mode, 6792 fState->scale, 6793 fState->font_aliasing? "YES" : "NO"); 6794 6795 fState->font.PrintToStream(); 6796 6797 // TODO: also print the line array. 6798 } 6799 6800 6801 void 6802 BView::_PrintTree() 6803 { 6804 int32 spaces = 2; 6805 BView* c = fFirstChild; //c = short for: current 6806 printf( "'%s'\n", Name() ); 6807 if (c != NULL) { 6808 while(true) { 6809 // action block 6810 { 6811 for (int i = 0; i < spaces; i++) 6812 printf(" "); 6813 6814 printf( "'%s'\n", c->Name() ); 6815 } 6816 6817 // go deep 6818 if (c->fFirstChild) { 6819 c = c->fFirstChild; 6820 spaces += 2; 6821 } else { 6822 // go right 6823 if (c->fNextSibling) { 6824 c = c->fNextSibling; 6825 } else { 6826 // go up 6827 while (!c->fParent->fNextSibling && c->fParent != this) { 6828 c = c->fParent; 6829 spaces -= 2; 6830 } 6831 6832 // that enough! We've reached this view. 6833 if (c->fParent == this) 6834 break; 6835 6836 c = c->fParent->fNextSibling; 6837 spaces -= 2; 6838 } 6839 } 6840 } 6841 } 6842 } 6843 6844 6845 // #pragma mark - 6846 6847 6848 BLayoutItem* 6849 BView::Private::LayoutItemAt(int32 index) 6850 { 6851 return fView->fLayoutData->fLayoutItems.ItemAt(index); 6852 } 6853 6854 6855 int32 6856 BView::Private::CountLayoutItems() 6857 { 6858 return fView->fLayoutData->fLayoutItems.CountItems(); 6859 } 6860 6861 6862 void 6863 BView::Private::RegisterLayoutItem(BLayoutItem* item) 6864 { 6865 fView->fLayoutData->fLayoutItems.AddItem(item); 6866 } 6867 6868 6869 void 6870 BView::Private::DeregisterLayoutItem(BLayoutItem* item) 6871 { 6872 fView->fLayoutData->fLayoutItems.RemoveItem(item); 6873 } 6874 6875 6876 bool 6877 BView::Private::MinMaxValid() 6878 { 6879 return fView->fLayoutData->fMinMaxValid; 6880 } 6881 6882 6883 bool 6884 BView::Private::WillLayout() 6885 { 6886 BView::LayoutData* data = fView->fLayoutData; 6887 if (data->fLayoutInProgress) 6888 return false; 6889 if (data->fNeedsRelayout || !data->fLayoutValid || !data->fMinMaxValid) 6890 return true; 6891 return false; 6892 } 6893