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 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 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 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 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 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 117 PopupSlider::AttachedToWindow() 118 { 119 fSliderButtonRect.OffsetTo(Bounds().right - fSliderButtonRect.Width(), 120 fSliderButtonRect.top); 121 PopupControl::AttachedToWindow(); 122 } 123 124 // Draw 125 void 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 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 171 PopupSlider::PopupShown() 172 { 173 TriggerValueChanged(fPressModel); 174 fTracking = true; 175 } 176 177 // PopupHidden 178 void 179 PopupSlider::PopupHidden(bool canceled) 180 { 181 TriggerValueChanged(fReleaseModel); 182 fTracking = false; 183 } 184 185 // SetValue 186 void 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 207 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 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 233 PopupSlider::IsEnabled() const 234 { 235 return fEnabled; 236 } 237 238 // TriggerValueChanged 239 void 240 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 254 PopupSlider::IsTracking() const 255 { 256 return fTracking; 257 } 258 259 // ValueChanged 260 void 261 PopupSlider::ValueChanged(int32 newValue) 262 { 263 TriggerValueChanged(fModel); 264 } 265 266 // DrawSlider 267 void 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 298 PopupSlider::Scale(float ratio) const 299 { 300 return ratio; 301 } 302 303 // DeScale 304 float 305 PopupSlider::DeScale(float ratio) const 306 { 307 return ratio; 308 } 309 310 // SetMessage 311 void 312 PopupSlider::SetMessage(BMessage* message) 313 { 314 delete fModel; 315 fModel = message; 316 } 317 318 // SetPressedMessage 319 void 320 PopupSlider::SetPressedMessage(BMessage* message) 321 { 322 delete fPressModel; 323 fPressModel = message; 324 } 325 326 // SetReleasedMessage 327 void 328 PopupSlider::SetReleasedMessage(BMessage* message) 329 { 330 delete fReleaseModel; 331 fReleaseModel = message; 332 } 333 334 // SetMin 335 void 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 347 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 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 371 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 384 PopupSlider::SetLabel(const char* label) 385 { 386 fLabel.SetTo(label); 387 Invalidate(); 388 } 389 390 // Label 391 const char* 392 PopupSlider::Label() const 393 { 394 return fLabel.String(); 395 } 396 397 // LabelWidth 398 float 399 PopupSlider::LabelWidth() 400 { 401 return _MinLabelWidth(); 402 } 403 404 // StringForValue 405 const char* 406 PopupSlider::StringForValue(int32 value) 407 { 408 return NULL; 409 } 410 411 // MaxValueStringWidth 412 float 413 PopupSlider::MaxValueStringWidth() 414 { 415 return 0.0; 416 } 417 418 // SetFormatString 419 void 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* 431 PopupSlider::FormatString() const 432 { 433 return fSlider->FormatString(); 434 } 435 436 // _MinLabelWidth 437 float 438 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