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