Rotation Transformation for UITextField, but text is displaced - objective-c

I am trying to rotate UITextField at 90 angle.It is rotationg perfectly..but text inside the UITextField, is displaced.I am unable to find out the reason behind it.

[InputField setTransform:CGAffineTransformMakeRotation(-M_PI / 2.0)];
[InputField setContentVerticalAlignment:UIControlContentVerticalAlignmentTop];
[InputField setContentHorizontalAlignment:UIControlContentHorizontalAlignmentCenter];
works for me!

What exactly is the problem? When I apply an CGAffineTransformation to an TextField, everything looks fine.
myTextField.transform = CGAffineTransformMakeRotation(M_PI_2);

Instead of setting the vertical and horizontal alignment (which produces the off-center edit window observed above), you could handle the editing rect manually. I overrided editingRectForBounds as follows. This centers the editing rect regardless of rotation:
-(CGRect)editingRectForBounds:(CGRect)bounds
{
// how tall is the font?
CGFloat fontHeight = [self.text sizeWithFont:self.font].height;
// compute pad
CGFloat pad = (bounds.size.height - fontHeight) / 2.0f;
// return rect with pad on top and bottom
return CGRectMake(bounds.origin.x, bounds.origin.y + pad, bounds.size.width, fontHeight);
}

Related

NSTableCellView padding

How can I add padding to a NSTableCellView?
I want the contents to have a padding of 10px, similar to how you would do it in plain HTML. (All sides). The text should be vertically centered in the middle.
At the moment I'm doing this in a subclass of NSTextFieldCell. But this doesn't seem to work correctly.
When I edit the text, the edit text field does not use the padding from the textfieldcell.
Image 2:
Here is the code I currently have, (subclass of NSTextFieldCell)
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
NSRect titleRect = [self titleRectForBounds:cellFrame];
NSAttributedString *aTitle = [self attributedStringValue];
if ([aTitle length] > 0) {
[aTitle drawInRect:titleRect];
}
}
- (NSRect)titleRectForBounds:(NSRect)bounds
{
NSRect titleRect = bounds;
titleRect.origin.x += 10;
titleRect.origin.y = 2;
NSAttributedString *title = [self attributedStringValue];
if (title) {
titleRect.size = [title size];
} else {
titleRect.size = NSZeroSize;
}
// We don't want the width of the string going outside the cell's bounds
CGFloat maxX = NSMaxX(bounds);
CGFloat maxWidth = maxX - NSMinX(titleRect);
if (maxWidth < 0) {
maxWidth = 0;
}
titleRect.size.width = MIN(NSWidth(titleRect), maxWidth);
return titleRect;
}
Below are some options for getting the padding.
Earlier I had some problems getting the correct bounding box height for NSAttributedString. I don't remember how I solved them but there are some discussions on the matter.
Idea #1:
Use NSTableView's intercell spacing. It's also available in the Interface Builder from the table view's size tab. Look for cell spacing.
Idea #2:
When editing the interface:
Unless you need something else, use the text or image and text table cell view provided by Apple.
Change the height of the table cell view inside the table view using the size tab.
Reposition the text field inside the table cell view.
Idea #3:
Use a custom cell.
You can change the field editor position by overriding -[NSTextFieldCell editWithFrame:inView:editor:delegate:event:]. There's also -[NSTextFieldCell setUpFieldEditorAttributes]. I found this sample code useful.
If you increase the height of the cell, there are a couple of ways to make NSTextFieldCell draw the text vertically centered.
use the setContentInset method.it sets the distance of the inset between the content view and the enclosing table view.
for example
self.tableView.contentInset = UIEdgeInsetsMake(-35, 0, -20, 0);

Change font size UITextField when pinch

I'm developing an iOS6 app for iPad. The user can add a textfield, edit it, move and rotate it. I would like that when the user pinches the field, it gets bigger. I've tried it, but the text gets pixeled, because the font size doesn't change. How can I detect the actual font size so as to increase it? This is my actual code:
- (void)pinchDetected:(UIPinchGestureRecognizer*) pinchRecognizer {
CGFloat scale = pinchRecognizer.scale;
self.transform = CGAffineTransformScale(self.transform, scale, scale);
pinchRecognizer.scale = 1.0;
}
Thanks for your help!
Why not try this?
CGFloat currentFontSize = self.font.pointSize;
CGFloat newFontSize = currentFontSize * scale; //or anything you wish
self.font = [self.font fontWithSize:newFontSize];

How do I avoid interpolation artifacts when drawing NSImage into a different size rect?

My end goal is to fill an arbitrarily sized rectangle with an NSImage. I want to:
Fill the entire rectangle
Preserve the aspect ratio of the image
Show as much as possible of the image while maintaining 1) and 2)
When not all the image can be shown, crop toward the center.
This demonstrates what I'm trying to do. The original image of the boat at the top is drawn into various sized rectangles below.
Okay, so far so good. I added a category to NSImage to do this.
#implementation NSImage (Fill)
/**
* Crops source to best fit the destination
*
* destRect is the rect in which we want to draw the image
* sourceRect is the rect of the image
*/
-(NSRect)scaleAspectFillRect:(NSRect)destRect fromRect:(NSRect)sourceRect
{
NSSize sourceSize = sourceRect.size;
NSSize destSize = destRect.size;
CGFloat sourceAspect = sourceSize.width / sourceSize.height;
CGFloat destAspect = destSize.width / destSize.height;
NSRect cropRect = NSZeroRect;
if (sourceAspect > destAspect) { // source is proportionally wider than dest
cropRect.size.height = sourceSize.height;
cropRect.size.width = cropRect.size.height * destAspect;
cropRect.origin.x = (sourceSize.width - cropRect.size.width) / 2;
} else { // dest is proportionally wider than source (or they are equal)
cropRect.size.width = sourceSize.width;
cropRect.size.height = cropRect.size.width / destAspect;
cropRect.origin.y = (sourceSize.height - cropRect.size.height) / 2;
}
return cropRect;
}
- (void)drawScaledAspectFilledInRect:(NSRect)rect
{
NSRect imageRect = NSMakeRect(0, 0, [self size].width, [self size].height);
NSRect sourceRect = [self scaleAspectFillRect:rect fromRect:imageRect];
[[NSGraphicsContext currentContext]
setImageInterpolation:NSImageInterpolationHigh];
[self drawInRect:rect
fromRect:sourceRect
operation:NSCompositeSourceOver
fraction:1.0 respectFlipped:YES hints:nil];
}
#end
When I want to draw the image into a certain rectangle I call:
[myImage drawScaledAspectFilledInRect:onScreenRect];
Works really well except for one problem. At certain sizes the image looks quite blurry:
My first thought was that I need to draw on integral pixels, so I used NSIntegralRect() before drawing. No luck.
As I thought about it I figured that it's probably a result of the interpolation. To draw from the larger image to the smaller draw rect NSImage has to interpolate. The blurry images are likely just a case where the values don't map very well and we end up with some undesirable artifacts that can't be avoided.
So, the question is this: How do I choose an optimal rect that avoids those artifacts? I can adjust either the draw rect or the crop rect before drawing to avoid this, but I don't know how or when to adjust them.

NSSlider NSSliderCell clipping custom knob

I am creating a custom NSSlider with a custom NSSliderCell. All is working beautifully, other than the knob. When I drag it to the max value the knob is being clipped, I can only see 50% of the knob image.
When assigning my custom NSSliderCell I am setting the knobThickness to the width of the image I am using as the knob. I assumed (I guess wrongly) that it would take that into account and stop it from clipping?
Any ideas what I am doing wrong? The slider is hitting the maxValue only when the knob is clipped at 50%, so its not travelling without adding any value.
- (void)drawKnob:(NSRect)knobRect {
NSImage * knob = _knobOff;
knobRectVar = knobRect;
[[self controlView] lockFocus];
[knob
compositeToPoint:
NSMakePoint(knobRect.origin.x+4,knobRect.origin.y+knobRect.size.height+20)
operation:NSCompositeSourceOver];
[[self controlView] unlockFocus];
}
- (void)drawBarInside:(NSRect)rect flipped:(BOOL)flipped {
rect.size.height = 8;
[[self controlView] lockFocus];
NSImage *leftCurve = [NSImage imageNamed:#"customSliderLeft"];
[leftCurve drawInRect:NSMakeRect(5, 25, 8, 8) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1];
NSRect leftRect = rect;
leftRect.origin.x=13;
leftRect.origin.y=25;
leftRect.size.width = knobRectVar.origin.x + (knobRectVar.size.width/2);
[leftBarImage setSize:leftRect.size];
[leftBarImage drawInRect:leftRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction:1];
[[self controlView] unlockFocus];
}
The NSSLider expects a special sizes off the knob images for each control size:
NSRegularControlSize: 21x21
NSSmallControlSize: 15x15
NSMiniControlSize: 12x12
Unfortunately the height of your knob image mustn't exceed one of this parameters. But it's width may be longer. If it is you may count an x position for the knob like this:
CGFloat newOriginX = knobRect.origin.x *
(_barRect.size.width - (_knobImage.size.width - knobRect.size.width)) / _barRect.size.width;
Where _barRect is a cellFrame of your bar background from:
- (void)drawBarInside:(NSRect)cellFrame flipped:(BOOL)flipped;
I've created a simple solution for the custom NSSlider. Follow this link
https://github.com/Doshipak/LADSlider
You can override [NSSliderCell knobRectFlipped:] in addition to [NSSliderCell drawKnob:].
Here is my solution:
- (void)drawKnob:(NSRect)rect
{
NSImage *drawImage = [self knobImage];
NSRect drawRect = [self knobRectFlipped:[self.controlView isFlipped]];
CGFloat fraction = 1.0;
[drawImage drawInRect:drawRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:fraction respectFlipped:YES hints:nil];
}
- (NSRect)knobRectFlipped:(BOOL)flipped
{
NSImage *drawImage = [self knobImage];
NSRect drawRect = [super knobRectFlipped:flipped];
drawRect.size = drawImage.size;
NSRect bounds = self.controlView.bounds;
bounds = NSInsetRect(bounds, ceil(drawRect.size.width / 2), 0);
CGFloat val = MIN(self.maxValue, MAX(self.minValue, self.doubleValue));
val = (val - self.minValue) / (self.maxValue - self.minValue);
CGFloat x = val * NSWidth(bounds) + NSMinX(bounds);
drawRect = NSOffsetRect(drawRect, x - NSMidX(drawRect) + 1, 0);
return drawRect;
}
Know it's been awhile but I ran into this issue myself and found a quick-and-dirty workaround.
I couldn't get around the initial reason for this but it seems that NSSlider is expecting a quadratic handle image.
The easiest way I found was to set the range of your slider to be from 0.0f - 110.0f for example.
Then you check in the valueChanged target method assigned if the value is > 100.0f and set it back to that value if it is. I created a background image with some pixels of alpha-only pixels on the right side so your background isn't wider than the actual fader range.
Quick-and-dirty but doesn't require a lot code and works pretty well.
Hope this helps other guys stumbling upon the same issue.
You don’t need to lock and unlock focus on the controlView from inside cell drawing methods. These methods are only called by your controlView’s -drawRect: method, which is called with the view’s focus locked.
Why are you adding 20 points to the Y coordinate the knob image is composited to in -drawKnob?

NSAffineTransforms not being used?

I have a subclass of NSView, and in that I'm drawing an NSImage. I'm unsing NSAffineTransforms to rotate, translate and scale the image.
Most of it works fine. However, sometimes, the transforms just don't seem to get activated.
For example, when I resize the window, the rotate transform doesn't happen.
When I zoom in on the image, it puts the lower left of the image in the correct place, but doesn't zoom it, but it does zoom the part of the image that would be to the right of the original sized image. If I rotate this, it zooms correctly, but translates wrong. (The transation may be a calculation error on my part)
Here is the code of my drawRect: (sorry for the long code chunk)
- (void)drawRect:(NSRect)rect
{
// Drawing code here.
double rotateDeg = -90* rotation;
NSAffineTransform *afTrans = [[NSAffineTransform alloc] init];
NSGraphicsContext *context = [NSGraphicsContext currentContext];
NSSize sz;
NSRect windowFrame = [[self window] frame];
float deltaX, deltaY;
NSSize superSize = [[self superview] frame].size;
float height, width, sHeight, sWidth;
NSRect imageRect;
if(image)
{
sz = [ image size];
imageRect.size = sz;
imageRect.origin = NSZeroPoint;
imageRect.size.width *= zoom;
imageRect.size.height *= zoom;
height = sz.height * zoom ;
width = sz.width *zoom ;
sHeight = superSize.height;
sWidth = superSize.width;
}
I need to grab the sizes of everything early so that I can use them later when I rotate. I am not sure that I need to protect any of that, but I'm paranoid from years of C...
[context saveGraphicsState];
// rotate
[afTrans rotateByDegrees:rotateDeg];
// translate to account for window size;
deltaX = 0;
deltaY = 0;
// translate to account for rotation
// in 1 and 3, X and Y are reversed because the entire FRAME
// (inculding axes) is rotated!
switch (rotation)
{
case 0:
// NSLog(#"No rotation ");
break;
case 1:
deltaY -= (sHeight - height);
deltaX -= sHeight ;
break;
case 2:
deltaX -= width;
deltaY -= ( 2*sHeight - height);
// it's rotating around the lower left of the FRAME, so,
// we need to move it up two frame hights, and then down
// the hieght of the image
break;
case 3:
deltaX += (sHeight - width);
deltaY -= sHeight;
break;
}
Since I'm rotating around the lower left corner, and I want the image to be locked to the upper left corner, I need to move the image around. When I rotate once, the image is in the +- quadrant, so I need to shift it up one view-height, and to the left a view-height minus an image height. etc.
[afTrans translateXBy:deltaX yBy:deltaY];
// for putting image in upper left
// zoom
[afTrans scaleBy: zoom];
printMatrix([afTrans transformStruct]);
NSLog(#"zoom %f", zoom);
[afTrans concat];
if(image)
{
NSRect drawingRect = imageRect;
NSRect frame = imageRect;
frame.size.height = MAX(superSize.height, imageRect.size.height) ;
[self setFrame:frame];
deltaY = superSize.height - imageRect.size.height;
drawingRect.origin.y += deltaY;
This makes the frame the correct size so that the image is in the upper left of the frame.
If the image is bigger than the window, I want the frame to be big enough so scroll bars appear. If it isn't I want the frame to be big enough that it reaches the top of the window.
[image drawInRect:drawingRect
fromRect:imageRect
operation:NSCompositeSourceOver
fraction:1];
if((rotation %2) )
{
float tmp;
tmp = drawingRect.size.width;
drawingRect.size.width = drawingRect.size.height;
drawingRect.size.height = tmp;
}
This code may be entirely historical, now that I look at it... the idea was to swap height andwidth if I rotated 90 or 270 degs.
}
else
NSLog(#"no image");
[afTrans release];
[context restoreGraphicsState];
}
Why do you use the superview's size? That's something you should almost never need to worry about. You should make the view work on its own without dependencies on being embedded in any specific view.
Scaling the size of imageRect is probably not the right way to go. Generally when calling -drawImage you want the source rect to be the bounds of the image, and scale the destination rect to zoom it.
The problems you're reporting kind of sound like you're not redrawing the entire view after changing the transformation. Are you calling -setNeedsDisplay: YES?
How is this view embedded in the window? Is it inside an NSScrollView? Have you made sure the scroll view resizes along with the window?