Implementing custom NSView in Cocoa on OS X - cocoa

I am creating a Cocoa application wherein one view will contain the "hex dump" of the currently loaded document. Up until this point, I have been using a bog-standard (and very unappealing) NSTextField, but I am now looking for something more powerful.
I am a great fan of 0xED.app and would love to replicate its main "hex dump" view. How would I go about doing this?
I'm not necessarily after the eye-candy, but the ability to select a range of bytes without also selecting the offset or text columns. I am a loss as to where I would even begin to implement this effectively. Surely this is not drawn upon a blank canvas?

To get started and see how things basically work:
Subclass NSView.
Add an instance variable to hold your NSData.
Override drawRect:
Iterate your NSData
Use methods from NSString drawing AppKit additions to draw the bytes.
This approach will be slow for a large amount of data, but will give you a good handle on implementing a NSView subclass. After that, you'll want to improve the drawing performance by implementing something better than repeated calls to draw strings one at a time. You'll also want to implement overrides of methods like mouseDown: and keyDown: to handle input from the user to allow things like selecting a range of bytes.
That should get you started, once you have that going, I'd suggest asking follow up questions.

My guess is that it's probably accomplished using a NSTableView or subclass of it.
It might be a little tricky to get the correct text selection accomplished this way, but it's probably possible.

If you want to take a look at how a Cocoa interface is built you can use NibToXibConverter.
Download 0xED, right click on 0xED.app and select "Show Package Contents". Extract the Contents/Resources/English.lproj folder.
Run NibToXibConverter, browse to the folder extracted above, and put a tick next to "Decompile NIBs".
Select the "Convert" button and it will convert the NIBs to XIBs
Double click a XIB to open it in XCode and you can see how they are constructed
You will note that in the case of 0xED he is using a custom class (most likely a subclass of UIView with custom drawing as Jon Hess suggests).

Related

Is it possible for an NSView to request all drag types?

Apple's Clipboard Viewer app is tremendously helpful when implementing copy and paste. I'd like to have a similar thing for drag and drop, but I'm not sure how to start.
Normally the first step to implementing a drop target is to have your NSView call -registerForDraggedTypes. Is there any way to declare that you want to receive all possible types of drops? Or is there a lower-level API that one could use to get the pasteboard without needing to specifically register first?
I'm not 100% sure it works really in all cases but I have successfully be using something like:
[self registerForDraggedTypes: #[(NSString*)kUTTypeItem]];
Also look up th eother type items.

iOS - memory efficiency on loading image via code OR utility panel

for loading only one image, 1st step is to drag a UIImageView to the screen.
Now I can assign an IBOutlet to it and load the image in code. And it adds the setImage=nil in viewDidUnload for me.
Or I can just use the utility panel to assign that image to the UIImage and write no code. But is this as efficient as that? Better? Worse?
How about assigning images to buttons? Is it better to assign them in code or just selecting the button's image from the utility panel?
It seems to me you are comparing doing something in interface builder to programatically, correct? They are both equally the same considering you use the same sort of memory management (nil out the ivar, etc.). Basically the xib does the exact same thing as coding it out when it comes down to it, it is just a matter of preference.

Getting accented characters in a custom NSView

In Mac OSX text views, it's possible to enter accented characters with a sequence of key presses (e.g. option-e e to get e-acute). Is there a way to access this functionality in a custom NSView. In my case I have class derived from NSOpenGLView. I've implemented a responder for keyDown: so I can get the unicode characters that come from a single press, but with the sequences I just get events for the individual presses. I hoped that interpretKeyEvents: from NSResponder would help but it doesn't seem to.
I could implement it myself by copying what NSTextView does but I imagine it will be tricky, especially if people use a different keyboard setup to mine.
Calling interpretKeyEvents: is the right way to go, but you need to also implement other methods that will notify you when marked text (which I always called 'in progress text') or text to be inserted arrives in your view.
Your NSView must implement NSTextInputClient. See the Cocoa reference here. A search for some of the methods in that protocol found this chunk of code on github. which looks like a very good starting point.
For what you're asking for, it will be sufficient to test with English and at least one other Western language (French is a good one). But longer term, you'll also want to test with at least one of the Kotoeri and Hangul layouts. The code I linked to above, however, looks like it will handle the vast majority of text you can throw at it.
Hhhmm.. that sounds pretty tricky.
NSTextField does some pretty similar things as it does not have its own editing facilities but rather delegates them to the parent window's "field editor" which is an instance of an invisible NSTextView. You also get a lot of the NSTextView behavior without a window in NSText.
It might be worth checking how NSTextFields delegate to the field editor and see whether you can hook yourself into the field editor in the same way rather than doing your keyDown: events.
Another possibility could be to create an invisible NSTextView and delegate each key press to it and then display the NSTextStorage associated with it in your own view.
It sounds like you are in for a bit of pain, but that's what I would start by exploring.
Of course, I'm no Cocoa Text Subsystem wizard..
I hope this helps.

Creating a view with draggable text elements

I am trying to create a view for a kind of brainstorming application like, for example, OmniGraffle, with elements that contain textviews and can be dragged around. (Also, the should be connectable with arrows, but that is not (yet) the problem)
I did my homework and searched via google and read books about cocoa, but there seems to be no similar example around.
Since I am also new to cocoa, I’m a bit helpless here.
The thing I am sure of is, that I need a custom view in which I can create my elements - what I tried until now to do that is:
First, I searched for the syntax to add subwindows to a window to create my elements. Subwindows, I imagined, would automatically be movable and come to front and so on.
The problem: As the experienced Cocoa-programmers of you probably are not surprised, I was stunned to find nothing about anything like that - this seems to be something, that is just not intended in Cocoa?!
Then I thought about creating subviews that contain a custom view for the title bar drawing (where the user can click to drag the element) and a NSTextView.
Problems:
I read, that it is not so clever to create dozens of subviews in a window because that would be very slow (or would that be not so bad in this case because all the subviews would be instances of always the same class?).
Also I can’t find out how to load a subview from a nib- or xib-file. Would I need a viewController? Or would that make the dozens-of-instances-problem even worse?
And Apple tells you not to overlap subviews (okay, that would be not so important, but I really wonder how the guys at OmniGroup made OmniGraffle...)
Because of that, I now wanted to do the title-bar-drawing in the surrounding custom view and create the textview programmatically (as I understand, a text-“view“ ist not really a view and takes its functionality from NSCell to reduce all the effort with the views?).
Problems:
Even that failed because I was not able to create a textview that doesn’t fill the complete window (the initWithFrame: of the [[NSScrollView alloc] initWithFrame: aRect] just seems to be ignored or do I get that wrong?).
Also, there should be some buttons on each element in the final application. I imagine that would be easier to accomplish with a subview from a nib-file for each element?
Well, now that nothing works and the more I read, the more problems seem to occur, I am pretty confused and frustrated.
How could I realize such a program? Could someone please push me in the right direction?
I created a class for the draggable elements where I save position, size and text in instance variables. In my view, every new element instance is added to an array (for now, this works without a controller). The array is used to draw all the elements in a loop in drawRect:. For the text of the element I just use a NSTextFieldCell which is set to the saved text from every element in the same loop.
That way it is also possible to overlap the elements.

How to imitate the workflow view of Automator?

I’m starting to develop my first full-blown Cocoa application containing a view which I would like to behave (and look) similar to Automator’s AMWorkflowView.
The basic features I’d like to achieve:
Positioning of subviews
Display of subviews in expanded / collapsed states
Multiple selection
Drag and drop
In order to get accustomed to Cocoa, I started with a custom NSView which mainly served as a container for the custom subviews and handled their positioning and multiple selection.
The subviews are also subclasses of NSView, and contain a variable amount of views themselves, like buttons, labels and popup menus, and therefore can have different heights.
This worked quite well, but before going on, I want to make sure to have everything neat and tidy according to the MVC pattern.
I suspect that there already is a class in Cocoa that facilitates the implementation of a view container, like maybe NSCollectionView.
It seems that there is no (easy) way to display differently sized views in an NSCollectionView, though. Should I continue implementing my custom NSView (probably using an NSArrayController for selection and sorting support), or are there better ways to go?
Any help is much appreciated
Unfortunately the answer is you'll have to roll your own. NSCollectionView does not allow for variable-sized items (which also rules out expanded/collapsed states).
For a limited number of items, you can accomplish this rather easily (you just need a container view that arranges the subviews properly when asked to layout, then you need to make sure you re-layout when things change). For many subviews, however, you'll need to take care to be as efficient as possible. This can start with laying out as little as possible (only those "after" the resized view, for example) and get as complex as caching a visual representation of a prototype view, drawing the cached images (fast!) for all but the view being edited, and only using/positioning a "real" view for the view being edited.
Drag and drop works the same as it always has, but none of the above accounts for the pretty animation NSCollectionView gives you. :-) It's fast and beautifully-animated precisely because all the subviews are uniform (so the layout calculations are fast and simple). Once you add irregular sizes, the problem becomes significantly more complicated.
The bottom line: If you need variably-sized views, NSCollectionView will not work and you'll need to roll your own or find someone else's shared code, but performance and beautiful animation will not be easy.

Resources