tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / interface / View.cpp
blobeb07f0f64b256093eff5502d0a91a15e6dcab0dd
1 /*
2 * Copyright 2001-2015 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
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
13 #include <View.h>
15 #include <algorithm>
16 #include <new>
18 #include <math.h>
19 #include <stdio.h>
21 #include <Application.h>
22 #include <Bitmap.h>
23 #include <Button.h>
24 #include <Cursor.h>
25 #include <File.h>
26 #include <GradientLinear.h>
27 #include <GradientRadial.h>
28 #include <GradientRadialFocus.h>
29 #include <GradientDiamond.h>
30 #include <GradientConic.h>
31 #include <InterfaceDefs.h>
32 #include <Layout.h>
33 #include <LayoutContext.h>
34 #include <LayoutUtils.h>
35 #include <MenuBar.h>
36 #include <Message.h>
37 #include <MessageQueue.h>
38 #include <ObjectList.h>
39 #include <Picture.h>
40 #include <Point.h>
41 #include <Polygon.h>
42 #include <PropertyInfo.h>
43 #include <Region.h>
44 #include <ScrollBar.h>
45 #include <Shape.h>
46 #include <Shelf.h>
47 #include <String.h>
48 #include <Window.h>
50 #include <AppMisc.h>
51 #include <AppServerLink.h>
52 #include <binary_compatibility/Interface.h>
53 #include <binary_compatibility/Support.h>
54 #include <MessagePrivate.h>
55 #include <MessageUtils.h>
56 #include <PortLink.h>
57 #include <ServerProtocol.h>
58 #include <ServerProtocolStructs.h>
59 #include <ShapePrivate.h>
60 #include <ToolTip.h>
61 #include <ToolTipManager.h>
62 #include <TokenSpace.h>
63 #include <ViewPrivate.h>
65 using std::nothrow;
67 //#define DEBUG_BVIEW
68 #ifdef DEBUG_BVIEW
69 # include <stdio.h>
70 # define STRACE(x) printf x
71 # define BVTRACE _PrintToStream()
72 #else
73 # define STRACE(x) ;
74 # define BVTRACE ;
75 #endif
78 static property_info sViewPropInfo[] = {
79 { "Frame", { B_GET_PROPERTY, B_SET_PROPERTY },
80 { B_DIRECT_SPECIFIER, 0 }, "The view's frame rectangle.", 0,
81 { B_RECT_TYPE }
83 { "Hidden", { B_GET_PROPERTY, B_SET_PROPERTY },
84 { B_DIRECT_SPECIFIER, 0 }, "Whether or not the view is hidden.",
85 0, { B_BOOL_TYPE }
87 { "Shelf", { 0 },
88 { B_DIRECT_SPECIFIER, 0 }, "Directs the scripting message to the "
89 "shelf.", 0
91 { "View", { B_COUNT_PROPERTIES, 0 },
92 { B_DIRECT_SPECIFIER, 0 }, "Returns the number of child views.", 0,
93 { B_INT32_TYPE }
95 { "View", { 0 },
96 { B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, B_NAME_SPECIFIER, 0 },
97 "Directs the scripting message to the specified view.", 0
100 { 0, { 0 }, { 0 }, 0, 0 }
104 // #pragma mark -
107 static inline uint32
108 get_uint32_color(rgb_color color)
110 return B_BENDIAN_TO_HOST_INT32(*(uint32*)&color);
111 // rgb_color is always in rgba format, no matter what endian;
112 // we always return the int32 value in host endian.
116 static inline rgb_color
117 get_rgb_color(uint32 value)
119 value = B_HOST_TO_BENDIAN_INT32(value);
120 return *(rgb_color*)&value;
124 // #pragma mark -
127 namespace BPrivate {
129 ViewState::ViewState()
131 pen_location.Set(0, 0);
132 pen_size = 1.0;
134 // NOTE: the clipping_region is empty
135 // on construction but it is not used yet,
136 // we avoid having to keep track of it via
137 // this flag
138 clipping_region_used = false;
140 high_color = (rgb_color){ 0, 0, 0, 255 };
141 low_color = (rgb_color){ 255, 255, 255, 255 };
142 view_color = low_color;
144 pattern = B_SOLID_HIGH;
145 drawing_mode = B_OP_COPY;
147 origin.Set(0, 0);
149 line_join = B_MITER_JOIN;
150 line_cap = B_BUTT_CAP;
151 miter_limit = B_DEFAULT_MITER_LIMIT;
152 fill_rule = B_NONZERO;
154 alpha_source_mode = B_PIXEL_ALPHA;
155 alpha_function_mode = B_ALPHA_OVERLAY;
157 scale = 1.0;
159 font = *be_plain_font;
160 font_flags = font.Flags();
161 font_aliasing = false;
163 // We only keep the B_VIEW_CLIP_REGION_BIT flag invalidated,
164 // because we should get the clipping region from app_server.
165 // The other flags do not need to be included because the data they
166 // represent is already in sync with app_server - app_server uses the
167 // same init (default) values.
168 valid_flags = ~B_VIEW_CLIP_REGION_BIT;
170 archiving_flags = B_VIEW_FRAME_BIT | B_VIEW_RESIZE_BIT;
174 void
175 ViewState::UpdateServerFontState(BPrivate::PortLink &link)
177 link.StartMessage(AS_VIEW_SET_FONT_STATE);
178 link.Attach<uint16>(font_flags);
179 // always present
181 if (font_flags & B_FONT_FAMILY_AND_STYLE)
182 link.Attach<uint32>(font.FamilyAndStyle());
184 if (font_flags & B_FONT_SIZE)
185 link.Attach<float>(font.Size());
187 if (font_flags & B_FONT_SHEAR)
188 link.Attach<float>(font.Shear());
190 if (font_flags & B_FONT_ROTATION)
191 link.Attach<float>(font.Rotation());
193 if (font_flags & B_FONT_FALSE_BOLD_WIDTH)
194 link.Attach<float>(font.FalseBoldWidth());
196 if (font_flags & B_FONT_SPACING)
197 link.Attach<uint8>(font.Spacing());
199 if (font_flags & B_FONT_ENCODING)
200 link.Attach<uint8>(font.Encoding());
202 if (font_flags & B_FONT_FACE)
203 link.Attach<uint16>(font.Face());
205 if (font_flags & B_FONT_FLAGS)
206 link.Attach<uint32>(font.Flags());
210 void
211 ViewState::UpdateServerState(BPrivate::PortLink &link)
213 UpdateServerFontState(link);
215 link.StartMessage(AS_VIEW_SET_STATE);
217 ViewSetStateInfo info;
218 info.penLocation = pen_location;
219 info.penSize = pen_size;
220 info.highColor = high_color;
221 info.lowColor = low_color;
222 info.pattern = pattern;
223 info.drawingMode = drawing_mode;
224 info.origin = origin;
225 info.scale = scale;
226 info.transform = transform;
227 info.lineJoin = line_join;
228 info.lineCap = line_cap;
229 info.miterLimit = miter_limit;
230 info.fillRule = fill_rule;
231 info.alphaSourceMode = alpha_source_mode;
232 info.alphaFunctionMode = alpha_function_mode;
233 info.fontAntialiasing = font_aliasing;
234 link.Attach<ViewSetStateInfo>(info);
236 // we send the 'local' clipping region... if we have one...
237 // TODO: Could be optimized, but is low prio, since most views won't
238 // have a custom clipping region.
239 if (clipping_region_used) {
240 int32 count = clipping_region.CountRects();
241 link.Attach<int32>(count);
242 for (int32 i = 0; i < count; i++)
243 link.Attach<BRect>(clipping_region.RectAt(i));
244 } else {
245 // no clipping region
246 link.Attach<int32>(-1);
249 // Although we might have a 'local' clipping region, when we call
250 // BView::GetClippingRegion() we ask for the 'global' one and it
251 // is kept on server, so we must invalidate B_VIEW_CLIP_REGION_BIT flag
253 valid_flags = ~B_VIEW_CLIP_REGION_BIT;
257 void
258 ViewState::UpdateFrom(BPrivate::PortLink &link)
260 link.StartMessage(AS_VIEW_GET_STATE);
262 int32 code;
263 if (link.FlushWithReply(code) != B_OK
264 || code != B_OK)
265 return;
267 ViewGetStateInfo info;
268 link.Read<ViewGetStateInfo>(&info);
270 // set view's font state
271 font_flags = B_FONT_ALL;
272 font.SetFamilyAndStyle(info.fontID);
273 font.SetSize(info.fontSize);
274 font.SetShear(info.fontShear);
275 font.SetRotation(info.fontRotation);
276 font.SetFalseBoldWidth(info.fontFalseBoldWidth);
277 font.SetSpacing(info.fontSpacing);
278 font.SetEncoding(info.fontEncoding);
279 font.SetFace(info.fontFace);
280 font.SetFlags(info.fontFlags);
282 // set view's state
283 pen_location = info.viewStateInfo.penLocation;
284 pen_size = info.viewStateInfo.penSize;
285 high_color = info.viewStateInfo.highColor;
286 low_color = info.viewStateInfo.lowColor;
287 pattern = info.viewStateInfo.pattern;
288 drawing_mode = info.viewStateInfo.drawingMode;
289 origin = info.viewStateInfo.origin;
290 scale = info.viewStateInfo.scale;
291 transform = info.viewStateInfo.transform;
292 line_join = info.viewStateInfo.lineJoin;
293 line_cap = info.viewStateInfo.lineCap;
294 miter_limit = info.viewStateInfo.miterLimit;
295 fill_rule = info.viewStateInfo.fillRule;
296 alpha_source_mode = info.viewStateInfo.alphaSourceMode;
297 alpha_function_mode = info.viewStateInfo.alphaFunctionMode;
298 font_aliasing = info.viewStateInfo.fontAntialiasing;
300 // read the user clipping
301 // (that's NOT the current View visible clipping but the additional
302 // user specified clipping!)
303 int32 clippingRectCount;
304 link.Read<int32>(&clippingRectCount);
305 if (clippingRectCount >= 0) {
306 clipping_region.MakeEmpty();
307 for (int32 i = 0; i < clippingRectCount; i++) {
308 BRect rect;
309 link.Read<BRect>(&rect);
310 clipping_region.Include(rect);
312 } else {
313 // no user clipping used
314 clipping_region_used = false;
317 valid_flags = ~B_VIEW_CLIP_REGION_BIT;
320 } // namespace BPrivate
323 // #pragma mark -
326 // archiving constants
327 namespace {
328 const char* const kSizesField = "BView:sizes";
329 // kSizesField = {min, max, pref}
330 const char* const kAlignmentField = "BView:alignment";
331 const char* const kLayoutField = "BView:layout";
335 struct BView::LayoutData {
336 LayoutData()
338 fMinSize(),
339 fMaxSize(),
340 fPreferredSize(),
341 fAlignment(),
342 fLayoutInvalidationDisabled(0),
343 fLayout(NULL),
344 fLayoutContext(NULL),
345 fLayoutItems(5, false),
346 fLayoutValid(true), // TODO: Rethink these initial values!
347 fMinMaxValid(true), //
348 fLayoutInProgress(false),
349 fNeedsRelayout(true)
353 status_t
354 AddDataToArchive(BMessage* archive)
356 status_t err = archive->AddSize(kSizesField, fMinSize);
358 if (err == B_OK)
359 err = archive->AddSize(kSizesField, fMaxSize);
361 if (err == B_OK)
362 err = archive->AddSize(kSizesField, fPreferredSize);
364 if (err == B_OK)
365 err = archive->AddAlignment(kAlignmentField, fAlignment);
367 return err;
370 void
371 PopulateFromArchive(BMessage* archive)
373 archive->FindSize(kSizesField, 0, &fMinSize);
374 archive->FindSize(kSizesField, 1, &fMaxSize);
375 archive->FindSize(kSizesField, 2, &fPreferredSize);
376 archive->FindAlignment(kAlignmentField, &fAlignment);
379 BSize fMinSize;
380 BSize fMaxSize;
381 BSize fPreferredSize;
382 BAlignment fAlignment;
383 int fLayoutInvalidationDisabled;
384 BLayout* fLayout;
385 BLayoutContext* fLayoutContext;
386 BObjectList<BLayoutItem> fLayoutItems;
387 bool fLayoutValid;
388 bool fMinMaxValid;
389 bool fLayoutInProgress;
390 bool fNeedsRelayout;
394 BView::BView(const char* name, uint32 flags, BLayout* layout)
396 BHandler(name)
398 _InitData(BRect(0, 0, 0, 0), name, B_FOLLOW_NONE,
399 flags | B_SUPPORTS_LAYOUT);
400 SetLayout(layout);
404 BView::BView(BRect frame, const char* name, uint32 resizingMode, uint32 flags)
406 BHandler(name)
408 _InitData(frame, name, resizingMode, flags);
412 BView::BView(BMessage* archive)
414 BHandler(BUnarchiver::PrepareArchive(archive))
416 BUnarchiver unarchiver(archive);
417 if (!archive)
418 debugger("BView cannot be constructed from a NULL archive.");
420 BRect frame;
421 archive->FindRect("_frame", &frame);
423 uint32 resizingMode;
424 if (archive->FindInt32("_resize_mode", (int32*)&resizingMode) != B_OK)
425 resizingMode = 0;
427 uint32 flags;
428 if (archive->FindInt32("_flags", (int32*)&flags) != B_OK)
429 flags = 0;
431 _InitData(frame, Name(), resizingMode, flags);
433 font_family family;
434 font_style style;
435 if (archive->FindString("_fname", 0, (const char**)&family) == B_OK
436 && archive->FindString("_fname", 1, (const char**)&style) == B_OK) {
437 BFont font;
438 font.SetFamilyAndStyle(family, style);
440 float size;
441 if (archive->FindFloat("_fflt", 0, &size) == B_OK)
442 font.SetSize(size);
444 float shear;
445 if (archive->FindFloat("_fflt", 1, &shear) == B_OK
446 && shear >= 45.0 && shear <= 135.0)
447 font.SetShear(shear);
449 float rotation;
450 if (archive->FindFloat("_fflt", 2, &rotation) == B_OK
451 && rotation >=0 && rotation <= 360)
452 font.SetRotation(rotation);
454 SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE
455 | B_FONT_SHEAR | B_FONT_ROTATION);
458 int32 color;
459 if (archive->FindInt32("_color", 0, &color) == B_OK)
460 SetHighColor(get_rgb_color(color));
461 if (archive->FindInt32("_color", 1, &color) == B_OK)
462 SetLowColor(get_rgb_color(color));
463 if (archive->FindInt32("_color", 2, &color) == B_OK)
464 SetViewColor(get_rgb_color(color));
466 uint32 evMask;
467 uint32 options;
468 if (archive->FindInt32("_evmask", 0, (int32*)&evMask) == B_OK
469 && archive->FindInt32("_evmask", 1, (int32*)&options) == B_OK)
470 SetEventMask(evMask, options);
472 BPoint origin;
473 if (archive->FindPoint("_origin", &origin) == B_OK)
474 SetOrigin(origin);
476 float scale;
477 if (archive->FindFloat("_scale", &scale) == B_OK)
478 SetScale(scale);
480 BAffineTransform transform;
481 if (archive->FindFlat("_transform", &transform) == B_OK)
482 SetTransform(transform);
484 float penSize;
485 if (archive->FindFloat("_psize", &penSize) == B_OK)
486 SetPenSize(penSize);
488 BPoint penLocation;
489 if (archive->FindPoint("_ploc", &penLocation) == B_OK)
490 MovePenTo(penLocation);
492 int16 lineCap;
493 int16 lineJoin;
494 float lineMiter;
495 if (archive->FindInt16("_lmcapjoin", 0, &lineCap) == B_OK
496 && archive->FindInt16("_lmcapjoin", 1, &lineJoin) == B_OK
497 && archive->FindFloat("_lmmiter", &lineMiter) == B_OK)
498 SetLineMode((cap_mode)lineCap, (join_mode)lineJoin, lineMiter);
500 int16 fillRule;
501 if (archive->FindInt16("_fillrule", &fillRule) == B_OK)
502 SetFillRule(fillRule);
504 int16 alphaBlend;
505 int16 modeBlend;
506 if (archive->FindInt16("_blend", 0, &alphaBlend) == B_OK
507 && archive->FindInt16("_blend", 1, &modeBlend) == B_OK)
508 SetBlendingMode( (source_alpha)alphaBlend, (alpha_function)modeBlend);
510 uint32 drawingMode;
511 if (archive->FindInt32("_dmod", (int32*)&drawingMode) == B_OK)
512 SetDrawingMode((drawing_mode)drawingMode);
514 fLayoutData->PopulateFromArchive(archive);
516 if (archive->FindInt16("_show", &fShowLevel) != B_OK)
517 fShowLevel = 0;
519 if (BUnarchiver::IsArchiveManaged(archive)) {
520 int32 i = 0;
521 while (unarchiver.EnsureUnarchived("_views", i++) == B_OK)
523 unarchiver.EnsureUnarchived(kLayoutField);
525 } else {
526 BMessage msg;
527 for (int32 i = 0; archive->FindMessage("_views", i, &msg) == B_OK;
528 i++) {
529 BArchivable* object = instantiate_object(&msg);
530 if (BView* child = dynamic_cast<BView*>(object))
531 AddChild(child);
537 BArchivable*
538 BView::Instantiate(BMessage* data)
540 if (!validate_instantiation(data , "BView"))
541 return NULL;
543 return new(std::nothrow) BView(data);
547 status_t
548 BView::Archive(BMessage* data, bool deep) const
550 BArchiver archiver(data);
551 status_t ret = BHandler::Archive(data, deep);
553 if (ret != B_OK)
554 return ret;
556 if ((fState->archiving_flags & B_VIEW_FRAME_BIT) != 0)
557 ret = data->AddRect("_frame", Bounds().OffsetToCopy(fParentOffset));
559 if (ret == B_OK)
560 ret = data->AddInt32("_resize_mode", ResizingMode());
562 if (ret == B_OK)
563 ret = data->AddInt32("_flags", Flags());
565 if (ret == B_OK && (fState->archiving_flags & B_VIEW_EVENT_MASK_BIT) != 0) {
566 ret = data->AddInt32("_evmask", fEventMask);
567 if (ret == B_OK)
568 ret = data->AddInt32("_evmask", fEventOptions);
571 if (ret == B_OK && (fState->archiving_flags & B_VIEW_FONT_BIT) != 0) {
572 BFont font;
573 GetFont(&font);
575 font_family family;
576 font_style style;
577 font.GetFamilyAndStyle(&family, &style);
578 ret = data->AddString("_fname", family);
579 if (ret == B_OK)
580 ret = data->AddString("_fname", style);
581 if (ret == B_OK)
582 ret = data->AddFloat("_fflt", font.Size());
583 if (ret == B_OK)
584 ret = data->AddFloat("_fflt", font.Shear());
585 if (ret == B_OK)
586 ret = data->AddFloat("_fflt", font.Rotation());
589 // colors
590 if (ret == B_OK)
591 ret = data->AddInt32("_color", get_uint32_color(HighColor()));
592 if (ret == B_OK)
593 ret = data->AddInt32("_color", get_uint32_color(LowColor()));
594 if (ret == B_OK)
595 ret = data->AddInt32("_color", get_uint32_color(ViewColor()));
597 // NOTE: we do not use this flag any more
598 // if ( 1 ){
599 // ret = data->AddInt32("_dbuf", 1);
600 // }
602 if (ret == B_OK && (fState->archiving_flags & B_VIEW_ORIGIN_BIT) != 0)
603 ret = data->AddPoint("_origin", Origin());
605 if (ret == B_OK && (fState->archiving_flags & B_VIEW_SCALE_BIT) != 0)
606 ret = data->AddFloat("_scale", Scale());
608 if (ret == B_OK && (fState->archiving_flags & B_VIEW_TRANSFORM_BIT) != 0) {
609 BAffineTransform transform = Transform();
610 ret = data->AddFlat("_transform", &transform);
613 if (ret == B_OK && (fState->archiving_flags & B_VIEW_PEN_SIZE_BIT) != 0)
614 ret = data->AddFloat("_psize", PenSize());
616 if (ret == B_OK && (fState->archiving_flags & B_VIEW_PEN_LOCATION_BIT) != 0)
617 ret = data->AddPoint("_ploc", PenLocation());
619 if (ret == B_OK && (fState->archiving_flags & B_VIEW_LINE_MODES_BIT) != 0) {
620 ret = data->AddInt16("_lmcapjoin", (int16)LineCapMode());
621 if (ret == B_OK)
622 ret = data->AddInt16("_lmcapjoin", (int16)LineJoinMode());
623 if (ret == B_OK)
624 ret = data->AddFloat("_lmmiter", LineMiterLimit());
627 if (ret == B_OK && (fState->archiving_flags & B_VIEW_FILL_RULE_BIT) != 0)
628 ret = data->AddInt16("_fillrule", (int16)FillRule());
630 if (ret == B_OK && (fState->archiving_flags & B_VIEW_BLENDING_BIT) != 0) {
631 source_alpha alphaSourceMode;
632 alpha_function alphaFunctionMode;
633 GetBlendingMode(&alphaSourceMode, &alphaFunctionMode);
635 ret = data->AddInt16("_blend", (int16)alphaSourceMode);
636 if (ret == B_OK)
637 ret = data->AddInt16("_blend", (int16)alphaFunctionMode);
640 if (ret == B_OK && (fState->archiving_flags & B_VIEW_DRAWING_MODE_BIT) != 0)
641 ret = data->AddInt32("_dmod", DrawingMode());
643 if (ret == B_OK)
644 ret = fLayoutData->AddDataToArchive(data);
646 if (ret == B_OK)
647 ret = data->AddInt16("_show", fShowLevel);
649 if (deep && ret == B_OK) {
650 for (BView* child = fFirstChild; child != NULL && ret == B_OK;
651 child = child->fNextSibling)
652 ret = archiver.AddArchivable("_views", child, deep);
654 if (ret == B_OK)
655 ret = archiver.AddArchivable(kLayoutField, GetLayout(), deep);
658 return archiver.Finish(ret);
662 status_t
663 BView::AllUnarchived(const BMessage* from)
665 BUnarchiver unarchiver(from);
666 status_t err = B_OK;
668 int32 count;
669 from->GetInfo("_views", NULL, &count);
671 for (int32 i = 0; err == B_OK && i < count; i++) {
672 BView* child;
673 err = unarchiver.FindObject<BView>("_views", i, child);
674 if (err == B_OK)
675 err = _AddChild(child, NULL) ? B_OK : B_ERROR;
678 if (err == B_OK) {
679 BLayout*& layout = fLayoutData->fLayout;
680 err = unarchiver.FindObject(kLayoutField, layout);
681 if (err == B_OK && layout) {
682 fFlags |= B_SUPPORTS_LAYOUT;
683 fLayoutData->fLayout->SetOwner(this);
687 return err;
691 status_t
692 BView::AllArchived(BMessage* into) const
694 return BHandler::AllArchived(into);
698 BView::~BView()
700 STRACE(("BView(%s)::~BView()\n", this->Name()));
702 if (fOwner != NULL) {
703 debugger("Trying to delete a view that belongs to a window. "
704 "Call RemoveSelf first.");
707 // we also delete all our children
709 BView* child = fFirstChild;
710 while (child) {
711 BView* nextChild = child->fNextSibling;
713 delete child;
714 child = nextChild;
717 SetLayout(NULL);
718 _RemoveLayoutItemsFromLayout(true);
720 delete fLayoutData;
722 _RemoveSelf();
724 if (fToolTip != NULL)
725 fToolTip->ReleaseReference();
727 if (fVerScroller != NULL)
728 fVerScroller->SetTarget((BView*)NULL);
729 if (fHorScroller != NULL)
730 fHorScroller->SetTarget((BView*)NULL);
732 SetName(NULL);
734 _RemoveCommArray();
735 delete fState;
739 BRect
740 BView::Bounds() const
742 _CheckLock();
744 if (fIsPrinting)
745 return fState->print_rect;
747 return fBounds;
751 void
752 BView::_ConvertToParent(BPoint* point, bool checkLock) const
754 if (!fParent)
755 return;
757 if (checkLock)
758 _CheckLock();
760 // - our scrolling offset
761 // + our bounds location within the parent
762 point->x += -fBounds.left + fParentOffset.x;
763 point->y += -fBounds.top + fParentOffset.y;
767 void
768 BView::ConvertToParent(BPoint* point) const
770 _ConvertToParent(point, true);
774 BPoint
775 BView::ConvertToParent(BPoint point) const
777 ConvertToParent(&point);
779 return point;
783 void
784 BView::_ConvertFromParent(BPoint* point, bool checkLock) const
786 if (!fParent)
787 return;
789 if (checkLock)
790 _CheckLock();
792 // - our bounds location within the parent
793 // + our scrolling offset
794 point->x += -fParentOffset.x + fBounds.left;
795 point->y += -fParentOffset.y + fBounds.top;
799 void
800 BView::ConvertFromParent(BPoint* point) const
802 _ConvertFromParent(point, true);
806 BPoint
807 BView::ConvertFromParent(BPoint point) const
809 ConvertFromParent(&point);
811 return point;
815 void
816 BView::ConvertToParent(BRect* rect) const
818 if (!fParent)
819 return;
821 _CheckLock();
823 // - our scrolling offset
824 // + our bounds location within the parent
825 rect->OffsetBy(-fBounds.left + fParentOffset.x,
826 -fBounds.top + fParentOffset.y);
830 BRect
831 BView::ConvertToParent(BRect rect) const
833 ConvertToParent(&rect);
835 return rect;
839 void
840 BView::ConvertFromParent(BRect* rect) const
842 if (!fParent)
843 return;
845 _CheckLock();
847 // - our bounds location within the parent
848 // + our scrolling offset
849 rect->OffsetBy(-fParentOffset.x + fBounds.left,
850 -fParentOffset.y + fBounds.top);
854 BRect
855 BView::ConvertFromParent(BRect rect) const
857 ConvertFromParent(&rect);
859 return rect;
863 void
864 BView::_ConvertToScreen(BPoint* point, bool checkLock) const
866 if (!fParent) {
867 if (fOwner)
868 fOwner->ConvertToScreen(point);
870 return;
873 if (checkLock)
874 _CheckOwnerLock();
876 _ConvertToParent(point, false);
877 fParent->_ConvertToScreen(point, false);
881 void
882 BView::ConvertToScreen(BPoint* point) const
884 _ConvertToScreen(point, true);
888 BPoint
889 BView::ConvertToScreen(BPoint point) const
891 ConvertToScreen(&point);
893 return point;
897 void
898 BView::_ConvertFromScreen(BPoint* point, bool checkLock) const
900 if (!fParent) {
901 if (fOwner)
902 fOwner->ConvertFromScreen(point);
904 return;
907 if (checkLock)
908 _CheckOwnerLock();
910 _ConvertFromParent(point, false);
911 fParent->_ConvertFromScreen(point, false);
915 void
916 BView::ConvertFromScreen(BPoint* point) const
918 _ConvertFromScreen(point, true);
922 BPoint
923 BView::ConvertFromScreen(BPoint point) const
925 ConvertFromScreen(&point);
927 return point;
931 void
932 BView::ConvertToScreen(BRect* rect) const
934 BPoint offset(0.0, 0.0);
935 ConvertToScreen(&offset);
936 rect->OffsetBy(offset);
940 BRect
941 BView::ConvertToScreen(BRect rect) const
943 ConvertToScreen(&rect);
945 return rect;
949 void
950 BView::ConvertFromScreen(BRect* rect) const
952 BPoint offset(0.0, 0.0);
953 ConvertFromScreen(&offset);
954 rect->OffsetBy(offset);
958 BRect
959 BView::ConvertFromScreen(BRect rect) const
961 ConvertFromScreen(&rect);
963 return rect;
967 uint32
968 BView::Flags() const
970 _CheckLock();
971 return fFlags & ~_RESIZE_MASK_;
975 void
976 BView::SetFlags(uint32 flags)
978 if (Flags() == flags)
979 return;
981 if (fOwner) {
982 if (flags & B_PULSE_NEEDED) {
983 _CheckLock();
984 if (fOwner->fPulseRunner == NULL)
985 fOwner->SetPulseRate(fOwner->PulseRate());
988 uint32 changesFlags = flags ^ fFlags;
989 if (changesFlags & (B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE
990 | B_FRAME_EVENTS | B_SUBPIXEL_PRECISE)) {
991 _CheckLockAndSwitchCurrent();
993 fOwner->fLink->StartMessage(AS_VIEW_SET_FLAGS);
994 fOwner->fLink->Attach<uint32>(flags);
995 fOwner->fLink->Flush();
999 /* Some useful info:
1000 fFlags is a unsigned long (32 bits)
1001 * bits 1-16 are used for BView's flags
1002 * bits 17-32 are used for BView' resize mask
1003 * _RESIZE_MASK_ is used for that. Look into View.h to see how
1004 it's defined
1006 fFlags = (flags & ~_RESIZE_MASK_) | (fFlags & _RESIZE_MASK_);
1008 fState->archiving_flags |= B_VIEW_FLAGS_BIT;
1012 BRect
1013 BView::Frame() const
1015 return Bounds().OffsetToCopy(fParentOffset.x, fParentOffset.y);
1019 void
1020 BView::Hide()
1022 if (fOwner && fShowLevel == 0) {
1023 _CheckLockAndSwitchCurrent();
1024 fOwner->fLink->StartMessage(AS_VIEW_HIDE);
1025 fOwner->fLink->Flush();
1027 fShowLevel++;
1029 if (fShowLevel == 1)
1030 _InvalidateParentLayout();
1034 void
1035 BView::Show()
1037 fShowLevel--;
1038 if (fOwner && fShowLevel == 0) {
1039 _CheckLockAndSwitchCurrent();
1040 fOwner->fLink->StartMessage(AS_VIEW_SHOW);
1041 fOwner->fLink->Flush();
1044 if (fShowLevel == 0)
1045 _InvalidateParentLayout();
1049 bool
1050 BView::IsFocus() const
1052 if (fOwner) {
1053 _CheckLock();
1054 return fOwner->CurrentFocus() == this;
1055 } else
1056 return false;
1060 bool
1061 BView::IsHidden(const BView* lookingFrom) const
1063 if (fShowLevel > 0)
1064 return true;
1066 // may we be egocentric?
1067 if (lookingFrom == this)
1068 return false;
1070 // we have the same visibility state as our
1071 // parent, if there is one
1072 if (fParent)
1073 return fParent->IsHidden(lookingFrom);
1075 // if we're the top view, and we're interested
1076 // in the "global" view, we're inheriting the
1077 // state of the window's visibility
1078 if (fOwner && lookingFrom == NULL)
1079 return fOwner->IsHidden();
1081 return false;
1085 bool
1086 BView::IsHidden() const
1088 return IsHidden(NULL);
1092 bool
1093 BView::IsPrinting() const
1095 return fIsPrinting;
1099 BPoint
1100 BView::LeftTop() const
1102 return Bounds().LeftTop();
1106 void
1107 BView::SetResizingMode(uint32 mode)
1109 if (fOwner) {
1110 _CheckLockAndSwitchCurrent();
1112 fOwner->fLink->StartMessage(AS_VIEW_RESIZE_MODE);
1113 fOwner->fLink->Attach<uint32>(mode);
1116 // look at SetFlags() for more info on the below line
1117 fFlags = (fFlags & ~_RESIZE_MASK_) | (mode & _RESIZE_MASK_);
1121 uint32
1122 BView::ResizingMode() const
1124 return fFlags & _RESIZE_MASK_;
1128 void
1129 BView::SetViewCursor(const BCursor* cursor, bool sync)
1131 if (cursor == NULL || fOwner == NULL)
1132 return;
1134 _CheckLock();
1136 ViewSetViewCursorInfo info;
1137 info.cursorToken = cursor->fServerToken;
1138 info.viewToken = _get_object_token_(this);
1139 info.sync = sync;
1141 BPrivate::AppServerLink link;
1142 link.StartMessage(AS_SET_VIEW_CURSOR);
1143 link.Attach<ViewSetViewCursorInfo>(info);
1145 if (sync) {
1146 // Make sure the server has processed the message.
1147 int32 code;
1148 link.FlushWithReply(code);
1153 void
1154 BView::Flush() const
1156 if (fOwner)
1157 fOwner->Flush();
1161 void
1162 BView::Sync() const
1164 _CheckOwnerLock();
1165 if (fOwner)
1166 fOwner->Sync();
1170 BWindow*
1171 BView::Window() const
1173 return fOwner;
1177 // #pragma mark - Hook Functions
1180 void
1181 BView::AttachedToWindow()
1183 // Hook function
1184 STRACE(("\tHOOK: BView(%s)::AttachedToWindow()\n", Name()));
1188 void
1189 BView::AllAttached()
1191 // Hook function
1192 STRACE(("\tHOOK: BView(%s)::AllAttached()\n", Name()));
1196 void
1197 BView::DetachedFromWindow()
1199 // Hook function
1200 STRACE(("\tHOOK: BView(%s)::DetachedFromWindow()\n", Name()));
1204 void
1205 BView::AllDetached()
1207 // Hook function
1208 STRACE(("\tHOOK: BView(%s)::AllDetached()\n", Name()));
1212 void
1213 BView::Draw(BRect updateRect)
1215 // Hook function
1216 STRACE(("\tHOOK: BView(%s)::Draw()\n", Name()));
1220 void
1221 BView::DrawAfterChildren(BRect updateRect)
1223 // Hook function
1224 STRACE(("\tHOOK: BView(%s)::DrawAfterChildren()\n", Name()));
1228 void
1229 BView::FrameMoved(BPoint newPosition)
1231 // Hook function
1232 STRACE(("\tHOOK: BView(%s)::FrameMoved()\n", Name()));
1236 void
1237 BView::FrameResized(float newWidth, float newHeight)
1239 // Hook function
1240 STRACE(("\tHOOK: BView(%s)::FrameResized()\n", Name()));
1244 void
1245 BView::GetPreferredSize(float* _width, float* _height)
1247 STRACE(("\tHOOK: BView(%s)::GetPreferredSize()\n", Name()));
1249 if (_width != NULL)
1250 *_width = fBounds.Width();
1251 if (_height != NULL)
1252 *_height = fBounds.Height();
1256 void
1257 BView::ResizeToPreferred()
1259 STRACE(("\tHOOK: BView(%s)::ResizeToPreferred()\n", Name()));
1261 float width;
1262 float height;
1263 GetPreferredSize(&width, &height);
1265 ResizeTo(width, height);
1269 void
1270 BView::KeyDown(const char* bytes, int32 numBytes)
1272 // Hook function
1273 STRACE(("\tHOOK: BView(%s)::KeyDown()\n", Name()));
1275 if (Window())
1276 Window()->_KeyboardNavigation();
1280 void
1281 BView::KeyUp(const char* bytes, int32 numBytes)
1283 // Hook function
1284 STRACE(("\tHOOK: BView(%s)::KeyUp()\n", Name()));
1288 void
1289 BView::MouseDown(BPoint where)
1291 // Hook function
1292 STRACE(("\tHOOK: BView(%s)::MouseDown()\n", Name()));
1296 void
1297 BView::MouseUp(BPoint where)
1299 // Hook function
1300 STRACE(("\tHOOK: BView(%s)::MouseUp()\n", Name()));
1304 void
1305 BView::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
1307 // Hook function
1308 STRACE(("\tHOOK: BView(%s)::MouseMoved()\n", Name()));
1312 void
1313 BView::Pulse()
1315 // Hook function
1316 STRACE(("\tHOOK: BView(%s)::Pulse()\n", Name()));
1320 void
1321 BView::TargetedByScrollView(BScrollView* scroll_view)
1323 // Hook function
1324 STRACE(("\tHOOK: BView(%s)::TargetedByScrollView()\n", Name()));
1328 void
1329 BView::WindowActivated(bool active)
1331 // Hook function
1332 STRACE(("\tHOOK: BView(%s)::WindowActivated()\n", Name()));
1336 // #pragma mark - Input Functions
1339 void
1340 BView::BeginRectTracking(BRect startRect, uint32 style)
1342 if (_CheckOwnerLockAndSwitchCurrent()) {
1343 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_RECT_TRACK);
1344 fOwner->fLink->Attach<BRect>(startRect);
1345 fOwner->fLink->Attach<uint32>(style);
1346 fOwner->fLink->Flush();
1351 void
1352 BView::EndRectTracking()
1354 if (_CheckOwnerLockAndSwitchCurrent()) {
1355 fOwner->fLink->StartMessage(AS_VIEW_END_RECT_TRACK);
1356 fOwner->fLink->Flush();
1361 void
1362 BView::DragMessage(BMessage* message, BRect dragRect, BHandler* replyTo)
1364 if (!message)
1365 return;
1367 _CheckOwnerLock();
1369 // calculate the offset
1370 BPoint offset;
1371 uint32 buttons;
1372 BMessage* current = fOwner->CurrentMessage();
1373 if (!current || current->FindPoint("be:view_where", &offset) != B_OK)
1374 GetMouse(&offset, &buttons, false);
1375 offset -= dragRect.LeftTop();
1377 if (!dragRect.IsValid()) {
1378 DragMessage(message, NULL, B_OP_BLEND, offset, replyTo);
1379 return;
1382 // TODO: that's not really what should happen - the app_server should take
1383 // the chance *NOT* to need to drag a whole bitmap around but just a frame.
1385 // create a drag bitmap for the rect
1386 BBitmap* bitmap = new(std::nothrow) BBitmap(dragRect, B_RGBA32);
1387 if (bitmap == NULL)
1388 return;
1390 uint32* bits = (uint32*)bitmap->Bits();
1391 uint32 bytesPerRow = bitmap->BytesPerRow();
1392 uint32 width = dragRect.IntegerWidth() + 1;
1393 uint32 height = dragRect.IntegerHeight() + 1;
1394 uint32 lastRow = (height - 1) * width;
1396 memset(bits, 0x00, height * bytesPerRow);
1398 // top
1399 for (uint32 i = 0; i < width; i += 2)
1400 bits[i] = 0xff000000;
1402 // bottom
1403 for (uint32 i = (height % 2 == 0 ? 1 : 0); i < width; i += 2)
1404 bits[lastRow + i] = 0xff000000;
1406 // left
1407 for (uint32 i = 0; i < lastRow; i += width * 2)
1408 bits[i] = 0xff000000;
1410 // right
1411 for (uint32 i = (width % 2 == 0 ? width : 0); i < lastRow; i += width * 2)
1412 bits[width - 1 + i] = 0xff000000;
1414 DragMessage(message, bitmap, B_OP_BLEND, offset, replyTo);
1418 void
1419 BView::DragMessage(BMessage* message, BBitmap* image, BPoint offset,
1420 BHandler* replyTo)
1422 DragMessage(message, image, B_OP_COPY, offset, replyTo);
1426 void
1427 BView::DragMessage(BMessage* message, BBitmap* image,
1428 drawing_mode dragMode, BPoint offset, BHandler* replyTo)
1430 if (message == NULL)
1431 return;
1433 if (image == NULL) {
1434 // TODO: workaround for drags without a bitmap - should not be necessary if
1435 // we move the rectangle dragging into the app_server
1436 image = new(std::nothrow) BBitmap(BRect(0, 0, 0, 0), B_RGBA32);
1437 if (image == NULL)
1438 return;
1441 if (replyTo == NULL)
1442 replyTo = this;
1444 if (replyTo->Looper() == NULL)
1445 debugger("DragMessage: warning - the Handler needs a looper");
1447 _CheckOwnerLock();
1449 if (!message->HasInt32("buttons")) {
1450 BMessage* msg = fOwner->CurrentMessage();
1451 uint32 buttons;
1453 if (msg == NULL
1454 || msg->FindInt32("buttons", (int32*)&buttons) != B_OK) {
1455 BPoint point;
1456 GetMouse(&point, &buttons, false);
1459 message->AddInt32("buttons", buttons);
1462 BMessage::Private privateMessage(message);
1463 privateMessage.SetReply(BMessenger(replyTo, replyTo->Looper()));
1465 int32 bufferSize = message->FlattenedSize();
1466 char* buffer = new(std::nothrow) char[bufferSize];
1467 if (buffer != NULL) {
1468 message->Flatten(buffer, bufferSize);
1470 fOwner->fLink->StartMessage(AS_VIEW_DRAG_IMAGE);
1471 fOwner->fLink->Attach<int32>(image->_ServerToken());
1472 fOwner->fLink->Attach<int32>((int32)dragMode);
1473 fOwner->fLink->Attach<BPoint>(offset);
1474 fOwner->fLink->Attach<int32>(bufferSize);
1475 fOwner->fLink->Attach(buffer, bufferSize);
1477 // we need to wait for the server
1478 // to actually process this message
1479 // before we can delete the bitmap
1480 int32 code;
1481 fOwner->fLink->FlushWithReply(code);
1483 delete [] buffer;
1484 } else {
1485 fprintf(stderr, "BView::DragMessage() - no memory to flatten drag "
1486 "message\n");
1489 delete image;
1493 void
1494 BView::GetMouse(BPoint* _location, uint32* _buttons, bool checkMessageQueue)
1496 if (_location == NULL && _buttons == NULL)
1497 return;
1499 _CheckOwnerLockAndSwitchCurrent();
1501 uint32 eventOptions = fEventOptions | fMouseEventOptions;
1502 bool noHistory = eventOptions & B_NO_POINTER_HISTORY;
1503 bool fullHistory = eventOptions & B_FULL_POINTER_HISTORY;
1505 if (checkMessageQueue && !noHistory) {
1506 Window()->UpdateIfNeeded();
1507 BMessageQueue* queue = Window()->MessageQueue();
1508 queue->Lock();
1510 // Look out for mouse update messages
1512 BMessage* message;
1513 for (int32 i = 0; (message = queue->FindMessage(i)) != NULL; i++) {
1514 switch (message->what) {
1515 case B_MOUSE_MOVED:
1516 case B_MOUSE_UP:
1517 case B_MOUSE_DOWN:
1518 bool deleteMessage;
1519 if (!Window()->_StealMouseMessage(message, deleteMessage))
1520 continue;
1522 if (!fullHistory && message->what == B_MOUSE_MOVED) {
1523 // Check if the message is too old. Some applications
1524 // check the message queue in such a way that mouse
1525 // messages *must* pile up. This check makes them work
1526 // as intended, although these applications could simply
1527 // use the version of BView::GetMouse() that does not
1528 // check the history. Also note that it isn't a problem
1529 // to delete the message in case there is not a newer
1530 // one. If we don't find a message in the queue, we will
1531 // just fall back to asking the app_sever directly. So
1532 // the imposed delay will not be a problem on slower
1533 // computers. This check also prevents another problem,
1534 // when the message that we use is *not* removed from
1535 // the queue. Subsequent calls to GetMouse() would find
1536 // this message over and over!
1537 bigtime_t eventTime;
1538 if (message->FindInt64("when", &eventTime) == B_OK
1539 && system_time() - eventTime > 10000) {
1540 // just discard the message
1541 if (deleteMessage)
1542 delete message;
1543 continue;
1546 message->FindPoint("screen_where", _location);
1547 message->FindInt32("buttons", (int32*)_buttons);
1548 queue->Unlock();
1549 // we need to hold the queue lock until here, because
1550 // the message might still be used for something else
1552 if (_location != NULL)
1553 ConvertFromScreen(_location);
1555 if (deleteMessage)
1556 delete message;
1558 return;
1561 queue->Unlock();
1564 // If no mouse update message has been found in the message queue,
1565 // we get the current mouse location and buttons from the app_server
1567 fOwner->fLink->StartMessage(AS_GET_MOUSE);
1569 int32 code;
1570 if (fOwner->fLink->FlushWithReply(code) == B_OK
1571 && code == B_OK) {
1572 BPoint location;
1573 uint32 buttons;
1574 fOwner->fLink->Read<BPoint>(&location);
1575 fOwner->fLink->Read<uint32>(&buttons);
1576 // TODO: ServerWindow replies with an int32 here
1578 ConvertFromScreen(&location);
1579 // TODO: in beos R5, location is already converted to the view
1580 // local coordinate system, so if an app checks the window message
1581 // queue by itself, it might not find what it expects.
1582 // NOTE: the fact that we have mouse coords in screen space in our
1583 // queue avoids the problem that messages already in the queue will
1584 // be outdated as soon as a window or even the view moves. The
1585 // second situation being quite common actually, also with regards
1586 // to scrolling. An app reading these messages would have to know
1587 // the locations of the window and view for each message...
1588 // otherwise it is potentially broken anyways.
1589 if (_location != NULL)
1590 *_location = location;
1591 if (_buttons != NULL)
1592 *_buttons = buttons;
1593 } else {
1594 if (_location != NULL)
1595 _location->Set(0, 0);
1596 if (_buttons != NULL)
1597 *_buttons = 0;
1602 void
1603 BView::MakeFocus(bool focus)
1605 if (fOwner == NULL)
1606 return;
1608 // TODO: If this view has focus and focus == false,
1609 // will there really be no other view with focus? No
1610 // cycling to the next one?
1611 BView* focusView = fOwner->CurrentFocus();
1612 if (focus) {
1613 // Unfocus a previous focus view
1614 if (focusView != NULL && focusView != this)
1615 focusView->MakeFocus(false);
1617 // if we want to make this view the current focus view
1618 fOwner->_SetFocus(this, true);
1619 } else {
1620 // we want to unfocus this view, but only if it actually has focus
1621 if (focusView == this)
1622 fOwner->_SetFocus(NULL, true);
1627 BScrollBar*
1628 BView::ScrollBar(orientation direction) const
1630 switch (direction) {
1631 case B_VERTICAL:
1632 return fVerScroller;
1634 case B_HORIZONTAL:
1635 return fHorScroller;
1637 default:
1638 return NULL;
1643 void
1644 BView::ScrollBy(float deltaX, float deltaY)
1646 ScrollTo(BPoint(fBounds.left + deltaX, fBounds.top + deltaY));
1650 void
1651 BView::ScrollTo(BPoint where)
1653 // scrolling by fractional values is not supported
1654 where.x = roundf(where.x);
1655 where.y = roundf(where.y);
1657 // no reason to process this further if no scroll is intended.
1658 if (where.x == fBounds.left && where.y == fBounds.top)
1659 return;
1661 // make sure scrolling is within valid bounds
1662 if (fHorScroller) {
1663 float min, max;
1664 fHorScroller->GetRange(&min, &max);
1666 if (where.x < min)
1667 where.x = min;
1668 else if (where.x > max)
1669 where.x = max;
1671 if (fVerScroller) {
1672 float min, max;
1673 fVerScroller->GetRange(&min, &max);
1675 if (where.y < min)
1676 where.y = min;
1677 else if (where.y > max)
1678 where.y = max;
1681 _CheckLockAndSwitchCurrent();
1683 float xDiff = where.x - fBounds.left;
1684 float yDiff = where.y - fBounds.top;
1686 // if we're attached to a window tell app_server about this change
1687 if (fOwner) {
1688 fOwner->fLink->StartMessage(AS_VIEW_SCROLL);
1689 fOwner->fLink->Attach<float>(xDiff);
1690 fOwner->fLink->Attach<float>(yDiff);
1692 fOwner->fLink->Flush();
1694 // fState->valid_flags &= ~B_VIEW_FRAME_BIT;
1697 // we modify our bounds rectangle by deltaX/deltaY coord units hor/ver.
1698 fBounds.OffsetTo(where.x, where.y);
1700 // then set the new values of the scrollbars
1701 if (fHorScroller && xDiff != 0.0)
1702 fHorScroller->SetValue(fBounds.left);
1703 if (fVerScroller && yDiff != 0.0)
1704 fVerScroller->SetValue(fBounds.top);
1709 status_t
1710 BView::SetEventMask(uint32 mask, uint32 options)
1712 if (fEventMask == mask && fEventOptions == options)
1713 return B_OK;
1715 // don't change the mask if it's zero and we've got options
1716 if (mask != 0 || options == 0)
1717 fEventMask = mask | (fEventMask & 0xffff0000);
1718 fEventOptions = options;
1720 fState->archiving_flags |= B_VIEW_EVENT_MASK_BIT;
1722 if (fOwner) {
1723 _CheckLockAndSwitchCurrent();
1725 fOwner->fLink->StartMessage(AS_VIEW_SET_EVENT_MASK);
1726 fOwner->fLink->Attach<uint32>(mask);
1727 fOwner->fLink->Attach<uint32>(options);
1728 fOwner->fLink->Flush();
1731 return B_OK;
1735 uint32
1736 BView::EventMask()
1738 return fEventMask;
1742 status_t
1743 BView::SetMouseEventMask(uint32 mask, uint32 options)
1745 // Just don't do anything if the view is not yet attached
1746 // or we were called outside of BView::MouseDown()
1747 if (fOwner != NULL
1748 && fOwner->CurrentMessage() != NULL
1749 && fOwner->CurrentMessage()->what == B_MOUSE_DOWN) {
1750 _CheckLockAndSwitchCurrent();
1751 fMouseEventOptions = options;
1753 fOwner->fLink->StartMessage(AS_VIEW_SET_MOUSE_EVENT_MASK);
1754 fOwner->fLink->Attach<uint32>(mask);
1755 fOwner->fLink->Attach<uint32>(options);
1756 fOwner->fLink->Flush();
1757 return B_OK;
1760 return B_ERROR;
1764 // #pragma mark - Graphic State Functions
1767 void
1768 BView::PushState()
1770 _CheckOwnerLockAndSwitchCurrent();
1772 fOwner->fLink->StartMessage(AS_VIEW_PUSH_STATE);
1774 // initialize origin, scale and transform, new states start "clean".
1775 fState->valid_flags |= B_VIEW_SCALE_BIT | B_VIEW_ORIGIN_BIT
1776 | B_VIEW_TRANSFORM_BIT;
1777 fState->scale = 1.0f;
1778 fState->origin.Set(0, 0);
1779 fState->transform.Reset();
1783 void
1784 BView::PopState()
1786 _CheckOwnerLockAndSwitchCurrent();
1788 fOwner->fLink->StartMessage(AS_VIEW_POP_STATE);
1789 _FlushIfNotInTransaction();
1791 // invalidate all flags (except those that are not part of pop/push)
1792 fState->valid_flags = B_VIEW_VIEW_COLOR_BIT;
1796 void
1797 BView::SetOrigin(BPoint where)
1799 SetOrigin(where.x, where.y);
1803 void
1804 BView::SetOrigin(float x, float y)
1806 if (fState->IsValid(B_VIEW_ORIGIN_BIT)
1807 && x == fState->origin.x && y == fState->origin.y)
1808 return;
1810 fState->origin.x = x;
1811 fState->origin.y = y;
1813 if (_CheckOwnerLockAndSwitchCurrent()) {
1814 fOwner->fLink->StartMessage(AS_VIEW_SET_ORIGIN);
1815 fOwner->fLink->Attach<float>(x);
1816 fOwner->fLink->Attach<float>(y);
1818 fState->valid_flags |= B_VIEW_ORIGIN_BIT;
1821 // our local coord system origin has changed, so when archiving we'll add
1822 // this too
1823 fState->archiving_flags |= B_VIEW_ORIGIN_BIT;
1827 BPoint
1828 BView::Origin() const
1830 if (!fState->IsValid(B_VIEW_ORIGIN_BIT)) {
1831 // we don't keep graphics state information, therefor
1832 // we need to ask the server for the origin after PopState()
1833 _CheckOwnerLockAndSwitchCurrent();
1835 fOwner->fLink->StartMessage(AS_VIEW_GET_ORIGIN);
1837 int32 code;
1838 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK)
1839 fOwner->fLink->Read<BPoint>(&fState->origin);
1841 fState->valid_flags |= B_VIEW_ORIGIN_BIT;
1844 return fState->origin;
1848 void
1849 BView::SetScale(float scale) const
1851 if (fState->IsValid(B_VIEW_SCALE_BIT) && scale == fState->scale)
1852 return;
1854 if (fOwner) {
1855 _CheckLockAndSwitchCurrent();
1857 fOwner->fLink->StartMessage(AS_VIEW_SET_SCALE);
1858 fOwner->fLink->Attach<float>(scale);
1860 fState->valid_flags |= B_VIEW_SCALE_BIT;
1863 fState->scale = scale;
1864 fState->archiving_flags |= B_VIEW_SCALE_BIT;
1868 float
1869 BView::Scale() const
1871 if (!fState->IsValid(B_VIEW_SCALE_BIT) && fOwner) {
1872 _CheckLockAndSwitchCurrent();
1874 fOwner->fLink->StartMessage(AS_VIEW_GET_SCALE);
1876 int32 code;
1877 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK)
1878 fOwner->fLink->Read<float>(&fState->scale);
1880 fState->valid_flags |= B_VIEW_SCALE_BIT;
1883 return fState->scale;
1887 void
1888 BView::SetTransform(BAffineTransform transform)
1890 if (fState->IsValid(B_VIEW_TRANSFORM_BIT) && transform == fState->transform)
1891 return;
1893 if (fOwner != NULL) {
1894 _CheckLockAndSwitchCurrent();
1896 fOwner->fLink->StartMessage(AS_VIEW_SET_TRANSFORM);
1897 fOwner->fLink->Attach<BAffineTransform>(transform);
1899 fState->valid_flags |= B_VIEW_TRANSFORM_BIT;
1902 fState->transform = transform;
1903 fState->archiving_flags |= B_VIEW_TRANSFORM_BIT;
1907 BAffineTransform
1908 BView::Transform() const
1910 if (!fState->IsValid(B_VIEW_TRANSFORM_BIT) && fOwner != NULL) {
1911 _CheckLockAndSwitchCurrent();
1913 fOwner->fLink->StartMessage(AS_VIEW_GET_TRANSFORM);
1915 int32 code;
1916 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK)
1917 fOwner->fLink->Read<BAffineTransform>(&fState->transform);
1919 fState->valid_flags |= B_VIEW_TRANSFORM_BIT;
1922 return fState->transform;
1926 void
1927 BView::SetLineMode(cap_mode lineCap, join_mode lineJoin, float miterLimit)
1929 if (fState->IsValid(B_VIEW_LINE_MODES_BIT)
1930 && lineCap == fState->line_cap && lineJoin == fState->line_join
1931 && miterLimit == fState->miter_limit)
1932 return;
1934 if (fOwner) {
1935 _CheckLockAndSwitchCurrent();
1937 ViewSetLineModeInfo info;
1938 info.lineJoin = lineJoin;
1939 info.lineCap = lineCap;
1940 info.miterLimit = miterLimit;
1942 fOwner->fLink->StartMessage(AS_VIEW_SET_LINE_MODE);
1943 fOwner->fLink->Attach<ViewSetLineModeInfo>(info);
1945 fState->valid_flags |= B_VIEW_LINE_MODES_BIT;
1948 fState->line_cap = lineCap;
1949 fState->line_join = lineJoin;
1950 fState->miter_limit = miterLimit;
1952 fState->archiving_flags |= B_VIEW_LINE_MODES_BIT;
1956 join_mode
1957 BView::LineJoinMode() const
1959 // This will update the current state, if necessary
1960 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT))
1961 LineMiterLimit();
1963 return fState->line_join;
1967 cap_mode
1968 BView::LineCapMode() const
1970 // This will update the current state, if necessary
1971 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT))
1972 LineMiterLimit();
1974 return fState->line_cap;
1978 float
1979 BView::LineMiterLimit() const
1981 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT) && fOwner) {
1982 _CheckLockAndSwitchCurrent();
1984 fOwner->fLink->StartMessage(AS_VIEW_GET_LINE_MODE);
1986 int32 code;
1987 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) {
1989 ViewSetLineModeInfo info;
1990 fOwner->fLink->Read<ViewSetLineModeInfo>(&info);
1992 fState->line_cap = info.lineCap;
1993 fState->line_join = info.lineJoin;
1994 fState->miter_limit = info.miterLimit;
1997 fState->valid_flags |= B_VIEW_LINE_MODES_BIT;
2000 return fState->miter_limit;
2004 void
2005 BView::SetFillRule(int32 fillRule)
2007 if (fState->IsValid(B_VIEW_FILL_RULE_BIT) && fillRule == fState->fill_rule)
2008 return;
2010 if (fOwner) {
2011 _CheckLockAndSwitchCurrent();
2013 fOwner->fLink->StartMessage(AS_VIEW_SET_FILL_RULE);
2014 fOwner->fLink->Attach<int32>(fillRule);
2016 fState->valid_flags |= B_VIEW_FILL_RULE_BIT;
2019 fState->fill_rule = fillRule;
2021 fState->archiving_flags |= B_VIEW_FILL_RULE_BIT;
2025 int32
2026 BView::FillRule() const
2028 if (!fState->IsValid(B_VIEW_FILL_RULE_BIT) && fOwner) {
2029 _CheckLockAndSwitchCurrent();
2031 fOwner->fLink->StartMessage(AS_VIEW_GET_FILL_RULE);
2033 int32 code;
2034 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) {
2036 int32 fillRule;
2037 fOwner->fLink->Read<int32>(&fillRule);
2039 fState->fill_rule = fillRule;
2042 fState->valid_flags |= B_VIEW_FILL_RULE_BIT;
2045 return fState->fill_rule;
2049 void
2050 BView::SetDrawingMode(drawing_mode mode)
2052 if (fState->IsValid(B_VIEW_DRAWING_MODE_BIT)
2053 && mode == fState->drawing_mode)
2054 return;
2056 if (fOwner) {
2057 _CheckLockAndSwitchCurrent();
2059 fOwner->fLink->StartMessage(AS_VIEW_SET_DRAWING_MODE);
2060 fOwner->fLink->Attach<int8>((int8)mode);
2062 fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT;
2065 fState->drawing_mode = mode;
2066 fState->archiving_flags |= B_VIEW_DRAWING_MODE_BIT;
2070 drawing_mode
2071 BView::DrawingMode() const
2073 if (!fState->IsValid(B_VIEW_DRAWING_MODE_BIT) && fOwner) {
2074 _CheckLockAndSwitchCurrent();
2076 fOwner->fLink->StartMessage(AS_VIEW_GET_DRAWING_MODE);
2078 int32 code;
2079 if (fOwner->fLink->FlushWithReply(code) == B_OK
2080 && code == B_OK) {
2081 int8 drawingMode;
2082 fOwner->fLink->Read<int8>(&drawingMode);
2084 fState->drawing_mode = (drawing_mode)drawingMode;
2085 fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT;
2089 return fState->drawing_mode;
2093 void
2094 BView::SetBlendingMode(source_alpha sourceAlpha, alpha_function alphaFunction)
2096 if (fState->IsValid(B_VIEW_BLENDING_BIT)
2097 && sourceAlpha == fState->alpha_source_mode
2098 && alphaFunction == fState->alpha_function_mode)
2099 return;
2101 if (fOwner) {
2102 _CheckLockAndSwitchCurrent();
2104 ViewBlendingModeInfo info;
2105 info.sourceAlpha = sourceAlpha;
2106 info.alphaFunction = alphaFunction;
2108 fOwner->fLink->StartMessage(AS_VIEW_SET_BLENDING_MODE);
2109 fOwner->fLink->Attach<ViewBlendingModeInfo>(info);
2111 fState->valid_flags |= B_VIEW_BLENDING_BIT;
2114 fState->alpha_source_mode = sourceAlpha;
2115 fState->alpha_function_mode = alphaFunction;
2117 fState->archiving_flags |= B_VIEW_BLENDING_BIT;
2121 void
2122 BView::GetBlendingMode(source_alpha* _sourceAlpha,
2123 alpha_function* _alphaFunction) const
2125 if (!fState->IsValid(B_VIEW_BLENDING_BIT) && fOwner) {
2126 _CheckLockAndSwitchCurrent();
2128 fOwner->fLink->StartMessage(AS_VIEW_GET_BLENDING_MODE);
2130 int32 code;
2131 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) {
2132 ViewBlendingModeInfo info;
2133 fOwner->fLink->Read<ViewBlendingModeInfo>(&info);
2135 fState->alpha_source_mode = info.sourceAlpha;
2136 fState->alpha_function_mode = info.alphaFunction;
2138 fState->valid_flags |= B_VIEW_BLENDING_BIT;
2142 if (_sourceAlpha)
2143 *_sourceAlpha = fState->alpha_source_mode;
2145 if (_alphaFunction)
2146 *_alphaFunction = fState->alpha_function_mode;
2150 void
2151 BView::MovePenTo(BPoint point)
2153 MovePenTo(point.x, point.y);
2157 void
2158 BView::MovePenTo(float x, float y)
2160 if (fState->IsValid(B_VIEW_PEN_LOCATION_BIT)
2161 && x == fState->pen_location.x && y == fState->pen_location.y)
2162 return;
2164 if (fOwner) {
2165 _CheckLockAndSwitchCurrent();
2167 fOwner->fLink->StartMessage(AS_VIEW_SET_PEN_LOC);
2168 fOwner->fLink->Attach<BPoint>(BPoint(x, y));
2170 fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT;
2173 fState->pen_location.x = x;
2174 fState->pen_location.y = y;
2176 fState->archiving_flags |= B_VIEW_PEN_LOCATION_BIT;
2180 void
2181 BView::MovePenBy(float x, float y)
2183 // this will update the pen location if necessary
2184 if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT))
2185 PenLocation();
2187 MovePenTo(fState->pen_location.x + x, fState->pen_location.y + y);
2191 BPoint
2192 BView::PenLocation() const
2194 if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT) && fOwner) {
2195 _CheckLockAndSwitchCurrent();
2197 fOwner->fLink->StartMessage(AS_VIEW_GET_PEN_LOC);
2199 int32 code;
2200 if (fOwner->fLink->FlushWithReply(code) == B_OK
2201 && code == B_OK) {
2202 fOwner->fLink->Read<BPoint>(&fState->pen_location);
2204 fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT;
2208 return fState->pen_location;
2212 void
2213 BView::SetPenSize(float size)
2215 if (fState->IsValid(B_VIEW_PEN_SIZE_BIT) && size == fState->pen_size)
2216 return;
2218 if (fOwner) {
2219 _CheckLockAndSwitchCurrent();
2221 fOwner->fLink->StartMessage(AS_VIEW_SET_PEN_SIZE);
2222 fOwner->fLink->Attach<float>(size);
2224 fState->valid_flags |= B_VIEW_PEN_SIZE_BIT;
2227 fState->pen_size = size;
2228 fState->archiving_flags |= B_VIEW_PEN_SIZE_BIT;
2232 float
2233 BView::PenSize() const
2235 if (!fState->IsValid(B_VIEW_PEN_SIZE_BIT) && fOwner) {
2236 _CheckLockAndSwitchCurrent();
2238 fOwner->fLink->StartMessage(AS_VIEW_GET_PEN_SIZE);
2240 int32 code;
2241 if (fOwner->fLink->FlushWithReply(code) == B_OK
2242 && code == B_OK) {
2243 fOwner->fLink->Read<float>(&fState->pen_size);
2245 fState->valid_flags |= B_VIEW_PEN_SIZE_BIT;
2249 return fState->pen_size;
2253 void
2254 BView::SetHighColor(rgb_color color)
2256 // are we up-to-date already?
2257 if (fState->IsValid(B_VIEW_HIGH_COLOR_BIT)
2258 && fState->high_color == color)
2259 return;
2261 if (fOwner) {
2262 _CheckLockAndSwitchCurrent();
2264 fOwner->fLink->StartMessage(AS_VIEW_SET_HIGH_COLOR);
2265 fOwner->fLink->Attach<rgb_color>(color);
2267 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT;
2270 fState->high_color = color;
2272 fState->archiving_flags |= B_VIEW_HIGH_COLOR_BIT;
2276 rgb_color
2277 BView::HighColor() const
2279 if (!fState->IsValid(B_VIEW_HIGH_COLOR_BIT) && fOwner) {
2280 _CheckLockAndSwitchCurrent();
2282 fOwner->fLink->StartMessage(AS_VIEW_GET_HIGH_COLOR);
2284 int32 code;
2285 if (fOwner->fLink->FlushWithReply(code) == B_OK
2286 && code == B_OK) {
2287 fOwner->fLink->Read<rgb_color>(&fState->high_color);
2289 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT;
2293 return fState->high_color;
2297 void
2298 BView::SetLowColor(rgb_color color)
2300 if (fState->IsValid(B_VIEW_LOW_COLOR_BIT)
2301 && fState->low_color == color)
2302 return;
2304 if (fOwner) {
2305 _CheckLockAndSwitchCurrent();
2307 fOwner->fLink->StartMessage(AS_VIEW_SET_LOW_COLOR);
2308 fOwner->fLink->Attach<rgb_color>(color);
2310 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT;
2313 fState->low_color = color;
2315 fState->archiving_flags |= B_VIEW_LOW_COLOR_BIT;
2319 rgb_color
2320 BView::LowColor() const
2322 if (!fState->IsValid(B_VIEW_LOW_COLOR_BIT) && fOwner) {
2323 _CheckLockAndSwitchCurrent();
2325 fOwner->fLink->StartMessage(AS_VIEW_GET_LOW_COLOR);
2327 int32 code;
2328 if (fOwner->fLink->FlushWithReply(code) == B_OK
2329 && code == B_OK) {
2330 fOwner->fLink->Read<rgb_color>(&fState->low_color);
2332 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT;
2336 return fState->low_color;
2340 void
2341 BView::SetViewColor(rgb_color color)
2343 if (fState->IsValid(B_VIEW_VIEW_COLOR_BIT) && fState->view_color == color)
2344 return;
2346 if (fOwner) {
2347 _CheckLockAndSwitchCurrent();
2349 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_COLOR);
2350 fOwner->fLink->Attach<rgb_color>(color);
2351 fOwner->fLink->Flush();
2353 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT;
2356 fState->view_color = color;
2358 fState->archiving_flags |= B_VIEW_VIEW_COLOR_BIT;
2362 rgb_color
2363 BView::ViewColor() const
2365 if (!fState->IsValid(B_VIEW_VIEW_COLOR_BIT) && fOwner) {
2366 _CheckLockAndSwitchCurrent();
2368 fOwner->fLink->StartMessage(AS_VIEW_GET_VIEW_COLOR);
2370 int32 code;
2371 if (fOwner->fLink->FlushWithReply(code) == B_OK
2372 && code == B_OK) {
2373 fOwner->fLink->Read<rgb_color>(&fState->view_color);
2375 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT;
2379 return fState->view_color;
2383 void
2384 BView::ForceFontAliasing(bool enable)
2386 if (fState->IsValid(B_VIEW_FONT_ALIASING_BIT)
2387 && enable == fState->font_aliasing)
2388 return;
2390 if (fOwner) {
2391 _CheckLockAndSwitchCurrent();
2393 fOwner->fLink->StartMessage(AS_VIEW_PRINT_ALIASING);
2394 fOwner->fLink->Attach<bool>(enable);
2396 fState->valid_flags |= B_VIEW_FONT_ALIASING_BIT;
2399 fState->font_aliasing = enable;
2400 fState->archiving_flags |= B_VIEW_FONT_ALIASING_BIT;
2404 void
2405 BView::SetFont(const BFont* font, uint32 mask)
2407 if (!font || mask == 0)
2408 return;
2410 if (mask == B_FONT_ALL) {
2411 fState->font = *font;
2412 } else {
2413 // TODO: move this into a BFont method
2414 if (mask & B_FONT_FAMILY_AND_STYLE)
2415 fState->font.SetFamilyAndStyle(font->FamilyAndStyle());
2417 if (mask & B_FONT_SIZE)
2418 fState->font.SetSize(font->Size());
2420 if (mask & B_FONT_SHEAR)
2421 fState->font.SetShear(font->Shear());
2423 if (mask & B_FONT_ROTATION)
2424 fState->font.SetRotation(font->Rotation());
2426 if (mask & B_FONT_FALSE_BOLD_WIDTH)
2427 fState->font.SetFalseBoldWidth(font->FalseBoldWidth());
2429 if (mask & B_FONT_SPACING)
2430 fState->font.SetSpacing(font->Spacing());
2432 if (mask & B_FONT_ENCODING)
2433 fState->font.SetEncoding(font->Encoding());
2435 if (mask & B_FONT_FACE)
2436 fState->font.SetFace(font->Face());
2438 if (mask & B_FONT_FLAGS)
2439 fState->font.SetFlags(font->Flags());
2442 fState->font_flags |= mask;
2444 if (fOwner) {
2445 _CheckLockAndSwitchCurrent();
2447 fState->UpdateServerFontState(*fOwner->fLink);
2448 fState->valid_flags |= B_VIEW_FONT_BIT;
2451 fState->archiving_flags |= B_VIEW_FONT_BIT;
2452 // TODO: InvalidateLayout() here for convenience?
2456 void
2457 BView::GetFont(BFont* font) const
2459 if (!fState->IsValid(B_VIEW_FONT_BIT)) {
2460 // we don't keep graphics state information, therefor
2461 // we need to ask the server for the origin after PopState()
2462 _CheckOwnerLockAndSwitchCurrent();
2464 // TODO: add a font getter!
2465 fState->UpdateFrom(*fOwner->fLink);
2468 *font = fState->font;
2472 void
2473 BView::GetFontHeight(font_height* height) const
2475 fState->font.GetHeight(height);
2479 void
2480 BView::SetFontSize(float size)
2482 BFont font;
2483 font.SetSize(size);
2485 SetFont(&font, B_FONT_SIZE);
2489 float
2490 BView::StringWidth(const char* string) const
2492 return fState->font.StringWidth(string);
2496 float
2497 BView::StringWidth(const char* string, int32 length) const
2499 return fState->font.StringWidth(string, length);
2503 void
2504 BView::GetStringWidths(char* stringArray[], int32 lengthArray[],
2505 int32 numStrings, float widthArray[]) const
2507 fState->font.GetStringWidths(const_cast<const char**>(stringArray),
2508 const_cast<const int32*>(lengthArray), numStrings, widthArray);
2512 void
2513 BView::TruncateString(BString* string, uint32 mode, float width) const
2515 fState->font.TruncateString(string, mode, width);
2519 void
2520 BView::ClipToPicture(BPicture* picture, BPoint where, bool sync)
2522 _ClipToPicture(picture, where, false, sync);
2526 void
2527 BView::ClipToInversePicture(BPicture* picture, BPoint where, bool sync)
2529 _ClipToPicture(picture, where, true, sync);
2533 void
2534 BView::GetClippingRegion(BRegion* region) const
2536 if (!region)
2537 return;
2539 // NOTE: the client has no idea when the clipping in the server
2540 // changed, so it is always read from the server
2541 region->MakeEmpty();
2544 if (fOwner) {
2545 if (fIsPrinting && _CheckOwnerLock()) {
2546 region->Set(fState->print_rect);
2547 return;
2550 _CheckLockAndSwitchCurrent();
2551 fOwner->fLink->StartMessage(AS_VIEW_GET_CLIP_REGION);
2553 int32 code;
2554 if (fOwner->fLink->FlushWithReply(code) == B_OK
2555 && code == B_OK) {
2556 fOwner->fLink->ReadRegion(region);
2557 fState->valid_flags |= B_VIEW_CLIP_REGION_BIT;
2563 void
2564 BView::ConstrainClippingRegion(BRegion* region)
2566 if (_CheckOwnerLockAndSwitchCurrent()) {
2567 fOwner->fLink->StartMessage(AS_VIEW_SET_CLIP_REGION);
2569 if (region) {
2570 int32 count = region->CountRects();
2571 fOwner->fLink->Attach<int32>(count);
2572 if (count > 0)
2573 fOwner->fLink->AttachRegion(*region);
2574 } else {
2575 fOwner->fLink->Attach<int32>(-1);
2576 // '-1' means that in the app_server, there won't be any 'local'
2577 // clipping region (it will be NULL)
2580 _FlushIfNotInTransaction();
2582 fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT;
2583 fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT;
2588 // #pragma mark - Drawing Functions
2591 void
2592 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect,
2593 uint32 options)
2595 if (bitmap == NULL || fOwner == NULL
2596 || !bitmapRect.IsValid() || !viewRect.IsValid())
2597 return;
2599 _CheckLockAndSwitchCurrent();
2601 ViewDrawBitmapInfo info;
2602 info.bitmapToken = bitmap->_ServerToken();
2603 info.options = options;
2604 info.viewRect = viewRect;
2605 info.bitmapRect = bitmapRect;
2607 fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP);
2608 fOwner->fLink->Attach<ViewDrawBitmapInfo>(info);
2610 _FlushIfNotInTransaction();
2614 void
2615 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect)
2617 DrawBitmapAsync(bitmap, bitmapRect, viewRect, 0);
2621 void
2622 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect viewRect)
2624 if (bitmap && fOwner) {
2625 DrawBitmapAsync(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN),
2626 viewRect, 0);
2631 void
2632 BView::DrawBitmapAsync(const BBitmap* bitmap, BPoint where)
2634 if (bitmap == NULL || fOwner == NULL)
2635 return;
2637 _CheckLockAndSwitchCurrent();
2639 ViewDrawBitmapInfo info;
2640 info.bitmapToken = bitmap->_ServerToken();
2641 info.options = 0;
2642 info.bitmapRect = bitmap->Bounds().OffsetToCopy(B_ORIGIN);
2643 info.viewRect = info.bitmapRect.OffsetToCopy(where);
2645 fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP);
2646 fOwner->fLink->Attach<ViewDrawBitmapInfo>(info);
2648 _FlushIfNotInTransaction();
2652 void
2653 BView::DrawBitmapAsync(const BBitmap* bitmap)
2655 DrawBitmapAsync(bitmap, PenLocation());
2659 void
2660 BView::DrawBitmap(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect,
2661 uint32 options)
2663 if (fOwner) {
2664 DrawBitmapAsync(bitmap, bitmapRect, viewRect, options);
2665 Sync();
2670 void
2671 BView::DrawBitmap(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect)
2673 if (fOwner) {
2674 DrawBitmapAsync(bitmap, bitmapRect, viewRect, 0);
2675 Sync();
2680 void
2681 BView::DrawBitmap(const BBitmap* bitmap, BRect viewRect)
2683 if (bitmap && fOwner) {
2684 DrawBitmap(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN), viewRect,
2690 void
2691 BView::DrawBitmap(const BBitmap* bitmap, BPoint where)
2693 if (fOwner) {
2694 DrawBitmapAsync(bitmap, where);
2695 Sync();
2700 void
2701 BView::DrawBitmap(const BBitmap* bitmap)
2703 DrawBitmap(bitmap, PenLocation());
2707 void
2708 BView::DrawChar(char c)
2710 DrawString(&c, 1, PenLocation());
2714 void
2715 BView::DrawChar(char c, BPoint location)
2717 DrawString(&c, 1, location);
2721 void
2722 BView::DrawString(const char* string, escapement_delta* delta)
2724 if (string == NULL)
2725 return;
2727 DrawString(string, strlen(string), PenLocation(), delta);
2731 void
2732 BView::DrawString(const char* string, BPoint location, escapement_delta* delta)
2734 if (string == NULL)
2735 return;
2737 DrawString(string, strlen(string), location, delta);
2741 void
2742 BView::DrawString(const char* string, int32 length, escapement_delta* delta)
2744 DrawString(string, length, PenLocation(), delta);
2748 void
2749 BView::DrawString(const char* string, int32 length, BPoint location,
2750 escapement_delta* delta)
2752 if (fOwner == NULL || string == NULL || length < 1)
2753 return;
2755 _CheckLockAndSwitchCurrent();
2757 ViewDrawStringInfo info;
2758 info.stringLength = length;
2759 info.location = location;
2760 if (delta != NULL)
2761 info.delta = *delta;
2763 // quite often delta will be NULL
2764 if (delta)
2765 fOwner->fLink->StartMessage(AS_DRAW_STRING_WITH_DELTA);
2766 else
2767 fOwner->fLink->StartMessage(AS_DRAW_STRING);
2769 fOwner->fLink->Attach<ViewDrawStringInfo>(info);
2770 fOwner->fLink->Attach(string, length);
2772 _FlushIfNotInTransaction();
2774 // this modifies our pen location, so we invalidate the flag.
2775 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT;
2779 void
2780 BView::DrawString(const char* string, const BPoint* locations,
2781 int32 locationCount)
2783 if (string == NULL)
2784 return;
2786 DrawString(string, strlen(string), locations, locationCount);
2790 void
2791 BView::DrawString(const char* string, int32 length, const BPoint* locations,
2792 int32 locationCount)
2794 if (fOwner == NULL || string == NULL || length < 1 || locations == NULL)
2795 return;
2797 _CheckLockAndSwitchCurrent();
2799 fOwner->fLink->StartMessage(AS_DRAW_STRING_WITH_OFFSETS);
2801 fOwner->fLink->Attach<int32>(length);
2802 fOwner->fLink->Attach<int32>(locationCount);
2803 fOwner->fLink->Attach(string, length);
2804 fOwner->fLink->Attach(locations, locationCount * sizeof(BPoint));
2806 _FlushIfNotInTransaction();
2808 // this modifies our pen location, so we invalidate the flag.
2809 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT;
2813 void
2814 BView::StrokeEllipse(BPoint center, float xRadius, float yRadius,
2815 ::pattern pattern)
2817 StrokeEllipse(BRect(center.x - xRadius, center.y - yRadius,
2818 center.x + xRadius, center.y + yRadius), pattern);
2822 void
2823 BView::StrokeEllipse(BRect rect, ::pattern pattern)
2825 if (fOwner == NULL)
2826 return;
2828 _CheckLockAndSwitchCurrent();
2829 _UpdatePattern(pattern);
2831 fOwner->fLink->StartMessage(AS_STROKE_ELLIPSE);
2832 fOwner->fLink->Attach<BRect>(rect);
2834 _FlushIfNotInTransaction();
2838 void
2839 BView::FillEllipse(BPoint center, float xRadius, float yRadius,
2840 ::pattern pattern)
2842 FillEllipse(BRect(center.x - xRadius, center.y - yRadius,
2843 center.x + xRadius, center.y + yRadius), pattern);
2847 void
2848 BView::FillEllipse(BPoint center, float xRadius, float yRadius,
2849 const BGradient& gradient)
2851 FillEllipse(BRect(center.x - xRadius, center.y - yRadius,
2852 center.x + xRadius, center.y + yRadius), gradient);
2856 void
2857 BView::FillEllipse(BRect rect, ::pattern pattern)
2859 if (fOwner == NULL)
2860 return;
2862 _CheckLockAndSwitchCurrent();
2863 _UpdatePattern(pattern);
2865 fOwner->fLink->StartMessage(AS_FILL_ELLIPSE);
2866 fOwner->fLink->Attach<BRect>(rect);
2868 _FlushIfNotInTransaction();
2872 void
2873 BView::FillEllipse(BRect rect, const BGradient& gradient)
2875 if (fOwner == NULL)
2876 return;
2878 _CheckLockAndSwitchCurrent();
2880 fOwner->fLink->StartMessage(AS_FILL_ELLIPSE_GRADIENT);
2881 fOwner->fLink->Attach<BRect>(rect);
2882 fOwner->fLink->AttachGradient(gradient);
2884 _FlushIfNotInTransaction();
2888 void
2889 BView::StrokeArc(BPoint center, float xRadius, float yRadius, float startAngle,
2890 float arcAngle, ::pattern pattern)
2892 StrokeArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius,
2893 center.y + yRadius), startAngle, arcAngle, pattern);
2897 void
2898 BView::StrokeArc(BRect rect, float startAngle, float arcAngle,
2899 ::pattern pattern)
2901 if (fOwner == NULL)
2902 return;
2904 _CheckLockAndSwitchCurrent();
2905 _UpdatePattern(pattern);
2907 fOwner->fLink->StartMessage(AS_STROKE_ARC);
2908 fOwner->fLink->Attach<BRect>(rect);
2909 fOwner->fLink->Attach<float>(startAngle);
2910 fOwner->fLink->Attach<float>(arcAngle);
2912 _FlushIfNotInTransaction();
2916 void
2917 BView::FillArc(BPoint center,float xRadius, float yRadius, float startAngle,
2918 float arcAngle, ::pattern pattern)
2920 FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius,
2921 center.y + yRadius), startAngle, arcAngle, pattern);
2925 void
2926 BView::FillArc(BPoint center,float xRadius, float yRadius, float startAngle,
2927 float arcAngle, const BGradient& gradient)
2929 FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius,
2930 center.y + yRadius), startAngle, arcAngle, gradient);
2934 void
2935 BView::FillArc(BRect rect, float startAngle, float arcAngle,
2936 ::pattern pattern)
2938 if (fOwner == NULL)
2939 return;
2941 _CheckLockAndSwitchCurrent();
2942 _UpdatePattern(pattern);
2944 fOwner->fLink->StartMessage(AS_FILL_ARC);
2945 fOwner->fLink->Attach<BRect>(rect);
2946 fOwner->fLink->Attach<float>(startAngle);
2947 fOwner->fLink->Attach<float>(arcAngle);
2949 _FlushIfNotInTransaction();
2953 void
2954 BView::FillArc(BRect rect, float startAngle, float arcAngle,
2955 const BGradient& gradient)
2957 if (fOwner == NULL)
2958 return;
2960 _CheckLockAndSwitchCurrent();
2962 fOwner->fLink->StartMessage(AS_FILL_ARC_GRADIENT);
2963 fOwner->fLink->Attach<BRect>(rect);
2964 fOwner->fLink->Attach<float>(startAngle);
2965 fOwner->fLink->Attach<float>(arcAngle);
2966 fOwner->fLink->AttachGradient(gradient);
2968 _FlushIfNotInTransaction();
2972 void
2973 BView::StrokeBezier(BPoint* controlPoints, ::pattern pattern)
2975 if (fOwner == NULL)
2976 return;
2978 _CheckLockAndSwitchCurrent();
2979 _UpdatePattern(pattern);
2981 fOwner->fLink->StartMessage(AS_STROKE_BEZIER);
2982 fOwner->fLink->Attach<BPoint>(controlPoints[0]);
2983 fOwner->fLink->Attach<BPoint>(controlPoints[1]);
2984 fOwner->fLink->Attach<BPoint>(controlPoints[2]);
2985 fOwner->fLink->Attach<BPoint>(controlPoints[3]);
2987 _FlushIfNotInTransaction();
2991 void
2992 BView::FillBezier(BPoint* controlPoints, ::pattern pattern)
2994 if (fOwner == NULL)
2995 return;
2997 _CheckLockAndSwitchCurrent();
2998 _UpdatePattern(pattern);
3000 fOwner->fLink->StartMessage(AS_FILL_BEZIER);
3001 fOwner->fLink->Attach<BPoint>(controlPoints[0]);
3002 fOwner->fLink->Attach<BPoint>(controlPoints[1]);
3003 fOwner->fLink->Attach<BPoint>(controlPoints[2]);
3004 fOwner->fLink->Attach<BPoint>(controlPoints[3]);
3006 _FlushIfNotInTransaction();
3010 void
3011 BView::FillBezier(BPoint* controlPoints, const BGradient& gradient)
3013 if (fOwner == NULL)
3014 return;
3016 _CheckLockAndSwitchCurrent();
3018 fOwner->fLink->StartMessage(AS_FILL_BEZIER_GRADIENT);
3019 fOwner->fLink->Attach<BPoint>(controlPoints[0]);
3020 fOwner->fLink->Attach<BPoint>(controlPoints[1]);
3021 fOwner->fLink->Attach<BPoint>(controlPoints[2]);
3022 fOwner->fLink->Attach<BPoint>(controlPoints[3]);
3023 fOwner->fLink->AttachGradient(gradient);
3025 _FlushIfNotInTransaction();
3029 void
3030 BView::StrokePolygon(const BPolygon* polygon, bool closed, ::pattern pattern)
3032 if (polygon == NULL)
3033 return;
3035 StrokePolygon(polygon->fPoints, polygon->fCount, polygon->Frame(), closed,
3036 pattern);
3040 void
3041 BView::StrokePolygon(const BPoint* pointArray, int32 numPoints, bool closed,
3042 ::pattern pattern)
3044 BPolygon polygon(pointArray, numPoints);
3046 StrokePolygon(polygon.fPoints, polygon.fCount, polygon.Frame(), closed,
3047 pattern);
3051 void
3052 BView::StrokePolygon(const BPoint* pointArray, int32 numPoints, BRect bounds,
3053 bool closed, ::pattern pattern)
3055 if (pointArray == NULL
3056 || numPoints <= 1
3057 || fOwner == NULL)
3058 return;
3060 _CheckLockAndSwitchCurrent();
3061 _UpdatePattern(pattern);
3063 BPolygon polygon(pointArray, numPoints);
3064 polygon.MapTo(polygon.Frame(), bounds);
3066 if (fOwner->fLink->StartMessage(AS_STROKE_POLYGON,
3067 polygon.fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(bool)
3068 + sizeof(int32)) == B_OK) {
3069 fOwner->fLink->Attach<BRect>(polygon.Frame());
3070 fOwner->fLink->Attach<bool>(closed);
3071 fOwner->fLink->Attach<int32>(polygon.fCount);
3072 fOwner->fLink->Attach(polygon.fPoints, polygon.fCount * sizeof(BPoint));
3074 _FlushIfNotInTransaction();
3075 } else {
3076 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n");
3081 void
3082 BView::FillPolygon(const BPolygon* polygon, ::pattern pattern)
3084 if (polygon == NULL
3085 || polygon->fCount <= 2
3086 || fOwner == NULL)
3087 return;
3089 _CheckLockAndSwitchCurrent();
3090 _UpdatePattern(pattern);
3092 if (fOwner->fLink->StartMessage(AS_FILL_POLYGON,
3093 polygon->fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(int32))
3094 == B_OK) {
3095 fOwner->fLink->Attach<BRect>(polygon->Frame());
3096 fOwner->fLink->Attach<int32>(polygon->fCount);
3097 fOwner->fLink->Attach(polygon->fPoints,
3098 polygon->fCount * sizeof(BPoint));
3100 _FlushIfNotInTransaction();
3101 } else {
3102 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n");
3107 void
3108 BView::FillPolygon(const BPolygon* polygon, const BGradient& gradient)
3110 if (polygon == NULL
3111 || polygon->fCount <= 2
3112 || fOwner == NULL)
3113 return;
3115 _CheckLockAndSwitchCurrent();
3117 if (fOwner->fLink->StartMessage(AS_FILL_POLYGON_GRADIENT,
3118 polygon->fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(int32))
3119 == B_OK) {
3120 fOwner->fLink->Attach<BRect>(polygon->Frame());
3121 fOwner->fLink->Attach<int32>(polygon->fCount);
3122 fOwner->fLink->Attach(polygon->fPoints,
3123 polygon->fCount * sizeof(BPoint));
3124 fOwner->fLink->AttachGradient(gradient);
3126 _FlushIfNotInTransaction();
3127 } else {
3128 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n");
3133 void
3134 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, ::pattern pattern)
3136 if (pointArray == NULL)
3137 return;
3139 BPolygon polygon(pointArray, numPoints);
3140 FillPolygon(&polygon, pattern);
3144 void
3145 BView::FillPolygon(const BPoint* pointArray, int32 numPoints,
3146 const BGradient& gradient)
3148 if (pointArray == NULL)
3149 return;
3151 BPolygon polygon(pointArray, numPoints);
3152 FillPolygon(&polygon, gradient);
3156 void
3157 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, BRect bounds,
3158 ::pattern pattern)
3160 if (pointArray == NULL)
3161 return;
3163 BPolygon polygon(pointArray, numPoints);
3165 polygon.MapTo(polygon.Frame(), bounds);
3166 FillPolygon(&polygon, pattern);
3170 void
3171 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, BRect bounds,
3172 const BGradient& gradient)
3174 if (pointArray == NULL)
3175 return;
3177 BPolygon polygon(pointArray, numPoints);
3179 polygon.MapTo(polygon.Frame(), bounds);
3180 FillPolygon(&polygon, gradient);
3184 void
3185 BView::StrokeRect(BRect rect, ::pattern pattern)
3187 if (fOwner == NULL)
3188 return;
3190 _CheckLockAndSwitchCurrent();
3191 _UpdatePattern(pattern);
3193 fOwner->fLink->StartMessage(AS_STROKE_RECT);
3194 fOwner->fLink->Attach<BRect>(rect);
3196 _FlushIfNotInTransaction();
3200 void
3201 BView::FillRect(BRect rect, ::pattern pattern)
3203 if (fOwner == NULL)
3204 return;
3206 // NOTE: ensuring compatibility with R5,
3207 // invalid rects are not filled, they are stroked though!
3208 if (!rect.IsValid())
3209 return;
3211 _CheckLockAndSwitchCurrent();
3212 _UpdatePattern(pattern);
3214 fOwner->fLink->StartMessage(AS_FILL_RECT);
3215 fOwner->fLink->Attach<BRect>(rect);
3217 _FlushIfNotInTransaction();
3221 void
3222 BView::FillRect(BRect rect, const BGradient& gradient)
3224 if (fOwner == NULL)
3225 return;
3227 // NOTE: ensuring compatibility with R5,
3228 // invalid rects are not filled, they are stroked though!
3229 if (!rect.IsValid())
3230 return;
3232 _CheckLockAndSwitchCurrent();
3234 fOwner->fLink->StartMessage(AS_FILL_RECT_GRADIENT);
3235 fOwner->fLink->Attach<BRect>(rect);
3236 fOwner->fLink->AttachGradient(gradient);
3238 _FlushIfNotInTransaction();
3242 void
3243 BView::StrokeRoundRect(BRect rect, float xRadius, float yRadius,
3244 ::pattern pattern)
3246 if (fOwner == NULL)
3247 return;
3249 _CheckLockAndSwitchCurrent();
3250 _UpdatePattern(pattern);
3252 fOwner->fLink->StartMessage(AS_STROKE_ROUNDRECT);
3253 fOwner->fLink->Attach<BRect>(rect);
3254 fOwner->fLink->Attach<float>(xRadius);
3255 fOwner->fLink->Attach<float>(yRadius);
3257 _FlushIfNotInTransaction();
3261 void
3262 BView::FillRoundRect(BRect rect, float xRadius, float yRadius,
3263 ::pattern pattern)
3265 if (fOwner == NULL)
3266 return;
3268 _CheckLockAndSwitchCurrent();
3270 _UpdatePattern(pattern);
3272 fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT);
3273 fOwner->fLink->Attach<BRect>(rect);
3274 fOwner->fLink->Attach<float>(xRadius);
3275 fOwner->fLink->Attach<float>(yRadius);
3277 _FlushIfNotInTransaction();
3281 void
3282 BView::FillRoundRect(BRect rect, float xRadius, float yRadius,
3283 const BGradient& gradient)
3285 if (fOwner == NULL)
3286 return;
3288 _CheckLockAndSwitchCurrent();
3290 fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT_GRADIENT);
3291 fOwner->fLink->Attach<BRect>(rect);
3292 fOwner->fLink->Attach<float>(xRadius);
3293 fOwner->fLink->Attach<float>(yRadius);
3294 fOwner->fLink->AttachGradient(gradient);
3296 _FlushIfNotInTransaction();
3300 void
3301 BView::FillRegion(BRegion* region, ::pattern pattern)
3303 if (region == NULL || fOwner == NULL)
3304 return;
3306 _CheckLockAndSwitchCurrent();
3308 _UpdatePattern(pattern);
3310 fOwner->fLink->StartMessage(AS_FILL_REGION);
3311 fOwner->fLink->AttachRegion(*region);
3313 _FlushIfNotInTransaction();
3317 void
3318 BView::FillRegion(BRegion* region, const BGradient& gradient)
3320 if (region == NULL || fOwner == NULL)
3321 return;
3323 _CheckLockAndSwitchCurrent();
3325 fOwner->fLink->StartMessage(AS_FILL_REGION_GRADIENT);
3326 fOwner->fLink->AttachRegion(*region);
3327 fOwner->fLink->AttachGradient(gradient);
3329 _FlushIfNotInTransaction();
3333 void
3334 BView::StrokeTriangle(BPoint point1, BPoint point2, BPoint point3, BRect bounds,
3335 ::pattern pattern)
3337 if (fOwner == NULL)
3338 return;
3340 _CheckLockAndSwitchCurrent();
3342 _UpdatePattern(pattern);
3344 fOwner->fLink->StartMessage(AS_STROKE_TRIANGLE);
3345 fOwner->fLink->Attach<BPoint>(point1);
3346 fOwner->fLink->Attach<BPoint>(point2);
3347 fOwner->fLink->Attach<BPoint>(point3);
3348 fOwner->fLink->Attach<BRect>(bounds);
3350 _FlushIfNotInTransaction();
3354 void
3355 BView::StrokeTriangle(BPoint point1, BPoint point2, BPoint point3,
3356 ::pattern pattern)
3358 if (fOwner) {
3359 // we construct the smallest rectangle that contains the 3 points
3360 // for the 1st point
3361 BRect bounds(point1, point1);
3363 // for the 2nd point
3364 if (point2.x < bounds.left)
3365 bounds.left = point2.x;
3367 if (point2.y < bounds.top)
3368 bounds.top = point2.y;
3370 if (point2.x > bounds.right)
3371 bounds.right = point2.x;
3373 if (point2.y > bounds.bottom)
3374 bounds.bottom = point2.y;
3376 // for the 3rd point
3377 if (point3.x < bounds.left)
3378 bounds.left = point3.x;
3380 if (point3.y < bounds.top)
3381 bounds.top = point3.y;
3383 if (point3.x > bounds.right)
3384 bounds.right = point3.x;
3386 if (point3.y > bounds.bottom)
3387 bounds.bottom = point3.y;
3389 StrokeTriangle(point1, point2, point3, bounds, pattern);
3394 void
3395 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3,
3396 ::pattern pattern)
3398 if (fOwner) {
3399 // we construct the smallest rectangle that contains the 3 points
3400 // for the 1st point
3401 BRect bounds(point1, point1);
3403 // for the 2nd point
3404 if (point2.x < bounds.left)
3405 bounds.left = point2.x;
3407 if (point2.y < bounds.top)
3408 bounds.top = point2.y;
3410 if (point2.x > bounds.right)
3411 bounds.right = point2.x;
3413 if (point2.y > bounds.bottom)
3414 bounds.bottom = point2.y;
3416 // for the 3rd point
3417 if (point3.x < bounds.left)
3418 bounds.left = point3.x;
3420 if (point3.y < bounds.top)
3421 bounds.top = point3.y;
3423 if (point3.x > bounds.right)
3424 bounds.right = point3.x;
3426 if (point3.y > bounds.bottom)
3427 bounds.bottom = point3.y;
3429 FillTriangle(point1, point2, point3, bounds, pattern);
3434 void
3435 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3,
3436 const BGradient& gradient)
3438 if (fOwner) {
3439 // we construct the smallest rectangle that contains the 3 points
3440 // for the 1st point
3441 BRect bounds(point1, point1);
3443 // for the 2nd point
3444 if (point2.x < bounds.left)
3445 bounds.left = point2.x;
3447 if (point2.y < bounds.top)
3448 bounds.top = point2.y;
3450 if (point2.x > bounds.right)
3451 bounds.right = point2.x;
3453 if (point2.y > bounds.bottom)
3454 bounds.bottom = point2.y;
3456 // for the 3rd point
3457 if (point3.x < bounds.left)
3458 bounds.left = point3.x;
3460 if (point3.y < bounds.top)
3461 bounds.top = point3.y;
3463 if (point3.x > bounds.right)
3464 bounds.right = point3.x;
3466 if (point3.y > bounds.bottom)
3467 bounds.bottom = point3.y;
3469 FillTriangle(point1, point2, point3, bounds, gradient);
3474 void
3475 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3,
3476 BRect bounds, ::pattern pattern)
3478 if (fOwner == NULL)
3479 return;
3481 _CheckLockAndSwitchCurrent();
3482 _UpdatePattern(pattern);
3484 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE);
3485 fOwner->fLink->Attach<BPoint>(point1);
3486 fOwner->fLink->Attach<BPoint>(point2);
3487 fOwner->fLink->Attach<BPoint>(point3);
3488 fOwner->fLink->Attach<BRect>(bounds);
3490 _FlushIfNotInTransaction();
3494 void
3495 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3, BRect bounds,
3496 const BGradient& gradient)
3498 if (fOwner == NULL)
3499 return;
3501 _CheckLockAndSwitchCurrent();
3502 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE_GRADIENT);
3503 fOwner->fLink->Attach<BPoint>(point1);
3504 fOwner->fLink->Attach<BPoint>(point2);
3505 fOwner->fLink->Attach<BPoint>(point3);
3506 fOwner->fLink->Attach<BRect>(bounds);
3507 fOwner->fLink->AttachGradient(gradient);
3509 _FlushIfNotInTransaction();
3513 void
3514 BView::StrokeLine(BPoint toPoint, ::pattern pattern)
3516 StrokeLine(PenLocation(), toPoint, pattern);
3520 void
3521 BView::StrokeLine(BPoint start, BPoint end, ::pattern pattern)
3523 if (fOwner == NULL)
3524 return;
3526 _CheckLockAndSwitchCurrent();
3527 _UpdatePattern(pattern);
3529 ViewStrokeLineInfo info;
3530 info.startPoint = start;
3531 info.endPoint = end;
3533 fOwner->fLink->StartMessage(AS_STROKE_LINE);
3534 fOwner->fLink->Attach<ViewStrokeLineInfo>(info);
3536 _FlushIfNotInTransaction();
3538 // this modifies our pen location, so we invalidate the flag.
3539 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT;
3543 void
3544 BView::StrokeShape(BShape* shape, ::pattern pattern)
3546 if (shape == NULL || fOwner == NULL)
3547 return;
3549 shape_data* sd = (shape_data*)shape->fPrivateData;
3550 if (sd->opCount == 0 || sd->ptCount == 0)
3551 return;
3553 _CheckLockAndSwitchCurrent();
3554 _UpdatePattern(pattern);
3556 fOwner->fLink->StartMessage(AS_STROKE_SHAPE);
3557 fOwner->fLink->Attach<BRect>(shape->Bounds());
3558 fOwner->fLink->Attach<int32>(sd->opCount);
3559 fOwner->fLink->Attach<int32>(sd->ptCount);
3560 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(uint32));
3561 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint));
3563 _FlushIfNotInTransaction();
3567 void
3568 BView::FillShape(BShape* shape, ::pattern pattern)
3570 if (shape == NULL || fOwner == NULL)
3571 return;
3573 shape_data* sd = (shape_data*)(shape->fPrivateData);
3574 if (sd->opCount == 0 || sd->ptCount == 0)
3575 return;
3577 _CheckLockAndSwitchCurrent();
3578 _UpdatePattern(pattern);
3580 fOwner->fLink->StartMessage(AS_FILL_SHAPE);
3581 fOwner->fLink->Attach<BRect>(shape->Bounds());
3582 fOwner->fLink->Attach<int32>(sd->opCount);
3583 fOwner->fLink->Attach<int32>(sd->ptCount);
3584 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32));
3585 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint));
3587 _FlushIfNotInTransaction();
3591 void
3592 BView::FillShape(BShape* shape, const BGradient& gradient)
3594 if (shape == NULL || fOwner == NULL)
3595 return;
3597 shape_data* sd = (shape_data*)(shape->fPrivateData);
3598 if (sd->opCount == 0 || sd->ptCount == 0)
3599 return;
3601 _CheckLockAndSwitchCurrent();
3603 fOwner->fLink->StartMessage(AS_FILL_SHAPE_GRADIENT);
3604 fOwner->fLink->Attach<BRect>(shape->Bounds());
3605 fOwner->fLink->Attach<int32>(sd->opCount);
3606 fOwner->fLink->Attach<int32>(sd->ptCount);
3607 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32));
3608 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint));
3609 fOwner->fLink->AttachGradient(gradient);
3611 _FlushIfNotInTransaction();
3615 void
3616 BView::BeginLineArray(int32 count)
3618 if (fOwner == NULL)
3619 return;
3621 if (count <= 0)
3622 debugger("Calling BeginLineArray with a count <= 0");
3624 _CheckLock();
3626 if (fCommArray) {
3627 debugger("Can't nest BeginLineArray calls");
3628 // not fatal, but it helps during
3629 // development of your app and is in
3630 // line with R5...
3631 delete[] fCommArray->array;
3632 delete fCommArray;
3635 // TODO: since this method cannot return failure, and further AddLine()
3636 // calls with a NULL fCommArray would drop into the debugger anyway,
3637 // we allow the possible std::bad_alloc exceptions here...
3638 fCommArray = new _array_data_;
3639 fCommArray->count = 0;
3641 // Make sure the fCommArray is initialized to reasonable values in cases of
3642 // bad_alloc. At least the exception can be caught and EndLineArray won't
3643 // crash.
3644 fCommArray->array = NULL;
3645 fCommArray->maxCount = 0;
3647 fCommArray->array = new ViewLineArrayInfo[count];
3648 fCommArray->maxCount = count;
3652 void
3653 BView::AddLine(BPoint start, BPoint end, rgb_color color)
3655 if (fOwner == NULL)
3656 return;
3658 if (!fCommArray)
3659 debugger("BeginLineArray must be called before using AddLine");
3661 _CheckLock();
3663 const uint32 &arrayCount = fCommArray->count;
3664 if (arrayCount < fCommArray->maxCount) {
3665 fCommArray->array[arrayCount].startPoint = start;
3666 fCommArray->array[arrayCount].endPoint = end;
3667 fCommArray->array[arrayCount].color = color;
3669 fCommArray->count++;
3674 void
3675 BView::EndLineArray()
3677 if (fOwner == NULL)
3678 return;
3680 if (fCommArray == NULL)
3681 debugger("Can't call EndLineArray before BeginLineArray");
3683 _CheckLockAndSwitchCurrent();
3685 fOwner->fLink->StartMessage(AS_STROKE_LINEARRAY);
3686 fOwner->fLink->Attach<int32>(fCommArray->count);
3687 fOwner->fLink->Attach(fCommArray->array,
3688 fCommArray->count * sizeof(ViewLineArrayInfo));
3690 _FlushIfNotInTransaction();
3692 _RemoveCommArray();
3696 void
3697 BView::SetDiskMode(char* filename, long offset)
3699 // TODO: implement
3700 // One BeBook version has this to say about SetDiskMode():
3702 // "Begins recording a picture to the file with the given filename
3703 // at the given offset. Subsequent drawing commands sent to the view
3704 // will be written to the file until EndPicture() is called. The
3705 // stored commands may be played from the file with DrawPicture()."
3709 void
3710 BView::BeginPicture(BPicture* picture)
3712 if (_CheckOwnerLockAndSwitchCurrent()
3713 && picture && picture->fUsurped == NULL) {
3714 picture->Usurp(fCurrentPicture);
3715 fCurrentPicture = picture;
3717 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_PICTURE);
3722 void
3723 BView::AppendToPicture(BPicture* picture)
3725 _CheckLockAndSwitchCurrent();
3727 if (picture && picture->fUsurped == NULL) {
3728 int32 token = picture->Token();
3730 if (token == -1) {
3731 BeginPicture(picture);
3732 } else {
3733 picture->SetToken(-1);
3734 picture->Usurp(fCurrentPicture);
3735 fCurrentPicture = picture;
3736 fOwner->fLink->StartMessage(AS_VIEW_APPEND_TO_PICTURE);
3737 fOwner->fLink->Attach<int32>(token);
3743 BPicture*
3744 BView::EndPicture()
3746 if (_CheckOwnerLockAndSwitchCurrent() && fCurrentPicture) {
3747 int32 token;
3749 fOwner->fLink->StartMessage(AS_VIEW_END_PICTURE);
3751 int32 code;
3752 if (fOwner->fLink->FlushWithReply(code) == B_OK
3753 && code == B_OK
3754 && fOwner->fLink->Read<int32>(&token) == B_OK) {
3755 BPicture* picture = fCurrentPicture;
3756 fCurrentPicture = picture->StepDown();
3757 picture->SetToken(token);
3759 // TODO do this more efficient e.g. use a shared area and let the
3760 // client write into it
3761 picture->_Download();
3762 return picture;
3766 return NULL;
3770 void
3771 BView::SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect,
3772 uint32 followFlags, uint32 options)
3774 _SetViewBitmap(bitmap, srcRect, dstRect, followFlags, options);
3778 void
3779 BView::SetViewBitmap(const BBitmap* bitmap, uint32 followFlags, uint32 options)
3781 BRect rect;
3782 if (bitmap)
3783 rect = bitmap->Bounds();
3785 rect.OffsetTo(B_ORIGIN);
3787 _SetViewBitmap(bitmap, rect, rect, followFlags, options);
3791 void
3792 BView::ClearViewBitmap()
3794 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0);
3798 status_t
3799 BView::SetViewOverlay(const BBitmap* overlay, BRect srcRect, BRect dstRect,
3800 rgb_color* colorKey, uint32 followFlags, uint32 options)
3802 if (overlay == NULL || (overlay->fFlags & B_BITMAP_WILL_OVERLAY) == 0)
3803 return B_BAD_VALUE;
3805 status_t status = _SetViewBitmap(overlay, srcRect, dstRect, followFlags,
3806 options | AS_REQUEST_COLOR_KEY);
3807 if (status == B_OK) {
3808 // read the color that will be treated as transparent
3809 fOwner->fLink->Read<rgb_color>(colorKey);
3812 return status;
3816 status_t
3817 BView::SetViewOverlay(const BBitmap* overlay, rgb_color* colorKey,
3818 uint32 followFlags, uint32 options)
3820 if (overlay == NULL)
3821 return B_BAD_VALUE;
3823 BRect rect = overlay->Bounds();
3824 rect.OffsetTo(B_ORIGIN);
3826 return SetViewOverlay(overlay, rect, rect, colorKey, followFlags, options);
3830 void
3831 BView::ClearViewOverlay()
3833 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0);
3837 void
3838 BView::CopyBits(BRect src, BRect dst)
3840 if (fOwner == NULL)
3841 return;
3843 if (!src.IsValid() || !dst.IsValid())
3844 return;
3846 _CheckLockAndSwitchCurrent();
3848 fOwner->fLink->StartMessage(AS_VIEW_COPY_BITS);
3849 fOwner->fLink->Attach<BRect>(src);
3850 fOwner->fLink->Attach<BRect>(dst);
3852 _FlushIfNotInTransaction();
3856 void
3857 BView::DrawPicture(const BPicture* picture)
3859 if (picture == NULL)
3860 return;
3862 DrawPictureAsync(picture, PenLocation());
3863 Sync();
3867 void
3868 BView::DrawPicture(const BPicture* picture, BPoint where)
3870 if (picture == NULL)
3871 return;
3873 DrawPictureAsync(picture, where);
3874 Sync();
3878 void
3879 BView::DrawPicture(const char* filename, long offset, BPoint where)
3881 if (!filename)
3882 return;
3884 DrawPictureAsync(filename, offset, where);
3885 Sync();
3889 void
3890 BView::DrawPictureAsync(const BPicture* picture)
3892 if (picture == NULL)
3893 return;
3895 DrawPictureAsync(picture, PenLocation());
3899 void
3900 BView::DrawPictureAsync(const BPicture* picture, BPoint where)
3902 if (picture == NULL)
3903 return;
3905 if (_CheckOwnerLockAndSwitchCurrent() && picture->Token() > 0) {
3906 fOwner->fLink->StartMessage(AS_VIEW_DRAW_PICTURE);
3907 fOwner->fLink->Attach<int32>(picture->Token());
3908 fOwner->fLink->Attach<BPoint>(where);
3910 _FlushIfNotInTransaction();
3915 void
3916 BView::DrawPictureAsync(const char* filename, long offset, BPoint where)
3918 if (!filename)
3919 return;
3921 // TODO: Test
3922 BFile file(filename, B_READ_ONLY);
3923 if (file.InitCheck() < B_OK)
3924 return;
3926 file.Seek(offset, SEEK_SET);
3928 BPicture picture;
3929 if (picture.Unflatten(&file) < B_OK)
3930 return;
3932 DrawPictureAsync(&picture, where);
3936 void
3937 BView::Invalidate(BRect invalRect)
3939 if (fOwner == NULL)
3940 return;
3942 // NOTE: This rounding of the invalid rect is to stay compatible with BeOS.
3943 // On the server side, the invalid rect will be converted to a BRegion,
3944 // which rounds in a different manner, so that it really includes the
3945 // fractional coordinates of a BRect (ie ceilf(rect.right) &
3946 // ceilf(rect.bottom)), which is also what BeOS does. So we have to do the
3947 // different rounding here to stay compatible in both ways.
3948 invalRect.left = (int)invalRect.left;
3949 invalRect.top = (int)invalRect.top;
3950 invalRect.right = (int)invalRect.right;
3951 invalRect.bottom = (int)invalRect.bottom;
3952 if (!invalRect.IsValid())
3953 return;
3955 _CheckLockAndSwitchCurrent();
3957 fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_RECT);
3958 fOwner->fLink->Attach<BRect>(invalRect);
3960 // TODO: determine why this check isn't working correctly.
3961 #if 0
3962 if (!fOwner->fUpdateRequested) {
3963 fOwner->fLink->Flush();
3964 fOwner->fUpdateRequested = true;
3966 #else
3967 fOwner->fLink->Flush();
3968 #endif
3972 void
3973 BView::Invalidate(const BRegion* region)
3975 if (region == NULL || fOwner == NULL)
3976 return;
3978 _CheckLockAndSwitchCurrent();
3980 fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_REGION);
3981 fOwner->fLink->AttachRegion(*region);
3983 // TODO: See above.
3984 #if 0
3985 if (!fOwner->fUpdateRequested) {
3986 fOwner->fLink->Flush();
3987 fOwner->fUpdateRequested = true;
3989 #else
3990 fOwner->fLink->Flush();
3991 #endif
3995 void
3996 BView::Invalidate()
3998 Invalidate(Bounds());
4002 void
4003 BView::InvertRect(BRect rect)
4005 if (fOwner) {
4006 _CheckLockAndSwitchCurrent();
4008 fOwner->fLink->StartMessage(AS_VIEW_INVERT_RECT);
4009 fOwner->fLink->Attach<BRect>(rect);
4011 _FlushIfNotInTransaction();
4016 // #pragma mark - View Hierarchy Functions
4019 void
4020 BView::AddChild(BView* child, BView* before)
4022 STRACE(("BView(%s)::AddChild(child '%s', before '%s')\n",
4023 this->Name(),
4024 child != NULL && child->Name() ? child->Name() : "NULL",
4025 before != NULL && before->Name() ? before->Name() : "NULL"));
4027 if (!_AddChild(child, before))
4028 return;
4030 if (fLayoutData->fLayout)
4031 fLayoutData->fLayout->AddView(child);
4035 bool
4036 BView::AddChild(BLayoutItem* child)
4038 if (!fLayoutData->fLayout)
4039 return false;
4040 return fLayoutData->fLayout->AddItem(child);
4044 bool
4045 BView::_AddChild(BView* child, BView* before)
4047 if (!child)
4048 return false;
4050 if (child->fParent != NULL) {
4051 debugger("AddChild failed - the view already has a parent.");
4052 return false;
4055 if (child == this) {
4056 debugger("AddChild failed - cannot add a view to itself.");
4057 return false;
4060 bool lockedOwner = false;
4061 if (fOwner && !fOwner->IsLocked()) {
4062 fOwner->Lock();
4063 lockedOwner = true;
4066 if (!_AddChildToList(child, before)) {
4067 debugger("AddChild failed!");
4068 if (lockedOwner)
4069 fOwner->Unlock();
4070 return false;
4073 if (fOwner) {
4074 _CheckLockAndSwitchCurrent();
4076 child->_SetOwner(fOwner);
4077 child->_CreateSelf();
4078 child->_Attach();
4080 if (lockedOwner)
4081 fOwner->Unlock();
4084 InvalidateLayout();
4086 return true;
4090 bool
4091 BView::RemoveChild(BView* child)
4093 STRACE(("BView(%s)::RemoveChild(%s)\n", Name(), child->Name()));
4095 if (!child)
4096 return false;
4098 if (child->fParent != this)
4099 return false;
4101 return child->RemoveSelf();
4105 int32
4106 BView::CountChildren() const
4108 _CheckLock();
4110 uint32 count = 0;
4111 BView* child = fFirstChild;
4113 while (child != NULL) {
4114 count++;
4115 child = child->fNextSibling;
4118 return count;
4122 BView*
4123 BView::ChildAt(int32 index) const
4125 _CheckLock();
4127 BView* child = fFirstChild;
4128 while (child != NULL && index-- > 0) {
4129 child = child->fNextSibling;
4132 return child;
4136 BView*
4137 BView::NextSibling() const
4139 return fNextSibling;
4143 BView*
4144 BView::PreviousSibling() const
4146 return fPreviousSibling;
4150 bool
4151 BView::RemoveSelf()
4153 _RemoveLayoutItemsFromLayout(false);
4155 return _RemoveSelf();
4159 bool
4160 BView::_RemoveSelf()
4162 STRACE(("BView(%s)::_RemoveSelf()\n", Name()));
4164 // Remove this child from its parent
4166 BWindow* owner = fOwner;
4167 _CheckLock();
4169 if (owner != NULL) {
4170 _UpdateStateForRemove();
4171 _Detach();
4174 BView* parent = fParent;
4175 if (!parent || !parent->_RemoveChildFromList(this))
4176 return false;
4178 if (owner != NULL && !fTopLevelView) {
4179 // the top level view is deleted by the app_server automatically
4180 owner->fLink->StartMessage(AS_VIEW_DELETE);
4181 owner->fLink->Attach<int32>(_get_object_token_(this));
4184 parent->InvalidateLayout();
4186 STRACE(("DONE: BView(%s)::_RemoveSelf()\n", Name()));
4188 return true;
4192 void
4193 BView::_RemoveLayoutItemsFromLayout(bool deleteItems)
4195 if (fParent == NULL || fParent->fLayoutData->fLayout == NULL)
4196 return;
4198 int32 index = fLayoutData->fLayoutItems.CountItems();
4199 while (index-- > 0) {
4200 BLayoutItem* item = fLayoutData->fLayoutItems.ItemAt(index);
4201 item->RemoveSelf();
4202 // Removes item from fLayoutItems list
4203 if (deleteItems)
4204 delete item;
4209 BView*
4210 BView::Parent() const
4212 if (fParent && fParent->fTopLevelView)
4213 return NULL;
4215 return fParent;
4219 BView*
4220 BView::FindView(const char* name) const
4222 if (name == NULL)
4223 return NULL;
4225 if (Name() != NULL && !strcmp(Name(), name))
4226 return const_cast<BView*>(this);
4228 BView* child = fFirstChild;
4229 while (child != NULL) {
4230 BView* view = child->FindView(name);
4231 if (view != NULL)
4232 return view;
4234 child = child->fNextSibling;
4237 return NULL;
4241 void
4242 BView::MoveBy(float deltaX, float deltaY)
4244 MoveTo(fParentOffset.x + roundf(deltaX), fParentOffset.y + roundf(deltaY));
4248 void
4249 BView::MoveTo(BPoint where)
4251 MoveTo(where.x, where.y);
4255 void
4256 BView::MoveTo(float x, float y)
4258 if (x == fParentOffset.x && y == fParentOffset.y)
4259 return;
4261 // BeBook says we should do this. And it makes sense.
4262 x = roundf(x);
4263 y = roundf(y);
4265 if (fOwner) {
4266 _CheckLockAndSwitchCurrent();
4267 fOwner->fLink->StartMessage(AS_VIEW_MOVE_TO);
4268 fOwner->fLink->Attach<float>(x);
4269 fOwner->fLink->Attach<float>(y);
4271 // fState->valid_flags |= B_VIEW_FRAME_BIT;
4273 _FlushIfNotInTransaction();
4276 _MoveTo((int32)x, (int32)y);
4280 void
4281 BView::ResizeBy(float deltaWidth, float deltaHeight)
4283 // BeBook says we should do this. And it makes sense.
4284 deltaWidth = roundf(deltaWidth);
4285 deltaHeight = roundf(deltaHeight);
4287 if (deltaWidth == 0 && deltaHeight == 0)
4288 return;
4290 if (fOwner) {
4291 _CheckLockAndSwitchCurrent();
4292 fOwner->fLink->StartMessage(AS_VIEW_RESIZE_TO);
4294 fOwner->fLink->Attach<float>(fBounds.Width() + deltaWidth);
4295 fOwner->fLink->Attach<float>(fBounds.Height() + deltaHeight);
4297 // fState->valid_flags |= B_VIEW_FRAME_BIT;
4299 _FlushIfNotInTransaction();
4302 _ResizeBy((int32)deltaWidth, (int32)deltaHeight);
4306 void
4307 BView::ResizeTo(float width, float height)
4309 ResizeBy(width - fBounds.Width(), height - fBounds.Height());
4313 void
4314 BView::ResizeTo(BSize size)
4316 ResizeBy(size.width - fBounds.Width(), size.height - fBounds.Height());
4320 // #pragma mark - Inherited Methods (from BHandler)
4323 status_t
4324 BView::GetSupportedSuites(BMessage* data)
4326 if (data == NULL)
4327 return B_BAD_VALUE;
4329 status_t status = data->AddString("suites", "suite/vnd.Be-view");
4330 BPropertyInfo propertyInfo(sViewPropInfo);
4331 if (status == B_OK)
4332 status = data->AddFlat("messages", &propertyInfo);
4333 if (status == B_OK)
4334 return BHandler::GetSupportedSuites(data);
4335 return status;
4339 BHandler*
4340 BView::ResolveSpecifier(BMessage* message, int32 index, BMessage* specifier,
4341 int32 what, const char* property)
4343 if (message->what == B_WINDOW_MOVE_BY
4344 || message->what == B_WINDOW_MOVE_TO) {
4345 return this;
4348 BPropertyInfo propertyInfo(sViewPropInfo);
4349 status_t err = B_BAD_SCRIPT_SYNTAX;
4350 BMessage replyMsg(B_REPLY);
4352 switch (propertyInfo.FindMatch(message, index, specifier, what, property)) {
4353 case 0:
4354 case 1:
4355 case 3:
4356 return this;
4358 case 2:
4359 if (fShelf) {
4360 message->PopSpecifier();
4361 return fShelf;
4364 err = B_NAME_NOT_FOUND;
4365 replyMsg.AddString("message", "This window doesn't have a shelf");
4366 break;
4368 case 4:
4370 if (!fFirstChild) {
4371 err = B_NAME_NOT_FOUND;
4372 replyMsg.AddString("message", "This window doesn't have "
4373 "children.");
4374 break;
4376 BView* child = NULL;
4377 switch (what) {
4378 case B_INDEX_SPECIFIER:
4380 int32 index;
4381 err = specifier->FindInt32("index", &index);
4382 if (err == B_OK)
4383 child = ChildAt(index);
4384 break;
4386 case B_REVERSE_INDEX_SPECIFIER:
4388 int32 rindex;
4389 err = specifier->FindInt32("index", &rindex);
4390 if (err == B_OK)
4391 child = ChildAt(CountChildren() - rindex);
4392 break;
4394 case B_NAME_SPECIFIER:
4396 const char* name;
4397 err = specifier->FindString("name", &name);
4398 if (err == B_OK)
4399 child = FindView(name);
4400 break;
4404 if (child != NULL) {
4405 message->PopSpecifier();
4406 return child;
4409 if (err == B_OK)
4410 err = B_BAD_INDEX;
4412 replyMsg.AddString("message",
4413 "Cannot find view at/with specified index/name.");
4414 break;
4417 default:
4418 return BHandler::ResolveSpecifier(message, index, specifier, what,
4419 property);
4422 if (err < B_OK) {
4423 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
4425 if (err == B_BAD_SCRIPT_SYNTAX)
4426 replyMsg.AddString("message", "Didn't understand the specifier(s)");
4427 else
4428 replyMsg.AddString("message", strerror(err));
4431 replyMsg.AddInt32("error", err);
4432 message->SendReply(&replyMsg);
4433 return NULL;
4437 void
4438 BView::MessageReceived(BMessage* message)
4440 if (!message->HasSpecifiers()) {
4441 switch (message->what) {
4442 case B_VIEW_RESIZED:
4443 // By the time the message arrives, the bounds may have
4444 // changed already, that's why we don't use the values
4445 // in the message itself.
4446 FrameResized(fBounds.Width(), fBounds.Height());
4447 break;
4449 case B_VIEW_MOVED:
4450 FrameMoved(fParentOffset);
4451 break;
4453 case B_MOUSE_IDLE:
4455 BPoint where;
4456 if (message->FindPoint("be:view_where", &where) != B_OK)
4457 break;
4459 BToolTip* tip;
4460 if (GetToolTipAt(where, &tip))
4461 ShowToolTip(tip);
4462 else
4463 BHandler::MessageReceived(message);
4464 break;
4467 case B_MOUSE_WHEEL_CHANGED:
4469 BScrollBar* horizontal = ScrollBar(B_HORIZONTAL);
4470 BScrollBar* vertical = ScrollBar(B_VERTICAL);
4471 if (horizontal == NULL && vertical == NULL) {
4472 // Pass the message to the next handler
4473 BHandler::MessageReceived(message);
4474 break;
4477 float deltaX = 0.0f;
4478 float deltaY = 0.0f;
4480 if (horizontal != NULL)
4481 message->FindFloat("be:wheel_delta_x", &deltaX);
4483 if (vertical != NULL)
4484 message->FindFloat("be:wheel_delta_y", &deltaY);
4486 if (deltaX == 0.0f && deltaY == 0.0f)
4487 break;
4489 if ((modifiers() & B_CONTROL_KEY) != 0)
4490 std::swap(horizontal, vertical);
4492 if (horizontal != NULL && deltaX != 0.0f)
4493 ScrollWithMouseWheelDelta(horizontal, deltaX);
4495 if (vertical != NULL && deltaY != 0.0f)
4496 ScrollWithMouseWheelDelta(vertical, deltaY);
4498 break;
4501 default:
4502 BHandler::MessageReceived(message);
4503 break;
4506 return;
4509 // Scripting message
4511 BMessage replyMsg(B_REPLY);
4512 status_t err = B_BAD_SCRIPT_SYNTAX;
4513 int32 index;
4514 BMessage specifier;
4515 int32 what;
4516 const char* property;
4518 if (message->GetCurrentSpecifier(&index, &specifier, &what, &property)
4519 != B_OK) {
4520 return BHandler::MessageReceived(message);
4523 BPropertyInfo propertyInfo(sViewPropInfo);
4524 switch (propertyInfo.FindMatch(message, index, &specifier, what,
4525 property)) {
4526 case 0:
4527 if (message->what == B_GET_PROPERTY) {
4528 err = replyMsg.AddRect("result", Frame());
4529 } else if (message->what == B_SET_PROPERTY) {
4530 BRect newFrame;
4531 err = message->FindRect("data", &newFrame);
4532 if (err == B_OK) {
4533 MoveTo(newFrame.LeftTop());
4534 ResizeTo(newFrame.Width(), newFrame.Height());
4537 break;
4538 case 1:
4539 if (message->what == B_GET_PROPERTY) {
4540 err = replyMsg.AddBool("result", IsHidden());
4541 } else if (message->what == B_SET_PROPERTY) {
4542 bool newHiddenState;
4543 err = message->FindBool("data", &newHiddenState);
4544 if (err == B_OK) {
4545 if (newHiddenState == true)
4546 Hide();
4547 else
4548 Show();
4551 break;
4552 case 3:
4553 err = replyMsg.AddInt32("result", CountChildren());
4554 break;
4555 default:
4556 return BHandler::MessageReceived(message);
4559 if (err != B_OK) {
4560 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
4562 if (err == B_BAD_SCRIPT_SYNTAX)
4563 replyMsg.AddString("message", "Didn't understand the specifier(s)");
4564 else
4565 replyMsg.AddString("message", strerror(err));
4567 replyMsg.AddInt32("error", err);
4570 message->SendReply(&replyMsg);
4574 status_t
4575 BView::Perform(perform_code code, void* _data)
4577 switch (code) {
4578 case PERFORM_CODE_MIN_SIZE:
4579 ((perform_data_min_size*)_data)->return_value
4580 = BView::MinSize();
4581 return B_OK;
4582 case PERFORM_CODE_MAX_SIZE:
4583 ((perform_data_max_size*)_data)->return_value
4584 = BView::MaxSize();
4585 return B_OK;
4586 case PERFORM_CODE_PREFERRED_SIZE:
4587 ((perform_data_preferred_size*)_data)->return_value
4588 = BView::PreferredSize();
4589 return B_OK;
4590 case PERFORM_CODE_LAYOUT_ALIGNMENT:
4591 ((perform_data_layout_alignment*)_data)->return_value
4592 = BView::LayoutAlignment();
4593 return B_OK;
4594 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
4595 ((perform_data_has_height_for_width*)_data)->return_value
4596 = BView::HasHeightForWidth();
4597 return B_OK;
4598 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
4600 perform_data_get_height_for_width* data
4601 = (perform_data_get_height_for_width*)_data;
4602 BView::GetHeightForWidth(data->width, &data->min, &data->max,
4603 &data->preferred);
4604 return B_OK;
4606 case PERFORM_CODE_SET_LAYOUT:
4608 perform_data_set_layout* data = (perform_data_set_layout*)_data;
4609 BView::SetLayout(data->layout);
4610 return B_OK;
4612 case PERFORM_CODE_LAYOUT_INVALIDATED:
4614 perform_data_layout_invalidated* data
4615 = (perform_data_layout_invalidated*)_data;
4616 BView::LayoutInvalidated(data->descendants);
4617 return B_OK;
4619 case PERFORM_CODE_DO_LAYOUT:
4621 BView::DoLayout();
4622 return B_OK;
4624 case PERFORM_CODE_LAYOUT_CHANGED:
4626 BView::LayoutChanged();
4627 return B_OK;
4629 case PERFORM_CODE_GET_TOOL_TIP_AT:
4631 perform_data_get_tool_tip_at* data
4632 = (perform_data_get_tool_tip_at*)_data;
4633 data->return_value
4634 = BView::GetToolTipAt(data->point, data->tool_tip);
4635 return B_OK;
4637 case PERFORM_CODE_ALL_UNARCHIVED:
4639 perform_data_all_unarchived* data =
4640 (perform_data_all_unarchived*)_data;
4642 data->return_value = BView::AllUnarchived(data->archive);
4643 return B_OK;
4645 case PERFORM_CODE_ALL_ARCHIVED:
4647 perform_data_all_archived* data =
4648 (perform_data_all_archived*)_data;
4650 data->return_value = BView::AllArchived(data->archive);
4651 return B_OK;
4655 return BHandler::Perform(code, _data);
4659 // #pragma mark - Layout Functions
4662 BSize
4663 BView::MinSize()
4665 // TODO: make sure this works correctly when some methods are overridden
4666 float width, height;
4667 GetPreferredSize(&width, &height);
4669 return BLayoutUtils::ComposeSize(fLayoutData->fMinSize,
4670 (fLayoutData->fLayout ? fLayoutData->fLayout->MinSize()
4671 : BSize(width, height)));
4675 BSize
4676 BView::MaxSize()
4678 return BLayoutUtils::ComposeSize(fLayoutData->fMaxSize,
4679 (fLayoutData->fLayout ? fLayoutData->fLayout->MaxSize()
4680 : BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)));
4684 BSize
4685 BView::PreferredSize()
4687 // TODO: make sure this works correctly when some methods are overridden
4688 float width, height;
4689 GetPreferredSize(&width, &height);
4691 return BLayoutUtils::ComposeSize(fLayoutData->fPreferredSize,
4692 (fLayoutData->fLayout ? fLayoutData->fLayout->PreferredSize()
4693 : BSize(width, height)));
4697 BAlignment
4698 BView::LayoutAlignment()
4700 return BLayoutUtils::ComposeAlignment(fLayoutData->fAlignment,
4701 (fLayoutData->fLayout ? fLayoutData->fLayout->Alignment()
4702 : BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER)));
4706 void
4707 BView::SetExplicitMinSize(BSize size)
4709 fLayoutData->fMinSize = size;
4710 InvalidateLayout();
4714 void
4715 BView::SetExplicitMaxSize(BSize size)
4717 fLayoutData->fMaxSize = size;
4718 InvalidateLayout();
4722 void
4723 BView::SetExplicitPreferredSize(BSize size)
4725 fLayoutData->fPreferredSize = size;
4726 InvalidateLayout();
4730 void
4731 BView::SetExplicitSize(BSize size)
4733 fLayoutData->fMinSize = size;
4734 fLayoutData->fMaxSize = size;
4735 fLayoutData->fPreferredSize = size;
4736 InvalidateLayout();
4740 void
4741 BView::SetExplicitAlignment(BAlignment alignment)
4743 fLayoutData->fAlignment = alignment;
4744 InvalidateLayout();
4748 BSize
4749 BView::ExplicitMinSize() const
4751 return fLayoutData->fMinSize;
4755 BSize
4756 BView::ExplicitMaxSize() const
4758 return fLayoutData->fMaxSize;
4762 BSize
4763 BView::ExplicitPreferredSize() const
4765 return fLayoutData->fPreferredSize;
4769 BAlignment
4770 BView::ExplicitAlignment() const
4772 return fLayoutData->fAlignment;
4776 bool
4777 BView::HasHeightForWidth()
4779 return (fLayoutData->fLayout
4780 ? fLayoutData->fLayout->HasHeightForWidth() : false);
4784 void
4785 BView::GetHeightForWidth(float width, float* min, float* max, float* preferred)
4787 if (fLayoutData->fLayout)
4788 fLayoutData->fLayout->GetHeightForWidth(width, min, max, preferred);
4792 void
4793 BView::SetLayout(BLayout* layout)
4795 if (layout == fLayoutData->fLayout)
4796 return;
4798 if (layout && layout->Layout())
4799 debugger("BView::SetLayout() failed, layout is already in use.");
4801 fFlags |= B_SUPPORTS_LAYOUT;
4803 // unset and delete the old layout
4804 if (fLayoutData->fLayout) {
4805 fLayoutData->fLayout->RemoveSelf();
4806 fLayoutData->fLayout->SetOwner(NULL);
4807 delete fLayoutData->fLayout;
4810 fLayoutData->fLayout = layout;
4812 if (fLayoutData->fLayout) {
4813 fLayoutData->fLayout->SetOwner(this);
4815 // add all children
4816 int count = CountChildren();
4817 for (int i = 0; i < count; i++)
4818 fLayoutData->fLayout->AddView(ChildAt(i));
4821 InvalidateLayout();
4825 BLayout*
4826 BView::GetLayout() const
4828 return fLayoutData->fLayout;
4832 void
4833 BView::InvalidateLayout(bool descendants)
4835 // printf("BView(%p)::InvalidateLayout(%i), valid: %i, inProgress: %i\n",
4836 // this, descendants, fLayoutData->fLayoutValid,
4837 // fLayoutData->fLayoutInProgress);
4839 if (!fLayoutData->fMinMaxValid || fLayoutData->fLayoutInProgress
4840 || fLayoutData->fLayoutInvalidationDisabled > 0) {
4841 return;
4844 fLayoutData->fLayoutValid = false;
4845 fLayoutData->fMinMaxValid = false;
4846 LayoutInvalidated(descendants);
4848 if (descendants) {
4849 for (BView* child = fFirstChild;
4850 child; child = child->fNextSibling) {
4851 child->InvalidateLayout(descendants);
4855 if (fLayoutData->fLayout)
4856 fLayoutData->fLayout->InvalidateLayout(descendants);
4857 else
4858 _InvalidateParentLayout();
4860 if (fTopLevelView && fOwner)
4861 fOwner->PostMessage(B_LAYOUT_WINDOW);
4865 void
4866 BView::EnableLayoutInvalidation()
4868 if (fLayoutData->fLayoutInvalidationDisabled > 0)
4869 fLayoutData->fLayoutInvalidationDisabled--;
4873 void
4874 BView::DisableLayoutInvalidation()
4876 fLayoutData->fLayoutInvalidationDisabled++;
4880 bool
4881 BView::IsLayoutInvalidationDisabled()
4883 if (fLayoutData->fLayoutInvalidationDisabled > 0)
4884 return true;
4885 return false;
4889 bool
4890 BView::IsLayoutValid() const
4892 return fLayoutData->fLayoutValid;
4896 void
4897 BView::ResetLayoutInvalidation()
4899 fLayoutData->fMinMaxValid = true;
4903 BLayoutContext*
4904 BView::LayoutContext() const
4906 return fLayoutData->fLayoutContext;
4910 void
4911 BView::Layout(bool force)
4913 BLayoutContext context;
4914 _Layout(force, &context);
4918 void
4919 BView::Relayout()
4921 if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) {
4922 fLayoutData->fNeedsRelayout = true;
4923 if (fLayoutData->fLayout)
4924 fLayoutData->fLayout->RequireLayout();
4926 // Layout() is recursive, that is if the parent view is currently laid
4927 // out, we don't call layout() on this view, but wait for the parent's
4928 // Layout() to do that for us.
4929 if (!fParent || !fParent->fLayoutData->fLayoutInProgress)
4930 Layout(false);
4935 void
4936 BView::LayoutInvalidated(bool descendants)
4938 // hook method
4942 void
4943 BView::DoLayout()
4945 if (fLayoutData->fLayout)
4946 fLayoutData->fLayout->_LayoutWithinContext(false, LayoutContext());
4950 void
4951 BView::SetToolTip(const char* text)
4953 if (text == NULL || text[0] == '\0') {
4954 SetToolTip((BToolTip*)NULL);
4955 return;
4958 if (BTextToolTip* tip = dynamic_cast<BTextToolTip*>(fToolTip))
4959 tip->SetText(text);
4960 else
4961 SetToolTip(new BTextToolTip(text));
4965 void
4966 BView::SetToolTip(BToolTip* tip)
4968 if (fToolTip == tip)
4969 return;
4970 else if (tip == NULL)
4971 HideToolTip();
4973 if (fToolTip != NULL)
4974 fToolTip->ReleaseReference();
4976 fToolTip = tip;
4978 if (fToolTip != NULL)
4979 fToolTip->AcquireReference();
4983 BToolTip*
4984 BView::ToolTip() const
4986 return fToolTip;
4990 void
4991 BView::ShowToolTip(BToolTip* tip)
4993 if (tip == NULL)
4994 return;
4996 BPoint where;
4997 GetMouse(&where, NULL, false);
4999 BToolTipManager::Manager()->ShowTip(tip, ConvertToScreen(where), this);
5003 void
5004 BView::HideToolTip()
5006 BToolTipManager::Manager()->HideTip();
5010 bool
5011 BView::GetToolTipAt(BPoint point, BToolTip** _tip)
5013 if (fToolTip != NULL) {
5014 *_tip = fToolTip;
5015 return true;
5018 *_tip = NULL;
5019 return false;
5023 void
5024 BView::LayoutChanged()
5026 // hook method
5030 void
5031 BView::_Layout(bool force, BLayoutContext* context)
5033 //printf("%p->BView::_Layout(%d, %p)\n", this, force, context);
5034 //printf(" fNeedsRelayout: %d, fLayoutValid: %d, fLayoutInProgress: %d\n",
5035 //fLayoutData->fNeedsRelayout, fLayoutData->fLayoutValid,
5036 //fLayoutData->fLayoutInProgress);
5037 if (fLayoutData->fNeedsRelayout || !fLayoutData->fLayoutValid || force) {
5038 fLayoutData->fLayoutValid = false;
5040 if (fLayoutData->fLayoutInProgress)
5041 return;
5043 BLayoutContext* oldContext = fLayoutData->fLayoutContext;
5044 fLayoutData->fLayoutContext = context;
5046 fLayoutData->fLayoutInProgress = true;
5047 DoLayout();
5048 fLayoutData->fLayoutInProgress = false;
5050 fLayoutData->fLayoutValid = true;
5051 fLayoutData->fMinMaxValid = true;
5052 fLayoutData->fNeedsRelayout = false;
5054 // layout children
5055 for(BView* child = fFirstChild; child; child = child->fNextSibling) {
5056 if (!child->IsHidden(child))
5057 child->_Layout(force, context);
5060 LayoutChanged();
5062 fLayoutData->fLayoutContext = oldContext;
5064 // invalidate the drawn content, if requested
5065 if (fFlags & B_INVALIDATE_AFTER_LAYOUT)
5066 Invalidate();
5071 void
5072 BView::_LayoutLeft(BLayout* deleted)
5074 // If our layout is added to another layout (via BLayout::AddItem())
5075 // then we share ownership of our layout. In the event that our layout gets
5076 // deleted by the layout it has been added to, this method is called so
5077 // that we don't double-delete our layout.
5078 if (fLayoutData->fLayout == deleted)
5079 fLayoutData->fLayout = NULL;
5080 InvalidateLayout();
5084 void
5085 BView::_InvalidateParentLayout()
5087 if (!fParent)
5088 return;
5090 BLayout* layout = fLayoutData->fLayout;
5091 BLayout* layoutParent = layout ? layout->Layout() : NULL;
5092 if (layoutParent) {
5093 layoutParent->InvalidateLayout();
5094 } else if (fLayoutData->fLayoutItems.CountItems() > 0) {
5095 int32 count = fLayoutData->fLayoutItems.CountItems();
5096 for (int32 i = 0; i < count; i++) {
5097 fLayoutData->fLayoutItems.ItemAt(i)->Layout()->InvalidateLayout();
5099 } else {
5100 fParent->InvalidateLayout();
5105 // #pragma mark - Private Functions
5108 void
5109 BView::_InitData(BRect frame, const char* name, uint32 resizingMode,
5110 uint32 flags)
5112 // Info: The name of the view is set by BHandler constructor
5114 STRACE(("BView::_InitData: enter\n"));
5116 // initialize members
5117 if ((resizingMode & ~_RESIZE_MASK_) || (flags & _RESIZE_MASK_))
5118 printf("%s BView::_InitData(): resizing mode or flags swapped\n", name);
5120 // There are applications that swap the resize mask and the flags in the
5121 // BView constructor. This does not cause problems under BeOS as it just
5122 // ors the two fields to one 32bit flag.
5123 // For now we do the same but print the above warning message.
5124 // TODO: this should be removed at some point and the original
5125 // version restored:
5126 // fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_);
5127 fFlags = resizingMode | flags;
5129 // handle rounding
5130 frame.left = roundf(frame.left);
5131 frame.top = roundf(frame.top);
5132 frame.right = roundf(frame.right);
5133 frame.bottom = roundf(frame.bottom);
5135 fParentOffset.Set(frame.left, frame.top);
5137 fOwner = NULL;
5138 fParent = NULL;
5139 fNextSibling = NULL;
5140 fPreviousSibling = NULL;
5141 fFirstChild = NULL;
5143 fShowLevel = 0;
5144 fTopLevelView = false;
5146 fCurrentPicture = NULL;
5147 fCommArray = NULL;
5149 fVerScroller = NULL;
5150 fHorScroller = NULL;
5152 fIsPrinting = false;
5153 fAttached = false;
5155 // TODO: Since we cannot communicate failure, we don't use std::nothrow here
5156 // TODO: Maybe we could auto-delete those views on AddChild() instead?
5157 fState = new BPrivate::ViewState;
5159 fBounds = frame.OffsetToCopy(B_ORIGIN);
5160 fShelf = NULL;
5162 fEventMask = 0;
5163 fEventOptions = 0;
5164 fMouseEventOptions = 0;
5166 fLayoutData = new LayoutData;
5168 fToolTip = NULL;
5172 void
5173 BView::_RemoveCommArray()
5175 if (fCommArray) {
5176 delete [] fCommArray->array;
5177 delete fCommArray;
5178 fCommArray = NULL;
5183 void
5184 BView::_SetOwner(BWindow* newOwner)
5186 if (!newOwner)
5187 _RemoveCommArray();
5189 if (fOwner != newOwner && fOwner) {
5190 if (fOwner->fFocus == this)
5191 MakeFocus(false);
5193 if (fOwner->fLastMouseMovedView == this)
5194 fOwner->fLastMouseMovedView = NULL;
5196 fOwner->RemoveHandler(this);
5197 if (fShelf)
5198 fOwner->RemoveHandler(fShelf);
5201 if (newOwner && newOwner != fOwner) {
5202 newOwner->AddHandler(this);
5203 if (fShelf)
5204 newOwner->AddHandler(fShelf);
5206 if (fTopLevelView)
5207 SetNextHandler(newOwner);
5208 else
5209 SetNextHandler(fParent);
5212 fOwner = newOwner;
5214 for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling)
5215 child->_SetOwner(newOwner);
5219 void
5220 BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync)
5222 if (!_CheckOwnerLockAndSwitchCurrent())
5223 return;
5225 if (picture == NULL) {
5226 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE);
5227 fOwner->fLink->Attach<int32>(-1);
5229 // NOTE: No need to sync here, since the -1 token cannot
5230 // become invalid on the server.
5231 } else {
5232 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE);
5233 fOwner->fLink->Attach<int32>(picture->Token());
5234 fOwner->fLink->Attach<BPoint>(where);
5235 fOwner->fLink->Attach<bool>(invert);
5237 // NOTE: "sync" defaults to true in public methods. If you know what
5238 // you are doing, i.e. if you know your BPicture stays valid, you
5239 // can avoid the performance impact of syncing. In a use-case where
5240 // the client creates BPictures on the stack, these BPictures may
5241 // have issued a AS_DELETE_PICTURE command to the ServerApp when Draw()
5242 // goes out of scope, and the command is processed earlier in the
5243 // ServerApp thread than the AS_VIEW_CLIP_TO_PICTURE command in the
5244 // ServerWindow thread, which will then have the result that no
5245 // ServerPicture is found of the token.
5246 if (sync)
5247 Sync();
5252 bool
5253 BView::_RemoveChildFromList(BView* child)
5255 if (child->fParent != this)
5256 return false;
5258 if (fFirstChild == child) {
5259 // it's the first view in the list
5260 fFirstChild = child->fNextSibling;
5261 } else {
5262 // there must be a previous sibling
5263 child->fPreviousSibling->fNextSibling = child->fNextSibling;
5266 if (child->fNextSibling)
5267 child->fNextSibling->fPreviousSibling = child->fPreviousSibling;
5269 child->fParent = NULL;
5270 child->fNextSibling = NULL;
5271 child->fPreviousSibling = NULL;
5273 return true;
5277 bool
5278 BView::_AddChildToList(BView* child, BView* before)
5280 if (!child)
5281 return false;
5282 if (child->fParent != NULL) {
5283 debugger("View already belongs to someone else");
5284 return false;
5286 if (before != NULL && before->fParent != this) {
5287 debugger("Invalid before view");
5288 return false;
5291 if (before != NULL) {
5292 // add view before this one
5293 child->fNextSibling = before;
5294 child->fPreviousSibling = before->fPreviousSibling;
5295 if (child->fPreviousSibling != NULL)
5296 child->fPreviousSibling->fNextSibling = child;
5298 before->fPreviousSibling = child;
5299 if (fFirstChild == before)
5300 fFirstChild = child;
5301 } else {
5302 // add view to the end of the list
5303 BView* last = fFirstChild;
5304 while (last != NULL && last->fNextSibling != NULL) {
5305 last = last->fNextSibling;
5308 if (last != NULL) {
5309 last->fNextSibling = child;
5310 child->fPreviousSibling = last;
5311 } else {
5312 fFirstChild = child;
5313 child->fPreviousSibling = NULL;
5316 child->fNextSibling = NULL;
5319 child->fParent = this;
5320 return true;
5324 /*! \brief Creates the server counterpart of this view.
5325 This is only done for views that are part of the view hierarchy, ie. when
5326 they are attached to a window.
5327 RemoveSelf() deletes the server object again.
5329 bool
5330 BView::_CreateSelf()
5332 // AS_VIEW_CREATE & AS_VIEW_CREATE_ROOT do not use the
5333 // current view mechanism via _CheckLockAndSwitchCurrent() - the token
5334 // of the view and its parent are both send to the server.
5336 if (fTopLevelView)
5337 fOwner->fLink->StartMessage(AS_VIEW_CREATE_ROOT);
5338 else
5339 fOwner->fLink->StartMessage(AS_VIEW_CREATE);
5341 fOwner->fLink->Attach<int32>(_get_object_token_(this));
5342 fOwner->fLink->AttachString(Name());
5343 fOwner->fLink->Attach<BRect>(Frame());
5344 fOwner->fLink->Attach<BPoint>(LeftTop());
5345 fOwner->fLink->Attach<uint32>(ResizingMode());
5346 fOwner->fLink->Attach<uint32>(fEventMask);
5347 fOwner->fLink->Attach<uint32>(fEventOptions);
5348 fOwner->fLink->Attach<uint32>(Flags());
5349 fOwner->fLink->Attach<bool>(IsHidden(this));
5350 fOwner->fLink->Attach<rgb_color>(fState->view_color);
5351 if (fTopLevelView)
5352 fOwner->fLink->Attach<int32>(B_NULL_TOKEN);
5353 else
5354 fOwner->fLink->Attach<int32>(_get_object_token_(fParent));
5355 fOwner->fLink->Flush();
5357 _CheckOwnerLockAndSwitchCurrent();
5358 fState->UpdateServerState(*fOwner->fLink);
5360 // we create all its children, too
5362 for (BView* child = fFirstChild; child != NULL;
5363 child = child->fNextSibling) {
5364 child->_CreateSelf();
5367 fOwner->fLink->Flush();
5368 return true;
5372 /*! Sets the new view position.
5373 It doesn't contact the server, though - the only case where this
5374 is called outside of MoveTo() is as reaction of moving a view
5375 in the server (a.k.a. B_WINDOW_RESIZED).
5376 It also calls the BView's FrameMoved() hook.
5378 void
5379 BView::_MoveTo(int32 x, int32 y)
5381 fParentOffset.Set(x, y);
5383 if (Window() != NULL && fFlags & B_FRAME_EVENTS) {
5384 BMessage moved(B_VIEW_MOVED);
5385 moved.AddInt64("when", system_time());
5386 moved.AddPoint("where", BPoint(x, y));
5388 BMessenger target(this);
5389 target.SendMessage(&moved);
5394 /*! Computes the actual new frame size and recalculates the size of
5395 the children as well.
5396 It doesn't contact the server, though - the only case where this
5397 is called outside of ResizeBy() is as reaction of resizing a view
5398 in the server (a.k.a. B_WINDOW_RESIZED).
5399 It also calls the BView's FrameResized() hook.
5401 void
5402 BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight)
5404 fBounds.right += deltaWidth;
5405 fBounds.bottom += deltaHeight;
5407 if (Window() == NULL) {
5408 // we're not supposed to exercise the resizing code in case
5409 // we haven't been attached to a window yet
5410 return;
5413 // layout the children
5414 if (fFlags & B_SUPPORTS_LAYOUT) {
5415 Relayout();
5416 } else {
5417 for (BView* child = fFirstChild; child; child = child->fNextSibling)
5418 child->_ParentResizedBy(deltaWidth, deltaHeight);
5421 if (fFlags & B_FRAME_EVENTS) {
5422 BMessage resized(B_VIEW_RESIZED);
5423 resized.AddInt64("when", system_time());
5424 resized.AddInt32("width", fBounds.IntegerWidth());
5425 resized.AddInt32("height", fBounds.IntegerHeight());
5427 BMessenger target(this);
5428 target.SendMessage(&resized);
5433 /*! Relayouts the view according to its resizing mode. */
5434 void
5435 BView::_ParentResizedBy(int32 x, int32 y)
5437 uint32 resizingMode = fFlags & _RESIZE_MASK_;
5438 BRect newFrame = Frame();
5440 // follow with left side
5441 if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8)
5442 newFrame.left += x;
5443 else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8)
5444 newFrame.left += x / 2;
5446 // follow with right side
5447 if ((resizingMode & 0x000FU) == _VIEW_RIGHT_)
5448 newFrame.right += x;
5449 else if ((resizingMode & 0x000FU) == _VIEW_CENTER_)
5450 newFrame.right += x / 2;
5452 // follow with top side
5453 if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12)
5454 newFrame.top += y;
5455 else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12)
5456 newFrame.top += y / 2;
5458 // follow with bottom side
5459 if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4)
5460 newFrame.bottom += y;
5461 else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4)
5462 newFrame.bottom += y / 2;
5464 if (newFrame.LeftTop() != fParentOffset) {
5465 // move view
5466 _MoveTo((int32)roundf(newFrame.left), (int32)roundf(newFrame.top));
5469 if (newFrame != Frame()) {
5470 // resize view
5471 int32 widthDiff = (int32)(newFrame.Width() - fBounds.Width());
5472 int32 heightDiff = (int32)(newFrame.Height() - fBounds.Height());
5473 _ResizeBy(widthDiff, heightDiff);
5478 void
5479 BView::_Activate(bool active)
5481 WindowActivated(active);
5483 for (BView* child = fFirstChild; child != NULL;
5484 child = child->fNextSibling) {
5485 child->_Activate(active);
5490 void
5491 BView::_Attach()
5493 AttachedToWindow();
5494 fAttached = true;
5496 // after giving the view a chance to do this itself,
5497 // check for the B_PULSE_NEEDED flag and make sure the
5498 // window set's up the pulse messaging
5499 if (fOwner) {
5500 if (fFlags & B_PULSE_NEEDED) {
5501 _CheckLock();
5502 if (fOwner->fPulseRunner == NULL)
5503 fOwner->SetPulseRate(fOwner->PulseRate());
5506 if (!fOwner->IsHidden())
5507 Invalidate();
5510 for (BView* child = fFirstChild; child != NULL;
5511 child = child->fNextSibling) {
5512 // we need to check for fAttached as new views could have been
5513 // added in AttachedToWindow() - and those are already attached
5514 if (!child->fAttached)
5515 child->_Attach();
5518 AllAttached();
5522 void
5523 BView::_Detach()
5525 DetachedFromWindow();
5526 fAttached = false;
5528 for (BView* child = fFirstChild; child != NULL;
5529 child = child->fNextSibling) {
5530 child->_Detach();
5533 AllDetached();
5535 if (fOwner) {
5536 _CheckLock();
5538 if (!fOwner->IsHidden())
5539 Invalidate();
5541 // make sure our owner doesn't need us anymore
5543 if (fOwner->CurrentFocus() == this) {
5544 MakeFocus(false);
5545 // MakeFocus() is virtual and might not be
5546 // passing through to the BView version,
5547 // but we need to make sure at this point
5548 // that we are not the focus view anymore.
5549 if (fOwner->CurrentFocus() == this)
5550 fOwner->_SetFocus(NULL, true);
5553 if (fOwner->fDefaultButton == this)
5554 fOwner->SetDefaultButton(NULL);
5556 if (fOwner->fKeyMenuBar == this)
5557 fOwner->fKeyMenuBar = NULL;
5559 if (fOwner->fLastMouseMovedView == this)
5560 fOwner->fLastMouseMovedView = NULL;
5562 if (fOwner->fLastViewToken == _get_object_token_(this))
5563 fOwner->fLastViewToken = B_NULL_TOKEN;
5565 _SetOwner(NULL);
5570 void
5571 BView::_Draw(BRect updateRect)
5573 if (IsHidden(this) || !(Flags() & B_WILL_DRAW))
5574 return;
5576 // NOTE: if ViewColor() == B_TRANSPARENT_COLOR and no B_WILL_DRAW
5577 // -> View is simply not drawn at all
5579 _SwitchServerCurrentView();
5581 ConvertFromScreen(&updateRect);
5583 // TODO: make states robust (the hook implementation could
5584 // mess things up if it uses non-matching Push- and PopState(),
5585 // we would not be guaranteed to still have the same state on
5586 // the stack after having called Draw())
5587 PushState();
5588 Draw(updateRect);
5589 PopState();
5590 Flush();
5594 void
5595 BView::_DrawAfterChildren(BRect updateRect)
5597 if (IsHidden(this) || !(Flags() & B_WILL_DRAW)
5598 || !(Flags() & B_DRAW_ON_CHILDREN))
5599 return;
5601 _SwitchServerCurrentView();
5603 ConvertFromScreen(&updateRect);
5605 // TODO: make states robust (see above)
5606 PushState();
5607 DrawAfterChildren(updateRect);
5608 PopState();
5609 Flush();
5613 void
5614 BView::_Pulse()
5616 if ((Flags() & B_PULSE_NEEDED) != 0)
5617 Pulse();
5619 for (BView* child = fFirstChild; child != NULL;
5620 child = child->fNextSibling) {
5621 child->_Pulse();
5626 void
5627 BView::_UpdateStateForRemove()
5629 // TODO: _CheckLockAndSwitchCurrent() would be good enough, no?
5630 if (!_CheckOwnerLockAndSwitchCurrent())
5631 return;
5633 fState->UpdateFrom(*fOwner->fLink);
5634 // if (!fState->IsValid(B_VIEW_FRAME_BIT)) {
5635 // fOwner->fLink->StartMessage(AS_VIEW_GET_COORD);
5637 // status_t code;
5638 // if (fOwner->fLink->FlushWithReply(code) == B_OK
5639 // && code == B_OK) {
5640 // fOwner->fLink->Read<BPoint>(&fParentOffset);
5641 // fOwner->fLink->Read<BRect>(&fBounds);
5642 // fState->valid_flags |= B_VIEW_FRAME_BIT;
5643 // }
5644 // }
5646 // update children as well
5648 for (BView* child = fFirstChild; child != NULL;
5649 child = child->fNextSibling) {
5650 if (child->fOwner)
5651 child->_UpdateStateForRemove();
5656 inline void
5657 BView::_UpdatePattern(::pattern pattern)
5659 if (fState->IsValid(B_VIEW_PATTERN_BIT) && pattern == fState->pattern)
5660 return;
5662 if (fOwner) {
5663 _CheckLockAndSwitchCurrent();
5665 fOwner->fLink->StartMessage(AS_VIEW_SET_PATTERN);
5666 fOwner->fLink->Attach< ::pattern>(pattern);
5668 fState->valid_flags |= B_VIEW_PATTERN_BIT;
5671 fState->pattern = pattern;
5675 void
5676 BView::_FlushIfNotInTransaction()
5678 if (!fOwner->fInTransaction) {
5679 fOwner->Flush();
5684 BShelf*
5685 BView::_Shelf() const
5687 return fShelf;
5691 void
5692 BView::_SetShelf(BShelf* shelf)
5694 if (fShelf != NULL && fOwner != NULL)
5695 fOwner->RemoveHandler(fShelf);
5697 fShelf = shelf;
5699 if (fShelf != NULL && fOwner != NULL)
5700 fOwner->AddHandler(fShelf);
5704 status_t
5705 BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect,
5706 uint32 followFlags, uint32 options)
5708 if (!_CheckOwnerLockAndSwitchCurrent())
5709 return B_ERROR;
5711 int32 serverToken = bitmap ? bitmap->_ServerToken() : -1;
5713 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_BITMAP);
5714 fOwner->fLink->Attach<int32>(serverToken);
5715 fOwner->fLink->Attach<BRect>(srcRect);
5716 fOwner->fLink->Attach<BRect>(dstRect);
5717 fOwner->fLink->Attach<int32>(followFlags);
5718 fOwner->fLink->Attach<int32>(options);
5720 status_t status = B_ERROR;
5721 fOwner->fLink->FlushWithReply(status);
5723 return status;
5727 bool
5728 BView::_CheckOwnerLockAndSwitchCurrent() const
5730 STRACE(("BView(%s)::_CheckOwnerLockAndSwitchCurrent()\n", Name()));
5732 if (fOwner == NULL) {
5733 debugger("View method requires owner and doesn't have one.");
5734 return false;
5737 _CheckLockAndSwitchCurrent();
5739 return true;
5743 bool
5744 BView::_CheckOwnerLock() const
5746 if (fOwner) {
5747 fOwner->check_lock();
5748 return true;
5749 } else {
5750 debugger("View method requires owner and doesn't have one.");
5751 return false;
5756 void
5757 BView::_CheckLockAndSwitchCurrent() const
5759 STRACE(("BView(%s)::_CheckLockAndSwitchCurrent()\n", Name()));
5761 if (!fOwner)
5762 return;
5764 fOwner->check_lock();
5766 _SwitchServerCurrentView();
5770 void
5771 BView::_CheckLock() const
5773 if (fOwner)
5774 fOwner->check_lock();
5778 void
5779 BView::_SwitchServerCurrentView() const
5781 int32 serverToken = _get_object_token_(this);
5783 if (fOwner->fLastViewToken != serverToken) {
5784 STRACE(("contacting app_server... sending token: %" B_PRId32 "\n",
5785 serverToken));
5786 fOwner->fLink->StartMessage(AS_SET_CURRENT_VIEW);
5787 fOwner->fLink->Attach<int32>(serverToken);
5789 fOwner->fLastViewToken = serverToken;
5794 status_t
5795 BView::ScrollWithMouseWheelDelta(BScrollBar* scrollBar, float delta)
5797 if (scrollBar == NULL || delta == 0.0f)
5798 return B_BAD_VALUE;
5800 float smallStep;
5801 float largeStep;
5802 scrollBar->GetSteps(&smallStep, &largeStep);
5804 // pressing the shift key scrolls faster (following the pseudo-standard set
5805 // by other desktop environments).
5806 if ((modifiers() & B_SHIFT_KEY) != 0)
5807 delta *= largeStep;
5808 else
5809 delta *= smallStep * 3;
5811 scrollBar->SetValue(scrollBar->Value() + delta);
5813 return B_OK;
5817 #if __GNUC__ == 2
5820 extern "C" void
5821 _ReservedView1__5BView(BView* view, BRect rect)
5823 view->BView::DrawAfterChildren(rect);
5827 extern "C" void
5828 _ReservedView2__5BView(BView* view)
5830 // MinSize()
5831 perform_data_min_size data;
5832 view->Perform(PERFORM_CODE_MIN_SIZE, &data);
5836 extern "C" void
5837 _ReservedView3__5BView(BView* view)
5839 // MaxSize()
5840 perform_data_max_size data;
5841 view->Perform(PERFORM_CODE_MAX_SIZE, &data);
5845 extern "C" BSize
5846 _ReservedView4__5BView(BView* view)
5848 // PreferredSize()
5849 perform_data_preferred_size data;
5850 view->Perform(PERFORM_CODE_PREFERRED_SIZE, &data);
5851 return data.return_value;
5855 extern "C" BAlignment
5856 _ReservedView5__5BView(BView* view)
5858 // LayoutAlignment()
5859 perform_data_layout_alignment data;
5860 view->Perform(PERFORM_CODE_LAYOUT_ALIGNMENT, &data);
5861 return data.return_value;
5865 extern "C" bool
5866 _ReservedView6__5BView(BView* view)
5868 // HasHeightForWidth()
5869 perform_data_has_height_for_width data;
5870 view->Perform(PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH, &data);
5871 return data.return_value;
5875 extern "C" void
5876 _ReservedView7__5BView(BView* view, float width, float* min, float* max,
5877 float* preferred)
5879 // GetHeightForWidth()
5880 perform_data_get_height_for_width data;
5881 data.width = width;
5882 view->Perform(PERFORM_CODE_GET_HEIGHT_FOR_WIDTH, &data);
5883 if (min != NULL)
5884 *min = data.min;
5885 if (max != NULL)
5886 *max = data.max;
5887 if (preferred != NULL)
5888 *preferred = data.preferred;
5892 extern "C" void
5893 _ReservedView8__5BView(BView* view, BLayout* layout)
5895 // SetLayout()
5896 perform_data_set_layout data;
5897 data.layout = layout;
5898 view->Perform(PERFORM_CODE_SET_LAYOUT, &data);
5902 extern "C" void
5903 _ReservedView9__5BView(BView* view, bool descendants)
5905 // LayoutInvalidated()
5906 perform_data_layout_invalidated data;
5907 data.descendants = descendants;
5908 view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data);
5912 extern "C" void
5913 _ReservedView10__5BView(BView* view)
5915 // DoLayout()
5916 view->Perform(PERFORM_CODE_DO_LAYOUT, NULL);
5920 #endif // __GNUC__ == 2
5923 extern "C" bool
5924 B_IF_GCC_2(_ReservedView11__5BView, _ZN5BView15_ReservedView11Ev)(
5925 BView* view, BPoint point, BToolTip** _toolTip)
5927 // GetToolTipAt()
5928 perform_data_get_tool_tip_at data;
5929 data.point = point;
5930 data.tool_tip = _toolTip;
5931 view->Perform(PERFORM_CODE_GET_TOOL_TIP_AT, &data);
5932 return data.return_value;
5936 extern "C" void
5937 B_IF_GCC_2(_ReservedView12__5BView, _ZN5BView15_ReservedView12Ev)(
5938 BView* view)
5940 // LayoutChanged();
5941 view->Perform(PERFORM_CODE_LAYOUT_CHANGED, NULL);
5945 void BView::_ReservedView13() {}
5946 void BView::_ReservedView14() {}
5947 void BView::_ReservedView15() {}
5948 void BView::_ReservedView16() {}
5951 BView::BView(const BView& other)
5953 BHandler()
5955 // this is private and not functional, but exported
5959 BView&
5960 BView::operator=(const BView& other)
5962 // this is private and not functional, but exported
5963 return *this;
5967 void
5968 BView::_PrintToStream()
5970 printf("BView::_PrintToStream()\n");
5971 printf("\tName: %s\n"
5972 "\tParent: %s\n"
5973 "\tFirstChild: %s\n"
5974 "\tNextSibling: %s\n"
5975 "\tPrevSibling: %s\n"
5976 "\tOwner(Window): %s\n"
5977 "\tToken: %" B_PRId32 "\n"
5978 "\tFlags: %" B_PRId32 "\n"
5979 "\tView origin: (%f,%f)\n"
5980 "\tView Bounds rectangle: (%f,%f,%f,%f)\n"
5981 "\tShow level: %d\n"
5982 "\tTopView?: %s\n"
5983 "\tBPicture: %s\n"
5984 "\tVertical Scrollbar %s\n"
5985 "\tHorizontal Scrollbar %s\n"
5986 "\tIs Printing?: %s\n"
5987 "\tShelf?: %s\n"
5988 "\tEventMask: %" B_PRId32 "\n"
5989 "\tEventOptions: %" B_PRId32 "\n",
5990 Name(),
5991 fParent ? fParent->Name() : "NULL",
5992 fFirstChild ? fFirstChild->Name() : "NULL",
5993 fNextSibling ? fNextSibling->Name() : "NULL",
5994 fPreviousSibling ? fPreviousSibling->Name() : "NULL",
5995 fOwner ? fOwner->Name() : "NULL",
5996 _get_object_token_(this),
5997 fFlags,
5998 fParentOffset.x, fParentOffset.y,
5999 fBounds.left, fBounds.top, fBounds.right, fBounds.bottom,
6000 fShowLevel,
6001 fTopLevelView ? "YES" : "NO",
6002 fCurrentPicture? "YES" : "NULL",
6003 fVerScroller? "YES" : "NULL",
6004 fHorScroller? "YES" : "NULL",
6005 fIsPrinting? "YES" : "NO",
6006 fShelf? "YES" : "NO",
6007 fEventMask,
6008 fEventOptions);
6010 printf("\tState status:\n"
6011 "\t\tLocalCoordianteSystem: (%f,%f)\n"
6012 "\t\tPenLocation: (%f,%f)\n"
6013 "\t\tPenSize: %f\n"
6014 "\t\tHighColor: [%d,%d,%d,%d]\n"
6015 "\t\tLowColor: [%d,%d,%d,%d]\n"
6016 "\t\tViewColor: [%d,%d,%d,%d]\n"
6017 "\t\tPattern: %" B_PRIx64 "\n"
6018 "\t\tDrawingMode: %d\n"
6019 "\t\tLineJoinMode: %d\n"
6020 "\t\tLineCapMode: %d\n"
6021 "\t\tMiterLimit: %f\n"
6022 "\t\tAlphaSource: %d\n"
6023 "\t\tAlphaFuntion: %d\n"
6024 "\t\tScale: %f\n"
6025 "\t\t(Print)FontAliasing: %s\n"
6026 "\t\tFont Info:\n",
6027 fState->origin.x, fState->origin.y,
6028 fState->pen_location.x, fState->pen_location.y,
6029 fState->pen_size,
6030 fState->high_color.red, fState->high_color.blue, fState->high_color.green, fState->high_color.alpha,
6031 fState->low_color.red, fState->low_color.blue, fState->low_color.green, fState->low_color.alpha,
6032 fState->view_color.red, fState->view_color.blue, fState->view_color.green, fState->view_color.alpha,
6033 *((uint64*)&(fState->pattern)),
6034 fState->drawing_mode,
6035 fState->line_join,
6036 fState->line_cap,
6037 fState->miter_limit,
6038 fState->alpha_source_mode,
6039 fState->alpha_function_mode,
6040 fState->scale,
6041 fState->font_aliasing? "YES" : "NO");
6043 fState->font.PrintToStream();
6045 // TODO: also print the line array.
6049 void
6050 BView::_PrintTree()
6052 int32 spaces = 2;
6053 BView* c = fFirstChild; //c = short for: current
6054 printf( "'%s'\n", Name() );
6055 if (c != NULL) {
6056 while(true) {
6057 // action block
6059 for (int i = 0; i < spaces; i++)
6060 printf(" ");
6062 printf( "'%s'\n", c->Name() );
6065 // go deep
6066 if (c->fFirstChild) {
6067 c = c->fFirstChild;
6068 spaces += 2;
6069 } else {
6070 // go right
6071 if (c->fNextSibling) {
6072 c = c->fNextSibling;
6073 } else {
6074 // go up
6075 while (!c->fParent->fNextSibling && c->fParent != this) {
6076 c = c->fParent;
6077 spaces -= 2;
6080 // that enough! We've reached this view.
6081 if (c->fParent == this)
6082 break;
6084 c = c->fParent->fNextSibling;
6085 spaces -= 2;
6093 // #pragma mark -
6096 BLayoutItem*
6097 BView::Private::LayoutItemAt(int32 index)
6099 return fView->fLayoutData->fLayoutItems.ItemAt(index);
6103 int32
6104 BView::Private::CountLayoutItems()
6106 return fView->fLayoutData->fLayoutItems.CountItems();
6110 void
6111 BView::Private::RegisterLayoutItem(BLayoutItem* item)
6113 fView->fLayoutData->fLayoutItems.AddItem(item);
6117 void
6118 BView::Private::DeregisterLayoutItem(BLayoutItem* item)
6120 fView->fLayoutData->fLayoutItems.RemoveItem(item);
6124 bool
6125 BView::Private::MinMaxValid()
6127 return fView->fLayoutData->fMinMaxValid;
6131 bool
6132 BView::Private::WillLayout()
6134 BView::LayoutData* data = fView->fLayoutData;
6135 if (data->fLayoutInProgress)
6136 return false;
6137 if (data->fNeedsRelayout || !data->fLayoutValid || !data->fMinMaxValid)
6138 return true;
6139 return false;