* fixed memory leaks and display bugs
* VectorPath objects were released one two many times by the Shape PathContainers (they don't acquire when a path is added, the Shape does that for them) the PathContainer of the Icon needs to release though, as it "owns" the paths * put the Selection class used by PathManipulator into the PathManipulator namespace, since the compiler seemed to use the wrong destructor (the one from the generic Selection class) * uses a better mechanism to track and render changed parts of icon git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17903 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
63a9a8f72a
commit
ce181bb0cd
@ -21,7 +21,9 @@ CanvasView::CanvasView(BRect frame)
|
||||
: StateView(frame, "canvas view", B_FOLLOW_ALL,
|
||||
B_WILL_DRAW | B_FRAME_EVENTS),
|
||||
fBitmap(new BBitmap(BRect(0, 0, 63, 63), 0, B_RGB32)),
|
||||
fIcon(NULL),
|
||||
fRenderer(new IconRenderer(fBitmap)),
|
||||
fDirtyIconArea(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN),
|
||||
|
||||
fCanvasOrigin(50.0, 50.0),
|
||||
fZoomLevel(8.0),
|
||||
@ -37,6 +39,7 @@ CanvasView::CanvasView(BRect frame)
|
||||
// destructor
|
||||
CanvasView::~CanvasView()
|
||||
{
|
||||
SetIcon(NULL);
|
||||
delete fRenderer;
|
||||
delete fBitmap;
|
||||
|
||||
@ -101,13 +104,40 @@ CanvasView::Draw(BRect updateRect)
|
||||
}
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// AreaInvalidated
|
||||
void
|
||||
CanvasView::AreaInvalidated(const BRect& area)
|
||||
{
|
||||
if (fDirtyIconArea.Contains(area))
|
||||
return;
|
||||
|
||||
fDirtyIconArea = fDirtyIconArea | area;
|
||||
|
||||
BRect viewArea(area);
|
||||
ConvertFromCanvas(&viewArea);
|
||||
Invalidate(viewArea);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// SetIcon
|
||||
void
|
||||
CanvasView::SetIcon(Icon* icon)
|
||||
{
|
||||
if (fIcon == icon)
|
||||
return;
|
||||
|
||||
if (fIcon)
|
||||
fIcon->RemoveListener(this);
|
||||
|
||||
fIcon = icon;
|
||||
fRenderer->SetIcon(icon);
|
||||
|
||||
if (fIcon)
|
||||
fIcon->AddListener(this);
|
||||
}
|
||||
|
||||
// ConvertFromCanvas
|
||||
@ -234,9 +264,10 @@ CanvasView::_FreeBackBitmap()
|
||||
void
|
||||
CanvasView::_DrawInto(BView* view, BRect updateRect)
|
||||
{
|
||||
// TODO: don't render here, use some
|
||||
// listener technique on the shapes instead...
|
||||
fRenderer->Render();
|
||||
if (fDirtyIconArea.IsValid()) {
|
||||
fRenderer->Render(fDirtyIconArea);
|
||||
fDirtyIconArea.Set(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN);
|
||||
}
|
||||
|
||||
// icon
|
||||
BRect canvas(_CanvasRect());
|
||||
|
@ -9,13 +9,14 @@
|
||||
#ifndef CANVAS_VIEW_H
|
||||
#define CANVAS_VIEW_H
|
||||
|
||||
#include "Icon.h"
|
||||
#include "StateView.h"
|
||||
|
||||
class BBitmap;
|
||||
class Icon;
|
||||
class IconRenderer;
|
||||
|
||||
class CanvasView : public StateView {
|
||||
class CanvasView : public StateView,
|
||||
public IconListener {
|
||||
public:
|
||||
CanvasView(BRect frame);
|
||||
virtual ~CanvasView();
|
||||
@ -25,6 +26,9 @@ class CanvasView : public StateView {
|
||||
virtual void FrameResized(float width, float height);
|
||||
virtual void Draw(BRect updateRect);
|
||||
|
||||
// IconListener interface
|
||||
virtual void AreaInvalidated(const BRect& area);
|
||||
|
||||
// CanvasView
|
||||
void SetIcon(Icon* icon);
|
||||
|
||||
@ -52,7 +56,9 @@ class CanvasView : public StateView {
|
||||
|
||||
private:
|
||||
BBitmap* fBitmap;
|
||||
Icon* fIcon;
|
||||
IconRenderer* fRenderer;
|
||||
BRect fDirtyIconArea;
|
||||
|
||||
BPoint fCanvasOrigin;
|
||||
float fZoomLevel;
|
||||
|
@ -28,6 +28,10 @@ IconEditorApp::IconEditorApp()
|
||||
// destructor
|
||||
IconEditorApp::~IconEditorApp()
|
||||
{
|
||||
// NOTE: it is important that the GUI has been deleted
|
||||
// at this point, so that all the listener/observer
|
||||
// stuff is properly detached
|
||||
delete fDocument;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
@ -44,6 +44,7 @@ MainWindow::MainWindow(IconEditorApp* app, Document* document)
|
||||
// destructor
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete fState;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
@ -139,6 +140,7 @@ MainWindow::_Init()
|
||||
|
||||
PathManipulator* pathManipulator = new PathManipulator(path);
|
||||
state->AddManipulator(pathManipulator);
|
||||
fState = state;
|
||||
// ----
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
class CanvasView;
|
||||
class Document;
|
||||
class IconEditorApp;
|
||||
class ViewState;
|
||||
|
||||
class MainWindow : public BWindow {
|
||||
public:
|
||||
@ -33,6 +34,8 @@ class MainWindow : public BWindow {
|
||||
Document* fDocument;
|
||||
|
||||
CanvasView* fCanvasView;
|
||||
// TODO: for testing only...
|
||||
ViewState* fState;
|
||||
};
|
||||
|
||||
#endif // MAIN_WINDOW_H
|
||||
|
@ -33,6 +33,7 @@ Document::Document(const char* name)
|
||||
// destructor
|
||||
Document::~Document()
|
||||
{
|
||||
delete fIcon;
|
||||
delete fCommandStack;
|
||||
delete fSelection;
|
||||
delete fRef;
|
||||
|
@ -11,21 +11,101 @@
|
||||
#include <new>
|
||||
|
||||
#include "PathContainer.h"
|
||||
#include "ShapeContainer.h"
|
||||
#include "Shape.h"
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
// constructor
|
||||
Icon::Icon()
|
||||
: fPaths(new (nothrow) PathContainer()),
|
||||
fShapes(new (nothrow) ShapeContainer())
|
||||
IconListener::IconListener()
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
IconListener::~IconListener()
|
||||
{
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
Icon::Icon()
|
||||
: fPaths(new (nothrow) PathContainer(true)),
|
||||
fShapes(new (nothrow) ShapeContainer()),
|
||||
fListeners(2)
|
||||
{
|
||||
if (fShapes)
|
||||
fShapes->AddListener(this);
|
||||
}
|
||||
|
||||
// destructor
|
||||
Icon::~Icon()
|
||||
{
|
||||
delete fShapes;
|
||||
if (fShapes) {
|
||||
fShapes->MakeEmpty();
|
||||
fShapes->RemoveListener(this);
|
||||
delete fShapes;
|
||||
}
|
||||
delete fPaths;
|
||||
}
|
||||
|
||||
// ShapeAdded
|
||||
void
|
||||
Icon::ShapeAdded(Shape* shape)
|
||||
{
|
||||
shape->AddObserver(this);
|
||||
_NotifyAreaInvalidated(shape->Bounds());
|
||||
}
|
||||
|
||||
// ShapeRemoved
|
||||
void
|
||||
Icon::ShapeRemoved(Shape* shape)
|
||||
{
|
||||
shape->RemoveObserver(this);
|
||||
_NotifyAreaInvalidated(shape->Bounds());
|
||||
}
|
||||
|
||||
// ObjectChanged
|
||||
void
|
||||
Icon::ObjectChanged(const Observable* object)
|
||||
{
|
||||
const Shape* shape = dynamic_cast<const Shape*>(object);
|
||||
if (shape) {
|
||||
BRect area = shape->LastBounds();
|
||||
area = area | shape->Bounds(true);
|
||||
area.InsetBy(-1, -1);
|
||||
_NotifyAreaInvalidated(area);
|
||||
}
|
||||
}
|
||||
|
||||
// AddListener
|
||||
bool
|
||||
Icon::AddListener(IconListener* listener)
|
||||
{
|
||||
if (listener && !fListeners.HasItem((void*)listener))
|
||||
return fListeners.AddItem((void*)listener);
|
||||
return false;
|
||||
}
|
||||
|
||||
// RemoveListener
|
||||
bool
|
||||
Icon::RemoveListener(IconListener* listener)
|
||||
{
|
||||
return fListeners.RemoveItem((void*)listener);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _NotifyShapeRemoved
|
||||
void
|
||||
Icon::_NotifyAreaInvalidated(const BRect& area) const
|
||||
{
|
||||
BList listeners(fListeners);
|
||||
int32 count = listeners.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
IconListener* listener
|
||||
= (IconListener*)listeners.ItemAtFast(i);
|
||||
listener->AreaInvalidated(area);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -9,22 +9,51 @@
|
||||
#ifndef ICON_H
|
||||
#define ICON_H
|
||||
|
||||
class PathContainer;
|
||||
class ShapeContainer;
|
||||
#include <List.h>
|
||||
|
||||
class Icon {
|
||||
#include "Observer.h"
|
||||
#include "ShapeContainer.h"
|
||||
|
||||
class PathContainer;
|
||||
|
||||
class IconListener {
|
||||
public:
|
||||
IconListener();
|
||||
virtual ~IconListener();
|
||||
|
||||
virtual void AreaInvalidated(const BRect& area) = 0;
|
||||
};
|
||||
|
||||
class Icon : public ShapeContainerListener,
|
||||
public Observer {
|
||||
public:
|
||||
Icon();
|
||||
virtual ~Icon();
|
||||
|
||||
// ShapeContainerListener interface
|
||||
virtual void ShapeAdded(Shape* shape);
|
||||
virtual void ShapeRemoved(Shape* shape);
|
||||
|
||||
// Observer interface
|
||||
virtual void ObjectChanged(const Observable* object);
|
||||
|
||||
// Icon
|
||||
PathContainer* Paths() const
|
||||
{ return fPaths; }
|
||||
ShapeContainer* Shapes() const
|
||||
{ return fShapes; }
|
||||
|
||||
bool AddListener(IconListener* listener);
|
||||
bool RemoveListener(IconListener* listener);
|
||||
|
||||
private:
|
||||
void _NotifyAreaInvalidated(
|
||||
const BRect& area) const;
|
||||
|
||||
PathContainer* fPaths;
|
||||
ShapeContainer* fShapes;
|
||||
|
||||
BList fListeners;
|
||||
};
|
||||
|
||||
#endif // ICON_H
|
||||
|
@ -28,9 +28,10 @@ PathContainerListener::~PathContainerListener()
|
||||
|
||||
|
||||
// constructor
|
||||
PathContainer::PathContainer()
|
||||
PathContainer::PathContainer(bool ownsPaths)
|
||||
: fPaths(16),
|
||||
fListeners(2)
|
||||
fListeners(2),
|
||||
fOwnsPaths(ownsPaths)
|
||||
{
|
||||
}
|
||||
|
||||
@ -156,7 +157,8 @@ PathContainer::_MakeEmpty()
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
VectorPath* path = PathAtFast(i);
|
||||
_NotifyPathRemoved(path);
|
||||
path->Release();
|
||||
if (fOwnsPaths)
|
||||
path->Release();
|
||||
}
|
||||
fPaths.MakeEmpty();
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ class PathContainerListener {
|
||||
|
||||
class PathContainer {
|
||||
public:
|
||||
PathContainer();
|
||||
PathContainer(bool ownsPaths);
|
||||
virtual ~PathContainer();
|
||||
|
||||
bool AddPath(VectorPath* path);
|
||||
@ -50,6 +50,7 @@ class PathContainer {
|
||||
|
||||
BList fPaths;
|
||||
BList fListeners;
|
||||
bool fOwnsPaths;
|
||||
};
|
||||
|
||||
#endif // PATH_CONTAINER_H
|
||||
|
@ -109,7 +109,7 @@ string_for_mode(uint32 mode)
|
||||
return "<unknown mode>";
|
||||
}
|
||||
|
||||
class Selection : protected BList
|
||||
class PathManipulator::Selection : protected BList
|
||||
{
|
||||
public:
|
||||
inline Selection(int32 count = 20)
|
||||
|
@ -16,7 +16,6 @@ class CanvasView;
|
||||
class ChangePointCommand;
|
||||
class UndoStack;
|
||||
class InsertPointCommand;
|
||||
class Selection;
|
||||
class VectorPath;
|
||||
|
||||
//class PathSelection {
|
||||
@ -146,6 +145,7 @@ class PathManipulator : public Manipulator {
|
||||
InsertPointCommand* fInsertPointCommand;
|
||||
AddPointCommand* fAddPointCommand;
|
||||
|
||||
class Selection;
|
||||
Selection* fSelection;
|
||||
Selection* fOldSelection;
|
||||
|
||||
|
@ -2,6 +2,9 @@
|
||||
|
||||
#include <new>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "agg_bounding_rect.h"
|
||||
|
||||
#include "Style.h"
|
||||
#include "VectorPath.h"
|
||||
@ -13,10 +16,14 @@ Shape::Shape(::Style* style)
|
||||
: Observable(),
|
||||
Referenceable(),
|
||||
PathContainerListener(),
|
||||
fPaths(new (nothrow) PathContainer()),
|
||||
|
||||
fPaths(new (nothrow) PathContainer(false)),
|
||||
fStyle(style),
|
||||
|
||||
fPathSource(fPaths),
|
||||
fTransformers(4)
|
||||
fTransformers(4),
|
||||
|
||||
fLastBounds(0, 0, -1, -1)
|
||||
{
|
||||
if (fPaths)
|
||||
fPaths->AddListener(this);
|
||||
@ -45,17 +52,31 @@ void
|
||||
Shape::PathAdded(VectorPath* path)
|
||||
{
|
||||
path->Acquire();
|
||||
path->AddObserver(this);
|
||||
Notify();
|
||||
}
|
||||
|
||||
// PathRemoved
|
||||
void
|
||||
Shape::PathRemoved(VectorPath* path)
|
||||
{
|
||||
path->RemoveObserver(this);
|
||||
Notify();
|
||||
path->Release();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// ObjectChanged
|
||||
void
|
||||
Shape::ObjectChanged(const Observable* object)
|
||||
{
|
||||
// simply pass on the event for now
|
||||
Notify();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// InitCheck
|
||||
status_t
|
||||
Shape::InitCheck() const
|
||||
@ -83,14 +104,26 @@ Shape::SetStyle(::Style* style)
|
||||
|
||||
// Bounds
|
||||
BRect
|
||||
Shape::Bounds() const
|
||||
Shape::Bounds(bool updateLast) const
|
||||
{
|
||||
// TODO: incorrect - use VertexSource instead!!
|
||||
BRect bounds(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN);
|
||||
// TODO: what about sub-paths?!?
|
||||
// the problem is that the path ids are
|
||||
// nowhere stored while converting VectorPath
|
||||
// to agg::path_storage, but it is also unclear
|
||||
// if those would mean anything later on in
|
||||
// the Transformer pipeline
|
||||
uint32 pathID[1];
|
||||
pathID[0] = 0;
|
||||
double left, top, right, bottom;
|
||||
|
||||
int32 count = fPaths->CountPaths();
|
||||
for (int32 i = 0; i < count; i++)
|
||||
bounds = bounds | fPaths->PathAtFast(i)->Bounds();
|
||||
::VertexSource& source = const_cast<Shape*>(this)->VertexSource();
|
||||
agg::bounding_rect(source, pathID, 0, 1,
|
||||
&left, &top, &right, &bottom);
|
||||
|
||||
BRect bounds(left, top, right, bottom);
|
||||
|
||||
if (updateLast)
|
||||
fLastBounds = bounds;
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <Rect.h>
|
||||
|
||||
#include "Observable.h"
|
||||
#include "Observer.h"
|
||||
#include "PathContainer.h"
|
||||
#include "PathSource.h"
|
||||
#include "Referenceable.h"
|
||||
@ -12,6 +13,7 @@
|
||||
class Style;
|
||||
|
||||
class Shape : public Observable,
|
||||
public Observer, // observing all the paths
|
||||
public Referenceable,
|
||||
public PathContainerListener {
|
||||
public:
|
||||
@ -22,6 +24,9 @@ class Shape : public Observable,
|
||||
virtual void PathAdded(VectorPath* path);
|
||||
virtual void PathRemoved(VectorPath* path);
|
||||
|
||||
// Observer interface
|
||||
virtual void ObjectChanged(const Observable* object);
|
||||
|
||||
// Shape
|
||||
status_t InitCheck() const;
|
||||
|
||||
@ -32,7 +37,9 @@ class Shape : public Observable,
|
||||
inline ::Style* Style() const
|
||||
{ return fStyle; }
|
||||
|
||||
BRect Bounds() const;
|
||||
inline BRect LastBounds() const
|
||||
{ return fLastBounds; }
|
||||
BRect Bounds(bool updateLast = false) const;
|
||||
|
||||
::VertexSource& VertexSource();
|
||||
bool AppendTransformer(
|
||||
@ -44,6 +51,8 @@ class Shape : public Observable,
|
||||
|
||||
PathSource fPathSource;
|
||||
BList fTransformers;
|
||||
|
||||
mutable BRect fLastBounds;
|
||||
};
|
||||
|
||||
#endif // SHAPE_H
|
||||
|
@ -135,7 +135,7 @@ bool
|
||||
ShapeContainer::AddListener(ShapeContainerListener* listener)
|
||||
{
|
||||
if (listener && !fListeners.HasItem((void*)listener))
|
||||
return fListeners.AddItem(listener);
|
||||
return fListeners.AddItem((void*)listener);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -143,7 +143,7 @@ ShapeContainer::AddListener(ShapeContainerListener* listener)
|
||||
bool
|
||||
ShapeContainer::RemoveListener(ShapeContainerListener* listener)
|
||||
{
|
||||
return fListeners.RemoveItem(listener);
|
||||
return fListeners.RemoveItem((void*)listener);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
Loading…
Reference in New Issue
Block a user