1/* 2 * Copyright 2001 Werner Freytag - please read to the LICENSE file 3 * 4 * Copyright 2002-2006, Stephan Aßmus <superstippi@gmx.de> 5 * All rights reserved. 6 * 7 */ 8 9#include "ColorField.h" 10 11#include <stdio.h> 12 13#include <Bitmap.h> 14#include <ControlLook.h> 15#include <LayoutUtils.h> 16#include <OS.h> 17#include <Region.h> 18#include <Window.h> 19 20#include "support_ui.h" 21 22#include "rgb_hsv.h" 23 24#define round(x) (int)(x +.5) 25 26enum { 27 MSG_UPDATE = 'Updt', 28}; 29 30#define MAX_X 255 31#define MAX_Y 255 32 33// constructor 34ColorField::ColorField(BPoint offsetPoint, SelectedColorMode mode, 35 float fixedValue, orientation orient, border_style border) 36 : BControl(BRect(0.0, 0.0, MAX_X + 4.0, MAX_Y + 4.0) 37 .OffsetToCopy(offsetPoint), 38 "ColorField", "", new BMessage(MSG_COLOR_FIELD), 39 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_FRAME_EVENTS) 40{ 41 _Init(mode, fixedValue, orient, border); 42 FrameResized(Bounds().Width(), Bounds().Height()); 43} 44 45// constructor 46ColorField::ColorField(SelectedColorMode mode, float fixedValue, 47 orientation orient, border_style border) 48 : BControl("ColorField", "", new BMessage(MSG_COLOR_FIELD), 49 B_WILL_DRAW | B_FRAME_EVENTS) 50{ 51 _Init(mode, fixedValue, orient, border); 52} 53 54// destructor 55ColorField::~ColorField() 56{ 57 delete fBitmap; 58} 59 60// MinSize 61BSize 62ColorField::MinSize() 63{ 64 BSize minSize; 65 if (fOrientation == B_VERTICAL) 66 minSize = BSize(4 + MAX_X / 17, 4 + MAX_Y / 5); 67 else 68 minSize = BSize(4 + MAX_X / 5, 4 + MAX_Y / 17); 69 70 return BLayoutUtils::ComposeSize(ExplicitMinSize(), minSize); 71} 72 73// PreferredSize 74BSize 75ColorField::PreferredSize() 76{ 77 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), MinSize()); 78} 79 80// MaxSize 81BSize 82ColorField::MaxSize() 83{ 84 BSize maxSize(4 + MAX_X, 4 + MAX_Y); 85 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), maxSize); 86// return BLayoutUtils::ComposeSize(ExplicitMaxSize(), 87// BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); 88} 89 90// Invoke 91status_t 92ColorField::Invoke(BMessage* message) 93{ 94 if (message == NULL) 95 message = Message(); 96 97 if (message == NULL) 98 return BControl::Invoke(message); 99 100 message->RemoveName("value"); 101 102 float v1 = 0; 103 float v2 = 0; 104 105 switch (fMode) { 106 case R_SELECTED: 107 case G_SELECTED: 108 case B_SELECTED: 109 v1 = fMarkerPosition.x / Width(); 110 v2 = 1.0 - fMarkerPosition.y / Height(); 111 break; 112 113 case H_SELECTED: 114 if (fOrientation == B_VERTICAL) { 115 v1 = fMarkerPosition.x / Width(); 116 v2 = 1.0 - fMarkerPosition.y / Height(); 117 } else { 118 v1 = fMarkerPosition.y / Height(); 119 v2 = 1.0 - fMarkerPosition.x / Width(); 120 } 121 break; 122 123 case S_SELECTED: 124 case V_SELECTED: 125 v1 = fMarkerPosition.x / Width() * 6.0; 126 v2 = 1.0 - fMarkerPosition.y / Height(); 127 break; 128 129 } 130 131 message->AddFloat("value", v1); 132 message->AddFloat("value", v2); 133 134 return BControl::Invoke(message); 135} 136 137// AttachedToWindow 138void 139ColorField::AttachedToWindow() 140{ 141} 142 143// Draw 144void 145ColorField::Draw(BRect updateRect) 146{ 147 if (fBitmapDirty && fBitmap != NULL) { 148 _FillBitmap(fBitmap, fMode, fFixedValue, fOrientation); 149 fBitmapDirty = false; 150 } 151 152 BRect bounds = Bounds(); 153 154 // Frame 155 if (fBorderStyle == B_FANCY_BORDER) { 156 rgb_color color = LowColor(); 157 be_control_look->DrawTextControlBorder(this, bounds, updateRect, 158 color); 159 BRegion region(bounds); 160 ConstrainClippingRegion(®ion); 161 } 162 163 // Color field fill 164 if (fBitmap != NULL) 165 DrawBitmap(fBitmap, bounds.LeftTop()); 166 else { 167 SetHighColor(255, 0, 0); 168 FillRect(bounds); 169 } 170 171 // Marker 172 SetHighColor(0, 0, 0); 173 StrokeEllipse(fMarkerPosition + bounds.LeftTop(), 5.0, 5.0); 174 SetHighColor(255.0, 255.0, 255.0); 175 StrokeEllipse(fMarkerPosition + bounds.LeftTop(), 4.0, 4.0); 176} 177 178// FrameResized 179void 180ColorField::FrameResized(float width, float height) 181{ 182 BRect r = _BitmapRect(); 183 _AllocBitmap(r.IntegerWidth() + 1, r.IntegerHeight() + 1); 184 Invalidate(); 185} 186 187// MouseDown 188void 189ColorField::MouseDown(BPoint where) 190{ 191 fMouseDown = true; 192 SetMouseEventMask(B_POINTER_EVENTS, 193 B_SUSPEND_VIEW_FOCUS | B_LOCK_WINDOW_FOCUS); 194 PositionMarkerAt(where); 195 196 if (Message() != NULL) { 197 BMessage message(*Message()); 198 message.AddBool("begin", true); 199 Invoke(&message); 200 } else 201 Invoke(); 202} 203 204// MouseUp 205void 206ColorField::MouseUp(BPoint where) 207{ 208 fMouseDown = false; 209} 210 211// MouseMoved 212void 213ColorField::MouseMoved(BPoint where, uint32 transit, 214 const BMessage* dragMessage) 215{ 216 if (dragMessage != NULL || !fMouseDown ) { 217 BView::MouseMoved(where, transit, dragMessage); 218 return; 219 } 220 221 PositionMarkerAt(where); 222 Invoke(); 223} 224 225// SetModeAndValue 226void 227ColorField::SetModeAndValue(SelectedColorMode mode, float fixedValue) 228{ 229 float R(0), G(0), B(0); 230 float H(0), S(0), V(0); 231 232 float width = Width(); 233 float height = Height(); 234 235 switch (fMode) { 236 237 case R_SELECTED: { 238 R = fFixedValue * 255; 239 G = round(fMarkerPosition.x / width * 255.0); 240 B = round(255.0 - fMarkerPosition.y / height * 255.0); 241 }; break; 242 243 case G_SELECTED: { 244 R = round(fMarkerPosition.x / width * 255.0); 245 G = fFixedValue * 255; 246 B = round(255.0 - fMarkerPosition.y / height * 255.0); 247 }; break; 248 249 case B_SELECTED: { 250 R = round(fMarkerPosition.x / width * 255.0); 251 G = round(255.0 - fMarkerPosition.y / height * 255.0); 252 B = fFixedValue * 255; 253 }; break; 254 255 case H_SELECTED: { 256 H = fFixedValue; 257 S = fMarkerPosition.x / width; 258 V = 1.0 - fMarkerPosition.y / height; 259 }; break; 260 261 case S_SELECTED: { 262 H = fMarkerPosition.x / width * 6.0; 263 S = fFixedValue; 264 V = 1.0 - fMarkerPosition.y / height; 265 }; break; 266 267 case V_SELECTED: { 268 H = fMarkerPosition.x / width * 6.0; 269 S = 1.0 - fMarkerPosition.y / height; 270 V = fFixedValue; 271 }; break; 272 } 273 274 if (fMode & (H_SELECTED | S_SELECTED | V_SELECTED)) { 275 HSV_to_RGB(H, S, V, R, G, B); 276 R *= 255.0; G *= 255.0; B *= 255.0; 277 } 278 279 rgb_color color = { (uint8)round(R), (uint8)round(G), (uint8)round(B), 280 255 }; 281 282 if (fFixedValue != fixedValue || fMode != mode) { 283 fFixedValue = fixedValue; 284 fMode = mode; 285 286 _Update(); 287 } 288 289 SetMarkerToColor(color); 290} 291 292// SetFixedValue 293void 294ColorField::SetFixedValue(float fixedValue) 295{ 296 if (fFixedValue != fixedValue) { 297 fFixedValue = fixedValue; 298 _Update(); 299 } 300} 301 302// SetMarkerToColor 303void 304ColorField::SetMarkerToColor(rgb_color color) 305{ 306 float h, s, v; 307 RGB_to_HSV(color.red / 255.0, color.green / 255.0, color.blue / 255.0, 308 h, s, v ); 309 310 fLastMarkerPosition = fMarkerPosition; 311 312 float width = Width(); 313 float height = Height(); 314 315 switch (fMode) { 316 case R_SELECTED: 317 fMarkerPosition = BPoint(color.green / 255.0 * width, 318 (255.0 - color.blue) / 255.0 * height); 319 break; 320 321 case G_SELECTED: 322 fMarkerPosition = BPoint(color.red / 255.0 * width, 323 (255.0 - color.blue) / 255.0 * height); 324 break; 325 326 case B_SELECTED: 327 fMarkerPosition = BPoint(color.red / 255.0 * width, 328 (255.0 - color.green) / 255.0 * height); 329 break; 330 331 case H_SELECTED: 332 if (fOrientation == B_VERTICAL) 333 fMarkerPosition = BPoint(s * width, height - v * height); 334 else 335 fMarkerPosition = BPoint(width - v * width, s * height); 336 break; 337 338 case S_SELECTED: 339 fMarkerPosition = BPoint(h / 6.0 * width, height - v * height); 340 break; 341 342 case V_SELECTED: 343 fMarkerPosition = BPoint( h / 6.0 * width, height - s * height); 344 break; 345 } 346 347 Invalidate(); 348} 349 350// PositionMarkerAt 351void 352ColorField::PositionMarkerAt(BPoint where) 353{ 354 BRect rect = _BitmapRect(); 355 where.ConstrainTo(rect); 356 where -= rect.LeftTop(); 357 358 fLastMarkerPosition = fMarkerPosition; 359 fMarkerPosition = where; 360 Invalidate(); 361} 362 363// Width 364float 365ColorField::Width() const 366{ 367 return _BitmapRect().IntegerWidth() + 1; 368} 369 370// Height 371float 372ColorField::Height() const 373{ 374 return _BitmapRect().IntegerHeight() + 1; 375} 376 377// set_bits 378static inline void 379set_bits(uint8* bits, uint8 r, uint8 g, uint8 b) 380{ 381 bits[0] = b; 382 bits[1] = g; 383 bits[2] = r; 384 bits[3] = 255; 385} 386 387// _Init 388void 389ColorField::_Init(SelectedColorMode mode, float fixedValue, 390 orientation orient, border_style border) 391{ 392 fMode = mode; 393 fFixedValue = fixedValue; 394 fOrientation = orient; 395 fBorderStyle = border; 396 397 fMarkerPosition = BPoint(0.0, 0.0); 398 fLastMarkerPosition = BPoint(-1.0, -1.0); 399 fMouseDown = false; 400 401 fBitmap = NULL; 402 fBitmapDirty = true; 403 404 SetViewColor(B_TRANSPARENT_COLOR); 405 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 406} 407 408// _AllocBitmap 409void 410ColorField::_AllocBitmap(int32 width, int32 height) 411{ 412 if (width < 2 || height < 2) 413 return; 414 415 delete fBitmap; 416 fBitmap = new BBitmap(BRect(0, 0, width - 1, height - 1), 0, B_RGB32); 417 418 fBitmapDirty = true; 419} 420 421// _Update 422void 423ColorField::_Update() 424{ 425 fBitmapDirty = true; 426 Invalidate(); 427} 428 429// _BitmapRect 430BRect 431ColorField::_BitmapRect() const 432{ 433 BRect r = Bounds(); 434 if (fBorderStyle == B_FANCY_BORDER) 435 r.InsetBy(2, 2); 436 return r; 437} 438 439// _FillBitmap 440void 441ColorField::_FillBitmap(BBitmap* bitmap, SelectedColorMode mode, 442 float fixedValue, orientation orient) const 443{ 444 int32 width = bitmap->Bounds().IntegerWidth(); 445 int32 height = bitmap->Bounds().IntegerHeight(); 446 uint32 bpr = bitmap->BytesPerRow(); 447 448//bigtime_t now = system_time(); 449 uint8* bits = (uint8*)bitmap->Bits(); 450 451 float r = 0; 452 float g = 0; 453 float b = 0; 454 float h; 455 float s; 456 float v; 457 458 switch (mode) { 459 case R_SELECTED: 460 r = round(fixedValue * 255); 461 for (int y = height; y >= 0; y--) { 462 uint8* bitsHandle = bits; 463 b = y * 255 / height; 464 for (int32 x = 0; x <= width; x++) { 465 g = x * 255 / width; 466 set_bits(bitsHandle, (uint8)r, (uint8)g, (uint8)b); 467 bitsHandle += 4; 468 } 469 bits += bpr; 470 } 471 break; 472 473 case G_SELECTED: 474 g = round(fixedValue * 255); 475 for (int y = height; y >= 0; y--) { 476 uint8* bitsHandle = bits; 477 b = y * 255 / height; 478 for (int x = 0; x <= width; x++) { 479 r = x * 255 / width; 480 set_bits(bitsHandle, (uint8)r, (uint8)g, (uint8)b); 481 bitsHandle += 4; 482 } 483 bits += bpr; 484 } 485 break; 486 487 case B_SELECTED: 488 b = round(fixedValue * 255); 489 for (int y = height; y >= 0; y--) { 490 uint8* bitsHandle = bits; 491 g = y * 255 / height; 492 for (int x = 0; x <= width; ++x) { 493 r = x * 255 / width; 494 set_bits(bitsHandle, (uint8)r, (uint8)g, (uint8)b); 495 bitsHandle += 4; 496 } 497 bits += bpr; 498 } 499 break; 500 501 case H_SELECTED: 502 h = fixedValue; 503 if (orient == B_VERTICAL) { 504 for (int y = 0; y <= height; ++y) { 505 v = (float)(height - y) / height; 506 uint8* bitsHandle = bits; 507 for (int x = 0; x <= width; ++x) { 508 s = (float)x / width; 509 HSV_to_RGB(h, s, v, r, g, b); 510 set_bits(bitsHandle, 511 round(r * 255.0), 512 round(g * 255.0), 513 round(b * 255.0)); 514 bitsHandle += 4; 515 } 516 bits += bpr; 517 } 518 } else { 519 for (int y = 0; y <= height; ++y) { 520 s = (float)y / height; 521 uint8* bitsHandle = bits; 522 for (int x = 0; x <= width; ++x) { 523 v = (float)(width - x) / width; 524 HSV_to_RGB(h, s, v, r, g, b); 525 set_bits(bitsHandle, 526 round(r * 255.0), 527 round(g * 255.0), 528 round(b * 255.0)); 529 bitsHandle += 4; 530 } 531 bits += bpr; 532 } 533 } 534 break; 535 536 case S_SELECTED: 537 s = fixedValue; 538 for (int y = 0; y <= height; ++y) { 539 v = (float)(height - y) / height; 540 uint8* bitsHandle = bits; 541 for (int x = 0; x <= width; ++x) { 542 h = 6.0 / width * x; 543 HSV_to_RGB(h, s, v, r, g, b); 544 set_bits(bitsHandle, 545 round(r * 255.0), 546 round(g * 255.0), 547 round(b * 255.0)); 548 bitsHandle += 4; 549 } 550 bits += bpr; 551 } 552 break; 553 554 case V_SELECTED: 555 v = fixedValue; 556 for (int y = 0; y <= height; ++y) { 557 s = (float)(height - y) / height; 558 uint8* bitsHandle = bits; 559 for (int x = 0; x <= width; ++x) { 560 h = 6.0 / width * x; 561 HSV_to_RGB(h, s, v, r, g, b); 562 set_bits(bitsHandle, 563 round(r * 255.0), 564 round(g * 255.0), 565 round(b * 255.0)); 566 bitsHandle += 4; 567 } 568 bits += bpr; 569 } 570 break; 571 } 572} 573