1 /*
2 * Copyright 2006-2016 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 * Marc Flerackers, mflerackers@androme.be
8 * John Scipione, jscipione@gmail.com
9 * Ingo Weinhold, bonefish@cs.tu-berlin.de
10 */
11
12
13 #include <MenuField.h>
14
15 #include <algorithm>
16
17 #include <stdio.h>
18 // for printf in TRACE
19 #include <stdlib.h>
20 #include <string.h>
21
22 #include <AbstractLayoutItem.h>
23 #include <Archivable.h>
24 #include <BMCPrivate.h>
25 #include <ControlLook.h>
26 #include <LayoutUtils.h>
27 #include <MenuBar.h>
28 #include <MenuItem.h>
29 #include <MenuItemPrivate.h>
30 #include <MenuPrivate.h>
31 #include <Message.h>
32 #include <MessageFilter.h>
33 #include <Window.h>
34
35 #include <binary_compatibility/Interface.h>
36 #include <binary_compatibility/Support.h>
37
38
39 #ifdef CALLED
40 # undef CALLED
41 #endif
42 #ifdef TRACE
43 # undef TRACE
44 #endif
45
46 //#define TRACE_MENU_FIELD
47 #ifdef TRACE_MENU_FIELD
48 # include <FunctionTracer.h>
49 static int32 sFunctionDepth = -1;
50 # define CALLED(x...) FunctionTracer _ft("BMenuField", __FUNCTION__, \
51 sFunctionDepth)
52 # define TRACE(x...) { BString _to; \
53 _to.Append(' ', (sFunctionDepth + 1) * 2); \
54 printf("%s", _to.String()); printf(x); }
55 #else
56 # define CALLED(x...)
57 # define TRACE(x...)
58 #endif
59
60
61 static const float kMinMenuBarWidth = 20.0f;
62 // found by experimenting on BeOS R5
63
64
65 namespace {
66 const char* const kFrameField = "BMenuField:layoutItem:frame";
67 const char* const kMenuBarItemField = "BMenuField:barItem";
68 const char* const kLabelItemField = "BMenuField:labelItem";
69 }
70
71
72 // #pragma mark - LabelLayoutItem
73
74
75 class BMenuField::LabelLayoutItem : public BAbstractLayoutItem {
76 public:
77 LabelLayoutItem(BMenuField* parent);
78 LabelLayoutItem(BMessage* archive);
79
80 BRect FrameInParent() const;
81
82 virtual bool IsVisible();
83 virtual void SetVisible(bool visible);
84
85 virtual BRect Frame();
86 virtual void SetFrame(BRect frame);
87
88 void SetParent(BMenuField* parent);
89 virtual BView* View();
90
91 virtual BSize BaseMinSize();
92 virtual BSize BaseMaxSize();
93 virtual BSize BasePreferredSize();
94 virtual BAlignment BaseAlignment();
95
96 virtual status_t Archive(BMessage* into, bool deep = true) const;
97 static BArchivable* Instantiate(BMessage* from);
98
99 private:
100 BMenuField* fParent;
101 BRect fFrame;
102 };
103
104
105 // #pragma mark - MenuBarLayoutItem
106
107
108 class BMenuField::MenuBarLayoutItem : public BAbstractLayoutItem {
109 public:
110 MenuBarLayoutItem(BMenuField* parent);
111 MenuBarLayoutItem(BMessage* from);
112
113 BRect FrameInParent() const;
114
115 virtual bool IsVisible();
116 virtual void SetVisible(bool visible);
117
118 virtual BRect Frame();
119 virtual void SetFrame(BRect frame);
120
121 void SetParent(BMenuField* parent);
122 virtual BView* View();
123
124 virtual BSize BaseMinSize();
125 virtual BSize BaseMaxSize();
126 virtual BSize BasePreferredSize();
127 virtual BAlignment BaseAlignment();
128
129 virtual status_t Archive(BMessage* into, bool deep = true) const;
130 static BArchivable* Instantiate(BMessage* from);
131
132 private:
133 BMenuField* fParent;
134 BRect fFrame;
135 };
136
137
138 // #pragma mark - LayoutData
139
140
141 struct BMenuField::LayoutData {
LayoutDataBMenuField::LayoutData142 LayoutData()
143 :
144 label_layout_item(NULL),
145 menu_bar_layout_item(NULL),
146 previous_height(-1),
147 valid(false)
148 {
149 }
150
151 LabelLayoutItem* label_layout_item;
152 MenuBarLayoutItem* menu_bar_layout_item;
153 float previous_height; // used in FrameResized() for
154 // invalidation
155 font_height font_info;
156 float label_width;
157 float label_height;
158 BSize min;
159 BSize menu_bar_min;
160 bool valid;
161 };
162
163
164 // #pragma mark - MouseDownFilter
165
166 namespace {
167
168 class MouseDownFilter : public BMessageFilter
169 {
170 public:
171 MouseDownFilter();
172 virtual ~MouseDownFilter();
173
174 virtual filter_result Filter(BMessage* message, BHandler** target);
175 };
176
177
MouseDownFilter()178 MouseDownFilter::MouseDownFilter()
179 :
180 BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE)
181 {
182 }
183
184
~MouseDownFilter()185 MouseDownFilter::~MouseDownFilter()
186 {
187 }
188
189
190 filter_result
Filter(BMessage * message,BHandler ** target)191 MouseDownFilter::Filter(BMessage* message, BHandler** target)
192 {
193 return message->what == B_MOUSE_DOWN ? B_SKIP_MESSAGE : B_DISPATCH_MESSAGE;
194 }
195
196 };
197
198
199
200 // #pragma mark - BMenuField
201
202
BMenuField(BRect frame,const char * name,const char * label,BMenu * menu,uint32 resizingMode,uint32 flags)203 BMenuField::BMenuField(BRect frame, const char* name, const char* label,
204 BMenu* menu, uint32 resizingMode, uint32 flags)
205 :
206 BView(frame, name, resizingMode, flags)
207 {
208 CALLED();
209
210 TRACE("frame.width: %.2f, height: %.2f\n", frame.Width(), frame.Height());
211
212 InitObject(label);
213
214 frame.OffsetTo(B_ORIGIN);
215 _InitMenuBar(menu, frame, false);
216
217 InitObject2();
218 }
219
220
BMenuField(BRect frame,const char * name,const char * label,BMenu * menu,bool fixedSize,uint32 resizingMode,uint32 flags)221 BMenuField::BMenuField(BRect frame, const char* name, const char* label,
222 BMenu* menu, bool fixedSize, uint32 resizingMode, uint32 flags)
223 :
224 BView(frame, name, resizingMode, flags)
225 {
226 InitObject(label);
227
228 fFixedSizeMB = fixedSize;
229
230 frame.OffsetTo(B_ORIGIN);
231 _InitMenuBar(menu, frame, fixedSize);
232
233 InitObject2();
234 }
235
236
BMenuField(const char * name,const char * label,BMenu * menu,uint32 flags)237 BMenuField::BMenuField(const char* name, const char* label, BMenu* menu,
238 uint32 flags)
239 :
240 BView(name, flags | B_FRAME_EVENTS)
241 {
242 InitObject(label);
243
244 _InitMenuBar(menu, BRect(0, 0, 100, 15), true);
245
246 InitObject2();
247 }
248
249
BMenuField(const char * name,const char * label,BMenu * menu,bool fixedSize,uint32 flags)250 BMenuField::BMenuField(const char* name, const char* label, BMenu* menu,
251 bool fixedSize, uint32 flags)
252 :
253 BView(name, flags | B_FRAME_EVENTS)
254 {
255 InitObject(label);
256
257 fFixedSizeMB = fixedSize;
258
259 _InitMenuBar(menu, BRect(0, 0, 100, 15), fixedSize);
260
261 InitObject2();
262 }
263
264
BMenuField(const char * label,BMenu * menu,uint32 flags)265 BMenuField::BMenuField(const char* label, BMenu* menu, uint32 flags)
266 :
267 BView(NULL, flags | B_FRAME_EVENTS)
268 {
269 InitObject(label);
270
271 _InitMenuBar(menu, BRect(0, 0, 100, 15), true);
272
273 InitObject2();
274 }
275
276
BMenuField(BMessage * data)277 BMenuField::BMenuField(BMessage* data)
278 :
279 BView(BUnarchiver::PrepareArchive(data))
280 {
281 BUnarchiver unarchiver(data);
282 const char* label = NULL;
283 data->FindString("_label", &label);
284
285 InitObject(label);
286
287 data->FindFloat("_divide", &fDivider);
288
289 int32 align;
290 if (data->FindInt32("_align", &align) == B_OK)
291 SetAlignment((alignment)align);
292
293 if (!BUnarchiver::IsArchiveManaged(data))
294 _InitMenuBar(data);
295
296 unarchiver.Finish();
297 }
298
299
~BMenuField()300 BMenuField::~BMenuField()
301 {
302 free(fLabel);
303
304 status_t dummy;
305 if (fMenuTaskID >= 0)
306 wait_for_thread(fMenuTaskID, &dummy);
307
308 delete fLayoutData;
309 delete fMouseDownFilter;
310 }
311
312
313 BArchivable*
Instantiate(BMessage * data)314 BMenuField::Instantiate(BMessage* data)
315 {
316 if (validate_instantiation(data, "BMenuField"))
317 return new BMenuField(data);
318
319 return NULL;
320 }
321
322
323 status_t
Archive(BMessage * data,bool deep) const324 BMenuField::Archive(BMessage* data, bool deep) const
325 {
326 BArchiver archiver(data);
327 status_t ret = BView::Archive(data, deep);
328
329 if (ret == B_OK && Label())
330 ret = data->AddString("_label", Label());
331
332 if (ret == B_OK && !IsEnabled())
333 ret = data->AddBool("_disable", true);
334
335 if (ret == B_OK)
336 ret = data->AddInt32("_align", Alignment());
337 if (ret == B_OK)
338 ret = data->AddFloat("_divide", Divider());
339
340 if (ret == B_OK && fFixedSizeMB)
341 ret = data->AddBool("be:fixeds", true);
342
343 bool dmark = false;
344 if (_BMCMenuBar_* menuBar = dynamic_cast<_BMCMenuBar_*>(fMenuBar))
345 dmark = menuBar->IsPopUpMarkerShown();
346
347 data->AddBool("be:dmark", dmark);
348
349 return archiver.Finish(ret);
350 }
351
352
353 status_t
AllArchived(BMessage * into) const354 BMenuField::AllArchived(BMessage* into) const
355 {
356 status_t err;
357 if ((err = BView::AllArchived(into)) != B_OK)
358 return err;
359
360 BArchiver archiver(into);
361
362 BArchivable* menuBarItem = fLayoutData->menu_bar_layout_item;
363 if (archiver.IsArchived(menuBarItem))
364 err = archiver.AddArchivable(kMenuBarItemField, menuBarItem);
365
366 if (err != B_OK)
367 return err;
368
369 BArchivable* labelBarItem = fLayoutData->label_layout_item;
370 if (archiver.IsArchived(labelBarItem))
371 err = archiver.AddArchivable(kLabelItemField, labelBarItem);
372
373 return err;
374 }
375
376
377 status_t
AllUnarchived(const BMessage * from)378 BMenuField::AllUnarchived(const BMessage* from)
379 {
380 BUnarchiver unarchiver(from);
381
382 status_t err = B_OK;
383 if ((err = BView::AllUnarchived(from)) != B_OK)
384 return err;
385
386 _InitMenuBar(from);
387
388 if (unarchiver.IsInstantiated(kMenuBarItemField)) {
389 MenuBarLayoutItem*& menuItem = fLayoutData->menu_bar_layout_item;
390 err = unarchiver.FindObject(kMenuBarItemField,
391 BUnarchiver::B_DONT_ASSUME_OWNERSHIP, menuItem);
392
393 if (err == B_OK)
394 menuItem->SetParent(this);
395 else
396 return err;
397 }
398
399 if (unarchiver.IsInstantiated(kLabelItemField)) {
400 LabelLayoutItem*& labelItem = fLayoutData->label_layout_item;
401 err = unarchiver.FindObject(kLabelItemField,
402 BUnarchiver::B_DONT_ASSUME_OWNERSHIP, labelItem);
403
404 if (err == B_OK)
405 labelItem->SetParent(this);
406 }
407
408 return err;
409 }
410
411
412 void
Draw(BRect updateRect)413 BMenuField::Draw(BRect updateRect)
414 {
415 _DrawLabel(updateRect);
416 _DrawMenuBar(updateRect);
417 }
418
419
420 void
AttachedToWindow()421 BMenuField::AttachedToWindow()
422 {
423 CALLED();
424
425 // Our low color must match the parent's view color.
426 if (Parent() != NULL) {
427 AdoptParentColors();
428
429 float tint = B_NO_TINT;
430 color_which which = ViewUIColor(&tint);
431
432 if (which == B_NO_COLOR)
433 SetLowColor(ViewColor());
434 else
435 SetLowUIColor(which, tint);
436 } else
437 AdoptSystemColors();
438 }
439
440
441 void
AllAttached()442 BMenuField::AllAttached()
443 {
444 CALLED();
445
446 TRACE("width: %.2f, height: %.2f\n", Frame().Width(), Frame().Height());
447
448 float width = Bounds().Width();
449 if (!fFixedSizeMB && _MenuBarWidth() < kMinMenuBarWidth) {
450 // The menu bar is too narrow, resize it to fit the menu items
451 BMenuItem* item = fMenuBar->ItemAt(0);
452 if (item != NULL) {
453 float right;
454 fMenuBar->GetItemMargins(NULL, NULL, &right, NULL);
455 width = item->Frame().Width() + kVMargin + _MenuBarOffset() + right;
456 }
457 }
458
459 ResizeTo(width, fMenuBar->Bounds().Height() + kVMargin * 2);
460
461 TRACE("width: %.2f, height: %.2f\n", Frame().Width(), Frame().Height());
462 }
463
464
465 void
MouseDown(BPoint where)466 BMenuField::MouseDown(BPoint where)
467 {
468 BRect bounds = fMenuBar->ConvertFromParent(Bounds());
469
470 fMenuBar->StartMenuBar(-1, false, true, &bounds);
471
472 fMenuTaskID = spawn_thread((thread_func)_thread_entry,
473 "_m_task_", B_NORMAL_PRIORITY, this);
474 if (fMenuTaskID >= 0 && resume_thread(fMenuTaskID) == B_OK) {
475 if (fMouseDownFilter->Looper() == NULL)
476 Window()->AddCommonFilter(fMouseDownFilter);
477
478 SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
479 }
480 }
481
482
483 void
KeyDown(const char * bytes,int32 numBytes)484 BMenuField::KeyDown(const char* bytes, int32 numBytes)
485 {
486 switch (bytes[0]) {
487 case B_SPACE:
488 case B_RIGHT_ARROW:
489 case B_DOWN_ARROW:
490 {
491 if (!IsEnabled())
492 break;
493
494 BRect bounds = fMenuBar->ConvertFromParent(Bounds());
495
496 fMenuBar->StartMenuBar(0, true, true, &bounds);
497
498 bounds = Bounds();
499 bounds.right = fDivider;
500
501 Invalidate(bounds);
502 }
503
504 default:
505 BView::KeyDown(bytes, numBytes);
506 }
507 }
508
509
510 void
MakeFocus(bool focused)511 BMenuField::MakeFocus(bool focused)
512 {
513 if (IsFocus() == focused)
514 return;
515
516 BView::MakeFocus(focused);
517
518 if (Window() != NULL)
519 Invalidate(); // TODO: use fLayoutData->label_width
520 }
521
522
523 void
MessageReceived(BMessage * message)524 BMenuField::MessageReceived(BMessage* message)
525 {
526 BView::MessageReceived(message);
527 }
528
529
530 void
WindowActivated(bool active)531 BMenuField::WindowActivated(bool active)
532 {
533 BView::WindowActivated(active);
534
535 if (IsFocus())
536 Invalidate();
537 }
538
539
540 void
MouseMoved(BPoint point,uint32 code,const BMessage * message)541 BMenuField::MouseMoved(BPoint point, uint32 code, const BMessage* message)
542 {
543 BView::MouseMoved(point, code, message);
544 }
545
546
547 void
MouseUp(BPoint where)548 BMenuField::MouseUp(BPoint where)
549 {
550 Window()->RemoveCommonFilter(fMouseDownFilter);
551 BView::MouseUp(where);
552 }
553
554
555 void
DetachedFromWindow()556 BMenuField::DetachedFromWindow()
557 {
558 BView::DetachedFromWindow();
559 }
560
561
562 void
AllDetached()563 BMenuField::AllDetached()
564 {
565 BView::AllDetached();
566 }
567
568
569 void
FrameMoved(BPoint newPosition)570 BMenuField::FrameMoved(BPoint newPosition)
571 {
572 BView::FrameMoved(newPosition);
573 }
574
575
576 void
FrameResized(float newWidth,float newHeight)577 BMenuField::FrameResized(float newWidth, float newHeight)
578 {
579 BView::FrameResized(newWidth, newHeight);
580
581 if (fFixedSizeMB) {
582 // we have let the menubar resize itself, but
583 // in fixed size mode, the menubar is supposed to
584 // be at the right end of the view always. Since
585 // the menu bar is in follow left/right mode then,
586 // resizing ourselfs might have caused the menubar
587 // to be outside now
588 fMenuBar->ResizeTo(_MenuBarWidth(), fMenuBar->Frame().Height());
589 }
590
591 if (newHeight != fLayoutData->previous_height && Label()) {
592 // The height changed, which means the label has to move and we
593 // probably also invalidate a part of the borders around the menu bar.
594 // So don't be shy and invalidate the whole thing.
595 Invalidate();
596 }
597
598 fLayoutData->previous_height = newHeight;
599 }
600
601
602 BMenu*
Menu() const603 BMenuField::Menu() const
604 {
605 return fMenu;
606 }
607
608
609 BMenuBar*
MenuBar() const610 BMenuField::MenuBar() const
611 {
612 return fMenuBar;
613 }
614
615
616 BMenuItem*
MenuItem() const617 BMenuField::MenuItem() const
618 {
619 return fMenuBar->ItemAt(0);
620 }
621
622
623 void
SetLabel(const char * label)624 BMenuField::SetLabel(const char* label)
625 {
626 if (fLabel) {
627 if (label && strcmp(fLabel, label) == 0)
628 return;
629
630 free(fLabel);
631 }
632
633 fLabel = strdup(label);
634
635 if (Window())
636 Invalidate();
637
638 InvalidateLayout();
639 }
640
641
642 const char*
Label() const643 BMenuField::Label() const
644 {
645 return fLabel;
646 }
647
648
649 void
SetEnabled(bool on)650 BMenuField::SetEnabled(bool on)
651 {
652 if (fEnabled == on)
653 return;
654
655 fEnabled = on;
656 fMenuBar->SetEnabled(on);
657
658 if (Window()) {
659 fMenuBar->Invalidate(fMenuBar->Bounds());
660 Invalidate(Bounds());
661 }
662 }
663
664
665 bool
IsEnabled() const666 BMenuField::IsEnabled() const
667 {
668 return fEnabled;
669 }
670
671
672 void
SetAlignment(alignment label)673 BMenuField::SetAlignment(alignment label)
674 {
675 fAlign = label;
676 }
677
678
679 alignment
Alignment() const680 BMenuField::Alignment() const
681 {
682 return fAlign;
683 }
684
685
686 void
SetDivider(float position)687 BMenuField::SetDivider(float position)
688 {
689 position = roundf(position);
690
691 float delta = fDivider - position;
692 if (delta == 0.0f)
693 return;
694
695 fDivider = position;
696
697 if ((Flags() & B_SUPPORTS_LAYOUT) != 0) {
698 // We should never get here, since layout support means, we also
699 // layout the divider, and don't use this method at all.
700 Relayout();
701 } else {
702 BRect dirty(fMenuBar->Frame());
703
704 fMenuBar->MoveTo(_MenuBarOffset(), kVMargin);
705
706 if (fFixedSizeMB)
707 fMenuBar->ResizeTo(_MenuBarWidth(), dirty.Height());
708
709 dirty = dirty | fMenuBar->Frame();
710 dirty.InsetBy(-kVMargin, -kVMargin);
711
712 Invalidate(dirty);
713 }
714 }
715
716
717 float
Divider() const718 BMenuField::Divider() const
719 {
720 return fDivider;
721 }
722
723
724 void
ShowPopUpMarker()725 BMenuField::ShowPopUpMarker()
726 {
727 if (_BMCMenuBar_* menuBar = dynamic_cast<_BMCMenuBar_*>(fMenuBar)) {
728 menuBar->TogglePopUpMarker(true);
729 menuBar->Invalidate();
730 }
731 }
732
733
734 void
HidePopUpMarker()735 BMenuField::HidePopUpMarker()
736 {
737 if (_BMCMenuBar_* menuBar = dynamic_cast<_BMCMenuBar_*>(fMenuBar)) {
738 menuBar->TogglePopUpMarker(false);
739 menuBar->Invalidate();
740 }
741 }
742
743
744 BHandler*
ResolveSpecifier(BMessage * message,int32 index,BMessage * specifier,int32 form,const char * property)745 BMenuField::ResolveSpecifier(BMessage* message, int32 index,
746 BMessage* specifier, int32 form, const char* property)
747 {
748 return BView::ResolveSpecifier(message, index, specifier, form, property);
749 }
750
751
752 status_t
GetSupportedSuites(BMessage * data)753 BMenuField::GetSupportedSuites(BMessage* data)
754 {
755 return BView::GetSupportedSuites(data);
756 }
757
758
759 void
ResizeToPreferred()760 BMenuField::ResizeToPreferred()
761 {
762 CALLED();
763
764 TRACE("fMenuBar->Frame().width: %.2f, height: %.2f\n",
765 fMenuBar->Frame().Width(), fMenuBar->Frame().Height());
766
767 fMenuBar->ResizeToPreferred();
768
769 TRACE("fMenuBar->Frame().width: %.2f, height: %.2f\n",
770 fMenuBar->Frame().Width(), fMenuBar->Frame().Height());
771
772 BView::ResizeToPreferred();
773
774 Invalidate();
775 }
776
777
778 void
GetPreferredSize(float * _width,float * _height)779 BMenuField::GetPreferredSize(float* _width, float* _height)
780 {
781 CALLED();
782
783 _ValidateLayoutData();
784
785 if (_width)
786 *_width = fLayoutData->min.width;
787
788 if (_height)
789 *_height = fLayoutData->min.height;
790 }
791
792
793 BSize
MinSize()794 BMenuField::MinSize()
795 {
796 CALLED();
797
798 _ValidateLayoutData();
799 return BLayoutUtils::ComposeSize(ExplicitMinSize(), fLayoutData->min);
800 }
801
802
803 BSize
MaxSize()804 BMenuField::MaxSize()
805 {
806 CALLED();
807
808 _ValidateLayoutData();
809
810 BSize max = fLayoutData->min;
811 max.width = B_SIZE_UNLIMITED;
812
813 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), max);
814 }
815
816
817 BSize
PreferredSize()818 BMenuField::PreferredSize()
819 {
820 CALLED();
821
822 _ValidateLayoutData();
823 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), fLayoutData->min);
824 }
825
826
827 BLayoutItem*
CreateLabelLayoutItem()828 BMenuField::CreateLabelLayoutItem()
829 {
830 if (fLayoutData->label_layout_item == NULL)
831 fLayoutData->label_layout_item = new LabelLayoutItem(this);
832
833 return fLayoutData->label_layout_item;
834 }
835
836
837 BLayoutItem*
CreateMenuBarLayoutItem()838 BMenuField::CreateMenuBarLayoutItem()
839 {
840 if (fLayoutData->menu_bar_layout_item == NULL) {
841 // align the menu bar in the full available space
842 fMenuBar->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH,
843 B_ALIGN_VERTICAL_UNSET));
844 fLayoutData->menu_bar_layout_item = new MenuBarLayoutItem(this);
845 }
846
847 return fLayoutData->menu_bar_layout_item;
848 }
849
850
851 status_t
Perform(perform_code code,void * _data)852 BMenuField::Perform(perform_code code, void* _data)
853 {
854 switch (code) {
855 case PERFORM_CODE_MIN_SIZE:
856 ((perform_data_min_size*)_data)->return_value
857 = BMenuField::MinSize();
858 return B_OK;
859
860 case PERFORM_CODE_MAX_SIZE:
861 ((perform_data_max_size*)_data)->return_value
862 = BMenuField::MaxSize();
863 return B_OK;
864
865 case PERFORM_CODE_PREFERRED_SIZE:
866 ((perform_data_preferred_size*)_data)->return_value
867 = BMenuField::PreferredSize();
868 return B_OK;
869
870 case PERFORM_CODE_LAYOUT_ALIGNMENT:
871 ((perform_data_layout_alignment*)_data)->return_value
872 = BMenuField::LayoutAlignment();
873 return B_OK;
874
875 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
876 ((perform_data_has_height_for_width*)_data)->return_value
877 = BMenuField::HasHeightForWidth();
878 return B_OK;
879
880 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
881 {
882 perform_data_get_height_for_width* data
883 = (perform_data_get_height_for_width*)_data;
884 BMenuField::GetHeightForWidth(data->width, &data->min, &data->max,
885 &data->preferred);
886 return B_OK;
887 }
888
889 case PERFORM_CODE_SET_LAYOUT:
890 {
891 perform_data_set_layout* data = (perform_data_set_layout*)_data;
892 BMenuField::SetLayout(data->layout);
893 return B_OK;
894 }
895
896 case PERFORM_CODE_LAYOUT_INVALIDATED:
897 {
898 perform_data_layout_invalidated* data
899 = (perform_data_layout_invalidated*)_data;
900 BMenuField::LayoutInvalidated(data->descendants);
901 return B_OK;
902 }
903
904 case PERFORM_CODE_DO_LAYOUT:
905 {
906 BMenuField::DoLayout();
907 return B_OK;
908 }
909
910 case PERFORM_CODE_ALL_UNARCHIVED:
911 {
912 perform_data_all_unarchived* data
913 = (perform_data_all_unarchived*)_data;
914 data->return_value = BMenuField::AllUnarchived(data->archive);
915 return B_OK;
916 }
917
918 case PERFORM_CODE_ALL_ARCHIVED:
919 {
920 perform_data_all_archived* data
921 = (perform_data_all_archived*)_data;
922 data->return_value = BMenuField::AllArchived(data->archive);
923 return B_OK;
924 }
925 }
926
927 return BView::Perform(code, _data);
928 }
929
930
931 void
LayoutInvalidated(bool descendants)932 BMenuField::LayoutInvalidated(bool descendants)
933 {
934 CALLED();
935
936 fLayoutData->valid = false;
937 }
938
939
940 void
DoLayout()941 BMenuField::DoLayout()
942 {
943 // Bail out, if we shan't do layout.
944 if ((Flags() & B_SUPPORTS_LAYOUT) == 0)
945 return;
946
947 CALLED();
948
949 // If the user set a layout, we let the base class version call its
950 // hook.
951 if (GetLayout() != NULL) {
952 BView::DoLayout();
953 return;
954 }
955
956 _ValidateLayoutData();
957
958 // validate current size
959 BSize size(Bounds().Size());
960 if (size.width < fLayoutData->min.width)
961 size.width = fLayoutData->min.width;
962
963 if (size.height < fLayoutData->min.height)
964 size.height = fLayoutData->min.height;
965
966 // divider
967 float divider = 0;
968 if (fLayoutData->label_layout_item != NULL
969 && fLayoutData->menu_bar_layout_item != NULL
970 && fLayoutData->label_layout_item->Frame().IsValid()
971 && fLayoutData->menu_bar_layout_item->Frame().IsValid()) {
972 // We have valid layout items, they define the divider location.
973 divider = fabs(fLayoutData->menu_bar_layout_item->Frame().left
974 - fLayoutData->label_layout_item->Frame().left);
975 } else if (fLayoutData->label_width > 0) {
976 divider = fLayoutData->label_width
977 + be_control_look->DefaultLabelSpacing();
978 }
979
980 // menu bar
981 BRect dirty(fMenuBar->Frame());
982 BRect menuBarFrame(divider + kVMargin, kVMargin, size.width - kVMargin,
983 size.height - kVMargin);
984
985 // place the menu bar and set the divider
986 BLayoutUtils::AlignInFrame(fMenuBar, menuBarFrame);
987
988 fDivider = divider;
989
990 // invalidate dirty region
991 dirty = dirty | fMenuBar->Frame();
992 dirty.InsetBy(-kVMargin, -kVMargin);
993
994 Invalidate(dirty);
995 }
996
997
_ReservedMenuField1()998 void BMenuField::_ReservedMenuField1() {}
_ReservedMenuField2()999 void BMenuField::_ReservedMenuField2() {}
_ReservedMenuField3()1000 void BMenuField::_ReservedMenuField3() {}
1001
1002
1003 void
InitObject(const char * label)1004 BMenuField::InitObject(const char* label)
1005 {
1006 CALLED();
1007
1008 fLabel = NULL;
1009 fMenu = NULL;
1010 fMenuBar = NULL;
1011 fAlign = B_ALIGN_LEFT;
1012 fEnabled = true;
1013 fFixedSizeMB = false;
1014 fMenuTaskID = -1;
1015 fLayoutData = new LayoutData;
1016 fMouseDownFilter = new MouseDownFilter();
1017
1018 SetLabel(label);
1019
1020 if (label)
1021 fDivider = floorf(Frame().Width() / 2.0f);
1022 else
1023 fDivider = 0;
1024 }
1025
1026
1027 void
InitObject2()1028 BMenuField::InitObject2()
1029 {
1030 CALLED();
1031
1032 if (!fFixedSizeMB) {
1033 float height;
1034 fMenuBar->GetPreferredSize(NULL, &height);
1035 fMenuBar->ResizeTo(_MenuBarWidth(), height);
1036 }
1037
1038 TRACE("frame(%.1f, %.1f, %.1f, %.1f) (%.2f, %.2f)\n",
1039 fMenuBar->Frame().left, fMenuBar->Frame().top,
1040 fMenuBar->Frame().right, fMenuBar->Frame().bottom,
1041 fMenuBar->Frame().Width(), fMenuBar->Frame().Height());
1042
1043 fMenuBar->AddFilter(new _BMCFilter_(this, B_MOUSE_DOWN));
1044 }
1045
1046
1047 void
_DrawLabel(BRect updateRect)1048 BMenuField::_DrawLabel(BRect updateRect)
1049 {
1050 CALLED();
1051
1052 _ValidateLayoutData();
1053
1054 const char* label = Label();
1055 if (label == NULL)
1056 return;
1057
1058 BRect rect;
1059 if (fLayoutData->label_layout_item != NULL)
1060 rect = fLayoutData->label_layout_item->FrameInParent();
1061 else {
1062 rect = Bounds();
1063 rect.right = fDivider;
1064 }
1065
1066 if (!rect.IsValid() || !rect.Intersects(updateRect))
1067 return;
1068
1069 uint32 flags = 0;
1070 if (!IsEnabled())
1071 flags |= BControlLook::B_DISABLED;
1072
1073 // save the current low color
1074 PushState();
1075 rgb_color textColor;
1076
1077 BPrivate::MenuPrivate menuPrivate(fMenuBar);
1078 if (menuPrivate.State() != MENU_STATE_CLOSED) {
1079 // highlight the background of the label grey (like BeOS R5)
1080 SetLowColor(ui_color(B_MENU_SELECTED_BACKGROUND_COLOR));
1081 BRect fillRect(rect.InsetByCopy(0, kVMargin));
1082 FillRect(fillRect, B_SOLID_LOW);
1083 textColor = ui_color(B_MENU_SELECTED_ITEM_TEXT_COLOR);
1084 } else
1085 textColor = ui_color(B_PANEL_TEXT_COLOR);
1086
1087 be_control_look->DrawLabel(this, label, rect, updateRect, LowColor(), flags,
1088 BAlignment(fAlign, B_ALIGN_MIDDLE), &textColor);
1089
1090 // restore the previous low color
1091 PopState();
1092 }
1093
1094
1095 void
_DrawMenuBar(BRect updateRect)1096 BMenuField::_DrawMenuBar(BRect updateRect)
1097 {
1098 CALLED();
1099
1100 BRect rect(fMenuBar->Frame().InsetByCopy(-kVMargin, -kVMargin));
1101 if (!rect.IsValid() || !rect.Intersects(updateRect))
1102 return;
1103
1104 uint32 flags = 0;
1105 if (!IsEnabled())
1106 flags |= BControlLook::B_DISABLED;
1107
1108 if (IsFocus() && Window()->IsActive())
1109 flags |= BControlLook::B_FOCUSED;
1110
1111 be_control_look->DrawMenuFieldFrame(this, rect, updateRect,
1112 fMenuBar->LowColor(), LowColor(), flags);
1113 }
1114
1115
1116 void
InitMenu(BMenu * menu)1117 BMenuField::InitMenu(BMenu* menu)
1118 {
1119 menu->SetFont(be_plain_font);
1120
1121 int32 index = 0;
1122 BMenu* subMenu;
1123
1124 while ((subMenu = menu->SubmenuAt(index++)) != NULL)
1125 InitMenu(subMenu);
1126 }
1127
1128
1129 /*static*/ int32
_thread_entry(void * arg)1130 BMenuField::_thread_entry(void* arg)
1131 {
1132 return static_cast<BMenuField*>(arg)->_MenuTask();
1133 }
1134
1135
1136 int32
_MenuTask()1137 BMenuField::_MenuTask()
1138 {
1139 if (!LockLooper())
1140 return 0;
1141
1142 Invalidate();
1143 UnlockLooper();
1144
1145 bool tracking;
1146 do {
1147 snooze(20000);
1148 if (!LockLooper())
1149 return 0;
1150
1151 tracking = fMenuBar->fTracking;
1152
1153 UnlockLooper();
1154 } while (tracking);
1155
1156 if (LockLooper()) {
1157 Invalidate();
1158 UnlockLooper();
1159 }
1160
1161 return 0;
1162 }
1163
1164
1165 void
_UpdateFrame()1166 BMenuField::_UpdateFrame()
1167 {
1168 CALLED();
1169
1170 if (fLayoutData->label_layout_item == NULL
1171 || fLayoutData->menu_bar_layout_item == NULL) {
1172 return;
1173 }
1174
1175 BRect labelFrame = fLayoutData->label_layout_item->Frame();
1176 BRect menuFrame = fLayoutData->menu_bar_layout_item->Frame();
1177
1178 if (!labelFrame.IsValid() || !menuFrame.IsValid())
1179 return;
1180
1181 // update divider
1182 fDivider = menuFrame.left - labelFrame.left;
1183
1184 // update our frame
1185 MoveTo(labelFrame.left, labelFrame.top);
1186 BSize oldSize = Bounds().Size();
1187 ResizeTo(menuFrame.left + menuFrame.Width() - labelFrame.left,
1188 menuFrame.top + menuFrame.Height() - labelFrame.top);
1189 BSize newSize = Bounds().Size();
1190
1191 // If the size changes, ResizeTo() will trigger a relayout, otherwise
1192 // we need to do that explicitly.
1193 if (newSize != oldSize)
1194 Relayout();
1195 }
1196
1197
1198 void
_InitMenuBar(BMenu * menu,BRect frame,bool fixedSize)1199 BMenuField::_InitMenuBar(BMenu* menu, BRect frame, bool fixedSize)
1200 {
1201 CALLED();
1202
1203 if ((Flags() & B_SUPPORTS_LAYOUT) != 0) {
1204 fMenuBar = new _BMCMenuBar_(this);
1205 } else {
1206 frame.left = _MenuBarOffset();
1207 frame.top = kVMargin;
1208 frame.right -= kVMargin;
1209 frame.bottom -= kVMargin;
1210
1211 TRACE("frame(%.1f, %.1f, %.1f, %.1f) (%.2f, %.2f)\n",
1212 frame.left, frame.top, frame.right, frame.bottom,
1213 frame.Width(), frame.Height());
1214
1215 fMenuBar = new _BMCMenuBar_(frame, fixedSize, this);
1216 }
1217
1218 if (fixedSize) {
1219 // align the menu bar in the full available space
1220 fMenuBar->SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH,
1221 B_ALIGN_VERTICAL_UNSET));
1222 } else {
1223 // align the menu bar left in the available space
1224 fMenuBar->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
1225 B_ALIGN_VERTICAL_UNSET));
1226 }
1227
1228 AddChild(fMenuBar);
1229
1230 _AddMenu(menu);
1231
1232 fMenuBar->SetFont(be_plain_font);
1233 }
1234
1235
1236 void
_InitMenuBar(const BMessage * archive)1237 BMenuField::_InitMenuBar(const BMessage* archive)
1238 {
1239 bool fixed;
1240 if (archive->FindBool("be:fixeds", &fixed) == B_OK)
1241 fFixedSizeMB = fixed;
1242
1243 fMenuBar = (BMenuBar*)FindView("_mc_mb_");
1244 if (fMenuBar == NULL) {
1245 _InitMenuBar(new BMenu(""), BRect(0, 0, 100, 15), fFixedSizeMB);
1246 InitObject2();
1247 } else {
1248 fMenuBar->AddFilter(new _BMCFilter_(this, B_MOUSE_DOWN));
1249 // this is normally done in InitObject2()
1250 }
1251
1252 _AddMenu(fMenuBar->SubmenuAt(0));
1253
1254 bool disable;
1255 if (archive->FindBool("_disable", &disable) == B_OK)
1256 SetEnabled(!disable);
1257
1258 bool dmark = false;
1259 archive->FindBool("be:dmark", &dmark);
1260 _BMCMenuBar_* menuBar = dynamic_cast<_BMCMenuBar_*>(fMenuBar);
1261 if (menuBar != NULL)
1262 menuBar->TogglePopUpMarker(dmark);
1263 }
1264
1265
1266 void
_AddMenu(BMenu * menu)1267 BMenuField::_AddMenu(BMenu* menu)
1268 {
1269 if (menu == NULL || fMenuBar == NULL)
1270 return;
1271
1272 fMenu = menu;
1273 InitMenu(menu);
1274
1275 BMenuItem* item = NULL;
1276 if (!menu->IsRadioMode() || (item = menu->FindMarked()) == NULL) {
1277 // find the first enabled non-seperator item
1278 int32 itemCount = menu->CountItems();
1279 for (int32 i = 0; i < itemCount; i++) {
1280 item = menu->ItemAt((int32)i);
1281 if (item == NULL || !item->IsEnabled()
1282 || dynamic_cast<BSeparatorItem*>(item) != NULL) {
1283 item = NULL;
1284 continue;
1285 }
1286 break;
1287 }
1288 }
1289
1290 if (item == NULL) {
1291 fMenuBar->AddItem(menu);
1292 return;
1293 }
1294
1295 // build an empty copy of item
1296
1297 BMessage data;
1298 status_t result = item->Archive(&data, false);
1299 if (result != B_OK) {
1300 fMenuBar->AddItem(menu);
1301 return;
1302 }
1303
1304 BArchivable* object = instantiate_object(&data);
1305 if (object == NULL) {
1306 fMenuBar->AddItem(menu);
1307 return;
1308 }
1309
1310 BMenuItem* newItem = static_cast<BMenuItem*>(object);
1311
1312 // unset parameters
1313 BPrivate::MenuItemPrivate newMenuItemPrivate(newItem);
1314 newMenuItemPrivate.Uninstall();
1315
1316 // set the menu
1317 newMenuItemPrivate.SetSubmenu(menu);
1318 fMenuBar->AddItem(newItem);
1319 }
1320
1321
1322 void
_ValidateLayoutData()1323 BMenuField::_ValidateLayoutData()
1324 {
1325 CALLED();
1326
1327 if (fLayoutData->valid)
1328 return;
1329
1330 // cache font height
1331 font_height& fh = fLayoutData->font_info;
1332 GetFontHeight(&fh);
1333
1334 const char* label = Label();
1335 if (label != NULL) {
1336 fLayoutData->label_width = ceilf(StringWidth(label));
1337 fLayoutData->label_height = ceilf(fh.ascent) + ceilf(fh.descent);
1338 } else {
1339 fLayoutData->label_width = 0;
1340 fLayoutData->label_height = 0;
1341 }
1342
1343 // compute the minimal divider
1344 float divider = 0;
1345 if (fLayoutData->label_width > 0) {
1346 divider = fLayoutData->label_width
1347 + be_control_look->DefaultLabelSpacing();
1348 }
1349
1350 // If we shan't do real layout, we let the current divider take influence.
1351 if ((Flags() & B_SUPPORTS_LAYOUT) == 0)
1352 divider = std::max(divider, fDivider);
1353
1354 // get the minimal (== preferred) menu bar size
1355 // TODO: BMenu::MinSize() is using the ResizeMode() to decide the
1356 // minimum width. If the mode is B_FOLLOW_LEFT_RIGHT, it will use the
1357 // parent's frame width or window's frame width. So at least the returned
1358 // size is wrong, but apparantly it doesn't have much bad effect.
1359 fLayoutData->menu_bar_min = fMenuBar->MinSize();
1360
1361 TRACE("menu bar min width: %.2f\n", fLayoutData->menu_bar_min.width);
1362
1363 // compute our minimal (== preferred) size
1364 BSize min(fLayoutData->menu_bar_min);
1365 min.width += 2 * kVMargin;
1366 min.height += 2 * kVMargin;
1367
1368 if (divider > 0)
1369 min.width += divider;
1370
1371 if (fLayoutData->label_height > min.height)
1372 min.height = fLayoutData->label_height;
1373
1374 fLayoutData->min = min;
1375
1376 fLayoutData->valid = true;
1377 ResetLayoutInvalidation();
1378
1379 TRACE("width: %.2f, height: %.2f\n", min.width, min.height);
1380 }
1381
1382
1383 float
_MenuBarOffset() const1384 BMenuField::_MenuBarOffset() const
1385 {
1386 return std::max(fDivider + kVMargin, kVMargin);
1387 }
1388
1389
1390 float
_MenuBarWidth() const1391 BMenuField::_MenuBarWidth() const
1392 {
1393 return Bounds().Width() - (_MenuBarOffset() + kVMargin);
1394 }
1395
1396
1397 // #pragma mark - BMenuField::LabelLayoutItem
1398
1399
LabelLayoutItem(BMenuField * parent)1400 BMenuField::LabelLayoutItem::LabelLayoutItem(BMenuField* parent)
1401 :
1402 fParent(parent),
1403 fFrame()
1404 {
1405 }
1406
1407
LabelLayoutItem(BMessage * from)1408 BMenuField::LabelLayoutItem::LabelLayoutItem(BMessage* from)
1409 :
1410 BAbstractLayoutItem(from),
1411 fParent(NULL),
1412 fFrame()
1413 {
1414 from->FindRect(kFrameField, &fFrame);
1415 }
1416
1417
1418 BRect
FrameInParent() const1419 BMenuField::LabelLayoutItem::FrameInParent() const
1420 {
1421 return fFrame.OffsetByCopy(-fParent->Frame().left, -fParent->Frame().top);
1422 }
1423
1424
1425 bool
IsVisible()1426 BMenuField::LabelLayoutItem::IsVisible()
1427 {
1428 return !fParent->IsHidden(fParent);
1429 }
1430
1431
1432 void
SetVisible(bool visible)1433 BMenuField::LabelLayoutItem::SetVisible(bool visible)
1434 {
1435 // not allowed
1436 }
1437
1438
1439 BRect
Frame()1440 BMenuField::LabelLayoutItem::Frame()
1441 {
1442 return fFrame;
1443 }
1444
1445
1446 void
SetFrame(BRect frame)1447 BMenuField::LabelLayoutItem::SetFrame(BRect frame)
1448 {
1449 fFrame = frame;
1450 fParent->_UpdateFrame();
1451 }
1452
1453
1454 void
SetParent(BMenuField * parent)1455 BMenuField::LabelLayoutItem::SetParent(BMenuField* parent)
1456 {
1457 fParent = parent;
1458 }
1459
1460
1461 BView*
View()1462 BMenuField::LabelLayoutItem::View()
1463 {
1464 return fParent;
1465 }
1466
1467
1468 BSize
BaseMinSize()1469 BMenuField::LabelLayoutItem::BaseMinSize()
1470 {
1471 fParent->_ValidateLayoutData();
1472
1473 if (fParent->Label() == NULL)
1474 return BSize(-1, -1);
1475
1476 return BSize(fParent->fLayoutData->label_width
1477 + be_control_look->DefaultLabelSpacing(),
1478 fParent->fLayoutData->label_height);
1479 }
1480
1481
1482 BSize
BaseMaxSize()1483 BMenuField::LabelLayoutItem::BaseMaxSize()
1484 {
1485 return BaseMinSize();
1486 }
1487
1488
1489 BSize
BasePreferredSize()1490 BMenuField::LabelLayoutItem::BasePreferredSize()
1491 {
1492 return BaseMinSize();
1493 }
1494
1495
1496 BAlignment
BaseAlignment()1497 BMenuField::LabelLayoutItem::BaseAlignment()
1498 {
1499 return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
1500 }
1501
1502
1503 status_t
Archive(BMessage * into,bool deep) const1504 BMenuField::LabelLayoutItem::Archive(BMessage* into, bool deep) const
1505 {
1506 BArchiver archiver(into);
1507 status_t err = BAbstractLayoutItem::Archive(into, deep);
1508
1509 if (err == B_OK)
1510 err = into->AddRect(kFrameField, fFrame);
1511
1512 return archiver.Finish(err);
1513 }
1514
1515
1516 BArchivable*
Instantiate(BMessage * from)1517 BMenuField::LabelLayoutItem::Instantiate(BMessage* from)
1518 {
1519 if (validate_instantiation(from, "BMenuField::LabelLayoutItem"))
1520 return new LabelLayoutItem(from);
1521
1522 return NULL;
1523 }
1524
1525
1526 // #pragma mark - BMenuField::MenuBarLayoutItem
1527
1528
MenuBarLayoutItem(BMenuField * parent)1529 BMenuField::MenuBarLayoutItem::MenuBarLayoutItem(BMenuField* parent)
1530 :
1531 fParent(parent),
1532 fFrame()
1533 {
1534 // by default the part right of the divider shall have an unlimited maximum
1535 // width
1536 SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
1537 }
1538
1539
MenuBarLayoutItem(BMessage * from)1540 BMenuField::MenuBarLayoutItem::MenuBarLayoutItem(BMessage* from)
1541 :
1542 BAbstractLayoutItem(from),
1543 fParent(NULL),
1544 fFrame()
1545 {
1546 from->FindRect(kFrameField, &fFrame);
1547 }
1548
1549
1550 BRect
FrameInParent() const1551 BMenuField::MenuBarLayoutItem::FrameInParent() const
1552 {
1553 return fFrame.OffsetByCopy(-fParent->Frame().left, -fParent->Frame().top);
1554 }
1555
1556
1557 bool
IsVisible()1558 BMenuField::MenuBarLayoutItem::IsVisible()
1559 {
1560 return !fParent->IsHidden(fParent);
1561 }
1562
1563
1564 void
SetVisible(bool visible)1565 BMenuField::MenuBarLayoutItem::SetVisible(bool visible)
1566 {
1567 // not allowed
1568 }
1569
1570
1571 BRect
Frame()1572 BMenuField::MenuBarLayoutItem::Frame()
1573 {
1574 return fFrame;
1575 }
1576
1577
1578 void
SetFrame(BRect frame)1579 BMenuField::MenuBarLayoutItem::SetFrame(BRect frame)
1580 {
1581 fFrame = frame;
1582 fParent->_UpdateFrame();
1583 }
1584
1585
1586 void
SetParent(BMenuField * parent)1587 BMenuField::MenuBarLayoutItem::SetParent(BMenuField* parent)
1588 {
1589 fParent = parent;
1590 }
1591
1592
1593 BView*
View()1594 BMenuField::MenuBarLayoutItem::View()
1595 {
1596 return fParent;
1597 }
1598
1599
1600 BSize
BaseMinSize()1601 BMenuField::MenuBarLayoutItem::BaseMinSize()
1602 {
1603 fParent->_ValidateLayoutData();
1604
1605 BSize size = fParent->fLayoutData->menu_bar_min;
1606 size.width += 2 * kVMargin;
1607 size.height += 2 * kVMargin;
1608
1609 return size;
1610 }
1611
1612
1613 BSize
BaseMaxSize()1614 BMenuField::MenuBarLayoutItem::BaseMaxSize()
1615 {
1616 BSize size(BaseMinSize());
1617 size.width = B_SIZE_UNLIMITED;
1618
1619 return size;
1620 }
1621
1622
1623 BSize
BasePreferredSize()1624 BMenuField::MenuBarLayoutItem::BasePreferredSize()
1625 {
1626 return BaseMinSize();
1627 }
1628
1629
1630 BAlignment
BaseAlignment()1631 BMenuField::MenuBarLayoutItem::BaseAlignment()
1632 {
1633 return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
1634 }
1635
1636
1637 status_t
Archive(BMessage * into,bool deep) const1638 BMenuField::MenuBarLayoutItem::Archive(BMessage* into, bool deep) const
1639 {
1640 BArchiver archiver(into);
1641 status_t err = BAbstractLayoutItem::Archive(into, deep);
1642
1643 if (err == B_OK)
1644 err = into->AddRect(kFrameField, fFrame);
1645
1646 return archiver.Finish(err);
1647 }
1648
1649
1650 BArchivable*
Instantiate(BMessage * from)1651 BMenuField::MenuBarLayoutItem::Instantiate(BMessage* from)
1652 {
1653 if (validate_instantiation(from, "BMenuField::MenuBarLayoutItem"))
1654 return new MenuBarLayoutItem(from);
1655 return NULL;
1656 }
1657
1658
1659 extern "C" void
B_IF_GCC_2(InvalidateLayout__10BMenuFieldb,_ZN10BMenuField16InvalidateLayoutEb)1660 B_IF_GCC_2(InvalidateLayout__10BMenuFieldb, _ZN10BMenuField16InvalidateLayoutEb)(
1661 BMenuField* field, bool descendants)
1662 {
1663 perform_data_layout_invalidated data;
1664 data.descendants = descendants;
1665
1666 field->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data);
1667 }
1668