xref: /haiku/src/kits/tracker/DialogPane.cpp (revision 850f2d1e58cc443f77353c7fc0ce0c158c1fd328)
1 /*
2 Open Tracker License
3 
4 Terms and Conditions
5 
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7 
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
14 
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
28 
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
32 All rights reserved.
33 */
34 
35 
36 #include "DialogPane.h"
37 
38 #include <ControlLook.h>
39 #include <LayoutUtils.h>
40 
41 #include "Thread.h"
42 #include "Utilities.h"
43 #include "Window.h"
44 
45 
46 const uint32 kValueChanged = 'swch';
47 
48 const rgb_color kNormalColor = {150, 150, 150, 255};
49 const rgb_color kHighlightColor = {100, 100, 0, 255};
50 
51 
52 static void
53 AddSelf(BView* self, BView* to)
54 {
55 	to->AddChild(self);
56 }
57 
58 
59 void
60 ViewList::RemoveAll(BView*)
61 {
62 	EachListItemIgnoreResult(this, &BView::RemoveSelf);
63 }
64 
65 
66 void
67 ViewList::AddAll(BView* toParent)
68 {
69 	EachListItem(this, &AddSelf, toParent);
70 }
71 
72 
73 //	#pragma mark - DialogPane
74 
75 
76 DialogPane::DialogPane(BRect mode1Frame, BRect mode2Frame, int32 initialMode,
77 	const char* name, uint32 followFlags, uint32 flags)
78 	:
79 	BView(FrameForMode(initialMode, mode1Frame, mode2Frame, mode2Frame),
80 		name, followFlags, flags),
81 	fMode(initialMode),
82 	fMode1Frame(mode1Frame),
83 	fMode2Frame(mode2Frame),
84 	fMode3Frame(mode2Frame)
85 {
86 	SetMode(fMode, true);
87 }
88 
89 
90 DialogPane::DialogPane(BRect mode1Frame, BRect mode2Frame, BRect mode3Frame,
91 	int32 initialMode, const char* name, uint32 followFlags, uint32 flags)
92 	:
93 	BView(FrameForMode(initialMode, mode1Frame, mode2Frame, mode3Frame),
94 		name, followFlags, flags),
95 	fMode(initialMode),
96 	fMode1Frame(mode1Frame),
97 	fMode2Frame(mode2Frame),
98 	fMode3Frame(mode3Frame)
99 {
100 	SetMode(fMode, true);
101 }
102 
103 
104 DialogPane::~DialogPane()
105 {
106 	fMode3Items.RemoveAll(this);
107 	fMode2Items.RemoveAll(this);
108 }
109 
110 
111 void
112 DialogPane::SetMode(int32 mode, bool initialSetup)
113 {
114 	ASSERT(mode < 3 && mode >= 0);
115 
116 	if (!initialSetup && mode == fMode)
117 		return;
118 
119 	int32 oldMode = fMode;
120 	fMode = mode;
121 
122 	bool followBottom = (ResizingMode() & B_FOLLOW_BOTTOM) != 0;
123 	// if we are follow bottom, we will move ourselves, need to place us back
124 	float bottomOffset = 0;
125 	if (followBottom && Window() != NULL)
126 		bottomOffset = Window()->Bounds().bottom - Frame().bottom;
127 
128 	BRect newBounds(BoundsForMode(fMode));
129 	if (!initialSetup)
130 		ResizeParentWindow(fMode, oldMode);
131 
132 	ResizeTo(newBounds.Width(), newBounds.Height());
133 
134 	float delta = 0;
135 	if (followBottom && Window() != NULL)
136 		delta = (Window()->Bounds().bottom - Frame().bottom) - bottomOffset;
137 
138 	if (delta != 0) {
139 		MoveBy(0, delta);
140 		if (fLatch && (fLatch->ResizingMode() & B_FOLLOW_BOTTOM))
141 			fLatch->MoveBy(0, delta);
142 	}
143 
144 	switch (fMode) {
145 		case 0:
146 		{
147 			if (oldMode > 1)
148 				fMode3Items.RemoveAll(this);
149 			if (oldMode > 0)
150 				fMode2Items.RemoveAll(this);
151 
152 			BView* separator = FindView("separatorLine");
153 			if (separator) {
154 				BRect frame(separator->Frame());
155 				frame.InsetBy(-1, -1);
156 				RemoveChild(separator);
157 				Invalidate();
158 			}
159 
160 			AddChild(new SeparatorLine(BPoint(newBounds.left, newBounds.top
161 				+ newBounds.Height() / 2), newBounds.Width(), false,
162 				"separatorLine"));
163 			break;
164 		}
165 
166 		case 1:
167 		{
168 			if (oldMode > 1)
169 				fMode3Items.RemoveAll(this);
170 			else
171 				fMode2Items.AddAll(this);
172 
173 			BView* separator = FindView("separatorLine");
174 			if (separator) {
175 				BRect frame(separator->Frame());
176 				frame.InsetBy(-1, -1);
177 				RemoveChild(separator);
178 				Invalidate();
179 			}
180 			break;
181 		}
182 
183 		case 2:
184 		{
185 			fMode3Items.AddAll(this);
186 			if (oldMode < 1)
187 				fMode2Items.AddAll(this);
188 
189 			BView* separator = FindView("separatorLine");
190 			if (separator) {
191 				BRect frame(separator->Frame());
192 				frame.InsetBy(-1, -1);
193 				RemoveChild(separator);
194 				Invalidate();
195 			}
196 			break;
197 		}
198 	}
199 }
200 
201 
202 void
203 DialogPane::AttachedToWindow()
204 {
205 	BView* parent = Parent();
206 	if (parent != NULL) {
207 		SetViewColor(parent->ViewColor());
208 		SetLowColor(parent->LowColor());
209 	}
210 }
211 
212 
213 void
214 DialogPane::ResizeParentWindow(int32 from, int32 to)
215 {
216 	if (Window() == NULL)
217 		return;
218 
219 	BRect oldBounds = BoundsForMode(from);
220 	BRect newBounds = BoundsForMode(to);
221 
222 	BPoint by = oldBounds.RightBottom() - newBounds.RightBottom();
223 	if (by != BPoint(0, 0))
224 		Window()->ResizeBy(by.x, by.y);
225 }
226 
227 
228 void
229 DialogPane::AddItem(BView* view, int32 toMode)
230 {
231 	if (toMode == 1)
232 		fMode2Items.AddItem(view);
233 	else if (toMode == 2)
234 		fMode3Items.AddItem(view);
235 
236 	if (fMode >= toMode)
237 		AddChild(view);
238 }
239 
240 
241 BRect
242 DialogPane::FrameForMode(int32 mode)
243 {
244 	switch (mode) {
245 		case 0:
246 			return fMode1Frame;
247 
248 		case 1:
249 			return fMode2Frame;
250 
251 		case 2:
252 			return fMode3Frame;
253 	}
254 
255 	return fMode1Frame;
256 }
257 
258 
259 BRect
260 DialogPane::BoundsForMode(int32 mode)
261 {
262 	BRect result;
263 	switch (mode) {
264 		case 0:
265 			result = fMode1Frame;
266 			break;
267 
268 		case 1:
269 			result = fMode2Frame;
270 			break;
271 
272 		case 2:
273 			result = fMode3Frame;
274 			break;
275 	}
276 	result.OffsetTo(0, 0);
277 
278 	return result;
279 }
280 
281 
282 BRect
283 DialogPane::FrameForMode(int32 mode, BRect mode1Frame, BRect mode2Frame,
284 	BRect mode3Frame)
285 {
286 	switch (mode) {
287 		case 0:
288 			return mode1Frame;
289 
290 		case 1:
291 			return mode2Frame;
292 
293 		case 2:
294 			return mode3Frame;
295 	}
296 
297 	return mode1Frame;
298 }
299 
300 
301 void
302 DialogPane::SetSwitch(BControl* control)
303 {
304 	fLatch = control;
305 	control->SetMessage(new BMessage(kValueChanged));
306 	control->SetTarget(this);
307 }
308 
309 
310 void
311 DialogPane::MessageReceived(BMessage* message)
312 {
313 	if (message->what == kValueChanged) {
314 		int32 value;
315 		if (message->FindInt32("be:value", &value) == B_OK)
316 			SetMode(value);
317 	} else
318 		_inherited::MessageReceived(message);
319 }
320 
321 
322 //	#pragma mark - PaneSwitch
323 
324 
325 PaneSwitch::PaneSwitch(BRect frame, const char* name, bool leftAligned,
326 		uint32 resizeMask, uint32 flags)
327 	:
328 	BControl(frame, name, "", 0, resizeMask, flags),
329 	fLeftAligned(leftAligned),
330 	fPressing(false),
331 	fLabelOn(NULL),
332 	fLabelOff(NULL)
333 {
334 }
335 
336 
337 PaneSwitch::PaneSwitch(const char* name, bool leftAligned, uint32 flags)
338 	:
339 	BControl(name, "", 0, flags),
340 	fLeftAligned(leftAligned),
341 	fPressing(false),
342 	fLabelOn(NULL),
343 	fLabelOff(NULL)
344 {
345 }
346 
347 
348 PaneSwitch::~PaneSwitch()
349 {
350 	free(fLabelOn);
351 	free(fLabelOff);
352 }
353 
354 
355 void
356 PaneSwitch::Draw(BRect)
357 {
358 	BRect bounds(Bounds());
359 
360 	// Draw the label, if any
361 	const char* label = fLabelOff;
362 	if (fLabelOn != NULL && Value() == B_CONTROL_ON)
363 		label = fLabelOn;
364 
365 	if (label != NULL) {
366 		BPoint point;
367 		float labelDist = sLatchSize + ceilf(sLatchSize / 2.0);
368 		if (fLeftAligned)
369 			point.x = labelDist;
370 		else
371 			point.x = bounds.right - labelDist - StringWidth(label);
372 
373 		font_height fontHeight;
374 		GetFontHeight(&fontHeight);
375 		point.y = (bounds.top + bounds.bottom
376 			- ceilf(fontHeight.ascent) - ceilf(fontHeight.descent)) / 2
377 			+ ceilf(fontHeight.ascent);
378 
379 		DrawString(label, point);
380 	}
381 
382 	// draw the latch
383 	if (fPressing)
384 		DrawInState(kPressed);
385 	else if (Value())
386 		DrawInState(kExpanded);
387 	else
388 		DrawInState(kCollapsed);
389 
390 	// ...and the focus indication
391 	if (!IsFocus() || !Window()->IsActive())
392 		return;
393 
394 	rgb_color markColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
395 
396 	BeginLineArray(2);
397 	AddLine(BPoint(bounds.left + 2, bounds.bottom - 1),
398 		BPoint(bounds.right - 2, bounds.bottom - 1), markColor);
399 	AddLine(BPoint(bounds.left + 2, bounds.bottom),
400 		BPoint(bounds.right - 2, bounds.bottom), kWhite);
401 	EndLineArray();
402 }
403 
404 
405 void
406 PaneSwitch::MouseDown(BPoint)
407 {
408 	if (!IsEnabled())
409 		return;
410 
411 	fPressing = true;
412 	MouseDownThread<PaneSwitch>::TrackMouse(this, &PaneSwitch::DoneTracking,
413 		&PaneSwitch::Track);
414 	Invalidate();
415 }
416 
417 
418 void
419 PaneSwitch::GetPreferredSize(float* _width, float* _height)
420 {
421 	BSize size = MinSize();
422 	if (_width != NULL)
423 		*_width = size.width;
424 
425 	if (_height != NULL)
426 		*_height = size.height;
427 }
428 
429 
430 BSize
431 PaneSwitch::MinSize()
432 {
433 	BSize size;
434 	float onLabelWidth = StringWidth(fLabelOn);
435 	float offLabelWidth = StringWidth(fLabelOff);
436 	float labelWidth = max_c(onLabelWidth, offLabelWidth);
437 	size.width = sLatchSize;
438 	if (labelWidth > 0.0)
439 		size.width += ceilf(sLatchSize / 2.0) + labelWidth;
440 
441 	font_height fontHeight;
442 	GetFontHeight(&fontHeight);
443 	size.height = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
444 	size.height = max_c(size.height, sLatchSize);
445 
446 	return BLayoutUtils::ComposeSize(ExplicitMinSize(), size);
447 }
448 
449 
450 BSize
451 PaneSwitch::MaxSize()
452 {
453 	return BLayoutUtils::ComposeSize(ExplicitMaxSize(), MinSize());
454 }
455 
456 
457 BSize
458 PaneSwitch::PreferredSize()
459 {
460 	return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), MinSize());
461 }
462 
463 
464 void
465 PaneSwitch::SetLabels(const char* labelOn, const char* labelOff)
466 {
467 	free(fLabelOn);
468 	free(fLabelOff);
469 
470 	if (labelOn != NULL)
471 		fLabelOn = strdup(labelOn);
472 	else
473 		fLabelOn = NULL;
474 
475 	if (labelOff != NULL)
476 		fLabelOff = strdup(labelOff);
477 	else
478 		fLabelOff = NULL;
479 
480 	Invalidate();
481 	InvalidateLayout();
482 }
483 
484 
485 void
486 PaneSwitch::DoneTracking(BPoint point)
487 {
488 	BRect bounds(Bounds());
489 	bounds.InsetBy(-3, -3);
490 
491 	fPressing = false;
492 	Invalidate();
493 	if (bounds.Contains(point)) {
494 		SetValue(!Value());
495 		Invoke();
496 	}
497 }
498 
499 
500 void
501 PaneSwitch::Track(BPoint point, uint32)
502 {
503 	BRect bounds(Bounds());
504 	bounds.InsetBy(-3, -3);
505 
506 	bool newPressing = bounds.Contains(point);
507 	if (newPressing != fPressing) {
508 		fPressing = newPressing;
509 		Invalidate();
510 	}
511 }
512 
513 
514 void
515 PaneSwitch::DrawInState(PaneSwitch::State state)
516 {
517 	BRect rect(0, 0, be_plain_font->Size(), be_plain_font->Size());
518 	rect.OffsetBy(1, 1);
519 
520 	rgb_color arrowColor = state == kPressed ? kHighlightColor : kNormalColor;
521 	int32 arrowDirection = BControlLook::B_RIGHT_ARROW;
522 	float tint = IsEnabled() && Window()->IsActive() ? B_DARKEN_3_TINT
523 		: B_DARKEN_1_TINT;
524 
525 	switch (state) {
526 		case kCollapsed:
527 			arrowDirection = BControlLook::B_RIGHT_ARROW;
528 			break;
529 
530 		case kPressed:
531 			arrowDirection = BControlLook::B_RIGHT_DOWN_ARROW;
532 			break;
533 
534 		case kExpanded:
535 			arrowDirection = BControlLook::B_DOWN_ARROW;
536 			break;
537 	}
538 
539 	SetDrawingMode(B_OP_COPY);
540 	be_control_look->DrawArrowShape(this, rect, rect, arrowColor,
541 		arrowDirection, 0, tint);
542 }
543