From 2205ee09148c5472af4cecc2b4cc15a65d643c1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Mon, 10 Jul 2006 21:36:46 +0000 Subject: [PATCH] * 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 --- src/apps/icon-o-matic/Jamfile | 3 + src/apps/icon-o-matic/MainWindow.cpp | 22 +- src/apps/icon-o-matic/MainWindow.h | 2 + src/apps/icon-o-matic/NOTES | 6 +- src/apps/icon-o-matic/gui/GradientControl.cpp | 634 ++++++++++++++++++ src/apps/icon-o-matic/gui/GradientControl.h | 90 +++ .../icon-o-matic/gui/IconObjectListView.cpp | 2 +- src/apps/icon-o-matic/gui/StyleView.cpp | 273 +++++++- src/apps/icon-o-matic/gui/StyleView.h | 39 +- .../icon-o-matic/style/SetGradientCommand.cpp | 105 +++ .../icon-o-matic/style/SetGradientCommand.h | 37 + src/apps/icon-o-matic/style/Style.cpp | 38 +- src/apps/icon-o-matic/style/Style.h | 2 +- .../transformer/StrokeTransformer.cpp | 6 +- 14 files changed, 1233 insertions(+), 26 deletions(-) create mode 100644 src/apps/icon-o-matic/gui/GradientControl.cpp create mode 100644 src/apps/icon-o-matic/gui/GradientControl.h create mode 100644 src/apps/icon-o-matic/style/SetGradientCommand.cpp create mode 100644 src/apps/icon-o-matic/style/SetGradientCommand.h diff --git a/src/apps/icon-o-matic/Jamfile b/src/apps/icon-o-matic/Jamfile index 5196f802ea..b6e32cd733 100644 --- a/src/apps/icon-o-matic/Jamfile +++ b/src/apps/icon-o-matic/Jamfile @@ -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 diff --git a/src/apps/icon-o-matic/MainWindow.cpp b/src/apps/icon-o-matic/MainWindow.cpp index 6d25ebcc04..377482d2ad 100644 --- a/src/apps/icon-o-matic/MainWindow.cpp +++ b/src/apps/icon-o-matic/MainWindow.cpp @@ -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; diff --git a/src/apps/icon-o-matic/MainWindow.h b/src/apps/icon-o-matic/MainWindow.h index c5f45d0ffc..21f36fc4bc 100644 --- a/src/apps/icon-o-matic/MainWindow.h +++ b/src/apps/icon-o-matic/MainWindow.h @@ -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; diff --git a/src/apps/icon-o-matic/NOTES b/src/apps/icon-o-matic/NOTES index a5c55ebd5b..fb531693d1 100644 --- a/src/apps/icon-o-matic/NOTES +++ b/src/apps/icon-o-matic/NOTES @@ -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 diff --git a/src/apps/icon-o-matic/gui/GradientControl.cpp b/src/apps/icon-o-matic/gui/GradientControl.cpp new file mode 100644 index 0000000000..c286f72348 --- /dev/null +++ b/src/apps/icon-o-matic/gui/GradientControl.cpp @@ -0,0 +1,634 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#include "GradientControl.h" + +#include + +#include +#include +#include +#include + +#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); + } +} diff --git a/src/apps/icon-o-matic/gui/GradientControl.h b/src/apps/icon-o-matic/gui/GradientControl.h new file mode 100644 index 0000000000..16bdb8d367 --- /dev/null +++ b/src/apps/icon-o-matic/gui/GradientControl.h @@ -0,0 +1,90 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#ifndef GRADIENT_CONTROL_H +#define GRADIENT_CONTROL_H + +#include + +#if LIB_LAYOUT +#include +#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 diff --git a/src/apps/icon-o-matic/gui/IconObjectListView.cpp b/src/apps/icon-o-matic/gui/IconObjectListView.cpp index d3b1a26eda..f644cad077 100644 --- a/src/apps/icon-o-matic/gui/IconObjectListView.cpp +++ b/src/apps/icon-o-matic/gui/IconObjectListView.cpp @@ -94,7 +94,7 @@ IconObjectListView::ObjectChanged(const Observable* object) _SetObject(dynamic_cast(selected)); } - if (object == fObject && !fIgnoreObjectChange) { + if (object == fObject/* && !fIgnoreObjectChange*/) { printf("IconObjectListView::ObjectChanged(fObject)\n"); SetTo(fObject->MakePropertyObject()); } diff --git a/src/apps/icon-o-matic/gui/StyleView.cpp b/src/apps/icon-o-matic/gui/StyleView.cpp index 9dfebfedb7..bd0d270b9c 100644 --- a/src/apps/icon-o-matic/gui/StyleView.cpp +++ b/src/apps/icon-o-matic/gui/StyleView.cpp @@ -8,13 +8,282 @@ #include "StyleView.h" +#include +#include +#include +#include +#include +#include + +#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(""); + 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(""); + 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); +} diff --git a/src/apps/icon-o-matic/gui/StyleView.h b/src/apps/icon-o-matic/gui/StyleView.h index 5b40eeff26..2c7f3b2488 100644 --- a/src/apps/icon-o-matic/gui/StyleView.h +++ b/src/apps/icon-o-matic/gui/StyleView.h @@ -11,12 +11,49 @@ #include -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 diff --git a/src/apps/icon-o-matic/style/SetGradientCommand.cpp b/src/apps/icon-o-matic/style/SetGradientCommand.cpp new file mode 100644 index 0000000000..f8a1b9c95a --- /dev/null +++ b/src/apps/icon-o-matic/style/SetGradientCommand.cpp @@ -0,0 +1,105 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#include "SetGradientCommand.h" + +#include +#include + +#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(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; +} + diff --git a/src/apps/icon-o-matic/style/SetGradientCommand.h b/src/apps/icon-o-matic/style/SetGradientCommand.h new file mode 100644 index 0000000000..1691279664 --- /dev/null +++ b/src/apps/icon-o-matic/style/SetGradientCommand.h @@ -0,0 +1,37 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#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 diff --git a/src/apps/icon-o-matic/style/Style.cpp b/src/apps/icon-o-matic/style/Style.cpp index d7fce826cb..14f7163a65 100644 --- a/src/apps/icon-o-matic/style/Style.cpp +++ b/src/apps/icon-o-matic/style/Style.cpp @@ -8,8 +8,12 @@ #include "Style.h" +#include + #include "Gradient.h" +using std::nothrow; + // constructor Style::Style() : IconObject("