NSPoint and IMKCandidate Window Placement - objective-c

I am using the inputmethodkit and trying to place a window underneath some text.
_currentClient is an IMKTextInput instance
candidates is an IMKCandidates instance
// Get the current location to place the window
NSRect tempRect = NSMakeRect(0, 0, 0, 0);
NSDictionary* clientData = [_currentClient attributesForCharacterIndex:0 lineHeightRectangle:&tempRect];
NSPoint* windowInsertionPoint = (NSPoint*)[clientData objectForKey:#"IMKBaseline"];
...
[candidates setCandidateFrameTopLeft:*windowInsertionPoint];
[candidates showCandidates];
Now, I know that the windowInsertionPoint variable is fine, when I debug I can see it's value, eg: NSPoint: {647,365}
However when I use this, the candidate window just shows in the bottom left corner of the screen. I haven't worked with screen placement of stuff before, so help is appreciated.
If I pass in arbitrary static values to setCandidateFrameTopLeft, it gets placed in the screen. The following works:
[candidates setCandidateFrameTopLeft:NSMakePoint(401, 354)];
Is it a pointer problem?

OK, the solution to this is that I am an idiot. Here is the code you need:
NSRect tempRect;
NSDictionary* clientData = [_currentClient attributesForCharacterIndex:0 lineHeightRectangle:&tempRect];
NSPoint windowInsertionPoint = NSMakePoint(NSMinX(tempRect), NSMinY(tempRect));
The documentation for IMKTextInput attributesForCharacterIndex says
lineRect: On return, a rectangle that frames a one-pixel wide rectangle with the height of the line. This rectangle is oriented the same way the line is oriented.
This means it returns an NSRect into the variable your passed it for the lineHeightRectangle value. The important point is that the location of that NSRect is the location of the character you are searching for. So, then you need to just make a point from that rectangle and use NSMinY for the Y value. The rectangle is only a single pixel wide so Min/Max for X are basically the same.

You probably don't have this issue anymore, but this works too, for future:
[candidates show:kIMKLocateCandidatesBelowHint];

Related

Equal sized cells in NSSegmentedControl

For my NSSegmentedControl, I use it do display a bar to control a NSTableView. I have code set up to control the size programmatically:
for (NSInteger i = 1; i <= numberOfSegments; i++) {
CGSize textSize = [[NSString stringWithFormat:#"Workspace %ld", (long)i] sizeWithAttributes:#{NSFontAttributeName: [NSFont systemFontOfSize:13.0f]}];
NSInteger segmentWidth = self.workspaceControl.frame.size.width / numberOfSegments;
if (textSize.width > segmentWidth) {
[self.workspaceControl setLabel:[NSString stringWithFormat:#"%ld", (long)i] forSegment:i - 1];
} else {
[self.workspaceControl setLabel:[NSString stringWithFormat:#"Workspace %ld", (long)i] forSegment:i - 1];
}
[self.workspaceControl setWidth:segmentWidth forSegment:i - 1];
}
This works, by a small problem occurs.
At the beginning (with one segment) it looks like this:
As I change the value, the right side gets clipped slightly.
And then back to one segment:
The constraints are as follows:
Im very puzzled by the clipping (probably because a couple pixels t0o large), but I have no idea how to fix it, or is there a better way to get evenly spaced cells?
In my testing the generated width constraints of the NSSegmentedControl segments appear to round to whole numbers despite setWidth(_ width: CGFloat, forSegment segment: Int) taking a CGFloat. Thus the total width of the segments can add up to more than the width of the control itself.
To get even segments pass segmentWidth through the floor. Also, set a manual width for the control and constrain it horizontally by the centerXAnchor instead of by the leading and trailing anchors to preserve its center-alignment.
Drawbacks: the width must be hard-coded and the left and right margins may not match your other views exactly.

CGContextShowGlyphsAtPoint DEPRECATED

After spending quite a bit of time to display "Thai Phonetic YK" fonts in an iPhone app. I finally got things sorted out and working.
Though it is functionning there is still a complaint (warning) from the compiler about one line of code in the (void)drawRect: method of my class performing the display.
CGContextShowGlyphsAtPoint(context, 20, 50, textToPrint, textLength);
The compiler tells me that this code is DEPRECATED. My question is “How am I supposed to change it?”.
Even though I searched the net for an answer, I didn’t find any thing clear.
The documentation says something like “Use Core Text instead” which is far too vague to be considered as an answer.
Core Graphics:
void CGContextShowGlyphsAtPoint (
CGContextRef context,
CGFloat x,
CGFloat y,
const CGGlyph glyphs[],
size_t count
);
Core Text:
void CTFontDrawGlyphs (
CTFontRef font,
const CGGlyph glyphs[],
const CGPoint positions[],
size_t count,
CGContextRef context
);
The Core Text version requires a CTFontRef (in the Core Graphics version, the font is expected to be set in the context).
You can obtain a CTFontRef from a UIFont:
CTFontRef ctFont = CTFontCreateWithName( (__bridge CFStringRef)uiFont.fontName, uiFont.pointSize, NULL);
The CT version also requires an array of points, one for each glyph. Assuming you were drawing a single glyph with the CG code, you could create the array like this:
CGPoint point = CGPointMake(x, y);
const CGPoint* positions = &point;
This change does mean you will need a point position for each glyph. In my case the extra work was minimal: I was advancing the typesetter one character at a time (for curved text) so I had to do this calculation anyway.
You may be able to typeset one text run at a time with CTRun:
void CTRunDraw (
CTRunRef run,
CGContextRef context,
CFRange range );
That could save you the trouble of iterating over each glyph. You could use it something like this...
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CTLineRef line = CTLineCreateWithAttributedString(
(__bridge CFTypeRef)self.attributedString);
CFArrayRef runs = CTLineGetGlyphRuns(line);
CFIndex runCount = CFArrayGetCount(runs);
for (CFIndex runIndex = 0; runIndex < runCount; ++runIndex) {
CTRunRef run = CFArrayGetValueAtIndex(runs, runIndex);
[self adjustContextForRun:run];
CTRunDraw (run, context, 0)
}
(thats just a sketch, implementation will depend on your needs, and i haven't tested the code)
adjustContextForRun would be responsible for setting things like font and initial draw position for the run.
Each CTRun represents a subrange of an attributed string where all of the attributes are the same. IF you don't vary attributes over a line, you can abstract this further:
CTLineDraw(line, context);
I don't know if that level of abstraction would work in your case (i am only used to working with Latin fonts), but its worth knowing it's there, saves a lot of lower-level trouble.
You can set the initial drawing position for the text with this:
void CGContextSetTextPosition (
CGContextRef c,
CGFloat x,
CGFloat y );

Stopping objects when collision occurs in sprite kit

I'm building a game using Apple's SpriteKit and SKPhysics that use squares that move around on the screen based on user input. I'm having an issue with collisions in that the squares will move out of place if they collide. For example, if all the blocks move to the right, any blocks that are on the same "row" need stack next to each other and not overlap or move position vertically. As of now, they will change their vertical direction. Here is my code:
self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.size];
self.physicsBody.dynamic = YES;
self.physicsBody.allowsRotation = NO;
self.physicsBody.affectedByGravity = NO;
Are there any other settings that I'm missing?
The issue could be coming from your collisionBitMask category. In order to solve that, you need to first create categories for the blocks' physics bodies as follows:
struct PhysicsCategory {
static let None : UInt32 = 0
static let All : UInt32 = UInt32.max
static let block : UInt32 = 0b1
}
then set the blocks' settings to the following.
block.physicsBody?.categoryBitMask = PhysicsCategory.block
block.physicsBody?.collisionBitMask = PhysicsCategory.None
This should prevent the collision calculations from being automatically carried out by spritekit.
If you're moving your sprites via user inputs(i.g. SKAction's moveTo), then you're most likely not using physics to move your sprite. In this case, you should make the velocity of the physicsbody to 0- this will make the sprite completely rigid when it comes in contact with another object.
Try:
self.physicsBody.velocity = CGVectorMake(0, 0);
You should put this code inside your update loop.

Change LHSprite position from code (levelhelper-XCODE)

I'm trying to move all sprites with the same tag some inches to the right.
I have tried 4 different type of expressions in order to do so, but nothing worked. Here is what i ve done so far...
-(void) moveSprites {
NSArray* spritesWithTag = [lh spritesWithTag: BOXES1]
for (LHSprite* spr in spritesWithTag)
(NSLog (#"name is %#", [spr uniqueName]);
CGPoint newposition = ccpSub (ccp(-50,0), [spr position]);
//generating the new position for the elements
[spr transformPosition: newposition];
//first attemp, should work but for some reason it doesn't work
spr.position = newposition;
//2nd attemp
b2Vec2 newpositionVector (newposition.x, newposition.y);
[spr body]->SetTransform(newpositionVector, 0);
//third try
[spr setPosition:newposition];
//last form
}
When i run the app the method call works fine and all sprites with tag BOXES1 appear in the output tab, but its position hasn't changed at all. Any idea over why is it happening. What did I wrong? Is there any other way to move an sprite or are them prevented from moving in some other form i dont know? Those are static sprites, dont know if this affects... thanks!

Performance issues when drawing many MKOverlays

When I draw a path with MKOverlays (sometimes with 5000+ individual MKPolylines), there is a very long wait for all of the overlays to be drawn, and every time the map view is scrolled to a new area, the overlays for that area have to be drawn, and there is another noticeable freeze-up.
My dilemma is that I have two sets of code which both draw the path correctly. The first draws the path as one long line, and draws very quickly. The second draws each line segment as an individual line, and takes a long long time.
Now, why would I even consider the second way? Because I have to analyze each individual line to see what color the line should be. For example, if the line's title property is "red", then I make the line red, but if it is "blue", then the line is blue. With the first technique, this kind of specificity is not possible (as far as I know, but maybe someone else knows differently?) because the path is just one big line, and accessing each individual segment is impossible. With the second way it is easy, but just takes a long time.
Here are my two sets of code:
First way (fast but can't access individual segments):
CLLocationCoordinate2D coords[sizeOverlayLat];
for(int iii = 0; iii < sizeOverlayLat; iii++) {
coords[iii].latitude = [[overlayLat objectAtIndex:iii] doubleValue];
coords[iii].longitude = [[overlayLong objectAtIndex:iii] doubleValue];
}
MKPolyline* line = [MKPolyline polylineWithCoordinates:coords count:sizeOverlayLat];
[mapViewGlobal addOverlay:line];
Second way (slow but I can draw each line with a specific color):
NSMutableArray* lines = [NSMutableArray new];
for(int idx = 1; idx < sizeOverlayLat; idx++) {
CLLocationCoordinate2D coords[2];
coords[0].latitude = [[overlayLat objectAtIndex:(idx - 1)] doubleValue];
coords[0].longitude = [[overlayLong objectAtIndex:(idx - 1)] doubleValue];
coords[1].latitude = [[overlayLat objectAtIndex:idx] doubleValue];
coords[1].longitude = [[overlayLong objectAtIndex:idx] doubleValue];
MKPolyline* line = [MKPolyline polylineWithCoordinates:coords count:2];
[line setTitle:[overlayColors objectAtIndex:idx]];
[lines addObject:line];
}
[mapViewGlobal addOverlays:lines];
My question is: Can I get the performance of the first way with the control over each line that the second way provides me?
You can definitely get such performance, but you would probably need to create your own overlay view.
In that view, you can draw polylines by calling CGAddLineToPoint repeatedly, while skipping parts using CGMoveToPoint. Do this separately for each color and you're done. So if you have 2 colors (red+blue), you would loop through your polygon twice, first drawing red (skipping blue pieces) and then drawing blue (skipping red pieces).