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 */ 8 9#include "AlphaSlider.h" 10 11#include <stdio.h> 12 13#include <AppDefs.h> 14#include <Bitmap.h> 15#include <Message.h> 16#include <Window.h> 17 18#include "ui_defines.h" 19#include "support_ui.h" 20 21// constructor 22AlphaSlider::AlphaSlider(orientation dir, BMessage* message) 23 : BControl(dir == B_HORIZONTAL ? BRect(0, 0, 255 + 4, 7 + 4) 24 : BRect(0, 0, 7 + 4, 255 + 4), 25 "alpha slider", NULL, message, 26 27 B_FOLLOW_NONE, 28 B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE), 29 30 fBitmap(NULL), 31 fColor(kBlack), 32 fDragging(false), 33 fOrientation(dir) 34{ 35 FrameResized(Bounds().Width(), Bounds().Height()); 36 37 SetViewColor(B_TRANSPARENT_32_BIT); 38 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 39 40 SetValue(255); 41} 42 43// destructor 44AlphaSlider::~AlphaSlider() 45{ 46 delete fBitmap; 47} 48 49#if LIB_LAYOUT 50// layoutprefs 51minimax 52AlphaSlider::layoutprefs() 53{ 54 mpm.mini.x = 256 + 4; 55 mpm.maxi.x = mpm.mini.x + 10000; 56 mpm.mini.y = 8 + 4; 57 mpm.maxi.y = mpm.mini.y + 10; 58 59 mpm.weight = 1.0; 60 61 return mpm; 62} 63 64// layout 65BRect 66AlphaSlider::layout(BRect frame) 67{ 68 MoveTo(frame.LeftTop()); 69 ResizeTo(frame.Width(), frame.Height()); 70 return Frame(); 71} 72#endif // LIB_LAYOUT 73 74// WindowActivated 75void 76AlphaSlider::WindowActivated(bool active) 77{ 78 if (IsFocus()) 79 Invalidate(); 80} 81 82// MakeFocus 83void 84AlphaSlider::MakeFocus(bool focus) 85{ 86 if (focus != IsFocus()) { 87 BControl::MakeFocus(focus); 88 Invalidate(); 89 } 90} 91 92// MouseDown 93void 94AlphaSlider::MouseDown(BPoint where) 95{ 96 if (!IsEnabled()) 97 return; 98 99// if (!IsFocus()) 100// MakeFocus(true); 101 102 fDragging = true; 103 SetValue(_ValueFor(where)); 104 105 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); 106} 107 108// MouseUp 109void 110AlphaSlider::MouseUp(BPoint where) 111{ 112 fDragging = false; 113} 114 115// MouseMoved 116void 117AlphaSlider::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage) 118{ 119 if (!IsEnabled() || !fDragging) 120 return; 121 122 SetValue(_ValueFor(where)); 123} 124 125// KeyDown 126void 127AlphaSlider::KeyDown(const char* bytes, int32 numBytes) 128{ 129 if (!IsEnabled() || numBytes <= 0) { 130 BControl::KeyDown(bytes, numBytes); 131 return; 132 } 133 134 switch (bytes[0]) { 135 case B_HOME: 136 SetValue(0); 137 break; 138 case B_END: 139 SetValue(255); 140 break; 141 142 case B_LEFT_ARROW: 143 case B_UP_ARROW: 144 SetValue(max_c(0, Value() - 1)); 145 break; 146 case B_RIGHT_ARROW: 147 case B_DOWN_ARROW: 148 SetValue(min_c(255, Value() + 1)); 149 break; 150 151 default: 152 BControl::KeyDown(bytes, numBytes); 153 break; 154 } 155} 156 157// Draw 158void 159AlphaSlider::Draw(BRect updateRect) 160{ 161 BRect b = _BitmapRect(); 162 b.InsetBy(-2.0, -2.0); 163 164 bool isFocus = IsFocus() && Window()->IsActive(); 165 166 rgb_color bg = LowColor(); 167 rgb_color shadow; 168 rgb_color darkShadow; 169 rgb_color light; 170 rgb_color black; 171 172 if (IsEnabled()) { 173 shadow = tint_color(bg, B_DARKEN_1_TINT); 174 darkShadow = tint_color(bg, B_DARKEN_3_TINT); 175 light = tint_color(bg, B_LIGHTEN_MAX_TINT); 176 black = tint_color(bg, B_DARKEN_MAX_TINT); 177 } else { 178 shadow = bg; 179 darkShadow = tint_color(bg, B_DARKEN_1_TINT); 180 light = tint_color(bg, B_LIGHTEN_2_TINT); 181 black = tint_color(bg, B_DARKEN_2_TINT); 182 } 183 184 rgb_color focus = isFocus ? ui_color(B_KEYBOARD_NAVIGATION_COLOR) 185 : black; 186 187 stroke_frame(this, b, shadow, shadow, light, light); 188 b.InsetBy(1.0, 1.0); 189 if (isFocus) 190 stroke_frame(this, b, focus, focus, focus, focus); 191 else 192 stroke_frame(this, b, darkShadow, darkShadow, bg, bg); 193 b.InsetBy(1.0, 1.0); 194 195 DrawBitmap(fBitmap, b.LeftTop()); 196 197 // value marker 198 if (fOrientation == B_HORIZONTAL) { 199 float pos = floorf(b.left + Value() * b.Width() / 255.0 + 0.5); 200 201 if (pos - 2 >= b.left) { 202 SetHighColor(kWhite); 203 StrokeLine(BPoint(pos - 2, b.top), BPoint(pos - 2, b.bottom)); 204 } 205 if (pos - 1 >= b.left) { 206 SetHighColor(kBlack); 207 StrokeLine(BPoint(pos - 1, b.top), BPoint(pos - 1, b.bottom)); 208 } 209 if (pos + 1 <= b.right) { 210 SetHighColor(kBlack); 211 StrokeLine(BPoint(pos + 1, b.top), BPoint(pos + 1, b.bottom)); 212 } 213 if (pos + 2 <= b.right) { 214 SetHighColor(kWhite); 215 StrokeLine(BPoint(pos + 2, b.top), BPoint(pos + 2, b.bottom)); 216 } 217 } else { 218 float pos = floorf(b.top + Value() * b.Height() / 255.0 + 0.5); 219 220 if (pos - 2 >= b.top) { 221 SetHighColor(kWhite); 222 StrokeLine(BPoint(b.left, pos - 2), BPoint(b.right, pos - 2)); 223 } 224 if (pos - 1 >= b.top) { 225 SetHighColor(kBlack); 226 StrokeLine(BPoint(b.left, pos - 1), BPoint(b.right, pos - 1)); 227 } 228 if (pos + 1 <= b.bottom) { 229 SetHighColor(kBlack); 230 StrokeLine(BPoint(b.left, pos + 1), BPoint(b.right, pos + 1)); 231 } 232 if (pos + 2 <= b.bottom) { 233 SetHighColor(kWhite); 234 StrokeLine(BPoint(b.left, pos + 2), BPoint(b.right, pos + 2)); 235 } 236 } 237} 238 239// FrameResized 240void 241AlphaSlider::FrameResized(float width, float height) 242{ 243 BRect r = _BitmapRect(); 244 _AllocBitmap(r.IntegerWidth() + 1, r.IntegerHeight() + 1); 245 _UpdateColors(); 246 Invalidate(); 247 248} 249 250// SetValue 251void 252AlphaSlider::SetValue(int32 value) 253{ 254 if (value == Value()) 255 return; 256 257 Invoke(Message()); 258 BControl::SetValue(value); 259} 260 261// SetEnabled 262void 263AlphaSlider::SetEnabled(bool enabled) 264{ 265 if (enabled == IsEnabled()) 266 return; 267 268 BControl::SetEnabled(enabled); 269 270 _UpdateColors(); 271 Invalidate(); 272} 273 274// #pragma mark - 275 276// SetColor 277void 278AlphaSlider::SetColor(const rgb_color& color) 279{ 280 if ((uint32&)fColor == (uint32&)color) 281 return; 282 283 fColor = color; 284 285 _UpdateColors(); 286 Invalidate(); 287} 288 289// #pragma mark - 290 291// blend_colors 292inline void 293blend_colors(uint8* d, uint8 alpha, uint8 c1, uint8 c2, uint8 c3) 294{ 295 if (alpha > 0) { 296 if (alpha == 255) { 297 d[0] = c1; 298 d[1] = c2; 299 d[2] = c3; 300 } else { 301 d[0] += (uint8)(((c1 - d[0]) * alpha) >> 8); 302 d[1] += (uint8)(((c2 - d[1]) * alpha) >> 8); 303 d[2] += (uint8)(((c3 - d[2]) * alpha) >> 8); 304 } 305 } 306} 307 308// _UpdateColors 309void 310AlphaSlider::_UpdateColors() 311{ 312 if (!fBitmap || !fBitmap->IsValid()) 313 return; 314 315 // fill in top row with alpha gradient 316 uint8* topRow = (uint8*)fBitmap->Bits(); 317 uint32 width = fBitmap->Bounds().IntegerWidth() + 1; 318 319 uint8* p = topRow; 320 rgb_color color = fColor; 321 if (!IsEnabled()) { 322 // blend low color and color to give disabled look 323 rgb_color bg = LowColor(); 324 color.red = (uint8)(((uint32)bg.red + color.red) / 2); 325 color.green = (uint8)(((uint32)bg.green + color.green) / 2); 326 color.blue = (uint8)(((uint32)bg.blue + color.blue) / 2); 327 } 328 for (uint32 x = 0; x < width; x++) { 329 p[0] = color.blue; 330 p[1] = color.green; 331 p[2] = color.red; 332 p[3] = x * 255 / width; 333 p += 4; 334 } 335 // copy top row to rest of bitmap 336 uint32 height = fBitmap->Bounds().IntegerHeight() + 1; 337 uint32 bpr = fBitmap->BytesPerRow(); 338 uint8* dstRow = topRow + bpr; 339 for (uint32 i = 1; i < height; i++) { 340 memcpy(dstRow, topRow, bpr); 341 dstRow += bpr; 342 } 343 // post process bitmap to underlay it with a pattern to visualize alpha 344 uint8* row = topRow; 345 for (uint32 i = 0; i < height; i++) { 346 uint8* p = row; 347 for (uint32 x = 0; x < width; x++) { 348 uint8 alpha = p[3]; 349 if (alpha < 255) { 350 p[3] = 255; 351 alpha = 255 - alpha; 352 if (x % 8 >= 4) { 353 if (i % 8 >= 4) { 354 blend_colors(p, alpha, 355 kAlphaLow.blue, 356 kAlphaLow.green, 357 kAlphaLow.red); 358 } else { 359 blend_colors(p, alpha, 360 kAlphaHigh.blue, 361 kAlphaHigh.green, 362 kAlphaHigh.red); 363 } 364 } else { 365 if (i % 8 >= 4) { 366 blend_colors(p, alpha, 367 kAlphaHigh.blue, 368 kAlphaHigh.green, 369 kAlphaHigh.red); 370 } else { 371 blend_colors(p, alpha, 372 kAlphaLow.blue, 373 kAlphaLow.green, 374 kAlphaLow.red); 375 } 376 } 377 } 378 p += 4; 379 } 380 row += bpr; 381 } 382} 383 384// _AllocBitmap 385void 386AlphaSlider::_AllocBitmap(int32 width, int32 height) 387{ 388 if (width < 2 || height < 2) 389 return; 390 391 delete fBitmap; 392 fBitmap = new BBitmap(BRect(0, 0, width - 1, height - 1), 0, B_RGB32); 393} 394 395// _BitmapRect 396BRect 397AlphaSlider::_BitmapRect() const 398{ 399 BRect r = Bounds(); 400 r.InsetBy(2, 2); 401 return r; 402} 403 404// _ValueFor 405int32 406AlphaSlider::_ValueFor(BPoint where) const 407{ 408 BRect r = _BitmapRect(); 409 410 int32 value; 411 if (fOrientation == B_HORIZONTAL) 412 value = (int32)(255 * (where.x - r.left) / r.Width() + 0.5); 413 else 414 value = (int32)(255 * (where.y - r.top) / r.Height() + 0.5); 415 416 value = max_c(0, value); 417 value = min_c(255, value); 418 419 return value; 420} 421 422