1/* 2 * Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>. 3 * All rights reserved. Distributed under the terms of the MIT License. 4 */ 5 6#include "AbstractButton.h" 7 8#include <View.h> 9 10 11// #pragma mark - AbstractButton 12 13 14AbstractButton::AbstractButton(button_policy policy, BMessage* message, 15 BMessenger target) 16 : View(BRect(0, 0, 0, 0)), 17 BInvoker(message, target), 18 fPolicy(policy), 19 fSelected(false), 20 fPressed(false), 21 fPressedInBounds(false) 22{ 23} 24 25 26void 27AbstractButton::SetPolicy(button_policy policy) 28{ 29 fPolicy = policy; 30} 31 32 33button_policy 34AbstractButton::Policy() const 35{ 36 return fPolicy; 37} 38 39 40void 41AbstractButton::SetSelected(bool selected) 42{ 43 if (selected != fSelected) { 44 fSelected = selected; 45 Invalidate(); 46 47 // check whether to notify the listeners depending on the button policy 48 bool notify = false; 49 switch (fPolicy) { 50 case BUTTON_POLICY_TOGGLE_ON_RELEASE: 51 case BUTTON_POLICY_SELECT_ON_RELEASE: 52 // always notify on selection changes 53 notify = true; 54 break; 55 case BUTTON_POLICY_INVOKE_ON_RELEASE: 56 // only notify when the user interaction has been finished 57 notify = !fPressed; 58 break; 59 } 60 61 if (notify) { 62 // notify synchronous listeners 63 _NotifyListeners(); 64 65 // send the message 66 if (Message()) { 67 BMessage message(*Message()); 68 message.AddBool("selected", IsSelected()); 69 InvokeNotify(&message); 70 } 71 } 72 } 73} 74 75 76bool 77AbstractButton::IsSelected() const 78{ 79 return fSelected; 80} 81 82 83void 84AbstractButton::MouseDown(BPoint where, uint32 buttons, int32 modifiers) 85{ 86 if (fPressed) 87 return; 88 89 fPressed = true; 90 _PressedUpdate(where); 91} 92 93 94void 95AbstractButton::MouseUp(BPoint where, uint32 buttons, int32 modifiers) 96{ 97 if (!fPressed || (buttons & B_PRIMARY_MOUSE_BUTTON)) 98 return; 99 100 _PressedUpdate(where); 101 fPressed = false; 102 if (fPressedInBounds) { 103 fPressedInBounds = false; 104 105 // update selected state according to policy 106 bool selected = fSelected; 107 switch (fPolicy) { 108 case BUTTON_POLICY_TOGGLE_ON_RELEASE: 109 selected = !fSelected; 110 break; 111 case BUTTON_POLICY_SELECT_ON_RELEASE: 112 selected = true; 113 break; 114 case BUTTON_POLICY_INVOKE_ON_RELEASE: 115 selected = false; 116 break; 117 } 118 119 SetSelected(selected); 120 } 121 Invalidate(); 122} 123 124 125void 126AbstractButton::MouseMoved(BPoint where, uint32 buttons, int32 modifiers) 127{ 128 if (!fPressed) 129 return; 130 131 _PressedUpdate(where); 132} 133 134 135void 136AbstractButton::AddListener(Listener* listener) 137{ 138 if (listener && !fListeners.HasItem(listener)) 139 fListeners.AddItem(listener); 140} 141 142 143void 144AbstractButton::RemoveListener(Listener* listener) 145{ 146 if (listener) 147 fListeners.RemoveItem(listener); 148} 149 150 151bool 152AbstractButton::IsPressed() const 153{ 154 return (fPressed && fPressedInBounds); 155} 156 157 158void 159AbstractButton::_PressedUpdate(BPoint where) 160{ 161 bool pressedInBounds = Bounds().Contains(where); 162 if (pressedInBounds == fPressedInBounds) 163 return; 164 165 fPressedInBounds = pressedInBounds; 166 167 // update the selected state according to the button policy 168 switch (fPolicy) { 169 case BUTTON_POLICY_TOGGLE_ON_RELEASE: 170 case BUTTON_POLICY_SELECT_ON_RELEASE: 171 // nothing to do 172 break; 173 case BUTTON_POLICY_INVOKE_ON_RELEASE: 174 SetSelected(fPressedInBounds); 175 break; 176 } 177 178 Invalidate(); 179} 180 181 182void 183AbstractButton::_NotifyListeners() 184{ 185 if (!fListeners.IsEmpty()) { 186 BList listeners(fListeners); 187 for (int32 i = 0; Listener* listener = (Listener*)listeners.ItemAt(i); 188 i++) { 189 listener->SelectionChanged(this); 190 } 191 } 192} 193 194 195// #pragma mark - AbstractButton::Listener 196 197 198AbstractButton::Listener::~Listener() 199{ 200} 201 202