TransportButton.cpp
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:13k
源码类别:

多媒体

开发平台:

MultiPlatform

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