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 if (horizontal != NULL) { 4354 ScrollWithMouseWheelDelta(horizontal, deltaX); 4355 } 4356 4357 if (vertical != NULL) { 4358 ScrollWithMouseWheelDelta(vertical, deltaY); 4359 } 4360 break; 4361 } 4362 4363 default: 4364 BHandler::MessageReceived(msg); 4365 break; 4366 } 4367 4368 return; 4369 } 4370 4371 // Scripting message 4372 4373 BMessage replyMsg(B_REPLY); 4374 status_t err = B_BAD_SCRIPT_SYNTAX; 4375 int32 index; 4376 BMessage specifier; 4377 int32 what; 4378 const char* property; 4379 4380 if (msg->GetCurrentSpecifier(&index, &specifier, &what, &property) != B_OK) 4381 return BHandler::MessageReceived(msg); 4382 4383 BPropertyInfo propertyInfo(sViewPropInfo); 4384 switch (propertyInfo.FindMatch(msg, index, &specifier, what, property)) { 4385 case 0: 4386 if (msg->what == B_GET_PROPERTY) { 4387 err = replyMsg.AddRect("result", Frame()); 4388 } else if (msg->what == B_SET_PROPERTY) { 4389 BRect newFrame; 4390 err = msg->FindRect("data", &newFrame); 4391 if (err == B_OK) { 4392 MoveTo(newFrame.LeftTop()); 4393 ResizeTo(newFrame.Width(), newFrame.Height()); 4394 } 4395 } 4396 break; 4397 case 1: 4398 if (msg->what == B_GET_PROPERTY) { 4399 err = replyMsg.AddBool("result", IsHidden()); 4400 } else if (msg->what == B_SET_PROPERTY) { 4401 bool newHiddenState; 4402 err = msg->FindBool("data", &newHiddenState); 4403 if (err == B_OK) { 4404 if (newHiddenState == true) 4405 Hide(); 4406 else 4407 Show(); 4408 } 4409 } 4410 break; 4411 case 3: 4412 err = replyMsg.AddInt32("result", CountChildren()); 4413 break; 4414 default: 4415 return BHandler::MessageReceived(msg); 4416 } 4417 4418 if (err != B_OK) { 4419 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD; 4420 4421 if (err == B_BAD_SCRIPT_SYNTAX) 4422 replyMsg.AddString("message", "Didn't understand the specifier(s)"); 4423 else 4424 replyMsg.AddString("message", strerror(err)); 4425 4426 replyMsg.AddInt32("error", err); 4427 } 4428 4429 msg->SendReply(&replyMsg); 4430 } 4431 4432 4433 status_t 4434 BView::Perform(perform_code code, void* _data) 4435 { 4436 switch (code) { 4437 case PERFORM_CODE_MIN_SIZE: 4438 ((perform_data_min_size*)_data)->return_value 4439 = BView::MinSize(); 4440 return B_OK; 4441 case PERFORM_CODE_MAX_SIZE: 4442 ((perform_data_max_size*)_data)->return_value 4443 = BView::MaxSize(); 4444 return B_OK; 4445 case PERFORM_CODE_PREFERRED_SIZE: 4446 ((perform_data_preferred_size*)_data)->return_value 4447 = BView::PreferredSize(); 4448 return B_OK; 4449 case PERFORM_CODE_LAYOUT_ALIGNMENT: 4450 ((perform_data_layout_alignment*)_data)->return_value 4451 = BView::LayoutAlignment(); 4452 return B_OK; 4453 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH: 4454 ((perform_data_has_height_for_width*)_data)->return_value 4455 = BView::HasHeightForWidth(); 4456 return B_OK; 4457 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH: 4458 { 4459 perform_data_get_height_for_width* data 4460 = (perform_data_get_height_for_width*)_data; 4461 BView::GetHeightForWidth(data->width, &data->min, &data->max, 4462 &data->preferred); 4463 return B_OK; 4464 } 4465 case PERFORM_CODE_SET_LAYOUT: 4466 { 4467 perform_data_set_layout* data = (perform_data_set_layout*)_data; 4468 BView::SetLayout(data->layout); 4469 return B_OK; 4470 } 4471 case PERFORM_CODE_LAYOUT_INVALIDATED: 4472 { 4473 perform_data_layout_invalidated* data 4474 = (perform_data_layout_invalidated*)_data; 4475 BView::LayoutInvalidated(data->descendants); 4476 return B_OK; 4477 } 4478 case PERFORM_CODE_DO_LAYOUT: 4479 { 4480 BView::DoLayout(); 4481 return B_OK; 4482 } 4483 case PERFORM_CODE_LAYOUT_CHANGED: 4484 { 4485 BView::LayoutChanged(); 4486 return B_OK; 4487 } 4488 case PERFORM_CODE_GET_TOOL_TIP_AT: 4489 { 4490 perform_data_get_tool_tip_at* data 4491 = (perform_data_get_tool_tip_at*)_data; 4492 data->return_value 4493 = BView::GetToolTipAt(data->point, data->tool_tip); 4494 return B_OK; 4495 } 4496 case PERFORM_CODE_ALL_UNARCHIVED: 4497 { 4498 perform_data_all_unarchived* data = 4499 (perform_data_all_unarchived*)_data; 4500 4501 data->return_value = BView::AllUnarchived(data->archive); 4502 return B_OK; 4503 } 4504 case PERFORM_CODE_ALL_ARCHIVED: 4505 { 4506 perform_data_all_archived* data = 4507 (perform_data_all_archived*)_data; 4508 4509 data->return_value = BView::AllArchived(data->archive); 4510 return B_OK; 4511 } 4512 } 4513 4514 return BHandler::Perform(code, _data); 4515 } 4516 4517 4518 // #pragma mark - Layout Functions 4519 4520 4521 BSize 4522 BView::MinSize() 4523 { 4524 // TODO: make sure this works correctly when some methods are overridden 4525 float width, height; 4526 GetPreferredSize(&width, &height); 4527 4528 return BLayoutUtils::ComposeSize(fLayoutData->fMinSize, 4529 (fLayoutData->fLayout ? fLayoutData->fLayout->MinSize() 4530 : BSize(width, height))); 4531 } 4532 4533 4534 BSize 4535 BView::MaxSize() 4536 { 4537 return BLayoutUtils::ComposeSize(fLayoutData->fMaxSize, 4538 (fLayoutData->fLayout ? fLayoutData->fLayout->MaxSize() 4539 : BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED))); 4540 } 4541 4542 4543 BSize 4544 BView::PreferredSize() 4545 { 4546 // TODO: make sure this works correctly when some methods are overridden 4547 float width, height; 4548 GetPreferredSize(&width, &height); 4549 4550 return BLayoutUtils::ComposeSize(fLayoutData->fPreferredSize, 4551 (fLayoutData->fLayout ? fLayoutData->fLayout->PreferredSize() 4552 : BSize(width, height))); 4553 } 4554 4555 4556 BAlignment 4557 BView::LayoutAlignment() 4558 { 4559 return BLayoutUtils::ComposeAlignment(fLayoutData->fAlignment, 4560 (fLayoutData->fLayout ? fLayoutData->fLayout->Alignment() 4561 : BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER))); 4562 } 4563 4564 4565 void 4566 BView::SetExplicitMinSize(BSize size) 4567 { 4568 fLayoutData->fMinSize = size; 4569 InvalidateLayout(); 4570 } 4571 4572 4573 void 4574 BView::SetExplicitMaxSize(BSize size) 4575 { 4576 fLayoutData->fMaxSize = size; 4577 InvalidateLayout(); 4578 } 4579 4580 4581 void 4582 BView::SetExplicitPreferredSize(BSize size) 4583 { 4584 fLayoutData->fPreferredSize = size; 4585 InvalidateLayout(); 4586 } 4587 4588 4589 void 4590 BView::SetExplicitAlignment(BAlignment alignment) 4591 { 4592 fLayoutData->fAlignment = alignment; 4593 InvalidateLayout(); 4594 } 4595 4596 4597 BSize 4598 BView::ExplicitMinSize() const 4599 { 4600 return fLayoutData->fMinSize; 4601 } 4602 4603 4604 BSize 4605 BView::ExplicitMaxSize() const 4606 { 4607 return fLayoutData->fMaxSize; 4608 } 4609 4610 4611 BSize 4612 BView::ExplicitPreferredSize() const 4613 { 4614 return fLayoutData->fPreferredSize; 4615 } 4616 4617 4618 BAlignment 4619 BView::ExplicitAlignment() const 4620 { 4621 return fLayoutData->fAlignment; 4622 } 4623 4624 4625 bool 4626 BView::HasHeightForWidth() 4627 { 4628 return (fLayoutData->fLayout 4629 ? fLayoutData->fLayout->HasHeightForWidth() : false); 4630 } 4631 4632 4633 void 4634 BView::GetHeightForWidth(float width, float* min, float* max, float* preferred) 4635 { 4636 if (fLayoutData->fLayout) 4637 fLayoutData->fLayout->GetHeightForWidth(width, min, max, preferred); 4638 } 4639 4640 4641 void 4642 BView::SetLayout(BLayout* layout) 4643 { 4644 if (layout == fLayoutData->fLayout) 4645 return; 4646 4647 if (layout && layout->Layout()) 4648 debugger("BView::SetLayout() failed, layout is already in use."); 4649 4650 fFlags |= B_SUPPORTS_LAYOUT; 4651 4652 // unset and delete the old layout 4653 if (fLayoutData->fLayout) { 4654 fLayoutData->fLayout->SetOwner(NULL); 4655 delete fLayoutData->fLayout; 4656 } 4657 4658 fLayoutData->fLayout = layout; 4659 4660 if (fLayoutData->fLayout) { 4661 fLayoutData->fLayout->SetOwner(this); 4662 4663 // add all children 4664 int count = CountChildren(); 4665 for (int i = 0; i < count; i++) 4666 fLayoutData->fLayout->AddView(ChildAt(i)); 4667 } 4668 4669 InvalidateLayout(); 4670 } 4671 4672 4673 BLayout* 4674 BView::GetLayout() const 4675 { 4676 return fLayoutData->fLayout; 4677 } 4678 4679 4680 void 4681 BView::InvalidateLayout(bool descendants) 4682 { 4683 // printf("BView(%p)::InvalidateLayout(%i), valid: %i, inProgress: %i\n", 4684 // this, descendants, fLayoutData->fLayoutValid, 4685 // fLayoutData->fLayoutInProgress); 4686 4687 if (!fLayoutData->fMinMaxValid || fLayoutData->fLayoutInProgress 4688 || fLayoutData->fLayoutInvalidationDisabled > 0) { 4689 return; 4690 } 4691 4692 fLayoutData->fLayoutValid = false; 4693 fLayoutData->fMinMaxValid = false; 4694 LayoutInvalidated(descendants); 4695 4696 if (descendants) { 4697 for (BView* child = fFirstChild; 4698 child; child = child->fNextSibling) { 4699 child->InvalidateLayout(descendants); 4700 } 4701 } 4702 4703 if (fLayoutData->fLayout) 4704 fLayoutData->fLayout->InvalidateLayout(descendants); 4705 else 4706 _InvalidateParentLayout(); 4707 4708 if (fTopLevelView && fOwner) 4709 fOwner->PostMessage(B_LAYOUT_WINDOW); 4710 } 4711 4712 4713 void 4714 BView::EnableLayoutInvalidation() 4715 { 4716 if (fLayoutData->fLayoutInvalidationDisabled > 0) 4717 fLayoutData->fLayoutInvalidationDisabled--; 4718 } 4719 4720 4721 void 4722 BView::DisableLayoutInvalidation() 4723 { 4724 fLayoutData->fLayoutInvalidationDisabled++; 4725 } 4726 4727 4728 bool 4729 BView::IsLayoutInvalidationDisabled() 4730 { 4731 if (fLayoutData->fLayoutInvalidationDisabled > 0) 4732 return true; 4733 return false; 4734 } 4735 4736 4737 bool 4738 BView::IsLayoutValid() const 4739 { 4740 return fLayoutData->fLayoutValid; 4741 } 4742 4743 4744 /*! \brief Service call for BView derived classes reenabling 4745 InvalidateLayout() notifications. 4746 4747 BLayout & BView will avoid calling InvalidateLayout on views that have 4748 already been invalidated, but if the view caches internal layout information 4749 which it updates in methods other than DoLayout(), it has to invoke this 4750 method, when it has done so, since otherwise the information might become 4751 obsolete without the layout noticing. 4752 */ 4753 void 4754 BView::ResetLayoutInvalidation() 4755 { 4756 fLayoutData->fMinMaxValid = true; 4757 } 4758 4759 4760 BLayoutContext* 4761 BView::LayoutContext() const 4762 { 4763 return fLayoutData->fLayoutContext; 4764 } 4765 4766 4767 void 4768 BView::Layout(bool force) 4769 { 4770 BLayoutContext context; 4771 _Layout(force, &context); 4772 } 4773 4774 4775 void 4776 BView::Relayout() 4777 { 4778 if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) { 4779 fLayoutData->fNeedsRelayout = true; 4780 if (fLayoutData->fLayout) 4781 fLayoutData->fLayout->RequireLayout(); 4782 4783 // Layout() is recursive, that is if the parent view is currently laid 4784 // out, we don't call layout() on this view, but wait for the parent's 4785 // Layout() to do that for us. 4786 if (!fParent || !fParent->fLayoutData->fLayoutInProgress) 4787 Layout(false); 4788 } 4789 } 4790 4791 4792 void 4793 BView::LayoutInvalidated(bool descendants) 4794 { 4795 // hook method 4796 } 4797 4798 4799 void 4800 BView::DoLayout() 4801 { 4802 if (fLayoutData->fLayout) 4803 fLayoutData->fLayout->_LayoutWithinContext(false, LayoutContext()); 4804 } 4805 4806 4807 void 4808 BView::SetToolTip(const char* text) 4809 { 4810 if (text == NULL || text[0] == '\0') { 4811 SetToolTip((BToolTip*)NULL); 4812 return; 4813 } 4814 4815 if (BTextToolTip* tip = dynamic_cast<BTextToolTip*>(fToolTip)) 4816 tip->SetText(text); 4817 else 4818 SetToolTip(new BTextToolTip(text)); 4819 } 4820 4821 4822 void 4823 BView::SetToolTip(BToolTip* tip) 4824 { 4825 if (fToolTip == tip) 4826 return; 4827 else if (tip == NULL) 4828 HideToolTip(); 4829 4830 if (fToolTip != NULL) 4831 fToolTip->ReleaseReference(); 4832 4833 fToolTip = tip; 4834 4835 if (fToolTip != NULL) 4836 fToolTip->AcquireReference(); 4837 } 4838 4839 4840 BToolTip* 4841 BView::ToolTip() const 4842 { 4843 return fToolTip; 4844 } 4845 4846 4847 void 4848 BView::ShowToolTip(BToolTip* tip) 4849 { 4850 if (tip == NULL) 4851 return; 4852 4853 BPoint where; 4854 GetMouse(&where, NULL, false); 4855 4856 BToolTipManager::Manager()->ShowTip(tip, ConvertToScreen(where), this); 4857 } 4858 4859 4860 void 4861 BView::HideToolTip() 4862 { 4863 BToolTipManager::Manager()->HideTip(); 4864 } 4865 4866 4867 bool 4868 BView::GetToolTipAt(BPoint point, BToolTip** _tip) 4869 { 4870 if (fToolTip != NULL) { 4871 *_tip = fToolTip; 4872 return true; 4873 } 4874 4875 *_tip = NULL; 4876 return false; 4877 } 4878 4879 4880 void 4881 BView::LayoutChanged() 4882 { 4883 // hook method 4884 } 4885 4886 4887 void 4888 BView::_Layout(bool force, BLayoutContext* context) 4889 { 4890 //printf("%p->BView::_Layout(%d, %p)\n", this, force, context); 4891 //printf(" fNeedsRelayout: %d, fLayoutValid: %d, fLayoutInProgress: %d\n", 4892 //fLayoutData->fNeedsRelayout, fLayoutData->fLayoutValid, 4893 //fLayoutData->fLayoutInProgress); 4894 if (fLayoutData->fNeedsRelayout || !fLayoutData->fLayoutValid || force) { 4895 fLayoutData->fLayoutValid = false; 4896 4897 if (fLayoutData->fLayoutInProgress) 4898 return; 4899 4900 BLayoutContext* oldContext = fLayoutData->fLayoutContext; 4901 fLayoutData->fLayoutContext = context; 4902 4903 fLayoutData->fLayoutInProgress = true; 4904 DoLayout(); 4905 fLayoutData->fLayoutInProgress = false; 4906 4907 fLayoutData->fLayoutValid = true; 4908 fLayoutData->fMinMaxValid = true; 4909 fLayoutData->fNeedsRelayout = false; 4910 4911 // layout children 4912 for(BView* child = fFirstChild; child; child = child->fNextSibling) { 4913 if (!child->IsHidden(child)) 4914 child->_Layout(force, context); 4915 } 4916 4917 LayoutChanged(); 4918 4919 fLayoutData->fLayoutContext = oldContext; 4920 4921 // invalidate the drawn content, if requested 4922 if (fFlags & B_INVALIDATE_AFTER_LAYOUT) 4923 Invalidate(); 4924 } 4925 } 4926 4927 4928 void 4929 BView::_LayoutLeft(BLayout* deleted) 4930 { 4931 // If our layout is added to another layout (via BLayout::AddItem()) 4932 // then we share ownership of our layout. In the event that our layout gets 4933 // deleted by the layout it has been added to, this method is called so 4934 // that we don't double-delete our layout. 4935 if (fLayoutData->fLayout == deleted) 4936 fLayoutData->fLayout = NULL; 4937 InvalidateLayout(); 4938 } 4939 4940 4941 void 4942 BView::_InvalidateParentLayout() 4943 { 4944 if (!fParent) 4945 return; 4946 4947 BLayout* layout = fLayoutData->fLayout; 4948 BLayout* layoutParent = layout ? layout->Layout() : NULL; 4949 if (layoutParent) { 4950 layoutParent->InvalidateLayout(); 4951 } else if (fLayoutData->fLayoutItems.CountItems() > 0) { 4952 int32 count = fLayoutData->fLayoutItems.CountItems(); 4953 for (int32 i = 0; i < count; i++) { 4954 fLayoutData->fLayoutItems.ItemAt(i)->Layout()->InvalidateLayout(); 4955 } 4956 } else { 4957 fParent->InvalidateLayout(); 4958 } 4959 } 4960 4961 4962 // #pragma mark - Private Functions 4963 4964 4965 void 4966 BView::_InitData(BRect frame, const char* name, uint32 resizingMode, 4967 uint32 flags) 4968 { 4969 // Info: The name of the view is set by BHandler constructor 4970 4971 STRACE(("BView::_InitData: enter\n")); 4972 4973 // initialize members 4974 if ((resizingMode & ~_RESIZE_MASK_) || (flags & _RESIZE_MASK_)) 4975 printf("%s BView::_InitData(): resizing mode or flags swapped\n", name); 4976 4977 // There are applications that swap the resize mask and the flags in the 4978 // BView constructor. This does not cause problems under BeOS as it just 4979 // ors the two fields to one 32bit flag. 4980 // For now we do the same but print the above warning message. 4981 // TODO: this should be removed at some point and the original 4982 // version restored: 4983 // fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_); 4984 fFlags = resizingMode | flags; 4985 4986 // handle rounding 4987 frame.left = roundf(frame.left); 4988 frame.top = roundf(frame.top); 4989 frame.right = roundf(frame.right); 4990 frame.bottom = roundf(frame.bottom); 4991 4992 fParentOffset.Set(frame.left, frame.top); 4993 4994 fOwner = NULL; 4995 fParent = NULL; 4996 fNextSibling = NULL; 4997 fPreviousSibling = NULL; 4998 fFirstChild = NULL; 4999 5000 fShowLevel = 0; 5001 fTopLevelView = false; 5002 5003 fCurrentPicture = NULL; 5004 fCommArray = NULL; 5005 5006 fVerScroller = NULL; 5007 fHorScroller = NULL; 5008 5009 fIsPrinting = false; 5010 fAttached = false; 5011 5012 // TODO: Since we cannot communicate failure, we don't use std::nothrow here 5013 // TODO: Maybe we could auto-delete those views on AddChild() instead? 5014 fState = new BPrivate::ViewState; 5015 5016 fBounds = frame.OffsetToCopy(B_ORIGIN); 5017 fShelf = NULL; 5018 5019 fEventMask = 0; 5020 fEventOptions = 0; 5021 fMouseEventOptions = 0; 5022 5023 fLayoutData = new LayoutData; 5024 5025 fToolTip = NULL; 5026 } 5027 5028 5029 void 5030 BView::_RemoveCommArray() 5031 { 5032 if (fCommArray) { 5033 delete [] fCommArray->array; 5034 delete fCommArray; 5035 fCommArray = NULL; 5036 } 5037 } 5038 5039 5040 void 5041 BView::_SetOwner(BWindow* newOwner) 5042 { 5043 if (!newOwner) 5044 _RemoveCommArray(); 5045 5046 if (fOwner != newOwner && fOwner) { 5047 if (fOwner->fFocus == this) 5048 MakeFocus(false); 5049 5050 if (fOwner->fLastMouseMovedView == this) 5051 fOwner->fLastMouseMovedView = NULL; 5052 5053 fOwner->RemoveHandler(this); 5054 if (fShelf) 5055 fOwner->RemoveHandler(fShelf); 5056 } 5057 5058 if (newOwner && newOwner != fOwner) { 5059 newOwner->AddHandler(this); 5060 if (fShelf) 5061 newOwner->AddHandler(fShelf); 5062 5063 if (fTopLevelView) 5064 SetNextHandler(newOwner); 5065 else 5066 SetNextHandler(fParent); 5067 } 5068 5069 fOwner = newOwner; 5070 5071 for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling) 5072 child->_SetOwner(newOwner); 5073 } 5074 5075 5076 void 5077 BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync) 5078 { 5079 if (!picture) 5080 return; 5081 5082 #if 1 5083 // TODO: Move the implementation to the server!!! 5084 // This implementation is pretty slow, since just creating an offscreen 5085 // bitmap takes a lot of time. That's the main reason why it should be moved 5086 // to the server. 5087 5088 // Here the idea is to get rid of the padding bytes in the bitmap, 5089 // as padding complicates and slows down the iteration. 5090 // TODO: Maybe it's not so nice as it assumes BBitmaps to be aligned 5091 // to a 4 byte boundary. 5092 BRect bounds(Bounds()); 5093 if ((bounds.IntegerWidth() + 1) % 32) { 5094 bounds.right = bounds.left + ((bounds.IntegerWidth() + 1) / 32 + 1) 5095 * 32 - 1; 5096 } 5097 5098 // TODO: I used a RGBA32 bitmap because drawing on a GRAY8 doesn't work. 5099 BBitmap* bitmap = new(std::nothrow) BBitmap(bounds, B_RGBA32, true); 5100 if (bitmap != NULL && bitmap->InitCheck() == B_OK && bitmap->Lock()) { 5101 BView* view = new(std::nothrow) BView(bounds, "drawing view", 5102 B_FOLLOW_NONE, 0); 5103 if (view != NULL) { 5104 bitmap->AddChild(view); 5105 view->DrawPicture(picture, where); 5106 view->Sync(); 5107 } 5108 bitmap->Unlock(); 5109 } 5110 5111 BRegion region; 5112 int32 width = bounds.IntegerWidth() + 1; 5113 int32 height = bounds.IntegerHeight() + 1; 5114 if (bitmap != NULL && bitmap->LockBits() == B_OK) { 5115 uint32 bit = 0; 5116 uint32* bits = (uint32*)bitmap->Bits(); 5117 clipping_rect rect; 5118 5119 // TODO: A possible optimization would be adding "spans" instead 5120 // of 1x1 rects. That would probably help with very complex 5121 // BPictures 5122 for (int32 y = 0; y < height; y++) { 5123 for (int32 x = 0; x < width; x++) { 5124 bit = *bits++; 5125 if (bit != 0xFFFFFFFF) { 5126 rect.left = x; 5127 rect.right = rect.left; 5128 rect.top = rect.bottom = y; 5129 region.Include(rect); 5130 } 5131 } 5132 } 5133 bitmap->UnlockBits(); 5134 } 5135 delete bitmap; 5136 5137 if (invert) { 5138 BRegion inverseRegion; 5139 inverseRegion.Include(Bounds()); 5140 inverseRegion.Exclude(®ion); 5141 ConstrainClippingRegion(&inverseRegion); 5142 } else 5143 ConstrainClippingRegion(®ion); 5144 #else 5145 if (_CheckOwnerLockAndSwitchCurrent()) { 5146 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE); 5147 fOwner->fLink->Attach<int32>(picture->Token()); 5148 fOwner->fLink->Attach<BPoint>(where); 5149 fOwner->fLink->Attach<bool>(invert); 5150 5151 // TODO: I think that "sync" means another thing here: 5152 // the bebook, at least, says so. 5153 if (sync) 5154 fOwner->fLink->Flush(); 5155 5156 fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT; 5157 } 5158 5159 fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT; 5160 #endif 5161 } 5162 5163 5164 bool 5165 BView::_RemoveChildFromList(BView* child) 5166 { 5167 if (child->fParent != this) 5168 return false; 5169 5170 if (fFirstChild == child) { 5171 // it's the first view in the list 5172 fFirstChild = child->fNextSibling; 5173 } else { 5174 // there must be a previous sibling 5175 child->fPreviousSibling->fNextSibling = child->fNextSibling; 5176 } 5177 5178 if (child->fNextSibling) 5179 child->fNextSibling->fPreviousSibling = child->fPreviousSibling; 5180 5181 child->fParent = NULL; 5182 child->fNextSibling = NULL; 5183 child->fPreviousSibling = NULL; 5184 5185 return true; 5186 } 5187 5188 5189 bool 5190 BView::_AddChildToList(BView* child, BView* before) 5191 { 5192 if (!child) 5193 return false; 5194 if (child->fParent != NULL) { 5195 debugger("View already belongs to someone else"); 5196 return false; 5197 } 5198 if (before != NULL && before->fParent != this) { 5199 debugger("Invalid before view"); 5200 return false; 5201 } 5202 5203 if (before != NULL) { 5204 // add view before this one 5205 child->fNextSibling = before; 5206 child->fPreviousSibling = before->fPreviousSibling; 5207 if (child->fPreviousSibling != NULL) 5208 child->fPreviousSibling->fNextSibling = child; 5209 5210 before->fPreviousSibling = child; 5211 if (fFirstChild == before) 5212 fFirstChild = child; 5213 } else { 5214 // add view to the end of the list 5215 BView* last = fFirstChild; 5216 while (last != NULL && last->fNextSibling != NULL) { 5217 last = last->fNextSibling; 5218 } 5219 5220 if (last != NULL) { 5221 last->fNextSibling = child; 5222 child->fPreviousSibling = last; 5223 } else { 5224 fFirstChild = child; 5225 child->fPreviousSibling = NULL; 5226 } 5227 5228 child->fNextSibling = NULL; 5229 } 5230 5231 child->fParent = this; 5232 return true; 5233 } 5234 5235 5236 /*! \brief Creates the server counterpart of this view. 5237 This is only done for views that are part of the view hierarchy, ie. when 5238 they are attached to a window. 5239 RemoveSelf() deletes the server object again. 5240 */ 5241 bool 5242 BView::_CreateSelf() 5243 { 5244 // AS_VIEW_CREATE & AS_VIEW_CREATE_ROOT do not use the 5245 // current view mechanism via _CheckLockAndSwitchCurrent() - the token 5246 // of the view and its parent are both send to the server. 5247 5248 if (fTopLevelView) 5249 fOwner->fLink->StartMessage(AS_VIEW_CREATE_ROOT); 5250 else 5251 fOwner->fLink->StartMessage(AS_VIEW_CREATE); 5252 5253 fOwner->fLink->Attach<int32>(_get_object_token_(this)); 5254 fOwner->fLink->AttachString(Name()); 5255 fOwner->fLink->Attach<BRect>(Frame()); 5256 fOwner->fLink->Attach<BPoint>(LeftTop()); 5257 fOwner->fLink->Attach<uint32>(ResizingMode()); 5258 fOwner->fLink->Attach<uint32>(fEventMask); 5259 fOwner->fLink->Attach<uint32>(fEventOptions); 5260 fOwner->fLink->Attach<uint32>(Flags()); 5261 fOwner->fLink->Attach<bool>(IsHidden(this)); 5262 fOwner->fLink->Attach<rgb_color>(fState->view_color); 5263 if (fTopLevelView) 5264 fOwner->fLink->Attach<int32>(B_NULL_TOKEN); 5265 else 5266 fOwner->fLink->Attach<int32>(_get_object_token_(fParent)); 5267 fOwner->fLink->Flush(); 5268 5269 _CheckOwnerLockAndSwitchCurrent(); 5270 fState->UpdateServerState(*fOwner->fLink); 5271 5272 // we create all its children, too 5273 5274 for (BView* child = fFirstChild; child != NULL; 5275 child = child->fNextSibling) { 5276 child->_CreateSelf(); 5277 } 5278 5279 fOwner->fLink->Flush(); 5280 return true; 5281 } 5282 5283 5284 /*! Sets the new view position. 5285 It doesn't contact the server, though - the only case where this 5286 is called outside of MoveTo() is as reaction of moving a view 5287 in the server (a.k.a. B_WINDOW_RESIZED). 5288 It also calls the BView's FrameMoved() hook. 5289 */ 5290 void 5291 BView::_MoveTo(int32 x, int32 y) 5292 { 5293 fParentOffset.Set(x, y); 5294 5295 if (Window() != NULL && fFlags & B_FRAME_EVENTS) { 5296 BMessage moved(B_VIEW_MOVED); 5297 moved.AddInt64("when", system_time()); 5298 moved.AddPoint("where", BPoint(x, y)); 5299 5300 BMessenger target(this); 5301 target.SendMessage(&moved); 5302 } 5303 } 5304 5305 5306 /*! Computes the actual new frame size and recalculates the size of 5307 the children as well. 5308 It doesn't contact the server, though - the only case where this 5309 is called outside of ResizeBy() is as reaction of resizing a view 5310 in the server (a.k.a. B_WINDOW_RESIZED). 5311 It also calls the BView's FrameResized() hook. 5312 */ 5313 void 5314 BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight) 5315 { 5316 fBounds.right += deltaWidth; 5317 fBounds.bottom += deltaHeight; 5318 5319 if (Window() == NULL) { 5320 // we're not supposed to exercise the resizing code in case 5321 // we haven't been attached to a window yet 5322 return; 5323 } 5324 5325 // layout the children 5326 if (fFlags & B_SUPPORTS_LAYOUT) { 5327 Relayout(); 5328 } else { 5329 for (BView* child = fFirstChild; child; child = child->fNextSibling) 5330 child->_ParentResizedBy(deltaWidth, deltaHeight); 5331 } 5332 5333 if (fFlags & B_FRAME_EVENTS) { 5334 BMessage resized(B_VIEW_RESIZED); 5335 resized.AddInt64("when", system_time()); 5336 resized.AddInt32("width", fBounds.IntegerWidth()); 5337 resized.AddInt32("height", fBounds.IntegerHeight()); 5338 5339 BMessenger target(this); 5340 target.SendMessage(&resized); 5341 } 5342 } 5343 5344 5345 /*! Relayouts the view according to its resizing mode. */ 5346 void 5347 BView::_ParentResizedBy(int32 x, int32 y) 5348 { 5349 uint32 resizingMode = fFlags & _RESIZE_MASK_; 5350 BRect newFrame = Frame(); 5351 5352 // follow with left side 5353 if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8) 5354 newFrame.left += x; 5355 else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8) 5356 newFrame.left += x / 2; 5357 5358 // follow with right side 5359 if ((resizingMode & 0x000FU) == _VIEW_RIGHT_) 5360 newFrame.right += x; 5361 else if ((resizingMode & 0x000FU) == _VIEW_CENTER_) 5362 newFrame.right += x / 2; 5363 5364 // follow with top side 5365 if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12) 5366 newFrame.top += y; 5367 else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12) 5368 newFrame.top += y / 2; 5369 5370 // follow with bottom side 5371 if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4) 5372 newFrame.bottom += y; 5373 else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4) 5374 newFrame.bottom += y / 2; 5375 5376 if (newFrame.LeftTop() != fParentOffset) { 5377 // move view 5378 _MoveTo((int32)roundf(newFrame.left), (int32)roundf(newFrame.top)); 5379 } 5380 5381 if (newFrame != Frame()) { 5382 // resize view 5383 int32 widthDiff = (int32)(newFrame.Width() - fBounds.Width()); 5384 int32 heightDiff = (int32)(newFrame.Height() - fBounds.Height()); 5385 _ResizeBy(widthDiff, heightDiff); 5386 } 5387 } 5388 5389 5390 void 5391 BView::_Activate(bool active) 5392 { 5393 WindowActivated(active); 5394 5395 for (BView* child = fFirstChild; child != NULL; 5396 child = child->fNextSibling) { 5397 child->_Activate(active); 5398 } 5399 } 5400 5401 5402 void 5403 BView::_Attach() 5404 { 5405 AttachedToWindow(); 5406 fAttached = true; 5407 5408 // after giving the view a chance to do this itself, 5409 // check for the B_PULSE_NEEDED flag and make sure the 5410 // window set's up the pulse messaging 5411 if (fOwner) { 5412 if (fFlags & B_PULSE_NEEDED) { 5413 _CheckLock(); 5414 if (fOwner->fPulseRunner == NULL) 5415 fOwner->SetPulseRate(fOwner->PulseRate()); 5416 } 5417 5418 if (!fOwner->IsHidden()) 5419 Invalidate(); 5420 } 5421 5422 for (BView* child = fFirstChild; child != NULL; 5423 child = child->fNextSibling) { 5424 // we need to check for fAttached as new views could have been 5425 // added in AttachedToWindow() - and those are already attached 5426 if (!child->fAttached) 5427 child->_Attach(); 5428 } 5429 5430 AllAttached(); 5431 } 5432 5433 5434 void 5435 BView::_Detach() 5436 { 5437 DetachedFromWindow(); 5438 fAttached = false; 5439 5440 for (BView* child = fFirstChild; child != NULL; 5441 child = child->fNextSibling) { 5442 child->_Detach(); 5443 } 5444 5445 AllDetached(); 5446 5447 if (fOwner) { 5448 _CheckLock(); 5449 5450 if (!fOwner->IsHidden()) 5451 Invalidate(); 5452 5453 // make sure our owner doesn't need us anymore 5454 5455 if (fOwner->CurrentFocus() == this) { 5456 MakeFocus(false); 5457 // MakeFocus() is virtual and might not be 5458 // passing through to the BView version, 5459 // but we need to make sure at this point 5460 // that we are not the focus view anymore. 5461 if (fOwner->CurrentFocus() == this) 5462 fOwner->_SetFocus(NULL, true); 5463 } 5464 5465 if (fOwner->fDefaultButton == this) 5466 fOwner->SetDefaultButton(NULL); 5467 5468 if (fOwner->fKeyMenuBar == this) 5469 fOwner->fKeyMenuBar = NULL; 5470 5471 if (fOwner->fLastMouseMovedView == this) 5472 fOwner->fLastMouseMovedView = NULL; 5473 5474 if (fOwner->fLastViewToken == _get_object_token_(this)) 5475 fOwner->fLastViewToken = B_NULL_TOKEN; 5476 5477 _SetOwner(NULL); 5478 } 5479 } 5480 5481 5482 void 5483 BView::_Draw(BRect updateRect) 5484 { 5485 if (IsHidden(this) || !(Flags() & B_WILL_DRAW)) 5486 return; 5487 5488 // NOTE: if ViewColor() == B_TRANSPARENT_COLOR and no B_WILL_DRAW 5489 // -> View is simply not drawn at all 5490 5491 _SwitchServerCurrentView(); 5492 5493 ConvertFromScreen(&updateRect); 5494 5495 // TODO: make states robust (the hook implementation could 5496 // mess things up if it uses non-matching Push- and PopState(), 5497 // we would not be guaranteed to still have the same state on 5498 // the stack after having called Draw()) 5499 PushState(); 5500 Draw(updateRect); 5501 PopState(); 5502 Flush(); 5503 } 5504 5505 5506 void 5507 BView::_DrawAfterChildren(BRect updateRect) 5508 { 5509 if (IsHidden(this) || !(Flags() & B_WILL_DRAW) 5510 || !(Flags() & B_DRAW_ON_CHILDREN)) 5511 return; 5512 5513 _SwitchServerCurrentView(); 5514 5515 ConvertFromScreen(&updateRect); 5516 5517 // TODO: make states robust (see above) 5518 PushState(); 5519 DrawAfterChildren(updateRect); 5520 PopState(); 5521 Flush(); 5522 } 5523 5524 5525 void 5526 BView::_Pulse() 5527 { 5528 if ((Flags() & B_PULSE_NEEDED) != 0) 5529 Pulse(); 5530 5531 for (BView* child = fFirstChild; child != NULL; 5532 child = child->fNextSibling) { 5533 child->_Pulse(); 5534 } 5535 } 5536 5537 5538 void 5539 BView::_UpdateStateForRemove() 5540 { 5541 // TODO: _CheckLockAndSwitchCurrent() would be good enough, no? 5542 if (!_CheckOwnerLockAndSwitchCurrent()) 5543 return; 5544 5545 fState->UpdateFrom(*fOwner->fLink); 5546 // if (!fState->IsValid(B_VIEW_FRAME_BIT)) { 5547 // fOwner->fLink->StartMessage(AS_VIEW_GET_COORD); 5548 // 5549 // status_t code; 5550 // if (fOwner->fLink->FlushWithReply(code) == B_OK 5551 // && code == B_OK) { 5552 // fOwner->fLink->Read<BPoint>(&fParentOffset); 5553 // fOwner->fLink->Read<BRect>(&fBounds); 5554 // fState->valid_flags |= B_VIEW_FRAME_BIT; 5555 // } 5556 // } 5557 5558 // update children as well 5559 5560 for (BView* child = fFirstChild; child != NULL; 5561 child = child->fNextSibling) { 5562 if (child->fOwner) 5563 child->_UpdateStateForRemove(); 5564 } 5565 } 5566 5567 5568 inline void 5569 BView::_UpdatePattern(::pattern pattern) 5570 { 5571 if (fState->IsValid(B_VIEW_PATTERN_BIT) && pattern == fState->pattern) 5572 return; 5573 5574 if (fOwner) { 5575 _CheckLockAndSwitchCurrent(); 5576 5577 fOwner->fLink->StartMessage(AS_VIEW_SET_PATTERN); 5578 fOwner->fLink->Attach< ::pattern>(pattern); 5579 5580 fState->valid_flags |= B_VIEW_PATTERN_BIT; 5581 } 5582 5583 fState->pattern = pattern; 5584 } 5585 5586 5587 void 5588 BView::_FlushIfNotInTransaction() 5589 { 5590 if (!fOwner->fInTransaction) { 5591 fOwner->Flush(); 5592 } 5593 } 5594 5595 5596 BShelf* 5597 BView::_Shelf() const 5598 { 5599 return fShelf; 5600 } 5601 5602 5603 void 5604 BView::_SetShelf(BShelf* shelf) 5605 { 5606 if (fShelf != NULL && fOwner != NULL) 5607 fOwner->RemoveHandler(fShelf); 5608 5609 fShelf = shelf; 5610 5611 if (fShelf != NULL && fOwner != NULL) 5612 fOwner->AddHandler(fShelf); 5613 } 5614 5615 5616 status_t 5617 BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect, 5618 uint32 followFlags, uint32 options) 5619 { 5620 if (!_CheckOwnerLockAndSwitchCurrent()) 5621 return B_ERROR; 5622 5623 int32 serverToken = bitmap ? bitmap->_ServerToken() : -1; 5624 5625 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_BITMAP); 5626 fOwner->fLink->Attach<int32>(serverToken); 5627 fOwner->fLink->Attach<BRect>(srcRect); 5628 fOwner->fLink->Attach<BRect>(dstRect); 5629 fOwner->fLink->Attach<int32>(followFlags); 5630 fOwner->fLink->Attach<int32>(options); 5631 5632 status_t status = B_ERROR; 5633 fOwner->fLink->FlushWithReply(status); 5634 5635 return status; 5636 } 5637 5638 5639 bool 5640 BView::_CheckOwnerLockAndSwitchCurrent() const 5641 { 5642 STRACE(("BView(%s)::_CheckOwnerLockAndSwitchCurrent()\n", Name())); 5643 5644 if (fOwner == NULL) { 5645 debugger("View method requires owner and doesn't have one."); 5646 return false; 5647 } 5648 5649 _CheckLockAndSwitchCurrent(); 5650 5651 return true; 5652 } 5653 5654 5655 bool 5656 BView::_CheckOwnerLock() const 5657 { 5658 if (fOwner) { 5659 fOwner->check_lock(); 5660 return true; 5661 } else { 5662 debugger("View method requires owner and doesn't have one."); 5663 return false; 5664 } 5665 } 5666 5667 5668 void 5669 BView::_CheckLockAndSwitchCurrent() const 5670 { 5671 STRACE(("BView(%s)::_CheckLockAndSwitchCurrent()\n", Name())); 5672 5673 if (!fOwner) 5674 return; 5675 5676 fOwner->check_lock(); 5677 5678 _SwitchServerCurrentView(); 5679 } 5680 5681 5682 void 5683 BView::_CheckLock() const 5684 { 5685 if (fOwner) 5686 fOwner->check_lock(); 5687 } 5688 5689 5690 void 5691 BView::_SwitchServerCurrentView() const 5692 { 5693 int32 serverToken = _get_object_token_(this); 5694 5695 if (fOwner->fLastViewToken != serverToken) { 5696 STRACE(("contacting app_server... sending token: %ld\n", serverToken)); 5697 fOwner->fLink->StartMessage(AS_SET_CURRENT_VIEW); 5698 fOwner->fLink->Attach<int32>(serverToken); 5699 5700 fOwner->fLastViewToken = serverToken; 5701 } 5702 } 5703 5704 5705 void 5706 BView::ScrollWithMouseWheelDelta(BScrollBar* scrollBar, float delta) 5707 { 5708 if (scrollBar == NULL || delta == 0.0f) 5709 return; 5710 5711 float smallStep, largeStep; 5712 scrollBar->GetSteps(&smallStep, &largeStep); 5713 5714 // pressing the option/command/control key scrolls faster 5715 if (modifiers() 5716 & (B_OPTION_KEY | B_COMMAND_KEY | B_CONTROL_KEY)) { 5717 delta *= largeStep; 5718 } else 5719 delta *= smallStep * 3; 5720 5721 scrollBar->SetValue(scrollBar->Value() + delta); 5722 } 5723 5724 5725 #if __GNUC__ == 2 5726 5727 5728 extern "C" void 5729 _ReservedView1__5BView(BView* view, BRect rect) 5730 { 5731 view->BView::DrawAfterChildren(rect); 5732 } 5733 5734 5735 extern "C" void 5736 _ReservedView2__5BView(BView* view) 5737 { 5738 // MinSize() 5739 perform_data_min_size data; 5740 view->Perform(PERFORM_CODE_MIN_SIZE, &data); 5741 } 5742 5743 5744 extern "C" void 5745 _ReservedView3__5BView(BView* view) 5746 { 5747 // MaxSize() 5748 perform_data_max_size data; 5749 view->Perform(PERFORM_CODE_MAX_SIZE, &data); 5750 } 5751 5752 5753 extern "C" BSize 5754 _ReservedView4__5BView(BView* view) 5755 { 5756 // PreferredSize() 5757 perform_data_preferred_size data; 5758 view->Perform(PERFORM_CODE_PREFERRED_SIZE, &data); 5759 return data.return_value; 5760 } 5761 5762 5763 extern "C" BAlignment 5764 _ReservedView5__5BView(BView* view) 5765 { 5766 // LayoutAlignment() 5767 perform_data_layout_alignment data; 5768 view->Perform(PERFORM_CODE_LAYOUT_ALIGNMENT, &data); 5769 return data.return_value; 5770 } 5771 5772 5773 extern "C" bool 5774 _ReservedView6__5BView(BView* view) 5775 { 5776 // HasHeightForWidth() 5777 perform_data_has_height_for_width data; 5778 view->Perform(PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH, &data); 5779 return data.return_value; 5780 } 5781 5782 5783 extern "C" void 5784 _ReservedView7__5BView(BView* view, float width, float* min, float* max, 5785 float* preferred) 5786 { 5787 // GetHeightForWidth() 5788 perform_data_get_height_for_width data; 5789 data.width = width; 5790 view->Perform(PERFORM_CODE_GET_HEIGHT_FOR_WIDTH, &data); 5791 if (min != NULL) 5792 *min = data.min; 5793 if (max != NULL) 5794 *max = data.max; 5795 if (preferred != NULL) 5796 *preferred = data.preferred; 5797 } 5798 5799 5800 extern "C" void 5801 _ReservedView8__5BView(BView* view, BLayout* layout) 5802 { 5803 // SetLayout() 5804 perform_data_set_layout data; 5805 data.layout = layout; 5806 view->Perform(PERFORM_CODE_SET_LAYOUT, &data); 5807 } 5808 5809 5810 extern "C" void 5811 _ReservedView9__5BView(BView* view, bool descendants) 5812 { 5813 // LayoutInvalidated() 5814 perform_data_layout_invalidated data; 5815 data.descendants = descendants; 5816 view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data); 5817 } 5818 5819 5820 extern "C" void 5821 _ReservedView10__5BView(BView* view) 5822 { 5823 // DoLayout() 5824 view->Perform(PERFORM_CODE_DO_LAYOUT, NULL); 5825 } 5826 5827 5828 #endif // __GNUC__ == 2 5829 5830 5831 extern "C" bool 5832 B_IF_GCC_2(_ReservedView11__5BView, _ZN5BView15_ReservedView11Ev)( 5833 BView* view, BPoint point, BToolTip** _toolTip) 5834 { 5835 // GetToolTipAt() 5836 perform_data_get_tool_tip_at data; 5837 data.point = point; 5838 data.tool_tip = _toolTip; 5839 view->Perform(PERFORM_CODE_GET_TOOL_TIP_AT, &data); 5840 return data.return_value; 5841 } 5842 5843 5844 extern "C" void 5845 B_IF_GCC_2(_ReservedView12__5BView, _ZN5BView15_ReservedView12Ev)( 5846 BView* view) 5847 { 5848 // LayoutChanged(); 5849 view->Perform(PERFORM_CODE_LAYOUT_CHANGED, NULL); 5850 } 5851 5852 5853 void BView::_ReservedView13() {} 5854 void BView::_ReservedView14() {} 5855 void BView::_ReservedView15() {} 5856 void BView::_ReservedView16() {} 5857 5858 5859 BView::BView(const BView& other) 5860 : 5861 BHandler() 5862 { 5863 // this is private and not functional, but exported 5864 } 5865 5866 5867 BView& 5868 BView::operator=(const BView& other) 5869 { 5870 // this is private and not functional, but exported 5871 return *this; 5872 } 5873 5874 5875 void 5876 BView::_PrintToStream() 5877 { 5878 printf("BView::_PrintToStream()\n"); 5879 printf("\tName: %s\n" 5880 "\tParent: %s\n" 5881 "\tFirstChild: %s\n" 5882 "\tNextSibling: %s\n" 5883 "\tPrevSibling: %s\n" 5884 "\tOwner(Window): %s\n" 5885 "\tToken: %ld\n" 5886 "\tFlags: %ld\n" 5887 "\tView origin: (%f,%f)\n" 5888 "\tView Bounds rectangle: (%f,%f,%f,%f)\n" 5889 "\tShow level: %d\n" 5890 "\tTopView?: %s\n" 5891 "\tBPicture: %s\n" 5892 "\tVertical Scrollbar %s\n" 5893 "\tHorizontal Scrollbar %s\n" 5894 "\tIs Printing?: %s\n" 5895 "\tShelf?: %s\n" 5896 "\tEventMask: %ld\n" 5897 "\tEventOptions: %ld\n", 5898 Name(), 5899 fParent ? fParent->Name() : "NULL", 5900 fFirstChild ? fFirstChild->Name() : "NULL", 5901 fNextSibling ? fNextSibling->Name() : "NULL", 5902 fPreviousSibling ? fPreviousSibling->Name() : "NULL", 5903 fOwner ? fOwner->Name() : "NULL", 5904 _get_object_token_(this), 5905 fFlags, 5906 fParentOffset.x, fParentOffset.y, 5907 fBounds.left, fBounds.top, fBounds.right, fBounds.bottom, 5908 fShowLevel, 5909 fTopLevelView ? "YES" : "NO", 5910 fCurrentPicture? "YES" : "NULL", 5911 fVerScroller? "YES" : "NULL", 5912 fHorScroller? "YES" : "NULL", 5913 fIsPrinting? "YES" : "NO", 5914 fShelf? "YES" : "NO", 5915 fEventMask, 5916 fEventOptions); 5917 5918 printf("\tState status:\n" 5919 "\t\tLocalCoordianteSystem: (%f,%f)\n" 5920 "\t\tPenLocation: (%f,%f)\n" 5921 "\t\tPenSize: %f\n" 5922 "\t\tHighColor: [%d,%d,%d,%d]\n" 5923 "\t\tLowColor: [%d,%d,%d,%d]\n" 5924 "\t\tViewColor: [%d,%d,%d,%d]\n" 5925 "\t\tPattern: %llx\n" 5926 "\t\tDrawingMode: %d\n" 5927 "\t\tLineJoinMode: %d\n" 5928 "\t\tLineCapMode: %d\n" 5929 "\t\tMiterLimit: %f\n" 5930 "\t\tAlphaSource: %d\n" 5931 "\t\tAlphaFuntion: %d\n" 5932 "\t\tScale: %f\n" 5933 "\t\t(Print)FontAliasing: %s\n" 5934 "\t\tFont Info:\n", 5935 fState->origin.x, fState->origin.y, 5936 fState->pen_location.x, fState->pen_location.y, 5937 fState->pen_size, 5938 fState->high_color.red, fState->high_color.blue, fState->high_color.green, fState->high_color.alpha, 5939 fState->low_color.red, fState->low_color.blue, fState->low_color.green, fState->low_color.alpha, 5940 fState->view_color.red, fState->view_color.blue, fState->view_color.green, fState->view_color.alpha, 5941 *((uint64*)&(fState->pattern)), 5942 fState->drawing_mode, 5943 fState->line_join, 5944 fState->line_cap, 5945 fState->miter_limit, 5946 fState->alpha_source_mode, 5947 fState->alpha_function_mode, 5948 fState->scale, 5949 fState->font_aliasing? "YES" : "NO"); 5950 5951 fState->font.PrintToStream(); 5952 5953 // TODO: also print the line array. 5954 } 5955 5956 5957 void 5958 BView::_PrintTree() 5959 { 5960 int32 spaces = 2; 5961 BView* c = fFirstChild; //c = short for: current 5962 printf( "'%s'\n", Name() ); 5963 if (c != NULL) { 5964 while(true) { 5965 // action block 5966 { 5967 for (int i = 0; i < spaces; i++) 5968 printf(" "); 5969 5970 printf( "'%s'\n", c->Name() ); 5971 } 5972 5973 // go deep 5974 if (c->fFirstChild) { 5975 c = c->fFirstChild; 5976 spaces += 2; 5977 } else { 5978 // go right 5979 if (c->fNextSibling) { 5980 c = c->fNextSibling; 5981 } else { 5982 // go up 5983 while (!c->fParent->fNextSibling && c->fParent != this) { 5984 c = c->fParent; 5985 spaces -= 2; 5986 } 5987 5988 // that enough! We've reached this view. 5989 if (c->fParent == this) 5990 break; 5991 5992 c = c->fParent->fNextSibling; 5993 spaces -= 2; 5994 } 5995 } 5996 } 5997 } 5998 } 5999 6000 6001 // #pragma mark - 6002 6003 6004 BLayoutItem* 6005 BView::Private::LayoutItemAt(int32 index) 6006 { 6007 return fView->fLayoutData->fLayoutItems.ItemAt(index); 6008 } 6009 6010 6011 int32 6012 BView::Private::CountLayoutItems() 6013 { 6014 return fView->fLayoutData->fLayoutItems.CountItems(); 6015 } 6016 6017 6018 void 6019 BView::Private::RegisterLayoutItem(BLayoutItem* item) 6020 { 6021 fView->fLayoutData->fLayoutItems.AddItem(item); 6022 } 6023 6024 6025 void 6026 BView::Private::DeregisterLayoutItem(BLayoutItem* item) 6027 { 6028 fView->fLayoutData->fLayoutItems.RemoveItem(item); 6029 } 6030 6031 6032 bool 6033 BView::Private::MinMaxValid() 6034 { 6035 return fView->fLayoutData->fMinMaxValid; 6036 } 6037 6038 6039 bool 6040 BView::Private::WillLayout() 6041 { 6042 BView::LayoutData* data = fView->fLayoutData; 6043 if (data->fLayoutInProgress) 6044 return false; 6045 if (data->fNeedsRelayout || !data->fLayoutValid || !data->fMinMaxValid) 6046 return true; 6047 return false; 6048 } 6049