xref: /haiku/src/apps/icon-o-matic/generic/gui/popup_control/PopupSlider.cpp (revision 128277c969aa806add78941cd2972754c37a1572)
1 /*
2  * Copyright 2006, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stephan Aßmus <superstippi@gmx.de>
7  *		Ingo Weinhold <bonefish@cs.tu-berlin.de>
8  */
9 
10 #include "PopupSlider.h"
11 
12 #include <math.h>
13 #include <stdio.h>
14 
15 #include <Message.h>
16 
17 #include <MDividable.h>
18 #include <MWindow.h>
19 
20 #include "SliderView.h"
21 
22 // constructor
PopupSlider(const char * name,const char * label,BMessage * model,BHandler * target,int32 min,int32 max,int32 value,const char * formatString)23 PopupSlider::PopupSlider(const char* name, const char* label,
24 						 BMessage* model, BHandler* target,
25 						 int32 min, int32 max, int32 value,
26 						 const char* formatString)
27 	: PopupControl(name, fSlider = new SliderView(this, min, max, value,
28 												  formatString)),
29 	  MDividable(),
30 	  fModel(model),
31 	  fPressModel(NULL),
32 	  fReleaseModel(NULL),
33 	  fTarget(target),
34 	  fLabel(label),
35 	  fSliderButtonRect(0.0, 0.0, -1.0, -1.0),
36 	  fEnabled(true),
37 	  fTracking(false)
38 {
39 	SetViewColor(B_TRANSPARENT_32_BIT);
40 }
41 
42 // destructor
~PopupSlider()43 PopupSlider::~PopupSlider()
44 {
45 	delete fModel;
46 	if (BWindow* window = fSlider->Window()) {
47 		window->Lock();
48 		window->RemoveChild(fSlider);
49 		window->Unlock();
50 	}
51 	delete fSlider;
52 }
53 
54 // layoutprefs
55 minimax
layoutprefs()56 PopupSlider::layoutprefs()
57 {
58 	BFont font;
59 	GetFont(&font);
60 	font_height fh;
61 	font.GetHeight(&fh);
62 	float labelHeight = 2.0 + ceilf(fh.ascent + fh.descent) + 2.0;
63 	float sliderWidth, sliderHeight;
64 	SliderView::GetSliderButtonDimensions(Max(), FormatString(), &font,
65 										  sliderWidth, sliderHeight);
66 
67 	float height = labelHeight > sliderHeight + 2.0 ?
68 						labelHeight : sliderHeight + 2.0;
69 
70 	float minLabelWidth = LabelWidth();
71 	if (rolemodel)
72 		labelwidth = rolemodel->LabelWidth();
73 	labelwidth = minLabelWidth > labelwidth ? minLabelWidth : labelwidth;
74 
75 	fSliderButtonRect.left = labelwidth;
76 	fSliderButtonRect.right = fSliderButtonRect.left + sliderWidth + 2.0;
77 	fSliderButtonRect.top = floorf(height / 2.0 - (sliderHeight + 2.0) / 2.0);
78 	fSliderButtonRect.bottom = fSliderButtonRect.top + sliderHeight + 2.0;
79 
80 	fSliderButtonRect.OffsetTo(Bounds().right - fSliderButtonRect.Width(),
81 							   fSliderButtonRect.top);
82 
83 	mpm.mini.x = labelwidth + fSliderButtonRect.Width() + 1.0;
84 	mpm.maxi.x = 10000.0;
85 	mpm.mini.y = mpm.maxi.y = height + 1.0;
86 
87 	mpm.weight = 1.0;
88 
89 	return mpm;
90 }
91 
92 // layout
93 BRect
layout(BRect frame)94 PopupSlider::layout(BRect frame)
95 {
96 	MoveTo(frame.LeftTop());
97 	ResizeTo(frame.Width(), frame.Height());
98 
99 	fSliderButtonRect.OffsetTo(Bounds().right - fSliderButtonRect.Width(),
100 							   fSliderButtonRect.top);
101 	return Frame();
102 }
103 
104 // MessageReceived
105 void
MessageReceived(BMessage * message)106 PopupSlider::MessageReceived(BMessage* message)
107 {
108 	switch (message->what) {
109 		default:
110 			PopupControl::MessageReceived(message);
111 			break;
112 	}
113 }
114 
115 // AttachedToWindow
116 void
AttachedToWindow()117 PopupSlider::AttachedToWindow()
118 {
119 	fSliderButtonRect.OffsetTo(Bounds().right - fSliderButtonRect.Width(),
120 							   fSliderButtonRect.top);
121 	PopupControl::AttachedToWindow();
122 }
123 
124 // Draw
125 void
Draw(BRect updateRect)126 PopupSlider::Draw(BRect updateRect)
127 {
128 	bool enabled = IsEnabled();
129 	rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
130 	rgb_color black;
131 	if (enabled) {
132 		black = tint_color(background, B_DARKEN_MAX_TINT);
133 	} else {
134 		black = tint_color(background, B_DISABLED_LABEL_TINT);
135 	}
136 	// draw label
137 	BRect r(Bounds());
138 	r.right = fSliderButtonRect.left - 1.0;
139 	font_height fh;
140 	GetFontHeight(&fh);
141 	BPoint textPoint(0.0, (r.top + r.bottom) / 2.0 + fh.ascent / 2.0);
142 	SetLowColor(background);
143 	SetHighColor(black);
144 	FillRect(r, B_SOLID_LOW);
145 	DrawString(fLabel.String(), textPoint);
146 	// draw slider button
147 	DrawSlider(fSliderButtonRect, enabled);
148 }
149 
150 // MouseDown
151 void
MouseDown(BPoint where)152 PopupSlider::MouseDown(BPoint where)
153 {
154 	if (fEnabled && fSliderButtonRect.Contains(where) &&
155 		!fSlider->LockLooper()) {
156 
157 		SetPopupLocation(BPoint(fSliderButtonRect.left + 1.0
158 								- fSlider->ButtonOffset(),
159 								-5.0));
160 		where.x -= fSliderButtonRect.left + 1.0;
161 		fSlider->SetDragOffset(where.x);
162 		// just to be on the safe side (avoid a dead lock)
163 		fTracking = true;
164 		ShowPopup(&where);
165 //		fSlider->SetDragOffset(where.x);
166 	}
167 }
168 
169 // PopupShown
170 void
PopupShown()171 PopupSlider::PopupShown()
172 {
173 	TriggerValueChanged(fPressModel);
174 	fTracking = true;
175 }
176 
177 // PopupHidden
178 void
PopupHidden(bool canceled)179 PopupSlider::PopupHidden(bool canceled)
180 {
181 	TriggerValueChanged(fReleaseModel);
182 	fTracking = false;
183 }
184 
185 // SetValue
186 void
SetValue(int32 value)187 PopupSlider::SetValue(int32 value)
188 {
189 	if (!fTracking) {
190 /*		if (fSlider->LockLooper()) {
191 			fSlider->SetValue(value);
192 			fSlider->UnlockLooper();
193 		} else*/
194 		if (value != Value()) {
195 			fSlider->SetValue(value);
196 			if (LockLooperWithTimeout(0) >= B_OK) {
197 				Invalidate();
198 				UnlockLooper();
199 			}
200 		}
201 	} else
202 		ValueChanged(value);
203 }
204 
205 // Value
206 int32
Value() const207 PopupSlider::Value() const
208 {
209 	int32 value = 0;
210 /*	if (fSlider->LockLooper()) {
211 		value = fSlider->Value();
212 		fSlider->UnlockLooper();
213 	} else*/
214 		value = fSlider->Value();
215 	return value;
216 }
217 
218 // SetEnabled
219 void
SetEnabled(bool enable)220 PopupSlider::SetEnabled(bool enable)
221 {
222 	if (enable != fEnabled) {
223 		fEnabled = enable;
224 		if (LockLooper()) {
225 			Invalidate();
226 			UnlockLooper();
227 		}
228 	}
229 }
230 
231 // SetEnabled
232 bool
IsEnabled() const233 PopupSlider::IsEnabled() const
234 {
235 	return fEnabled;
236 }
237 
238 // TriggerValueChanged
239 void
TriggerValueChanged(const BMessage * message) const240 PopupSlider::TriggerValueChanged(const BMessage* message) const
241 {
242 	if (message && fTarget) {
243 		BMessage msg(*message);
244 		msg.AddInt64("be:when", system_time());
245 		msg.AddInt32("be:value", Value());
246 		msg.AddPointer("be:source", (void*)this);
247 		if (BLooper* looper = fTarget->Looper())
248 			looper->PostMessage(&msg, fTarget);
249 	}
250 }
251 
252 // IsTracking
253 bool
IsTracking() const254 PopupSlider::IsTracking() const
255 {
256 	return fTracking;
257 }
258 
259 // ValueChanged
260 void
ValueChanged(int32 newValue)261 PopupSlider::ValueChanged(int32 newValue)
262 {
263 	TriggerValueChanged(fModel);
264 }
265 
266 // DrawSlider
267 void
DrawSlider(BRect frame,bool enabled)268 PopupSlider::DrawSlider(BRect frame, bool enabled)
269 {
270 	rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
271 	rgb_color lightShadow;
272 	rgb_color darkShadow;
273 	if (enabled) {
274 		lightShadow = tint_color(background, B_DARKEN_2_TINT);
275 		darkShadow = tint_color(background, B_DARKEN_4_TINT);
276 	} else {
277 		lightShadow = tint_color(background, B_DARKEN_1_TINT);
278 		darkShadow = tint_color(background, B_DARKEN_2_TINT);
279 	}
280 
281 	BeginLineArray(4);
282 		AddLine(BPoint(frame.left, frame.bottom),
283 				BPoint(frame.left, frame.top), lightShadow);
284 		AddLine(BPoint(frame.left + 1.0, frame.top),
285 				BPoint(frame.right, frame.top), lightShadow);
286 		AddLine(BPoint(frame.right, frame.top + 1.0),
287 				BPoint(frame.right, frame.bottom), darkShadow);
288 		AddLine(BPoint(frame.right - 1.0, frame.bottom),
289 				BPoint(frame.left + 1.0, frame.bottom), darkShadow);
290 	EndLineArray();
291 
292 	frame.InsetBy(1.0, 1.0);
293 	SliderView::DrawSliderButton(this, frame, Value(), FormatString(), enabled);
294 }
295 
296 // Scale
297 float
Scale(float ratio) const298 PopupSlider::Scale(float ratio) const
299 {
300 	return ratio;
301 }
302 
303 // DeScale
304 float
DeScale(float ratio) const305 PopupSlider::DeScale(float ratio) const
306 {
307 	return ratio;
308 }
309 
310 // SetMessage
311 void
SetMessage(BMessage * message)312 PopupSlider::SetMessage(BMessage* message)
313 {
314 	delete fModel;
315 	fModel = message;
316 }
317 
318 // SetPressedMessage
319 void
SetPressedMessage(BMessage * message)320 PopupSlider::SetPressedMessage(BMessage* message)
321 {
322 	delete fPressModel;
323 	fPressModel = message;
324 }
325 
326 // SetReleasedMessage
327 void
SetReleasedMessage(BMessage * message)328 PopupSlider::SetReleasedMessage(BMessage* message)
329 {
330 	delete fReleaseModel;
331 	fReleaseModel = message;
332 }
333 
334 // SetMin
335 void
SetMin(int32 min)336 PopupSlider::SetMin(int32 min)
337 {
338 /*	if (fSlider->LockLooper()) {
339 		fSlider->SetMin(min);
340 		fSlider->UnlockLooper();
341 	} else*/
342 		fSlider->SetMin(min);
343 }
344 
345 // Min
346 int32
Min() const347 PopupSlider::Min() const
348 {
349 	int32 value = 0;
350 /*	if (fSlider->LockLooper()) {
351 		value = fSlider->Min();
352 		fSlider->UnlockLooper();
353 	} else*/
354 		value = fSlider->Min();
355 	return value;
356 }
357 
358 // SetMax
359 void
SetMax(int32 max)360 PopupSlider::SetMax(int32 max)
361 {
362 /*	if (fSlider->LockLooper()) {
363 		fSlider->SetMax(max);
364 		fSlider->UnlockLooper();
365 	} else*/
366 		fSlider->SetMax(max);
367 }
368 
369 // Max
370 int32
Max() const371 PopupSlider::Max() const
372 {
373 	int32 value = 0;
374 /*	if (fSlider->LockLooper()) {
375 		value = fSlider->Max();
376 		fSlider->UnlockLooper();
377 	} else*/
378 		value = fSlider->Max();
379 	return value;
380 }
381 
382 // SetLabel
383 void
SetLabel(const char * label)384 PopupSlider::SetLabel(const char* label)
385 {
386 	fLabel.SetTo(label);
387 	Invalidate();
388 }
389 
390 // Label
391 const char*
Label() const392 PopupSlider::Label() const
393 {
394 	return fLabel.String();
395 }
396 
397 // LabelWidth
398 float
LabelWidth()399 PopupSlider::LabelWidth()
400 {
401 	return _MinLabelWidth();
402 }
403 
404 // StringForValue
405 const char*
StringForValue(int32 value)406 PopupSlider::StringForValue(int32 value)
407 {
408 	return NULL;
409 }
410 
411 // MaxValueStringWidth
412 float
MaxValueStringWidth()413 PopupSlider::MaxValueStringWidth()
414 {
415 	return 0.0;
416 }
417 
418 // SetFormatString
419 void
SetFormatString(const char * formatString)420 PopupSlider::SetFormatString(const char* formatString)
421 {
422 /*	if (fSlider->LockLooper()) {
423 		fSlider->SetFormatString(formatString);
424 		fSlider->UnlockLooper();
425 	} else*/
426 		fSlider->SetFormatString(formatString);
427 }
428 
429 // FormatString
430 const char*
FormatString() const431 PopupSlider::FormatString() const
432 {
433 	return fSlider->FormatString();
434 }
435 
436 // _MinLabelWidth
437 float
_MinLabelWidth() const438 PopupSlider::_MinLabelWidth() const
439 {
440 	return ceilf(StringWidth(fLabel.String())) + 5.0;
441 }
442 
443 /*
444 // StringForValue
445 const char*
446 PercentSlider::StringForValue(int32 value)
447 {
448 	BString string;
449 	string << (value * 100) / Max() << "%";
450 	return
451 }
452 */
453 
454 
455