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