xref: /haiku/src/apps/soundrecorder/TransportButton.cpp (revision 3ee964070b768aa3482c08fa82aa73e70cd175d1)
157e2f323SJérôme Duval /*
257e2f323SJérôme Duval  * Copyright 2005, Jérôme Duval. All rights reserved.
357e2f323SJérôme Duval  * Distributed under the terms of the MIT License.
457e2f323SJérôme Duval  *
5*3ee96407SJérôme Duval  * Inspired by SoundCapture from Be newsletter (Media Kit Basics: Consumers
6*3ee96407SJérôme Duval  * and Producers)
757e2f323SJérôme Duval  */
857e2f323SJérôme Duval 
957e2f323SJérôme Duval #include <Bitmap.h>
1057e2f323SJérôme Duval #include <Debug.h>
1157e2f323SJérôme Duval #include <MessageFilter.h>
1257e2f323SJérôme Duval #include <Window.h>
1357e2f323SJérôme Duval 
1457e2f323SJérôme Duval #include <map>
1557e2f323SJérôme Duval 
1657e2f323SJérôme Duval #include "TransportButton.h"
1757e2f323SJérôme Duval #include "DrawingTidbits.h"
1857e2f323SJérôme Duval 
19758b1d0eSIngo Weinhold using std::map;
20758b1d0eSIngo Weinhold 
2157e2f323SJérôme Duval class BitmapStash {
2257e2f323SJérôme Duval // Bitmap stash is a simple class to hold all the lazily-allocated
2357e2f323SJérôme Duval // bitmaps that the TransportButton needs when rendering itself.
2457e2f323SJérôme Duval // signature is a combination of the different enabled, pressed, playing, etc.
2557e2f323SJérôme Duval // flavors of a bitmap. If the stash does not have a particular bitmap,
2657e2f323SJérôme Duval // it turns around to ask the button to create one and stores it for next time.
2757e2f323SJérôme Duval public:
2857e2f323SJérôme Duval 	BitmapStash(TransportButton *);
2957e2f323SJérôme Duval 	~BitmapStash();
3057e2f323SJérôme Duval 	BBitmap *GetBitmap(uint32 signature);
3157e2f323SJérôme Duval 
3257e2f323SJérôme Duval private:
3357e2f323SJérôme Duval 	TransportButton *owner;
3457e2f323SJérôme Duval 	map<uint32, BBitmap *> stash;
3557e2f323SJérôme Duval };
3657e2f323SJérôme Duval 
3757e2f323SJérôme Duval 
BitmapStash(TransportButton * owner)3857e2f323SJérôme Duval BitmapStash::BitmapStash(TransportButton *owner)
3957e2f323SJérôme Duval 	:	owner(owner)
4057e2f323SJérôme Duval {
4157e2f323SJérôme Duval }
4257e2f323SJérôme Duval 
4357e2f323SJérôme Duval 
4457e2f323SJérôme Duval BBitmap *
GetBitmap(uint32 signature)4557e2f323SJérôme Duval BitmapStash::GetBitmap(uint32 signature)
4657e2f323SJérôme Duval {
4757e2f323SJérôme Duval 	if (stash.find(signature) == stash.end()) {
4857e2f323SJérôme Duval 		BBitmap *newBits = owner->MakeBitmap(signature);
4957e2f323SJérôme Duval 		ASSERT(newBits);
5057e2f323SJérôme Duval 		stash[signature] = newBits;
5157e2f323SJérôme Duval 	}
5257e2f323SJérôme Duval 
5357e2f323SJérôme Duval 	return stash[signature];
5457e2f323SJérôme Duval }
5557e2f323SJérôme Duval 
5657e2f323SJérôme Duval 
~BitmapStash()5757e2f323SJérôme Duval BitmapStash::~BitmapStash()
5857e2f323SJérôme Duval {
5957e2f323SJérôme Duval 	// delete all the bitmaps
60*3ee96407SJérôme Duval 	for (map<uint32, BBitmap *>::iterator i = stash.begin();
61*3ee96407SJérôme Duval 		i != stash.end(); i++)
6257e2f323SJérôme Duval 		delete (*i).second;
6357e2f323SJérôme Duval }
6457e2f323SJérôme Duval 
6557e2f323SJérôme Duval 
6657e2f323SJérôme Duval class PeriodicMessageSender {
6757e2f323SJérôme Duval 	// used to send a specified message repeatedly when holding down a button
6857e2f323SJérôme Duval public:
6957e2f323SJérôme Duval 	static PeriodicMessageSender *Launch(BMessenger target,
7057e2f323SJérôme Duval 		const BMessage *message, bigtime_t period);
7157e2f323SJérôme Duval 	void Quit();
7257e2f323SJérôme Duval 
7357e2f323SJérôme Duval private:
7457e2f323SJérôme Duval 	PeriodicMessageSender(BMessenger target, const BMessage *message,
7557e2f323SJérôme Duval 		bigtime_t period);
~PeriodicMessageSender()7657e2f323SJérôme Duval 	~PeriodicMessageSender() {}
7757e2f323SJérôme Duval 		// use quit
7857e2f323SJérôme Duval 
7957e2f323SJérôme Duval 	static status_t TrackBinder(void *);
8057e2f323SJérôme Duval 	void Run();
8157e2f323SJérôme Duval 
8257e2f323SJérôme Duval 	BMessenger target;
8357e2f323SJérôme Duval 	BMessage message;
8457e2f323SJérôme Duval 
8557e2f323SJérôme Duval 	bigtime_t period;
8657e2f323SJérôme Duval 
8757e2f323SJérôme Duval 	bool requestToQuit;
8857e2f323SJérôme Duval };
8957e2f323SJérôme Duval 
9057e2f323SJérôme Duval 
PeriodicMessageSender(BMessenger target,const BMessage * message,bigtime_t period)9157e2f323SJérôme Duval PeriodicMessageSender::PeriodicMessageSender(BMessenger target,
9257e2f323SJérôme Duval 	const BMessage *message, bigtime_t period)
9357e2f323SJérôme Duval 	:	target(target),
9457e2f323SJérôme Duval 		message(*message),
9557e2f323SJérôme Duval 		period(period),
9657e2f323SJérôme Duval 		requestToQuit(false)
9757e2f323SJérôme Duval {
9857e2f323SJérôme Duval }
9957e2f323SJérôme Duval 
10057e2f323SJérôme Duval 
10157e2f323SJérôme Duval PeriodicMessageSender *
Launch(BMessenger target,const BMessage * message,bigtime_t period)10257e2f323SJérôme Duval PeriodicMessageSender::Launch(BMessenger target, const BMessage *message,
10357e2f323SJérôme Duval 	bigtime_t period)
10457e2f323SJérôme Duval {
105*3ee96407SJérôme Duval 	PeriodicMessageSender *result = new PeriodicMessageSender(target,
106*3ee96407SJérôme Duval 		message, period);
10757e2f323SJérôme Duval 	thread_id thread = spawn_thread(&PeriodicMessageSender::TrackBinder,
10857e2f323SJérôme Duval 		"ButtonRepeatingThread", B_NORMAL_PRIORITY, result);
10957e2f323SJérôme Duval 
11057e2f323SJérôme Duval 	if (thread <= 0 || resume_thread(thread) != B_OK) {
11157e2f323SJérôme Duval 		// didn't start, don't leak self
11257e2f323SJérôme Duval 		delete result;
11357e2f323SJérôme Duval 		result = 0;
11457e2f323SJérôme Duval 	}
11557e2f323SJérôme Duval 
11657e2f323SJérôme Duval 	return result;
11757e2f323SJérôme Duval }
11857e2f323SJérôme Duval 
11957e2f323SJérôme Duval 
12057e2f323SJérôme Duval void
Quit()12157e2f323SJérôme Duval PeriodicMessageSender::Quit()
12257e2f323SJérôme Duval {
12357e2f323SJérôme Duval 	requestToQuit = true;
12457e2f323SJérôme Duval }
12557e2f323SJérôme Duval 
12657e2f323SJérôme Duval 
12757e2f323SJérôme Duval status_t
TrackBinder(void * castToThis)12857e2f323SJérôme Duval PeriodicMessageSender::TrackBinder(void *castToThis)
12957e2f323SJérôme Duval {
13057e2f323SJérôme Duval 	((PeriodicMessageSender *)castToThis)->Run();
13157e2f323SJérôme Duval 	return 0;
13257e2f323SJérôme Duval }
13357e2f323SJérôme Duval 
13457e2f323SJérôme Duval 
13557e2f323SJérôme Duval void
Run()13657e2f323SJérôme Duval PeriodicMessageSender::Run()
13757e2f323SJérôme Duval {
13857e2f323SJérôme Duval 	for (;;) {
13957e2f323SJérôme Duval 		snooze(period);
14057e2f323SJérôme Duval 		if (requestToQuit)
14157e2f323SJérôme Duval 			break;
14257e2f323SJérôme Duval 		target.SendMessage(&message);
14357e2f323SJérôme Duval 	}
14457e2f323SJérôme Duval 	delete this;
14557e2f323SJérôme Duval }
14657e2f323SJérôme Duval 
14757e2f323SJérôme Duval 
14857e2f323SJérôme Duval class SkipButtonKeypressFilter : public BMessageFilter {
14957e2f323SJérôme Duval public:
15057e2f323SJérôme Duval 	SkipButtonKeypressFilter(uint32 shortcutKey, uint32 shortcutModifier,
15157e2f323SJérôme Duval 		TransportButton *target);
15257e2f323SJérôme Duval 
15357e2f323SJérôme Duval protected:
15457e2f323SJérôme Duval 	filter_result Filter(BMessage *message, BHandler **handler);
15557e2f323SJérôme Duval 
15657e2f323SJérôme Duval private:
15757e2f323SJérôme Duval 	uint32 shortcutKey;
15857e2f323SJérôme Duval 	uint32 shortcutModifier;
15957e2f323SJérôme Duval 	TransportButton *target;
16057e2f323SJérôme Duval };
16157e2f323SJérôme Duval 
16257e2f323SJérôme Duval 
SkipButtonKeypressFilter(uint32 shortcutKey,uint32 shortcutModifier,TransportButton * target)16357e2f323SJérôme Duval SkipButtonKeypressFilter::SkipButtonKeypressFilter(uint32 shortcutKey,
16457e2f323SJérôme Duval 	uint32 shortcutModifier, TransportButton *target)
16557e2f323SJérôme Duval 	:	BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
16657e2f323SJérôme Duval 		shortcutKey(shortcutKey),
16757e2f323SJérôme Duval 		shortcutModifier(shortcutModifier),
16857e2f323SJérôme Duval 		target(target)
16957e2f323SJérôme Duval {
17057e2f323SJérôme Duval }
17157e2f323SJérôme Duval 
17257e2f323SJérôme Duval 
17357e2f323SJérôme Duval filter_result
Filter(BMessage * message,BHandler ** handler)17457e2f323SJérôme Duval SkipButtonKeypressFilter::Filter(BMessage *message, BHandler **handler)
17557e2f323SJérôme Duval {
17657e2f323SJérôme Duval 	if (target->IsEnabled()
17757e2f323SJérôme Duval 		&& (message->what == B_KEY_DOWN || message->what == B_KEY_UP)) {
17857e2f323SJérôme Duval 		uint32 modifiers;
17957e2f323SJérôme Duval 		uint32 rawKeyChar = 0;
18057e2f323SJérôme Duval 		uint8 byte = 0;
18157e2f323SJérôme Duval 		int32 key = 0;
18257e2f323SJérôme Duval 
18357e2f323SJérôme Duval 		if (message->FindInt32("modifiers", (int32 *)&modifiers) != B_OK
18457e2f323SJérôme Duval 			|| message->FindInt32("raw_char", (int32 *)&rawKeyChar) != B_OK
18557e2f323SJérôme Duval 			|| message->FindInt8("byte", (int8 *)&byte) != B_OK
18657e2f323SJérôme Duval 			|| message->FindInt32("key", &key) != B_OK)
18757e2f323SJérôme Duval 			return B_DISPATCH_MESSAGE;
18857e2f323SJérôme Duval 
18957e2f323SJérôme Duval 		modifiers &= B_SHIFT_KEY | B_COMMAND_KEY | B_CONTROL_KEY
19057e2f323SJérôme Duval 			| B_OPTION_KEY | B_MENU_KEY;
19157e2f323SJérôme Duval 			// strip caps lock, etc.
19257e2f323SJérôme Duval 
19357e2f323SJérôme Duval 		if (modifiers == shortcutModifier && rawKeyChar == shortcutKey) {
19457e2f323SJérôme Duval 			if (message->what == B_KEY_DOWN)
19557e2f323SJérôme Duval 				target->ShortcutKeyDown();
19657e2f323SJérôme Duval 			else
19757e2f323SJérôme Duval 				target->ShortcutKeyUp();
19857e2f323SJérôme Duval 
19957e2f323SJérôme Duval 			return B_SKIP_MESSAGE;
20057e2f323SJérôme Duval 		}
20157e2f323SJérôme Duval 	}
20257e2f323SJérôme Duval 
20357e2f323SJérôme Duval 	// let others deal with this
20457e2f323SJérôme Duval 	return B_DISPATCH_MESSAGE;
20557e2f323SJérôme Duval }
20657e2f323SJérôme Duval 
20757e2f323SJérôme Duval 
TransportButton(BRect frame,const char * name,const unsigned char * normalBits,const unsigned char * pressedBits,const unsigned char * disabledBits,BMessage * invokeMessage,BMessage * startPressingMessage,BMessage * pressingMessage,BMessage * donePressingMessage,bigtime_t period,uint32 key,uint32 modifiers,uint32 resizeFlags)20857e2f323SJérôme Duval TransportButton::TransportButton(BRect frame, const char *name,
20957e2f323SJérôme Duval 	const unsigned char *normalBits,
21057e2f323SJérôme Duval 	const unsigned char *pressedBits,
21157e2f323SJérôme Duval 	const unsigned char *disabledBits,
21257e2f323SJérôme Duval 	BMessage *invokeMessage, BMessage *startPressingMessage,
21357e2f323SJérôme Duval 	BMessage *pressingMessage, BMessage *donePressingMessage, bigtime_t period,
21457e2f323SJérôme Duval 	uint32 key, uint32 modifiers, uint32 resizeFlags)
215*3ee96407SJérôme Duval 	:	BControl(frame, name, "", invokeMessage, resizeFlags,
216*3ee96407SJérôme Duval 			B_WILL_DRAW | B_NAVIGABLE),
21757e2f323SJérôme Duval 		bitmaps(new BitmapStash(this)),
21857e2f323SJérôme Duval 		normalBits(normalBits),
21957e2f323SJérôme Duval 		pressedBits(pressedBits),
22057e2f323SJérôme Duval 		disabledBits(disabledBits),
22157e2f323SJérôme Duval 		startPressingMessage(startPressingMessage),
22257e2f323SJérôme Duval 		pressingMessage(pressingMessage),
22357e2f323SJérôme Duval 		donePressingMessage(donePressingMessage),
22457e2f323SJérôme Duval 		pressingPeriod(period),
22557e2f323SJérôme Duval 		mouseDown(false),
22657e2f323SJérôme Duval 		keyDown(false),
22757e2f323SJérôme Duval 		messageSender(0),
22857e2f323SJérôme Duval 		keyPressFilter(0)
22957e2f323SJérôme Duval {
23057e2f323SJérôme Duval 	if (key)
23157e2f323SJérôme Duval 		keyPressFilter = new SkipButtonKeypressFilter(key, modifiers, this);
23257e2f323SJérôme Duval }
23357e2f323SJérôme Duval 
23457e2f323SJérôme Duval 
23557e2f323SJérôme Duval void
AttachedToWindow()23657e2f323SJérôme Duval TransportButton::AttachedToWindow()
23757e2f323SJérôme Duval {
23857e2f323SJérôme Duval 	_inherited::AttachedToWindow();
23957e2f323SJérôme Duval 	if (keyPressFilter)
24057e2f323SJérôme Duval 		Window()->AddCommonFilter(keyPressFilter);
24157e2f323SJérôme Duval 
24257e2f323SJérôme Duval 	// transparent to reduce flicker
24357e2f323SJérôme Duval 	SetViewColor(B_TRANSPARENT_COLOR);
24457e2f323SJérôme Duval }
24557e2f323SJérôme Duval 
24657e2f323SJérôme Duval 
24757e2f323SJérôme Duval void
DetachedFromWindow()24857e2f323SJérôme Duval TransportButton::DetachedFromWindow()
24957e2f323SJérôme Duval {
25057e2f323SJérôme Duval 	if (keyPressFilter) {
25157e2f323SJérôme Duval 		Window()->RemoveCommonFilter(keyPressFilter);
25257e2f323SJérôme Duval 		delete keyPressFilter;
25357e2f323SJérôme Duval 	}
25457e2f323SJérôme Duval 	_inherited::DetachedFromWindow();
25557e2f323SJérôme Duval }
25657e2f323SJérôme Duval 
25757e2f323SJérôme Duval 
~TransportButton()25857e2f323SJérôme Duval TransportButton::~TransportButton()
25957e2f323SJérôme Duval {
26057e2f323SJérôme Duval 	delete startPressingMessage;
26157e2f323SJérôme Duval 	delete pressingMessage;
26257e2f323SJérôme Duval 	delete donePressingMessage;
26357e2f323SJérôme Duval 	delete bitmaps;
26457e2f323SJérôme Duval }
26557e2f323SJérôme Duval 
26657e2f323SJérôme Duval 
26757e2f323SJérôme Duval void
WindowActivated(bool state)26857e2f323SJérôme Duval TransportButton::WindowActivated(bool state)
26957e2f323SJérôme Duval {
27057e2f323SJérôme Duval 	if (!state)
27157e2f323SJérôme Duval 		ShortcutKeyUp();
27257e2f323SJérôme Duval 
27357e2f323SJérôme Duval 	_inherited::WindowActivated(state);
27457e2f323SJérôme Duval }
27557e2f323SJérôme Duval 
27657e2f323SJérôme Duval 
27757e2f323SJérôme Duval void
SetEnabled(bool on)27857e2f323SJérôme Duval TransportButton::SetEnabled(bool on)
27957e2f323SJérôme Duval {
28057e2f323SJérôme Duval 	_inherited::SetEnabled(on);
28157e2f323SJérôme Duval 	if (!on)
28257e2f323SJérôme Duval 		ShortcutKeyUp();
28357e2f323SJérôme Duval }
28457e2f323SJérôme Duval 
28557e2f323SJérôme Duval 
28657e2f323SJérôme Duval const unsigned char *
BitsForMask(uint32 mask) const28757e2f323SJérôme Duval TransportButton::BitsForMask(uint32 mask) const
28857e2f323SJérôme Duval {
28957e2f323SJérôme Duval 	switch (mask) {
29057e2f323SJérôme Duval 		case 0:
29157e2f323SJérôme Duval 			return normalBits;
29257e2f323SJérôme Duval 		case kDisabledMask:
29357e2f323SJérôme Duval 			return disabledBits;
29457e2f323SJérôme Duval 		case kPressedMask:
29557e2f323SJérôme Duval 			return pressedBits;
29657e2f323SJérôme Duval 		default:
29757e2f323SJérôme Duval 			break;
29857e2f323SJérôme Duval 	}
29957e2f323SJérôme Duval 	TRESPASS();
30057e2f323SJérôme Duval 	return 0;
30157e2f323SJérôme Duval }
30257e2f323SJérôme Duval 
30357e2f323SJérôme Duval 
30457e2f323SJérôme Duval BBitmap *
MakeBitmap(uint32 mask)30557e2f323SJérôme Duval TransportButton::MakeBitmap(uint32 mask)
30657e2f323SJérôme Duval {
307c228b168SJérôme Duval 	BBitmap *result = new BBitmap(Bounds(), B_CMAP8);
308*3ee96407SJérôme Duval 	result->SetBits(BitsForMask(mask), (Bounds().Width() + 1)
309*3ee96407SJérôme Duval 		* (Bounds().Height() + 1), 0, B_CMAP8);
31057e2f323SJérôme Duval 
31157e2f323SJérôme Duval 	ReplaceTransparentColor(result, Parent()->ViewColor());
31257e2f323SJérôme Duval 
31357e2f323SJérôme Duval 	return result;
31457e2f323SJérôme Duval }
31557e2f323SJérôme Duval 
31657e2f323SJérôme Duval 
31757e2f323SJérôme Duval uint32
ModeMask() const31857e2f323SJérôme Duval TransportButton::ModeMask() const
31957e2f323SJérôme Duval {
32057e2f323SJérôme Duval 	return (IsEnabled() ? 0 : kDisabledMask)
32157e2f323SJérôme Duval 		| (Value() ? kPressedMask : 0);
32257e2f323SJérôme Duval }
32357e2f323SJérôme Duval 
32457e2f323SJérôme Duval 
32557e2f323SJérôme Duval void
Draw(BRect)32657e2f323SJérôme Duval TransportButton::Draw(BRect)
32757e2f323SJérôme Duval {
32857e2f323SJérôme Duval 	DrawBitmapAsync(bitmaps->GetBitmap(ModeMask()));
32957e2f323SJérôme Duval }
33057e2f323SJérôme Duval 
33157e2f323SJérôme Duval 
33257e2f323SJérôme Duval void
StartPressing()33357e2f323SJérôme Duval TransportButton::StartPressing()
33457e2f323SJérôme Duval {
33557e2f323SJérôme Duval 	SetValue(1);
33657e2f323SJérôme Duval 	if (startPressingMessage)
33757e2f323SJérôme Duval 		Invoke(startPressingMessage);
33857e2f323SJérôme Duval 
33957e2f323SJérôme Duval 	if (pressingMessage) {
34057e2f323SJérôme Duval 		ASSERT(pressingMessage);
34157e2f323SJérôme Duval 		messageSender = PeriodicMessageSender::Launch(Messenger(),
34257e2f323SJérôme Duval 			pressingMessage, pressingPeriod);
34357e2f323SJérôme Duval 	}
34457e2f323SJérôme Duval }
34557e2f323SJérôme Duval 
34657e2f323SJérôme Duval 
34757e2f323SJérôme Duval void
MouseCancelPressing()34857e2f323SJérôme Duval TransportButton::MouseCancelPressing()
34957e2f323SJérôme Duval {
35057e2f323SJérôme Duval 	if (!mouseDown || keyDown)
35157e2f323SJérôme Duval 		return;
35257e2f323SJérôme Duval 
35357e2f323SJérôme Duval 	mouseDown = false;
35457e2f323SJérôme Duval 
35557e2f323SJérôme Duval 	if (pressingMessage) {
35657e2f323SJérôme Duval 		ASSERT(messageSender);
35757e2f323SJérôme Duval 		PeriodicMessageSender *sender = messageSender;
35857e2f323SJérôme Duval 		messageSender = 0;
35957e2f323SJérôme Duval 		sender->Quit();
36057e2f323SJérôme Duval 	}
36157e2f323SJérôme Duval 
36257e2f323SJérôme Duval 	if (donePressingMessage)
36357e2f323SJérôme Duval 		Invoke(donePressingMessage);
36457e2f323SJérôme Duval 	SetValue(0);
36557e2f323SJérôme Duval }
36657e2f323SJérôme Duval 
36757e2f323SJérôme Duval 
36857e2f323SJérôme Duval void
DonePressing()36957e2f323SJérôme Duval TransportButton::DonePressing()
37057e2f323SJérôme Duval {
37157e2f323SJérôme Duval 	if (pressingMessage) {
37257e2f323SJérôme Duval 		ASSERT(messageSender);
37357e2f323SJérôme Duval 		PeriodicMessageSender *sender = messageSender;
37457e2f323SJérôme Duval 		messageSender = 0;
37557e2f323SJérôme Duval 		sender->Quit();
37657e2f323SJérôme Duval 	}
37757e2f323SJérôme Duval 
37857e2f323SJérôme Duval 	Invoke();
37957e2f323SJérôme Duval 	SetValue(0);
38057e2f323SJérôme Duval }
38157e2f323SJérôme Duval 
38257e2f323SJérôme Duval 
38357e2f323SJérôme Duval void
MouseStartPressing()38457e2f323SJérôme Duval TransportButton::MouseStartPressing()
38557e2f323SJérôme Duval {
38657e2f323SJérôme Duval 	if (mouseDown)
38757e2f323SJérôme Duval 		return;
38857e2f323SJérôme Duval 
38957e2f323SJérôme Duval 	mouseDown = true;
39057e2f323SJérôme Duval 	if (!keyDown)
39157e2f323SJérôme Duval 		StartPressing();
39257e2f323SJérôme Duval }
39357e2f323SJérôme Duval 
39457e2f323SJérôme Duval 
39557e2f323SJérôme Duval void
MouseDonePressing()39657e2f323SJérôme Duval TransportButton::MouseDonePressing()
39757e2f323SJérôme Duval {
39857e2f323SJérôme Duval 	if (!mouseDown)
39957e2f323SJérôme Duval 		return;
40057e2f323SJérôme Duval 
40157e2f323SJérôme Duval 	mouseDown = false;
40257e2f323SJérôme Duval 	if (!keyDown)
40357e2f323SJérôme Duval 		DonePressing();
40457e2f323SJérôme Duval }
40557e2f323SJérôme Duval 
40657e2f323SJérôme Duval 
40757e2f323SJérôme Duval void
ShortcutKeyDown()40857e2f323SJérôme Duval TransportButton::ShortcutKeyDown()
40957e2f323SJérôme Duval {
41057e2f323SJérôme Duval 	if (!IsEnabled())
41157e2f323SJérôme Duval 		return;
41257e2f323SJérôme Duval 
41357e2f323SJérôme Duval 	if (keyDown)
41457e2f323SJérôme Duval 		return;
41557e2f323SJérôme Duval 
41657e2f323SJérôme Duval 	keyDown = true;
41757e2f323SJérôme Duval 	if (!mouseDown)
41857e2f323SJérôme Duval 		StartPressing();
41957e2f323SJérôme Duval }
42057e2f323SJérôme Duval 
42157e2f323SJérôme Duval 
42257e2f323SJérôme Duval void
ShortcutKeyUp()42357e2f323SJérôme Duval TransportButton::ShortcutKeyUp()
42457e2f323SJérôme Duval {
42557e2f323SJérôme Duval 	if (!keyDown)
42657e2f323SJérôme Duval 		return;
42757e2f323SJérôme Duval 
42857e2f323SJérôme Duval 	keyDown = false;
42957e2f323SJérôme Duval 	if (!mouseDown)
43057e2f323SJérôme Duval 		DonePressing();
43157e2f323SJérôme Duval }
43257e2f323SJérôme Duval 
43357e2f323SJérôme Duval 
43457e2f323SJérôme Duval void
MouseDown(BPoint)43557e2f323SJérôme Duval TransportButton::MouseDown(BPoint)
43657e2f323SJérôme Duval {
43757e2f323SJérôme Duval 	if (!IsEnabled())
43857e2f323SJérôme Duval 		return;
43957e2f323SJérôme Duval 
44057e2f323SJérôme Duval 	ASSERT(Window()->Flags() & B_ASYNCHRONOUS_CONTROLS);
44157e2f323SJérôme Duval 	SetTracking(true);
44257e2f323SJérôme Duval 	SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
44357e2f323SJérôme Duval 	MouseStartPressing();
44457e2f323SJérôme Duval }
44557e2f323SJérôme Duval 
44657e2f323SJérôme Duval void
MouseMoved(BPoint point,uint32 code,const BMessage *)44757e2f323SJérôme Duval TransportButton::MouseMoved(BPoint point, uint32 code, const BMessage *)
44857e2f323SJérôme Duval {
44957e2f323SJérôme Duval 	if (IsTracking() && Bounds().Contains(point) != Value()) {
45057e2f323SJérôme Duval 		if (!Value())
45157e2f323SJérôme Duval 			MouseStartPressing();
45257e2f323SJérôme Duval 		else
45357e2f323SJérôme Duval 			MouseCancelPressing();
45457e2f323SJérôme Duval 	}
45557e2f323SJérôme Duval }
45657e2f323SJérôme Duval 
45757e2f323SJérôme Duval void
MouseUp(BPoint point)45857e2f323SJérôme Duval TransportButton::MouseUp(BPoint point)
45957e2f323SJérôme Duval {
46057e2f323SJérôme Duval 	if (IsTracking()) {
46157e2f323SJérôme Duval 		if (Bounds().Contains(point))
46257e2f323SJérôme Duval 			MouseDonePressing();
46357e2f323SJérôme Duval 		else
46457e2f323SJérôme Duval 			MouseCancelPressing();
46557e2f323SJérôme Duval 		SetTracking(false);
46657e2f323SJérôme Duval 	}
46757e2f323SJérôme Duval }
46857e2f323SJérôme Duval 
46957e2f323SJérôme Duval void
SetStartPressingMessage(BMessage * message)47057e2f323SJérôme Duval TransportButton::SetStartPressingMessage(BMessage *message)
47157e2f323SJérôme Duval {
47257e2f323SJérôme Duval 	delete startPressingMessage;
47357e2f323SJérôme Duval 	startPressingMessage = message;
47457e2f323SJérôme Duval }
47557e2f323SJérôme Duval 
47657e2f323SJérôme Duval void
SetPressingMessage(BMessage * message)47757e2f323SJérôme Duval TransportButton::SetPressingMessage(BMessage *message)
47857e2f323SJérôme Duval {
47957e2f323SJérôme Duval 	delete pressingMessage;
48057e2f323SJérôme Duval 	pressingMessage = message;
48157e2f323SJérôme Duval }
48257e2f323SJérôme Duval 
48357e2f323SJérôme Duval void
SetDonePressingMessage(BMessage * message)48457e2f323SJérôme Duval TransportButton::SetDonePressingMessage(BMessage *message)
48557e2f323SJérôme Duval {
48657e2f323SJérôme Duval 	delete donePressingMessage;
48757e2f323SJérôme Duval 	donePressingMessage = message;
48857e2f323SJérôme Duval }
48957e2f323SJérôme Duval 
49057e2f323SJérôme Duval void
SetPressingPeriod(bigtime_t newTime)49157e2f323SJérôme Duval TransportButton::SetPressingPeriod(bigtime_t newTime)
49257e2f323SJérôme Duval {
49357e2f323SJérôme Duval 	pressingPeriod = newTime;
49457e2f323SJérôme Duval }
49557e2f323SJérôme Duval 
49657e2f323SJérôme Duval 
PlayPauseButton(BRect frame,const char * name,BMessage * invokeMessage,BMessage * blinkMessage,uint32 key,uint32 modifiers,uint32 resizeFlags)49757e2f323SJérôme Duval PlayPauseButton::PlayPauseButton(BRect frame, const char *name,
49857e2f323SJérôme Duval 	BMessage *invokeMessage, BMessage *blinkMessage,
49957e2f323SJérôme Duval 	uint32 key, uint32 modifiers, uint32 resizeFlags)
500*3ee96407SJérôme Duval 	:	TransportButton(frame, name, kPlayButtonBitmapBits,
501*3ee96407SJérôme Duval 			kPressedPlayButtonBitmapBits,
50257e2f323SJérôme Duval 			kDisabledPlayButtonBitmapBits, invokeMessage, NULL,
50357e2f323SJérôme Duval 			NULL, NULL, 0, key, modifiers, resizeFlags),
50457e2f323SJérôme Duval 		fState(PlayPauseButton::kStopped),
50557e2f323SJérôme Duval 		fLastModeMask(0),
50657e2f323SJérôme Duval 		fRunner(NULL),
50757e2f323SJérôme Duval 		fBlinkMessage(blinkMessage)
50857e2f323SJérôme Duval {
50957e2f323SJérôme Duval }
51057e2f323SJérôme Duval 
51157e2f323SJérôme Duval void
SetStopped()51257e2f323SJérôme Duval PlayPauseButton::SetStopped()
51357e2f323SJérôme Duval {
51457e2f323SJérôme Duval 	if (fState == kStopped || fState == kAboutToPlay)
51557e2f323SJérôme Duval 		return;
51657e2f323SJérôme Duval 
51757e2f323SJérôme Duval 	fState = kStopped;
51857e2f323SJérôme Duval 	delete fRunner;
51957e2f323SJérôme Duval 	fRunner = NULL;
52057e2f323SJérôme Duval 	Invalidate();
52157e2f323SJérôme Duval }
52257e2f323SJérôme Duval 
52357e2f323SJérôme Duval void
SetPlaying()52457e2f323SJérôme Duval PlayPauseButton::SetPlaying()
52557e2f323SJérôme Duval {
52657e2f323SJérôme Duval 	if (fState == kAboutToPause)
52757e2f323SJérôme Duval 		return;
52857e2f323SJérôme Duval 
52957e2f323SJérôme Duval 	// in playing state blink the LED on and off
53057e2f323SJérôme Duval 	if (fState == kPlayingLedOn)
53157e2f323SJérôme Duval 		fState = kPlayingLedOff;
53257e2f323SJérôme Duval 	else
53357e2f323SJérôme Duval 		fState = kPlayingLedOn;
53457e2f323SJérôme Duval 
53557e2f323SJérôme Duval 	Invalidate();
53657e2f323SJérôme Duval }
53757e2f323SJérôme Duval 
53857e2f323SJérôme Duval const bigtime_t kPlayingBlinkPeriod = 600000;
53957e2f323SJérôme Duval 
54057e2f323SJérôme Duval void
SetPaused()54157e2f323SJérôme Duval PlayPauseButton::SetPaused()
54257e2f323SJérôme Duval {
54357e2f323SJérôme Duval 	if (fState == kAboutToPlay)
54457e2f323SJérôme Duval 		return;
54557e2f323SJérôme Duval 
54657e2f323SJérôme Duval 	// in paused state blink the LED on and off
54757e2f323SJérôme Duval 	if (fState == kPausedLedOn)
54857e2f323SJérôme Duval 		fState = kPausedLedOff;
54957e2f323SJérôme Duval 	else
55057e2f323SJérôme Duval 		fState = kPausedLedOn;
55157e2f323SJérôme Duval 
55257e2f323SJérôme Duval 	Invalidate();
55357e2f323SJérôme Duval }
55457e2f323SJérôme Duval 
55557e2f323SJérôme Duval uint32
ModeMask() const55657e2f323SJérôme Duval PlayPauseButton::ModeMask() const
55757e2f323SJérôme Duval {
55857e2f323SJérôme Duval 	if (!IsEnabled())
55957e2f323SJérôme Duval 		return kDisabledMask;
56057e2f323SJérôme Duval 
56157e2f323SJérôme Duval 	uint32 result = 0;
56257e2f323SJérôme Duval 
56357e2f323SJérôme Duval 	if (Value())
56457e2f323SJérôme Duval 		result = kPressedMask;
56557e2f323SJérôme Duval 
56657e2f323SJérôme Duval 	if (fState == kPlayingLedOn || fState == kAboutToPlay)
56757e2f323SJérôme Duval 		result |= kPlayingMask;
56857e2f323SJérôme Duval 	else if (fState == kAboutToPause || fState == kPausedLedOn)
56957e2f323SJérôme Duval 		result |= kPausedMask;
57057e2f323SJérôme Duval 
57157e2f323SJérôme Duval 	return result;
57257e2f323SJérôme Duval }
57357e2f323SJérôme Duval 
57457e2f323SJérôme Duval const unsigned char *
BitsForMask(uint32 mask) const57557e2f323SJérôme Duval PlayPauseButton::BitsForMask(uint32 mask) const
57657e2f323SJérôme Duval {
57757e2f323SJérôme Duval 	switch (mask) {
57857e2f323SJérôme Duval 		case kPlayingMask:
57957e2f323SJérôme Duval 			return kPlayingPlayButtonBitmapBits;
58057e2f323SJérôme Duval 		case kPlayingMask | kPressedMask:
58157e2f323SJérôme Duval 			return kPressedPlayingPlayButtonBitmapBits;
58257e2f323SJérôme Duval 		case kPausedMask:
58357e2f323SJérôme Duval 			return kPausedPlayButtonBitmapBits;
58457e2f323SJérôme Duval 		case kPausedMask | kPressedMask:
58557e2f323SJérôme Duval 			return kPressedPausedPlayButtonBitmapBits;
58657e2f323SJérôme Duval 		default:
58757e2f323SJérôme Duval 			return _inherited::BitsForMask(mask);
58857e2f323SJérôme Duval 	}
58957e2f323SJérôme Duval 	TRESPASS();
59057e2f323SJérôme Duval 	return 0;
59157e2f323SJérôme Duval }
59257e2f323SJérôme Duval 
59357e2f323SJérôme Duval 
59457e2f323SJérôme Duval void
StartPressing()59557e2f323SJérôme Duval PlayPauseButton::StartPressing()
59657e2f323SJérôme Duval {
59757e2f323SJérôme Duval 	if (fState == kPlayingLedOn || fState == kPlayingLedOff)
59857e2f323SJérôme Duval 		fState = kAboutToPause;
59957e2f323SJérôme Duval 	else
60057e2f323SJérôme Duval 	 	fState = kAboutToPlay;
60157e2f323SJérôme Duval 
60257e2f323SJérôme Duval 	_inherited::StartPressing();
60357e2f323SJérôme Duval }
60457e2f323SJérôme Duval 
60557e2f323SJérôme Duval void
MouseCancelPressing()60657e2f323SJérôme Duval PlayPauseButton::MouseCancelPressing()
60757e2f323SJérôme Duval {
60857e2f323SJérôme Duval 	if (fState == kAboutToPause)
60957e2f323SJérôme Duval 	 	fState = kPlayingLedOn;
61057e2f323SJérôme Duval 	else
61157e2f323SJérôme Duval 		fState = kStopped;
61257e2f323SJérôme Duval 
61357e2f323SJérôme Duval 	_inherited::MouseCancelPressing();
61457e2f323SJérôme Duval }
61557e2f323SJérôme Duval 
61657e2f323SJérôme Duval void
DonePressing()61757e2f323SJérôme Duval PlayPauseButton::DonePressing()
61857e2f323SJérôme Duval {
61957e2f323SJérôme Duval 	if (fState == kAboutToPause) {
62057e2f323SJérôme Duval 	 	fState = kPausedLedOn;
62157e2f323SJérôme Duval 	} else if (fState == kAboutToPlay) {
62257e2f323SJérôme Duval 		fState = kPlayingLedOn;
62357e2f323SJérôme Duval 		if (!fRunner && fBlinkMessage)
624*3ee96407SJérôme Duval 			fRunner = new BMessageRunner(Messenger(), fBlinkMessage,
625*3ee96407SJérôme Duval 				kPlayingBlinkPeriod);
62657e2f323SJérôme Duval 	}
62757e2f323SJérôme Duval 
62857e2f323SJérôme Duval 	_inherited::DonePressing();
62957e2f323SJérôme Duval }
63057e2f323SJérôme Duval 
63157e2f323SJérôme Duval 
RecordButton(BRect frame,const char * name,BMessage * invokeMessage,BMessage * blinkMessage,uint32 key,uint32 modifiers,uint32 resizeFlags)63257e2f323SJérôme Duval RecordButton::RecordButton(BRect frame, const char *name,
63357e2f323SJérôme Duval 	BMessage *invokeMessage, BMessage *blinkMessage,
63457e2f323SJérôme Duval 	uint32 key, uint32 modifiers, uint32 resizeFlags)
635*3ee96407SJérôme Duval 	:	TransportButton(frame, name, kRecordButtonBitmapBits,
636*3ee96407SJérôme Duval 			kPressedRecordButtonBitmapBits,
63757e2f323SJérôme Duval 			kDisabledRecordButtonBitmapBits, invokeMessage, NULL, NULL,
63857e2f323SJérôme Duval 			NULL, 0, key, modifiers, resizeFlags),
63957e2f323SJérôme Duval 		fState(RecordButton::kStopped),
64057e2f323SJérôme Duval 		fLastModeMask(0),
64157e2f323SJérôme Duval 		fRunner(NULL),
64257e2f323SJérôme Duval 		fBlinkMessage(blinkMessage)
64357e2f323SJérôme Duval {
64457e2f323SJérôme Duval }
64557e2f323SJérôme Duval 
64657e2f323SJérôme Duval void
SetStopped()64757e2f323SJérôme Duval RecordButton::SetStopped()
64857e2f323SJérôme Duval {
64957e2f323SJérôme Duval 	if (fState == kStopped || fState == kAboutToRecord)
65057e2f323SJérôme Duval 		return;
65157e2f323SJérôme Duval 
65257e2f323SJérôme Duval 	fState = kStopped;
65357e2f323SJérôme Duval 	delete fRunner;
65457e2f323SJérôme Duval 	fRunner = NULL;
65557e2f323SJérôme Duval 	Invalidate();
65657e2f323SJérôme Duval }
65757e2f323SJérôme Duval 
65857e2f323SJérôme Duval const bigtime_t kRecordingBlinkPeriod = 600000;
65957e2f323SJérôme Duval 
66057e2f323SJérôme Duval void
SetRecording()66157e2f323SJérôme Duval RecordButton::SetRecording()
66257e2f323SJérôme Duval {
66357e2f323SJérôme Duval 	if (fState == kAboutToStop)
66457e2f323SJérôme Duval 		return;
66557e2f323SJérôme Duval 
66657e2f323SJérôme Duval 	if (fState == kRecordingLedOff)
66757e2f323SJérôme Duval 		fState = kRecordingLedOn;
66857e2f323SJérôme Duval 	else
66957e2f323SJérôme Duval 		fState = kRecordingLedOff;
67057e2f323SJérôme Duval 
67157e2f323SJérôme Duval 	Invalidate();
67257e2f323SJérôme Duval }
67357e2f323SJérôme Duval 
67457e2f323SJérôme Duval uint32
ModeMask() const67557e2f323SJérôme Duval RecordButton::ModeMask() const
67657e2f323SJérôme Duval {
67757e2f323SJérôme Duval 	if (!IsEnabled())
67857e2f323SJérôme Duval 		return kDisabledMask;
67957e2f323SJérôme Duval 
68057e2f323SJérôme Duval 	uint32 result = 0;
68157e2f323SJérôme Duval 
68257e2f323SJérôme Duval 	if (Value())
68357e2f323SJérôme Duval 		result = kPressedMask;
68457e2f323SJérôme Duval 
68557e2f323SJérôme Duval 	if (fState == kAboutToStop || fState == kRecordingLedOn)
68657e2f323SJérôme Duval 		result |= kRecordingMask;
68757e2f323SJérôme Duval 
68857e2f323SJérôme Duval 	return result;
68957e2f323SJérôme Duval }
69057e2f323SJérôme Duval 
69157e2f323SJérôme Duval const unsigned char *
BitsForMask(uint32 mask) const69257e2f323SJérôme Duval RecordButton::BitsForMask(uint32 mask) const
69357e2f323SJérôme Duval {
69457e2f323SJérôme Duval 	switch (mask) {
69557e2f323SJérôme Duval 		case kRecordingMask:
69657e2f323SJérôme Duval 			return kRecordingRecordButtonBitmapBits;
69757e2f323SJérôme Duval 		case kRecordingMask | kPressedMask:
69857e2f323SJérôme Duval 			return kPressedRecordingRecordButtonBitmapBits;
69957e2f323SJérôme Duval 		default:
70057e2f323SJérôme Duval 			return _inherited::BitsForMask(mask);
70157e2f323SJérôme Duval 	}
70257e2f323SJérôme Duval 	TRESPASS();
70357e2f323SJérôme Duval 	return 0;
70457e2f323SJérôme Duval }
70557e2f323SJérôme Duval 
70657e2f323SJérôme Duval 
70757e2f323SJérôme Duval void
StartPressing()70857e2f323SJérôme Duval RecordButton::StartPressing()
70957e2f323SJérôme Duval {
71057e2f323SJérôme Duval 	if (fState == kRecordingLedOn || fState == kRecordingLedOff)
71157e2f323SJérôme Duval 		fState = kAboutToStop;
71257e2f323SJérôme Duval 	else
71357e2f323SJérôme Duval 	 	fState = kAboutToRecord;
71457e2f323SJérôme Duval 
71557e2f323SJérôme Duval 	_inherited::StartPressing();
71657e2f323SJérôme Duval }
71757e2f323SJérôme Duval 
71857e2f323SJérôme Duval void
MouseCancelPressing()71957e2f323SJérôme Duval RecordButton::MouseCancelPressing()
72057e2f323SJérôme Duval {
72157e2f323SJérôme Duval 	if (fState == kAboutToStop)
72257e2f323SJérôme Duval 	 	fState = kRecordingLedOn;
72357e2f323SJérôme Duval 	else
72457e2f323SJérôme Duval 		fState = kStopped;
72557e2f323SJérôme Duval 
72657e2f323SJérôme Duval 	_inherited::MouseCancelPressing();
72757e2f323SJérôme Duval }
72857e2f323SJérôme Duval 
72957e2f323SJérôme Duval void
DonePressing()73057e2f323SJérôme Duval RecordButton::DonePressing()
73157e2f323SJérôme Duval {
73257e2f323SJérôme Duval 	if (fState == kAboutToStop) {
73357e2f323SJérôme Duval 	 	fState = kStopped;
73457e2f323SJérôme Duval 	 	delete fRunner;
73557e2f323SJérôme Duval 	 	fRunner = NULL;
73657e2f323SJérôme Duval 	} else if (fState == kAboutToRecord) {
73757e2f323SJérôme Duval 		fState = kRecordingLedOn;
73857e2f323SJérôme Duval 		if (!fRunner && fBlinkMessage)
739*3ee96407SJérôme Duval 			fRunner = new BMessageRunner(Messenger(), fBlinkMessage,
740*3ee96407SJérôme Duval 				kRecordingBlinkPeriod);
74157e2f323SJérôme Duval 	}
74257e2f323SJérôme Duval 
74357e2f323SJérôme Duval 	_inherited::DonePressing();
74457e2f323SJérôme Duval }
745