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