xref: /haiku/src/kits/interface/MenuField.cpp (revision be3db2942c0e8dda63cdd226ec3c99309d3eab0c)
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_", B_NORMAL_PRIORITY, this);
286 	if (fMenuTaskID)
287 		resume_thread(fMenuTaskID);
288 }
289 
290 
291 void
292 BMenuField::KeyDown(const char *bytes, int32 numBytes)
293 {
294 	switch (bytes[0]) {
295 		case B_SPACE:
296 		case B_RIGHT_ARROW:
297 		case B_DOWN_ARROW:
298 		{
299 			if (!IsEnabled())
300 				break;
301 
302 			BRect bounds = fMenuBar->ConvertFromParent(Bounds());
303 
304 			fMenuBar->StartMenuBar(0, true, true, &bounds);
305 
306 			fSelected = true;
307 			fTransition = true;
308 
309 			bounds = Bounds();
310 			bounds.right = fDivider;
311 
312 			Invalidate(bounds);
313 		}
314 
315 		default:
316 			BView::KeyDown(bytes, numBytes);
317 	}
318 }
319 
320 
321 void
322 BMenuField::MakeFocus(bool state)
323 {
324 	if (IsFocus() == state)
325 		return;
326 
327 	BView::MakeFocus(state);
328 
329 	if (Window())
330 		Invalidate(); // TODO: use fStringWidth
331 }
332 
333 
334 void
335 BMenuField::MessageReceived(BMessage *msg)
336 {
337 	BView::MessageReceived(msg);
338 }
339 
340 
341 void
342 BMenuField::WindowActivated(bool state)
343 {
344 	BView::WindowActivated(state);
345 
346 	if (IsFocus())
347 		Invalidate();
348 }
349 
350 
351 void
352 BMenuField::MouseUp(BPoint point)
353 {
354 	BView::MouseUp(point);
355 }
356 
357 
358 void
359 BMenuField::MouseMoved(BPoint point, uint32 code, const BMessage *message)
360 {
361 	BView::MouseMoved(point, code, message);
362 }
363 
364 
365 void
366 BMenuField::DetachedFromWindow()
367 {
368 	BView::DetachedFromWindow();
369 }
370 
371 
372 void
373 BMenuField::AllDetached()
374 {
375 	BView::AllDetached();
376 }
377 
378 
379 void
380 BMenuField::FrameMoved(BPoint newPosition)
381 {
382 	BView::FrameMoved(newPosition);
383 }
384 
385 
386 void
387 BMenuField::FrameResized(float newWidth, float newHeight)
388 {
389 	BView::FrameResized(newWidth, newHeight);
390 }
391 
392 
393 BMenu *
394 BMenuField::Menu() const
395 {
396 	return fMenu;
397 }
398 
399 
400 BMenuBar *
401 BMenuField::MenuBar() const
402 {
403 	return fMenuBar;
404 }
405 
406 
407 BMenuItem *
408 BMenuField::MenuItem() const
409 {
410 	return fMenuBar->ItemAt(0);
411 }
412 
413 
414 void
415 BMenuField::SetLabel(const char *label)
416 {
417 	if (fLabel) {
418 		if (label && strcmp(fLabel, label) == 0)
419 			return;
420 
421 		free(fLabel);
422 	}
423 
424 	fLabel = strdup(label);
425 
426 	if (Window()) {
427 		Invalidate();
428 		if (fLabel)
429 			fStringWidth = StringWidth(fLabel);
430 	}
431 
432 	InvalidateLayout();
433 }
434 
435 
436 const char *
437 BMenuField::Label() const
438 {
439 	return fLabel;
440 }
441 
442 
443 void
444 BMenuField::SetEnabled(bool on)
445 {
446 	if (fEnabled == on)
447 		return;
448 
449 	fEnabled = on;
450 	fMenuBar->SetEnabled(on);
451 
452 	if (Window()) {
453 		fMenuBar->Invalidate(fMenuBar->Bounds());
454 		Invalidate(Bounds());
455 	}
456 }
457 
458 
459 bool
460 BMenuField::IsEnabled() const
461 {
462 	return fEnabled;
463 }
464 
465 
466 void
467 BMenuField::SetAlignment(alignment label)
468 {
469 	fAlign = label;
470 }
471 
472 
473 alignment
474 BMenuField::Alignment() const
475 {
476 	return fAlign;
477 }
478 
479 
480 void
481 BMenuField::SetDivider(float divider)
482 {
483 	divider = floorf(divider + 0.5);
484 
485 	float dx = fDivider - divider;
486 
487 	if (dx == 0.0f)
488 		return;
489 
490 	fDivider = divider;
491 
492 	BRect dirty(fMenuBar->Frame());
493 
494 	fMenuBar->MoveTo(fDivider + 1, kVMargin);
495 
496 	if (fFixedSizeMB) {
497 		fMenuBar->ResizeTo(Bounds().Width() - fDivider + 1 - 2,
498 						   dirty.Height());
499 	}
500 
501 	dirty = dirty | fMenuBar->Frame();
502 
503 	dirty.left -= 1;
504 	dirty.top -= 1;
505 	dirty.right += 2;
506 	dirty.bottom += 2;
507 
508 	Invalidate(dirty);
509 }
510 
511 
512 float
513 BMenuField::Divider() const
514 {
515 	return fDivider;
516 }
517 
518 
519 void
520 BMenuField::ShowPopUpMarker()
521 {
522 	if (_BMCMenuBar_ *menuBar = dynamic_cast<_BMCMenuBar_ *>(fMenuBar)) {
523 		menuBar->TogglePopUpMarker(true);
524 		menuBar->Invalidate();
525 	}
526 }
527 
528 
529 void
530 BMenuField::HidePopUpMarker()
531 {
532 	if (_BMCMenuBar_ *menuBar = dynamic_cast<_BMCMenuBar_ *>(fMenuBar)) {
533 		menuBar->TogglePopUpMarker(false);
534 		menuBar->Invalidate();
535 	}
536 }
537 
538 
539 BHandler *
540 BMenuField::ResolveSpecifier(BMessage *message, int32 index,
541 	BMessage *specifier, int32 form, const char *property)
542 {
543 	return BView::ResolveSpecifier(message, index, specifier, form, property);
544 }
545 
546 
547 status_t
548 BMenuField::GetSupportedSuites(BMessage *data)
549 {
550 	return BView::GetSupportedSuites(data);
551 }
552 
553 
554 void
555 BMenuField::ResizeToPreferred()
556 {
557 	fMenuBar->ResizeToPreferred();
558 
559 	BView::ResizeToPreferred();
560 }
561 
562 
563 void
564 BMenuField::GetPreferredSize(float *_width, float *_height)
565 {
566 	fMenuBar->GetPreferredSize(_width, _height);
567 
568 	if (_width) {
569 		// the width is already the menu bars preferred width
570 		// add the room we need to draw the shadow and stuff
571 		*_width += 2 * kVMargin;
572 
573 		// add the room needed for the label
574 		float labelWidth = fDivider;
575 		if (Label()) {
576 			labelWidth = ceilf(StringWidth(Label()));
577 			if (labelWidth > 0.0) {
578 				// add some room between label and menu bar
579 				labelWidth += 5.0;
580 			}
581 
582 			// have divider override the calculated label width
583 			labelWidth = max_c(labelWidth, fDivider);
584 		}
585 
586 		*_width += labelWidth;
587 	}
588 
589 	if (_height) {
590 		// the height is already the menu bars preferred height
591 		// add the room we need to draw the shadow and stuff
592 		*_height += 2 * kVMargin;
593 
594 		// see if our label would fit vertically
595 		font_height fh;
596 		GetFontHeight(&fh);
597 		*_height = max_c(*_height, ceilf(fh.ascent + fh.descent));
598 	}
599 }
600 
601 
602 BLayoutItem*
603 BMenuField::CreateLabelLayoutItem()
604 {
605 	if (!fLabelLayoutItem)
606 		fLabelLayoutItem = new LabelLayoutItem(this);
607 	return fLabelLayoutItem;
608 }
609 
610 
611 BLayoutItem*
612 BMenuField::CreateMenuBarLayoutItem()
613 {
614 	if (!fMenuBarLayoutItem)
615 		fMenuBarLayoutItem = new MenuBarLayoutItem(this);
616 	return fMenuBarLayoutItem;
617 }
618 
619 
620 status_t
621 BMenuField::Perform(perform_code d, void *arg)
622 {
623 	return BView::Perform(d, arg);
624 }
625 
626 
627 void BMenuField::_ReservedMenuField1() {}
628 void BMenuField::_ReservedMenuField2() {}
629 void BMenuField::_ReservedMenuField3() {}
630 
631 
632 BMenuField &
633 BMenuField::operator=(const BMenuField &)
634 {
635 	return *this;
636 }
637 
638 
639 void
640 BMenuField::InitObject(const char *label)
641 {
642 	fLabel = NULL;
643 	fMenu = NULL;
644 	fMenuBar = NULL;
645 	fAlign = B_ALIGN_LEFT;
646 	fStringWidth = 0;
647 	fEnabled = true;
648 	fSelected = false;
649 	fTransition = false;
650 	fFixedSizeMB = false;
651 	fMenuTaskID = -1;
652 	fLabelLayoutItem = NULL;
653 	fMenuBarLayoutItem = NULL;
654 
655 	SetLabel(label);
656 
657 	if (label)
658 		fDivider = (float)floor(Frame().Width() / 2.0f);
659 	else
660 		fDivider = 0;
661 }
662 
663 
664 void
665 BMenuField::InitObject2()
666 {
667 	font_height fontHeight;
668 	GetFontHeight(&fontHeight);
669 
670 	// TODO: fix this calculation
671 	float height = floorf(fontHeight.ascent + fontHeight.descent
672 		+ fontHeight.leading) + 7;
673 
674 	fMenuBar->ResizeTo(Bounds().Width() - fDivider, height);
675 	fMenuBar->AddFilter(new _BMCFilter_(this, B_MOUSE_DOWN));
676 }
677 
678 
679 void
680 BMenuField::DrawLabel(BRect bounds, BRect update)
681 {
682 	font_height fh;
683 	GetFontHeight(&fh);
684 
685 	if (Label()) {
686 		SetLowColor(ViewColor());
687 
688 		float y = (float)ceil(fh.ascent + fh.descent + fh.leading) + 2.0f;
689 		float x;
690 
691 		switch (fAlign) {
692 			case B_ALIGN_RIGHT:
693 				x = fDivider - StringWidth(Label()) - 3.0f;
694 				break;
695 
696 			case B_ALIGN_CENTER:
697 				x = fDivider - StringWidth(Label()) / 2.0f;
698 				break;
699 
700 			default:
701 				x = 3.0f;
702 				break;
703 		}
704 
705 		SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
706 			IsEnabled() ? B_DARKEN_MAX_TINT : B_DISABLED_LABEL_TINT));
707 		DrawString(Label(), BPoint(x, y));
708 	}
709 }
710 
711 
712 void
713 BMenuField::InitMenu(BMenu *menu)
714 {
715 	menu->SetFont(be_plain_font);
716 
717 	int32 index = 0;
718 	BMenu *subMenu;
719 
720 	while ((subMenu = menu->SubmenuAt(index++)) != NULL)
721 		InitMenu(subMenu);
722 }
723 
724 
725 long
726 BMenuField::MenuTask(void *arg)
727 {
728 	BMenuField *menuField = static_cast<BMenuField *>(arg);
729 
730 	if (!menuField->LockLooper())
731 		return 0;
732 
733 	menuField->fSelected = true;
734 	menuField->fTransition = true;
735 	menuField->Invalidate();
736 	menuField->UnlockLooper();
737 
738 	bool tracking;
739 	do {
740 		snooze(20000);
741 		if (!menuField->LockLooper())
742 			return 0;
743 
744 		tracking = menuField->fMenuBar->fTracking;
745 
746 		menuField->UnlockLooper();
747 	} while (tracking);
748 
749 	if (menuField->LockLooper()) {
750 		menuField->fSelected = false;
751 		menuField->fTransition = true;
752 		menuField->Invalidate();
753 		menuField->UnlockLooper();
754 	}
755 
756 	return 0;
757 }
758 
759 
760 void
761 BMenuField::_UpdateFrame()
762 {
763 	if (fLabelLayoutItem && fMenuBarLayoutItem) {
764 		BRect labelFrame = fLabelLayoutItem->Frame();
765 		BRect menuFrame = fMenuBarLayoutItem->Frame();
766 		MoveTo(labelFrame.left, labelFrame.top);
767 		ResizeTo(menuFrame.left + menuFrame.Width() - labelFrame.left,
768 			menuFrame.top + menuFrame.Height() - labelFrame.top);
769 		SetDivider(menuFrame.left - labelFrame.left);
770 	}
771 }
772 
773 
774 void
775 BMenuField::_InitMenuBar(BMenu* menu, BRect frame, bool fixedSize)
776 {
777 	fMenu = menu;
778 	InitMenu(menu);
779 
780 	fMenuBar = new _BMCMenuBar_(BRect(frame.left + fDivider + 1,
781 		frame.top + kVMargin, frame.right, frame.bottom - kVMargin),
782 		fixedSize, this);
783 
784 	AddChild(fMenuBar);
785 	fMenuBar->AddItem(menu);
786 
787 	fMenuBar->SetFont(be_plain_font);
788 }
789 
790 
791 // #pragma mark -
792 
793 
794 BMenuField::LabelLayoutItem::LabelLayoutItem(BMenuField* parent)
795 	: fParent(parent),
796 	  fFrame()
797 {
798 }
799 
800 
801 bool
802 BMenuField::LabelLayoutItem::IsVisible()
803 {
804 	return !fParent->IsHidden(fParent);
805 }
806 
807 
808 void
809 BMenuField::LabelLayoutItem::SetVisible(bool visible)
810 {
811 	// not allowed
812 }
813 
814 
815 BRect
816 BMenuField::LabelLayoutItem::Frame()
817 {
818 	return fFrame;
819 }
820 
821 
822 void
823 BMenuField::LabelLayoutItem::SetFrame(BRect frame)
824 {
825 	fFrame = frame;
826 	fParent->_UpdateFrame();
827 }
828 
829 
830 BView*
831 BMenuField::LabelLayoutItem::View()
832 {
833 	return fParent;
834 }
835 
836 
837 BSize
838 BMenuField::LabelLayoutItem::BaseMinSize()
839 {
840 // TODO: Cache the info. Might be too expensive for this call.
841 	const char* label = fParent->Label();
842 	if (!label)
843 		return BSize(-1, -1);
844 
845 	BSize size;
846 	fParent->GetPreferredSize(NULL, &size.height);
847 
848 	size.width = fParent->StringWidth(label) + 2 * 3 - 1;
849 
850 	return size;
851 }
852 
853 
854 BSize
855 BMenuField::LabelLayoutItem::BaseMaxSize()
856 {
857 	return BaseMinSize();
858 }
859 
860 
861 BSize
862 BMenuField::LabelLayoutItem::BasePreferredSize()
863 {
864 	return BaseMinSize();
865 }
866 
867 
868 BAlignment
869 BMenuField::LabelLayoutItem::BaseAlignment()
870 {
871 	return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
872 }
873 
874 
875 // #pragma mark -
876 
877 
878 BMenuField::MenuBarLayoutItem::MenuBarLayoutItem(BMenuField* parent)
879 	: fParent(parent),
880 	  fFrame()
881 {
882 }
883 
884 
885 bool
886 BMenuField::MenuBarLayoutItem::IsVisible()
887 {
888 	return !fParent->IsHidden(fParent);
889 }
890 
891 
892 void
893 BMenuField::MenuBarLayoutItem::SetVisible(bool visible)
894 {
895 	// not allowed
896 }
897 
898 
899 BRect
900 BMenuField::MenuBarLayoutItem::Frame()
901 {
902 	return fFrame;
903 }
904 
905 
906 void
907 BMenuField::MenuBarLayoutItem::SetFrame(BRect frame)
908 {
909 	fFrame = frame;
910 	fParent->_UpdateFrame();
911 }
912 
913 
914 BView*
915 BMenuField::MenuBarLayoutItem::View()
916 {
917 	return fParent;
918 }
919 
920 
921 BSize
922 BMenuField::MenuBarLayoutItem::BaseMinSize()
923 {
924 // TODO: Cache the info. Might be too expensive for this call.
925 	BSize size;
926 	fParent->fMenuBar->GetPreferredSize(&size.width, &size.height);
927 
928 	// BMenuField draws additional lines around BMenuBar,
929 	// one line on left and top side, two on right and bottom
930 	size.width += 3;
931 	size.height += 3;
932 
933 	return size;
934 }
935 
936 
937 BSize
938 BMenuField::MenuBarLayoutItem::BaseMaxSize()
939 {
940 	BSize size(BaseMinSize());
941 	size.width = B_SIZE_UNLIMITED;
942 	return size;
943 }
944 
945 
946 BSize
947 BMenuField::MenuBarLayoutItem::BasePreferredSize()
948 {
949 	BSize size(BaseMinSize());
950 	// puh, no idea...
951 	size.width = 100;
952 	return size;
953 }
954 
955 
956 BAlignment
957 BMenuField::MenuBarLayoutItem::BaseAlignment()
958 {
959 	return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
960 }
961 
962