xref: /haiku/src/kits/interface/MenuField.cpp (revision 9d6d3fcf5fe8308cd020cecf89dede440346f8c4)
1 /*
2  * Copyright 2001-2006, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Marc Flerackers (mflerackers@androme.be)
7  *		Stephan Aßmus <superstippi@gmx.de>
8  *		Ingo Weinhold <bonefish@cs.tu-berlin.de>
9  */
10 
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include <AbstractLayoutItem.h>
15 #include <LayoutUtils.h>
16 #include <MenuBar.h>
17 #include <MenuField.h>
18 #include <Message.h>
19 #include <BMCPrivate.h>
20 #include <Window.h>
21 
22 
23 class BMenuField::LabelLayoutItem : public BAbstractLayoutItem {
24 public:
25 								LabelLayoutItem(BMenuField* parent);
26 
27 	virtual	bool				IsVisible();
28 	virtual	void				SetVisible(bool visible);
29 
30 	virtual	BRect				Frame();
31 	virtual	void				SetFrame(BRect frame);
32 
33 	virtual	BView*				View();
34 
35 	virtual	BSize				BaseMinSize();
36 	virtual	BSize				BaseMaxSize();
37 	virtual	BSize				BasePreferredSize();
38 	virtual	BAlignment			BaseAlignment();
39 
40 private:
41 			BMenuField*			fParent;
42 			BRect				fFrame;
43 };
44 
45 
46 class BMenuField::MenuBarLayoutItem : public BAbstractLayoutItem {
47 public:
48 								MenuBarLayoutItem(BMenuField* parent);
49 
50 	virtual	bool				IsVisible();
51 	virtual	void				SetVisible(bool visible);
52 
53 	virtual	BRect				Frame();
54 	virtual	void				SetFrame(BRect frame);
55 
56 	virtual	BView*				View();
57 
58 	virtual	BSize				BaseMinSize();
59 	virtual	BSize				BaseMaxSize();
60 	virtual	BSize				BasePreferredSize();
61 	virtual	BAlignment			BaseAlignment();
62 
63 private:
64 			BMenuField*			fParent;
65 			BRect				fFrame;
66 };
67 
68 
69 // #pragma mark -
70 
71 
72 static float kVMargin = 2.0f;
73 
74 
75 BMenuField::BMenuField(BRect frame, const char *name, const char *label,
76 	BMenu *menu, uint32 resize, uint32 flags)
77 	: BView(frame, name, resize, flags)
78 {
79 	InitObject(label);
80 
81 	frame.OffsetTo(B_ORIGIN);
82 	_InitMenuBar(menu, frame, false);
83 
84 	InitObject2();
85 }
86 
87 
88 BMenuField::BMenuField(BRect frame, const char *name, const char *label,
89 	BMenu *menu, bool fixedSize, uint32 resize, uint32 flags)
90 	: BView(frame, name, resize, flags)
91 {
92 	InitObject(label);
93 
94 	fFixedSizeMB = fixedSize;
95 
96 	frame.OffsetTo(B_ORIGIN);
97 	_InitMenuBar(menu, frame, fixedSize);
98 
99 	InitObject2();
100 }
101 
102 
103 BMenuField::BMenuField(const char* name, const char* label, BMenu* menu,
104 					   BMessage* message, uint32 flags)
105 	: BView(BRect(0, 0, -1, -1), name, B_FOLLOW_NONE,
106 			flags | B_FRAME_EVENTS | B_SUPPORTS_LAYOUT)
107 {
108 	InitObject(label);
109 
110 	_InitMenuBar(menu, BRect(0, 0, 100, 15), false);
111 
112 	InitObject2();
113 }
114 
115 
116 BMenuField::BMenuField(const char* label,
117 					   BMenu* menu, BMessage* message)
118 	: BView(BRect(0, 0, -1, -1), NULL, B_FOLLOW_NONE,
119 			B_WILL_DRAW | B_NAVIGABLE | B_FRAME_EVENTS | B_SUPPORTS_LAYOUT)
120 {
121 	InitObject(label);
122 
123 	_InitMenuBar(menu, BRect(0, 0, 100, 15), false);
124 
125 	InitObject2();
126 }
127 
128 
129 BMenuField::BMenuField(BMessage *data)
130 	: BView(data)
131 {
132 	const char *label = NULL;
133 	data->FindString("_label", &label);
134 
135 	InitObject(label);
136 
137 	fMenuBar = (BMenuBar*)FindView("_mc_mb_");
138 	fMenu = fMenuBar->SubmenuAt(0);
139 
140 	InitObject2();
141 
142 	bool disable;
143 	if (data->FindBool("_disable", &disable) == B_OK)
144 		SetEnabled(!disable);
145 
146 	int32 align;
147 	data->FindInt32("_align", &align);
148 		SetAlignment((alignment)align);
149 
150 	data->FindFloat("_divide", &fDivider);
151 
152 	bool fixed;
153 	if (data->FindBool("be:fixeds", &fixed) == B_OK)
154 		fFixedSizeMB = fixed;
155 
156 	bool dmark = false;
157 	data->FindBool("be:dmark", &dmark);
158 	if (_BMCMenuBar_ *menuBar = dynamic_cast<_BMCMenuBar_ *>(fMenuBar)) {
159 		menuBar->TogglePopUpMarker(dmark);
160 	}
161 }
162 
163 
164 BMenuField::~BMenuField()
165 {
166 	free(fLabel);
167 
168 	status_t dummy;
169 	if (fMenuTaskID >= 0)
170 		wait_for_thread(fMenuTaskID, &dummy);
171 }
172 
173 
174 BArchivable *
175 BMenuField::Instantiate(BMessage *data)
176 {
177 	if (validate_instantiation(data, "BMenuField"))
178 		return new BMenuField(data);
179 
180 	return NULL;
181 }
182 
183 
184 status_t
185 BMenuField::Archive(BMessage *data, bool deep) const
186 {
187 	status_t ret = BView::Archive(data, deep);
188 
189 	if (ret == B_OK && Label())
190 		ret = data->AddString("_label", Label());
191 
192 	if (ret == B_OK && !IsEnabled())
193 		ret = data->AddBool("_disable", true);
194 
195 	if (ret == B_OK)
196 		ret = data->AddInt32("_align", Alignment());
197 	if (ret == B_OK)
198 		ret = data->AddFloat("_divide", Divider());
199 
200 	if (ret == B_OK && fFixedSizeMB)
201 		ret = data->AddBool("be:fixeds", true);
202 
203 	bool dmark = false;
204 	if (_BMCMenuBar_ *menuBar = dynamic_cast<_BMCMenuBar_ *>(fMenuBar)) {
205 		dmark = menuBar->IsPopUpMarkerShown();
206 	}
207 	data->AddBool("be:dmark", dmark);
208 
209 	return ret;
210 }
211 
212 
213 void
214 BMenuField::Draw(BRect update)
215 {
216 	BRect bounds(Bounds());
217 	bool active = false;
218 
219 	if (IsFocus())
220 		active = Window()->IsActive();
221 
222 	DrawLabel(bounds, update);
223 
224 	BRect frame(fMenuBar->Frame());
225 
226 	if (frame.InsetByCopy(-kVMargin, -kVMargin).Intersects(update)) {
227 		SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_2_TINT));
228 		StrokeLine(BPoint(frame.left - 1.0f, frame.top - 1.0f),
229 			BPoint(frame.left - 1.0f, frame.bottom - 1.0f));
230 		StrokeLine(BPoint(frame.left - 1.0f, frame.top - 1.0f),
231 			BPoint(frame.right - 1.0f, frame.top - 1.0f));
232 
233 		StrokeLine(BPoint(frame.left + 1.0f, frame.bottom + 1.0f),
234 			BPoint(frame.right + 1.0f, frame.bottom + 1.0f));
235 		StrokeLine(BPoint(frame.right + 1.0f, frame.top + 1.0f));
236 
237 		SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_4_TINT));
238 		StrokeLine(BPoint(frame.left - 1.0f, frame.bottom),
239 			BPoint(frame.left - 1.0f, frame.bottom));
240 		StrokeLine(BPoint(frame.right, frame.top - 1.0f),
241 			BPoint(frame.right, frame.top - 1.0f));
242 	}
243 
244 	if (active || fTransition) {
245 		SetHighColor(active ? ui_color(B_KEYBOARD_NAVIGATION_COLOR) :
246 			ViewColor());
247 		StrokeRect(frame.InsetByCopy(-kVMargin, -kVMargin));
248 
249 		fTransition = false;
250 	}
251 }
252 
253 
254 void
255 BMenuField::AttachedToWindow()
256 {
257 	if (Parent()) {
258 		SetViewColor(Parent()->ViewColor());
259 		SetLowColor(Parent()->ViewColor());
260 	}
261 
262 	if (fLabel)
263 		fStringWidth = StringWidth(fLabel);
264 }
265 
266 
267 void
268 BMenuField::AllAttached()
269 {
270 	ResizeTo(Bounds().Width(),
271 		fMenuBar->Bounds().Height() + kVMargin + kVMargin);
272 }
273 
274 
275 void
276 BMenuField::MouseDown(BPoint where)
277 {
278 	if (!fMenuBar->Frame().Contains(where))
279 		return;
280 
281 	BRect bounds = fMenuBar->ConvertFromParent(Bounds());
282 
283 	fMenuBar->StartMenuBar(-1, false, true, &bounds);
284 
285 	fMenuTaskID = spawn_thread((thread_func)MenuTask, "_m_task_",
286 		B_NORMAL_PRIORITY, this);
287 	if (fMenuTaskID)
288 		resume_thread(fMenuTaskID);
289 }
290 
291 
292 void
293 BMenuField::KeyDown(const char *bytes, int32 numBytes)
294 {
295 	switch (bytes[0]) {
296 		case B_SPACE:
297 		case B_RIGHT_ARROW:
298 		case B_DOWN_ARROW:
299 		{
300 			if (!IsEnabled())
301 				break;
302 
303 			BRect bounds = fMenuBar->ConvertFromParent(Bounds());
304 
305 			fMenuBar->StartMenuBar(0, true, true, &bounds);
306 
307 			fSelected = true;
308 			fTransition = true;
309 
310 			bounds = Bounds();
311 			bounds.right = fDivider;
312 
313 			Invalidate(bounds);
314 		}
315 
316 		default:
317 			BView::KeyDown(bytes, numBytes);
318 	}
319 }
320 
321 
322 void
323 BMenuField::MakeFocus(bool state)
324 {
325 	if (IsFocus() == state)
326 		return;
327 
328 	BView::MakeFocus(state);
329 
330 	if (Window())
331 		Invalidate(); // TODO: use fStringWidth
332 }
333 
334 
335 void
336 BMenuField::MessageReceived(BMessage *msg)
337 {
338 	BView::MessageReceived(msg);
339 }
340 
341 
342 void
343 BMenuField::WindowActivated(bool state)
344 {
345 	BView::WindowActivated(state);
346 
347 	if (IsFocus())
348 		Invalidate();
349 }
350 
351 
352 void
353 BMenuField::MouseUp(BPoint point)
354 {
355 	BView::MouseUp(point);
356 }
357 
358 
359 void
360 BMenuField::MouseMoved(BPoint point, uint32 code, const BMessage *message)
361 {
362 	BView::MouseMoved(point, code, message);
363 }
364 
365 
366 void
367 BMenuField::DetachedFromWindow()
368 {
369 	BView::DetachedFromWindow();
370 }
371 
372 
373 void
374 BMenuField::AllDetached()
375 {
376 	BView::AllDetached();
377 }
378 
379 
380 void
381 BMenuField::FrameMoved(BPoint newPosition)
382 {
383 	BView::FrameMoved(newPosition);
384 }
385 
386 
387 void
388 BMenuField::FrameResized(float newWidth, float newHeight)
389 {
390 	BView::FrameResized(newWidth, newHeight);
391 }
392 
393 
394 BMenu *
395 BMenuField::Menu() const
396 {
397 	return fMenu;
398 }
399 
400 
401 BMenuBar *
402 BMenuField::MenuBar() const
403 {
404 	return fMenuBar;
405 }
406 
407 
408 BMenuItem *
409 BMenuField::MenuItem() const
410 {
411 	return fMenuBar->ItemAt(0);
412 }
413 
414 
415 void
416 BMenuField::SetLabel(const char *label)
417 {
418 	if (fLabel) {
419 		if (label && strcmp(fLabel, label) == 0)
420 			return;
421 
422 		free(fLabel);
423 	}
424 
425 	fLabel = strdup(label);
426 
427 	if (Window()) {
428 		Invalidate();
429 		if (fLabel)
430 			fStringWidth = StringWidth(fLabel);
431 	}
432 
433 	InvalidateLayout();
434 }
435 
436 
437 const char *
438 BMenuField::Label() const
439 {
440 	return fLabel;
441 }
442 
443 
444 void
445 BMenuField::SetEnabled(bool on)
446 {
447 	if (fEnabled == on)
448 		return;
449 
450 	fEnabled = on;
451 	fMenuBar->SetEnabled(on);
452 
453 	if (Window()) {
454 		fMenuBar->Invalidate(fMenuBar->Bounds());
455 		Invalidate(Bounds());
456 	}
457 }
458 
459 
460 bool
461 BMenuField::IsEnabled() const
462 {
463 	return fEnabled;
464 }
465 
466 
467 void
468 BMenuField::SetAlignment(alignment label)
469 {
470 	fAlign = label;
471 }
472 
473 
474 alignment
475 BMenuField::Alignment() const
476 {
477 	return fAlign;
478 }
479 
480 
481 void
482 BMenuField::SetDivider(float divider)
483 {
484 	divider = floorf(divider + 0.5);
485 
486 	float dx = fDivider - divider;
487 
488 	if (dx == 0.0f)
489 		return;
490 
491 	fDivider = divider;
492 
493 	BRect dirty(fMenuBar->Frame());
494 
495 	fMenuBar->MoveTo(fDivider + 1, kVMargin);
496 
497 	if (fFixedSizeMB) {
498 		fMenuBar->ResizeTo(Bounds().Width() - fDivider + 1 - 2,
499 						   dirty.Height());
500 	}
501 
502 	dirty = dirty | fMenuBar->Frame();
503 
504 	dirty.left -= 1;
505 	dirty.top -= 1;
506 	dirty.right += 2;
507 	dirty.bottom += 2;
508 
509 	Invalidate(dirty);
510 }
511 
512 
513 float
514 BMenuField::Divider() const
515 {
516 	return fDivider;
517 }
518 
519 
520 void
521 BMenuField::ShowPopUpMarker()
522 {
523 	if (_BMCMenuBar_ *menuBar = dynamic_cast<_BMCMenuBar_ *>(fMenuBar)) {
524 		menuBar->TogglePopUpMarker(true);
525 		menuBar->Invalidate();
526 	}
527 }
528 
529 
530 void
531 BMenuField::HidePopUpMarker()
532 {
533 	if (_BMCMenuBar_ *menuBar = dynamic_cast<_BMCMenuBar_ *>(fMenuBar)) {
534 		menuBar->TogglePopUpMarker(false);
535 		menuBar->Invalidate();
536 	}
537 }
538 
539 
540 BHandler *
541 BMenuField::ResolveSpecifier(BMessage *message, int32 index,
542 	BMessage *specifier, int32 form, const char *property)
543 {
544 	return BView::ResolveSpecifier(message, index, specifier, form, property);
545 }
546 
547 
548 status_t
549 BMenuField::GetSupportedSuites(BMessage *data)
550 {
551 	return BView::GetSupportedSuites(data);
552 }
553 
554 
555 void
556 BMenuField::ResizeToPreferred()
557 {
558 	fMenuBar->ResizeToPreferred();
559 
560 	BView::ResizeToPreferred();
561 }
562 
563 
564 void
565 BMenuField::GetPreferredSize(float *_width, float *_height)
566 {
567 	fMenuBar->GetPreferredSize(_width, _height);
568 
569 	if (_width) {
570 		// the width is already the menu bars preferred width
571 		// add the room we need to draw the shadow and stuff
572 		*_width += 2 * kVMargin;
573 
574 		// add the room needed for the label
575 		float labelWidth = fDivider;
576 		if (Label()) {
577 			labelWidth = ceilf(StringWidth(Label()));
578 			if (labelWidth > 0.0) {
579 				// add some room between label and menu bar
580 				labelWidth += 5.0;
581 			}
582 
583 			// have divider override the calculated label width
584 			labelWidth = max_c(labelWidth, fDivider);
585 		}
586 
587 		*_width += labelWidth;
588 	}
589 
590 	if (_height) {
591 		// the height is already the menu bars preferred height
592 		// add the room we need to draw the shadow and stuff
593 		*_height += 2 * kVMargin;
594 
595 		// see if our label would fit vertically
596 		font_height fh;
597 		GetFontHeight(&fh);
598 		*_height = max_c(*_height, ceilf(fh.ascent + fh.descent));
599 	}
600 }
601 
602 
603 BLayoutItem*
604 BMenuField::CreateLabelLayoutItem()
605 {
606 	if (!fLabelLayoutItem)
607 		fLabelLayoutItem = new LabelLayoutItem(this);
608 	return fLabelLayoutItem;
609 }
610 
611 
612 BLayoutItem*
613 BMenuField::CreateMenuBarLayoutItem()
614 {
615 	if (!fMenuBarLayoutItem)
616 		fMenuBarLayoutItem = new MenuBarLayoutItem(this);
617 	return fMenuBarLayoutItem;
618 }
619 
620 
621 status_t
622 BMenuField::Perform(perform_code d, void *arg)
623 {
624 	return BView::Perform(d, arg);
625 }
626 
627 
628 void BMenuField::_ReservedMenuField1() {}
629 void BMenuField::_ReservedMenuField2() {}
630 void BMenuField::_ReservedMenuField3() {}
631 
632 
633 BMenuField &
634 BMenuField::operator=(const BMenuField &)
635 {
636 	return *this;
637 }
638 
639 
640 void
641 BMenuField::InitObject(const char *label)
642 {
643 	fLabel = NULL;
644 	fMenu = NULL;
645 	fMenuBar = NULL;
646 	fAlign = B_ALIGN_LEFT;
647 	fStringWidth = 0;
648 	fEnabled = true;
649 	fSelected = false;
650 	fTransition = false;
651 	fFixedSizeMB = false;
652 	fMenuTaskID = -1;
653 	fLabelLayoutItem = NULL;
654 	fMenuBarLayoutItem = NULL;
655 
656 	SetLabel(label);
657 
658 	if (label)
659 		fDivider = (float)floor(Frame().Width() / 2.0f);
660 	else
661 		fDivider = 0;
662 }
663 
664 
665 void
666 BMenuField::InitObject2()
667 {
668 	font_height fontHeight;
669 	GetFontHeight(&fontHeight);
670 
671 	// TODO: fix this calculation
672 	float height = floorf(fontHeight.ascent + fontHeight.descent
673 		+ fontHeight.leading) + 7;
674 
675 	fMenuBar->ResizeTo(Bounds().Width() - fDivider, height);
676 	fMenuBar->AddFilter(new _BMCFilter_(this, B_MOUSE_DOWN));
677 }
678 
679 
680 void
681 BMenuField::DrawLabel(BRect bounds, BRect update)
682 {
683 	font_height fh;
684 	GetFontHeight(&fh);
685 
686 	if (Label()) {
687 		SetLowColor(ViewColor());
688 
689 		float y = (float)ceil(fh.ascent + fh.descent + fh.leading) + 2.0f;
690 		float x;
691 
692 		switch (fAlign) {
693 			case B_ALIGN_RIGHT:
694 				x = fDivider - StringWidth(Label()) - 3.0f;
695 				break;
696 
697 			case B_ALIGN_CENTER:
698 				x = fDivider - StringWidth(Label()) / 2.0f;
699 				break;
700 
701 			default:
702 				x = 3.0f;
703 				break;
704 		}
705 
706 		SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
707 			IsEnabled() ? B_DARKEN_MAX_TINT : B_DISABLED_LABEL_TINT));
708 		DrawString(Label(), BPoint(x, y));
709 	}
710 }
711 
712 
713 void
714 BMenuField::InitMenu(BMenu *menu)
715 {
716 	menu->SetFont(be_plain_font);
717 
718 	int32 index = 0;
719 	BMenu *subMenu;
720 
721 	while ((subMenu = menu->SubmenuAt(index++)) != NULL)
722 		InitMenu(subMenu);
723 }
724 
725 
726 long
727 BMenuField::MenuTask(void *arg)
728 {
729 	BMenuField *menuField = static_cast<BMenuField *>(arg);
730 
731 	if (!menuField->LockLooper())
732 		return 0;
733 
734 	menuField->fSelected = true;
735 	menuField->fTransition = true;
736 	menuField->Invalidate();
737 	menuField->UnlockLooper();
738 
739 	bool tracking;
740 	do {
741 		snooze(20000);
742 		if (!menuField->LockLooper())
743 			return 0;
744 
745 		tracking = menuField->fMenuBar->fTracking;
746 
747 		menuField->UnlockLooper();
748 	} while (tracking);
749 
750 	if (menuField->LockLooper()) {
751 		menuField->fSelected = false;
752 		menuField->fTransition = true;
753 		menuField->Invalidate();
754 		menuField->UnlockLooper();
755 	}
756 
757 	return 0;
758 }
759 
760 
761 void
762 BMenuField::_UpdateFrame()
763 {
764 	if (fLabelLayoutItem && fMenuBarLayoutItem) {
765 		BRect labelFrame = fLabelLayoutItem->Frame();
766 		BRect menuFrame = fMenuBarLayoutItem->Frame();
767 		MoveTo(labelFrame.left, labelFrame.top);
768 		ResizeTo(menuFrame.left + menuFrame.Width() - labelFrame.left,
769 			menuFrame.top + menuFrame.Height() - labelFrame.top);
770 		SetDivider(menuFrame.left - labelFrame.left);
771 	}
772 }
773 
774 
775 void
776 BMenuField::_InitMenuBar(BMenu* menu, BRect frame, bool fixedSize)
777 {
778 	fMenu = menu;
779 	InitMenu(menu);
780 
781 	fMenuBar = new _BMCMenuBar_(BRect(frame.left + fDivider + 1,
782 		frame.top + kVMargin, frame.right, frame.bottom - kVMargin),
783 		fixedSize, this);
784 
785 	AddChild(fMenuBar);
786 	fMenuBar->AddItem(menu);
787 
788 	fMenuBar->SetFont(be_plain_font);
789 }
790 
791 
792 // #pragma mark -
793 
794 
795 BMenuField::LabelLayoutItem::LabelLayoutItem(BMenuField* parent)
796 	: fParent(parent),
797 	  fFrame()
798 {
799 }
800 
801 
802 bool
803 BMenuField::LabelLayoutItem::IsVisible()
804 {
805 	return !fParent->IsHidden(fParent);
806 }
807 
808 
809 void
810 BMenuField::LabelLayoutItem::SetVisible(bool visible)
811 {
812 	// not allowed
813 }
814 
815 
816 BRect
817 BMenuField::LabelLayoutItem::Frame()
818 {
819 	return fFrame;
820 }
821 
822 
823 void
824 BMenuField::LabelLayoutItem::SetFrame(BRect frame)
825 {
826 	fFrame = frame;
827 	fParent->_UpdateFrame();
828 }
829 
830 
831 BView*
832 BMenuField::LabelLayoutItem::View()
833 {
834 	return fParent;
835 }
836 
837 
838 BSize
839 BMenuField::LabelLayoutItem::BaseMinSize()
840 {
841 // TODO: Cache the info. Might be too expensive for this call.
842 	const char* label = fParent->Label();
843 	if (!label)
844 		return BSize(-1, -1);
845 
846 	BSize size;
847 	fParent->GetPreferredSize(NULL, &size.height);
848 
849 	size.width = fParent->StringWidth(label) + 2 * 3 - 1;
850 
851 	return size;
852 }
853 
854 
855 BSize
856 BMenuField::LabelLayoutItem::BaseMaxSize()
857 {
858 	return BaseMinSize();
859 }
860 
861 
862 BSize
863 BMenuField::LabelLayoutItem::BasePreferredSize()
864 {
865 	return BaseMinSize();
866 }
867 
868 
869 BAlignment
870 BMenuField::LabelLayoutItem::BaseAlignment()
871 {
872 	return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
873 }
874 
875 
876 // #pragma mark -
877 
878 
879 BMenuField::MenuBarLayoutItem::MenuBarLayoutItem(BMenuField* parent)
880 	: fParent(parent),
881 	  fFrame()
882 {
883 }
884 
885 
886 bool
887 BMenuField::MenuBarLayoutItem::IsVisible()
888 {
889 	return !fParent->IsHidden(fParent);
890 }
891 
892 
893 void
894 BMenuField::MenuBarLayoutItem::SetVisible(bool visible)
895 {
896 	// not allowed
897 }
898 
899 
900 BRect
901 BMenuField::MenuBarLayoutItem::Frame()
902 {
903 	return fFrame;
904 }
905 
906 
907 void
908 BMenuField::MenuBarLayoutItem::SetFrame(BRect frame)
909 {
910 	fFrame = frame;
911 	fParent->_UpdateFrame();
912 }
913 
914 
915 BView*
916 BMenuField::MenuBarLayoutItem::View()
917 {
918 	return fParent;
919 }
920 
921 
922 BSize
923 BMenuField::MenuBarLayoutItem::BaseMinSize()
924 {
925 // TODO: Cache the info. Might be too expensive for this call.
926 	BSize size;
927 	fParent->fMenuBar->GetPreferredSize(&size.width, &size.height);
928 
929 	// BMenuField draws additional lines around BMenuBar,
930 	// one line on left and top side, two on right and bottom
931 	size.width += 3;
932 	size.height += 3;
933 
934 	return size;
935 }
936 
937 
938 BSize
939 BMenuField::MenuBarLayoutItem::BaseMaxSize()
940 {
941 	BSize size(BaseMinSize());
942 	size.width = B_SIZE_UNLIMITED;
943 	return size;
944 }
945 
946 
947 BSize
948 BMenuField::MenuBarLayoutItem::BasePreferredSize()
949 {
950 	BSize size(BaseMinSize());
951 	// puh, no idea...
952 	size.width = 100;
953 	return size;
954 }
955 
956 
957 BAlignment
958 BMenuField::MenuBarLayoutItem::BaseAlignment()
959 {
960 	return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
961 }
962 
963