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