Ticket #6761: View.cpp

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