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