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.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "TabView.h"
30
31#include <stdio.h>
32
33#include <Application.h>
34#include <Bitmap.h>
35#include <Button.h>
36#include <CardLayout.h>
37#include <ControlLook.h>
38#include <GroupView.h>
39#include <MenuBar.h>
40#include <SpaceLayoutItem.h>
41#include <Window.h>
42
43#include "TabContainerView.h"
44
45
46// #pragma mark - TabView
47
48
49TabView::TabView()
50	:
51	fContainerView(NULL),
52	fLayoutItem(new TabLayoutItem(this)),
53	fLabel()
54{
55}
56
57
58TabView::~TabView()
59{
60	// The layout item is deleted for us by the layout which contains it.
61	if (!fContainerView)
62		delete fLayoutItem;
63}
64
65
66BSize
67TabView::MinSize()
68{
69	BSize size(MaxSize());
70	size.width = 60.0f;
71	return size;
72}
73
74
75BSize
76TabView::PreferredSize()
77{
78	return MaxSize();
79}
80
81
82BSize
83TabView::MaxSize()
84{
85	float extra = be_control_look->DefaultLabelSpacing();
86	float labelWidth = 300.0f;
87	return BSize(labelWidth, _LabelHeight() + extra);
88}
89
90
91void
92TabView::Draw(BRect updateRect)
93{
94	BRect frame(fLayoutItem->Frame());
95	if (fIsFront) {
96	    // Extend the front tab outward left/right in order to merge
97	    // the frames of adjacent tabs.
98	    if (!fIsFirst)
99	    	frame.left--;
100	    if (!fIsLast)
101	    	frame.right++;
102
103	   	frame.bottom++;
104	}
105	DrawBackground(fContainerView, frame, updateRect, fIsFirst, fIsLast,
106		fIsFront);
107	if (fIsFront) {
108	    frame.top += 3.0f;
109	    if (!fIsFirst)
110	    	frame.left++;
111	    if (!fIsLast)
112	    	frame.right--;
113	} else
114		frame.top += 6.0f;
115	float spacing = be_control_look->DefaultLabelSpacing();
116	frame.InsetBy(spacing, spacing / 2);
117	DrawContents(fContainerView, frame, updateRect, fIsFirst, fIsLast,
118		fIsFront);
119}
120
121
122void
123TabView::DrawBackground(BView* owner, BRect frame, const BRect& updateRect,
124	bool isFirst, bool isLast, bool isFront)
125{
126	rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
127	uint32 borders = BControlLook::B_TOP_BORDER
128		| BControlLook::B_BOTTOM_BORDER;
129	if (isFirst)
130		borders |= BControlLook::B_LEFT_BORDER;
131	if (isLast)
132		borders |= BControlLook::B_RIGHT_BORDER;
133	if (isFront) {
134		be_control_look->DrawActiveTab(owner, frame, updateRect, base,
135			0, borders);
136	} else {
137		be_control_look->DrawInactiveTab(owner, frame, updateRect, base,
138			0, borders);
139	}
140}
141
142
143void
144TabView::DrawContents(BView* owner, BRect frame, const BRect& updateRect,
145	bool isFirst, bool isLast, bool isFront)
146{
147	rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
148	be_control_look->DrawLabel(owner, fLabel.String(), frame, updateRect,
149		base, 0, BAlignment(B_ALIGN_LEFT, B_ALIGN_MIDDLE));
150}
151
152
153void
154TabView::MouseDown(BPoint where, uint32 buttons)
155{
156	fContainerView->SelectTab(this);
157}
158
159
160void
161TabView::MouseUp(BPoint where)
162{
163}
164
165
166void
167TabView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
168{
169}
170
171
172void
173TabView::SetIsFront(bool isFront)
174{
175	Update(fIsFirst, fIsLast, isFront);
176}
177
178
179bool
180TabView::IsFront() const
181{
182	return fIsFront;
183}
184
185
186void
187TabView::SetIsLast(bool isLast)
188{
189	Update(fIsFirst, isLast, fIsFront);
190}
191
192
193void
194TabView::Update(bool isFirst, bool isLast, bool isFront)
195{
196	if (fIsFirst == isFirst && fIsLast == isLast && fIsFront == isFront)
197		return;
198	fIsFirst = isFirst;
199	fIsLast = isLast;
200	fIsFront = isFront;
201
202	fLayoutItem->InvalidateContainer();
203}
204
205
206void
207TabView::SetContainerView(TabContainerView* containerView)
208{
209	fContainerView = containerView;
210}
211
212
213TabContainerView*
214TabView::ContainerView() const
215{
216	return fContainerView;
217}
218
219
220BLayoutItem*
221TabView::LayoutItem() const
222{
223	return fLayoutItem;
224}
225
226
227void
228TabView::SetLabel(const char* label)
229{
230	if (fLabel == label)
231		return;
232	fLabel = label;
233	fLayoutItem->InvalidateLayout();
234}
235
236
237const BString&
238TabView::Label() const
239{
240	return fLabel;
241}
242
243
244BRect
245TabView::Frame() const
246{
247	return fLayoutItem->Frame();
248}
249
250
251float
252TabView::_LabelHeight() const
253{
254	font_height fontHeight;
255	fContainerView->GetFontHeight(&fontHeight);
256	return ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
257}
258
259
260// #pragma mark - TabLayoutItem
261
262
263TabLayoutItem::TabLayoutItem(TabView* parent)
264	:
265	fParent(parent),
266	fVisible(true)
267{
268}
269
270
271bool
272TabLayoutItem::IsVisible()
273{
274	return fVisible;
275}
276
277
278void
279TabLayoutItem::SetVisible(bool visible)
280{
281	if (fVisible == visible)
282		return;
283
284	fVisible = visible;
285
286	InvalidateContainer();
287	fParent->ContainerView()->InvalidateLayout();
288}
289
290
291BRect
292TabLayoutItem::Frame()
293{
294	return fFrame;
295}
296
297
298void
299TabLayoutItem::SetFrame(BRect frame)
300{
301	BRect dirty = fFrame;
302	fFrame = frame;
303	dirty = dirty | fFrame;
304	InvalidateContainer(dirty);
305}
306
307
308BView*
309TabLayoutItem::View()
310{
311	return NULL;
312}
313
314
315BSize
316TabLayoutItem::BaseMinSize()
317{
318	return fParent->MinSize();
319}
320
321
322BSize
323TabLayoutItem::BaseMaxSize()
324{
325	return fParent->MaxSize();
326}
327
328
329BSize
330TabLayoutItem::BasePreferredSize()
331{
332	return fParent->PreferredSize();
333}
334
335
336BAlignment
337TabLayoutItem::BaseAlignment()
338{
339	return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
340}
341
342
343TabView*
344TabLayoutItem::Parent() const
345{
346	return fParent;
347}
348
349
350void
351TabLayoutItem::InvalidateContainer()
352{
353	InvalidateContainer(Frame());
354}
355
356
357void
358TabLayoutItem::InvalidateContainer(BRect frame)
359{
360	// Invalidate more than necessary, to help the TabContainerView
361	// redraw the parts outside any tabs...
362	frame.bottom++;
363	frame.right++;
364	fParent->ContainerView()->Invalidate(frame);
365}
366