1fd7c0c2eSStephan Aßmus/*
2323ba9b7SRyan Leavengood * Copyright 2004-2011, Haiku, Inc. All Rights Reserved.
3fd7c0c2eSStephan Aßmus * Distributed under the terms of the MIT License.
4fd7c0c2eSStephan Aßmus *
5fd7c0c2eSStephan Aßmus * Authors:
600826781SKarsten Heimrich *		Mike Berg <mike@berg-net.us>
7fd7c0c2eSStephan Aßmus *		Julun <host.haiku@gmx.de>
8323ba9b7SRyan Leavengood *		Hamish Morrison <hamish@lavabit.com>
9fd7c0c2eSStephan Aßmus */
1026c008b7SPhil Greenway
1190433c43SOliver Tappe
1226c008b7SPhil Greenway#include "SectionEdit.h"
1326c008b7SPhil Greenway
14fd7c0c2eSStephan Aßmus#include <Bitmap.h>
1502b73236SAxel Dörfler#include <ControlLook.h>
16323ba9b7SRyan Leavengood#include <LayoutUtils.h>
17fd7c0c2eSStephan Aßmus#include <List.h>
18fd7c0c2eSStephan Aßmus#include <Window.h>
1926c008b7SPhil Greenway
2002b73236SAxel Dörfler#include "TimeMessages.h"
2102b73236SAxel Dörfler
2226c008b7SPhil Greenway
23fd7c0c2eSStephan Aßmusconst uint32 kArrowAreaWidth = 16;
2426c008b7SPhil Greenway
2526c008b7SPhil Greenway
26323ba9b7SRyan LeavengoodTSectionEdit::TSectionEdit(const char* name, uint32 sections)
2702b73236SAxel Dörfler	:
28323ba9b7SRyan Leavengood	BControl(name, NULL, NULL, B_WILL_DRAW | B_NAVIGABLE),
2902b73236SAxel Dörfler	fFocus(-1),
30420e9637SOliver Tappe	fSectionCount(sections),
31420e9637SOliver Tappe	fHoldValue(0)
3226c008b7SPhil Greenway{
3326c008b7SPhil Greenway}
3426c008b7SPhil Greenway
3526c008b7SPhil Greenway
3626c008b7SPhil GreenwayTSectionEdit::~TSectionEdit()
3726c008b7SPhil Greenway{
3826c008b7SPhil Greenway}
3926c008b7SPhil Greenway
4026c008b7SPhil Greenway
4126c008b7SPhil Greenwayvoid
4226c008b7SPhil GreenwayTSectionEdit::AttachedToWindow()
4326c008b7SPhil Greenway{
44f0650dc9Slooncraz	AdoptParentColors();
4526c008b7SPhil Greenway}
4626c008b7SPhil Greenway
4726c008b7SPhil Greenway
4826c008b7SPhil Greenwayvoid
4900826781SKarsten HeimrichTSectionEdit::Draw(BRect updateRect)
5026c008b7SPhil Greenway{
5102b73236SAxel Dörfler	DrawBorder(updateRect);
5202b73236SAxel Dörfler
5300826781SKarsten Heimrich	for (uint32 idx = 0; idx < fSectionCount; idx++) {
54323ba9b7SRyan Leavengood		DrawSection(idx, FrameForSection(idx),
55323ba9b7SRyan Leavengood			((uint32)fFocus == idx) && IsFocus());
5690433c43SOliver Tappe		if (idx < fSectionCount - 1)
57323ba9b7SRyan Leavengood			DrawSeparator(idx, FrameForSeparator(idx));
5826c008b7SPhil Greenway	}
5926c008b7SPhil Greenway}
6026c008b7SPhil Greenway
6126c008b7SPhil Greenway
6226c008b7SPhil Greenwayvoid
6326c008b7SPhil GreenwayTSectionEdit::MouseDown(BPoint where)
6426c008b7SPhil Greenway{
6526c008b7SPhil Greenway	MakeFocus(true);
6602b73236SAxel Dörfler
67fd7c0c2eSStephan Aßmus	if (fUpRect.Contains(where))
6826c008b7SPhil Greenway		DoUpPress();
69fd7c0c2eSStephan Aßmus	else if (fDownRect.Contains(where))
7026c008b7SPhil Greenway		DoDownPress();
71323ba9b7SRyan Leavengood	else if (fSectionCount > 0) {
72fd7c0c2eSStephan Aßmus		for (uint32 idx = 0; idx < fSectionCount; idx++) {
73323ba9b7SRyan Leavengood			if (FrameForSection(idx).Contains(where)) {
7426c008b7SPhil Greenway				SectionFocus(idx);
7526c008b7SPhil Greenway				return;
7626c008b7SPhil Greenway			}
7702b73236SAxel Dörfler		}
7826c008b7SPhil Greenway	}
7926c008b7SPhil Greenway}
8026c008b7SPhil Greenway
8126c008b7SPhil Greenway
82323ba9b7SRyan LeavengoodBSize
83323ba9b7SRyan LeavengoodTSectionEdit::MaxSize()
84323ba9b7SRyan Leavengood{
85323ba9b7SRyan Leavengood	return BLayoutUtils::ComposeSize(ExplicitMaxSize(),
86323ba9b7SRyan Leavengood		BSize(B_SIZE_UNLIMITED, PreferredHeight()));
87323ba9b7SRyan Leavengood}
88323ba9b7SRyan Leavengood
89323ba9b7SRyan Leavengood
90323ba9b7SRyan LeavengoodBSize
91323ba9b7SRyan LeavengoodTSectionEdit::MinSize()
92323ba9b7SRyan Leavengood{
93323ba9b7SRyan Leavengood	BSize minSize;
94323ba9b7SRyan Leavengood	minSize.height = PreferredHeight();
95323ba9b7SRyan Leavengood	minSize.width = (SeparatorWidth() + MinSectionWidth())
96323ba9b7SRyan Leavengood		* fSectionCount;
97323ba9b7SRyan Leavengood	return BLayoutUtils::ComposeSize(ExplicitMinSize(),
98323ba9b7SRyan Leavengood		minSize);
99323ba9b7SRyan Leavengood}
100323ba9b7SRyan Leavengood
101323ba9b7SRyan Leavengood
102323ba9b7SRyan LeavengoodBSize
103323ba9b7SRyan LeavengoodTSectionEdit::PreferredSize()
104323ba9b7SRyan Leavengood{
105323ba9b7SRyan Leavengood	return BLayoutUtils::ComposeSize(ExplicitPreferredSize(),
106323ba9b7SRyan Leavengood		MinSize());
107323ba9b7SRyan Leavengood}
108323ba9b7SRyan Leavengood
109323ba9b7SRyan Leavengood
110323ba9b7SRyan LeavengoodBRect
111323ba9b7SRyan LeavengoodTSectionEdit::FrameForSection(uint32 index)
112323ba9b7SRyan Leavengood{
113323ba9b7SRyan Leavengood	BRect area = SectionArea();
114323ba9b7SRyan Leavengood	float sepWidth = SeparatorWidth();
115323ba9b7SRyan Leavengood
116323ba9b7SRyan Leavengood	float width = (area.Width() -
117323ba9b7SRyan Leavengood		sepWidth * (fSectionCount - 1))
118323ba9b7SRyan Leavengood		/ fSectionCount;
119323ba9b7SRyan Leavengood	area.left += index * (width + sepWidth);
120323ba9b7SRyan Leavengood	area.right = area.left + width;
121323ba9b7SRyan Leavengood
122323ba9b7SRyan Leavengood	return area;
123323ba9b7SRyan Leavengood}
124323ba9b7SRyan Leavengood
125323ba9b7SRyan Leavengood
126323ba9b7SRyan LeavengoodBRect
127323ba9b7SRyan LeavengoodTSectionEdit::FrameForSeparator(uint32 index)
128323ba9b7SRyan Leavengood{
129323ba9b7SRyan Leavengood	BRect area = SectionArea();
130323ba9b7SRyan Leavengood	float sepWidth = SeparatorWidth();
131323ba9b7SRyan Leavengood
132323ba9b7SRyan Leavengood	float width = (area.Width() -
133323ba9b7SRyan Leavengood		sepWidth * (fSectionCount - 1))
134323ba9b7SRyan Leavengood		/ fSectionCount;
135323ba9b7SRyan Leavengood	area.left += (index + 1) * width + index * sepWidth;
136323ba9b7SRyan Leavengood	area.right = area.left + sepWidth;
137323ba9b7SRyan Leavengood
138323ba9b7SRyan Leavengood	return area;
139323ba9b7SRyan Leavengood}
140323ba9b7SRyan Leavengood
141323ba9b7SRyan Leavengood
14200826781SKarsten Heimrichvoid
14300826781SKarsten HeimrichTSectionEdit::MakeFocus(bool focused)
14400826781SKarsten Heimrich{
14500826781SKarsten Heimrich	if (focused == IsFocus())
14600826781SKarsten Heimrich		return;
14700826781SKarsten Heimrich
14800826781SKarsten Heimrich	BControl::MakeFocus(focused);
14902b73236SAxel Dörfler
15000826781SKarsten Heimrich	if (fFocus == -1)
15100826781SKarsten Heimrich		SectionFocus(0);
15200826781SKarsten Heimrich	else
15300826781SKarsten Heimrich		SectionFocus(fFocus);
15400826781SKarsten Heimrich}
15500826781SKarsten Heimrich
15600826781SKarsten Heimrich
15726c008b7SPhil Greenwayvoid
1586d6408d6SOliver TappeTSectionEdit::KeyDown(const char* bytes, int32 numbytes)
15926c008b7SPhil Greenway{
160fd7c0c2eSStephan Aßmus	if (fFocus == -1)
16126c008b7SPhil Greenway		SectionFocus(0);
16202b73236SAxel Dörfler
16326c008b7SPhil Greenway	switch (bytes[0]) {
16426c008b7SPhil Greenway		case B_LEFT_ARROW:
165fd7c0c2eSStephan Aßmus			fFocus -= 1;
166fd7c0c2eSStephan Aßmus			if (fFocus < 0)
16790433c43SOliver Tappe				fFocus = fSectionCount - 1;
168fd7c0c2eSStephan Aßmus			SectionFocus(fFocus);
16902b73236SAxel Dörfler			break;
17002b73236SAxel Dörfler
17126c008b7SPhil Greenway		case B_RIGHT_ARROW:
172fd7c0c2eSStephan Aßmus			fFocus += 1;
173fd7c0c2eSStephan Aßmus			if ((uint32)fFocus >= fSectionCount)
174fd7c0c2eSStephan Aßmus				fFocus = 0;
175fd7c0c2eSStephan Aßmus			SectionFocus(fFocus);
17602b73236SAxel Dörfler			break;
17702b73236SAxel Dörfler
17826c008b7SPhil Greenway		case B_UP_ARROW:
17926c008b7SPhil Greenway			DoUpPress();
18002b73236SAxel Dörfler			break;
18102b73236SAxel Dörfler
18226c008b7SPhil Greenway		case B_DOWN_ARROW:
18326c008b7SPhil Greenway			DoDownPress();
18402b73236SAxel Dörfler			break;
18502b73236SAxel Dörfler
18626c008b7SPhil Greenway		default:
18726c008b7SPhil Greenway			BControl::KeyDown(bytes, numbytes);
18802b73236SAxel Dörfler			break;
18926c008b7SPhil Greenway	}
19026c008b7SPhil Greenway	Draw(Bounds());
19126c008b7SPhil Greenway}
19226c008b7SPhil Greenway
19326c008b7SPhil Greenway
19426c008b7SPhil Greenwayvoid
19526c008b7SPhil GreenwayTSectionEdit::DispatchMessage()
19626c008b7SPhil Greenway{
19700826781SKarsten Heimrich	BMessage message(H_USER_CHANGE);
19800826781SKarsten Heimrich	BuildDispatch(&message);
19900826781SKarsten Heimrich	Window()->PostMessage(&message);
20026c008b7SPhil Greenway}
20126c008b7SPhil Greenway
20226c008b7SPhil Greenway
20326c008b7SPhil Greenwayuint32
20426c008b7SPhil GreenwayTSectionEdit::CountSections() const
20526c008b7SPhil Greenway{
206323ba9b7SRyan Leavengood	return fSectionCount;
20726c008b7SPhil Greenway}
20826c008b7SPhil Greenway
20926c008b7SPhil Greenway
21026c008b7SPhil Greenwayint32
21126c008b7SPhil GreenwayTSectionEdit::FocusIndex() const
21226c008b7SPhil Greenway{
213fd7c0c2eSStephan Aßmus	return fFocus;
21426c008b7SPhil Greenway}
21526c008b7SPhil Greenway
21626c008b7SPhil Greenway
217323ba9b7SRyan LeavengoodBRect
218323ba9b7SRyan LeavengoodTSectionEdit::SectionArea() const
21926c008b7SPhil Greenway{
220323ba9b7SRyan Leavengood	BRect sectionArea = Bounds().InsetByCopy(2, 2);
221323ba9b7SRyan Leavengood	sectionArea.right -= kArrowAreaWidth;
222323ba9b7SRyan Leavengood	return sectionArea;
22326c008b7SPhil Greenway}
22426c008b7SPhil Greenway
22526c008b7SPhil Greenway
22626c008b7SPhil Greenwayvoid
22702b73236SAxel DörflerTSectionEdit::DrawBorder(const BRect& updateRect)
22826c008b7SPhil Greenway{
22902b73236SAxel Dörfler	BRect bounds(Bounds());
230420e9637SOliver Tappe	bool showFocus = (IsFocus() && Window() && Window()->IsActive());
231fd7c0c2eSStephan Aßmus
23202b73236SAxel Dörfler	be_control_look->DrawBorder(this, bounds, updateRect, ViewColor(),
233420e9637SOliver Tappe		B_FANCY_BORDER, showFocus ? BControlLook::B_FOCUSED : 0);
23426c008b7SPhil Greenway
23502b73236SAxel Dörfler	// draw up/down control
23626c008b7SPhil Greenway
23702b73236SAxel Dörfler	bounds.left = bounds.right - kArrowAreaWidth;
23802b73236SAxel Dörfler	bounds.right = Bounds().right - 2;
23902b73236SAxel Dörfler	fUpRect.Set(bounds.left + 3, bounds.top + 2, bounds.right,
24002b73236SAxel Dörfler		bounds.bottom / 2.0);
24102b73236SAxel Dörfler	fDownRect = fUpRect.OffsetByCopy(0, fUpRect.Height() + 2);
24202b73236SAxel Dörfler
243323ba9b7SRyan Leavengood	BPoint middle(floorf(fUpRect.left + fUpRect.Width() / 2),
244323ba9b7SRyan Leavengood		fUpRect.top + 1);
24502b73236SAxel Dörfler	BPoint left(fUpRect.left + 3, fUpRect.bottom - 1);
24602b73236SAxel Dörfler	BPoint right(left.x + 2 * (middle.x - left.x), fUpRect.bottom - 1);
24702b73236SAxel Dörfler
24802b73236SAxel Dörfler	SetPenSize(2);
249323ba9b7SRyan Leavengood	SetLowColor(ViewColor());
25002b73236SAxel Dörfler
25102b73236SAxel Dörfler	if (updateRect.Intersects(fUpRect)) {
25202b73236SAxel Dörfler		FillRect(fUpRect, B_SOLID_LOW);
25302b73236SAxel Dörfler		BeginLineArray(2);
25402b73236SAxel Dörfler			AddLine(left, middle, HighColor());
25502b73236SAxel Dörfler			AddLine(middle, right, HighColor());
25602b73236SAxel Dörfler		EndLineArray();
25702b73236SAxel Dörfler	}
25802b73236SAxel Dörfler	if (updateRect.Intersects(fDownRect)) {
25902b73236SAxel Dörfler		middle.y = fDownRect.bottom - 1;
26002b73236SAxel Dörfler		left.y = right.y = fDownRect.top + 1;
26102b73236SAxel Dörfler
26202b73236SAxel Dörfler		FillRect(fDownRect, B_SOLID_LOW);
26302b73236SAxel Dörfler		BeginLineArray(2);
26402b73236SAxel Dörfler			AddLine(left, middle, HighColor());
26502b73236SAxel Dörfler			AddLine(middle, right, HighColor());
26602b73236SAxel Dörfler		EndLineArray();
26726c008b7SPhil Greenway	}
26826c008b7SPhil Greenway
26902b73236SAxel Dörfler	SetPenSize(1);
27026c008b7SPhil Greenway}
271