btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / kits / interface / View.cpp
bloba709eee1dc4ba9383a7b16fc473ac0aa8867179c
1 /*
2 * Copyright 2001-2017 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
10 * Julian Harnath, julian.harnath@rwth-aachen.de
11 * Joseph Groover, looncraz@looncraz.net
15 #include <View.h>
17 #include <algorithm>
18 #include <new>
20 #include <math.h>
21 #include <stdio.h>
23 #include <Application.h>
24 #include <Bitmap.h>
25 #include <Button.h>
26 #include <Cursor.h>
27 #include <File.h>
28 #include <GradientLinear.h>
29 #include <GradientRadial.h>
30 #include <GradientRadialFocus.h>
31 #include <GradientDiamond.h>
32 #include <GradientConic.h>
33 #include <InterfaceDefs.h>
34 #include <Layout.h>
35 #include <LayoutContext.h>
36 #include <LayoutUtils.h>
37 #include <MenuBar.h>
38 #include <Message.h>
39 #include <MessageQueue.h>
40 #include <ObjectList.h>
41 #include <Picture.h>
42 #include <Point.h>
43 #include <Polygon.h>
44 #include <PropertyInfo.h>
45 #include <Region.h>
46 #include <ScrollBar.h>
47 #include <Shape.h>
48 #include <Shelf.h>
49 #include <String.h>
50 #include <Window.h>
52 #include <AppMisc.h>
53 #include <AppServerLink.h>
54 #include <binary_compatibility/Interface.h>
55 #include <binary_compatibility/Support.h>
56 #include <MessagePrivate.h>
57 #include <MessageUtils.h>
58 #include <PortLink.h>
59 #include <ServerProtocol.h>
60 #include <ServerProtocolStructs.h>
61 #include <ShapePrivate.h>
62 #include <ToolTip.h>
63 #include <ToolTipManager.h>
64 #include <TokenSpace.h>
65 #include <ViewPrivate.h>
67 using std::nothrow;
69 //#define DEBUG_BVIEW
70 #ifdef DEBUG_BVIEW
71 # include <stdio.h>
72 # define STRACE(x) printf x
73 # define BVTRACE _PrintToStream()
74 #else
75 # define STRACE(x) ;
76 # define BVTRACE ;
77 #endif
80 static property_info sViewPropInfo[] = {
81 { "Frame", { B_GET_PROPERTY, B_SET_PROPERTY },
82 { B_DIRECT_SPECIFIER, 0 }, "The view's frame rectangle.", 0,
83 { B_RECT_TYPE }
85 { "Hidden", { B_GET_PROPERTY, B_SET_PROPERTY },
86 { B_DIRECT_SPECIFIER, 0 }, "Whether or not the view is hidden.",
87 0, { B_BOOL_TYPE }
89 { "Shelf", { 0 },
90 { B_DIRECT_SPECIFIER, 0 }, "Directs the scripting message to the "
91 "shelf.", 0
93 { "View", { B_COUNT_PROPERTIES, 0 },
94 { B_DIRECT_SPECIFIER, 0 }, "Returns the number of child views.", 0,
95 { B_INT32_TYPE }
97 { "View", { 0 },
98 { B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER, B_NAME_SPECIFIER, 0 },
99 "Directs the scripting message to the specified view.", 0
102 { 0 }
106 // #pragma mark -
109 static inline uint32
110 get_uint32_color(rgb_color color)
112 return B_BENDIAN_TO_HOST_INT32(*(uint32*)&color);
113 // rgb_color is always in rgba format, no matter what endian;
114 // we always return the int32 value in host endian.
118 static inline rgb_color
119 get_rgb_color(uint32 value)
121 value = B_HOST_TO_BENDIAN_INT32(value);
122 return *(rgb_color*)&value;
126 // #pragma mark -
129 namespace BPrivate {
131 ViewState::ViewState()
133 pen_location.Set(0, 0);
134 pen_size = 1.0;
136 // NOTE: the clipping_region is empty
137 // on construction but it is not used yet,
138 // we avoid having to keep track of it via
139 // this flag
140 clipping_region_used = false;
142 high_color = (rgb_color){ 0, 0, 0, 255 };
143 low_color = (rgb_color){ 255, 255, 255, 255 };
144 view_color = low_color;
145 which_view_color = B_NO_COLOR;
146 which_view_color_tint = B_NO_TINT;
148 which_high_color = B_NO_COLOR;
149 which_high_color_tint = B_NO_TINT;
151 which_low_color = B_NO_COLOR;
152 which_low_color_tint = B_NO_TINT;
154 pattern = B_SOLID_HIGH;
155 drawing_mode = B_OP_COPY;
157 origin.Set(0, 0);
159 line_join = B_MITER_JOIN;
160 line_cap = B_BUTT_CAP;
161 miter_limit = B_DEFAULT_MITER_LIMIT;
162 fill_rule = B_NONZERO;
164 alpha_source_mode = B_PIXEL_ALPHA;
165 alpha_function_mode = B_ALPHA_OVERLAY;
167 scale = 1.0;
169 font = *be_plain_font;
170 font_flags = font.Flags();
171 font_aliasing = false;
173 // We only keep the B_VIEW_CLIP_REGION_BIT flag invalidated,
174 // because we should get the clipping region from app_server.
175 // The other flags do not need to be included because the data they
176 // represent is already in sync with app_server - app_server uses the
177 // same init (default) values.
178 valid_flags = ~B_VIEW_CLIP_REGION_BIT;
180 archiving_flags = B_VIEW_FRAME_BIT | B_VIEW_RESIZE_BIT;
184 void
185 ViewState::UpdateServerFontState(BPrivate::PortLink &link)
187 link.StartMessage(AS_VIEW_SET_FONT_STATE);
188 link.Attach<uint16>(font_flags);
189 // always present
191 if (font_flags & B_FONT_FAMILY_AND_STYLE)
192 link.Attach<uint32>(font.FamilyAndStyle());
194 if (font_flags & B_FONT_SIZE)
195 link.Attach<float>(font.Size());
197 if (font_flags & B_FONT_SHEAR)
198 link.Attach<float>(font.Shear());
200 if (font_flags & B_FONT_ROTATION)
201 link.Attach<float>(font.Rotation());
203 if (font_flags & B_FONT_FALSE_BOLD_WIDTH)
204 link.Attach<float>(font.FalseBoldWidth());
206 if (font_flags & B_FONT_SPACING)
207 link.Attach<uint8>(font.Spacing());
209 if (font_flags & B_FONT_ENCODING)
210 link.Attach<uint8>(font.Encoding());
212 if (font_flags & B_FONT_FACE)
213 link.Attach<uint16>(font.Face());
215 if (font_flags & B_FONT_FLAGS)
216 link.Attach<uint32>(font.Flags());
220 void
221 ViewState::UpdateServerState(BPrivate::PortLink &link)
223 UpdateServerFontState(link);
225 link.StartMessage(AS_VIEW_SET_STATE);
227 ViewSetStateInfo info;
228 info.penLocation = pen_location;
229 info.penSize = pen_size;
230 info.highColor = high_color;
231 info.lowColor = low_color;
232 info.whichHighColor = which_high_color;
233 info.whichLowColor = which_low_color;
234 info.whichHighColorTint = which_high_color_tint;
235 info.whichLowColorTint = which_low_color_tint;
236 info.pattern = pattern;
237 info.drawingMode = drawing_mode;
238 info.origin = origin;
239 info.scale = scale;
240 info.transform = transform;
241 info.lineJoin = line_join;
242 info.lineCap = line_cap;
243 info.miterLimit = miter_limit;
244 info.fillRule = fill_rule;
245 info.alphaSourceMode = alpha_source_mode;
246 info.alphaFunctionMode = alpha_function_mode;
247 info.fontAntialiasing = font_aliasing;
248 link.Attach<ViewSetStateInfo>(info);
250 // we send the 'local' clipping region... if we have one...
251 // TODO: Could be optimized, but is low prio, since most views won't
252 // have a custom clipping region.
253 if (clipping_region_used) {
254 int32 count = clipping_region.CountRects();
255 link.Attach<int32>(count);
256 for (int32 i = 0; i < count; i++)
257 link.Attach<BRect>(clipping_region.RectAt(i));
258 } else {
259 // no clipping region
260 link.Attach<int32>(-1);
263 // Although we might have a 'local' clipping region, when we call
264 // BView::GetClippingRegion() we ask for the 'global' one and it
265 // is kept on server, so we must invalidate B_VIEW_CLIP_REGION_BIT flag
267 valid_flags = ~B_VIEW_CLIP_REGION_BIT;
271 void
272 ViewState::UpdateFrom(BPrivate::PortLink &link)
274 link.StartMessage(AS_VIEW_GET_STATE);
276 int32 code;
277 if (link.FlushWithReply(code) != B_OK
278 || code != B_OK)
279 return;
281 ViewGetStateInfo info;
282 link.Read<ViewGetStateInfo>(&info);
284 // set view's font state
285 font_flags = B_FONT_ALL;
286 font.SetFamilyAndStyle(info.fontID);
287 font.SetSize(info.fontSize);
288 font.SetShear(info.fontShear);
289 font.SetRotation(info.fontRotation);
290 font.SetFalseBoldWidth(info.fontFalseBoldWidth);
291 font.SetSpacing(info.fontSpacing);
292 font.SetEncoding(info.fontEncoding);
293 font.SetFace(info.fontFace);
294 font.SetFlags(info.fontFlags);
296 // set view's state
297 pen_location = info.viewStateInfo.penLocation;
298 pen_size = info.viewStateInfo.penSize;
299 high_color = info.viewStateInfo.highColor;
300 low_color = info.viewStateInfo.lowColor;
301 pattern = info.viewStateInfo.pattern;
302 drawing_mode = info.viewStateInfo.drawingMode;
303 origin = info.viewStateInfo.origin;
304 scale = info.viewStateInfo.scale;
305 transform = info.viewStateInfo.transform;
306 line_join = info.viewStateInfo.lineJoin;
307 line_cap = info.viewStateInfo.lineCap;
308 miter_limit = info.viewStateInfo.miterLimit;
309 fill_rule = info.viewStateInfo.fillRule;
310 alpha_source_mode = info.viewStateInfo.alphaSourceMode;
311 alpha_function_mode = info.viewStateInfo.alphaFunctionMode;
312 font_aliasing = info.viewStateInfo.fontAntialiasing;
314 // read the user clipping
315 // (that's NOT the current View visible clipping but the additional
316 // user specified clipping!)
317 int32 clippingRectCount;
318 link.Read<int32>(&clippingRectCount);
319 if (clippingRectCount >= 0) {
320 clipping_region.MakeEmpty();
321 for (int32 i = 0; i < clippingRectCount; i++) {
322 BRect rect;
323 link.Read<BRect>(&rect);
324 clipping_region.Include(rect);
326 } else {
327 // no user clipping used
328 clipping_region_used = false;
331 valid_flags = ~B_VIEW_CLIP_REGION_BIT;
334 } // namespace BPrivate
337 // #pragma mark -
340 // archiving constants
341 namespace {
342 const char* const kSizesField = "BView:sizes";
343 // kSizesField = {min, max, pref}
344 const char* const kAlignmentField = "BView:alignment";
345 const char* const kLayoutField = "BView:layout";
349 struct BView::LayoutData {
350 LayoutData()
352 fMinSize(),
353 fMaxSize(),
354 fPreferredSize(),
355 fAlignment(),
356 fLayoutInvalidationDisabled(0),
357 fLayout(NULL),
358 fLayoutContext(NULL),
359 fLayoutItems(5, false),
360 fLayoutValid(true), // TODO: Rethink these initial values!
361 fMinMaxValid(true), //
362 fLayoutInProgress(false),
363 fNeedsRelayout(true)
367 status_t
368 AddDataToArchive(BMessage* archive)
370 status_t err = archive->AddSize(kSizesField, fMinSize);
372 if (err == B_OK)
373 err = archive->AddSize(kSizesField, fMaxSize);
375 if (err == B_OK)
376 err = archive->AddSize(kSizesField, fPreferredSize);
378 if (err == B_OK)
379 err = archive->AddAlignment(kAlignmentField, fAlignment);
381 return err;
384 void
385 PopulateFromArchive(BMessage* archive)
387 archive->FindSize(kSizesField, 0, &fMinSize);
388 archive->FindSize(kSizesField, 1, &fMaxSize);
389 archive->FindSize(kSizesField, 2, &fPreferredSize);
390 archive->FindAlignment(kAlignmentField, &fAlignment);
393 BSize fMinSize;
394 BSize fMaxSize;
395 BSize fPreferredSize;
396 BAlignment fAlignment;
397 int fLayoutInvalidationDisabled;
398 BLayout* fLayout;
399 BLayoutContext* fLayoutContext;
400 BObjectList<BLayoutItem> fLayoutItems;
401 bool fLayoutValid;
402 bool fMinMaxValid;
403 bool fLayoutInProgress;
404 bool fNeedsRelayout;
408 BView::BView(const char* name, uint32 flags, BLayout* layout)
410 BHandler(name)
412 _InitData(BRect(0, 0, -1, -1), name, B_FOLLOW_NONE,
413 flags | B_SUPPORTS_LAYOUT);
414 SetLayout(layout);
418 BView::BView(BRect frame, const char* name, uint32 resizingMode, uint32 flags)
420 BHandler(name)
422 _InitData(frame, name, resizingMode, flags);
426 BView::BView(BMessage* archive)
428 BHandler(BUnarchiver::PrepareArchive(archive))
430 BUnarchiver unarchiver(archive);
431 if (!archive)
432 debugger("BView cannot be constructed from a NULL archive.");
434 BRect frame;
435 archive->FindRect("_frame", &frame);
437 uint32 resizingMode;
438 if (archive->FindInt32("_resize_mode", (int32*)&resizingMode) != B_OK)
439 resizingMode = 0;
441 uint32 flags;
442 if (archive->FindInt32("_flags", (int32*)&flags) != B_OK)
443 flags = 0;
445 _InitData(frame, Name(), resizingMode, flags);
447 font_family family;
448 font_style style;
449 if (archive->FindString("_fname", 0, (const char**)&family) == B_OK
450 && archive->FindString("_fname", 1, (const char**)&style) == B_OK) {
451 BFont font;
452 font.SetFamilyAndStyle(family, style);
454 float size;
455 if (archive->FindFloat("_fflt", 0, &size) == B_OK)
456 font.SetSize(size);
458 float shear;
459 if (archive->FindFloat("_fflt", 1, &shear) == B_OK
460 && shear >= 45.0 && shear <= 135.0)
461 font.SetShear(shear);
463 float rotation;
464 if (archive->FindFloat("_fflt", 2, &rotation) == B_OK
465 && rotation >=0 && rotation <= 360)
466 font.SetRotation(rotation);
468 SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE
469 | B_FONT_SHEAR | B_FONT_ROTATION);
472 int32 color = 0;
473 if (archive->FindInt32("_color", 0, &color) == B_OK)
474 SetHighColor(get_rgb_color(color));
475 if (archive->FindInt32("_color", 1, &color) == B_OK)
476 SetLowColor(get_rgb_color(color));
477 if (archive->FindInt32("_color", 2, &color) == B_OK)
478 SetViewColor(get_rgb_color(color));
480 float tint = B_NO_TINT;
481 if (archive->FindInt32("_uicolor", 0, &color) == B_OK
482 && color != B_NO_COLOR) {
483 if (archive->FindFloat("_uitint", 0, &tint) != B_OK)
484 tint = B_NO_TINT;
486 SetHighUIColor((color_which)color, tint);
488 if (archive->FindInt32("_uicolor", 1, &color) == B_OK
489 && color != B_NO_COLOR) {
490 if (archive->FindFloat("_uitint", 1, &tint) != B_OK)
491 tint = B_NO_TINT;
493 SetLowUIColor((color_which)color, tint);
495 if (archive->FindInt32("_uicolor", 2, &color) == B_OK
496 && color != B_NO_COLOR) {
497 if (archive->FindFloat("_uitint", 2, &tint) != B_OK)
498 tint = B_NO_TINT;
500 SetViewUIColor((color_which)color, tint);
503 uint32 evMask;
504 uint32 options;
505 if (archive->FindInt32("_evmask", 0, (int32*)&evMask) == B_OK
506 && archive->FindInt32("_evmask", 1, (int32*)&options) == B_OK)
507 SetEventMask(evMask, options);
509 BPoint origin;
510 if (archive->FindPoint("_origin", &origin) == B_OK)
511 SetOrigin(origin);
513 float scale;
514 if (archive->FindFloat("_scale", &scale) == B_OK)
515 SetScale(scale);
517 BAffineTransform transform;
518 if (archive->FindFlat("_transform", &transform) == B_OK)
519 SetTransform(transform);
521 float penSize;
522 if (archive->FindFloat("_psize", &penSize) == B_OK)
523 SetPenSize(penSize);
525 BPoint penLocation;
526 if (archive->FindPoint("_ploc", &penLocation) == B_OK)
527 MovePenTo(penLocation);
529 int16 lineCap;
530 int16 lineJoin;
531 float lineMiter;
532 if (archive->FindInt16("_lmcapjoin", 0, &lineCap) == B_OK
533 && archive->FindInt16("_lmcapjoin", 1, &lineJoin) == B_OK
534 && archive->FindFloat("_lmmiter", &lineMiter) == B_OK)
535 SetLineMode((cap_mode)lineCap, (join_mode)lineJoin, lineMiter);
537 int16 fillRule;
538 if (archive->FindInt16("_fillrule", &fillRule) == B_OK)
539 SetFillRule(fillRule);
541 int16 alphaBlend;
542 int16 modeBlend;
543 if (archive->FindInt16("_blend", 0, &alphaBlend) == B_OK
544 && archive->FindInt16("_blend", 1, &modeBlend) == B_OK)
545 SetBlendingMode( (source_alpha)alphaBlend, (alpha_function)modeBlend);
547 uint32 drawingMode;
548 if (archive->FindInt32("_dmod", (int32*)&drawingMode) == B_OK)
549 SetDrawingMode((drawing_mode)drawingMode);
551 fLayoutData->PopulateFromArchive(archive);
553 if (archive->FindInt16("_show", &fShowLevel) != B_OK)
554 fShowLevel = 0;
556 if (BUnarchiver::IsArchiveManaged(archive)) {
557 int32 i = 0;
558 while (unarchiver.EnsureUnarchived("_views", i++) == B_OK)
560 unarchiver.EnsureUnarchived(kLayoutField);
562 } else {
563 BMessage msg;
564 for (int32 i = 0; archive->FindMessage("_views", i, &msg) == B_OK;
565 i++) {
566 BArchivable* object = instantiate_object(&msg);
567 if (BView* child = dynamic_cast<BView*>(object))
568 AddChild(child);
574 BArchivable*
575 BView::Instantiate(BMessage* data)
577 if (!validate_instantiation(data , "BView"))
578 return NULL;
580 return new(std::nothrow) BView(data);
584 status_t
585 BView::Archive(BMessage* data, bool deep) const
587 BArchiver archiver(data);
588 status_t ret = BHandler::Archive(data, deep);
590 if (ret != B_OK)
591 return ret;
593 if ((fState->archiving_flags & B_VIEW_FRAME_BIT) != 0)
594 ret = data->AddRect("_frame", Bounds().OffsetToCopy(fParentOffset));
596 if (ret == B_OK)
597 ret = data->AddInt32("_resize_mode", ResizingMode());
599 if (ret == B_OK)
600 ret = data->AddInt32("_flags", Flags());
602 if (ret == B_OK && (fState->archiving_flags & B_VIEW_EVENT_MASK_BIT) != 0) {
603 ret = data->AddInt32("_evmask", fEventMask);
604 if (ret == B_OK)
605 ret = data->AddInt32("_evmask", fEventOptions);
608 if (ret == B_OK && (fState->archiving_flags & B_VIEW_FONT_BIT) != 0) {
609 BFont font;
610 GetFont(&font);
612 font_family family;
613 font_style style;
614 font.GetFamilyAndStyle(&family, &style);
615 ret = data->AddString("_fname", family);
616 if (ret == B_OK)
617 ret = data->AddString("_fname", style);
618 if (ret == B_OK)
619 ret = data->AddFloat("_fflt", font.Size());
620 if (ret == B_OK)
621 ret = data->AddFloat("_fflt", font.Shear());
622 if (ret == B_OK)
623 ret = data->AddFloat("_fflt", font.Rotation());
626 // colors
627 if (ret == B_OK)
628 ret = data->AddInt32("_color", get_uint32_color(HighColor()));
629 if (ret == B_OK)
630 ret = data->AddInt32("_color", get_uint32_color(LowColor()));
631 if (ret == B_OK)
632 ret = data->AddInt32("_color", get_uint32_color(ViewColor()));
634 if (ret == B_OK)
635 ret = data->AddInt32("_uicolor", (int32)HighUIColor());
636 if (ret == B_OK)
637 ret = data->AddInt32("_uicolor", (int32)LowUIColor());
638 if (ret == B_OK)
639 ret = data->AddInt32("_uicolor", (int32)ViewUIColor());
641 if (ret == B_OK)
642 ret = data->AddFloat("_uitint", fState->which_high_color_tint);
643 if (ret == B_OK)
644 ret = data->AddFloat("_uitint", fState->which_low_color_tint);
645 if (ret == B_OK)
646 ret = data->AddFloat("_uitint", fState->which_view_color_tint);
648 // NOTE: we do not use this flag any more
649 // if ( 1 ){
650 // ret = data->AddInt32("_dbuf", 1);
651 // }
653 if (ret == B_OK && (fState->archiving_flags & B_VIEW_ORIGIN_BIT) != 0)
654 ret = data->AddPoint("_origin", Origin());
656 if (ret == B_OK && (fState->archiving_flags & B_VIEW_SCALE_BIT) != 0)
657 ret = data->AddFloat("_scale", Scale());
659 if (ret == B_OK && (fState->archiving_flags & B_VIEW_TRANSFORM_BIT) != 0) {
660 BAffineTransform transform = Transform();
661 ret = data->AddFlat("_transform", &transform);
664 if (ret == B_OK && (fState->archiving_flags & B_VIEW_PEN_SIZE_BIT) != 0)
665 ret = data->AddFloat("_psize", PenSize());
667 if (ret == B_OK && (fState->archiving_flags & B_VIEW_PEN_LOCATION_BIT) != 0)
668 ret = data->AddPoint("_ploc", PenLocation());
670 if (ret == B_OK && (fState->archiving_flags & B_VIEW_LINE_MODES_BIT) != 0) {
671 ret = data->AddInt16("_lmcapjoin", (int16)LineCapMode());
672 if (ret == B_OK)
673 ret = data->AddInt16("_lmcapjoin", (int16)LineJoinMode());
674 if (ret == B_OK)
675 ret = data->AddFloat("_lmmiter", LineMiterLimit());
678 if (ret == B_OK && (fState->archiving_flags & B_VIEW_FILL_RULE_BIT) != 0)
679 ret = data->AddInt16("_fillrule", (int16)FillRule());
681 if (ret == B_OK && (fState->archiving_flags & B_VIEW_BLENDING_BIT) != 0) {
682 source_alpha alphaSourceMode;
683 alpha_function alphaFunctionMode;
684 GetBlendingMode(&alphaSourceMode, &alphaFunctionMode);
686 ret = data->AddInt16("_blend", (int16)alphaSourceMode);
687 if (ret == B_OK)
688 ret = data->AddInt16("_blend", (int16)alphaFunctionMode);
691 if (ret == B_OK && (fState->archiving_flags & B_VIEW_DRAWING_MODE_BIT) != 0)
692 ret = data->AddInt32("_dmod", DrawingMode());
694 if (ret == B_OK)
695 ret = fLayoutData->AddDataToArchive(data);
697 if (ret == B_OK)
698 ret = data->AddInt16("_show", fShowLevel);
700 if (deep && ret == B_OK) {
701 for (BView* child = fFirstChild; child != NULL && ret == B_OK;
702 child = child->fNextSibling)
703 ret = archiver.AddArchivable("_views", child, deep);
705 if (ret == B_OK)
706 ret = archiver.AddArchivable(kLayoutField, GetLayout(), deep);
709 return archiver.Finish(ret);
713 status_t
714 BView::AllUnarchived(const BMessage* from)
716 BUnarchiver unarchiver(from);
717 status_t err = B_OK;
719 int32 count;
720 from->GetInfo("_views", NULL, &count);
722 for (int32 i = 0; err == B_OK && i < count; i++) {
723 BView* child;
724 err = unarchiver.FindObject<BView>("_views", i, child);
725 if (err == B_OK)
726 err = _AddChild(child, NULL) ? B_OK : B_ERROR;
729 if (err == B_OK) {
730 BLayout*& layout = fLayoutData->fLayout;
731 err = unarchiver.FindObject(kLayoutField, layout);
732 if (err == B_OK && layout) {
733 fFlags |= B_SUPPORTS_LAYOUT;
734 fLayoutData->fLayout->SetOwner(this);
738 return err;
742 status_t
743 BView::AllArchived(BMessage* into) const
745 return BHandler::AllArchived(into);
749 BView::~BView()
751 STRACE(("BView(%s)::~BView()\n", this->Name()));
753 if (fOwner != NULL) {
754 debugger("Trying to delete a view that belongs to a window. "
755 "Call RemoveSelf first.");
758 // we also delete all our children
760 BView* child = fFirstChild;
761 while (child) {
762 BView* nextChild = child->fNextSibling;
764 delete child;
765 child = nextChild;
768 SetLayout(NULL);
769 _RemoveLayoutItemsFromLayout(true);
771 delete fLayoutData;
773 _RemoveSelf();
775 if (fToolTip != NULL)
776 fToolTip->ReleaseReference();
778 if (fVerScroller != NULL)
779 fVerScroller->SetTarget((BView*)NULL);
780 if (fHorScroller != NULL)
781 fHorScroller->SetTarget((BView*)NULL);
783 SetName(NULL);
785 _RemoveCommArray();
786 delete fState;
790 BRect
791 BView::Bounds() const
793 _CheckLock();
795 if (fIsPrinting)
796 return fState->print_rect;
798 return fBounds;
802 void
803 BView::_ConvertToParent(BPoint* point, bool checkLock) const
805 if (!fParent)
806 return;
808 if (checkLock)
809 _CheckLock();
811 // - our scrolling offset
812 // + our bounds location within the parent
813 point->x += -fBounds.left + fParentOffset.x;
814 point->y += -fBounds.top + fParentOffset.y;
818 void
819 BView::ConvertToParent(BPoint* point) const
821 _ConvertToParent(point, true);
825 BPoint
826 BView::ConvertToParent(BPoint point) const
828 ConvertToParent(&point);
830 return point;
834 void
835 BView::_ConvertFromParent(BPoint* point, bool checkLock) const
837 if (!fParent)
838 return;
840 if (checkLock)
841 _CheckLock();
843 // - our bounds location within the parent
844 // + our scrolling offset
845 point->x += -fParentOffset.x + fBounds.left;
846 point->y += -fParentOffset.y + fBounds.top;
850 void
851 BView::ConvertFromParent(BPoint* point) const
853 _ConvertFromParent(point, true);
857 BPoint
858 BView::ConvertFromParent(BPoint point) const
860 ConvertFromParent(&point);
862 return point;
866 void
867 BView::ConvertToParent(BRect* rect) const
869 if (!fParent)
870 return;
872 _CheckLock();
874 // - our scrolling offset
875 // + our bounds location within the parent
876 rect->OffsetBy(-fBounds.left + fParentOffset.x,
877 -fBounds.top + fParentOffset.y);
881 BRect
882 BView::ConvertToParent(BRect rect) const
884 ConvertToParent(&rect);
886 return rect;
890 void
891 BView::ConvertFromParent(BRect* rect) const
893 if (!fParent)
894 return;
896 _CheckLock();
898 // - our bounds location within the parent
899 // + our scrolling offset
900 rect->OffsetBy(-fParentOffset.x + fBounds.left,
901 -fParentOffset.y + fBounds.top);
905 BRect
906 BView::ConvertFromParent(BRect rect) const
908 ConvertFromParent(&rect);
910 return rect;
914 void
915 BView::_ConvertToScreen(BPoint* point, bool checkLock) const
917 if (!fParent) {
918 if (fOwner)
919 fOwner->ConvertToScreen(point);
921 return;
924 if (checkLock)
925 _CheckOwnerLock();
927 _ConvertToParent(point, false);
928 fParent->_ConvertToScreen(point, false);
932 void
933 BView::ConvertToScreen(BPoint* point) const
935 _ConvertToScreen(point, true);
939 BPoint
940 BView::ConvertToScreen(BPoint point) const
942 ConvertToScreen(&point);
944 return point;
948 void
949 BView::_ConvertFromScreen(BPoint* point, bool checkLock) const
951 if (!fParent) {
952 if (fOwner)
953 fOwner->ConvertFromScreen(point);
955 return;
958 if (checkLock)
959 _CheckOwnerLock();
961 _ConvertFromParent(point, false);
962 fParent->_ConvertFromScreen(point, false);
966 void
967 BView::ConvertFromScreen(BPoint* point) const
969 _ConvertFromScreen(point, true);
973 BPoint
974 BView::ConvertFromScreen(BPoint point) const
976 ConvertFromScreen(&point);
978 return point;
982 void
983 BView::ConvertToScreen(BRect* rect) const
985 BPoint offset(0.0, 0.0);
986 ConvertToScreen(&offset);
987 rect->OffsetBy(offset);
991 BRect
992 BView::ConvertToScreen(BRect rect) const
994 ConvertToScreen(&rect);
996 return rect;
1000 void
1001 BView::ConvertFromScreen(BRect* rect) const
1003 BPoint offset(0.0, 0.0);
1004 ConvertFromScreen(&offset);
1005 rect->OffsetBy(offset);
1009 BRect
1010 BView::ConvertFromScreen(BRect rect) const
1012 ConvertFromScreen(&rect);
1014 return rect;
1018 uint32
1019 BView::Flags() const
1021 _CheckLock();
1022 return fFlags & ~_RESIZE_MASK_;
1026 void
1027 BView::SetFlags(uint32 flags)
1029 if (Flags() == flags)
1030 return;
1032 if (fOwner) {
1033 if (flags & B_PULSE_NEEDED) {
1034 _CheckLock();
1035 if (fOwner->fPulseRunner == NULL)
1036 fOwner->SetPulseRate(fOwner->PulseRate());
1039 uint32 changesFlags = flags ^ fFlags;
1040 if (changesFlags & (B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE
1041 | B_FRAME_EVENTS | B_SUBPIXEL_PRECISE)) {
1042 _CheckLockAndSwitchCurrent();
1044 fOwner->fLink->StartMessage(AS_VIEW_SET_FLAGS);
1045 fOwner->fLink->Attach<uint32>(flags);
1046 fOwner->fLink->Flush();
1050 /* Some useful info:
1051 fFlags is a unsigned long (32 bits)
1052 * bits 1-16 are used for BView's flags
1053 * bits 17-32 are used for BView' resize mask
1054 * _RESIZE_MASK_ is used for that. Look into View.h to see how
1055 it's defined
1057 fFlags = (flags & ~_RESIZE_MASK_) | (fFlags & _RESIZE_MASK_);
1059 fState->archiving_flags |= B_VIEW_FLAGS_BIT;
1063 BRect
1064 BView::Frame() const
1066 return Bounds().OffsetToCopy(fParentOffset.x, fParentOffset.y);
1070 void
1071 BView::Hide()
1073 if (fOwner && fShowLevel == 0) {
1074 _CheckLockAndSwitchCurrent();
1075 fOwner->fLink->StartMessage(AS_VIEW_HIDE);
1076 fOwner->fLink->Flush();
1078 fShowLevel++;
1080 if (fShowLevel == 1)
1081 _InvalidateParentLayout();
1085 void
1086 BView::Show()
1088 fShowLevel--;
1089 if (fOwner && fShowLevel == 0) {
1090 _CheckLockAndSwitchCurrent();
1091 fOwner->fLink->StartMessage(AS_VIEW_SHOW);
1092 fOwner->fLink->Flush();
1095 if (fShowLevel == 0)
1096 _InvalidateParentLayout();
1100 bool
1101 BView::IsFocus() const
1103 if (fOwner) {
1104 _CheckLock();
1105 return fOwner->CurrentFocus() == this;
1106 } else
1107 return false;
1111 bool
1112 BView::IsHidden(const BView* lookingFrom) const
1114 if (fShowLevel > 0)
1115 return true;
1117 // may we be egocentric?
1118 if (lookingFrom == this)
1119 return false;
1121 // we have the same visibility state as our
1122 // parent, if there is one
1123 if (fParent)
1124 return fParent->IsHidden(lookingFrom);
1126 // if we're the top view, and we're interested
1127 // in the "global" view, we're inheriting the
1128 // state of the window's visibility
1129 if (fOwner && lookingFrom == NULL)
1130 return fOwner->IsHidden();
1132 return false;
1136 bool
1137 BView::IsHidden() const
1139 return IsHidden(NULL);
1143 bool
1144 BView::IsPrinting() const
1146 return fIsPrinting;
1150 BPoint
1151 BView::LeftTop() const
1153 return Bounds().LeftTop();
1157 void
1158 BView::SetResizingMode(uint32 mode)
1160 if (fOwner) {
1161 _CheckLockAndSwitchCurrent();
1163 fOwner->fLink->StartMessage(AS_VIEW_RESIZE_MODE);
1164 fOwner->fLink->Attach<uint32>(mode);
1167 // look at SetFlags() for more info on the below line
1168 fFlags = (fFlags & ~_RESIZE_MASK_) | (mode & _RESIZE_MASK_);
1172 uint32
1173 BView::ResizingMode() const
1175 return fFlags & _RESIZE_MASK_;
1179 void
1180 BView::SetViewCursor(const BCursor* cursor, bool sync)
1182 if (cursor == NULL || fOwner == NULL)
1183 return;
1185 _CheckLock();
1187 ViewSetViewCursorInfo info;
1188 info.cursorToken = cursor->fServerToken;
1189 info.viewToken = _get_object_token_(this);
1190 info.sync = sync;
1192 BPrivate::AppServerLink link;
1193 link.StartMessage(AS_SET_VIEW_CURSOR);
1194 link.Attach<ViewSetViewCursorInfo>(info);
1196 if (sync) {
1197 // Make sure the server has processed the message.
1198 int32 code;
1199 link.FlushWithReply(code);
1204 void
1205 BView::Flush() const
1207 if (fOwner)
1208 fOwner->Flush();
1212 void
1213 BView::Sync() const
1215 _CheckOwnerLock();
1216 if (fOwner)
1217 fOwner->Sync();
1221 BWindow*
1222 BView::Window() const
1224 return fOwner;
1228 // #pragma mark - Hook Functions
1231 void
1232 BView::AttachedToWindow()
1234 // Hook function
1235 STRACE(("\tHOOK: BView(%s)::AttachedToWindow()\n", Name()));
1239 void
1240 BView::AllAttached()
1242 // Hook function
1243 STRACE(("\tHOOK: BView(%s)::AllAttached()\n", Name()));
1247 void
1248 BView::DetachedFromWindow()
1250 // Hook function
1251 STRACE(("\tHOOK: BView(%s)::DetachedFromWindow()\n", Name()));
1255 void
1256 BView::AllDetached()
1258 // Hook function
1259 STRACE(("\tHOOK: BView(%s)::AllDetached()\n", Name()));
1263 void
1264 BView::Draw(BRect updateRect)
1266 // Hook function
1267 STRACE(("\tHOOK: BView(%s)::Draw()\n", Name()));
1271 void
1272 BView::DrawAfterChildren(BRect updateRect)
1274 // Hook function
1275 STRACE(("\tHOOK: BView(%s)::DrawAfterChildren()\n", Name()));
1279 void
1280 BView::FrameMoved(BPoint newPosition)
1282 // Hook function
1283 STRACE(("\tHOOK: BView(%s)::FrameMoved()\n", Name()));
1287 void
1288 BView::FrameResized(float newWidth, float newHeight)
1290 // Hook function
1291 STRACE(("\tHOOK: BView(%s)::FrameResized()\n", Name()));
1295 void
1296 BView::GetPreferredSize(float* _width, float* _height)
1298 STRACE(("\tHOOK: BView(%s)::GetPreferredSize()\n", Name()));
1300 if (_width != NULL)
1301 *_width = fBounds.Width();
1302 if (_height != NULL)
1303 *_height = fBounds.Height();
1307 void
1308 BView::ResizeToPreferred()
1310 STRACE(("\tHOOK: BView(%s)::ResizeToPreferred()\n", Name()));
1312 float width;
1313 float height;
1314 GetPreferredSize(&width, &height);
1316 ResizeTo(width, height);
1320 void
1321 BView::KeyDown(const char* bytes, int32 numBytes)
1323 // Hook function
1324 STRACE(("\tHOOK: BView(%s)::KeyDown()\n", Name()));
1326 if (Window())
1327 Window()->_KeyboardNavigation();
1331 void
1332 BView::KeyUp(const char* bytes, int32 numBytes)
1334 // Hook function
1335 STRACE(("\tHOOK: BView(%s)::KeyUp()\n", Name()));
1339 void
1340 BView::MouseDown(BPoint where)
1342 // Hook function
1343 STRACE(("\tHOOK: BView(%s)::MouseDown()\n", Name()));
1347 void
1348 BView::MouseUp(BPoint where)
1350 // Hook function
1351 STRACE(("\tHOOK: BView(%s)::MouseUp()\n", Name()));
1355 void
1356 BView::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
1358 // Hook function
1359 STRACE(("\tHOOK: BView(%s)::MouseMoved()\n", Name()));
1363 void
1364 BView::Pulse()
1366 // Hook function
1367 STRACE(("\tHOOK: BView(%s)::Pulse()\n", Name()));
1371 void
1372 BView::TargetedByScrollView(BScrollView* scroll_view)
1374 // Hook function
1375 STRACE(("\tHOOK: BView(%s)::TargetedByScrollView()\n", Name()));
1379 void
1380 BView::WindowActivated(bool active)
1382 // Hook function
1383 STRACE(("\tHOOK: BView(%s)::WindowActivated()\n", Name()));
1387 // #pragma mark - Input Functions
1390 void
1391 BView::BeginRectTracking(BRect startRect, uint32 style)
1393 if (_CheckOwnerLockAndSwitchCurrent()) {
1394 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_RECT_TRACK);
1395 fOwner->fLink->Attach<BRect>(startRect);
1396 fOwner->fLink->Attach<uint32>(style);
1397 fOwner->fLink->Flush();
1402 void
1403 BView::EndRectTracking()
1405 if (_CheckOwnerLockAndSwitchCurrent()) {
1406 fOwner->fLink->StartMessage(AS_VIEW_END_RECT_TRACK);
1407 fOwner->fLink->Flush();
1412 void
1413 BView::DragMessage(BMessage* message, BRect dragRect, BHandler* replyTo)
1415 if (!message)
1416 return;
1418 _CheckOwnerLock();
1420 // calculate the offset
1421 BPoint offset;
1422 uint32 buttons;
1423 BMessage* current = fOwner->CurrentMessage();
1424 if (!current || current->FindPoint("be:view_where", &offset) != B_OK)
1425 GetMouse(&offset, &buttons, false);
1426 offset -= dragRect.LeftTop();
1428 if (!dragRect.IsValid()) {
1429 DragMessage(message, NULL, B_OP_BLEND, offset, replyTo);
1430 return;
1433 // TODO: that's not really what should happen - the app_server should take
1434 // the chance *NOT* to need to drag a whole bitmap around but just a frame.
1436 // create a drag bitmap for the rect
1437 BBitmap* bitmap = new(std::nothrow) BBitmap(dragRect, B_RGBA32);
1438 if (bitmap == NULL)
1439 return;
1441 uint32* bits = (uint32*)bitmap->Bits();
1442 uint32 bytesPerRow = bitmap->BytesPerRow();
1443 uint32 width = dragRect.IntegerWidth() + 1;
1444 uint32 height = dragRect.IntegerHeight() + 1;
1445 uint32 lastRow = (height - 1) * width;
1447 memset(bits, 0x00, height * bytesPerRow);
1449 // top
1450 for (uint32 i = 0; i < width; i += 2)
1451 bits[i] = 0xff000000;
1453 // bottom
1454 for (uint32 i = (height % 2 == 0 ? 1 : 0); i < width; i += 2)
1455 bits[lastRow + i] = 0xff000000;
1457 // left
1458 for (uint32 i = 0; i < lastRow; i += width * 2)
1459 bits[i] = 0xff000000;
1461 // right
1462 for (uint32 i = (width % 2 == 0 ? width : 0); i < lastRow; i += width * 2)
1463 bits[width - 1 + i] = 0xff000000;
1465 DragMessage(message, bitmap, B_OP_BLEND, offset, replyTo);
1469 void
1470 BView::DragMessage(BMessage* message, BBitmap* image, BPoint offset,
1471 BHandler* replyTo)
1473 DragMessage(message, image, B_OP_COPY, offset, replyTo);
1477 void
1478 BView::DragMessage(BMessage* message, BBitmap* image,
1479 drawing_mode dragMode, BPoint offset, BHandler* replyTo)
1481 if (message == NULL)
1482 return;
1484 if (image == NULL) {
1485 // TODO: workaround for drags without a bitmap - should not be necessary if
1486 // we move the rectangle dragging into the app_server
1487 image = new(std::nothrow) BBitmap(BRect(0, 0, 0, 0), B_RGBA32);
1488 if (image == NULL)
1489 return;
1492 if (replyTo == NULL)
1493 replyTo = this;
1495 if (replyTo->Looper() == NULL)
1496 debugger("DragMessage: warning - the Handler needs a looper");
1498 _CheckOwnerLock();
1500 if (!message->HasInt32("buttons")) {
1501 BMessage* msg = fOwner->CurrentMessage();
1502 uint32 buttons;
1504 if (msg == NULL
1505 || msg->FindInt32("buttons", (int32*)&buttons) != B_OK) {
1506 BPoint point;
1507 GetMouse(&point, &buttons, false);
1510 message->AddInt32("buttons", buttons);
1513 BMessage::Private privateMessage(message);
1514 privateMessage.SetReply(BMessenger(replyTo, replyTo->Looper()));
1516 int32 bufferSize = message->FlattenedSize();
1517 char* buffer = new(std::nothrow) char[bufferSize];
1518 if (buffer != NULL) {
1519 message->Flatten(buffer, bufferSize);
1521 fOwner->fLink->StartMessage(AS_VIEW_DRAG_IMAGE);
1522 fOwner->fLink->Attach<int32>(image->_ServerToken());
1523 fOwner->fLink->Attach<int32>((int32)dragMode);
1524 fOwner->fLink->Attach<BPoint>(offset);
1525 fOwner->fLink->Attach<int32>(bufferSize);
1526 fOwner->fLink->Attach(buffer, bufferSize);
1528 // we need to wait for the server
1529 // to actually process this message
1530 // before we can delete the bitmap
1531 int32 code;
1532 fOwner->fLink->FlushWithReply(code);
1534 delete [] buffer;
1535 } else {
1536 fprintf(stderr, "BView::DragMessage() - no memory to flatten drag "
1537 "message\n");
1540 delete image;
1544 void
1545 BView::GetMouse(BPoint* _location, uint32* _buttons, bool checkMessageQueue)
1547 if (_location == NULL && _buttons == NULL)
1548 return;
1550 _CheckOwnerLockAndSwitchCurrent();
1552 uint32 eventOptions = fEventOptions | fMouseEventOptions;
1553 bool noHistory = eventOptions & B_NO_POINTER_HISTORY;
1554 bool fullHistory = eventOptions & B_FULL_POINTER_HISTORY;
1556 if (checkMessageQueue && !noHistory) {
1557 Window()->UpdateIfNeeded();
1558 BMessageQueue* queue = Window()->MessageQueue();
1559 queue->Lock();
1561 // Look out for mouse update messages
1563 BMessage* message;
1564 for (int32 i = 0; (message = queue->FindMessage(i)) != NULL; i++) {
1565 switch (message->what) {
1566 case B_MOUSE_MOVED:
1567 case B_MOUSE_UP:
1568 case B_MOUSE_DOWN:
1569 bool deleteMessage;
1570 if (!Window()->_StealMouseMessage(message, deleteMessage))
1571 continue;
1573 if (!fullHistory && message->what == B_MOUSE_MOVED) {
1574 // Check if the message is too old. Some applications
1575 // check the message queue in such a way that mouse
1576 // messages *must* pile up. This check makes them work
1577 // as intended, although these applications could simply
1578 // use the version of BView::GetMouse() that does not
1579 // check the history. Also note that it isn't a problem
1580 // to delete the message in case there is not a newer
1581 // one. If we don't find a message in the queue, we will
1582 // just fall back to asking the app_sever directly. So
1583 // the imposed delay will not be a problem on slower
1584 // computers. This check also prevents another problem,
1585 // when the message that we use is *not* removed from
1586 // the queue. Subsequent calls to GetMouse() would find
1587 // this message over and over!
1588 bigtime_t eventTime;
1589 if (message->FindInt64("when", &eventTime) == B_OK
1590 && system_time() - eventTime > 10000) {
1591 // just discard the message
1592 if (deleteMessage)
1593 delete message;
1594 continue;
1597 if (_location != NULL)
1598 message->FindPoint("screen_where", _location);
1599 if (_buttons != NULL)
1600 message->FindInt32("buttons", (int32*)_buttons);
1601 queue->Unlock();
1602 // we need to hold the queue lock until here, because
1603 // the message might still be used for something else
1605 if (_location != NULL)
1606 ConvertFromScreen(_location);
1608 if (deleteMessage)
1609 delete message;
1611 return;
1614 queue->Unlock();
1617 // If no mouse update message has been found in the message queue,
1618 // we get the current mouse location and buttons from the app_server
1620 fOwner->fLink->StartMessage(AS_GET_MOUSE);
1622 int32 code;
1623 if (fOwner->fLink->FlushWithReply(code) == B_OK
1624 && code == B_OK) {
1625 BPoint location;
1626 uint32 buttons;
1627 fOwner->fLink->Read<BPoint>(&location);
1628 fOwner->fLink->Read<uint32>(&buttons);
1629 // TODO: ServerWindow replies with an int32 here
1631 ConvertFromScreen(&location);
1632 // TODO: in beos R5, location is already converted to the view
1633 // local coordinate system, so if an app checks the window message
1634 // queue by itself, it might not find what it expects.
1635 // NOTE: the fact that we have mouse coords in screen space in our
1636 // queue avoids the problem that messages already in the queue will
1637 // be outdated as soon as a window or even the view moves. The
1638 // second situation being quite common actually, also with regards
1639 // to scrolling. An app reading these messages would have to know
1640 // the locations of the window and view for each message...
1641 // otherwise it is potentially broken anyways.
1642 if (_location != NULL)
1643 *_location = location;
1644 if (_buttons != NULL)
1645 *_buttons = buttons;
1646 } else {
1647 if (_location != NULL)
1648 _location->Set(0, 0);
1649 if (_buttons != NULL)
1650 *_buttons = 0;
1655 void
1656 BView::MakeFocus(bool focus)
1658 if (fOwner == NULL)
1659 return;
1661 // TODO: If this view has focus and focus == false,
1662 // will there really be no other view with focus? No
1663 // cycling to the next one?
1664 BView* focusView = fOwner->CurrentFocus();
1665 if (focus) {
1666 // Unfocus a previous focus view
1667 if (focusView != NULL && focusView != this)
1668 focusView->MakeFocus(false);
1670 // if we want to make this view the current focus view
1671 fOwner->_SetFocus(this, true);
1672 } else {
1673 // we want to unfocus this view, but only if it actually has focus
1674 if (focusView == this)
1675 fOwner->_SetFocus(NULL, true);
1680 BScrollBar*
1681 BView::ScrollBar(orientation direction) const
1683 switch (direction) {
1684 case B_VERTICAL:
1685 return fVerScroller;
1687 case B_HORIZONTAL:
1688 return fHorScroller;
1690 default:
1691 return NULL;
1696 void
1697 BView::ScrollBy(float deltaX, float deltaY)
1699 ScrollTo(BPoint(fBounds.left + deltaX, fBounds.top + deltaY));
1703 void
1704 BView::ScrollTo(BPoint where)
1706 // scrolling by fractional values is not supported
1707 where.x = roundf(where.x);
1708 where.y = roundf(where.y);
1710 // no reason to process this further if no scroll is intended.
1711 if (where.x == fBounds.left && where.y == fBounds.top)
1712 return;
1714 // make sure scrolling is within valid bounds
1715 if (fHorScroller) {
1716 float min, max;
1717 fHorScroller->GetRange(&min, &max);
1719 if (where.x < min)
1720 where.x = min;
1721 else if (where.x > max)
1722 where.x = max;
1724 if (fVerScroller) {
1725 float min, max;
1726 fVerScroller->GetRange(&min, &max);
1728 if (where.y < min)
1729 where.y = min;
1730 else if (where.y > max)
1731 where.y = max;
1734 _CheckLockAndSwitchCurrent();
1736 float xDiff = where.x - fBounds.left;
1737 float yDiff = where.y - fBounds.top;
1739 // if we're attached to a window tell app_server about this change
1740 if (fOwner) {
1741 fOwner->fLink->StartMessage(AS_VIEW_SCROLL);
1742 fOwner->fLink->Attach<float>(xDiff);
1743 fOwner->fLink->Attach<float>(yDiff);
1745 fOwner->fLink->Flush();
1747 // fState->valid_flags &= ~B_VIEW_FRAME_BIT;
1750 // we modify our bounds rectangle by deltaX/deltaY coord units hor/ver.
1751 fBounds.OffsetTo(where.x, where.y);
1753 // then set the new values of the scrollbars
1754 if (fHorScroller && xDiff != 0.0)
1755 fHorScroller->SetValue(fBounds.left);
1756 if (fVerScroller && yDiff != 0.0)
1757 fVerScroller->SetValue(fBounds.top);
1762 status_t
1763 BView::SetEventMask(uint32 mask, uint32 options)
1765 if (fEventMask == mask && fEventOptions == options)
1766 return B_OK;
1768 // don't change the mask if it's zero and we've got options
1769 if (mask != 0 || options == 0)
1770 fEventMask = mask | (fEventMask & 0xffff0000);
1771 fEventOptions = options;
1773 fState->archiving_flags |= B_VIEW_EVENT_MASK_BIT;
1775 if (fOwner) {
1776 _CheckLockAndSwitchCurrent();
1778 fOwner->fLink->StartMessage(AS_VIEW_SET_EVENT_MASK);
1779 fOwner->fLink->Attach<uint32>(mask);
1780 fOwner->fLink->Attach<uint32>(options);
1781 fOwner->fLink->Flush();
1784 return B_OK;
1788 uint32
1789 BView::EventMask()
1791 return fEventMask;
1795 status_t
1796 BView::SetMouseEventMask(uint32 mask, uint32 options)
1798 // Just don't do anything if the view is not yet attached
1799 // or we were called outside of BView::MouseDown()
1800 if (fOwner != NULL
1801 && fOwner->CurrentMessage() != NULL
1802 && fOwner->CurrentMessage()->what == B_MOUSE_DOWN) {
1803 _CheckLockAndSwitchCurrent();
1804 fMouseEventOptions = options;
1806 fOwner->fLink->StartMessage(AS_VIEW_SET_MOUSE_EVENT_MASK);
1807 fOwner->fLink->Attach<uint32>(mask);
1808 fOwner->fLink->Attach<uint32>(options);
1809 fOwner->fLink->Flush();
1810 return B_OK;
1813 return B_ERROR;
1817 // #pragma mark - Graphic State Functions
1820 void
1821 BView::PushState()
1823 _CheckOwnerLockAndSwitchCurrent();
1825 fOwner->fLink->StartMessage(AS_VIEW_PUSH_STATE);
1827 // initialize origin, scale and transform, new states start "clean".
1828 fState->valid_flags |= B_VIEW_SCALE_BIT | B_VIEW_ORIGIN_BIT
1829 | B_VIEW_TRANSFORM_BIT;
1830 fState->scale = 1.0f;
1831 fState->origin.Set(0, 0);
1832 fState->transform.Reset();
1836 void
1837 BView::PopState()
1839 _CheckOwnerLockAndSwitchCurrent();
1841 fOwner->fLink->StartMessage(AS_VIEW_POP_STATE);
1842 _FlushIfNotInTransaction();
1844 // invalidate all flags (except those that are not part of pop/push)
1845 fState->valid_flags = B_VIEW_VIEW_COLOR_BIT;
1849 void
1850 BView::SetOrigin(BPoint where)
1852 SetOrigin(where.x, where.y);
1856 void
1857 BView::SetOrigin(float x, float y)
1859 if (fState->IsValid(B_VIEW_ORIGIN_BIT)
1860 && x == fState->origin.x && y == fState->origin.y)
1861 return;
1863 fState->origin.x = x;
1864 fState->origin.y = y;
1866 if (_CheckOwnerLockAndSwitchCurrent()) {
1867 fOwner->fLink->StartMessage(AS_VIEW_SET_ORIGIN);
1868 fOwner->fLink->Attach<float>(x);
1869 fOwner->fLink->Attach<float>(y);
1871 fState->valid_flags |= B_VIEW_ORIGIN_BIT;
1874 // our local coord system origin has changed, so when archiving we'll add
1875 // this too
1876 fState->archiving_flags |= B_VIEW_ORIGIN_BIT;
1880 BPoint
1881 BView::Origin() const
1883 if (!fState->IsValid(B_VIEW_ORIGIN_BIT)) {
1884 // we don't keep graphics state information, therefor
1885 // we need to ask the server for the origin after PopState()
1886 _CheckOwnerLockAndSwitchCurrent();
1888 fOwner->fLink->StartMessage(AS_VIEW_GET_ORIGIN);
1890 int32 code;
1891 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK)
1892 fOwner->fLink->Read<BPoint>(&fState->origin);
1894 fState->valid_flags |= B_VIEW_ORIGIN_BIT;
1897 return fState->origin;
1901 void
1902 BView::SetScale(float scale) const
1904 if (fState->IsValid(B_VIEW_SCALE_BIT) && scale == fState->scale)
1905 return;
1907 if (fOwner) {
1908 _CheckLockAndSwitchCurrent();
1910 fOwner->fLink->StartMessage(AS_VIEW_SET_SCALE);
1911 fOwner->fLink->Attach<float>(scale);
1913 fState->valid_flags |= B_VIEW_SCALE_BIT;
1916 fState->scale = scale;
1917 fState->archiving_flags |= B_VIEW_SCALE_BIT;
1921 float
1922 BView::Scale() const
1924 if (!fState->IsValid(B_VIEW_SCALE_BIT) && fOwner) {
1925 _CheckLockAndSwitchCurrent();
1927 fOwner->fLink->StartMessage(AS_VIEW_GET_SCALE);
1929 int32 code;
1930 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK)
1931 fOwner->fLink->Read<float>(&fState->scale);
1933 fState->valid_flags |= B_VIEW_SCALE_BIT;
1936 return fState->scale;
1940 void
1941 BView::SetTransform(BAffineTransform transform)
1943 if (fState->IsValid(B_VIEW_TRANSFORM_BIT) && transform == fState->transform)
1944 return;
1946 if (fOwner != NULL) {
1947 _CheckLockAndSwitchCurrent();
1949 fOwner->fLink->StartMessage(AS_VIEW_SET_TRANSFORM);
1950 fOwner->fLink->Attach<BAffineTransform>(transform);
1952 fState->valid_flags |= B_VIEW_TRANSFORM_BIT;
1955 fState->transform = transform;
1956 fState->archiving_flags |= B_VIEW_TRANSFORM_BIT;
1960 BAffineTransform
1961 BView::Transform() const
1963 if (!fState->IsValid(B_VIEW_TRANSFORM_BIT) && fOwner != NULL) {
1964 _CheckLockAndSwitchCurrent();
1966 fOwner->fLink->StartMessage(AS_VIEW_GET_TRANSFORM);
1968 int32 code;
1969 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK)
1970 fOwner->fLink->Read<BAffineTransform>(&fState->transform);
1972 fState->valid_flags |= B_VIEW_TRANSFORM_BIT;
1975 return fState->transform;
1979 void
1980 BView::TranslateBy(double x, double y)
1982 if (fOwner != NULL) {
1983 _CheckLockAndSwitchCurrent();
1985 fOwner->fLink->StartMessage(AS_VIEW_AFFINE_TRANSLATE);
1986 fOwner->fLink->Attach<double>(x);
1987 fOwner->fLink->Attach<double>(y);
1989 fState->valid_flags &= ~B_VIEW_TRANSFORM_BIT;
1992 fState->archiving_flags |= B_VIEW_TRANSFORM_BIT;
1996 void
1997 BView::ScaleBy(double x, double y)
1999 if (fOwner != NULL) {
2000 _CheckLockAndSwitchCurrent();
2002 fOwner->fLink->StartMessage(AS_VIEW_AFFINE_SCALE);
2003 fOwner->fLink->Attach<double>(x);
2004 fOwner->fLink->Attach<double>(y);
2006 fState->valid_flags &= ~B_VIEW_TRANSFORM_BIT;
2009 fState->archiving_flags |= B_VIEW_TRANSFORM_BIT;
2013 void
2014 BView::RotateBy(double angleRadians)
2016 if (fOwner != NULL) {
2017 _CheckLockAndSwitchCurrent();
2019 fOwner->fLink->StartMessage(AS_VIEW_AFFINE_ROTATE);
2020 fOwner->fLink->Attach<double>(angleRadians);
2022 fState->valid_flags &= ~B_VIEW_TRANSFORM_BIT;
2025 fState->archiving_flags |= B_VIEW_TRANSFORM_BIT;
2029 void
2030 BView::SetLineMode(cap_mode lineCap, join_mode lineJoin, float miterLimit)
2032 if (fState->IsValid(B_VIEW_LINE_MODES_BIT)
2033 && lineCap == fState->line_cap && lineJoin == fState->line_join
2034 && miterLimit == fState->miter_limit)
2035 return;
2037 if (fOwner) {
2038 _CheckLockAndSwitchCurrent();
2040 ViewSetLineModeInfo info;
2041 info.lineJoin = lineJoin;
2042 info.lineCap = lineCap;
2043 info.miterLimit = miterLimit;
2045 fOwner->fLink->StartMessage(AS_VIEW_SET_LINE_MODE);
2046 fOwner->fLink->Attach<ViewSetLineModeInfo>(info);
2048 fState->valid_flags |= B_VIEW_LINE_MODES_BIT;
2051 fState->line_cap = lineCap;
2052 fState->line_join = lineJoin;
2053 fState->miter_limit = miterLimit;
2055 fState->archiving_flags |= B_VIEW_LINE_MODES_BIT;
2059 join_mode
2060 BView::LineJoinMode() const
2062 // This will update the current state, if necessary
2063 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT))
2064 LineMiterLimit();
2066 return fState->line_join;
2070 cap_mode
2071 BView::LineCapMode() const
2073 // This will update the current state, if necessary
2074 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT))
2075 LineMiterLimit();
2077 return fState->line_cap;
2081 float
2082 BView::LineMiterLimit() const
2084 if (!fState->IsValid(B_VIEW_LINE_MODES_BIT) && fOwner) {
2085 _CheckLockAndSwitchCurrent();
2087 fOwner->fLink->StartMessage(AS_VIEW_GET_LINE_MODE);
2089 int32 code;
2090 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) {
2092 ViewSetLineModeInfo info;
2093 fOwner->fLink->Read<ViewSetLineModeInfo>(&info);
2095 fState->line_cap = info.lineCap;
2096 fState->line_join = info.lineJoin;
2097 fState->miter_limit = info.miterLimit;
2100 fState->valid_flags |= B_VIEW_LINE_MODES_BIT;
2103 return fState->miter_limit;
2107 void
2108 BView::SetFillRule(int32 fillRule)
2110 if (fState->IsValid(B_VIEW_FILL_RULE_BIT) && fillRule == fState->fill_rule)
2111 return;
2113 if (fOwner) {
2114 _CheckLockAndSwitchCurrent();
2116 fOwner->fLink->StartMessage(AS_VIEW_SET_FILL_RULE);
2117 fOwner->fLink->Attach<int32>(fillRule);
2119 fState->valid_flags |= B_VIEW_FILL_RULE_BIT;
2122 fState->fill_rule = fillRule;
2124 fState->archiving_flags |= B_VIEW_FILL_RULE_BIT;
2128 int32
2129 BView::FillRule() const
2131 if (!fState->IsValid(B_VIEW_FILL_RULE_BIT) && fOwner) {
2132 _CheckLockAndSwitchCurrent();
2134 fOwner->fLink->StartMessage(AS_VIEW_GET_FILL_RULE);
2136 int32 code;
2137 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) {
2139 int32 fillRule;
2140 fOwner->fLink->Read<int32>(&fillRule);
2142 fState->fill_rule = fillRule;
2145 fState->valid_flags |= B_VIEW_FILL_RULE_BIT;
2148 return fState->fill_rule;
2152 void
2153 BView::SetDrawingMode(drawing_mode mode)
2155 if (fState->IsValid(B_VIEW_DRAWING_MODE_BIT)
2156 && mode == fState->drawing_mode)
2157 return;
2159 if (fOwner) {
2160 _CheckLockAndSwitchCurrent();
2162 fOwner->fLink->StartMessage(AS_VIEW_SET_DRAWING_MODE);
2163 fOwner->fLink->Attach<int8>((int8)mode);
2165 fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT;
2168 fState->drawing_mode = mode;
2169 fState->archiving_flags |= B_VIEW_DRAWING_MODE_BIT;
2173 drawing_mode
2174 BView::DrawingMode() const
2176 if (!fState->IsValid(B_VIEW_DRAWING_MODE_BIT) && fOwner) {
2177 _CheckLockAndSwitchCurrent();
2179 fOwner->fLink->StartMessage(AS_VIEW_GET_DRAWING_MODE);
2181 int32 code;
2182 if (fOwner->fLink->FlushWithReply(code) == B_OK
2183 && code == B_OK) {
2184 int8 drawingMode;
2185 fOwner->fLink->Read<int8>(&drawingMode);
2187 fState->drawing_mode = (drawing_mode)drawingMode;
2188 fState->valid_flags |= B_VIEW_DRAWING_MODE_BIT;
2192 return fState->drawing_mode;
2196 void
2197 BView::SetBlendingMode(source_alpha sourceAlpha, alpha_function alphaFunction)
2199 if (fState->IsValid(B_VIEW_BLENDING_BIT)
2200 && sourceAlpha == fState->alpha_source_mode
2201 && alphaFunction == fState->alpha_function_mode)
2202 return;
2204 if (fOwner) {
2205 _CheckLockAndSwitchCurrent();
2207 ViewBlendingModeInfo info;
2208 info.sourceAlpha = sourceAlpha;
2209 info.alphaFunction = alphaFunction;
2211 fOwner->fLink->StartMessage(AS_VIEW_SET_BLENDING_MODE);
2212 fOwner->fLink->Attach<ViewBlendingModeInfo>(info);
2214 fState->valid_flags |= B_VIEW_BLENDING_BIT;
2217 fState->alpha_source_mode = sourceAlpha;
2218 fState->alpha_function_mode = alphaFunction;
2220 fState->archiving_flags |= B_VIEW_BLENDING_BIT;
2224 void
2225 BView::GetBlendingMode(source_alpha* _sourceAlpha,
2226 alpha_function* _alphaFunction) const
2228 if (!fState->IsValid(B_VIEW_BLENDING_BIT) && fOwner) {
2229 _CheckLockAndSwitchCurrent();
2231 fOwner->fLink->StartMessage(AS_VIEW_GET_BLENDING_MODE);
2233 int32 code;
2234 if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) {
2235 ViewBlendingModeInfo info;
2236 fOwner->fLink->Read<ViewBlendingModeInfo>(&info);
2238 fState->alpha_source_mode = info.sourceAlpha;
2239 fState->alpha_function_mode = info.alphaFunction;
2241 fState->valid_flags |= B_VIEW_BLENDING_BIT;
2245 if (_sourceAlpha)
2246 *_sourceAlpha = fState->alpha_source_mode;
2248 if (_alphaFunction)
2249 *_alphaFunction = fState->alpha_function_mode;
2253 void
2254 BView::MovePenTo(BPoint point)
2256 MovePenTo(point.x, point.y);
2260 void
2261 BView::MovePenTo(float x, float y)
2263 if (fState->IsValid(B_VIEW_PEN_LOCATION_BIT)
2264 && x == fState->pen_location.x && y == fState->pen_location.y)
2265 return;
2267 if (fOwner) {
2268 _CheckLockAndSwitchCurrent();
2270 fOwner->fLink->StartMessage(AS_VIEW_SET_PEN_LOC);
2271 fOwner->fLink->Attach<BPoint>(BPoint(x, y));
2273 fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT;
2276 fState->pen_location.x = x;
2277 fState->pen_location.y = y;
2279 fState->archiving_flags |= B_VIEW_PEN_LOCATION_BIT;
2283 void
2284 BView::MovePenBy(float x, float y)
2286 // this will update the pen location if necessary
2287 if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT))
2288 PenLocation();
2290 MovePenTo(fState->pen_location.x + x, fState->pen_location.y + y);
2294 BPoint
2295 BView::PenLocation() const
2297 if (!fState->IsValid(B_VIEW_PEN_LOCATION_BIT) && fOwner) {
2298 _CheckLockAndSwitchCurrent();
2300 fOwner->fLink->StartMessage(AS_VIEW_GET_PEN_LOC);
2302 int32 code;
2303 if (fOwner->fLink->FlushWithReply(code) == B_OK
2304 && code == B_OK) {
2305 fOwner->fLink->Read<BPoint>(&fState->pen_location);
2307 fState->valid_flags |= B_VIEW_PEN_LOCATION_BIT;
2311 return fState->pen_location;
2315 void
2316 BView::SetPenSize(float size)
2318 if (fState->IsValid(B_VIEW_PEN_SIZE_BIT) && size == fState->pen_size)
2319 return;
2321 if (fOwner) {
2322 _CheckLockAndSwitchCurrent();
2324 fOwner->fLink->StartMessage(AS_VIEW_SET_PEN_SIZE);
2325 fOwner->fLink->Attach<float>(size);
2327 fState->valid_flags |= B_VIEW_PEN_SIZE_BIT;
2330 fState->pen_size = size;
2331 fState->archiving_flags |= B_VIEW_PEN_SIZE_BIT;
2335 float
2336 BView::PenSize() const
2338 if (!fState->IsValid(B_VIEW_PEN_SIZE_BIT) && fOwner) {
2339 _CheckLockAndSwitchCurrent();
2341 fOwner->fLink->StartMessage(AS_VIEW_GET_PEN_SIZE);
2343 int32 code;
2344 if (fOwner->fLink->FlushWithReply(code) == B_OK
2345 && code == B_OK) {
2346 fOwner->fLink->Read<float>(&fState->pen_size);
2348 fState->valid_flags |= B_VIEW_PEN_SIZE_BIT;
2352 return fState->pen_size;
2356 void
2357 BView::SetHighColor(rgb_color color)
2359 SetHighUIColor(B_NO_COLOR);
2361 // are we up-to-date already?
2362 if (fState->IsValid(B_VIEW_HIGH_COLOR_BIT)
2363 && fState->high_color == color)
2364 return;
2366 if (fOwner) {
2367 _CheckLockAndSwitchCurrent();
2369 fOwner->fLink->StartMessage(AS_VIEW_SET_HIGH_COLOR);
2370 fOwner->fLink->Attach<rgb_color>(color);
2372 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT;
2375 fState->high_color = color;
2377 fState->archiving_flags |= B_VIEW_HIGH_COLOR_BIT;
2381 rgb_color
2382 BView::HighColor() const
2384 if (!fState->IsValid(B_VIEW_HIGH_COLOR_BIT) && fOwner) {
2385 _CheckLockAndSwitchCurrent();
2387 fOwner->fLink->StartMessage(AS_VIEW_GET_HIGH_COLOR);
2389 int32 code;
2390 if (fOwner->fLink->FlushWithReply(code) == B_OK
2391 && code == B_OK) {
2392 fOwner->fLink->Read<rgb_color>(&fState->high_color);
2394 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT;
2398 return fState->high_color;
2402 void
2403 BView::SetHighUIColor(color_which which, float tint)
2405 if (fState->IsValid(B_VIEW_WHICH_HIGH_COLOR_BIT)
2406 && fState->which_high_color == which
2407 && fState->which_high_color_tint == tint)
2408 return;
2410 if (fOwner != NULL) {
2411 _CheckLockAndSwitchCurrent();
2413 fOwner->fLink->StartMessage(AS_VIEW_SET_HIGH_UI_COLOR);
2414 fOwner->fLink->Attach<color_which>(which);
2415 fOwner->fLink->Attach<float>(tint);
2417 fState->valid_flags |= B_VIEW_WHICH_HIGH_COLOR_BIT;
2420 fState->which_high_color = which;
2421 fState->which_high_color_tint = tint;
2423 if (which != B_NO_COLOR) {
2424 fState->archiving_flags |= B_VIEW_WHICH_HIGH_COLOR_BIT;
2425 fState->archiving_flags &= ~B_VIEW_HIGH_COLOR_BIT;
2426 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT;
2428 fState->high_color = tint_color(ui_color(which), tint);
2429 } else {
2430 fState->valid_flags &= ~B_VIEW_HIGH_COLOR_BIT;
2431 fState->archiving_flags &= ~B_VIEW_WHICH_HIGH_COLOR_BIT;
2436 color_which
2437 BView::HighUIColor(float* tint) const
2439 if (!fState->IsValid(B_VIEW_WHICH_HIGH_COLOR_BIT)
2440 && fOwner != NULL) {
2441 _CheckLockAndSwitchCurrent();
2443 fOwner->fLink->StartMessage(AS_VIEW_GET_HIGH_UI_COLOR);
2445 int32 code;
2446 if (fOwner->fLink->FlushWithReply(code) == B_OK
2447 && code == B_OK) {
2448 fOwner->fLink->Read<color_which>(&fState->which_high_color);
2449 fOwner->fLink->Read<float>(&fState->which_high_color_tint);
2450 fOwner->fLink->Read<rgb_color>(&fState->high_color);
2452 fState->valid_flags |= B_VIEW_WHICH_HIGH_COLOR_BIT;
2453 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT;
2457 if (tint != NULL)
2458 *tint = fState->which_high_color_tint;
2460 return fState->which_high_color;
2464 void
2465 BView::SetLowColor(rgb_color color)
2467 SetLowUIColor(B_NO_COLOR);
2469 if (fState->IsValid(B_VIEW_LOW_COLOR_BIT)
2470 && fState->low_color == color)
2471 return;
2473 if (fOwner) {
2474 _CheckLockAndSwitchCurrent();
2476 fOwner->fLink->StartMessage(AS_VIEW_SET_LOW_COLOR);
2477 fOwner->fLink->Attach<rgb_color>(color);
2479 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT;
2482 fState->low_color = color;
2484 fState->archiving_flags |= B_VIEW_LOW_COLOR_BIT;
2488 rgb_color
2489 BView::LowColor() const
2491 if (!fState->IsValid(B_VIEW_LOW_COLOR_BIT) && fOwner) {
2492 _CheckLockAndSwitchCurrent();
2494 fOwner->fLink->StartMessage(AS_VIEW_GET_LOW_COLOR);
2496 int32 code;
2497 if (fOwner->fLink->FlushWithReply(code) == B_OK
2498 && code == B_OK) {
2499 fOwner->fLink->Read<rgb_color>(&fState->low_color);
2501 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT;
2505 return fState->low_color;
2509 void
2510 BView::SetLowUIColor(color_which which, float tint)
2512 if (fState->IsValid(B_VIEW_WHICH_LOW_COLOR_BIT)
2513 && fState->which_low_color == which
2514 && fState->which_low_color_tint == tint)
2515 return;
2517 if (fOwner != NULL) {
2518 _CheckLockAndSwitchCurrent();
2520 fOwner->fLink->StartMessage(AS_VIEW_SET_LOW_UI_COLOR);
2521 fOwner->fLink->Attach<color_which>(which);
2522 fOwner->fLink->Attach<float>(tint);
2524 fState->valid_flags |= B_VIEW_WHICH_LOW_COLOR_BIT;
2527 fState->which_low_color = which;
2528 fState->which_low_color_tint = tint;
2530 if (which != B_NO_COLOR) {
2531 fState->archiving_flags |= B_VIEW_WHICH_LOW_COLOR_BIT;
2532 fState->archiving_flags &= ~B_VIEW_LOW_COLOR_BIT;
2533 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT;
2535 fState->low_color = tint_color(ui_color(which), tint);
2536 } else {
2537 fState->valid_flags &= ~B_VIEW_LOW_COLOR_BIT;
2538 fState->archiving_flags &= ~B_VIEW_WHICH_LOW_COLOR_BIT;
2543 color_which
2544 BView::LowUIColor(float* tint) const
2546 if (!fState->IsValid(B_VIEW_WHICH_LOW_COLOR_BIT)
2547 && fOwner != NULL) {
2548 _CheckLockAndSwitchCurrent();
2550 fOwner->fLink->StartMessage(AS_VIEW_GET_LOW_UI_COLOR);
2552 int32 code;
2553 if (fOwner->fLink->FlushWithReply(code) == B_OK
2554 && code == B_OK) {
2555 fOwner->fLink->Read<color_which>(&fState->which_low_color);
2556 fOwner->fLink->Read<float>(&fState->which_low_color_tint);
2557 fOwner->fLink->Read<rgb_color>(&fState->low_color);
2559 fState->valid_flags |= B_VIEW_WHICH_LOW_COLOR_BIT;
2560 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT;
2564 if (tint != NULL)
2565 *tint = fState->which_low_color_tint;
2567 return fState->which_low_color;
2571 bool
2572 BView::HasDefaultColors() const
2574 // If we don't have any of these flags, then we have default colors
2575 uint32 testMask = B_VIEW_VIEW_COLOR_BIT | B_VIEW_HIGH_COLOR_BIT
2576 | B_VIEW_LOW_COLOR_BIT | B_VIEW_WHICH_VIEW_COLOR_BIT
2577 | B_VIEW_WHICH_HIGH_COLOR_BIT | B_VIEW_WHICH_LOW_COLOR_BIT;
2579 return (fState->archiving_flags & testMask) == 0;
2583 bool
2584 BView::HasSystemColors() const
2586 return fState->which_view_color == B_PANEL_BACKGROUND_COLOR
2587 && fState->which_high_color == B_PANEL_TEXT_COLOR
2588 && fState->which_low_color == B_PANEL_BACKGROUND_COLOR
2589 && fState->which_view_color_tint == B_NO_TINT
2590 && fState->which_high_color_tint == B_NO_TINT
2591 && fState->which_low_color_tint == B_NO_TINT;
2595 void
2596 BView::AdoptParentColors()
2598 AdoptViewColors(Parent());
2602 void
2603 BView::AdoptSystemColors()
2605 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
2606 SetLowUIColor(B_PANEL_BACKGROUND_COLOR);
2607 SetHighUIColor(B_PANEL_TEXT_COLOR);
2611 void
2612 BView::AdoptViewColors(BView* view)
2614 if (view == NULL || (view->Window() != NULL && !view->LockLooper()))
2615 return;
2617 float tint = B_NO_TINT;
2618 float viewTint = tint;
2619 color_which viewWhich = view->ViewUIColor(&viewTint);
2621 // View color
2622 if (viewWhich != B_NO_COLOR)
2623 SetViewUIColor(viewWhich, viewTint);
2624 else
2625 SetViewColor(view->ViewColor());
2627 // Low color
2628 color_which which = view->LowUIColor(&tint);
2629 if (which != B_NO_COLOR)
2630 SetLowUIColor(which, tint);
2631 else if (viewWhich != B_NO_COLOR)
2632 SetLowUIColor(viewWhich, viewTint);
2633 else
2634 SetLowColor(view->LowColor());
2636 // High color
2637 which = view->HighUIColor(&tint);
2638 if (which != B_NO_COLOR)
2639 SetHighUIColor(which, tint);
2640 else
2641 SetHighColor(view->HighColor());
2643 if (view->Window() != NULL)
2644 view->UnlockLooper();
2648 void
2649 BView::SetViewColor(rgb_color color)
2651 SetViewUIColor(B_NO_COLOR);
2653 if (fState->IsValid(B_VIEW_VIEW_COLOR_BIT)
2654 && fState->view_color == color)
2655 return;
2657 if (fOwner) {
2658 _CheckLockAndSwitchCurrent();
2660 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_COLOR);
2661 fOwner->fLink->Attach<rgb_color>(color);
2662 fOwner->fLink->Flush();
2664 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT;
2667 fState->view_color = color;
2669 fState->archiving_flags |= B_VIEW_VIEW_COLOR_BIT;
2673 rgb_color
2674 BView::ViewColor() const
2676 if (!fState->IsValid(B_VIEW_VIEW_COLOR_BIT) && fOwner) {
2677 _CheckLockAndSwitchCurrent();
2679 fOwner->fLink->StartMessage(AS_VIEW_GET_VIEW_COLOR);
2681 int32 code;
2682 if (fOwner->fLink->FlushWithReply(code) == B_OK
2683 && code == B_OK) {
2684 fOwner->fLink->Read<rgb_color>(&fState->view_color);
2686 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT;
2690 return fState->view_color;
2694 void
2695 BView::SetViewUIColor(color_which which, float tint)
2697 if (fState->IsValid(B_VIEW_WHICH_VIEW_COLOR_BIT)
2698 && fState->which_view_color == which
2699 && fState->which_view_color_tint == tint)
2700 return;
2702 if (fOwner != NULL) {
2703 _CheckLockAndSwitchCurrent();
2705 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_UI_COLOR);
2706 fOwner->fLink->Attach<color_which>(which);
2707 fOwner->fLink->Attach<float>(tint);
2709 fState->valid_flags |= B_VIEW_WHICH_VIEW_COLOR_BIT;
2712 fState->which_view_color = which;
2713 fState->which_view_color_tint = tint;
2715 if (which != B_NO_COLOR) {
2716 fState->archiving_flags |= B_VIEW_WHICH_VIEW_COLOR_BIT;
2717 fState->archiving_flags &= ~B_VIEW_VIEW_COLOR_BIT;
2718 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT;
2720 fState->view_color = tint_color(ui_color(which), tint);
2721 } else {
2722 fState->valid_flags &= ~B_VIEW_VIEW_COLOR_BIT;
2723 fState->archiving_flags &= ~B_VIEW_WHICH_VIEW_COLOR_BIT;
2726 if (!fState->IsValid(B_VIEW_WHICH_LOW_COLOR_BIT))
2727 SetLowUIColor(which, tint);
2731 color_which
2732 BView::ViewUIColor(float* tint) const
2734 if (!fState->IsValid(B_VIEW_WHICH_VIEW_COLOR_BIT)
2735 && fOwner != NULL) {
2736 _CheckLockAndSwitchCurrent();
2738 fOwner->fLink->StartMessage(AS_VIEW_GET_VIEW_UI_COLOR);
2740 int32 code;
2741 if (fOwner->fLink->FlushWithReply(code) == B_OK
2742 && code == B_OK) {
2743 fOwner->fLink->Read<color_which>(&fState->which_view_color);
2744 fOwner->fLink->Read<float>(&fState->which_view_color_tint);
2745 fOwner->fLink->Read<rgb_color>(&fState->view_color);
2747 fState->valid_flags |= B_VIEW_WHICH_VIEW_COLOR_BIT;
2748 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT;
2752 if (tint != NULL)
2753 *tint = fState->which_view_color_tint;
2755 return fState->which_view_color;
2759 void
2760 BView::ForceFontAliasing(bool enable)
2762 if (fState->IsValid(B_VIEW_FONT_ALIASING_BIT)
2763 && enable == fState->font_aliasing)
2764 return;
2766 if (fOwner) {
2767 _CheckLockAndSwitchCurrent();
2769 fOwner->fLink->StartMessage(AS_VIEW_PRINT_ALIASING);
2770 fOwner->fLink->Attach<bool>(enable);
2772 fState->valid_flags |= B_VIEW_FONT_ALIASING_BIT;
2775 fState->font_aliasing = enable;
2776 fState->archiving_flags |= B_VIEW_FONT_ALIASING_BIT;
2780 void
2781 BView::SetFont(const BFont* font, uint32 mask)
2783 if (!font || mask == 0)
2784 return;
2786 if (mask == B_FONT_ALL) {
2787 fState->font = *font;
2788 } else {
2789 // TODO: move this into a BFont method
2790 if (mask & B_FONT_FAMILY_AND_STYLE)
2791 fState->font.SetFamilyAndStyle(font->FamilyAndStyle());
2793 if (mask & B_FONT_SIZE)
2794 fState->font.SetSize(font->Size());
2796 if (mask & B_FONT_SHEAR)
2797 fState->font.SetShear(font->Shear());
2799 if (mask & B_FONT_ROTATION)
2800 fState->font.SetRotation(font->Rotation());
2802 if (mask & B_FONT_FALSE_BOLD_WIDTH)
2803 fState->font.SetFalseBoldWidth(font->FalseBoldWidth());
2805 if (mask & B_FONT_SPACING)
2806 fState->font.SetSpacing(font->Spacing());
2808 if (mask & B_FONT_ENCODING)
2809 fState->font.SetEncoding(font->Encoding());
2811 if (mask & B_FONT_FACE)
2812 fState->font.SetFace(font->Face());
2814 if (mask & B_FONT_FLAGS)
2815 fState->font.SetFlags(font->Flags());
2818 fState->font_flags |= mask;
2820 if (fOwner) {
2821 _CheckLockAndSwitchCurrent();
2823 fState->UpdateServerFontState(*fOwner->fLink);
2824 fState->valid_flags |= B_VIEW_FONT_BIT;
2827 fState->archiving_flags |= B_VIEW_FONT_BIT;
2828 // TODO: InvalidateLayout() here for convenience?
2832 void
2833 BView::GetFont(BFont* font) const
2835 if (!fState->IsValid(B_VIEW_FONT_BIT)) {
2836 // we don't keep graphics state information, therefor
2837 // we need to ask the server for the origin after PopState()
2838 _CheckOwnerLockAndSwitchCurrent();
2840 // TODO: add a font getter!
2841 fState->UpdateFrom(*fOwner->fLink);
2844 *font = fState->font;
2848 void
2849 BView::GetFontHeight(font_height* height) const
2851 fState->font.GetHeight(height);
2855 void
2856 BView::SetFontSize(float size)
2858 BFont font;
2859 font.SetSize(size);
2861 SetFont(&font, B_FONT_SIZE);
2865 float
2866 BView::StringWidth(const char* string) const
2868 return fState->font.StringWidth(string);
2872 float
2873 BView::StringWidth(const char* string, int32 length) const
2875 return fState->font.StringWidth(string, length);
2879 void
2880 BView::GetStringWidths(char* stringArray[], int32 lengthArray[],
2881 int32 numStrings, float widthArray[]) const
2883 fState->font.GetStringWidths(const_cast<const char**>(stringArray),
2884 const_cast<const int32*>(lengthArray), numStrings, widthArray);
2888 void
2889 BView::TruncateString(BString* string, uint32 mode, float width) const
2891 fState->font.TruncateString(string, mode, width);
2895 void
2896 BView::ClipToPicture(BPicture* picture, BPoint where, bool sync)
2898 _ClipToPicture(picture, where, false, sync);
2902 void
2903 BView::ClipToInversePicture(BPicture* picture, BPoint where, bool sync)
2905 _ClipToPicture(picture, where, true, sync);
2909 void
2910 BView::GetClippingRegion(BRegion* region) const
2912 if (!region)
2913 return;
2915 // NOTE: the client has no idea when the clipping in the server
2916 // changed, so it is always read from the server
2917 region->MakeEmpty();
2920 if (fOwner) {
2921 if (fIsPrinting && _CheckOwnerLock()) {
2922 region->Set(fState->print_rect);
2923 return;
2926 _CheckLockAndSwitchCurrent();
2927 fOwner->fLink->StartMessage(AS_VIEW_GET_CLIP_REGION);
2929 int32 code;
2930 if (fOwner->fLink->FlushWithReply(code) == B_OK
2931 && code == B_OK) {
2932 fOwner->fLink->ReadRegion(region);
2933 fState->valid_flags |= B_VIEW_CLIP_REGION_BIT;
2939 void
2940 BView::ConstrainClippingRegion(BRegion* region)
2942 if (_CheckOwnerLockAndSwitchCurrent()) {
2943 fOwner->fLink->StartMessage(AS_VIEW_SET_CLIP_REGION);
2945 if (region) {
2946 int32 count = region->CountRects();
2947 fOwner->fLink->Attach<int32>(count);
2948 if (count > 0)
2949 fOwner->fLink->AttachRegion(*region);
2950 } else {
2951 fOwner->fLink->Attach<int32>(-1);
2952 // '-1' means that in the app_server, there won't be any 'local'
2953 // clipping region (it will be NULL)
2956 _FlushIfNotInTransaction();
2958 fState->valid_flags &= ~B_VIEW_CLIP_REGION_BIT;
2959 fState->archiving_flags |= B_VIEW_CLIP_REGION_BIT;
2964 void
2965 BView::ClipToRect(BRect rect)
2967 _ClipToRect(rect, false);
2971 void
2972 BView::ClipToInverseRect(BRect rect)
2974 _ClipToRect(rect, true);
2978 void
2979 BView::ClipToShape(BShape* shape)
2981 _ClipToShape(shape, false);
2985 void
2986 BView::ClipToInverseShape(BShape* shape)
2988 _ClipToShape(shape, true);
2992 // #pragma mark - Drawing Functions
2995 void
2996 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect,
2997 uint32 options)
2999 if (bitmap == NULL || fOwner == NULL
3000 || !bitmapRect.IsValid() || !viewRect.IsValid())
3001 return;
3003 _CheckLockAndSwitchCurrent();
3005 ViewDrawBitmapInfo info;
3006 info.bitmapToken = bitmap->_ServerToken();
3007 info.options = options;
3008 info.viewRect = viewRect;
3009 info.bitmapRect = bitmapRect;
3011 fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP);
3012 fOwner->fLink->Attach<ViewDrawBitmapInfo>(info);
3014 _FlushIfNotInTransaction();
3018 void
3019 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect)
3021 DrawBitmapAsync(bitmap, bitmapRect, viewRect, 0);
3025 void
3026 BView::DrawBitmapAsync(const BBitmap* bitmap, BRect viewRect)
3028 if (bitmap && fOwner) {
3029 DrawBitmapAsync(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN),
3030 viewRect, 0);
3035 void
3036 BView::DrawBitmapAsync(const BBitmap* bitmap, BPoint where)
3038 if (bitmap == NULL || fOwner == NULL)
3039 return;
3041 _CheckLockAndSwitchCurrent();
3043 ViewDrawBitmapInfo info;
3044 info.bitmapToken = bitmap->_ServerToken();
3045 info.options = 0;
3046 info.bitmapRect = bitmap->Bounds().OffsetToCopy(B_ORIGIN);
3047 info.viewRect = info.bitmapRect.OffsetToCopy(where);
3049 fOwner->fLink->StartMessage(AS_VIEW_DRAW_BITMAP);
3050 fOwner->fLink->Attach<ViewDrawBitmapInfo>(info);
3052 _FlushIfNotInTransaction();
3056 void
3057 BView::DrawBitmapAsync(const BBitmap* bitmap)
3059 DrawBitmapAsync(bitmap, PenLocation());
3063 void
3064 BView::DrawBitmap(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect,
3065 uint32 options)
3067 if (fOwner) {
3068 DrawBitmapAsync(bitmap, bitmapRect, viewRect, options);
3069 Sync();
3074 void
3075 BView::DrawBitmap(const BBitmap* bitmap, BRect bitmapRect, BRect viewRect)
3077 if (fOwner) {
3078 DrawBitmapAsync(bitmap, bitmapRect, viewRect, 0);
3079 Sync();
3084 void
3085 BView::DrawBitmap(const BBitmap* bitmap, BRect viewRect)
3087 if (bitmap && fOwner) {
3088 DrawBitmap(bitmap, bitmap->Bounds().OffsetToCopy(B_ORIGIN), viewRect,
3094 void
3095 BView::DrawBitmap(const BBitmap* bitmap, BPoint where)
3097 if (fOwner) {
3098 DrawBitmapAsync(bitmap, where);
3099 Sync();
3104 void
3105 BView::DrawBitmap(const BBitmap* bitmap)
3107 DrawBitmap(bitmap, PenLocation());
3111 void
3112 BView::DrawChar(char c)
3114 DrawString(&c, 1, PenLocation());
3118 void
3119 BView::DrawChar(char c, BPoint location)
3121 DrawString(&c, 1, location);
3125 void
3126 BView::DrawString(const char* string, escapement_delta* delta)
3128 if (string == NULL)
3129 return;
3131 DrawString(string, strlen(string), PenLocation(), delta);
3135 void
3136 BView::DrawString(const char* string, BPoint location, escapement_delta* delta)
3138 if (string == NULL)
3139 return;
3141 DrawString(string, strlen(string), location, delta);
3145 void
3146 BView::DrawString(const char* string, int32 length, escapement_delta* delta)
3148 DrawString(string, length, PenLocation(), delta);
3152 void
3153 BView::DrawString(const char* string, int32 length, BPoint location,
3154 escapement_delta* delta)
3156 if (fOwner == NULL || string == NULL || length < 1)
3157 return;
3159 _CheckLockAndSwitchCurrent();
3161 ViewDrawStringInfo info;
3162 info.stringLength = length;
3163 info.location = location;
3164 if (delta != NULL)
3165 info.delta = *delta;
3167 // quite often delta will be NULL
3168 if (delta)
3169 fOwner->fLink->StartMessage(AS_DRAW_STRING_WITH_DELTA);
3170 else
3171 fOwner->fLink->StartMessage(AS_DRAW_STRING);
3173 fOwner->fLink->Attach<ViewDrawStringInfo>(info);
3174 fOwner->fLink->Attach(string, length);
3176 _FlushIfNotInTransaction();
3178 // this modifies our pen location, so we invalidate the flag.
3179 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT;
3183 void
3184 BView::DrawString(const char* string, const BPoint* locations,
3185 int32 locationCount)
3187 if (string == NULL)
3188 return;
3190 DrawString(string, strlen(string), locations, locationCount);
3194 void
3195 BView::DrawString(const char* string, int32 length, const BPoint* locations,
3196 int32 locationCount)
3198 if (fOwner == NULL || string == NULL || length < 1 || locations == NULL)
3199 return;
3201 _CheckLockAndSwitchCurrent();
3203 fOwner->fLink->StartMessage(AS_DRAW_STRING_WITH_OFFSETS);
3205 fOwner->fLink->Attach<int32>(length);
3206 fOwner->fLink->Attach<int32>(locationCount);
3207 fOwner->fLink->Attach(string, length);
3208 fOwner->fLink->Attach(locations, locationCount * sizeof(BPoint));
3210 _FlushIfNotInTransaction();
3212 // this modifies our pen location, so we invalidate the flag.
3213 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT;
3217 void
3218 BView::StrokeEllipse(BPoint center, float xRadius, float yRadius,
3219 ::pattern pattern)
3221 StrokeEllipse(BRect(center.x - xRadius, center.y - yRadius,
3222 center.x + xRadius, center.y + yRadius), pattern);
3226 void
3227 BView::StrokeEllipse(BRect rect, ::pattern pattern)
3229 if (fOwner == NULL)
3230 return;
3232 _CheckLockAndSwitchCurrent();
3233 _UpdatePattern(pattern);
3235 fOwner->fLink->StartMessage(AS_STROKE_ELLIPSE);
3236 fOwner->fLink->Attach<BRect>(rect);
3238 _FlushIfNotInTransaction();
3242 void
3243 BView::FillEllipse(BPoint center, float xRadius, float yRadius,
3244 ::pattern pattern)
3246 FillEllipse(BRect(center.x - xRadius, center.y - yRadius,
3247 center.x + xRadius, center.y + yRadius), pattern);
3251 void
3252 BView::FillEllipse(BPoint center, float xRadius, float yRadius,
3253 const BGradient& gradient)
3255 FillEllipse(BRect(center.x - xRadius, center.y - yRadius,
3256 center.x + xRadius, center.y + yRadius), gradient);
3260 void
3261 BView::FillEllipse(BRect rect, ::pattern pattern)
3263 if (fOwner == NULL)
3264 return;
3266 _CheckLockAndSwitchCurrent();
3267 _UpdatePattern(pattern);
3269 fOwner->fLink->StartMessage(AS_FILL_ELLIPSE);
3270 fOwner->fLink->Attach<BRect>(rect);
3272 _FlushIfNotInTransaction();
3276 void
3277 BView::FillEllipse(BRect rect, const BGradient& gradient)
3279 if (fOwner == NULL)
3280 return;
3282 _CheckLockAndSwitchCurrent();
3284 fOwner->fLink->StartMessage(AS_FILL_ELLIPSE_GRADIENT);
3285 fOwner->fLink->Attach<BRect>(rect);
3286 fOwner->fLink->AttachGradient(gradient);
3288 _FlushIfNotInTransaction();
3292 void
3293 BView::StrokeArc(BPoint center, float xRadius, float yRadius, float startAngle,
3294 float arcAngle, ::pattern pattern)
3296 StrokeArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius,
3297 center.y + yRadius), startAngle, arcAngle, pattern);
3301 void
3302 BView::StrokeArc(BRect rect, float startAngle, float arcAngle,
3303 ::pattern pattern)
3305 if (fOwner == NULL)
3306 return;
3308 _CheckLockAndSwitchCurrent();
3309 _UpdatePattern(pattern);
3311 fOwner->fLink->StartMessage(AS_STROKE_ARC);
3312 fOwner->fLink->Attach<BRect>(rect);
3313 fOwner->fLink->Attach<float>(startAngle);
3314 fOwner->fLink->Attach<float>(arcAngle);
3316 _FlushIfNotInTransaction();
3320 void
3321 BView::FillArc(BPoint center,float xRadius, float yRadius, float startAngle,
3322 float arcAngle, ::pattern pattern)
3324 FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius,
3325 center.y + yRadius), startAngle, arcAngle, pattern);
3329 void
3330 BView::FillArc(BPoint center,float xRadius, float yRadius, float startAngle,
3331 float arcAngle, const BGradient& gradient)
3333 FillArc(BRect(center.x - xRadius, center.y - yRadius, center.x + xRadius,
3334 center.y + yRadius), startAngle, arcAngle, gradient);
3338 void
3339 BView::FillArc(BRect rect, float startAngle, float arcAngle,
3340 ::pattern pattern)
3342 if (fOwner == NULL)
3343 return;
3345 _CheckLockAndSwitchCurrent();
3346 _UpdatePattern(pattern);
3348 fOwner->fLink->StartMessage(AS_FILL_ARC);
3349 fOwner->fLink->Attach<BRect>(rect);
3350 fOwner->fLink->Attach<float>(startAngle);
3351 fOwner->fLink->Attach<float>(arcAngle);
3353 _FlushIfNotInTransaction();
3357 void
3358 BView::FillArc(BRect rect, float startAngle, float arcAngle,
3359 const BGradient& gradient)
3361 if (fOwner == NULL)
3362 return;
3364 _CheckLockAndSwitchCurrent();
3366 fOwner->fLink->StartMessage(AS_FILL_ARC_GRADIENT);
3367 fOwner->fLink->Attach<BRect>(rect);
3368 fOwner->fLink->Attach<float>(startAngle);
3369 fOwner->fLink->Attach<float>(arcAngle);
3370 fOwner->fLink->AttachGradient(gradient);
3372 _FlushIfNotInTransaction();
3376 void
3377 BView::StrokeBezier(BPoint* controlPoints, ::pattern pattern)
3379 if (fOwner == NULL)
3380 return;
3382 _CheckLockAndSwitchCurrent();
3383 _UpdatePattern(pattern);
3385 fOwner->fLink->StartMessage(AS_STROKE_BEZIER);
3386 fOwner->fLink->Attach<BPoint>(controlPoints[0]);
3387 fOwner->fLink->Attach<BPoint>(controlPoints[1]);
3388 fOwner->fLink->Attach<BPoint>(controlPoints[2]);
3389 fOwner->fLink->Attach<BPoint>(controlPoints[3]);
3391 _FlushIfNotInTransaction();
3395 void
3396 BView::FillBezier(BPoint* controlPoints, ::pattern pattern)
3398 if (fOwner == NULL)
3399 return;
3401 _CheckLockAndSwitchCurrent();
3402 _UpdatePattern(pattern);
3404 fOwner->fLink->StartMessage(AS_FILL_BEZIER);
3405 fOwner->fLink->Attach<BPoint>(controlPoints[0]);
3406 fOwner->fLink->Attach<BPoint>(controlPoints[1]);
3407 fOwner->fLink->Attach<BPoint>(controlPoints[2]);
3408 fOwner->fLink->Attach<BPoint>(controlPoints[3]);
3410 _FlushIfNotInTransaction();
3414 void
3415 BView::FillBezier(BPoint* controlPoints, const BGradient& gradient)
3417 if (fOwner == NULL)
3418 return;
3420 _CheckLockAndSwitchCurrent();
3422 fOwner->fLink->StartMessage(AS_FILL_BEZIER_GRADIENT);
3423 fOwner->fLink->Attach<BPoint>(controlPoints[0]);
3424 fOwner->fLink->Attach<BPoint>(controlPoints[1]);
3425 fOwner->fLink->Attach<BPoint>(controlPoints[2]);
3426 fOwner->fLink->Attach<BPoint>(controlPoints[3]);
3427 fOwner->fLink->AttachGradient(gradient);
3429 _FlushIfNotInTransaction();
3433 void
3434 BView::StrokePolygon(const BPolygon* polygon, bool closed, ::pattern pattern)
3436 if (polygon == NULL)
3437 return;
3439 StrokePolygon(polygon->fPoints, polygon->fCount, polygon->Frame(), closed,
3440 pattern);
3444 void
3445 BView::StrokePolygon(const BPoint* pointArray, int32 numPoints, bool closed,
3446 ::pattern pattern)
3448 BPolygon polygon(pointArray, numPoints);
3450 StrokePolygon(polygon.fPoints, polygon.fCount, polygon.Frame(), closed,
3451 pattern);
3455 void
3456 BView::StrokePolygon(const BPoint* pointArray, int32 numPoints, BRect bounds,
3457 bool closed, ::pattern pattern)
3459 if (pointArray == NULL
3460 || numPoints <= 1
3461 || fOwner == NULL)
3462 return;
3464 _CheckLockAndSwitchCurrent();
3465 _UpdatePattern(pattern);
3467 BPolygon polygon(pointArray, numPoints);
3468 polygon.MapTo(polygon.Frame(), bounds);
3470 if (fOwner->fLink->StartMessage(AS_STROKE_POLYGON,
3471 polygon.fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(bool)
3472 + sizeof(int32)) == B_OK) {
3473 fOwner->fLink->Attach<BRect>(polygon.Frame());
3474 fOwner->fLink->Attach<bool>(closed);
3475 fOwner->fLink->Attach<int32>(polygon.fCount);
3476 fOwner->fLink->Attach(polygon.fPoints, polygon.fCount * sizeof(BPoint));
3478 _FlushIfNotInTransaction();
3479 } else {
3480 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n");
3485 void
3486 BView::FillPolygon(const BPolygon* polygon, ::pattern pattern)
3488 if (polygon == NULL
3489 || polygon->fCount <= 2
3490 || fOwner == NULL)
3491 return;
3493 _CheckLockAndSwitchCurrent();
3494 _UpdatePattern(pattern);
3496 if (fOwner->fLink->StartMessage(AS_FILL_POLYGON,
3497 polygon->fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(int32))
3498 == B_OK) {
3499 fOwner->fLink->Attach<BRect>(polygon->Frame());
3500 fOwner->fLink->Attach<int32>(polygon->fCount);
3501 fOwner->fLink->Attach(polygon->fPoints,
3502 polygon->fCount * sizeof(BPoint));
3504 _FlushIfNotInTransaction();
3505 } else {
3506 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n");
3511 void
3512 BView::FillPolygon(const BPolygon* polygon, const BGradient& gradient)
3514 if (polygon == NULL
3515 || polygon->fCount <= 2
3516 || fOwner == NULL)
3517 return;
3519 _CheckLockAndSwitchCurrent();
3521 if (fOwner->fLink->StartMessage(AS_FILL_POLYGON_GRADIENT,
3522 polygon->fCount * sizeof(BPoint) + sizeof(BRect) + sizeof(int32))
3523 == B_OK) {
3524 fOwner->fLink->Attach<BRect>(polygon->Frame());
3525 fOwner->fLink->Attach<int32>(polygon->fCount);
3526 fOwner->fLink->Attach(polygon->fPoints,
3527 polygon->fCount * sizeof(BPoint));
3528 fOwner->fLink->AttachGradient(gradient);
3530 _FlushIfNotInTransaction();
3531 } else {
3532 fprintf(stderr, "ERROR: Can't send polygon to app_server!\n");
3537 void
3538 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, ::pattern pattern)
3540 if (pointArray == NULL)
3541 return;
3543 BPolygon polygon(pointArray, numPoints);
3544 FillPolygon(&polygon, pattern);
3548 void
3549 BView::FillPolygon(const BPoint* pointArray, int32 numPoints,
3550 const BGradient& gradient)
3552 if (pointArray == NULL)
3553 return;
3555 BPolygon polygon(pointArray, numPoints);
3556 FillPolygon(&polygon, gradient);
3560 void
3561 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, BRect bounds,
3562 ::pattern pattern)
3564 if (pointArray == NULL)
3565 return;
3567 BPolygon polygon(pointArray, numPoints);
3569 polygon.MapTo(polygon.Frame(), bounds);
3570 FillPolygon(&polygon, pattern);
3574 void
3575 BView::FillPolygon(const BPoint* pointArray, int32 numPoints, BRect bounds,
3576 const BGradient& gradient)
3578 if (pointArray == NULL)
3579 return;
3581 BPolygon polygon(pointArray, numPoints);
3583 polygon.MapTo(polygon.Frame(), bounds);
3584 FillPolygon(&polygon, gradient);
3588 void
3589 BView::StrokeRect(BRect rect, ::pattern pattern)
3591 if (fOwner == NULL)
3592 return;
3594 _CheckLockAndSwitchCurrent();
3595 _UpdatePattern(pattern);
3597 fOwner->fLink->StartMessage(AS_STROKE_RECT);
3598 fOwner->fLink->Attach<BRect>(rect);
3600 _FlushIfNotInTransaction();
3604 void
3605 BView::FillRect(BRect rect, ::pattern pattern)
3607 if (fOwner == NULL)
3608 return;
3610 // NOTE: ensuring compatibility with R5,
3611 // invalid rects are not filled, they are stroked though!
3612 if (!rect.IsValid())
3613 return;
3615 _CheckLockAndSwitchCurrent();
3616 _UpdatePattern(pattern);
3618 fOwner->fLink->StartMessage(AS_FILL_RECT);
3619 fOwner->fLink->Attach<BRect>(rect);
3621 _FlushIfNotInTransaction();
3625 void
3626 BView::FillRect(BRect rect, const BGradient& gradient)
3628 if (fOwner == NULL)
3629 return;
3631 // NOTE: ensuring compatibility with R5,
3632 // invalid rects are not filled, they are stroked though!
3633 if (!rect.IsValid())
3634 return;
3636 _CheckLockAndSwitchCurrent();
3638 fOwner->fLink->StartMessage(AS_FILL_RECT_GRADIENT);
3639 fOwner->fLink->Attach<BRect>(rect);
3640 fOwner->fLink->AttachGradient(gradient);
3642 _FlushIfNotInTransaction();
3646 void
3647 BView::StrokeRoundRect(BRect rect, float xRadius, float yRadius,
3648 ::pattern pattern)
3650 if (fOwner == NULL)
3651 return;
3653 _CheckLockAndSwitchCurrent();
3654 _UpdatePattern(pattern);
3656 fOwner->fLink->StartMessage(AS_STROKE_ROUNDRECT);
3657 fOwner->fLink->Attach<BRect>(rect);
3658 fOwner->fLink->Attach<float>(xRadius);
3659 fOwner->fLink->Attach<float>(yRadius);
3661 _FlushIfNotInTransaction();
3665 void
3666 BView::FillRoundRect(BRect rect, float xRadius, float yRadius,
3667 ::pattern pattern)
3669 if (fOwner == NULL)
3670 return;
3672 _CheckLockAndSwitchCurrent();
3674 _UpdatePattern(pattern);
3676 fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT);
3677 fOwner->fLink->Attach<BRect>(rect);
3678 fOwner->fLink->Attach<float>(xRadius);
3679 fOwner->fLink->Attach<float>(yRadius);
3681 _FlushIfNotInTransaction();
3685 void
3686 BView::FillRoundRect(BRect rect, float xRadius, float yRadius,
3687 const BGradient& gradient)
3689 if (fOwner == NULL)
3690 return;
3692 _CheckLockAndSwitchCurrent();
3694 fOwner->fLink->StartMessage(AS_FILL_ROUNDRECT_GRADIENT);
3695 fOwner->fLink->Attach<BRect>(rect);
3696 fOwner->fLink->Attach<float>(xRadius);
3697 fOwner->fLink->Attach<float>(yRadius);
3698 fOwner->fLink->AttachGradient(gradient);
3700 _FlushIfNotInTransaction();
3704 void
3705 BView::FillRegion(BRegion* region, ::pattern pattern)
3707 if (region == NULL || fOwner == NULL)
3708 return;
3710 _CheckLockAndSwitchCurrent();
3712 _UpdatePattern(pattern);
3714 fOwner->fLink->StartMessage(AS_FILL_REGION);
3715 fOwner->fLink->AttachRegion(*region);
3717 _FlushIfNotInTransaction();
3721 void
3722 BView::FillRegion(BRegion* region, const BGradient& gradient)
3724 if (region == NULL || fOwner == NULL)
3725 return;
3727 _CheckLockAndSwitchCurrent();
3729 fOwner->fLink->StartMessage(AS_FILL_REGION_GRADIENT);
3730 fOwner->fLink->AttachRegion(*region);
3731 fOwner->fLink->AttachGradient(gradient);
3733 _FlushIfNotInTransaction();
3737 void
3738 BView::StrokeTriangle(BPoint point1, BPoint point2, BPoint point3, BRect bounds,
3739 ::pattern pattern)
3741 if (fOwner == NULL)
3742 return;
3744 _CheckLockAndSwitchCurrent();
3746 _UpdatePattern(pattern);
3748 fOwner->fLink->StartMessage(AS_STROKE_TRIANGLE);
3749 fOwner->fLink->Attach<BPoint>(point1);
3750 fOwner->fLink->Attach<BPoint>(point2);
3751 fOwner->fLink->Attach<BPoint>(point3);
3752 fOwner->fLink->Attach<BRect>(bounds);
3754 _FlushIfNotInTransaction();
3758 void
3759 BView::StrokeTriangle(BPoint point1, BPoint point2, BPoint point3,
3760 ::pattern pattern)
3762 if (fOwner) {
3763 // we construct the smallest rectangle that contains the 3 points
3764 // for the 1st point
3765 BRect bounds(point1, point1);
3767 // for the 2nd point
3768 if (point2.x < bounds.left)
3769 bounds.left = point2.x;
3771 if (point2.y < bounds.top)
3772 bounds.top = point2.y;
3774 if (point2.x > bounds.right)
3775 bounds.right = point2.x;
3777 if (point2.y > bounds.bottom)
3778 bounds.bottom = point2.y;
3780 // for the 3rd point
3781 if (point3.x < bounds.left)
3782 bounds.left = point3.x;
3784 if (point3.y < bounds.top)
3785 bounds.top = point3.y;
3787 if (point3.x > bounds.right)
3788 bounds.right = point3.x;
3790 if (point3.y > bounds.bottom)
3791 bounds.bottom = point3.y;
3793 StrokeTriangle(point1, point2, point3, bounds, pattern);
3798 void
3799 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3,
3800 ::pattern pattern)
3802 if (fOwner) {
3803 // we construct the smallest rectangle that contains the 3 points
3804 // for the 1st point
3805 BRect bounds(point1, point1);
3807 // for the 2nd point
3808 if (point2.x < bounds.left)
3809 bounds.left = point2.x;
3811 if (point2.y < bounds.top)
3812 bounds.top = point2.y;
3814 if (point2.x > bounds.right)
3815 bounds.right = point2.x;
3817 if (point2.y > bounds.bottom)
3818 bounds.bottom = point2.y;
3820 // for the 3rd point
3821 if (point3.x < bounds.left)
3822 bounds.left = point3.x;
3824 if (point3.y < bounds.top)
3825 bounds.top = point3.y;
3827 if (point3.x > bounds.right)
3828 bounds.right = point3.x;
3830 if (point3.y > bounds.bottom)
3831 bounds.bottom = point3.y;
3833 FillTriangle(point1, point2, point3, bounds, pattern);
3838 void
3839 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3,
3840 const BGradient& gradient)
3842 if (fOwner) {
3843 // we construct the smallest rectangle that contains the 3 points
3844 // for the 1st point
3845 BRect bounds(point1, point1);
3847 // for the 2nd point
3848 if (point2.x < bounds.left)
3849 bounds.left = point2.x;
3851 if (point2.y < bounds.top)
3852 bounds.top = point2.y;
3854 if (point2.x > bounds.right)
3855 bounds.right = point2.x;
3857 if (point2.y > bounds.bottom)
3858 bounds.bottom = point2.y;
3860 // for the 3rd point
3861 if (point3.x < bounds.left)
3862 bounds.left = point3.x;
3864 if (point3.y < bounds.top)
3865 bounds.top = point3.y;
3867 if (point3.x > bounds.right)
3868 bounds.right = point3.x;
3870 if (point3.y > bounds.bottom)
3871 bounds.bottom = point3.y;
3873 FillTriangle(point1, point2, point3, bounds, gradient);
3878 void
3879 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3,
3880 BRect bounds, ::pattern pattern)
3882 if (fOwner == NULL)
3883 return;
3885 _CheckLockAndSwitchCurrent();
3886 _UpdatePattern(pattern);
3888 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE);
3889 fOwner->fLink->Attach<BPoint>(point1);
3890 fOwner->fLink->Attach<BPoint>(point2);
3891 fOwner->fLink->Attach<BPoint>(point3);
3892 fOwner->fLink->Attach<BRect>(bounds);
3894 _FlushIfNotInTransaction();
3898 void
3899 BView::FillTriangle(BPoint point1, BPoint point2, BPoint point3, BRect bounds,
3900 const BGradient& gradient)
3902 if (fOwner == NULL)
3903 return;
3905 _CheckLockAndSwitchCurrent();
3906 fOwner->fLink->StartMessage(AS_FILL_TRIANGLE_GRADIENT);
3907 fOwner->fLink->Attach<BPoint>(point1);
3908 fOwner->fLink->Attach<BPoint>(point2);
3909 fOwner->fLink->Attach<BPoint>(point3);
3910 fOwner->fLink->Attach<BRect>(bounds);
3911 fOwner->fLink->AttachGradient(gradient);
3913 _FlushIfNotInTransaction();
3917 void
3918 BView::StrokeLine(BPoint toPoint, ::pattern pattern)
3920 StrokeLine(PenLocation(), toPoint, pattern);
3924 void
3925 BView::StrokeLine(BPoint start, BPoint end, ::pattern pattern)
3927 if (fOwner == NULL)
3928 return;
3930 _CheckLockAndSwitchCurrent();
3931 _UpdatePattern(pattern);
3933 ViewStrokeLineInfo info;
3934 info.startPoint = start;
3935 info.endPoint = end;
3937 fOwner->fLink->StartMessage(AS_STROKE_LINE);
3938 fOwner->fLink->Attach<ViewStrokeLineInfo>(info);
3940 _FlushIfNotInTransaction();
3942 // this modifies our pen location, so we invalidate the flag.
3943 fState->valid_flags &= ~B_VIEW_PEN_LOCATION_BIT;
3947 void
3948 BView::StrokeShape(BShape* shape, ::pattern pattern)
3950 if (shape == NULL || fOwner == NULL)
3951 return;
3953 shape_data* sd = (shape_data*)shape->fPrivateData;
3954 if (sd->opCount == 0 || sd->ptCount == 0)
3955 return;
3957 _CheckLockAndSwitchCurrent();
3958 _UpdatePattern(pattern);
3960 fOwner->fLink->StartMessage(AS_STROKE_SHAPE);
3961 fOwner->fLink->Attach<BRect>(shape->Bounds());
3962 fOwner->fLink->Attach<int32>(sd->opCount);
3963 fOwner->fLink->Attach<int32>(sd->ptCount);
3964 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(uint32));
3965 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint));
3967 _FlushIfNotInTransaction();
3971 void
3972 BView::FillShape(BShape* shape, ::pattern pattern)
3974 if (shape == NULL || fOwner == NULL)
3975 return;
3977 shape_data* sd = (shape_data*)(shape->fPrivateData);
3978 if (sd->opCount == 0 || sd->ptCount == 0)
3979 return;
3981 _CheckLockAndSwitchCurrent();
3982 _UpdatePattern(pattern);
3984 fOwner->fLink->StartMessage(AS_FILL_SHAPE);
3985 fOwner->fLink->Attach<BRect>(shape->Bounds());
3986 fOwner->fLink->Attach<int32>(sd->opCount);
3987 fOwner->fLink->Attach<int32>(sd->ptCount);
3988 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32));
3989 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint));
3991 _FlushIfNotInTransaction();
3995 void
3996 BView::FillShape(BShape* shape, const BGradient& gradient)
3998 if (shape == NULL || fOwner == NULL)
3999 return;
4001 shape_data* sd = (shape_data*)(shape->fPrivateData);
4002 if (sd->opCount == 0 || sd->ptCount == 0)
4003 return;
4005 _CheckLockAndSwitchCurrent();
4007 fOwner->fLink->StartMessage(AS_FILL_SHAPE_GRADIENT);
4008 fOwner->fLink->Attach<BRect>(shape->Bounds());
4009 fOwner->fLink->Attach<int32>(sd->opCount);
4010 fOwner->fLink->Attach<int32>(sd->ptCount);
4011 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(int32));
4012 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint));
4013 fOwner->fLink->AttachGradient(gradient);
4015 _FlushIfNotInTransaction();
4019 void
4020 BView::BeginLineArray(int32 count)
4022 if (fOwner == NULL)
4023 return;
4025 if (count <= 0)
4026 debugger("Calling BeginLineArray with a count <= 0");
4028 _CheckLock();
4030 if (fCommArray) {
4031 debugger("Can't nest BeginLineArray calls");
4032 // not fatal, but it helps during
4033 // development of your app and is in
4034 // line with R5...
4035 delete[] fCommArray->array;
4036 delete fCommArray;
4039 // TODO: since this method cannot return failure, and further AddLine()
4040 // calls with a NULL fCommArray would drop into the debugger anyway,
4041 // we allow the possible std::bad_alloc exceptions here...
4042 fCommArray = new _array_data_;
4043 fCommArray->count = 0;
4045 // Make sure the fCommArray is initialized to reasonable values in cases of
4046 // bad_alloc. At least the exception can be caught and EndLineArray won't
4047 // crash.
4048 fCommArray->array = NULL;
4049 fCommArray->maxCount = 0;
4051 fCommArray->array = new ViewLineArrayInfo[count];
4052 fCommArray->maxCount = count;
4056 void
4057 BView::AddLine(BPoint start, BPoint end, rgb_color color)
4059 if (fOwner == NULL)
4060 return;
4062 if (!fCommArray)
4063 debugger("BeginLineArray must be called before using AddLine");
4065 _CheckLock();
4067 const uint32 &arrayCount = fCommArray->count;
4068 if (arrayCount < fCommArray->maxCount) {
4069 fCommArray->array[arrayCount].startPoint = start;
4070 fCommArray->array[arrayCount].endPoint = end;
4071 fCommArray->array[arrayCount].color = color;
4073 fCommArray->count++;
4078 void
4079 BView::EndLineArray()
4081 if (fOwner == NULL)
4082 return;
4084 if (fCommArray == NULL)
4085 debugger("Can't call EndLineArray before BeginLineArray");
4087 _CheckLockAndSwitchCurrent();
4089 fOwner->fLink->StartMessage(AS_STROKE_LINEARRAY);
4090 fOwner->fLink->Attach<int32>(fCommArray->count);
4091 fOwner->fLink->Attach(fCommArray->array,
4092 fCommArray->count * sizeof(ViewLineArrayInfo));
4094 _FlushIfNotInTransaction();
4096 _RemoveCommArray();
4100 void
4101 BView::SetDiskMode(char* filename, long offset)
4103 // TODO: implement
4104 // One BeBook version has this to say about SetDiskMode():
4106 // "Begins recording a picture to the file with the given filename
4107 // at the given offset. Subsequent drawing commands sent to the view
4108 // will be written to the file until EndPicture() is called. The
4109 // stored commands may be played from the file with DrawPicture()."
4113 void
4114 BView::BeginPicture(BPicture* picture)
4116 if (_CheckOwnerLockAndSwitchCurrent()
4117 && picture && picture->fUsurped == NULL) {
4118 picture->Usurp(fCurrentPicture);
4119 fCurrentPicture = picture;
4121 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_PICTURE);
4126 void
4127 BView::AppendToPicture(BPicture* picture)
4129 _CheckLockAndSwitchCurrent();
4131 if (picture && picture->fUsurped == NULL) {
4132 int32 token = picture->Token();
4134 if (token == -1) {
4135 BeginPicture(picture);
4136 } else {
4137 picture->SetToken(-1);
4138 picture->Usurp(fCurrentPicture);
4139 fCurrentPicture = picture;
4140 fOwner->fLink->StartMessage(AS_VIEW_APPEND_TO_PICTURE);
4141 fOwner->fLink->Attach<int32>(token);
4147 BPicture*
4148 BView::EndPicture()
4150 if (_CheckOwnerLockAndSwitchCurrent() && fCurrentPicture) {
4151 int32 token;
4153 fOwner->fLink->StartMessage(AS_VIEW_END_PICTURE);
4155 int32 code;
4156 if (fOwner->fLink->FlushWithReply(code) == B_OK
4157 && code == B_OK
4158 && fOwner->fLink->Read<int32>(&token) == B_OK) {
4159 BPicture* picture = fCurrentPicture;
4160 fCurrentPicture = picture->StepDown();
4161 picture->SetToken(token);
4163 // TODO do this more efficient e.g. use a shared area and let the
4164 // client write into it
4165 picture->_Download();
4166 return picture;
4170 return NULL;
4174 void
4175 BView::SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect,
4176 uint32 followFlags, uint32 options)
4178 _SetViewBitmap(bitmap, srcRect, dstRect, followFlags, options);
4182 void
4183 BView::SetViewBitmap(const BBitmap* bitmap, uint32 followFlags, uint32 options)
4185 BRect rect;
4186 if (bitmap)
4187 rect = bitmap->Bounds();
4189 rect.OffsetTo(B_ORIGIN);
4191 _SetViewBitmap(bitmap, rect, rect, followFlags, options);
4195 void
4196 BView::ClearViewBitmap()
4198 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0);
4202 status_t
4203 BView::SetViewOverlay(const BBitmap* overlay, BRect srcRect, BRect dstRect,
4204 rgb_color* colorKey, uint32 followFlags, uint32 options)
4206 if (overlay == NULL || (overlay->fFlags & B_BITMAP_WILL_OVERLAY) == 0)
4207 return B_BAD_VALUE;
4209 status_t status = _SetViewBitmap(overlay, srcRect, dstRect, followFlags,
4210 options | AS_REQUEST_COLOR_KEY);
4211 if (status == B_OK) {
4212 // read the color that will be treated as transparent
4213 fOwner->fLink->Read<rgb_color>(colorKey);
4216 return status;
4220 status_t
4221 BView::SetViewOverlay(const BBitmap* overlay, rgb_color* colorKey,
4222 uint32 followFlags, uint32 options)
4224 if (overlay == NULL)
4225 return B_BAD_VALUE;
4227 BRect rect = overlay->Bounds();
4228 rect.OffsetTo(B_ORIGIN);
4230 return SetViewOverlay(overlay, rect, rect, colorKey, followFlags, options);
4234 void
4235 BView::ClearViewOverlay()
4237 _SetViewBitmap(NULL, BRect(), BRect(), 0, 0);
4241 void
4242 BView::CopyBits(BRect src, BRect dst)
4244 if (fOwner == NULL)
4245 return;
4247 if (!src.IsValid() || !dst.IsValid())
4248 return;
4250 _CheckLockAndSwitchCurrent();
4252 fOwner->fLink->StartMessage(AS_VIEW_COPY_BITS);
4253 fOwner->fLink->Attach<BRect>(src);
4254 fOwner->fLink->Attach<BRect>(dst);
4256 _FlushIfNotInTransaction();
4260 void
4261 BView::DrawPicture(const BPicture* picture)
4263 if (picture == NULL)
4264 return;
4266 DrawPictureAsync(picture, PenLocation());
4267 Sync();
4271 void
4272 BView::DrawPicture(const BPicture* picture, BPoint where)
4274 if (picture == NULL)
4275 return;
4277 DrawPictureAsync(picture, where);
4278 Sync();
4282 void
4283 BView::DrawPicture(const char* filename, long offset, BPoint where)
4285 if (!filename)
4286 return;
4288 DrawPictureAsync(filename, offset, where);
4289 Sync();
4293 void
4294 BView::DrawPictureAsync(const BPicture* picture)
4296 if (picture == NULL)
4297 return;
4299 DrawPictureAsync(picture, PenLocation());
4303 void
4304 BView::DrawPictureAsync(const BPicture* picture, BPoint where)
4306 if (picture == NULL)
4307 return;
4309 if (_CheckOwnerLockAndSwitchCurrent() && picture->Token() > 0) {
4310 fOwner->fLink->StartMessage(AS_VIEW_DRAW_PICTURE);
4311 fOwner->fLink->Attach<int32>(picture->Token());
4312 fOwner->fLink->Attach<BPoint>(where);
4314 _FlushIfNotInTransaction();
4319 void
4320 BView::DrawPictureAsync(const char* filename, long offset, BPoint where)
4322 if (!filename)
4323 return;
4325 // TODO: Test
4326 BFile file(filename, B_READ_ONLY);
4327 if (file.InitCheck() < B_OK)
4328 return;
4330 file.Seek(offset, SEEK_SET);
4332 BPicture picture;
4333 if (picture.Unflatten(&file) < B_OK)
4334 return;
4336 DrawPictureAsync(&picture, where);
4340 void
4341 BView::BeginLayer(uint8 opacity)
4343 if (_CheckOwnerLockAndSwitchCurrent()) {
4344 fOwner->fLink->StartMessage(AS_VIEW_BEGIN_LAYER);
4345 fOwner->fLink->Attach<uint8>(opacity);
4346 _FlushIfNotInTransaction();
4351 void
4352 BView::EndLayer()
4354 if (_CheckOwnerLockAndSwitchCurrent()) {
4355 fOwner->fLink->StartMessage(AS_VIEW_END_LAYER);
4356 _FlushIfNotInTransaction();
4361 void
4362 BView::Invalidate(BRect invalRect)
4364 if (fOwner == NULL)
4365 return;
4367 // NOTE: This rounding of the invalid rect is to stay compatible with BeOS.
4368 // On the server side, the invalid rect will be converted to a BRegion,
4369 // which rounds in a different manner, so that it really includes the
4370 // fractional coordinates of a BRect (ie ceilf(rect.right) &
4371 // ceilf(rect.bottom)), which is also what BeOS does. So we have to do the
4372 // different rounding here to stay compatible in both ways.
4373 invalRect.left = (int)invalRect.left;
4374 invalRect.top = (int)invalRect.top;
4375 invalRect.right = (int)invalRect.right;
4376 invalRect.bottom = (int)invalRect.bottom;
4377 if (!invalRect.IsValid())
4378 return;
4380 _CheckLockAndSwitchCurrent();
4382 fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_RECT);
4383 fOwner->fLink->Attach<BRect>(invalRect);
4385 // TODO: determine why this check isn't working correctly.
4386 #if 0
4387 if (!fOwner->fUpdateRequested) {
4388 fOwner->fLink->Flush();
4389 fOwner->fUpdateRequested = true;
4391 #else
4392 fOwner->fLink->Flush();
4393 #endif
4397 void
4398 BView::Invalidate(const BRegion* region)
4400 if (region == NULL || fOwner == NULL)
4401 return;
4403 _CheckLockAndSwitchCurrent();
4405 fOwner->fLink->StartMessage(AS_VIEW_INVALIDATE_REGION);
4406 fOwner->fLink->AttachRegion(*region);
4408 // TODO: See above.
4409 #if 0
4410 if (!fOwner->fUpdateRequested) {
4411 fOwner->fLink->Flush();
4412 fOwner->fUpdateRequested = true;
4414 #else
4415 fOwner->fLink->Flush();
4416 #endif
4420 void
4421 BView::Invalidate()
4423 Invalidate(Bounds());
4427 void
4428 BView::DelayedInvalidate(bigtime_t delay)
4430 DelayedInvalidate(delay, Bounds());
4434 void
4435 BView::DelayedInvalidate(bigtime_t delay, BRect invalRect)
4437 if (fOwner == NULL)
4438 return;
4440 invalRect.left = (int)invalRect.left;
4441 invalRect.top = (int)invalRect.top;
4442 invalRect.right = (int)invalRect.right;
4443 invalRect.bottom = (int)invalRect.bottom;
4444 if (!invalRect.IsValid())
4445 return;
4447 _CheckLockAndSwitchCurrent();
4449 fOwner->fLink->StartMessage(AS_VIEW_DELAYED_INVALIDATE_RECT);
4450 fOwner->fLink->Attach<bigtime_t>(system_time() + delay);
4451 fOwner->fLink->Attach<BRect>(invalRect);
4452 fOwner->fLink->Flush();
4456 void
4457 BView::InvertRect(BRect rect)
4459 if (fOwner) {
4460 _CheckLockAndSwitchCurrent();
4462 fOwner->fLink->StartMessage(AS_VIEW_INVERT_RECT);
4463 fOwner->fLink->Attach<BRect>(rect);
4465 _FlushIfNotInTransaction();
4470 // #pragma mark - View Hierarchy Functions
4473 void
4474 BView::AddChild(BView* child, BView* before)
4476 STRACE(("BView(%s)::AddChild(child '%s', before '%s')\n",
4477 this->Name(),
4478 child != NULL && child->Name() ? child->Name() : "NULL",
4479 before != NULL && before->Name() ? before->Name() : "NULL"));
4481 if (!_AddChild(child, before))
4482 return;
4484 if (fLayoutData->fLayout)
4485 fLayoutData->fLayout->AddView(child);
4489 bool
4490 BView::AddChild(BLayoutItem* child)
4492 if (!fLayoutData->fLayout)
4493 return false;
4494 return fLayoutData->fLayout->AddItem(child);
4498 bool
4499 BView::_AddChild(BView* child, BView* before)
4501 if (!child)
4502 return false;
4504 if (child->fParent != NULL) {
4505 debugger("AddChild failed - the view already has a parent.");
4506 return false;
4509 if (child == this) {
4510 debugger("AddChild failed - cannot add a view to itself.");
4511 return false;
4514 bool lockedOwner = false;
4515 if (fOwner && !fOwner->IsLocked()) {
4516 fOwner->Lock();
4517 lockedOwner = true;
4520 if (!_AddChildToList(child, before)) {
4521 debugger("AddChild failed!");
4522 if (lockedOwner)
4523 fOwner->Unlock();
4524 return false;
4527 if (fOwner) {
4528 _CheckLockAndSwitchCurrent();
4530 child->_SetOwner(fOwner);
4531 child->_CreateSelf();
4532 child->_Attach();
4534 if (lockedOwner)
4535 fOwner->Unlock();
4538 InvalidateLayout();
4540 return true;
4544 bool
4545 BView::RemoveChild(BView* child)
4547 STRACE(("BView(%s)::RemoveChild(%s)\n", Name(), child->Name()));
4549 if (!child)
4550 return false;
4552 if (child->fParent != this)
4553 return false;
4555 return child->RemoveSelf();
4559 int32
4560 BView::CountChildren() const
4562 _CheckLock();
4564 uint32 count = 0;
4565 BView* child = fFirstChild;
4567 while (child != NULL) {
4568 count++;
4569 child = child->fNextSibling;
4572 return count;
4576 BView*
4577 BView::ChildAt(int32 index) const
4579 _CheckLock();
4581 BView* child = fFirstChild;
4582 while (child != NULL && index-- > 0) {
4583 child = child->fNextSibling;
4586 return child;
4590 BView*
4591 BView::NextSibling() const
4593 return fNextSibling;
4597 BView*
4598 BView::PreviousSibling() const
4600 return fPreviousSibling;
4604 bool
4605 BView::RemoveSelf()
4607 _RemoveLayoutItemsFromLayout(false);
4609 return _RemoveSelf();
4613 bool
4614 BView::_RemoveSelf()
4616 STRACE(("BView(%s)::_RemoveSelf()\n", Name()));
4618 // Remove this child from its parent
4620 BWindow* owner = fOwner;
4621 _CheckLock();
4623 if (owner != NULL) {
4624 _UpdateStateForRemove();
4625 _Detach();
4628 BView* parent = fParent;
4629 if (!parent || !parent->_RemoveChildFromList(this))
4630 return false;
4632 if (owner != NULL && !fTopLevelView) {
4633 // the top level view is deleted by the app_server automatically
4634 owner->fLink->StartMessage(AS_VIEW_DELETE);
4635 owner->fLink->Attach<int32>(_get_object_token_(this));
4638 parent->InvalidateLayout();
4640 STRACE(("DONE: BView(%s)::_RemoveSelf()\n", Name()));
4642 return true;
4646 void
4647 BView::_RemoveLayoutItemsFromLayout(bool deleteItems)
4649 if (fParent == NULL || fParent->fLayoutData->fLayout == NULL)
4650 return;
4652 int32 index = fLayoutData->fLayoutItems.CountItems();
4653 while (index-- > 0) {
4654 BLayoutItem* item = fLayoutData->fLayoutItems.ItemAt(index);
4655 item->RemoveSelf();
4656 // Removes item from fLayoutItems list
4657 if (deleteItems)
4658 delete item;
4663 BView*
4664 BView::Parent() const
4666 if (fParent && fParent->fTopLevelView)
4667 return NULL;
4669 return fParent;
4673 BView*
4674 BView::FindView(const char* name) const
4676 if (name == NULL)
4677 return NULL;
4679 if (Name() != NULL && !strcmp(Name(), name))
4680 return const_cast<BView*>(this);
4682 BView* child = fFirstChild;
4683 while (child != NULL) {
4684 BView* view = child->FindView(name);
4685 if (view != NULL)
4686 return view;
4688 child = child->fNextSibling;
4691 return NULL;
4695 void
4696 BView::MoveBy(float deltaX, float deltaY)
4698 MoveTo(fParentOffset.x + roundf(deltaX), fParentOffset.y + roundf(deltaY));
4702 void
4703 BView::MoveTo(BPoint where)
4705 MoveTo(where.x, where.y);
4709 void
4710 BView::MoveTo(float x, float y)
4712 if (x == fParentOffset.x && y == fParentOffset.y)
4713 return;
4715 // BeBook says we should do this. And it makes sense.
4716 x = roundf(x);
4717 y = roundf(y);
4719 if (fOwner) {
4720 _CheckLockAndSwitchCurrent();
4721 fOwner->fLink->StartMessage(AS_VIEW_MOVE_TO);
4722 fOwner->fLink->Attach<float>(x);
4723 fOwner->fLink->Attach<float>(y);
4725 // fState->valid_flags |= B_VIEW_FRAME_BIT;
4727 _FlushIfNotInTransaction();
4730 _MoveTo((int32)x, (int32)y);
4734 void
4735 BView::ResizeBy(float deltaWidth, float deltaHeight)
4737 // BeBook says we should do this. And it makes sense.
4738 deltaWidth = roundf(deltaWidth);
4739 deltaHeight = roundf(deltaHeight);
4741 if (deltaWidth == 0 && deltaHeight == 0)
4742 return;
4744 if (fOwner) {
4745 _CheckLockAndSwitchCurrent();
4746 fOwner->fLink->StartMessage(AS_VIEW_RESIZE_TO);
4748 fOwner->fLink->Attach<float>(fBounds.Width() + deltaWidth);
4749 fOwner->fLink->Attach<float>(fBounds.Height() + deltaHeight);
4751 // fState->valid_flags |= B_VIEW_FRAME_BIT;
4753 _FlushIfNotInTransaction();
4756 _ResizeBy((int32)deltaWidth, (int32)deltaHeight);
4760 void
4761 BView::ResizeTo(float width, float height)
4763 ResizeBy(width - fBounds.Width(), height - fBounds.Height());
4767 void
4768 BView::ResizeTo(BSize size)
4770 ResizeBy(size.width - fBounds.Width(), size.height - fBounds.Height());
4774 // #pragma mark - Inherited Methods (from BHandler)
4777 status_t
4778 BView::GetSupportedSuites(BMessage* data)
4780 if (data == NULL)
4781 return B_BAD_VALUE;
4783 status_t status = data->AddString("suites", "suite/vnd.Be-view");
4784 BPropertyInfo propertyInfo(sViewPropInfo);
4785 if (status == B_OK)
4786 status = data->AddFlat("messages", &propertyInfo);
4787 if (status == B_OK)
4788 return BHandler::GetSupportedSuites(data);
4789 return status;
4793 BHandler*
4794 BView::ResolveSpecifier(BMessage* message, int32 index, BMessage* specifier,
4795 int32 what, const char* property)
4797 if (message->what == B_WINDOW_MOVE_BY
4798 || message->what == B_WINDOW_MOVE_TO) {
4799 return this;
4802 BPropertyInfo propertyInfo(sViewPropInfo);
4803 status_t err = B_BAD_SCRIPT_SYNTAX;
4804 BMessage replyMsg(B_REPLY);
4806 switch (propertyInfo.FindMatch(message, index, specifier, what, property)) {
4807 case 0:
4808 case 1:
4809 case 3:
4810 return this;
4812 case 2:
4813 if (fShelf) {
4814 message->PopSpecifier();
4815 return fShelf;
4818 err = B_NAME_NOT_FOUND;
4819 replyMsg.AddString("message", "This window doesn't have a shelf");
4820 break;
4822 case 4:
4824 if (!fFirstChild) {
4825 err = B_NAME_NOT_FOUND;
4826 replyMsg.AddString("message", "This window doesn't have "
4827 "children.");
4828 break;
4830 BView* child = NULL;
4831 switch (what) {
4832 case B_INDEX_SPECIFIER:
4834 int32 index;
4835 err = specifier->FindInt32("index", &index);
4836 if (err == B_OK)
4837 child = ChildAt(index);
4838 break;
4840 case B_REVERSE_INDEX_SPECIFIER:
4842 int32 rindex;
4843 err = specifier->FindInt32("index", &rindex);
4844 if (err == B_OK)
4845 child = ChildAt(CountChildren() - rindex);
4846 break;
4848 case B_NAME_SPECIFIER:
4850 const char* name;
4851 err = specifier->FindString("name", &name);
4852 if (err == B_OK)
4853 child = FindView(name);
4854 break;
4858 if (child != NULL) {
4859 message->PopSpecifier();
4860 return child;
4863 if (err == B_OK)
4864 err = B_BAD_INDEX;
4866 replyMsg.AddString("message",
4867 "Cannot find view at/with specified index/name.");
4868 break;
4871 default:
4872 return BHandler::ResolveSpecifier(message, index, specifier, what,
4873 property);
4876 if (err < B_OK) {
4877 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
4879 if (err == B_BAD_SCRIPT_SYNTAX)
4880 replyMsg.AddString("message", "Didn't understand the specifier(s)");
4881 else
4882 replyMsg.AddString("message", strerror(err));
4885 replyMsg.AddInt32("error", err);
4886 message->SendReply(&replyMsg);
4887 return NULL;
4891 void
4892 BView::MessageReceived(BMessage* message)
4894 if (!message->HasSpecifiers()) {
4895 switch (message->what) {
4896 case B_VIEW_RESIZED:
4897 FrameResized(message->GetInt32("width", 0),
4898 message->GetInt32("height", 0));
4899 break;
4901 case B_VIEW_MOVED:
4902 FrameMoved(fParentOffset);
4903 break;
4905 case B_MOUSE_IDLE:
4907 BPoint where;
4908 if (message->FindPoint("be:view_where", &where) != B_OK)
4909 break;
4911 BToolTip* tip;
4912 if (GetToolTipAt(where, &tip))
4913 ShowToolTip(tip);
4914 else
4915 BHandler::MessageReceived(message);
4916 break;
4919 case B_MOUSE_WHEEL_CHANGED:
4921 BScrollBar* horizontal = ScrollBar(B_HORIZONTAL);
4922 BScrollBar* vertical = ScrollBar(B_VERTICAL);
4923 if (horizontal == NULL && vertical == NULL) {
4924 // Pass the message to the next handler
4925 BHandler::MessageReceived(message);
4926 break;
4929 float deltaX = 0.0f;
4930 float deltaY = 0.0f;
4932 if (horizontal != NULL)
4933 message->FindFloat("be:wheel_delta_x", &deltaX);
4935 if (vertical != NULL)
4936 message->FindFloat("be:wheel_delta_y", &deltaY);
4938 if (deltaX == 0.0f && deltaY == 0.0f)
4939 break;
4941 if ((modifiers() & B_CONTROL_KEY) != 0)
4942 std::swap(horizontal, vertical);
4944 if (horizontal != NULL && deltaX != 0.0f)
4945 ScrollWithMouseWheelDelta(horizontal, deltaX);
4947 if (vertical != NULL && deltaY != 0.0f)
4948 ScrollWithMouseWheelDelta(vertical, deltaY);
4950 break;
4953 // prevent message repeats
4954 case B_COLORS_UPDATED:
4955 case B_FONTS_UPDATED:
4956 break;
4958 case B_SCREEN_CHANGED:
4960 // propegate message to child views
4961 int32 childCount = CountChildren();
4962 for (int32 i = 0; i < childCount; i++) {
4963 BView* view = ChildAt(i);
4964 if (view != NULL)
4965 view->MessageReceived(message);
4967 break;
4970 default:
4971 BHandler::MessageReceived(message);
4972 break;
4975 return;
4978 // Scripting message
4980 BMessage replyMsg(B_REPLY);
4981 status_t err = B_BAD_SCRIPT_SYNTAX;
4982 int32 index;
4983 BMessage specifier;
4984 int32 what;
4985 const char* property;
4987 if (message->GetCurrentSpecifier(&index, &specifier, &what, &property)
4988 != B_OK) {
4989 return BHandler::MessageReceived(message);
4992 BPropertyInfo propertyInfo(sViewPropInfo);
4993 switch (propertyInfo.FindMatch(message, index, &specifier, what,
4994 property)) {
4995 case 0:
4996 if (message->what == B_GET_PROPERTY) {
4997 err = replyMsg.AddRect("result", Frame());
4998 } else if (message->what == B_SET_PROPERTY) {
4999 BRect newFrame;
5000 err = message->FindRect("data", &newFrame);
5001 if (err == B_OK) {
5002 MoveTo(newFrame.LeftTop());
5003 ResizeTo(newFrame.Width(), newFrame.Height());
5006 break;
5007 case 1:
5008 if (message->what == B_GET_PROPERTY) {
5009 err = replyMsg.AddBool("result", IsHidden());
5010 } else if (message->what == B_SET_PROPERTY) {
5011 bool newHiddenState;
5012 err = message->FindBool("data", &newHiddenState);
5013 if (err == B_OK) {
5014 if (newHiddenState == true)
5015 Hide();
5016 else
5017 Show();
5020 break;
5021 case 3:
5022 err = replyMsg.AddInt32("result", CountChildren());
5023 break;
5024 default:
5025 return BHandler::MessageReceived(message);
5028 if (err != B_OK) {
5029 replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
5031 if (err == B_BAD_SCRIPT_SYNTAX)
5032 replyMsg.AddString("message", "Didn't understand the specifier(s)");
5033 else
5034 replyMsg.AddString("message", strerror(err));
5036 replyMsg.AddInt32("error", err);
5039 message->SendReply(&replyMsg);
5043 status_t
5044 BView::Perform(perform_code code, void* _data)
5046 switch (code) {
5047 case PERFORM_CODE_MIN_SIZE:
5048 ((perform_data_min_size*)_data)->return_value
5049 = BView::MinSize();
5050 return B_OK;
5051 case PERFORM_CODE_MAX_SIZE:
5052 ((perform_data_max_size*)_data)->return_value
5053 = BView::MaxSize();
5054 return B_OK;
5055 case PERFORM_CODE_PREFERRED_SIZE:
5056 ((perform_data_preferred_size*)_data)->return_value
5057 = BView::PreferredSize();
5058 return B_OK;
5059 case PERFORM_CODE_LAYOUT_ALIGNMENT:
5060 ((perform_data_layout_alignment*)_data)->return_value
5061 = BView::LayoutAlignment();
5062 return B_OK;
5063 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
5064 ((perform_data_has_height_for_width*)_data)->return_value
5065 = BView::HasHeightForWidth();
5066 return B_OK;
5067 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
5069 perform_data_get_height_for_width* data
5070 = (perform_data_get_height_for_width*)_data;
5071 BView::GetHeightForWidth(data->width, &data->min, &data->max,
5072 &data->preferred);
5073 return B_OK;
5075 case PERFORM_CODE_SET_LAYOUT:
5077 perform_data_set_layout* data = (perform_data_set_layout*)_data;
5078 BView::SetLayout(data->layout);
5079 return B_OK;
5081 case PERFORM_CODE_LAYOUT_INVALIDATED:
5083 perform_data_layout_invalidated* data
5084 = (perform_data_layout_invalidated*)_data;
5085 BView::LayoutInvalidated(data->descendants);
5086 return B_OK;
5088 case PERFORM_CODE_DO_LAYOUT:
5090 BView::DoLayout();
5091 return B_OK;
5093 case PERFORM_CODE_LAYOUT_CHANGED:
5095 BView::LayoutChanged();
5096 return B_OK;
5098 case PERFORM_CODE_GET_TOOL_TIP_AT:
5100 perform_data_get_tool_tip_at* data
5101 = (perform_data_get_tool_tip_at*)_data;
5102 data->return_value
5103 = BView::GetToolTipAt(data->point, data->tool_tip);
5104 return B_OK;
5106 case PERFORM_CODE_ALL_UNARCHIVED:
5108 perform_data_all_unarchived* data =
5109 (perform_data_all_unarchived*)_data;
5111 data->return_value = BView::AllUnarchived(data->archive);
5112 return B_OK;
5114 case PERFORM_CODE_ALL_ARCHIVED:
5116 perform_data_all_archived* data =
5117 (perform_data_all_archived*)_data;
5119 data->return_value = BView::AllArchived(data->archive);
5120 return B_OK;
5124 return BHandler::Perform(code, _data);
5128 // #pragma mark - Layout Functions
5131 BSize
5132 BView::MinSize()
5134 // TODO: make sure this works correctly when some methods are overridden
5135 float width, height;
5136 GetPreferredSize(&width, &height);
5138 return BLayoutUtils::ComposeSize(fLayoutData->fMinSize,
5139 (fLayoutData->fLayout ? fLayoutData->fLayout->MinSize()
5140 : BSize(width, height)));
5144 BSize
5145 BView::MaxSize()
5147 return BLayoutUtils::ComposeSize(fLayoutData->fMaxSize,
5148 (fLayoutData->fLayout ? fLayoutData->fLayout->MaxSize()
5149 : BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)));
5153 BSize
5154 BView::PreferredSize()
5156 // TODO: make sure this works correctly when some methods are overridden
5157 float width, height;
5158 GetPreferredSize(&width, &height);
5160 return BLayoutUtils::ComposeSize(fLayoutData->fPreferredSize,
5161 (fLayoutData->fLayout ? fLayoutData->fLayout->PreferredSize()
5162 : BSize(width, height)));
5166 BAlignment
5167 BView::LayoutAlignment()
5169 return BLayoutUtils::ComposeAlignment(fLayoutData->fAlignment,
5170 (fLayoutData->fLayout ? fLayoutData->fLayout->Alignment()
5171 : BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER)));
5175 void
5176 BView::SetExplicitMinSize(BSize size)
5178 fLayoutData->fMinSize = size;
5179 InvalidateLayout();
5183 void
5184 BView::SetExplicitMaxSize(BSize size)
5186 fLayoutData->fMaxSize = size;
5187 InvalidateLayout();
5191 void
5192 BView::SetExplicitPreferredSize(BSize size)
5194 fLayoutData->fPreferredSize = size;
5195 InvalidateLayout();
5199 void
5200 BView::SetExplicitSize(BSize size)
5202 fLayoutData->fMinSize = size;
5203 fLayoutData->fMaxSize = size;
5204 fLayoutData->fPreferredSize = size;
5205 InvalidateLayout();
5209 void
5210 BView::SetExplicitAlignment(BAlignment alignment)
5212 fLayoutData->fAlignment = alignment;
5213 InvalidateLayout();
5217 BSize
5218 BView::ExplicitMinSize() const
5220 return fLayoutData->fMinSize;
5224 BSize
5225 BView::ExplicitMaxSize() const
5227 return fLayoutData->fMaxSize;
5231 BSize
5232 BView::ExplicitPreferredSize() const
5234 return fLayoutData->fPreferredSize;
5238 BAlignment
5239 BView::ExplicitAlignment() const
5241 return fLayoutData->fAlignment;
5245 bool
5246 BView::HasHeightForWidth()
5248 return (fLayoutData->fLayout
5249 ? fLayoutData->fLayout->HasHeightForWidth() : false);
5253 void
5254 BView::GetHeightForWidth(float width, float* min, float* max, float* preferred)
5256 if (fLayoutData->fLayout)
5257 fLayoutData->fLayout->GetHeightForWidth(width, min, max, preferred);
5261 void
5262 BView::SetLayout(BLayout* layout)
5264 if (layout == fLayoutData->fLayout)
5265 return;
5267 if (layout && layout->Layout())
5268 debugger("BView::SetLayout() failed, layout is already in use.");
5270 fFlags |= B_SUPPORTS_LAYOUT;
5272 // unset and delete the old layout
5273 if (fLayoutData->fLayout) {
5274 fLayoutData->fLayout->RemoveSelf();
5275 fLayoutData->fLayout->SetOwner(NULL);
5276 delete fLayoutData->fLayout;
5279 fLayoutData->fLayout = layout;
5281 if (fLayoutData->fLayout) {
5282 fLayoutData->fLayout->SetOwner(this);
5284 // add all children
5285 int count = CountChildren();
5286 for (int i = 0; i < count; i++)
5287 fLayoutData->fLayout->AddView(ChildAt(i));
5290 InvalidateLayout();
5294 BLayout*
5295 BView::GetLayout() const
5297 return fLayoutData->fLayout;
5301 void
5302 BView::InvalidateLayout(bool descendants)
5304 // printf("BView(%p)::InvalidateLayout(%i), valid: %i, inProgress: %i\n",
5305 // this, descendants, fLayoutData->fLayoutValid,
5306 // fLayoutData->fLayoutInProgress);
5308 if (!fLayoutData->fMinMaxValid || fLayoutData->fLayoutInProgress
5309 || fLayoutData->fLayoutInvalidationDisabled > 0) {
5310 return;
5312 fLayoutData->fLayoutValid = false;
5313 fLayoutData->fMinMaxValid = false;
5314 LayoutInvalidated(descendants);
5316 if (descendants) {
5317 for (BView* child = fFirstChild;
5318 child; child = child->fNextSibling) {
5319 child->InvalidateLayout(descendants);
5323 if (fLayoutData->fLayout)
5324 fLayoutData->fLayout->InvalidateLayout(descendants);
5325 else
5326 _InvalidateParentLayout();
5328 if (fTopLevelView
5329 && fOwner != NULL)
5330 fOwner->PostMessage(B_LAYOUT_WINDOW);
5334 void
5335 BView::EnableLayoutInvalidation()
5337 if (fLayoutData->fLayoutInvalidationDisabled > 0)
5338 fLayoutData->fLayoutInvalidationDisabled--;
5342 void
5343 BView::DisableLayoutInvalidation()
5345 fLayoutData->fLayoutInvalidationDisabled++;
5349 bool
5350 BView::IsLayoutInvalidationDisabled()
5352 if (fLayoutData->fLayoutInvalidationDisabled > 0)
5353 return true;
5354 return false;
5358 bool
5359 BView::IsLayoutValid() const
5361 return fLayoutData->fLayoutValid;
5365 void
5366 BView::ResetLayoutInvalidation()
5368 fLayoutData->fMinMaxValid = true;
5372 BLayoutContext*
5373 BView::LayoutContext() const
5375 return fLayoutData->fLayoutContext;
5379 void
5380 BView::Layout(bool force)
5382 BLayoutContext context;
5383 _Layout(force, &context);
5387 void
5388 BView::Relayout()
5390 if (fLayoutData->fLayoutValid && !fLayoutData->fLayoutInProgress) {
5391 fLayoutData->fNeedsRelayout = true;
5392 if (fLayoutData->fLayout)
5393 fLayoutData->fLayout->RequireLayout();
5395 // Layout() is recursive, that is if the parent view is currently laid
5396 // out, we don't call layout() on this view, but wait for the parent's
5397 // Layout() to do that for us.
5398 if (!fParent || !fParent->fLayoutData->fLayoutInProgress)
5399 Layout(false);
5404 void
5405 BView::LayoutInvalidated(bool descendants)
5407 // hook method
5411 void
5412 BView::DoLayout()
5414 if (fLayoutData->fLayout)
5415 fLayoutData->fLayout->_LayoutWithinContext(false, LayoutContext());
5419 void
5420 BView::SetToolTip(const char* text)
5422 if (text == NULL || text[0] == '\0') {
5423 SetToolTip((BToolTip*)NULL);
5424 return;
5427 if (BTextToolTip* tip = dynamic_cast<BTextToolTip*>(fToolTip))
5428 tip->SetText(text);
5429 else
5430 SetToolTip(new BTextToolTip(text));
5434 void
5435 BView::SetToolTip(BToolTip* tip)
5437 if (fToolTip == tip)
5438 return;
5439 else if (tip == NULL)
5440 HideToolTip();
5442 if (fToolTip != NULL)
5443 fToolTip->ReleaseReference();
5445 fToolTip = tip;
5447 if (fToolTip != NULL)
5448 fToolTip->AcquireReference();
5452 BToolTip*
5453 BView::ToolTip() const
5455 return fToolTip;
5459 void
5460 BView::ShowToolTip(BToolTip* tip)
5462 if (tip == NULL)
5463 return;
5465 BPoint where;
5466 GetMouse(&where, NULL, false);
5468 BToolTipManager::Manager()->ShowTip(tip, ConvertToScreen(where), this);
5472 void
5473 BView::HideToolTip()
5475 BToolTipManager::Manager()->HideTip();
5479 bool
5480 BView::GetToolTipAt(BPoint point, BToolTip** _tip)
5482 if (fToolTip != NULL) {
5483 *_tip = fToolTip;
5484 return true;
5487 *_tip = NULL;
5488 return false;
5492 void
5493 BView::LayoutChanged()
5495 // hook method
5499 void
5500 BView::_Layout(bool force, BLayoutContext* context)
5502 //printf("%p->BView::_Layout(%d, %p)\n", this, force, context);
5503 //printf(" fNeedsRelayout: %d, fLayoutValid: %d, fLayoutInProgress: %d\n",
5504 //fLayoutData->fNeedsRelayout, fLayoutData->fLayoutValid,
5505 //fLayoutData->fLayoutInProgress);
5506 if (fLayoutData->fNeedsRelayout || !fLayoutData->fLayoutValid || force) {
5507 fLayoutData->fLayoutValid = false;
5509 if (fLayoutData->fLayoutInProgress)
5510 return;
5512 BLayoutContext* oldContext = fLayoutData->fLayoutContext;
5513 fLayoutData->fLayoutContext = context;
5515 fLayoutData->fLayoutInProgress = true;
5516 DoLayout();
5517 fLayoutData->fLayoutInProgress = false;
5519 fLayoutData->fLayoutValid = true;
5520 fLayoutData->fMinMaxValid = true;
5521 fLayoutData->fNeedsRelayout = false;
5523 // layout children
5524 for(BView* child = fFirstChild; child; child = child->fNextSibling) {
5525 if (!child->IsHidden(child))
5526 child->_Layout(force, context);
5529 LayoutChanged();
5531 fLayoutData->fLayoutContext = oldContext;
5533 // invalidate the drawn content, if requested
5534 if (fFlags & B_INVALIDATE_AFTER_LAYOUT)
5535 Invalidate();
5540 void
5541 BView::_LayoutLeft(BLayout* deleted)
5543 // If our layout is added to another layout (via BLayout::AddItem())
5544 // then we share ownership of our layout. In the event that our layout gets
5545 // deleted by the layout it has been added to, this method is called so
5546 // that we don't double-delete our layout.
5547 if (fLayoutData->fLayout == deleted)
5548 fLayoutData->fLayout = NULL;
5549 InvalidateLayout();
5553 void
5554 BView::_InvalidateParentLayout()
5556 if (!fParent)
5557 return;
5559 BLayout* layout = fLayoutData->fLayout;
5560 BLayout* layoutParent = layout ? layout->Layout() : NULL;
5561 if (layoutParent) {
5562 layoutParent->InvalidateLayout();
5563 } else if (fLayoutData->fLayoutItems.CountItems() > 0) {
5564 int32 count = fLayoutData->fLayoutItems.CountItems();
5565 for (int32 i = 0; i < count; i++) {
5566 fLayoutData->fLayoutItems.ItemAt(i)->Layout()->InvalidateLayout();
5568 } else {
5569 fParent->InvalidateLayout();
5574 // #pragma mark - Private Functions
5577 void
5578 BView::_InitData(BRect frame, const char* name, uint32 resizingMode,
5579 uint32 flags)
5581 // Info: The name of the view is set by BHandler constructor
5583 STRACE(("BView::_InitData: enter\n"));
5585 // initialize members
5586 if ((resizingMode & ~_RESIZE_MASK_) || (flags & _RESIZE_MASK_))
5587 printf("%s BView::_InitData(): resizing mode or flags swapped\n", name);
5589 // There are applications that swap the resize mask and the flags in the
5590 // BView constructor. This does not cause problems under BeOS as it just
5591 // ors the two fields to one 32bit flag.
5592 // For now we do the same but print the above warning message.
5593 // TODO: this should be removed at some point and the original
5594 // version restored:
5595 // fFlags = (resizingMode & _RESIZE_MASK_) | (flags & ~_RESIZE_MASK_);
5596 fFlags = resizingMode | flags;
5598 // handle rounding
5599 frame.left = roundf(frame.left);
5600 frame.top = roundf(frame.top);
5601 frame.right = roundf(frame.right);
5602 frame.bottom = roundf(frame.bottom);
5604 fParentOffset.Set(frame.left, frame.top);
5606 fOwner = NULL;
5607 fParent = NULL;
5608 fNextSibling = NULL;
5609 fPreviousSibling = NULL;
5610 fFirstChild = NULL;
5612 fShowLevel = 0;
5613 fTopLevelView = false;
5615 fCurrentPicture = NULL;
5616 fCommArray = NULL;
5618 fVerScroller = NULL;
5619 fHorScroller = NULL;
5621 fIsPrinting = false;
5622 fAttached = false;
5624 // TODO: Since we cannot communicate failure, we don't use std::nothrow here
5625 // TODO: Maybe we could auto-delete those views on AddChild() instead?
5626 fState = new BPrivate::ViewState;
5628 fBounds = frame.OffsetToCopy(B_ORIGIN);
5629 fShelf = NULL;
5631 fEventMask = 0;
5632 fEventOptions = 0;
5633 fMouseEventOptions = 0;
5635 fLayoutData = new LayoutData;
5637 fToolTip = NULL;
5639 if ((flags & B_SUPPORTS_LAYOUT) != 0) {
5640 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
5641 SetLowUIColor(ViewUIColor());
5642 SetHighUIColor(B_PANEL_TEXT_COLOR);
5647 void
5648 BView::_RemoveCommArray()
5650 if (fCommArray) {
5651 delete [] fCommArray->array;
5652 delete fCommArray;
5653 fCommArray = NULL;
5658 void
5659 BView::_SetOwner(BWindow* newOwner)
5661 if (!newOwner)
5662 _RemoveCommArray();
5664 if (fOwner != newOwner && fOwner) {
5665 if (fOwner->fFocus == this)
5666 MakeFocus(false);
5668 if (fOwner->fLastMouseMovedView == this)
5669 fOwner->fLastMouseMovedView = NULL;
5671 fOwner->RemoveHandler(this);
5672 if (fShelf)
5673 fOwner->RemoveHandler(fShelf);
5676 if (newOwner && newOwner != fOwner) {
5677 newOwner->AddHandler(this);
5678 if (fShelf)
5679 newOwner->AddHandler(fShelf);
5681 if (fTopLevelView)
5682 SetNextHandler(newOwner);
5683 else
5684 SetNextHandler(fParent);
5687 fOwner = newOwner;
5689 for (BView* child = fFirstChild; child != NULL; child = child->fNextSibling)
5690 child->_SetOwner(newOwner);
5694 void
5695 BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync)
5697 if (!_CheckOwnerLockAndSwitchCurrent())
5698 return;
5700 if (picture == NULL) {
5701 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE);
5702 fOwner->fLink->Attach<int32>(-1);
5704 // NOTE: No need to sync here, since the -1 token cannot
5705 // become invalid on the server.
5706 } else {
5707 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE);
5708 fOwner->fLink->Attach<int32>(picture->Token());
5709 fOwner->fLink->Attach<BPoint>(where);
5710 fOwner->fLink->Attach<bool>(invert);
5712 // NOTE: "sync" defaults to true in public methods. If you know what
5713 // you are doing, i.e. if you know your BPicture stays valid, you
5714 // can avoid the performance impact of syncing. In a use-case where
5715 // the client creates BPictures on the stack, these BPictures may
5716 // have issued a AS_DELETE_PICTURE command to the ServerApp when Draw()
5717 // goes out of scope, and the command is processed earlier in the
5718 // ServerApp thread than the AS_VIEW_CLIP_TO_PICTURE command in the
5719 // ServerWindow thread, which will then have the result that no
5720 // ServerPicture is found of the token.
5721 if (sync)
5722 Sync();
5727 void
5728 BView::_ClipToRect(BRect rect, bool inverse)
5730 if (_CheckOwnerLockAndSwitchCurrent()) {
5731 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_RECT);
5732 fOwner->fLink->Attach<bool>(inverse);
5733 fOwner->fLink->Attach<BRect>(rect);
5734 _FlushIfNotInTransaction();
5739 void
5740 BView::_ClipToShape(BShape* shape, bool inverse)
5742 if (shape == NULL)
5743 return;
5745 shape_data* sd = (shape_data*)shape->fPrivateData;
5746 if (sd->opCount == 0 || sd->ptCount == 0)
5747 return;
5749 if (_CheckOwnerLockAndSwitchCurrent()) {
5750 fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_SHAPE);
5751 fOwner->fLink->Attach<bool>(inverse);
5752 fOwner->fLink->Attach<int32>(sd->opCount);
5753 fOwner->fLink->Attach<int32>(sd->ptCount);
5754 fOwner->fLink->Attach(sd->opList, sd->opCount * sizeof(uint32));
5755 fOwner->fLink->Attach(sd->ptList, sd->ptCount * sizeof(BPoint));
5756 _FlushIfNotInTransaction();
5761 bool
5762 BView::_RemoveChildFromList(BView* child)
5764 if (child->fParent != this)
5765 return false;
5767 if (fFirstChild == child) {
5768 // it's the first view in the list
5769 fFirstChild = child->fNextSibling;
5770 } else {
5771 // there must be a previous sibling
5772 child->fPreviousSibling->fNextSibling = child->fNextSibling;
5775 if (child->fNextSibling)
5776 child->fNextSibling->fPreviousSibling = child->fPreviousSibling;
5778 child->fParent = NULL;
5779 child->fNextSibling = NULL;
5780 child->fPreviousSibling = NULL;
5782 return true;
5786 bool
5787 BView::_AddChildToList(BView* child, BView* before)
5789 if (!child)
5790 return false;
5791 if (child->fParent != NULL) {
5792 debugger("View already belongs to someone else");
5793 return false;
5795 if (before != NULL && before->fParent != this) {
5796 debugger("Invalid before view");
5797 return false;
5800 if (before != NULL) {
5801 // add view before this one
5802 child->fNextSibling = before;
5803 child->fPreviousSibling = before->fPreviousSibling;
5804 if (child->fPreviousSibling != NULL)
5805 child->fPreviousSibling->fNextSibling = child;
5807 before->fPreviousSibling = child;
5808 if (fFirstChild == before)
5809 fFirstChild = child;
5810 } else {
5811 // add view to the end of the list
5812 BView* last = fFirstChild;
5813 while (last != NULL && last->fNextSibling != NULL) {
5814 last = last->fNextSibling;
5817 if (last != NULL) {
5818 last->fNextSibling = child;
5819 child->fPreviousSibling = last;
5820 } else {
5821 fFirstChild = child;
5822 child->fPreviousSibling = NULL;
5825 child->fNextSibling = NULL;
5828 child->fParent = this;
5829 return true;
5833 /*! \brief Creates the server counterpart of this view.
5834 This is only done for views that are part of the view hierarchy, ie. when
5835 they are attached to a window.
5836 RemoveSelf() deletes the server object again.
5838 bool
5839 BView::_CreateSelf()
5841 // AS_VIEW_CREATE & AS_VIEW_CREATE_ROOT do not use the
5842 // current view mechanism via _CheckLockAndSwitchCurrent() - the token
5843 // of the view and its parent are both send to the server.
5845 if (fTopLevelView)
5846 fOwner->fLink->StartMessage(AS_VIEW_CREATE_ROOT);
5847 else
5848 fOwner->fLink->StartMessage(AS_VIEW_CREATE);
5850 fOwner->fLink->Attach<int32>(_get_object_token_(this));
5851 fOwner->fLink->AttachString(Name());
5852 fOwner->fLink->Attach<BRect>(Frame());
5853 fOwner->fLink->Attach<BPoint>(LeftTop());
5854 fOwner->fLink->Attach<uint32>(ResizingMode());
5855 fOwner->fLink->Attach<uint32>(fEventMask);
5856 fOwner->fLink->Attach<uint32>(fEventOptions);
5857 fOwner->fLink->Attach<uint32>(Flags());
5858 fOwner->fLink->Attach<bool>(IsHidden(this));
5859 fOwner->fLink->Attach<rgb_color>(fState->view_color);
5860 if (fTopLevelView)
5861 fOwner->fLink->Attach<int32>(B_NULL_TOKEN);
5862 else
5863 fOwner->fLink->Attach<int32>(_get_object_token_(fParent));
5864 fOwner->fLink->Flush();
5866 _CheckOwnerLockAndSwitchCurrent();
5867 fState->UpdateServerState(*fOwner->fLink);
5869 // we create all its children, too
5871 for (BView* child = fFirstChild; child != NULL;
5872 child = child->fNextSibling) {
5873 child->_CreateSelf();
5876 fOwner->fLink->Flush();
5877 return true;
5881 /*! Sets the new view position.
5882 It doesn't contact the server, though - the only case where this
5883 is called outside of MoveTo() is as reaction of moving a view
5884 in the server (a.k.a. B_WINDOW_RESIZED).
5885 It also calls the BView's FrameMoved() hook.
5887 void
5888 BView::_MoveTo(int32 x, int32 y)
5890 fParentOffset.Set(x, y);
5892 if (Window() != NULL && fFlags & B_FRAME_EVENTS) {
5893 BMessage moved(B_VIEW_MOVED);
5894 moved.AddInt64("when", system_time());
5895 moved.AddPoint("where", BPoint(x, y));
5897 BMessenger target(this);
5898 target.SendMessage(&moved);
5903 /*! Computes the actual new frame size and recalculates the size of
5904 the children as well.
5905 It doesn't contact the server, though - the only case where this
5906 is called outside of ResizeBy() is as reaction of resizing a view
5907 in the server (a.k.a. B_WINDOW_RESIZED).
5908 It also calls the BView's FrameResized() hook.
5910 void
5911 BView::_ResizeBy(int32 deltaWidth, int32 deltaHeight)
5913 fBounds.right += deltaWidth;
5914 fBounds.bottom += deltaHeight;
5916 if (Window() == NULL) {
5917 // we're not supposed to exercise the resizing code in case
5918 // we haven't been attached to a window yet
5919 return;
5922 // layout the children
5923 if ((fFlags & B_SUPPORTS_LAYOUT) != 0) {
5924 Relayout();
5925 } else {
5926 for (BView* child = fFirstChild; child; child = child->fNextSibling)
5927 child->_ParentResizedBy(deltaWidth, deltaHeight);
5930 if (fFlags & B_FRAME_EVENTS) {
5931 BMessage resized(B_VIEW_RESIZED);
5932 resized.AddInt64("when", system_time());
5933 resized.AddInt32("width", fBounds.IntegerWidth());
5934 resized.AddInt32("height", fBounds.IntegerHeight());
5936 BMessenger target(this);
5937 target.SendMessage(&resized);
5942 /*! Relayouts the view according to its resizing mode. */
5943 void
5944 BView::_ParentResizedBy(int32 x, int32 y)
5946 uint32 resizingMode = fFlags & _RESIZE_MASK_;
5947 BRect newFrame = Frame();
5949 // follow with left side
5950 if ((resizingMode & 0x0F00U) == _VIEW_RIGHT_ << 8)
5951 newFrame.left += x;
5952 else if ((resizingMode & 0x0F00U) == _VIEW_CENTER_ << 8)
5953 newFrame.left += x / 2;
5955 // follow with right side
5956 if ((resizingMode & 0x000FU) == _VIEW_RIGHT_)
5957 newFrame.right += x;
5958 else if ((resizingMode & 0x000FU) == _VIEW_CENTER_)
5959 newFrame.right += x / 2;
5961 // follow with top side
5962 if ((resizingMode & 0xF000U) == _VIEW_BOTTOM_ << 12)
5963 newFrame.top += y;
5964 else if ((resizingMode & 0xF000U) == _VIEW_CENTER_ << 12)
5965 newFrame.top += y / 2;
5967 // follow with bottom side
5968 if ((resizingMode & 0x00F0U) == _VIEW_BOTTOM_ << 4)
5969 newFrame.bottom += y;
5970 else if ((resizingMode & 0x00F0U) == _VIEW_CENTER_ << 4)
5971 newFrame.bottom += y / 2;
5973 if (newFrame.LeftTop() != fParentOffset) {
5974 // move view
5975 _MoveTo((int32)roundf(newFrame.left), (int32)roundf(newFrame.top));
5978 if (newFrame != Frame()) {
5979 // resize view
5980 int32 widthDiff = (int32)(newFrame.Width() - fBounds.Width());
5981 int32 heightDiff = (int32)(newFrame.Height() - fBounds.Height());
5982 _ResizeBy(widthDiff, heightDiff);
5987 void
5988 BView::_Activate(bool active)
5990 WindowActivated(active);
5992 for (BView* child = fFirstChild; child != NULL;
5993 child = child->fNextSibling) {
5994 child->_Activate(active);
5999 void
6000 BView::_Attach()
6002 if (fOwner != NULL) {
6003 // unmask state flags to force [re]syncing with the app_server
6004 fState->valid_flags &= ~(B_VIEW_WHICH_VIEW_COLOR_BIT
6005 | B_VIEW_WHICH_LOW_COLOR_BIT | B_VIEW_WHICH_HIGH_COLOR_BIT);
6007 if (fState->which_view_color != B_NO_COLOR)
6008 SetViewUIColor(fState->which_view_color,
6009 fState->which_view_color_tint);
6011 if (fState->which_high_color != B_NO_COLOR)
6012 SetHighUIColor(fState->which_high_color,
6013 fState->which_high_color_tint);
6015 if (fState->which_low_color != B_NO_COLOR)
6016 SetLowUIColor(fState->which_low_color,
6017 fState->which_low_color_tint);
6020 AttachedToWindow();
6022 fAttached = true;
6024 // after giving the view a chance to do this itself,
6025 // check for the B_PULSE_NEEDED flag and make sure the
6026 // window set's up the pulse messaging
6027 if (fOwner) {
6028 if (fFlags & B_PULSE_NEEDED) {
6029 _CheckLock();
6030 if (fOwner->fPulseRunner == NULL)
6031 fOwner->SetPulseRate(fOwner->PulseRate());
6034 if (!fOwner->IsHidden())
6035 Invalidate();
6038 for (BView* child = fFirstChild; child != NULL;
6039 child = child->fNextSibling) {
6040 // we need to check for fAttached as new views could have been
6041 // added in AttachedToWindow() - and those are already attached
6042 if (!child->fAttached)
6043 child->_Attach();
6046 AllAttached();
6050 void
6051 BView::_ColorsUpdated(BMessage* message)
6053 if (fTopLevelView
6054 && fLayoutData->fLayout != NULL
6055 && !fState->IsValid(B_VIEW_WHICH_VIEW_COLOR_BIT)) {
6056 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
6057 SetHighUIColor(B_PANEL_TEXT_COLOR);
6060 rgb_color color;
6062 const char* colorName = ui_color_name(fState->which_view_color);
6063 if (colorName != NULL && message->FindColor(colorName, &color) == B_OK) {
6064 fState->view_color = tint_color(color, fState->which_view_color_tint);
6065 fState->valid_flags |= B_VIEW_VIEW_COLOR_BIT;
6068 colorName = ui_color_name(fState->which_low_color);
6069 if (colorName != NULL && message->FindColor(colorName, &color) == B_OK) {
6070 fState->low_color = tint_color(color, fState->which_low_color_tint);
6071 fState->valid_flags |= B_VIEW_LOW_COLOR_BIT;
6074 colorName = ui_color_name(fState->which_high_color);
6075 if (colorName != NULL && message->FindColor(colorName, &color) == B_OK) {
6076 fState->high_color = tint_color(color, fState->which_high_color_tint);
6077 fState->valid_flags |= B_VIEW_HIGH_COLOR_BIT;
6080 MessageReceived(message);
6082 for (BView* child = fFirstChild; child != NULL;
6083 child = child->fNextSibling)
6084 child->_ColorsUpdated(message);
6086 Invalidate();
6090 void
6091 BView::_Detach()
6093 DetachedFromWindow();
6094 fAttached = false;
6096 for (BView* child = fFirstChild; child != NULL;
6097 child = child->fNextSibling) {
6098 child->_Detach();
6101 AllDetached();
6103 if (fOwner) {
6104 _CheckLock();
6106 if (!fOwner->IsHidden())
6107 Invalidate();
6109 // make sure our owner doesn't need us anymore
6111 if (fOwner->CurrentFocus() == this) {
6112 MakeFocus(false);
6113 // MakeFocus() is virtual and might not be
6114 // passing through to the BView version,
6115 // but we need to make sure at this point
6116 // that we are not the focus view anymore.
6117 if (fOwner->CurrentFocus() == this)
6118 fOwner->_SetFocus(NULL, true);
6121 if (fOwner->fDefaultButton == this)
6122 fOwner->SetDefaultButton(NULL);
6124 if (fOwner->fKeyMenuBar == this)
6125 fOwner->fKeyMenuBar = NULL;
6127 if (fOwner->fLastMouseMovedView == this)
6128 fOwner->fLastMouseMovedView = NULL;
6130 if (fOwner->fLastViewToken == _get_object_token_(this))
6131 fOwner->fLastViewToken = B_NULL_TOKEN;
6133 _SetOwner(NULL);
6138 void
6139 BView::_Draw(BRect updateRect)
6141 if (IsHidden(this) || !(Flags() & B_WILL_DRAW))
6142 return;
6144 // NOTE: if ViewColor() == B_TRANSPARENT_COLOR and no B_WILL_DRAW
6145 // -> View is simply not drawn at all
6147 _SwitchServerCurrentView();
6149 ConvertFromScreen(&updateRect);
6151 // TODO: make states robust (the hook implementation could
6152 // mess things up if it uses non-matching Push- and PopState(),
6153 // we would not be guaranteed to still have the same state on
6154 // the stack after having called Draw())
6155 PushState();
6156 Draw(updateRect);
6157 PopState();
6158 Flush();
6162 void
6163 BView::_DrawAfterChildren(BRect updateRect)
6165 if (IsHidden(this) || !(Flags() & B_WILL_DRAW)
6166 || !(Flags() & B_DRAW_ON_CHILDREN))
6167 return;
6169 _SwitchServerCurrentView();
6171 ConvertFromScreen(&updateRect);
6173 // TODO: make states robust (see above)
6174 PushState();
6175 DrawAfterChildren(updateRect);
6176 PopState();
6177 Flush();
6181 void
6182 BView::_FontsUpdated(BMessage* message)
6184 MessageReceived(message);
6186 for (BView* child = fFirstChild; child != NULL;
6187 child = child->fNextSibling) {
6188 child->_FontsUpdated(message);
6193 void
6194 BView::_Pulse()
6196 if ((Flags() & B_PULSE_NEEDED) != 0)
6197 Pulse();
6199 for (BView* child = fFirstChild; child != NULL;
6200 child = child->fNextSibling) {
6201 child->_Pulse();
6206 void
6207 BView::_UpdateStateForRemove()
6209 // TODO: _CheckLockAndSwitchCurrent() would be good enough, no?
6210 if (!_CheckOwnerLockAndSwitchCurrent())
6211 return;
6213 fState->UpdateFrom(*fOwner->fLink);
6214 // if (!fState->IsValid(B_VIEW_FRAME_BIT)) {
6215 // fOwner->fLink->StartMessage(AS_VIEW_GET_COORD);
6217 // status_t code;
6218 // if (fOwner->fLink->FlushWithReply(code) == B_OK
6219 // && code == B_OK) {
6220 // fOwner->fLink->Read<BPoint>(&fParentOffset);
6221 // fOwner->fLink->Read<BRect>(&fBounds);
6222 // fState->valid_flags |= B_VIEW_FRAME_BIT;
6223 // }
6224 // }
6226 // update children as well
6228 for (BView* child = fFirstChild; child != NULL;
6229 child = child->fNextSibling) {
6230 if (child->fOwner)
6231 child->_UpdateStateForRemove();
6236 inline void
6237 BView::_UpdatePattern(::pattern pattern)
6239 if (fState->IsValid(B_VIEW_PATTERN_BIT) && pattern == fState->pattern)
6240 return;
6242 if (fOwner) {
6243 _CheckLockAndSwitchCurrent();
6245 fOwner->fLink->StartMessage(AS_VIEW_SET_PATTERN);
6246 fOwner->fLink->Attach< ::pattern>(pattern);
6248 fState->valid_flags |= B_VIEW_PATTERN_BIT;
6251 fState->pattern = pattern;
6255 void
6256 BView::_FlushIfNotInTransaction()
6258 if (!fOwner->fInTransaction) {
6259 fOwner->Flush();
6264 BShelf*
6265 BView::_Shelf() const
6267 return fShelf;
6271 void
6272 BView::_SetShelf(BShelf* shelf)
6274 if (fShelf != NULL && fOwner != NULL)
6275 fOwner->RemoveHandler(fShelf);
6277 fShelf = shelf;
6279 if (fShelf != NULL && fOwner != NULL)
6280 fOwner->AddHandler(fShelf);
6284 status_t
6285 BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect, BRect dstRect,
6286 uint32 followFlags, uint32 options)
6288 if (!_CheckOwnerLockAndSwitchCurrent())
6289 return B_ERROR;
6291 int32 serverToken = bitmap ? bitmap->_ServerToken() : -1;
6293 fOwner->fLink->StartMessage(AS_VIEW_SET_VIEW_BITMAP);
6294 fOwner->fLink->Attach<int32>(serverToken);
6295 fOwner->fLink->Attach<BRect>(srcRect);
6296 fOwner->fLink->Attach<BRect>(dstRect);
6297 fOwner->fLink->Attach<int32>(followFlags);
6298 fOwner->fLink->Attach<int32>(options);
6300 status_t status = B_ERROR;
6301 fOwner->fLink->FlushWithReply(status);
6303 return status;
6307 bool
6308 BView::_CheckOwnerLockAndSwitchCurrent() const
6310 STRACE(("BView(%s)::_CheckOwnerLockAndSwitchCurrent()\n", Name()));
6312 if (fOwner == NULL) {
6313 debugger("View method requires owner and doesn't have one.");
6314 return false;
6317 _CheckLockAndSwitchCurrent();
6319 return true;
6323 bool
6324 BView::_CheckOwnerLock() const
6326 if (fOwner) {
6327 fOwner->check_lock();
6328 return true;
6329 } else {
6330 debugger("View method requires owner and doesn't have one.");
6331 return false;
6336 void
6337 BView::_CheckLockAndSwitchCurrent() const
6339 STRACE(("BView(%s)::_CheckLockAndSwitchCurrent()\n", Name()));
6341 if (!fOwner)
6342 return;
6344 fOwner->check_lock();
6346 _SwitchServerCurrentView();
6350 void
6351 BView::_CheckLock() const
6353 if (fOwner)
6354 fOwner->check_lock();
6358 void
6359 BView::_SwitchServerCurrentView() const
6361 int32 serverToken = _get_object_token_(this);
6363 if (fOwner->fLastViewToken != serverToken) {
6364 STRACE(("contacting app_server... sending token: %" B_PRId32 "\n",
6365 serverToken));
6366 fOwner->fLink->StartMessage(AS_SET_CURRENT_VIEW);
6367 fOwner->fLink->Attach<int32>(serverToken);
6369 fOwner->fLastViewToken = serverToken;
6374 status_t
6375 BView::ScrollWithMouseWheelDelta(BScrollBar* scrollBar, float delta)
6377 if (scrollBar == NULL || delta == 0.0f)
6378 return B_BAD_VALUE;
6380 float smallStep;
6381 float largeStep;
6382 scrollBar->GetSteps(&smallStep, &largeStep);
6384 // pressing the shift key scrolls faster (following the pseudo-standard set
6385 // by other desktop environments).
6386 if ((modifiers() & B_SHIFT_KEY) != 0)
6387 delta *= largeStep;
6388 else
6389 delta *= smallStep * 3;
6391 scrollBar->SetValue(scrollBar->Value() + delta);
6393 return B_OK;
6397 #if __GNUC__ == 2
6400 extern "C" void
6401 _ReservedView1__5BView(BView* view, BRect rect)
6403 view->BView::DrawAfterChildren(rect);
6407 extern "C" void
6408 _ReservedView2__5BView(BView* view)
6410 // MinSize()
6411 perform_data_min_size data;
6412 view->Perform(PERFORM_CODE_MIN_SIZE, &data);
6416 extern "C" void
6417 _ReservedView3__5BView(BView* view)
6419 // MaxSize()
6420 perform_data_max_size data;
6421 view->Perform(PERFORM_CODE_MAX_SIZE, &data);
6425 extern "C" BSize
6426 _ReservedView4__5BView(BView* view)
6428 // PreferredSize()
6429 perform_data_preferred_size data;
6430 view->Perform(PERFORM_CODE_PREFERRED_SIZE, &data);
6431 return data.return_value;
6435 extern "C" BAlignment
6436 _ReservedView5__5BView(BView* view)
6438 // LayoutAlignment()
6439 perform_data_layout_alignment data;
6440 view->Perform(PERFORM_CODE_LAYOUT_ALIGNMENT, &data);
6441 return data.return_value;
6445 extern "C" bool
6446 _ReservedView6__5BView(BView* view)
6448 // HasHeightForWidth()
6449 perform_data_has_height_for_width data;
6450 view->Perform(PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH, &data);
6451 return data.return_value;
6455 extern "C" void
6456 _ReservedView7__5BView(BView* view, float width, float* min, float* max,
6457 float* preferred)
6459 // GetHeightForWidth()
6460 perform_data_get_height_for_width data;
6461 data.width = width;
6462 view->Perform(PERFORM_CODE_GET_HEIGHT_FOR_WIDTH, &data);
6463 if (min != NULL)
6464 *min = data.min;
6465 if (max != NULL)
6466 *max = data.max;
6467 if (preferred != NULL)
6468 *preferred = data.preferred;
6472 extern "C" void
6473 _ReservedView8__5BView(BView* view, BLayout* layout)
6475 // SetLayout()
6476 perform_data_set_layout data;
6477 data.layout = layout;
6478 view->Perform(PERFORM_CODE_SET_LAYOUT, &data);
6482 extern "C" void
6483 _ReservedView9__5BView(BView* view, bool descendants)
6485 // LayoutInvalidated()
6486 perform_data_layout_invalidated data;
6487 data.descendants = descendants;
6488 view->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data);
6492 extern "C" void
6493 _ReservedView10__5BView(BView* view)
6495 // DoLayout()
6496 view->Perform(PERFORM_CODE_DO_LAYOUT, NULL);
6500 #endif // __GNUC__ == 2
6503 extern "C" bool
6504 B_IF_GCC_2(_ReservedView11__5BView, _ZN5BView15_ReservedView11Ev)(
6505 BView* view, BPoint point, BToolTip** _toolTip)
6507 // GetToolTipAt()
6508 perform_data_get_tool_tip_at data;
6509 data.point = point;
6510 data.tool_tip = _toolTip;
6511 view->Perform(PERFORM_CODE_GET_TOOL_TIP_AT, &data);
6512 return data.return_value;
6516 extern "C" void
6517 B_IF_GCC_2(_ReservedView12__5BView, _ZN5BView15_ReservedView12Ev)(
6518 BView* view)
6520 // LayoutChanged();
6521 view->Perform(PERFORM_CODE_LAYOUT_CHANGED, NULL);
6525 void BView::_ReservedView13() {}
6526 void BView::_ReservedView14() {}
6527 void BView::_ReservedView15() {}
6528 void BView::_ReservedView16() {}
6531 BView::BView(const BView& other)
6533 BHandler()
6535 // this is private and not functional, but exported
6539 BView&
6540 BView::operator=(const BView& other)
6542 // this is private and not functional, but exported
6543 return *this;
6547 void
6548 BView::_PrintToStream()
6550 printf("BView::_PrintToStream()\n");
6551 printf("\tName: %s\n"
6552 "\tParent: %s\n"
6553 "\tFirstChild: %s\n"
6554 "\tNextSibling: %s\n"
6555 "\tPrevSibling: %s\n"
6556 "\tOwner(Window): %s\n"
6557 "\tToken: %" B_PRId32 "\n"
6558 "\tFlags: %" B_PRId32 "\n"
6559 "\tView origin: (%f,%f)\n"
6560 "\tView Bounds rectangle: (%f,%f,%f,%f)\n"
6561 "\tShow level: %d\n"
6562 "\tTopView?: %s\n"
6563 "\tBPicture: %s\n"
6564 "\tVertical Scrollbar %s\n"
6565 "\tHorizontal Scrollbar %s\n"
6566 "\tIs Printing?: %s\n"
6567 "\tShelf?: %s\n"
6568 "\tEventMask: %" B_PRId32 "\n"
6569 "\tEventOptions: %" B_PRId32 "\n",
6570 Name(),
6571 fParent ? fParent->Name() : "NULL",
6572 fFirstChild ? fFirstChild->Name() : "NULL",
6573 fNextSibling ? fNextSibling->Name() : "NULL",
6574 fPreviousSibling ? fPreviousSibling->Name() : "NULL",
6575 fOwner ? fOwner->Name() : "NULL",
6576 _get_object_token_(this),
6577 fFlags,
6578 fParentOffset.x, fParentOffset.y,
6579 fBounds.left, fBounds.top, fBounds.right, fBounds.bottom,
6580 fShowLevel,
6581 fTopLevelView ? "YES" : "NO",
6582 fCurrentPicture? "YES" : "NULL",
6583 fVerScroller? "YES" : "NULL",
6584 fHorScroller? "YES" : "NULL",
6585 fIsPrinting? "YES" : "NO",
6586 fShelf? "YES" : "NO",
6587 fEventMask,
6588 fEventOptions);
6590 printf("\tState status:\n"
6591 "\t\tLocalCoordianteSystem: (%f,%f)\n"
6592 "\t\tPenLocation: (%f,%f)\n"
6593 "\t\tPenSize: %f\n"
6594 "\t\tHighColor: [%d,%d,%d,%d]\n"
6595 "\t\tLowColor: [%d,%d,%d,%d]\n"
6596 "\t\tViewColor: [%d,%d,%d,%d]\n"
6597 "\t\tPattern: %" B_PRIx64 "\n"
6598 "\t\tDrawingMode: %d\n"
6599 "\t\tLineJoinMode: %d\n"
6600 "\t\tLineCapMode: %d\n"
6601 "\t\tMiterLimit: %f\n"
6602 "\t\tAlphaSource: %d\n"
6603 "\t\tAlphaFuntion: %d\n"
6604 "\t\tScale: %f\n"
6605 "\t\t(Print)FontAliasing: %s\n"
6606 "\t\tFont Info:\n",
6607 fState->origin.x, fState->origin.y,
6608 fState->pen_location.x, fState->pen_location.y,
6609 fState->pen_size,
6610 fState->high_color.red, fState->high_color.blue, fState->high_color.green, fState->high_color.alpha,
6611 fState->low_color.red, fState->low_color.blue, fState->low_color.green, fState->low_color.alpha,
6612 fState->view_color.red, fState->view_color.blue, fState->view_color.green, fState->view_color.alpha,
6613 *((uint64*)&(fState->pattern)),
6614 fState->drawing_mode,
6615 fState->line_join,
6616 fState->line_cap,
6617 fState->miter_limit,
6618 fState->alpha_source_mode,
6619 fState->alpha_function_mode,
6620 fState->scale,
6621 fState->font_aliasing? "YES" : "NO");
6623 fState->font.PrintToStream();
6625 // TODO: also print the line array.
6629 void
6630 BView::_PrintTree()
6632 int32 spaces = 2;
6633 BView* c = fFirstChild; //c = short for: current
6634 printf( "'%s'\n", Name() );
6635 if (c != NULL) {
6636 while(true) {
6637 // action block
6639 for (int i = 0; i < spaces; i++)
6640 printf(" ");
6642 printf( "'%s'\n", c->Name() );
6645 // go deep
6646 if (c->fFirstChild) {
6647 c = c->fFirstChild;
6648 spaces += 2;
6649 } else {
6650 // go right
6651 if (c->fNextSibling) {
6652 c = c->fNextSibling;
6653 } else {
6654 // go up
6655 while (!c->fParent->fNextSibling && c->fParent != this) {
6656 c = c->fParent;
6657 spaces -= 2;
6660 // that enough! We've reached this view.
6661 if (c->fParent == this)
6662 break;
6664 c = c->fParent->fNextSibling;
6665 spaces -= 2;
6673 // #pragma mark -
6676 BLayoutItem*
6677 BView::Private::LayoutItemAt(int32 index)
6679 return fView->fLayoutData->fLayoutItems.ItemAt(index);
6683 int32
6684 BView::Private::CountLayoutItems()
6686 return fView->fLayoutData->fLayoutItems.CountItems();
6690 void
6691 BView::Private::RegisterLayoutItem(BLayoutItem* item)
6693 fView->fLayoutData->fLayoutItems.AddItem(item);
6697 void
6698 BView::Private::DeregisterLayoutItem(BLayoutItem* item)
6700 fView->fLayoutData->fLayoutItems.RemoveItem(item);
6704 bool
6705 BView::Private::MinMaxValid()
6707 return fView->fLayoutData->fMinMaxValid;
6711 bool
6712 BView::Private::WillLayout()
6714 BView::LayoutData* data = fView->fLayoutData;
6715 if (data->fLayoutInProgress)
6716 return false;
6717 if (data->fNeedsRelayout || !data->fLayoutValid || !data->fMinMaxValid)
6718 return true;
6719 return false;