xref: /haiku/src/kits/tracker/DialogPane.cpp (revision b671e9bbdbd10268a042b4f4cc4317ccd03d105e)
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 #include "DialogPane.h"
36 
37 #include <LayoutUtils.h>
38 
39 #include "Thread.h"
40 #include "Utilities.h"
41 #include "Window.h"
42 
43 
44 const uint32 kValueChanged = 'swch';
45 
46 const rgb_color kNormalColor = {150, 150, 150, 255};
47 const rgb_color kHighlightColor = {100, 100, 0, 255};
48 
49 
50 static void
51 AddSelf(BView *self, BView *to)
52 {
53 	to->AddChild(self);
54 }
55 
56 
57 void
58 ViewList::RemoveAll(BView *)
59 {
60 	EachListItemIgnoreResult(this, &BView::RemoveSelf);
61 }
62 
63 
64 void
65 ViewList::AddAll(BView *toParent)
66 {
67 	EachListItem(this, &AddSelf, toParent);
68 }
69 
70 
71 //	#pragma mark -
72 
73 
74 DialogPane::DialogPane(BRect mode1Frame, BRect mode2Frame, int32 initialMode,
75 	const char *name, uint32 followFlags, uint32 flags)
76 	: BView(FrameForMode(initialMode, mode1Frame, mode2Frame, mode2Frame),
77 		name, followFlags, flags),
78 	fMode(initialMode),
79 	fMode1Frame(mode1Frame),
80 	fMode2Frame(mode2Frame),
81 	fMode3Frame(mode2Frame)
82 {
83 	SetMode(fMode, true);
84 }
85 
86 
87 DialogPane::DialogPane(BRect mode1Frame, BRect mode2Frame, BRect mode3Frame,
88 	int32 initialMode, const char *name, uint32 followFlags, uint32 flags)
89 	: BView(FrameForMode(initialMode, mode1Frame, mode2Frame, mode3Frame),
90 		name, followFlags, flags),
91 	fMode(initialMode),
92 	fMode1Frame(mode1Frame),
93 	fMode2Frame(mode2Frame),
94 	fMode3Frame(mode3Frame)
95 {
96 	SetMode(fMode, true);
97 }
98 
99 
100 DialogPane::~DialogPane()
101 {
102 	fMode3Items.RemoveAll(this);
103 	fMode2Items.RemoveAll(this);
104 }
105 
106 
107 void
108 DialogPane::SetMode(int32 mode, bool initialSetup)
109 {
110 	ASSERT(mode < 3 && mode >= 0);
111 
112 	if (!initialSetup && mode == fMode)
113 		return;
114 
115 	int32 oldMode = fMode;
116 	fMode = mode;
117 
118 	bool followBottom = (ResizingMode() & B_FOLLOW_BOTTOM) != 0;
119 	// if we are follow bottom, we will move ourselves, need to place us back
120 	float bottomOffset = 0;
121 	if (followBottom && Window() != NULL)
122 		bottomOffset = Window()->Bounds().bottom - Frame().bottom;
123 
124 	BRect newBounds(BoundsForMode(fMode));
125 	if (!initialSetup)
126 		ResizeParentWindow(fMode, oldMode);
127 
128 	ResizeTo(newBounds.Width(), newBounds.Height());
129 
130 	float delta = 0;
131 	if (followBottom && Window() != NULL)
132 		delta = (Window()->Bounds().bottom - Frame().bottom) - bottomOffset;
133 
134 	if (delta != 0) {
135 		MoveBy(0, delta);
136 		if (fLatch && (fLatch->ResizingMode() & B_FOLLOW_BOTTOM))
137 			fLatch->MoveBy(0, delta);
138 	}
139 
140 	switch (fMode) {
141 		case 0:
142 		{
143 			if (oldMode > 1)
144 				fMode3Items.RemoveAll(this);
145 			if (oldMode > 0)
146 				fMode2Items.RemoveAll(this);
147 
148 			BView *separator = FindView("separatorLine");
149 			if (separator) {
150 				BRect frame(separator->Frame());
151 				frame.InsetBy(-1, -1);
152 				RemoveChild(separator);
153 				Invalidate();
154 			}
155 
156 			AddChild(new SeparatorLine(BPoint(newBounds.left, newBounds.top
157 				+ newBounds.Height() / 2), newBounds.Width(), false,
158 				"separatorLine"));
159 			break;
160 		}
161 		case 1:
162 		{
163 			if (oldMode > 1)
164 				fMode3Items.RemoveAll(this);
165 			else
166 				fMode2Items.AddAll(this);
167 
168 			BView *separator = FindView("separatorLine");
169 			if (separator) {
170 				BRect frame(separator->Frame());
171 				frame.InsetBy(-1, -1);
172 				RemoveChild(separator);
173 				Invalidate();
174 			}
175 			break;
176 		}
177 		case 2:
178 		{
179 			fMode3Items.AddAll(this);
180 			if (oldMode < 1)
181 				fMode2Items.AddAll(this);
182 
183 			BView *separator = FindView("separatorLine");
184 			if (separator) {
185 				BRect frame(separator->Frame());
186 				frame.InsetBy(-1, -1);
187 				RemoveChild(separator);
188 				Invalidate();
189 			}
190 			break;
191 		}
192 	}
193 }
194 
195 
196 void
197 DialogPane::AttachedToWindow()
198 {
199 	BView *parent = Parent();
200 	if (parent) {
201 		SetViewColor(parent->ViewColor());
202 		SetLowColor(parent->LowColor());
203 	}
204 }
205 
206 
207 void
208 DialogPane::ResizeParentWindow(int32 from, int32 to)
209 {
210 	if (!Window())
211 		return;
212 
213 	BRect oldBounds = BoundsForMode(from);
214 	BRect newBounds = BoundsForMode(to);
215 
216 	BPoint by = oldBounds.RightBottom() - newBounds.RightBottom();
217 	if (by != BPoint(0, 0))
218 		Window()->ResizeBy(by.x, by.y);
219 }
220 
221 
222 void
223 DialogPane::AddItem(BView *view, int32 toMode)
224 {
225 	if (toMode == 1)
226 		fMode2Items.AddItem(view);
227 	else if (toMode == 2)
228 		fMode3Items.AddItem(view);
229 	if (fMode >= toMode)
230 		AddChild(view);
231 }
232 
233 
234 BRect
235 DialogPane::FrameForMode(int32 mode)
236 {
237 	switch (mode) {
238 		case 0:
239 			return fMode1Frame;
240 		case 1:
241 			return fMode2Frame;
242 		case 2:
243 			return fMode3Frame;
244 	}
245 	return fMode1Frame;
246 }
247 
248 
249 BRect
250 DialogPane::BoundsForMode(int32 mode)
251 {
252 	BRect result;
253 	switch (mode) {
254 		case 0:
255 			result = fMode1Frame;
256 			break;
257 		case 1:
258 			result = fMode2Frame;
259 			break;
260 		case 2:
261 			result = fMode3Frame;
262 			break;
263 	}
264 	result.OffsetTo(0, 0);
265 	return result;
266 }
267 
268 
269 BRect
270 DialogPane::FrameForMode(int32 mode, BRect mode1Frame, BRect mode2Frame,
271 	BRect mode3Frame)
272 {
273 	switch (mode) {
274 		case 0:
275 			return mode1Frame;
276 		case 1:
277 			return mode2Frame;
278 		case 2:
279 			return mode3Frame;
280 	}
281 	return mode1Frame;
282 }
283 
284 
285 void
286 DialogPane::SetSwitch(BControl *control)
287 {
288 	fLatch = control;
289 	control->SetMessage(new BMessage(kValueChanged));
290 	control->SetTarget(this);
291 }
292 
293 
294 void
295 DialogPane::MessageReceived(BMessage *message)
296 {
297 	if (message->what == kValueChanged) {
298 		int32 value;
299 		if (message->FindInt32("be:value", &value) == B_OK)
300 			SetMode(value);
301 	} else
302 		_inherited::MessageReceived(message);
303 }
304 
305 
306 //	#pragma mark - PaneSwitch
307 
308 
309 PaneSwitch::PaneSwitch(BRect frame, const char *name, bool leftAligned,
310 		uint32 resizeMask, uint32 flags)
311 	:
312 	BControl(frame, name, "", 0, resizeMask, flags),
313 	fLeftAligned(leftAligned),
314 	fPressing(false),
315 	fLabelOn(NULL),
316 	fLabelOff(NULL)
317 {
318 }
319 
320 
321 PaneSwitch::PaneSwitch(const char *name, bool leftAligned, uint32 flags)
322 	:
323 	BControl(name, "", 0, flags),
324 	fLeftAligned(leftAligned),
325 	fPressing(false),
326 	fLabelOn(NULL),
327 	fLabelOff(NULL)
328 {
329 }
330 
331 
332 PaneSwitch::~PaneSwitch()
333 {
334 	free(fLabelOn);
335 	free(fLabelOff);
336 }
337 
338 
339 void
340 PaneSwitch::Draw(BRect)
341 {
342 	BRect bounds(Bounds());
343 
344 	// Draw the label, if any
345 	const char* label = fLabelOff;
346 	if (fLabelOn != NULL && Value() == B_CONTROL_ON)
347 		label = fLabelOn;
348 
349 	if (label != NULL) {
350 		BPoint point;
351 		float labelDist = sLatchSize + ceilf(sLatchSize / 2.0);
352 		if (fLeftAligned)
353 			point.x = labelDist;
354 		else
355 			point.x = bounds.right - labelDist - StringWidth(label);
356 
357 		font_height fontHeight;
358 		GetFontHeight(&fontHeight);
359 		point.y = (bounds.top + bounds.bottom
360 			- ceilf(fontHeight.ascent) - ceilf(fontHeight.descent)) / 2
361 			+ ceilf(fontHeight.ascent);
362 
363 		DrawString(label, point);
364 	}
365 
366 	// draw the latch
367 	if (fPressing)
368 		DrawInState(kPressed);
369 	else if (Value())
370 		DrawInState(kExpanded);
371 	else
372 		DrawInState(kCollapsed);
373 
374 	// ...and the focus indication
375 	if (!IsFocus() || !Window()->IsActive())
376 		return;
377 
378 	rgb_color markColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
379 
380 	BeginLineArray(2);
381 	AddLine(BPoint(bounds.left + 2, bounds.bottom - 1),
382 		BPoint(bounds.right - 2, bounds.bottom - 1), markColor);
383 	AddLine(BPoint(bounds.left + 2, bounds.bottom),
384 		BPoint(bounds.right - 2, bounds.bottom), kWhite);
385 	EndLineArray();
386 }
387 
388 
389 void
390 PaneSwitch::MouseDown(BPoint)
391 {
392 	if (!IsEnabled())
393 		return;
394 
395 	fPressing = true;
396 	MouseDownThread<PaneSwitch>::TrackMouse(this, &PaneSwitch::DoneTracking,
397 		&PaneSwitch::Track);
398 	Invalidate();
399 }
400 
401 
402 void
403 PaneSwitch::GetPreferredSize(float* _width, float* _height)
404 {
405 	BSize size = MinSize();
406 	if (_width)
407 		*_width = size.width;
408 	if (_height)
409 		*_height = size.height;
410 }
411 
412 
413 BSize
414 PaneSwitch::MinSize()
415 {
416 	BSize size;
417 	float onLabelWidth = StringWidth(fLabelOn);
418 	float offLabelWidth = StringWidth(fLabelOff);
419 	float labelWidth = max_c(onLabelWidth, offLabelWidth);
420 	size.width = sLatchSize;
421 	if (labelWidth > 0.0)
422 		size.width += ceilf(sLatchSize / 2.0) + labelWidth;
423 	font_height fontHeight;
424 	GetFontHeight(&fontHeight);
425 	size.height = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
426 	size.height = max_c(size.height, sLatchSize);
427 	return BLayoutUtils::ComposeSize(ExplicitMinSize(), size);
428 }
429 
430 
431 BSize
432 PaneSwitch::MaxSize()
433 {
434 	return BLayoutUtils::ComposeSize(ExplicitMaxSize(), MinSize());
435 }
436 
437 
438 BSize
439 PaneSwitch::PreferredSize()
440 {
441 	return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), MinSize());
442 }
443 
444 
445 void
446 PaneSwitch::SetLabels(const char* labelOn, const char* labelOff)
447 {
448 	free(fLabelOn);
449 	free(fLabelOff);
450 
451 	if (labelOn != NULL)
452 		fLabelOn = strdup(labelOn);
453 	else
454 		fLabelOn = NULL;
455 
456 	if (labelOff != NULL)
457 		fLabelOff = strdup(labelOff);
458 	else
459 		fLabelOff = NULL;
460 
461 	Invalidate();
462 	InvalidateLayout();
463 }
464 
465 
466 void
467 PaneSwitch::DoneTracking(BPoint point)
468 {
469 	BRect bounds(Bounds());
470 	bounds.InsetBy(-3, -3);
471 
472 	fPressing = false;
473 	Invalidate();
474 	if (bounds.Contains(point)) {
475 		SetValue(!Value());
476 		Invoke();
477 	}
478 }
479 
480 
481 void
482 PaneSwitch::Track(BPoint point, uint32)
483 {
484 	BRect bounds(Bounds());
485 	bounds.InsetBy(-3, -3);
486 
487 	bool newPressing = bounds.Contains(point);
488 	if (newPressing != fPressing) {
489 		fPressing = newPressing;
490 		Invalidate();
491 	}
492 }
493 
494 
495 void
496 PaneSwitch::DrawInState(PaneSwitch::State state)
497 {
498 	BRect rect(0, 0, 10, 10);
499 
500 	rgb_color outlineColor = {0, 0, 0, 255};
501 	rgb_color middleColor = state == kPressed ? kHighlightColor : kNormalColor;
502 
503 	SetDrawingMode(B_OP_COPY);
504 
505 	switch (state) {
506 		case kCollapsed:
507 			BeginLineArray(6);
508 
509 			if (fLeftAligned) {
510 				AddLine(BPoint(rect.left + 3, rect.top + 1),
511 					BPoint(rect.left + 3, rect.bottom - 1), outlineColor);
512 				AddLine(BPoint(rect.left + 3, rect.top + 1),
513 					BPoint(rect.left + 7, rect.top + 5), outlineColor);
514 				AddLine(BPoint(rect.left + 7, rect.top + 5),
515 					BPoint(rect.left + 3, rect.bottom - 1), outlineColor);
516 
517 				AddLine(BPoint(rect.left + 4, rect.top + 3),
518 					BPoint(rect.left + 4, rect.bottom - 3), middleColor);
519 				AddLine(BPoint(rect.left + 5, rect.top + 4),
520 					BPoint(rect.left + 5, rect.bottom - 4), middleColor);
521 				AddLine(BPoint(rect.left + 5, rect.top + 5),
522 					BPoint(rect.left + 6, rect.top + 5), middleColor);
523 			} else {
524 				AddLine(BPoint(rect.right - 3, rect.top + 1),
525 					BPoint(rect.right - 3, rect.bottom - 1), outlineColor);
526 				AddLine(BPoint(rect.right - 3, rect.top + 1),
527 					BPoint(rect.right - 7, rect.top + 5), outlineColor);
528 				AddLine(BPoint(rect.right - 7, rect.top + 5),
529 					BPoint(rect.right - 3, rect.bottom - 1), outlineColor);
530 
531 				AddLine(BPoint(rect.right - 4, rect.top + 3),
532 					BPoint(rect.right - 4, rect.bottom - 3), middleColor);
533 				AddLine(BPoint(rect.right - 5, rect.top + 4),
534 					BPoint(rect.right - 5, rect.bottom - 4), middleColor);
535 				AddLine(BPoint(rect.right - 5, rect.top + 5),
536 					BPoint(rect.right - 6, rect.top + 5), middleColor);
537 			}
538 			EndLineArray();
539 			break;
540 
541 		case kPressed:
542 			BeginLineArray(7);
543 			if (fLeftAligned) {
544 				AddLine(BPoint(rect.left + 1, rect.top + 7),
545 					BPoint(rect.left + 7, rect.top + 7), outlineColor);
546 				AddLine(BPoint(rect.left + 7, rect.top + 1),
547 					BPoint(rect.left + 7, rect.top + 7), outlineColor);
548 				AddLine(BPoint(rect.left + 1, rect.top + 7),
549 					BPoint(rect.left + 7, rect.top + 1), outlineColor);
550 
551 				AddLine(BPoint(rect.left + 3, rect.top + 6),
552 					BPoint(rect.left + 6, rect.top + 6), middleColor);
553 				AddLine(BPoint(rect.left + 4, rect.top + 5),
554 					BPoint(rect.left + 6, rect.top + 5), middleColor);
555 				AddLine(BPoint(rect.left + 5, rect.top + 4),
556 					BPoint(rect.left + 6, rect.top + 4), middleColor);
557 				AddLine(BPoint(rect.left + 6, rect.top + 3),
558 					BPoint(rect.left + 6, rect.top + 4), middleColor);
559 			} else {
560 				AddLine(BPoint(rect.right - 1, rect.top + 7),
561 					BPoint(rect.right - 7, rect.top + 7), outlineColor);
562 				AddLine(BPoint(rect.right - 7, rect.top + 1),
563 					BPoint(rect.right - 7, rect.top + 7), outlineColor);
564 				AddLine(BPoint(rect.right - 1, rect.top + 7),
565 					BPoint(rect.right - 7, rect.top + 1), outlineColor);
566 
567 				AddLine(BPoint(rect.right - 3, rect.top + 6),
568 					BPoint(rect.right - 6, rect.top + 6), middleColor);
569 				AddLine(BPoint(rect.right - 4, rect.top + 5),
570 					BPoint(rect.right - 6, rect.top + 5), middleColor);
571 				AddLine(BPoint(rect.right - 5, rect.top + 4),
572 					BPoint(rect.right - 6, rect.top + 4), middleColor);
573 				AddLine(BPoint(rect.right - 6, rect.top + 3),
574 					BPoint(rect.right - 6, rect.top + 4), middleColor);
575 			}
576 			EndLineArray();
577 			break;
578 
579 		case kExpanded:
580 			BeginLineArray(6);
581 			AddLine(BPoint(rect.left + 1, rect.top + 3),
582 				BPoint(rect.right - 1, rect.top + 3), outlineColor);
583 			AddLine(BPoint(rect.left + 1, rect.top + 3),
584 				BPoint(rect.left + 5, rect.top + 7), outlineColor);
585 			AddLine(BPoint(rect.left + 5, rect.top + 7),
586 				BPoint(rect.right - 1, rect.top + 3), outlineColor);
587 
588 			AddLine(BPoint(rect.left + 3, rect.top + 4),
589 				BPoint(rect.right - 3, rect.top + 4), middleColor);
590 			AddLine(BPoint(rect.left + 4, rect.top + 5),
591 				BPoint(rect.right - 4, rect.top + 5), middleColor);
592 			AddLine(BPoint(rect.left + 5, rect.top + 5),
593 				BPoint(rect.left + 5, rect.top + 6), middleColor);
594 			EndLineArray();
595 			break;
596 	}
597 }
598 
599