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 23PopupSlider::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 43PopupSlider::~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 55minimax 56PopupSlider::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 93BRect 94PopupSlider::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 105void 106PopupSlider::MessageReceived(BMessage* message) 107{ 108 switch (message->what) { 109 default: 110 PopupControl::MessageReceived(message); 111 break; 112 } 113} 114 115// AttachedToWindow 116void 117PopupSlider::AttachedToWindow() 118{ 119 fSliderButtonRect.OffsetTo(Bounds().right - fSliderButtonRect.Width(), 120 fSliderButtonRect.top); 121 PopupControl::AttachedToWindow(); 122} 123 124// Draw 125void 126PopupSlider::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 151void 152PopupSlider::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 170void 171PopupSlider::PopupShown() 172{ 173 TriggerValueChanged(fPressModel); 174 fTracking = true; 175} 176 177// PopupHidden 178void 179PopupSlider::PopupHidden(bool canceled) 180{ 181 TriggerValueChanged(fReleaseModel); 182 fTracking = false; 183} 184 185// SetValue 186void 187PopupSlider::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 206int32 207PopupSlider::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 219void 220PopupSlider::SetEnabled(bool enable) 221{ 222 if (enable != fEnabled) { 223 fEnabled = enable; 224 if (LockLooper()) { 225 Invalidate(); 226 UnlockLooper(); 227 } 228 } 229} 230 231// SetEnabled 232bool 233PopupSlider::IsEnabled() const 234{ 235 return fEnabled; 236} 237 238// TriggerValueChanged 239void 240PopupSlider::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 253bool 254PopupSlider::IsTracking() const 255{ 256 return fTracking; 257} 258 259// ValueChanged 260void 261PopupSlider::ValueChanged(int32 newValue) 262{ 263 TriggerValueChanged(fModel); 264} 265 266// DrawSlider 267void 268PopupSlider::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 297float 298PopupSlider::Scale(float ratio) const 299{ 300 return ratio; 301} 302 303// DeScale 304float 305PopupSlider::DeScale(float ratio) const 306{ 307 return ratio; 308} 309 310// SetMessage 311void 312PopupSlider::SetMessage(BMessage* message) 313{ 314 delete fModel; 315 fModel = message; 316} 317 318// SetPressedMessage 319void 320PopupSlider::SetPressedMessage(BMessage* message) 321{ 322 delete fPressModel; 323 fPressModel = message; 324} 325 326// SetReleasedMessage 327void 328PopupSlider::SetReleasedMessage(BMessage* message) 329{ 330 delete fReleaseModel; 331 fReleaseModel = message; 332} 333 334// SetMin 335void 336PopupSlider::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 346int32 347PopupSlider::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 359void 360PopupSlider::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 370int32 371PopupSlider::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 383void 384PopupSlider::SetLabel(const char* label) 385{ 386 fLabel.SetTo(label); 387 Invalidate(); 388} 389 390// Label 391const char* 392PopupSlider::Label() const 393{ 394 return fLabel.String(); 395} 396 397// LabelWidth 398float 399PopupSlider::LabelWidth() 400{ 401 return _MinLabelWidth(); 402} 403 404// StringForValue 405const char* 406PopupSlider::StringForValue(int32 value) 407{ 408 return NULL; 409} 410 411// MaxValueStringWidth 412float 413PopupSlider::MaxValueStringWidth() 414{ 415 return 0.0; 416} 417 418// SetFormatString 419void 420PopupSlider::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 430const char* 431PopupSlider::FormatString() const 432{ 433 return fSlider->FormatString(); 434} 435 436// _MinLabelWidth 437float 438PopupSlider::_MinLabelWidth() const 439{ 440 return ceilf(StringWidth(fLabel.String())) + 5.0; 441} 442 443/* 444// StringForValue 445const char* 446PercentSlider::StringForValue(int32 value) 447{ 448 BString string; 449 string << (value * 100) / Max() << "%"; 450 return 451} 452*/ 453 454 455