1 /* 2 * Copyright 2001-2013 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus, superstippi@gmx.de 7 * Axel Dörfler, axeld@pinc-software.de 8 * Adrian Oanca, adioanca@cotty.iren.ro 9 * Ingo Weinhold. ingo_weinhold@gmx.de 10 */ 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* point, bool checkLock) const 838 { 839 if (!fParent) { 840 if (fOwner) 841 fOwner->ConvertToScreen(point); 842 843 return; 844 } 845 846 if (checkLock) 847 _CheckOwnerLock(); 848 849 _ConvertToParent(point, false); 850 fParent->_ConvertToScreen(point, false); 851 } 852 853 854 void 855 BView::ConvertToScreen(BPoint* point) const 856 { 857 _ConvertToScreen(point, true); 858 } 859 860 861 BPoint 862 BView::ConvertToScreen(BPoint point) const 863 { 864 ConvertToScreen(&point); 865 866 return point; 867 } 868 869 870 void 871 BView::_ConvertFromScreen(BPoint* point, bool checkLock) const 872 { 873 if (!fParent) { 874 if (fOwner) 875 fOwner->ConvertFromScreen(point); 876 877 return; 878 } 879 880 if (checkLock) 881 _CheckOwnerLock(); 882 883 _ConvertFromParent(point, false); 884 fParent->_ConvertFromScreen(point, false); 885 } 886 887 888 void 889 BView::ConvertFromScreen(BPoint* point) const 890 { 891 _ConvertFromScreen(point, true); 892 } 893 894 895 BPoint 896 BView::ConvertFromScreen(BPoint point) const 897 { 898 ConvertFromScreen(&point); 899 900 return point; 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 updateRect) 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 == NULL) 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* pointArray, int32 numPoints, BRect bounds, 2943 bool closed, ::pattern pattern) 2944 { 2945 if (pointArray == NULL 2946 || numPoints <= 1 2947 || fOwner == NULL) 2948 return; 2949 2950 _CheckLockAndSwitchCurrent(); 2951 _UpdatePattern(pattern); 2952 2953 BPolygon polygon(pointArray, 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* pointArray, int32 numPoints, ::pattern pattern) 3025 { 3026 if (pointArray == NULL) 3027 return; 3028 3029 BPolygon polygon(pointArray, numPoints); 3030 FillPolygon(&polygon, pattern); 3031 } 3032 3033 3034 void 3035 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, 3036 const BGradient& gradient) 3037 { 3038 if (pointArray == NULL) 3039 return; 3040 3041 BPolygon polygon(pointArray, numPoints); 3042 FillPolygon(&polygon, gradient); 3043 } 3044 3045 3046 void 3047 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, BRect bounds, 3048 ::pattern pattern) 3049 { 3050 if (pointArray == NULL) 3051 return; 3052 3053 BPolygon polygon(pointArray, numPoints); 3054 3055 polygon.MapTo(polygon.Frame(), bounds); 3056 FillPolygon(&polygon, pattern); 3057 } 3058 3059 3060 void 3061 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, BRect bounds, 3062 const BGradient& gradient) 3063 { 3064 if (pointArray == NULL) 3065 return; 3066 3067 BPolygon polygon(pointArray, numPoints); 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 point1, BPoint point2, BPoint point3, 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>(point1); 3236 fOwner->fLink->Attach<BPoint>(point2); 3237 fOwner->fLink->Attach<BPoint>(point3); 3238 fOwner->fLink->Attach<BRect>(bounds); 3239 3240 _FlushIfNotInTransaction(); 3241 } 3242 3243 3244 void 3245 BView::StrokeTriangle(BPoint point1, BPoint point2, BPoint point3, 3246 ::pattern pattern) 3247 { 3248 if (fOwner) { 3249 // we construct the smallest rectangle that contains the 3 points 3250 // for the 1st point 3251 BRect bounds(point1, point1); 3252 3253 // for the 2nd point 3254 if (point2.x < bounds.left) 3255 bounds.left = point2.x; 3256 3257 if (point2.y < bounds.top) 3258 bounds.top = point2.y; 3259 3260 if (point2.x > bounds.right) 3261 bounds.right = point2.x; 3262 3263 if (point2.y > bounds.bottom) 3264 bounds.bottom = point2.y; 3265 3266 // for the 3rd point 3267 if (point3.x < bounds.left) 3268 bounds.left = point3.x; 3269 3270 if (point3.y < bounds.top) 3271 bounds.top = point3.y; 3272 3273 if (point3.x > bounds.right) 3274 bounds.right = point3.x; 3275 3276 if (point3.y > bounds.bottom) 3277 bounds.bottom = point3.y; 3278 3279 StrokeTriangle(point1, point2, point3, bounds, pattern); 3280 } 3281 } 3282 3283 3284 void 3285 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3, 3286 ::pattern pattern) 3287 { 3288 if (fOwner) { 3289 // we construct the smallest rectangle that contains the 3 points 3290 // for the 1st point 3291 BRect bounds(point1, point1); 3292 3293 // for the 2nd point 3294 if (point2.x < bounds.left) 3295 bounds.left = point2.x; 3296 3297 if (point2.y < bounds.top) 3298 bounds.top = point2.y; 3299 3300 if (point2.x > bounds.right) 3301 bounds.right = point2.x; 3302 3303 if (point2.y > bounds.bottom) 3304 bounds.bottom = point2.y; 3305 3306 // for the 3rd point 3307 if (point3.x < bounds.left) 3308 bounds.left = point3.x; 3309 3310 if (point3.y < bounds.top) 3311 bounds.top = point3.y; 3312 3313 if (point3.x > bounds.right) 3314 bounds.right = point3.x; 3315 3316 if (point3.y > bounds.bottom) 3317 bounds.bottom = point3.y; 3318 3319 FillTriangle(point1, point2, point3, bounds, pattern); 3320 } 3321 } 3322 3323 3324 void 3325 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3, 3326 const BGradient& gradient) 3327 { 3328 if (fOwner) { 3329 // we construct the smallest rectangle that contains the 3 points 3330 // for the 1st point 3331 BRect bounds(point1, point1); 3332 3333 // for the 2nd point 3334 if (point2.x < bounds.left) 3335 bounds.left = point2.x; 3336 3337 if (point2.y < bounds.top) 3338 bounds.top = point2.y; 3339 3340 if (point2.x > bounds.right) 3341 bounds.right = point2.x; 3342 3343 if (point2.y > bounds.bottom) 3344 bounds.bottom = point2.y; 3345 3346 // for the 3rd point 3347 if (point3.x < bounds.left) 3348 bounds.left = point3.x; 3349 3350 if (point3.y < bounds.top) 3351 bounds.top = point3.y; 3352 3353 if (point3.x > bounds.right) 3354 bounds.right = point3.x; 3355 3356 if (point3.y > bounds.bottom) 3357 bounds.bottom = point3.y; 3358 3359 FillTriangle(point1, point2, point3, bounds, gradient); 3360 } 3361 } 3362 3363 3364 void 3365 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3, 3366 BRect bounds, ::pattern pattern) 3367 { 3368 if (fOwner == NULL) 3369 return; 3370 3371 _CheckLockAndSwitchCurrent(); 3372 _UpdatePattern(pattern); 3373 3374 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE); 3375 fOwner->fLink->Attach<BPoint>(point1); 3376 fOwner->fLink->Attach<BPoint>(point2); 3377 fOwner->fLink->Attach<BPoint>(point3); 3378 fOwner->fLink->Attach<BRect>(bounds); 3379 3380 _FlushIfNotInTransaction(); 3381 } 3382 3383 3384 void 3385 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3, BRect bounds, 3386 const BGradient& gradient) 3387 { 3388 if (fOwner == NULL) 3389 return; 3390 3391 _CheckLockAndSwitchCurrent(); 3392 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE_GRADIENT); 3393 fOwner->fLink->Attach<BPoint>(point1); 3394 fOwner->fLink->Attach<BPoint>(point2); 3395 fOwner->fLink->Attach<BPoint>(point3); 3396 fOwner->fLink->Attach<BRect>(bounds); 3397 fOwner->fLink->AttachGradient(gradient); 3398 3399 _FlushIfNotInTransaction(); 3400 } 3401 3402 3403 void 3404 BView::StrokeLine(BPoint toPoint, ::pattern pattern) 3405 { 3406 StrokeLine(PenLocation(), toPoint, pattern); 3407 } 3408 3409 3410 void 3411 BView::StrokeLine(BPoint start, BPoint end, ::pattern pattern) 3412 { 3413 if (fOwner == NULL) 3414 return; 3415 3416 _CheckLockAndSwitchCurrent(); 3417 _UpdatePattern(pattern); 3418 3419 ViewStrokeLineInfo info; 3420 info.startPoint = start; 3421 info.endPoint = end; 3422 3423 fOwner->fLink->StartMessage(AS_STROKE_LINE); 3424 fOwner->fLink->Attach<ViewStrokeLineInfo>(info); 3425 3426 _FlushIfNotInTransaction(); 3427 3428 // this modifies our pen location, so we invalidate the flag. 3429 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT; 3430 } 3431 3432 3433 void 3434 BView::StrokeShape(BShape* shape, ::pattern pattern) 3435 { 3436 if (shape == NULL || fOwner == NULL) 3437 return; 3438 3439 shape_data* sd = (shape_data*)shape->fPrivateData; 3440 if (sd->opCount == 0 || sd->ptCount == 0) 3441 return; 3442 3443 _CheckLockAndSwitchCurrent(); 3444 _UpdatePattern(pattern); 3445 3446 fOwner->fLink->StartMessage(AS_STROKE_SHAPE); 3447 fOwner->fLink->Attach<BRect>(shape->Bounds()); 3448 fOwner->fLink->Attach<int32>(sd->opCount); 3449 fOwner->fLink->Attach<int32>(sd->ptCount); 3450 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(uint32)); 3451 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 3452 3453 _FlushIfNotInTransaction(); 3454 } 3455 3456 3457 void 3458 BView::FillShape(BShape* shape, ::pattern pattern) 3459 { 3460 if (shape == NULL || fOwner == NULL) 3461 return; 3462 3463 shape_data* sd = (shape_data*)(shape->fPrivateData); 3464 if (sd->opCount == 0 || sd->ptCount == 0) 3465 return; 3466 3467 _CheckLockAndSwitchCurrent(); 3468 _UpdatePattern(pattern); 3469 3470 fOwner->fLink->StartMessage(AS_FILL_SHAPE); 3471 fOwner->fLink->Attach<BRect>(shape->Bounds()); 3472 fOwner->fLink->Attach<int32>(sd->opCount); 3473 fOwner->fLink->Attach<int32>(sd->ptCount); 3474 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32)); 3475 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 3476 3477 _FlushIfNotInTransaction(); 3478 } 3479 3480 3481 void 3482 BView::FillShape(BShape* shape, const BGradient& gradient) 3483 { 3484 if (shape == NULL || fOwner == NULL) 3485 return; 3486 3487 shape_data* sd = (shape_data*)(shape->fPrivateData); 3488 if (sd->opCount == 0 || sd->ptCount == 0) 3489 return; 3490 3491 _CheckLockAndSwitchCurrent(); 3492 3493 fOwner->fLink->StartMessage(AS_FILL_SHAPE_GRADIENT); 3494 fOwner->fLink->Attach<BRect>(shape->Bounds()); 3495 fOwner->fLink->Attach<int32>(sd->opCount); 3496 fOwner->fLink->Attach<int32>(sd->ptCount); 3497 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32)); 3498 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint)); 3499 fOwner->fLink->AttachGradient(gradient); 3500 3501 _FlushIfNotInTransaction(); 3502 } 3503 3504 3505 void 3506 BView::BeginLineArray(int32 count) 3507 { 3508 if (fOwner == NULL) 3509 return; 3510 3511 if (count <= 0) 3512 debugger("Calling BeginLineArray with a count <= 0"); 3513 3514 _CheckLock(); 3515 3516 if (fCommArray) { 3517 debugger("Can't nest BeginLineArray calls"); 3518 // not fatal, but it helps during 3519 // development of your app and is in 3520 // line with R5... 3521 delete[] fCommArray->array; 3522 delete fCommArray; 3523 } 3524 3525 // TODO: since this method cannot return failure, and further AddLine() 3526 // calls with a NULL fCommArray would drop into the debugger anyway, 3527 // we allow the possible std::bad_alloc exceptions here... 3528 fCommArray = new _array_data_; 3529 fCommArray->maxCount = count; 3530 fCommArray->count = 0; 3531 fCommArray->array = new ViewLineArrayInfo[count]; 3532 } 3533 3534 3535 void 3536 BView::AddLine(BPoint start, BPoint end, rgb_color color) 3537 { 3538 if (fOwner == NULL) 3539 return; 3540 3541 if (!fCommArray) 3542 debugger("BeginLineArray must be called before using AddLine"); 3543 3544 _CheckLock(); 3545 3546 const uint32 &arrayCount = fCommArray->count; 3547 if (arrayCount < fCommArray->maxCount) { 3548 fCommArray->array[arrayCount].startPoint = start; 3549 fCommArray->array[arrayCount].endPoint = end; 3550 fCommArray->array[arrayCount].color = color; 3551 3552 fCommArray->count++; 3553 } 3554 } 3555 3556 3557 void 3558 BView::EndLineArray() 3559 { 3560 if (fOwner == NULL) 3561 return; 3562 3563 if (fCommArray == NULL) 3564 debugger("Can't call EndLineArray before BeginLineArray"); 3565 3566 _CheckLockAndSwitchCurrent(); 3567 3568 fOwner->fLink->StartMessage(AS_STROKE_LINEARRAY); 3569 fOwner->fLink->Attach<int32>(fCommArray->count); 3570 fOwner->fLink->Attach(fCommArray->array, 3571 fCommArray->count * sizeof(ViewLineArrayInfo)); 3572 3573 _FlushIfNotInTransaction(); 3574 3575 _RemoveCommArray(); 3576 } 3577 3578 3579 void 3580 BView::SetDiskMode(char* filename, long offset) 3581 { 3582 // TODO: implement 3583 // One BeBook version has this to say about SetDiskMode(): 3584 // 3585 // "Begins recording a picture to the file with the given filename 3586 // at the given offset. Subsequent drawing commands sent to the view 3587 // will be written to the file until EndPicture() is called. The 3588 // stored commands may be played from the file with DrawPicture()." 3589 } 3590 3591 3592 void 3593 BView::BeginPicture(BPicture* picture) 3594 { 3595 if (_CheckOwnerLockAndSwitchCurrent() 3596 && picture && picture->fUsurped == NULL) { 3597 picture->Usurp(fCurrentPicture); 3598 fCurrentPicture = picture; 3599 3600 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_PICTURE); 3601 } 3602 } 3603 3604 3605 void 3606 BView::AppendToPicture(BPicture* picture) 3607 { 3608 _CheckLockAndSwitchCurrent(); 3609 3610 if (picture && picture->fUsurped == NULL) { 3611 int32 token = picture->Token(); 3612 3613 if (token == -1) { 3614 BeginPicture(picture); 3615 } else { 3616 picture->SetToken(-1); 3617 picture->Usurp(fCurrentPicture); 3618 fCurrentPicture = picture; 3619 fOwner->fLink->StartMessage(AS_VIEW_APPEND_TO_PICTURE); 3620 fOwner->fLink->Attach<int32>(token); 3621 } 3622 } 3623 } 3624 3625 3626 BPicture* 3627 BView::EndPicture() 3628 { 3629 if (_CheckOwnerLockAndSwitchCurrent() && fCurrentPicture) { 3630 int32 token; 3631 3632 fOwner->fLink->StartMessage(AS_VIEW_END_PICTURE); 3633 3634 int32 code; 3635 if (fOwner->fLink->FlushWithReply(code) == B_OK 3636 && code == B_OK 3637 && fOwner->fLink->Read<int32>(&token) == B_OK) { 3638 BPicture* picture = fCurrentPicture; 3639 fCurrentPicture = picture->StepDown(); 3640 picture->SetToken(token); 3641 3642 // TODO do this more efficient e.g. use a shared area and let the 3643 // client write into it 3644 picture->_Download(); 3645 return picture; 3646 } 3647 } 3648 3649 return NULL; 3650 } 3651 3652 3653 void 3654 BView::SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect, 3655 uint32 followFlags, uint32 options) 3656 { 3657 _SetViewBitmap(bitmap, srcRect, dstRect, followFlags, options); 3658 } 3659 3660 3661 void 3662 BView::SetViewBitmap(const BBitmap* bitmap, uint32 followFlags, uint32 options) 3663 { 3664 BRect rect; 3665 if (bitmap) 3666 rect = bitmap->Bounds(); 3667 3668 rect.OffsetTo(B_ORIGIN); 3669 3670 _SetViewBitmap(bitmap, rect, rect, followFlags, options); 3671 } 3672 3673 3674 void 3675 BView::ClearViewBitmap() 3676 { 3677 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0); 3678 } 3679 3680 3681 status_t 3682 BView::SetViewOverlay(const BBitmap* overlay, BRect srcRect, BRect dstRect, 3683 rgb_color* colorKey, uint32 followFlags, uint32 options) 3684 { 3685 if (overlay == NULL || (overlay->fFlags & B_BITMAP_WILL_OVERLAY) == 0) 3686 return B_BAD_VALUE; 3687 3688 status_t status = _SetViewBitmap(overlay, srcRect, dstRect, followFlags, 3689 options | AS_REQUEST_COLOR_KEY); 3690 if (status == B_OK) { 3691 // read the color that will be treated as transparent 3692 fOwner->fLink->Read<rgb_color>(colorKey); 3693 } 3694 3695 return status; 3696 } 3697 3698 3699 status_t 3700 BView::SetViewOverlay(const BBitmap* overlay, rgb_color* colorKey, 3701 uint32 followFlags, uint32 options) 3702 { 3703 if (overlay == NULL) 3704 return B_BAD_VALUE; 3705 3706 BRect rect = overlay->Bounds(); 3707 rect.OffsetTo(B_ORIGIN); 3708 3709 return SetViewOverlay(overlay, rect, rect, colorKey, followFlags, options); 3710 } 3711 3712 3713 void 3714 BView::ClearViewOverlay() 3715 { 3716 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0); 3717 } 3718 3719 3720 void 3721 BView::CopyBits(BRect src, BRect dst) 3722 { 3723 if (fOwner == NULL) 3724 return; 3725 3726 if (!src.IsValid() || !dst.IsValid()) 3727 return; 3728 3729 _CheckLockAndSwitchCurrent(); 3730 3731 fOwner->fLink->StartMessage(AS_VIEW_COPY_BITS); 3732 fOwner->fLink->Attach<BRect>(src); 3733 fOwner->fLink->Attach<BRect>(dst); 3734 3735 _FlushIfNotInTransaction(); 3736 } 3737 3738 3739 void 3740 BView::DrawPicture(const BPicture* picture) 3741 { 3742 if (picture == NULL) 3743 return; 3744 3745 DrawPictureAsync(picture, PenLocation()); 3746 Sync(); 3747 } 3748 3749 3750 void 3751 BView::DrawPicture(const BPicture* picture, BPoint where) 3752 { 3753 if (picture == NULL) 3754 return; 3755 3756 DrawPictureAsync(picture, where); 3757 Sync(); 3758 } 3759 3760 3761 void 3762 BView::DrawPicture(const char* filename, long offset, BPoint where) 3763 { 3764 if (!filename) 3765 return; 3766 3767 DrawPictureAsync(filename, offset, where); 3768 Sync(); 3769 } 3770 3771 3772 void 3773 BView::DrawPictureAsync(const BPicture* picture) 3774 { 3775 if (picture == NULL) 3776 return; 3777 3778 DrawPictureAsync(picture, PenLocation()); 3779 } 3780 3781 3782 void 3783 BView::DrawPictureAsync(const BPicture* picture, BPoint where) 3784 { 3785 if (picture == NULL) 3786 return; 3787 3788 if (_CheckOwnerLockAndSwitchCurrent() && picture->Token() > 0) { 3789 fOwner->fLink->StartMessage(AS_VIEW_DRAW_PICTURE); 3790 fOwner->fLink->Attach<int32>(picture->Token()); 3791 fOwner->fLink->Attach<BPoint>(where); 3792 3793 _FlushIfNotInTransaction(); 3794 } 3795 } 3796 3797 3798 void 3799 BView::DrawPictureAsync(const char* filename, long offset, BPoint where) 3800 { 3801 if (!filename) 3802 return; 3803 3804 // TODO: Test 3805 BFile file(filename, B_READ_ONLY); 3806 if (file.InitCheck() < B_OK) 3807 return; 3808 3809 file.Seek(offset, SEEK_SET); 3810 3811 BPicture picture; 3812 if (picture.Unflatten(&file) < B_OK) 3813 return; 3814 3815 DrawPictureAsync(&picture, where); 3816 } 3817 3818 3819 void 3820 BView::Invalidate(BRect invalRect) 3821 { 3822 if (fOwner == NULL) 3823 return; 3824 3825 // NOTE: This rounding of the invalid rect is to stay compatible with BeOS. 3826 // On the server side, the invalid rect will be converted to a BRegion, 3827 // which rounds in a different manner, so that it really includes the 3828 // fractional coordinates of a BRect (ie ceilf(rect.right) & 3829 // ceilf(rect.bottom)), which is also what BeOS does. So we have to do the 3830 // different rounding here to stay compatible in both ways. 3831 invalRect.left = (int)invalRect.left; 3832 invalRect.top = (int)invalRect.top; 3833 invalRect.right = (int)invalRect.right; 3834 invalRect.bottom = (int)invalRect.bottom; 3835 if (!invalRect.IsValid()) 3836 return; 3837 3838 _CheckLockAndSwitchCurrent(); 3839 3840 fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_RECT); 3841 fOwner->fLink->Attach<BRect>(invalRect); 3842 3843 // TODO: determine why this check isn't working correctly. 3844 #if 0 3845 if (!fOwner->fUpdateRequested) { 3846 fOwner->fLink->Flush(); 3847 fOwner->fUpdateRequested = true; 3848 } 3849 #else 3850 fOwner->fLink->Flush(); 3851 #endif 3852 } 3853 3854 3855 void 3856 BView::Invalidate(const BRegion* region) 3857 { 3858 if (region == NULL || fOwner == NULL) 3859 return; 3860 3861 _CheckLockAndSwitchCurrent(); 3862 3863 fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_REGION); 3864 fOwner->fLink->AttachRegion(*region); 3865 3866 // TODO: See above. 3867 #if 0 3868 if (!fOwner->fUpdateRequested) { 3869 fOwner->fLink->Flush(); 3870 fOwner->fUpdateRequested = true; 3871 } 3872 #else 3873 fOwner->fLink->Flush(); 3874 #endif 3875 } 3876 3877 3878 void 3879 BView::Invalidate() 3880 { 3881 Invalidate(Bounds()); 3882 } 3883 3884 3885 void 3886 BView::InvertRect(BRect rect) 3887 { 3888 if (fOwner) { 3889 _CheckLockAndSwitchCurrent(); 3890 3891 fOwner->fLink->StartMessage(AS_VIEW_INVERT_RECT); 3892 fOwner->fLink->Attach<BRect>(rect); 3893 3894 _FlushIfNotInTransaction(); 3895 } 3896 } 3897 3898 3899 // #pragma mark - View Hierarchy Functions 3900 3901 3902 void 3903 BView::AddChild(BView* child, BView* before) 3904 { 3905 STRACE(("BView(%s)::AddChild(child '%s', before '%s')\n", 3906 this->Name(), 3907 child != NULL && child->Name() ? child->Name() : "NULL", 3908 before != NULL && before->Name() ? before->Name() : "NULL")); 3909 3910 if (!_AddChild(child, before)) 3911 return; 3912 3913 if (fLayoutData->fLayout) 3914 fLayoutData->fLayout->AddView(child); 3915 } 3916 3917 3918 bool 3919 BView::AddChild(BLayoutItem* child) 3920 { 3921 if (!fLayoutData->fLayout) 3922 return false; 3923 return fLayoutData->fLayout->AddItem(child); 3924 } 3925 3926 3927 bool 3928 BView::_AddChild(BView* child, BView* before) 3929 { 3930 if (!child) 3931 return false; 3932 3933 if (child->fParent != NULL) { 3934 debugger("AddChild failed - the view already has a parent."); 3935 return false; 3936 } 3937 3938 bool lockedOwner = false; 3939 if (fOwner && !fOwner->IsLocked()) { 3940 fOwner->Lock(); 3941 lockedOwner = true; 3942 } 3943 3944 if (!_AddChildToList(child, before)) { 3945 debugger("AddChild failed!"); 3946 if (lockedOwner) 3947 fOwner->Unlock(); 3948 return false; 3949 } 3950 3951 if (fOwner) { 3952 _CheckLockAndSwitchCurrent(); 3953 3954 child->_SetOwner(fOwner); 3955 child->_CreateSelf(); 3956 child->_Attach(); 3957 3958 if (lockedOwner) 3959 fOwner->Unlock(); 3960 } 3961 3962 InvalidateLayout(); 3963 3964 return true; 3965 } 3966 3967 3968 bool 3969 BView::RemoveChild(BView* child) 3970 { 3971 STRACE(("BView(%s)::RemoveChild(%s)\n", Name(), child->Name())); 3972 3973 if (!child) 3974 return false; 3975 3976 if (child->fParent != this) 3977 return false; 3978 3979 return child->RemoveSelf(); 3980 } 3981 3982 3983 int32 3984 BView::CountChildren() const 3985 { 3986 _CheckLock(); 3987 3988 uint32 count = 0; 3989 BView* child = fFirstChild; 3990 3991 while (child != NULL) { 3992 count++; 3993 child = child->fNextSibling; 3994 } 3995 3996 return count; 3997 } 3998 3999 4000 BView* 4001 BView::ChildAt(int32 index) const 4002 { 4003 _CheckLock(); 4004 4005 BView* child = fFirstChild; 4006 while (child != NULL && index-- > 0) { 4007 child = child->fNextSibling; 4008 } 4009 4010 return child; 4011 } 4012 4013 4014 BView* 4015 BView::NextSibling() const 4016 { 4017 return fNextSibling; 4018 } 4019 4020 4021 BView* 4022 BView::PreviousSibling() const 4023 { 4024 return fPreviousSibling; 4025 } 4026 4027 4028 bool 4029 BView::RemoveSelf() 4030 { 4031 if (fParent && fParent->fLayoutData->fLayout) { 4032 int32 itemsRemaining = fLayoutData->fLayoutItems.CountItems(); 4033 while (itemsRemaining-- > 0) { 4034 BLayoutItem* item = fLayoutData->fLayoutItems.ItemAt(0); 4035 // always remove item at index 0, since items are shuffled 4036 // downwards by BObjectList 4037 item->Layout()->RemoveItem(item); 4038 // removes item from fLayoutItems list 4039 delete item; 4040 } 4041 } 4042 4043 return _RemoveSelf(); 4044 } 4045 4046 4047 bool 4048 BView::_RemoveSelf() 4049 { 4050 STRACE(("BView(%s)::_RemoveSelf()\n", Name())); 4051 4052 // Remove this child from its parent 4053 4054 BWindow* owner = fOwner; 4055 _CheckLock(); 4056 4057 if (owner != NULL) { 4058 _UpdateStateForRemove(); 4059 _Detach(); 4060 } 4061 4062 BView* parent = fParent; 4063 if (!parent || !parent->_RemoveChildFromList(this)) 4064 return false; 4065 4066 if (owner != NULL && !fTopLevelView) { 4067 // the top level view is deleted by the app_server automatically 4068 owner->fLink->StartMessage(AS_VIEW_DELETE); 4069 owner->fLink->Attach<int32>(_get_object_token_(this)); 4070 } 4071 4072 parent->InvalidateLayout(); 4073 4074 STRACE(("DONE: BView(%s)::_RemoveSelf()\n", Name())); 4075 4076 return true; 4077 } 4078 4079 4080 BView* 4081 BView::Parent() const 4082 { 4083 if (fParent && fParent->fTopLevelView) 4084 return NULL; 4085 4086 return fParent; 4087 } 4088 4089 4090 BView* 4091 BView::FindView(const char* name) const 4092 { 4093 if (name == NULL) 4094 return NULL; 4095 4096 if (Name() != NULL && !strcmp(Name(), name)) 4097 return const_cast<BView*>(this); 4098 4099 BView* child = fFirstChild; 4100 while (child != NULL) { 4101 BView* view = child->FindView(name); 4102 if (view != NULL) 4103 return view; 4104 4105 child = child->fNextSibling; 4106 } 4107 4108 return NULL; 4109 } 4110 4111 4112 void 4113 BView::MoveBy(float deltaX, float deltaY) 4114 { 4115 MoveTo(fParentOffset.x + roundf(deltaX), fParentOffset.y + roundf(deltaY)); 4116 } 4117 4118 4119 void 4120 BView::MoveTo(BPoint where) 4121 { 4122 MoveTo(where.x, where.y); 4123 } 4124 4125 4126 void 4127 BView::MoveTo(float x, float y) 4128 { 4129 if (x == fParentOffset.x && y == fParentOffset.y) 4130 return; 4131 4132 // BeBook says we should do this. And it makes sense. 4133 x = roundf(x); 4134 y = roundf(y); 4135 4136 if (fOwner) { 4137 _CheckLockAndSwitchCurrent(); 4138 fOwner->fLink->StartMessage(AS_VIEW_MOVE_TO); 4139 fOwner->fLink->Attach<float>(x); 4140 fOwner->fLink->Attach<float>(y); 4141 4142 // fState->valid_flags |= B_VIEW_FRAME_BIT; 4143 4144 _FlushIfNotInTransaction(); 4145 } 4146 4147 _MoveTo((int32)x, (int32)y); 4148 } 4149 4150 4151 void 4152 BView::ResizeBy(float deltaWidth, float deltaHeight) 4153 { 4154 // BeBook says we should do this. And it makes sense. 4155 deltaWidth = roundf(deltaWidth); 4156 deltaHeight = roundf(deltaHeight); 4157 4158 if (deltaWidth == 0 && deltaHeight == 0) 4159 return; 4160 4161 if (fOwner) { 4162 _CheckLockAndSwitchCurrent(); 4163 fOwner->fLink->StartMessage(AS_VIEW_RESIZE_TO); 4164 4165 fOwner->fLink->Attach<float>(fBounds.Width() + deltaWidth); 4166 fOwner->fLink->Attach<float>(fBounds.Height() + deltaHeight); 4167 4168 // fState->valid_flags |= B_VIEW_FRAME_BIT; 4169 4170 _FlushIfNotInTransaction(); 4171 } 4172 4173 _ResizeBy((int32)deltaWidth, (int32)deltaHeight); 4174 } 4175 4176 4177 void 4178 BView::ResizeTo(float width, float height) 4179 { 4180 ResizeBy(width - fBounds.Width(), height - fBounds.Height()); 4181 } 4182 4183 4184 void 4185 BView::ResizeTo(BSize size) 4186 { 4187 ResizeBy(size.width - fBounds.Width(), size.height - fBounds.Height()); 4188 } 4189 4190 4191 // #pragma mark - Inherited Methods (from BHandler) 4192 4193 4194 status_t 4195 BView::GetSupportedSuites(BMessage* data) 4196 { 4197 if (data == NULL) 4198 return B_BAD_VALUE; 4199 4200 status_t status = data->AddString("suites", "suite/vnd.Be-view"); 4201 BPropertyInfo propertyInfo(sViewPropInfo); 4202 if (status == B_OK) 4203 status = data->AddFlat("messages", &propertyInfo); 4204 if (status == B_OK) 4205 return BHandler::GetSupportedSuites(data); 4206 return status; 4207 } 4208 4209 4210 BHandler* 4211 BView::ResolveSpecifier(BMessage* message, int32 index, BMessage* specifier, 4212 int32 what, const char* property) 4213 { 4214 if (message->what == B_WINDOW_MOVE_BY 4215 || message->what == B_WINDOW_MOVE_TO) { 4216 return this; 4217 } 4218 4219 BPropertyInfo propertyInfo(sViewPropInfo); 4220 status_t err = B_BAD_SCRIPT_SYNTAX; 4221 BMessage replyMsg(B_REPLY); 4222 4223 switch (propertyInfo.FindMatch(message, index, specifier, what, property)) { 4224 case 0: 4225 case 1: 4226 case 3: 4227 return this; 4228 4229 case 2: 4230 if (fShelf) { 4231 message->PopSpecifier(); 4232 return fShelf; 4233 } 4234 4235 err = B_NAME_NOT_FOUND; 4236 replyMsg.AddString("message", "This window doesn't have a shelf"); 4237 break; 4238 4239 case 4: 4240 { 4241 if (!fFirstChild) { 4242 err = B_NAME_NOT_FOUND; 4243 replyMsg.AddString("message", "This window doesn't have " 4244 "children."); 4245 break; 4246 } 4247 BView* child = NULL; 4248 switch (what) { 4249 case B_INDEX_SPECIFIER: 4250 { 4251 int32 index; 4252 err = specifier->FindInt32("index", &index); 4253 if (err == B_OK) 4254 child = ChildAt(index); 4255 break; 4256 } 4257 case B_REVERSE_INDEX_SPECIFIER: 4258 { 4259 int32 rindex; 4260 err = specifier->FindInt32("index", &rindex); 4261 if (err == B_OK) 4262 child = ChildAt(CountChildren() - rindex); 4263 break; 4264 } 4265 case B_NAME_SPECIFIER: 4266 { 4267 const char* name; 4268 err = specifier->FindString("name", &name); 4269 if (err == B_OK) 4270 child = FindView(name); 4271 break; 4272 } 4273 } 4274 4275 if (child != NULL) { 4276 message->PopSpecifier(); 4277 return child; 4278 } 4279 4280 if (err == B_OK) 4281 err = B_BAD_INDEX; 4282 4283 replyMsg.AddString("message", 4284 "Cannot find view at/with specified index/name."); 4285 break; 4286 } 4287 4288 default: 4289 return BHandler::ResolveSpecifier(message, index, specifier, what, 4290 property); 4291 } 4292 4293 if (err < B_OK) { 4294 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD; 4295 4296 if (err == B_BAD_SCRIPT_SYNTAX) 4297 replyMsg.AddString("message", "Didn't understand the specifier(s)"); 4298 else 4299 replyMsg.AddString("message", strerror(err)); 4300 } 4301 4302 replyMsg.AddInt32("error", err); 4303 message->SendReply(&replyMsg); 4304 return NULL; 4305 } 4306 4307 4308 void 4309 BView::MessageReceived(BMessage* message) 4310 { 4311 if (!message->HasSpecifiers()) { 4312 switch (message->what) { 4313 case B_VIEW_RESIZED: 4314 // By the time the message arrives, the bounds may have 4315 // changed already, that's why we don't use the values 4316 // in the message itself. 4317 FrameResized(fBounds.Width(), fBounds.Height()); 4318 break; 4319 4320 case B_VIEW_MOVED: 4321 FrameMoved(fParentOffset); 4322 break; 4323 4324 case B_MOUSE_IDLE: 4325 { 4326 BPoint where; 4327 if (message->FindPoint("be:view_where", &where) != B_OK) 4328 break; 4329 4330 BToolTip* tip; 4331 if (GetToolTipAt(where, &tip)) 4332 ShowToolTip(tip); 4333 else 4334 BHandler::MessageReceived(message); 4335 break; 4336 } 4337 4338 case B_MOUSE_WHEEL_CHANGED: 4339 { 4340 BScrollBar* horizontal = ScrollBar(B_HORIZONTAL); 4341 BScrollBar* vertical = ScrollBar(B_VERTICAL); 4342 if (horizontal == NULL && vertical == NULL) { 4343 // Pass the message to the next handler 4344 BHandler::MessageReceived(message); 4345 break; 4346 } 4347 4348 float deltaX = 0.0f, deltaY = 0.0f; 4349 if (horizontal != NULL) 4350 message->FindFloat("be:wheel_delta_x", &deltaX); 4351 if (vertical != NULL) 4352 message->FindFloat("be:wheel_delta_y", &deltaY); 4353 4354 if (deltaX == 0.0f && deltaY == 0.0f) 4355 break; 4356 4357 if (horizontal != NULL) { 4358 ScrollWithMouseWheelDelta(horizontal, deltaX); 4359 } 4360 4361 if (vertical != NULL) { 4362 ScrollWithMouseWheelDelta(vertical, deltaY); 4363 } 4364 break; 4365 } 4366 4367 default: 4368 BHandler::MessageReceived(message); 4369 break; 4370 } 4371 4372 return; 4373 } 4374 4375 // Scripting message 4376 4377 BMessage replyMsg(B_REPLY); 4378 status_t err = B_BAD_SCRIPT_SYNTAX; 4379 int32 index; 4380 BMessage specifier; 4381 int32 what; 4382 const char* property; 4383 4384 if (message->GetCurrentSpecifier(&index, &specifier, &what, &property) 4385 != B_OK) { 4386 return BHandler::MessageReceived(message); 4387 } 4388 4389 BPropertyInfo propertyInfo(sViewPropInfo); 4390 switch (propertyInfo.FindMatch(message, index, &specifier, what, 4391 property)) { 4392 case 0: 4393 if (message->what == B_GET_PROPERTY) { 4394 err = replyMsg.AddRect("result", Frame()); 4395 } else if (message->what == B_SET_PROPERTY) { 4396 BRect newFrame; 4397 err = message->FindRect("data", &newFrame); 4398 if (err == B_OK) { 4399 MoveTo(newFrame.LeftTop()); 4400 ResizeTo(newFrame.Width(), newFrame.Height()); 4401 } 4402 } 4403 break; 4404 case 1: 4405 if (message->what == B_GET_PROPERTY) { 4406 err = replyMsg.AddBool("result", IsHidden()); 4407 } else if (message->what == B_SET_PROPERTY) { 4408 bool newHiddenState; 4409 err = message->FindBool("data", &newHiddenState); 4410 if (err == B_OK) { 4411 if (newHiddenState == true) 4412 Hide(); 4413 else 4414 Show(); 4415 } 4416 } 4417 break; 4418 case 3: 4419 err = replyMsg.AddInt32("result", CountChildren()); 4420 break; 4421 default: 4422 return BHandler::MessageReceived(message); 4423 } 4424 4425 if (err != B_OK) { 4426 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD; 4427 4428 if (err == B_BAD_SCRIPT_SYNTAX) 4429 replyMsg.AddString("message", "Didn't understand the specifier(s)"); 4430 else 4431 replyMsg.AddString("message", strerror(err)); 4432 4433 replyMsg.AddInt32("error", err); 4434 } 4435 4436 message->SendReply(&replyMsg); 4437 } 4438 4439 4440 status_t 4441 BView::Perform(perform_code code, void* _data) 4442 { 4443 switch (code) { 4444 case PERFORM_CODE_MIN_SIZE: 4445 ((perform_data_min_size*)_data)->return_value 4446 = BView::MinSize(); 4447 return B_OK; 4448 case PERFORM_CODE_MAX_SIZE: 4449 ((perform_data_max_size*)_data)->return_value 4450 = BView::MaxSize(); 4451 return B_OK; 4452 case PERFORM_CODE_PREFERRED_SIZE: 4453 ((perform_data_preferred_size*)_data)->return_value 4454 = BView::PreferredSize(); 4455 return B_OK; 4456 case PERFORM_CODE_LAYOUT_ALIGNMENT: 4457 ((perform_data_layout_alignment*)_data)->return_value 4458 = BView::LayoutAlignment(); 4459 return B_OK; 4460 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH: 4461 ((perform_data_has_height_for_width*)_data)->return_value 4462 = BView::HasHeightForWidth(); 4463 return B_OK; 4464 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH: 4465 { 4466 perform_data_get_height_for_width* data 4467 = (perform_data_get_height_for_width*)_data; 4468 BView::GetHeightForWidth(data->width, &data->min, &data->max, 4469 &data->preferred); 4470 return B_OK; 4471 } 4472 case PERFORM_CODE_SET_LAYOUT: 4473 { 4474 perform_data_set_layout* data = (perform_data_set_layout*)_data; 4475 BView::SetLayout(data->layout); 4476 return B_OK; 4477 } 4478 case PERFORM_CODE_LAYOUT_INVALIDATED: 4479 { 4480 perform_data_layout_invalidated* data 4481 = (perform_data_layout_invalidated*)_data; 4482 BView::LayoutInvalidated(data->descendants); 4483 return B_OK; 4484 } 4485 case PERFORM_CODE_DO_LAYOUT: 4486 { 4487 BView::DoLayout(); 4488 return B_OK; 4489 } 4490 case PERFORM_CODE_LAYOUT_CHANGED: 4491 { 4492 BView::LayoutChanged(); 4493 return B_OK; 4494 } 4495 case PERFORM_CODE_GET_TOOL_TIP_AT: 4496 { 4497 perform_data_get_tool_tip_at* data 4498 = (perform_data_get_tool_tip_at*)_data; 4499 data->return_value 4500 = BView::GetToolTipAt(data->point, data->tool_tip); 4501 return B_OK; 4502 } 4503 case PERFORM_CODE_ALL_UNARCHIVED: 4504 { 4505 perform_data_all_unarchived* data = 4506 (perform_data_all_unarchived*)_data; 4507 4508 data->return_value = BView::AllUnarchived(data->archive); 4509 return B_OK; 4510 } 4511 case PERFORM_CODE_ALL_ARCHIVED: 4512 { 4513 perform_data_all_archived* data = 4514 (perform_data_all_archived*)_data; 4515 4516 data->return_value = BView::AllArchived(data->archive); 4517 return B_OK; 4518 } 4519 } 4520 4521 return BHandler::Perform(code, _data); 4522 } 4523 4524 4525 // #pragma mark - Layout Functions 4526 4527 4528 BSize 4529 BView::MinSize() 4530 { 4531 // TODO: make sure this works correctly when some methods are overridden 4532 float width, height; 4533 GetPreferredSize(&width, &height); 4534 4535 return BLayoutUtils::ComposeSize(fLayoutData->fMinSize, 4536 (fLayoutData->fLayout ? fLayoutData->fLayout->MinSize() 4537 : BSize(width, height))); 4538 } 4539 4540 4541 BSize 4542 BView::MaxSize() 4543 { 4544 return BLayoutUtils::ComposeSize(fLayoutData->fMaxSize, 4545 (fLayoutData->fLayout ? fLayoutData->fLayout->MaxSize() 4546 : BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED))); 4547 } 4548 4549 4550 BSize 4551 BView::PreferredSize() 4552 { 4553 // TODO: make sure this works correctly when some methods are overridden 4554 float width, height; 4555 GetPreferredSize(&width, &height); 4556 4557 return BLayoutUtils::ComposeSize(fLayoutData->fPreferredSize, 4558 (fLayoutData->fLayout ? fLayoutData->fLayout->PreferredSize() 4559 : BSize(width, height))); 4560 } 4561 4562 4563 BAlignment 4564 BView::LayoutAlignment() 4565 { 4566 return BLayoutUtils::ComposeAlignment(fLayoutData->fAlignment, 4567 (fLayoutData->fLayout ? fLayoutData->fLayout->Alignment() 4568 : BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER))); 4569 } 4570 4571 4572 void 4573 BView::SetExplicitMinSize(BSize size) 4574 { 4575 fLayoutData->fMinSize = size; 4576 InvalidateLayout(); 4577 } 4578 4579 4580 void 4581 BView::SetExplicitMaxSize(BSize size) 4582 { 4583 fLayoutData->fMaxSize = size; 4584 InvalidateLayout(); 4585 } 4586 4587 4588 void 4589 BView::SetExplicitPreferredSize(BSize size) 4590 { 4591 fLayoutData->fPreferredSize = size; 4592 InvalidateLayout(); 4593 } 4594 4595 4596 void 4597 BView::SetExplicitSize(BSize size) 4598 { 4599 fLayoutData->fMinSize = size; 4600 fLayoutData->fMaxSize = size; 4601 fLayoutData->fPreferredSize = size; 4602 InvalidateLayout(); 4603 } 4604 4605 4606 void 4607 BView::SetExplicitAlignment(BAlignment alignment) 4608 { 4609 fLayoutData->fAlignment = alignment; 4610 InvalidateLayout(); 4611 } 4612 4613 4614 BSize 4615 BView::ExplicitMinSize() const 4616 { 4617 return fLayoutData->fMinSize; 4618 } 4619 4620 4621 BSize 4622 BView::ExplicitMaxSize() const 4623 { 4624 return fLayoutData->fMaxSize; 4625 } 4626 4627 4628 BSize 4629 BView::ExplicitPreferredSize() const 4630 { 4631 return fLayoutData->fPreferredSize; 4632 } 4633 4634 4635 BAlignment 4636 BView::ExplicitAlignment() const 4637 { 4638 return fLayoutData->fAlignment; 4639 } 4640 4641 4642 bool 4643 BView::HasHeightForWidth() 4644 { 4645 return (fLayoutData->fLayout 4646 ? fLayoutData->fLayout->HasHeightForWidth() : false); 4647 } 4648 4649 4650 void 4651 BView::GetHeightForWidth(float width, float* min, float* max, float* preferred) 4652 { 4653 if (fLayoutData->fLayout) 4654 fLayoutData->fLayout->GetHeightForWidth(width, min, max, preferred); 4655 } 4656 4657 4658 void 4659 BView::SetLayout(BLayout* layout) 4660 { 4661 if (layout == fLayoutData->fLayout) 4662 return; 4663 4664 if (layout && layout->Layout()) 4665 debugger("BView::SetLayout() failed, layout is already in use."); 4666 4667 fFlags |= B_SUPPORTS_LAYOUT; 4668 4669 // unset and delete the old layout 4670 if (fLayoutData->fLayout) { 4671 fLayoutData->fLayout->SetOwner(NULL); 4672 delete fLayoutData->fLayout; 4673 } 4674 4675 fLayoutData->fLayout = layout; 4676 4677 if (fLayoutData->fLayout) { 4678 fLayoutData->fLayout->SetOwner(this); 4679 4680 // add all children 4681 int count = CountChildren(); 4682 for (int i = 0; i < count; i++) 4683 fLayoutData->fLayout->AddView(ChildAt(i)); 4684 } 4685 4686 InvalidateLayout(); 4687 } 4688 4689 4690 BLayout* 4691 BView::GetLayout() const 4692 { 4693 return fLayoutData->fLayout; 4694 } 4695 4696 4697 void 4698 BView::InvalidateLayout(bool descendants) 4699 { 4700 // printf("BView(%p)::InvalidateLayout(%i), valid: %i, inProgress: %i\n", 4701 // this, descendants, fLayoutData->fLayoutValid, 4702 // fLayoutData->fLayoutInProgress); 4703 4704 if (!fLayoutData->fMinMaxValid || fLayoutData->fLayoutInProgress 4705 || fLayoutData->fLayoutInvalidationDisabled > 0) { 4706 return; 4707 } 4708 4709 fLayoutData->fLayoutValid = false; 4710 fLayoutData->fMinMaxValid = false; 4711 LayoutInvalidated(descendants); 4712 4713 if (descendants) { 4714 for (BView* child = fFirstChild; 4715 child; child = child->fNextSibling) { 4716 child->InvalidateLayout(descendants); 4717 } 4718 } 4719 4720 if (fLayoutData->fLayout) 4721 fLayoutData->fLayout->InvalidateLayout(descendants); 4722 else 4723 _InvalidateParentLayout(); 4724 4725 if (fTopLevelView && fOwner) 4726 fOwner->PostMessage(B_LAYOUT_WINDOW); 4727 } 4728 4729 4730 void 4731 BView::EnableLayoutInvalidation() 4732 { 4733 if (fLayoutData->fLayoutInvalidationDisabled > 0) 4734 fLayoutData->fLayoutInvalidationDisabled--; 4735 } 4736 4737 4738 void 4739 BView::DisableLayoutInvalidation() 4740 { 4741 fLayoutData->fLayoutInvalidationDisabled++; 4742 } 4743 4744 4745 bool 4746 BView::IsLayoutInvalidationDisabled() 4747 { 4748 if (fLayoutData->fLayoutInvalidationDisabled > 0) 4749 return true; 4750 return false; 4751 } 4752 4753 4754 bool 4755 BView::IsLayoutValid() const 4756 { 4757 return fLayoutData->fLayoutValid; 4758 } 4759 4760 4761 void 4762 BView::ResetLayoutInvalidation() 4763 { 4764 fLayoutData->fMinMaxValid = true; 4765 } 4766 4767 4768 BLayoutContext* 4769 BView::LayoutContext() const 4770 { 4771 return fLayoutData->fLayoutContext; 4772 } 4773 4774 4775 void 4776 BView::Layout(bool force) 4777 { 4778 BLayoutContext context; 4779 _Layout(force, &context); 4780 } 4781 4782 4783 void 4784 BView::Relayout() 4785 { 4786 if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) { 4787 fLayoutData->fNeedsRelayout = true; 4788 if (fLayoutData->fLayout) 4789 fLayoutData->fLayout->RequireLayout(); 4790 4791 // Layout() is recursive, that is if the parent view is currently laid 4792 // out, we don't call layout() on this view, but wait for the parent's 4793 // Layout() to do that for us. 4794 if (!fParent || !fParent->fLayoutData->fLayoutInProgress) 4795 Layout(false); 4796 } 4797 } 4798 4799 4800 void 4801 BView::LayoutInvalidated(bool descendants) 4802 { 4803 // hook method 4804 } 4805 4806 4807 void 4808 BView::DoLayout() 4809 { 4810 if (fLayoutData->fLayout) 4811 fLayoutData->fLayout->_LayoutWithinContext(false, LayoutContext()); 4812 } 4813 4814 4815 void 4816 BView::SetToolTip(const char* text) 4817 { 4818 if (text == NULL || text[0] == '\0') { 4819 SetToolTip((BToolTip*)NULL); 4820 return; 4821 } 4822 4823 if (BTextToolTip* tip = dynamic_cast<BTextToolTip*>(fToolTip)) 4824 tip->SetText(text); 4825 else 4826 SetToolTip(new BTextToolTip(text)); 4827 } 4828 4829 4830 void 4831 BView::SetToolTip(BToolTip* tip) 4832 { 4833 if (fToolTip == tip) 4834 return; 4835 else if (tip == NULL) 4836 HideToolTip(); 4837 4838 if (fToolTip != NULL) 4839 fToolTip->ReleaseReference(); 4840 4841 fToolTip = tip; 4842 4843 if (fToolTip != NULL) 4844 fToolTip->AcquireReference(); 4845 } 4846 4847 4848 BToolTip* 4849 BView::ToolTip() const 4850 { 4851 return fToolTip; 4852 } 4853 4854 4855 void 4856 BView::ShowToolTip(BToolTip* tip) 4857 { 4858 if (tip == NULL) 4859 return; 4860 4861 BPoint where; 4862 GetMouse(&where, NULL, false); 4863 4864 BToolTipManager::Manager()->ShowTip(tip, ConvertToScreen(where), this); 4865 } 4866 4867 4868 void 4869 BView::HideToolTip() 4870 { 4871 BToolTipManager::Manager()->HideTip(); 4872 } 4873 4874 4875 bool 4876 BView::GetToolTipAt(BPoint point, BToolTip** _tip) 4877 { 4878 if (fToolTip != NULL) { 4879 *_tip = fToolTip; 4880 return true; 4881 } 4882 4883 *_tip = NULL; 4884 return false; 4885 } 4886 4887 4888 void 4889 BView::LayoutChanged() 4890 { 4891 // hook method 4892 } 4893 4894 4895 void 4896 BView::_Layout(bool force, BLayoutContext* context) 4897 { 4898 //printf("%p->BView::_Layout(%d, %p)\n", this, force, context); 4899 //printf(" fNeedsRelayout: %d, fLayoutValid: %d, fLayoutInProgress: %d\n", 4900 //fLayoutData->fNeedsRelayout, fLayoutData->fLayoutValid, 4901 //fLayoutData->fLayoutInProgress); 4902 if (fLayoutData->fNeedsRelayout || !fLayoutData->fLayoutValid || force) { 4903 fLayoutData->fLayoutValid = false; 4904 4905 if (fLayoutData->fLayoutInProgress) 4906 return; 4907 4908 BLayoutContext* oldContext = fLayoutData->fLayoutContext; 4909 fLayoutData->fLayoutContext = context; 4910 4911 fLayoutData->fLayoutInProgress = true; 4912 DoLayout(); 4913 fLayoutData->fLayoutInProgress = false; 4914 4915 fLayoutData->fLayoutValid = true; 4916 fLayoutData->fMinMaxValid = true; 4917 fLayoutData->fNeedsRelayout = false; 4918 4919 // layout children 4920 for(BView* child = fFirstChild; child; child = child->fNextSibling) { 4921 if (!child->IsHidden(child)) 4922 child->_Layout(force, context); 4923 } 4924 4925 LayoutChanged(); 4926 4927 fLayoutData->fLayoutContext = oldContext; 4928 4929 // invalidate the drawn content, if requested 4930 if (fFlags & B_INVALIDATE_AFTER_LAYOUT) 4931 Invalidate(); 4932 } 4933 } 4934 4935 4936 void 4937 BView::_LayoutLeft(BLayout* deleted) 4938 { 4939 // If our layout is added to another layout (via BLayout::AddItem()) 4940 // then we share ownership of our layout. In the event that our layout gets 4941 // deleted by the layout it has been added to, this method is called so 4942 // that we don't double-delete our layout. 4943 if (fLayoutData->fLayout == deleted) 4944 fLayoutData->fLayout = NULL; 4945 InvalidateLayout(); 4946 } 4947 4948 4949 void 4950 BView::_InvalidateParentLayout() 4951 { 4952 if (!fParent) 4953 return; 4954 4955 BLayout* layout = fLayoutData->fLayout; 4956 BLayout* layoutParent = layout ? layout->Layout() : NULL; 4957 if (layoutParent) { 4958 layoutParent->InvalidateLayout(); 4959 } else if (fLayoutData->fLayoutItems.CountItems() > 0) { 4960 int32 count = fLayoutData->fLayoutItems.CountItems(); 4961 for (int32 i = 0; i < count; i++) { 4962 fLayoutData->fLayoutItems.ItemAt(i)->Layout()->InvalidateLayout(); 4963 } 4964 } else { 4965 fParent->InvalidateLayout(); 4966 } 4967 } 4968 4969 4970 // #pragma mark - Private Functions 4971 4972 4973 void 4974 BView::_InitData(BRect frame, const char* name, uint32 resizingMode, 4975 uint32 flags) 4976 { 4977 // Info: The name of the view is set by BHandler constructor 4978 4979 STRACE(("BView::_InitData: enter\n")); 4980 4981 // initialize members 4982 if ((resizingMode & ~_RESIZE_MASK_) || (flags & _RESIZE_MASK_)) 4983 printf("%s BView::_InitData(): resizing mode or flags swapped\n", name); 4984 4985 // There are applications that swap the resize mask and the flags in the 4986 // BView constructor. This does not cause problems under BeOS as it just 4987 // ors the two fields to one 32bit flag. 4988 // For now we do the same but print the above warning message. 4989 // TODO: this should be removed at some point and the original 4990 // version restored: 4991 // fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_); 4992 fFlags = resizingMode | flags; 4993 4994 // handle rounding 4995 frame.left = roundf(frame.left); 4996 frame.top = roundf(frame.top); 4997 frame.right = roundf(frame.right); 4998 frame.bottom = roundf(frame.bottom); 4999 5000 fParentOffset.Set(frame.left, frame.top); 5001 5002 fOwner = NULL; 5003 fParent = NULL; 5004 fNextSibling = NULL; 5005 fPreviousSibling = NULL; 5006 fFirstChild = NULL; 5007 5008 fShowLevel = 0; 5009 fTopLevelView = false; 5010 5011 fCurrentPicture = NULL; 5012 fCommArray = NULL; 5013 5014 fVerScroller = NULL; 5015 fHorScroller = NULL; 5016 5017 fIsPrinting = false; 5018 fAttached = false; 5019 5020 // TODO: Since we cannot communicate failure, we don't use std::nothrow here 5021 // TODO: Maybe we could auto-delete those views on AddChild() instead? 5022 fState = new BPrivate::ViewState; 5023 5024 fBounds = frame.OffsetToCopy(B_ORIGIN); 5025 fShelf = NULL; 5026 5027 fEventMask = 0; 5028 fEventOptions = 0; 5029 fMouseEventOptions = 0; 5030 5031 fLayoutData = new LayoutData; 5032 5033 fToolTip = NULL; 5034 } 5035 5036 5037 void 5038 BView::_RemoveCommArray() 5039 { 5040 if (fCommArray) { 5041 delete [] fCommArray->array; 5042 delete fCommArray; 5043 fCommArray = NULL; 5044 } 5045 } 5046 5047 5048 void 5049 BView::_SetOwner(BWindow* newOwner) 5050 { 5051 if (!newOwner) 5052 _RemoveCommArray(); 5053 5054 if (fOwner != newOwner && fOwner) { 5055 if (fOwner->fFocus == this) 5056 MakeFocus(false); 5057 5058 if (fOwner->fLastMouseMovedView == this) 5059 fOwner->fLastMouseMovedView = NULL; 5060 5061 fOwner->RemoveHandler(this); 5062 if (fShelf) 5063 fOwner->RemoveHandler(fShelf); 5064 } 5065 5066 if (newOwner && newOwner != fOwner) { 5067 newOwner->AddHandler(this); 5068 if (fShelf) 5069 newOwner->AddHandler(fShelf); 5070 5071 if (fTopLevelView) 5072 SetNextHandler(newOwner); 5073 else 5074 SetNextHandler(fParent); 5075 } 5076 5077 fOwner = newOwner; 5078 5079 for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling) 5080 child->_SetOwner(newOwner); 5081 } 5082 5083 5084 void 5085 BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync) 5086 { 5087 if (!picture) 5088 return; 5089 5090 #if 1 5091 // TODO: Move the implementation to the server!!! 5092 // This implementation is pretty slow, since just creating an offscreen 5093 // bitmap takes a lot of time. That's the main reason why it should be moved 5094 // to the server. 5095 5096 // Here the idea is to get rid of the padding bytes in the bitmap, 5097 // as padding complicates and slows down the iteration. 5098 // TODO: Maybe it's not so nice as it assumes BBitmaps to be aligned 5099 // to a 4 byte boundary. 5100 BRect bounds(Bounds()); 5101 if ((bounds.IntegerWidth() + 1) % 32) { 5102 bounds.right = bounds.left + ((bounds.IntegerWidth() + 1) / 32 + 1) 5103 * 32 - 1; 5104 } 5105 5106 // TODO: I used a RGBA32 bitmap because drawing on a GRAY8 doesn't work. 5107 BBitmap* bitmap = new(std::nothrow) BBitmap(bounds, B_RGBA32, true); 5108 if (bitmap != NULL && bitmap->InitCheck() == B_OK && bitmap->Lock()) { 5109 BView* view = new(std::nothrow) BView(bounds, "drawing view", 5110 B_FOLLOW_NONE, 0); 5111 if (view != NULL) { 5112 bitmap->AddChild(view); 5113 view->DrawPicture(picture, where); 5114 view->Sync(); 5115 } 5116 bitmap->Unlock(); 5117 } 5118 5119 BRegion region; 5120 int32 width = bounds.IntegerWidth() + 1; 5121 int32 height = bounds.IntegerHeight() + 1; 5122 if (bitmap != NULL && bitmap->LockBits() == B_OK) { 5123 uint32 bit = 0; 5124 uint32* bits = (uint32*)bitmap->Bits(); 5125 clipping_rect rect; 5126 5127 // TODO: A possible optimization would be adding "spans" instead 5128 // of 1x1 rects. That would probably help with very complex 5129 // BPictures 5130 for (int32 y = 0; y < height; y++) { 5131 for (int32 x = 0; x < width; x++) { 5132 bit = *bits++; 5133 if (bit != 0xFFFFFFFF) { 5134 rect.left = x; 5135 rect.right = rect.left; 5136 rect.top = rect.bottom = y; 5137 region.Include(rect); 5138 } 5139 } 5140 } 5141 bitmap->UnlockBits(); 5142 } 5143 delete bitmap; 5144 5145 if (invert) { 5146 BRegion inverseRegion; 5147 inverseRegion.Include(Bounds()); 5148 inverseRegion.Exclude(®ion); 5149 ConstrainClippingRegion(&inverseRegion); 5150 } else 5151 ConstrainClippingRegion(®ion); 5152 #else 5153 if (_CheckOwnerLockAndSwitchCurrent()) { 5154 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE); 5155 fOwner->fLink->Attach<int32>(picture->Token()); 5156 fOwner->fLink->Attach<BPoint>(where); 5157 fOwner->fLink->Attach<bool>(invert); 5158 5159 // TODO: I think that "sync" means another thing here: 5160 // the bebook, at least, says so. 5161 if (sync) 5162 fOwner->fLink->Flush(); 5163 5164 fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT; 5165 } 5166 5167 fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT; 5168 #endif 5169 } 5170 5171 5172 bool 5173 BView::_RemoveChildFromList(BView* child) 5174 { 5175 if (child->fParent != this) 5176 return false; 5177 5178 if (fFirstChild == child) { 5179 // it's the first view in the list 5180 fFirstChild = child->fNextSibling; 5181 } else { 5182 // there must be a previous sibling 5183 child->fPreviousSibling->fNextSibling = child->fNextSibling; 5184 } 5185 5186 if (child->fNextSibling) 5187 child->fNextSibling->fPreviousSibling = child->fPreviousSibling; 5188 5189 child->fParent = NULL; 5190 child->fNextSibling = NULL; 5191 child->fPreviousSibling = NULL; 5192 5193 return true; 5194 } 5195 5196 5197 bool 5198 BView::_AddChildToList(BView* child, BView* before) 5199 { 5200 if (!child) 5201 return false; 5202 if (child->fParent != NULL) { 5203 debugger("View already belongs to someone else"); 5204 return false; 5205 } 5206 if (before != NULL && before->fParent != this) { 5207 debugger("Invalid before view"); 5208 return false; 5209 } 5210 5211 if (before != NULL) { 5212 // add view before this one 5213 child->fNextSibling = before; 5214 child->fPreviousSibling = before->fPreviousSibling; 5215 if (child->fPreviousSibling != NULL) 5216 child->fPreviousSibling->fNextSibling = child; 5217 5218 before->fPreviousSibling = child; 5219 if (fFirstChild == before) 5220 fFirstChild = child; 5221 } else { 5222 // add view to the end of the list 5223 BView* last = fFirstChild; 5224 while (last != NULL && last->fNextSibling != NULL) { 5225 last = last->fNextSibling; 5226 } 5227 5228 if (last != NULL) { 5229 last->fNextSibling = child; 5230 child->fPreviousSibling = last; 5231 } else { 5232 fFirstChild = child; 5233 child->fPreviousSibling = NULL; 5234 } 5235 5236 child->fNextSibling = NULL; 5237 } 5238 5239 child->fParent = this; 5240 return true; 5241 } 5242 5243 5244 /*! \brief Creates the server counterpart of this view. 5245 This is only done for views that are part of the view hierarchy, ie. when 5246 they are attached to a window. 5247 RemoveSelf() deletes the server object again. 5248 */ 5249 bool 5250 BView::_CreateSelf() 5251 { 5252 // AS_VIEW_CREATE & AS_VIEW_CREATE_ROOT do not use the 5253 // current view mechanism via _CheckLockAndSwitchCurrent() - the token 5254 // of the view and its parent are both send to the server. 5255 5256 if (fTopLevelView) 5257 fOwner->fLink->StartMessage(AS_VIEW_CREATE_ROOT); 5258 else 5259 fOwner->fLink->StartMessage(AS_VIEW_CREATE); 5260 5261 fOwner->fLink->Attach<int32>(_get_object_token_(this)); 5262 fOwner->fLink->AttachString(Name()); 5263 fOwner->fLink->Attach<BRect>(Frame()); 5264 fOwner->fLink->Attach<BPoint>(LeftTop()); 5265 fOwner->fLink->Attach<uint32>(ResizingMode()); 5266 fOwner->fLink->Attach<uint32>(fEventMask); 5267 fOwner->fLink->Attach<uint32>(fEventOptions); 5268 fOwner->fLink->Attach<uint32>(Flags()); 5269 fOwner->fLink->Attach<bool>(IsHidden(this)); 5270 fOwner->fLink->Attach<rgb_color>(fState->view_color); 5271 if (fTopLevelView) 5272 fOwner->fLink->Attach<int32>(B_NULL_TOKEN); 5273 else 5274 fOwner->fLink->Attach<int32>(_get_object_token_(fParent)); 5275 fOwner->fLink->Flush(); 5276 5277 _CheckOwnerLockAndSwitchCurrent(); 5278 fState->UpdateServerState(*fOwner->fLink); 5279 5280 // we create all its children, too 5281 5282 for (BView* child = fFirstChild; child != NULL; 5283 child = child->fNextSibling) { 5284 child->_CreateSelf(); 5285 } 5286 5287 fOwner->fLink->Flush(); 5288 return true; 5289 } 5290 5291 5292 /*! Sets the new view position. 5293 It doesn't contact the server, though - the only case where this 5294 is called outside of MoveTo() is as reaction of moving a view 5295 in the server (a.k.a. B_WINDOW_RESIZED). 5296 It also calls the BView's FrameMoved() hook. 5297 */ 5298 void 5299 BView::_MoveTo(int32 x, int32 y) 5300 { 5301 fParentOffset.Set(x, y); 5302 5303 if (Window() != NULL && fFlags & B_FRAME_EVENTS) { 5304 BMessage moved(B_VIEW_MOVED); 5305 moved.AddInt64("when", system_time()); 5306 moved.AddPoint("where", BPoint(x, y)); 5307 5308 BMessenger target(this); 5309 target.SendMessage(&moved); 5310 } 5311 } 5312 5313 5314 /*! Computes the actual new frame size and recalculates the size of 5315 the children as well. 5316 It doesn't contact the server, though - the only case where this 5317 is called outside of ResizeBy() is as reaction of resizing a view 5318 in the server (a.k.a. B_WINDOW_RESIZED). 5319 It also calls the BView's FrameResized() hook. 5320 */ 5321 void 5322 BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight) 5323 { 5324 fBounds.right += deltaWidth; 5325 fBounds.bottom += deltaHeight; 5326 5327 if (Window() == NULL) { 5328 // we're not supposed to exercise the resizing code in case 5329 // we haven't been attached to a window yet 5330 return; 5331 } 5332 5333 // layout the children 5334 if (fFlags & B_SUPPORTS_LAYOUT) { 5335 Relayout(); 5336 } else { 5337 for (BView* child = fFirstChild; child; child = child->fNextSibling) 5338 child->_ParentResizedBy(deltaWidth, deltaHeight); 5339 } 5340 5341 if (fFlags & B_FRAME_EVENTS) { 5342 BMessage resized(B_VIEW_RESIZED); 5343 resized.AddInt64("when", system_time()); 5344 resized.AddInt32("width", fBounds.IntegerWidth()); 5345 resized.AddInt32("height", fBounds.IntegerHeight()); 5346 5347 BMessenger target(this); 5348 target.SendMessage(&resized); 5349 } 5350 } 5351 5352 5353 /*! Relayouts the view according to its resizing mode. */ 5354 void 5355 BView::_ParentResizedBy(int32 x, int32 y) 5356 { 5357 uint32 resizingMode = fFlags & _RESIZE_MASK_; 5358 BRect newFrame = Frame(); 5359 5360 // follow with left side 5361 if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8) 5362 newFrame.left += x; 5363 else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8) 5364 newFrame.left += x / 2; 5365 5366 // follow with right side 5367 if ((resizingMode & 0x000FU) == _VIEW_RIGHT_) 5368 newFrame.right += x; 5369 else if ((resizingMode & 0x000FU) == _VIEW_CENTER_) 5370 newFrame.right += x / 2; 5371 5372 // follow with top side 5373 if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12) 5374 newFrame.top += y; 5375 else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12) 5376 newFrame.top += y / 2; 5377 5378 // follow with bottom side 5379 if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4) 5380 newFrame.bottom += y; 5381 else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4) 5382 newFrame.bottom += y / 2; 5383 5384 if (newFrame.LeftTop() != fParentOffset) { 5385 // move view 5386 _MoveTo((int32)roundf(newFrame.left), (int32)roundf(newFrame.top)); 5387 } 5388 5389 if (newFrame != Frame()) { 5390 // resize view 5391 int32 widthDiff = (int32)(newFrame.Width() - fBounds.Width()); 5392 int32 heightDiff = (int32)(newFrame.Height() - fBounds.Height()); 5393 _ResizeBy(widthDiff, heightDiff); 5394 } 5395 } 5396 5397 5398 void 5399 BView::_Activate(bool active) 5400 { 5401 WindowActivated(active); 5402 5403 for (BView* child = fFirstChild; child != NULL; 5404 child = child->fNextSibling) { 5405 child->_Activate(active); 5406 } 5407 } 5408 5409 5410 void 5411 BView::_Attach() 5412 { 5413 AttachedToWindow(); 5414 fAttached = true; 5415 5416 // after giving the view a chance to do this itself, 5417 // check for the B_PULSE_NEEDED flag and make sure the 5418 // window set's up the pulse messaging 5419 if (fOwner) { 5420 if (fFlags & B_PULSE_NEEDED) { 5421 _CheckLock(); 5422 if (fOwner->fPulseRunner == NULL) 5423 fOwner->SetPulseRate(fOwner->PulseRate()); 5424 } 5425 5426 if (!fOwner->IsHidden()) 5427 Invalidate(); 5428 } 5429 5430 for (BView* child = fFirstChild; child != NULL; 5431 child = child->fNextSibling) { 5432 // we need to check for fAttached as new views could have been 5433 // added in AttachedToWindow() - and those are already attached 5434 if (!child->fAttached) 5435 child->_Attach(); 5436 } 5437 5438 AllAttached(); 5439 } 5440 5441 5442 void 5443 BView::_Detach() 5444 { 5445 DetachedFromWindow(); 5446 fAttached = false; 5447 5448 for (BView* child = fFirstChild; child != NULL; 5449 child = child->fNextSibling) { 5450 child->_Detach(); 5451 } 5452 5453 AllDetached(); 5454 5455 if (fOwner) { 5456 _CheckLock(); 5457 5458 if (!fOwner->IsHidden()) 5459 Invalidate(); 5460 5461 // make sure our owner doesn't need us anymore 5462 5463 if (fOwner->CurrentFocus() == this) { 5464 MakeFocus(false); 5465 // MakeFocus() is virtual and might not be 5466 // passing through to the BView version, 5467 // but we need to make sure at this point 5468 // that we are not the focus view anymore. 5469 if (fOwner->CurrentFocus() == this) 5470 fOwner->_SetFocus(NULL, true); 5471 } 5472 5473 if (fOwner->fDefaultButton == this) 5474 fOwner->SetDefaultButton(NULL); 5475 5476 if (fOwner->fKeyMenuBar == this) 5477 fOwner->fKeyMenuBar = NULL; 5478 5479 if (fOwner->fLastMouseMovedView == this) 5480 fOwner->fLastMouseMovedView = NULL; 5481 5482 if (fOwner->fLastViewToken == _get_object_token_(this)) 5483 fOwner->fLastViewToken = B_NULL_TOKEN; 5484 5485 _SetOwner(NULL); 5486 } 5487 } 5488 5489 5490 void 5491 BView::_Draw(BRect updateRect) 5492 { 5493 if (IsHidden(this) || !(Flags() & B_WILL_DRAW)) 5494 return; 5495 5496 // NOTE: if ViewColor() == B_TRANSPARENT_COLOR and no B_WILL_DRAW 5497 // -> View is simply not drawn at all 5498 5499 _SwitchServerCurrentView(); 5500 5501 ConvertFromScreen(&updateRect); 5502 5503 // TODO: make states robust (the hook implementation could 5504 // mess things up if it uses non-matching Push- and PopState(), 5505 // we would not be guaranteed to still have the same state on 5506 // the stack after having called Draw()) 5507 PushState(); 5508 Draw(updateRect); 5509 PopState(); 5510 Flush(); 5511 } 5512 5513 5514 void 5515 BView::_DrawAfterChildren(BRect updateRect) 5516 { 5517 if (IsHidden(this) || !(Flags() & B_WILL_DRAW) 5518 || !(Flags() & B_DRAW_ON_CHILDREN)) 5519 return; 5520 5521 _SwitchServerCurrentView(); 5522 5523 ConvertFromScreen(&updateRect); 5524 5525 // TODO: make states robust (see above) 5526 PushState(); 5527 DrawAfterChildren(updateRect); 5528 PopState(); 5529 Flush(); 5530 } 5531 5532 5533 void 5534 BView::_Pulse() 5535 { 5536 if ((Flags() & B_PULSE_NEEDED) != 0) 5537 Pulse(); 5538 5539 for (BView* child = fFirstChild; child != NULL; 5540 child = child->fNextSibling) { 5541 child->_Pulse(); 5542 } 5543 } 5544 5545 5546 void 5547 BView::_UpdateStateForRemove() 5548 { 5549 // TODO: _CheckLockAndSwitchCurrent() would be good enough, no? 5550 if (!_CheckOwnerLockAndSwitchCurrent()) 5551 return; 5552 5553 fState->UpdateFrom(*fOwner->fLink); 5554 // if (!fState->IsValid(B_VIEW_FRAME_BIT)) { 5555 // fOwner->fLink->StartMessage(AS_VIEW_GET_COORD); 5556 // 5557 // status_t code; 5558 // if (fOwner->fLink->FlushWithReply(code) == B_OK 5559 // && code == B_OK) { 5560 // fOwner->fLink->Read<BPoint>(&fParentOffset); 5561 // fOwner->fLink->Read<BRect>(&fBounds); 5562 // fState->valid_flags |= B_VIEW_FRAME_BIT; 5563 // } 5564 // } 5565 5566 // update children as well 5567 5568 for (BView* child = fFirstChild; child != NULL; 5569 child = child->fNextSibling) { 5570 if (child->fOwner) 5571 child->_UpdateStateForRemove(); 5572 } 5573 } 5574 5575 5576 inline void 5577 BView::_UpdatePattern(::pattern pattern) 5578 { 5579 if (fState->IsValid(B_VIEW_PATTERN_BIT) && pattern == fState->pattern) 5580 return; 5581 5582 if (fOwner) { 5583 _CheckLockAndSwitchCurrent(); 5584 5585 fOwner->fLink->StartMessage(AS_VIEW_SET_PATTERN); 5586 fOwner->fLink->Attach< ::pattern>(pattern); 5587 5588 fState->valid_flags |= B_VIEW_PATTERN_BIT; 5589 } 5590 5591 fState->pattern = pattern; 5592 } 5593 5594 5595 void 5596 BView::_FlushIfNotInTransaction() 5597 { 5598 if (!fOwner->fInTransaction) { 5599 fOwner->Flush(); 5600 } 5601 } 5602 5603 5604 BShelf* 5605 BView::_Shelf() const 5606 { 5607 return fShelf; 5608 } 5609 5610 5611 void 5612 BView::_SetShelf(BShelf* shelf) 5613 { 5614 if (fShelf != NULL && fOwner != NULL) 5615 fOwner->RemoveHandler(fShelf); 5616 5617 fShelf = shelf; 5618 5619 if (fShelf != NULL && fOwner != NULL) 5620 fOwner->AddHandler(fShelf); 5621 } 5622 5623 5624 status_t 5625 BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect, 5626 uint32 followFlags, uint32 options) 5627 { 5628 if (!_CheckOwnerLockAndSwitchCurrent()) 5629 return B_ERROR; 5630 5631 int32 serverToken = bitmap ? bitmap->_ServerToken() : -1; 5632 5633 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_BITMAP); 5634 fOwner->fLink->Attach<int32>(serverToken); 5635 fOwner->fLink->Attach<BRect>(srcRect); 5636 fOwner->fLink->Attach<BRect>(dstRect); 5637 fOwner->fLink->Attach<int32>(followFlags); 5638 fOwner->fLink->Attach<int32>(options); 5639 5640 status_t status = B_ERROR; 5641 fOwner->fLink->FlushWithReply(status); 5642 5643 return status; 5644 } 5645 5646 5647 bool 5648 BView::_CheckOwnerLockAndSwitchCurrent() const 5649 { 5650 STRACE(("BView(%s)::_CheckOwnerLockAndSwitchCurrent()\n", Name())); 5651 5652 if (fOwner == NULL) { 5653 debugger("View method requires owner and doesn't have one."); 5654 return false; 5655 } 5656 5657 _CheckLockAndSwitchCurrent(); 5658 5659 return true; 5660 } 5661 5662 5663 bool 5664 BView::_CheckOwnerLock() const 5665 { 5666 if (fOwner) { 5667 fOwner->check_lock(); 5668 return true; 5669 } else { 5670 debugger("View method requires owner and doesn't have one."); 5671 return false; 5672 } 5673 } 5674 5675 5676 void 5677 BView::_CheckLockAndSwitchCurrent() const 5678 { 5679 STRACE(("BView(%s)::_CheckLockAndSwitchCurrent()\n", Name())); 5680 5681 if (!fOwner) 5682 return; 5683 5684 fOwner->check_lock(); 5685 5686 _SwitchServerCurrentView(); 5687 } 5688 5689 5690 void 5691 BView::_CheckLock() const 5692 { 5693 if (fOwner) 5694 fOwner->check_lock(); 5695 } 5696 5697 5698 void 5699 BView::_SwitchServerCurrentView() const 5700 { 5701 int32 serverToken = _get_object_token_(this); 5702 5703 if (fOwner->fLastViewToken != serverToken) { 5704 STRACE(("contacting app_server... sending token: %ld\n", serverToken)); 5705 fOwner->fLink->StartMessage(AS_SET_CURRENT_VIEW); 5706 fOwner->fLink->Attach<int32>(serverToken); 5707 5708 fOwner->fLastViewToken = serverToken; 5709 } 5710 } 5711 5712 5713 void 5714 BView::ScrollWithMouseWheelDelta(BScrollBar* scrollBar, float delta) 5715 { 5716 if (scrollBar == NULL || delta == 0.0f) 5717 return; 5718 5719 float smallStep, largeStep; 5720 scrollBar->GetSteps(&smallStep, &largeStep); 5721 5722 // pressing the shift key scrolls faster (following the pseudo-standard set 5723 // by other desktop environments). 5724 if ((modifiers() & B_SHIFT_KEY) != 0) 5725 delta *= largeStep; 5726 else 5727 delta *= smallStep * 3; 5728 5729 scrollBar->SetValue(scrollBar->Value() + delta); 5730 } 5731 5732 5733 #if __GNUC__ == 2 5734 5735 5736 extern "C" void 5737 _ReservedView1__5BView(BView* view, BRect rect) 5738 { 5739 view->BView::DrawAfterChildren(rect); 5740 } 5741 5742 5743 extern "C" void 5744 _ReservedView2__5BView(BView* view) 5745 { 5746 // MinSize() 5747 perform_data_min_size data; 5748 view->Perform(PERFORM_CODE_MIN_SIZE, &data); 5749 } 5750 5751 5752 extern "C" void 5753 _ReservedView3__5BView(BView* view) 5754 { 5755 // MaxSize() 5756 perform_data_max_size data; 5757 view->Perform(PERFORM_CODE_MAX_SIZE, &data); 5758 } 5759 5760 5761 extern "C" BSize 5762 _ReservedView4__5BView(BView* view) 5763 { 5764 // PreferredSize() 5765 perform_data_preferred_size data; 5766 view->Perform(PERFORM_CODE_PREFERRED_SIZE, &data); 5767 return data.return_value; 5768 } 5769 5770 5771 extern "C" BAlignment 5772 _ReservedView5__5BView(BView* view) 5773 { 5774 // LayoutAlignment() 5775 perform_data_layout_alignment data; 5776 view->Perform(PERFORM_CODE_LAYOUT_ALIGNMENT, &data); 5777 return data.return_value; 5778 } 5779 5780 5781 extern "C" bool 5782 _ReservedView6__5BView(BView* view) 5783 { 5784 // HasHeightForWidth() 5785 perform_data_has_height_for_width data; 5786 view->Perform(PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH, &data); 5787 return data.return_value; 5788 } 5789 5790 5791 extern "C" void 5792 _ReservedView7__5BView(BView* view, float width, float* min, float* max, 5793 float* preferred) 5794 { 5795 // GetHeightForWidth() 5796 perform_data_get_height_for_width data; 5797 data.width = width; 5798 view->Perform(PERFORM_CODE_GET_HEIGHT_FOR_WIDTH, &data); 5799 if (min != NULL) 5800 *min = data.min; 5801 if (max != NULL) 5802 *max = data.max; 5803 if (preferred != NULL) 5804 *preferred = data.preferred; 5805 } 5806 5807 5808 extern "C" void 5809 _ReservedView8__5BView(BView* view, BLayout* layout) 5810 { 5811 // SetLayout() 5812 perform_data_set_layout data; 5813 data.layout = layout; 5814 view->Perform(PERFORM_CODE_SET_LAYOUT, &data); 5815 } 5816 5817 5818 extern "C" void 5819 _ReservedView9__5BView(BView* view, bool descendants) 5820 { 5821 // LayoutInvalidated() 5822 perform_data_layout_invalidated data; 5823 data.descendants = descendants; 5824 view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data); 5825 } 5826 5827 5828 extern "C" void 5829 _ReservedView10__5BView(BView* view) 5830 { 5831 // DoLayout() 5832 view->Perform(PERFORM_CODE_DO_LAYOUT, NULL); 5833 } 5834 5835 5836 #endif // __GNUC__ == 2 5837 5838 5839 extern "C" bool 5840 B_IF_GCC_2(_ReservedView11__5BView, _ZN5BView15_ReservedView11Ev)( 5841 BView* view, BPoint point, BToolTip** _toolTip) 5842 { 5843 // GetToolTipAt() 5844 perform_data_get_tool_tip_at data; 5845 data.point = point; 5846 data.tool_tip = _toolTip; 5847 view->Perform(PERFORM_CODE_GET_TOOL_TIP_AT, &data); 5848 return data.return_value; 5849 } 5850 5851 5852 extern "C" void 5853 B_IF_GCC_2(_ReservedView12__5BView, _ZN5BView15_ReservedView12Ev)( 5854 BView* view) 5855 { 5856 // LayoutChanged(); 5857 view->Perform(PERFORM_CODE_LAYOUT_CHANGED, NULL); 5858 } 5859 5860 5861 void BView::_ReservedView13() {} 5862 void BView::_ReservedView14() {} 5863 void BView::_ReservedView15() {} 5864 void BView::_ReservedView16() {} 5865 5866 5867 BView::BView(const BView& other) 5868 : 5869 BHandler() 5870 { 5871 // this is private and not functional, but exported 5872 } 5873 5874 5875 BView& 5876 BView::operator=(const BView& other) 5877 { 5878 // this is private and not functional, but exported 5879 return *this; 5880 } 5881 5882 5883 void 5884 BView::_PrintToStream() 5885 { 5886 printf("BView::_PrintToStream()\n"); 5887 printf("\tName: %s\n" 5888 "\tParent: %s\n" 5889 "\tFirstChild: %s\n" 5890 "\tNextSibling: %s\n" 5891 "\tPrevSibling: %s\n" 5892 "\tOwner(Window): %s\n" 5893 "\tToken: %" B_PRId32 "\n" 5894 "\tFlags: %" B_PRId32 "\n" 5895 "\tView origin: (%f,%f)\n" 5896 "\tView Bounds rectangle: (%f,%f,%f,%f)\n" 5897 "\tShow level: %d\n" 5898 "\tTopView?: %s\n" 5899 "\tBPicture: %s\n" 5900 "\tVertical Scrollbar %s\n" 5901 "\tHorizontal Scrollbar %s\n" 5902 "\tIs Printing?: %s\n" 5903 "\tShelf?: %s\n" 5904 "\tEventMask: %" B_PRId32 "\n" 5905 "\tEventOptions: %" B_PRId32 "\n", 5906 Name(), 5907 fParent ? fParent->Name() : "NULL", 5908 fFirstChild ? fFirstChild->Name() : "NULL", 5909 fNextSibling ? fNextSibling->Name() : "NULL", 5910 fPreviousSibling ? fPreviousSibling->Name() : "NULL", 5911 fOwner ? fOwner->Name() : "NULL", 5912 _get_object_token_(this), 5913 fFlags, 5914 fParentOffset.x, fParentOffset.y, 5915 fBounds.left, fBounds.top, fBounds.right, fBounds.bottom, 5916 fShowLevel, 5917 fTopLevelView ? "YES" : "NO", 5918 fCurrentPicture? "YES" : "NULL", 5919 fVerScroller? "YES" : "NULL", 5920 fHorScroller? "YES" : "NULL", 5921 fIsPrinting? "YES" : "NO", 5922 fShelf? "YES" : "NO", 5923 fEventMask, 5924 fEventOptions); 5925 5926 printf("\tState status:\n" 5927 "\t\tLocalCoordianteSystem: (%f,%f)\n" 5928 "\t\tPenLocation: (%f,%f)\n" 5929 "\t\tPenSize: %f\n" 5930 "\t\tHighColor: [%d,%d,%d,%d]\n" 5931 "\t\tLowColor: [%d,%d,%d,%d]\n" 5932 "\t\tViewColor: [%d,%d,%d,%d]\n" 5933 "\t\tPattern: %" B_PRIx64 "\n" 5934 "\t\tDrawingMode: %d\n" 5935 "\t\tLineJoinMode: %d\n" 5936 "\t\tLineCapMode: %d\n" 5937 "\t\tMiterLimit: %f\n" 5938 "\t\tAlphaSource: %d\n" 5939 "\t\tAlphaFuntion: %d\n" 5940 "\t\tScale: %f\n" 5941 "\t\t(Print)FontAliasing: %s\n" 5942 "\t\tFont Info:\n", 5943 fState->origin.x, fState->origin.y, 5944 fState->pen_location.x, fState->pen_location.y, 5945 fState->pen_size, 5946 fState->high_color.red, fState->high_color.blue, fState->high_color.green, fState->high_color.alpha, 5947 fState->low_color.red, fState->low_color.blue, fState->low_color.green, fState->low_color.alpha, 5948 fState->view_color.red, fState->view_color.blue, fState->view_color.green, fState->view_color.alpha, 5949 *((uint64*)&(fState->pattern)), 5950 fState->drawing_mode, 5951 fState->line_join, 5952 fState->line_cap, 5953 fState->miter_limit, 5954 fState->alpha_source_mode, 5955 fState->alpha_function_mode, 5956 fState->scale, 5957 fState->font_aliasing? "YES" : "NO"); 5958 5959 fState->font.PrintToStream(); 5960 5961 // TODO: also print the line array. 5962 } 5963 5964 5965 void 5966 BView::_PrintTree() 5967 { 5968 int32 spaces = 2; 5969 BView* c = fFirstChild; //c = short for: current 5970 printf( "'%s'\n", Name() ); 5971 if (c != NULL) { 5972 while(true) { 5973 // action block 5974 { 5975 for (int i = 0; i < spaces; i++) 5976 printf(" "); 5977 5978 printf( "'%s'\n", c->Name() ); 5979 } 5980 5981 // go deep 5982 if (c->fFirstChild) { 5983 c = c->fFirstChild; 5984 spaces += 2; 5985 } else { 5986 // go right 5987 if (c->fNextSibling) { 5988 c = c->fNextSibling; 5989 } else { 5990 // go up 5991 while (!c->fParent->fNextSibling && c->fParent != this) { 5992 c = c->fParent; 5993 spaces -= 2; 5994 } 5995 5996 // that enough! We've reached this view. 5997 if (c->fParent == this) 5998 break; 5999 6000 c = c->fParent->fNextSibling; 6001 spaces -= 2; 6002 } 6003 } 6004 } 6005 } 6006 } 6007 6008 6009 // #pragma mark - 6010 6011 6012 BLayoutItem* 6013 BView::Private::LayoutItemAt(int32 index) 6014 { 6015 return fView->fLayoutData->fLayoutItems.ItemAt(index); 6016 } 6017 6018 6019 int32 6020 BView::Private::CountLayoutItems() 6021 { 6022 return fView->fLayoutData->fLayoutItems.CountItems(); 6023 } 6024 6025 6026 void 6027 BView::Private::RegisterLayoutItem(BLayoutItem* item) 6028 { 6029 fView->fLayoutData->fLayoutItems.AddItem(item); 6030 } 6031 6032 6033 void 6034 BView::Private::DeregisterLayoutItem(BLayoutItem* item) 6035 { 6036 fView->fLayoutData->fLayoutItems.RemoveItem(item); 6037 } 6038 6039 6040 bool 6041 BView::Private::MinMaxValid() 6042 { 6043 return fView->fLayoutData->fMinMaxValid; 6044 } 6045 6046 6047 bool 6048 BView::Private::WillLayout() 6049 { 6050 BView::LayoutData* data = fView->fLayoutData; 6051 if (data->fLayoutInProgress) 6052 return false; 6053 if (data->fNeedsRelayout || !data->fLayoutValid || !data->fMinMaxValid) 6054 return true; 6055 return false; 6056 } 6057