TransportButton.cpp
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:15k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * TransportButton.cpp
  3.  *****************************************************************************
  4.  * Copyright (C) 2001 the VideoLAN team
  5.  * $Id: 23f214fe5d6c45ba4e324a0a1a376bda4e2216e3 $
  6.  *
  7.  * Authors: Tony Castley <tcastley@mail.powerup.com.au>
  8.  *          Stephan Aßmus <stippi@yellowbites.com>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23.  *****************************************************************************/
  24. #include <Bitmap.h>
  25. #include <Debug.h>
  26. #include <MessageFilter.h>
  27. #include <Screen.h>
  28. #include <Window.h>
  29. #include <map>
  30. #include "TransportButton.h"
  31. #include "DrawingTidbits.h"
  32. class BitmapStash {
  33. // Bitmap stash is a simple class to hold all the lazily-allocated
  34. // bitmaps that the TransportButton needs when rendering itself.
  35. // signature is a combination of the different enabled, pressed, playing, etc.
  36. // flavors of a bitmap. If the stash does not have a particular bitmap,
  37. // it turns around to ask the button to create one and stores it for next time.
  38. public:
  39.     BitmapStash(TransportButton *);
  40.     ~BitmapStash();
  41.     BBitmap *GetBitmap(uint32 signature);
  42.     
  43. private:
  44.     TransportButton *owner;
  45.     map<uint32, BBitmap *> stash;
  46. };
  47. BitmapStash::BitmapStash(TransportButton *owner)
  48.     :    owner(owner)
  49. {
  50. }
  51. BBitmap *
  52. BitmapStash::GetBitmap(uint32 signature)
  53. {
  54.     if (stash.find(signature) == stash.end()) {
  55.         BBitmap *newBits = owner->MakeBitmap(signature);
  56.         ASSERT(newBits);
  57.         stash[signature] = newBits;
  58.     }
  59.     
  60.     return stash[signature];
  61. }
  62. BitmapStash::~BitmapStash()
  63. {
  64.     // delete all the bitmaps
  65.     for (map<uint32, BBitmap *>::iterator i = stash.begin(); i != stash.end(); i++)
  66.         delete (*i).second;
  67. }
  68. class PeriodicMessageSender {
  69.     // used to send a specified message repeatedly when holding down a button
  70. public:
  71.     static PeriodicMessageSender *Launch(BMessenger target,
  72.         const BMessage *message, bigtime_t period);
  73.     void Quit();
  74. private:
  75.     PeriodicMessageSender(BMessenger target, const BMessage *message,
  76.         bigtime_t period);
  77.     ~PeriodicMessageSender() {}
  78.         // use quit
  79.     static status_t TrackBinder(void *);
  80.     void Run();
  81.     
  82.     BMessenger target;
  83.     BMessage message;
  84.     bigtime_t period;
  85.     
  86.     bool requestToQuit;
  87. };
  88. PeriodicMessageSender::PeriodicMessageSender(BMessenger target,
  89.     const BMessage *message, bigtime_t period)
  90.     :    target(target),
  91.         message(*message),
  92.         period(period),
  93.         requestToQuit(false)
  94. {
  95. }
  96. PeriodicMessageSender *
  97. PeriodicMessageSender::Launch(BMessenger target, const BMessage *message,
  98.     bigtime_t period)
  99. {
  100.     PeriodicMessageSender *result = new PeriodicMessageSender(target, message, period);
  101.     thread_id thread = spawn_thread(&PeriodicMessageSender::TrackBinder,
  102.         "ButtonRepeatingThread", B_NORMAL_PRIORITY, result);
  103.     
  104.     if (thread <= 0 || resume_thread(thread) != B_OK) {
  105.         // didn't start, don't leak self
  106.         delete result;
  107.         result = 0;
  108.     }
  109.     return result;
  110. }
  111. void
  112. PeriodicMessageSender::Quit()
  113. {
  114.     requestToQuit = true;
  115. }
  116. status_t
  117. PeriodicMessageSender::TrackBinder(void *castToThis)
  118. {
  119.     ((PeriodicMessageSender *)castToThis)->Run();
  120.     return 0;
  121. }
  122. void
  123. PeriodicMessageSender::Run()
  124. {
  125.     for (;;) {
  126.         snooze(period);
  127.         if (requestToQuit)
  128.             break;
  129.         target.SendMessage(&message);
  130.     }
  131.     delete this;
  132. }
  133. class SkipButtonKeypressFilter : public BMessageFilter {
  134. public:
  135.     SkipButtonKeypressFilter(uint32 shortcutKey, uint32 shortcutModifier,
  136.         TransportButton *target);
  137. protected:
  138.     filter_result Filter(BMessage *message, BHandler **handler);
  139. private:
  140.     uint32 shortcutKey;
  141.     uint32 shortcutModifier;
  142.     TransportButton *target;
  143. };
  144. SkipButtonKeypressFilter::SkipButtonKeypressFilter(uint32 shortcutKey,
  145.     uint32 shortcutModifier, TransportButton *target)
  146.     :    BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
  147.         shortcutKey(shortcutKey),
  148.         shortcutModifier(shortcutModifier),
  149.         target(target)
  150. {
  151. }
  152. filter_result
  153. SkipButtonKeypressFilter::Filter(BMessage *message, BHandler **handler)
  154. {
  155.     if (target->IsEnabled()
  156.         && (message->what == B_KEY_DOWN || message->what == B_KEY_UP)) {
  157.         uint32 modifiers;
  158.         uint32 rawKeyChar = 0;
  159.         uint8 byte = 0;
  160.         int32 key = 0;
  161.         
  162.         if (message->FindInt32("modifiers", (int32 *)&modifiers) != B_OK
  163.             || message->FindInt32("raw_char", (int32 *)&rawKeyChar) != B_OK
  164.             || message->FindInt8("byte", (int8 *)&byte) != B_OK
  165.             || message->FindInt32("key", &key) != B_OK)
  166.             return B_DISPATCH_MESSAGE;
  167.         modifiers &= B_SHIFT_KEY | B_COMMAND_KEY | B_CONTROL_KEY
  168.             | B_OPTION_KEY | B_MENU_KEY;
  169.             // strip caps lock, etc.
  170.         if (modifiers == shortcutModifier && rawKeyChar == shortcutKey) {
  171.             if (message->what == B_KEY_DOWN)
  172.                 target->ShortcutKeyDown();
  173.             else
  174.                 target->ShortcutKeyUp();
  175.             
  176.             return B_SKIP_MESSAGE;
  177.         }
  178.     }
  179.     // let others deal with this
  180.     return B_DISPATCH_MESSAGE;
  181. }
  182. TransportButton::TransportButton(BRect frame, const char *name,
  183.     const unsigned char *normalBits,
  184.     const unsigned char *pressedBits,
  185.     const unsigned char *disabledBits,
  186.     BMessage *invokeMessage, BMessage *startPressingMessage,
  187.     BMessage *pressingMessage, BMessage *donePressingMessage, bigtime_t period,
  188.     uint32 key, uint32 modifiers, uint32 resizeFlags)
  189.     :    BControl(frame, name, "", invokeMessage, resizeFlags, B_WILL_DRAW | B_NAVIGABLE),
  190.         bitmaps(new BitmapStash(this)),
  191.         normalBits(normalBits),
  192.         pressedBits(pressedBits),
  193.         disabledBits(disabledBits),
  194.         startPressingMessage(startPressingMessage),
  195.         pressingMessage(pressingMessage),
  196.         donePressingMessage(donePressingMessage),
  197.         pressingPeriod(period),
  198.         mouseDown(false),
  199.         keyDown(false),
  200.         messageSender(0),
  201.         keyPressFilter(0)
  202. {
  203.     if (key)
  204.         keyPressFilter = new SkipButtonKeypressFilter(key, modifiers, this);
  205. }
  206. void
  207. TransportButton::AttachedToWindow()
  208. {
  209.     _inherited::AttachedToWindow();
  210.     if (keyPressFilter)
  211.         Window()->AddCommonFilter(keyPressFilter);
  212.     
  213.     // transparent to reduce flicker
  214.     SetViewColor(B_TRANSPARENT_COLOR);
  215. }
  216. void
  217. TransportButton::DetachedFromWindow()
  218. {
  219.     if (keyPressFilter)
  220.         Window()->RemoveCommonFilter(keyPressFilter);
  221.     _inherited::DetachedFromWindow();
  222. }
  223. TransportButton::~TransportButton()
  224. {
  225.     delete startPressingMessage;
  226.     delete pressingMessage;
  227.     delete donePressingMessage;
  228.     delete bitmaps;
  229.     delete keyPressFilter;
  230. }
  231. void
  232. TransportButton::WindowActivated(bool state)
  233. {
  234.     if (!state)
  235.         ShortcutKeyUp();
  236.     
  237.     _inherited::WindowActivated(state);
  238. }
  239. void
  240. TransportButton::SetEnabled(bool on)
  241. {
  242.     if (on != IsEnabled()) {
  243.         _inherited::SetEnabled(on);
  244.         if (!on)
  245.             ShortcutKeyUp();
  246.     }    
  247. }
  248. const unsigned char *
  249. TransportButton::BitsForMask(uint32 mask) const
  250. {
  251.     switch (mask) {
  252.         case 0:
  253.             return normalBits;
  254.         case kDisabledMask:
  255.             return disabledBits;
  256.         case kPressedMask:
  257.             return pressedBits;
  258.         default:
  259.             break;
  260.     }    
  261.     TRESPASS();
  262.     return 0;
  263. }
  264. BBitmap *
  265. TransportButton::MakeBitmap(uint32 mask)
  266. {
  267.     BRect r(Bounds());
  268.     BBitmap *result = new BBitmap(r, B_CMAP8);
  269.     uint8* src = (uint8*)BitsForMask(mask);
  270.     if (src && result && result->IsValid()) {
  271.         // int32 width = r.IntegerWidth() + 1;
  272.         int32 height = r.IntegerHeight() + 1;
  273.         int32 bpr = result->BytesPerRow();
  274.         uint8* dst = (uint8*)result->Bits();
  275.         // copy source bits into bitmap line by line,
  276.         // taking possible alignment into account
  277.         // since the source data has been generated
  278.         // by QuickRes, it still contains aligment too
  279.         // (hence skipping bpr and not width bytes)
  280.         for (int32 y = 0; y < height; y++) {
  281.             memcpy(dst, src, bpr);
  282.             src += bpr;
  283.             dst += bpr;
  284.         }
  285.         ReplaceTransparentColor(result, Parent()->ViewColor());
  286.     } else {
  287.         delete result;
  288.         result = NULL;
  289.     }
  290.     
  291.     return result;
  292. }
  293. uint32
  294. TransportButton::ModeMask() const
  295. {
  296.     return (IsEnabled() ? 0 : kDisabledMask)
  297.         | (Value() ? kPressedMask : 0);
  298. }
  299. void
  300. TransportButton::Draw(BRect)
  301. {
  302.     DrawBitmapAsync(bitmaps->GetBitmap(ModeMask()));
  303. }
  304. void
  305. TransportButton::StartPressing()
  306. {
  307.     SetValue(1);
  308.     if (startPressingMessage)
  309.         Invoke(startPressingMessage);
  310.     
  311.     if (pressingMessage) {
  312.         ASSERT(pressingMessage);
  313.         messageSender = PeriodicMessageSender::Launch(Messenger(),
  314.             pressingMessage, pressingPeriod);
  315.     }
  316. }
  317. void
  318. TransportButton::MouseCancelPressing()
  319. {
  320.     if (!mouseDown || keyDown)
  321.         return;
  322.     mouseDown = false;
  323.     if (pressingMessage) {
  324.         ASSERT(messageSender);
  325.         PeriodicMessageSender *sender = messageSender;
  326.         messageSender = 0;
  327.         sender->Quit();
  328.     }
  329.     if (donePressingMessage)
  330.         Invoke(donePressingMessage);
  331.     SetValue(0);
  332. }
  333. void
  334. TransportButton::DonePressing()
  335. {    
  336.     if (pressingMessage) {
  337.         ASSERT(messageSender);
  338.         PeriodicMessageSender *sender = messageSender;
  339.         messageSender = 0;
  340.         sender->Quit();
  341.     }
  342.     Invoke();
  343.     SetValue(0);
  344. }
  345. void
  346. TransportButton::MouseStartPressing()
  347. {
  348.     if (mouseDown)
  349.         return;
  350.     
  351.     mouseDown = true;
  352.     if (!keyDown)
  353.         StartPressing();
  354. }
  355. void
  356. TransportButton::MouseDonePressing()
  357. {
  358.     if (!mouseDown)
  359.         return;
  360.     
  361.     mouseDown = false;
  362.     if (!keyDown)
  363.         DonePressing();
  364. }
  365. void
  366. TransportButton::ShortcutKeyDown()
  367. {
  368.     if (!IsEnabled())
  369.         return;
  370.     if (keyDown)
  371.         return;
  372.     
  373.     keyDown = true;
  374.     if (!mouseDown)
  375.         StartPressing();
  376. }
  377. void
  378. TransportButton::ShortcutKeyUp()
  379. {
  380.     if (!keyDown)
  381.         return;
  382.     
  383.     keyDown = false;
  384.     if (!mouseDown)
  385.         DonePressing();
  386. }
  387. void
  388. TransportButton::MouseDown(BPoint)
  389. {
  390.     if (!IsEnabled())
  391.         return;
  392.     ASSERT(Window()->Flags() & B_ASYNCHRONOUS_CONTROLS);
  393.     SetTracking(true);
  394.     SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
  395.     MouseStartPressing();
  396. }
  397. void
  398. TransportButton::MouseMoved(BPoint point, uint32 code, const BMessage *)
  399. {
  400.     if (IsTracking() && Bounds().Contains(point) != Value()) {
  401.         if (!Value())
  402.             MouseStartPressing();
  403.         else
  404.             MouseCancelPressing();
  405.     }
  406. }
  407. void
  408. TransportButton::MouseUp(BPoint point)
  409. {
  410.     if (IsTracking()) {
  411.         if (Bounds().Contains(point))
  412.             MouseDonePressing();
  413.         else
  414.             MouseCancelPressing();
  415.         SetTracking(false);
  416.     }
  417. }
  418. void
  419. TransportButton::SetStartPressingMessage(BMessage *message)
  420. {
  421.     delete startPressingMessage;
  422.     startPressingMessage = message;
  423. }
  424. void
  425. TransportButton::SetPressingMessage(BMessage *message)
  426. {
  427.     delete pressingMessage;
  428.     pressingMessage = message;
  429. }
  430. void
  431. TransportButton::SetDonePressingMessage(BMessage *message)
  432. {
  433.     delete donePressingMessage;
  434.     donePressingMessage = message;
  435. }
  436. void
  437. TransportButton::SetPressingPeriod(bigtime_t newTime)
  438. {
  439.     pressingPeriod = newTime;
  440. }
  441. PlayPauseButton::PlayPauseButton(BRect frame, const char *name,
  442.     const unsigned char *normalBits, const unsigned char *pressedBits,
  443.     const unsigned char *disabledBits, const unsigned char *normalPlayingBits,
  444.     const unsigned char *pressedPlayingBits, const unsigned char *normalPausedBits,
  445.     const unsigned char *pressedPausedBits,
  446.     BMessage *invokeMessage, uint32 key, uint32 modifiers, uint32 resizeFlags)
  447.     :    TransportButton(frame, name, normalBits, pressedBits,
  448.             disabledBits, invokeMessage, 0,
  449.             0, 0, 0, key, modifiers, resizeFlags),
  450.         normalPlayingBits(normalPlayingBits),
  451.         pressedPlayingBits(pressedPlayingBits),
  452.         normalPausedBits(normalPausedBits),
  453.         pressedPausedBits(pressedPausedBits),
  454.         state(PlayPauseButton::kStopped),
  455.         lastPauseBlinkTime(0),
  456.         lastModeMask(0)
  457. {
  458. }
  459. void
  460. PlayPauseButton::SetStopped()
  461. {
  462.     if (state == kStopped || state == kAboutToPlay)
  463.         return;
  464.     
  465.     state = kStopped;
  466.     Invalidate();
  467. }
  468. void
  469. PlayPauseButton::SetPlaying()
  470. {
  471.     if (state == kPlaying || state == kAboutToPause)
  472.         return;
  473.     
  474.     state = kPlaying;
  475.     Invalidate();
  476. }
  477. const bigtime_t kPauseBlinkPeriod = 600000;
  478. void
  479. PlayPauseButton::SetPaused()
  480. {
  481.     if (state == kAboutToPlay)
  482.         return;
  483.     // in paused state blink the LED on and off
  484.     bigtime_t now = system_time();
  485.     if (state == kPausedLedOn || state == kPausedLedOff) {
  486.         if (now - lastPauseBlinkTime < kPauseBlinkPeriod)
  487.             return;
  488.         
  489.         if (state == kPausedLedOn)
  490.             state = kPausedLedOff;
  491.         else
  492.             state = kPausedLedOn;
  493.     } else
  494.         state = kPausedLedOn;
  495.     
  496.     lastPauseBlinkTime = now;
  497.     Invalidate();
  498. }
  499. uint32
  500. PlayPauseButton::ModeMask() const
  501. {
  502.     if (!IsEnabled())
  503.         return kDisabledMask;
  504.     
  505.     uint32 result = 0;
  506.     if (Value())
  507.         result = kPressedMask;
  508.     if (state == kPlaying || state == kAboutToPlay)
  509.         result |= kPlayingMask;
  510.     else if (state == kAboutToPause || state == kPausedLedOn)        
  511.         result |= kPausedMask;
  512.     
  513.     return result;
  514. }
  515. const unsigned char *
  516. PlayPauseButton::BitsForMask(uint32 mask) const
  517. {
  518.     switch (mask) {
  519.         case kPlayingMask:
  520.             return normalPlayingBits;
  521.         case kPlayingMask | kPressedMask:
  522.             return pressedPlayingBits;
  523.         case kPausedMask:
  524.             return normalPausedBits;
  525.         case kPausedMask | kPressedMask:
  526.             return pressedPausedBits;
  527.         default:
  528.             return _inherited::BitsForMask(mask);
  529.     }    
  530.     TRESPASS();
  531.     return 0;
  532. }
  533. void
  534. PlayPauseButton::StartPressing()
  535. {
  536.     if (state == kPlaying)
  537.         state = kAboutToPause;
  538.     else
  539.          state = kAboutToPlay;
  540.     
  541.     _inherited::StartPressing();
  542. }
  543. void
  544. PlayPauseButton::MouseCancelPressing()
  545. {
  546.     if (state == kAboutToPause)
  547.          state = kPlaying;
  548.     else
  549.         state = kStopped;
  550.     
  551.     _inherited::MouseCancelPressing();
  552. }
  553. void
  554. PlayPauseButton::DonePressing()
  555. {
  556.     if (state == kAboutToPause) {
  557.          state = kPausedLedOn;
  558.         lastPauseBlinkTime = system_time();
  559.     } else if (state == kAboutToPlay)
  560.         state = kPlaying;
  561.     
  562.     _inherited::DonePressing();
  563. }