1 // This file is part of VSTGUI. It is subject to the license terms
2 // in the LICENSE file found in the top-level directory of this
3 // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
4 
5 #include "ccontrol.h"
6 #include "icontrollistener.h"
7 #include "../cframe.h"
8 #include "../cgraphicspath.h"
9 #include "../cvstguitimer.h"
10 #include <cassert>
11 
12 #define VSTGUI_CCONTROL_LOG_EDITING 0 //DEBUG
13 
14 namespace VSTGUI {
15 
16 //------------------------------------------------------------------------
17 // CControl
18 //------------------------------------------------------------------------
19 /*! @class CControl
20 This object manages the tag identification and the value of a control object.
21 */
CControl(const CRect & size,IControlListener * listener,int32_t tag,CBitmap * pBackground)22 CControl::CControl (const CRect& size, IControlListener* listener, int32_t tag, CBitmap *pBackground)
23 : CView (size)
24 , listener (listener)
25 , tag (tag)
26 , oldValue (1)
27 , defaultValue (0.5f)
28 , value (0)
29 , vmin (0)
30 , vmax (1.f)
31 , wheelInc (0.1f)
32 , editing (0)
33 {
34 	setTransparency (false);
35 	setMouseEnabled (true);
36 	setBackground (pBackground);
37 }
38 
39 //------------------------------------------------------------------------
CControl(const CControl & c)40 CControl::CControl (const CControl& c)
41 : CView (c)
42 , listener (c.listener)
43 , tag (c.tag)
44 , oldValue (c.oldValue)
45 , defaultValue (c.defaultValue)
46 , value (c.value)
47 , vmin (c.vmin)
48 , vmax (c.vmax)
49 , wheelInc (c.wheelInc)
50 , editing (0)
51 {
52 }
53 
54 //------------------------------------------------------------------------
registerControlListener(IControlListener * subListener)55 void CControl::registerControlListener (IControlListener* subListener)
56 {
57 	vstgui_assert (listener != subListener, "the subListener is already the main listener");
58 	subListeners.add (subListener);
59 }
60 
61 //------------------------------------------------------------------------
unregisterControlListener(IControlListener * subListener)62 void CControl::unregisterControlListener (IControlListener* subListener)
63 {
64 	subListeners.remove (subListener);
65 }
66 
67 //------------------------------------------------------------------------
68 int32_t CControl::kZoomModifier = kShift;
69 int32_t CControl::kDefaultValueModifier = kControl;
70 
71 //------------------------------------------------------------------------
setTag(int32_t val)72 void CControl::setTag (int32_t val)
73 {
74 	if (listener)
75 		listener->controlTagWillChange (this);
76 	tag = val;
77 	if (listener)
78 		listener->controlTagDidChange (this);
79 }
80 
81 //------------------------------------------------------------------------
beginEdit()82 void CControl::beginEdit ()
83 {
84 	// begin of edit parameter
85 	editing++;
86 	if (editing == 1)
87 	{
88 		if (listener)
89 			listener->controlBeginEdit (this);
90 		subListeners.forEach ([this] (IControlListener* l) { l->controlBeginEdit (this); });
91 		if (getFrame ())
92 			getFrame ()->beginEdit (tag);
93 	}
94 #if VSTGUI_CCONTROL_LOG_EDITING
95 	DebugPrint("beginEdit [%d] - %d\n", tag, editing);
96 #endif
97 }
98 
99 //------------------------------------------------------------------------
endEdit()100 void CControl::endEdit ()
101 {
102 	if (!isEditing ())
103 		return;
104 	--editing;
105 	if (editing == 0)
106 	{
107 		if (getFrame ())
108 			getFrame ()->endEdit (tag);
109 		if (listener)
110 			listener->controlEndEdit (this);
111 		subListeners.forEach ([this] (IControlListener* l) { l->controlEndEdit (this); });
112 	}
113 #if VSTGUI_CCONTROL_LOG_EDITING
114 	DebugPrint("endEdit [%d] - %d\n", tag, editing);
115 #endif
116 }
117 
118 //------------------------------------------------------------------------
setValue(float val)119 void CControl::setValue (float val)
120 {
121 	if (val < getMin ())
122 		val = getMin ();
123 	else if (val > getMax ())
124 		val = getMax ();
125 	if (val != value)
126 	{
127 		value = val;
128 	}
129 }
130 
131 //------------------------------------------------------------------------
setValueNormalized(float val)132 void CControl::setValueNormalized (float val)
133 {
134 	if (val > 1.f)
135 		val = 1.f;
136 	else if (val < 0.f)
137 		val = 0.f;
138 	setValue (getRange () * val + getMin ());
139 }
140 
141 //------------------------------------------------------------------------
getValueNormalized() const142 float CControl::getValueNormalized () const
143 {
144 	auto range = getRange ();
145 	if (range == 0.f)
146 		return 0.f;
147 	return (value - getMin ()) / range;
148 }
149 
150 //------------------------------------------------------------------------
valueChanged()151 void CControl::valueChanged ()
152 {
153 	if (listener)
154 		listener->valueChanged (this);
155 	subListeners.forEach ([this] (IControlListener* l) { l->valueChanged (this); });
156 }
157 
158 //------------------------------------------------------------------------
isDirty() const159 bool CControl::isDirty () const
160 {
161 	if (getOldValue () != value || CView::isDirty ())
162 		return true;
163 	return false;
164 }
165 
166 //------------------------------------------------------------------------
setDirty(bool val)167 void CControl::setDirty (bool val)
168 {
169 	CView::setDirty (val);
170 	if (val)
171 	{
172 		if (value != -1.f)
173 			setOldValue (-1.f);
174 		else
175 			setOldValue (0.f);
176 	}
177 	else
178 		setOldValue (value);
179 }
180 
181 //------------------------------------------------------------------------
bounceValue()182 void CControl::bounceValue ()
183 {
184 	if (value > getMax ())
185 		value = getMax ();
186 	else if (value < getMin ())
187 		value = getMin ();
188 }
189 
190 //-----------------------------------------------------------------------------
checkDefaultValue(CButtonState button)191 bool CControl::checkDefaultValue (CButtonState button)
192 {
193 #if TARGET_OS_IPHONE
194 	if (button.isDoubleClick ())
195 #else
196 	if (button.isLeftButton () && button.getModifierState () == kDefaultValueModifier)
197 #endif
198 	{
199 		float defValue = getDefaultValue ();
200 		if (defValue != getValue ())
201 		{
202 			// begin of edit parameter
203 			beginEdit ();
204 
205 			setValue (defValue);
206 			valueChanged ();
207 
208 			// end of edit parameter
209 			endEdit ();
210 
211 			setDirty ();
212 		}
213 		return true;
214 	}
215 	return false;
216 }
217 
218 //------------------------------------------------------------------------
drawFocusOnTop()219 bool CControl::drawFocusOnTop ()
220 {
221 	return false;
222 }
223 
224 //------------------------------------------------------------------------
getFocusPath(CGraphicsPath & outPath)225 bool CControl::getFocusPath (CGraphicsPath& outPath)
226 {
227 	if (wantsFocus ())
228 	{
229 		CCoord focusWidth = getFrame ()->getFocusWidth ();
230 		CRect r (getVisibleViewSize ());
231 		if (!r.isEmpty ())
232 		{
233 			outPath.addRect (r);
234 			r.extend (focusWidth, focusWidth);
235 			outPath.addRect (r);
236 		}
237 	}
238 	return true;
239 }
240 
241 //-----------------------------------------------------------------------------
mapVstKeyModifier(int32_t vstModifier)242 int32_t CControl::mapVstKeyModifier (int32_t vstModifier)
243 {
244 	int32_t modifiers = 0;
245 	if (vstModifier & MODIFIER_SHIFT)
246 		modifiers |= kShift;
247 	if (vstModifier & MODIFIER_ALTERNATE)
248 		modifiers |= kAlt;
249 	if (vstModifier & MODIFIER_COMMAND)
250 		modifiers |= kApple;
251 	if (vstModifier & MODIFIER_CONTROL)
252 		modifiers |= kControl;
253 	return modifiers;
254 }
255 
256 //------------------------------------------------------------------------
257 //------------------------------------------------------------------------
258 //------------------------------------------------------------------------
autoComputeHeightOfOneImage()259 void IMultiBitmapControl::autoComputeHeightOfOneImage ()
260 {
261 	auto* view = dynamic_cast<CView*>(this);
262 	if (view)
263 	{
264 		const CRect& viewSize = view->getViewSize ();
265 		heightOfOneImage = viewSize.getHeight ();
266 	}
267 }
268 
269 //------------------------------------------------------------------------
270 //------------------------------------------------------------------------
271 //------------------------------------------------------------------------
onMouseWheelEditing(CControl * control)272 void CMouseWheelEditingSupport::onMouseWheelEditing (CControl* control)
273 {
274 	if (!control->isEditing ())
275 		control->beginEdit ();
276 	endEditTimer = makeOwned<CVSTGUITimer> (
277 	    [control] (CVSTGUITimer* timer) {
278 		    control->endEdit ();
279 		    timer->stop ();
280 	    },
281 	    500);
282 }
283 
284 //------------------------------------------------------------------------
invalidMouseWheelEditTimer(CControl * control)285 void CMouseWheelEditingSupport::invalidMouseWheelEditTimer (CControl* control)
286 {
287 	if (endEditTimer)
288 		endEditTimer = nullptr;
289 	if (control->isEditing ())
290 		control->endEdit ();
291 }
292 
293 } // VSTGUI
294