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 14 AbstractButton::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 26 void 27 AbstractButton::SetPolicy(button_policy policy) 28 { 29 fPolicy = policy; 30 } 31 32 33 button_policy 34 AbstractButton::Policy() const 35 { 36 return fPolicy; 37 } 38 39 40 void 41 AbstractButton::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 76 bool 77 AbstractButton::IsSelected() const 78 { 79 return fSelected; 80 } 81 82 83 void 84 AbstractButton::MouseDown(BPoint where, uint32 buttons, int32 modifiers) 85 { 86 if (fPressed) 87 return; 88 89 fPressed = true; 90 _PressedUpdate(where); 91 } 92 93 94 void 95 AbstractButton::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 125 void 126 AbstractButton::MouseMoved(BPoint where, uint32 buttons, int32 modifiers) 127 { 128 if (!fPressed) 129 return; 130 131 _PressedUpdate(where); 132 } 133 134 135 void 136 AbstractButton::AddListener(Listener* listener) 137 { 138 if (listener && !fListeners.HasItem(listener)) 139 fListeners.AddItem(listener); 140 } 141 142 143 void 144 AbstractButton::RemoveListener(Listener* listener) 145 { 146 if (listener) 147 fListeners.RemoveItem(listener); 148 } 149 150 151 bool 152 AbstractButton::IsPressed() const 153 { 154 return (fPressed && fPressedInBounds); 155 } 156 157 158 void 159 AbstractButton::_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 182 void 183 AbstractButton::_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 198 AbstractButton::Listener::~Listener() 199 { 200 } 201 202