Lisp HUG Maillist Archive

"Scalable" output panes / extending metafiles

Unable to parse email body. Email id is 7338

Re: "Scalable" output panes / extending metafiles

Disclaimer: I don't do CAPI programming, but I found your question
quite fascinating and read your code and most of the CAPI User Guide
section on Graphics Ports.  So hopefully my comments/questions will
make sense, but possibly not.

On Fri, Dec 21, 2007 at 12:53:19AM +0100, Edi Weitz wrote:
> I'm trying to create an interface with an output pane that can
> scale: The application will draw geometric shapes to the output
> pane, and when the user resizes the pane, the shapes are supposed to
> resize accordingly.
> 
> My first idea was to record all of the drawing operations within the
> interface and to replay them after resizing with corresponding
> transformations.  A quick sketch of this approach is attached as
> scale.lisp.  Click into the pane several times to draw a couple of
> lines, resize, draw some more lines, resize, and so on.  (The real
> application will draw the shapes programmatically - the clicking
> part is just for demonstation purposes.)
> 
> This is doable, but obviously pretty inconvenient.  More or less by
> chance, I then came across metafiles, and it turns out that with
> metafiles the scaling part already comes for free.  A demo of the
> same "scalable interface" with metafiles is in the second
> attachment.  However, you will notice that the interface only
> "remembers" the last line which was drawn.  This is due to the fact
> that the line I commented out doesn't work.
> 
> What I obviously need for the metafile approach to be successful is
> a way to "apply" ("draw") one metafile to another metafile, but I
> didn't find out how I could achieve this.  (Yes, as an alternative,
> I could probably store a growing list of metafiles in the interface
> and apply/draw them in turn when the interface is resized.  But that
> seems terribly wrong.)
> 
> Questions:
> 
> 1. Is there a way to draw one metafile to another one that I just
>    didn't find yet?  Or, alternatively, is there a way to somehow
>    "extend" an in-memory metafile once you've left the dynamic
>    extent of the CAPI:WITH-INTERNAL-METAFILE macro?
> 
>    If this can't be done in LispWorks, but if it /can/ be done in C,
>    would it make sense to add this to LispWorks as a new feature?

I macroexpanded with-internal-metafile, and it basically opens an
internal metafile, does the drawing, closes the metafile, and returns
it.  I bet the Lispworks folks could figure out how to re-open the
metafile and append to it.

> 2. Am I missing a better way to do "scalable interfaces"?

Baring the above, I think so.

> 3. In scale.lisp, I compute the transformations myself.  I'm aware
>    of graphics states and transformations in GP, but I think it
>    wouldn't buy me anything here.  Or am I wrong again?

Graphics Ports have transforms designed to do scaling.  I think you
could

- Draw to a special variable *off-screen-port* instead of a
  lexically-defined off-screen-port.
- Store a closure that does the drawing instead of the coordinates of
  the drawing operation.  That means you can do any drawing operations
  whatsoever without storing all the coordinates of each individual
  drawing operation.  (I think.  :)
- On resize, bind *off-screen-port* to a different port, set up the
  appropriate scaling on the port, and call all the closures you've
  stored.  (Or, if necessary, set the scaling individually for each
  operation.  Not sure exactly how that'd work out.  Might require you
  to pre-scale all the "original" drawing operations to some large
  coordinate system, and then re-scale them down to the actual port
  size, for each operation.  Or something like that.  Did I mention I
  don't do CAPI programming?  :)

Admittedly, you're basically reinventing the internal metafile, but
this approach at least seems a little easier than yours.  (And it'd
work under Unix, too.)

Anyway, hope this helps, or at least makes sense.  :)

-- Larry Clapp


Re: "Scalable" output panes / extending metafiles

Hi

I have not looked at your code yet, but I did fiddle with these  
things a long time ago when working on cl-plot (a CAPI plotting library)
I think I posted the code here at some point.

If you want to see some screenshots you can look here http:// 
bioinformatics.nyu.edu/Projects/GOALIE/#Screenshots
The plots (the panes which contain plots) in the interface are fully  
scalable.

Cheers

marco





On Dec 21, 2007, at 24:53 , Edi Weitz wrote:

> I'm trying to create an interface with an output pane that can scale:
> The application will draw geometric shapes to the output pane, and
> when the user resizes the pane, the shapes are supposed to resize
> accordingly.
>
> My first idea was to record all of the drawing operations within the
> interface and to replay them after resizing with corresponding
> transformations.  A quick sketch of this approach is attached as
> scale.lisp.  Click into the pane several times to draw a couple of
> lines, resize, draw some more lines, resize, and so on.  (The real
> application will draw the shapes programmatically - the clicking part
> is just for demonstation purposes.)
>
> This is doable, but obviously pretty inconvenient.  More or less by
> chance, I then came across metafiles, and it turns out that with
> metafiles the scaling part already comes for free.  A demo of the same
> "scalable interface" with metafiles is in the second attachment.
> However, you will notice that the interface only "remembers" the last
> line which was drawn.  This is due to the fact that the line I
> commented out doesn't work.
>
> What I obviously need for the metafile approach to be successful is a
> way to "apply" ("draw") one metafile to another metafile, but I didn't
> find out how I could achieve this.  (Yes, as an alternative, I could
> probably store a growing list of metafiles in the interface and
> apply/draw them in turn when the interface is resized.  But that seems
> terribly wrong.)
>
> Questions:
>
> 1. Is there a way to draw one metafile to another one that I just
>    didn't find yet?  Or, alternatively, is there a way to somehow
>    "extend" an in-memory metafile once you've left the dynamic extent
>    of the CAPI:WITH-INTERNAL-METAFILE macro?
>
>    If this can't be done in LispWorks, but if it /can/ be done in C,
>    would it make sense to add this to LispWorks as a new feature?
>
> 2. Am I missing a better way to do "scalable interfaces"?
>
> 3. In scale.lisp, I compute the transformations myself.  I'm aware of
>    graphics states and transformations in GP, but I think it wouldn't
>    buy me anything here.  Or am I wrong again?
>
> Remark:
>
> Someone will probably ask why, if the shapes in my pane are generated
> programmatically, I don't try to create all of them within one
> metafile.  This is an option, but it would entail a significant
> rewrite of the existing code, so I'd rather not do it.
>
> Thanks in advance for your help,
> Edi.
>
> <scale.lisp><metafile.lisp>

--
Marco Antoniotti, Associate Professor
DISCo, Università Milano Bicocca U14 2043
Viale Sarca 336
I-20126 Milan (MI) ITALY

Please note that I am not checking my Spam-box anymore.





Re: "Scalable" output panes / extending metafiles

On Thursday 20 December 2007 6:53:19 pm Edi Weitz wrote:
> I'm trying to create an interface with an output pane that can scale:
> The application will draw geometric shapes to the output pane, and
> when the user resizes the pane, the shapes are supposed to resize
> accordingly.

Why are you drawing to an off-screen port (or metafile)?

I would have expected the gp:draw-xxx code to be in the display-callback, 
wrapped within a gp:with-graphics-scale.  I would have expected the resize 
callback to calculate the zoom factor, stuff it into an instance variable and 
to call gp:invalidate-rectangle (which then causes the display-callback to be 
fired).

eg.

(defun display-callback (...)
  (let ((intf (capi:element-interface pane)))
    (gp:with-graphics-scale (pane (zoom intf) (zoom intf))
        (gp:draw-line ....)
        (gp:draw-line ....) ...)))

(defun resize-callback (...)
  (setf (zoom intf) (your-calculation-here))
  (gp:invalidate-rectangle pane))


(Use x,y,w,h in display-callback and invalidate-rectangle if you need to 
optimize by not drawing to regions outside of the visible window (clipped)).

The only reason I see for using an off-screen port is to perform 
double-buffering (to get rid of tearing effects during lengthy graphic 
manipulations).  In which case, have you looked at capi:with-atomic-redisplay 
(example balloons.lisp)?


Another option:

I am working on something like this at this very moment (so feel free to 
discuss with me - we'll both learn something :-).  

The background of my window is generated (in a C dll) using a very expensive 
operation, sometimes needing a few seconds to generate it.  I've optimized 
the "damage" events (cover, uncover portions of the window - stuff that 
should not require a complete recalculation of the background) by taking a 
snapshot of the window once the C program is done scribbling on the window.  
I use gp:make-image-from-port to grab the result as an image and stick it 
into an instance variable (cache).  Then, in the display callback, I use 
gp:draw-image to slap the cached background into the window, inside a call to 
gp:with-graphics-scale.  This works (on Windows at least).

pt


Re: "Scalable" output panes / extending metafiles

Hi Paul,

On Sat, 22 Dec 2007 15:03:27 -0500, Paul Tarvydas <tarvydas@visualframeworksinc.com> wrote:

> I would have expected the gp:draw-xxx code to be in the
> display-callback, wrapped within a gp:with-graphics-scale.  I would
> have expected the resize callback to calculate the zoom factor,
> stuff it into an instance variable and to call
> gp:invalidate-rectangle (which then causes the display-callback to
> be fired).

That will work with a static image that is known in advance, but not
in my case.  It was probably not totally clear from my initial
question, but what I'm looking for is the best way to handle a
situation where something is drawn to the pane, it is then resized,
some more stuff is drawn, it is resized again, and so on.

> I am working on something like this at this very moment (so feel
> free to discuss with me - we'll both learn something :-).

Sounds like a good plan... :)

> I use gp:make-image-from-port to grab the result as an image and
> stick it into an instance variable (cache).  Then, in the display
> callback, I use gp:draw-image to slap the cached background into the
> window, inside a call to gp:with-graphics-scale.

Ah, thanks, that gave me something new to think about.  I wasn't aware
that you could scale images that you grabbed that way.  For some
reason, I thought the images acquired with MAKE-IMAGE-FROM-PORT were
pixel-by-pixel copies of the port.

Thanks,
Edi.


Re: "Scalable" output panes / extending metafiles

On Fri, 21 Dec 2007 10:25:34 -0500, Larry Clapp <larry@theclapp.org> wrote:

> I macroexpanded with-internal-metafile, and it basically opens an
> internal metafile, does the drawing, closes the metafile, and
> returns it.  I bet the Lispworks folks could figure out how to
> re-open the metafile and append to it.

Even if it won't help in my case, it seems to me like it would be a
good thing to have.

>> 2. Am I missing a better way to do "scalable interfaces"?
>
> Baring the above, I think so.

You mean the part I commented out in my code or something else?

> - Draw to a special variable *off-screen-port* instead of a
> lexically-defined off-screen-port.
> - Store a closure that does the drawing instead of the coordinates
> of the drawing operation.  That means you can do any drawing
> operations whatsoever without storing all the coordinates of each
> individual drawing operation.  (I think.  :)
> - On resize, bind *off-screen-port* to a different port, set up the
> appropriate scaling on the port, and call all the closures you've
> stored.  (Or, if necessary, set the scaling individually for each
> operation.  Not sure exactly how that'd work out.  Might require you
> to pre-scale all the "original" drawing operations to some large
> coordinate system, and then re-scale them down to the actual port
> size, for each operation.  Or something like that.  Did I mention I
> don't do CAPI programming?  :)

Yes, something like this will certainly also work, but it again boils
down to "keep track of the drawing history yourself."  That's the part
I was trying to avoid... :)


Re: "Scalable" output panes / extending metafiles

On Fri, 21 Dec 2007 16:55:52 +0100, Marco Antoniotti <marcoxa@cs.nyu.edu> wrote:

> I have not looked at your code yet, but I did fiddle with these
> things a long time ago when working on cl-plot (a CAPI plotting
> library) I think I posted the code here at some point.

I found a reference to

  http://bioinformatics.nyu.edu/~marcoxa/common-lisp/code/cl-plot/

on Gmane, but that URL doesn't seem to exist anymore.

> If you want to see some screenshots you can look here http://
> bioinformatics.nyu.edu/Projects/GOALIE/#Screenshots

  Not Found
  The requested URL /Projects/GOALIE/ was not found on this server.

> The plots (the panes which contain plots) in the interface are fully
> scalable.

But they are also static in the sense that after resizing they don't
change anymore, right?


Updated at: 2020-12-10 08:44 UTC