[PATCH] style/colors for the autocomplete box

143 views
Skip to first unread message

Stefan Küng

unread,
Feb 5, 2021, 4:19:11 PM2/5/21
to scintilla-interest
this patch adds two new styles STYLE_AUTOC and STYLE_AUTOCHIGHLIGHT to configure the colors used to draw the autocomplete listbox. There's also a new command SCI_AUTOCSETUSESTYLE which is used to enable the custom styling. If not enabled, the default colors of the OS are used.
And finally, a new notification is sent right before the autocomplete popup is shown, with the window ID passed in the lParam parameter. This allows the application to deal with the window before it is shown (e.g. on Windows set WS_STYLE flags, move the window, ...)

Unfortunately I can't build for Gtk or Mac, so the patch only handles the Windows part.

With this patch, I'm finally able to get the popup to show up with suitable colors for a dark mode - and the HWND I get via the notification lParam I can use to set the dark mode flag on the window itself so even the scrollbars get drawn properly.

kind regards,
Stefan
styleAutoCompleteBox.patch

Neil Hodgson

unread,
Feb 5, 2021, 5:25:43 PM2/5/21
to Scintilla mailing list
Hi Stefan,

> this patch adds two new styles STYLE_AUTOC and STYLE_AUTOCHIGHLIGHT to configure the colors used to draw the autocomplete listbox.

STYLE_AUTOC=40 and STYLE_AUTOCHIGHLIGHT=41. This clashes with existing lexers with, for example, SCE_PL_SUB_PROTOTYPE=40 and SCE_HJ_DEFAULT=41. It will also clash with lexers developed by projects that use Scintilla.

Since a separate style is being used for STYLE_AUTOCHIGHLIGHT it might be assumed that the patch allows a different font for the highlighted entry but this is not the case. Allocating an extra style entry may be reasonable to define a font for the list box but, it should then use an extended style as is done for annotations by calling https://www.scintilla.org/ScintillaDoc.html#SCI_ALLOCATEEXTENDEDSTYLES .

Here is a patch I worked on for just setting the list box colours for Scintilla 5. The optionsSet field might later become a set of flags of which options were being set.

Neil
8452.patch

Stefan Küng

unread,
Feb 6, 2021, 2:13:55 AM2/6/21
to scintilla-interest
On Friday, February 5, 2021 at 11:25:43 PM UTC+1 Neil Hodgson wrote:

Here is a patch I worked on for just setting the list box colours for Scintilla 5. The optionsSet field might later become a set of flags of which options were being set.

will there also be a command to set those options? Can't see any SCI_SETACOPTIONS or something like that in your patch?
Your patch would work for me if it's possible to set those options from a client app.
However I would still need the notification which passes the window handle - that's very important since I need that handle to set the darkmode flag and call SetWindowTheme() on it.

Stefan


Neil Hodgson

unread,
Feb 6, 2021, 5:37:40 PM2/6/21
to Scintilla mailing list
Stefan Küng:

> will there also be a command to set those options? Can't see any SCI_SETACOPTIONS or something like that in your patch?

That patch was part of platform interface changes for Scintilla 5. Adding a method to ListBox is a breaking change and I was trying to find a mechanism where further list box settings could be added without breaking downstream platform layers.

There was an issue containing some early platform interface changing code here:
https://sourceforge.net/p/scintilla/feature-requests/1364/


Not all platforms can (easily) support changing list box colours so there should also be a mechanism for communicating that to the application. Its possible that the SCI_SUPPORTSFEATURE API proposed for 5 could be used here.

The most consistent way to expose this in the API would be as 4 separate optional properties with the colours following the system until the application sets a colour.

set void SetListText(Colour fore)
get Colour GetListText()
set void SetListBackground(Colour fore)
get …
set void SetListSelectedText(Colour fore)
get …
set void SetListSelectedBackground(Colour fore)
get …

The application should also be able to reset the colour so it agains follows the system. Previously, adding separate properties for each colour has been a little onerous so a more streamlined API could be examined with a colour option enumeration. Something like:

enum ColourOption { WhitespaceText=0, Border=1, …,
ListText=392, ListBackground=393, ListSelectedText=394, ListSelectedBackground=395 };

ColourOptionSet(ColourOption, Colour);
ColourOptionReset(ColourOption);
Colour ColourOptionGet(ColourOption);
bool ColourOptionIsSet(ColourOption);
bool ColourOptionCanSet(ColourOption);

This could also make some existing optional colour features more regular like setting the selection foreground which is currently SCI_SETSELFORE(bool useSetting, colour fore) where a false useSetting turns off the application preference.

> However I would still need the notification which passes the window handle - that's very important since I need that handle to set the darkmode flag and call SetWindowTheme() on it.

Placing the window handle in lParam isn’t great as the purpose of lParam is macro recording. Exposing internal window details is messy - ac.lb->GetID() is the top-level but the actual list is generally a child of that with (potentially) more sub windows between them. I’ll think some more on APIs for returning platform handles or pointers.

Neil

Neil Hodgson

unread,
Mar 25, 2021, 5:13:30 AM3/25/21
to Scintilla mailing list
Defining colours to override the appearance is similar to some other issues so it would solve more problems if a generic solution can be implemented.

Contributors are often drawn to the text style definition APIs to add new system styles for a new feature as this seems simpler than defining a set of new APIs. However, styles are more complex than they initially appear with a fixed number (256) of lexical styles possible and additional styles for features like annotations requiring allocation and tracking. They also require extra memory and management of font resources which is not reasonable when the feature is just changing a colour.

Some features, such as list colours, are normally defined by the system. The system may change them while the application is running: Windows normally uses a white background for lists but, if the user opens the settings app and chooses Ease of Access | High contrast | On + High Contrast Black then this changes to a black background. Currently, Scintilla will automatically show lists with the system background and any implementation of list colours should not break this.

Ideally, it should be possible for the application to ask Scintilla what the current system or default colours are so that these can be used as a base for the application choices: perhaps only defining the selected item background to match an application theme but making this darker or lighter to ensure enough contrast with the selected item text. However, it may take more work to implement this and its unlikely to be done for all platforms.

Different platforms have different sets of modes. For example, some platforms (such as Qt on Windows) have a ‘prelight’ or ‘mouseover’ colour so that you can see which item would be selected if the mouse button is pressed.

Attached is a patch that addresses some of the issues. Each ‘element’ may be set a colour by the application (SetElementColour) which may be retrieved (GetElementColour) when set. Whether the application has set a colour can be determined with GetElementIsSet. The application can drop its choice so that the system (or Scintilla) default is used instead with ResetElementColour. The result from GetElementColour is uncertain when GetElementIsSet is false - it may be the default if this can be easily determined. An additional API could be provided to indicate if the default is available for this element. Some elements may allow translucency or may allow translucency on some platforms and this can be accessed through the GetElementAllowsTranslucent call.

As well as the 4 main list box colours, there are 17 current elements in Scintilla that could be accessed through this Element API in a way that is more capable and simpler than the current set of per-element APIs. There have been requests for control over other elements that could be met through this API: a translucent colour for visible whitespace and an override colour for control character and line end blobs.

The attached patch is approximate and was based on in-progress work so won’t apply cleanly on any published revision of Scintilla - its for discussion or manual application.

Neil
SetElementColour2.patch

Stefan Küng

unread,
Mar 25, 2021, 2:59:40 PM3/25/21
to scintilla-interest
patch looks good to me. But I'm still missing a way to get the window handle of the autocompletion popup. As I mentioned before, that's very important to me so I can set certain flags to handle a proper dark mode.

Also, I don't think that Scintilla should report back the system colors but the application should directly get them from the OS instead.

Neil Hodgson

unread,
Mar 25, 2021, 6:17:42 PM3/25/21
to Scintilla mailing list
Stefan Küng:

> But I'm still missing a way to get the window handle of the autocompletion popup. As I mentioned before, that's very important to me so I can set certain flags to handle a proper dark mode.

I haven’t got a good solution to that yet. Even if you receive a window ID, you may still have to navigate the window hierarchy to get to the sub window of interest. And if you are willing to do that then you may as well find the autocompletion through the same technique. For Win32 you can use its class name FindWindowEx(NULL, NULL, “ListBoxX”, NULL).

Neil

Stefan Küng

unread,
Mar 26, 2021, 12:14:27 PM3/26/21
to scintilla-interest
But to use those APIs (I have to use EnumChildWindows anyway), I need to know the moment the window is created but not shown yet. So maybe a notification for that would suffice.

Stefan 

Neil Hodgson

unread,
May 7, 2021, 7:22:46 PM5/7/21
to Scintilla mailing list
Stefan Küng:

> But to use those APIs (I have to use EnumChildWindows anyway), I need to know the moment the window is created but not shown yet. So maybe a notification for that would suffice.

Is the goal here to suppress the resizable attribute of the autocompletion and thus the extra space?

If that is so then it would be possible to add a Win32-specific ’SCI_AUTOCSETRESIZABLE’ API. That is simpler, localized to the platform where it is applicable, and doesn’t add another callback that could be used in unexpected ways.

Neil

Stefan Küng

unread,
May 8, 2021, 2:51:26 AM5/8/21
to scintilla-interest
On Saturday, May 8, 2021 at 1:22:46 AM UTC+2 Neil Hodgson wrote:
Stefan Küng:

> But to use those APIs (I have to use EnumChildWindows anyway), I need to know the moment the window is created but not shown yet. So maybe a notification for that would suffice.

Is the goal here to suppress the resizable attribute of the autocompletion and thus the extra space?

Not exactly. Well, I'm removing the resizable attribute for the dark mode, yes, but that's just because the resizable border of the window stays white and therefore does not look good.
But the main reason I do that is to use undocumented APIs to set dark mode for the windows. There's an undocumented API "AllowDarkModeForWindow" and "SetWindowCompositionAttribute" which I use - that way even the scrollbars are drawn in a dark style.
Anyway: I found that it's enough if I do that right after calling SCI_AUTOCSHOW - it's fast enough so the user does not see any flickering.

Stefan

Neil Hodgson

unread,
Jul 17, 2021, 12:59:35 AM7/17/21
to Scintilla mailing list
Stefan Küng:

Not exactly. Well, I'm removing the resizable attribute for the dark mode, yes, but that's just because the resizable border of the window stays white and therefore does not look good.

   There is a potential change to switch off autocompletion resizing and thus the extra whitespace on Win32 at

   Neil

Reply all
Reply to author
Forward
0 new messages