some more "putting things together" for testing:

* add a VectorPath to Document->Icon()->Paths()
* add a Style to the global StyleManager
* actually add a Shape to the Document->Icon()->Shapes()
  which uses the style and the path from above

fleshing out of CanvasView:
* use an offscreen bitmap/view to avoid flickering
* use an IconRenderer to render the set Icon
* implement support for zooming

PathManipulator:
* use the conversion from/to Canvas space and View space
  in CanvasView (I would have liked to solve this in a
  more generic way, so that PathManipulator didn't have to
  know CanvasView, but I was not very creative...)



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17891 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2006-06-21 10:43:19 +00:00
parent 3f6acee003
commit f67876a0c5
5 changed files with 312 additions and 37 deletions
+211 -6
View File
@@ -8,22 +8,151 @@
#include "CanvasView.h"
#include "CommandStack.h"
#include <Bitmap.h>
#include <Region.h>
#include "ui_defines.h"
#include "CommandStack.h"
#include "IconRenderer.h"
// constructor
CanvasView::CanvasView(BRect frame)
: StateView(frame, "canvas view", B_FOLLOW_ALL, B_WILL_DRAW)
: StateView(frame, "canvas view", B_FOLLOW_ALL,
B_WILL_DRAW | B_FRAME_EVENTS),
fBitmap(new BBitmap(BRect(0, 0, 63, 63), 0, B_RGB32)),
fRenderer(new IconRenderer(fBitmap)),
fCanvasOrigin(50.0, 50.0),
fZoomLevel(8.0),
fOffsreenBitmap(NULL),
fOffsreenView(NULL)
{
#if __HAIKU__
#if __HAIKU__
SetFlags(Flags() | B_SUBPIXEL_PRECISE);
#endif // __HAIKU__
#endif // __HAIKU__
}
// destructor
CanvasView::~CanvasView()
{
delete fRenderer;
delete fBitmap;
_FreeBackBitmap();
}
// #pragma mark -
// AttachedToWindow
void
CanvasView::AttachedToWindow()
{
StateView::AttachedToWindow();
SetViewColor(B_TRANSPARENT_COLOR);
SetLowColor(kStripesHigh);
SetHighColor(kStripesLow);
_AllocBackBitmap(Bounds().Width(), Bounds().Height());
}
// FrameResized
void
CanvasView::FrameResized(float width, float height)
{
_AllocBackBitmap(width, height);
}
// Draw
void
CanvasView::Draw(BRect updateRect)
{
if (!fOffsreenView) {
_DrawInto(this, updateRect);
} else {
BPoint boundsLeftTop = Bounds().LeftTop();
if (fOffsreenBitmap->Lock()) {
fOffsreenView->PushState();
// apply scrolling offset to offscreen view
fOffsreenView->SetOrigin(-boundsLeftTop.x, -boundsLeftTop.y);
// mirror the clipping of this view
// to the offscreen view for performance
BRegion clipping;
GetClippingRegion(&clipping);
fOffsreenView->ConstrainClippingRegion(&clipping);
fOffsreenView->FillRect(updateRect, B_SOLID_LOW);
_DrawInto(fOffsreenView, updateRect);
fOffsreenView->PopState();
fOffsreenView->Sync();
fOffsreenBitmap->Unlock();
}
// compensate scrolling offset in BView
BRect bitmapRect = updateRect;
bitmapRect.OffsetBy(-boundsLeftTop.x, -boundsLeftTop.y);
SetDrawingMode(B_OP_COPY);
DrawBitmap(fOffsreenBitmap, bitmapRect, updateRect);
}
}
// #pragma mark -
// SetIcon
void
CanvasView::SetIcon(Icon* icon)
{
fRenderer->SetIcon(icon);
}
// ConvertFromCanvas
void
CanvasView::ConvertFromCanvas(BPoint* point) const
{
point->x = point->x * fZoomLevel + fCanvasOrigin.x;
point->y = point->y * fZoomLevel + fCanvasOrigin.y;
}
// ConvertToCanvas
void
CanvasView::ConvertToCanvas(BPoint* point) const
{
point->x = (point->x - fCanvasOrigin.x) / fZoomLevel;
point->y = (point->y - fCanvasOrigin.y) / fZoomLevel;
}
// ConvertFromCanvas
void
CanvasView::ConvertFromCanvas(BRect* r) const
{
r->left = r->left * fZoomLevel + fCanvasOrigin.x;
r->top = r->top * fZoomLevel + fCanvasOrigin.y;
r->right++;
r->bottom++;
r->right = r->right * fZoomLevel + fCanvasOrigin.x;
r->bottom = r->bottom * fZoomLevel + fCanvasOrigin.y;
r->right--;
r->bottom--;
}
// ConvertToCanvas
void
CanvasView::ConvertToCanvas(BRect* r) const
{
r->left = (r->left - fCanvasOrigin.x) / fZoomLevel;
r->top = (r->top - fCanvasOrigin.y) / fZoomLevel;
r->right = (r->right - fCanvasOrigin.x) / fZoomLevel;
r->bottom = (r->bottom - fCanvasOrigin.y) / fZoomLevel;
}
// #pragma mark -
// _HandleKeyDown
bool
CanvasView::_HandleKeyDown(uint32 key, uint32 modifiers)
{
@@ -37,11 +166,87 @@ CanvasView::_HandleKeyDown(uint32 key, uint32 modifiers)
break;
default:
return StateView::HandleKeyDown(key, modifiers);
return StateView::_HandleKeyDown(key, modifiers);
}
return true;
}
// _CanvasRect()
BRect
CanvasView::_CanvasRect() const
{
BRect r = fBitmap->Bounds();
ConvertFromCanvas(&r);
return r;
}
// _AllocBackBitmap
void
CanvasView::_AllocBackBitmap(float width, float height)
{
// sanity check
if (width <= 0.0 || height <= 0.0)
return;
if (fOffsreenBitmap) {
// see if the bitmap needs to be expanded
BRect b = fOffsreenBitmap->Bounds();
if (b.Width() >= width && b.Height() >= height)
return;
// it does; clean up:
_FreeBackBitmap();
}
BRect b(0.0, 0.0, width, height);
fOffsreenBitmap = new (nothrow) BBitmap(b, B_RGB32, true);
if (!fOffsreenBitmap) {
fprintf(stderr, "CanvasView::_AllocBackBitmap(): failed to allocate\n");
return;
}
if (fOffsreenBitmap->IsValid()) {
fOffsreenView = new BView(b, 0, B_FOLLOW_NONE, B_WILL_DRAW);
BFont font;
GetFont(&font);
fOffsreenView->SetFont(&font);
fOffsreenView->SetHighColor(HighColor());
fOffsreenView->SetLowColor(LowColor());
fOffsreenBitmap->AddChild(fOffsreenView);
} else {
_FreeBackBitmap();
fprintf(stderr, "CanvasView::_AllocBackBitmap(): bitmap invalid\n");
}
}
// _FreeBackBitmap
void
CanvasView::_FreeBackBitmap()
{
if (fOffsreenBitmap) {
delete fOffsreenBitmap;
fOffsreenBitmap = NULL;
fOffsreenView = NULL;
}
}
// _DrawInto
void
CanvasView::_DrawInto(BView* view, BRect updateRect)
{
// TODO: don't render here, use some
// listener technique on the shapes instead...
fRenderer->Render();
// icon
BRect canvas(_CanvasRect());
view->DrawBitmap(fBitmap, fBitmap->Bounds(), canvas);
// outside icon
BRegion outside(Bounds() & updateRect);
outside.Exclude(canvas);
view->FillRegion(&outside, kStripes);
StateView::Draw(view, updateRect);
}
+38
View File
@@ -11,16 +11,54 @@
#include "StateView.h"
class BBitmap;
class Icon;
class IconRenderer;
class CanvasView : public StateView {
public:
CanvasView(BRect frame);
virtual ~CanvasView();
// StateView interface
virtual void AttachedToWindow();
virtual void FrameResized(float width, float height);
virtual void Draw(BRect updateRect);
// CanvasView
void SetIcon(Icon* icon);
inline float ZoomLevel() const
{ return fZoomLevel; }
void ConvertFromCanvas(BPoint* point) const;
void ConvertToCanvas(BPoint* point) const;
void ConvertFromCanvas(BRect* rect) const;
void ConvertToCanvas(BRect* rect) const;
protected:
// StateView interface
virtual bool _HandleKeyDown(uint32 key, uint32 modifiers);
// CanvasView
BRect _CanvasRect() const;
void _AllocBackBitmap(float width,
float height);
void _FreeBackBitmap();
void _DrawInto(BView* view,
BRect updateRect);
private:
BBitmap* fBitmap;
IconRenderer* fRenderer;
BPoint fCanvasOrigin;
float fZoomLevel;
BBitmap* fOffsreenBitmap;
BView* fOffsreenView;
};
#endif // CANVAS_VIEW_H
+20 -1
View File
@@ -17,13 +17,18 @@
#include "IconEditorApp.h"
// TODO: just for testing
#include "Icon.h"
#include "MultipleManipulatorState.h"
#include "PathManipulator.h"
#include "Shape.h"
#include "ShapeContainer.h"
#include "Style.h"
#include "StyleManager.h"
#include "VectorPath.h"
// constructor
MainWindow::MainWindow(IconEditorApp* app, Document* document)
: BWindow(BRect(50.0, 50.0, 689, 529), "Icon-O-Matic",
: BWindow(BRect(50, 50, 661, 661), "Icon-O-Matic",
B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
B_ASYNCHRONOUS_CONTROLS),
fApp(app),
@@ -75,12 +80,26 @@ MainWindow::_Init()
fCanvasView->SetCatchAllEvents(true);
fCanvasView->SetCommandStack(fDocument->CommandStack());
// fCanvasView->SetSelection(fDocument->Selection());
fCanvasView->SetIcon(fDocument->Icon());
// TODO: for testing only:
MultipleManipulatorState* state = new MultipleManipulatorState(fCanvasView);
fCanvasView->SetState(state);
VectorPath* path = new VectorPath();
fDocument->Icon()->Paths()->AddPath(path);
Style* style = new Style();
style->SetColor((rgb_color){ 255, 0, 0, 255 });
StyleManager::Default()->AddStyle(style);
Shape* shape = new Shape(style);
shape->Paths()->AddPath(path);
fDocument->Icon()->Shapes()->AddShape(shape);
PathManipulator* pathManipulator = new PathManipulator(path);
state->AddManipulator(pathManipulator);
// ----
+41 -28
View File
@@ -18,7 +18,7 @@
#include "cursors.h"
#include "support.h"
#include "StateView.h"
#include "CanvasView.h"
#include "VectorPath.h"
#include "AddPointCommand.h"
@@ -237,8 +237,10 @@ PathManipulator::~PathManipulator()
class StrokePathIterator : public VectorPath::Iterator {
public:
StrokePathIterator(BView* drawingView)
: fDrawingView(drawingView)
StrokePathIterator(CanvasView* canvasView,
BView* drawingView)
: fCanvasView(canvasView),
fDrawingView(drawingView)
{
fDrawingView->SetHighColor(0, 0, 0, 255);
fDrawingView->SetDrawingMode(B_OP_OVER);
@@ -249,26 +251,34 @@ class StrokePathIterator : public VectorPath::Iterator {
virtual void MoveTo(BPoint point)
{
fBlack = true;
fSkip = false;
fDrawingView->SetHighColor(0, 0, 0, 255);
// fCanvasView->ConvertFromCanvas(point);
fCanvasView->ConvertFromCanvas(&point);
fDrawingView->MovePenTo(point);
}
virtual void LineTo(BPoint point)
{
if (fBlack)
fDrawingView->SetHighColor(255, 255, 255, 255);
else
fDrawingView->SetHighColor(0, 0, 0, 255);
fBlack = !fBlack;
// fCanvasView->ConvertFromCanvas(point);
fDrawingView->StrokeLine(point);
fCanvasView->ConvertFromCanvas(&point);
if (!fSkip) {
if (fBlack)
fDrawingView->SetHighColor(255, 255, 255, 255);
else
fDrawingView->SetHighColor(0, 0, 0, 255);
fBlack = !fBlack;
fDrawingView->StrokeLine(point);
} else {
fDrawingView->MovePenTo(point);
}
fSkip = !fSkip;
}
private:
CanvasView* fCanvasView;
BView* fDrawingView;
bool fBlack;
bool fSkip;
};
// Draw
@@ -278,8 +288,8 @@ PathManipulator::Draw(BView* into, BRect updateRect)
// draw the Bezier curve, but only if editing
// if not "editing", the path is actually on top all other modifiers
// TODO: make this customizable in the GUI
StrokePathIterator iterator(into);
fPath->Iterate(&iterator, 1.0/*fCanvasView->ZoomLevel()*/);
StrokePathIterator iterator(fCanvasView, into);
fPath->Iterate(&iterator, fCanvasView->ZoomLevel());
into->SetLowColor(0, 0, 0, 255);
BPoint point;
@@ -294,9 +304,9 @@ PathManipulator::Draw(BView* into, BRect updateRect)
into->SetLowColor(normal);
into->SetHighColor(255, 255, 255, 255);
// convert to view coordinate space
// fCanvasView->ConvertFromCanvas(point);
// fCanvasView->ConvertFromCanvas(pointIn);
// fCanvasView->ConvertFromCanvas(pointOut);
fCanvasView->ConvertFromCanvas(&point);
fCanvasView->ConvertFromCanvas(&pointIn);
fCanvasView->ConvertFromCanvas(&pointOut);
// connect the points belonging to one control point
into->SetDrawingMode(B_OP_INVERT);
into->StrokeLine(point, pointIn);
@@ -369,8 +379,8 @@ PathManipulator::MouseDown(BPoint where)
fMode = TRANSLATE_POINTS;
}
// TODO: translate from BView to canvas space
BPoint canvasWhere = where;
fCanvasView->ConvertToCanvas(&canvasWhere);
// maybe we're changing some point, so we construct the
// "ChangePointCommand" here so that the point is remembered
@@ -465,8 +475,8 @@ PathManipulator::MouseDown(BPoint where)
// remember the subpixel position
// so that MouseMoved() will work even before
// the integer position becomes different
// fCanvasView->ConvertToCanvas(where);
fLastCanvasPos = where;
fCanvasView->ConvertToCanvas(&fLastCanvasPos);
// the reason to exclude the select mode
// is that the BView rect tracking does not
@@ -484,8 +494,8 @@ PathManipulator::MouseDown(BPoint where)
void
PathManipulator::MouseMoved(BPoint where)
{
// TODO: translate from BView to canvas space
BPoint canvasWhere = where;
fCanvasView->ConvertToCanvas(&canvasWhere);
// since the tablet is generating mouse moved messages
// even if only the pressure changes (and not the actual mouse position)
@@ -626,8 +636,8 @@ PathManipulator::MouseUp()
bool
PathManipulator::MouseOver(BPoint where)
{
// TODO: translate from BView to canvas space
BPoint canvasWhere = where;
fCanvasView->ConvertToCanvas(&canvasWhere);
// since the tablet is generating mouse moved messages
// even if only the pressure changes (and not the actual mouse position)
@@ -639,7 +649,7 @@ PathManipulator::MouseOver(BPoint where)
// hit testing
// (use a subpixel mouse pos)
// fCanvasView->ConvertToCanvas(where);
fCanvasView->ConvertToCanvas(&where);
_SetModeForMousePos(where);
// TODO: always true?
@@ -657,7 +667,9 @@ PathManipulator::DoubleClicked(BPoint where)
BRect
PathManipulator::Bounds()
{
return _ControlPointRect();
BRect r = _ControlPointRect();
fCanvasView->ConvertFromCanvas(&r);
return r;
}
// TrackingBounds
@@ -736,8 +748,8 @@ PathManipulator::HandleKeyDown(uint32 key, uint32 modifiers, Command** _command)
bool result = true;
float nudgeDist = 1.0;
// if (modifiers & B_SHIFT_KEY)
// nudgeDist /= fCanvasView->ZoomLevel();
if (modifiers & B_SHIFT_KEY)
nudgeDist /= fCanvasView->ZoomLevel();
switch (key) {
// commit
@@ -859,7 +871,7 @@ PathManipulator::UpdateCursor()
void
PathManipulator::AttachedToView(BView* view)
{
fCanvasView = dynamic_cast<StateView*>(view);
fCanvasView = dynamic_cast<CanvasView*>(view);
}
// DetachedFromView
@@ -1199,7 +1211,8 @@ PathManipulator::_IsSelected(int32 index) const
void
PathManipulator::_InvalidateCanvas(BRect rect) const
{
// TODO: convert from canvas to view space
// convert from canvas to view space
fCanvasView->ConvertFromCanvas(&rect);
fCanvasView->Invalidate(rect);
}
@@ -1283,7 +1296,7 @@ PathManipulator::_SetModeForMousePos(BPoint where)
uint32 mode = UNDEFINED;
int32 index = -1;
float zoomLevel = 1.0;//fCanvasView->ZoomLevel();
float zoomLevel = fCanvasView->ZoomLevel();
// see if we're close enough at a control point
BPoint point;
@@ -12,11 +12,11 @@
#include "Manipulator.h"
class AddPointCommand;
class CanvasView;
class ChangePointCommand;
class UndoStack;
class InsertPointCommand;
class Selection;
class StateView;
class VectorPath;
//class PathSelection {
@@ -122,7 +122,7 @@ class PathManipulator : public Manipulator {
void _Nudge(BPoint direction);
void _FinishNudging();
StateView* fCanvasView;
CanvasView* fCanvasView;
bool fCommandDown;
bool fOptionDown;