* 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:
Stephan Aßmus 2006-06-22 00:22:23 +00:00
parent 63a9a8f72a
commit ce181bb0cd
15 changed files with 231 additions and 30 deletions

View File

@ -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());

View File

@ -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;

View File

@ -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 -

View File

@ -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;
// ----
}

View File

@ -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

View File

@ -33,6 +33,7 @@ Document::Document(const char* name)
// destructor
Document::~Document()
{
delete fIcon;
delete fCommandStack;
delete fSelection;
delete fRef;

View File

@ -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);
}
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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 -