Help: Mojo Canvas, Glyph Navigator Idea
I am trying to make a zoomed in preview that has similar functionality to Illustrators Navigator panel, it's purpose is so that I can have a permanent crop of an enlarged area of a glyph whilst I am editing it.
I should be able to control the level of zoom, and it should be draggable (you might call this panning) so I can inspect other areas of the glyph at the same magnification.
Are there native ways of the canvas to achieve this? Perhaps there's something like
When it comes to moving around the canvas I assumed it would scroll if the canvas is bigger than the window, but this does not seem to be the case even with the relevant keyword args set to true, at least in my test.
I also tried
acceptsMouseMoved=True(as it sounds useful) but this is an unexpected keyword.
I also tried to do something with the
mouseDragged()method but I am not sure how to use it correctly. I would appreciate some guidance on this. I am receiving the
NSEventcontaining dragging data, but I don't know how to do something useful with it.
I have attached my first test of implementing this idea.
If I have done something wrong, please let me know.
I haven't changed much from the canvas API example it is based on. (http://doc.robofont.com/api/mojo/mojo-canvas/)
My apologies, I cannot attach the .py file.
- you can transform the canvas with a drawBot style api see http://doc.robofont.com/api/mojo/mojo-drawingtools/
scale(value)will do it
acceptsMouseMovedis very intensive as the canvas would send notifications whenever the mouse has moved, instead of the sequence
mouseUpbut you will need
you will need to check for the notifications:
currentGlyphChangedto be able to make such a panning panel
each glyph window has a glyph view, and a handy method is
_getMousePosition(nsEventObj)now private, but I can open that in next versions... this is converting the
NSEventmouse positions to glyph space coordinates.
I guess from here you should be able to make the puzzle :)
acceptsMouseMovedthat seems to be a typo in the docs
your controller class needs:
def acceptsMouseMoved(self): return True
Hi Frederik, thank you for your response.
I have been trying your suggestions and have had success with the use of scale, but am still struggling to make sense of
mouseUprelative to the canvas.
From what I have tried, using those observers in the usual way works for the mouse position relative to the current glyph window, but not relative to my canvas window.
I can get the 'raw'
mouseDownrelative to my canvas, but I have no idea how to turn that into useful tuples etc.
I updated the Gist with comments and questions that explain what I mean, please take a look
I didn't understand what
_getMousePosition(nsEventObj)is or how to use it. Could you explain further?
I hope to learn a lot from this, thanks for your guidance.
PS: sorry I can't find the formatting instructions to make this post look as pretty as yours!
here are some hints and tricks to get it working :)
I hope this sets you in the right direction
from mojo.canvas import Canvas from mojo.drawingTools import * import mojo.drawingTools as mojoDrawingTools from vanilla import * from mojo.events import addObserver,removeObserver from defconAppKit.windows.baseWindow import BaseWindowController import AppKit class ExampleWindow(BaseWindowController): def __init__(self): self.size = 50 self.offset = 0, 0 self.w = Window((400, 400), minSize=(200, 200)) self.w.slider = Slider((10, 5, -10, 22), value=self.size, callback=self.sliderCallback) self.w.canvas = Canvas((0, 30, -0, 400), canvasSize=(1000, 1000),delegate=self, hasHorizontalScroller=True, hasVerticalScroller=True)#,acceptsMouseMoved=True) # acceptsMouseMoved=True sounds useful, but it is an unexpected keyword? # ----->>>> 'acceptsMouseMoved' is a method, return True to receive mouseMoved callback in the delegate (see below) self.setUpBaseWindowBehavior() self.w.open() print help(mojoDrawingTools) # module docs link broken http://docs.python.org/library/mojo.drawingTools # ----->>>>> euh funny :) print help(Canvas) ## HELP ## if I use these observers, I can only get information about the mouse when clicking in a glyph window, ## I Want the information when I click in the canvas I created ## If I don't use these observers and use the methods directly, I do get the event when clicking on the canvas, but it is NSEvent, the information for instance location is relative to this window, which is what I want. ## how can I get this inforation as python dict or tuples or lists? addObserver(self, "_mouseMoved", "mouseMoved") addObserver(self, "_mouseDown", "mouseDown") # ----->>>>> # this object acts a delegate for the canvas object # every event can be redirected to this object from the canvas object # this will provide you info about events within the canvas object # obserers just observer a specific action and send a notification to a given method # <<<<<<----- def windowCloseCallback(self, sender): #when this window w is closed, remove the observer removeObserver(self, "mouseMoved") removeObserver(self, "mouseDown") # super I do not know what it's for, but it is in the example # ------>>>>> you need this as the BaseWindowController also does stuff while closing the window super(ExampleWindow, self).windowCloseCallback(sender) def sliderCallback(self, sender): self.size = sender.get() self.w.canvas.update() def draw(self): # offset the canvas x, y = self.offset translate(x, y) #set scale of canvas scale(self.size*0.1) #print CurrentGlyph() if CurrentGlyph(): #draw current glyph to canvas (will need to observe when current glyph changes, but this is just to test) drawGlyph(CurrentGlyph()) def acceptsMouseMoved(self): return False # mouse down that is not from observer, gives NSEvent for click relative to window def mouseDown(self, event): # ----->>>> see https://developer.apple.com/documentation/appkit/nsevent?language=objc print type(event) view = self.w.canvas.getNSView() print view.convertPoint_fromView_(event.locationInWindow(), None) # mouse down from observer give info as dict def _mouseDown(self, notification): print notification["event"] print notification["glyph"] print notification["point"] # mouse moved that is not from observer, gives NSEvent for mouse relative to window def mouseMoved(self, event): print event.locationInWindow() # mouse moved from observer give info as dict def _mouseMoved(self, notification): print notification def mouseDragged(self, event): # how to grab and drag the canvas? from sender I get information in an NSEvent, how can I access that information and do something useful with it? print 'drag?', event x, y = self.offset self.offset = x + event.deltaX(), y - event.deltaY() self.w.canvas.update() ExampleWindow()
Thank you so much for the example, not only for the fact you got the basic functionality there, but also for the comments and tips. I will study it hard :)
I can certainly take it from here,
It's mostly a learning exercise, but if it turns out to be useful I'll see about making it robust enough for sharing.
Side note about docs: I think that if you print help it should not print a joke (or broken) link otherwise it leads you to believe you're missing important information that is no longer accessible, perhaps it can be updated?
It's a similar story for the "starting with mojo" link on the homepage, I can't count the amount of times I clicked on that thinking that's where I will find answers and there's nothing there. Both examples undermine the authority of the docs that do exist, leaving you wondering if they are incomplete.