* added GradientControl which can edit a Gradient

* filled out StyleView for configuring a Style
* added SetGradientCommand for undo/redo editing a
  Gradient
* Style::SetGradient() doesn't assume ownership
  of the Gradient passed in anymore


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18092 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2006-07-10 21:36:46 +00:00
parent 67bdea52ce
commit 2205ee0914
14 changed files with 1233 additions and 26 deletions
+3
View File
@@ -108,10 +108,12 @@ Application Icon-O-Matic :
support.cpp
support_ui.cpp
# gui
GradientControl.cpp
IconObjectListView.cpp
PathListView.cpp
ShapeListView.cpp
StyleListView.cpp
StyleView.cpp
SwatchGroup.cpp
TransformerListView.cpp
# shape
@@ -133,6 +135,7 @@ Application Icon-O-Matic :
# style
CurrentColor.cpp
Gradient.cpp
SetGradientCommand.cpp
Style.cpp
StyleManager.cpp
# transformer
+17 -5
View File
@@ -27,6 +27,7 @@
#include "ScrollView.h"
#include "ShapeListView.h"
#include "StyleListView.h"
#include "StyleView.h"
#include "SwatchGroup.h"
#include "TransformerFactory.h"
#include "TransformerListView.h"
@@ -127,6 +128,7 @@ case MSG_STYLE_SELECTED: {
if (message->FindPointer("style", (void**)&style) < B_OK)
style = NULL;
fSwatchGroup->SetCurrentStyle(style);
fStyleView->SetStyle(style);
break;
}
// TODO: use an AddShapeCommand
@@ -237,6 +239,8 @@ MainWindow::_Init()
// fStyleListView->SetCommandStack(fDocument->CommandStack());
fStyleListView->SetSelection(fDocument->Selection());
fStyleView->SetCommandStack(fDocument->CommandStack());
fShapeListView->SetShapeContainer(fDocument->Icon()->Shapes());
fShapeListView->SetCommandStack(fDocument->CommandStack());
fShapeListView->SetSelection(fDocument->Selection());
@@ -271,11 +275,11 @@ MainWindow::_Init()
StyleManager::Default()->AddStyle(style1);
Style* style2 = new Style();
Gradient* gradient = new Gradient(true);
gradient->AddColor((rgb_color){ 255, 211, 6, 255 }, 0.0);
gradient->AddColor((rgb_color){ 255, 238, 160, 255 }, 0.5);
gradient->AddColor((rgb_color){ 208, 43, 92, 255 }, 1.0);
style2->SetGradient(gradient);
Gradient gradient(true);
gradient.AddColor((rgb_color){ 255, 211, 6, 255 }, 0.0);
gradient.AddColor((rgb_color){ 255, 238, 160, 255 }, 0.5);
gradient.AddColor((rgb_color){ 208, 43, 92, 255 }, 1.0);
style2->SetGradient(&gradient);
StyleManager::Default()->AddStyle(style2);
@@ -407,6 +411,14 @@ MainWindow::_CreateGUI(BRect bounds)
new BMessage(MSG_STYLE_SELECTED), this);
// style view
bounds.left = menuBar->Frame().right + 1;
bounds.top = bg->Bounds().top;
bounds.right = fSwatchGroup->Frame().left - 1;
bounds.bottom = fCanvasView->Frame().top - 1;
fStyleView = new StyleView(bounds);
bg->AddChild(fStyleView);
// path list view
bounds.left = 0;
bounds.right = fCanvasView->Frame().left - 1;
+2
View File
@@ -23,6 +23,7 @@ class IconView;
class PathListView;
class ShapeListView;
class StyleListView;
class StyleView;
class SwatchGroup;
class TransformerListView;
@@ -62,6 +63,7 @@ class MainWindow : public BWindow,
CanvasView* fCanvasView;
SwatchGroup* fSwatchGroup;
StyleView* fStyleView;
IconView* fIconPreview16;
IconView* fIconPreview32;
+5 -1
View File
@@ -33,6 +33,10 @@
* implement commands for the newly added editing features
* built-in transformation for Gradient and Shape?
* Transformation manipulator
--------- user interface
@@ -45,7 +49,7 @@
* list of transformers attached to the selected shape [done]
* area for styles, style is either solid color or gradient
* area for styles, style is either solid color or gradient [done]
--------- icon format
@@ -0,0 +1,634 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "GradientControl.h"
#include <stdio.h>
#include <AppDefs.h>
#include <Bitmap.h>
#include <Message.h>
#include <Window.h>
#include "ui_defines.h"
#include "support_ui.h"
#include "Gradient.h"
// constructor
GradientControl::GradientControl(BMessage* message, BHandler* target)
: BView(BRect(0, 0, 259, 19), "gradient control", B_FOLLOW_NONE,
B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE),
fGradient(new ::Gradient()),
fGradientBitmap(NULL),
fDraggingStepIndex(-1),
fCurrentStepIndex(-1),
fDropOffset(-1.0),
fDropIndex(-1),
fEnabled(true),
fMessage(message),
fTarget(target)
{
FrameResized(Bounds().Width(), Bounds().Height());
SetViewColor(B_TRANSPARENT_32_BIT);
SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
}
// destructor
GradientControl::~GradientControl()
{
delete fGradient;
delete fGradientBitmap;
delete fMessage;
}
#if LIB_LAYOUT
// layoutprefs
minimax
GradientControl::layoutprefs()
{
mpm.mini.x = 256 + 4;
mpm.maxi.x = mpm.mini.x + 10000;
mpm.mini.y = 20;
mpm.maxi.y = mpm.mini.y + 10;
mpm.weight = 2.0;
return mpm;
}
// layout
BRect
GradientControl::layout(BRect frame)
{
MoveTo(frame.LeftTop());
ResizeTo(frame.Width(), frame.Height());
return Frame();
}
#endif // LIB_LAYOUT
// WindowActivated
void
GradientControl::WindowActivated(bool active)
{
if (IsFocus())
Invalidate();
}
// MakeFocus
void
GradientControl::MakeFocus(bool focus)
{
if (focus != IsFocus()) {
_UpdateCurrentColor();
Invalidate();
// keep the window informed when the focus of this object changes
if (BWindow* window = Window())
window->PostMessage(MSG_GRADIENT_CONTROL_FOCUS_CHANGED);
}
BView::MakeFocus(focus);
}
// MouseDown
void
GradientControl::MouseDown(BPoint where)
{
if (!fEnabled)
return;
if (!IsFocus()) {
MakeFocus(true);
}
fDraggingStepIndex = _StepIndexFor(where);
if (fDraggingStepIndex >= 0)
SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
// handle double click
int32 clicks;
if (Window()->CurrentMessage()->FindInt32("clicks", &clicks) >= B_OK && clicks >= 2) {
if (fDraggingStepIndex < 0) {
// create a new offset at the click location that uses
// the interpolated color
float offset = _OffsetFor(where);
// create a clean gradient
uint32 width = fGradientBitmap->Bounds().IntegerWidth();
uint8* temp = new uint8[width * 4];
fGradient->MakeGradient((uint32*)temp, width);
// get the color at the offset
rgb_color color;
uint8* bits = temp;
bits += 4 * (uint32)((width - 1) * offset);
color.red = bits[2];
color.green = bits[1];
color.blue = bits[0];
color.alpha = bits[3];
fCurrentStepIndex = fGradient->AddColor(color, offset);
fDraggingStepIndex = -1;
_UpdateColors();
Invalidate();
_UpdateCurrentColor();
delete[] temp;
}
}
if (fCurrentStepIndex != fDraggingStepIndex && fDraggingStepIndex >= 0) {
// start dragging this stop
fCurrentStepIndex = fDraggingStepIndex;
Invalidate();
_UpdateCurrentColor();
}
}
// MouseUp
void
GradientControl::MouseUp(BPoint where)
{
fDraggingStepIndex = -1;
}
// MouseMoved
void
GradientControl::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
{
if (!fEnabled)
return;
float offset = _OffsetFor(where);
if (fDraggingStepIndex >= 0) {
color_step* step = fGradient->ColorAt(fDraggingStepIndex);
if (step) {
if (fGradient->SetOffset(fDraggingStepIndex, offset)) {
_UpdateColors();
Invalidate();
}
}
}
int32 dropIndex = -1;
float dropOffset = -1.0;
if (dragMessage && (transit == B_INSIDE_VIEW || transit == B_ENTERED_VIEW)) {
rgb_color dragColor;
if (restore_color_from_message(dragMessage, dragColor, 0) >= B_OK) {
dropIndex = _StepIndexFor(where);
// fall back to inserting a color step if no direct hit on an existing step
if (dropIndex < 0)
dropOffset = offset;
}
}
if (fDropOffset != dropOffset || fDropIndex != dropIndex) {
fDropOffset = dropOffset;
fDropIndex = dropIndex;
Invalidate();
}
}
// MessageReceived
void
GradientControl::MessageReceived(BMessage* message)
{
switch (message->what) {
case B_PASTE:
if (fEnabled) {
rgb_color color;
if (restore_color_from_message(message, color, 0) >= B_OK) {
bool update = false;
if (fDropIndex >= 0) {
if (color_step* step = fGradient->ColorAt(fDropIndex)) {
color.alpha = step->color.alpha;
}
fGradient->SetColor(fDropIndex, color);
fCurrentStepIndex = fDropIndex;
fDropIndex = -1;
update = true;
} else if (fDropOffset >= 0.0) {
fCurrentStepIndex = fGradient->AddColor(color, fDropOffset);
fDropOffset = -1.0;
update = true;
}
if (update) {
_UpdateColors();
if (!IsFocus())
MakeFocus(true);
else
Invalidate();
_UpdateCurrentColor();
}
}
}
break;
default:
BView::MessageReceived(message);
}
}
// KeyDown
void
GradientControl::KeyDown(const char* bytes, int32 numBytes)
{
bool handled = false;
bool update = false;
if (fEnabled) {
if (numBytes > 0) {
handled = true;
int32 count = fGradient->CountColors();
switch (bytes[0]) {
case B_DELETE:
// remove step
update = fGradient->RemoveColor(fCurrentStepIndex);
if (update) {
fCurrentStepIndex = max_c(0, fCurrentStepIndex - 1);
_UpdateCurrentColor();
}
break;
case B_HOME:
case B_END:
case B_LEFT_ARROW:
case B_RIGHT_ARROW: {
if (color_step* step = fGradient->ColorAt(fCurrentStepIndex)) {
BRect r = _GradientBitmapRect();
float x = r.left + r.Width() * step->offset;
switch (bytes[0]) {
case B_LEFT_ARROW:
// move step to the left
x = max_c(r.left, x - 1.0);
break;
case B_RIGHT_ARROW:
// move step to the right
x = min_c(r.right, x + 1.0);
break;
case B_HOME:
// move step to the start
x = r.left;
break;
case B_END:
// move step to the start
x = r.right;
break;
}
update = fGradient->SetOffset(fCurrentStepIndex, (x - r.left) / r.Width());
}
break;
}
case B_UP_ARROW:
// previous step
fCurrentStepIndex--;
if (fCurrentStepIndex < 0) {
fCurrentStepIndex = count - 1;
_UpdateCurrentColor();
}
break;
case B_DOWN_ARROW:
// next step
fCurrentStepIndex++;
if (fCurrentStepIndex >= count) {
fCurrentStepIndex = 0;
_UpdateCurrentColor();
}
break;
default:
handled = false;
break;
}
}
}
if (!handled)
BView::KeyDown(bytes, numBytes);
else {
if (update)
_UpdateColors();
Invalidate();
}
}
// Draw
void
GradientControl::Draw(BRect updateRect)
{
BRect b = _GradientBitmapRect();
b.InsetBy(-2.0, -2.0);
// background
// left of gradient rect
BRect lb(updateRect.left, updateRect.top, b.left - 1, b.bottom);
if (lb.IsValid())
FillRect(lb, B_SOLID_LOW);
// right of gradient rect
BRect rb(b.right + 1, updateRect.top, updateRect.right, b.bottom);
if (rb.IsValid())
FillRect(rb, B_SOLID_LOW);
// bottom of gradient rect
BRect bb(updateRect.left, b.bottom + 1, updateRect.right, updateRect.bottom);
if (bb.IsValid())
FillRect(bb, B_SOLID_LOW);
bool isFocus = IsFocus() && Window()->IsActive();
rgb_color bg = LowColor();
rgb_color shadow;
rgb_color darkShadow;
rgb_color light;
rgb_color black;
if (fEnabled) {
shadow = tint_color(bg, B_DARKEN_1_TINT);
darkShadow = tint_color(bg, B_DARKEN_3_TINT);
light = tint_color(bg, B_LIGHTEN_MAX_TINT);
black = tint_color(bg, B_DARKEN_MAX_TINT);
} else {
shadow = bg;
darkShadow = tint_color(bg, B_DARKEN_1_TINT);
light = tint_color(bg, B_LIGHTEN_2_TINT);
black = tint_color(bg, B_DARKEN_2_TINT);
}
rgb_color focus = isFocus ? ui_color(B_KEYBOARD_NAVIGATION_COLOR)
: black;
stroke_frame(this, b, shadow, shadow, light, light);
b.InsetBy(1.0, 1.0);
if (isFocus)
stroke_frame(this, b, focus, focus, focus, focus);
else
stroke_frame(this, b, darkShadow, darkShadow, bg, bg);
b.InsetBy(1.0, 1.0);
// DrawBitmapAsync(fGradientBitmap, b.LeftTop());
// Sync();
DrawBitmap(fGradientBitmap, b.LeftTop());
// show drop offset
if (fDropOffset >= 0.0) {
SetHighColor(255, 0, 0, 255);
float x = b.left + b.Width() * fDropOffset;
StrokeLine(BPoint(x, b.top), BPoint(x, b.bottom));
}
BPoint markerPos;
markerPos.y = b.bottom + 4.0;
BPoint leftBottom(-6.0, 6.0);
BPoint rightBottom(6.0, 6.0);
for (int32 i = 0; color_step* step = fGradient->ColorAt(i); i++) {
markerPos.x = b.left + (b.Width() * step->offset);
if (i == fCurrentStepIndex) {
SetLowColor(focus);
if (isFocus) {
StrokeLine(markerPos + leftBottom + BPoint(1.0, 4.0),
markerPos + rightBottom + BPoint(-1.0, 4.0), B_SOLID_LOW);
}
} else {
SetLowColor(black);
}
// override in case this is the drop index step
if (i == fDropIndex)
SetLowColor(255, 0, 0, 255);
StrokeTriangle(markerPos,
markerPos + leftBottom,
markerPos + rightBottom, B_SOLID_LOW);
if (fEnabled) {
SetHighColor(step->color);
} else {
rgb_color c = step->color;
c.red = (uint8)(((uint32)bg.red + (uint32)c.red) / 2);
c.green = (uint8)(((uint32)bg.green + (uint32)c.green) / 2);
c.blue = (uint8)(((uint32)bg.blue + (uint32)c.blue) / 2);
SetHighColor(c);
}
FillTriangle(markerPos + BPoint(0.0, 1.0),
markerPos + leftBottom + BPoint(1.0, 0.0),
markerPos + rightBottom + BPoint(-1.0, 0.0));
StrokeLine(markerPos + leftBottom + BPoint(0.0, 1.0),
markerPos + rightBottom + BPoint(0.0, 1.0), B_SOLID_LOW);
}
}
// FrameResized
void
GradientControl::FrameResized(float width, float height)
{
BRect r = _GradientBitmapRect();
_AllocBitmap(r.IntegerWidth() + 1, r.IntegerHeight() + 1);
_UpdateColors();
Invalidate();
}
// SetGradient
void
GradientControl::SetGradient(const ::Gradient* gradient)
{
if (!gradient)
return;
*fGradient = *gradient;
_UpdateColors();
fDropOffset = -1.0;
fDropIndex = -1;
fDraggingStepIndex = -1;
fCurrentStepIndex = 0;
Invalidate();
}
// SetCurrentStop
void
GradientControl::SetCurrentStop(const rgb_color& color)
{
if (fEnabled && fCurrentStepIndex >= 0) {
fGradient->SetColor(fCurrentStepIndex, color);
_UpdateColors();
Invalidate();
}
}
// GetCurrentStop
bool
GradientControl::GetCurrentStop(rgb_color* color) const
{
color_step* stop = fGradient->ColorAt(fCurrentStepIndex);
if (stop && color) {
*color = stop->color;
return true;
}
return false;
}
// SetEnabled
void
GradientControl::SetEnabled(bool enabled)
{
if (enabled == fEnabled)
return;
fEnabled = enabled;
if (!fEnabled)
fDropIndex = -1;
_UpdateColors();
Invalidate();
}
// blend_colors
inline void
blend_colors(uint8* d, uint8 alpha, uint8 c1, uint8 c2, uint8 c3)
{
if (alpha > 0) {
if (alpha == 255) {
d[0] = c1;
d[1] = c2;
d[2] = c3;
} else {
d[0] += (uint8)(((c1 - d[0]) * alpha) >> 8);
d[1] += (uint8)(((c2 - d[1]) * alpha) >> 8);
d[2] += (uint8)(((c3 - d[2]) * alpha) >> 8);
}
}
}
// _UpdateColors
void
GradientControl::_UpdateColors()
{
if (!fGradientBitmap || !fGradientBitmap->IsValid())
return;
// fill in top row by gradient
uint8* topRow = (uint8*)fGradientBitmap->Bits();
uint32 width = fGradientBitmap->Bounds().IntegerWidth() + 1;
fGradient->MakeGradient((uint32*)topRow, width);
// flip colors, since they are the wrong endianess
// make colors the disabled look
// TODO: apply gamma lut
uint8* p = topRow;
if (!fEnabled) {
rgb_color bg = LowColor();
for (uint32 x = 0; x < width; x++) {
uint8 p0 = p[0];
p[0] = (uint8)(((uint32)bg.blue + (uint32)p[2]) / 2);
p[1] = (uint8)(((uint32)bg.green + (uint32)p[1]) / 2);
p[2] = (uint8)(((uint32)bg.red + (uint32)p0) / 2);
p += 4;
}
} else {
for (uint32 x = 0; x < width; x++) {
uint8 p0 = p[0];
p[0] = p[2];
p[2] = p0;
p += 4;
}
}
// copy top row to rest of bitmap
uint32 height = fGradientBitmap->Bounds().IntegerHeight() + 1;
uint32 bpr = fGradientBitmap->BytesPerRow();
uint8* dstRow = topRow + bpr;
for (uint32 i = 1; i < height; i++) {
memcpy(dstRow, topRow, bpr);
dstRow += bpr;
}
// post process bitmap to underlay it with a pattern
// in order to make gradient steps with alpha more visible!
uint8* row = topRow;
for (uint32 i = 0; i < height; i++) {
uint8* p = row;
for (uint32 x = 0; x < width; x++) {
uint8 alpha = p[3];
if (alpha < 255) {
p[3] = 255;
alpha = 255 - alpha;
if (x % 10 >= 5) {
if (i % 10 >= 5) {
blend_colors(p, alpha, kAlphaLow.blue, kAlphaLow.green, kAlphaLow.red);
} else {
blend_colors(p, alpha, kAlphaHigh.blue, kAlphaHigh.green, kAlphaHigh.red);
}
} else {
if (i % 10 >= 5) {
blend_colors(p, alpha, kAlphaHigh.blue, kAlphaHigh.green, kAlphaHigh.red);
} else {
blend_colors(p, alpha, kAlphaLow.blue, kAlphaLow.green, kAlphaLow.red);
}
}
}
p += 4;
}
row += bpr;
}
}
// _AllocBitmap
void
GradientControl::_AllocBitmap(int32 width, int32 height)
{
if (width < 2 || height < 2)
return;
delete fGradientBitmap;
fGradientBitmap = new BBitmap(BRect(0, 0, width - 1, height - 1), 0, B_RGB32);
}
// _GradientBitmapRect
BRect
GradientControl::_GradientBitmapRect() const
{
BRect r = Bounds();
r.left += 6.0;
r.top += 2.0;
r.right -= 6.0;
r.bottom -= 14.0;
return r;
}
// _StepIndexFor
int32
GradientControl::_StepIndexFor(BPoint where) const
{
int32 index = -1;
BRect r = _GradientBitmapRect();
BRect markerFrame(Bounds());
for (int32 i = 0; color_step* step = fGradient->ColorAt(i); i++) {
markerFrame.left = markerFrame.right = r.left + (r.Width() * step->offset);
markerFrame.InsetBy(-6.0, 0.0);
if (markerFrame.Contains(where)) {
index = i;
break;
}
}
return index;
}
// _OffsetFor
float
GradientControl::_OffsetFor(BPoint where) const
{
BRect r = _GradientBitmapRect();
float offset = (where.x - r.left) / r.Width();
offset = max_c(0.0, offset);
offset = min_c(1.0, offset);
return offset;
}
// _UpdateCurrentColor
void
GradientControl::_UpdateCurrentColor() const
{
if (!fMessage || !fTarget || !fTarget->Looper())
// set the CanvasView current color
if (color_step* step = fGradient->ColorAt(fCurrentStepIndex)) {
BMessage message(*fMessage);
store_color_in_message(&message, step->color);
fTarget->Looper()->PostMessage(&message, fTarget);
}
}
@@ -0,0 +1,90 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef GRADIENT_CONTROL_H
#define GRADIENT_CONTROL_H
#include <View.h>
#if LIB_LAYOUT
#include <layout.h>
#endif
class Gradient;
enum {
MSG_GRADIENT_CONTROL_FOCUS_CHANGED = 'gcfc',
};
class GradientControl :
#if LIB_LAYOUT
public MView,
#endif
public BView {
public:
GradientControl(BMessage* message = NULL,
BHandler* target = NULL);
virtual ~GradientControl();
// MView
#if LIB_LAYOUT
virtual minimax layoutprefs();
virtual BRect layout(BRect frame);
#endif
// BView
virtual void WindowActivated(bool active);
virtual void MakeFocus(bool focus);
virtual void MouseDown(BPoint where);
virtual void MouseUp(BPoint where);
virtual void MouseMoved(BPoint where, uint32 transit,
const BMessage* dragMessage);
virtual void MessageReceived(BMessage* message);
virtual void KeyDown(const char* bytes, int32 numBytes);
virtual void Draw(BRect updateRect);
virtual void FrameResized(float width, float height);
// GradientControl
void SetGradient(const ::Gradient* gradient);
::Gradient* Gradient() const
{ return fGradient; }
void SetCurrentStop(const rgb_color& color);
bool GetCurrentStop(rgb_color* color) const;
void SetEnabled(bool enabled);
bool IsEnabled() const
{ return fEnabled; }
private:
void _UpdateColors();
void _AllocBitmap(int32 width, int32 height);
BRect _GradientBitmapRect() const;
int32 _StepIndexFor(BPoint where) const;
float _OffsetFor(BPoint where) const;
void _UpdateCurrentColor() const;
::Gradient* fGradient;
BBitmap* fGradientBitmap;
int32 fDraggingStepIndex;
int32 fCurrentStepIndex;
float fDropOffset;
int32 fDropIndex;
bool fEnabled;
BMessage* fMessage;
BHandler* fTarget;
};
#endif // GRADIENT_CONTROL_H
@@ -94,7 +94,7 @@ IconObjectListView::ObjectChanged(const Observable* object)
_SetObject(dynamic_cast<IconObject*>(selected));
}
if (object == fObject && !fIgnoreObjectChange) {
if (object == fObject/* && !fIgnoreObjectChange*/) {
printf("IconObjectListView::ObjectChanged(fObject)\n");
SetTo(fObject->MakePropertyObject());
}
+271 -2
View File
@@ -8,13 +8,282 @@
#include "StyleView.h"
#include <Menu.h>
#include <MenuBar.h>
#include <MenuField.h>
#include <MenuItem.h>
#include <Message.h>
#include <PopUpMenu.h>
#include "CommandStack.h"
#include "Gradient.h"
#include "GradientControl.h"
#include "SetGradientCommand.h"
#include "Style.h"
enum {
MSG_SET_COLOR = 'stcl',
MSG_SET_STYLE_TYPE = 'stst',
MSG_SET_GRADIENT_TYPE = 'stgt',
};
enum {
STYLE_TYPE_COLOR = 0,
STYLE_TYPE_GRADIENT,
};
// constructor
StyleView::StyleView(BRect frame)
: BView(frame, "style view", B_FOLLOW_NONE, 0)
: BView(frame, "style view", B_FOLLOW_LEFT | B_FOLLOW_TOP, 0),
fCommandStack(NULL),
fStyle(NULL),
fGradient(NULL)
{
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
frame.OffsetTo(B_ORIGIN);
frame.InsetBy(5, 5);
frame.bottom = frame.top + 15;
// style type
BMenu* menu = new BPopUpMenu("<unavailable>");
BMessage* message = new BMessage(MSG_SET_STYLE_TYPE);
message->AddInt32("type", STYLE_TYPE_COLOR);
menu->AddItem(new BMenuItem("Color", message));
message = new BMessage(MSG_SET_STYLE_TYPE);
message->AddInt32("type", STYLE_TYPE_GRADIENT);
menu->AddItem(new BMenuItem("Gradient", message));
fStyleType = new BMenuField(frame, "style type", "Style Type",
menu, true);
AddChild(fStyleType);
float width;
float height;
fStyleType->MenuBar()->GetPreferredSize(&width, &height);
fStyleType->MenuBar()->ResizeTo(width, height);
fStyleType->ResizeTo(frame.Width(), height + 6);
// gradient type
menu = new BPopUpMenu("<unavailable>");
message = new BMessage(MSG_SET_GRADIENT_TYPE);
message->AddInt32("type", GRADIENT_LINEAR);
menu->AddItem(new BMenuItem("Linear", message));
message = new BMessage(MSG_SET_GRADIENT_TYPE);
message->AddInt32("type", GRADIENT_CIRCULAR);
menu->AddItem(new BMenuItem("Radial", message));
message = new BMessage(MSG_SET_GRADIENT_TYPE);
message->AddInt32("type", GRADIENT_DIAMONT);
menu->AddItem(new BMenuItem("Diamont", message));
message = new BMessage(MSG_SET_GRADIENT_TYPE);
message->AddInt32("type", GRADIENT_CONIC);
menu->AddItem(new BMenuItem("Conic", message));
frame.OffsetBy(0, fStyleType->Frame().Height() + 6);
fGradientType = new BMenuField(frame, "gradient type", "Gradient Type",
menu, true);
AddChild(fGradientType);
fGradientType->MenuBar()->GetPreferredSize(&width, &height);
fGradientType->MenuBar()->ResizeTo(width, height);
fGradientType->ResizeTo(frame.Width(), height + 6);
// create gradient control
frame.top = fGradientType->Frame().bottom + 8;
frame.right = Bounds().right - 5;
fGradientControl = new GradientControl(new BMessage(MSG_SET_COLOR),
this);
width = max_c(fGradientControl->Frame().Width(), frame.Width());
height = max_c(fGradientControl->Frame().Height(), 30);
fGradientControl->ResizeTo(width, height);
fGradientControl->FrameResized(width, height);
fGradientControl->MoveTo(frame.left, frame.top);
AddChild(fGradientControl);
fGradientControl->SetEnabled(false);
fGradientControl->Gradient()->AddObserver(this);
}
// destructor
StyleView::~StyleView()
{
SetStyle(NULL);
fGradientControl->Gradient()->RemoveObserver(this);
}
// AttachedToWindow
void
StyleView::AttachedToWindow()
{
fStyleType->Menu()->SetTargetForItems(this);
fGradientType->Menu()->SetTargetForItems(this);
}
// MessageReceived
void
StyleView::MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_SET_STYLE_TYPE: {
int32 type;
if (message->FindInt32("type", &type) == B_OK)
_SetStyleType(type);
break;
}
case MSG_SET_GRADIENT_TYPE: {
int32 type;
if (message->FindInt32("type", &type) == B_OK)
_SetGradientType(type);
break;
}
default:
BView::MessageReceived(message);
break;
}
}
// #pragma mark -
// ObjectChanged
void
StyleView::ObjectChanged(const Observable* object)
{
if (!fStyle)
return;
Gradient* controlGradient = fGradientControl->Gradient();
// NOTE: it is important to compare the gradients
// before assignment, or we will get into an endless loop
if (object == controlGradient) {
if (fGradient && *fGradient != *controlGradient) {
if (fCommandStack) {
fCommandStack->Perform(
new (nothrow) SetGradientCommand(
fStyle, controlGradient));
} else {
*fGradient = *controlGradient;
}
}
} else if (object == fGradient) {
if (*fGradient != *controlGradient) {
fGradientControl->SetGradient(fGradient);
_MarkType(fGradientType->Menu(), fGradient->Type());
}
} else if (object == fStyle) {
// maybe the gradient was added or removed
_SetGradient(fStyle->Gradient());
}
}
// #pragma mark -
// StyleView
void
StyleView::SetStyle(Style* style)
{
if (fStyle == style)
return;
if (fStyle)
fStyle->RemoveObserver(this);
fStyle = style;
Gradient* gradient = NULL;
if (fStyle) {
fStyle->AddObserver(this);
gradient = fStyle->Gradient();
}
_SetGradient(gradient);
}
// SetCommandStack
void
StyleView::SetCommandStack(CommandStack* stack)
{
fCommandStack = stack;
}
// #pragma mark -
// _SetGradient
void
StyleView::_SetGradient(Gradient* gradient)
{
if (fGradient == gradient)
return;
if (fGradient)
fGradient->RemoveObserver(this);
fGradient = gradient;
if (fGradient)
fGradient->AddObserver(this);
if (fGradient) {
fGradientControl->SetEnabled(true);
fGradientControl->SetGradient(fGradient);
fGradientType->SetEnabled(true);
_MarkType(fStyleType->Menu(), STYLE_TYPE_GRADIENT);
_MarkType(fGradientType->Menu(), fGradient->Type());
} else {
fGradientControl->SetEnabled(false);
fGradientType->SetEnabled(false);
_MarkType(fStyleType->Menu(), STYLE_TYPE_COLOR);
_MarkType(fGradientType->Menu(), -1);
}
}
// _MarkType
void
StyleView::_MarkType(BMenu* menu, int32 type) const
{
for (int32 i = 0; BMenuItem* item = menu->ItemAt(i); i++) {
BMessage* message = item->Message();
int32 t;
if (message->FindInt32("type", &t) == B_OK && t == type) {
item->SetMarked(true);
return;
}
}
}
// _SetStyleType
void
StyleView::_SetStyleType(int32 type)
{
if (!fStyle)
return;
if (type == STYLE_TYPE_COLOR) {
if (fCommandStack) {
fCommandStack->Perform(
new (nothrow) SetGradientCommand(fStyle, NULL));
} else {
fStyle->SetGradient(NULL);
}
} else if (type == STYLE_TYPE_GRADIENT) {
if (fCommandStack) {
fCommandStack->Perform(
new (nothrow) SetGradientCommand(
fStyle, fGradientControl->Gradient()));
} else {
fStyle->SetGradient(fGradientControl->Gradient());
}
}
}
// _SetGradientType
void
StyleView::_SetGradientType(int32 type)
{
fGradientControl->Gradient()->SetType((gradient_type)type);
}
+38 -1
View File
@@ -11,12 +11,49 @@
#include <View.h>
class StyleView : public {
#include "Observer.h"
class BMenuField;
class CommandStack;
class Gradient;
class GradientControl;
class Style;
// TODO: write lock the document when changing something...
class StyleView : public BView,
public Observer {
public:
StyleView(BRect frame);
virtual ~StyleView();
// BView interface
virtual void AttachedToWindow();
virtual void MessageReceived(BMessage* message);
// Observer interface
virtual void ObjectChanged(const Observable* object);
// StyleView
void SetStyle(Style* style);
void SetCommandStack(CommandStack* stack);
private:
void _SetGradient(Gradient* gradient);
void _MarkType(BMenu* menu,
int32 type) const;
void _SetStyleType(int32 type);
void _SetGradientType(int32 type);
CommandStack* fCommandStack;
Style* fStyle;
Gradient* fGradient;
GradientControl* fGradientControl;
BMenuField* fStyleType;
BMenuField* fGradientType;
};
#endif // STYLE_VIEW_H
@@ -0,0 +1,105 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#include "SetGradientCommand.h"
#include <new>
#include <stdio.h>
#include "Gradient.h"
#include "Style.h"
using std::nothrow;
// constructor
SetGradientCommand::SetGradientCommand(Style* style,
const Gradient* gradient)
: Command(),
fStyle(style),
fGradient(gradient ? new (nothrow) Gradient(*gradient) : NULL)
{
}
// destructor
SetGradientCommand::~SetGradientCommand()
{
delete fGradient;
}
// InitCheck
status_t
SetGradientCommand::InitCheck()
{
return fStyle ? B_OK : B_NO_INIT;
}
// Perform
status_t
SetGradientCommand::Perform()
{
// clone the new gradient for handling over to the style
Gradient* clone = NULL;
if (fGradient) {
clone = new (nothrow) Gradient(*fGradient);
if (!clone)
return B_NO_MEMORY;
}
if (fStyle->Gradient()) {
// remember the current gradient of the style
if (fGradient)
*fGradient = *fStyle->Gradient();
else {
fGradient = new (nothrow) Gradient(*fStyle->Gradient());
if (!fGradient)
return B_NO_MEMORY;
}
} else {
// the style didn't have a gradient set
delete fGradient;
fGradient = NULL;
}
// remove the gradient or set the new one
fStyle->SetGradient(clone);
delete clone;
return B_OK;
}
// Undo
status_t
SetGradientCommand::Undo()
{
return Perform();
}
// GetName
void
SetGradientCommand::GetName(BString& name)
{
name << _GetString(/*EDIT_GRADIENT*/0, "Edit Gradient");
}
// CombineWithNext
bool
SetGradientCommand::CombineWithNext(const Command* command)
{
const SetGradientCommand* next
= dynamic_cast<const SetGradientCommand*>(command);
if (next && next->fTimeStamp - fTimeStamp < 1000000) {
fTimeStamp = next->fTimeStamp;
// NOTE: next was already performed, but
// when undoing, we want to use our
// remembered gradient
return true;
}
return false;
}
@@ -0,0 +1,37 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <[email protected]>
*/
#ifndef SET_GRADIENT_COMMAND_H
#define SET_GRADIENT_COMMAND_H
#include "Command.h"
class Gradient;
class Style;
class SetGradientCommand : public Command {
public:
SetGradientCommand(Style* style,
const Gradient* gradient);
virtual ~SetGradientCommand();
virtual status_t InitCheck();
virtual status_t Perform();
virtual status_t Undo();
virtual void GetName(BString& name);
virtual bool CombineWithNext(const Command* next);
private:
Style* fStyle;
Gradient* fGradient;
};
#endif // CHANGE_GRADIENT_COMMAND_H
+25 -13
View File
@@ -8,8 +8,12 @@
#include "Style.h"
#include <new>
#include "Gradient.h"
using std::nothrow;
// constructor
Style::Style()
: IconObject("<style>"),
@@ -52,23 +56,31 @@ Style::SetColor(const rgb_color& color)
// SetGradient
void
Style::SetGradient(::Gradient* gradient)
Style::SetGradient(const ::Gradient* gradient)
{
if (fGradient) {
fGradient->RemoveObserver(this);
delete fGradient;
}
if (!fGradient && !gradient)
return;
fGradient = gradient;
if (fGradient) {
fGradient->AddObserver(this);
// generate gradient
if (!fColors)
fColors = new agg::rgba8[256];
fGradient->MakeGradient((uint32*)fColors, 256);
if (gradient) {
if (!fGradient) {
fGradient = new (nothrow) ::Gradient(*gradient);
if (fGradient) {
fGradient->AddObserver(this);
// generate gradient
fColors = new agg::rgba8[256];
fGradient->MakeGradient((uint32*)fColors, 256);
Notify();
}
} else {
if (*fGradient != *gradient) {
*fGradient = *gradient;
}
}
} else {
fGradient->RemoveObserver(this);
delete[] fColors;
fColors = NULL;
fGradient = NULL;
Notify();
}
}
+1 -1
View File
@@ -33,7 +33,7 @@ class Style : public IconObject,
inline rgb_color Color() const
{ return fColor; }
void SetGradient(::Gradient* gradient);
void SetGradient(const ::Gradient* gradient);
::Gradient* Gradient() const
{ return fGradient; }
@@ -93,8 +93,10 @@ StrokeTransformer::MakePropertyObject() const
object->AddProperty(property);
// miter limit
object->AddProperty(new FloatProperty(PROPERTY_MITER_LIMIT,
miter_limit()));
if (line_join() == agg::miter_join) {
object->AddProperty(new FloatProperty(PROPERTY_MITER_LIMIT,
miter_limit()));
}
return object;
}