Hi Everyone,
I’ve been working on a custom canvas subclass (hopefully included soon in the piDog Bundle for Xojo) and would like some opinions/feedback.
Basically what I have, is a canvas with:
Backdrop image (below all layers)
Scrolling Image (below scrolling layer)
Scolling layer (dynamic with mouse events adjusted for scroll/zoom)
Drag Layer (synced to the scolling layer to avoid redrawing the scrolling layer during drags)
Overlay layer (dynamic with events relative to the control-nonscrolled)
Overlay image (lies on top of the Overlay layer)
The control has built-in scrollbars and handles mouse event scaling and offsets automatically. Also has a scrollpast “bump” available. It is pretty well optimized for Cocoa/Linux but seems a bit laggy on win32 and Carbon.
Since Carbon doesn’t support alpha and gdi+ is so slow, the scrolling layer is opaque on those platforms.
My test machine for windows is almost 10 years old, so I’m hoping someone can give me an idea if this is useable on modern windows OS’s and cpu’s.
The example is using a draggable object class I wrote with subclasses for plain boxes,text boxes, and images.
Oh and I threw in a little something for Halloween!
Download the demo apps if you’d like to check it out.
I think this could make a great foundation for some cool custom controls (listboxes/image editor/layout/etc)
OK, I had a look on a native Windows 7 machine (HP probook 4740s) equipped with 4 GB Ram. App works fine, responds good, the only sluggish thing is dragging objects. The dragged object can’t follow the mouse cursor fast enough.
It works very nicely on my 1.8 GHz MacBook Air with 4 GB RAM. (I tested the Cocoa build on Mac OS X 10.9)
Moving objects not at all sluggish. The only slight problem I see is noticeable jerkiness with a high friction setting, especially as the scroll comes to a stop.
I found a bottleneck under windows and carbon that was slowing things down a bit. Still not happy with rendering speed under win32 and carbon. Seems scaling is the main problem. I’m going to see if I can get this working as an OpenGLSurface. That should make a huge difference. A little tricky though…
Cocoa works very nice on my MB running 10.7.5, and carbon is a bit laggy on dragging. One thing I noticed is in Cocoa if you are dragging an object and your mouse leaves the canvas/window, then you re-enter the canvas/window, the app forgets what object you were dragging, even if the mouse is not released. I’m not sure if this is intended or not since it doesn’t do it in carbon, just thought you should know. Also, the textbox that displays what is happening (mouse move, drag, scroll, etc) drags just fine on carbon while the other text box doesn’t. Overall however, it works great. I would like to second Christoph’s request.
Edit: Now that I play with it a little more, I see that the backdrop doesn’t seem to work on carbon.
I’ve uploaded a new build that should improve rendering on carbon and win32. Seems some of my previous optimizations interfere with subsequent optimizations! The dragexit behavior in cocoa was something I had done to avoid objects being lost when dragged out of the canvas, but seems unneeded now.
I’m planning to add it to the piDog Bundle, so the source wouldn’t be getting released, although the draggable objects are an abstract class that handles mouse interaction with subclasses to handle different drawing behaviors, and those will be part of the demo project and available freely. They could still be just as useful with a regular canvas, and a decent example of handling object based drawing in Xojo.
[quote=44036:@Peter Fargo]Much better on Windows 7 (Parallels VM).
I am still getting the color picker twice when setting the scroller color.[/quote]
I think the first one is the Scroller color and the second one is the scroller border color
I am impressed on the responsiveness to your objects when you have 3000 on the canvas. Are you using a picture snapshot of all objects except the one that is selected?
There is an internal buffer that all the images draw into, and they can call refreshrect on that image when they need to redraw (mouseover). The dragging happens in a separate buffer so that the images behind the drag don’t need to redraw every frame. The overlay is also in it’s own buffer. Using it in an app will be like writing backing code for a canvas that’s as big as you want (a virtual canvas?), while being able to size the actual control as you like.
I’m also buffering refreshrect calls to avoid duplicate redraws. So if the overlay layer refreshes an area that intersects an area that the scrolling layer needs redrawn, I combine the two rects and just do one redraw.
I don’t know if you know this, but if you want to stack up refreshRect calls, just use invalidate as it does the same thing. There isn’t an invalidateRect, but if you pass a rect to the invalidate function it works just the same.
Hi Jim,
I’m interested and congratulations on quite a complex project! I don’t want to be a stick in the mud, but there are several things I would like to point out, especially as I want to use something like in a forthcoming project.
#1 I would want to buy the source code so that I can modify it to suit my needs if I have to. #2 It would be great if you can get it automatically handle on the Mac gesture “Pinch to Zoom”. #3 On a Retina display the text is drawn in low resolution and zooming in, seems to enlarge the low resolution text. I personally would want the text displayed in High resolution and re-rendered if needed while zooming. #4 I like your custom scrollbars, but they should really adhear to the OS setting if they should display or not. My wife for one doesn’t like them disappearing on her, she likes them constantly on display. I can help you out with the code for reading this value.
Last but not least, have you thought about using an actual NSScrollView on Cocoa?
Other than that performance is superb and very slick, you’ve done some great work here, that makes me a little envious
The reasoning is that the control has several methods: Refresh, RefreshRect, RefreshRectScrollingLayer, RefreshRectDragLayer and RefreshRectOverlayLayer. The coordinates for scrolling and drag layers are translated for scroll and zoom. Each call then redraws the invalid area via PaintScrollingLayer, PaintDragLayer, PaintOverlayLayer events, then the areas get added together and redrawn to screen in a single frame. This way the programmer can treat each layer as an independent object without regard to whether other layers need to be invalidated.
[quote=44744:@Sam Rowlands]#2 It would be great if you can get it automatically handle on the Mac gesture “Pinch to Zoom”.
[/quote]
Pinch to zoom seems like it should be possible, but everything I’ve tried seems to work and then fails… I looked at an example that adds an NSView to the window, but it doesn’t work for me. I tried subclassing the canvas via objective c runtime calls and it succeeds, but the events never make it through. I just get a bonk bonk bonk. I’m wondering if Xojo has trapped the events in anticipation of adding gestures to a coming release. With iOS coming, I would be surprised if that weren’t the case.
[quote=44744:@Sam Rowlands]#3 On a Retina display the text is drawn in low resolution and zooming in, seems to enlarge the low resolution text. I personally would want the text displayed in High resolution and re-rendered if needed while zooming.
[/quote]
That would be great for a vector based system, but not realistic for this project. There could be another similar project in the works, or I could extend this one to include resolution adjusted rendering also, but that would be further down the line.
I’ll be adding this by looking at defaults -global for the value, but I’m hoping to find a way to get the current correct behavior based on input device also. Not sure if this is possible, or reserved for built-in controls.
[quote=44744:@Sam Rowlands]#1 I would want to buy the source code so that I can modify it to suit my needs if I have to.
[/quote]
I generally don’t do source code licenses, as the code can change in ways that might completely break your implementation down the road, leaving you with a product that can’t get new features, or you needing to rewrite larger and larger portions of the code with each subsequent release.
Thanks! Have you looked at TheBigUndo? Now that’s a complex project!
I seriously appreciate the feedback. I should have a beta version ready soon, so everyone can try it out and see how it could be used in a project. I think there’s a lot of potential.
I have a class that does this but it’s complicated with also receiving touch events. If you want I can try trimming it down to just the gestures: pinch/magnify and rotate.
The hybrid mode does raster below 100% zoom and vector above 100%
Keep in mind that expanding the scrolling area requires a buffer picture in raster mode, so a large area will be slow zooming.