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 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 52 SliderView::~SliderView() 53 { 54 } 55 56 // minimax 57 minimax 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 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 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 188 SliderView::MouseUp(BPoint where) 189 { 190 PopupDone(false); 191 fTarget->TriggerValueChanged(fTarget->Message()); 192 } 193 194 // MouseMoved 195 void 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 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 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 240 SliderView::Value() const 241 { 242 return fValue; 243 } 244 245 // SetMin 246 void 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 259 SliderView::Min() const 260 { 261 return fMin; 262 } 263 264 // SetMax 265 void 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 278 SliderView::Max() const 279 { 280 return fMax; 281 } 282 283 // SetFormatString 284 void 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* 293 SliderView::FormatString() const 294 { 295 return fFormatString.String(); 296 } 297 298 // SetDragOffset 299 void 300 SliderView::SetDragOffset(float offset) 301 { 302 fDragOffset = offset; 303 } 304 305 // ButtonOffset 306 float 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 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 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 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