* Rewrote long click mouse tracking. This avoids busy looping in TimeView::MouseDown and fixes
#591. The helper class could be reused for similar situations (ex: Tracker context menu and drag detection). See the brief doc in the code. Comments welcomed! git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27258 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -34,6 +34,7 @@ Application Deskbar :
|
|||||||
CalendarMenuItem.cpp
|
CalendarMenuItem.cpp
|
||||||
DeskBarUtils.cpp
|
DeskBarUtils.cpp
|
||||||
ExpandoMenuBar.cpp
|
ExpandoMenuBar.cpp
|
||||||
|
LongClickTracker.cpp
|
||||||
ShowHideMenuItem.cpp
|
ShowHideMenuItem.cpp
|
||||||
StatusView.cpp
|
StatusView.cpp
|
||||||
StatusViewShelf.cpp
|
StatusViewShelf.cpp
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Alexandre Deckner <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "LongClickTracker.h"
|
||||||
|
|
||||||
|
#include <View.h>
|
||||||
|
|
||||||
|
|
||||||
|
LongClickTracker::LongClickTracker(BView *view, uint32 messageWhat)
|
||||||
|
: fView(view),
|
||||||
|
fMessenger(NULL),
|
||||||
|
fMessageWhat(messageWhat),
|
||||||
|
fThread(B_ERROR),
|
||||||
|
fQuit(false)
|
||||||
|
{
|
||||||
|
// use the doubleClickSpeed as a threshold
|
||||||
|
get_click_speed(&fLongClickThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LongClickTracker::~LongClickTracker()
|
||||||
|
{
|
||||||
|
if (fThread != B_NO_ERROR)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fQuit = true;
|
||||||
|
|
||||||
|
status_t ret;
|
||||||
|
wait_for_thread(fThread, &ret);
|
||||||
|
|
||||||
|
delete fMessenger;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Must be called _after_ the view has been attached to a window
|
||||||
|
status_t
|
||||||
|
LongClickTracker::Start()
|
||||||
|
{
|
||||||
|
status_t err;
|
||||||
|
|
||||||
|
if (!fView->Window())
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
fMessenger = new BMessenger(fView, NULL, &err);
|
||||||
|
if (err != B_OK)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
fThread = spawn_thread(LongClickTracker::_ThreadEntry, "clickTracker",
|
||||||
|
B_NORMAL_PRIORITY, this);
|
||||||
|
|
||||||
|
err = resume_thread(fThread);
|
||||||
|
|
||||||
|
if (err != B_NO_ERROR) {
|
||||||
|
kill_thread(fThread);
|
||||||
|
fThread = B_ERROR;
|
||||||
|
} else {
|
||||||
|
fQuit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
LongClickTracker::_ThreadEntry(void *pointer)
|
||||||
|
{
|
||||||
|
LongClickTracker *that = reinterpret_cast<LongClickTracker*>(pointer);
|
||||||
|
that->_Track();
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LongClickTracker::_Track()
|
||||||
|
{
|
||||||
|
uint32 buttons;
|
||||||
|
BPoint position;
|
||||||
|
|
||||||
|
bool timing = false;
|
||||||
|
//when true, we are currently timing the last click duration
|
||||||
|
bool ready = true;
|
||||||
|
//when true, button has been released, we can start timing on next click
|
||||||
|
|
||||||
|
bigtime_t clickTime = 0;
|
||||||
|
|
||||||
|
BRect bounds;
|
||||||
|
fView->LockLooper();
|
||||||
|
bounds = fView->Bounds();
|
||||||
|
fView->UnlockLooper();
|
||||||
|
|
||||||
|
while (!fQuit) {
|
||||||
|
snooze(20000);
|
||||||
|
|
||||||
|
if (fView->Window()) {
|
||||||
|
fView->LockLooper();
|
||||||
|
fView->GetMouse(&position, &buttons, false);
|
||||||
|
fView->UnlockLooper();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timing) {
|
||||||
|
if (!bounds.Contains(position)) {
|
||||||
|
//mouse exited the view, stop timing
|
||||||
|
timing = false;
|
||||||
|
ready = false; //not ready yet, the button might be still down
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buttons != B_PRIMARY_MOUSE_BUTTON) {
|
||||||
|
//button has been released, stop timing, set ready
|
||||||
|
timing = false;
|
||||||
|
ready = true;
|
||||||
|
|
||||||
|
} else if ((system_time() - clickTime) > fLongClickThreshold){
|
||||||
|
BMessage message(fMessageWhat);
|
||||||
|
message.AddPoint("where", position);
|
||||||
|
fMessenger->SendMessage(&message);
|
||||||
|
timing = false;
|
||||||
|
ready = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ready && !timing && (buttons != B_PRIMARY_MOUSE_BUTTON)) {
|
||||||
|
//mouse released, ready to time on next click
|
||||||
|
ready = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ready && !timing && buttons == B_PRIMARY_MOUSE_BUTTON
|
||||||
|
&& bounds.Contains(position)) {
|
||||||
|
//mouse clicked in view, start timing
|
||||||
|
timing = true;
|
||||||
|
clickTime = system_time();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007-2008, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Alexandre Deckner <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LongClickTracker:
|
||||||
|
* This class provides a way to track long clicks asynchronously.
|
||||||
|
* Set the view to track and the code of the message you want to receive.
|
||||||
|
* When a long click occurs in the view, a message will be sent to the view.
|
||||||
|
* It contains the coordinates of the click (last postion) in a BPoint:"where"
|
||||||
|
*
|
||||||
|
* Could be extended to be more parametrable and/or support other kind of
|
||||||
|
* complex mouse tracking. This could also be done on the input server side
|
||||||
|
* eventually, and use this class for R5 backward compatibility.
|
||||||
|
*
|
||||||
|
* Call Start() after the view has been attached to a window.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LONG_CLICK_TRACKER_H_
|
||||||
|
#define _LONG_CLICK_TRACKER_H_
|
||||||
|
|
||||||
|
#include <Messenger.h>
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
|
class BView;
|
||||||
|
class BMessenger;
|
||||||
|
|
||||||
|
class LongClickTracker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LongClickTracker(BView *view, uint32 messageWhat);
|
||||||
|
~LongClickTracker();
|
||||||
|
|
||||||
|
status_t Start();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static int32 _ThreadEntry(void *that);
|
||||||
|
void _Track();
|
||||||
|
|
||||||
|
BView* fView;
|
||||||
|
BMessenger* fMessenger;
|
||||||
|
int32 fMessageWhat;
|
||||||
|
thread_id fThread;
|
||||||
|
bool fQuit;
|
||||||
|
bigtime_t fLongClickThreshold;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _LONG_CLICK_TRACKER_H_
|
||||||
@@ -65,7 +65,8 @@ static const float kHMargin = 2.0;
|
|||||||
enum {
|
enum {
|
||||||
kMsgShowClock,
|
kMsgShowClock,
|
||||||
kMsgChangeClock,
|
kMsgChangeClock,
|
||||||
kMsgHide
|
kMsgHide,
|
||||||
|
kMsgLongClick
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -82,7 +83,8 @@ TTimeView::TTimeView(float maxWidth, float height, bool showSeconds, bool milTim
|
|||||||
fEuroDate(euroDate),
|
fEuroDate(euroDate),
|
||||||
fMaxWidth(maxWidth),
|
fMaxWidth(maxWidth),
|
||||||
fHeight(height),
|
fHeight(height),
|
||||||
fOrientation(true)
|
fOrientation(true),
|
||||||
|
fLongClickTracker(this, kMsgLongClick)
|
||||||
{
|
{
|
||||||
fShowingDate = false;
|
fShowingDate = false;
|
||||||
fTime = fLastTime = time(NULL);
|
fTime = fLastTime = time(NULL);
|
||||||
@@ -154,6 +156,8 @@ TTimeView::AttachedToWindow()
|
|||||||
|
|
||||||
ResizeToPreferred();
|
ResizeToPreferred();
|
||||||
CalculateTextPlacement();
|
CalculateTextPlacement();
|
||||||
|
|
||||||
|
fLongClickTracker.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -230,6 +234,49 @@ TTimeView::MessageReceived(BMessage* message)
|
|||||||
case 'time':
|
case 'time':
|
||||||
Window()->PostMessage(message, Parent());
|
Window()->PostMessage(message, Parent());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kMsgLongClick:
|
||||||
|
{
|
||||||
|
BPoint where;
|
||||||
|
message->FindPoint("where", &where);
|
||||||
|
|
||||||
|
//TODO: do nothing if the calendar is already shown
|
||||||
|
|
||||||
|
#ifdef _SHOW_CALENDAR_MENU_ITEM
|
||||||
|
|
||||||
|
BPopUpMenu *menu = new BPopUpMenu("", false, false);
|
||||||
|
menu->SetFont(be_plain_font);
|
||||||
|
|
||||||
|
menu->AddItem(new CalendarMenuItem());
|
||||||
|
menu->ResizeToPreferred();
|
||||||
|
|
||||||
|
BPoint point = where;
|
||||||
|
BScreen screen;
|
||||||
|
where.y = Bounds().bottom + 4;
|
||||||
|
|
||||||
|
// make sure the menu is visible and doesn't hide the date
|
||||||
|
ConvertToScreen(&where);
|
||||||
|
if (where.y + menu->Bounds().Height() > screen.Frame().bottom)
|
||||||
|
where.y -= menu->Bounds().Height() + 2 * Bounds().Height();
|
||||||
|
|
||||||
|
ConvertToScreen(&point);
|
||||||
|
menu->Go(where, true, true, BRect(point.x - 4, point.y - 4,
|
||||||
|
point.x + 4, point.y + 4), true);
|
||||||
|
|
||||||
|
#elif _SHOW_CALENDAR_MENU_WINDOW
|
||||||
|
|
||||||
|
where.y = Bounds().bottom + 4.0;
|
||||||
|
ConvertToScreen(&where);
|
||||||
|
|
||||||
|
if (where.y >= BScreen().Frame().bottom)
|
||||||
|
where.y -= (Bounds().Height() + 4.0);
|
||||||
|
|
||||||
|
CalendarMenuWindow* window = new CalendarMenuWindow(where, fEuroDate);
|
||||||
|
window->Show();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BView::MessageReceived(message);
|
BView::MessageReceived(message);
|
||||||
@@ -326,71 +373,6 @@ TTimeView::MouseDown(BPoint point)
|
|||||||
fLastDateStr[0] = '\0';
|
fLastDateStr[0] = '\0';
|
||||||
fLastTimeStr[0] = '\0';
|
fLastTimeStr[0] = '\0';
|
||||||
Pulse();
|
Pulse();
|
||||||
|
|
||||||
#ifdef _SHOW_CALENDAR_MENU_ITEM
|
|
||||||
// see if the user holds down the button long enough to show him the calendar
|
|
||||||
|
|
||||||
bigtime_t startTime = system_time();
|
|
||||||
|
|
||||||
// use the doubleClickSpeed as a treshold
|
|
||||||
bigtime_t doubleClickSpeed;
|
|
||||||
get_click_speed(&doubleClickSpeed);
|
|
||||||
|
|
||||||
while (buttons) {
|
|
||||||
BPoint where;
|
|
||||||
GetMouse(&where, &buttons, false);
|
|
||||||
|
|
||||||
if ((system_time() - startTime) > doubleClickSpeed) {
|
|
||||||
BPopUpMenu *menu = new BPopUpMenu("", false, false);
|
|
||||||
menu->SetFont(be_plain_font);
|
|
||||||
|
|
||||||
menu->AddItem(new CalendarMenuItem());
|
|
||||||
menu->ResizeToPreferred();
|
|
||||||
|
|
||||||
point = where;
|
|
||||||
BScreen screen;
|
|
||||||
where.y = Bounds().bottom + 4;
|
|
||||||
|
|
||||||
// make sure the menu is visible at doesn't hide the date
|
|
||||||
ConvertToScreen(&where);
|
|
||||||
if (where.y + menu->Bounds().Height() > screen.Frame().bottom)
|
|
||||||
where.y -= menu->Bounds().Height() + 2 * Bounds().Height();
|
|
||||||
|
|
||||||
ConvertToScreen(&point);
|
|
||||||
menu->Go(where, true, true, BRect(point.x - 4, point.y - 4,
|
|
||||||
point.x + 4, point.y + 4), true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
snooze(15000);
|
|
||||||
}
|
|
||||||
#elif _SHOW_CALENDAR_MENU_WINDOW
|
|
||||||
bigtime_t startTime = system_time();
|
|
||||||
|
|
||||||
// use the doubleClickSpeed as a treshold
|
|
||||||
bigtime_t doubleClickSpeed;
|
|
||||||
get_click_speed(&doubleClickSpeed);
|
|
||||||
|
|
||||||
while (buttons) {
|
|
||||||
BPoint where;
|
|
||||||
GetMouse(&where, &buttons, false);
|
|
||||||
|
|
||||||
if ((system_time() - startTime) > doubleClickSpeed) {
|
|
||||||
where.y = Bounds().bottom + 4.0;
|
|
||||||
ConvertToScreen(&where);
|
|
||||||
|
|
||||||
if (where.y >= BScreen().Frame().bottom)
|
|
||||||
where.y -= (Bounds().Height() + 4.0);
|
|
||||||
|
|
||||||
CalendarMenuWindow* window = new CalendarMenuWindow(where, fEuroDate);
|
|
||||||
window->Show();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
snooze(15000);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -34,10 +34,9 @@ All rights reserved.
|
|||||||
#ifndef TIME_VIEW_H
|
#ifndef TIME_VIEW_H
|
||||||
#define TIME_VIEW_H
|
#define TIME_VIEW_H
|
||||||
|
|
||||||
|
|
||||||
#include <OS.h>
|
#include <OS.h>
|
||||||
#include <View.h>
|
#include <View.h>
|
||||||
|
#include "LongClickTracker.h"
|
||||||
|
|
||||||
const uint32 kMsgShowSeconds = 'ShSc';
|
const uint32 kMsgShowSeconds = 'ShSc';
|
||||||
const uint32 kMsgMilTime = 'MilT';
|
const uint32 kMsgMilTime = 'MilT';
|
||||||
@@ -124,6 +123,8 @@ class TTimeView : public BView {
|
|||||||
bool fOrientation; // vertical = true
|
bool fOrientation; // vertical = true
|
||||||
BPoint fTimeLocation;
|
BPoint fTimeLocation;
|
||||||
BPoint fDateLocation;
|
BPoint fDateLocation;
|
||||||
|
|
||||||
|
LongClickTracker fLongClickTracker;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user