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 "SliderView.h"
11
12 #include <math.h>
13 #include <stdio.h>
14
15 #include <Message.h>
16 #include <Window.h>
17
18 #include "PopupSlider.h"
19
20 // constructor
SliderView(PopupSlider * target,int32 min,int32 max,int32 value,const char * formatString)21 SliderView::SliderView(PopupSlider* target,
22 int32 min, int32 max, int32 value,
23 const char* formatString)
24 : PopupView("slider"),
25 fTarget(target),
26 fFormatString(formatString),
27 fMin(min),
28 fMax(max),
29 fValue(value),
30 fButtonRect(0.0, 0.0, -1.0, -1.0),
31 fDragOffset(0.0)
32 {
33 SetViewColor(B_TRANSPARENT_32_BIT);
34 if (Max() < Min())
35 SetMax(Min());
36 BFont font;
37 GetFont(&font);
38 float buttonWidth, buttonHeight;
39 GetSliderButtonDimensions(Max(), FormatString(), &font,
40 buttonWidth, buttonHeight);
41
42 fButtonRect.right = fButtonRect.left + buttonWidth;
43 fButtonRect.bottom = fButtonRect.top + buttonHeight;
44 float size = Max() - Min();
45 if (size > 200)
46 size = 200;
47 ResizeTo(6.0 + fButtonRect.Width() + size + 6.0,
48 6.0 + fButtonRect.Height() + 6.0);
49 }
50
51 // destructor
~SliderView()52 SliderView::~SliderView()
53 {
54 }
55
56 // minimax
57 minimax
layoutprefs()58 SliderView::layoutprefs()
59 {
60 mpm.mini.x = mpm.maxi.x = Bounds().Width() + 1.0;
61 mpm.mini.y = mpm.maxi.y = Bounds().Height() + 1.0;
62
63 mpm.weight = 1.0;
64
65 return mpm;
66 }
67
68 // layout
69 BRect
layout(BRect frame)70 SliderView::layout(BRect frame)
71 {
72 MoveTo(frame.LeftTop());
73 ResizeTo(frame.Width(), frame.Height());
74 return Frame();
75 }
76
77 // Draw
78 void
Draw(BRect updateRect)79 SliderView::Draw(BRect updateRect)
80 {
81 fButtonRect.OffsetTo(ButtonOffset(), 6.0);
82
83 rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
84 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
85 rgb_color lightShadow = tint_color(background, B_DARKEN_1_TINT);
86 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
87 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
88
89 BRect r(Bounds());
90 BeginLineArray(24);
91 // outer dark line
92 AddLine(BPoint(r.left, r.bottom),
93 BPoint(r.left, r.top), lightShadow);
94 AddLine(BPoint(r.left + 1.0, r.top),
95 BPoint(r.right, r.top), lightShadow);
96 AddLine(BPoint(r.right, r.top + 1.0),
97 BPoint(r.right, r.bottom), darkShadow);
98 AddLine(BPoint(r.right - 1.0, r.bottom),
99 BPoint(r.left + 1.0, r.bottom), darkShadow);
100 // second line (raised)
101 r.InsetBy(1.0, 1.0);
102 AddLine(BPoint(r.left, r.bottom),
103 BPoint(r.left, r.top), light);
104 AddLine(BPoint(r.left + 1.0, r.top),
105 BPoint(r.right, r.top), light);
106 AddLine(BPoint(r.right, r.top + 1.0),
107 BPoint(r.right, r.bottom), shadow);
108 AddLine(BPoint(r.right - 1.0, r.bottom),
109 BPoint(r.left + 1.0, r.bottom), shadow);
110 // third line (normal)
111 r.InsetBy(1.0, 1.0);
112 AddLine(BPoint(r.left, r.bottom),
113 BPoint(r.left, r.top), background);
114 AddLine(BPoint(r.left + 1.0, r.top),
115 BPoint(r.right, r.top), background);
116 AddLine(BPoint(r.right, r.top + 1.0),
117 BPoint(r.right, r.bottom), background);
118 AddLine(BPoint(r.right - 1.0, r.bottom),
119 BPoint(r.left + 1.0, r.bottom), background);
120 // fourth line (normal)
121 r.InsetBy(1.0, 1.0);
122 AddLine(BPoint(r.left, r.bottom),
123 BPoint(r.left, r.top), background);
124 AddLine(BPoint(r.left + 1.0, r.top),
125 BPoint(r.right, r.top), background);
126 AddLine(BPoint(r.right, r.top + 1.0),
127 BPoint(r.right, r.bottom), background);
128 AddLine(BPoint(r.right - 1.0, r.bottom),
129 BPoint(r.left + 1.0, r.bottom), background);
130 // fifth line (depressed)
131 r.InsetBy(1.0, 1.0);
132 AddLine(BPoint(r.left, r.bottom),
133 BPoint(r.left, r.top), lightShadow);
134 AddLine(BPoint(r.left + 1.0, r.top),
135 BPoint(r.right, r.top), lightShadow);
136 AddLine(BPoint(r.right, r.top + 1.0),
137 BPoint(r.right, r.bottom), light);
138 AddLine(BPoint(r.right - 1.0, r.bottom),
139 BPoint(r.left + 1.0, r.bottom), light);
140 // fifth line (strongly depressed)
141 r.InsetBy(1.0, 1.0);
142 AddLine(BPoint(r.left, r.bottom),
143 BPoint(r.left, r.top), darkShadow);
144 AddLine(BPoint(r.left + 1.0, r.top),
145 BPoint(r.right, r.top), darkShadow);
146 AddLine(BPoint(r.right, r.top + 1.0),
147 BPoint(r.right, r.bottom), shadow);
148 AddLine(BPoint(r.right - 1.0, r.bottom),
149 BPoint(r.left + 1.0, r.bottom), shadow);
150 EndLineArray();
151
152 r.InsetBy(1.0, 1.0);
153 SetLowColor(lightShadow);
154 BRect leftOfButton(r.left + 1.0, r.top + 1.0, fButtonRect.left - 2.0, r.bottom);
155 if (leftOfButton.IsValid())
156 FillRect(leftOfButton, B_SOLID_LOW);
157 BRect rightOfButton(fButtonRect.right + 2.0, r.top + 1.0,
158 r.right, r.bottom);
159 if (rightOfButton.IsValid())
160 FillRect(rightOfButton, B_SOLID_LOW);
161
162 // inner shadow and knob out lines
163 BeginLineArray(5);
164 // shadow
165 AddLine(BPoint(r.left, r.bottom),
166 BPoint(r.left, r.top), shadow);
167 AddLine(BPoint(r.left + 1.0, r.top),
168 BPoint(r.right, r.top), shadow);
169 // at knob
170 if (fButtonRect.left == 6.0)
171 AddLine(BPoint(fButtonRect.left - 1.0, r.top),
172 BPoint(fButtonRect.left - 1.0, r.bottom), darkShadow);
173 else
174 AddLine(BPoint(fButtonRect.left - 1.0, r.top),
175 BPoint(fButtonRect.left - 1.0, r.bottom), shadow);
176 AddLine(BPoint(fButtonRect.left, fButtonRect.bottom + 1.0),
177 BPoint(fButtonRect.right + 1.0, fButtonRect.bottom + 1.0), darkShadow);
178 AddLine(BPoint(fButtonRect.right + 1.0, fButtonRect.bottom),
179 BPoint(fButtonRect.right + 1.0, fButtonRect.top), darkShadow);
180 EndLineArray();
181
182
183 DrawSliderButton(this, fButtonRect, fValue, fFormatString.String(), fTarget->IsEnabled());
184 }
185
186 // MouseUp
187 void
MouseUp(BPoint where)188 SliderView::MouseUp(BPoint where)
189 {
190 PopupDone(false);
191 fTarget->TriggerValueChanged(fTarget->Message());
192 }
193
194 // MouseMoved
195 void
MouseMoved(BPoint where,uint32 transit,const BMessage * message)196 SliderView::MouseMoved(BPoint where, uint32 transit, const BMessage* message)
197 {
198 uint32 buttons = 0;
199 if (BMessage* message = Window()->CurrentMessage()) {
200 if (message->FindInt32("buttons", (int32*)&buttons) < B_OK)
201 buttons = 0;
202 }
203
204 if (buttons == 0) {
205 MouseUp(where);
206 return;
207 }
208
209 SetValue(_ValueAt(where.x - fDragOffset - 6.0));
210 }
211
212 // MessageReceived
213 void
MessageReceived(BMessage * message)214 SliderView::MessageReceived(BMessage* message)
215 {
216 switch (message->what) {
217 default:
218 PopupView::MessageReceived(message);
219 break;
220 }
221 }
222
223 // SetValue
224 void
SetValue(int32 value)225 SliderView::SetValue(int32 value)
226 {
227 if (value < fMin)
228 value = fMin;
229 if (value > fMax)
230 value = fMax;
231 if (value != fValue) {
232 fValue = value;
233 fTarget->SetValue(value);
234 Invalidate();
235 }
236 }
237
238 // Value
239 int32
Value() const240 SliderView::Value() const
241 {
242 return fValue;
243 }
244
245 // SetMin
246 void
SetMin(int32 min)247 SliderView::SetMin(int32 min)
248 {
249 if (min != fMax) {
250 fMin = min;
251 if (fValue < fMin)
252 SetValue(fMin);
253 Invalidate();
254 }
255 }
256
257 // Min
258 int32
Min() const259 SliderView::Min() const
260 {
261 return fMin;
262 }
263
264 // SetMax
265 void
SetMax(int32 max)266 SliderView::SetMax(int32 max)
267 {
268 if (max != fMax) {
269 fMax = max;
270 if (fValue > fMax)
271 SetValue(fMax);
272 Invalidate();
273 }
274 }
275
276 // Max
277 int32
Max() const278 SliderView::Max() const
279 {
280 return fMax;
281 }
282
283 // SetFormatString
284 void
SetFormatString(const char * formatString)285 SliderView::SetFormatString(const char* formatString)
286 {
287 // TODO: check if formatString contains "%ld"
288 fFormatString.SetTo(formatString);
289 }
290
291 // FormatString
292 const char*
FormatString() const293 SliderView::FormatString() const
294 {
295 return fFormatString.String();
296 }
297
298 // SetDragOffset
299 void
SetDragOffset(float offset)300 SliderView::SetDragOffset(float offset)
301 {
302 fDragOffset = offset;
303 }
304
305 // ButtonOffset
306 float
ButtonOffset()307 SliderView::ButtonOffset()
308 {
309 // float range = Bounds().Width() - 12.0 - fButtonRect.Width() + 1.0;
310 // return 6.0 + range / (float)(fMax - fMin + 1) * (float)(fValue - fMin);
311 float ratio = fTarget->DeScale((float)(fValue - fMin) / (float)(fMax - fMin));
312 return 6.0 + ratio * (Bounds().Width() - 12.0 - fButtonRect.Width());
313 }
314
315 // GetSliderButtonDimensions
316 void
GetSliderButtonDimensions(int32 max,const char * formatString,BFont * font,float & width,float & height)317 SliderView::GetSliderButtonDimensions(int32 max, const char* formatString,
318 BFont* font,
319 float& width, float& height)
320 {
321 if (font) {
322 char label[256];
323 sprintf(label, formatString, max);
324 font_height fh;
325 font->GetHeight(&fh);
326 // 4 pixels room on each side,
327 // 1 pixel room at top and bottom
328 width = 5.0 + ceilf(font->StringWidth(label)) + 5.0;
329 height = 2.0 + ceilf(fh.ascent + fh.descent) + 2.0;
330 }
331 }
332
333 // DrawSliderButton
334 void
DrawSliderButton(BView * v,BRect r,int32 value,const char * formatString,bool enabled)335 SliderView::DrawSliderButton(BView* v, BRect r, int32 value,
336 const char* formatString, bool enabled)
337 {
338 rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
339 rgb_color light;
340 rgb_color shadow;
341 rgb_color button;
342 rgb_color black;
343 if (enabled) {
344 light = tint_color(background, B_LIGHTEN_MAX_TINT);
345 shadow = tint_color(background, B_DARKEN_1_TINT);
346 button = tint_color(background, B_LIGHTEN_1_TINT);
347 black = tint_color(background, B_DARKEN_MAX_TINT);
348 } else {
349 light = tint_color(background, B_LIGHTEN_1_TINT);
350 shadow = tint_color(background, 1.1);
351 button = tint_color(background, 0.8);
352 black = tint_color(background, B_DISABLED_LABEL_TINT);
353 }
354 // border
355 v->BeginLineArray(4);
356 v->AddLine(BPoint(r.left, r.bottom),
357 BPoint(r.left, r.top), light);
358 v->AddLine(BPoint(r.left + 1.0, r.top),
359 BPoint(r.right, r.top), light);
360 v->AddLine(BPoint(r.right, r.top + 1.0),
361 BPoint(r.right, r.bottom), shadow);
362 v->AddLine(BPoint(r.right - 1.0, r.bottom),
363 BPoint(r.left + 1.0, r.bottom), shadow);
364 v->EndLineArray();
365 // background & label
366 r.InsetBy(1.0, 1.0);
367 char label[256];
368 sprintf(label, formatString, value);
369 float width = v->StringWidth(label);
370 font_height fh;
371 v->GetFontHeight(&fh);
372 BPoint textPoint((r.left + r.right) / 2.0 - width / 2.0,
373 (r.top + r.bottom) / 2.0 + fh.ascent / 2.0);
374 v->SetHighColor(black);
375 v->SetLowColor(button);
376 v->FillRect(r, B_SOLID_LOW);
377 v->DrawString(label, textPoint);
378 }
379
380 // _ValueAt
381 int32
_ValueAt(float h)382 SliderView::_ValueAt(float h)
383 {
384 /* return fMin + (int32)(((float)(fMax - fMin + 1) * h) /
385 (Bounds().Width() - fButtonRect.Width() - 12.0));*/
386 float ratio = h / (Bounds().Width() - fButtonRect.Width() - 12.0);
387 if (ratio < 0.0)
388 ratio = 0.0;
389 if (ratio > 1.0)
390 ratio = 1.0;
391 ratio = fTarget->Scale(ratio);
392 return fMin + (int32)((fMax - fMin + 1) * ratio);
393 }
394
395
396
397
398