I'd like to draw a proper, modern animated focus ring around a control, which according to Q&A 1785, should be a simple matter of overriding the -drawFocusRingMask and -focusRingMaskBounds methods.
Trouble is, for this project I have to use Xojo, which can declare and invoke Cocoa methods, but doesn't give me any opportunity to actually create my own view subclass.
So, is there any way to get a proper focus ring without making an actual subclass? Some other methods, perhaps introduced after this 10.7 tech note, that get the job done? Or some sneaky way to inject a method into an existing class at runtime?
As one comment suggested, class_addMethod() would be right if you want to add an optional protocol method. The public macoslib project has some code that shows how to do that, just search for that name.
However, if the function is already implemented, then you cannot add another. In that case method swizzling is the solution. It's a common method to replace a selector'd function address with another, and then call the original one.
I don't seem to have an example in Xojo for that at hand, though.
Update
For standard Cocoa controls the simplest solution is to set the NSView property focusRingType accordingly (available in macoslib). Implementing drawFocusRingMask is only necessary for custom controls.
Related
I want to know how can I create custom widgets/controls in Cocoa.
Not a full tutorial, but some guidance on what to start looking into. I'm confused by custom views, Core Animation, etc. I feel lost.
I see a lot of cool looking controls, like in Reeder App, or Sparrow etc. For example:
The left side is a collapsable menu that includes animations etc. How can I achieve something similar? I thought of using a WebView + HTML + JavaScript, but that doesn't seem like a very optimized solution.
Controls are views, so if custom views confuse you, you'll need to get that figured out before moving on to custom controls. Although you should really read the entire View Programming Guide, the section called Creating a Custom View will get you started on creating your own views. Try creating a simple view that draws a circle, for example, or the time.
When you've got views figured out, move on to custom controls. Most controls work about the same way. The user touches them, and the control responds by: a) tracking the user's input, b) changing its value, c) sending its action message to its target, and d) giving the user some feedback by redrawing itself. To get started, first make sure that you know how to use controls. Reading Control and Cell Programming Topics should help, and the section titled Subclassing NSControl covers (obviously) creating your own subclasses.
The example you provided is pretty clearly Apple's Mail.app. The view on the left side of the window might be an instance of NSOutlineView, or it might be a custom class. Either way, NSOutlineView would be a good starting point if you want to duplicate that functionality. NSOutlineView is a subclass of NSTableView, which in turn is a subclass of NSControl, which in turn is a subclass of NSView. Read Outline View Programming Topics for help getting started -- tables and outlines are extremely useful, but also more complicated to use than basic controls like buttons and text fields.
I know it's only a part of the UI, but I've recently coded something similar to the sidebar. If you look though the source-code it may give you some help on learning how to use custom controls and cells.
You can check it out on Github:
https://github.com/iluuu1994/ITSidebar
I've been learning about when to use WindowController and when to put stuff in the Document object. Looks like Document can work fine as a Controller if you have a simple interface. I have a simple interface in my application, but is it a good practice to put IB outlets into WC anyway? What would be a scenario when you would NOT want to use a WC?
Here are some scenarios:
A document object you intend to use with multiple windows (as commenter noted above) or having different views
A document object you could potentially open and process without displaying a window at all
An application with so much controller code that it's difficult to manage with a single class
During window initialization, the the document will instantiate the window controller.
After that happens, part of the point of separating the model controller and view controller is removing the document's dependency on the window.
As you refine your design, take a look at places where the document needs access to the window, and consider whether you can implement that functionality a different way, for example, by handling it in the window controller instead of the document.
I'm hoping this will be a relatively easy thing to do.
I am writing a Mac app that will be (mostly) a giant NSTextView. I would like to override the default text position cursor to a unique color/shape cursor. I don't have a lot of Quartz or general drawing experience but that's something I can look into more on my own.
What I'm primarily looking for is advice on the best way to implement this. Is it going to be a matter of overriding the drawRect function, calling the super, and then implementing my own draw code?
How would I find the appropriate location to draw that cursor? Is it contained within the drawRect's passed rect?
Essentially, you'll have to subclass the NSTextView and override some methods. The obvious one is
-(void)drawInsertionPointInRect:(NSRect)aRect color:(NSColor *)aColor turnedOn:(BOOL)flag
but that doesn't seem to entirely take care of it. Apparently, you also have to override a private method:
-(void)_drawInsertionPointInRect:(NSRect)arg1 color:(NSColor *)color
Look here for someone who's already trying to do this:
http://www.cocoadev.com/index.pl?CustomInsertionPoint
I currently have to develop a system very similar to MIT's Scratch's UI. In case you don't know it, here a screenshot: http://kidconfidence.com/blogs/wp-content/uploads/2007/10/scratch1.png
Basically you have bricks in the library on the left you can drop into the window on the right side. The problem I have is that I'm new to Cocoa and not sure what would be the best way to accomplish that.
Because you can nest these bricks sometimes and other times stick them together I wonder if there is something that would help implementing that. I recognize this is not a very common interface that there are probably no implementations of that around, but maybe there are helpers for parts of this.
Regards,
Armin
Edit: switching to desktop
There are no standard cocoa controls that you could leverage for the building blocks. You will probably want to subclass NSControl to make your standard brick object.
The list on the left could be an NSTableView. The main work area can be an NSScrollView.
You probably want to use your own brick hierarchy independent of the view hierarchy because of the freeform dragging.
I'm beginning to think that my Cocoa application is not really done according to the principles of MVC. My problem is the following:
I have some classes in my project, one of called Copier.h and another called DropReciever.h. Copier is sort of my main view controller, as it has all the bindings and main methods. DropReciever is a custom implementation of an NSView to allow the app to accept files via drag and drop.
Now, is there an easy way to send messages to Copier from DropReceiver? Right now, the two don't know each other, and I can't think of an elegant way to connect them, since since they are both kinda instantiated seperately. How can I make them see each other? Or, is there an elegant, Coca-ish way to do this better?
(If you want to look at my source code, it's here.)
Another way would be to expose a property of the drop receiver as a binding, and bind the copier to it (programmatically). Then, in the drop method, have the drop receiver set the dropped content as the value of this property (which you would name something like droppedObject).
When you set the property, the magic of Bindings will set the bound property of your copier. The copier can react appropriately there in its setter method.
I would have a delegate property on the DropReceiver. Whatever is responsible for tying these things together would set the delegate. The delegate object can be an id, or you could create a protocol for it (both idioms are common in Cocoa). I do this all over the place. You get the separation you need, without having to work around the houses too much.
The only downside, if you don't set the delegate on initialisation, is that all your calls to it need to be protected by if( delegate ) checks.
The way I usually do it is to instantiate DropReceiver in the nib and then add an IBOutlet DropReceiver * to your Copier.h, then drag a connection from the Copier instance to your DropReceiver in the window