1789f68f0SAxel Dörfler/*
281364c9dSJohn Scipione * Copyright 2006-2016 Haiku, Inc. All rights reserved.
3789f68f0SAxel Dörfler * Distributed under the terms of the MIT License.
4789f68f0SAxel Dörfler *
5789f68f0SAxel Dörfler * Authors:
63de334b9SJohn Scipione *		Stephan A��mus, superstippi@gmx.de
73de334b9SJohn Scipione *		Marc Flerackers, mflerackers@androme.be
83de334b9SJohn Scipione *		John Scipione, jscipione@gmail.com
93de334b9SJohn Scipione *		Ingo Weinhold, bonefish@cs.tu-berlin.de
10789f68f0SAxel Dörfler */
11789f68f0SAxel Dörfler
1250f8cd14SAxel Dörfler
132f86ba45SStephan Aßmus#include <MenuField.h>
142f86ba45SStephan Aßmus
154e1b1920SJohn Scipione#include <algorithm>
1681364c9dSJohn Scipione
173de334b9SJohn Scipione#include <stdio.h>
183de334b9SJohn Scipione	// for printf in TRACE
19db11bebfSAxel Dörfler#include <stdlib.h>
20db11bebfSAxel Dörfler#include <string.h>
217ea7a892SMarc Flerackers
229ecf9d1cSIngo Weinhold#include <AbstractLayoutItem.h>
2381364c9dSJohn Scipione#include <Archivable.h>
24285b7163SJohn Scipione#include <BMCPrivate.h>
252f86ba45SStephan Aßmus#include <ControlLook.h>
269ecf9d1cSIngo Weinhold#include <LayoutUtils.h>
277ea7a892SMarc Flerackers#include <MenuBar.h>
28a1cf3eadSJohn Scipione#include <MenuItem.h>
2981364c9dSJohn Scipione#include <MenuItemPrivate.h>
309422c92eSJohn Scipione#include <MenuPrivate.h>
317ea7a892SMarc Flerackers#include <Message.h>
32285b7163SJohn Scipione#include <MessageFilter.h>
33285b7163SJohn Scipione#include <Thread.h>
347ea7a892SMarc Flerackers#include <Window.h>
357ea7a892SMarc Flerackers
3639fbf550SOliver Tappe#include <binary_compatibility/Interface.h>
377a37b89bSAlex Wilson#include <binary_compatibility/Support.h>
3839fbf550SOliver Tappe
397ea7a892SMarc Flerackers
40285b7163SJohn Scipione#ifdef CALLED
41285b7163SJohn Scipione#	undef CALLED
42285b7163SJohn Scipione#endif
43285b7163SJohn Scipione#ifdef TRACE
44285b7163SJohn Scipione#	undef TRACE
45285b7163SJohn Scipione#endif
46285b7163SJohn Scipione
4714f63456SStephan Aßmus//#define TRACE_MENU_FIELD
4814f63456SStephan Aßmus#ifdef TRACE_MENU_FIELD
4914f63456SStephan Aßmus#	include <FunctionTracer.h>
5014f63456SStephan Aßmus	static int32 sFunctionDepth = -1;
5114f63456SStephan Aßmus#	define CALLED(x...)	FunctionTracer _ft("BMenuField", __FUNCTION__, \
5214f63456SStephan Aßmus							sFunctionDepth)
5314f63456SStephan Aßmus#	define TRACE(x...)	{ BString _to; \
5414f63456SStephan Aßmus							_to.Append(' ', (sFunctionDepth + 1) * 2); \
5514f63456SStephan Aßmus							printf("%s", _to.String()); printf(x); }
5614f63456SStephan Aßmus#else
5714f63456SStephan Aßmus#	define CALLED(x...)
5814f63456SStephan Aßmus#	define TRACE(x...)
5914f63456SStephan Aßmus#endif
6014f63456SStephan Aßmus
6114f63456SStephan Aßmus
62cccc4076SJohn Scipionestatic const float kMinMenuBarWidth = 20.0f;
63cccc4076SJohn Scipione	// found by experimenting on BeOS R5
64cccc4076SJohn Scipione
65cccc4076SJohn Scipione
667a37b89bSAlex Wilsonnamespace {
677a37b89bSAlex Wilson	const char* const kFrameField = "BMenuField:layoutItem:frame";
687a37b89bSAlex Wilson	const char* const kMenuBarItemField = "BMenuField:barItem";
697a37b89bSAlex Wilson	const char* const kLabelItemField = "BMenuField:labelItem";
707a37b89bSAlex Wilson}
717a37b89bSAlex Wilson
727a37b89bSAlex Wilson
73cccc4076SJohn Scipione//	#pragma mark - LabelLayoutItem
74cccc4076SJohn Scipione
75cccc4076SJohn Scipione
769ecf9d1cSIngo Weinholdclass BMenuField::LabelLayoutItem : public BAbstractLayoutItem {
779ecf9d1cSIngo Weinholdpublic:
789ecf9d1cSIngo Weinhold								LabelLayoutItem(BMenuField* parent);
797a37b89bSAlex Wilson								LabelLayoutItem(BMessage* archive);
809ecf9d1cSIngo Weinhold
81d8919236SAxel Dörfler			BRect				FrameInParent() const;
82d8919236SAxel Dörfler
839ecf9d1cSIngo Weinhold	virtual	bool				IsVisible();
849ecf9d1cSIngo Weinhold	virtual	void				SetVisible(bool visible);
859ecf9d1cSIngo Weinhold
869ecf9d1cSIngo Weinhold	virtual	BRect				Frame();
879ecf9d1cSIngo Weinhold	virtual	void				SetFrame(BRect frame);
889ecf9d1cSIngo Weinhold
897a37b89bSAlex Wilson			void				SetParent(BMenuField* parent);
909ecf9d1cSIngo Weinhold	virtual	BView*				View();
919ecf9d1cSIngo Weinhold
929ecf9d1cSIngo Weinhold	virtual	BSize				BaseMinSize();
939ecf9d1cSIngo Weinhold	virtual	BSize				BaseMaxSize();
949ecf9d1cSIngo Weinhold	virtual	BSize				BasePreferredSize();
959ecf9d1cSIngo Weinhold	virtual	BAlignment			BaseAlignment();
969ecf9d1cSIngo Weinhold
977a37b89bSAlex Wilson	virtual status_t			Archive(BMessage* into, bool deep = true) const;
987a37b89bSAlex Wilson	static	BArchivable*		Instantiate(BMessage* from);
997a37b89bSAlex Wilson
1009ecf9d1cSIngo Weinholdprivate:
1019ecf9d1cSIngo Weinhold			BMenuField*			fParent;
1029ecf9d1cSIngo Weinhold			BRect				fFrame;
1039ecf9d1cSIngo Weinhold};
1049ecf9d1cSIngo Weinhold
1059ecf9d1cSIngo Weinhold
106cccc4076SJohn Scipione//	#pragma mark - MenuBarLayoutItem
107cccc4076SJohn Scipione
108cccc4076SJohn Scipione
1099ecf9d1cSIngo Weinholdclass BMenuField::MenuBarLayoutItem : public BAbstractLayoutItem {
1109ecf9d1cSIngo Weinholdpublic:
1119ecf9d1cSIngo Weinhold								MenuBarLayoutItem(BMenuField* parent);
1127a37b89bSAlex Wilson								MenuBarLayoutItem(BMessage* from);
1139ecf9d1cSIngo Weinhold
114d8919236SAxel Dörfler			BRect				FrameInParent() const;
115d8919236SAxel Dörfler
1169ecf9d1cSIngo Weinhold	virtual	bool				IsVisible();
1179ecf9d1cSIngo Weinhold	virtual	void				SetVisible(bool visible);
1189ecf9d1cSIngo Weinhold
1199ecf9d1cSIngo Weinhold	virtual	BRect				Frame();
1209ecf9d1cSIngo Weinhold	virtual	void				SetFrame(BRect frame);
1219ecf9d1cSIngo Weinhold
1227a37b89bSAlex Wilson			void				SetParent(BMenuField* parent);
1239ecf9d1cSIngo Weinhold	virtual	BView*				View();
1249ecf9d1cSIngo Weinhold
1259ecf9d1cSIngo Weinhold	virtual	BSize				BaseMinSize();
1269ecf9d1cSIngo Weinhold	virtual	BSize				BaseMaxSize();
1279ecf9d1cSIngo Weinhold	virtual	BSize				BasePreferredSize();
1289ecf9d1cSIngo Weinhold	virtual	BAlignment			BaseAlignment();
1299ecf9d1cSIngo Weinhold
1307a37b89bSAlex Wilson	virtual status_t			Archive(BMessage* into, bool deep = true) const;
1317a37b89bSAlex Wilson	static	BArchivable*		Instantiate(BMessage* from);
1327a37b89bSAlex Wilson
1339ecf9d1cSIngo Weinholdprivate:
1349ecf9d1cSIngo Weinhold			BMenuField*			fParent;
1359ecf9d1cSIngo Weinhold			BRect				fFrame;
1369ecf9d1cSIngo Weinhold};
1379ecf9d1cSIngo Weinhold
1389ecf9d1cSIngo Weinhold
139cccc4076SJohn Scipione//	#pragma mark - LayoutData
140cccc4076SJohn Scipione
141cccc4076SJohn Scipione
142b321303cSIngo Weinholdstruct BMenuField::LayoutData {
143b321303cSIngo Weinhold	LayoutData()
14450f8cd14SAxel Dörfler		:
14550f8cd14SAxel Dörfler		label_layout_item(NULL),
14650f8cd14SAxel Dörfler		menu_bar_layout_item(NULL),
14750f8cd14SAxel Dörfler		previous_height(-1),
14850f8cd14SAxel Dörfler		valid(false)
149b321303cSIngo Weinhold	{
150b321303cSIngo Weinhold	}
151b321303cSIngo Weinhold
152b321303cSIngo Weinhold	LabelLayoutItem*	label_layout_item;
153b321303cSIngo Weinhold	MenuBarLayoutItem*	menu_bar_layout_item;
154b321303cSIngo Weinhold	float				previous_height;	// used in FrameResized() for
155b321303cSIngo Weinhold											// invalidation
156b321303cSIngo Weinhold	font_height			font_info;
157b321303cSIngo Weinhold	float				label_width;
158b321303cSIngo Weinhold	float				label_height;
159b321303cSIngo Weinhold	BSize				min;
160b321303cSIngo Weinhold	BSize				menu_bar_min;
161b321303cSIngo Weinhold	bool				valid;
162b321303cSIngo Weinhold};
163b321303cSIngo Weinhold
164b321303cSIngo Weinhold
165285b7163SJohn Scipione// #pragma mark - MouseDownFilter
166285b7163SJohn Scipione
167285b7163SJohn Scipione
168285b7163SJohn Scipioneclass MouseDownFilter : public BMessageFilter
169285b7163SJohn Scipione{
170285b7163SJohn Scipionepublic:
171285b7163SJohn Scipione								MouseDownFilter();
172285b7163SJohn Scipione	virtual						~MouseDownFilter();
173285b7163SJohn Scipione
174285b7163SJohn Scipione	virtual	filter_result		Filter(BMessage* message, BHandler** target);
175285b7163SJohn Scipione};
176285b7163SJohn Scipione
177285b7163SJohn Scipione
178285b7163SJohn ScipioneMouseDownFilter::MouseDownFilter()
179285b7163SJohn Scipione	:
180285b7163SJohn Scipione	BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE)
181285b7163SJohn Scipione{
182285b7163SJohn Scipione}
183285b7163SJohn Scipione
184285b7163SJohn Scipione
185285b7163SJohn ScipioneMouseDownFilter::~MouseDownFilter()
186285b7163SJohn Scipione{
187285b7163SJohn Scipione}
188285b7163SJohn Scipione
189285b7163SJohn Scipione
190285b7163SJohn Scipionefilter_result
191285b7163SJohn ScipioneMouseDownFilter::Filter(BMessage* message, BHandler** target)
192285b7163SJohn Scipione{
193285b7163SJohn Scipione	return message->what == B_MOUSE_DOWN ? B_SKIP_MESSAGE : B_DISPATCH_MESSAGE;
194285b7163SJohn Scipione}
195285b7163SJohn Scipione
196285b7163SJohn Scipione
197cccc4076SJohn Scipione// #pragma mark - BMenuField
19892c12506SJohn Scipione
19992c12506SJohn Scipione
20050f8cd14SAxel DörflerBMenuField::BMenuField(BRect frame, const char* name, const char* label,
201df5d08a7SJohn Scipione	BMenu* menu, uint32 resizingMode, uint32 flags)
20250f8cd14SAxel Dörfler	:
203df5d08a7SJohn Scipione	BView(frame, name, resizingMode, flags)
2047ea7a892SMarc Flerackers{
20514f63456SStephan Aßmus	CALLED();
20614f63456SStephan Aßmus
20714f63456SStephan Aßmus	TRACE("frame.width: %.2f, height: %.2f\n", frame.Width(), frame.Height());
20814f63456SStephan Aßmus
2097ea7a892SMarc Flerackers	InitObject(label);
2107ea7a892SMarc Flerackers
211e3d07155SStefano Ceccherini	frame.OffsetTo(B_ORIGIN);
2129ecf9d1cSIngo Weinhold	_InitMenuBar(menu, frame, false);
2137ea7a892SMarc Flerackers
2147ea7a892SMarc Flerackers	InitObject2();
2157ea7a892SMarc Flerackers}
216789f68f0SAxel Dörfler
217789f68f0SAxel Dörfler
21850f8cd14SAxel DörflerBMenuField::BMenuField(BRect frame, const char* name, const char* label,
219df5d08a7SJohn Scipione	BMenu* menu, bool fixedSize, uint32 resizingMode, uint32 flags)
22050f8cd14SAxel Dörfler	:
221df5d08a7SJohn Scipione	BView(frame, name, resizingMode, flags)
2227ea7a892SMarc Flerackers{
2237ea7a892SMarc Flerackers	InitObject(label);
2247ea7a892SMarc Flerackers
225789f68f0SAxel Dörfler	fFixedSizeMB = fixedSize;
2267ea7a892SMarc Flerackers
227e3d07155SStefano Ceccherini	frame.OffsetTo(B_ORIGIN);
2289ecf9d1cSIngo Weinhold	_InitMenuBar(menu, frame, fixedSize);
2297ea7a892SMarc Flerackers
2309ecf9d1cSIngo Weinhold	InitObject2();
2319ecf9d1cSIngo Weinhold}
2327ea7a892SMarc Flerackers
2339ecf9d1cSIngo Weinhold
2344296233fSAxel DörflerBMenuField::BMenuField(const char* name, const char* label, BMenu* menu,
235df5d08a7SJohn Scipione	uint32 flags)
2364296233fSAxel Dörfler	:
2374296233fSAxel Dörfler	BView(name, flags | B_FRAME_EVENTS)
2384296233fSAxel Dörfler{
2394296233fSAxel Dörfler	InitObject(label);
2404296233fSAxel Dörfler
2414296233fSAxel Dörfler	_InitMenuBar(menu, BRect(0, 0, 100, 15), true);
2424296233fSAxel Dörfler
2434296233fSAxel Dörfler	InitObject2();
2444296233fSAxel Dörfler}
2454296233fSAxel Dörfler
2464296233fSAxel Dörfler
2474296233fSAxel DörflerBMenuField::BMenuField(const char* label, BMenu* menu, uint32 flags)
2484296233fSAxel Dörfler	:
2494296233fSAxel Dörfler	BView(NULL, flags | B_FRAME_EVENTS)
2504296233fSAxel Dörfler{
2514296233fSAxel Dörfler	InitObject(label);
2524296233fSAxel Dörfler
2534296233fSAxel Dörfler	_InitMenuBar(menu, BRect(0, 0, 100, 15), true);
2544296233fSAxel Dörfler
2554296233fSAxel Dörfler	InitObject2();
2564296233fSAxel Dörfler}
2574296233fSAxel Dörfler
2584296233fSAxel Dörfler
2594296233fSAxel Dörfler//! Copy&Paste error, should be removed at some point (already private)
2609ecf9d1cSIngo WeinholdBMenuField::BMenuField(const char* name, const char* label, BMenu* menu,
26150f8cd14SAxel Dörfler		BMessage* message, uint32 flags)
26250f8cd14SAxel Dörfler	:
26350f8cd14SAxel Dörfler	BView(name, flags | B_FRAME_EVENTS)
2649ecf9d1cSIngo Weinhold{
2659ecf9d1cSIngo Weinhold	InitObject(label);
2669ecf9d1cSIngo Weinhold
26747e745c6SStephan Aßmus	_InitMenuBar(menu, BRect(0, 0, 100, 15), true);
2689ecf9d1cSIngo Weinhold
2699ecf9d1cSIngo Weinhold	InitObject2();
2709ecf9d1cSIngo Weinhold}
2719ecf9d1cSIngo Weinhold
2729ecf9d1cSIngo Weinhold
2734296233fSAxel Dörfler//! Copy&Paste error, should be removed at some point (already private)
27450f8cd14SAxel DörflerBMenuField::BMenuField(const char* label, BMenu* menu, BMessage* message)
27550f8cd14SAxel Dörfler	:
27650f8cd14SAxel Dörfler	BView(NULL, B_WILL_DRAW | B_NAVIGABLE | B_FRAME_EVENTS)
2779ecf9d1cSIngo Weinhold{
2789ecf9d1cSIngo Weinhold	InitObject(label);
2799ecf9d1cSIngo Weinhold
28047e745c6SStephan Aßmus	_InitMenuBar(menu, BRect(0, 0, 100, 15), true);
2817ea7a892SMarc Flerackers
2827ea7a892SMarc Flerackers	InitObject2();
2837ea7a892SMarc Flerackers}
284789f68f0SAxel Dörfler
285789f68f0SAxel Dörfler
28650f8cd14SAxel DörflerBMenuField::BMenuField(BMessage* data)
28750f8cd14SAxel Dörfler	:
2887a37b89bSAlex Wilson	BView(BUnarchiver::PrepareArchive(data))
2897ea7a892SMarc Flerackers{
2907a37b89bSAlex Wilson	BUnarchiver unarchiver(data);
29150f8cd14SAxel Dörfler	const char* label = NULL;
2927ea7a892SMarc Flerackers	data->FindString("_label", &label);
293789f68f0SAxel Dörfler
2947ea7a892SMarc Flerackers	InitObject(label);
2957ea7a892SMarc Flerackers
2967a37b89bSAlex Wilson	data->FindFloat("_divide", &fDivider);
2977ea7a892SMarc Flerackers
2987ea7a892SMarc Flerackers	int32 align;
2997a37b89bSAlex Wilson	if (data->FindInt32("_align", &align) == B_OK)
3007ea7a892SMarc Flerackers		SetAlignment((alignment)align);
3014296233fSAxel Dörfler
3027a37b89bSAlex Wilson	if (!BUnarchiver::IsArchiveManaged(data))
3037a37b89bSAlex Wilson		_InitMenuBar(data);
30481364c9dSJohn Scipione
3057a37b89bSAlex Wilson	unarchiver.Finish();
3067ea7a892SMarc Flerackers}
307789f68f0SAxel Dörfler
308789f68f0SAxel Dörfler
3097ea7a892SMarc FlerackersBMenuField::~BMenuField()
3107ea7a892SMarc Flerackers{
311789f68f0SAxel Dörfler	free(fLabel);
3127ea7a892SMarc Flerackers
313e3d07155SStefano Ceccherini	status_t dummy;
3147ea7a892SMarc Flerackers	if (fMenuTaskID >= 0)
315e3d07155SStefano Ceccherini		wait_for_thread(fMenuTaskID, &dummy);
316b321303cSIngo Weinhold
317b321303cSIngo Weinhold	delete fLayoutData;
318285b7163SJohn Scipione	delete fMouseDownFilter;
3197ea7a892SMarc Flerackers}
320789f68f0SAxel Dörfler
321789f68f0SAxel Dörfler
32250f8cd14SAxel DörflerBArchivable*
32350f8cd14SAxel DörflerBMenuField::Instantiate(BMessage* data)
3247ea7a892SMarc Flerackers{
3257ea7a892SMarc Flerackers	if (validate_instantiation(data, "BMenuField"))
3267ea7a892SMarc Flerackers		return new BMenuField(data);
327789f68f0SAxel Dörfler
328789f68f0SAxel Dörfler	return NULL;
3297ea7a892SMarc Flerackers}
330789f68f0SAxel Dörfler
331789f68f0SAxel Dörfler
332789f68f0SAxel Dörflerstatus_t
33350f8cd14SAxel DörflerBMenuField::Archive(BMessage* data, bool deep) const
3347ea7a892SMarc Flerackers{
3357a37b89bSAlex Wilson	BArchiver archiver(data);
3364fdedfbdSJérôme Duval	status_t ret = BView::Archive(data, deep);
3377ea7a892SMarc Flerackers
3384fdedfbdSJérôme Duval	if (ret == B_OK && Label())
3394fdedfbdSJérôme Duval		ret = data->AddString("_label", Label());
3407ea7a892SMarc Flerackers
3414fdedfbdSJérôme Duval	if (ret == B_OK && !IsEnabled())
3424fdedfbdSJérôme Duval		ret = data->AddBool("_disable", true);
3437ea7a892SMarc Flerackers
3444fdedfbdSJérôme Duval	if (ret == B_OK)
3454fdedfbdSJérôme Duval		ret = data->AddInt32("_align", Alignment());
3464fdedfbdSJérôme Duval	if (ret == B_OK)
3474fdedfbdSJérôme Duval		ret = data->AddFloat("_divide", Divider());
3487ea7a892SMarc Flerackers
3494fdedfbdSJérôme Duval	if (ret == B_OK && fFixedSizeMB)
3504fdedfbdSJérôme Duval		ret = data->AddBool("be:fixeds", true);
3517ea7a892SMarc Flerackers
352cd39deccSStefano Ceccherini	bool dmark = false;
35350f8cd14SAxel Dörfler	if (_BMCMenuBar_* menuBar = dynamic_cast<_BMCMenuBar_*>(fMenuBar))
354cd39deccSStefano Ceccherini		dmark = menuBar->IsPopUpMarkerShown();
35550f8cd14SAxel Dörfler
356cd39deccSStefano Ceccherini	data->AddBool("be:dmark", dmark);
3577ea7a892SMarc Flerackers
3587a37b89bSAlex Wilson	return archiver.Finish(ret);
3597a37b89bSAlex Wilson}
3607a37b89bSAlex Wilson
3617a37b89bSAlex Wilson
3627a37b89bSAlex Wilsonstatus_t
3637a37b89bSAlex WilsonBMenuField::AllArchived(BMessage* into) const
3647a37b89bSAlex Wilson{
3657a37b89bSAlex Wilson	status_t err;
3667a37b89bSAlex Wilson	if ((err = BView::AllArchived(into)) != B_OK)
3677a37b89bSAlex Wilson		return err;
3687a37b89bSAlex Wilson
3697a37b89bSAlex Wilson	BArchiver archiver(into);
3707a37b89bSAlex Wilson
3717a37b89bSAlex Wilson	BArchivable* menuBarItem = fLayoutData->menu_bar_layout_item;
3727a37b89bSAlex Wilson	if (archiver.IsArchived(menuBarItem))
3737a37b89bSAlex Wilson		err = archiver.AddArchivable(kMenuBarItemField, menuBarItem);
3747a37b89bSAlex Wilson
3757a37b89bSAlex Wilson	if (err != B_OK)
3767a37b89bSAlex Wilson		return err;
3777a37b89bSAlex Wilson
3787a37b89bSAlex Wilson	BArchivable* labelBarItem = fLayoutData->label_layout_item;
3797a37b89bSAlex Wilson	if (archiver.IsArchived(labelBarItem))
3807a37b89bSAlex Wilson		err = archiver.AddArchivable(kLabelItemField, labelBarItem);
3817a37b89bSAlex Wilson
3827a37b89bSAlex Wilson	return err;
3837a37b89bSAlex Wilson}
3847a37b89bSAlex Wilson
3857a37b89bSAlex Wilson
3867a37b89bSAlex Wilsonstatus_t
3877a37b89bSAlex WilsonBMenuField::AllUnarchived(const BMessage* from)
3887a37b89bSAlex Wilson{
3897a37b89bSAlex Wilson	BUnarchiver unarchiver(from);
3907a37b89bSAlex Wilson
3917a37b89bSAlex Wilson	status_t err = B_OK;
3927a37b89bSAlex Wilson	if ((err = BView::AllUnarchived(from)) != B_OK)
3937a37b89bSAlex Wilson		return err;
3947a37b89bSAlex Wilson
3957a37b89bSAlex Wilson	_InitMenuBar(from);
3967a37b89bSAlex Wilson
3977a37b89bSAlex Wilson	if (unarchiver.IsInstantiated(kMenuBarItemField)) {
3987a37b89bSAlex Wilson		MenuBarLayoutItem*& menuItem = fLayoutData->menu_bar_layout_item;
3997a37b89bSAlex Wilson		err = unarchiver.FindObject(kMenuBarItemField,
4007a37b89bSAlex Wilson			BUnarchiver::B_DONT_ASSUME_OWNERSHIP, menuItem);
4017a37b89bSAlex Wilson
4027a37b89bSAlex Wilson		if (err == B_OK)
4037a37b89bSAlex Wilson			menuItem->SetParent(this);
4047a37b89bSAlex Wilson		else
4057a37b89bSAlex Wilson			return err;
4067a37b89bSAlex Wilson	}
4077a37b89bSAlex Wilson
4087a37b89bSAlex Wilson	if (unarchiver.IsInstantiated(kLabelItemField)) {
4097a37b89bSAlex Wilson		LabelLayoutItem*& labelItem = fLayoutData->label_layout_item;
4107a37b89bSAlex Wilson		err = unarchiver.FindObject(kLabelItemField,
4117a37b89bSAlex Wilson			BUnarchiver::B_DONT_ASSUME_OWNERSHIP, labelItem);
4127a37b89bSAlex Wilson
4137a37b89bSAlex Wilson		if (err == B_OK)
4147a37b89bSAlex Wilson			labelItem->SetParent(this);
4157a37b89bSAlex Wilson	}
4167a37b89bSAlex Wilson
4177a37b89bSAlex Wilson	return err;
4187ea7a892SMarc Flerackers}
419789f68f0SAxel Dörfler
420789f68f0SAxel Dörfler
421789f68f0SAxel Dörflervoid
422d97b4340SJohn ScipioneBMenuField::Draw(BRect updateRect)
4237ea7a892SMarc Flerackers{
4249422c92eSJohn Scipione	_DrawLabel(updateRect);
4259422c92eSJohn Scipione	_DrawMenuBar(updateRect);
4267ea7a892SMarc Flerackers}
427789f68f0SAxel Dörfler
428789f68f0SAxel Dörfler
429789f68f0SAxel Dörflervoid
430789f68f0SAxel DörflerBMenuField::AttachedToWindow()
4317ea7a892SMarc Flerackers{
43214f63456SStephan Aßmus	CALLED();
4333e08f216Slooncraz
4343e08f216Slooncraz	// Our low color must match the parent's view color.
4353e08f216Slooncraz	if (Parent() != NULL) {
4363e08f216Slooncraz		AdoptParentColors();
4373e08f216Slooncraz
4383e08f216Slooncraz		float tint = B_NO_TINT;
4393e08f216Slooncraz		color_which which = ViewUIColor(&tint);
4403e08f216Slooncraz
4413e08f216Slooncraz		if (which == B_NO_COLOR)
4423e08f216Slooncraz			SetLowColor(ViewColor());
4433e08f216Slooncraz		else
4443e08f216Slooncraz			SetLowUIColor(which, tint);
4453e08f216Slooncraz	} else
4463e08f216Slooncraz		AdoptSystemColors();
4477ea7a892SMarc Flerackers}
448789f68f0SAxel Dörfler
449789f68f0SAxel Dörfler
450789f68f0SAxel Dörflervoid
451789f68f0SAxel DörflerBMenuField::AllAttached()
4527ea7a892SMarc Flerackers{
45314f63456SStephan Aßmus	CALLED();
45414f63456SStephan Aßmus
45514f63456SStephan Aßmus	TRACE("width: %.2f, height: %.2f\n", Frame().Width(), Frame().Height());
45614f63456SStephan Aßmus
457a1cf3eadSJohn Scipione	float width = Bounds().Width();
458a1cf3eadSJohn Scipione	if (!fFixedSizeMB && _MenuBarWidth() < kMinMenuBarWidth) {
459a1cf3eadSJohn Scipione		// The menu bar is too narrow, resize it to fit the menu items
460a1cf3eadSJohn Scipione		BMenuItem* item = fMenuBar->ItemAt(0);
461a1cf3eadSJohn Scipione		if (item != NULL) {
462a1cf3eadSJohn Scipione			float right;
463a1cf3eadSJohn Scipione			fMenuBar->GetItemMargins(NULL, NULL, &right, NULL);
464a1cf3eadSJohn Scipione			width = item->Frame().Width() + kVMargin + _MenuBarOffset() + right;
465a1cf3eadSJohn Scipione		}
466a1cf3eadSJohn Scipione	}
467a1cf3eadSJohn Scipione
468a1cf3eadSJohn Scipione	ResizeTo(width, fMenuBar->Bounds().Height() + kVMargin * 2);
46914f63456SStephan Aßmus
47014f63456SStephan Aßmus	TRACE("width: %.2f, height: %.2f\n", Frame().Width(), Frame().Height());
4717ea7a892SMarc Flerackers}
472789f68f0SAxel Dörfler
473789f68f0SAxel Dörfler
474789f68f0SAxel Dörflervoid
475789f68f0SAxel DörflerBMenuField::MouseDown(BPoint where)
4767ea7a892SMarc Flerackers{
477db11bebfSAxel Dörfler	BRect bounds = fMenuBar->ConvertFromParent(Bounds());
4787ea7a892SMarc Flerackers
47944cd9847SStefano Ceccherini	fMenuBar->StartMenuBar(-1, false, true, &bounds);
4807ea7a892SMarc Flerackers
48144cd9847SStefano Ceccherini	fMenuTaskID = spawn_thread((thread_func)_thread_entry,
482d97b4340SJohn Scipione		"_m_task_", B_NORMAL_PRIORITY, this);
483285b7163SJohn Scipione	if (fMenuTaskID >= 0 && resume_thread(fMenuTaskID) == B_OK) {
484285b7163SJohn Scipione		if (fMouseDownFilter->Looper() == NULL)
485285b7163SJohn Scipione			Window()->AddCommonFilter(fMouseDownFilter);
486285b7163SJohn Scipione
487285b7163SJohn Scipione		MouseDownThread<BMenuField>::TrackMouse(this, &BMenuField::_DoneTracking,
488285b7163SJohn Scipione			&BMenuField::_Track);
489285b7163SJohn Scipione	}
4907ea7a892SMarc Flerackers}
491789f68f0SAxel Dörfler
492789f68f0SAxel Dörfler
493789f68f0SAxel Dörflervoid
49450f8cd14SAxel DörflerBMenuField::KeyDown(const char* bytes, int32 numBytes)
4957ea7a892SMarc Flerackers{
496789f68f0SAxel Dörfler	switch (bytes[0]) {
4977ea7a892SMarc Flerackers		case B_SPACE:
4987ea7a892SMarc Flerackers		case B_RIGHT_ARROW:
4997ea7a892SMarc Flerackers		case B_DOWN_ARROW:
5007ea7a892SMarc Flerackers		{
501f9f970d9SStefano Ceccherini			if (!IsEnabled())
502f9f970d9SStefano Ceccherini				break;
503f9f970d9SStefano Ceccherini
504db11bebfSAxel Dörfler			BRect bounds = fMenuBar->ConvertFromParent(Bounds());
5057ea7a892SMarc Flerackers
506db11bebfSAxel Dörfler			fMenuBar->StartMenuBar(0, true, true, &bounds);
5077ea7a892SMarc Flerackers
5087ea7a892SMarc Flerackers			bounds = Bounds();
5097ea7a892SMarc Flerackers			bounds.right = fDivider;
5107ea7a892SMarc Flerackers
5112e6a5805SStephan Aßmus			Invalidate(bounds);
5127ea7a892SMarc Flerackers		}
513789f68f0SAxel Dörfler
5147ea7a892SMarc Flerackers		default:
5157ea7a892SMarc Flerackers			BView::KeyDown(bytes, numBytes);
5167ea7a892SMarc Flerackers	}
5177ea7a892SMarc Flerackers}
518789f68f0SAxel Dörfler
519789f68f0SAxel Dörfler
520789f68f0SAxel Dörflervoid
521cccc4076SJohn ScipioneBMenuField::MakeFocus(bool focused)
5227ea7a892SMarc Flerackers{
523cccc4076SJohn Scipione	if (IsFocus() == focused)
5247ea7a892SMarc Flerackers		return;
5257ea7a892SMarc Flerackers
526cccc4076SJohn Scipione	BView::MakeFocus(focused);
5277ea7a892SMarc Flerackers
528cccc4076SJohn Scipione	if (Window() != NULL)
529b321303cSIngo Weinhold		Invalidate(); // TODO: use fLayoutData->label_width
5307ea7a892SMarc Flerackers}
531789f68f0SAxel Dörfler
532789f68f0SAxel Dörfler
533789f68f0SAxel Dörflervoid
534d97b4340SJohn ScipioneBMenuField::MessageReceived(BMessage* message)
5357ea7a892SMarc Flerackers{
536d97b4340SJohn Scipione	BView::MessageReceived(message);
5377ea7a892SMarc Flerackers}
538789f68f0SAxel Dörfler
539789f68f0SAxel Dörfler
540789f68f0SAxel Dörflervoid
5411f424632SJohn ScipioneBMenuField::WindowActivated(bool active)
5427ea7a892SMarc Flerackers{
5431f424632SJohn Scipione	BView::WindowActivated(active);
5447ea7a892SMarc Flerackers
5457ea7a892SMarc Flerackers	if (IsFocus())
5462e6a5805SStephan Aßmus		Invalidate();
5477ea7a892SMarc Flerackers}
548789f68f0SAxel Dörfler
549789f68f0SAxel Dörfler
550789f68f0SAxel Dörflervoid
551285b7163SJohn ScipioneBMenuField::MouseMoved(BPoint point, uint32 code, const BMessage* message)
5527ea7a892SMarc Flerackers{
553285b7163SJohn Scipione	BView::MouseMoved(point, code, message);
5547ea7a892SMarc Flerackers}
555789f68f0SAxel Dörfler
556789f68f0SAxel Dörfler
557789f68f0SAxel Dörflervoid
5581f424632SJohn ScipioneBMenuField::MouseUp(BPoint where)
5597ea7a892SMarc Flerackers{
5601f424632SJohn Scipione	BView::MouseUp(where);
5617ea7a892SMarc Flerackers}
562789f68f0SAxel Dörfler
563789f68f0SAxel Dörfler
564789f68f0SAxel Dörflervoid
565789f68f0SAxel DörflerBMenuField::DetachedFromWindow()
5667ea7a892SMarc Flerackers{
5677ea7a892SMarc Flerackers	BView::DetachedFromWindow();
5687ea7a892SMarc Flerackers}
569789f68f0SAxel Dörfler
570789f68f0SAxel Dörfler
571789f68f0SAxel Dörflervoid
572789f68f0SAxel DörflerBMenuField::AllDetached()
5737ea7a892SMarc Flerackers{
5747ea7a892SMarc Flerackers	BView::AllDetached();
5757ea7a892SMarc Flerackers}
576789f68f0SAxel Dörfler
577789f68f0SAxel Dörfler
578789f68f0SAxel Dörflervoid
579789f68f0SAxel DörflerBMenuField::FrameMoved(BPoint newPosition)
5807ea7a892SMarc Flerackers{
581789f68f0SAxel Dörfler	BView::FrameMoved(newPosition);
5827ea7a892SMarc Flerackers}
583789f68f0SAxel Dörfler
584789f68f0SAxel Dörfler
585789f68f0SAxel Dörflervoid
586789f68f0SAxel DörflerBMenuField::FrameResized(float newWidth, float newHeight)
5877ea7a892SMarc Flerackers{
588789f68f0SAxel Dörfler	BView::FrameResized(newWidth, newHeight);
589b321303cSIngo Weinhold
590ca3a1c04SJohn Scipione	if (fFixedSizeMB) {
591ca3a1c04SJohn Scipione		// we have let the menubar resize itself, but
592ca3a1c04SJohn Scipione		// in fixed size mode, the menubar is supposed to
593ca3a1c04SJohn Scipione		// be at the right end of the view always. Since
594ca3a1c04SJohn Scipione		// the menu bar is in follow left/right mode then,
595ca3a1c04SJohn Scipione		// resizing ourselfs might have caused the menubar
596ca3a1c04SJohn Scipione		// to be outside now
597ca3a1c04SJohn Scipione		fMenuBar->ResizeTo(_MenuBarWidth(), fMenuBar->Frame().Height());
598ca3a1c04SJohn Scipione	}
599ca3a1c04SJohn Scipione
600b321303cSIngo Weinhold	if (newHeight != fLayoutData->previous_height && Label()) {
601b321303cSIngo Weinhold		// The height changed, which means the label has to move and we
602b321303cSIngo Weinhold		// probably also invalidate a part of the borders around the menu bar.
603b321303cSIngo Weinhold		// So don't be shy and invalidate the whole thing.
604b321303cSIngo Weinhold		Invalidate();
605b321303cSIngo Weinhold	}
606b321303cSIngo Weinhold
607b321303cSIngo Weinhold	fLayoutData->previous_height = newHeight;
6087ea7a892SMarc Flerackers}
609789f68f0SAxel Dörfler
610789f68f0SAxel Dörfler
61150f8cd14SAxel DörflerBMenu*
612789f68f0SAxel DörflerBMenuField::Menu() const
6137ea7a892SMarc Flerackers{
6147ea7a892SMarc Flerackers	return fMenu;
6157ea7a892SMarc Flerackers}
616789f68f0SAxel Dörfler
617789f68f0SAxel Dörfler
61850f8cd14SAxel DörflerBMenuBar*
619789f68f0SAxel DörflerBMenuField::MenuBar() const
6207ea7a892SMarc Flerackers{
6217ea7a892SMarc Flerackers	return fMenuBar;
6227ea7a892SMarc Flerackers}
623789f68f0SAxel Dörfler
624789f68f0SAxel Dörfler
62550f8cd14SAxel DörflerBMenuItem*
626789f68f0SAxel DörflerBMenuField::MenuItem() const
6277ea7a892SMarc Flerackers{
6287ea7a892SMarc Flerackers	return fMenuBar->ItemAt(0);
6297ea7a892SMarc Flerackers}
630789f68f0SAxel Dörfler
631789f68f0SAxel Dörfler
632789f68f0SAxel Dörflervoid
63350f8cd14SAxel DörflerBMenuField::SetLabel(const char* label)
6347ea7a892SMarc Flerackers{
635789f68f0SAxel Dörfler	if (fLabel) {
6367ea7a892SMarc Flerackers		if (label && strcmp(fLabel, label) == 0)
6377ea7a892SMarc Flerackers			return;
6387ea7a892SMarc Flerackers
6397ea7a892SMarc Flerackers		free(fLabel);
6407ea7a892SMarc Flerackers	}
6417ea7a892SMarc Flerackers
6427ea7a892SMarc Flerackers	fLabel = strdup(label);
6437ea7a892SMarc Flerackers
644b321303cSIngo Weinhold	if (Window())
6457ea7a892SMarc Flerackers		Invalidate();
6469ecf9d1cSIngo Weinhold
6479ecf9d1cSIngo Weinhold	InvalidateLayout();
6487ea7a892SMarc Flerackers}
649789f68f0SAxel Dörfler
650789f68f0SAxel Dörfler
65150f8cd14SAxel Dörflerconst char*
652789f68f0SAxel DörflerBMenuField::Label() const
6537ea7a892SMarc Flerackers{
6547ea7a892SMarc Flerackers	return fLabel;
6557ea7a892SMarc Flerackers}
656789f68f0SAxel Dörfler
657789f68f0SAxel Dörfler
658789f68f0SAxel Dörflervoid
659789f68f0SAxel DörflerBMenuField::SetEnabled(bool on)
6607ea7a892SMarc Flerackers{
6617ea7a892SMarc Flerackers	if (fEnabled == on)
6627ea7a892SMarc Flerackers		return;
6637ea7a892SMarc Flerackers
6647ea7a892SMarc Flerackers	fEnabled = on;
6657ea7a892SMarc Flerackers	fMenuBar->SetEnabled(on);
6667ea7a892SMarc Flerackers
667789f68f0SAxel Dörfler	if (Window()) {
6687ea7a892SMarc Flerackers		fMenuBar->Invalidate(fMenuBar->Bounds());
6697ea7a892SMarc Flerackers		Invalidate(Bounds());
6707ea7a892SMarc Flerackers	}
6717ea7a892SMarc Flerackers}
672789f68f0SAxel Dörfler
673789f68f0SAxel Dörfler
674789f68f0SAxel Dörflerbool
675789f68f0SAxel DörflerBMenuField::IsEnabled() const
6767ea7a892SMarc Flerackers{
6777ea7a892SMarc Flerackers	return fEnabled;
6787ea7a892SMarc Flerackers}
679789f68f0SAxel Dörfler
680789f68f0SAxel Dörfler
681789f68f0SAxel Dörflervoid
682789f68f0SAxel DörflerBMenuField::SetAlignment(alignment label)
6837ea7a892SMarc Flerackers{
6847ea7a892SMarc Flerackers	fAlign = label;
6857ea7a892SMarc Flerackers}
686789f68f0SAxel Dörfler
687789f68f0SAxel Dörfler
688789f68f0SAxel Dörfleralignment
689789f68f0SAxel DörflerBMenuField::Alignment() const
6907ea7a892SMarc Flerackers{
6917ea7a892SMarc Flerackers	return fAlign;
6927ea7a892SMarc Flerackers}
693789f68f0SAxel Dörfler
694789f68f0SAxel Dörfler
695789f68f0SAxel Dörflervoid
69691810d8eSJohn ScipioneBMenuField::SetDivider(float position)
6977ea7a892SMarc Flerackers{
69817aed1bfSJohn Scipione	position = roundf(position);
6992e6a5805SStephan Aßmus
70091810d8eSJohn Scipione	float delta = fDivider - position;
70191810d8eSJohn Scipione	if (delta == 0.0f)
7027ea7a892SMarc Flerackers		return;
7037ea7a892SMarc Flerackers
70491810d8eSJohn Scipione	fDivider = position;
7057ea7a892SMarc Flerackers
706df5d08a7SJohn Scipione	if ((Flags() & B_SUPPORTS_LAYOUT) != 0) {
707b321303cSIngo Weinhold		// We should never get here, since layout support means, we also
708b321303cSIngo Weinhold		// layout the divider, and don't use this method at all.
709b321303cSIngo Weinhold		Relayout();
710b321303cSIngo Weinhold	} else {
711b321303cSIngo Weinhold		BRect dirty(fMenuBar->Frame());
7129ecf9d1cSIngo Weinhold
713cda78e4fSStephan Aßmus		fMenuBar->MoveTo(_MenuBarOffset(), kVMargin);
7149ecf9d1cSIngo Weinhold
7151c95f722SJohn Scipione		if (fFixedSizeMB)
71647e745c6SStephan Aßmus			fMenuBar->ResizeTo(_MenuBarWidth(), dirty.Height());
7179ecf9d1cSIngo Weinhold
718b321303cSIngo Weinhold		dirty = dirty | fMenuBar->Frame();
719b321303cSIngo Weinhold		dirty.InsetBy(-kVMargin, -kVMargin);
7209ecf9d1cSIngo Weinhold
721b321303cSIngo Weinhold		Invalidate(dirty);
722b321303cSIngo Weinhold	}
7237ea7a892SMarc Flerackers}
724789f68f0SAxel Dörfler
725789f68f0SAxel Dörfler
726789f68f0SAxel Dörflerfloat
727789f68f0SAxel DörflerBMenuField::Divider() const
7287ea7a892SMarc Flerackers{
7297ea7a892SMarc Flerackers	return fDivider;
7307ea7a892SMarc Flerackers}
731789f68f0SAxel Dörfler
732789f68f0SAxel Dörfler
733789f68f0SAxel Dörflervoid
734789f68f0SAxel DörflerBMenuField::ShowPopUpMarker()
7357ea7a892SMarc Flerackers{
73650f8cd14SAxel Dörfler	if (_BMCMenuBar_* menuBar = dynamic_cast<_BMCMenuBar_*>(fMenuBar)) {
737cd39deccSStefano Ceccherini		menuBar->TogglePopUpMarker(true);
738cd39deccSStefano Ceccherini		menuBar->Invalidate();
739cd39deccSStefano Ceccherini	}
7407ea7a892SMarc Flerackers}
741789f68f0SAxel Dörfler
742789f68f0SAxel Dörfler
743789f68f0SAxel Dörflervoid
744789f68f0SAxel DörflerBMenuField::HidePopUpMarker()
7457ea7a892SMarc Flerackers{
74650f8cd14SAxel Dörfler	if (_BMCMenuBar_* menuBar = dynamic_cast<_BMCMenuBar_*>(fMenuBar)) {
747cd39deccSStefano Ceccherini		menuBar->TogglePopUpMarker(false);
748cd39deccSStefano Ceccherini		menuBar->Invalidate();
749cd39deccSStefano Ceccherini	}
7507ea7a892SMarc Flerackers}
751789f68f0SAxel Dörfler
752789f68f0SAxel Dörfler
75350f8cd14SAxel DörflerBHandler*
75450f8cd14SAxel DörflerBMenuField::ResolveSpecifier(BMessage* message, int32 index,
75550f8cd14SAxel Dörfler	BMessage* specifier, int32 form, const char* property)
7567ea7a892SMarc Flerackers{
757789f68f0SAxel Dörfler	return BView::ResolveSpecifier(message, index, specifier, form, property);
7587ea7a892SMarc Flerackers}
759789f68f0SAxel Dörfler
760789f68f0SAxel Dörfler
761789f68f0SAxel Dörflerstatus_t
76250f8cd14SAxel DörflerBMenuField::GetSupportedSuites(BMessage* data)
7637ea7a892SMarc Flerackers{
7647ea7a892SMarc Flerackers	return BView::GetSupportedSuites(data);
7657ea7a892SMarc Flerackers}
766789f68f0SAxel Dörfler
767789f68f0SAxel Dörfler
768789f68f0SAxel Dörflervoid
769789f68f0SAxel DörflerBMenuField::ResizeToPreferred()
7707ea7a892SMarc Flerackers{
77114f63456SStephan Aßmus	CALLED();
77214f63456SStephan Aßmus
77314f63456SStephan Aßmus	TRACE("fMenuBar->Frame().width: %.2f, height: %.2f\n",
77414f63456SStephan Aßmus		fMenuBar->Frame().Width(), fMenuBar->Frame().Height());
77514f63456SStephan Aßmus
776c72e7319SStephan Aßmus	fMenuBar->ResizeToPreferred();
777c72e7319SStephan Aßmus
77814f63456SStephan Aßmus	TRACE("fMenuBar->Frame().width: %.2f, height: %.2f\n",
77914f63456SStephan Aßmus		fMenuBar->Frame().Width(), fMenuBar->Frame().Height());
78014f63456SStephan Aßmus
7817ea7a892SMarc Flerackers	BView::ResizeToPreferred();
782c831635fSStephan Aßmus
783ca3a1c04SJohn Scipione	Invalidate();
7847ea7a892SMarc Flerackers}
785789f68f0SAxel Dörfler
786789f68f0SAxel Dörfler
7875e3af71dSAxel Dörflervoid
788