xref: /haiku/src/kits/interface/BMCPrivate.cpp (revision a4f6a81235ca2522c01f532de13cad9b729d4029)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2001-2002, OpenBeOS
3 //
4 //	Permission is hereby granted, free of charge, to any person obtaining a
5 //	copy of this software and associated documentation files (the "Software"),
6 //	to deal in the Software without restriction, including without limitation
7 //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 //	and/or sell copies of the Software, and to permit persons to whom the
9 //	Software is furnished to do so, subject to the following conditions:
10 //
11 //	The above copyright notice and this permission notice shall be included in
12 //	all copies or substantial portions of the Software.
13 //
14 //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 //	DEALINGS IN THE SOFTWARE.
21 //
22 //	File Name:		BMCPrivate.cpp
23 //	Author:			Marc Flerackers (mflerackers@androme.be)
24 //	Description:	The BMCPrivate classes are used by BMenuField.
25 //------------------------------------------------------------------------------
26 
27 #include <BMCPrivate.h>
28 #include <MenuField.h>
29 #include <MenuItem.h>
30 #include <Message.h>
31 #include <Region.h>
32 #include <Window.h>
33 
34 
35 _BMCItem_::_BMCItem_(BMenu *menu)
36 	:	BMenuItem(menu),
37 		fShowPopUpMarker(true)
38 {
39 }
40 
41 
42 _BMCItem_::_BMCItem_(BMessage *message)
43 	:	BMenuItem(message),
44 		fShowPopUpMarker(true)
45 {
46 }
47 
48 
49 _BMCItem_::~_BMCItem_()
50 {
51 }
52 
53 
54 BArchivable *
55 _BMCItem_::Instantiate(BMessage *data)
56 {
57 	if (validate_instantiation(data, "_BMCItem_"))
58 		return new _BMCItem_(data);
59 	else
60 		return NULL;
61 }
62 
63 
64 void
65 _BMCItem_::Draw()
66 {
67 	BMenu *menu = Menu();
68 
69 	BMenuItem::Draw();
70 
71 	if (!fShowPopUpMarker)
72 		return;
73 
74 	BRect rect(menu->Bounds());
75 
76 	rect.right -= 4;
77 	rect.bottom -= 5;
78 	rect.left = rect.right - 4;
79 	rect.top = rect.bottom - 2;
80 
81 	if (IsEnabled())
82 		menu->SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR),
83 			B_DARKEN_4_TINT));
84 	else
85 		menu->SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR),
86 			B_DARKEN_4_TINT));
87 
88 	menu->StrokeLine(BPoint(rect.left, rect.top), BPoint(rect.right, rect.top));
89 	menu->StrokeLine(BPoint(rect.left + 1.0f, rect.top + 1.0f),
90 		BPoint(rect.right - 1.0f, rect.top + 1.0f));
91 	menu->StrokeLine(BPoint(rect.left + 2.0f, rect.bottom),
92 		BPoint(rect.left + 2.0f, rect.bottom));
93 }
94 
95 
96 void
97 _BMCItem_::GetContentSize(float *width, float *height)
98 {
99 	BMenuItem::GetContentSize(width, height);
100 }
101 
102 
103 /*
104 _BMCFilter_::_BMCFilter_(BMenuField *menuField, uint32)
105 {
106 }
107 
108 
109 _BMCFilter_::~_BMCFilter_()
110 {
111 }
112 
113 
114 filter_result
115 _BMCFilter_::Filter(BMessage *message, BHandler **handler)
116 {
117 }
118 
119 
120 _BMCFilter_ &
121 _BMCFilter_::operator=(const _BMCFilter_ &)
122 {
123 	return *this;
124 }*/
125 
126 
127 _BMCMenuBar_::_BMCMenuBar_(BRect frame, bool fixed_size, BMenuField *menuField)
128 	:	BMenuBar(frame, "_mc_mb_", B_FOLLOW_LEFT | B_FOLLOW_TOP, B_ITEMS_IN_ROW,
129 			!fixed_size)
130 {
131 	SetFlags(Flags() | B_FRAME_EVENTS);
132 	SetBorder(B_BORDER_CONTENTS);
133 
134 	fMenuField = menuField;
135 	fFixedSize = fixed_size;
136 	fRunner = NULL;
137 
138 	float left, top, right, bottom;
139 
140 	GetItemMargins(&left, &top, &right, &bottom);
141 	SetItemMargins(left, top, right, bottom); // TODO:
142 
143 	SetMaxContentWidth(frame.Width() - (left + right));
144 }
145 
146 
147 _BMCMenuBar_::_BMCMenuBar_(BMessage *data)
148 	:	BMenuBar(data)
149 {
150 	SetFlags(Flags() | B_FRAME_EVENTS);
151 
152 	bool rsize_to_fit;
153 
154 	if (data->FindBool("_rsize_to_fit", &rsize_to_fit) == B_OK)
155 		fFixedSize = !rsize_to_fit;
156 	else
157 		fFixedSize = true;
158 }
159 
160 
161 _BMCMenuBar_::~_BMCMenuBar_()
162 {
163 }
164 
165 
166 BArchivable *
167 _BMCMenuBar_::Instantiate(BMessage *data)
168 {
169 	if (validate_instantiation(data, "_BMCMenuBar_"))
170 		return new _BMCMenuBar_(data);
171 	else
172 		return NULL;
173 }
174 
175 
176 void
177 _BMCMenuBar_::AttachedToWindow()
178 {
179 	fMenuField = (BMenuField*)Parent();
180 
181 	BMenuBar *menuBar = Window()->KeyMenuBar();
182 	BMenuBar::AttachedToWindow();
183 	Window()->SetKeyMenuBar(menuBar);
184 }
185 
186 
187 void
188 _BMCMenuBar_::Draw(BRect updateRect)
189 {
190 	// draw the right and bottom line here in a darker tint
191 	BRect bounds(Bounds());
192 	bounds.right -= 2.0;
193 	bounds.bottom -= 1.0;
194 
195 	// prevent the original BMenuBar's Draw from
196 	// drawing in those parts
197 	BRegion clipping(bounds);
198 	ConstrainClippingRegion(&clipping);
199 
200 	BMenuBar::Draw(updateRect);
201 
202 	ConstrainClippingRegion(NULL);
203 
204 	bounds.right += 2.0;
205 	bounds.bottom += 1.0;
206 
207 	SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_4_TINT));
208 	StrokeLine(BPoint(bounds.left, bounds.bottom),
209 			   BPoint(bounds.right, bounds.bottom));
210 	StrokeLine(BPoint(bounds.right, bounds.bottom - 1),
211 			   BPoint(bounds.right, bounds.top));
212 	SetHighColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR), B_DARKEN_1_TINT));
213 	StrokeLine(BPoint(bounds.right - 1, bounds.bottom - 1),
214 			   BPoint(bounds.right - 1, bounds.top + 1));
215 }
216 
217 
218 void
219 _BMCMenuBar_::FrameResized(float width, float height)
220 {
221 	// we need to take care of resizing and cleaning up
222 	// the parent menu field
223 	float diff = Frame().right - fMenuField->Bounds().right;
224 	if (Window()) {
225 		if (diff > 0) {
226 			// clean up the dirty right top corner of
227 			// the menu field when enlarging
228 			BRect dirty(fMenuField->Bounds());
229 			dirty.left = dirty.right - 2;
230 			dirty.bottom = Frame().top - 1;
231 			fMenuField->Invalidate(dirty);
232 		} else if (diff < 0) {
233 			// clean up the dirty right line of
234 			// the menu field when shrinking
235 			BRect dirty(fMenuField->Bounds());
236 			dirty.left = dirty.right + diff + 1;
237 			dirty.right = dirty.left + 1;
238 			fMenuField->Invalidate(dirty);
239 		}
240 	}
241 	// we have been shrinked or enlarged and need to take
242 	// of the size of the parent menu field as well
243 	// NOTE: no worries about follow mode, we follow left and top
244 	fMenuField->ResizeBy(diff + 2, 0.0);
245 	BMenuBar::FrameResized(width, height);
246 }
247 
248 
249 void
250 _BMCMenuBar_::MessageReceived(BMessage *msg)
251 {
252 	switch (msg->what) {
253 		case 'TICK':
254 		{
255 			BMenuItem *item = ItemAt(0);
256 
257 			if (item && item->Submenu() &&  item->Submenu()->Window()) {
258 				BMessage message(B_KEY_DOWN);
259 
260 				message.AddInt8("byte", B_ESCAPE);
261 				message.AddInt8("key", B_ESCAPE);
262 				message.AddInt32("modifiers", 0);
263 				message.AddInt8("raw_char", B_ESCAPE);
264 
265 				Window()->PostMessage(&message, this, NULL);
266 			}
267 		}
268 		// fall through
269 		default:
270 			BMenuBar::MessageReceived(msg);
271 			break;
272 	}
273 }
274 
275 
276 void
277 _BMCMenuBar_::MakeFocus(bool focused)
278 {
279 	if (IsFocus() == focused)
280 		return;
281 
282 	BMenuBar::MakeFocus(focused);
283 
284 	if (focused) {
285 		BMessage message('TICK');
286 		//fRunner = new BMessageRunner(BMessenger(this, NULL, NULL), &message,
287 		//	50000, -1);
288 	} else if (fRunner) {
289 		//delete fRunner;
290 		fRunner = NULL;
291 	}
292 
293 	if (focused)
294 		return;
295 
296 	fMenuField->fSelected = false;
297 	fMenuField->fTransition = true;
298 
299 	BRect bounds(fMenuField->Bounds());
300 
301 	fMenuField->Invalidate(BRect(bounds.left, bounds.top, fMenuField->fDivider,
302 		bounds.bottom));
303 }
304 
305 
306 void
307 _BMCMenuBar_::MouseDown(BPoint where)
308 {
309 	// Don't show the associated menu if it's disabled
310 	if (fMenuField->IsEnabled() && SubmenuAt(0)->IsEnabled())
311 		BMenuBar::MouseDown(where);
312 }
313 
314 
315 _BMCMenuBar_
316 &_BMCMenuBar_::operator=(const _BMCMenuBar_ &)
317 {
318 	return *this;
319 }
320