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