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