/* * Copyright 2007, Ingo Weinhold . * All rights reserved. Distributed under the terms of the MIT License. */ #include "AbstractButton.h" #include // #pragma mark - AbstractButton AbstractButton::AbstractButton(button_policy policy, BMessage* message, BMessenger target) : View(BRect(0, 0, 0, 0)), BInvoker(message, target), fPolicy(policy), fSelected(false), fPressed(false), fPressedInBounds(false) { } void AbstractButton::SetPolicy(button_policy policy) { fPolicy = policy; } button_policy AbstractButton::Policy() const { return fPolicy; } void AbstractButton::SetSelected(bool selected) { if (selected != fSelected) { fSelected = selected; Invalidate(); // check whether to notify the listeners depending on the button policy bool notify = false; switch (fPolicy) { case BUTTON_POLICY_TOGGLE_ON_RELEASE: case BUTTON_POLICY_SELECT_ON_RELEASE: // always notify on selection changes notify = true; break; case BUTTON_POLICY_INVOKE_ON_RELEASE: // only notify when the user interaction has been finished notify = !fPressed; break; } if (notify) { // notify synchronous listeners _NotifyListeners(); // send the message if (Message()) { BMessage message(*Message()); message.AddBool("selected", IsSelected()); InvokeNotify(&message); } } } } bool AbstractButton::IsSelected() const { return fSelected; } void AbstractButton::MouseDown(BPoint where, uint32 buttons, int32 modifiers) { if (fPressed) return; fPressed = true; _PressedUpdate(where); } void AbstractButton::MouseUp(BPoint where, uint32 buttons, int32 modifiers) { if (!fPressed || (buttons & B_PRIMARY_MOUSE_BUTTON)) return; _PressedUpdate(where); fPressed = false; if (fPressedInBounds) { fPressedInBounds = false; // update selected state according to policy bool selected = fSelected; switch (fPolicy) { case BUTTON_POLICY_TOGGLE_ON_RELEASE: selected = !fSelected; break; case BUTTON_POLICY_SELECT_ON_RELEASE: selected = true; break; case BUTTON_POLICY_INVOKE_ON_RELEASE: selected = false; break; } SetSelected(selected); } Invalidate(); } void AbstractButton::MouseMoved(BPoint where, uint32 buttons, int32 modifiers) { if (!fPressed) return; _PressedUpdate(where); } void AbstractButton::AddListener(Listener* listener) { if (listener && !fListeners.HasItem(listener)) fListeners.AddItem(listener); } void AbstractButton::RemoveListener(Listener* listener) { if (listener) fListeners.RemoveItem(listener); } bool AbstractButton::IsPressed() const { return (fPressed && fPressedInBounds); } void AbstractButton::_PressedUpdate(BPoint where) { bool pressedInBounds = Bounds().Contains(where); if (pressedInBounds == fPressedInBounds) return; fPressedInBounds = pressedInBounds; // update the selected state according to the button policy switch (fPolicy) { case BUTTON_POLICY_TOGGLE_ON_RELEASE: case BUTTON_POLICY_SELECT_ON_RELEASE: // nothing to do break; case BUTTON_POLICY_INVOKE_ON_RELEASE: SetSelected(fPressedInBounds); break; } Invalidate(); } void AbstractButton::_NotifyListeners() { if (!fListeners.IsEmpty()) { BList listeners(fListeners); for (int32 i = 0; Listener* listener = (Listener*)listeners.ItemAt(i); i++) { listener->SelectionChanged(this); } } } // #pragma mark - AbstractButton::Listener AbstractButton::Listener::~Listener() { }