⛏️ index : haiku.git

/*
 * Copyright 2003-2009, Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Jonas SundstrΓΆm, jonas@kirilla.com
 */


#include "ZipOMaticActivity.h"

#include <ControlLook.h>

#include <stdio.h>


Activity::Activity(const char* name)
	:
	BView(name, B_WILL_DRAW | B_FRAME_EVENTS),
	fIsRunning(false),
	fBitmap(NULL),
	fSpinSpeed(0.15),
	fColors(NULL),
	fNumColors(0),
	fScrollOffset(0.0),
	fStripeWidth(0.0),
	fNumStripes(0)
{
	_InactiveColors();
	SetExplicitMinSize(BSize(17, 17));
	SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 17));
};


Activity::~Activity()
{
	delete fBitmap;
	delete[] fColors;
}


void 
Activity::AllAttached()
{
	_CreateBitmap();
	FrameResized(Bounds().Width(), Bounds().Height());
}


void 
Activity::Start()
{
	fIsRunning = true;
	_ActiveColors();
	Window()->SetPulseRate(100000);
	SetFlags(Flags() | B_PULSE_NEEDED);
	Invalidate();
}


void 
Activity::Pause()
{
	Window()->SetPulseRate(500000);
	SetFlags(Flags() & (~B_PULSE_NEEDED));
	Invalidate();
}


void 
Activity::Stop()
{
	fIsRunning = false;
	_InactiveColors();
	Window()->SetPulseRate(500000);
	SetFlags(Flags() & (~B_PULSE_NEEDED));
	Invalidate();
}


bool 
Activity::IsRunning()	
{
	return fIsRunning;
}


void 
Activity::Pulse()
{
	fScrollOffset += fStripeWidth / (1.0f / fSpinSpeed);
	if (fScrollOffset >= fStripeWidth * fNumColors) {
		// Cycle completed, jump back to where we started
		fScrollOffset = 0;
	}
	Invalidate();
}


void
Activity::SetColors(const rgb_color* colors, uint32 numColors)
{
	delete[] fColors;
	rgb_color* colorsCopy = new rgb_color[numColors];
	for (uint32 i = 0; i < numColors; i++)
		colorsCopy[i] = colors[i];

	fColors = colorsCopy;
	fNumColors = numColors;
}


void 
Activity::Draw(BRect rect)
{
	BRect viewRect = Bounds();
	BRect bitmapRect = fBitmap->Bounds();

	if (bitmapRect != viewRect) {
		delete fBitmap;
		_CreateBitmap();
	}

	_DrawOnBitmap(IsRunning());
	SetDrawingMode(B_OP_COPY);
	DrawBitmap(fBitmap);
}


void
Activity::_DrawOnBitmap(bool running)
{
	if (fBitmap->Lock()) {
		BRect bounds = fBitmap->Bounds();

		fBitmapView->SetDrawingMode(B_OP_COPY);
	
		// Draw color stripes
		float position = -fStripeWidth * (fNumColors + 0.5) + fScrollOffset;
		// Starting position: beginning of the second color cycle
		// The + 0.5 is so we start out without a partially visible stripe
		// on the left side (makes it simpler to loop)
		BRect innerFrame = bounds;
		innerFrame.InsetBy(-2, -2);

		be_control_look->DrawStatusBar(fBitmapView, innerFrame, innerFrame,
			ui_color(B_PANEL_BACKGROUND_COLOR),
			running ? ui_color(B_STATUS_BAR_COLOR)
				: ui_color(B_PANEL_BACKGROUND_COLOR),
			bounds.Width());
		fBitmapView->SetDrawingMode(B_OP_ALPHA);
		uint32 colorIndex = 0;
		for (uint32 i = 0; i < fNumStripes; i++) {
			fBitmapView->SetHighColor(fColors[colorIndex]);
			colorIndex++;
			if (colorIndex >= fNumColors)
				colorIndex = 0;

			BRect stripeFrame = fStripe.Frame();
			fStripe.MapTo(stripeFrame,
			stripeFrame.OffsetToCopy(position, 0.0));
			fBitmapView->FillPolygon(&fStripe);

			position += fStripeWidth;
		}

		fBitmapView->SetDrawingMode(B_OP_COPY);
		// Draw box around it
		be_control_look->DrawTextControlBorder(fBitmapView, bounds, bounds,
			ui_color(B_PANEL_BACKGROUND_COLOR), B_PLAIN_BORDER);
		
		fBitmapView->Sync();
		fBitmap->Unlock();
	}
}


void
Activity::_CreateBitmap(void)
{
	BRect rect = Bounds();
	fBitmap = new BBitmap(rect, B_RGBA32, true);
	fBitmapView = new BView(Bounds(), "buffer", B_FOLLOW_NONE, 0);
	fBitmap->AddChild(fBitmapView);
}


void
Activity::FrameResized(float width, float height)
{
	delete fBitmap;
	_CreateBitmap();
	// Choose stripe width so that at least 2 full stripes fit into the view,
	// but with a minimum of 5px. Larger views get wider stripes, but they
	// grow slower than the view and are capped to a maximum of 200px.
	fStripeWidth = (width / (fIsRunning ? 4 : 6)) + 5;
	if (fStripeWidth > 200)
		fStripeWidth = 200;

	BPoint stripePoints[4];
	stripePoints[0].Set(fStripeWidth * 0.5, 0.0); // top left
	stripePoints[1].Set(fStripeWidth * 1.5, 0.0); // top right
	stripePoints[2].Set(fStripeWidth, height);    // bottom right
	stripePoints[3].Set(0.0, height);             // bottom left

	fStripe = BPolygon(stripePoints, 4);

	fNumStripes = (int32)ceilf((width) / fStripeWidth) + 1 + fNumColors;
		// Number of color stripes drawn in total for the barber pole, the
		// user-visible part is a "window" onto the complete pole. We need
		// as many stripes as are visible, an extra one on the right side
		// (will be partially visible, that's the + 1); and then a whole color
		// cycle of strips extra which we scroll into until we loop.
		//
		// Example with 3 colors and a visible area of 2*fStripeWidth (which means
		// that 2 will be fully visible, and a third one partially):
		//               ........
		//   X___________v______v___
		//  / 1 / 2 / 3 / 1 / 2 / 3 /
		//  `````````````````````````
		// Pole is scrolled to the right into the visible region, which is marked
		// between the two 'v'. Once the left edge of the visible area reaches
		// point X, we can jump back to the initial region position.
	Invalidate();
}

void
Activity::_ActiveColors()
{
	// Default colors, chosen from system color scheme
	rgb_color defaultColors[2];
	rgb_color otherColor = tint_color(ui_color(B_STATUS_BAR_COLOR), 1.3);
	otherColor.alpha = 50;
	defaultColors[0] = otherColor;
	defaultColors[1] = B_TRANSPARENT_COLOR;
	SetColors(defaultColors, 2);

}


void
Activity::_InactiveColors()
{
	// Default colors, chosen from system color scheme
	rgb_color defaultColors[2];
	rgb_color otherColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 1.7);
	otherColor.alpha = 50;
	defaultColors[0] = otherColor;
	defaultColors[1] = B_TRANSPARENT_COLOR;
	SetColors(defaultColors, 2);
}