NSOutlineView cell-based background glitch while editing in 10.12 - cocoa

I have an cell-based NSOutlineView under 10.12 with Source-View highlighting. When I first click on the cell and it goes into edit mode, everything is ok:
However, as soon as I start editing, the background turns blue like the highlight.
I have tried (without success):
#interface NonBackgroundDrawingTextView : NSTextView
#end
#implementation NonBackgroundDrawingTextView
-(BOOL)drawsBackground
{
return NO;
}
#end
-(NSTextView *)fieldEditorForView:(NSView *)controlView
{
NSTextView* textView = [[NonBackgroundDrawingTextView alloc] initWithFrame:NSZeroRect];
[textView setFieldEditor:YES];
[textView setFocusRingType:NSFocusRingTypeDefault];
return textView;
}
Any ideas? It works fine in 10.10 and 10.11.

Subclass NSTextFiled, and set datacell to this
then override
- (void)selectWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)anObject start:(NSInteger)selStart length:(NSInteger)selLength
{
NSRect textFrame = [self titleRectForBounds:aRect];
[super selectWithFrame:textFrame inView:controlView editor:textObj delegate:anObject start:selStart length:selLength];
[textObj setBackgroundColor:[NSColor whiteColor]];
[textObj setDrawsBackground:YES];
}

Related

Xcode 10 - NSVisualEffectView added to NSWindow when displayed modally (Mac OS)

I have a NSWindow that I display modally on some other window to display alerts.
The code is:
// This code is in MyAlert .m file. MyAlert inherits from NSWindow
- (void)showInWindow:(NSWindow *) {
[window beginSheet:self completionHandler:NULL];
}
Thing is that when compiled with Xcode 10.1 in a Mac running Mojave I see a gray "blurring" view behind the alert which I don't want there: I want the background window where it's shown to be visible.
Same code compiled with Xcode 9.4.1 does not show this blurring view.
Furthermore, I debugged the UI and there's indeed a NSVisualEffectView inserted in the Xcode 10.1 compiled version which is not there when compiling on 9.4.1, but I can't seem to find a way to get rid of it.
Below are screenshots of the UI debugged in both versions.
Has someone faced and figured this one out?
Update (Minimal Project reproducing issue of inserted nsvisualeffectview): http://s000.tinyupload.com/?file_id=43114618701497778758
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
__weak typeof(self)weakSelf = self;
NSView *contentView = self.window.contentView;
contentView.wantsLayer = YES;
[self.window setOpaque:NO];
[self.window setHasShadow:NO];
contentView.layer.backgroundColor = [NSColor redColor].CGColor;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf showAlert];
});
}
- (void)showAlert {
DummyAlertWindowController *alertController = [[DummyAlertWindowController alloc] initWithWindowNibName:#"DummyAlertWindowController"];
[self.window beginSheet:alertController.window completionHandler:^(NSModalResponse returnCode) {
;
}];
}
#implementation DummyAlertWindowController
- (void)windowDidLoad {
[super windowDidLoad];
self.properContentView.wantsLayer = YES;
self.properContentView.layer.backgroundColor = [NSColor blueColor].CGColor;
[self.window setOpaque:NO];
[self.window setHasShadow:NO];
self.window.contentView.wantsLayer = YES;
self.window.contentView.layer.backgroundColor = [NSColor clearColor].CGColor;
}
#end
You can recover your non-frosted appearance by making your window borderless.
Add this class to your project.
#interface BorderlessWindow : NSWindow
#end
#implementation BorderlessWindow
- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style backing:(NSBackingStoreType)backingStoreType defer:(BOOL)flag {
self = [super initWithContentRect:contentRect
styleMask:NSWindowStyleMaskBorderless
backing:backingStoreType
defer:flag];
return self;
}
#end
And set the window class in your XIB to BorderlessWindow
Lastly set the backgroundColor on the window to get the transparency.
#implementation DummyAlertWindowController
- (void)windowDidLoad {
[super windowDidLoad];
//stuff
[self.window setOpaque:NO];
[self.window setHasShadow:NO];
[self.window setBackgroundColor:[NSColor clearColor]];
}
#end
As a side note using wantsLayer to get backgroundColors is better served now by using a custom style NSBox with a custom color or using the backgroundColor property on the window.

NSButton Toggle : OnClick title get removed on OSX 10.11

I am using a Toggle button in XIB,
in AwakeFromNib :I set title and BG image of the button.
Code works very well till OSX 10.10.5 and below but on higher versions when I click on button the text gets removed.
Set attributed Title
[self.deleteButton setWantsLayer:YES];
self.deleteButton.layer.backgroundColor = [self setButtonBGColor];
[self setButtonTitleFor:self.deleteButton
toString:#"Delete"];
[self.deleteButton setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawOnSetNeedsDisplay];
- (void)setButtonTitleFor:(NSButton*)button toString:(NSString*)title
{
NSAttributedString *attrString = [self getAttributedStringForString:title];
[button setAttributedTitle:attrString];
}
Any idea hat should be done.
So finally got it right
Subclassing NSButtonCell helped me out
RPButtonTextTopCell.h
#interface RPButtonTextTopCell : NSButtonCell
#end
RPButtonTextTopCell.m
#implementation RPButtonTextTopCell
-(id) init
{
self = [super init];
if (self) {
}
return self;
}
-(id) initWithCoder:(NSCoder *)decoder
{
return [super initWithCoder:decoder];
}
-(id) initTextCell:(NSString *)string
{
return [super initTextCell:string];
}
-(NSRect)titleRectForBounds:(NSRect)theRect
{
NSRect titleFrame = [super titleRectForBounds:theRect];
NSSize titleSize = [[self attributedStringValue] size];
titleFrame.origin.y = (theRect.origin.y - (theRect.size.height-titleSize.height)*0.5) + 5;
return titleFrame;
}
#end
Utilizing This Custom Class
RPButtonTextTopCell *deleteCell = [[RPButtonTextTopCell alloc] init];
deleteCell.backgroundColor = [self setNSButtonBGColor];
[self.deleteButton setCell:deleteCell];
[self setButtonTitleFor:self.deleteButton
toString:#"Delete"];
[self.deleteButton setAction:#selector(deleteButtonClicked:)];
[self.deleteButton setTarget:self];
and its solved....

Black Text-Background on cell-based NSTableView with Sourcelist Highlight style (10.12)

I have noticed an issue under macOS 10.12: When I create a NSTableView with "Sourcelist" Highlight style, the Text-Cells draw a black background while being edited, making the text black on black and actually unreadable.
I wonder if anybody else ran into this issue and if there is a possible workaround.
I have found a workaround by subclassing NSTextFieldCell and make it return a subclass of NSTextTextView as its field editor.
This subclass needs to override - drawsBackground returning NO.
Setting this property after initialization does not seem to be enough.
#interface NonBackgroundDrawingTextView : NSTextView
#end
#implementation NonBackgroundDrawingTextView
- (BOOL)drawsBackground {
return NO;
}
#end
#interface CustomTextFieldCell : NSTextFieldCell
#end
#implementation CustomTextFieldCell
- (NSTextView *)fieldEditorForView:(NSView *)controlView {
static NSMutableDictionary* FieldEditors = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
FieldEditors = [NSMutableDictionary dictionary];
});
if (FieldEditors[#(controlView.hash)]) {
return FieldEditors[#(controlView.hash)];
}
NSTextView* textView = [[NonBackgroundDrawingTextView alloc] initWithFrame:NSZeroRect];
[textView setFieldEditor:YES];
[textView setFocusRingType:NSFocusRingTypeExterior];
FieldEditors[#(controlView.hash)] = textView;
return textView;
}
#end

Changing view in NSWindow removes contents of view

I am using an NSToolbar and NSWindowController to change the views of an NSWindow. When the toolbar items are selected, the view is successfully changed for the window and the window changes it's size according to the view size. Upon the initial loading of the window, the contents of the view appear as expected. However, once a toolbar item is selected the contents of the new view are not visible and when the view is switched back to the original view, it's contents are no longer visible either. Not sure what is causing this so any help would be appreciated.
#import <Cocoa/Cocoa.h>
#interface WindowController : NSWindowController {
IBOutlet NSView *firstView;
IBOutlet NSView *secondView;
int currentViewTag;
}
- (IBAction)switchView:(id)sender;
#end
and
#import "WindowController.h"
#interface WindowController ()
#end
#implementation WindowController
- (id)init {
self = [super initWithWindowNibName:#"WindowController"];
if (self) {
}
return self;
}
- (void)windowDidLoad {
[super windowDidLoad];
}
- (NSRect)newFrameForNewContentView:(NSView*)view {
NSWindow *window = [self window];
NSRect newFrameRect = [window frameRectForContentRect:[view frame]];
NSRect oldFrameRect = [window frame];
NSSize newSize = newFrameRect.size;
NSSize oldSize = oldFrameRect.size;
NSRect frame = [window frame];
frame.size = newSize;
frame.origin.y -= (newSize.height - oldSize.height);
return frame;
}
- (NSView *)viewForTag:(int)tag {
NSView *view = nil;
switch (tag) {
case 0:
view = firstView;
break;
case 1:
view = secondView;
break;
}
return view;
}
- (BOOL)validateToolbarItem:(NSToolbarItem *)item {
if ([item tag] == currentViewTag) return NO;
else return YES;
}
- (void)awakeFromNib {
[[self window] setContentSize:[firstView frame].size];
[[[self window] contentView] addSubview:firstView];
[[[self window] contentView] setWantsLayer:YES];
}
- (IBAction)switchView:(id)sender {
double tag = [sender tag];
NSView *view = [self viewForTag:tag];
NSView *previousView = [self viewForTag:currentViewTag];
currentViewTag = tag;
NSRect newFrame = [self newFrameForNewContentView:view];
[NSAnimationContext beginGrouping];
if ([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask)
[[NSAnimationContext currentContext] setDuration:1.0];
[[[[self window] contentView] animator] replaceSubview:previousView with:view];
[[[self window] animator] setFrame:newFrame display:YES];
[NSAnimationContext endGrouping];
}
#end
I tried out your code, and what I saw was not that the views disappeared, but that they were positioned wrongly and moved out of view. I fixed this by turning off auto layout in IB, and deselecting all the struts and springs in the size inspector. I also deselected the window's "restorable" property so that if you closed the program with view 2 visible, and reopened, the window (with view 1 inside) would be the correct size for view 1.

Cocoa: Right Click NSStatusItem

I am a .Net developer who need to port a small project into Mac, so I know next to nothing about Objective C. In fact the code below was just a bunch of grasping at straws and shooting in the dark.
Trying to build a Status Menu program that opens one or another window depending on if it is a left-click or a right-click/ctrl+click. Here is what I have, and it works for left-click only (obviously):
-(void) awakeFromNib{
NSBundle *bundle = [NSbundle mainBundle];
statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
[statusImage = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:#"icon" ofType:#"png"]];
[statusItem setImage:statusImage];
[statusItem setToolTip:#"Program Name"];
[statusItem setHighlightMode:YES];
[statusItem setAction:#selector(openWin:)];
[statusItem setTarget: self];
}
-(void)openWin:(id)sender{
[self openLeftWindow:sender];
}
-(IBAction)openLeftWindow:(id)sender{
//Code to populate Left Click Window
[leftWindow makeKeyAndorderFront:nil];
}
-(IBAction)openRightWindow:(id)sender{
//Code to populate Right Click Window
[rightWindow makeKeyAndorderFront:nil];
}
It seems to me that the solution would be either an if statement in the openWin() function to determine which button is clicked (or if ctrl was held down) then run the appropriate code or to make the menu aware of both the left and right clicks. But neither of these have worked when I attempted to do so.
Thanks In Advance.
If you will be satisfied with detecting control-click and not right click, then the first block of code will do what you want. If you really need the right click detection, you will have to use a custom view instead of an image in your NSStatusItem, and the second block of code will work.
Simple Method:
- (void)openWin:(id)sender {
NSEvent *event = [NSApp currentEvent];
if([event modifierFlags] & NSControlKeyMask) {
[self openRightWindow:nil];
} else {
[self openLeftWindow:nil];
}
}
Custom view method:
- (void)awakeFromNib {
...
statusImage = ...
MyView *view = [MyView new];
view.image = statusImage;
[statusItem setView:view];
[statusItem setToolTip:#"Program Name"];
view target = self;
view action = #selector(openLeftWindow:);
view rightAction = #selector(openRightWindow:);
[view release];
//[statusImage release]; //If you are not using it anymore, you should release it.
}
MyView.h
#import <Cocoa/Cocoa.h>
#interface MyView : NSControl {
NSImage *image;
id target;
SEL action, rightAction;
}
#property (retain) NSImage *image;
#property (assign) id target;
#property (assign) SEL action, rightAction;
#end
MyView.m
#import "MyView.h"
#implementation MyView
#synthesize image, target, action, rightAction;
- (void)mouseUp:(NSEvent *)event {
if([event modifierFlags] & NSControlKeyMask) {
[NSApp sendAction:self.rightAction to:self.target from:self];
} else {
[NSApp sendAction:self.action to:self.target from:self];
}
}
- (void)rightMouseUp:(NSEvent *)event {
[NSApp sendAction:self.rightAction to:self.target from:self];
}
- (void)dealloc {
self.image = nil;
[super dealloc];
}
- (void)drawRect:(NSRect)rect {
[self.image drawInRect:self.bounds fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1];
}
#end
I would create a view and use the status items method.
-setView:
Then in the subclassed view you can detect ctrl+LMB using the following
- (void)mouseDown:(NSEvent *)theEvent
{
[super mouseDown:theEvent];
//Respond to the mouse click
if ([theEvent modifierFlags] & NSCommandKeyMask) //Command + LMB
{
//Do something
}
}
I think you can figure out the rest.
A more simplified response (Note, only works with control + click)
Properties:
#property (strong, nonatomic) NSStatusItem *statusItem;
#property (weak) IBOutlet NSMenu *statusMenu;
In Your Application Did Load:
[self.statusItem setAction:#selector(itemClicked:)];
Clicked Function:
- (void)itemClicked:(id)sender
{
NSEvent *event = [NSApp currentEvent];
if([event modifierFlags] & NSControlKeyMask) {
NSLog(#"Right Click Pressed");
[self.statusItem popUpStatusItemMenu:self.statusMenu];
} else {
// Do Nothing
NSLog(#"Left Click Pressed");
}
}

Resources