* added a color picker panel

(heavily modified, but originally based on Colors! by Werner Freytag)


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17915 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2006-06-23 22:09:53 +00:00
parent d134f89267
commit 31e2089106
19 changed files with 2710 additions and 21 deletions

View File

@ -242,6 +242,7 @@ CanvasView::_AllocBackBitmap(float width, float height)
fOffsreenView->SetFont(&font);
fOffsreenView->SetHighColor(HighColor());
fOffsreenView->SetLowColor(LowColor());
fOffsreenView->SetFlags(Flags());
fOffsreenBitmap->AddChild(fOffsreenView);
} else {
_FreeBackBitmap();

View File

@ -15,6 +15,9 @@
#include "Document.h"
#include "MainWindow.h"
// testing:
#include "ColorPickerPanel.h"
using std::nothrow;
// constructor
@ -68,6 +71,11 @@ IconEditorApp::ReadyToRun()
{
fMainWindow = new MainWindow(this, fDocument);
fMainWindow->Show();
ColorPickerPanel* panel = new ColorPickerPanel(
BRect(80, 80, 200, 200),
(rgb_color){ 100, 200, 150, 255 });
panel->Show();
}

View File

@ -10,6 +10,7 @@ local sourceDirs =
generic/command
generic/gui
generic/gui/panel
generic/gui/panel/color_picker
generic/gui/popup_control
generic/gui/scrollview
generic/gui/stateview
@ -43,6 +44,13 @@ Application Icon-O-Matic :
Selection.cpp
# generic/gui
# generic/gui/panel
Panel.cpp
# generic/gui/panel/color_picker
ColorField.cpp
ColorPickerPanel.cpp
ColorPickerView.cpp
ColorPreview.cpp
ColorSlider.cpp
# generic/gui/popup_control
# generic/gui/scrollview
# generic/gui/stateview
@ -57,6 +65,7 @@ Application Icon-O-Matic :
# generic/support
RWLocker.cpp
support.cpp
support_ui.cpp
# gradient
Gradient.cpp
# shape

View File

@ -0,0 +1,627 @@
/*
* Copyright 2001 Werner Freytag - please read to the LICENSE file
*
* Copyright 2002-2006, Stephan Aßmus <superstippi@gmx.de>
* All rights reserved.
*
*/
#include "ColorField.h"
#include <stdio.h>
#include <Bitmap.h>
#include <OS.h>
#include <Region.h>
#include <Window.h>
#include "selected_color_mode.h"
#include "support_ui.h"
#include "rgb_hsv.h"
#define round(x) (int)(x+.5)
enum {
MSG_UPDATE = 'Updt',
};
#define MAX_X 255
#define MAX_Y 255
// constructor
ColorField::ColorField(BPoint offset_point, selected_color_mode mode,
float fixed_value, orientation orient)
: BControl(BRect(0.0, 0.0, MAX_X + 4.0, MAX_Y + 4.0).OffsetToCopy(offset_point),
"ColorField", "", new BMessage(MSG_COLOR_FIELD),
B_FOLLOW_LEFT | B_FOLLOW_TOP,
B_WILL_DRAW | B_FRAME_EVENTS),
fMode(mode),
fFixedValue(fixed_value),
fOrientation(orient),
fMarkerPosition(0.0, 0.0),
fLastMarkerPosition(-1.0, -1.0),
fMouseDown(false),
fUpdateThread(B_ERROR),
fUpdatePort(B_ERROR)
{
SetViewColor(B_TRANSPARENT_32_BIT);
for (int i = 0; i < 2; ++i) {
fBgBitmap[i] = new BBitmap(Bounds(), B_RGB32, true);
fBgBitmap[i]->Lock();
fBgView[i] = new BView(Bounds(), "", B_FOLLOW_NONE, B_WILL_DRAW);
fBgBitmap[i]->AddChild(fBgView[i]);
fBgView[i]->SetOrigin(2.0, 2.0);
fBgBitmap[i]->Unlock();
}
_DrawBorder();
fUpdatePort = create_port(100, "color field update port");
fUpdateThread = spawn_thread(ColorField::_UpdateThread,
"color field update thread", 10, this);
resume_thread(fUpdateThread);
// Update(3);
}
// destructor
ColorField::~ColorField()
{
if (fUpdatePort >= B_OK)
delete_port(fUpdatePort);
if (fUpdateThread >= B_OK)
kill_thread(fUpdateThread);
delete fBgBitmap[0];
delete fBgBitmap[1];
}
#if LIB_LAYOUT
// layoutprefs
minimax
ColorField::layoutprefs()
{
if (fOrientation == B_VERTICAL) {
mpm.mini.x = 4 + MAX_X / 17;
mpm.mini.y = 4 + MAX_Y / 5;
} else {
mpm.mini.x = 4 + MAX_X / 5;
mpm.mini.y = 4 + MAX_Y / 17;
}
mpm.maxi.x = 4 + MAX_X;
mpm.maxi.y = 4 + MAX_Y;
mpm.weight = 1.0;
return mpm;
}
// layout
BRect
ColorField::layout(BRect frame)
{
MoveTo(frame.LeftTop());
// reposition marker
fMarkerPosition.x *= (frame.Width() - 4.0) / (Bounds().Width() - 4.0);
fMarkerPosition.y *= (frame.Height() - 4.0) / (Bounds().Height() - 4.0);
ResizeTo(frame.Width(), frame.Height());
_DrawBorder();
Update(3);
return Frame();
}
#endif // LIB_LAYOUT
// Invoke
status_t
ColorField::Invoke(BMessage *msg)
{
if (!msg)
msg = Message();
msg->RemoveName("value");
float v1 = 0;
float v2 = 0;
switch (fMode) {
case R_SELECTED:
case G_SELECTED:
case B_SELECTED:
v1 = fMarkerPosition.x / Width();
v2 = 1.0 - fMarkerPosition.y / Height();
break;
case H_SELECTED:
if (fOrientation == B_VERTICAL) {
v1 = fMarkerPosition.x / Width();
v2 = 1.0 - fMarkerPosition.y / Height();
} else {
v1 = fMarkerPosition.y / Height();
v2 = 1.0 - fMarkerPosition.x / Width();
}
break;
case S_SELECTED:
case V_SELECTED:
v1 = fMarkerPosition.x / Width() * 6.0;
v2 = 1.0 - fMarkerPosition.y / Height();
break;
}
msg->AddFloat("value", v1);
msg->AddFloat("value", v2);
return BControl::Invoke(msg);
}
// AttachedToWindow
void
ColorField::AttachedToWindow()
{
Update(3);
}
// Draw
void
ColorField::Draw(BRect updateRect)
{
Update(0);
}
// MouseDown
void
ColorField::MouseDown(BPoint where)
{
Window()->Activate();
fMouseDown = true;
SetMouseEventMask(B_POINTER_EVENTS, B_SUSPEND_VIEW_FOCUS|B_LOCK_WINDOW_FOCUS );
PositionMarkerAt( where );
if (Message()) {
BMessage message(*Message());
message.AddBool("begin", true);
Invoke(&message);
} else
Invoke();
}
// MouseUp
void
ColorField::MouseUp(BPoint where)
{
fMouseDown = false;
}
// MouseMoved
void
ColorField::MouseMoved(BPoint where, uint32 code, const BMessage *a_message)
{
if (a_message || !fMouseDown ) {
BView::MouseMoved( where, code, a_message);
return;
}
PositionMarkerAt(where);
Invoke();
}
// Update
void
ColorField::Update(int depth)
{
// depth: 0 = only onscreen redraw, 1 = only cursor 1, 2 = full update part 2, 3 = full
if (depth == 3) {
write_port(fUpdatePort, MSG_UPDATE, NULL, 0);
return;
}
if (depth >= 1) {
fBgBitmap[1]->Lock();
fBgView[1]->DrawBitmap( fBgBitmap[0], BPoint(-2.0, -2.0) );
fBgView[1]->SetHighColor( 0, 0, 0 );
fBgView[1]->StrokeEllipse( fMarkerPosition, 5.0, 5.0 );
fBgView[1]->SetHighColor( 255.0, 255.0, 255.0 );
fBgView[1]->StrokeEllipse( fMarkerPosition, 4.0, 4.0 );
fBgView[1]->Sync();
fBgBitmap[1]->Unlock();
}
if (depth != 0 && depth != 2 && fMarkerPosition != fLastMarkerPosition) {
fBgBitmap[1]->Lock();
DrawBitmap( fBgBitmap[1],
BRect(-3.0, -3.0, 7.0, 7.0).OffsetByCopy(fMarkerPosition),
BRect(-3.0, -3.0, 7.0, 7.0).OffsetByCopy(fMarkerPosition));
DrawBitmap( fBgBitmap[1],
BRect(-3.0, -3.0, 7.0, 7.0).OffsetByCopy(fLastMarkerPosition),
BRect(-3.0, -3.0, 7.0, 7.0).OffsetByCopy(fLastMarkerPosition));
fLastMarkerPosition = fMarkerPosition;
fBgBitmap[1]->Unlock();
} else
DrawBitmap(fBgBitmap[1]);
}
// SetModeAndValue
void
ColorField::SetModeAndValue(selected_color_mode mode, float fixed_value)
{
float R(0), G(0), B(0);
float H(0), S(0), V(0);
fBgBitmap[0]->Lock();
float width = Width();
float height = Height();
switch (fMode) {
case R_SELECTED: {
R = fFixedValue * 255;
G = round(fMarkerPosition.x / width * 255.0);
B = round(255.0 - fMarkerPosition.y / height * 255.0);
}; break;
case G_SELECTED: {
R = round(fMarkerPosition.x / width * 255.0);
G = fFixedValue * 255;
B = round(255.0 - fMarkerPosition.y / height * 255.0);
}; break;
case B_SELECTED: {
R = round(fMarkerPosition.x / width * 255.0);
G = round(255.0 - fMarkerPosition.y / height * 255.0);
B = fFixedValue * 255;
}; break;
case H_SELECTED: {
H = fFixedValue;
S = fMarkerPosition.x / width;
V = 1.0 - fMarkerPosition.y / height;
}; break;
case S_SELECTED: {
H = fMarkerPosition.x / width * 6.0;
S = fFixedValue;
V = 1.0 - fMarkerPosition.y / height;
}; break;
case V_SELECTED: {
H = fMarkerPosition.x / width * 6.0;
S = 1.0 - fMarkerPosition.y / height;
V = fFixedValue;
}; break;
}
if (fMode & (H_SELECTED | S_SELECTED | V_SELECTED)) {
HSV_to_RGB(H, S, V, R, G, B);
R *= 255.0; G *= 255.0; B *= 255.0;
}
rgb_color color = { round(R), round(G), round(B), 255 };
fBgBitmap[0]->Unlock();
if (fFixedValue != fixed_value || fMode != mode) {
fFixedValue = fixed_value;
fMode = mode;
Update(3);
}
SetMarkerToColor(color);
}
// SetFixedValue
void
ColorField::SetFixedValue(float fixed_value)
{
if (fFixedValue != fixed_value) {
fFixedValue = fixed_value;
Update(3);
}
}
// SetMarkerToColor
void
ColorField::SetMarkerToColor(rgb_color color)
{
float h, s, v;
RGB_to_HSV( (float)color.red / 255.0, (float)color.green / 255.0, (float)color.blue / 255.0, h, s, v );
fLastMarkerPosition = fMarkerPosition;
float width = Width();
float height = Height();
switch (fMode) {
case R_SELECTED: {
fMarkerPosition = BPoint(color.green / 255.0 * width,
(255.0 - color.blue) / 255.0 * height);
} break;
case G_SELECTED: {
fMarkerPosition = BPoint(color.red / 255.0 * width,
(255.0 - color.blue) / 255.0 * height);
} break;
case B_SELECTED: {
fMarkerPosition = BPoint(color.red / 255.0 * width,
(255.0 - color.green) / 255.0 * height);
} break;
case H_SELECTED: {
if (fOrientation == B_VERTICAL)
fMarkerPosition = BPoint(s * width, height - v * height);
else
fMarkerPosition = BPoint(width - v * width, s * height);
} break;
case S_SELECTED: {
fMarkerPosition = BPoint(h / 6.0 * width, height - v * height);
} break;
case V_SELECTED: {
fMarkerPosition = BPoint( h / 6.0 * width, height - s * height);
} break;
}
Update(1);
}
// PositionMarkerAt
void
ColorField::PositionMarkerAt( BPoint where )
{
BRect rect = Bounds().InsetByCopy( 2.0, 2.0 ).OffsetToCopy(0.0, 0.0);
where = BPoint(max_c(min_c(where.x - 2.0, rect.right), 0.0),
max_c(min_c(where.y - 2.0, rect.bottom), 0.0) );
fLastMarkerPosition = fMarkerPosition;
fMarkerPosition = where;
Update(1);
}
// Width
float
ColorField::Width() const
{
return Bounds().IntegerWidth() + 1 - 4;
}
// Height
float
ColorField::Height() const
{
return Bounds().IntegerHeight() + 1 - 4;
}
// set_bits
void
set_bits(uint8* bits, uint8 r, uint8 g, uint8 b)
{
bits[0] = b;
bits[1] = g;
bits[2] = r;
// bits[3] = 255;
}
// _UpdateThread
int32
ColorField::_UpdateThread(void* data)
{
// initializing
ColorField* colorField = (ColorField *)data;
bool looperLocked = colorField->LockLooper();
BBitmap* bitmap = colorField->fBgBitmap[0];
port_id port = colorField->fUpdatePort;
orientation orient = colorField->fOrientation;
if (looperLocked)
colorField->UnlockLooper();
float h, s, v, r, g, b;
int R, G, B;
// drawing
int32 msg_code;
char msg_buffer;
while (true) {
port_info info;
do {
read_port(port, &msg_code, &msg_buffer, sizeof(msg_buffer));
get_port_info(port, &info);
} while (info.queue_count);
if (colorField->LockLooper()) {
uint colormode = colorField->fMode;
float fixedvalue = colorField->fFixedValue;
int width = (int)colorField->Width();
int height = (int)colorField->Height();
colorField->UnlockLooper();
bitmap->Lock();
//bigtime_t now = system_time();
uint8* bits = (uint8*)bitmap->Bits();
uint32 bpr = bitmap->BytesPerRow();
// offset 2 pixels from top and left
bits += 2 * 4 + 2 * bpr;
switch (colormode) {
case R_SELECTED: {
R = round(fixedvalue * 255);
for (int y = height; y >= 0; y--) {
uint8* bitsHandle = bits;
int B = y / height * 255;
for (int x = 0; x <= width; ++x) {
int G = x / width * 255;
set_bits(bitsHandle, R, G, B);
bitsHandle += 4;
}
bits += bpr;
}
}; break;
case G_SELECTED: {
G = round(fixedvalue * 255);
for (int y = height; y >= 0; y--) {
uint8* bitsHandle = bits;
int B = y / height * 255;
for (int x = 0; x <= width; ++x) {
int R = x / width * 255;
set_bits(bitsHandle, R, G, B);
bitsHandle += 4;
}
bits += bpr;
}
}; break;
case B_SELECTED: {
B = round(fixedvalue * 255);
for (int y = height; y >= 0; y--) {
uint8* bitsHandle = bits;
int G = y / height * 255;
for (int x = 0; x <= width; ++x) {
int R = x / width * 255;
set_bits(bitsHandle, R, G, B);
bitsHandle += 4;
}
bits += bpr;
}
}; break;
case H_SELECTED: {
h = fixedvalue;
if (orient == B_VERTICAL) {
for (int y = 0; y <= height; ++y) {
v = (float)(height - y) / height;
uint8* bitsHandle = bits;
for (int x = 0; x <= width; ++x) {
s = (float)x / width;
HSV_to_RGB( h, s, v, r, g, b );
set_bits(bitsHandle, round(r * 255.0), round(g * 255.0), round(b * 255.0));
bitsHandle += 4;
}
bits += bpr;
}
} else {
for (int y = 0; y <= height; ++y) {
s = (float)y / height;
uint8* bitsHandle = bits;
for (int x = 0; x <= width; ++x) {
v = (float)(width - x) / width;
HSV_to_RGB( h, s, v, r, g, b );
set_bits(bitsHandle, round(r * 255.0), round(g * 255.0), round(b * 255.0));
bitsHandle += 4;
}
bits += bpr;
}
}
}; break;
case S_SELECTED: {
s = fixedvalue;
for (int y = 0; y <= height; ++y) {
v = (float)(height - y) / height;
uint8* bitsHandle = bits;
for (int x = 0; x <= width; ++x) {
h = 6.0 / width * x;
HSV_to_RGB( h, s, v, r, g, b );
set_bits(bitsHandle, round(r * 255.0), round(g * 255.0), round(b * 255.0));
bitsHandle += 4;
}
bits += bpr;
}
}; break;
case V_SELECTED: {
v = fixedvalue;
for (int y = 0; y <= height; ++y) {
s = (float)(height - y) / height;
uint8* bitsHandle = bits;
for (int x = 0; x <= width; ++x) {
h = 6.0 / width * x;
HSV_to_RGB( h, s, v, r, g, b );
set_bits(bitsHandle, round(r * 255.0), round(g * 255.0), round(b * 255.0));
bitsHandle += 4;
}
bits += bpr;
}
}; break;
}
//printf("color field update: %lld\n", system_time() - now);
bitmap->Unlock();
if (colorField->LockLooper()) {
colorField->Update(2);
colorField->UnlockLooper();
}
}
}
}
// _DrawBorder
void
ColorField::_DrawBorder()
{
bool looperLocked = LockLooper();
fBgBitmap[1]->Lock();
rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
rgb_color shadow = tint_color(background, B_DARKEN_1_TINT);
rgb_color darkShadow = tint_color(background, B_DARKEN_3_TINT);
rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
BRect r(fBgView[1]->Bounds());
r.OffsetBy(-2.0, -2.0);
BRegion region(r);
fBgView[1]->ConstrainClippingRegion(&region);
r = Bounds();
r.OffsetBy(-2.0, -2.0);
stroke_frame(fBgView[1], r, shadow, shadow, light, light);
r.InsetBy(1.0, 1.0);
stroke_frame(fBgView[1], r, darkShadow, darkShadow, background, background);
r.InsetBy(1.0, 1.0);
region.Set(r);
fBgView[1]->ConstrainClippingRegion(&region);
fBgBitmap[1]->Unlock();
if (looperLocked)
UnlockLooper();
}

View File

@ -0,0 +1,93 @@
/*
* Copyright 2001 Werner Freytag - please read to the LICENSE file
*
* Copyright 2002-2006, Stephan Aßmus <superstippi@gmx.de>
* All rights reserved.
*
*/
#ifndef _COLOR_FIELD_H
#define _COLOR_FIELD_H
#include "ColorPickerDefs.h"
#include <Control.h>
#if LIB_LAYOUT
# include <layout.h>
#endif
#include "selected_color_mode.h"
enum {
MSG_COLOR_FIELD = 'ColF',
};
class BBitmap;
class ColorField :
#if LIB_LAYOUT
public MView,
#endif
public BControl {
public:
ColorField(BPoint offset_point,
selected_color_mode mode,
float fixed_value,
orientation orient = B_VERTICAL);
virtual ~ColorField();
// MView
#if LIB_LAYOUT
virtual minimax layoutprefs();
virtual BRect layout(BRect frame);
#endif
// BControl
virtual status_t Invoke(BMessage *msg = NULL);
virtual void AttachedToWindow();
virtual void Draw(BRect updateRect);
virtual void MouseDown(BPoint where);
virtual void MouseUp(BPoint where);
virtual void MouseMoved(BPoint where, uint32 code,
const BMessage* message);
// ColorField
void Update(int depth);
void SetModeAndValue(selected_color_mode mode, float fixed_value);
void SetFixedValue(float fixed_value);
float FixedValue() const
{ return fFixedValue; }
void SetMarkerToColor( rgb_color color );
void PositionMarkerAt( BPoint where );
float Width() const;
float Height() const;
bool IsTracking() const
{ return fMouseDown; }
private:
static int32 _UpdateThread(void* data);
void _DrawBorder();
selected_color_mode fMode;
float fFixedValue;
orientation fOrientation;
BPoint fMarkerPosition;
BPoint fLastMarkerPosition;
bool fMouseDown;
BBitmap* fBgBitmap[2];
BView* fBgView[2];
thread_id fUpdateThread;
port_id fUpdatePort;
};
#endif

View File

@ -0,0 +1,6 @@
#ifndef COLOR_PICKER_COMMON_H
#define COLOR_PICKER_COMMON_H
#define LIB_LAYOUT 0
#endif // COLOR_PICKER_COMMON_H

View File

@ -0,0 +1,164 @@
/*
* Copyright 2002-2006, Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT license.
*
*/
#include "ColorPickerPanel.h"
#include <stdio.h>
#include <Application.h>
#include "ColorPickerDefs.h"
#if LIB_LAYOUT
# include <MBorder.h>
# include <HGroup.h>
# include <Space.h>
# include <MButton.h>
# include <VGroup.h>
#else
# include <Box.h>
# include <Button.h>
#endif
#include "support_ui.h"
#include "ColorPickerView.h"
enum {
MSG_CANCEL = 'cncl',
MSG_DONE = 'done',
};
// constructor
ColorPickerPanel::ColorPickerPanel(BRect frame, rgb_color color,
selected_color_mode mode,
BMessage* message, BWindow* target)
: Panel(frame, "Pick Color",
B_FLOATING_WINDOW_LOOK, B_FLOATING_SUBSET_WINDOW_FEEL,
B_ASYNCHRONOUS_CONTROLS |
B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_NOT_CLOSABLE),
fMessage(message),
fTarget(target)
{
SetTitle("Pick Color");
fColorPickerView = new ColorPickerView("color picker", color, mode);
#if LIB_LAYOUT
MButton* defaultButton = new MButton("Ok", new BMessage(MSG_DONE), this);
// interface layout
BView* topView = new VGroup (
fColorPickerView,
new MBorder (
M_RAISED_BORDER, 5, "buttons",
new HGroup (
new Space(minimax(0.0, 0.0, 10000.0, 10000.0, 5.0)),
new MButton("Cancel", new BMessage(MSG_CANCEL), this),
new Space(minimax(5.0, 0.0, 10.0, 10000.0, 1.0)),
defaultButton,
new Space(minimax(2.0, 0.0, 2.0, 10000.0, 0.0)),
0
)
),
0
);
#else // LIB_LAYOUT
frame = BRect(0, 0, 40, 15);
BButton* defaultButton = new BButton(frame, "ok button", "Ok",
new BMessage(MSG_DONE),
B_FOLLOW_RIGHT | B_FOLLOW_TOP);
defaultButton->ResizeToPreferred();
BButton* cancelButton = new BButton(frame, "cancel button", "Cancel",
new BMessage(MSG_CANCEL),
B_FOLLOW_RIGHT | B_FOLLOW_TOP);
cancelButton->ResizeToPreferred();
frame.bottom = frame.top + (defaultButton->Frame().Height() + 16);
frame.right = frame.left + fColorPickerView->Frame().Width();
BBox* buttonBox = new BBox(frame, "button group",
B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM,
B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP,
B_PLAIN_BORDER);
ResizeTo(frame.Width(),
fColorPickerView->Frame().Height() + frame.Height() + 1);
frame = Bounds();
BView* topView = new BView(frame, "bg", B_FOLLOW_ALL, 0);
topView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
buttonBox->MoveTo(frame.left, frame.bottom - buttonBox->Frame().Height());
defaultButton->MoveTo(frame.right - defaultButton->Frame().Width() - 10,
frame.top + 8);
buttonBox->AddChild(defaultButton);
cancelButton->MoveTo(defaultButton->Frame().left - 10
- cancelButton->Frame().Width(),
frame.top + 8);
buttonBox->AddChild(cancelButton);
topView->AddChild(fColorPickerView);
topView->AddChild(buttonBox);
#endif // LIB_LAYOUT
SetDefaultButton(defaultButton);
if (fTarget)
AddToSubset(fTarget);
else
SetFeel(B_FLOATING_APP_WINDOW_FEEL);
AddChild(topView);
}
// destructor
ColorPickerPanel::~ColorPickerPanel()
{
delete fMessage;
}
// Cancel
void
ColorPickerPanel::Cancel()
{
PostMessage(MSG_CANCEL);
}
// MessageReceived
void
ColorPickerPanel::MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_CANCEL:
case MSG_DONE: {
BMessage msg('PSTE');
BLooper* looper = fTarget ? static_cast<BLooper*>(fTarget)
: static_cast<BLooper*>(be_app);
if (fMessage)
msg = *fMessage;
if (message->what == MSG_DONE)
store_color_in_message(&msg, fColorPickerView->Color());
msg.AddRect("panel frame", Frame());
msg.AddInt32("panel mode", fColorPickerView->Mode());
msg.AddBool("begin", true);
looper->PostMessage(&msg);
PostMessage(B_QUIT_REQUESTED);
break;
}
default:
Panel::MessageReceived(message);
break;
}
}
// SetColor
void
ColorPickerPanel::SetColor(rgb_color color)
{
fColorPickerView->SetColor(color);
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2002-2006, Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT license.
*
*/
#ifndef COLOR_PICKER_PANEL_H
#define COLOR_PICKER_PANEL_H
#include "Panel.h"
#include "selected_color_mode.h"
class ColorPickerView;
class ColorPickerPanel : public Panel {
public:
ColorPickerPanel(BRect frame,
rgb_color color,
selected_color_mode mode
= H_SELECTED,
BMessage* message = NULL,
BWindow* target = NULL);
virtual ~ColorPickerPanel();
// Panel
virtual void Cancel();
virtual void MessageReceived(BMessage* message);
void SetColor(rgb_color color);
private:
ColorPickerView* fColorPickerView;
BMessage* fMessage;
BWindow* fTarget;
};
#endif // COLOR_PICKER_PANEL_H

View File

@ -0,0 +1,504 @@
/*
* Copyright 2001 Werner Freytag - please read to the LICENSE file
*
* Copyright 2002-2006, Stephan Aßmus <superstippi@gmx.de>
* All rights reserved.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Application.h>
#include <Bitmap.h>
#include <Beep.h>
#include <Font.h>
#include <Message.h>
#include <RadioButton.h>
#include <Screen.h>
#include <TextControl.h>
#include <Window.h>
#include "ColorField.h"
#include "ColorPreview.h"
#include "ColorSlider.h"
#include "rgb_hsv.h"
#include "ColorPickerView.h"
#define round(x) (int)(x+.5)
#define hexdec(str, offset) (int)(((str[offset]<60?str[offset]-48:(str[offset]|32)-87)<<4)|(str[offset+1]<60?str[offset+1]-48:(str[offset+1]|32)-87))
// constructor
ColorPickerView::ColorPickerView(const char* name, rgb_color color,
selected_color_mode mode)
: BView(BRect(0.0, 0.0, 400.0, 277.0), name,
B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED),
h(0.0),
s(1.0),
v(1.0),
r((float)color.red / 255.0),
g((float)color.green / 255.0),
b((float)color.blue / 255.0),
fRequiresUpdate(false)
{
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
RGB_to_HSV(r, g, b, h, s, v);
SetColorMode(mode, false);
}
// destructor
ColorPickerView::~ColorPickerView()
{
}
#if LIB_LAYOUT
// layoutprefs
minimax
ColorPickerView::layoutprefs()
{
mpm.mini.x = mpm.maxi.x = Bounds().Width() + 1.0;
mpm.mini.y = mpm.maxi.y = Bounds().Height() + 1.0;
mpm.weight = 1.0;
return mpm;
}
// layout
BRect
ColorPickerView::layout(BRect frame)
{
MoveTo(frame.LeftTop());
ResizeTo(frame.Width(), frame.Height());
return Frame();
}
#endif // LIB_LAYOUT
// AttachedToWindow
void
ColorPickerView::AttachedToWindow()
{
rgb_color color = { (int)(r * 255), (int)(g * 255), (int)(b * 255), 255 };
BView::AttachedToWindow();
fColorField = new ColorField(BPoint(10.0, 10.0), fSelectedColorMode, *p);
fColorField->SetMarkerToColor(color);
AddChild(fColorField);
fColorField->SetTarget(this);
fColorSlider = new ColorSlider(BPoint(278.0, 7.0), fSelectedColorMode, *p1, *p2);
fColorSlider->SetMarkerToColor(color);
AddChild(fColorSlider);
fColorSlider->SetTarget(this);
fColorPreview = new ColorPreview(BRect(0.0, 0.0, 66.0, 70.0).OffsetToCopy(321.0, 10.0), color);
AddChild(fColorPreview);
fColorPreview->SetTarget(this);
BFont font(be_plain_font);
font.SetSize(10.0);
SetFont(&font);
const char *title[] = { "H", "S", "V", "R", "G", "B" };
BTextView *textView;
int32 selectedRadioButton = _NumForMode(fSelectedColorMode);
for (int i=0; i<6; ++i) {
fRadioButton[i] = new BRadioButton(BRect(0.0, 0.0, 30.0, 10.0).OffsetToCopy(320.0, 92.0 + 24.0 * i + (int)i/3 * 8),
NULL, title[i], new BMessage(MSG_RADIOBUTTON + i));
fRadioButton[i]->SetFont(&font);
AddChild(fRadioButton[i]);
fRadioButton[i]->SetTarget(this);
if (i == selectedRadioButton)
fRadioButton[i]->SetValue(1);
}
for (int i=0; i<6; ++i) {
fTextControl[i] = new BTextControl(BRect(0.0, 0.0, 32.0, 19.0).OffsetToCopy(350.0, 90.0 + 24.0 * i + (int)i/3 * 8),
NULL, NULL, NULL, new BMessage(MSG_TEXTCONTROL + i));
textView = fTextControl[i]->TextView();
textView->SetMaxBytes(3);
for (int j=32; j<255; ++j) {
if (j<'0'||j>'9') textView->DisallowChar(j);
}
fTextControl[i]->SetFont(&font);
fTextControl[i]->SetDivider(0.0);
AddChild(fTextControl[i]);
fTextControl[i]->SetTarget(this);
}
fHexTextControl = new BTextControl(BRect(0.0, 0.0, 69.0, 19.0).OffsetToCopy(320.0, 248.0),
NULL, "#", NULL, new BMessage(MSG_HEXTEXTCONTROL));
textView = fHexTextControl->TextView();
textView->SetMaxBytes(6);
for (int j=32; j<255; ++j) {
if (!((j>='0' && j<='9') || (j>='a' && j<='f') || (j>='A' && j<='F'))) textView->DisallowChar(j);
}
fHexTextControl->SetFont(&font);
fHexTextControl->SetDivider(12.0);
AddChild(fHexTextControl);
fHexTextControl->SetTarget(this);
_UpdateTextControls();
}
// MessageReceived
void
ColorPickerView::MessageReceived(BMessage *message)
{
switch (message->what) {
case MSG_COLOR_FIELD: {
float value1, value2;
value1 = message->FindFloat("value");
value2 = message->FindFloat("value", 1);
_UpdateColor(-1, value1, value2);
fRequiresUpdate = true;
} break;
case MSG_COLOR_SLIDER: {
float value;
message->FindFloat("value", &value);
_UpdateColor(value, -1, -1);
fRequiresUpdate = true;
} break;
case MSG_COLOR_PREVIEW: {
rgb_color *color;
ssize_t numBytes;
if (message->FindData("color", B_RGB_COLOR_TYPE, (const void **)&color, &numBytes)==B_OK) {
color->alpha = 255;
SetColor(*color);
}
} break;
case MSG_RADIOBUTTON: {
SetColorMode(H_SELECTED);
} break;
case MSG_RADIOBUTTON + 1: {
SetColorMode(S_SELECTED);
} break;
case MSG_RADIOBUTTON + 2: {
SetColorMode(V_SELECTED);
} break;
case MSG_RADIOBUTTON + 3: {
SetColorMode(R_SELECTED);
} break;
case MSG_RADIOBUTTON + 4: {
SetColorMode(G_SELECTED);
} break;
case MSG_RADIOBUTTON + 5: {
SetColorMode(B_SELECTED);
} break;
case MSG_TEXTCONTROL:
case MSG_TEXTCONTROL + 1:
case MSG_TEXTCONTROL + 2:
case MSG_TEXTCONTROL + 3:
case MSG_TEXTCONTROL + 4:
case MSG_TEXTCONTROL + 5: {
int nr = message->what - MSG_TEXTCONTROL;
int value = atoi(fTextControl[nr]->Text());
char string[4];
switch (nr) {
case 0: {
value %= 360;
sprintf(string, "%d", value);
h = (float)value / 60;
} break;
case 1: {
value = min_c(value, 100);
sprintf(string, "%d", value);
s = (float)value / 100;
} break;
case 2: {
value = min_c(value, 100);
sprintf(string, "%d", value);
v = (float)value / 100;
} break;
case 3: {
value = min_c(value, 255);
sprintf(string, "%d", value);
r = (float)value / 255;
} break;
case 4: {
value = min_c(value, 255);
sprintf(string, "%d", value);
g = (float)value / 255;
} break;
case 5: {
value = min_c(value, 255);
sprintf(string, "%d", value);
b = (float)value / 255;
} break;
}
if (nr<3) { // hsv-mode
HSV_to_RGB(h, s, v, r, g, b);
}
rgb_color color = { round(r*255), round(g*255), round(b*255), 255 };
SetColor(color);
} break;
case MSG_HEXTEXTCONTROL: {
if (fHexTextControl->TextView()->TextLength()==6) {
const char *string = fHexTextControl->TextView()->Text();
rgb_color color = { hexdec(string, 0), hexdec(string, 2), hexdec(string, 4), 255 };
SetColor(color);
}
} break;
default:
BView::MessageReceived(message);
}
}
// Draw
void
ColorPickerView::Draw(BRect updateRect)
{
// raised border
BRect r(Bounds());
if (updateRect.Intersects(r)) {
rgb_color light = tint_color(LowColor(), B_LIGHTEN_MAX_TINT);
rgb_color shadow = tint_color(LowColor(), B_DARKEN_2_TINT);
BeginLineArray(4);
AddLine(BPoint(r.left, r.bottom),
BPoint(r.left, r.top), light);
AddLine(BPoint(r.left + 1.0, r.top),
BPoint(r.right, r.top), light);
AddLine(BPoint(r.right, r.top + 1.0),
BPoint(r.right, r.bottom), shadow);
AddLine(BPoint(r.right - 1.0, r.bottom),
BPoint(r.left + 1.0, r.bottom), shadow);
EndLineArray();
// exclude border from update rect
r.InsetBy(1.0, 1.0);
updateRect = r & updateRect;
}
// some additional labels
font_height fh;
GetFontHeight(&fh);
const char *title[] = { "°", "%", "%" };
for (int i = 0; i < 3; ++i) {
DrawString(title[i],
BPoint(385.0, 93.0 + 24.0 * i + (int)i / 3 * 8 + fh.ascent));
}
}
// Pulse
void
ColorPickerView::Pulse()
{
if (fRequiresUpdate)
_UpdateTextControls();
}
// SetColorMode
void
ColorPickerView::SetColorMode(selected_color_mode mode, bool update)
{
fSelectedColorMode = mode;
switch (mode) {
case R_SELECTED:
p = &r; p1 = &g; p2 = &b;
break;
case G_SELECTED:
p = &g; p1 = &r; p2 = &b;
break;
case B_SELECTED:
p = &b; p1 = &r; p2 = &g;
break;
case H_SELECTED:
p = &h; p1 = &s; p2 = &v;
break;
case S_SELECTED:
p = &s; p1 = &h; p2 = &v;
break;
case V_SELECTED:
p = &v; p1 = &h; p2 = &s;
break;
}
if (!update) return;
fColorSlider->SetModeAndValues(fSelectedColorMode, *p1, *p2);
fColorField->SetModeAndValue(fSelectedColorMode, *p);
}
// SetColor
void
ColorPickerView::SetColor(rgb_color color)
{
r = (float)color.red/255; g = (float)color.green/255; b = (float)color.blue/255;
RGB_to_HSV(r, g, b, h, s, v);
fColorSlider->SetModeAndValues(fSelectedColorMode, *p1, *p2);
fColorSlider->SetMarkerToColor(color);
fColorField->SetModeAndValue(fSelectedColorMode, *p);
fColorField->SetMarkerToColor(color);
fColorPreview->SetColor(color);
fRequiresUpdate = true;
}
// Color
rgb_color
ColorPickerView::Color()
{
if (fSelectedColorMode & (R_SELECTED|G_SELECTED|B_SELECTED))
RGB_to_HSV(r, g, b, h, s, v);
else
HSV_to_RGB(h, s, v, r, g, b);
rgb_color color;
color.red = (uint8)round(r * 255.0);
color.green = (uint8)round(g * 255.0);
color.blue = (uint8)round(b * 255.0);
color.alpha = 255;
return color;
}
// _NumForMode
int32
ColorPickerView::_NumForMode(selected_color_mode mode) const
{
int32 num = -1;
switch (mode) {
case H_SELECTED:
num = 0;
break;
case S_SELECTED:
num = 1;
break;
case V_SELECTED:
num = 2;
break;
case R_SELECTED:
num = 3;
break;
case G_SELECTED:
num = 4;
break;
case B_SELECTED:
num = 5;
break;
}
return num;
}
// _UpdateColor
void
ColorPickerView::_UpdateColor(float value, float value1, float value2)
{
if (value!=-1) {
fColorField->SetFixedValue(value);
*p = value;
}
else if (value1!=-1 && value2!=-1) {
fColorSlider->SetOtherValues(value1, value2);
*p1 = value1; *p2 = value2;
}
if (fSelectedColorMode & (R_SELECTED|G_SELECTED|B_SELECTED))
RGB_to_HSV(r, g, b, h, s, v);
else
HSV_to_RGB(h, s, v, r, g, b);
rgb_color color = { (int)(r*255), (int)(g*255), (int)(b*255), 255 };
fColorPreview->SetColor(color);
}
// _UpdateTextControls
void
ColorPickerView::_UpdateTextControls()
{
Window()->DisableUpdates();
char string[10];
fRequiresUpdate = false;
sprintf(string, "%d", round(h*60));
_SetText(fTextControl[0], string, &fRequiresUpdate);
sprintf(string, "%d", round(s*100));
_SetText(fTextControl[1], string, &fRequiresUpdate);
sprintf(string, "%d", round(v*100));
_SetText(fTextControl[2], string, &fRequiresUpdate);
sprintf(string, "%d", round(r*255));
_SetText(fTextControl[3], string, &fRequiresUpdate);
sprintf(string, "%d", round(g*255));
_SetText(fTextControl[4], string, &fRequiresUpdate);
sprintf(string, "%d", round(b*255));
_SetText(fTextControl[5], string, &fRequiresUpdate);
sprintf(string, "%.6X", (round(r*255)<<16)|(round(g*255)<<8)|round(b*255));
_SetText(fHexTextControl, string, &fRequiresUpdate);
Window()->EnableUpdates();
}
// _SetText
void
ColorPickerView::_SetText(BTextControl* control, const char* text,
bool* requiresUpdate)
{
if (strcmp(control->Text(), text) != 0) {
// this textview needs updating
if (!control->TextView()->IsFocus())
// but don't screw with user while she is typing
control->SetText(text);
else
*requiresUpdate = true;
}
}

View File

@ -0,0 +1,94 @@
/*
* Copyright 2001 Werner Freytag - please read to the LICENSE file
*
* Copyright 2002-2006, Stephan Aßmus <superstippi@gmx.de>
* All rights reserved.
*
*/
#ifndef COLOR_PICKER_VIEW_H
#define COLOR_PICKER_VIEW_H
#include "ColorPickerDefs.h"
#include <View.h>
#if LIB_LAYOUT
# include <layout.h>
#endif
#include "selected_color_mode.h"
#define MSG_RADIOBUTTON 'Rad0'
#define MSG_TEXTCONTROL 'Txt0'
#define MSG_HEXTEXTCONTROL 'HTxt'
class ColorField;
class ColorSlider;
class ColorPreview;
class BRadioButton;
class BTextControl;
class ColorPickerView :
#if LIB_LAYOUT
public MView,
#endif
public BView {
public:
ColorPickerView(const char* name,
rgb_color color,
selected_color_mode mode);
virtual ~ColorPickerView();
#if LIB_LAYOUT
// MView
virtual minimax layoutprefs();
virtual BRect layout(BRect frame);
#endif
// BView
virtual void AttachedToWindow();
virtual void MessageReceived(BMessage *message);
virtual void Draw(BRect updateRect);
virtual void Pulse();
// ColorPickerView
void SetColorMode(selected_color_mode mode,
bool update = true);
void SetColor(rgb_color color);
rgb_color Color();
selected_color_mode Mode() const
{ return fSelectedColorMode; }
private:
int32 _NumForMode(selected_color_mode mode) const;
void _UpdateColor(float value, float value1,
float value2);
void _UpdateTextControls();
void _SetText(BTextControl* control,
const char* text,
bool* requiresUpdate);
selected_color_mode fSelectedColorMode;
float h, s, v, r, g, b;
float *p, *p1, *p2;
bool fRequiresUpdate;
ColorField* fColorField;
ColorSlider* fColorSlider;
ColorPreview* fColorPreview;
BRadioButton* fRadioButton[6];
BTextControl* fTextControl[6];
BTextControl* fHexTextControl;
};
#endif // COLOR_PICKER_VIEW_H

View File

@ -0,0 +1,211 @@
/*
* Copyright 2001 Werner Freytag - please read to the LICENSE file
*
* Copyright 2002-2006, Stephan Aßmus <superstippi@gmx.de>
* All rights reserved.
*
*/
#include "ColorPreview.h"
#include <stdio.h>
#include <Bitmap.h>
#include <Cursor.h>
#include <MessageRunner.h>
#include <String.h>
#include <Window.h>
#include "cursors.h"
#include "support_ui.h"
// constructor
ColorPreview::ColorPreview(BRect frame, rgb_color color)
: BControl(frame, "colorpreview", "", new BMessage(MSG_COLOR_PREVIEW),
B_FOLLOW_TOP|B_FOLLOW_LEFT, B_WILL_DRAW),
fColor(color),
fOldColor(color),
fMouseDown(false),
fMessageRunner(0)
{
}
// AttachedToWindow
void
ColorPreview::AttachedToWindow()
{
BControl::AttachedToWindow();
SetViewColor(B_TRANSPARENT_COLOR);
}
// Draw
void
ColorPreview::Draw(BRect updateRect)
{
rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
rgb_color shadow = tint_color(background, B_DARKEN_1_TINT);
rgb_color darkShadow = tint_color(background, B_DARKEN_3_TINT);
rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
BRect r(Bounds());
stroke_frame(this, r, shadow, shadow, light, light);
r.InsetBy(1.0, 1.0);
stroke_frame(this, r, darkShadow, darkShadow, background, background);
r.InsetBy(1.0, 1.0);
r.bottom = r.top + r.Height() / 2.0;
SetHighColor(fColor);
FillRect(r);
r.top = r.bottom + 1;
r.bottom = Bounds().bottom - 2.0;
SetHighColor(fOldColor);
FillRect(r);
}
// MessageReceived
void
ColorPreview::MessageReceived(BMessage* message)
{
if (message->what == MSG_MESSAGERUNNER) {
BPoint where;
uint32 buttons;
GetMouse(&where, &buttons);
_DragColor(where);
} else {
#ifdef TARGET_PLATFORM_ZETA
const
#endif
char* nameFound;
type_code typeFound;
if (message->GetInfo(B_RGB_COLOR_TYPE, 0,
&nameFound, &typeFound) != B_OK) {
BControl::MessageReceived(message);
return;
}
rgb_color* color;
ssize_t numBytes;
message->FindData(nameFound, typeFound,
(const void**)&color, &numBytes);
BPoint where;
bool droppedOnNewArea = false;
if (message->FindPoint("_drop_point_", &where) == B_OK) {
ConvertFromScreen(&where);
if (where.y > Bounds().top + (Bounds().IntegerHeight() >> 1))
droppedOnNewArea = true;
}
if (droppedOnNewArea)
SetNewColor(*color);
else
SetColor(*color);
Invoke();
}
}
// MouseDown
void
ColorPreview::MouseDown(BPoint where)
{
Window()->Activate();
fMouseDown = true;
fMessageRunner = new BMessageRunner(
this, new BMessage(MSG_MESSAGERUNNER), 300000, 1);
SetMouseEventMask(B_POINTER_EVENTS,
B_SUSPEND_VIEW_FOCUS | B_LOCK_WINDOW_FOCUS);
BRect rect = Bounds().InsetByCopy(2.0, 2.0);
rect.top = rect.bottom/2 + 1;
if (rect.Contains( where ) ) {
fColor = fOldColor;
Draw( Bounds() );
Invoke();
}
}
// MouseUp
void
ColorPreview::MouseUp(BPoint where)
{
delete fMessageRunner;
fMessageRunner = NULL;
fMouseDown = false;
BControl::MouseUp(where);
}
// MouseMoved
void
ColorPreview::MouseMoved(BPoint where, uint32 transit, const BMessage* message)
{
if (transit == B_ENTERED_VIEW) {
BCursor cursor(kDropperCursor);
SetViewCursor(&cursor, true);
}
if (fMouseDown)
_DragColor(where);
}
// Invoke
status_t
ColorPreview::Invoke(BMessage* message)
{
if (!message)
message = Message();
if (message) {
message->RemoveName("color");
message->AddData("color", B_RGB_COLOR_TYPE, &fColor, sizeof(fColor));
}
return BControl::Invoke(message);
}
// SetColor
void
ColorPreview::SetColor(rgb_color color)
{
color.alpha = 255;
fColor = color;
Invalidate();
}
// SetNewColor
void
ColorPreview::SetNewColor(rgb_color color)
{
fColor = color;
fOldColor = color;
Invalidate();
}
// #pragma mark -
// _DragColor
void
ColorPreview::_DragColor(BPoint where)
{
BBitmap* bitmap = new BBitmap(BRect(0.0, 0.0, 15.0, 15.0), B_RGB32);
BMessage message = make_color_drop_message(fColor, bitmap);
DragMessage(&message, bitmap, B_OP_ALPHA, BPoint(9.0, 9.0));
MouseUp(where);
}

View File

@ -0,0 +1,57 @@
/*
* Copyright 2001 Werner Freytag - please read to the LICENSE file
*
* Copyright 2002-2006, Stephan Aßmus <superstippi@gmx.de>
* All rights reserved.
*
*/
#ifndef _COLOR_PREVIEW_H
#define _COLOR_PREVIEW_H
#include <Control.h>
#define MSG_COLOR_PREVIEW 'ColP'
#define MSG_MESSAGERUNNER 'MsgR'
class BMessageRunner;
class ColorPreview : public BControl {
public:
ColorPreview(BRect frame,
rgb_color color);
// BControl interface
virtual void AttachedToWindow();
virtual void Draw(BRect updateRect);
virtual void MessageReceived(BMessage* message);
virtual void MouseDown(BPoint where);
virtual void MouseUp(BPoint where);
virtual void MouseMoved(BPoint where, uint32 transit,
const BMessage* message);
virtual status_t Invoke(BMessage* message = NULL);
// ColorPreview
void SetColor(rgb_color color);
// changes the displayed color
void SetNewColor(rgb_color color);
// changes also the old color
private:
void _DragColor(BPoint where);
rgb_color fColor;
rgb_color fOldColor;
bool fMouseDown;
BMessageRunner* fMessageRunner;
};
#endif // _COLOR_PREVIEW_H

View File

@ -0,0 +1,669 @@
/*
* Copyright 2001 Werner Freytag - please read to the LICENSE file
*
* Copyright 2002-2006, Stephan Aßmus <superstippi@gmx.de>
* All rights reserved.
*
*/
#include "ColorSlider.h"
#include <stdio.h>
#include <Bitmap.h>
#include <OS.h>
#include <Window.h>
#include <math.h>
#include "selected_color_mode.h"
#include "support_ui.h"
#include "rgb_hsv.h"
#define round(x) (int)(x+.5)
enum {
MSG_UPDATE = 'Updt',
};
#define MAX_X 255
#define MAX_Y 255
// constructor
ColorSlider::ColorSlider(BPoint offset_point,
selected_color_mode mode,
float value1, float value2, orientation dir)
: BControl(BRect(0.0, 0.0, 35.0, 265.0).OffsetToCopy(offset_point),
"ColorSlider", "", new BMessage(MSG_COLOR_SLIDER),
B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_FRAME_EVENTS),
fMode(mode),
fFixedValue1(value1),
fFixedValue2(value2),
fMouseDown(false),
fBgBitmap(new BBitmap(Bounds(), B_RGB32, true)),
fBgView(NULL),
fUpdateThread(0),
fUpdatePort(0),
fOrientation(dir)
{
SetViewColor(B_TRANSPARENT_32_BIT);
if (fBgBitmap->IsValid() && fBgBitmap->Lock()) {
fBgView = new BView(Bounds(), "", B_FOLLOW_NONE, B_WILL_DRAW);
fBgBitmap->AddChild(fBgView);
/* if (fOrientation == B_VERTICAL)
fBgView->SetOrigin(8.0, 2.0);
else
fBgView->SetOrigin(2.0, 2.0);*/
fBgBitmap->Unlock();
} else {
delete fBgBitmap;
fBgBitmap = NULL;
fBgView = this;
}
fUpdatePort = create_port(100, "color slider update port");
fUpdateThread = spawn_thread(ColorSlider::_UpdateThread, "color slider update thread", 10, this);
resume_thread( fUpdateThread );
Update(2);
}
// destructor
ColorSlider::~ColorSlider()
{
if (fUpdatePort)
delete_port(fUpdatePort);
if (fUpdateThread)
kill_thread(fUpdateThread);
delete fBgBitmap;
}
#if LIB_LAYOUT
// layoutprefs
minimax
ColorSlider::layoutprefs()
{
if (fOrientation == B_VERTICAL) {
mpm.mini.x = 36;
mpm.maxi.x = 36;
mpm.mini.y = 10 + MAX_Y / 17;
mpm.maxi.y = 10 + MAX_Y;
} else {
mpm.mini.x = 10 + MAX_X / 17;
mpm.maxi.x = 10 + MAX_X;
mpm.mini.y = 10.0;
mpm.maxi.y = 12.0;
}
mpm.weight = 1.0;
return mpm;
}
// layout
BRect
ColorSlider::layout(BRect frame)
{
MoveTo(frame.LeftTop());
ResizeTo(frame.Width(), frame.Height());
// Update(2);
return Frame();
}
#endif // LIB_LAYOUT
// AttachedToWindow
void
ColorSlider::AttachedToWindow()
{
BControl::AttachedToWindow();
SetViewColor(B_TRANSPARENT_32_BIT);
if (fBgBitmap && fBgBitmap->Lock()) {
fBgView->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
fBgView->FillRect(Bounds());
fBgBitmap->Unlock();
} else {
SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
}
Update(2);
}
// Invoke
status_t
ColorSlider::Invoke(BMessage *msg)
{
if (!msg) msg = Message();
msg->RemoveName("value");
msg->RemoveName("begin");
switch (fMode) {
case R_SELECTED:
case G_SELECTED:
case B_SELECTED: {
msg->AddFloat("value", 1.0 - (float)Value() / 255);
} break;
case H_SELECTED: {
msg->AddFloat("value", (1.0 - (float)Value() / 255) * 6);
} break;
case S_SELECTED:
case V_SELECTED: {
msg->AddFloat("value", 1.0 - (float)Value() / 255);
} break;
}
// some other parts of WonderBrush rely on this.
// if the flag is present, it triggers generating an undo action
// fMouseDown is not set yet the first message is sent
if (!fMouseDown)
msg->AddBool("begin", true);
return BControl::Invoke(msg);
}
// Draw
void
ColorSlider::Draw(BRect updateRect)
{
Update(0);
}
// FrameResized
void
ColorSlider::FrameResized(float width, float height)
{
if (fBgBitmap) {
fBgBitmap->Lock();
delete fBgBitmap;
}
fBgBitmap = new BBitmap(Bounds(), B_RGB32, true);
if (fBgBitmap->IsValid() && fBgBitmap->Lock()) {
fBgView = new BView(Bounds(), "", B_FOLLOW_NONE, B_WILL_DRAW);
fBgBitmap->AddChild(fBgView);
/* if (fOrientation == B_VERTICAL)
fBgView->SetOrigin(8.0, 2.0);
else
fBgView->SetOrigin(2.0, 2.0);*/
fBgBitmap->Unlock();
} else {
delete fBgBitmap;
fBgBitmap = NULL;
fBgView = this;
}
Update(2);
}
// MouseDown
void
ColorSlider::MouseDown(BPoint where)
{
Window()->Activate();
SetMouseEventMask(B_POINTER_EVENTS, B_SUSPEND_VIEW_FOCUS | B_LOCK_WINDOW_FOCUS);
_TrackMouse(where);
fMouseDown = true;
}
// MouseUp
void
ColorSlider::MouseUp(BPoint where)
{
fMouseDown = false;
}
// MouseMoved
void
ColorSlider::MouseMoved( BPoint where, uint32 code, const BMessage* dragMessage)
{
if (dragMessage || !fMouseDown)
return;
_TrackMouse(where);
}
// SetValue
void
ColorSlider::SetValue(int32 value)
{
value = max_c(min_c(value, 255), 0);
if (value != Value()) {
BControl::SetValue(value);
Update(1);
}
}
// Update
void
ColorSlider::Update(int depth)
{
// depth: 0 = onscreen only, 1 = bitmap 1, 2 = bitmap 0
if (depth == 2) {
write_port(fUpdatePort, MSG_UPDATE, NULL, 0);
return;
}
if (!Parent())
return;
fBgBitmap->Lock();
// BRect r(fBgView->Bounds());
BRect r(Bounds());
BRect bounds(r);
if (fOrientation == B_VERTICAL) {
// r.OffsetBy(-8.0, -2.0);
r.InsetBy(6.0, 3.0);
// bounds.Set(-8.0, -2.0, r.right - 8.0, r.bottom - 2.0);
// bounds.OffsetBy(8.0, 2.0);
} else {
// r.OffsetBy(-2.0, -2.0);
// bounds.Set(-2.0, -2.0, r.right - 2.0, r.bottom - 2.0);
// bounds.OffsetBy(2.0, 2.0);
}
fBgBitmap->Unlock();
rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
rgb_color shadow = tint_color(background, B_DARKEN_1_TINT);
rgb_color darkShadow = tint_color(background, B_DARKEN_3_TINT);
rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
if (depth >= 1) {
fBgBitmap->Lock();
// frame
stroke_frame(fBgView, r, shadow, shadow, light, light);
r.InsetBy(1.0, 1.0);
stroke_frame(fBgView, r, darkShadow, darkShadow, background, background);
if (fOrientation == B_VERTICAL) {
// clear area left and right from slider
fBgView->SetHighColor( background );
fBgView->FillRect( BRect(bounds.left, bounds.top, bounds.left + 5.0, bounds.bottom) );
fBgView->FillRect( BRect(bounds.right - 5.0, bounds.top, bounds.right, bounds.bottom) );
}
/*
// marker
if (fOrientation == B_VERTICAL) {
// clear area left and right from slider
fBgView->SetHighColor( background );
fBgView->FillRect( BRect(bounds.left, bounds.top, bounds.left + 5.0, bounds.bottom) );
fBgView->FillRect( BRect(bounds.right - 5.0, bounds.top, bounds.right, bounds.bottom) );
// draw the triangle markers
fBgView->SetHighColor( 0, 0, 0 );
float value = Value();
fBgView->StrokeLine( BPoint(bounds.left, value - 2.0), BPoint(bounds.left + 5.0, value + 3.0));
fBgView->StrokeLine( BPoint(bounds.left, value + 8.0));
fBgView->StrokeLine( BPoint(bounds.left, value - 2.0));
fBgView->StrokeLine( BPoint(bounds.right, value - 2.0), BPoint(bounds.right - 5.0, value + 3.0));
fBgView->StrokeLine( BPoint(bounds.right, value + 8.0));
fBgView->StrokeLine( BPoint(bounds.right, value - 2.0));
} else {
r.InsetBy(1.0, 1.0);
float value = (Value() / 255.0) * (bounds.Width() - 4.0);
if (value - 2 > r.left) {
fBgView->SetHighColor( 255, 255, 255 );
fBgView->StrokeLine( BPoint(value - 2, bounds.top + 2.0),
BPoint(value - 2, bounds.bottom - 2.0));
}
if (value - 1 > r.left) {
fBgView->SetHighColor( 0, 0, 0 );
fBgView->StrokeLine( BPoint(value - 1, bounds.top + 2.0),
BPoint(value - 1, bounds.bottom - 2.0));
}
if (value + 1 < r.right) {
fBgView->SetHighColor( 0, 0, 0 );
fBgView->StrokeLine( BPoint(value + 1, bounds.top + 2.0),
BPoint(value + 1, bounds.bottom - 2.0));
}
if (value + 2 < r.right) {
fBgView->SetHighColor( 255, 255, 255 );
fBgView->StrokeLine( BPoint(value + 2, bounds.top + 2.0),
BPoint(value + 2, bounds.bottom - 2.0));
}
}*/
fBgView->Sync();
fBgBitmap->Unlock();
} else
r.InsetBy(1.0, 1.0);
DrawBitmap(fBgBitmap, BPoint(0.0, 0.0));
// marker
if (fOrientation == B_VERTICAL) {
// draw the triangle markers
SetHighColor( 0, 0, 0 );
float value = Value();
StrokeLine( BPoint(bounds.left, value),
BPoint(bounds.left + 5.0, value + 5.0));
StrokeLine( BPoint(bounds.left, value + 10.0));
StrokeLine( BPoint(bounds.left, value));
StrokeLine( BPoint(bounds.right, value),
BPoint(bounds.right - 5.0, value + 5.0));
StrokeLine( BPoint(bounds.right, value + 10.0));
StrokeLine( BPoint(bounds.right, value));
} else {
r.InsetBy(1.0, 1.0);
float value = (Value() / 255.0) * (bounds.Width() - 4.0);
if (value > r.left) {
SetHighColor( 255, 255, 255 );
StrokeLine( BPoint(value, bounds.top + 2.0),
BPoint(value, bounds.bottom - 2.0));
}
if (value + 1 > r.left) {
SetHighColor( 0, 0, 0 );
StrokeLine( BPoint(value + 1, bounds.top + 2.0),
BPoint(value + 1, bounds.bottom - 2.0));
}
if (value + 3 < r.right) {
SetHighColor( 0, 0, 0 );
StrokeLine( BPoint(value + 3, bounds.top + 2.0),
BPoint(value + 3, bounds.bottom - 2.0));
}
if (value + 4 < r.right) {
SetHighColor( 255, 255, 255 );
StrokeLine( BPoint(value + 4, bounds.top + 2.0),
BPoint(value + 4, bounds.bottom - 2.0));
}
}
SetOrigin(0.0, 0.0);
}
// SetModeAndValues
void
ColorSlider::SetModeAndValues(selected_color_mode mode,
float value1, float value2)
{
float R(0), G(0), B(0);
float h(0), s(0), v(0);
fBgBitmap->Lock();
switch (fMode) {
case R_SELECTED: {
R = 255 - Value();
G = round(fFixedValue1 * 255.0);
B = round(fFixedValue2 * 255.0);
}; break;
case G_SELECTED: {
R = round(fFixedValue1 * 255.0);
G = 255 - Value();
B = round(fFixedValue2 * 255.0);
}; break;
case B_SELECTED: {
R = round(fFixedValue1 * 255.0);
G = round(fFixedValue2 * 255.0);
B = 255 - Value();
}; break;
case H_SELECTED: {
h = (1.0 - (float)Value()/255.0)*6.0;
s = fFixedValue1;
v = fFixedValue2;
}; break;
case S_SELECTED: {
h = fFixedValue1;
s = 1.0 - (float)Value()/255.0;
v = fFixedValue2;
}; break;
case V_SELECTED: {
h = fFixedValue1;
s = fFixedValue2;
v = 1.0 - (float)Value()/255.0;
}; break;
}
if (fMode & (H_SELECTED|S_SELECTED|V_SELECTED) ) {
HSV_to_RGB(h, s, v, R, G, B);
R*=255.0; G*=255.0; B*=255.0;
}
rgb_color color = { round(R), round(G), round(B), 255 };
fMode = mode;
SetOtherValues(value1, value2);
fBgBitmap->Unlock();
SetMarkerToColor( color );
Update(2);
}
// SetOtherValues
void
ColorSlider::SetOtherValues(float value1, float value2)
{
fFixedValue1 = value1;
fFixedValue2 = value2;
if (fMode != H_SELECTED) {
Update(2);
}
}
// GetOtherValues
void
ColorSlider::GetOtherValues(float* value1, float* value2) const
{
if (value1 && value2) {
*value1 = fFixedValue1;
*value2 = fFixedValue2;
}
}
// SetMarkerToColor
void
ColorSlider::SetMarkerToColor(rgb_color color)
{
float h, s, v;
if (fMode & (H_SELECTED | S_SELECTED | V_SELECTED)) {
RGB_to_HSV((float)color.red / 255.0,
(float)color.green / 255.0,
(float)color.blue / 255.0,
h, s, v);
}
switch (fMode) {
case R_SELECTED: {
SetValue( 255 - color.red );
} break;
case G_SELECTED: {
SetValue( 255 - color.green );
} break;
case B_SELECTED: {
SetValue( 255 - color.blue );
} break;
case H_SELECTED: {
SetValue( 255.0 - round(h / 6.0 * 255.0) );
} break;
case S_SELECTED: {
SetValue( 255.0 - round(s * 255.0) );
} break;
case V_SELECTED: {
SetValue( 255.0 - round(v * 255.0) );
} break;
}
}
// _UpdateThread
int32
ColorSlider::_UpdateThread(void* data)
{
// initializing
ColorSlider* colorSlider = (ColorSlider*)data;
bool looperLocked = colorSlider->LockLooper();
port_id port = colorSlider->fUpdatePort;
orientation orient = colorSlider->fOrientation;
if (looperLocked)
colorSlider->UnlockLooper();
float h, s, v, r, g, b;
int R, G, B;
// drawing
int32 msg_code;
char msg_buffer;
while (true) {
port_info info;
do {
read_port(port, &msg_code, &msg_buffer, sizeof(msg_buffer));
get_port_info(port, &info);
} while (info.queue_count);
if (colorSlider->LockLooper()) {
uint colormode = colorSlider->fMode;
float fixedvalue1 = colorSlider->fFixedValue1;
float fixedvalue2 = colorSlider->fFixedValue2;
BBitmap* bitmap = colorSlider->fBgBitmap;
BView* view = colorSlider->fBgView;
bitmap->Lock();
colorSlider->UnlockLooper();
view->BeginLineArray(256);
switch (colormode) {
case R_SELECTED: {
G = round(fixedvalue1 * 255);
B = round(fixedvalue2 * 255);
for (int R = 0; R < 256; ++R) {
_DrawColorLineY( view, R, R, G, B );
}
}; break;
case G_SELECTED: {
R = round(fixedvalue1 * 255);
B = round(fixedvalue2 * 255);
for (int G = 0; G < 256; ++G) {
_DrawColorLineY( view, G, R, G, B );
}
}; break;
case B_SELECTED: {
R = round(fixedvalue1 * 255);
G = round(fixedvalue2 * 255);
for (int B = 0; B < 256; ++B) {
_DrawColorLineY( view, B, R, G, B );
}
}; break;
case H_SELECTED: {
s = 1.0;//fixedvalue1;
v = 1.0;//fixedvalue2;
if (orient == B_VERTICAL) {
for (int y = 0; y < 256; ++y) {
HSV_to_RGB( (float)y*6.0/255.0, s, v, r, g, b );
_DrawColorLineY( view, y, r*255, g*255, b*255 );
}
} else {
for (int x = 0; x < 256; ++x) {
HSV_to_RGB( (float)x*6.0/255.0, s, v, r, g, b );
_DrawColorLineX( view, x, r*255, g*255, b*255 );
}
}
}; break;
case S_SELECTED: {
h = fixedvalue1;
v = 1.0;//fixedvalue2;
for (int y = 0; y < 256; ++y) {
HSV_to_RGB( h, (float)y/255, v, r, g, b );
_DrawColorLineY( view, y, r*255, g*255, b*255 );
}
}; break;
case V_SELECTED: {
h = fixedvalue1;
s = 1.0;//fixedvalue2;
for (int y = 0; y < 256; ++y) {
HSV_to_RGB( h, s, (float)y/255, r, g, b );
_DrawColorLineY( view, y, r*255, g*255, b*255 );
}
}; break;
}
view->EndLineArray();
view->Sync();
bitmap->Unlock();
if (colorSlider->LockLooper()) {
colorSlider->Update(1);
colorSlider->UnlockLooper();
}
}
}
}
// _DrawColorLineY
void
ColorSlider::_DrawColorLineY(BView *view, float y,
int r, int g, int b)
{
rgb_color color = { r, g, b, 255 };
y = 255.0 - y;
view->AddLine( BPoint(8.0, y + 5.0), BPoint(27.0, y + 5.0), color );
}
// _DrawColorLineX
void
ColorSlider::_DrawColorLineX(BView *view, float x,
int r, int g, int b)
{
rgb_color color = { r, g, b, 255 };
BRect bounds(view->Bounds());
x = (255.0 - x) * (bounds.Width() - 2.0) / 255.0 + 2.0;
view->AddLine( BPoint(x, bounds.top + 2.0), BPoint(x, bounds.bottom - 2.0), color );
}
// _TrackMouse
void
ColorSlider::_TrackMouse(BPoint where)
{
if (fOrientation == B_VERTICAL) {
SetValue((int)where.y - 2);
} else {
BRect b(Bounds());
SetValue((int)(((where.x - 2.0) / b.Width()) * 255.0));
}
Invoke();
}

View File

@ -0,0 +1,98 @@
/*
* Copyright 2001 Werner Freytag - please read to the LICENSE file
*
* Copyright 2002-2006, Stephan Aßmus <superstippi@gmx.de>
* All rights reserved.
*
*/
#ifndef _COLOR_SLIDER_H
#define _COLOR_SLIDER_H
#include "ColorPickerDefs.h"
#include <Control.h>
#if LIB_LAYOUT
# include <layout.h>
#endif
#include "selected_color_mode.h"
#define MSG_COLOR_SLIDER 'ColS'
class BBitmap;
class ColorSlider :
#if LIB_LAYOUT
public MView,
#endif
public BControl {
public:
ColorSlider(BPoint offset_point,
selected_color_mode mode,
float value1, float value2,
orientation dir = B_VERTICAL);
virtual ~ColorSlider();
#if LIB_LAYOUT
// MView
virtual minimax layoutprefs();
virtual BRect layout(BRect frame);
#endif
// BControl
virtual void AttachedToWindow();
virtual status_t Invoke(BMessage* message = NULL);
virtual void Draw(BRect updateRect);
virtual void FrameResized(float width, float height);
virtual void MouseDown(BPoint where);
virtual void MouseUp(BPoint where);
virtual void MouseMoved(BPoint where, uint32 code,
const BMessage* dragMessage);
virtual void SetValue(int32 value);
// ColorSlider
void Update(int depth);
bool IsTracking() const
{ return fMouseDown; }
void SetModeAndValues(selected_color_mode mode,
float value1, float value2);
void SetOtherValues(float value1, float value2);
void GetOtherValues(float* value1, float* value2) const;
void SetMarkerToColor( rgb_color color );
// inline void _DrawColorLineY( float y, int r, int g, int b);
private:
static int32 _UpdateThread(void* cookie);
static inline void _DrawColorLineY(BView* view, float y,
int r, int g, int b);
static inline void _DrawColorLineX(BView* view, float x,
int r, int g, int b);
void _TrackMouse(BPoint where);
selected_color_mode fMode;
float fFixedValue1;
float fFixedValue2;
bool fMouseDown;
BBitmap* fBgBitmap;
BView* fBgView;
thread_id fUpdateThread;
port_id fUpdatePort;
orientation fOrientation;
};
#endif

View File

@ -0,0 +1,16 @@
License
You may use this source code without charge in your own projects, as long as you create a BeOS program. If you want to create something else, please contact the author about an individual license.
If you re-release this source code or parts of it, you must add this LICENSE file.
All graphics, especially the icon or brands are copyrighted by the author and may not be used in any form without the author's consent.
Author / contact
Werner Freytag
Neurieder Str. 8
82152 Martinsried
Germany
e-mail: info@pecora.de
visit: http://www.pecora.de

View File

@ -0,0 +1,94 @@
/*
* Copyright 2001 Werner Freytag - please read to the LICENSE file
*
*/
#ifndef CONVERT_RGB_HSV_H
#define CONVERT_RGB_HSV_H
#define RETURN_HSV(h, s, v) { H = h; S = s; V = v; return; }
#define RETURN_RGB(r, g, b) { R = r; G = g; B = b; return; }
#include <math.h>
#define UNDEFINED 0
inline void
RGB_to_HSV(float R, float G, float B, float& H, float& S, float& V)
{
// RGB are each on [0, 1]. S and max are returned on [0, 1] and H is
// returned on [0, 6]. Eminception: H is returned UNDEFINED if S==0.
float min, max;
if (R > G) {
if (R > B) {
max = R;
min = G > B ? B : G;
}
else {
max = B;
min = G;
}
}
else {
if (G > B) {
max = G;
min = R > B ? B : R;
}
else {
max = B;
min = R;
}
}
if (max == min) RETURN_HSV(UNDEFINED, 0, max);
float dist = max - min;
float f = (R == min) ? G - B : ((G == min) ? B - R : R - G);
float i = (R == min) ? 3 : ((G == min) ? 5 : 1);
float h = i - f / dist;
while (h >= 6.0) h -= 6.0;
RETURN_HSV(h, dist/max, max);
}
inline void
HSV_to_RGB(float h, float s, float v, float& R, float& G, float& B)
{
// H is given on [0, 6] or UNDEFINED. S and V are given on [0, 1].
// RGB are each returned on [0, 1].
int i = (int)floor(h);
float f = h - i;
if ( !(i & 1) ) f = 1 - f; // if i is even
float m = v * (1 - s);
float n = v * (1 - s * f);
switch (i) {
case 6:
case 0: RETURN_RGB(v, n, m);
case 1: RETURN_RGB(n, v, m);
case 2: RETURN_RGB(m, v, n)
case 3: RETURN_RGB(m, n, v);
case 4: RETURN_RGB(n, m, v);
case 5: RETURN_RGB(v, m, n);
}
}
#endif // CONVERT_RGB_HSV_H

View File

@ -0,0 +1,18 @@
/*
* Copyright 2001 Werner Freytag - please read to the LICENSE file
*
*/
#ifndef _SELECTED_COLOR_MODE_H
#define _SELECTED_COLOR_MODE_H
enum selected_color_mode {
R_SELECTED = 0x01,
G_SELECTED = 0x02,
B_SELECTED = 0x04,
H_SELECTED = 0x10,
S_SELECTED = 0x20,
V_SELECTED = 0x40
};
#endif // _SELECTED_COLOR_MODE_H

View File

@ -6,7 +6,7 @@
* Stephan Aßmus <superstippi@gmx.de>
*/
#include "support.h"
#include "support_ui.h"
#include <stdio.h>
#include <string.h>
@ -21,8 +21,6 @@
#include <Path.h>
#include <View.h>
#include <Space.h>
// stroke_frame
void
stroke_frame(BView* v, BRect r, rgb_color left, rgb_color top,
@ -42,20 +40,6 @@ stroke_frame(BView* v, BRect r, rgb_color left, rgb_color top,
}
}
// vertical_space
Space*
vertical_space()
{
return new Space(minimax(0.0, 3.0, 10000.0, 3.0, 1.0));
}
// horizontal_space
Space*
horizontal_space()
{
return new Space(minimax(3.0, 0.0, 3.0, 10000.0, 1.0));
}
// store_color_in_message
status_t
store_color_in_message(BMessage* message, rgb_color color)

View File

@ -20,7 +20,6 @@ class BPositionIO;
class BString;
class BView;
class BWindow;
class Space;
// looper of view must be locked!
void stroke_frame(BView* view, BRect frame,
@ -28,9 +27,6 @@ void stroke_frame(BView* view, BRect frame,
rgb_color right, rgb_color bottom);
Space* vertical_space();
Space* horizontal_space();
status_t store_color_in_message(BMessage* message, rgb_color color);
status_t restore_color_from_message(const BMessage* message, rgb_color& color, int32 index = 0);