Popup window similar to Xcode's code completion? - objective-c

I would like to build something similar to the code-completion feature in Xcode 4. (The visual style and behavior, not the data structure type work required for code completion).
As the user is typing, a pop-up window presents other word choices that can be selected.
The Feature in action:
I'm not exactly sure where to start. I am mainly concerned with the visual appearance of the window and how I should populate the list with a given set of words. Later I will get into making the window follow the cursor around the screen and etc.
I am mainly looking for an overview of how to display such data in a "window", and how to cusomize the appearance of the thing so it looks like a nice little informational popup rather than a full-on OS X window.

Just add a subview to your current view that happens to be a tableview. Programmatically cause it to be visible on an event (such as mouseDown), and adjust it's position based on where you want it. You will need to instantiate the proper delegate/datasource methods, but it should be pretty straight forward. You will also need a source for the words you want to use in your autocomplete, and put them in an array or something for your tableview datasource to go through.
Like I said, it's not terribly hard, provided you are comfortable using tableviews and adding views to your existing view. If this doesn't explain enough, leave a comment and I can flesh this comment out more.

Add a (completions) subview to your view and set its visible property to NO. Create a separate AutoComplete object that includes the subview as a property and fills it with potential completions. Your controller can respond to key pressed (key typed) events and give the last word (substring the text from the end to the 1st preceding blank) to the AutoComplete on each event. The basic logic in AutoComplete could be something like:
Given an AutoComplete with a list of known words "dog, spaghetti, minute, horse, spare, speed"
When asked to complete a fragment "sp"
Then the following words should be offered as potential completions, "spaghetti, spare, speed"
Which would imply that you need to instantiate it with a list of words (this could be done in the init of your controller), and create a method "-(NSArray*) completeFragment:(NSString*)fragment;". You could drop this into an OCUnit test case and iterate over your implementation of autocomplete until you get it right. You would then write a method that takes the completions from AutoComplete and lists them in the subview. Even better you might create currentWord and potentialCompletions properties in AutoComplete that gets updated as you send it "newFragment:(NSString*)fragment;" messages. Throw that into OCUnit and work it out then use that potentialCompletions property to drive updated of a the subview (which is probably best modeled as a custom tableView).

Related

NSSegmentedCell Subclass and Custom Geometry/Layout Impossible?

A Tale of Two Subclasses
By Ben Stock
Prologue
I'm in the process of making a really nice looking set of controls which automatically change their appearance depending on the type of window they're used in (e.g. If you drop a button in a normal window, it looks like any other standard Aqua button. If you drop it on an NSPanel with a window mask of NSHUDWindowMask, however, it'll automatically switch its style to look good on a HUD background. So far, I've subclassed NSButton, NSTextField, NSSlider, and NSSearchField. Last night I started on NSTabView, only to be slammed down by its lack of customizability. It's a real pain in the ass, but I'm a developer, so I'm used to finding my own way. The first thing I think to do is add an instance of NSSegmentedControl in place of the private tabs used by NSTabView. So far, so good. I've got the buttons selectable, they automatically update when new NSTabViewItem's are added, and they work just like the real thing.
And the Pain Begins …
Finally, I start to style my segments, and … WTF have I gotten myself into‽ I should've just gone into acting or something. Objective-C development is slowly taking years off my life. No matter what I do, the "tracking areas" used by NSSegmentedCell don't seem to be updating when my segment widths change. So when my widths change, my artwork does, too. However, the actual tracking area doesn't update (even when I override -updateTrackingAreas. It's really hard to explain, so I decided to draw my segment rectangles behind and in front of the ones drawn by super in -drawSegment:inFrame:withView. Here's a screenshot with my art drawn on top of the underlying tracking areas:
And here's super's implementation above my segment rects:
I've tried overriding everything I can think of. Here are a few of the methods I've overridden (and un-overridden):
-cellSize (NSSegmentedCell)
-cellSizeForBounds: (NSSegmentedCell)
-sizeToFit (NSSegmentedControl)
-intrinsicContentSize (NSSegmentedControl)
-setWidth:forSegment: (NSSegmentedControl/Cell)
-startTrackingAt:inView: (NSSegmentedCell)
-continueTracking:at:inView: (NSSegmentedCell)
-stopTracking:at:inView:mouseIsUp: (NSSegmentedCell)
At this point, some of those methods in the above list are still using my overrides and some aren't. I've mixed and matched, deleted, simplified, rewrote, and refactored, and no matter what I do, the underlying rectangles don't change. I love Apple as much as the next guy, but their view of customization needs to change. I can't stand not being able to understand what's going on in the implementation of all these stupid controls. Not to mention the fact that I still can't fully wrap my head around Auto Layout (which is about the most un-"auto" thing I've ever dealt with), but that's a post for another day. Anyway, if anybody could help a brotha out, I'd be super grateful. Sorry for ranting and thanks for reading!
P.S. None of these things are finished, so please don't be too hard on a few pixel imperfections. ;-)

Catch key events in a NSWindow

I'm trying to get a very basic web browser with 3 Webviews (2 hidden and 1 visible at all times).
I'd like to switch between these 3 webviews by pressing CMD+1, CMD+2, CMD+3.
I have created a basic Cocoa app, added 3 webviews in it, referenced the Webkit framework and I'm up and running with it, this part is working.
Now I wonder:
1) How to catch key event? It seems so overly complicated that browsing the event structure docs gave me a headache.
[rant]From someone who did lots of Windows forms, GTK, QT and Java/C#/C++ work it seems that XCode is getting worse every release by moving everything around and creating 3 different ways of achieving the same thing, etc. Each time I have to use it's always like I have to learn everything once again.[/rant]
2) How to specifically catch CMD+NUMBERS ?
This is just for a quick productivity app I'm building to use in conjunction with JIRA (project management).
I'd appreciate if somebody could point me in the good direction.
Every time I stumble upon a good tutorial, it was outdated or was for iOS dev which most of the time doesn't use the same APIs as OS X anymore.
Sorry about the rant and thanks about your help!
What you are looking to override is the NSResponder method "keyDown:", and what I would recommend doing is subclassing "WebView" and create your own "keyDown" method (make certain to call "[super keyDown: theEvent]" somewhere in your implementation, though).
Now, within your "keyDown" implementation, to look for the command key, "NSEvent" objects respond to the "modifierFlags" method and one of the flags is "NSCommandKeyMask".
E.G.:
NSUInteger flags = [theEvent modifierFlags];
if( flags == NSCommandKeyMask ){
// Got it!
}
Don't worry about what kind of views they are.
Put each one inside a tab of an NSTabView, with or without tab control displayed.
With tab control, set the desired key combo per tab in IB.
With or without it, create a menu item in a menu in the menu bar for each tab with the same key combos. This is the recommended way since long ago. Apple recommends adding a menu bar menu item for everything that has a keyboard shortcut. The menu bar will receive the keys before anything else.

Fundamental Drag And Drop In iOS

I've been considering an app now that implements a drag and drop sort of idiom from maybe a side pane or a drawer, etc. what I can't wrap my head around are how to keep reference to the objects I drop. I mean; it would be easy if it was just drop the object, then let it alone, but I want more manipulation after the fact.
My brain just cannot wrap around the concept of creating objects out of thin air to place on the 'canvas', or having preset objects (which I imagine would be limited, cumbersome and awkward) already on the canvas that would then just be activated and manipulated easily, seeing as the references to them are created before the fact (my apologies for the loose term 'reference', I mean something like selecting the object and having it's unique properties recognized or displayed).
There must be something I'm missing. So, I wonder how one might go about implementing drag and drop with interface and manipulation with the dropped object after the fact or maybe sample code or a link to a git or svn repo? (something like how MIT's scratch, or Xcode's interface builder might work).
For clarity's sake, I know how to go about fiddling with drag and drop thanks to DragKit, but not about editing 'properties' on the object dropped onto the 'canvas', and I would like there to be a near infinite amount of objects that can be dropped on the canvas, yet a set amount of items in the drawer/side view.
If I'm understanding your question correctly, you want to be able to drag objects onto a canvas and then manipulate their properties individually. For instance, you'd drag square views onto the screen and then increase its size or change its color.
In order to do something like that, I would have a NSMutableArray or an NSMutableSet that would hold all of the on canvas objects. Then when any interaction comes, you could either dynamically generate gesture recognizers if the objects are UIViews or a subclass. Then in the target of the gesture recognizer you would use the recognizer.view property.
Or you would have to check which object on the canvas you were currently manipulating. That would be done by iterating through the array and seeing which object equals the one you are touching.
Is there anything that you are trying to do but is not working? Have you written any code in attempt to do this?

Why does the execution order of touchesBegan, target-action and touchesEnded change with fast touches of UIButton?

UPDATE: With the blush of shame I discovered that the order had nothing to do with the speed of tapping. I was calling the visual code before the super touchesEnded:withEvent call, which was why if you tapped really fast, the display never got a chance to draw the highlighted state before being dismissed again. Because the code that was actually causing the main thread to block just a few milliseconds, the highlighted state would stay visible until the main thread unblocked again, where as if you tapped really fast, it looked like nothing happened at all. Moving the super call up to the top of the overridden method fixed it all. Sorry, if any moderator sees this post it can be deleted. shame
This problem must have been asked a 1000 times at SO, yet I can't find the explanation to match my specific issue.
I have a UIButton subclass with a custom design. Of course the design is custom enough that I can't just use the regular setSomething:forControlState: methods. I need a different backgroundcolor on touch, for one, and some icons that need to flash.
To implement these view changes, I (counter-intuitively) put the display code in (A) touchesBegan:withEvent and (Z) touchesEnded:withEvent:, before calling their respective super methods. Feels weird, but it works as intended, or so it seemed at first.
After implementing addTarget:action:forControlEvents was used to bind the UIControlEventTouchUpInside to the method (X) itemTapped:, I would expect these methods to always fire in the order (A)(X)(Z). However, if you tap the screen real fast (or the mouse in simulator), they fire in the order (A)(Z)(X). Where (A) and (Z) follow each other in such rapid succession, that the whole visual feedback for tapping is invisible. This is unwanted behavior. This also can't be the way to go, for so many apps need similar behavior, right?
So my question to you is: What am I doing wrong? One thing I'm guessing is that the visual appearance of the buttons shouldn't be manipulated in the touchesBegan:withEvent and touchesEnded:withEvent, but then where? Or am I missing some other well known fact?
Thanks for the nudge,
Eric-Paul.
I don't know why the order is different, but here's 2 suggestions to help deal with it.
What visual changes are you making to the button? If it's things like changing title/image/background image, you can do all this by modifying the highlighted state of the button. You can set a few properties like title and background image per-state. When the user's finger is down on the button, the highlighted state is turned on, so any changes you make to this state will be visible at this time. Do note that if you're making use of the selected state on the button, then you'll need to also set up the visual appearance for UIControlStateHighlighted|UIControlStateSelected, otherwise it will default back to inheriting from Normal when both highlighted & selected are on.
The other suggestion is to ditch touchesBegan:withEvent: and touchesEnded:withEvent: and switch over to using the methods inherited from UIControl, namely beginTrackingWithTouch:withEvent: and endTrackingWithTouch:withEvent:. You may also want to implement continueTrackingWithTouch:withEvent: and use the touchInside property to turn off your visual tweaks if the touch leaves the control.

OOP: Designing a menu system

I am currently trying to create a menu system for a game and cannot arrive at any really sound way to do it. There are several menu screens, each of them non-trivial, so that I would like to keep these as separate classes. The main problem I am having is passing control between these menu screens.
I tried building each of the screens as a singleton and call one screen from the other directly, ie. something like [[MainMenu instance] display] in Objective C. This is a bit messy, because (1) I have to write the singleton boilerplate code for each of the menu screens and (2) the classes get dependent on each other, sometimes I have to code around circular dependencies etc.
I thought about making the classes fully static to get around the instance management (which is a bit extra in this case, since there really is just one instance of each screen). But this also looks quite ugly, especially with Objective C having to “fake” class variables by declaring them static.
Then I thought about some “manager” class that would create the instances and pass the control around, but I am not sure introducing an extra class would solve the problem, especially if this class was to be named Manager :-)
I should note that I do have a working system, it just doesn’t feel very nice. By which I mean there is a bit of code duplication going on, if I am not careful the thing might hang, and so on. Any ideas? I am aware that this is underspecified, so that the discussion will probably be more of a brainstorming, but I am interested in the ideas anyway, even if they do not outright solve my problem.
Update: Thank You all for the ideas. What I did in the end:
I reworked the menu contents (buttons, graphics, etc.) to fit under one interface called ScreenView. This is a general interface that looks like this:
#protocol ScreenView
- (void) draw;
- (BOOL) handlesPoint: (CGPoint) p;
- (void) appearWithAnimation;
- (void) disappearWithAnimation;
- (BOOL) hasFinishedAnimating;
#optional
- (void) fingerDown;
- (void) fingerUp;
#end
Thanks to this protocol I was able to throw away all the specific menu screens and create a general menu screen that takes a list of subviews to display and handles all the presentation like drawing, transitions, events and such. This general menu screen does not get subclassed much, because most of the menu screens are happy simply displaying a list of subviews. This would be the V in MVC.
Then I also created a controller class that handles all the events for a certain menu screen. (Obviously the C in MVC.) The root controller class handles the instance management, transitions between menus and some other little things. Most of the menu screens get a customized subclass of the controller that handles the events from the buttons and other subviews.
The number of classes got up, but the code is much cleaner, does not repeat itself and is less prone to errors. The instance management is still not perfect, but I’m reasonably happy with the design. Once again, thank to all who answered.
One of the tricks I learned to decent design is always separate your data from your code. This will do WONDERS for your specific problem.
By this I mean that the menu items (strings) and relationships between the menus should be stored somewhere either in an array or a separate file (and read into an array).
You then use this array to instantiate all your menu classes.
Once you recode it to work this way (I've done this with menus), all your code will fall into place, you'll also factor out--90% of your menuing code (each menu will no longer be it's own class, just the same class instantiated with its own unique data.
The target of the menu items are stored in the "data" as well (as method pointers or class instances).
I think a MenuManager class would be the way to go. You'd have one Menu base class which all the menu screens derive from, and the manager would have a pointer to the currently active menu screen. It could also, for example, keep track of previous menu screens for easy use of back buttons on menu screens in arbitrary menu screen calls. Maybe just use a std::vector for that so you don't have to recreate the previous menu screens when going back (this would also prevent loss of entered information, like in an Options menu with an Advanced submenu).
Putting all the contents of the menus into a dictionary, dumping to a plist and reading each as necessary by the menu screens is likely the simplest route but in all honesty, you should consider taking a more MVC-centric approach to solving the problem. The screens should be for presentation of data not the storage of it. If you provide for a clean separation of the data from the views, the problem solves itself.