NSMenuItem toggle Bold Font style - objective-c

I have to implement NSMenuItem such a way that selected NSMenuItem should have Bold Text , this is what i have done,
#implementation NSMenuItem (Font)
-(void)setBoldStyle:(bool)bBold{
NSString* title = [self title] ;
NSFont *pFont = (bold)?[NSFont boldSystemFontOfSize:14]:[NSFont menuFontOfSize:12];
NSDictionary* fontAttribute = [NSDictionary dictionaryWithObjectsAndKeys:
pFont, NSFontAttributeName,
nil] ;
NSMutableAttributedString* newTitle = [[NSMutableAttributedString alloc] initWithString:title
attributes:fontAttribute] ;
[self setAttributedTitle:newTitle] ;
[newTitle release] ;
}
#end
With Above peiece of code, i am able to set the bold text when a particular NSMenuItem gets selected,
but if it needs to be toggled ( Means if an item was bold earlier, it should be normal now), then its not happening,
This is the way i am calling it,
// have we selected any menuitem yet
if ( prevStatusIndex >0){
// then deselect it
pTempMenuItem = [pMenu itemAtIndex:prevStatusIndex];
[pTempMenuItem setBoldStyle:NO];
}
prevStatusIndex = clientStatus+1;
pTempMenuItem = [pMenu itemAtIndex:prevStatusIndex]; // 1 because a separator added
[pTempMenuItem setBoldStyle:YES];
Any idea whats going wrong ?

You need to use similar to this :
if ([pTempMenuItem boldStyle]) {
NSLog(#"currently bold. change it");
[pTempMenuItem setBoldStyle:NO]);
}
else{
[pTempMenuItem setBoldStyle:YES]);
NSLog(#"currenlty normal. change it");
}

We can only guess as there is a lot of information missing from your question - where are prevStatusIndex, pMenuItem, pMenu and clientStatus declared and given values? What is the valid range of clientStatus? Etc.
In the comments you've said you have used the debugger and breakpoints, but gave no indication of what values you saw.
You really need to provide more detail so folk can help you.
Provided the selected index is never 0 (i.e. prevStatusIndex is not 0 or clientStatus is not -1) and pMenu points to the correct menu then your code works. If the selected index can be zero then you need to change your test for de-bolding to prevStatusIndex >= 0 otherwise the first entry in the menu can be bolded but not unbolded.
HTH.

Related

Returning NSTextView's Selection Attributes

When you use TextEdit and have a selection of string, it will give you the selection color, font, size and other attributes as you see above. How do you get those text selection attributes? I'm certain that I need to use the selectedTextAttributes method. I have the following lines of code.
- (void)textViewDidChangeSelection:(NSNotification *)notification {
if ([notification object] == textView1) {
...
...
NSMutableDictionary *dict = [[textView1 selectedTextAttributes] mutableCopy];
NSLog(#"%#",dict);
}
}
If I run it, the result is not quite like what I expect.
NSBackgroundColor = "NSNamedColorSpace System selectedTextBackgroundColor";
NSColor = "NSNamedColorSpace System selectedTextColor";
There aren't really useful values that I can use to get the text color of the string selection and other attributes. If I ask Google about selectedTextColor, I don't get much luck.
Thank you for your help.
selectedTextAttributes describe what the selection highlighting looks like, not the attributes of selected text. I looked for quite some time for the answer to this question, and finally found it here:
Attribute String Programming Guide
Some example code. For an NSTextView* named editingView, this gathers an array of NSDictionary objects for all the differently formatted ranges in the selection.
NSMutableArray* attributes = [NSMutableArray array];
NSRange selRange = editingView.selectedRange;
NSRange effectiveRange = NSMakeRange(selRange.location, 0);
while (NSMaxRange(effectiveRange) < NSMaxRange(selRange)) {
[attributes addObject: [editingView.textStorage attributesAtIndex: NSMaxRange(effectiveRange) longestEffectiveRange: &effectiveRange inRange: selRange]];
}

Strange behavior in NSTextView when pressing tabs (Even when tabStops are set)

I'm observing a strange behavior in my NSTextView.
Assume there are multiple lines (separated by enter key presses) and when I keep pressing tabs, the whole paragraph turns into bulleted lines.
I did set the tabStops and enabled the Ruler to see the tabStops as mentioned in
Premature line wrapping in NSTextView when tabs are used
For an empty NSTextView it works fine, but when I apply it to an existing text, even though the tabStops are properly set, there is this strange behavior of turning into bulleted paragraph when pressing tabs.
Here is my code used to retrieve the existing string in the NSTextView and to set the tabStops
- (IBAction)formatTextView:(EditorTextView *)editorTextView tableWidth:(double) width
{
int cnt;
int numStops;
int tabInterval = 30;
NSTextTab *tabStop;
//attributes for attributed String of TextView
NSMutableDictionary* attrs = [[[editorTextView textStorage] attributesAtIndex:0 effectiveRange:NULL] mutableCopy];
NSParagraphStyle *paraStyle = [attrs objectForKey:NSParagraphStyleAttributeName];
NSMutableParagraphStyle *paraStyleM = [paraStyle mutableCopy];
// This first clears all tab stops, then adds tab stops, at desired intervals...
[paraStyle setTabStops:[NSArray array]];
for (cnt = 1; cnt <= numStops; cnt++) {
tabStop = [[NSTextTab alloc] initWithType:NSLeftTabStopType location: tabInterval * (cnt)];
[paraStyleM addTabStop:tabStop];
}
[attrs setObject:paraStyleM forKey:NSParagraphStyleAttributeName];
[[editorTextView textStorage] addAttributes:attrs range:NSMakeRange(0, [[[editorTextView textStorage] string] length])];
}
Is your existing text from HTML? I’m guessing it’s got some kind of <ul> thing going on in it.
They only recently (last six years?) hacked HTML ordered list and unordered list support into NSTextView to support richer messages in Mail, and it’s still pretty ugly.

How to do an on-item-changed for an NSPopUpButton?

I'm trying to implement a system that changes a label based on the state of an NSPopUpButton.
So far I've tried to do what's displayed in the code below, but whenever I run it, the code just jumps into the else clause, throwing an alert
- (IBAction)itemChanged:(id)sender {
if([typePopUp.stringValue isEqualToString: #"Price per character"]) {
_currency = [currencyField stringValue];
[additionalLabel setStringValue: _currency];
}
else if([typePopUp.stringValue isEqualToString: #"Percent saved"]) {
_currency = additionalLabel.stringValue = #"%";
}
else alert(#"Error", #"Please select a calculation type!");
}
So does anyone here know what to do to fix this?
#hamstergene is on the right track, but is comparing the title of the menu item rather than, say, the tag, which is wrong for the following reasons:
It means you cannot internationalize the app.
It introduces the possibility of spelling mistakes.
It's an inefficient comparison; comparing every character in a string takes way longer than comparing a single integer value.
Having said all that, NSPopUpButton makes it difficult to insert tags into the menu items, so you need to use the index of the selected item:
Assume you create the menu items using:
[typePopUp removeAllItems];
[typePopUp addItemsWithTitles: [NSArray arrayWithObjects: #"Choose one...", #"Price per character", #"Percent saved", nil]];
Then create an enum that matches the order of the titles in the array:
typedef enum {
ItemChooseOne,
ItemPricePerCharacter,
ItemPercentSaved
} ItemIndexes;
And then compare the selected item index, as follows:
- (IBAction)itemChanged:(id)sender {
NSInteger index = [(NSPopUpButton *)sender indexOfSelectedItem];
switch (index) {
case ItemChooseOne:
// something here
break;
case ItemPricePerCharacter:
_currency = [currencyField stringValue];
[additionalLabel setStringValue: _currency];
break;
case ItemPercentSaved:
_currency = #"%"; // See NOTE, below
additionalLabel.stringValue = #"%";
break;
default:
alert(#"Error", #"Please select a calculation type!");
}
}
NOTE the following line was incorrect in your code:
_currency = additionalLabel.stringValue = #"%";
Multiple assignment works because the result of x = y is y. This is not the case when a setter is involved. The corrected code is above.
EDIT This answer was heavily edited following more info from the OP.
To query the title of currently selected item in NSPopUpButton:
NSMenuItem* selectedItem = [typePopUp selectedItem];
NSString* selectedItemTitle = [selectedItem title];
if ([selectedItemTitle isEqualTo: ... ]) { ... }
Note that comparing UI strings is a very bad idea. A slightest change in UI will immediately break your code, and you are preventing future localization. You should assign numeric or object values to each item using -[NSMenuItem setTag:] or -[NSMenuItem setRepresentedObject:] and use them to identify items instead.

Programmatically change the state of a UIButton

I've got a pop-up view that loads when a user clicks on a TableView with Core Data elements. On the pop-up view I have a label that represents an int value.
The pop-up view has two butons, one for decreasing the value of the label by 1 and one for increasing it by one. So + and -
What I want to do is to disable the minus button if the label's value is 0. What I've tried is:
-(void)viewDidLayoutSubviews{
NSString *daString = currentVal.text;
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber * myNumber = [f numberFromString:daString];
int number = [myNumber intValue];
if (number==0)
minus.enabled = NO;
else
minus.enabled = YES
}
The problem with my code is that the button stays disabled after I increase the label's value, and it's no longer equal to 0.
Any suggestions?
You should keep a reference to minus button e.g.
#property (strong, nonatomic) IBOutlet UIButton *minusButton;
Set it with a value of your minus button, or connect outlet in Interface Builder
in your action handler for plusButton, do something like that
-(IBAction)plusAction:(id)sender {
//Do your business logic
...
self.minusButton.enabled = YES;
}
//In your minusButton action handler
-(IBAction)minusAction:(id)sender {
//Do your business logic
...
NSString *daString = currentVal.text;
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber * myNumber = [f numberFromString:daString];
int number = [myNumber intValue];
if (number==0)
self.minusButton.enabled = NO;
else
self.minusButton.enabled = YES
}
It seems like you have things the other way around. I would take a totally different approach:
Keep an instance variable (which we'll call 'count') in this viewController which holds the number. it can be an NSInteger. now add a target (self) to both buttons with a #selector(buttonPressed:). now this is how this selector should look like:
- (void)buttonPressed:(id)sender{
if (sender==plusButton)
self.count++;
if (sender==minusButton)
self.count--;
label.text = [NSString stringWithFormat:#"%d",self.count];
minusButton.enabled = (self.count>0);
}
I would just do this with a UIStepper, instead of the 2 buttons. You can set properties right in your storyboard/IB file that specify the max and min, increments, and a bunch of other useful things too. There are a couple video tutorials posted on YouTube that probably cover everything you'll need to know to use it.
Also, I have noticed one thing that...
If the button in disabled state and you are trying to change the title of normal state, it wont work.
I had to change the state to enabled and then I could manipulate title and set back to disabled.

Moving the cursor in an UITextView

I try to move the cursor when a UITextView is selected(touched) to simulate kind of a UITextField placeholder thing.
I'd like the cursor to be at the beginning of the first line. My problem is, that [someTextField setSelectedRange]is not working reliably. When I call it in textView:shouldChangeTextInRange:replacementText: it works as it should. But this method is only called when the user starts typing. I'm using textViewDidBeginEditing: to move the cursor when the UITextView becomes the first responder:
- (void)textViewDidBeginEditing:(UITextView *)textView
{
if (textView == self.descriptionText) {
CustomTextView* customTV = (CustomTextView *)textView;
if ([customTV.text isEqualToString:customTV.placeholder]) {
// text in text view is still the placeholder -> move cursor to the beginning
customTV.text = customTV.placeholder;
customTV.textColor = [UIColor lightGrayColor];
customTV.selectedRange = NSMakeRange(0, 0);
}
}
}
Any ideas why customTV.selectedRange = NSMakeRange(0, 0); isn't working correctly in textViewDidBeginEditing: ?
Thanks for your help!
Actually there's a very simple way of accomplishing this.
// Count the characters on screen
NSMutableString *numOfChar = [self.myTextField.text mutableCopy];
// Skip that many characters to the left
self.myTextField.selectedRange = NSMakeRange(self.myTextField.selectedRange.location-[numOfChar length], 0);
Hope this helps.