1/*
2 * Copyright (C) 2010 Rene Gollent <rene@gollent.com>
3 * Copyright (C) 2010 Stephan A��mus <superstippi@gmx.de>
4 *
5 * All rights reserved. Distributed under the terms of the MIT License.
6 */
7
8#include "TabView.h"
9
10#include <stdio.h>
11
12#include <Application.h>
13#include <Bitmap.h>
14#include <Button.h>
15#include <CardLayout.h>
16#include <ControlLook.h>
17#include <GroupView.h>
18#include <SpaceLayoutItem.h>
19#include <TabView.h>
20#include <Window.h>
21
22#include "TabContainerView.h"
23
24
25// #pragma mark - TabView
26
27
28TabView::TabView()
29	:
30	fContainerView(NULL),
31	fLayoutItem(new TabLayoutItem(this)),
32	fLabel()
33{
34}
35
36
37TabView::~TabView()
38{
39	// The layout item is deleted for us by the layout which contains it.
40	if (fContainerView == NULL)
41		delete fLayoutItem;
42}
43
44
45BSize
46TabView::MinSize()
47{
48	BSize size(MaxSize());
49	size.width = 60.0f;
50	return size;
51}
52
53
54BSize
55TabView::PreferredSize()
56{
57	return MaxSize();
58}
59
60
61BSize
62TabView::MaxSize()
63{
64	float extra = be_control_look->DefaultLabelSpacing();
65	float labelWidth = 300.0f;
66	return BSize(labelWidth, _LabelHeight() + extra);
67}
68
69
70void
71TabView::Draw(BRect updateRect)
72{
73	BRect frame(fLayoutItem->Frame());
74	frame.right++;
75	frame.bottom++;
76
77	int32 index = fContainerView->IndexOf(this);
78
79	// make room for tail of last tab
80	bool isLast = index == fContainerView->LastTabIndex();
81	if (isLast)
82		frame.right -= 2;
83
84	DrawBackground(fContainerView, frame, updateRect);
85
86	bool isFront = index == fContainerView->SelectedTabIndex();
87	if (isFront)
88		frame.top += 3.0f;
89	else
90		frame.top += 6.0f;
91
92	float spacing = be_control_look->DefaultLabelSpacing();
93	frame.InsetBy(spacing, spacing / 2);
94	DrawContents(fContainerView, frame, updateRect);
95}
96
97
98void
99TabView::DrawBackground(BView* owner, BRect frame, const BRect& updateRect)
100{
101	rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
102	uint32 flags = 0;
103	uint32 borders = BControlLook::B_TOP_BORDER
104		| BControlLook::B_BOTTOM_BORDER;
105
106	int32 index = fContainerView->IndexOf(this);
107	int32 selected = fContainerView->SelectedTabIndex();
108	int32 first = fContainerView->FirstTabIndex();
109	int32 last = fContainerView->LastTabIndex();
110
111	if (index == selected) {
112		be_control_look->DrawActiveTab(owner, frame, updateRect, base, flags,
113			borders, BControlLook::B_TOP_BORDER, index, selected, first, last);
114	} else {
115		be_control_look->DrawInactiveTab(owner, frame, updateRect, base, flags,
116			borders, BControlLook::B_TOP_BORDER, index, selected, first, last);
117	}
118}
119
120
121void
122TabView::DrawContents(BView* owner, BRect frame, const BRect& updateRect)
123{
124	rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
125	be_control_look->DrawLabel(owner, fLabel.String(), frame, updateRect,
126		base, 0, BAlignment(B_ALIGN_LEFT, B_ALIGN_MIDDLE));
127}
128
129
130void
131TabView::MouseDown(BPoint where, uint32 buttons)
132{
133	fContainerView->SelectTab(this);
134}
135
136
137void
138TabView::MouseUp(BPoint where)
139{
140}
141
142
143void
144TabView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
145{
146}
147
148
149void
150TabView::Update()
151{
152	fLayoutItem->InvalidateContainer();
153}
154
155
156void
157TabView::SetContainerView(TabContainerView* containerView)
158{
159	fContainerView = containerView;
160}
161
162
163TabContainerView*
164TabView::ContainerView() const
165{
166	return fContainerView;
167}
168
169
170BLayoutItem*
171TabView::LayoutItem() const
172{
173	return fLayoutItem;
174}
175
176
177void
178TabView::SetLabel(const char* label)
179{
180	if (fLabel == label)
181		return;
182
183	fLabel = label;
184	fLayoutItem->InvalidateLayout();
185}
186
187
188const BString&
189TabView::Label() const
190{
191	return fLabel;
192}
193
194
195BRect
196TabView::Frame() const
197{
198	return fLayoutItem->Frame();
199}
200
201
202float
203TabView::_LabelHeight() const
204{
205	font_height fontHeight;
206	fContainerView->GetFontHeight(&fontHeight);
207	return ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
208}
209
210
211// #pragma mark - TabLayoutItem
212
213
214TabLayoutItem::TabLayoutItem(TabView* parent)
215	:
216	fParent(parent),
217	fVisible(true)
218{
219}
220
221
222bool
223TabLayoutItem::IsVisible()
224{
225	return fVisible;
226}
227
228
229void
230TabLayoutItem::SetVisible(bool visible)
231{
232	if (fVisible == visible)
233		return;
234
235	fVisible = visible;
236
237	InvalidateContainer();
238	fParent->ContainerView()->InvalidateLayout();
239}
240
241
242BRect
243TabLayoutItem::Frame()
244{
245	return fFrame;
246}
247
248
249void
250TabLayoutItem::SetFrame(BRect frame)
251{
252	BRect dirty = fFrame;
253	fFrame = frame;
254	dirty = dirty | fFrame;
255	InvalidateContainer(dirty);
256}
257
258
259BView*
260TabLayoutItem::View()
261{
262	return NULL;
263}
264
265
266BSize
267TabLayoutItem::BaseMinSize()
268{
269	return fParent->MinSize();
270}
271
272
273BSize
274TabLayoutItem::BaseMaxSize()
275{
276	return fParent->MaxSize();
277}
278
279
280BSize
281TabLayoutItem::BasePreferredSize()
282{
283	return fParent->PreferredSize();
284}
285
286
287BAlignment
288TabLayoutItem::BaseAlignment()
289{
290	return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
291}
292
293
294TabView*
295TabLayoutItem::Parent() const
296{
297	return fParent;
298}
299
300
301void
302TabLayoutItem::InvalidateContainer()
303{
304	InvalidateContainer(Frame());
305}
306
307
308void
309TabLayoutItem::InvalidateContainer(BRect frame)
310{
311	// Invalidate more than necessary, to help the TabContainerView
312	// redraw the parts outside any tabs... need 2px
313	frame.bottom += 2;
314	frame.right += 2;
315	fParent->ContainerView()->Invalidate(frame);
316}
317