"Scalable" output panes / extending metafiles
Unable to parse email body. Email id is 7338
Unable to parse email body. Email id is 7338
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
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.
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
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.
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... :)
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?