Positioning Stacked NSTextView subviews within Scroll View - objective-c

This might be a long winded explanation but I'd rather say too much than not enough. In a nutshell I need to embed a series of stacked textViews in a single scrollView programatically and I can't get it working. I'm basing my efforts off the Text Architecture sample code in the docs.
http://developer.apple.com/library/mac/#documentation/TextFonts/Conceptual/CocoaTextArchitecture/TextSystemArchitecture/ArchitectureOverview.html
I can create a textView programatically well enough but I can't make two inside a scroll view and have them move as one and be editable. There's a nice little diagram explaining how it's possible to create pagination using the same basic concepts but there is no accompanying code and I haven't been successful at doing it myself. I've made a sad little collage of overlapping textViews where only one is editable so far.
Also, if there is a standard way of accomplishing this, a nudge in the right direction would be most appreciated.
Here's my code:
float w = self.windowView.frame.size.width;
float h = self.windowView.frame.size.height*.5;
NSSize halfSize = NSMakeSize(w,h);
textStorage = [[NSTextStorage alloc]
initWithString:#"Here's to the ones who see things different."];
NSLayoutManager *layoutManager;
layoutManager = [[NSLayoutManager alloc] init];
[textStorage addLayoutManager:layoutManager];
NSTextContainer *textContainer;
textContainer = [[NSTextContainer alloc]
initWithContainerSize:halfSize];
[layoutManager addTextContainer:textContainer];
NSTextContainer *textContainer2;
textContainer2 = [[NSTextContainer alloc]
initWithContainerSize:halfSize];
[layoutManager addTextContainer:textContainer2];
self.windowView = [[NSTextView alloc]
initWithFrame:_windowView.frame
textContainer:textContainer];
[self.window setContentView:_windowView];
[self.window makeKeyAndOrderFront:nil];
[self.window makeFirstResponder:_windowView];
NSTextView *textView = [[NSTextView alloc]init];
[textView setTextContainer:textContainer2];
[self.windowView addSubview:textView];
[textView setFrameSize:halfSize];
NSPoint thePoint = NSMakePoint(0, self.windowView.frame.size.height);
[textView setFrameOrigin:thePoint];
[textView setEditable:YES];
[textView setNeedsDisplay:YES];
I should mention. I'm an enthusiast, but by no means a particularly competent programmer. Completely self taught. (Well, actually the book I bought did most of the teaching). I just finished Hillegrass's Cocoa Programming for Mac OSX and I'm working on a bit of a personal learning project to get the ball rolling. I want to make a screenwriting app which formats scene headings, descriptions, dialogs, characters, etc in different ways and
attaches a bunch of information to each section so that standing over a block would show information about that particular segment (scene info).
I've been making mini apps to test everything I would need and so far I've gone through the Text Attribute Guide and The Text Layout Guide in the docs and have figured out a lot. I'm using Core data and bindings for most of everything but I'm stuck at what is arguably the most important part of the app. Getting the main scrollView to display stacked blocks of differently styled text that can be accessed individually by other parts of the app. (my thoughts are on creating an array of NSTextViews and using current index to link an array of info items to particular blocks, though I keep thinking this feels like a bindings sort of job.)
Thanks in advance!
Omar

Related

Mavericks Style Tagging

I'm quite new to cocoa and I'm trying to find out how I can create something similar to the new tagging UI in Mavericks:
I assume, I'll have to overwrite NSTokenFieldCell to get the coloured dots or an icon on the tags. But how does this popup list work?
Thanks for your help!
Sadly, you'll have to roll your own. Almost all of the drawing taking place in NSTokenFieldCell is private, so adding any kind of ornamental elements would have to be done by you. If I remember correctly, NSTokenFieldCell uses an NSTokenTextView instead of the window's standard field editor. I'm not sure what's different about it, but I think it's mostly to deal with the specialized nature of "tokenizing" attributed strings. I think they just use NSAttachmentCell objects for the graphical tokens, and when the cell receives a -mouseDown: event, they show the menu.
The menu part would actually be pretty easy because you can add images to menu items like so:
NSMenuItem *redItem = [[NSMenuItem alloc] initWithTitle:#"Red"
action:#selector(chooseColorMenuItem:)
keyEquivalent:#""];
// You could add an image from your app's Resources folder:
NSImage *redSwatchImage = [NSImage imageNamed:#"red-menu-item-swatch"];
// ----- or -----
// You could dynamically draw a color swatch and use that as its image:
NSImage *redSwatchImage = [NSImage imageWithSize:NSMakeSize(16.0, 16.0)
flipped:NO
drawingHandler:^BOOL(NSRect dstRect) {
NSRect pathRect = NSInsetRect(dstRect, 0.5, 0.5); // Aligns border to integral values
NSBezierPath *path = [NSBezierPath bezierPathWithOvalInRect:pathRect];
NSColor *fillColor = [NSColor redColor];
NSColor *strokeColor = [fillColor shadowWithLevel:0.5];
[fillColor setFill];
[path fill];
[strokeColor setStroke];
[path stroke];
return YES;
}];
redItem.image = redImage;
With respect to the token drawing stuff, take my info with a grain of salt because Apple's documentation on this stuff is pretty lacking, so everything I'm telling you is from personal struggles, cursing, and head-banging. Anyway, I'm sorry I couldn't bring you better news, but I guess, it is what it is. Good luck.

How to remove or hide background in MKMapView when using custom tiles

Having tried many methods I still haven't found a good and full-proof way of preventing the usual "maps" from being shown behind custom map tiles that I am using. Ultimately I want my app to have a map page consisting only of a custom map.
I am really looking for a solution that is pure iOS and doesn't require any 3rd party software but it would appear difficult.
I have tried 3 methods already:
Number 1, hiding the background map via it's view:
NSArray *views = [[[self.mapView subviews] objectAtIndex:0] subviews];
[[views objectAtIndex:0] setHidden:YES];
this however doesn't work on a certain new operating system coming out very soon! The whole screen goes blank. The Apple Developer Forum hasn't provided a solution either
Number 2, Using another blank overlay (e.g. MKCircle) to cover the background map. This works however when scrolling or zooming out quickly, sometimes the overlay flickers off and you can briefly see the background map behind so not ideal.
Number 3, and this is what I have been working on for a few days now is to simply prevent the user from zooming out. Most documented methods tend to use regionDidChangeAnimated or regionWillChangeAnimated, however these do not seem to suddenly stop the map zooming out when pinching - they wait until the pinch movement has finished before taking effect so again it means the background map can be viewed briefly.
So now I am stumped, unless of course I have missed something with these other two methods.
So any help would be much appreciated!
Add this:
-(void)viewDidAppear:(BOOL)animated
{
MKTileOverlay *overlay = [[MKTileOverlay alloc] init];// initWithURLTemplate:tileTemplate];
overlay.canReplaceMapContent = YES;
[map addOverlay:overlay];
overlay = nil;
}
-(void)loadTileAtPath:(MKTileOverlayPath)path result:(void (^)(NSData *, NSError *))result
{
NSData *tile =nil;
}
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay: (id<MKOverlay>)overlay
{
if ([overlay isKindOfClass:[MKTileOverlay class]])
{
MKTileOverlayRenderer *renderer = [[MKTileOverlayRenderer alloc] initWithOverlay:overlay];
[renderer setAlpha:0.5];
return renderer;
}
}
It will replace the map content from the background. It worked very well in my case where I am adding an overlay on the whole map and hiding the real map from the user.
You can't do this in current releases without a third-party library like MapBox. However, the future OS release that you speak of lets you do this.

Using the camera on the iPad/iPhone with an overlay

I am trying to add an overlay image to a photo that is taken. Has anyone seen any examples on how I can do this? I want to have a picture which is a transparent PNG file, and then allow the user to take a picture with the image in it.
Iulius is correct that this is essentially a duplicate question. However, just to rule out one issue-- would you like the user to be able to see the overlay while composing the shot? (i.e. if your app makes different hats appear on people's heads, do you want to show the hat floating in space while they take the photo?). If you want to learn more about that, you'll need to use the cameraOverlayView property of the imagePickerController, which lets you superimpose your own view(s) on the camera. There are questions on this topic already on SO, like this one: How to add a overlay view to the cameraview and save it
Update re: scaling-- LilMoke, I assume when you say that the image is offset you're getting into trouble with the difference with the camera's aspect ratio (4:3) and the screen of the iPhone (3:4). You can define a constant and use it to set the cameraViewTransform property of your UIImagePickerController. Here's a code snippet, partially borrowed, and simplified from the excellent augmented reality tutorial at raywenderlich.com:
#define CAMERA_TRANSFORM 1.24299
// First create an overlay view for your superimposed image
overlay = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
overlay.backgroundColor=[UIColor clearColor];
overlay.opaque = NO;
UIImagePickerController *imagePicker;
imagePicker = [[[UIImagePickerController alloc] init] autorelease];
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePicker.showsCameraControls = YES; // assuming you need these?
imagePicker.toolbarHidden = YES;
imagePicker.navigationBarHidden = YES;
imagePicker.wantsFullScreenLayout = YES;
imagePicker.cameraViewTransform = CGAffineTransformScale(imagePicker.cameraViewTransform,
CAMERA_TRANSFORM, CAMERA_TRANSFORM); // If I understood your problem, this should help
imagePicker.cameraOverlayView = overlay;
If code along these lines doesn't get you on track, then maybe you can post all the relevant code from your troubled project here. Hopefully it's just a matter of setting the cameraViewTransform as I said above.

AQGridView iOS Create custom icons (image+label) instead of image

I've just started using AQGridView from Alan Quatermain more specifically, the SpringBoard demo..
The demo shows icons/tiles that consist of a UIImageView. I'd like to know how to use a custom UIView instead so that I can have an icon with text/button underneath.
I'm currently trawling through the code with no real luck in finding how my icons are created.
Any ideas/suggestions would be greatly appreciated..
Cheers.
Check out AQGridViewCell and, specifically, contentView property. This is similar to customizing UITableViewCell.
Have you checked out three20's TTLauncherView?
Although it is for the iPhone you might be able to adopt it for the iPad. It allows for an icon with text underneath. Though you might have to hack it for inserting a custom UIView in place of the image and text.
I found iOSGuy's tutorial helpful when working with TTLauncherView.
And here is an excerpt from iOSGuy's tutorial to show little bit about how it is setup/used.
TTLauncherView* launcherView = [[TTLauncherView alloc]
initWithFrame:self.view.bounds];
launcherView.backgroundColor = [UIColor blackColor];
launcherView.columnCount = 4;
launcherView.pages = [NSArray arrayWithObjects:
[NSArray arrayWithObjects:
[self launcherItemWithTitle:#"Google"
image:#"bundle://safari_logo.png"
URL:#"http://google.com"],
[self launcherItemWithTitle:#"Apple"
image:#"bundle://safari_logo.png"
URL:#"myAppController/myView"]
, nil]
, nil];

Printing Off-screen PDFViews

I have a situation where I want to print a multi-page PDF. While I could use the PDFKit utility classes and/or quartz functions to get the information to manually write drawing/pagination code for a NSView subclass, I had thought that quicker alternative would be to create an off-screen PDFView and tell it to print itself. When I tried this solution, the print dialog didn't go away, all of the print settings controls on the right half of the print dialog disappeared, and the application froze.
I then wrote a tiny test application with the following method that illustrates the problem. When the test program is compiled without the USE_PDF_VIEW preprocessor macro defined, the blank view displays fine. If USE_PDF_VIEW is defined, the document doesn't print, most of the print dialog controls disappear, and the app freezes. While I have other ways of accomplishing my goal, I'm curious as to why this shortcut doesn't work. Is there something about Cocoa drawing I still don't understand? Am I banging into Apple Voodoo Magic(tm) behind the scenes that makes PDFView behave in a completely different way than other NSViews?
- (void)printMyStuff:(id)sender {
NSPrintInfo *currInfo = [NSPrintInfo sharedPrintInfo];
#ifdef USE_PDF_VIEW
PDFView *pdfView = [[PDFView alloc] init];
PDFDocument *pdfDoc = [[PDFDocument alloc] initWithURL:[NSURL fileURLWithPath:#"/Users/wls/Documents/my_document.pdf"]];
[pdfView setDocument: pdfDoc];
[pdfView printWithInfo:currInfo autoRotate:YES];
#else
NSView *myView = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 500, 500)];
NSPrintOperation *myop = [NSPrintOperation printOperationWithView:myView printInfo:currInfo];
[myop runOperation];
#endif
}
Had the exact same problem.
The PDFView needs to be added to a NSWindow in order for printWithInfo:autoRotate: to work (atleast in my case), otherwise the printing controls go blank or won't work.
Here's the complete code:
PDFView *vDoc = [[PDFView alloc] init];
[vDoc setDocument:pdfDoc];
[vDoc setAutoScales: YES];
[vDoc setDisplaysPageBreaks: NO];
NSWindow *wnd = [[NSWindow alloc] init];
[wnd setContentSize:vDoc.frame.size];
[wnd setContentView:vDoc];
[vDoc printWithInfo:printInfo autoRotate:YES];
[wnd release];
[vDoc release];
Building on alex-i's excellent answer, I added the following lines so the print dialog showed up in a user-friendly location:
NSRect windowRect = self.window.frame;
NSPoint printTopLeftPoint = NSMakePoint(CGRectGetMidX(windowRect), CGRectGetMaxY(windowRect));
[wnd setFrameTopLeftPoint:printTopLeftPoint];
My self.window is for my current window controller, not the temporary window.
I like alex-i's answer because it does not use private APIs. But in my case, I already have a window (and I suppose in most cases you would!), so I figured I would use that window instead of creating one. Here is what I ended up doing, using swift:
func print(_ pdfDocument: PDFDocument, using window: NSWindow) {
// create a hidden pdf view with the document
let pdfView = PDFView()
pdfView.document = pdfDocument
pdfView.autoScales = true
pdfView.displaysPageBreaks = false
pdfView.frame = NSMakeRect(0.0, 0.0, 50.0, 50.0)
pdfView.isHidden = true
// add the view to the window and print
window.contentView.addSubview(pdfView)
pdfView.print(nil)
pdfView.removeFromSuperview()
}
PDFView is a subclass of NSView. The designated initializer for NSView is -initWithFrame: ... if you don't use -initWithFrame: strange things can happen. Since PDFView has no other designated initializers, -initWithFrame: is it. I'm guessing that's at least part of your problem.
Another part may be memory related. Are you using garbage collection or not? If you are, you're not keeping a reference to your PDFView anywhere, so may be getting deallocated. If you aren't using garbage collection, you're leaking your PDFView (also because you keep no reference to it, so you can release it when you're done). Same with your myView NSView instance ... you're leaking it if you're not using GC.