Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » GEF » Generic "ghost" figure for ResizableEditPolicy.createDragSourceFeedbackFigure()
Generic "ghost" figure for ResizableEditPolicy.createDragSourceFeedbackFigure() [message #205758] Wed, 21 December 2005 17:37 Go to next message
Eclipse UserFriend
Originally posted by: cricard.businessobjects.com

I'd like to submit a sexier alternative to the standard gray X-OR'ed
rectangle that appears whenever you drag and drop a part in GEF.
It should also slightly relieve those of you who have to create a "ghost"
figure for each and every kind of visual that could be moved.

The original idea was to build an alpha-blended image once and for all, then
stop painting recursively our part's children figures when the former is
dragged around (have a peek at that in a profiler).
Eventually, it's only slightly faster, but well-isolated and thus more
easily maintained since located in one spot.

A snapshot can be found there:
http://img277.imageshack.us/img277/4348/ghostimagefigure7ip. png

Please find the associated source code below, it's pretty straightforward
(and feel free to point out my bugs):

public class GhostImageFigure extends ImageFigure {
IFigure source = null;
int alpha;

public GhostImageFigure(IFigure source, int alpha) {
this.source = source;
this.alpha = alpha;

setOpaque(false);

if(source != null) {
Rectangle bounds = source.getBounds().getCopy();
Image image = new Image(Display.getCurrent(),
bounds.width, bounds.height);

GC gc = new GC(image);
SWTGraphics swtGraphics = new SWTGraphics(gc);

swtGraphics.translate(-bounds.x, -bounds.y);

source.paint(swtGraphics); // Let your figure do its
complex painting here.

ImageData data = image.getImageData();

data.alpha = alpha; // Note that changing the
ImageData has no affect on Images already constructed using it...
Image finalImage = new Image(Display.getCurrent(),
data); //... hence the creation of a second bitmap from the modified data.
setImage(finalImage);

image.dispose();
swtGraphics.dispose();
gc.dispose();
}
}

public void dispose() { // Beware, the base class ImageFigure
doesn't dispose its image...
if(getImage() != null)
getImage().dispose();
}
}

*** IMPORTANT ***
Please note that the source figure blits crappy fonts into the ghost figure
when the current zoom is not 1.0.
Example : http://img277.imageshack.us/img277/6771/ghostimagefigurebug3 mb.png
If someone could give me a hint, I'd appreciate it.... anyway, I'll
definitely add a newsgroupListener to this topic ;)

Q: When should I call GhostImageFigure's constructor?
A: Let createDragSourceFeedbackFigure() return that kind of figure in your
ResizableEditPolicy.

Q: When should I call its dispose() method?
A: From eraseChangeBoundsFeedback() in your ResizableEditPolicy.
Re: Generic "ghost" figure for ResizableEditPolicy.createDragSourceFeedbackFigure() [message #205784 is a reply to message #205758] Wed, 21 December 2005 20:22 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: sunil_kamath.nohotspammail.com

cricri <cricard@businessobjects.com> wrote:
> I'd like to submit a sexier alternative to the standard gray X-OR'ed
> rectangle that appears whenever you drag and drop a part in GEF.
> It should also slightly relieve those of you who have to create a
> "ghost" figure for each and every kind of visual that could be moved.
>
> The original idea was to build an alpha-blended image once and for
> all, then stop painting recursively our part's children figures when
> the former is dragged around (have a peek at that in a profiler).
> Eventually, it's only slightly faster, but well-isolated and thus more
> easily maintained since located in one spot.
>
[snip]

Nice! I would like to include this in my project.
Do you have a copyright notice you would like me to include with it?

--
Sunil
Re: Generic "ghost" figure for ResizableEditPolicy.createDragSourceFeedbackFigure() [message #205792 is a reply to message #205758] Wed, 21 December 2005 20:24 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: sunil_kamath.nohotspammail.com

cricri <cricard@businessobjects.com> wrote:
> I'd like to submit a sexier alternative to the standard gray X-OR'ed
> rectangle that appears whenever you drag and drop a part in GEF.
> It should also slightly relieve those of you who have to create a
> "ghost" figure for each and every kind of visual that could be moved.
>
> The original idea was to build an alpha-blended image once and for
> all, then stop painting recursively our part's children figures when
> the former is dragged around (have a peek at that in a profiler).
> Eventually, it's only slightly faster, but well-isolated and thus more
> easily maintained since located in one spot.
>
Oooh... doesn't work too well for resize feedback.
Great for move feedback, however.

--
Sunil
Re: Generic "ghost" figure for ResizableEditPolicy.createDragSourceFeedbackFigure() [message #205815 is a reply to message #205792] Thu, 22 December 2005 10:30 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: ingo.koch[nospam].sap.com

A solution would be to resize the figure and regenerate the image
in the FeedbackFigures paint method, when the dimension changes.
But you cannot change the figure
Re: Generic "ghost" figure for ResizableEditPolicy.createDragSourceFeedbackFigure() [message #205823 is a reply to message #205792] Thu, 22 December 2005 10:43 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: cricard.businessobjects.com

Yes, I know about the resize but I can't decide what kind of feedback you
want to give if you do not wish to stretch/shrink your ghost bitmap, so I
had left it as an "exercise" for the reader ;)

I you're stuck, then simply do this, for example:

@Override
public void paint(Graphics graphics) {
if(source != null)
super.paint(graphics);
else {
Rectangle r = bounds.getCopy();

graphics.setAlpha(alpha);
graphics.setBackgroundColor(<some color>);
graphics.fillRectangle(r);
r.width--;
r.height--;
graphics.drawRectangle(r);
}
}

Well, I'm not a lawyer, but I think you can use this example "as is" if it
suits your needs, since it was not too hard to write and useful (at least I
hope).
Of course I'd be glad you mentioned my name, but I'd be even happier if you
(or someone... grateful?) helped me solve this darn zooming bug, so
everybody can display a "neat" figure under all circumstances.

"Sunil Kamath" <sunil_kamath@nohotspammail.com> wrote in message
news:docdn7$akc$1@utils.eclipse.org...
> cricri <cricard@businessobjects.com> wrote:
> > I'd like to submit a sexier alternative to the standard gray X-OR'ed
> > rectangle that appears whenever you drag and drop a part in GEF.
> > It should also slightly relieve those of you who have to create a
> > "ghost" figure for each and every kind of visual that could be moved.
> >
> > The original idea was to build an alpha-blended image once and for
> > all, then stop painting recursively our part's children figures when
> > the former is dragged around (have a peek at that in a profiler).
> > Eventually, it's only slightly faster, but well-isolated and thus more
> > easily maintained since located in one spot.
> >
> Oooh... doesn't work too well for resize feedback.
> Great for move feedback, however.
>
> --
> Sunil
>
>
Re: Generic "ghost" figure for ResizableEditPolicy.createDragSourceFeedbackFigure() [message #205847 is a reply to message #205758] Thu, 22 December 2005 16:19 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: none.us.ibm.com

To solve the zoom bug, you need to put the feedback on the non-zoomed
feedback layer. Also, you need to re-implement the zooming. So, you'll have
to create a much larger Image, and then introduce a ScaledGraphics instance
that zooms so that the painting fills the larger image.

This image approach works well for drag sources that have no transparent
areas. Another approach is to delegate back to the original figure to paint
itself, perhaps enabling the new alpha support in SWT.

The pattern the applies in the most cases is the one we added to the Logic
example. That is, create a deep-custom-copy of the figure. The feedback
version can have modified methods of painting itself, such as enabling
alpha, XOR, etc.

"cricri" <cricard@businessobjects.com> wrote in message
news:doc3sq$ufu$1@utils.eclipse.org...
> I'd like to submit a sexier alternative to the standard gray X-OR'ed
> rectangle that appears whenever you drag and drop a part in GEF.
> It should also slightly relieve those of you who have to create a "ghost"
> figure for each and every kind of visual that could be moved.
>
> The original idea was to build an alpha-blended image once and for all,
> then
> stop painting recursively our part's children figures when the former is
> dragged around (have a peek at that in a profiler).
> Eventually, it's only slightly faster, but well-isolated and thus more
> easily maintained since located in one spot.
>
> A snapshot can be found there:
> http://img277.imageshack.us/img277/4348/ghostimagefigure7ip. png
>
> Please find the associated source code below, it's pretty straightforward
> (and feel free to point out my bugs):
>
> public class GhostImageFigure extends ImageFigure {
> IFigure source = null;
> int alpha;
>
> public GhostImageFigure(IFigure source, int alpha) {
> this.source = source;
> this.alpha = alpha;
>
> setOpaque(false);
>
> if(source != null) {
> Rectangle bounds = source.getBounds().getCopy();
> Image image = new Image(Display.getCurrent(),
> bounds.width, bounds.height);
>
> GC gc = new GC(image);
> SWTGraphics swtGraphics = new SWTGraphics(gc);
>
> swtGraphics.translate(-bounds.x, -bounds.y);
>
> source.paint(swtGraphics); // Let your figure do its
> complex painting here.
>
> ImageData data = image.getImageData();
>
> data.alpha = alpha; // Note that changing the
> ImageData has no affect on Images already constructed using it...
> Image finalImage = new Image(Display.getCurrent(),
> data); //... hence the creation of a second bitmap from the modified data.
> setImage(finalImage);
>
> image.dispose();
> swtGraphics.dispose();
> gc.dispose();
> }
> }
>
> public void dispose() { // Beware, the base class ImageFigure
> doesn't dispose its image...
> if(getImage() != null)
> getImage().dispose();
> }
> }
>
> *** IMPORTANT ***
> Please note that the source figure blits crappy fonts into the ghost
> figure
> when the current zoom is not 1.0.
> Example :
> http://img277.imageshack.us/img277/6771/ghostimagefigurebug3 mb.png
> If someone could give me a hint, I'd appreciate it.... anyway, I'll
> definitely add a newsgroupListener to this topic ;)
>
> Q: When should I call GhostImageFigure's constructor?
> A: Let createDragSourceFeedbackFigure() return that kind of figure in your
> ResizableEditPolicy.
>
> Q: When should I call its dispose() method?
> A: From eraseChangeBoundsFeedback() in your ResizableEditPolicy.
>
>
Re: Generic "ghost" figure for ResizableEditPolicy.createDragSourceFeedbackFigure() [message #205863 is a reply to message #205847] Thu, 22 December 2005 17:15 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: cricard.businessobjects.com

In fact, before writing this class I used the approach you suggest: having a
complex figure that knows how to draw itself when "ghosted" (making good use
of the graphic's alpha channel), and propagates the info to all its
descendants that also know how to do that (e.g. those implementing a
specific interface).
On the one hand, it's rather bulky, slightly slower (especially when we have
half a dozen figures+ to drag around) and we lose this generic flavor that
makes the GhostImageFigure so cool to use.
BUT on the other hand, it works pretty well.

As you mentioned, I had to write the following piece of code in my
ResizeEditPolicy for the zoom factor to be properly taken into account:

@Override
protected IFigure getFeedbackLayer() {
return getLayer (LayerConstants.SCALED_FEEDBACK_LAYER);
}

But, if I understand you well, from mandatory it has become harmful now I
changed tactics.
I must admit I hadn't thought of commenting it out...

As for the ScalableGraphics, I've already tried several things (including
scaling the original image bounds, calling the graphic's "scale" method,
using copyArea and so on...) to no avail.
Blitting the image to the (on)screen graphic displays it properly scaled,
but no matter how hard I tried, I couldn't put it to work with the
ScaledGraphics in my constructor :s
I'll give it another try thanks to your advice concerning the proper
feedback layer to use, and will let you know if the results are the ones
expected.

For those of you who are interested, the best compromise I've found so far
was to use graphics.setInterpolation(SWT.HIGH) inside my paint method:

- for zooms > 1, the rendered image is somewhat less ugly (however it has a
jpeg touch)...
- ...but for zooms < 1 it is incomparably more detailed!

Thanks again for your tips and feedback.
Please feel free to post your comments and suggestions, I'll be happy to
discuss them with you ;)

"Randy Hudson" <none@us.ibm.com> wrote in message
news:doejn8$ot2$1@utils.eclipse.org...
> To solve the zoom bug, you need to put the feedback on the non-zoomed
> feedback layer. Also, you need to re-implement the zooming. So, you'll
have
> to create a much larger Image, and then introduce a ScaledGraphics
instance
> that zooms so that the painting fills the larger image.
>
> This image approach works well for drag sources that have no transparent
> areas. Another approach is to delegate back to the original figure to
paint
> itself, perhaps enabling the new alpha support in SWT.
>
> The pattern the applies in the most cases is the one we added to the Logic
> example. That is, create a deep-custom-copy of the figure. The feedback
> version can have modified methods of painting itself, such as enabling
> alpha, XOR, etc.
>
> "cricri" <cricard@businessobjects.com> wrote in message
> news:doc3sq$ufu$1@utils.eclipse.org...
> > I'd like to submit a sexier alternative to the standard gray X-OR'ed
> > rectangle that appears whenever you drag and drop a part in GEF.
> > It should also slightly relieve those of you who have to create a
"ghost"
> > figure for each and every kind of visual that could be moved.
> >
> > The original idea was to build an alpha-blended image once and for all,
> > then
> > stop painting recursively our part's children figures when the former is
> > dragged around (have a peek at that in a profiler).
> > Eventually, it's only slightly faster, but well-isolated and thus more
> > easily maintained since located in one spot.
> >
> > A snapshot can be found there:
> > http://img277.imageshack.us/img277/4348/ghostimagefigure7ip. png
> >
> > Please find the associated source code below, it's pretty
straightforward
> > (and feel free to point out my bugs):
> >
> > public class GhostImageFigure extends ImageFigure {
> > IFigure source = null;
> > int alpha;
> >
> > public GhostImageFigure(IFigure source, int alpha) {
> > this.source = source;
> > this.alpha = alpha;
> >
> > setOpaque(false);
> >
> > if(source != null) {
> > Rectangle bounds = source.getBounds().getCopy();
> > Image image = new Image(Display.getCurrent(),
> > bounds.width, bounds.height);
> >
> > GC gc = new GC(image);
> > SWTGraphics swtGraphics = new SWTGraphics(gc);
> >
> > swtGraphics.translate(-bounds.x, -bounds.y);
> >
> > source.paint(swtGraphics); // Let your figure do its
> > complex painting here.
> >
> > ImageData data = image.getImageData();
> >
> > data.alpha = alpha; // Note that changing the
> > ImageData has no affect on Images already constructed using it...
> > Image finalImage = new Image(Display.getCurrent(),
> > data); //... hence the creation of a second bitmap from the modified
data.
> > setImage(finalImage);
> >
> > image.dispose();
> > swtGraphics.dispose();
> > gc.dispose();
> > }
> > }
> >
> > public void dispose() { // Beware, the base class ImageFigure
> > doesn't dispose its image...
> > if(getImage() != null)
> > getImage().dispose();
> > }
> > }
> >
> > *** IMPORTANT ***
> > Please note that the source figure blits crappy fonts into the ghost
> > figure
> > when the current zoom is not 1.0.
> > Example :
> > http://img277.imageshack.us/img277/6771/ghostimagefigurebug3 mb.png
> > If someone could give me a hint, I'd appreciate it.... anyway, I'll
> > definitely add a newsgroupListener to this topic ;)
> >
> > Q: When should I call GhostImageFigure's constructor?
> > A: Let createDragSourceFeedbackFigure() return that kind of figure in
your
> > ResizableEditPolicy.
> >
> > Q: When should I call its dispose() method?
> > A: From eraseChangeBoundsFeedback() in your ResizableEditPolicy.
> >
> >
>
>
Re: Generic "ghost" figure for ResizableEditPolicy.createDragSourceFeedbackFigure() [message #205919 is a reply to message #205863] Fri, 23 December 2005 04:04 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: none.us.ibm.com

> In fact, before writing this class I used the approach you suggest: having
> a
> complex figure that knows how to draw itself when "ghosted" (making good
> use
> of the graphic's alpha channel), and propagates the info to all its
> descendants that also know how to do that (e.g. those implementing a
> specific interface).
> On the one hand, it's rather bulky, slightly slower (especially when we
> have
> half a dozen figures+ to drag around) and we lose this generic flavor that
> makes the GhostImageFigure so cool to use.
> BUT on the other hand, it works pretty well.

I think there are times when painting alpha with GDI+ is faster than drawing
an Image containing alpha channel. It probably depends on the specific
type/amount of painting. But there are also times where it doesn't work. For
example, if you need to "overpaint", what normally would cover up will only
cover partially due to transparency.

> As you mentioned, I had to write the following piece of code in my
> ResizeEditPolicy for the zoom factor to be properly taken into account:
>
> @Override
> protected IFigure getFeedbackLayer() {
> return getLayer (LayerConstants.SCALED_FEEDBACK_LAYER);
> }

I'm actually surprised that scaling an alpha image is faster than scaled
GDI+ alpha painting.

> But, if I understand you well, from mandatory it has become harmful now I
> changed tactics.
> I must admit I hadn't thought of commenting it out...
>
> As for the ScalableGraphics, I've already tried several things (including
> scaling the original image bounds, calling the graphic's "scale" method,
> using copyArea and so on...) to no avail.

Take the figure's bounds (or a copy actually), then translate it to
absolute, then translate it relative to the feedback figure itself. Now, you
have the zoom ratio.
Re: Generic "ghost" figure for ResizableEditPolicy.createDragSourceFeedbackFigure() [message #205988 is a reply to message #205919] Fri, 23 December 2005 16:30 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: cricard.businessobjects.com

Thanks for your help, Randy. The problem actually dealt with the scaled
feedback layer.
Now it works perfectly well (also meaning that its's rather responsive when
there are lots of tables in the model / involved in the drag and drop, since
all the computing is done at the beginning of the process. Afterwards,
there's only blitting to do, which saves up a lot of computing time,
especially in the recursive calls to paint when there are several embedded
children).

Here's the final code:

public class GhostImageFigure extends ImageFigure {
protected IFigure source = null;
protected int alpha = 200;
protected double zoomFactor = 1.0;

protected double computeZoomFactor() {
PrecisionRectangle abs = new PrecisionRectangle(source.getBounds());
PrecisionRectangle rel = new PrecisionRectangle(source.getBounds());
source.translateToAbsolute(abs);
translateToRelative(rel);

return (double)abs.width / (double)rel.width;
}

public GhostImageFigure(IFigure source, int alpha) {
this.source = source;
this.alpha = alpha;

setOpaque(false);

if(source != null) {
zoomFactor = computeZoomFactor();

PrecisionRectangle scaledBounds = new
PrecisionRectangle(source.getBounds().getCopy().scale(zoomFa ctor));
Image image = new Image(Display.getCurrent(),
scaledBounds.width, scaledBounds.height);
GC gc = new GC(image);
SWTGraphics swtGraphics = new SWTGraphics(gc);
ScaledGraphics scaledGraphics = new ScaledGraphics(swtGraphics);

scaledGraphics.translate(-scaledBounds.x, -scaledBounds.y);
scaledGraphics.scale(zoomFactor);
source.paint(scaledGraphics);

ImageData data = image.getImageData();

data.alpha = alpha;

Image finalImage = new Image(Display.getCurrent(), data);

setImage(finalImage);
setAlignment(PositionConstants.NORTH | PositionConstants.WEST);
image.dispose();
scaledGraphics.dispose();
swtGraphics.dispose();
gc.dispose();
}
}

@Override
protected void paintFigure(Graphics graphics) {
Rectangle r = bounds.getCopy();

super.paintFigure(graphics);

graphics.setAlpha(alpha/2);
graphics.setBackgroundColor(<somecolor>);
graphics.fillRectangle(r);
r.width--;
r.height--;
graphics.drawRectangle(r);
}

public void dispose() {
if(source != null)
getImage().dispose();
}
}

"Randy Hudson" <none@us.ibm.com> wrote in message
news:doft0c$7oo$1@utils.eclipse.org...
> > In fact, before writing this class I used the approach you suggest:
having
> > a
> > complex figure that knows how to draw itself when "ghosted" (making good
> > use
> > of the graphic's alpha channel), and propagates the info to all its
> > descendants that also know how to do that (e.g. those implementing a
> > specific interface).
> > On the one hand, it's rather bulky, slightly slower (especially when we
> > have
> > half a dozen figures+ to drag around) and we lose this generic flavor
that
> > makes the GhostImageFigure so cool to use.
> > BUT on the other hand, it works pretty well.
>
> I think there are times when painting alpha with GDI+ is faster than
drawing
> an Image containing alpha channel. It probably depends on the specific
> type/amount of painting. But there are also times where it doesn't work.
For
> example, if you need to "overpaint", what normally would cover up will
only
> cover partially due to transparency.
>
> > As you mentioned, I had to write the following piece of code in my
> > ResizeEditPolicy for the zoom factor to be properly taken into account:
> >
> > @Override
> > protected IFigure getFeedbackLayer() {
> > return getLayer (LayerConstants.SCALED_FEEDBACK_LAYER);
> > }
>
> I'm actually surprised that scaling an alpha image is faster than scaled
> GDI+ alpha painting.
>
> > But, if I understand you well, from mandatory it has become harmful now
I
> > changed tactics.
> > I must admit I hadn't thought of commenting it out...
> >
> > As for the ScalableGraphics, I've already tried several things
(including
> > scaling the original image bounds, calling the graphic's "scale" method,
> > using copyArea and so on...) to no avail.
>
> Take the figure's bounds (or a copy actually), then translate it to
> absolute, then translate it relative to the feedback figure itself. Now,
you
> have the zoom ratio.
>
>
>
Re: Generic "ghost" figure for ResizableEditPolicy.createDragSourceFeedbackFigure() [message #206343 is a reply to message #205988] Wed, 28 December 2005 21:12 Go to previous message
Eclipse UserFriend
Originally posted by: none.us.ibm.com

> Thanks for your help, Randy. The problem actually dealt with the scaled
> feedback layer.
> Now it works perfectly well (also meaning that its's rather responsive
> when
> there are lots of tables in the model / involved in the drag and drop,
> since
> all the computing is done at the beginning of the process. Afterwards,
> there's only blitting to do, which saves up a lot of computing time,
> especially in the recursive calls to paint when there are several embedded
> children).

It all depends on whether you are seeing hardware support for drawing alpha
images. If your video card/platform doesn't support it, then it can be a lot
slower than painting. Which platform are you on?
Previous Topic:Move Drag feedback only appearing on top of Selection box / handles.
Next Topic:How to add undo/redo of my actions to GEF CommandStack?
Goto Forum:
  


Current Time: Fri Apr 26 07:58:23 GMT 2024

Powered by FUDForum. Page generated in 0.03971 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top