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