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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
// ----
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user