Menu

#2056 Scintilla Cocoa cannot set some color properties

Bug
closed-rejected
5
2018-10-21
2018-10-20
No

The Cocoa wrapper for Scintilla has a methods for setting colors:

- (void) setColorProperty: (int) property parameter: (long) parameter value: (NSColor *) value {
- (void) setColorProperty: (int) property parameter: (long) parameter fromHTML: (NSString *) fromHTML {

These methods pass the parameter in wParam and the color in lParam. But some color setting messages in Scingtilla have no parameter and pass the color in wParam (SCI_SETCARETFORE for example). The color setter methods cannot set these colors. Two additional color setter methods need to be defined that pass the color in wParam.

static long NSColorToLong(NSColor* value)
{
    if (value.colorSpaceName != NSDeviceRGBColorSpace)
        value = [value colorUsingColorSpaceName: NSDeviceRGBColorSpace];
    long red = static_cast<long>(value.redComponent * 255);
    long green = static_cast<long>(value.greenComponent * 255);
    long blue = static_cast<long>(value.blueComponent * 255);

    long color = (blue << 16) + (green << 8) + red;
    return color;
}

/**
 * Specialized property setter for colors.
 */
- (void) setColorProperty: (int) property parameter: (long) parameter value: (NSColor *) value {
    mBackend->WndProc(property, parameter, NSColorToLong(value));
}

- (void) setColorProperty: (int) property value: (NSColor *) value {
    mBackend->WndProc(property, NSColorToLong(value), 0);
}

//--------------------------------------------------------------------------------------------------

static long HTMLtoLong(NSString* fromHTML)
{
    if (fromHTML.length > 3 && [fromHTML characterAtIndex: 0] == '#') {
        bool longVersion = fromHTML.length > 6;
        int index = 1;

        char value[3] = {0, 0, 0};
        value[0] = static_cast<char>([fromHTML characterAtIndex: index++]);
        if (longVersion)
            value[1] = static_cast<char>([fromHTML characterAtIndex: index++]);
        else
            value[1] = value[0];

        unsigned rawRed;
        [[NSScanner scannerWithString: @(value)] scanHexInt: &rawRed];

        value[0] = static_cast<char>([fromHTML characterAtIndex: index++]);
        if (longVersion)
            value[1] = static_cast<char>([fromHTML characterAtIndex: index++]);
        else
            value[1] = value[0];

        unsigned rawGreen;
        [[NSScanner scannerWithString: @(value)] scanHexInt: &rawGreen];

        value[0] = static_cast<char>([fromHTML characterAtIndex: index++]);
        if (longVersion)
            value[1] = static_cast<char>([fromHTML characterAtIndex: index++]);
        else
            value[1] = value[0];

        unsigned rawBlue;
        [[NSScanner scannerWithString: @(value)] scanHexInt: &rawBlue];

        long color = (rawBlue << 16) + (rawGreen << 8) + rawRed;
        return color;
    } else {
        return -1;
    }
}

/**
 * Another color property setting, which allows to specify the color as string like in HTML
 * documents (i.e. with leading # and either 3 hex digits or 6).
 */
- (void) setColorProperty: (int) property parameter: (long) parameter fromHTML: (NSString *) fromHTML {
    long color = HTMLtoLong(fromHTML);
    if (color >= 0)
        mBackend->WndProc(property, parameter, color);
}

- (void) setColorProperty: (int) property fromHTML: (NSString *) fromHTML {
    long color = HTMLtoLong(fromHTML);
    if (color >= 0)
        mBackend->WndProc(property, color, 0);
}

Discussion

  • Neil Hodgson

    Neil Hodgson - 2018-10-20

    I did not write setColorProperty and do not like it and other similar methods (setGeneralProperty, setReferenceProperty, setLexerProperty... - the last 470 lines of ScintillaView.mm) as they are incomplete and inconsistent, assume UTF-8, and are not documented. They provide the hope of an API that follows Objective C conventions but doesn't really deliver so application code becomes a mix of these and more 'C-like' calls. They are an awkward part-way stage producing code like [mEditor setGeneralProperty: SCI_SETLEXER parameter: SCLEX_MYSQL value: 0] when a more ambitious wrapper would have mEditor.lexer = SCLEX_MYSQL.

    The path I recommend is for applications to retrieve the 'direct function' (SCI_GETDIRECTFUNCTION + SCI_GETDIRECTPOINTER) and use that to call Scintilla APIs directly. If there is a desire for a more pleasant API then that should be constructed over the direct function.

    If you really want to continue down this path then the changes can go in but I had rather hoped that these methods wouldn't be widely used.

     
  • John Horigan

    John Horigan - 2018-10-21

    I guess you're right. There is no point in polishing a turd. I will revert my local changes and just use the low level API.

     
    • Neil Hodgson

      Neil Hodgson - 2018-10-21

      OK, closing this issue.

      In the long term, there may be some work towards a more friendly API wrapper for C++ but that won't match Objective C or Swift that well. The include/Scintilla.iface file can be used for creating language-friendly APIs either at run time for interpreted languages like Lua or by code generation.

       
  • Neil Hodgson

    Neil Hodgson - 2018-10-21
    • labels: --> scintilla, cocoa
    • status: open --> closed-rejected
    • assigned_to: Neil Hodgson
     

Log in to post a comment.