From 9b4fa889fd63d9f22bffcf743dc22f25eef8ebd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Tue, 4 Jul 2006 00:04:50 +0000 Subject: [PATCH] * the path list view shows check boxes now when a shape is selected, the marked paths are used in the shape * a new path is auto-selected * deselecting a shape still sends the selection message * PathSource does not call agg::path_storage::start_new_path() for each subpath... a move_to() is sufficient and makes sure the subpaths are rendered even :-) * updated NOTES * moved IconView into gui subfolder git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18021 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/icon-o-matic/MainWindow.cpp | 11 +- src/apps/icon-o-matic/NOTES | 22 +- src/apps/icon-o-matic/{ => gui}/IconView.cpp | 0 src/apps/icon-o-matic/{ => gui}/IconView.h | 0 src/apps/icon-o-matic/gui/PathListView.cpp | 283 +++++++++++++++++- src/apps/icon-o-matic/gui/PathListView.h | 22 ++ src/apps/icon-o-matic/gui/ShapeListView.cpp | 4 +- .../icon-o-matic/transformer/PathSource.cpp | 8 +- 8 files changed, 325 insertions(+), 25 deletions(-) rename src/apps/icon-o-matic/{ => gui}/IconView.cpp (100%) rename src/apps/icon-o-matic/{ => gui}/IconView.h (100%) diff --git a/src/apps/icon-o-matic/MainWindow.cpp b/src/apps/icon-o-matic/MainWindow.cpp index 3511a667fb..a88dae3854 100644 --- a/src/apps/icon-o-matic/MainWindow.cpp +++ b/src/apps/icon-o-matic/MainWindow.cpp @@ -45,6 +45,7 @@ enum { MSG_NEW_PATH = 'nwvp', MSG_PATH_SELECTED = 'vpsl', + MSG_SHAPE_SELECTED = 'spsl', }; // constructor @@ -100,6 +101,13 @@ case MSG_PATH_SELECTED: { } break; } +case MSG_SHAPE_SELECTED: { + Shape* shape; + if (message->FindPointer("shape", (void**)&shape) < B_OK) + shape = NULL; + fPathListView->SetCurrentShape(shape); + break; +} default: BWindow::MessageReceived(message); @@ -291,7 +299,8 @@ MainWindow::_CreateGUI(BRect bounds) new BMessage(MSG_PATH_SELECTED), this); bounds.OffsetBy(bounds.Width() + 6 + B_V_SCROLL_BAR_WIDTH, 0); - fShapeListView = new ShapeListView(bounds, "shape list view"); + fShapeListView = new ShapeListView(bounds, "shape list view", + new BMessage(MSG_SHAPE_SELECTED), this); bg->AddChild(fSwatchGroup); diff --git a/src/apps/icon-o-matic/NOTES b/src/apps/icon-o-matic/NOTES index 5012da0f16..5383a612ff 100644 --- a/src/apps/icon-o-matic/NOTES +++ b/src/apps/icon-o-matic/NOTES @@ -15,21 +15,33 @@ different paths showing at the same time... * solve the problem of individual gradient transformation per shape + -> introduce "StyleInstance", a Shape would not reference a Style + directly but via a StyleInstance... this object can have additional + information like the gradient transformation * IconRenderer should construct a separate StyleManager and append the styles in the order of shapes, also adding styles multiple times, if two or more shapes use the same style (the compound shape - rendering uses the style index for z ordering) + rendering uses the style index for z ordering) [done] + +* add more functionality to Transformer/VertexSource interface: + - (inverse) Transformation + - Cloning + +* add more powerful listener interface to Shape + (TransformerAdded()/Removed()...) + +* implement commands for the newly added editing features --------- user interface -* list of global vector paths +* list of global vector paths [done] -* list of shapes +* list of shapes [done] * list of paths used by shape, but it could also be done such that - used paths are marked in the global list when a shape is selected + used paths are marked in the global list when a shape is selected [done] * list of transformers attached to the selected shape @@ -40,12 +52,12 @@ * 192 "built-in" (pre-defined) style definitions * up to 64 additional style definitions per document +* referencing of fill style by uint8 id * solid colors and different types of gradients * uint8 precision for coordinates on a 64x64 virtual pixel grid (* removal (freezing) of transformations at export time not sure about this one, it would remove the possiblity to store vector path only once for referenced objects) -* referencing of fill style by uint8 id * IFF type chunk format diff --git a/src/apps/icon-o-matic/IconView.cpp b/src/apps/icon-o-matic/gui/IconView.cpp similarity index 100% rename from src/apps/icon-o-matic/IconView.cpp rename to src/apps/icon-o-matic/gui/IconView.cpp diff --git a/src/apps/icon-o-matic/IconView.h b/src/apps/icon-o-matic/gui/IconView.h similarity index 100% rename from src/apps/icon-o-matic/IconView.h rename to src/apps/icon-o-matic/gui/IconView.h diff --git a/src/apps/icon-o-matic/gui/PathListView.cpp b/src/apps/icon-o-matic/gui/PathListView.cpp index 5ef57e1cd1..1e59347371 100644 --- a/src/apps/icon-o-matic/gui/PathListView.cpp +++ b/src/apps/icon-o-matic/gui/PathListView.cpp @@ -18,16 +18,25 @@ #include "VectorPath.h" #include "Observer.h" +#include "Shape.h" +#include "ShapeContainer.h" #include "Selection.h" +static const float kMarkWidth = 14.0; +static const float kBorderOffset = 3.0; +static const float kTextOffset = 4.0; + class PathListItem : public SimpleItem, public Observer { public: PathListItem(VectorPath* p, - PathListView* listView) + PathListView* listView, + bool markEnabled) : SimpleItem(""), path(NULL), - fListView(listView) + fListView(listView), + fMarkEnabled(markEnabled), + fMarked(false) { SetPath(p); } @@ -37,11 +46,63 @@ class PathListItem : public SimpleItem, SetPath(NULL); } + // SimpleItem interface + virtual void Draw(BView* owner, BRect itemFrame, uint32 flags) + { + SimpleItem::DrawBackground(owner, itemFrame, flags); + + // text + owner->SetHighColor(0, 0, 0, 255); + font_height fh; + owner->GetFontHeight(&fh); + BString truncatedString(Text()); + owner->TruncateString(&truncatedString, B_TRUNCATE_MIDDLE, + itemFrame.Width() + - kBorderOffset + - kMarkWidth + - kTextOffset + - kBorderOffset); + float height = itemFrame.Height(); + float textHeight = fh.ascent + fh.descent; + BPoint pos; + pos.x = itemFrame.left + + kBorderOffset + kMarkWidth + kTextOffset; + pos.y = itemFrame.top + + ceilf((height - textHeight) / 2.0 + fh.ascent); + owner->DrawString(truncatedString.String(), pos); + + if (!fMarkEnabled) + return; + + // mark + BRect markRect = itemFrame; + markRect.left += kBorderOffset; + markRect.right = markRect.left + kMarkWidth; + markRect.top = (markRect.top + markRect.bottom - kMarkWidth) / 2.0; + markRect.bottom = markRect.top + kMarkWidth; + owner->SetHighColor(tint_color(owner->LowColor(), B_DARKEN_1_TINT)); + owner->StrokeRect(markRect); + markRect.InsetBy(1, 1); + owner->SetHighColor(tint_color(owner->LowColor(), 1.04)); + owner->FillRect(markRect); + if (fMarked) { + markRect.InsetBy(2, 2); + owner->SetHighColor(tint_color(owner->LowColor(), + B_DARKEN_4_TINT)); + owner->SetPenSize(2); + owner->StrokeLine(markRect.LeftTop(), markRect.RightBottom()); + owner->StrokeLine(markRect.LeftBottom(), markRect.RightTop()); + owner->SetPenSize(1); + } + } + + // Observer interface virtual void ObjectChanged(const Observable* object) { UpdateText(); } + // PathListItem void SetPath(VectorPath* p) { if (p == path) @@ -63,17 +124,92 @@ class PathListItem : public SimpleItem, void UpdateText() { SetText(path->Name()); - // :-/ - if (fListView->LockLooper()) { - fListView->InvalidateItem( - fListView->IndexOf(this)); - fListView->UnlockLooper(); - } + Invalidate(); } + void SetMarkEnabled(bool enabled) + { + if (fMarkEnabled == enabled) + return; + fMarkEnabled = enabled; + Invalidate(); + } + void SetMarked(bool marked) + { + if (fMarked == marked) + return; + fMarked = marked; + Invalidate(); + } + + void Invalidate() + { + // :-/ + if (fListView->LockLooper()) { + fListView->InvalidateItem( + fListView->IndexOf(this)); + fListView->UnlockLooper(); + } + } + VectorPath* path; private: PathListView* fListView; + bool fMarkEnabled; + bool fMarked; +}; + + +class ShapePathListener : public PathContainerListener, + public ShapeContainerListener { + public: + ShapePathListener(PathListView* listView) + : fListView(listView), + fShape(NULL) + { + } + virtual ~ShapePathListener() + { + SetShape(NULL); + } + + virtual void PathAdded(VectorPath* path) + { + fListView->_SetPathMarked(path, true); + } + virtual void PathRemoved(VectorPath* path) + { + fListView->_SetPathMarked(path, false); + } + + virtual void ShapeAdded(Shape* shape, int32 index) {} + virtual void ShapeRemoved(Shape* shape) + { + fListView->SetCurrentShape(NULL); + } + + void SetShape(Shape* shape) + { + if (fShape == shape) + return; + + if (fShape) + fShape->Paths()->RemoveListener(this); + + fShape = shape; + + if (fShape) + fShape->Paths()->AddListener(this); + } + + Shape* CurrentShape() const + { + return fShape; + } + + private: + PathListView* fListView; + Shape* fShape; }; // #pragma mark - @@ -86,7 +222,12 @@ PathListView::PathListView(BRect frame, NULL, B_SINGLE_SELECTION_LIST), fMessage(message), fPathContainer(NULL), - fSelection(NULL) + fShapeContainer(NULL), + fSelection(NULL), + fCommandStack(NULL), + + fCurrentShape(NULL), + fShapePathListener(new ShapePathListener(this)) { SetTarget(target); } @@ -99,6 +240,11 @@ PathListView::~PathListView() if (fPathContainer) fPathContainer->RemoveListener(this); + + if (fShapeContainer) + fShapeContainer->RemoveListener(fShapePathListener); + + delete fShapePathListener; } // SelectionChanged @@ -125,6 +271,49 @@ PathListView::SelectionChanged() // fSelection->DeselectAll(); } +// MouseDown +void +PathListView::MouseDown(BPoint where) +{ + if (!fCurrentShape) { + SimpleListView::MouseDown(where); + return; + } + + bool handled = false; + int32 index = IndexOf(where); + PathListItem* item = dynamic_cast(ItemAt(index)); + if (item) { + BRect itemFrame(ItemFrame(index)); + itemFrame.right = itemFrame.left + + kBorderOffset + kMarkWidth + + kTextOffset / 2.0; + VectorPath* path = item->path; + if (itemFrame.Contains(where)) { + // add or remove the path to the shape +// TODO: code these commands... +// Command* command; +// if (fCurrentShape->Paths()->HasPath(path)) { +// command = new RemovePathFromShapeCommand( +// fCurrentShape, path); +// } else { +// command = new AddPathToShapeCommand( +// fCurrentShape, path); +// } +// fCommandStack->Perform(command); +if (fCurrentShape->Paths()->HasPath(path)) { + fCurrentShape->Paths()->RemovePath(path); +} else { + fCurrentShape->Paths()->AddPath(path); +} + handled = true; + } + } + + if (!handled) + SimpleListView::MouseDown(where); +} + // MessageReceived void PathListView::MessageReceived(BMessage* message) @@ -176,7 +365,8 @@ PathListView::CloneItem(int32 index) const { if (PathListItem* item = dynamic_cast(ItemAt(index))) { return new PathListItem(item->path, - const_cast(this)); + const_cast(this), + fCurrentShape != NULL); } return NULL; } @@ -196,7 +386,8 @@ PathListView::PathAdded(VectorPath* path) // NOTE: shapes are always added at the end // of the list, so the sorting is synced... - _AddPath(path); + if (_AddPath(path)) + Select(CountItems() - 1); UnlockLooper(); } @@ -251,6 +442,23 @@ PathListView::SetPathContainer(PathContainer* container) // fPathContainer->ReadUnlock(); } +// SetShapeContainer +void +PathListView::SetShapeContainer(ShapeContainer* container) +{ + if (fShapeContainer == container) + return; + + // detach from old container + if (fShapeContainer) + fShapeContainer->RemoveListener(fShapePathListener); + + fShapeContainer = container; + + if (fShapeContainer) + fShapeContainer->AddListener(fShapePathListener); +} + // SetSelection void PathListView::SetSelection(Selection* selection) @@ -258,6 +466,19 @@ PathListView::SetSelection(Selection* selection) fSelection = selection; } +// SetCurrentShape +void +PathListView::SetCurrentShape(Shape* shape) +{ + if (fCurrentShape == shape) + return; + + fCurrentShape = shape; + fShapePathListener->SetShape(shape); + + _UpdateMarks(); +} + // #pragma mark - // _AddPath @@ -265,7 +486,7 @@ bool PathListView::_AddPath(VectorPath* path) { if (path) - return AddItem(new PathListItem(path, this)); + return AddItem(new PathListItem(path, this, fCurrentShape != NULL)); return false; } @@ -306,3 +527,41 @@ PathListView::_MakeEmpty() delete RemoveItem(i); } +// #pragma mark - + +// _UpdateMarks +void +PathListView::_UpdateMarks() +{ + int32 count = CountItems(); + if (fCurrentShape) { + // enable display of marks and mark items whoes + // path is contained in fCurrentShape + for (int32 i = 0; i < count; i++) { + PathListItem* item = dynamic_cast(ItemAt(i)); + if (!item) + continue; + item->SetMarkEnabled(true); + item->SetMarked(fCurrentShape->Paths()->HasPath(item->path)); + } + } else { + // disable display of marks + for (int32 i = 0; i < count; i++) { + PathListItem* item = dynamic_cast(ItemAt(i)); + if (!item) + continue; + item->SetMarkEnabled(false); + } + } + + Invalidate(); +} + +// _SetPathMarked +void +PathListView::_SetPathMarked(VectorPath* path, bool marked) +{ + if (PathListItem* item = _ItemForPath(path)) { + item->SetMarked(marked); + } +} diff --git a/src/apps/icon-o-matic/gui/PathListView.h b/src/apps/icon-o-matic/gui/PathListView.h index 152ff5db59..3ddbbfe8a7 100644 --- a/src/apps/icon-o-matic/gui/PathListView.h +++ b/src/apps/icon-o-matic/gui/PathListView.h @@ -12,9 +12,13 @@ #include "ListViews.h" #include "PathContainer.h" +class CommandStack; class VectorPath; class PathListItem; class Selection; +class Shape; +class ShapeContainer; +class ShapePathListener; class PathListView : public SimpleListView, public PathContainerListener { @@ -28,6 +32,7 @@ class PathListView : public SimpleListView, // SimpleListView interface virtual void SelectionChanged(); + virtual void MouseDown(BPoint where); virtual void MessageReceived(BMessage* message); virtual void MakeDragMessage(BMessage* message) const; @@ -48,8 +53,13 @@ class PathListView : public SimpleListView, // PathListView void SetPathContainer(PathContainer* container); + void SetShapeContainer(ShapeContainer* container); void SetSelection(Selection* selection); + void SetCurrentShape(Shape* shape); + Shape* CurrentShape() const + { return fCurrentShape; } + private: bool _AddPath(VectorPath* path); bool _RemovePath(VectorPath* path); @@ -57,10 +67,22 @@ class PathListView : public SimpleListView, PathListItem* _ItemForPath(VectorPath* path) const; void _MakeEmpty(); + friend class ShapePathListener; + void _UpdateMarks(); + void _SetPathMarked(VectorPath* path, bool marked); + BMessage* fMessage; PathContainer* fPathContainer; + ShapeContainer* fShapeContainer; Selection* fSelection; + CommandStack* fCommandStack; + + Shape* fCurrentShape; + // those path items will be marked that + // are referenced by this shape + + ShapePathListener* fShapePathListener; }; #endif // PATH_LIST_VIEW_H diff --git a/src/apps/icon-o-matic/gui/ShapeListView.cpp b/src/apps/icon-o-matic/gui/ShapeListView.cpp index d761a5ca0c..ceec56ffb8 100644 --- a/src/apps/icon-o-matic/gui/ShapeListView.cpp +++ b/src/apps/icon-o-matic/gui/ShapeListView.cpp @@ -120,9 +120,9 @@ ShapeListView::SelectionChanged() // TODO: single selection versus multiple selection ShapeListItem* item = dynamic_cast(ItemAt(CurrentSelection(0))); - if (item && fMessage) { + if (fMessage) { BMessage message(*fMessage); - message.AddPointer("shape", (void*)item->shape); + message.AddPointer("shape", item ? (void*)item->shape : NULL); Invoke(&message); } diff --git a/src/apps/icon-o-matic/transformer/PathSource.cpp b/src/apps/icon-o-matic/transformer/PathSource.cpp index 15cc7a2e28..e129932063 100644 --- a/src/apps/icon-o-matic/transformer/PathSource.cpp +++ b/src/apps/icon-o-matic/transformer/PathSource.cpp @@ -44,11 +44,9 @@ void PathSource::Update() { fAGGPath.remove_all(); + int32 count = fPaths->CountPaths(); - for (int32 i = 0; i < count; i++) { - VectorPath* path = fPaths->PathAtFast(i); - fAGGPath.start_new_path(); - path->GetAGGPathStorage(fAGGPath); - } + for (int32 i = 0; i < count; i++) + fPaths->PathAtFast(i)->GetAGGPathStorage(fAGGPath); }