Setting NSColorPanel to affect NSBackgroundColorAttributeName

  • Hi,

    I'm trying to implement to custom colour wells like the ones in Pages, whereby one affects the font colour of the text view and the other one affects the highlight/background colour of the text (set via NSBackgroundColorAttributeName). However, I am having some difficulties.

    When a colour is selected in the shared NSColorPanel, a -changeColor: message is sent to the first responder - the text view. The standard text view's implementation of this is to change the NSForegroundColorAttributeName value. So, it seems to me that I need to override NSTextView's -changeColor: so that it can handle either a foreground or background change. In fact, I've done this, as follows:

    - (void)setColorPanelChangesBackgroundColor:(BOOL)flag

    {

    colorPanelChangesBackgroundColor = flag;

    }

    - (BOOL)colorPanelChangesBackgroundColor

    {

    return colorPanelChangesBackgroundColor;

    }

    - (void)changeColor:(id)sender

    {

    if (![self colorPanelChangesBackgroundColor])

    {

      [super changeColor:sender];

      return;

    }



    NSColor *color = [sender color];



    if (![self isRichText])

    {

      NSBeep();

      return;

    }



    NSArray *selection = [self rangesForUserCharacterAttributeChange];

    NSValue *val;

    NSRange selRange;

    NSEnumerator *e = [selection objectEnumerator];

    NSTextStorage *text = [self textStorage];

    NSUndoManager *undo = [self undoManager];



    while (val = [e nextObject])

    {

      selRange = [val rangeValue];



      if ( ([selection count] == 1) && (selRange.length == 0) )

      {

      NSMutableDictionary *attribs = [NSMutableDictionary dictionaryWithDictionary:[self typingAttributes]];

      [attribs setValue:color forKey:NSBackgroundColorAttributeName];

      [self setTypingAttributes:attribs];

      break;

      }



      if (selRange.length > 0)

      {

      if ([self shouldChangeTextInRange:selRange replacementString:nil])

      {

        [text addAttribute:NSBackgroundColorAttributeName

                                value:color

                                range:selRange];

        [self didChangeText];



        if (![undo isUndoing])

        [undo setActionName:NSLocalizedString(@"Background Color",nil)];

      }

      }

    }



    // [self setColorPanelChangesBackgroundColor:NO];

    }

    The problem, however, is that once the flag is set to tell -changeColor: to affect the background colour, there is easy way of resetting (as in no obvious place to do this). So, when you select Format > Font > Show Colors, which you would expect to affect the foreground colour as it does in TextEdit, it will now affect the background colour if the background colour button has been used. If you reset the flag at the end of -changeColor:, the next click in the open colour panel after changing the background colour will change the foreground colour, which again, would not be expected.

    So, my question is, what is the best way of doing this?

    Thanks in advance for any help.
    All the best,
    Keith

          ____________________________________________________________________________________
    Looking for last minute shopping deals?
    Find them fast with Yahoo! Search.  http://tools.search.yahoo.com/newsearch/category.php?category=shopping
  • > So, when you select Format > Font > Show Colors, which you would
    > expect to affect the foreground colour as it does in TextEdit, it
    > will now affect the background colour if the background colour
    > button has been used.

    Can't you just have the action method for your Show Colors menu reset
    your color targeting state? Just replace the default action with one
    that clears your flag and then calls the default color panel method.

    In our application we have other complications that required
    overriding private NSColorPanel methods that work in tandem with some
    custom subclasses. It's pretty messy and hopefully you don't need to
    go that route.

    ~Martin
  • Thanks yet again, Martin. Your suggestion was indeed the best way to go. My main issue was that I had I have several text views that could be affected, so I ended up just creating an NSTextView category with a class setter and getter for the color panel mode (background or foreground colour). Along with your suggestion, this works well.

    Thanks again!
    Keith

    ----- Original Message ----
    From: Martin Wierschin <martin...>
    To: Keith Blount <keithblount...>
    Cc: CocoaDev (Apple) <cocoa-dev...>
    Sent: Friday, December 14, 2007 2:24:11 AM
    Subject: Re: Setting NSColorPanel to affect NSBackgroundColorAttributeName

    > So, when you select Format > Font > Show Colors, which you would
    > expect to affect the foreground colour as it does in TextEdit, it
    > will now affect the background colour if the background colour
    > button has been used.

    Can't you just have the action method for your Show Colors menu reset
    your color targeting state? Just replace the default action with one
    that clears your flag and then calls the default color panel method.

    In our application we have other complications that required
    overriding private NSColorPanel methods that work in tandem with some
    custom subclasses. It's pretty messy and hopefully you don't need to
    go that route.

    ~Martin

          ____________________________________________________________________________________
    Be a better friend, newshound, and
    know-it-all with Yahoo! Mobile.  Try it now.  http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ
previous month december 2007 next month
MTWTFSS
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
Go to today