1/*
2 * Copyright 2011 Stephan A��mus <superstippi@gmx.de>
3 * All rights reserved. Distributed under the terms of the MIT license.
4 */
5#include "ToolBar.h"
6
7#include <Button.h>
8#include <ControlLook.h>
9#include <Message.h>
10#include <SeparatorView.h>
11#include <SpaceLayoutItem.h>
12
13
14namespace BPrivate {
15
16
17
18// Button to adopt backgrond color of toolbar
19class ToolBarButton : public BButton {
20public:
21			ToolBarButton(const char* name, const char* label,
22				BMessage* message);
23
24	void	AttachedToWindow();
25};
26
27
28ToolBarButton::ToolBarButton(const char* name, const char* label,
29				BMessage* message)
30	:
31	BButton(name, label, message)
32	{}
33
34
35void
36ToolBarButton::AttachedToWindow()
37{
38	BButton::AttachedToWindow();
39	SetLowUIColor(B_PANEL_BACKGROUND_COLOR);
40	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
41		// have to remove the darkening caused by BButton's drawing
42}
43
44
45//# pragma mark -
46
47
48class LockableButton: public ToolBarButton {
49public:
50			LockableButton(const char* name, const char* label,
51				BMessage* message);
52
53	void	MouseDown(BPoint point);
54};
55
56
57LockableButton::LockableButton(const char* name, const char* label,
58	BMessage* message)
59	:
60	ToolBarButton(name, label, message)
61{
62}
63
64
65void
66LockableButton::MouseDown(BPoint point)
67{
68	if ((modifiers() & B_SHIFT_KEY) != 0 || Value() == B_CONTROL_ON)
69		SetBehavior(B_TOGGLE_BEHAVIOR);
70	else
71		SetBehavior(B_BUTTON_BEHAVIOR);
72
73	Message()->SetInt32("behavior", Behavior());
74	ToolBarButton::MouseDown(point);
75}
76
77
78//#pragma mark  -
79
80
81BToolBar::BToolBar(BRect frame, orientation ont)
82	:
83	BGroupView(ont),
84	fOrientation(ont)
85{
86	_Init();
87
88	MoveTo(frame.LeftTop());
89	ResizeTo(frame.Width(), frame.Height());
90	SetResizingMode(B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP);
91}
92
93
94BToolBar::BToolBar(orientation ont)
95	:
96	BGroupView(ont),
97	fOrientation(ont)
98{
99	_Init();
100}
101
102
103BToolBar::~BToolBar()
104{
105}
106
107
108void
109BToolBar::Hide()
110{
111	BView::Hide();
112	// TODO: This could be fixed in BView instead. Looking from the
113	// BButtons, they are not hidden though, only their parent is...
114	_HideToolTips();
115}
116
117
118void
119BToolBar::AddAction(uint32 command, BHandler* target, const BBitmap* icon,
120	const char* toolTipText, const char* text, bool lockable)
121{
122	AddAction(new BMessage(command), target, icon, toolTipText, text, lockable);
123}
124
125
126void
127BToolBar::AddAction(BMessage* message, BHandler* target,
128	const BBitmap* icon, const char* toolTipText, const char* text,
129	bool lockable)
130{
131	ToolBarButton* button;
132	if (lockable)
133		button = new LockableButton(NULL, NULL, message);
134	else
135		button = new ToolBarButton(NULL, NULL, message);
136	button->SetIcon(icon);
137	button->SetFlat(true);
138	if (toolTipText != NULL)
139		button->SetToolTip(toolTipText);
140	if (text != NULL)
141		button->SetLabel(text);
142	AddView(button);
143	button->SetTarget(target);
144}
145
146
147void
148BToolBar::AddSeparator()
149{
150	orientation ont = (fOrientation == B_HORIZONTAL) ?
151		B_VERTICAL : B_HORIZONTAL;
152	AddView(new BSeparatorView(ont, B_PLAIN_BORDER));
153}
154
155
156void
157BToolBar::AddGlue()
158{
159	GroupLayout()->AddItem(BSpaceLayoutItem::CreateGlue());
160}
161
162
163void
164BToolBar::AddView(BView* view)
165{
166	GroupLayout()->AddView(view);
167}
168
169
170void
171BToolBar::SetActionEnabled(uint32 command, bool enabled)
172{
173	if (BButton* button = FindButton(command))
174		button->SetEnabled(enabled);
175}
176
177
178void
179BToolBar::SetActionPressed(uint32 command, bool pressed)
180{
181	if (BButton* button = FindButton(command))
182		button->SetValue(pressed);
183}
184
185
186void
187BToolBar::SetActionVisible(uint32 command, bool visible)
188{
189	BButton* button = FindButton(command);
190	if (button == NULL)
191		return;
192	for (int32 i = 0; BLayoutItem* item = GroupLayout()->ItemAt(i); i++) {
193		if (item->View() != button)
194			continue;
195		item->SetVisible(visible);
196		break;
197	}
198}
199
200
201BButton*
202BToolBar::FindButton(uint32 command) const
203{
204	for (int32 i = 0; BView* view = ChildAt(i); i++) {
205		BButton* button = dynamic_cast<BButton*>(view);
206		if (button == NULL)
207			continue;
208		BMessage* message = button->Message();
209		if (message == NULL)
210			continue;
211		if (message->what == command) {
212			return button;
213			// Assumes there is only one button with this message...
214			break;
215		}
216	}
217	return NULL;
218}
219
220
221// #pragma mark - Private methods
222
223void
224BToolBar::Pulse()
225{
226	// TODO: Perhaps this could/should be addressed in BView instead.
227	if (IsHidden())
228		_HideToolTips();
229}
230
231
232void
233BToolBar::FrameResized(float width, float height)
234{
235	// TODO: There seems to be a bug in app_server which does not
236	// correctly trigger invalidation of views which are shown, when
237	// the resulting dirty area is somehow already part of an update region.
238	Invalidate();
239}
240
241
242void
243BToolBar::_Init()
244{
245	float inset = ceilf(be_control_look->DefaultItemSpacing() / 2);
246	GroupLayout()->SetInsets(inset, 0, inset, 0);
247	GroupLayout()->SetSpacing(1);
248
249	SetFlags(Flags() | B_FRAME_EVENTS | B_PULSE_NEEDED);
250}
251
252
253void
254BToolBar::_HideToolTips() const
255{
256	for (int32 i = 0; BView* view = ChildAt(i); i++)
257		view->HideToolTip();
258}
259
260
261} // namespace BPrivate
262