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