1 /* 2 * Copyright 2001-2008, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Adrian Oanca <adioanca@cotty.iren.ro> 7 * Axel Dörfler, axeld@pinc-software.de 8 * Stephan Aßmus <superstippi@gmx.de> 9 * Ingo Weinhold <bonefish@cs.tu-berlin.de> 10 */ 11 12 #include <math.h> 13 #include <stdio.h> 14 15 #include <new> 16 17 #include <Application.h> 18 #include <Bitmap.h> 19 #include <Button.h> 20 #include <Cursor.h> 21 #include <File.h> 22 #include <InterfaceDefs.h> 23 #include <Layout.h> 24 #include <LayoutContext.h> 25 #include <LayoutUtils.h> 26 #include <MenuBar.h> 27 #include <Message.h> 28 #include <MessageQueue.h> 29 #include <Picture.h> 30 #include <Point.h> 31 #include <Polygon.h> 32 #include <PropertyInfo.h> 33 #include <Region.h> 34 #include <ScrollBar.h> 35 #include <Shape.h> 36 #include <Shelf.h> 37 #include <String.h> 38 #include <View.h> 39 #include <Window.h> 40 41 #include <GradientLinear.h> 42 #include <GradientRadial.h> 43 #include <GradientRadialFocus.h> 44 #include <GradientDiamond.h> 45 #include <GradientConic.h> 46 47 #include <AppMisc.h> 48 #include <AppServerLink.h> 49 #include <binary_compatibility/Interface.h> 50 #include <MessagePrivate.h> 51 #include <MessageUtils.h> 52 #include <PortLink.h> 53 #include <ServerProtocol.h> 54 #include <ShapePrivate.h> 55 #include <TokenSpace.h> 56 #include <ViewPrivate.h> 57 58 59 using std::nothrow; 60 61 //#define DEBUG_BVIEW 62 #ifdef DEBUG_BVIEW 63 # include <stdio.h> 64 # define STRACE(x) printf x 65 # define BVTRACE _PrintToStream() 66 #else 67 # define STRACE(x) ; 68 # define BVTRACE ; 69 #endif 70 71 72 static property_info sViewPropInfo[] = { 73 { "Frame", { B_GET_PROPERTY, 0 }, 74 { B_DIRECT_SPECIFIER, 0 }, "Returns the view's frame rectangle.", 0, 75 { B_RECT_TYPE } 76 }, 77 { "Frame", { B_SET_PROPERTY, 0 }, 78 { B_DIRECT_SPECIFIER, 0 }, "Sets the view's frame rectangle.", 0, 79 { B_RECT_TYPE } 80 }, 81 { "Hidden", { B_GET_PROPERTY, 0 }, 82 { B_DIRECT_SPECIFIER, 0 }, "Returns wether or not the view is hidden.", 83 0, { B_BOOL_TYPE } 84 }, 85 { "Hidden", { B_SET_PROPERTY, 0 }, 86 { B_DIRECT_SPECIFIER, 0 }, "Hides or shows the view.", 0, 87 { 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, { 0 }, { 0 }, 0, 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 146 pattern = B_SOLID_HIGH; 147 drawing_mode = B_OP_COPY; 148 149 origin.Set(0, 0); 150 151 line_join = B_MITER_JOIN; 152 line_cap = B_BUTT_CAP; 153 miter_limit = B_DEFAULT_MITER_LIMIT; 154 155 alpha_source_mode = B_PIXEL_ALPHA; 156 alpha_function_mode = B_ALPHA_OVERLAY; 157 158 scale = 1.0; 159 160 font = *be_plain_font; 161 font_flags = font.Flags(); 162 font_aliasing = false; 163 164 /* 165 INFO: We include(invalidate) only B_VIEW_CLIP_REGION_BIT flag 166 because we should get the clipping region from app_server. 167 The other flags do not need to be included because the data they 168 represent is already in sync with app_server - app_server uses the 169 same init(default) values. 170 */ 171 valid_flags = ~B_VIEW_CLIP_REGION_BIT; 172 173 archiving_flags = B_VIEW_FRAME_BIT | B_VIEW_RESIZE_BIT; 174 } 175 176 177 void 178 ViewState::UpdateServerFontState(BPrivate::PortLink &link) 179 { 180 link.StartMessage(AS_VIEW_SET_FONT_STATE); 181 link.Attach<uint16>(font_flags); 182 // always present 183 184 if (font_flags & B_FONT_FAMILY_AND_STYLE) 185 link.Attach<uint32>(font.FamilyAndStyle()); 186 187 if (font_flags & B_FONT_SIZE) 188 link.Attach<float>(font.Size()); 189 190 if (font_flags & B_FONT_SHEAR) 191 link.Attach<float>(font.Shear()); 192 193 if (font_flags & B_FONT_ROTATION) 194 link.Attach<float>(font.Rotation()); 195 196 if (font_flags & B_FONT_FALSE_BOLD_WIDTH) 197 link.Attach<float>(font.FalseBoldWidth()); 198 199 if (font_flags & B_FONT_SPACING) 200 link.Attach<uint8>(font.Spacing()); 201 202 if (font_flags & B_FONT_ENCODING) 203 link.Attach<uint8>(font.Encoding()); 204 205 if (font_flags & B_FONT_FACE) 206 link.Attach<uint16>(font.Face()); 207 208 if (font_flags & B_FONT_FLAGS) 209 link.Attach<uint32>(font.Flags()); 210 } 211 212 213 void 214 ViewState::UpdateServerState(BPrivate::PortLink &link) 215 { 216 UpdateServerFontState(link); 217 218 link.StartMessage(AS_VIEW_SET_STATE); 219 link.Attach<BPoint>(pen_location); 220 link.Attach<float>(pen_size); 221 link.Attach<rgb_color>(high_color); 222 link.Attach<rgb_color>(low_color); 223 link.Attach< ::pattern>(pattern); 224 link.Attach<int8>((int8)drawing_mode); 225 link.Attach<BPoint>(origin); 226 link.Attach<int8>((int8)line_join); 227 link.Attach<int8>((int8)line_cap); 228 link.Attach<float>(miter_limit); 229 link.Attach<int8>((int8)alpha_source_mode); 230 link.Attach<int8>((int8)alpha_function_mode); 231 link.Attach<float>(scale); 232 link.Attach<bool>(font_aliasing); 233 234 // we send the 'local' clipping region... if we have one... 235 if (clipping_region_used) { 236 int32 count = clipping_region.CountRects(); 237 link.Attach<int32>(count); 238 for (int32 i = 0; i < count; i++) 239 link.Attach<BRect>(clipping_region.RectAt(i)); 240 } else { 241 // no clipping region 242 link.Attach<int32>(-1); 243 } 244 245 // Although we might have a 'local' clipping region, when we call 246 // BView::GetClippingRegion() we ask for the 'global' one and it 247 // is kept on server, so we must invalidate B_VIEW_CLIP_REGION_BIT flag 248 249 valid_flags = ~B_VIEW_CLIP_REGION_BIT; 250 } 251 252 253 void 254 ViewState::UpdateFrom(BPrivate::PortLink &link) 255 { 256 link.StartMessage(AS_VIEW_GET_STATE); 257 258 int32 code; 259 if (link.FlushWithReply(code) != B_OK 260 || code != B_OK) 261 return; 262 263 uint32 fontID; 264 float size; 265 float shear; 266 float rotation; 267 float falseBoldeWidth; 268 uint8 spacing; 269 uint8 encoding; 270 uint16 face; 271 uint32 flags; 272 273 // read and set the font state 274 link.Read<int32>((int32 *)&fontID); 275 link.Read<float>(&size); 276 link.Read<float>(&shear); 277 link.Read<float>(&rotation); 278 link.Read<float>(&falseBoldeWidth); 279 link.Read<int8>((int8 *)&spacing); 280 link.Read<int8>((int8 *)&encoding); 281 link.Read<int16>((int16 *)&face); 282 link.Read<int32>((int32 *)&flags); 283 284 font_flags = B_FONT_ALL; 285 font.SetFamilyAndStyle(fontID); 286 font.SetSize(size); 287 font.SetShear(shear); 288 font.SetRotation(rotation); 289 font.SetFalseBoldWidth(falseBoldeWidth); 290 font.SetSpacing(spacing); 291 font.SetEncoding(encoding); 292 font.SetFace(face); 293 font.SetFlags(flags); 294 295 // read and set view's state 296 link.Read<BPoint>(&pen_location); 297 link.Read<float>(&pen_size); 298 link.Read<rgb_color>(&high_color); 299 link.Read<rgb_color>(&low_color); 300 link.Read< ::pattern>(&pattern); 301 link.Read<BPoint>(&origin); 302 303 int8 drawingMode; 304 link.Read<int8>((int8 *)&drawingMode); 305 drawing_mode = (::drawing_mode)drawingMode; 306 307 link.Read<int8>((int8 *)&line_cap); 308 link.Read<int8>((int8 *)&line_join); 309 link.Read<float>(&miter_limit); 310 link.Read<int8>((int8 *)&alpha_source_mode); 311 link.Read<int8>((int8 *)&alpha_function_mode); 312 link.Read<float>(&scale); 313 link.Read<bool>(&font_aliasing); 314 315 // read the user clipping 316 // (that's NOT the current View visible clipping but the additional 317 // user specified clipping!) 318 int32 clippingRectCount; 319 link.Read<int32>(&clippingRectCount); 320 if (clippingRectCount >= 0) { 321 clipping_region.MakeEmpty(); 322 for (int32 i = 0; i < clippingRectCount; i++) { 323 BRect rect; 324 link.Read<BRect>(&rect); 325 clipping_region.Include(rect); 326 } 327 } else { 328 // no user clipping used 329 clipping_region_used = false; 330 } 331 332 valid_flags = ~B_VIEW_CLIP_REGION_BIT; 333 } 334 335 } // namespace BPrivate 336 337 338 // #pragma mark - 339 340 341 struct BView::LayoutData { 342 LayoutData() 343 : fMinSize(), 344 fMaxSize(), 345 fPreferredSize(), 346 fAlignment(), 347 fLayoutInvalidationDisabled(0), 348 fLayout(NULL), 349 fLayoutContext(NULL), 350 fLayoutValid(true), // <- TODO: Rethink this! 351 fLayoutInProgress(false), 352 fNeedsRelayout(true) 353 { 354 } 355 356 BSize fMinSize; 357 BSize fMaxSize; 358 BSize fPreferredSize; 359 BAlignment fAlignment; 360 int fLayoutInvalidationDisabled; 361 BLayout* fLayout; 362 BLayoutContext* fLayoutContext; 363 bool fLayoutValid; 364 bool fLayoutInProgress; 365 bool fNeedsRelayout; 366 }; 367 368 369 BView::BView(const char* name, uint32 flags, BLayout* layout) 370 : BHandler(name) 371 { 372 _InitData(BRect(0, 0, 0, 0), name, B_FOLLOW_NONE, 373 flags | B_SUPPORTS_LAYOUT); 374 SetLayout(layout); 375 } 376 377 378 BView::BView(BRect frame, const char *name, uint32 resizingMode, uint32 flags) 379 : BHandler(name) 380 { 381 _InitData(frame, name, resizingMode, flags); 382 } 383 384 385 BView::BView(BMessage *archive) 386 : BHandler(archive) 387 { 388 BRect frame; 389 archive->FindRect("_frame", &frame); 390 391 uint32 resizingMode; 392 if (archive->FindInt32("_resize_mode", (int32*)&resizingMode) != B_OK) 393 resizingMode = 0; 394 395 uint32 flags; 396 if (archive->FindInt32("_flags", (int32*)&flags) != B_OK) 397 flags = 0; 398 399 _InitData(frame, Name(), resizingMode, flags); 400 401 font_family family; 402 font_style style; 403 if (archive->FindString("_fname", 0, (const char **)&family) == B_OK 404 && archive->FindString("_fname", 1, (const char **)&style) == B_OK) { 405 BFont font; 406 font.SetFamilyAndStyle(family, style); 407 408 float size; 409 if (archive->FindFloat("_fflt", 0, &size) == B_OK) 410 font.SetSize(size); 411 412 float shear; 413 if (archive->FindFloat("_fflt", 1, &shear) == B_OK 414 && shear >= 45.0 && shear <= 135.0) 415 font.SetShear(shear); 416 417 float rotation; 418 if (archive->FindFloat("_fflt", 2, &rotation) == B_OK 419 && rotation >=0 && rotation <= 360) 420 font.SetRotation(rotation); 421 422 SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE 423 | B_FONT_SHEAR | B_FONT_ROTATION); 424 } 425 426 int32 color; 427 if (archive->FindInt32("_color", 0, &color) == B_OK) 428 SetHighColor(get_rgb_color(color)); 429 if (archive->FindInt32("_color", 1, &color) == B_OK) 430 SetLowColor(get_rgb_color(color)); 431 if (archive->FindInt32("_color", 2, &color) == B_OK) 432 SetViewColor(get_rgb_color(color)); 433 434 uint32 evMask; 435 uint32 options; 436 if (archive->FindInt32("_evmask", 0, (int32 *)&evMask) == B_OK 437 && archive->FindInt32("_evmask", 1, (int32 *)&options) == B_OK) 438 SetEventMask(evMask, options); 439 440 BPoint origin; 441 if (archive->FindPoint("_origin", &origin) == B_OK) 442 SetOrigin(origin); 443 444 float penSize; 445 if (archive->FindFloat("_psize", &penSize) == B_OK) 446 SetPenSize(penSize); 447 448 BPoint penLocation; 449 if (archive->FindPoint("_ploc", &penLocation) == B_OK) 450 MovePenTo(penLocation); 451 452 int16 lineCap; 453 int16 lineJoin; 454 float lineMiter; 455 if (archive->FindInt16("_lmcapjoin", 0, &lineCap) == B_OK 456 && archive->FindInt16("_lmcapjoin", 1, &lineJoin) == B_OK 457 && archive->FindFloat("_lmmiter", &lineMiter) == B_OK) 458 SetLineMode((cap_mode)lineCap, (join_mode)lineJoin, lineMiter); 459 460 int16 alphaBlend; 461 int16 modeBlend; 462 if (archive->FindInt16("_blend", 0, &alphaBlend) == B_OK 463 && archive->FindInt16("_blend", 1, &modeBlend) == B_OK) 464 SetBlendingMode( (source_alpha)alphaBlend, (alpha_function)modeBlend); 465 466 uint32 drawingMode; 467 if (archive->FindInt32("_dmod", (int32 *)&drawingMode) == B_OK) 468 SetDrawingMode((drawing_mode)drawingMode); 469 470 BMessage msg; 471 for (int32 i = 0; archive->FindMessage("_views", i, &msg) == B_OK; i++) { 472 BArchivable *object = instantiate_object(&msg); 473 if (BView *child = dynamic_cast<BView *>(object)) 474 AddChild(child); 475 } 476 } 477 478 479 BArchivable * 480 BView::Instantiate(BMessage *data) 481 { 482 if (!validate_instantiation(data , "BView")) 483 return NULL; 484 485 return new(std::nothrow) BView(data); 486 } 487 488 489 status_t 490 BView::Archive(BMessage *data, bool deep) const 491 { 492 status_t ret = BHandler::Archive(data, deep); 493 if (ret != B_OK) 494 return ret; 495 496 if (fState->archiving_flags & B_VIEW_FRAME_BIT) 497 ret = data->AddRect("_frame", Bounds().OffsetToCopy(fParentOffset)); 498 499 if (ret == B_OK) 500 ret = data->AddInt32("_resize_mode", ResizingMode()); 501 502 if (ret == B_OK) 503 ret = data->AddInt32("_flags", Flags()); 504 505 if (ret == B_OK && fState->archiving_flags & B_VIEW_EVENT_MASK_BIT) { 506 ret = data->AddInt32("_evmask", fEventMask); 507 if (ret == B_OK) 508 ret = data->AddInt32("_evmask", fEventOptions); 509 } 510 511 if (ret == B_OK && fState->archiving_flags & B_VIEW_FONT_BIT) { 512 BFont font; 513 GetFont(&font); 514 515 font_family family; 516 font_style style; 517 font.GetFamilyAndStyle(&family, &style); 518 ret = data->AddString("_fname", family); 519 if (ret == B_OK) 520 ret = data->AddString("_fname", style); 521 if (ret == B_OK) 522 ret = data->AddFloat("_fflt", font.Size()); 523 if (ret == B_OK) 524 ret = data->AddFloat("_fflt", font.Shear()); 525 if (ret == B_OK) 526 ret = data->AddFloat("_fflt", font.Rotation()); 527 } 528 529 // colors 530 if (ret == B_OK) 531 ret = data->AddInt32("_color", get_uint32_color(HighColor())); 532 if (ret == B_OK) 533 ret = data->AddInt32("_color", get_uint32_color(LowColor())); 534 if (ret == B_OK) 535 ret = data->AddInt32("_color", get_uint32_color(ViewColor())); 536 537 // NOTE: we do not use this flag any more 538 // if ( 1 ){ 539 // ret = data->AddInt32("_dbuf", 1); 540 // } 541 542 if (ret == B_OK && fState->archiving_flags & B_VIEW_ORIGIN_BIT) 543 ret = data->AddPoint("_origin", Origin()); 544 545 if (ret == B_OK && fState->archiving_flags & B_VIEW_PEN_SIZE_BIT) 546 ret = data->AddFloat("_psize", PenSize()); 547 548 if (ret == B_OK && fState->archiving_flags & B_VIEW_PEN_LOCATION_BIT) 549 ret = data->AddPoint("_ploc", PenLocation()); 550 551 if (ret == B_OK && fState->archiving_flags & B_VIEW_LINE_MODES_BIT) { 552 ret = data->AddInt16("_lmcapjoin", (int16)LineCapMode()); 553 if (ret == B_OK) 554 ret = data->AddInt16("_lmcapjoin", (int16)LineJoinMode()); 555 if (ret == B_OK) 556 ret = data->AddFloat("_lmmiter", LineMiterLimit()); 557 } 558 559 if (ret == B_OK && fState->archiving_flags & B_VIEW_BLENDING_BIT) { 560 source_alpha alphaSourceMode; 561 alpha_function alphaFunctionMode; 562 GetBlendingMode(&alphaSourceMode, &alphaFunctionMode); 563 564 ret = data->AddInt16("_blend", (int16)alphaSourceMode); 565 if (ret == B_OK) 566 ret = data->AddInt16("_blend", (int16)alphaFunctionMode); 567 } 568 569 if (ret == B_OK && fState->archiving_flags & B_VIEW_DRAWING_MODE_BIT) 570 ret = data->AddInt32("_dmod", DrawingMode()); 571 572 if (deep) { 573 int32 i = 0; 574 BView *child; 575 576 while (ret == B_OK && (child = ChildAt(i++)) != NULL) { 577 BMessage childArchive; 578 579 ret = child->Archive(&childArchive, deep); 580 if (ret == B_OK) 581 ret = data->AddMessage("_views", &childArchive); 582 } 583 } 584 585 return ret; 586 } 587 588 589 BView::~BView() 590 { 591 STRACE(("BView(%s)::~BView()\n", this->Name())); 592 593 if (fOwner) 594 debugger("Trying to delete a view that belongs to a window. Call RemoveSelf first."); 595 596 RemoveSelf(); 597 598 // TODO: see about BShelf! must I delete it here? is it deleted by the window? 599 600 // we also delete all our children 601 602 BView *child = fFirstChild; 603 while (child) { 604 BView *nextChild = child->fNextSibling; 605 606 delete child; 607 child = nextChild; 608 } 609 610 // delete the layout and the layout data 611 delete fLayoutData->fLayout; 612 delete fLayoutData; 613 614 if (fVerScroller) 615 fVerScroller->SetTarget((BView*)NULL); 616 if (fHorScroller) 617 fHorScroller->SetTarget((BView*)NULL); 618 619 SetName(NULL); 620 621 _RemoveCommArray(); 622 delete fState; 623 } 624 625 626 BRect 627 BView::Bounds() const 628 { 629 _CheckLock(); 630 631 if (fIsPrinting) 632 return fState->print_rect; 633 634 return fBounds; 635 } 636 637 638 void 639 BView::_ConvertToParent(BPoint *point, bool checkLock) const 640 { 641 if (!fParent) 642 return; 643 644 if (checkLock) 645 _CheckLock(); 646 647 // - our scrolling offset 648 // + our bounds location within the parent 649 point->x += -fBounds.left + fParentOffset.x; 650 point->y += -fBounds.top + fParentOffset.y; 651 } 652 653 void 654 BView::ConvertToParent(BPoint *point) const 655 { 656 _ConvertToParent(point, true); 657 } 658 659 660 BPoint 661 BView::ConvertToParent(BPoint point) const 662 { 663 ConvertToParent(&point); 664 665 return point; 666 } 667 668 669 void 670 BView::_ConvertFromParent(BPoint *point, bool checkLock) const 671 { 672 if (!fParent) 673 return; 674 675 if (checkLock) 676 _CheckLock(); 677 678 // - our bounds location within the parent 679 // + our scrolling offset 680 point->x += -fParentOffset.x + fBounds.left; 681 point->y += -fParentOffset.y + fBounds.top; 682 } 683 684 void 685 BView::ConvertFromParent(BPoint *point) const 686 { 687 _ConvertFromParent(point, true); 688 } 689 690 691 BPoint 692 BView::ConvertFromParent(BPoint point) const 693 { 694 ConvertFromParent(&point); 695 696 return point; 697 } 698 699 700 void 701 BView::ConvertToParent(BRect *rect) const 702 { 703 if (!fParent) 704 return; 705 706 _CheckLock(); 707 708 // - our scrolling offset 709 // + our bounds location within the parent 710 rect->OffsetBy(-fBounds.left + fParentOffset.x, 711 -fBounds.top + fParentOffset.y); 712 } 713 714 715 BRect 716 BView::ConvertToParent(BRect rect) const 717 { 718 ConvertToParent(&rect); 719 720 return rect; 721 } 722 723 724 void 725 BView::ConvertFromParent(BRect *rect) const 726 { 727 if (!fParent) 728 return; 729 730 _CheckLock(); 731 732 // - our bounds location within the parent 733 // + our scrolling offset 734 rect->OffsetBy(-fParentOffset.x + fBounds.left, 735 -fParentOffset.y + fBounds.top); 736 } 737 738 739 BRect 740 BView::ConvertFromParent(BRect rect) const 741 { 742 ConvertFromParent(&rect); 743 744 return rect; 745 } 746 747 748 void 749 BView::_ConvertToScreen(BPoint *pt, bool checkLock) const 750 { 751 if (!fParent) { 752 if (fOwner) 753 fOwner->ConvertToScreen(pt); 754 755 return; 756 } 757 758 if (checkLock) 759 _CheckOwnerLock(); 760 761 _ConvertToParent(pt, false); 762 fParent->_ConvertToScreen(pt, false); 763 } 764 765 766 void 767 BView::ConvertToScreen(BPoint *pt) const 768 { 769 _ConvertToScreen(pt, true); 770 } 771 772 773 BPoint 774 BView::ConvertToScreen(BPoint pt) const 775 { 776 ConvertToScreen(&pt); 777 778 return pt; 779 } 780 781 782 void 783 BView::_ConvertFromScreen(BPoint *pt, bool checkLock) const 784 { 785 if (!fParent) { 786 if (fOwner) 787 fOwner->ConvertFromScreen(pt); 788 789 return; 790 } 791 792 if (checkLock) 793 _CheckOwnerLock(); 794 795 _ConvertFromParent(pt, false); 796 fParent->_ConvertFromScreen(pt, false); 797 } 798 799 void 800 BView::ConvertFromScreen(BPoint *pt) const 801 { 802 _ConvertFromScreen(pt, true); 803 } 804 805 806 BPoint 807 BView::ConvertFromScreen(BPoint pt) const 808 { 809 ConvertFromScreen(&pt); 810 811 return pt; 812 } 813 814 815 void 816 BView::ConvertToScreen(BRect *rect) const 817 { 818 BPoint offset(0.0, 0.0); 819 ConvertToScreen(&offset); 820 rect->OffsetBy(offset); 821 } 822 823 824 BRect 825 BView::ConvertToScreen(BRect rect) const 826 { 827 ConvertToScreen(&rect); 828 829 return rect; 830 } 831 832 833 void 834 BView::ConvertFromScreen(BRect *rect) const 835 { 836 BPoint offset(0.0, 0.0); 837 ConvertFromScreen(&offset); 838 rect->OffsetBy(offset); 839 } 840 841 842 BRect 843 BView::ConvertFromScreen(BRect rect) const 844 { 845 ConvertFromScreen(&rect); 846 847 return rect; 848 } 849 850 851 uint32 852 BView::Flags() const 853 { 854 _CheckLock(); 855 return fFlags & ~_RESIZE_MASK_; 856 } 857 858 859 void 860 BView::SetFlags(uint32 flags) 861 { 862 if (Flags() == flags) 863 return; 864 865 if (fOwner) { 866 if (flags & B_PULSE_NEEDED) { 867 _CheckLock(); 868 if (fOwner->fPulseRunner == NULL) 869 fOwner->SetPulseRate(fOwner->PulseRate()); 870 } 871 872 if (flags & (B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE 873 | B_FRAME_EVENTS | B_SUBPIXEL_PRECISE)) { 874 _CheckLockAndSwitchCurrent(); 875 876 fOwner->fLink->StartMessage(AS_VIEW_SET_FLAGS); 877 fOwner->fLink->Attach<uint32>(flags); 878 fOwner->fLink->Flush(); 879 } 880 } 881 882 /* Some useful info: 883 fFlags is a unsigned long (32 bits) 884 * bits 1-16 are used for BView's flags 885 * bits 17-32 are used for BView' resize mask 886 * _RESIZE_MASK_ is used for that. Look into View.h to see how 887 it's defined 888 */ 889 fFlags = (flags & ~_RESIZE_MASK_) | (fFlags & _RESIZE_MASK_); 890 891 fState->archiving_flags |= B_VIEW_FLAGS_BIT; 892 } 893 894 895 BRect 896 BView::Frame() const 897 { 898 return Bounds().OffsetToCopy(fParentOffset.x, fParentOffset.y); 899 } 900 901 902 void 903 BView::Hide() 904 { 905 if (fOwner && fShowLevel == 0) { 906 _CheckLockAndSwitchCurrent(); 907 fOwner->fLink->StartMessage(AS_VIEW_HIDE); 908 fOwner->fLink->Flush(); 909 } 910 fShowLevel++; 911 912 if (fShowLevel == 1 && fParent) 913 fParent->InvalidateLayout(); 914 } 915 916 917 void 918 BView::Show() 919 { 920 fShowLevel--; 921 if (fOwner && fShowLevel == 0) { 922 _CheckLockAndSwitchCurrent(); 923 fOwner->fLink->StartMessage(AS_VIEW_SHOW); 924 fOwner->fLink->Flush(); 925 } 926 927 if (fShowLevel == 0 && fParent) 928 fParent->InvalidateLayout(); 929 } 930 931 932 bool 933 BView::IsFocus() const 934 { 935 if (fOwner) { 936 _CheckLock(); 937 return fOwner->CurrentFocus() == this; 938 } else 939 return false; 940 } 941 942 943 bool 944 BView::IsHidden(const BView *lookingFrom) const 945 { 946 if (fShowLevel > 0) 947 return true; 948 949 // may we be egocentric? 950 if (lookingFrom == this) 951 return false; 952 953 // we have the same visibility state as our 954 // parent, if there is one 955 if (fParent) 956 return fParent->IsHidden(lookingFrom); 957 958 // if we're the top view, and we're interested 959 // in the "global" view, we're inheriting the 960 // state of the window's visibility 961 if (fOwner && lookingFrom == NULL) 962 return fOwner->IsHidden(); 963 964 return false; 965 } 966 967 968 bool 969 BView::IsHidden() const 970 { 971 return IsHidden(NULL); 972 } 973 974 975 bool 976 BView::IsPrinting() const 977 { 978 return fIsPrinting; 979 } 980 981 982 BPoint 983 BView::LeftTop() const 984 { 985 return Bounds().LeftTop(); 986 } 987 988 989 void 990 BView::SetResizingMode(uint32 mode) 991 { 992 if (fOwner) { 993 _CheckLockAndSwitchCurrent(); 994 995 fOwner->fLink->StartMessage(AS_VIEW_RESIZE_MODE); 996 fOwner->fLink->Attach<uint32>(mode); 997 } 998 999 // look at SetFlags() for more info on the below line 1000 fFlags = (fFlags & ~_RESIZE_MASK_) | (mode & _RESIZE_MASK_); 1001 } 1002 1003 1004 uint32 1005 BView::ResizingMode() const 1006 { 1007 return fFlags & _RESIZE_MASK_; 1008 } 1009 1010 1011 void 1012 BView::SetViewCursor(const BCursor *cursor, bool sync) 1013 { 1014 if (cursor == NULL || fOwner == NULL) 1015 return; 1016 1017 _CheckLockAndSwitchCurrent(); 1018 1019 fOwner->fLink->StartMessage(AS_VIEW_SET_CURSOR); 1020 fOwner->fLink->Attach<int32>(cursor->fServerToken); 1021 fOwner->fLink->Attach<bool>(sync); 1022 1023 if (!sync) { 1024 cursor->fPendingViewCursor = true; 1025 // this avoids a race condition in case the cursor is 1026 // immediately deleted after this call, as the deletion 1027 // is handled by the application, not the window 1028 } else { 1029 // make sure the server has processed the 1030 // message and "acquired" the cursor in 1031 // the window thread before returning from 1032 // this function 1033 int32 code; 1034 fOwner->fLink->FlushWithReply(code); 1035 } 1036 } 1037 1038 1039 void 1040 BView::Flush() const 1041 { 1042 if (fOwner) 1043 fOwner->Flush(); 1044 } 1045 1046 1047 void 1048 BView::Sync() const 1049 { 1050 _CheckOwnerLock(); 1051 if (fOwner) 1052 fOwner->Sync(); 1053 } 1054 1055 1056 BWindow * 1057 BView::Window() const 1058 { 1059 return fOwner; 1060 } 1061 1062 1063 // #pragma mark - Hook Functions 1064 1065 1066 void 1067 BView::AttachedToWindow() 1068 { 1069 // Hook function 1070 STRACE(("\tHOOK: BView(%s)::AttachedToWindow()\n", Name())); 1071 } 1072 1073 1074 void 1075 BView::AllAttached() 1076 { 1077 // Hook function 1078 STRACE(("\tHOOK: BView(%s)::AllAttached()\n", Name())); 1079 } 1080 1081 1082 void 1083 BView::DetachedFromWindow() 1084 { 1085 // Hook function 1086 STRACE(("\tHOOK: BView(%s)::DetachedFromWindow()\n", Name())); 1087 } 1088 1089 1090 void 1091 BView::AllDetached() 1092 { 1093 // Hook function 1094 STRACE(("\tHOOK: BView(%s)::AllDetached()\n", Name())); 1095 } 1096 1097 1098 void 1099 BView::Draw(BRect updateRect) 1100 { 1101 // Hook function 1102 STRACE(("\tHOOK: BView(%s)::Draw()\n", Name())); 1103 } 1104 1105 1106 void 1107 BView::DrawAfterChildren(BRect r) 1108 { 1109 // Hook function 1110 STRACE(("\tHOOK: BView(%s)::DrawAfterChildren()\n", Name())); 1111 } 1112 1113 1114 void 1115 BView::FrameMoved(BPoint newPosition) 1116 { 1117 // Hook function 1118 STRACE(("\tHOOK: BView(%s)::FrameMoved()\n", Name())); 1119 } 1120 1121 1122 void 1123 BView::FrameResized(float newWidth, float newHeight) 1124 { 1125 // Hook function 1126 STRACE(("\tHOOK: BView(%s)::FrameResized()\n", Name())); 1127 } 1128 1129 1130 void 1131 BView::GetPreferredSize(float* _width, float* _height) 1132 { 1133 STRACE(("\tHOOK: BView(%s)::GetPreferredSize()\n", Name())); 1134 1135 if (_width != NULL) 1136 *_width = fBounds.Width(); 1137 if (_height != NULL) 1138 *_height = fBounds.Height(); 1139 } 1140 1141 1142 void 1143 BView::ResizeToPreferred() 1144 { 1145 STRACE(("\tHOOK: BView(%s)::ResizeToPreferred()\n", Name())); 1146 1147 float width; 1148 float height; 1149 GetPreferredSize(&width, &height); 1150 1151 ResizeTo(width, height); 1152 } 1153 1154 1155 void 1156 BView::KeyDown(const char* bytes, int32 numBytes) 1157 { 1158 // Hook function 1159 STRACE(("\tHOOK: BView(%s)::KeyDown()\n", Name())); 1160 1161 if (Window()) 1162 Window()->_KeyboardNavigation(); 1163 } 1164 1165 1166 void 1167 BView::KeyUp(const char* bytes, int32 numBytes) 1168 { 1169 // Hook function 1170 STRACE(("\tHOOK: BView(%s)::KeyUp()\n", Name())); 1171 } 1172 1173 1174 void 1175 BView::MouseDown(BPoint where) 1176 { 1177 // Hook function 1178 STRACE(("\tHOOK: BView(%s)::MouseDown()\n", Name())); 1179 } 1180 1181 1182 void 1183 BView::MouseUp(BPoint where) 1184 { 1185 // Hook function 1186 STRACE(("\tHOOK: BView(%s)::MouseUp()\n", Name())); 1187 } 1188 1189 1190 void 1191 BView::MouseMoved(BPoint where, uint32 code, const BMessage* a_message) 1192 { 1193 // Hook function 1194 STRACE(("\tHOOK: BView(%s)::MouseMoved()\n", Name())); 1195 } 1196 1197 1198 void 1199 BView::Pulse() 1200 { 1201 // Hook function 1202 STRACE(("\tHOOK: BView(%s)::Pulse()\n", Name())); 1203 } 1204 1205 1206 void 1207 BView::TargetedByScrollView(BScrollView* scroll_view) 1208 { 1209 // Hook function 1210 STRACE(("\tHOOK: BView(%s)::TargetedByScrollView()\n", Name())); 1211 } 1212 1213 1214 void 1215 BView::WindowActivated(bool state) 1216 { 1217 // Hook function 1218 STRACE(("\tHOOK: BView(%s)::WindowActivated()\n", Name())); 1219 } 1220 1221 1222 // #pragma mark - Input Functions 1223 1224 1225 void 1226 BView::BeginRectTracking(BRect startRect, uint32 style) 1227 { 1228 if (_CheckOwnerLockAndSwitchCurrent()) { 1229 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_RECT_TRACK); 1230 fOwner->fLink->Attach<BRect>(startRect); 1231 fOwner->fLink->Attach<uint32>(style); 1232 fOwner->fLink->Flush(); 1233 } 1234 } 1235 1236 1237 void 1238 BView::EndRectTracking() 1239 { 1240 if (_CheckOwnerLockAndSwitchCurrent()) { 1241 fOwner->fLink->StartMessage(AS_VIEW_END_RECT_TRACK); 1242 fOwner->fLink->Flush(); 1243 } 1244 } 1245 1246 1247 void 1248 BView::DragMessage(BMessage *message, BRect dragRect, BHandler *replyTo) 1249 { 1250 if (!message) 1251 return; 1252 1253 _CheckOwnerLock(); 1254 1255 // calculate the offset 1256 BPoint offset; 1257 uint32 buttons; 1258 BMessage *current = fOwner->CurrentMessage(); 1259 if (!current || current->FindPoint("be:view_where", &offset) != B_OK) 1260 GetMouse(&offset, &buttons, false); 1261 offset -= dragRect.LeftTop(); 1262 1263 if (!dragRect.IsValid()) { 1264 DragMessage(message, NULL, B_OP_BLEND, offset, replyTo); 1265 return; 1266 } 1267 1268 // TODO: that's not really what should happen - the app_server should take 1269 // the chance *NOT* to need to drag a whole bitmap around but just a frame. 1270 1271 // create a drag bitmap for the rect 1272 BBitmap *bitmap = new(std::nothrow) BBitmap(dragRect, B_RGBA32); 1273 if (bitmap == NULL) 1274 return; 1275 1276 uint32 *bits = (uint32*)bitmap->Bits(); 1277 uint32 bytesPerRow = bitmap->BytesPerRow(); 1278 uint32 width = dragRect.IntegerWidth() + 1; 1279 uint32 height = dragRect.IntegerHeight() + 1; 1280 uint32 lastRow = (height - 1) * width; 1281 1282 memset(bits, 0x00, height * bytesPerRow); 1283 1284 // top 1285 for (uint32 i = 0; i < width; i += 2) 1286 bits[i] = 0xff000000; 1287 1288 // bottom 1289 for (uint32 i = (height % 2 == 0 ? 1 : 0); i < width; i += 2) 1290 bits[lastRow + i] = 0xff000000; 1291 1292 // left 1293 for (uint32 i = 0; i < lastRow; i += width * 2) 1294 bits[i] = 0xff000000; 1295 1296 // right 1297 for (uint32 i = (width % 2 == 0 ? width : 0); i < lastRow; i += width * 2) 1298 bits[width - 1 + i] = 0xff000000; 1299 1300 DragMessage(message, bitmap, B_OP_BLEND, offset, replyTo); 1301 } 1302 1303 1304 void 1305 BView::DragMessage(BMessage *message, BBitmap *image, BPoint offset, 1306 BHandler *replyTo) 1307 { 1308 DragMessage(message, image, B_OP_COPY, offset, replyTo); 1309 } 1310 1311 1312 void 1313 BView::DragMessage(BMessage *message, BBitmap *image, 1314 drawing_mode dragMode, BPoint offset, BHandler *replyTo) 1315 { 1316 if (message == NULL) 1317 return; 1318 1319 if (image == NULL) { 1320 // TODO: workaround for drags without a bitmap - should not be necessary if 1321 // we move the rectangle dragging into the app_server 1322 image = new(std::nothrow) BBitmap(BRect(0, 0, 0, 0), B_RGBA32); 1323 if (image == NULL) 1324 return; 1325 } 1326 1327 if (replyTo == NULL) 1328 replyTo = this; 1329 1330 if (replyTo->Looper() == NULL) 1331 debugger("DragMessage: warning - the Handler needs a looper"); 1332 1333 _CheckOwnerLock(); 1334 1335 if (!message->HasInt32("buttons")) { 1336 BMessage *msg = fOwner->CurrentMessage(); 1337 uint32 buttons; 1338 1339 if (msg == NULL 1340 || msg->FindInt32("buttons", (int32 *)&buttons) != B_OK) { 1341 BPoint point; 1342 GetMouse(&point, &buttons, false); 1343 } 1344 1345 message->AddInt32("buttons", buttons); 1346 } 1347 1348 BMessage::Private privateMessage(message); 1349 privateMessage.SetReply(BMessenger(replyTo, replyTo->Looper())); 1350 1351 // TODO: create area and flatten message into that area! 1352 // send area info over port, not the actual message! 1353 int32 bufferSize = privateMessage.NativeFlattenedSize(); 1354 char* buffer = new(std::nothrow) char[bufferSize]; 1355 if (buffer != NULL) { 1356 privateMessage.NativeFlatten(buffer, bufferSize); 1357 1358 fOwner->fLink->StartMessage(AS_VIEW_DRAG_IMAGE); 1359 fOwner->fLink->Attach<int32>(image->_ServerToken()); 1360 fOwner->fLink->Attach<int32>((int32)dragMode); 1361 fOwner->fLink->Attach<BPoint>(offset); 1362 fOwner->fLink->Attach<int32>(bufferSize); 1363 fOwner->fLink->Attach(buffer, bufferSize); 1364 1365 // we need to wait for the server 1366 // to actually process this message 1367 // before we can delete the bitmap 1368 int32 code; 1369 fOwner->fLink->FlushWithReply(code); 1370 1371 delete [] buffer; 1372 } else { 1373 fprintf(stderr, "BView::DragMessage() - no memory to flatten drag " 1374 "message\n"); 1375 } 1376 1377 delete image; 1378 } 1379 1380 1381 void 1382 BView::GetMouse(BPoint *_location, uint32 *_buttons, bool checkMessageQueue) 1383 { 1384 if (_location == NULL && _buttons == NULL) 1385 return; 1386 1387 _CheckOwnerLockAndSwitchCurrent(); 1388 1389 uint32 eventOptions = fEventOptions | fMouseEventOptions; 1390 bool noHistory = eventOptions & B_NO_POINTER_HISTORY; 1391 bool fullHistory = eventOptions & B_FULL_POINTER_HISTORY; 1392 1393 if (checkMessageQueue && !noHistory) { 1394 Window()->UpdateIfNeeded(); 1395 BMessageQueue *queue = Window()->MessageQueue(); 1396 queue->Lock(); 1397 1398 // Look out for mouse update messages 1399 1400 BMessage *message; 1401 for (int32 i = 0; (message = queue->FindMessage(i)) != NULL; i++) { 1402 switch (message->what) { 1403 case B_MOUSE_MOVED: 1404 case B_MOUSE_UP: 1405 case B_MOUSE_DOWN: 1406 bool deleteMessage; 1407 if (!Window()->_StealMouseMessage(message, deleteMessage)) 1408 continue; 1409 1410 if (!fullHistory && message->what == B_MOUSE_MOVED) { 1411 // Check if the message is too old. Some applications 1412 // check the message queue in such a way that mouse 1413 // messages *must* pile up. This check makes them work 1414 // as intended, although these applications could simply 1415 // use the version of BView::GetMouse() that does not 1416 // check the history. Also note that it isn't a problem 1417 // to delete the message in case there is not a newer 1418 // one. If we don't find a message in the queue, we will 1419 // just fall back to asking the app_sever directly. So 1420 // the imposed delay will not be a problem on slower 1421 // computers. This check also prevents another problem, 1422 // when the message that we use is *not* removed from 1423 // the queue. Subsequent calls to GetMouse() would find 1424 // this message over and over! 1425 bigtime_t eventTime; 1426 if (message->FindInt64("when", &eventTime) == B_OK 1427 && system_time() - eventTime > 10000) { 1428 // just discard the message 1429 if (deleteMessage) 1430 delete message; 1431 continue; 1432 } 1433 } 1434 message->FindPoint("screen_where", _location); 1435 message->FindInt32("buttons", (int32 *)_buttons); 1436 queue->Unlock(); 1437 // we need to hold the queue lock until here, because 1438 // the message might still be used for something else 1439 1440 if (_location != NULL) 1441 ConvertFromScreen(_location); 1442 1443 if (deleteMessage) 1444 delete message; 1445 1446 return; 1447 } 1448 } 1449 queue->Unlock(); 1450 } 1451 1452 // If no mouse update message has been found in the message queue, 1453 // we get the current mouse location and buttons from the app_server 1454 1455 fOwner->fLink->StartMessage(AS_GET_MOUSE); 1456 1457 int32 code; 1458 if (fOwner->fLink->FlushWithReply(code) == B_OK 1459 && code == B_OK) { 1460 BPoint location; 1461 uint32 buttons; 1462 fOwner->fLink->Read<BPoint>(&location); 1463 fOwner->fLink->Read<uint32>(&buttons); 1464 // TODO: ServerWindow replies with an int32 here 1465 1466 ConvertFromScreen(&location); 1467 // TODO: in beos R5, location is already converted to the view 1468 // local coordinate system, so if an app checks the window message 1469 // queue by itself, it might not find what it expects. 1470 // NOTE: the fact that we have mouse coords in screen space in our 1471 // queue avoids the problem that messages already in the queue will 1472 // be outdated as soon as a window or even the view moves. The 1473 // second situation being quite common actually, also with regards 1474 // to scrolling. An app reading these messages would have to know 1475 // the locations of the window and view for each message... 1476 // otherwise it is potentially broken anyways. 1477 if (_location != NULL) 1478 *_location = location; 1479 if (_buttons != NULL) 1480 *_buttons = buttons; 1481 } else { 1482 if (_location != NULL) 1483 _location->Set(0, 0); 1484 if (_buttons != NULL) 1485 *_buttons = 0; 1486 } 1487 } 1488 1489 1490 void 1491 BView::MakeFocus(bool focusState) 1492 { 1493 if (fOwner) { 1494 // TODO: If this view has focus and focusState==false, 1495 // will there really be no other view with focus? No 1496 // cycling to the next one? 1497 BView *focus = fOwner->CurrentFocus(); 1498 if (focusState) { 1499 // Unfocus a previous focus view 1500 if (focus && focus != this) 1501 focus->MakeFocus(false); 1502 // if we want to make this view the current focus view 1503 fOwner->_SetFocus(this, true); 1504 } else { 1505 // we want to unfocus this view, but only if it actually has focus 1506 if (focus == this) { 1507 fOwner->_SetFocus(NULL, true); 1508 } 1509 } 1510 } 1511 } 1512 1513 1514 BScrollBar * 1515 BView::ScrollBar(orientation posture) const 1516 { 1517 switch (posture) { 1518 case B_VERTICAL: 1519 return fVerScroller; 1520 1521 case B_HORIZONTAL: 1522 return fHorScroller; 1523 1524 default: 1525 return NULL; 1526 } 1527 } 1528 1529 1530 void 1531 BView::ScrollBy(float deltaX, float deltaY) 1532 { 1533 ScrollTo(BPoint(fBounds.left + deltaX, fBounds.top + deltaY)); 1534 } 1535 1536 1537 void 1538 BView::ScrollTo(BPoint where) 1539 { 1540 // scrolling by fractional values is not supported 1541 where.x = roundf(where.x); 1542 where.y = roundf(where.y); 1543 1544 // no reason to process this further if no scroll is intended. 1545 if (where.x == fBounds.left && where.y == fBounds.top) 1546 return; 1547 1548 // make sure scrolling is within valid bounds 1549 if (fHorScroller) { 1550 float min, max; 1551 fHorScroller->GetRange(&min, &max); 1552 1553 if (where.x < min) 1554 where.x = min; 1555 else if (where.x > max) 1556 where.x = max; 1557 } 1558 if (fVerScroller) { 1559 float min, max; 1560 fVerScroller->GetRange(&min, &max); 1561 1562 if (where.y < min) 1563 where.y = min; 1564 else if (where.y > max) 1565 where.y = max; 1566 } 1567 1568 _CheckLockAndSwitchCurrent(); 1569 1570 float xDiff = where.x - fBounds.left; 1571 float yDiff = where.y - fBounds.top; 1572 1573 // if we're attached to a window tell app_server about this change 1574 if (fOwner) { 1575 fOwner->fLink->StartMessage(AS_VIEW_SCROLL); 1576 fOwner->fLink->Attach<float>(xDiff); 1577 fOwner->fLink->Attach<float>(yDiff); 1578 1579 fOwner->fLink->Flush(); 1580 1581 // fState->valid_flags &= ~B_VIEW_FRAME_BIT; 1582 } 1583 1584 // we modify our bounds rectangle by deltaX/deltaY coord units hor/ver. 1585 fBounds.OffsetTo(where.x, where.y); 1586 1587 // then set the new values of the scrollbars 1588 if (fHorScroller && xDiff != 0.0) 1589 fHorScroller->SetValue(fBounds.left); 1590 if (fVerScroller && yDiff != 0.0) 1591 fVerScroller->SetValue(fBounds.top); 1592 1593 } 1594 1595 1596 status_t 1597 BView::SetEventMask(uint32 mask, uint32 options) 1598 { 1599 if (fEventMask == mask && fEventOptions == options) 1600 return B_OK; 1601 1602 fEventMask = mask | (fEventMask & 0xffff0000); 1603 fEventOptions = options; 1604 1605 fState->archiving_flags |= B_VIEW_EVENT_MASK_BIT; 1606 1607 if (fOwner) { 1608 _CheckLockAndSwitchCurrent(); 1609 1610 fOwner->fLink->StartMessage(AS_VIEW_SET_EVENT_MASK); 1611 fOwner->fLink->Attach<uint32>(mask); 1612 fOwner->fLink->Attach<uint32>(options); 1613 fOwner->fLink->Flush(); 1614 } 1615 1616 return B_OK; 1617 } 1618 1619 1620 uint32 1621 BView::EventMask() 1622 { 1623 return fEventMask; 1624 } 1625 1626 1627 status_t 1628 BView::SetMouseEventMask(uint32 mask, uint32 options) 1629 { 1630 // Just don't do anything if the view is not yet attached 1631 // or we were called outside of BView::MouseDown() 1632 if (fOwner != NULL 1633 && fOwner->CurrentMessage() != NULL 1634 && fOwner->CurrentMessage()->what == B_MOUSE_DOWN) { 1635 _CheckLockAndSwitchCurrent(); 1636 fMouseEventOptions = options; 1637 1638 fOwner->fLink->StartMessage(AS_VIEW_SET_MOUSE_EVENT_MASK); 1639 fOwner->fLink->Attach<uint32>(mask); 1640 fOwner->fLink->Attach<uint32>(options); 1641 fOwner->fLink->Flush(); 1642 return B_OK; 1643 } 1644 1645 return B_ERROR; 1646 } 1647 1648 1649 // #pragma mark - Graphic State Functions 1650 1651 1652 void 1653 BView::PushState() 1654 { 1655 _CheckOwnerLockAndSwitchCurrent(); 1656 1657 fOwner->fLink->StartMessage(AS_VIEW_PUSH_STATE); 1658 1659 // initialize origin and scale 1660 fState->valid_flags |= B_VIEW_SCALE_BIT | B_VIEW_ORIGIN_BIT; 1661 fState->scale = 1.0f; 1662 fState->origin.Set(0, 0); 1663 } 1664 1665 1666 void 1667 BView::PopState() 1668 { 1669 _CheckOwnerLockAndSwitchCurrent(); 1670 1671 fOwner->fLink->StartMessage(AS_VIEW_POP_STATE); 1672 _FlushIfNotInTransaction(); 1673 1674 // invalidate all flags (except those that are not part of pop/push) 1675 fState->valid_flags = B_VIEW_VIEW_COLOR_BIT; 1676 } 1677 1678 1679 void 1680 BView::SetOrigin(BPoint pt) 1681 { 1682 SetOrigin(pt.x, pt.y); 1683 } 1684 1685 1686 void 1687 BView::SetOrigin(float x, float y) 1688 { 1689 if (fState->IsValid(B_VIEW_ORIGIN_BIT) 1690 && x == fState->origin.x && y == fState->origin.y) 1691 return; 1692 1693 fState->origin.x = x; 1694 fState->origin.y = y; 1695 1696 if (_CheckOwnerLockAndSwitchCurrent()) { 1697 fOwner->fLink->StartMessage(AS_VIEW_SET_ORIGIN); 1698 fOwner->fLink->Attach<float>(x); 1699 fOwner->fLink->Attach<float>(y); 1700 1701 fState->valid_flags |= B_VIEW_ORIGIN_BIT; 1702 } 1703 1704 // our local coord system origin has changed, so when archiving we'll add 1705 // this too 1706 fState->archiving_flags |= B_VIEW_ORIGIN_BIT; 1707 } 1708 1709 1710 BPoint 1711 BView::Origin() const 1712 { 1713 if (!fState->IsValid(B_VIEW_ORIGIN_BIT)) { 1714 // we don't keep graphics state information, therefor 1715 // we need to ask the server for the origin after PopState() 1716 _CheckOwnerLockAndSwitchCurrent(); 1717 1718 fOwner->fLink->StartMessage(AS_VIEW_GET_ORIGIN); 1719 1720 int32 code; 1721 if (fOwner->fLink->FlushWithReply(code) == B_OK 1722 && code == B_OK) { 1723 fOwner->fLink->Read<BPoint>(&fState->origin); 1724 1725 fState->valid_flags |= B_VIEW_ORIGIN_BIT; 1726 } 1727 } 1728 1729 return fState->origin; 1730 } 1731 1732 1733 void 1734 BView::SetScale(float scale) const 1735 { 1736 if (fState->IsValid(B_VIEW_SCALE_BIT) && scale == fState->scale) 1737 return; 1738 1739 if (fOwner) { 1740 _CheckLockAndSwitchCurrent(); 1741 1742 fOwner->fLink->StartMessage(AS_VIEW_SET_SCALE); 1743 fOwner->fLink->Attach<float>(scale); 1744 1745 fState->valid_flags |= B_VIEW_SCALE_BIT; 1746 } 1747 1748 fState->scale = scale; 1749 fState->archiving_flags |= B_VIEW_SCALE_BIT; 1750 } 1751 1752 1753 float 1754 BView::Scale() const 1755 { 1756 if (!fState->IsValid(B_VIEW_SCALE_BIT) && fOwner) { 1757 _CheckLockAndSwitchCurrent(); 1758 1759 fOwner->fLink->StartMessage(AS_VIEW_GET_SCALE); 1760 1761 int32 code; 1762 if (fOwner->fLink->FlushWithReply(code) == B_OK 1763 && code == B_OK) 1764 fOwner->fLink->Read<float>(&fState->scale); 1765 1766 fState->valid_flags |= B_VIEW_SCALE_BIT; 1767 } 1768 1769 return fState->scale; 1770 } 1771 1772 1773 void 1774 BView::SetLineMode(cap_mode lineCap, join_mode lineJoin, float miterLimit) 1775 { 1776 if (fState->IsValid(B_VIEW_LINE_MODES_BIT) 1777 && lineCap == fState->line_cap && lineJoin == fState->line_join 1778 && miterLimit == fState->miter_limit) 1779 return; 1780 1781 if (fOwner) { 1782 _CheckLockAndSwitchCurrent(); 1783 1784 fOwner->fLink->StartMessage(AS_VIEW_SET_LINE_MODE); 1785 fOwner->fLink->Attach<int8>((int8)lineCap); 1786 fOwner->fLink->Attach<int8>((int8)lineJoin); 1787 fOwner->fLink->Attach<float>(miterLimit); 1788 1789 fState->valid_flags |= B_VIEW_LINE_MODES_BIT; 1790 } 1791 1792 fState->line_cap = lineCap; 1793 fState->line_join = lineJoin; 1794 fState->miter_limit = miterLimit; 1795 1796 fState->archiving_flags |= B_VIEW_LINE_MODES_BIT; 1797 } 1798 1799 1800 join_mode 1801 BView::LineJoinMode() const 1802 { 1803 // This will update the current state, if necessary 1804 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT)) 1805 LineMiterLimit(); 1806 1807 return fState->line_join; 1808 } 1809 1810 1811 cap_mode 1812 BView::LineCapMode() const 1813 { 1814 // This will update the current state, if necessary 1815 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT)) 1816 LineMiterLimit(); 1817 1818 return fState->line_cap; 1819 } 1820 1821 1822 float 1823 BView::LineMiterLimit() const 1824 { 1825 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT) && fOwner) { 1826 _CheckLockAndSwitchCurrent(); 1827 1828 fOwner->fLink->StartMessage(AS_VIEW_GET_LINE_MODE); 1829 1830 int32 code; 1831 if (fOwner->fLink->FlushWithReply(code) == B_OK 1832 && code == B_OK) { 1833 int8 cap, join; 1834 fOwner->fLink->Read<int8>((int8 *)&cap); 1835 fOwner->fLink->Read<int8>((int8 *)&join); 1836 fOwner->fLink->Read<float>(&fState->miter_limit); 1837 1838 fState->line_cap = (cap_mode)cap; 1839 fState->line_join = (join_mode)join; 1840 } 1841 1842 fState->valid_flags |= B_VIEW_LINE_MODES_BIT; 1843 } 1844 1845 return fState->miter_limit; 1846 } 1847 1848 1849 void 1850 BView::SetDrawingMode(drawing_mode mode) 1851 { 1852 if (fState->IsValid(B_VIEW_DRAWING_MODE_BIT) 1853 && mode == fState->drawing_mode) 1854 return; 1855 1856 if (fOwner) { 1857 _CheckLockAndSwitchCurrent(); 1858 1859 fOwner->fLink->StartMessage(AS_VIEW_SET_DRAWING_MODE); 1860 fOwner->fLink->Attach<int8>((int8)mode); 1861 1862 fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT; 1863 } 1864 1865 fState->drawing_mode = mode; 1866 fState->archiving_flags |= B_VIEW_DRAWING_MODE_BIT; 1867 } 1868 1869 1870 drawing_mode 1871 BView::DrawingMode() const 1872 { 1873 if (!fState->IsValid(B_VIEW_DRAWING_MODE_BIT) && fOwner) { 1874 _CheckLockAndSwitchCurrent(); 1875 1876 fOwner->fLink->StartMessage(AS_VIEW_GET_DRAWING_MODE); 1877 1878 int32 code; 1879 if (fOwner->fLink->FlushWithReply(code) == B_OK 1880 && code == B_OK) { 1881 int8 drawingMode; 1882 fOwner->fLink->Read<int8>(&drawingMode); 1883 1884 fState->drawing_mode = (drawing_mode)drawingMode; 1885 fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT; 1886 } 1887 } 1888 1889 return fState->drawing_mode; 1890 } 1891 1892 1893 void 1894 BView::SetBlendingMode(source_alpha sourceAlpha, alpha_function alphaFunction) 1895 { 1896 if (fState->IsValid(B_VIEW_BLENDING_BIT) 1897 && sourceAlpha == fState->alpha_source_mode 1898 && alphaFunction == fState->alpha_function_mode) 1899 return; 1900 1901 if (fOwner) { 1902 _CheckLockAndSwitchCurrent(); 1903 1904 fOwner->fLink->StartMessage(AS_VIEW_SET_BLENDING_MODE); 1905 fOwner->fLink->Attach<int8>((int8)sourceAlpha); 1906 fOwner->fLink->Attach<int8>((int8)alphaFunction); 1907 1908 fState->valid_flags |= B_VIEW_BLENDING_BIT; 1909 } 1910 1911 fState->alpha_source_mode = sourceAlpha; 1912 fState->alpha_function_mode = alphaFunction; 1913 1914 fState->archiving_flags |= B_VIEW_BLENDING_BIT; 1915 } 1916 1917 1918 void 1919 BView::GetBlendingMode(source_alpha *_sourceAlpha, 1920 alpha_function *_alphaFunction) const 1921 { 1922 if (!fState->IsValid(B_VIEW_BLENDING_BIT) && fOwner) { 1923 _CheckLockAndSwitchCurrent(); 1924 1925 fOwner->fLink->StartMessage(AS_VIEW_GET_BLENDING_MODE); 1926 1927 int32 code; 1928 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) { 1929 int8 alphaSourceMode, alphaFunctionMode; 1930 fOwner->fLink->Read<int8>(&alphaSourceMode); 1931 fOwner->fLink->Read<int8>(&alphaFunctionMode); 1932 1933 fState->alpha_source_mode = (source_alpha)alphaSourceMode; 1934 fState->alpha_function_mode = (alpha_function)alphaFunctionMode; 1935 1936 fState->valid_flags |= B_VIEW_BLENDING_BIT; 1937 } 1938 } 1939 1940 if (_sourceAlpha) 1941 *_sourceAlpha = fState->alpha_source_mode; 1942 1943 if (_alphaFunction) 1944 *_alphaFunction = fState->alpha_function_mode; 1945 } 1946 1947 1948 void 1949 BView::MovePenTo(BPoint point) 1950 { 1951 MovePenTo(point.x, point.y); 1952 } 1953 1954 1955 void 1956 BView::MovePenTo(float x, float y) 1957 { 1958 if (fState->IsValid(B_VIEW_PEN_LOCATION_BIT) 1959 && x == fState->pen_location.x && y == fState->pen_location.y) 1960 return; 1961 1962 if (fOwner) { 1963 _CheckLockAndSwitchCurrent(); 1964 1965 fOwner->fLink->StartMessage(AS_VIEW_SET_PEN_LOC); 1966 fOwner->fLink->Attach<float>(x); 1967 fOwner->fLink->Attach<float>(y); 1968 1969 fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT; 1970 } 1971 1972 fState->pen_location.x = x; 1973 fState->pen_location.y = y; 1974 1975 fState->archiving_flags |= B_VIEW_PEN_LOCATION_BIT; 1976 } 1977 1978 1979 void 1980 BView::MovePenBy(float x, float y) 1981 { 1982 // this will update the pen location if necessary 1983 if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT)) 1984 PenLocation(); 1985 1986 MovePenTo(fState->pen_location.x + x, fState->pen_location.y + y); 1987 } 1988 1989 1990 BPoint 1991 BView::PenLocation() const 1992 { 1993 if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT) && fOwner) { 1994 _CheckLockAndSwitchCurrent(); 1995 1996 fOwner->fLink->StartMessage(AS_VIEW_GET_PEN_LOC); 1997 1998 int32 code; 1999 if (fOwner->fLink->FlushWithReply(code) == B_OK 2000 && code == B_OK) { 2001 fOwner->fLink->Read<BPoint>(&fState->pen_location); 2002 2003 fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT; 2004 } 2005 } 2006 2007 return fState->pen_location; 2008 } 2009 2010 2011 void 2012 BView::SetPenSize(float size) 2013 { 2014 if (fState->IsValid(B_VIEW_PEN_SIZE_BIT) && size == fState->pen_size) 2015 return; 2016 2017 if (fOwner) { 2018 _CheckLockAndSwitchCurrent(); 2019 2020 fOwner->fLink->StartMessage(AS_VIEW_SET_PEN_SIZE); 2021 fOwner->fLink->Attach<float>(size); 2022 2023 fState->valid_flags |= B_VIEW_PEN_SIZE_BIT; 2024 } 2025 2026 fState->pen_size = size; 2027 fState->archiving_flags |= B_VIEW_PEN_SIZE_BIT; 2028 } 2029 2030 2031 float 2032 BView::PenSize() const 2033 { 2034 if (!fState->IsValid(B_VIEW_PEN_SIZE_BIT) && fOwner) { 2035 _CheckLockAndSwitchCurrent(); 2036 2037 fOwner->fLink->StartMessage(AS_VIEW_GET_PEN_SIZE); 2038 2039 int32 code; 2040 if (fOwner->fLink->FlushWithReply(code) == B_OK 2041 && code == B_OK) { 2042 fOwner->fLink->Read<float>(&fState->pen_size); 2043 2044 fState->valid_flags |= B_VIEW_PEN_SIZE_BIT; 2045 } 2046 } 2047 2048 return fState->pen_size; 2049 } 2050 2051 2052 void 2053 BView::SetHighColor(rgb_color color) 2054 { 2055 // are we up-to-date already? 2056 if (fState->IsValid(B_VIEW_HIGH_COLOR_BIT) 2057 && fState->high_color == color) 2058 return; 2059 2060 if (fOwner) { 2061 _CheckLockAndSwitchCurrent(); 2062 2063 fOwner->fLink->StartMessage(AS_VIEW_SET_HIGH_COLOR); 2064 fOwner->fLink->Attach<rgb_color>(color); 2065 2066 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT; 2067 } 2068 2069 fState->high_color = color; 2070 2071 fState->archiving_flags |= B_VIEW_HIGH_COLOR_BIT; 2072 } 2073 2074 2075 rgb_color 2076 BView::HighColor() const 2077 { 2078 if (!fState->IsValid(B_VIEW_HIGH_COLOR_BIT) && fOwner) { 2079 _CheckLockAndSwitchCurrent(); 2080 2081 fOwner->fLink->StartMessage(AS_VIEW_GET_HIGH_COLOR); 2082 2083 int32 code; 2084 if (fOwner->fLink->FlushWithReply(code) == B_OK 2085 && code == B_OK) { 2086 fOwner->fLink->Read<rgb_color>(&fState->high_color); 2087 2088 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT; 2089 } 2090 } 2091 2092 return fState->high_color; 2093 } 2094 2095 2096 void 2097 BView::SetLowColor(rgb_color color) 2098 { 2099 if (fState->IsValid(B_VIEW_LOW_COLOR_BIT) 2100 && fState->low_color == color) 2101 return; 2102 2103 if (fOwner) { 2104 _CheckLockAndSwitchCurrent(); 2105 2106 fOwner->fLink->StartMessage(AS_VIEW_SET_LOW_COLOR); 2107 fOwner->fLink->Attach<rgb_color>(color); 2108 2109 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT; 2110 } 2111 2112 fState->low_color = color; 2113 2114 fState->archiving_flags |= B_VIEW_LOW_COLOR_BIT; 2115 } 2116 2117 2118 rgb_color 2119 BView::LowColor() const 2120 { 2121 if (!fState->IsValid(B_VIEW_LOW_COLOR_BIT) && fOwner) { 2122 _CheckLockAndSwitchCurrent(); 2123 2124 fOwner->fLink->StartMessage(AS_VIEW_GET_LOW_COLOR); 2125 2126 int32 code; 2127 if (fOwner->fLink->FlushWithReply(code) == B_OK 2128 && code == B_OK) { 2129 fOwner->fLink->Read<rgb_color>(&fState->low_color); 2130 2131 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT; 2132 } 2133 } 2134 2135 return fState->low_color; 2136 } 2137 2138 2139 void 2140 BView::SetViewColor(rgb_color color) 2141 { 2142 if (fState->IsValid(B_VIEW_VIEW_COLOR_BIT) && fState->view_color == color) 2143 return; 2144 2145 if (fOwner) { 2146 _CheckLockAndSwitchCurrent(); 2147 2148 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_COLOR); 2149 fOwner->fLink->Attach<rgb_color>(color); 2150 fOwner->fLink->Flush(); 2151 2152 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT; 2153 } 2154 2155 fState->view_color = color; 2156 2157 fState->archiving_flags |= B_VIEW_VIEW_COLOR_BIT; 2158 } 2159 2160 2161 rgb_color 2162 BView::ViewColor() const 2163 { 2164 if (!fState->IsValid(B_VIEW_VIEW_COLOR_BIT) && fOwner) { 2165 _CheckLockAndSwitchCurrent(); 2166 2167 fOwner->fLink->StartMessage(AS_VIEW_GET_VIEW_COLOR); 2168 2169 int32 code; 2170 if (fOwner->fLink->FlushWithReply(code) == B_OK 2171 && code == B_OK) { 2172 fOwner->fLink->Read<rgb_color>(&fState->view_color); 2173 2174 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT; 2175 } 2176 } 2177 2178 return fState->view_color; 2179 } 2180 2181 2182 void 2183 BView::ForceFontAliasing(bool enable) 2184 { 2185 if (fState->IsValid(B_VIEW_FONT_ALIASING_BIT) 2186 && enable == fState->font_aliasing) 2187 return; 2188 2189 if (fOwner) { 2190 _CheckLockAndSwitchCurrent(); 2191 2192 fOwner->fLink->StartMessage(AS_VIEW_PRINT_ALIASING); 2193 fOwner->fLink->Attach<bool>(enable); 2194 2195 fState->valid_flags |= B_VIEW_FONT_ALIASING_BIT; 2196 } 2197 2198 fState->font_aliasing = enable; 2199 fState->archiving_flags |= B_VIEW_FONT_ALIASING_BIT; 2200 } 2201 2202 2203 void 2204 BView::SetFont(const BFont* font, uint32 mask) 2205 { 2206 if (!font || mask == 0) 2207 return; 2208 2209 if (mask == B_FONT_ALL) { 2210 fState->font = *font; 2211 } else { 2212 // ToDo: move this into a BFont method 2213 if (mask & B_FONT_FAMILY_AND_STYLE) 2214 fState->font.SetFamilyAndStyle(font->FamilyAndStyle()); 2215 2216 if (mask & B_FONT_SIZE) 2217 fState->font.SetSize(font->Size()); 2218 2219 if (mask & B_FONT_SHEAR) 2220 fState->font.SetShear(font->Shear()); 2221 2222 if (mask & B_FONT_ROTATION) 2223 fState->font.SetRotation(font->Rotation()); 2224 2225 if (mask & B_FONT_FALSE_BOLD_WIDTH) 2226 fState->font.SetFalseBoldWidth(font->FalseBoldWidth()); 2227 2228 if (mask & B_FONT_SPACING) 2229 fState->font.SetSpacing(font->Spacing()); 2230 2231 if (mask & B_FONT_ENCODING) 2232 fState->font.SetEncoding(font->Encoding()); 2233 2234 if (mask & B_FONT_FACE) 2235 fState->font.SetFace(font->Face()); 2236 2237 if (mask & B_FONT_FLAGS) 2238 fState->font.SetFlags(font->Flags()); 2239 } 2240 2241 fState->font_flags |= mask; 2242 2243 if (fOwner) { 2244 _CheckLockAndSwitchCurrent(); 2245 2246 fState->UpdateServerFontState(*fOwner->fLink); 2247 } 2248 2249 // TODO: InvalidateLayout() here for convenience? 2250 } 2251 2252 2253 void 2254 BView::GetFont(BFont *font) const 2255 { 2256 *font = fState->font; 2257 } 2258 2259 2260 void 2261 BView::GetFontHeight(font_height *height) const 2262 { 2263 fState->font.GetHeight(height); 2264 } 2265 2266 2267 void 2268 BView::SetFontSize(float size) 2269 { 2270 BFont font; 2271 font.SetSize(size); 2272 2273 SetFont(&font, B_FONT_SIZE); 2274 } 2275 2276 2277 float 2278 BView::StringWidth(const char *string) const 2279 { 2280 return fState->font.StringWidth(string); 2281 } 2282 2283 2284 float 2285 BView::StringWidth(const char* string, int32 length) const 2286 { 2287 return fState->font.StringWidth(string, length); 2288 } 2289 2290 2291 void 2292 BView::GetStringWidths(char *stringArray[],int32 lengthArray[], 2293 int32 numStrings, float widthArray[]) const 2294 { 2295 fState->font.GetStringWidths(const_cast<const char **>(stringArray), 2296 const_cast<const int32 *>(lengthArray), numStrings, widthArray); 2297 } 2298 2299 2300 void 2301 BView::TruncateString(BString *in_out, uint32 mode, float width) const 2302 { 2303 fState->font.TruncateString(in_out, mode, width); 2304 } 2305 2306 2307 void 2308 BView::ClipToPicture(BPicture *picture, BPoint where, bool sync) 2309 { 2310 _ClipToPicture(picture, where, false, sync); 2311 } 2312 2313 2314 void 2315 BView::ClipToInversePicture(BPicture *picture, 2316 BPoint where, bool sync) 2317 { 2318 _ClipToPicture(picture, where, true, sync); 2319 } 2320 2321 2322 void 2323 BView::GetClippingRegion(BRegion* region) const 2324 { 2325 if (!region) 2326 return; 2327 2328 // NOTE: the client has no idea when the clipping in the server 2329 // changed, so it is always read from the server 2330 region->MakeEmpty(); 2331 2332 2333 if (fOwner) { 2334 if (fIsPrinting && _CheckOwnerLock()) { 2335 region->Set(fState->print_rect); 2336 return; 2337 } 2338 2339 _CheckLockAndSwitchCurrent(); 2340 fOwner->fLink->StartMessage(AS_VIEW_GET_CLIP_REGION); 2341 2342 int32 code; 2343 if (fOwner->fLink->FlushWithReply(code) == B_OK 2344 && code == B_OK) { 2345 fOwner->fLink->ReadRegion(region); 2346 fState->valid_flags |= B_VIEW_CLIP_REGION_BIT; 2347 } 2348 } 2349 } 2350 2351 2352 void 2353 BView::ConstrainClippingRegion(BRegion* region) 2354 { 2355 if (_CheckOwnerLockAndSwitchCurrent()) { 2356 fOwner->fLink->StartMessage(AS_VIEW_SET_CLIP_REGION); 2357 2358 if (region) { 2359 int32 count = region->CountRects(); 2360 fOwner->fLink->Attach<int32>(count); 2361 if (count > 0) 2362 fOwner->fLink->AttachRegion(*region); 2363 } else { 2364 fOwner->fLink->Attach<int32>(-1); 2365 // '-1' means that in the app_server, there won't be any 'local' 2366 // clipping region (it will be NULL) 2367 } 2368 2369 _FlushIfNotInTransaction(); 2370 2371 fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT; 2372 fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT; 2373 } 2374 } 2375 2376 2377 // #pragma mark - Drawing Functions 2378 2379 2380 void 2381 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect, 2382 uint32 options) 2383 { 2384 if (bitmap == NULL || fOwner == NULL 2385 || !bitmapRect.IsValid() || !viewRect.IsValid()) 2386 return; 2387 2388 _CheckLockAndSwitchCurrent(); 2389 2390 fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP); 2391 fOwner->fLink->Attach<int32>(bitmap->_ServerToken()); 2392 fOwner->fLink->Attach<uint32>(options); 2393 fOwner->fLink->Attach<BRect>(viewRect); 2394 fOwner->fLink->Attach<BRect>(bitmapRect); 2395 2396 _FlushIfNotInTransaction(); 2397 } 2398 2399 2400 void 2401 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect) 2402 { 2403 DrawBitmapAsync(bitmap, bitmapRect, viewRect, 0); 2404 } 2405 2406 2407 void 2408 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect viewRect) 2409 { 2410 if (bitmap && fOwner) { 2411 DrawBitmapAsync(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN), 2412 viewRect, 0); 2413 } 2414 } 2415 2416 2417 void 2418 BView::DrawBitmapAsync(const BBitmap* bitmap, BPoint where) 2419 { 2420 if (bitmap == NULL || fOwner == NULL) 2421 return; 2422 2423 _CheckLockAndSwitchCurrent(); 2424 2425 BRect bitmapRect = bitmap->Bounds().OffsetToCopy(B_ORIGIN); 2426 BRect viewRect = bitmapRect.OffsetToCopy(where); 2427 uint32 options = 0; 2428 2429 fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP); 2430 fOwner->fLink->Attach<int32>(bitmap->_ServerToken()); 2431 fOwner->fLink->Attach<uint32>(options); 2432 fOwner->fLink->Attach<BRect>(viewRect); 2433 fOwner->fLink->Attach<BRect>(bitmapRect); 2434 2435 _FlushIfNotInTransaction(); 2436 } 2437 2438 2439 void 2440 BView::DrawBitmapAsync(const BBitmap* bitmap) 2441 { 2442 DrawBitmapAsync(bitmap, PenLocation()); 2443 } 2444 2445 2446 void 2447 BView::DrawBitmap(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect, 2448 uint32 options) 2449 { 2450 if (fOwner) { 2451 DrawBitmapAsync(bitmap, bitmapRect, viewRect, options); 2452 Sync(); 2453 } 2454 } 2455 2456 2457 void 2458 BView::DrawBitmap(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect) 2459 { 2460 if (fOwner) { 2461 DrawBitmapAsync(bitmap, bitmapRect, viewRect, 0); 2462 Sync(); 2463 } 2464 } 2465 2466 2467 void 2468 BView::DrawBitmap(const BBitmap* bitmap, BRect viewRect) 2469 { 2470 if (bitmap && fOwner) { 2471 DrawBitmap(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN), viewRect, 2472 0); 2473 } 2474 } 2475 2476 2477 void 2478 BView::DrawBitmap(const BBitmap* bitmap, BPoint where) 2479 { 2480 if (fOwner) { 2481 DrawBitmapAsync(bitmap, where); 2482 Sync(); 2483 } 2484 } 2485 2486 2487 void 2488 BView::DrawBitmap(const BBitmap* bitmap) 2489 { 2490 DrawBitmap(bitmap, PenLocation()); 2491 } 2492 2493 2494 void 2495 BView::DrawChar(char c) 2496 { 2497 DrawString(&c, 1, PenLocation()); 2498 } 2499 2500 2501 void 2502 BView::DrawChar(char c, BPoint location) 2503 { 2504 DrawString(&c, 1, location); 2505 } 2506 2507 2508 void 2509 BView::DrawString(const char *string, escapement_delta *delta) 2510 { 2511 if (string == NULL) 2512 return; 2513 2514 DrawString(string, strlen(string), PenLocation(), delta); 2515 } 2516 2517 2518 void 2519 BView::DrawString(const char *string, BPoint location, escapement_delta *delta) 2520 { 2521 if (string == NULL) 2522 return; 2523 2524 DrawString(string, strlen(string), location, delta); 2525 } 2526 2527 2528 void 2529 BView::DrawString(const char *string, int32 length, escapement_delta *delta) 2530 { 2531 DrawString(string, length, PenLocation(), delta); 2532 } 2533 2534 2535 void 2536 BView::DrawString(const char *string, int32 length, BPoint location, 2537 escapement_delta *delta) 2538 { 2539 if (string == NULL || length < 1) 2540 return; 2541 2542 if (fOwner) { 2543 _CheckLockAndSwitchCurrent(); 2544 2545 // quite often delta will be NULL 2546 if (delta) 2547 fOwner->fLink->StartMessage(AS_DRAW_STRING_WITH_DELTA); 2548 else 2549 fOwner->fLink->StartMessage(AS_DRAW_STRING); 2550 fOwner->fLink->Attach<int32>(length); 2551 fOwner->fLink->Attach<BPoint>(location); 2552 2553 if (delta) 2554 fOwner->fLink->Attach<escapement_delta>(*delta); 2555 2556 fOwner->fLink->AttachString(string, length); 2557 2558 _FlushIfNotInTransaction(); 2559 2560 // this modifies our pen location, so we invalidate the flag. 2561 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT; 2562 } 2563 } 2564 2565 2566 void 2567 BView::StrokeEllipse(BPoint center, float xRadius, float yRadius, 2568 ::pattern pattern) 2569 { 2570 StrokeEllipse(BRect(center.x - xRadius, center.y - yRadius, 2571 center.x + xRadius, center.y + yRadius), pattern); 2572 } 2573 2574 2575 void 2576 BView::StrokeEllipse(BRect rect, ::pattern pattern) 2577 { 2578 if (fOwner == NULL) 2579 return; 2580 2581 _CheckLockAndSwitchCurrent(); 2582 _UpdatePattern(pattern); 2583 2584 fOwner->fLink->StartMessage(AS_STROKE_ELLIPSE); 2585 fOwner->fLink->Attach<BRect>(rect); 2586 2587 _FlushIfNotInTransaction(); 2588 } 2589 2590 2591 void 2592 BView::FillEllipse(BPoint center, float xRadius, float yRadius, 2593 ::pattern pattern) 2594 { 2595 FillEllipse(BRect(center.x - xRadius, center.y - yRadius, 2596 center.x + xRadius, center.y + yRadius), pattern); 2597 } 2598 2599 2600 void 2601 BView::FillEllipse(BPoint center, float xRadius, float yRadius, 2602 const BGradient& gradient) 2603 { 2604 FillEllipse(BRect(center.x - xRadius, center.y - yRadius, 2605 center.x + xRadius, center.y + yRadius), gradient); 2606 } 2607 2608 2609 void 2610 BView::FillEllipse(BRect rect, ::pattern pattern) 2611 { 2612 if (fOwner == NULL) 2613 return; 2614 2615 _CheckLockAndSwitchCurrent(); 2616 _UpdatePattern(pattern); 2617 2618 fOwner->fLink->StartMessage(AS_FILL_ELLIPSE); 2619 fOwner->fLink->Attach<BRect>(rect); 2620 2621 _FlushIfNotInTransaction(); 2622 } 2623 2624 2625 void 2626 BView::FillEllipse(BRect rect, const BGradient& gradient) 2627 { 2628 if (fOwner == NULL) 2629 return; 2630 2631 _CheckLockAndSwitchCurrent(); 2632 2633 fOwner->fLink->StartMessage(AS_FILL_ELLIPSE_GRADIENT); 2634 fOwner->fLink->Attach<BRect>(rect); 2635 fOwner->fLink->AttachGradient(gradient); 2636 2637 _FlushIfNotInTransaction(); 2638 } 2639 2640 2641 void 2642 BView::StrokeArc(BPoint center, float xRadius, float yRadius, float startAngle, 2643 float arcAngle, ::pattern pattern) 2644 { 2645 StrokeArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius, 2646 center.y + yRadius), startAngle, arcAngle, pattern); 2647 } 2648 2649 2650 void 2651 BView::StrokeArc(BRect rect, float startAngle, float arcAngle, 2652 ::pattern pattern) 2653 { 2654 if (fOwner == NULL) 2655 return; 2656 2657 _CheckLockAndSwitchCurrent(); 2658 _UpdatePattern(pattern); 2659 2660 fOwner->fLink->StartMessage(AS_STROKE_ARC); 2661 fOwner->fLink->Attach<BRect>(rect); 2662 fOwner->fLink->Attach<float>(startAngle); 2663 fOwner->fLink->Attach<float>(arcAngle); 2664 2665 _FlushIfNotInTransaction(); 2666 } 2667 2668 2669 void 2670 BView::FillArc(BPoint center,float xRadius, float yRadius, float startAngle, 2671 float arcAngle, ::pattern pattern) 2672 { 2673 FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius, 2674 center.y + yRadius), startAngle, arcAngle, pattern); 2675 } 2676 2677 2678 void 2679 BView::FillArc(BPoint center,float xRadius, float yRadius, float startAngle, 2680 float arcAngle, const BGradient& gradient) 2681 { 2682 FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius, 2683 center.y + yRadius), startAngle, arcAngle, gradient); 2684 } 2685 2686 2687 void 2688 BView::FillArc(BRect rect, float startAngle, float arcAngle, 2689 ::pattern pattern) 2690 { 2691 if (fOwner == NULL) 2692 return; 2693 2694 _CheckLockAndSwitchCurrent(); 2695 _UpdatePattern(pattern); 2696 2697 fOwner->fLink->StartMessage(AS_FILL_ARC); 2698 fOwner->fLink->Attach<BRect>(rect); 2699 fOwner->fLink->Attach<float>(startAngle); 2700 fOwner->fLink->Attach<float>(arcAngle); 2701 2702 _FlushIfNotInTransaction(); 2703 } 2704 2705 2706 void 2707 BView::FillArc(BRect rect, float startAngle, float arcAngle, 2708 const BGradient& gradient) 2709 { 2710 if (fOwner == NULL) 2711 return; 2712 2713 _CheckLockAndSwitchCurrent(); 2714 2715 fOwner->fLink->StartMessage(AS_FILL_ARC_GRADIENT); 2716 fOwner->fLink->Attach<BRect>(rect); 2717 fOwner->fLink->Attach<float>(startAngle); 2718 fOwner->fLink->Attach<float>(arcAngle); 2719 fOwner->fLink->AttachGradient(gradient); 2720 2721 _FlushIfNotInTransaction(); 2722 } 2723 2724 2725 void 2726 BView::StrokeBezier(BPoint *controlPoints, ::pattern pattern) 2727 { 2728 if (fOwner == NULL) 2729 return; 2730 2731 _CheckLockAndSwitchCurrent(); 2732 _UpdatePattern(pattern); 2733 2734 fOwner->fLink->StartMessage(AS_STROKE_BEZIER); 2735 fOwner->fLink->Attach<BPoint>(controlPoints[0]); 2736 fOwner->fLink->Attach<BPoint>(controlPoints[1]); 2737 fOwner->fLink->Attach<BPoint>(controlPoints[2]); 2738 fOwner->fLink->Attach<BPoint>(controlPoints[3]); 2739 2740 _FlushIfNotInTransaction(); 2741 } 2742 2743 2744 void 2745 BView::FillBezier(BPoint *controlPoints, ::pattern pattern) 2746 { 2747 if (fOwner == NULL) 2748 return; 2749 2750 _CheckLockAndSwitchCurrent(); 2751 _UpdatePattern(pattern); 2752 2753 fOwner->fLink->StartMessage(AS_FILL_BEZIER); 2754 fOwner->fLink->Attach<BPoint>(controlPoints[0]); 2755 fOwner->fLink->Attach<BPoint>(controlPoints[1]); 2756 fOwner->fLink->Attach<BPoint>(controlPoints[2]); 2757 fOwner->fLink->Attach<BPoint>(controlPoints[3]); 2758 2759 _FlushIfNotInTransaction(); 2760 } 2761 2762 2763 void 2764 BView::FillBezier(BPoint *controlPoints, const BGradient& gradient) 2765 { 2766 if (fOwner == NULL) 2767 return; 2768 2769 _CheckLockAndSwitchCurrent(); 2770 2771 fOwner->fLink->StartMessage(AS_FILL_BEZIER_GRADIENT); 2772 fOwner->fLink->Attach<BPoint>(controlPoints[0]); 2773 fOwner->fLink->Attach<BPoint>(controlPoints[1]); 2774 fOwner->fLink->Attach<BPoint>(controlPoints[2]); 2775 fOwner->fLink->Attach<BPoint>(controlPoints[3]); 2776 fOwner->fLink->AttachGradient(gradient); 2777 2778 _FlushIfNotInTransaction(); 2779 } 2780 2781 2782 void 2783 BView::StrokePolygon(const BPolygon *polygon, bool closed, ::pattern pattern) 2784 { 2785 if (!polygon) 2786 return; 2787 2788 StrokePolygon(polygon->fPoints, polygon->fCount, polygon->Frame(), closed, 2789 pattern); 2790 } 2791 2792 2793 void 2794 BView::StrokePolygon(const BPoint* pointArray, int32 numPoints, bool closed, 2795 ::pattern pattern) 2796 { 2797 BPolygon polygon(pointArray, numPoints); 2798 2799 StrokePolygon(polygon.fPoints, polygon.fCount, polygon.Frame(), closed, 2800 pattern); 2801 } 2802 2803 2804 void 2805 BView::StrokePolygon(const BPoint *ptArray, int32 numPoints, BRect bounds, 2806 bool closed, ::pattern pattern) 2807 { 2808 if (!ptArray 2809 || numPoints <= 1 2810 || fOwner == NULL) 2811 return; 2812 2813 _CheckLockAndSwitchCurrent(); 2814 _UpdatePattern(pattern); 2815 2816 BPolygon polygon(ptArray, numPoints); 2817 polygon.MapTo(polygon.Frame(), bounds); 2818 2819 if (fOwner->fLink->StartMessage(AS_STROKE_POLYGON, 2820 polygon.fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(bool) 2821 + sizeof(int32)) == B_OK) { 2822 fOwner->fLink->Attach<BRect>(polygon.Frame()); 2823 fOwner->fLink->Attach<bool>(closed); 2824 fOwner->fLink->Attach<int32>(polygon.fCount); 2825 fOwner->fLink->Attach(polygon.fPoints, polygon.fCount * sizeof(BPoint)); 2826 2827 _FlushIfNotInTransaction(); 2828 } else { 2829 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n"); 2830 } 2831 } 2832 2833 2834 void 2835 BView::FillPolygon(const BPolygon *polygon, ::pattern pattern) 2836 { 2837 if (polygon == NULL 2838 || polygon->fCount <= 2 2839 || fOwner == NULL) 2840 return; 2841 2842 _CheckLockAndSwitchCurrent(); 2843 _UpdatePattern(pattern); 2844 2845 if (fOwner->fLink->StartMessage(AS_FILL_POLYGON, 2846 polygon->fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(int32)) 2847 == B_OK) { 2848 fOwner->fLink->Attach<BRect>(polygon->Frame()); 2849 fOwner->fLink->Attach<int32>(polygon->fCount); 2850 fOwner->fLink->Attach(polygon->fPoints, 2851 polygon->fCount * sizeof(BPoint)); 2852 2853 _FlushIfNotInTransaction(); 2854 } else { 2855 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n"); 2856 } 2857 } 2858 2859 2860 void 2861 BView::FillPolygon(const BPolygon *polygon, const BGradient& gradient) 2862 { 2863 if (polygon == NULL 2864 || polygon->fCount <= 2 2865 || fOwner == NULL) 2866 return; 2867 2868 _CheckLockAndSwitchCurrent(); 2869 2870 if (fOwner->fLink->StartMessage(AS_FILL_POLYGON_GRADIENT, 2871 polygon->fCount * sizeof(BPoint) 2872 + sizeof(BRect) + sizeof(int32)) == B_OK) { 2873 fOwner->fLink->Attach<BRect>(polygon->Frame()); 2874 fOwner->fLink->Attach<int32>(polygon->fCount); 2875 fOwner->fLink->Attach(polygon->fPoints, 2876 polygon->fCount * sizeof(BPoint)); 2877 fOwner->fLink->AttachGradient(gradient); 2878 2879 _FlushIfNotInTransaction(); 2880 } else { 2881 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n"); 2882 } 2883 } 2884 2885 2886 void 2887 BView::FillPolygon(const BPoint *ptArray, int32 numPts, ::pattern pattern) 2888 { 2889 if (!ptArray) 2890 return; 2891 2892 BPolygon polygon(ptArray, numPts); 2893 FillPolygon(&polygon, pattern); 2894 } 2895 2896 2897 void 2898 BView::FillPolygon(const BPoint *ptArray, int32 numPts, 2899 const BGradient& gradient) 2900 { 2901 if (!ptArray) 2902 return; 2903 2904 BPolygon polygon(ptArray, numPts); 2905 FillPolygon(&polygon, gradient); 2906 } 2907 2908 2909 void 2910 BView::FillPolygon(const BPoint *ptArray, int32 numPts, BRect bounds, 2911 pattern p) 2912 { 2913 if (!ptArray) 2914 return; 2915 2916 BPolygon polygon(ptArray, numPts); 2917 2918 polygon.MapTo(polygon.Frame(), bounds); 2919 FillPolygon(&polygon, p); 2920 } 2921 2922 2923 void 2924 BView::FillPolygon(const BPoint *ptArray, int32 numPts, BRect bounds, 2925 const BGradient& gradient) 2926 { 2927 if (!ptArray) 2928 return; 2929 2930 BPolygon polygon(ptArray, numPts); 2931 2932 polygon.MapTo(polygon.Frame(), bounds); 2933 FillPolygon(&polygon, gradient); 2934 } 2935 2936 2937 void 2938 BView::StrokeRect(BRect rect, ::pattern pattern) 2939 { 2940 if (fOwner == NULL) 2941 return; 2942 2943 _CheckLockAndSwitchCurrent(); 2944 _UpdatePattern(pattern); 2945 2946 fOwner->fLink->StartMessage(AS_STROKE_RECT); 2947 fOwner->fLink->Attach<BRect>(rect); 2948 2949 _FlushIfNotInTransaction(); 2950 } 2951 2952 2953 void 2954 BView::FillRect(BRect rect, ::pattern pattern) 2955 { 2956 if (fOwner == NULL) 2957 return; 2958 2959 // NOTE: ensuring compatibility with R5, 2960 // invalid rects are not filled, they are stroked though! 2961 if (!rect.IsValid()) 2962 return; 2963 2964 _CheckLockAndSwitchCurrent(); 2965 _UpdatePattern(pattern); 2966 2967 fOwner->fLink->StartMessage(AS_FILL_RECT); 2968 fOwner->fLink->Attach<BRect>(rect); 2969 2970 _FlushIfNotInTransaction(); 2971 } 2972 2973 2974 void 2975 BView::FillRect(BRect rect, const BGradient& gradient) 2976 { 2977 if (fOwner == NULL) 2978 return; 2979 2980 // NOTE: ensuring compatibility with R5, 2981 // invalid rects are not filled, they are stroked though! 2982 if (!rect.IsValid()) 2983 return; 2984 2985 _CheckLockAndSwitchCurrent(); 2986 2987 fOwner->fLink->StartMessage(AS_FILL_RECT_GRADIENT); 2988 fOwner->fLink->Attach<BRect>(rect); 2989 fOwner->fLink->AttachGradient(gradient); 2990 2991 _FlushIfNotInTransaction(); 2992 } 2993 2994 2995 void 2996 BView::StrokeRoundRect(BRect rect, float xRadius, float yRadius, 2997 ::pattern pattern) 2998 { 2999 if (fOwner == NULL) 3000 return; 3001 3002 _CheckLockAndSwitchCurrent(); 3003 _UpdatePattern(pattern); 3004 3005 fOwner->fLink->StartMessage(AS_STROKE_ROUNDRECT); 3006 fOwner->fLink->Attach<BRect>(rect); 3007 fOwner->fLink->Attach<float>(xRadius); 3008 fOwner->fLink->Attach<float>(yRadius); 3009 3010 _FlushIfNotInTransaction(); 3011 } 3012 3013 3014 void 3015 BView::FillRoundRect(BRect rect, float xRadius, float yRadius, 3016 ::pattern pattern) 3017 { 3018 if (fOwner == NULL) 3019 return; 3020 3021 _CheckLockAndSwitchCurrent(); 3022 3023 _UpdatePattern(pattern); 3024 3025 fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT); 3026 fOwner->fLink->Attach<BRect>(rect); 3027 fOwner->fLink->Attach<float>(xRadius); 3028 fOwner->fLink->Attach<float>(yRadius); 3029 3030 _FlushIfNotInTransaction(); 3031 } 3032 3033 3034 void 3035 BView::FillRoundRect(BRect rect, float xRadius, float yRadius, 3036 const BGradient& gradient) 3037 { 3038 if (fOwner == NULL) 3039 return; 3040 3041 _CheckLockAndSwitchCurrent(); 3042 3043 fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT_GRADIENT); 3044 fOwner->fLink->Attach<BRect>(rect); 3045 fOwner->fLink->Attach<float>(xRadius); 3046 fOwner->fLink->Attach<float>(yRadius); 3047 fOwner->fLink->AttachGradient(gradient); 3048 3049 _FlushIfNotInTransaction(); 3050 } 3051 3052 3053 void 3054 BView::FillRegion(BRegion *region, ::pattern pattern) 3055 { 3056 if (region == NULL || fOwner == NULL) 3057 return; 3058 3059 _CheckLockAndSwitchCurrent(); 3060 3061 _UpdatePattern(pattern); 3062 3063 fOwner->fLink->StartMessage(AS_FILL_REGION); 3064 fOwner->fLink->AttachRegion(*region); 3065 3066 _FlushIfNotInTransaction(); 3067 } 3068 3069 3070 void 3071 BView::FillRegion(BRegion *region, const BGradient& gradient) 3072 { 3073 if (region == NULL || fOwner == NULL) 3074 return; 3075 3076 _CheckLockAndSwitchCurrent(); 3077 3078 fOwner->fLink->StartMessage(AS_FILL_REGION_GRADIENT); 3079 fOwner->fLink->AttachRegion(*region); 3080 fOwner->fLink->AttachGradient(gradient); 3081 3082 _FlushIfNotInTransaction(); 3083 } 3084 3085 3086 void 3087 BView::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, BRect bounds, 3088 ::pattern pattern) 3089 { 3090 if (fOwner == NULL) 3091 return; 3092 3093 _CheckLockAndSwitchCurrent(); 3094 3095 _UpdatePattern(pattern); 3096 3097 fOwner->fLink->StartMessage(AS_STROKE_TRIANGLE); 3098 fOwner->fLink->Attach<BPoint>(pt1); 3099 fOwner->fLink->Attach<BPoint>(pt2); 3100 fOwner->fLink->Attach<BPoint>(pt3); 3101 fOwner->fLink->Attach<BRect>(bounds); 3102 3103 _FlushIfNotInTransaction(); 3104 } 3105 3106 3107 void 3108 BView::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, pattern p) 3109 { 3110 if (fOwner) { 3111 // we construct the smallest rectangle that contains the 3 points 3112 // for the 1st point 3113 BRect bounds(pt1, pt1); 3114 3115 // for the 2nd point 3116 if (pt2.x < bounds.left) 3117 bounds.left = pt2.x; 3118 3119 if (pt2.y < bounds.top) 3120 bounds.top = pt2.y; 3121 3122 if (pt2.x > bounds.right) 3123 bounds.right = pt2.x; 3124 3125 if (pt2.y > bounds.bottom) 3126 bounds.bottom = pt2.y; 3127 3128 // for the 3rd point 3129 if (pt3.x < bounds.left) 3130 bounds.left = pt3.x; 3131 3132 if (pt3.y < bounds.top) 3133 bounds.top = pt3.y; 3134 3135 if (pt3.x > bounds.right) 3136 bounds.right = pt3.x; 3137 3138 if (pt3.y > bounds.bottom) 3139 bounds.bottom = pt3.y; 3140 3141 StrokeTriangle(pt1, pt2, pt3, bounds, p); 3142 } 3143 } 3144 3145 3146 void 3147 BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, pattern p) 3148 { 3149 if (fOwner) { 3150 // we construct the smallest rectangle that contains the 3 points 3151 // for the 1st point 3152 BRect bounds(pt1, pt1); 3153 3154 // for the 2nd point 3155 if (pt2.x < bounds.left) 3156 bounds.left = pt2.x; 3157 3158 if (pt2.y < bounds.top) 3159 bounds.top = pt2.y; 3160 3161 if (pt2.x > bounds.right) 3162 bounds.right = pt2.x; 3163 3164 if (pt2.y > bounds.bottom) 3165 bounds.bottom = pt2.y; 3166 3167 // for the 3rd point 3168 if (pt3.x < bounds.left) 3169 bounds.left = pt3.x; 3170 3171 if (pt3.y < bounds.top) 3172 bounds.top = pt3.y; 3173 3174 if (pt3.x > bounds.right) 3175 bounds.right = pt3.x; 3176 3177 if (pt3.y > bounds.bottom) 3178 bounds.bottom = pt3.y; 3179 3180 FillTriangle(pt1, pt2, pt3, bounds, p); 3181 } 3182 } 3183 3184 3185 void 3186 BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, 3187 const BGradient& gradient) 3188 { 3189 if (fOwner) { 3190 // we construct the smallest rectangle that contains the 3 points 3191 // for the 1st point 3192 BRect bounds(pt1, pt1); 3193 3194 // for the 2nd point 3195 if (pt2.x < bounds.left) 3196 bounds.left = pt2.x; 3197 3198 if (pt2.y < bounds.top) 3199 bounds.top = pt2.y; 3200 3201 if (pt2.x > bounds.right) 3202 bounds.right = pt2.x; 3203 3204 if (pt2.y > bounds.bottom) 3205 bounds.bottom = pt2.y; 3206 3207 // for the 3rd point 3208 if (pt3.x < bounds.left) 3209 bounds.left = pt3.x; 3210 3211 if (pt3.y < bounds.top) 3212 bounds.top = pt3.y; 3213 3214 if (pt3.x > bounds.right) 3215 bounds.right = pt3.x; 3216 3217 if (pt3.y > bounds.bottom) 3218 bounds.bottom = pt3.y; 3219 3220 FillTriangle(pt1, pt2, pt3, bounds, gradient); 3221 } 3222 } 3223 3224 3225 void 3226 BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, 3227 BRect bounds, ::pattern pattern) 3228 { 3229 if (fOwner == NULL) 3230 return; 3231 3232 _CheckLockAndSwitchCurrent(); 3233 _UpdatePattern(pattern); 3234 3235 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE); 3236 fOwner->fLink->Attach<BPoint>(pt1); 3237 fOwner->fLink->Attach<BPoint>(pt2); 3238 fOwner->fLink->Attach<BPoint>(pt3); 3239 fOwner->fLink->Attach<BRect>(bounds); 3240 3241 _FlushIfNotInTransaction(); 3242 } 3243 3244 3245 void 3246 BView::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, 3247 BRect bounds, const BGradient& gradient) 3248 { 3249 if (fOwner == NULL) 3250 return; 3251 3252 _CheckLockAndSwitchCurrent(); 3253 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE_GRADIENT); 3254 fOwner->fLink->Attach<BPoint>(pt1); 3255 fOwner->fLink->Attach<BPoint>(pt2); 3256 fOwner->fLink->Attach<BPoint>(pt3); 3257 fOwner->fLink->Attach<BRect>(bounds); 3258 fOwner->fLink->AttachGradient(gradient); 3259 3260 _FlushIfNotInTransaction(); 3261 } 3262 3263 3264 void 3265 BView::StrokeLine(BPoint toPt, pattern p) 3266 { 3267 StrokeLine(PenLocation(), toPt, p); 3268 } 3269 3270 3271 void 3272 BView::StrokeLine(BPoint pt0, BPoint pt1, ::pattern pattern) 3273 { 3274 if (fOwner == NULL) 3275 return; 3276 3277 _CheckLockAndSwitchCurrent(); 3278 _UpdatePattern(pattern); 3279 3280 fOwner->fLink->StartMessage(AS_STROKE_LINE); 3281 fOwner->fLink->Attach<BPoint>(pt0); 3282 fOwner->fLink->Attach<BPoint>(pt1); 3283 3284 _FlushIfNotInTransaction(); 3285 3286 // this modifies our pen location, so we invalidate the flag. 3287 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT; 3288 } 3289 3290 3291 void 3292 BView::StrokeShape(BShape *shape, ::pattern pattern) 3293 { 3294 if (shape == NULL || fOwner == NULL) 3295 return; 3296 3297 shape_data *sd = (shape_data *)shape->fPrivateData; 3298 if (sd->opCount == 0 || sd->ptCount == 0) 3299 return; 3300 3301 _CheckLockAndSwitchCurrent(); 3302 _UpdatePattern(pattern); 3303 3304 fOwner->fLink->StartMessage(AS_STROKE_SHAPE); 3305 fOwner->fLink->Attach<BRect>(shape->Bounds()); 3306 fOwner->fLink->Attach<int32>(sd->opCount); 3307 fOwner->fLink->Attach<int32>(sd->ptCount); 3308 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(uint32)); 3309 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 3310 3311 _FlushIfNotInTransaction(); 3312 } 3313 3314 3315 void 3316 BView::FillShape(BShape *shape, ::pattern pattern) 3317 { 3318 if (shape == NULL || fOwner == NULL) 3319 return; 3320 3321 shape_data *sd = (shape_data *)(shape->fPrivateData); 3322 if (sd->opCount == 0 || sd->ptCount == 0) 3323 return; 3324 3325 _CheckLockAndSwitchCurrent(); 3326 _UpdatePattern(pattern); 3327 3328 fOwner->fLink->StartMessage(AS_FILL_SHAPE); 3329 fOwner->fLink->Attach<BRect>(shape->Bounds()); 3330 fOwner->fLink->Attach<int32>(sd->opCount); 3331 fOwner->fLink->Attach<int32>(sd->ptCount); 3332 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32)); 3333 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 3334 3335 _FlushIfNotInTransaction(); 3336 } 3337 3338 3339 void 3340 BView::FillShape(BShape *shape, const BGradient& gradient) 3341 { 3342 if (shape == NULL || fOwner == NULL) 3343 return; 3344 3345 shape_data *sd = (shape_data *)(shape->fPrivateData); 3346 if (sd->opCount == 0 || sd->ptCount == 0) 3347 return; 3348 3349 _CheckLockAndSwitchCurrent(); 3350 3351 fOwner->fLink->StartMessage(AS_FILL_SHAPE_GRADIENT); 3352 fOwner->fLink->Attach<BRect>(shape->Bounds()); 3353 fOwner->fLink->Attach<int32>(sd->opCount); 3354 fOwner->fLink->Attach<int32>(sd->ptCount); 3355 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32)); 3356 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 3357 fOwner->fLink->AttachGradient(gradient); 3358 3359 _FlushIfNotInTransaction(); 3360 } 3361 3362 3363 void 3364 BView::BeginLineArray(int32 count) 3365 { 3366 if (fOwner == NULL) 3367 return; 3368 3369 if (count <= 0) 3370 debugger("Calling BeginLineArray with a count <= 0"); 3371 3372 _CheckLock(); 3373 3374 if (fCommArray) { 3375 debugger("Can't nest BeginLineArray calls"); 3376 // not fatal, but it helps during 3377 // development of your app and is in 3378 // line with R5... 3379 delete[] fCommArray->array; 3380 delete fCommArray; 3381 } 3382 3383 // TODO: since this method cannot return failure, and further AddLine() 3384 // calls with a NULL fCommArray would drop into the debugger anyway, 3385 // we allow the possible std::bad_alloc exceptions here... 3386 fCommArray = new _array_data_; 3387 fCommArray->maxCount = count; 3388 fCommArray->count = 0; 3389 fCommArray->array = new _array_hdr_[count]; 3390 } 3391 3392 3393 void 3394 BView::AddLine(BPoint pt0, BPoint pt1, rgb_color col) 3395 { 3396 if (fOwner == NULL) 3397 return; 3398 3399 if (!fCommArray) 3400 debugger("BeginLineArray must be called before using AddLine"); 3401 3402 _CheckLock(); 3403 3404 const uint32 &arrayCount = fCommArray->count; 3405 if (arrayCount < fCommArray->maxCount) { 3406 fCommArray->array[arrayCount].startX = pt0.x; 3407 fCommArray->array[arrayCount].startY = pt0.y; 3408 fCommArray->array[arrayCount].endX = pt1.x; 3409 fCommArray->array[arrayCount].endY = pt1.y; 3410 fCommArray->array[arrayCount].color = col; 3411 3412 fCommArray->count++; 3413 } 3414 } 3415 3416 3417 void 3418 BView::EndLineArray() 3419 { 3420 if (fOwner == NULL) 3421 return; 3422 3423 if (!fCommArray) 3424 debugger("Can't call EndLineArray before BeginLineArray"); 3425 3426 _CheckLockAndSwitchCurrent(); 3427 3428 fOwner->fLink->StartMessage(AS_STROKE_LINEARRAY); 3429 fOwner->fLink->Attach<int32>(fCommArray->count); 3430 fOwner->fLink->Attach(fCommArray->array, 3431 fCommArray->count * sizeof(_array_hdr_)); 3432 3433 _FlushIfNotInTransaction(); 3434 3435 _RemoveCommArray(); 3436 } 3437 3438 3439 void 3440 BView::SetDiskMode(char* filename, long offset) 3441 { 3442 // TODO: implement 3443 // One BeBook version has this to say about SetDiskMode(): 3444 // 3445 // "Begins recording a picture to the file with the given filename 3446 // at the given offset. Subsequent drawing commands sent to the view 3447 // will be written to the file until EndPicture() is called. The 3448 // stored commands may be played from the file with DrawPicture()." 3449 } 3450 3451 3452 void 3453 BView::BeginPicture(BPicture *picture) 3454 { 3455 if (_CheckOwnerLockAndSwitchCurrent() 3456 && picture && picture->fUsurped == NULL) { 3457 picture->Usurp(fCurrentPicture); 3458 fCurrentPicture = picture; 3459 3460 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_PICTURE); 3461 } 3462 } 3463 3464 3465 void 3466 BView::AppendToPicture(BPicture *picture) 3467 { 3468 _CheckLockAndSwitchCurrent(); 3469 3470 if (picture && picture->fUsurped == NULL) { 3471 int32 token = picture->Token(); 3472 3473 if (token == -1) { 3474 BeginPicture(picture); 3475 } else { 3476 picture->SetToken(-1); 3477 picture->Usurp(fCurrentPicture); 3478 fCurrentPicture = picture; 3479 fOwner->fLink->StartMessage(AS_VIEW_APPEND_TO_PICTURE); 3480 fOwner->fLink->Attach<int32>(token); 3481 } 3482 } 3483 } 3484 3485 3486 BPicture * 3487 BView::EndPicture() 3488 { 3489 if (_CheckOwnerLockAndSwitchCurrent() && fCurrentPicture) { 3490 int32 token; 3491 3492 fOwner->fLink->StartMessage(AS_VIEW_END_PICTURE); 3493 3494 int32 code; 3495 if (fOwner->fLink->FlushWithReply(code) == B_OK 3496 && code == B_OK 3497 && fOwner->fLink->Read<int32>(&token) == B_OK) { 3498 BPicture *picture = fCurrentPicture; 3499 fCurrentPicture = picture->StepDown(); 3500 picture->SetToken(token); 3501 3502 return picture; 3503 } 3504 } 3505 3506 return NULL; 3507 } 3508 3509 3510 void 3511 BView::SetViewBitmap(const BBitmap *bitmap, BRect srcRect, BRect dstRect, 3512 uint32 followFlags, uint32 options) 3513 { 3514 _SetViewBitmap(bitmap, srcRect, dstRect, followFlags, options); 3515 } 3516 3517 3518 void 3519 BView::SetViewBitmap(const BBitmap *bitmap, uint32 followFlags, uint32 options) 3520 { 3521 BRect rect; 3522 if (bitmap) 3523 rect = bitmap->Bounds(); 3524 3525 rect.OffsetTo(B_ORIGIN); 3526 3527 _SetViewBitmap(bitmap, rect, rect, followFlags, options); 3528 } 3529 3530 3531 void 3532 BView::ClearViewBitmap() 3533 { 3534 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0); 3535 } 3536 3537 3538 status_t 3539 BView::SetViewOverlay(const BBitmap *overlay, BRect srcRect, BRect dstRect, 3540 rgb_color *colorKey, uint32 followFlags, uint32 options) 3541 { 3542 if ((overlay->fFlags & B_BITMAP_WILL_OVERLAY) == 0) 3543 return B_BAD_VALUE; 3544 3545 status_t status = _SetViewBitmap(overlay, srcRect, dstRect, followFlags, 3546 options | AS_REQUEST_COLOR_KEY); 3547 if (status == B_OK) { 3548 // read the color that will be treated as transparent 3549 fOwner->fLink->Read<rgb_color>(colorKey); 3550 } 3551 3552 return status; 3553 } 3554 3555 3556 status_t 3557 BView::SetViewOverlay(const BBitmap *overlay, rgb_color *colorKey, 3558 uint32 followFlags, uint32 options) 3559 { 3560 BRect rect; 3561 if (overlay != NULL) { 3562 rect = overlay->Bounds(); 3563 rect.OffsetTo(B_ORIGIN); 3564 } 3565 3566 return SetViewOverlay(overlay, rect, rect, colorKey, followFlags, options); 3567 } 3568 3569 3570 void 3571 BView::ClearViewOverlay() 3572 { 3573 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0); 3574 } 3575 3576 3577 void 3578 BView::CopyBits(BRect src, BRect dst) 3579 { 3580 if (fOwner == NULL) 3581 return; 3582 3583 if (!src.IsValid() || !dst.IsValid()) 3584 return; 3585 3586 _CheckLockAndSwitchCurrent(); 3587 3588 fOwner->fLink->StartMessage(AS_VIEW_COPY_BITS); 3589 fOwner->fLink->Attach<BRect>(src); 3590 fOwner->fLink->Attach<BRect>(dst); 3591 3592 _FlushIfNotInTransaction(); 3593 } 3594 3595 3596 void 3597 BView::DrawPicture(const BPicture *picture) 3598 { 3599 if (picture == NULL) 3600 return; 3601 3602 DrawPictureAsync(picture, PenLocation()); 3603 Sync(); 3604 } 3605 3606 3607 void 3608 BView::DrawPicture(const BPicture *picture, BPoint where) 3609 { 3610 if (picture == NULL) 3611 return; 3612 3613 DrawPictureAsync(picture, where); 3614 Sync(); 3615 } 3616 3617 3618 void 3619 BView::DrawPicture(const char *filename, long offset, BPoint where) 3620 { 3621 if (!filename) 3622 return; 3623 3624 DrawPictureAsync(filename, offset, where); 3625 Sync(); 3626 } 3627 3628 3629 void 3630 BView::DrawPictureAsync(const BPicture *picture) 3631 { 3632 if (picture == NULL) 3633 return; 3634 3635 DrawPictureAsync(picture, PenLocation()); 3636 } 3637 3638 3639 void 3640 BView::DrawPictureAsync(const BPicture *picture, BPoint where) 3641 { 3642 if (picture == NULL) 3643 return; 3644 3645 if (_CheckOwnerLockAndSwitchCurrent() && picture->Token() > 0) { 3646 fOwner->fLink->StartMessage(AS_VIEW_DRAW_PICTURE); 3647 fOwner->fLink->Attach<int32>(picture->Token()); 3648 fOwner->fLink->Attach<BPoint>(where); 3649 3650 _FlushIfNotInTransaction(); 3651 } 3652 } 3653 3654 3655 void 3656 BView::DrawPictureAsync(const char *filename, long offset, BPoint where) 3657 { 3658 if (!filename) 3659 return; 3660 3661 // TODO: Test 3662 BFile file(filename, B_READ_ONLY); 3663 if (file.InitCheck() < B_OK) 3664 return; 3665 3666 file.Seek(offset, SEEK_SET); 3667 3668 BPicture picture; 3669 if (picture.Unflatten(&file) < B_OK) 3670 return; 3671 3672 DrawPictureAsync(&picture, where); 3673 } 3674 3675 3676 void 3677 BView::Invalidate(BRect invalRect) 3678 { 3679 if (fOwner == NULL) 3680 return; 3681 3682 // NOTE: This rounding of the invalid rect is to stay compatible with BeOS. 3683 // On the server side, the invalid rect will be converted to a BRegion, 3684 // which rounds in a different manner, so that it really includes the 3685 // fractional coordinates of a BRect (ie ceilf(rect.right) & 3686 // ceilf(rect.bottom)), which is also what BeOS does. So we have to do the 3687 // different rounding here to stay compatible in both ways. 3688 invalRect.left = (int)invalRect.left; 3689 invalRect.top = (int)invalRect.top; 3690 invalRect.right = (int)invalRect.right; 3691 invalRect.bottom = (int)invalRect.bottom; 3692 if (!invalRect.IsValid()) 3693 return; 3694 3695 _CheckLockAndSwitchCurrent(); 3696 3697 fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_RECT); 3698 fOwner->fLink->Attach<BRect>(invalRect); 3699 3700 // TODO: determine why this check isn't working correctly. 3701 #if 0 3702 if (!fOwner->fUpdateRequested) { 3703 fOwner->fLink->Flush(); 3704 fOwner->fUpdateRequested = true; 3705 } 3706 #endif 3707 fOwner->fLink->Flush(); 3708 } 3709 3710 3711 void 3712 BView::Invalidate(const BRegion* region) 3713 { 3714 if (region == NULL || fOwner == NULL) 3715 return; 3716 3717 _CheckLockAndSwitchCurrent(); 3718 3719 fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_REGION); 3720 fOwner->fLink->AttachRegion(*region); 3721 3722 if (!fOwner->fUpdateRequested) { 3723 fOwner->fLink->Flush(); 3724 fOwner->fUpdateRequested = true; 3725 } 3726 } 3727 3728 3729 void 3730 BView::Invalidate() 3731 { 3732 Invalidate(Bounds()); 3733 } 3734 3735 3736 void 3737 BView::InvertRect(BRect rect) 3738 { 3739 if (fOwner) { 3740 _CheckLockAndSwitchCurrent(); 3741 3742 fOwner->fLink->StartMessage(AS_VIEW_INVERT_RECT); 3743 fOwner->fLink->Attach<BRect>(rect); 3744 3745 _FlushIfNotInTransaction(); 3746 } 3747 } 3748 3749 3750 // #pragma mark - View Hierarchy Functions 3751 3752 3753 void 3754 BView::AddChild(BView *child, BView *before) 3755 { 3756 STRACE(("BView(%s)::AddChild(child='%s' before='%s')\n", 3757 this->Name() ? this->Name(): "NULL", 3758 child && child->Name() ? child->Name(): "NULL", 3759 before && before->Name() ? before->Name(): "NULL")); 3760 3761 if (!_AddChild(child, before)) 3762 return; 3763 3764 if (fLayoutData->fLayout) 3765 fLayoutData->fLayout->AddView(child); 3766 } 3767 3768 3769 bool 3770 BView::AddChild(BLayoutItem* child) 3771 { 3772 if (!fLayoutData->fLayout) 3773 return false; 3774 return fLayoutData->fLayout->AddItem(child); 3775 } 3776 3777 3778 bool 3779 BView::_AddChild(BView *child, BView *before) 3780 { 3781 if (!child) 3782 return false; 3783 3784 if (child->fParent != NULL) { 3785 debugger("AddChild failed - the view already has a parent."); 3786 return false; 3787 } 3788 3789 bool lockedOwner = false; 3790 if (fOwner && !fOwner->IsLocked()) { 3791 fOwner->Lock(); 3792 lockedOwner = true; 3793 } 3794 3795 if (!_AddChildToList(child, before)) { 3796 debugger("AddChild failed!"); 3797 if (lockedOwner) 3798 fOwner->Unlock(); 3799 return false; 3800 } 3801 3802 if (fOwner) { 3803 _CheckLockAndSwitchCurrent(); 3804 3805 child->_SetOwner(fOwner); 3806 child->_CreateSelf(); 3807 child->_Attach(); 3808 3809 if (lockedOwner) 3810 fOwner->Unlock(); 3811 } 3812 3813 InvalidateLayout(); 3814 3815 return true; 3816 } 3817 3818 3819 bool 3820 BView::RemoveChild(BView *child) 3821 { 3822 STRACE(("BView(%s)::RemoveChild(%s)\n", Name(), child->Name())); 3823 3824 if (!child) 3825 return false; 3826 3827 if (child->fParent != this) 3828 return false; 3829 3830 return child->RemoveSelf(); 3831 } 3832 3833 int32 3834 BView::CountChildren() const 3835 { 3836 _CheckLock(); 3837 3838 uint32 count = 0; 3839 BView *child = fFirstChild; 3840 3841 while (child != NULL) { 3842 count++; 3843 child = child->fNextSibling; 3844 } 3845 3846 return count; 3847 } 3848 3849 3850 BView * 3851 BView::ChildAt(int32 index) const 3852 { 3853 _CheckLock(); 3854 3855 BView *child = fFirstChild; 3856 while (child != NULL && index-- > 0) { 3857 child = child->fNextSibling; 3858 } 3859 3860 return child; 3861 } 3862 3863 3864 BView * 3865 BView::NextSibling() const 3866 { 3867 return fNextSibling; 3868 } 3869 3870 3871 BView * 3872 BView::PreviousSibling() const 3873 { 3874 return fPreviousSibling; 3875 } 3876 3877 3878 bool 3879 BView::RemoveSelf() 3880 { 3881 if (fParent && fParent->fLayoutData->fLayout) 3882 return fParent->fLayoutData->fLayout->RemoveView(this); 3883 else 3884 return _RemoveSelf(); 3885 } 3886 3887 3888 bool 3889 BView::_RemoveSelf() 3890 { 3891 STRACE(("BView(%s)::RemoveSelf()...\n", Name())); 3892 3893 // Remove this child from its parent 3894 3895 BWindow* owner = fOwner; 3896 _CheckLock(); 3897 3898 if (owner != NULL) { 3899 _UpdateStateForRemove(); 3900 _Detach(); 3901 } 3902 3903 BView* parent = fParent; 3904 if (!parent || !parent->_RemoveChildFromList(this)) 3905 return false; 3906 3907 if (owner != NULL && !fTopLevelView) { 3908 // the top level view is deleted by the app_server automatically 3909 owner->fLink->StartMessage(AS_VIEW_DELETE); 3910 owner->fLink->Attach<int32>(_get_object_token_(this)); 3911 } 3912 3913 parent->InvalidateLayout(); 3914 3915 STRACE(("DONE: BView(%s)::RemoveSelf()\n", Name())); 3916 3917 return true; 3918 } 3919 3920 3921 BView * 3922 BView::Parent() const 3923 { 3924 if (fParent && fParent->fTopLevelView) 3925 return NULL; 3926 3927 return fParent; 3928 } 3929 3930 3931 BView * 3932 BView::FindView(const char *name) const 3933 { 3934 if (name == NULL) 3935 return NULL; 3936 3937 if (Name() != NULL && !strcmp(Name(), name)) 3938 return const_cast<BView *>(this); 3939 3940 BView *child = fFirstChild; 3941 while (child != NULL) { 3942 BView *view = child->FindView(name); 3943 if (view != NULL) 3944 return view; 3945 3946 child = child->fNextSibling; 3947 } 3948 3949 return NULL; 3950 } 3951 3952 3953 void 3954 BView::MoveBy(float deltaX, float deltaY) 3955 { 3956 MoveTo(fParentOffset.x + roundf(deltaX), fParentOffset.y + roundf(deltaY)); 3957 } 3958 3959 3960 void 3961 BView::MoveTo(BPoint where) 3962 { 3963 MoveTo(where.x, where.y); 3964 } 3965 3966 3967 void 3968 BView::MoveTo(float x, float y) 3969 { 3970 if (x == fParentOffset.x && y == fParentOffset.y) 3971 return; 3972 3973 // BeBook says we should do this. And it makes sense. 3974 x = roundf(x); 3975 y = roundf(y); 3976 3977 if (fOwner) { 3978 _CheckLockAndSwitchCurrent(); 3979 fOwner->fLink->StartMessage(AS_VIEW_MOVE_TO); 3980 fOwner->fLink->Attach<float>(x); 3981 fOwner->fLink->Attach<float>(y); 3982 3983 // fState->valid_flags |= B_VIEW_FRAME_BIT; 3984 3985 _FlushIfNotInTransaction(); 3986 } 3987 3988 _MoveTo((int32)x, (int32)y); 3989 } 3990 3991 3992 void 3993 BView::ResizeBy(float deltaWidth, float deltaHeight) 3994 { 3995 // BeBook says we should do this. And it makes sense. 3996 deltaWidth = roundf(deltaWidth); 3997 deltaHeight = roundf(deltaHeight); 3998 3999 if (deltaWidth == 0 && deltaHeight == 0) 4000 return; 4001 4002 if (fOwner) { 4003 _CheckLockAndSwitchCurrent(); 4004 fOwner->fLink->StartMessage(AS_VIEW_RESIZE_TO); 4005 4006 fOwner->fLink->Attach<float>(fBounds.Width() + deltaWidth); 4007 fOwner->fLink->Attach<float>(fBounds.Height() + deltaHeight); 4008 4009 // fState->valid_flags |= B_VIEW_FRAME_BIT; 4010 4011 _FlushIfNotInTransaction(); 4012 } 4013 4014 _ResizeBy((int32)deltaWidth, (int32)deltaHeight); 4015 } 4016 4017 4018 void 4019 BView::ResizeTo(float width, float height) 4020 { 4021 ResizeBy(width - fBounds.Width(), height - fBounds.Height()); 4022 } 4023 4024 4025 void 4026 BView::ResizeTo(BSize size) 4027 { 4028 ResizeBy(size.width - fBounds.Width(), size.height - fBounds.Height()); 4029 } 4030 4031 4032 // #pragma mark - Inherited Methods (from BHandler) 4033 4034 4035 status_t 4036 BView::GetSupportedSuites(BMessage *data) 4037 { 4038 if (data == NULL) 4039 return B_BAD_VALUE; 4040 4041 status_t status = data->AddString("suites", "suite/vnd.Be-view"); 4042 BPropertyInfo propertyInfo(sViewPropInfo); 4043 if (status == B_OK) 4044 status = data->AddFlat("messages", &propertyInfo); 4045 if (status == B_OK) 4046 return BHandler::GetSupportedSuites(data); 4047 return status; 4048 } 4049 4050 4051 BHandler * 4052 BView::ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier, 4053 int32 what, const char *property) 4054 { 4055 if (msg->what == B_WINDOW_MOVE_BY 4056 || msg->what == B_WINDOW_MOVE_TO) 4057 return this; 4058 4059 BPropertyInfo propertyInfo(sViewPropInfo); 4060 status_t err = B_BAD_SCRIPT_SYNTAX; 4061 BMessage replyMsg(B_REPLY); 4062 4063 switch (propertyInfo.FindMatch(msg, index, specifier, what, property)) { 4064 case 0: 4065 case 1: 4066 case 2: 4067 case 3: 4068 case 5: 4069 return this; 4070 4071 case 4: 4072 if (fShelf) { 4073 msg->PopSpecifier(); 4074 return fShelf; 4075 } 4076 4077 err = B_NAME_NOT_FOUND; 4078 replyMsg.AddString("message", "This window doesn't have a shelf"); 4079 break; 4080 4081 case 6: 4082 { 4083 if (!fFirstChild) { 4084 err = B_NAME_NOT_FOUND; 4085 replyMsg.AddString("message", "This window doesn't have children."); 4086 break; 4087 } 4088 BView *child = NULL; 4089 switch (what) { 4090 case B_INDEX_SPECIFIER: 4091 { 4092 int32 index; 4093 err = specifier->FindInt32("index", &index); 4094 if (err == B_OK) 4095 child = ChildAt(index); 4096 break; 4097 } 4098 case B_REVERSE_INDEX_SPECIFIER: 4099 { 4100 int32 rindex; 4101 err = specifier->FindInt32("index", &rindex); 4102 if (err == B_OK) 4103 child = ChildAt(CountChildren() - rindex); 4104 break; 4105 } 4106 case B_NAME_SPECIFIER: 4107 { 4108 const char *name; 4109 err = specifier->FindString("name", &name); 4110 if (err == B_OK) 4111 child = FindView(name); 4112 break; 4113 } 4114 } 4115 4116 if (child != NULL) { 4117 msg->PopSpecifier(); 4118 return child; 4119 } 4120 4121 if (err == B_OK) 4122 err = B_BAD_INDEX; 4123 4124 replyMsg.AddString("message", 4125 "Cannot find view at/with specified index/name."); 4126 break; 4127 } 4128 4129 default: 4130 return BHandler::ResolveSpecifier(msg, index, specifier, what, 4131 property); 4132 } 4133 4134 if (err < B_OK) { 4135 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD; 4136 4137 if (err == B_BAD_SCRIPT_SYNTAX) 4138 replyMsg.AddString("message", "Didn't understand the specifier(s)"); 4139 else 4140 replyMsg.AddString("message", strerror(err)); 4141 } 4142 4143 replyMsg.AddInt32("error", err); 4144 msg->SendReply(&replyMsg); 4145 return NULL; 4146 } 4147 4148 4149 void 4150 BView::MessageReceived(BMessage* msg) 4151 { 4152 if (!msg->HasSpecifiers()) { 4153 switch (msg->what) { 4154 case B_VIEW_RESIZED: 4155 // By the time the message arrives, the bounds may have 4156 // changed already, that's why we don't use the values 4157 // in the message itself. 4158 FrameResized(fBounds.Width(), fBounds.Height()); 4159 break; 4160 4161 case B_VIEW_MOVED: 4162 FrameMoved(fParentOffset); 4163 break; 4164 4165 case B_MOUSE_WHEEL_CHANGED: 4166 { 4167 float deltaX = 0.0f, deltaY = 0.0f; 4168 4169 BScrollBar *horizontal = ScrollBar(B_HORIZONTAL); 4170 if (horizontal != NULL) 4171 msg->FindFloat("be:wheel_delta_x", &deltaX); 4172 4173 BScrollBar *vertical = ScrollBar(B_VERTICAL); 4174 if (vertical != NULL) 4175 msg->FindFloat("be:wheel_delta_y", &deltaY); 4176 4177 if (deltaX == 0.0f && deltaY == 0.0f) 4178 return; 4179 4180 float smallStep, largeStep; 4181 if (horizontal != NULL) { 4182 horizontal->GetSteps(&smallStep, &largeStep); 4183 4184 // pressing the option/command/control key scrolls faster 4185 if (modifiers() 4186 & (B_OPTION_KEY | B_COMMAND_KEY | B_CONTROL_KEY)) { 4187 deltaX *= largeStep; 4188 } else 4189 deltaX *= smallStep * 3; 4190 4191 horizontal->SetValue(horizontal->Value() + deltaX); 4192 } 4193 4194 if (vertical != NULL) { 4195 vertical->GetSteps(&smallStep, &largeStep); 4196 4197 // pressing the option/command/control key scrolls faster 4198 if (modifiers() 4199 & (B_OPTION_KEY | B_COMMAND_KEY | B_CONTROL_KEY)) { 4200 deltaY *= largeStep; 4201 } else 4202 deltaY *= smallStep * 3; 4203 4204 vertical->SetValue(vertical->Value() + deltaY); 4205 } 4206 break; 4207 } 4208 4209 default: 4210 return BHandler::MessageReceived(msg); 4211 } 4212 4213 return; 4214 } 4215 4216 // Scripting message 4217 4218 BMessage replyMsg(B_REPLY); 4219 status_t err = B_BAD_SCRIPT_SYNTAX; 4220 int32 index; 4221 BMessage specifier; 4222 int32 what; 4223 const char *prop; 4224 4225 if (msg->GetCurrentSpecifier(&index, &specifier, &what, &prop) != B_OK) 4226 return BHandler::MessageReceived(msg); 4227 4228 BPropertyInfo propertyInfo(sViewPropInfo); 4229 switch (propertyInfo.FindMatch(msg, index, &specifier, what, prop)) { 4230 case 0: 4231 err = replyMsg.AddRect("result", Frame()); 4232 break; 4233 case 1: 4234 { 4235 BRect newFrame; 4236 err = msg->FindRect("data", &newFrame); 4237 if (err == B_OK) { 4238 MoveTo(newFrame.LeftTop()); 4239 ResizeTo(newFrame.right, newFrame.bottom); 4240 } 4241 break; 4242 } 4243 case 2: 4244 err = replyMsg.AddBool( "result", IsHidden()); 4245 break; 4246 case 3: 4247 { 4248 bool newHiddenState; 4249 err = msg->FindBool("data", &newHiddenState); 4250 if (err == B_OK) { 4251 if (!IsHidden() && newHiddenState == true) 4252 Hide(); 4253 else if (IsHidden() && newHiddenState == false) 4254 Show(); 4255 } 4256 } 4257 case 5: 4258 err = replyMsg.AddInt32("result", CountChildren()); 4259 break; 4260 default: 4261 return BHandler::MessageReceived(msg); 4262 } 4263 4264 if (err < B_OK) { 4265 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD; 4266 4267 if (err == B_BAD_SCRIPT_SYNTAX) 4268 replyMsg.AddString("message", "Didn't understand the specifier(s)"); 4269 else 4270 replyMsg.AddString("message", strerror(err)); 4271 } 4272 4273 replyMsg.AddInt32("error", err); 4274 msg->SendReply(&replyMsg); 4275 } 4276 4277 4278 status_t 4279 BView::Perform(perform_code code, void* _data) 4280 { 4281 switch (code) { 4282 case PERFORM_CODE_MIN_SIZE: 4283 ((perform_data_min_size*)_data)->return_value 4284 = BView::MinSize(); 4285 return B_OK; 4286 case PERFORM_CODE_MAX_SIZE: 4287 ((perform_data_max_size*)_data)->return_value 4288 = BView::MaxSize(); 4289 return B_OK; 4290 case PERFORM_CODE_PREFERRED_SIZE: 4291 ((perform_data_preferred_size*)_data)->return_value 4292 = BView::PreferredSize(); 4293 return B_OK; 4294 case PERFORM_CODE_LAYOUT_ALIGNMENT: 4295 ((perform_data_layout_alignment*)_data)->return_value 4296 = BView::LayoutAlignment(); 4297 return B_OK; 4298 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH: 4299 ((perform_data_has_height_for_width*)_data)->return_value 4300 = BView::HasHeightForWidth(); 4301 return B_OK; 4302 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH: 4303 { 4304 perform_data_get_height_for_width* data 4305 = (perform_data_get_height_for_width*)_data; 4306 BView::GetHeightForWidth(data->width, &data->min, &data->max, 4307 &data->preferred); 4308 return B_OK; 4309 } 4310 case PERFORM_CODE_SET_LAYOUT: 4311 { 4312 perform_data_set_layout* data = (perform_data_set_layout*)_data; 4313 BView::SetLayout(data->layout); 4314 return B_OK; 4315 } 4316 case PERFORM_CODE_INVALIDATE_LAYOUT: 4317 { 4318 perform_data_invalidate_layout* data 4319 = (perform_data_invalidate_layout*)_data; 4320 BView::InvalidateLayout(data->descendants); 4321 return B_OK; 4322 } 4323 case PERFORM_CODE_DO_LAYOUT: 4324 { 4325 BView::DoLayout(); 4326 return B_OK; 4327 } 4328 } 4329 4330 return BHandler::Perform(code, _data); 4331 } 4332 4333 4334 // #pragma mark - Layout Functions 4335 4336 4337 BSize 4338 BView::MinSize() 4339 { 4340 // TODO: make sure this works correctly when some methods are overridden 4341 float width, height; 4342 GetPreferredSize(&width, &height); 4343 4344 return BLayoutUtils::ComposeSize(fLayoutData->fMinSize, 4345 (fLayoutData->fLayout ? fLayoutData->fLayout->MinSize() 4346 : BSize(width, height))); 4347 } 4348 4349 4350 BSize 4351 BView::MaxSize() 4352 { 4353 return BLayoutUtils::ComposeSize(fLayoutData->fMaxSize, 4354 (fLayoutData->fLayout ? fLayoutData->fLayout->MaxSize() 4355 : BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED))); 4356 } 4357 4358 4359 BSize 4360 BView::PreferredSize() 4361 { 4362 // TODO: make sure this works correctly when some methods are overridden 4363 float width, height; 4364 GetPreferredSize(&width, &height); 4365 4366 return BLayoutUtils::ComposeSize(fLayoutData->fPreferredSize, 4367 (fLayoutData->fLayout ? fLayoutData->fLayout->PreferredSize() 4368 : BSize(width, height))); 4369 } 4370 4371 4372 BAlignment 4373 BView::LayoutAlignment() 4374 { 4375 return BLayoutUtils::ComposeAlignment(fLayoutData->fAlignment, 4376 (fLayoutData->fLayout ? fLayoutData->fLayout->Alignment() 4377 : BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER))); 4378 } 4379 4380 4381 void 4382 BView::SetExplicitMinSize(BSize size) 4383 { 4384 fLayoutData->fMinSize = size; 4385 InvalidateLayout(); 4386 } 4387 4388 4389 void 4390 BView::SetExplicitMaxSize(BSize size) 4391 { 4392 fLayoutData->fMaxSize = size; 4393 InvalidateLayout(); 4394 } 4395 4396 4397 void 4398 BView::SetExplicitPreferredSize(BSize size) 4399 { 4400 fLayoutData->fPreferredSize = size; 4401 InvalidateLayout(); 4402 } 4403 4404 4405 void 4406 BView::SetExplicitAlignment(BAlignment alignment) 4407 { 4408 fLayoutData->fAlignment = alignment; 4409 InvalidateLayout(); 4410 } 4411 4412 4413 BSize 4414 BView::ExplicitMinSize() const 4415 { 4416 return fLayoutData->fMinSize; 4417 } 4418 4419 4420 BSize 4421 BView::ExplicitMaxSize() const 4422 { 4423 return fLayoutData->fMaxSize; 4424 } 4425 4426 4427 BSize 4428 BView::ExplicitPreferredSize() const 4429 { 4430 return fLayoutData->fPreferredSize; 4431 } 4432 4433 4434 BAlignment 4435 BView::ExplicitAlignment() const 4436 { 4437 return fLayoutData->fAlignment; 4438 } 4439 4440 4441 bool 4442 BView::HasHeightForWidth() 4443 { 4444 return (fLayoutData->fLayout 4445 ? fLayoutData->fLayout->HasHeightForWidth() : false); 4446 } 4447 4448 4449 void 4450 BView::GetHeightForWidth(float width, float* min, float* max, float* preferred) 4451 { 4452 if (fLayoutData->fLayout) 4453 fLayoutData->fLayout->GetHeightForWidth(width, min, max, preferred); 4454 } 4455 4456 4457 void 4458 BView::SetLayout(BLayout* layout) 4459 { 4460 if (layout == fLayoutData->fLayout) 4461 return; 4462 4463 fFlags |= B_SUPPORTS_LAYOUT; 4464 4465 // unset and delete the old layout 4466 if (fLayoutData->fLayout) { 4467 fLayoutData->fLayout->SetView(NULL); 4468 delete fLayoutData->fLayout; 4469 } 4470 4471 fLayoutData->fLayout = layout; 4472 4473 if (fLayoutData->fLayout) { 4474 fLayoutData->fLayout->SetView(this); 4475 4476 // add all children 4477 int count = CountChildren(); 4478 for (int i = 0; i < count; i++) 4479 fLayoutData->fLayout->AddView(ChildAt(i)); 4480 } 4481 4482 InvalidateLayout(); 4483 } 4484 4485 4486 BLayout* 4487 BView::GetLayout() const 4488 { 4489 return fLayoutData->fLayout; 4490 } 4491 4492 4493 void 4494 BView::InvalidateLayout(bool descendants) 4495 { 4496 if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress 4497 && fLayoutData->fLayoutInvalidationDisabled == 0) { 4498 if (fParent && fParent->fLayoutData->fLayoutValid) 4499 fParent->InvalidateLayout(false); 4500 4501 fLayoutData->fLayoutValid = false; 4502 4503 if (fLayoutData->fLayout) 4504 fLayoutData->fLayout->InvalidateLayout(); 4505 4506 if (descendants) { 4507 int count = CountChildren(); 4508 for (int i = 0; i < count; i++) 4509 ChildAt(i)->InvalidateLayout(descendants); 4510 } 4511 4512 if (fTopLevelView) { 4513 // trigger layout process 4514 if (fOwner) 4515 fOwner->PostMessage(B_LAYOUT_WINDOW); 4516 } 4517 } 4518 } 4519 4520 4521 void 4522 BView::EnableLayoutInvalidation() 4523 { 4524 if (fLayoutData->fLayoutInvalidationDisabled > 0) 4525 fLayoutData->fLayoutInvalidationDisabled--; 4526 } 4527 4528 4529 void 4530 BView::DisableLayoutInvalidation() 4531 { 4532 fLayoutData->fLayoutInvalidationDisabled++; 4533 } 4534 4535 4536 bool 4537 BView::IsLayoutValid() const 4538 { 4539 return fLayoutData->fLayoutValid; 4540 } 4541 4542 4543 BLayoutContext* 4544 BView::LayoutContext() const 4545 { 4546 return fLayoutData->fLayoutContext; 4547 } 4548 4549 4550 void 4551 BView::Layout(bool force) 4552 { 4553 BLayoutContext context; 4554 _Layout(force, &context); 4555 } 4556 4557 4558 void 4559 BView::Relayout() 4560 { 4561 if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) { 4562 fLayoutData->fNeedsRelayout = true; 4563 4564 // Layout() is recursive, that is if the parent view is currently laid 4565 // out, we don't call layout() on this view, but wait for the parent's 4566 // Layout() to do that for us. 4567 if (!fParent || !fParent->fLayoutData->fLayoutInProgress) 4568 Layout(false); 4569 } 4570 } 4571 4572 4573 void 4574 BView::DoLayout() 4575 { 4576 if (fLayoutData->fLayout) 4577 fLayoutData->fLayout->LayoutView(); 4578 } 4579 4580 4581 void 4582 BView::_Layout(bool force, BLayoutContext* context) 4583 { 4584 //printf("%p->BView::_Layout(%d, %p)\n", this, force, context); 4585 //printf(" fNeedsRelayout: %d, fLayoutValid: %d, fLayoutInProgress: %d\n", 4586 //fLayoutData->fNeedsRelayout, fLayoutData->fLayoutValid, fLayoutData->fLayoutInProgress); 4587 if (fLayoutData->fNeedsRelayout || !fLayoutData->fLayoutValid || force) { 4588 fLayoutData->fLayoutValid = false; 4589 4590 if (fLayoutData->fLayoutInProgress) 4591 return; 4592 4593 BLayoutContext* oldContext = fLayoutData->fLayoutContext; 4594 fLayoutData->fLayoutContext = context; 4595 4596 fLayoutData->fLayoutInProgress = true; 4597 DoLayout(); 4598 fLayoutData->fLayoutInProgress = false; 4599 4600 fLayoutData->fLayoutValid = true; 4601 fLayoutData->fNeedsRelayout = false; 4602 4603 // layout children 4604 int32 childCount = CountChildren(); 4605 for (int32 i = 0; i < childCount; i++) { 4606 BView* child = ChildAt(i); 4607 if (!child->IsHidden(child)) 4608 child->_Layout(force, context); 4609 } 4610 4611 fLayoutData->fLayoutContext = oldContext; 4612 4613 // invalidate the drawn content, if requested 4614 if (fFlags & B_INVALIDATE_AFTER_LAYOUT) 4615 Invalidate(); 4616 } 4617 } 4618 4619 4620 // #pragma mark - Private Functions 4621 4622 4623 void 4624 BView::_InitData(BRect frame, const char *name, uint32 resizingMode, 4625 uint32 flags) 4626 { 4627 // Info: The name of the view is set by BHandler constructor 4628 4629 STRACE(("BView::InitData: enter\n")); 4630 4631 // initialize members 4632 if ((resizingMode & ~_RESIZE_MASK_) || (flags & _RESIZE_MASK_)) 4633 printf("%s BView::InitData(): resizing mode or flags swapped\n", name); 4634 4635 // There are applications that swap the resize mask and the flags in the 4636 // BView constructor. This does not cause problems under BeOS as it just 4637 // ors the two fields to one 32bit flag. 4638 // For now we do the same but print the above warning message. 4639 // TODO: this should be removed at some point and the original 4640 // version restored: 4641 // fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_); 4642 fFlags = resizingMode | flags; 4643 4644 // handle rounding 4645 frame.left = roundf(frame.left); 4646 frame.top = roundf(frame.top); 4647 frame.right = roundf(frame.right); 4648 frame.bottom = roundf(frame.bottom); 4649 4650 fParentOffset.Set(frame.left, frame.top); 4651 4652 fOwner = NULL; 4653 fParent = NULL; 4654 fNextSibling = NULL; 4655 fPreviousSibling = NULL; 4656 fFirstChild = NULL; 4657 4658 fShowLevel = 0; 4659 fTopLevelView = false; 4660 4661 fCurrentPicture = NULL; 4662 fCommArray = NULL; 4663 4664 fVerScroller = NULL; 4665 fHorScroller = NULL; 4666 4667 fIsPrinting = false; 4668 fAttached = false; 4669 4670 // TODO: Since we cannot communicate failure, we don't use std::nothrow here 4671 // TODO: Maybe we could auto-delete those views on AddChild() instead? 4672 fState = new BPrivate::ViewState; 4673 4674 fBounds = frame.OffsetToCopy(B_ORIGIN); 4675 fShelf = NULL; 4676 4677 fEventMask = 0; 4678 fEventOptions = 0; 4679 fMouseEventOptions = 0; 4680 4681 fLayoutData = new LayoutData; 4682 } 4683 4684 4685 void 4686 BView::_RemoveCommArray() 4687 { 4688 if (fCommArray) { 4689 delete [] fCommArray->array; 4690 delete fCommArray; 4691 fCommArray = NULL; 4692 } 4693 } 4694 4695 4696 void 4697 BView::_SetOwner(BWindow *newOwner) 4698 { 4699 if (!newOwner) 4700 _RemoveCommArray(); 4701 4702 if (fOwner != newOwner && fOwner) { 4703 if (fOwner->fFocus == this) 4704 MakeFocus(false); 4705 4706 if (fOwner->fLastMouseMovedView == this) 4707 fOwner->fLastMouseMovedView = NULL; 4708 4709 fOwner->RemoveHandler(this); 4710 if (fShelf) 4711 fOwner->RemoveHandler(fShelf); 4712 } 4713 4714 if (newOwner && newOwner != fOwner) { 4715 newOwner->AddHandler(this); 4716 if (fShelf) 4717 newOwner->AddHandler(fShelf); 4718 4719 if (fTopLevelView) 4720 SetNextHandler(newOwner); 4721 else 4722 SetNextHandler(fParent); 4723 } 4724 4725 fOwner = newOwner; 4726 4727 for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) 4728 child->_SetOwner(newOwner); 4729 } 4730 4731 4732 void 4733 BView::_ClipToPicture(BPicture *picture, BPoint where, 4734 bool invert, bool sync) 4735 { 4736 if (!picture) 4737 return; 4738 4739 #if 1 4740 // TODO: Move the implementation to the server!!! 4741 // This implementation is pretty slow, since just creating an offscreen bitmap 4742 // takes a lot of time. That's the main reason why it should be moved 4743 // to the server. 4744 4745 // Here the idea is to get rid of the padding bytes in the bitmap, 4746 // as padding complicates and slows down the iteration. 4747 // TODO: Maybe it's not so nice as it assumes BBitmaps to be aligned 4748 // to a 4 byte boundary. 4749 BRect bounds(Bounds()); 4750 if ((bounds.IntegerWidth() + 1) % 32) 4751 bounds.right = bounds.left + ((bounds.IntegerWidth() + 1) / 32 + 1) * 32 - 1; 4752 4753 // TODO: I used a RGBA32 bitmap because drawing on a GRAY8 doesn't work. 4754 BBitmap *bitmap = new(std::nothrow) BBitmap(bounds, B_RGBA32, true); 4755 if (bitmap != NULL && bitmap->InitCheck() == B_OK && bitmap->Lock()) { 4756 BView *view = new(std::nothrow) BView(bounds, "drawing view", 4757 B_FOLLOW_NONE, 0); 4758 if (view != NULL) { 4759 bitmap->AddChild(view); 4760 view->DrawPicture(picture, where); 4761 view->Sync(); 4762 } 4763 bitmap->Unlock(); 4764 } 4765 4766 BRegion region; 4767 int32 width = bounds.IntegerWidth() + 1; 4768 int32 height = bounds.IntegerHeight() + 1; 4769 if (bitmap != NULL && bitmap->LockBits() == B_OK) { 4770 uint32 bit = 0; 4771 uint32 *bits = (uint32 *)bitmap->Bits(); 4772 clipping_rect rect; 4773 4774 // TODO: A possible optimization would be adding "spans" instead 4775 // of 1x1 rects. That would probably help with very complex 4776 // BPictures 4777 for (int32 y = 0; y < height; y++) { 4778 for (int32 x = 0; x < width; x++) { 4779 bit = *bits++; 4780 if (bit != 0xFFFFFFFF) { 4781 rect.left = x; 4782 rect.right = rect.left; 4783 rect.top = rect.bottom = y; 4784 region.Include(rect); 4785 } 4786 } 4787 } 4788 bitmap->UnlockBits(); 4789 } 4790 delete bitmap; 4791 4792 if (invert) { 4793 BRegion inverseRegion; 4794 inverseRegion.Include(Bounds()); 4795 inverseRegion.Exclude(®ion); 4796 ConstrainClippingRegion(&inverseRegion); 4797 } else 4798 ConstrainClippingRegion(®ion); 4799 #else 4800 if (_CheckOwnerLockAndSwitchCurrent()) { 4801 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE); 4802 fOwner->fLink->Attach<int32>(picture->Token()); 4803 fOwner->fLink->Attach<BPoint>(where); 4804 fOwner->fLink->Attach<bool>(invert); 4805 4806 // TODO: I think that "sync" means another thing here: 4807 // the bebook, at least, says so. 4808 if (sync) 4809 fOwner->fLink->Flush(); 4810 4811 fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT; 4812 } 4813 4814 fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT; 4815 #endif 4816 } 4817 4818 4819 bool 4820 BView::_RemoveChildFromList(BView* child) 4821 { 4822 if (child->fParent != this) 4823 return false; 4824 4825 if (fFirstChild == child) { 4826 // it's the first view in the list 4827 fFirstChild = child->fNextSibling; 4828 } else { 4829 // there must be a previous sibling 4830 child->fPreviousSibling->fNextSibling = child->fNextSibling; 4831 } 4832 4833 if (child->fNextSibling) 4834 child->fNextSibling->fPreviousSibling = child->fPreviousSibling; 4835 4836 child->fParent = NULL; 4837 child->fNextSibling = NULL; 4838 child->fPreviousSibling = NULL; 4839 4840 return true; 4841 } 4842 4843 4844 bool 4845 BView::_AddChildToList(BView* child, BView* before) 4846 { 4847 if (!child) 4848 return false; 4849 if (child->fParent != NULL) { 4850 debugger("View already belongs to someone else"); 4851 return false; 4852 } 4853 if (before != NULL && before->fParent != this) { 4854 debugger("Invalid before view"); 4855 return false; 4856 } 4857 4858 if (before != NULL) { 4859 // add view before this one 4860 child->fNextSibling = before; 4861 child->fPreviousSibling = before->fPreviousSibling; 4862 if (child->fPreviousSibling != NULL) 4863 child->fPreviousSibling->fNextSibling = child; 4864 4865 before->fPreviousSibling = child; 4866 if (fFirstChild == before) 4867 fFirstChild = child; 4868 } else { 4869 // add view to the end of the list 4870 BView *last = fFirstChild; 4871 while (last != NULL && last->fNextSibling != NULL) { 4872 last = last->fNextSibling; 4873 } 4874 4875 if (last != NULL) { 4876 last->fNextSibling = child; 4877 child->fPreviousSibling = last; 4878 } else { 4879 fFirstChild = child; 4880 child->fPreviousSibling = NULL; 4881 } 4882 4883 child->fNextSibling = NULL; 4884 } 4885 4886 child->fParent = this; 4887 return true; 4888 } 4889 4890 4891 /*! \brief Creates the server counterpart of this view. 4892 This is only done for views that are part of the view hierarchy, ie. when 4893 they are attached to a window. 4894 RemoveSelf() deletes the server object again. 4895 */ 4896 bool 4897 BView::_CreateSelf() 4898 { 4899 // AS_VIEW_CREATE & AS_VIEW_CREATE_ROOT do not use the 4900 // current view mechanism via _CheckLockAndSwitchCurrent() - the token 4901 // of the view and its parent are both send to the server. 4902 4903 if (fTopLevelView) 4904 fOwner->fLink->StartMessage(AS_VIEW_CREATE_ROOT); 4905 else 4906 fOwner->fLink->StartMessage(AS_VIEW_CREATE); 4907 4908 fOwner->fLink->Attach<int32>(_get_object_token_(this)); 4909 fOwner->fLink->AttachString(Name()); 4910 fOwner->fLink->Attach<BRect>(Frame()); 4911 fOwner->fLink->Attach<BPoint>(LeftTop()); 4912 fOwner->fLink->Attach<uint32>(ResizingMode()); 4913 fOwner->fLink->Attach<uint32>(fEventMask); 4914 fOwner->fLink->Attach<uint32>(fEventOptions); 4915 fOwner->fLink->Attach<uint32>(Flags()); 4916 fOwner->fLink->Attach<bool>(IsHidden(this)); 4917 fOwner->fLink->Attach<rgb_color>(fState->view_color); 4918 if (fTopLevelView) 4919 fOwner->fLink->Attach<int32>(B_NULL_TOKEN); 4920 else 4921 fOwner->fLink->Attach<int32>(_get_object_token_(fParent)); 4922 fOwner->fLink->Flush(); 4923 4924 _CheckOwnerLockAndSwitchCurrent(); 4925 fState->UpdateServerState(*fOwner->fLink); 4926 4927 // we create all its children, too 4928 4929 for (BView *child = fFirstChild; child != NULL; 4930 child = child->fNextSibling) { 4931 child->_CreateSelf(); 4932 } 4933 4934 fOwner->fLink->Flush(); 4935 return true; 4936 } 4937 4938 4939 /*! Sets the new view position. 4940 It doesn't contact the server, though - the only case where this 4941 is called outside of MoveTo() is as reaction of moving a view 4942 in the server (a.k.a. B_WINDOW_RESIZED). 4943 It also calls the BView's FrameMoved() hook. 4944 */ 4945 void 4946 BView::_MoveTo(int32 x, int32 y) 4947 { 4948 fParentOffset.Set(x, y); 4949 4950 if (Window() != NULL && fFlags & B_FRAME_EVENTS) { 4951 BMessage moved(B_VIEW_MOVED); 4952 moved.AddInt64("when", system_time()); 4953 moved.AddPoint("where", BPoint(x, y)); 4954 4955 BMessenger target(this); 4956 target.SendMessage(&moved); 4957 } 4958 } 4959 4960 4961 /*! Computes the actual new frame size and recalculates the size of 4962 the children as well. 4963 It doesn't contact the server, though - the only case where this 4964 is called outside of ResizeBy() is as reaction of resizing a view 4965 in the server (a.k.a. B_WINDOW_RESIZED). 4966 It also calls the BView's FrameResized() hook. 4967 */ 4968 void 4969 BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight) 4970 { 4971 fBounds.right += deltaWidth; 4972 fBounds.bottom += deltaHeight; 4973 4974 if (Window() == NULL) { 4975 // we're not supposed to exercise the resizing code in case 4976 // we haven't been attached to a window yet 4977 return; 4978 } 4979 4980 // layout the children 4981 if (fFlags & B_SUPPORTS_LAYOUT) { 4982 Relayout(); 4983 } else { 4984 for (BView* child = fFirstChild; child; child = child->fNextSibling) 4985 child->_ParentResizedBy(deltaWidth, deltaHeight); 4986 } 4987 4988 if (fFlags & B_FRAME_EVENTS) { 4989 BMessage resized(B_VIEW_RESIZED); 4990 resized.AddInt64("when", system_time()); 4991 resized.AddFloat("width", fBounds.Width()); 4992 resized.AddFloat("height", fBounds.Height()); 4993 4994 BMessenger target(this); 4995 target.SendMessage(&resized); 4996 } 4997 } 4998 4999 5000 /*! Relayouts the view according to its resizing mode. */ 5001 void 5002 BView::_ParentResizedBy(int32 x, int32 y) 5003 { 5004 uint32 resizingMode = fFlags & _RESIZE_MASK_; 5005 BRect newFrame = Frame(); 5006 5007 // follow with left side 5008 if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8) 5009 newFrame.left += x; 5010 else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8) 5011 newFrame.left += x / 2; 5012 5013 // follow with right side 5014 if ((resizingMode & 0x000FU) == _VIEW_RIGHT_) 5015 newFrame.right += x; 5016 else if ((resizingMode & 0x000FU) == _VIEW_CENTER_) 5017 newFrame.right += x / 2; 5018 5019 // follow with top side 5020 if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12) 5021 newFrame.top += y; 5022 else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12) 5023 newFrame.top += y / 2; 5024 5025 // follow with bottom side 5026 if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4) 5027 newFrame.bottom += y; 5028 else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4) 5029 newFrame.bottom += y / 2; 5030 5031 if (newFrame.LeftTop() != fParentOffset) { 5032 // move view 5033 _MoveTo((int32)roundf(newFrame.left), (int32)roundf(newFrame.top)); 5034 } 5035 5036 if (newFrame != Frame()) { 5037 // resize view 5038 int32 widthDiff = (int32)(newFrame.Width() - fBounds.Width()); 5039 int32 heightDiff = (int32)(newFrame.Height() - fBounds.Height()); 5040 _ResizeBy(widthDiff, heightDiff); 5041 } 5042 } 5043 5044 5045 void 5046 BView::_Activate(bool active) 5047 { 5048 WindowActivated(active); 5049 5050 for (BView *child = fFirstChild; child != NULL; 5051 child = child->fNextSibling) { 5052 child->_Activate(active); 5053 } 5054 } 5055 5056 5057 void 5058 BView::_Attach() 5059 { 5060 AttachedToWindow(); 5061 fAttached = true; 5062 5063 // after giving the view a chance to do this itself, 5064 // check for the B_PULSE_NEEDED flag and make sure the 5065 // window set's up the pulse messaging 5066 if (fOwner) { 5067 if (fFlags & B_PULSE_NEEDED) { 5068 _CheckLock(); 5069 if (fOwner->fPulseRunner == NULL) 5070 fOwner->SetPulseRate(fOwner->PulseRate()); 5071 } 5072 5073 if (!fOwner->IsHidden()) 5074 Invalidate(); 5075 } 5076 5077 for (BView* child = fFirstChild; child != NULL; 5078 child = child->fNextSibling) { 5079 // we need to check for fAttached as new views could have been 5080 // added in AttachedToWindow() - and those are already attached 5081 if (!child->fAttached) 5082 child->_Attach(); 5083 } 5084 5085 AllAttached(); 5086 } 5087 5088 5089 void 5090 BView::_Detach() 5091 { 5092 DetachedFromWindow(); 5093 fAttached = false; 5094 5095 for (BView* child = fFirstChild; child != NULL; 5096 child = child->fNextSibling) { 5097 child->_Detach(); 5098 } 5099 5100 AllDetached(); 5101 5102 if (fOwner) { 5103 _CheckLock(); 5104 5105 if (!fOwner->IsHidden()) 5106 Invalidate(); 5107 5108 // make sure our owner doesn't need us anymore 5109 5110 if (fOwner->CurrentFocus() == this) { 5111 MakeFocus(false); 5112 // MakeFocus() is virtual and might not be 5113 // passing through to the BView version, 5114 // but we need to make sure at this point 5115 // that we are not the focus view anymore. 5116 if (fOwner->CurrentFocus() == this) 5117 fOwner->_SetFocus(NULL, true); 5118 } 5119 5120 if (fOwner->fDefaultButton == this) 5121 fOwner->SetDefaultButton(NULL); 5122 5123 if (fOwner->fKeyMenuBar == this) 5124 fOwner->fKeyMenuBar = NULL; 5125 5126 if (fOwner->fLastMouseMovedView == this) 5127 fOwner->fLastMouseMovedView = NULL; 5128 5129 if (fOwner->fLastViewToken == _get_object_token_(this)) 5130 fOwner->fLastViewToken = B_NULL_TOKEN; 5131 5132 _SetOwner(NULL); 5133 } 5134 } 5135 5136 5137 void 5138 BView::_Draw(BRect updateRect) 5139 { 5140 if (IsHidden(this) || !(Flags() & B_WILL_DRAW)) 5141 return; 5142 5143 // NOTE: if ViewColor() == B_TRANSPARENT_COLOR and no B_WILL_DRAW 5144 // -> View is simply not drawn at all 5145 5146 _SwitchServerCurrentView(); 5147 5148 ConvertFromScreen(&updateRect); 5149 5150 // TODO: make states robust (the hook implementation could 5151 // mess things up if it uses non-matching Push- and PopState(), 5152 // we would not be guaranteed to still have the same state on 5153 // the stack after having called Draw()) 5154 PushState(); 5155 Draw(updateRect); 5156 PopState(); 5157 Flush(); 5158 } 5159 5160 void 5161 BView::_DrawAfterChildren(BRect updateRect) 5162 { 5163 if (IsHidden(this) || !(Flags() & B_WILL_DRAW) 5164 || !(Flags() & B_DRAW_ON_CHILDREN)) 5165 return; 5166 5167 _SwitchServerCurrentView(); 5168 5169 ConvertFromScreen(&updateRect); 5170 5171 // TODO: make states robust (see above) 5172 PushState(); 5173 DrawAfterChildren(updateRect); 5174 PopState(); 5175 Flush(); 5176 } 5177 5178 5179 void 5180 BView::_Pulse() 5181 { 5182 if (Flags() & B_PULSE_NEEDED) 5183 Pulse(); 5184 5185 for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) { 5186 child->_Pulse(); 5187 } 5188 } 5189 5190 5191 void 5192 BView::_UpdateStateForRemove() 5193 { 5194 // TODO: _CheckLockAndSwitchCurrent() would be good enough, no? 5195 if (!_CheckOwnerLockAndSwitchCurrent()) 5196 return; 5197 5198 fState->UpdateFrom(*fOwner->fLink); 5199 // if (!fState->IsValid(B_VIEW_FRAME_BIT)) { 5200 // fOwner->fLink->StartMessage(AS_VIEW_GET_COORD); 5201 // 5202 // status_t code; 5203 // if (fOwner->fLink->FlushWithReply(code) == B_OK 5204 // && code == B_OK) { 5205 // fOwner->fLink->Read<BPoint>(&fParentOffset); 5206 // fOwner->fLink->Read<BRect>(&fBounds); 5207 // fState->valid_flags |= B_VIEW_FRAME_BIT; 5208 // } 5209 // } 5210 5211 // update children as well 5212 5213 for (BView *child = fFirstChild; child != NULL; child = child->fNextSibling) { 5214 if (child->fOwner) 5215 child->_UpdateStateForRemove(); 5216 } 5217 } 5218 5219 5220 inline void 5221 BView::_UpdatePattern(::pattern pattern) 5222 { 5223 if (fState->IsValid(B_VIEW_PATTERN_BIT) && pattern == fState->pattern) 5224 return; 5225 5226 if (fOwner) { 5227 _CheckLockAndSwitchCurrent(); 5228 5229 fOwner->fLink->StartMessage(AS_VIEW_SET_PATTERN); 5230 fOwner->fLink->Attach< ::pattern>(pattern); 5231 5232 fState->valid_flags |= B_VIEW_PATTERN_BIT; 5233 } 5234 5235 fState->pattern = pattern; 5236 } 5237 5238 5239 void 5240 BView::_FlushIfNotInTransaction() 5241 { 5242 if (!fOwner->fInTransaction) { 5243 fOwner->Flush(); 5244 } 5245 } 5246 5247 5248 BShelf * 5249 BView::_Shelf() const 5250 { 5251 return fShelf; 5252 } 5253 5254 5255 void 5256 BView::_SetShelf(BShelf *shelf) 5257 { 5258 if (fShelf != NULL && fOwner != NULL) 5259 fOwner->RemoveHandler(fShelf); 5260 5261 fShelf = shelf; 5262 5263 if (fShelf != NULL && fOwner != NULL) 5264 fOwner->AddHandler(fShelf); 5265 } 5266 5267 5268 status_t 5269 BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect, 5270 uint32 followFlags, uint32 options) 5271 { 5272 if (!_CheckOwnerLockAndSwitchCurrent()) 5273 return B_ERROR; 5274 5275 int32 serverToken = bitmap ? bitmap->_ServerToken() : -1; 5276 5277 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_BITMAP); 5278 fOwner->fLink->Attach<int32>(serverToken); 5279 fOwner->fLink->Attach<BRect>(srcRect); 5280 fOwner->fLink->Attach<BRect>(dstRect); 5281 fOwner->fLink->Attach<int32>(followFlags); 5282 fOwner->fLink->Attach<int32>(options); 5283 5284 status_t status = B_ERROR; 5285 fOwner->fLink->FlushWithReply(status); 5286 5287 return status; 5288 } 5289 5290 5291 bool 5292 BView::_CheckOwnerLockAndSwitchCurrent() const 5293 { 5294 STRACE(("BView(%s)::_CheckOwnerLockAndSwitchCurrent()...", Name())); 5295 5296 if (fOwner == NULL) { 5297 debugger("View method requires owner and doesn't have one."); 5298 return false; 5299 } 5300 5301 _CheckLockAndSwitchCurrent(); 5302 5303 return true; 5304 } 5305 5306 5307 bool 5308 BView::_CheckOwnerLock() const 5309 { 5310 if (fOwner) { 5311 fOwner->check_lock(); 5312 return true; 5313 } else { 5314 debugger("View method requires owner and doesn't have one."); 5315 return false; 5316 } 5317 } 5318 5319 5320 void 5321 BView::_CheckLockAndSwitchCurrent() const 5322 { 5323 STRACE(("BView(%s)::_CheckLockAndSwitchCurrent()...", Name() ? Name(): "NULL")); 5324 5325 if (!fOwner) 5326 return; 5327 5328 fOwner->check_lock(); 5329 5330 _SwitchServerCurrentView(); 5331 } 5332 5333 5334 void 5335 BView::_CheckLock() const 5336 { 5337 if (fOwner) 5338 fOwner->check_lock(); 5339 } 5340 5341 5342 void 5343 BView::_SwitchServerCurrentView() const 5344 { 5345 int32 serverToken = _get_object_token_(this); 5346 5347 if (fOwner->fLastViewToken != serverToken) { 5348 STRACE(("contacting app_server... sending token: %ld\n", serverToken)); 5349 fOwner->fLink->StartMessage(AS_SET_CURRENT_VIEW); 5350 fOwner->fLink->Attach<int32>(serverToken); 5351 5352 fOwner->fLastViewToken = serverToken; 5353 } else { 5354 STRACE(("quiet2\n")); 5355 } 5356 } 5357 5358 5359 extern "C" void 5360 _ReservedView1__5BView(BView* view, BRect rect) 5361 { 5362 view->BView::DrawAfterChildren(rect); 5363 } 5364 5365 5366 extern "C" void 5367 _ReservedView2__5BView(BView* view) 5368 { 5369 // MinSize() 5370 perform_data_min_size data; 5371 view->Perform(PERFORM_CODE_MIN_SIZE, &data); 5372 } 5373 5374 5375 extern "C" void 5376 _ReservedView3__5BView(BView* view) 5377 { 5378 // MaxSize() 5379 perform_data_max_size data; 5380 view->Perform(PERFORM_CODE_MAX_SIZE, &data); 5381 } 5382 5383 5384 extern "C" BSize 5385 _ReservedView4__5BView(BView* view) 5386 { 5387 // PreferredSize() 5388 perform_data_preferred_size data; 5389 view->Perform(PERFORM_CODE_PREFERRED_SIZE, &data); 5390 return data.return_value; 5391 } 5392 5393 5394 extern "C" BAlignment 5395 _ReservedView5__5BView(BView* view) 5396 { 5397 // LayoutAlignment() 5398 perform_data_layout_alignment data; 5399 view->Perform(PERFORM_CODE_LAYOUT_ALIGNMENT, &data); 5400 return data.return_value; 5401 } 5402 5403 5404 extern "C" bool 5405 _ReservedView6__5BView(BView* view) 5406 { 5407 // HasHeightForWidth() 5408 perform_data_has_height_for_width data; 5409 view->Perform(PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH, &data); 5410 return data.return_value; 5411 } 5412 5413 5414 extern "C" void 5415 _ReservedView7__5BView(BView* view, float width, float* min, float* max, 5416 float* preferred) 5417 { 5418 // GetHeightForWidth() 5419 perform_data_get_height_for_width data; 5420 data.width = width; 5421 view->Perform(PERFORM_CODE_GET_HEIGHT_FOR_WIDTH, &data); 5422 if (min != NULL) 5423 *min = data.min; 5424 if (max != NULL) 5425 *max = data.max; 5426 if (preferred != NULL) 5427 *preferred = data.preferred; 5428 } 5429 5430 5431 extern "C" void 5432 _ReservedView8__5BView(BView* view, BLayout* layout) 5433 { 5434 // SetLayout() 5435 perform_data_set_layout data; 5436 data.layout = layout; 5437 view->Perform(PERFORM_CODE_SET_LAYOUT, &data); 5438 } 5439 5440 5441 extern "C" void 5442 _ReservedView9__5BView(BView* view, bool descendants) 5443 { 5444 // InvalidateLayout() 5445 perform_data_invalidate_layout data; 5446 data.descendants = descendants; 5447 view->Perform(PERFORM_CODE_INVALIDATE_LAYOUT, &data); 5448 } 5449 5450 5451 extern "C" void 5452 _ReservedView10__5BView(BView* view) 5453 { 5454 // DoLayout() 5455 view->Perform(PERFORM_CODE_DO_LAYOUT, NULL); 5456 } 5457 5458 5459 void BView::_ReservedView11(){} 5460 void BView::_ReservedView12(){} 5461 void BView::_ReservedView13(){} 5462 void BView::_ReservedView14(){} 5463 void BView::_ReservedView15(){} 5464 void BView::_ReservedView16(){} 5465 5466 5467 BView::BView(const BView &other) 5468 : BHandler() 5469 { 5470 // this is private and not functional, but exported 5471 } 5472 5473 5474 BView & 5475 BView::operator=(const BView &other) 5476 { 5477 // this is private and not functional, but exported 5478 return *this; 5479 } 5480 5481 5482 void 5483 BView::_PrintToStream() 5484 { 5485 printf("BView::_PrintToStream()\n"); 5486 printf("\tName: %s\n" 5487 "\tParent: %s\n" 5488 "\tFirstChild: %s\n" 5489 "\tNextSibling: %s\n" 5490 "\tPrevSibling: %s\n" 5491 "\tOwner(Window): %s\n" 5492 "\tToken: %ld\n" 5493 "\tFlags: %ld\n" 5494 "\tView origin: (%f,%f)\n" 5495 "\tView Bounds rectangle: (%f,%f,%f,%f)\n" 5496 "\tShow level: %d\n" 5497 "\tTopView?: %s\n" 5498 "\tBPicture: %s\n" 5499 "\tVertical Scrollbar %s\n" 5500 "\tHorizontal Scrollbar %s\n" 5501 "\tIs Printing?: %s\n" 5502 "\tShelf?: %s\n" 5503 "\tEventMask: %ld\n" 5504 "\tEventOptions: %ld\n", 5505 Name(), 5506 fParent ? fParent->Name() : "NULL", 5507 fFirstChild ? fFirstChild->Name() : "NULL", 5508 fNextSibling ? fNextSibling->Name() : "NULL", 5509 fPreviousSibling ? fPreviousSibling->Name() : "NULL", 5510 fOwner ? fOwner->Name() : "NULL", 5511 _get_object_token_(this), 5512 fFlags, 5513 fParentOffset.x, fParentOffset.y, 5514 fBounds.left, fBounds.top, fBounds.right, fBounds.bottom, 5515 fShowLevel, 5516 fTopLevelView ? "YES" : "NO", 5517 fCurrentPicture? "YES" : "NULL", 5518 fVerScroller? "YES" : "NULL", 5519 fHorScroller? "YES" : "NULL", 5520 fIsPrinting? "YES" : "NO", 5521 fShelf? "YES" : "NO", 5522 fEventMask, 5523 fEventOptions); 5524 5525 printf("\tState status:\n" 5526 "\t\tLocalCoordianteSystem: (%f,%f)\n" 5527 "\t\tPenLocation: (%f,%f)\n" 5528 "\t\tPenSize: %f\n" 5529 "\t\tHighColor: [%d,%d,%d,%d]\n" 5530 "\t\tLowColor: [%d,%d,%d,%d]\n" 5531 "\t\tViewColor: [%d,%d,%d,%d]\n" 5532 "\t\tPattern: %llx\n" 5533 "\t\tDrawingMode: %d\n" 5534 "\t\tLineJoinMode: %d\n" 5535 "\t\tLineCapMode: %d\n" 5536 "\t\tMiterLimit: %f\n" 5537 "\t\tAlphaSource: %d\n" 5538 "\t\tAlphaFuntion: %d\n" 5539 "\t\tScale: %f\n" 5540 "\t\t(Print)FontAliasing: %s\n" 5541 "\t\tFont Info:\n", 5542 fState->origin.x, fState->origin.y, 5543 fState->pen_location.x, fState->pen_location.y, 5544 fState->pen_size, 5545 fState->high_color.red, fState->high_color.blue, fState->high_color.green, fState->high_color.alpha, 5546 fState->low_color.red, fState->low_color.blue, fState->low_color.green, fState->low_color.alpha, 5547 fState->view_color.red, fState->view_color.blue, fState->view_color.green, fState->view_color.alpha, 5548 *((uint64*)&(fState->pattern)), 5549 fState->drawing_mode, 5550 fState->line_join, 5551 fState->line_cap, 5552 fState->miter_limit, 5553 fState->alpha_source_mode, 5554 fState->alpha_function_mode, 5555 fState->scale, 5556 fState->font_aliasing? "YES" : "NO"); 5557 5558 fState->font.PrintToStream(); 5559 5560 // TODO: also print the line array. 5561 } 5562 5563 5564 void 5565 BView::_PrintTree() 5566 { 5567 int32 spaces = 2; 5568 BView *c = fFirstChild; //c = short for: current 5569 printf( "'%s'\n", Name() ); 5570 if (c != NULL) { 5571 while(true) { 5572 // action block 5573 { 5574 for (int i = 0; i < spaces; i++) 5575 printf(" "); 5576 5577 printf( "'%s'\n", c->Name() ); 5578 } 5579 5580 // go deep 5581 if (c->fFirstChild) { 5582 c = c->fFirstChild; 5583 spaces += 2; 5584 } else { 5585 // go right 5586 if (c->fNextSibling) { 5587 c = c->fNextSibling; 5588 } else { 5589 // go up 5590 while (!c->fParent->fNextSibling && c->fParent != this) { 5591 c = c->fParent; 5592 spaces -= 2; 5593 } 5594 5595 // that enough! We've reached this view. 5596 if (c->fParent == this) 5597 break; 5598 5599 c = c->fParent->fNextSibling; 5600 spaces -= 2; 5601 } 5602 } 5603 } 5604 } 5605 } 5606