How to repaint window after hide or show control - macos

I have a NSTextField control on the bottom of the window.
I need to show them or hide according to some condition.
In the initial state the control is hidden.
The window shows the blank space on the control's position.
When in runtime the control should become visible
mpTxtCtrl.hidden = NO;
it does not happen.
The tasks:
1 Display/Hide control.
2 Resize the main window according to the control's state.
I can't find any tutorials how to manage layouts in the cocoa.
I would be grateful for any help!

When in runtime the control should become visible
mpTxtCtrl.hidden = NO;
it does not happen.
Make sure you connected the mpTxtCtrl outlet to the text field in your nib. Having forgotten to connect your outlet to anything is a leading cause of nothing happening.
I can't find any tutorials how to manage layouts in the cocoa.
Switch to the File Inspector while editing the nib and turn “Use Auto Layout” on. Xcode will create constraints whenever you place views along Aqua guides (the blue lines that appear when you place and size views correctly), and Cocoa will enforce these constraints as the sizes of views and the window change.
More info:
Cocoa Auto Layout Guide
WWDC 2012 videos — include several sessions on Auto Layout
OS X Human Interface Guidelines — Aqua guide lines appear to indicate conformance to the HIG

Check this code, if you will find some useful stuffs here:
-(void)awakeFromNib{
[self.label setHidden:YES];
}
- (IBAction)showHide:(id)sender {
NSLog(#"%#",[sender title]);
if ([[sender title] isEqualToString:#"Hide"]) {
[self.label setHidden:YES];
[sender setTitle:#"Show"];
}
else if ([[sender title] isEqualToString:#"Show"]){
[self.label setHidden:NO];
[sender setTitle:#"Hide"];
}
}
- (IBAction)maximize:(id)sender {
NSArray *screens = [NSScreen screens];
NSRect screenRect;
for (NSInteger index=0; index < [screens count]; index++) {
NSScreen *screen = screens[index];
screenRect = [screen visibleFrame];
}
[self.window setFrame:screenRect display:YES];
}

Related

How to add watermark to Screen (NSScreen) in macOS

I am making an application that will add a watermark to the live screen on Mac. Which API should I choose? I tried NSScreen but I didn't find any method that could add a view to NSScreen.
Such app like Sakura in Mac Appstore.Please check it out,i have no idea which API should i use.
The easiest solution is to define a custom, transparent, window.
When you create the window, you specify the special BorderlessWindowMask. This creates a window that is a simple rectangular area on the screen with no titlebar, edges, etc.
Then you set up a bunch of properties so that
the window floats above the other windows
it doesn't respond to events
it doesn't have a shadow
its background is transparent
And so on
#implementation WatermarkOverlayWindow
- (id)initWithContentRect:(NSRect)contentRect
{
self = [super initWithContentRect:contentRect
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO];
if (self!=nil)
{
self.level = NSFloatingWindowLevel;
self.ignoresMouseEvents = YES;
self.releasedWhenClosed = NO;
self.movableByWindowBackground = NO;
self.alphaValue = 1.0f;
self.backgroundColor = NSColor.clearColor;
self.opaque = NO;
self.hasShadow = NO;
}
return self;
}
...
Now you can add semi-transparent views to this window and those views will appear to float on the screen. Alternatively, you can place opaque views in this window and then change the overall alphaValue of the window to something less than 1.0.

UITextField resize issue

I have found an issue with UITextField. I have created a subclass of uitexfield that allows the user to click on the text to start editing and then rotate and resize the text.
If you resize the textfield by making the height larger the centered text moves to the right even though the width of the textfield does not increase. I have investigated this and found that uitextfield has an internval view of the type UIFieldEditor which in turn has a _UIFieldEditorContentView view. UIFieldEditor seems to be a subclass of UIScrollView and the contentsize of this scrollview becomes much larger than the size of uitextview. When the textview increases it's height the scrollviews contentsize width increases. I guess this might be an internal autolayout issue.
I have added a demo project here that demonstrates the issue. CLick on the text to start edit, then drag the resize icon so that the height increases and you will see the issue.
https://github.com/permagnus/UITextField-Resize-Issue-Demo
Screenhots from revealapp:
Incorrect size of underlying view in scrollview: https://github.com/permagnus/UITextField-Resize-Issue-Demo/blob/master/Screenshots/screenshot-showing-incorrect-size.png
The actuall size of the uitextfield: https://github.com/permagnus/UITextField-Resize-Issue-Demo/blob/master/Screenshots/screenshot-showing-textfield-size.png
Any ideas on how to fix this issue?
I found two ways to fix the issue:
The problems lies within the underlying scrollview. One way is to find the scrollview and se how much offseted it is and compensate for the wrong offset:
- (CGRect)editingRectForBounds:(CGRect)bounds
{
CGRect editRect = [super editingRectForBounds:bounds];
UIScrollView *scrollView = [self findScrollViewFromView:self];
if(scrollView)
{
float diff = (self.bounds.size.width - scrollView.contentSize.width)/2;
return CGRectInset(editRect, diff, 0);
}
return editRect;
}
- (UIScrollView *)findScrollViewFromView:(UIView *)view
{
if([view isKindOfClass:[UIScrollView class]])
{
return (UIScrollView *) view;
}
for(UIView *v in view.subviews)
{
UIScrollView *scrollView = [self findScrollViewFromView:v];
if(scrollView)
{
return scrollView;
}
}
return nil;
}
I also contacted Apple Support to get their point of the problem. They confirmed that this probably is a bug and I have submitted it as one. Their solution is the following:
Field editor is only activated for current editing session, so you can
end the editing session of the text field (by calling
resignFirstResponder) before resizing it (in touchesBegan... ?). In
your scenario, I guess keeping the editing session might not be
necessary.
If you really need to keep the editing session, one solution (ugly) I
can see is to reset the text and make sure the cursor is at the
beginning of document:
self.text = [self.text copy];
UITextPosition *beginningOfDocument = [self positionFromPosition:self.beginningOfDocument offset:0];
self.selectedTextRange = [self textRangeFromPosition:self.beginningOfDocument toPosition:beginningOfDocument];
Both of these solutions are shitty hacks and are not recommended so you use these at your own risk :)

NSOpenGLView toggle to fullscreen from within the view

I'm trying to create a method that will toggle between fullscreen and a window. I'm trying to do this from within a class inherited from NSOpenGLView, essentially following this blogpost. That works once, going from windowed to fullscreen; trying to go back fails in various ways: the window screen doesn't get updated, or I don't even manage switch to the window but the fullscreen just blanks out. Trying to go back and forth a few times anyway (mapped it to the 'f' key), the program often locks up, and in a worst case, I have to restart my computer.
I've attached the code for the method below; for debugging purposes, I've set the full frame rectangle much smaller, so that if things freeze, the application is never at full screen.
The fullscreen example in the Apple developer examples suggest using a controller, and does not go fullscreen from within the inherited NSOpenGLView.
My questions:
should I use a controller instead, and from there switch between windowed and fullscreen (creating a separate fullscreen view each time)? Or should both methods work?
If both methods should work, which one is preferred?
If both methods can work, what am I doing wrong in the current way of implementing this?
or, is there a third, better, method?
Note that for both references, I'll have to assume that things haven't changed for 10.8 (both references seem to apply to 10.6).
Code follows:
#implementation MyOpenGLView
[...]
- (void)toggleFullscreen
{
mainWindow = [self window];
if (isFullscreen) {
[fullscreenWindow close];
[mainWindow setAcceptsMouseMovedEvents:YES];
[mainWindow setContentView: self];
[mainWindow makeKeyAndOrderFront: self];
[mainWindow makeFirstResponder: self];
isFullscreen = false;
} else {
[mainWindow setAcceptsMouseMovedEvents:NO];
//NSRect fullscreenFrame = [[NSScreen mainScreen] frame];
NSRect fullscreenFrame = { {300, 300}, {300, 300} };
fullscreenWindow = [[NSWindow alloc] initWithContentRect:fullscreenFrame
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO];
if (fullscreenWindow) {
[fullscreenWindow setAcceptsMouseMovedEvents:YES];
[fullscreenWindow setTitle:#"Full screen"];
[fullscreenWindow setReleasedWhenClosed: YES];
[fullscreenWindow setContentView: self];
[fullscreenWindow makeKeyAndOrderFront: self];
//[fullscreenWindow setOpaque:YES];
//[fullscreenWindow setHidesOnDeactivate:YES];
// Set the window level to be just above the menu bar
//[fullScreenWindow setLevel:NSMainMenuWindowLevel+1];
// Set the window level to be just below the screen saver
[fullscreenWindow setLevel:NSScreenSaverWindowLevel-1];
[fullscreenWindow makeFirstResponder:self];
isFullscreen = true;
} else {
NSLog(#"Error: could not switch to full screen.");
}
}
}
[...]
#end
I now think this can't be done, and should not be done. When windowed, the rendering context is a window, which is a different beast than a screen, when rendering fullscreen.
Thus, when switching between, things have to re-setup everytime you switch.
It is possible to simply use the native fullscreen option that is in the newest OS X variants. This will (presumably) enlarge the containg window to full screen size while removing the frame, borders and buttons. Thus, you're still rendering to a window, though it looks fullscreen.
I'm not sure if this option makes things slower: there's a window layer in between, which could make it a slower than rendering directly to a screen.
For the curious, implementing the native fullscreen is ridiculously easy (at least in 10.8 and 10.9): In XCode, select the .xib file, select the (main) window in the editor's sidebar, then select the attributes selector on the right. You can find a "Full Screen" selection between Unsupported, Primary Window or Auxiliary Window. That will automatically add the full screen toggle to the window.
Even neater, now select the main menu -> view menu in the sidebar, find the "Full Screen Menu Item" in the inspector at the bottom (there's a search bar for it), drag it into the View menu in the editor, and voilà, it will have a shortcut and automatically connect to the full screen option for the window (select the new View menu item and look at the Connections inspector to it's already connected for you).
A nice way to test all this is to grab the full screen example I linked in my question, and edit it as suggested above. Using the default control-command F shortcut to toggle back and forth between fullscreen will show the opengl view and the frame with text below it in a full screen. Using the fullscreen option as coded in the example will toggle the openglview to use the fullscreen, without any extra (Cocoa) frames, buttons or text.
I'm curious about this too- specifically your first two bullet point questions.
This doesn't address those questions, but your third one about the bug, I think you can get away with just changing the properties of the same window (works for me):
- (void)toggleFullscreen
{
if (isFullscreen) {
NSRect windowFrame = [[NSScreen mainScreen] visibleFrame];
[mainWindow setStyleMask:NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask ];
[mainWindow setFrame:windowFrame display:true];
[mainWindow setAcceptsMouseMovedEvents:YES];
[mainWindow setLevel:NSNormalWindowLevel];
[mainWindow setTitle:#"SimpleOculus"];
[mainWindow makeKeyAndOrderFront:self];
[mainWindow makeFirstResponder:self];
isFullscreen = false;
}
else {
NSRect fullscreenFrame = [[NSScreen mainScreen] frame];
[mainWindow setStyleMask:NSBorderlessWindowMask];
[mainWindow setFrame:fullscreenFrame display:true];
[mainWindow setAcceptsMouseMovedEvents:YES];
[mainWindow setLevel:NSScreenSaverWindowLevel-1];
[mainWindow makeKeyAndOrderFront:self];
[mainWindow makeFirstResponder:self];
isFullscreen = true;
}
}

NSOutlineView scroll animation is not working

I want to remove the NSOutlineView's show/hide button.So,I override the NSOutlineView and get the mouseDown event.The follow is the code.
-(void)mouseDown:(NSEvent *)theEvent
{
NSLog(#"LeftFolderListOutlineView mouseDown");
[super mouseDown:theEvent];
NSPoint localPoint = [self convertPoint:theEvent.locationInWindow
fromView:nil];
NSInteger row = [self rowAtPoint:localPoint];
id clickedItem = [self itemAtRow:row];
if (![clickedItem isKindOfClass:[NSDictionary class]]) {
return;
}
if ([self isItemExpanded:clickedItem]) {
[[self animator] collapseItem:clickedItem];
}else{
[[self animator] expandItem:clickedItem];
}
}
It should be a scroll animation when the NSOutlineView collapse or expand.But in this case it's not working.Anyone tell me why and how can I improve this?
To remove 'show/hide button' (outline cell) you could implement - (NSRect)frameOfOutlineCellAtRow:(NSInteger)row method in the NSOutliveView subclass and return NSZeroRect.
NSOutlineView collapse/expand animation is not animatable via animator.
Only OS 10.7 or above provide collapse/expand animation effects. So it you planed to support older OS versions you need to provide separate implementation.
If you want to provide collapse/expand animation on OS 10.6 or below, you definitely needed to override 'drawRect' of NSOutlineView.
-- Update --
Sorry, I think I neglected the main point. 10.7 expand/collapse animation is automatically kick in only when users clicked the outline cell. If we want to show the animation without default outline cells, there is no other way but manually implementing animation effects, I think.
I made a sample project that implement expand/collapse animation effects with image drawing.
Check the source codes in here: https://github.com/roh0sun/ovanimation

Two Finger Drag with IKImageView and NSScrollView in Mountain Lion

I have a Mac App that's been in the app store for a year or so now. It was first published with target SDK 10.7, Lion. Upon the update to Mountain Lion it no longer works.
The application displays large images in an IKImageView which is embedded in an NSScrollView. The purpose of putting it into a scrollview was to get two finger dragging working, rather than the user having to click to drag. Using ScrollViewWorkaround by Nicholas Riley, I was able to use two finger scrolling to show the clipped content after the user had zoomed in. Just like you see in the Preview app.
Nicholas Riley's Solution:
IKImageView and scroll bars
Now in Mountain Lion this doesn't work. After zooming in, pinch or zoom button, the image is locked in the lower left portion of the image. It won't scroll.
So the question is, what's the appropriate way to display a large image in IKImageView and have two finger dragging of the zoomed image?
Thank you,
Stateful
Well, Nicholas Riley's Solution is an ugly hack in that it addresses the wrong class; the issue isn't with NSClipView (which he subclassed, but which works just fine as is), but with IKImageView.
The issue with IKImageView is actually quite simple (God knows why Apple hasn't fixed this in what? … 7 years ...): Its size does not adjust to the size of the image it displays. Now, when you embed an IKImageView in an NSScrollView, the scroll view obviously can only adjust its scroll bars relative to the size of the embedded IKImageView, not to the image it contains. And since the size of the IKImageView always stays the same, the scroll bars won't work as expected.
The following code subclasses IKImageView and fixes this behavior. Alas, it won't fix the fact that IKImageView is crash-prone in Mountain Lion as soon as you zoom …
///////////////////// HEADER FILE - FixedIKImageView.h
#import <Quartz/Quartz.h>
#interface FixedIKImageView : IKImageView
#end
///////////////////// IMPLEMENTATION FILE - FixedIKImageView.m
#import "FixedIKImageView.h"
#implementation FixedIKImageView
- (void)awakeFromNib
{
[self setTranslatesAutoresizingMaskIntoConstraints:NO]; // compatibility with Auto Layout; without this, there could be Auto Layout error messages when we are resized (delete this line if your app does not use Auto Layout)
}
// FixedIKImageView must *only* be used embedded within an NSScrollView. This means that setFrame: should never be called explicitly from outside the scroll view. Instead, this method is overwritten here to provide the correct behavior within a scroll view. The new implementation ignores the frameRect parameter.
- (void)setFrame:(NSRect)frameRect
{
NSSize imageSize = [self imageSize];
CGFloat zoomFactor = [self zoomFactor];
NSSize clipViewSize = [[self superview] frame].size;
// The content of our scroll view (which is ourselves) should stay at least as large as the scroll clip view, so we make ourselves as large as the clip view in case our (zoomed) image is smaller. However, if our image is larger than the clip view, we make ourselves as large as the image, to make the scrollbars appear and scale appropriately.
CGFloat newWidth = (imageSize.width * zoomFactor < clipViewSize.width)? clipViewSize.width : imageSize.width * zoomFactor;
CGFloat newHeight = (imageSize.height * zoomFactor < clipViewSize.height)? clipViewSize.height : imageSize.height * zoomFactor;
[super setFrame:NSMakeRect(0, 0, newWidth - 2, newHeight - 2)]; // actually, the clip view is 1 pixel larger than the content view on each side, so we must take that into account
}
//// We forward size affecting messages to our superclass, but add [self setFrame:NSZeroRect] to update the scroll bars. We also add [self setAutoresizes:NO]. Since IKImageView, instead of using [self setAutoresizes:NO], seems to set the autoresizes instance variable to NO directly, the scrollers would not be activated again without invoking [self setAutoresizes:NO] ourselves when these methods are invoked.
- (void)setZoomFactor:(CGFloat)zoomFactor
{
[super setZoomFactor:zoomFactor];
[self setFrame:NSZeroRect];
[self setAutoresizes:NO];
}
- (void)zoomImageToRect:(NSRect)rect
{
[super zoomImageToRect:rect];
[self setFrame:NSZeroRect];
[self setAutoresizes:NO];
}
- (void)zoomIn:(id)sender
{
[super zoomIn:self];
[self setFrame:NSZeroRect];
[self setAutoresizes:NO];
}
- (void)zoomOut:(id)sender
{
[super zoomOut:self];
[self setFrame:NSZeroRect];
[self setAutoresizes:NO];
}
- (void)zoomImageToActualSize:(id)sender
{
[super zoomImageToActualSize:sender];
[self setFrame:NSZeroRect];
[self setAutoresizes:NO];
}
- (void)zoomImageToFit:(id)sender
{
[self setAutoresizes:YES]; // instead of invoking super's zoomImageToFit: method, which has problems of its own, we invoke setAutoresizes:YES, which does the same thing, but also makes sure the image stays zoomed to fit even if the scroll view is resized, which is the most intuitive behavior, anyway. Since there are no scroll bars in autoresize mode, we need not add [self setFrame:NSZeroRect].
}
- (void)setAutoresizes:(BOOL)autoresizes // As long as we autoresize, make sure that no scrollers flicker up occasionally during live update.
{
[self setHasHorizontalScroller:!autoresizes];
[self setHasVerticalScroller:!autoresizes];
[super setAutoresizes:autoresizes];
}
#end

Resources