1/*
2 * Copyright 2003-2009, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Jonas Sundstr��m, jonas@kirilla.com
7 */
8
9
10#include "ZipOMaticActivity.h"
11
12#include <ControlLook.h>
13
14#include <stdio.h>
15
16
17Activity::Activity(const char* name)
18	:
19	BView(name, B_WILL_DRAW | B_FRAME_EVENTS),
20	fIsRunning(false),
21	fBitmap(NULL),
22	fSpinSpeed(0.15),
23	fColors(NULL),
24	fNumColors(0),
25	fScrollOffset(0.0),
26	fStripeWidth(0.0),
27	fNumStripes(0)
28{
29	_InactiveColors();
30	SetExplicitMinSize(BSize(17, 17));
31	SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 17));
32};
33
34
35Activity::~Activity()
36{
37	delete fBitmap;
38	delete[] fColors;
39}
40
41
42void
43Activity::AllAttached()
44{
45	_CreateBitmap();
46	FrameResized(Bounds().Width(), Bounds().Height());
47}
48
49
50void
51Activity::Start()
52{
53	fIsRunning = true;
54	_ActiveColors();
55	Window()->SetPulseRate(100000);
56	SetFlags(Flags() | B_PULSE_NEEDED);
57	Invalidate();
58}
59
60
61void
62Activity::Pause()
63{
64	Window()->SetPulseRate(500000);
65	SetFlags(Flags() & (~B_PULSE_NEEDED));
66	Invalidate();
67}
68
69
70void
71Activity::Stop()
72{
73	fIsRunning = false;
74	_InactiveColors();
75	Window()->SetPulseRate(500000);
76	SetFlags(Flags() & (~B_PULSE_NEEDED));
77	Invalidate();
78}
79
80
81bool
82Activity::IsRunning()
83{
84	return fIsRunning;
85}
86
87
88void
89Activity::Pulse()
90{
91	fScrollOffset += fStripeWidth / (1.0f / fSpinSpeed);
92	if (fScrollOffset >= fStripeWidth * fNumColors) {
93		// Cycle completed, jump back to where we started
94		fScrollOffset = 0;
95	}
96	Invalidate();
97}
98
99
100void
101Activity::SetColors(const rgb_color* colors, uint32 numColors)
102{
103	delete[] fColors;
104	rgb_color* colorsCopy = new rgb_color[numColors];
105	for (uint32 i = 0; i < numColors; i++)
106		colorsCopy[i] = colors[i];
107
108	fColors = colorsCopy;
109	fNumColors = numColors;
110}
111
112
113void
114Activity::Draw(BRect rect)
115{
116	BRect viewRect = Bounds();
117	BRect bitmapRect = fBitmap->Bounds();
118
119	if (bitmapRect != viewRect) {
120		delete fBitmap;
121		_CreateBitmap();
122	}
123
124	_DrawOnBitmap(IsRunning());
125	SetDrawingMode(B_OP_COPY);
126	DrawBitmap(fBitmap);
127}
128
129
130void
131Activity::_DrawOnBitmap(bool running)
132{
133	if (fBitmap->Lock()) {
134		BRect bounds = fBitmap->Bounds();
135
136		fBitmapView->SetDrawingMode(B_OP_COPY);
137
138		// Draw color stripes
139		float position = -fStripeWidth * (fNumColors + 0.5) + fScrollOffset;
140		// Starting position: beginning of the second color cycle
141		// The + 0.5 is so we start out without a partially visible stripe
142		// on the left side (makes it simpler to loop)
143		BRect innerFrame = bounds;
144		innerFrame.InsetBy(-2, -2);
145
146		be_control_look->DrawStatusBar(fBitmapView, innerFrame, innerFrame,
147			ui_color(B_PANEL_BACKGROUND_COLOR),
148			running ? ui_color(B_STATUS_BAR_COLOR)
149				: ui_color(B_PANEL_BACKGROUND_COLOR),
150			bounds.Width());
151		fBitmapView->SetDrawingMode(B_OP_ALPHA);
152		uint32 colorIndex = 0;
153		for (uint32 i = 0; i < fNumStripes; i++) {
154			fBitmapView->SetHighColor(fColors[colorIndex]);
155			colorIndex++;
156			if (colorIndex >= fNumColors)
157				colorIndex = 0;
158
159			BRect stripeFrame = fStripe.Frame();
160			fStripe.MapTo(stripeFrame,
161			stripeFrame.OffsetToCopy(position, 0.0));
162			fBitmapView->FillPolygon(&fStripe);
163
164			position += fStripeWidth;
165		}
166
167		fBitmapView->SetDrawingMode(B_OP_COPY);
168		// Draw box around it
169		be_control_look->DrawTextControlBorder(fBitmapView, bounds, bounds,
170			ui_color(B_PANEL_BACKGROUND_COLOR), B_PLAIN_BORDER);
171
172		fBitmapView->Sync();
173		fBitmap->Unlock();
174	}
175}
176
177
178void
179Activity::_CreateBitmap(void)
180{
181	BRect rect = Bounds();
182	fBitmap = new BBitmap(rect, B_RGBA32, true);
183	fBitmapView = new BView(Bounds(), "buffer", B_FOLLOW_NONE, 0);
184	fBitmap->AddChild(fBitmapView);
185}
186
187
188void
189Activity::FrameResized(float width, float height)
190{
191	delete fBitmap;
192	_CreateBitmap();
193	// Choose stripe width so that at least 2 full stripes fit into the view,
194	// but with a minimum of 5px. Larger views get wider stripes, but they
195	// grow slower than the view and are capped to a maximum of 200px.
196	fStripeWidth = (width / (fIsRunning ? 4 : 6)) + 5;
197	if (fStripeWidth > 200)
198		fStripeWidth = 200;
199
200	BPoint stripePoints[4];
201	stripePoints[0].Set(fStripeWidth * 0.5, 0.0); // top left
202	stripePoints[1].Set(fStripeWidth * 1.5, 0.0); // top right
203	stripePoints[2].Set(fStripeWidth, height);    // bottom right
204	stripePoints[3].Set(0.0, height);             // bottom left
205
206	fStripe = BPolygon(stripePoints, 4);
207
208	fNumStripes = (int32)ceilf((width) / fStripeWidth) + 1 + fNumColors;
209		// Number of color stripes drawn in total for the barber pole, the
210		// user-visible part is a "window" onto the complete pole. We need
211		// as many stripes as are visible, an extra one on the right side
212		// (will be partially visible, that's the + 1); and then a whole color
213		// cycle of strips extra which we scroll into until we loop.
214		//
215		// Example with 3 colors and a visible area of 2*fStripeWidth (which means
216		// that 2 will be fully visible, and a third one partially):
217		//               ........
218		//   X___________v______v___
219		//  / 1 / 2 / 3 / 1 / 2 / 3 /
220		//  `````````````````````````
221		// Pole is scrolled to the right into the visible region, which is marked
222		// between the two 'v'. Once the left edge of the visible area reaches
223		// point X, we can jump back to the initial region position.
224	Invalidate();
225}
226
227void
228Activity::_ActiveColors()
229{
230	// Default colors, chosen from system color scheme
231	rgb_color defaultColors[2];
232	rgb_color otherColor = tint_color(ui_color(B_STATUS_BAR_COLOR), 1.3);
233	otherColor.alpha = 50;
234	defaultColors[0] = otherColor;
235	defaultColors[1] = B_TRANSPARENT_COLOR;
236	SetColors(defaultColors, 2);
237
238}
239
240
241void
242Activity::_InactiveColors()
243{
244	// Default colors, chosen from system color scheme
245	rgb_color defaultColors[2];
246	rgb_color otherColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 1.7);
247	otherColor.alpha = 50;
248	defaultColors[0] = otherColor;
249	defaultColors[1] = B_TRANSPARENT_COLOR;
250	SetColors(defaultColors, 2);
251}
252