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