From cfda5dd75bf4c1cae5b1aa808f37b59da114be26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Fri, 30 Jun 2006 21:39:18 +0000 Subject: [PATCH] * work in progress on GUI classes - added IconView which just uses an IconRenderer to display a preview of the icon at a certain size - PathListView and ShapeListView (very much work in progress) * actually had the gamma correction applied in the wrong direction... now the anti-aliasing looks as smooth as planned * added SetName() and Name() to Shape and VectorPath... will be in a common base class later on git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17988 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/icon-o-matic/IconView.cpp | 99 +++++ src/apps/icon-o-matic/IconView.h | 44 +++ src/apps/icon-o-matic/Jamfile | 5 + src/apps/icon-o-matic/MainWindow.cpp | 71 +++- src/apps/icon-o-matic/MainWindow.h | 11 + .../icon-o-matic/document/IconRenderer.cpp | 32 +- src/apps/icon-o-matic/document/IconRenderer.h | 19 +- .../icon-o-matic/generic/gui/ListViews.cpp | 237 ++++++------ src/apps/icon-o-matic/generic/gui/ListViews.h | 67 ++-- src/apps/icon-o-matic/gui/PathListView.cpp | 308 ++++++++++++++++ src/apps/icon-o-matic/gui/PathListView.h | 66 ++++ src/apps/icon-o-matic/gui/ShapeListView.cpp | 340 ++++++++++++++++++ src/apps/icon-o-matic/gui/ShapeListView.h | 66 ++++ src/apps/icon-o-matic/shape/Shape.cpp | 35 +- src/apps/icon-o-matic/shape/Shape.h | 11 + src/apps/icon-o-matic/shape/VectorPath.cpp | 110 ++++-- src/apps/icon-o-matic/shape/VectorPath.h | 7 + 17 files changed, 1324 insertions(+), 204 deletions(-) create mode 100644 src/apps/icon-o-matic/IconView.cpp create mode 100644 src/apps/icon-o-matic/IconView.h create mode 100644 src/apps/icon-o-matic/gui/PathListView.cpp create mode 100644 src/apps/icon-o-matic/gui/PathListView.h create mode 100644 src/apps/icon-o-matic/gui/ShapeListView.cpp create mode 100644 src/apps/icon-o-matic/gui/ShapeListView.h diff --git a/src/apps/icon-o-matic/IconView.cpp b/src/apps/icon-o-matic/IconView.cpp new file mode 100644 index 0000000000..71229c4a21 --- /dev/null +++ b/src/apps/icon-o-matic/IconView.cpp @@ -0,0 +1,99 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#include "IconView.h" + +#include + +#include "ui_defines.h" + +#include "IconRenderer.h" + +// constructor +IconView::IconView(BRect frame, const char* name) + : BView(frame, name, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW), + fBitmap(new BBitmap(frame.OffsetToCopy(B_ORIGIN), 0, B_RGB32)), + fIcon(NULL), + fRenderer(new IconRenderer(fBitmap)), + fDirtyIconArea(fBitmap->Bounds()), + + fScale((frame.Width() + 1.0) / 64.0) +{ + fRenderer->SetScale(fScale); +} + +// destructor +IconView::~IconView() +{ + SetIcon(NULL); + delete fRenderer; + delete fBitmap; +} + +// #pragma mark - + +// AttachedToWindow +void +IconView::AttachedToWindow() +{ + SetViewColor(B_TRANSPARENT_COLOR); +} + +// Draw +void +IconView::Draw(BRect updateRect) +{ + if (fDirtyIconArea.IsValid()) { + fRenderer->Render(fDirtyIconArea); + fDirtyIconArea.Set(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN); + } + + // icon + DrawBitmap(fBitmap, B_ORIGIN); +} + +// #pragma mark - + +// AreaInvalidated +void +IconView::AreaInvalidated(const BRect& area) +{ + BRect scaledArea(area); + scaledArea.left *= fScale; + scaledArea.top *= fScale; + scaledArea.right *= fScale; + scaledArea.bottom *= fScale; + + if (fDirtyIconArea.Contains(scaledArea)) + return; + + fDirtyIconArea = fDirtyIconArea | scaledArea; + + Invalidate(scaledArea); +} + + +// #pragma mark - + +// SetIcon +void +IconView::SetIcon(Icon* icon) +{ + if (fIcon == icon) + return; + + if (fIcon) + fIcon->RemoveListener(this); + + fIcon = icon; + fRenderer->SetIcon(icon); + + if (fIcon) + fIcon->AddListener(this); +} + diff --git a/src/apps/icon-o-matic/IconView.h b/src/apps/icon-o-matic/IconView.h new file mode 100644 index 0000000000..5face1a6f1 --- /dev/null +++ b/src/apps/icon-o-matic/IconView.h @@ -0,0 +1,44 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#ifndef ICON_VIEW_H +#define ICON_VIEW_H + +#include + +#include "Icon.h" + +class BBitmap; +class IconRenderer; + +class IconView : public BView, + public IconListener { + public: + IconView(BRect frame, const char* name); + virtual ~IconView(); + + // BView interface + virtual void AttachedToWindow(); + virtual void Draw(BRect updateRect); + + // IconListener interface + virtual void AreaInvalidated(const BRect& area); + + // IconView + void SetIcon(Icon* icon); + + private: + BBitmap* fBitmap; + Icon* fIcon; + IconRenderer* fRenderer; + BRect fDirtyIconArea; + + double fScale; +}; + +#endif // ICON_VIEW_H diff --git a/src/apps/icon-o-matic/Jamfile b/src/apps/icon-o-matic/Jamfile index 62719e3aa5..cd4c32ac33 100644 --- a/src/apps/icon-o-matic/Jamfile +++ b/src/apps/icon-o-matic/Jamfile @@ -41,10 +41,12 @@ Application Icon-O-Matic : # generic/command Command.cpp CommandStack.cpp + # generic/selection Selectable.cpp Selection.cpp # generic/gui Group.cpp + ListViews.cpp SwatchView.cpp # generic/gui/panel Panel.cpp @@ -70,6 +72,8 @@ Application Icon-O-Matic : support.cpp support_ui.cpp # gui + PathListView.cpp + ShapeListView.cpp SwatchGroup.cpp # gradient Gradient.cpp @@ -98,6 +102,7 @@ Application Icon-O-Matic : # CanvasView.cpp IconEditorApp.cpp + IconView.cpp main.cpp MainWindow.cpp : be libagg.a diff --git a/src/apps/icon-o-matic/MainWindow.cpp b/src/apps/icon-o-matic/MainWindow.cpp index 5b0ee58534..2bf12602a2 100644 --- a/src/apps/icon-o-matic/MainWindow.cpp +++ b/src/apps/icon-o-matic/MainWindow.cpp @@ -11,10 +11,14 @@ #include #include +#include #include "Document.h" #include "CanvasView.h" #include "IconEditorApp.h" +#include "IconView.h" +#include "PathListView.h" +#include "ShapeListView.h" #include "SwatchGroup.h" // TODO: just for testing @@ -25,6 +29,7 @@ #include "PathManipulator.h" #include "Shape.h" #include "ShapeContainer.h" +#include "ShapeListView.h" #include "StrokeTransformer.h" #include "Style.h" #include "StyleManager.h" @@ -36,8 +41,7 @@ MainWindow::MainWindow(IconEditorApp* app, Document* document) B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, B_ASYNCHRONOUS_CONTROLS), fApp(app), - fDocument(document), - fCanvasView(NULL) + fDocument(document) { _Init(); } @@ -87,6 +91,19 @@ MainWindow::_Init() // fCanvasView->SetSelection(fDocument->Selection()); fCanvasView->SetIcon(fDocument->Icon()); + fPathListView->SetPathContainer(fDocument->Icon()->Paths()); +// fPathListView->SetCommandStack(fDocument->CommandStack()); +// fPathListView->SetSelection(fDocument->Selection()); + + fShapeListView->SetShapeContainer(fDocument->Icon()->Shapes()); +// fShapeListView->SetCommandStack(fDocument->CommandStack()); +// fShapeListView->SetSelection(fDocument->Selection()); + + fIconPreview16->SetIcon(fDocument->Icon()); + fIconPreview32->SetIcon(fDocument->Icon()); +// fIconPreview48->SetIcon(fDocument->Icon()); + fIconPreview64->SetIcon(fDocument->Icon()); + // TODO: for testing only: MultipleManipulatorState* state = new MultipleManipulatorState(fCanvasView); fCanvasView->SetState(state); @@ -112,6 +129,7 @@ MainWindow::_Init() Shape* shape = new Shape(style2); shape->Paths()->AddPath(path); + shape->SetName("Gradient"); fDocument->Icon()->Shapes()->AddShape(shape); shape = new Shape(style1); @@ -121,6 +139,7 @@ MainWindow::_Init() transformer->width(5.0); shape->AppendTransformer(transformer); + shape->SetName("Outline"); fDocument->Icon()->Shapes()->AddShape(shape); Style* style3 = new Style(); @@ -137,6 +156,7 @@ MainWindow::_Init() *transformer2 *= agg::trans_affine_scaling(0.8, 0.6); shape->AppendTransformer(transformer2); + shape->SetName("Transformed"); fDocument->Icon()->Shapes()->AddShape(shape); PathManipulator* pathManipulator = new PathManipulator(path); @@ -157,7 +177,54 @@ MainWindow::_CreateGUI(BRect bounds) fCanvasView = new CanvasView(bounds); + bounds.left = fSwatchGroup->Frame().right + 5; + bounds.top = fSwatchGroup->Frame().top + 5; + bounds.right = bounds.left + 15; + bounds.bottom = bounds.top + 15; + fIconPreview16 = new IconView(bounds, "icon preview 16"); + + bounds.OffsetBy(bounds.Width() + 6, 0); + bounds.right = bounds.left + 31; + bounds.bottom = bounds.top + 31; + fIconPreview32 = new IconView(bounds, "icon preview 32"); + +// bounds.OffsetBy(bounds.Width() + 6, 0); +// bounds.right = bounds.left + 47; +// bounds.bottom = bounds.top + 47; +// fIconPreview48 = new IconView(bounds, "icon preview 48"); + + bounds.OffsetBy(bounds.Width() + 6, 0); + bounds.right = bounds.left + 63; + bounds.bottom = bounds.top + 63; + fIconPreview64 = new IconView(bounds, "icon preview 64"); + + bounds.OffsetBy(bounds.Width() + 6, 0); + bounds.right = bounds.left + 100; + bounds.bottom = fCanvasView->Frame().top - 5.0; + + fPathListView = new PathListView(bounds, "path list view"); + + bounds.OffsetBy(bounds.Width() + 6 + B_V_SCROLL_BAR_WIDTH, 0); + fShapeListView = new ShapeListView(bounds, "shape list view"); + bg->AddChild(fSwatchGroup); + + bg->AddChild(fIconPreview16); + bg->AddChild(fIconPreview32); +// bg->AddChild(fIconPreview48); + bg->AddChild(fIconPreview64); + + bg->AddChild(new BScrollView("path list scroll view", + fPathListView, + B_FOLLOW_LEFT | B_FOLLOW_TOP, + 0, false, true, + B_NO_BORDER)); + bg->AddChild(new BScrollView("shape list scroll view", + fShapeListView, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, + 0, false, true, + B_NO_BORDER)); + bg->AddChild(fCanvasView); return bg; diff --git a/src/apps/icon-o-matic/MainWindow.h b/src/apps/icon-o-matic/MainWindow.h index f8a35fbc74..f7f0e1c873 100644 --- a/src/apps/icon-o-matic/MainWindow.h +++ b/src/apps/icon-o-matic/MainWindow.h @@ -14,6 +14,9 @@ class CanvasView; class Document; class IconEditorApp; +class IconView; +class PathListView; +class ShapeListView; class SwatchGroup; class ViewState; @@ -36,6 +39,14 @@ class MainWindow : public BWindow { CanvasView* fCanvasView; SwatchGroup* fSwatchGroup; + + IconView* fIconPreview16; + IconView* fIconPreview32; + IconView* fIconPreview48; + IconView* fIconPreview64; + + PathListView* fPathListView; + ShapeListView* fShapeListView; // TODO: for testing only... ViewState* fState; }; diff --git a/src/apps/icon-o-matic/document/IconRenderer.cpp b/src/apps/icon-o-matic/document/IconRenderer.cpp index 53e021e6cc..cb5f0b43f2 100644 --- a/src/apps/icon-o-matic/document/IconRenderer.cpp +++ b/src/apps/icon-o-matic/document/IconRenderer.cpp @@ -103,6 +103,7 @@ StyleHandler::generate_span(agg::rgba8* span, int x, int y, agg::trans_affine transformation; // TODO: construct the gradient transformation here + // remember to invert() it! switch (gradient->Type()) { case GRADIENT_LINEAR: { @@ -191,7 +192,9 @@ IconRenderer::IconRenderer(BBitmap* bitmap) fBinaryScanline(), fSpanAllocator(), - fRasterizer() + fRasterizer(), + + fGlobalTransform() { // attach rendering buffer to bitmap fRenderingBuffer.attach((uint8*)bitmap->Bits(), @@ -230,6 +233,14 @@ IconRenderer::Render(const BRect& area) _Render(fBitmap->Bounds() & area); } +//SetScale +void +IconRenderer::SetScale(double scale) +{ + fGlobalTransform.reset(); + fGlobalTransform.multiply(agg::trans_affine_scaling(scale)); +} + // #pragma mark - // _Render @@ -247,17 +258,23 @@ IconRenderer::_Render(const BRect& r) (int)ceilf(r.bottom)); fRasterizer.reset(); - // iterate over shapes in icon and + // iterate over the shapes in the icon, // add the vector paths to the rasterizer - // and associate the shapes style + // and associate each shapes style int32 shapeCount = fIcon->Shapes()->CountShapes(); - for (int32 s = 0; s < shapeCount; s++) { - Shape* shape = fIcon->Shapes()->ShapeAtFast(s); + for (int32 i = 0; i < shapeCount; i++) { + Shape* shape = fIcon->Shapes()->ShapeAtFast(i); int32 styleIndex = fStyles->IndexOf(shape->Style()); fRasterizer.styles(styleIndex, -1); - fRasterizer.add_path(shape->VertexSource()); + if (fGlobalTransform.is_identity()) { + fRasterizer.add_path(shape->VertexSource()); + } else { + agg::conv_transform + scaledPath(shape->VertexSource(), fGlobalTransform); + fRasterizer.add_path(scaledPath); + } } StyleHandler styleHandler(fStyles, fGammaTable); @@ -269,6 +286,7 @@ IconRenderer::_Render(const BRect& r) fSpanAllocator, styleHandler); - fPixelFormat.apply_gamma_dir(fGammaTable); + if (fGammaTable.gamma() != 1.0) + fPixelFormat.apply_gamma_inv(fGammaTable); } diff --git a/src/apps/icon-o-matic/document/IconRenderer.h b/src/apps/icon-o-matic/document/IconRenderer.h index d352d2abe2..7ad048e5fe 100644 --- a/src/apps/icon-o-matic/document/IconRenderer.h +++ b/src/apps/icon-o-matic/document/IconRenderer.h @@ -10,13 +10,14 @@ #define ICON_RENDERER_H #include "agg_gamma_lut.h" -#include "agg_rendering_buffer.h" -#include "agg_rasterizer_compound_aa.h" -#include "agg_scanline_u.h" -#include "agg_scanline_bin.h" -#include "agg_renderer_scanline.h" -#include "agg_span_allocator.h" #include "agg_pixfmt_rgba.h" +#include "agg_rasterizer_compound_aa.h" +#include "agg_rendering_buffer.h" +#include "agg_renderer_scanline.h" +#include "agg_scanline_bin.h" +#include "agg_scanline_u.h" +#include "agg_span_allocator.h" +#include "agg_trans_affine.h" class BBitmap; class Icon; @@ -37,6 +38,8 @@ typedef agg::span_allocator SpanAllocator; typedef agg::rasterizer_compound_aa CompoundRasterizer; +typedef agg::trans_affine Transformation; + class IconRenderer { public: IconRenderer(BBitmap* bitmap); @@ -47,6 +50,8 @@ class IconRenderer { void Render(); void Render(const BRect& area); + void SetScale(double scale); + private: void _Render(const BRect& area); @@ -67,6 +72,8 @@ class IconRenderer { SpanAllocator fSpanAllocator; CompoundRasterizer fRasterizer; + + Transformation fGlobalTransform; }; #endif // ICON_RENDERER_H diff --git a/src/apps/icon-o-matic/generic/gui/ListViews.cpp b/src/apps/icon-o-matic/generic/gui/ListViews.cpp index aa6ce3de30..52324a94fd 100644 --- a/src/apps/icon-o-matic/generic/gui/ListViews.cpp +++ b/src/apps/icon-o-matic/generic/gui/ListViews.cpp @@ -32,8 +32,8 @@ enum { }; // SimpleItem class -SimpleItem::SimpleItem( const char *name ) - : BStringItem( name ) +SimpleItem::SimpleItem(const char *name) + : BStringItem(name) { } @@ -47,13 +47,13 @@ SimpleItem::Draw(BView *owner, BRect frame, uint32 flags) { DrawBackground(owner, frame, flags); // label - owner->SetHighColor( 0, 0, 0, 255 ); + owner->SetHighColor(0, 0, 0, 255); font_height fh; - owner->GetFontHeight( &fh ); + owner->GetFontHeight(&fh); const char* text = Text(); - BString truncatedString( text ); - owner->TruncateString( &truncatedString, B_TRUNCATE_MIDDLE, - frame.Width() - TEXT_OFFSET - 4.0 ); + BString truncatedString(text); + owner->TruncateString(&truncatedString, B_TRUNCATE_MIDDLE, + frame.Width() - TEXT_OFFSET - 4.0); float height = frame.Height(); float textHeight = fh.ascent + fh.descent; BPoint textPoint; @@ -76,13 +76,13 @@ SimpleItem::DrawBackground(BView *owner, BRect frame, uint32 flags) } // figure out bg-color rgb_color color = (rgb_color){ 255, 255, 255, 255 }; - if ( flags & FLAGS_TINTED_LINE ) - color = tint_color( color, 1.06 ); + if (flags & FLAGS_TINTED_LINE) + color = tint_color(color, 1.06); // background - if ( IsSelected() ) - color = tint_color( color, B_DARKEN_2_TINT ); - owner->SetLowColor( color ); - owner->FillRect( frame, B_SOLID_LOW ); + if (IsSelected()) + color = tint_color(color, B_DARKEN_2_TINT); + owner->SetLowColor(color); + owner->FillRect(frame, B_SOLID_LOW); } // DragSortableListView class @@ -150,7 +150,7 @@ DragSortableListView::MakeFocus(bool focused) */ // Draw void -DragSortableListView::Draw( BRect updateRect ) +DragSortableListView::Draw(BRect updateRect) { int32 firstIndex = IndexOf(updateRect.LeftTop()); int32 lastIndex = IndexOf(updateRect.RightBottom()); @@ -206,58 +206,59 @@ DragSortableListView::TargetedByScrollView(BScrollView* scrollView) // InitiateDrag bool -DragSortableListView::InitiateDrag( BPoint point, int32 index, bool ) +DragSortableListView::InitiateDrag(BPoint point, int32 index, bool) { // supress drag&drop while an item is focused if (fFocusedIndex >= 0) return false; bool success = false; - BListItem* item = ItemAt( CurrentSelection( 0 ) ); - if ( !item ) { + BListItem* item = ItemAt(CurrentSelection(0)); + if (!item) { // workarround a timing problem - Select( index ); - item = ItemAt( index ); + Select(index); + item = ItemAt(index); } - if ( item ) { + if (item) { // create drag message - BMessage msg( fDragCommand ); - MakeDragMessage( &msg ); + BMessage msg(fDragCommand); + MakeDragMessage(&msg); // figure out drag rect float width = Bounds().Width(); BRect dragRect(0.0, 0.0, width, -1.0); // figure out, how many items fit into our bitmap int32 numItems; bool fade = false; - for (numItems = 0; BListItem* item = ItemAt( CurrentSelection( numItems ) ); numItems++) { - dragRect.bottom += ceilf( item->Height() ) + 1.0; - if ( dragRect.Height() > MAX_DRAG_HEIGHT ) { + for (numItems = 0; BListItem* item = ItemAt(CurrentSelection(numItems)); numItems++) { + dragRect.bottom += ceilf(item->Height()) + 1.0; + if (dragRect.Height() > MAX_DRAG_HEIGHT) { fade = true; dragRect.bottom = MAX_DRAG_HEIGHT; numItems++; break; } } - BBitmap* dragBitmap = new BBitmap( dragRect, B_RGB32, true ); - if ( dragBitmap && dragBitmap->IsValid() ) { - if ( BView *v = new BView( dragBitmap->Bounds(), "helper", B_FOLLOW_NONE, B_WILL_DRAW ) ) { - dragBitmap->AddChild( v ); + BBitmap* dragBitmap = new BBitmap(dragRect, B_RGB32, true); + if (dragBitmap && dragBitmap->IsValid()) { + if (BView *v = new BView(dragBitmap->Bounds(), "helper", + B_FOLLOW_NONE, B_WILL_DRAW)) { + dragBitmap->AddChild(v); dragBitmap->Lock(); - BRect itemBounds( dragRect) ; + BRect itemBounds(dragRect) ; itemBounds.bottom = 0.0; // let all selected items, that fit into our drag_bitmap, draw - for ( int32 i = 0; i < numItems; i++ ) { - int32 index = CurrentSelection( i ); - BListItem* item = ItemAt( index ); - itemBounds.bottom = itemBounds.top + ceilf( item->Height() ); - if ( itemBounds.bottom > dragRect.bottom ) + for (int32 i = 0; i < numItems; i++) { + int32 index = CurrentSelection(i); + BListItem* item = ItemAt(index); + itemBounds.bottom = itemBounds.top + ceilf(item->Height()); + if (itemBounds.bottom > dragRect.bottom) itemBounds.bottom = dragRect.bottom; - DrawListItem( v, index, itemBounds ); + DrawListItem(v, index, itemBounds); itemBounds.top = itemBounds.bottom + 1.0; } // make a black frame arround the edge - v->SetHighColor( 0, 0, 0, 255 ); - v->StrokeRect( v->Bounds() ); + v->SetHighColor(0, 0, 0, 255); + v->StrokeRect(v->Bounds()); v->Sync(); uint8 *bits = (uint8 *)dragBitmap->Bits(); @@ -266,18 +267,18 @@ DragSortableListView::InitiateDrag( BPoint point, int32 index, bool ) int32 bpr = dragBitmap->BytesPerRow(); if (fade) { - for ( int32 y = 0; y < height - ALPHA / 2; y++, bits += bpr ) { + for (int32 y = 0; y < height - ALPHA / 2; y++, bits += bpr) { uint8 *line = bits + 3; for (uint8 *end = line + 4 * width; line < end; line += 4) *line = ALPHA; } - for ( int32 y = height - ALPHA / 2; y < height; y++, bits += bpr ) { + for (int32 y = height - ALPHA / 2; y < height; y++, bits += bpr) { uint8 *line = bits + 3; for (uint8 *end = line + 4 * width; line < end; line += 4) *line = (height - y) << 1; } } else { - for ( int32 y = 0; y < height; y++, bits += bpr ) { + for (int32 y = 0; y < height; y++, bits += bpr) { uint8 *line = bits + 3; for (uint8 *end = line + 4 * width; line < end; line += 4) *line = ALPHA; @@ -290,9 +291,9 @@ DragSortableListView::InitiateDrag( BPoint point, int32 index, bool ) dragBitmap = NULL; } if (dragBitmap) - DragMessage( &msg, dragBitmap, B_OP_ALPHA, BPoint( 0.0, 0.0 ) ); + DragMessage(&msg, dragBitmap, B_OP_ALPHA, BPoint(0.0, 0.0)); else - DragMessage( &msg, dragRect.OffsetToCopy( point ), this ); + DragMessage(&msg, dragRect.OffsetToCopy(point), this); _SetDragMessage(&msg); success = true; @@ -302,10 +303,10 @@ DragSortableListView::InitiateDrag( BPoint point, int32 index, bool ) // WindowActivated void -DragSortableListView::WindowActivated( bool active ) +DragSortableListView::WindowActivated(bool active) { // workarround for buggy focus indication of BScrollView - if ( BView* view = Parent() ) + if (BView* view = Parent()) view->Invalidate(); } @@ -315,26 +316,26 @@ DragSortableListView::MessageReceived(BMessage* message) { if (message->what == fDragCommand) { DragSortableListView *list = NULL; - if ( message->FindPointer( "list", (void **)&list ) == B_OK - && list == this ) { + if (message->FindPointer("list", (void **)&list) == B_OK + && list == this) { int32 count = CountItems(); - if ( fDropIndex < 0 || fDropIndex > count ) + if (fDropIndex < 0 || fDropIndex > count) fDropIndex = count; BList items; int32 index; - for ( int32 i = 0; message->FindInt32( "index", i, &index ) == B_OK; i++ ) - if ( BListItem* item = ItemAt(index) ) - items.AddItem( (void*)item ); - if ( items.CountItems() > 0 ) { - if ( modifiers() & B_SHIFT_KEY ) - CopyItems( items, fDropIndex ); + for (int32 i = 0; message->FindInt32("index", i, &index) == B_OK; i++) + if (BListItem* item = ItemAt(index)) + items.AddItem((void*)item); + if (items.CountItems() > 0) { + if (modifiers() & B_SHIFT_KEY) + CopyItems(items, fDropIndex); else - MoveItems( items, fDropIndex ); + MoveItems(items, fDropIndex); } fDropIndex = -1; } } else { - switch ( message->what ) { + switch (message->what) { case MSG_TICK: { float scrollV = 0.0; BRect rect(Bounds()); @@ -370,7 +371,7 @@ DragSortableListView::MessageReceived(BMessage* message) // ModifiersChanged(); // break; case B_MOUSE_WHEEL_CHANGED: { - BListView::MessageReceived( message ); + BListView::MessageReceived(message); BPoint point; uint32 buttons; GetMouse(&point, &buttons, false); @@ -379,7 +380,7 @@ DragSortableListView::MessageReceived(BMessage* message) break; } default: - BListView::MessageReceived( message ); + BListView::MessageReceived(message); break; } } @@ -387,20 +388,20 @@ DragSortableListView::MessageReceived(BMessage* message) // KeyDown void -DragSortableListView::KeyDown( const char* bytes, int32 numBytes ) +DragSortableListView::KeyDown(const char* bytes, int32 numBytes) { - if ( numBytes < 1 ) + if (numBytes < 1) return; - if ( ( bytes[0] == B_BACKSPACE ) || ( bytes[0] == B_DELETE ) ) + if ((bytes[0] == B_BACKSPACE) || (bytes[0] == B_DELETE)) RemoveSelected(); - BListView::KeyDown( bytes, numBytes ); + BListView::KeyDown(bytes, numBytes); } // MouseDown void -DragSortableListView::MouseDown( BPoint where ) +DragSortableListView::MouseDown(BPoint where) { int32 clicks = 1; uint32 buttons = 0; @@ -478,14 +479,14 @@ DragSortableListView::MouseMoved(BPoint where, uint32 transit, const BMessage *m // MouseUp void -DragSortableListView::MouseUp( BPoint where ) +DragSortableListView::MouseUp(BPoint where) { // remove drop mark - _SetDropAnticipationRect( BRect( 0.0, 0.0, -1.0, -1.0 ) ); + _SetDropAnticipationRect(BRect(0.0, 0.0, -1.0, -1.0)); SetAutoScrolling(false); // be sure to forget drag message _SetDragMessage(NULL); - BListView::MouseUp( where ); + BListView::MouseUp(where); BCursor cursor(B_HAND_CURSOR); SetViewCursor(&cursor, true); @@ -493,9 +494,9 @@ DragSortableListView::MouseUp( BPoint where ) // DrawItem void -DragSortableListView::DrawItem( BListItem *item, BRect itemFrame, bool complete ) +DragSortableListView::DrawItem(BListItem *item, BRect itemFrame, bool complete) { - DrawListItem( this, IndexOf( item ), itemFrame ); + DrawListItem(this, IndexOf(item), itemFrame); /* if (IsFocus()) { SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR)); StrokeRect(Bounds()); @@ -620,7 +621,7 @@ DragSortableListView::ScrollTo(int32 index) // MoveItems void -DragSortableListView::MoveItems( BList& items, int32 index ) +DragSortableListView::MoveItems(BList& items, int32 index) { DeselectAll(); // we remove the items while we look at them, the insertion index is decreased @@ -628,34 +629,30 @@ DragSortableListView::MoveItems( BList& items, int32 index ) // removal BList removedItems; int32 count = items.CountItems(); - for ( int32 i = 0; i < count; i++ ) - { - BListItem* item = (BListItem*)items.ItemAt( i ); - int32 removeIndex = IndexOf( item ); - if ( RemoveItem( item ) && removedItems.AddItem( (void*)item ) ) - { - if ( removeIndex < index ) + for (int32 i = 0; i < count; i++) { + BListItem* item = (BListItem*)items.ItemAt(i); + int32 removeIndex = IndexOf(item); + if (RemoveItem(item) && removedItems.AddItem((void*)item)) { + if (removeIndex < index) index--; } // else ??? -> blow up } - for ( int32 i = 0; BListItem* item = (BListItem*)removedItems.ItemAt( i ); i++ ) - { - if ( AddItem( item, index ) ) - { + for (int32 i = 0; + BListItem* item = (BListItem*)removedItems.ItemAt(i); i++) { + if (AddItem(item, index)) { // after we're done, the newly inserted items will be selected - Select( index, true ); + Select(index, true); // next items will be inserted after this one index++; - } - else + } else delete item; } } // CopyItems void -DragSortableListView::CopyItems( BList& items, int32 index ) +DragSortableListView::CopyItems(BList& items, int32 index) { DeselectAll(); // by inserting the items after we copied all items first, we avoid @@ -664,35 +661,31 @@ DragSortableListView::CopyItems( BList& items, int32 index ) // need to be cloned BList clonedItems; int32 count = items.CountItems(); - for ( int32 i = 0; i < count; i++ ) - { - BListItem* item = CloneItem( IndexOf( (BListItem*)items.ItemAt( i ) ) ); - if ( item && !clonedItems.AddItem( (void*)item ) ) + for (int32 i = 0; i < count; i++) { + BListItem* item = CloneItem(IndexOf((BListItem*)items.ItemAt(i))); + if (item && !clonedItems.AddItem((void*)item)) delete item; } - for ( int32 i = 0; BListItem* item = (BListItem*)clonedItems.ItemAt( i ); i++ ) - { - if ( AddItem( item, index ) ) - { + for (int32 i = 0; + BListItem* item = (BListItem*)clonedItems.ItemAt(i); i++) { + if (AddItem(item, index)) { // after we're done, the newly inserted items will be selected - Select( index, true ); + Select(index, true); // next items will be inserted after this one index++; - } - else + } else delete item; } } // RemoveItemList void -DragSortableListView::RemoveItemList( BList& items ) +DragSortableListView::RemoveItemList(BList& items) { int32 count = items.CountItems(); - for ( int32 i = 0; i < count; i++ ) - { - BListItem* item = (BListItem*)items.ItemAt( i ); - if ( RemoveItem( item ) ) + for (int32 i = 0; i < count; i++) { + BListItem* item = (BListItem*)items.ItemAt(i); + if (RemoveItem(item)) delete item; } } @@ -705,9 +698,9 @@ DragSortableListView::RemoveSelected() // return; BList items; - for ( int32 i = 0; BListItem* item = ItemAt( CurrentSelection( i ) ); i++ ) - items.AddItem( (void*)item ); - RemoveItemList( items ); + for (int32 i = 0; BListItem* item = ItemAt(CurrentSelection(i)); i++) + items.AddItem((void*)item); + RemoveItemList(items); } // CountSelectedItems @@ -715,7 +708,7 @@ int32 DragSortableListView::CountSelectedItems() const { int32 count = 0; - while ( CurrentSelection( count ) >= 0 ) + while (CurrentSelection(count) >= 0) count++; return count; } @@ -802,22 +795,22 @@ DragSortableListView::_SetDragMessage(const BMessage* message) // SimpleListView class -SimpleListView::SimpleListView( BRect frame, BMessage* selectionChangeMessage ) - : DragSortableListView( frame, "playlist listview", - B_MULTIPLE_SELECTION_LIST, B_FOLLOW_ALL, - B_WILL_DRAW | B_NAVIGABLE - | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE ), - fSelectionChangeMessage( selectionChangeMessage ) +SimpleListView::SimpleListView(BRect frame, BMessage* selectionChangeMessage) + : DragSortableListView(frame, "playlist listview", + B_MULTIPLE_SELECTION_LIST, B_FOLLOW_ALL, + B_WILL_DRAW | B_NAVIGABLE + | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE), + fSelectionChangeMessage(selectionChangeMessage) { } // SimpleListView class -SimpleListView::SimpleListView( BRect frame, const char* name, - BMessage* selectionChangeMessage, - list_view_type type, - uint32 resizingMode, uint32 flags ) - : DragSortableListView( frame, name, type, resizingMode, flags ), - fSelectionChangeMessage( selectionChangeMessage ) +SimpleListView::SimpleListView(BRect frame, const char* name, + BMessage* selectionChangeMessage, + list_view_type type, + uint32 resizingMode, uint32 flags) + : DragSortableListView(frame, name, type, resizingMode, flags), + fSelectionChangeMessage(selectionChangeMessage) { } @@ -827,6 +820,7 @@ SimpleListView::~SimpleListView() delete fSelectionChangeMessage; } +#ifdef LIB_LAYOUT // layoutprefs minimax SimpleListView::layoutprefs() @@ -847,14 +841,15 @@ SimpleListView::layout(BRect frame) ResizeTo(frame.Width(), frame.Height()); return Frame(); } +#endif // LIB_LAYOUT // MessageReceived void -SimpleListView::MessageReceived( BMessage* message) +SimpleListView::MessageReceived(BMessage* message) { - switch ( message->what ) { + switch (message->what) { default: - DragSortableListView::MessageReceived( message ); + DragSortableListView::MessageReceived(message); break; } } @@ -899,10 +894,10 @@ void SimpleListView::MakeDragMessage(BMessage* message) const { if (message) { - message->AddPointer( "list", (void*)dynamic_cast(this)); + message->AddPointer("list", (void*)dynamic_cast(this)); int32 index; for (int32 i = 0; (index = CurrentSelection(i)) >= 0; i++) - message->AddInt32( "index", index ); + message->AddInt32("index", index); } } diff --git a/src/apps/icon-o-matic/generic/gui/ListViews.h b/src/apps/icon-o-matic/generic/gui/ListViews.h index 1d015ca28c..df1aff3b59 100644 --- a/src/apps/icon-o-matic/generic/gui/ListViews.h +++ b/src/apps/icon-o-matic/generic/gui/ListViews.h @@ -13,7 +13,9 @@ #include #include -#include +#ifdef LIB_LAYOUT +# include +#endif #include "MouseWheelFilter.h" @@ -59,17 +61,17 @@ class SimpleItem : public BStringItem class DragSortableListView : public MouseWheelTarget, public BListView { public: - DragSortableListView( BRect frame, - const char* name, - list_view_type type + DragSortableListView(BRect frame, + const char* name, + list_view_type type = B_SINGLE_SELECTION_LIST, - uint32 resizingMode + uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP, - uint32 flags + uint32 flags = B_WILL_DRAW | B_NAVIGABLE - | B_FRAME_EVENTS ); + | B_FRAME_EVENTS); virtual ~DragSortableListView(); // BListView @@ -77,20 +79,20 @@ class DragSortableListView : public MouseWheelTarget, virtual void DetachedFromWindow(); virtual void FrameResized(float width, float height); // virtual void MakeFocus(bool focused); - virtual void Draw( BRect updateRect ); + virtual void Draw(BRect updateRect); virtual void ScrollTo(BPoint where); virtual void TargetedByScrollView(BScrollView* scrollView); - virtual bool InitiateDrag( BPoint point, int32 index, - bool wasSelected ); - virtual void MessageReceived( BMessage* message ); - virtual void KeyDown( const char* bytes, int32 numBytes ); - virtual void MouseDown( BPoint where ); - virtual void MouseMoved( BPoint where, uint32 transit, - const BMessage* dragMessage ); - virtual void MouseUp( BPoint where ); - virtual void WindowActivated( bool active ); - virtual void DrawItem( BListItem *item, BRect itemFrame, - bool complete = false); + virtual bool InitiateDrag(BPoint point, int32 index, + bool wasSelected); + virtual void MessageReceived(BMessage* message); + virtual void KeyDown(const char* bytes, int32 numBytes); + virtual void MouseDown(BPoint where); + virtual void MouseMoved(BPoint where, uint32 transit, + const BMessage* dragMessage); + virtual void MouseUp(BPoint where); + virtual void WindowActivated(bool active); + virtual void DrawItem(BListItem *item, BRect itemFrame, + bool complete = false); // MouseWheelTarget virtual bool MouseWheelChanged(float x, float y); @@ -148,26 +150,31 @@ class DragSortableListView : public MouseWheelTarget, }; // SimpleListView -class SimpleListView : public MView, public DragSortableListView { +class SimpleListView : + #ifdef LIB_LAYOUT + public MView, + #endif + public DragSortableListView { public: - SimpleListView( BRect frame, - BMessage* selectionChangeMessage = NULL ); - SimpleListView( BRect frame, - const char* name, - BMessage* selectionChangeMessage = NULL, - list_view_type type + SimpleListView(BRect frame, + BMessage* selectionChangeMessage = NULL); + SimpleListView(BRect frame, + const char* name, + BMessage* selectionChangeMessage = NULL, + list_view_type type = B_MULTIPLE_SELECTION_LIST, - uint32 resizingMode + uint32 resizingMode = B_FOLLOW_ALL_SIDES, - uint32 flags + uint32 flags = B_WILL_DRAW | B_NAVIGABLE - | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE ); + | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE); ~SimpleListView(); + #ifdef LIB_LAYOUT // MView virtual minimax layoutprefs(); virtual BRect layout(BRect frame); - + #endif // BListView virtual void MessageReceived(BMessage* message); virtual void SelectionChanged(); diff --git a/src/apps/icon-o-matic/gui/PathListView.cpp b/src/apps/icon-o-matic/gui/PathListView.cpp new file mode 100644 index 0000000000..5ef57e1cd1 --- /dev/null +++ b/src/apps/icon-o-matic/gui/PathListView.cpp @@ -0,0 +1,308 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#include "PathListView.h" + +#include + +#include +#include +#include +#include +#include + +#include "VectorPath.h" +#include "Observer.h" +#include "Selection.h" + +class PathListItem : public SimpleItem, + public Observer { + public: + PathListItem(VectorPath* p, + PathListView* listView) + : SimpleItem(""), + path(NULL), + fListView(listView) + { + SetPath(p); + } + + virtual ~PathListItem() + { + SetPath(NULL); + } + + virtual void ObjectChanged(const Observable* object) + { + UpdateText(); + } + + void SetPath(VectorPath* p) + { + if (p == path) + return; + + if (path) { + path->RemoveObserver(this); + path->Release(); + } + + path = p; + + if (path) { + path->Acquire(); + path->AddObserver(this); + UpdateText(); + } + } + void UpdateText() + { + SetText(path->Name()); + // :-/ + if (fListView->LockLooper()) { + fListView->InvalidateItem( + fListView->IndexOf(this)); + fListView->UnlockLooper(); + } + } + + VectorPath* path; + private: + PathListView* fListView; +}; + +// #pragma mark - + +// constructor +PathListView::PathListView(BRect frame, + const char* name, + BMessage* message, BHandler* target) + : SimpleListView(frame, name, + NULL, B_SINGLE_SELECTION_LIST), + fMessage(message), + fPathContainer(NULL), + fSelection(NULL) +{ + SetTarget(target); +} + +// destructor +PathListView::~PathListView() +{ + _MakeEmpty(); + delete fMessage; + + if (fPathContainer) + fPathContainer->RemoveListener(this); +} + +// SelectionChanged +void +PathListView::SelectionChanged() +{ + // NOTE: single selection list + + PathListItem* item + = dynamic_cast(ItemAt(CurrentSelection(0))); + if (item && fMessage) { + BMessage message(*fMessage); + message.AddPointer("path", (void*)item->path); + Invoke(&message); + } + + // modify global Selection + if (!fSelection) + return; + +// if (item) +// fSelection->Select(item->path); +// else +// fSelection->DeselectAll(); +} + +// MessageReceived +void +PathListView::MessageReceived(BMessage* message) +{ + SimpleListView::MessageReceived(message); +} + +// MakeDragMessage +void +PathListView::MakeDragMessage(BMessage* message) const +{ +} + +// AcceptDragMessage +bool +PathListView::AcceptDragMessage(const BMessage* message) const +{ + return false; +} + +// SetDropTargetRect +void +PathListView::SetDropTargetRect(const BMessage* message, BPoint where) +{ +} + +// MoveItems +void +PathListView::MoveItems(BList& items, int32 toIndex) +{ +} + +// CopyItems +void +PathListView::CopyItems(BList& items, int32 toIndex) +{ +} + +// RemoveItemList +void +PathListView::RemoveItemList(BList& indices) +{ + // TODO: allow removing items +} + +// CloneItem +BListItem* +PathListView::CloneItem(int32 index) const +{ + if (PathListItem* item = dynamic_cast(ItemAt(index))) { + return new PathListItem(item->path, + const_cast(this)); + } + return NULL; +} + +// #pragma mark - + +// PathAdded +void +PathListView::PathAdded(VectorPath* path) +{ + // NOTE: we are in the thread that messed with the + // ShapeContainer, so no need to lock the + // container, when this is changed to asynchronous + // notifications, then it would need to be read-locked! + if (!LockLooper()) + return; + + // NOTE: shapes are always added at the end + // of the list, so the sorting is synced... + _AddPath(path); + + UnlockLooper(); +} + +// PathRemoved +void +PathListView::PathRemoved(VectorPath* path) +{ + // NOTE: we are in the thread that messed with the + // ShapeContainer, so no need to lock the + // container, when this is changed to asynchronous + // notifications, then it would need to be read-locked! + if (!LockLooper()) + return; + + // NOTE: we're only interested in VectorPath objects + _RemovePath(path); + + UnlockLooper(); +} + +// #pragma mark - + +// SetPathContainer +void +PathListView::SetPathContainer(PathContainer* container) +{ + if (fPathContainer == container) + return; + + // detach from old container + if (fPathContainer) + fPathContainer->RemoveListener(this); + + _MakeEmpty(); + + fPathContainer = container; + + if (!fPathContainer) + return; + + fPathContainer->AddListener(this); + + // sync +// if (!fPathContainer->ReadLock()) +// return; + + int32 count = fPathContainer->CountPaths(); + for (int32 i = 0; i < count; i++) + _AddPath(fPathContainer->PathAtFast(i)); + +// fPathContainer->ReadUnlock(); +} + +// SetSelection +void +PathListView::SetSelection(Selection* selection) +{ + fSelection = selection; +} + +// #pragma mark - + +// _AddPath +bool +PathListView::_AddPath(VectorPath* path) +{ + if (path) + return AddItem(new PathListItem(path, this)); + return false; +} + +// _RemovePath +bool +PathListView::_RemovePath(VectorPath* path) +{ + PathListItem* item = _ItemForPath(path); + if (item && RemoveItem(item)) { + delete item; + return true; + } + return false; +} + +// _ItemForPath +PathListItem* +PathListView::_ItemForPath(VectorPath* path) const +{ + for (int32 i = 0; + PathListItem* item = dynamic_cast(ItemAt(i)); + i++) { + if (item->path == path) + return item; + } + return NULL; +} + +// _MakeEmpty +void +PathListView::_MakeEmpty() +{ + // NOTE: BListView::MakeEmpty() uses ScrollTo() + // for which the object needs to be attached to + // a BWindow.... :-( + int32 count = CountItems(); + for (int32 i = count - 1; i >= 0; i--) + delete RemoveItem(i); +} + diff --git a/src/apps/icon-o-matic/gui/PathListView.h b/src/apps/icon-o-matic/gui/PathListView.h new file mode 100644 index 0000000000..152ff5db59 --- /dev/null +++ b/src/apps/icon-o-matic/gui/PathListView.h @@ -0,0 +1,66 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#ifndef PATH_LIST_VIEW_H +#define PATH_LIST_VIEW_H + +#include "ListViews.h" +#include "PathContainer.h" + +class VectorPath; +class PathListItem; +class Selection; + +class PathListView : public SimpleListView, + public PathContainerListener { + public: + PathListView(BRect frame, + const char* name, + BMessage* selectionMessage = NULL, + BHandler* target = NULL); + virtual ~PathListView(); + + // SimpleListView interface + virtual void SelectionChanged(); + + virtual void MessageReceived(BMessage* message); + + virtual void MakeDragMessage(BMessage* message) const; + + virtual bool AcceptDragMessage(const BMessage* message) const; + virtual void SetDropTargetRect(const BMessage* message, + BPoint where); + + virtual void MoveItems(BList& items, int32 toIndex); + virtual void CopyItems(BList& items, int32 toIndex); + virtual void RemoveItemList(BList& indices); + + virtual BListItem* CloneItem(int32 atIndex) const; + + // ShapeContainerListener interface + virtual void PathAdded(VectorPath* path); + virtual void PathRemoved(VectorPath* path); + + // PathListView + void SetPathContainer(PathContainer* container); + void SetSelection(Selection* selection); + + private: + bool _AddPath(VectorPath* path); + bool _RemovePath(VectorPath* path); + + PathListItem* _ItemForPath(VectorPath* path) const; + void _MakeEmpty(); + + BMessage* fMessage; + + PathContainer* fPathContainer; + Selection* fSelection; +}; + +#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 new file mode 100644 index 0000000000..d1f3b1cf70 --- /dev/null +++ b/src/apps/icon-o-matic/gui/ShapeListView.cpp @@ -0,0 +1,340 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#include "ShapeListView.h" + +#include + +#include +#include +#include +#include +#include + +#include "Shape.h" +#include "Observer.h" +#include "Selection.h" + +class ShapeListItem : public SimpleItem, + public Observer { + public: + ShapeListItem(Shape* s, + ShapeListView* listView) + : SimpleItem(""), + shape(NULL), + fListView(listView) + { + SetClip(s); + } + + virtual ~ShapeListItem() + { + SetClip(NULL); + } + + virtual void ObjectChanged(const Observable* object) + { + UpdateText(); + } + + void SetClip(Shape* s) + { + if (s == shape) + return; + + if (shape) { + shape->RemoveObserver(this); + shape->Release(); + } + + shape = s; + + if (shape) { + shape->Acquire(); + shape->AddObserver(this); + UpdateText(); + } + } + void UpdateText() + { + SetText(shape->Name()); + // :-/ + if (fListView->LockLooper()) { + fListView->InvalidateItem( + fListView->IndexOf(this)); + fListView->UnlockLooper(); + } + } + + Shape* shape; + private: + ShapeListView* fListView; +}; + +// #pragma mark - + +enum { + MSG_DRAG_SHAPE = 'drgs', +}; + +// constructor +ShapeListView::ShapeListView(BRect frame, + const char* name, + BMessage* message, BHandler* target) + : SimpleListView(frame, name, + NULL, B_MULTIPLE_SELECTION_LIST), + fMessage(message), + fShapeContainer(NULL), + fSelection(NULL) +{ + SetDragCommand(MSG_DRAG_SHAPE); + SetTarget(target); +} + +// destructor +ShapeListView::~ShapeListView() +{ + _MakeEmpty(); + delete fMessage; + + if (fShapeContainer) + fShapeContainer->RemoveListener(this); +} + +// SelectionChanged +void +ShapeListView::SelectionChanged() +{ + // TODO: single selection versus multiple selection + + ShapeListItem* item = dynamic_cast(ItemAt(CurrentSelection(0))); + if (item && fMessage) { + BMessage message(*fMessage); + message.AddPointer("shape", (void*)item->shape); + Invoke(&message); + } + + // modify global Selection + if (!fSelection) + return; + + if (item) + fSelection->Select(item->shape); + else + fSelection->DeselectAll(); +} + +// MessageReceived +void +ShapeListView::MessageReceived(BMessage* message) +{ + SimpleListView::MessageReceived(message); +} + +// MakeDragMessage +void +ShapeListView::MakeDragMessage(BMessage* message) const +{ + SimpleListView::MakeDragMessage(message); + message->AddPointer("container", fShapeContainer); + int32 count = CountItems(); + for (int32 i = 0; i < count; i++) { + ShapeListItem* item = dynamic_cast(ItemAt(CurrentSelection(i))); + if (item) { + message->AddPointer("shape", (void*)item->shape); + } else + break; + } + +// message->AddInt32("be:actions", B_COPY_TARGET); +// message->AddInt32("be:actions", B_TRASH_TARGET); +// +// message->AddString("be:types", B_FILE_MIME_TYPE); +//// message->AddString("be:filetypes", ""); +//// message->AddString("be:type_descriptions", ""); +// +// message->AddString("be:clip_name", item->shape->Name()); +// +// message->AddString("be:originator", "Icon-O-Matic"); +// message->AddPointer("be:originator_data", (void*)item->shape); +} + +// AcceptDragMessage +bool +ShapeListView::AcceptDragMessage(const BMessage* message) const +{ + return SimpleListView::AcceptDragMessage(message); +} + +// SetDropTargetRect +void +ShapeListView::SetDropTargetRect(const BMessage* message, BPoint where) +{ + SimpleListView::SetDropTargetRect(message, where); +} + +// MoveItems +void +ShapeListView::MoveItems(BList& items, int32 toIndex) +{ + SimpleListView::MoveItems(items, toIndex); +} + +// CopyItems +void +ShapeListView::CopyItems(BList& items, int32 toIndex) +{ + MoveItems(items, toIndex); + // copy operation not allowed -> ?!? + // TODO: what about clips that reference the same file but + // with different "in/out points" +} + +// RemoveItemList +void +ShapeListView::RemoveItemList(BList& indices) +{ + // TODO: allow removing items +} + +// CloneItem +BListItem* +ShapeListView::CloneItem(int32 index) const +{ + if (ShapeListItem* item = dynamic_cast(ItemAt(index))) { + return new ShapeListItem(item->shape, + const_cast(this)); + } + return NULL; +} + +// #pragma mark - + +// ShapeAdded +void +ShapeListView::ShapeAdded(Shape* shape) +{ + // NOTE: we are in the thread that messed with the + // ShapeContainer, so no need to lock the + // container, when this is changed to asynchronous + // notifications, then it would need to be read-locked! + if (!LockLooper()) + return; + + // NOTE: shapes are always added at the end + // of the list, so the sorting is synced... + _AddShape(shape); + + UnlockLooper(); +} + +// ShapeRemoved +void +ShapeListView::ShapeRemoved(Shape* shape) +{ + // NOTE: we are in the thread that messed with the + // ShapeContainer, so no need to lock the + // container, when this is changed to asynchronous + // notifications, then it would need to be read-locked! + if (!LockLooper()) + return; + + // NOTE: we're only interested in Shape objects + _RemoveShape(shape); + + UnlockLooper(); +} + +// #pragma mark - + +// SetShapeContainer +void +ShapeListView::SetShapeContainer(ShapeContainer* container) +{ + if (fShapeContainer == container) + return; + + // detach from old container + if (fShapeContainer) + fShapeContainer->RemoveListener(this); + + _MakeEmpty(); + + fShapeContainer = container; + + if (!fShapeContainer) + return; + + fShapeContainer->AddListener(this); + + // sync +// if (!fShapeContainer->ReadLock()) +// return; + + int32 count = fShapeContainer->CountShapes(); + for (int32 i = 0; i < count; i++) + _AddShape(fShapeContainer->ShapeAtFast(i)); + +// fShapeContainer->ReadUnlock(); +} + +// SetSelection +void +ShapeListView::SetSelection(Selection* selection) +{ + fSelection = selection; +} + +// #pragma mark - + +// _AddShape +bool +ShapeListView::_AddShape(Shape* shape) +{ + if (shape) + return AddItem(new ShapeListItem(shape, this)); + return false; +} + +// _RemoveShape +bool +ShapeListView::_RemoveShape(Shape* shape) +{ + ShapeListItem* item = _ItemForShape(shape); + if (item && RemoveItem(item)) { + delete item; + return true; + } + return false; +} + +// _ItemForShape +ShapeListItem* +ShapeListView::_ItemForShape(Shape* shape) const +{ + for (int32 i = 0; + ShapeListItem* item = dynamic_cast(ItemAt(i)); + i++) { + if (item->shape == shape) + return item; + } + return NULL; +} + +// _MakeEmpty +void +ShapeListView::_MakeEmpty() +{ + // NOTE: BListView::MakeEmpty() uses ScrollTo() + // for which the object needs to be attached to + // a BWindow.... :-( + int32 count = CountItems(); + for (int32 i = count - 1; i >= 0; i--) + delete RemoveItem(i); +} + diff --git a/src/apps/icon-o-matic/gui/ShapeListView.h b/src/apps/icon-o-matic/gui/ShapeListView.h new file mode 100644 index 0000000000..f7dd5f0f1e --- /dev/null +++ b/src/apps/icon-o-matic/gui/ShapeListView.h @@ -0,0 +1,66 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#ifndef SHAPE_LIST_VIEW_H +#define SHAPE_LIST_VIEW_H + +#include "ListViews.h" +#include "ShapeContainer.h" + +class Shape; +class ShapeListItem; +class Selection; + +class ShapeListView : public SimpleListView, + public ShapeContainerListener { + public: + ShapeListView(BRect frame, + const char* name, + BMessage* selectionMessage = NULL, + BHandler* target = NULL); + virtual ~ShapeListView(); + + // SimpleListView interface + virtual void SelectionChanged(); + + virtual void MessageReceived(BMessage* message); + + virtual void MakeDragMessage(BMessage* message) const; + + virtual bool AcceptDragMessage(const BMessage* message) const; + virtual void SetDropTargetRect(const BMessage* message, + BPoint where); + + virtual void MoveItems(BList& items, int32 toIndex); + virtual void CopyItems(BList& items, int32 toIndex); + virtual void RemoveItemList(BList& indices); + + virtual BListItem* CloneItem(int32 atIndex) const; + + // ShapeContainerListener interface + virtual void ShapeAdded(Shape* shape); + virtual void ShapeRemoved(Shape* shape); + + // ShapeListView + void SetShapeContainer(ShapeContainer* container); + void SetSelection(Selection* selection); + + private: + bool _AddShape(Shape* shape); + bool _RemoveShape(Shape* shape); + + ShapeListItem* _ItemForShape(Shape* shape) const; + void _MakeEmpty(); + + BMessage* fMessage; + + ShapeContainer* fShapeContainer; + Selection* fSelection; +}; + +#endif // SHAPE_LIST_VIEW_H diff --git a/src/apps/icon-o-matic/shape/Shape.cpp b/src/apps/icon-o-matic/shape/Shape.cpp index ce2f19e514..a467f415ad 100644 --- a/src/apps/icon-o-matic/shape/Shape.cpp +++ b/src/apps/icon-o-matic/shape/Shape.cpp @@ -23,7 +23,9 @@ Shape::Shape(::Style* style) fPathSource(fPaths), fTransformers(4), - fLastBounds(0, 0, -1, -1) + fLastBounds(0, 0, -1, -1), + + fName("") { if (fPaths) fPaths->AddListener(this); @@ -77,6 +79,16 @@ Shape::ObjectChanged(const Observable* object) // #pragma mark - +// SelectedChanged +void +Shape::SelectedChanged() +{ + // simply pass on the event for now + Notify(); +} + +// #pragma mark - + // InitCheck status_t Shape::InitCheck() const @@ -158,3 +170,24 @@ Shape::AppendTransformer(Transformer* transformer) Notify(); return true; } + +// #pragma mark - + +// SetName +void +Shape::SetName(const char* name) +{ + if (fName == name) + return; + + fName = name; + Notify(); +} + +// Name +const char* +Shape::Name() const +{ + return fName.String(); +} + diff --git a/src/apps/icon-o-matic/shape/Shape.h b/src/apps/icon-o-matic/shape/Shape.h index e0409ad3c1..6b1a024749 100644 --- a/src/apps/icon-o-matic/shape/Shape.h +++ b/src/apps/icon-o-matic/shape/Shape.h @@ -3,18 +3,21 @@ #include #include +#include #include "Observable.h" #include "Observer.h" #include "PathContainer.h" #include "PathSource.h" #include "Referenceable.h" +#include "Selectable.h" class Style; class Shape : public Observable, public Observer, // observing all the paths public Referenceable, + public Selectable, public PathContainerListener { public: Shape(::Style* style); @@ -27,6 +30,9 @@ class Shape : public Observable, // Observer interface virtual void ObjectChanged(const Observable* object); + // Selectable interface + virtual void SelectedChanged(); + // Shape status_t InitCheck() const; @@ -45,6 +51,9 @@ class Shape : public Observable, bool AppendTransformer( Transformer* transformer); + void SetName(const char* name); + const char* Name() const; + private: PathContainer* fPaths; ::Style* fStyle; @@ -53,6 +62,8 @@ class Shape : public Observable, BList fTransformers; mutable BRect fLastBounds; + + BString fName; }; #endif // SHAPE_H diff --git a/src/apps/icon-o-matic/shape/VectorPath.cpp b/src/apps/icon-o-matic/shape/VectorPath.cpp index 822159365d..4220b9465f 100644 --- a/src/apps/icon-o-matic/shape/VectorPath.cpp +++ b/src/apps/icon-o-matic/shape/VectorPath.cpp @@ -78,7 +78,8 @@ VectorPath::VectorPath() fClosed(false), fPointCount(0), fAllocCount(0), - fCachedBounds(0.0, 0.0, -1.0, -1.0) + fCachedBounds(0.0, 0.0, -1.0, -1.0), + fName("") { } @@ -90,7 +91,8 @@ VectorPath::VectorPath(const VectorPath& from) fPath(NULL), fPointCount(0), fAllocCount(0), - fCachedBounds(0.0, 0.0, -1.0, -1.0) + fCachedBounds(0.0, 0.0, -1.0, -1.0), + fName() { *this = from; } @@ -104,7 +106,8 @@ VectorPath::VectorPath(const BMessage* archive) fClosed(false), fPointCount(0), fAllocCount(0), - fCachedBounds(0.0, 0.0, -1.0, -1.0) + fCachedBounds(0.0, 0.0, -1.0, -1.0), + fName() { if (archive) { type_code typeFound; @@ -130,6 +133,9 @@ VectorPath::VectorPath(const BMessage* archive) if (archive->FindBool("path closed", &fClosed) < B_OK) { fClosed = false; } + if (archive->FindString("name", &fName) < B_OK) { + fName = ""; + } } } @@ -155,6 +161,7 @@ VectorPath::operator=(const VectorPath& from) fPointCount = 0; fCachedBounds.Set(0.0, 0.0, -1.0, -1.0); } + fName = from.fName; return *this; } @@ -171,46 +178,53 @@ status_t VectorPath::Archive(BMessage* into, bool deep) const { status_t ret = BArchivable::Archive(into, deep); - if (ret >= B_OK) { - if (fPointCount > 0) { - // improve BMessage efficency by preallocating storage for all points - // with the first call - ret = into->AddData("point", B_POINT_TYPE, &fPath[0].point, + if (ret < B_OK) + return ret; + + if (fPointCount > 0) { + // improve BMessage efficency by preallocating storage for all points + // with the first call + ret = into->AddData("point", B_POINT_TYPE, &fPath[0].point, + sizeof(BPoint), true, fPointCount); + if (ret >= B_OK) + ret = into->AddData("point in", B_POINT_TYPE, &fPath[0].point_in, sizeof(BPoint), true, fPointCount); + if (ret >= B_OK) + ret = into->AddData("point out", B_POINT_TYPE, &fPath[0].point_out, + sizeof(BPoint), true, fPointCount); + if (ret >= B_OK) + ret = into->AddData("connected", B_BOOL_TYPE, &fPath[0].connected, + sizeof(bool), true, fPointCount); + // add the rest of the points + for (int32 i = 1; i < fPointCount && ret >= B_OK; i++) { + ret = into->AddData("point", B_POINT_TYPE, &fPath[i].point, sizeof(BPoint)); if (ret >= B_OK) - ret = into->AddData("point in", B_POINT_TYPE, &fPath[0].point_in, - sizeof(BPoint), true, fPointCount); + ret = into->AddData("point in", B_POINT_TYPE, &fPath[i].point_in, sizeof(BPoint)); if (ret >= B_OK) - ret = into->AddData("point out", B_POINT_TYPE, &fPath[0].point_out, - sizeof(BPoint), true, fPointCount); + ret = into->AddData("point out", B_POINT_TYPE, &fPath[i].point_out, sizeof(BPoint)); if (ret >= B_OK) - ret = into->AddData("connected", B_BOOL_TYPE, &fPath[0].connected, - sizeof(bool), true, fPointCount); - // add the rest of the points - for (int32 i = 1; i < fPointCount && ret >= B_OK; i++) { - ret = into->AddData("point", B_POINT_TYPE, &fPath[i].point, sizeof(BPoint)); - if (ret >= B_OK) - ret = into->AddData("point in", B_POINT_TYPE, &fPath[i].point_in, sizeof(BPoint)); - if (ret >= B_OK) - ret = into->AddData("point out", B_POINT_TYPE, &fPath[i].point_out, sizeof(BPoint)); - if (ret >= B_OK) - ret = into->AddData("connected", B_BOOL_TYPE, &fPath[i].connected, sizeof(bool)); - } - } - - if (ret >= B_OK) { - ret = into->AddBool("path closed", fClosed); - } else { - fprintf(stderr, "failed adding points!\n"); - } - if (ret < B_OK) { - fprintf(stderr, "failed adding closed!\n"); - } - // finish off - if (ret < B_OK) { - ret = into->AddString("class", "VectorPath"); + ret = into->AddData("connected", B_BOOL_TYPE, &fPath[i].connected, sizeof(bool)); } } + + if (ret >= B_OK) { + ret = into->AddBool("path closed", fClosed); + } else { + fprintf(stderr, "failed adding points!\n"); + } + if (ret >= B_OK) { + ret = into->AddString("name", fName.String()); + } else { + fprintf(stderr, "failed adding close!\n"); + } + if (ret < B_OK) { + fprintf(stderr, "failed adding name!\n"); + } + // finish off + if (ret < B_OK) { + ret = into->AddString("class", "VectorPath"); + } + return ret; } @@ -829,6 +843,28 @@ VectorPath::_SetPoint(int32 index, BPoint point) fCachedBounds.Set(0.0, 0.0, -1.0, -1.0); } +// #pragma mark - + +// SetName +void +VectorPath::SetName(const char* name) +{ + if (fName == name) + return; + + fName = name; + Notify(); +} + +// Name +const char* +VectorPath::Name() const +{ + return fName.String(); +} + +// #pragma mark - + // _SetPointCount bool VectorPath::_SetPointCount(int32 count) diff --git a/src/apps/icon-o-matic/shape/VectorPath.h b/src/apps/icon-o-matic/shape/VectorPath.h index 2a5c78c949..98f59545ce 100644 --- a/src/apps/icon-o-matic/shape/VectorPath.h +++ b/src/apps/icon-o-matic/shape/VectorPath.h @@ -11,6 +11,7 @@ #include #include +#include #include @@ -121,6 +122,9 @@ class VectorPath : public BArchivable, bool GetAGGPathStorage(agg::path_storage& path) const; + void SetName(const char* name); + const char* Name() const; + private: BRect _Bounds() const; void _SetPoint(int32 index, BPoint point); @@ -134,6 +138,9 @@ class VectorPath : public BArchivable, int32 fAllocCount; mutable BRect fCachedBounds; + + // TODO: should this really be part of VectorPath? + BString fName; }; #endif // VECTOR_PATH_H