Beispiel #1
0
void
BTextWidget::MouseUp(BRect bounds, BPoseView* view, BPose* pose, BPoint)
{
	// Register the time of that click.  The PoseView, through its Pulse()
	// will allow us to StartEdit() if no other click have been registered since
	// then.

	// TODO: re-enable modifiers, one should be enough
	view->SetTextWidgetToCheck(NULL);
	if (IsEditable() && pose->IsSelected()) {
		bigtime_t doubleClickSpeed;
		get_click_speed(&doubleClickSpeed);

		if (fLastClickedTime == 0) {
			fLastClickedTime = system_time();
			if (fLastClickedTime - doubleClickSpeed < pose->SelectionTime())
				fLastClickedTime = 0;
		} else
			fLastClickedTime = 0;

		if (fLastClickedTime == 0)
			return;

		view->SetTextWidgetToCheck(this);

		fParams.pose = pose;
		fParams.bounds = bounds;
		fParams.poseView = view;
	} else
		fLastClickedTime = 0;
}
Beispiel #2
0
Slider::Slider (BRect p, float _sep, const char *_name, float _min, float _max, float _step, BMessage *_msg, orientation _posture, int _f, const char *_fmt)
: BView (p, _name, B_FOLLOW_NONE, B_WILL_DRAW | B_NAVIGABLE)
{
	value = _min;
	min = _min;
	max = _max;
	step = _step;
	pos = _posture;
	msg = _msg;
	width = p.Width() - _sep;
	height = p.Height();
	bounds.top = 0;
	bounds.left = 0;
	bounds.right = width + 1;
	bounds.bottom = height;
	f = _f;
	strcpy (fmt, _fmt);
	strcpy (name, _name);
	sep = _sep;
	offslid = new BBitmap (bounds, B_COLOR_8_BIT, true);
	offview = new BView (bounds, "Offscreen Slider View", B_FOLLOW_NONE, (uint32) NULL);
	offslid->AddChild (offview);
	SetViewColor (B_TRANSPARENT_32_BIT);
	get_click_speed (&dcspeed);
	click = 1;
	tc = NULL;
	target = NULL;
}
void SeqPhraseMatrixView::MouseDown(BPoint where)
{
    inherited::MouseDown(where);
    mDownTime = -1;
    mDownPt = where;
    StopPopUpTimer();

    SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
    SeqSongWinPropertiesI*		win = dynamic_cast<SeqSongWinPropertiesI*>( Window() );
    _SeqPhraseToolTarget*	target;
    if (win && (target = new _SeqPhraseToolTarget(win, this, &mMtc)) ) {
        mTool.MouseDown(target, where);
        delete target;
    }

    uint32		buttons;
    GetMouse(&where, &buttons, false);
    if (buttons&B_SECONDARY_MOUSE_BUTTON) {
        bigtime_t	doubleClickTime;
        get_click_speed(&doubleClickTime);
//		doubleClickTime *= 2;
        StartPopUpTimer(BMessage(SHOW_POPUP_MSG), doubleClickTime);
        mDownTime = system_time();
    }
}
Beispiel #4
0
PatternMenuView::PatternMenuView (BRect frame, const char *name, PatternMenuButton *cmb)
: BView (frame, name, B_FOLLOW_ALL, B_WILL_DRAW)
{
	SetViewColor (B_TRANSPARENT_32_BIT);
	fPMB = cmb;
	cmb->lock->Lock();
	cmb->MenuWinOnScreen = true;
	cmb->lock->Unlock();
	index = -1;
	get_click_speed (&dcspeed);
	click = 1;
}
Beispiel #5
0
void
BTextWidget::MouseUp(BRect bounds, BPoseView *view, BPose *pose, BPoint)
{
	// Start editing without delay if the pose was selected recently and this
	// click is not the second click of a doubleclick.
	// If the pose has been selected a long time ago, check again
	// for a double click (inducing a delay).

	// TODO: re-enable modifiers, one should be enough

	if (IsEditable() && pose->IsSelected()) {
		bigtime_t delta = system_time() - pose->SelectionTime();
		bigtime_t doubleClickSpeed;
		get_click_speed(&doubleClickSpeed);
		bigtime_t oldClickSpeed = 2 * doubleClickSpeed;

		// freshly selected and not a double click
		if (delta > doubleClickSpeed && delta < oldClickSpeed) {
			StartEdit(bounds, view, pose);
			return;
		}

		// TODO: reimplement asynchronous
		// selected a longer time ago, redo a double click detection
		if (delta > oldClickSpeed) {
			// check for double click
			bigtime_t doubleClickTime = system_time() + doubleClickSpeed;
			while (system_time() < doubleClickTime) {
				// loop for double-click time and watch the mouse and keyboard

				BPoint point;
				uint32 buttons;
				view->GetMouse(&point, &buttons, false);

				// double click
				if (buttons)
					return;

				// mouse moved too far
				if (!bounds.Contains(point))
					return;

				//if (modifiers() & (B_SHIFT_KEY | B_COMMAND_KEY
				//	| B_CONTROL_KEY | B_MENU_KEY))
				//	// watch the keyboard (ignoring standard locking keys)
				//	break;

				snooze(10000);
			}
			StartEdit(bounds, view, pose);
		}
	}
}
Beispiel #6
0
void
MouseSettings::_RetrieveSettings()
{
	// retrieve current values

	if (get_mouse_map(&fSettings.map) != B_OK)
		fprintf(stderr, "error when get_mouse_map\n");
	if (get_click_speed(&fSettings.click_speed) != B_OK)
		fprintf(stderr, "error when get_click_speed\n");
	if (get_mouse_speed(&fSettings.accel.speed) != B_OK)
		fprintf(stderr, "error when get_mouse_speed\n");
	if (get_mouse_acceleration(&fSettings.accel.accel_factor) != B_OK)
		fprintf(stderr, "error when get_mouse_acceleration\n");
	if (get_mouse_type(&fSettings.type) != B_OK)
		fprintf(stderr, "error when get_mouse_type\n");

	fMode = mouse_mode();
	fFocusFollowsMouseMode = focus_follows_mouse_mode();
	fAcceptFirstClick = accept_first_click();

	// also try to load the window position from disk

	BPath path;
	if (_GetSettingsPath(path) < B_OK)
		return;

	BFile file(path.Path(), B_READ_ONLY);
	if (file.InitCheck() < B_OK)
		return;

#if R5_COMPATIBLE
	const off_t kOffset = sizeof(mouse_settings) - sizeof(mouse_map)
		+ sizeof(int32) * 3;
		// we have to do this because mouse_map counts 16 buttons in OBOS
#else
	const off_t kOffset = sizeof(mouse_settings);
#endif

	if (file.ReadAt(kOffset, &fWindowPosition, sizeof(BPoint))
		!= sizeof(BPoint)) {
		// set default window position (invalid positions will be
		// corrected by the application; the window will be centered
		// in this case)
		fWindowPosition.x = -1;
		fWindowPosition.y = -1;
	}

#ifdef DEBUG
	Dump();
#endif
}
Beispiel #7
0
void BHSplitter::MouseUp(BPoint where)
{
	drag=0;
	bigtime_t now=system_time();

	bigtime_t doubleClickSpeed;
	get_click_speed(&doubleClickSpeed);
	
	if(now-fLastClickTime<doubleClickSpeed)
	 Window()->PostMessage(new BMessage('QuVi'));
	fLastClickTime=now;
	//be_app->SetCursor(B_HAND_CURSOR);

}
PadView::PadView(const char* name)
	: BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE, NULL),
	  fDragging(false),
	  fClickTime(0),
	  fButtonLayout(new BGroupLayout(B_VERTICAL, 4)),
	  fIconSize(DEFAULT_ICON_SIZE)
{
	SetViewColor(B_TRANSPARENT_32_BIT);
	SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
	get_click_speed(&sActivationDelay);

	fButtonLayout->SetInsets(2, 7, 2, 2);
	SetLayout(fButtonLayout);
}
Beispiel #9
0
PatternMenuButton::PatternMenuButton (BRect frame, const char *name)
: BView (frame, name, B_FOLLOW_LEFT, B_WILL_DRAW)
{
	SetViewColor (B_TRANSPARENT_32_BIT);
	index = 0;
	strcpy (_name, name);
	menu = new PatternMenu (this, P_H_NUM, P_V_NUM, P_SIZE);
	lock = new BLocker();
	MenuWinOnScreen = false;
	editorshowing = false;
	get_click_speed (&dcspeed);
	click = 1;
	menu->setParent (this);
}
Beispiel #10
0
void ArpIntControl::MouseUp(BPoint pt)
{
	if (IsEnabled() == false) return;

	if (mMotion) mMotion->MouseUp(pt);
	if ( mDownPt == pt && Bounds().Contains(pt) ) {
		/* Start the edit timer in case the user is invoking an inline
		 * text view.
		 */
		bigtime_t	doubleClickTime;
		get_click_speed(&doubleClickTime);
		doubleClickTime *= 2;
		SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
		StartTimer(BMessage(EDIT_START_MSG), doubleClickTime);
	} else Invoke();
}
Beispiel #11
0
	virtual void MouseDown(BPoint point)
	{
		// Don't reopen the menu if it's already open or freshly closed.
		bigtime_t clickSpeed = 2000000;
		get_click_speed(&clickSpeed);
		bigtime_t clickTime = Window()->CurrentMessage()->FindInt64("when");
		if (!IsEnabled() || (Value() == B_CONTROL_ON) 
			|| clickTime < fCloseTime + clickSpeed) {
			return;
		}

		// Invoke must be called before setting B_CONTROL_ON
		// for the button to stay "down"
		Invoke();
		SetValue(B_CONTROL_ON);
	}
Beispiel #12
0
void
BTextWidget::CheckExpiration()
{
	if (IsEditable() && fParams.pose->IsSelected() && fLastClickedTime) {
		bigtime_t doubleClickSpeed;
		get_click_speed(&doubleClickSpeed);

		bigtime_t delta = system_time() - fLastClickedTime;

		if (delta > doubleClickSpeed) {
			// at least 'doubleClickSpeed' microseconds ellapsed and no click
			// was registered since.
			fLastClickedTime = 0;
			StartEdit(fParams.bounds, fParams.poseView, fParams.pose);
		}
	} else {
		fLastClickedTime = 0;
		fParams.poseView->SetTextWidgetToCheck(NULL);
	}
}
Beispiel #13
0
void
ValControlSegment::MouseDown(BPoint point)
{
	if (!parent()->IsEnabled())
		return;

	parent()->MakeFocus();

	// not left button?
	uint32 nButton;
	GetMouse(&point, &nButton);
	if (!(nButton & B_PRIMARY_MOUSE_BUTTON))
		return;

	// double click?
	bigtime_t doubleClickInterval;
	if (get_click_speed(&doubleClickInterval) < B_OK) {
		PRINT(("* ValControlSegment::MouseDown():\n"
			"  get_click_speed() failed."));
		return;
	}

	bigtime_t now = system_time();
	if (now - fLastClickTime < doubleClickInterval) {
		if(isTracking()) {
			setTracking(false);
			mouseReleased();
		}

		// hand off to parent control
		parent()->showEditField();
		fLastClickTime = 0LL;
		return;
	}
	else
		fLastClickTime = now;

		
	// engage tracking
	trackMouse(point, TRACK_VERTICAL);
}
void
BTitleView::MouseDown(BPoint where)
{
	if (!Window()->IsActive()) {
		// wasn't active, just activate and bail
		Window()->Activate();
		return;
	}

	// finish any pending edits
	fPoseView->CommitActivePose();

	BColumnTitle *title = FindColumnTitle(where);
	BColumnTitle *resizedTitle = InColumnResizeArea(where);

	uint32 buttons;
	GetMouse(&where, &buttons);

	// Check if the user clicked the secondary mouse button.
	// if so, display the attribute menu:

	if (buttons & B_SECONDARY_MOUSE_BUTTON) {
		BContainerWindow *window = dynamic_cast<BContainerWindow *>
			(Window());
		BPopUpMenu *menu = new BPopUpMenu("Attributes", false, false);
		menu->SetFont(be_plain_font);
		window->NewAttributeMenu(menu);
		window->AddMimeTypesToMenu(menu);
		window->MarkAttributeMenu(menu);
		menu->SetTargetForItems(window->PoseView());
		menu->Go(ConvertToScreen(where), true, false);
		return;
	}

	bigtime_t doubleClickSpeed;
	get_click_speed(&doubleClickSpeed);

	if (resizedTitle) {
		bool force = static_cast<bool>(buttons & B_TERTIARY_MOUSE_BUTTON);
		if (force || buttons & B_PRIMARY_MOUSE_BUTTON) {
			if (force || fPreviouslyClickedColumnTitle != 0) {
				if (force || system_time() - fPreviousLeftClickTime < doubleClickSpeed) {
					if (fPoseView->ResizeColumnToWidest(resizedTitle->Column())) {
						Invalidate();
						return;
					}
				}
			}
			fPreviousLeftClickTime = system_time();
			fPreviouslyClickedColumnTitle = resizedTitle;
		}
	} else if (!title)
		return;

	SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY | B_LOCK_WINDOW_FOCUS);

	// track the mouse
	if (resizedTitle) {
		fTrackingState = new ColumnResizeState(this, resizedTitle, where,
			system_time() + doubleClickSpeed);
	} else {
		fTrackingState = new ColumnDragState(this, title, where,
			system_time() + doubleClickSpeed);
	}
}
Beispiel #15
0
void
TExpandoMenuBar::MouseDown(BPoint where)
{
	BMessage *message = Window()->CurrentMessage();
	
	// check for three finger salute, a.k.a. Vulcan Death Grip
	if (message != NULL) {
		int32 modifiers = 0;
		message->FindInt32("modifiers", &modifiers);

		if ((modifiers & B_COMMAND_KEY) != 0
			&& (modifiers & B_OPTION_KEY) != 0
			&& (modifiers & B_SHIFT_KEY) != 0
			&& !fBarView->Dragging()) {
			
			TTeamMenuItem *item = ItemAtPoint(where);
			if (item) {
				const BList	*teams = item->Teams();
				int32 teamCount = teams->CountItems();

				team_id teamID;
				for (int32 team = 0; team < teamCount; team++) {
					teamID = (team_id)teams->ItemAt(team);
					kill_team(teamID);
					//	remove the team immediately
					//	from display
					RemoveTeam(teamID, false);
				}
					
				return;
			}		
		}
	}
	
	const int32 count = CountItems();

// This feature is broken because the menu bar never receives
// the second click
#ifdef DOUBLECLICKBRINGSTOFRONT
	// doubleclick on an item brings all to front
	for (int32 i = fFirstApp; i < count; i++) {
		TTeamMenuItem *item = (TTeamMenuItem *)ItemAt(i);
		if (item->Frame().Contains(where)) {
			bigtime_t clickSpeed = 0;
			get_click_speed(&clickSpeed);
			if ( (fLastClickItem == i) && 
				 (clickSpeed > (system_time() - fLastClickTime)) ) {
				// bring this team's window to the front
				BMessage showMessage(M_BRING_TEAM_TO_FRONT);
				showMessage.AddInt32("itemIndex", i);
				Window()->PostMessage(&showMessage, this);
				return;
			}

			fLastClickItem = i;
			fLastClickTime = system_time();
			break;
		}
	}
#endif

	// control click - show all/hide all shortcut
	if (message != NULL) {
		int32 modifiers = 0;
		message->FindInt32("modifiers", &modifiers);
		if ((modifiers & B_CONTROL_KEY) != 0
			&& ! fBarView->Dragging()) {
			int32 lastApp = -1;

			// find the clicked item
			for (int32 i = fFirstApp; i < count; i++) {
				const TTeamMenuItem *item = (TTeamMenuItem *)ItemAt(i);

				// check if this item is really a team item	(what a cruel way...)
				// "lastApp" will always point to the last application in
				// the list - the other entries might be windows (due to the team expander)
				if (item->Submenu())
					 lastApp = i;

				if (item->Frame().Contains(where)) {
					// show/hide item's teams
					BMessage showMessage((modifiers & B_SHIFT_KEY) != 0
						? M_MINIMIZE_TEAM : M_BRING_TEAM_TO_FRONT);
					showMessage.AddInt32("itemIndex", lastApp);
					Window()->PostMessage(&showMessage, this);
					return;
				}
			}
		}
	}

	// Check the bounds of the expand Team icon
	if (fShowTeamExpander && fVertical && !fBarView->Dragging()) {
		TTeamMenuItem *item = ItemAtPoint(where);
		if (item->Submenu()){
			BRect expanderRect = item->ExpanderBounds();
			if (expanderRect.Contains(where)) {
				item->ToggleExpandState(true);
				item->Draw();
				// Absorb the message.
				return; 
			}
		}
	}

	BMenuBar::MouseDown(where);
}
Beispiel #16
0
void
BListView::MouseDown(BPoint where)
{
    if (!IsFocus()) {
        MakeFocus();
        Sync();
        Window()->UpdateIfNeeded();
    }

    BMessage* message = Looper()->CurrentMessage();
    int32 index = IndexOf(where);

    int32 buttons = 0;
    if (message != NULL)
        message->FindInt32("buttons", &buttons);

    int32 modifiers = 0;
    if (message != NULL)
        message->FindInt32("modifiers", &modifiers);

    // If the user double (or more) clicked within the current selection,
    // we don't change the selection but invoke the selection.
    // TODO: move this code someplace where it can be shared everywhere
    // instead of every class having to reimplement it, once some sane
    // API for it is decided.
    BPoint delta = where - fTrack->drag_start;
    bigtime_t sysTime;
    Window()->CurrentMessage()->FindInt64("when", &sysTime);
    bigtime_t timeDelta = sysTime - fTrack->last_click_time;
    bigtime_t doubleClickSpeed;
    get_click_speed(&doubleClickSpeed);
    bool doubleClick = false;

    if (timeDelta < doubleClickSpeed
            && fabs(delta.x) < kDoubleClickThreshold
            && fabs(delta.y) < kDoubleClickThreshold
            && fTrack->item_index == index) {
        doubleClick = true;
    }

    if (doubleClick && index >= fFirstSelected && index <= fLastSelected) {
        fTrack->drag_start.Set(INT32_MAX, INT32_MAX);
        Invoke();
        return BView::MouseDown(where);
    }

    if (!doubleClick) {
        fTrack->drag_start = where;
        fTrack->last_click_time = system_time();
        fTrack->item_index = index;
        fTrack->was_selected = index >= 0 ? ItemAt(index)->IsSelected() : false;
        fTrack->try_drag = true;

        MouseDownThread<BListView>::TrackMouse(this,
                                               &BListView::_DoneTracking, &BListView::_Track);
    }

    if (index >= 0) {
        if (fListType == B_MULTIPLE_SELECTION_LIST) {
            if ((modifiers & B_SHIFT_KEY) != 0) {
                // select entire block
                // TODO: maybe review if we want it like in Tracker
                // (anchor item)
                if (index >= fFirstSelected && index < fLastSelected) {
                    // clicked inside of selected items block, deselect all
                    // but from the first selected item to the clicked item
                    DeselectExcept(fFirstSelected, index);
                } else {
                    Select(std::min(index, fFirstSelected), std::max(index,
                            fLastSelected));
                }
            } else {
                if ((modifiers & B_COMMAND_KEY) != 0) {
                    // toggle selection state of clicked item (like in Tracker)
                    // toggle selection state of clicked item
                    if (ItemAt(index)->IsSelected())
                        Deselect(index);
                    else
                        Select(index, true);
                } else
                    Select(index);
            }
        } else {
            // toggle selection state of clicked item
            if ((modifiers & B_COMMAND_KEY) != 0 && ItemAt(index)->IsSelected())
                Deselect(index);
            else
                Select(index);
        }
    } else if ((modifiers & B_COMMAND_KEY) == 0)
        DeselectAll();

    BView::MouseDown(where);
}
Beispiel #17
0
void BComboBox::ChoiceListView::MouseDown(BPoint where)
{
	BRect rect(Window()->Frame());
	ConvertFromScreen(&rect);
	if (!rect.Contains(where))
	{
		// hide the popup window when the user clicks outside of it
		if (fParent->Window()->Lock())
		{
			fParent->HidePopupWindow();
			fParent->Window()->Unlock();
		}

		// HACK: the window is locked and unlocked so that it will get
		// activated before we potentially send the mouse down event in the
		// code below.  Is there a way to wait until the window is activated
		// before sending the mouse down? Should we call
		// fParent->Window()->MakeActive(true) here?
		
		if (fParent->Window()->Lock())
		{
			// resend the mouse event to the textinput, if necessary
			BTextView *text = fParent->TextView();
			BPoint screenWhere(ConvertToScreen(where));
			rect = text->Window()->ConvertToScreen(text->Frame());
			if (rect.Contains(screenWhere))
			{
				//printf("  resending mouse down to textinput\n");
				BMessage *msg = new BMessage(*Window()->CurrentMessage());
				msg->RemoveName("be:view_where");
				text->ConvertFromScreen(&screenWhere);
				msg->AddPoint("be:view_where", screenWhere);
				text->Window()->PostMessage(msg, text);
				delete msg;
			}
			fParent->Window()->Unlock();
		}
		
		return;
	}

	rect = Bounds();
	if (!rect.Contains(where))
		return;
	
	fTrackingMouseDown = true;
	// check for double click
	bigtime_t now = system_time();
	bigtime_t clickSpeed;
	get_click_speed(&clickSpeed);
	if ((now - fClickTime < clickSpeed)
		&& ((abs((int)(fClickLoc.x - where.x)) < 3)
		&& (abs((int)(fClickLoc.y - where.y)) < 3)))
	{
		// this is a double click
		// XXX: what to do here?
		printf("BComboBox::ChoiceListView::MouseDown() -- unhandled double click\n");
	}
	fClickTime = now;
	fClickLoc = where;

	float h = LineHeight();
	int32 oldIndex = fSelIndex;
	fSelIndex = (int32)floor(where.y / h);
	int32 choices = fParent->fChoiceList->CountChoices();
	if (fSelIndex < 0 || fSelIndex >= choices)
		fSelIndex = -1;

	if (oldIndex != fSelIndex)
	{
		InvalidateItem(oldIndex);
		InvalidateItem(fSelIndex);
	}
	// XXX: this probably isn't necessary since we are doing a SetEventMask
	// whenever the popup window becomes visible which routes all mouse events
	// to this view
//	SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
}
Beispiel #18
0
void
BListView::MouseDown(BPoint point)
{
	if (!IsFocus()) {
		MakeFocus();
		Sync();
		Window()->UpdateIfNeeded();
	}

	BMessage* message = Looper()->CurrentMessage();
	int32 index = IndexOf(point);

	// If the user double (or more) clicked within the current selection,
	// we don't change the selection but invoke the selection.
	// TODO: move this code someplace where it can be shared everywhere
	// instead of every class having to reimplement it, once some sane
	// API for it is decided.
	BPoint delta = point - fTrack->drag_start;
	bigtime_t sysTime;
	Window()->CurrentMessage()->FindInt64("when", &sysTime);
	bigtime_t timeDelta = sysTime - fTrack->last_click_time;
	bigtime_t doubleClickSpeed;
	get_click_speed(&doubleClickSpeed);
	bool doubleClick = false;

	if (timeDelta < doubleClickSpeed
		&& fabs(delta.x) < kDoubleClickTresh
		&& fabs(delta.y) < kDoubleClickTresh
		&& fTrack->item_index == index) {
		doubleClick = true;
	}

	if (doubleClick && index >= fFirstSelected && index <= fLastSelected) {
		fTrack->drag_start.Set(INT32_MAX, INT32_MAX);
		Invoke();
		return;
	}

	int32 modifiers;
	message->FindInt32("modifiers", &modifiers);

	if (!doubleClick) {
		fTrack->drag_start = point;
		fTrack->last_click_time = system_time();
		fTrack->item_index = index;
		fTrack->was_selected = index >= 0 ? ItemAt(index)->IsSelected() : false;
		fTrack->try_drag = true;
	}

	if (index > -1) {
		if (fListType == B_MULTIPLE_SELECTION_LIST) {
			if (modifiers & B_SHIFT_KEY) {
				// select entire block
				// TODO: maybe review if we want it like in Tracker
				// (anchor item)
				Select(min_c(index, fFirstSelected), max_c(index,
					fLastSelected));
			} else {
				if (modifiers & B_COMMAND_KEY) {
					// toggle selection state of clicked item (like in Tracker)
					// toggle selection state of clicked item
					if (ItemAt(index)->IsSelected())
						Deselect(index);
					else
						Select(index, true);
				} else
					Select(index);
			}
		} else {
			// toggle selection state of clicked item
			if ((modifiers & B_COMMAND_KEY) && ItemAt(index)->IsSelected())
				Deselect(index);
			else
				Select(index);
		}
	} else if ((modifiers & B_COMMAND_KEY) == 0)
		DeselectAll();
}
int32 MouseDragOrPopupWatcher(void* data)
{
	BMessenger* TheMessenger = (BMessenger*)data;
	BPoint StartPos;
	uint32 StartButtons = 0;
	bigtime_t StartTime = 0;
	bool FirstCheck = true;
	BMessage MessageToSend;
	MessageToSend.AddPoint("where",BPoint(0,0));
	MessageToSend.AddInt32("buttons",0);
	MessageToSend.AddInt32("modifiers",0);
	bigtime_t PopupTime;
	if(get_click_speed(&PopupTime) != B_OK)
		return 0;
	PopupTime *= 2;
	while(true)
	{
		if (!TheMessenger->LockTarget())
		{
			delete TheMessenger;
			return 0;			// window is dead so exit
		}
		BLooper *TheLooper;
		BView* TheView = (BView*)TheMessenger->Target(&TheLooper);
		BPoint Where;
		uint32 Buttons;
		bigtime_t Time = system_time();
		TheView->GetMouse(&Where,&Buttons,false);
		if(FirstCheck)
		{
			StartPos = Where;
			StartButtons = Buttons;
			StartTime = Time;
			FirstCheck = false;
		}
		bool Send = false;
		if(Buttons == 0 || Buttons != StartButtons)
		{
			//Changed or released
			MessageToSend.what = MW_MOUSE_CLICK;
			Send = true;
		}
		else if(Where.x < StartPos.x-1.0 || Where.x > StartPos.x+1.0 ||
			Where.y < StartPos.y-1.0 || Where.y > StartPos.y+1.0)
		{
			MessageToSend.what = MW_MOUSE_DRAG;
			Send = true;
		}
		else if(Time >= StartTime + PopupTime)
		{
			MessageToSend.what = MW_MOUSE_POPUP;
			Send = true;
		}
		TheLooper->Unlock();
		if(Send)
		{
			MessageToSend.ReplacePoint("where",StartPos);
			MessageToSend.ReplaceInt32("buttons",Buttons);
			MessageToSend.ReplaceInt32("modifiers",modifiers());
			TheMessenger->SendMessage(&MessageToSend);
			delete TheMessenger;
			return 0;
		}
		snooze(50000);
	}
}